chainlesschain 0.162.155 → 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-Cth_zZeA.js → AIOps-CfMP2Oud.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-zfwA3Oxn.js → ActionButton-Zu0N8BQL.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-FeKc4aU2.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-C2gRq5Qi.js → Audit-BMfiLj7T.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TeTIFiW-.js → BackgroundAgents-BslPCdGF.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CLJk3k6i.js → Backup-CQ_fMC1r.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-5ms537NY.js → BaseInput-CsFsARiC.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-4Nr5U9PJ.js → Chat-CwfBobco.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-K6Nf3xeN.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-B2Bca5ev.js → Checkbox-DkSyjjPp.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D6Uysdbv.js → Codegen-B7Fx3zZ6.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B3XQ8xc7.js → Col-Dzfqn8Ep.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CqwKtoPz.js → Community-DhHPdzMM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BZZINTus.js → Compact-Ct18_8y7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dr3BXkWA.js → Compliance-CY64IqBi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-rx_x9Wqc.js → Cowork-BYSmWlUl.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BpZr7rHc.js → Cron-_4xtP3Ug.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CeV5EYVg.js → Crosschain-B4qY-Ycr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-fe2Qaowz.js → DID-CkCzWkx1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Fh_EdWVa.js → Dashboard-C1scT7Ke.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-N1PIwWYf.js → Dropdown-DBnQ2EWd.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-B6vK93Ed.js → EmailListRenderer-C9JhOTq0.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-e3iUZhAg.js → FamilyGuardDashboard-CWXv5RUv.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-uInc9YcN.js → Federation-fYdcbz9W.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DmQZSX0z.js → FormItemContext-CJqOT3Yj.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CV_Z8OAo.js → GenericCardRenderer-DGCsHc5K.js} +1 -1
- package/src/assets/web-panel/assets/{Git-jXAhNN8d.js → Git-EH2K-H0Q.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Blw1esBB.js → Governance-DJn1X2pR.js} +1 -1
- package/src/assets/web-panel/assets/Inference-Dch1E8qd.js +1 -0
- package/src/assets/web-panel/assets/{KnowledgeGraph-5xrglMTK.js → KnowledgeGraph-QIur8j8-.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BGIG9798.js → Logs-DUgHldPg.js} +2 -2
- package/src/assets/web-panel/assets/Marketplace-DafrSfvd.js +1 -0
- package/src/assets/web-panel/assets/{McpTools-7U8tEhwK.js → McpTools-D2xRbfJx.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-BrvboPLE.js → Memory-C6RbVHAo.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-nzcd7d1H.js → MobileBridge-BPtVBKqn.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DETVNKa7.js → MobileProjects-Cuw832cr.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-SZcCYec3.js → Mtc-D6O9fWFa.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-Cx_d3N17.js → MtcAudit-CWZcXIH1.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-DtcmSUo-.js → Multisig-DhIBxTFd.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dgx2QHl-.js → NLProgramming-wkBFS33e.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-oHTGEHoJ.js → Notes-B09FxncA.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-qKD-IlOl.js → NotificationSettings-oQwtH6-9.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CiU4Sy1J.js → OrderTableRenderer-iFKeNf6Y.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BBNXnltP.js → Organization-CsF-NIjz.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Df2fDbvT.js → Overflow-bLxv9Dqi.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DUHj6zjO.js → P2P-DVwQtm4q.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B2nWgdoV.js → PdhVaultBrowser-Bgic3QKm.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CiW0afny.js → Permissions-as80-9ep.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-cc1mHU_D.js → PersonalDataHub-BGmUw36a.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-B93zTapU.js → Pipeline-BM96zBxG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Db1jXWfd.js → Privacy-BBOzBSWe.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DFoZ1h9U.js → ProjectInit-GHX41V28.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BkkUnmYs.js → ProjectSettings-DraqzxKD.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Xa779XLC.js → Projects-BzzdUml4.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DOF01IEN.js → Providers-CSeYNAtW.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-TohRsKd0.js → QrScannerModal-DlzBCdXh.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DjLcr1ZU.js → QuickAsk-p8iB7od_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend--Ism6bMx.js → Recommend-DjOVXacd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-B8CL3YHM.js → RemoteSession-CIGk7gk-.js} +2 -2
- package/src/assets/web-panel/assets/Reputation-CjT3M0Di.js +1 -0
- package/src/assets/web-panel/assets/{Row-BioxZBBH.js → Row-tw8m6T0c.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B2LipwH3.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-TibHuJWP.js → Security-JmtL8g7D.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DtkuWseW.js → Services-BxrNqjin.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BIcPQae6.js → Skeleton-udk8L18t.js} +1 -1
- package/src/assets/web-panel/assets/Skills-DooLT9of.js +1 -0
- package/src/assets/web-panel/assets/{Sla-uUSU185m.js → Sla-ITVZE1xI.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-B7Bgc9mk.js → SpeechSettings-DCkfqY1n.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-K-XrJ2s9.js → SyncSettings-CkNlgFjM.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-BMAoyCM_.js +1 -0
- package/src/assets/web-panel/assets/{Templates-CaFnyGDK.js → Templates-BnrFTlrz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C2X0PtEC.js → Tenant-BjNsy3-i.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CKU5yVsT.js → Terminal-C0gxLL7V.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-8trZeYDC.js → TimelineRenderer-CUtj_KHA.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BUEEe9US.js → Tokens-DOg61zlq.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-COU97I7Y.js → Trigger-D4ldCewj.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DNWQChaP.js → Trust-3lk_Zd8j.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DWX_VtCp.js → UkeySign-kWhFR6Li.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D9eIDhsp.js → VideoEditing-D3GOFVWg.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BOnCCgIL.js → Wallet-DzrZfBuh.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DN4dD-W8.js → WebAuthn-CyVJVp_g.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-ClvDb_jX.js → WorkflowEditor-i_b0wi9b.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DIxQ_Eeb.js → chat-DwPCK8I7.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BOX3WKcP.js → colors-D0vaVqZU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Bny82VDi.js → compact-item-Don7nGW2.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Cnoy3enS.js → createContext-D84R5qy2.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BBwWehQ7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BJ7fkx3F.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-CZ6CHiCQ.js → index-4MkfPLGv.js} +1 -1
- package/src/assets/web-panel/assets/{index-7GLXvG8p.js → index-7QUwcGTg.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1nHEOFE.js → index-B57al0Z5.js} +1 -1
- package/src/assets/web-panel/assets/{index-Kio1ekYg.js → index-BER98o4P.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9QEc7Tq.js → index-BNpJf-sf.js} +1 -1
- package/src/assets/web-panel/assets/{index--CcGiwAI.js → index-BZ1N07Sp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWPey0Uf.js → index-BlfTf0ka.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7Fah_BX.js → index-BohrJpBf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJ8-oLHI.js → index-Br3SOdER.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2qNdrNW.js → index-C0_sKVi7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQ-xLCVb.js → index-CAdCTTBC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSRIjAWO.js → index-CExWtm98.js} +1 -1
- package/src/assets/web-panel/assets/{index--Xb2lq6E.js → index-CL71rIwo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDkN6YOI.js → index-CfYRv-zA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bk5yST66.js → index-CnnxzIx0.js} +1 -1
- package/src/assets/web-panel/assets/{index-2N9Y1cLx.js → index-CrnVEEQO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW6n-y1L.js → index-CzT56x-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-OaNFXV8N.js → index-D4b5XqIy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEPTiBWy.js → index-D84BnuFg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZCTan8Q.js → index-D8r7WKk-.js} +1 -1
- package/src/assets/web-panel/assets/{index-rn6xd12s.js → index-DA0-EJKx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcmXbIwv.js → index-DBzBLX-K.js} +3 -3
- package/src/assets/web-panel/assets/{index-C--PPqwi.js → index-DFFzwrNs.js} +1 -1
- package/src/assets/web-panel/assets/index-DJ8etkBT.js +1 -0
- package/src/assets/web-panel/assets/{index-Ty4w18mR.js → index-DMT8n9vB.js} +4 -4
- package/src/assets/web-panel/assets/{index-qOBKrw-g.js → index-DQor_7NF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN6emwbq.js → index-DT40zd7K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM0mQhVv.js → index-De85D9Pc.js} +1 -1
- package/src/assets/web-panel/assets/{index-ceH9DsAi.js → index-IGGttsCv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBhkJqVF.js → index-L73NrmlW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbZynivw.js → index-LMo9bBLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bvheiep2.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-DxX8hhmL.js → index-WRw1pM5E.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6WoW8DJ.js → index-YKLCotoo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BP7HFsAK.js → index-hjgrIX5I.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnjtAKdw.js → index-m9bn0F1p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEq5Vh0i.js → index-wesQQ2cH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1-h2QrC.js → index-x7VYlV41.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BmxMBuUZ.js → initDefaultProps-DGeU4vPS.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DnXNwo2k.js → motion-Dgqj9ab3.js} +1 -1
- package/src/assets/web-panel/assets/{move-WnIJwmZN.js → move-BFyEU6Lr.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DAto-c2w.js → mtc-parser-CueCXXPC.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BtvW9W0H.js → omit-D2pU5OyE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DFqI9-_C.js → pickAttrs-CKTf6zD6.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Dax6wOK3.js → placementArrow-DieJaGCN.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BUFWWC83.js → responsiveObserve-Bxr-rmU6.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DyARyuSz.js → slide-CDEDk3Se.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BZSDugpi.js → statusUtils-icf2eCTx.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B7o_K-4R.js → styleChecker-qKvgmBhE.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dg7Bg8VG.js → useFlexGapSupport-1_UhiyJZ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DQYXo5Rk.js → useFs-CFGLXDWh.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-E8NBAnkq.js → usePersonalDataHub-UafOXvQ6.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DD71_w1b.js → vnode-BfPqSx79.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-zc9EMd3q.js → zoom-CXsVcRB6.js} +1 -1
- package/src/assets/web-panel/index.html +2 -2
- package/src/command-manifest.json +22 -1
- package/src/commands/agenda.js +228 -0
- package/src/commands/agent.js +45 -4
- package/src/commands/artifacts.js +161 -0
- package/src/commands/batch.js +345 -0
- package/src/commands/browse.js +204 -2
- package/src/data/changelog.json +13 -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 +18 -0
- package/src/lib/accessibility.js +55 -0
- package/src/lib/agent-batch.js +235 -0
- package/src/lib/agent-notify.js +66 -0
- package/src/lib/agent-schedule-store.js +330 -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 +197 -8
- package/src/runtime/coding-agent-contract-shared.cjs +156 -0
- package/src/runtime/coding-agent-policy.cjs +43 -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-C6WIrDZk.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BFEnA8LN.js +0 -1
- package/src/assets/web-panel/assets/Inference-CoK8Ia0Z.js +0 -1
- package/src/assets/web-panel/assets/Marketplace-DFqhJMuY.js +0 -1
- package/src/assets/web-panel/assets/Reputation-CaRxB3Ep.js +0 -1
- package/src/assets/web-panel/assets/Search-BpjLBV8u.js +0 -1
- package/src/assets/web-panel/assets/Skills-DoTWIQOX.js +0 -1
- package/src/assets/web-panel/assets/Tasks-B3hEXNcI.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Dr9dzlQ5.js +0 -1
- package/src/assets/web-panel/assets/index-B92M3t6B.js +0 -1
- package/src/assets/web-panel/assets/index-d2UcGpK-.js +0 -1
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc batch` — dynamic worktree batch (gap-analysis 第四阶段 #4). Split a big
|
|
3
|
+
* change into independent UNITS, run each in its own git worktree in parallel,
|
|
4
|
+
* test each, and aggregate diff/test/merge-conflict results.
|
|
5
|
+
*
|
|
6
|
+
* cc batch --units units.json # run declared units
|
|
7
|
+
* cc batch --units units.json --test "npm test" --concurrency 4 --merge
|
|
8
|
+
* cc batch --decompose "migrate all foo() calls to bar()" --parts 8
|
|
9
|
+
* # ask an agent to split the goal into a units.json, then run it
|
|
10
|
+
* cc batch --decompose "…" --parts 8 --plan-only # emit units, don't run
|
|
11
|
+
*
|
|
12
|
+
* units.json: { "units": [ { "key": "u1", "prompt": "…", "test": "npm test -w a" } ] }
|
|
13
|
+
*
|
|
14
|
+
* Real isolation comes from worktree-isolator (the same primitive `cc team
|
|
15
|
+
* --worktree` uses); the fan-out + aggregation core lives in lib/agent-batch.js
|
|
16
|
+
* (fully injectable). Branches persist for inspection unless merged.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from "fs";
|
|
20
|
+
import path from "path";
|
|
21
|
+
import { fileURLToPath } from "url";
|
|
22
|
+
import { spawn } from "child_process";
|
|
23
|
+
import { execFileSync } from "child_process";
|
|
24
|
+
import chalk from "chalk";
|
|
25
|
+
import { logger } from "../lib/logger.js";
|
|
26
|
+
import { runBatch } from "../lib/agent-batch.js";
|
|
27
|
+
import {
|
|
28
|
+
createWorktree,
|
|
29
|
+
removeWorktree,
|
|
30
|
+
previewWorktreeMerge,
|
|
31
|
+
mergeWorktree,
|
|
32
|
+
} from "../harness/worktree-isolator.js";
|
|
33
|
+
import { findProjectRoot } from "../lib/project-detector.js";
|
|
34
|
+
|
|
35
|
+
const BIN = path.resolve(
|
|
36
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
37
|
+
"..",
|
|
38
|
+
"..",
|
|
39
|
+
"bin",
|
|
40
|
+
"chainlesschain.js",
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const DECOMPOSE_SCHEMA = {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
units: {
|
|
47
|
+
type: "array",
|
|
48
|
+
items: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
key: { type: "string" },
|
|
52
|
+
prompt: { type: "string" },
|
|
53
|
+
test: { type: "string" },
|
|
54
|
+
},
|
|
55
|
+
required: ["key", "prompt"],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
required: ["units"],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export function registerBatchCommand(program) {
|
|
63
|
+
program
|
|
64
|
+
.command("batch")
|
|
65
|
+
.description(
|
|
66
|
+
"Split a large change into independent units, run each in its own git worktree in parallel, and aggregate results",
|
|
67
|
+
)
|
|
68
|
+
.option(
|
|
69
|
+
"--units <file>",
|
|
70
|
+
"Units JSON file ({ units: [{key, prompt, test?}] })",
|
|
71
|
+
)
|
|
72
|
+
.option(
|
|
73
|
+
"--decompose <goal>",
|
|
74
|
+
"Ask an agent to split this goal into units first (structured output)",
|
|
75
|
+
)
|
|
76
|
+
.option("--parts <n>", "Target number of units for --decompose", "6")
|
|
77
|
+
.option(
|
|
78
|
+
"--plan-only",
|
|
79
|
+
"With --decompose: print the units and exit (no run)",
|
|
80
|
+
)
|
|
81
|
+
.option("--concurrency <n>", "Max worktrees running at once", "4")
|
|
82
|
+
.option("--test <cmd>", "Default test command run in each worktree")
|
|
83
|
+
.option("--merge", "Merge clean, passing branches back to base")
|
|
84
|
+
.option("--model <model>", "Model for agent runs")
|
|
85
|
+
.option("--json", "Machine-readable JSON output")
|
|
86
|
+
.action(async (options) => {
|
|
87
|
+
process.exitCode = await runBatchCommand(options);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function runBatchCommand(options = {}, _deps = {}) {
|
|
92
|
+
const log = _deps.log || ((m) => console.log(m));
|
|
93
|
+
const errLog = _deps.err || ((m) => logger.error(m));
|
|
94
|
+
const repoDir =
|
|
95
|
+
_deps.repoDir || findProjectRoot(process.cwd()) || process.cwd();
|
|
96
|
+
|
|
97
|
+
// 1. Resolve the unit list — from a file, or by decomposing a goal.
|
|
98
|
+
let units;
|
|
99
|
+
try {
|
|
100
|
+
if (options.units) {
|
|
101
|
+
const doc = JSON.parse(fs.readFileSync(options.units, "utf8"));
|
|
102
|
+
units = Array.isArray(doc) ? doc : doc.units;
|
|
103
|
+
} else if (options.decompose) {
|
|
104
|
+
units = await (_deps.decompose || decomposeGoal)(
|
|
105
|
+
options.decompose,
|
|
106
|
+
Number(options.parts) || 6,
|
|
107
|
+
{ model: options.model, repoDir },
|
|
108
|
+
);
|
|
109
|
+
if (options.planOnly) {
|
|
110
|
+
log(JSON.stringify({ units }, null, 2));
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
errLog("Provide --units <file> or --decompose <goal>.");
|
|
115
|
+
return 4;
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
errLog(`Failed to resolve units: ${err.message}`);
|
|
119
|
+
return 4;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 2. Run the batch with real worktree + agent + git deps.
|
|
123
|
+
const deps = _deps.batchDeps || {
|
|
124
|
+
createWorktree: (key, branch) => createWorktree(repoDir, branch).path,
|
|
125
|
+
removeWorktree: (worktreePath, opts) =>
|
|
126
|
+
removeWorktree(repoDir, worktreePath, opts),
|
|
127
|
+
runAgent:
|
|
128
|
+
_deps.runAgent ||
|
|
129
|
+
((prompt, cwd) => spawnAgent(prompt, cwd, { model: options.model })),
|
|
130
|
+
runTest: _deps.runTest || runTestCommand,
|
|
131
|
+
diffStat: _deps.diffStat || gitDiffStat,
|
|
132
|
+
commit: _deps.commit || gitCommitAll,
|
|
133
|
+
previewMerge: (branch) => previewWorktreeMerge(repoDir, branch),
|
|
134
|
+
mergeBranch: (branch, message) =>
|
|
135
|
+
mergeWorktree(repoDir, branch, { message }),
|
|
136
|
+
branchFor: (key) => `batch/${sanitize(key)}`,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const onEvent = options.json ? () => {} : (ev) => log(formatEvent(ev));
|
|
140
|
+
|
|
141
|
+
let outcome;
|
|
142
|
+
try {
|
|
143
|
+
outcome = await runBatch(
|
|
144
|
+
{
|
|
145
|
+
units,
|
|
146
|
+
concurrency: options.concurrency,
|
|
147
|
+
test: options.test || null,
|
|
148
|
+
merge: options.merge === true,
|
|
149
|
+
onEvent,
|
|
150
|
+
},
|
|
151
|
+
deps,
|
|
152
|
+
);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
errLog(`Batch failed: ${err.message}`);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (options.json) {
|
|
159
|
+
log(JSON.stringify(outcome, null, 2));
|
|
160
|
+
} else {
|
|
161
|
+
log("");
|
|
162
|
+
log(chalk.bold(" Batch summary:"));
|
|
163
|
+
const s = outcome.summary;
|
|
164
|
+
log(
|
|
165
|
+
` ${s.total} units — ${chalk.green(s.done + " done")}, ` +
|
|
166
|
+
`${chalk.red(s.testFailed + " test-failed")}, ` +
|
|
167
|
+
`${chalk.yellow(s.errored + " errored")}, ${s.noChanges} no-change`,
|
|
168
|
+
);
|
|
169
|
+
if (options.merge) {
|
|
170
|
+
log(
|
|
171
|
+
` merged ${chalk.green(s.merged)}, conflicts ${chalk.yellow(s.conflicted)}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
log("");
|
|
175
|
+
}
|
|
176
|
+
// Non-zero when anything failed so CI can gate on it.
|
|
177
|
+
return outcome.summary.testFailed + outcome.summary.errored > 0 ? 1 : 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ─── real effectful deps ───────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
function sanitize(key) {
|
|
183
|
+
return String(key).replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function spawnAgent(prompt, cwd, opts = {}) {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
const args = [
|
|
189
|
+
BIN,
|
|
190
|
+
"agent",
|
|
191
|
+
"-p",
|
|
192
|
+
prompt,
|
|
193
|
+
"--permission-mode",
|
|
194
|
+
"acceptEdits",
|
|
195
|
+
"--output-format",
|
|
196
|
+
"text",
|
|
197
|
+
];
|
|
198
|
+
if (opts.model) args.push("--model", opts.model);
|
|
199
|
+
const child = spawn(process.execPath, args, {
|
|
200
|
+
cwd,
|
|
201
|
+
env: { ...process.env, CLAUDECODE: "1" },
|
|
202
|
+
windowsHide: true,
|
|
203
|
+
});
|
|
204
|
+
let err = "";
|
|
205
|
+
child.stderr?.on("data", (d) => (err += d.toString("utf8")));
|
|
206
|
+
child.on("error", (e) => reject(new Error(e.message)));
|
|
207
|
+
child.on("close", (code) =>
|
|
208
|
+
code === 0
|
|
209
|
+
? resolve({ code })
|
|
210
|
+
: reject(new Error(err.trim() || `agent exited ${code}`)),
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function runTestCommand(command, cwd) {
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
const child = spawn(command, {
|
|
218
|
+
cwd,
|
|
219
|
+
shell: true,
|
|
220
|
+
env: process.env,
|
|
221
|
+
windowsHide: true,
|
|
222
|
+
});
|
|
223
|
+
let err = "";
|
|
224
|
+
child.stderr?.on("data", (d) => (err += d.toString("utf8")));
|
|
225
|
+
child.on("error", (e) => reject(new Error(e.message)));
|
|
226
|
+
child.on("close", (code) =>
|
|
227
|
+
code === 0
|
|
228
|
+
? resolve({ code })
|
|
229
|
+
: reject(new Error(err.trim() || `test exited ${code}`)),
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** `git add -A` staged numstat totals for a worktree. */
|
|
235
|
+
function gitDiffStat(cwd) {
|
|
236
|
+
try {
|
|
237
|
+
execFileSync("git", ["add", "-A"], { cwd, stdio: "ignore" });
|
|
238
|
+
const out = execFileSync("git", ["diff", "--cached", "--numstat"], {
|
|
239
|
+
cwd,
|
|
240
|
+
encoding: "utf8",
|
|
241
|
+
});
|
|
242
|
+
let insertions = 0;
|
|
243
|
+
let deletions = 0;
|
|
244
|
+
let filesChanged = 0;
|
|
245
|
+
for (const line of out.split("\n")) {
|
|
246
|
+
const trimmed = line.trim();
|
|
247
|
+
if (!trimmed) continue;
|
|
248
|
+
const [add, del] = trimmed.split("\t");
|
|
249
|
+
filesChanged += 1;
|
|
250
|
+
insertions += add === "-" ? 0 : parseInt(add, 10) || 0;
|
|
251
|
+
deletions += del === "-" ? 0 : parseInt(del, 10) || 0;
|
|
252
|
+
}
|
|
253
|
+
return { filesChanged, insertions, deletions };
|
|
254
|
+
} catch {
|
|
255
|
+
return { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function gitCommitAll(cwd, message) {
|
|
260
|
+
try {
|
|
261
|
+
execFileSync("git", ["add", "-A"], { cwd, stdio: "ignore" });
|
|
262
|
+
execFileSync("git", ["commit", "-m", message, "--no-verify"], {
|
|
263
|
+
cwd,
|
|
264
|
+
stdio: "ignore",
|
|
265
|
+
});
|
|
266
|
+
return true;
|
|
267
|
+
} catch {
|
|
268
|
+
return false; // nothing to commit / commit failed
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Spawn a headless agent that emits a units JSON via --json-schema. */
|
|
273
|
+
async function decomposeGoal(goal, parts, opts = {}) {
|
|
274
|
+
const prompt =
|
|
275
|
+
`Split this task into ${parts} INDEPENDENT units that can each be done in a ` +
|
|
276
|
+
`separate git worktree WITHOUT depending on each other's changes. For each ` +
|
|
277
|
+
`unit give a short kebab-case "key", a self-contained "prompt" (the full ` +
|
|
278
|
+
`instruction for an agent working only on that unit), and optionally a "test" ` +
|
|
279
|
+
`shell command to verify it.\n\nTask: ${goal}`;
|
|
280
|
+
return new Promise((resolve, reject) => {
|
|
281
|
+
const args = [
|
|
282
|
+
BIN,
|
|
283
|
+
"agent",
|
|
284
|
+
"-p",
|
|
285
|
+
prompt,
|
|
286
|
+
"--json-schema",
|
|
287
|
+
JSON.stringify(DECOMPOSE_SCHEMA),
|
|
288
|
+
"--permission-mode",
|
|
289
|
+
"plan",
|
|
290
|
+
];
|
|
291
|
+
if (opts.model) args.push("--model", opts.model);
|
|
292
|
+
const child = spawn(process.execPath, args, {
|
|
293
|
+
cwd: opts.repoDir || process.cwd(),
|
|
294
|
+
env: { ...process.env, CLAUDECODE: "1" },
|
|
295
|
+
windowsHide: true,
|
|
296
|
+
});
|
|
297
|
+
let out = "";
|
|
298
|
+
let err = "";
|
|
299
|
+
child.stdout?.on("data", (d) => (out += d.toString("utf8")));
|
|
300
|
+
child.stderr?.on("data", (d) => (err += d.toString("utf8")));
|
|
301
|
+
child.on("error", (e) => reject(new Error(e.message)));
|
|
302
|
+
child.on("close", (code) => {
|
|
303
|
+
if (code !== 0) {
|
|
304
|
+
reject(new Error(err.trim() || `decompose agent exited ${code}`));
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
const parsed = JSON.parse(out.trim());
|
|
309
|
+
resolve(parsed.units);
|
|
310
|
+
} catch (e) {
|
|
311
|
+
reject(new Error(`could not parse decomposition output: ${e.message}`));
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function formatEvent(ev) {
|
|
318
|
+
switch (ev.type) {
|
|
319
|
+
case "batch:start":
|
|
320
|
+
return chalk.dim(
|
|
321
|
+
` batch: ${ev.units} units, concurrency ${ev.concurrency}`,
|
|
322
|
+
);
|
|
323
|
+
case "unit:start":
|
|
324
|
+
return chalk.dim(` ▶ ${ev.key} (${ev.branch})`);
|
|
325
|
+
case "unit:done": {
|
|
326
|
+
const badge =
|
|
327
|
+
ev.status === "done"
|
|
328
|
+
? chalk.green("✓")
|
|
329
|
+
: ev.status === "test-failed"
|
|
330
|
+
? chalk.red("✗ test")
|
|
331
|
+
: ev.status === "error"
|
|
332
|
+
? chalk.red("✗ error")
|
|
333
|
+
: chalk.gray("·");
|
|
334
|
+
return ` ${badge} ${ev.key} (${ev.filesChanged} files)`;
|
|
335
|
+
}
|
|
336
|
+
case "unit:integrated":
|
|
337
|
+
return ev.conflicts
|
|
338
|
+
? chalk.yellow(` ⚠ ${ev.key}: ${ev.conflicts} conflict(s)`)
|
|
339
|
+
: chalk.green(` ↳ ${ev.key}: ${ev.merged ? "merged" : "clean"}`);
|
|
340
|
+
default:
|
|
341
|
+
return "";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export const _internal = { decomposeGoal, gitDiffStat, DECOMPOSE_SCHEMA };
|
package/src/commands/browse.js
CHANGED
|
@@ -168,8 +168,18 @@ export function registerBrowseCommand(program) {
|
|
|
168
168
|
try {
|
|
169
169
|
const spinner = ora(`Taking screenshot of ${url}...`).start();
|
|
170
170
|
const result = await takeScreenshot(url, options.output, {
|
|
171
|
-
width: numericOption(options.width, {
|
|
172
|
-
|
|
171
|
+
width: numericOption(options.width, {
|
|
172
|
+
name: "--width",
|
|
173
|
+
integer: true,
|
|
174
|
+
min: 1,
|
|
175
|
+
fallback: 1280,
|
|
176
|
+
}),
|
|
177
|
+
height: numericOption(options.height, {
|
|
178
|
+
name: "--height",
|
|
179
|
+
integer: true,
|
|
180
|
+
min: 1,
|
|
181
|
+
fallback: 720,
|
|
182
|
+
}),
|
|
173
183
|
fullPage: !!options.fullPage,
|
|
174
184
|
});
|
|
175
185
|
spinner.stop();
|
|
@@ -188,9 +198,201 @@ export function registerBrowseCommand(program) {
|
|
|
188
198
|
}
|
|
189
199
|
});
|
|
190
200
|
|
|
201
|
+
registerBrowseChromeCommand(browse);
|
|
191
202
|
registerBrowseV2Command(browse);
|
|
192
203
|
}
|
|
193
204
|
|
|
205
|
+
/**
|
|
206
|
+
* `cc browse chrome` — Chrome connector: attach to the USER'S real Chrome
|
|
207
|
+
* over CDP so page state (DOM/console/network/screenshot) is captured WITH
|
|
208
|
+
* their login sessions. `launch` starts a debuggable Chrome (dedicated
|
|
209
|
+
* profile by default; `--default-profile` reuses the real one but requires
|
|
210
|
+
* every Chrome window to be closed first); `status` checks the port;
|
|
211
|
+
* `state` attaches, observes, and prints the page state.
|
|
212
|
+
*/
|
|
213
|
+
export function registerBrowseChromeCommand(browse) {
|
|
214
|
+
const chrome = browse
|
|
215
|
+
.command("chrome")
|
|
216
|
+
.description(
|
|
217
|
+
"Chrome connector — capture page state from YOUR logged-in Chrome over CDP",
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
chrome
|
|
221
|
+
.command("status")
|
|
222
|
+
.description("Is a debuggable Chrome listening on the CDP port?")
|
|
223
|
+
.option("-p, --port <port>", "CDP port", "9222")
|
|
224
|
+
.option("--json", "Output as JSON")
|
|
225
|
+
.action(async (options) => {
|
|
226
|
+
const { discoverCdp } = await import("../lib/chrome-connector.js");
|
|
227
|
+
const port = numericOption(options.port, {
|
|
228
|
+
name: "--port",
|
|
229
|
+
integer: true,
|
|
230
|
+
min: 1,
|
|
231
|
+
fallback: 9222,
|
|
232
|
+
});
|
|
233
|
+
const res = await discoverCdp({ port });
|
|
234
|
+
if (options.json) {
|
|
235
|
+
console.log(JSON.stringify(res, null, 2));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (res.ok) {
|
|
239
|
+
logger.success(`Debuggable Chrome on port ${port}: ${res.browser}`);
|
|
240
|
+
} else {
|
|
241
|
+
logger.info(
|
|
242
|
+
`No debuggable Chrome on port ${port}. Start one: cc browse chrome launch`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
chrome
|
|
248
|
+
.command("launch")
|
|
249
|
+
.description(
|
|
250
|
+
"Launch a debuggable Chrome (dedicated profile; sign in once there and it persists)",
|
|
251
|
+
)
|
|
252
|
+
.option("-p, --port <port>", "CDP port", "9222")
|
|
253
|
+
.option("-u, --url <url>", "Open this URL")
|
|
254
|
+
.option(
|
|
255
|
+
"--default-profile",
|
|
256
|
+
"Reuse your REAL Chrome profile (requires ALL Chrome windows closed; the CDP port then controls your logged-in browser)",
|
|
257
|
+
)
|
|
258
|
+
.option("--profile <dir>", "Custom profile directory")
|
|
259
|
+
.option("--json", "Output as JSON")
|
|
260
|
+
.action(async (options) => {
|
|
261
|
+
const { discoverCdp, launchChrome } =
|
|
262
|
+
await import("../lib/chrome-connector.js");
|
|
263
|
+
const port = numericOption(options.port, {
|
|
264
|
+
name: "--port",
|
|
265
|
+
integer: true,
|
|
266
|
+
min: 1,
|
|
267
|
+
fallback: 9222,
|
|
268
|
+
});
|
|
269
|
+
const existing = await discoverCdp({ port });
|
|
270
|
+
if (existing.ok) {
|
|
271
|
+
if (options.json) {
|
|
272
|
+
console.log(
|
|
273
|
+
JSON.stringify({ ok: true, already: true, port }, null, 2),
|
|
274
|
+
);
|
|
275
|
+
} else {
|
|
276
|
+
logger.success(
|
|
277
|
+
`A debuggable Chrome is already on port ${port} (${existing.browser})`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const res = launchChrome({
|
|
283
|
+
port,
|
|
284
|
+
url: options.url,
|
|
285
|
+
defaultProfile: options.defaultProfile === true,
|
|
286
|
+
profileDir: options.profile,
|
|
287
|
+
});
|
|
288
|
+
if (options.json) {
|
|
289
|
+
console.log(JSON.stringify({ ...res, port }, null, 2));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (!res.ok) {
|
|
293
|
+
logger.error(res.error);
|
|
294
|
+
process.exitCode = 1;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
logger.success(`Launched ${res.executable} (CDP port ${port})`);
|
|
298
|
+
if (options.defaultProfile) {
|
|
299
|
+
logger.info(
|
|
300
|
+
"Default profile requested — if the window did NOT get the debug port, close every Chrome window and retry.",
|
|
301
|
+
);
|
|
302
|
+
} else {
|
|
303
|
+
logger.info(
|
|
304
|
+
"Dedicated connector profile — sign in to your sites once there; the login state persists.",
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
logger.warn(
|
|
308
|
+
"The CDP port is an unauthenticated local control channel — close this Chrome when you are done.",
|
|
309
|
+
);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
chrome
|
|
313
|
+
.command("state")
|
|
314
|
+
.description(
|
|
315
|
+
"Attach to the connected Chrome and capture a tab's state (DOM/console/network/screenshot)",
|
|
316
|
+
)
|
|
317
|
+
.option("-p, --port <port>", "CDP port", "9222")
|
|
318
|
+
.option("-t, --tab <n>", "Tab index (see the tabs list in the output)", "0")
|
|
319
|
+
.option(
|
|
320
|
+
"--watch-ms <ms>",
|
|
321
|
+
"Observe console/network for this long (collected from attach time)",
|
|
322
|
+
"3000",
|
|
323
|
+
)
|
|
324
|
+
.option(
|
|
325
|
+
"--reload",
|
|
326
|
+
"Reload the tab first so load-time console/network is captured",
|
|
327
|
+
)
|
|
328
|
+
.option("--no-dom", "Skip the DOM snapshot")
|
|
329
|
+
.option("--dom-cap <chars>", "DOM snapshot cap", "150000")
|
|
330
|
+
.option("--screenshot <file>", "Also write a screenshot")
|
|
331
|
+
.option("--json", "Output as JSON")
|
|
332
|
+
.action(async (options) => {
|
|
333
|
+
const { captureState } = await import("../lib/chrome-connector.js");
|
|
334
|
+
const state = await captureState({
|
|
335
|
+
port: numericOption(options.port, {
|
|
336
|
+
name: "--port",
|
|
337
|
+
integer: true,
|
|
338
|
+
min: 1,
|
|
339
|
+
fallback: 9222,
|
|
340
|
+
}),
|
|
341
|
+
tab: numericOption(options.tab, {
|
|
342
|
+
name: "--tab",
|
|
343
|
+
integer: true,
|
|
344
|
+
min: 0,
|
|
345
|
+
fallback: 0,
|
|
346
|
+
}),
|
|
347
|
+
watchMs: numericOption(options.watchMs, {
|
|
348
|
+
name: "--watch-ms",
|
|
349
|
+
integer: true,
|
|
350
|
+
min: 0,
|
|
351
|
+
fallback: 3000,
|
|
352
|
+
}),
|
|
353
|
+
reload: options.reload === true,
|
|
354
|
+
includeDom: options.dom !== false,
|
|
355
|
+
domCap: numericOption(options.domCap, {
|
|
356
|
+
name: "--dom-cap",
|
|
357
|
+
integer: true,
|
|
358
|
+
min: 1000,
|
|
359
|
+
fallback: 150000,
|
|
360
|
+
}),
|
|
361
|
+
screenshotPath: options.screenshot || null,
|
|
362
|
+
});
|
|
363
|
+
if (options.json) {
|
|
364
|
+
console.log(JSON.stringify(state, null, 2));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!state.ok) {
|
|
368
|
+
logger.error(state.error);
|
|
369
|
+
process.exitCode = 1;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
logger.log(
|
|
373
|
+
chalk.bold(`Tab ${state.tab}: ${state.title || "(untitled)"}`),
|
|
374
|
+
);
|
|
375
|
+
logger.log(` ${chalk.cyan(state.url)}`);
|
|
376
|
+
logger.log(
|
|
377
|
+
` tabs: ${state.tabs.length} console: ${state.console.length} network issues: ${state.network.length}` +
|
|
378
|
+
(state.html
|
|
379
|
+
? ` dom: ${state.html.length}${state.htmlTruncated ? "+ (truncated)" : ""} chars`
|
|
380
|
+
: ""),
|
|
381
|
+
);
|
|
382
|
+
for (const c of state.console.slice(0, 20)) {
|
|
383
|
+
logger.log(` [console:${c.type}] ${c.text}`);
|
|
384
|
+
}
|
|
385
|
+
for (const nw of state.network.slice(0, 20)) {
|
|
386
|
+
logger.log(
|
|
387
|
+
` [net:${nw.kind}] ${nw.url}${nw.status ? ` → ${nw.status}` : ""}${nw.error ? ` (${nw.error})` : ""}`,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
if (state.screenshotPath) {
|
|
391
|
+
logger.success(`Screenshot: ${state.screenshotPath}`);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
194
396
|
import {
|
|
195
397
|
BROWSE_TARGET_MATURITY_V2,
|
|
196
398
|
BROWSE_ACTION_LIFECYCLE_V2,
|
package/src/data/changelog.json
CHANGED
|
@@ -3,20 +3,31 @@
|
|
|
3
3
|
"releases": [
|
|
4
4
|
{
|
|
5
5
|
"productVersion": "Unreleased",
|
|
6
|
-
"cliVersion": "0.162.
|
|
6
|
+
"cliVersion": "0.162.157",
|
|
7
7
|
"cliVersions": [
|
|
8
8
|
"0.4.46",
|
|
9
|
+
"0.4.51",
|
|
9
10
|
"0.37.4",
|
|
10
11
|
"0.162.150",
|
|
11
12
|
"0.162.151",
|
|
12
13
|
"0.162.152",
|
|
13
14
|
"0.162.153",
|
|
14
15
|
"0.162.154",
|
|
15
|
-
"0.162.155"
|
|
16
|
+
"0.162.155",
|
|
17
|
+
"0.162.156",
|
|
18
|
+
"0.162.157"
|
|
16
19
|
],
|
|
17
20
|
"date": null,
|
|
18
21
|
"title": "",
|
|
19
22
|
"sections": [
|
|
23
|
+
{
|
|
24
|
+
"heading": "Added — cc CLI 0.162.157:diff 审阅修订摘要 + plan 审阅快照 + Chrome 连接器 + Artifacts + Windows/PowerShell 一等 + --bare/无斜杠/读屏模式(CLI-only npm 发版)",
|
|
25
|
+
"body": "> `chainlesschain` 0.162.156 → **0.162.157** 发 npm `latest`(经 `npm-publish.yml`,`--provenance --access public`)。纯 `packages/cli/src` + 依赖指针(`@chainlesschain/personal-data-hub` 0.4.50→**0.4.51**,交易短信→金额事件,已先行在 npm);命令数 **172 → 173**(新增顶层 `cc artifacts`,13 文档面已扫);无 Android cc bundle rollover / 无 USR_VERSION 改动。agent-sdk 0.1.1(plan review payload additive 类型)此前已在 npm。\n\n- **Artifacts v1:`publish_artifact` agent 工具 + `cc artifacts` 命令**:agent 完成的交付物(报告/图表/构建产物)发布到 `~/.chainlesschain/artifacts`(index.jsonl + 按 id 存文件,title/kind/mime/sha256/session/TTL 元数据,100MB 守卫)——**只有元数据进对话/transcript**,大产物不再撑爆上下文;`cc artifacts list|show|open|remove|clean`(别名 `artifact`)管理与打开;工具 LOW 风险、plan 模式禁用(AGENT_TOOLS 23→24)。\n- **Windows/PowerShell 一等公民(批 22)**:run_shell 新增可选 `shell` 参数(`default|cmd|powershell|pwsh`),选择链 per-call > settings `shell.windowsDefault`(win32-only 分层,`CC_WINDOWS_SHELL` env 胜出)> 平台默认(未配置路径字节不变);PowerShell 经**显式 argv** 运行(`-NoProfile [-ExecutionPolicy <enum 校验>] -Command`,防 argv 走私);权限规则新增 `PowerShell(...)` 伞形族与 `shell:pwsh` 参数域;settings hooks 每 hook 可声明 `shell: powershell|pwsh`。结果携带 `shell`/`shell_note`。\n\n- **IDE diff 审阅:agent 能看到你改了什么(gap #4 收口的 CLI 面)**:在 IDE diff 里编辑 proposed content 后 Accept,工具结果此前只带 `userEdited: true` 布尔——agent 不知道你具体改了什么,其对文件的心智模型仍是它自己的原提案。现在新增 `userAmendments`:新纯核 `summarizeUserAmendments`(`lib/ide-context.js`)产出提案→实际写入的 -/+ 行级摘要,按最终文件 1-based 行锚定分块(复用 note-versioning 的 simpleDiff LCS;纯插入/删除直排防幻影空行;1M cell 守卫降级粗块;行数/字符双 cap)。配合 JetBrains 0.4.55(可编辑右栏回读)/ VS Code 0.37.x(原生支持)形成端到端闭环。\n- **plan 审阅快照写入会话(IDE plan review 的 CLI 协议面)**:`{type:\"plan\", action:\"approve\"|\"reject\"}` 控制消息现可携带 `review` 载荷(IDE 端 Markdown 审阅文档的快照 + 元数据,24k cap),CLI 把它写进会话 transcript——计划批准/拒绝留档可审计可回放(headless-stream.js;agent-sdk 0.1.1 `PlanControlInput.review` 类型同步)。\n- **`--bare`(`CC_BARE`)裸模式**:`--safe-mode` 全开关之上再关 skills(`CC_SKILLS=0`)、plugins(`CC_PLUGINS=0`)与 MCP/IDE/PDH/JetBrains 自动连接——两个新 env 各在单一咽喉点生效(skill-loader `loadAll` / plugin-runtime `discoverPlugins`);显式 `--mcp-config/--ide/--pdh/--jetbrains` 仍胜出;权限规则不放松。最小攻击面/最快启动的干净 agent 环境。\n- **`--disable-slash-commands`(`CC_DISABLE_SLASH_COMMANDS`)**:REPL 里 `/` 开头输入原样送模型(纯谓词 + NUL 哨兵,`lib/slash-dispatch`);`/exit`、`/quit` 保留;TAB 补全不再提示斜杠命令;宏与 MCP prompt 展开一并旁路。粘贴含 `/` 行首文本不再误触发。\n- **`--ax-screen-reader`(`CC_SCREEN_READER`)读屏友好模式**:mono 主题(零 ANSI 色)+ 状态栏关闭(新 `lib/accessibility.js`)——读屏器不再逐字念转义序列与高频刷新的状态行。\n- **`cc browse chrome status|launch|state`**:与 `browse fetch/scrape`(每次冷启空白 headless 浏览器)不同,连接器经 CDP attach 到**用户自己的 Chrome**,页面状态带着登录会话。`launch` 启动可调试 Chrome(默认**专用配置目录** `~/.chainlesschain/chrome-profile`——登录一次持久复用;`--default-profile` 可选复用真实配置但要求所有 Chrome 窗口先关闭);`status` 探测 CDP 端口;`state` attach 后观察窗口期内的 console 消息与失败/4xx-5xx 网络请求(CDP 无追溯历史,`--reload` 可捕获加载期输出),快照 URL/标题/DOM(默认 150k cap)/可选截图,断开不杀浏览器。安全注记:CDP 端口是本机无鉴权控制通道,仅绑 loopback,用完关闭该 Chrome。查找 Chrome/Edge 可执行文件跨三平台(`CHROME_PATH` 优先)。attach 后 page targets 有挂载延迟——轮询 3s 而非误报\"无标签页\"。6 单测(注入 deps)+ 真 Chrome 145 live e2e(discover→attach→console/network 捕获→DOM→截图→干净断开)。两 IDE 插件入口(VS `ChainlessChain: Chrome Connector` / JB Tools 同名)已随 VS Code 0.37.10 / JetBrains 0.4.53 上市场——本版补上其依赖的 CLI 端命令。"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"heading": "Added — cc CLI 0.162.156:agenda/batch 双命令(第四阶段收口)+ @chainlesschain/agent-sdk 0.1.0 npm 首发(CLI-only npm 发版)",
|
|
29
|
+
"body": "> `chainlesschain` 0.162.155 → **0.162.156** 发 npm `latest`(经 `npm-publish.yml`,`--provenance --access public`);**`@chainlesschain/agent-sdk` 0.1.0 同 run 首发 npm**(平台化第三阶段产物,npm-publish.yml / release.yml 均已加发布 step,防 trap #127 漏发)。纯 `packages/cli/src`(+web-panel dist 随包)+ 新独立包,未触 `pdh/lib` → 无 Android cc bundle rollover / 无 USR_VERSION 改动。命令数 **170 → 172**(新增顶层 `agenda`/`batch`,清单已重生,13 文档面已扫)。\n\n- **`cc agenda` + notify/schedule 双 agent 工具(第四阶段批19)**:Monitor/Cron/Push 暴露为 agent 可调工具(AGENT_TOOLS 21→23)——`notify` 推送到用户已配置的多通道通知器(Telegram/企业微信/钉钉/飞书);`schedule` 一工具五动作(wakeup/cron/monitor/list/cancel),单轮进程持不住定时器 → 意图持久化到 `~/.chainlesschain/agent-schedule/*.jsonl`(0600),由 `cc agenda list|run|cancel` 消费触发(wakeup/cron 到期 spawn `cc agent -p`,monitor 跑命令匹配 stop_when 即通知)。两工具 LOW 风险、plan 模式禁用;29 单测 + 真进程 smoke。\n- **`cc batch` 动态 worktree 批处理(第四阶段批20,第四阶段全收口)**:把大改动拆成独立单元并行跑——`--units <file>` 或 `--decompose <goal> --parts N`(agent 经 `--json-schema` 产单元 JSON,`--plan-only` 只打印);每单元独立 git worktree(复用 `cc team --worktree` 的 worktree-isolator),`--test` 门控、`--merge` 顺序集成(后合分支与已合冲突时报告不强合、测试失败单元永不合并);15 单测 + 2 真 git/worktree 集成测试。\n- **`@chainlesschain/agent-sdk` 0.1.0 首发**:`cc agent` stream-json 双工协议的 TypeScript 正式契约(Agent Protocol v1)——流式事件全词汇 + 审批回调(fail-closed)+ 检查点 + 会话恢复;`AgentSession` spawn 客户端(Windows `cmd.exe /c` shim + `NoDefaultCurrentDirectoryInExePath` 反劫持 + `taskkill /T` 进程树回收内置)、`attachBackgroundSession` 后台管道接管、`/browser` 浏览器安全入口(web-panel bg-\\* 帧)、`/protocol` 纯类型入口;双构建 ESM+CJS,零运行时依赖,36 测试(单元+真管道集成+真 CLI e2e)。VS Code 扩展(vendored)与 web-panel(vite alias)已消费;JetBrains 对齐语言中立 `docs/PROTOCOL.md`。用户文档 `docs-site/docs/chainlesschain/agent-sdk.md`。\n- 修复(随本版仓内,不在 cli 包面):SDK 真 CLI e2e 抓出的两 IDE 首会话不落盘洞(IDE 重载后 resume 静默空会话)已在两插件修复,随各自下次插件发版出货。"
|
|
30
|
+
},
|
|
20
31
|
{
|
|
21
32
|
"heading": "Added — cc CLI 0.162.155:权限模式/auto 分类器 + 后台会话可交互接管全家桶(第一阶段收口,CLI-only npm 发版)",
|
|
22
33
|
"body": "> `chainlesschain` 0.162.154 → **0.162.155** 已发 npm `latest`(经 `npm-publish.yml`,`--provenance --access public`)。纯 `packages/cli/src`(+web-panel dist 随包)增量,未触 `pdh/lib` → 无 Android cc bundle rollover / 无 USR_VERSION 改动。gap-analysis「第一阶段:安全与可运营性」4 项全部落地(批 1-15,9 commit `e3ab46c73f..1618a3ca83`)。命令数 **165 → 170**(新增顶层 `attach`/`auto-mode`/`daemon`/`logs`/`remote-control`,清单已重生)。发版前本机三层全绿(unit 21808 / integration 除 1 已知 real-spawn flake 隔离 3 连绿 / e2e 628)。\n\n- **权限模式补齐 `manual`/`auto`/`dontAsk`**(headless + 交互 REPL 双面):`manual`=default 别名;`auto`=可配置分类器——settings `autoMode.decisions` 按 riskLevel(对象/数组形)与 tool/commandPattern 细粒度规则(`*` glob,声明序优先)映射 allow/ask/deny,未配置时字节不变映射 trusted;`dontAsk`=需确认动作直接 deny 不弹审批(REPL 两处 confirmer 全覆盖)。REPL `/permissions auto|dontask` 中途切换,Shift+Tab 循环兼容;`cc agent --permission-mode` 对交互式会话生效(顺带修 `resolveAgentPolicy` 白名单静默丢弃 `--vim/--think/--fallback-model/--pdh` 等交互 flag 的预存 bug)。\n- **`cc auto-mode defaults|config [--json]`**:内置分类默认值文档 + user/project/local/managed 分层合并后的有效配置(含细粒度规则展示);修 `mergeSandboxSettings` 数组分支把数组形 decisions 毁成 `\"[object Object]\"` 的潜伏 bug(新 `mergeAutoModeSettings`,decisions=有序规则集 closer 层整体替换)。\n- **`cc permissions recent|denials [--json|--clear]` + 决策逐层解释链**:跨会话持久 denial ring buffer(headless + REPL 双源);被拒 run_shell 附带 `permissionChain`(settings-rules→shell-policy→approval-gate 各层判定+理由),`/permissions denials` 与 `cc permissions recent` 渲染紧凑链——一眼看清「allow 规则为何没生效」。\n- **后台会话可运营全家桶**:顶层 `cc logs <id>` / `cc attach <id>` / `cc daemon status|view|stop|rename|resume`。worker heartbeat + workerPid/agentPid 分离 + stale-heartbeat/PID-reuse 防误杀(可靠标 `lost`);`cc daemon resume <id> <prompt>` 把崩溃/终态会话按 sessionId 续接为新后台运行(原 argv 有意不持久化防 secrets 落盘)。\n- **`cc attach` 可交互接管(session transport)**:worker 每会话托管本地 NDJSON 控制通道(Win named pipe / POSIX socket,随机 token 存 0600 state 文件);attach 后键入即发 follow-up prompt(同 `--session` 自动续接对话史,多轮 turn 循环),`/stop` 截断当前轮,turn 运行中断开任务照跑、idle 断开会话收尾;transport 不可用自动回退日志流,`--no-input` 强制纯日志。\n- **web-panel「后台 Agent」面板**:新 `bg-*` WS 协议(list/view/attach/prompt/stop-turn/detach/stop/rename/resume,attach 期间推送 worker 事件与日志增量);takeover token 永不过 WS 边界。面板含列表/接管卡片/日志流/重命名/续跑。\n- 修复:后台 rename 与 worker read-modify-write 竞态(写后校验+有界重试);`settingsVerdict` 未传入 executeToolInner 的解释链断点;launcher/worker 状态竞写(先写 state 后 spawn + heartbeat 重申 transport)。\n- **`cc remote-control`(第四阶段批17,随本版一同发布)**:统一远控入口(别名 `rc`)——start/status/stop 组合既有 remote-session 栈(WS server + E2EE relay + registry + ledger + push + audit),配对 URI 双模式(relay E2EE / 直连 LAN),跨进程 0600 state 发现;顺带修 `cc serve --remote-session-relay-url` 白名单丢参从未生效的预存 bug。\n- **MCP tool search(第二阶段批16,随本版一同发布)**:大规模 MCP 面下工具定义超上下文阈值(默认窗口 10%,`mcp.toolSearch` settings / `CC_TOOL_SEARCH` env 可配)时自动换成 `[deferred]` stub + 内部 `tool_search` 检索工具;完整 schema 经 tool result 返回(append-only,保 prompt cache 稳定);REPL `/context` 新增 MCP tool schemas 占用与优化建议一节。未超阈值/关闭时行为字节不变。"
|