luckerr 0.41.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/README.md +267 -0
- package/README.zh-CN.md +237 -0
- package/dashboard/app.css +3022 -0
- package/dashboard/dist/app.js +30137 -0
- package/dashboard/dist/app.js.map +1 -0
- package/dashboard/dist/vendor-hljs.css +10 -0
- package/dashboard/dist/vendor-uplot.css +1 -0
- package/dashboard/index.html +19 -0
- package/data/deepseek-tokenizer.json.gz +0 -0
- package/dist/cli/acp-EOOAI4F5.js +712 -0
- package/dist/cli/acp-EOOAI4F5.js.map +1 -0
- package/dist/cli/chat-7J6GJXL2.js +51 -0
- package/dist/cli/chat-7J6GJXL2.js.map +1 -0
- package/dist/cli/chunk-2425HK6U.js +54 -0
- package/dist/cli/chunk-2425HK6U.js.map +1 -0
- package/dist/cli/chunk-25T6CVUP.js +172 -0
- package/dist/cli/chunk-25T6CVUP.js.map +1 -0
- package/dist/cli/chunk-2UQP6H6T.js +31 -0
- package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
- package/dist/cli/chunk-56OAJILV.js +47 -0
- package/dist/cli/chunk-56OAJILV.js.map +1 -0
- package/dist/cli/chunk-5FTI4KXH.js +150 -0
- package/dist/cli/chunk-5FTI4KXH.js.map +1 -0
- package/dist/cli/chunk-5TWQD73O.js +2846 -0
- package/dist/cli/chunk-5TWQD73O.js.map +1 -0
- package/dist/cli/chunk-653BOCMK.js +40 -0
- package/dist/cli/chunk-653BOCMK.js.map +1 -0
- package/dist/cli/chunk-6ALJTWWQ.js +2663 -0
- package/dist/cli/chunk-6ALJTWWQ.js.map +1 -0
- package/dist/cli/chunk-6DRKA2IL.js +341 -0
- package/dist/cli/chunk-6DRKA2IL.js.map +1 -0
- package/dist/cli/chunk-6LV63NJV.js +634 -0
- package/dist/cli/chunk-6LV63NJV.js.map +1 -0
- package/dist/cli/chunk-74EX7SUH.js +25293 -0
- package/dist/cli/chunk-74EX7SUH.js.map +1 -0
- package/dist/cli/chunk-74U5RKTX.js +60611 -0
- package/dist/cli/chunk-74U5RKTX.js.map +1 -0
- package/dist/cli/chunk-ANJSUESV.js +143 -0
- package/dist/cli/chunk-ANJSUESV.js.map +1 -0
- package/dist/cli/chunk-DB2Z3DKZ.js +54 -0
- package/dist/cli/chunk-DB2Z3DKZ.js.map +1 -0
- package/dist/cli/chunk-DDIH3ZAA.js +400 -0
- package/dist/cli/chunk-DDIH3ZAA.js.map +1 -0
- package/dist/cli/chunk-ELN3Z3B2.js +621 -0
- package/dist/cli/chunk-ELN3Z3B2.js.map +1 -0
- package/dist/cli/chunk-F6BSQJGV.js +200 -0
- package/dist/cli/chunk-F6BSQJGV.js.map +1 -0
- package/dist/cli/chunk-FET2UAG5.js +246 -0
- package/dist/cli/chunk-FET2UAG5.js.map +1 -0
- package/dist/cli/chunk-FFJ342IJ.js +190 -0
- package/dist/cli/chunk-FFJ342IJ.js.map +1 -0
- package/dist/cli/chunk-GB3247B6.js +130 -0
- package/dist/cli/chunk-GB3247B6.js.map +1 -0
- package/dist/cli/chunk-HC2J4U3G.js +373 -0
- package/dist/cli/chunk-HC2J4U3G.js.map +1 -0
- package/dist/cli/chunk-HRUZAIHQ.js +42 -0
- package/dist/cli/chunk-HRUZAIHQ.js.map +1 -0
- package/dist/cli/chunk-J3ZJFUDL.js +308 -0
- package/dist/cli/chunk-J3ZJFUDL.js.map +1 -0
- package/dist/cli/chunk-J5XJHLWM.js +55 -0
- package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
- package/dist/cli/chunk-JFGLMRZ6.js +160 -0
- package/dist/cli/chunk-JFGLMRZ6.js.map +1 -0
- package/dist/cli/chunk-JMBMLOBP.js +26 -0
- package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
- package/dist/cli/chunk-JMWHXZEL.js +551 -0
- package/dist/cli/chunk-JMWHXZEL.js.map +1 -0
- package/dist/cli/chunk-KEQGPJBO.js +209 -0
- package/dist/cli/chunk-KEQGPJBO.js.map +1 -0
- package/dist/cli/chunk-M4K6U37F.js +232 -0
- package/dist/cli/chunk-M4K6U37F.js.map +1 -0
- package/dist/cli/chunk-MIJI2WMN.js +95 -0
- package/dist/cli/chunk-MIJI2WMN.js.map +1 -0
- package/dist/cli/chunk-MPAO3JNR.js +128 -0
- package/dist/cli/chunk-MPAO3JNR.js.map +1 -0
- package/dist/cli/chunk-PZOFBEDC.js +873 -0
- package/dist/cli/chunk-PZOFBEDC.js.map +1 -0
- package/dist/cli/chunk-RAILYQLN.js +46 -0
- package/dist/cli/chunk-RAILYQLN.js.map +1 -0
- package/dist/cli/chunk-RR35VQVT.js +90 -0
- package/dist/cli/chunk-RR35VQVT.js.map +1 -0
- package/dist/cli/chunk-RRA7VPW4.js +417 -0
- package/dist/cli/chunk-RRA7VPW4.js.map +1 -0
- package/dist/cli/chunk-RU36QVN3.js +452 -0
- package/dist/cli/chunk-RU36QVN3.js.map +1 -0
- package/dist/cli/chunk-RUBIINXR.js +1819 -0
- package/dist/cli/chunk-RUBIINXR.js.map +1 -0
- package/dist/cli/chunk-S4XVGLRW.js +499 -0
- package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
- package/dist/cli/chunk-TUK7OWJA.js +51 -0
- package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
- package/dist/cli/chunk-VALDDV76.js +580 -0
- package/dist/cli/chunk-VALDDV76.js.map +1 -0
- package/dist/cli/chunk-WQOGPYGN.js +11390 -0
- package/dist/cli/chunk-WQOGPYGN.js.map +1 -0
- package/dist/cli/chunk-WREKDFXT.js +34320 -0
- package/dist/cli/chunk-WREKDFXT.js.map +1 -0
- package/dist/cli/chunk-Y7XQU2EL.js +270 -0
- package/dist/cli/chunk-Y7XQU2EL.js.map +1 -0
- package/dist/cli/chunk-YBVCZJU4.js +54 -0
- package/dist/cli/chunk-YBVCZJU4.js.map +1 -0
- package/dist/cli/chunk-YLIHDXUQ.js +749 -0
- package/dist/cli/chunk-YLIHDXUQ.js.map +1 -0
- package/dist/cli/chunk-YV5XXFD7.js +767 -0
- package/dist/cli/chunk-YV5XXFD7.js.map +1 -0
- package/dist/cli/chunk-ZRCNIYRQ.js +101 -0
- package/dist/cli/chunk-ZRCNIYRQ.js.map +1 -0
- package/dist/cli/code-CRKVCMFZ.js +155 -0
- package/dist/cli/code-CRKVCMFZ.js.map +1 -0
- package/dist/cli/commands-QLMD3T7B.js +356 -0
- package/dist/cli/commands-QLMD3T7B.js.map +1 -0
- package/dist/cli/commit-53PP32NC.js +293 -0
- package/dist/cli/commit-53PP32NC.js.map +1 -0
- package/dist/cli/desktop-R6W5CLJ5.js +1046 -0
- package/dist/cli/desktop-R6W5CLJ5.js.map +1 -0
- package/dist/cli/devtools-YECO25QO.js +3719 -0
- package/dist/cli/devtools-YECO25QO.js.map +1 -0
- package/dist/cli/diff-LYNRCJZE.js +166 -0
- package/dist/cli/diff-LYNRCJZE.js.map +1 -0
- package/dist/cli/doctor-5IBP4R5J.js +28 -0
- package/dist/cli/doctor-5IBP4R5J.js.map +1 -0
- package/dist/cli/events-QN6KLN2V.js +340 -0
- package/dist/cli/events-QN6KLN2V.js.map +1 -0
- package/dist/cli/index.js +3500 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mcp-FGKEH7RG.js +277 -0
- package/dist/cli/mcp-FGKEH7RG.js.map +1 -0
- package/dist/cli/mcp-browse-YCND4NWT.js +178 -0
- package/dist/cli/mcp-browse-YCND4NWT.js.map +1 -0
- package/dist/cli/mcp-inspect-V34J3VX5.js +143 -0
- package/dist/cli/mcp-inspect-V34J3VX5.js.map +1 -0
- package/dist/cli/package.json +3 -0
- package/dist/cli/prompt-I775PNKT.js +16 -0
- package/dist/cli/prompt-I775PNKT.js.map +1 -0
- package/dist/cli/prune-sessions-KGIIYD3P.js +44 -0
- package/dist/cli/prune-sessions-KGIIYD3P.js.map +1 -0
- package/dist/cli/replay-RDXLUAOE.js +292 -0
- package/dist/cli/replay-RDXLUAOE.js.map +1 -0
- package/dist/cli/run-RCAC2RYW.js +223 -0
- package/dist/cli/run-RCAC2RYW.js.map +1 -0
- package/dist/cli/server-FFU6TLYJ.js +3658 -0
- package/dist/cli/server-FFU6TLYJ.js.map +1 -0
- package/dist/cli/sessions-QT26MQAE.js +107 -0
- package/dist/cli/sessions-QT26MQAE.js.map +1 -0
- package/dist/cli/setup-VV4WKXHV.js +767 -0
- package/dist/cli/setup-VV4WKXHV.js.map +1 -0
- package/dist/cli/stats-JVZPQWAN.js +15 -0
- package/dist/cli/stats-JVZPQWAN.js.map +1 -0
- package/dist/cli/update-KYI3OVJP.js +15 -0
- package/dist/cli/update-KYI3OVJP.js.map +1 -0
- package/dist/cli/version-ANYORXTI.js +34 -0
- package/dist/cli/version-ANYORXTI.js.map +1 -0
- package/dist/index.d.ts +2557 -0
- package/dist/index.js +15000 -0
- package/dist/index.js.map +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/mcp-inspect.ts"],"sourcesContent":["import { mcpEnvFor, readConfig } from \"../../config.js\";\nimport { McpClient } from \"../../mcp/client.js\";\nimport { inspectMcpServer } from \"../../mcp/inspect.js\";\nimport type { InspectionReport } from \"../../mcp/inspect.js\";\nimport { preflightStdioSpec } from \"../../mcp/preflight.js\";\nimport { parseMcpSpec } from \"../../mcp/spec.js\";\nimport { buildTransportFromSpec } from \"../../mcp/transport-from-spec.js\";\n\nexport interface McpInspectOptions {\n /** The raw --mcp spec string (e.g. `fs=npx -y @modelcontextprotocol/server-filesystem .`). */\n spec: string;\n /** Emit JSON on stdout instead of the human-readable table. */\n json?: boolean;\n}\n\nexport async function mcpInspectCommand(opts: McpInspectOptions): Promise<void> {\n const spec = parseMcpSpec(opts.spec);\n if (spec.transport === \"stdio\") preflightStdioSpec(spec);\n const transport = buildTransportFromSpec(spec, { env: mcpEnvFor(spec.name, readConfig()) });\n const client = new McpClient({ transport });\n try {\n await client.initialize();\n const report = await inspectMcpServer(client);\n if (opts.json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(formatReport(spec.name ?? \"(anon)\", report));\n }\n } finally {\n await client.close();\n }\n}\n\nexport function formatMcpInspectFailure(err: unknown): string {\n const error = err instanceof Error ? err : new Error(String(err));\n const message = error.message;\n const code = (error as NodeJS.ErrnoException).code;\n\n if (code === \"ENOENT\") {\n const command = message.match(/^spawn\\s+([^\\s]+)\\s+ENOENT$/)?.[1] ?? \"the command\";\n return `${message} — try: install or verify \\`${command}\\`, then check the MCP spec's command spelling`;\n }\n\n if (code === \"ECONNREFUSED\") {\n const target = message.match(/\\b(https?:\\/\\/\\S+|\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+|localhost:\\d+)\\b/i)?.[1];\n return `${message} — try: confirm ${target ?? \"the MCP server\"} is running and the host/port match the spec`;\n }\n\n if (code === \"ENOTFOUND\" || code === \"EAI_AGAIN\") {\n return `${message} — try: confirm the hostname is spelled correctly and DNS resolution is working (check your network/VPN)`;\n }\n\n if (code === \"ECONNRESET\") {\n return `${message} — try: retry the request; if it keeps happening, check the server's logs for crashes or rate limits`;\n }\n\n if (code === \"ETIMEDOUT\") {\n return `${message} — try: confirm the host is reachable and no firewall/proxy is blocking the port`;\n }\n\n if (\n code === \"CERT_HAS_EXPIRED\" ||\n code === \"DEPTH_ZERO_SELF_SIGNED_CERT\" ||\n code === \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\" ||\n code === \"SELF_SIGNED_CERT_IN_CHAIN\"\n ) {\n return `${message} — try: renew or trust the server's TLS certificate, or point the spec at an endpoint with a valid cert`;\n }\n\n // HTTP non-2xx from SSE / Streamable HTTP transports. Match the three\n // exact shapes those transports emit and surface an auth/endpoint hint.\n const httpStatus = matchTransportHttpStatus(message);\n if (httpStatus !== null) {\n return `${message}${hintForHttpStatus(httpStatus)}`;\n }\n\n if (/^MCP request initialize \\(id=\\d+\\) timed out after \\d+ms$/.test(message)) {\n return `${message} — try: confirm the target speaks MCP and completes the handshake before the request timeout`;\n }\n\n if (/^(empty MCP spec|MCP spec \".*\" has name but no command)/.test(message)) {\n return `${message} — try: pass \\`name=command args\\` or an http(s):// URL`;\n }\n\n return message;\n}\n\nfunction matchTransportHttpStatus(message: string): number | null {\n // src/mcp/sse.ts: `SSE handshake <url> → <status> <statusText>`\n // src/mcp/sse.ts: `MCP SSE POST <url> failed: <status> <statusText>`\n // src/mcp/streamable-http.ts: `MCP Streamable HTTP POST <url> → <status> <statusText>...`\n const m =\n message.match(/^SSE handshake \\S+ → (\\d{3})\\b/) ??\n message.match(/^MCP SSE POST \\S+ failed: (\\d{3})\\b/) ??\n message.match(/^MCP Streamable HTTP POST \\S+ → (\\d{3})\\b/);\n return m ? Number(m[1]) : null;\n}\n\nfunction hintForHttpStatus(status: number): string {\n if (status === 401) {\n return \" — try: check the spec's auth header (e.g. `Authorization: Bearer …`) or confirm the token isn't expired\";\n }\n if (status === 403) {\n return \" — try: confirm the credentials have permission to reach this MCP endpoint\";\n }\n if (status === 404) {\n return \" — try: confirm the endpoint path in the spec matches what the server actually exposes\";\n }\n if (status >= 500 && status <= 599) {\n return \" — try: retry shortly; if the failure persists, check the MCP server's logs\";\n }\n return \"\";\n}\n\nfunction formatReport(nsName: string, r: InspectionReport): string {\n const lines: string[] = [];\n lines.push(`MCP server [${nsName}]`);\n lines.push(\n ` server ${r.serverInfo.name || \"(unknown)\"}${r.serverInfo.version ? ` v${r.serverInfo.version}` : \"\"}`,\n );\n lines.push(` protocol ${r.protocolVersion}`);\n const capKeys = Object.keys(r.capabilities);\n lines.push(` caps ${capKeys.length > 0 ? capKeys.join(\", \") : \"(none advertised)\"}`);\n if (r.instructions) {\n lines.push(` notes ${r.instructions.trim().slice(0, 200)}`);\n }\n lines.push(\"\");\n lines.push(formatSection(\"Tools\", r.tools, toolLine));\n lines.push(formatSection(\"Resources\", r.resources, resourceLine));\n lines.push(formatSection(\"Prompts\", r.prompts, promptLine));\n return lines.join(\"\\n\");\n}\n\nfunction formatSection<T>(\n title: string,\n section: { supported: true; items: T[] } | { supported: false; reason: string },\n render: (item: T) => string,\n): string {\n if (!section.supported) {\n return `${title}: (not supported — ${section.reason})`;\n }\n if (section.items.length === 0) {\n return `${title}: (none)`;\n }\n const lines = [`${title} (${section.items.length}):`];\n for (const item of section.items) lines.push(` ${render(item)}`);\n return lines.join(\"\\n\");\n}\n\nfunction toolLine(t: { name: string; description?: string }): string {\n const desc = t.description ? ` — ${oneLine(t.description, 80)}` : \"\";\n return `· ${t.name}${desc}`;\n}\n\nfunction resourceLine(r: { uri: string; name: string; mimeType?: string }): string {\n const mime = r.mimeType ? ` [${r.mimeType}]` : \"\";\n return `· ${r.name}${mime} ${r.uri}`;\n}\n\nfunction promptLine(p: {\n name: string;\n description?: string;\n arguments?: Array<{ name: string; required?: boolean }>;\n}): string {\n const argPart =\n p.arguments && p.arguments.length > 0\n ? ` (${p.arguments.map((a) => (a.required ? a.name : `${a.name}?`)).join(\", \")})`\n : \"\";\n const desc = p.description ? ` — ${oneLine(p.description, 80)}` : \"\";\n return `· ${p.name}${argPart}${desc}`;\n}\n\nfunction oneLine(s: string, max: number): string {\n const flat = s.replace(/\\s+/g, \" \").trim();\n return flat.length <= max ? flat : `${flat.slice(0, max - 1)}…`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
|
+
import {
|
|
4
|
+
CODE_SYSTEM_PROMPT,
|
|
5
|
+
codeSystemBase,
|
|
6
|
+
codeSystemPrompt
|
|
7
|
+
} from "./chunk-6LV63NJV.js";
|
|
8
|
+
import "./chunk-VALDDV76.js";
|
|
9
|
+
import "./chunk-6ALJTWWQ.js";
|
|
10
|
+
import "./chunk-TUK7OWJA.js";
|
|
11
|
+
export {
|
|
12
|
+
CODE_SYSTEM_PROMPT,
|
|
13
|
+
codeSystemBase,
|
|
14
|
+
codeSystemPrompt
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=prompt-I775PNKT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
|
+
import {
|
|
4
|
+
listSessions,
|
|
5
|
+
pruneStaleSessions
|
|
6
|
+
} from "./chunk-Y7XQU2EL.js";
|
|
7
|
+
import "./chunk-TUK7OWJA.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/commands/prune-sessions.ts
|
|
10
|
+
function pruneSessionsCommand(opts) {
|
|
11
|
+
const days = opts.days ?? 90;
|
|
12
|
+
if (!Number.isFinite(days) || days < 1) {
|
|
13
|
+
console.error(`--days must be a positive integer (got ${days}).`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
if (opts.dryRun) {
|
|
17
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
18
|
+
const stale = listSessions().filter((s) => s.mtime.getTime() < cutoff);
|
|
19
|
+
if (stale.length === 0) {
|
|
20
|
+
console.log(`no sessions idle \u2265${days} days. Nothing would be pruned.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(`would prune ${stale.length} session(s) idle \u2265${days} days:`);
|
|
24
|
+
for (const s of stale) {
|
|
25
|
+
console.log(` ${s.name}`);
|
|
26
|
+
}
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log("re-run without --dry-run to actually delete.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const removed = pruneStaleSessions(days);
|
|
32
|
+
if (removed.length === 0) {
|
|
33
|
+
console.log(`no sessions idle \u2265${days} days. Nothing pruned.`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(`pruned ${removed.length} session(s) idle \u2265${days} days:`);
|
|
37
|
+
for (const name of removed) {
|
|
38
|
+
console.log(` ${name}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
pruneSessionsCommand
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=prune-sessions-KGIIYD3P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/prune-sessions.ts"],"sourcesContent":["import { listSessions, pruneStaleSessions } from \"../../memory/session.js\";\n\nexport interface PruneSessionsOptions {\n days?: number;\n dryRun?: boolean;\n}\n\nexport function pruneSessionsCommand(opts: PruneSessionsOptions): void {\n const days = opts.days ?? 90;\n if (!Number.isFinite(days) || days < 1) {\n console.error(`--days must be a positive integer (got ${days}).`);\n process.exit(1);\n }\n if (opts.dryRun) {\n const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;\n const stale = listSessions().filter((s) => s.mtime.getTime() < cutoff);\n if (stale.length === 0) {\n console.log(`no sessions idle ≥${days} days. Nothing would be pruned.`);\n return;\n }\n console.log(`would prune ${stale.length} session(s) idle ≥${days} days:`);\n for (const s of stale) {\n console.log(` ${s.name}`);\n }\n console.log(\"\");\n console.log(\"re-run without --dry-run to actually delete.\");\n return;\n }\n const removed = pruneStaleSessions(days);\n if (removed.length === 0) {\n console.log(`no sessions idle ≥${days} days. Nothing pruned.`);\n return;\n }\n console.log(`pruned ${removed.length} session(s) idle ≥${days} days:`);\n for (const name of removed) {\n console.log(` ${name}`);\n }\n}\n"],"mappings":";;;;;;;;;AAOO,SAAS,qBAAqB,MAAkC;AACrE,QAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,GAAG;AACtC,YAAQ,MAAM,0CAA0C,IAAI,IAAI;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,KAAK,QAAQ;AACf,UAAM,SAAS,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK;AAClD,UAAM,QAAQ,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,QAAQ,IAAI,MAAM;AACrE,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,IAAI,0BAAqB,IAAI,iCAAiC;AACtE;AAAA,IACF;AACA,YAAQ,IAAI,eAAe,MAAM,MAAM,0BAAqB,IAAI,QAAQ;AACxE,eAAW,KAAK,OAAO;AACrB,cAAQ,IAAI,KAAK,EAAE,IAAI,EAAE;AAAA,IAC3B;AACA,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,8CAA8C;AAC1D;AAAA,EACF;AACA,QAAM,UAAU,mBAAmB,IAAI;AACvC,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,IAAI,0BAAqB,IAAI,wBAAwB;AAC7D;AAAA,EACF;AACA,UAAQ,IAAI,UAAU,QAAQ,MAAM,0BAAqB,IAAI,QAAQ;AACrE,aAAW,QAAQ,SAAS;AAC1B,YAAQ,IAAI,KAAK,IAAI,EAAE;AAAA,EACzB;AACF;","names":[]}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
|
+
import {
|
|
4
|
+
RecordView
|
|
5
|
+
} from "./chunk-YBVCZJU4.js";
|
|
6
|
+
import {
|
|
7
|
+
Bar,
|
|
8
|
+
ChromeRule,
|
|
9
|
+
stringWidth
|
|
10
|
+
} from "./chunk-RR35VQVT.js";
|
|
11
|
+
import {
|
|
12
|
+
computeCumulativeStats,
|
|
13
|
+
groupRecordsByTurn,
|
|
14
|
+
replayFromFile
|
|
15
|
+
} from "./chunk-FFJ342IJ.js";
|
|
16
|
+
import {
|
|
17
|
+
COLOR,
|
|
18
|
+
GRADIENT
|
|
19
|
+
} from "./chunk-JFGLMRZ6.js";
|
|
20
|
+
import {
|
|
21
|
+
Box_default,
|
|
22
|
+
Static,
|
|
23
|
+
Text,
|
|
24
|
+
render_default,
|
|
25
|
+
require_react,
|
|
26
|
+
use_app_default,
|
|
27
|
+
use_input_default,
|
|
28
|
+
use_stdout_default
|
|
29
|
+
} from "./chunk-WREKDFXT.js";
|
|
30
|
+
import "./chunk-DDIH3ZAA.js";
|
|
31
|
+
import "./chunk-25T6CVUP.js";
|
|
32
|
+
import {
|
|
33
|
+
t
|
|
34
|
+
} from "./chunk-5TWQD73O.js";
|
|
35
|
+
import {
|
|
36
|
+
formatBalance,
|
|
37
|
+
formatCost
|
|
38
|
+
} from "./chunk-6ALJTWWQ.js";
|
|
39
|
+
import "./chunk-ANJSUESV.js";
|
|
40
|
+
import "./chunk-JMWHXZEL.js";
|
|
41
|
+
import {
|
|
42
|
+
__toESM
|
|
43
|
+
} from "./chunk-TUK7OWJA.js";
|
|
44
|
+
|
|
45
|
+
// src/cli/commands/replay.ts
|
|
46
|
+
var import_react3 = __toESM(require_react(), 1);
|
|
47
|
+
|
|
48
|
+
// src/cli/ui/ReplayApp.tsx
|
|
49
|
+
var import_react2 = __toESM(require_react(), 1);
|
|
50
|
+
|
|
51
|
+
// src/cli/ui/StatsPanel.tsx
|
|
52
|
+
import { basename } from "path";
|
|
53
|
+
var import_react = __toESM(require_react(), 1);
|
|
54
|
+
var COLD_START_TURNS = 3;
|
|
55
|
+
function StatsPanel({
|
|
56
|
+
summary,
|
|
57
|
+
planMode,
|
|
58
|
+
editMode,
|
|
59
|
+
balance,
|
|
60
|
+
updateAvailable,
|
|
61
|
+
proArmed,
|
|
62
|
+
escalated,
|
|
63
|
+
budgetUsd,
|
|
64
|
+
rootDir,
|
|
65
|
+
sessionName
|
|
66
|
+
}) {
|
|
67
|
+
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
68
|
+
return /* @__PURE__ */ import_react.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react.default.createElement(
|
|
69
|
+
ChromeRow,
|
|
70
|
+
{
|
|
71
|
+
editMode,
|
|
72
|
+
planMode,
|
|
73
|
+
proArmed: proArmed ?? false,
|
|
74
|
+
escalated: escalated ?? false,
|
|
75
|
+
summary,
|
|
76
|
+
coldStart,
|
|
77
|
+
rootDir,
|
|
78
|
+
sessionName: sessionName ?? null,
|
|
79
|
+
updateAvailable,
|
|
80
|
+
balance: balance ?? null
|
|
81
|
+
}
|
|
82
|
+
), /* @__PURE__ */ import_react.default.createElement(ChromeRule, null), budgetUsd !== null && budgetUsd !== void 0 ? /* @__PURE__ */ import_react.default.createElement(BudgetRow, { spent: summary.totalCostUsd, cap: budgetUsd }) : null);
|
|
83
|
+
}
|
|
84
|
+
function ChromeRow({
|
|
85
|
+
editMode,
|
|
86
|
+
planMode,
|
|
87
|
+
proArmed,
|
|
88
|
+
escalated,
|
|
89
|
+
summary,
|
|
90
|
+
coldStart,
|
|
91
|
+
rootDir,
|
|
92
|
+
sessionName,
|
|
93
|
+
updateAvailable,
|
|
94
|
+
balance
|
|
95
|
+
}) {
|
|
96
|
+
const modePill = pickModePill(planMode, editMode);
|
|
97
|
+
const proLabel = t("statsPanel.pro");
|
|
98
|
+
const proPill = escalated ? { label: proLabel, color: COLOR.err } : proArmed ? { label: proLabel, color: COLOR.warn } : null;
|
|
99
|
+
const projectName = rootDir ? basename(rootDir) : null;
|
|
100
|
+
const cachePct = (summary.cacheHitRatio * 100).toFixed(1);
|
|
101
|
+
const cacheColor = summary.cacheHitRatio >= 0.7 ? COLOR.ok : summary.cacheHitRatio >= 0.4 ? COLOR.warn : COLOR.err;
|
|
102
|
+
const balanceLabel = balance ? `[${formatBalance(balance.total, balance.currency, { label: true })}]` : "";
|
|
103
|
+
const costLabel = `[${formatCost(summary.totalCostUsd, balance?.currency)}]`;
|
|
104
|
+
const cacheLabel = "[c \u25B0\u25B0\u25B0\u25B0\u25B0\u25B0 100%]";
|
|
105
|
+
const updateLabel = updateAvailable ? `\u2191 ${updateAvailable}` : "";
|
|
106
|
+
const { stdout } = use_stdout_default();
|
|
107
|
+
const cols = (stdout?.columns ?? 80) - 2;
|
|
108
|
+
const SEP_DOT = stringWidth(" \xB7 ");
|
|
109
|
+
const SEP_ARROW = stringWidth(" \u203A ");
|
|
110
|
+
const GAP = 2;
|
|
111
|
+
const fixedLeft = stringWidth("\u25C8 luckerr") + (projectName ? SEP_DOT + stringWidth(projectName) : 0);
|
|
112
|
+
const modeW = modePill ? GAP + stringWidth(`[${modePill.label}]`) : 0;
|
|
113
|
+
const proW = proPill ? GAP + stringWidth(`[${proPill.label}]`) : 0;
|
|
114
|
+
const fixedRight = modeW + proW + stringWidth(costLabel);
|
|
115
|
+
let budget = cols - fixedLeft - fixedRight;
|
|
116
|
+
const balW = balance ? GAP + stringWidth(balanceLabel) : 0;
|
|
117
|
+
const cacheW = GAP + stringWidth(cacheLabel);
|
|
118
|
+
const sessionW = sessionName ? SEP_ARROW + stringWidth(sessionName) : 0;
|
|
119
|
+
const updateW = updateLabel ? GAP + stringWidth(updateLabel) : 0;
|
|
120
|
+
const showBalance = balW > 0 && budget >= balW;
|
|
121
|
+
if (showBalance) budget -= balW;
|
|
122
|
+
const showCache = budget >= cacheW;
|
|
123
|
+
if (showCache) budget -= cacheW;
|
|
124
|
+
const showSession = sessionW > 0 && budget >= sessionW;
|
|
125
|
+
if (showSession) budget -= sessionW;
|
|
126
|
+
const showUpdate = updateW > 0 && budget >= updateW;
|
|
127
|
+
if (showUpdate) budget -= updateW;
|
|
128
|
+
return /* @__PURE__ */ import_react.default.createElement(Box_default, null, /* @__PURE__ */ import_react.default.createElement(Text, { bold: true, color: GRADIENT[0] }, "\u25C8 "), /* @__PURE__ */ import_react.default.createElement(Text, { color: COLOR.brand, bold: true }, "luckerr"), projectName ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, { color: COLOR.info, dimColor: true }, " \xB7 "), /* @__PURE__ */ import_react.default.createElement(Text, null, projectName), showSession && sessionName ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, { color: COLOR.info, dimColor: true }, " \u203A "), /* @__PURE__ */ import_react.default.createElement(Text, { color: COLOR.info }, sessionName)) : null) : null, /* @__PURE__ */ import_react.default.createElement(Box_default, { flexGrow: 1 }), showUpdate ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, { color: COLOR.warn, bold: true }, updateLabel), /* @__PURE__ */ import_react.default.createElement(Text, null, " ")) : null, modePill ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, { color: modePill.color, bold: true }, `[${modePill.label}]`), /* @__PURE__ */ import_react.default.createElement(Text, null, " ")) : null, proPill ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, { color: proPill.color, bold: true }, `[${proPill.label}]`), /* @__PURE__ */ import_react.default.createElement(Text, null, " ")) : null, /* @__PURE__ */ import_react.default.createElement(
|
|
129
|
+
Text,
|
|
130
|
+
{
|
|
131
|
+
color: summary.turns === 0 || coldStart ? COLOR.info : sessionCostColor(summary.totalCostUsd),
|
|
132
|
+
bold: summary.turns > 0 && !coldStart,
|
|
133
|
+
dimColor: summary.turns === 0 || coldStart
|
|
134
|
+
},
|
|
135
|
+
costLabel
|
|
136
|
+
), showBalance && balance ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, null, " "), /* @__PURE__ */ import_react.default.createElement(Text, { color: balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok }, balanceLabel)) : null, showCache ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(Text, null, " "), /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, "["), /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, "c "), /* @__PURE__ */ import_react.default.createElement(
|
|
137
|
+
Bar,
|
|
138
|
+
{
|
|
139
|
+
ratio: summary.cacheHitRatio,
|
|
140
|
+
color: coldStart ? COLOR.info : cacheColor,
|
|
141
|
+
cells: 6,
|
|
142
|
+
dim: coldStart
|
|
143
|
+
}
|
|
144
|
+
), /* @__PURE__ */ import_react.default.createElement(Text, null, " "), /* @__PURE__ */ import_react.default.createElement(Text, { color: coldStart ? void 0 : cacheColor, dimColor: coldStart }, coldStart && summary.turns === 0 ? "\u2014" : `${cachePct}%`), /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, "]")) : null);
|
|
145
|
+
}
|
|
146
|
+
function pickModePill(planMode, editMode) {
|
|
147
|
+
if (planMode) return { label: t("statsPanel.modePlan"), color: COLOR.err };
|
|
148
|
+
if (editMode === "yolo") return { label: t("statsPanel.modeYolo"), color: COLOR.err };
|
|
149
|
+
if (editMode === "auto") return { label: t("statsPanel.modeAuto"), color: COLOR.primary };
|
|
150
|
+
if (editMode === "review") return { label: t("statsPanel.modeReview"), color: COLOR.info };
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function BudgetRow({ spent, cap }) {
|
|
154
|
+
const pct = Math.max(0, spent / cap * 100);
|
|
155
|
+
const color = pct >= 100 ? "#f87171" : pct >= 80 ? "#fbbf24" : "#94a3b8";
|
|
156
|
+
return /* @__PURE__ */ import_react.default.createElement(Box_default, null, /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, t("statsPanel.budget")), /* @__PURE__ */ import_react.default.createElement(Text, { color }, `$${spent.toFixed(4)} / $${cap.toFixed(2)}`, /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, ` (${pct.toFixed(0)}%)`)));
|
|
157
|
+
}
|
|
158
|
+
function sessionCostColor(cost) {
|
|
159
|
+
if (cost <= 0) return void 0;
|
|
160
|
+
if (cost >= 5) return COLOR.err;
|
|
161
|
+
if (cost >= 0.5) return COLOR.warn;
|
|
162
|
+
return COLOR.ok;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/cli/ui/ReplayApp.tsx
|
|
166
|
+
function ReplayApp({ meta, pages }) {
|
|
167
|
+
const { exit } = use_app_default();
|
|
168
|
+
const maxIdx = Math.max(0, pages.length - 1);
|
|
169
|
+
const [idx, setIdx] = (0, import_react2.useState)(maxIdx);
|
|
170
|
+
use_input_default((input, key) => {
|
|
171
|
+
if (input === "q" || key.ctrl && input === "c") {
|
|
172
|
+
exit();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (input === "j" || key.downArrow || input === " " || key.return) {
|
|
176
|
+
setIdx((i) => Math.min(maxIdx, i + 1));
|
|
177
|
+
} else if (input === "k" || key.upArrow) {
|
|
178
|
+
setIdx((i) => Math.max(0, i - 1));
|
|
179
|
+
} else if (input === "g") {
|
|
180
|
+
setIdx(0);
|
|
181
|
+
} else if (input === "G") {
|
|
182
|
+
setIdx(maxIdx);
|
|
183
|
+
} else if (input === "h" || key.leftArrow) {
|
|
184
|
+
setIdx(0);
|
|
185
|
+
} else if (input === "l" || key.rightArrow) {
|
|
186
|
+
setIdx(maxIdx);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
const cumStats = (0, import_react2.useMemo)(() => computeCumulativeStats(pages, idx), [pages, idx]);
|
|
190
|
+
const summary = {
|
|
191
|
+
turns: cumStats.turns,
|
|
192
|
+
totalCostUsd: cumStats.totalCostUsd,
|
|
193
|
+
totalInputCostUsd: cumStats.totalInputCostUsd,
|
|
194
|
+
totalOutputCostUsd: cumStats.totalOutputCostUsd,
|
|
195
|
+
claudeEquivalentUsd: cumStats.claudeEquivalentUsd,
|
|
196
|
+
savingsVsClaudePct: cumStats.savingsVsClaudePct,
|
|
197
|
+
cacheHitRatio: cumStats.cacheHitRatio,
|
|
198
|
+
// Replay is read-only — no live last-turn prompt tokens to show.
|
|
199
|
+
lastPromptTokens: 0,
|
|
200
|
+
lastTurnCostUsd: 0
|
|
201
|
+
};
|
|
202
|
+
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? t("replayApp.untracked") : t("replayApp.churned", { count: cumStats.prefixHashes.length });
|
|
203
|
+
const currentPage = pages[idx];
|
|
204
|
+
const progressLabel = pages.length === 0 ? t("replayApp.emptyTranscript") : t("replayApp.turnProgress", { current: idx + 1, total: pages.length });
|
|
205
|
+
return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react2.default.createElement(StatsPanel, { summary }), /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, { justifyContent: "space-between" }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ import_react2.default.createElement(Static, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ import_react2.default.createElement(RecordView, { key, rec })) : /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true, italic: true }, t("replayApp.noRecords"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "j"), "/", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "\u2193"), "/", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "k"), "/", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, "q"), " quit")));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/cli/commands/replay.ts
|
|
209
|
+
async function replayCommand(opts) {
|
|
210
|
+
const wantPrint = opts.print || !process.stdout.isTTY || opts.head !== void 0 || opts.tail !== void 0;
|
|
211
|
+
if (wantPrint) {
|
|
212
|
+
printReplay(opts);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const { parsed } = replayFromFile(opts.path);
|
|
216
|
+
const pages = groupRecordsByTurn(parsed.records);
|
|
217
|
+
const { waitUntilExit } = render_default(import_react3.default.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
218
|
+
exitOnCtrlC: true,
|
|
219
|
+
patchConsole: false
|
|
220
|
+
});
|
|
221
|
+
await waitUntilExit();
|
|
222
|
+
}
|
|
223
|
+
function printReplay(opts) {
|
|
224
|
+
const { parsed, stats } = replayFromFile(opts.path);
|
|
225
|
+
if (parsed.meta) {
|
|
226
|
+
const m = parsed.meta;
|
|
227
|
+
const bits = [`source=${m.source}`];
|
|
228
|
+
if (m.model) bits.push(`model=${m.model}`);
|
|
229
|
+
if (m.task) bits.push(`task=${m.task}`);
|
|
230
|
+
if (m.mode) bits.push(`mode=${m.mode}`);
|
|
231
|
+
if (m.repeat !== void 0) bits.push(`repeat=${m.repeat}`);
|
|
232
|
+
bits.push(`started=${m.startedAt}`);
|
|
233
|
+
console.log(`[meta] ${bits.join(" ")}`);
|
|
234
|
+
console.log("");
|
|
235
|
+
}
|
|
236
|
+
const records = sliceRecords(parsed.records, opts);
|
|
237
|
+
for (const rec of records) {
|
|
238
|
+
renderRecord(rec);
|
|
239
|
+
}
|
|
240
|
+
console.log("");
|
|
241
|
+
console.log("\u2500\u2500 summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
242
|
+
console.log(`model calls: ${stats.turns}`);
|
|
243
|
+
console.log(`user turns: ${stats.userTurns}`);
|
|
244
|
+
console.log(`tool calls: ${stats.toolCalls}`);
|
|
245
|
+
console.log(`cache hit: ${(stats.cacheHitRatio * 100).toFixed(1)}%`);
|
|
246
|
+
console.log(`cost: $${stats.totalCostUsd.toFixed(6)}`);
|
|
247
|
+
console.log(`claude equivalent: $${stats.claudeEquivalentUsd.toFixed(6)}`);
|
|
248
|
+
console.log(`savings vs claude: ${stats.savingsVsClaudePct.toFixed(1)}%`);
|
|
249
|
+
console.log(`models: ${stats.models.join(", ") || "\u2014"}`);
|
|
250
|
+
console.log(`prefix hashes: ${stats.prefixHashes.length} distinct`);
|
|
251
|
+
if (stats.prefixHashes.length === 1) {
|
|
252
|
+
console.log(` (byte-stable prefix: ${stats.prefixHashes[0]?.slice(0, 16)}\u2026)`);
|
|
253
|
+
} else if (stats.prefixHashes.length > 1) {
|
|
254
|
+
console.log(" (prefix churned \u2014 cache-hostile session)");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function sliceRecords(records, opts) {
|
|
258
|
+
if (opts.head !== void 0 && opts.head > 0) return records.slice(0, opts.head);
|
|
259
|
+
if (opts.tail !== void 0 && opts.tail > 0) return records.slice(-opts.tail);
|
|
260
|
+
return records;
|
|
261
|
+
}
|
|
262
|
+
function renderRecord(rec) {
|
|
263
|
+
const turn = `[t${rec.turn}]`;
|
|
264
|
+
if (rec.role === "user") {
|
|
265
|
+
console.log(`${turn} USER: ${oneLine(rec.content)}`);
|
|
266
|
+
} else if (rec.role === "assistant_final") {
|
|
267
|
+
const cost = rec.cost !== void 0 ? ` $${rec.cost.toFixed(6)}` : "";
|
|
268
|
+
const cache = rec.usage && (rec.usage.prompt_cache_hit_tokens !== void 0 || rec.usage.prompt_cache_miss_tokens !== void 0) ? (() => {
|
|
269
|
+
const hit = rec.usage.prompt_cache_hit_tokens ?? 0;
|
|
270
|
+
const miss = rec.usage.prompt_cache_miss_tokens ?? 0;
|
|
271
|
+
const total = hit + miss;
|
|
272
|
+
return total > 0 ? ` cache=${(hit / total * 100).toFixed(1)}%` : "";
|
|
273
|
+
})() : "";
|
|
274
|
+
console.log(`${turn} AGENT:${cost}${cache} ${oneLine(rec.content)}`);
|
|
275
|
+
} else if (rec.role === "tool") {
|
|
276
|
+
const args = rec.args ? ` args=${oneLine(rec.args, 80)}` : "";
|
|
277
|
+
console.log(`${turn} TOOL ${rec.tool ?? "?"}:${args} \u2192 ${oneLine(rec.content, 120)}`);
|
|
278
|
+
} else if (rec.role === "error") {
|
|
279
|
+
console.log(`${turn} ERROR: ${rec.error ?? rec.content}`);
|
|
280
|
+
} else if (rec.role === "done") {
|
|
281
|
+
} else {
|
|
282
|
+
console.log(`${turn} ${rec.role}: ${oneLine(rec.content)}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function oneLine(s, max = 200) {
|
|
286
|
+
const collapsed = s.replace(/\s+/g, " ").trim();
|
|
287
|
+
return collapsed.length > max ? `${collapsed.slice(0, max)}\u2026` : collapsed;
|
|
288
|
+
}
|
|
289
|
+
export {
|
|
290
|
+
replayCommand
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=replay-RDXLUAOE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/replay.ts","../../src/cli/ui/ReplayApp.tsx","../../src/cli/ui/StatsPanel.tsx"],"sourcesContent":["import { render } from \"ink\";\nimport React from \"react\";\nimport type { TranscriptRecord } from \"../../transcript/log.js\";\nimport { groupRecordsByTurn, replayFromFile } from \"../../transcript/replay.js\";\nimport { ReplayApp } from \"../ui/ReplayApp.js\";\n\nexport interface ReplayOptions {\n path: string;\n head?: number;\n tail?: number;\n /** Force stdout pretty-print mode (no Ink TUI). Also auto-enabled when stdout is not a TTY. */\n print?: boolean;\n}\n\nexport async function replayCommand(opts: ReplayOptions): Promise<void> {\n const wantPrint =\n opts.print || !process.stdout.isTTY || opts.head !== undefined || opts.tail !== undefined;\n if (wantPrint) {\n printReplay(opts);\n return;\n }\n\n const { parsed } = replayFromFile(opts.path);\n const pages = groupRecordsByTurn(parsed.records);\n const { waitUntilExit } = render(React.createElement(ReplayApp, { meta: parsed.meta, pages }), {\n exitOnCtrlC: true,\n patchConsole: false,\n });\n await waitUntilExit();\n}\n\n// stdout pretty-print path (original behavior, preserved for piping / CI)\n\nfunction printReplay(opts: ReplayOptions): void {\n const { parsed, stats } = replayFromFile(opts.path);\n\n if (parsed.meta) {\n const m = parsed.meta;\n const bits: string[] = [`source=${m.source}`];\n if (m.model) bits.push(`model=${m.model}`);\n if (m.task) bits.push(`task=${m.task}`);\n if (m.mode) bits.push(`mode=${m.mode}`);\n if (m.repeat !== undefined) bits.push(`repeat=${m.repeat}`);\n bits.push(`started=${m.startedAt}`);\n console.log(`[meta] ${bits.join(\" \")}`);\n console.log(\"\");\n }\n\n const records = sliceRecords(parsed.records, opts);\n for (const rec of records) {\n renderRecord(rec);\n }\n\n console.log(\"\");\n console.log(\"── summary ─────────────────────────────────────────\");\n console.log(`model calls: ${stats.turns}`);\n console.log(`user turns: ${stats.userTurns}`);\n console.log(`tool calls: ${stats.toolCalls}`);\n console.log(`cache hit: ${(stats.cacheHitRatio * 100).toFixed(1)}%`);\n console.log(`cost: $${stats.totalCostUsd.toFixed(6)}`);\n console.log(`claude equivalent: $${stats.claudeEquivalentUsd.toFixed(6)}`);\n console.log(`savings vs claude: ${stats.savingsVsClaudePct.toFixed(1)}%`);\n console.log(`models: ${stats.models.join(\", \") || \"—\"}`);\n console.log(`prefix hashes: ${stats.prefixHashes.length} distinct`);\n if (stats.prefixHashes.length === 1) {\n console.log(` (byte-stable prefix: ${stats.prefixHashes[0]?.slice(0, 16)}…)`);\n } else if (stats.prefixHashes.length > 1) {\n console.log(\" (prefix churned — cache-hostile session)\");\n }\n}\n\nfunction sliceRecords(records: TranscriptRecord[], opts: ReplayOptions): TranscriptRecord[] {\n if (opts.head !== undefined && opts.head > 0) return records.slice(0, opts.head);\n if (opts.tail !== undefined && opts.tail > 0) return records.slice(-opts.tail);\n return records;\n}\n\nfunction renderRecord(rec: TranscriptRecord): void {\n const turn = `[t${rec.turn}]`;\n if (rec.role === \"user\") {\n console.log(`${turn} USER: ${oneLine(rec.content)}`);\n } else if (rec.role === \"assistant_final\") {\n const cost = rec.cost !== undefined ? ` $${rec.cost.toFixed(6)}` : \"\";\n const cache =\n rec.usage &&\n (rec.usage.prompt_cache_hit_tokens !== undefined ||\n rec.usage.prompt_cache_miss_tokens !== undefined)\n ? (() => {\n const hit = rec.usage!.prompt_cache_hit_tokens ?? 0;\n const miss = rec.usage!.prompt_cache_miss_tokens ?? 0;\n const total = hit + miss;\n return total > 0 ? ` cache=${((hit / total) * 100).toFixed(1)}%` : \"\";\n })()\n : \"\";\n console.log(`${turn} AGENT:${cost}${cache} ${oneLine(rec.content)}`);\n } else if (rec.role === \"tool\") {\n const args = rec.args ? ` args=${oneLine(rec.args, 80)}` : \"\";\n console.log(`${turn} TOOL ${rec.tool ?? \"?\"}:${args} → ${oneLine(rec.content, 120)}`);\n } else if (rec.role === \"error\") {\n console.log(`${turn} ERROR: ${rec.error ?? rec.content}`);\n } else if (rec.role === \"done\") {\n // Suppress — visually noisy, not informative in replay.\n } else {\n console.log(`${turn} ${rec.role}: ${oneLine(rec.content)}`);\n }\n}\n\nfunction oneLine(s: string, max = 200): string {\n const collapsed = s.replace(/\\s+/g, \" \").trim();\n return collapsed.length > max ? `${collapsed.slice(0, max)}…` : collapsed;\n}\n","/**\n * Ink TUI for `luckerr replay`. Read-only: no input box, no loop.\n * j/k navigation across turn-pages, cumulative stats sidebar updates\n * as you move through time.\n *\n * The navigation logic (grouping records into pages, computing cumulative\n * stats) lives in src/replay.ts as pure functions; this file is just\n * presentation + key bindings.\n */\n\nimport { Box, Static, Text, useApp, useInput } from \"ink\";\nimport React, { useMemo, useState } from \"react\";\nimport { t } from \"../../i18n/index.js\";\nimport type { TranscriptMeta } from \"../../transcript/log.js\";\nimport { type TurnPage, computeCumulativeStats } from \"../../transcript/replay.js\";\nimport { RecordView } from \"./RecordView.js\";\nimport { StatsPanel } from \"./StatsPanel.js\";\n\nexport interface ReplayAppProps {\n meta: TranscriptMeta | null;\n pages: TurnPage[];\n}\n\nexport function ReplayApp({ meta, pages }: ReplayAppProps) {\n const { exit } = useApp();\n const maxIdx = Math.max(0, pages.length - 1);\n // Start at the last page — more useful than \"start from the beginning\"\n // in practice: users mostly want to see the summary + last turn first.\n const [idx, setIdx] = useState(maxIdx);\n\n useInput((input, key) => {\n if (input === \"q\" || (key.ctrl && input === \"c\")) {\n exit();\n return;\n }\n if (input === \"j\" || key.downArrow || input === \" \" || key.return) {\n setIdx((i) => Math.min(maxIdx, i + 1));\n } else if (input === \"k\" || key.upArrow) {\n setIdx((i) => Math.max(0, i - 1));\n } else if (input === \"g\") {\n setIdx(0);\n } else if (input === \"G\") {\n setIdx(maxIdx);\n } else if (input === \"h\" || key.leftArrow) {\n setIdx(0);\n } else if (input === \"l\" || key.rightArrow) {\n setIdx(maxIdx);\n }\n });\n\n const cumStats = useMemo(() => computeCumulativeStats(pages, idx), [pages, idx]);\n\n const summary = {\n turns: cumStats.turns,\n totalCostUsd: cumStats.totalCostUsd,\n totalInputCostUsd: cumStats.totalInputCostUsd,\n totalOutputCostUsd: cumStats.totalOutputCostUsd,\n claudeEquivalentUsd: cumStats.claudeEquivalentUsd,\n savingsVsClaudePct: cumStats.savingsVsClaudePct,\n cacheHitRatio: cumStats.cacheHitRatio,\n // Replay is read-only — no live last-turn prompt tokens to show.\n lastPromptTokens: 0,\n lastTurnCostUsd: 0,\n };\n\n const prefixHash =\n cumStats.prefixHashes.length === 1\n ? cumStats.prefixHashes[0]!.slice(0, 16)\n : cumStats.prefixHashes.length === 0\n ? t(\"replayApp.untracked\")\n : t(\"replayApp.churned\", { count: cumStats.prefixHashes.length });\n\n const currentPage = pages[idx];\n const progressLabel =\n pages.length === 0\n ? t(\"replayApp.emptyTranscript\")\n : t(\"replayApp.turnProgress\", { current: idx + 1, total: pages.length });\n\n return (\n <Box flexDirection=\"column\">\n <StatsPanel summary={summary} />\n\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n <Box justifyContent=\"space-between\">\n <Text color=\"cyan\" bold>\n {progressLabel}\n </Text>\n {meta ? (\n <Text dimColor>\n {meta.source}\n {meta.task ? ` · ${meta.task}` : \"\"}\n {meta.mode ? ` · ${meta.mode}` : \"\"}\n </Text>\n ) : null}\n </Box>\n\n {currentPage ? (\n <Static items={currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec }))}>\n {({ key, rec }) => <RecordView key={key} rec={rec} />}\n </Static>\n ) : (\n <Text dimColor italic>\n {t(\"replayApp.noRecords\")}\n </Text>\n )}\n </Box>\n\n <Box marginTop={1} paddingX={1} borderStyle=\"single\" borderColor=\"gray\">\n <Text dimColor>\n <Text bold>j</Text>/<Text bold>↓</Text>/<Text bold>space</Text> next · <Text bold>k</Text>\n /<Text bold>↑</Text> prev · <Text bold>g</Text> first · <Text bold>G</Text> last ·{\" \"}\n <Text bold>q</Text> quit\n </Text>\n </Box>\n </Box>\n );\n}\n","import { basename } from \"node:path\";\nimport { Box, Text, useStdout } from \"ink\";\nimport React from \"react\";\nimport stringWidth from \"string-width\";\nimport type { EditMode } from \"../../config.js\";\nimport { t } from \"../../i18n/index.js\";\nimport type { SessionSummary } from \"../../telemetry/stats.js\";\nimport { Bar, ChromeRule } from \"./primitives.js\";\nimport { COLOR, GRADIENT } from \"./theme.js\";\nimport { formatBalance, formatCost } from \"./theme/tokens.js\";\n\nconst COLD_START_TURNS = 3;\n\nexport interface StatsPanelProps {\n summary: SessionSummary;\n planMode?: boolean;\n editMode?: EditMode;\n balance?: { currency: string; total: number } | null;\n updateAvailable?: string | null;\n proArmed?: boolean;\n escalated?: boolean;\n budgetUsd?: number | null;\n rootDir?: string;\n sessionName?: string | null;\n}\n\nexport function StatsPanel({\n summary,\n planMode,\n editMode,\n balance,\n updateAvailable,\n proArmed,\n escalated,\n budgetUsd,\n rootDir,\n sessionName,\n}: StatsPanelProps) {\n const coldStart = summary.turns <= COLD_START_TURNS;\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <ChromeRow\n editMode={editMode}\n planMode={planMode}\n proArmed={proArmed ?? false}\n escalated={escalated ?? false}\n summary={summary}\n coldStart={coldStart}\n rootDir={rootDir}\n sessionName={sessionName ?? null}\n updateAvailable={updateAvailable}\n balance={balance ?? null}\n />\n <ChromeRule />\n {budgetUsd !== null && budgetUsd !== undefined ? (\n <BudgetRow spent={summary.totalCostUsd} cap={budgetUsd} />\n ) : null}\n </Box>\n );\n}\n\nfunction ChromeRow({\n editMode,\n planMode,\n proArmed,\n escalated,\n summary,\n coldStart,\n rootDir,\n sessionName,\n updateAvailable,\n balance,\n}: {\n editMode?: EditMode;\n planMode?: boolean;\n proArmed: boolean;\n escalated: boolean;\n summary: SessionSummary;\n coldStart: boolean;\n rootDir?: string;\n sessionName?: string | null;\n updateAvailable?: string | null;\n balance?: { currency: string; total: number } | null;\n}) {\n const modePill = pickModePill(planMode, editMode);\n const proLabel = t(\"statsPanel.pro\");\n const proPill = escalated\n ? { label: proLabel, color: COLOR.err }\n : proArmed\n ? { label: proLabel, color: COLOR.warn }\n : null;\n const projectName = rootDir ? basename(rootDir) : null;\n const cachePct = (summary.cacheHitRatio * 100).toFixed(1);\n const cacheColor =\n summary.cacheHitRatio >= 0.7 ? COLOR.ok : summary.cacheHitRatio >= 0.4 ? COLOR.warn : COLOR.err;\n const balanceLabel = balance\n ? `[${formatBalance(balance.total, balance.currency, { label: true })}]`\n : \"\";\n const costLabel = `[${formatCost(summary.totalCostUsd, balance?.currency)}]`;\n const cacheLabel = \"[c ▰▰▰▰▰▰ 100%]\";\n const updateLabel = updateAvailable ? `↑ ${updateAvailable}` : \"\";\n\n // Greedy width-aware fit. Layout (every gap = 2 cells, applied as suffix\n // to update/mode/pro and as prefix to balance/cache):\n // [brand][·project][›session]<spacer>[update][mode][pro][cost][balance][cache]\n // Always shown: brand, project (if rootDir), mode (if set), pro (if armed),\n // cost. These carve fixedLeft / fixedRight first.\n // Optional, dropped greedy by priority: balance > cache > session > update.\n // The flexbox spacer can shrink to 0, so no minimum reserve.\n const { stdout } = useStdout();\n const cols = (stdout?.columns ?? 80) - 2; // subtract paddingX={1} on both sides\n const SEP_DOT = stringWidth(\" · \");\n const SEP_ARROW = stringWidth(\" › \");\n const GAP = 2;\n\n const fixedLeft =\n stringWidth(\"◈ luckerr\") + (projectName ? SEP_DOT + stringWidth(projectName) : 0);\n const modeW = modePill ? GAP + stringWidth(`[${modePill.label}]`) : 0;\n const proW = proPill ? GAP + stringWidth(`[${proPill.label}]`) : 0;\n const fixedRight = modeW + proW + stringWidth(costLabel);\n let budget = cols - fixedLeft - fixedRight;\n\n const balW = balance ? GAP + stringWidth(balanceLabel) : 0;\n const cacheW = GAP + stringWidth(cacheLabel);\n const sessionW = sessionName ? SEP_ARROW + stringWidth(sessionName) : 0;\n const updateW = updateLabel ? GAP + stringWidth(updateLabel) : 0;\n\n const showBalance = balW > 0 && budget >= balW;\n if (showBalance) budget -= balW;\n const showCache = budget >= cacheW;\n if (showCache) budget -= cacheW;\n const showSession = sessionW > 0 && budget >= sessionW;\n if (showSession) budget -= sessionW;\n const showUpdate = updateW > 0 && budget >= updateW;\n if (showUpdate) budget -= updateW;\n\n return (\n <Box>\n <Text bold color={GRADIENT[0]}>\n {\"◈ \"}\n </Text>\n <Text color={COLOR.brand} bold>\n luckerr\n </Text>\n {projectName ? (\n <>\n <Text color={COLOR.info} dimColor>\n {\" · \"}\n </Text>\n <Text>{projectName}</Text>\n {showSession && sessionName ? (\n <>\n <Text color={COLOR.info} dimColor>\n {\" › \"}\n </Text>\n <Text color={COLOR.info}>{sessionName}</Text>\n </>\n ) : null}\n </>\n ) : null}\n\n <Box flexGrow={1} />\n\n {showUpdate ? (\n <>\n <Text color={COLOR.warn} bold>\n {updateLabel}\n </Text>\n <Text>{\" \"}</Text>\n </>\n ) : null}\n {modePill ? (\n <>\n <Text color={modePill.color} bold>\n {`[${modePill.label}]`}\n </Text>\n <Text>{\" \"}</Text>\n </>\n ) : null}\n {proPill ? (\n <>\n <Text color={proPill.color} bold>\n {`[${proPill.label}]`}\n </Text>\n <Text>{\" \"}</Text>\n </>\n ) : null}\n <Text\n color={\n summary.turns === 0 || coldStart ? COLOR.info : sessionCostColor(summary.totalCostUsd)\n }\n bold={summary.turns > 0 && !coldStart}\n dimColor={summary.turns === 0 || coldStart}\n >\n {costLabel}\n </Text>\n {showBalance && balance ? (\n <>\n <Text>{\" \"}</Text>\n <Text color={balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok}>\n {balanceLabel}\n </Text>\n </>\n ) : null}\n {showCache ? (\n <>\n <Text>{\" \"}</Text>\n <Text dimColor>{\"[\"}</Text>\n <Text dimColor>{\"c \"}</Text>\n <Bar\n ratio={summary.cacheHitRatio}\n color={coldStart ? COLOR.info : cacheColor}\n cells={6}\n dim={coldStart}\n />\n <Text> </Text>\n <Text color={coldStart ? undefined : cacheColor} dimColor={coldStart}>\n {coldStart && summary.turns === 0 ? \"—\" : `${cachePct}%`}\n </Text>\n <Text dimColor>{\"]\"}</Text>\n </>\n ) : null}\n </Box>\n );\n}\n\nfunction pickModePill(\n planMode: boolean | undefined,\n editMode: EditMode | undefined,\n): { label: string; color: string } | null {\n if (planMode) return { label: t(\"statsPanel.modePlan\"), color: COLOR.err };\n if (editMode === \"yolo\") return { label: t(\"statsPanel.modeYolo\"), color: COLOR.err };\n if (editMode === \"auto\") return { label: t(\"statsPanel.modeAuto\"), color: COLOR.primary };\n if (editMode === \"review\") return { label: t(\"statsPanel.modeReview\"), color: COLOR.info };\n return null;\n}\n\nfunction BudgetRow({ spent, cap }: { spent: number; cap: number }) {\n const pct = Math.max(0, (spent / cap) * 100);\n const color = pct >= 100 ? \"#f87171\" : pct >= 80 ? \"#fbbf24\" : \"#94a3b8\";\n return (\n <Box>\n <Text dimColor>{t(\"statsPanel.budget\")}</Text>\n <Text color={color}>\n {`$${spent.toFixed(4)} / $${cap.toFixed(2)}`}\n <Text dimColor>{` (${pct.toFixed(0)}%)`}</Text>\n </Text>\n </Box>\n );\n}\n\nfunction sessionCostColor(cost: number): string | undefined {\n if (cost <= 0) return undefined;\n if (cost >= 5) return COLOR.err;\n if (cost >= 0.5) return COLOR.warn;\n return COLOR.ok;\n}\n"],"mappings":"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","names":["import_react","import_react","React","React","React"]}
|