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
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>selftune — Dashboard</title>
|
|
7
7
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DOu3iLD9.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dw2cE7zH.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-CKkiCskZ.js">
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-DIwlrGlb.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/vendor-table-pHbDxq36.js">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BMIS6uUh.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -5,64 +5,45 @@
|
|
|
5
5
|
* (or null if the rule doesn't fire). Rules must be pure functions —
|
|
6
6
|
* no network calls, no imports from evolution/monitoring/grading layers.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* only when context paths differ from the well-known constants
|
|
10
|
-
* (test/custom-path override).
|
|
8
|
+
* All log data is read from SQLite.
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
14
|
-
import {
|
|
12
|
+
import { join } from "node:path";
|
|
15
13
|
|
|
16
|
-
import { EVOLUTION_AUDIT_LOG, QUERY_LOG } from "./constants.js";
|
|
17
14
|
import { getDb } from "./localdb/db.js";
|
|
18
15
|
import { queryEvolutionAudit, queryQueryLog, querySkillUsageRecords } from "./localdb/queries.js";
|
|
19
16
|
import type { ActivationContext, ActivationRule } from "./types.js";
|
|
20
|
-
import { readJsonl } from "./utils/jsonl.js";
|
|
21
17
|
|
|
22
18
|
// ---------------------------------------------------------------------------
|
|
23
|
-
// Rule: post-session diagnostic
|
|
19
|
+
// Rule: post-session diagnostic
|
|
24
20
|
// ---------------------------------------------------------------------------
|
|
25
21
|
|
|
26
22
|
const postSessionDiagnostic: ActivationRule = {
|
|
27
23
|
id: "post-session-diagnostic",
|
|
28
24
|
description: "Suggest `selftune last` when session has >2 unmatched queries",
|
|
29
25
|
evaluate(ctx: ActivationContext): string | null {
|
|
30
|
-
// Count queries for this session
|
|
26
|
+
// Count queries for this session
|
|
31
27
|
let queries: Array<{ session_id: string; query: string }>;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
// test/custom-path fallback
|
|
41
|
-
queries = readJsonl<{ session_id: string; query: string }>(ctx.query_log_path);
|
|
28
|
+
try {
|
|
29
|
+
const db = getDb();
|
|
30
|
+
queries = queryQueryLog(db) as Array<{ session_id: string; query: string }>;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
42
33
|
}
|
|
43
34
|
const sessionQueries = queries.filter((q) => q.session_id === ctx.session_id);
|
|
44
35
|
|
|
45
36
|
if (sessionQueries.length === 0) return null;
|
|
46
37
|
|
|
47
|
-
// Count skill usages for this session
|
|
38
|
+
// Count skill usages for this session
|
|
48
39
|
let skillUsages: Array<{ session_id: string }>;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
} else {
|
|
59
|
-
// test/custom-path fallback
|
|
60
|
-
const skillLogPath = join(dirname(ctx.query_log_path), "skill_usage_log.jsonl");
|
|
61
|
-
skillUsages = existsSync(skillLogPath)
|
|
62
|
-
? readJsonl<{ session_id: string }>(skillLogPath).filter(
|
|
63
|
-
(s) => s.session_id === ctx.session_id,
|
|
64
|
-
)
|
|
65
|
-
: [];
|
|
40
|
+
try {
|
|
41
|
+
const db = getDb();
|
|
42
|
+
skillUsages = (querySkillUsageRecords(db) as Array<{ session_id: string }>).filter(
|
|
43
|
+
(s) => s.session_id === ctx.session_id,
|
|
44
|
+
);
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
66
47
|
}
|
|
67
48
|
|
|
68
49
|
const unmatchedCount = sessionQueries.length - skillUsages.length;
|
|
@@ -114,7 +95,7 @@ const gradingThresholdBreach: ActivationRule = {
|
|
|
114
95
|
};
|
|
115
96
|
|
|
116
97
|
// ---------------------------------------------------------------------------
|
|
117
|
-
// Rule: stale evolution
|
|
98
|
+
// Rule: stale evolution
|
|
118
99
|
// ---------------------------------------------------------------------------
|
|
119
100
|
|
|
120
101
|
const staleEvolution: ActivationRule = {
|
|
@@ -124,18 +105,13 @@ const staleEvolution: ActivationRule = {
|
|
|
124
105
|
evaluate(ctx: ActivationContext): string | null {
|
|
125
106
|
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
126
107
|
|
|
127
|
-
// Check last evolution timestamp
|
|
108
|
+
// Check last evolution timestamp
|
|
128
109
|
let auditEntries: Array<{ timestamp: string; action: string }>;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
// test/custom-path fallback
|
|
138
|
-
auditEntries = readJsonl<{ timestamp: string; action: string }>(ctx.evolution_audit_log_path);
|
|
110
|
+
try {
|
|
111
|
+
const db = getDb();
|
|
112
|
+
auditEntries = queryEvolutionAudit(db) as Array<{ timestamp: string; action: string }>;
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
139
115
|
}
|
|
140
116
|
|
|
141
117
|
if (auditEntries.length === 0) {
|
|
@@ -24,6 +24,7 @@ import { join } from "node:path";
|
|
|
24
24
|
|
|
25
25
|
import { SELFTUNE_CONFIG_DIR, SELFTUNE_CONFIG_PATH } from "./constants.js";
|
|
26
26
|
import type { SelftuneConfig } from "./types.js";
|
|
27
|
+
import { CLIError } from "./utils/cli-error.js";
|
|
27
28
|
|
|
28
29
|
// ---------------------------------------------------------------------------
|
|
29
30
|
// Configuration
|
|
@@ -280,11 +281,11 @@ https://github.com/selftune-dev/selftune#telemetry`);
|
|
|
280
281
|
try {
|
|
281
282
|
writeConfigField("analytics_disabled", true);
|
|
282
283
|
} catch {
|
|
283
|
-
|
|
284
|
-
"Failed to disable telemetry: cannot write ~/.selftune/config.json
|
|
285
|
-
|
|
284
|
+
throw new CLIError(
|
|
285
|
+
"Failed to disable telemetry: cannot write ~/.selftune/config.json",
|
|
286
|
+
"OPERATION_FAILED",
|
|
287
|
+
"Check file permissions, or set SELFTUNE_NO_ANALYTICS=1",
|
|
286
288
|
);
|
|
287
|
-
process.exit(1);
|
|
288
289
|
}
|
|
289
290
|
console.log("Telemetry disabled. No anonymous usage data will be sent.");
|
|
290
291
|
console.log("You can re-enable with: selftune telemetry enable");
|
|
@@ -294,11 +295,11 @@ https://github.com/selftune-dev/selftune#telemetry`);
|
|
|
294
295
|
try {
|
|
295
296
|
writeConfigField("analytics_disabled", false);
|
|
296
297
|
} catch {
|
|
297
|
-
|
|
298
|
-
"Failed to enable telemetry: cannot write ~/.selftune/config.json
|
|
299
|
-
|
|
298
|
+
throw new CLIError(
|
|
299
|
+
"Failed to enable telemetry: cannot write ~/.selftune/config.json",
|
|
300
|
+
"OPERATION_FAILED",
|
|
301
|
+
"Check file permissions",
|
|
300
302
|
);
|
|
301
|
-
process.exit(1);
|
|
302
303
|
}
|
|
303
304
|
console.log("Telemetry enabled. Anonymous usage data will be sent.");
|
|
304
305
|
console.log("Disable anytime with: selftune telemetry disable");
|
|
@@ -331,10 +332,11 @@ https://github.com/selftune-dev/selftune#telemetry`);
|
|
|
331
332
|
break;
|
|
332
333
|
}
|
|
333
334
|
default:
|
|
334
|
-
|
|
335
|
-
`Unknown telemetry subcommand: ${sub}
|
|
335
|
+
throw new CLIError(
|
|
336
|
+
`Unknown telemetry subcommand: ${sub}`,
|
|
337
|
+
"INVALID_FLAG",
|
|
338
|
+
"selftune telemetry --help",
|
|
336
339
|
);
|
|
337
|
-
process.exit(1);
|
|
338
340
|
}
|
|
339
341
|
}
|
|
340
342
|
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
SessionTelemetryRecord,
|
|
25
25
|
SkillUsageRecord,
|
|
26
26
|
} from "../types.js";
|
|
27
|
+
import { CLIError, handleCLIError } from "../utils/cli-error.js";
|
|
27
28
|
import type { BadgeFormat } from "./badge-data.js";
|
|
28
29
|
import { findSkillBadgeData } from "./badge-data.js";
|
|
29
30
|
import { formatBadgeOutput } from "./badge-svg.js";
|
|
@@ -58,15 +59,15 @@ export async function cliMain(): Promise<void> {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
if (!values.skill) {
|
|
61
|
-
|
|
62
|
-
console.error(HELP);
|
|
63
|
-
process.exit(1);
|
|
62
|
+
throw new CLIError("--skill is required", "MISSING_FLAG", "selftune badge --skill <name>");
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
if (values.format && !VALID_FORMATS.has(values.format as BadgeFormat)) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
throw new CLIError(
|
|
67
|
+
`Invalid format '${values.format}'. Must be one of: svg, markdown, url`,
|
|
68
|
+
"INVALID_FLAG",
|
|
69
|
+
"selftune badge --skill <name> --format svg",
|
|
70
|
+
);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
const format: BadgeFormat =
|
|
@@ -90,8 +91,11 @@ export async function cliMain(): Promise<void> {
|
|
|
90
91
|
// Find skill badge data
|
|
91
92
|
const badgeData = findSkillBadgeData(result, values.skill);
|
|
92
93
|
if (!badgeData) {
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
throw new CLIError(
|
|
95
|
+
`Skill not found: ${values.skill}`,
|
|
96
|
+
"MISSING_DATA",
|
|
97
|
+
"selftune status --json # list available skill names",
|
|
98
|
+
);
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
// Generate output
|
|
@@ -106,5 +110,5 @@ export async function cliMain(): Promise<void> {
|
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
if (import.meta.main) {
|
|
109
|
-
cliMain();
|
|
113
|
+
cliMain().catch(handleCLIError);
|
|
110
114
|
}
|
|
@@ -26,13 +26,14 @@ import {
|
|
|
26
26
|
readCanonicalRecords,
|
|
27
27
|
serializeCanonicalRecords,
|
|
28
28
|
} from "./utils/canonical-log.js";
|
|
29
|
+
import { CLIError, handleCLIError } from "./utils/cli-error.js";
|
|
29
30
|
|
|
30
31
|
function exitWithUsage(message?: string): never {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
throw new CLIError(
|
|
33
|
+
message ?? "Invalid usage.",
|
|
34
|
+
"INVALID_FLAG",
|
|
35
|
+
"Usage: selftune export-canonical [--out FILE] [--platform NAME] [--record-kind KIND] [--pretty] [--log FILE] [--projects-dir PATH] [--push-payload]",
|
|
34
36
|
);
|
|
35
|
-
process.exit(1);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function validatePlatform(value: string | undefined): CanonicalPlatform | undefined {
|
|
@@ -195,7 +196,6 @@ if (import.meta.main) {
|
|
|
195
196
|
try {
|
|
196
197
|
cliMain();
|
|
197
198
|
} catch (error) {
|
|
198
|
-
|
|
199
|
-
exitWithUsage(message);
|
|
199
|
+
handleCLIError(error);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
@@ -22,15 +22,22 @@ export const SELFTUNE_CONFIG_PATH = join(SELFTUNE_CONFIG_DIR, "config.json");
|
|
|
22
22
|
|
|
23
23
|
export const LOG_DIR = (process.env.SELFTUNE_LOG_DIR || undefined) ?? claudeHomeDir;
|
|
24
24
|
|
|
25
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
25
26
|
export const TELEMETRY_LOG = join(LOG_DIR, "session_telemetry_log.jsonl");
|
|
26
27
|
export const SKILL_LOG = join(LOG_DIR, "skill_usage_log.jsonl");
|
|
27
28
|
export const REPAIRED_SKILL_LOG = join(LOG_DIR, "skill_usage_repaired.jsonl");
|
|
29
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
28
30
|
export const CANONICAL_LOG = join(LOG_DIR, "canonical_telemetry_log.jsonl");
|
|
29
31
|
export const REPAIRED_SKILL_SESSIONS_MARKER = join(LOG_DIR, "skill_usage_repaired_sessions.json");
|
|
32
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
30
33
|
export const QUERY_LOG = join(LOG_DIR, "all_queries_log.jsonl");
|
|
34
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
31
35
|
export const EVOLUTION_AUDIT_LOG = join(LOG_DIR, "evolution_audit_log.jsonl");
|
|
36
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
32
37
|
export const EVOLUTION_EVIDENCE_LOG = join(LOG_DIR, "evolution_evidence_log.jsonl");
|
|
38
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
33
39
|
export const ORCHESTRATE_RUN_LOG = join(LOG_DIR, "orchestrate_runs.jsonl");
|
|
40
|
+
/** @deprecated Phase 3: JSONL writes removed. Used only by materializer recovery and export. */
|
|
34
41
|
export const SIGNAL_LOG = join(LOG_DIR, "improvement_signals.jsonl");
|
|
35
42
|
export const ORCHESTRATE_LOCK = join(LOG_DIR, ".orchestrate.lock");
|
|
36
43
|
|
|
@@ -9,13 +9,7 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
EVOLUTION_AUDIT_LOG,
|
|
14
|
-
QUERY_LOG,
|
|
15
|
-
SELFTUNE_CONFIG_DIR,
|
|
16
|
-
SKILL_LOG,
|
|
17
|
-
TELEMETRY_LOG,
|
|
18
|
-
} from "../constants.js";
|
|
12
|
+
import { SELFTUNE_CONFIG_DIR } from "../constants.js";
|
|
19
13
|
import { buildEvalSet, classifyInvocation } from "../eval/hooks-to-evals.js";
|
|
20
14
|
import { getDb } from "../localdb/db.js";
|
|
21
15
|
import {
|
|
@@ -36,7 +30,6 @@ import type {
|
|
|
36
30
|
SessionTelemetryRecord,
|
|
37
31
|
SkillUsageRecord,
|
|
38
32
|
} from "../types.js";
|
|
39
|
-
import { readJsonl } from "../utils/jsonl.js";
|
|
40
33
|
|
|
41
34
|
// ---------------------------------------------------------------------------
|
|
42
35
|
// Helpers
|
|
@@ -201,42 +194,14 @@ export function assembleBundle(options: {
|
|
|
201
194
|
telemetryLogPath?: string;
|
|
202
195
|
evolutionAuditLogPath?: string;
|
|
203
196
|
}): ContributionBundle {
|
|
204
|
-
const {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} = options;
|
|
213
|
-
|
|
214
|
-
// Read from JSONL when custom (non-default) paths are provided (test isolation),
|
|
215
|
-
// otherwise read from SQLite (production).
|
|
216
|
-
const useJsonl =
|
|
217
|
-
queryLogPath !== QUERY_LOG ||
|
|
218
|
-
skillLogPath !== SKILL_LOG ||
|
|
219
|
-
telemetryLogPath !== TELEMETRY_LOG ||
|
|
220
|
-
evolutionAuditLogPath !== EVOLUTION_AUDIT_LOG;
|
|
221
|
-
|
|
222
|
-
let allSkillRecords: SkillUsageRecord[];
|
|
223
|
-
let allQueryRecords: QueryLogRecord[];
|
|
224
|
-
let allTelemetryRecords: SessionTelemetryRecord[];
|
|
225
|
-
let allEvolutionRecords: EvolutionAuditEntry[];
|
|
226
|
-
|
|
227
|
-
if (useJsonl) {
|
|
228
|
-
// JSONL fallback: only used when custom (non-default) log paths are provided (test isolation)
|
|
229
|
-
allSkillRecords = readJsonl<SkillUsageRecord>(skillLogPath);
|
|
230
|
-
allQueryRecords = readJsonl<QueryLogRecord>(queryLogPath);
|
|
231
|
-
allTelemetryRecords = readJsonl<SessionTelemetryRecord>(telemetryLogPath);
|
|
232
|
-
allEvolutionRecords = readJsonl<EvolutionAuditEntry>(evolutionAuditLogPath);
|
|
233
|
-
} else {
|
|
234
|
-
const db = getDb();
|
|
235
|
-
allSkillRecords = querySkillUsageRecords(db) as SkillUsageRecord[];
|
|
236
|
-
allQueryRecords = queryQueryLog(db) as QueryLogRecord[];
|
|
237
|
-
allTelemetryRecords = querySessionTelemetry(db) as SessionTelemetryRecord[];
|
|
238
|
-
allEvolutionRecords = queryEvolutionAudit(db) as EvolutionAuditEntry[];
|
|
239
|
-
}
|
|
197
|
+
const { skillName, since, sanitizationLevel } = options;
|
|
198
|
+
|
|
199
|
+
const db = getDb();
|
|
200
|
+
const allSkillRecords = querySkillUsageRecords(db) as SkillUsageRecord[];
|
|
201
|
+
const allQueryRecords = queryQueryLog(db) as QueryLogRecord[];
|
|
202
|
+
const allTelemetryRecords = querySessionTelemetry(db) as SessionTelemetryRecord[];
|
|
203
|
+
// queryEvolutionAudit returns DESC order; reverse to ASC for chronological processing
|
|
204
|
+
const allEvolutionRecords = (queryEvolutionAudit(db) as EvolutionAuditEntry[]).toReversed();
|
|
240
205
|
|
|
241
206
|
// Filter by skill and since
|
|
242
207
|
const skillRecords = filterSince(
|
|
@@ -12,6 +12,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
12
12
|
import { parseArgs } from "node:util";
|
|
13
13
|
|
|
14
14
|
import { CONTRIBUTIONS_DIR } from "../constants.js";
|
|
15
|
+
import { handleCLIError } from "../utils/cli-error.js";
|
|
15
16
|
import { assembleBundle } from "./bundle.js";
|
|
16
17
|
import { sanitizeBundle } from "./sanitize.js";
|
|
17
18
|
|
|
@@ -211,5 +212,5 @@ function submitToGitHub(json: string, outputPath: string): boolean {
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
if (import.meta.main) {
|
|
214
|
-
|
|
215
|
+
cliMain().catch(handleCLIError);
|
|
215
216
|
}
|
|
@@ -18,6 +18,8 @@ import { homedir } from "node:os";
|
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { parseArgs } from "node:util";
|
|
20
20
|
|
|
21
|
+
import { handleCLIError } from "../utils/cli-error.js";
|
|
22
|
+
|
|
21
23
|
// ---------------------------------------------------------------------------
|
|
22
24
|
// Types & constants
|
|
23
25
|
// ---------------------------------------------------------------------------
|
|
@@ -262,5 +264,5 @@ Subcommands:
|
|
|
262
264
|
}
|
|
263
265
|
|
|
264
266
|
if (import.meta.main) {
|
|
265
|
-
|
|
267
|
+
cliMain().catch(handleCLIError);
|
|
266
268
|
}
|
|
@@ -48,6 +48,15 @@ export interface PendingProposal {
|
|
|
48
48
|
skill_name?: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
export interface RecentActivityItem {
|
|
52
|
+
timestamp: string;
|
|
53
|
+
session_id: string;
|
|
54
|
+
skill_name: string;
|
|
55
|
+
query: string;
|
|
56
|
+
triggered: boolean;
|
|
57
|
+
is_live: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
51
60
|
export interface SkillSummary {
|
|
52
61
|
skill_name: string;
|
|
53
62
|
skill_scope: string | null;
|
|
@@ -73,6 +82,8 @@ export interface OverviewPayload {
|
|
|
73
82
|
};
|
|
74
83
|
unmatched_queries: UnmatchedQuery[];
|
|
75
84
|
pending_proposals: PendingProposal[];
|
|
85
|
+
active_sessions: number;
|
|
86
|
+
recent_activity: RecentActivityItem[];
|
|
76
87
|
}
|
|
77
88
|
|
|
78
89
|
export interface OverviewResponse {
|
|
@@ -179,6 +190,7 @@ export interface OrchestrateRunReport {
|
|
|
179
190
|
deployed: number;
|
|
180
191
|
watched: number;
|
|
181
192
|
skipped: number;
|
|
193
|
+
auto_graded?: number;
|
|
182
194
|
skill_actions: OrchestrateRunSkillAction[];
|
|
183
195
|
}
|
|
184
196
|
|
|
@@ -230,4 +242,14 @@ export interface SkillReportResponse extends SkillReportPayload {
|
|
|
230
242
|
};
|
|
231
243
|
prompt_samples: PromptSample[];
|
|
232
244
|
session_metadata: SessionMeta[];
|
|
245
|
+
description_quality?: {
|
|
246
|
+
composite: number;
|
|
247
|
+
criteria: {
|
|
248
|
+
length: number;
|
|
249
|
+
trigger_context: number;
|
|
250
|
+
vagueness: number;
|
|
251
|
+
specificity: number;
|
|
252
|
+
not_just_name: number;
|
|
253
|
+
};
|
|
254
|
+
} | null;
|
|
233
255
|
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* selftune dashboard --serve — Deprecated alias for the default behavior
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { CLIError } from "./utils/cli-error.js";
|
|
11
|
+
|
|
10
12
|
export async function cliMain(): Promise<void> {
|
|
11
13
|
const args = process.argv.slice(2);
|
|
12
14
|
|
|
@@ -22,11 +24,11 @@ Usage:
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
if (args.includes("--export") || args.includes("--out")) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
throw new CLIError(
|
|
28
|
+
"Legacy dashboard export was removed.",
|
|
29
|
+
"INVALID_FLAG",
|
|
27
30
|
"Use `selftune dashboard` to run the SPA locally, then share a route or screenshot instead.",
|
|
28
31
|
);
|
|
29
|
-
process.exit(1);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const portIdx = args.indexOf("--port");
|
|
@@ -34,8 +36,11 @@ Usage:
|
|
|
34
36
|
if (portIdx !== -1) {
|
|
35
37
|
const parsed = Number.parseInt(args[portIdx + 1], 10);
|
|
36
38
|
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
throw new CLIError(
|
|
40
|
+
`Invalid port "${args[portIdx + 1]}": must be an integer between 1 and 65535.`,
|
|
41
|
+
"INVALID_FLAG",
|
|
42
|
+
"Provide a port number between 1 and 65535 (e.g., --port 3141).",
|
|
43
|
+
);
|
|
39
44
|
}
|
|
40
45
|
port = parsed;
|
|
41
46
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { parseArgs } from "node:util";
|
|
12
12
|
|
|
13
13
|
import type { BaselineResult, EvalEntry } from "../types.js";
|
|
14
|
+
import { CLIError, handleCLIError } from "../utils/cli-error.js";
|
|
14
15
|
import { callLlm } from "../utils/llm-call.js";
|
|
15
16
|
import { buildTriggerCheckPrompt, parseTriggerResponse } from "../utils/trigger-check.js";
|
|
16
17
|
|
|
@@ -166,8 +167,11 @@ Options:
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
if (!values.skill || !values["skill-path"]) {
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
throw new CLIError(
|
|
171
|
+
"--skill and --skill-path are required",
|
|
172
|
+
"MISSING_FLAG",
|
|
173
|
+
"selftune grade baseline --skill <name> --skill-path <path>",
|
|
174
|
+
);
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
const { existsSync, readFileSync } = await import("node:fs");
|
|
@@ -175,8 +179,11 @@ Options:
|
|
|
175
179
|
// Read skill description
|
|
176
180
|
const skillPath = values["skill-path"];
|
|
177
181
|
if (!existsSync(skillPath)) {
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
throw new CLIError(
|
|
183
|
+
`SKILL.md not found at ${skillPath}`,
|
|
184
|
+
"FILE_NOT_FOUND",
|
|
185
|
+
"Provide a valid --skill-path pointing to SKILL.md",
|
|
186
|
+
);
|
|
180
187
|
}
|
|
181
188
|
const skillDescription = readFileSync(skillPath, "utf-8");
|
|
182
189
|
|
|
@@ -204,27 +211,19 @@ Options:
|
|
|
204
211
|
const { detectAgent } = await import("../utils/llm-call.js");
|
|
205
212
|
const requestedAgent = values.agent;
|
|
206
213
|
if (requestedAgent && !Bun.which(requestedAgent)) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
message: `Agent CLI '${requestedAgent}' not found in PATH.`,
|
|
212
|
-
action: "Install it or omit --agent to use auto-detection.",
|
|
213
|
-
}),
|
|
214
|
+
throw new CLIError(
|
|
215
|
+
`Agent CLI '${requestedAgent}' not found in PATH`,
|
|
216
|
+
"AGENT_NOT_FOUND",
|
|
217
|
+
"Install it or omit --agent to use auto-detection",
|
|
214
218
|
);
|
|
215
|
-
process.exit(1);
|
|
216
219
|
}
|
|
217
220
|
const agent = requestedAgent ?? detectAgent();
|
|
218
221
|
if (!agent) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
message: "No agent CLI (claude/codex/opencode) found in PATH.",
|
|
224
|
-
action: "Install Claude Code, Codex, or OpenCode.",
|
|
225
|
-
}),
|
|
222
|
+
throw new CLIError(
|
|
223
|
+
"No agent CLI (claude/codex/opencode) found in PATH",
|
|
224
|
+
"AGENT_NOT_FOUND",
|
|
225
|
+
"Install Claude Code, Codex, or OpenCode",
|
|
226
226
|
);
|
|
227
|
-
process.exit(1);
|
|
228
227
|
}
|
|
229
228
|
|
|
230
229
|
const result = await measureBaseline({
|
|
@@ -239,14 +238,5 @@ Options:
|
|
|
239
238
|
}
|
|
240
239
|
|
|
241
240
|
if (import.meta.main) {
|
|
242
|
-
cliMain().catch(
|
|
243
|
-
console.error(
|
|
244
|
-
JSON.stringify({
|
|
245
|
-
level: "fatal",
|
|
246
|
-
message: err instanceof Error ? err.message : String(err),
|
|
247
|
-
stack: err instanceof Error ? err.stack : undefined,
|
|
248
|
-
}),
|
|
249
|
-
);
|
|
250
|
-
process.exit(1);
|
|
251
|
-
});
|
|
241
|
+
cliMain().catch(handleCLIError);
|
|
252
242
|
}
|