chainlesschain 0.162.142 → 0.162.147
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/bin/chainlesschain.js +5 -3
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-Dc6fWgoa.js → AIOps-DywJ7xTv.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DzMx25vJ.js → ActionButton-BTlqcY-q.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-eDC3KNht.js → Analytics-FdG1Mvwy.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-uA1TOtNp.js → AppLayout-CVsnbvN1.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-Bq3QX9Cj.js → Audit-ITdpJ7vR.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B1V3Jfyv.js → Backup-BfXqnXo1.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DMFwddIF.js → BaseInput-C09ip3_E.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CKWQDH5j.js → Chat-qdkhB42l.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CStSBCnk.js → ChatBubbleRenderer-D2KfETZD.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DepIzI7G.js → Checkbox-j6WZCuff.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-ClanWll2.js → Codegen-CGZ-K3uK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CFBzsL4W.js → Col-CIlPOAu6.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CaAyZ_Pt.js → Community-sY-i-hic.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-3dCHRSVe.js → Compact-DcoEfyL8.js} +1 -1
- package/src/assets/web-panel/assets/Compliance-T8EtTecW.js +1 -0
- package/src/assets/web-panel/assets/{Cowork-DkJmdQaU.js → Cowork-DLY_fkLv.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DKfNf6J2.js → Cron-D049pZBC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-COu1aQIO.js → Crosschain-DCXdE8M9.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CkAgFLkI.js → DID-JCvPZtjW.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CfaKWZCU.js → Dashboard-Cg2xu3iE.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Cjw97sdb.js → Dropdown-DjJLjbLh.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DROLQgOn.js → EmailListRenderer-DugNcSLR.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-o_cYzlLq.js → FamilyGuardDashboard-J6Nb-E30.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Boex3ljt.js → Federation-CQ3Ttpbl.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BQQ05T_3.js → FormItemContext-Cz0NKag4.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CdfL8PBd.js → GenericCardRenderer-NYcMP6iz.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CfZ07qJy.js → Git-B4hYN18N.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B21ISudq.js → Governance-DOQPCcC0.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CGIK4Im1.js → Inference-HtLF746W.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CI1kmfdT.js → KnowledgeGraph-BXrk8rMm.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Dpc1-__h.js → Logs-DS0JnD3-.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-BpMtMWyK.js → Marketplace-Cqnjihrz.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-B94WvOOS.js → McpTools-Cx3Psk-U.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DODsAxZf.js → Memory-BjyysPtj.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C3Bjshem.js → MobileBridge-CYaITZ7w.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Bi8IHDv_.js → MobileProjects-Xwf-fdOQ.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CH5BSuWG.js → Mtc-Djkql5m5.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DN3MzNtL.js → MtcAudit-D2BAZlu0.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CO6GWQOh.js → Multisig-ByqP1ZzH.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DhIr3V_u.js → NLProgramming-C_kn0nE2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CNgrvZCJ.js → Notes-7l7eXHPq.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Crr4LPjQ.js → NotificationSettings-BrCDoitw.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C8q-kK2z.js → OrderTableRenderer-CmtqIdwr.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-hWhCmeUn.js → Organization-DdoNAxsM.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-t_EBxns-.js → Overflow-Bw7R6dE3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B8fqfwis.js → P2P-DJNtBugA.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-d-wlJw3R.js → PdhVaultBrowser-Dwhd5_ue.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Ch13YpBo.js → Permissions-BYoSfhPR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DW7LlLbS.js → PersonalDataHub-aYCYJbnH.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BHh3HqOQ.js → Pipeline-DJp6CprF.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DAhlJDSC.js → Privacy-Cq9HZweR.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BRtddAM_.js → ProjectInit-CmF0HsSt.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CzR1EC7b.js → ProjectSettings-P8V5Aea2.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DSavX602.js → Projects-DPd5-lNS.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-D55_kGZs.js → Providers-D589v0q2.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BR5qDIaT.js → QuickAsk-lvRV2osB.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CTFAM97K.js → Recommend-sb84MTpY.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-Z7pvEha9.js → Reputation-d9Y3vy-W.js} +1 -1
- package/src/assets/web-panel/assets/{Row-MqKcIsjP.js → Row-DMdhLUTp.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DdLDjRpk.js → RssFeed-OL-SMDkz.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CeOzh2hz.js → Search-BjStLKq1.js} +1 -1
- package/src/assets/web-panel/assets/{Security-gHrXaf4o.js → Security-MeI411qr.js} +3 -3
- package/src/assets/web-panel/assets/{Services-B8Y7pmY1.js → Services-UajosuhT.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CRS0WNut.js → Skeleton-CGpG-QJ1.js} +1 -1
- package/src/assets/web-panel/assets/{Skills--a5_Pdxx.js → Skills-C6P2RPY-.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-EcTyL6EM.js → Sla-B_fPprgw.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-QpfvOiJr.js → SpeechSettings-CqxLjSlQ.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DaLBBzlE.js → SyncSettings-DixSfFOQ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Ca6xvO-I.js → Tasks-PavzPBxc.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CWguiCoE.js → Templates-BYdGRnfX.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BGLLZulu.js → Tenant-BQLgnarD.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-BzOHpq-B.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-CLjvjbmr.js → TimelineRenderer-Bv7uZRM7.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-De5mmw_a.js → Tokens-DxhgszRJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Chbq6U0N.js → Trigger-nQYHayuc.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CYxUO2lv.js → Trust-CvqZDuZ4.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-iyoZXXF6.js → UkeySign-DaR8GV2I.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CHg3ifJs.js → VideoEditing-C6Mpsokw.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DfjqObsO.js → Wallet-B57VRrWc.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-0FI6xfud.js → WebAuthn-BbtEEtpq.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CJgGcctS.js → WorkflowEditor-C5LwvKmH.js} +1 -1
- package/src/assets/web-panel/assets/{chat-fH-E4vhY.js → chat-MzuPR5jh.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CuxsOD6d.js → colors-HyW8mi_y.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-AfVcFrFU.js → compact-item-DvUSzWAp.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DTsD7sPO.js → createContext-4MppZl7X.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-6YJJMjSH.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DJR763M6.js → hasIn-D9q3CJ-u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhM9FZUH.js → index--Bm6OqmU.js} +1 -1
- package/src/assets/web-panel/assets/{index-OZwLoscJ.js → index-B5E4DhVc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF8OSTin.js → index-B994UQfE.js} +1 -1
- package/src/assets/web-panel/assets/{index-9cryBBzh.js → index-BF2JsbiX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMVULNUC.js → index-BFGfC5RS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj1_lz3M.js → index-BGQtFso0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBPAH7rp.js → index-BcunsBIx.js} +1 -1
- package/src/assets/web-panel/assets/{index-mLAfJXAf.js → index-Bl-E4W4q.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cfppli6E.js → index-BmCo2Xdp.js} +1 -1
- package/src/assets/web-panel/assets/{index-_hP8-Y2F.js → index-Btz8pU68.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvlzcX3Q.js → index-C0DiL97c.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBBStCbO.js → index-C9I5MuJ0.js} +1 -1
- package/src/assets/web-panel/assets/{index-SuJ2_OzM.js → index-CLAZs1Vd.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8DLT-F4.js → index-Caqtu6Et.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cm4cHE5_.js → index-CgIfXOD9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbQX0Zbf.js → index-Ci6adKh8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEGMojUg.js → index-CifKUNtV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdV7a6-K.js → index-Cs-RKRUM.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dswd93W4.js → index-CucRo4Vz.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2KdGSMa.js → index-CvAqCAo9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqflTl_b.js → index-D2jrnaq3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cl7chKuM.js → index-D7TDMMfu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAbZ3dW9.js → index-DDZ6fP5Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BD4-kWQY.js → index-DFqvWeGc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DejUsZOw.js → index-DNYqw0MO.js} +1 -1
- package/src/assets/web-panel/assets/index-D_oeGLr6.js +1 -0
- package/src/assets/web-panel/assets/{index-DH-dA4pG.js → index-DcMkjb92.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMcYdHhK.js → index-DmZ6-suL.js} +1 -1
- package/src/assets/web-panel/assets/{index-85iIi3qF.js → index-Dv7ffI2g.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJIFQ-Ay.js → index-Dvg5xYuP.js} +1 -1
- package/src/assets/web-panel/assets/index-Qa57YG19.js +1 -0
- package/src/assets/web-panel/assets/{index-DxD03TL7.js → index-SDblbKj6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmUxSTNy.js → index-UUMCA2Sq.js} +3 -3
- package/src/assets/web-panel/assets/{index-BJl6Ob-o.js → index-Zvtru2oE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPHYW3IK.js → index-eOQO6KnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-rcowKd.js → index-m0b6Fj9q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTtL2Qkb.js → index-ryFLxB1p.js} +1 -1
- package/src/assets/web-panel/assets/{index-fj3ZXgiy.js → index-xvUVuFnA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbpuFc8C.js → index-zLwYpvX0.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BGoLJP6T.js → initDefaultProps-CC--PMsC.js} +1 -1
- package/src/assets/web-panel/assets/{motion-23xdoVi0.js → motion-DdrBjRF1.js} +1 -1
- package/src/assets/web-panel/assets/{move-C3Bnnft-.js → move-D712Gwl2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Dv0C3a90.js → mtc-parser-39y-keKO.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C3r9qzDO.js → omit-6Y51gDB9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B4bJOcNp.js → pickAttrs-Cy6EHbq9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Dxf48wcO.js → placementArrow-BYxdAm0p.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Rq9U2hbz.js → responsiveObserve-C9R6q_cr.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BeWiqbdF.js → slide-CXUJlilB.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-yX9N1cEc.js → statusUtils-DOtrOeql.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-5Ko9NorO.js → styleChecker-D5r39o92.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-WKpkTLok.js → useFlexGapSupport-DfAD5U4Z.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BV4X0JOG.js → useFs-BkrT-Zbc.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-g41wq_2p.js → usePersonalDataHub-BwnnnZjU.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BAurbOH8.js → vnode-SU-N4pum.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cl5XniRg.js → zoom-DHScfpTP.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/auth/npm-auth.js +65 -0
- package/src/command-manifest.json +1126 -0
- package/src/commands/agent.js +92 -0
- package/src/commands/agents.js +68 -0
- package/src/commands/note.js +2 -1
- package/src/commands/permissions.js +66 -10
- package/src/commands/plugin.js +50 -3
- package/src/commands/search.js +2 -1
- package/src/harness/worktree-isolator.js +14 -7
- package/src/index.js +4 -12
- package/src/lazy-dispatch.js +107 -0
- package/src/lib/agent-sandbox.js +72 -0
- package/src/lib/background-agent-supervisor.js +197 -0
- package/src/lib/code-review.js +72 -0
- package/src/lib/ensure-utf8.js +25 -7
- package/src/lib/knowledge-exporter.js +3 -2
- package/src/lib/permission-engine.js +1 -1
- package/src/lib/plugin-security.js +128 -0
- package/src/lib/pr-create.js +108 -0
- package/src/lib/publish-workspace.js +107 -0
- package/src/lib/resume-session.js +111 -0
- package/src/lib/session-manager.js +2 -1
- package/src/lib/settings-hooks.cjs +68 -25
- package/src/lib/settings-loader.cjs +115 -2
- package/src/lib/task-list.js +53 -0
- package/src/program-base.js +24 -0
- package/src/repl/agent-repl.js +108 -3
- package/src/repl/agents-status.js +8 -2
- package/src/repl/btw-command.js +56 -0
- package/src/repl/chat-repl.js +52 -1
- package/src/repl/hooks-status.js +1 -2
- package/src/repl/slash-command-registry.js +197 -0
- package/src/repl/think-command.js +31 -0
- package/src/runtime/agent-core.js +137 -1
- package/src/runtime/coding-agent-contract-shared.cjs +37 -0
- package/src/runtime/coding-agent-policy.cjs +14 -0
- package/src/runtime/file-ref-expander.js +100 -14
- package/src/runtime/headless-runner.js +26 -6
- package/src/runtime/headless-stream.js +25 -6
- package/src/runtime/mcp-config.js +46 -2
- package/src/runtime/policies/agent-policy.js +1 -0
- package/src/workers/background-agent-worker.js +60 -0
- package/src/assets/web-panel/assets/Compliance-BKYHHTdq.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Bryzb1Rm.js +0 -3
- package/src/assets/web-panel/assets/devWarning-DffbPlEe.js +0 -1
- package/src/assets/web-panel/assets/index-BAHgOh3h.js +0 -1
- package/src/assets/web-panel/assets/index-zfkDb9FC.js +0 -1
package/src/commands/agent.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "../runtime/fallback-model.js";
|
|
17
17
|
import { resolveImages, resolveVisionLlm } from "../lib/image-input.js";
|
|
18
18
|
import { loadConfig } from "../lib/config-manager.js";
|
|
19
|
+
import { normalizeAgentSandbox } from "../lib/agent-sandbox.js";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Resolve + validate `--add-dir` values into absolute, existing, de-duped
|
|
@@ -171,6 +172,15 @@ export function registerAgentCommand(program) {
|
|
|
171
172
|
"--worktree",
|
|
172
173
|
"Run this session in a fresh git worktree (isolated branch; auto-removed when the session changes nothing)",
|
|
173
174
|
)
|
|
175
|
+
.option(
|
|
176
|
+
"--sandbox [image]",
|
|
177
|
+
"Run shell commands in an ephemeral Docker sandbox (network disabled by default)",
|
|
178
|
+
)
|
|
179
|
+
.option("--sandbox-network", "Allow network access inside --sandbox")
|
|
180
|
+
.option(
|
|
181
|
+
"--bg, --background",
|
|
182
|
+
"Start as a detached background agent and return its id immediately",
|
|
183
|
+
)
|
|
174
184
|
.option("--agent-id <id>", "Agent id for scoped memory recall")
|
|
175
185
|
.option("--recall-limit <n>", "Top-K memories to inject into system prompt")
|
|
176
186
|
.option("--recall-query <q>", "Query string for startup memory recall")
|
|
@@ -308,7 +318,29 @@ export function registerAgentCommand(program) {
|
|
|
308
318
|
"--replay-user-messages",
|
|
309
319
|
"Stream-input mode: echo each accepted stdin user message back as a `user` event (transcript/correlation)",
|
|
310
320
|
)
|
|
321
|
+
.option(
|
|
322
|
+
"--allow-dangerous-bypass",
|
|
323
|
+
"Bypass all permission prompts in headless mode (DANGEROUS: auto-approves all tool calls)",
|
|
324
|
+
false,
|
|
325
|
+
)
|
|
326
|
+
.option("-y, --yolo", "Alias for --allow-dangerous-bypass", false)
|
|
327
|
+
.option(
|
|
328
|
+
"--dangerously-skip-permissions",
|
|
329
|
+
"Alias for --allow-dangerous-bypass",
|
|
330
|
+
false,
|
|
331
|
+
)
|
|
311
332
|
.action(async (task, options, command) => {
|
|
333
|
+
const bypassPermissions = !!(
|
|
334
|
+
options.allowDangerousBypass ||
|
|
335
|
+
options.yolo ||
|
|
336
|
+
options.dangerouslySkipPermissions
|
|
337
|
+
);
|
|
338
|
+
if (bypassPermissions) {
|
|
339
|
+
process.env.CC_BYPASS_PERMISSIONS = "1";
|
|
340
|
+
process.stderr.write(
|
|
341
|
+
"⚠️ DANGER MODE: All permissions bypassed, no prompts will be shown.\n",
|
|
342
|
+
);
|
|
343
|
+
}
|
|
312
344
|
// --safe-mode flag OR CC_SAFE_MODE / CLAUDE_CODE_SAFE_MODE env (Claude-Code
|
|
313
345
|
// 2.1.169 parity): flip every customization kill-switch BEFORE anything
|
|
314
346
|
// loads. Permission rules stay active.
|
|
@@ -735,7 +767,62 @@ export function registerAgentCommand(program) {
|
|
|
735
767
|
if (piped) prompt = piped;
|
|
736
768
|
}
|
|
737
769
|
|
|
770
|
+
if (options.bg && !prompt) {
|
|
771
|
+
process.stderr.write(
|
|
772
|
+
"--bg requires a task via positional text, -p, or piped stdin.\n",
|
|
773
|
+
);
|
|
774
|
+
process.exitCode = 1;
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
738
778
|
if (prompt) {
|
|
779
|
+
if (options.bg) {
|
|
780
|
+
if (options.worktree) {
|
|
781
|
+
process.stderr.write(
|
|
782
|
+
"--bg and --worktree cannot be combined yet; create the worktree first and launch the background agent from it.\n",
|
|
783
|
+
);
|
|
784
|
+
process.exitCode = 1;
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
const { launchBackgroundAgent } =
|
|
788
|
+
await import("../lib/background-agent-supervisor.js");
|
|
789
|
+
const childArgv = process.argv
|
|
790
|
+
.slice(2)
|
|
791
|
+
.filter((arg) => arg !== "--bg" && arg !== "--background");
|
|
792
|
+
const hasSessionArg = childArgv.some(
|
|
793
|
+
(arg) =>
|
|
794
|
+
arg === "--session" ||
|
|
795
|
+
arg === "--resume" ||
|
|
796
|
+
arg === "--continue" ||
|
|
797
|
+
arg === "-c",
|
|
798
|
+
);
|
|
799
|
+
const sessionId =
|
|
800
|
+
options.session ||
|
|
801
|
+
`session-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
|
|
802
|
+
if (!hasSessionArg) childArgv.push("--session", sessionId);
|
|
803
|
+
const promptWasPiped =
|
|
804
|
+
positional.length === 0 &&
|
|
805
|
+
!(typeof options.print === "string" && options.print.trim());
|
|
806
|
+
if (promptWasPiped) childArgv.push(prompt);
|
|
807
|
+
const state = launchBackgroundAgent({
|
|
808
|
+
argv: childArgv,
|
|
809
|
+
cwd: process.cwd(),
|
|
810
|
+
sessionId,
|
|
811
|
+
title: prompt.slice(0, 100),
|
|
812
|
+
});
|
|
813
|
+
if (options.outputFormat === "json") {
|
|
814
|
+
console.log(JSON.stringify(state));
|
|
815
|
+
} else {
|
|
816
|
+
console.log(`Background agent started: ${state.id}`);
|
|
817
|
+
console.log(` logs: cc agents logs ${state.id}`);
|
|
818
|
+
console.log(` stop: cc agents stop ${state.id}`);
|
|
819
|
+
}
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
const agentSandbox = normalizeAgentSandbox(options.sandbox, {
|
|
823
|
+
cwd: process.cwd(),
|
|
824
|
+
network: options.sandboxNetwork === true,
|
|
825
|
+
});
|
|
739
826
|
// Resume requested onto a session with no headless (JSONL) transcript?
|
|
740
827
|
// Warn instead of silently starting empty 鈥?headless resume rebuilds
|
|
741
828
|
// from the JSONL store only (DB-only sessions are not replayable here).
|
|
@@ -775,6 +862,7 @@ export function registerAgentCommand(program) {
|
|
|
775
862
|
allowedTools: parseToolList(options.allowedTools),
|
|
776
863
|
disallowedTools: parseToolList(options.disallowedTools),
|
|
777
864
|
additionalDirectories,
|
|
865
|
+
sandbox: agentSandbox,
|
|
778
866
|
autoCheckpoint,
|
|
779
867
|
maxTurns,
|
|
780
868
|
// commander maps --no-file-refs 鈫?options.fileRefs === false
|
|
@@ -884,6 +972,10 @@ export function registerAgentCommand(program) {
|
|
|
884
972
|
parkOnExit: options.parkOnExit, // false when --no-park-on-exit
|
|
885
973
|
bundlePath: options.bundle || null,
|
|
886
974
|
additionalDirectories,
|
|
975
|
+
sandbox: normalizeAgentSandbox(options.sandbox, {
|
|
976
|
+
cwd: process.cwd(),
|
|
977
|
+
network: options.sandboxNetwork === true,
|
|
978
|
+
}),
|
|
887
979
|
autoCheckpoint,
|
|
888
980
|
// --vim: start the REPL in vim-mode editing (also CC_VIM=1 or /vim).
|
|
889
981
|
vimMode: options.vim === true,
|
package/src/commands/agents.js
CHANGED
|
@@ -22,6 +22,74 @@ export function registerAgentsCommand(program) {
|
|
|
22
22
|
.command("agents")
|
|
23
23
|
.description("User-defined subagents (.claude/agents/*.md)");
|
|
24
24
|
|
|
25
|
+
cmd
|
|
26
|
+
.command("background")
|
|
27
|
+
.alias("bg")
|
|
28
|
+
.description("List background agent sessions")
|
|
29
|
+
.option("--all", "Include completed, failed, stopped and lost sessions")
|
|
30
|
+
.option("--json", "Output as JSON")
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
const { listBackgroundAgents } =
|
|
33
|
+
await import("../lib/background-agent-supervisor.js");
|
|
34
|
+
const sessions = listBackgroundAgents({ all: options.all === true });
|
|
35
|
+
if (options.json) {
|
|
36
|
+
console.log(JSON.stringify(sessions, null, 2));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (sessions.length === 0) {
|
|
40
|
+
logger.log(chalk.gray("No background agents."));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const session of sessions) {
|
|
44
|
+
const elapsed = session.endedAt
|
|
45
|
+
? session.endedAt - session.startedAt
|
|
46
|
+
: Date.now() - session.startedAt;
|
|
47
|
+
logger.log(
|
|
48
|
+
`${chalk.cyan(session.id)} ${session.status.padEnd(9)} ${Math.max(0, Math.round(elapsed / 1000))}s ${session.title || ""}`,
|
|
49
|
+
);
|
|
50
|
+
logger.log(chalk.gray(` pid ${session.pid} ${session.cwd}`));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
cmd
|
|
55
|
+
.command("logs <id>")
|
|
56
|
+
.description("Print recent output from a background agent")
|
|
57
|
+
.option("-n, --lines <n>", "Number of lines", "100")
|
|
58
|
+
.action(async (id, options) => {
|
|
59
|
+
try {
|
|
60
|
+
const { readBackgroundAgentState, readBackgroundAgentLog } =
|
|
61
|
+
await import("../lib/background-agent-supervisor.js");
|
|
62
|
+
if (!readBackgroundAgentState(id)) {
|
|
63
|
+
throw new Error(`Background agent not found: ${id}`);
|
|
64
|
+
}
|
|
65
|
+
process.stdout.write(
|
|
66
|
+
readBackgroundAgentLog(id, { lines: Number(options.lines) }),
|
|
67
|
+
);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.error(chalk.red(error.message));
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
cmd
|
|
75
|
+
.command("stop <id>")
|
|
76
|
+
.description("Stop a running background agent")
|
|
77
|
+
.option("--json", "Output as JSON")
|
|
78
|
+
.action(async (id, options) => {
|
|
79
|
+
try {
|
|
80
|
+
const { stopBackgroundAgent } =
|
|
81
|
+
await import("../lib/background-agent-supervisor.js");
|
|
82
|
+
const state = stopBackgroundAgent(id);
|
|
83
|
+
if (options.json) console.log(JSON.stringify(state, null, 2));
|
|
84
|
+
else if (state.stopped)
|
|
85
|
+
logger.log(chalk.green(`Stopped background agent ${id}`));
|
|
86
|
+
else logger.log(chalk.gray(`${id} is already ${state.status}`));
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.error(chalk.red(error.message));
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
25
93
|
// ── list ──────────────────────────────────────────────────────────────
|
|
26
94
|
cmd
|
|
27
95
|
.command("list")
|
package/src/commands/note.js
CHANGED
|
@@ -8,6 +8,7 @@ import { numericOption } from "../lib/cli-numeric.js";
|
|
|
8
8
|
import { logger } from "../lib/logger.js";
|
|
9
9
|
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
10
10
|
import { likePrefix } from "../lib/sql-like.js";
|
|
11
|
+
import { safeJsonParse } from "../lib/safe-json.js";
|
|
11
12
|
import {
|
|
12
13
|
ensureVersionsTable,
|
|
13
14
|
saveVersion,
|
|
@@ -204,7 +205,7 @@ export function registerNoteCommand(program) {
|
|
|
204
205
|
} else {
|
|
205
206
|
logger.log(chalk.bold(`Notes (${notes.length}):\n`));
|
|
206
207
|
for (const n of notes) {
|
|
207
|
-
const tags =
|
|
208
|
+
const tags = safeJsonParse(n.tags, []);
|
|
208
209
|
const tagStr =
|
|
209
210
|
tags.length > 0 ? chalk.gray(` [${tags.join(", ")}]`) : "";
|
|
210
211
|
logger.log(
|
|
@@ -53,26 +53,33 @@ export function registerPermissionsCommand(program) {
|
|
|
53
53
|
cmd
|
|
54
54
|
.command("list")
|
|
55
55
|
.alias("ls")
|
|
56
|
-
.description(
|
|
56
|
+
.description(
|
|
57
|
+
"Show the merged permission ruleset and where each rule came from",
|
|
58
|
+
)
|
|
57
59
|
.option("--json", "Output as JSON")
|
|
58
60
|
.option("--settings <file>", "Also merge an explicit settings file")
|
|
59
61
|
.action(async (options) => {
|
|
60
62
|
try {
|
|
61
63
|
const { loadSettings } = await import("../lib/settings-loader.cjs");
|
|
62
|
-
const { rules, sources, files } = loadSettings({
|
|
64
|
+
const { rules, sources, files, managed, managedFile } = loadSettings({
|
|
63
65
|
cwd: process.cwd(),
|
|
64
66
|
settingsFile: options.settings,
|
|
65
67
|
});
|
|
66
68
|
if (options.json) {
|
|
67
|
-
console.log(
|
|
69
|
+
console.log(
|
|
70
|
+
JSON.stringify(
|
|
71
|
+
{ rules, sources, files, managed, managedFile },
|
|
72
|
+
null,
|
|
73
|
+
2,
|
|
74
|
+
),
|
|
75
|
+
);
|
|
68
76
|
return;
|
|
69
77
|
}
|
|
70
|
-
const total =
|
|
71
|
-
rules.allow.length + rules.ask.length + rules.deny.length;
|
|
78
|
+
const total = rules.allow.length + rules.ask.length + rules.deny.length;
|
|
72
79
|
if (total === 0) {
|
|
73
80
|
logger.log(
|
|
74
81
|
chalk.gray(
|
|
75
|
-
|
|
82
|
+
'No permission rules. Add one: cc permissions add deny "Bash(rm:*)"\n' +
|
|
76
83
|
"(or create .claude/settings.json with a permissions block)",
|
|
77
84
|
),
|
|
78
85
|
);
|
|
@@ -89,6 +96,40 @@ export function registerPermissionsCommand(program) {
|
|
|
89
96
|
if (files.length) {
|
|
90
97
|
logger.log(chalk.dim(`\nsources: ${files.join(", ")}`));
|
|
91
98
|
}
|
|
99
|
+
if (managedFile) {
|
|
100
|
+
logger.log(chalk.yellow(`managed policy: ${managedFile}`));
|
|
101
|
+
if (managed?.allowManagedPermissionRulesOnly) {
|
|
102
|
+
logger.log(
|
|
103
|
+
chalk.yellow(" user/project permission rules disabled"),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (
|
|
107
|
+
managed?.disableBypassPermissionsMode === true ||
|
|
108
|
+
managed?.disableBypassPermissionsMode === "disable"
|
|
109
|
+
) {
|
|
110
|
+
logger.log(chalk.yellow(" bypassPermissions disabled"));
|
|
111
|
+
}
|
|
112
|
+
if (managed?.allowManagedHooksOnly) {
|
|
113
|
+
logger.log(chalk.yellow(" only managed hooks may run"));
|
|
114
|
+
}
|
|
115
|
+
if (managed?.allowManagedMcpServersOnly) {
|
|
116
|
+
logger.log(
|
|
117
|
+
chalk.yellow(" only managed-allowed MCP servers may connect"),
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (managed?.requireSignedPlugins) {
|
|
121
|
+
logger.log(chalk.yellow(" signed plugin manifests required"));
|
|
122
|
+
}
|
|
123
|
+
if (
|
|
124
|
+
Array.isArray(managed?.allowedPlugins) ||
|
|
125
|
+
Array.isArray(managed?.deniedPlugins) ||
|
|
126
|
+
Array.isArray(managed?.blockedMarketplaces)
|
|
127
|
+
) {
|
|
128
|
+
logger.log(
|
|
129
|
+
chalk.yellow(" managed plugin supply-chain policy active"),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
92
133
|
} catch (err) {
|
|
93
134
|
logger.error(chalk.red(`permissions list failed: ${err.message}`));
|
|
94
135
|
process.exitCode = 1;
|
|
@@ -131,7 +172,13 @@ export function registerPermissionsCommand(program) {
|
|
|
131
172
|
if (options.json) {
|
|
132
173
|
console.log(
|
|
133
174
|
JSON.stringify(
|
|
134
|
-
{
|
|
175
|
+
{
|
|
176
|
+
tool: concrete,
|
|
177
|
+
args: toolArgs,
|
|
178
|
+
decision,
|
|
179
|
+
rule: result.rule,
|
|
180
|
+
source,
|
|
181
|
+
},
|
|
135
182
|
null,
|
|
136
183
|
2,
|
|
137
184
|
),
|
|
@@ -164,14 +211,19 @@ export function registerPermissionsCommand(program) {
|
|
|
164
211
|
cmd
|
|
165
212
|
.command("add <decision> <rule>")
|
|
166
213
|
.description("Append a rule (allow|ask|deny) to a settings file")
|
|
167
|
-
.option(
|
|
214
|
+
.option(
|
|
215
|
+
"--local",
|
|
216
|
+
"Write to .claude/settings.local.json (personal, gitignored)",
|
|
217
|
+
)
|
|
168
218
|
.option("--user", "Write to ~/.claude/settings.json (all projects)")
|
|
169
219
|
.action(async (decision, rule, options) => {
|
|
170
220
|
try {
|
|
171
221
|
const kind = String(decision || "").toLowerCase();
|
|
172
222
|
if (!["allow", "ask", "deny"].includes(kind)) {
|
|
173
223
|
logger.error(
|
|
174
|
-
chalk.red(
|
|
224
|
+
chalk.red(
|
|
225
|
+
`decision must be allow | ask | deny (got "${decision}")`,
|
|
226
|
+
),
|
|
175
227
|
);
|
|
176
228
|
process.exitCode = 1;
|
|
177
229
|
return;
|
|
@@ -188,7 +240,11 @@ export function registerPermissionsCommand(program) {
|
|
|
188
240
|
return;
|
|
189
241
|
}
|
|
190
242
|
|
|
191
|
-
const scope = options.user
|
|
243
|
+
const scope = options.user
|
|
244
|
+
? "user"
|
|
245
|
+
: options.local
|
|
246
|
+
? "local"
|
|
247
|
+
: "project";
|
|
192
248
|
const { addRule } = await import("../lib/settings-loader.cjs");
|
|
193
249
|
const { file, added } = addRule({
|
|
194
250
|
cwd: process.cwd(),
|
package/src/commands/plugin.js
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { logger } from "../lib/logger.js";
|
|
8
|
+
import {
|
|
9
|
+
enforcePluginPolicy,
|
|
10
|
+
loadPluginManagedPolicy,
|
|
11
|
+
verifyPluginManifest,
|
|
12
|
+
} from "../lib/plugin-security.js";
|
|
8
13
|
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
14
|
import {
|
|
10
15
|
installPlugin,
|
|
@@ -90,9 +95,32 @@ export function registerPluginCommand(program) {
|
|
|
90
95
|
.option("--description <desc>", "Plugin description")
|
|
91
96
|
.option("--author <author>", "Plugin author")
|
|
92
97
|
.option("--manifest <path>", "Plugin manifest file with skill declarations")
|
|
98
|
+
.option("--source <source>", "Plugin source or marketplace identifier")
|
|
99
|
+
.option("--sha256 <hex>", "Expected SHA-256 of the manifest")
|
|
100
|
+
.option("--signature <path>", "Detached Ed25519 signature of the manifest")
|
|
101
|
+
.option("--public-key <path>", "PEM public key used to verify --signature")
|
|
93
102
|
.option("--json", "Output as JSON")
|
|
94
103
|
.action(async (name, options) => {
|
|
95
104
|
try {
|
|
105
|
+
const managed = loadPluginManagedPolicy();
|
|
106
|
+
enforcePluginPolicy(
|
|
107
|
+
{ name, source: options.source, action: "install" },
|
|
108
|
+
managed,
|
|
109
|
+
);
|
|
110
|
+
let verifiedManifest = null;
|
|
111
|
+
let parsedManifest = null;
|
|
112
|
+
if (options.manifest || managed?.requireSignedPlugins) {
|
|
113
|
+
verifiedManifest = verifyPluginManifest({
|
|
114
|
+
manifestFile: options.manifest,
|
|
115
|
+
expectedSha256: options.sha256,
|
|
116
|
+
signatureFile: options.signature,
|
|
117
|
+
publicKeyFile: options.publicKey,
|
|
118
|
+
requireSignature: managed?.requireSignedPlugins === true,
|
|
119
|
+
trustedKeySha256: managed?.trustedPluginKeySha256,
|
|
120
|
+
requireTrustedKey: managed?.requireSignedPlugins === true,
|
|
121
|
+
});
|
|
122
|
+
parsedManifest = JSON.parse(verifiedManifest.bytes.toString("utf8"));
|
|
123
|
+
}
|
|
96
124
|
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
97
125
|
if (!ctx.db) {
|
|
98
126
|
logger.error("Database not available");
|
|
@@ -111,8 +139,9 @@ export function registerPluginCommand(program) {
|
|
|
111
139
|
if (options.manifest) {
|
|
112
140
|
try {
|
|
113
141
|
const fs = await import("fs");
|
|
114
|
-
const
|
|
115
|
-
|
|
142
|
+
const manifest =
|
|
143
|
+
parsedManifest ||
|
|
144
|
+
JSON.parse(fs.readFileSync(options.manifest, "utf-8"));
|
|
116
145
|
if (manifest.skills && manifest.skills.length > 0) {
|
|
117
146
|
const path = await import("path");
|
|
118
147
|
const pluginPath = path.dirname(path.resolve(options.manifest));
|
|
@@ -131,7 +160,17 @@ export function registerPluginCommand(program) {
|
|
|
131
160
|
if (options.json) {
|
|
132
161
|
console.log(
|
|
133
162
|
JSON.stringify(
|
|
134
|
-
{
|
|
163
|
+
{
|
|
164
|
+
...result,
|
|
165
|
+
skills: skillResult.installed,
|
|
166
|
+
integrity: verifiedManifest
|
|
167
|
+
? {
|
|
168
|
+
sha256: verifiedManifest.sha256,
|
|
169
|
+
signatureVerified: verifiedManifest.signatureVerified,
|
|
170
|
+
publicKeySha256: verifiedManifest.publicKeySha256,
|
|
171
|
+
}
|
|
172
|
+
: null,
|
|
173
|
+
},
|
|
135
174
|
null,
|
|
136
175
|
2,
|
|
137
176
|
),
|
|
@@ -205,6 +244,10 @@ export function registerPluginCommand(program) {
|
|
|
205
244
|
.argument("<name>", "Plugin name")
|
|
206
245
|
.action(async (name) => {
|
|
207
246
|
try {
|
|
247
|
+
enforcePluginPolicy(
|
|
248
|
+
{ name, action: "enable" },
|
|
249
|
+
loadPluginManagedPolicy(),
|
|
250
|
+
);
|
|
208
251
|
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
209
252
|
if (!ctx.db) {
|
|
210
253
|
logger.error("Database not available");
|
|
@@ -262,6 +305,10 @@ export function registerPluginCommand(program) {
|
|
|
262
305
|
.argument("<version>", "New version")
|
|
263
306
|
.action(async (name, version) => {
|
|
264
307
|
try {
|
|
308
|
+
enforcePluginPolicy(
|
|
309
|
+
{ name, action: "update" },
|
|
310
|
+
loadPluginManagedPolicy(),
|
|
311
|
+
);
|
|
265
312
|
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
266
313
|
if (!ctx.db) {
|
|
267
314
|
logger.error("Database not available");
|
package/src/commands/search.js
CHANGED
|
@@ -8,6 +8,7 @@ import ora from "ora";
|
|
|
8
8
|
import { logger } from "../lib/logger.js";
|
|
9
9
|
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
10
10
|
import { BM25Search } from "../lib/bm25-search.js";
|
|
11
|
+
import { safeJsonParse } from "../lib/safe-json.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Ensure the notes table exists (same as note.js)
|
|
@@ -213,7 +214,7 @@ export function registerSearchCommand(program) {
|
|
|
213
214
|
),
|
|
214
215
|
);
|
|
215
216
|
for (const r of results) {
|
|
216
|
-
const tags =
|
|
217
|
+
const tags = safeJsonParse(r.doc.tags, []);
|
|
217
218
|
const tagStr =
|
|
218
219
|
tags.length > 0 ? chalk.gray(` [${tags.join(", ")}]`) : "";
|
|
219
220
|
const snippet = (r.doc.content || "")
|
|
@@ -857,23 +857,30 @@ function _resolveBaseBranchForMerge(repoDir, baseBranch) {
|
|
|
857
857
|
}
|
|
858
858
|
|
|
859
859
|
function _applyAutomationResolution(repoDir, candidateId, filePath) {
|
|
860
|
+
// filePath here is a conflicted filename straight from `git diff --name-only`
|
|
861
|
+
// — i.e. it reflects whatever names exist in the (possibly untrusted) branch
|
|
862
|
+
// being merged. The sibling public functions assertSafeGitPath their filePath,
|
|
863
|
+
// but this internal helper interpolated it raw into a shell command string, so
|
|
864
|
+
// a file named `x"; rm -rf ~; ".txt` was a command-injection vector. Use the
|
|
865
|
+
// array-form gitExecArgs (spawnSync, no shell) so the path is a literal arg —
|
|
866
|
+
// injection-proof and correct for filenames with spaces/special chars too.
|
|
860
867
|
switch (candidateId) {
|
|
861
868
|
case "accept-current":
|
|
862
|
-
|
|
863
|
-
|
|
869
|
+
gitExecArgs(["checkout", "--theirs", "--", filePath], repoDir);
|
|
870
|
+
gitExecArgs(["add", "--", filePath], repoDir);
|
|
864
871
|
return;
|
|
865
872
|
case "accept-incoming":
|
|
866
873
|
case "restore-incoming":
|
|
867
|
-
|
|
868
|
-
|
|
874
|
+
gitExecArgs(["checkout", "--ours", "--", filePath], repoDir);
|
|
875
|
+
gitExecArgs(["add", "--", filePath], repoDir);
|
|
869
876
|
return;
|
|
870
877
|
case "restore-current":
|
|
871
|
-
|
|
872
|
-
|
|
878
|
+
gitExecArgs(["checkout", "--theirs", "--", filePath], repoDir);
|
|
879
|
+
gitExecArgs(["add", "--", filePath], repoDir);
|
|
873
880
|
return;
|
|
874
881
|
case "confirm-delete":
|
|
875
882
|
case "accept-delete":
|
|
876
|
-
|
|
883
|
+
gitExecArgs(["rm", "--", filePath], repoDir);
|
|
877
884
|
return;
|
|
878
885
|
default:
|
|
879
886
|
throw new Error(`Unsupported automation resolution: ${candidateId}`);
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { VERSION } from "./constants.js";
|
|
1
|
+
import { createBaseProgram } from "./program-base.js";
|
|
3
2
|
import { maybeNotifyUpdate } from "./lib/update-notice.js";
|
|
4
3
|
import { registerSetupCommand } from "./commands/setup.js";
|
|
5
4
|
import { registerStartCommand } from "./commands/start.js";
|
|
@@ -391,16 +390,9 @@ import { registerPipoV2Commands } from "./commands/pipeline.js";
|
|
|
391
390
|
* opts.allowedCommands takes precedence over the env var.
|
|
392
391
|
*/
|
|
393
392
|
export function createProgram(opts = {}) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
program
|
|
397
|
-
.name("chainlesschain")
|
|
398
|
-
.description(
|
|
399
|
-
"CLI for ChainlessChain - install, configure, and manage your personal AI management system",
|
|
400
|
-
)
|
|
401
|
-
.version(VERSION, "-v, --version")
|
|
402
|
-
.option("--verbose", "Enable verbose output")
|
|
403
|
-
.option("--quiet", "Suppress non-essential output");
|
|
393
|
+
// Base (name/version/global options) is shared with the lazy fast path
|
|
394
|
+
// (src/lazy-dispatch.js) via program-base.js so they can never drift.
|
|
395
|
+
const program = createBaseProgram();
|
|
404
396
|
|
|
405
397
|
// Passive update nudge (Claude-Code parity): one sync cache read + gray
|
|
406
398
|
// stderr line when a newer npm version is known; stale cache refreshes in a
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy CLI dispatch — the cold-start optimization.
|
|
3
|
+
*
|
|
4
|
+
* Importing src/index.js eagerly loads all ~154 command modules + their
|
|
5
|
+
* transitive dependency graph (~2.7s; see memory
|
|
6
|
+
* cli_cold_start_bottleneck_hub_repl). But a real `cc <cmd>` invocation only
|
|
7
|
+
* needs ONE command's module. This dispatcher resolves the target command from
|
|
8
|
+
* argv against the generated manifest (src/command-manifest.json) and imports
|
|
9
|
+
* just that module, then parses.
|
|
10
|
+
*
|
|
11
|
+
* SAFETY: anything uncertain — no command, --help, an unknown command, or a
|
|
12
|
+
* project-mode subcommand whitelist — falls back to the full eager program
|
|
13
|
+
* (src/index.js `createProgram`), i.e. exactly today's behavior. The fast path
|
|
14
|
+
* only activates when a single known command resolves cleanly. Worst case is
|
|
15
|
+
* therefore "as slow as today, still correct", never "wrong".
|
|
16
|
+
*
|
|
17
|
+
* The manifest is regenerated by scripts/gen-command-manifest.mjs and guarded
|
|
18
|
+
* against drift by lazy-dispatch.test.js.
|
|
19
|
+
*/
|
|
20
|
+
import { readFileSync } from "fs";
|
|
21
|
+
import { createBaseProgram } from "./program-base.js";
|
|
22
|
+
import { maybeNotifyUpdate } from "./lib/update-notice.js";
|
|
23
|
+
|
|
24
|
+
const manifest = JSON.parse(
|
|
25
|
+
readFileSync(new URL("./command-manifest.json", import.meta.url), "utf8"),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// name + every alias -> manifest entry
|
|
29
|
+
const byName = new Map();
|
|
30
|
+
for (const entry of manifest.commands) {
|
|
31
|
+
byName.set(entry.name, entry);
|
|
32
|
+
for (const alias of entry.aliases || []) byName.set(alias, entry);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The command token is the first positional arg (the first token that is not a
|
|
37
|
+
* global option). The root program's only global options (--verbose, --quiet)
|
|
38
|
+
* and the -v/--version / -h/--help flags are all boolean and never consume a
|
|
39
|
+
* following value, so "first token not starting with '-'" is unambiguous.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveCommandToken(argv) {
|
|
42
|
+
const rest = argv.slice(2);
|
|
43
|
+
for (const arg of rest) {
|
|
44
|
+
if (arg === "--") break;
|
|
45
|
+
if (arg.startsWith("-")) continue;
|
|
46
|
+
return arg;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hasVersionFlag(argv) {
|
|
52
|
+
return argv.slice(2).some((a) => a === "-v" || a === "--version");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function notify() {
|
|
56
|
+
// Mirror index.js: passive update nudge, suppressed under vitest.
|
|
57
|
+
if (!process.env.VITEST) {
|
|
58
|
+
try {
|
|
59
|
+
maybeNotifyUpdate();
|
|
60
|
+
} catch {
|
|
61
|
+
/* fail-open — never block the CLI on the nudge */
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse and run the CLI. Used by the bin entry in place of importing index.js
|
|
68
|
+
* directly (which would defeat lazy loading).
|
|
69
|
+
*
|
|
70
|
+
* @param {string[]} [argv] defaults to process.argv
|
|
71
|
+
* @returns {Promise<import('commander').Command>}
|
|
72
|
+
*/
|
|
73
|
+
export async function runCli(argv = process.argv) {
|
|
74
|
+
// Project-mode packed exes restrict the visible command set; the filtering
|
|
75
|
+
// lives in the eager createProgram, so defer to it for correctness.
|
|
76
|
+
const whitelistActive = !!process.env.CC_PROJECT_ALLOWED_SUBCOMMANDS;
|
|
77
|
+
const token = resolveCommandToken(argv);
|
|
78
|
+
|
|
79
|
+
// Fast path 1: a known command resolves cleanly.
|
|
80
|
+
if (token && !whitelistActive && byName.has(token)) {
|
|
81
|
+
const entry = byName.get(token);
|
|
82
|
+
const program = createBaseProgram();
|
|
83
|
+
notify();
|
|
84
|
+
const mod = await import(new URL(entry.module, import.meta.url));
|
|
85
|
+
const register = mod[entry.register];
|
|
86
|
+
if (typeof register === "function") {
|
|
87
|
+
register(program);
|
|
88
|
+
return program.parseAsync(argv);
|
|
89
|
+
}
|
|
90
|
+
// Manifest pointed at a missing export (should be impossible given the
|
|
91
|
+
// drift test) — fall through to the eager path rather than crash.
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Fast path 2: bare version request, no command (base program short-circuits
|
|
95
|
+
// without loading any command module).
|
|
96
|
+
if (!token && !whitelistActive && hasVersionFlag(argv)) {
|
|
97
|
+
const program = createBaseProgram();
|
|
98
|
+
notify();
|
|
99
|
+
return program.parseAsync(argv);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Fallback: --help, no args, unknown command, or project whitelist — load the
|
|
103
|
+
// full eager program (today's behavior; createProgram fires its own update
|
|
104
|
+
// nudge so we do not call notify() here to avoid a double nudge).
|
|
105
|
+
const { createProgram } = await import("./index.js");
|
|
106
|
+
return createProgram().parseAsync(argv);
|
|
107
|
+
}
|