selftune 0.2.9 → 0.2.10
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 +35 -35
- package/apps/local-dashboard/dist/assets/index-BZVLv70T.js +16 -0
- package/apps/local-dashboard/dist/assets/{vendor-react-BQH_6WrG.js → vendor-react-BXP54cYo.js} +4 -4
- package/apps/local-dashboard/dist/assets/{vendor-table-dK1QMLq9.js → vendor-table-DTF_SXoy.js} +1 -1
- package/apps/local-dashboard/dist/assets/{vendor-ui-CO2mrx6e.js → vendor-ui-CWU0d1wd.js} +66 -66
- package/apps/local-dashboard/dist/index.html +15 -15
- package/bin/selftune.cjs +1 -1
- package/cli/selftune/activation-rules.ts +1 -0
- package/cli/selftune/alpha-upload/build-payloads.ts +18 -2
- package/cli/selftune/alpha-upload/stage-canonical.ts +94 -0
- package/cli/selftune/auth/device-code.ts +32 -0
- package/cli/selftune/auto-update.ts +12 -0
- package/cli/selftune/badge/badge.ts +1 -0
- package/cli/selftune/canonical-export.ts +5 -0
- package/cli/selftune/claude-agents.ts +154 -0
- package/cli/selftune/contribute/bundle.ts +1 -0
- package/cli/selftune/contribute/contribute.ts +1 -0
- package/cli/selftune/cron/setup.ts +2 -2
- package/cli/selftune/dashboard-server.ts +1 -0
- package/cli/selftune/eval/hooks-to-evals.ts +1 -0
- package/cli/selftune/eval/import-skillsbench.ts +1 -0
- package/cli/selftune/eval/synthetic-evals.ts +2 -3
- package/cli/selftune/eval/unit-test.ts +1 -0
- package/cli/selftune/evolution/deploy-proposal.ts +1 -0
- package/cli/selftune/evolution/evolve-body.ts +93 -6
- package/cli/selftune/evolution/evolve.ts +0 -1
- package/cli/selftune/evolution/propose-body.ts +3 -2
- package/cli/selftune/evolution/propose-routing.ts +3 -2
- package/cli/selftune/evolution/refine-body.ts +3 -2
- package/cli/selftune/export.ts +1 -0
- package/cli/selftune/grading/grade-session.ts +8 -0
- package/cli/selftune/hooks/auto-activate.ts +1 -0
- package/cli/selftune/hooks/evolution-guard.ts +1 -1
- package/cli/selftune/hooks/prompt-log.ts +1 -0
- package/cli/selftune/hooks/session-stop.ts +34 -40
- package/cli/selftune/hooks/skill-change-guard.ts +1 -0
- package/cli/selftune/hooks/skill-eval.ts +1 -1
- package/cli/selftune/index.ts +23 -14
- package/cli/selftune/ingestors/claude-replay.ts +1 -0
- package/cli/selftune/ingestors/codex-rollout.ts +1 -0
- package/cli/selftune/ingestors/codex-wrapper.ts +1 -0
- package/cli/selftune/ingestors/openclaw-ingest.ts +1 -0
- package/cli/selftune/ingestors/opencode-ingest.ts +1 -0
- package/cli/selftune/init.ts +121 -29
- package/cli/selftune/localdb/db.ts +1 -0
- package/cli/selftune/localdb/direct-write.ts +39 -0
- package/cli/selftune/localdb/materialize.ts +2 -0
- package/cli/selftune/localdb/queries.ts +53 -0
- package/cli/selftune/localdb/schema.ts +28 -0
- package/cli/selftune/normalization.ts +1 -0
- package/cli/selftune/observability.ts +1 -0
- package/cli/selftune/repair/skill-usage.ts +1 -0
- package/cli/selftune/routes/orchestrate-runs.ts +1 -0
- package/cli/selftune/routes/overview.ts +1 -0
- package/cli/selftune/routes/skill-report.ts +1 -0
- package/cli/selftune/sync.ts +30 -1
- package/cli/selftune/uninstall.ts +412 -0
- package/cli/selftune/utils/canonical-log.ts +2 -0
- package/cli/selftune/utils/jsonl.ts +1 -0
- package/cli/selftune/utils/llm-call.ts +131 -3
- package/cli/selftune/utils/skill-log.ts +1 -0
- package/cli/selftune/utils/transcript.ts +1 -0
- package/cli/selftune/utils/trigger-check.ts +1 -1
- package/cli/selftune/workflows/skill-md-writer.ts +5 -5
- package/cli/selftune/workflows/workflows.ts +1 -0
- package/package.json +37 -33
- package/packages/telemetry-contract/fixtures/golden.test.ts +1 -0
- package/packages/telemetry-contract/package.json +1 -1
- package/packages/telemetry-contract/src/schemas.ts +1 -0
- package/packages/telemetry-contract/tests/compatibility.test.ts +1 -0
- package/packages/ui/README.md +35 -34
- package/packages/ui/package.json +3 -3
- package/packages/ui/src/components/ActivityTimeline.tsx +49 -42
- package/packages/ui/src/components/EvidenceViewer.tsx +306 -182
- package/packages/ui/src/components/EvolutionTimeline.tsx +83 -72
- package/packages/ui/src/components/InfoTip.tsx +4 -3
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +60 -53
- package/packages/ui/src/components/section-cards.tsx +19 -24
- package/packages/ui/src/components/skill-health-grid.tsx +213 -193
- package/packages/ui/src/lib/constants.tsx +1 -0
- package/packages/ui/src/primitives/badge.tsx +12 -15
- package/packages/ui/src/primitives/button.tsx +7 -7
- package/packages/ui/src/primitives/card.tsx +15 -26
- package/packages/ui/src/primitives/checkbox.tsx +7 -8
- package/packages/ui/src/primitives/collapsible.tsx +5 -5
- package/packages/ui/src/primitives/dropdown-menu.tsx +45 -55
- package/packages/ui/src/primitives/label.tsx +6 -6
- package/packages/ui/src/primitives/select.tsx +28 -37
- package/packages/ui/src/primitives/table.tsx +17 -44
- package/packages/ui/src/primitives/tabs.tsx +14 -21
- package/packages/ui/src/primitives/tooltip.tsx +10 -22
- package/skill/SKILL.md +70 -57
- package/skill/Workflows/AlphaUpload.md +4 -4
- package/skill/Workflows/AutoActivation.md +11 -6
- package/skill/Workflows/Badge.md +22 -16
- package/skill/Workflows/Baseline.md +34 -36
- package/skill/Workflows/Composability.md +16 -11
- package/skill/Workflows/Contribute.md +26 -21
- package/skill/Workflows/Cron.md +23 -22
- package/skill/Workflows/Dashboard.md +32 -27
- package/skill/Workflows/Doctor.md +33 -27
- package/skill/Workflows/Evals.md +48 -47
- package/skill/Workflows/EvolutionMemory.md +31 -21
- package/skill/Workflows/Evolve.md +84 -82
- package/skill/Workflows/EvolveBody.md +58 -47
- package/skill/Workflows/Grade.md +16 -13
- package/skill/Workflows/ImportSkillsBench.md +9 -6
- package/skill/Workflows/Ingest.md +36 -21
- package/skill/Workflows/Initialize.md +108 -40
- package/skill/Workflows/Orchestrate.md +22 -16
- package/skill/Workflows/Replay.md +12 -7
- package/skill/Workflows/Rollback.md +13 -6
- package/skill/Workflows/Schedule.md +6 -6
- package/skill/Workflows/Sync.md +18 -11
- package/skill/Workflows/UnitTest.md +28 -17
- package/skill/Workflows/Watch.md +28 -21
- package/skill/agents/diagnosis-analyst.md +11 -0
- package/skill/agents/evolution-reviewer.md +15 -1
- package/skill/agents/integration-guide.md +10 -0
- package/skill/agents/pattern-analyst.md +12 -1
- package/skill/references/grading-methodology.md +23 -24
- package/skill/references/interactive-config.md +7 -7
- package/skill/references/invocation-taxonomy.md +22 -20
- package/skill/references/logs.md +14 -6
- package/skill/references/setup-patterns.md +4 -2
- package/.claude/agents/diagnosis-analyst.md +0 -156
- package/.claude/agents/evolution-reviewer.md +0 -180
- package/.claude/agents/integration-guide.md +0 -212
- package/.claude/agents/pattern-analyst.md +0 -160
- package/apps/local-dashboard/dist/assets/index-C4UYGWKr.js +0 -15
package/cli/selftune/init.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
10
|
* selftune init [--agent <type>] [--cli-path <path>] [--force]
|
|
11
|
-
* selftune init --
|
|
11
|
+
* selftune init [--no-sync] [--no-autonomy] [--schedule-format cron|launchd|systemd]
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import {
|
|
@@ -35,12 +35,20 @@ import {
|
|
|
35
35
|
readAlphaIdentity,
|
|
36
36
|
} from "./alpha-identity.js";
|
|
37
37
|
import { TELEMETRY_NOTICE } from "./analytics.js";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
buildVerificationUrl,
|
|
40
|
+
pollDeviceCode,
|
|
41
|
+
requestDeviceCode,
|
|
42
|
+
tryOpenUrl,
|
|
43
|
+
} from "./auth/device-code.js";
|
|
44
|
+
import { installAgentFiles } from "./claude-agents.js";
|
|
39
45
|
import { CLAUDE_CODE_HOOK_KEYS, SELFTUNE_CONFIG_DIR, SELFTUNE_CONFIG_PATH } from "./constants.js";
|
|
40
46
|
import type { AgentCommandGuidance, AlphaIdentity, SelftuneConfig } from "./types.js";
|
|
41
47
|
import { hookKeyHasSelftuneEntry } from "./utils/hooks.js";
|
|
42
48
|
import { detectAgent } from "./utils/llm-call.js";
|
|
43
49
|
|
|
50
|
+
export { installAgentFiles } from "./claude-agents.js";
|
|
51
|
+
|
|
44
52
|
interface InitCliErrorPayload extends AgentCommandGuidance {
|
|
45
53
|
error: string;
|
|
46
54
|
}
|
|
@@ -309,19 +317,6 @@ export function installClaudeCodeHooks(options?: {
|
|
|
309
317
|
return addedKeys;
|
|
310
318
|
}
|
|
311
319
|
|
|
312
|
-
// ---------------------------------------------------------------------------
|
|
313
|
-
// Agent file installation
|
|
314
|
-
// ---------------------------------------------------------------------------
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* @deprecated Agent files are now bundled in skill/agents/ and read directly
|
|
318
|
-
* by the consuming agent via progressive disclosure. No installation needed.
|
|
319
|
-
* Kept as a no-op for backwards compatibility with callers.
|
|
320
|
-
*/
|
|
321
|
-
export function installAgentFiles(_options?: { homeDir?: string; force?: boolean }): string[] {
|
|
322
|
-
return [];
|
|
323
|
-
}
|
|
324
|
-
|
|
325
320
|
// ---------------------------------------------------------------------------
|
|
326
321
|
// Workspace type detection
|
|
327
322
|
// ---------------------------------------------------------------------------
|
|
@@ -508,7 +503,11 @@ export async function runInit(opts: InitOptions): Promise<SelftuneConfig> {
|
|
|
508
503
|
if (!force && !hasAlphaMutation && existsSync(configPath)) {
|
|
509
504
|
const raw = readFileSync(configPath, "utf-8");
|
|
510
505
|
try {
|
|
511
|
-
|
|
506
|
+
const existingConfig = JSON.parse(raw) as SelftuneConfig;
|
|
507
|
+
if (existingConfig.agent_type === "claude_code") {
|
|
508
|
+
installAgentFiles({ homeDir: opts.homeDir });
|
|
509
|
+
}
|
|
510
|
+
return existingConfig;
|
|
512
511
|
} catch (err) {
|
|
513
512
|
throw new Error(
|
|
514
513
|
`Config file at ${configPath} contains invalid JSON. Delete it or use --force to reinitialize. Cause: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -548,6 +547,7 @@ export async function runInit(opts: InitOptions): Promise<SelftuneConfig> {
|
|
|
548
547
|
process.stderr.write("[alpha] Starting device-code authentication flow...\n");
|
|
549
548
|
|
|
550
549
|
const grant = await requestDeviceCode();
|
|
550
|
+
const verificationUrlWithCode = buildVerificationUrl(grant.verification_url, grant.user_code);
|
|
551
551
|
|
|
552
552
|
// Emit structured JSON for the agent to parse
|
|
553
553
|
console.log(
|
|
@@ -555,25 +555,24 @@ export async function runInit(opts: InitOptions): Promise<SelftuneConfig> {
|
|
|
555
555
|
level: "info",
|
|
556
556
|
code: "device_code_issued",
|
|
557
557
|
verification_url: grant.verification_url,
|
|
558
|
+
verification_url_with_code: verificationUrlWithCode,
|
|
558
559
|
user_code: grant.user_code,
|
|
559
560
|
expires_in: grant.expires_in,
|
|
560
|
-
message: `Open ${
|
|
561
|
+
message: `Open ${verificationUrlWithCode} to approve.`,
|
|
561
562
|
}),
|
|
562
563
|
);
|
|
563
564
|
|
|
564
565
|
// Try to open browser (skip in test environments)
|
|
565
566
|
if (!process.env.BUN_ENV?.includes("test") && !process.env.SELFTUNE_NO_BROWSER) {
|
|
566
|
-
|
|
567
|
-
const url = `${grant.verification_url}?code=${grant.user_code}`;
|
|
568
|
-
Bun.spawn(["open", url], { stdout: "ignore", stderr: "ignore" });
|
|
567
|
+
if (tryOpenUrl(verificationUrlWithCode)) {
|
|
569
568
|
process.stderr.write(`[alpha] Browser opened. Waiting for approval...\n`);
|
|
570
|
-
}
|
|
571
|
-
process.stderr.write(
|
|
569
|
+
} else {
|
|
570
|
+
process.stderr.write(
|
|
571
|
+
`[alpha] Could not open browser. Visit ${verificationUrlWithCode} manually.\n`,
|
|
572
|
+
);
|
|
572
573
|
}
|
|
573
574
|
} else {
|
|
574
|
-
process.stderr.write(
|
|
575
|
-
`[alpha] Visit ${grant.verification_url}?code=${grant.user_code} to approve.\n`,
|
|
576
|
-
);
|
|
575
|
+
process.stderr.write(`[alpha] Visit ${verificationUrlWithCode} to approve.\n`);
|
|
577
576
|
}
|
|
578
577
|
|
|
579
578
|
process.stderr.write("[alpha] Polling");
|
|
@@ -606,11 +605,15 @@ export async function runInit(opts: InitOptions): Promise<SelftuneConfig> {
|
|
|
606
605
|
mkdirSync(configDir, { recursive: true });
|
|
607
606
|
writeSelftuneConfig(configPath, config);
|
|
608
607
|
|
|
609
|
-
// Agent files are bundled in skill/agents/ and read directly by the
|
|
610
|
-
// consuming agent — no installation step needed.
|
|
611
|
-
|
|
612
608
|
// Auto-install hooks into ~/.claude/settings.json (Claude Code only)
|
|
613
609
|
if (agentType === "claude_code") {
|
|
610
|
+
const syncedAgentFiles = installAgentFiles({ homeDir: home });
|
|
611
|
+
if (syncedAgentFiles.length > 0) {
|
|
612
|
+
console.error(
|
|
613
|
+
`[INFO] Synced ${syncedAgentFiles.length} selftune agent file(s) into ${join(home, ".claude", "agents")}: ${syncedAgentFiles.join(", ")}`,
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
|
|
614
617
|
const addedHookKeys = installClaudeCodeHooks({
|
|
615
618
|
settingsPath,
|
|
616
619
|
cliPath,
|
|
@@ -668,6 +671,8 @@ export async function cliMain(): Promise<void> {
|
|
|
668
671
|
"cli-path": { type: "string" },
|
|
669
672
|
force: { type: "boolean", default: false },
|
|
670
673
|
"enable-autonomy": { type: "boolean", default: false },
|
|
674
|
+
"no-sync": { type: "boolean", default: false },
|
|
675
|
+
"no-autonomy": { type: "boolean", default: false },
|
|
671
676
|
"schedule-format": { type: "string" },
|
|
672
677
|
alpha: { type: "boolean", default: false },
|
|
673
678
|
"no-alpha": { type: "boolean", default: false },
|
|
@@ -680,7 +685,10 @@ export async function cliMain(): Promise<void> {
|
|
|
680
685
|
const configDir = SELFTUNE_CONFIG_DIR;
|
|
681
686
|
const configPath = SELFTUNE_CONFIG_PATH;
|
|
682
687
|
const force = values.force ?? false;
|
|
683
|
-
|
|
688
|
+
// Sync and autonomy are on by default; opt out with --no-sync / --no-autonomy
|
|
689
|
+
const enableSync = !(values["no-sync"] ?? false);
|
|
690
|
+
// --enable-autonomy is a backward-compatible alias (now default behavior)
|
|
691
|
+
const enableAutonomy = !values["no-autonomy"];
|
|
684
692
|
try {
|
|
685
693
|
validateAlphaMetadataFlags(values.alpha, values["alpha-email"], values["alpha-name"]);
|
|
686
694
|
} catch (error) {
|
|
@@ -695,6 +703,7 @@ export async function cliMain(): Promise<void> {
|
|
|
695
703
|
values["alpha-email"] ||
|
|
696
704
|
values["alpha-name"]
|
|
697
705
|
);
|
|
706
|
+
let existingConfigDetected = false;
|
|
698
707
|
if (!force && !enableAutonomy && !hasAlphaMutation && existsSync(configPath)) {
|
|
699
708
|
try {
|
|
700
709
|
const raw = readFileSync(configPath, "utf-8");
|
|
@@ -708,6 +717,14 @@ export async function cliMain(): Promise<void> {
|
|
|
708
717
|
);
|
|
709
718
|
}
|
|
710
719
|
}
|
|
720
|
+
if (!force && !hasAlphaMutation && existsSync(configPath)) {
|
|
721
|
+
try {
|
|
722
|
+
JSON.parse(readFileSync(configPath, "utf-8")) as SelftuneConfig;
|
|
723
|
+
existingConfigDetected = true;
|
|
724
|
+
} catch {
|
|
725
|
+
existingConfigDetected = false;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
711
728
|
|
|
712
729
|
const config = await runInit({
|
|
713
730
|
configDir,
|
|
@@ -727,6 +744,9 @@ export async function cliMain(): Promise<void> {
|
|
|
727
744
|
safeConfig.alpha.api_key = "<redacted>";
|
|
728
745
|
}
|
|
729
746
|
console.log(JSON.stringify(safeConfig, null, 2));
|
|
747
|
+
if (existingConfigDetected) {
|
|
748
|
+
console.error("Already initialized. Use --force to reinitialize.");
|
|
749
|
+
}
|
|
730
750
|
|
|
731
751
|
// Alpha enrollment output
|
|
732
752
|
if (values.alpha) {
|
|
@@ -790,6 +810,78 @@ export async function cliMain(): Promise<void> {
|
|
|
790
810
|
}),
|
|
791
811
|
);
|
|
792
812
|
|
|
813
|
+
// Backfill historical transcripts into SQLite
|
|
814
|
+
if (enableSync) {
|
|
815
|
+
try {
|
|
816
|
+
const { syncSources } = await import("./sync.js");
|
|
817
|
+
const syncResult = syncSources({
|
|
818
|
+
syncClaude: true,
|
|
819
|
+
syncCodex: true,
|
|
820
|
+
syncOpenCode: true,
|
|
821
|
+
syncOpenClaw: true,
|
|
822
|
+
rebuildSkillUsage: true,
|
|
823
|
+
dryRun: false,
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
const totalSynced =
|
|
827
|
+
(syncResult.sources.claude?.synced ?? 0) +
|
|
828
|
+
(syncResult.sources.codex?.synced ?? 0) +
|
|
829
|
+
(syncResult.sources.opencode?.synced ?? 0) +
|
|
830
|
+
(syncResult.sources.openclaw?.synced ?? 0);
|
|
831
|
+
|
|
832
|
+
console.log(
|
|
833
|
+
JSON.stringify({
|
|
834
|
+
level: "info",
|
|
835
|
+
code: "sync_complete",
|
|
836
|
+
sessions_synced: totalSynced,
|
|
837
|
+
repaired_records: syncResult.repair.repaired_records,
|
|
838
|
+
elapsed_ms: syncResult.total_elapsed_ms,
|
|
839
|
+
}),
|
|
840
|
+
);
|
|
841
|
+
} catch (err) {
|
|
842
|
+
// Fail-open: sync failure should not block init completion
|
|
843
|
+
console.log(
|
|
844
|
+
JSON.stringify({
|
|
845
|
+
level: "warn",
|
|
846
|
+
code: "sync_failed",
|
|
847
|
+
error: err instanceof Error ? err.message : String(err),
|
|
848
|
+
}),
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Trigger initial alpha upload if enrolled — push synced data immediately
|
|
854
|
+
if (config.alpha?.enrolled && config.alpha?.api_key) {
|
|
855
|
+
try {
|
|
856
|
+
const { runUploadCycle } = await import("./alpha-upload/index.js");
|
|
857
|
+
const { getDb } = await import("./localdb/db.js");
|
|
858
|
+
const db = getDb();
|
|
859
|
+
const uploadSummary = await runUploadCycle(db, {
|
|
860
|
+
enrolled: true,
|
|
861
|
+
userId: config.alpha.user_id,
|
|
862
|
+
apiKey: config.alpha.api_key,
|
|
863
|
+
});
|
|
864
|
+
console.log(
|
|
865
|
+
JSON.stringify({
|
|
866
|
+
level: "info",
|
|
867
|
+
code: "init_upload_complete",
|
|
868
|
+
prepared: uploadSummary.prepared,
|
|
869
|
+
sent: uploadSummary.sent,
|
|
870
|
+
failed: uploadSummary.failed,
|
|
871
|
+
}),
|
|
872
|
+
);
|
|
873
|
+
} catch (err) {
|
|
874
|
+
// Fail-open: upload failure should not block init
|
|
875
|
+
console.log(
|
|
876
|
+
JSON.stringify({
|
|
877
|
+
level: "warn",
|
|
878
|
+
code: "init_upload_failed",
|
|
879
|
+
error: err instanceof Error ? err.message : String(err),
|
|
880
|
+
}),
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
793
885
|
if (enableAutonomy) {
|
|
794
886
|
try {
|
|
795
887
|
const { installSchedule } = await import("./schedule.js");
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { Database } from "bun:sqlite";
|
|
12
12
|
import { existsSync, mkdirSync } from "node:fs";
|
|
13
13
|
import { dirname, join } from "node:path";
|
|
14
|
+
|
|
14
15
|
import { SELFTUNE_CONFIG_DIR } from "../constants.js";
|
|
15
16
|
import { ALL_DDL, MIGRATIONS, POST_MIGRATION_INDEXES } from "./schema.js";
|
|
16
17
|
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { Database } from "bun:sqlite";
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
|
|
13
15
|
import type {
|
|
14
16
|
CanonicalExecutionFactRecord,
|
|
15
17
|
CanonicalPromptRecord,
|
|
@@ -17,10 +19,12 @@ import type {
|
|
|
17
19
|
CanonicalSessionRecord,
|
|
18
20
|
CanonicalSkillInvocationRecord,
|
|
19
21
|
} from "@selftune/telemetry-contract";
|
|
22
|
+
|
|
20
23
|
import type { OrchestrateRunReport } from "../dashboard-contract.js";
|
|
21
24
|
import type {
|
|
22
25
|
EvolutionAuditEntry,
|
|
23
26
|
EvolutionEvidenceEntry,
|
|
27
|
+
GradingResult,
|
|
24
28
|
SessionTelemetryRecord,
|
|
25
29
|
SkillUsageRecord,
|
|
26
30
|
} from "../types.js";
|
|
@@ -353,6 +357,41 @@ export function writeQueryToDb(record: {
|
|
|
353
357
|
});
|
|
354
358
|
}
|
|
355
359
|
|
|
360
|
+
export function writeGradingResultToDb(result: GradingResult): boolean {
|
|
361
|
+
const gradingId = `gr_${createHash("sha256").update(`${result.session_id}:${result.skill_name}:${result.graded_at}`).digest("hex").slice(0, 16)}`;
|
|
362
|
+
return safeWrite("grading-result", (db) => {
|
|
363
|
+
getStmt(
|
|
364
|
+
db,
|
|
365
|
+
"grading-result",
|
|
366
|
+
`
|
|
367
|
+
INSERT OR IGNORE INTO grading_results
|
|
368
|
+
(grading_id, session_id, skill_name, transcript_path, graded_at,
|
|
369
|
+
pass_rate, mean_score, score_std_dev, passed_count, failed_count, total_count,
|
|
370
|
+
expectations_json, claims_json, eval_feedback_json, failure_feedback_json,
|
|
371
|
+
execution_metrics_json)
|
|
372
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
373
|
+
`,
|
|
374
|
+
).run(
|
|
375
|
+
gradingId,
|
|
376
|
+
result.session_id,
|
|
377
|
+
result.skill_name,
|
|
378
|
+
result.transcript_path,
|
|
379
|
+
result.graded_at,
|
|
380
|
+
result.summary.pass_rate,
|
|
381
|
+
result.summary.mean_score ?? null,
|
|
382
|
+
result.summary.score_std_dev ?? null,
|
|
383
|
+
result.summary.passed,
|
|
384
|
+
result.summary.failed,
|
|
385
|
+
result.summary.total,
|
|
386
|
+
JSON.stringify(result.expectations),
|
|
387
|
+
JSON.stringify(result.claims),
|
|
388
|
+
JSON.stringify(result.eval_feedback),
|
|
389
|
+
result.failure_feedback ? JSON.stringify(result.failure_feedback) : null,
|
|
390
|
+
JSON.stringify(result.execution_metrics),
|
|
391
|
+
);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
356
395
|
export function writeImprovementSignalToDb(record: {
|
|
357
396
|
timestamp: string;
|
|
358
397
|
session_id: string;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// 3. Backfill from batch ingestors that don't yet dual-write
|
|
15
15
|
|
|
16
16
|
import type { Database } from "bun:sqlite";
|
|
17
|
+
|
|
17
18
|
import {
|
|
18
19
|
type CanonicalExecutionFactRecord,
|
|
19
20
|
type CanonicalPromptRecord,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
type CanonicalSkillInvocationRecord,
|
|
23
24
|
isCanonicalRecord,
|
|
24
25
|
} from "@selftune/telemetry-contract";
|
|
26
|
+
|
|
25
27
|
import {
|
|
26
28
|
CANONICAL_LOG,
|
|
27
29
|
EVOLUTION_AUDIT_LOG,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Database } from "bun:sqlite";
|
|
9
|
+
|
|
9
10
|
import type {
|
|
10
11
|
OrchestrateRunReport,
|
|
11
12
|
OverviewPayload,
|
|
@@ -578,6 +579,58 @@ export function queryImprovementSignals(
|
|
|
578
579
|
}));
|
|
579
580
|
}
|
|
580
581
|
|
|
582
|
+
// -- Grading results query ----------------------------------------------------
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Read grading results from SQLite for upload staging.
|
|
586
|
+
*/
|
|
587
|
+
export function queryGradingResults(db: Database): Array<{
|
|
588
|
+
grading_id: string;
|
|
589
|
+
session_id: string;
|
|
590
|
+
skill_name: string;
|
|
591
|
+
transcript_path: string | null;
|
|
592
|
+
graded_at: string;
|
|
593
|
+
pass_rate: number | null;
|
|
594
|
+
mean_score: number | null;
|
|
595
|
+
score_std_dev: number | null;
|
|
596
|
+
passed_count: number | null;
|
|
597
|
+
failed_count: number | null;
|
|
598
|
+
total_count: number | null;
|
|
599
|
+
expectations_json: string | null;
|
|
600
|
+
claims_json: string | null;
|
|
601
|
+
eval_feedback_json: string | null;
|
|
602
|
+
failure_feedback_json: string | null;
|
|
603
|
+
execution_metrics_json: string | null;
|
|
604
|
+
}> {
|
|
605
|
+
return db
|
|
606
|
+
.query(
|
|
607
|
+
`SELECT grading_id, session_id, skill_name, transcript_path, graded_at,
|
|
608
|
+
pass_rate, mean_score, score_std_dev, passed_count, failed_count, total_count,
|
|
609
|
+
expectations_json, claims_json, eval_feedback_json, failure_feedback_json,
|
|
610
|
+
execution_metrics_json
|
|
611
|
+
FROM grading_results
|
|
612
|
+
ORDER BY graded_at DESC`,
|
|
613
|
+
)
|
|
614
|
+
.all() as Array<{
|
|
615
|
+
grading_id: string;
|
|
616
|
+
session_id: string;
|
|
617
|
+
skill_name: string;
|
|
618
|
+
transcript_path: string | null;
|
|
619
|
+
graded_at: string;
|
|
620
|
+
pass_rate: number | null;
|
|
621
|
+
mean_score: number | null;
|
|
622
|
+
score_std_dev: number | null;
|
|
623
|
+
passed_count: number | null;
|
|
624
|
+
failed_count: number | null;
|
|
625
|
+
total_count: number | null;
|
|
626
|
+
expectations_json: string | null;
|
|
627
|
+
claims_json: string | null;
|
|
628
|
+
eval_feedback_json: string | null;
|
|
629
|
+
failure_feedback_json: string | null;
|
|
630
|
+
execution_metrics_json: string | null;
|
|
631
|
+
}>;
|
|
632
|
+
}
|
|
633
|
+
|
|
581
634
|
// -- Canonical record staging query -------------------------------------------
|
|
582
635
|
|
|
583
636
|
/**
|
|
@@ -188,6 +188,28 @@ CREATE TABLE IF NOT EXISTS queries (
|
|
|
188
188
|
source TEXT
|
|
189
189
|
)`;
|
|
190
190
|
|
|
191
|
+
// -- Grading results table (from grade-session output) -----------------------
|
|
192
|
+
|
|
193
|
+
export const CREATE_GRADING_RESULTS = `
|
|
194
|
+
CREATE TABLE IF NOT EXISTS grading_results (
|
|
195
|
+
grading_id TEXT PRIMARY KEY,
|
|
196
|
+
session_id TEXT NOT NULL,
|
|
197
|
+
skill_name TEXT NOT NULL,
|
|
198
|
+
transcript_path TEXT,
|
|
199
|
+
graded_at TEXT NOT NULL,
|
|
200
|
+
pass_rate REAL,
|
|
201
|
+
mean_score REAL,
|
|
202
|
+
score_std_dev REAL,
|
|
203
|
+
passed_count INTEGER,
|
|
204
|
+
failed_count INTEGER,
|
|
205
|
+
total_count INTEGER,
|
|
206
|
+
expectations_json TEXT,
|
|
207
|
+
claims_json TEXT,
|
|
208
|
+
eval_feedback_json TEXT,
|
|
209
|
+
failure_feedback_json TEXT,
|
|
210
|
+
execution_metrics_json TEXT
|
|
211
|
+
)`;
|
|
212
|
+
|
|
191
213
|
// -- Improvement signal table (from signal_log.jsonl) ------------------------
|
|
192
214
|
|
|
193
215
|
export const CREATE_IMPROVEMENT_SIGNALS = `
|
|
@@ -278,6 +300,11 @@ export const CREATE_INDEXES = [
|
|
|
278
300
|
`CREATE INDEX IF NOT EXISTS idx_queries_session ON queries(session_id)`,
|
|
279
301
|
`CREATE INDEX IF NOT EXISTS idx_queries_ts ON queries(timestamp)`,
|
|
280
302
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_queries_dedup ON queries(session_id, query, timestamp)`,
|
|
303
|
+
// -- Grading results indexes -------------------------------------------------
|
|
304
|
+
`CREATE INDEX IF NOT EXISTS idx_grading_session ON grading_results(session_id)`,
|
|
305
|
+
`CREATE INDEX IF NOT EXISTS idx_grading_skill ON grading_results(skill_name)`,
|
|
306
|
+
`CREATE INDEX IF NOT EXISTS idx_grading_ts ON grading_results(graded_at)`,
|
|
307
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_grading_dedup ON grading_results(session_id, skill_name, graded_at)`,
|
|
281
308
|
// -- Improvement signal indexes ---------------------------------------------
|
|
282
309
|
`CREATE INDEX IF NOT EXISTS idx_signals_session ON improvement_signals(session_id)`,
|
|
283
310
|
`CREATE INDEX IF NOT EXISTS idx_signals_consumed ON improvement_signals(consumed)`,
|
|
@@ -347,6 +374,7 @@ export const ALL_DDL = [
|
|
|
347
374
|
CREATE_SKILL_USAGE,
|
|
348
375
|
CREATE_ORCHESTRATE_RUNS,
|
|
349
376
|
CREATE_QUERIES,
|
|
377
|
+
CREATE_GRADING_RESULTS,
|
|
350
378
|
CREATE_IMPROVEMENT_SIGNALS,
|
|
351
379
|
CREATE_UPLOAD_QUEUE,
|
|
352
380
|
CREATE_UPLOAD_WATERMARKS,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
writeFileSync,
|
|
25
25
|
} from "node:fs";
|
|
26
26
|
import { basename, dirname } from "node:path";
|
|
27
|
+
|
|
27
28
|
import { CANONICAL_LOG, canonicalSessionStatePath } from "./constants.js";
|
|
28
29
|
import { writeCanonicalBatchToDb, writeCanonicalToDb } from "./localdb/direct-write.js";
|
|
29
30
|
import {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { existsSync, readFileSync } from "node:fs";
|
|
12
12
|
import { homedir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
+
|
|
14
15
|
import { getAlphaGuidance } from "./agent-guidance.js";
|
|
15
16
|
import { getAlphaLinkState, readAlphaIdentity } from "./alpha-identity.js";
|
|
16
17
|
import { LOG_DIR, REQUIRED_FIELDS, SELFTUNE_CONFIG_PATH } from "./constants.js";
|
package/cli/selftune/sync.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { existsSync } from "node:fs";
|
|
|
17
17
|
import { homedir } from "node:os";
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { parseArgs } from "node:util";
|
|
20
|
+
|
|
20
21
|
import {
|
|
21
22
|
CLAUDE_CODE_MARKER,
|
|
22
23
|
CLAUDE_CODE_PROJECTS_DIR,
|
|
@@ -504,7 +505,7 @@ function formatStepLine(label: string, step: SyncStepResult, timing?: SyncPhaseT
|
|
|
504
505
|
return ` ${label}: ${parts.join(", ")}${time}`;
|
|
505
506
|
}
|
|
506
507
|
|
|
507
|
-
export function cliMain(): void {
|
|
508
|
+
export async function cliMain(): Promise<void> {
|
|
508
509
|
const { values } = parseArgs({
|
|
509
510
|
options: {
|
|
510
511
|
"projects-dir": { type: "string", default: CLAUDE_CODE_PROJECTS_DIR },
|
|
@@ -633,6 +634,34 @@ Options:
|
|
|
633
634
|
|
|
634
635
|
process.stderr.write(`\nDone in ${formatMs(result.total_elapsed_ms)}\n`);
|
|
635
636
|
}
|
|
637
|
+
|
|
638
|
+
// Trigger alpha upload if enrolled — pushes freshly synced data to cloud
|
|
639
|
+
if (!result.dry_run) {
|
|
640
|
+
try {
|
|
641
|
+
const { readAlphaIdentity } = await import("./alpha-identity.js");
|
|
642
|
+
const { SELFTUNE_CONFIG_PATH } = await import("./constants.js");
|
|
643
|
+
const identity = readAlphaIdentity(SELFTUNE_CONFIG_PATH);
|
|
644
|
+
if (identity?.enrolled && identity.api_key) {
|
|
645
|
+
const { runUploadCycle } = await import("./alpha-upload/index.js");
|
|
646
|
+
const { getDb } = await import("./localdb/db.js");
|
|
647
|
+
const db = getDb();
|
|
648
|
+
const uploadSummary = await runUploadCycle(db, {
|
|
649
|
+
enrolled: true,
|
|
650
|
+
userId: identity.user_id,
|
|
651
|
+
apiKey: identity.api_key,
|
|
652
|
+
});
|
|
653
|
+
if (!jsonOutput) {
|
|
654
|
+
process.stderr.write(
|
|
655
|
+
`\nAlpha upload: prepared=${uploadSummary.prepared}, sent=${uploadSummary.sent}, failed=${uploadSummary.failed}\n`,
|
|
656
|
+
);
|
|
657
|
+
} else {
|
|
658
|
+
console.log(JSON.stringify({ code: "alpha_upload", ...uploadSummary }));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
} catch {
|
|
662
|
+
// fail-open: upload failure should not break sync
|
|
663
|
+
}
|
|
664
|
+
}
|
|
636
665
|
}
|
|
637
666
|
|
|
638
667
|
if (import.meta.main) {
|