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/lib/agent-batch.js
CHANGED
|
@@ -94,7 +94,10 @@ export async function runBatch(opts, deps) {
|
|
|
94
94
|
try {
|
|
95
95
|
worktreePath = createWorktree(unit.key, branch);
|
|
96
96
|
onEvent({ type: "unit:start", key: unit.key, branch });
|
|
97
|
-
await runAgent(unit.prompt, worktreePath
|
|
97
|
+
await runAgent(unit.prompt, worktreePath, {
|
|
98
|
+
key: unit.key,
|
|
99
|
+
branch,
|
|
100
|
+
});
|
|
98
101
|
|
|
99
102
|
const stat = diffStat(worktreePath);
|
|
100
103
|
record.filesChanged = stat.filesChanged;
|
|
@@ -51,6 +51,10 @@ export class TeamRunner {
|
|
|
51
51
|
this._executions = 0;
|
|
52
52
|
this._inFlight = 0;
|
|
53
53
|
this._maxInFlight = 0;
|
|
54
|
+
// Keys executing in this runner process. An event-loop stall may let a
|
|
55
|
+
// short lease expire before its heartbeat callback runs; peer loops in the
|
|
56
|
+
// same process must not steal and double-run that still-active task.
|
|
57
|
+
this._activeKeys = new Set();
|
|
54
58
|
this._members = new Map(); // holder → lifecycle record
|
|
55
59
|
this._budgetStopped = false;
|
|
56
60
|
}
|
|
@@ -208,6 +212,7 @@ export class TeamRunner {
|
|
|
208
212
|
let best = null;
|
|
209
213
|
let bestScore = Infinity;
|
|
210
214
|
for (const key of claimable) {
|
|
215
|
+
if (this._activeKeys.has(key)) continue;
|
|
211
216
|
const t = this.registry.getTask(key);
|
|
212
217
|
const score = rank[t?.priority] ?? 1;
|
|
213
218
|
if (score < bestScore) {
|
|
@@ -222,10 +227,22 @@ export class TeamRunner {
|
|
|
222
227
|
const task = this.registry.getTask(key);
|
|
223
228
|
this._executions++;
|
|
224
229
|
this._inFlight++;
|
|
230
|
+
this._activeKeys.add(key);
|
|
225
231
|
this._maxInFlight = Math.max(this._maxInFlight, this._inFlight);
|
|
226
232
|
this._setState(holder, "running", { key });
|
|
227
233
|
this._emit("task:claimed", { key, holder, attempts: task.attempts });
|
|
228
|
-
const renew = () =>
|
|
234
|
+
const renew = () => {
|
|
235
|
+
const result = this.registry.renew(key, {
|
|
236
|
+
holder,
|
|
237
|
+
ttlMs: this.ttlMs,
|
|
238
|
+
});
|
|
239
|
+
// A delayed timer may wake just after expiry. Reacquire is safe and
|
|
240
|
+
// optimistic: it succeeds only if no external runner has taken the
|
|
241
|
+
// lease; a real takeover remains authoritative and stops the heartbeat.
|
|
242
|
+
return !result?.ok && result?.reason === "not_holder_or_expired"
|
|
243
|
+
? this.registry.acquire(key, { holder, ttlMs: this.ttlMs })
|
|
244
|
+
: result;
|
|
245
|
+
};
|
|
229
246
|
// Heartbeat: the built-in executors (shell / agent / worktree) never call
|
|
230
247
|
// `renew` themselves, so before this ANY task outliving the lease TTL was
|
|
231
248
|
// indistinguishable from a crash — a peer could steal it and the SAME task
|
|
@@ -338,6 +355,7 @@ export class TeamRunner {
|
|
|
338
355
|
});
|
|
339
356
|
} finally {
|
|
340
357
|
clearInterval(heartbeat);
|
|
358
|
+
this._activeKeys.delete(key);
|
|
341
359
|
this._inFlight--;
|
|
342
360
|
}
|
|
343
361
|
}
|
|
@@ -126,6 +126,8 @@ export class TeamWorktreeCoordinator {
|
|
|
126
126
|
sparsePaths: options.sparsePaths ?? null,
|
|
127
127
|
symlinkDirectories: options.symlinkDirectories ?? null,
|
|
128
128
|
};
|
|
129
|
+
this._onWorktree =
|
|
130
|
+
typeof options.onWorktree === "function" ? options.onWorktree : null;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
isGitRepo() {
|
|
@@ -173,6 +175,7 @@ export class TeamWorktreeCoordinator {
|
|
|
173
175
|
wtOptions,
|
|
174
176
|
);
|
|
175
177
|
this._created.set(key, { branch, path: worktreePath, committed: false });
|
|
178
|
+
this._onWorktree?.({ key, branch, path: worktreePath, holder });
|
|
176
179
|
if (typeof runInWorktree === "function") {
|
|
177
180
|
await runInWorktree({ key, task, holder, cwd: worktreePath });
|
|
178
181
|
} else {
|
|
@@ -36,6 +36,13 @@ const {
|
|
|
36
36
|
tryParseDecision,
|
|
37
37
|
resolveHookSandboxPolicy,
|
|
38
38
|
} = require("./hook-runner.cjs");
|
|
39
|
+
const {
|
|
40
|
+
buildExplicitHookShellInvocation,
|
|
41
|
+
issueTrustedHookSandboxContract,
|
|
42
|
+
requireTrustedHookRoot,
|
|
43
|
+
requiresExplicitHookShell,
|
|
44
|
+
sandboxBoundaryError,
|
|
45
|
+
} = require("./hook-shell-command.cjs");
|
|
39
46
|
|
|
40
47
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
41
48
|
const MAX_TIMEOUT_MS = 600000;
|
|
@@ -117,8 +124,25 @@ class AsyncHookSupervisor {
|
|
|
117
124
|
* the process 'exit' reaper, where async work would be cut off. A child with no
|
|
118
125
|
* real pid (the unit-test fakes) falls back to its own `.kill()`.
|
|
119
126
|
*/
|
|
120
|
-
_killChildTree(
|
|
127
|
+
_killChildTree(
|
|
128
|
+
child,
|
|
129
|
+
signal = "SIGTERM",
|
|
130
|
+
{ sandboxManagedTree = false } = {},
|
|
131
|
+
) {
|
|
121
132
|
if (!child) return;
|
|
133
|
+
if (sandboxManagedTree) {
|
|
134
|
+
// The Linux generic backend launches bubblewrap with --die-with-parent,
|
|
135
|
+
// --new-session, and a private PID namespace. Killing the Broker child
|
|
136
|
+
// therefore tears down the complete sandbox tree; a negative host PID
|
|
137
|
+
// would be both unnecessary and invalid because strong launches must not
|
|
138
|
+
// use detached:true.
|
|
139
|
+
try {
|
|
140
|
+
child.kill(signal);
|
|
141
|
+
} catch {
|
|
142
|
+
/* already gone */
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
122
146
|
const pid = child.pid;
|
|
123
147
|
if (typeof pid !== "number" || pid <= 0) {
|
|
124
148
|
try {
|
|
@@ -361,25 +385,39 @@ class AsyncHookSupervisor {
|
|
|
361
385
|
: DEFAULT_TIMEOUT_MS;
|
|
362
386
|
|
|
363
387
|
let child;
|
|
388
|
+
let sandboxManagedTree = false;
|
|
364
389
|
try {
|
|
365
390
|
const sandboxPolicy = resolveHookSandboxPolicy(hook, opts);
|
|
391
|
+
const explicitSandboxShell = requiresExplicitHookShell(sandboxPolicy);
|
|
392
|
+
const trustedRoot = explicitSandboxShell
|
|
393
|
+
? requireTrustedHookRoot(opts.cwd)
|
|
394
|
+
: null;
|
|
395
|
+
const workingDirectory = trustedRoot || opts.cwd || process.cwd();
|
|
396
|
+
sandboxManagedTree =
|
|
397
|
+
explicitSandboxShell && this._deps.platform === "linux";
|
|
366
398
|
const spawnOptions = {
|
|
367
|
-
cwd:
|
|
368
|
-
shell: true,
|
|
399
|
+
cwd: workingDirectory,
|
|
400
|
+
shell: explicitSandboxShell ? false : true,
|
|
369
401
|
// POSIX: own process group so a timeout / stopAll can signal the whole
|
|
370
402
|
// tree (shell + the real hook command), not just the shell wrapper.
|
|
371
403
|
// No-op on Windows, where the tree is reaped via `taskkill /T` instead.
|
|
372
|
-
detached: this._deps.platform !== "win32",
|
|
404
|
+
detached: this._deps.platform !== "win32" && !sandboxManagedTree,
|
|
373
405
|
env: {
|
|
374
406
|
...process.env,
|
|
375
407
|
CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
|
|
376
408
|
},
|
|
377
409
|
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
378
410
|
};
|
|
379
|
-
|
|
411
|
+
const brokerRun =
|
|
412
|
+
explicitSandboxShell &&
|
|
413
|
+
opts.broker &&
|
|
414
|
+
typeof opts.broker.spawn === "function"
|
|
415
|
+
? opts.broker.spawn.bind(opts.broker)
|
|
416
|
+
: null;
|
|
417
|
+
if (typeof (brokerRun || this._deps.run) !== "function") {
|
|
380
418
|
throw new Error("async hook process runner unavailable");
|
|
381
419
|
}
|
|
382
|
-
|
|
420
|
+
const processOptions = {
|
|
383
421
|
...spawnOptions,
|
|
384
422
|
origin: hook.origin || "async-hook:command",
|
|
385
423
|
policy: "allow",
|
|
@@ -387,7 +425,39 @@ class AsyncHookSupervisor {
|
|
|
387
425
|
pluginId: hook.pluginId || null,
|
|
388
426
|
pluginVersion: hook.pluginVersion || null,
|
|
389
427
|
pluginSource: hook.pluginSource || null,
|
|
390
|
-
}
|
|
428
|
+
};
|
|
429
|
+
if (explicitSandboxShell) {
|
|
430
|
+
const invocation = buildExplicitHookShellInvocation(hook.command, {
|
|
431
|
+
platform: this._deps.platform,
|
|
432
|
+
});
|
|
433
|
+
const run = brokerRun || this._deps.run;
|
|
434
|
+
let brokerOptions = processOptions;
|
|
435
|
+
if (brokerRun) {
|
|
436
|
+
const issuer =
|
|
437
|
+
opts.broker.issueLinuxWorkspaceSandboxExecutionContract;
|
|
438
|
+
const sandboxExecutionContract = issueTrustedHookSandboxContract({
|
|
439
|
+
issuer,
|
|
440
|
+
receiver: opts.broker,
|
|
441
|
+
file: invocation.file,
|
|
442
|
+
args: invocation.argv,
|
|
443
|
+
options: processOptions,
|
|
444
|
+
trustedRoot,
|
|
445
|
+
label: "trusted async-hook sandbox contract issuance failed",
|
|
446
|
+
});
|
|
447
|
+
if (this._deps.platform === "linux" && !sandboxExecutionContract) {
|
|
448
|
+
throw sandboxBoundaryError(
|
|
449
|
+
"trusted Linux async-hook sandbox contract issuer is unavailable",
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
brokerOptions = {
|
|
453
|
+
...processOptions,
|
|
454
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
child = run(invocation.file, invocation.argv, brokerOptions);
|
|
458
|
+
} else {
|
|
459
|
+
child = this._deps.run(hook.command, processOptions);
|
|
460
|
+
}
|
|
391
461
|
} catch (err) {
|
|
392
462
|
const sandboxDenied =
|
|
393
463
|
err?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
|
|
@@ -406,7 +476,7 @@ class AsyncHookSupervisor {
|
|
|
406
476
|
let out = "";
|
|
407
477
|
let errOut = "";
|
|
408
478
|
let killedByTimeout = false;
|
|
409
|
-
const rec = { child, timer: null };
|
|
479
|
+
const rec = { child, timer: null, sandboxManagedTree };
|
|
410
480
|
this._running.set(key, rec);
|
|
411
481
|
|
|
412
482
|
try {
|
|
@@ -432,7 +502,7 @@ class AsyncHookSupervisor {
|
|
|
432
502
|
killedByTimeout = true;
|
|
433
503
|
// Tree-kill: a hook that spawned a subprocess (e.g. `npm test`) must not
|
|
434
504
|
// leave that subprocess orphaned when it exceeds its timeout.
|
|
435
|
-
this._killChildTree(child, "SIGTERM");
|
|
505
|
+
this._killChildTree(child, "SIGTERM", { sandboxManagedTree });
|
|
436
506
|
}, timeout);
|
|
437
507
|
if (typeof timer.unref === "function") timer.unref();
|
|
438
508
|
rec.timer = timer;
|
|
@@ -594,7 +664,9 @@ class AsyncHookSupervisor {
|
|
|
594
664
|
}
|
|
595
665
|
// Tree-kill (not a bare child.kill) so a session end / process exit never
|
|
596
666
|
// leaves an orphaned hook subprocess — the guarantee this class documents.
|
|
597
|
-
this._killChildTree(rec.child, "SIGTERM"
|
|
667
|
+
this._killChildTree(rec.child, "SIGTERM", {
|
|
668
|
+
sandboxManagedTree: rec.sandboxManagedTree === true,
|
|
669
|
+
});
|
|
598
670
|
this._running.delete(key);
|
|
599
671
|
}
|
|
600
672
|
try {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import supervisor from "./async-hook-supervisor.cjs";
|
|
2
2
|
import executionBroker from "./process-execution-broker/index.js";
|
|
3
|
+
import hookShellCommand from "./hook-shell-command.cjs";
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
issueTrustedHookSandboxContract,
|
|
7
|
+
requireTrustedHookRoot,
|
|
8
|
+
requiresExplicitHookShell,
|
|
9
|
+
sandboxBoundaryError,
|
|
10
|
+
} = hookShellCommand;
|
|
3
11
|
|
|
4
12
|
const brokerRunner = executionBroker.spawn.bind(executionBroker);
|
|
5
13
|
const brokerSyncRunner = executionBroker.spawnSync.bind(executionBroker);
|
|
@@ -9,12 +17,50 @@ export const _processDeps = {
|
|
|
9
17
|
runSync: brokerSyncRunner,
|
|
10
18
|
};
|
|
11
19
|
|
|
12
|
-
function
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
function normalizeInvocation(argsOrOptions, maybeOptions) {
|
|
21
|
+
return Array.isArray(argsOrOptions)
|
|
22
|
+
? { args: argsOrOptions, options: maybeOptions || {} }
|
|
23
|
+
: { args: [], options: argsOrOptions || {} };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function runAsyncHook(command, argsOrOptions = {}, maybeOptions) {
|
|
27
|
+
const { args, options } = normalizeInvocation(argsOrOptions, maybeOptions);
|
|
28
|
+
const callerOptions = { ...options };
|
|
29
|
+
delete callerOptions.sandboxExecutionContract;
|
|
30
|
+
const processOptions = {
|
|
31
|
+
...callerOptions,
|
|
32
|
+
origin: callerOptions.origin || "async-hook:command",
|
|
16
33
|
policy: "allow",
|
|
17
34
|
scope: "async-hook",
|
|
35
|
+
};
|
|
36
|
+
const requiresContract = requiresExplicitHookShell(
|
|
37
|
+
processOptions.sandboxPolicy,
|
|
38
|
+
);
|
|
39
|
+
const trustedRoot = requiresContract
|
|
40
|
+
? requireTrustedHookRoot(processOptions.cwd)
|
|
41
|
+
: null;
|
|
42
|
+
const sandboxExecutionContract = requiresContract
|
|
43
|
+
? issueTrustedHookSandboxContract({
|
|
44
|
+
issuer: executionBroker.issueLinuxWorkspaceSandboxExecutionContract,
|
|
45
|
+
receiver: executionBroker,
|
|
46
|
+
file: command,
|
|
47
|
+
args,
|
|
48
|
+
options: processOptions,
|
|
49
|
+
trustedRoot,
|
|
50
|
+
})
|
|
51
|
+
: null;
|
|
52
|
+
if (
|
|
53
|
+
process.platform === "linux" &&
|
|
54
|
+
requiresContract &&
|
|
55
|
+
!sandboxExecutionContract
|
|
56
|
+
) {
|
|
57
|
+
throw sandboxBoundaryError(
|
|
58
|
+
"trusted Linux async-hook sandbox contract could not be issued",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return _processDeps.run(command, args, {
|
|
62
|
+
...processOptions,
|
|
63
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
18
64
|
});
|
|
19
65
|
}
|
|
20
66
|
|
|
@@ -762,6 +762,47 @@ export function normalizeBackgroundWorktree(worktree, cwd) {
|
|
|
762
762
|
return normalized;
|
|
763
763
|
}
|
|
764
764
|
|
|
765
|
+
/**
|
|
766
|
+
* Persist only the bounded, secret-free governance envelope needed by IDE task
|
|
767
|
+
* rows. The supervisor owns `owner`; callers cannot forge it. Prompt text,
|
|
768
|
+
* argv, credentials and tool arguments are deliberately excluded.
|
|
769
|
+
*/
|
|
770
|
+
export function normalizeBackgroundGovernance(
|
|
771
|
+
governance,
|
|
772
|
+
{ id, sessionId } = {},
|
|
773
|
+
) {
|
|
774
|
+
const source = governance && typeof governance === "object" ? governance : {};
|
|
775
|
+
const budget =
|
|
776
|
+
source.resourceBudget && typeof source.resourceBudget === "object"
|
|
777
|
+
? source.resourceBudget
|
|
778
|
+
: {};
|
|
779
|
+
const positive = (value) => {
|
|
780
|
+
const n = Number(value);
|
|
781
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
782
|
+
};
|
|
783
|
+
const permissionMode = new Set([
|
|
784
|
+
"manual",
|
|
785
|
+
"auto",
|
|
786
|
+
"dontAsk",
|
|
787
|
+
"default",
|
|
788
|
+
"plan",
|
|
789
|
+
"acceptEdits",
|
|
790
|
+
"bypassPermissions",
|
|
791
|
+
]).has(source.permissionMode)
|
|
792
|
+
? source.permissionMode
|
|
793
|
+
: "default";
|
|
794
|
+
return {
|
|
795
|
+
version: 1,
|
|
796
|
+
owner: `background:${String(id || "").slice(0, 160)}`,
|
|
797
|
+
sessionId: sessionId ? String(sessionId).slice(0, 256) : null,
|
|
798
|
+
permissionMode,
|
|
799
|
+
resourceBudget: {
|
|
800
|
+
maxTurns: positive(budget.maxTurns),
|
|
801
|
+
maxCostUsd: positive(budget.maxCostUsd),
|
|
802
|
+
},
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
765
806
|
function persistedWorktree(state) {
|
|
766
807
|
if (!state?.worktreePath) return null;
|
|
767
808
|
return {
|
|
@@ -817,6 +858,7 @@ export function resumeBackgroundAgent(id, prompt, options = {}) {
|
|
|
817
858
|
cliEntry: options.cliEntry,
|
|
818
859
|
followUpArgv: ["agent", "--session", state.sessionId],
|
|
819
860
|
worktree,
|
|
861
|
+
governance: state.governance,
|
|
820
862
|
});
|
|
821
863
|
}
|
|
822
864
|
|
|
@@ -855,10 +897,15 @@ export function launchBackgroundAgent({
|
|
|
855
897
|
cliEntry,
|
|
856
898
|
followUpArgv,
|
|
857
899
|
worktree,
|
|
900
|
+
governance,
|
|
858
901
|
}) {
|
|
859
902
|
assertUsableCwd(cwd);
|
|
860
903
|
const worktreeState = normalizeBackgroundWorktree(worktree, cwd);
|
|
861
904
|
const id = createBackgroundAgentId();
|
|
905
|
+
const governanceState = normalizeBackgroundGovernance(governance, {
|
|
906
|
+
id,
|
|
907
|
+
sessionId,
|
|
908
|
+
});
|
|
862
909
|
const dir = backgroundAgentsDir();
|
|
863
910
|
const jobFile = join(dir, `${id}.job.${process.pid}.json`);
|
|
864
911
|
const worker = fileURLToPath(
|
|
@@ -873,6 +920,7 @@ export function launchBackgroundAgent({
|
|
|
873
920
|
cliEntry: cliEntry || process.argv[1],
|
|
874
921
|
logFile: logPath(id),
|
|
875
922
|
...(worktreeState || {}),
|
|
923
|
+
governance: governanceState,
|
|
876
924
|
// Present = interactive attach can start follow-up turns; absent = the
|
|
877
925
|
// transport rejects prompts (log-only session).
|
|
878
926
|
...(Array.isArray(followUpArgv) ? { followUpArgv } : {}),
|
|
@@ -897,6 +945,7 @@ export function launchBackgroundAgent({
|
|
|
897
945
|
exitCode: null,
|
|
898
946
|
logFile: job.logFile,
|
|
899
947
|
...(worktreeState || {}),
|
|
948
|
+
governance: governanceState,
|
|
900
949
|
};
|
|
901
950
|
writeBackgroundAgentState(state);
|
|
902
951
|
let child;
|