chainlesschain 0.162.166 → 0.162.168
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/assets/{AIOps-LbDx7jL6.js → AIOps-CDzzuWZV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DnurtK34.js → ActionButton-Dy-8MmQi.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DXSsV1am.js → Analytics-BtJ_VWkx.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-dqRpzNuD.js → AppLayout-DkjiI4VS.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BwdmYepK.js → Artifacts-h8PyDO86.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-oSX0kOUG.js → Audit-DiDV0C6l.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-C2KxJahT.js → BackgroundAgents-DTw_aOaf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B4TkxWkC.js → Backup-CihFuUO9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CX5-KxeU.js → BaseInput-CqP2QNoR.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-O_HzD-PL.js → Chat-tm-ygX-p.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Br8saHQA.js → ChatBubbleRenderer-BVKEhj_y.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-ChepDpC1.js → Checkbox-BFMyRN3Q.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D9z8kc7q.js → Codegen-B1gTeoAS.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B-H5eoNw.js → Col-1GP8MvKL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Ccyp_Kk5.js → Community-BLY938F6.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BNvBznp_.js → Compact-DVt_p36I.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-D1FjRd8n.js → Compliance-DxqEBXVG.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CV9B9u-8.js → Cowork-CyWrM-T8.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BowJ4VIx.js → Cron-Domu6aI9.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BJc6jzRF.js → Crosschain-C8LKpjHJ.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BEp8NV6D.js → DID-XBy15RZ5.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Dls0B3YB.js → Dashboard-DDAyPD-V.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DQ7zXVtD.js → Dropdown-BHV0MZ13.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-B9q79tOl.js → EmailListRenderer-DmFGW4PX.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CD8Ie-88.js → FamilyGuardDashboard-CqYdbKvd.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-5o7XU5Vf.js → Federation-YP5-Puv5.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DeKbMvOs.js → FormItemContext-BOmcIcTe.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CZiQvz_z.js → GenericCardRenderer-CvTZdoc4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CTvFxVV8.js → Git-Q2oxua0L.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DwzFIjHt.js → Governance-D-WpyWEU.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CJBk59c-.js → Inference-NUtsYHQo.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DfsaXN2z.js → KnowledgeGraph-BHQLa8fr.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DVRYf18S.js → Logs-6WsR5Q1G.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DuWoDwMx.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BuIwyE4t.js → Marketplace-CigohRRW.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D3U0o78E.js → McpTools-jcp6jVLf.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-QYVmyb3b.js → Memory-B00NU1ph.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BFgrj6eZ.js → MobileBridge-Cs_p3PzU.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BFs2WljZ.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-BZQu8TcH.js → Mtc-CSEflwzw.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BnFfEkLo.js → MtcAudit-dxSiEZ96.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-iUnNS9Cm.js → Multisig-CDAFEAyq.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DNNz1y9Y.js → NLProgramming-HoFpZNiB.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CZezNYRU.js → Notes-tAoQvVcE.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DBvrplIR.js → NotificationSettings-Czo2M9F4.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CTDtee49.js → OrderTableRenderer-CM1kNTp6.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CCOUJX1R.js → Organization-Cudr0VOC.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DcZghdk0.js → Overflow-BSXeDKiN.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-jmddWX9q.js → P2P-Cqv_g-F9.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-wfjMcczl.js → PdhVaultBrowser-7rjprPh8.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DU1GJjca.js → Permissions-97pIDQKE.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BzTMzDF9.js → PersonalDataHub-bparK9eQ.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DPmjlpVc.js → Pipeline-CJgerM09.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B6HRLpfK.js → Privacy-JqFS3PN7.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Cyy86AsN.js → ProjectInit-DMITd-2c.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Bl_WQxJ5.js → ProjectSettings-1UkdJ8Ii.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Co9yKThA.js → Projects-CYZqegqw.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DLa4NlIs.js → Providers-ChfXz3U0.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BvzM7q5f.js → QrScannerModal-Rzkka-mf.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BN8yyyUj.js → QuickAsk-DEz9HaON.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-QsVN4w0i.js → Recommend-EFGP8AVu.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-tkDXw-TY.js → RemoteSession-6um0lGGy.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DAifkGsy.js → Reputation-CA1BXTup.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D7dZEyak.js → Row-stTnDJ9y.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DB5sImTA.js → RssFeed-B10qCCoG.js} +2 -2
- package/src/assets/web-panel/assets/{Search-3py3TO9V.js → Search-DSJroZ6p.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DhNUfT_k.js → Security-BpXkwiMW.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DjJAA_5D.js → Services-BPQxjwK6.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-u95JjK3n.js → Skeleton-CfbKAMul.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DPo3L0Tz.js → Skills-CttYTfX0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DWhkAZV1.js → Sla-ByluHich.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-PUegMtqV.js → SpeechSettings-BdZXKsfV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BMNYrnrU.js → SyncSettings-xCR7iDzy.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CYm_oTJC.js → Tasks-qTko_INn.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Dw9Er5DN.js → Templates-CkIzhgDJ.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-7P3QIBSo.js → Tenant-BIaCaaK8.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-B2Qq38XP.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DbCd1bDH.js → TimelineRenderer-D5eQDnEF.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-EQofpA0t.js → Tokens-DmeJ8NMQ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ChNLLypd.js → Trigger-C5sgb3C7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-dlVGUKs5.js → Trust-H2vOb3Rb.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BXyBUhNF.js → UkeySign-NmPtHK2u.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BE8-68ge.js → VideoEditing-DHv-Ti7K.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-7ZIJOwNg.js → Wallet-BYZ3-PRP.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgNd2Amr.js → WebAuthn-BaSlP7om.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Z-Un-9l5.js → WorkflowEditor-CZ7IHuIi.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CtVDEkUc.js → chat-Dd9kY8gn.js} +1 -1
- package/src/assets/web-panel/assets/{colors-PXtJ2f1B.js → colors-yhzo6QSV.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-oN96nuBi.js → compact-item-C1JneVdM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-okCJXQXa.js → createContext-C_waVCg2.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DaDlyVDY.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-pcHm--4o.js → hasIn-CkVg0Xnh.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeAWCGEK.js → index-1VYhIr6D.js} +1 -1
- package/src/assets/web-panel/assets/{index-DC0bqrqV.js → index-BTMiVIBI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQYes2mk.js → index-BYOyb5X2.js} +1 -1
- package/src/assets/web-panel/assets/{index-vW0lwj0Y.js → index-BjDnI7oM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUUJ2WfG.js → index-BlJNvg-2.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0rfJBU3.js → index-BlzbSUK9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Rk0X8lVz.js → index-BrN2hAeE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDR2mi1p.js → index-BsSsurcn.js} +1 -1
- package/src/assets/web-panel/assets/index-BtsLExcc.js +1 -0
- package/src/assets/web-panel/assets/{index-jAY55MSx.js → index-Bwuu3Bf3.js} +1 -1
- package/src/assets/web-panel/assets/{index-_SaFHNsG.js → index-Bx3A6X4J.js} +1 -1
- package/src/assets/web-panel/assets/{index-T3QE8LuV.js → index-C-Sscgnv.js} +1 -1
- package/src/assets/web-panel/assets/index-C3qDvvIb.js +1 -0
- package/src/assets/web-panel/assets/{index-BUTyx-Lk.js → index-C4HNdMCt.js} +1 -1
- package/src/assets/web-panel/assets/{index-nMqLdwao.js → index-CBwmwTNa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuME9k4Y.js → index-CErewFeT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHJIfdCV.js → index-CGtoL5mR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0bfypsF.js → index-CUDjGt_V.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bl6N7ZyX.js → index-C_qqYZT7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXhezK4d.js → index-C_riAa6d.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnhHxZul.js → index-CfEMjbhu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs1fGk1Z.js → index-ClQhh6v3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjVIZfdA.js → index-CmiLmG0i.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWUJlCvK.js → index-D1xIbAxQ.js} +3 -3
- package/src/assets/web-panel/assets/{index-DfL10EcN.js → index-D6UXDH2D.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4ravjdv.js → index-D7kQ_4uL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtsyPnF5.js → index-DPkqQ2Pr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQ1ZzJjN.js → index-DUA96wEj.js} +1 -1
- package/src/assets/web-panel/assets/{index-5aO2V0V4.js → index-DXHk9Vof.js} +1 -1
- package/src/assets/web-panel/assets/{index-CopGaCI_.js → index-DapftLUr.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1efSh1X.js → index-Dez7TUgG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBcKBb1E.js → index-DhZgULsY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bht9n8Sm.js → index-Diquc7-l.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAQktO-6.js → index-DuGtLiTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK0H3pQW.js → index-U_nLXGIx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZKk4Lnm.js → index-_M8El5iz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc_MkksW.js → index-_VmzCYFn.js} +1 -1
- package/src/assets/web-panel/assets/{index-mB1UV7wA.js → index-_rZxgFtc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEtzqJw3.js → index-ewb0-LoH.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CG1jyiI7.js → initDefaultProps-DNN6qtGa.js} +1 -1
- package/src/assets/web-panel/assets/{motion-C8BYa98D.js → motion-BcM9exeo.js} +1 -1
- package/src/assets/web-panel/assets/{move-D1hqwitW.js → move-DsKJ-YvA.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C2lol8rp.js → mtc-parser-glgGkxaK.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Ct6Zghfi.js → omit-BwHCU50S.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CSYbYfdc.js → pickAttrs-BVp-bLt7.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-WCk8di0z.js → placementArrow-CZNe0r-w.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CEC8CZ-3.js → responsiveObserve-DUafj9pU.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BsXyd7Lq.js → slide-H4NqXQxu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-tDKldiUT.js → statusUtils-UjMzzGZ5.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BIS2unhx.js → styleChecker-qO5aCjyk.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-yFTVMDUv.js → useFlexGapSupport-ChecYwC8.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CZYbJwkO.js → useFs-BR0QvwO3.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-sbEHRLAM.js → usePersonalDataHub-DitK2Qgz.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BVjeSEQK.js → vnode-dxSb40dY.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BZKVvEZ6.js → zoom-ekJk8YB2.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +75 -0
- package/src/commands/session.js +132 -0
- package/src/data/changelog.json +8 -2
- package/src/harness/jsonl-session-store.js +9 -0
- package/src/harness/session-mirror.js +212 -6
- package/src/harness/worktree-isolator.js +10 -2
- package/src/lib/agent-core.js +1 -0
- package/src/lib/async-hook-queue.cjs +288 -0
- package/src/lib/async-hook-supervisor.cjs +52 -0
- package/src/lib/background-phase-reporter.js +116 -0
- package/src/lib/doctor-checkup.js +184 -4
- package/src/lib/hook-runner.cjs +248 -36
- package/src/lib/install-command-policy.js +343 -0
- package/src/lib/jsonl-session-store.js +1 -0
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +27 -0
- package/src/lib/lsp/code-intelligence.js +5 -1
- package/src/lib/lsp/lsp-server-registry.js +14 -0
- package/src/lib/lsp/workspace-roots.js +115 -0
- package/src/lib/runtime-checkup.js +33 -0
- package/src/lib/settings-hook-events.cjs +173 -3
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/shell-approval.js +47 -1
- package/src/lib/sub-agent-context.js +13 -0
- package/src/repl/add-dir.js +59 -1
- package/src/repl/agent-repl.js +85 -3
- package/src/runtime/agent-core.js +411 -82
- package/src/runtime/headless-runner.js +111 -9
- package/src/runtime/headless-stream.js +39 -0
- package/src/runtime/system-prompt.js +39 -12
- package/src/workers/background-agent-worker.js +8 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-BL_WsWZM.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-Bp5QB-46.js +0 -1
- package/src/assets/web-panel/assets/Terminal-ClPrfWW7.js +0 -3
- package/src/assets/web-panel/assets/devWarning-BzV6dk1B.js +0 -1
- package/src/assets/web-panel/assets/index-BFrAwXHp.js +0 -1
- package/src/assets/web-panel/assets/index-DJQFP47u.js +0 -1
|
@@ -28,6 +28,11 @@ import { mergeProviderOptions } from "../lib/provider-options.js";
|
|
|
28
28
|
import { applyCredentialProxy } from "../lib/credential-proxy.js";
|
|
29
29
|
import { describeBackgroundCommand } from "../lib/terminal-context.js";
|
|
30
30
|
import { buildTelemetryAttributes } from "../lib/telemetry-ids.js";
|
|
31
|
+
import {
|
|
32
|
+
workspaceRootsFor,
|
|
33
|
+
pickRootForFile,
|
|
34
|
+
mergeWorkspaceSymbolResults,
|
|
35
|
+
} from "../lib/lsp/workspace-roots.js";
|
|
31
36
|
import { getPlanModeManager } from "../lib/plan-mode.js";
|
|
32
37
|
import { CLISkillLoader } from "../lib/skill-loader.js";
|
|
33
38
|
import { executeHooks, HookEvents } from "../lib/hook-manager.js";
|
|
@@ -91,9 +96,14 @@ const { isDangerousGitCommand, isReadOnlyGitCommand, normalizeGitCommand } =
|
|
|
91
96
|
const { evaluateShellCommandPolicy } = sharedShellPolicy;
|
|
92
97
|
const { evaluatePermissionRules } = sharedPermissionRules;
|
|
93
98
|
const { collectHooks, umbrellaFor } = sharedSettingsHooks;
|
|
94
|
-
const { runHooks: runCommandHooks } =
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
const { runHooks: runCommandHooks, runHooksParallel: runCommandHooksParallel } =
|
|
100
|
+
sharedHookRunner;
|
|
101
|
+
const {
|
|
102
|
+
runObserveHooks,
|
|
103
|
+
aggregateContext,
|
|
104
|
+
partitionAsyncHooks,
|
|
105
|
+
withDeliveryId,
|
|
106
|
+
} = sharedHookEvents;
|
|
97
107
|
|
|
98
108
|
// ─── Background shell tasks ────────────────────────────────────────────────
|
|
99
109
|
//
|
|
@@ -409,6 +419,19 @@ function _resolveShellTimeout(raw) {
|
|
|
409
419
|
return Math.min(Math.floor(n), MAX_SHELL_TIMEOUT_MS);
|
|
410
420
|
}
|
|
411
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Opt-in: run ALL matching decision hooks and take the STRICTEST outcome
|
|
424
|
+
* (block > ask > allow > continue) instead of the default in-order first-wins
|
|
425
|
+
* short-circuit — so an earlier hook's `ask` can no longer mask a later hook's
|
|
426
|
+
* `block`. Default off = byte-identical short-circuit behavior. Flipping the
|
|
427
|
+
* default is a product decision (all matching hooks then run every time, which
|
|
428
|
+
* changes hook-execution volume + side effects).
|
|
429
|
+
*/
|
|
430
|
+
function _hookStrictMergeEnabled() {
|
|
431
|
+
const v = process.env.CC_HOOK_STRICT_MERGE;
|
|
432
|
+
return v === "1" || v === "true";
|
|
433
|
+
}
|
|
434
|
+
|
|
412
435
|
/**
|
|
413
436
|
* Run settings.json `PreToolUse` hooks (decision-capable). DB hooks are handled
|
|
414
437
|
* separately + stay observe-only. A `block` decision stops the tool; an `ask`
|
|
@@ -419,18 +442,36 @@ function _resolveShellTimeout(raw) {
|
|
|
419
442
|
async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
420
443
|
const matched = collectHooks(context.settingsHooks, "PreToolUse", name);
|
|
421
444
|
if (!matched || matched.length === 0) return { blocked: false };
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
445
|
+
// Unified-bus envelope (P2): stamps event_id + threads trace_id (this run) /
|
|
446
|
+
// parent_id (spawning run) from the loop context. Additive fields — a hook
|
|
447
|
+
// that ignores them is unaffected; absent context omits them entirely.
|
|
448
|
+
const payload = withDeliveryId(
|
|
449
|
+
"PreToolUse",
|
|
450
|
+
{
|
|
451
|
+
hook_event_name: "PreToolUse",
|
|
452
|
+
tool_name: umbrellaFor(name),
|
|
453
|
+
raw_tool_name: name,
|
|
454
|
+
tool_input: args,
|
|
455
|
+
cwd,
|
|
456
|
+
session_id: context.sessionId || null,
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
sessionId: context.sessionId || null,
|
|
460
|
+
traceId: context.hookTraceId || null,
|
|
461
|
+
parentId: context.hookParentId || null,
|
|
462
|
+
},
|
|
463
|
+
);
|
|
464
|
+
// Strict merge (opt-in) runs ALL matching hooks and takes the strictest
|
|
465
|
+
// decision. This path is async so the hooks run in TRUE PARALLEL
|
|
466
|
+
// (runHooksParallel) — wall-clock is the slowest hook, not their sum — while
|
|
467
|
+
// still yielding the same strictest outcome. Default path is the sync in-order
|
|
468
|
+
// short-circuit runner (byte-identical).
|
|
469
|
+
const outcome = _hookStrictMergeEnabled()
|
|
470
|
+
? await runCommandHooksParallel(matched, payload, {
|
|
471
|
+
cwd,
|
|
472
|
+
event: "PreToolUse",
|
|
473
|
+
})
|
|
474
|
+
: runCommandHooks(matched, payload, { cwd, event: "PreToolUse" });
|
|
434
475
|
if (outcome.decision === "block") {
|
|
435
476
|
return { blocked: true, reason: outcome.reason, hook: outcome.hook };
|
|
436
477
|
}
|
|
@@ -490,18 +531,27 @@ function runSettingsPermissionRequestHooks(name, args, context, cwd, reason) {
|
|
|
490
531
|
name,
|
|
491
532
|
);
|
|
492
533
|
if (!matched || matched.length === 0) return { decision: null };
|
|
493
|
-
const payload =
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
534
|
+
const payload = withDeliveryId(
|
|
535
|
+
"PermissionRequest",
|
|
536
|
+
{
|
|
537
|
+
hook_event_name: "PermissionRequest",
|
|
538
|
+
tool_name: umbrellaFor(name),
|
|
539
|
+
raw_tool_name: name,
|
|
540
|
+
tool_input: args,
|
|
541
|
+
permission_reason: reason || null,
|
|
542
|
+
cwd,
|
|
543
|
+
session_id: context.sessionId || null,
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
sessionId: context.sessionId || null,
|
|
547
|
+
traceId: context.hookTraceId || null,
|
|
548
|
+
parentId: context.hookParentId || null,
|
|
549
|
+
},
|
|
550
|
+
);
|
|
502
551
|
const outcome = runCommandHooks(matched, payload, {
|
|
503
552
|
cwd,
|
|
504
553
|
event: "PermissionRequest",
|
|
554
|
+
mergeStrict: _hookStrictMergeEnabled(),
|
|
505
555
|
});
|
|
506
556
|
// Precedence: deny > ask > allow > defer. The runner normalizes deny/block →
|
|
507
557
|
// "block" and short-circuits block/ask, but it COLLAPSES an "allow" into the
|
|
@@ -726,6 +776,7 @@ Key behaviors:
|
|
|
726
776
|
- When asked about files or code, use read_file and search_files to find information
|
|
727
777
|
- Before renaming or changing a symbol, use code_intelligence (action: references/definition) to find every real usage instead of guessing with text search. It degrades to "unavailable" when no language server is installed — fall back to search_files then.
|
|
728
778
|
- After an edit, if the tool result includes a "newDiagnostics" array, you just introduced (or exposed) those errors/warnings — read them and fix before moving on. You can also run code_intelligence (action: diagnostics) on any file to check it on demand.
|
|
779
|
+
- If a tool result includes a "subtreeInstructions" array, you just entered a subdirectory that carries its own cc.md/CLAUDE.md/AGENTS.md — treat that content as authoritative project rules for work in that subtree (it is injected once, the first time you touch the subtree).
|
|
729
780
|
- You have multi-layer skills (built-in, marketplace, global, project-level) — use list_skills to discover them and run_skill to execute them
|
|
730
781
|
- Always explain what you're doing and show results
|
|
731
782
|
- Be concise but thorough
|
|
@@ -1642,18 +1693,26 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1642
1693
|
// ran synchronously here, defeating fire-and-forget (a background lint /
|
|
1643
1694
|
// test after each edit would stall the turn).
|
|
1644
1695
|
const { sync, async: asyncHooks } = partitionAsyncHooks(matched);
|
|
1645
|
-
const payload =
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1696
|
+
const payload = withDeliveryId(
|
|
1697
|
+
"PostToolUse",
|
|
1698
|
+
{
|
|
1699
|
+
hook_event_name: "PostToolUse",
|
|
1700
|
+
tool_name: umbrellaFor(name),
|
|
1701
|
+
raw_tool_name: name,
|
|
1702
|
+
tool_input: args,
|
|
1703
|
+
tool_response:
|
|
1704
|
+
typeof toolResult === "object"
|
|
1705
|
+
? JSON.stringify(toolResult).substring(0, 2000)
|
|
1706
|
+
: String(toolResult).substring(0, 2000),
|
|
1707
|
+
cwd,
|
|
1708
|
+
session_id: context.sessionId || null,
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
sessionId: context.sessionId || null,
|
|
1712
|
+
traceId: context.hookTraceId || null,
|
|
1713
|
+
parentId: context.hookParentId || null,
|
|
1714
|
+
},
|
|
1715
|
+
);
|
|
1657
1716
|
if (sync.length > 0) {
|
|
1658
1717
|
const outcome = runCommandHooks(sync, payload, {
|
|
1659
1718
|
cwd,
|
|
@@ -1700,7 +1759,11 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1700
1759
|
? JSON.stringify(toolResult).substring(0, 2000)
|
|
1701
1760
|
: String(toolResult).substring(0, 2000),
|
|
1702
1761
|
},
|
|
1703
|
-
{
|
|
1762
|
+
{
|
|
1763
|
+
cwd,
|
|
1764
|
+
traceId: context.hookTraceId || null,
|
|
1765
|
+
parentId: context.hookParentId || null,
|
|
1766
|
+
},
|
|
1704
1767
|
);
|
|
1705
1768
|
if (outcome.decision === "block" && outcome.reason) {
|
|
1706
1769
|
toolResult.hookFeedback = toolResult.hookFeedback
|
|
@@ -2056,6 +2119,21 @@ const _codeIntelPool = new Map(); // root -> { ci, idleTimer }
|
|
|
2056
2119
|
const CODE_INTEL_IDLE_MS = 60_000;
|
|
2057
2120
|
let _codeIntelExitHooked = false;
|
|
2058
2121
|
|
|
2122
|
+
// Restart backoff between language-server re-spawns (P2 LSP): DEFAULT ON at a
|
|
2123
|
+
// 1s base (1s→2s→4s→8s cap, see lsp-manager) so a server that crashes on
|
|
2124
|
+
// startup can't burst `maxRestarts` spawns back-to-back before quarantine.
|
|
2125
|
+
// `CC_LSP_RESTART_BACKOFF_MS` overrides the base; 0 restores the legacy
|
|
2126
|
+
// immediate-respawn behavior.
|
|
2127
|
+
const DEFAULT_LSP_RESTART_BACKOFF_MS = 1000;
|
|
2128
|
+
function _lspRestartBackoffBaseMs() {
|
|
2129
|
+
const raw = process.env.CC_LSP_RESTART_BACKOFF_MS;
|
|
2130
|
+
if (raw !== undefined && raw !== "") {
|
|
2131
|
+
const n = Number(raw);
|
|
2132
|
+
if (Number.isFinite(n)) return Math.max(0, n);
|
|
2133
|
+
}
|
|
2134
|
+
return DEFAULT_LSP_RESTART_BACKOFF_MS;
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2059
2137
|
export async function _getSharedCodeIntel(cwd) {
|
|
2060
2138
|
const root = path.resolve(cwd || process.cwd());
|
|
2061
2139
|
let entry = _codeIntelPool.get(root);
|
|
@@ -2075,7 +2153,11 @@ export async function _getSharedCodeIntel(cwd) {
|
|
|
2075
2153
|
entry = _codeIntelPool.get(root);
|
|
2076
2154
|
if (!entry) {
|
|
2077
2155
|
entry = {
|
|
2078
|
-
ci: new CodeIntelligence({
|
|
2156
|
+
ci: new CodeIntelligence({
|
|
2157
|
+
projectRoot: root,
|
|
2158
|
+
coldStart: true,
|
|
2159
|
+
lspOptions: { restartBackoffBaseMs: _lspRestartBackoffBaseMs() },
|
|
2160
|
+
}),
|
|
2079
2161
|
idleTimer: null,
|
|
2080
2162
|
};
|
|
2081
2163
|
_codeIntelPool.set(root, entry);
|
|
@@ -2152,7 +2234,17 @@ async function _postEditDiagnostics(filePath, cwd) {
|
|
|
2152
2234
|
const diags = (res.diagnostics || []).filter(
|
|
2153
2235
|
(d) => d.severity === "error" || d.severity === "warning",
|
|
2154
2236
|
);
|
|
2155
|
-
|
|
2237
|
+
if (!diags.length) return null;
|
|
2238
|
+
// Bound by a TOKEN budget, severity-prioritized (errors survive over
|
|
2239
|
+
// warnings), replacing the arbitrary unsorted count-cap of 20. Guarantees
|
|
2240
|
+
// the model sees the most severe diagnostics first and can't be flooded by
|
|
2241
|
+
// a pathological diagnostics dump. Budget is overridable via
|
|
2242
|
+
// CC_EDIT_DIAGNOSTICS_TOKENS (default 2000).
|
|
2243
|
+
const { capDiagnostics } =
|
|
2244
|
+
await import("../lib/lsp/diagnostics-scheduler.js");
|
|
2245
|
+
const budget = Number(process.env.CC_EDIT_DIAGNOSTICS_TOKENS) || 2000;
|
|
2246
|
+
const { kept } = capDiagnostics(diags, { maxTokens: budget });
|
|
2247
|
+
return kept.length ? kept : null;
|
|
2156
2248
|
} catch {
|
|
2157
2249
|
return null;
|
|
2158
2250
|
}
|
|
@@ -2176,6 +2268,96 @@ async function _withPostEditDiagnostics(result, filePath, cwd) {
|
|
|
2176
2268
|
return newDiagnostics ? { ...result, newDiagnostics } : result;
|
|
2177
2269
|
}
|
|
2178
2270
|
|
|
2271
|
+
// ─── Lazy subtree instruction injection (large-monorepo lever) ─────────────
|
|
2272
|
+
//
|
|
2273
|
+
// cc.md / CLAUDE.md / AGENTS.md that sit BELOW the startup cwd are intentionally
|
|
2274
|
+
// NOT loaded up front — they cost tokens for subtrees a run may never touch.
|
|
2275
|
+
// When a tool first ACCESSES a path inside such a subtree, we inject that
|
|
2276
|
+
// subtree's directory instructions into the tool result (the SAME channel as
|
|
2277
|
+
// newDiagnostics), exactly once per subtree per process. A stateful
|
|
2278
|
+
// SubtreeInstructionLoader per root remembers what it already injected so a
|
|
2279
|
+
// second access to the same subtree is a no-op. Disable with
|
|
2280
|
+
// CC_SUBTREE_INSTRUCTIONS=0. Common case (no cc.md below cwd) → zero cost.
|
|
2281
|
+
const _subtreeLoaderPool = new Map(); // root -> SubtreeInstructionLoader
|
|
2282
|
+
|
|
2283
|
+
async function _getSubtreeLoader(cwd) {
|
|
2284
|
+
const root = path.resolve(cwd || process.cwd());
|
|
2285
|
+
let loader = _subtreeLoaderPool.get(root);
|
|
2286
|
+
if (!loader) {
|
|
2287
|
+
const { SubtreeInstructionLoader } =
|
|
2288
|
+
await import("../lib/project-instructions.js");
|
|
2289
|
+
let instructionExcludes;
|
|
2290
|
+
try {
|
|
2291
|
+
const { readStringArraySetting } =
|
|
2292
|
+
await import("../lib/settings-loader.cjs");
|
|
2293
|
+
instructionExcludes = readStringArraySetting("instructionExcludes", {
|
|
2294
|
+
cwd: root,
|
|
2295
|
+
});
|
|
2296
|
+
} catch {
|
|
2297
|
+
instructionExcludes = undefined; // fail-open — honor no excludes
|
|
2298
|
+
}
|
|
2299
|
+
loader = new SubtreeInstructionLoader({
|
|
2300
|
+
repoRoot: root,
|
|
2301
|
+
baseDir: root,
|
|
2302
|
+
instructionExcludes,
|
|
2303
|
+
});
|
|
2304
|
+
_subtreeLoaderPool.set(root, loader);
|
|
2305
|
+
}
|
|
2306
|
+
return loader;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
/** Test/shutdown hook: forget every remembered subtree-injection set. */
|
|
2310
|
+
export function _resetSubtreeInstructionLoaders() {
|
|
2311
|
+
_subtreeLoaderPool.clear();
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
/**
|
|
2315
|
+
* Freshly-discovered subtree instruction files for a path a tool just touched,
|
|
2316
|
+
* with their (capped) content read for inline injection — or null when the
|
|
2317
|
+
* subtree has no NEW cc.md/CLAUDE.md/AGENTS.md (the common case → zero cost).
|
|
2318
|
+
*/
|
|
2319
|
+
async function _subtreeInstructionsFor(accessedPath, cwd) {
|
|
2320
|
+
if (process.env.CC_SUBTREE_INSTRUCTIONS === "0") return null;
|
|
2321
|
+
try {
|
|
2322
|
+
const loader = await _getSubtreeLoader(cwd);
|
|
2323
|
+
const fresh = loader.onAccess(accessedPath);
|
|
2324
|
+
if (!fresh || !fresh.length) return null;
|
|
2325
|
+
const { DEFAULT_MAX_FILE_BYTES } =
|
|
2326
|
+
await import("../lib/project-instructions.js");
|
|
2327
|
+
const out = [];
|
|
2328
|
+
for (const f of fresh) {
|
|
2329
|
+
try {
|
|
2330
|
+
const buf = fs.readFileSync(f.path);
|
|
2331
|
+
const truncated = buf.length > DEFAULT_MAX_FILE_BYTES;
|
|
2332
|
+
const content = (
|
|
2333
|
+
truncated ? buf.slice(0, DEFAULT_MAX_FILE_BYTES) : buf
|
|
2334
|
+
).toString("utf-8");
|
|
2335
|
+
out.push({
|
|
2336
|
+
path: f.path,
|
|
2337
|
+
scope: f.scope || "project",
|
|
2338
|
+
content,
|
|
2339
|
+
...(truncated ? { truncated: true } : {}),
|
|
2340
|
+
});
|
|
2341
|
+
} catch {
|
|
2342
|
+
// discovered file vanished before we could read it — skip it
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return out.length ? out : null;
|
|
2346
|
+
} catch {
|
|
2347
|
+
return null; // fail-open: never break a tool because injection errored
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
/**
|
|
2352
|
+
* Attach freshly-discovered subtree instructions to a SUCCESSFUL tool result
|
|
2353
|
+
* (no-op on an error result or when the subtree has nothing new).
|
|
2354
|
+
*/
|
|
2355
|
+
async function _withSubtreeInstructions(result, accessedPath, cwd) {
|
|
2356
|
+
if (result && result.error) return result;
|
|
2357
|
+
const subtreeInstructions = await _subtreeInstructionsFor(accessedPath, cwd);
|
|
2358
|
+
return subtreeInstructions ? { ...result, subtreeInstructions } : result;
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2179
2361
|
/**
|
|
2180
2362
|
* Drop skills whose `paths:` frontmatter scopes them to a different subtree than
|
|
2181
2363
|
* the agent's cwd (large-monorepo lazy skill surface). A skill with no `paths`
|
|
@@ -2230,6 +2412,9 @@ async function executeToolInner(
|
|
|
2230
2412
|
signal = null,
|
|
2231
2413
|
backgroundSubAgents = null,
|
|
2232
2414
|
subAgentUsageSink = null,
|
|
2415
|
+
// Hook-envelope tracing: this run's trace id, threaded into child loops
|
|
2416
|
+
// (spawn_sub_agent / isolated run_skill) as their parent_id.
|
|
2417
|
+
hookTraceId = null,
|
|
2233
2418
|
},
|
|
2234
2419
|
) {
|
|
2235
2420
|
const localToolDescriptor =
|
|
@@ -2338,18 +2523,30 @@ async function executeToolInner(
|
|
|
2338
2523
|
}
|
|
2339
2524
|
|
|
2340
2525
|
if (rendered.length > 50000) {
|
|
2341
|
-
return attachDescriptor(
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2526
|
+
return attachDescriptor(
|
|
2527
|
+
await _withSubtreeInstructions(
|
|
2528
|
+
{
|
|
2529
|
+
content: rendered.substring(0, 50000) + "\n...(truncated)",
|
|
2530
|
+
size: rendered.length,
|
|
2531
|
+
hashed: args.hashed === true,
|
|
2532
|
+
...(range ? { range } : {}),
|
|
2533
|
+
},
|
|
2534
|
+
filePath,
|
|
2535
|
+
cwd,
|
|
2536
|
+
),
|
|
2537
|
+
);
|
|
2347
2538
|
}
|
|
2348
|
-
return attachDescriptor(
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2539
|
+
return attachDescriptor(
|
|
2540
|
+
await _withSubtreeInstructions(
|
|
2541
|
+
{
|
|
2542
|
+
content: rendered,
|
|
2543
|
+
hashed: args.hashed === true,
|
|
2544
|
+
...(range ? { range } : {}),
|
|
2545
|
+
},
|
|
2546
|
+
filePath,
|
|
2547
|
+
cwd,
|
|
2548
|
+
),
|
|
2549
|
+
);
|
|
2353
2550
|
}
|
|
2354
2551
|
|
|
2355
2552
|
case "write_file": {
|
|
@@ -2368,8 +2565,12 @@ async function executeToolInner(
|
|
|
2368
2565
|
if (wrote.error) return attachDescriptor({ error: wrote.error });
|
|
2369
2566
|
_recordFileObservation(filePath);
|
|
2370
2567
|
return attachDescriptor(
|
|
2371
|
-
await
|
|
2372
|
-
|
|
2568
|
+
await _withSubtreeInstructions(
|
|
2569
|
+
await _withPostEditDiagnostics(
|
|
2570
|
+
{ success: true, path: filePath, size: wrote.size },
|
|
2571
|
+
filePath,
|
|
2572
|
+
cwd,
|
|
2573
|
+
),
|
|
2373
2574
|
filePath,
|
|
2374
2575
|
cwd,
|
|
2375
2576
|
),
|
|
@@ -2457,13 +2658,17 @@ async function executeToolInner(
|
|
|
2457
2658
|
if (wrote.error) return attachDescriptor({ error: wrote.error });
|
|
2458
2659
|
_recordFileObservation(filePath);
|
|
2459
2660
|
return attachDescriptor(
|
|
2460
|
-
await
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2661
|
+
await _withSubtreeInstructions(
|
|
2662
|
+
await _withPostEditDiagnostics(
|
|
2663
|
+
{
|
|
2664
|
+
success: true,
|
|
2665
|
+
path: filePath,
|
|
2666
|
+
size: wrote.size,
|
|
2667
|
+
replaced: replaceAll ? count : 1,
|
|
2668
|
+
},
|
|
2669
|
+
filePath,
|
|
2670
|
+
cwd,
|
|
2671
|
+
),
|
|
2467
2672
|
filePath,
|
|
2468
2673
|
cwd,
|
|
2469
2674
|
),
|
|
@@ -2515,14 +2720,18 @@ async function executeToolInner(
|
|
|
2515
2720
|
if (wrote.error) return attachDescriptor({ error: wrote.error });
|
|
2516
2721
|
_recordFileObservation(filePath);
|
|
2517
2722
|
return attachDescriptor(
|
|
2518
|
-
await
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2723
|
+
await _withSubtreeInstructions(
|
|
2724
|
+
await _withPostEditDiagnostics(
|
|
2725
|
+
{
|
|
2726
|
+
success: true,
|
|
2727
|
+
path: filePath,
|
|
2728
|
+
size: wrote.size,
|
|
2729
|
+
lineNumber: result.lineNumber,
|
|
2730
|
+
previousContent: result.previousContent,
|
|
2731
|
+
},
|
|
2732
|
+
filePath,
|
|
2733
|
+
cwd,
|
|
2734
|
+
),
|
|
2526
2735
|
filePath,
|
|
2527
2736
|
cwd,
|
|
2528
2737
|
),
|
|
@@ -3104,6 +3313,8 @@ async function executeToolInner(
|
|
|
3104
3313
|
subAgentBudget,
|
|
3105
3314
|
subAgentContract,
|
|
3106
3315
|
settingsHooks,
|
|
3316
|
+
// Parent trace for the child's hook envelopes (parent_id).
|
|
3317
|
+
hookTraceId,
|
|
3107
3318
|
// Parent MCP plumbing — a spawn can inherit these into the child,
|
|
3108
3319
|
// filtered by the resolved contract's mcpServers allow-list.
|
|
3109
3320
|
mcpClient,
|
|
@@ -3675,8 +3886,15 @@ async function executeToolInner(
|
|
|
3675
3886
|
error: `code_intelligence action "rename_preview" requires "new_name".`,
|
|
3676
3887
|
});
|
|
3677
3888
|
}
|
|
3678
|
-
|
|
3889
|
+
// Multi-root workspace (P2 LSP): key the shared server pool on the root
|
|
3890
|
+
// that actually CONTAINS the file — a file inside an `--add-dir` root
|
|
3891
|
+
// gets that project's language server, not the cwd's. Single-root
|
|
3892
|
+
// sessions resolve to cwd exactly as before (byte-identical).
|
|
3679
3893
|
const file = args.file ? path.resolve(cwd, args.file) : null;
|
|
3894
|
+
const wsRoots = workspaceRootsFor(cwd, additionalDirectories);
|
|
3895
|
+
const ci = await _getSharedCodeIntel(
|
|
3896
|
+
file ? pickRootForFile(file, wsRoots) : cwd,
|
|
3897
|
+
);
|
|
3680
3898
|
let res;
|
|
3681
3899
|
try {
|
|
3682
3900
|
switch (action) {
|
|
@@ -3692,9 +3910,29 @@ async function executeToolInner(
|
|
|
3692
3910
|
case "document_symbols":
|
|
3693
3911
|
res = await ci.documentSymbols(file);
|
|
3694
3912
|
break;
|
|
3695
|
-
case "workspace_symbols":
|
|
3696
|
-
|
|
3913
|
+
case "workspace_symbols": {
|
|
3914
|
+
// Fan out across EVERY workspace root and merge — symbols from an
|
|
3915
|
+
// --add-dir project are stamped with their `root` so same-named
|
|
3916
|
+
// symbols stay unambiguous. One root → the exact legacy call.
|
|
3917
|
+
if (wsRoots.length > 1) {
|
|
3918
|
+
const perRoot = [];
|
|
3919
|
+
for (const r of wsRoots) {
|
|
3920
|
+
try {
|
|
3921
|
+
const rci = await _getSharedCodeIntel(r);
|
|
3922
|
+
perRoot.push(await rci.workspaceSymbols(String(args.query)));
|
|
3923
|
+
} catch (err) {
|
|
3924
|
+
perRoot.push({
|
|
3925
|
+
available: false,
|
|
3926
|
+
reason: err?.message || "workspace_symbols failed",
|
|
3927
|
+
});
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
res = mergeWorkspaceSymbolResults(perRoot, wsRoots);
|
|
3931
|
+
} else {
|
|
3932
|
+
res = await ci.workspaceSymbols(String(args.query));
|
|
3933
|
+
}
|
|
3697
3934
|
break;
|
|
3935
|
+
}
|
|
3698
3936
|
case "diagnostics":
|
|
3699
3937
|
res = await ci.diagnostics(file);
|
|
3700
3938
|
break;
|
|
@@ -3743,12 +3981,18 @@ async function executeToolInner(
|
|
|
3743
3981
|
});
|
|
3744
3982
|
}
|
|
3745
3983
|
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
3746
|
-
return attachDescriptor(
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3984
|
+
return attachDescriptor(
|
|
3985
|
+
await _withSubtreeInstructions(
|
|
3986
|
+
{
|
|
3987
|
+
entries: entries.map((e) => ({
|
|
3988
|
+
name: e.name,
|
|
3989
|
+
type: e.isDirectory() ? "dir" : "file",
|
|
3990
|
+
})),
|
|
3991
|
+
},
|
|
3992
|
+
dirPath,
|
|
3993
|
+
cwd,
|
|
3994
|
+
),
|
|
3995
|
+
);
|
|
3752
3996
|
}
|
|
3753
3997
|
|
|
3754
3998
|
case "run_skill": {
|
|
@@ -3788,6 +4032,7 @@ async function executeToolInner(
|
|
|
3788
4032
|
role: `skill-${args.skill_name}`,
|
|
3789
4033
|
task: `Execute the "${args.skill_name}" skill with input: ${(args.input || "").substring(0, 200)}`,
|
|
3790
4034
|
allowedTools: ["read_file", "search_files", "list_dir"],
|
|
4035
|
+
hookParentTraceId: hookTraceId || null,
|
|
3791
4036
|
cwd,
|
|
3792
4037
|
onUsage: skillUsageSink
|
|
3793
4038
|
? (u) => {
|
|
@@ -4251,6 +4496,32 @@ async function _executeRunCode(args, cwd) {
|
|
|
4251
4496
|
};
|
|
4252
4497
|
}
|
|
4253
4498
|
|
|
4499
|
+
// Unified install-command audit (P0 sandbox slice): the same opt-in
|
|
4500
|
+
// trail (CC_INSTALL_AUDIT / settings installPolicy) that records
|
|
4501
|
+
// run_shell installs also records run_code auto-installs — one audit
|
|
4502
|
+
// file covers every "fetch and run third-party code" entry point.
|
|
4503
|
+
// Best-effort; default (policy off) writes nothing.
|
|
4504
|
+
let auditUnifiedInstall = () => {};
|
|
4505
|
+
try {
|
|
4506
|
+
const icp = await import("../lib/install-command-policy.js");
|
|
4507
|
+
const unified = icp.resolveInstallPolicy({});
|
|
4508
|
+
if (unified.audit) {
|
|
4509
|
+
const installCommand = `${interpreter} -m pip install ${packageName}`;
|
|
4510
|
+
const cls = icp.classifyInstallCommand(installCommand);
|
|
4511
|
+
auditUnifiedInstall = (outcome, detail) =>
|
|
4512
|
+
icp.recordInstallCommandAudit({
|
|
4513
|
+
source: "run_code_auto_install",
|
|
4514
|
+
command: installCommand,
|
|
4515
|
+
outcome,
|
|
4516
|
+
...(detail ? { detail } : {}),
|
|
4517
|
+
installs: cls.installs,
|
|
4518
|
+
global: icp.hasGlobalInstall(cls),
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
} catch {
|
|
4522
|
+
/* unified audit must never affect the install itself */
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4254
4525
|
// Attempt pip install
|
|
4255
4526
|
try {
|
|
4256
4527
|
execSync(`${interpreter} -m pip install ${packageName}`, {
|
|
@@ -4265,6 +4536,7 @@ async function _executeRunCode(args, cwd) {
|
|
|
4265
4536
|
cwd,
|
|
4266
4537
|
outcome: "installed",
|
|
4267
4538
|
});
|
|
4539
|
+
auditUnifiedInstall("installed");
|
|
4268
4540
|
|
|
4269
4541
|
// Retry execution
|
|
4270
4542
|
const retryStart = Date.now();
|
|
@@ -4292,6 +4564,10 @@ async function _executeRunCode(args, cwd) {
|
|
|
4292
4564
|
outcome: "failed",
|
|
4293
4565
|
detail: (pipErr.stderr || pipErr.message || "").substring(0, 200),
|
|
4294
4566
|
});
|
|
4567
|
+
auditUnifiedInstall(
|
|
4568
|
+
"failed",
|
|
4569
|
+
(pipErr.stderr || pipErr.message || "").substring(0, 200),
|
|
4570
|
+
);
|
|
4295
4571
|
return {
|
|
4296
4572
|
error: (stderr || message).substring(0, 5000),
|
|
4297
4573
|
stderr: stderr.substring(0, 5000),
|
|
@@ -4556,6 +4832,8 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4556
4832
|
let mdProfile = null;
|
|
4557
4833
|
let mdModel = null;
|
|
4558
4834
|
let mdContract = null; // agent-file's normalized subagent contract (definition)
|
|
4835
|
+
let mdSparsePaths = null; // agent-file worktree sparse-checkout paths
|
|
4836
|
+
let mdSymlinkDirectories = null; // agent-file worktree dep-dir symlinks
|
|
4559
4837
|
if (args.agent) {
|
|
4560
4838
|
try {
|
|
4561
4839
|
const { getAgent } = await import("../lib/agents.js");
|
|
@@ -4574,6 +4852,10 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4574
4852
|
if (!subIsolation && md.isolation === "worktree") {
|
|
4575
4853
|
subIsolation = "worktree";
|
|
4576
4854
|
}
|
|
4855
|
+
if (md.sparsePaths != null) mdSparsePaths = md.sparsePaths;
|
|
4856
|
+
if (md.symlinkDirectories != null) {
|
|
4857
|
+
mdSymlinkDirectories = md.symlinkDirectories;
|
|
4858
|
+
}
|
|
4577
4859
|
if (md.model) mdModel = md.model;
|
|
4578
4860
|
if (md.contract) mdContract = md.contract;
|
|
4579
4861
|
if (md.systemPrompt) {
|
|
@@ -4894,10 +5176,37 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4894
5176
|
}
|
|
4895
5177
|
: null;
|
|
4896
5178
|
|
|
5179
|
+
// Worktree sparse-checkout + dependency symlink (large-monorepo lever): when
|
|
5180
|
+
// the child runs in an isolated worktree, only materialize the packages it
|
|
5181
|
+
// needs (sparsePaths) and reuse approved dep dirs (e.g. node_modules) from the
|
|
5182
|
+
// main checkout (symlinkDirectories). Mirrors the team-worktree passthrough;
|
|
5183
|
+
// spawn args win over the agent-file's values. Resolved ONLY when isolation is
|
|
5184
|
+
// on → absent for a non-worktree spawn = byte-identical (full checkout).
|
|
5185
|
+
let subWorktreeOptions = null;
|
|
5186
|
+
if (subIsolation === "worktree") {
|
|
5187
|
+
try {
|
|
5188
|
+
const { normalizeSparsePaths } =
|
|
5189
|
+
await import("../lib/worktree-sparse.js");
|
|
5190
|
+
const sparse = normalizeSparsePaths(
|
|
5191
|
+
args.sparsePaths ?? mdSparsePaths ?? null,
|
|
5192
|
+
);
|
|
5193
|
+
const symlink = args.symlinkDirectories ?? mdSymlinkDirectories ?? null;
|
|
5194
|
+
const wtOpts = {};
|
|
5195
|
+
if (sparse) wtOpts.sparsePaths = sparse;
|
|
5196
|
+
if (symlink != null) wtOpts.symlinkDirectories = symlink;
|
|
5197
|
+
if (Object.keys(wtOpts).length) subWorktreeOptions = wtOpts;
|
|
5198
|
+
} catch {
|
|
5199
|
+
subWorktreeOptions = null; // best-effort → full checkout on any error
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
|
|
4897
5203
|
const subCtx = SubAgentContext.create({
|
|
4898
5204
|
role,
|
|
4899
5205
|
task,
|
|
4900
5206
|
parentId: parentSessionId,
|
|
5207
|
+
// Hook-envelope tracing: the child loop stamps its own runId as trace_id
|
|
5208
|
+
// and THIS run's id as parent_id on every settings-hook payload it fires.
|
|
5209
|
+
hookParentTraceId: ctx.hookTraceId || null,
|
|
4901
5210
|
inheritedContext: resolvedContext,
|
|
4902
5211
|
allowedTools: allowedTools || null,
|
|
4903
5212
|
cwd: ctx.cwd,
|
|
@@ -4912,6 +5221,9 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4912
5221
|
// worktree isolation. undefined keeps the profile/flag defaults intact.
|
|
4913
5222
|
...(subMaxTurns ? { maxIterations: subMaxTurns } : {}),
|
|
4914
5223
|
...(subIsolation === "worktree" ? { useWorktree: true } : {}),
|
|
5224
|
+
// Worktree sparse-checkout / dep-symlink options (large-monorepo); only
|
|
5225
|
+
// present for a worktree spawn that requested them (else full checkout).
|
|
5226
|
+
...(subWorktreeOptions ? { worktreeOptions: subWorktreeOptions } : {}),
|
|
4915
5227
|
// Resolved contract (gap 2026-07-12): cap the child's token budget and hand
|
|
4916
5228
|
// it its EFFECTIVE contract so its OWN spawns inherit this ceiling.
|
|
4917
5229
|
...(effectiveContract?.budget?.tokens
|
|
@@ -4993,7 +5305,15 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
4993
5305
|
// refuses to finish while any background sub-agent is still running). Only
|
|
4994
5306
|
// available when the calling loop provided the per-run map — a bare
|
|
4995
5307
|
// executeTool() without it falls through to the blocking path.
|
|
4996
|
-
|
|
5308
|
+
//
|
|
5309
|
+
// `background` is driven by the resolved contract (spawn arg > agent-file
|
|
5310
|
+
// definition), so an agent-file can declare `background: true` and be spawned
|
|
5311
|
+
// detached without the caller passing it. `effectiveContract.background`
|
|
5312
|
+
// already folds in `args.background`; the explicit OR keeps the path
|
|
5313
|
+
// byte-identical if contract resolution was skipped (effectiveContract null).
|
|
5314
|
+
const wantsBackground =
|
|
5315
|
+
args.background === true || effectiveContract?.background === true;
|
|
5316
|
+
if (wantsBackground && ctx.backgroundSubAgents instanceof Map) {
|
|
4997
5317
|
// Cancel with the parent: forward the loop's abort signal so killing the
|
|
4998
5318
|
// run doesn't orphan a detached child mid-LLM-call.
|
|
4999
5319
|
subCtx._signal = subCtx._signal || ctx.signal || null;
|
|
@@ -6544,9 +6864,23 @@ export async function* agentLoop(messages, options) {
|
|
|
6544
6864
|
// Optional OpenTelemetry recorder (TelemetryRecorder). When present, the loop
|
|
6545
6865
|
// emits model/tool/retry spans + a per-run counter; when absent, zero cost.
|
|
6546
6866
|
const recorder = options.recorder || null;
|
|
6867
|
+
// Phase 5 run bookends — a stable runId lets envelope subscribers correlate
|
|
6868
|
+
// every tool_call / tool_result / message / ended event back to one run.
|
|
6869
|
+
// Minted BEFORE the tool context so hook envelopes can carry it as trace_id.
|
|
6870
|
+
const runId =
|
|
6871
|
+
options.runId ||
|
|
6872
|
+
`run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
6873
|
+
|
|
6547
6874
|
const toolContext = {
|
|
6548
6875
|
hookDb: options.hookDb || null,
|
|
6549
6876
|
skillLoader: options.skillLoader || _defaultSkillLoader,
|
|
6877
|
+
// Hook-envelope tracing (P2 unified event bus): every settings-hook payload
|
|
6878
|
+
// fired during this run carries trace_id = this run's id; a spawned child
|
|
6879
|
+
// loop carries parent_id = the spawning run's id (threaded by
|
|
6880
|
+
// spawn_sub_agent via hookParentTraceId), so a subagent's hook events
|
|
6881
|
+
// correlate back to the parent trace. Null parent at the top level.
|
|
6882
|
+
hookTraceId: runId,
|
|
6883
|
+
hookParentId: options.hookParentTraceId || null,
|
|
6550
6884
|
// Contract-driven skill allow-list (subagent capability INTERSECT). null =
|
|
6551
6885
|
// unrestricted; [] = none; a list restricts run_skill/list_skills to those
|
|
6552
6886
|
// ids/dirNames. Set by the spawn path from the resolved subagent contract.
|
|
@@ -6736,11 +7070,6 @@ export async function* agentLoop(messages, options) {
|
|
|
6736
7070
|
});
|
|
6737
7071
|
}
|
|
6738
7072
|
|
|
6739
|
-
// Phase 5 run bookends — a stable runId lets envelope subscribers correlate
|
|
6740
|
-
// every tool_call / tool_result / message / ended event back to one run.
|
|
6741
|
-
const runId =
|
|
6742
|
-
options.runId ||
|
|
6743
|
-
`run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
6744
7073
|
// Workflow-tracing attributes (Claude-Code 2.1.202): stamp the run id (and
|
|
6745
7074
|
// an optional caller-provided workflow name) onto EVERY span this run emits,
|
|
6746
7075
|
// so a collector can group one run's model/tool spans into one workflow.
|