feat(KB-334): change default task prefix from KB to FN
- Change default taskPrefix from KB to FN and branch naming from kb/ to fusion/ - Update all test expectations and patterns for new naming convention - Update settings UI placeholder text to reflect FN prefix - Update dashboard, engine, and CLI components for fusion/ branch paths - Add changeset documenting the breaking change for users
This commit is contained in:
8
.changeset/rename-task-prefix-branch.md
Normal file
8
.changeset/rename-task-prefix-branch.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
"@gsxdsm/fusion": minor
|
||||||
|
"@fusion/core": minor
|
||||||
|
"@fusion/dashboard": minor
|
||||||
|
"@fusion/engine": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Rename default task ID prefix from KB to FN and branch naming from kb/ to fusion/
|
||||||
@@ -153,7 +153,7 @@ describe("kb pi extension", () => {
|
|||||||
|
|
||||||
expect(result.details.taskId).toBe("FN-002");
|
expect(result.details.taskId).toBe("FN-002");
|
||||||
expect(result.details.dependencies).toEqual(["FN-001"]);
|
expect(result.details.dependencies).toEqual(["FN-001"]);
|
||||||
expect(result.content[0].text).toContain("Dependencies: KB-001");
|
expect(result.content[0].text).toContain("Dependencies: FN-001");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ describe("kb pi extension", () => {
|
|||||||
makeCtx(tmpDir),
|
makeCtx(tmpDir),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.content[0].text).toContain("Attached to KB-001");
|
expect(result.content[0].text).toContain("Attached to FN-001");
|
||||||
expect(result.content[0].text).toContain("test.txt");
|
expect(result.content[0].text).toContain("test.txt");
|
||||||
expect(result.details.attachment).toBeDefined();
|
expect(result.details.attachment).toBeDefined();
|
||||||
expect(result.details.attachment.originalName).toBe("test.txt");
|
expect(result.details.attachment.originalName).toBe("test.txt");
|
||||||
@@ -366,7 +366,7 @@ describe("kb pi extension", () => {
|
|||||||
undefined,
|
undefined,
|
||||||
makeCtx(tmpDir),
|
makeCtx(tmpDir),
|
||||||
);
|
);
|
||||||
expect(pauseResult.content[0].text).toContain("Paused KB-001");
|
expect(pauseResult.content[0].text).toContain("Paused FN-001");
|
||||||
|
|
||||||
// Verify it's paused
|
// Verify it's paused
|
||||||
const showTool = api.tools.get("kb_task_show")!;
|
const showTool = api.tools.get("kb_task_show")!;
|
||||||
@@ -388,7 +388,7 @@ describe("kb pi extension", () => {
|
|||||||
undefined,
|
undefined,
|
||||||
makeCtx(tmpDir),
|
makeCtx(tmpDir),
|
||||||
);
|
);
|
||||||
expect(unpauseResult.content[0].text).toContain("Unpaused KB-001");
|
expect(unpauseResult.content[0].text).toContain("Unpaused FN-001");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe("runTaskSteer", () => {
|
|||||||
|
|
||||||
expect(mockAddSteeringComment).toHaveBeenCalledWith("FN-001", "Focus on error handling", "user");
|
expect(mockAddSteeringComment).toHaveBeenCalledWith("FN-001", "Focus on error handling", "user");
|
||||||
expect(mockConsoleLog).toHaveBeenCalledWith(
|
expect(mockConsoleLog).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("Steering comment added to KB-001")
|
expect.stringContaining("Steering comment added to FN-001")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -942,7 +942,7 @@ describe("runTaskRefine", () => {
|
|||||||
|
|
||||||
mockRefineTask = vi.fn().mockResolvedValue({
|
mockRefineTask = vi.fn().mockResolvedValue({
|
||||||
id: "FN-002",
|
id: "FN-002",
|
||||||
description: "Refinement of KB-001",
|
description: "Refinement of FN-001",
|
||||||
column: "triage",
|
column: "triage",
|
||||||
dependencies: ["FN-001"],
|
dependencies: ["FN-001"],
|
||||||
steps: [],
|
steps: [],
|
||||||
@@ -1132,7 +1132,7 @@ describe("runTaskDelete", () => {
|
|||||||
await runTaskDelete("FN-001", false);
|
await runTaskDelete("FN-001", false);
|
||||||
|
|
||||||
expect(mockRlQuestion).toHaveBeenCalledOnce();
|
expect(mockRlQuestion).toHaveBeenCalledOnce();
|
||||||
expect(mockRlQuestion).toHaveBeenCalledWith("Are you sure you want to delete KB-001? [y/N] ");
|
expect(mockRlQuestion).toHaveBeenCalledWith("Are you sure you want to delete FN-001? [y/N] ");
|
||||||
expect(mockRlClose).toHaveBeenCalled();
|
expect(mockRlClose).toHaveBeenCalled();
|
||||||
expect(mockDeleteTask).toHaveBeenCalledOnce();
|
expect(mockDeleteTask).toHaveBeenCalledOnce();
|
||||||
expect(mockDeleteTask).toHaveBeenCalledWith("FN-001");
|
expect(mockDeleteTask).toHaveBeenCalledWith("FN-001");
|
||||||
@@ -1227,7 +1227,7 @@ describe("runTaskComment", () => {
|
|||||||
|
|
||||||
const store = (TaskStore as unknown as ReturnType<typeof vi.fn>).mock.results.at(-1)?.value;
|
const store = (TaskStore as unknown as ReturnType<typeof vi.fn>).mock.results.at(-1)?.value;
|
||||||
expect(store.addTaskComment).toHaveBeenCalledWith("FN-001", "Hello", "alice");
|
expect(store.addTaskComment).toHaveBeenCalledWith("FN-001", "Hello", "alice");
|
||||||
expect(logSpy).toHaveBeenCalledWith(" ✓ Comment added to KB-001");
|
expect(logSpy).toHaveBeenCalledWith(" ✓ Comment added to FN-001");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lists task comments", async () => {
|
it("lists task comments", async () => {
|
||||||
@@ -1309,7 +1309,7 @@ describe("runTaskRetry", () => {
|
|||||||
column: "in-progress"
|
column: "in-progress"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await expect(runTaskRetry("FN-001")).rejects.toThrow("Task KB-001 is not failed (status: none)");
|
await expect(runTaskRetry("FN-001")).rejects.toThrow("Task FN-001 is not failed (status: none)");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws error with correct status when task has different status", async () => {
|
it("throws error with correct status when task has different status", async () => {
|
||||||
@@ -1319,7 +1319,7 @@ describe("runTaskRetry", () => {
|
|||||||
column: "in-progress"
|
column: "in-progress"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await expect(runTaskRetry("FN-001")).rejects.toThrow("Task KB-001 is not failed (status: paused)");
|
await expect(runTaskRetry("FN-001")).rejects.toThrow("Task FN-001 is not failed (status: paused)");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1434,7 +1434,7 @@ describe("runTaskLogs", () => {
|
|||||||
|
|
||||||
await runTaskLogs("FN-001");
|
await runTaskLogs("FN-001");
|
||||||
|
|
||||||
expect(logSpy).toHaveBeenCalledWith("No agent logs found for KB-001");
|
expect(logSpy).toHaveBeenCalledWith("No agent logs found for FN-001");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exits with error when task not found", async () => {
|
it("exits with error when task not found", async () => {
|
||||||
@@ -1937,7 +1937,7 @@ describe("runTaskPrCreate", () => {
|
|||||||
it("exits with error when branch has no commits", async () => {
|
it("exits with error when branch has no commits", async () => {
|
||||||
const task = makeInReviewTask();
|
const task = makeInReviewTask();
|
||||||
mockGetTask.mockResolvedValueOnce(task);
|
mockGetTask.mockResolvedValueOnce(task);
|
||||||
mockCreatePr.mockRejectedValueOnce(new Error("No commits between main and kb/kb-001"));
|
mockCreatePr.mockRejectedValueOnce(new Error("No commits between main and fusion/fn-001"));
|
||||||
|
|
||||||
const exitSpy = vi.spyOn(process, "exit").mockImplementation((() => {
|
const exitSpy = vi.spyOn(process, "exit").mockImplementation((() => {
|
||||||
throw new Error("process.exit");
|
throw new Error("process.exit");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
import { Database, createDatabase, toJson, toJsonNullable, fromJson } from "./db.js";
|
import { Database, createDatabase, toJson, toJsonNullable, fromJson } from "./db.js";
|
||||||
|
import { DEFAULT_PROJECT_SETTINGS } from "./types.js";
|
||||||
import { mkdtempSync, existsSync } from "node:fs";
|
import { mkdtempSync, existsSync } from "node:fs";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
@@ -99,7 +100,7 @@ describe("Database", () => {
|
|||||||
expect(row).toBeDefined();
|
expect(row).toBeDefined();
|
||||||
expect(row.nextId).toBe(1);
|
expect(row.nextId).toBe(1);
|
||||||
expect(row.nextWorkflowStepId).toBe(1);
|
expect(row.nextWorkflowStepId).toBe(1);
|
||||||
expect(row.settings).toBe("{}");
|
expect(row.settings).toBe(JSON.stringify(DEFAULT_PROJECT_SETTINGS));
|
||||||
expect(row.workflowSteps).toBe("[]");
|
expect(row.workflowSteps).toBe("[]");
|
||||||
expect(row.updatedAt).toBeTruthy();
|
expect(row.updatedAt).toBeTruthy();
|
||||||
// updatedAt should be a valid ISO timestamp
|
// updatedAt should be a valid ISO timestamp
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import { DatabaseSync } from "node:sqlite";
|
import { DatabaseSync } from "node:sqlite";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { mkdirSync, existsSync } from "node:fs";
|
import { mkdirSync, existsSync } from "node:fs";
|
||||||
|
import { DEFAULT_PROJECT_SETTINGS } from "./types.js";
|
||||||
|
|
||||||
// ── Types ────────────────────────────────────────────────────────────
|
// ── Types ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -283,10 +284,10 @@ export class Database {
|
|||||||
// Run schema migrations
|
// Run schema migrations
|
||||||
this.migrate();
|
this.migrate();
|
||||||
|
|
||||||
// Seed config row idempotently
|
// Seed config row idempotently with default settings
|
||||||
const configNow = new Date().toISOString();
|
const configNow = new Date().toISOString();
|
||||||
this.db.exec(
|
this.db.exec(
|
||||||
`INSERT OR IGNORE INTO config (id, nextId, nextWorkflowStepId, settings, workflowSteps, updatedAt) VALUES (1, 1, 1, '{}', '[]', '${configNow}')`,
|
`INSERT OR IGNORE INTO config (id, nextId, nextWorkflowStepId, settings, workflowSteps, updatedAt) VALUES (1, 1, 1, '${JSON.stringify(DEFAULT_PROJECT_SETTINGS)}', '[]', '${configNow}')`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -696,7 +696,7 @@ export const DEFAULT_PROJECT_SETTINGS: ProjectSettings = {
|
|||||||
worktreeInitCommand: undefined,
|
worktreeInitCommand: undefined,
|
||||||
recycleWorktrees: false,
|
recycleWorktrees: false,
|
||||||
worktreeNaming: "random",
|
worktreeNaming: "random",
|
||||||
taskPrefix: undefined,
|
taskPrefix: "FN",
|
||||||
includeTaskIdInCommit: true,
|
includeTaskIdInCommit: true,
|
||||||
planningProvider: undefined,
|
planningProvider: undefined,
|
||||||
planningModelId: undefined,
|
planningModelId: undefined,
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ export function SettingsModal({
|
|||||||
<input
|
<input
|
||||||
id="taskPrefix"
|
id="taskPrefix"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="KB"
|
placeholder="FN"
|
||||||
value={form.taskPrefix || ""}
|
value={form.taskPrefix || ""}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const val = e.target.value;
|
const val = e.target.value;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe("MergeDetails", () => {
|
|||||||
deletions: 2,
|
deletions: 2,
|
||||||
mergedAt: "2026-01-01T01:00:00.000Z",
|
mergedAt: "2026-01-01T01:00:00.000Z",
|
||||||
prNumber: 42,
|
prNumber: 42,
|
||||||
mergeCommitMessage: "feat(KB-001): merge kb/kb-001",
|
mergeCommitMessage: "feat(FN-001): merge fusion/fn-001",
|
||||||
mergeConfirmed: true,
|
mergeConfirmed: true,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
@@ -44,7 +44,7 @@ describe("MergeDetails", () => {
|
|||||||
expect(screen.getByText("5")).toBeTruthy();
|
expect(screen.getByText("5")).toBeTruthy();
|
||||||
expect(screen.getByText("+10 / -2")).toBeTruthy();
|
expect(screen.getByText("+10 / -2")).toBeTruthy();
|
||||||
expect(screen.getByText("#42")).toBeTruthy();
|
expect(screen.getByText("#42")).toBeTruthy();
|
||||||
expect(screen.getByText("feat(KB-001): merge kb/kb-001")).toBeTruthy();
|
expect(screen.getByText("feat(FN-001): merge fusion/fn-001")).toBeTruthy();
|
||||||
expect(screen.getByText("Merged successfully")).toBeTruthy();
|
expect(screen.getByText("Merged successfully")).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ describe("WorktreePool", () => {
|
|||||||
(c) => typeof c[0] === "string" && (c[0] as string).includes("checkout -B"),
|
(c) => typeof c[0] === "string" && (c[0] as string).includes("checkout -B"),
|
||||||
);
|
);
|
||||||
expect(checkoutCall).toBeDefined();
|
expect(checkoutCall).toBeDefined();
|
||||||
expect(checkoutCall![0]).toBe('git checkout -B "fusion/fn-042" kb/kb-041');
|
expect(checkoutCall![0]).toBe('git checkout -B "fusion/fn-042" fusion/fn-041');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("tolerates git checkout -- . failure (already clean)", () => {
|
it("tolerates git checkout -- . failure (already clean)", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user