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
|
@@ -2,19 +2,25 @@
|
|
|
2
2
|
* Auto-update check for selftune CLI.
|
|
3
3
|
*
|
|
4
4
|
* Runs before command dispatch (skipped for hooks and --help).
|
|
5
|
+
* Set SELFTUNE_SKIP_AUTO_UPDATE=1 or SELFTUNE_SKIP_UPDATE_CHECK=1 to disable
|
|
6
|
+
* it for source-tree smoke tests and hermetic automation.
|
|
5
7
|
* Checks npm registry at most once per hour (cached in ~/.selftune/update-check.json).
|
|
6
|
-
* If outdated, auto-updates
|
|
8
|
+
* If outdated, auto-updates the active global install (npm or Bun) and syncs
|
|
9
|
+
* bundled skill files into common global skill registries.
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import { spawnSync } from "node:child_process";
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
11
14
|
import { homedir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
13
16
|
|
|
14
17
|
import { SELFTUNE_CONFIG_DIR } from "./constants.js";
|
|
15
18
|
|
|
16
19
|
const UPDATE_CHECK_PATH = join(SELFTUNE_CONFIG_DIR, "update-check.json");
|
|
17
20
|
const CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
|
21
|
+
const PACKAGE_NAME = "selftune";
|
|
22
|
+
const PACKAGE_ROOT = resolve(import.meta.dir, "..", "..");
|
|
23
|
+
const BUNDLED_SKILL_DIR = join(PACKAGE_ROOT, "skill");
|
|
18
24
|
|
|
19
25
|
interface UpdateCheckCache {
|
|
20
26
|
lastCheck: number;
|
|
@@ -22,6 +28,33 @@ interface UpdateCheckCache {
|
|
|
22
28
|
latestVersion: string;
|
|
23
29
|
}
|
|
24
30
|
|
|
31
|
+
type InstallSource = "bun-global" | "npm-global";
|
|
32
|
+
|
|
33
|
+
interface UpdateCommand {
|
|
34
|
+
source: InstallSource;
|
|
35
|
+
command: string;
|
|
36
|
+
args: string[];
|
|
37
|
+
manualCommand: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface UpdateCommandOptions {
|
|
41
|
+
homeDir?: string;
|
|
42
|
+
moduleDir?: string;
|
|
43
|
+
npmGlobalRoot?: string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isTruthyEnv(value: string | undefined): boolean {
|
|
47
|
+
if (!value) return false;
|
|
48
|
+
return !["0", "false", "no", "off"].includes(value.trim().toLowerCase());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isAutoUpdateSkipped(): boolean {
|
|
52
|
+
return (
|
|
53
|
+
isTruthyEnv(process.env.SELFTUNE_SKIP_AUTO_UPDATE) ||
|
|
54
|
+
isTruthyEnv(process.env.SELFTUNE_SKIP_UPDATE_CHECK)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
25
58
|
function readCache(): UpdateCheckCache | null {
|
|
26
59
|
try {
|
|
27
60
|
if (!existsSync(UPDATE_CHECK_PATH)) return null;
|
|
@@ -47,6 +80,139 @@ function getCurrentVersion(): string {
|
|
|
47
80
|
return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
|
|
48
81
|
}
|
|
49
82
|
|
|
83
|
+
function normalizePath(path: string): string {
|
|
84
|
+
return resolve(path).replaceAll("\\", "/");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getActivePackageRoot(moduleDir = import.meta.dir): string {
|
|
88
|
+
return resolve(moduleDir, "..", "..");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getNpmGlobalRoot(): string | null {
|
|
92
|
+
const result = spawnSync("npm", ["root", "-g"], {
|
|
93
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
94
|
+
timeout: 5000,
|
|
95
|
+
});
|
|
96
|
+
if (result.status !== 0) return null;
|
|
97
|
+
const root = result.stdout?.toString().trim();
|
|
98
|
+
return root ? root : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildManualUpdateCommand(source: InstallSource, version: string): string {
|
|
102
|
+
const packageSpec = `${PACKAGE_NAME}@${version}`;
|
|
103
|
+
if (source === "bun-global") {
|
|
104
|
+
return `bun add -g ${packageSpec}`;
|
|
105
|
+
}
|
|
106
|
+
return `npm install -g ${packageSpec}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function resolveSelftuneUpdateCommand(
|
|
110
|
+
version: string,
|
|
111
|
+
options?: UpdateCommandOptions,
|
|
112
|
+
): UpdateCommand | null {
|
|
113
|
+
const homeDir = options?.homeDir ?? homedir();
|
|
114
|
+
const activePackageRoot = normalizePath(getActivePackageRoot(options?.moduleDir));
|
|
115
|
+
|
|
116
|
+
const bunPackageRoot = normalizePath(
|
|
117
|
+
join(homeDir, ".bun", "install", "global", "node_modules", PACKAGE_NAME),
|
|
118
|
+
);
|
|
119
|
+
if (
|
|
120
|
+
activePackageRoot === bunPackageRoot ||
|
|
121
|
+
activePackageRoot.includes("/.bun/install/global/node_modules/selftune")
|
|
122
|
+
) {
|
|
123
|
+
return {
|
|
124
|
+
source: "bun-global",
|
|
125
|
+
command: "bun",
|
|
126
|
+
args: ["add", "-g", `${PACKAGE_NAME}@${version}`],
|
|
127
|
+
manualCommand: buildManualUpdateCommand("bun-global", version),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const npmGlobalRoot = options?.npmGlobalRoot ?? getNpmGlobalRoot();
|
|
132
|
+
if (npmGlobalRoot) {
|
|
133
|
+
const npmPackageRoot = normalizePath(join(npmGlobalRoot, PACKAGE_NAME));
|
|
134
|
+
if (activePackageRoot === npmPackageRoot) {
|
|
135
|
+
return {
|
|
136
|
+
source: "npm-global",
|
|
137
|
+
command: "npm",
|
|
138
|
+
args: ["install", "-g", `${PACKAGE_NAME}@${version}`],
|
|
139
|
+
manualCommand: buildManualUpdateCommand("npm-global", version),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (activePackageRoot.includes("/lib/node_modules/selftune")) {
|
|
145
|
+
return {
|
|
146
|
+
source: "npm-global",
|
|
147
|
+
command: "npm",
|
|
148
|
+
args: ["install", "-g", `${PACKAGE_NAME}@${version}`],
|
|
149
|
+
manualCommand: buildManualUpdateCommand("npm-global", version),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function getSelftuneUpdateHint(version = "latest", options?: UpdateCommandOptions): string {
|
|
157
|
+
return (
|
|
158
|
+
resolveSelftuneUpdateCommand(version, options)?.manualCommand ??
|
|
159
|
+
"npx skills add selftune-dev/selftune"
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function readSkillVersion(skillDir: string): string | null {
|
|
164
|
+
try {
|
|
165
|
+
const skillPath = join(skillDir, "SKILL.md");
|
|
166
|
+
if (!existsSync(skillPath)) return null;
|
|
167
|
+
const skillContent = readFileSync(skillPath, "utf-8");
|
|
168
|
+
const match = skillContent.match(/^\s*version:\s*(.+)$/m);
|
|
169
|
+
return match?.[1]?.trim() ?? null;
|
|
170
|
+
} catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function getInstalledSkillDirs(homeDir = homedir()): string[] {
|
|
176
|
+
return [
|
|
177
|
+
join(homeDir, ".claude", "skills", PACKAGE_NAME),
|
|
178
|
+
join(homeDir, ".agents", "skills", PACKAGE_NAME),
|
|
179
|
+
].filter((dir) => existsSync(dir));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function syncInstalledSkillFiles(options?: {
|
|
183
|
+
force?: boolean;
|
|
184
|
+
homeDir?: string;
|
|
185
|
+
packageSkillDir?: string;
|
|
186
|
+
}): string[] {
|
|
187
|
+
const homeDir = options?.homeDir ?? homedir();
|
|
188
|
+
const packageSkillDir = options?.packageSkillDir ?? BUNDLED_SKILL_DIR;
|
|
189
|
+
if (!existsSync(packageSkillDir)) return [];
|
|
190
|
+
|
|
191
|
+
const sourceVersion = readSkillVersion(packageSkillDir);
|
|
192
|
+
const syncedDirs: string[] = [];
|
|
193
|
+
|
|
194
|
+
for (const targetDir of getInstalledSkillDirs(homeDir)) {
|
|
195
|
+
const targetVersion = readSkillVersion(targetDir);
|
|
196
|
+
const shouldSync =
|
|
197
|
+
options?.force ||
|
|
198
|
+
sourceVersion === null ||
|
|
199
|
+
targetVersion === null ||
|
|
200
|
+
sourceVersion !== targetVersion;
|
|
201
|
+
if (!shouldSync) continue;
|
|
202
|
+
|
|
203
|
+
mkdirSync(targetDir, { recursive: true });
|
|
204
|
+
for (const entry of readdirSync(packageSkillDir)) {
|
|
205
|
+
cpSync(join(packageSkillDir, entry), join(targetDir, entry), {
|
|
206
|
+
recursive: true,
|
|
207
|
+
force: true,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
syncedDirs.push(targetDir);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return syncedDirs;
|
|
214
|
+
}
|
|
215
|
+
|
|
50
216
|
function compareSemver(a: string, b: string): -1 | 0 | 1 {
|
|
51
217
|
const pa = a.split(".").map(Number);
|
|
52
218
|
const pb = b.split(".").map(Number);
|
|
@@ -66,6 +232,8 @@ function compareSemver(a: string, b: string): -1 | 0 | 1 {
|
|
|
66
232
|
*/
|
|
67
233
|
export async function autoUpdate(): Promise<void> {
|
|
68
234
|
try {
|
|
235
|
+
if (isAutoUpdateSkipped()) return;
|
|
236
|
+
|
|
69
237
|
const currentVersion = getCurrentVersion();
|
|
70
238
|
const cache = readCache();
|
|
71
239
|
|
|
@@ -74,6 +242,8 @@ export async function autoUpdate(): Promise<void> {
|
|
|
74
242
|
// Even with a recent check, if we know we're outdated, try updating
|
|
75
243
|
if (cache.latestVersion && compareSemver(currentVersion, cache.latestVersion) < 0) {
|
|
76
244
|
await performUpdate(currentVersion, cache.latestVersion);
|
|
245
|
+
} else if (cache.latestVersion && compareSemver(currentVersion, cache.latestVersion) >= 0) {
|
|
246
|
+
syncInstalledSkillFiles();
|
|
77
247
|
}
|
|
78
248
|
return;
|
|
79
249
|
}
|
|
@@ -87,7 +257,7 @@ export async function autoUpdate(): Promise<void> {
|
|
|
87
257
|
signal: controller.signal,
|
|
88
258
|
});
|
|
89
259
|
if (!res.ok) {
|
|
90
|
-
writeCache({ lastCheck: Date.now(), currentVersion, latestVersion:
|
|
260
|
+
writeCache({ lastCheck: Date.now(), currentVersion, latestVersion: "" });
|
|
91
261
|
return;
|
|
92
262
|
}
|
|
93
263
|
const data = (await res.json()) as { version: string };
|
|
@@ -102,7 +272,10 @@ export async function autoUpdate(): Promise<void> {
|
|
|
102
272
|
// Auto-update if outdated
|
|
103
273
|
if (compareSemver(currentVersion, latestVersion) < 0) {
|
|
104
274
|
await performUpdate(currentVersion, latestVersion);
|
|
275
|
+
return;
|
|
105
276
|
}
|
|
277
|
+
|
|
278
|
+
syncInstalledSkillFiles();
|
|
106
279
|
} catch {
|
|
107
280
|
// Non-critical — silently skip
|
|
108
281
|
}
|
|
@@ -111,7 +284,16 @@ export async function autoUpdate(): Promise<void> {
|
|
|
111
284
|
async function performUpdate(currentVersion: string, latestVersion: string): Promise<void> {
|
|
112
285
|
console.error(`[selftune] Update available: v${currentVersion} → v${latestVersion}. Updating...`);
|
|
113
286
|
|
|
114
|
-
const
|
|
287
|
+
const updateCommand = resolveSelftuneUpdateCommand(latestVersion);
|
|
288
|
+
if (!updateCommand) {
|
|
289
|
+
console.error(
|
|
290
|
+
"[selftune] Auto-update skipped. Current install path is not a supported global package install.",
|
|
291
|
+
);
|
|
292
|
+
console.error(`[selftune] Refresh manually: ${getSelftuneUpdateHint(latestVersion)}`);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const result = spawnSync(updateCommand.command, updateCommand.args, {
|
|
115
297
|
stdio: ["ignore", "pipe", "pipe"],
|
|
116
298
|
timeout: 30000,
|
|
117
299
|
});
|
|
@@ -130,11 +312,21 @@ async function performUpdate(currentVersion: string, latestVersion: string): Pro
|
|
|
130
312
|
} catch {
|
|
131
313
|
// Non-critical — updated CLI is usable even if agent sync fails
|
|
132
314
|
}
|
|
315
|
+
|
|
316
|
+
// Refresh installed selftune skill registries after a successful package update.
|
|
317
|
+
try {
|
|
318
|
+
const syncedSkillDirs = syncInstalledSkillFiles({ force: true });
|
|
319
|
+
if (getInstalledSkillDirs().length > 0 && syncedSkillDirs.length === 0) {
|
|
320
|
+
console.error(
|
|
321
|
+
`[selftune] Skill file sync failed — run: ${getSelftuneUpdateHint(latestVersion)}`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
} catch {
|
|
325
|
+
// Non-critical — skill files can be updated manually
|
|
326
|
+
}
|
|
133
327
|
} else {
|
|
134
328
|
const stderr = result.stderr?.toString().trim();
|
|
135
|
-
console.error(
|
|
136
|
-
`[selftune] Auto-update failed. Run manually: npm install -g selftune@${latestVersion}`,
|
|
137
|
-
);
|
|
329
|
+
console.error(`[selftune] Auto-update failed. Run manually: ${updateCommand.manualCommand}`);
|
|
138
330
|
if (stderr) {
|
|
139
331
|
console.error(` ${stderr.split("\n")[0]}`);
|
|
140
332
|
}
|
|
@@ -5,6 +5,8 @@ import { readFileSync, writeFileSync } from "node:fs";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
7
7
|
|
|
8
|
+
import type { PushPayloadV2 } from "@selftune/telemetry-contract/types";
|
|
9
|
+
|
|
8
10
|
import { CANONICAL_LOG, CLAUDE_CODE_PROJECTS_DIR } from "./constants.js";
|
|
9
11
|
import {
|
|
10
12
|
buildCanonicalRecordsFromReplay,
|
|
@@ -61,6 +63,12 @@ function getClientVersion(): string {
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
function addOptional(record: Record<string, unknown>, key: string, value: unknown): void {
|
|
67
|
+
if (value !== undefined && value !== null) {
|
|
68
|
+
record[key] = value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
export function loadCanonicalRecordsForExport(
|
|
65
73
|
logPath: string = CANONICAL_LOG,
|
|
66
74
|
projectsDir: string = CLAUDE_CODE_PROJECTS_DIR,
|
|
@@ -88,13 +96,47 @@ export function buildPushPayloadV2(
|
|
|
88
96
|
orchestrateRuns: Record<string, unknown>[] = [],
|
|
89
97
|
gradingResults: Record<string, unknown>[] = [],
|
|
90
98
|
improvementSignals: Record<string, unknown>[] = [],
|
|
91
|
-
):
|
|
92
|
-
const sessions = records.filter(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
99
|
+
): PushPayloadV2 {
|
|
100
|
+
const sessions = records.filter(
|
|
101
|
+
(record): record is Extract<CanonicalRecord, { record_kind: "session" }> =>
|
|
102
|
+
record.record_kind === "session",
|
|
103
|
+
);
|
|
104
|
+
const prompts = records.filter(
|
|
105
|
+
(record): record is Extract<CanonicalRecord, { record_kind: "prompt" }> =>
|
|
106
|
+
record.record_kind === "prompt",
|
|
107
|
+
);
|
|
108
|
+
const skillInvocations = records.filter(
|
|
109
|
+
(record): record is Extract<CanonicalRecord, { record_kind: "skill_invocation" }> =>
|
|
110
|
+
record.record_kind === "skill_invocation",
|
|
111
|
+
);
|
|
112
|
+
const executionFacts = records.filter(
|
|
113
|
+
(record): record is Extract<CanonicalRecord, { record_kind: "execution_fact" }> =>
|
|
114
|
+
record.record_kind === "execution_fact",
|
|
115
|
+
);
|
|
116
|
+
const normalizationRuns = records.filter(
|
|
117
|
+
(record): record is Extract<CanonicalRecord, { record_kind: "normalization_run" }> =>
|
|
118
|
+
record.record_kind === "normalization_run",
|
|
119
|
+
);
|
|
97
120
|
const normalizerVersion = records[0]?.normalizer_version ?? "1.0.0";
|
|
121
|
+
const evolutionEvidence = evidenceEntries.map((entry) => {
|
|
122
|
+
const record: Record<string, unknown> = {
|
|
123
|
+
evidence_id: entry.evidence_id,
|
|
124
|
+
skill_name: entry.skill_name,
|
|
125
|
+
target: entry.target,
|
|
126
|
+
stage: entry.stage,
|
|
127
|
+
};
|
|
128
|
+
addOptional(record, "timestamp", entry.timestamp);
|
|
129
|
+
addOptional(record, "skill_path", entry.skill_path);
|
|
130
|
+
addOptional(record, "proposal_id", entry.proposal_id);
|
|
131
|
+
addOptional(record, "rationale", entry.rationale);
|
|
132
|
+
addOptional(record, "confidence", entry.confidence);
|
|
133
|
+
addOptional(record, "details", entry.details);
|
|
134
|
+
addOptional(record, "original_text", entry.original_text);
|
|
135
|
+
addOptional(record, "proposed_text", entry.proposed_text);
|
|
136
|
+
addOptional(record, "eval_set_json", entry.eval_set);
|
|
137
|
+
addOptional(record, "validation_json", entry.validation);
|
|
138
|
+
return record;
|
|
139
|
+
});
|
|
98
140
|
|
|
99
141
|
return {
|
|
100
142
|
schema_version: "2.0",
|
|
@@ -107,25 +149,13 @@ export function buildPushPayloadV2(
|
|
|
107
149
|
skill_invocations: skillInvocations,
|
|
108
150
|
execution_facts: executionFacts,
|
|
109
151
|
normalization_runs: normalizationRuns,
|
|
110
|
-
evolution_evidence:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
stage: entry.stage,
|
|
118
|
-
rationale: entry.rationale,
|
|
119
|
-
confidence: entry.confidence,
|
|
120
|
-
details: entry.details,
|
|
121
|
-
original_text: entry.original_text,
|
|
122
|
-
proposed_text: entry.proposed_text,
|
|
123
|
-
eval_set_json: entry.eval_set,
|
|
124
|
-
validation_json: entry.validation,
|
|
125
|
-
})),
|
|
126
|
-
orchestrate_runs: orchestrateRuns,
|
|
127
|
-
grading_results: gradingResults,
|
|
128
|
-
improvement_signals: improvementSignals,
|
|
152
|
+
evolution_evidence:
|
|
153
|
+
evolutionEvidence as unknown as PushPayloadV2["canonical"]["evolution_evidence"],
|
|
154
|
+
orchestrate_runs:
|
|
155
|
+
orchestrateRuns as unknown as PushPayloadV2["canonical"]["orchestrate_runs"],
|
|
156
|
+
grading_results: gradingResults as unknown as PushPayloadV2["canonical"]["grading_results"],
|
|
157
|
+
improvement_signals:
|
|
158
|
+
improvementSignals as unknown as PushPayloadV2["canonical"]["improvement_signals"],
|
|
129
159
|
},
|
|
130
160
|
};
|
|
131
161
|
}
|