@skillstate/cli 2.0.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.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ // skillstate CLI shim (ESM) — @skillstate/cli bin entry.
3
+ import { main } from '../dist/index.js';
4
+
5
+ const code = await main(process.argv.slice(2), process.cwd());
6
+ process.exit(code);
@@ -0,0 +1,40 @@
1
+ import type { SkillStateConfig } from '@skillstate/core';
2
+ import type { ProceduralSpec, SkillState } from '@skillstate/core';
3
+ export declare const CLI_USAGE = "Usage: skillstate init | run [--config <path>] [--resume] | report [--format json|md]";
4
+ /** Parsed `run` flags. */
5
+ export interface RunFlags {
6
+ configPath?: string;
7
+ resume: boolean;
8
+ }
9
+ /** Parsed `report` flags. */
10
+ export interface ReportFlags {
11
+ format: 'json' | 'md';
12
+ }
13
+ /** Resolve `p` against `cwd` (absolute paths pass through). */
14
+ export declare function resolveInCwd(cwd: string, p: string): string;
15
+ /**
16
+ * Parse `run` flags: `--config <path>`, `--config=<path>`, `--resume`.
17
+ * Throws an `Error` with {@link CLI_USAGE} on unknown flags or a missing
18
+ * `--config` value.
19
+ */
20
+ export declare function parseRunArgs(args: string[]): RunFlags;
21
+ /**
22
+ * Parse `report` flags: `--format json|md` (default `json`).
23
+ * Throws an `Error` with {@link CLI_USAGE} on unknown/invalid flags.
24
+ */
25
+ export declare function parseReportArgs(args: string[]): ReportFlags;
26
+ /** Load config: `loadConfig(cwd)`, or the `--config` file overlaid with env. */
27
+ export declare function loadCliConfig(cwd: string, configPath?: string): SkillStateConfig;
28
+ /** Load the procedural spec: JSON file at `specPath`, else the builtin CTF spec. */
29
+ export declare function loadCliSpec(cwd: string, specPath: string): ProceduralSpec;
30
+ /** Load persisted state for `--resume` (null = fresh start, never throws). */
31
+ export declare function loadResumeState(cwd: string, statePath: string): SkillState | null;
32
+ /** Deterministic offline stub LLM: valid empty patch + `noop` action. */
33
+ export declare function stubLlmResponse(): string;
34
+ /**
35
+ * CLI entry: `argv` without the node/bin prefix, `cwd` defaulting to
36
+ * `process.cwd()`. Returns a process exit code (0 ok, 1 runtime error,
37
+ * 2 usage error). Never throws for usage errors.
38
+ */
39
+ export declare function main(argv: string[], cwd?: string): Promise<number>;
40
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOzD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnE,eAAO,MAAM,SAAS,0FACmE,CAAC;AAE1F,0BAA0B;AAC1B,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAMD,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAOD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CAyBrD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAsB3D;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAWhF;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAoBzE;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAOjF;AAED,yEAAyE;AACzE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AA6ID;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBxE"}
@@ -0,0 +1,302 @@
1
+ // skillstate CLI — init | run [--config <path>] [--resume] | report [--format json|md].
2
+ //
3
+ // @non-paper Wave-4 DX layer (additive): thin file orchestration over the
4
+ // paper-exact runtime. `run` uses a deterministic offline stub LLM (empty
5
+ // patch + `noop` action) so `init → run → report` works from a clean
6
+ // directory with no network; bring your own `LLMFn`/`LLMProvider` for real
7
+ // runs via the library API.
8
+ //
9
+ // Units are raw string CHARS throughout (paper §4.3).
10
+ /// <reference types="node" />
11
+ import * as fs from 'node:fs';
12
+ import * as path from 'node:path';
13
+ import { defaultConfig, loadConfig, mergeConfig, CONFIG_FILE_NAME, } from '@skillstate/core';
14
+ import { SkillStateRuntime } from '@skillstate/core';
15
+ import { TokenTracker } from '@skillstate/core';
16
+ import { atomicWriteFile } from '@skillstate/core';
17
+ import { migrate } from '@skillstate/core';
18
+ import { generateReport } from './dashboard.js';
19
+ import { INTERCODE_CTF_SPEC } from '@skillstate/core/schemas';
20
+ export const CLI_USAGE = 'Usage: skillstate init | run [--config <path>] [--resume] | report [--format json|md]';
21
+ function isRecord(value) {
22
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
23
+ }
24
+ /** Resolve `p` against `cwd` (absolute paths pass through). */
25
+ export function resolveInCwd(cwd, p) {
26
+ return path.isAbsolute(p) ? p : path.join(cwd, p);
27
+ }
28
+ function readJsonFile(absPath) {
29
+ const raw = fs.readFileSync(absPath, 'utf-8');
30
+ return JSON.parse(raw);
31
+ }
32
+ /**
33
+ * Parse `run` flags: `--config <path>`, `--config=<path>`, `--resume`.
34
+ * Throws an `Error` with {@link CLI_USAGE} on unknown flags or a missing
35
+ * `--config` value.
36
+ */
37
+ export function parseRunArgs(args) {
38
+ let configPath;
39
+ let resume = false;
40
+ for (let i = 0; i < args.length; i += 1) {
41
+ const arg = args[i];
42
+ if (arg === '--resume') {
43
+ resume = true;
44
+ }
45
+ else if (arg === '--config') {
46
+ const next = args[i + 1];
47
+ if (next === undefined || next.startsWith('--')) {
48
+ throw new Error(`Missing value for --config\n${CLI_USAGE}`);
49
+ }
50
+ configPath = next;
51
+ i += 1;
52
+ }
53
+ else if (arg.startsWith('--config=')) {
54
+ const value = arg.slice('--config='.length);
55
+ if (value.length === 0) {
56
+ throw new Error(`Missing value for --config\n${CLI_USAGE}`);
57
+ }
58
+ configPath = value;
59
+ }
60
+ else {
61
+ throw new Error(`Unknown flag for run: ${arg}\n${CLI_USAGE}`);
62
+ }
63
+ }
64
+ return { configPath, resume };
65
+ }
66
+ /**
67
+ * Parse `report` flags: `--format json|md` (default `json`).
68
+ * Throws an `Error` with {@link CLI_USAGE} on unknown/invalid flags.
69
+ */
70
+ export function parseReportArgs(args) {
71
+ let format = 'json';
72
+ for (let i = 0; i < args.length; i += 1) {
73
+ const arg = args[i];
74
+ if (arg === '--format') {
75
+ const next = args[i + 1];
76
+ if (next !== 'json' && next !== 'md') {
77
+ throw new Error(`Invalid --format (want json|md)\n${CLI_USAGE}`);
78
+ }
79
+ format = next;
80
+ i += 1;
81
+ }
82
+ else if (arg.startsWith('--format=')) {
83
+ const value = arg.slice('--format='.length);
84
+ if (value !== 'json' && value !== 'md') {
85
+ throw new Error(`Invalid --format (want json|md)\n${CLI_USAGE}`);
86
+ }
87
+ format = value;
88
+ }
89
+ else {
90
+ throw new Error(`Unknown flag for report: ${arg}\n${CLI_USAGE}`);
91
+ }
92
+ }
93
+ return { format };
94
+ }
95
+ /** Load config: `loadConfig(cwd)`, or the `--config` file overlaid with env. */
96
+ export function loadCliConfig(cwd, configPath) {
97
+ if (configPath === undefined) {
98
+ return loadConfig(cwd);
99
+ }
100
+ let parsed = {};
101
+ try {
102
+ parsed = readJsonFile(resolveInCwd(cwd, configPath));
103
+ }
104
+ catch {
105
+ parsed = {};
106
+ }
107
+ return mergeConfig(parsed);
108
+ }
109
+ /** Load the procedural spec: JSON file at `specPath`, else the builtin CTF spec. */
110
+ export function loadCliSpec(cwd, specPath) {
111
+ if (specPath === '@intercode-ctf') {
112
+ return INTERCODE_CTF_SPEC;
113
+ }
114
+ try {
115
+ const parsed = readJsonFile(resolveInCwd(cwd, specPath));
116
+ if (isRecord(parsed) &&
117
+ typeof parsed['id'] === 'string' &&
118
+ typeof parsed['name'] === 'string' &&
119
+ typeof parsed['instructions'] === 'string' &&
120
+ isRecord(parsed['schema']) &&
121
+ typeof parsed['version'] === 'string') {
122
+ return parsed;
123
+ }
124
+ }
125
+ catch {
126
+ // Fall through to the builtin below.
127
+ }
128
+ return INTERCODE_CTF_SPEC;
129
+ }
130
+ /** Load persisted state for `--resume` (null = fresh start, never throws). */
131
+ export function loadResumeState(cwd, statePath) {
132
+ try {
133
+ const parsed = readJsonFile(resolveInCwd(cwd, statePath));
134
+ return migrate(parsed).state;
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ }
140
+ /** Deterministic offline stub LLM: valid empty patch + `noop` action. */
141
+ export function stubLlmResponse() {
142
+ return `noop step\n\n\`\`\`json\n${JSON.stringify({ state_patch: {}, action: 'noop' })}\n\`\`\``;
143
+ }
144
+ async function cmdInit(cwd) {
145
+ const configPath = path.join(cwd, CONFIG_FILE_NAME);
146
+ const defaults = defaultConfig();
147
+ if (fs.existsSync(configPath) === false) {
148
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
149
+ fs.writeFileSync(configPath, `${JSON.stringify(defaults, null, 2)}\n`, 'utf-8');
150
+ console.log(`Created ${CONFIG_FILE_NAME}`);
151
+ }
152
+ else {
153
+ console.log(`${CONFIG_FILE_NAME} already exists`);
154
+ }
155
+ const specAbs = resolveInCwd(cwd, defaults.specPath);
156
+ if (fs.existsSync(specAbs) === false) {
157
+ fs.mkdirSync(path.dirname(specAbs), { recursive: true });
158
+ fs.writeFileSync(specAbs, `${JSON.stringify(INTERCODE_CTF_SPEC, null, 2)}\n`, 'utf-8');
159
+ console.log(`Created ${defaults.specPath}`);
160
+ }
161
+ return 0;
162
+ }
163
+ async function cmdRun(cwd, flags) {
164
+ const config = loadCliConfig(cwd, flags.configPath);
165
+ const spec = loadCliSpec(cwd, config.specPath);
166
+ const tracker = new TokenTracker({
167
+ platform: config.platform,
168
+ sessionName: config.sessionName,
169
+ });
170
+ const resumed = flags.resume ? loadResumeState(cwd, config.statePath) : null;
171
+ const runtime = new SkillStateRuntime({
172
+ spec,
173
+ llm: async () => stubLlmResponse(),
174
+ execute: async (action) => ({
175
+ content: `executed:${action}`,
176
+ timestamp: Date.now(),
177
+ source: 'cli',
178
+ }),
179
+ tracker,
180
+ maxValidationRetries: config.maxValidationRetries,
181
+ ...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),
182
+ ...(resumed !== null ? { initialState: resumed } : {}),
183
+ });
184
+ const maxSteps = config.maxSteps;
185
+ await runtime.run({ content: 'cli start', timestamp: Date.now(), source: 'cli' }, () => false, maxSteps);
186
+ const stateAbs = resolveInCwd(cwd, config.statePath);
187
+ await atomicWriteFile(stateAbs, JSON.stringify({ version: 1, state: runtime.state }));
188
+ const reportAbs = resolveInCwd(cwd, config.reportPath);
189
+ fs.mkdirSync(path.dirname(reportAbs), { recursive: true });
190
+ tracker.save(reportAbs);
191
+ console.log(`Ran ${tracker.getBookkeeping().stepCount} steps`);
192
+ return 0;
193
+ }
194
+ async function cmdReport(cwd, flags) {
195
+ const config = loadConfig(cwd);
196
+ const reportAbs = resolveInCwd(cwd, config.reportPath);
197
+ let raw;
198
+ try {
199
+ raw = fs.readFileSync(reportAbs, 'utf-8');
200
+ }
201
+ catch {
202
+ console.error(`No report at ${config.reportPath} (run first)`);
203
+ return 1;
204
+ }
205
+ let parsed;
206
+ try {
207
+ parsed = JSON.parse(raw);
208
+ }
209
+ catch {
210
+ console.error(`Corrupt report at ${config.reportPath}`);
211
+ return 1;
212
+ }
213
+ if (flags.format === 'json') {
214
+ console.log(raw);
215
+ return 0;
216
+ }
217
+ if (isRecord(parsed) === false) {
218
+ console.error(`Corrupt report at ${config.reportPath}`);
219
+ return 1;
220
+ }
221
+ const rec = parsed;
222
+ const steps = Array.isArray(rec['steps'])
223
+ ? rec['steps']
224
+ : [];
225
+ let stateChars = 0;
226
+ let conversationChars = 0;
227
+ let running = 0;
228
+ for (const s of steps) {
229
+ const pc = typeof s?.promptChars === 'number' && s.promptChars >= 0 ? s.promptChars : 0;
230
+ running += pc;
231
+ stateChars += pc;
232
+ conversationChars += running;
233
+ }
234
+ const metrics = isRecord(rec['metrics'])
235
+ ? rec['metrics']
236
+ : {
237
+ sessionName: config.sessionName,
238
+ totalChars: 0,
239
+ stepCount: steps.length,
240
+ averagePromptSize: 0,
241
+ };
242
+ const session = isRecord(rec['session'])
243
+ ? rec['session']
244
+ : {
245
+ name: config.sessionName,
246
+ platform: config.platform,
247
+ startedAt: new Date().toISOString(),
248
+ };
249
+ const md = generateReport({
250
+ metrics: {
251
+ sessionName: metrics.sessionName,
252
+ totalChars: metrics.totalChars,
253
+ stepCount: metrics.stepCount,
254
+ averagePromptSize: metrics.averagePromptSize,
255
+ accuracy: metrics.accuracy ?? null,
256
+ },
257
+ comparison: {
258
+ conversationChars,
259
+ stateChars,
260
+ reductionFactor: stateChars > 0 ? conversationChars / stateChars : 0,
261
+ },
262
+ history: steps,
263
+ session: {
264
+ name: session.name,
265
+ platform: session.platform,
266
+ startedAt: session.startedAt,
267
+ },
268
+ });
269
+ console.log(md);
270
+ return 0;
271
+ }
272
+ /**
273
+ * CLI entry: `argv` without the node/bin prefix, `cwd` defaulting to
274
+ * `process.cwd()`. Returns a process exit code (0 ok, 1 runtime error,
275
+ * 2 usage error). Never throws for usage errors.
276
+ */
277
+ export async function main(argv, cwd) {
278
+ const dir = cwd ?? process.cwd();
279
+ const [command, ...rest] = argv;
280
+ try {
281
+ if (command === 'init') {
282
+ if (rest.length > 0) {
283
+ console.error(`Unknown flag for init: ${rest[0]}\n${CLI_USAGE}`);
284
+ return 2;
285
+ }
286
+ return await cmdInit(dir);
287
+ }
288
+ if (command === 'run') {
289
+ return await cmdRun(dir, parseRunArgs(rest));
290
+ }
291
+ if (command === 'report') {
292
+ return await cmdReport(dir, parseReportArgs(rest));
293
+ }
294
+ console.error(CLI_USAGE);
295
+ return 2;
296
+ }
297
+ catch (error) {
298
+ console.error(error instanceof Error ? error.message : String(error));
299
+ return 2;
300
+ }
301
+ }
302
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { ExecutionStep } from '@skillstate/core';
2
+ export interface DashboardMetrics {
3
+ sessionName: string;
4
+ totalChars: number;
5
+ totalPromptChars?: number;
6
+ stepCount: number;
7
+ averagePromptSize: number;
8
+ /** Task Accuracy (paper §4.3). Null/undefined renders as 'n/a'. */
9
+ accuracy?: number | null;
10
+ lastStepTimestamp?: number | null;
11
+ }
12
+ export interface BaselineComparison {
13
+ conversationChars: number;
14
+ stateChars: number;
15
+ reductionFactor: number;
16
+ }
17
+ export interface SessionInfo {
18
+ name: string;
19
+ platform: string;
20
+ startedAt: string | number;
21
+ }
22
+ export interface BudgetProgress {
23
+ used: number;
24
+ budget: number;
25
+ }
26
+ export interface ReportInput {
27
+ metrics: DashboardMetrics;
28
+ comparison: BaselineComparison;
29
+ history: ExecutionStep[];
30
+ session: SessionInfo;
31
+ }
32
+ export interface DashboardInput extends ReportInput {
33
+ progress?: BudgetProgress;
34
+ }
35
+ export declare function formatMetricsTable(metrics: DashboardMetrics): string;
36
+ export declare function formatComparisonTable(comparison: BaselineComparison): string;
37
+ export declare function formatStepHistory(steps: ExecutionStep[]): string;
38
+ export declare function formatProgressBar(progressOrPercent: BudgetProgress | number, width?: number): string;
39
+ export declare function generateReport(input: ReportInput): string;
40
+ export declare function printDashboard(input: DashboardInput): string;
41
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAQtD,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAID,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAID,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAGD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AA4ED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAqBpE;AAMD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAY5E;AAMD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAehE;AAQD,wBAAgB,iBAAiB,CAC/B,iBAAiB,EAAE,cAAc,GAAG,MAAM,EAC1C,KAAK,GAAE,MAAW,GACjB,MAAM,CAeR;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA0BzD;AAQD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAkC5D"}
@@ -0,0 +1,187 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Internal helpers
3
+ // ---------------------------------------------------------------------------
4
+ const RESET = '\x1b[0m';
5
+ const CYAN = '\x1b[36m';
6
+ const DIM = '\x1b[2m';
7
+ const BOLD = '\x1b[1m';
8
+ // Checked at call time (not module load) so env changes like FORCE_COLOR
9
+ // set by tests are honored.
10
+ function colorEnabled() {
11
+ if (process.env['NO_COLOR'])
12
+ return false;
13
+ const force = process.env['FORCE_COLOR'];
14
+ if (force !== undefined && force !== '')
15
+ return force !== '0';
16
+ return Boolean(process.stdout?.isTTY);
17
+ }
18
+ function paint(text, code) {
19
+ if (!colorEnabled())
20
+ return text;
21
+ return `${code}${text}${RESET}`;
22
+ }
23
+ // Plain number formatting — never locale-aware (tests assert exact digits,
24
+ // e.g. "4500" must not become "4,500"). Integers print exactly; fractions
25
+ // are trimmed to one decimal.
26
+ function fmtNum(n) {
27
+ if (Number.isInteger(n))
28
+ return String(n);
29
+ return String(Math.round(n * 10) / 10);
30
+ }
31
+ function truncate(text, max) {
32
+ return text.length > max ? `${text.slice(0, Math.max(0, max - 3))}...` : text;
33
+ }
34
+ // Renders a timestamp that may be an epoch-ms number or an ISO string.
35
+ // Falls back to the raw value when unparsable.
36
+ function formatTimestamp(ts) {
37
+ const d = new Date(ts);
38
+ return Number.isNaN(d.getTime()) ? String(ts) : d.toISOString();
39
+ }
40
+ // Renders a box-drawing table with computed column widths.
41
+ // Precondition: every row has exactly one cell per header column —
42
+ // all call sites construct rows via .map over the column list, and
43
+ // `widths` is derived from `headers`, so index access is always in range.
44
+ function renderTable(title, headers, rows) {
45
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
46
+ const bar = (left, mid, right) => left + widths.map((w) => '─'.repeat(w + 2)).join(mid) + right;
47
+ const lines = [paint(title, BOLD)];
48
+ lines.push(bar('┌', '┬', '┐'));
49
+ lines.push(`│${headers.map((h, i) => ` ${h.padEnd(widths[i], ' ')} `).join('│')}│`);
50
+ lines.push(bar('├', '┼', '┤'));
51
+ for (const row of rows) {
52
+ lines.push(`│${headers
53
+ .map((_, i) => ` ${row[i].padEnd(widths[i], ' ')} `)
54
+ .join('│')}│`);
55
+ }
56
+ lines.push(bar('└', '┴', '┘'));
57
+ return lines.join('\n');
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // 1. formatMetricsTable
61
+ // ---------------------------------------------------------------------------
62
+ export function formatMetricsTable(metrics) {
63
+ // Task Accuracy (paper §4.3): '75.0%' when actionable steps exist, 'n/a'
64
+ // otherwise (null from TokenTracker, or absent on legacy metric shapes).
65
+ const accuracyText = metrics.accuracy == null
66
+ ? 'n/a'
67
+ : `${(metrics.accuracy * 100).toFixed(1)}%`;
68
+ const rows = [
69
+ ['Session', metrics.sessionName],
70
+ ['Total Chars', fmtNum(metrics.totalChars)],
71
+ ['Steps', fmtNum(metrics.stepCount)],
72
+ ['Accuracy', accuracyText],
73
+ ['Avg Prompt Size', `${fmtNum(metrics.averagePromptSize)} chars`],
74
+ ];
75
+ return renderTable(`Session Metrics (${metrics.sessionName})`, ['Metric', 'Value'], rows);
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // 2. formatComparisonTable
79
+ // ---------------------------------------------------------------------------
80
+ export function formatComparisonTable(comparison) {
81
+ const rows = [
82
+ ['Conversation Chars', fmtNum(comparison.conversationChars)],
83
+ ['State Chars', fmtNum(comparison.stateChars)],
84
+ ['Reduction Factor', `${comparison.reductionFactor.toFixed(1)}x`],
85
+ ];
86
+ return renderTable('Comparison vs Conversation Baseline', ['Metric', 'Value'], rows);
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // 3. formatStepHistory
90
+ // ---------------------------------------------------------------------------
91
+ export function formatStepHistory(steps) {
92
+ const rows = steps.length
93
+ ? steps.map((s) => [
94
+ String(s.step),
95
+ truncate(s.action ?? '', 24),
96
+ fmtNum(s.promptChars),
97
+ fmtNum(s.responseChars),
98
+ ])
99
+ : [['-', '(no steps recorded)', '-', '-']];
100
+ return renderTable('Step History', ['Step', 'Action', 'Prompt Chars', 'Response Chars'], rows);
101
+ }
102
+ // ---------------------------------------------------------------------------
103
+ // 4. formatProgressBar
104
+ // ---------------------------------------------------------------------------
105
+ // Accepts either a ready percent or a { used, budget } pair (as supplied by
106
+ // the CLI when rendering token budget usage). Width defaults to 20 cells.
107
+ export function formatProgressBar(progressOrPercent, width = 20) {
108
+ let percent;
109
+ if (typeof progressOrPercent === 'number') {
110
+ percent = progressOrPercent;
111
+ }
112
+ else {
113
+ const { used, budget } = progressOrPercent;
114
+ percent = budget > 0 ? (used / budget) * 100 : 0;
115
+ }
116
+ const clamped = Math.max(0, Math.min(100, percent));
117
+ const filled = Math.round((clamped / 100) * width);
118
+ const empty = width - filled;
119
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
120
+ return `[${bar}] ${Math.round(clamped)}%`;
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // 5. generateReport
124
+ // ---------------------------------------------------------------------------
125
+ export function generateReport(input) {
126
+ const { metrics, comparison, history, session } = input;
127
+ const generatedAt = new Date().toISOString();
128
+ const startedAt = formatTimestamp(session.startedAt);
129
+ return [
130
+ `# SkillState Report: ${session.name}`,
131
+ '',
132
+ `- **Generated:** ${generatedAt}`,
133
+ `- **Platform:** ${session.platform}`,
134
+ `- **Session:** ${session.name}`,
135
+ `- **Started:** ${startedAt}`,
136
+ '',
137
+ '## Metrics',
138
+ '',
139
+ formatMetricsTable(metrics),
140
+ '',
141
+ '## Comparison',
142
+ '',
143
+ formatComparisonTable(comparison),
144
+ '',
145
+ '## Step History',
146
+ '',
147
+ formatStepHistory(history),
148
+ '',
149
+ ].join('\n');
150
+ }
151
+ // ---------------------------------------------------------------------------
152
+ // 6. printDashboard
153
+ // ---------------------------------------------------------------------------
154
+ // Composes the full terminal dashboard as a string. Never prints — callers
155
+ // decide whether to write it to the console.
156
+ export function printDashboard(input) {
157
+ const { metrics, comparison, history, session, progress } = input;
158
+ const separator = paint('═'.repeat(60), CYAN);
159
+ const parts = [
160
+ separator,
161
+ paint(' SKILLSTATE DASHBOARD', BOLD),
162
+ separator,
163
+ '',
164
+ `Session: ${session.name} (${session.platform})`,
165
+ `Started: ${formatTimestamp(session.startedAt)}`,
166
+ '',
167
+ paint('── Metrics ' + '─'.repeat(47), DIM),
168
+ '',
169
+ formatMetricsTable(metrics),
170
+ ];
171
+ if (progress) {
172
+ parts.push('');
173
+ parts.push(`Budget: ${formatProgressBar(progress)} (${progress.used}/${progress.budget} chars)`);
174
+ }
175
+ parts.push('');
176
+ parts.push(paint('── Comparison ' + '─'.repeat(45), DIM));
177
+ parts.push('');
178
+ parts.push(formatComparisonTable(comparison));
179
+ parts.push('');
180
+ parts.push(paint('── Step History ' + '─'.repeat(43), DIM));
181
+ parts.push('');
182
+ parts.push(formatStepHistory(history));
183
+ parts.push('');
184
+ parts.push(separator);
185
+ return parts.join('\n');
186
+ }
187
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './commands.js';
2
+ export * from './dashboard.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @skillstate/cli — skillstate CLI commands + dashboard.
2
+ export * from './commands.js';
3
+ export * from './dashboard.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@skillstate/cli",
3
+ "version": "2.0.0",
4
+ "description": "skillstate CLI — init | run | report.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "skillstate": "bin/skillstate.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "files": ["dist", "bin"],
19
+ "sideEffects": false,
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@skillstate/core": "^2.0.0"
26
+ }
27
+ }