feat(FN-2924): merge fusion/fn-2924
- Add task provenance display to TaskDetailModal, surfacing AI-generated merge commit summaries so users understand when and why tasks landed - New `ai-summarize` module in core with structured commit summarization logic and tests - Extend CLI `fn task show` with provenance output - Refactor merger to produce cleaner merge commit messages with task context - Update SettingsModal to expose AI summarization toggle (hidden behind feature flag) - Adjust QuickChatFAB styling for theme compatibility - Update scheduler and node-routing policy tests to match new behavior - Add changeset for `@runfusion/fusion` minor release Commits merged: - feat(FN-2924): display task provenance in dashboard and cli - feat(FN-2971): merge fusion/fn-2971 - feat(FN-2947): merge fusion/fn-2947 - feat(FN-2970): merge fusion/fn-2970 - feat(FN-2956): merge fusion/fn-2956 Files changed: .changeset/add-ai-merge-commit-summary.md | 5 + docs/cli-reference.md | 3 +- docs/settings-reference.md | 3 + packages/cli/src/commands/__tests__/task.test.ts | 44 ++++- packages/cli/src/commands/task.ts | 55 +++++++ packages/core/src/__tests__/ai-summarize.test.ts | 64 ++++++++ packages/core/src/ai-summarize.ts | 114 +++++++++++++ packages/core/src/index.ts | 3 + packages/core/src/settings-schema.ts | 1 + packages/core/src/types.ts | 4 + packages/dashboard/app/components/QuickChatFAB.css | 17 +- packages/dashboard/app/components/QuickChatFAB.tsx | 2 +- .../dashboard/app/components/SettingsModal.css | 11 +- .../dashboard/app/components/SettingsModal.tsx | 22 ++- .../dashboard/app/components/TaskDetailModal.css | 40 +++++ .../dashboard/app/components/TaskDetailModal.tsx | 82 +++++++++- .../__tests__/SettingsModalNodeRouting.test.tsx | 12 +- .../components/__tests__/TaskDetailModal.test.tsx | 81 ++++++++- packages/engine/src/__tests__/merger.test.ts | 75 +++++++++ .../src/__tests__/node-routing-policy.test.ts | 25 ++- .../src/__tests__/scheduler-node-routing.test.ts | 18 +- packages/engine/src/merger.ts | 181 +++++++++------------ packages/engine/src/scheduler.ts | 8 +- 23 files changed, 723 insertions(+), 147 deletions(-) Fusion-Task-Id: FN-2924
This commit is contained in:
@@ -113,6 +113,13 @@ function makeTask(overrides: Record<string, unknown> = {}) {
|
||||
describe("runTaskShow", () => {
|
||||
let logSpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
const mockTaskStoreGetTask = (task: Record<string, unknown>) => {
|
||||
(TaskStore as unknown as ReturnType<typeof vi.fn>).mockImplementation(() => ({
|
||||
init: vi.fn(),
|
||||
getTask: vi.fn().mockResolvedValue(task),
|
||||
}));
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
});
|
||||
@@ -125,10 +132,7 @@ describe("runTaskShow", () => {
|
||||
const longDesc = "A".repeat(120); // well over 60 chars
|
||||
const task = makeTask({ description: longDesc });
|
||||
|
||||
(TaskStore as unknown as ReturnType<typeof vi.fn>).mockImplementation(() => ({
|
||||
init: vi.fn(),
|
||||
getTask: vi.fn().mockResolvedValue(task),
|
||||
}));
|
||||
mockTaskStoreGetTask(task);
|
||||
|
||||
await runTaskShow("FN-001");
|
||||
|
||||
@@ -148,10 +152,7 @@ describe("runTaskShow", () => {
|
||||
description: "This is the full description that should not appear in the header",
|
||||
});
|
||||
|
||||
(TaskStore as unknown as ReturnType<typeof vi.fn>).mockImplementation(() => ({
|
||||
init: vi.fn(),
|
||||
getTask: vi.fn().mockResolvedValue(task),
|
||||
}));
|
||||
mockTaskStoreGetTask(task);
|
||||
|
||||
await runTaskShow("FN-001");
|
||||
|
||||
@@ -162,6 +163,33 @@ describe("runTaskShow", () => {
|
||||
expect(headerLine![0]).toContain("My Task Title");
|
||||
expect(headerLine![0]).not.toContain("This is the full description");
|
||||
});
|
||||
|
||||
it.each([
|
||||
[{ sourceType: "dashboard_ui" }, "Source: Dashboard"],
|
||||
[{ sourceType: "agent_heartbeat", sourceAgentId: "agent-123" }, "Source: Agent (agent-123)"],
|
||||
[{ sourceType: "task_refine", sourceParentTaskId: "FN-2904" }, "Source: Refinement of FN-2904"],
|
||||
[{ sourceType: "task_duplicate", sourceParentTaskId: "FN-2905" }, "Source: Duplicate of FN-2905"],
|
||||
[
|
||||
{ sourceType: "github_import", sourceMetadata: { issueUrl: "https://github.com/owner/repo/issues/42" } },
|
||||
"Source: GitHub Import (https://github.com/owner/repo/issues/42)",
|
||||
],
|
||||
] as const)("prints provenance line for %o", async (overrides, expectedLine) => {
|
||||
mockTaskStoreGetTask(makeTask(overrides));
|
||||
|
||||
await runTaskShow("FN-001");
|
||||
|
||||
const output = logSpy.mock.calls.map((call) => String(call[0])).join("\n");
|
||||
expect(output).toContain(expectedLine);
|
||||
});
|
||||
|
||||
it.each([{ sourceType: "unknown" }, {}])("omits provenance line for %o", async (overrides) => {
|
||||
mockTaskStoreGetTask(makeTask(overrides));
|
||||
|
||||
await runTaskShow("FN-001");
|
||||
|
||||
const output = logSpy.mock.calls.map((call) => String(call[0])).join("\n");
|
||||
expect(output).not.toContain("Source:");
|
||||
});
|
||||
});
|
||||
|
||||
describe("task node overrides", () => {
|
||||
|
||||
Reference in New Issue
Block a user