catherd-cli 0.2.1 → 1.0.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 (187) hide show
  1. package/README.md +114 -30
  2. package/THIRD_PARTY_NOTICES.md +37 -0
  3. package/catalog/jev.json +89 -0
  4. package/catalog/models.json +236 -0
  5. package/catalog/scores.json +366 -0
  6. package/package.json +24 -8
  7. package/plugin/.claude-plugin/plugin.json +2 -2
  8. package/plugin/.mcp.json +1 -1
  9. package/plugin/commands/catherd.md +1 -1
  10. package/plugin/skills/catherd/SKILL.md +97 -51
  11. package/plugin/skills/catherd-setup/SKILL.md +34 -24
  12. package/src/adapters/all.ts +8 -0
  13. package/src/adapters/backend.ts +144 -0
  14. package/src/adapters/claude-code/events.ts +86 -0
  15. package/src/adapters/claude-code/index.ts +223 -0
  16. package/src/adapters/claude-code/models-api.ts +65 -0
  17. package/src/adapters/claude-code/models.ts +26 -0
  18. package/src/adapters/cli.ts +74 -0
  19. package/src/adapters/codex/events.ts +65 -0
  20. package/src/adapters/codex/home.ts +47 -0
  21. package/src/adapters/codex/index.ts +227 -0
  22. package/src/adapters/discovery.ts +87 -0
  23. package/src/adapters/opencode/agents.ts +84 -0
  24. package/src/adapters/opencode/events.ts +109 -0
  25. package/src/adapters/opencode/index.ts +316 -0
  26. package/src/adapters/registry.ts +14 -0
  27. package/src/cli.ts +159 -19
  28. package/src/domain/agents.ts +60 -0
  29. package/src/domain/budget.ts +45 -0
  30. package/src/domain/catalog.ts +262 -0
  31. package/src/domain/changes.ts +52 -0
  32. package/src/domain/cost.ts +89 -0
  33. package/src/domain/errors.ts +58 -0
  34. package/src/domain/hints.ts +22 -0
  35. package/src/domain/ids.ts +97 -0
  36. package/src/domain/jev.ts +283 -0
  37. package/src/domain/lane.ts +69 -0
  38. package/src/domain/profile-rules.ts +205 -0
  39. package/src/domain/profile.ts +383 -0
  40. package/src/domain/record.ts +84 -0
  41. package/src/{profile → domain}/role-prompts.ts +42 -26
  42. package/src/domain/roles.ts +25 -0
  43. package/src/domain/route.ts +126 -0
  44. package/src/domain/runtime.ts +21 -0
  45. package/src/domain/sanitize.ts +29 -0
  46. package/src/domain/secrets.ts +57 -0
  47. package/src/domain/select.ts +136 -0
  48. package/src/domain/state.ts +33 -0
  49. package/src/domain/util.ts +18 -0
  50. package/src/entry/capture-fixtures-command.ts +57 -0
  51. package/src/entry/catalog-command.ts +106 -0
  52. package/src/entry/cli-kit.ts +36 -0
  53. package/src/entry/deps.ts +16 -0
  54. package/src/entry/doctor-command.ts +45 -0
  55. package/src/entry/glyphs.ts +33 -0
  56. package/src/entry/init-command.ts +142 -0
  57. package/src/entry/lock-command.ts +123 -0
  58. package/src/entry/mcp/dispatch-tools.ts +82 -0
  59. package/src/entry/mcp/handshake.ts +48 -0
  60. package/src/entry/mcp/lane-tools.ts +83 -0
  61. package/src/entry/mcp/result.ts +51 -0
  62. package/src/entry/mcp/run-tools.ts +144 -0
  63. package/src/entry/mcp/server.ts +72 -0
  64. package/src/entry/mcp/setup-tools.ts +81 -0
  65. package/src/entry/profile-command.ts +320 -0
  66. package/src/entry/prompt.ts +103 -0
  67. package/src/entry/runs-command.ts +217 -0
  68. package/src/entry/supervise-bin.ts +18 -0
  69. package/src/entry/supervise-command.ts +37 -0
  70. package/src/entry/tui/commands.ts +545 -0
  71. package/src/entry/tui/effects.ts +270 -0
  72. package/src/entry/tui/fixtures.ts +318 -0
  73. package/src/entry/tui/profile-edits.ts +138 -0
  74. package/src/entry/tui/profile-tree.ts +419 -0
  75. package/src/entry/tui/providers/app.tsx +162 -0
  76. package/src/entry/tui/providers/boundary.tsx +57 -0
  77. package/src/entry/tui/providers/data.tsx +133 -0
  78. package/src/entry/tui/providers/keymap.tsx +166 -0
  79. package/src/entry/tui/providers/root.tsx +45 -0
  80. package/src/entry/tui/providers/theme.tsx +17 -0
  81. package/src/entry/tui/providers/toast.tsx +77 -0
  82. package/src/entry/tui/run.tsx +98 -0
  83. package/src/entry/tui/state.ts +336 -0
  84. package/src/entry/tui/stories.ts +75 -0
  85. package/src/entry/tui/text.ts +118 -0
  86. package/src/entry/tui/theme.ts +139 -0
  87. package/src/entry/tui/views/app.tsx +208 -0
  88. package/src/entry/tui/views/dialogs.tsx +41 -0
  89. package/src/entry/tui/views/profile-actions.ts +321 -0
  90. package/src/entry/tui/views/profiles.tsx +440 -0
  91. package/src/entry/tui/views/runs.tsx +281 -0
  92. package/src/entry/tui/views/save-dialog.tsx +332 -0
  93. package/src/entry/tui/views/status.tsx +206 -0
  94. package/src/entry/tui/widgets/chrome.tsx +114 -0
  95. package/src/entry/tui/widgets/dialog-confirm.tsx +58 -0
  96. package/src/entry/tui/widgets/dialog-prompt.tsx +52 -0
  97. package/src/entry/tui/widgets/dialog-select.tsx +212 -0
  98. package/src/entry/tui/widgets/dialog.tsx +68 -0
  99. package/src/entry/tui/widgets/line.tsx +92 -0
  100. package/src/entry/tui/widgets/list.tsx +196 -0
  101. package/src/entry/tui/widgets/spinner.tsx +49 -0
  102. package/src/entry/tui/widgets/toast.tsx +62 -0
  103. package/src/infra/assets.ts +4 -0
  104. package/src/infra/dispatch-dir.ts +278 -0
  105. package/src/infra/env.ts +43 -0
  106. package/src/infra/filelock.ts +159 -0
  107. package/src/infra/git.ts +91 -0
  108. package/src/infra/heavy-lock.ts +36 -0
  109. package/src/infra/jev-client.ts +162 -0
  110. package/src/infra/launch.ts +25 -0
  111. package/src/infra/log.ts +84 -0
  112. package/src/infra/paths.ts +38 -0
  113. package/src/infra/proc.ts +110 -0
  114. package/src/infra/store.ts +229 -0
  115. package/src/infra/supervisor.ts +257 -0
  116. package/src/infra/version.ts +6 -0
  117. package/src/services/admission.ts +277 -0
  118. package/src/services/agent-links.ts +139 -0
  119. package/src/services/backends.ts +44 -0
  120. package/src/services/budget.ts +47 -0
  121. package/src/services/capture.ts +233 -0
  122. package/src/services/catalog-service.ts +382 -0
  123. package/src/services/dispatch-service.ts +479 -0
  124. package/src/services/dispatches.ts +145 -0
  125. package/src/services/doctor-backends.ts +185 -0
  126. package/src/services/doctor-checks.ts +103 -0
  127. package/src/services/doctor.ts +358 -0
  128. package/src/services/finalize.ts +359 -0
  129. package/src/services/jev-service.ts +183 -0
  130. package/src/services/lane-service.ts +248 -0
  131. package/src/services/ports.ts +132 -0
  132. package/src/services/preflight.ts +207 -0
  133. package/src/services/profile-service.ts +292 -0
  134. package/src/services/profile-store.ts +141 -0
  135. package/src/services/reconcile.ts +101 -0
  136. package/src/services/routing-service.ts +190 -0
  137. package/src/services/run-debug.ts +79 -0
  138. package/src/services/run-service.ts +161 -0
  139. package/src/services/run-store.ts +316 -0
  140. package/src/services/setup.ts +87 -0
  141. package/src/services/state.ts +104 -0
  142. package/src/services/summary.ts +227 -0
  143. package/catalog/catalog.json +0 -112
  144. package/catalog/models-dev.json +0 -56453
  145. package/src/core/codex-events.ts +0 -49
  146. package/src/core/codex.ts +0 -166
  147. package/src/core/harness.ts +0 -89
  148. package/src/core/lanes.ts +0 -67
  149. package/src/core/lock.ts +0 -111
  150. package/src/core/opencode.ts +0 -207
  151. package/src/core/reconcile.ts +0 -26
  152. package/src/core/reply.ts +0 -54
  153. package/src/core/runstore.ts +0 -163
  154. package/src/core/spawn.ts +0 -89
  155. package/src/core/status.ts +0 -193
  156. package/src/files.ts +0 -19
  157. package/src/mcp/dispatch.ts +0 -154
  158. package/src/mcp/lane-tools.ts +0 -200
  159. package/src/mcp/out.ts +0 -6
  160. package/src/mcp/preflight.ts +0 -84
  161. package/src/mcp/run-tools.ts +0 -121
  162. package/src/mcp/runs.ts +0 -118
  163. package/src/mcp/server.ts +0 -26
  164. package/src/mcp/setup-tools.ts +0 -175
  165. package/src/paths.ts +0 -20
  166. package/src/profile/agents.ts +0 -130
  167. package/src/profile/profile.ts +0 -228
  168. package/src/routing/catalog.ts +0 -227
  169. package/src/routing/commands.ts +0 -22
  170. package/src/routing/jev.ts +0 -185
  171. package/src/routing/route.ts +0 -155
  172. package/src/routing/select.ts +0 -90
  173. package/src/tui/backends.ts +0 -57
  174. package/src/tui/commands.ts +0 -53
  175. package/src/tui/dashboard.tsx +0 -245
  176. package/src/tui/editor.tsx +0 -214
  177. package/src/tui/init.tsx +0 -208
  178. package/src/tui/matrix-model.ts +0 -279
  179. package/src/tui/matrix.tsx +0 -512
  180. package/src/tui/profiles.ts +0 -38
  181. package/src/tui/theme.ts +0 -177
  182. package/src/tui/ui.tsx +0 -267
  183. package/src/tui/watch-model.ts +0 -83
  184. package/src/tui/watch.tsx +0 -236
  185. package/src/types.ts +0 -184
  186. package/src/version.ts +0 -7
  187. /package/src/{mcp/commands.ts → entry/mcp/command.ts} +0 -0
package/src/tui/watch.tsx DELETED
@@ -1,236 +0,0 @@
1
- import { join } from "node:path";
2
- import { TextAttributes } from "@opentui/core";
3
- import { useKeyboard, useRenderer } from "@opentui/react";
4
- import { useEffect, useRef, useState } from "react";
5
- import { type BudgetStatus, formatBudget, type RunSummary, summarizeRun } from "../core/status.ts";
6
- import { listRuns, readJsonl, readRunRecords, type Run } from "../core/runstore.ts";
7
- import type { RunRecord, RungId } from "../types.ts";
8
- import { face, glyph, tint, type Ui } from "./theme.ts";
9
- import { CatSpinner, DetailPane, Frame, gradientLetters, ListLine } from "./ui.tsx";
10
- import {
11
- budgetTone,
12
- climbs,
13
- jevLine,
14
- type JevLine,
15
- liveLine,
16
- plainBudgetBar,
17
- runLine,
18
- } from "./watch-model.ts";
19
-
20
- export interface WatchDeps {
21
- listRuns: () => Run[];
22
- summarizeRun: (run: Run) => RunSummary;
23
- readRunRecords: (dir: string) => RunRecord[];
24
- readJev: (dir: string) => JevLine[];
25
- }
26
-
27
- const watchDeps: WatchDeps = {
28
- listRuns,
29
- summarizeRun,
30
- readRunRecords,
31
- readJev: (dir) => readJsonl<JevLine>(join(dir, "jev.jsonl")),
32
- };
33
-
34
- // ponytail: only the 20 newest runs are summarized each poll; add paging when someone keeps more than that live
35
- const MAX_RUNS = 20;
36
- const LEFT_HEIGHT = 12;
37
-
38
- interface Item {
39
- run: Run;
40
- summary: RunSummary | null;
41
- error: string | null;
42
- }
43
-
44
- function poll(d: WatchDeps): { items: Item[]; problem: string | null } {
45
- try {
46
- const items = d
47
- .listRuns()
48
- .slice(0, MAX_RUNS)
49
- .map((run): Item => {
50
- try {
51
- return { run, summary: d.summarizeRun(run), error: null };
52
- } catch (e) {
53
- return { run, summary: null, error: (e as Error).message };
54
- }
55
- });
56
- return { items, problem: null };
57
- } catch (e) {
58
- return { items: [], problem: (e as Error).message };
59
- }
60
- }
61
-
62
- /** spec §11b: a bar in the ginger-to-pink gradient, solid ginger from 80% spent and solid pink once
63
- * the budget is exhausted (the palette has no dedicated warning/error tones, see watch-model.ts). */
64
- function BudgetBar({ ui, budget }: { ui: Ui; budget: BudgetStatus }) {
65
- const width = 10;
66
- if (ui.plain) {
67
- return (
68
- <text
69
- wrapMode="none"
70
- truncate
71
- >{`${plainBudgetBar(budget.fraction, width)} ${formatBudget(budget)}`}</text>
72
- );
73
- }
74
- const filled = Math.round(Math.max(0, Math.min(1, budget.fraction)) * width);
75
- const tone = budgetTone(budget.fraction);
76
- const solid =
77
- tone === "error" ? tint("pink", ui.depth) : tone === "warning" ? tint("ginger", ui.depth) : null;
78
- const cells = solid
79
- ? Array.from({ length: filled }, () => ({ ch: "█", fg: solid }))
80
- : gradientLetters("█".repeat(filled));
81
- return (
82
- <text wrapMode="none" truncate>
83
- {cells.map((cell, i) => (
84
- // biome-ignore lint: index key is stable, the bar never reorders
85
- <span key={i} fg={cell.fg}>
86
- {cell.ch}
87
- </span>
88
- ))}
89
- <span attributes={TextAttributes.DIM}>{"░".repeat(width - filled)}</span>
90
- {` ${formatBudget(budget)}`}
91
- </text>
92
- );
93
- }
94
-
95
- /** The right pane for the highlighted run: its live lanes, recent climbs, Jev decisions and the
96
- * budget bar — the run's records and raw state text stay out (they were noise, spec §item 4). */
97
- function RunDetail({ ui, it, climbed, deps }: { ui: Ui; it: Item; climbed: string[]; deps: WatchDeps }) {
98
- const pink = tint("pink", ui.depth);
99
- if (!it.summary) {
100
- return (
101
- <DetailPane ui={ui} title={it.run.id} subtitle="unreadable">
102
- <text fg={pink} wrapMode="none" truncate>
103
- {`${face("failed", ui.plain)} ${it.error}`}
104
- </text>
105
- </DetailPane>
106
- );
107
- }
108
- const s = it.summary;
109
- const jev = deps.readJev(it.run.dir);
110
- return (
111
- <DetailPane ui={ui} title={s.title} subtitle={it.run.meta.repo}>
112
- {s.live.length > 0 ? (
113
- s.live.map((l) => (
114
- <text key={l.name} wrapMode="none" truncate>
115
- {liveLine(l, ui.plain)}
116
- </text>
117
- ))
118
- ) : (
119
- <text attributes={TextAttributes.DIM}>no lane is running right now</text>
120
- )}
121
- {climbed.length > 0 ? (
122
- <>
123
- <text> </text>
124
- {climbed.map((c, i) => (
125
- <text key={`c${i}`} fg={pink} wrapMode="none" truncate>
126
- {c}
127
- </text>
128
- ))}
129
- </>
130
- ) : null}
131
- <text> </text>
132
- <text attributes={TextAttributes.DIM}>
133
- {`jev ${glyph("dot", ui.plain)} ${s.jev.decisions} decisions ${glyph("dot", ui.plain)} ${s.jev.fallbacks} fell back`}
134
- </text>
135
- {jev.slice(-4).map((e, i) => (
136
- <text key={`j${i}`} wrapMode="none" truncate>
137
- {jevLine(e, ui.plain)}
138
- </text>
139
- ))}
140
- {s.budget ? (
141
- <>
142
- <text> </text>
143
- <BudgetBar ui={ui} budget={s.budget} />
144
- </>
145
- ) : null}
146
- </DetailPane>
147
- );
148
- }
149
-
150
- export function Watch({
151
- ui,
152
- deps = {},
153
- intervalMs = 2000,
154
- }: {
155
- ui: Ui;
156
- deps?: Partial<WatchDeps>;
157
- intervalMs?: number;
158
- }) {
159
- const d = { ...watchDeps, ...deps };
160
- const renderer = useRenderer();
161
- const seen = useRef(new Map<string, RungId>());
162
- const [state, setState] = useState<{ items: Item[]; problem: string | null } | null>(null);
163
- const [climbed, setClimbed] = useState<string[]>([]);
164
- const [cursor, setCursor] = useState(0);
165
-
166
- useEffect(() => {
167
- const refresh = () => {
168
- const next = poll(d);
169
- const fresh = next.items.flatMap((it) =>
170
- it.summary ? climbs(seen.current, it.summary, ui.plain) : [],
171
- );
172
- if (fresh.length > 0) setClimbed((c) => [...fresh, ...c].slice(0, 3));
173
- setState(next);
174
- };
175
- refresh();
176
- const t = setInterval(refresh, intervalMs);
177
- return () => clearInterval(t);
178
- }, []);
179
-
180
- const items = state?.items ?? [];
181
- const at = Math.min(cursor, Math.max(0, items.length - 1));
182
- const leftStart = Math.max(0, Math.min(at - Math.floor(LEFT_HEIGHT / 2), items.length - LEFT_HEIGHT));
183
-
184
- useKeyboard((key) => {
185
- if (key.sequence === "q") {
186
- renderer.destroy();
187
- return;
188
- }
189
- if (key.name === "up") setCursor(Math.max(0, at - 1));
190
- else if (key.name === "down") setCursor(Math.min(items.length - 1, at + 1));
191
- });
192
-
193
- const pink = tint("pink", ui.depth);
194
- const title = `Watch ${glyph("dot", ui.plain)} ${items.length} runs`;
195
- const hint = `${glyph("keys", ui.plain)} navigate q quit refreshes every ${intervalMs / 1000} s`;
196
-
197
- if (state?.problem) {
198
- return (
199
- <Frame ui={ui} title={title} hint="q quit">
200
- <text fg={pink} wrapMode="none" truncate>{`${face("failed", ui.plain)} ${state.problem}`}</text>
201
- </Frame>
202
- );
203
- }
204
-
205
- return (
206
- <Frame ui={ui} title={title} hint={hint}>
207
- {state === null ? (
208
- <CatSpinner ui={ui} label="reading the runs" />
209
- ) : items.length === 0 ? (
210
- <text>No runs yet. Start one with /catherd in Claude Code.</text>
211
- ) : (
212
- <box style={{ flexDirection: "row" }}>
213
- <box style={{ flexDirection: "column", width: 24 }}>
214
- <text fg={pink} attributes={TextAttributes.BOLD}>
215
- RUNS
216
- </text>
217
- {items.slice(leftStart, leftStart + LEFT_HEIGHT).map((it, i) => (
218
- <ListLine
219
- key={it.run.dir}
220
- ui={ui}
221
- selected={leftStart + i === at}
222
- dim={!it.summary}
223
- text={
224
- it.summary
225
- ? runLine(it.summary, ui.plain)
226
- : `${face("failed", ui.plain)} ${it.run.id} ${glyph("dot", ui.plain)} unreadable: ${it.error}`
227
- }
228
- />
229
- ))}
230
- </box>
231
- {items[at] ? <RunDetail ui={ui} it={items[at]} climbed={climbed} deps={d} /> : null}
232
- </box>
233
- )}
234
- </Frame>
235
- );
236
- }
package/src/types.ts DELETED
@@ -1,184 +0,0 @@
1
- export const ROLES = [
2
- "architect",
3
- "verifier",
4
- "worker",
5
- "reviewer",
6
- "ui-reviewer",
7
- "artist",
8
- "writer",
9
- "researcher",
10
- ] as const;
11
- export type Role = (typeof ROLES)[number];
12
-
13
- export type Backend = "codex" | "opencode" | "claude";
14
-
15
- /** "<model-id>#<effort>". Model ids may contain "/" (opencode providers); split at the LAST "#". */
16
- export type RungId = string;
17
-
18
- export function splitRung(rung: RungId): { model: string; effort: string } {
19
- const i = rung.lastIndexOf("#");
20
- if (i < 1 || i === rung.length - 1) throw new Error(`catherd: bad rung "${rung}", expected model#effort`);
21
- return { model: rung.slice(0, i), effort: rung.slice(i + 1) };
22
- }
23
-
24
- export const rungOf = (model: string, effort: string): RungId => `${model}#${effort}`;
25
-
26
- export type Sandbox = "read-only" | "workspace-write" | "danger-full-access";
27
-
28
- /** Spec §4: the sandbox a Codex or opencode run of each role gets. */
29
- export const ROLE_SANDBOX: Record<Role, Sandbox> = {
30
- architect: "read-only",
31
- verifier: "danger-full-access",
32
- worker: "workspace-write",
33
- reviewer: "read-only",
34
- "ui-reviewer": "danger-full-access",
35
- artist: "workspace-write",
36
- writer: "workspace-write",
37
- researcher: "read-only",
38
- };
39
-
40
- export interface Capabilities {
41
- toolCall: boolean;
42
- imageIn: boolean;
43
- imageOut: boolean;
44
- reasoning: boolean;
45
- context: number;
46
- }
47
-
48
- /** Spec §4: what a model must have to be offered for a role. */
49
- export const ROLE_NEEDS: Record<Role, Partial<Capabilities>> = {
50
- architect: { toolCall: true },
51
- verifier: { toolCall: true },
52
- worker: { toolCall: true },
53
- reviewer: { toolCall: true },
54
- "ui-reviewer": { toolCall: true, imageIn: true },
55
- artist: { imageOut: true },
56
- writer: { toolCall: true },
57
- researcher: { toolCall: true },
58
- };
59
-
60
- export const KINDS = ["repo_code", "terminal", "ui", "prose", "research"] as const;
61
- export type Kind = (typeof KINDS)[number];
62
-
63
- export const DIFFICULTIES = ["copy", "build", "logic", "hard"] as const;
64
- export type Difficulty = (typeof DIFFICULTIES)[number];
65
-
66
- export type ScoreDim = "repo_code" | "terminal" | "honesty";
67
-
68
- export interface Scores {
69
- repo_code?: number;
70
- terminal?: number;
71
- honesty?: number;
72
- secs_per_task?: number;
73
- }
74
-
75
- export interface CatalogModel {
76
- id: string;
77
- backend: Backend;
78
- efforts: string[];
79
- capabilities: Capabilities;
80
- }
81
-
82
- export interface CatalogEntry {
83
- rung: RungId;
84
- scores: Scores;
85
- costRank: number;
86
- }
87
-
88
- export type Bars = Record<Kind, Record<Difficulty, Partial<Record<ScoreDim, number>>>>;
89
-
90
- export interface Catalog {
91
- version: string;
92
- models: CatalogModel[];
93
- entries: CatalogEntry[];
94
- bars: Bars;
95
- /** unscored rung -> scored rung whose scores it borrows */
96
- treatLike: Record<RungId, RungId>;
97
- }
98
-
99
- export interface RoleConfig {
100
- enabled: boolean;
101
- /** model id -> enabled efforts */
102
- models: Record<string, string[]>;
103
- defaultRung?: RungId;
104
- }
105
-
106
- export type NotifyMoment = "milestone" | "finish" | "blocked";
107
-
108
- /** Spec §8.2: false (the default) runs the vendor harness exactly as the user configured it. */
109
- export interface HarnessConfig {
110
- isolated: boolean;
111
- }
112
-
113
- export interface Profile {
114
- name: string;
115
- objective: "cost" | "speed";
116
- roles: Record<Role, RoleConfig>;
117
- harness: { codex: HarnessConfig; opencode: HarnessConfig };
118
- lock: { heavy: number | "cpus/2" };
119
- notify: NotifyMoment[];
120
- /** spec §11b: a rung's stand-in on another backend, used on a `limit` result */
121
- failover?: Record<RungId, RungId>;
122
- /** spec §11b: the run budget; `status` shows spend against it, `route` and `dispatch` react at 80%/100% */
123
- budget?: { minutes?: number; tokens?: number; usd?: number };
124
- }
125
-
126
- export interface RouteDecision {
127
- kind: Kind | null;
128
- difficulty: Difficulty | null;
129
- confidence: { kind: number | null; difficulty: number | null };
130
- source: "jev" | "default";
131
- rung: RungId;
132
- ladder: RungId[];
133
- }
134
-
135
- export type ReplyStatus = "complete" | "partial" | "blocked" | "refused";
136
- export type RunStatus = "ok" | "failed" | "limit" | "cli-too-old" | "timeout" | "interrupted";
137
-
138
- export interface Tokens {
139
- input: number;
140
- cached: number;
141
- output: number;
142
- }
143
-
144
- /** One Codex or opencode role run. Appended to <run>/runs.jsonl; the only record of it. */
145
- export interface RunRecord {
146
- name: string;
147
- role: Role;
148
- backend: "codex" | "opencode";
149
- rung: RungId;
150
- thread: string | null;
151
- status: RunStatus;
152
- startedAt: string;
153
- secs: number;
154
- pid: number | null;
155
- tokens: Tokens;
156
- costUsd: number | null;
157
- changedOwned: string[];
158
- replyStatus: ReplyStatus | null;
159
- replyWhy: string | null;
160
- threadHeavy: boolean;
161
- /** the harness ran isolated (spec §8.2); lets reports measure what the user's customizations cost */
162
- isolated: boolean;
163
- images: string[];
164
- error: string | null;
165
- replyPath: string;
166
- }
167
-
168
- export interface RunMeta {
169
- id: string;
170
- repo: string;
171
- title: string;
172
- aLines: string[];
173
- createdAt: string;
174
- }
175
-
176
- export interface StateSnapshot {
177
- head: string;
178
- dirty: { path: string; owner: string | null }[];
179
- running: { name: string; rung: RungId; thread: string | null; brief: string; since: string }[];
180
- lastCheck: string | null;
181
- next: string;
182
- }
183
-
184
- export const THREAD_HEAVY_INPUT = 8_000_000;
package/src/version.ts DELETED
@@ -1,7 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
-
3
- const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")) as {
4
- version: string;
5
- };
6
-
7
- export const VERSION: string = pkg.version;
File without changes