selftune 0.2.22 → 0.2.24
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/CHANGELOG.md +6 -0
- package/README.md +95 -15
- package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +1 -0
- package/apps/local-dashboard/dist/assets/index-Dmx7LPVX.js +15 -0
- package/apps/local-dashboard/dist/assets/vendor-react-C5oyHiV1.js +11 -0
- package/apps/local-dashboard/dist/assets/{vendor-table-BIiI3YhS.js → vendor-table-Bc_bbKd8.js} +1 -1
- package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +1 -0
- package/apps/local-dashboard/dist/index.html +5 -5
- package/cli/selftune/adapters/codex/install.ts +310 -78
- package/cli/selftune/adapters/opencode/install.ts +3 -4
- package/cli/selftune/adapters/pi/hook.ts +273 -0
- package/cli/selftune/adapters/pi/install.ts +207 -0
- package/cli/selftune/alpha-upload/build-payloads.ts +3 -3
- package/cli/selftune/alpha-upload/stage-canonical.ts +17 -11
- package/cli/selftune/auto-update.ts +200 -8
- package/cli/selftune/canonical-export.ts +55 -25
- package/cli/selftune/command-surface.ts +397 -0
- package/cli/selftune/constants.ts +10 -1
- package/cli/selftune/contribute/contribute.ts +64 -13
- package/cli/selftune/contribution-config.ts +57 -3
- package/cli/selftune/contribution-preferences.ts +117 -0
- package/cli/selftune/contribution-signals.ts +8 -4
- package/cli/selftune/contribution-staging.ts +13 -2
- package/cli/selftune/contributions.ts +55 -121
- package/cli/selftune/creator-contributions.ts +29 -10
- package/cli/selftune/cron/setup.ts +7 -3
- package/cli/selftune/dashboard-contract.ts +87 -0
- package/cli/selftune/dashboard-server.ts +168 -17
- package/cli/selftune/dashboard.ts +350 -17
- package/cli/selftune/eval/baseline.ts +21 -5
- package/cli/selftune/eval/execution-eval.ts +170 -0
- package/cli/selftune/eval/family-overlap.ts +2 -2
- package/cli/selftune/eval/hooks-to-evals.ts +228 -82
- package/cli/selftune/eval/import-skillsbench.ts +2 -2
- package/cli/selftune/eval/invocation-classifier.ts +56 -0
- package/cli/selftune/eval/synthetic-evals.ts +5 -3
- package/cli/selftune/eval/unit-test-cli.ts +7 -4
- package/cli/selftune/evolution/apply-proposal.ts +295 -0
- package/cli/selftune/evolution/engines/judge-engine.ts +96 -0
- package/cli/selftune/evolution/engines/replay-engine.ts +180 -0
- package/cli/selftune/evolution/evidence.ts +2 -6
- package/cli/selftune/evolution/evolve-body.ts +152 -38
- package/cli/selftune/evolution/evolve.ts +244 -52
- package/cli/selftune/evolution/rollback.ts +0 -1
- package/cli/selftune/evolution/validate-body.ts +111 -49
- package/cli/selftune/evolution/validate-host-replay.ts +510 -60
- package/cli/selftune/evolution/validate-proposal.ts +11 -150
- package/cli/selftune/evolution/validate-routing.ts +51 -108
- package/cli/selftune/evolution/validation-contract.ts +91 -0
- package/cli/selftune/grading/auto-grade.ts +11 -7
- package/cli/selftune/grading/grade-session.ts +10 -16
- package/cli/selftune/hooks/skill-eval.ts +2 -1
- package/cli/selftune/hooks-shared/types.ts +1 -0
- package/cli/selftune/index.ts +58 -15
- package/cli/selftune/ingestors/claude-replay.ts +15 -10
- package/cli/selftune/ingestors/codex-wrapper.ts +3 -3
- package/cli/selftune/ingestors/opencode-ingest.ts +2 -2
- package/cli/selftune/ingestors/pi-ingest.ts +727 -0
- package/cli/selftune/init.ts +38 -4
- package/cli/selftune/localdb/direct-write.ts +120 -1
- package/cli/selftune/localdb/materialize.ts +6 -7
- package/cli/selftune/localdb/queries/cron.ts +34 -0
- package/cli/selftune/localdb/queries/dashboard.ts +834 -0
- package/cli/selftune/localdb/queries/evolution.ts +158 -0
- package/cli/selftune/localdb/queries/execution.ts +133 -0
- package/cli/selftune/localdb/queries/json.ts +18 -0
- package/cli/selftune/localdb/queries/monitoring.ts +263 -0
- package/cli/selftune/localdb/queries/raw.ts +95 -0
- package/cli/selftune/localdb/queries/staging.ts +270 -0
- package/cli/selftune/localdb/queries/trust.ts +392 -0
- package/cli/selftune/localdb/queries.ts +60 -2162
- package/cli/selftune/localdb/schema.ts +59 -0
- package/cli/selftune/monitoring/watch.ts +96 -29
- package/cli/selftune/normalization.ts +3 -0
- package/cli/selftune/observability.ts +12 -3
- package/cli/selftune/orchestrate/cli.ts +161 -0
- package/cli/selftune/orchestrate/execute.ts +295 -0
- package/cli/selftune/orchestrate/finalize.ts +157 -0
- package/cli/selftune/orchestrate/locks.ts +40 -0
- package/cli/selftune/orchestrate/plan.ts +131 -0
- package/cli/selftune/orchestrate/post-run.ts +59 -0
- package/cli/selftune/orchestrate/prepare.ts +334 -0
- package/cli/selftune/orchestrate/report.ts +182 -0
- package/cli/selftune/orchestrate/runtime.ts +120 -0
- package/cli/selftune/orchestrate/signals.ts +48 -0
- package/cli/selftune/orchestrate.ts +162 -1142
- package/cli/selftune/registry/client.ts +74 -0
- package/cli/selftune/registry/history.ts +54 -0
- package/cli/selftune/registry/index.ts +90 -0
- package/cli/selftune/registry/install.ts +141 -0
- package/cli/selftune/registry/list.ts +44 -0
- package/cli/selftune/registry/push.ts +171 -0
- package/cli/selftune/registry/rollback.ts +49 -0
- package/cli/selftune/registry/status.ts +62 -0
- package/cli/selftune/registry/sync.ts +125 -0
- package/cli/selftune/repair/skill-usage.ts +9 -3
- package/cli/selftune/routes/overview.ts +5 -2
- package/cli/selftune/routes/skill-report.ts +15 -2
- package/cli/selftune/schedule.ts +5 -5
- package/cli/selftune/status.ts +70 -2
- package/cli/selftune/sync.ts +127 -23
- package/cli/selftune/testing-readiness.ts +597 -0
- package/cli/selftune/types.ts +46 -5
- package/cli/selftune/uninstall.ts +2 -1
- package/cli/selftune/utils/canonical-log.ts +1 -9
- package/cli/selftune/utils/cli-error.ts +9 -0
- package/cli/selftune/utils/jsonl.ts +1 -30
- package/cli/selftune/utils/llm-call.ts +126 -6
- package/cli/selftune/utils/skill-discovery.ts +24 -0
- package/cli/selftune/workflows/proposals.ts +184 -0
- package/cli/selftune/workflows/skill-scaffold.ts +241 -0
- package/cli/selftune/workflows/workflows.ts +100 -26
- package/node_modules/@selftune/telemetry-contract/fixtures/complete-push.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
- package/node_modules/@selftune/telemetry-contract/fixtures/golden.test.ts +0 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
- package/node_modules/@selftune/telemetry-contract/package.json +1 -1
- package/node_modules/@selftune/telemetry-contract/src/index.ts +1 -0
- package/node_modules/@selftune/telemetry-contract/src/schemas.ts +63 -5
- package/node_modules/@selftune/telemetry-contract/src/types.ts +97 -7
- package/node_modules/@selftune/telemetry-contract/tests/compatibility.test.ts +0 -1
- package/package.json +25 -9
- package/packages/dashboard-core/AGENTS.md +18 -0
- package/packages/dashboard-core/README.md +30 -0
- package/packages/dashboard-core/index.ts +3 -0
- package/packages/dashboard-core/package.json +39 -0
- package/packages/dashboard-core/src/chrome/DashboardChrome.tsx +74 -0
- package/packages/dashboard-core/src/chrome/DashboardHeader.tsx +200 -0
- package/packages/dashboard-core/src/chrome/DashboardSidebar.tsx +219 -0
- package/packages/dashboard-core/src/chrome/RuntimeBadge.tsx +46 -0
- package/packages/dashboard-core/src/chrome/index.ts +14 -0
- package/packages/dashboard-core/src/chrome/types.ts +81 -0
- package/packages/dashboard-core/src/chrome/utils.ts +23 -0
- package/packages/dashboard-core/src/gates/FeatureGate.tsx +11 -0
- package/packages/dashboard-core/src/gates/LockedRoute.tsx +29 -0
- package/packages/dashboard-core/src/gates/UpgradeCard.tsx +89 -0
- package/packages/dashboard-core/src/gates/index.ts +3 -0
- package/packages/dashboard-core/src/host/DashboardHostProvider.tsx +62 -0
- package/packages/dashboard-core/src/host/adapter.ts +47 -0
- package/packages/dashboard-core/src/host/capabilities.ts +55 -0
- package/packages/dashboard-core/src/host/index.ts +3 -0
- package/packages/dashboard-core/src/models/analytics.ts +39 -0
- package/packages/dashboard-core/src/models/index.ts +4 -0
- package/packages/dashboard-core/src/models/overview.ts +98 -0
- package/packages/dashboard-core/src/models/runtime.ts +7 -0
- package/packages/dashboard-core/src/models/skills.ts +34 -0
- package/packages/dashboard-core/src/routes/index.ts +2 -0
- package/packages/dashboard-core/src/routes/manifest.test.ts +70 -0
- package/packages/dashboard-core/src/routes/manifest.ts +451 -0
- package/packages/dashboard-core/src/routes/types.ts +39 -0
- package/packages/dashboard-core/src/screens/analytics/AnalyticsScreen.tsx +278 -0
- package/packages/dashboard-core/src/screens/analytics/index.ts +1 -0
- package/packages/dashboard-core/src/screens/index.ts +37 -0
- package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.test.ts +101 -0
- package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.tsx +393 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.test.tsx +113 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.tsx +72 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCoreSurface.tsx +71 -0
- package/packages/dashboard-core/src/screens/overview/OverviewOnboardingBanner.tsx +90 -0
- package/packages/dashboard-core/src/screens/overview/OverviewRunSummary.tsx +40 -0
- package/packages/dashboard-core/src/screens/overview/index.ts +16 -0
- package/packages/dashboard-core/src/screens/overview/types.ts +13 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +99 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportDataQualityTabContent.tsx +35 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceRail.tsx +71 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceSection.tsx +63 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceTabContent.tsx +25 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportInvocationsSection.tsx +24 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportMissedQueriesSection.tsx +79 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +150 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportSections.test.tsx +224 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.test.tsx +76 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.tsx +88 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTrendSection.tsx +33 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +67 -0
- package/packages/dashboard-core/src/screens/skill-report/index.ts +45 -0
- package/packages/dashboard-core/src/screens/skills/SkillsLibraryScreen.tsx +162 -0
- package/packages/dashboard-core/src/screens/skills/index.ts +6 -0
- package/packages/telemetry-contract/fixtures/complete-push.ts +1 -1
- package/packages/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
- package/packages/telemetry-contract/fixtures/golden.test.ts +0 -1
- package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
- package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
- package/packages/telemetry-contract/package.json +1 -1
- package/packages/telemetry-contract/src/index.ts +1 -0
- package/packages/telemetry-contract/src/schemas.ts +63 -5
- package/packages/telemetry-contract/src/types.ts +97 -7
- package/packages/telemetry-contract/tests/compatibility.test.ts +0 -1
- package/packages/ui/AGENTS.md +16 -0
- package/packages/ui/README.md +1 -1
- package/packages/ui/package.json +1 -1
- package/packages/ui/src/components/ActivityTimeline.tsx +152 -168
- package/packages/ui/src/components/AnalyticsCharts.tsx +344 -0
- package/packages/ui/src/components/EvidenceViewer.tsx +229 -464
- package/packages/ui/src/components/EvolutionTimeline.tsx +34 -87
- package/packages/ui/src/components/InfoTip.tsx +1 -2
- package/packages/ui/src/components/InvocationsPanel.tsx +413 -0
- package/packages/ui/src/components/JobHistoryTimeline.tsx +156 -0
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +18 -36
- package/packages/ui/src/components/OverviewPanels.tsx +693 -0
- package/packages/ui/src/components/PipelineStatusBar.tsx +65 -0
- package/packages/ui/src/components/SkillReportGuide.tsx +215 -0
- package/packages/ui/src/components/SkillReportPanels.tsx +919 -0
- package/packages/ui/src/components/SkillsLibrary.tsx +437 -0
- package/packages/ui/src/components/index.ts +56 -1
- package/packages/ui/src/components/section-cards.tsx +18 -35
- package/packages/ui/src/components/skill-health-grid.tsx +47 -37
- package/packages/ui/src/lib/constants.tsx +0 -1
- package/packages/ui/src/primitives/card.tsx +1 -1
- package/packages/ui/src/primitives/checkbox.tsx +1 -1
- package/packages/ui/src/primitives/dropdown-menu.tsx +2 -2
- package/packages/ui/src/primitives/select.tsx +2 -2
- package/packages/ui/src/primitives/tabs.tsx +7 -6
- package/packages/ui/src/types.ts +182 -4
- package/skill/SKILL.md +130 -318
- package/skill/agents/diagnosis-analyst.md +3 -3
- package/skill/agents/evolution-reviewer.md +3 -3
- package/skill/agents/integration-guide.md +3 -3
- package/skill/agents/pattern-analyst.md +2 -2
- package/skill/references/cli-quick-reference.md +89 -0
- package/skill/references/creator-playbook.md +131 -0
- package/skill/references/examples.md +48 -0
- package/skill/references/troubleshooting.md +47 -0
- package/skill/references/version-history.md +1 -1
- package/skill/selftune.contribute.json +11 -0
- package/skill/{Workflows → workflows}/Baseline.md +20 -1
- package/skill/{Workflows → workflows}/Contribute.md +23 -10
- package/skill/{Workflows → workflows}/Contributions.md +13 -5
- package/skill/workflows/CreateTestDeploy.md +170 -0
- package/skill/{Workflows → workflows}/CreatorContributions.md +18 -6
- package/skill/{Workflows → workflows}/Cron.md +1 -1
- package/skill/{Workflows → workflows}/Dashboard.md +20 -0
- package/skill/{Workflows → workflows}/Doctor.md +1 -1
- package/skill/{Workflows → workflows}/Evals.md +67 -2
- package/skill/{Workflows → workflows}/Evolve.md +119 -30
- package/skill/{Workflows → workflows}/EvolveBody.md +41 -1
- package/skill/{Workflows → workflows}/Grade.md +1 -1
- package/skill/{Workflows → workflows}/Ingest.md +60 -2
- package/skill/{Workflows → workflows}/Initialize.md +16 -9
- package/skill/{Workflows → workflows}/Orchestrate.md +13 -3
- package/skill/{Workflows → workflows}/PlatformHooks.md +19 -3
- package/skill/workflows/Registry.md +99 -0
- package/skill/{Workflows → workflows}/Schedule.md +3 -3
- package/skill/workflows/SignalsDashboard.md +87 -0
- package/skill/{Workflows → workflows}/Sync.md +3 -1
- package/skill/{Workflows → workflows}/UnitTest.md +19 -0
- package/skill/{Workflows → workflows}/Watch.md +42 -2
- package/skill/{Workflows → workflows}/Workflows.md +39 -2
- package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +0 -60
- package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +0 -1
- package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +0 -11
- package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +0 -12
- package/cli/selftune/utils/html.ts +0 -27
- package/packages/ui/src/components/RecentActivityFeed.tsx +0 -117
- /package/skill/{Workflows → workflows}/AlphaUpload.md +0 -0
- /package/skill/{Workflows → workflows}/AutoActivation.md +0 -0
- /package/skill/{Workflows → workflows}/Badge.md +0 -0
- /package/skill/{Workflows → workflows}/Composability.md +0 -0
- /package/skill/{Workflows → workflows}/EvolutionMemory.md +0 -0
- /package/skill/{Workflows → workflows}/ExportCanonical.md +0 -0
- /package/skill/{Workflows → workflows}/Hook.md +0 -0
- /package/skill/{Workflows → workflows}/ImportSkillsBench.md +0 -0
- /package/skill/{Workflows → workflows}/Quickstart.md +0 -0
- /package/skill/{Workflows → workflows}/Recover.md +0 -0
- /package/skill/{Workflows → workflows}/RepairSkillUsage.md +0 -0
- /package/skill/{Workflows → workflows}/Replay.md +0 -0
- /package/skill/{Workflows → workflows}/Rollback.md +0 -0
- /package/skill/{Workflows → workflows}/Telemetry.md +0 -0
- /package/skill/{Workflows → workflows}/Uninstall.md +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
import type { OrchestrateRunReport, PendingProposal } from "../../dashboard-contract.js";
|
|
4
|
+
import { safeParseJson, safeParseJsonArray } from "./json.js";
|
|
5
|
+
|
|
6
|
+
export function queryEvolutionAudit(
|
|
7
|
+
db: Database,
|
|
8
|
+
skillName?: string,
|
|
9
|
+
): Array<{
|
|
10
|
+
timestamp: string;
|
|
11
|
+
proposal_id: string;
|
|
12
|
+
skill_name?: string;
|
|
13
|
+
action: string;
|
|
14
|
+
details: string;
|
|
15
|
+
eval_snapshot?: Record<string, unknown>;
|
|
16
|
+
validation_mode?: string;
|
|
17
|
+
validation_agent?: string;
|
|
18
|
+
validation_fixture_id?: string;
|
|
19
|
+
validation_evidence_ref?: string;
|
|
20
|
+
}> {
|
|
21
|
+
const sql = skillName
|
|
22
|
+
? `SELECT * FROM evolution_audit
|
|
23
|
+
WHERE skill_name = ?
|
|
24
|
+
OR (skill_name IS NULL AND proposal_id LIKE 'evo-' || ? || '-%')
|
|
25
|
+
ORDER BY timestamp DESC`
|
|
26
|
+
: `SELECT * FROM evolution_audit ORDER BY timestamp DESC`;
|
|
27
|
+
const rows = (skillName ? db.query(sql).all(skillName, skillName) : db.query(sql).all()) as Array<
|
|
28
|
+
Record<string, unknown>
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
return rows.map((row) => ({
|
|
32
|
+
timestamp: row.timestamp as string,
|
|
33
|
+
proposal_id: row.proposal_id as string,
|
|
34
|
+
skill_name: typeof row.skill_name === "string" ? row.skill_name : undefined,
|
|
35
|
+
action: row.action as string,
|
|
36
|
+
details: row.details as string,
|
|
37
|
+
eval_snapshot: row.eval_snapshot_json
|
|
38
|
+
? (safeParseJson(row.eval_snapshot_json as string) as Record<string, unknown>)
|
|
39
|
+
: undefined,
|
|
40
|
+
validation_mode: typeof row.validation_mode === "string" ? row.validation_mode : undefined,
|
|
41
|
+
validation_agent: typeof row.validation_agent === "string" ? row.validation_agent : undefined,
|
|
42
|
+
validation_fixture_id:
|
|
43
|
+
typeof row.validation_fixture_id === "string" ? row.validation_fixture_id : undefined,
|
|
44
|
+
validation_evidence_ref:
|
|
45
|
+
typeof row.validation_evidence_ref === "string" ? row.validation_evidence_ref : undefined,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function queryEvolutionEvidence(
|
|
50
|
+
db: Database,
|
|
51
|
+
skillName?: string,
|
|
52
|
+
): Array<{
|
|
53
|
+
timestamp: string;
|
|
54
|
+
proposal_id: string;
|
|
55
|
+
skill_name: string;
|
|
56
|
+
skill_path: string;
|
|
57
|
+
target: string;
|
|
58
|
+
stage: string;
|
|
59
|
+
rationale?: string;
|
|
60
|
+
confidence?: number;
|
|
61
|
+
details?: string;
|
|
62
|
+
original_text?: string;
|
|
63
|
+
proposed_text?: string;
|
|
64
|
+
eval_set?: Record<string, unknown>[];
|
|
65
|
+
validation?: Record<string, unknown>;
|
|
66
|
+
}> {
|
|
67
|
+
const sql = skillName
|
|
68
|
+
? `SELECT * FROM evolution_evidence WHERE skill_name = ? ORDER BY timestamp DESC`
|
|
69
|
+
: `SELECT * FROM evolution_evidence ORDER BY timestamp DESC`;
|
|
70
|
+
const rows = (skillName ? db.query(sql).all(skillName) : db.query(sql).all()) as Array<
|
|
71
|
+
Record<string, unknown>
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
return rows.map((row) => ({
|
|
75
|
+
timestamp: row.timestamp as string,
|
|
76
|
+
proposal_id: row.proposal_id as string,
|
|
77
|
+
skill_name: row.skill_name as string,
|
|
78
|
+
skill_path: row.skill_path as string,
|
|
79
|
+
target: row.target as string,
|
|
80
|
+
stage: row.stage as string,
|
|
81
|
+
rationale: row.rationale as string | undefined,
|
|
82
|
+
confidence: row.confidence as number | undefined,
|
|
83
|
+
details: row.details as string | undefined,
|
|
84
|
+
original_text: row.original_text as string | undefined,
|
|
85
|
+
proposed_text: row.proposed_text as string | undefined,
|
|
86
|
+
eval_set: row.eval_set_json
|
|
87
|
+
? safeParseJsonArray<Record<string, unknown>>(row.eval_set_json as string)
|
|
88
|
+
: undefined,
|
|
89
|
+
validation: row.validation_json
|
|
90
|
+
? (safeParseJson(row.validation_json as string) as Record<string, unknown>)
|
|
91
|
+
: undefined,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getPendingProposals(db: Database, skillName?: string): PendingProposal[] {
|
|
96
|
+
const whereClause = skillName ? "WHERE ea.skill_name = ? AND" : "WHERE";
|
|
97
|
+
const params = skillName ? [skillName] : [];
|
|
98
|
+
|
|
99
|
+
return db
|
|
100
|
+
.query(
|
|
101
|
+
`WITH latest AS (
|
|
102
|
+
SELECT ea.proposal_id, ea.action, ea.timestamp, ea.details, ea.skill_name,
|
|
103
|
+
ROW_NUMBER() OVER (PARTITION BY ea.proposal_id ORDER BY ea.timestamp DESC, ea.id DESC) AS rn
|
|
104
|
+
FROM evolution_audit ea
|
|
105
|
+
LEFT JOIN evolution_audit ea2
|
|
106
|
+
ON ea2.proposal_id = ea.proposal_id
|
|
107
|
+
AND ea2.action IN ('deployed', 'rejected', 'rolled_back')
|
|
108
|
+
${whereClause} ea.action IN ('created', 'validated')
|
|
109
|
+
AND ea2.id IS NULL
|
|
110
|
+
)
|
|
111
|
+
SELECT proposal_id, action, timestamp, details, skill_name
|
|
112
|
+
FROM latest
|
|
113
|
+
WHERE rn = 1
|
|
114
|
+
ORDER BY timestamp DESC`,
|
|
115
|
+
)
|
|
116
|
+
.all(...params) as PendingProposal[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getOrchestrateRuns(db: Database, limit = 20): OrchestrateRunReport[] {
|
|
120
|
+
const rows = db
|
|
121
|
+
.query(
|
|
122
|
+
`SELECT run_id, timestamp, elapsed_ms, dry_run, approval_mode,
|
|
123
|
+
total_skills, evaluated, evolved, deployed, watched, skipped,
|
|
124
|
+
skill_actions_json
|
|
125
|
+
FROM orchestrate_runs
|
|
126
|
+
ORDER BY timestamp DESC
|
|
127
|
+
LIMIT ?`,
|
|
128
|
+
)
|
|
129
|
+
.all(limit) as Array<{
|
|
130
|
+
run_id: string;
|
|
131
|
+
timestamp: string;
|
|
132
|
+
elapsed_ms: number;
|
|
133
|
+
dry_run: number;
|
|
134
|
+
approval_mode: string;
|
|
135
|
+
total_skills: number;
|
|
136
|
+
evaluated: number;
|
|
137
|
+
evolved: number;
|
|
138
|
+
deployed: number;
|
|
139
|
+
watched: number;
|
|
140
|
+
skipped: number;
|
|
141
|
+
skill_actions_json: string;
|
|
142
|
+
}>;
|
|
143
|
+
|
|
144
|
+
return rows.map((row) => ({
|
|
145
|
+
run_id: row.run_id,
|
|
146
|
+
timestamp: row.timestamp,
|
|
147
|
+
elapsed_ms: row.elapsed_ms,
|
|
148
|
+
dry_run: row.dry_run === 1,
|
|
149
|
+
approval_mode: row.approval_mode as "auto" | "review",
|
|
150
|
+
total_skills: row.total_skills,
|
|
151
|
+
evaluated: row.evaluated,
|
|
152
|
+
evolved: row.evolved,
|
|
153
|
+
deployed: row.deployed,
|
|
154
|
+
watched: row.watched,
|
|
155
|
+
skipped: row.skipped,
|
|
156
|
+
skill_actions: safeParseJsonArray(row.skill_actions_json),
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
import type { CommitRecord, CommitSummary, ExecutionMetrics } from "../../dashboard-contract.js";
|
|
4
|
+
|
|
5
|
+
export function getExecutionMetrics(db: Database, sessionIds: string[]): ExecutionMetrics {
|
|
6
|
+
const empty: ExecutionMetrics = {
|
|
7
|
+
avg_files_changed: 0,
|
|
8
|
+
total_lines_added: 0,
|
|
9
|
+
total_lines_removed: 0,
|
|
10
|
+
total_cost_usd: 0,
|
|
11
|
+
avg_cost_usd: 0,
|
|
12
|
+
cached_input_tokens_total: 0,
|
|
13
|
+
reasoning_output_tokens_total: 0,
|
|
14
|
+
artifact_count: 0,
|
|
15
|
+
session_type_distribution: {},
|
|
16
|
+
};
|
|
17
|
+
if (sessionIds.length === 0) return empty;
|
|
18
|
+
|
|
19
|
+
const placeholders = sessionIds.map(() => "?").join(",");
|
|
20
|
+
const row = db
|
|
21
|
+
.query(
|
|
22
|
+
`SELECT
|
|
23
|
+
COALESCE(AVG(files_changed), 0) AS avg_files_changed,
|
|
24
|
+
COALESCE(SUM(lines_added), 0) AS total_lines_added,
|
|
25
|
+
COALESCE(SUM(lines_removed), 0) AS total_lines_removed,
|
|
26
|
+
COALESCE(SUM(cost_usd), 0) AS total_cost_usd,
|
|
27
|
+
COALESCE(AVG(cost_usd), 0) AS avg_cost_usd,
|
|
28
|
+
COALESCE(SUM(cached_input_tokens), 0) AS cached_input_tokens_total,
|
|
29
|
+
COALESCE(SUM(reasoning_output_tokens), 0) AS reasoning_output_tokens_total,
|
|
30
|
+
COALESCE(SUM(artifact_count), 0) AS artifact_count
|
|
31
|
+
FROM execution_facts
|
|
32
|
+
WHERE session_id IN (${placeholders})`,
|
|
33
|
+
)
|
|
34
|
+
.get(...sessionIds) as {
|
|
35
|
+
avg_files_changed: number;
|
|
36
|
+
total_lines_added: number;
|
|
37
|
+
total_lines_removed: number;
|
|
38
|
+
total_cost_usd: number;
|
|
39
|
+
avg_cost_usd: number;
|
|
40
|
+
cached_input_tokens_total: number;
|
|
41
|
+
reasoning_output_tokens_total: number;
|
|
42
|
+
artifact_count: number;
|
|
43
|
+
} | null;
|
|
44
|
+
|
|
45
|
+
const typeRows = db
|
|
46
|
+
.query(
|
|
47
|
+
`SELECT session_type, COUNT(*) AS count
|
|
48
|
+
FROM execution_facts
|
|
49
|
+
WHERE session_id IN (${placeholders}) AND session_type IS NOT NULL
|
|
50
|
+
GROUP BY session_type`,
|
|
51
|
+
)
|
|
52
|
+
.all(...sessionIds) as Array<{ session_type: string; count: number }>;
|
|
53
|
+
|
|
54
|
+
const session_type_distribution: Record<string, number> = {};
|
|
55
|
+
for (const rowEntry of typeRows) {
|
|
56
|
+
session_type_distribution[rowEntry.session_type] = rowEntry.count;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
avg_files_changed: row?.avg_files_changed ?? 0,
|
|
61
|
+
total_lines_added: row?.total_lines_added ?? 0,
|
|
62
|
+
total_lines_removed: row?.total_lines_removed ?? 0,
|
|
63
|
+
total_cost_usd: row?.total_cost_usd ?? 0,
|
|
64
|
+
avg_cost_usd: row?.avg_cost_usd ?? 0,
|
|
65
|
+
cached_input_tokens_total: row?.cached_input_tokens_total ?? 0,
|
|
66
|
+
reasoning_output_tokens_total: row?.reasoning_output_tokens_total ?? 0,
|
|
67
|
+
artifact_count: row?.artifact_count ?? 0,
|
|
68
|
+
session_type_distribution,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getSessionCommits(db: Database, sessionId: string): CommitRecord[] {
|
|
73
|
+
return db
|
|
74
|
+
.query(
|
|
75
|
+
`SELECT commit_sha, commit_title, branch, repo_remote, timestamp
|
|
76
|
+
FROM commit_tracking
|
|
77
|
+
WHERE session_id = ?
|
|
78
|
+
ORDER BY timestamp DESC`,
|
|
79
|
+
)
|
|
80
|
+
.all(sessionId) as CommitRecord[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getSkillCommitSummary(db: Database, skillName: string): CommitSummary {
|
|
84
|
+
const empty: CommitSummary = {
|
|
85
|
+
total_commits: 0,
|
|
86
|
+
unique_branches: 0,
|
|
87
|
+
recent_commits: [],
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const statsRow = db
|
|
91
|
+
.query(
|
|
92
|
+
`WITH skill_sessions AS (
|
|
93
|
+
SELECT DISTINCT session_id FROM skill_invocations WHERE skill_name = ?
|
|
94
|
+
)
|
|
95
|
+
SELECT
|
|
96
|
+
COUNT(*) AS total_commits,
|
|
97
|
+
COUNT(DISTINCT ct.branch) AS unique_branches
|
|
98
|
+
FROM commit_tracking ct
|
|
99
|
+
WHERE ct.session_id IN (SELECT session_id FROM skill_sessions)`,
|
|
100
|
+
)
|
|
101
|
+
.get(skillName) as { total_commits: number; unique_branches: number } | null;
|
|
102
|
+
|
|
103
|
+
if (!statsRow || statsRow.total_commits === 0) return empty;
|
|
104
|
+
|
|
105
|
+
const recentRows = db
|
|
106
|
+
.query(
|
|
107
|
+
`WITH skill_sessions AS (
|
|
108
|
+
SELECT DISTINCT session_id FROM skill_invocations WHERE skill_name = ?
|
|
109
|
+
)
|
|
110
|
+
SELECT ct.commit_sha, ct.commit_title, ct.branch, ct.timestamp
|
|
111
|
+
FROM commit_tracking ct
|
|
112
|
+
WHERE ct.session_id IN (SELECT session_id FROM skill_sessions)
|
|
113
|
+
ORDER BY ct.timestamp DESC
|
|
114
|
+
LIMIT 20`,
|
|
115
|
+
)
|
|
116
|
+
.all(skillName) as Array<{
|
|
117
|
+
commit_sha: string;
|
|
118
|
+
commit_title: string | null;
|
|
119
|
+
branch: string | null;
|
|
120
|
+
timestamp: string;
|
|
121
|
+
}>;
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
total_commits: statsRow.total_commits,
|
|
125
|
+
unique_branches: statsRow.unique_branches,
|
|
126
|
+
recent_commits: recentRows.map((row) => ({
|
|
127
|
+
sha: row.commit_sha,
|
|
128
|
+
title: row.commit_title ?? "",
|
|
129
|
+
branch: row.branch ?? "",
|
|
130
|
+
timestamp: row.timestamp,
|
|
131
|
+
})),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function safeParseJsonArray<T = string>(json: string | null): T[] {
|
|
2
|
+
if (!json) return [];
|
|
3
|
+
try {
|
|
4
|
+
const parsed = JSON.parse(json);
|
|
5
|
+
return Array.isArray(parsed) ? (parsed as T[]) : [];
|
|
6
|
+
} catch {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function safeParseJson(json: string | null): Record<string, unknown> | null {
|
|
12
|
+
if (!json) return null;
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(json);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
export function queryImprovementSignals(
|
|
4
|
+
db: Database,
|
|
5
|
+
consumedOnly?: boolean,
|
|
6
|
+
): Array<{
|
|
7
|
+
timestamp: string;
|
|
8
|
+
session_id: string;
|
|
9
|
+
query: string;
|
|
10
|
+
signal_type: string;
|
|
11
|
+
mentioned_skill?: string;
|
|
12
|
+
consumed: boolean;
|
|
13
|
+
consumed_at?: string;
|
|
14
|
+
consumed_by_run?: string;
|
|
15
|
+
}> {
|
|
16
|
+
const where =
|
|
17
|
+
consumedOnly === undefined ? "" : consumedOnly ? " WHERE consumed = 1" : " WHERE consumed = 0";
|
|
18
|
+
const rows = db
|
|
19
|
+
.query(`SELECT * FROM improvement_signals${where} ORDER BY timestamp DESC`)
|
|
20
|
+
.all() as Array<Record<string, unknown>>;
|
|
21
|
+
return rows.map((row) => ({
|
|
22
|
+
timestamp: row.timestamp as string,
|
|
23
|
+
session_id: row.session_id as string,
|
|
24
|
+
query: row.query as string,
|
|
25
|
+
signal_type: row.signal_type as string,
|
|
26
|
+
mentioned_skill: row.mentioned_skill as string | undefined,
|
|
27
|
+
consumed: (row.consumed as number) === 1,
|
|
28
|
+
consumed_at: row.consumed_at as string | undefined,
|
|
29
|
+
consumed_by_run: row.consumed_by_run as string | undefined,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function queryGradingResults(db: Database): Array<{
|
|
34
|
+
grading_id: string;
|
|
35
|
+
session_id: string;
|
|
36
|
+
skill_name: string;
|
|
37
|
+
transcript_path: string | null;
|
|
38
|
+
graded_at: string;
|
|
39
|
+
pass_rate: number | null;
|
|
40
|
+
mean_score: number | null;
|
|
41
|
+
score_std_dev: number | null;
|
|
42
|
+
passed_count: number | null;
|
|
43
|
+
failed_count: number | null;
|
|
44
|
+
total_count: number | null;
|
|
45
|
+
expectations_json: string | null;
|
|
46
|
+
claims_json: string | null;
|
|
47
|
+
eval_feedback_json: string | null;
|
|
48
|
+
failure_feedback_json: string | null;
|
|
49
|
+
execution_metrics_json: string | null;
|
|
50
|
+
}> {
|
|
51
|
+
return db
|
|
52
|
+
.query(
|
|
53
|
+
`SELECT grading_id, session_id, skill_name, transcript_path, graded_at,
|
|
54
|
+
pass_rate, mean_score, score_std_dev, passed_count, failed_count, total_count,
|
|
55
|
+
expectations_json, claims_json, eval_feedback_json, failure_feedback_json,
|
|
56
|
+
execution_metrics_json
|
|
57
|
+
FROM grading_results
|
|
58
|
+
ORDER BY graded_at DESC`,
|
|
59
|
+
)
|
|
60
|
+
.all() as Array<{
|
|
61
|
+
grading_id: string;
|
|
62
|
+
session_id: string;
|
|
63
|
+
skill_name: string;
|
|
64
|
+
transcript_path: string | null;
|
|
65
|
+
graded_at: string;
|
|
66
|
+
pass_rate: number | null;
|
|
67
|
+
mean_score: number | null;
|
|
68
|
+
score_std_dev: number | null;
|
|
69
|
+
passed_count: number | null;
|
|
70
|
+
failed_count: number | null;
|
|
71
|
+
total_count: number | null;
|
|
72
|
+
expectations_json: string | null;
|
|
73
|
+
claims_json: string | null;
|
|
74
|
+
eval_feedback_json: string | null;
|
|
75
|
+
failure_feedback_json: string | null;
|
|
76
|
+
execution_metrics_json: string | null;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function queryReplayEntryResults(
|
|
81
|
+
db: Database,
|
|
82
|
+
proposalId: string,
|
|
83
|
+
phase?: string,
|
|
84
|
+
): Array<{
|
|
85
|
+
id: number;
|
|
86
|
+
proposal_id: string;
|
|
87
|
+
skill_name: string;
|
|
88
|
+
validation_mode: string;
|
|
89
|
+
phase: string;
|
|
90
|
+
query: string;
|
|
91
|
+
should_trigger: boolean;
|
|
92
|
+
triggered: boolean;
|
|
93
|
+
passed: boolean;
|
|
94
|
+
evidence: string | null;
|
|
95
|
+
}> {
|
|
96
|
+
const sql = phase
|
|
97
|
+
? `SELECT id, proposal_id, skill_name, validation_mode, phase, query,
|
|
98
|
+
should_trigger, triggered, passed, evidence
|
|
99
|
+
FROM replay_entry_results
|
|
100
|
+
WHERE proposal_id = ? AND phase = ?
|
|
101
|
+
ORDER BY id`
|
|
102
|
+
: `SELECT id, proposal_id, skill_name, validation_mode, phase, query,
|
|
103
|
+
should_trigger, triggered, passed, evidence
|
|
104
|
+
FROM replay_entry_results
|
|
105
|
+
WHERE proposal_id = ?
|
|
106
|
+
ORDER BY id`;
|
|
107
|
+
|
|
108
|
+
const rows = phase
|
|
109
|
+
? (db.query(sql).all(proposalId, phase) as Array<Record<string, unknown>>)
|
|
110
|
+
: (db.query(sql).all(proposalId) as Array<Record<string, unknown>>);
|
|
111
|
+
|
|
112
|
+
return rows.map((row) => ({
|
|
113
|
+
id: row.id as number,
|
|
114
|
+
proposal_id: row.proposal_id as string,
|
|
115
|
+
skill_name: row.skill_name as string,
|
|
116
|
+
validation_mode: row.validation_mode as string,
|
|
117
|
+
phase: row.phase as string,
|
|
118
|
+
query: row.query as string,
|
|
119
|
+
should_trigger: (row.should_trigger as number) === 1,
|
|
120
|
+
triggered: (row.triggered as number) === 1,
|
|
121
|
+
passed: (row.passed as number) === 1,
|
|
122
|
+
evidence: row.evidence as string | null,
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function queryReplayRegressions(
|
|
127
|
+
db: Database,
|
|
128
|
+
proposalId: string,
|
|
129
|
+
): Array<{
|
|
130
|
+
query: string;
|
|
131
|
+
skill_name: string;
|
|
132
|
+
before_passed: boolean;
|
|
133
|
+
after_passed: boolean;
|
|
134
|
+
}> {
|
|
135
|
+
const rows = db
|
|
136
|
+
.query(
|
|
137
|
+
`SELECT b.query, b.skill_name,
|
|
138
|
+
b.passed AS before_passed,
|
|
139
|
+
a.passed AS after_passed
|
|
140
|
+
FROM replay_entry_results b
|
|
141
|
+
JOIN replay_entry_results a
|
|
142
|
+
ON b.proposal_id = a.proposal_id
|
|
143
|
+
AND b.query = a.query
|
|
144
|
+
AND b.skill_name = a.skill_name
|
|
145
|
+
WHERE b.proposal_id = ?
|
|
146
|
+
AND b.phase = 'before'
|
|
147
|
+
AND a.phase = 'after'
|
|
148
|
+
AND b.passed = 1
|
|
149
|
+
AND a.passed = 0
|
|
150
|
+
ORDER BY b.query`,
|
|
151
|
+
)
|
|
152
|
+
.all(proposalId) as Array<Record<string, unknown>>;
|
|
153
|
+
|
|
154
|
+
return rows.map((row) => ({
|
|
155
|
+
query: row.query as string,
|
|
156
|
+
skill_name: row.skill_name as string,
|
|
157
|
+
before_passed: (row.before_passed as number) === 1,
|
|
158
|
+
after_passed: (row.after_passed as number) === 1,
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface GradingBaselineRow {
|
|
163
|
+
id: number;
|
|
164
|
+
skill_name: string;
|
|
165
|
+
proposal_id: string | null;
|
|
166
|
+
measured_at: string;
|
|
167
|
+
pass_rate: number;
|
|
168
|
+
mean_score: number | null;
|
|
169
|
+
sample_size: number;
|
|
170
|
+
grading_results_json: string | null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface GradeRegressionResult {
|
|
174
|
+
before: GradingBaselineRow;
|
|
175
|
+
after: GradingBaselineRow;
|
|
176
|
+
delta_pass_rate: number;
|
|
177
|
+
delta_mean_score: number | null;
|
|
178
|
+
regressed: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function queryGradingBaseline(
|
|
182
|
+
db: Database,
|
|
183
|
+
skillName: string,
|
|
184
|
+
proposalId?: string,
|
|
185
|
+
): GradingBaselineRow | null {
|
|
186
|
+
if (proposalId !== undefined) {
|
|
187
|
+
return (
|
|
188
|
+
(db
|
|
189
|
+
.query(
|
|
190
|
+
`SELECT * FROM grading_baselines
|
|
191
|
+
WHERE skill_name = ? AND proposal_id = ?
|
|
192
|
+
ORDER BY measured_at DESC
|
|
193
|
+
LIMIT 1`,
|
|
194
|
+
)
|
|
195
|
+
.get(skillName, proposalId) as GradingBaselineRow | null) ?? null
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return (
|
|
200
|
+
(db
|
|
201
|
+
.query(
|
|
202
|
+
`SELECT * FROM grading_baselines
|
|
203
|
+
WHERE skill_name = ? AND proposal_id IS NULL
|
|
204
|
+
ORDER BY measured_at DESC
|
|
205
|
+
LIMIT 1`,
|
|
206
|
+
)
|
|
207
|
+
.get(skillName) as GradingBaselineRow | null) ?? null
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function queryGradeRegression(
|
|
212
|
+
db: Database,
|
|
213
|
+
skillName: string,
|
|
214
|
+
afterProposalId: string,
|
|
215
|
+
beforeProposalId?: string,
|
|
216
|
+
): GradeRegressionResult | null {
|
|
217
|
+
const before = queryGradingBaseline(db, skillName, beforeProposalId);
|
|
218
|
+
const after = queryGradingBaseline(db, skillName, afterProposalId);
|
|
219
|
+
if (!before || !after) return null;
|
|
220
|
+
|
|
221
|
+
const deltaPR = after.pass_rate - before.pass_rate;
|
|
222
|
+
const deltaMS =
|
|
223
|
+
after.mean_score != null && before.mean_score != null
|
|
224
|
+
? after.mean_score - before.mean_score
|
|
225
|
+
: null;
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
before,
|
|
229
|
+
after,
|
|
230
|
+
delta_pass_rate: deltaPR,
|
|
231
|
+
delta_mean_score: deltaMS,
|
|
232
|
+
regressed: deltaPR < 0,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface RecentGradingResultRow {
|
|
237
|
+
grading_id: string;
|
|
238
|
+
session_id: string;
|
|
239
|
+
skill_name: string;
|
|
240
|
+
graded_at: string;
|
|
241
|
+
pass_rate: number | null;
|
|
242
|
+
mean_score: number | null;
|
|
243
|
+
total_count: number | null;
|
|
244
|
+
passed_count: number | null;
|
|
245
|
+
failed_count: number | null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function queryRecentGradingResults(
|
|
249
|
+
db: Database,
|
|
250
|
+
skillName: string,
|
|
251
|
+
limit: number = 20,
|
|
252
|
+
): RecentGradingResultRow[] {
|
|
253
|
+
return db
|
|
254
|
+
.query(
|
|
255
|
+
`SELECT grading_id, session_id, skill_name, graded_at,
|
|
256
|
+
pass_rate, mean_score, total_count, passed_count, failed_count
|
|
257
|
+
FROM grading_results
|
|
258
|
+
WHERE skill_name = ?
|
|
259
|
+
ORDER BY graded_at DESC
|
|
260
|
+
LIMIT ?`,
|
|
261
|
+
)
|
|
262
|
+
.all(skillName, limit) as RecentGradingResultRow[];
|
|
263
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
import type { SkillUsageRecord } from "../../types.js";
|
|
4
|
+
import { safeParseJson, safeParseJsonArray } from "./json.js";
|
|
5
|
+
|
|
6
|
+
export function querySessionTelemetry(
|
|
7
|
+
db: Database,
|
|
8
|
+
limit?: number,
|
|
9
|
+
): Array<{
|
|
10
|
+
timestamp: string;
|
|
11
|
+
session_id: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
transcript_path: string;
|
|
14
|
+
tool_calls: Record<string, number>;
|
|
15
|
+
total_tool_calls: number;
|
|
16
|
+
bash_commands: string[];
|
|
17
|
+
skills_triggered: string[];
|
|
18
|
+
skills_invoked?: string[];
|
|
19
|
+
assistant_turns: number;
|
|
20
|
+
errors_encountered: number;
|
|
21
|
+
transcript_chars: number;
|
|
22
|
+
last_user_query: string;
|
|
23
|
+
source?: string;
|
|
24
|
+
input_tokens?: number;
|
|
25
|
+
output_tokens?: number;
|
|
26
|
+
}> {
|
|
27
|
+
const sql =
|
|
28
|
+
limit != null
|
|
29
|
+
? `SELECT * FROM session_telemetry ORDER BY timestamp DESC LIMIT ${limit}`
|
|
30
|
+
: `SELECT * FROM session_telemetry ORDER BY timestamp DESC`;
|
|
31
|
+
const rows = db.query(sql).all() as Array<Record<string, unknown>>;
|
|
32
|
+
return rows.map((row) => ({
|
|
33
|
+
timestamp: row.timestamp as string,
|
|
34
|
+
session_id: row.session_id as string,
|
|
35
|
+
cwd: row.cwd as string,
|
|
36
|
+
transcript_path: row.transcript_path as string,
|
|
37
|
+
tool_calls: (safeParseJson(row.tool_calls_json as string) as Record<string, number>) ?? {},
|
|
38
|
+
total_tool_calls: row.total_tool_calls as number,
|
|
39
|
+
bash_commands: safeParseJsonArray<string>(row.bash_commands_json as string),
|
|
40
|
+
skills_triggered: safeParseJsonArray<string>(row.skills_triggered_json as string),
|
|
41
|
+
skills_invoked: row.skills_invoked_json
|
|
42
|
+
? safeParseJsonArray<string>(row.skills_invoked_json as string)
|
|
43
|
+
: undefined,
|
|
44
|
+
assistant_turns: row.assistant_turns as number,
|
|
45
|
+
errors_encountered: row.errors_encountered as number,
|
|
46
|
+
transcript_chars: (row.transcript_chars as number) ?? 0,
|
|
47
|
+
last_user_query: (row.last_user_query as string) ?? "",
|
|
48
|
+
source: row.source as string | undefined,
|
|
49
|
+
input_tokens: row.input_tokens as number | undefined,
|
|
50
|
+
output_tokens: row.output_tokens as number | undefined,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function querySkillRecords(db: Database, limit?: number): SkillUsageRecord[] {
|
|
55
|
+
const sql =
|
|
56
|
+
limit != null
|
|
57
|
+
? `SELECT occurred_at, session_id, skill_name, skill_path, skill_scope, query, triggered, source
|
|
58
|
+
FROM skill_invocations ORDER BY occurred_at DESC LIMIT ${limit}`
|
|
59
|
+
: `SELECT occurred_at, session_id, skill_name, skill_path, skill_scope, query, triggered, source
|
|
60
|
+
FROM skill_invocations ORDER BY occurred_at DESC`;
|
|
61
|
+
const rows = db.query(sql).all() as Array<Record<string, unknown>>;
|
|
62
|
+
return rows.map((row) => ({
|
|
63
|
+
timestamp: row.occurred_at as string,
|
|
64
|
+
session_id: row.session_id as string,
|
|
65
|
+
skill_name: row.skill_name as string,
|
|
66
|
+
skill_path: row.skill_path as string,
|
|
67
|
+
skill_scope: row.skill_scope as SkillUsageRecord["skill_scope"],
|
|
68
|
+
query: row.query as string,
|
|
69
|
+
triggered: (row.triggered as number) === 1,
|
|
70
|
+
source: row.source as string | undefined,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const querySkillUsageRecords = querySkillRecords;
|
|
75
|
+
|
|
76
|
+
export function queryQueryLog(
|
|
77
|
+
db: Database,
|
|
78
|
+
limit?: number,
|
|
79
|
+
): Array<{
|
|
80
|
+
timestamp: string;
|
|
81
|
+
session_id: string;
|
|
82
|
+
query: string;
|
|
83
|
+
source?: string;
|
|
84
|
+
}> {
|
|
85
|
+
const sql =
|
|
86
|
+
limit != null
|
|
87
|
+
? `SELECT timestamp, session_id, query, source FROM queries ORDER BY timestamp DESC LIMIT ${limit}`
|
|
88
|
+
: `SELECT timestamp, session_id, query, source FROM queries ORDER BY timestamp DESC`;
|
|
89
|
+
return db.query(sql).all() as Array<{
|
|
90
|
+
timestamp: string;
|
|
91
|
+
session_id: string;
|
|
92
|
+
query: string;
|
|
93
|
+
source?: string;
|
|
94
|
+
}>;
|
|
95
|
+
}
|