reasonix 0.32.0 → 0.33.1

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.
Files changed (118) hide show
  1. package/dist/cli/chat-Q5ZCVIOO.js +39 -0
  2. package/dist/cli/chunk-2AWTGJ2C.js +110 -0
  3. package/dist/cli/chunk-2AWTGJ2C.js.map +1 -0
  4. package/dist/cli/chunk-3Q3C4W66.js +30 -0
  5. package/dist/cli/chunk-3Q3C4W66.js.map +1 -0
  6. package/dist/cli/chunk-4DCHFFEY.js +149 -0
  7. package/dist/cli/chunk-4DCHFFEY.js.map +1 -0
  8. package/dist/cli/chunk-5X7LZJDE.js +36 -0
  9. package/dist/cli/chunk-5X7LZJDE.js.map +1 -0
  10. package/dist/cli/chunk-63KAV5DX.js +106 -0
  11. package/dist/cli/chunk-63KAV5DX.js.map +1 -0
  12. package/dist/cli/chunk-6TMHAK5D.js +576 -0
  13. package/dist/cli/chunk-6TMHAK5D.js.map +1 -0
  14. package/dist/cli/chunk-APPB3ZPQ.js +43 -0
  15. package/dist/cli/chunk-APPB3ZPQ.js.map +1 -0
  16. package/dist/cli/chunk-BQNUJJN7.js +42 -0
  17. package/dist/cli/chunk-BQNUJJN7.js.map +1 -0
  18. package/dist/cli/chunk-CPOV2O73.js +39 -0
  19. package/dist/cli/chunk-CPOV2O73.js.map +1 -0
  20. package/dist/cli/chunk-D5DKXIP5.js +368 -0
  21. package/dist/cli/chunk-D5DKXIP5.js.map +1 -0
  22. package/dist/cli/chunk-DFP4YSVM.js +247 -0
  23. package/dist/cli/chunk-DFP4YSVM.js.map +1 -0
  24. package/dist/cli/chunk-DULSP7JH.js +410 -0
  25. package/dist/cli/chunk-DULSP7JH.js.map +1 -0
  26. package/dist/cli/chunk-FM57FNPJ.js +46 -0
  27. package/dist/cli/chunk-FM57FNPJ.js.map +1 -0
  28. package/dist/cli/chunk-FWGEHRB7.js +54 -0
  29. package/dist/cli/chunk-FWGEHRB7.js.map +1 -0
  30. package/dist/cli/chunk-FXGQ5NHE.js +513 -0
  31. package/dist/cli/chunk-FXGQ5NHE.js.map +1 -0
  32. package/dist/cli/chunk-G3XNWSFN.js +53 -0
  33. package/dist/cli/chunk-G3XNWSFN.js.map +1 -0
  34. package/dist/cli/chunk-I6YIAK6C.js +757 -0
  35. package/dist/cli/chunk-I6YIAK6C.js.map +1 -0
  36. package/dist/cli/chunk-J5VLP23S.js +94 -0
  37. package/dist/cli/chunk-J5VLP23S.js.map +1 -0
  38. package/dist/cli/chunk-KMWKGPFZ.js +303 -0
  39. package/dist/cli/chunk-KMWKGPFZ.js.map +1 -0
  40. package/dist/cli/chunk-MDHVWCJ4.js +14965 -0
  41. package/dist/cli/chunk-MDHVWCJ4.js.map +1 -0
  42. package/dist/cli/chunk-MHDNZXJJ.js +48 -0
  43. package/dist/cli/chunk-MHDNZXJJ.js.map +1 -0
  44. package/dist/cli/chunk-ORM6PK57.js +140 -0
  45. package/dist/cli/chunk-ORM6PK57.js.map +1 -0
  46. package/dist/cli/chunk-Q6YFXW7H.js +4986 -0
  47. package/dist/cli/chunk-Q6YFXW7H.js.map +1 -0
  48. package/dist/cli/chunk-QGE6AF76.js +1467 -0
  49. package/dist/cli/chunk-QGE6AF76.js.map +1 -0
  50. package/dist/cli/chunk-RFX7TYVV.js +28 -0
  51. package/dist/cli/chunk-RFX7TYVV.js.map +1 -0
  52. package/dist/cli/chunk-RZILUXUC.js +940 -0
  53. package/dist/cli/chunk-RZILUXUC.js.map +1 -0
  54. package/dist/cli/chunk-SDE5U32Z.js +535 -0
  55. package/dist/cli/chunk-SDE5U32Z.js.map +1 -0
  56. package/dist/cli/chunk-SOZE7V7V.js +340 -0
  57. package/dist/cli/chunk-SOZE7V7V.js.map +1 -0
  58. package/dist/cli/chunk-U3V2ZQ5J.js +479 -0
  59. package/dist/cli/chunk-U3V2ZQ5J.js.map +1 -0
  60. package/dist/cli/chunk-W4LDFAZ6.js +1544 -0
  61. package/dist/cli/chunk-W4LDFAZ6.js.map +1 -0
  62. package/dist/cli/chunk-WBDE4IRI.js +208 -0
  63. package/dist/cli/chunk-WBDE4IRI.js.map +1 -0
  64. package/dist/cli/chunk-XHQIK7B6.js +189 -0
  65. package/dist/cli/chunk-XHQIK7B6.js.map +1 -0
  66. package/dist/cli/chunk-XJLZ4HKU.js +307 -0
  67. package/dist/cli/chunk-XJLZ4HKU.js.map +1 -0
  68. package/dist/cli/chunk-ZPTSJGX5.js +88 -0
  69. package/dist/cli/chunk-ZPTSJGX5.js.map +1 -0
  70. package/dist/cli/chunk-ZTLZO42A.js +231 -0
  71. package/dist/cli/chunk-ZTLZO42A.js.map +1 -0
  72. package/dist/cli/code-DLR77NPZ.js +151 -0
  73. package/dist/cli/code-DLR77NPZ.js.map +1 -0
  74. package/dist/cli/commands-JWT2MWVH.js +352 -0
  75. package/dist/cli/commands-JWT2MWVH.js.map +1 -0
  76. package/dist/cli/commit-RPZBOZS2.js +288 -0
  77. package/dist/cli/commit-RPZBOZS2.js.map +1 -0
  78. package/dist/cli/diff-NTEHCSDW.js +145 -0
  79. package/dist/cli/diff-NTEHCSDW.js.map +1 -0
  80. package/dist/cli/doctor-3TGB2NZN.js +19 -0
  81. package/dist/cli/doctor-3TGB2NZN.js.map +1 -0
  82. package/dist/cli/events-P27CX7LN.js +338 -0
  83. package/dist/cli/events-P27CX7LN.js.map +1 -0
  84. package/dist/cli/index.js +80 -33693
  85. package/dist/cli/index.js.map +1 -1
  86. package/dist/cli/mcp-ARTNQ24O.js +266 -0
  87. package/dist/cli/mcp-ARTNQ24O.js.map +1 -0
  88. package/dist/cli/mcp-browse-HLO2ENDL.js +163 -0
  89. package/dist/cli/mcp-browse-HLO2ENDL.js.map +1 -0
  90. package/dist/cli/mcp-inspect-T2HBR22P.js +103 -0
  91. package/dist/cli/mcp-inspect-T2HBR22P.js.map +1 -0
  92. package/dist/cli/{prompt-XHICFAYN.js → prompt-V47QKSAR.js} +3 -2
  93. package/dist/cli/prompt-V47QKSAR.js.map +1 -0
  94. package/dist/cli/prune-sessions-ERL6B4G5.js +42 -0
  95. package/dist/cli/prune-sessions-ERL6B4G5.js.map +1 -0
  96. package/dist/cli/replay-Q43DSMG6.js +273 -0
  97. package/dist/cli/replay-Q43DSMG6.js.map +1 -0
  98. package/dist/cli/run-JMEOTQCG.js +215 -0
  99. package/dist/cli/run-JMEOTQCG.js.map +1 -0
  100. package/dist/cli/server-SYC3OVOP.js +2967 -0
  101. package/dist/cli/server-SYC3OVOP.js.map +1 -0
  102. package/dist/cli/sessions-MOJAALJI.js +102 -0
  103. package/dist/cli/sessions-MOJAALJI.js.map +1 -0
  104. package/dist/cli/setup-CCJZAWTY.js +404 -0
  105. package/dist/cli/setup-CCJZAWTY.js.map +1 -0
  106. package/dist/cli/stats-5RJCATCE.js +12 -0
  107. package/dist/cli/stats-5RJCATCE.js.map +1 -0
  108. package/dist/cli/update-4TJWRUIN.js +90 -0
  109. package/dist/cli/update-4TJWRUIN.js.map +1 -0
  110. package/dist/cli/version-3MYFE4G6.js +29 -0
  111. package/dist/cli/version-3MYFE4G6.js.map +1 -0
  112. package/dist/index.d.ts +13 -2
  113. package/dist/index.js +493 -89
  114. package/dist/index.js.map +1 -1
  115. package/package.json +1 -1
  116. package/dist/cli/chunk-VWFJNLIK.js +0 -1031
  117. package/dist/cli/chunk-VWFJNLIK.js.map +0 -1
  118. /package/dist/cli/{prompt-XHICFAYN.js.map → chat-Q5ZCVIOO.js.map} +0 -0
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ chatCommand
4
+ } from "./chunk-MDHVWCJ4.js";
5
+ import "./chunk-BQNUJJN7.js";
6
+ import "./chunk-RFX7TYVV.js";
7
+ import "./chunk-63KAV5DX.js";
8
+ import "./chunk-CPOV2O73.js";
9
+ import "./chunk-Q6YFXW7H.js";
10
+ import "./chunk-I6YIAK6C.js";
11
+ import "./chunk-XJLZ4HKU.js";
12
+ import "./chunk-XHQIK7B6.js";
13
+ import "./chunk-6TMHAK5D.js";
14
+ import "./chunk-SDE5U32Z.js";
15
+ import "./chunk-ZPTSJGX5.js";
16
+ import "./chunk-MHDNZXJJ.js";
17
+ import "./chunk-D5DKXIP5.js";
18
+ import "./chunk-KMWKGPFZ.js";
19
+ import "./chunk-3Q3C4W66.js";
20
+ import "./chunk-4DCHFFEY.js";
21
+ import "./chunk-FXGQ5NHE.js";
22
+ import "./chunk-G3XNWSFN.js";
23
+ import "./chunk-SOZE7V7V.js";
24
+ import "./chunk-W4LDFAZ6.js";
25
+ import "./chunk-U3V2ZQ5J.js";
26
+ import "./chunk-FM57FNPJ.js";
27
+ import "./chunk-RZILUXUC.js";
28
+ import "./chunk-WBDE4IRI.js";
29
+ import "./chunk-2AWTGJ2C.js";
30
+ import "./chunk-5X7LZJDE.js";
31
+ import "./chunk-DFP4YSVM.js";
32
+ import "./chunk-QGE6AF76.js";
33
+ import "./chunk-DULSP7JH.js";
34
+ import "./chunk-ZTLZO42A.js";
35
+ import "./chunk-ORM6PK57.js";
36
+ export {
37
+ chatCommand
38
+ };
39
+ //# sourceMappingURL=chat-Q5ZCVIOO.js.map
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/version.ts
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
+ import { homedir } from "os";
6
+ import { dirname, join } from "path";
7
+ import { fileURLToPath } from "url";
8
+ var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
9
+ var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
10
+ var LATEST_FETCH_TIMEOUT_MS = 2e3;
11
+ function readPackageVersion() {
12
+ try {
13
+ let dir = dirname(fileURLToPath(import.meta.url));
14
+ for (let i = 0; i < 6; i++) {
15
+ const p = join(dir, "package.json");
16
+ if (existsSync(p)) {
17
+ const pkg = JSON.parse(readFileSync(p, "utf8"));
18
+ if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
19
+ return pkg.version;
20
+ }
21
+ }
22
+ const parent = dirname(dir);
23
+ if (parent === dir) break;
24
+ dir = parent;
25
+ }
26
+ } catch {
27
+ }
28
+ return "0.0.0-dev";
29
+ }
30
+ var VERSION = readPackageVersion();
31
+ function cachePath(homeDirOverride) {
32
+ return join(homeDirOverride ?? homedir(), ".reasonix", "version-cache.json");
33
+ }
34
+ function readCache(homeDirOverride) {
35
+ try {
36
+ const raw = readFileSync(cachePath(homeDirOverride), "utf8");
37
+ const parsed = JSON.parse(raw);
38
+ if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
39
+ return parsed;
40
+ }
41
+ } catch {
42
+ }
43
+ return null;
44
+ }
45
+ function writeCache(entry, homeDirOverride) {
46
+ try {
47
+ const p = cachePath(homeDirOverride);
48
+ mkdirSync(dirname(p), { recursive: true });
49
+ writeFileSync(p, JSON.stringify(entry), "utf8");
50
+ } catch {
51
+ }
52
+ }
53
+ async function getLatestVersion(opts = {}) {
54
+ const ttl = opts.ttlMs ?? LATEST_CACHE_TTL_MS;
55
+ if (!opts.force) {
56
+ const cached = readCache(opts.homeDir);
57
+ if (cached && Date.now() - cached.checkedAt < ttl) return cached.version;
58
+ }
59
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
60
+ if (!fetchImpl) return null;
61
+ const url = opts.registryUrl ?? REGISTRY_URL;
62
+ const timeout = opts.timeoutMs ?? LATEST_FETCH_TIMEOUT_MS;
63
+ const controller = new AbortController();
64
+ const timer = setTimeout(() => controller.abort(), timeout);
65
+ try {
66
+ const res = await fetchImpl(url, {
67
+ signal: controller.signal,
68
+ headers: { accept: "application/json" }
69
+ });
70
+ if (!res.ok) return null;
71
+ const body = await res.json();
72
+ if (typeof body.version !== "string") return null;
73
+ writeCache({ version: body.version, checkedAt: Date.now() }, opts.homeDir);
74
+ return body.version;
75
+ } catch {
76
+ return null;
77
+ } finally {
78
+ clearTimeout(timer);
79
+ }
80
+ }
81
+ function compareVersions(a, b) {
82
+ const [aCore = "0", aPre = ""] = a.split("-", 2);
83
+ const [bCore = "0", bPre = ""] = b.split("-", 2);
84
+ const aParts = aCore.split(".").map((p) => Number.parseInt(p, 10) || 0);
85
+ const bParts = bCore.split(".").map((p) => Number.parseInt(p, 10) || 0);
86
+ for (let i = 0; i < 3; i++) {
87
+ const diff = (aParts[i] ?? 0) - (bParts[i] ?? 0);
88
+ if (diff !== 0) return diff;
89
+ }
90
+ if (!aPre && !bPre) return 0;
91
+ if (!aPre) return 1;
92
+ if (!bPre) return -1;
93
+ return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;
94
+ }
95
+ function isNpxInstall() {
96
+ const bin = process.argv[1] ?? "";
97
+ if (/[/\\]_npx[/\\]/.test(bin)) return true;
98
+ if (/[/\\]\.pnpm[/\\]/.test(bin) && /dlx/i.test(bin)) return true;
99
+ const ua = process.env.npm_config_user_agent ?? "";
100
+ if (ua.includes("npx/")) return true;
101
+ return false;
102
+ }
103
+
104
+ export {
105
+ VERSION,
106
+ getLatestVersion,
107
+ compareVersions,
108
+ isNpxInstall
109
+ };
110
+ //# sourceMappingURL=chunk-2AWTGJ2C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/version.ts"],"sourcesContent":["/** VERSION sourced from package.json so it never drifts from npm; latest-check returns null on any failure. */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/** npm registry endpoint for the `latest` dist-tag of this package. */\nconst REGISTRY_URL = \"https://registry.npmjs.org/reasonix/latest\";\n\n/** TTL for the on-disk cache entry. 24h keeps noise low; users who\n * want a fresh check can run `reasonix update` which passes\n * `force: true`. */\nexport const LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/** Network timeout. Short — we never block the UI waiting on this. */\nexport const LATEST_FETCH_TIMEOUT_MS = 2_000;\n\n/** `name === \"reasonix\"` guard avoids picking up an outer package.json when loaded as a dep. */\nfunction readPackageVersion(): string {\n try {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 6; i++) {\n const p = join(dir, \"package.json\");\n if (existsSync(p)) {\n const pkg = JSON.parse(readFileSync(p, \"utf8\"));\n if (pkg?.name === \"reasonix\" && typeof pkg.version === \"string\") {\n return pkg.version;\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n /* fall through to fallback */\n }\n return \"0.0.0-dev\";\n}\n\nexport const VERSION: string = readPackageVersion();\n\ninterface VersionCacheEntry {\n version: string;\n /** Epoch millis the entry was written. Drives TTL comparisons. */\n checkedAt: number;\n}\n\nfunction cachePath(homeDirOverride?: string): string {\n return join(homeDirOverride ?? homedir(), \".reasonix\", \"version-cache.json\");\n}\n\nfunction readCache(homeDirOverride?: string): VersionCacheEntry | null {\n try {\n const raw = readFileSync(cachePath(homeDirOverride), \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed.version === \"string\" && typeof parsed.checkedAt === \"number\") {\n return parsed;\n }\n } catch {\n /* missing or malformed → no cached entry */\n }\n return null;\n}\n\nfunction writeCache(entry: VersionCacheEntry, homeDirOverride?: string): void {\n try {\n const p = cachePath(homeDirOverride);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(entry), \"utf8\");\n } catch {\n /* cache is best-effort — a failed write just means we'll re-fetch\n * next launch. No reason to surface this to the user. */\n }\n}\n\nexport interface GetLatestVersionOptions {\n /** Ignore the cached entry and always fetch fresh. Used by `reasonix update`. */\n force?: boolean;\n /** Registry URL override (tests). */\n registryUrl?: string;\n /** Home-directory override (tests). */\n homeDir?: string;\n /** Fetch implementation override (tests). Defaults to `globalThis.fetch`. */\n fetchImpl?: typeof fetch;\n /** TTL override (tests). */\n ttlMs?: number;\n /** Network timeout override (tests). */\n timeoutMs?: number;\n}\n\n/** Returns null on failure; cache only writes on success so bad responses can't poison it. */\nexport async function getLatestVersion(opts: GetLatestVersionOptions = {}): Promise<string | null> {\n const ttl = opts.ttlMs ?? LATEST_CACHE_TTL_MS;\n if (!opts.force) {\n const cached = readCache(opts.homeDir);\n if (cached && Date.now() - cached.checkedAt < ttl) return cached.version;\n }\n\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n if (!fetchImpl) return null;\n const url = opts.registryUrl ?? REGISTRY_URL;\n const timeout = opts.timeoutMs ?? LATEST_FETCH_TIMEOUT_MS;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n try {\n const res = await fetchImpl(url, {\n signal: controller.signal,\n headers: { accept: \"application/json\" },\n });\n if (!res.ok) return null;\n const body = (await res.json()) as { version?: unknown };\n if (typeof body.version !== \"string\") return null;\n writeCache({ version: body.version, checkedAt: Date.now() }, opts.homeDir);\n return body.version;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** Pre-release with same core sorts BELOW the bare version — matches npm `latest` dist-tag semantics. */\nexport function compareVersions(a: string, b: string): number {\n const [aCore = \"0\", aPre = \"\"] = a.split(\"-\", 2);\n const [bCore = \"0\", bPre = \"\"] = b.split(\"-\", 2);\n const aParts = aCore.split(\".\").map((p) => Number.parseInt(p, 10) || 0);\n const bParts = bCore.split(\".\").map((p) => Number.parseInt(p, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const diff = (aParts[i] ?? 0) - (bParts[i] ?? 0);\n if (diff !== 0) return diff;\n }\n if (!aPre && !bPre) return 0;\n if (!aPre) return 1;\n if (!bPre) return -1;\n return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;\n}\n\n/** False negatives are safe — `npm i -g` works for npx users too. */\nexport function isNpxInstall(): boolean {\n const bin = process.argv[1] ?? \"\";\n if (/[/\\\\]_npx[/\\\\]/.test(bin)) return true;\n if (/[/\\\\]\\.pnpm[/\\\\]/.test(bin) && /dlx/i.test(bin)) return true;\n const ua = process.env.npm_config_user_agent ?? \"\";\n if (ua.includes(\"npx/\")) return true;\n return false;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/env.ts
4
+ import { readFileSync } from "fs";
5
+ import { resolve } from "path";
6
+ function loadDotenv(path = ".env") {
7
+ let raw;
8
+ try {
9
+ raw = readFileSync(resolve(process.cwd(), path), "utf8");
10
+ } catch {
11
+ return;
12
+ }
13
+ for (const line of raw.split(/\r?\n/)) {
14
+ const trimmed = line.trim();
15
+ if (!trimmed || trimmed.startsWith("#")) continue;
16
+ const eq = trimmed.indexOf("=");
17
+ if (eq === -1) continue;
18
+ const key = trimmed.slice(0, eq).trim();
19
+ let value = trimmed.slice(eq + 1).trim();
20
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
21
+ value = value.slice(1, -1);
22
+ }
23
+ if (process.env[key] === void 0) process.env[key] = value;
24
+ }
25
+ }
26
+
27
+ export {
28
+ loadDotenv
29
+ };
30
+ //# sourceMappingURL=chunk-3Q3C4W66.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/env.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nexport function loadDotenv(path = \".env\"): void {\n let raw: string;\n try {\n raw = readFileSync(resolve(process.cwd(), path), \"utf8\");\n } catch {\n return;\n }\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (process.env[key] === undefined) process.env[key] = value;\n }\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AAEjB,SAAS,WAAW,OAAO,QAAc;AAC9C,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,QAAQ,QAAQ,IAAI,GAAG,IAAI,GAAG,MAAM;AAAA,EACzD,QAAQ;AACN;AAAA,EACF;AACA,aAAW,QAAQ,IAAI,MAAM,OAAO,GAAG;AACrC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,EAAG;AACzC,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,OAAO,GAAI;AACf,UAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;AACtC,QAAI,QAAQ,QAAQ,MAAM,KAAK,CAAC,EAAE,KAAK;AACvC,QACG,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,KAC3C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAC5C;AACA,cAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,IAC3B;AACA,QAAI,QAAQ,IAAI,GAAG,MAAM,OAAW,SAAQ,IAAI,GAAG,IAAI;AAAA,EACzD;AACF;","names":[]}
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ aggregateUsage,
4
+ bucketCacheHitRatio,
5
+ bucketSavingsFraction,
6
+ defaultUsageLogPath,
7
+ formatLogSize,
8
+ readUsageLog
9
+ } from "./chunk-ZTLZO42A.js";
10
+
11
+ // src/cli/commands/stats.ts
12
+ import { existsSync, readFileSync } from "fs";
13
+ function statsCommand(opts) {
14
+ if (opts.transcript) {
15
+ transcriptSummary(opts.transcript);
16
+ return;
17
+ }
18
+ dashboard(opts);
19
+ }
20
+ function transcriptSummary(path) {
21
+ if (!existsSync(path)) {
22
+ console.error(`no such transcript: ${path}`);
23
+ process.exit(1);
24
+ }
25
+ const lines = readFileSync(path, "utf8").split(/\r?\n/).filter(Boolean);
26
+ let assistantTurns = 0;
27
+ let toolCalls = 0;
28
+ let lastTurn = 0;
29
+ for (const line of lines) {
30
+ try {
31
+ const rec = JSON.parse(line);
32
+ if (rec.role === "assistant_final") assistantTurns++;
33
+ if (rec.role === "tool") toolCalls++;
34
+ if (typeof rec.turn === "number") lastTurn = Math.max(lastTurn, rec.turn);
35
+ } catch {
36
+ }
37
+ }
38
+ console.log(`transcript: ${path}`);
39
+ console.log(`assistant turns: ${assistantTurns}`);
40
+ console.log(`tool invocations: ${toolCalls}`);
41
+ console.log(`last turn index: ${lastTurn}`);
42
+ }
43
+ function dashboard(opts) {
44
+ const path = opts.logPath ?? defaultUsageLogPath();
45
+ const records = readUsageLog(path);
46
+ if (records.length === 0) {
47
+ console.log("no usage data yet.");
48
+ console.log("");
49
+ console.log(` ${path}`);
50
+ console.log("");
51
+ console.log("run `reasonix chat`, `reasonix code`, or `reasonix run <task>` \u2014 every turn");
52
+ console.log("appends one line to the log and `reasonix stats` will roll it up.");
53
+ return;
54
+ }
55
+ const agg = aggregateUsage(records, { now: opts.now });
56
+ console.log(renderDashboard(agg, path));
57
+ }
58
+ function renderDashboard(agg, logPath) {
59
+ const lines = [];
60
+ const size = formatLogSize(logPath);
61
+ lines.push(`Reasonix usage \u2014 ${logPath}${size ? ` (${size})` : ""}`);
62
+ lines.push("");
63
+ lines.push(header());
64
+ lines.push(divider());
65
+ for (const b of agg.buckets) {
66
+ lines.push(bucketRow(b));
67
+ }
68
+ lines.push("");
69
+ if (agg.byModel.length > 0) {
70
+ const totalTurns = agg.buckets[agg.buckets.length - 1]?.turns ?? 0;
71
+ const top = agg.byModel[0];
72
+ if (top && totalTurns > 0) {
73
+ const pct = (top.turns / totalTurns * 100).toFixed(0);
74
+ lines.push(`most used model: ${top.model} (${pct}% of turns)`);
75
+ }
76
+ }
77
+ if (agg.bySession.length > 0) {
78
+ const top = agg.bySession[0];
79
+ if (top) lines.push(`top session: ${top.session} (${top.turns} turns)`);
80
+ }
81
+ if (agg.firstSeen) {
82
+ lines.push(`tracked since: ${new Date(agg.firstSeen).toISOString().slice(0, 10)}`);
83
+ }
84
+ if (agg.subagents) {
85
+ lines.push("");
86
+ lines.push(renderSubagentSection(agg.subagents));
87
+ }
88
+ return lines.join("\n");
89
+ }
90
+ function renderSubagentSection(sub) {
91
+ const lines = [];
92
+ const seconds = (sub.totalDurationMs / 1e3).toFixed(1);
93
+ lines.push(
94
+ `subagent activity: ${sub.total} run(s) \xB7 $${sub.costUsd.toFixed(6)} \xB7 ${seconds}s total`
95
+ );
96
+ const top = sub.bySkill.slice(0, 5);
97
+ for (const s of top) {
98
+ const sec = (s.durationMs / 1e3).toFixed(1);
99
+ lines.push(
100
+ ` ${pad(s.skillName, 18)} ${pad(`${s.count}`, 4, "right")} $${s.costUsd.toFixed(6)} ${sec}s`
101
+ );
102
+ }
103
+ if (sub.bySkill.length > top.length) {
104
+ lines.push(` (+${sub.bySkill.length - top.length} more)`);
105
+ }
106
+ return lines.join("\n");
107
+ }
108
+ function header() {
109
+ return [
110
+ pad("", 10),
111
+ pad("turns", 8, "right"),
112
+ pad("cache hit", 10, "right"),
113
+ pad("cost (USD)", 14, "right"),
114
+ pad("cache saved", 14, "right"),
115
+ pad("vs Claude", 14, "right"),
116
+ pad("saved", 10, "right")
117
+ ].join(" ");
118
+ }
119
+ function divider() {
120
+ return "-".repeat(86);
121
+ }
122
+ function bucketRow(b) {
123
+ const hit = bucketCacheHitRatio(b);
124
+ const savings = bucketSavingsFraction(b);
125
+ return [
126
+ pad(b.label, 10),
127
+ pad(b.turns.toString(), 8, "right"),
128
+ pad(b.turns > 0 ? `${(hit * 100).toFixed(1)}%` : "\u2014", 10, "right"),
129
+ pad(b.turns > 0 ? `$${b.costUsd.toFixed(6)}` : "\u2014", 14, "right"),
130
+ pad(
131
+ b.turns > 0 && b.cacheSavingsUsd > 0 ? `$${b.cacheSavingsUsd.toFixed(4)}` : "\u2014",
132
+ 14,
133
+ "right"
134
+ ),
135
+ pad(b.turns > 0 ? `$${b.claudeEquivUsd.toFixed(4)}` : "\u2014", 14, "right"),
136
+ pad(b.turns > 0 && savings > 0 ? `${(savings * 100).toFixed(1)}%` : "\u2014", 10, "right")
137
+ ].join(" ");
138
+ }
139
+ function pad(s, width, align = "left") {
140
+ if (s.length >= width) return s;
141
+ const fill = " ".repeat(width - s.length);
142
+ return align === "right" ? `${fill}${s}` : `${s}${fill}`;
143
+ }
144
+
145
+ export {
146
+ statsCommand,
147
+ renderDashboard
148
+ };
149
+ //# sourceMappingURL=chunk-4DCHFFEY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/stats.ts"],"sourcesContent":["/** `reasonix stats [path]` — path arg switches to per-transcript mode; default is the cross-session dashboard. */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport {\n type UsageAggregate,\n type UsageBucket,\n aggregateUsage,\n bucketCacheHitRatio,\n bucketSavingsFraction,\n defaultUsageLogPath,\n formatLogSize,\n readUsageLog,\n} from \"../../telemetry/usage.js\";\n\nexport interface StatsOptions {\n /** Optional transcript path. Absent → dashboard mode. */\n transcript?: string;\n /** Override usage log location (tests). */\n logPath?: string;\n /** Inject a fixed timestamp (tests) so rolling windows are deterministic. */\n now?: number;\n}\n\nexport function statsCommand(opts: StatsOptions): void {\n if (opts.transcript) {\n transcriptSummary(opts.transcript);\n return;\n }\n dashboard(opts);\n}\n\nfunction transcriptSummary(path: string): void {\n if (!existsSync(path)) {\n console.error(`no such transcript: ${path}`);\n process.exit(1);\n }\n const lines = readFileSync(path, \"utf8\").split(/\\r?\\n/).filter(Boolean);\n let assistantTurns = 0;\n let toolCalls = 0;\n let lastTurn = 0;\n for (const line of lines) {\n try {\n const rec = JSON.parse(line);\n if (rec.role === \"assistant_final\") assistantTurns++;\n if (rec.role === \"tool\") toolCalls++;\n if (typeof rec.turn === \"number\") lastTurn = Math.max(lastTurn, rec.turn);\n } catch {\n /* skip */\n }\n }\n console.log(`transcript: ${path}`);\n console.log(`assistant turns: ${assistantTurns}`);\n console.log(`tool invocations: ${toolCalls}`);\n console.log(`last turn index: ${lastTurn}`);\n}\n\nfunction dashboard(opts: StatsOptions): void {\n const path = opts.logPath ?? defaultUsageLogPath();\n const records = readUsageLog(path);\n if (records.length === 0) {\n console.log(\"no usage data yet.\");\n console.log(\"\");\n console.log(` ${path}`);\n console.log(\"\");\n console.log(\"run `reasonix chat`, `reasonix code`, or `reasonix run <task>` — every turn\");\n console.log(\"appends one line to the log and `reasonix stats` will roll it up.\");\n return;\n }\n\n const agg = aggregateUsage(records, { now: opts.now });\n console.log(renderDashboard(agg, path));\n}\n\n/** Pure renderer — pulled out so tests can assert on the string directly. */\nexport function renderDashboard(agg: UsageAggregate, logPath: string): string {\n const lines: string[] = [];\n const size = formatLogSize(logPath);\n lines.push(`Reasonix usage — ${logPath}${size ? ` (${size})` : \"\"}`);\n lines.push(\"\");\n lines.push(header());\n lines.push(divider());\n for (const b of agg.buckets) {\n lines.push(bucketRow(b));\n }\n lines.push(\"\");\n\n // Model + session breakdown — both trim to top 3 so a user with 20\n // sessions doesn't drown the table.\n if (agg.byModel.length > 0) {\n const totalTurns = agg.buckets[agg.buckets.length - 1]?.turns ?? 0;\n const top = agg.byModel[0];\n if (top && totalTurns > 0) {\n const pct = ((top.turns / totalTurns) * 100).toFixed(0);\n lines.push(`most used model: ${top.model} (${pct}% of turns)`);\n }\n }\n if (agg.bySession.length > 0) {\n const top = agg.bySession[0];\n if (top) lines.push(`top session: ${top.session} (${top.turns} turns)`);\n }\n if (agg.firstSeen) {\n lines.push(`tracked since: ${new Date(agg.firstSeen).toISOString().slice(0, 10)}`);\n }\n if (agg.subagents) {\n lines.push(\"\");\n lines.push(renderSubagentSection(agg.subagents));\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderSubagentSection(sub: NonNullable<UsageAggregate[\"subagents\"]>): string {\n const lines: string[] = [];\n const seconds = (sub.totalDurationMs / 1000).toFixed(1);\n lines.push(\n `subagent activity: ${sub.total} run(s) · $${sub.costUsd.toFixed(6)} · ${seconds}s total`,\n );\n // Show at most 5 skills so the section never dwarfs the main table.\n const top = sub.bySkill.slice(0, 5);\n for (const s of top) {\n const sec = (s.durationMs / 1000).toFixed(1);\n lines.push(\n ` ${pad(s.skillName, 18)} ${pad(`${s.count}`, 4, \"right\")} $${s.costUsd.toFixed(6)} ${sec}s`,\n );\n }\n if (sub.bySkill.length > top.length) {\n lines.push(` (+${sub.bySkill.length - top.length} more)`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction header(): string {\n // Fixed column widths so alignment works in any TTY.\n // `cache saved` reports DeepSeek's hit-vs-miss USD diff; the existing\n // `saved` column is the % saved vs Claude-Sonnet equivalent.\n return [\n pad(\"\", 10),\n pad(\"turns\", 8, \"right\"),\n pad(\"cache hit\", 10, \"right\"),\n pad(\"cost (USD)\", 14, \"right\"),\n pad(\"cache saved\", 14, \"right\"),\n pad(\"vs Claude\", 14, \"right\"),\n pad(\"saved\", 10, \"right\"),\n ].join(\" \");\n}\n\nfunction divider(): string {\n return \"-\".repeat(86);\n}\n\nfunction bucketRow(b: UsageBucket): string {\n const hit = bucketCacheHitRatio(b);\n const savings = bucketSavingsFraction(b);\n return [\n pad(b.label, 10),\n pad(b.turns.toString(), 8, \"right\"),\n pad(b.turns > 0 ? `${(hit * 100).toFixed(1)}%` : \"—\", 10, \"right\"),\n pad(b.turns > 0 ? `$${b.costUsd.toFixed(6)}` : \"—\", 14, \"right\"),\n pad(\n b.turns > 0 && b.cacheSavingsUsd > 0 ? `$${b.cacheSavingsUsd.toFixed(4)}` : \"—\",\n 14,\n \"right\",\n ),\n pad(b.turns > 0 ? `$${b.claudeEquivUsd.toFixed(4)}` : \"—\", 14, \"right\"),\n pad(b.turns > 0 && savings > 0 ? `${(savings * 100).toFixed(1)}%` : \"—\", 10, \"right\"),\n ].join(\" \");\n}\n\nfunction pad(s: string, width: number, align: \"left\" | \"right\" = \"left\"): string {\n if (s.length >= width) return s;\n const fill = \" \".repeat(width - s.length);\n return align === \"right\" ? `${fill}${s}` : `${s}${fill}`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/gitignore.ts
4
+ import { readFileSync } from "fs";
5
+ import { readFile } from "fs/promises";
6
+ import path from "path";
7
+ import ignore from "ignore";
8
+ async function loadGitignoreAt(dirAbs) {
9
+ try {
10
+ return ignore().add(await readFile(path.join(dirAbs, ".gitignore"), "utf8"));
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ function loadGitignoreAtSync(dirAbs) {
16
+ try {
17
+ return ignore().add(readFileSync(path.join(dirAbs, ".gitignore"), "utf8"));
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function ignoredByLayers(layers, abs, isDir) {
23
+ for (const layer of layers) {
24
+ const rel = path.relative(layer.dirAbs, abs).split(path.sep).join("/");
25
+ if (!rel || rel.startsWith("..")) continue;
26
+ if (layer.ig.ignores(isDir ? `${rel}/` : rel)) return true;
27
+ }
28
+ return false;
29
+ }
30
+
31
+ export {
32
+ loadGitignoreAt,
33
+ loadGitignoreAtSync,
34
+ ignoredByLayers
35
+ };
36
+ //# sourceMappingURL=chunk-5X7LZJDE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/gitignore.ts"],"sourcesContent":["/** Nested .gitignore evaluation — shared by the at-mention picker walker and the semantic chunker. */\n\nimport { readFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\n\nexport interface GitignoreLayer {\n /** Absolute dir the .gitignore lives in. Patterns evaluate relative to this. */\n dirAbs: string;\n ig: Ignore;\n}\n\nexport async function loadGitignoreAt(dirAbs: string): Promise<Ignore | null> {\n try {\n return ignore().add(await readFile(path.join(dirAbs, \".gitignore\"), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nexport function loadGitignoreAtSync(dirAbs: string): Ignore | null {\n try {\n return ignore().add(readFileSync(path.join(dirAbs, \".gitignore\"), \"utf8\"));\n } catch {\n return null;\n }\n}\n\n/** True if any layer — outermost to innermost — ignores this path. */\nexport function ignoredByLayers(\n layers: readonly GitignoreLayer[],\n abs: string,\n isDir: boolean,\n): boolean {\n for (const layer of layers) {\n const rel = path.relative(layer.dirAbs, abs).split(path.sep).join(\"/\");\n if (!rel || rel.startsWith(\"..\")) continue;\n if (layer.ig.ignores(isDir ? `${rel}/` : rel)) return true;\n }\n return false;\n}\n"],"mappings":";;;AAEA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,OAAO,YAA6B;AAQpC,eAAsB,gBAAgB,QAAwC;AAC5E,MAAI;AACF,WAAO,OAAO,EAAE,IAAI,MAAM,SAAS,KAAK,KAAK,QAAQ,YAAY,GAAG,MAAM,CAAC;AAAA,EAC7E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAAoB,QAA+B;AACjE,MAAI;AACF,WAAO,OAAO,EAAE,IAAI,aAAa,KAAK,KAAK,QAAQ,YAAY,GAAG,MAAM,CAAC;AAAA,EAC3E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,gBACd,QACA,KACA,OACS;AACT,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,KAAK,SAAS,MAAM,QAAQ,GAAG,EAAE,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG;AACrE,QAAI,CAAC,OAAO,IAAI,WAAW,IAAI,EAAG;AAClC,QAAI,MAAM,GAAG,QAAQ,QAAQ,GAAG,GAAG,MAAM,GAAG,EAAG,QAAO;AAAA,EACxD;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/ui/theme/tokens.ts
4
+ var FG = {
5
+ strong: "#e6edf3",
6
+ body: "#c9d1d9",
7
+ sub: "#8b949e",
8
+ meta: "#6e7681",
9
+ faint: "#484f58"
10
+ };
11
+ var TONE = {
12
+ brand: "#79c0ff",
13
+ accent: "#d2a8ff",
14
+ violet: "#b395f5",
15
+ ok: "#7ee787",
16
+ warn: "#f0b07d",
17
+ err: "#ff8b81",
18
+ info: "#79c0ff"
19
+ };
20
+ var TONE_ACTIVE = {
21
+ brand: "#a5d6ff",
22
+ accent: "#e2c5ff",
23
+ violet: "#c8aaff",
24
+ ok: "#a8f5ad",
25
+ warn: "#ffc99e",
26
+ err: "#ffaba3",
27
+ info: "#a5d6ff"
28
+ };
29
+ var SURFACE = {
30
+ bg: "#0a0c10",
31
+ bgInput: "#0d1015",
32
+ bgCode: "#06080c",
33
+ bgElev: "#11141a"
34
+ };
35
+ var CARD = {
36
+ user: { color: FG.meta, glyph: "\u25C7" },
37
+ reasoning: { color: TONE.accent, glyph: "\u25C6" },
38
+ streaming: { color: TONE.brand, glyph: "\u25C8" },
39
+ task: { color: TONE.warn, glyph: "\u25B6" },
40
+ tool: { color: TONE.info, glyph: "\u25A3" },
41
+ plan: { color: TONE.accent, glyph: "\u229E" },
42
+ diff: { color: TONE.ok, glyph: "\xB1" },
43
+ error: { color: TONE.err, glyph: "\u2716" },
44
+ warn: { color: TONE.warn, glyph: "\u26A0" },
45
+ usage: { color: FG.meta, glyph: "\u03A3" },
46
+ subagent: { color: TONE.violet, glyph: "\u232C" },
47
+ approval: { color: TONE.warn, glyph: "?" },
48
+ search: { color: TONE.info, glyph: "\u2299" },
49
+ memory: { color: FG.meta, glyph: "\u2311" },
50
+ ctx: { color: TONE.brand, glyph: "\u25D4" },
51
+ doctor: { color: FG.meta, glyph: "\u2695" },
52
+ branch: { color: TONE.violet, glyph: "\u2387" }
53
+ };
54
+ var USD_TO_CNY = 7.2;
55
+ var SYMBOL = { USD: "$", CNY: "\xA5" };
56
+ function formatBalance(amount, currency, opts) {
57
+ const cur = currency ?? "CNY";
58
+ const sym = SYMBOL[cur];
59
+ const digits = opts?.fractionDigits ?? 2;
60
+ const body = sym ? `${sym}${amount.toFixed(digits)}` : `${cur} ${amount.toFixed(digits)}`;
61
+ return opts?.label ? `w ${body}` : body;
62
+ }
63
+ function formatCost(costUsd, currency, fractionDigits = 4) {
64
+ const cur = currency ?? "CNY";
65
+ const amount = cur === "CNY" ? costUsd * USD_TO_CNY : costUsd;
66
+ return formatBalance(amount, cur, { fractionDigits });
67
+ }
68
+ function balanceColor(amount, currency) {
69
+ const cny = (currency ?? "CNY") === "USD" ? amount * USD_TO_CNY : amount;
70
+ if (cny < 5) return TONE.err;
71
+ if (cny < 20) return TONE.warn;
72
+ return TONE.brand;
73
+ }
74
+
75
+ // src/cli/ui/primitives.tsx
76
+ import { Text, useStdout } from "ink";
77
+ import React from "react";
78
+ function ChromeRule() {
79
+ const { stdout } = useStdout();
80
+ const cols = stdout?.columns ?? 80;
81
+ const w = Math.max(20, cols - 2);
82
+ return /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2500".repeat(w));
83
+ }
84
+ function Bar({
85
+ ratio,
86
+ color,
87
+ cells = 14,
88
+ dim
89
+ }) {
90
+ const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
91
+ return /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { color, dimColor: dim }, "\u25B0".repeat(filled)), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u25B1".repeat(cells - filled)));
92
+ }
93
+
94
+ export {
95
+ FG,
96
+ TONE,
97
+ TONE_ACTIVE,
98
+ SURFACE,
99
+ CARD,
100
+ formatBalance,
101
+ formatCost,
102
+ balanceColor,
103
+ ChromeRule,
104
+ Bar
105
+ };
106
+ //# sourceMappingURL=chunk-63KAV5DX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/ui/theme/tokens.ts","../../src/cli/ui/primitives.tsx"],"sourcesContent":["export const FG = {\n strong: \"#e6edf3\",\n body: \"#c9d1d9\",\n sub: \"#8b949e\",\n meta: \"#6e7681\",\n faint: \"#484f58\",\n} as const;\n\nexport const TONE = {\n brand: \"#79c0ff\",\n accent: \"#d2a8ff\",\n violet: \"#b395f5\",\n ok: \"#7ee787\",\n warn: \"#f0b07d\",\n err: \"#ff8b81\",\n info: \"#79c0ff\",\n} as const;\n\n/** Used only while a card is streaming/running, so live cards stand out from settled history. */\nexport const TONE_ACTIVE = {\n brand: \"#a5d6ff\",\n accent: \"#e2c5ff\",\n violet: \"#c8aaff\",\n ok: \"#a8f5ad\",\n warn: \"#ffc99e\",\n err: \"#ffaba3\",\n info: \"#a5d6ff\",\n} as const;\n\nexport const SURFACE = {\n bg: \"#0a0c10\",\n bgInput: \"#0d1015\",\n bgCode: \"#06080c\",\n bgElev: \"#11141a\",\n} as const;\n\nexport const CARD = {\n user: { color: FG.meta, glyph: \"◇\" },\n reasoning: { color: TONE.accent, glyph: \"◆\" },\n streaming: { color: TONE.brand, glyph: \"◈\" },\n task: { color: TONE.warn, glyph: \"▶\" },\n tool: { color: TONE.info, glyph: \"▣\" },\n plan: { color: TONE.accent, glyph: \"⊞\" },\n diff: { color: TONE.ok, glyph: \"±\" },\n error: { color: TONE.err, glyph: \"✖\" },\n warn: { color: TONE.warn, glyph: \"⚠\" },\n usage: { color: FG.meta, glyph: \"Σ\" },\n subagent: { color: TONE.violet, glyph: \"⌬\" },\n approval: { color: TONE.warn, glyph: \"?\" },\n search: { color: TONE.info, glyph: \"⊙\" },\n memory: { color: FG.meta, glyph: \"⌑\" },\n ctx: { color: TONE.brand, glyph: \"◔\" },\n doctor: { color: FG.meta, glyph: \"⚕\" },\n branch: { color: TONE.violet, glyph: \"⎇\" },\n} as const;\n\nexport type CardTone = keyof typeof CARD;\n\n/** DeepSeek prices in CNY; our internal table is USD divided by 7.2. Multiply back for display. */\nexport const USD_TO_CNY = 7.2;\n\nconst SYMBOL: Record<string, string> = { USD: \"$\", CNY: \"¥\" };\n\n/** Format an amount already in `currency`. Undefined currency → CNY (matches pre-fix behavior). */\nexport function formatBalance(\n amount: number,\n currency?: string,\n opts?: { fractionDigits?: number; label?: boolean },\n): string {\n const cur = currency ?? \"CNY\";\n const sym = SYMBOL[cur];\n const digits = opts?.fractionDigits ?? 2;\n const body = sym ? `${sym}${amount.toFixed(digits)}` : `${cur} ${amount.toFixed(digits)}`;\n return opts?.label ? `w ${body}` : body;\n}\n\n/** Format an internal USD cost in the wallet's display currency. Undefined currency → CNY. */\nexport function formatCost(costUsd: number, currency?: string, fractionDigits = 4): string {\n const cur = currency ?? \"CNY\";\n const amount = cur === \"CNY\" ? costUsd * USD_TO_CNY : costUsd;\n return formatBalance(amount, cur, { fractionDigits });\n}\n\n/** Threshold color for a wallet balance. USD is converted to CNY before the threshold check. */\nexport function balanceColor(amount: number, currency?: string): string {\n const cny = (currency ?? \"CNY\") === \"USD\" ? amount * USD_TO_CNY : amount;\n if (cny < 5) return TONE.err;\n if (cny < 20) return TONE.warn;\n return TONE.brand;\n}\n","import { Text, useStdout } from \"ink\";\n// biome-ignore lint/style/useImportType: tsconfig jsx=react needs React in value scope for JSX compilation\nimport React from \"react\";\nimport { COLOR } from \"./theme.js\";\n\n/**\n * Faint full-width horizontal rule. Width tracks the terminal columns\n * minus 2 cells so it lines up exactly under content rendered inside\n * a `paddingX={1}` parent — the standard chrome layout. Used by the\n * top chrome bar, the replay StatsPanel, and the bottom ctx footer.\n */\nexport function ChromeRule(): React.ReactElement {\n const { stdout } = useStdout();\n const cols = stdout?.columns ?? 80;\n const w = Math.max(20, cols - 2);\n return <Text dimColor>{\"─\".repeat(w)}</Text>;\n}\n\n/** Compact binary-K formatter — `1234 → \"1.2K\"`, `131072 → \"128K\"`. */\nexport function formatTokens(n: number): string {\n if (n < 1024) return String(n);\n const k = n / 1024;\n return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;\n}\n\n/**\n * Filled / empty progress bar. `▰▱` glyphs have distinct shapes so the\n * boundary stays visible even when the terminal collapses to 8-color slots.\n */\nexport function Bar({\n ratio,\n color,\n cells = 14,\n dim,\n}: {\n ratio: number;\n color: string;\n cells?: number;\n dim?: boolean;\n}): React.ReactElement {\n const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));\n return (\n <Text>\n <Text color={color} dimColor={dim}>\n {\"▰\".repeat(filled)}\n </Text>\n <Text dimColor>{\"▱\".repeat(cells - filled)}</Text>\n </Text>\n );\n}\n\n/**\n * `▣ ctx ▰▰▱▱… 14K/128K (11%)` — the canonical context-pressure cell.\n * Used by the persistent footer (chat) and StatsPanel (replay). Color\n * thresholds match the `/compact` warning policy in the loop:\n * green <60% · amber 60-80% · red ≥80% (with `· /compact` hint).\n */\nexport function ContextCell({\n ratio,\n promptTokens,\n ctxMax,\n showBar,\n}: {\n ratio: number;\n promptTokens: number;\n ctxMax: number;\n showBar?: boolean;\n}): React.ReactElement {\n if (promptTokens === 0) {\n return (\n <Text>\n <Text color={COLOR.info} dimColor>\n {\"▣ ctx \"}\n </Text>\n <Text dimColor>— (no turns yet)</Text>\n </Text>\n );\n }\n const color = ratio >= 0.8 ? COLOR.err : ratio >= 0.6 ? COLOR.warn : COLOR.ok;\n const pct = Math.round(ratio * 100);\n return (\n <Text>\n <Text color={COLOR.info}>{\"▣ ctx \"}</Text>\n <Bar ratio={ratio} color={color} cells={showBar ? 14 : 10} />\n <Text> </Text>\n <Text color={color} bold>\n {formatTokens(promptTokens)}/{formatTokens(ctxMax)}\n </Text>\n <Text dimColor> ({pct}%)</Text>\n {ratio >= 0.8 ? (\n <Text color={COLOR.err} bold>\n {\" · /compact\"}\n </Text>\n ) : null}\n </Text>\n );\n}\n"],"mappings":"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","names":[]}