chainlesschain 0.162.156 → 0.162.157
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-DjBXlypQ.js → AIOps-CfMP2Oud.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Cv9er9bp.js → ActionButton-Zu0N8BQL.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CLKDjSNs.js → Analytics-DZTwj5T_.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-CVFJh47v.js +9 -0
- package/src/assets/web-panel/assets/Artifacts-BbN5V7au.js +1 -0
- package/src/assets/web-panel/assets/Artifacts-CRkepl4t.css +1 -0
- package/src/assets/web-panel/assets/{Audit-CXafD178.js → Audit-BMfiLj7T.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CP5c-GSd.js → BackgroundAgents-BslPCdGF.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BbYLQfyt.js → Backup-CQ_fMC1r.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Bqe0MwZL.js → BaseInput-CsFsARiC.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-jNA_yUPH.js → Chat-CwfBobco.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BOFLF01s.js → ChatBubbleRenderer-K6Nf3xeN.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Dlzz-zD1.js → Checkbox-DkSyjjPp.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BAsDQjGf.js → Codegen-B7Fx3zZ6.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Ju0HrAuS.js → Col-Dzfqn8Ep.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DynJd43Z.js → Community-DhHPdzMM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CabbZVww.js → Compact-Ct18_8y7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DW4BmAoh.js → Compliance-CY64IqBi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bk1S_7X-.js → Cowork-BYSmWlUl.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-By4sh_NM.js → Cron-_4xtP3Ug.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DdZdbS1C.js → Crosschain-B4qY-Ycr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CkL-sQyS.js → DID-CkCzWkx1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-g_mOpumg.js → Dashboard-C1scT7Ke.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DtHyE7Ao.js → Dropdown-DBnQ2EWd.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Kpvov5Wr.js → EmailListRenderer-C9JhOTq0.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C4kZoePR.js → FamilyGuardDashboard-CWXv5RUv.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BAwWoK2N.js → Federation-fYdcbz9W.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DeI0i5f8.js → FormItemContext-CJqOT3Yj.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CkcKRtos.js → GenericCardRenderer-DGCsHc5K.js} +1 -1
- package/src/assets/web-panel/assets/{Git-kX6jjI9y.js → Git-EH2K-H0Q.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BXJCBm6x.js → Governance-DJn1X2pR.js} +1 -1
- package/src/assets/web-panel/assets/Inference-Dch1E8qd.js +1 -0
- package/src/assets/web-panel/assets/{KnowledgeGraph-3Dnuf1Wh.js → KnowledgeGraph-QIur8j8-.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-lVAZCtUB.js → Logs-DUgHldPg.js} +2 -2
- package/src/assets/web-panel/assets/Marketplace-DafrSfvd.js +1 -0
- package/src/assets/web-panel/assets/{McpTools-CqjzefRU.js → McpTools-D2xRbfJx.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BFiPAxk6.js → Memory-C6RbVHAo.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-D0O43VwF.js → MobileBridge-BPtVBKqn.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B3now48t.js → MobileProjects-Cuw832cr.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DybhtaCS.js → Mtc-D6O9fWFa.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-D7MmY4F0.js → MtcAudit-CWZcXIH1.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-wZvGJnB8.js → Multisig-DhIBxTFd.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BNPpgfvn.js → NLProgramming-wkBFS33e.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B6FS3KBj.js → Notes-B09FxncA.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CK0yla9U.js → NotificationSettings-oQwtH6-9.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-iFKeNf6Y.js +1 -0
- package/src/assets/web-panel/assets/{Organization-geqgwN1T.js → Organization-CsF-NIjz.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BWJYZFbC.js → Overflow-bLxv9Dqi.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DnU1505F.js → P2P-DVwQtm4q.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BGY74KnC.js → PdhVaultBrowser-Bgic3QKm.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-CgArrWtQ.js → Permissions-as80-9ep.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-C2vYE61a.js → PersonalDataHub-BGmUw36a.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-CBYLI4yW.js → Pipeline-BM96zBxG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B-PdW9aN.js → Privacy-BBOzBSWe.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CuWQegbV.js → ProjectInit-GHX41V28.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-4d32m_cS.js → ProjectSettings-DraqzxKD.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-VLA7ttwd.js → Projects-BzzdUml4.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B_Izb_oa.js → Providers-CSeYNAtW.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C6B_ndXV.js → QrScannerModal-DlzBCdXh.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C6tavL-y.js → QuickAsk-p8iB7od_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CF-LaZ6x.js → Recommend-DjOVXacd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DBqTTQ9_.js → RemoteSession-CIGk7gk-.js} +2 -2
- package/src/assets/web-panel/assets/Reputation-CjT3M0Di.js +1 -0
- package/src/assets/web-panel/assets/{Row-DO0fd48A.js → Row-tw8m6T0c.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BV5LDzFR.js → RssFeed-B47KBx_f.js} +2 -2
- package/src/assets/web-panel/assets/Search-D2sx1PBe.js +1 -0
- package/src/assets/web-panel/assets/{Security-DwSrWRCw.js → Security-JmtL8g7D.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BEf1QyM4.js → Services-BxrNqjin.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-LZXTpovy.js → Skeleton-udk8L18t.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-SKgc0Zug.js → Skills-DooLT9of.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-C_QVOtkN.js → Sla-ITVZE1xI.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-v5TW2V-X.js → SpeechSettings-DCkfqY1n.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CQPjHdqU.js → SyncSettings-CkNlgFjM.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DCd-uYcI.js → Tasks-BMAoyCM_.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-62VDIjtj.js → Templates-BnrFTlrz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BnFQ0pNy.js → Tenant-BjNsy3-i.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D3v0MGSj.js → Terminal-C0gxLL7V.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BI1Ka-cu.js → TimelineRenderer-CUtj_KHA.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BwX1jXYP.js → Tokens-DOg61zlq.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CSA8TqNx.js → Trigger-D4ldCewj.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Bn3IjCx7.js → Trust-3lk_Zd8j.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-pUbOAqNi.js → UkeySign-kWhFR6Li.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Db2RercF.js → VideoEditing-D3GOFVWg.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CpR1BVAl.js → Wallet-DzrZfBuh.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Yxtkn7Zp.js → WebAuthn-CyVJVp_g.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CYLe9a2E.js → WorkflowEditor-i_b0wi9b.js} +1 -1
- package/src/assets/web-panel/assets/{chat-gsOGdak0.js → chat-DwPCK8I7.js} +1 -1
- package/src/assets/web-panel/assets/{colors-D9fN299a.js → colors-D0vaVqZU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-vkd7s-ay.js → compact-item-Don7nGW2.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C7YkbMyy.js → createContext-D84R5qy2.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BBwWehQ7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-ig7reRSU.js → hasIn-BeUqVVKU.js} +1 -1
- package/src/assets/web-panel/assets/{icons-DEmcnxBf.js → icons-DG5UD-6K.js} +4 -4
- package/src/assets/web-panel/assets/{index-Bt-9ZhIu.js → index-4MkfPLGv.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7QRpKif.js → index-7QUwcGTg.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2yhtk6a.js → index-B57al0Z5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpGlLbRv.js → index-BER98o4P.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFM1oNe1.js → index-BNpJf-sf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYe9HRSt.js → index-BZ1N07Sp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CspGymmg.js → index-BlfTf0ka.js} +1 -1
- package/src/assets/web-panel/assets/{index-W52sHRdr.js → index-BohrJpBf.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7AY39sg.js → index-Br3SOdER.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co2NYyew.js → index-C0_sKVi7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQ8U7kzC.js → index-CAdCTTBC.js} +1 -1
- package/src/assets/web-panel/assets/{index-bVbgYBhv.js → index-CExWtm98.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAkz1f1r.js → index-CL71rIwo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGzGe5tv.js → index-CfYRv-zA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFfxF7Vt.js → index-CnnxzIx0.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8HZMygt.js → index-CrnVEEQO.js} +1 -1
- package/src/assets/web-panel/assets/{index-FzGr6CVk.js → index-CzT56x-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuwbKHoS.js → index-D4b5XqIy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHHN_KTS.js → index-D84BnuFg.js} +1 -1
- package/src/assets/web-panel/assets/{index-9TxdMYju.js → index-D8r7WKk-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dy_TKZ9h.js → index-DA0-EJKx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhftELHI.js → index-DBzBLX-K.js} +3 -3
- package/src/assets/web-panel/assets/{index-BkP17Z95.js → index-DFFzwrNs.js} +1 -1
- package/src/assets/web-panel/assets/index-DJ8etkBT.js +1 -0
- package/src/assets/web-panel/assets/{index-DPguq3X7.js → index-DMT8n9vB.js} +4 -4
- package/src/assets/web-panel/assets/{index-BfpVcXKa.js → index-DQor_7NF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvCJXmrx.js → index-DT40zd7K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvDEukXe.js → index-De85D9Pc.js} +1 -1
- package/src/assets/web-panel/assets/{index-PkH39qsp.js → index-IGGttsCv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMw48d19.js → index-L73NrmlW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDWTycrg.js → index-LMo9bBLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-nX8YE6cj.js → index-MKZrJrP_.js} +1 -1
- package/src/assets/web-panel/assets/index-OeaK-zXZ.js +1 -0
- package/src/assets/web-panel/assets/{index-SDrcQXO1.js → index-WRw1pM5E.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZAxCnjS.js → index-YKLCotoo.js} +1 -1
- package/src/assets/web-panel/assets/{index-gj8kxcAi.js → index-hjgrIX5I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhdXbsXX.js → index-m9bn0F1p.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6s_kbjt.js → index-wesQQ2cH.js} +1 -1
- package/src/assets/web-panel/assets/{index-gpurplyq.js → index-x7VYlV41.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BrgfVRg9.js → initDefaultProps-DGeU4vPS.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D_3xmwac.js → motion-Dgqj9ab3.js} +1 -1
- package/src/assets/web-panel/assets/{move-DDDJdlxw.js → move-BFyEU6Lr.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BK2uEWwn.js → mtc-parser-CueCXXPC.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BPHKbDcf.js → omit-D2pU5OyE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-LNnTscuz.js → pickAttrs-CKTf6zD6.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CvmTZll5.js → placementArrow-DieJaGCN.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-eBj7qi2J.js → responsiveObserve-Bxr-rmU6.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D68hHkrM.js → slide-CDEDk3Se.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-daTlaeo0.js → statusUtils-icf2eCTx.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DtyKMtHB.js → styleChecker-qKvgmBhE.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ekFwFs9h.js → useFlexGapSupport-1_UhiyJZ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-jRaSEoF4.js → useFs-CFGLXDWh.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DD5nGzjA.js → usePersonalDataHub-UafOXvQ6.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-KcgLUiom.js → vnode-BfPqSx79.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cyk2PQ-s.js → zoom-CXsVcRB6.js} +1 -1
- package/src/assets/web-panel/index.html +2 -2
- package/src/command-manifest.json +8 -1
- package/src/commands/agent.js +45 -4
- package/src/commands/artifacts.js +161 -0
- package/src/commands/browse.js +204 -2
- package/src/data/changelog.json +8 -2
- package/src/gateways/ws/artifact-protocol.js +219 -0
- package/src/gateways/ws/message-dispatcher.js +6 -0
- package/src/gateways/ws/ws-server.js +32 -0
- package/src/index.js +6 -0
- package/src/lib/accessibility.js +55 -0
- package/src/lib/artifact-store.js +236 -0
- package/src/lib/chrome-connector.js +314 -0
- package/src/lib/hook-runner.cjs +47 -7
- package/src/lib/ide-context.js +84 -0
- package/src/lib/permission-rules.cjs +26 -3
- package/src/lib/plugin-runtime/scopes.js +12 -0
- package/src/lib/safe-mode.js +40 -0
- package/src/lib/shell-selector.cjs +203 -0
- package/src/lib/skill-loader.js +19 -0
- package/src/lib/slash-dispatch.js +34 -0
- package/src/repl/agent-repl.js +99 -58
- package/src/runtime/agent-core.js +93 -8
- package/src/runtime/coding-agent-contract-shared.cjs +52 -0
- package/src/runtime/coding-agent-policy.cjs +15 -0
- package/src/runtime/headless-stream.js +51 -1
- package/src/runtime/policies/agent-policy.js +1 -0
- package/src/assets/web-panel/assets/AppLayout-CfyZNzmJ.js +0 -9
- package/src/assets/web-panel/assets/Inference-ujD2JSKo.js +0 -1
- package/src/assets/web-panel/assets/Marketplace-qnzNPm-A.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CXfPHIpy.js +0 -1
- package/src/assets/web-panel/assets/Reputation-B01FALUi.js +0 -1
- package/src/assets/web-panel/assets/Search-CTti4_MP.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DEcR2h6k.js +0 -1
- package/src/assets/web-panel/assets/index-BEibanjg.js +0 -1
- package/src/assets/web-panel/assets/index-z_25tU3p.js +0 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* shell-selector — Windows / PowerShell first-class shell selection
|
|
5
|
+
* (gap-analysis P1 #8).
|
|
6
|
+
*
|
|
7
|
+
* Decides WHICH shell a `run_shell` command (or a settings hook with a
|
|
8
|
+
* `shell` field) executes under:
|
|
9
|
+
*
|
|
10
|
+
* - per-call: run_shell `{ shell: "powershell" | "pwsh" | "cmd" | "default" }`
|
|
11
|
+
* - configured: settings `shell.windowsDefault` ("cmd" | "powershell" | "pwsh",
|
|
12
|
+
* layered .claude/settings.json, closest wins) or the
|
|
13
|
+
* CC_WINDOWS_SHELL env var (wins over settings)
|
|
14
|
+
* - default: unchanged platform default (cmd.exe via ComSpec on Windows,
|
|
15
|
+
* /bin/sh elsewhere) — the unconfigured path is byte-identical.
|
|
16
|
+
*
|
|
17
|
+
* PowerShell runs go through explicit argv (`powershell.exe -NoProfile
|
|
18
|
+
* [-ExecutionPolicy <p>] -Command <command>`), NOT `shell: "powershell.exe"`,
|
|
19
|
+
* so the enterprise ExecutionPolicy override (settings
|
|
20
|
+
* `shell.powershell.executionPolicy`) can be applied per-invocation without
|
|
21
|
+
* touching machine state. The policy value is validated against the fixed
|
|
22
|
+
* PowerShell enum — a settings typo can NOT smuggle extra argv.
|
|
23
|
+
*
|
|
24
|
+
* Scope notes:
|
|
25
|
+
* - `windowsDefault` only applies on win32 (hence the name). A per-call
|
|
26
|
+
* `pwsh` request is honored on any platform (PowerShell 7 is
|
|
27
|
+
* cross-platform); `powershell`/`cmd` requests outside Windows fall back
|
|
28
|
+
* to the platform default with a note.
|
|
29
|
+
* - `-ExecutionPolicy` is only attached on win32 (POSIX pwsh has no policy).
|
|
30
|
+
* - Hooks opt in per-hook via `{ "shell": "powershell" }` — the configured
|
|
31
|
+
* windowsDefault deliberately does NOT rewrite existing hooks.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const settingsLoader = require("./settings-loader.cjs");
|
|
35
|
+
|
|
36
|
+
const SHELL_KINDS = Object.freeze(["default", "cmd", "powershell", "pwsh"]);
|
|
37
|
+
|
|
38
|
+
/** The fixed PowerShell ExecutionPolicy enum (canonical casing). */
|
|
39
|
+
const EXECUTION_POLICIES = Object.freeze([
|
|
40
|
+
"Restricted",
|
|
41
|
+
"AllSigned",
|
|
42
|
+
"RemoteSigned",
|
|
43
|
+
"Unrestricted",
|
|
44
|
+
"Bypass",
|
|
45
|
+
"Undefined",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
/** Normalize a shell kind; unknown/empty → null (fail to default). */
|
|
49
|
+
function normalizeShellKind(value) {
|
|
50
|
+
if (typeof value !== "string") return null;
|
|
51
|
+
const v = value.trim().toLowerCase();
|
|
52
|
+
if (v === "powershell.exe" || v === "windowspowershell") return "powershell";
|
|
53
|
+
if (v === "pwsh.exe") return "pwsh";
|
|
54
|
+
if (v === "cmd.exe") return "cmd";
|
|
55
|
+
return SHELL_KINDS.includes(v) ? v : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Normalize an ExecutionPolicy to canonical casing; unknown → null. */
|
|
59
|
+
function normalizeExecutionPolicy(value) {
|
|
60
|
+
if (typeof value !== "string") return null;
|
|
61
|
+
const v = value.trim().toLowerCase();
|
|
62
|
+
return EXECUTION_POLICIES.find((p) => p.toLowerCase() === v) || null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Layered `shell` settings: `{ windowsDefault, powershell: { executionPolicy } }`.
|
|
67
|
+
* Closest layer wins per key; invalid values are ignored (fail-to-default).
|
|
68
|
+
* CC_WINDOWS_SHELL env overrides the settings-provided windowsDefault.
|
|
69
|
+
*
|
|
70
|
+
* @param {{ cwd?: string, env?: object, settingsFile?: string, onWarn?: Function }} [opts]
|
|
71
|
+
* @returns {{ windowsDefault: string|null, executionPolicy: string|null, files: string[] }}
|
|
72
|
+
*/
|
|
73
|
+
// Per-process memo: run_shell resolves the config on EVERY call, and the
|
|
74
|
+
// layered settings walk is filesystem I/O. A short TTL keeps mid-session
|
|
75
|
+
// settings edits honored without re-reading per tool call.
|
|
76
|
+
const _configCache = new Map(); // key → { at, value }
|
|
77
|
+
const CONFIG_CACHE_TTL_MS = 3000;
|
|
78
|
+
|
|
79
|
+
function loadShellConfig(opts = {}) {
|
|
80
|
+
const cwd = opts.cwd || process.cwd();
|
|
81
|
+
const env = opts.env || process.env;
|
|
82
|
+
const cacheable = !opts.env && !opts.onWarn;
|
|
83
|
+
const cacheKey = cacheable ? `${cwd}|${opts.settingsFile || ""}` : null;
|
|
84
|
+
if (cacheKey) {
|
|
85
|
+
const hit = _configCache.get(cacheKey);
|
|
86
|
+
if (hit && Date.now() - hit.at < CONFIG_CACHE_TTL_MS) return hit.value;
|
|
87
|
+
}
|
|
88
|
+
let windowsDefault = null;
|
|
89
|
+
let executionPolicy = null;
|
|
90
|
+
const files = [];
|
|
91
|
+
try {
|
|
92
|
+
for (const file of settingsLoader.settingsPaths(cwd, opts.settingsFile)) {
|
|
93
|
+
const data = settingsLoader.readSettingsFile(file, {
|
|
94
|
+
onWarn: opts.onWarn,
|
|
95
|
+
});
|
|
96
|
+
const shell = data && typeof data === "object" ? data.shell : null;
|
|
97
|
+
if (!shell || typeof shell !== "object" || Array.isArray(shell)) continue;
|
|
98
|
+
const kind = normalizeShellKind(shell.windowsDefault);
|
|
99
|
+
if (kind) windowsDefault = kind;
|
|
100
|
+
const pol = normalizeExecutionPolicy(shell.powershell?.executionPolicy);
|
|
101
|
+
if (pol) executionPolicy = pol;
|
|
102
|
+
files.push(file);
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
/* settings are best-effort — never fail shell resolution over them */
|
|
106
|
+
}
|
|
107
|
+
const envKind = normalizeShellKind(env.CC_WINDOWS_SHELL);
|
|
108
|
+
if (envKind) windowsDefault = envKind;
|
|
109
|
+
const value = { windowsDefault, executionPolicy, files };
|
|
110
|
+
if (cacheKey) _configCache.set(cacheKey, { at: Date.now(), value });
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Test hook: drop the config memo. */
|
|
115
|
+
function _clearShellConfigCache() {
|
|
116
|
+
_configCache.clear();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Build the explicit argv for a PowerShell invocation of `command`.
|
|
121
|
+
* @param {string} command
|
|
122
|
+
* @param {"powershell"|"pwsh"} kind
|
|
123
|
+
* @param {{ executionPolicy?: string|null, platform?: string }} [opts]
|
|
124
|
+
* @returns {{ file: string, argv: string[] }}
|
|
125
|
+
*/
|
|
126
|
+
function buildPowershellArgv(command, kind, opts = {}) {
|
|
127
|
+
const platform = opts.platform || process.platform;
|
|
128
|
+
const file = kind === "pwsh" ? "pwsh" : "powershell.exe";
|
|
129
|
+
const policy =
|
|
130
|
+
platform === "win32"
|
|
131
|
+
? normalizeExecutionPolicy(opts.executionPolicy)
|
|
132
|
+
: null;
|
|
133
|
+
return {
|
|
134
|
+
file,
|
|
135
|
+
argv: [
|
|
136
|
+
"-NoProfile",
|
|
137
|
+
...(policy ? ["-ExecutionPolicy", policy] : []),
|
|
138
|
+
"-Command",
|
|
139
|
+
String(command ?? ""),
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Resolve how to run one shell command.
|
|
146
|
+
*
|
|
147
|
+
* Precedence: per-call `requested` > configured windowsDefault (win32 only)
|
|
148
|
+
* > platform default. Returns either the default-shell marker (caller keeps
|
|
149
|
+
* its existing exec/spawn `shell: true` path — byte-identical) or an explicit
|
|
150
|
+
* `{ file, argv }` PowerShell invocation.
|
|
151
|
+
*
|
|
152
|
+
* @param {{ command: string, requested?: string, cwd?: string, env?: object,
|
|
153
|
+
* platform?: string, settingsFile?: string,
|
|
154
|
+
* config?: { windowsDefault?: string|null, executionPolicy?: string|null } }} opts
|
|
155
|
+
* @returns {{ kind: string, useDefaultShell: boolean, file?: string,
|
|
156
|
+
* argv?: string[], note?: string }}
|
|
157
|
+
*/
|
|
158
|
+
function resolveShellInvocation(opts = {}) {
|
|
159
|
+
const platform = opts.platform || process.platform;
|
|
160
|
+
const config = opts.config || loadShellConfig(opts);
|
|
161
|
+
const requested = normalizeShellKind(opts.requested);
|
|
162
|
+
let kind =
|
|
163
|
+
requested ||
|
|
164
|
+
(platform === "win32" ? config.windowsDefault : null) ||
|
|
165
|
+
"default";
|
|
166
|
+
let note;
|
|
167
|
+
|
|
168
|
+
if (kind === "cmd") {
|
|
169
|
+
if (platform === "win32") {
|
|
170
|
+
// cmd IS the Windows default shell — take the untouched default path so
|
|
171
|
+
// an explicit `shell:"cmd"` opt-out of a PowerShell windowsDefault stays
|
|
172
|
+
// byte-identical to the historical behavior.
|
|
173
|
+
return { kind: "cmd", useDefaultShell: true };
|
|
174
|
+
}
|
|
175
|
+
note = "cmd is Windows-only; using the platform default shell";
|
|
176
|
+
return { kind: "default", useDefaultShell: true, note };
|
|
177
|
+
}
|
|
178
|
+
if (kind === "powershell" && platform !== "win32") {
|
|
179
|
+
// Windows PowerShell 5.1 doesn't exist off-Windows; pwsh might.
|
|
180
|
+
note =
|
|
181
|
+
"powershell (5.1) is Windows-only; using the platform default shell (request pwsh for PowerShell 7)";
|
|
182
|
+
return { kind: "default", useDefaultShell: true, note };
|
|
183
|
+
}
|
|
184
|
+
if (kind === "powershell" || kind === "pwsh") {
|
|
185
|
+
const { file, argv } = buildPowershellArgv(opts.command, kind, {
|
|
186
|
+
executionPolicy: config.executionPolicy,
|
|
187
|
+
platform,
|
|
188
|
+
});
|
|
189
|
+
return { kind, useDefaultShell: false, file, argv };
|
|
190
|
+
}
|
|
191
|
+
return { kind: "default", useDefaultShell: true };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
SHELL_KINDS,
|
|
196
|
+
EXECUTION_POLICIES,
|
|
197
|
+
normalizeShellKind,
|
|
198
|
+
normalizeExecutionPolicy,
|
|
199
|
+
loadShellConfig,
|
|
200
|
+
buildPowershellArgv,
|
|
201
|
+
resolveShellInvocation,
|
|
202
|
+
_clearShellConfigCache,
|
|
203
|
+
};
|
package/src/lib/skill-loader.js
CHANGED
|
@@ -68,6 +68,19 @@ export function bundledSkillsDisabled(opts = {}) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Whether ALL skill layers are disabled — `cc agent --bare` sets CC_SKILLS=0
|
|
73
|
+
* (safe-mode "feature=0 disables" convention). Single gate: `loadAll` is the
|
|
74
|
+
* one place every layer funnels through, so this empties list_skills /
|
|
75
|
+
* run_skill / persona auto-activation in one check.
|
|
76
|
+
* @param {{ env?: object }} [opts]
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
export function allSkillsDisabled(opts = {}) {
|
|
80
|
+
const raw = (opts.env || process.env).CC_SKILLS;
|
|
81
|
+
return raw != null && /^(0|false|no|off)$/i.test(String(raw).trim());
|
|
82
|
+
}
|
|
83
|
+
|
|
71
84
|
/** Layer names in priority order (lowest → highest) */
|
|
72
85
|
export const LAYER_NAMES = [
|
|
73
86
|
"bundled",
|
|
@@ -475,6 +488,12 @@ export class CLISkillLoader {
|
|
|
475
488
|
* @returns {object[]} Resolved skill list
|
|
476
489
|
*/
|
|
477
490
|
loadAll(options = {}) {
|
|
491
|
+
// `cc agent --bare` (CC_SKILLS=0): no skill layer loads at all — cache the
|
|
492
|
+
// empty result so getResolvedSkills stays cheap on every call.
|
|
493
|
+
if (allSkillsDisabled(options)) {
|
|
494
|
+
this._cache = [];
|
|
495
|
+
return this._cache;
|
|
496
|
+
}
|
|
478
497
|
const layers = this.getLayerPaths();
|
|
479
498
|
const skillMap = new Map();
|
|
480
499
|
// Claude-Code `disableBundledSkills`: hide the built-in layer so only
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc agent --disable-slash-commands` — REPL slash-dispatch bypass predicate.
|
|
3
|
+
*
|
|
4
|
+
* When active, a "/"-leading line is NOT dispatched to the built-in slash
|
|
5
|
+
* handlers (nor custom .claude/commands macros nor MCP prompt expansion): it
|
|
6
|
+
* reaches the model verbatim, the same fall-through an unmatched slash line
|
|
7
|
+
* already takes. `/exit` and `/quit` stay live so the session remains
|
|
8
|
+
* closable from the keyboard.
|
|
9
|
+
*
|
|
10
|
+
* The REPL swaps the dispatched string for a sentinel no handler can match
|
|
11
|
+
* (leading NUL — nothing in the dispatch chain starts with a control char)
|
|
12
|
+
* and restores the user's real text for the model turn.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** The dispatch sentinel — starts with NUL so no handler branch matches. */
|
|
16
|
+
export function slashBypassSentinel() {
|
|
17
|
+
return String.fromCharCode(0) + "slash-bypassed";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Should this line bypass slash dispatch?
|
|
22
|
+
* @param {string} line the trimmed input line
|
|
23
|
+
* @param {boolean} disabled whether --disable-slash-commands is active
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
export function slashDispatchBypassed(line, disabled) {
|
|
27
|
+
return (
|
|
28
|
+
disabled === true &&
|
|
29
|
+
typeof line === "string" &&
|
|
30
|
+
line.startsWith("/") &&
|
|
31
|
+
line !== "/exit" &&
|
|
32
|
+
line !== "/quit"
|
|
33
|
+
);
|
|
34
|
+
}
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -1262,6 +1262,24 @@ export async function startAgentRepl(options = {}) {
|
|
|
1262
1262
|
options.vimMode === true || process.env.CC_VIM === "1" ? true : false;
|
|
1263
1263
|
let _vim = null;
|
|
1264
1264
|
|
|
1265
|
+
// --disable-slash-commands (Claude-Code parity): built-in slash dispatch,
|
|
1266
|
+
// custom command macros and MCP prompt expansion are all bypassed — a
|
|
1267
|
+
// "/"-leading line reaches the model verbatim, the same fall-through an
|
|
1268
|
+
// unmatched slash line already takes. /exit and /quit stay live so the
|
|
1269
|
+
// session remains closable from the keyboard.
|
|
1270
|
+
const _slashCommandsDisabled =
|
|
1271
|
+
options.disableSlashCommands === true ||
|
|
1272
|
+
/^(1|true|yes|on)$/i.test(
|
|
1273
|
+
String(process.env.CC_DISABLE_SLASH_COMMANDS || "").trim(),
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
// --ax-screen-reader / CC_SCREEN_READER: force the mono theme (no ANSI
|
|
1277
|
+
// color codes) so output linearizes cleanly. The repainting status line is
|
|
1278
|
+
// already killed by the CC_STATUSLINE=0 switch agent.js applies.
|
|
1279
|
+
const _screenReaderMode = /^(1|true|yes|on)$/i.test(
|
|
1280
|
+
String(process.env.CC_SCREEN_READER || "").trim(),
|
|
1281
|
+
);
|
|
1282
|
+
|
|
1265
1283
|
// Color theme (Claude-Code `/theme` parity). Capture chalk's auto-detected
|
|
1266
1284
|
// level BEFORE any theme touches it so `mono`→level 0 stays reversible, then
|
|
1267
1285
|
// apply the persisted theme (config `cli.theme`). `mono` strips all color;
|
|
@@ -1282,6 +1300,10 @@ export async function startAgentRepl(options = {}) {
|
|
|
1282
1300
|
} catch (_e) {
|
|
1283
1301
|
/* config optional — keep default */
|
|
1284
1302
|
}
|
|
1303
|
+
// Screen-reader mode overrides the persisted theme: colors are invisible to
|
|
1304
|
+
// a reader and ANSI codes are noise, so run mono for this session (the
|
|
1305
|
+
// stored cli.theme is untouched — /theme still shows and can change it).
|
|
1306
|
+
if (_screenReaderMode) _theme = "mono";
|
|
1285
1307
|
applyThemeChalk(_theme, chalk, _chalkBaselineLevel);
|
|
1286
1308
|
const themedPrompt = (text) => {
|
|
1287
1309
|
const a = promptAccent(_theme);
|
|
@@ -1316,65 +1338,69 @@ export async function startAgentRepl(options = {}) {
|
|
|
1316
1338
|
// cwd left unset on purpose: the completer resolves process.cwd() lazily
|
|
1317
1339
|
// so it follows `/cd` mid-session.
|
|
1318
1340
|
// Keep in sync with the rl.on("line") handlers + /help below.
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1341
|
+
// --disable-slash-commands: nothing to complete — "/" input is plain text.
|
|
1342
|
+
slashCommands: _slashCommandsDisabled
|
|
1343
|
+
? []
|
|
1344
|
+
: [
|
|
1345
|
+
"/add-dir",
|
|
1346
|
+
"/agents",
|
|
1347
|
+
"/auto",
|
|
1348
|
+
"/btw",
|
|
1349
|
+
"/cd",
|
|
1350
|
+
"/clear",
|
|
1351
|
+
"/compact",
|
|
1352
|
+
"/config",
|
|
1353
|
+
"/context",
|
|
1354
|
+
"/copy",
|
|
1355
|
+
"/cost",
|
|
1356
|
+
"/cowork",
|
|
1357
|
+
"/doctor",
|
|
1358
|
+
"/effort",
|
|
1359
|
+
"/exit",
|
|
1360
|
+
"/export",
|
|
1361
|
+
"/help",
|
|
1362
|
+
"/hooks",
|
|
1363
|
+
"/ide",
|
|
1364
|
+
"/init",
|
|
1365
|
+
"/mcp",
|
|
1366
|
+
"/memory",
|
|
1367
|
+
"/microcompact",
|
|
1368
|
+
"/model",
|
|
1369
|
+
"/output-style",
|
|
1370
|
+
"/permissions",
|
|
1371
|
+
"/plan",
|
|
1372
|
+
"/pr-comments",
|
|
1373
|
+
"/profile",
|
|
1374
|
+
"/provider",
|
|
1375
|
+
"/quit",
|
|
1376
|
+
"/reindex",
|
|
1377
|
+
"/release-notes",
|
|
1378
|
+
"/reload-plugins",
|
|
1379
|
+
"/reload-skills",
|
|
1380
|
+
"/review",
|
|
1381
|
+
"/rewind",
|
|
1382
|
+
"/search",
|
|
1383
|
+
"/session",
|
|
1384
|
+
"/sessions",
|
|
1385
|
+
"/stats",
|
|
1386
|
+
"/status",
|
|
1387
|
+
"/statusline",
|
|
1388
|
+
"/sub-agents",
|
|
1389
|
+
"/task",
|
|
1390
|
+
"/tasks",
|
|
1391
|
+
"/terminal-setup",
|
|
1392
|
+
"/theme",
|
|
1393
|
+
"/think",
|
|
1394
|
+
"/todos",
|
|
1395
|
+
"/ultrathink",
|
|
1396
|
+
"/vim",
|
|
1397
|
+
],
|
|
1373
1398
|
// User/project custom commands (.claude/commands/*.md) join TAB completion
|
|
1374
1399
|
// alongside the built-ins above. Sync + best-effort; the completer
|
|
1375
1400
|
// TTL-caches the result so this filesystem walk runs at most once per few
|
|
1376
1401
|
// seconds, and process.cwd() makes it follow `/cd` mid-session.
|
|
1377
1402
|
getDynamicSlashCommands: () => {
|
|
1403
|
+
if (_slashCommandsDisabled) return [];
|
|
1378
1404
|
try {
|
|
1379
1405
|
return discoverCommands(process.cwd()).map((cmd) => `/${cmd.name}`);
|
|
1380
1406
|
} catch {
|
|
@@ -1719,7 +1745,20 @@ export async function startAgentRepl(options = {}) {
|
|
|
1719
1745
|
_mlBuffer.length = 0;
|
|
1720
1746
|
}
|
|
1721
1747
|
|
|
1722
|
-
const
|
|
1748
|
+
const rawLine = input.trim();
|
|
1749
|
+
// --disable-slash-commands: hide "/"-leading input from every built-in
|
|
1750
|
+
// slash handler below by dispatching a sentinel no handler can match; the
|
|
1751
|
+
// turn tail restores the user's real text (promptText), so the line goes
|
|
1752
|
+
// to the model verbatim — the same fall-through an unmatched slash line
|
|
1753
|
+
// already takes. /exit and /quit stay live so the session can be closed.
|
|
1754
|
+
// Predicate + sentinel are pure (lib/slash-dispatch.js, unit-tested).
|
|
1755
|
+
const { slashDispatchBypassed, slashBypassSentinel } =
|
|
1756
|
+
await import("../lib/slash-dispatch.js");
|
|
1757
|
+
const _slashBypassed = slashDispatchBypassed(
|
|
1758
|
+
rawLine,
|
|
1759
|
+
_slashCommandsDisabled,
|
|
1760
|
+
);
|
|
1761
|
+
const trimmed = _slashBypassed ? slashBypassSentinel() : rawLine;
|
|
1723
1762
|
if (!trimmed) {
|
|
1724
1763
|
prompt();
|
|
1725
1764
|
return;
|
|
@@ -4086,13 +4125,15 @@ export async function startAgentRepl(options = {}) {
|
|
|
4086
4125
|
// parity. resolveSlashMacro maps a leading /name to a command macro and
|
|
4087
4126
|
// expands its template; a non-match returns the line unchanged so a literal
|
|
4088
4127
|
// prompt like "/etc/hosts" still reaches the LLM. Wire is unit-tested.
|
|
4089
|
-
|
|
4128
|
+
// Under --disable-slash-commands the sentinel never reached a handler;
|
|
4129
|
+
// restore the user's real text so the model sees it verbatim.
|
|
4130
|
+
let promptText = _slashBypassed ? rawLine : trimmed;
|
|
4090
4131
|
|
|
4091
4132
|
// MCP server-provided prompts (Claude-Code parity): `/mcp__<server>__<name>
|
|
4092
4133
|
// [json-args]` fetches a rendered prompt template from the connected MCP
|
|
4093
4134
|
// server and uses its text as this turn's input. Falls through unchanged
|
|
4094
4135
|
// when the line isn't an MCP prompt command.
|
|
4095
|
-
if (promptText.startsWith("/mcp__")) {
|
|
4136
|
+
if (!_slashBypassed && promptText.startsWith("/mcp__")) {
|
|
4096
4137
|
try {
|
|
4097
4138
|
const expanded = await expandMcpPrompt(
|
|
4098
4139
|
promptText,
|
|
@@ -4114,7 +4155,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
4114
4155
|
// `/pr-comments [<n>|<url>] [--repo owner/name]` (Claude-Code parity):
|
|
4115
4156
|
// fetch a GitHub PR's reviews + conversation + inline comments via `gh` and
|
|
4116
4157
|
// feed them as this turn's input so the agent can address the feedback.
|
|
4117
|
-
if (promptText.startsWith("/pr-comments")) {
|
|
4158
|
+
if (!_slashBypassed && promptText.startsWith("/pr-comments")) {
|
|
4118
4159
|
try {
|
|
4119
4160
|
const { expandPrComments } = await import("./pr-comments.js");
|
|
4120
4161
|
const res = await expandPrComments(promptText);
|
|
@@ -1041,6 +1041,7 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1041
1041
|
hasIdeOpenDiff,
|
|
1042
1042
|
requestIdeDiffApproval,
|
|
1043
1043
|
formatReviewComments,
|
|
1044
|
+
summarizeUserAmendments,
|
|
1044
1045
|
} = await import("../lib/ide-context.js");
|
|
1045
1046
|
const mcpLike = {
|
|
1046
1047
|
mcpClient: context.mcpClient,
|
|
@@ -1056,15 +1057,22 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1056
1057
|
title: `cc agent: ${name} ${path.basename(proposal.filePath)}`,
|
|
1057
1058
|
});
|
|
1058
1059
|
if (verdict?.outcome === "accepted") {
|
|
1060
|
+
// When the reviewer amended the proposal in the diff before accepting,
|
|
1061
|
+
// hand the agent the actual -/+ delta — not just a flag — so its model
|
|
1062
|
+
// of the file matches what was really written (gap #4: the agent
|
|
1063
|
+
// perceives the user's edits).
|
|
1064
|
+
const amendments =
|
|
1065
|
+
verdict.finalText != null && verdict.finalText !== proposal.newContent
|
|
1066
|
+
? summarizeUserAmendments(proposal.newContent, verdict.finalText)
|
|
1067
|
+
: null;
|
|
1059
1068
|
return {
|
|
1060
1069
|
outcome: "accepted",
|
|
1061
1070
|
result: {
|
|
1062
1071
|
success: true,
|
|
1063
1072
|
path: proposal.filePath,
|
|
1064
1073
|
appliedVia: "ide-diff",
|
|
1065
|
-
...(
|
|
1066
|
-
|
|
1067
|
-
? { userEdited: true }
|
|
1074
|
+
...(amendments
|
|
1075
|
+
? { userEdited: true, userAmendments: amendments }
|
|
1068
1076
|
: {}),
|
|
1069
1077
|
policy: { decision: "allow", rule, via: "ide-diff" },
|
|
1070
1078
|
},
|
|
@@ -2431,6 +2439,24 @@ async function executeToolInner(
|
|
|
2431
2439
|
}
|
|
2432
2440
|
}
|
|
2433
2441
|
|
|
2442
|
+
// P1 #8 Windows/PowerShell first-class: per-call args.shell or the
|
|
2443
|
+
// configured settings `shell.windowsDefault` may route this command
|
|
2444
|
+
// through PowerShell via explicit argv (`powershell.exe -NoProfile
|
|
2445
|
+
// [-ExecutionPolicy <p>] -Command <cmd>`). The unconfigured path keeps
|
|
2446
|
+
// the historical default shell byte-identical (useDefaultShell=true).
|
|
2447
|
+
const { resolveShellInvocation } =
|
|
2448
|
+
await import("../lib/shell-selector.cjs");
|
|
2449
|
+
const shellInv = resolveShellInvocation({
|
|
2450
|
+
command: args.command,
|
|
2451
|
+
requested: args.shell,
|
|
2452
|
+
cwd: args.cwd || cwd,
|
|
2453
|
+
});
|
|
2454
|
+
const shellMeta = shellInv.useDefaultShell
|
|
2455
|
+
? shellInv.note
|
|
2456
|
+
? { shell_note: shellInv.note }
|
|
2457
|
+
: {}
|
|
2458
|
+
: { shell: shellInv.kind };
|
|
2459
|
+
|
|
2434
2460
|
// Background: spawn, register, return a task_id immediately. The agent
|
|
2435
2461
|
// polls output + completion via check_shell. No timeout — that's the whole
|
|
2436
2462
|
// point of backgrounding (builds, test suites, dev servers).
|
|
@@ -2463,9 +2489,9 @@ async function executeToolInner(
|
|
|
2463
2489
|
child: null,
|
|
2464
2490
|
};
|
|
2465
2491
|
try {
|
|
2466
|
-
const
|
|
2492
|
+
const bgSpawnOpts = {
|
|
2467
2493
|
cwd: task.cwd,
|
|
2468
|
-
shell:
|
|
2494
|
+
shell: shellInv.useDefaultShell,
|
|
2469
2495
|
windowsHide: true,
|
|
2470
2496
|
// Same agent-identity env as the foreground path: CLAUDECODE marks
|
|
2471
2497
|
// "running under the agent"; the session id correlates work to the
|
|
@@ -2484,7 +2510,12 @@ async function executeToolInner(
|
|
|
2484
2510
|
// the whole tree (shell + its grandchild command). No-op on Windows
|
|
2485
2511
|
// where the tree is killed via taskkill /T instead.
|
|
2486
2512
|
detached: process.platform !== "win32",
|
|
2487
|
-
}
|
|
2513
|
+
};
|
|
2514
|
+
// PowerShell route: explicit argv (shell:false above); default route
|
|
2515
|
+
// is the historical spawn(command, {shell:true}) byte-for-byte.
|
|
2516
|
+
const child = shellInv.useDefaultShell
|
|
2517
|
+
? spawn(args.command, bgSpawnOpts)
|
|
2518
|
+
: spawn(shellInv.file, shellInv.argv, bgSpawnOpts);
|
|
2488
2519
|
task.child = child;
|
|
2489
2520
|
if (child.stdout) {
|
|
2490
2521
|
child.stdout.setEncoding("utf8");
|
|
@@ -2532,6 +2563,7 @@ async function executeToolInner(
|
|
|
2532
2563
|
task_id: id,
|
|
2533
2564
|
status: task.status,
|
|
2534
2565
|
command: task.command,
|
|
2566
|
+
...shellMeta,
|
|
2535
2567
|
hint: "Poll output and completion with the check_shell tool using this task_id. Kill long-lived servers with check_shell { task_id, kill: true } when done.",
|
|
2536
2568
|
shellCommandPolicy: shellPolicy,
|
|
2537
2569
|
approval: approvalOutcome,
|
|
@@ -2630,7 +2662,7 @@ async function executeToolInner(
|
|
|
2630
2662
|
}
|
|
2631
2663
|
|
|
2632
2664
|
try {
|
|
2633
|
-
const
|
|
2665
|
+
const fgExecOpts = {
|
|
2634
2666
|
cwd: args.cwd || cwd,
|
|
2635
2667
|
encoding: "utf8",
|
|
2636
2668
|
timeout: _resolveShellTimeout(args.timeout),
|
|
@@ -2649,10 +2681,35 @@ async function executeToolInner(
|
|
|
2649
2681
|
}
|
|
2650
2682
|
: {}),
|
|
2651
2683
|
},
|
|
2652
|
-
}
|
|
2684
|
+
};
|
|
2685
|
+
let output;
|
|
2686
|
+
if (shellInv.useDefaultShell) {
|
|
2687
|
+
output = execSync(args.command, fgExecOpts);
|
|
2688
|
+
} else {
|
|
2689
|
+
// PowerShell route: explicit argv, no intermediate default shell.
|
|
2690
|
+
// Reproduce execSync's contract so the shared catch shapes errors
|
|
2691
|
+
// identically: throw on spawn error; throw an Error carrying
|
|
2692
|
+
// status/stdout/stderr on non-zero exit.
|
|
2693
|
+
const res = spawnSync(shellInv.file, shellInv.argv, {
|
|
2694
|
+
...fgExecOpts,
|
|
2695
|
+
windowsHide: true,
|
|
2696
|
+
});
|
|
2697
|
+
if (res.error) throw res.error;
|
|
2698
|
+
if (res.status !== 0) {
|
|
2699
|
+
const e = new Error(
|
|
2700
|
+
`Command failed (${shellInv.kind}, exit ${res.status}): ${args.command}`,
|
|
2701
|
+
);
|
|
2702
|
+
e.status = res.status;
|
|
2703
|
+
e.stdout = res.stdout;
|
|
2704
|
+
e.stderr = res.stderr;
|
|
2705
|
+
throw e;
|
|
2706
|
+
}
|
|
2707
|
+
output = res.stdout ?? "";
|
|
2708
|
+
}
|
|
2653
2709
|
return attachDescriptor(
|
|
2654
2710
|
{
|
|
2655
2711
|
stdout: output.substring(0, 30000),
|
|
2712
|
+
...shellMeta,
|
|
2656
2713
|
shellCommandPolicy: shellPolicy,
|
|
2657
2714
|
approval: approvalOutcome,
|
|
2658
2715
|
},
|
|
@@ -2672,6 +2729,7 @@ async function executeToolInner(
|
|
|
2672
2729
|
: {}),
|
|
2673
2730
|
stderr: (err.stderr || "").substring(0, 2000),
|
|
2674
2731
|
exitCode: err.status,
|
|
2732
|
+
...shellMeta,
|
|
2675
2733
|
shellCommandPolicy: shellPolicy,
|
|
2676
2734
|
approval: approvalOutcome,
|
|
2677
2735
|
},
|
|
@@ -3104,6 +3162,31 @@ async function executeToolInner(
|
|
|
3104
3162
|
}
|
|
3105
3163
|
}
|
|
3106
3164
|
|
|
3165
|
+
case "publish_artifact": {
|
|
3166
|
+
// P1 #10: copy a finished deliverable into the user's artifact store.
|
|
3167
|
+
// Only METADATA returns to the conversation (the transcript never
|
|
3168
|
+
// carries the file body); `cc artifacts` lists/inspects/cleans.
|
|
3169
|
+
try {
|
|
3170
|
+
const { ArtifactStore } = await import("../lib/artifact-store.js");
|
|
3171
|
+
const store = new ArtifactStore();
|
|
3172
|
+
const entry = store.publish({
|
|
3173
|
+
filePath: path.resolve(cwd, String(args.path || "")),
|
|
3174
|
+
title: args.title,
|
|
3175
|
+
kind: args.kind,
|
|
3176
|
+
ttlDays: args.ttl_days,
|
|
3177
|
+
sessionId: sessionId ? String(sessionId) : null,
|
|
3178
|
+
});
|
|
3179
|
+
return attachDescriptor({
|
|
3180
|
+
published: entry,
|
|
3181
|
+
hint: "The user can browse this with `cc artifacts list` / `cc artifacts show <id>`.",
|
|
3182
|
+
});
|
|
3183
|
+
} catch (err) {
|
|
3184
|
+
return attachDescriptor({
|
|
3185
|
+
error: `publish_artifact failed: ${err.message}`,
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3107
3190
|
case "search_files": {
|
|
3108
3191
|
// An explicit directory scopes the search to one root; otherwise span
|
|
3109
3192
|
// cwd plus any --add-dir roots so cross-package searches find matches.
|
|
@@ -6438,6 +6521,8 @@ export function formatToolArgs(name, args) {
|
|
|
6438
6521
|
return `"${(args.query || "").substring(0, 60)}"`;
|
|
6439
6522
|
case "notify":
|
|
6440
6523
|
return `${args.level || "info"}: ${(args.title || "").substring(0, 50)}`;
|
|
6524
|
+
case "publish_artifact":
|
|
6525
|
+
return `${args.kind || "other"}: ${(args.title || args.path || "").substring(0, 60)}`;
|
|
6441
6526
|
case "schedule":
|
|
6442
6527
|
return args.action === "cron"
|
|
6443
6528
|
? `cron ${args.cron || ""}`.trim()
|