feat(KB-604): include task context in notifications with description fallback
- Add formatTaskIdentifier helper to format task references with title or description fallback - Update notification messages to include task identifier context - Show truncated description (200 chars) prefixed with task ID when no title - Add comprehensive tests for formatTaskIdentifier function - Add changeset for notification improvements and update AGENTS.md
This commit is contained in:
@@ -220,18 +220,56 @@ describe("NtfyNotifier", () => {
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses task ID when title is not available", async () => {
|
||||
it("uses task ID and description when title is not available", async () => {
|
||||
notifier = new NtfyNotifier(store);
|
||||
await notifier.start();
|
||||
|
||||
store.triggerTaskMoved(createTask("KB-001"), "in-progress", "in-review");
|
||||
const taskWithoutTitle = { ...createTask("KB-001"), description: "Implement user authentication flow" };
|
||||
store.triggerTaskMoved(taskWithoutTitle, "in-progress", "in-review");
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"https://ntfy.sh/test-topic",
|
||||
expect.objectContaining({
|
||||
body: 'Task "KB-001" is ready for review',
|
||||
body: 'Task "KB-001: Implement user authentication flow" is ready for review',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("truncates description to 200 characters when no title is set", async () => {
|
||||
notifier = new NtfyNotifier(store);
|
||||
await notifier.start();
|
||||
|
||||
const longDescription = "A".repeat(250);
|
||||
const taskWithoutTitle = { ...createTask("KB-001"), description: longDescription };
|
||||
store.triggerTaskMoved(taskWithoutTitle, "in-progress", "in-review");
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
const expectedSnippet = "A".repeat(200) + "...";
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"https://ntfy.sh/test-topic",
|
||||
expect.objectContaining({
|
||||
body: `Task "KB-001: ${expectedSnippet}" is ready for review`,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("does not truncate description at exactly 200 characters", async () => {
|
||||
notifier = new NtfyNotifier(store);
|
||||
await notifier.start();
|
||||
|
||||
const exactDescription = "B".repeat(200);
|
||||
const taskWithoutTitle = { ...createTask("KB-001"), description: exactDescription };
|
||||
store.triggerTaskMoved(taskWithoutTitle, "in-progress", "in-review");
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"https://ntfy.sh/test-topic",
|
||||
expect.objectContaining({
|
||||
body: `Task "KB-001: ${exactDescription}" is ready for review`,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,22 @@ export interface NtfyNotifierOptions {
|
||||
ntfyBaseUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a task identifier for notifications.
|
||||
* - If title exists: returns "{title}"
|
||||
* - If no title: returns "{id}: {first 200 chars of description}" (truncated with "..." if > 200)
|
||||
*/
|
||||
function formatTaskIdentifier(task: Task): string {
|
||||
if (task.title) {
|
||||
return task.title;
|
||||
}
|
||||
const maxLen = 200;
|
||||
const snippet = task.description.length > maxLen
|
||||
? task.description.slice(0, maxLen) + "..."
|
||||
: task.description;
|
||||
return `${task.id}: ${snippet}`;
|
||||
}
|
||||
|
||||
/** Minimal store interface needed by NtfyNotifier */
|
||||
interface NtfyNotifierStore {
|
||||
getSettings(): Promise<Settings> | Settings;
|
||||
@@ -104,7 +120,7 @@ export class NtfyNotifier {
|
||||
this.sendNotification(
|
||||
this.config.topic!,
|
||||
`Task ${task.id} completed`,
|
||||
`Task "${task.title ?? task.id}" is ready for review`,
|
||||
`Task "${formatTaskIdentifier(task)}" is ready for review`,
|
||||
"default",
|
||||
),
|
||||
);
|
||||
@@ -123,7 +139,7 @@ export class NtfyNotifier {
|
||||
this.sendNotification(
|
||||
this.config.topic!,
|
||||
`Task ${task.id} failed`,
|
||||
`Task "${task.title ?? task.id}" has failed and needs attention`,
|
||||
`Task "${formatTaskIdentifier(task)}" has failed and needs attention`,
|
||||
"high",
|
||||
),
|
||||
);
|
||||
@@ -139,7 +155,7 @@ export class NtfyNotifier {
|
||||
this.sendNotification(
|
||||
this.config.topic!,
|
||||
`Task ${result.task.id} merged`,
|
||||
`Task "${result.task.title ?? result.task.id}" has been merged to main`,
|
||||
`Task "${formatTaskIdentifier(result.task)}" has been merged to main`,
|
||||
"default",
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user