feat(KB-341): unify steeringComments and comments into single comments system
- Consolidate steeringComments and comments into unified comments field using TaskComment type - Remove SteeringComment type, migrate all comments to TaskComment format - Update addComment to delegate to addTaskComment with auto-refinement for done tasks - Merge legacy steeringComments data into comments during database migration - Update dashboard API endpoint from /steer to /comments - Update executor to use unified comments field for real-time injection - Update PR comment handler to use addTaskComment method
This commit is contained in:
@@ -541,8 +541,9 @@ describe("migrateFromLegacy", () => {
|
||||
expect(JSON.parse(row.steps)).toHaveLength(2);
|
||||
expect(JSON.parse(row.log)).toHaveLength(1);
|
||||
expect(JSON.parse(row.attachments)).toHaveLength(1);
|
||||
// steeringComments should be merged into comments
|
||||
expect(JSON.parse(row.comments)).toHaveLength(1); // 1 steering comment migrated
|
||||
// steeringComments are merged into comments during migration
|
||||
expect(JSON.parse(row.steeringComments)).toEqual([]); // Now empty - merged into comments
|
||||
expect(JSON.parse(row.comments)).toHaveLength(1); // Migrated from steeringComments
|
||||
expect(JSON.parse(row.workflowStepResults)).toHaveLength(1);
|
||||
expect(JSON.parse(row.prInfo).number).toBe(1);
|
||||
expect(JSON.parse(row.issueInfo).number).toBe(10);
|
||||
|
||||
@@ -224,7 +224,10 @@ async function migrateTasks(kbDir: string, db: Database): Promise<void> {
|
||||
toJson(task.steps || []),
|
||||
toJson(task.log || []),
|
||||
toJson(task.attachments || []),
|
||||
toJson(mergedComments),
|
||||
toJson(task.attachments || []),
|
||||
"[]", // steeringComments column - no longer used, write empty array
|
||||
// Merge legacy steeringComments into unified comments field during migration
|
||||
toJson([...((task as any).steeringComments || []), ...(task.comments || [])]),
|
||||
toJson(task.workflowStepResults || []),
|
||||
toJsonNullable(task.prInfo),
|
||||
toJsonNullable(task.issueInfo),
|
||||
|
||||
@@ -1276,13 +1276,13 @@ describe("TaskStore", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("unifies task comments and steering comments into single comments field", async () => {
|
||||
it("persists all comments in unified comments field", async () => {
|
||||
const task = await createTestTask();
|
||||
await store.addTaskComment(task.id, "General note", "alice");
|
||||
await store.addComment(task.id, "Execution note");
|
||||
|
||||
const reopened = await store.getTask(task.id);
|
||||
// Both comments should now be in the unified comments field
|
||||
// Both comments should be in the unified comments array
|
||||
expect(reopened.comments).toHaveLength(2);
|
||||
expect(reopened.comments![0].text).toBe("General note");
|
||||
expect(reopened.comments![1].text).toBe("Execution note");
|
||||
@@ -1367,8 +1367,7 @@ describe("TaskStore", () => {
|
||||
const task = await createTestTask();
|
||||
const updated = await store.addComment(task.id, "Comment with log");
|
||||
|
||||
expect(updated.log.some((l) => l.action === "Comment added")).toBe(true);
|
||||
expect(updated.log.some((l) => l.outcome === "by user")).toBe(true);
|
||||
expect(updated.log.some((l) => l.action === "Comment added by user")).toBe(true);
|
||||
});
|
||||
|
||||
it("updates updatedAt timestamp", async () => {
|
||||
@@ -1499,12 +1498,11 @@ describe("TaskStore", () => {
|
||||
});
|
||||
|
||||
describe("task comments and merge details types", () => {
|
||||
it("keeps task comments distinct from steering comments on new tasks", async () => {
|
||||
it("has undefined comments on new tasks", async () => {
|
||||
const task = await createTestTask();
|
||||
const reopened = await store.getTask(task.id);
|
||||
|
||||
expect(reopened.comments).toBeUndefined();
|
||||
expect(reopened.comments).toBeUndefined();
|
||||
});
|
||||
|
||||
it("supports the task comment and merge details shapes", async () => {
|
||||
@@ -2244,6 +2242,7 @@ describe("TaskStore", () => {
|
||||
|
||||
const duplicated = await store.duplicateTask(task.id);
|
||||
|
||||
// Comments should not be copied when duplicating
|
||||
expect(duplicated.comments).toBeUndefined();
|
||||
});
|
||||
|
||||
|
||||
@@ -150,7 +150,13 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
steps: fromJson<import("./types.js").TaskStep[]>(row.steps) || [],
|
||||
log: fromJson<import("./types.js").TaskLogEntry[]>(row.log) || [],
|
||||
attachments: (() => { const a = fromJson<TaskAttachment[]>(row.attachments); return a && a.length > 0 ? a : undefined; })(),
|
||||
comments: (() => { const c = fromJson<import("./types.js").TaskComment[]>(row.comments); return c && c.length > 0 ? c : undefined; })(),
|
||||
comments: (() => {
|
||||
// Merge legacy steeringComments and comments into unified comments field
|
||||
const legacySteering = fromJson<Array<{ id: string; text: string; createdAt: string; author: string }>>(row.steeringComments) || [];
|
||||
const regularComments = fromJson<import("./types.js").TaskComment[]>(row.comments) || [];
|
||||
const merged = [...legacySteering, ...regularComments];
|
||||
return merged.length > 0 ? merged : undefined;
|
||||
})(),
|
||||
workflowStepResults: (() => { const w = fromJson<import("./types.js").WorkflowStepResult[]>(row.workflowStepResults); return w && w.length > 0 ? w : undefined; })(),
|
||||
prInfo: fromJson<import("./types.js").PrInfo>(row.prInfo),
|
||||
issueInfo: fromJson<import("./types.js").IssueInfo>(row.issueInfo),
|
||||
@@ -208,6 +214,7 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
toJson(task.steps || []),
|
||||
toJson(task.log || []),
|
||||
toJson(task.attachments || []),
|
||||
"[]", // steeringComments column - no longer used, write empty array
|
||||
toJson(task.comments || []),
|
||||
toJson(task.workflowStepResults || []),
|
||||
toJsonNullable(task.prInfo),
|
||||
@@ -1997,6 +2004,8 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
* Comments are injected into the AI execution context.
|
||||
* When a comment is added to a task in the "done" column by a user,
|
||||
* automatically creates a refinement task with the comment text as feedback.
|
||||
*
|
||||
* Note: Now uses the unified comments system (TaskComment).
|
||||
*/
|
||||
async addComment(
|
||||
id: string,
|
||||
|
||||
Reference in New Issue
Block a user