chainlesschain 0.162.159 → 0.162.161
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/README.md +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-ByIiF5bT.js → AIOps-DMn528q-.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-NlgSFZq5.js → ActionButton-D9ZcDCJL.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D17cOUcb.js → Analytics-A_K-8PX0.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-B4mEZcbl.js → AppLayout-D4pFW3X6.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CASsmyQw.js → Artifacts-Dz46COAd.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DYAia2e2.js → Audit-cbMjbyg0.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-C1lvYUSu.js → BackgroundAgents-Dtf88GAj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B6agK6bA.js → Backup-C5KRxn52.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DM43R2vy.js → BaseInput-Dd2UK3BN.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Dtdp3eXp.js → Chat-lptKTFdG.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BL5c_OQ1.js → ChatBubbleRenderer-C2KLtwHz.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-D2xf7uZt.js → Checkbox-_yspG6rG.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D3j45jJL.js → Codegen-BGq_GAha.js} +1 -1
- package/src/assets/web-panel/assets/{Col-voPJ9fUZ.js → Col-CePor71g.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DEsyTESF.js → Community-CLOWhIT7.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-OHV_QXLD.js → Compact-CivJt2vT.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-eDTJWC-J.js → Compliance-Btmo1GGE.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BBvy-6d1.js → Cowork-Ct35OlG4.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Dw2eoJxu.js → Cron-CTc2GmhB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DQHms_Bh.js → Crosschain-ZtiBETk1.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Cyu7Id1c.js → DID-BNqMQQXw.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-sIDzkG92.js → Dashboard-BmzZd-9V.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DUW3T2ey.js → Dropdown-CMVgvP2M.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CECELXW8.js → EmailListRenderer-CcqQFAfT.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BIZR37ov.js → FamilyGuardDashboard-CTqB1_4V.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BEZIQX84.js → Federation-CiKOOzlb.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BcdUMznL.js → FormItemContext-Wk-OT0gr.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DsN_fr5H.js → GenericCardRenderer-DbEQT6ue.js} +1 -1
- package/src/assets/web-panel/assets/{Git-63LhjBx2.js → Git-0ZvCPSD9.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CYtQtIcH.js → Governance-CmVuKkPb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BwR6UUox.js → Inference-CTWE3Jwg.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-D9lVNTUA.js → KnowledgeGraph-CBEIF00L.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-C4q5h7Ut.js → Logs-DLhxDwVG.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DxywvhTU.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Plksliuw.js → Marketplace-BgsCBrnc.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DZUFfeuG.js → McpTools-ClBUGDS2.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-NoDYt29V.js → Memory-CnG_ZnYw.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CEXGTkdh.js → MobileBridge-BUOAbR1Z.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DnbJkbZo.js → MobileProjects-Dnt_9-WB.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DTAa0cwy.js → Mtc-CLjt4kCD.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CVV7LnNS.js → MtcAudit-f24U9Aes.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BqqGrjt_.js → Multisig-GrmGQbSq.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C4WP8DRp.js → NLProgramming-DADaWn-n.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Zo4DJUVI.js → Notes-xtf5RX6C.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DBcjRaz2.js → NotificationSettings-Cd27Rgtx.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-fXRxlDjl.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BT9WPBOX.js → Organization-joCFlNB0.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-D6b4bZ3q.js → Overflow-B1HoURq0.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cw3OsYx-.js → P2P-DiwsKbT7.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C0nyiK2b.js → PdhVaultBrowser-Xe-BsW6S.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-zVBZEB_C.js → Permissions-C23qi8kl.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BOspsFew.js → PersonalDataHub-BS1syX2f.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-CQWfZ4XH.js → Pipeline-DRYwwDyh.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-C2oGJ_WL.js → Privacy-BQKaDHPH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BZMR4qY1.js → ProjectInit-BC6F9xiG.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DAujoP63.js → ProjectSettings-ClFPc1Nd.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Dn-f5aYe.js +1 -0
- package/src/assets/web-panel/assets/{Providers-D_RGHM-v.js → Providers-CLWuOUNt.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Mf6KfL2J.js → QrScannerModal-DiqULTxb.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-5D8URoI_.js → QuickAsk-9A03P-E_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Df4kC8Gy.js → Recommend-CJZAnbq_.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DGi3f3vO.js → RemoteSession-C9A1R77h.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-jmkGFNWb.js → Reputation-BIZc6Rky.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DP6Pcu3m.js → Row-DfIPNtuG.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D60hSuPO.js → RssFeed-C5znFcQ1.js} +3 -3
- package/src/assets/web-panel/assets/{Search-0mf1BQUK.js → Search-DSs2z3OX.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CfZtLFYV.js → Security-CV6LcrLY.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D9zpZLWz.js → Services-cmhoX0Xj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D1_44eMD.js → Skeleton-tCsg2po7.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-cVFa8zkz.js → Skills-BK1KUDiy.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Cinpzc3L.js → Sla-yRgyeA82.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-bqdiJE_P.js → SpeechSettings-c1mo1mlp.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Dgl_SLgj.js → SyncSettings-koIAfuT3.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DawWAEhy.js → Tasks-DkkreAaB.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Ca0nY651.js → Templates-fy5Ctf9M.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CgaGEhLm.js → Tenant-Bw70Jf6S.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D-9EnpRx.js → Terminal-BKh6Rx-4.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CSOxDHZ6.js → TimelineRenderer-Dg54WP0c.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BpwLZpL3.js → Tokens-BvvD5SxJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DgowwBK5.js → Trigger-B7Ug9x4e.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BZutapjE.js → Trust-BjvuMORY.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-QZPt8_Sp.js → UkeySign-CZqhkx8p.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DlQx5UDJ.js → VideoEditing-ClR50lhX.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-ZfdTgtWA.js → Wallet-DlfppYjx.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CAp0y_Cr.js → WebAuthn-BirgVr8B.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BVITZEmr.js → WorkflowEditor-B8DP_bax.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CC2tPaNg.js → chat-DA8AUZzL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-31brc9CA.js → colors-C38pLGp1.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DLMkC9C-.js → compact-item-81rtr98o.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BMtveI6F.js → createContext-D34ixq8t.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CHDIEOeN.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DbD6WHW2.js → hasIn-D4bzqTrZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoO4WEJB.js → index-9qoVpPt6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJhREOlG.js → index-B0QArPQt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnFLzejT.js → index-B8mkLM4x.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bbc2JeQG.js → index-BIP62a6r.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFXKbOek.js → index-BP-zkXK8.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-cGlCDW.js → index-BS3M5H9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-AaIKG60c.js → index-BXd2_LmH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEXa-4zd.js → index-BlxEphl7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZl-UXB6.js → index-BqIhLAbA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOM-VFlv.js → index-BtGxuQrO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcVszn2b.js → index-BvD7b2IK.js} +1 -1
- package/src/assets/web-panel/assets/{index-C21pdBqs.js → index-BvL_3J_n.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJvxFyIz.js → index-COe_cOLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-ALvoNTRF.js → index-CP5alL4t.js} +1 -1
- package/src/assets/web-panel/assets/index-CY1NURWZ.js +1 -0
- package/src/assets/web-panel/assets/{index-Dm0byjm1.js → index-CbhE3j5j.js} +1 -1
- package/src/assets/web-panel/assets/{index-WQUO2vvK.js → index-Cd3KuNK5.js} +1 -1
- package/src/assets/web-panel/assets/{index-bdaJwTXJ.js → index-CoVgZw_b.js} +1 -1
- package/src/assets/web-panel/assets/{index-COHHQ9cU.js → index-CuS-UPoj.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7LHNw_N.js → index-D0Ih7Hwn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cod97Urs.js → index-D3zCCZRS.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cwbqh0KZ.js → index-D6GfvEQG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKAB6-6V.js → index-DBFSo1NF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEwjBA9q.js → index-DFHa1HIg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DndNnYc0.js → index-DFyWKOBD.js} +1 -1
- package/src/assets/web-panel/assets/{index-3oBsXZmF.js → index-DMgnRwrK.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_eUKGYP.js → index-DUQLXLQM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUmLMFsy.js → index-D_2VYPr1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BPpS-lGb.js → index-DakfFZ-k.js} +1 -1
- package/src/assets/web-panel/assets/{index-ep6JchNG.js → index-Ddk0e_Pi.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7cV0tu0.js → index-DkHqMnn3.js} +1 -1
- package/src/assets/web-panel/assets/{index-jG6h22Qg.js → index-Dmo3dFHb.js} +1 -1
- package/src/assets/web-panel/assets/index-DokUYqpq.js +1 -0
- package/src/assets/web-panel/assets/{index-C1PfeI88.js → index-DvfCEJG-.js} +1 -1
- package/src/assets/web-panel/assets/{index-ntVQqSML.js → index-E1OJRXs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWgfipcC.js → index-F76w1NiL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiRQUoyE.js → index-ZRJRItm0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFRLmCR3.js → index-fI5sXMLg.js} +1 -1
- package/src/assets/web-panel/assets/{index-D67kIagl.js → index-tKiC8T-4.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D5UoBRhN.js → initDefaultProps-ByyvflIR.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DltOw0CR.js → motion-B3FQm2By.js} +1 -1
- package/src/assets/web-panel/assets/{move-_oPkk5zj.js → move-BSfns6Ef.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-EES8ROCS.js → mtc-parser-CTG1Ieri.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B-_39x_M.js → omit-DObM_2j6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-l6D0yJHz.js → pickAttrs-DOfelQ1t.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DIeUK31L.js → placementArrow-CHZILds_.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-dG4EzUQo.js → responsiveObserve-REbucKSx.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DWFzYGdH.js → slide-C6EZzD7o.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CECdTA5H.js → statusUtils-BxkWS-g3.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-D6kP-mMK.js → styleChecker-Chklyoq6.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BWfna_rd.js → useFlexGapSupport-CRVwKrrI.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Bb-j6rzo.js → useFs-DV24ik_J.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D5OIsYM4.js → usePersonalDataHub-C7vIo4Pg.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DNpwzFTM.js → vnode-By-v5GlF.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-vNLpFQBW.js → zoom-B1w9Am3r.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +15 -1
- package/src/commands/agent.js +72 -6
- package/src/commands/background-session.js +46 -2
- package/src/commands/mcp.js +46 -0
- package/src/commands/session.js +70 -0
- package/src/data/changelog.json +12 -2
- package/src/gateways/ws/background-agent-protocol.js +88 -14
- package/src/harness/jsonl-session-store.js +70 -1
- package/src/harness/mcp-client.js +50 -0
- package/src/lib/agent-authority.js +251 -0
- package/src/lib/agent-sandbox.js +68 -0
- package/src/lib/agents.js +12 -4
- package/src/lib/api-key-helper.js +62 -0
- package/src/lib/background-agent-phase.js +100 -0
- package/src/lib/background-agent-supervisor.js +320 -8
- package/src/lib/backpressure-policy.js +105 -0
- package/src/lib/capability-negotiation.js +212 -0
- package/src/lib/credential-guard.js +11 -0
- package/src/lib/credential-proxy.js +182 -0
- package/src/lib/dependency-install-policy.js +130 -0
- package/src/lib/event-seq-replay.js +167 -0
- package/src/lib/exit-codes.cjs +77 -0
- package/src/lib/goal-condition-engine.js +369 -0
- package/src/lib/headless-manifest.js +188 -0
- package/src/lib/hook-runner.cjs +70 -4
- package/src/lib/ide-context-redaction.js +130 -0
- package/src/lib/ide-context.js +128 -13
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/llm-config-defaults.js +24 -8
- package/src/lib/project-instructions.js +98 -1
- package/src/lib/project-mcp-trust.js +87 -0
- package/src/lib/remote-path-mapping.js +229 -0
- package/src/lib/schedule-planner.js +136 -0
- package/src/lib/sensitive-file-guard.js +51 -0
- package/src/lib/sub-agent-context.js +7 -3
- package/src/repl/bg-dashboard.js +13 -12
- package/src/runtime/agent-core.js +113 -10
- package/src/runtime/coding-agent-contract-shared.cjs +19 -2
- package/src/runtime/headless-runner.js +66 -7
- package/src/runtime/headless-stream.js +224 -12
- package/src/runtime/mcp-config.js +32 -1
- package/src/runtime/system-prompt.js +3 -0
- package/src/workers/background-agent-worker.js +37 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DexLlXfN.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +0 -1
- package/src/assets/web-panel/assets/Projects-DvH_P2Uq.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +0 -1
- package/src/assets/web-panel/assets/index-BhXiaiev.js +0 -1
- package/src/assets/web-panel/assets/index-WpaYaE3D.js +0 -1
package/src/repl/bg-dashboard.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Background-agent dashboard — the interactive agent view behind
|
|
3
3
|
* `cc daemon view` (no id). Claude-Code `claude agents` parity: one live panel
|
|
4
|
-
* over every background session with grouping (Needs input / Working /
|
|
4
|
+
* over every background session with grouping (Needs input / Working / Idle /
|
|
5
5
|
* Completed / Failed / Stopped), peek + reply, attach hand-off, stop, rename,
|
|
6
|
-
* pin, filter, and new-task dispatch.
|
|
6
|
+
* pin, filter, and new-task dispatch. Phase→group classification is the shared
|
|
7
|
+
* `background-agent-phase.js` contract, so `idle` (parked, nothing blocking)
|
|
8
|
+
* is kept distinct from a genuine `needs-input` (a human decision blocks it).
|
|
7
9
|
*
|
|
8
10
|
* Design:
|
|
9
11
|
* - Pure model/render layer (`groupKey`, `buildDashboardModel`,
|
|
@@ -17,10 +19,12 @@
|
|
|
17
19
|
*/
|
|
18
20
|
|
|
19
21
|
import chalk from "chalk";
|
|
22
|
+
import { phaseGroupKey } from "../lib/background-agent-phase.js";
|
|
20
23
|
|
|
21
24
|
export const GROUP_ORDER = [
|
|
22
25
|
"needs-input",
|
|
23
26
|
"working",
|
|
27
|
+
"idle",
|
|
24
28
|
"completed",
|
|
25
29
|
"failed",
|
|
26
30
|
"stopped",
|
|
@@ -29,24 +33,21 @@ export const GROUP_ORDER = [
|
|
|
29
33
|
export const GROUP_TITLES = {
|
|
30
34
|
"needs-input": "Needs input",
|
|
31
35
|
working: "Working",
|
|
36
|
+
idle: "Idle",
|
|
32
37
|
completed: "Completed",
|
|
33
38
|
failed: "Failed",
|
|
34
39
|
stopped: "Stopped",
|
|
35
40
|
};
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
|
-
* Group a session
|
|
39
|
-
*
|
|
40
|
-
*
|
|
43
|
+
* Group a session into a dashboard bucket. Delegates to the shared
|
|
44
|
+
* `background-agent-phase.js` contract so the worker/supervisor and this panel
|
|
45
|
+
* agree on phase semantics: running + pending approval / blocking phase →
|
|
46
|
+
* "needs-input"; running + idle (parked, nothing blocking) → "idle"; running +
|
|
47
|
+
* working/turn/starting → "working"; lost/unknown → "failed".
|
|
41
48
|
*/
|
|
42
49
|
export function groupKey(session) {
|
|
43
|
-
|
|
44
|
-
if (status === "running") {
|
|
45
|
-
return session.phase === "idle" ? "needs-input" : "working";
|
|
46
|
-
}
|
|
47
|
-
if (status === "completed") return "completed";
|
|
48
|
-
if (status === "stopped") return "stopped";
|
|
49
|
-
return "failed"; // failed | lost | unknown
|
|
50
|
+
return phaseGroupKey(session);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
function formatAge(ms) {
|
|
@@ -25,6 +25,7 @@ import sharedSettingsHooks from "../lib/settings-hooks.cjs";
|
|
|
25
25
|
import sharedHookRunner from "../lib/hook-runner.cjs";
|
|
26
26
|
import sharedHookEvents from "../lib/settings-hook-events.cjs";
|
|
27
27
|
import { mergeProviderOptions } from "../lib/provider-options.js";
|
|
28
|
+
import { applyCredentialProxy } from "../lib/credential-proxy.js";
|
|
28
29
|
import { getPlanModeManager } from "../lib/plan-mode.js";
|
|
29
30
|
import { CLISkillLoader } from "../lib/skill-loader.js";
|
|
30
31
|
import { executeHooks, HookEvents } from "../lib/hook-manager.js";
|
|
@@ -673,8 +674,8 @@ Key behaviors:
|
|
|
673
674
|
When the user's problem involves data processing, calculations, file operations, text parsing, API calls, web scraping, or any task that can be solved programmatically:
|
|
674
675
|
- Proactively write and execute code using run_code tool
|
|
675
676
|
- Choose the best language: Python for data/math/scraping, Node.js for JSON/API, Bash for system tasks
|
|
676
|
-
- Missing Python packages are auto-installed
|
|
677
|
-
- Scripts
|
|
677
|
+
- Missing Python packages are NOT auto-installed by default; the tool result tells you (and the user) how to opt in (settings runCode.autoInstall)
|
|
678
|
+
- Scripts run from a temp file by default; pass persist:true to keep one in .chainlesschain/agent-scripts/ for reference
|
|
678
679
|
- Show the results and explain them clearly
|
|
679
680
|
- If the first attempt fails, debug and retry with a different approach
|
|
680
681
|
|
|
@@ -1263,6 +1264,8 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1263
1264
|
// Sensitive-file write guard (Claude-Code 2.1.160 parity): shell startup
|
|
1264
1265
|
// files / PowerShell profiles / git+husky hooks execute code on the user's
|
|
1265
1266
|
// next shell or commit — even otherwise-permitted edit flows confirm first.
|
|
1267
|
+
// Auto-exec configs (.vscode/tasks.json, .mcp.json, .idea run configs, …)
|
|
1268
|
+
// ride the same gate via autoExecConfigReason.
|
|
1266
1269
|
// An explicit settings `allow` rule is the only bypass (exact user
|
|
1267
1270
|
// pre-authorization); headless without a confirmer fails closed.
|
|
1268
1271
|
if (
|
|
@@ -1272,9 +1275,10 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1272
1275
|
settingsVerdict.decision !== "allow" &&
|
|
1273
1276
|
args?.path
|
|
1274
1277
|
) {
|
|
1275
|
-
const { sensitiveFileReason } =
|
|
1278
|
+
const { sensitiveFileReason, autoExecConfigReason } =
|
|
1276
1279
|
await import("../lib/sensitive-file-guard.js");
|
|
1277
|
-
const sensReason =
|
|
1280
|
+
const sensReason =
|
|
1281
|
+
sensitiveFileReason(args.path) || autoExecConfigReason(args.path);
|
|
1278
1282
|
if (sensReason) {
|
|
1279
1283
|
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1280
1284
|
tool: name,
|
|
@@ -2537,7 +2541,10 @@ async function executeToolInner(
|
|
|
2537
2541
|
// Same agent-identity env as the foreground path: CLAUDECODE marks
|
|
2538
2542
|
// "running under the agent"; the session id correlates work to the
|
|
2539
2543
|
// run (CC_SESSION_ID + CLAUDE_CODE_SESSION_ID for Claude-Code parity).
|
|
2540
|
-
|
|
2544
|
+
// Credential proxy (opt-in, CC_CREDENTIAL_PROXY): keeps the agent's
|
|
2545
|
+
// real long-lived secrets out of the spawned command's env — a
|
|
2546
|
+
// no-op (same object) when disabled. See credential-proxy.js.
|
|
2547
|
+
env: applyCredentialProxy({
|
|
2541
2548
|
...process.env,
|
|
2542
2549
|
CLAUDECODE: "1",
|
|
2543
2550
|
...(sessionId
|
|
@@ -2546,7 +2553,7 @@ async function executeToolInner(
|
|
|
2546
2553
|
CLAUDE_CODE_SESSION_ID: String(sessionId),
|
|
2547
2554
|
}
|
|
2548
2555
|
: {}),
|
|
2549
|
-
},
|
|
2556
|
+
}).env,
|
|
2550
2557
|
// POSIX: own process group so check_shell{kill}/teardown can signal
|
|
2551
2558
|
// the whole tree (shell + its grandchild command). No-op on Windows
|
|
2552
2559
|
// where the tree is killed via taskkill /T instead.
|
|
@@ -2712,7 +2719,10 @@ async function executeToolInner(
|
|
|
2712
2719
|
// parity): CLAUDECODE=1 marks "running under the agent"; CC_SESSION_ID
|
|
2713
2720
|
// + its CLAUDE_CODE_SESSION_ID mirror let scripts/hooks correlate work
|
|
2714
2721
|
// to the agent session (the mirror is what CC-targeting tools expect).
|
|
2715
|
-
|
|
2722
|
+
// Credential proxy (opt-in, CC_CREDENTIAL_PROXY): keeps the agent's
|
|
2723
|
+
// real long-lived secrets out of the shell's env — a no-op (same
|
|
2724
|
+
// object) when disabled. See credential-proxy.js.
|
|
2725
|
+
env: applyCredentialProxy({
|
|
2716
2726
|
...process.env,
|
|
2717
2727
|
CLAUDECODE: "1",
|
|
2718
2728
|
...(sessionId
|
|
@@ -2721,7 +2731,7 @@ async function executeToolInner(
|
|
|
2721
2731
|
CLAUDE_CODE_SESSION_ID: String(sessionId),
|
|
2722
2732
|
}
|
|
2723
2733
|
: {}),
|
|
2724
|
-
},
|
|
2734
|
+
}).env,
|
|
2725
2735
|
};
|
|
2726
2736
|
let output;
|
|
2727
2737
|
if (shellInv.useDefaultShell) {
|
|
@@ -3908,7 +3918,10 @@ async function _executeRunCode(args, cwd) {
|
|
|
3908
3918
|
const lang = args.language;
|
|
3909
3919
|
const code = args.code;
|
|
3910
3920
|
const timeoutSec = Math.min(Math.max(args.timeout || 60, 1), 300);
|
|
3911
|
-
|
|
3921
|
+
// gap-analysis 2026-07-11 P0 "依赖安装与凭据": agent-generated scripts
|
|
3922
|
+
// default to the OS temp dir; only an explicit persist:true lands them in
|
|
3923
|
+
// the project (.chainlesschain/agent-scripts/).
|
|
3924
|
+
const persist = args.persist === true; // default false (temp dir)
|
|
3912
3925
|
|
|
3913
3926
|
const extMap = { python: ".py", node: ".js", bash: ".sh" };
|
|
3914
3927
|
const ext = extMap[lang];
|
|
@@ -3978,6 +3991,51 @@ async function _executeRunCode(args, cwd) {
|
|
|
3978
3991
|
};
|
|
3979
3992
|
}
|
|
3980
3993
|
|
|
3994
|
+
// Auto-install is OPT-IN (settings runCode.autoInstall / env
|
|
3995
|
+
// CC_RUN_CODE_AUTO_INSTALL=1) with an optional package allowlist;
|
|
3996
|
+
// every attempt — including refused ones — is audited.
|
|
3997
|
+
const {
|
|
3998
|
+
resolveAutoInstallPolicy,
|
|
3999
|
+
isPackageAllowed,
|
|
4000
|
+
autoInstallDisabledHint,
|
|
4001
|
+
recordInstallAudit,
|
|
4002
|
+
} = await import("../lib/dependency-install-policy.js");
|
|
4003
|
+
const installPolicy = resolveAutoInstallPolicy({ cwd });
|
|
4004
|
+
if (!installPolicy.enabled) {
|
|
4005
|
+
recordInstallAudit({
|
|
4006
|
+
package: packageName,
|
|
4007
|
+
interpreter,
|
|
4008
|
+
cwd,
|
|
4009
|
+
outcome: "disabled",
|
|
4010
|
+
});
|
|
4011
|
+
return {
|
|
4012
|
+
error: (stderr || message).substring(0, 5000),
|
|
4013
|
+
stderr: stderr.substring(0, 5000),
|
|
4014
|
+
exitCode: err.status,
|
|
4015
|
+
language: lang,
|
|
4016
|
+
...classified,
|
|
4017
|
+
hint: autoInstallDisabledHint(packageName),
|
|
4018
|
+
scriptPath: persist ? scriptPath : undefined,
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
if (!isPackageAllowed(packageName, installPolicy.allowlist)) {
|
|
4022
|
+
recordInstallAudit({
|
|
4023
|
+
package: packageName,
|
|
4024
|
+
interpreter,
|
|
4025
|
+
cwd,
|
|
4026
|
+
outcome: "blocked",
|
|
4027
|
+
});
|
|
4028
|
+
return {
|
|
4029
|
+
error: (stderr || message).substring(0, 5000),
|
|
4030
|
+
stderr: stderr.substring(0, 5000),
|
|
4031
|
+
exitCode: err.status,
|
|
4032
|
+
language: lang,
|
|
4033
|
+
...classified,
|
|
4034
|
+
hint: `Package "${packageName}" is not in runCode.installAllowlist — install it manually or add it to the allowlist.`,
|
|
4035
|
+
scriptPath: persist ? scriptPath : undefined,
|
|
4036
|
+
};
|
|
4037
|
+
}
|
|
4038
|
+
|
|
3981
4039
|
// Attempt pip install
|
|
3982
4040
|
try {
|
|
3983
4041
|
execSync(`${interpreter} -m pip install ${packageName}`, {
|
|
@@ -3986,6 +4044,12 @@ async function _executeRunCode(args, cwd) {
|
|
|
3986
4044
|
maxBuffer: 2 * 1024 * 1024,
|
|
3987
4045
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3988
4046
|
});
|
|
4047
|
+
recordInstallAudit({
|
|
4048
|
+
package: packageName,
|
|
4049
|
+
interpreter,
|
|
4050
|
+
cwd,
|
|
4051
|
+
outcome: "installed",
|
|
4052
|
+
});
|
|
3989
4053
|
|
|
3990
4054
|
// Retry execution
|
|
3991
4055
|
const retryStart = Date.now();
|
|
@@ -4006,6 +4070,13 @@ async function _executeRunCode(args, cwd) {
|
|
|
4006
4070
|
scriptPath: persist ? scriptPath : undefined,
|
|
4007
4071
|
};
|
|
4008
4072
|
} catch (pipErr) {
|
|
4073
|
+
recordInstallAudit({
|
|
4074
|
+
package: packageName,
|
|
4075
|
+
interpreter,
|
|
4076
|
+
cwd,
|
|
4077
|
+
outcome: "failed",
|
|
4078
|
+
detail: (pipErr.stderr || pipErr.message || "").substring(0, 200),
|
|
4079
|
+
});
|
|
4009
4080
|
return {
|
|
4010
4081
|
error: (stderr || message).substring(0, 5000),
|
|
4011
4082
|
stderr: stderr.substring(0, 5000),
|
|
@@ -4233,6 +4304,17 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4233
4304
|
tools: explicitTools,
|
|
4234
4305
|
profile: profileName,
|
|
4235
4306
|
} = args;
|
|
4307
|
+
// Extended sub-agent contract (gap 2026-07-11 P1): per-spawn deny-list,
|
|
4308
|
+
// iteration cap and worktree isolation — spawn args win over the agent
|
|
4309
|
+
// file's frontmatter defaults.
|
|
4310
|
+
let disallowedTools = Array.isArray(args.disallowedTools)
|
|
4311
|
+
? args.disallowedTools.filter(Boolean)
|
|
4312
|
+
: null;
|
|
4313
|
+
let subMaxTurns =
|
|
4314
|
+
Number.isFinite(Number(args.maxTurns)) && Number(args.maxTurns) > 0
|
|
4315
|
+
? Math.floor(Number(args.maxTurns))
|
|
4316
|
+
: null;
|
|
4317
|
+
let subIsolation = args.isolation === "worktree" ? "worktree" : null;
|
|
4236
4318
|
|
|
4237
4319
|
// Named subagent delegation (cc agents / .chainlesschain|.claude/agents/*.md):
|
|
4238
4320
|
// load the agent's persona (its body = system prompt) + tool allow-list.
|
|
@@ -4250,6 +4332,13 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4250
4332
|
}
|
|
4251
4333
|
role = role || md.name;
|
|
4252
4334
|
if (!explicitTools && Array.isArray(md.tools)) explicitTools = md.tools;
|
|
4335
|
+
if (!disallowedTools && Array.isArray(md.disallowedTools)) {
|
|
4336
|
+
disallowedTools = md.disallowedTools;
|
|
4337
|
+
}
|
|
4338
|
+
if (!subMaxTurns && md.maxTurns) subMaxTurns = md.maxTurns;
|
|
4339
|
+
if (!subIsolation && md.isolation === "worktree") {
|
|
4340
|
+
subIsolation = "worktree";
|
|
4341
|
+
}
|
|
4253
4342
|
if (md.model) mdModel = md.model;
|
|
4254
4343
|
if (md.systemPrompt) {
|
|
4255
4344
|
mdProfile = { name: md.name, systemPrompt: md.systemPrompt };
|
|
@@ -4289,9 +4378,19 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4289
4378
|
// profile.systemPrompt seam) when no declarative profile was requested.
|
|
4290
4379
|
if (!profile && mdProfile) profile = mdProfile;
|
|
4291
4380
|
|
|
4292
|
-
|
|
4381
|
+
let allowedTools = Array.isArray(explicitTools)
|
|
4293
4382
|
? explicitTools
|
|
4294
4383
|
: profile?.toolAllowlist || null;
|
|
4384
|
+
// Deny-list: subtract from the resolved allow-list; with no allow-list
|
|
4385
|
+
// ("all tools"), subtract from the full built-in contract set. spawn itself
|
|
4386
|
+
// is always denied downstream by depth/breadth caps, so no special-casing.
|
|
4387
|
+
if (Array.isArray(disallowedTools) && disallowedTools.length > 0) {
|
|
4388
|
+
const deny = new Set(disallowedTools.map((t) => String(t).trim()));
|
|
4389
|
+
const base = Array.isArray(allowedTools)
|
|
4390
|
+
? allowedTools
|
|
4391
|
+
: listCodingAgentToolNames();
|
|
4392
|
+
allowedTools = base.filter((t) => !deny.has(t));
|
|
4393
|
+
}
|
|
4295
4394
|
|
|
4296
4395
|
// Auto-condense parent context if caller didn't provide explicit context
|
|
4297
4396
|
let resolvedContext = inheritedContext || null;
|
|
@@ -4399,6 +4498,10 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4399
4498
|
// single total-sub-agent pool (breadth cap spans the whole tree).
|
|
4400
4499
|
subAgentBudget: ctx.subAgentBudget || null,
|
|
4401
4500
|
onUsage,
|
|
4501
|
+
// Extended contract (gap 2026-07-11): per-agent iteration cap + opt-in
|
|
4502
|
+
// worktree isolation. undefined keeps the profile/flag defaults intact.
|
|
4503
|
+
...(subMaxTurns ? { maxIterations: subMaxTurns } : {}),
|
|
4504
|
+
...(subIsolation === "worktree" ? { useWorktree: true } : {}),
|
|
4402
4505
|
});
|
|
4403
4506
|
subCtxRef = subCtx;
|
|
4404
4507
|
|
|
@@ -521,7 +521,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
521
521
|
kind: "code",
|
|
522
522
|
tier: "extension",
|
|
523
523
|
description:
|
|
524
|
-
"Write and execute code in Python, Node.js, or Bash. Use this when the user needs data processing, calculations, file batch operations, API calls, or any task best solved with a script. Scripts
|
|
524
|
+
"Write and execute code in Python, Node.js, or Bash. Use this when the user needs data processing, calculations, file batch operations, API calls, or any task best solved with a script. Scripts run from a temp file unless persist:true. Missing Python packages are NOT auto-installed unless the user opted in (settings runCode.autoInstall).",
|
|
525
525
|
inputSchema: {
|
|
526
526
|
type: "object",
|
|
527
527
|
properties: {
|
|
@@ -538,7 +538,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
538
538
|
persist: {
|
|
539
539
|
type: "boolean",
|
|
540
540
|
description:
|
|
541
|
-
"If true
|
|
541
|
+
"If true, save the script in .chainlesschain/agent-scripts/ for reference. Default false: run from a temp file outside the project.",
|
|
542
542
|
},
|
|
543
543
|
},
|
|
544
544
|
required: ["language", "code"],
|
|
@@ -599,6 +599,23 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
599
599
|
description:
|
|
600
600
|
"Run the sub-agent in the BACKGROUND: the call returns immediately with a running handle and you continue working; the sub-agent's result is delivered to you automatically in a later turn (the run waits for stragglers before finishing). Use for independent subtasks you don't need before your next step.",
|
|
601
601
|
},
|
|
602
|
+
disallowedTools: {
|
|
603
|
+
type: "array",
|
|
604
|
+
items: { type: "string" },
|
|
605
|
+
description:
|
|
606
|
+
"Optional tool DENY-list for the sub-agent: these are removed from whatever tool set it would otherwise get (explicit `tools`, agent-file allowlist, or all).",
|
|
607
|
+
},
|
|
608
|
+
maxTurns: {
|
|
609
|
+
type: "number",
|
|
610
|
+
description:
|
|
611
|
+
"Optional iteration cap for the sub-agent's own loop (positive integer; default 8 or the profile's cap).",
|
|
612
|
+
},
|
|
613
|
+
isolation: {
|
|
614
|
+
type: "string",
|
|
615
|
+
enum: ["worktree"],
|
|
616
|
+
description:
|
|
617
|
+
"Optional isolation mode: \"worktree\" runs the sub-agent in a fresh git worktree so its file edits land on an isolated branch (diff/merge summary comes back with the result).",
|
|
618
|
+
},
|
|
602
619
|
},
|
|
603
620
|
required: ["task"],
|
|
604
621
|
},
|
|
@@ -54,6 +54,18 @@ import { composeSystemPrompt } from "./system-prompt.js";
|
|
|
54
54
|
import { buildUserContent } from "../lib/image-input.js";
|
|
55
55
|
import { mergeConsecutiveMessages } from "./message-roles.js";
|
|
56
56
|
import { isHeadlessConfigCommand } from "../lib/headless-config-command.js";
|
|
57
|
+
import {
|
|
58
|
+
STREAM_PROTOCOL_VERSION,
|
|
59
|
+
computePolicyDigest,
|
|
60
|
+
computeToolsHash,
|
|
61
|
+
buildLoadedSources,
|
|
62
|
+
} from "../lib/headless-manifest.js";
|
|
63
|
+
import {
|
|
64
|
+
HEADLESS_EXIT_CODES,
|
|
65
|
+
classifyLoopError,
|
|
66
|
+
exitCodeForEndReason,
|
|
67
|
+
} from "../lib/exit-codes.cjs";
|
|
68
|
+
import { isolationLevel } from "../lib/agent-sandbox.js";
|
|
57
69
|
import { withQuietStdout } from "./quiet-stdout.js";
|
|
58
70
|
import { CostBudget } from "../lib/cost-budget.js";
|
|
59
71
|
import {
|
|
@@ -200,13 +212,18 @@ export function parseToolList(value) {
|
|
|
200
212
|
* Persistence is intentionally OFF unless a resume/continue/persist intent is
|
|
201
213
|
* present, so a plain one-shot `cc agent -p "..."` writes nothing to disk.
|
|
202
214
|
*
|
|
203
|
-
*
|
|
215
|
+
* `--ephemeral` forces persistence OFF regardless of the above: a resume id
|
|
216
|
+
* still REPLAYS prior history into context, but nothing new is written — the
|
|
217
|
+
* deterministic-CI shape ("read context, leave no trace").
|
|
218
|
+
*
|
|
219
|
+
* @param {object} options { resume, continueSession, sessionId, persistSession, ephemeral }
|
|
204
220
|
* @param {object} store { getLastSessionId } (injection seam)
|
|
205
221
|
* @param {string} fallbackId used when nothing is being resumed
|
|
206
222
|
* @returns {{ sessionId:string, resumeId:string|null, persist:boolean, wantLatest:boolean }}
|
|
207
223
|
*/
|
|
208
224
|
export function resolveHeadlessSession(options = {}, store = {}, fallbackId) {
|
|
209
|
-
const { resume, continueSession, sessionId, persistSession } =
|
|
225
|
+
const { resume, continueSession, sessionId, persistSession, ephemeral } =
|
|
226
|
+
options;
|
|
210
227
|
const wantLatest = continueSession === true || resume === true;
|
|
211
228
|
let resumeId = null;
|
|
212
229
|
if (wantLatest) {
|
|
@@ -217,7 +234,10 @@ export function resolveHeadlessSession(options = {}, store = {}, fallbackId) {
|
|
|
217
234
|
} else if (typeof resume === "string" && resume.trim()) {
|
|
218
235
|
resumeId = resume.trim();
|
|
219
236
|
}
|
|
220
|
-
const persist =
|
|
237
|
+
const persist =
|
|
238
|
+
ephemeral === true
|
|
239
|
+
? false
|
|
240
|
+
: persistSession === true || resumeId != null || wantLatest;
|
|
221
241
|
const id = resumeId || sessionId || fallbackId;
|
|
222
242
|
return { sessionId: id, resumeId, persist, wantLatest };
|
|
223
243
|
}
|
|
@@ -900,7 +920,12 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
900
920
|
} catch (err) {
|
|
901
921
|
writeErr(`Error: ${err.message}\n`);
|
|
902
922
|
emitHeadlessError(err.message);
|
|
903
|
-
|
|
923
|
+
// Bad --mcp-config / MCP wiring is a CONFIG error, not a run failure.
|
|
924
|
+
return {
|
|
925
|
+
exitCode: HEADLESS_EXIT_CODES.CONFIG_ERROR,
|
|
926
|
+
result: err.message,
|
|
927
|
+
isError: true,
|
|
928
|
+
};
|
|
904
929
|
}
|
|
905
930
|
}
|
|
906
931
|
|
|
@@ -943,7 +968,12 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
943
968
|
writeErr(`Error: ${err.message}\n`);
|
|
944
969
|
if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
|
|
945
970
|
emitHeadlessError(err.message);
|
|
946
|
-
|
|
971
|
+
// A bad --permission-prompt-tool reference is a CONFIG error.
|
|
972
|
+
return {
|
|
973
|
+
exitCode: HEADLESS_EXIT_CODES.CONFIG_ERROR,
|
|
974
|
+
result: err.message,
|
|
975
|
+
isError: true,
|
|
976
|
+
};
|
|
947
977
|
}
|
|
948
978
|
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
949
979
|
approvalGate.setConfirmer(
|
|
@@ -1175,11 +1205,32 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1175
1205
|
emitStream({
|
|
1176
1206
|
type: "system",
|
|
1177
1207
|
subtype: "init",
|
|
1208
|
+
// Deterministic-headless manifest (gap-analysis 2026-07-11): protocol
|
|
1209
|
+
// version + persistence + live sources + policy/tool digests so CI can
|
|
1210
|
+
// assert the run shape. Mirrors agent-sdk PROTOCOL_VERSION.
|
|
1211
|
+
protocol_version: STREAM_PROTOCOL_VERSION,
|
|
1178
1212
|
session_id: sessionId,
|
|
1213
|
+
session_persistence: persist,
|
|
1179
1214
|
model,
|
|
1180
1215
|
provider,
|
|
1181
1216
|
permission_mode: options.permissionMode || "default",
|
|
1182
1217
|
tools: enabledToolNames,
|
|
1218
|
+
tools_hash: computeToolsHash(enabledToolNames),
|
|
1219
|
+
policy_digest: computePolicyDigest({
|
|
1220
|
+
permissionMode: options.permissionMode,
|
|
1221
|
+
allowedTools: options.allowedTools,
|
|
1222
|
+
disallowedTools: options.disallowedTools,
|
|
1223
|
+
permissionRules,
|
|
1224
|
+
}),
|
|
1225
|
+
loaded_sources: buildLoadedSources({
|
|
1226
|
+
permissionRules,
|
|
1227
|
+
settingsHooks,
|
|
1228
|
+
mcp: Boolean(mcp),
|
|
1229
|
+
enabledToolNames,
|
|
1230
|
+
}),
|
|
1231
|
+
// True isolation level for tool subprocesses: os-sandbox (bwrap) /
|
|
1232
|
+
// container (docker) / policy-only (no sandbox — rules are pre-execution).
|
|
1233
|
+
isolation_level: isolationLevel(options.sandbox),
|
|
1183
1234
|
max_turns: budget.limit,
|
|
1184
1235
|
resumed_from: resumeId,
|
|
1185
1236
|
history_messages: history.length,
|
|
@@ -1471,7 +1522,9 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1471
1522
|
} else {
|
|
1472
1523
|
writeErr(`Error: ${message}\n`);
|
|
1473
1524
|
}
|
|
1474
|
-
|
|
1525
|
+
// Provider/transport failures get their own exit code (5) so CI can tell
|
|
1526
|
+
// "the model call failed" from "the run itself errored" (1).
|
|
1527
|
+
return { exitCode: classifyLoopError(err), result: message, isError: true };
|
|
1475
1528
|
} finally {
|
|
1476
1529
|
// Drop the signal handlers first — a normal return must not leave a
|
|
1477
1530
|
// process-wide SIGINT/SIGTERM listener behind (a later Ctrl-C would wrongly
|
|
@@ -1739,7 +1792,13 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1739
1792
|
}
|
|
1740
1793
|
}
|
|
1741
1794
|
|
|
1742
|
-
|
|
1795
|
+
// Exit-code taxonomy: max-turns → 3, cost cap → 4 (both still non-zero, so
|
|
1796
|
+
// "any failure" checks keep working; scripts can now tell exhaustion apart).
|
|
1797
|
+
return {
|
|
1798
|
+
exitCode: exitCodeForEndReason(endReason, isError),
|
|
1799
|
+
result: finalText,
|
|
1800
|
+
isError,
|
|
1801
|
+
};
|
|
1743
1802
|
}
|
|
1744
1803
|
|
|
1745
1804
|
function buildResultEnvelope({
|