@viraatdas/rudder 2.10.22 → 2.10.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.
Files changed (47) hide show
  1. package/README.md +41 -0
  2. package/dist/improve/advisor.d.ts +10 -0
  3. package/dist/improve/advisor.js +115 -0
  4. package/dist/improve/advisor.js.map +1 -0
  5. package/dist/improve/collect.d.ts +23 -0
  6. package/dist/improve/collect.js +228 -0
  7. package/dist/improve/collect.js.map +1 -0
  8. package/dist/improve/gate.d.ts +17 -0
  9. package/dist/improve/gate.js +60 -0
  10. package/dist/improve/gate.js.map +1 -0
  11. package/dist/improve/index.d.ts +9 -0
  12. package/dist/improve/index.js +336 -0
  13. package/dist/improve/index.js.map +1 -0
  14. package/dist/improve/judge.d.ts +22 -0
  15. package/dist/improve/judge.js +101 -0
  16. package/dist/improve/judge.js.map +1 -0
  17. package/dist/improve/mine.d.ts +25 -0
  18. package/dist/improve/mine.js +173 -0
  19. package/dist/improve/mine.js.map +1 -0
  20. package/dist/improve/propose.d.ts +51 -0
  21. package/dist/improve/propose.js +150 -0
  22. package/dist/improve/propose.js.map +1 -0
  23. package/dist/improve/rank.d.ts +16 -0
  24. package/dist/improve/rank.js +49 -0
  25. package/dist/improve/rank.js.map +1 -0
  26. package/dist/improve/schedule.d.ts +1 -0
  27. package/dist/improve/schedule.js +93 -0
  28. package/dist/improve/schedule.js.map +1 -0
  29. package/dist/improve/ship.d.ts +25 -0
  30. package/dist/improve/ship.js +82 -0
  31. package/dist/improve/ship.js.map +1 -0
  32. package/dist/improve/state.d.ts +152 -0
  33. package/dist/improve/state.js +261 -0
  34. package/dist/improve/state.js.map +1 -0
  35. package/dist/jj.js +4 -0
  36. package/dist/jj.js.map +1 -1
  37. package/dist/main.js +11 -0
  38. package/dist/main.js.map +1 -1
  39. package/dist/native/darwin-arm64/rudder-native +0 -0
  40. package/dist/native/darwin-x64/rudder-native +0 -0
  41. package/dist/native/linux-x64/rudder-native +0 -0
  42. package/dist/task-summary.d.ts +6 -0
  43. package/dist/task-summary.js +6 -1
  44. package/dist/task-summary.js.map +1 -1
  45. package/dist/types.d.ts +20 -0
  46. package/dist/types.js.map +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,173 @@
1
+ import { callAdvisedTextModel } from "./advisor.js";
2
+ import { titleKey, } from "./state.js";
3
+ const MAX_SESSIONS_IN_PROMPT = 30;
4
+ const MAX_FINDINGS_FROM_MODEL = 8;
5
+ /**
6
+ * A condensed surface map so the miner proposes real file paths instead of
7
+ * hallucinated ones. Keep in sync with AGENTS.md section 2 when the layout
8
+ * moves.
9
+ */
10
+ export const SURFACE_MAP = `Rudder surface map (repo-relative paths):
11
+ - src/run-manager.ts run lifecycle: start, worker, merge/sync routing
12
+ - src/backends.ts claude/codex/acpx adapters, spawn + event streaming
13
+ - src/brain.ts worker spec/contract rendering, verifyRun
14
+ - src/planner.ts headless DAG planner + plan block parsing
15
+ - src/scheduler.ts headless DAG scheduler (daemon), merge serialization
16
+ - src/jj.ts jj workspace create/merge/rebase/undo substrate
17
+ - src/state.ts run records, config, projects registry persistence
18
+ - src/surfaces.ts DECISIONS.md / completion notes / shared context
19
+ - src/board/daemon.ts web board HTTP+SSE server
20
+ - src/cloud.ts Rudder Cloud client
21
+ - native/src/main.rs Rust TUI: App state machine, poll loop, scheduling
22
+ - native/src/tasks.rs prompt construction, orchestrator system prompt
23
+ - native/src/launch.rs agent launch/resume command building
24
+ - native/src/signals.rs completion signal hooks (Stop hook / notify)
25
+ - native/src/detect.rs idle/permission output heuristics (fallback only)
26
+ - native/src/render.rs TUI rendering`;
27
+ const MINER_SYSTEM = `You are the triage stage of Rudder's continual improvement loop.
28
+ Rudder is a terminal app that runs coding agents (Claude Code / Codex) in parallel jj worktrees with an orchestrator DAG.
29
+ You receive telemetry summaries of recent Rudder sessions. Your job is to identify friction caused by RUDDER ITSELF (its prompts, orchestration, scheduling, merge handling, UX, performance, crashes), NOT problems in the user's own projects or model quality.
30
+ Return findings as a single fenced json block: an array of objects with fields:
31
+ class: one of "prompt" | "orchestration" | "ux" | "perf" | "crash" | "other"
32
+ title: short imperative description of the defect (not the fix)
33
+ detail: 2-4 sentences: what happens, why it is Rudder's fault, what a fix might touch
34
+ evidence: array of {project, runId, excerpt} referencing the sessions given
35
+ severity: 1-5 (5 = data loss / task failure, 1 = cosmetic)
36
+ frequency: how many given sessions show it
37
+ suspectedSurfaces: repo-relative file paths from the surface map
38
+ Only report findings supported by the evidence. Fewer, well-supported findings beat many speculative ones. If nothing is attributable to Rudder, return [].`;
39
+ export async function mineFindings(params) {
40
+ const worst = [...params.sessions].sort((a, b) => frictionScore(b) - frictionScore(a));
41
+ const sample = worst.slice(0, MAX_SESSIONS_IN_PROMPT);
42
+ if (sample.length === 0)
43
+ return [];
44
+ const user = [
45
+ "Cycle metrics snapshot:",
46
+ JSON.stringify(params.snapshot),
47
+ "",
48
+ SURFACE_MAP,
49
+ "",
50
+ `Sessions (worst-first, ${sample.length} of ${params.sessions.length} new):`,
51
+ JSON.stringify(sample, null, 1),
52
+ ].join("\n");
53
+ if (!params.meter.canAfford(0.1))
54
+ return [];
55
+ // Advisor pattern: the executor (minerModel) does the bulk generation and
56
+ // consults the advisor for judgment; usage.iterations meters both sides.
57
+ const output = await callAdvisedTextModel({
58
+ executorModel: params.model,
59
+ advisorModel: params.advisorModel,
60
+ system: MINER_SYSTEM,
61
+ user,
62
+ maxTokens: 4096,
63
+ timeoutMs: 240000,
64
+ meter: params.meter,
65
+ });
66
+ const parsed = parseFindingsJson(output).slice(0, MAX_FINDINGS_FROM_MODEL);
67
+ const findings = parsed.map((raw, index) => normalizeFinding(raw, params.cycleId, index));
68
+ return dedupeAgainstLedger(findings, params.ledger);
69
+ }
70
+ export function frictionScore(session) {
71
+ let score = 0;
72
+ if (session.status === "failed")
73
+ score += 5;
74
+ if (session.status === "cancelled")
75
+ score += 3;
76
+ if (session.status === "merge-conflict" || session.mergeStatus === "conflict")
77
+ score += 4;
78
+ if (session.verifierSatisfied === false)
79
+ score += 4;
80
+ score += Math.min(3, session.steerCount);
81
+ score += Math.min(2, session.autoSteerCount);
82
+ score += session.errorExcerpts.length;
83
+ return score;
84
+ }
85
+ /** Parse the model's findings array out of a fenced block or bare JSON. */
86
+ export function parseFindingsJson(output) {
87
+ const fenced = output.match(/```(?:json)?\s*([\s\S]*?)```/);
88
+ const candidates = [fenced?.[1], output];
89
+ for (const candidate of candidates) {
90
+ if (!candidate)
91
+ continue;
92
+ const start = candidate.indexOf("[");
93
+ const end = candidate.lastIndexOf("]");
94
+ if (start < 0 || end <= start)
95
+ continue;
96
+ try {
97
+ const value = JSON.parse(candidate.slice(start, end + 1));
98
+ if (Array.isArray(value)) {
99
+ return value.filter((item) => typeof item === "object" && item !== null);
100
+ }
101
+ }
102
+ catch {
103
+ // try the next candidate
104
+ }
105
+ }
106
+ return [];
107
+ }
108
+ const FINDING_CLASSES = ["prompt", "orchestration", "ux", "perf", "crash", "other"];
109
+ function normalizeFinding(raw, cycleId, index) {
110
+ const classValue = typeof raw.class === "string" && FINDING_CLASSES.includes(raw.class)
111
+ ? raw.class
112
+ : "other";
113
+ const evidence = Array.isArray(raw.evidence)
114
+ ? raw.evidence
115
+ .filter((item) => typeof item === "object" && item !== null)
116
+ .slice(0, 5)
117
+ .map((item) => ({
118
+ project: String(item.project ?? ""),
119
+ runId: String(item.runId ?? ""),
120
+ excerpt: String(item.excerpt ?? "").slice(0, 400),
121
+ }))
122
+ : [];
123
+ return {
124
+ id: `f-${cycleId}-${index}`,
125
+ class: classValue,
126
+ title: String(raw.title ?? "untitled finding").slice(0, 160),
127
+ detail: String(raw.detail ?? "").slice(0, 1200),
128
+ evidence,
129
+ severity: clampInt(raw.severity, 1, 5, 2),
130
+ frequency: clampInt(raw.frequency, 1, 1000, 1),
131
+ suspectedSurfaces: Array.isArray(raw.suspectedSurfaces)
132
+ ? raw.suspectedSurfaces.map((s) => String(s)).slice(0, 6)
133
+ : [],
134
+ };
135
+ }
136
+ /**
137
+ * Drop findings the ledger already knows: anything shipped or currently
138
+ * banked under the same title key, and anything previously rejected unless
139
+ * its frequency has at least doubled since the rejection was recorded.
140
+ */
141
+ export function dedupeAgainstLedger(findings, ledger) {
142
+ const byKey = new Map();
143
+ for (const entry of ledger) {
144
+ const list = byKey.get(entry.titleKey) ?? [];
145
+ list.push(entry);
146
+ byKey.set(entry.titleKey, list);
147
+ }
148
+ return findings.filter((finding) => {
149
+ const history = byKey.get(titleKey(finding.title)) ?? [];
150
+ if (history.length === 0)
151
+ return true;
152
+ if (history.some((e) => e.status === "shipped" || e.status === "branch-pushed")) {
153
+ return false;
154
+ }
155
+ const rejected = history.filter((e) => e.status === "judge-rejected" || e.status === "gated-out" || e.status === "agent-failed");
156
+ if (rejected.length > 0) {
157
+ const lastFrequency = extractFrequency(rejected.at(-1)?.detail ?? "");
158
+ return finding.frequency >= Math.max(2, lastFrequency * 2);
159
+ }
160
+ return true;
161
+ });
162
+ }
163
+ function extractFrequency(detail) {
164
+ const match = detail.match(/frequency=(\d+)/);
165
+ return match ? Number.parseInt(match[1], 10) : 1;
166
+ }
167
+ function clampInt(value, min, max, fallback) {
168
+ const parsed = typeof value === "number" ? Math.round(value) : Number.parseInt(String(value), 10);
169
+ if (!Number.isFinite(parsed))
170
+ return fallback;
171
+ return Math.min(max, Math.max(min, parsed));
172
+ }
173
+ //# sourceMappingURL=mine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mine.js","sourceRoot":"","sources":["../../src/improve/mine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { type Finding, type ImproveSettings, type LedgerEntry, type MetricsSnapshot, type StepResult } from "./state.js";
2
+ export type Proposal = {
3
+ finding: Finding;
4
+ worktree: string;
5
+ branch: string;
6
+ baseRef: string;
7
+ changedFiles: string[];
8
+ diffStat: string;
9
+ diffText: string;
10
+ resultNote: {
11
+ summary: string;
12
+ changeClass: "prompt-only" | "logic";
13
+ testsRun?: string;
14
+ risks?: string;
15
+ } | null;
16
+ agentLogPath: string;
17
+ };
18
+ /**
19
+ * Create an isolated git worktree of the rudder checkout for one finding.
20
+ * Plain git worktrees are safe on the jj-colocated repo: jj does not track
21
+ * them and the loop only ever uses git plumbing inside them.
22
+ */
23
+ export declare function prepareWorktree(settings: ImproveSettings, findingId: string): Promise<{
24
+ worktree: string;
25
+ branch: string;
26
+ baseRef: string;
27
+ }>;
28
+ export declare function removeWorktree(settings: ImproveSettings, worktree: string, branch: string): Promise<void>;
29
+ /**
30
+ * The context pack: everything an autonomous agent needs to fix this finding
31
+ * well. It runs inside a full rudder worktree, so the pack points at the
32
+ * canonical context (AGENTS.md, the design doc, real paths, prior attempts)
33
+ * instead of pasting whole files.
34
+ */
35
+ export declare function buildContextPack(params: {
36
+ finding: Finding;
37
+ history: LedgerEntry[];
38
+ snapshot: MetricsSnapshot;
39
+ }): string;
40
+ export declare function runImprovementAgent(params: {
41
+ settings: ImproveSettings;
42
+ finding: Finding;
43
+ worktree: string;
44
+ branch: string;
45
+ baseRef: string;
46
+ contextPack: string;
47
+ extraNote?: string;
48
+ }): Promise<{
49
+ proposal: Proposal | null;
50
+ agentResult: StepResult;
51
+ }>;
@@ -0,0 +1,150 @@
1
+ import path from "node:path";
2
+ import { promises as fs } from "node:fs";
3
+ import { readJson, runCommand } from "../util.js";
4
+ import { SURFACE_MAP } from "./mine.js";
5
+ import { execStep, logsDir, tail, worktreesDir, } from "./state.js";
6
+ /**
7
+ * Create an isolated git worktree of the rudder checkout for one finding.
8
+ * Plain git worktrees are safe on the jj-colocated repo: jj does not track
9
+ * them and the loop only ever uses git plumbing inside them.
10
+ */
11
+ export async function prepareWorktree(settings, findingId) {
12
+ const repo = settings.repoPath;
13
+ const pkg = await readJson(path.join(repo, "package.json"));
14
+ if (pkg?.name !== "@viraatdas/rudder") {
15
+ throw new Error(`improve.repoPath ${repo} is not a rudder checkout (package name ${pkg?.name ?? "missing"})`);
16
+ }
17
+ await runCommand("git", ["fetch", "origin", "main"], { cwd: repo, allowFailure: true });
18
+ const originMain = await runCommand("git", ["rev-parse", "--verify", "origin/main"], {
19
+ cwd: repo,
20
+ allowFailure: true,
21
+ });
22
+ const baseRef = originMain.code === 0 ? "origin/main" : "HEAD";
23
+ const branch = `improve/${findingId}`;
24
+ const worktree = path.join(worktreesDir(), findingId);
25
+ await fs.rm(worktree, { recursive: true, force: true });
26
+ await runCommand("git", ["worktree", "prune"], { cwd: repo, allowFailure: true });
27
+ await runCommand("git", ["branch", "-D", branch], { cwd: repo, allowFailure: true });
28
+ await runCommand("git", ["worktree", "add", "-b", branch, worktree, baseRef], { cwd: repo });
29
+ return { worktree, branch, baseRef };
30
+ }
31
+ export async function removeWorktree(settings, worktree, branch) {
32
+ await runCommand("git", ["worktree", "remove", "--force", worktree], {
33
+ cwd: settings.repoPath,
34
+ allowFailure: true,
35
+ });
36
+ await runCommand("git", ["branch", "-D", branch], { cwd: settings.repoPath, allowFailure: true });
37
+ }
38
+ /**
39
+ * The context pack: everything an autonomous agent needs to fix this finding
40
+ * well. It runs inside a full rudder worktree, so the pack points at the
41
+ * canonical context (AGENTS.md, the design doc, real paths, prior attempts)
42
+ * instead of pasting whole files.
43
+ */
44
+ export function buildContextPack(params) {
45
+ const { finding } = params;
46
+ const evidence = finding.evidence
47
+ .map((item, i) => ` ${i + 1}. [${item.project} run ${item.runId}] ${item.excerpt}`)
48
+ .join("\n");
49
+ const priorAttempts = params.history
50
+ .filter((entry) => ["judge-rejected", "gated-out", "agent-failed", "push-conflict"].includes(entry.status))
51
+ .slice(-3)
52
+ .map((entry) => ` - ${entry.ts} ${entry.status}: ${entry.detail ?? "no detail"}`)
53
+ .join("\n");
54
+ return `You are an autonomous maintenance engineer working on Rudder itself, dispatched by Rudder's continual improvement loop (docs/continual-improvement.md). You are in an isolated git worktree of the rudder repo on branch-per-finding; nothing you do here touches the user's checkout.
55
+
56
+ FIRST, before changing anything: read AGENTS.md in the repo root end to end. It is the engineering reference and the source of truth for architecture, conventions, invariants, and gotchas. Respect it over your instincts.
57
+
58
+ FINDING (mined from real usage telemetry)
59
+ - id: ${finding.id}
60
+ - class: ${finding.class}
61
+ - severity: ${finding.severity}/5, seen in ${finding.frequency} recent session(s)
62
+ - title: ${finding.title}
63
+ - detail: ${finding.detail}
64
+
65
+ EVIDENCE (redacted excerpts from real sessions)
66
+ ${evidence || " (none beyond the metrics)"}
67
+
68
+ SUSPECTED SURFACES (verify before trusting; the miner can be wrong)
69
+ ${finding.suspectedSurfaces.map((s) => ` - ${s}`).join("\n") || " (none suggested)"}
70
+
71
+ ${SURFACE_MAP}
72
+
73
+ CURRENT CYCLE METRICS
74
+ ${JSON.stringify(params.snapshot)}
75
+
76
+ PRIOR ATTEMPTS ON THIS FINDING (do not repeat what already failed)
77
+ ${priorAttempts || " (none)"}
78
+
79
+ REQUIREMENTS
80
+ 1. Diagnose the root cause in the actual code before writing a fix. If the finding is wrong or not actionable, make NO changes and say why in the result file.
81
+ 2. Keep the diff minimal and surgical. Match surrounding style. Follow repo conventions from AGENTS.md (atomic writes via writeJson/updateJson, no em dashes in copy, signals wiring invariant, parity fixtures, etc.).
82
+ 3. Add or update tests that lock the fix in: tests/*.test.mjs for TypeScript, native/src/app_tests.rs for the TUI.
83
+ 4. Verify your own work: run \`npm run check\`, and the relevant test suite(s) for what you touched.
84
+ 5. Commit your work yourself with a clear message: git add -A && git commit. Leave the worktree clean.
85
+ 6. Write a file .rudder-improve-result.json at the worktree root: {"summary": "...", "changeClass": "prompt-only" | "logic", "testsRun": "...", "risks": "..."}. changeClass is prompt-only when you changed only prompt/instruction text.
86
+ 7. NEVER: bump the version, touch package.json version or tags, push, publish, or edit files outside this worktree.`;
87
+ }
88
+ export async function runImprovementAgent(params) {
89
+ const agentLogPath = path.join(logsDir(), `${params.finding.id}-agent.log`);
90
+ const args = ["-p", "--dangerously-skip-permissions"];
91
+ if (params.settings.workerModel) {
92
+ args.push("--model", params.settings.workerModel);
93
+ }
94
+ const prompt = params.extraNote
95
+ ? `${params.contextPack}\n\nADDITIONAL CONTEXT FROM THE PREVIOUS ATTEMPT\n${params.extraNote}`
96
+ : params.contextPack;
97
+ const agentResult = await execStep({
98
+ command: "claude",
99
+ args,
100
+ cwd: params.worktree,
101
+ timeoutMs: params.settings.agentTimeoutMs,
102
+ stdin: prompt,
103
+ logFile: agentLogPath,
104
+ });
105
+ // Read (then drop) the agent's structured result note so it never lands in
106
+ // the commit history.
107
+ const resultPath = path.join(params.worktree, ".rudder-improve-result.json");
108
+ const rawNote = await readJson(resultPath);
109
+ await fs.rm(resultPath, { force: true });
110
+ const resultNote = rawNote
111
+ ? {
112
+ summary: String(rawNote.summary ?? "").slice(0, 800),
113
+ changeClass: rawNote.changeClass === "prompt-only" ? "prompt-only" : "logic",
114
+ testsRun: rawNote.testsRun ? String(rawNote.testsRun).slice(0, 400) : undefined,
115
+ risks: rawNote.risks ? String(rawNote.risks).slice(0, 400) : undefined,
116
+ }
117
+ : null;
118
+ // Commit any uncommitted leftovers so the diff below is complete.
119
+ const status = await runCommand("git", ["status", "--porcelain"], { cwd: params.worktree });
120
+ if (status.stdout.trim()) {
121
+ await runCommand("git", ["add", "-A"], { cwd: params.worktree });
122
+ await runCommand("git", ["commit", "-m", `improve: ${params.finding.title}\n\nAutomated fix for ${params.finding.id} (continual improvement loop).`], { cwd: params.worktree, allowFailure: true });
123
+ }
124
+ const changed = await runCommand("git", ["diff", "--name-only", `${params.baseRef}..HEAD`], {
125
+ cwd: params.worktree,
126
+ });
127
+ const changedFiles = changed.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
128
+ if (changedFiles.length === 0) {
129
+ return { proposal: null, agentResult };
130
+ }
131
+ const diffStat = await runCommand("git", ["diff", "--stat", `${params.baseRef}..HEAD`], {
132
+ cwd: params.worktree,
133
+ });
134
+ const diffText = await runCommand("git", ["diff", `${params.baseRef}..HEAD`], { cwd: params.worktree });
135
+ return {
136
+ agentResult,
137
+ proposal: {
138
+ finding: params.finding,
139
+ worktree: params.worktree,
140
+ branch: params.branch,
141
+ baseRef: params.baseRef,
142
+ changedFiles,
143
+ diffStat: diffStat.stdout.trim(),
144
+ diffText: tail(diffText.stdout, 120_000),
145
+ resultNote,
146
+ agentLogPath,
147
+ },
148
+ };
149
+ }
150
+ //# sourceMappingURL=propose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propose.js","sourceRoot":"","sources":["../../src/improve/propose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Finding, FindingClass } from "./state.js";
2
+ /**
3
+ * Static tractability weights: how likely a one-shot autonomous agent is to
4
+ * land a safe fix in that area. Prompt/text changes are cheap and low-risk;
5
+ * native scheduler/merge changes are not. Phase 4 of the design feeds shipped
6
+ * outcomes back into these; until then they are priors.
7
+ */
8
+ export declare const TRACTABILITY: Record<FindingClass, number>;
9
+ export declare function scoreFinding(finding: Finding): number;
10
+ /** Rank findings best-first and return the top N; the rest is banked. */
11
+ export declare function rankFindings(findings: Finding[], maxFindings: number): {
12
+ selected: Finding[];
13
+ banked: Finding[];
14
+ };
15
+ /** The production metric a finding class is expected to move (see §8). */
16
+ export declare function targetMetricFor(findingClass: FindingClass): string;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Static tractability weights: how likely a one-shot autonomous agent is to
3
+ * land a safe fix in that area. Prompt/text changes are cheap and low-risk;
4
+ * native scheduler/merge changes are not. Phase 4 of the design feeds shipped
5
+ * outcomes back into these; until then they are priors.
6
+ */
7
+ export const TRACTABILITY = {
8
+ prompt: 1.0,
9
+ ux: 0.8,
10
+ orchestration: 0.6,
11
+ crash: 0.6,
12
+ perf: 0.5,
13
+ other: 0.4,
14
+ };
15
+ export function scoreFinding(finding) {
16
+ const tractability = TRACTABILITY[finding.class] ?? 0.4;
17
+ return round2(finding.severity * Math.log(1 + finding.frequency) * tractability);
18
+ }
19
+ /** Rank findings best-first and return the top N; the rest is banked. */
20
+ export function rankFindings(findings, maxFindings) {
21
+ const scored = findings
22
+ .map((finding) => ({ ...finding, score: scoreFinding(finding) }))
23
+ .sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
24
+ return {
25
+ selected: scored.slice(0, Math.max(0, maxFindings)),
26
+ banked: scored.slice(Math.max(0, maxFindings)),
27
+ };
28
+ }
29
+ /** The production metric a finding class is expected to move (see §8). */
30
+ export function targetMetricFor(findingClass) {
31
+ switch (findingClass) {
32
+ case "prompt":
33
+ return "verifierMissRate";
34
+ case "ux":
35
+ return "steerRate";
36
+ case "orchestration":
37
+ return "mergeConflictRate";
38
+ case "perf":
39
+ return "medianDurationMs";
40
+ case "crash":
41
+ return "failedRate";
42
+ default:
43
+ return "failedRate";
44
+ }
45
+ }
46
+ function round2(value) {
47
+ return Math.round(value * 100) / 100;
48
+ }
49
+ //# sourceMappingURL=rank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rank.js","sourceRoot":"","sources":["../../src/improve/rank.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAiC;IACxD,MAAM,EAAE,GAAG;IACX,EAAE,EAAE,GAAG;IACP,aAAa,EAAE,GAAG;IAClB,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,YAAY,CAAC,CAAC;AACnF,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,QAAmB,EAAE,WAAmB;IAInE,MAAM,MAAM,GAAG,QAAQ;SACpB,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;SAChE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,YAA0B;IACxD,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,kBAAkB,CAAC;QAC5B,KAAK,IAAI;YACP,OAAO,WAAW,CAAC;QACrB,KAAK,eAAe;YAClB,OAAO,mBAAmB,CAAC;QAC7B,KAAK,MAAM;YACT,OAAO,kBAAkB,CAAC;QAC5B,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB;YACE,OAAO,YAAY,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function scheduleCommand(action: string): Promise<void>;
@@ -0,0 +1,93 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { promises as fs } from "node:fs";
4
+ import { ensureDir, pathExists, runCommand, shortenHome } from "../util.js";
5
+ import { improveHome } from "./state.js";
6
+ const LAUNCHD_LABEL = "dev.rudder.improve";
7
+ function plistPath() {
8
+ return path.join(os.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
9
+ }
10
+ function launchdLogPath() {
11
+ return path.join(improveHome(), "launchd.log");
12
+ }
13
+ /**
14
+ * Scheduled batch, not a resident daemon (docs/continual-improvement.md §2).
15
+ * The plist shells through a login shell so the globally installed `rudder`
16
+ * resolves via the user's normal PATH. launchd fires missed
17
+ * StartCalendarInterval jobs on wake, which is exactly the laptop behavior we
18
+ * want.
19
+ */
20
+ function renderPlist() {
21
+ const log = launchdLogPath();
22
+ return `<?xml version="1.0" encoding="UTF-8"?>
23
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
24
+ <plist version="1.0">
25
+ <dict>
26
+ <key>Label</key>
27
+ <string>${LAUNCHD_LABEL}</string>
28
+ <key>ProgramArguments</key>
29
+ <array>
30
+ <string>/bin/zsh</string>
31
+ <string>-lc</string>
32
+ <string>rudder improve run</string>
33
+ </array>
34
+ <key>StartCalendarInterval</key>
35
+ <dict>
36
+ <key>Hour</key>
37
+ <integer>3</integer>
38
+ <key>Minute</key>
39
+ <integer>30</integer>
40
+ </dict>
41
+ <key>StandardOutPath</key>
42
+ <string>${log}</string>
43
+ <key>StandardErrorPath</key>
44
+ <string>${log}</string>
45
+ </dict>
46
+ </plist>
47
+ `;
48
+ }
49
+ export async function scheduleCommand(action) {
50
+ if (process.platform !== "darwin") {
51
+ throw new Error("rudder improve schedule currently supports macOS (launchd) only; run `rudder improve run` from cron/systemd on other platforms.");
52
+ }
53
+ switch (action) {
54
+ case "install": {
55
+ await ensureDir(path.dirname(plistPath()));
56
+ await ensureDir(improveHome());
57
+ await fs.writeFile(plistPath(), renderPlist(), "utf8");
58
+ const uid = process.getuid?.() ?? 501;
59
+ // Re-bootstrap idempotently: boot out any prior registration first.
60
+ await runCommand("launchctl", ["bootout", `gui/${uid}/${LAUNCHD_LABEL}`], { allowFailure: true });
61
+ const bootstrap = await runCommand("launchctl", ["bootstrap", `gui/${uid}`, plistPath()], {
62
+ allowFailure: true,
63
+ });
64
+ if (bootstrap.code !== 0) {
65
+ await runCommand("launchctl", ["load", "-w", plistPath()]);
66
+ }
67
+ console.log(`Installed ${shortenHome(plistPath())}: nightly \`rudder improve run\` at 03:30.`);
68
+ console.log(`Logs: ${shortenHome(launchdLogPath())}`);
69
+ return;
70
+ }
71
+ case "uninstall": {
72
+ const uid = process.getuid?.() ?? 501;
73
+ await runCommand("launchctl", ["bootout", `gui/${uid}/${LAUNCHD_LABEL}`], { allowFailure: true });
74
+ await runCommand("launchctl", ["unload", plistPath()], { allowFailure: true });
75
+ await fs.rm(plistPath(), { force: true });
76
+ console.log(`Removed ${shortenHome(plistPath())}.`);
77
+ return;
78
+ }
79
+ case "status": {
80
+ const installed = await pathExists(plistPath());
81
+ const uid = process.getuid?.() ?? 501;
82
+ const print = await runCommand("launchctl", ["print", `gui/${uid}/${LAUNCHD_LABEL}`], {
83
+ allowFailure: true,
84
+ });
85
+ console.log(`plist: ${installed ? shortenHome(plistPath()) : "not installed"}`);
86
+ console.log(`launchd: ${print.code === 0 ? "loaded" : "not loaded"}`);
87
+ return;
88
+ }
89
+ default:
90
+ throw new Error("Usage: rudder improve schedule install|uninstall|status");
91
+ }
92
+ }
93
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/improve/schedule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type ImproveSettings } from "./state.js";
2
+ import type { Proposal } from "./propose.js";
3
+ export type ShipResult = {
4
+ status: "shipped";
5
+ version: string;
6
+ } | {
7
+ status: "branch-pushed";
8
+ branch: string;
9
+ } | {
10
+ status: "push-conflict";
11
+ detail: string;
12
+ };
13
+ /**
14
+ * Ship a judged proposal. In `ship` autonomy this follows the repo release
15
+ * rule end to end: rebase onto the latest origin/main, re-typecheck, `npm
16
+ * version patch` (commit + tag vX.Y.Z), and push commit + tag together so the
17
+ * tag-driven release workflow publishes to npm. Non-force push: if main moved
18
+ * between the rebase and the push, this fails cleanly and is recorded as a
19
+ * push-conflict for the next cycle. In `propose` autonomy only the branch is
20
+ * pushed for human review.
21
+ */
22
+ export declare function shipProposal(params: {
23
+ settings: ImproveSettings;
24
+ proposal: Proposal;
25
+ }): Promise<ShipResult>;