@exla/rudder 0.0.0-stage → 3.4.0

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 (181) hide show
  1. package/LICENSE +100 -0
  2. package/README.md +733 -2
  3. package/assets/rudder.icns +0 -0
  4. package/assets/sounds/NOTICE.md +8 -0
  5. package/assets/sounds/ping.mp3 +0 -0
  6. package/dist/agent-attention.d.ts +5 -0
  7. package/dist/agent-attention.js +54 -0
  8. package/dist/agent-attention.js.map +1 -0
  9. package/dist/analytics.d.ts +36 -0
  10. package/dist/analytics.js +178 -0
  11. package/dist/analytics.js.map +1 -0
  12. package/dist/attach-session.d.ts +91 -0
  13. package/dist/attach-session.js +290 -0
  14. package/dist/attach-session.js.map +1 -0
  15. package/dist/auth.d.ts +36 -0
  16. package/dist/auth.js +392 -0
  17. package/dist/auth.js.map +1 -0
  18. package/dist/backends.d.ts +3 -0
  19. package/dist/backends.js +638 -0
  20. package/dist/backends.js.map +1 -0
  21. package/dist/board/board.css +1 -0
  22. package/dist/board/board.js +2 -0
  23. package/dist/board/daemon.d.ts +39 -0
  24. package/dist/board/daemon.js +1510 -0
  25. package/dist/board/daemon.js.map +1 -0
  26. package/dist/brain.d.ts +24 -0
  27. package/dist/brain.js +244 -0
  28. package/dist/brain.js.map +1 -0
  29. package/dist/bus.d.ts +9 -0
  30. package/dist/bus.js +23 -0
  31. package/dist/bus.js.map +1 -0
  32. package/dist/checkout-sync.d.ts +35 -0
  33. package/dist/checkout-sync.js +247 -0
  34. package/dist/checkout-sync.js.map +1 -0
  35. package/dist/cloud.d.ts +48 -0
  36. package/dist/cloud.js +4596 -0
  37. package/dist/cloud.js.map +1 -0
  38. package/dist/codex-binary.d.ts +12 -0
  39. package/dist/codex-binary.js +184 -0
  40. package/dist/codex-binary.js.map +1 -0
  41. package/dist/context-audit.d.ts +21 -0
  42. package/dist/context-audit.js +109 -0
  43. package/dist/context-audit.js.map +1 -0
  44. package/dist/daemon.d.ts +27 -0
  45. package/dist/daemon.js +203 -0
  46. package/dist/daemon.js.map +1 -0
  47. package/dist/effort.d.ts +9 -0
  48. package/dist/effort.js +72 -0
  49. package/dist/effort.js.map +1 -0
  50. package/dist/feedback.d.ts +46 -0
  51. package/dist/feedback.js +173 -0
  52. package/dist/feedback.js.map +1 -0
  53. package/dist/gc.d.ts +3 -0
  54. package/dist/gc.js +262 -0
  55. package/dist/gc.js.map +1 -0
  56. package/dist/git.d.ts +31 -0
  57. package/dist/git.js +455 -0
  58. package/dist/git.js.map +1 -0
  59. package/dist/goal.d.ts +33 -0
  60. package/dist/goal.js +95 -0
  61. package/dist/goal.js.map +1 -0
  62. package/dist/graph.d.ts +93 -0
  63. package/dist/graph.js +372 -0
  64. package/dist/graph.js.map +1 -0
  65. package/dist/handoff.d.ts +110 -0
  66. package/dist/handoff.js +565 -0
  67. package/dist/handoff.js.map +1 -0
  68. package/dist/improve/advisor.d.ts +10 -0
  69. package/dist/improve/advisor.js +115 -0
  70. package/dist/improve/advisor.js.map +1 -0
  71. package/dist/improve/collect.d.ts +49 -0
  72. package/dist/improve/collect.js +274 -0
  73. package/dist/improve/collect.js.map +1 -0
  74. package/dist/improve/gate.d.ts +17 -0
  75. package/dist/improve/gate.js +60 -0
  76. package/dist/improve/gate.js.map +1 -0
  77. package/dist/improve/index.d.ts +9 -0
  78. package/dist/improve/index.js +376 -0
  79. package/dist/improve/index.js.map +1 -0
  80. package/dist/improve/judge.d.ts +32 -0
  81. package/dist/improve/judge.js +114 -0
  82. package/dist/improve/judge.js.map +1 -0
  83. package/dist/improve/mine.d.ts +31 -0
  84. package/dist/improve/mine.js +192 -0
  85. package/dist/improve/mine.js.map +1 -0
  86. package/dist/improve/propose.d.ts +51 -0
  87. package/dist/improve/propose.js +150 -0
  88. package/dist/improve/propose.js.map +1 -0
  89. package/dist/improve/rank.d.ts +16 -0
  90. package/dist/improve/rank.js +49 -0
  91. package/dist/improve/rank.js.map +1 -0
  92. package/dist/improve/schedule.d.ts +1 -0
  93. package/dist/improve/schedule.js +95 -0
  94. package/dist/improve/schedule.js.map +1 -0
  95. package/dist/improve/ship.d.ts +25 -0
  96. package/dist/improve/ship.js +82 -0
  97. package/dist/improve/ship.js.map +1 -0
  98. package/dist/improve/state.d.ts +157 -0
  99. package/dist/improve/state.js +264 -0
  100. package/dist/improve/state.js.map +1 -0
  101. package/dist/index.d.ts +2 -0
  102. package/dist/index.js +88 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/jj-binary.d.ts +36 -0
  105. package/dist/jj-binary.js +143 -0
  106. package/dist/jj-binary.js.map +1 -0
  107. package/dist/jj.d.ts +163 -0
  108. package/dist/jj.js +926 -0
  109. package/dist/jj.js.map +1 -0
  110. package/dist/logger.d.ts +22 -0
  111. package/dist/logger.js +110 -0
  112. package/dist/logger.js.map +1 -0
  113. package/dist/main.d.ts +3 -0
  114. package/dist/main.js +1366 -0
  115. package/dist/main.js.map +1 -0
  116. package/dist/migration.d.ts +82 -0
  117. package/dist/migration.js +198 -0
  118. package/dist/migration.js.map +1 -0
  119. package/dist/models.d.ts +9 -0
  120. package/dist/models.js +623 -0
  121. package/dist/models.js.map +1 -0
  122. package/dist/move-home.d.ts +82 -0
  123. package/dist/move-home.js +472 -0
  124. package/dist/move-home.js.map +1 -0
  125. package/dist/native/darwin-arm64/rudder-native +0 -0
  126. package/dist/native/darwin-x64/rudder-native +0 -0
  127. package/dist/native/linux-x64/rudder-native +0 -0
  128. package/dist/native-agents.d.ts +8 -0
  129. package/dist/native-agents.js +178 -0
  130. package/dist/native-agents.js.map +1 -0
  131. package/dist/native-binary.d.ts +4 -0
  132. package/dist/native-binary.js +140 -0
  133. package/dist/native-binary.js.map +1 -0
  134. package/dist/paste-bridge.d.ts +36 -0
  135. package/dist/paste-bridge.js +279 -0
  136. package/dist/paste-bridge.js.map +1 -0
  137. package/dist/plan-mode.d.ts +2 -0
  138. package/dist/plan-mode.js +22 -0
  139. package/dist/plan-mode.js.map +1 -0
  140. package/dist/planner.d.ts +27 -0
  141. package/dist/planner.js +587 -0
  142. package/dist/planner.js.map +1 -0
  143. package/dist/predict.d.ts +67 -0
  144. package/dist/predict.js +369 -0
  145. package/dist/predict.js.map +1 -0
  146. package/dist/report.d.ts +74 -0
  147. package/dist/report.js +412 -0
  148. package/dist/report.js.map +1 -0
  149. package/dist/rudder-md.d.ts +33 -0
  150. package/dist/rudder-md.js +142 -0
  151. package/dist/rudder-md.js.map +1 -0
  152. package/dist/run-manager.d.ts +62 -0
  153. package/dist/run-manager.js +1400 -0
  154. package/dist/run-manager.js.map +1 -0
  155. package/dist/scheduler.d.ts +128 -0
  156. package/dist/scheduler.js +955 -0
  157. package/dist/scheduler.js.map +1 -0
  158. package/dist/state.d.ts +127 -0
  159. package/dist/state.js +704 -0
  160. package/dist/state.js.map +1 -0
  161. package/dist/surfaces.d.ts +91 -0
  162. package/dist/surfaces.js +460 -0
  163. package/dist/surfaces.js.map +1 -0
  164. package/dist/task-summary.d.ts +30 -0
  165. package/dist/task-summary.js +472 -0
  166. package/dist/task-summary.js.map +1 -0
  167. package/dist/types.d.ts +492 -0
  168. package/dist/types.js +2 -0
  169. package/dist/types.js.map +1 -0
  170. package/dist/usage.d.ts +198 -0
  171. package/dist/usage.js +830 -0
  172. package/dist/usage.js.map +1 -0
  173. package/dist/util.d.ts +73 -0
  174. package/dist/util.js +399 -0
  175. package/dist/util.js.map +1 -0
  176. package/dist/version-check.d.ts +16 -0
  177. package/dist/version-check.js +269 -0
  178. package/dist/version-check.js.map +1 -0
  179. package/package.json +68 -4
  180. package/scripts/copy-native.mjs +89 -0
  181. package/scripts/postinstall.mjs +34 -0
@@ -0,0 +1,115 @@
1
+ import { callTextModel, resolveAnthropicApiKey } from "../task-summary.js";
2
+ /**
3
+ * Advisor-pattern text call (Anthropic advisor tool, beta
4
+ * advisor-tool-2026-03-01): a cheaper executor model generates the output and
5
+ * consults a higher-intelligence advisor mid-generation for strategic
6
+ * guidance. Most tokens bill at the executor rate; the loop gets near
7
+ * advisor-grade judgment on its mining and judging calls at a fraction of the
8
+ * cost of running the big model end to end.
9
+ *
10
+ * Degradation path: the deterministic test hook and the no-API-key case (CLI
11
+ * auth) fall back to callTextModel, and any advisor-request failure falls
12
+ * back to a plain executor-only call, so the loop never hard-depends on the
13
+ * beta.
14
+ */
15
+ const ADVISOR_BETA = "advisor-tool-2026-03-01";
16
+ const ADVISOR_MAX_TOKENS = 2048;
17
+ const MAX_PAUSE_RESUMES = 3;
18
+ const ADVISOR_SYSTEM_NUDGE = `
19
+
20
+ You have access to an \`advisor\` tool backed by a stronger reviewer model. It takes NO parameters; your full context is forwarded automatically. Consult it once before committing to your answer, weigh its guidance seriously, then produce the final output yourself in the requested format.`;
21
+ const ADVISOR_USER_SUFFIX = "\n\n(Advisor: please keep your guidance under 200 words; a focused verdict on the hard part beats a comprehensive plan.)";
22
+ export async function callAdvisedTextModel(params) {
23
+ const plainFallback = () => callTextModel({
24
+ model: params.executorModel,
25
+ system: params.system,
26
+ user: params.user,
27
+ maxTokens: params.maxTokens,
28
+ timeoutMs: params.timeoutMs,
29
+ });
30
+ // Deterministic test hook and disabled-advisor path go straight through.
31
+ if (process.env.RUDDER_FAKE_MODEL_OUTPUT || !params.advisorModel) {
32
+ return await plainFallback();
33
+ }
34
+ const apiKey = await resolveAnthropicApiKey();
35
+ if (!apiKey) {
36
+ // CLI-auth users have no raw key to hit the API with; use the CLI path.
37
+ return await plainFallback();
38
+ }
39
+ const tools = [
40
+ {
41
+ type: "advisor_20260301",
42
+ name: "advisor",
43
+ model: params.advisorModel,
44
+ max_tokens: ADVISOR_MAX_TOKENS,
45
+ },
46
+ ];
47
+ const messages = [
48
+ { role: "user", content: params.user + ADVISOR_USER_SUFFIX },
49
+ ];
50
+ const timeoutMs = params.timeoutMs ?? 240000;
51
+ const collected = [];
52
+ for (let attempt = 0; attempt <= MAX_PAUSE_RESUMES; attempt += 1) {
53
+ let data;
54
+ try {
55
+ const controller = new AbortController();
56
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
57
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
58
+ method: "POST",
59
+ headers: {
60
+ "content-type": "application/json",
61
+ "x-api-key": apiKey,
62
+ "anthropic-version": "2023-06-01",
63
+ "anthropic-beta": ADVISOR_BETA,
64
+ },
65
+ body: JSON.stringify({
66
+ model: params.executorModel,
67
+ max_tokens: params.maxTokens ?? 2048,
68
+ system: params.system + ADVISOR_SYSTEM_NUDGE,
69
+ tools,
70
+ messages,
71
+ }),
72
+ signal: controller.signal,
73
+ });
74
+ clearTimeout(timer);
75
+ if (!response.ok) {
76
+ // Invalid pair / beta unavailable / overloaded: degrade to plain.
77
+ return await plainFallback();
78
+ }
79
+ data = (await response.json());
80
+ }
81
+ catch {
82
+ return await plainFallback();
83
+ }
84
+ meterIterations(params, data);
85
+ for (const block of data.content ?? []) {
86
+ if (block.type === "text" && typeof block.text === "string") {
87
+ collected.push(block.text);
88
+ }
89
+ }
90
+ if (data.stop_reason === "pause_turn" && attempt < MAX_PAUSE_RESUMES) {
91
+ // Resume the paused turn: round-trip the assistant content verbatim.
92
+ messages.push({ role: "assistant", content: data.content ?? [] });
93
+ continue;
94
+ }
95
+ break;
96
+ }
97
+ const text = collected.join("").trim();
98
+ return text || (await plainFallback());
99
+ }
100
+ function meterIterations(params, data) {
101
+ if (!params.meter)
102
+ return;
103
+ const iterations = data.usage?.iterations;
104
+ if (iterations && iterations.length > 0) {
105
+ for (const iteration of iterations) {
106
+ const model = iteration.type === "advisor_message"
107
+ ? (iteration.model ?? params.advisorModel)
108
+ : params.executorModel;
109
+ params.meter.addModelTokens(model, iteration.input_tokens ?? 0, iteration.output_tokens ?? 0);
110
+ }
111
+ return;
112
+ }
113
+ params.meter.addModelTokens(params.executorModel, data.usage?.input_tokens ?? 0, data.usage?.output_tokens ?? 0);
114
+ }
115
+ //# sourceMappingURL=advisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advisor.js","sourceRoot":"","sources":["../../src/improve/advisor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { RunRecord } from "../types.js";
2
+ import type { ImproveSettings, MetricsSnapshot, SessionRecord, Watermark } from "./state.js";
3
+ /**
4
+ * Walk registered projects and build redacted session records for every run
5
+ * newer than the watermark. Pure telemetry read; never writes into a project.
6
+ */
7
+ export declare function collectSessions(settings: ImproveSettings, watermark: Watermark): Promise<{
8
+ sessions: SessionRecord[];
9
+ nextWatermark: Watermark;
10
+ }>;
11
+ /**
12
+ * Whether a run experienced an integration conflict at ANY point, not just one
13
+ * still unresolved at collect time. `status`/`merge.status` are LIVE state:
14
+ * once a resolver or re-merge succeeds they are rewritten to merged, which is
15
+ * why counting them alone reported mergeConflictRate 0 while resolver-labeled
16
+ * sessions were everywhere. Reads, in order of reliability: the durable
17
+ * `hadMergeConflict` marker, the live conflict state, `resolverFor` (the
18
+ * daemon's resolver runs), and finally the native resolver task labels, which
19
+ * are the only trace on records written before `hadMergeConflict` existed
20
+ * (formats set in native/src/main.rs start_conflict_resolution_agent).
21
+ */
22
+ export declare function runHadMergeConflict(run: Pick<RunRecord, "status" | "merge" | "sync" | "hadMergeConflict" | "resolverFor" | "task" | "taskSummary">): boolean;
23
+ /**
24
+ * Raw timestamp parse (millis string or ISO), with NO plausibility window.
25
+ * Used for watermark ordering, where the job is a consistent total order over
26
+ * whatever stamps actually exist on disk, not measurement quality. The
27
+ * plausibility-checked parseRunTimestampMs below stays the right tool for
28
+ * durations. This exists because run.json carries two formats (ISO from the
29
+ * TS writers, epoch millis from the native TUI) and the previous LEXICOGRAPHIC
30
+ * comparison ordered every ISO string ("2026-…") above every millis string
31
+ * ("17834…"): one ISO-stamped run would push the watermark somewhere no
32
+ * native-written run could ever exceed, permanently blinding collection to
33
+ * that project's native runs.
34
+ */
35
+ export declare function rawTimestampMs(value: string | number | undefined): number | undefined;
36
+ /** Read a watermark entry, tolerating the legacy string formats (ISO or millis). */
37
+ export declare function watermarkValueMs(value: string | number | undefined): number;
38
+ /**
39
+ * Parse a run timestamp into epoch ms, rejecting implausible values. Run
40
+ * records carry two formats: ISO strings (the TS writers, util.nowIso) and
41
+ * epoch-millisecond strings (the native TUI's now_stamp in
42
+ * native/src/gitio.rs), which Date.parse cannot read. Anything implausible is
43
+ * rejected rather than letting Date.parse guess: native test fixtures once
44
+ * leaked run.json records with the sentinel createdAt "1" into a real
45
+ * .rudder/runs dir, Date.parse("1") is 2001-01-01, and the resulting 25-year
46
+ * durations dominated medianDurationMs for the whole cycle.
47
+ */
48
+ export declare function parseRunTimestampMs(value: string | undefined): number | undefined;
49
+ export declare function computeMetrics(cycleId: string, sessions: SessionRecord[]): MetricsSnapshot;
@@ -0,0 +1,274 @@
1
+ import path from "node:path";
2
+ import { promises as fs } from "node:fs";
3
+ import { loadProjects, runRecordPath, runsDir, verifierPath } from "../state.js";
4
+ import { readJson } from "../util.js";
5
+ import { redactTaskSummarySecrets } from "../task-summary.js";
6
+ const MAX_SESSIONS_PER_PROJECT = 200;
7
+ const MAX_ERROR_EXCERPTS = 3;
8
+ const ERROR_EXCERPT_CHARS = 300;
9
+ const EVENTS_TAIL_BYTES = 64 * 1024;
10
+ /**
11
+ * Walk registered projects and build redacted session records for every run
12
+ * newer than the watermark. Pure telemetry read; never writes into a project.
13
+ */
14
+ export async function collectSessions(settings, watermark) {
15
+ const projects = await loadProjects();
16
+ const sessions = [];
17
+ const nextWatermark = { version: 1, projects: { ...watermark.projects } };
18
+ for (const project of projects) {
19
+ if (!project.repoRoot)
20
+ continue;
21
+ if (settings.excludeProjects.some((pattern) => matchesGlobish(project.repoRoot, pattern))) {
22
+ continue;
23
+ }
24
+ let exists = false;
25
+ try {
26
+ exists = (await fs.stat(project.repoRoot)).isDirectory();
27
+ }
28
+ catch {
29
+ exists = false;
30
+ }
31
+ if (!exists)
32
+ continue;
33
+ const sinceMs = watermarkValueMs(watermark.projects[project.repoRoot]);
34
+ const runs = await readRunsRaw(project.repoRoot);
35
+ const fresh = runs
36
+ .filter((run) => (rawTimestampMs(run.updatedAt) ?? 0) > sinceMs)
37
+ // Skip runs still in flight; their story is not over yet.
38
+ .filter((run) => !["created", "running", "steering", "verifying"].includes(run.status))
39
+ .sort((a, b) => (rawTimestampMs(a.updatedAt) ?? 0) - (rawTimestampMs(b.updatedAt) ?? 0))
40
+ .slice(-MAX_SESSIONS_PER_PROJECT);
41
+ for (const run of fresh) {
42
+ sessions.push(await sessionFromRun(project.name ?? project.slug ?? project.repoRoot, run));
43
+ }
44
+ const newestMs = rawTimestampMs(fresh.at(-1)?.updatedAt);
45
+ if (newestMs !== undefined && newestMs > watermarkValueMs(nextWatermark.projects[project.repoRoot])) {
46
+ nextWatermark.projects[project.repoRoot] = newestMs;
47
+ }
48
+ }
49
+ return { sessions, nextWatermark };
50
+ }
51
+ /**
52
+ * Read run records WITHOUT the state.ts load path: loadRunRecord fires the
53
+ * background LLM task summarizer per record, which both costs model calls and
54
+ * rewrites run.json (bumping updatedAt past the watermark). Telemetry
55
+ * collection must be a pure read.
56
+ */
57
+ async function readRunsRaw(repoRoot) {
58
+ let entries = [];
59
+ try {
60
+ const dirents = await fs.readdir(runsDir(repoRoot), { withFileTypes: true });
61
+ entries = dirents.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ const runs = await Promise.all(entries.map((id) => readJson(runRecordPath(repoRoot, id))));
67
+ return runs.filter((run) => Boolean(run?.id && run?.status && run?.updatedAt));
68
+ }
69
+ /**
70
+ * Whether a run experienced an integration conflict at ANY point, not just one
71
+ * still unresolved at collect time. `status`/`merge.status` are LIVE state:
72
+ * once a resolver or re-merge succeeds they are rewritten to merged, which is
73
+ * why counting them alone reported mergeConflictRate 0 while resolver-labeled
74
+ * sessions were everywhere. Reads, in order of reliability: the durable
75
+ * `hadMergeConflict` marker, the live conflict state, `resolverFor` (the
76
+ * daemon's resolver runs), and finally the native resolver task labels, which
77
+ * are the only trace on records written before `hadMergeConflict` existed
78
+ * (formats set in native/src/main.rs start_conflict_resolution_agent).
79
+ */
80
+ export function runHadMergeConflict(run) {
81
+ if (run.hadMergeConflict)
82
+ return true;
83
+ if (run.status === "merge-conflict")
84
+ return true;
85
+ if (run.merge?.status === "conflict" || run.sync?.status === "conflict")
86
+ return true;
87
+ if (run.resolverFor)
88
+ return true;
89
+ if (/^(?:merge|rebase) conflicts → /.test(run.taskSummary ?? ""))
90
+ return true;
91
+ return /^Resolve (?:merge|rebase) conflicts(?::|$)/.test(run.task ?? "");
92
+ }
93
+ /**
94
+ * Raw timestamp parse (millis string or ISO), with NO plausibility window.
95
+ * Used for watermark ordering, where the job is a consistent total order over
96
+ * whatever stamps actually exist on disk, not measurement quality. The
97
+ * plausibility-checked parseRunTimestampMs below stays the right tool for
98
+ * durations. This exists because run.json carries two formats (ISO from the
99
+ * TS writers, epoch millis from the native TUI) and the previous LEXICOGRAPHIC
100
+ * comparison ordered every ISO string ("2026-…") above every millis string
101
+ * ("17834…"): one ISO-stamped run would push the watermark somewhere no
102
+ * native-written run could ever exceed, permanently blinding collection to
103
+ * that project's native runs.
104
+ */
105
+ export function rawTimestampMs(value) {
106
+ if (value === undefined || value === "")
107
+ return undefined;
108
+ if (typeof value === "number")
109
+ return Number.isFinite(value) ? value : undefined;
110
+ const ms = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
111
+ return Number.isFinite(ms) ? ms : undefined;
112
+ }
113
+ /** Read a watermark entry, tolerating the legacy string formats (ISO or millis). */
114
+ export function watermarkValueMs(value) {
115
+ return rawTimestampMs(value) ?? 0;
116
+ }
117
+ // Timestamps outside [Rudder's existence, now + a day of clock skew] are
118
+ // sentinel or corrupt stamps, not real run times.
119
+ const EARLIEST_PLAUSIBLE_RUN_MS = Date.parse("2024-01-01T00:00:00Z");
120
+ const MAX_CLOCK_SKEW_MS = 24 * 60 * 60 * 1000;
121
+ /**
122
+ * Parse a run timestamp into epoch ms, rejecting implausible values. Run
123
+ * records carry two formats: ISO strings (the TS writers, util.nowIso) and
124
+ * epoch-millisecond strings (the native TUI's now_stamp in
125
+ * native/src/gitio.rs), which Date.parse cannot read. Anything implausible is
126
+ * rejected rather than letting Date.parse guess: native test fixtures once
127
+ * leaked run.json records with the sentinel createdAt "1" into a real
128
+ * .rudder/runs dir, Date.parse("1") is 2001-01-01, and the resulting 25-year
129
+ * durations dominated medianDurationMs for the whole cycle.
130
+ */
131
+ export function parseRunTimestampMs(value) {
132
+ if (!value)
133
+ return undefined;
134
+ const ms = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
135
+ if (!Number.isFinite(ms))
136
+ return undefined;
137
+ if (ms < EARLIEST_PLAUSIBLE_RUN_MS || ms > Date.now() + MAX_CLOCK_SKEW_MS)
138
+ return undefined;
139
+ return ms;
140
+ }
141
+ async function sessionFromRun(project, run) {
142
+ const steerCount = (run.turns ?? []).filter((turn) => turn.source === "steerer" || turn.source === "regoal").length;
143
+ let durationMs;
144
+ const startMs = parseRunTimestampMs(run.process?.startedAt ?? run.createdAt);
145
+ const endMs = parseRunTimestampMs(run.process?.endedAt ?? run.updatedAt);
146
+ if (startMs !== undefined && endMs !== undefined && endMs >= startMs) {
147
+ durationMs = endMs - startMs;
148
+ }
149
+ let verifierSatisfied;
150
+ let verifierMissing;
151
+ const verification = run.verification ??
152
+ (await readJson(verifierPath(run.repoRoot, run.id))) ??
153
+ undefined;
154
+ if (verification && typeof verification.satisfied === "boolean") {
155
+ verifierSatisfied = verification.satisfied;
156
+ verifierMissing = (verification.missing ?? []).slice(0, 5).map(redactAndTrim);
157
+ }
158
+ const hadMergeConflict = runHadMergeConflict(run);
159
+ const interesting = run.status === "failed" ||
160
+ run.status === "cancelled" ||
161
+ hadMergeConflict ||
162
+ verifierSatisfied === false;
163
+ return {
164
+ project,
165
+ repoRoot: run.repoRoot,
166
+ runId: run.id,
167
+ task: redactAndTrim(run.taskSummary ?? run.task ?? "", 160),
168
+ backend: run.backend,
169
+ model: run.model,
170
+ effort: run.effort,
171
+ status: run.status,
172
+ createdAt: run.createdAt,
173
+ updatedAt: run.updatedAt,
174
+ durationMs,
175
+ steerCount,
176
+ autoSteerCount: run.autoSteer?.count ?? 0,
177
+ tokensIn: run.tokens?.input ?? 0,
178
+ tokensOut: run.tokens?.output ?? 0,
179
+ verifierSatisfied,
180
+ verifierMissing,
181
+ mergeStatus: run.merge?.status,
182
+ hadMergeConflict,
183
+ errorExcerpts: interesting ? await readErrorExcerpts(run) : [],
184
+ };
185
+ }
186
+ /**
187
+ * Read the tail of a run's events.ndjson and pull out error-shaped events.
188
+ * Redaction happens here, before anything reaches a model.
189
+ */
190
+ async function readErrorExcerpts(run) {
191
+ const eventsFile = path.join(run.repoRoot, ".rudder", "runs", run.id, "events.ndjson");
192
+ let raw = "";
193
+ try {
194
+ const handle = await fs.open(eventsFile, "r");
195
+ try {
196
+ const stat = await handle.stat();
197
+ const start = Math.max(0, stat.size - EVENTS_TAIL_BYTES);
198
+ const buffer = Buffer.alloc(stat.size - start);
199
+ await handle.read(buffer, 0, buffer.length, start);
200
+ raw = buffer.toString("utf8");
201
+ }
202
+ finally {
203
+ await handle.close();
204
+ }
205
+ }
206
+ catch {
207
+ return [];
208
+ }
209
+ const excerpts = [];
210
+ for (const line of raw.split("\n").reverse()) {
211
+ if (excerpts.length >= MAX_ERROR_EXCERPTS)
212
+ break;
213
+ const trimmed = line.trim();
214
+ if (!trimmed)
215
+ continue;
216
+ let event = null;
217
+ try {
218
+ event = JSON.parse(trimmed);
219
+ }
220
+ catch {
221
+ continue;
222
+ }
223
+ const type = event?.type ?? "";
224
+ if (!/error|fail/i.test(type))
225
+ continue;
226
+ const text = event?.text ?? event?.message ?? "";
227
+ if (!text.trim())
228
+ continue;
229
+ excerpts.push(`[${type}] ${redactAndTrim(text, ERROR_EXCERPT_CHARS)}`);
230
+ }
231
+ return excerpts;
232
+ }
233
+ export function computeMetrics(cycleId, sessions) {
234
+ const n = sessions.length;
235
+ const rate = (count) => (n === 0 ? 0 : round4(count / n));
236
+ const failed = sessions.filter((s) => s.status === "failed").length;
237
+ const cancelled = sessions.filter((s) => s.status === "cancelled").length;
238
+ const conflicts = sessions.filter((s) => s.hadMergeConflict || s.status === "merge-conflict" || s.mergeStatus === "conflict").length;
239
+ const verifierMisses = sessions.filter((s) => s.verifierSatisfied === false).length;
240
+ const steered = sessions.filter((s) => s.steerCount > 0).length;
241
+ const durations = sessions
242
+ .map((s) => s.durationMs)
243
+ .filter((d) => typeof d === "number")
244
+ .sort((a, b) => a - b);
245
+ return {
246
+ ts: new Date().toISOString(),
247
+ cycleId,
248
+ runsSeen: n,
249
+ failedRate: rate(failed),
250
+ cancelledRate: rate(cancelled),
251
+ steerRate: rate(steered),
252
+ mergeConflictRate: rate(conflicts),
253
+ verifierMissRate: rate(verifierMisses),
254
+ medianDurationMs: durations.length ? durations[Math.floor(durations.length / 2)] : 0,
255
+ totalTokensIn: sessions.reduce((sum, s) => sum + s.tokensIn, 0),
256
+ totalTokensOut: sessions.reduce((sum, s) => sum + s.tokensOut, 0),
257
+ };
258
+ }
259
+ function redactAndTrim(value, maxChars = 240) {
260
+ const redacted = redactTaskSummarySecrets(value).replace(/\s+/g, " ").trim();
261
+ return redacted.length > maxChars ? `${redacted.slice(0, maxChars - 1)}…` : redacted;
262
+ }
263
+ function round4(value) {
264
+ return Math.round(value * 10000) / 10000;
265
+ }
266
+ /** Minimal glob support: `*` wildcards only, matched against the repo path. */
267
+ function matchesGlobish(value, pattern) {
268
+ const regex = new RegExp(`^${pattern.split("*").map(escapeRegExp).join(".*")}$`);
269
+ return regex.test(value);
270
+ }
271
+ function escapeRegExp(value) {
272
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
273
+ }
274
+ //# sourceMappingURL=collect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.js","sourceRoot":"","sources":["../../src/improve/collect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Proposal } from "./propose.js";
2
+ export type GateResult = {
3
+ passed: boolean;
4
+ steps: Array<{
5
+ name: string;
6
+ code: number;
7
+ timedOut: boolean;
8
+ failureTail?: string;
9
+ }>;
10
+ };
11
+ /**
12
+ * The repo's own deterministic gates, run inside the proposal worktree before
13
+ * any judge tokens are spent. Order matches AGENTS.md section 11: typecheck,
14
+ * native tests when native/ changed, then the node test suite (which builds).
15
+ */
16
+ export declare function runGates(proposal: Proposal): Promise<GateResult>;
17
+ export declare function gateSummary(gate: GateResult): string;
@@ -0,0 +1,60 @@
1
+ import path from "node:path";
2
+ import { execStep, logsDir, tail } from "./state.js";
3
+ const MINUTE = 60 * 1000;
4
+ /**
5
+ * The repo's own deterministic gates, run inside the proposal worktree before
6
+ * any judge tokens are spent. Order matches AGENTS.md section 11: typecheck,
7
+ * native tests when native/ changed, then the node test suite (which builds).
8
+ */
9
+ export async function runGates(proposal) {
10
+ const logFile = path.join(logsDir(), `${proposal.finding.id}-gates.log`);
11
+ const nativeChanged = proposal.changedFiles.some((file) => file.startsWith("native/"));
12
+ const steps = [
13
+ {
14
+ name: "npm ci",
15
+ command: "npm",
16
+ args: ["ci", "--no-audit", "--no-fund"],
17
+ timeoutMs: 15 * MINUTE,
18
+ },
19
+ { name: "npm run check", command: "npm", args: ["run", "check"], timeoutMs: 10 * MINUTE },
20
+ ...(nativeChanged
21
+ ? [
22
+ {
23
+ name: "cargo test",
24
+ command: "cargo",
25
+ args: ["test", "--manifest-path", "native/Cargo.toml"],
26
+ timeoutMs: 40 * MINUTE,
27
+ },
28
+ ]
29
+ : []),
30
+ { name: "npm test", command: "npm", args: ["test"], timeoutMs: 40 * MINUTE },
31
+ ];
32
+ const result = { passed: true, steps: [] };
33
+ for (const step of steps) {
34
+ const outcome = await execStep({
35
+ command: step.command,
36
+ args: step.args,
37
+ cwd: proposal.worktree,
38
+ timeoutMs: step.timeoutMs,
39
+ logFile,
40
+ });
41
+ const entry = {
42
+ name: step.name,
43
+ code: outcome.code,
44
+ timedOut: outcome.timedOut,
45
+ ...(outcome.code !== 0 ? { failureTail: tail(outcome.output, 4000) } : {}),
46
+ };
47
+ result.steps.push(entry);
48
+ if (outcome.code !== 0) {
49
+ result.passed = false;
50
+ break;
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ export function gateSummary(gate) {
56
+ return gate.steps
57
+ .map((step) => `${step.name}: ${step.code === 0 ? "ok" : step.timedOut ? "TIMEOUT" : `exit ${step.code}`}`)
58
+ .join(", ");
59
+ }
60
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/improve/gate.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQrD,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAkB;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/F,MAAM,KAAK,GAAgF;QACzF;YACE,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC;YACvC,SAAS,EAAE,EAAE,GAAG,MAAM;SACvB;QACD,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,EAAE,GAAG,MAAM,EAAE;QACzF,GAAG,CAAC,aAAa;YACf,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,mBAAmB,CAAC;oBACtD,SAAS,EAAE,EAAE,GAAG,MAAM;iBACvB;aACF;YACH,CAAC,CAAC,EAAE,CAAC;QACP,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,GAAG,MAAM,EAAE;KAC7E,CAAC;IAEF,MAAM,MAAM,GAAe,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;YAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,EAAE,QAAQ,CAAC,QAAQ;YACtB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO;SACR,CAAC,CAAC;QACH,MAAM,KAAK,GAAG;YACZ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3E,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;YACtB,MAAM;QACR,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,OAAO,IAAI,CAAC,KAAK;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;SAC1G,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ type ImproveArgs = {
2
+ args: string[];
3
+ flags: {
4
+ dryRun?: boolean;
5
+ json?: boolean;
6
+ };
7
+ };
8
+ export declare function runImprove(parsed: ImproveArgs): Promise<void>;
9
+ export {};