selftune 0.2.0 → 0.2.2

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.
Files changed (122) hide show
  1. package/.claude/agents/diagnosis-analyst.md +20 -10
  2. package/.claude/agents/evolution-reviewer.md +14 -1
  3. package/.claude/agents/integration-guide.md +18 -6
  4. package/.claude/agents/pattern-analyst.md +18 -5
  5. package/CHANGELOG.md +12 -4
  6. package/README.md +43 -35
  7. package/apps/local-dashboard/dist/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
  8. package/apps/local-dashboard/dist/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
  9. package/apps/local-dashboard/dist/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
  10. package/apps/local-dashboard/dist/assets/index-C4EOTFZ2.js +15 -0
  11. package/apps/local-dashboard/dist/assets/index-bl-Webyd.css +1 -0
  12. package/apps/local-dashboard/dist/assets/vendor-react-U7zYD9Rg.js +60 -0
  13. package/apps/local-dashboard/dist/assets/vendor-table-B7VF2Ipl.js +26 -0
  14. package/apps/local-dashboard/dist/assets/vendor-ui-D7_zX_qy.js +346 -0
  15. package/apps/local-dashboard/dist/favicon.png +0 -0
  16. package/apps/local-dashboard/dist/index.html +17 -0
  17. package/apps/local-dashboard/dist/logo.png +0 -0
  18. package/apps/local-dashboard/dist/logo.svg +9 -0
  19. package/cli/selftune/badge/badge-data.ts +1 -1
  20. package/cli/selftune/badge/badge.ts +4 -8
  21. package/cli/selftune/canonical-export.ts +183 -0
  22. package/cli/selftune/constants.ts +28 -0
  23. package/cli/selftune/contribute/contribute.ts +1 -1
  24. package/cli/selftune/cron/setup.ts +17 -17
  25. package/cli/selftune/dashboard-contract.ts +202 -0
  26. package/cli/selftune/dashboard-server.ts +653 -186
  27. package/cli/selftune/dashboard.ts +41 -176
  28. package/cli/selftune/eval/baseline.ts +5 -4
  29. package/cli/selftune/eval/composability-v2.ts +273 -0
  30. package/cli/selftune/eval/hooks-to-evals.ts +34 -15
  31. package/cli/selftune/eval/unit-test-cli.ts +1 -1
  32. package/cli/selftune/evolution/evidence.ts +26 -0
  33. package/cli/selftune/evolution/evolve-body.ts +105 -11
  34. package/cli/selftune/evolution/evolve.ts +371 -25
  35. package/cli/selftune/evolution/extract-patterns.ts +87 -29
  36. package/cli/selftune/evolution/rollback.ts +2 -2
  37. package/cli/selftune/grading/auto-grade.ts +200 -0
  38. package/cli/selftune/grading/grade-session.ts +448 -97
  39. package/cli/selftune/grading/results.ts +42 -0
  40. package/cli/selftune/hooks/prompt-log.ts +172 -2
  41. package/cli/selftune/hooks/session-stop.ts +123 -3
  42. package/cli/selftune/hooks/skill-eval.ts +119 -3
  43. package/cli/selftune/index.ts +395 -116
  44. package/cli/selftune/ingestors/claude-replay.ts +140 -114
  45. package/cli/selftune/ingestors/codex-rollout.ts +345 -46
  46. package/cli/selftune/ingestors/codex-wrapper.ts +207 -39
  47. package/cli/selftune/ingestors/openclaw-ingest.ts +141 -8
  48. package/cli/selftune/ingestors/opencode-ingest.ts +193 -17
  49. package/cli/selftune/init.ts +227 -14
  50. package/cli/selftune/last.ts +14 -5
  51. package/cli/selftune/localdb/db.ts +63 -0
  52. package/cli/selftune/localdb/materialize.ts +428 -0
  53. package/cli/selftune/localdb/queries.ts +376 -0
  54. package/cli/selftune/localdb/schema.ts +204 -0
  55. package/cli/selftune/monitoring/watch.ts +66 -15
  56. package/cli/selftune/normalization.ts +682 -0
  57. package/cli/selftune/observability.ts +19 -44
  58. package/cli/selftune/orchestrate.ts +1073 -0
  59. package/cli/selftune/quickstart.ts +203 -0
  60. package/cli/selftune/repair/skill-usage.ts +576 -0
  61. package/cli/selftune/schedule.ts +561 -0
  62. package/cli/selftune/status.ts +48 -26
  63. package/cli/selftune/sync.ts +627 -0
  64. package/cli/selftune/types.ts +148 -0
  65. package/cli/selftune/utils/canonical-log.ts +45 -0
  66. package/cli/selftune/utils/hooks.ts +41 -0
  67. package/cli/selftune/utils/html.ts +27 -0
  68. package/cli/selftune/utils/llm-call.ts +78 -20
  69. package/cli/selftune/utils/math.ts +10 -0
  70. package/cli/selftune/utils/query-filter.ts +139 -0
  71. package/cli/selftune/utils/skill-discovery.ts +340 -0
  72. package/cli/selftune/utils/skill-log.ts +68 -0
  73. package/cli/selftune/utils/skill-usage-confidence.ts +18 -0
  74. package/cli/selftune/utils/transcript.ts +272 -26
  75. package/cli/selftune/workflows/discover.ts +254 -0
  76. package/cli/selftune/workflows/skill-md-writer.ts +288 -0
  77. package/cli/selftune/workflows/workflows.ts +188 -0
  78. package/package.json +21 -8
  79. package/packages/telemetry-contract/README.md +11 -0
  80. package/packages/telemetry-contract/fixtures/golden.json +87 -0
  81. package/packages/telemetry-contract/fixtures/golden.test.ts +42 -0
  82. package/packages/telemetry-contract/index.ts +1 -0
  83. package/packages/telemetry-contract/package.json +19 -0
  84. package/packages/telemetry-contract/src/index.ts +2 -0
  85. package/packages/telemetry-contract/src/types.ts +163 -0
  86. package/packages/telemetry-contract/src/validators.ts +109 -0
  87. package/skill/SKILL.md +84 -53
  88. package/skill/Workflows/AutoActivation.md +17 -16
  89. package/skill/Workflows/Badge.md +6 -0
  90. package/skill/Workflows/Baseline.md +46 -23
  91. package/skill/Workflows/Composability.md +12 -5
  92. package/skill/Workflows/Contribute.md +17 -14
  93. package/skill/Workflows/Cron.md +56 -79
  94. package/skill/Workflows/Dashboard.md +45 -34
  95. package/skill/Workflows/Doctor.md +30 -17
  96. package/skill/Workflows/Evals.md +64 -40
  97. package/skill/Workflows/EvolutionMemory.md +2 -0
  98. package/skill/Workflows/Evolve.md +102 -47
  99. package/skill/Workflows/EvolveBody.md +6 -6
  100. package/skill/Workflows/Grade.md +36 -31
  101. package/skill/Workflows/ImportSkillsBench.md +11 -5
  102. package/skill/Workflows/Ingest.md +43 -36
  103. package/skill/Workflows/Initialize.md +44 -30
  104. package/skill/Workflows/Orchestrate.md +139 -0
  105. package/skill/Workflows/Replay.md +39 -18
  106. package/skill/Workflows/Rollback.md +3 -3
  107. package/skill/Workflows/Schedule.md +61 -0
  108. package/skill/Workflows/Sync.md +88 -0
  109. package/skill/Workflows/UnitTest.md +34 -22
  110. package/skill/Workflows/Watch.md +14 -4
  111. package/skill/Workflows/Workflows.md +129 -0
  112. package/skill/assets/activation-rules-default.json +26 -0
  113. package/skill/assets/multi-skill-settings.json +63 -0
  114. package/skill/assets/single-skill-settings.json +57 -0
  115. package/skill/references/invocation-taxonomy.md +2 -2
  116. package/skill/references/logs.md +164 -2
  117. package/skill/references/setup-patterns.md +65 -0
  118. package/skill/references/version-history.md +40 -0
  119. package/skill/settings_snippet.json +1 -1
  120. package/templates/multi-skill-settings.json +7 -7
  121. package/templates/single-skill-settings.json +6 -6
  122. package/dashboard/index.html +0 -1680
@@ -0,0 +1,203 @@
1
+ /**
2
+ * selftune quickstart — Guided onboarding that runs init, ingest, and status.
3
+ *
4
+ * Steps:
5
+ * 1. Run `init` if config doesn't exist
6
+ * 2. Run `ingest claude` if marker file doesn't exist
7
+ * 3. Run `status` to display current state
8
+ * 4. Suggest top 3 skills to evolve
9
+ */
10
+
11
+ import { existsSync } from "node:fs";
12
+
13
+ import {
14
+ CLAUDE_CODE_MARKER,
15
+ CLAUDE_CODE_PROJECTS_DIR,
16
+ EVOLUTION_AUDIT_LOG,
17
+ QUERY_LOG,
18
+ SELFTUNE_CONFIG_DIR,
19
+ SELFTUNE_CONFIG_PATH,
20
+ TELEMETRY_LOG,
21
+ } from "./constants.js";
22
+ import { findTranscriptFiles, parseSession, writeSession } from "./ingestors/claude-replay.js";
23
+ import { runInit } from "./init.js";
24
+ import { doctor } from "./observability.js";
25
+ import type { SkillStatus } from "./status.js";
26
+ import { computeStatus, formatStatus } from "./status.js";
27
+ import type { EvolutionAuditEntry, QueryLogRecord, SessionTelemetryRecord } from "./types.js";
28
+ import { loadMarker, readJsonl, saveMarker } from "./utils/jsonl.js";
29
+ import { readEffectiveSkillUsageRecords } from "./utils/skill-log.js";
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // quickstart logic
33
+ // ---------------------------------------------------------------------------
34
+
35
+ export async function quickstart(): Promise<void> {
36
+ console.log("selftune quickstart");
37
+ console.log("=".repeat(20));
38
+ console.log("");
39
+
40
+ // Step 1: Init if needed
41
+ if (existsSync(SELFTUNE_CONFIG_PATH)) {
42
+ console.log("[1/3] Config exists, skipping init.");
43
+ } else {
44
+ console.log("[1/3] Running init...");
45
+ try {
46
+ await runInit({
47
+ configDir: SELFTUNE_CONFIG_DIR,
48
+ configPath: SELFTUNE_CONFIG_PATH,
49
+ force: false,
50
+ });
51
+ console.log(" Config created.");
52
+ } catch (err) {
53
+ const msg = err instanceof Error ? err.message : String(err);
54
+ console.error(` Init failed: ${msg}`);
55
+ console.log(" You can run `selftune init` manually to troubleshoot.");
56
+ }
57
+ }
58
+
59
+ // Step 2: Ingest if marker doesn't exist
60
+ if (existsSync(CLAUDE_CODE_MARKER)) {
61
+ console.log("[2/3] Ingest marker exists, skipping ingestion.");
62
+ } else {
63
+ console.log("[2/3] Running ingest claude...");
64
+ try {
65
+ const transcriptFiles = findTranscriptFiles(CLAUDE_CODE_PROJECTS_DIR);
66
+ if (transcriptFiles.length === 0) {
67
+ console.log(" No Claude Code transcripts found. Skipping.");
68
+ } else {
69
+ const alreadyIngested = loadMarker(CLAUDE_CODE_MARKER);
70
+ const newIngested = new Set<string>();
71
+ let ingestedCount = 0;
72
+
73
+ for (const transcriptFile of transcriptFiles) {
74
+ const session = parseSession(transcriptFile);
75
+ if (session === null) continue;
76
+ writeSession(session, false);
77
+ newIngested.add(transcriptFile);
78
+ ingestedCount++;
79
+ }
80
+
81
+ if (newIngested.size > 0) {
82
+ saveMarker(CLAUDE_CODE_MARKER, new Set([...alreadyIngested, ...newIngested]));
83
+ }
84
+ console.log(` Ingested ${ingestedCount} sessions.`);
85
+ }
86
+ } catch (err) {
87
+ const msg = err instanceof Error ? err.message : String(err);
88
+ console.error(` Ingest failed: ${msg}`);
89
+ console.log(" You can run `selftune ingest claude` manually to troubleshoot.");
90
+ }
91
+ }
92
+
93
+ // Check if any telemetry was produced after ingest
94
+ const telemetry = readJsonl<SessionTelemetryRecord>(TELEMETRY_LOG);
95
+ const skillRecords = readEffectiveSkillUsageRecords();
96
+ const queryRecords = readJsonl<QueryLogRecord>(QUERY_LOG);
97
+ const hasSessions = telemetry.length > 0 || queryRecords.length > 0;
98
+ const hasSkills = skillRecords.length > 0;
99
+
100
+ if (!hasSessions) {
101
+ console.log(" No sessions found. Checking for skills from hooks...");
102
+ if (hasSkills) {
103
+ const skillNames = [...new Set(skillRecords.map((r) => r.skill_name))].sort();
104
+ console.log(` Found ${skillNames.length} skill(s) from hooks: ${skillNames.join(", ")}`);
105
+ } else {
106
+ console.log(" No skills detected yet. Use your agent normally, then run");
107
+ console.log(" `selftune status` to see health scores.");
108
+ }
109
+ console.log("");
110
+ }
111
+
112
+ // Step 3: Status
113
+ console.log("[3/3] Current status:");
114
+ console.log("");
115
+
116
+ try {
117
+ const auditEntries = readJsonl<EvolutionAuditEntry>(EVOLUTION_AUDIT_LOG);
118
+ const doctorResult = doctor();
119
+
120
+ const result = computeStatus(telemetry, skillRecords, queryRecords, auditEntries, doctorResult);
121
+ const output = formatStatus(result);
122
+ console.log(output);
123
+
124
+ // Step 4: Suggest top 3 skills to evolve
125
+ console.log("");
126
+ suggestSkillsToEvolve(result.skills);
127
+ } catch (err) {
128
+ const msg = err instanceof Error ? err.message : String(err);
129
+ console.error(`Status failed: ${msg}`);
130
+ console.log("Run `selftune status` manually to troubleshoot.");
131
+ }
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Suggest skills to evolve
136
+ // ---------------------------------------------------------------------------
137
+
138
+ function suggestSkillsToEvolve(skills: SkillStatus[]): void {
139
+ if (skills.length === 0) {
140
+ console.log("No skills found. Create skills and run sessions to get started.");
141
+ return;
142
+ }
143
+
144
+ // Score each skill: prioritize highest trigger count with lowest pass rate or no data
145
+ const scored: Array<{ name: string; score: number; reason: string }> = skills.map((s) => {
146
+ let score = 0;
147
+ let reason: string;
148
+ const passRateLabel = s.passRate !== null ? `${Math.round(s.passRate * 100)}%` : "unknown";
149
+
150
+ if (s.status === "UNGRADED" || s.status === "UNKNOWN") {
151
+ score = 100; // Highest priority: needs grading
152
+ reason = `needs grading — run \`selftune grade --skill ${s.name}\``;
153
+ } else if (s.status === "CRITICAL") {
154
+ score = 90;
155
+ reason = `pass rate ${passRateLabel} — needs evolution`;
156
+ } else if (s.status === "WARNING") {
157
+ score = 70;
158
+ reason = `pass rate ${passRateLabel} — could improve`;
159
+ } else {
160
+ score = 10;
161
+ reason = "healthy";
162
+ }
163
+
164
+ return { name: s.name, score, reason };
165
+ });
166
+
167
+ // Sort by score descending, take top 3
168
+ scored.sort((a, b) => b.score - a.score);
169
+ const top = scored.slice(0, 3).filter((s) => s.score > 10);
170
+
171
+ if (top.length === 0) {
172
+ console.log("All skills are healthy. No immediate actions needed.");
173
+ return;
174
+ }
175
+
176
+ console.log("Suggested next steps:");
177
+ for (const suggestion of top) {
178
+ console.log(` - ${suggestion.name}: ${suggestion.reason}`);
179
+ }
180
+ }
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // CLI entry point
184
+ // ---------------------------------------------------------------------------
185
+
186
+ export async function cliMain(): Promise<void> {
187
+ // Check for --help
188
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
189
+ console.log(`selftune quickstart — Guided onboarding
190
+
191
+ Usage:
192
+ selftune quickstart
193
+
194
+ Steps:
195
+ 1. Runs init if ~/.selftune/config.json doesn't exist
196
+ 2. Runs ingest claude if session marker doesn't exist
197
+ 3. Shows current status
198
+ 4. Suggests top skills to evolve`);
199
+ process.exit(0);
200
+ }
201
+
202
+ await quickstart();
203
+ }