selftune 0.2.13 → 0.2.15
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/apps/local-dashboard/dist/assets/index-BMIS6uUh.css +2 -0
- package/apps/local-dashboard/dist/assets/index-DOu3iLD9.js +16 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-DIwlrGlb.js +12 -0
- package/apps/local-dashboard/dist/index.html +3 -3
- package/cli/selftune/activation-rules.ts +24 -48
- package/cli/selftune/analytics.ts +13 -11
- package/cli/selftune/badge/badge.ts +13 -9
- package/cli/selftune/canonical-export.ts +6 -6
- package/cli/selftune/constants.ts +7 -0
- package/cli/selftune/contribute/bundle.ts +9 -44
- package/cli/selftune/contribute/contribute.ts +2 -1
- package/cli/selftune/cron/setup.ts +3 -1
- package/cli/selftune/dashboard-contract.ts +22 -0
- package/cli/selftune/dashboard.ts +10 -5
- package/cli/selftune/eval/baseline.ts +20 -30
- package/cli/selftune/eval/hooks-to-evals.ts +27 -34
- package/cli/selftune/eval/import-skillsbench.ts +21 -8
- package/cli/selftune/eval/unit-test-cli.ts +22 -11
- package/cli/selftune/evolution/description-quality.ts +224 -0
- package/cli/selftune/evolution/evolve-body.ts +17 -10
- package/cli/selftune/evolution/evolve.ts +70 -57
- package/cli/selftune/evolution/rollback.ts +7 -6
- package/cli/selftune/grading/auto-grade.ts +27 -35
- package/cli/selftune/grading/grade-session.ts +24 -30
- package/cli/selftune/hooks/auto-activate.ts +12 -3
- package/cli/selftune/hooks/evolution-guard.ts +14 -24
- package/cli/selftune/hooks/prompt-log.ts +7 -9
- package/cli/selftune/hooks/session-stop.ts +0 -8
- package/cli/selftune/index.ts +66 -69
- package/cli/selftune/ingestors/claude-replay.ts +29 -14
- package/cli/selftune/ingestors/codex-rollout.ts +15 -5
- package/cli/selftune/ingestors/codex-wrapper.ts +15 -13
- package/cli/selftune/ingestors/openclaw-ingest.ts +24 -5
- package/cli/selftune/ingestors/opencode-ingest.ts +9 -4
- package/cli/selftune/init.ts +14 -9
- package/cli/selftune/localdb/queries.ts +57 -0
- package/cli/selftune/monitoring/watch.ts +39 -38
- package/cli/selftune/normalization.ts +2 -23
- package/cli/selftune/orchestrate.ts +224 -24
- package/cli/selftune/routes/skill-report.ts +17 -0
- package/cli/selftune/schedule.ts +74 -14
- package/cli/selftune/sync.ts +7 -3
- package/cli/selftune/types.ts +44 -10
- package/cli/selftune/utils/cli-error.ts +102 -0
- package/cli/selftune/utils/jsonl.ts +2 -0
- package/cli/selftune/workflows/workflows.ts +23 -17
- package/package.json +3 -1
- package/packages/ui/src/components/RecentActivityFeed.tsx +86 -0
- package/packages/ui/src/components/index.ts +1 -0
- package/packages/ui/src/components/section-cards.tsx +13 -0
- package/skill/SKILL.md +1 -1
- package/skill/Workflows/Evolve.md +4 -0
- package/skill/Workflows/Initialize.md +8 -8
- package/skill/Workflows/Orchestrate.md +11 -7
- package/skill/Workflows/Schedule.md +11 -0
- package/skill/references/logs.md +22 -21
- package/skill/settings_snippet.json +29 -6
- package/apps/local-dashboard/dist/assets/index-4_dAY17K.js +0 -16
- package/apps/local-dashboard/dist/assets/index-BxV5WZHc.css +0 -2
- package/apps/local-dashboard/dist/assets/vendor-ui-7xD7fNEU.js +0 -12
package/cli/selftune/index.ts
CHANGED
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
* selftune hook <name> — Run a hook by name (prompt-log, session-stop, etc.)
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
+
import { CLIError, handleCLIError } from "./utils/cli-error.js";
|
|
33
|
+
|
|
34
|
+
process.on("uncaughtException", handleCLIError);
|
|
35
|
+
process.on("unhandledRejection", handleCLIError);
|
|
36
|
+
|
|
32
37
|
const command = process.argv[2];
|
|
33
38
|
|
|
34
39
|
if (command === "--help" || command === "-h") {
|
|
@@ -84,6 +89,7 @@ if (!command) {
|
|
|
84
89
|
// Show status by default — same as `selftune status`
|
|
85
90
|
const { cliMain: statusMain } = await import("./status.js");
|
|
86
91
|
statusMain();
|
|
92
|
+
process.exit(0);
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
// Route to the appropriate subcommand module.
|
|
@@ -142,10 +148,11 @@ Run 'selftune ingest <agent> --help' for agent-specific options.`);
|
|
|
142
148
|
break;
|
|
143
149
|
}
|
|
144
150
|
default:
|
|
145
|
-
|
|
146
|
-
`Unknown ingest agent: ${sub}
|
|
151
|
+
throw new CLIError(
|
|
152
|
+
`Unknown ingest agent: ${sub}`,
|
|
153
|
+
"UNKNOWN_COMMAND",
|
|
154
|
+
"selftune ingest --help",
|
|
147
155
|
);
|
|
148
|
-
process.exit(1);
|
|
149
156
|
}
|
|
150
157
|
break;
|
|
151
158
|
}
|
|
@@ -182,10 +189,11 @@ Run 'selftune grade <subcommand> --help' for subcommand-specific options.`);
|
|
|
182
189
|
break;
|
|
183
190
|
}
|
|
184
191
|
default:
|
|
185
|
-
|
|
186
|
-
`Unknown grade mode: ${sub}
|
|
192
|
+
throw new CLIError(
|
|
193
|
+
`Unknown grade mode: ${sub}`,
|
|
194
|
+
"UNKNOWN_COMMAND",
|
|
195
|
+
"selftune grade --help",
|
|
187
196
|
);
|
|
188
|
-
process.exit(1);
|
|
189
197
|
}
|
|
190
198
|
}
|
|
191
199
|
break;
|
|
@@ -223,10 +231,11 @@ Run 'selftune evolve <subcommand> --help' for subcommand-specific options.`);
|
|
|
223
231
|
break;
|
|
224
232
|
}
|
|
225
233
|
default:
|
|
226
|
-
|
|
227
|
-
`Unknown evolve target: ${sub}
|
|
234
|
+
throw new CLIError(
|
|
235
|
+
`Unknown evolve target: ${sub}`,
|
|
236
|
+
"UNKNOWN_COMMAND",
|
|
237
|
+
"selftune evolve --help",
|
|
228
238
|
);
|
|
229
|
-
process.exit(1);
|
|
230
239
|
}
|
|
231
240
|
}
|
|
232
241
|
break;
|
|
@@ -289,13 +298,18 @@ Run 'selftune eval <action> --help' for action-specific options.`);
|
|
|
289
298
|
}));
|
|
290
299
|
} catch (error) {
|
|
291
300
|
const message = error instanceof Error ? error.message : String(error);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
301
|
+
throw new CLIError(
|
|
302
|
+
`Invalid arguments: ${message}`,
|
|
303
|
+
"INVALID_FLAG",
|
|
304
|
+
"selftune eval composability --help",
|
|
305
|
+
);
|
|
295
306
|
}
|
|
296
307
|
if (!values.skill) {
|
|
297
|
-
|
|
298
|
-
|
|
308
|
+
throw new CLIError(
|
|
309
|
+
"--skill <name> is required.",
|
|
310
|
+
"MISSING_FLAG",
|
|
311
|
+
"selftune eval composability --skill <name>",
|
|
312
|
+
);
|
|
299
313
|
}
|
|
300
314
|
const logPath = values["telemetry-log"] ?? TELEMETRY_LOG;
|
|
301
315
|
let telemetry: unknown[];
|
|
@@ -316,8 +330,11 @@ Run 'selftune eval <action> --help' for action-specific options.`);
|
|
|
316
330
|
}
|
|
317
331
|
const rawWindow = values.window as string | undefined;
|
|
318
332
|
if (rawWindow !== undefined && !/^[1-9]\d*$/.test(rawWindow)) {
|
|
319
|
-
|
|
320
|
-
|
|
333
|
+
throw new CLIError(
|
|
334
|
+
"Invalid --window value. Use a positive integer number of days.",
|
|
335
|
+
"INVALID_FLAG",
|
|
336
|
+
"selftune eval composability --skill <name> --window 30",
|
|
337
|
+
);
|
|
321
338
|
}
|
|
322
339
|
const windowSize = rawWindow === undefined ? undefined : Number(rawWindow);
|
|
323
340
|
const report = analyzeComposability(values.skill, telemetry, windowSize);
|
|
@@ -325,10 +342,11 @@ Run 'selftune eval <action> --help' for action-specific options.`);
|
|
|
325
342
|
break;
|
|
326
343
|
}
|
|
327
344
|
default:
|
|
328
|
-
|
|
329
|
-
`Unknown eval action: ${sub}
|
|
345
|
+
throw new CLIError(
|
|
346
|
+
`Unknown eval action: ${sub}`,
|
|
347
|
+
"UNKNOWN_COMMAND",
|
|
348
|
+
"selftune eval --help",
|
|
330
349
|
);
|
|
331
|
-
process.exit(1);
|
|
332
350
|
}
|
|
333
351
|
break;
|
|
334
352
|
}
|
|
@@ -457,10 +475,11 @@ Run 'selftune cron <subcommand> --help' for subcommand-specific options.`);
|
|
|
457
475
|
break;
|
|
458
476
|
}
|
|
459
477
|
default:
|
|
460
|
-
|
|
461
|
-
`Unknown cron subcommand: ${sub}
|
|
478
|
+
throw new CLIError(
|
|
479
|
+
`Unknown cron subcommand: ${sub}`,
|
|
480
|
+
"UNKNOWN_COMMAND",
|
|
481
|
+
"selftune cron --help",
|
|
462
482
|
);
|
|
463
|
-
process.exit(1);
|
|
464
483
|
}
|
|
465
484
|
break;
|
|
466
485
|
}
|
|
@@ -505,9 +524,7 @@ Run 'selftune cron <subcommand> --help' for subcommand-specific options.`);
|
|
|
505
524
|
}));
|
|
506
525
|
} catch (error) {
|
|
507
526
|
const message = error instanceof Error ? error.message : String(error);
|
|
508
|
-
|
|
509
|
-
console.error("Run 'selftune export --help' for usage.");
|
|
510
|
-
process.exit(1);
|
|
527
|
+
throw new CLIError(`Invalid arguments: ${message}`, "INVALID_FLAG", "selftune export --help");
|
|
511
528
|
}
|
|
512
529
|
if (values.help) {
|
|
513
530
|
console.log(`selftune export — Export SQLite data to JSONL files
|
|
@@ -544,9 +561,7 @@ Options:
|
|
|
544
561
|
}
|
|
545
562
|
} catch (err: unknown) {
|
|
546
563
|
const message = err instanceof Error ? err.message : String(err);
|
|
547
|
-
|
|
548
|
-
console.error("Ensure the SQLite database exists. Run 'selftune sync' first if needed.");
|
|
549
|
-
process.exit(1);
|
|
564
|
+
throw new CLIError(`Export failed: ${message}`, "OPERATION_FAILED", "selftune sync");
|
|
550
565
|
}
|
|
551
566
|
break;
|
|
552
567
|
}
|
|
@@ -590,8 +605,11 @@ Run 'selftune alpha <subcommand> --help' for subcommand-specific options.`);
|
|
|
590
605
|
}));
|
|
591
606
|
} catch (error) {
|
|
592
607
|
const message = error instanceof Error ? error.message : String(error);
|
|
593
|
-
|
|
594
|
-
|
|
608
|
+
throw new CLIError(
|
|
609
|
+
`Invalid arguments: ${message}`,
|
|
610
|
+
"INVALID_FLAG",
|
|
611
|
+
"selftune alpha upload --help",
|
|
612
|
+
);
|
|
595
613
|
}
|
|
596
614
|
if (values.help) {
|
|
597
615
|
console.log(`selftune alpha upload — Run a manual alpha data upload cycle
|
|
@@ -619,44 +637,20 @@ Output:
|
|
|
619
637
|
const identity = readAlphaIdentity(SELFTUNE_CONFIG_PATH);
|
|
620
638
|
if (!identity?.enrolled) {
|
|
621
639
|
const guidance = getAlphaGuidance(identity);
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
prepared: 0,
|
|
627
|
-
sent: 0,
|
|
628
|
-
failed: 0,
|
|
629
|
-
skipped: 0,
|
|
630
|
-
guidance,
|
|
631
|
-
},
|
|
632
|
-
null,
|
|
633
|
-
2,
|
|
634
|
-
),
|
|
640
|
+
throw new CLIError(
|
|
641
|
+
`[alpha upload] ${guidance.message}`,
|
|
642
|
+
"OPERATION_FAILED",
|
|
643
|
+
guidance.next_command,
|
|
635
644
|
);
|
|
636
|
-
console.error(`[alpha upload] ${guidance.message}`);
|
|
637
|
-
console.error(`[alpha upload] Next: ${guidance.next_command}`);
|
|
638
|
-
process.exit(1);
|
|
639
645
|
}
|
|
640
646
|
|
|
641
647
|
if (!identity.user_id?.trim() || !identity.api_key?.trim()) {
|
|
642
648
|
const guidance = getAlphaGuidance(identity);
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
prepared: 0,
|
|
648
|
-
sent: 0,
|
|
649
|
-
failed: 0,
|
|
650
|
-
skipped: 0,
|
|
651
|
-
guidance,
|
|
652
|
-
},
|
|
653
|
-
null,
|
|
654
|
-
2,
|
|
655
|
-
),
|
|
649
|
+
throw new CLIError(
|
|
650
|
+
`[alpha upload] ${guidance.message}`,
|
|
651
|
+
"OPERATION_FAILED",
|
|
652
|
+
guidance.next_command,
|
|
656
653
|
);
|
|
657
|
-
console.error(`[alpha upload] ${guidance.message}`);
|
|
658
|
-
console.error(`[alpha upload] Next: ${guidance.next_command}`);
|
|
659
|
-
process.exit(1);
|
|
660
654
|
}
|
|
661
655
|
|
|
662
656
|
const db = getDb();
|
|
@@ -742,10 +736,11 @@ Output:
|
|
|
742
736
|
break;
|
|
743
737
|
}
|
|
744
738
|
default:
|
|
745
|
-
|
|
746
|
-
`Unknown alpha subcommand: ${sub}
|
|
739
|
+
throw new CLIError(
|
|
740
|
+
`Unknown alpha subcommand: ${sub}`,
|
|
741
|
+
"UNKNOWN_COMMAND",
|
|
742
|
+
"selftune alpha --help",
|
|
747
743
|
);
|
|
748
|
-
process.exit(1);
|
|
749
744
|
}
|
|
750
745
|
break;
|
|
751
746
|
}
|
|
@@ -767,8 +762,11 @@ Output:
|
|
|
767
762
|
};
|
|
768
763
|
if (!hookName || !HOOK_MAP[hookName]) {
|
|
769
764
|
const available = Object.keys(HOOK_MAP).join(", ");
|
|
770
|
-
|
|
771
|
-
|
|
765
|
+
throw new CLIError(
|
|
766
|
+
`Unknown hook: ${hookName ?? "(none)"}. Available: ${available}`,
|
|
767
|
+
"UNKNOWN_COMMAND",
|
|
768
|
+
"selftune hook prompt-log",
|
|
769
|
+
);
|
|
772
770
|
}
|
|
773
771
|
const { resolve, dirname } = await import("node:path");
|
|
774
772
|
const { fileURLToPath } = await import("node:url");
|
|
@@ -782,6 +780,5 @@ Output:
|
|
|
782
780
|
break;
|
|
783
781
|
}
|
|
784
782
|
default:
|
|
785
|
-
|
|
786
|
-
process.exit(1);
|
|
783
|
+
throw new CLIError(`Unknown command: ${command}`, "UNKNOWN_COMMAND", "selftune --help");
|
|
787
784
|
}
|
|
@@ -55,6 +55,7 @@ import type {
|
|
|
55
55
|
SessionTelemetryRecord,
|
|
56
56
|
TranscriptMetrics,
|
|
57
57
|
} from "../types.js";
|
|
58
|
+
import { CLIError, handleCLIError } from "../utils/cli-error.js";
|
|
58
59
|
import { loadMarker, saveMarker } from "../utils/jsonl.js";
|
|
59
60
|
import { isActionableQueryText } from "../utils/query-filter.js";
|
|
60
61
|
import {
|
|
@@ -326,26 +327,36 @@ export function buildCanonicalRecordsFromReplay(session: ParsedSession): Canonic
|
|
|
326
327
|
|
|
327
328
|
// --- CLI main ---
|
|
328
329
|
export function cliMain(): void {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
330
|
+
let values: Record<string, string | boolean | undefined>;
|
|
331
|
+
try {
|
|
332
|
+
({ values } = parseArgs({
|
|
333
|
+
options: {
|
|
334
|
+
"projects-dir": { type: "string", default: CLAUDE_CODE_PROJECTS_DIR },
|
|
335
|
+
since: { type: "string" },
|
|
336
|
+
"dry-run": { type: "boolean", default: false },
|
|
337
|
+
force: { type: "boolean", default: false },
|
|
338
|
+
verbose: { type: "boolean", short: "v", default: false },
|
|
339
|
+
},
|
|
340
|
+
strict: true,
|
|
341
|
+
}));
|
|
342
|
+
} catch (err) {
|
|
343
|
+
throw new CLIError(
|
|
344
|
+
err instanceof Error ? err.message : String(err),
|
|
345
|
+
"INVALID_FLAG",
|
|
346
|
+
"selftune ingest claude --since 2026-01-01",
|
|
347
|
+
);
|
|
348
|
+
}
|
|
339
349
|
|
|
340
350
|
const projectsDir = values["projects-dir"] ?? CLAUDE_CODE_PROJECTS_DIR;
|
|
341
351
|
let since: Date | undefined;
|
|
342
352
|
if (values.since) {
|
|
343
353
|
since = new Date(values.since);
|
|
344
354
|
if (Number.isNaN(since.getTime())) {
|
|
345
|
-
|
|
346
|
-
`
|
|
355
|
+
throw new CLIError(
|
|
356
|
+
`Invalid --since date: "${values.since}"`,
|
|
357
|
+
"INVALID_FLAG",
|
|
358
|
+
"selftune ingest claude --since 2026-01-01",
|
|
347
359
|
);
|
|
348
|
-
process.exit(1);
|
|
349
360
|
}
|
|
350
361
|
}
|
|
351
362
|
|
|
@@ -401,5 +412,9 @@ export function cliMain(): void {
|
|
|
401
412
|
}
|
|
402
413
|
|
|
403
414
|
if (import.meta.main) {
|
|
404
|
-
|
|
415
|
+
try {
|
|
416
|
+
cliMain();
|
|
417
|
+
} catch (err) {
|
|
418
|
+
handleCLIError(err);
|
|
419
|
+
}
|
|
405
420
|
}
|
|
@@ -27,6 +27,11 @@ import { basename, join } from "node:path";
|
|
|
27
27
|
import { parseArgs } from "node:util";
|
|
28
28
|
|
|
29
29
|
import { CANONICAL_LOG, QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
30
|
+
import {
|
|
31
|
+
writeQueryToDb,
|
|
32
|
+
writeSessionTelemetryToDb,
|
|
33
|
+
writeSkillUsageToDb,
|
|
34
|
+
} from "../localdb/direct-write.js";
|
|
30
35
|
import {
|
|
31
36
|
appendCanonicalRecords,
|
|
32
37
|
buildCanonicalExecutionFact,
|
|
@@ -44,7 +49,8 @@ import type {
|
|
|
44
49
|
SessionTelemetryRecord,
|
|
45
50
|
SkillUsageRecord,
|
|
46
51
|
} from "../types.js";
|
|
47
|
-
import {
|
|
52
|
+
import { handleCLIError } from "../utils/cli-error.js";
|
|
53
|
+
import { loadMarker, saveMarker } from "../utils/jsonl.js";
|
|
48
54
|
import { extractActionableQueryText } from "../utils/query-filter.js";
|
|
49
55
|
import {
|
|
50
56
|
classifySkillPath,
|
|
@@ -490,7 +496,7 @@ export function ingestFile(
|
|
|
490
496
|
query: prompt,
|
|
491
497
|
source: "codex_rollout",
|
|
492
498
|
};
|
|
493
|
-
|
|
499
|
+
writeQueryToDb(queryRecord);
|
|
494
500
|
}
|
|
495
501
|
|
|
496
502
|
// Write telemetry — explicitly select SessionTelemetryRecord fields
|
|
@@ -513,7 +519,7 @@ export function ingestFile(
|
|
|
513
519
|
output_tokens: parsed.output_tokens,
|
|
514
520
|
rollout_path: parsed.rollout_path,
|
|
515
521
|
};
|
|
516
|
-
|
|
522
|
+
writeSessionTelemetryToDb(telemetry);
|
|
517
523
|
|
|
518
524
|
// Write skill triggers
|
|
519
525
|
for (const skillName of skills) {
|
|
@@ -537,7 +543,7 @@ export function ingestFile(
|
|
|
537
543
|
triggered: true,
|
|
538
544
|
source: isExplicit ? "codex_rollout_explicit" : "codex_rollout",
|
|
539
545
|
};
|
|
540
|
-
|
|
546
|
+
writeSkillUsageToDb(skillRecord);
|
|
541
547
|
}
|
|
542
548
|
|
|
543
549
|
// --- Canonical normalization records (additive) ---
|
|
@@ -712,5 +718,9 @@ export function cliMain(): void {
|
|
|
712
718
|
}
|
|
713
719
|
|
|
714
720
|
if (import.meta.main) {
|
|
715
|
-
|
|
721
|
+
try {
|
|
722
|
+
cliMain();
|
|
723
|
+
} catch (err) {
|
|
724
|
+
handleCLIError(err);
|
|
725
|
+
}
|
|
716
726
|
}
|
|
@@ -11,16 +11,19 @@
|
|
|
11
11
|
* The wrapper:
|
|
12
12
|
* 1. Runs `codex exec --json <your args>` as a subprocess
|
|
13
13
|
* 2. Streams stdout (JSONL events) to your terminal in real time
|
|
14
|
-
* 3.
|
|
15
|
-
*
|
|
16
|
-
* ~/.claude/session_telemetry_log.jsonl
|
|
17
|
-
* ~/.claude/skill_usage_log.jsonl
|
|
14
|
+
* 3. Writes to SQLite via writeQueryToDb, writeSessionTelemetryToDb,
|
|
15
|
+
* writeSkillUsageToDb (Phase 3: JSONL writes removed)
|
|
18
16
|
*/
|
|
19
17
|
|
|
20
18
|
import { homedir } from "node:os";
|
|
21
19
|
import { join } from "node:path";
|
|
22
20
|
|
|
23
21
|
import { CANONICAL_LOG, QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
22
|
+
import {
|
|
23
|
+
writeQueryToDb,
|
|
24
|
+
writeSessionTelemetryToDb,
|
|
25
|
+
writeSkillUsageToDb,
|
|
26
|
+
} from "../localdb/direct-write.js";
|
|
24
27
|
import {
|
|
25
28
|
appendCanonicalRecords,
|
|
26
29
|
buildCanonicalExecutionFact,
|
|
@@ -38,7 +41,6 @@ import type {
|
|
|
38
41
|
SessionTelemetryRecord,
|
|
39
42
|
SkillUsageRecord,
|
|
40
43
|
} from "../types.js";
|
|
41
|
-
import { appendJsonl } from "../utils/jsonl.js";
|
|
42
44
|
import {
|
|
43
45
|
classifySkillPath,
|
|
44
46
|
containsWholeSkillMention,
|
|
@@ -240,8 +242,8 @@ export function parseJsonlStream(lines: string[], skillNames: Set<string>): Pars
|
|
|
240
242
|
};
|
|
241
243
|
}
|
|
242
244
|
|
|
243
|
-
/**
|
|
244
|
-
export function logQuery(prompt: string, sessionId: string,
|
|
245
|
+
/** Write the user prompt to SQLite. */
|
|
246
|
+
export function logQuery(prompt: string, sessionId: string, _logPath: string = QUERY_LOG): void {
|
|
245
247
|
if (!prompt || prompt.length < 4) return;
|
|
246
248
|
const record: QueryLogRecord = {
|
|
247
249
|
timestamp: new Date().toISOString(),
|
|
@@ -249,16 +251,16 @@ export function logQuery(prompt: string, sessionId: string, logPath: string = QU
|
|
|
249
251
|
query: prompt,
|
|
250
252
|
source: "codex",
|
|
251
253
|
};
|
|
252
|
-
|
|
254
|
+
writeQueryToDb(record);
|
|
253
255
|
}
|
|
254
256
|
|
|
255
|
-
/**
|
|
257
|
+
/** Write session metrics to SQLite. */
|
|
256
258
|
export function logTelemetry(
|
|
257
259
|
metrics: Omit<ParsedCodexStream, "thread_id">,
|
|
258
260
|
prompt: string,
|
|
259
261
|
sessionId: string,
|
|
260
262
|
cwd: string,
|
|
261
|
-
|
|
263
|
+
_logPath: string = TELEMETRY_LOG,
|
|
262
264
|
): void {
|
|
263
265
|
const record: SessionTelemetryRecord = {
|
|
264
266
|
timestamp: new Date().toISOString(),
|
|
@@ -269,10 +271,10 @@ export function logTelemetry(
|
|
|
269
271
|
source: "codex",
|
|
270
272
|
...metrics,
|
|
271
273
|
};
|
|
272
|
-
|
|
274
|
+
writeSessionTelemetryToDb(record);
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
/**
|
|
277
|
+
/** Write a skill trigger to SQLite. */
|
|
276
278
|
export function logSkillTrigger(
|
|
277
279
|
skillName: string,
|
|
278
280
|
prompt: string,
|
|
@@ -300,7 +302,7 @@ export function logSkillTrigger(
|
|
|
300
302
|
triggered: true,
|
|
301
303
|
source: "codex",
|
|
302
304
|
};
|
|
303
|
-
|
|
305
|
+
writeSkillUsageToDb(record);
|
|
304
306
|
}
|
|
305
307
|
|
|
306
308
|
/** Build canonical records from a wrapper session. */
|
|
@@ -34,6 +34,11 @@ import {
|
|
|
34
34
|
SKILL_LOG,
|
|
35
35
|
TELEMETRY_LOG,
|
|
36
36
|
} from "../constants.js";
|
|
37
|
+
import {
|
|
38
|
+
writeQueryToDb,
|
|
39
|
+
writeSessionTelemetryToDb,
|
|
40
|
+
writeSkillUsageToDb,
|
|
41
|
+
} from "../localdb/direct-write.js";
|
|
37
42
|
import {
|
|
38
43
|
appendCanonicalRecords,
|
|
39
44
|
buildCanonicalExecutionFact,
|
|
@@ -46,7 +51,7 @@ import {
|
|
|
46
51
|
deriveSkillInvocationId,
|
|
47
52
|
} from "../normalization.js";
|
|
48
53
|
import type { CanonicalRecord, QueryLogRecord, SkillUsageRecord } from "../types.js";
|
|
49
|
-
import {
|
|
54
|
+
import { loadMarker, saveMarker } from "../utils/jsonl.js";
|
|
50
55
|
|
|
51
56
|
export interface SessionFile {
|
|
52
57
|
agentId: string;
|
|
@@ -389,11 +394,25 @@ export function writeSession(
|
|
|
389
394
|
query: prompt,
|
|
390
395
|
source: session.source,
|
|
391
396
|
};
|
|
392
|
-
|
|
397
|
+
writeQueryToDb(queryRecord);
|
|
393
398
|
}
|
|
394
399
|
|
|
395
|
-
|
|
396
|
-
|
|
400
|
+
// Build a SessionTelemetryRecord-shaped object for SQLite
|
|
401
|
+
writeSessionTelemetryToDb({
|
|
402
|
+
timestamp: session.timestamp,
|
|
403
|
+
session_id: session.session_id,
|
|
404
|
+
cwd: session.cwd,
|
|
405
|
+
transcript_path: session.transcript_path,
|
|
406
|
+
tool_calls: session.tool_calls,
|
|
407
|
+
total_tool_calls: session.total_tool_calls,
|
|
408
|
+
bash_commands: session.bash_commands,
|
|
409
|
+
skills_triggered: session.skills_triggered,
|
|
410
|
+
assistant_turns: session.assistant_turns,
|
|
411
|
+
errors_encountered: session.errors_encountered,
|
|
412
|
+
transcript_chars: session.transcript_chars,
|
|
413
|
+
last_user_query: session.last_user_query,
|
|
414
|
+
source: session.source,
|
|
415
|
+
});
|
|
397
416
|
|
|
398
417
|
for (const skillName of skills) {
|
|
399
418
|
const skillRecord: SkillUsageRecord = {
|
|
@@ -405,7 +424,7 @@ export function writeSession(
|
|
|
405
424
|
triggered: true,
|
|
406
425
|
source: session.source,
|
|
407
426
|
};
|
|
408
|
-
|
|
427
|
+
writeSkillUsageToDb(skillRecord);
|
|
409
428
|
}
|
|
410
429
|
|
|
411
430
|
// --- Canonical normalization records (additive) ---
|
|
@@ -27,6 +27,11 @@ import { basename, join } from "node:path";
|
|
|
27
27
|
import { parseArgs } from "node:util";
|
|
28
28
|
|
|
29
29
|
import { CANONICAL_LOG, QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
30
|
+
import {
|
|
31
|
+
writeQueryToDb,
|
|
32
|
+
writeSessionTelemetryToDb,
|
|
33
|
+
writeSkillUsageToDb,
|
|
34
|
+
} from "../localdb/direct-write.js";
|
|
30
35
|
import {
|
|
31
36
|
appendCanonicalRecords,
|
|
32
37
|
buildCanonicalExecutionFact,
|
|
@@ -44,7 +49,7 @@ import type {
|
|
|
44
49
|
SessionTelemetryRecord,
|
|
45
50
|
SkillUsageRecord,
|
|
46
51
|
} from "../types.js";
|
|
47
|
-
import {
|
|
52
|
+
import { loadMarker, saveMarker } from "../utils/jsonl.js";
|
|
48
53
|
|
|
49
54
|
const XDG_DATA_HOME = process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share");
|
|
50
55
|
const DEFAULT_DATA_DIR = join(XDG_DATA_HOME, "opencode");
|
|
@@ -528,7 +533,7 @@ export function writeSession(
|
|
|
528
533
|
query: prompt,
|
|
529
534
|
source: session.source,
|
|
530
535
|
};
|
|
531
|
-
|
|
536
|
+
writeQueryToDb(queryRecord);
|
|
532
537
|
}
|
|
533
538
|
|
|
534
539
|
const telemetry: SessionTelemetryRecord = {
|
|
@@ -546,7 +551,7 @@ export function writeSession(
|
|
|
546
551
|
last_user_query: session.last_user_query,
|
|
547
552
|
source: session.source,
|
|
548
553
|
};
|
|
549
|
-
|
|
554
|
+
writeSessionTelemetryToDb(telemetry);
|
|
550
555
|
|
|
551
556
|
for (const skillName of skills) {
|
|
552
557
|
const skillRecord: SkillUsageRecord = {
|
|
@@ -558,7 +563,7 @@ export function writeSession(
|
|
|
558
563
|
triggered: true,
|
|
559
564
|
source: session.source,
|
|
560
565
|
};
|
|
561
|
-
|
|
566
|
+
writeSkillUsageToDb(skillRecord);
|
|
562
567
|
}
|
|
563
568
|
|
|
564
569
|
// --- Canonical normalization records (additive) ---
|
package/cli/selftune/init.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
import { installAgentFiles } from "./claude-agents.js";
|
|
45
45
|
import { CLAUDE_CODE_HOOK_KEYS, SELFTUNE_CONFIG_DIR, SELFTUNE_CONFIG_PATH } from "./constants.js";
|
|
46
46
|
import type { AgentCommandGuidance, AlphaIdentity, SelftuneConfig } from "./types.js";
|
|
47
|
+
import { CLIError, handleCLIError } from "./utils/cli-error.js";
|
|
47
48
|
import { hookKeyHasSelftuneEntry } from "./utils/hooks.js";
|
|
48
49
|
import { detectAgent } from "./utils/llm-call.js";
|
|
49
50
|
|
|
@@ -692,8 +693,11 @@ export async function cliMain(): Promise<void> {
|
|
|
692
693
|
try {
|
|
693
694
|
validateAlphaMetadataFlags(values.alpha, values["alpha-email"], values["alpha-name"]);
|
|
694
695
|
} catch (error) {
|
|
695
|
-
|
|
696
|
-
|
|
696
|
+
throw new CLIError(
|
|
697
|
+
error instanceof Error ? error.message : String(error),
|
|
698
|
+
"INVALID_FLAG",
|
|
699
|
+
"Pass --alpha along with --alpha-email and --alpha-name.",
|
|
700
|
+
);
|
|
697
701
|
}
|
|
698
702
|
|
|
699
703
|
// Check for existing config without force
|
|
@@ -890,10 +894,11 @@ export async function cliMain(): Promise<void> {
|
|
|
890
894
|
});
|
|
891
895
|
|
|
892
896
|
if (!scheduleResult.activated) {
|
|
893
|
-
|
|
894
|
-
"Failed to activate the autonomous scheduler.
|
|
897
|
+
throw new CLIError(
|
|
898
|
+
"Failed to activate the autonomous scheduler.",
|
|
899
|
+
"OPERATION_FAILED",
|
|
900
|
+
"Re-run with --schedule-format or use `selftune schedule --install --dry-run` to inspect the generated artifacts first.",
|
|
895
901
|
);
|
|
896
|
-
process.exit(1);
|
|
897
902
|
}
|
|
898
903
|
|
|
899
904
|
console.log(
|
|
@@ -906,10 +911,11 @@ export async function cliMain(): Promise<void> {
|
|
|
906
911
|
}),
|
|
907
912
|
);
|
|
908
913
|
} catch (err) {
|
|
909
|
-
|
|
914
|
+
throw new CLIError(
|
|
910
915
|
`Failed to enable autonomy: ${err instanceof Error ? err.message : String(err)}`,
|
|
916
|
+
"OPERATION_FAILED",
|
|
917
|
+
"Re-run with --schedule-format or use `selftune schedule --install --dry-run` to inspect artifacts.",
|
|
911
918
|
);
|
|
912
|
-
process.exit(1);
|
|
913
919
|
}
|
|
914
920
|
}
|
|
915
921
|
}
|
|
@@ -947,7 +953,6 @@ if (isMain) {
|
|
|
947
953
|
console.error(JSON.stringify(err.payload));
|
|
948
954
|
process.exit(1);
|
|
949
955
|
}
|
|
950
|
-
|
|
951
|
-
process.exit(1);
|
|
956
|
+
handleCLIError(err);
|
|
952
957
|
});
|
|
953
958
|
}
|