chainlesschain 0.165.8 → 0.165.9
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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-B3gWmXjo.js → AIOps-DxwjrnEA.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-G9pdT-0e.js → ActionButton-JdbYowzn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Ca30J7m2.js → Analytics-C06GCahv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BtVTm8PU.js → AppLayout-BUVEEyi1.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BhViNa6u.js → Artifacts-D_ORzkJd.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DhKq-FnY.js → Audit-8o_Y5ejG.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BL0SVbnE.js → BackgroundAgents-DrkHd5VU.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BWkblnFi.js → Backup-CKBZCX11.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ClaRNrF8.js → BaseInput-C8HkI399.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-sZE2Z77o.js → Chat-zb2H2Wux.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BAfKOnRe.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Cvhay5WM.js → Checkbox-MwPtQmNz.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BpejL-4N.js → Codegen-3p5QCkFK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-g2Ki6g_1.js → Col-BPLlhn52.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D2xKbNo9.js → Community-C-3dBNOM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DbL1Pds3.js → Compact-BUcy-F_b.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DGtZCV4c.js → Compliance-CI8NxT8m.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-4kQpoNsI.js → Cowork-DaDEBS-Q.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BxTYXXAN.js → Cron-BSv9HXu5.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-k0J0LT2N.js → Crosschain-yuiKlJmv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BaqhoPgN.js → DID-D6LfldB0.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-T4RVPIM1.js → Dashboard-CBhLqG61.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DszOToWq.js → Dropdown-BG8pIl3O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9KJU7HF.js → EmailListRenderer-CY92VIE6.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Cmr0JnsA.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BI-_2xZX.js → Federation-D3XirJIU.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DsnDEPsl.js → FormItemContext-DfI9UuGZ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BLncAKKK.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BPQhGXDn.js → Git-DzK4IJAZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CyElbUQW.js → Governance-BHf5KfmQ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CcSntBQD.js → Inference-BmaxSALS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-p6e7HZ2r.js → KnowledgeGraph-BgePFLA9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CNEtr-wz.js → Logs-nqgxpOc4.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Dd2notAJ.js → Marketplace-Bu8to-86.js} +1 -1
- package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
- package/src/assets/web-panel/assets/{Memory-Dg2uTvwx.js → Memory-B026G2GA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-r1YMRiJV.js → MobileBridge-CM2Eeg6I.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-C-89kSm4.js → MobileProjects-B79Ob3hy.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CrPZcVgf.js → Mtc-CxevSZuV.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-sxi7hqJb.js → MtcAudit-X396cPEX.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-CAgOMfF1.js → Multisig-HWIB_aZ1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DafaPts3.js → NLProgramming-gnYD1Xwy.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CJM-xUW_.js → Notes-Dn2Gf_J1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-L0ZjfAh_.js → NotificationSettings-BRKBQ5rq.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BB1CvCK0.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DeLtgAD8.js → Organization-cqfccxnt.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CKC2b10z.js → Overflow-CSX4FHN3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-eyf2rzY1.js → P2P-Bwa4aghp.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-5upNIOW8.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-B8p3W6JK.js → Permissions-CXzTyk6e.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BnRMxTq3.js → PersonalDataHub-CFCAAJbb.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DjCNI1li.js → Pipeline-BPJbx6xt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-u6gXLbWT.js → Privacy-BbiXvEHz.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BZAw4tkM.js → ProjectInit-B-s7-wSD.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B1Tr72q7.js → ProjectSettings-Dyug206y.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DO7HFuBQ.js → Projects-BtAI5Fwo.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BjCztyhj.js → Providers-JpIPmz6N.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-ZWyCUbR1.js → QrScannerModal-CZdoN64A.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DhDjeW4G.js → QuickAsk-BwvnoRIT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-R_CN2MuU.js → Recommend-ASMlMQrD.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-uxFcujeu.js → RemoteSession-BiJzKFKi.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DX8D7rks.js → Reputation-C80TWLIO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BYahQILD.js → Row-C1VNmjmX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CUSQ2tm-.js → RssFeed-T2MyGUlG.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CnN_S8Cs.js → Search-DXM6O83L.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DcZlh-O4.js → Security-nv69kU7W.js} +4 -4
- package/src/assets/web-panel/assets/{Services-ZhBOjzIX.js → Services-AyHWe7Qj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D5Qnq_lI.js → Skeleton-D6PWLxFI.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BC9cZ3Be.js → Skills-BqVeOmNQ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DauJ3E8_.js → Sla-BegIPl9M.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-CKJn3xk-.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-DUvJbSct.js → SyncSettings-Th4cnAMl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BXa-5noQ.js → Tasks-BuKfBroh.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-JxaiUt_3.js → Templates-CMuWN8Ac.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BW4ERQN8.js → Tenant-C4je8E8Q.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DltUbdtv.js → Terminal-agJESOcO.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CMoZz0Tc.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D_VEV60K.js → Tokens-Cvmn99rH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CCXTCs0R.js → Trigger-D_QYIHH8.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-lkGRIPcG.js → Trust-BmzvQLnX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BfGeQ9HX.js → UkeySign-D_LopHwH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BEC7pYvc.js → VideoEditing-DoWl3PhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BZdG24o0.js → Wallet-5NYcAkxe.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-yoEddedp.js → WebAuthn-B-_Q3ewp.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-BXZEprOW.js → WorkflowEditor-CHET-gi2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-gg0bzZal.js → chat-C6nvb-n6.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DjRVRuin.js → colors-CTDE9LTX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-su-dieAc.js → compact-item-KnemdF8D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Ci3S8oKF.js → createContext-DUJR3Uek.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D8F10heH.js → hasIn-CFNTaby8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CusgZPtc.js → index-65HO56Bv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbF1IHof.js → index-B8RtbSkV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEmXRhAE.js → index-BHqSqnW7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIJ2qFOC.js → index-BTetEUWd.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUmDhC4j.js → index-BXWg1crv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBAETXft.js → index-BdiC4LOs.js} +1 -1
- package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
- package/src/assets/web-panel/assets/{index-Tu8eWqh-.js → index-BuizJo2E.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzPB6kGZ.js → index-BwZM1rod.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkMEF5VT.js → index-C96N9xeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTFpdBtt.js → index-CHfUdnJH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkfQR3hM.js → index-CKvBF3Ov.js} +1 -1
- package/src/assets/web-panel/assets/{index-T6_6ygJZ.js → index-CSD9_I2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CR0h6seT.js → index-Cc7dbl_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbq4NMET.js → index-CcF0D7UZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6ygzplr.js → index-Ceu92a8D.js} +1 -1
- package/src/assets/web-panel/assets/{index-11wtYQiF.js → index-CnLpuTAU.js} +1 -1
- package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
- package/src/assets/web-panel/assets/{index-1IgxgALJ.js → index-CquKnw5r.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMPqd5Cv.js → index-CyEtHvEE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMMOVoLD.js → index-DF-fcTvQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-W7XUgdVL.js → index-DF1Y0Vuw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyLUarhZ.js → index-DJyPeBBk.js} +3 -3
- package/src/assets/web-panel/assets/{index-BDJntYmJ.js → index-DP-PbO11.js} +1 -1
- package/src/assets/web-panel/assets/{index-COWd8uGx.js → index-DZgCRMxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-8Z-8BIlN.js → index-DfJzS3Qa.js} +1 -1
- package/src/assets/web-panel/assets/{index-dHZinfko.js → index-DqPpJkte.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCI5v0yB.js → index-DzReoLyh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPIYSp4H.js → index-JGTiDeOW.js} +1 -1
- package/src/assets/web-panel/assets/{index-jyNgp5FI.js → index-NUR0If7O.js} +1 -1
- package/src/assets/web-panel/assets/{index-6Tniqk1s.js → index-NtAcnJYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgT9su_e.js → index-OmuhFYKE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DugB_aKa.js → index-Wlc7o_C8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ba_HyPnE.js → index-bxTPfdri.js} +1 -1
- package/src/assets/web-panel/assets/{index-CC3ZDjzY.js → index-k6uorYmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-5JqhujnR.js → index-ox6mIwE2.js} +1 -1
- package/src/assets/web-panel/assets/{index-1agckWSq.js → index-rVDD7AAR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGzixOGZ.js → index-u0h6QqVV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnLucOn9.js → index-v-mtxmWH.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cv4p8e4w.js → initDefaultProps-qEt8dI-t.js} +1 -1
- package/src/assets/web-panel/assets/{motion-B8EwmMOw.js → motion-DetKPWy-.js} +1 -1
- package/src/assets/web-panel/assets/{move-B8R9F8TK.js → move-BeNYeDV2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DoFYz5Bp.js → mtc-parser-C0q0MK_T.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CHWYLBjI.js → omit-DLKkrKpE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CXuPDO77.js → pickAttrs-Bw1tWsY8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BaAtUUon.js → placementArrow-DeesBLbd.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DCc4zcDD.js → responsiveObserve-bqLhxHhn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B_lx89oZ.js → slide-DGCXRoQm.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DE8DPmR0.js → statusUtils-H-re3Egl.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-1ktXOsL_.js → styleChecker-BXg4qGX_.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-xH89-wjh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DscvfW5p.js → useFs-CTAhHeyw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-RdMKQta7.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Z3wTni2T.js → vnode-jrSK6j4j.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B0iChCsm.js → zoom-fOQE24pw.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +13 -0
- package/src/gateways/ws/mcp-topic-handlers.js +167 -0
- package/src/lib/agent-network.js +166 -29
- package/src/lib/agent-router.js +62 -6
- package/src/lib/agent-sandbox.js +7 -1
- package/src/lib/claude-code-bridge.js +159 -54
- package/src/lib/cowork-workflow.js +69 -6
- package/src/lib/external-agent-adapters.js +269 -0
- package/src/lib/ipfs-storage.js +127 -25
- package/src/lib/orchestrator.js +47 -0
- package/src/lib/shell-approval.js +7 -5
- package/src/lib/workflow-engine.js +42 -11
- package/src/runtime/agent-runtime.js +12 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +0 -1
- package/src/assets/web-panel/assets/McpTools-BBsN2CSW.js +0 -7
- package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +0 -1
- package/src/assets/web-panel/assets/index-CJGOlduY.js +0 -1
- package/src/assets/web-panel/assets/index-CkBCN5yH.js +0 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-specific contracts for non-interactive coding-agent CLIs.
|
|
3
|
+
*
|
|
4
|
+
* Keep argv construction and JSONL parsing here instead of assuming that two
|
|
5
|
+
* CLIs with similar product goals expose the same wire protocol.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const EXTERNAL_AGENT_PROTOCOL = Object.freeze({
|
|
9
|
+
CLAUDE_STREAM_JSON: "claude-stream-json-v1",
|
|
10
|
+
CODEX_EXEC_JSONL: "codex-exec-jsonl-v1",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const EXTERNAL_AGENT_ERROR = Object.freeze({
|
|
14
|
+
CANCELLED: "EXTERNAL_AGENT_CANCELLED",
|
|
15
|
+
TIMEOUT: "EXTERNAL_AGENT_TIMEOUT",
|
|
16
|
+
EXIT_NONZERO: "EXTERNAL_AGENT_EXIT_NONZERO",
|
|
17
|
+
SPAWN_FAILED: "EXTERNAL_AGENT_SPAWN_FAILED",
|
|
18
|
+
PROTOCOL_FAILED: "EXTERNAL_AGENT_PROTOCOL_FAILED",
|
|
19
|
+
UNSUPPORTED_OPTION: "EXTERNAL_AGENT_UNSUPPORTED_OPTION",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const KNOWN_CODEX_ITEM_TYPES = new Set([
|
|
23
|
+
"agent_message",
|
|
24
|
+
"reasoning",
|
|
25
|
+
"command_execution",
|
|
26
|
+
"file_change",
|
|
27
|
+
"mcp_tool_call",
|
|
28
|
+
"web_search",
|
|
29
|
+
"plan_update",
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
function stringifyValue(value) {
|
|
33
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function errorMessage(value, fallback) {
|
|
37
|
+
if (typeof value === "string" && value) return value;
|
|
38
|
+
if (value && typeof value.message === "string" && value.message) {
|
|
39
|
+
return value.message;
|
|
40
|
+
}
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Common adapter surface. Subclasses provide buildArgs() and parseEvent().
|
|
46
|
+
*/
|
|
47
|
+
export class ExternalAgentAdapter {
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.command = options.command;
|
|
50
|
+
this.model = options.model || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
capabilities() {
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
protocol: "unknown",
|
|
56
|
+
jsonl: false,
|
|
57
|
+
modelOverride: false,
|
|
58
|
+
allowedTools: false,
|
|
59
|
+
requiresTerminalEvent: false,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
buildArgs() {
|
|
64
|
+
throw new Error("ExternalAgentAdapter.buildArgs() must be implemented");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
parseEvent() {
|
|
68
|
+
throw new Error("ExternalAgentAdapter.parseEvent() must be implemented");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Reduce a JSONL transcript into a provider-neutral terminal projection.
|
|
73
|
+
* Unknown additive events are retained for diagnostics but do not make a
|
|
74
|
+
* successful run fail.
|
|
75
|
+
*/
|
|
76
|
+
parseTranscript(raw) {
|
|
77
|
+
const lines = String(raw || "")
|
|
78
|
+
.split(/\r?\n/)
|
|
79
|
+
.filter((line) => line.trim().length > 0);
|
|
80
|
+
const projection = {
|
|
81
|
+
output: "",
|
|
82
|
+
terminal: null,
|
|
83
|
+
error: null,
|
|
84
|
+
parsedEventCount: 0,
|
|
85
|
+
malformedLineCount: 0,
|
|
86
|
+
unknownEventTypes: [],
|
|
87
|
+
unknownItemTypes: [],
|
|
88
|
+
usage: null,
|
|
89
|
+
};
|
|
90
|
+
const unknownEvents = new Set();
|
|
91
|
+
const unknownItems = new Set();
|
|
92
|
+
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
let event;
|
|
95
|
+
try {
|
|
96
|
+
event = JSON.parse(line);
|
|
97
|
+
projection.parsedEventCount += 1;
|
|
98
|
+
} catch (_err) {
|
|
99
|
+
projection.malformedLineCount += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const normalized = this.parseEvent(event);
|
|
104
|
+
if (normalized.output) projection.output = normalized.output;
|
|
105
|
+
if (normalized.terminal) projection.terminal = normalized.terminal;
|
|
106
|
+
if (normalized.error) projection.error = normalized.error;
|
|
107
|
+
if (normalized.usage) projection.usage = normalized.usage;
|
|
108
|
+
if (normalized.unknownEventType) {
|
|
109
|
+
unknownEvents.add(normalized.unknownEventType);
|
|
110
|
+
}
|
|
111
|
+
if (normalized.unknownItemType) {
|
|
112
|
+
unknownItems.add(normalized.unknownItemType);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
projection.unknownEventTypes = [...unknownEvents];
|
|
117
|
+
projection.unknownItemTypes = [...unknownItems];
|
|
118
|
+
return projection;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export class ClaudeAdapter extends ExternalAgentAdapter {
|
|
123
|
+
constructor(options = {}) {
|
|
124
|
+
super({ ...options, command: options.command || "claude" });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
capabilities() {
|
|
128
|
+
return Object.freeze({
|
|
129
|
+
protocol: EXTERNAL_AGENT_PROTOCOL.CLAUDE_STREAM_JSON,
|
|
130
|
+
jsonl: true,
|
|
131
|
+
modelOverride: true,
|
|
132
|
+
allowedTools: true,
|
|
133
|
+
requiresTerminalEvent: true,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
buildArgs({ prompt, allowedTools = null } = {}) {
|
|
138
|
+
const args = ["-p", String(prompt || ""), "--output-format", "stream-json"];
|
|
139
|
+
if (this.model) args.push("--model", this.model);
|
|
140
|
+
if (allowedTools) args.push("--allowedTools", allowedTools);
|
|
141
|
+
return args;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
parseEvent(event) {
|
|
145
|
+
if (!event || typeof event !== "object") {
|
|
146
|
+
return { unknownEventType: "<non-object>" };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (event.type === "result") {
|
|
150
|
+
const failed = event.is_error === true || event.subtype === "error";
|
|
151
|
+
return {
|
|
152
|
+
output: event.result ? stringifyValue(event.result) : "",
|
|
153
|
+
terminal: failed ? "failed" : "completed",
|
|
154
|
+
error: failed
|
|
155
|
+
? errorMessage(event.error || event.result, "Claude Code turn failed")
|
|
156
|
+
: null,
|
|
157
|
+
usage: event.usage || null,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (event.type === "assistant" && Array.isArray(event.message?.content)) {
|
|
162
|
+
const output = event.message.content
|
|
163
|
+
.filter((block) => block?.type === "text")
|
|
164
|
+
.map((block) => block.text)
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.join("\n");
|
|
167
|
+
return { output };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// These are progress/input events in Claude Code stream-json.
|
|
171
|
+
if (["system", "user", "rate_limit_event"].includes(event.type)) {
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
return { unknownEventType: String(event.type || "<missing>") };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export class CodexAdapter extends ExternalAgentAdapter {
|
|
179
|
+
constructor(options = {}) {
|
|
180
|
+
super({ ...options, command: options.command || "codex" });
|
|
181
|
+
this.sandbox = options.sandbox || null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
capabilities() {
|
|
185
|
+
return Object.freeze({
|
|
186
|
+
protocol: EXTERNAL_AGENT_PROTOCOL.CODEX_EXEC_JSONL,
|
|
187
|
+
jsonl: true,
|
|
188
|
+
modelOverride: true,
|
|
189
|
+
allowedTools: false,
|
|
190
|
+
requiresTerminalEvent: true,
|
|
191
|
+
sandboxModes: ["read-only", "workspace-write", "danger-full-access"],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
buildArgs({ prompt, allowedTools = null } = {}) {
|
|
196
|
+
if (allowedTools) {
|
|
197
|
+
const err = new Error(
|
|
198
|
+
"Codex CLI does not expose Claude Code's --allowedTools option",
|
|
199
|
+
);
|
|
200
|
+
err.code = EXTERNAL_AGENT_ERROR.UNSUPPORTED_OPTION;
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const args = ["exec", "--json"];
|
|
205
|
+
if (this.model) args.push("--model", this.model);
|
|
206
|
+
if (this.sandbox) args.push("--sandbox", this.sandbox);
|
|
207
|
+
args.push(String(prompt || ""));
|
|
208
|
+
return args;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
parseEvent(event) {
|
|
212
|
+
if (!event || typeof event !== "object") {
|
|
213
|
+
return { unknownEventType: "<non-object>" };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
switch (event.type) {
|
|
217
|
+
case "thread.started":
|
|
218
|
+
case "turn.started":
|
|
219
|
+
return {};
|
|
220
|
+
case "turn.completed":
|
|
221
|
+
return {
|
|
222
|
+
terminal: "completed",
|
|
223
|
+
usage: event.usage || null,
|
|
224
|
+
};
|
|
225
|
+
case "turn.failed":
|
|
226
|
+
return {
|
|
227
|
+
terminal: "failed",
|
|
228
|
+
error: errorMessage(event.error, "Codex turn failed"),
|
|
229
|
+
};
|
|
230
|
+
case "error":
|
|
231
|
+
return {
|
|
232
|
+
terminal: "failed",
|
|
233
|
+
error: errorMessage(event.error || event, "Codex emitted an error"),
|
|
234
|
+
};
|
|
235
|
+
case "item.started":
|
|
236
|
+
case "item.updated":
|
|
237
|
+
case "item.completed": {
|
|
238
|
+
const itemType = event.item?.type;
|
|
239
|
+
const unknownItemType =
|
|
240
|
+
itemType && !KNOWN_CODEX_ITEM_TYPES.has(itemType)
|
|
241
|
+
? String(itemType)
|
|
242
|
+
: null;
|
|
243
|
+
const output =
|
|
244
|
+
event.type === "item.completed" &&
|
|
245
|
+
itemType === "agent_message" &&
|
|
246
|
+
typeof event.item?.text === "string"
|
|
247
|
+
? event.item.text
|
|
248
|
+
: "";
|
|
249
|
+
return { output, unknownItemType };
|
|
250
|
+
}
|
|
251
|
+
default:
|
|
252
|
+
return { unknownEventType: String(event.type || "<missing>") };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function createExternalAgentAdapter(options = {}) {
|
|
258
|
+
const command = options.command || options.cliCommand || "claude";
|
|
259
|
+
if (command === "codex" || /(^|[\\/])codex(?:\.cmd|\.exe)?$/i.test(command)) {
|
|
260
|
+
return new CodexAdapter({ ...options, command });
|
|
261
|
+
}
|
|
262
|
+
if (
|
|
263
|
+
command === "claude" ||
|
|
264
|
+
/(^|[\\/])claude(?:\.cmd|\.exe)?$/i.test(command)
|
|
265
|
+
) {
|
|
266
|
+
return new ClaudeAdapter({ ...options, command });
|
|
267
|
+
}
|
|
268
|
+
throw new Error(`Unsupported external agent CLI: ${command}`);
|
|
269
|
+
}
|
package/src/lib/ipfs-storage.js
CHANGED
|
@@ -21,6 +21,35 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import crypto from "crypto";
|
|
24
|
+
import { createSecretStore } from "./secret-store.js";
|
|
25
|
+
|
|
26
|
+
let configuredIpfsSecretStore = null;
|
|
27
|
+
|
|
28
|
+
export function setIpfsSecretStore(secretStore) {
|
|
29
|
+
if (
|
|
30
|
+
!secretStore ||
|
|
31
|
+
typeof secretStore.set !== "function" ||
|
|
32
|
+
typeof secretStore.get !== "function" ||
|
|
33
|
+
typeof secretStore.delete !== "function"
|
|
34
|
+
) {
|
|
35
|
+
throw new TypeError("IPFS storage requires a SecretStore");
|
|
36
|
+
}
|
|
37
|
+
configuredIpfsSecretStore = secretStore;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getIpfsSecretStore() {
|
|
41
|
+
if (!configuredIpfsSecretStore) {
|
|
42
|
+
configuredIpfsSecretStore = createSecretStore({
|
|
43
|
+
service: "chainlesschain-ipfs-dek",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return configuredIpfsSecretStore;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function _encryptionKeyRef(cid) {
|
|
50
|
+
const digest = crypto.createHash("sha256").update(cid).digest("hex");
|
|
51
|
+
return `ipfs/dek/${digest}`;
|
|
52
|
+
}
|
|
24
53
|
|
|
25
54
|
/* ── Constants ──────────────────────────────────────────── */
|
|
26
55
|
|
|
@@ -91,7 +120,8 @@ export function ensureIpfsTables(db) {
|
|
|
91
120
|
mime_type TEXT,
|
|
92
121
|
pinned INTEGER DEFAULT 0,
|
|
93
122
|
encrypted INTEGER DEFAULT 0,
|
|
94
|
-
encryption_key TEXT,
|
|
123
|
+
encryption_key TEXT DEFAULT '',
|
|
124
|
+
encryption_key_ref TEXT,
|
|
95
125
|
knowledge_id TEXT,
|
|
96
126
|
metadata TEXT,
|
|
97
127
|
payload TEXT,
|
|
@@ -105,9 +135,63 @@ export function ensureIpfsTables(db) {
|
|
|
105
135
|
updated_at INTEGER NOT NULL
|
|
106
136
|
)`);
|
|
107
137
|
|
|
138
|
+
const columns = db.prepare("PRAGMA table_info(ipfs_content)").all();
|
|
139
|
+
if (
|
|
140
|
+
columns.length > 0 &&
|
|
141
|
+
!columns.some((entry) => entry.name === "encryption_key_ref")
|
|
142
|
+
) {
|
|
143
|
+
db.exec("ALTER TABLE ipfs_content ADD COLUMN encryption_key_ref TEXT");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
migrateIpfsEncryptionKeys(db);
|
|
147
|
+
|
|
108
148
|
_loadAll(db);
|
|
109
149
|
}
|
|
110
150
|
|
|
151
|
+
export function migrateIpfsEncryptionKeys(db, { dryRun = false } = {}) {
|
|
152
|
+
db.exec("PRAGMA secure_delete = ON");
|
|
153
|
+
const rows = db
|
|
154
|
+
.prepare("SELECT cid, encryption_key, encryption_key_ref FROM ipfs_content")
|
|
155
|
+
.all()
|
|
156
|
+
.filter((row) => row.encryption_key && !row.encryption_key_ref);
|
|
157
|
+
if (dryRun) {
|
|
158
|
+
return { pending: rows.length, migrated: 0, dryRun: true };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (rows.length > 0 && typeof db.transaction !== "function") {
|
|
162
|
+
throw new Error(
|
|
163
|
+
"IPFS data-key migration requires transactional database support",
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const secretStore = rows.length > 0 ? getIpfsSecretStore() : null;
|
|
168
|
+
const stagedKeyRefs = [];
|
|
169
|
+
try {
|
|
170
|
+
for (const row of rows) {
|
|
171
|
+
const keyRef = _encryptionKeyRef(row.cid);
|
|
172
|
+
secretStore.set(keyRef, row.encryption_key);
|
|
173
|
+
stagedKeyRefs.push(keyRef);
|
|
174
|
+
}
|
|
175
|
+
const applyMigration = db.transaction(() => {
|
|
176
|
+
for (const row of rows) {
|
|
177
|
+
const keyRef = _encryptionKeyRef(row.cid);
|
|
178
|
+
db.prepare(
|
|
179
|
+
"UPDATE ipfs_content SET encryption_key = ?, encryption_key_ref = ? WHERE cid = ?",
|
|
180
|
+
).run("", keyRef, row.cid);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
applyMigration();
|
|
184
|
+
} catch (error) {
|
|
185
|
+
for (const keyRef of stagedKeyRefs) secretStore.delete(keyRef);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
pending: rows.length,
|
|
190
|
+
migrated: rows.length,
|
|
191
|
+
dryRun: false,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
111
195
|
function _loadAll(db) {
|
|
112
196
|
_content.clear();
|
|
113
197
|
_knowledgeLinks.clear();
|
|
@@ -263,6 +347,7 @@ export function addContent(
|
|
|
263
347
|
}
|
|
264
348
|
|
|
265
349
|
const cid = _computeCid(payload);
|
|
350
|
+
const encryptionKeyRef = encryptionKey ? _encryptionKeyRef(cid) : null;
|
|
266
351
|
|
|
267
352
|
// Idempotent: if CID exists, just update flags
|
|
268
353
|
const existing = _content.get(cid);
|
|
@@ -301,7 +386,8 @@ export function addContent(
|
|
|
301
386
|
mime_type: mimeType || null,
|
|
302
387
|
pinned: pin ? 1 : 0,
|
|
303
388
|
encrypted: encrypt ? 1 : 0,
|
|
304
|
-
encryption_key:
|
|
389
|
+
encryption_key: "",
|
|
390
|
+
encryption_key_ref: encryptionKeyRef,
|
|
305
391
|
knowledge_id: knowledgeId || null,
|
|
306
392
|
metadata: metadataJson,
|
|
307
393
|
payload: payloadBase64,
|
|
@@ -309,24 +395,33 @@ export function addContent(
|
|
|
309
395
|
updated_at: now,
|
|
310
396
|
};
|
|
311
397
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
398
|
+
if (encryptionKeyRef) {
|
|
399
|
+
getIpfsSecretStore().set(encryptionKeyRef, encryptionKey);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
db.prepare(
|
|
403
|
+
`INSERT INTO ipfs_content (id, cid, filename, size, mime_type, pinned, encrypted, encryption_key, encryption_key_ref, knowledge_id, metadata, payload, created_at, updated_at)
|
|
404
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
405
|
+
).run(
|
|
406
|
+
id,
|
|
407
|
+
cid,
|
|
408
|
+
entry.filename,
|
|
409
|
+
size,
|
|
410
|
+
entry.mime_type,
|
|
411
|
+
entry.pinned,
|
|
412
|
+
entry.encrypted,
|
|
413
|
+
entry.encryption_key,
|
|
414
|
+
entry.encryption_key_ref,
|
|
415
|
+
entry.knowledge_id,
|
|
416
|
+
entry.metadata,
|
|
417
|
+
entry.payload,
|
|
418
|
+
now,
|
|
419
|
+
now,
|
|
420
|
+
);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
if (encryptionKeyRef) getIpfsSecretStore().delete(encryptionKeyRef);
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
330
425
|
|
|
331
426
|
_content.set(cid, entry);
|
|
332
427
|
if (knowledgeId) {
|
|
@@ -350,9 +445,12 @@ export function getContent(db, cid, { asString } = {}) {
|
|
|
350
445
|
if (!entry) return null;
|
|
351
446
|
|
|
352
447
|
let buffer = Buffer.from(entry.payload, "base64");
|
|
353
|
-
if (entry.encrypted
|
|
448
|
+
if (entry.encrypted) {
|
|
354
449
|
try {
|
|
355
|
-
|
|
450
|
+
if (!entry.encryption_key_ref) return null;
|
|
451
|
+
const encryptionKey = getIpfsSecretStore().get(entry.encryption_key_ref);
|
|
452
|
+
if (!encryptionKey) return null;
|
|
453
|
+
buffer = _decrypt(buffer, encryptionKey);
|
|
356
454
|
} catch (_e) {
|
|
357
455
|
return null;
|
|
358
456
|
}
|
|
@@ -395,7 +493,7 @@ export function listContent(db, { pinned, knowledgeId, limit = 50 } = {}) {
|
|
|
395
493
|
.sort((a, b) => b.created_at - a.created_at)
|
|
396
494
|
.slice(0, limit)
|
|
397
495
|
.map((c) => {
|
|
398
|
-
const { payload, encryption_key, ...rest } = c;
|
|
496
|
+
const { payload, encryption_key, encryption_key_ref, ...rest } = c;
|
|
399
497
|
return rest;
|
|
400
498
|
});
|
|
401
499
|
}
|
|
@@ -446,7 +544,7 @@ export function listPins(db, { limit = 50, sortBy = "created_at" } = {}) {
|
|
|
446
544
|
.sort(sorter)
|
|
447
545
|
.slice(0, limit)
|
|
448
546
|
.map((c) => {
|
|
449
|
-
const { payload, encryption_key, ...rest } = c;
|
|
547
|
+
const { payload, encryption_key, encryption_key_ref, ...rest } = c;
|
|
450
548
|
return rest;
|
|
451
549
|
});
|
|
452
550
|
}
|
|
@@ -501,8 +599,12 @@ export function garbageCollect(db) {
|
|
|
501
599
|
}
|
|
502
600
|
}
|
|
503
601
|
for (const cid of toRemove) {
|
|
602
|
+
const entry = _content.get(cid);
|
|
504
603
|
_content.delete(cid);
|
|
505
604
|
db.prepare("DELETE FROM ipfs_content WHERE cid = ?").run(cid);
|
|
605
|
+
if (entry?.encryption_key_ref) {
|
|
606
|
+
getIpfsSecretStore().delete(entry.encryption_key_ref);
|
|
607
|
+
}
|
|
506
608
|
}
|
|
507
609
|
// Clean up knowledge links pointing to removed CIDs
|
|
508
610
|
for (const [kid, set] of _knowledgeLinks) {
|
|
@@ -555,7 +657,7 @@ export function getKnowledgeAttachments(db, knowledgeId) {
|
|
|
555
657
|
.map((cid) => _content.get(cid))
|
|
556
658
|
.filter(Boolean)
|
|
557
659
|
.map((c) => {
|
|
558
|
-
const { payload, encryption_key, ...rest } = c;
|
|
660
|
+
const { payload, encryption_key, encryption_key_ref, ...rest } = c;
|
|
559
661
|
return rest;
|
|
560
662
|
});
|
|
561
663
|
}
|
package/src/lib/orchestrator.js
CHANGED
|
@@ -28,6 +28,17 @@ import { NotificationManager } from "./notifiers/index.js";
|
|
|
28
28
|
import { createChatFn } from "./cowork-adapter.js";
|
|
29
29
|
import { firstBalancedJson } from "./json-schema-output.js";
|
|
30
30
|
import executionBroker from "./process-execution-broker/index.js";
|
|
31
|
+
import runtimeClaimsContract from "@chainlesschain/session-core/runtime-claims";
|
|
32
|
+
|
|
33
|
+
const { RUNTIME_MODE, createRuntimeClaims, hasTerminalSuccessEvidence } =
|
|
34
|
+
runtimeClaimsContract;
|
|
35
|
+
|
|
36
|
+
const ORCHESTRATOR_RUNTIME_CLAIMS = createRuntimeClaims({
|
|
37
|
+
mode: RUNTIME_MODE.REAL_EXECUTION,
|
|
38
|
+
durable: false,
|
|
39
|
+
crashSafe: false,
|
|
40
|
+
isolatedWrites: false,
|
|
41
|
+
});
|
|
31
42
|
|
|
32
43
|
/* ---------- _deps injection (Vitest CJS mock pattern) ---------- */
|
|
33
44
|
export const _deps = {
|
|
@@ -160,6 +171,8 @@ export class Orchestrator extends EventEmitter {
|
|
|
160
171
|
ciErrors: [],
|
|
161
172
|
createdAt: new Date().toISOString(),
|
|
162
173
|
completedAt: null,
|
|
174
|
+
runtimeClaims: ORCHESTRATOR_RUNTIME_CLAIMS,
|
|
175
|
+
terminalEvidence: [],
|
|
163
176
|
};
|
|
164
177
|
|
|
165
178
|
this._tasks.set(task.id, task);
|
|
@@ -192,6 +205,8 @@ export class Orchestrator extends EventEmitter {
|
|
|
192
205
|
source: t.source,
|
|
193
206
|
retries: t.retries,
|
|
194
207
|
createdAt: t.createdAt,
|
|
208
|
+
runtimeClaims: t.runtimeClaims,
|
|
209
|
+
terminalEvidence: t.terminalEvidence,
|
|
195
210
|
}));
|
|
196
211
|
return {
|
|
197
212
|
tasks,
|
|
@@ -228,6 +243,7 @@ export class Orchestrator extends EventEmitter {
|
|
|
228
243
|
|
|
229
244
|
// Step 2: Dispatch to Claude Code agents
|
|
230
245
|
task.agentResults = await this._dispatch(task);
|
|
246
|
+
this._assertSuccessfulAgentResults(task);
|
|
231
247
|
|
|
232
248
|
// Step 3: CI/CD check
|
|
233
249
|
if (task.runCI) {
|
|
@@ -368,6 +384,7 @@ export class Orchestrator extends EventEmitter {
|
|
|
368
384
|
task.agentResults = await this._router.dispatch(fixSubtasks, {
|
|
369
385
|
cwd: task.cwd,
|
|
370
386
|
});
|
|
387
|
+
this._assertSuccessfulAgentResults(task);
|
|
371
388
|
this.emit("agents:complete", { task, results: task.agentResults });
|
|
372
389
|
}
|
|
373
390
|
|
|
@@ -409,6 +426,36 @@ export class Orchestrator extends EventEmitter {
|
|
|
409
426
|
}
|
|
410
427
|
}
|
|
411
428
|
|
|
429
|
+
_assertSuccessfulAgentResults(task) {
|
|
430
|
+
if (!Array.isArray(task.agentResults) || task.agentResults.length === 0) {
|
|
431
|
+
throw new Error("Agent dispatch produced no terminal results");
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const failed = [];
|
|
435
|
+
const evidence = [];
|
|
436
|
+
for (let index = 0; index < task.agentResults.length; index += 1) {
|
|
437
|
+
const result = task.agentResults[index];
|
|
438
|
+
const valid =
|
|
439
|
+
result?.success === true &&
|
|
440
|
+
hasTerminalSuccessEvidence(
|
|
441
|
+
result.runtimeClaims,
|
|
442
|
+
result.terminalEvidence,
|
|
443
|
+
);
|
|
444
|
+
if (!valid) {
|
|
445
|
+
failed.push(
|
|
446
|
+
`${result?.taskId || `result-${index}`}: ${result?.error || result?.status || "missing terminal evidence"}`,
|
|
447
|
+
);
|
|
448
|
+
} else {
|
|
449
|
+
evidence.push(...result.terminalEvidence);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (failed.length > 0) {
|
|
454
|
+
throw new Error(`Agent execution did not succeed: ${failed.join("; ")}`);
|
|
455
|
+
}
|
|
456
|
+
task.terminalEvidence = evidence;
|
|
457
|
+
}
|
|
458
|
+
|
|
412
459
|
/**
|
|
413
460
|
* Bound retained task history to maxTasks. Evicts the oldest TERMINAL tasks
|
|
414
461
|
* first (Map preserves insertion order = FIFO); an in-flight task is never
|
|
@@ -238,13 +238,15 @@ export async function evaluateShellCommandWithApproval({
|
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
//
|
|
241
|
+
// A missing gate is an unavailable security boundary, not an implicit
|
|
242
|
+
// authorization. Explicit bypass modes must provide their own auditable
|
|
243
|
+
// gate implementation instead of omitting the gate.
|
|
242
244
|
if (!approvalGate || typeof approvalGate.decide !== "function") {
|
|
243
245
|
return {
|
|
244
|
-
allowed:
|
|
245
|
-
decision: DECISION.
|
|
246
|
-
via: "
|
|
247
|
-
reason:
|
|
246
|
+
allowed: false,
|
|
247
|
+
decision: DECISION.DENY,
|
|
248
|
+
via: "approval-gate-unavailable",
|
|
249
|
+
reason: "Approval gate is unavailable",
|
|
248
250
|
shellPolicy,
|
|
249
251
|
riskLevel,
|
|
250
252
|
policy: null,
|