reasonix 0.32.0 → 0.33.0
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/dist/cli/chat-EIFLHBZ6.js +39 -0
- package/dist/cli/chunk-2AWTGJ2C.js +110 -0
- package/dist/cli/chunk-2AWTGJ2C.js.map +1 -0
- package/dist/cli/chunk-3Q3C4W66.js +30 -0
- package/dist/cli/chunk-3Q3C4W66.js.map +1 -0
- package/dist/cli/chunk-4DCHFFEY.js +149 -0
- package/dist/cli/chunk-4DCHFFEY.js.map +1 -0
- package/dist/cli/chunk-5X7LZJDE.js +36 -0
- package/dist/cli/chunk-5X7LZJDE.js.map +1 -0
- package/dist/cli/chunk-6TMHAK5D.js +576 -0
- package/dist/cli/chunk-6TMHAK5D.js.map +1 -0
- package/dist/cli/chunk-APPB3ZPQ.js +43 -0
- package/dist/cli/chunk-APPB3ZPQ.js.map +1 -0
- package/dist/cli/chunk-BQNUJJN7.js +42 -0
- package/dist/cli/chunk-BQNUJJN7.js.map +1 -0
- package/dist/cli/chunk-CPOV2O73.js +39 -0
- package/dist/cli/chunk-CPOV2O73.js.map +1 -0
- package/dist/cli/chunk-D5DKXIP5.js +368 -0
- package/dist/cli/chunk-D5DKXIP5.js.map +1 -0
- package/dist/cli/chunk-DFP4YSVM.js +247 -0
- package/dist/cli/chunk-DFP4YSVM.js.map +1 -0
- package/dist/cli/chunk-DULSP7JH.js +410 -0
- package/dist/cli/chunk-DULSP7JH.js.map +1 -0
- package/dist/cli/chunk-FM57FNPJ.js +46 -0
- package/dist/cli/chunk-FM57FNPJ.js.map +1 -0
- package/dist/cli/chunk-FWGEHRB7.js +54 -0
- package/dist/cli/chunk-FWGEHRB7.js.map +1 -0
- package/dist/cli/chunk-FXGQ5NHE.js +513 -0
- package/dist/cli/chunk-FXGQ5NHE.js.map +1 -0
- package/dist/cli/chunk-G3XNWSFN.js +53 -0
- package/dist/cli/chunk-G3XNWSFN.js.map +1 -0
- package/dist/cli/chunk-I6YIAK6C.js +757 -0
- package/dist/cli/chunk-I6YIAK6C.js.map +1 -0
- package/dist/cli/chunk-J5VLP23S.js +94 -0
- package/dist/cli/chunk-J5VLP23S.js.map +1 -0
- package/dist/cli/chunk-KMWKGPFZ.js +303 -0
- package/dist/cli/chunk-KMWKGPFZ.js.map +1 -0
- package/dist/cli/chunk-LVQX5KGF.js +14934 -0
- package/dist/cli/chunk-LVQX5KGF.js.map +1 -0
- package/dist/cli/chunk-MHDNZXJJ.js +48 -0
- package/dist/cli/chunk-MHDNZXJJ.js.map +1 -0
- package/dist/cli/chunk-ORM6PK57.js +140 -0
- package/dist/cli/chunk-ORM6PK57.js.map +1 -0
- package/dist/cli/chunk-Q5GRLZJF.js +99 -0
- package/dist/cli/chunk-Q5GRLZJF.js.map +1 -0
- package/dist/cli/chunk-Q6YFXW7H.js +4986 -0
- package/dist/cli/chunk-Q6YFXW7H.js.map +1 -0
- package/dist/cli/chunk-QGE6AF76.js +1467 -0
- package/dist/cli/chunk-QGE6AF76.js.map +1 -0
- package/dist/cli/chunk-RFX7TYVV.js +28 -0
- package/dist/cli/chunk-RFX7TYVV.js.map +1 -0
- package/dist/cli/chunk-RZILUXUC.js +940 -0
- package/dist/cli/chunk-RZILUXUC.js.map +1 -0
- package/dist/cli/chunk-SDE5U32Z.js +535 -0
- package/dist/cli/chunk-SDE5U32Z.js.map +1 -0
- package/dist/cli/chunk-SOZE7V7V.js +340 -0
- package/dist/cli/chunk-SOZE7V7V.js.map +1 -0
- package/dist/cli/chunk-U3V2ZQ5J.js +479 -0
- package/dist/cli/chunk-U3V2ZQ5J.js.map +1 -0
- package/dist/cli/chunk-W4LDFAZ6.js +1544 -0
- package/dist/cli/chunk-W4LDFAZ6.js.map +1 -0
- package/dist/cli/chunk-WBDE4IRI.js +208 -0
- package/dist/cli/chunk-WBDE4IRI.js.map +1 -0
- package/dist/cli/chunk-XHQIK7B6.js +189 -0
- package/dist/cli/chunk-XHQIK7B6.js.map +1 -0
- package/dist/cli/chunk-XJLZ4HKU.js +307 -0
- package/dist/cli/chunk-XJLZ4HKU.js.map +1 -0
- package/dist/cli/chunk-ZPTSJGX5.js +88 -0
- package/dist/cli/chunk-ZPTSJGX5.js.map +1 -0
- package/dist/cli/chunk-ZTLZO42A.js +231 -0
- package/dist/cli/chunk-ZTLZO42A.js.map +1 -0
- package/dist/cli/code-F4KJOE3K.js +151 -0
- package/dist/cli/code-F4KJOE3K.js.map +1 -0
- package/dist/cli/commands-JWT2MWVH.js +352 -0
- package/dist/cli/commands-JWT2MWVH.js.map +1 -0
- package/dist/cli/commit-RPZBOZS2.js +288 -0
- package/dist/cli/commit-RPZBOZS2.js.map +1 -0
- package/dist/cli/diff-NTEHCSDW.js +145 -0
- package/dist/cli/diff-NTEHCSDW.js.map +1 -0
- package/dist/cli/doctor-3TGB2NZN.js +19 -0
- package/dist/cli/doctor-3TGB2NZN.js.map +1 -0
- package/dist/cli/events-P27CX7LN.js +338 -0
- package/dist/cli/events-P27CX7LN.js.map +1 -0
- package/dist/cli/index.js +80 -33693
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-ARTNQ24O.js +266 -0
- package/dist/cli/mcp-ARTNQ24O.js.map +1 -0
- package/dist/cli/mcp-browse-HLO2ENDL.js +163 -0
- package/dist/cli/mcp-browse-HLO2ENDL.js.map +1 -0
- package/dist/cli/mcp-inspect-T2HBR22P.js +103 -0
- package/dist/cli/mcp-inspect-T2HBR22P.js.map +1 -0
- package/dist/cli/{prompt-XHICFAYN.js → prompt-V47QKSAR.js} +3 -2
- package/dist/cli/prompt-V47QKSAR.js.map +1 -0
- package/dist/cli/prune-sessions-ERL6B4G5.js +42 -0
- package/dist/cli/prune-sessions-ERL6B4G5.js.map +1 -0
- package/dist/cli/replay-TMJASRC4.js +273 -0
- package/dist/cli/replay-TMJASRC4.js.map +1 -0
- package/dist/cli/run-JMEOTQCG.js +215 -0
- package/dist/cli/run-JMEOTQCG.js.map +1 -0
- package/dist/cli/server-SYC3OVOP.js +2967 -0
- package/dist/cli/server-SYC3OVOP.js.map +1 -0
- package/dist/cli/sessions-MOJAALJI.js +102 -0
- package/dist/cli/sessions-MOJAALJI.js.map +1 -0
- package/dist/cli/setup-CCJZAWTY.js +404 -0
- package/dist/cli/setup-CCJZAWTY.js.map +1 -0
- package/dist/cli/stats-5RJCATCE.js +12 -0
- package/dist/cli/stats-5RJCATCE.js.map +1 -0
- package/dist/cli/update-4TJWRUIN.js +90 -0
- package/dist/cli/update-4TJWRUIN.js.map +1 -0
- package/dist/cli/version-3MYFE4G6.js +29 -0
- package/dist/cli/version-3MYFE4G6.js.map +1 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +493 -89
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-VWFJNLIK.js +0 -1031
- package/dist/cli/chunk-VWFJNLIK.js.map +0 -1
- /package/dist/cli/{prompt-XHICFAYN.js.map → chat-EIFLHBZ6.js.map} +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
chatCommand
|
|
4
|
+
} from "./chunk-LVQX5KGF.js";
|
|
5
|
+
import "./chunk-BQNUJJN7.js";
|
|
6
|
+
import "./chunk-RFX7TYVV.js";
|
|
7
|
+
import "./chunk-Q5GRLZJF.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-EIFLHBZ6.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":[]}
|