selftune 0.2.18 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +60 -0
- package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +1 -0
- package/apps/local-dashboard/dist/assets/vendor-table-BIiI3YhS.js +1 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +12 -0
- package/apps/local-dashboard/dist/index.html +5 -5
- package/cli/selftune/alpha-upload/stage-canonical.ts +7 -6
- package/cli/selftune/constants.ts +10 -0
- package/cli/selftune/contribute/contribute.ts +30 -2
- package/cli/selftune/contribution-config.ts +249 -0
- package/cli/selftune/contribution-relay.ts +177 -0
- package/cli/selftune/contribution-signals.ts +219 -0
- package/cli/selftune/contribution-staging.ts +147 -0
- package/cli/selftune/contributions.ts +532 -0
- package/cli/selftune/creator-contributions.ts +333 -0
- package/cli/selftune/dashboard-contract.ts +209 -1
- package/cli/selftune/dashboard-server.ts +45 -11
- package/cli/selftune/eval/family-overlap.ts +714 -0
- package/cli/selftune/eval/hooks-to-evals.ts +182 -28
- package/cli/selftune/eval/synthetic-evals.ts +298 -11
- package/cli/selftune/evolution/evidence.ts +5 -0
- package/cli/selftune/evolution/evolve-body.ts +62 -2
- package/cli/selftune/evolution/evolve.ts +58 -1
- package/cli/selftune/evolution/validate-body.ts +10 -0
- package/cli/selftune/evolution/validate-host-replay.ts +236 -0
- package/cli/selftune/evolution/validate-proposal.ts +10 -0
- package/cli/selftune/evolution/validate-routing.ts +112 -5
- package/cli/selftune/export.ts +2 -2
- package/cli/selftune/index.ts +41 -5
- package/cli/selftune/ingestors/codex-rollout.ts +31 -35
- package/cli/selftune/ingestors/codex-wrapper.ts +32 -24
- package/cli/selftune/localdb/db.ts +2 -2
- package/cli/selftune/localdb/direct-write.ts +8 -3
- package/cli/selftune/localdb/materialize.ts +7 -2
- package/cli/selftune/localdb/queries.ts +712 -31
- package/cli/selftune/localdb/schema.ts +30 -1
- package/cli/selftune/recover.ts +153 -0
- package/cli/selftune/repair/skill-usage.ts +363 -4
- package/cli/selftune/routes/actions.ts +35 -1
- package/cli/selftune/routes/analytics.ts +14 -0
- package/cli/selftune/routes/index.ts +1 -0
- package/cli/selftune/routes/overview.ts +112 -4
- package/cli/selftune/routes/skill-report.ts +575 -11
- package/cli/selftune/status.ts +81 -2
- package/cli/selftune/sync.ts +56 -2
- package/cli/selftune/trust-model.ts +66 -0
- package/cli/selftune/types.ts +103 -0
- package/cli/selftune/utils/skill-detection.ts +43 -0
- package/cli/selftune/utils/text-similarity.ts +73 -0
- package/cli/selftune/watchlist.ts +65 -0
- package/package.json +1 -1
- package/packages/ui/src/components/ActivityTimeline.tsx +165 -150
- package/packages/ui/src/components/EvidenceViewer.tsx +419 -145
- package/packages/ui/src/components/EvolutionTimeline.tsx +81 -29
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +33 -16
- package/packages/ui/src/components/RecentActivityFeed.tsx +72 -41
- package/packages/ui/src/components/section-cards.tsx +12 -9
- package/packages/ui/src/primitives/card.tsx +1 -1
- package/packages/ui/src/types.ts +4 -0
- package/skill/SKILL.md +11 -1
- package/skill/Workflows/AlphaUpload.md +4 -0
- package/skill/Workflows/Composability.md +78 -0
- package/skill/Workflows/Contribute.md +6 -3
- package/skill/Workflows/Contributions.md +97 -0
- package/skill/Workflows/CreatorContributions.md +74 -0
- package/skill/Workflows/Dashboard.md +31 -0
- package/skill/Workflows/Evals.md +57 -8
- package/skill/Workflows/Evolve.md +23 -0
- package/skill/Workflows/Ingest.md +7 -0
- package/skill/Workflows/Initialize.md +20 -1
- package/skill/Workflows/Recover.md +84 -0
- package/skill/Workflows/RepairSkillUsage.md +12 -4
- package/skill/Workflows/Sync.md +18 -12
- package/apps/local-dashboard/dist/assets/index-BMIS6uUh.css +0 -2
- package/apps/local-dashboard/dist/assets/index-DOu3iLD9.js +0 -16
- package/apps/local-dashboard/dist/assets/vendor-table-pHbDxq36.js +0 -8
- package/apps/local-dashboard/dist/assets/vendor-ui-DIwlrGlb.js +0 -12
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Route handler: POST /api/actions/{watch,evolve,rollback}
|
|
2
|
+
* Route handler: POST /api/actions/{watch,evolve,rollback,watchlist}
|
|
3
3
|
*
|
|
4
4
|
* Triggers selftune CLI commands as child processes and returns the result.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
|
|
9
|
+
import { saveWatchedSkills } from "../watchlist.js";
|
|
10
|
+
|
|
9
11
|
export type ActionRunner = (
|
|
10
12
|
command: string,
|
|
11
13
|
args: string[],
|
|
@@ -41,6 +43,38 @@ export async function handleAction(
|
|
|
41
43
|
body: Record<string, unknown>,
|
|
42
44
|
executeAction: ActionRunner = runAction,
|
|
43
45
|
): Promise<Response> {
|
|
46
|
+
if (action === "watchlist") {
|
|
47
|
+
const skills = body.skills;
|
|
48
|
+
if (skills === undefined || skills === null) {
|
|
49
|
+
return Response.json(
|
|
50
|
+
{ success: false, error: "Missing required field: skills[]" },
|
|
51
|
+
{ status: 400 },
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!Array.isArray(skills) || !skills.every((skill) => typeof skill === "string")) {
|
|
55
|
+
return Response.json(
|
|
56
|
+
{
|
|
57
|
+
success: false,
|
|
58
|
+
error: "Invalid type for skills: expected array of strings",
|
|
59
|
+
},
|
|
60
|
+
{ status: 400 },
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const saved = saveWatchedSkills(skills);
|
|
65
|
+
return Response.json({ success: true, watched_skills: saved, error: null });
|
|
66
|
+
} catch (error: unknown) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
return Response.json(
|
|
69
|
+
{
|
|
70
|
+
success: false,
|
|
71
|
+
error: `Failed to save watched skills. Check your selftune config directory and try again. ${message}`,
|
|
72
|
+
},
|
|
73
|
+
{ status: 500 },
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
44
78
|
if (action === "watch" || action === "evolve") {
|
|
45
79
|
const skill = body.skill as string | undefined;
|
|
46
80
|
const skillPath = body.skillPath as string | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handler: GET /api/v2/analytics
|
|
3
|
+
*
|
|
4
|
+
* Returns performance analytics payload from SQLite.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Database } from "bun:sqlite";
|
|
8
|
+
|
|
9
|
+
import { getAnalyticsPayload } from "../localdb/queries.js";
|
|
10
|
+
|
|
11
|
+
export function handleAnalytics(db: Database): Response {
|
|
12
|
+
const analytics = getAnalyticsPayload(db);
|
|
13
|
+
return Response.json(analytics);
|
|
14
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
export type { ActionRunner } from "./actions.js";
|
|
8
8
|
export { handleAction, runAction } from "./actions.js";
|
|
9
|
+
export { handleAnalytics } from "./analytics.js";
|
|
9
10
|
export { handleBadge } from "./badge.js";
|
|
10
11
|
export { handleDoctor } from "./doctor.js";
|
|
11
12
|
export { handleOrchestrateRuns } from "./orchestrate-runs.js";
|
|
@@ -8,12 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Database } from "bun:sqlite";
|
|
10
10
|
|
|
11
|
+
import type {
|
|
12
|
+
AttentionItem,
|
|
13
|
+
AutonomousDecision,
|
|
14
|
+
AutonomyStatus,
|
|
15
|
+
AutonomyStatusLevel,
|
|
16
|
+
OverviewResponse,
|
|
17
|
+
} from "../dashboard-contract.js";
|
|
11
18
|
import { parseCursorParam, parseIntParam } from "../dashboard-contract.js";
|
|
12
19
|
import {
|
|
20
|
+
getAttentionQueue,
|
|
13
21
|
getOverviewPayload,
|
|
14
22
|
getOverviewPayloadPaginated,
|
|
23
|
+
getRecentDecisions,
|
|
24
|
+
getSkillTrustSummaries,
|
|
15
25
|
getSkillsList,
|
|
16
26
|
} from "../localdb/queries.js";
|
|
27
|
+
import { buildTrustWatchlist } from "../trust-model.js";
|
|
28
|
+
import { loadWatchedSkills } from "../watchlist.js";
|
|
17
29
|
|
|
18
30
|
export function handleOverview(
|
|
19
31
|
db: Database,
|
|
@@ -22,18 +34,43 @@ export function handleOverview(
|
|
|
22
34
|
): Response {
|
|
23
35
|
const skills = getSkillsList(db);
|
|
24
36
|
|
|
25
|
-
//
|
|
37
|
+
// -- Autonomy-first enrichment fields ----------------------------------------
|
|
38
|
+
const attentionQueue = getAttentionQueue(db);
|
|
39
|
+
const recentDecisions = getRecentDecisions(db);
|
|
40
|
+
const trustSummaries = getSkillTrustSummaries(db);
|
|
41
|
+
const pendingReviews = attentionQueue.filter((a) => a.category === "needs_review").length;
|
|
42
|
+
|
|
43
|
+
const trustWatchlist = buildTrustWatchlist(trustSummaries);
|
|
44
|
+
const autonomyStatus = buildAutonomyStatus(
|
|
45
|
+
db,
|
|
46
|
+
attentionQueue,
|
|
47
|
+
recentDecisions,
|
|
48
|
+
skills.length,
|
|
49
|
+
pendingReviews,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const enrichment = {
|
|
53
|
+
watched_skills: loadWatchedSkills(),
|
|
54
|
+
autonomy_status: autonomyStatus,
|
|
55
|
+
attention_queue: attentionQueue,
|
|
56
|
+
trust_watchlist: trustWatchlist,
|
|
57
|
+
recent_decisions: recentDecisions,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// -- Standard overview payload -----------------------------------------------
|
|
26
61
|
const hasPaginationParams =
|
|
27
62
|
searchParams &&
|
|
28
63
|
(searchParams.has("telemetry_cursor") ||
|
|
29
64
|
searchParams.has("telemetry_limit") ||
|
|
30
65
|
searchParams.has("skills_cursor") ||
|
|
31
66
|
searchParams.has("skills_limit"));
|
|
67
|
+
const hasSkillsPagination =
|
|
68
|
+
searchParams && (searchParams.has("skills_cursor") || searchParams.has("skills_limit"));
|
|
32
69
|
|
|
33
70
|
if (!hasPaginationParams) {
|
|
34
|
-
// Backward-compatible: return the unpaginated overview
|
|
35
71
|
const overview = getOverviewPayload(db);
|
|
36
|
-
|
|
72
|
+
const response: OverviewResponse = { overview, skills, version, ...enrichment };
|
|
73
|
+
return Response.json(response);
|
|
37
74
|
}
|
|
38
75
|
|
|
39
76
|
// Parse pagination params
|
|
@@ -49,5 +86,76 @@ export function handleOverview(
|
|
|
49
86
|
skills_limit: skillsLimit,
|
|
50
87
|
});
|
|
51
88
|
|
|
52
|
-
|
|
89
|
+
const paginatedSkillNames = new Set(overview.skills_page.items.map((row) => row.skill_name));
|
|
90
|
+
const paginatedSkills = hasSkillsPagination
|
|
91
|
+
? skills.filter((skill) => paginatedSkillNames.has(skill.skill_name))
|
|
92
|
+
: skills;
|
|
93
|
+
|
|
94
|
+
return Response.json({ overview, skills: paginatedSkills, version, ...enrichment });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// -- Internal helpers ----------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
function buildAutonomyStatus(
|
|
100
|
+
db: Database,
|
|
101
|
+
attentionQueue: AttentionItem[],
|
|
102
|
+
recentDecisions: AutonomousDecision[],
|
|
103
|
+
skillsObserved: number,
|
|
104
|
+
pendingReviews: number,
|
|
105
|
+
): AutonomyStatus {
|
|
106
|
+
let lastRun: string | null = null;
|
|
107
|
+
try {
|
|
108
|
+
const row = db
|
|
109
|
+
.query(`SELECT timestamp FROM orchestrate_runs ORDER BY timestamp DESC LIMIT 1`)
|
|
110
|
+
.get() as { timestamp: string } | null;
|
|
111
|
+
lastRun = row?.timestamp ?? null;
|
|
112
|
+
} catch {
|
|
113
|
+
// Table may not exist
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const hasCritical = attentionQueue.some((a) => a.severity === "critical");
|
|
117
|
+
|
|
118
|
+
// "watching" means recent autonomous activity — last run within 24 hours
|
|
119
|
+
// or recent decisions within the 7-day freshness window
|
|
120
|
+
const hasRecentActivity =
|
|
121
|
+
(lastRun != null && Date.now() - new Date(lastRun).getTime() < 24 * 60 * 60 * 1000) ||
|
|
122
|
+
recentDecisions.length > 0;
|
|
123
|
+
|
|
124
|
+
let level: AutonomyStatusLevel;
|
|
125
|
+
if (hasCritical) {
|
|
126
|
+
level = "blocked";
|
|
127
|
+
} else if (pendingReviews > 0) {
|
|
128
|
+
level = "needs_review";
|
|
129
|
+
} else if (hasRecentActivity) {
|
|
130
|
+
level = "watching";
|
|
131
|
+
} else {
|
|
132
|
+
level = "healthy";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let summary: string;
|
|
136
|
+
switch (level) {
|
|
137
|
+
case "healthy":
|
|
138
|
+
summary = "No action needed. System is healthy.";
|
|
139
|
+
break;
|
|
140
|
+
case "blocked": {
|
|
141
|
+
const critCount = attentionQueue.filter((a) => a.severity === "critical").length;
|
|
142
|
+
summary = `${critCount} skill${critCount !== 1 ? "s" : ""} need${critCount === 1 ? "s" : ""} urgent attention after rollback.`;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case "needs_review":
|
|
146
|
+
summary = `selftune is watching ${skillsObserved} skill${skillsObserved !== 1 ? "s" : ""} and needs review on ${pendingReviews} proposal${pendingReviews !== 1 ? "s" : ""}.`;
|
|
147
|
+
break;
|
|
148
|
+
case "watching":
|
|
149
|
+
summary = `selftune is actively watching ${skillsObserved} skill${skillsObserved !== 1 ? "s" : ""}. No action needed.`;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
level,
|
|
155
|
+
summary,
|
|
156
|
+
last_run: lastRun,
|
|
157
|
+
skills_observed: skillsObserved,
|
|
158
|
+
pending_reviews: pendingReviews,
|
|
159
|
+
attention_required: attentionQueue.length,
|
|
160
|
+
};
|
|
53
161
|
}
|