chainlesschain 0.165.9 → 0.166.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/completions/_cc +2 -1
- package/completions/cc.bash +2 -2
- package/completions/cc.fish +2 -2
- package/completions/cc.ps1 +2 -1
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-DxwjrnEA.js → AIOps-D5_pwQ7M.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-JdbYowzn.js → ActionButton-DgoYO32D.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C06GCahv.js → Analytics-BIpoZ4QH.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BUVEEyi1.js → AppLayout-BJ3XrCEe.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-D_ORzkJd.js → Artifacts-DUFs_izZ.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-8o_Y5ejG.js → Audit-BZdPwwfL.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DrkHd5VU.js → BackgroundAgents-DK9Fn-8B.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CKBZCX11.js → Backup-Bd6bOhV_.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C8HkI399.js → BaseInput-CRnWlXrd.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-zb2H2Wux.js → Chat-D1G_yEl6.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BDcNpU_F.js → ChatBubbleRenderer-DDAlEtm-.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-MwPtQmNz.js → Checkbox-CP35SH7R.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-3p5QCkFK.js → Codegen-DugeL4pj.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BPLlhn52.js → Col-DPuJsvKg.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C-3dBNOM.js → Community-CZqNjNNp.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BUcy-F_b.js → Compact-eeyIPEAb.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CI8NxT8m.js → Compliance-MGzTw87k.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DaDEBS-Q.js → Cowork-D3goVIA5.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BSv9HXu5.js → Cron-9HA8hLLG.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-yuiKlJmv.js → Crosschain-DCSOX3l6.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D6LfldB0.js → DID-ji3lN5Bc.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CBhLqG61.js → Dashboard-DlZvF1E5.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BG8pIl3O.js → Dropdown-2FyZcow9.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CY92VIE6.js → EmailListRenderer-qH2bSpSY.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-1Q_ehauM.js → FamilyGuardDashboard-Bfx47wZj.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D3XirJIU.js → Federation-DhGcZbIv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DfI9UuGZ.js → FormItemContext-BMgi9_YQ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-IeCZk2m7.js → GenericCardRenderer-DugMac-4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DzK4IJAZ.js → Git-D943BpH-.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BHf5KfmQ.js → Governance-DZ66a8Aa.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BmaxSALS.js → Inference-B00Mp2tN.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BgePFLA9.js → KnowledgeGraph-BdwXXO2Q.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-nqgxpOc4.js → Logs-_MVXyYWc.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-hOTeNyi7.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Bu8to-86.js → Marketplace-CxeHRsnO.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BFWTzEk0.js → McpTools-BOieTxZ4.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-B026G2GA.js → Memory-BQD26CM3.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CM2Eeg6I.js → MobileBridge-CPJ8ZlvR.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B79Ob3hy.js → MobileProjects-D7qRVu0y.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CxevSZuV.js → Mtc-BOyndGuk.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-X396cPEX.js → MtcAudit-CXQ_8ZoR.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-HWIB_aZ1.js → Multisig-32Oh9KbH.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-gnYD1Xwy.js → NLProgramming-CFAd00CX.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dn2Gf_J1.js → Notes-BBCY_qJA.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BRKBQ5rq.js → NotificationSettings-uaQ0PdmW.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Dy___Cgo.js → OrderTableRenderer-kpBxJ-SG.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-cqfccxnt.js → Organization-CmFn7Oeo.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CSX4FHN3.js → Overflow-R_avat3a.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Bwa4aghp.js → P2P-BIhLFmkY.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Dhszyjig.js → PdhVaultBrowser-DTJjk-_i.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CXzTyk6e.js → Permissions-CkzYv8Yb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CFCAAJbb.js → PersonalDataHub--0QvN2Nz.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BPJbx6xt.js → Pipeline-Bfw5gQCH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BbiXvEHz.js → Privacy-DicjKfax.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B-s7-wSD.js → ProjectInit-DUl_ykBp.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Dyug206y.js → ProjectSettings-CPYDvN8a.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BtAI5Fwo.js → Projects-DnZ9_fAr.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-JpIPmz6N.js → Providers-BX1jP31w.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CZdoN64A.js → QrScannerModal-COab5qUl.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BwvnoRIT.js → QuickAsk-CdKQ_JZ0.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-ASMlMQrD.js → Recommend-BPFHg8pK.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BiJzKFKi.js → RemoteSession-CqrfTJvO.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-C80TWLIO.js → Reputation-DM-l8Pb3.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C1VNmjmX.js → Row-CKGBTeCw.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-T2MyGUlG.js → RssFeed-Wb0YHIkc.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DXM6O83L.js → Search-DiBjxKv-.js} +1 -1
- package/src/assets/web-panel/assets/{Security-nv69kU7W.js → Security-BAVEmbWP.js} +4 -4
- package/src/assets/web-panel/assets/{Services-AyHWe7Qj.js → Services-A_a3TIRn.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D6PWLxFI.js → Skeleton-CloHJ-I7.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BqVeOmNQ.js → Skills-CkvV5hKa.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BegIPl9M.js → Sla-BYozxxsV.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CKJn3xk-.js → SpeechSettings-CWianiZF.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Th4cnAMl.js → SyncSettings-BR4G75do.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BuKfBroh.js → Tasks-D6gyUVrM.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CMuWN8Ac.js → Templates-DbfYIRzT.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C4je8E8Q.js → Tenant-BHutvukT.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-agJESOcO.js → Terminal-CYEiy2wJ.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D2qDuVZ_.js → TimelineRenderer-D9s1AxfE.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Cvmn99rH.js → Tokens-ij9vxnoy.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-D_QYIHH8.js → Trigger-Dq_DCVeQ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BmzvQLnX.js → Trust-Bs6wdfoH.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D_LopHwH.js → UkeySign-CLazyr5t.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DoWl3PhQ.js → VideoEditing-viWotIHA.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-5NYcAkxe.js → Wallet-DlZ-A78d.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-B-_Q3ewp.js → WebAuthn-DSmOND3Y.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-CHET-gi2.js → WorkflowEditor-BempLOJi.js} +1 -1
- package/src/assets/web-panel/assets/{chat-C6nvb-n6.js → chat-CyJzf4JI.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CTDE9LTX.js → colors-C62q7WrL.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-KnemdF8D.js → compact-item-7dYM1KW3.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DUJR3Uek.js → createContext-CYTy7z2Q.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BdTg_AMF.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CFNTaby8.js → hasIn-DHoclUqm.js} +1 -1
- package/src/assets/web-panel/assets/{index-65HO56Bv.js → index-2C8Xx2UO.js} +1 -1
- package/src/assets/web-panel/assets/{index-ox6mIwE2.js → index-3pI7AfmD.js} +1 -1
- package/src/assets/web-panel/assets/{index-JGTiDeOW.js → index-4gWv-Ubg.js} +1 -1
- package/src/assets/web-panel/assets/{index-rVDD7AAR.js → index-94ktimZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-OmuhFYKE.js → index-9uR7rc9a.js} +1 -1
- package/src/assets/web-panel/assets/index-B6WvFV4N.js +1 -0
- package/src/assets/web-panel/assets/index-BKgfptzA.js +1 -0
- package/src/assets/web-panel/assets/{index-CquKnw5r.js → index-BMRmxFU_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzReoLyh.js → index-BMxvWauP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DP-PbO11.js → index-BghdJ87W.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSD9_I2_.js → index-Bzz0aJ86.js} +1 -1
- package/src/assets/web-panel/assets/{index-DF1Y0Vuw.js → index-C2efftJb.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8RtbSkV.js → index-C5YWYlW9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHfUdnJH.js → index-CVTnruDt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwZM1rod.js → index-CW86F2Zw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEtHvEE.js → index-CZRBvN6i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ceu92a8D.js → index-CjeViaU-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJyPeBBk.js → index-CnEZ4ZHj.js} +3 -3
- package/src/assets/web-panel/assets/{index-BdiC4LOs.js → index-D6BC4mmz.js} +1 -1
- package/src/assets/web-panel/assets/{index-k6uorYmf.js → index-DA-_807C.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqPpJkte.js → index-DAYanuSk.js} +1 -1
- package/src/assets/web-panel/assets/{index-NtAcnJYW.js → index-DHgSRimK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Wlc7o_C8.js → index-DJzZaPlb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKvBF3Ov.js → index-DK84lAS0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcF0D7UZ.js → index-DKdv8cju.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnLpuTAU.js → index-DNLD3nZY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZgCRMxk.js → index-DOFAwpUK.js} +1 -1
- package/src/assets/web-panel/assets/{index-v-mtxmWH.js → index-DYKwGrAn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc7dbl_p.js → index-DghnbMlY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuizJo2E.js → index-DhJjifZe.js} +1 -1
- package/src/assets/web-panel/assets/{index-NUR0If7O.js → index-DkczsbiP.js} +1 -1
- package/src/assets/web-panel/assets/{index-u0h6QqVV.js → index-DvEtHpLc.js} +1 -1
- package/src/assets/web-panel/assets/{index-bxTPfdri.js → index-Dyq9tK5u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfJzS3Qa.js → index-LK1MZoBj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DF-fcTvQ.js → index-NuNCstRO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXWg1crv.js → index-QXtrdrub.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTetEUWd.js → index-XrsAHHQN.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHqSqnW7.js → index-ZXYp76IB.js} +1 -1
- package/src/assets/web-panel/assets/{index-C96N9xeL.js → index-lHfNxiB5.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-qEt8dI-t.js → initDefaultProps-CwCl5sFQ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DetKPWy-.js → motion-BFJFy70N.js} +1 -1
- package/src/assets/web-panel/assets/{move-BeNYeDV2.js → move-ByrtVGq8.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C0q0MK_T.js → mtc-parser-BFiH1mT3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DLKkrKpE.js → omit-bdvgpivj.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Bw1tWsY8.js → pickAttrs-BlfuuE3s.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DeesBLbd.js → placementArrow-t2SC3DMy.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-bqLhxHhn.js → responsiveObserve-CoEXv2Li.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DGCXRoQm.js → slide-BfXCf0Fu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-H-re3Egl.js → statusUtils-DNsdyOuS.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BXg4qGX_.js → styleChecker-9aHukmoG.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CKLb2KA6.js → useFlexGapSupport-dTkPxzHN.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CTAhHeyw.js → useFs-DINwfItP.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BQ4pDh5g.js → usePersonalDataHub-Bj_RriBV.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-jrSK6j4j.js → vnode-BzRAZrTc.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-fOQE24pw.js → zoom-CamPjkeK.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +4 -4
- package/src/command-manifest.json +1 -1
- package/src/commands/agent.js +1 -1
- package/src/commands/graph.js +100 -0
- package/src/commands/mcp.js +49 -21
- package/src/commands/orchestrate.js +85 -18
- package/src/commands/serve.js +39 -0
- package/src/commands/team.js +2 -0
- package/src/data/changelog.json +26 -0
- package/src/generated/cc-agent-protocol.schema.json +1964 -0
- package/src/lib/agent-sandbox.js +4 -7
- package/src/lib/app-server/bounded-queue.js +87 -0
- package/src/lib/app-server/cli-agent-kernel-adapter.js +309 -0
- package/src/lib/app-server/protocol.js +125 -0
- package/src/lib/app-server/rollout-store.js +603 -0
- package/src/lib/app-server/server.js +922 -0
- package/src/lib/app-server/sqlite-rollout-store.js +315 -0
- package/src/lib/app-server/stdio-transport.js +118 -0
- package/src/lib/codex-app-server-adapter.js +249 -0
- package/src/lib/graph-kernel/adapters.js +238 -0
- package/src/lib/graph-kernel/compiler.js +911 -0
- package/src/lib/graph-kernel/eval.js +207 -0
- package/src/lib/graph-kernel/event-store.js +101 -0
- package/src/lib/graph-kernel/index.js +7 -0
- package/src/lib/graph-kernel/runtime.js +2660 -0
- package/src/lib/graph-kernel/trace-reducer.js +315 -0
- package/src/lib/graph-kernel/trigger-adapter.js +183 -0
- package/src/lib/orchestrator.js +2 -1
- package/src/lib/record-replay/index.js +1 -0
- package/src/lib/record-replay/skill-recorder.js +386 -0
- package/src/lib/webhook-security.js +159 -0
- package/src/repl/agent-repl.js +5 -4
- package/src/repl/prompt-interactions.js +11 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +0 -1
- package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +0 -1
- package/src/assets/web-panel/assets/index-BhJtcPWo.js +0 -1
- package/src/assets/web-panel/assets/index-Cq8MWPDT.js +0 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const SAFE_ACTION_CAPABILITIES = Object.freeze({
|
|
4
|
+
observe: "ui.observe",
|
|
5
|
+
click: "ui.interact",
|
|
6
|
+
type: "ui.interact",
|
|
7
|
+
select: "ui.interact",
|
|
8
|
+
assert: "ui.observe",
|
|
9
|
+
});
|
|
10
|
+
const SECRET_PATTERNS = Object.freeze([
|
|
11
|
+
/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/u,
|
|
12
|
+
/\bbearer\s+[A-Za-z0-9._~+/-]{6,}/iu,
|
|
13
|
+
/\b(?:bearer|token|password|passwd|secret|api[_-]?key)\s*[:=]\s*[^\s]{6,}/iu,
|
|
14
|
+
/\bAKIA[0-9A-Z]{16}\b/u,
|
|
15
|
+
/\b(?:sk|ghp|github_pat)_[A-Za-z0-9_-]{16,}\b/u,
|
|
16
|
+
]);
|
|
17
|
+
const PII_PATTERNS = Object.freeze([
|
|
18
|
+
/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/iu,
|
|
19
|
+
/(?<!\d)(?:\+?86[- ]?)?1[3-9]\d{9}(?!\d)/u,
|
|
20
|
+
/\b\d{3}-\d{2}-\d{4}\b/u,
|
|
21
|
+
]);
|
|
22
|
+
const VOLATILE_PATTERNS = Object.freeze([
|
|
23
|
+
/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/iu,
|
|
24
|
+
/\b20\d{2}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/u,
|
|
25
|
+
/(?:^|[\\/])(?:tmp|temp)(?:[\\/]|$)/iu,
|
|
26
|
+
]);
|
|
27
|
+
const PARAMETER_PATTERN = /^\$\{parameter\.([A-Za-z][A-Za-z0-9_]*)\}$/u;
|
|
28
|
+
|
|
29
|
+
function canonicalValue(value) {
|
|
30
|
+
if (Array.isArray(value)) return value.map(canonicalValue);
|
|
31
|
+
if (!value || typeof value !== "object") return value;
|
|
32
|
+
return Object.fromEntries(
|
|
33
|
+
Object.keys(value)
|
|
34
|
+
.sort()
|
|
35
|
+
.map((key) => [key, canonicalValue(value[key])]),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function digest(value, domain) {
|
|
40
|
+
return `sha256:${createHash("sha256")
|
|
41
|
+
.update(domain)
|
|
42
|
+
.update("\0")
|
|
43
|
+
.update(JSON.stringify(canonicalValue(value)))
|
|
44
|
+
.digest("hex")}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function clone(value) {
|
|
48
|
+
return value == null ? value : JSON.parse(JSON.stringify(value));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function recorderError(code, message, details = {}) {
|
|
52
|
+
const error = new Error(message);
|
|
53
|
+
error.name = "RecordReplayError";
|
|
54
|
+
error.code = code;
|
|
55
|
+
Object.assign(error, details);
|
|
56
|
+
return error;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function walkStrings(value, visit, path = "#") {
|
|
60
|
+
if (typeof value === "string") {
|
|
61
|
+
visit(value, path);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
value.forEach((item, index) =>
|
|
66
|
+
walkStrings(item, visit, `${path}/${index}`),
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!value || typeof value !== "object") return;
|
|
71
|
+
for (const [key, child] of Object.entries(value)) {
|
|
72
|
+
walkStrings(child, visit, `${path}/${key}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function substituteCaptured(value, bindings) {
|
|
77
|
+
if (typeof value === "string") {
|
|
78
|
+
return bindings.reduce(
|
|
79
|
+
(current, binding) =>
|
|
80
|
+
current.split(binding.value).join(`\${parameter.${binding.name}}`),
|
|
81
|
+
value,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value.map((item) => substituteCaptured(item, bindings));
|
|
86
|
+
}
|
|
87
|
+
if (!value || typeof value !== "object") return value;
|
|
88
|
+
return Object.fromEntries(
|
|
89
|
+
Object.entries(value).map(([key, child]) => [
|
|
90
|
+
key,
|
|
91
|
+
substituteCaptured(child, bindings),
|
|
92
|
+
]),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function scanRecordedValue(value) {
|
|
97
|
+
const findings = [];
|
|
98
|
+
walkStrings(value, (text, path) => {
|
|
99
|
+
if (PARAMETER_PATTERN.test(text)) return;
|
|
100
|
+
if (SECRET_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
101
|
+
findings.push({ path, category: "secret" });
|
|
102
|
+
} else if (PII_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
103
|
+
findings.push({ path, category: "pii" });
|
|
104
|
+
} else if (VOLATILE_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
105
|
+
findings.push({ path, category: "volatile" });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return findings;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function environmentBinding(environment) {
|
|
112
|
+
const value = canonicalValue(environment || {});
|
|
113
|
+
return Object.freeze({
|
|
114
|
+
requirements: Object.freeze(clone(value)),
|
|
115
|
+
digest: digest(value, "cc.record-replay.environment/v1"),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function assertIdentifier(value, label) {
|
|
120
|
+
const text = String(value || "").trim();
|
|
121
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]{0,127}$/u.test(text)) {
|
|
122
|
+
throw recorderError("CC_REPLAY_INVALID_ARGUMENT", `${label} is invalid`);
|
|
123
|
+
}
|
|
124
|
+
return text;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function createRecordedSkillDraft({
|
|
128
|
+
name,
|
|
129
|
+
description = "",
|
|
130
|
+
actions,
|
|
131
|
+
parameterBindings = [],
|
|
132
|
+
environment = {},
|
|
133
|
+
failureConditions = [],
|
|
134
|
+
} = {}) {
|
|
135
|
+
const safeName = assertIdentifier(name, "skill name");
|
|
136
|
+
if (!Array.isArray(actions) || actions.length === 0 || actions.length > 256) {
|
|
137
|
+
throw recorderError(
|
|
138
|
+
"CC_REPLAY_INVALID_ARGUMENT",
|
|
139
|
+
"recording requires between 1 and 256 actions",
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const names = new Set();
|
|
143
|
+
const bindings = parameterBindings.map((binding) => {
|
|
144
|
+
const parameterName = assertIdentifier(binding?.name, "parameter name");
|
|
145
|
+
if (names.has(parameterName)) {
|
|
146
|
+
throw recorderError(
|
|
147
|
+
"CC_REPLAY_INVALID_ARGUMENT",
|
|
148
|
+
`duplicate parameter: ${parameterName}`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
names.add(parameterName);
|
|
152
|
+
if (typeof binding?.value !== "string" || !binding.value) {
|
|
153
|
+
throw recorderError(
|
|
154
|
+
"CC_REPLAY_INVALID_ARGUMENT",
|
|
155
|
+
`parameter ${parameterName} requires a captured value`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
name: parameterName,
|
|
160
|
+
value: binding.value,
|
|
161
|
+
sensitive: binding.sensitive === true,
|
|
162
|
+
required: binding.required !== false,
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
const sanitizedActions = substituteCaptured(clone(actions), bindings);
|
|
166
|
+
const findings = scanRecordedValue(sanitizedActions);
|
|
167
|
+
if (findings.length) {
|
|
168
|
+
throw recorderError(
|
|
169
|
+
"CC_REPLAY_SENSITIVE_OR_VOLATILE_DATA",
|
|
170
|
+
"recording contains secret, PII, or volatile data that must be parameterized",
|
|
171
|
+
{ findings },
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const requiredCapabilities = new Set();
|
|
175
|
+
const normalizedActions = sanitizedActions.map((action, index) => {
|
|
176
|
+
if (!action || typeof action !== "object" || Array.isArray(action)) {
|
|
177
|
+
throw recorderError(
|
|
178
|
+
"CC_REPLAY_INVALID_ARGUMENT",
|
|
179
|
+
`action ${index} must be an object`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const kind = String(action.kind || "");
|
|
183
|
+
const capability = SAFE_ACTION_CAPABILITIES[kind];
|
|
184
|
+
if (!capability) {
|
|
185
|
+
throw recorderError(
|
|
186
|
+
"CC_REPLAY_UNSAFE_ACTION",
|
|
187
|
+
`recorded action kind is not in the low-risk prototype allowlist: ${kind}`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
requiredCapabilities.add(capability);
|
|
191
|
+
return {
|
|
192
|
+
id: `action-${index + 1}`,
|
|
193
|
+
...action,
|
|
194
|
+
kind,
|
|
195
|
+
requiredCapability: capability,
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
const body = {
|
|
199
|
+
schema: "chainlesschain.recorded-skill-draft/v1",
|
|
200
|
+
name: safeName,
|
|
201
|
+
description: String(description).slice(0, 2048),
|
|
202
|
+
status: "draft",
|
|
203
|
+
actions: normalizedActions,
|
|
204
|
+
parameters: bindings.map(
|
|
205
|
+
({ name: parameterName, sensitive, required }) => ({
|
|
206
|
+
name: parameterName,
|
|
207
|
+
sensitive,
|
|
208
|
+
required,
|
|
209
|
+
}),
|
|
210
|
+
),
|
|
211
|
+
capabilityManifest: [...requiredCapabilities].sort(),
|
|
212
|
+
failureConditions: failureConditions.map((value) =>
|
|
213
|
+
String(value).slice(0, 512),
|
|
214
|
+
),
|
|
215
|
+
environment: environmentBinding(environment),
|
|
216
|
+
};
|
|
217
|
+
return Object.freeze({
|
|
218
|
+
...clone(body),
|
|
219
|
+
draftDigest: digest(body, "cc.record-replay.skill-draft/v1"),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function reviewRecordedSkillDraft(
|
|
224
|
+
draft,
|
|
225
|
+
{ reviewerId, approvedCapabilities, acceptedFailureConditions = false } = {},
|
|
226
|
+
) {
|
|
227
|
+
if (draft?.status !== "draft" || !draft?.draftDigest) {
|
|
228
|
+
throw recorderError(
|
|
229
|
+
"CC_REPLAY_DRAFT_INVALID",
|
|
230
|
+
"a valid skill draft is required",
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const reviewer = assertIdentifier(reviewerId, "reviewerId");
|
|
234
|
+
const approved = [...new Set(approvedCapabilities || [])].sort();
|
|
235
|
+
if (
|
|
236
|
+
JSON.stringify(approved) !==
|
|
237
|
+
JSON.stringify([...draft.capabilityManifest].sort()) ||
|
|
238
|
+
acceptedFailureConditions !== true
|
|
239
|
+
) {
|
|
240
|
+
throw recorderError(
|
|
241
|
+
"CC_REPLAY_REVIEW_INCOMPLETE",
|
|
242
|
+
"review must approve the exact capability manifest and failure conditions",
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
const review = {
|
|
246
|
+
reviewerId: reviewer,
|
|
247
|
+
draftDigest: draft.draftDigest,
|
|
248
|
+
approvedCapabilities: approved,
|
|
249
|
+
acceptedFailureConditions: true,
|
|
250
|
+
};
|
|
251
|
+
return Object.freeze({
|
|
252
|
+
...clone(draft),
|
|
253
|
+
status: "approved",
|
|
254
|
+
review,
|
|
255
|
+
approvalDigest: digest(review, "cc.record-replay.review/v1"),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function expandParameters(value, inputs, definitions) {
|
|
260
|
+
if (typeof value === "string") {
|
|
261
|
+
const match = PARAMETER_PATTERN.exec(value);
|
|
262
|
+
if (match) {
|
|
263
|
+
const definition = definitions.get(match[1]);
|
|
264
|
+
if (!definition || !(match[1] in inputs)) {
|
|
265
|
+
throw recorderError(
|
|
266
|
+
"CC_REPLAY_PARAMETER_MISSING",
|
|
267
|
+
`required replay parameter is missing: ${match[1]}`,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
return inputs[match[1]];
|
|
271
|
+
}
|
|
272
|
+
return value.replace(
|
|
273
|
+
/\$\{parameter\.([A-Za-z][A-Za-z0-9_]*)\}/gu,
|
|
274
|
+
(_placeholder, name) => {
|
|
275
|
+
if (!definitions.has(name) || !(name in inputs)) {
|
|
276
|
+
throw recorderError(
|
|
277
|
+
"CC_REPLAY_PARAMETER_MISSING",
|
|
278
|
+
`required replay parameter is missing: ${name}`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
if (typeof inputs[name] !== "string") {
|
|
282
|
+
throw recorderError(
|
|
283
|
+
"CC_REPLAY_PARAMETER_INVALID",
|
|
284
|
+
`embedded replay parameter must be a string: ${name}`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
return inputs[name];
|
|
288
|
+
},
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
if (Array.isArray(value)) {
|
|
292
|
+
return value.map((item) => expandParameters(item, inputs, definitions));
|
|
293
|
+
}
|
|
294
|
+
if (!value || typeof value !== "object") return value;
|
|
295
|
+
return Object.fromEntries(
|
|
296
|
+
Object.entries(value).map(([key, child]) => [
|
|
297
|
+
key,
|
|
298
|
+
expandParameters(child, inputs, definitions),
|
|
299
|
+
]),
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export async function replayRecordedSkill(
|
|
304
|
+
skill,
|
|
305
|
+
{
|
|
306
|
+
inputs = {},
|
|
307
|
+
environment = {},
|
|
308
|
+
isolation = { sandboxed: true, network: "deny" },
|
|
309
|
+
executor,
|
|
310
|
+
} = {},
|
|
311
|
+
) {
|
|
312
|
+
if (skill?.status !== "approved" || !skill?.approvalDigest) {
|
|
313
|
+
throw recorderError(
|
|
314
|
+
"CC_REPLAY_NOT_APPROVED",
|
|
315
|
+
"recorded skill must be explicitly reviewed before replay",
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
if (isolation?.sandboxed !== true || isolation?.network !== "deny") {
|
|
319
|
+
throw recorderError(
|
|
320
|
+
"CC_REPLAY_ISOLATION_REQUIRED",
|
|
321
|
+
"recorded skill replay requires a sandbox with network denied",
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
if (environmentBinding(environment).digest !== skill.environment.digest) {
|
|
325
|
+
throw recorderError(
|
|
326
|
+
"CC_REPLAY_ENVIRONMENT_DRIFT",
|
|
327
|
+
"replay environment does not match the reviewed recording",
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
if (typeof executor?.execute !== "function") {
|
|
331
|
+
throw recorderError(
|
|
332
|
+
"CC_REPLAY_EXECUTOR_INVALID",
|
|
333
|
+
"a replay executor is required",
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
const executorCapabilities = new Set(executor.capabilities || []);
|
|
337
|
+
for (const capability of skill.capabilityManifest) {
|
|
338
|
+
if (!executorCapabilities.has(capability)) {
|
|
339
|
+
throw recorderError(
|
|
340
|
+
"CC_REPLAY_CAPABILITY_DENIED",
|
|
341
|
+
`replay executor did not grant capability: ${capability}`,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const definitions = new Map(
|
|
346
|
+
skill.parameters.map((parameter) => [parameter.name, parameter]),
|
|
347
|
+
);
|
|
348
|
+
for (const parameter of skill.parameters) {
|
|
349
|
+
if (parameter.required && !(parameter.name in inputs)) {
|
|
350
|
+
throw recorderError(
|
|
351
|
+
"CC_REPLAY_PARAMETER_MISSING",
|
|
352
|
+
`required replay parameter is missing: ${parameter.name}`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const receipts = [];
|
|
357
|
+
for (const action of skill.actions) {
|
|
358
|
+
const expanded = expandParameters(action, inputs, definitions);
|
|
359
|
+
const result = await executor.execute(expanded, {
|
|
360
|
+
isolation: clone(isolation),
|
|
361
|
+
capability: action.requiredCapability,
|
|
362
|
+
});
|
|
363
|
+
if (!result || result.ok !== true || !result.evidence) {
|
|
364
|
+
throw recorderError(
|
|
365
|
+
"CC_REPLAY_ACTION_FAILED",
|
|
366
|
+
`replay action failed without terminal evidence: ${action.id}`,
|
|
367
|
+
{ actionId: action.id },
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
receipts.push({
|
|
371
|
+
actionId: action.id,
|
|
372
|
+
evidenceDigest: digest(result.evidence, "cc.record-replay.evidence/v1"),
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
const report = {
|
|
376
|
+
schema: "chainlesschain.recorded-skill-replay/v1",
|
|
377
|
+
skillDigest: skill.draftDigest,
|
|
378
|
+
environmentDigest: skill.environment.digest,
|
|
379
|
+
status: "succeeded",
|
|
380
|
+
receipts,
|
|
381
|
+
};
|
|
382
|
+
return Object.freeze({
|
|
383
|
+
...report,
|
|
384
|
+
replayDigest: digest(report, "cc.record-replay.report/v1"),
|
|
385
|
+
});
|
|
386
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
function webhookError(code, message, statusCode, details = {}) {
|
|
4
|
+
const error = new Error(message);
|
|
5
|
+
error.name = "WebhookSecurityError";
|
|
6
|
+
error.code = code;
|
|
7
|
+
error.statusCode = statusCode;
|
|
8
|
+
Object.assign(error, details);
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function header(headers, name) {
|
|
13
|
+
const value = headers?.[name] ?? headers?.[name.toLowerCase()];
|
|
14
|
+
return Array.isArray(value) ? value[0] : value == null ? "" : String(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function signWebhookBody(secret, timestamp, body) {
|
|
18
|
+
return `sha256=${createHmac("sha256", secret)
|
|
19
|
+
.update(String(timestamp))
|
|
20
|
+
.update(".")
|
|
21
|
+
.update(body)
|
|
22
|
+
.digest("hex")}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class WebhookSecurityGate {
|
|
26
|
+
constructor({
|
|
27
|
+
secret,
|
|
28
|
+
now = Date.now,
|
|
29
|
+
maxClockSkewMs = 5 * 60_000,
|
|
30
|
+
maxRequestsPerMinute = 30,
|
|
31
|
+
maxReplayEntries = 10_000,
|
|
32
|
+
} = {}) {
|
|
33
|
+
if (typeof secret !== "string" || secret.length < 16) {
|
|
34
|
+
throw webhookError(
|
|
35
|
+
"CC_WEBHOOK_SECRET_REQUIRED",
|
|
36
|
+
"webhook mode requires an authentication secret of at least 16 characters",
|
|
37
|
+
503,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
this.secret = secret;
|
|
41
|
+
this.now = now;
|
|
42
|
+
this.maxClockSkewMs = Math.max(1_000, Number(maxClockSkewMs) || 300_000);
|
|
43
|
+
this.maxRequestsPerMinute = Math.max(1, Number(maxRequestsPerMinute) || 30);
|
|
44
|
+
this.maxReplayEntries = Math.max(100, Number(maxReplayEntries) || 10_000);
|
|
45
|
+
this.replays = new Map();
|
|
46
|
+
this.rates = new Map();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
verify({ channel, headers, body, remoteAddress = "unknown" }) {
|
|
50
|
+
const now = this.now();
|
|
51
|
+
const window = Math.floor(now / 60_000);
|
|
52
|
+
const rateKey = `${channel}\0${remoteAddress}\0${window}`;
|
|
53
|
+
const requests = (this.rates.get(rateKey) || 0) + 1;
|
|
54
|
+
this.rates.set(rateKey, requests);
|
|
55
|
+
for (const key of this.rates.keys()) {
|
|
56
|
+
if (!key.endsWith(`\0${window}`)) this.rates.delete(key);
|
|
57
|
+
}
|
|
58
|
+
if (requests > this.maxRequestsPerMinute) {
|
|
59
|
+
throw webhookError(
|
|
60
|
+
"CC_WEBHOOK_RATE_LIMITED",
|
|
61
|
+
"webhook rate limit exceeded",
|
|
62
|
+
429,
|
|
63
|
+
{ retryAfterSeconds: 60 - Math.floor((now % 60_000) / 1000) },
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const timestampText = header(headers, "x-cc-webhook-timestamp");
|
|
67
|
+
const deliveryId = header(headers, "x-cc-webhook-delivery");
|
|
68
|
+
const supplied = header(headers, "x-cc-webhook-signature");
|
|
69
|
+
const timestamp = Number(timestampText);
|
|
70
|
+
if (
|
|
71
|
+
!Number.isFinite(timestamp) ||
|
|
72
|
+
Math.abs(now - timestamp) > this.maxClockSkewMs ||
|
|
73
|
+
!deliveryId ||
|
|
74
|
+
deliveryId.length > 256
|
|
75
|
+
) {
|
|
76
|
+
throw webhookError(
|
|
77
|
+
"CC_WEBHOOK_AUTH_INVALID",
|
|
78
|
+
"webhook timestamp or delivery identity is invalid",
|
|
79
|
+
401,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const expected = signWebhookBody(this.secret, timestampText, body);
|
|
83
|
+
const expectedBytes = Buffer.from(expected, "utf8");
|
|
84
|
+
const suppliedBytes = Buffer.from(supplied, "utf8");
|
|
85
|
+
if (
|
|
86
|
+
expectedBytes.length !== suppliedBytes.length ||
|
|
87
|
+
!timingSafeEqual(expectedBytes, suppliedBytes)
|
|
88
|
+
) {
|
|
89
|
+
throw webhookError(
|
|
90
|
+
"CC_WEBHOOK_AUTH_INVALID",
|
|
91
|
+
"webhook signature is invalid",
|
|
92
|
+
401,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
for (const [key, expiresAt] of this.replays) {
|
|
96
|
+
if (expiresAt <= now) this.replays.delete(key);
|
|
97
|
+
}
|
|
98
|
+
const replayKey = `${channel}\0${deliveryId}`;
|
|
99
|
+
if (this.replays.has(replayKey)) {
|
|
100
|
+
throw webhookError(
|
|
101
|
+
"CC_WEBHOOK_REPLAYED",
|
|
102
|
+
"webhook delivery was already processed",
|
|
103
|
+
409,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (this.replays.size >= this.maxReplayEntries) {
|
|
107
|
+
throw webhookError(
|
|
108
|
+
"CC_WEBHOOK_REPLAY_CACHE_FULL",
|
|
109
|
+
"webhook replay cache is full",
|
|
110
|
+
503,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
this.replays.set(replayKey, now + this.maxClockSkewMs);
|
|
114
|
+
return Object.freeze({
|
|
115
|
+
deliveryId,
|
|
116
|
+
dataPolicy: Object.freeze({
|
|
117
|
+
origin: `webhook:${channel}:${deliveryId}`,
|
|
118
|
+
trust: "authenticated_user",
|
|
119
|
+
sensitivity: "internal",
|
|
120
|
+
allowedSinks: Object.freeze(["agent:*", "artifact:local"]),
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function readBoundedWebhookBody(request, maxBytes = 256 * 1024) {
|
|
127
|
+
const limit = Math.max(1, Number(maxBytes) || 256 * 1024);
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const chunks = [];
|
|
130
|
+
let size = 0;
|
|
131
|
+
let settled = false;
|
|
132
|
+
request.on("data", (chunk) => {
|
|
133
|
+
if (settled) return;
|
|
134
|
+
size += chunk.length;
|
|
135
|
+
if (size > limit) {
|
|
136
|
+
settled = true;
|
|
137
|
+
reject(
|
|
138
|
+
webhookError(
|
|
139
|
+
"CC_WEBHOOK_BODY_TOO_LARGE",
|
|
140
|
+
"webhook body exceeds the configured limit",
|
|
141
|
+
413,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
chunks.push(chunk);
|
|
147
|
+
});
|
|
148
|
+
request.on("end", () => {
|
|
149
|
+
if (settled) return;
|
|
150
|
+
settled = true;
|
|
151
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
152
|
+
});
|
|
153
|
+
request.on("error", (error) => {
|
|
154
|
+
if (settled) return;
|
|
155
|
+
settled = true;
|
|
156
|
+
reject(error);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -9686,14 +9686,15 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
9686
9686
|
);
|
|
9687
9687
|
}
|
|
9688
9688
|
|
|
9689
|
-
// Generate follow-up suggestions from the settled assistant turn.
|
|
9690
|
-
//
|
|
9691
|
-
//
|
|
9689
|
+
// Generate follow-up suggestions from the settled assistant turn. Wait
|
|
9690
|
+
// for their bounded local generation before reopening readline: writing
|
|
9691
|
+
// and refreshing suggestions after rl.prompt() breaks Windows IME
|
|
9692
|
+
// composition and can make subsequent Chinese input unusable.
|
|
9692
9693
|
const suggestionRun = _promptInteractions.scheduleSuggestions({
|
|
9693
9694
|
messages: messages.slice(),
|
|
9694
9695
|
lastAssistantText: effectiveResponse || "",
|
|
9695
9696
|
});
|
|
9696
|
-
|
|
9697
|
+
await suggestionRun.promise;
|
|
9697
9698
|
|
|
9698
9699
|
// Auto-save session
|
|
9699
9700
|
if (sessionId) {
|
|
@@ -204,7 +204,11 @@ export class PromptInteractionController {
|
|
|
204
204
|
|
|
205
205
|
_showSuggestionUpdate(suggestions) {
|
|
206
206
|
if (this.screenReader || !suggestions.length) return;
|
|
207
|
-
|
|
207
|
+
// Suggestion generation is asynchronous. Refreshing an already-visible
|
|
208
|
+
// readline prompt here interrupts Windows IME composition and can leave
|
|
209
|
+
// Chinese input unusable. The REPL awaits suggestion settlement before it
|
|
210
|
+
// reopens the prompt, so this output must never repaint the active line.
|
|
211
|
+
this._print(`\n${renderPromptSuggestions(suggestions)}`);
|
|
208
212
|
}
|
|
209
213
|
|
|
210
214
|
_suggestionContext(overrides = {}) {
|
|
@@ -285,6 +289,12 @@ export class PromptInteractionController {
|
|
|
285
289
|
context: this._suggestionContext(),
|
|
286
290
|
});
|
|
287
291
|
this._print(result.message, { error: !result.ok });
|
|
292
|
+
// Keep generated output ahead of the next rl.prompt(). In particular,
|
|
293
|
+
// do not let a late suggestion callback redraw a prompt while an IME is
|
|
294
|
+
// composing text.
|
|
295
|
+
if (result.action === "refresh" && result.promise) {
|
|
296
|
+
await result.promise;
|
|
297
|
+
}
|
|
288
298
|
return { handled: true, ...result };
|
|
289
299
|
}
|
|
290
300
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{P as c,J as p,b as s}from"./vendor-Bn1JzzAn.js";import{r as a}from"./markdown-Yo_c6Krv.js";import{_ as d}from"./index-DJyPeBBk.js";const _={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(t,{expose:o}){o();const e=t,r=s(()=>a(e.content||"")),n={props:e,rendered:r,computed:s,get renderMarkdown(){return a}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},i=["innerHTML"];function u(t,o,e,r,n,m){return c(),p("div",{class:"markdown-content",innerHTML:r.rendered},null,8,i)}const w=d(_,[["render",u],["__scopeId","data-v-0b0b9f63"],["__file","/tmp/cc-web-panel-guJHFi/repo/packages/web-panel/src/components/MarkdownRenderer.vue"]]);export{w as M};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Q as r}from"./index-DJyPeBBk.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-BPLlhn52.js";import{a0 as t}from"./index-DJyPeBBk.js";import"./vendor-Bn1JzzAn.js";import"./index-NUR0If7O.js";import"./icons-DG5UD-6K.js";const s=t(o);export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-C1VNmjmX.js";import{a0 as t}from"./index-DJyPeBBk.js";import"./vendor-Bn1JzzAn.js";import"./responsiveObserve-bqLhxHhn.js";import"./useFlexGapSupport-CKLb2KA6.js";import"./styleChecker-BXg4qGX_.js";import"./index-NUR0If7O.js";import"./icons-DG5UD-6K.js";const l=t(o);export{l as default};
|