local-commander-agent 0.3.52 → 0.3.53

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.
@@ -1,136 +1,136 @@
1
- import { readdir, lstat } from "node:fs/promises";
2
- import path from "node:path";
3
- import { readState, presenceDirectory } from "./monitor-agents.mjs";
4
-
5
- const text = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f-\u009f]/u.test(value);
6
- const count = value => Number.isSafeInteger(value) && value >= 0 && value <= 1e12;
7
- const id = value => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$/.test(value);
8
- const nullable = (value, test) => value === null || test(value);
9
- const tool = value => typeof value === "string" && /^[a-z_]{1,64}$/.test(value);
10
- const model = value => text(value, 80) && /^[A-Za-z0-9][A-Za-z0-9._:/+-]{0,79}$/.test(value);
11
- const name = value => text(value, 8) && /^[A-Za-z][A-Za-z0-9]{0,7}$/.test(value);
12
- const preview = row => {
13
- if (row.preview === undefined) return row.command;
14
- if (!text(row.preview, 240)) throw Error("MCP_MONITOR_INVALID");
15
- return row.preview;
16
- };
17
- const optionalModel = row => row.model === undefined || row.model === null ? null : model(row.model) ? row.model : invalid();
18
- const optionalExit = row => row.exitCode === undefined || row.exitCode === null ? null : Number.isInteger(row.exitCode) && Math.abs(row.exitCode) <= 2147483648 ? row.exitCode : invalid();
19
- const invalid = () => { throw Error("MCP_MONITOR_INVALID"); };
20
- function agentView(a) {
21
- if (a === null) return null;
22
- if (!a || !id(a.runtimeId) || !name(a.name) ||
23
- !nullable(a.model, model) || !nullable(a.activity, value => text(value, 500)) ||
24
- !["working", "analysis", "message", "idle"].includes(a.phase) || !nullable(a.taskId, id) || !nullable(a.project, value => text(value, 96))) invalid();
25
- return { runtimeId: a.runtimeId, name: a.name, model: a.model, activity: a.activity, phase: a.phase, taskId: a.taskId, project: a.project };
26
- }
27
- export function contextView(raw) {
28
- if (!raw || !nullable(raw.project, value => text(value, 96)) || !nullable(raw.directory, value => text(value, 96)) ||
29
- !nullable(raw.taskId, id) || !nullable(raw.pr, value => count(value) && value > 0 && value <= 9_999_999) || typeof raw.inferred !== "boolean") invalid();
30
- return { project: raw.project, directory: raw.directory, taskId: raw.taskId, pr: raw.pr, inferred: raw.inferred };
31
- }
32
- export function mcpView(raw, alive = pid => { try { process.kill(pid, 0); return true; } catch (error) { return error.code === "EPERM"; } }) {
33
- if (!raw || raw.schemaVersion !== 1 || !/^[a-f0-9-]{36}$/.test(raw.instanceId) || !count(raw.pid) || !raw.pid || !text(raw.computer, 64) ||
34
- typeof raw.updatedAt !== "string" || !Number.isFinite(Date.parse(raw.updatedAt)) || !nullable(raw.queue, count) ||
35
- ![raw.dropped, raw.writeErrors, raw.writes].every(count) || !Array.isArray(raw.calls) || raw.calls.length > 256 ||
36
- !Array.isArray(raw.events) || raw.events.length > 100 || !Array.isArray(raw.metrics) || raw.metrics.length > 64) invalid();
37
- const command = row => {
38
- if (!tool(row.tool) || !text(row.command, 80) || !(row.command === row.tool ||
39
- row.tool === "agent_message" && /^agent_message (?:send|inbox|ack)(?: (?:status|question|answer|handoff|result_summary|blocker))?(?: -> [A-Za-z0-9_.:-]{1,8})?$/.test(row.command) ||
40
- /^(?:node|npm|npx|git|rg|powershell|pwsh|cmd|tsc|python|dotnet|gh|command)(?: \[args\]| --test| (?:status|diff|log|show|fetch|pull|push|commit|test|install|ci|pack|publish)| run (?:test|build|typecheck|lint|dev|start))?$/.test(row.command))) invalid();
41
- return row.command;
42
- };
43
- const calls = raw.calls.map(row => {
44
- if (!count(row.id) || !["accepted", "queued", "running"].includes(row.state) || !Number.isSafeInteger(row.at) || row.at < 1 || row.at > Date.now() + 5000) invalid();
45
- const agent = agentView(row.agent);
46
- return { id: row.id, tool: row.tool, command: command(row), preview: preview(row), state: row.state, at: row.at, agent, context: contextView(row.context) };
47
- });
48
- const metrics = raw.metrics.map(row => {
49
- if (!tool(row.tool) || ![row.calls, row.errors, row.sentBytes, row.savedBytes, row.outputBytes, row.durationMs].every(count) || row.errors > row.calls) invalid();
50
- return Object.fromEntries(["tool", "calls", "errors", "sentBytes", "savedBytes", "outputBytes", "durationMs"].map(key => [key, row[key]]));
51
- });
52
- if (raw.agents !== undefined && (!Array.isArray(raw.agents) || raw.agents.length > 64)) invalid();
53
- const agents = (raw.agents ?? []).map(row => {
54
- if (!id(row.runtimeId) || !name(row.name) || !nullable(row.model, model) ||
55
- ![row.calls, row.errors, row.sentBytes, row.savedBytes, row.outputBytes, row.durationMs].every(count) || row.errors > row.calls) invalid();
56
- return Object.fromEntries(["runtimeId", "name", "model", "calls", "errors", "sentBytes", "savedBytes", "outputBytes", "durationMs"].map(key => [key, row[key]]));
57
- });
58
- if (raw.processes !== undefined && (!Array.isArray(raw.processes) || raw.processes.length > 64)) invalid();
59
- const processes = (raw.processes ?? []).map(row => {
60
- if (!id(row.id) || !count(row.pid) || !row.pid) invalid();
61
- return { id: row.id, pid: row.pid, command: command({ tool: "process_start", command: row.command }), preview: preview(row), context: contextView(row.context), agent: agentView(row.agent) };
62
- });
63
- const events = raw.events.map(row => {
64
- if (!count(row.id) || typeof row.at !== "string" || !Number.isFinite(Date.parse(row.at)) || !["failed", "finished"].includes(row.state) ||
65
- !nullable(row.agent, id) || !nullable(row.name, name) ||
66
- !nullable(row.code, value => /^[A-Z][A-Z0-9_]{0,63}$/.test(value)) || ![row.durationMs, row.sentBytes, row.savedBytes].every(count)) invalid();
67
- return { id: row.id, at: row.at, tool: row.tool, command: command(row), preview: preview(row), state: row.state, agent: row.agent, name: row.name,
68
- context: contextView(row.context), model: optionalModel(row), exitCode: optionalExit(row), timedOut: row.timedOut === true, code: row.code, durationMs: row.durationMs, sentBytes: row.sentBytes, savedBytes: row.savedBytes };
69
- });
70
- if (raw.transitions !== undefined && (!Array.isArray(raw.transitions) || raw.transitions.length > 100)) invalid();
71
- const transitions = (raw.transitions ?? []).map(row => {
72
- if (!count(row.seq) || !count(row.id) || row.state !== "running" || !tool(row.tool) ||
73
- typeof row.at !== "string" || !Number.isFinite(Date.parse(row.at)) || !nullable(row.name, name) || !text(row.preview, 240)) invalid();
74
- return { seq: row.seq, id: row.id, at: row.at, tool: row.tool, preview: row.preview, state: row.state,
75
- context: contextView(row.context), name: row.name, model: optionalModel(row) };
76
- });
77
- return { instanceId: raw.instanceId, pid: raw.pid, computer: raw.computer, updatedAt: raw.updatedAt, running: alive(raw.pid), queue: raw.queue,
78
- calls, processes, agents, metrics, events, transitions, dropped: raw.dropped, writeErrors: raw.writeErrors, writes: raw.writes };
79
- }
80
- export async function readMcpActivity(projectRoot = process.cwd()) {
81
- const directory = path.join(presenceDirectory(projectRoot), "activity");
82
- let entries;
83
- try {
84
- const stat = await lstat(directory);
85
- if (!stat.isDirectory() || stat.isSymbolicLink()) invalid();
86
- entries = (await readdir(directory)).filter(name => /^\d+-[a-f0-9-]{36}\.json$/.test(name)).sort();
87
- } catch (error) { return { instances: [], unavailable: error.code === "ENOENT" ? 0 : 1 }; }
88
- const instances = [];
89
- let unavailable = Math.max(0, entries.length - 32);
90
- for (const name of entries.slice(-32)) {
91
- try { instances.push(mcpView(await readState(path.join(directory, name)))); } catch { unavailable++; }
92
- }
93
- return { instances: instances.sort((a, b) => a.instanceId.localeCompare(b.instanceId)), unavailable };
94
- }
95
-
96
- let healthCache;
97
- /** Probe only the existing loopback health route, once per 30s; idle activity age is not health. */
98
- export async function readMcpHealth(projectRoot = process.cwd()) {
99
- if (healthCache && Date.now() - healthCache.time < 30_000) return healthCache.result;
100
- let endpoint = "http://127.0.0.1:17321/health", configured = false;
101
- try {
102
- const file = path.resolve(projectRoot, process.env.LCMCP_CONFIG?.trim() || "local-commander.config.json");
103
- const stat = await lstat(file);
104
- if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 65_536) throw Error("CONFIG_INVALID");
105
- const config = await readState(file);
106
- const host = config.server?.host ?? "127.0.0.1", port = config.server?.port ?? 17321;
107
- if (!["localhost", "127.0.0.1", "::1"].includes(host) || !Number.isInteger(port) || port < 1 || port > 65535) throw Error("HEALTH_NOT_LOOPBACK");
108
- endpoint = "http://" + (host === "::1" ? "[::1]" : host) + ":" + port + "/health";
109
- configured = true;
110
- } catch (error) {
111
- if (error.code !== "ENOENT") return { state: "unavailable", status: null, at: new Date().toISOString(), latencyMs: null };
112
- }
113
- const start = Date.now();
114
- let result;
115
- try {
116
- const response = await fetch(endpoint, { signal: AbortSignal.timeout(800), redirect: "error" });
117
- const reader = response.body?.getReader();
118
- let body = "", bytes = 0;
119
- if (reader) {
120
- try {
121
- while (true) {
122
- const chunk = await reader.read();
123
- if (chunk.done) break;
124
- bytes += chunk.value.byteLength;
125
- if (bytes > 2048) throw Error("HEALTH_RESPONSE_LIMIT");
126
- body += Buffer.from(chunk.value).toString("utf8");
127
- }
128
- } finally { void reader.cancel().catch(() => {}); }
129
- }
130
- const value = JSON.parse(body);
131
- result = { state: response.ok && value.status === "ok" ? "healthy" : "failed", status: response.status,
132
- at: new Date().toISOString(), latencyMs: Date.now() - start };
133
- } catch { result = { state: configured ? "unreachable" : "not observed", status: null, at: new Date().toISOString(), latencyMs: Date.now() - start }; }
134
- healthCache = { time: Date.now(), result };
135
- return result;
136
- }
1
+ import { readdir, lstat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readState, presenceDirectory } from "./monitor-agents.mjs";
4
+
5
+ const text = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f-\u009f]/u.test(value);
6
+ const count = value => Number.isSafeInteger(value) && value >= 0 && value <= 1e12;
7
+ const id = value => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$/.test(value);
8
+ const nullable = (value, test) => value === null || test(value);
9
+ const tool = value => typeof value === "string" && /^[a-z_]{1,64}$/.test(value);
10
+ const model = value => text(value, 80) && /^[A-Za-z0-9][A-Za-z0-9._:/+-]{0,79}$/.test(value);
11
+ const name = value => text(value, 8) && /^[A-Za-z][A-Za-z0-9]{0,7}$/.test(value);
12
+ const preview = row => {
13
+ if (row.preview === undefined) return row.command;
14
+ if (!text(row.preview, 240)) throw Error("MCP_MONITOR_INVALID");
15
+ return row.preview;
16
+ };
17
+ const optionalModel = row => row.model === undefined || row.model === null ? null : model(row.model) ? row.model : invalid();
18
+ const optionalExit = row => row.exitCode === undefined || row.exitCode === null ? null : Number.isInteger(row.exitCode) && Math.abs(row.exitCode) <= 2147483648 ? row.exitCode : invalid();
19
+ const invalid = () => { throw Error("MCP_MONITOR_INVALID"); };
20
+ function agentView(a) {
21
+ if (a === null) return null;
22
+ if (!a || !id(a.runtimeId) || !name(a.name) ||
23
+ !nullable(a.model, model) || !nullable(a.activity, value => text(value, 500)) ||
24
+ !["working", "analysis", "message", "idle"].includes(a.phase) || !nullable(a.taskId, id) || !nullable(a.project, value => text(value, 96))) invalid();
25
+ return { runtimeId: a.runtimeId, name: a.name, model: a.model, activity: a.activity, phase: a.phase, taskId: a.taskId, project: a.project };
26
+ }
27
+ export function contextView(raw) {
28
+ if (!raw || !nullable(raw.project, value => text(value, 96)) || !nullable(raw.directory, value => text(value, 96)) ||
29
+ !nullable(raw.taskId, id) || !nullable(raw.pr, value => count(value) && value > 0 && value <= 9_999_999) || typeof raw.inferred !== "boolean") invalid();
30
+ return { project: raw.project, directory: raw.directory, taskId: raw.taskId, pr: raw.pr, inferred: raw.inferred };
31
+ }
32
+ export function mcpView(raw, alive = pid => { try { process.kill(pid, 0); return true; } catch (error) { return error.code === "EPERM"; } }) {
33
+ if (!raw || raw.schemaVersion !== 1 || !/^[a-f0-9-]{36}$/.test(raw.instanceId) || !count(raw.pid) || !raw.pid || !text(raw.computer, 64) ||
34
+ typeof raw.updatedAt !== "string" || !Number.isFinite(Date.parse(raw.updatedAt)) || !nullable(raw.queue, count) ||
35
+ ![raw.dropped, raw.writeErrors, raw.writes].every(count) || !Array.isArray(raw.calls) || raw.calls.length > 256 ||
36
+ !Array.isArray(raw.events) || raw.events.length > 100 || !Array.isArray(raw.metrics) || raw.metrics.length > 64) invalid();
37
+ const command = row => {
38
+ if (!tool(row.tool) || !text(row.command, 80) || !(row.command === row.tool ||
39
+ row.tool === "agent_message" && /^agent_message (?:send|inbox|ack)(?: (?:status|question|answer|handoff|result_summary|blocker))?(?: -> [A-Za-z0-9_.:-]{1,8})?$/.test(row.command) ||
40
+ /^(?:node|npm|npx|git|rg|powershell|pwsh|cmd|tsc|python|dotnet|gh|command)(?: \[args\]| --test| (?:status|diff|log|show|fetch|pull|push|commit|test|install|ci|pack|publish)| run (?:test|build|typecheck|lint|dev|start))?$/.test(row.command))) invalid();
41
+ return row.command;
42
+ };
43
+ const calls = raw.calls.map(row => {
44
+ if (!count(row.id) || !["accepted", "queued", "running"].includes(row.state) || !Number.isSafeInteger(row.at) || row.at < 1 || row.at > Date.now() + 5000) invalid();
45
+ const agent = agentView(row.agent);
46
+ return { id: row.id, tool: row.tool, command: command(row), preview: preview(row), state: row.state, at: row.at, agent, context: contextView(row.context) };
47
+ });
48
+ const metrics = raw.metrics.map(row => {
49
+ if (!tool(row.tool) || ![row.calls, row.errors, row.sentBytes, row.savedBytes, row.outputBytes, row.durationMs].every(count) || row.errors > row.calls) invalid();
50
+ return Object.fromEntries(["tool", "calls", "errors", "sentBytes", "savedBytes", "outputBytes", "durationMs"].map(key => [key, row[key]]));
51
+ });
52
+ if (raw.agents !== undefined && (!Array.isArray(raw.agents) || raw.agents.length > 64)) invalid();
53
+ const agents = (raw.agents ?? []).map(row => {
54
+ if (!id(row.runtimeId) || !name(row.name) || !nullable(row.model, model) ||
55
+ ![row.calls, row.errors, row.sentBytes, row.savedBytes, row.outputBytes, row.durationMs].every(count) || row.errors > row.calls) invalid();
56
+ return Object.fromEntries(["runtimeId", "name", "model", "calls", "errors", "sentBytes", "savedBytes", "outputBytes", "durationMs"].map(key => [key, row[key]]));
57
+ });
58
+ if (raw.processes !== undefined && (!Array.isArray(raw.processes) || raw.processes.length > 64)) invalid();
59
+ const processes = (raw.processes ?? []).map(row => {
60
+ if (!id(row.id) || !count(row.pid) || !row.pid) invalid();
61
+ return { id: row.id, pid: row.pid, command: command({ tool: "process_start", command: row.command }), preview: preview(row), context: contextView(row.context), agent: agentView(row.agent) };
62
+ });
63
+ const events = raw.events.map(row => {
64
+ if (!count(row.id) || typeof row.at !== "string" || !Number.isFinite(Date.parse(row.at)) || !["failed", "finished"].includes(row.state) ||
65
+ !nullable(row.agent, id) || !nullable(row.name, name) ||
66
+ !nullable(row.code, value => /^[A-Z][A-Z0-9_]{0,63}$/.test(value)) || ![row.durationMs, row.sentBytes, row.savedBytes].every(count)) invalid();
67
+ return { id: row.id, at: row.at, tool: row.tool, command: command(row), preview: preview(row), state: row.state, agent: row.agent, name: row.name,
68
+ context: contextView(row.context), model: optionalModel(row), exitCode: optionalExit(row), timedOut: row.timedOut === true, code: row.code, durationMs: row.durationMs, sentBytes: row.sentBytes, savedBytes: row.savedBytes };
69
+ });
70
+ if (raw.transitions !== undefined && (!Array.isArray(raw.transitions) || raw.transitions.length > 100)) invalid();
71
+ const transitions = (raw.transitions ?? []).map(row => {
72
+ if (!count(row.seq) || !count(row.id) || row.state !== "running" || !tool(row.tool) ||
73
+ typeof row.at !== "string" || !Number.isFinite(Date.parse(row.at)) || !nullable(row.name, name) || !text(row.preview, 240)) invalid();
74
+ return { seq: row.seq, id: row.id, at: row.at, tool: row.tool, preview: row.preview, state: row.state,
75
+ context: contextView(row.context), name: row.name, model: optionalModel(row) };
76
+ });
77
+ return { instanceId: raw.instanceId, pid: raw.pid, computer: raw.computer, updatedAt: raw.updatedAt, running: alive(raw.pid), queue: raw.queue,
78
+ calls, processes, agents, metrics, events, transitions, dropped: raw.dropped, writeErrors: raw.writeErrors, writes: raw.writes };
79
+ }
80
+ export async function readMcpActivity(projectRoot = process.cwd()) {
81
+ const directory = path.join(presenceDirectory(projectRoot), "activity");
82
+ let entries;
83
+ try {
84
+ const stat = await lstat(directory);
85
+ if (!stat.isDirectory() || stat.isSymbolicLink()) invalid();
86
+ entries = (await readdir(directory)).filter(name => /^\d+-[a-f0-9-]{36}\.json$/.test(name)).sort();
87
+ } catch (error) { return { instances: [], unavailable: error.code === "ENOENT" ? 0 : 1 }; }
88
+ const instances = [];
89
+ let unavailable = Math.max(0, entries.length - 32);
90
+ for (const name of entries.slice(-32)) {
91
+ try { instances.push(mcpView(await readState(path.join(directory, name)))); } catch { unavailable++; }
92
+ }
93
+ return { instances: instances.sort((a, b) => a.instanceId.localeCompare(b.instanceId)), unavailable };
94
+ }
95
+
96
+ let healthCache;
97
+ /** Probe only the existing loopback health route, once per 30s; idle activity age is not health. */
98
+ export async function readMcpHealth(projectRoot = process.cwd()) {
99
+ if (healthCache && Date.now() - healthCache.time < 30_000) return healthCache.result;
100
+ let endpoint = "http://127.0.0.1:17321/health", configured = false;
101
+ try {
102
+ const file = path.resolve(projectRoot, process.env.LCMCP_CONFIG?.trim() || "local-commander.config.json");
103
+ const stat = await lstat(file);
104
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 65_536) throw Error("CONFIG_INVALID");
105
+ const config = await readState(file);
106
+ const host = config.server?.host ?? "127.0.0.1", port = config.server?.port ?? 17321;
107
+ if (!["localhost", "127.0.0.1", "::1"].includes(host) || !Number.isInteger(port) || port < 1 || port > 65535) throw Error("HEALTH_NOT_LOOPBACK");
108
+ endpoint = "http://" + (host === "::1" ? "[::1]" : host) + ":" + port + "/health";
109
+ configured = true;
110
+ } catch (error) {
111
+ if (error.code !== "ENOENT") return { state: "unavailable", status: null, at: new Date().toISOString(), latencyMs: null };
112
+ }
113
+ const start = Date.now();
114
+ let result;
115
+ try {
116
+ const response = await fetch(endpoint, { signal: AbortSignal.timeout(800), redirect: "error" });
117
+ const reader = response.body?.getReader();
118
+ let body = "", bytes = 0;
119
+ if (reader) {
120
+ try {
121
+ while (true) {
122
+ const chunk = await reader.read();
123
+ if (chunk.done) break;
124
+ bytes += chunk.value.byteLength;
125
+ if (bytes > 2048) throw Error("HEALTH_RESPONSE_LIMIT");
126
+ body += Buffer.from(chunk.value).toString("utf8");
127
+ }
128
+ } finally { void reader.cancel().catch(() => {}); }
129
+ }
130
+ const value = JSON.parse(body);
131
+ result = { state: response.ok && value.status === "ok" ? "healthy" : "failed", status: response.status,
132
+ at: new Date().toISOString(), latencyMs: Date.now() - start };
133
+ } catch { result = { state: configured ? "unreachable" : "not observed", status: null, at: new Date().toISOString(), latencyMs: Date.now() - start }; }
134
+ healthCache = { time: Date.now(), result };
135
+ return result;
136
+ }
@@ -1,20 +1,20 @@
1
- export interface LifetimeSavings {
2
- scope: "all_time";
3
- coverage: "recorded_native_results";
4
- since: string | null;
5
- asOf: string | null;
6
- calls: number;
7
- originalBytes: number;
8
- sentBytes: number;
9
- savedBytes: number;
10
- }
11
- export function lifetimeSavingsView(raw: unknown): LifetimeSavings | null;
12
- export function summarizeLifetimeSavings(result: {
13
- instances?: Array<{ lifetimeSavings?: unknown; savingsSourceId?: string }>;
14
- unavailable?: number;
15
- }): { available: boolean; partial: boolean; unavailable: number; sources?: number;
16
- calls?: number; originalBytes?: number; sentBytes?: number; savedBytes?: number;
17
- since?: string | null; asOf?: string | null; estimatedSavedTokens?: number };
18
- export function formatLifetimeSavings(result: Parameters<typeof summarizeLifetimeSavings>[0] & {
19
- mcp?: { instances: Array<{ instanceId: string; metrics?: Array<{ savedBytes: number }> }>; unavailable?: number };
20
- }): string[];
1
+ export interface LifetimeSavings {
2
+ scope: "all_time";
3
+ coverage: "recorded_native_results";
4
+ since: string | null;
5
+ asOf: string | null;
6
+ calls: number;
7
+ originalBytes: number;
8
+ sentBytes: number;
9
+ savedBytes: number;
10
+ }
11
+ export function lifetimeSavingsView(raw: unknown): LifetimeSavings | null;
12
+ export function summarizeLifetimeSavings(result: {
13
+ instances?: Array<{ lifetimeSavings?: unknown; savingsSourceId?: string }>;
14
+ unavailable?: number;
15
+ }): { available: boolean; partial: boolean; unavailable: number; sources?: number;
16
+ calls?: number; originalBytes?: number; sentBytes?: number; savedBytes?: number;
17
+ since?: string | null; asOf?: string | null; estimatedSavedTokens?: number };
18
+ export function formatLifetimeSavings(result: Parameters<typeof summarizeLifetimeSavings>[0] & {
19
+ mcp?: { instances: Array<{ instanceId: string; metrics?: Array<{ savedBytes: number }> }>; unavailable?: number };
20
+ }): string[];
@@ -1,71 +1,71 @@
1
- // Scalar projections only. Never read a ledger, private state or provider data here.
2
- const count = value => Number.isSafeInteger(value) && value >= 0 && value <= 1e15;
3
- const date = value => typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
4
-
5
- /** Invalid or older optional telemetry must not hide the rest of a computer. */
6
- export function lifetimeSavingsView(raw) {
7
- if (!raw || raw.scope !== "all_time" || raw.coverage !== "recorded_native_results" ||
8
- ![raw.calls, raw.originalBytes, raw.sentBytes, raw.savedBytes].every(count) ||
9
- raw.sentBytes > raw.originalBytes || raw.savedBytes !== raw.originalBytes - raw.sentBytes ||
10
- (raw.calls === 0 ? raw.since !== null || raw.asOf !== null || raw.originalBytes !== 0 :
11
- !date(raw.since) || !date(raw.asOf) || raw.since > raw.asOf)) return null;
12
- return { scope: "all_time", coverage: "recorded_native_results", since: raw.since, asOf: raw.asOf,
13
- calls: raw.calls, originalBytes: raw.originalBytes, sentBytes: raw.sentBytes, savedBytes: raw.savedBytes };
14
- }
15
-
16
- /** Aggregate complete scalar native histories, even when their producers have stopped. */
17
- export function summarizeLifetimeSavings(result) {
18
- const sources = new Map(), rejected = new Set();
19
- let unavailable = result.unavailable ?? 0;
20
- // Ascending counts expose old conflicts too, regardless of the reader's file order.
21
- const snapshots = (result.instances ?? []).map(instance => ({
22
- id: instance.savingsSourceId, value: lifetimeSavingsView(instance.lifetimeSavings)
23
- })).sort((a, b) => (a.value?.calls ?? 0) - (b.value?.calls ?? 0));
24
- for (const { id, value } of snapshots) {
25
- if (typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id)) { unavailable++; continue; }
26
- if (rejected.has(id)) continue;
27
- const old = sources.get(id);
28
- const conflict = old && (value?.calls === old.calls ?
29
- Object.keys(old).some(key => value[key] !== old[key]) :
30
- value && (["originalBytes", "sentBytes", "savedBytes"].some(key => value[key] < old[key]) ||
31
- (old.since !== null && value.since > old.since) || (old.asOf !== null && value.asOf < old.asOf)));
32
- if (!value || conflict) {
33
- sources.delete(id); rejected.add(id); unavailable++; continue;
34
- }
35
- sources.set(id, value);
36
- }
37
- const values = [...sources.values()];
38
- const totals = { calls: 0, originalBytes: 0, sentBytes: 0, savedBytes: 0 };
39
- for (const value of values) for (const key of Object.keys(totals)) totals[key] += value[key];
40
- if (!Object.values(totals).every(count)) return { available: false, partial: true, unavailable: unavailable + 1 };
41
- const dates = values.map(value => value.since).filter(Boolean).sort();
42
- const updates = values.map(value => value.asOf).filter(Boolean).sort();
43
- return { available: values.length > 0, partial: unavailable > 0, unavailable, sources: values.length,
44
- ...totals, since: dates[0] ?? null, asOf: updates.at(-1) ?? null,
45
- estimatedSavedTokens: Math.round(totals.savedBytes / 4) };
46
- }
47
-
48
- /** Native all-time and retained personal MCP have different coverage and byte units. */
49
- export function formatLifetimeSavings(result) {
50
- const total = summarizeLifetimeSavings(result);
51
- const tokens = bytes => "~" + Math.round(bytes / 4).toLocaleString("en-US");
52
- const personal = new Map();
53
- for (const instance of result.mcp?.instances ?? []) personal.set(instance.instanceId, instance);
54
- const personalBytes = [...personal.values()].flatMap(instance => instance.metrics ?? [])
55
- .reduce((sum, metric) => sum + metric.savedBytes, 0);
56
- const personalKnown = [...personal.values()].some(instance => instance.metrics?.length) && count(personalBytes);
57
- const knownBytes = (total.available ? total.savedBytes : 0) + (personalKnown ? personalBytes : 0);
58
- const available = (total.available || personalKnown) && count(knownBytes);
59
- const partial = total.partial || !total.available || personal.size > 0 || Boolean(result.mcp?.unavailable);
60
- const lines = [available ?
61
- "All-time saved" + (partial ? " (partial)" : " (native)") + ": " + tokens(knownBytes) + " tokens" :
62
- "All-time saved: unavailable | historical measurements not reported"];
63
- if (total.available) lines.push("Native history: Raw " + tokens(total.originalBytes) + " | Sent " + tokens(total.sentBytes) +
64
- " | " + (total.originalBytes ? (100 * total.savedBytes / total.originalBytes).toFixed(1) : "0.0") + "% | " +
65
- (total.since ? "since " + total.since.slice(0, 10) + " | as of " + total.asOf.slice(0, 16).replace("T", " ") + "Z" : "no recorded results"));
66
- lines.push(personalKnown ?
67
- "Personal MCP (partial): " + tokens(personalBytes) + " tok retained" :
68
- "Personal MCP saved: unavailable (historical total not reported)");
69
- lines.push("Est: bytes/4; provider tokens unknown");
70
- return lines;
71
- }
1
+ // Scalar projections only. Never read a ledger, private state or provider data here.
2
+ const count = value => Number.isSafeInteger(value) && value >= 0 && value <= 1e15;
3
+ const date = value => typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
4
+
5
+ /** Invalid or older optional telemetry must not hide the rest of a computer. */
6
+ export function lifetimeSavingsView(raw) {
7
+ if (!raw || raw.scope !== "all_time" || raw.coverage !== "recorded_native_results" ||
8
+ ![raw.calls, raw.originalBytes, raw.sentBytes, raw.savedBytes].every(count) ||
9
+ raw.sentBytes > raw.originalBytes || raw.savedBytes !== raw.originalBytes - raw.sentBytes ||
10
+ (raw.calls === 0 ? raw.since !== null || raw.asOf !== null || raw.originalBytes !== 0 :
11
+ !date(raw.since) || !date(raw.asOf) || raw.since > raw.asOf)) return null;
12
+ return { scope: "all_time", coverage: "recorded_native_results", since: raw.since, asOf: raw.asOf,
13
+ calls: raw.calls, originalBytes: raw.originalBytes, sentBytes: raw.sentBytes, savedBytes: raw.savedBytes };
14
+ }
15
+
16
+ /** Aggregate complete scalar native histories, even when their producers have stopped. */
17
+ export function summarizeLifetimeSavings(result) {
18
+ const sources = new Map(), rejected = new Set();
19
+ let unavailable = result.unavailable ?? 0;
20
+ // Ascending counts expose old conflicts too, regardless of the reader's file order.
21
+ const snapshots = (result.instances ?? []).map(instance => ({
22
+ id: instance.savingsSourceId, value: lifetimeSavingsView(instance.lifetimeSavings)
23
+ })).sort((a, b) => (a.value?.calls ?? 0) - (b.value?.calls ?? 0));
24
+ for (const { id, value } of snapshots) {
25
+ if (typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id)) { unavailable++; continue; }
26
+ if (rejected.has(id)) continue;
27
+ const old = sources.get(id);
28
+ const conflict = old && (value?.calls === old.calls ?
29
+ Object.keys(old).some(key => value[key] !== old[key]) :
30
+ value && (["originalBytes", "sentBytes", "savedBytes"].some(key => value[key] < old[key]) ||
31
+ (old.since !== null && value.since > old.since) || (old.asOf !== null && value.asOf < old.asOf)));
32
+ if (!value || conflict) {
33
+ sources.delete(id); rejected.add(id); unavailable++; continue;
34
+ }
35
+ sources.set(id, value);
36
+ }
37
+ const values = [...sources.values()];
38
+ const totals = { calls: 0, originalBytes: 0, sentBytes: 0, savedBytes: 0 };
39
+ for (const value of values) for (const key of Object.keys(totals)) totals[key] += value[key];
40
+ if (!Object.values(totals).every(count)) return { available: false, partial: true, unavailable: unavailable + 1 };
41
+ const dates = values.map(value => value.since).filter(Boolean).sort();
42
+ const updates = values.map(value => value.asOf).filter(Boolean).sort();
43
+ return { available: values.length > 0, partial: unavailable > 0, unavailable, sources: values.length,
44
+ ...totals, since: dates[0] ?? null, asOf: updates.at(-1) ?? null,
45
+ estimatedSavedTokens: Math.round(totals.savedBytes / 4) };
46
+ }
47
+
48
+ /** Native all-time and retained personal MCP have different coverage and byte units. */
49
+ export function formatLifetimeSavings(result) {
50
+ const total = summarizeLifetimeSavings(result);
51
+ const tokens = bytes => "~" + Math.round(bytes / 4).toLocaleString("en-US");
52
+ const personal = new Map();
53
+ for (const instance of result.mcp?.instances ?? []) personal.set(instance.instanceId, instance);
54
+ const personalBytes = [...personal.values()].flatMap(instance => instance.metrics ?? [])
55
+ .reduce((sum, metric) => sum + metric.savedBytes, 0);
56
+ const personalKnown = [...personal.values()].some(instance => instance.metrics?.length) && count(personalBytes);
57
+ const knownBytes = (total.available ? total.savedBytes : 0) + (personalKnown ? personalBytes : 0);
58
+ const available = (total.available || personalKnown) && count(knownBytes);
59
+ const partial = total.partial || !total.available || personal.size > 0 || Boolean(result.mcp?.unavailable);
60
+ const lines = [available ?
61
+ "All-time saved" + (partial ? " (partial)" : " (native)") + ": " + tokens(knownBytes) + " tokens" :
62
+ "All-time saved: unavailable | historical measurements not reported"];
63
+ if (total.available) lines.push("Native history: Raw " + tokens(total.originalBytes) + " | Sent " + tokens(total.sentBytes) +
64
+ " | " + (total.originalBytes ? (100 * total.savedBytes / total.originalBytes).toFixed(1) : "0.0") + "% | " +
65
+ (total.since ? "since " + total.since.slice(0, 10) + " | as of " + total.asOf.slice(0, 16).replace("T", " ") + "Z" : "no recorded results"));
66
+ lines.push(personalKnown ?
67
+ "Personal MCP (partial): " + tokens(personalBytes) + " tok retained" :
68
+ "Personal MCP saved: unavailable (historical total not reported)");
69
+ lines.push("Est: bytes/4; provider tokens unknown");
70
+ return lines;
71
+ }