@orkestrel/scaffold 0.0.107 → 0.0.109

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 (164) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/bench.js +326 -91
  2. package/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +110 -14
  3. package/dist/agents/skills/orkestrel-dispatch/scripts/chain.js +280 -0
  4. package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +188 -26
  5. package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +142 -43
  6. package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +240 -62
  7. package/dist/agents/skills/orkestrel-dispatch/scripts/patch.js +323 -0
  8. package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +169 -32
  9. package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +368 -27
  10. package/dist/agents/skills/orkestrel-falsify/scripts/mutate.js +560 -0
  11. package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +1052 -205
  12. package/dist/agents/skills/orkestrel-harden/scripts/measure.js +361 -0
  13. package/dist/agents/skills/orkestrel-harden/scripts/titles.js +455 -80
  14. package/dist/agents/skills/orkestrel-parallel/scripts/cases.js +327 -0
  15. package/dist/agents/skills/orkestrel-publish/scripts/compare.js +298 -51
  16. package/dist/agents/skills/orkestrel-publish/scripts/pins.js +170 -13
  17. package/dist/agents/skills/orkestrel-publish/scripts/swap.js +956 -191
  18. package/dist/agents/skills/orkestrel-publish/scripts/wave.js +707 -112
  19. package/dist/agents/skills/orkestrel-publish/scripts/window.js +235 -41
  20. package/dist/agents/skills/orkestrel-scout/scripts/map.js +341 -54
  21. package/dist/agents/templates/brief.md +1 -1
  22. package/dist/bin/main.js +51 -46
  23. package/dist/bin/main.js.map +1 -1
  24. package/dist/host/AGENTS.md +26 -20
  25. package/dist/host/agents/orchestration.md +98 -58
  26. package/dist/host/agents/platforms/posix.md +15 -0
  27. package/dist/host/agents/platforms/windows.md +37 -0
  28. package/dist/host/agents/skills/orkestrel-align/SKILL.md +10 -13
  29. package/dist/host/agents/skills/orkestrel-align/references/fleet.md +4 -10
  30. package/dist/host/agents/skills/orkestrel-align/references/integration.md +1 -1
  31. package/dist/host/agents/skills/orkestrel-build/SKILL.md +16 -48
  32. package/dist/host/agents/skills/orkestrel-build/agents/openai.yaml +1 -1
  33. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +19 -16
  34. package/dist/host/agents/skills/orkestrel-debrief/agents/openai.yaml +1 -1
  35. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +15 -28
  36. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +5 -6
  37. package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +12 -14
  38. package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +36 -24
  39. package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +14 -11
  40. package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +366 -75
  41. package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +126 -16
  42. package/dist/host/agents/skills/orkestrel-dispatch/scripts/chain.ts +323 -0
  43. package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +220 -31
  44. package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +176 -33
  45. package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +294 -59
  46. package/dist/host/agents/skills/orkestrel-dispatch/scripts/patch.ts +401 -0
  47. package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +199 -34
  48. package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +428 -27
  49. package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +10 -8
  50. package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +1 -5
  51. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
  52. package/dist/host/agents/skills/orkestrel-falsify/scripts/mutate.ts +701 -0
  53. package/dist/host/agents/skills/orkestrel-harden/SKILL.md +16 -12
  54. package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +23 -81
  55. package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +4 -5
  56. package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -0
  57. package/dist/host/agents/skills/orkestrel-harden/references/document.md +33 -0
  58. package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +6 -3
  59. package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +8 -4
  60. package/dist/host/agents/skills/orkestrel-harden/references/research.md +2 -0
  61. package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +1272 -279
  62. package/dist/host/agents/skills/orkestrel-harden/scripts/measure.ts +425 -0
  63. package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +603 -98
  64. package/dist/host/agents/skills/orkestrel-journey/SKILL.md +75 -98
  65. package/dist/host/agents/skills/orkestrel-journey/references/captures.md +54 -17
  66. package/dist/host/agents/skills/orkestrel-journey/references/decide.md +1 -20
  67. package/dist/host/agents/skills/orkestrel-journey/references/layer.md +21 -31
  68. package/dist/host/agents/skills/orkestrel-journey/references/styles.md +1 -1
  69. package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +91 -30
  70. package/dist/host/agents/skills/orkestrel-parallel/agents/openai.yaml +2 -2
  71. package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +34 -0
  72. package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +29 -0
  73. package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +29 -0
  74. package/dist/host/agents/skills/orkestrel-parallel/references/t3.md +31 -0
  75. package/dist/host/agents/skills/orkestrel-parallel/scripts/cases.ts +389 -0
  76. package/dist/host/agents/skills/orkestrel-polish/SKILL.md +16 -20
  77. package/dist/host/agents/skills/orkestrel-polish/references/capture-harness.md +16 -26
  78. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +12 -26
  79. package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +2 -2
  80. package/dist/host/agents/skills/orkestrel-publish/references/adopt.md +23 -0
  81. package/dist/host/agents/skills/orkestrel-publish/references/release.md +4 -4
  82. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +12 -10
  83. package/dist/host/agents/skills/orkestrel-publish/references/window.md +20 -25
  84. package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +348 -59
  85. package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +202 -22
  86. package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1061 -191
  87. package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +812 -140
  88. package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +280 -38
  89. package/dist/host/agents/skills/orkestrel-scout/SKILL.md +3 -3
  90. package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +428 -70
  91. package/dist/host/agents/templates/brief.md +1 -1
  92. package/dist/host/agents/transports/claude-cli.md +3 -3
  93. package/dist/host/agents/transports/codex.md +3 -8
  94. package/dist/host/agents/transports/cursor.md +2 -3
  95. package/dist/host/claude/AGENTS.md +7 -10
  96. package/dist/host/claude/agents/analyst.md +3 -3
  97. package/dist/host/claude/agents/astra.md +3 -3
  98. package/dist/host/claude/agents/builder.md +1 -1
  99. package/dist/host/claude/agents/checker.md +1 -1
  100. package/dist/host/claude/agents/distiller.md +1 -1
  101. package/dist/host/claude/agents/grok.md +1 -1
  102. package/dist/host/claude/agents/opus.md +2 -2
  103. package/dist/host/claude/agents/orkestrel.md +57 -90
  104. package/dist/host/claude/agents/researcher.md +1 -1
  105. package/dist/host/claude/agents/reviewer.md +4 -0
  106. package/dist/host/claude/agents/scout.md +1 -1
  107. package/dist/host/claude/agents/verifier.md +1 -1
  108. package/dist/host/claude/rules/application.md +14 -21
  109. package/dist/host/claude/rules/architecture.md +34 -44
  110. package/dist/host/claude/rules/browser.md +3 -4
  111. package/dist/host/claude/rules/campaign.md +55 -0
  112. package/dist/host/claude/rules/documentation.md +26 -11
  113. package/dist/host/claude/rules/names.md +9 -4
  114. package/dist/host/claude/rules/patterns.md +6 -7
  115. package/dist/host/claude/rules/portability.md +2 -3
  116. package/dist/host/claude/rules/quality.md +4 -5
  117. package/dist/host/claude/rules/styles.md +2 -2
  118. package/dist/host/claude/rules/tests.md +57 -114
  119. package/dist/host/claude/rules/typescript.md +8 -10
  120. package/dist/host/claude/rules/workspace.md +21 -19
  121. package/dist/host/claude/rules/writing.md +3 -3
  122. package/dist/host/claude/skills/orkestrel-dispatch/SKILL.md +1 -1
  123. package/dist/host/claude/skills/orkestrel-harden/SKILL.md +1 -1
  124. package/dist/host/claude/skills/orkestrel-parallel/SKILL.md +1 -1
  125. package/dist/host/claude/skills/orkestrel-publish/SKILL.md +1 -1
  126. package/dist/host/claude/skills/orkestrel-scout/SKILL.md +1 -1
  127. package/dist/host/codex/agents/analyst.toml +9 -3
  128. package/dist/host/codex/agents/astra.toml +3 -4
  129. package/dist/host/codex/agents/builder.toml +1 -1
  130. package/dist/host/codex/agents/opus.toml +3 -4
  131. package/dist/host/codex/agents/orkestrel.toml +1 -1
  132. package/dist/host/codex/agents/researcher.toml +2 -2
  133. package/dist/host/codex/agents/verifier.toml +1 -1
  134. package/dist/host/codex/config.toml +3 -3
  135. package/dist/host/configs/helpers.ts +21 -1
  136. package/dist/host/configs/policy.ts +405 -16
  137. package/dist/host/cursor/rules/orchestration.mdc +1 -0
  138. package/dist/host/dotfiles/oxlintrc.json +141 -5
  139. package/dist/host/guides/agent.md +111 -134
  140. package/dist/host/guides/capture.md +801 -0
  141. package/dist/host/guides/probe.md +27 -8
  142. package/dist/host/guides/scaffold.md +152 -19
  143. package/dist/host/guides/study.md +534 -440
  144. package/dist/host/guides/test.md +111 -44
  145. package/dist/host/manifest.json +199 -242
  146. package/dist/host/tests/config.test.ts +1558 -219
  147. package/dist/host/tests/policy.test.ts +127 -1
  148. package/dist/host/tests/setupPolicy.ts +1389 -39
  149. package/dist/src/core/index.cjs +239 -87
  150. package/dist/src/core/index.cjs.map +1 -1
  151. package/dist/src/core/index.d.cts +123 -39
  152. package/dist/src/core/index.d.ts +123 -39
  153. package/dist/src/core/index.js +234 -86
  154. package/dist/src/core/index.js.map +1 -1
  155. package/dist/src/server/index.cjs +20 -27
  156. package/dist/src/server/index.cjs.map +1 -1
  157. package/dist/src/server/index.js +21 -28
  158. package/dist/src/server/index.js.map +1 -1
  159. package/package.json +11 -11
  160. package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +0 -283
  161. package/dist/host/agents/skills/orkestrel-dispatch/references/bench.md +0 -25
  162. package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +0 -333
  163. package/dist/host/agents/skills/orkestrel-parallel/references/harnesses.md +0 -19
  164. package/dist/host/guides/supervisor.md +0 -4890
@@ -9,43 +9,174 @@
9
9
  // launch.ts wrote (`exit`, `capped`, `durationMs`) and the journal's `bytes`, `ageMs`, and last
10
10
  // event, which is the liveness reading for a run still going. The answer is written to --out when
11
11
  // given, and a journal with no session or answer exits 3 so a driver cannot pass off an empty lane.
12
- import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
12
+ // Name one mode per run; the script refuses a flag it does not read, the `--flag=value` form
13
+ // included. Exit 0 when the lane answered, 3 when it carries no session or answer, 64 on usage.
14
+ import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs'
13
15
  import { dirname } from 'node:path'
14
- import { readMissingFlags, readNumber, readOption, readString } from './helpers.ts'
15
16
 
16
- interface Reading {
17
+ /** Lists the flags that each select one journal reader. */
18
+ export const MODE_FLAGS: readonly string[] = ['--cursor', '--claude', '--codex']
19
+
20
+ /** Lists the flags that take a value. */
21
+ export const VALUE_FLAGS: readonly string[] = [...MODE_FLAGS, '--out']
22
+
23
+ /** Lists every flag the script reads, value flags and switches alike. */
24
+ export const FLAGS: readonly string[] = VALUE_FLAGS
25
+
26
+ /** Holds the usage line printed when a call names no journal or two modes. */
27
+ export const USAGE =
28
+ 'usage: result.ts (--cursor JOURNAL | --claude JOURNAL | --codex JOURNAL) [--out PATH]; name one mode'
29
+
30
+ /** Describes what a journal's events say: the session, the answer, and the run's duration. */
31
+ export interface SessionResult {
17
32
  readonly session: string | undefined
18
33
  readonly answer: string | undefined
19
34
  readonly durationMs: number | undefined
20
35
  }
21
36
 
22
- interface Errors {
37
+ /** Describes what the sibling errors file says about the run that wrote the journal. */
38
+ export interface Errors {
23
39
  readonly exit: number | undefined
24
40
  readonly capped: boolean | undefined
25
41
  readonly durationMs: number | undefined
26
42
  }
27
43
 
28
- function readEvents(path: string): ReadonlyArray<Record<string, unknown>> {
44
+ /**
45
+ * Reads the value that follows a flag.
46
+ *
47
+ * @remarks
48
+ * The first occurrence of a flag wins, a following value that opens with `--` is a missing value,
49
+ * and the `--flag=value` form is not read.
50
+ *
51
+ * @param argv - The arguments after the script path.
52
+ * @param name - The flag, such as `--out`.
53
+ * @returns The value after the flag, or undefined when the flag is absent, last, or followed by
54
+ * another flag.
55
+ */
56
+ export function readOption(argv: readonly string[], name: string): string | undefined {
57
+ const index = argv.indexOf(name)
58
+ const value = index === -1 ? undefined : argv[index + 1]
59
+ return value === undefined || value.startsWith('--') ? undefined : value
60
+ }
61
+
62
+ /**
63
+ * Names the value flags a caller gave with no value.
64
+ *
65
+ * @param argv - The arguments after the script path.
66
+ * @param names - The flags that take a value.
67
+ * @returns Each named flag that appears last or is followed by another flag, in argument order.
68
+ */
69
+ export function readMissingFlags(
70
+ argv: readonly string[],
71
+ names: readonly string[],
72
+ ): readonly string[] {
73
+ return names.filter((name) => argv.includes(name) && readOption(argv, name) === undefined)
74
+ }
75
+
76
+ /**
77
+ * Names the flags a caller gave that the script does not read.
78
+ *
79
+ * @remarks
80
+ * A `--flag=value` argument is unknown, because the script reads no such form. A bare `--` ends the
81
+ * scan.
82
+ *
83
+ * @param argv - The arguments after the script path.
84
+ * @param flags - Every flag the script reads, value flags and switches alike.
85
+ * @returns Each argument that opens with `--` and is not a read flag, in argument order.
86
+ */
87
+ export function readUnknownFlags(
88
+ argv: readonly string[],
89
+ flags: readonly string[],
90
+ ): readonly string[] {
91
+ const end = argv.indexOf('--')
92
+ return (end === -1 ? argv : argv.slice(0, end)).filter(
93
+ (argument) => argument.startsWith('--') && !flags.includes(argument),
94
+ )
95
+ }
96
+
97
+ /**
98
+ * Reads the last non-empty line of a text as a JSON object.
99
+ *
100
+ * @param text - Text whose last line is JSON, such as one journal line.
101
+ * @returns The parsed object, or undefined when the last line is not a JSON object.
102
+ */
103
+ export function parseJsonLine(text: string): Record<string, unknown> | undefined {
104
+ const line = text
105
+ .split(/\r\n|\n/)
106
+ .filter((candidate) => candidate.trim() !== '')
107
+ .at(-1)
108
+ if (line === undefined) return undefined
109
+ try {
110
+ const parsed: unknown = JSON.parse(line)
111
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
112
+ return Object.fromEntries(Object.entries(parsed))
113
+ }
114
+ } catch {}
115
+ return undefined
116
+ }
117
+
118
+ /**
119
+ * Reads a string member of a record.
120
+ *
121
+ * @param record - The record, or undefined.
122
+ * @param key - The member name.
123
+ * @returns The string, or undefined when the member is absent or not a string.
124
+ */
125
+ export function readString(
126
+ record: Record<string, unknown> | undefined,
127
+ key: string,
128
+ ): string | undefined {
129
+ const value = record?.[key]
130
+ return typeof value === 'string' ? value : undefined
131
+ }
132
+
133
+ /**
134
+ * Reads a finite number member of a record.
135
+ *
136
+ * @param record - The record, or undefined.
137
+ * @param key - The member name.
138
+ * @returns The number, or undefined when the member is absent, not a number, or not finite.
139
+ */
140
+ export function readNumber(
141
+ record: Record<string, unknown> | undefined,
142
+ key: string,
143
+ ): number | undefined {
144
+ const value = record?.[key]
145
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined
146
+ }
147
+
148
+ /**
149
+ * Reads every JSON object line of a journal.
150
+ *
151
+ * @param path - The journal file.
152
+ * @returns Each line that parses as a JSON object, in order; a blank or malformed line is skipped.
153
+ */
154
+ export function readEvents(path: string): ReadonlyArray<Record<string, unknown>> {
29
155
  return readFileSync(path, 'utf8')
30
156
  .split(/\r\n|\n/)
31
157
  .flatMap((line) => {
32
- if (line.trim() === '') return []
33
- try {
34
- const parsed: unknown = JSON.parse(line)
35
- return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
36
- ? [Object.fromEntries(Object.entries(parsed))]
37
- : []
38
- } catch {
39
- return []
40
- }
158
+ const event = parseJsonLine(line)
159
+ return event === undefined ? [] : [event]
41
160
  })
42
161
  }
43
162
 
44
- function readAnswer(text: string | undefined): string | undefined {
163
+ /**
164
+ * Reads an answer text as present only when it carries something besides whitespace.
165
+ *
166
+ * @param text - The answer text, or undefined.
167
+ * @returns The text unchanged, or undefined when it is absent or blank.
168
+ */
169
+ export function readAnswer(text: string | undefined): string | undefined {
45
170
  return text === undefined || text.trim() === '' ? undefined : text
46
171
  }
47
172
 
48
- function readStream(events: ReadonlyArray<Record<string, unknown>>): Reading {
173
+ /**
174
+ * Reads a Cursor or Claude stream journal's events.
175
+ *
176
+ * @param events - The journal's events.
177
+ * @returns The session from the `init` event and the answer and duration from the `result` event.
178
+ */
179
+ export function readStream(events: ReadonlyArray<Record<string, unknown>>): SessionResult {
49
180
  const init = events.find((event) => event.type === 'system' && event.subtype === 'init')
50
181
  const result = events.find((event) => event.type === 'result')
51
182
  return {
@@ -55,7 +186,17 @@ function readStream(events: ReadonlyArray<Record<string, unknown>>): Reading {
55
186
  }
56
187
  }
57
188
 
58
- function readCodex(path: string, events: ReadonlyArray<Record<string, unknown>>): Reading {
189
+ /**
190
+ * Reads a Codex journal's events and its sibling last-message file.
191
+ *
192
+ * @param path - The journal path; the answer sits beside it in `<name>-last.md`.
193
+ * @param events - The journal's events.
194
+ * @returns The thread id from the `thread.started` event and the answer from the last-message file.
195
+ */
196
+ export function readCodex(
197
+ path: string,
198
+ events: ReadonlyArray<Record<string, unknown>>,
199
+ ): SessionResult {
59
200
  const started = events.find((event) => event.type === 'thread.started')
60
201
  const last = path.replace(/\.jsonl$/u, '-last.md')
61
202
  return {
@@ -65,7 +206,14 @@ function readCodex(path: string, events: ReadonlyArray<Record<string, unknown>>)
65
206
  }
66
207
  }
67
208
 
68
- function readErrors(path: string): Errors {
209
+ /**
210
+ * Reads the exit trailer launch.ts wrote to the errors file beside a journal.
211
+ *
212
+ * @param path - The journal path; the trailer sits beside it in `<name>.err`.
213
+ * @returns The exit code, whether the run was capped, and its duration; each is undefined when the
214
+ * file is absent or carries no trailer.
215
+ */
216
+ export function readErrors(path: string): Errors {
69
217
  const errors = path.replace(/\.jsonl$/u, '.err')
70
218
  if (!existsSync(errors)) return { exit: undefined, capped: undefined, durationMs: undefined }
71
219
  const match = readFileSync(errors, 'utf8').match(
@@ -80,52 +228,69 @@ function readErrors(path: string): Errors {
80
228
  }
81
229
  }
82
230
 
83
- function describeEvent(event: Record<string, unknown> | undefined): string | undefined {
231
+ /**
232
+ * Describes an event by its type and subtype.
233
+ *
234
+ * @param event - The event, or undefined.
235
+ * @returns `type` or `type/subtype`, or undefined when there is no event.
236
+ */
237
+ export function describeEvent(event: Record<string, unknown> | undefined): string | undefined {
84
238
  if (event === undefined) return undefined
85
239
  const type = readString(event, 'type')
86
240
  const subtype = readString(event, 'subtype')
87
241
  return subtype === undefined ? type : `${type}/${subtype}`
88
242
  }
89
243
 
90
- function main(argv: readonly string[]): number {
91
- const missing = readMissingFlags(argv, ['--cursor', '--claude', '--codex', '--out'])
244
+ /**
245
+ * Runs the script on its arguments.
246
+ *
247
+ * @param argv - The arguments after the script path.
248
+ * @returns The exit code: 0 when the lane answered, 3 when it carries no session or answer, 64 on usage.
249
+ */
250
+ export function main(argv: readonly string[]): number {
251
+ const unknown = readUnknownFlags(argv, FLAGS)
252
+ if (unknown.length > 0) {
253
+ console.error(`result: ${unknown.join(', ')} is not a flag this script reads; ${USAGE}`)
254
+ return 64
255
+ }
256
+ const missing = readMissingFlags(argv, VALUE_FLAGS)
92
257
  if (missing.length > 0) {
93
258
  console.error(`result: ${missing.join(', ')} given with no value`)
94
259
  return 64
95
260
  }
96
- const modes = ['--cursor', '--claude', '--codex'].filter((flag) => argv.includes(flag))
261
+ const modes = MODE_FLAGS.filter((flag) => argv.includes(flag))
97
262
  const mode = modes[0]
98
263
  const path = mode === undefined ? undefined : readOption(argv, mode)
99
264
  const out = readOption(argv, '--out')
100
265
  if (modes.length !== 1 || mode === undefined || path === undefined || !existsSync(path)) {
101
- console.error(
102
- 'usage: result.ts (--cursor JOURNAL | --claude JOURNAL | --codex JOURNAL) [--out PATH]; name one mode',
103
- )
266
+ console.error(USAGE)
104
267
  return 64
105
268
  }
106
269
  const events = readEvents(path)
107
- const reading = mode === '--codex' ? readCodex(path, events) : readStream(events)
270
+ const result = mode === '--codex' ? readCodex(path, events) : readStream(events)
108
271
  const errors = readErrors(path)
109
272
  const stat = statSync(path)
110
- if (reading.answer !== undefined && out !== undefined) {
273
+ if (result.answer !== undefined && out !== undefined) {
111
274
  mkdirSync(dirname(out), { recursive: true })
112
- writeFileSync(out, reading.answer)
275
+ writeFileSync(out, result.answer)
113
276
  }
114
277
  console.log(
115
278
  JSON.stringify({
116
279
  journal: path,
117
- session: reading.session,
118
- durationMs: reading.durationMs ?? errors.durationMs,
280
+ session: result.session,
281
+ durationMs: result.durationMs ?? errors.durationMs,
119
282
  exit: errors.exit,
120
283
  capped: errors.capped,
121
284
  bytes: stat.size,
122
285
  ageMs: Math.max(0, Math.round(Date.now() - stat.mtimeMs)),
123
286
  lastEvent: describeEvent(events.at(-1)),
124
- answerLength: reading.answer?.length ?? 0,
125
- out: reading.answer === undefined ? undefined : out,
287
+ answerLength: result.answer?.length ?? 0,
288
+ out: result.answer === undefined ? undefined : out,
126
289
  }),
127
290
  )
128
- return reading.session === undefined || reading.answer === undefined ? 3 : 0
291
+ return result.session === undefined || result.answer === undefined ? 3 : 0
129
292
  }
130
293
 
131
- process.exitCode = main(process.argv.slice(2))
294
+ if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
295
+ process.exitCode = main(process.argv.slice(2))
296
+ }