@runfusion/fusion 0.9.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +7418 -5792
- package/dist/client/assets/AgentDetailView-B5tq9ius.css +1 -0
- package/dist/client/assets/AgentDetailView-DQBjJSPJ.js +18 -0
- package/dist/client/assets/AgentsView-DlA0yHBg.js +522 -0
- package/dist/client/assets/AgentsView-xm_3NO4M.css +1 -0
- package/dist/client/assets/ChatView-DK5CmiAk.js +1 -0
- package/dist/client/assets/{DevServerView-LOrDrAYm.js → DevServerView-BVixhlF0.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-Bgp6PCbu.js → DirectoryPicker-tvBgHxa7.js} +1 -1
- package/dist/client/assets/{DocumentsView-CNbnZ7Q3.js → DocumentsView-DVw_wT6V.js} +1 -1
- package/dist/client/assets/{InsightsView-CmJwV-ZC.js → InsightsView-G3MZhwSx.js} +2 -2
- package/dist/client/assets/{MemoryView-Bwi5p79s.js → MemoryView-Bl9gx2Dw.js} +2 -2
- package/dist/client/assets/{NodesView-1pZii99I.js → NodesView-dwVhD4V2.js} +4 -4
- package/dist/client/assets/{PiExtensionsManager-CokhM-MB.js → PiExtensionsManager-CEHp6_Mj.js} +3 -3
- package/dist/client/assets/PluginManager-Dx0mcwat.js +1 -0
- package/dist/client/assets/ResearchView-BvlLYC_1.js +1 -0
- package/dist/client/assets/{RoadmapsView-BTo3BT0I.js → RoadmapsView-DdYXssP2.js} +2 -2
- package/dist/client/assets/SettingsModal-Bgjg_4CD.js +31 -0
- package/dist/client/assets/{SettingsModal-D5slUUsC.js → SettingsModal-CGWipm3s.js} +1 -1
- package/dist/client/assets/SettingsModal-CriZP5Lp.css +1 -0
- package/dist/client/assets/{SetupWizardModal-1qSn8Yl0.js → SetupWizardModal-CKsJduYM.js} +1 -1
- package/dist/client/assets/{SkillsView-CY3I5OYc.js → SkillsView-C4Tz7CxC.js} +1 -1
- package/dist/client/assets/{TodoView-B1GDwwhR.js → TodoView-ByXJ90yL.js} +2 -2
- package/dist/client/assets/{folder-open-DPESt6bg.js → folder-open-CxOUgHDf.js} +1 -1
- package/dist/client/assets/index-BCz4ye4p.css +1 -0
- package/dist/client/assets/index-D7gT6mCr.js +656 -0
- package/dist/client/assets/{list-checks-D7D9kx7Y.js → list-checks--sf9u9ox.js} +1 -1
- package/dist/client/assets/{star-C59_6aNu.js → star-CF1f2iPu.js} +1 -1
- package/dist/client/assets/{upload-1I0eQddJ.js → upload-rOBd4OhB.js} +1 -1
- package/dist/client/assets/{users-DH50eBCX.js → users-De-vFat1.js} +1 -1
- package/dist/client/fonts/SymbolsNerdFontMono-Regular.ttf +0 -0
- package/dist/client/index.html +16 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +20717 -19343
- package/dist/pi-claude-cli/index.ts +31 -5
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/__tests__/process-manager.test.ts +90 -0
- package/dist/pi-claude-cli/src/__tests__/provider.test.ts +13 -3
- package/dist/pi-claude-cli/src/process-manager.ts +65 -0
- package/package.json +1 -1
- package/skill/fusion/SKILL.md +2 -0
- package/skill/fusion/references/engine-tools.md +4 -0
- package/skill/fusion/references/extension-tools.md +76 -0
- package/skill/fusion/references/fusion-capabilities.md +8 -0
- package/dist/client/assets/AgentDetailView-5W1q48YS.js +0 -18
- package/dist/client/assets/AgentDetailView-DIBOY8V-.css +0 -1
- package/dist/client/assets/AgentsView-DcEnemu0.js +0 -522
- package/dist/client/assets/AgentsView-MotzGhZJ.css +0 -1
- package/dist/client/assets/ChatView-CTc6mP8y.js +0 -1
- package/dist/client/assets/PluginManager-cHaGKMgY.js +0 -1
- package/dist/client/assets/ResearchView-CQDI2y7Q.js +0 -1
- package/dist/client/assets/SettingsModal-EEQwF0Ql.js +0 -31
- package/dist/client/assets/SettingsModal-FfIAhzcJ.css +0 -1
- package/dist/client/assets/index-2_pvFDiN.css +0 -1
- package/dist/client/assets/index-DNIrnlpO.js +0 -656
|
@@ -9,8 +9,8 @@ import { getModels } from "@mariozechner/pi-ai";
|
|
|
9
9
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
10
|
import { streamViaCli } from "./src/provider.js";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
validateCliPresenceAsync,
|
|
13
|
+
validateCliAuthAsync,
|
|
14
14
|
killAllProcesses,
|
|
15
15
|
} from "./src/process-manager.js";
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
@@ -26,6 +26,31 @@ process.on("exit", killAllProcesses);
|
|
|
26
26
|
|
|
27
27
|
const PROVIDER_ID = "pi-claude-cli";
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Run CLI presence + auth probes at most once per process, asynchronously.
|
|
31
|
+
*
|
|
32
|
+
* The factory below is invoked on every `createFnAgent` call (the dashboard
|
|
33
|
+
* does this per chat message). Doing the probes synchronously with execSync
|
|
34
|
+
* froze the entire Node event loop for a few seconds while `claude` cold-
|
|
35
|
+
* started. Memoizing as a Promise + spawning the probes async means the
|
|
36
|
+
* factory returns immediately and other requests keep flowing; the result
|
|
37
|
+
* is logged once on first run and reused thereafter.
|
|
38
|
+
*/
|
|
39
|
+
let cliValidationPromise: Promise<void> | undefined;
|
|
40
|
+
|
|
41
|
+
function runCliValidationOnce(): Promise<void> {
|
|
42
|
+
if (cliValidationPromise) return cliValidationPromise;
|
|
43
|
+
cliValidationPromise = (async () => {
|
|
44
|
+
const presence = await validateCliPresenceAsync();
|
|
45
|
+
if (!presence.ok) {
|
|
46
|
+
console.warn(`[pi-claude-cli] ${presence.error.message}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
await validateCliAuthAsync();
|
|
50
|
+
})();
|
|
51
|
+
return cliValidationPromise;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
let cachedMcpConfig: { hash: string; configPath: string } | undefined;
|
|
30
55
|
const DEBUG_MCP = process.env.PI_CLAUDE_CLI_DEBUG === "1";
|
|
31
56
|
|
|
@@ -116,9 +141,10 @@ function ensureMcpConfig(
|
|
|
116
141
|
|
|
117
142
|
export default function (pi: ExtensionAPI) {
|
|
118
143
|
try {
|
|
119
|
-
// Startup validation
|
|
120
|
-
|
|
121
|
-
|
|
144
|
+
// Startup validation: kick off async, memoized presence + auth probes
|
|
145
|
+
// without blocking the factory. Failures surface via warnings; the actual
|
|
146
|
+
// `claude` subprocess in streamViaCli still reports hard errors on send.
|
|
147
|
+
void runCliValidationOnce();
|
|
122
148
|
|
|
123
149
|
const catalogModels = getModels("anthropic").map((model) => ({
|
|
124
150
|
id: model.id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion/pi-claude-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Fusion vendored fork: pi coding-agent extension that routes LLM calls through the Claude Code CLI. Forked from rchern/pi-claude-cli (MIT). See UPSTREAM.md.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": true,
|
|
@@ -47,6 +47,8 @@ import {
|
|
|
47
47
|
captureStderr,
|
|
48
48
|
validateCliPresence,
|
|
49
49
|
validateCliAuth,
|
|
50
|
+
validateCliPresenceAsync,
|
|
51
|
+
validateCliAuthAsync,
|
|
50
52
|
forceKillProcess,
|
|
51
53
|
registerProcess,
|
|
52
54
|
killAllProcesses,
|
|
@@ -407,6 +409,94 @@ describe("validateCliAuth", () => {
|
|
|
407
409
|
});
|
|
408
410
|
});
|
|
409
411
|
|
|
412
|
+
describe("validateCliPresenceAsync", () => {
|
|
413
|
+
beforeEach(() => {
|
|
414
|
+
vi.clearAllMocks();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("resolves ok=true when claude --version exits 0", async () => {
|
|
418
|
+
const EventEmitter = require("node:events");
|
|
419
|
+
(spawn as any).mockImplementationOnce(() => {
|
|
420
|
+
const proc = new EventEmitter();
|
|
421
|
+
proc.kill = vi.fn();
|
|
422
|
+
setImmediate(() => proc.emit("exit", 0));
|
|
423
|
+
return proc;
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
const result = await validateCliPresenceAsync();
|
|
427
|
+
expect(result).toEqual({ ok: true });
|
|
428
|
+
const args = (spawn as any).mock.calls[0][1] as string[];
|
|
429
|
+
expect(args).toEqual(["--version"]);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it("resolves ok=false with install message when spawn errors", async () => {
|
|
433
|
+
const EventEmitter = require("node:events");
|
|
434
|
+
(spawn as any).mockImplementationOnce(() => {
|
|
435
|
+
const proc = new EventEmitter();
|
|
436
|
+
proc.kill = vi.fn();
|
|
437
|
+
setImmediate(() => proc.emit("error", new Error("ENOENT")));
|
|
438
|
+
return proc;
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const result = await validateCliPresenceAsync();
|
|
442
|
+
expect(result.ok).toBe(false);
|
|
443
|
+
if (!result.ok) {
|
|
444
|
+
expect(result.error.message).toContain("Claude Code CLI not found");
|
|
445
|
+
expect(result.error.message).toContain("npm install");
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it("resolves ok=false when claude --version exits non-zero", async () => {
|
|
450
|
+
const EventEmitter = require("node:events");
|
|
451
|
+
(spawn as any).mockImplementationOnce(() => {
|
|
452
|
+
const proc = new EventEmitter();
|
|
453
|
+
proc.kill = vi.fn();
|
|
454
|
+
setImmediate(() => proc.emit("exit", 1));
|
|
455
|
+
return proc;
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const result = await validateCliPresenceAsync();
|
|
459
|
+
expect(result.ok).toBe(false);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe("validateCliAuthAsync", () => {
|
|
464
|
+
beforeEach(() => {
|
|
465
|
+
vi.clearAllMocks();
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
it("resolves true when claude auth status exits 0", async () => {
|
|
469
|
+
const EventEmitter = require("node:events");
|
|
470
|
+
(spawn as any).mockImplementationOnce(() => {
|
|
471
|
+
const proc = new EventEmitter();
|
|
472
|
+
proc.kill = vi.fn();
|
|
473
|
+
setImmediate(() => proc.emit("exit", 0));
|
|
474
|
+
return proc;
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
expect(await validateCliAuthAsync()).toBe(true);
|
|
478
|
+
const args = (spawn as any).mock.calls[0][1] as string[];
|
|
479
|
+
expect(args).toEqual(["auth", "status"]);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it("resolves false and warns when claude auth status fails", async () => {
|
|
483
|
+
const EventEmitter = require("node:events");
|
|
484
|
+
(spawn as any).mockImplementationOnce(() => {
|
|
485
|
+
const proc = new EventEmitter();
|
|
486
|
+
proc.kill = vi.fn();
|
|
487
|
+
setImmediate(() => proc.emit("exit", 1));
|
|
488
|
+
return proc;
|
|
489
|
+
});
|
|
490
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
491
|
+
|
|
492
|
+
expect(await validateCliAuthAsync()).toBe(false);
|
|
493
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
494
|
+
expect.stringContaining("not authenticated"),
|
|
495
|
+
);
|
|
496
|
+
warnSpy.mockRestore();
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
410
500
|
describe("CLI flags", () => {
|
|
411
501
|
beforeEach(() => {
|
|
412
502
|
vi.clearAllMocks();
|
|
@@ -168,10 +168,10 @@ describe("provider registration (default export)", () => {
|
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
-
describe("streamViaCli", () => {
|
|
171
|
+
describe("streamViaCli", { timeout: 90_000 }, () => {
|
|
172
172
|
beforeEach(() => {
|
|
173
173
|
vi.clearAllMocks();
|
|
174
|
-
vi.useFakeTimers();
|
|
174
|
+
vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout"] });
|
|
175
175
|
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
176
176
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
177
177
|
delete process.env.PI_CLAUDE_CLI_DEBUG;
|
|
@@ -183,7 +183,7 @@ describe("streamViaCli", () => {
|
|
|
183
183
|
delete process.env.PI_CLAUDE_CLI_DEBUG;
|
|
184
184
|
});
|
|
185
185
|
|
|
186
|
-
it("returns an AssistantMessageEventStream", () => {
|
|
186
|
+
it("returns an AssistantMessageEventStream", async () => {
|
|
187
187
|
const model = mockModels[0] as any;
|
|
188
188
|
const context = {
|
|
189
189
|
messages: [{ role: "user", content: "Hello" }],
|
|
@@ -194,6 +194,16 @@ describe("streamViaCli", () => {
|
|
|
194
194
|
expect(result).toBeDefined();
|
|
195
195
|
expect(result.push).toBeDefined();
|
|
196
196
|
expect(result.end).toBeDefined();
|
|
197
|
+
|
|
198
|
+
// Ensure the spawned process/readline lifecycle completes so fake timers
|
|
199
|
+
// don't leave the test hanging on the inactivity timeout.
|
|
200
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
201
|
+
const proc = (spawn as any).mock.results[0].value;
|
|
202
|
+
proc.stdout.write(
|
|
203
|
+
`${JSON.stringify({ type: "result", subtype: "success", result: "ok" })}\n`,
|
|
204
|
+
);
|
|
205
|
+
proc.stdout.end();
|
|
206
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
197
207
|
});
|
|
198
208
|
|
|
199
209
|
it("logs PID and spawn args when debug mode is enabled", async () => {
|
|
@@ -241,3 +241,68 @@ export function validateCliAuth(): boolean {
|
|
|
241
241
|
return false;
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Run a one-shot `claude <args>` and resolve to the exit code.
|
|
247
|
+
*
|
|
248
|
+
* Why: the sync execSync variants block the Node event loop for the duration
|
|
249
|
+
* of a Claude CLI cold start (1–3s, occasionally longer). When pi-claude-cli's
|
|
250
|
+
* factory is invoked from a per-request createFnAgent path (Fusion dashboard
|
|
251
|
+
* does this on every chat send), those sync probes freeze every other request.
|
|
252
|
+
* This async variant uses spawn so the loop keeps turning while the subprocess
|
|
253
|
+
* starts up.
|
|
254
|
+
*/
|
|
255
|
+
function runClaudeProbe(args: string[], timeoutMs = 5000): Promise<number> {
|
|
256
|
+
return new Promise((resolve) => {
|
|
257
|
+
const proc = spawn("claude", args, { stdio: "ignore" });
|
|
258
|
+
const timer = setTimeout(() => {
|
|
259
|
+
try {
|
|
260
|
+
proc.kill("SIGKILL");
|
|
261
|
+
} catch {
|
|
262
|
+
// already dead
|
|
263
|
+
}
|
|
264
|
+
resolve(124);
|
|
265
|
+
}, timeoutMs);
|
|
266
|
+
proc.once("error", () => {
|
|
267
|
+
clearTimeout(timer);
|
|
268
|
+
resolve(127);
|
|
269
|
+
});
|
|
270
|
+
proc.once("exit", (code) => {
|
|
271
|
+
clearTimeout(timer);
|
|
272
|
+
resolve(code ?? 1);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Async, non-blocking variant of validateCliPresence.
|
|
279
|
+
* Resolves with `{ok: true}` on success, `{ok: false, error}` on failure —
|
|
280
|
+
* never rejects, so callers can fire-and-forget without unhandled rejections.
|
|
281
|
+
*/
|
|
282
|
+
export async function validateCliPresenceAsync(): Promise<
|
|
283
|
+
{ ok: true } | { ok: false; error: Error }
|
|
284
|
+
> {
|
|
285
|
+
const code = await runClaudeProbe(["--version"]);
|
|
286
|
+
if (code === 0) return { ok: true };
|
|
287
|
+
return {
|
|
288
|
+
ok: false,
|
|
289
|
+
error: new Error(
|
|
290
|
+
"Claude Code CLI not found. Install it: npm install -g @anthropic-ai/claude-code\n" +
|
|
291
|
+
"Then authenticate: claude auth login",
|
|
292
|
+
),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Async, non-blocking variant of validateCliAuth.
|
|
298
|
+
* Returns true if authenticated. Logs a warning (does not throw) otherwise.
|
|
299
|
+
*/
|
|
300
|
+
export async function validateCliAuthAsync(): Promise<boolean> {
|
|
301
|
+
const code = await runClaudeProbe(["auth", "status"]);
|
|
302
|
+
if (code === 0) return true;
|
|
303
|
+
console.warn(
|
|
304
|
+
"[pi-claude-cli] Claude CLI is not authenticated. " +
|
|
305
|
+
"Run 'claude auth login' to authenticate.",
|
|
306
|
+
);
|
|
307
|
+
return false;
|
|
308
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runfusion/fusion",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Fusion CLI: HTTP API server, daemon, dashboard launcher, and task tooling for the Fusion AI coding agent.",
|
|
6
6
|
"homepage": "https://github.com/Runfusion/Fusion#readme",
|
package/skill/fusion/SKILL.md
CHANGED
|
@@ -32,6 +32,8 @@ Mission → Milestone → Slice → Feature → Task
|
|
|
32
32
|
- **Mission tools** — `fn_mission_create`, `fn_mission_list`, `fn_mission_show`, `fn_mission_delete`, `fn_milestone_add`, `fn_slice_add`, `fn_feature_add`, `fn_slice_activate`, `fn_feature_link_task`
|
|
33
33
|
- **Agent tools** — `fn_agent_stop`, `fn_agent_start`
|
|
34
34
|
- **Skills tools** — `fn_skills_search`, `fn_skills_install`
|
|
35
|
+
- **Insight tools** — `fn_insight_list`, `fn_insight_show`, `fn_insight_run_list`, `fn_insight_run_show`
|
|
36
|
+
- **Other tools** — `fn_research_run`, `fn_research_list`, `fn_research_get`, `fn_research_cancel`
|
|
35
37
|
<!-- END: tool-categories -->
|
|
36
38
|
- **Dashboard** — Use `/fn` command to start/stop the dashboard
|
|
37
39
|
|
|
@@ -17,6 +17,10 @@ These tools are **not** part of the pi extension's user-invokable `extension.ts`
|
|
|
17
17
|
| `fn_memory_search` | triage, executor, heartbeat | Search project/agent memory snippets | `query` (string), `limit?` (number) |
|
|
18
18
|
| `fn_memory_get` | triage, executor, heartbeat | Read a bounded memory file window | `path` (string), `startLine?` (number), `lineCount?` (number) |
|
|
19
19
|
| `fn_memory_append` | executor, heartbeat (when writable backend enabled) | Append long-term/daily memory notes | `scope?` (`project` \| `agent`), `layer` (`long-term` \| `daily`), `content` (string) |
|
|
20
|
+
| `fn_research_run` | triage, executor | Start a bounded research run (optionally wait for completion) and return structured findings metadata | `query` (string), `wait_for_completion?` (boolean), `max_wait_ms?` (number) |
|
|
21
|
+
| `fn_research_list` | triage, executor | List recent research runs with status/summary metadata | `status?` (`pending` \| `running` \| `completed` \| `failed` \| `cancelled`), `limit?` (number) |
|
|
22
|
+
| `fn_research_get` | triage, executor | Read one research run's structured findings/citations payload | `id` (string) |
|
|
23
|
+
| `fn_research_cancel` | triage, executor | Cancel an active research run via orchestrator cancellation path | `id` (string) |
|
|
20
24
|
| `fn_reflect_on_performance` | executor | Generate reflection insights from prior runs | `focus_area?` (string) |
|
|
21
25
|
| `fn_list_agents` | triage, executor, heartbeat | List agents (optionally filtered) | `role?` (string), `state?` (string), `includeEphemeral?` (boolean) |
|
|
22
26
|
| `fn_delegate_task` | triage, executor, heartbeat | Create and assign a new task to a specific agent | `agent_id` (string), `description` (string), `dependencies?` (string[]) |
|
|
@@ -283,6 +283,82 @@ Install an agent skill from skills.sh into the current project. Downloads skill
|
|
|
283
283
|
| `source` | string | ✓ | GitHub source in owner/repo format (e.g., 'firebase/agent-skills') |
|
|
284
284
|
| `skill` | string | — | Specific skill name to install (e.g., 'firebase-basics'). Omit to install all skills from the source. |
|
|
285
285
|
|
|
286
|
+
## Insight Tools
|
|
287
|
+
|
|
288
|
+
### fn_insight_list
|
|
289
|
+
|
|
290
|
+
List persisted project insights with optional category/status filters.
|
|
291
|
+
|
|
292
|
+
| Parameter | Type | Required | Description |
|
|
293
|
+
|-----------|------|----------|-------------|
|
|
294
|
+
| `category` | string(enum) | — | Filter by insight category |
|
|
295
|
+
| `status` | string(enum) | — | Filter by insight status |
|
|
296
|
+
| `runId` | string | — | Filter to insights linked to a specific run ID |
|
|
297
|
+
| `limit` | number | — | Max insights to return |
|
|
298
|
+
| `offset` | number | — | Number of rows to skip |
|
|
299
|
+
|
|
300
|
+
### fn_insight_show
|
|
301
|
+
|
|
302
|
+
Show a single persisted insight by ID.
|
|
303
|
+
|
|
304
|
+
| Parameter | Type | Required | Description |
|
|
305
|
+
|-----------|------|----------|-------------|
|
|
306
|
+
| `id` | string | ✓ | Insight ID (e.g. INS-XXXXX) |
|
|
307
|
+
|
|
308
|
+
### fn_insight_run_list
|
|
309
|
+
|
|
310
|
+
List recent insight-generation runs with optional status/trigger filters.
|
|
311
|
+
|
|
312
|
+
| Parameter | Type | Required | Description |
|
|
313
|
+
|-----------|------|----------|-------------|
|
|
314
|
+
| `status` | string(enum) | — | Filter by run status |
|
|
315
|
+
| `trigger` | string(enum) | — | Filter by run trigger |
|
|
316
|
+
| `limit` | number | — | Max runs to return |
|
|
317
|
+
| `offset` | number | — | Number of runs to skip |
|
|
318
|
+
|
|
319
|
+
### fn_insight_run_show
|
|
320
|
+
|
|
321
|
+
Show a single insight-generation run by ID.
|
|
322
|
+
|
|
323
|
+
| Parameter | Type | Required | Description |
|
|
324
|
+
|-----------|------|----------|-------------|
|
|
325
|
+
| `id` | string | ✓ | Insight run ID (e.g. INSR-XXXXX) |
|
|
326
|
+
|
|
327
|
+
## Other Tools
|
|
328
|
+
|
|
329
|
+
### fn_research_run
|
|
330
|
+
|
|
331
|
+
Start a bounded research run and optionally wait for findings.
|
|
332
|
+
|
|
333
|
+
| Parameter | Type | Required | Description |
|
|
334
|
+
|-----------|------|----------|-------------|
|
|
335
|
+
| `query` | string | ✓ | Research query or question |
|
|
336
|
+
|
|
337
|
+
### fn_research_list
|
|
338
|
+
|
|
339
|
+
List recent research runs.
|
|
340
|
+
|
|
341
|
+
| Parameter | Type | Required | Description |
|
|
342
|
+
|-----------|------|----------|-------------|
|
|
343
|
+
| `status` | string(enum) | — | |
|
|
344
|
+
| `limit` | number | — | Max runs to return (default: 10) |
|
|
345
|
+
|
|
346
|
+
### fn_research_get
|
|
347
|
+
|
|
348
|
+
Get one research run and structured findings.
|
|
349
|
+
|
|
350
|
+
| Parameter | Type | Required | Description |
|
|
351
|
+
|-----------|------|----------|-------------|
|
|
352
|
+
| `id` | string | ✓ | Research run ID |
|
|
353
|
+
|
|
354
|
+
### fn_research_cancel
|
|
355
|
+
|
|
356
|
+
Cancel a research run.
|
|
357
|
+
|
|
358
|
+
| Parameter | Type | Required | Description |
|
|
359
|
+
|-----------|------|----------|-------------|
|
|
360
|
+
| `id` | string | ✓ | Research run ID |
|
|
361
|
+
|
|
286
362
|
<!-- END: extension-tools -->
|
|
287
363
|
## Dashboard Command
|
|
288
364
|
|
|
@@ -29,6 +29,14 @@ All skill/extension tool invocations in this catalog use the public `fn_*` names
|
|
|
29
29
|
| `fn_task_import_github_issue` | Import a specific GitHub issue as a Fusion task. Fetches the issue by number and creates a single task in the planning column with the issue title and body. |
|
|
30
30
|
| `fn_task_browse_github_issues` | List open GitHub issues from a repository to browse before importing. Returns issue numbers, titles, and URLs for selection. Use with fn_task_import_github_issue to import specific issues by number. |
|
|
31
31
|
| `fn_task_plan` | Create a task via AI-guided planning mode — interactive conversation to refine your idea into a well-specified task. |
|
|
32
|
+
| `fn_research_run` | Start a bounded research run and optionally wait for findings. |
|
|
33
|
+
| `fn_research_list` | List recent research runs. |
|
|
34
|
+
| `fn_research_get` | Get one research run and structured findings. |
|
|
35
|
+
| `fn_research_cancel` | Cancel a research run. |
|
|
36
|
+
| `fn_insight_list` | List persisted project insights with optional category/status filters. |
|
|
37
|
+
| `fn_insight_show` | Show a single persisted insight by ID. |
|
|
38
|
+
| `fn_insight_run_list` | List recent insight-generation runs with optional status/trigger filters. |
|
|
39
|
+
| `fn_insight_run_show` | Show a single insight-generation run by ID. |
|
|
32
40
|
| `fn_mission_create` | Create a new mission — a high-level objective that can span multiple milestones. Missions contain milestones that break down work into phases. |
|
|
33
41
|
| `fn_mission_list` | List all missions with their current status. |
|
|
34
42
|
| `fn_mission_show` | Show mission details with full hierarchy: milestones → slices → features. |
|