chainlesschain 0.162.46 → 0.162.48
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 +2 -2
- package/src/assets/web-panel/assets/{AIOps-QzHleqCS.js → AIOps-BeMOUkMq.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CZ3F-KVY.js → ActionButton-DrRegmIt.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CHml-drq.js → Analytics-BM7hvUn8.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-a-fczvRH.js → AppLayout-BfLLYSz_.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-CtMWsXwm.js → Audit-BpiPR-rs.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-ErWTcS0A.js → Backup-BLq4IRI9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B4w2b2dA.js → BaseInput-Bv89IFrM.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CFPKVfmV.js → Chat-BUM9MdnH.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-WGpUTY92.js → ChatBubbleRenderer-rH_t53ZW.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-C4vasfJc.js → Checkbox-82jih_zU.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DHmDAbSg.js → Codegen-ygmM1mNL.js} +1 -1
- package/src/assets/web-panel/assets/{Col-LhgveyhM.js → Col-CqXc8_ft.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CB8gtudt.js → Community-CqPPfyR3.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CTndsUSy.js → Compact-LR8Z206-.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CCpGUHPm.js → Compliance-D4alm_Gx.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CQmJiOM_.js → Cowork-D-DLVanT.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-TrTmpnSB.js → Cron-UDtmjvd4.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DvaR1Xq4.js → Crosschain-iqbVDPNE.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CdDdiRs3.js → DID-DzdUfzc9.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-S6gCBQDc.js → Dashboard-DvKp1skY.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CWO-Kwzl.js → Dropdown-S6ORlfef.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Crnrr1-p.js → EmailListRenderer-mJViHjiq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-OpG9ZtfR.js → FamilyGuardDashboard-A4Lu5m_e.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B0sybW7G.js → Federation-Bv-6737r.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DjHMvxwJ.js → FormItemContext-DNcZoiWu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DtU5cWwE.js → GenericCardRenderer-B_a0l9U4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BhOjZX2a.js → Git-BbVAsh_N.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D3_hjjA-.js → Governance-ChxUMZEU.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DwxLXmgA.js → Inference-Buu_bAQ-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C8-FVs02.js → KnowledgeGraph-BMmMjxEu.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CrHjnzfr.js → Logs-BeGHcPEC.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-KW1Am18o.js → Marketplace-CP2Qg_xJ.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-ezYH1J8m.js → McpTools-C42B4JYb.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-Dcv8Gume.js → Memory-D5VeitFY.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-v18J0LN4.js → MobileBridge-BouoJ2FQ.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-kk6hAwkK.js → MobileProjects-mAJsyk7U.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Cm35-vh_.js → Mtc-Chn6ES5y.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-DyeKAlI_.js → MtcAudit-D0_Q6GEn.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-Dy-imleB.js → Multisig-BWaCi_wo.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DMVmWNAH.js → NLProgramming-CoSEiroa.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dq6oHKbl.js → Notes-CiqCbDw3.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CCaSupDi.js → NotificationSettings-BXmzKL9F.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BhlKyGrE.js +1 -0
- package/src/assets/web-panel/assets/{Organization-8TF96XtV.js → Organization-CAVgSxyI.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BnYnh84b.js → Overflow-BIVUo8YB.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CZk3Qkec.js → P2P-DX-Ov-eJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D1HrzBx2.js → PdhVaultBrowser-6clRu-J6.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CwJ6hcaI.js → Permissions-CANl-V55.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BGnPTj1G.js → PersonalDataHub-BE90gjUO.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BzXhXLBz.js → Pipeline-Ck8lV8Pn.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BaVQ3GwL.js → Privacy-BBYUDK4T.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bik3h4R7.js → ProjectInit-DcbOrnbt.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CIuC6Hpr.js → ProjectSettings-DZ6-whxP.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DO25SEFT.js +1 -0
- package/src/assets/web-panel/assets/{Providers-mhxZrHiK.js → Providers-VWoO_Y9u.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Dk9mayL0.js → QuickAsk-RJfSXWYg.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BHC2sBZY.js → Recommend-Y7MWWkXa.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DV26B11J.js → Reputation-nG8nut3l.js} +1 -1
- package/src/assets/web-panel/assets/{Row-bJlVEnFC.js → Row-DAio6Dx2.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D_XucmWY.js → RssFeed-DwY72Lc7.js} +2 -2
- package/src/assets/web-panel/assets/{Search-uKXcm_Kf.js → Search-qGG6AUWY.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DEzqsQLn.js → Security-Djsmom8n.js} +3 -3
- package/src/assets/web-panel/assets/{Services-I8qKgcom.js → Services-DTEgHkUO.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BmrglBMu.js → Skeleton-R5xY0J9Y.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CHN4ZDyP.js → Skills-CFaRLO3o.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Ca6FsUS2.js → Sla-B5bzoY1I.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CP8IikWb.js → SpeechSettings-B_al6SiQ.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bqp-kPAA.js → SyncSettings-DkUU63oJ.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-C2y4XdrQ.js +1 -0
- package/src/assets/web-panel/assets/{Templates-Bq51Irli.js → Templates-CcYJxTNB.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-OTducEVg.js → Tenant-B0_sIpl2.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-B_waZb0O.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-kCmFL2wc.js → TimelineRenderer-DuMkErBx.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BUfD650M.js → Tokens-BXjPA6rV.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CqpM6xE7.js → Trigger-BMAAx3Uu.js} +1 -1
- package/src/assets/web-panel/assets/{Trust--4gS7a0j.js → Trust-BPeNXpsi.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B7wfki-b.js → UkeySign-A0qabV14.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-FwDEX2S-.js → VideoEditing-BMLfYykd.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DS_c2rMk.js → Wallet-BfDI3zjs.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CdMhP-GP.js → WebAuthn-BCnZEScW.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DVvpoOmg.js → WorkflowEditor-DvtS5Asf.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BQyTT2BS.js → chat-CDJZtBM7.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DvylfUTx.js → colors-fbH1Saco.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Budvh2nW.js → compact-item-CuZFa9l8.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DkNa84zG.js → createContext-CQuPOqqD.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-mhGhHpNs.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Dc1juUIf.js → hasIn-CDZlDrhJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0u5DW4Z.js → index--SCX46Az.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGHLsKyb.js → index-14gri6Vh.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEviVulf.js → index-BJCXJCUA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbCIBifY.js → index-BKaue5Pv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRNJnXik.js → index-BNEG9-EK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTnZ44a_.js → index-BSy0noke.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxCPTrC-.js → index-BdORz0iZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DecFF9je.js → index-BhZkMMey.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFMS9PKh.js → index-BivMeInw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCD2L2SI.js → index-Bt1j0mjJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BC08UMEf.js → index-Bz5_6E63.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgxdM7b_.js → index-BzIDfObk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz41iB_M.js → index-C6epsHef.js} +1 -1
- package/src/assets/web-panel/assets/{index-jTGSFnNF.js → index-CAzMdnkI.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgYKjtNP.js → index-CD9ml9ZJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DwJ0d_2Z.js → index-CNmJrCxV.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8he-Xo0.js → index-COSyGm80.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQJA__yH.js → index-CQ5FVEji.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKoWcis9.js → index-CdiNFWPp.js} +1 -1
- package/src/assets/web-panel/assets/{index-eD_MN29w.js → index-CkhudJH0.js} +1 -1
- package/src/assets/web-panel/assets/{index-By8Bs_eN.js → index-CmeO_DfK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTzrvuB0.js → index-CnfR7qmj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_0nyIY9.js → index-Cr_shi_7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7FYxxFT.js → index-CzeRvhia.js} +3 -3
- package/src/assets/web-panel/assets/{index-BCv_FUY5.js → index-D365qmj8.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1X5QpSy.js → index-DGAK9Dj4.js} +1 -1
- package/src/assets/web-panel/assets/index-DGBjZXvW.js +1 -0
- package/src/assets/web-panel/assets/{index-DMCqz0wy.js → index-DNN-xBWV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTcZkWJ7.js → index-Deqod8La.js} +1 -1
- package/src/assets/web-panel/assets/{index-TsPv8m1Z.js → index-DhFyStIG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYuozZuh.js → index-DjgZRX0_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2dcbmzD.js → index-Dkuecn17.js} +1 -1
- package/src/assets/web-panel/assets/index-DujMkFuc.js +1 -0
- package/src/assets/web-panel/assets/{index-yx5Y6xb7.js → index-DvBgQoaw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bk_Uhu49.js → index-DwAiu9LT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWcGURYh.js → index-WDQkyh-E.js} +1 -1
- package/src/assets/web-panel/assets/{index-YVdWdhK_.js → index-kGzPbvry.js} +1 -1
- package/src/assets/web-panel/assets/{index-D74oTZL7.js → index-oe9ZPRtQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO9Lvv1w.js → index-ycBlRXAf.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-gLjyJG0Q.js → initDefaultProps-DHRWNV-y.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BtXv1r2p.js → motion-MJ2jhdVO.js} +1 -1
- package/src/assets/web-panel/assets/{move-BgFqW2gA.js → move-Bly0QFE5.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CeIwl-eJ.js → omit-DkoMB0pZ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-VlY4igbs.js → pickAttrs-9M-gsXIc.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B9Wjn3oR.js → placementArrow-Bnht1xci.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BBgHTvYX.js → responsiveObserve-B0Cn1i64.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DWw81KAi.js → slide-BdI4DDyM.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bsho38w-.js → statusUtils-DdBktcMD.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BNvVEdm1.js → styleChecker-aYEwS4Pw.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DG9bkwrT.js → useFlexGapSupport-y8cUyKiP.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DU7qrIrQ.js → useFs-Bk1SrPFp.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DX-Bf7VJ.js → usePersonalDataHub-Dp04zAB3.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B1UcnNoK.js → vnode-B52a38TC.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BFgJuvLv.js → zoom-DFwyL43U.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +62 -0
- package/src/lib/agent-worktree.js +78 -0
- package/src/lib/ide-context.js +168 -0
- package/src/lib/memory-injection.js +2 -0
- package/src/lib/safe-mode.js +31 -0
- package/src/lib/sensitive-file-guard.js +58 -0
- package/src/lib/settings-hooks.cjs +5 -0
- package/src/lib/sub-agent-context.js +3 -0
- package/src/repl/agent-repl.js +72 -17
- package/src/repl/ide-status.js +76 -0
- package/src/runtime/agent-core.js +76 -0
- package/src/runtime/headless-runner.js +11 -2
- package/src/runtime/headless-stream.js +48 -5
- package/src/assets/web-panel/assets/OrderTableRenderer-DOwptdNb.js +0 -1
- package/src/assets/web-panel/assets/Projects-DLjnWEe6.js +0 -1
- package/src/assets/web-panel/assets/Tasks-C7FvJjze.js +0 -1
- package/src/assets/web-panel/assets/Terminal-ywwPryM5.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CG_75MBJ.js +0 -1
- package/src/assets/web-panel/assets/index-Ba6DLEa1.js +0 -1
- package/src/assets/web-panel/assets/index-CLycnSs-.js +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc agent --safe-mode` — Claude-Code 2.1.169 parity ("--safe-mode flag
|
|
3
|
+
* disables customizations"): one flag flips every customization kill-switch
|
|
4
|
+
* so a misbehaving hook / memory file / persona can be isolated by running
|
|
5
|
+
* the agent bare.
|
|
6
|
+
*
|
|
7
|
+
* Deliberate divergence from Claude Code: settings PERMISSION RULES stay
|
|
8
|
+
* active — deny rules are a safety surface, and "debug my customizations"
|
|
9
|
+
* must never widen what the agent may do.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** env switches applied by --safe-mode (all existing kill-switches). */
|
|
13
|
+
export const SAFE_MODE_SWITCHES = Object.freeze({
|
|
14
|
+
CC_PROJECT_MEMORY: "0", // cc.md / CLAUDE.md / rules auto-load
|
|
15
|
+
CC_SETTINGS_HOOKS: "0", // .claude/settings.json hooks
|
|
16
|
+
CC_MEMORY_INJECT: "0", // session-core startup memory recall
|
|
17
|
+
CC_IDE_CONTEXT: "0", // <ide-context> injection + diagnostics feedback
|
|
18
|
+
CC_STATUSLINE: "0", // custom/built-in status line
|
|
19
|
+
CC_UPDATE_NOTICE: "0", // passive update nudge
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Apply safe mode to an env (default process.env).
|
|
24
|
+
* @returns {string[]} the switch names applied (for the startup notice)
|
|
25
|
+
*/
|
|
26
|
+
export function applySafeMode(env = process.env) {
|
|
27
|
+
for (const [k, v] of Object.entries(SAFE_MODE_SWITCHES)) {
|
|
28
|
+
env[k] = v;
|
|
29
|
+
}
|
|
30
|
+
return Object.keys(SAFE_MODE_SWITCHES);
|
|
31
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitive-file write guard — Claude-Code 2.1.160 parity ("prompts before
|
|
3
|
+
* writing to shell startup files").
|
|
4
|
+
*
|
|
5
|
+
* Writing a shell startup file, PowerShell profile, or git hook plants code
|
|
6
|
+
* that EXECUTES on the user's next shell/commit — a step up from a normal
|
|
7
|
+
* edit, so even pre-authorized edit flows must confirm first. The check is
|
|
8
|
+
* name-based (basename / well-known relative fragments), deliberately
|
|
9
|
+
* conservative: build configs like Makefile/package.json are everyday edits
|
|
10
|
+
* and are NOT flagged (false-positive fatigue would teach users to blind-OK).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const SHELL_STARTUP_NAMES = new Set([
|
|
14
|
+
".bashrc",
|
|
15
|
+
".bash_profile",
|
|
16
|
+
".bash_login",
|
|
17
|
+
".bash_logout",
|
|
18
|
+
".profile",
|
|
19
|
+
".zshrc",
|
|
20
|
+
".zshenv",
|
|
21
|
+
".zprofile",
|
|
22
|
+
".zlogin",
|
|
23
|
+
".zlogout",
|
|
24
|
+
".cshrc",
|
|
25
|
+
".tcshrc",
|
|
26
|
+
".kshrc",
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const POWERSHELL_PROFILE_RE = /(^|[\\/])(microsoft\.powershell_profile\.ps1|profile\.ps1)$/i;
|
|
30
|
+
const FISH_CONFIG_RE = /[\\/]fish[\\/]config\.fish$/i;
|
|
31
|
+
const GIT_HOOK_RE = /[\\/]\.git[\\/]hooks[\\/][^\\/]+$/i;
|
|
32
|
+
const HUSKY_HOOK_RE = /[\\/]\.husky[\\/](?!_)[^\\/]+$/i;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} targetPath path as the tool received it (rel or abs)
|
|
36
|
+
* @returns {string|null} human reason when sensitive, null otherwise
|
|
37
|
+
*/
|
|
38
|
+
export function sensitiveFileReason(targetPath) {
|
|
39
|
+
const p = String(targetPath || "");
|
|
40
|
+
if (!p) return null;
|
|
41
|
+
const base = p.replace(/\\/g, "/").split("/").pop() || "";
|
|
42
|
+
if (SHELL_STARTUP_NAMES.has(base)) {
|
|
43
|
+
return `shell startup file (${base}) — runs on the user's next shell`;
|
|
44
|
+
}
|
|
45
|
+
if (POWERSHELL_PROFILE_RE.test(p)) {
|
|
46
|
+
return "PowerShell profile — runs on the user's next PowerShell session";
|
|
47
|
+
}
|
|
48
|
+
if (FISH_CONFIG_RE.test(p)) {
|
|
49
|
+
return "fish shell config — runs on the user's next shell";
|
|
50
|
+
}
|
|
51
|
+
if (GIT_HOOK_RE.test(p)) {
|
|
52
|
+
return "git hook — executes on the user's next git operation";
|
|
53
|
+
}
|
|
54
|
+
if (HUSKY_HOOK_RE.test(p)) {
|
|
55
|
+
return "husky hook — executes on the user's next git operation";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
@@ -76,6 +76,11 @@ function readJson(file, onWarn) {
|
|
|
76
76
|
function loadHooks({ cwd = process.cwd(), settingsFile, onWarn } = {}) {
|
|
77
77
|
const merged = {};
|
|
78
78
|
const files = [];
|
|
79
|
+
// Safe-mode kill switch (`cc agent --safe-mode` sets CC_SETTINGS_HOOKS=0):
|
|
80
|
+
// run with NO settings hooks so a broken hook can be diagnosed.
|
|
81
|
+
if (process.env.CC_SETTINGS_HOOKS === "0") {
|
|
82
|
+
return { hooks: merged, files };
|
|
83
|
+
}
|
|
79
84
|
for (const file of settingsFiles(cwd, settingsFile)) {
|
|
80
85
|
const data = readJson(file, onWarn);
|
|
81
86
|
const block =
|
|
@@ -73,6 +73,7 @@ export class SubAgentContext {
|
|
|
73
73
|
this.tokenBudget = options.tokenBudget || null;
|
|
74
74
|
this.inheritedContext = options.inheritedContext || null;
|
|
75
75
|
this.allowedTools = options.allowedTools || null; // null = all
|
|
76
|
+
this.depth = options.depth || 1; // nesting level (parent main loop = 0)
|
|
76
77
|
this.cwd = options.cwd || process.cwd();
|
|
77
78
|
this.status = "active";
|
|
78
79
|
this.result = null;
|
|
@@ -249,6 +250,8 @@ export class SubAgentContext {
|
|
|
249
250
|
...this._llmOptions,
|
|
250
251
|
contextEngine: this.contextEngine,
|
|
251
252
|
cwd: this.cwd,
|
|
253
|
+
// Nesting level: lets a nested spawn_sub_agent see — and cap — its depth.
|
|
254
|
+
subAgentDepth: this.depth,
|
|
252
255
|
...loopOptions,
|
|
253
256
|
};
|
|
254
257
|
if (this.iterationBudget) {
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -761,6 +761,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
761
761
|
"/cowork",
|
|
762
762
|
"/exit",
|
|
763
763
|
"/help",
|
|
764
|
+
"/ide",
|
|
764
765
|
"/mcp",
|
|
765
766
|
"/model",
|
|
766
767
|
"/output-style",
|
|
@@ -769,6 +770,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
769
770
|
"/provider",
|
|
770
771
|
"/quit",
|
|
771
772
|
"/reindex",
|
|
773
|
+
"/reload-skills",
|
|
772
774
|
"/rewind",
|
|
773
775
|
"/search",
|
|
774
776
|
"/session",
|
|
@@ -953,8 +955,16 @@ export async function startAgentRepl(options = {}) {
|
|
|
953
955
|
const { runBangCommand } = await import("../lib/repl-bang-memorize.js");
|
|
954
956
|
const res = runBangCommand(trimmed, { cwd: process.cwd() });
|
|
955
957
|
logger.log(chalk.gray(`$ ${res.cmd}`));
|
|
956
|
-
if (res.stdout)
|
|
957
|
-
|
|
958
|
+
if (res.stdout)
|
|
959
|
+
process.stdout.write(
|
|
960
|
+
res.stdout.endsWith("\n") ? res.stdout : `${res.stdout}\n`,
|
|
961
|
+
);
|
|
962
|
+
if (res.stderr)
|
|
963
|
+
process.stderr.write(
|
|
964
|
+
chalk.red(
|
|
965
|
+
res.stderr.endsWith("\n") ? res.stderr : `${res.stderr}\n`,
|
|
966
|
+
),
|
|
967
|
+
);
|
|
958
968
|
if (res.error) logger.error(`shell error: ${res.error.message}`);
|
|
959
969
|
logger.log(chalk.gray(`(exit ${res.exitCode})`));
|
|
960
970
|
messages.push(res.contextMessage);
|
|
@@ -969,14 +979,17 @@ export async function startAgentRepl(options = {}) {
|
|
|
969
979
|
// cc.md (auto-loaded next session) and keep it active in this one.
|
|
970
980
|
if (trimmed.startsWith("#") && trimmed.slice(1).trim()) {
|
|
971
981
|
try {
|
|
972
|
-
const { appendMemoryNote } =
|
|
982
|
+
const { appendMemoryNote } =
|
|
983
|
+
await import("../lib/repl-bang-memorize.js");
|
|
973
984
|
const res = appendMemoryNote(trimmed, { cwd: process.cwd() });
|
|
974
985
|
messages.push({
|
|
975
986
|
role: "system",
|
|
976
987
|
content: `<memory-note source="${res.target}">${res.note}</memory-note>`,
|
|
977
988
|
});
|
|
978
989
|
logger.log(
|
|
979
|
-
chalk.green(
|
|
990
|
+
chalk.green(
|
|
991
|
+
`✔ remembered in ${res.target}${res.created ? " (created)" : ""}`,
|
|
992
|
+
),
|
|
980
993
|
);
|
|
981
994
|
} catch (err) {
|
|
982
995
|
logger.error(`# memorize failed: ${err.message}`);
|
|
@@ -1018,6 +1031,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
1018
1031
|
logger.log(
|
|
1019
1032
|
` ${chalk.cyan("/cd <dir>")} Change working directory mid-session (completion/memory follow)`,
|
|
1020
1033
|
);
|
|
1034
|
+
logger.log(
|
|
1035
|
+
` ${chalk.cyan("/reload-skills")} Re-scan skill layers without restarting`,
|
|
1036
|
+
);
|
|
1021
1037
|
logger.log(
|
|
1022
1038
|
` ${chalk.cyan("/compact")} Smart compact (importance-based)`,
|
|
1023
1039
|
);
|
|
@@ -1055,6 +1071,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
1055
1071
|
logger.log(
|
|
1056
1072
|
` ${chalk.cyan("/sub-agents")} Show active/completed sub-agents`,
|
|
1057
1073
|
);
|
|
1074
|
+
logger.log(
|
|
1075
|
+
` ${chalk.cyan("/ide")} IDE bridge status (connected editor, tools, or why not)`,
|
|
1076
|
+
);
|
|
1058
1077
|
logger.log(chalk.bold("\nCapabilities:"));
|
|
1059
1078
|
logger.log(" Read, write, and edit files");
|
|
1060
1079
|
logger.log(" Run shell commands (git, npm, etc.)");
|
|
@@ -1278,14 +1297,11 @@ export async function startAgentRepl(options = {}) {
|
|
|
1278
1297
|
|
|
1279
1298
|
if (trimmed === "/rewind" || trimmed.startsWith("/rewind ")) {
|
|
1280
1299
|
try {
|
|
1281
|
-
const { listUserTurns, rewindToTurn, renderTurnList } =
|
|
1282
|
-
"../lib/repl-rewind.js"
|
|
1283
|
-
);
|
|
1300
|
+
const { listUserTurns, rewindToTurn, renderTurnList } =
|
|
1301
|
+
await import("../lib/repl-rewind.js");
|
|
1284
1302
|
const arg = trimmed.slice("/rewind".length).trim();
|
|
1285
1303
|
if (!arg) {
|
|
1286
|
-
logger.log(
|
|
1287
|
-
chalk.bold("\nRewind — pick a user turn (newest first):"),
|
|
1288
|
-
);
|
|
1304
|
+
logger.log(chalk.bold("\nRewind — pick a user turn (newest first):"));
|
|
1289
1305
|
logger.log(renderTurnList(listUserTurns(messages)));
|
|
1290
1306
|
logger.log(
|
|
1291
1307
|
chalk.gray(
|
|
@@ -1320,9 +1336,8 @@ export async function startAgentRepl(options = {}) {
|
|
|
1320
1336
|
// window. Reuses the same categorizer + estimator as the archived view.
|
|
1321
1337
|
try {
|
|
1322
1338
|
const { categorizeContext } = await import("../commands/context.js");
|
|
1323
|
-
const { estimateTokens } =
|
|
1324
|
-
"../harness/prompt-compressor.js"
|
|
1325
|
-
);
|
|
1339
|
+
const { estimateTokens } =
|
|
1340
|
+
await import("../harness/prompt-compressor.js");
|
|
1326
1341
|
const { buckets, counts, total } = categorizeContext(
|
|
1327
1342
|
messages,
|
|
1328
1343
|
estimateTokens,
|
|
@@ -1462,6 +1477,24 @@ export async function startAgentRepl(options = {}) {
|
|
|
1462
1477
|
}
|
|
1463
1478
|
|
|
1464
1479
|
// Reindex notes
|
|
1480
|
+
// `/reload-skills` (Claude-Code 2.1.152 parity): re-scan the 6 skill
|
|
1481
|
+
// layers (incl. .claude/skills) without restarting the session.
|
|
1482
|
+
if (trimmed === "/reload-skills") {
|
|
1483
|
+
try {
|
|
1484
|
+
const { reloadSkills } = await import("../runtime/agent-core.js");
|
|
1485
|
+
const n = reloadSkills();
|
|
1486
|
+
logger.log(
|
|
1487
|
+
chalk.green(
|
|
1488
|
+
`✔ skills reloaded — ${n} available (6 layers re-scanned)`,
|
|
1489
|
+
),
|
|
1490
|
+
);
|
|
1491
|
+
} catch (err) {
|
|
1492
|
+
logger.error(`/reload-skills failed: ${err.message}`);
|
|
1493
|
+
}
|
|
1494
|
+
prompt();
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1465
1498
|
if (trimmed === "/reindex") {
|
|
1466
1499
|
if (contextEngine) {
|
|
1467
1500
|
contextEngine.reindexNotes();
|
|
@@ -2085,6 +2118,22 @@ export async function startAgentRepl(options = {}) {
|
|
|
2085
2118
|
return;
|
|
2086
2119
|
}
|
|
2087
2120
|
|
|
2121
|
+
// `/ide` — IDE bridge connection status (Claude-Code parity): which editor
|
|
2122
|
+
// is connected, its tools, or why discovery came up empty.
|
|
2123
|
+
if (trimmed === "/ide" || trimmed === "/ide ") {
|
|
2124
|
+
let diag = null;
|
|
2125
|
+
try {
|
|
2126
|
+
const { diagnoseIde } = await import("../lib/ide-bridge.js");
|
|
2127
|
+
diag = diagnoseIde({ cwd: process.cwd(), env: process.env });
|
|
2128
|
+
} catch (_err) {
|
|
2129
|
+
// discovery is best-effort — fall back to in-session tools only
|
|
2130
|
+
}
|
|
2131
|
+
const { renderIdeStatus } = await import("./ide-status.js");
|
|
2132
|
+
logger.log(renderIdeStatus(_adhocMcp, diag));
|
|
2133
|
+
prompt();
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2088
2137
|
// User-defined slash-command macros (.claude/commands/*.md), Claude-Code
|
|
2089
2138
|
// parity. resolveSlashMacro maps a leading /name to a command macro and
|
|
2090
2139
|
// expands its template; a non-match returns the line unchanged so a literal
|
|
@@ -2201,9 +2250,17 @@ export async function startAgentRepl(options = {}) {
|
|
|
2201
2250
|
// Ephemeral: persistence stores effectivePrompt, not this snapshot.
|
|
2202
2251
|
// Best-effort; CC_IDE_CONTEXT=0 disables.
|
|
2203
2252
|
try {
|
|
2204
|
-
const { buildIdePromptContext } =
|
|
2253
|
+
const { buildIdePromptContext, expandIdeMentions } =
|
|
2254
|
+
await import("../lib/ide-context.js");
|
|
2205
2255
|
const ideCtx = await buildIdePromptContext(_adhocMcp);
|
|
2206
2256
|
if (ideCtx) userContent += `\n\n${ideCtx}`;
|
|
2257
|
+
// Explicit @selection / @diagnostics mentions (Claude-Code parity);
|
|
2258
|
+
// scan the user's original prompt, append the expansion ephemerally.
|
|
2259
|
+
const mentioned = await expandIdeMentions(effectivePrompt, _adhocMcp);
|
|
2260
|
+
for (const w of mentioned.warnings) {
|
|
2261
|
+
logger.info(chalk.yellow(`[@ide] ${w}`));
|
|
2262
|
+
}
|
|
2263
|
+
if (mentioned.block) userContent += `\n\n${mentioned.block}`;
|
|
2207
2264
|
} catch (_err) {
|
|
2208
2265
|
// optional polish — never fail the turn over it
|
|
2209
2266
|
}
|
|
@@ -2433,9 +2490,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
2433
2490
|
// Esc interrupt: an aborted turn is normal flow, not an error — the
|
|
2434
2491
|
// partial conversation stays usable and queued lines still drain.
|
|
2435
2492
|
if (err?.name === "AbortError" || /abort/i.test(err?.message || "")) {
|
|
2436
|
-
logger.log(
|
|
2437
|
-
chalk.yellow("⎋ turn interrupted — partial progress kept"),
|
|
2438
|
-
);
|
|
2493
|
+
logger.log(chalk.yellow("⎋ turn interrupted — partial progress kept"));
|
|
2439
2494
|
prompt();
|
|
2440
2495
|
return;
|
|
2441
2496
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/ide` REPL command renderer (Claude-Code parity) — report whether an IDE
|
|
3
|
+
* bridge is connected to THIS agent session, which editor/port/workspace it
|
|
4
|
+
* is, the IDE tools the agent can call, and — when nothing is connected — why
|
|
5
|
+
* discovery came up empty plus how to fix it.
|
|
6
|
+
*
|
|
7
|
+
* Pure and dependency-free: takes the resolved MCP bundle (for the live,
|
|
8
|
+
* in-session connection) and an optional `diagnoseIde()` result (for lockfile
|
|
9
|
+
* details), returns plain text. The REPL does the I/O.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const IDE_PREFIX = "mcp__ide__";
|
|
13
|
+
|
|
14
|
+
/** Sorted bare IDE tool names connected in this session (e.g. ["getSelection"]). */
|
|
15
|
+
export function ideToolNames(mcp) {
|
|
16
|
+
const ex = (mcp && mcp.externalToolExecutors) || {};
|
|
17
|
+
return Object.keys(ex)
|
|
18
|
+
.filter((k) => k.startsWith(IDE_PREFIX) && ex[k] && ex[k].kind === "mcp")
|
|
19
|
+
.map((k) => k.slice(IDE_PREFIX.length))
|
|
20
|
+
.sort();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object|null} mcp resolved bundle from resolveAgentMcp (or null)
|
|
25
|
+
* @param {object|null} diag diagnoseIde() result, or null when unavailable
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
export function renderIdeStatus(mcp, diag = null) {
|
|
29
|
+
const tools = ideToolNames(mcp);
|
|
30
|
+
const chosen = diag && diag.chosen ? diag.chosen : null;
|
|
31
|
+
const lines = [];
|
|
32
|
+
|
|
33
|
+
if (tools.length > 0) {
|
|
34
|
+
const where = chosen
|
|
35
|
+
? `${chosen.ide || "ide"} on 127.0.0.1:${chosen.port} (${chosen.transport})`
|
|
36
|
+
: "an editor extension";
|
|
37
|
+
lines.push(`● IDE bridge connected — ${where}`);
|
|
38
|
+
if (
|
|
39
|
+
chosen &&
|
|
40
|
+
Array.isArray(chosen.workspaceFolders) &&
|
|
41
|
+
chosen.workspaceFolders.length
|
|
42
|
+
) {
|
|
43
|
+
lines.push(` workspace: ${chosen.workspaceFolders.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
lines.push(` tools: ${tools.map((t) => IDE_PREFIX + t).join(", ")}`);
|
|
46
|
+
lines.push(
|
|
47
|
+
" selection/diagnostics auto-share each turn · " +
|
|
48
|
+
"@selection / @diagnostics expand on demand",
|
|
49
|
+
);
|
|
50
|
+
return lines.join("\n");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
lines.push("○ IDE bridge not connected to this session");
|
|
54
|
+
if (diag) {
|
|
55
|
+
if (diag.reason) lines.push(` ${diag.reason}`);
|
|
56
|
+
if (Array.isArray(diag.locks) && diag.locks.length) {
|
|
57
|
+
lines.push(` ${diag.locks.length} lockfile(s) in ${diag.lockDir}:`);
|
|
58
|
+
for (const l of diag.locks.slice(0, 5)) {
|
|
59
|
+
lines.push(
|
|
60
|
+
` - ${l.ide || "?"} :${l.port} ${l.transport} ` +
|
|
61
|
+
`(matchScore ${l.matchScore})`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
lines.push(
|
|
66
|
+
diag.inIdeTerminal
|
|
67
|
+
? " you're in an IDE terminal — restart the agent so it re-discovers the bridge"
|
|
68
|
+
: " launch `cc` from your IDE's integrated terminal, or pass --ide to force-connect",
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
lines.push(
|
|
72
|
+
" install the ChainlessChain IDE extension, then launch cc from its terminal",
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return lines.join("\n");
|
|
76
|
+
}
|
|
@@ -334,6 +334,16 @@ export function getAgentToolDescriptors(options = {}) {
|
|
|
334
334
|
|
|
335
335
|
const _defaultSkillLoader = new CLISkillLoader();
|
|
336
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Re-scan all skill layers (Claude-Code `/reload-skills` parity): drops the
|
|
339
|
+
* default loader's cache so newly added/edited SKILL.md dirs are picked up
|
|
340
|
+
* without restarting the session. Returns the resolved skill count.
|
|
341
|
+
*/
|
|
342
|
+
export function reloadSkills() {
|
|
343
|
+
_defaultSkillLoader.clearCache();
|
|
344
|
+
return _defaultSkillLoader.loadAll().length;
|
|
345
|
+
}
|
|
346
|
+
|
|
337
347
|
// ─── Cached environment detection ────────────────────────────────────────
|
|
338
348
|
|
|
339
349
|
let _cachedPython = null;
|
|
@@ -901,6 +911,40 @@ export async function executeTool(name, args, context = {}) {
|
|
|
901
911
|
ruleAllowed = true;
|
|
902
912
|
}
|
|
903
913
|
|
|
914
|
+
// Sensitive-file write guard (Claude-Code 2.1.160 parity): shell startup
|
|
915
|
+
// files / PowerShell profiles / git+husky hooks execute code on the user's
|
|
916
|
+
// next shell or commit — even otherwise-permitted edit flows confirm first.
|
|
917
|
+
// An explicit settings `allow` rule is the only bypass (exact user
|
|
918
|
+
// pre-authorization); headless without a confirmer fails closed.
|
|
919
|
+
if (
|
|
920
|
+
(name === "write_file" || name === "edit_file") &&
|
|
921
|
+
settingsVerdict.decision !== "allow" &&
|
|
922
|
+
args?.path
|
|
923
|
+
) {
|
|
924
|
+
const { sensitiveFileReason } = await import(
|
|
925
|
+
"../lib/sensitive-file-guard.js"
|
|
926
|
+
);
|
|
927
|
+
const sensReason = sensitiveFileReason(args.path);
|
|
928
|
+
if (sensReason) {
|
|
929
|
+
const confirm = context.permissionConfirm || context.shellConfirm || null;
|
|
930
|
+
const ok =
|
|
931
|
+
typeof confirm === "function"
|
|
932
|
+
? await confirm({
|
|
933
|
+
tool: name,
|
|
934
|
+
args,
|
|
935
|
+
rule: null,
|
|
936
|
+
reason: `sensitive file: ${sensReason}`,
|
|
937
|
+
})
|
|
938
|
+
: false;
|
|
939
|
+
if (!ok) {
|
|
940
|
+
return {
|
|
941
|
+
error: `[Sensitive File] Writing "${args.path}" requires confirmation (${sensReason}) — denied. Add a settings allow rule to pre-authorize.`,
|
|
942
|
+
policy: { decision: "ask", via: "sensitive-file" },
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
904
948
|
// Plan mode: check if tool is allowed (a settings `allow` rule pre-authorizes)
|
|
905
949
|
if (
|
|
906
950
|
planManager.isActive() &&
|
|
@@ -980,6 +1024,7 @@ export async function executeTool(name, args, context = {}) {
|
|
|
980
1024
|
shellConfirm: context.shellConfirm || null,
|
|
981
1025
|
additionalDirectories: context.additionalDirectories || null,
|
|
982
1026
|
ruleAllowed,
|
|
1027
|
+
subAgentDepth: context.subAgentDepth || 0,
|
|
983
1028
|
});
|
|
984
1029
|
} catch (err) {
|
|
985
1030
|
if (hookDb) {
|
|
@@ -1150,6 +1195,7 @@ async function executeToolInner(
|
|
|
1150
1195
|
shellConfirm,
|
|
1151
1196
|
additionalDirectories,
|
|
1152
1197
|
ruleAllowed = false,
|
|
1198
|
+
subAgentDepth = 0,
|
|
1153
1199
|
},
|
|
1154
1200
|
) {
|
|
1155
1201
|
const localToolDescriptor =
|
|
@@ -1363,6 +1409,11 @@ async function executeToolInner(
|
|
|
1363
1409
|
cwd: task.cwd,
|
|
1364
1410
|
shell: true,
|
|
1365
1411
|
windowsHide: true,
|
|
1412
|
+
// Same CC_SESSION_ID correlation as the foreground path.
|
|
1413
|
+
env: {
|
|
1414
|
+
...process.env,
|
|
1415
|
+
...(sessionId ? { CC_SESSION_ID: String(sessionId) } : {}),
|
|
1416
|
+
},
|
|
1366
1417
|
// POSIX: own process group so check_shell{kill}/teardown can signal
|
|
1367
1418
|
// the whole tree (shell + its grandchild command). No-op on Windows
|
|
1368
1419
|
// where the tree is killed via taskkill /T instead.
|
|
@@ -1420,6 +1471,12 @@ async function executeToolInner(
|
|
|
1420
1471
|
encoding: "utf8",
|
|
1421
1472
|
timeout: _resolveShellTimeout(args.timeout),
|
|
1422
1473
|
maxBuffer: 1024 * 1024,
|
|
1474
|
+
// CC_SESSION_ID (Claude-Code CLAUDE_CODE_SESSION_ID parity,
|
|
1475
|
+
// 2.1.132): lets scripts/hooks correlate work to the agent session.
|
|
1476
|
+
env: {
|
|
1477
|
+
...process.env,
|
|
1478
|
+
...(sessionId ? { CC_SESSION_ID: String(sessionId) } : {}),
|
|
1479
|
+
},
|
|
1423
1480
|
});
|
|
1424
1481
|
return attachDescriptor(
|
|
1425
1482
|
{
|
|
@@ -1528,6 +1585,7 @@ async function executeToolInner(
|
|
|
1528
1585
|
interaction,
|
|
1529
1586
|
sessionId,
|
|
1530
1587
|
llmOptions,
|
|
1588
|
+
subAgentDepth,
|
|
1531
1589
|
}),
|
|
1532
1590
|
);
|
|
1533
1591
|
}
|
|
@@ -2186,6 +2244,13 @@ async function _executeRunCode(args, cwd) {
|
|
|
2186
2244
|
|
|
2187
2245
|
// ─── spawn_sub_agent implementation ──────────────────────────────────────
|
|
2188
2246
|
|
|
2247
|
+
/**
|
|
2248
|
+
* Max sub-agent nesting depth (Claude-Code 2.1.172 parity: sub-agents may
|
|
2249
|
+
* spawn their own sub-agents, capped at 5 levels so a runaway model cannot
|
|
2250
|
+
* recurse forever). Main loop = depth 0, its children = 1, …
|
|
2251
|
+
*/
|
|
2252
|
+
export const MAX_SUB_AGENT_DEPTH = 5;
|
|
2253
|
+
|
|
2189
2254
|
/**
|
|
2190
2255
|
* Execute a spawn_sub_agent tool call.
|
|
2191
2256
|
* Creates an isolated SubAgentContext, runs it, and returns only the summary.
|
|
@@ -2195,6 +2260,13 @@ async function _executeRunCode(args, cwd) {
|
|
|
2195
2260
|
* @returns {Promise<object>}
|
|
2196
2261
|
*/
|
|
2197
2262
|
async function _executeSpawnSubAgent(args, ctx) {
|
|
2263
|
+
// Nesting cap: refuse before any context/registry work.
|
|
2264
|
+
const currentDepth = ctx.subAgentDepth || 0;
|
|
2265
|
+
if (currentDepth >= MAX_SUB_AGENT_DEPTH) {
|
|
2266
|
+
return {
|
|
2267
|
+
error: `spawn_sub_agent: max nesting depth (${MAX_SUB_AGENT_DEPTH}) reached — complete the task directly instead of delegating further.`,
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2198
2270
|
let {
|
|
2199
2271
|
role,
|
|
2200
2272
|
task,
|
|
@@ -2296,6 +2368,7 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
2296
2368
|
cwd: ctx.cwd,
|
|
2297
2369
|
profile: profile || null,
|
|
2298
2370
|
llmOptions: subLlmOptions,
|
|
2371
|
+
depth: currentDepth + 1, // nested spawns see their own level
|
|
2299
2372
|
});
|
|
2300
2373
|
|
|
2301
2374
|
const emit = (type, payload) => {
|
|
@@ -3332,6 +3405,9 @@ export async function* agentLoop(messages, options) {
|
|
|
3332
3405
|
autoCheckpoint: options.autoCheckpoint || false,
|
|
3333
3406
|
checkpointSession:
|
|
3334
3407
|
options.checkpointSession || options.sessionId || "agent",
|
|
3408
|
+
// Sub-agent nesting level (0 = main loop); spawn_sub_agent caps at
|
|
3409
|
+
// MAX_SUB_AGENT_DEPTH using this.
|
|
3410
|
+
subAgentDepth: options.subAgentDepth || 0,
|
|
3335
3411
|
};
|
|
3336
3412
|
|
|
3337
3413
|
throwIfAborted(signal);
|
|
@@ -552,15 +552,24 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
552
552
|
// session replays the prompt, not a stale editor snapshot. Best-effort with
|
|
553
553
|
// a short timeout; CC_IDE_CONTEXT=0 disables.
|
|
554
554
|
try {
|
|
555
|
-
const { buildIdePromptContext, appendTextToContent } =
|
|
555
|
+
const { buildIdePromptContext, appendTextToContent, expandIdeMentions } =
|
|
556
556
|
await import("../lib/ide-context.js");
|
|
557
|
+
const last = messages[messages.length - 1];
|
|
557
558
|
const ideCtx = await (deps.buildIdePromptContext || buildIdePromptContext)(
|
|
558
559
|
mcp,
|
|
559
560
|
);
|
|
560
561
|
if (ideCtx) {
|
|
561
|
-
const last = messages[messages.length - 1];
|
|
562
562
|
last.content = appendTextToContent(last.content, ideCtx);
|
|
563
563
|
}
|
|
564
|
+
// Explicit @selection / @diagnostics mentions in the user's prompt
|
|
565
|
+
// (Claude-Code parity). Scan the ORIGINAL prompt so injected file-ref
|
|
566
|
+
// blocks can't spoof a mention; append the expansion to the in-flight
|
|
567
|
+
// message only (ephemeral, like the ambient block above).
|
|
568
|
+
const mentioned = await expandIdeMentions(prompt, mcp);
|
|
569
|
+
for (const w of mentioned.warnings) writeErr(` @ide: ${w}\n`);
|
|
570
|
+
if (mentioned.block) {
|
|
571
|
+
last.content = appendTextToContent(last.content, mentioned.block);
|
|
572
|
+
}
|
|
564
573
|
} catch {
|
|
565
574
|
// IDE context is optional polish — never fail the run over it.
|
|
566
575
|
}
|
|
@@ -102,8 +102,21 @@ export function parseInputEvent(line) {
|
|
|
102
102
|
.map((b) => (typeof b === "string" ? b : b?.text || ""))
|
|
103
103
|
.join("");
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
// Vision input (chat-panel image paste): {"type":"user","text":…,
|
|
106
|
+
// "images":["/abs/file.png", …]} — file paths, resolved at turn build via
|
|
107
|
+
// the same image-input pipeline as `cc agent --image`.
|
|
108
|
+
const rawImages =
|
|
109
|
+
obj && typeof obj === "object" ? obj.images || msg.images : null;
|
|
110
|
+
const images = Array.isArray(rawImages)
|
|
111
|
+
? rawImages.filter((p) => typeof p === "string" && p.trim()).slice(0, 8)
|
|
112
|
+
: [];
|
|
113
|
+
if (typeof content !== "string" || !content.trim()) {
|
|
114
|
+
// An image-only turn is valid — give the model something to act on.
|
|
115
|
+
if (images.length)
|
|
116
|
+
return { text: "Please look at the attached image(s).", images };
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return images.length ? { text: content, images } : { text: content };
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
/**
|
|
@@ -718,19 +731,49 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
718
731
|
// IDE bridge is connected — the user's selection moves between prompts.
|
|
719
732
|
// Best-effort; CC_IDE_CONTEXT=0 disables.
|
|
720
733
|
try {
|
|
721
|
-
const { buildIdePromptContext } =
|
|
734
|
+
const { buildIdePromptContext, expandIdeMentions } =
|
|
735
|
+
await import("../lib/ide-context.js");
|
|
722
736
|
const ideCtx = await (
|
|
723
737
|
deps.buildIdePromptContext || buildIdePromptContext
|
|
724
738
|
)(mcp);
|
|
725
739
|
if (ideCtx) userContent += `\n\n${ideCtx}`;
|
|
740
|
+
// Explicit @selection / @diagnostics mentions (Claude-Code parity);
|
|
741
|
+
// scan the original user event text, append the expansion ephemerally.
|
|
742
|
+
const mentioned = await expandIdeMentions(parsed.text, mcp);
|
|
743
|
+
for (const w of mentioned.warnings) writeErr(` @ide: ${w}\n`);
|
|
744
|
+
if (mentioned.block) userContent += `\n\n${mentioned.block}`;
|
|
726
745
|
} catch {
|
|
727
746
|
// optional polish — never fail the turn over it
|
|
728
747
|
}
|
|
729
748
|
|
|
730
|
-
|
|
749
|
+
// Attach pasted/added images (panel parity with `--image`): file paths →
|
|
750
|
+
// data URLs → OpenAI-style multimodal content. buildUserContent returns
|
|
751
|
+
// the plain string when there are no images, so text turns are unchanged.
|
|
752
|
+
let turnContent = userContent;
|
|
753
|
+
if (parsed.images && parsed.images.length) {
|
|
754
|
+
try {
|
|
755
|
+
const { resolveImages, buildUserContent } =
|
|
756
|
+
await import("../lib/image-input.js");
|
|
757
|
+
turnContent = buildUserContent(
|
|
758
|
+
userContent,
|
|
759
|
+
resolveImages(parsed.images),
|
|
760
|
+
);
|
|
761
|
+
} catch (err) {
|
|
762
|
+
emit({
|
|
763
|
+
type: "result",
|
|
764
|
+
subtype: "error",
|
|
765
|
+
is_error: true,
|
|
766
|
+
result: `image attach failed: ${err.message}`,
|
|
767
|
+
session_id: sessionId,
|
|
768
|
+
});
|
|
769
|
+
continue; // bad attachment kills the turn, not the session
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
messages.push({ role: "user", content: turnContent });
|
|
731
774
|
if (persist) {
|
|
732
775
|
try {
|
|
733
|
-
store.appendUserMessage(sessionId,
|
|
776
|
+
store.appendUserMessage(sessionId, turnContent);
|
|
734
777
|
} catch {
|
|
735
778
|
/* best-effort */
|
|
736
779
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as w,P as l,J as u,U as s,R as n,c as i,K as v,Q as _,V as g,b as o}from"./vendor-BvqAck49.js";import{_ as S}from"./index-D7FYxxFT.js";import"./icons-DP3uiYxy.js";const k={__name:"OrderTableRenderer",props:{event:{type:Object,required:!0}},setup(p,{expose:r}){r();const a=p,e=o(()=>a.event.content||{}),d=o(()=>a.event.extra||{}),m=o(()=>d.value.merchant||e.value.merchant||e.value.counterparty||"—"),c=o(()=>e.value.title||e.value.name||e.value.itemName||e.value.text||"—"),y=o(()=>{const t=e.value.amount??e.value.price??e.value.total;return t==null?"—":`${e.value.currency||"¥"} ${typeof t=="number"?t.toFixed(2):t}`}),T=o(()=>d.value.orderNo||e.value.orderNo||e.value.orderId),f=o(()=>e.value.status||e.value.state),b=o(()=>{const t=(f.value||"").toLowerCase();return t.includes("成功")||t.includes("succe")||t.includes("paid")?"green":t.includes("退")||t.includes("refund")?"orange":t.includes("失败")||t.includes("fail")?"red":"default"}),h=o(()=>{if(!a.event.occurredAt)return"";const t=new Date(a.event.occurredAt);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}),x={props:a,c:e,e:d,merchantText:m,itemText:c,amountText:y,orderNo:T,statusText:f,statusColor:b,formattedTime:h,computed:o};return Object.defineProperty(x,"__isScriptSetup",{enumerable:!1,value:!0}),x}},N={class:"order-card"},C={class:"head"},O={class:"time"},V={class:"row"},R={class:"val"},B={class:"row"},D={class:"val"},I={class:"row amount-row"},j={class:"val amount"},A={key:0,class:"row"},F={class:"val mono"},H={key:1,class:"row"};function M(p,r,a,e,d,m){const c=w("a-tag");return l(),u("div",N,[s("div",C,[s("span",O,n(e.formattedTime),1),i(c,{color:"gold"},{default:v(()=>[_(n(a.event.source.adapter),1)]),_:1}),i(c,null,{default:v(()=>[_(n(a.event.subtype),1)]),_:1})]),s("div",V,[r[0]||(r[0]=s("span",{class:"key"},"商户",-1)),s("span",R,n(e.merchantText),1)]),s("div",B,[r[1]||(r[1]=s("span",{class:"key"},"商品/项目",-1)),s("span",D,n(e.itemText),1)]),s("div",I,[r[2]||(r[2]=s("span",{class:"key"},"金额",-1)),s("span",j,n(e.amountText),1)]),e.orderNo?(l(),u("div",A,[r[3]||(r[3]=s("span",{class:"key"},"单号",-1)),s("span",F,n(e.orderNo),1)])):g("v-if",!0),e.statusText?(l(),u("div",H,[r[4]||(r[4]=s("span",{class:"key"},"状态",-1)),i(c,{color:e.statusColor},{default:v(()=>[_(n(e.statusText),1)]),_:1},8,["color"])])):g("v-if",!0)])}const G=S(k,[["render",M],["__scopeId","data-v-5ed5524d"],["__file","/tmp/cc-web-panel-GzZ4oH/repo/packages/web-panel/src/components/pdh/renderers/OrderTableRenderer.vue"]]);export{G as default};
|