chainlesschain 0.162.30 → 0.162.31
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-CsNttUU7.js → AIOps-BqWP6FKu.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-lgohjckQ.js → ActionButton-CXwMgOvX.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-ccV3LAca.js → Analytics-DAebZ4IY.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-CYsqYoME.js +9 -0
- package/src/assets/web-panel/assets/{Audit-B1gFM5U9.js → Audit-BbTtX1Nf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BeWE3ERo.js → Backup-DgqY2Eb-.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CDkPsNG2.js → BaseInput-Cq2ZuSoO.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ztb9ia6e.js → Chat-D2kqpUyO.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-C-svYkrC.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BcfRBlIY.js → Checkbox-_9swHpyc.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DOs99xkr.js → Codegen-Cr9YbCPl.js} +1 -1
- package/src/assets/web-panel/assets/{Col-D1X6tYlj.js → Col--wdpCMxx.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DTksIWtz.js → Community-DuFcVnLu.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DIJtAYBO.js → Compact-1yzYeT04.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BBf7LF_k.js → Compliance-Dq3aU9Df.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-UBPXQ40s.js → Cowork-CrWcnIg8.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CkRm1jPB.js → Cron-Bh6fKZ0h.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-qALlTl7e.js → Crosschain-8ofPaWVW.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CqyqVS6E.js → DID-D3EiYm3w.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-BFjEdFne.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-Cb5UzbSZ.js → Dropdown-pYVPcP6O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CarBq8Fk.js → EmailListRenderer-zBPodwJ1.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CSiGXaZz.js → FamilyGuardDashboard-CyQTW6PW.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DUxhVoBN.js → Federation-Ctaq3zYq.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BoMQpkhx.js → FormItemContext-CWYJCLq1.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DTVqC_CX.js → GenericCardRenderer-B1g6t9R9.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C_XuPtK5.js → Git-DH-v8iwd.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BZyqlqz-.js → Governance-jZxXvOs5.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DdZVUimI.js → Inference-D07LRghn.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-IzZ-jnCn.js → KnowledgeGraph-DnGtRZhx.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-koTK6eNc.js → Logs-D2pM9C4W.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-6zpJ1L8n.js → Marketplace-UyIO7C7r.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Ywc4IVks.js → McpTools-Bf1gvZPf.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-C_zB9dUa.js → Memory-C1bWj4RN.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Nc05r24L.js → MobileBridge-C_Ot1H_a.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-BJGxL526.js → MobileProjects-zr-PpsT_.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Im7SIcz1.js → Mtc-CnzFUz5J.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BFFzvzMD.js → MtcAudit-CAAh99wz.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CcNEbycq.js → Multisig-D6IAg6HE.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CDH6OTXN.js → NLProgramming-BFMarxb0.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dqg3QXcU.js → Notes-BRp9ro3t.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CDVmK1eU.js → NotificationSettings-C0Au3Cxb.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-ISp6btRY.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DJb9bRQS.js → Organization-DYoxLBRX.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CK7Q5dje.js → Overflow-rO8JJWGJ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CJIyYfwc.js → P2P-DJleeXIK.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-uqRULcuw.js → PdhVaultBrowser-DM5qghFp.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Crvwt6bq.js → Permissions-D5v4Beya.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DcN5OWzg.js → PersonalDataHub-c2ZTX0Pv.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-DfWJvvJW.js → Pipeline-Crrkyhpz.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DepD0S3v.js → Privacy-DZVyrJKa.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B7OKhH27.js → ProjectInit-DKg7J0gz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BJ4ueRFv.js → ProjectSettings-3ndmTvVH.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Dl_hPdhU.js → Projects-ll5wnj2L.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Dl0FT1S3.js → Providers-BeqBVMhB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-V2hYLhfp.js → QuickAsk-DKAAxzuA.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-8Kaiodgv.js → Recommend-Byu7IGei.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-CsxB3JGg.js → Reputation-BKhWAmCu.js} +1 -1
- package/src/assets/web-panel/assets/{Row-6-x7tEYq.js → Row-BFtn11O6.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Buv6f5tw.js → RssFeed-D5a0PT0k.js} +2 -2
- package/src/assets/web-panel/assets/{Search-ABrDz84n.js → Search-DAkuaZNe.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DqOJmz18.js → Security-C79Ml2Ms.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Cq4Tda3q.js → Services-BBk_jH6-.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-n74QlyYq.js → Skeleton-Cy0VvL0M.js} +1 -1
- package/src/assets/web-panel/assets/Skills-OQNky3uI.js +1 -0
- package/src/assets/web-panel/assets/{Sla-hwRgJ99Z.js → Sla-CbX1f8xN.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-B6Bs6_-8.js → SpeechSettings-BIkoUjws.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CTp2dZ0z.js → SyncSettings-DG6Swk7G.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-D70Lis6S.js → Tasks-C9R8sgyi.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Cags0ssw.js → Templates-AaJPeCIz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BxCMzzGt.js → Tenant-jVFRofww.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-v05SDqHd.js → Terminal-DHBMzfK6.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BLUDHbBL.js → TimelineRenderer-9RFfOHSI.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D-xKLJYv.js → Tokens-ZTfwuABF.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B47tVIbH.js → Trigger-Xo7uZNQs.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmRU9kfs.js → Trust-C0cTPYvn.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DzgSGs-c.js → UkeySign-DmMKio71.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C6qu58up.js → VideoEditing-DP7B-oGT.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dh8ZWx8f.js → Wallet-B1kZDARo.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DFHOVuAY.js → WebAuthn-Bo5kBx27.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-B_fyQ3Y_.js → WorkflowEditor-DGI9SNHH.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BR-WxnCQ.js → chat-y97W1CIG.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C-6RysQe.js → colors-DtTNo0sH.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-B_9_SCKN.js → compact-item-D0q0exuS.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D6rklIbE.js → createContext-D7pLFs2I.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BDK34w0I.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BrotgSvd.js → hasIn-CXjG5B2j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkpDFJRn.js → index-1dwtkcJv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfqUsPl2.js → index-4mWZhCzz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaLhL3Tj.js → index-6np5ESBM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DigjvHuo.js → index-8jxbZupG.js} +1 -1
- package/src/assets/web-panel/assets/{index-MCmNzIC7.js → index-B3y_4OdG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWmJukRW.js → index-B4dPdrvC.js} +1 -1
- package/src/assets/web-panel/assets/index-B6SaRuCI.js +1 -0
- package/src/assets/web-panel/assets/index-B9ekWb3I.js +1 -0
- package/src/assets/web-panel/assets/{index-GzuCTHVZ.js → index-BJUf19Wd.js} +3 -3
- package/src/assets/web-panel/assets/{index-PzM_GlKb.js → index-BO644Q4S.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTQkYbir.js → index-BPXhU-jp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsDNNDBN.js → index-BU944DeT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bwkg_EJk.js → index-B_hjkMtX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMnomft7.js → index-BdhEYW2a.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJ70GAW2.js → index-BgmvrPJH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTh0fWI4.js → index-BgyrM0UN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAfRNHna.js → index-BnLrbXDA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCWzUY8K.js → index-BqVjUN8b.js} +1 -1
- package/src/assets/web-panel/assets/{index-kkjq_hwC.js → index-BzCPx1cq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK8YwdNd.js → index-CFsPe2N7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6KqyxG1.js → index-CKrbutAQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bv9BrnD2.js → index-CSdhC7Qo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJgp_QFo.js → index-Cbqu804A.js} +1 -1
- package/src/assets/web-panel/assets/{index-rWiOF7Iu.js → index-CkGFqlYX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrGp-4E2.js → index-Ct6xtKkc.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn5ghmbB.js → index-DY6KLlgG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbRl_gIW.js → index-D_4WcI1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTpElYJs.js → index-DjCawXk1.js} +1 -1
- package/src/assets/web-panel/assets/{index-MBOwmoOi.js → index-Dr45Nm9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2yXH6vy.js → index-EaIfumgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTCUOKu9.js → index-POaFzYGS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIiCIC2j.js → index-TrBGgrwG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdDmzoPE.js → index-YWOEx3rP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn21XmDt.js → index-_3wPBMKt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsWVDOd2.js → index-aarO4HT9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTpxOc5s.js → index-bVJvqDAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-B85rQNYG.js → index-gFLQe31v.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZehgEQYa.js → index-kvV0f4tV.js} +1 -1
- package/src/assets/web-panel/assets/{index-E_5VXq8H.js → index-qoB3whR9.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C2v_L5na.js → initDefaultProps-BnXISaAa.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DNDqGbfr.js → motion-ChY7C0zJ.js} +1 -1
- package/src/assets/web-panel/assets/{move-xvpQ_6hJ.js → move-ByFZMFM5.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Cb0FsfrO.js → omit-BYeliY1H.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BxhYpnum.js → pickAttrs-B9dcAKnu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B3soaW4h.js → placementArrow-D3F_txz7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B-eRSLvd.js → responsiveObserve-ClkwY7wS.js} +1 -1
- package/src/assets/web-panel/assets/{slide--cM2ZOx-.js → slide-BNgy2Eea.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DjBhfi8Q.js → statusUtils-Bv3heMCD.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C30mMh8o.js → styleChecker-DVdlHbQm.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-f7y2Qlzs.js → useFlexGapSupport-alrRY5BK.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-iTCXoLoZ.js → useFs-CcVh0-Vu.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BH0RXmVF.js → usePersonalDataHub-CkkHPhyq.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DQtmeDXM.js → vnode-DWi0X9WN.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-vw50zkLZ.js → zoom-DCbqxxLH.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +306 -1
- package/src/commands/ask.js +35 -1
- package/src/commands/checkpoint.js +239 -0
- package/src/commands/cost.js +114 -0
- package/src/commands/session.js +22 -2
- package/src/index.js +4 -0
- package/src/lib/file-checkpoint.js +300 -0
- package/src/lib/llm-pricing.js +227 -0
- package/src/lib/personal-data-hub-wiring.js +30 -0
- package/src/lib/recent-session.js +72 -0
- package/src/lib/session-picker.js +68 -0
- package/src/repl/agent-repl.js +58 -2
- package/src/repl/chat-repl.js +16 -1
- package/src/runtime/agent-core.js +68 -31
- package/src/runtime/fallback-model.js +109 -0
- package/src/runtime/file-ref-expander.js +258 -0
- package/src/runtime/headless-runner.js +576 -0
- package/src/runtime/headless-stream.js +302 -0
- package/src/runtime/policies/agent-policy.js +6 -0
- package/src/runtime/quiet-stdout.js +35 -0
- package/src/runtime/system-prompt.js +60 -0
- package/src/assets/web-panel/assets/AppLayout-B0hl5cPk.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Dlw_6n3M.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-XlMpT7K_.js +0 -3
- package/src/assets/web-panel/assets/OrderTableRenderer-Bg0bkfjR.js +0 -1
- package/src/assets/web-panel/assets/Skills-CC0iozL5.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BiN5HELJ.js +0 -1
- package/src/assets/web-panel/assets/index-BhxiT2LJ.js +0 -1
- package/src/assets/web-panel/assets/index-DBNSZ2oz.js +0 -1
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc checkpoint — manual file-state snapshot / rewind (Claude-Code rewind parity).
|
|
3
|
+
*
|
|
4
|
+
* cc checkpoint create <paths...> [--label <l>] snapshot files/dirs
|
|
5
|
+
* cc checkpoint list list checkpoints
|
|
6
|
+
* cc checkpoint show <id> [--diff] manifest, or diff vs current
|
|
7
|
+
* cc checkpoint restore <id> [--dry-run] [--force] roll files back
|
|
8
|
+
* cc checkpoint delete <id> [--force] remove a checkpoint
|
|
9
|
+
*
|
|
10
|
+
* Restore takes an automatic safety snapshot of the current contents first, so
|
|
11
|
+
* a rewind is itself reversible. Distinct from `cc workflow checkpoint`
|
|
12
|
+
* (workflow execution state, not files).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
import { logger } from "../lib/logger.js";
|
|
17
|
+
|
|
18
|
+
export function registerCheckpointCommand(program) {
|
|
19
|
+
const cp = program
|
|
20
|
+
.command("checkpoint")
|
|
21
|
+
.description("Snapshot / rewind file state (manual checkpoints)");
|
|
22
|
+
|
|
23
|
+
cp.command("create <paths...>")
|
|
24
|
+
.description("Snapshot the given files/directories")
|
|
25
|
+
.option("--label <label>", "Human label for this checkpoint")
|
|
26
|
+
.option("--json", "Output as JSON")
|
|
27
|
+
.action(async (paths, options) => {
|
|
28
|
+
try {
|
|
29
|
+
const { createCheckpoint } = await import("../lib/file-checkpoint.js");
|
|
30
|
+
const m = createCheckpoint(paths, { label: options.label });
|
|
31
|
+
if (options.json) {
|
|
32
|
+
console.log(JSON.stringify(m, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
logger.log(
|
|
36
|
+
chalk.green(`✓ checkpoint ${chalk.bold(m.id)}`) +
|
|
37
|
+
(m.label ? chalk.gray(` "${m.label}"`) : ""),
|
|
38
|
+
);
|
|
39
|
+
logger.log(chalk.gray(` ${m.fileCount} file(s) snapshotted`));
|
|
40
|
+
} catch (err) {
|
|
41
|
+
logger.error(chalk.red(`checkpoint create failed: ${err.message}`));
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
cp.command("list")
|
|
47
|
+
.alias("ls")
|
|
48
|
+
.description("List checkpoints (newest first)")
|
|
49
|
+
.option("--json", "Output as JSON")
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
try {
|
|
52
|
+
const { listCheckpoints } = await import("../lib/file-checkpoint.js");
|
|
53
|
+
const all = listCheckpoints();
|
|
54
|
+
if (options.json) {
|
|
55
|
+
console.log(JSON.stringify(all, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (all.length === 0) {
|
|
59
|
+
logger.log(
|
|
60
|
+
chalk.gray(
|
|
61
|
+
"No checkpoints. Create one: cc checkpoint create <paths...>",
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
for (const c of all) {
|
|
67
|
+
logger.log(
|
|
68
|
+
`${chalk.cyan(c.id.padEnd(22))} ${chalk.gray(c.createdAt)} ` +
|
|
69
|
+
`${String(c.fileCount).padStart(4)} files` +
|
|
70
|
+
(c.label ? chalk.gray(` "${c.label}"`) : ""),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
} catch (err) {
|
|
74
|
+
logger.error(chalk.red(`checkpoint list failed: ${err.message}`));
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
cp.command("show <id>")
|
|
80
|
+
.description("Show a checkpoint's files, or its diff vs current state")
|
|
81
|
+
.option("--diff", "Compare snapshot against current on-disk files")
|
|
82
|
+
.option("--json", "Output as JSON")
|
|
83
|
+
.action(async (id, options) => {
|
|
84
|
+
try {
|
|
85
|
+
const { getCheckpoint, diffCheckpoint } =
|
|
86
|
+
await import("../lib/file-checkpoint.js");
|
|
87
|
+
if (options.diff) {
|
|
88
|
+
const d = diffCheckpoint(id);
|
|
89
|
+
if (options.json) {
|
|
90
|
+
console.log(JSON.stringify(d, null, 2));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
logger.log(chalk.bold(`Diff vs current — ${id}`));
|
|
94
|
+
logger.log(` ${chalk.yellow("modified")}: ${d.modified.length}`);
|
|
95
|
+
d.modified.forEach((f) => logger.log(chalk.yellow(` M ${f}`)));
|
|
96
|
+
logger.log(` ${chalk.red("deleted")}: ${d.deleted.length}`);
|
|
97
|
+
d.deleted.forEach((f) => logger.log(chalk.red(` D ${f}`)));
|
|
98
|
+
logger.log(chalk.gray(` unchanged: ${d.unchanged.length}`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const m = getCheckpoint(id);
|
|
102
|
+
if (!m) {
|
|
103
|
+
logger.error(chalk.red(`no such checkpoint: ${id}`));
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (options.json) {
|
|
108
|
+
console.log(JSON.stringify(m, null, 2));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
logger.log(chalk.bold(`Checkpoint ${m.id}`));
|
|
112
|
+
if (m.label) logger.log(chalk.gray(` label: ${m.label}`));
|
|
113
|
+
logger.log(
|
|
114
|
+
chalk.gray(` created: ${m.createdAt} files: ${m.fileCount}`),
|
|
115
|
+
);
|
|
116
|
+
for (const f of m.files) {
|
|
117
|
+
logger.log(` ${chalk.gray(String(f.bytes).padStart(8))} ${f.rel}`);
|
|
118
|
+
}
|
|
119
|
+
} catch (err) {
|
|
120
|
+
logger.error(chalk.red(`checkpoint show failed: ${err.message}`));
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
cp.command("restore <id>")
|
|
126
|
+
.description(
|
|
127
|
+
"Restore files from a checkpoint (auto-snapshots current state first)",
|
|
128
|
+
)
|
|
129
|
+
.option("--dry-run", "Show what would change without writing")
|
|
130
|
+
.option("--force", "Restore without the interactive confirm prompt")
|
|
131
|
+
.option("--json", "Output as JSON")
|
|
132
|
+
.action(async (id, options) => {
|
|
133
|
+
try {
|
|
134
|
+
const { restoreCheckpoint, diffCheckpoint } =
|
|
135
|
+
await import("../lib/file-checkpoint.js");
|
|
136
|
+
|
|
137
|
+
if (options.dryRun) {
|
|
138
|
+
const r = restoreCheckpoint(id, { dryRun: true });
|
|
139
|
+
if (options.json) {
|
|
140
|
+
console.log(JSON.stringify(r, null, 2));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
logger.log(chalk.bold(`Dry-run restore — ${id}`));
|
|
144
|
+
logger.log(` would restore: ${r.restored.length} file(s)`);
|
|
145
|
+
r.restored.forEach((f) => logger.log(chalk.yellow(` ~ ${f}`)));
|
|
146
|
+
logger.log(chalk.gray(` already matching: ${r.unchanged.length}`));
|
|
147
|
+
if (r.missingBlob.length) {
|
|
148
|
+
logger.log(
|
|
149
|
+
chalk.red(` missing blobs: ${r.missingBlob.join(", ")}`),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Destructive: overwrites current files. Require --force when not a TTY;
|
|
156
|
+
// prompt when interactive.
|
|
157
|
+
if (!options.force) {
|
|
158
|
+
const d = diffCheckpoint(id);
|
|
159
|
+
const willChange = d.modified.length + d.deleted.length;
|
|
160
|
+
if (process.stdin.isTTY) {
|
|
161
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
162
|
+
const ok = await confirm({
|
|
163
|
+
message: `Restore ${id}? ${willChange} file(s) will be overwritten (a safety checkpoint is taken first).`,
|
|
164
|
+
default: false,
|
|
165
|
+
}).catch(() => false);
|
|
166
|
+
if (!ok) {
|
|
167
|
+
logger.log(chalk.gray("Aborted."));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
logger.error(
|
|
172
|
+
chalk.red(
|
|
173
|
+
`Refusing to restore without --force (non-interactive). ${willChange} file(s) would change. Re-run with --dry-run to preview or --force to proceed.`,
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const r = restoreCheckpoint(id);
|
|
182
|
+
if (options.json) {
|
|
183
|
+
console.log(JSON.stringify(r, null, 2));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
logger.log(
|
|
187
|
+
chalk.green(`✓ restored ${r.restored.length} file(s) from ${id}`),
|
|
188
|
+
);
|
|
189
|
+
r.restored.forEach((f) => logger.log(chalk.gray(` ~ ${f}`)));
|
|
190
|
+
if (r.safetyId) {
|
|
191
|
+
logger.log(
|
|
192
|
+
chalk.gray(
|
|
193
|
+
` safety checkpoint of prior state: ${r.safetyId} (undo with: cc checkpoint restore ${r.safetyId})`,
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (r.missingBlob.length) {
|
|
198
|
+
logger.log(
|
|
199
|
+
chalk.red(` missing blobs (skipped): ${r.missingBlob.join(", ")}`),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
logger.error(chalk.red(`checkpoint restore failed: ${err.message}`));
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
cp.command("delete <id>")
|
|
209
|
+
.alias("rm")
|
|
210
|
+
.description("Delete a checkpoint")
|
|
211
|
+
.option("--force", "Skip confirmation")
|
|
212
|
+
.action(async (id, options) => {
|
|
213
|
+
try {
|
|
214
|
+
const { deleteCheckpoint, getCheckpoint } =
|
|
215
|
+
await import("../lib/file-checkpoint.js");
|
|
216
|
+
if (!getCheckpoint(id)) {
|
|
217
|
+
logger.error(chalk.red(`no such checkpoint: ${id}`));
|
|
218
|
+
process.exitCode = 1;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (!options.force && process.stdin.isTTY) {
|
|
222
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
223
|
+
const ok = await confirm({
|
|
224
|
+
message: `Delete checkpoint ${id}?`,
|
|
225
|
+
default: false,
|
|
226
|
+
}).catch(() => false);
|
|
227
|
+
if (!ok) {
|
|
228
|
+
logger.log(chalk.gray("Aborted."));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
deleteCheckpoint(id);
|
|
233
|
+
logger.log(chalk.green(`✓ deleted ${id}`));
|
|
234
|
+
} catch (err) {
|
|
235
|
+
logger.error(chalk.red(`checkpoint delete failed: ${err.message}`));
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc cost [sessionId] — estimated $ spend from recorded token usage.
|
|
3
|
+
*
|
|
4
|
+
* Builds on `cc session usage` (token aggregation) by layering the
|
|
5
|
+
* llm-pricing rate table on top. Reads the same JSONL token_usage events,
|
|
6
|
+
* so no new data is collected — this is purely a reporting view.
|
|
7
|
+
*
|
|
8
|
+
* cc cost # global rollup across all sessions
|
|
9
|
+
* cc cost <sessionId> # one session
|
|
10
|
+
* cc cost --json # machine-readable
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import { logger } from "../lib/logger.js";
|
|
15
|
+
|
|
16
|
+
function fmtUsd(n) {
|
|
17
|
+
const v = Number(n) || 0;
|
|
18
|
+
// Sub-cent costs are common with cheap models — show enough precision.
|
|
19
|
+
if (v === 0) return "$0.00";
|
|
20
|
+
if (v < 0.01) return `$${v.toFixed(6)}`;
|
|
21
|
+
return `$${v.toFixed(4)}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function registerCostCommand(program) {
|
|
25
|
+
program
|
|
26
|
+
.command("cost")
|
|
27
|
+
.description(
|
|
28
|
+
"Estimated $ cost from recorded token usage (per-session or global)",
|
|
29
|
+
)
|
|
30
|
+
.argument("[id]", "Session ID (omit for global rollup)")
|
|
31
|
+
.option("--json", "Output as JSON")
|
|
32
|
+
.option("--limit <n>", "Max sessions for global rollup", "1000")
|
|
33
|
+
.action(async (id, options) => {
|
|
34
|
+
try {
|
|
35
|
+
const { sessionUsage, allSessionsUsage } =
|
|
36
|
+
await import("../lib/session-usage.js");
|
|
37
|
+
const { priceRollup, mergePricing } =
|
|
38
|
+
await import("../lib/llm-pricing.js");
|
|
39
|
+
const { loadConfig } = await import("../lib/config-manager.js");
|
|
40
|
+
|
|
41
|
+
// User price overrides live under config.llm.pricing — no need to edit
|
|
42
|
+
// source to correct/add a model rate.
|
|
43
|
+
const config = loadConfig();
|
|
44
|
+
const overrides = config?.llm?.pricing;
|
|
45
|
+
const table = mergePricing(overrides);
|
|
46
|
+
|
|
47
|
+
const raw = id
|
|
48
|
+
? sessionUsage(id)
|
|
49
|
+
: allSessionsUsage({ limit: parseInt(options.limit, 10) || 1000 });
|
|
50
|
+
const result = priceRollup(raw, { table });
|
|
51
|
+
|
|
52
|
+
if (options.json) {
|
|
53
|
+
console.log(JSON.stringify(result, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const header = id
|
|
58
|
+
? `Cost — session ${chalk.gray(id.slice(0, 16))}`
|
|
59
|
+
: "Cost — global";
|
|
60
|
+
logger.log(chalk.bold(header));
|
|
61
|
+
logger.log(
|
|
62
|
+
` total: ${chalk.green(fmtUsd(result.cost.totalCost))} USD ` +
|
|
63
|
+
`(${result.total.totalTokens.toLocaleString()} tokens, ${result.total.calls} calls)`,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (result.byModel.length === 0) {
|
|
67
|
+
logger.log(chalk.gray(" (no token_usage events recorded)"));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const row of result.byModel) {
|
|
72
|
+
const provider = (row.provider || "?").padEnd(10);
|
|
73
|
+
const model = (row.model || "?").padEnd(24);
|
|
74
|
+
const tokens = `in=${row.inputTokens} out=${row.outputTokens}`;
|
|
75
|
+
if (row.free) {
|
|
76
|
+
logger.log(
|
|
77
|
+
` ${chalk.gray(provider)} ${chalk.white(model)} ${chalk.gray("free (local)")} ${chalk.gray(tokens)}`,
|
|
78
|
+
);
|
|
79
|
+
} else if (row.matched) {
|
|
80
|
+
logger.log(
|
|
81
|
+
` ${chalk.gray(provider)} ${chalk.white(model)} ${chalk.green(fmtUsd(row.cost).padStart(12))} ${chalk.gray(tokens)}`,
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
logger.log(
|
|
85
|
+
` ${chalk.gray(provider)} ${chalk.white(model)} ${chalk.yellow("unpriced".padStart(12))} ${chalk.gray(tokens)}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (result.unpriced.length > 0) {
|
|
91
|
+
logger.log(
|
|
92
|
+
chalk.yellow(
|
|
93
|
+
` note: ${result.unpriced.length} model(s) have no rate — tokens excluded from total. Add rates via config: llm.pricing.`,
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (overrides && typeof overrides === "object") {
|
|
98
|
+
logger.log(
|
|
99
|
+
chalk.gray(
|
|
100
|
+
` (price overrides active from config.llm.pricing: ${Object.keys(overrides).join(", ")})`,
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
logger.log(
|
|
105
|
+
chalk.gray(
|
|
106
|
+
" prices are estimates of public list rates (USD/1M tokens).",
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
logger.error(chalk.red(`cost failed: ${err.message}`));
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
package/src/commands/session.js
CHANGED
|
@@ -209,8 +209,13 @@ export function registerSessionCommand(program) {
|
|
|
209
209
|
// session resume
|
|
210
210
|
session
|
|
211
211
|
.command("resume")
|
|
212
|
-
.description(
|
|
213
|
-
|
|
212
|
+
.description(
|
|
213
|
+
"Resume a session in chat mode (id optional — interactive picker, or most recent when piped)",
|
|
214
|
+
)
|
|
215
|
+
.argument(
|
|
216
|
+
"[id]",
|
|
217
|
+
"Session ID (or prefix); omit to pick / resume the most recent",
|
|
218
|
+
)
|
|
214
219
|
.option("--model <model>", "Model name")
|
|
215
220
|
.option("--provider <provider>", "LLM provider")
|
|
216
221
|
.action(async (id, options) => {
|
|
@@ -218,6 +223,21 @@ export function registerSessionCommand(program) {
|
|
|
218
223
|
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
219
224
|
let sess = null;
|
|
220
225
|
|
|
226
|
+
// No id → shared interactive picker (TTY + >1) or most-recent fallback
|
|
227
|
+
// (single / non-TTY / Ctrl-C). Same helper as `cc agent --resume`.
|
|
228
|
+
if (!id) {
|
|
229
|
+
const { pickRecentSession } =
|
|
230
|
+
await import("../lib/session-picker.js");
|
|
231
|
+
const picked = await pickRecentSession(ctx);
|
|
232
|
+
if (!picked.id) {
|
|
233
|
+
logger.error(
|
|
234
|
+
"No saved sessions to resume. Use 'chat' or 'agent' to create one.",
|
|
235
|
+
);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
id = picked.id;
|
|
239
|
+
}
|
|
240
|
+
|
|
221
241
|
// Try JSONL first
|
|
222
242
|
if (feature("JSONL_SESSION") && sessionExists(id)) {
|
|
223
243
|
const events = readEvents(id);
|
package/src/index.js
CHANGED
|
@@ -56,6 +56,8 @@ import { registerMemoryCommand } from "./commands/memory.js";
|
|
|
56
56
|
import { registerPermMemCommand } from "./commands/permmem.js";
|
|
57
57
|
import { registerRCacheCommand } from "./commands/rcache.js";
|
|
58
58
|
import { registerSessionCommand } from "./commands/session.js";
|
|
59
|
+
import { registerCostCommand } from "./commands/cost.js";
|
|
60
|
+
import { registerCheckpointCommand } from "./commands/checkpoint.js";
|
|
59
61
|
import { registerConsolCommand } from "./commands/consol.js";
|
|
60
62
|
import { registerImportCommand } from "./commands/import.js";
|
|
61
63
|
import { registerExportCommand } from "./commands/export.js";
|
|
@@ -448,6 +450,8 @@ export function createProgram(opts = {}) {
|
|
|
448
450
|
registerPermMemCommand(program);
|
|
449
451
|
registerRCacheCommand(program);
|
|
450
452
|
registerSessionCommand(program);
|
|
453
|
+
registerCostCommand(program);
|
|
454
|
+
registerCheckpointCommand(program);
|
|
451
455
|
registerConsolCommand(program);
|
|
452
456
|
|
|
453
457
|
// Phase 2: Knowledge & content management
|