chainlesschain 0.162.44 → 0.162.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-DKzTpK-Y.js → AIOps-QzHleqCS.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CMAlqdwe.js → ActionButton-CZ3F-KVY.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-QMe2cbkc.js → Analytics-CHml-drq.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DWSbQ4Li.js → AppLayout-a-fczvRH.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-B2m5_PZ1.js → Audit-CtMWsXwm.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CfTZgrj4.js → Backup-ErWTcS0A.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DQMQQpXM.js → BaseInput-B4w2b2dA.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-XSNjF8Mp.js → Chat-CFPKVfmV.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BjWwWSBW.js → ChatBubbleRenderer-WGpUTY92.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DcHFXGYe.js → Checkbox-C4vasfJc.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CbGi3e7e.js → Codegen-DHmDAbSg.js} +1 -1
- package/src/assets/web-panel/assets/{Col-uRz8SHXE.js → Col-LhgveyhM.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CneB2EQd.js → Community-CB8gtudt.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C9t4kI4u.js → Compact-CTndsUSy.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BSgNNAgN.js → Compliance-CCpGUHPm.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BOJD_XKQ.js → Cowork-CQmJiOM_.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DBZVqJWg.js → Cron-TrTmpnSB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BPBndx_n.js → Crosschain-DvaR1Xq4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BFeOnAbj.js → DID-CdDdiRs3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DR_krdui.js → Dashboard-S6gCBQDc.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DBFIX9zX.js → Dropdown-CWO-Kwzl.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-j7nUo0EN.js → EmailListRenderer-Crnrr1-p.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BNrIZkRp.js → FamilyGuardDashboard-OpG9ZtfR.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D1cPCDKh.js → Federation-B0sybW7G.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C24JXiJZ.js → FormItemContext-DjHMvxwJ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-g-EsfuMZ.js → GenericCardRenderer-DtU5cWwE.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BVEJZ29p.js → Git-BhOjZX2a.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B-fAe2v1.js → Governance-D3_hjjA-.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DBYa0ztr.js → Inference-DwxLXmgA.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-B0S0at2T.js → KnowledgeGraph-C8-FVs02.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BUHn58RG.js → Logs-CrHjnzfr.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-DSYpWtgR.js → Marketplace-KW1Am18o.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Cm_GD-uS.js → McpTools-ezYH1J8m.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CB9uRtzi.js → Memory-Dcv8Gume.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-vgX_FQ74.js → MobileBridge-v18J0LN4.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-DCMhJceG.js → MobileProjects-kk6hAwkK.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Atr0Zh0n.js → Mtc-Cm35-vh_.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DxQjtoAG.js → MtcAudit-DyeKAlI_.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DBc1IRY-.js → Multisig-Dy-imleB.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C55Qg6EX.js → NLProgramming-DMVmWNAH.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CVRXn9dM.js → Notes-Dq6oHKbl.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-B8_Y2rYz.js → NotificationSettings-CCaSupDi.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-DOwptdNb.js +1 -0
- package/src/assets/web-panel/assets/{Organization-fmONrEpS.js → Organization-8TF96XtV.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DtS9U-lj.js → Overflow-BnYnh84b.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BCp9IFsu.js → P2P-CZk3Qkec.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-FB03lQ_0.js → PdhVaultBrowser-D1HrzBx2.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BD3VCCBY.js → Permissions-CwJ6hcaI.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-I_dIzQfI.js → PersonalDataHub-BGnPTj1G.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BfqiuVgI.js → Pipeline-BzXhXLBz.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Dnm-Lxv0.js → Privacy-BaVQ3GwL.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-D12saZXQ.js → ProjectInit-Bik3h4R7.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BHk78dtG.js → ProjectSettings-CIuC6Hpr.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BQgMcz56.js → Projects-DLjnWEe6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Bs7dxjKE.js → Providers-mhxZrHiK.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CqhoJCPD.js → QuickAsk-Dk9mayL0.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D-l-eJFr.js → Recommend-BHC2sBZY.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-CPrlP2Ux.js → Reputation-DV26B11J.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C3Q9Dshq.js → Row-bJlVEnFC.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DlLlpbtD.js → RssFeed-D_XucmWY.js} +2 -2
- package/src/assets/web-panel/assets/{Search-EIs5mUs2.js → Search-uKXcm_Kf.js} +1 -1
- package/src/assets/web-panel/assets/{Security-NJbvreOk.js → Security-DEzqsQLn.js} +3 -3
- package/src/assets/web-panel/assets/{Services-B-GS4dFT.js → Services-I8qKgcom.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bycye0oO.js → Skeleton-BmrglBMu.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D9gOTB8D.js → Skills-CHN4ZDyP.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-hR2sLl6u.js → Sla-Ca6FsUS2.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-xNkqwlx_.js → SpeechSettings-CP8IikWb.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-C53VuHwk.js → SyncSettings-Bqp-kPAA.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-XIDFrKjD.js → Tasks-C7FvJjze.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-JA8aUZm3.js → Templates-Bq51Irli.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DjGO2SFi.js → Tenant-OTducEVg.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-ywwPryM5.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-Cfalxtc_.js → TimelineRenderer-kCmFL2wc.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-lvG8zW-n.js → Tokens-BUfD650M.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-G3EmMFkS.js → Trigger-CqpM6xE7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BDXSbpLN.js → Trust--4gS7a0j.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-9GtCtwS7.js → UkeySign-B7wfki-b.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DorUOflW.js → VideoEditing-FwDEX2S-.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B1PSsoH7.js → Wallet-DS_c2rMk.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BlawNPwk.js → WebAuthn-CdMhP-GP.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DT5tXYHC.js → WorkflowEditor-DVvpoOmg.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Db1ggy-d.js → chat-BQyTT2BS.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DvKRY65P.js → colors-DvylfUTx.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-ChJE-s12.js → compact-item-Budvh2nW.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C_n8N7R0.js → createContext-DkNa84zG.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CG_75MBJ.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-f5qrOyO8.js → hasIn-Dc1juUIf.js} +1 -1
- package/src/assets/web-panel/assets/{index-6-pawsDV.js → index-B0u5DW4Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-C99Tx6W3.js → index-BC08UMEf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cwx25An4.js → index-BCD2L2SI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBDuh9Q_.js → index-BCv_FUY5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_Db3y-q.js → index-BEviVulf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZM-f_GP.js → index-BQJA__yH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlXvSz68.js → index-BTnZ44a_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRPjpA9x.js → index-BTzrvuB0.js} +1 -1
- package/src/assets/web-panel/assets/{index-cNZUziLU.js → index-BWcGURYh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgVhpbwl.js → index-BYuozZuh.js} +1 -1
- package/src/assets/web-panel/assets/index-Ba6DLEa1.js +1 -0
- package/src/assets/web-panel/assets/{index-DNcqoZEW.js → index-BgYKjtNP.js} +1 -1
- package/src/assets/web-panel/assets/{index-MW_Zh_HW.js → index-BgxdM7b_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBtvIJ1P.js → index-Bk_Uhu49.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVWPEAS_.js → index-By8Bs_eN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkSc1UD0.js → index-C1X5QpSy.js} +1 -1
- package/src/assets/web-panel/assets/{index-ru1UNElJ.js → index-C8he-Xo0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRpYACac.js → index-CFMS9PKh.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2vRDPxa.js → index-CGHLsKyb.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_ca6G9G.js → index-CKoWcis9.js} +1 -1
- package/src/assets/web-panel/assets/index-CLycnSs-.js +1 -0
- package/src/assets/web-panel/assets/{index-B889nFIK.js → index-CbCIBifY.js} +1 -1
- package/src/assets/web-panel/assets/{index-dbd8KVOi.js → index-Cz41iB_M.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZIg1Yi8T.js → index-D2dcbmzD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLJldKpu.js → index-D74oTZL7.js} +1 -1
- package/src/assets/web-panel/assets/{index-bYgSwFp_.js → index-D7FYxxFT.js} +3 -3
- package/src/assets/web-panel/assets/{index-CnBPm5VW.js → index-DMCqz0wy.js} +1 -1
- package/src/assets/web-panel/assets/{index-LADrnz2q.js → index-DO9Lvv1w.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDwTm4HW.js → index-DRNJnXik.js} +1 -1
- package/src/assets/web-panel/assets/{index-aRdl6HAc.js → index-DTcZkWJ7.js} +1 -1
- package/src/assets/web-panel/assets/{index-xytEYrmf.js → index-D_0nyIY9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmDr3_dh.js → index-DecFF9je.js} +1 -1
- package/src/assets/web-panel/assets/{index-zDFZeRny.js → index-DwJ0d_2Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bv3rnRcv.js → index-DxCPTrC-.js} +1 -1
- package/src/assets/web-panel/assets/{index-gEBZrC4a.js → index-TsPv8m1Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzfpAd-L.js → index-YVdWdhK_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGcNc2FC.js → index-eD_MN29w.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSn8UWj1.js → index-jTGSFnNF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLbUSjRl.js → index-yx5Y6xb7.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BmuULb3C.js → initDefaultProps-gLjyJG0Q.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BPAdGPV0.js → motion-BtXv1r2p.js} +1 -1
- package/src/assets/web-panel/assets/{move-CfQuWRIA.js → move-BgFqW2gA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B4X1FaKf.js → omit-CeIwl-eJ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CnNXE2Fs.js → pickAttrs-VlY4igbs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bb5asP1f.js → placementArrow-B9Wjn3oR.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CFYMBsLT.js → responsiveObserve-BBgHTvYX.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Pf9K-RqE.js → slide-DWw81KAi.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DmGXqpMA.js → statusUtils-Bsho38w-.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-3ymOCpPp.js → styleChecker-BNvVEdm1.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CiCbo3Hx.js → useFlexGapSupport-DG9bkwrT.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BbhWqkvH.js → useFs-DU7qrIrQ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BNjAwFwx.js → usePersonalDataHub-DX-Bf7VJ.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Dsmjnl6v.js → vnode-B1UcnNoK.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Dx0p7V8W.js → zoom-BFgJuvLv.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +49 -30
- package/src/commands/hub.js +87 -0
- package/src/harness/mcp-client.js +86 -1
- package/src/lib/auto-checkpoint-default.js +49 -0
- package/src/lib/personal-data-hub-wiring.js +44 -2
- package/src/lib/repl-completer.js +6 -3
- package/src/lib/skill-loader.js +43 -7
- package/src/repl/agent-repl.js +27 -1
- package/src/runtime/headless-stream.js +77 -1
- package/src/runtime/mcp-config.js +19 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BvbjrcIW.js +0 -1
- package/src/assets/web-panel/assets/Terminal-D_8L6tYA.js +0 -3
- package/src/assets/web-panel/assets/devWarning-8RHlZueh.js +0 -1
- package/src/assets/web-panel/assets/index-DiVQYFZe.js +0 -1
- package/src/assets/web-panel/assets/index-QQHpE5N6.js +0 -1
package/src/commands/agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
2
|
* Agentic AI assistant - Claude Code style
|
|
3
3
|
* chainlesschain agent [--model] [--provider]
|
|
4
4
|
*
|
|
@@ -44,7 +44,7 @@ export function resolveAddDirs(rawDirs) {
|
|
|
44
44
|
* thinking `budget_tokens`), or undefined when unset/invalid. Pure; exported for
|
|
45
45
|
* tests. The companion `thinking` toggle comes from --think/--ultrathink; a
|
|
46
46
|
* budget without that toggle is a no-op (chatWithTools only reads it when
|
|
47
|
-
* thinking is on, and only for legacy models
|
|
47
|
+
* thinking is on, and only for legacy models 鈥?adaptive models use effort).
|
|
48
48
|
*
|
|
49
49
|
* @param {string|number} [raw]
|
|
50
50
|
* @returns {number|undefined}
|
|
@@ -85,7 +85,7 @@ export function registerAgentCommand(program) {
|
|
|
85
85
|
)
|
|
86
86
|
.argument(
|
|
87
87
|
"[task...]",
|
|
88
|
-
"Headless task
|
|
88
|
+
"Headless task 鈥?when given (or with -p / piped stdin), runs non-interactively",
|
|
89
89
|
)
|
|
90
90
|
.option("--model <model>", "Model name")
|
|
91
91
|
.option(
|
|
@@ -118,11 +118,11 @@ export function registerAgentCommand(program) {
|
|
|
118
118
|
.option("--session <id>", "Resume a previous agent session")
|
|
119
119
|
.option(
|
|
120
120
|
"-c, --continue",
|
|
121
|
-
"Resume the most recent session (no id needed
|
|
121
|
+
"Resume the most recent session (no id needed 鈥?claude --continue parity)",
|
|
122
122
|
)
|
|
123
123
|
.option(
|
|
124
124
|
"--resume [id]",
|
|
125
|
-
"Resume a session by id (no id
|
|
125
|
+
"Resume a session by id (no id 鈫?most recent 鈥?claude --resume parity)",
|
|
126
126
|
)
|
|
127
127
|
.option(
|
|
128
128
|
"--fork-session",
|
|
@@ -135,7 +135,11 @@ export function registerAgentCommand(program) {
|
|
|
135
135
|
)
|
|
136
136
|
.option(
|
|
137
137
|
"--checkpoint",
|
|
138
|
-
"Auto-snapshot the work tree before each mutating tool (git repo; cc checkpoint restore to roll back)",
|
|
138
|
+
"Auto-snapshot the work tree before each mutating tool (DEFAULT inside a git repo; cc checkpoint restore to roll back)",
|
|
139
|
+
)
|
|
140
|
+
.option(
|
|
141
|
+
"--no-checkpoint",
|
|
142
|
+
"Disable auto-checkpointing (it is on by default inside git repos)",
|
|
139
143
|
)
|
|
140
144
|
.option("--agent-id <id>", "Agent id for scoped memory recall")
|
|
141
145
|
.option("--recall-limit <n>", "Top-K memories to inject into system prompt")
|
|
@@ -150,7 +154,7 @@ export function registerAgentCommand(program) {
|
|
|
150
154
|
"--bundle <path>",
|
|
151
155
|
"Agent bundle directory (chainless-agent.toml + AGENTS.md + skills/ + mcp.json + USER.md)",
|
|
152
156
|
)
|
|
153
|
-
//
|
|
157
|
+
// 鈹€鈹€ Headless / print mode (Claude-Code `claude -p` parity) 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
154
158
|
.option(
|
|
155
159
|
"-p, --print [prompt]",
|
|
156
160
|
"Headless: run one non-interactive turn and exit",
|
|
@@ -227,6 +231,10 @@ export function registerAgentCommand(program) {
|
|
|
227
231
|
"Force-enable IDE bridge auto-connect: discover a running editor's MCP server via ~/.chainlesschain/ide/*.json (default: auto inside an IDE integrated terminal)",
|
|
228
232
|
)
|
|
229
233
|
.option("--no-ide", "Disable IDE bridge auto-connect")
|
|
234
|
+
.option(
|
|
235
|
+
"--interactive-approvals",
|
|
236
|
+
"Stream mode: confirm-tier approvals become approval_request/approval stdin-stdout events instead of failing closed (chat-panel UX)",
|
|
237
|
+
)
|
|
230
238
|
.option(
|
|
231
239
|
"--permission-prompt-tool <tool>",
|
|
232
240
|
"Defer tool approvals to an MCP tool (mcp__<server>__<tool>; requires --mcp-config) instead of headless fail-closed",
|
|
@@ -235,7 +243,18 @@ export function registerAgentCommand(program) {
|
|
|
235
243
|
"--settings <file>",
|
|
236
244
|
"Merge an extra .claude/settings.json-shaped file for this run: permission rules (allow/ask/deny) + native config overrides (model, env)",
|
|
237
245
|
)
|
|
238
|
-
.action(async (task, options) => {
|
|
246
|
+
.action(async (task, options, command) => {
|
|
247
|
+
// Claude-Code parity: auto-checkpoint defaults ON inside a git repo
|
|
248
|
+
// (shadow-commit engine, zero working-tree touch); explicit
|
|
249
|
+
// --checkpoint / --no-checkpoint always wins.
|
|
250
|
+
const { resolveAutoCheckpoint } = await import(
|
|
251
|
+
"../lib/auto-checkpoint-default.js"
|
|
252
|
+
);
|
|
253
|
+
const autoCheckpoint = resolveAutoCheckpoint({
|
|
254
|
+
flagValue: options.checkpoint,
|
|
255
|
+
flagSource: command?.getOptionValueSource?.("checkpoint"),
|
|
256
|
+
cwd: process.cwd(),
|
|
257
|
+
});
|
|
239
258
|
// `--continue` / `--resume` resolve a session id so the user need not
|
|
240
259
|
// copy it. Explicit `--session <id>` always wins. `--resume <id>` targets
|
|
241
260
|
// a specific session; `--continue` or a bare `--resume` pick the most
|
|
@@ -256,7 +275,7 @@ export function registerAgentCommand(program) {
|
|
|
256
275
|
!process.stdin.isTTY;
|
|
257
276
|
if (headlessIntent) {
|
|
258
277
|
// Headless replays the JSONL store only, so resolve "most recent"
|
|
259
|
-
// from there
|
|
278
|
+
// from there 鈥?a DB-only id would resume into an empty transcript.
|
|
260
279
|
const { getLastSessionId } =
|
|
261
280
|
await import("../harness/jsonl-session-store.js");
|
|
262
281
|
options.session = getLastSessionId();
|
|
@@ -279,7 +298,7 @@ export function registerAgentCommand(program) {
|
|
|
279
298
|
|
|
280
299
|
// --fork-session: branch the resolved session into a NEW id so the
|
|
281
300
|
// ORIGINAL transcript is preserved (Claude-Code parity). One chokepoint
|
|
282
|
-
// before headless / stream / interactive dispatch
|
|
301
|
+
// before headless / stream / interactive dispatch 鈥?all read
|
|
283
302
|
// `options.session`. The copy carries the full history, so the branch
|
|
284
303
|
// replays end-to-end on a later --resume. Only meaningful when resuming;
|
|
285
304
|
// a no-op (silent) for a fresh run.
|
|
@@ -293,12 +312,12 @@ export function registerAgentCommand(program) {
|
|
|
293
312
|
);
|
|
294
313
|
if (fork.missing) {
|
|
295
314
|
process.stderr.write(
|
|
296
|
-
`--fork-session: no headless transcript for "${options.session}"
|
|
315
|
+
`--fork-session: no headless transcript for "${options.session}" 鈥?` +
|
|
297
316
|
"nothing to fork; continuing on it.\n",
|
|
298
317
|
);
|
|
299
318
|
} else if (fork.forkedFrom) {
|
|
300
319
|
process.stderr.write(
|
|
301
|
-
`Forked session ${fork.forkedFrom}
|
|
320
|
+
`Forked session ${fork.forkedFrom} 鈫?${fork.sessionId} (original preserved)\n`,
|
|
302
321
|
);
|
|
303
322
|
options.session = fork.sessionId;
|
|
304
323
|
}
|
|
@@ -328,7 +347,7 @@ export function registerAgentCommand(program) {
|
|
|
328
347
|
}
|
|
329
348
|
|
|
330
349
|
// The explicit `--model` the user typed, captured BEFORE the --settings
|
|
331
|
-
// block below may default options.model
|
|
350
|
+
// block below may default options.model 鈥?so vision input can tell an
|
|
332
351
|
// explicit model from a settings default.
|
|
333
352
|
const explicitCliModel = options.model;
|
|
334
353
|
|
|
@@ -350,10 +369,10 @@ export function registerAgentCommand(program) {
|
|
|
350
369
|
}
|
|
351
370
|
if (!options.model && sc.model) options.model = sc.model;
|
|
352
371
|
} catch {
|
|
353
|
-
// settings overrides are best-effort
|
|
372
|
+
// settings overrides are best-effort 鈥?never block the run
|
|
354
373
|
}
|
|
355
374
|
|
|
356
|
-
// Extra workspace roots (--add-dir)
|
|
375
|
+
// Extra workspace roots (--add-dir) 鈥?shared by headless + interactive.
|
|
357
376
|
const additionalDirectories = resolveAddDirs(options.addDir);
|
|
358
377
|
|
|
359
378
|
// --image <path> (repeatable): read into {mediaType, base64} for the
|
|
@@ -372,7 +391,7 @@ export function registerAgentCommand(program) {
|
|
|
372
391
|
// When an image is attached, default the run to the configured vision LLM
|
|
373
392
|
// (config.llm provider/baseUrl/apiKey + llm.visionModel | --vision-model |
|
|
374
393
|
// doubao default) so `cc agent --image foo.png` works without extra flags.
|
|
375
|
-
// Explicit --provider/--model/etc. always win; no image
|
|
394
|
+
// Explicit --provider/--model/etc. always win; no image 鈫?unchanged.
|
|
376
395
|
const visionLlm = resolveVisionLlm({
|
|
377
396
|
hasImage: images.length > 0,
|
|
378
397
|
flags: {
|
|
@@ -387,7 +406,7 @@ export function registerAgentCommand(program) {
|
|
|
387
406
|
|
|
388
407
|
// Config-default LLM (parity with cc ask/chat): a bare `cc agent` honors
|
|
389
408
|
// config.json `llm` (provider/model/baseUrl/apiKey) instead of silently
|
|
390
|
-
// assuming local ollama
|
|
409
|
+
// assuming local ollama 鈥?this is what makes the editor chat panel work
|
|
391
410
|
// against a cloud-configured setup. Explicit --provider wins outright;
|
|
392
411
|
// the vision resolution above still overrides for --image runs. Applied
|
|
393
412
|
// AFTER resolveVisionLlm so config defaults don't masquerade as explicit
|
|
@@ -401,16 +420,15 @@ export function registerAgentCommand(program) {
|
|
|
401
420
|
});
|
|
402
421
|
}
|
|
403
422
|
|
|
404
|
-
// --think / --ultrathink
|
|
405
|
-
// extended thinking; ignored by other providers). --think with no value
|
|
406
|
-
// true; --think <level> → that level; --ultrathink wins as "ultra".
|
|
423
|
+
// --think / --ultrathink 鈫?options.thinking for the agent loop (Anthropic
|
|
424
|
+
// extended thinking; ignored by other providers). --think with no value 鈫? // true; --think <level> 鈫?that level; --ultrathink wins as "ultra".
|
|
407
425
|
const thinking = options.ultrathink
|
|
408
426
|
? "ultra"
|
|
409
427
|
: options.think === true
|
|
410
428
|
? true
|
|
411
429
|
: options.think || undefined;
|
|
412
430
|
// --thinking-budget <n>: legacy-model thinking budget (no-op without
|
|
413
|
-
// --think/--ultrathink and on adaptive models). undefined
|
|
431
|
+
// --think/--ultrathink and on adaptive models). undefined 鈫?engine default.
|
|
414
432
|
const thinkingBudget = resolveThinkingBudget(options.thinkingBudget);
|
|
415
433
|
|
|
416
434
|
// --fallback-model: a chatFn that retries once on the backup model when
|
|
@@ -427,7 +445,7 @@ export function registerAgentCommand(program) {
|
|
|
427
445
|
})
|
|
428
446
|
: undefined;
|
|
429
447
|
|
|
430
|
-
//
|
|
448
|
+
// 鈹€鈹€ Streaming-input mode (--input-format stream-json) 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
431
449
|
// A persistent multi-turn conversation driven by NDJSON user events on
|
|
432
450
|
// stdin; output is always NDJSON. Routed before single-prompt handling
|
|
433
451
|
// so stdin is consumed as events, not as one prompt.
|
|
@@ -465,6 +483,7 @@ export function registerAgentCommand(program) {
|
|
|
465
483
|
ide: options.ide,
|
|
466
484
|
cwd,
|
|
467
485
|
permissionPromptTool: options.permissionPromptTool || null,
|
|
486
|
+
interactiveApprovals: options.interactiveApprovals === true,
|
|
468
487
|
settingsFile: options.settings || null,
|
|
469
488
|
outputStyle: options.outputStyle || null,
|
|
470
489
|
chatFn: fallbackChatFn,
|
|
@@ -484,7 +503,7 @@ export function registerAgentCommand(program) {
|
|
|
484
503
|
}
|
|
485
504
|
|
|
486
505
|
// Resolve the headless prompt from: --print value, positional task, or
|
|
487
|
-
// piped stdin (in that precedence). Any of them
|
|
506
|
+
// piped stdin (in that precedence). Any of them 鈫?headless mode.
|
|
488
507
|
const positional =
|
|
489
508
|
Array.isArray(task) && task.length > 0 ? task.join(" ") : "";
|
|
490
509
|
let prompt = "";
|
|
@@ -506,7 +525,7 @@ export function registerAgentCommand(program) {
|
|
|
506
525
|
|
|
507
526
|
if (prompt) {
|
|
508
527
|
// Resume requested onto a session with no headless (JSONL) transcript?
|
|
509
|
-
// Warn instead of silently starting empty
|
|
528
|
+
// Warn instead of silently starting empty 鈥?headless resume rebuilds
|
|
510
529
|
// from the JSONL store only (DB-only sessions are not replayable here).
|
|
511
530
|
const resumeRequested =
|
|
512
531
|
Boolean(options.continue) || options.resume !== undefined;
|
|
@@ -515,7 +534,7 @@ export function registerAgentCommand(program) {
|
|
|
515
534
|
await import("../harness/jsonl-session-store.js");
|
|
516
535
|
if (!sessionExists(options.session)) {
|
|
517
536
|
process.stderr.write(
|
|
518
|
-
`Note: no headless transcript for session "${options.session}"
|
|
537
|
+
`Note: no headless transcript for session "${options.session}" 鈥?` +
|
|
519
538
|
"starting fresh (headless resume reads JSONL sessions only).\n",
|
|
520
539
|
);
|
|
521
540
|
}
|
|
@@ -544,9 +563,9 @@ export function registerAgentCommand(program) {
|
|
|
544
563
|
allowedTools: parseToolList(options.allowedTools),
|
|
545
564
|
disallowedTools: parseToolList(options.disallowedTools),
|
|
546
565
|
additionalDirectories,
|
|
547
|
-
autoCheckpoint
|
|
566
|
+
autoCheckpoint,
|
|
548
567
|
maxTurns,
|
|
549
|
-
// commander maps --no-file-refs
|
|
568
|
+
// commander maps --no-file-refs 鈫?options.fileRefs === false
|
|
550
569
|
expandFileRefs: options.fileRefs !== false,
|
|
551
570
|
// --system-prompt / --append-system-prompt (literal or @file)
|
|
552
571
|
systemPrompt: resolvePromptText(options.systemPrompt, {
|
|
@@ -577,7 +596,7 @@ export function registerAgentCommand(program) {
|
|
|
577
596
|
chatFn: fallbackChatFn,
|
|
578
597
|
};
|
|
579
598
|
|
|
580
|
-
// --json-schema: structured output
|
|
599
|
+
// --json-schema: structured output 鈥?wrap the runner with capture +
|
|
581
600
|
// validate + retry (json-schema-output.js); prints only the
|
|
582
601
|
// validated JSON. Incompatible with stream-json (event stream and a
|
|
583
602
|
// single JSON contract don't mix).
|
|
@@ -616,7 +635,7 @@ export function registerAgentCommand(program) {
|
|
|
616
635
|
}
|
|
617
636
|
|
|
618
637
|
// Reached only for an interactive session, where --image has no turn to
|
|
619
|
-
// attach to
|
|
638
|
+
// attach to 鈥?warn instead of silently dropping the attachment.
|
|
620
639
|
if (images.length) {
|
|
621
640
|
process.stderr.write(
|
|
622
641
|
"--image is only used in headless mode (-p / a task / piped stdin); ignoring for the interactive session.\n",
|
|
@@ -639,7 +658,7 @@ export function registerAgentCommand(program) {
|
|
|
639
658
|
parkOnExit: options.parkOnExit, // false when --no-park-on-exit
|
|
640
659
|
bundlePath: options.bundle || null,
|
|
641
660
|
additionalDirectories,
|
|
642
|
-
autoCheckpoint
|
|
661
|
+
autoCheckpoint,
|
|
643
662
|
// --system-prompt / --append-system-prompt (literal or @file) also
|
|
644
663
|
// apply to interactive sessions, composed in startAgentRepl.
|
|
645
664
|
systemPrompt: resolvePromptText(options.systemPrompt, {
|
package/src/commands/hub.js
CHANGED
|
@@ -1732,6 +1732,65 @@ async function cmdDouyinAdbSync(options) {
|
|
|
1732
1732
|
}
|
|
1733
1733
|
}
|
|
1734
1734
|
|
|
1735
|
+
async function cmdDouyinWatchSync(options) {
|
|
1736
|
+
try {
|
|
1737
|
+
const hub = await (options._getHub || getHub)();
|
|
1738
|
+
const result = await hub.douyinWatchSync({
|
|
1739
|
+
uid: options.uid,
|
|
1740
|
+
stagingDir: options.stagingDir,
|
|
1741
|
+
displayName: options.displayName,
|
|
1742
|
+
limit: parsePositiveInt(options.limit),
|
|
1743
|
+
resolveTitles: !!options.resolveTitles,
|
|
1744
|
+
titleLimit: parsePositiveInt(options.titleLimit),
|
|
1745
|
+
});
|
|
1746
|
+
if (options.json) {
|
|
1747
|
+
printJson(result);
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (!result.ok) {
|
|
1751
|
+
logger.log(chalk.red(`✗ douyin-watch-sync failed: ${result.reason}`));
|
|
1752
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1753
|
+
if (result.reason === "DOUYIN_NO_ROOT") {
|
|
1754
|
+
logger.log(
|
|
1755
|
+
chalk.gray(
|
|
1756
|
+
" Phone needs Magisk root — Douyin release APK isn't debuggable",
|
|
1757
|
+
),
|
|
1758
|
+
);
|
|
1759
|
+
} else if (result.reason === "DOUYIN_VIDEO_RECORD_MISSING") {
|
|
1760
|
+
logger.log(
|
|
1761
|
+
chalk.gray(
|
|
1762
|
+
" Open Douyin + watch a few videos to populate video_record.db, then retry",
|
|
1763
|
+
),
|
|
1764
|
+
);
|
|
1765
|
+
} else if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1766
|
+
logger.log(
|
|
1767
|
+
chalk.gray(
|
|
1768
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1769
|
+
),
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
process.exitCode = 1;
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
const report = result.report || {};
|
|
1776
|
+
const dy = report.douyin || {};
|
|
1777
|
+
const counts = dy.eventCounts || {};
|
|
1778
|
+
logger.log(chalk.green(`✓ douyin-watch-sync succeeded`));
|
|
1779
|
+
logger.log(` uid: ${chalk.cyan(dy.uid || "?")}`);
|
|
1780
|
+
logger.log(` watched: ${counts.history || 0}`);
|
|
1781
|
+
if (options.resolveTitles) {
|
|
1782
|
+
logger.log(` titles: ${dy.titlesResolved || 0} resolved`);
|
|
1783
|
+
}
|
|
1784
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1785
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1786
|
+
if (dy.cleanupFailed) {
|
|
1787
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1788
|
+
}
|
|
1789
|
+
} catch (err) {
|
|
1790
|
+
fail(null, err, options.json);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1735
1794
|
/**
|
|
1736
1795
|
* Phase 1e — `cc hub bilibili-adb-doctor`
|
|
1737
1796
|
*
|
|
@@ -2309,6 +2368,33 @@ export function registerHubCommand(program) {
|
|
|
2309
2368
|
.option("--json", "Output JSON")
|
|
2310
2369
|
.action(cmdDouyinAdbSync);
|
|
2311
2370
|
|
|
2371
|
+
// Douyin watch-history (video_record.db, plaintext — no X-Bogus / no SQLCipher)
|
|
2372
|
+
hub
|
|
2373
|
+
.command("douyin-watch-sync")
|
|
2374
|
+
.description(
|
|
2375
|
+
"Douyin 观看历史 C 路径: pull video_record.db via ADB from the user's Android Douyin App (com.ss.android.ugc.aweme), read record_<uid> (aid + view_time_timestamp + enter_from), ingest as `history` (BROWSE) events. Plaintext — no X-Bogus signing, no SQLCipher. Needs rooted Android + Douyin App with watch history. Add --resolve-titles to enrich each event with the video's desc/author/duration via the web detail endpoint (also no signing).",
|
|
2376
|
+
)
|
|
2377
|
+
.option(
|
|
2378
|
+
"--uid <id>",
|
|
2379
|
+
"Douyin uid to disambiguate multiple accounts (default: largest record_<uid> table)",
|
|
2380
|
+
)
|
|
2381
|
+
.option("--limit <n>", "Cap watch records (default 2000)")
|
|
2382
|
+
.option(
|
|
2383
|
+
"--resolve-titles",
|
|
2384
|
+
"Resolve aweme ids → desc/author/duration via the web detail endpoint (no signing) so events show WHAT was watched",
|
|
2385
|
+
)
|
|
2386
|
+
.option(
|
|
2387
|
+
"--title-limit <n>",
|
|
2388
|
+
"Cap unique videos to title-resolve (default 60; dedup'd, ~200ms/call)",
|
|
2389
|
+
)
|
|
2390
|
+
.option("--display-name <s>", "Account displayName for the snapshot")
|
|
2391
|
+
.option(
|
|
2392
|
+
"--staging-dir <path>",
|
|
2393
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2394
|
+
)
|
|
2395
|
+
.option("--json", "Output JSON")
|
|
2396
|
+
.action(cmdDouyinWatchSync);
|
|
2397
|
+
|
|
2312
2398
|
hub
|
|
2313
2399
|
.command("rederive")
|
|
2314
2400
|
.description(
|
|
@@ -2555,6 +2641,7 @@ export const _internal = {
|
|
|
2555
2641
|
cmdBilibiliAdbSync,
|
|
2556
2642
|
cmdBilibiliAdbDoctor,
|
|
2557
2643
|
cmdDouyinAdbSync,
|
|
2644
|
+
cmdDouyinWatchSync,
|
|
2558
2645
|
cmdWeiboAdbSync,
|
|
2559
2646
|
cmdXhsAdbSync,
|
|
2560
2647
|
cmdToutiaoAdbSync,
|
|
@@ -70,6 +70,23 @@ export function isHttpTransport(transportKind) {
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Heuristic: does this error look like the server went away (vs. the tool
|
|
75
|
+
* itself failing)? Used to gate reconnect-and-retry for servers that have a
|
|
76
|
+
* registered reconnector (e.g. the IDE bridge after a window reload, which
|
|
77
|
+
* comes back on a NEW port with a NEW token).
|
|
78
|
+
*
|
|
79
|
+
* Covers: fetch-level network failures, auth rejection after a token
|
|
80
|
+
* rotation (401/403), an unknown session on a restarted server (404), and
|
|
81
|
+
* this client's own "server gone" states.
|
|
82
|
+
*/
|
|
83
|
+
export function isLikelyConnectionError(err) {
|
|
84
|
+
const msg = String((err && err.message) || err || "");
|
|
85
|
+
return /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EPIPE|socket hang up|network error|HTTP 40[134]\b|not connected|not found|not available/i.test(
|
|
86
|
+
msg,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
73
90
|
/**
|
|
74
91
|
* MCP Client — manages connections to MCP servers.
|
|
75
92
|
*/
|
|
@@ -78,6 +95,23 @@ export class MCPClient extends EventEmitter {
|
|
|
78
95
|
super();
|
|
79
96
|
this.servers = new Map(); // name → { process, state, tools, resources, config }
|
|
80
97
|
this._nextId = 1;
|
|
98
|
+
this._reconnectors = new Map(); // name → async () => config|null
|
|
99
|
+
this._reconnecting = new Map(); // name → in-flight reconnect promise
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Register a reconnector for a server: an async function that returns a
|
|
104
|
+
* FRESH connection config (or null when the server can't be found anymore).
|
|
105
|
+
* When a `callTool` on that server fails with a connection-shaped error,
|
|
106
|
+
* the client re-resolves the config, reconnects, and retries the call once.
|
|
107
|
+
*
|
|
108
|
+
* Used by the IDE bridge: a window reload / extension update restarts the
|
|
109
|
+
* editor's MCP server on a new port with a new token, so the original
|
|
110
|
+
* config is permanently dead but a lockfile re-scan finds the new one.
|
|
111
|
+
*/
|
|
112
|
+
setReconnector(name, fn) {
|
|
113
|
+
if (typeof fn === "function") this._reconnectors.set(name, fn);
|
|
114
|
+
else this._reconnectors.delete(name);
|
|
81
115
|
}
|
|
82
116
|
|
|
83
117
|
/**
|
|
@@ -286,12 +320,31 @@ export class MCPClient extends EventEmitter {
|
|
|
286
320
|
}
|
|
287
321
|
|
|
288
322
|
/**
|
|
289
|
-
* Call a tool on a specific server.
|
|
323
|
+
* Call a tool on a specific server. If the server has a registered
|
|
324
|
+
* reconnector and the call fails with a connection-shaped error (server
|
|
325
|
+
* restarted / token rotated / entry dropped), re-resolve the config,
|
|
326
|
+
* reconnect, and retry the call exactly once.
|
|
290
327
|
* @param {string} serverName - Server name
|
|
291
328
|
* @param {string} toolName - Tool name
|
|
292
329
|
* @param {object} args - Tool arguments
|
|
293
330
|
*/
|
|
294
331
|
async callTool(serverName, toolName, args = {}) {
|
|
332
|
+
try {
|
|
333
|
+
return await this._callToolOnce(serverName, toolName, args);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
if (
|
|
336
|
+
!this._reconnectors.has(serverName) ||
|
|
337
|
+
!isLikelyConnectionError(err)
|
|
338
|
+
) {
|
|
339
|
+
throw err;
|
|
340
|
+
}
|
|
341
|
+
const reconnected = await this._tryReconnect(serverName);
|
|
342
|
+
if (!reconnected) throw err;
|
|
343
|
+
return await this._callToolOnce(serverName, toolName, args);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async _callToolOnce(serverName, toolName, args) {
|
|
295
348
|
const entry = this.servers.get(serverName);
|
|
296
349
|
if (!entry) throw new Error(`Server "${serverName}" not found`);
|
|
297
350
|
if (entry.state !== ServerState.CONNECTED) {
|
|
@@ -306,6 +359,38 @@ export class MCPClient extends EventEmitter {
|
|
|
306
359
|
return result;
|
|
307
360
|
}
|
|
308
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Re-resolve a server's config via its reconnector and reconnect.
|
|
364
|
+
* Single-flight per server: concurrent failing calls share one attempt
|
|
365
|
+
* (the IDE context injector fires getSelection + getOpenEditors in
|
|
366
|
+
* parallel — a double connect would throw "already connected").
|
|
367
|
+
* Resolves true on success, false on any failure (original error wins).
|
|
368
|
+
*/
|
|
369
|
+
_tryReconnect(name) {
|
|
370
|
+
const inFlight = this._reconnecting.get(name);
|
|
371
|
+
if (inFlight) return inFlight;
|
|
372
|
+
const p = (async () => {
|
|
373
|
+
try {
|
|
374
|
+
const fresh = await this._reconnectors.get(name)();
|
|
375
|
+
if (!fresh) return false;
|
|
376
|
+
try {
|
|
377
|
+
await this.disconnect(name);
|
|
378
|
+
} catch {
|
|
379
|
+
// entry may already be gone — connect() below is what matters
|
|
380
|
+
}
|
|
381
|
+
await this.connect(name, fresh);
|
|
382
|
+
this.emit("server-reconnected", { name, url: fresh.url || null });
|
|
383
|
+
return true;
|
|
384
|
+
} catch {
|
|
385
|
+
return false;
|
|
386
|
+
} finally {
|
|
387
|
+
this._reconnecting.delete(name);
|
|
388
|
+
}
|
|
389
|
+
})();
|
|
390
|
+
this._reconnecting.set(name, p);
|
|
391
|
+
return p;
|
|
392
|
+
}
|
|
393
|
+
|
|
309
394
|
/**
|
|
310
395
|
* List resources from a specific server or all servers. Each resource is
|
|
311
396
|
* annotated with its owning `server` (mirrors `listTools`).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-checkpoint default resolution — Claude-Code parity: checkpoints are ON
|
|
3
|
+
* by default inside a git repository (the shadow-commit engine never touches
|
|
4
|
+
* the working tree or real index, so the only cost is a plumbing commit per
|
|
5
|
+
* mutating tool), OFF elsewhere (the copy-based fallback writes real files
|
|
6
|
+
* under the user home — too surprising as a silent default).
|
|
7
|
+
*
|
|
8
|
+
* Explicit flags always win: `--checkpoint` forces on anywhere (copy engine
|
|
9
|
+
* included), `--no-checkpoint` forces off.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fsDefault from "fs";
|
|
13
|
+
import pathDefault from "path";
|
|
14
|
+
|
|
15
|
+
export const _deps = { fs: fsDefault, path: pathDefault };
|
|
16
|
+
|
|
17
|
+
/** Walk up from cwd looking for a `.git` marker. */
|
|
18
|
+
export function isInsideGitRepo(cwd, deps = _deps) {
|
|
19
|
+
let dir = deps.path.resolve(cwd || ".");
|
|
20
|
+
for (;;) {
|
|
21
|
+
try {
|
|
22
|
+
if (deps.fs.existsSync(deps.path.join(dir, ".git"))) return true;
|
|
23
|
+
} catch {
|
|
24
|
+
/* keep walking */
|
|
25
|
+
}
|
|
26
|
+
const parent = deps.path.dirname(dir);
|
|
27
|
+
if (parent === dir) return false;
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {object} opts
|
|
34
|
+
* @param {boolean} [opts.flagValue] commander's options.checkpoint
|
|
35
|
+
* @param {string} [opts.flagSource] commander getOptionValueSource("checkpoint")
|
|
36
|
+
* ("cli" when --checkpoint/--no-checkpoint given)
|
|
37
|
+
* @param {string} [opts.cwd]
|
|
38
|
+
* @param {object} [opts.deps]
|
|
39
|
+
* @returns {boolean}
|
|
40
|
+
*/
|
|
41
|
+
export function resolveAutoCheckpoint({
|
|
42
|
+
flagValue,
|
|
43
|
+
flagSource,
|
|
44
|
+
cwd = process.cwd(),
|
|
45
|
+
deps = _deps,
|
|
46
|
+
} = {}) {
|
|
47
|
+
if (flagSource === "cli") return flagValue === true;
|
|
48
|
+
return isInsideGitRepo(cwd, deps);
|
|
49
|
+
}
|
|
@@ -363,7 +363,7 @@ async function initHub() {
|
|
|
363
363
|
// Phase 2a: register `douyin.pull-im-db` extension so the
|
|
364
364
|
// douyinAdbSync hub method can pull <uid>_im.db cohort from the
|
|
365
365
|
// user's Android Douyin App.
|
|
366
|
-
const { createDouyinDbExtension } =
|
|
366
|
+
const { createDouyinDbExtension, createDouyinWatchExtension } =
|
|
367
367
|
await import("@chainlesschain/personal-data-hub/adapters/social-douyin-adb");
|
|
368
368
|
// Phase 3a: register `weibo.cookies` extension for the Weibo
|
|
369
369
|
// C-path collector (m.weibo.cn cookies + 4 HTTP endpoints).
|
|
@@ -377,7 +377,7 @@ async function initHub() {
|
|
|
377
377
|
// C-path collector (www.toutiao.com cookies + 4 endpoints, 3 of
|
|
378
378
|
// which need _signature signing — CLI context falls back to -99
|
|
379
379
|
// short-circuit, desktop wiring upgrades via ToutiaoSignBridge).
|
|
380
|
-
const { createToutiaoCookiesExtension } =
|
|
380
|
+
const { createToutiaoCookiesExtension, createToutiaoAccountExtension } =
|
|
381
381
|
await import("@chainlesschain/personal-data-hub/adapters/social-toutiao-adb");
|
|
382
382
|
// Phase 6d: register `kuaishou.cookies` extension. Profile from
|
|
383
383
|
// cookie's api_ph payload (no HTTP); 3 GraphQL POST endpoints need
|
|
@@ -389,9 +389,11 @@ async function initHub() {
|
|
|
389
389
|
extensions: {
|
|
390
390
|
"bilibili.cookies": createBilibiliCookiesExtension(),
|
|
391
391
|
"douyin.pull-im-db": createDouyinDbExtension(),
|
|
392
|
+
"douyin.watch-history": createDouyinWatchExtension(),
|
|
392
393
|
"weibo.cookies": createWeiboCookiesExtension(),
|
|
393
394
|
"xhs.cookies": createXhsCookiesExtension(),
|
|
394
395
|
"toutiao.cookies": createToutiaoCookiesExtension(),
|
|
396
|
+
"toutiao.account": createToutiaoAccountExtension(),
|
|
395
397
|
"kuaishou.cookies": createKuaishouCookiesExtension(),
|
|
396
398
|
},
|
|
397
399
|
});
|
|
@@ -1037,6 +1039,46 @@ async function initHub() {
|
|
|
1037
1039
|
}
|
|
1038
1040
|
},
|
|
1039
1041
|
|
|
1042
|
+
// ─── Douyin watch-history (video_record.db, plaintext, no X-Bogus) ───
|
|
1043
|
+
// Pulls video_record.db via the douyin.watch-history extension → reads
|
|
1044
|
+
// record_<uid> (aid + view_time_timestamp + enter_from) → history events
|
|
1045
|
+
// → syncAdapter("social-douyin") snapshot mode. Distinct from
|
|
1046
|
+
// douyinAdbSync (IM db). No SQLCipher, no signing.
|
|
1047
|
+
async douyinWatchSync(opts = {}) {
|
|
1048
|
+
if (!hostAdbBridge) {
|
|
1049
|
+
return {
|
|
1050
|
+
ok: false,
|
|
1051
|
+
reason: "BRIDGE_UNAVAILABLE",
|
|
1052
|
+
message:
|
|
1053
|
+
"host-adb-bridge failed to initialize at hub boot — check `adb` is on PATH or set ADB_PATH env var",
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
let collector;
|
|
1057
|
+
try {
|
|
1058
|
+
const mod =
|
|
1059
|
+
await import("@chainlesschain/personal-data-hub/adapters/social-douyin-adb");
|
|
1060
|
+
collector = mod.default ? mod.default : mod;
|
|
1061
|
+
} catch (err) {
|
|
1062
|
+
return {
|
|
1063
|
+
ok: false,
|
|
1064
|
+
reason: "MODULE_LOAD_FAILED",
|
|
1065
|
+
message: err && err.message ? err.message : String(err),
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
const report = await collector.collectWatchHistoryAndSync(
|
|
1070
|
+
hostAdbBridge,
|
|
1071
|
+
registry,
|
|
1072
|
+
opts,
|
|
1073
|
+
);
|
|
1074
|
+
return { ok: true, report };
|
|
1075
|
+
} catch (err) {
|
|
1076
|
+
const msg = err && err.message ? err.message : String(err);
|
|
1077
|
+
const m = msg.match(/^(DOUYIN_[A-Z_]+)/);
|
|
1078
|
+
return { ok: false, reason: m ? m[1] : "SYNC_FAILED", message: msg };
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
|
|
1040
1082
|
// ─── Phase 3a — Weibo C 路径 one-shot sync ──────────────────────────
|
|
1041
1083
|
//
|
|
1042
1084
|
// Pulls m.weibo.cn cookies via the weibo.cookies extension → fetchUid
|
|
@@ -86,7 +86,10 @@ export function fileCandidates(prefix, { cwd = process.cwd(), deps } = {}) {
|
|
|
86
86
|
* slashCommands?: string[], deps? }
|
|
87
87
|
*/
|
|
88
88
|
export function makeAtCompleter(opts = {}) {
|
|
89
|
-
|
|
89
|
+
// Lazy when not pinned: `/cd` mid-session moves process.cwd() and the
|
|
90
|
+
// completer must follow (explicit opts.cwd stays static for tests).
|
|
91
|
+
const baseCwd = opts.cwd || null;
|
|
92
|
+
const getCwd = () => baseCwd || process.cwd();
|
|
90
93
|
const getIde = opts.getIdeOpenFiles || null;
|
|
91
94
|
const now = opts.deps?.now || Date.now;
|
|
92
95
|
let ideFiles = [];
|
|
@@ -105,7 +108,7 @@ export function makeAtCompleter(opts = {}) {
|
|
|
105
108
|
? files
|
|
106
109
|
.filter((f) => typeof f === "string" && f.length > 0)
|
|
107
110
|
.map((f) => {
|
|
108
|
-
const rel = path.relative(
|
|
111
|
+
const rel = path.relative(getCwd(), f);
|
|
109
112
|
// Keep workspace files relative (the natural @ref form);
|
|
110
113
|
// out-of-workspace files keep their absolute path. On
|
|
111
114
|
// Windows a cross-drive relative() returns an *absolute*
|
|
@@ -145,7 +148,7 @@ export function makeAtCompleter(opts = {}) {
|
|
|
145
148
|
refreshIde(); // async top-up for the NEXT tab; this one uses the cache
|
|
146
149
|
const norm = fwd(at.prefix).toLowerCase();
|
|
147
150
|
const fromIde = ideFiles.filter((f) => f.toLowerCase().startsWith(norm));
|
|
148
|
-
const fromFs = fileCandidates(at.prefix, { cwd, deps: opts.deps });
|
|
151
|
+
const fromFs = fileCandidates(at.prefix, { cwd: getCwd(), deps: opts.deps });
|
|
149
152
|
const merged = [...new Set([...fromIde, ...fromFs])].slice(
|
|
150
153
|
0,
|
|
151
154
|
MAX_CANDIDATES,
|