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,397 @@
|
|
|
1
|
+
export interface PublicCommandFlag {
|
|
2
|
+
token: string;
|
|
3
|
+
helpLabel: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PublicCommandSurface {
|
|
8
|
+
command: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
usage: string;
|
|
11
|
+
flags: readonly PublicCommandFlag[];
|
|
12
|
+
quickReference: string;
|
|
13
|
+
extraHelpSections?: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function formatOptionLines(flags: readonly PublicCommandFlag[]): string[] {
|
|
17
|
+
const width = Math.max(...flags.map((flag) => flag.helpLabel.length), 0) + 2;
|
|
18
|
+
return flags.map((flag) => ` ${flag.helpLabel.padEnd(width)}${flag.description}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function renderCommandHelp(surface: PublicCommandSurface): string {
|
|
22
|
+
const lines = [
|
|
23
|
+
`${surface.command} — ${surface.summary}`,
|
|
24
|
+
"",
|
|
25
|
+
"Usage:",
|
|
26
|
+
` ${surface.usage}`,
|
|
27
|
+
"",
|
|
28
|
+
"Options:",
|
|
29
|
+
...formatOptionLines(surface.flags),
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
for (const section of surface.extraHelpSections ?? []) {
|
|
33
|
+
lines.push("", ...section.split("\n"));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const PUBLIC_COMMAND_SURFACES = {
|
|
40
|
+
evalGenerate: {
|
|
41
|
+
command: "selftune eval generate",
|
|
42
|
+
summary: "Build eval sets from logs or SKILL.md",
|
|
43
|
+
usage: "selftune eval generate --skill <name> [options]",
|
|
44
|
+
flags: [
|
|
45
|
+
{
|
|
46
|
+
token: "--skill",
|
|
47
|
+
helpLabel: "--skill",
|
|
48
|
+
description: "Skill name (required unless --list-skills)",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
token: "--list-skills",
|
|
52
|
+
helpLabel: "--list-skills",
|
|
53
|
+
description: "List skills with trusted-vs-raw readiness counts",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
token: "--stats",
|
|
57
|
+
helpLabel: "--stats",
|
|
58
|
+
description: "Show aggregate telemetry stats for the skill",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
token: "--max",
|
|
62
|
+
helpLabel: "--max",
|
|
63
|
+
description: "Maximum eval entries per side (default: 50)",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
token: "--seed",
|
|
67
|
+
helpLabel: "--seed",
|
|
68
|
+
description: "Deterministic shuffle seed (default: 42)",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
token: "--output",
|
|
72
|
+
helpLabel: "--output, --out",
|
|
73
|
+
description: "Output file path (default: <skill>_trigger_eval.json)",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
token: "--no-negatives",
|
|
77
|
+
helpLabel: "--no-negatives",
|
|
78
|
+
description: "Exclude negative examples from output",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
token: "--no-taxonomy",
|
|
82
|
+
helpLabel: "--no-taxonomy",
|
|
83
|
+
description: "Skip invocation_type classification",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
token: "--skill-log",
|
|
87
|
+
helpLabel: "--skill-log",
|
|
88
|
+
description: "Path to skill_usage_log.jsonl",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
token: "--query-log",
|
|
92
|
+
helpLabel: "--query-log",
|
|
93
|
+
description: "Path to all_queries_log.jsonl",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
token: "--telemetry-log",
|
|
97
|
+
helpLabel: "--telemetry-log",
|
|
98
|
+
description: "Path to session_telemetry_log.jsonl",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
token: "--synthetic",
|
|
102
|
+
helpLabel: "--synthetic",
|
|
103
|
+
description: "Generate evals from SKILL.md via LLM (no logs needed)",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
token: "--auto-synthetic",
|
|
107
|
+
helpLabel: "--auto-synthetic",
|
|
108
|
+
description: "Fall back to SKILL.md cold-start evals when no trusted triggers exist",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
token: "--blend",
|
|
112
|
+
helpLabel: "--blend",
|
|
113
|
+
description: "Blend log-based and synthetic evals into one set",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
token: "--skill-path",
|
|
117
|
+
helpLabel: "--skill-path",
|
|
118
|
+
description: "Path to SKILL.md (required with --synthetic, used by --blend)",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
token: "--model",
|
|
122
|
+
helpLabel: "--model",
|
|
123
|
+
description: "Override the synthetic-generation LLM model",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
token: "--help",
|
|
127
|
+
helpLabel: "--help",
|
|
128
|
+
description: "Show this help message",
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
quickReference:
|
|
132
|
+
"selftune eval generate --skill <name> [--list-skills] [--stats] [--max N] [--seed N] [--output PATH] [--blend]",
|
|
133
|
+
extraHelpSections: [
|
|
134
|
+
`Recommended creator loop:
|
|
135
|
+
1. selftune eval generate --skill <name>
|
|
136
|
+
2. selftune eval unit-test --skill <name> --generate --skill-path <path>
|
|
137
|
+
3. selftune evolve --skill <name> --skill-path <path> --dry-run --validation-mode replay
|
|
138
|
+
4. selftune grade baseline --skill <name> --skill-path <path>
|
|
139
|
+
|
|
140
|
+
Generated evals are also mirrored into ~/.selftune/eval-sets/<skill>.json so the dashboard and status surfaces can track readiness.`,
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
evolve: {
|
|
144
|
+
command: "selftune evolve",
|
|
145
|
+
summary: "Evolve a skill description via failure patterns",
|
|
146
|
+
usage: "selftune evolve --skill <name> --skill-path <path> [options]",
|
|
147
|
+
flags: [
|
|
148
|
+
{ token: "--skill", helpLabel: "--skill", description: "Skill name (required)" },
|
|
149
|
+
{
|
|
150
|
+
token: "--skill-path",
|
|
151
|
+
helpLabel: "--skill-path",
|
|
152
|
+
description: "Path to SKILL.md (required)",
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
token: "--eval-set",
|
|
156
|
+
helpLabel: "--eval-set",
|
|
157
|
+
description: "Path to eval set JSON (optional, builds from logs if omitted)",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
token: "--agent",
|
|
161
|
+
helpLabel: "--agent",
|
|
162
|
+
description: "Agent CLI to use (claude, codex, opencode)",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
token: "--dry-run",
|
|
166
|
+
helpLabel: "--dry-run",
|
|
167
|
+
description: "Validate proposal without deploying",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
token: "--confidence",
|
|
171
|
+
helpLabel: "--confidence",
|
|
172
|
+
description: "Confidence threshold 0.0-1.0 (default: 0.6)",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
token: "--max-iterations",
|
|
176
|
+
helpLabel: "--max-iterations",
|
|
177
|
+
description: "Max retry iterations (default: 3)",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
token: "--pareto",
|
|
181
|
+
helpLabel: "--pareto",
|
|
182
|
+
description: "Enable Pareto multi-candidate selection",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
token: "--candidates",
|
|
186
|
+
helpLabel: "--candidates",
|
|
187
|
+
description: "Number of candidates to generate (default: 3, max: 5)",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
token: "--token-efficiency",
|
|
191
|
+
helpLabel: "--token-efficiency",
|
|
192
|
+
description: "Enable 5D Pareto with token efficiency scoring",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
token: "--with-baseline",
|
|
196
|
+
helpLabel: "--with-baseline",
|
|
197
|
+
description: "Gate deployment on baseline lift > 0.05",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
token: "--validation-mode",
|
|
201
|
+
helpLabel: "--validation-mode",
|
|
202
|
+
description: "Validation strategy: auto|replay|judge (default: auto)",
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
token: "--validation-model",
|
|
206
|
+
helpLabel: "--validation-model",
|
|
207
|
+
description: "Model for trigger-check validation calls (default: haiku)",
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
token: "--cheap-loop",
|
|
211
|
+
helpLabel: "--cheap-loop",
|
|
212
|
+
description: "Use cheap models for loop, expensive for gate (default: on)",
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
token: "--full-model",
|
|
216
|
+
helpLabel: "--full-model",
|
|
217
|
+
description: "Use same model for all stages (disables cheap-loop)",
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
token: "--gate-model",
|
|
221
|
+
helpLabel: "--gate-model",
|
|
222
|
+
description: "Model for final gate validation (default: sonnet)",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
token: "--gate-effort",
|
|
226
|
+
helpLabel: "--gate-effort",
|
|
227
|
+
description: "Thinking effort for final gate (low|medium|high|max)",
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
token: "--adaptive-gate",
|
|
231
|
+
helpLabel: "--adaptive-gate",
|
|
232
|
+
description: "Escalate risky gate checks to opus + high effort",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
token: "--proposal-model",
|
|
236
|
+
helpLabel: "--proposal-model",
|
|
237
|
+
description: "Model for proposal generation LLM calls",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
token: "--sync-first",
|
|
241
|
+
helpLabel: "--sync-first",
|
|
242
|
+
description: "Refresh source-truth telemetry before building evals/failure patterns",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
token: "--sync-force",
|
|
246
|
+
helpLabel: "--sync-force",
|
|
247
|
+
description: "Force a full rescan during --sync-first",
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
token: "--verbose",
|
|
251
|
+
helpLabel: "--verbose",
|
|
252
|
+
description: "Output full EvolveResult JSON (default: compact summary)",
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
token: "--help",
|
|
256
|
+
helpLabel: "--help",
|
|
257
|
+
description: "Show this help message",
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
quickReference:
|
|
261
|
+
"selftune evolve --skill <name> --skill-path <path> [--dry-run] [--validation-mode auto|replay|judge]",
|
|
262
|
+
},
|
|
263
|
+
watch: {
|
|
264
|
+
command: "selftune watch",
|
|
265
|
+
summary: "Monitor post-deploy skill health",
|
|
266
|
+
usage: "selftune watch --skill <name> --skill-path <path> [options]",
|
|
267
|
+
flags: [
|
|
268
|
+
{ token: "--skill", helpLabel: "--skill", description: "Skill name (required)" },
|
|
269
|
+
{
|
|
270
|
+
token: "--skill-path",
|
|
271
|
+
helpLabel: "--skill-path",
|
|
272
|
+
description: "Path to SKILL.md (required)",
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
token: "--window",
|
|
276
|
+
helpLabel: "--window",
|
|
277
|
+
description: "Number of recent sessions to consider (default: 20)",
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
token: "--threshold",
|
|
281
|
+
helpLabel: "--threshold",
|
|
282
|
+
description: "Regression threshold below baseline (default: 0.1)",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
token: "--auto-rollback",
|
|
286
|
+
helpLabel: "--auto-rollback",
|
|
287
|
+
description: "Automatically rollback on regression detection",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
token: "--grade-threshold",
|
|
291
|
+
helpLabel: "--grade-threshold",
|
|
292
|
+
description: "Grade regression threshold (default: 0.15)",
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
token: "--no-grade-watch",
|
|
296
|
+
helpLabel: "--no-grade-watch",
|
|
297
|
+
description: "Disable grade-based regression watch (enabled by default)",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
token: "--sync-first",
|
|
301
|
+
helpLabel: "--sync-first",
|
|
302
|
+
description: "Refresh source-truth telemetry before reading watch inputs",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
token: "--sync-force",
|
|
306
|
+
helpLabel: "--sync-force",
|
|
307
|
+
description: "Force a full rescan during --sync-first",
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
token: "--help",
|
|
311
|
+
helpLabel: "--help",
|
|
312
|
+
description: "Show this help message",
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
quickReference:
|
|
316
|
+
"selftune watch --skill <name> --skill-path <path> [--auto-rollback] [--grade-threshold N] [--no-grade-watch]",
|
|
317
|
+
},
|
|
318
|
+
orchestrate: {
|
|
319
|
+
command: "selftune orchestrate",
|
|
320
|
+
summary: "Autonomous core loop",
|
|
321
|
+
usage: "selftune orchestrate [options]",
|
|
322
|
+
flags: [
|
|
323
|
+
{
|
|
324
|
+
token: "--dry-run",
|
|
325
|
+
helpLabel: "--dry-run",
|
|
326
|
+
description: "Preview actions without mutations",
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
token: "--review-required",
|
|
330
|
+
helpLabel: "--review-required",
|
|
331
|
+
description: "Validate candidates but require human review before deploy",
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
token: "--auto-approve",
|
|
335
|
+
helpLabel: "--auto-approve",
|
|
336
|
+
description: "Deprecated alias; autonomous mode is now the default",
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
token: "--skill",
|
|
340
|
+
helpLabel: "--skill <name>",
|
|
341
|
+
description: "Scope to a single skill",
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
token: "--max-skills",
|
|
345
|
+
helpLabel: "--max-skills <n>",
|
|
346
|
+
description: "Cap skills processed per run (default: 5)",
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
token: "--recent-window",
|
|
350
|
+
helpLabel: "--recent-window <hrs>",
|
|
351
|
+
description: "Hours to look back for watch targets (default: 48)",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
token: "--sync-force",
|
|
355
|
+
helpLabel: "--sync-force",
|
|
356
|
+
description: "Force full rescan during sync",
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
token: "--max-auto-grade",
|
|
360
|
+
helpLabel: "--max-auto-grade <n>",
|
|
361
|
+
description: "Max ungraded skills to auto-grade per run (default: 5, 0 to disable)",
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
token: "--loop",
|
|
365
|
+
helpLabel: "--loop",
|
|
366
|
+
description: "Run in continuous loop mode (never stops)",
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
token: "--loop-interval",
|
|
370
|
+
helpLabel: "--loop-interval <s>",
|
|
371
|
+
description: "Seconds between iterations (default: 3600, min: 60)",
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
token: "--help",
|
|
375
|
+
helpLabel: "-h, --help",
|
|
376
|
+
description: "Show this help message",
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
quickReference:
|
|
380
|
+
"selftune orchestrate [--dry-run] [--review-required] [--auto-approve] [--skill NAME] [--max-skills N] [--recent-window HOURS] [--sync-force] [--max-auto-grade N] [--loop] [--loop-interval SECS]",
|
|
381
|
+
extraHelpSections: [
|
|
382
|
+
`Safety:
|
|
383
|
+
By default, low-risk description evolution runs autonomously after
|
|
384
|
+
validation. Use --review-required to keep a human in the loop, or
|
|
385
|
+
--dry-run to preview the whole loop without mutations. Every deploy
|
|
386
|
+
still passes validation gates first.`,
|
|
387
|
+
`Examples:
|
|
388
|
+
selftune orchestrate # autonomous description evolution
|
|
389
|
+
selftune orchestrate --review-required # validate but do not deploy
|
|
390
|
+
selftune orchestrate --dry-run # preview only
|
|
391
|
+
selftune orchestrate --skill Research # single skill
|
|
392
|
+
selftune orchestrate --max-skills 3 # limit scope
|
|
393
|
+
selftune orchestrate --loop # continuous loop (hourly)
|
|
394
|
+
selftune orchestrate --loop --loop-interval 600 # every 10 minutes`,
|
|
395
|
+
],
|
|
396
|
+
},
|
|
397
|
+
} satisfies Record<string, PublicCommandSurface>;
|
|
@@ -13,6 +13,8 @@ const claudeHomeDir =
|
|
|
13
13
|
const openclawHomeDir =
|
|
14
14
|
process.env.SELFTUNE_OPENCLAW_DIR ??
|
|
15
15
|
(resolvedHome ? join(defaultHome, ".openclaw") : join(homedir(), ".openclaw"));
|
|
16
|
+
const piHomeDir =
|
|
17
|
+
process.env.SELFTUNE_PI_DIR ?? (resolvedHome ? join(defaultHome, ".pi") : join(homedir(), ".pi"));
|
|
16
18
|
|
|
17
19
|
export const SELFTUNE_CONFIG_DIR =
|
|
18
20
|
(process.env.SELFTUNE_CONFIG_DIR || undefined) ??
|
|
@@ -100,7 +102,7 @@ export const REQUIRED_FIELDS: Record<string, Set<string>> = {
|
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
/** Agent CLI candidates in detection order. */
|
|
103
|
-
export const AGENT_CANDIDATES = ["claude", "codex", "opencode", "openclaw"] as const;
|
|
105
|
+
export const AGENT_CANDIDATES = ["claude", "codex", "opencode", "openclaw", "pi"] as const;
|
|
104
106
|
|
|
105
107
|
/** Required Claude Code hook keys in settings.json. */
|
|
106
108
|
export const CLAUDE_CODE_HOOK_KEYS = [
|
|
@@ -158,6 +160,13 @@ export const OPENCLAW_AGENTS_DIR =
|
|
|
158
160
|
/** Marker file tracking which OpenClaw sessions have been ingested. */
|
|
159
161
|
export const OPENCLAW_INGEST_MARKER = join(SELFTUNE_CONFIG_DIR, "openclaw-ingest-marker.json");
|
|
160
162
|
|
|
163
|
+
/** Pi sessions directory. */
|
|
164
|
+
export const PI_SESSIONS_DIR =
|
|
165
|
+
process.env.SELFTUNE_PI_SESSIONS_DIR ?? join(piHomeDir, "agent", "sessions");
|
|
166
|
+
|
|
167
|
+
/** Marker file tracking which Pi sessions have been ingested. */
|
|
168
|
+
export const PI_INGEST_MARKER = join(SELFTUNE_CONFIG_DIR, "pi-ingest-marker.json");
|
|
169
|
+
|
|
161
170
|
/** Default output directory for contribution bundles. */
|
|
162
171
|
export const CONTRIBUTIONS_DIR = join(SELFTUNE_CONFIG_DIR, "contributions");
|
|
163
172
|
/** Creator-directed contribution preferences (per-skill opt-in state). */
|
|
@@ -11,8 +11,11 @@ import { spawnSync } from "node:child_process";
|
|
|
11
11
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { parseArgs } from "node:util";
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { readAlphaIdentity } from "../alpha-identity.js";
|
|
15
|
+
import { CONTRIBUTIONS_DIR, SELFTUNE_CONFIG_PATH } from "../constants.js";
|
|
16
|
+
import { findCreatorContributionConfig } from "../contribution-config.js";
|
|
15
17
|
import { handleCLIError } from "../utils/cli-error.js";
|
|
18
|
+
import { getSelftuneVersion } from "../utils/selftune-meta.js";
|
|
16
19
|
import { assembleBundle } from "./bundle.js";
|
|
17
20
|
import { sanitizeBundle } from "./sanitize.js";
|
|
18
21
|
|
|
@@ -29,7 +32,7 @@ export async function cliMain(): Promise<void> {
|
|
|
29
32
|
sanitize: { type: "string", default: "conservative" },
|
|
30
33
|
since: { type: "string" },
|
|
31
34
|
submit: { type: "boolean", default: false },
|
|
32
|
-
endpoint: { type: "string"
|
|
35
|
+
endpoint: { type: "string" },
|
|
33
36
|
github: { type: "boolean", default: false },
|
|
34
37
|
help: { type: "boolean", short: "h", default: false },
|
|
35
38
|
},
|
|
@@ -37,16 +40,16 @@ export async function cliMain(): Promise<void> {
|
|
|
37
40
|
});
|
|
38
41
|
|
|
39
42
|
if (values.help) {
|
|
40
|
-
console.log(`selftune contribute — Export an anonymized community bundle
|
|
43
|
+
console.log(`selftune contribute — Export an anonymized community export bundle
|
|
41
44
|
|
|
42
45
|
Usage:
|
|
43
46
|
selftune contribute --skill <name> [--preview] [--sanitize conservative|aggressive]
|
|
44
47
|
selftune contribute --skill <name> [--output <file>] [--submit]
|
|
45
48
|
|
|
46
49
|
Purpose:
|
|
47
|
-
Build a sanitized community
|
|
50
|
+
Build a sanitized community export bundle from local SQLite data.
|
|
48
51
|
This is separate from:
|
|
49
|
-
selftune contributions
|
|
52
|
+
selftune contributions Sharing preferences (creator-directed opt-in/out)
|
|
50
53
|
selftune alpha upload Personal cloud upload cycle
|
|
51
54
|
|
|
52
55
|
Options:
|
|
@@ -131,7 +134,8 @@ Options:
|
|
|
131
134
|
const ok = submitToGitHub(json, outputPath);
|
|
132
135
|
if (!ok) process.exit(1);
|
|
133
136
|
} else {
|
|
134
|
-
const
|
|
137
|
+
const auth = getLocalAuthConfig();
|
|
138
|
+
const endpoint = values.endpoint ?? auth?.apiUrl ?? "https://api.selftune.dev";
|
|
135
139
|
const ok = await submitToService(json, endpoint, skillName);
|
|
136
140
|
if (!ok) {
|
|
137
141
|
console.log("Falling back to GitHub submission...");
|
|
@@ -143,7 +147,27 @@ Options:
|
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
// ---------------------------------------------------------------------------
|
|
146
|
-
//
|
|
150
|
+
// Auth helpers
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
function getLocalAuthConfig(): { apiUrl: string; apiKey: string } | null {
|
|
154
|
+
try {
|
|
155
|
+
const identity = readAlphaIdentity(SELFTUNE_CONFIG_PATH);
|
|
156
|
+
if (!identity?.api_key) return null;
|
|
157
|
+
const apiUrl = identity.cloud_api_url || "https://api.selftune.dev";
|
|
158
|
+
return { apiUrl, apiKey: identity.api_key };
|
|
159
|
+
} catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function resolveCreatorId(skillName: string): string | null {
|
|
165
|
+
const config = findCreatorContributionConfig(skillName);
|
|
166
|
+
return config?.creator_id ?? null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Service submission (cloud endpoint)
|
|
147
171
|
// ---------------------------------------------------------------------------
|
|
148
172
|
|
|
149
173
|
async function submitToService(
|
|
@@ -151,12 +175,39 @@ async function submitToService(
|
|
|
151
175
|
endpoint: string,
|
|
152
176
|
skillName: string,
|
|
153
177
|
): Promise<boolean> {
|
|
178
|
+
// Resolve creator_id from the installed selftune.contribute.json
|
|
179
|
+
const creatorId = resolveCreatorId(skillName);
|
|
180
|
+
if (!creatorId) {
|
|
181
|
+
console.error(
|
|
182
|
+
`[ERROR] No creator_id found for skill "${skillName}". ` +
|
|
183
|
+
`Ensure selftune.contribute.json exists in the skill directory with a valid creator_id.`,
|
|
184
|
+
);
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Resolve auth from local config
|
|
189
|
+
const auth = getLocalAuthConfig();
|
|
190
|
+
|
|
154
191
|
try {
|
|
155
|
-
const url = `${endpoint}/api/
|
|
192
|
+
const url = `${endpoint}/api/v1/community/bundles`;
|
|
193
|
+
// Wrap the already-serialized bundle in the submission envelope
|
|
194
|
+
// without an unnecessary parse/stringify cycle
|
|
195
|
+
const payload = `{"creator_id":${JSON.stringify(creatorId)},"skill_name":${JSON.stringify(skillName)},"bundle":${json}}`;
|
|
196
|
+
|
|
197
|
+
const headers: Record<string, string> = {
|
|
198
|
+
"Content-Type": "application/json",
|
|
199
|
+
"User-Agent": `selftune/${getSelftuneVersion()}`,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
if (auth?.apiKey) {
|
|
203
|
+
headers.Authorization = `Bearer ${auth.apiKey}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
156
206
|
const res = await fetch(url, {
|
|
157
207
|
method: "POST",
|
|
158
|
-
headers
|
|
159
|
-
body:
|
|
208
|
+
headers,
|
|
209
|
+
body: payload,
|
|
210
|
+
signal: AbortSignal.timeout(60_000),
|
|
160
211
|
});
|
|
161
212
|
|
|
162
213
|
if (!res.ok) {
|
|
@@ -165,9 +216,9 @@ async function submitToService(
|
|
|
165
216
|
return false;
|
|
166
217
|
}
|
|
167
218
|
|
|
168
|
-
console.log(`\nSubmitted to ${endpoint}`);
|
|
169
|
-
console.log(`
|
|
170
|
-
console.log(`
|
|
219
|
+
console.log(`\nSubmitted to ${endpoint}/api/v1/community/bundles`);
|
|
220
|
+
console.log(` Skill: ${skillName}`);
|
|
221
|
+
console.log(` Creator: ${creatorId}`);
|
|
171
222
|
return true;
|
|
172
223
|
} catch (err) {
|
|
173
224
|
console.error(
|
|
@@ -7,21 +7,62 @@ import {
|
|
|
7
7
|
findRepositorySkillDirs,
|
|
8
8
|
} from "./utils/skill-discovery.js";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* The canonical UUID pattern for `creator_id`. This field must always be the
|
|
12
|
+
* creator's cloud user UUID (the `cloud_user_id` from alpha enrollment), e.g.
|
|
13
|
+
* "550e8400-e29b-41d4-a716-446655440000". Non-UUID values are accepted during
|
|
14
|
+
* local development but will be rejected by the relay endpoint.
|
|
15
|
+
*/
|
|
16
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17
|
+
export const SUPPORTED_CONTRIBUTION_SIGNALS = ["trigger", "grade", "miss_category"] as const;
|
|
18
|
+
export type SupportedContributionSignal = (typeof SUPPORTED_CONTRIBUTION_SIGNALS)[number];
|
|
19
|
+
|
|
20
|
+
/** Returns `true` when `value` looks like a valid UUID v4 (case-insensitive). */
|
|
21
|
+
export function isValidCreatorUUID(value: string): boolean {
|
|
22
|
+
return UUID_RE.test(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isSupportedContributionSignal(value: string): value is SupportedContributionSignal {
|
|
26
|
+
return SUPPORTED_CONTRIBUTION_SIGNALS.includes(value as SupportedContributionSignal);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function normalizeSupportedContributionSignals(
|
|
30
|
+
rawSignals: string[],
|
|
31
|
+
): SupportedContributionSignal[] {
|
|
32
|
+
const normalized = [...new Set(rawSignals.map((signal) => signal.trim()).filter(Boolean))];
|
|
33
|
+
if (normalized.length === 0) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`At least one contribution signal is required. Supported signals: ${SUPPORTED_CONTRIBUTION_SIGNALS.join(", ")}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const invalid = normalized.filter((signal) => !isSupportedContributionSignal(signal));
|
|
40
|
+
if (invalid.length > 0) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Unsupported contribution signals: ${invalid.join(", ")}. Supported signals: ${SUPPORTED_CONTRIBUTION_SIGNALS.join(", ")}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return normalized as SupportedContributionSignal[];
|
|
47
|
+
}
|
|
48
|
+
|
|
10
49
|
export interface CreatorContributionConfig {
|
|
11
50
|
version: 1;
|
|
51
|
+
/** Must be the creator's cloud user UUID (`cloud_user_id`). */
|
|
12
52
|
creator_id: string;
|
|
13
53
|
skill_name: string;
|
|
14
54
|
config_path: string;
|
|
15
55
|
skill_path: string;
|
|
16
56
|
contribution: {
|
|
17
57
|
enabled: boolean;
|
|
18
|
-
signals:
|
|
58
|
+
signals: SupportedContributionSignal[];
|
|
19
59
|
message?: string;
|
|
20
60
|
privacy_url?: string;
|
|
21
61
|
};
|
|
22
62
|
}
|
|
23
63
|
|
|
24
64
|
export interface CreatorContributionConfigInput {
|
|
65
|
+
/** Must be the creator's cloud user UUID (`cloud_user_id`). */
|
|
25
66
|
creator_id: string;
|
|
26
67
|
skill_name: string;
|
|
27
68
|
skill_path: string;
|
|
@@ -95,6 +136,13 @@ function normalizeContributionConfig(
|
|
|
95
136
|
.filter(Boolean);
|
|
96
137
|
if (signals.length === 0) return null;
|
|
97
138
|
|
|
139
|
+
if (!isValidCreatorUUID(creatorId)) {
|
|
140
|
+
process.stderr.write(
|
|
141
|
+
`[selftune] warning: creator_id "${creatorId}" is not a valid UUID. ` +
|
|
142
|
+
`Expected a cloud user UUID (e.g. "550e8400-e29b-41d4-a716-446655440000").\n`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
98
146
|
return {
|
|
99
147
|
version: 1,
|
|
100
148
|
creator_id: creatorId,
|
|
@@ -103,7 +151,7 @@ function normalizeContributionConfig(
|
|
|
103
151
|
skill_path: skillPath,
|
|
104
152
|
contribution: {
|
|
105
153
|
enabled: true,
|
|
106
|
-
signals:
|
|
154
|
+
signals: normalizeSupportedContributionSignals(signals),
|
|
107
155
|
message: typeof raw.contribution.message === "string" ? raw.contribution.message : undefined,
|
|
108
156
|
privacy_url:
|
|
109
157
|
typeof raw.contribution.privacy_url === "string" ? raw.contribution.privacy_url : undefined,
|
|
@@ -150,6 +198,12 @@ export function resolveContributionSkillPath(
|
|
|
150
198
|
export function writeCreatorContributionConfig(
|
|
151
199
|
input: CreatorContributionConfigInput,
|
|
152
200
|
): CreatorContributionConfig {
|
|
201
|
+
if (!isValidCreatorUUID(input.creator_id)) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`creator_id must be the creator's cloud user UUID. Received "${input.creator_id}".`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const signals = normalizeSupportedContributionSignals(input.signals);
|
|
153
207
|
const normalized = normalizeContributionConfig(
|
|
154
208
|
{
|
|
155
209
|
version: 1,
|
|
@@ -157,7 +211,7 @@ export function writeCreatorContributionConfig(
|
|
|
157
211
|
skill_name: input.skill_name,
|
|
158
212
|
contribution: {
|
|
159
213
|
enabled: true,
|
|
160
|
-
signals
|
|
214
|
+
signals,
|
|
161
215
|
message: input.message,
|
|
162
216
|
privacy_url: input.privacy_url,
|
|
163
217
|
},
|