selftune 0.2.6 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/apps/local-dashboard/dist/assets/index-Bs3Y4ixf.css +1 -0
- package/apps/local-dashboard/dist/assets/index-C4UYGWKr.js +15 -0
- package/apps/local-dashboard/dist/assets/vendor-react-BQH_6WrG.js +60 -0
- package/apps/local-dashboard/dist/assets/{vendor-table-B7VF2Ipl.js → vendor-table-dK1QMLq9.js} +1 -1
- package/apps/local-dashboard/dist/assets/{vendor-ui-r2k_Ku_V.js → vendor-ui-CO2mrx6e.js} +60 -65
- package/apps/local-dashboard/dist/index.html +5 -5
- package/cli/selftune/activation-rules.ts +57 -18
- package/cli/selftune/agent-guidance.ts +96 -0
- package/cli/selftune/alpha-identity.ts +156 -0
- package/cli/selftune/alpha-upload/build-payloads.ts +151 -0
- package/cli/selftune/alpha-upload/client.ts +113 -0
- package/cli/selftune/alpha-upload/flush.ts +191 -0
- package/cli/selftune/alpha-upload/index.ts +194 -0
- package/cli/selftune/alpha-upload/queue.ts +252 -0
- package/cli/selftune/alpha-upload/stage-canonical.ts +251 -0
- package/cli/selftune/alpha-upload-contract.ts +52 -0
- package/cli/selftune/auth/device-code.ts +110 -0
- package/cli/selftune/auto-update.ts +130 -0
- package/cli/selftune/badge/badge.ts +19 -9
- package/cli/selftune/canonical-export.ts +16 -3
- package/cli/selftune/constants.ts +28 -8
- package/cli/selftune/contribute/bundle.ts +33 -5
- package/cli/selftune/dashboard-contract.ts +32 -1
- package/cli/selftune/dashboard-server.ts +215 -693
- package/cli/selftune/dashboard.ts +1 -1
- package/cli/selftune/eval/baseline.ts +11 -7
- package/cli/selftune/eval/hooks-to-evals.ts +39 -15
- package/cli/selftune/eval/synthetic-evals.ts +54 -1
- package/cli/selftune/evolution/audit.ts +24 -19
- package/cli/selftune/evolution/constitutional.ts +176 -0
- package/cli/selftune/evolution/evidence.ts +18 -13
- package/cli/selftune/evolution/evolve-body.ts +104 -7
- package/cli/selftune/evolution/evolve.ts +195 -22
- package/cli/selftune/evolution/propose-body.ts +18 -1
- package/cli/selftune/evolution/propose-description.ts +27 -2
- package/cli/selftune/evolution/rollback.ts +11 -15
- package/cli/selftune/export.ts +84 -0
- package/cli/selftune/grading/auto-grade.ts +14 -4
- package/cli/selftune/grading/grade-session.ts +17 -6
- package/cli/selftune/hooks/auto-activate.ts +5 -0
- package/cli/selftune/hooks/evolution-guard.ts +25 -11
- package/cli/selftune/hooks/prompt-log.ts +23 -9
- package/cli/selftune/hooks/session-stop.ts +78 -15
- package/cli/selftune/hooks/skill-eval.ts +189 -10
- package/cli/selftune/index.ts +274 -2
- package/cli/selftune/ingestors/claude-replay.ts +48 -21
- package/cli/selftune/init.ts +260 -49
- package/cli/selftune/last.ts +7 -7
- package/cli/selftune/localdb/db.ts +90 -10
- package/cli/selftune/localdb/direct-write.ts +573 -0
- package/cli/selftune/localdb/materialize.ts +296 -42
- package/cli/selftune/localdb/queries.ts +482 -32
- package/cli/selftune/localdb/schema.ts +153 -1
- package/cli/selftune/monitoring/watch.ts +27 -8
- package/cli/selftune/normalization.ts +88 -15
- package/cli/selftune/observability.ts +257 -5
- package/cli/selftune/orchestrate.ts +176 -53
- package/cli/selftune/quickstart.ts +34 -10
- package/cli/selftune/repair/skill-usage.ts +15 -2
- package/cli/selftune/routes/actions.ts +77 -0
- package/cli/selftune/routes/badge.ts +66 -0
- package/cli/selftune/routes/doctor.ts +12 -0
- package/cli/selftune/routes/index.ts +14 -0
- package/cli/selftune/routes/orchestrate-runs.ts +13 -0
- package/cli/selftune/routes/overview.ts +14 -0
- package/cli/selftune/routes/report.ts +293 -0
- package/cli/selftune/routes/skill-report.ts +230 -0
- package/cli/selftune/status.ts +203 -7
- package/cli/selftune/sync.ts +14 -1
- package/cli/selftune/types.ts +52 -2
- package/cli/selftune/utils/jsonl.ts +58 -1
- package/cli/selftune/utils/selftune-meta.ts +38 -0
- package/cli/selftune/utils/skill-log.ts +30 -4
- package/cli/selftune/utils/transcript.ts +15 -0
- package/cli/selftune/workflows/workflows.ts +7 -6
- package/package.json +11 -6
- package/packages/telemetry-contract/fixtures/complete-push.ts +184 -0
- package/packages/telemetry-contract/fixtures/evidence-only-push.ts +58 -0
- package/packages/telemetry-contract/fixtures/golden.json +1 -0
- package/packages/telemetry-contract/fixtures/index.ts +4 -0
- package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +40 -0
- package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +79 -0
- package/packages/telemetry-contract/package.json +6 -1
- package/packages/telemetry-contract/src/schemas.ts +196 -0
- package/packages/telemetry-contract/src/types.ts +3 -1
- package/packages/telemetry-contract/src/validators.ts +3 -1
- package/packages/telemetry-contract/tests/compatibility.test.ts +144 -0
- package/packages/ui/package.json +4 -0
- package/packages/ui/src/components/ActivityTimeline.tsx +61 -29
- package/packages/ui/src/components/section-cards.tsx +31 -14
- package/packages/ui/src/types.ts +1 -0
- package/skill/SKILL.md +214 -174
- package/skill/Workflows/AlphaUpload.md +45 -0
- package/skill/Workflows/Baseline.md +18 -12
- package/skill/Workflows/Composability.md +3 -3
- package/skill/Workflows/Dashboard.md +39 -91
- package/skill/Workflows/Doctor.md +93 -66
- package/skill/Workflows/Evals.md +49 -40
- package/skill/Workflows/Evolve.md +76 -28
- package/skill/Workflows/EvolveBody.md +37 -38
- package/skill/Workflows/Initialize.md +145 -26
- package/skill/Workflows/Orchestrate.md +11 -2
- package/skill/Workflows/Sync.md +23 -0
- package/skill/Workflows/Watch.md +2 -5
- package/skill/agents/diagnosis-analyst.md +163 -0
- package/skill/agents/evolution-reviewer.md +149 -0
- package/skill/agents/integration-guide.md +154 -0
- package/skill/agents/pattern-analyst.md +149 -0
- package/skill/assets/multi-skill-settings.json +1 -1
- package/skill/assets/single-skill-settings.json +1 -1
- package/skill/references/interactive-config.md +39 -0
- package/skill/references/invocation-taxonomy.md +34 -0
- package/skill/references/logs.md +15 -1
- package/skill/references/setup-patterns.md +3 -3
- package/skill/settings_snippet.json +1 -1
- package/apps/local-dashboard/dist/assets/index-C75H1Q3n.css +0 -1
- package/apps/local-dashboard/dist/assets/index-axE4kz3Q.js +0 -15
- package/apps/local-dashboard/dist/assets/vendor-react-U7zYD9Rg.js +0 -60
|
@@ -21,7 +21,10 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
21
21
|
repo_remote TEXT,
|
|
22
22
|
branch TEXT,
|
|
23
23
|
schema_version TEXT,
|
|
24
|
-
normalized_at TEXT
|
|
24
|
+
normalized_at TEXT,
|
|
25
|
+
normalizer_version TEXT,
|
|
26
|
+
capture_mode TEXT,
|
|
27
|
+
raw_source_ref TEXT
|
|
25
28
|
)`;
|
|
26
29
|
|
|
27
30
|
export const CREATE_PROMPTS = `
|
|
@@ -33,6 +36,12 @@ CREATE TABLE IF NOT EXISTS prompts (
|
|
|
33
36
|
is_actionable INTEGER,
|
|
34
37
|
prompt_index INTEGER,
|
|
35
38
|
prompt_text TEXT,
|
|
39
|
+
schema_version TEXT,
|
|
40
|
+
platform TEXT,
|
|
41
|
+
normalized_at TEXT,
|
|
42
|
+
normalizer_version TEXT,
|
|
43
|
+
capture_mode TEXT,
|
|
44
|
+
raw_source_ref TEXT,
|
|
36
45
|
FOREIGN KEY (session_id) REFERENCES sessions(session_id)
|
|
37
46
|
)`;
|
|
38
47
|
|
|
@@ -47,6 +56,17 @@ CREATE TABLE IF NOT EXISTS skill_invocations (
|
|
|
47
56
|
confidence REAL,
|
|
48
57
|
tool_name TEXT,
|
|
49
58
|
matched_prompt_id TEXT,
|
|
59
|
+
agent_type TEXT,
|
|
60
|
+
query TEXT,
|
|
61
|
+
skill_path TEXT,
|
|
62
|
+
skill_scope TEXT,
|
|
63
|
+
source TEXT,
|
|
64
|
+
schema_version TEXT,
|
|
65
|
+
platform TEXT,
|
|
66
|
+
normalized_at TEXT,
|
|
67
|
+
normalizer_version TEXT,
|
|
68
|
+
capture_mode TEXT,
|
|
69
|
+
raw_source_ref TEXT,
|
|
50
70
|
FOREIGN KEY (session_id) REFERENCES sessions(session_id)
|
|
51
71
|
)`;
|
|
52
72
|
|
|
@@ -64,6 +84,12 @@ CREATE TABLE IF NOT EXISTS execution_facts (
|
|
|
64
84
|
output_tokens INTEGER,
|
|
65
85
|
duration_ms INTEGER,
|
|
66
86
|
completion_status TEXT,
|
|
87
|
+
schema_version TEXT,
|
|
88
|
+
platform TEXT,
|
|
89
|
+
normalized_at TEXT,
|
|
90
|
+
normalizer_version TEXT,
|
|
91
|
+
capture_mode TEXT,
|
|
92
|
+
raw_source_ref TEXT,
|
|
67
93
|
FOREIGN KEY (session_id) REFERENCES sessions(session_id)
|
|
68
94
|
)`;
|
|
69
95
|
|
|
@@ -151,6 +177,67 @@ CREATE TABLE IF NOT EXISTS orchestrate_runs (
|
|
|
151
177
|
skill_actions_json TEXT NOT NULL
|
|
152
178
|
)`;
|
|
153
179
|
|
|
180
|
+
// -- Query log table (from all_queries_log.jsonl) ----------------------------
|
|
181
|
+
|
|
182
|
+
export const CREATE_QUERIES = `
|
|
183
|
+
CREATE TABLE IF NOT EXISTS queries (
|
|
184
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
185
|
+
timestamp TEXT NOT NULL,
|
|
186
|
+
session_id TEXT NOT NULL,
|
|
187
|
+
query TEXT NOT NULL,
|
|
188
|
+
source TEXT
|
|
189
|
+
)`;
|
|
190
|
+
|
|
191
|
+
// -- Improvement signal table (from signal_log.jsonl) ------------------------
|
|
192
|
+
|
|
193
|
+
export const CREATE_IMPROVEMENT_SIGNALS = `
|
|
194
|
+
CREATE TABLE IF NOT EXISTS improvement_signals (
|
|
195
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
196
|
+
timestamp TEXT NOT NULL,
|
|
197
|
+
session_id TEXT NOT NULL,
|
|
198
|
+
query TEXT NOT NULL,
|
|
199
|
+
signal_type TEXT NOT NULL,
|
|
200
|
+
mentioned_skill TEXT,
|
|
201
|
+
consumed INTEGER NOT NULL DEFAULT 0,
|
|
202
|
+
consumed_at TEXT,
|
|
203
|
+
consumed_by_run TEXT
|
|
204
|
+
)`;
|
|
205
|
+
|
|
206
|
+
// -- Alpha upload queue -------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
export const CREATE_UPLOAD_QUEUE = `
|
|
209
|
+
CREATE TABLE IF NOT EXISTS upload_queue (
|
|
210
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
211
|
+
payload_type TEXT NOT NULL,
|
|
212
|
+
payload_json TEXT NOT NULL,
|
|
213
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
214
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
215
|
+
created_at TEXT NOT NULL,
|
|
216
|
+
updated_at TEXT NOT NULL,
|
|
217
|
+
last_error TEXT
|
|
218
|
+
)`;
|
|
219
|
+
|
|
220
|
+
// -- Canonical upload staging -------------------------------------------------
|
|
221
|
+
|
|
222
|
+
export const CREATE_CANONICAL_UPLOAD_STAGING = `
|
|
223
|
+
CREATE TABLE IF NOT EXISTS canonical_upload_staging (
|
|
224
|
+
local_seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
225
|
+
record_kind TEXT NOT NULL,
|
|
226
|
+
record_id TEXT NOT NULL,
|
|
227
|
+
record_json TEXT NOT NULL,
|
|
228
|
+
session_id TEXT,
|
|
229
|
+
prompt_id TEXT,
|
|
230
|
+
normalized_at TEXT,
|
|
231
|
+
staged_at TEXT NOT NULL
|
|
232
|
+
)`;
|
|
233
|
+
|
|
234
|
+
export const CREATE_UPLOAD_WATERMARKS = `
|
|
235
|
+
CREATE TABLE IF NOT EXISTS upload_watermarks (
|
|
236
|
+
payload_type TEXT PRIMARY KEY,
|
|
237
|
+
last_uploaded_id INTEGER NOT NULL,
|
|
238
|
+
updated_at TEXT NOT NULL
|
|
239
|
+
)`;
|
|
240
|
+
|
|
154
241
|
// -- Metadata table -----------------------------------------------------------
|
|
155
242
|
|
|
156
243
|
export const CREATE_META = `
|
|
@@ -167,6 +254,7 @@ export const CREATE_INDEXES = [
|
|
|
167
254
|
`CREATE INDEX IF NOT EXISTS idx_prompts_occurred ON prompts(occurred_at)`,
|
|
168
255
|
`CREATE INDEX IF NOT EXISTS idx_skill_inv_session ON skill_invocations(session_id)`,
|
|
169
256
|
`CREATE INDEX IF NOT EXISTS idx_skill_inv_name ON skill_invocations(skill_name)`,
|
|
257
|
+
`CREATE INDEX IF NOT EXISTS idx_skill_inv_ts ON skill_invocations(occurred_at)`,
|
|
170
258
|
`CREATE INDEX IF NOT EXISTS idx_exec_facts_session ON execution_facts(session_id)`,
|
|
171
259
|
`CREATE INDEX IF NOT EXISTS idx_evo_evidence_proposal ON evolution_evidence(proposal_id)`,
|
|
172
260
|
`CREATE INDEX IF NOT EXISTS idx_evo_evidence_skill ON evolution_evidence(skill_name)`,
|
|
@@ -186,6 +274,65 @@ export const CREATE_INDEXES = [
|
|
|
186
274
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_evo_evidence_dedup ON evolution_evidence(proposal_id, stage, timestamp)`,
|
|
187
275
|
// -- Orchestrate run indexes -----------------------------------------------
|
|
188
276
|
`CREATE INDEX IF NOT EXISTS idx_orchestrate_runs_ts ON orchestrate_runs(timestamp)`,
|
|
277
|
+
// -- Query log indexes ------------------------------------------------------
|
|
278
|
+
`CREATE INDEX IF NOT EXISTS idx_queries_session ON queries(session_id)`,
|
|
279
|
+
`CREATE INDEX IF NOT EXISTS idx_queries_ts ON queries(timestamp)`,
|
|
280
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_queries_dedup ON queries(session_id, query, timestamp)`,
|
|
281
|
+
// -- Improvement signal indexes ---------------------------------------------
|
|
282
|
+
`CREATE INDEX IF NOT EXISTS idx_signals_session ON improvement_signals(session_id)`,
|
|
283
|
+
`CREATE INDEX IF NOT EXISTS idx_signals_consumed ON improvement_signals(consumed)`,
|
|
284
|
+
`CREATE INDEX IF NOT EXISTS idx_signals_ts ON improvement_signals(timestamp)`,
|
|
285
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_signals_dedup ON improvement_signals(session_id, query, signal_type, timestamp)`,
|
|
286
|
+
// -- Alpha upload queue indexes ---------------------------------------------
|
|
287
|
+
`CREATE INDEX IF NOT EXISTS idx_upload_queue_status ON upload_queue(status)`,
|
|
288
|
+
`CREATE INDEX IF NOT EXISTS idx_upload_queue_type_status ON upload_queue(payload_type, status)`,
|
|
289
|
+
// -- Canonical upload staging indexes ---------------------------------------
|
|
290
|
+
`CREATE INDEX IF NOT EXISTS idx_staging_kind ON canonical_upload_staging(record_kind)`,
|
|
291
|
+
`CREATE INDEX IF NOT EXISTS idx_staging_session ON canonical_upload_staging(session_id)`,
|
|
292
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_staging_dedup ON canonical_upload_staging(record_kind, record_id)`,
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Schema migrations — ALTER TABLE statements for columns added after initial release.
|
|
297
|
+
* Each is safe to re-run: SQLite throws "duplicate column" which openDb() catches.
|
|
298
|
+
*/
|
|
299
|
+
export const MIGRATIONS = [
|
|
300
|
+
// skill_invocations consolidation (skill_usage columns merged in)
|
|
301
|
+
`ALTER TABLE skill_invocations ADD COLUMN query TEXT`,
|
|
302
|
+
`ALTER TABLE skill_invocations ADD COLUMN skill_path TEXT`,
|
|
303
|
+
`ALTER TABLE skill_invocations ADD COLUMN skill_scope TEXT`,
|
|
304
|
+
`ALTER TABLE skill_invocations ADD COLUMN source TEXT`,
|
|
305
|
+
// Track how many iteration loops each evolution run used
|
|
306
|
+
`ALTER TABLE evolution_audit ADD COLUMN iterations_used INTEGER`,
|
|
307
|
+
// Canonical contract fields for upload staging (sessions already has schema_version, platform, normalized_at)
|
|
308
|
+
`ALTER TABLE sessions ADD COLUMN normalizer_version TEXT`,
|
|
309
|
+
`ALTER TABLE sessions ADD COLUMN capture_mode TEXT`,
|
|
310
|
+
`ALTER TABLE sessions ADD COLUMN raw_source_ref TEXT`,
|
|
311
|
+
`ALTER TABLE prompts ADD COLUMN schema_version TEXT`,
|
|
312
|
+
`ALTER TABLE prompts ADD COLUMN platform TEXT`,
|
|
313
|
+
`ALTER TABLE prompts ADD COLUMN normalized_at TEXT`,
|
|
314
|
+
`ALTER TABLE prompts ADD COLUMN normalizer_version TEXT`,
|
|
315
|
+
`ALTER TABLE prompts ADD COLUMN capture_mode TEXT`,
|
|
316
|
+
`ALTER TABLE prompts ADD COLUMN raw_source_ref TEXT`,
|
|
317
|
+
`ALTER TABLE skill_invocations ADD COLUMN schema_version TEXT`,
|
|
318
|
+
`ALTER TABLE skill_invocations ADD COLUMN platform TEXT`,
|
|
319
|
+
`ALTER TABLE skill_invocations ADD COLUMN normalized_at TEXT`,
|
|
320
|
+
`ALTER TABLE skill_invocations ADD COLUMN normalizer_version TEXT`,
|
|
321
|
+
`ALTER TABLE skill_invocations ADD COLUMN capture_mode TEXT`,
|
|
322
|
+
`ALTER TABLE skill_invocations ADD COLUMN raw_source_ref TEXT`,
|
|
323
|
+
`ALTER TABLE execution_facts ADD COLUMN schema_version TEXT`,
|
|
324
|
+
`ALTER TABLE execution_facts ADD COLUMN platform TEXT`,
|
|
325
|
+
`ALTER TABLE execution_facts ADD COLUMN normalized_at TEXT`,
|
|
326
|
+
`ALTER TABLE execution_facts ADD COLUMN normalizer_version TEXT`,
|
|
327
|
+
`ALTER TABLE execution_facts ADD COLUMN capture_mode TEXT`,
|
|
328
|
+
`ALTER TABLE execution_facts ADD COLUMN raw_source_ref TEXT`,
|
|
329
|
+
];
|
|
330
|
+
|
|
331
|
+
/** Indexes that depend on migration columns — must run AFTER MIGRATIONS. */
|
|
332
|
+
export const POST_MIGRATION_INDEXES = [
|
|
333
|
+
`CREATE INDEX IF NOT EXISTS idx_skill_inv_query_triggered ON skill_invocations(query, triggered)`,
|
|
334
|
+
`CREATE INDEX IF NOT EXISTS idx_skill_inv_scope ON skill_invocations(skill_name, skill_scope, occurred_at)`,
|
|
335
|
+
`CREATE INDEX IF NOT EXISTS idx_skill_inv_dedup ON skill_invocations(session_id, skill_name, query, occurred_at, triggered)`,
|
|
189
336
|
];
|
|
190
337
|
|
|
191
338
|
/** All DDL statements in creation order. */
|
|
@@ -199,6 +346,11 @@ export const ALL_DDL = [
|
|
|
199
346
|
CREATE_SESSION_TELEMETRY,
|
|
200
347
|
CREATE_SKILL_USAGE,
|
|
201
348
|
CREATE_ORCHESTRATE_RUNS,
|
|
349
|
+
CREATE_QUERIES,
|
|
350
|
+
CREATE_IMPROVEMENT_SIGNALS,
|
|
351
|
+
CREATE_UPLOAD_QUEUE,
|
|
352
|
+
CREATE_UPLOAD_WATERMARKS,
|
|
353
|
+
CREATE_CANONICAL_UPLOAD_STAGING,
|
|
202
354
|
CREATE_META,
|
|
203
355
|
...CREATE_INDEXES,
|
|
204
356
|
];
|
|
@@ -11,6 +11,12 @@ import { parseArgs } from "node:util";
|
|
|
11
11
|
import { QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
12
12
|
import { classifyInvocation } from "../eval/hooks-to-evals.js";
|
|
13
13
|
import { getLastDeployedProposal } from "../evolution/audit.js";
|
|
14
|
+
import { getDb } from "../localdb/db.js";
|
|
15
|
+
import {
|
|
16
|
+
queryQueryLog,
|
|
17
|
+
querySessionTelemetry,
|
|
18
|
+
querySkillUsageRecords,
|
|
19
|
+
} from "../localdb/queries.js";
|
|
14
20
|
import { updateContextAfterWatch } from "../memory/writer.js";
|
|
15
21
|
import type { SyncResult } from "../sync.js";
|
|
16
22
|
import type {
|
|
@@ -25,7 +31,6 @@ import {
|
|
|
25
31
|
filterActionableQueryRecords,
|
|
26
32
|
filterActionableSkillUsageRecords,
|
|
27
33
|
} from "../utils/query-filter.js";
|
|
28
|
-
import { readEffectiveSkillUsageRecords } from "../utils/skill-log.js";
|
|
29
34
|
|
|
30
35
|
// ---------------------------------------------------------------------------
|
|
31
36
|
// Public interfaces
|
|
@@ -207,13 +212,27 @@ export async function watch(options: WatchOptions): Promise<WatchResult> {
|
|
|
207
212
|
);
|
|
208
213
|
}
|
|
209
214
|
|
|
210
|
-
// 1. Read log files
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
// 1. Read log files from SQLite (fall back to JSONL for custom paths)
|
|
216
|
+
let telemetry: SessionTelemetryRecord[];
|
|
217
|
+
let skillRecords: SkillUsageRecord[];
|
|
218
|
+
let queryRecords: QueryLogRecord[];
|
|
219
|
+
if (
|
|
220
|
+
_telemetryLogPath === TELEMETRY_LOG &&
|
|
221
|
+
_skillLogPath === SKILL_LOG &&
|
|
222
|
+
_queryLogPath === QUERY_LOG
|
|
223
|
+
) {
|
|
224
|
+
const db = getDb();
|
|
225
|
+
telemetry = querySessionTelemetry(db) as SessionTelemetryRecord[];
|
|
226
|
+
// SQLite queries return DESC order; computeMonitoringSnapshot expects chronological (ASC)
|
|
227
|
+
telemetry.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
228
|
+
skillRecords = querySkillUsageRecords(db) as SkillUsageRecord[];
|
|
229
|
+
queryRecords = queryQueryLog(db) as QueryLogRecord[];
|
|
230
|
+
} else {
|
|
231
|
+
// Intentional JSONL fallback: custom log path overrides bypass SQLite reads
|
|
232
|
+
telemetry = readJsonl<SessionTelemetryRecord>(_telemetryLogPath);
|
|
233
|
+
skillRecords = readJsonl<SkillUsageRecord>(_skillLogPath);
|
|
234
|
+
queryRecords = readJsonl<QueryLogRecord>(_queryLogPath);
|
|
235
|
+
}
|
|
217
236
|
|
|
218
237
|
// 2. Determine baseline pass rate from last deployed audit entry
|
|
219
238
|
const lastDeployed = getLastDeployedProposal(skillName, _auditLogPath);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Canonical telemetry normalization helpers.
|
|
3
3
|
*
|
|
4
4
|
* This module provides shared functions that all platform adapters call
|
|
5
|
-
* to produce canonical records
|
|
5
|
+
* to produce canonical records written to SQLite via writeCanonicalToDb().
|
|
6
6
|
*
|
|
7
7
|
* Contract rules (from telemetry-field-map.md):
|
|
8
8
|
* 1. Normalization is additive — raw capture is preserved separately.
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from "node:fs";
|
|
26
26
|
import { basename, dirname } from "node:path";
|
|
27
27
|
import { CANONICAL_LOG, canonicalSessionStatePath } from "./constants.js";
|
|
28
|
+
import { writeCanonicalBatchToDb, writeCanonicalToDb } from "./localdb/direct-write.js";
|
|
28
29
|
import {
|
|
29
30
|
CANONICAL_SCHEMA_VERSION,
|
|
30
31
|
type CanonicalCaptureMode,
|
|
@@ -81,9 +82,49 @@ function defaultPromptSessionState(sessionId: string): CanonicalPromptSessionSta
|
|
|
81
82
|
|
|
82
83
|
function derivePromptSessionStateFromCanonicalLog(
|
|
83
84
|
sessionId: string,
|
|
84
|
-
|
|
85
|
+
_canonicalLogPath: string = CANONICAL_LOG,
|
|
85
86
|
): CanonicalPromptSessionState {
|
|
86
87
|
const recovered = defaultPromptSessionState(sessionId);
|
|
88
|
+
|
|
89
|
+
// Try SQLite first — canonical records now go to the local DB.
|
|
90
|
+
// Uses dynamic require + try/catch so this remains fail-safe during
|
|
91
|
+
// hook execution when the DB module may not be loadable.
|
|
92
|
+
try {
|
|
93
|
+
const { getDb } = require("./localdb/db.js") as {
|
|
94
|
+
getDb: () => import("bun:sqlite").Database;
|
|
95
|
+
};
|
|
96
|
+
const db = getDb();
|
|
97
|
+
const rows = db
|
|
98
|
+
.query(
|
|
99
|
+
"SELECT prompt_id, prompt_index, is_actionable FROM prompts WHERE session_id = ? ORDER BY prompt_index DESC LIMIT 1",
|
|
100
|
+
)
|
|
101
|
+
.all(sessionId) as Array<{
|
|
102
|
+
prompt_id: string;
|
|
103
|
+
prompt_index: number;
|
|
104
|
+
is_actionable: number;
|
|
105
|
+
}>;
|
|
106
|
+
if (rows.length > 0) {
|
|
107
|
+
const row = rows[0];
|
|
108
|
+
recovered.next_prompt_index = row.prompt_index + 1;
|
|
109
|
+
recovered.last_prompt_id = row.prompt_id;
|
|
110
|
+
// Get last actionable
|
|
111
|
+
const actionable = db
|
|
112
|
+
.query(
|
|
113
|
+
"SELECT prompt_id, prompt_index FROM prompts WHERE session_id = ? AND is_actionable = 1 ORDER BY prompt_index DESC LIMIT 1",
|
|
114
|
+
)
|
|
115
|
+
.get(sessionId) as { prompt_id: string; prompt_index: number } | null;
|
|
116
|
+
if (actionable) recovered.last_actionable_prompt_id = actionable.prompt_id;
|
|
117
|
+
return recovered;
|
|
118
|
+
}
|
|
119
|
+
if (_canonicalLogPath === CANONICAL_LOG) {
|
|
120
|
+
return recovered;
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
// DB unavailable — fall through to JSONL recovery below.
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Fallback: scan canonical JSONL log (legacy path or DB unavailable).
|
|
127
|
+
const canonicalLogPath = _canonicalLogPath;
|
|
87
128
|
let maxPromptIndex = -1;
|
|
88
129
|
let maxActionablePromptIndex = -1;
|
|
89
130
|
|
|
@@ -346,22 +387,32 @@ export function getLatestPromptIdentity(
|
|
|
346
387
|
};
|
|
347
388
|
}
|
|
348
389
|
|
|
349
|
-
export function appendCanonicalRecord(
|
|
350
|
-
record
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
mkdirSync(dir, { recursive: true });
|
|
390
|
+
export function appendCanonicalRecord(record: CanonicalRecord, logPath?: string): void {
|
|
391
|
+
writeCanonicalToDb(record);
|
|
392
|
+
// JSONL append — best-effort backup for prompt state recovery
|
|
393
|
+
try {
|
|
394
|
+
const path = logPath ?? CANONICAL_LOG;
|
|
395
|
+
const dir = dirname(path);
|
|
396
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
397
|
+
appendFileSync(path, `${JSON.stringify(record)}\n`, "utf-8");
|
|
398
|
+
} catch {
|
|
399
|
+
/* best-effort only */
|
|
356
400
|
}
|
|
357
|
-
appendFileSync(logPath, `${JSON.stringify(record)}\n`, "utf-8");
|
|
358
401
|
}
|
|
359
402
|
|
|
360
|
-
export function appendCanonicalRecords(
|
|
361
|
-
records
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
403
|
+
export function appendCanonicalRecords(records: CanonicalRecord[], logPath?: string): void {
|
|
404
|
+
writeCanonicalBatchToDb(records);
|
|
405
|
+
// JSONL append — best-effort backup for prompt state recovery
|
|
406
|
+
try {
|
|
407
|
+
const path = logPath ?? CANONICAL_LOG;
|
|
408
|
+
const dir = dirname(path);
|
|
409
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
410
|
+
for (const record of records) {
|
|
411
|
+
appendFileSync(path, `${JSON.stringify(record)}\n`, "utf-8");
|
|
412
|
+
}
|
|
413
|
+
} catch {
|
|
414
|
+
/* best-effort only */
|
|
415
|
+
}
|
|
365
416
|
}
|
|
366
417
|
|
|
367
418
|
// ---------------------------------------------------------------------------
|
|
@@ -439,14 +490,34 @@ export interface InvocationClassification {
|
|
|
439
490
|
|
|
440
491
|
/**
|
|
441
492
|
* Classify how a skill was invoked.
|
|
493
|
+
*
|
|
494
|
+
* When `hook_invocation_type` is provided (from the skill-eval hook's
|
|
495
|
+
* classifyInvocationType), it takes precedence over the legacy heuristics:
|
|
496
|
+
* - "explicit" → user typed /skill (slash command) → explicit, confidence 1.0
|
|
497
|
+
* - "implicit" → user named the skill, Claude invoked it → implicit, confidence 0.85
|
|
498
|
+
* - "inferred" → Claude chose skill autonomously → inferred, confidence 0.6
|
|
499
|
+
* - "contextual" → SKILL.md was read (Read tool, not Skill tool) → inferred, confidence 0.5
|
|
442
500
|
*/
|
|
443
501
|
export function deriveInvocationMode(opts: {
|
|
444
502
|
has_skill_tool_call?: boolean;
|
|
445
503
|
has_skill_md_read?: boolean;
|
|
446
504
|
is_text_mention_only?: boolean;
|
|
447
505
|
is_repaired?: boolean;
|
|
506
|
+
hook_invocation_type?: "explicit" | "implicit" | "inferred" | "contextual";
|
|
448
507
|
}): InvocationClassification {
|
|
449
508
|
if (opts.is_repaired) return { invocation_mode: "repaired", confidence: 0.9 };
|
|
509
|
+
|
|
510
|
+
// Prefer hook-level classification when available
|
|
511
|
+
if (opts.hook_invocation_type === "explicit")
|
|
512
|
+
return { invocation_mode: "explicit", confidence: 1.0 };
|
|
513
|
+
if (opts.hook_invocation_type === "implicit")
|
|
514
|
+
return { invocation_mode: "implicit", confidence: 0.85 };
|
|
515
|
+
if (opts.hook_invocation_type === "inferred")
|
|
516
|
+
return { invocation_mode: "inferred", confidence: 0.6 };
|
|
517
|
+
if (opts.hook_invocation_type === "contextual")
|
|
518
|
+
return { invocation_mode: "inferred", confidence: 0.5 };
|
|
519
|
+
|
|
520
|
+
// Legacy fallback for callers that don't pass hook_invocation_type
|
|
450
521
|
if (opts.has_skill_tool_call) return { invocation_mode: "explicit", confidence: 1.0 };
|
|
451
522
|
if (opts.has_skill_md_read) return { invocation_mode: "implicit", confidence: 0.7 };
|
|
452
523
|
if (opts.is_text_mention_only) return { invocation_mode: "inferred", confidence: 0.4 };
|
|
@@ -613,6 +684,7 @@ export interface BuildSkillInvocationInput extends CanonicalBaseInput {
|
|
|
613
684
|
confidence: number;
|
|
614
685
|
tool_name?: string;
|
|
615
686
|
tool_call_id?: string;
|
|
687
|
+
agent_type?: string;
|
|
616
688
|
}
|
|
617
689
|
|
|
618
690
|
export function buildCanonicalSkillInvocation(
|
|
@@ -636,6 +708,7 @@ export function buildCanonicalSkillInvocation(
|
|
|
636
708
|
if (input.skill_version_hash !== undefined) record.skill_version_hash = input.skill_version_hash;
|
|
637
709
|
if (input.tool_name !== undefined) record.tool_name = input.tool_name;
|
|
638
710
|
if (input.tool_call_id !== undefined) record.tool_call_id = input.tool_call_id;
|
|
711
|
+
if (input.agent_type !== undefined) record.agent_type = input.agent_type;
|
|
639
712
|
|
|
640
713
|
return record;
|
|
641
714
|
}
|