feat(KB-330): rename internal packages from @kb/* to @fusion/*
- Rename @kb/core, @kb/dashboard, @kb/engine to @fusion/* namespace - Update all import statements across 143+ files to use new package names - Update workspace dependencies and root package.json references - Fix bundler configurations (tsup, vite) for new package names - Update test files and fix typecheck issues - Add changeset file documenting the package rename
This commit is contained in:
@@ -15,18 +15,18 @@ describe("CLI bundle output", () => {
|
||||
expect(content.startsWith("#!/usr/bin/env node")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not contain bare @kb/* import specifiers", () => {
|
||||
it("does not contain bare @fusion/* import specifiers", () => {
|
||||
const content = readFileSync(bundlePath, "utf-8");
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/core["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/dashboard["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/engine["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@fusion\/core["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@fusion\/dashboard["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@fusion\/engine["']/);
|
||||
});
|
||||
|
||||
it("contains inlined workspace code", () => {
|
||||
const content = readFileSync(bundlePath, "utf-8");
|
||||
// TaskStore from @kb/core
|
||||
// TaskStore from @fusion/core
|
||||
expect(content).toContain("TaskStore");
|
||||
// createServer from @kb/dashboard
|
||||
// createServer from @fusion/dashboard
|
||||
expect(content).toContain("createServer");
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
|
||||
import kbExtension from "../extension.js";
|
||||
import { TaskStore } from "@kb/core";
|
||||
import { TaskStore } from "@fusion/core";
|
||||
|
||||
// ── Mock ExtensionAPI that captures registrations ──────────────────
|
||||
|
||||
|
||||
@@ -75,11 +75,11 @@ describe("CLI package.json publishing config", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scoped @kb/* packages publishing config", () => {
|
||||
describe("Scoped @fusion/* packages publishing config", () => {
|
||||
const scopedPackages = ["core", "engine", "dashboard"];
|
||||
|
||||
for (const name of scopedPackages) {
|
||||
describe(`@kb/${name}`, () => {
|
||||
describe(`@fusion/${name}`, () => {
|
||||
const pkg = loadPackageJson(name);
|
||||
|
||||
it('has publishConfig with access "public"', () => {
|
||||
|
||||
@@ -5,8 +5,8 @@ vi.mock("node:readline/promises", () => ({
|
||||
createInterface: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock @kb/core before importing
|
||||
vi.mock("@kb/core", () => ({
|
||||
// Mock @fusion/core before importing
|
||||
vi.mock("@fusion/core", () => ({
|
||||
TaskStore: vi.fn(),
|
||||
COLUMNS: ["triage", "todo", "in-progress", "in-review", "done", "archived"],
|
||||
COLUMN_LABELS: {
|
||||
@@ -19,8 +19,8 @@ vi.mock("@kb/core", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock @kb/dashboard/planning
|
||||
vi.mock("@kb/dashboard/planning", () => ({
|
||||
// Mock @fusion/dashboard/planning
|
||||
vi.mock("@fusion/dashboard/planning", () => ({
|
||||
createSession: vi.fn(),
|
||||
submitResponse: vi.fn(),
|
||||
RateLimitError: class RateLimitError extends Error {
|
||||
@@ -45,8 +45,8 @@ vi.mock("@kb/dashboard/planning", () => ({
|
||||
|
||||
// Import after mocking
|
||||
import { createInterface } from "node:readline/promises";
|
||||
import { TaskStore } from "@kb/core";
|
||||
import { createSession, submitResponse, RateLimitError, SessionNotFoundError } from "@kb/dashboard/planning";
|
||||
import { TaskStore } from "@fusion/core";
|
||||
import { createSession, submitResponse, RateLimitError, SessionNotFoundError } from "@fusion/dashboard/planning";
|
||||
import { runTaskPlan } from "../commands/task.js";
|
||||
|
||||
describe("runTaskPlan", () => {
|
||||
|
||||
@@ -5,8 +5,8 @@ vi.mock("node:readline/promises", () => ({
|
||||
createInterface: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock @kb/core before importing
|
||||
vi.mock("@kb/core", () => ({
|
||||
// Mock @fusion/core before importing
|
||||
vi.mock("@fusion/core", () => ({
|
||||
TaskStore: vi.fn(),
|
||||
COLUMNS: ["triage", "todo", "in-progress", "in-review", "done", "archived"],
|
||||
COLUMN_LABELS: {
|
||||
@@ -21,7 +21,7 @@ vi.mock("@kb/core", () => ({
|
||||
|
||||
// Import after mocking
|
||||
import { createInterface } from "node:readline/promises";
|
||||
import { TaskStore } from "@kb/core";
|
||||
import { TaskStore } from "@fusion/core";
|
||||
import { runTaskSteer } from "../commands/task.js";
|
||||
|
||||
describe("runTaskSteer", () => {
|
||||
|
||||
@@ -24,9 +24,9 @@ function makeMockStore() {
|
||||
};
|
||||
}
|
||||
|
||||
// ── Mock @kb/core ──────────────────────────────────────────────────
|
||||
// ── Mock @fusion/core ──────────────────────────────────────────────────
|
||||
|
||||
vi.mock("@kb/core", () => ({
|
||||
vi.mock("@fusion/core", () => ({
|
||||
TaskStore: vi.fn().mockImplementation(() => makeMockStore()),
|
||||
AutomationStore: vi.fn().mockImplementation(() => ({
|
||||
init: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -35,7 +35,7 @@ vi.mock("@kb/core", () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
// ── Mock @kb/dashboard ─────────────────────────────────────────────
|
||||
// ── Mock @fusion/dashboard ─────────────────────────────────────────────
|
||||
|
||||
/** Create a mock server (EventEmitter) that simulates net.Server behavior. */
|
||||
function createMockServer(portToReturn: number = 0) {
|
||||
@@ -64,15 +64,15 @@ const MockGitHubClient = vi.fn().mockImplementation(() => ({
|
||||
mergePr: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@kb/dashboard", () => ({
|
||||
vi.mock("@fusion/dashboard", () => ({
|
||||
createServer: vi.fn(() => ({ listen: mockListen })),
|
||||
GitHubClient: MockGitHubClient,
|
||||
}));
|
||||
|
||||
// ── Mock @kb/engine ────────────────────────────────────────────────
|
||||
// ── Mock @fusion/engine ────────────────────────────────────────────────
|
||||
|
||||
vi.mock("@kb/engine", async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import("@kb/engine")>();
|
||||
vi.mock("@fusion/engine", async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import("@fusion/engine")>();
|
||||
return {
|
||||
...original,
|
||||
WorktreePool: original.WorktreePool,
|
||||
@@ -134,12 +134,12 @@ describe("runDashboard — AuthStorage & ModelRegistry wiring", () => {
|
||||
runtime: { pendingProviderRegistrations: [] },
|
||||
errors: [],
|
||||
});
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => makeMockStore());
|
||||
});
|
||||
|
||||
it("passes authStorage and modelRegistry to createServer", async () => {
|
||||
const { createServer } = await import("@kb/dashboard");
|
||||
const { createServer } = await import("@fusion/dashboard");
|
||||
|
||||
await runDashboard(0, {});
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ function makeMockStore() {
|
||||
};
|
||||
}
|
||||
|
||||
// ── Mock @kb/core ──────────────────────────────────────────────────
|
||||
// ── Mock @fusion/core ──────────────────────────────────────────────────
|
||||
|
||||
vi.mock("@kb/core", () => ({
|
||||
vi.mock("@fusion/core", () => ({
|
||||
TaskStore: vi.fn().mockImplementation(() => makeMockStore()),
|
||||
AutomationStore: vi.fn().mockImplementation(() => ({
|
||||
init: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -78,7 +78,7 @@ vi.mock("node:child_process", async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
// ── Mock @kb/dashboard ─────────────────────────────────────────────
|
||||
// ── Mock @fusion/dashboard ─────────────────────────────────────────────
|
||||
|
||||
/** Create a mock server (EventEmitter) that simulates net.Server behavior. */
|
||||
function createMockServer(portToReturn: number = 0) {
|
||||
@@ -100,7 +100,7 @@ const mockListen = vi.fn((port: number) => {
|
||||
return server;
|
||||
});
|
||||
|
||||
vi.mock("@kb/dashboard", () => ({
|
||||
vi.mock("@fusion/dashboard", () => ({
|
||||
createServer: vi.fn(() => ({ listen: mockListen })),
|
||||
GitHubClient: vi.fn().mockImplementation(() => ({
|
||||
findPrForBranch: mockFindPrForBranch,
|
||||
@@ -116,13 +116,13 @@ vi.mock("node:readline", () => ({
|
||||
createInterface: vi.fn(),
|
||||
}));
|
||||
|
||||
// ── Mock @kb/engine ────────────────────────────────────────────────
|
||||
// ── Mock @fusion/engine ────────────────────────────────────────────────
|
||||
|
||||
// We need the real WorktreePool class so we can assert `instanceof`.
|
||||
const { WorktreePool } = await import("@kb/engine");
|
||||
const { WorktreePool } = await import("@fusion/engine");
|
||||
|
||||
vi.mock("@kb/engine", async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import("@kb/engine")>();
|
||||
vi.mock("@fusion/engine", async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import("@fusion/engine")>();
|
||||
return {
|
||||
...original,
|
||||
// Keep real WorktreePool & AgentSemaphore
|
||||
@@ -452,12 +452,12 @@ describe("runDashboard — PR-first auto-merge queue", () => {
|
||||
log: [],
|
||||
});
|
||||
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
});
|
||||
|
||||
it("uses PR lifecycle instead of aiMergeTask when mergeStrategy is pull-request", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
await runDashboard(0, { open: false });
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
@@ -477,10 +477,10 @@ describe("runDashboard — WorktreePool wiring", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
// Re-set TaskStore mock (clearAllMocks wipes implementations)
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => makeMockStore());
|
||||
// Re-set engine mocks
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -500,8 +500,8 @@ describe("runDashboard — WorktreePool wiring", () => {
|
||||
});
|
||||
|
||||
it("passes a WorktreePool instance to aiMergeTask via rawMerge", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { createServer } = await import("@kb/dashboard");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
const { createServer } = await import("@fusion/dashboard");
|
||||
|
||||
await runDashboard(0, { open: false });
|
||||
|
||||
@@ -518,8 +518,8 @@ describe("runDashboard — WorktreePool wiring", () => {
|
||||
});
|
||||
|
||||
it("shares the same WorktreePool instance between executor and merger", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { createServer } = await import("@kb/dashboard");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
const { createServer } = await import("@fusion/dashboard");
|
||||
|
||||
await runDashboard(0, { open: false });
|
||||
|
||||
@@ -545,9 +545,9 @@ describe("runDashboard — auto-merge pause exclusion", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -569,7 +569,7 @@ describe("runDashboard — auto-merge pause exclusion", () => {
|
||||
|
||||
await runDashboard(0, { open: false });
|
||||
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
// Emit task:moved with a paused task
|
||||
mockStore.emit("task:moved", {
|
||||
@@ -596,7 +596,7 @@ describe("runDashboard — auto-merge pause exclusion", () => {
|
||||
{ id: "KB-ACTIVE", column: "in-review", paused: false },
|
||||
]);
|
||||
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
// Reset after import
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
@@ -623,9 +623,9 @@ describe("runDashboard — immediate resume on unpause", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -649,7 +649,7 @@ describe("runDashboard — immediate resume on unpause", () => {
|
||||
});
|
||||
|
||||
it("calls executor.resumeOrphaned() when globalPause transitions true → false", async () => {
|
||||
const { TaskExecutor } = await import("@kb/engine");
|
||||
const { TaskExecutor } = await import("@fusion/engine");
|
||||
const resumeOrphaned = vi.fn().mockResolvedValue(undefined);
|
||||
(TaskExecutor as unknown as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
(_store: unknown, _cwd: unknown, opts: unknown) => {
|
||||
@@ -694,7 +694,7 @@ describe("runDashboard — immediate resume on unpause", () => {
|
||||
paused: false,
|
||||
}));
|
||||
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -729,16 +729,16 @@ describe("runDashboard — engine pause/unpause cycle", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
});
|
||||
|
||||
it("calls executor.resumeOrphaned() when enginePaused transitions true → false", async () => {
|
||||
const { TaskExecutor } = await import("@kb/engine");
|
||||
const { TaskExecutor } = await import("@fusion/engine");
|
||||
const resumeOrphaned = vi.fn().mockResolvedValue(undefined);
|
||||
(TaskExecutor as unknown as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
(_store: unknown, _cwd: unknown, opts: unknown) => {
|
||||
@@ -770,9 +770,9 @@ describe("runDashboard — port fallback on EADDRINUSE", () => {
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => makeMockStore());
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.TaskExecutor as unknown as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
() => ({ resumeOrphaned: vi.fn().mockResolvedValue(undefined) }),
|
||||
);
|
||||
@@ -888,9 +888,9 @@ describe("runDashboard — enginePaused (soft pause)", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -913,7 +913,7 @@ describe("runDashboard — enginePaused (soft pause)", () => {
|
||||
|
||||
await runDashboard(0, { open: false });
|
||||
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
// Emit task:moved
|
||||
mockStore.emit("task:moved", {
|
||||
@@ -928,7 +928,7 @@ describe("runDashboard — enginePaused (soft pause)", () => {
|
||||
});
|
||||
|
||||
it("calls executor.resumeOrphaned() when enginePaused transitions true → false", async () => {
|
||||
const { TaskExecutor } = await import("@kb/engine");
|
||||
const { TaskExecutor } = await import("@fusion/engine");
|
||||
const resumeOrphaned = vi.fn().mockResolvedValue(undefined);
|
||||
(TaskExecutor as unknown as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
(_store: unknown, _cwd: unknown, opts: unknown) => {
|
||||
@@ -971,7 +971,7 @@ describe("runDashboard — enginePaused (soft pause)", () => {
|
||||
paused: false,
|
||||
}));
|
||||
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -1003,9 +1003,9 @@ describe("runDashboard — --paused flag", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -1064,9 +1064,9 @@ describe("runDashboard — --paused flag", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.TaskExecutor as unknown as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
() => ({ resumeOrphaned: vi.fn().mockResolvedValue(undefined) }),
|
||||
);
|
||||
@@ -1117,9 +1117,9 @@ describe("runDashboard — --dev mode", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -1137,25 +1137,25 @@ describe("runDashboard — --dev mode", () => {
|
||||
});
|
||||
|
||||
it("does NOT start TriageProcessor in dev mode", async () => {
|
||||
const { TriageProcessor } = await import("@kb/engine");
|
||||
const { TriageProcessor } = await import("@fusion/engine");
|
||||
await runDashboard(0, { open: false, dev: true });
|
||||
expect(TriageProcessor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does NOT start TaskExecutor in dev mode", async () => {
|
||||
const { TaskExecutor } = await import("@kb/engine");
|
||||
const { TaskExecutor } = await import("@fusion/engine");
|
||||
await runDashboard(0, { open: false, dev: true });
|
||||
expect(TaskExecutor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does NOT start Scheduler in dev mode", async () => {
|
||||
const { Scheduler } = await import("@kb/engine");
|
||||
const { Scheduler } = await import("@fusion/engine");
|
||||
await runDashboard(0, { open: false, dev: true });
|
||||
expect(Scheduler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("starts the server correctly in dev mode", async () => {
|
||||
const { createServer } = await import("@kb/dashboard");
|
||||
const { createServer } = await import("@fusion/dashboard");
|
||||
await runDashboard(4040, { open: false, dev: true });
|
||||
|
||||
// Wait for async 'listening' event
|
||||
@@ -1201,7 +1201,7 @@ describe("runDashboard — --dev mode", () => {
|
||||
});
|
||||
|
||||
it("starts all engine components when dev is false (default)", async () => {
|
||||
const { TriageProcessor, TaskExecutor, Scheduler } = await import("@kb/engine");
|
||||
const { TriageProcessor, TaskExecutor, Scheduler } = await import("@fusion/engine");
|
||||
await runDashboard(0, { open: false });
|
||||
|
||||
expect(TriageProcessor).toHaveBeenCalled();
|
||||
@@ -1231,7 +1231,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
vi.clearAllMocks();
|
||||
resetGitHubMocks();
|
||||
mockStore = makeMockStore();
|
||||
const { TaskStore } = await import("@kb/core");
|
||||
const { TaskStore } = await import("@fusion/core");
|
||||
(TaskStore as ReturnType<typeof vi.fn>).mockImplementation(() => mockStore);
|
||||
|
||||
// Default mock store.getTask implementation
|
||||
@@ -1242,7 +1242,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
mergeRetries: 0,
|
||||
}));
|
||||
|
||||
const engine = await import("@kb/engine");
|
||||
const engine = await import("@fusion/engine");
|
||||
(engine.aiMergeTask as ReturnType<typeof vi.fn>).mockImplementation(() =>
|
||||
Promise.resolve({ merged: true }),
|
||||
);
|
||||
@@ -1260,7 +1260,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
});
|
||||
|
||||
it("increments mergeRetries and re-enqueues on conflict error", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
// Simulate merge failure with conflict
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockRejectedValue(
|
||||
@@ -1300,7 +1300,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
});
|
||||
|
||||
it("gives up after max retries (3) exceeded", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockRejectedValue(
|
||||
new Error("Merge conflict detected"),
|
||||
@@ -1347,7 +1347,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
});
|
||||
|
||||
it("skips retry when autoResolveConflicts is disabled", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockRejectedValue(
|
||||
new Error("Merge conflict detected"),
|
||||
@@ -1381,7 +1381,7 @@ describe("runDashboard — merge conflict retry logic", () => {
|
||||
});
|
||||
|
||||
it("clears mergeRetries on successful merge after retries", async () => {
|
||||
const { aiMergeTask } = await import("@kb/engine");
|
||||
const { aiMergeTask } = await import("@fusion/engine");
|
||||
|
||||
(aiMergeTask as ReturnType<typeof vi.fn>).mockResolvedValue({ merged: true });
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { createInterface } from "node:readline";
|
||||
import { TaskStore, AutomationStore } from "@kb/core";
|
||||
import type { Settings, TaskDetail, PrInfo } from "@kb/core";
|
||||
import { createServer, GitHubClient } from "@kb/dashboard";
|
||||
import { TriageProcessor, TaskExecutor, Scheduler, AgentSemaphore, WorktreePool, aiMergeTask, UsageLimitPauser, PRIORITY_MERGE, scanIdleWorktrees, cleanupOrphanedWorktrees, NtfyNotifier, PrMonitor, PrCommentHandler, CronRunner, StuckTaskDetector } from "@kb/engine";
|
||||
import { TaskStore, AutomationStore } from "@fusion/core";
|
||||
import type { Settings, TaskDetail, PrInfo } from "@fusion/core";
|
||||
import { createServer, GitHubClient } from "@fusion/dashboard";
|
||||
import { TriageProcessor, TaskExecutor, Scheduler, AgentSemaphore, WorktreePool, aiMergeTask, UsageLimitPauser, PRIORITY_MERGE, scanIdleWorktrees, cleanupOrphanedWorktrees, NtfyNotifier, PrMonitor, PrCommentHandler, CronRunner, StuckTaskDetector } from "@fusion/engine";
|
||||
import { AuthStorage, ModelRegistry, discoverAndLoadExtensions, createExtensionRuntime } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
|
||||
// Mock @kb/core before importing the module under test
|
||||
vi.mock("@kb/core", () => {
|
||||
// Mock @fusion/core before importing the module under test
|
||||
vi.mock("@fusion/core", () => {
|
||||
const DEFAULT_SETTINGS = {
|
||||
maxConcurrent: 2,
|
||||
maxWorktrees: 4,
|
||||
@@ -21,7 +21,7 @@ vi.mock("@kb/core", () => {
|
||||
};
|
||||
});
|
||||
|
||||
import { TaskStore, DEFAULT_SETTINGS } from "@kb/core";
|
||||
import { TaskStore, DEFAULT_SETTINGS } from "@fusion/core";
|
||||
import {
|
||||
runSettingsShow,
|
||||
runSettingsSet,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TaskStore, type Settings, DEFAULT_SETTINGS } from "@kb/core";
|
||||
import { TaskStore, type Settings, DEFAULT_SETTINGS } from "@fusion/core";
|
||||
|
||||
// Settings that can be updated via CLI
|
||||
export const VALID_SETTINGS = [
|
||||
|
||||
@@ -14,8 +14,8 @@ vi.mock("node:fs", () => ({
|
||||
readFileSync: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock @kb/core before importing the module under test
|
||||
vi.mock("@kb/core", () => {
|
||||
// Mock @fusion/core before importing the module under test
|
||||
vi.mock("@fusion/core", () => {
|
||||
const COLUMNS = ["triage", "specified", "in-progress", "review", "done"];
|
||||
const COLUMN_LABELS: Record<string, string> = {
|
||||
triage: "Triage",
|
||||
@@ -32,29 +32,29 @@ vi.mock("@kb/core", () => {
|
||||
};
|
||||
});
|
||||
|
||||
// Mock @kb/engine
|
||||
vi.mock("@kb/engine", () => ({ aiMergeTask: vi.fn() }));
|
||||
// Mock @fusion/engine
|
||||
vi.mock("@fusion/engine", () => ({ aiMergeTask: vi.fn() }));
|
||||
|
||||
// Mock @kb/dashboard
|
||||
vi.mock("@kb/dashboard", () => ({
|
||||
// Mock @fusion/dashboard
|
||||
vi.mock("@fusion/dashboard", () => ({
|
||||
GitHubClient: vi.fn().mockImplementation(() => ({
|
||||
createPr: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock @kb/core/gh-cli
|
||||
vi.mock("@kb/core/gh-cli", () => ({
|
||||
// Mock @fusion/core/gh-cli
|
||||
vi.mock("@fusion/core/gh-cli", () => ({
|
||||
isGhAvailable: vi.fn(),
|
||||
isGhAuthenticated: vi.fn(),
|
||||
getCurrentRepo: vi.fn(),
|
||||
}));
|
||||
|
||||
import { createInterface } from "node:readline/promises";
|
||||
import { TaskStore } from "@kb/core";
|
||||
import { TaskStore } from "@fusion/core";
|
||||
import { watchFile, unwatchFile, statSync, existsSync, readFileSync } from "node:fs";
|
||||
import { runTaskShow, runTaskCreate, runTaskDuplicate, runTaskRefine, runTaskDelete, runTaskRetry, runTaskLogs, runTaskPrCreate, type LogsOptions } from "./task.js";
|
||||
import { isGhAvailable, isGhAuthenticated, getCurrentRepo } from "@kb/core/gh-cli";
|
||||
import { GitHubClient } from "@kb/dashboard";
|
||||
import { isGhAvailable, isGhAuthenticated, getCurrentRepo } from "@fusion/core/gh-cli";
|
||||
import { GitHubClient } from "@fusion/dashboard";
|
||||
|
||||
function makeTask(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
@@ -1299,7 +1299,7 @@ describe("runTaskLogs", () => {
|
||||
let mockReadFileSync: ReturnType<typeof vi.fn>;
|
||||
let sigintHandlers: Array<() => void> = [];
|
||||
|
||||
function makeAgentLogEntry(overrides: Record<string, unknown> = {}): import("@kb/core").AgentLogEntry {
|
||||
function makeAgentLogEntry(overrides: Record<string, unknown> = {}): import("@fusion/core").AgentLogEntry {
|
||||
return {
|
||||
timestamp: new Date().toISOString(),
|
||||
taskId: "KB-001",
|
||||
@@ -1461,7 +1461,7 @@ describe("runTaskLogs", () => {
|
||||
it("filters by type with --limit combined", async () => {
|
||||
mockGetTask.mockResolvedValueOnce(makeTask({ id: "KB-001" }));
|
||||
// Create 50 tool entries interspersed with text entries
|
||||
const entries: import("@kb/core").AgentLogEntry[] = [];
|
||||
const entries: import("@fusion/core").AgentLogEntry[] = [];
|
||||
for (let i = 0; i < 100; i++) {
|
||||
entries.push(makeAgentLogEntry({
|
||||
type: i % 2 === 0 ? "tool" : "text",
|
||||
@@ -1599,7 +1599,7 @@ describe("runTaskLogs", () => {
|
||||
|
||||
// ── PR Create Tests ───────────────────────────────────────────────────────────
|
||||
|
||||
import type { PrInfo } from "@kb/core";
|
||||
import type { PrInfo } from "@fusion/core";
|
||||
|
||||
describe("runTaskPrCreate", () => {
|
||||
let logSpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { TaskStore, COLUMNS, COLUMN_LABELS, type Column, type MergeResult, type StepStatus, type AgentLogType, type AgentLogEntry } from "@kb/core";
|
||||
import { aiMergeTask } from "@kb/engine";
|
||||
import { TaskStore, COLUMNS, COLUMN_LABELS, type Column, type MergeResult, type StepStatus, type AgentLogType, type AgentLogEntry } from "@fusion/core";
|
||||
import { aiMergeTask } from "@fusion/engine";
|
||||
import { createInterface } from "node:readline/promises";
|
||||
import type { PlanningQuestion, PlanningSummary } from "@kb/core";
|
||||
import { createSession, submitResponse, RateLimitError, SessionNotFoundError, InvalidSessionStateError } from "@kb/dashboard/planning";
|
||||
import type { PlanningQuestion, PlanningSummary } from "@fusion/core";
|
||||
import { createSession, submitResponse, RateLimitError, SessionNotFoundError, InvalidSessionStateError } from "@fusion/dashboard/planning";
|
||||
import { watchFile, unwatchFile, statSync, existsSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { GitHubClient } from "@kb/dashboard";
|
||||
import { isGhAvailable, isGhAuthenticated, getCurrentRepo } from "@kb/core/gh-cli";
|
||||
import { GitHubClient } from "@fusion/dashboard";
|
||||
import { isGhAvailable, isGhAuthenticated, getCurrentRepo } from "@fusion/core/gh-cli";
|
||||
|
||||
const STEP_STATUSES: StepStatus[] = ["pending", "in-progress", "done", "skipped"];
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
COLUMN_LABELS,
|
||||
type Column,
|
||||
type Task,
|
||||
} from "@kb/core";
|
||||
} from "@fusion/core";
|
||||
import { resolve, basename, extname } from "node:path";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { spawn, type ChildProcess } from "node:child_process";
|
||||
|
||||
Reference in New Issue
Block a user