@runfusion/fusion 0.24.0 → 0.25.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 +2254 -1349
- package/dist/client/assets/AgentDetailView-ZbHEbYRT.js +18 -0
- package/dist/client/assets/{AgentsView-BkB9FiMT.js → AgentsView-B3jYk8Kt.js} +3 -3
- package/dist/client/assets/ChatView-DhPkiEGs.js +1 -0
- package/dist/client/assets/{DevServerView-BkvtjZBa.js → DevServerView-DyGDEiBP.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-BK-KbnhP.js → DirectoryPicker-D5UIeIl6.js} +1 -1
- package/dist/client/assets/{DocumentsView-BEg1CQAk.js → DocumentsView-DNHu1T8K.js} +1 -1
- package/dist/client/assets/{EvalsView-Berf9bQm.js → EvalsView-CpRobtDi.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-jcInE50G.js → ExperimentalAgentOnboardingModal-DOY_oZi7.js} +1 -1
- package/dist/client/assets/{InsightsView-BX5bSF1J.js → InsightsView-vp0RE8Mg.js} +1 -1
- package/dist/client/assets/MemoryView-PSc5lGJt.js +2 -0
- package/dist/client/assets/MemoryView-zaXewZzi.css +1 -0
- package/dist/client/assets/{NodesView-DLUOBLf6.js → NodesView-DMj6HGeC.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-COlJf0Kx.js → PiExtensionsManager-DL_QcN56.js} +2 -2
- package/dist/client/assets/PluginManager-BtYKm8IT.js +1 -0
- package/dist/client/assets/{ResearchView-B256Lr8I.js → ResearchView-BhWqfdV0.js} +1 -1
- package/dist/client/assets/{SettingsModal-BeA_nQtW.js → SettingsModal-BAgB4_AR.js} +4 -4
- package/dist/client/assets/{SettingsModal-yRqM4DV8.js → SettingsModal-CUCyaAyE.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-uUZk3TKT.js → SetupWizardModal-BKscasuh.js} +1 -1
- package/dist/client/assets/{SkillsView-CP8JX0P_.js → SkillsView-BdELqTy7.js} +1 -1
- package/dist/client/assets/{TodoView-DCRIkDZ-.js → TodoView-DFNGBDNV.js} +1 -1
- package/dist/client/assets/{folder-open-DHjELt8-.js → folder-open-k1xmUMyr.js} +1 -1
- package/dist/client/assets/index-Qq2JOOWx.css +1 -0
- package/dist/client/assets/{index-CQyVRLOb.js → index-TFYXEVpn.js} +160 -160
- package/dist/client/assets/{star-DYesq1AV.js → star-ne32r3Y4.js} +1 -1
- package/dist/client/assets/{upload-DTWF3Db5.js → upload-MS-2Gx53.js} +1 -1
- package/dist/client/assets/{users--syrel4l.js → users-C519GSjH.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +1370 -629
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +9 -11
- package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +30 -0
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +3 -28
- package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +899 -895
- package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +68 -71
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +47 -50
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +155 -109
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/src/index.ts +49 -3
- package/dist/plugins/fusion-plugin-reports/src/report-schema.ts +38 -0
- package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-schema.test.ts +66 -0
- package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-store.test.ts +177 -0
- package/dist/plugins/fusion-plugin-reports/src/store/report-store.ts +341 -0
- package/dist/plugins/fusion-plugin-reports/src/store/report-types.ts +77 -0
- package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
- package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/AgentDetailView-gy_5SUj2.js +0 -18
- package/dist/client/assets/ChatView-B_-B8fqu.js +0 -1
- package/dist/client/assets/MemoryView-CKElJY_3.js +0 -2
- package/dist/client/assets/MemoryView-DiajLXby.css +0 -1
- package/dist/client/assets/PluginManager-CfW55BF4.js +0 -1
- package/dist/client/assets/createLucideIcon-BazL2hk5.js +0 -21
- package/dist/client/assets/dashboard-view-BkTMSZYn.css +0 -1
- package/dist/client/assets/dashboard-view-CyWN-d02.js +0 -63
- package/dist/client/assets/dashboard-view-DdGlfuu-.css +0 -1
- package/dist/client/assets/dashboard-view-lR7YYmSC.js +0 -21
- package/dist/client/assets/index-CxA2Nn0_.css +0 -1
- package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.css +0 -58
- package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.tsx +0 -301
- package/dist/plugins/fusion-plugin-dependency-graph/src/GraphHighlight.css +0 -27
- package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.css +0 -157
- package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx +0 -126
- package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.css +0 -35
- package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.tsx +0 -36
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.highlighting.test.tsx +0 -112
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.persistence.test.tsx +0 -115
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.test.tsx +0 -128
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.drag.test.tsx +0 -82
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.test.tsx +0 -307
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphToolbar.test.tsx +0 -60
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/edges.test.tsx +0 -75
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filtering.test.tsx +0 -62
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filters.test.ts +0 -78
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/graphPositionStorage.test.ts +0 -95
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/host-integration.test.ts +0 -74
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/index.test.ts +0 -58
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/interactions.test.tsx +0 -121
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/layout.test.ts +0 -70
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/persistence.test.tsx +0 -89
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphData.test.ts +0 -86
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphInteraction.test.ts +0 -167
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphPositions.test.ts +0 -66
- package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useNodeDrag.test.ts +0 -81
- package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-interop.d.ts +0 -35
- package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx +0 -19
- package/dist/plugins/fusion-plugin-dependency-graph/src/edges.tsx +0 -70
- package/dist/plugins/fusion-plugin-dependency-graph/src/filters.ts +0 -8
- package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/__tests__/useDependencyChain.test.ts +0 -53
- package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useDependencyChain.ts +0 -60
- package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useGraphPositions.ts +0 -45
- package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useNodeDrag.ts +0 -114
- package/dist/plugins/fusion-plugin-dependency-graph/src/index.ts +0 -24
- package/dist/plugins/fusion-plugin-dependency-graph/src/layout.ts +0 -91
- package/dist/plugins/fusion-plugin-dependency-graph/src/styles/drag.css +0 -15
- package/dist/plugins/fusion-plugin-dependency-graph/src/types.ts +0 -21
- package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphData.ts +0 -17
- package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphInteraction.ts +0 -292
- package/dist/plugins/fusion-plugin-dependency-graph/src/utils/graphPositionStorage.ts +0 -65
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// ../plugin-sdk/
|
|
1
|
+
// ../plugin-sdk/src/index.ts
|
|
2
2
|
function definePlugin(plugin2) {
|
|
3
3
|
return plugin2;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
// ../../plugins/fusion-plugin-paperclip-runtime/
|
|
6
|
+
// ../../plugins/fusion-plugin-paperclip-runtime/src/paperclip-client.ts
|
|
7
7
|
var ConflictError = class extends Error {
|
|
8
8
|
status = 409;
|
|
9
9
|
constructor(message) {
|
|
@@ -38,19 +38,18 @@ async function parseJsonBody(response) {
|
|
|
38
38
|
try {
|
|
39
39
|
return { value: JSON.parse(raw), raw };
|
|
40
40
|
} catch {
|
|
41
|
-
throw new Error(
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Paperclip API ${response.status} ${response.statusText}: invalid JSON response body`
|
|
43
|
+
);
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
function toErrorMessage(status, statusText, body, raw) {
|
|
45
47
|
if (body && typeof body === "object") {
|
|
46
48
|
const b = body;
|
|
47
|
-
if (typeof b.error === "string")
|
|
48
|
-
|
|
49
|
-
if (typeof b.message === "string")
|
|
50
|
-
return b.message;
|
|
49
|
+
if (typeof b.error === "string") return b.error;
|
|
50
|
+
if (typeof b.message === "string") return b.message;
|
|
51
51
|
}
|
|
52
|
-
if (raw.trim() !== "")
|
|
53
|
-
return raw.slice(0, 200).trim();
|
|
52
|
+
if (raw.trim() !== "") return raw.slice(0, 200).trim();
|
|
54
53
|
return `${status} ${statusText}`.trim();
|
|
55
54
|
}
|
|
56
55
|
async function request(apiUrl, path, options) {
|
|
@@ -73,8 +72,7 @@ async function request(apiUrl, path, options) {
|
|
|
73
72
|
if (!response.ok) {
|
|
74
73
|
const msg = toErrorMessage(response.status, response.statusText, value, raw);
|
|
75
74
|
const full = `Paperclip API ${response.status} (${method} ${path}): ${msg}`;
|
|
76
|
-
if (response.status === 409)
|
|
77
|
-
throw new ConflictError(full);
|
|
75
|
+
if (response.status === 409) throw new ConflictError(full);
|
|
78
76
|
throw new Error(full);
|
|
79
77
|
}
|
|
80
78
|
return value;
|
|
@@ -84,7 +82,9 @@ function getSettingString(settings, key) {
|
|
|
84
82
|
return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
|
|
85
83
|
}
|
|
86
84
|
function resolvePaperclipConfig(settings) {
|
|
87
|
-
const apiUrl = normalizeApiUrl(
|
|
85
|
+
const apiUrl = normalizeApiUrl(
|
|
86
|
+
getSettingString(settings, "apiUrl") ?? process.env.PAPERCLIP_API_URL?.trim() ?? "http://localhost:3100"
|
|
87
|
+
);
|
|
88
88
|
const apiKey = getSettingString(settings, "apiKey") ?? (process.env.PAPERCLIP_API_KEY?.trim() || void 0);
|
|
89
89
|
const agentId = getSettingString(settings, "agentId") ?? process.env.PAPERCLIP_AGENT_ID?.trim() ?? void 0;
|
|
90
90
|
const companyId = getSettingString(settings, "companyId") ?? process.env.PAPERCLIP_COMPANY_ID?.trim() ?? void 0;
|
|
@@ -96,9 +96,18 @@ function resolvePaperclipConfig(settings) {
|
|
|
96
96
|
const parentIssueId = getSettingString(settings, "parentIssueId") ?? process.env.PAPERCLIP_PARENT_ISSUE_ID?.trim() ?? void 0;
|
|
97
97
|
const projectId = getSettingString(settings, "projectId") ?? process.env.PAPERCLIP_PROJECT_ID?.trim() ?? void 0;
|
|
98
98
|
const goalId = getSettingString(settings, "goalId") ?? process.env.PAPERCLIP_GOAL_ID?.trim() ?? void 0;
|
|
99
|
-
const runTimeoutMs = parseInt(
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
const runTimeoutMs = parseInt(
|
|
100
|
+
getSettingString(settings, "runTimeoutMs") ?? process.env.PAPERCLIP_RUN_TIMEOUT_MS ?? "600000",
|
|
101
|
+
10
|
|
102
|
+
);
|
|
103
|
+
const pollIntervalMs = parseInt(
|
|
104
|
+
getSettingString(settings, "pollIntervalMs") ?? process.env.PAPERCLIP_POLL_INTERVAL_MS ?? "500",
|
|
105
|
+
10
|
|
106
|
+
);
|
|
107
|
+
const pollIntervalMaxMs = parseInt(
|
|
108
|
+
getSettingString(settings, "pollIntervalMaxMs") ?? process.env.PAPERCLIP_POLL_INTERVAL_MAX_MS ?? "2000",
|
|
109
|
+
10
|
|
110
|
+
);
|
|
102
111
|
return {
|
|
103
112
|
apiUrl,
|
|
104
113
|
apiKey,
|
|
@@ -191,25 +200,20 @@ async function getRunEvents(apiUrl, apiKey, runId, afterSeq, limit = 100) {
|
|
|
191
200
|
apiKey,
|
|
192
201
|
query
|
|
193
202
|
});
|
|
194
|
-
if (Array.isArray(result))
|
|
195
|
-
return result;
|
|
203
|
+
if (Array.isArray(result)) return result;
|
|
196
204
|
const r = result;
|
|
197
|
-
if (Array.isArray(r.events))
|
|
198
|
-
return r.events;
|
|
205
|
+
if (Array.isArray(r.events)) return r.events;
|
|
199
206
|
return [];
|
|
200
207
|
}
|
|
201
208
|
async function listCompanies(apiUrl, apiKey) {
|
|
202
209
|
const raw = await request(apiUrl, "/companies", { apiKey });
|
|
203
|
-
if (!Array.isArray(raw))
|
|
204
|
-
return [];
|
|
210
|
+
if (!Array.isArray(raw)) return [];
|
|
205
211
|
const out = [];
|
|
206
212
|
for (const entry of raw) {
|
|
207
|
-
if (!entry || typeof entry !== "object")
|
|
208
|
-
continue;
|
|
213
|
+
if (!entry || typeof entry !== "object") continue;
|
|
209
214
|
const r = entry;
|
|
210
215
|
const id = typeof r.id === "string" ? r.id : void 0;
|
|
211
|
-
if (!id)
|
|
212
|
-
continue;
|
|
216
|
+
if (!id) continue;
|
|
213
217
|
const name = typeof r.name === "string" ? r.name : id;
|
|
214
218
|
const urlKey = typeof r.urlKey === "string" ? r.urlKey : typeof r.slug === "string" ? r.slug : void 0;
|
|
215
219
|
out.push({ id, name, urlKey });
|
|
@@ -218,16 +222,13 @@ async function listCompanies(apiUrl, apiKey) {
|
|
|
218
222
|
}
|
|
219
223
|
async function listCompanyAgents(apiUrl, apiKey, companyId) {
|
|
220
224
|
const raw = await request(apiUrl, `/companies/${companyId}/agents`, { apiKey });
|
|
221
|
-
if (!Array.isArray(raw))
|
|
222
|
-
return [];
|
|
225
|
+
if (!Array.isArray(raw)) return [];
|
|
223
226
|
const out = [];
|
|
224
227
|
for (const entry of raw) {
|
|
225
|
-
if (!entry || typeof entry !== "object")
|
|
226
|
-
continue;
|
|
228
|
+
if (!entry || typeof entry !== "object") continue;
|
|
227
229
|
const r = entry;
|
|
228
230
|
const id = typeof r.id === "string" ? r.id : void 0;
|
|
229
|
-
if (!id)
|
|
230
|
-
continue;
|
|
231
|
+
if (!id) continue;
|
|
231
232
|
const name = typeof r.name === "string" ? r.name : id;
|
|
232
233
|
const role = typeof r.role === "string" ? r.role : void 0;
|
|
233
234
|
const cId = typeof r.companyId === "string" ? r.companyId : companyId;
|
|
@@ -337,7 +338,11 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
337
338
|
} catch (err) {
|
|
338
339
|
const code = err.code;
|
|
339
340
|
if (code === "ENOENT") {
|
|
340
|
-
reject(
|
|
341
|
+
reject(
|
|
342
|
+
new Error(
|
|
343
|
+
`paperclipai binary not found at ${bin}; install via \`npm i -g paperclipai\``
|
|
344
|
+
)
|
|
345
|
+
);
|
|
341
346
|
} else {
|
|
342
347
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
343
348
|
}
|
|
@@ -358,22 +363,24 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
358
363
|
const lines = chunk.toString("utf-8").split("\n");
|
|
359
364
|
for (const line of lines) {
|
|
360
365
|
const stripped = stripAnsi(line).trim();
|
|
361
|
-
if (stripped)
|
|
362
|
-
stderrLines.push(stripped);
|
|
366
|
+
if (stripped) stderrLines.push(stripped);
|
|
363
367
|
}
|
|
364
368
|
});
|
|
365
369
|
child.on("error", (err) => {
|
|
366
370
|
clearTimeout(timer);
|
|
367
371
|
if (err.code === "ENOENT") {
|
|
368
|
-
reject(
|
|
372
|
+
reject(
|
|
373
|
+
new Error(
|
|
374
|
+
`paperclipai binary not found at ${bin}; install via \`npm i -g paperclipai\``
|
|
375
|
+
)
|
|
376
|
+
);
|
|
369
377
|
} else {
|
|
370
378
|
reject(err);
|
|
371
379
|
}
|
|
372
380
|
});
|
|
373
381
|
child.on("close", (code) => {
|
|
374
382
|
clearTimeout(timer);
|
|
375
|
-
if (killed)
|
|
376
|
-
return;
|
|
383
|
+
if (killed) return;
|
|
377
384
|
const rawStdout = Buffer.concat(stdoutChunks).toString("utf-8");
|
|
378
385
|
const cleanedStdout = stripAnsi(rawStdout).trim();
|
|
379
386
|
if (code !== 0) {
|
|
@@ -385,20 +392,30 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
385
392
|
}
|
|
386
393
|
if (!cleanedStdout) {
|
|
387
394
|
const hint = "run `paperclipai onboard` to authenticate the CLI";
|
|
388
|
-
reject(
|
|
395
|
+
reject(
|
|
396
|
+
new Error(`paperclipai agent local-cli produced no output \u2014 ${hint}`)
|
|
397
|
+
);
|
|
389
398
|
return;
|
|
390
399
|
}
|
|
391
400
|
let parsed;
|
|
392
401
|
try {
|
|
393
402
|
parsed = JSON.parse(cleanedStdout);
|
|
394
403
|
} catch {
|
|
395
|
-
reject(
|
|
404
|
+
reject(
|
|
405
|
+
new Error(
|
|
406
|
+
`paperclipai agent local-cli returned non-JSON output: ${cleanedStdout.slice(0, 200)}`
|
|
407
|
+
)
|
|
408
|
+
);
|
|
396
409
|
return;
|
|
397
410
|
}
|
|
398
411
|
const r = parsed;
|
|
399
412
|
const apiKey = (typeof r.apiKey === "string" ? r.apiKey : void 0) ?? (typeof r.api_key === "string" ? r.api_key : void 0) ?? (typeof r.token === "string" ? r.token : void 0);
|
|
400
413
|
if (!apiKey) {
|
|
401
|
-
reject(
|
|
414
|
+
reject(
|
|
415
|
+
new Error(
|
|
416
|
+
`paperclipai agent local-cli JSON missing apiKey/api_key/token field: ${cleanedStdout.slice(0, 200)}`
|
|
417
|
+
)
|
|
418
|
+
);
|
|
402
419
|
return;
|
|
403
420
|
}
|
|
404
421
|
const apiBase = (typeof r.apiBase === "string" ? r.apiBase : void 0) ?? (typeof r.api_base === "string" ? r.api_base : void 0);
|
|
@@ -411,7 +428,9 @@ async function mintAgentApiKeyViaCli(opts) {
|
|
|
411
428
|
function remapSpawnError(err, bin) {
|
|
412
429
|
const code = err?.code;
|
|
413
430
|
if (code === "ENOENT") {
|
|
414
|
-
return new Error(
|
|
431
|
+
return new Error(
|
|
432
|
+
`paperclipai binary not found at ${bin}; install via \`npm i -g paperclipai\``
|
|
433
|
+
);
|
|
415
434
|
}
|
|
416
435
|
return err instanceof Error ? err : new Error(String(err));
|
|
417
436
|
}
|
|
@@ -447,8 +466,7 @@ async function spawnPaperclipCliJson(args, opts) {
|
|
|
447
466
|
const lines = chunk.toString("utf-8").split("\n");
|
|
448
467
|
for (const line of lines) {
|
|
449
468
|
const stripped = stripAnsi(line).trim();
|
|
450
|
-
if (stripped)
|
|
451
|
-
stderrLines.push(stripped);
|
|
469
|
+
if (stripped) stderrLines.push(stripped);
|
|
452
470
|
}
|
|
453
471
|
});
|
|
454
472
|
child.on("error", (err) => {
|
|
@@ -457,12 +475,17 @@ async function spawnPaperclipCliJson(args, opts) {
|
|
|
457
475
|
});
|
|
458
476
|
child.on("close", (code) => {
|
|
459
477
|
clearTimeout(timer);
|
|
460
|
-
if (killed)
|
|
461
|
-
|
|
462
|
-
|
|
478
|
+
if (killed) return;
|
|
479
|
+
const cleaned = stripAnsi(
|
|
480
|
+
Buffer.concat(stdoutChunks).toString("utf-8")
|
|
481
|
+
).trim();
|
|
463
482
|
if (code !== 0) {
|
|
464
483
|
const lastErr = stderrLines.filter(Boolean).pop() ?? "";
|
|
465
|
-
reject(
|
|
484
|
+
reject(
|
|
485
|
+
new Error(
|
|
486
|
+
lastErr ? `${label} exited ${code}: ${lastErr}` : `${label} exited ${code}`
|
|
487
|
+
)
|
|
488
|
+
);
|
|
466
489
|
return;
|
|
467
490
|
}
|
|
468
491
|
if (!cleaned) {
|
|
@@ -472,23 +495,22 @@ async function spawnPaperclipCliJson(args, opts) {
|
|
|
472
495
|
try {
|
|
473
496
|
resolve(JSON.parse(cleaned));
|
|
474
497
|
} catch {
|
|
475
|
-
reject(
|
|
498
|
+
reject(
|
|
499
|
+
new Error(`${label} returned non-JSON output: ${cleaned.slice(0, 200)}`)
|
|
500
|
+
);
|
|
476
501
|
}
|
|
477
502
|
});
|
|
478
503
|
});
|
|
479
504
|
}
|
|
480
505
|
async function listCompaniesViaCli(opts) {
|
|
481
506
|
const raw = await spawnPaperclipCliJson(["company", "list"], opts);
|
|
482
|
-
if (!Array.isArray(raw))
|
|
483
|
-
return [];
|
|
507
|
+
if (!Array.isArray(raw)) return [];
|
|
484
508
|
const out = [];
|
|
485
509
|
for (const entry of raw) {
|
|
486
|
-
if (!entry || typeof entry !== "object")
|
|
487
|
-
continue;
|
|
510
|
+
if (!entry || typeof entry !== "object") continue;
|
|
488
511
|
const r = entry;
|
|
489
512
|
const id = typeof r.id === "string" ? r.id : void 0;
|
|
490
|
-
if (!id)
|
|
491
|
-
continue;
|
|
513
|
+
if (!id) continue;
|
|
492
514
|
const name = typeof r.name === "string" ? r.name : id;
|
|
493
515
|
const urlKey = typeof r.urlKey === "string" ? r.urlKey : typeof r.slug === "string" ? r.slug : void 0;
|
|
494
516
|
out.push({ id, name, urlKey });
|
|
@@ -496,17 +518,17 @@ async function listCompaniesViaCli(opts) {
|
|
|
496
518
|
return out;
|
|
497
519
|
}
|
|
498
520
|
async function listCompanyAgentsViaCli(opts) {
|
|
499
|
-
const raw = await spawnPaperclipCliJson(
|
|
500
|
-
|
|
501
|
-
|
|
521
|
+
const raw = await spawnPaperclipCliJson(
|
|
522
|
+
["agent", "list", "--company-id", opts.companyId],
|
|
523
|
+
opts
|
|
524
|
+
);
|
|
525
|
+
if (!Array.isArray(raw)) return [];
|
|
502
526
|
const out = [];
|
|
503
527
|
for (const entry of raw) {
|
|
504
|
-
if (!entry || typeof entry !== "object")
|
|
505
|
-
continue;
|
|
528
|
+
if (!entry || typeof entry !== "object") continue;
|
|
506
529
|
const r = entry;
|
|
507
530
|
const id = typeof r.id === "string" ? r.id : void 0;
|
|
508
|
-
if (!id)
|
|
509
|
-
continue;
|
|
531
|
+
if (!id) continue;
|
|
510
532
|
const name = typeof r.name === "string" ? r.name : id;
|
|
511
533
|
const role = typeof r.role === "string" ? r.role : void 0;
|
|
512
534
|
const cId = typeof r.companyId === "string" ? r.companyId : opts.companyId;
|
|
@@ -518,40 +540,49 @@ async function listCompanyAgentsViaCli(opts) {
|
|
|
518
540
|
async function createIssueViaCli(opts) {
|
|
519
541
|
const args = ["issue", "create", "--company-id", opts.companyId];
|
|
520
542
|
args.push("--title", opts.body.title);
|
|
521
|
-
if (opts.body.description)
|
|
522
|
-
|
|
523
|
-
if (opts.body.status)
|
|
524
|
-
args.push("--status", opts.body.status);
|
|
543
|
+
if (opts.body.description) args.push("--description", opts.body.description);
|
|
544
|
+
if (opts.body.status) args.push("--status", opts.body.status);
|
|
525
545
|
if (opts.body.assigneeAgentId)
|
|
526
546
|
args.push("--assignee-agent-id", opts.body.assigneeAgentId);
|
|
527
|
-
if (opts.body.parentId)
|
|
528
|
-
|
|
529
|
-
if (opts.body.
|
|
530
|
-
args.push("--project-id", opts.body.projectId);
|
|
531
|
-
if (opts.body.goalId)
|
|
532
|
-
args.push("--goal-id", opts.body.goalId);
|
|
547
|
+
if (opts.body.parentId) args.push("--parent-id", opts.body.parentId);
|
|
548
|
+
if (opts.body.projectId) args.push("--project-id", opts.body.projectId);
|
|
549
|
+
if (opts.body.goalId) args.push("--goal-id", opts.body.goalId);
|
|
533
550
|
const raw = await spawnPaperclipCliJson(args, opts);
|
|
534
551
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
535
|
-
throw new Error(
|
|
552
|
+
throw new Error(
|
|
553
|
+
`paperclipai issue create returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`
|
|
554
|
+
);
|
|
536
555
|
}
|
|
537
556
|
return raw;
|
|
538
557
|
}
|
|
539
558
|
async function getIssueViaCli(opts) {
|
|
540
|
-
const raw = await spawnPaperclipCliJson(
|
|
559
|
+
const raw = await spawnPaperclipCliJson(
|
|
560
|
+
["issue", "get", opts.issueId],
|
|
561
|
+
opts
|
|
562
|
+
);
|
|
541
563
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
542
|
-
throw new Error(
|
|
564
|
+
throw new Error(
|
|
565
|
+
`paperclipai issue get returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`
|
|
566
|
+
);
|
|
543
567
|
}
|
|
544
568
|
return raw;
|
|
545
569
|
}
|
|
546
570
|
async function agentsMeViaCli(opts) {
|
|
547
|
-
const raw = await spawnPaperclipCliJson(
|
|
571
|
+
const raw = await spawnPaperclipCliJson(
|
|
572
|
+
["agent", "get", opts.agentId],
|
|
573
|
+
opts
|
|
574
|
+
);
|
|
548
575
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
549
|
-
throw new Error(
|
|
576
|
+
throw new Error(
|
|
577
|
+
`paperclipai agent get returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`
|
|
578
|
+
);
|
|
550
579
|
}
|
|
551
580
|
const id = typeof raw.id === "string" ? raw.id : void 0;
|
|
552
581
|
const cId = typeof raw.companyId === "string" ? raw.companyId : void 0;
|
|
553
582
|
if (!id || !cId) {
|
|
554
|
-
throw new Error(
|
|
583
|
+
throw new Error(
|
|
584
|
+
"paperclipai agent get returned a response missing `id` or `companyId`"
|
|
585
|
+
);
|
|
555
586
|
}
|
|
556
587
|
return {
|
|
557
588
|
agentId: id,
|
|
@@ -566,8 +597,7 @@ async function probePaperclipViaCli(opts) {
|
|
|
566
597
|
let apiUrl = "(via paperclipai CLI)";
|
|
567
598
|
try {
|
|
568
599
|
const disc = await discoverPaperclipCliConfig({ configPath: opts.cliConfigPath });
|
|
569
|
-
if (disc.ok)
|
|
570
|
-
apiUrl = disc.apiUrl;
|
|
600
|
+
if (disc.ok) apiUrl = disc.apiUrl;
|
|
571
601
|
} catch {
|
|
572
602
|
}
|
|
573
603
|
try {
|
|
@@ -583,7 +613,7 @@ async function probePaperclipViaCli(opts) {
|
|
|
583
613
|
}
|
|
584
614
|
}
|
|
585
615
|
|
|
586
|
-
// ../../plugins/fusion-plugin-paperclip-runtime/
|
|
616
|
+
// ../../plugins/fusion-plugin-paperclip-runtime/src/runtime-adapter.ts
|
|
587
617
|
import { randomUUID } from "node:crypto";
|
|
588
618
|
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
589
619
|
"succeeded",
|
|
@@ -623,8 +653,7 @@ function pickIssueId(issue) {
|
|
|
623
653
|
return issueId;
|
|
624
654
|
}
|
|
625
655
|
function normalizeMode(mode) {
|
|
626
|
-
if (mode && VALID_MODES.has(mode))
|
|
627
|
-
return mode;
|
|
656
|
+
if (mode && VALID_MODES.has(mode)) return mode;
|
|
628
657
|
return "rolling-issue";
|
|
629
658
|
}
|
|
630
659
|
var PaperclipRuntimeAdapter = class {
|
|
@@ -633,7 +662,9 @@ var PaperclipRuntimeAdapter = class {
|
|
|
633
662
|
config;
|
|
634
663
|
logger;
|
|
635
664
|
constructor(config, logger) {
|
|
636
|
-
const resolved = resolvePaperclipConfig(
|
|
665
|
+
const resolved = resolvePaperclipConfig(
|
|
666
|
+
config
|
|
667
|
+
);
|
|
637
668
|
this.config = {
|
|
638
669
|
...resolved,
|
|
639
670
|
mode: normalizeMode(resolved.mode),
|
|
@@ -649,13 +680,17 @@ var PaperclipRuntimeAdapter = class {
|
|
|
649
680
|
configPath: this.config.cliConfigPath
|
|
650
681
|
});
|
|
651
682
|
if (!discovery.ok) {
|
|
652
|
-
throw new Error(
|
|
683
|
+
throw new Error(
|
|
684
|
+
`Paperclip CLI mode failed: ${discovery.reason} (Switch to API mode in settings if paperclipai isn't installed.)`
|
|
685
|
+
);
|
|
653
686
|
}
|
|
654
687
|
effectiveApiUrl = discovery.apiUrl;
|
|
655
688
|
if (!effectiveApiKey) {
|
|
656
689
|
effectiveApiKey = discovery.apiKey;
|
|
657
690
|
}
|
|
658
|
-
this.logger.info(
|
|
691
|
+
this.logger.info(
|
|
692
|
+
`Paperclip CLI mode resolved apiUrl=${effectiveApiUrl} (deploymentMode=${discovery.deploymentMode ?? "unknown"})`
|
|
693
|
+
);
|
|
659
694
|
}
|
|
660
695
|
let agentId = this.config.agentId;
|
|
661
696
|
let companyId = this.config.companyId;
|
|
@@ -663,7 +698,9 @@ var PaperclipRuntimeAdapter = class {
|
|
|
663
698
|
try {
|
|
664
699
|
if (this.config.transport === "cli") {
|
|
665
700
|
if (!agentId) {
|
|
666
|
-
throw new Error(
|
|
701
|
+
throw new Error(
|
|
702
|
+
"agentId is required in Local CLI mode (paperclipai has no `agents/me` equivalent \u2014 pick an agent in settings)"
|
|
703
|
+
);
|
|
667
704
|
}
|
|
668
705
|
const me = await agentsMeViaCli({
|
|
669
706
|
agentId,
|
|
@@ -678,11 +715,15 @@ var PaperclipRuntimeAdapter = class {
|
|
|
678
715
|
}
|
|
679
716
|
} catch (error) {
|
|
680
717
|
const reason = error instanceof Error ? error.message : String(error);
|
|
681
|
-
throw new Error(
|
|
718
|
+
throw new Error(
|
|
719
|
+
`Paperclip runtime could not derive agentId/companyId. Configure them explicitly or check the API key / CLI auth. Underlying error: ${reason}`
|
|
720
|
+
);
|
|
682
721
|
}
|
|
683
722
|
}
|
|
684
723
|
if (!agentId || !companyId) {
|
|
685
|
-
throw new Error(
|
|
724
|
+
throw new Error(
|
|
725
|
+
"Paperclip runtime is missing required config: agentId or companyId. Configure plugin settings (apiUrl, apiKey, agentId, companyId) or PAPERCLIP_* env vars."
|
|
726
|
+
);
|
|
686
727
|
}
|
|
687
728
|
const session = {
|
|
688
729
|
apiUrl: effectiveApiUrl,
|
|
@@ -779,18 +820,15 @@ var PaperclipRuntimeAdapter = class {
|
|
|
779
820
|
if (!finalText) {
|
|
780
821
|
const comments = await getIssueComments(session.apiUrl, session.apiKey, issueId);
|
|
781
822
|
const latest = pickLatestVisibleComment(comments);
|
|
782
|
-
if (latest)
|
|
783
|
-
finalText = latest;
|
|
823
|
+
if (latest) finalText = latest;
|
|
784
824
|
}
|
|
785
825
|
} catch (error) {
|
|
786
826
|
const reason = error instanceof Error ? error.message : String(error);
|
|
787
827
|
this.logger.warn(`Paperclip post-run fetch failed: ${reason}`);
|
|
788
828
|
}
|
|
789
829
|
}
|
|
790
|
-
if (finalText)
|
|
791
|
-
|
|
792
|
-
if (stream.thinking)
|
|
793
|
-
session.onThinking?.(stream.thinking);
|
|
830
|
+
if (finalText) session.onText?.(finalText);
|
|
831
|
+
if (stream.thinking) session.onThinking?.(stream.thinking);
|
|
794
832
|
const isError = stream.runStatus === "failed" || stream.runStatus === "timed_out";
|
|
795
833
|
session.onToolEnd?.("paperclip.run", isError || stream.timedOutLocally, {
|
|
796
834
|
runId,
|
|
@@ -838,24 +876,27 @@ var PaperclipRuntimeAdapter = class {
|
|
|
838
876
|
while (true) {
|
|
839
877
|
let events = [];
|
|
840
878
|
try {
|
|
841
|
-
events = await getRunEvents(
|
|
879
|
+
events = await getRunEvents(
|
|
880
|
+
session.apiUrl,
|
|
881
|
+
session.apiKey,
|
|
882
|
+
runId,
|
|
883
|
+
afterSeq,
|
|
884
|
+
200
|
|
885
|
+
);
|
|
842
886
|
} catch (error) {
|
|
843
887
|
const reason = error instanceof Error ? error.message : String(error);
|
|
844
888
|
this.logger.warn(`Paperclip getRunEvents failed: ${reason}`);
|
|
845
889
|
}
|
|
846
890
|
for (const ev of events) {
|
|
847
|
-
if (typeof ev.seq === "number" && ev.seq > afterSeq)
|
|
848
|
-
afterSeq = ev.seq;
|
|
891
|
+
if (typeof ev.seq === "number" && ev.seq > afterSeq) afterSeq = ev.seq;
|
|
849
892
|
const type = ev.type ?? "";
|
|
850
893
|
const payload = ev.payload ?? {};
|
|
851
894
|
if (type === "heartbeat.run.status") {
|
|
852
895
|
const next = asString(payload.status);
|
|
853
|
-
if (next)
|
|
854
|
-
runStatus = next;
|
|
896
|
+
if (next) runStatus = next;
|
|
855
897
|
} else if (type === "heartbeat.run.log") {
|
|
856
898
|
const chunk = asString(payload.chunk) ?? "";
|
|
857
|
-
if (!chunk)
|
|
858
|
-
continue;
|
|
899
|
+
if (!chunk) continue;
|
|
859
900
|
if (payload.stream === "stdout") {
|
|
860
901
|
textBuf += chunk;
|
|
861
902
|
session.onText?.(chunk);
|
|
@@ -867,11 +908,12 @@ var PaperclipRuntimeAdapter = class {
|
|
|
867
908
|
}
|
|
868
909
|
}
|
|
869
910
|
}
|
|
870
|
-
if (TERMINAL_RUN_STATUSES.has(runStatus))
|
|
871
|
-
break;
|
|
911
|
+
if (TERMINAL_RUN_STATUSES.has(runStatus)) break;
|
|
872
912
|
if (Date.now() - startedAt > session.runTimeoutMs) {
|
|
873
913
|
timedOutLocally = true;
|
|
874
|
-
this.logger.warn(
|
|
914
|
+
this.logger.warn(
|
|
915
|
+
`Paperclip run ${runId} exceeded local runTimeoutMs=${session.runTimeoutMs}; abandoning poll. Run continues server-side.`
|
|
916
|
+
);
|
|
875
917
|
break;
|
|
876
918
|
}
|
|
877
919
|
await sleep(interval);
|
|
@@ -884,19 +926,21 @@ function pickLatestVisibleComment(comments) {
|
|
|
884
926
|
for (let i = comments.length - 1; i >= 0; i--) {
|
|
885
927
|
const c = comments[i];
|
|
886
928
|
const body = asString(c.body)?.trim();
|
|
887
|
-
if (body)
|
|
888
|
-
return body;
|
|
929
|
+
if (body) return body;
|
|
889
930
|
}
|
|
890
931
|
return void 0;
|
|
891
932
|
}
|
|
892
933
|
|
|
893
|
-
// ../../plugins/fusion-plugin-paperclip-runtime/
|
|
934
|
+
// ../../plugins/fusion-plugin-paperclip-runtime/src/index.ts
|
|
894
935
|
function getSettingsConfig(settings) {
|
|
895
936
|
return resolvePaperclipConfig(settings ?? {});
|
|
896
937
|
}
|
|
897
938
|
async function paperclipRuntimeFactory(ctx) {
|
|
898
939
|
const config = getSettingsConfig(ctx.settings);
|
|
899
|
-
return new PaperclipRuntimeAdapter(
|
|
940
|
+
return new PaperclipRuntimeAdapter(
|
|
941
|
+
config,
|
|
942
|
+
ctx.logger
|
|
943
|
+
);
|
|
900
944
|
}
|
|
901
945
|
var paperclipRuntime = {
|
|
902
946
|
metadata: {
|
|
@@ -936,7 +980,9 @@ var plugin = definePlugin({
|
|
|
936
980
|
});
|
|
937
981
|
if (status.available) {
|
|
938
982
|
const ident = status.identity;
|
|
939
|
-
ctx.logger.info(
|
|
983
|
+
ctx.logger.info(
|
|
984
|
+
ident ? `Paperclip reachable as ${ident.agentName} (${ident.role ?? "agent"}) at ${ident.companyName ?? ident.companyId}` : `Paperclip reachable at ${config.apiUrl}`
|
|
985
|
+
);
|
|
940
986
|
} else {
|
|
941
987
|
ctx.logger.warn(`Paperclip probe failed: ${status.reason ?? "unknown"}`);
|
|
942
988
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { PluginContext } from "@fusion/core";
|
|
2
2
|
import { definePlugin } from "@fusion/plugin-sdk";
|
|
3
3
|
import { runReviewPanel } from "./review-panel.js";
|
|
4
|
+
import { ensureReportSchema } from "./report-schema.js";
|
|
4
5
|
import type { CombinedReview, ReviewPanelMember, RunReviewPanelInput } from "./review-types.js";
|
|
6
|
+
import type { ReportCadence, ReportCreateInput } from "./store/report-types.js";
|
|
7
|
+
import { ReportStore } from "./store/report-store.js";
|
|
5
8
|
import { settingsSchema } from "./settings.js";
|
|
6
9
|
|
|
7
10
|
const plugin = definePlugin({
|
|
@@ -15,7 +18,9 @@ const plugin = definePlugin({
|
|
|
15
18
|
settingsSchema,
|
|
16
19
|
},
|
|
17
20
|
state: "installed",
|
|
18
|
-
hooks: {
|
|
21
|
+
hooks: {
|
|
22
|
+
onSchemaInit: ensureReportSchema,
|
|
23
|
+
},
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
export interface RunGeneratedReportReviewInput {
|
|
@@ -25,13 +30,51 @@ export interface RunGeneratedReportReviewInput {
|
|
|
25
30
|
cwd: string;
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
const reportStoreCache = new WeakMap<object, ReportStore>();
|
|
34
|
+
|
|
35
|
+
export function getReportStore(ctx: PluginContext): ReportStore {
|
|
36
|
+
const key = ctx.taskStore as object;
|
|
37
|
+
const cached = reportStoreCache.get(key);
|
|
38
|
+
if (cached) return cached;
|
|
39
|
+
|
|
40
|
+
const store = new ReportStore(ctx.taskStore.getDatabase());
|
|
41
|
+
reportStoreCache.set(key, store);
|
|
42
|
+
return store;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function toCadence(cadence: RunReviewPanelInput["reportMetadata"]["cadence"]): ReportCadence {
|
|
46
|
+
return cadence;
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
export async function runGeneratedReportReview(input: RunGeneratedReportReviewInput, ctx: PluginContext): Promise<CombinedReview> {
|
|
29
|
-
|
|
50
|
+
const store = getReportStore(ctx);
|
|
51
|
+
const reportInput: ReportCreateInput = {
|
|
52
|
+
cadence: toCadence(input.reportMetadata.cadence),
|
|
53
|
+
periodStart: input.reportMetadata.periodStart,
|
|
54
|
+
periodEnd: input.reportMetadata.periodEnd,
|
|
55
|
+
title: `Generated ${input.reportMetadata.cadence} report`,
|
|
56
|
+
draftMarkdown: input.reportDraft,
|
|
57
|
+
metadata: {
|
|
58
|
+
reportMetadata: input.reportMetadata,
|
|
59
|
+
source: "runGeneratedReportReview",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const report = store.createReport(reportInput);
|
|
63
|
+
store.setStatus(report.id, "review_pending");
|
|
64
|
+
store.setStatus(report.id, "review_in_progress");
|
|
65
|
+
|
|
66
|
+
const combinedReview = await runReviewPanel({
|
|
30
67
|
reportDraft: input.reportDraft,
|
|
31
|
-
reportMetadata:
|
|
68
|
+
reportMetadata: {
|
|
69
|
+
...input.reportMetadata,
|
|
70
|
+
reportId: report.id,
|
|
71
|
+
},
|
|
32
72
|
panel: input.panel,
|
|
33
73
|
cwd: input.cwd,
|
|
34
74
|
}, ctx);
|
|
75
|
+
|
|
76
|
+
store.attachReview(report.id, combinedReview);
|
|
77
|
+
return combinedReview;
|
|
35
78
|
}
|
|
36
79
|
|
|
37
80
|
export default plugin;
|
|
@@ -39,3 +82,6 @@ export default plugin;
|
|
|
39
82
|
export * from "./settings.js";
|
|
40
83
|
export * from "./review-types.js";
|
|
41
84
|
export * from "./review-panel.js";
|
|
85
|
+
export { ensureReportSchema } from "./report-schema.js";
|
|
86
|
+
export { ReportStore, ReportStoreError, type ReportStoreEvents } from "./store/report-store.js";
|
|
87
|
+
export * from "./store/report-types.js";
|