@viraatdas/rudder 2.10.22 → 2.10.23
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 +41 -0
- package/dist/improve/advisor.d.ts +10 -0
- package/dist/improve/advisor.js +115 -0
- package/dist/improve/advisor.js.map +1 -0
- package/dist/improve/collect.d.ts +10 -0
- package/dist/improve/collect.js +202 -0
- package/dist/improve/collect.js.map +1 -0
- package/dist/improve/gate.d.ts +17 -0
- package/dist/improve/gate.js +60 -0
- package/dist/improve/gate.js.map +1 -0
- package/dist/improve/index.d.ts +9 -0
- package/dist/improve/index.js +336 -0
- package/dist/improve/index.js.map +1 -0
- package/dist/improve/judge.d.ts +22 -0
- package/dist/improve/judge.js +101 -0
- package/dist/improve/judge.js.map +1 -0
- package/dist/improve/mine.d.ts +25 -0
- package/dist/improve/mine.js +173 -0
- package/dist/improve/mine.js.map +1 -0
- package/dist/improve/propose.d.ts +51 -0
- package/dist/improve/propose.js +150 -0
- package/dist/improve/propose.js.map +1 -0
- package/dist/improve/rank.d.ts +16 -0
- package/dist/improve/rank.js +49 -0
- package/dist/improve/rank.js.map +1 -0
- package/dist/improve/schedule.d.ts +1 -0
- package/dist/improve/schedule.js +93 -0
- package/dist/improve/schedule.js.map +1 -0
- package/dist/improve/ship.d.ts +25 -0
- package/dist/improve/ship.js +82 -0
- package/dist/improve/ship.js.map +1 -0
- package/dist/improve/state.d.ts +149 -0
- package/dist/improve/state.js +261 -0
- package/dist/improve/state.js.map +1 -0
- package/dist/main.js +11 -0
- package/dist/main.js.map +1 -1
- package/dist/task-summary.d.ts +6 -0
- package/dist/task-summary.js +6 -1
- package/dist/task-summary.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.js.map +1 -1
- 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":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,YAAY,GAMb,MAAM,YAAY,CAAC;AAmBpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAyB,EACzB,SAAiB;IAEjB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAoB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/E,IAAI,GAAG,EAAE,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,2CAA2C,GAAG,EAAE,IAAI,IAAI,SAAS,GAAG,CAAC,CAAC;IAChH,CAAC;IAED,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IACxF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE;QACnF,GAAG,EAAE,IAAI;QACT,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IAE/D,MAAM,MAAM,GAAG,WAAW,SAAS,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAClF,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7F,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAyB,EAAE,QAAgB,EAAE,MAAc;IAC9F,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE;QACnE,GAAG,EAAE,QAAQ,CAAC,QAAQ;QACtB,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IACH,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AACpG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAIhC;IACC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;SAC9B,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,QAAQ,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;SACnF,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO;SACjC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;SAC1G,KAAK,CAAC,CAAC,CAAC,CAAC;SACT,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;SACjF,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;;;;QAKD,OAAO,CAAC,EAAE;WACP,OAAO,CAAC,KAAK;cACV,OAAO,CAAC,QAAQ,eAAe,OAAO,CAAC,SAAS;WACnD,OAAO,CAAC,KAAK;YACZ,OAAO,CAAC,MAAM;;;EAGxB,QAAQ,IAAI,6BAA6B;;;EAGzC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,oBAAoB;;EAEnF,WAAW;;;EAGX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;;;EAG/B,aAAa,IAAI,UAAU;;;;;;;;;oHASuF,CAAC;AACrH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAQzC;IACC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS;QAC7B,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,qDAAqD,MAAM,CAAC,SAAS,EAAE;QAC9F,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;IACvB,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC;QACjC,OAAO,EAAE,QAAQ;QACjB,IAAI;QACJ,GAAG,EAAE,MAAM,CAAC,QAAQ;QACpB,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,cAAc;QACzC,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,YAAY;KACtB,CAAC,CAAC;IAEH,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,MAAM,QAAQ,CAK3B,UAAU,CAAC,CAAC;IACf,MAAM,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,OAAO;QACxB,CAAC,CAAC;YACE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;YACpD,WAAW,EAAE,OAAO,CAAC,WAAW,KAAK,aAAa,CAAC,CAAC,CAAE,aAAuB,CAAC,CAAC,CAAE,OAAiB;YAClG,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;YAC/E,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;SACvE;QACH,CAAC,CAAC,IAAI,CAAC;IAET,kEAAkE;IAClE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5F,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACzB,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjE,MAAM,UAAU,CACd,KAAK,EACL,CAAC,QAAQ,EAAE,IAAI,EAAE,YAAY,MAAM,CAAC,OAAO,CAAC,KAAK,yBAAyB,MAAM,CAAC,OAAO,CAAC,EAAE,gCAAgC,CAAC,EAC5H,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAC7C,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,EAAE;QAC1F,GAAG,EAAE,MAAM,CAAC,QAAQ;KACrB,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3F,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,EAAE;QACtF,GAAG,EAAE,MAAM,CAAC,QAAQ;KACrB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAExG,OAAO;QACL,WAAW;QACX,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY;YACZ,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE;YAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;YACxC,UAAU;YACV,YAAY;SACb;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -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>;
|