chainlesschain 0.162.182 → 0.162.184
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-DzZ5_xoj.js → AIOps-DzAl5fGx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DeLXddIg.js → ActionButton-DAHtMGeC.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-rvDCmet1.js → Analytics-BHQaexv5.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Yt6QVDnp.js → AppLayout-Phz_pD0n.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BS112K5L.js → Artifacts-DHt47kCA.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-0wJuQrNu.js → Audit--Y_8FULl.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-B90PMgbn.js → BackgroundAgents-N1zchH7D.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-TkgMglQQ.js → Backup-B_BoyN30.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CQVS9p1l.js → BaseInput-Gl4uQHcT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-YTjQHoC7.js → Chat-Cg-eIyAZ.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BzeUi3JH.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-5bwaOabq.js → Checkbox-D0MGR2wA.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BFmNQ_Xe.js → Codegen-BdObJEFn.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BT_u4Dzp.js → Col--ghxXT3z.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CJP52u5b.js → Community-BUFeXOqz.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BpzhJE9i.js → Compact-DhQO2_Mr.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Cg7rfslp.js → Compliance-3HoTqKYd.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-JisxL6Yy.js → Cowork-B3zmO4VW.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Bu7Ug_MC.js → Cron-CJDrZOcc.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CvuqoLdj.js → Crosschain-SMl15obd.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C2u9G8Pu.js → DID-CgTrTWrl.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BFt5Yv3d.js → Dashboard-dXFKaKol.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DIaT9Wxq.js → Dropdown-qQHEhCvI.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-D_A601Y4.js → EmailListRenderer-C_ej0MWH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard--IyQ8I8w.js → FamilyGuardDashboard-D6ajoE7I.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BihWHxuY.js → Federation-Cio2y49h.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BB8dOXc_.js → FormItemContext-ClJz1cYp.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DQYhj1HH.js → GenericCardRenderer-Dr_8Maca.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B-2QZxGf.js → Git-CevLwp5u.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CusSb-nG.js → Governance-CW9YyQUY.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BAjmvPPL.js → Inference-CQqeAyER.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DoNYWKYq.js → KnowledgeGraph-cuGVxHrw.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B8fKWD-n.js → Logs-DIuHri5d.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BlJm1J7E.js → MarkdownRenderer-R91Qw5JA.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CyOscbSL.js → Marketplace-CY1VhFGx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Ex6Om5da.js → McpTools-BBAbi1vt.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CDcD8l8r.js → Memory-BWYGHxJA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-xfBqoFDg.js → MobileBridge-CPIFkW7A.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BwObMMA2.js → MobileProjects-DQyWxCho.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CIWd36OV.js → Mtc-Bo3GnQbx.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CPX0ouuA.js → MtcAudit-C8-c4rSW.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BDJsIUuW.js → Multisig-ChqMTtoq.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DEkbuD3N.js → NLProgramming-C48TyhvI.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DJpHRhH1.js → Notes-zogUFWxp.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C1UZ-Qd5.js → NotificationSettings-v-K9XpSB.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-P94JGGNz.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Bbhj0fac.js → Organization-Boi1dQfR.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-1H04x3kx.js → Overflow-DM5YWwgA.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CDpPe3et.js → P2P-C57LKpKK.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-MUX0Bpvw.js → PdhVaultBrowser-BFkPqu6Q.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-A07-0Ci1.js → Permissions-D6fB9YSp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DhhDWxAZ.js → PersonalDataHub-Bp7EefEo.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-CyfbJfe-.js → Pipeline-BVln3hZf.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CNFps3ED.js → Privacy-Bf8P3nF6.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit--T-u3Dr5.js → ProjectInit-DM6wA2E2.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DJmrK2fC.js → ProjectSettings-CGbc5Iho.js} +2 -2
- package/src/assets/web-panel/assets/Projects-D0p9EOxm.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DLzzbOZd.js → Providers-B2kJcxS6.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CexOomKS.js → QrScannerModal-Cxu7dXYy.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-QklGi19_.js → QuickAsk-DTlrTPms.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bb9kwSw8.js → Recommend-Cm3X-cCj.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DZuVNNN5.js → RemoteSession-DNb2kjvt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Dr5cLP0N.js → Reputation-CZUFFjc1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-oCQHYv5t.js → Row-DAPgloxA.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-IFDEykIR.js → RssFeed-dsx9S793.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CspVIxDc.js → Search-DnnC8kz-.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bm66o_DH.js → Security-VuZknRMK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DvanNqXl.js → Services-B3XNX8Vx.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CHjEe9_O.js → Skeleton-Dl1nVtCj.js} +1 -1
- package/src/assets/web-panel/assets/Skills-CY09CZ_W.js +1 -0
- package/src/assets/web-panel/assets/{Sla-DxZm1491.js → Sla-HzU56n1z.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DWxEEclC.js → SpeechSettings-CRle7Jl2.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-FIvOFw5p.js → SyncSettings-DWadz7Sl.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CNVTDGg8.js +1 -0
- package/src/assets/web-panel/assets/{Templates-CaNjzV_t.js → Templates-BBAgvrlM.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DjlP6TmH.js → Tenant-BsbbvGN8.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-uscpZI4q.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DoZ8y7y8.js → TimelineRenderer-mTyjNE6r.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-390cg2TC.js → Tokens-Bz97oBgs.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CLrtCj5_.js → Trigger-BTRKC140.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DpESfSPn.js → Trust-B4A_KuyX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CN6279O0.js → UkeySign-DES9TmLU.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DPtAUlSe.js → VideoEditing-ClXs7Qxp.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-nKOMV_1n.js → Wallet-IzZqFz-7.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-HuXlSOc4.js → WebAuthn-BtOP04g_.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CUfFjARi.js → WorkflowEditor-_0cqnopY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-6Eq0PcZJ.js → chat-ax7193uU.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BP_Sf6Iy.js → colors-Bu4WGJah.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BufMKIh5.js → compact-item-BX1dlTW0.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BBMXxWSW.js → createContext-CktA_Dj7.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-x877iKKS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-fUK_tRO2.js → hasIn-D5wd817l.js} +1 -1
- package/src/assets/web-panel/assets/{index-t8N1tSeX.js → index-5PYYkr8S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLpIs_P_.js → index-A4uBPQCz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVsqvI4M.js → index-BAtBNfkr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bkg4ZePE.js → index-BLLsUNDc.js} +1 -1
- package/src/assets/web-panel/assets/{index-cpEli44X.js → index-BQtoRyTO.js} +1 -1
- package/src/assets/web-panel/assets/{index-wKTLbKyc.js → index-BRfXoRuh.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7Etk0Te.js → index-Bad2CYeH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwSf5pnf.js → index-BcGdL3sG.js} +1 -1
- package/src/assets/web-panel/assets/{index-3FuwBewR.js → index-C3HmzCLt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHy6yNiF.js → index-C8DkWyNr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgiECHu2.js → index-C8tLR2TG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C44atv4k.js → index-CP8ELJBc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW_G-MXw.js → index-CUForzsG.js} +1 -1
- package/src/assets/web-panel/assets/{index-pum7HYBA.js → index-CYRE0NJA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWKoBU8R.js → index-CeVZaJSC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4_MuGkd.js → index-CfzxR61U.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dyngbd29.js → index-Ci3y1ZAv.js} +19 -19
- package/src/assets/web-panel/assets/{index-fzaMtSJ8.js → index-CjEJjl5C.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp8vhyZy.js → index-Cv7bVWJ5.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPdUNk1i.js → index-D-o4Rwjk.js} +1 -1
- package/src/assets/web-panel/assets/index-D7pfPouB.js +1 -0
- package/src/assets/web-panel/assets/{index-CeASi4fr.js → index-D9op8poE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DASluSqY.js → index-DF1TysIF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DocdRcbd.js → index-DYo9S5OT.js} +1 -1
- package/src/assets/web-panel/assets/{index-2A5ph8b2.js → index-D_cycOET.js} +1 -1
- package/src/assets/web-panel/assets/{index-wV6iGdpY.js → index-Db3CpWTr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMLHv389.js → index-DkD1K-fF.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9WYSn4m.js → index-DmPJ6T6F.js} +1 -1
- package/src/assets/web-panel/assets/{index-uCbEN7cY.js → index-DmVUeWUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkMXwnR.js → index-Dzdr0zDf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ6Yt17L.js → index-PBLzwYnu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE2DdTP2.js → index-bFCaM7Eq.js} +1 -1
- package/src/assets/web-panel/assets/index-e4i-VLBd.js +1 -0
- package/src/assets/web-panel/assets/{index-GwdRUZ-x.js → index-h3KJZr95.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2vS66eI.js → index-iHcPtQ2e.js} +1 -1
- package/src/assets/web-panel/assets/{index-6GmBa4Kg.js → index-jzlzm4VK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9vU25ij.js → index-o14NNnxw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGjmILDm.js → index-tYPSfGbd.js} +1 -1
- package/src/assets/web-panel/assets/{index-LvCBfTLo.js → index-ytp2H5Zx.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-V5Fo95FM.js → initDefaultProps-D2Iut83B.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BYWU0hUT.js → motion-BuaJVdK9.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cr1M-J2h.js → move-CaEuM92y.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BysQKi2N.js → mtc-parser-wuKNBwys.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D1zHU8GC.js → omit-7a3eklaq.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CUArxtfi.js → pickAttrs-Dn4z7KvJ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ChoYEys0.js → placementArrow-DVn_qT4-.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BQRs3Mo7.js → responsiveObserve-Dodz1OMQ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B8zbsCkg.js → slide-CxoGskbp.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C2U8Gs6h.js → statusUtils-DBh_epQH.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Dd8MgL_V.js → styleChecker-RXQ4gG5P.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-hknqY5NH.js → useFlexGapSupport-1Wxm0HEG.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CLTAmcfw.js → useFs-CI_ySNxJ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-ByegHbiB.js → usePersonalDataHub-C6973rZP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DqlAy5DP.js → vnode-CalynwKr.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DiXiztQn.js → zoom-CM1cd-Q0.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +74 -1
- package/src/commands/agent.js +9 -0
- package/src/commands/background-session.js +60 -1
- package/src/commands/batch.js +160 -5
- package/src/commands/plugin.js +318 -43
- package/src/commands/session.js +44 -1
- package/src/commands/team.js +212 -6
- package/src/data/changelog.json +26 -0
- package/src/harness/jsonl-session-store.js +59 -6
- package/src/harness/mcp-client.js +65 -43
- package/src/lib/agent-batch.js +4 -1
- package/src/lib/agent-team/team-runner.js +19 -1
- package/src/lib/agent-team/team-worktree.js +3 -0
- package/src/lib/async-hook-supervisor.cjs +82 -10
- package/src/lib/async-hook-supervisor.js +50 -4
- package/src/lib/background-agent-supervisor.js +49 -0
- package/src/lib/collaboration-run-store.js +362 -0
- package/src/lib/hook-runner.cjs +98 -17
- package/src/lib/hook-runner.js +77 -6
- package/src/lib/hook-shell-command.cjs +148 -0
- package/src/lib/hooks-v2-runtime.js +188 -77
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +18 -0
- package/src/lib/lsp/lsp-client.js +12 -1
- package/src/lib/plugin-monitor-supervisor.js +53 -16
- package/src/lib/plugin-runtime/bin.js +1 -1
- package/src/lib/plugin-runtime/install.js +465 -54
- package/src/lib/plugin-runtime/mcp.js +21 -2
- package/src/lib/plugin-runtime/monitors.js +19 -3
- package/src/lib/plugin-runtime/sandbox-policy.js +99 -0
- package/src/lib/plugin-runtime/scopes.js +13 -2
- package/src/lib/plugin-usage-attribution.js +44 -0
- package/src/lib/process-execution-broker/index.js +705 -13
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1347 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +1260 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +1831 -157
- package/src/lib/session-usage.js +278 -1
- package/src/lib/stream-retry.js +29 -0
- package/src/repl/agent-repl.js +38 -9
- package/src/runtime/agent-core.js +32 -4
- package/src/runtime/headless-runner.js +46 -1
- package/src/runtime/headless-stream.js +54 -3
- package/src/runtime/mcp-config.js +15 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-GlJtqLjT.js +0 -1
- package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +0 -1
- package/src/assets/web-panel/assets/Skills-Cb8jWjMX.js +0 -1
- package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +0 -1
- package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +0 -3
- package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +0 -1
- package/src/assets/web-panel/assets/index-DOZTSoS7.js +0 -1
- package/src/assets/web-panel/assets/index-DhpvjpqI.js +0 -1
package/src/commands/team.js
CHANGED
|
@@ -24,14 +24,48 @@ import { TeamWorktreeCoordinator } from "../lib/agent-team/team-worktree.js";
|
|
|
24
24
|
import { TeamBudget } from "../lib/agent-team/team-budget.js";
|
|
25
25
|
import { TeamMailbox } from "../lib/agent-team/team-mailbox.js";
|
|
26
26
|
import { executionBroker } from "../lib/process-execution-broker/index.js";
|
|
27
|
+
import {
|
|
28
|
+
createCollaborationRun,
|
|
29
|
+
createCollaborationRunId,
|
|
30
|
+
createCollaborationSessionId,
|
|
31
|
+
finalizeCollaborationRun,
|
|
32
|
+
readCollaborationRun,
|
|
33
|
+
updateCollaborationUnit,
|
|
34
|
+
} from "../lib/collaboration-run-store.js";
|
|
35
|
+
import { loadSideEffectLedger } from "../lib/side-effect-ledger-store.js";
|
|
27
36
|
|
|
28
37
|
export const _deps = {
|
|
29
38
|
spawn: (...args) => executionBroker.spawn(...args),
|
|
39
|
+
collaborationStore: {
|
|
40
|
+
createRun: createCollaborationRun,
|
|
41
|
+
createRunId: createCollaborationRunId,
|
|
42
|
+
createSessionId: createCollaborationSessionId,
|
|
43
|
+
readRun: readCollaborationRun,
|
|
44
|
+
updateUnit: updateCollaborationUnit,
|
|
45
|
+
finalizeRun: finalizeCollaborationRun,
|
|
46
|
+
loadSideEffects: (sessionId) =>
|
|
47
|
+
loadSideEffectLedger(sessionId, { failIfUnavailable: false }),
|
|
48
|
+
},
|
|
30
49
|
};
|
|
31
50
|
|
|
32
51
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
33
52
|
const BIN = path.resolve(__dirname, "..", "..", "bin", "chainlesschain.js");
|
|
34
53
|
|
|
54
|
+
function normalizePermissionMode(value) {
|
|
55
|
+
const mode = String(value || "acceptEdits");
|
|
56
|
+
return new Set([
|
|
57
|
+
"manual",
|
|
58
|
+
"auto",
|
|
59
|
+
"dontAsk",
|
|
60
|
+
"default",
|
|
61
|
+
"plan",
|
|
62
|
+
"acceptEdits",
|
|
63
|
+
"bypassPermissions",
|
|
64
|
+
]).has(mode)
|
|
65
|
+
? mode
|
|
66
|
+
: "acceptEdits";
|
|
67
|
+
}
|
|
68
|
+
|
|
35
69
|
/** Load + validate a task-graph file into a registry (throws on bad input). */
|
|
36
70
|
export function loadRegistry(file, { ttlMs } = {}) {
|
|
37
71
|
const abs = path.resolve(process.cwd(), file);
|
|
@@ -136,6 +170,13 @@ export function spawnAgent(prompt, cwd, opts = {}) {
|
|
|
136
170
|
"text",
|
|
137
171
|
];
|
|
138
172
|
if (opts.model) args.push("--model", opts.model);
|
|
173
|
+
if (opts.sessionId) args.push("--session", opts.sessionId);
|
|
174
|
+
if (Number(opts.maxTurns) > 0) {
|
|
175
|
+
args.push("--max-turns", String(opts.maxTurns));
|
|
176
|
+
}
|
|
177
|
+
if (Number(opts.maxBudgetUsd) > 0) {
|
|
178
|
+
args.push("--max-budget-usd", String(opts.maxBudgetUsd));
|
|
179
|
+
}
|
|
139
180
|
const child = _deps.spawn(process.execPath, args, {
|
|
140
181
|
cwd,
|
|
141
182
|
env: { ...process.env, CLAUDECODE: "1" },
|
|
@@ -162,12 +203,15 @@ export function spawnAgent(prompt, cwd, opts = {}) {
|
|
|
162
203
|
|
|
163
204
|
/** Real executor: hand a task's `prompt` to a headless `cc agent -p` in cwd. */
|
|
164
205
|
function makeAgentRunTask(opts = {}) {
|
|
165
|
-
return function runTask({ task }) {
|
|
206
|
+
return function runTask({ key, task }) {
|
|
166
207
|
const prompt = task.metadata?.prompt || task?.prompt;
|
|
167
208
|
if (!prompt) {
|
|
168
209
|
throw new Error(`task "${task.key}" has no \`prompt\` to --agent`);
|
|
169
210
|
}
|
|
170
|
-
return spawnAgent(prompt, process.cwd(),
|
|
211
|
+
return spawnAgent(prompt, process.cwd(), {
|
|
212
|
+
...opts,
|
|
213
|
+
sessionId: opts.sessionIdForTask?.(key) || null,
|
|
214
|
+
});
|
|
171
215
|
};
|
|
172
216
|
}
|
|
173
217
|
|
|
@@ -220,6 +264,13 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
220
264
|
"Hand each task's `prompt` to a headless cc agent (real)",
|
|
221
265
|
)
|
|
222
266
|
.option("--model <model>", "Model for --agent runs")
|
|
267
|
+
.option(
|
|
268
|
+
"--permission-mode <mode>",
|
|
269
|
+
"Permission mode for each --agent task",
|
|
270
|
+
"acceptEdits",
|
|
271
|
+
)
|
|
272
|
+
.option("--agent-max-turns <n>", "Per-agent task turn cap")
|
|
273
|
+
.option("--agent-max-budget-usd <amount>", "Per-agent task cost cap")
|
|
223
274
|
.option(
|
|
224
275
|
"--worktree",
|
|
225
276
|
"Run each task's `command` in its own git worktree (parallel isolation)",
|
|
@@ -272,6 +323,7 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
272
323
|
: null,
|
|
273
324
|
});
|
|
274
325
|
let priorMembers = [];
|
|
326
|
+
let priorCollaborationRunId = null;
|
|
275
327
|
try {
|
|
276
328
|
// Resume from a prior (possibly crashed) run's state: completed tasks
|
|
277
329
|
// stay COMPLETED, and any lease left dangling by a crash is reclaimed so
|
|
@@ -297,6 +349,7 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
297
349
|
},
|
|
298
350
|
});
|
|
299
351
|
priorMembers = Array.isArray(snap.members) ? snap.members : [];
|
|
352
|
+
priorCollaborationRunId = snap.collaborationRunId || null;
|
|
300
353
|
}
|
|
301
354
|
// A teammate whose lease is still dangling here crashed last run — its
|
|
302
355
|
// task is about to be reclaimed, so report it LOST before the sweep.
|
|
@@ -331,6 +384,86 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
331
384
|
return;
|
|
332
385
|
}
|
|
333
386
|
|
|
387
|
+
const permissionMode = normalizePermissionMode(options.permissionMode);
|
|
388
|
+
let priorCollaborationRun = null;
|
|
389
|
+
if (priorCollaborationRunId) {
|
|
390
|
+
try {
|
|
391
|
+
priorCollaborationRun = _deps.collaborationStore.readRun(
|
|
392
|
+
priorCollaborationRunId,
|
|
393
|
+
);
|
|
394
|
+
} catch {
|
|
395
|
+
// A malformed/foreign v3 pointer must not block registry recovery.
|
|
396
|
+
priorCollaborationRun = null;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const priorUnits = new Map(
|
|
400
|
+
(priorCollaborationRun?.units || []).map((unit) => [unit.key, unit]),
|
|
401
|
+
);
|
|
402
|
+
let collaborationRun;
|
|
403
|
+
try {
|
|
404
|
+
const runId = _deps.collaborationStore.createRunId("team");
|
|
405
|
+
collaborationRun = _deps.collaborationStore.createRun({
|
|
406
|
+
id: runId,
|
|
407
|
+
kind: "team",
|
|
408
|
+
repoRoot: process.cwd(),
|
|
409
|
+
permissionMode: options.agent ? permissionMode : "default",
|
|
410
|
+
resourceBudget: {
|
|
411
|
+
maxTurns: options.agentMaxTurns,
|
|
412
|
+
maxCostUsd: options.agentMaxBudgetUsd,
|
|
413
|
+
maxTasks: options.maxTasks,
|
|
414
|
+
maxTokens: options.maxTokens,
|
|
415
|
+
maxWallMs: options.maxWall
|
|
416
|
+
? Math.max(1, Number(options.maxWall)) * 1000
|
|
417
|
+
: null,
|
|
418
|
+
},
|
|
419
|
+
units: reg.list().map((task) => ({
|
|
420
|
+
key: task.key,
|
|
421
|
+
branch: options.worktree ? `team/${task.key}` : null,
|
|
422
|
+
sessionId: options.agent
|
|
423
|
+
? priorUnits.get(task.key)?.sessionId ||
|
|
424
|
+
_deps.collaborationStore.createSessionId(runId, task.key)
|
|
425
|
+
: null,
|
|
426
|
+
status:
|
|
427
|
+
String(task.status || "").toLowerCase() === "completed"
|
|
428
|
+
? "completed"
|
|
429
|
+
: "pending",
|
|
430
|
+
})),
|
|
431
|
+
});
|
|
432
|
+
} catch (err) {
|
|
433
|
+
(log.error || console.error)(
|
|
434
|
+
`Failed to persist team governance: ${err.message}`,
|
|
435
|
+
);
|
|
436
|
+
process.exitCode = 1;
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const collaborationUnits = new Map(
|
|
440
|
+
collaborationRun.units.map((unit) => [unit.key, unit]),
|
|
441
|
+
);
|
|
442
|
+
const settleGovernance = (key, status, extra = {}) => {
|
|
443
|
+
const unit = collaborationUnits.get(key);
|
|
444
|
+
let sideEffects = null;
|
|
445
|
+
if (unit?.sessionId) {
|
|
446
|
+
try {
|
|
447
|
+
sideEffects = _deps.collaborationStore.loadSideEffects(
|
|
448
|
+
unit.sessionId,
|
|
449
|
+
);
|
|
450
|
+
} catch {
|
|
451
|
+
/* side-effect summary is additive */
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const updated = _deps.collaborationStore.updateUnit(
|
|
455
|
+
collaborationRun.id,
|
|
456
|
+
key,
|
|
457
|
+
{
|
|
458
|
+
status,
|
|
459
|
+
...extra,
|
|
460
|
+
...(sideEffects ? { sideEffects } : {}),
|
|
461
|
+
},
|
|
462
|
+
);
|
|
463
|
+
const next = updated.units.find((candidate) => candidate.key === key);
|
|
464
|
+
if (next) collaborationUnits.set(key, next);
|
|
465
|
+
};
|
|
466
|
+
|
|
334
467
|
// Persist a snapshot after each task settles so a crash mid-run is
|
|
335
468
|
// resumable (persist-after-run alone would lose everything on a crash).
|
|
336
469
|
// v2 bundles registry + mailbox + budget + member lifecycle so a resume
|
|
@@ -347,11 +480,12 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
347
480
|
tmp,
|
|
348
481
|
JSON.stringify(
|
|
349
482
|
{
|
|
350
|
-
version:
|
|
483
|
+
version: 3,
|
|
351
484
|
registry: reg.snapshot(),
|
|
352
485
|
mailbox: mailbox.snapshot(),
|
|
353
486
|
budget: budget.snapshot(),
|
|
354
487
|
members: runnerRef ? runnerRef.members() : priorMembers,
|
|
488
|
+
collaborationRunId: collaborationRun.id,
|
|
355
489
|
},
|
|
356
490
|
null,
|
|
357
491
|
2,
|
|
@@ -379,8 +513,20 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
379
513
|
coord = new TeamWorktreeCoordinator(process.cwd(), {
|
|
380
514
|
sparsePaths: splitList(options.sparsePaths),
|
|
381
515
|
symlinkDirectories: splitList(options.symlinkDirs),
|
|
516
|
+
onWorktree: ({ key, branch, path: worktreePath }) => {
|
|
517
|
+
settleGovernance(key, "running", {
|
|
518
|
+
branch,
|
|
519
|
+
worktreePath,
|
|
520
|
+
startedAt: Date.now(),
|
|
521
|
+
});
|
|
522
|
+
},
|
|
382
523
|
});
|
|
383
524
|
if (!coord.isGitRepo()) {
|
|
525
|
+
try {
|
|
526
|
+
_deps.collaborationStore.finalizeRun(collaborationRun.id, "failed");
|
|
527
|
+
} catch {
|
|
528
|
+
/* the original validation error remains primary */
|
|
529
|
+
}
|
|
384
530
|
(log.error || console.error)(
|
|
385
531
|
"--worktree requires a git repository (run inside one)",
|
|
386
532
|
);
|
|
@@ -397,7 +543,13 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
397
543
|
if (!prompt) {
|
|
398
544
|
throw new Error(`task "${key}" has no \`prompt\` to --agent`);
|
|
399
545
|
}
|
|
400
|
-
await spawnAgent(prompt, cwd, {
|
|
546
|
+
await spawnAgent(prompt, cwd, {
|
|
547
|
+
model: options.model,
|
|
548
|
+
permissionMode,
|
|
549
|
+
maxTurns: options.agentMaxTurns,
|
|
550
|
+
maxBudgetUsd: options.agentMaxBudgetUsd,
|
|
551
|
+
sessionId: collaborationUnits.get(key)?.sessionId,
|
|
552
|
+
});
|
|
401
553
|
},
|
|
402
554
|
});
|
|
403
555
|
} else {
|
|
@@ -412,7 +564,13 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
412
564
|
);
|
|
413
565
|
runTask = makeShellRunTask(log);
|
|
414
566
|
} else if (options.agent)
|
|
415
|
-
runTask = makeAgentRunTask({
|
|
567
|
+
runTask = makeAgentRunTask({
|
|
568
|
+
model: options.model,
|
|
569
|
+
permissionMode,
|
|
570
|
+
maxTurns: options.agentMaxTurns,
|
|
571
|
+
maxBudgetUsd: options.agentMaxBudgetUsd,
|
|
572
|
+
sessionIdForTask: (key) => collaborationUnits.get(key)?.sessionId,
|
|
573
|
+
});
|
|
416
574
|
else runTask = async () => ({ dryRun: true });
|
|
417
575
|
|
|
418
576
|
// Optional workflow tracing (Claude-Code 2.1.202 parity): every task
|
|
@@ -439,6 +597,19 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
439
597
|
mailbox,
|
|
440
598
|
recorder,
|
|
441
599
|
onEvent: (e) => {
|
|
600
|
+
if (e.type === "task:claimed") {
|
|
601
|
+
settleGovernance(e.key, "running", {
|
|
602
|
+
startedAt: Date.now(),
|
|
603
|
+
});
|
|
604
|
+
} else if (e.type === "task:completed") {
|
|
605
|
+
settleGovernance(e.key, "completed", {
|
|
606
|
+
endedAt: Date.now(),
|
|
607
|
+
});
|
|
608
|
+
} else if (e.type === "task:failed") {
|
|
609
|
+
settleGovernance(e.key, e.retry ? "pending" : "failed", {
|
|
610
|
+
endedAt: e.retry ? null : Date.now(),
|
|
611
|
+
});
|
|
612
|
+
}
|
|
442
613
|
if (options.json) console.log(JSON.stringify(e));
|
|
443
614
|
else if (e.type === "task:claimed")
|
|
444
615
|
(log.info || console.log)(` → ${e.key} [${e.holder}]`);
|
|
@@ -459,8 +630,43 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
459
630
|
runner.seedMembers(priorMembers);
|
|
460
631
|
runnerRef = runner;
|
|
461
632
|
|
|
462
|
-
|
|
633
|
+
let summary;
|
|
634
|
+
try {
|
|
635
|
+
summary = await runner.run();
|
|
636
|
+
} catch (err) {
|
|
637
|
+
try {
|
|
638
|
+
_deps.collaborationStore.finalizeRun(collaborationRun.id, "failed");
|
|
639
|
+
} catch {
|
|
640
|
+
/* retain the original runner failure */
|
|
641
|
+
}
|
|
642
|
+
throw err;
|
|
643
|
+
}
|
|
463
644
|
persist();
|
|
645
|
+
try {
|
|
646
|
+
// Reconcile from the authoritative registry after all event callbacks.
|
|
647
|
+
// This closes any best-effort onEvent write that failed mid-run.
|
|
648
|
+
for (const task of reg.list()) {
|
|
649
|
+
const state = String(task.status || "").toLowerCase();
|
|
650
|
+
const status =
|
|
651
|
+
state === "completed"
|
|
652
|
+
? "completed"
|
|
653
|
+
: state === "cancelled" || state === "pending"
|
|
654
|
+
? "cancelled"
|
|
655
|
+
: "failed";
|
|
656
|
+
settleGovernance(task.key, status, {
|
|
657
|
+
endedAt: Date.now(),
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
_deps.collaborationStore.finalizeRun(
|
|
661
|
+
collaborationRun.id,
|
|
662
|
+
summary.done ? "completed" : "failed",
|
|
663
|
+
);
|
|
664
|
+
} catch (err) {
|
|
665
|
+
(log.error || console.error)(
|
|
666
|
+
`Failed to finalize team governance: ${err.message}`,
|
|
667
|
+
);
|
|
668
|
+
process.exitCode = 1;
|
|
669
|
+
}
|
|
464
670
|
|
|
465
671
|
if (recorder && options.otlp) {
|
|
466
672
|
try {
|
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.162.184",
|
|
7
|
+
"cliVersions": ["0.4.75", "0.37.36", "0.162.183", "0.162.184"],
|
|
8
|
+
"date": "2026-07-28",
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Added — cc CLI 0.162.184 + IDE retry, collaboration, and recovery governance",
|
|
13
|
+
"body": "> `chainlesschain` **0.162.183 → 0.162.184**, VS Code\n> **0.37.35 → 0.37.36**, and JetBrains **0.4.74 → 0.4.75** (2026-07-28).\n> `@chainlesschain/personal-data-hub` remains **0.4.57** and\n> `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Measured retry and tool attribution**: compact transcripts now record\n bounded tool durations, observed same-turn retries, and secret-free streaming\n LLM retry reasons with actual provider/model identity. CLI and both IDE usage\n reports consume the same authoritative aggregates.\n- **Durable team/batch governance**: collaboration runs persist bounded\n owner/session, permission mode, resource budget, lifecycle, and side-effect\n counts without prompts, argv, tool arguments, output, or credentials. IDE\n worktree views project these records as managed tasks without exposing\n background attach/stop controls.\n- **Transactional plugin upgrades**: staged installs revalidate manifests and\n signed SBOMs before atomic activation. Failed copies, load checks,\n post-install handling, or declined capability widening restore the prior\n active version; forced same-version reinstalls restore the exact old bytes.\n- **IDE activation feedback**: VS Code and JetBrains parse controlled\n `activated / rolled_back / unchanged` results, reload live sessions only\n after activation, and require explicit user approval before retrying with a\n widened capability grant.\n- **Process-boundary hardening**: plugin hooks, MCP/LSP servers, monitors, and\n native bins retain sandbox policy through the centralized execution broker;\n Linux bubblewrap setup fails closed with bounded diagnostics.\n- **Release validation**: publication requires this exact release commit to\n pass CLI CI and CLI Strict Sandbox on Linux, Windows, and macOS plus the\n packaged VSIX and JetBrains unit/build/Remote Robot gates."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"productVersion": null,
|
|
19
|
+
"cliVersion": "0.162.183",
|
|
20
|
+
"cliVersions": ["0.4.74", "0.37.35", "0.162.182", "0.162.183"],
|
|
21
|
+
"date": "2026-07-27",
|
|
22
|
+
"title": "",
|
|
23
|
+
"sections": [
|
|
24
|
+
{
|
|
25
|
+
"heading": "Added — cc CLI 0.162.183 + IDE quality, plugin, and worktree governance",
|
|
26
|
+
"body": "> `chainlesschain` **0.162.182 → 0.162.183**, VS Code\n> **0.37.34 → 0.37.35**, and JetBrains **0.4.73 → 0.4.74** (2026-07-27).\n> `@chainlesschain/personal-data-hub` remains **0.4.57** and\n> `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **IDE-native quality context**: both IDE bridges negotiate bounded\n `cc-ide-quality/v1` test-result, coverage, and debugger snapshots with\n Context v2 freshness metadata; VS Code notebook execution now carries its\n real notebook context.\n- **Installation Doctor depth**: VS Code and JetBrains report Node/Java\n availability plus managed-CLI and plugin-registry offline recovery state,\n without probing executables from an untrusted workspace directory.\n- **Plugin lifecycle and supply-chain UI**: scoped enable/disable, source-aware\n upgrades, live-session reload, signature/SBOM summaries, managed-policy\n provenance, and sanitized registry/Git/local source metadata stay governed\n by the CLI runtime.\n- **Plugin usage attribution**: compact transcripts and usage reports now\n attribute plugin-bin and plugin-provided MCP calls by plugin/version without\n persisting tool arguments.\n- **Supervised worktree tasks**: IDE-created isolated tasks run as background\n worktree agents and display canonical lifecycle, owner/session, permission\n mode, resource budget, and bounded side-effect counts. Team and batch rows\n remain explicitly unmanaged until they expose equivalent durable state.\n- **Release validation**: publication remains gated on the exact release\n commit passing CLI CI, CLI Strict Sandbox, background reconnect E2E, packaged\n VSIX Extension Host gates, JetBrains unit/build/Remote Robot gates, and\n public marketplace readback."
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
4
30
|
{
|
|
5
31
|
"productVersion": null,
|
|
6
32
|
"cliVersion": "0.162.182",
|
|
@@ -164,20 +164,73 @@ export function appendToolCall(sessionId, toolName, args) {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Compact tool-call record for usage attribution (用量归因): tool name +
|
|
167
|
-
* error flag (+
|
|
168
|
-
* the args, which can carry whole file bodies (write_file
|
|
169
|
-
* bloat the transcript. Written at tool-result time by the
|
|
170
|
-
* `cc session usage --by tool|mcp` and `cc insights`
|
|
171
|
-
* for any persisted session.
|
|
167
|
+
* error flag (+ optional skill, plugin/version, and bounded observed duration)
|
|
168
|
+
* — deliberately NOT the args, which can carry whole file bodies (write_file
|
|
169
|
+
* content) and would bloat the transcript. Written at tool-result time by the
|
|
170
|
+
* agent drivers so `cc session usage --by tool|mcp|plugin` and `cc insights`
|
|
171
|
+
* can aggregate tool use for any persisted session.
|
|
172
172
|
*/
|
|
173
173
|
export function appendToolCallCompact(
|
|
174
174
|
sessionId,
|
|
175
|
-
{ tool, isError, skill } = {},
|
|
175
|
+
{ tool, isError, skill, plugin, pluginVersion, durationMs } = {},
|
|
176
176
|
) {
|
|
177
|
+
const duration = normalizeCompactDuration(durationMs);
|
|
177
178
|
appendEvent(sessionId, "tool_call", {
|
|
178
179
|
tool: tool || "?",
|
|
179
180
|
is_error: Boolean(isError),
|
|
180
181
|
...(skill ? { skill: String(skill) } : {}),
|
|
182
|
+
...(plugin ? { plugin: String(plugin) } : {}),
|
|
183
|
+
...(pluginVersion ? { plugin_version: String(pluginVersion) } : {}),
|
|
184
|
+
...(duration !== null ? { duration_ms: duration } : {}),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Hard cap for one observed failed LLM/tool attempt (seven days). */
|
|
189
|
+
export const MAX_COMPACT_DURATION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
190
|
+
|
|
191
|
+
function normalizeCompactDuration(value) {
|
|
192
|
+
if (value === null || value === undefined || value === "") return null;
|
|
193
|
+
const number = Number(value);
|
|
194
|
+
if (!Number.isFinite(number) || number < 0) return null;
|
|
195
|
+
return Math.min(MAX_COMPACT_DURATION_MS, Math.round(number));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Persist one automatic LLM stream retry without raw errors, prompts, URLs, or
|
|
200
|
+
* credentials. Provider/model are bounded identity labels; reason is a closed
|
|
201
|
+
* vocabulary produced by classifyStreamRetryReason().
|
|
202
|
+
*/
|
|
203
|
+
export function appendLlmRetryCompact(
|
|
204
|
+
sessionId,
|
|
205
|
+
{ attempt, durationMs, provider, model, reason } = {},
|
|
206
|
+
) {
|
|
207
|
+
const attemptNumber = Math.max(
|
|
208
|
+
1,
|
|
209
|
+
Math.min(15, Math.trunc(Number(attempt) || 1)),
|
|
210
|
+
);
|
|
211
|
+
const duration = normalizeCompactDuration(durationMs);
|
|
212
|
+
const cleanLabel = (value, max) => {
|
|
213
|
+
if (typeof value !== "string") return null;
|
|
214
|
+
const clean = value.replace(/\p{Cc}/gu, "").trim();
|
|
215
|
+
return clean ? clean.slice(0, max) : null;
|
|
216
|
+
};
|
|
217
|
+
const allowedReasons = new Set([
|
|
218
|
+
"timeout",
|
|
219
|
+
"dns",
|
|
220
|
+
"connection_refused",
|
|
221
|
+
"network_unreachable",
|
|
222
|
+
"connection_reset",
|
|
223
|
+
"unknown",
|
|
224
|
+
]);
|
|
225
|
+
const cleanReason = allowedReasons.has(reason) ? reason : "unknown";
|
|
226
|
+
const cleanProvider = cleanLabel(provider, 64);
|
|
227
|
+
const cleanModel = cleanLabel(model, 128);
|
|
228
|
+
appendEvent(sessionId, "llm_retry", {
|
|
229
|
+
attempt: attemptNumber,
|
|
230
|
+
duration_ms: duration ?? 0,
|
|
231
|
+
reason: cleanReason,
|
|
232
|
+
...(cleanProvider ? { provider: cleanProvider } : {}),
|
|
233
|
+
...(cleanModel ? { model: cleanModel } : {}),
|
|
181
234
|
});
|
|
182
235
|
}
|
|
183
236
|
|
|
@@ -14,6 +14,7 @@ import { EventEmitter } from "events";
|
|
|
14
14
|
import { pathToFileURL } from "url";
|
|
15
15
|
import { safeJsonParse } from "../lib/safe-json.js";
|
|
16
16
|
import { EventRuntimeProducer } from "../lib/event-runtime-producer.js";
|
|
17
|
+
import { resolvePluginWorkspaceAuthority } from "../lib/plugin-runtime/sandbox-policy.js";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Injectable dependencies — overridable from tests.
|
|
@@ -62,8 +63,7 @@ const URL_ELICITATION_REQUIRED = -32042;
|
|
|
62
63
|
function supportsUrlElicitationVersion(version) {
|
|
63
64
|
const normalized = String(version || "");
|
|
64
65
|
return (
|
|
65
|
-
/^\d{4}-\d{2}-\d{2}$/.test(normalized) &&
|
|
66
|
-
normalized >= MCP_PROTOCOL_VERSION
|
|
66
|
+
/^\d{4}-\d{2}-\d{2}$/.test(normalized) && normalized >= MCP_PROTOCOL_VERSION
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -130,9 +130,7 @@ export function normalizeMcpElicitationRequest(
|
|
|
130
130
|
|
|
131
131
|
const elicitationId = String(params.elicitationId || "").trim();
|
|
132
132
|
if (!elicitationId) {
|
|
133
|
-
const error = new Error(
|
|
134
|
-
"URL mode MCP elicitation requires elicitationId",
|
|
135
|
-
);
|
|
133
|
+
const error = new Error("URL mode MCP elicitation requires elicitationId");
|
|
136
134
|
error.code = "CC_MCP_ELICITATION_INVALID";
|
|
137
135
|
throw error;
|
|
138
136
|
}
|
|
@@ -267,10 +265,14 @@ export class MCPClient extends EventEmitter {
|
|
|
267
265
|
Number(options.maxConcurrentElicitations) > 0
|
|
268
266
|
? Math.min(128, Number(options.maxConcurrentElicitations))
|
|
269
267
|
: 32;
|
|
270
|
-
this._protocolVersion =
|
|
271
|
-
|
|
268
|
+
this._protocolVersion = String(
|
|
269
|
+
options.protocolVersion || MCP_PROTOCOL_VERSION,
|
|
270
|
+
);
|
|
272
271
|
this._runtimeProducer = options.eventRuntimeStore
|
|
273
|
-
? new EventRuntimeProducer({
|
|
272
|
+
? new EventRuntimeProducer({
|
|
273
|
+
store: options.eventRuntimeStore,
|
|
274
|
+
emitter: this,
|
|
275
|
+
})
|
|
274
276
|
: null;
|
|
275
277
|
}
|
|
276
278
|
|
|
@@ -279,11 +281,11 @@ export class MCPClient extends EventEmitter {
|
|
|
279
281
|
const sessionId = options.sessionId;
|
|
280
282
|
if (sessionId != null && sessionId !== "") {
|
|
281
283
|
const key = String(sessionId);
|
|
282
|
-
if (typeof handler === "function")
|
|
284
|
+
if (typeof handler === "function")
|
|
285
|
+
this._elicitationHandlers.set(key, handler);
|
|
283
286
|
else this._elicitationHandlers.delete(key);
|
|
284
287
|
} else {
|
|
285
|
-
this._elicitationHandler =
|
|
286
|
-
typeof handler === "function" ? handler : null;
|
|
288
|
+
this._elicitationHandler = typeof handler === "function" ? handler : null;
|
|
287
289
|
}
|
|
288
290
|
if (Number(options.timeoutMs) > 0) {
|
|
289
291
|
this._elicitationTimeoutMs = Number(options.timeoutMs);
|
|
@@ -389,8 +391,9 @@ export class MCPClient extends EventEmitter {
|
|
|
389
391
|
requestId,
|
|
390
392
|
params,
|
|
391
393
|
);
|
|
392
|
-
const negotiatedVersion =
|
|
393
|
-
|
|
394
|
+
const negotiatedVersion = this.servers.get(
|
|
395
|
+
String(serverName),
|
|
396
|
+
)?.protocolVersion;
|
|
394
397
|
if (
|
|
395
398
|
request.mode === "url" &&
|
|
396
399
|
negotiatedVersion &&
|
|
@@ -431,10 +434,7 @@ export class MCPClient extends EventEmitter {
|
|
|
431
434
|
direct !== undefined &&
|
|
432
435
|
String(direct?.action || "").toLowerCase() !== "defer"
|
|
433
436
|
) {
|
|
434
|
-
const response = this._normalizeElicitationResponse(
|
|
435
|
-
direct,
|
|
436
|
-
request,
|
|
437
|
-
);
|
|
437
|
+
const response = this._normalizeElicitationResponse(direct, request);
|
|
438
438
|
this._settleUrlElicitation(request, response);
|
|
439
439
|
try {
|
|
440
440
|
this._runtimeProducer?.store.acknowledgeInbox(
|
|
@@ -504,7 +504,8 @@ export class MCPClient extends EventEmitter {
|
|
|
504
504
|
});
|
|
505
505
|
this.emit("elicitation-request", {
|
|
506
506
|
...request,
|
|
507
|
-
respond: (response) =>
|
|
507
|
+
respond: (response) =>
|
|
508
|
+
this.respondElicitation(serverName, requestId, response),
|
|
508
509
|
cancel: () => this.cancelElicitation(serverName, requestId),
|
|
509
510
|
});
|
|
510
511
|
});
|
|
@@ -515,9 +516,7 @@ export class MCPClient extends EventEmitter {
|
|
|
515
516
|
if (!id) return;
|
|
516
517
|
const existing = this._urlElicitations.get(id);
|
|
517
518
|
if (existing && existing.server !== request.server) {
|
|
518
|
-
throw new Error(
|
|
519
|
-
`MCP URL elicitation id collision across servers: ${id}`,
|
|
520
|
-
);
|
|
519
|
+
throw new Error(`MCP URL elicitation id collision across servers: ${id}`);
|
|
521
520
|
}
|
|
522
521
|
if (existing && existing.request?.url !== request.url) {
|
|
523
522
|
throw new Error(
|
|
@@ -544,7 +543,9 @@ export class MCPClient extends EventEmitter {
|
|
|
544
543
|
const entry = this._urlElicitations.get(request.elicitationId);
|
|
545
544
|
if (!entry || entry.status === "completed") return;
|
|
546
545
|
entry.status =
|
|
547
|
-
response?.action === "accept"
|
|
546
|
+
response?.action === "accept"
|
|
547
|
+
? "accepted"
|
|
548
|
+
: response?.action || "decline";
|
|
548
549
|
if (entry.status === "accepted" && entry.completionNotified) {
|
|
549
550
|
this._completeUrlElicitation(entry);
|
|
550
551
|
}
|
|
@@ -757,7 +758,26 @@ export class MCPClient extends EventEmitter {
|
|
|
757
758
|
`stdio transport requires a command (server "${name}")`,
|
|
758
759
|
);
|
|
759
760
|
}
|
|
760
|
-
const
|
|
761
|
+
const isPlugin = config.origin === "plugin:mcp";
|
|
762
|
+
const pluginWorkspaceRoot = isPlugin
|
|
763
|
+
? resolvePluginWorkspaceAuthority(config.pluginWorkspaceAuthority, {
|
|
764
|
+
origin: config.origin,
|
|
765
|
+
pluginId: config.pluginId,
|
|
766
|
+
pluginVersion: config.pluginVersion,
|
|
767
|
+
pluginSource: config.pluginSource,
|
|
768
|
+
})
|
|
769
|
+
: null;
|
|
770
|
+
if (
|
|
771
|
+
isPlugin &&
|
|
772
|
+
config.sandboxPolicy?.requiredBoundaries?.length > 0 &&
|
|
773
|
+
!pluginWorkspaceRoot
|
|
774
|
+
) {
|
|
775
|
+
throw new Error(
|
|
776
|
+
`plugin MCP server "${name}" is missing its trusted workspace authority`,
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
const spawnOptions = {
|
|
780
|
+
cwd: pluginWorkspaceRoot || process.cwd(),
|
|
761
781
|
stdio: ["pipe", "pipe", "pipe"],
|
|
762
782
|
// process.env < agent identity (CLAUDECODE / session id) < the
|
|
763
783
|
// server's own config.env, so an explicit per-server override wins.
|
|
@@ -776,6 +796,19 @@ export class MCPClient extends EventEmitter {
|
|
|
776
796
|
...(config.sandboxPolicy
|
|
777
797
|
? { sandboxPolicy: config.sandboxPolicy }
|
|
778
798
|
: {}),
|
|
799
|
+
};
|
|
800
|
+
const sandboxExecutionContract =
|
|
801
|
+
!isPlugin || pluginWorkspaceRoot
|
|
802
|
+
? executionBroker.issueLinuxWorkspaceSandboxExecutionContract(
|
|
803
|
+
config.command,
|
|
804
|
+
config.args || [],
|
|
805
|
+
spawnOptions,
|
|
806
|
+
pluginWorkspaceRoot || process.cwd(),
|
|
807
|
+
)
|
|
808
|
+
: null;
|
|
809
|
+
const proc = _deps.spawn(config.command, config.args || [], {
|
|
810
|
+
...spawnOptions,
|
|
811
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
779
812
|
});
|
|
780
813
|
|
|
781
814
|
entry.process = proc;
|
|
@@ -1113,7 +1146,8 @@ export class MCPClient extends EventEmitter {
|
|
|
1113
1146
|
} catch {
|
|
1114
1147
|
return false;
|
|
1115
1148
|
}
|
|
1116
|
-
if (request.mode !== "url" || ids.has(request.elicitationId))
|
|
1149
|
+
if (request.mode !== "url" || ids.has(request.elicitationId))
|
|
1150
|
+
return false;
|
|
1117
1151
|
ids.add(request.elicitationId);
|
|
1118
1152
|
normalized.push(request);
|
|
1119
1153
|
}
|
|
@@ -1392,10 +1426,7 @@ export class MCPClient extends EventEmitter {
|
|
|
1392
1426
|
entry._httpMessageStream = stream;
|
|
1393
1427
|
stream.promise = (async () => {
|
|
1394
1428
|
try {
|
|
1395
|
-
while (
|
|
1396
|
-
!stream.stopped &&
|
|
1397
|
-
this.servers.get(serverName) === entry
|
|
1398
|
-
) {
|
|
1429
|
+
while (!stream.stopped && this.servers.get(serverName) === entry) {
|
|
1399
1430
|
stream.controller =
|
|
1400
1431
|
typeof AbortController === "function"
|
|
1401
1432
|
? new AbortController()
|
|
@@ -1427,9 +1458,7 @@ export class MCPClient extends EventEmitter {
|
|
|
1427
1458
|
);
|
|
1428
1459
|
}
|
|
1429
1460
|
const contentType = response.headers?.get
|
|
1430
|
-
? String(
|
|
1431
|
-
response.headers.get("content-type") || "",
|
|
1432
|
-
).toLowerCase()
|
|
1461
|
+
? String(response.headers.get("content-type") || "").toLowerCase()
|
|
1433
1462
|
: "";
|
|
1434
1463
|
if (!contentType.includes("text/event-stream")) return;
|
|
1435
1464
|
const cap = Number.isFinite(entry.config?.maxBufferChars)
|
|
@@ -1438,8 +1467,7 @@ export class MCPClient extends EventEmitter {
|
|
|
1438
1467
|
await _consumeSseMessageStream(response, {
|
|
1439
1468
|
cap,
|
|
1440
1469
|
stream,
|
|
1441
|
-
onMessage: (message) =>
|
|
1442
|
-
this._handleMessage(serverName, message),
|
|
1470
|
+
onMessage: (message) => this._handleMessage(serverName, message),
|
|
1443
1471
|
});
|
|
1444
1472
|
} catch (error) {
|
|
1445
1473
|
if (stream.stopped || stream.controller?.signal.aborted) return;
|
|
@@ -1564,11 +1592,8 @@ export class MCPClient extends EventEmitter {
|
|
|
1564
1592
|
|
|
1565
1593
|
let envelope;
|
|
1566
1594
|
if (contentType.includes("text/event-stream")) {
|
|
1567
|
-
envelope = await _extractSseResponse(
|
|
1568
|
-
|
|
1569
|
-
id,
|
|
1570
|
-
cap,
|
|
1571
|
-
(message) => this._handleMessage(serverName, message),
|
|
1595
|
+
envelope = await _extractSseResponse(response, id, cap, (message) =>
|
|
1596
|
+
this._handleMessage(serverName, message),
|
|
1572
1597
|
);
|
|
1573
1598
|
} else {
|
|
1574
1599
|
const text = await _readBodyCapped(response, cap);
|
|
@@ -1813,8 +1838,7 @@ export class MCPClient extends EventEmitter {
|
|
|
1813
1838
|
...(entry.httpSessionId
|
|
1814
1839
|
? { "Mcp-Session-Id": entry.httpSessionId }
|
|
1815
1840
|
: {}),
|
|
1816
|
-
"MCP-Protocol-Version":
|
|
1817
|
-
entry.protocolVersion || this._protocolVersion,
|
|
1841
|
+
"MCP-Protocol-Version": entry.protocolVersion || this._protocolVersion,
|
|
1818
1842
|
};
|
|
1819
1843
|
try {
|
|
1820
1844
|
const pending = _deps.fetch(entry.httpUrl, {
|
|
@@ -1986,9 +2010,7 @@ async function _consumeSseMessageStream(
|
|
|
1986
2010
|
if (done) break;
|
|
1987
2011
|
buffer += decoder.decode(value, { stream: true });
|
|
1988
2012
|
if (cap > 0 && buffer.length > cap) {
|
|
1989
|
-
throw new Error(
|
|
1990
|
-
`MCP HTTP SSE event exceeded the ${cap}-char cap`,
|
|
1991
|
-
);
|
|
2013
|
+
throw new Error(`MCP HTTP SSE event exceeded the ${cap}-char cap`);
|
|
1992
2014
|
}
|
|
1993
2015
|
let boundary;
|
|
1994
2016
|
while ((boundary = buffer.search(/\r?\n\r?\n/)) >= 0) {
|