@oneharness/sdk 0.3.22

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 ADDED
@@ -0,0 +1,46 @@
1
+ # @oneharness/sdk
2
+
3
+ Typed Node.js access to the `oneharness` engine. The SDK launches the packaged CLI and validates every response with named Zod schemas generated from the Rust wire types. The corresponding TypeScript declarations come from the same Rust JSON Schema bundle.
4
+
5
+ ```ts
6
+ import { OneHarness, RunReportSchema, type RunReport } from "@oneharness/sdk";
7
+
8
+ const oneharness = new OneHarness();
9
+ const report = await oneharness.run({ prompt: "Summarize this repository", harnesses: ["codex"], events: true });
10
+ const checked: RunReport = RunReportSchema.parse(report);
11
+ console.log(checked.results[0]?.text, checked.results[0]?.usage.input_tokens);
12
+ ```
13
+
14
+ `null` usage fields mean the harness did not report the value; zero remains a real measured zero. String-valued harness/model/event identifiers should be treated as open sets for forward compatibility.
15
+
16
+ Named exports include `RunOptionsSchema`, `HistoryLookupSchema`, `HistoryListOptionsSchema`, `RunReportSchema`, `RunResultSchema`, `ActionEventSchema`, `UsageSchema`, `HistoryRecordSchema`, `HistoryRecordsSchema`, `HistoryListSchema`, `HistorySessionSummarySchema`, `ListReportSchema`, `HarnessInfoSchema`, and the registry/detection enum and object schemas. Each schema's `z.infer` type is compile-time checked against its generated TypeScript type.
17
+
18
+ Output objects accept and preserve unknown fields. That deliberate loose-object behavior lets an older SDK validate a newer additive CLI response without erasing fields before an application can inspect them. Known fields are still validated recursively. The input schemas `RunOptionsSchema`, `HistoryLookupSchema`, and `HistoryListOptionsSchema` are deliberately strict instead: unknown input keys are rejected because this SDK version cannot forward an option it does not understand, which also catches misspellings. `run`, `history`, and `historyList` validate against them before reading any option, so an unusable input raises `invalid oneharness run options` / `invalid oneharness history options` / `invalid oneharness history list options` rather than reaching the CLI.
19
+
20
+ Nullable CLI fields remain required object keys: the generated response schemas model Rust's serialization contract, so an unavailable value is `null`, while an omitted guaranteed field is malformed. Optional `RunOptions`, `HistoryLookup`, and `HistoryListOptions` fields may be absent or explicitly `undefined`; every `HistoryListOptions` field is optional, so `historyList()` and `historyList({})` both list the default store.
21
+
22
+ Continuation passes the prior result's native session id with a new user message:
23
+
24
+ ```ts
25
+ const first = await oneharness.run({ prompt: "Inspect the bug", harnesses: ["codex"] });
26
+ const next = await oneharness.run({
27
+ prompt: "Now propose the smallest fix",
28
+ harnesses: ["codex"],
29
+ resume: first.results[0]?.session_id ?? undefined,
30
+ });
31
+ ```
32
+
33
+ Standardized history records and session summaries use their generated schemas too:
34
+
35
+ ```ts
36
+ import { HistoryListSchema, HistoryRecordSchema } from "@oneharness/sdk";
37
+
38
+ const records = await oneharness.history({ last: true });
39
+ const sessions = await oneharness.historyList({ allProjects: true });
40
+ HistoryRecordSchema.parse(records[0]);
41
+ HistoryListSchema.parse(sessions);
42
+ ```
43
+
44
+ `HistoryLookupSchema` states the selector rule itself: a lookup is a union of the only two ways to select a session, so it accepts `last: true` or a non-empty `session` and rejects a lookup that selects neither. `history({})`, `history({ last: false })`, and `history({ session: "" })` fail validation rather than reaching the CLI, and `HistoryLookup` rejects them at compile time too.
45
+
46
+ `last: true` has priority over a name, so `history({ session: "old", last: true })` returns the most recent session and `history({ session: "old", last: false })` returns `old`. The two cases overlap deliberately — the union resolves `last: true` to its last-session variant first — which keeps `last` an ordinary `boolean` beside a named session, so a caller can pass one straight through.
@@ -0,0 +1,421 @@
1
+ /**
2
+ * The normalized, closed set of failure reasons oneharness can classify from a
3
+ * harness's output. It is the single source for the `failure_kind` contract
4
+ * value: serialized as the snake_case token a consumer reads in the report
5
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
6
+ * wire shape is unchanged — modeling it as an enum keeps a misspelled or
7
+ * invalid kind unrepresentable and gives every producer/consumer (classifier,
8
+ * `is_failure`, the fallback fall-through rule, the report, history) one
9
+ * definition to share instead of scattered string literals.
10
+ */
11
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
12
+ /**
13
+ * How a harness emits its result, which decides how `text` is extracted.
14
+ *
15
+ * Also accepted as a CLI value (`--output-format`, parsed in the `oneharness`
16
+ * binary) and a config-file value (`output_format`, via `Deserialize`). The
17
+ * CLI parsing lives in the binary so this core crate stays free of `clap`.
18
+ */
19
+ export type OutputFormat = "text" | "json" | "stream-json";
20
+ /**
21
+ * The outcome of attempting to run one harness.
22
+ */
23
+ export type Status = "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned";
24
+ /**
25
+ * The top-level `run` report written to stdout.
26
+ */
27
+ export interface RunReport {
28
+ /**
29
+ * Same-prefix batch metadata when this run fanned **one** harness over more
30
+ * than one prompt; `null` on an ordinary run. Its presence is the signal a
31
+ * consumer keys on to read each result's own `prompt`.
32
+ */
33
+ batch: BatchReport | null;
34
+ /**
35
+ * Back-compat convenience: `true` exactly when `permission_mode` is
36
+ * `bypass`. Retained so existing consumers keep working; new consumers
37
+ * should read `permission_mode`.
38
+ */
39
+ bypass_permissions: boolean;
40
+ /**
41
+ * Config files that shaped this run, in layering order (user first,
42
+ * project last); empty under `--no-config` or when none exist.
43
+ */
44
+ config_files: string[];
45
+ dry_run: boolean;
46
+ /**
47
+ * Fallback-mode metadata when this run drove the selected harnesses in
48
+ * priority order, stopping at the first that ran (`--run-mode fallback`);
49
+ * `null` on a parallel run (and under `--print-command`, where nothing
50
+ * executes). Its presence tells a consumer that `results` holds only the
51
+ * harnesses actually *attempted* — the fallen-through ones in order, then
52
+ * the one that ran — not every selected harness.
53
+ */
54
+ fallback: FallbackReport | null;
55
+ /**
56
+ * Whether the resumed session was forked (`--fork`) rather than appended to.
57
+ * `false` unless `--resume` was given with `--fork`.
58
+ */
59
+ fork: boolean;
60
+ /**
61
+ * The history session file this run streamed normalized records to
62
+ * (absolute); `null` when history was not enabled (or under `--print-command`,
63
+ * where nothing runs). The programmatic handle a consumer captures to read the
64
+ * session back later with `oneharness history show`.
65
+ */
66
+ history_file: string | null;
67
+ /**
68
+ * The parsed `--mock-rules` ruleset this run was intercepted with; `null`
69
+ * when no mocking was requested. Present so a consumer can tell a mocked
70
+ * run's report from a clean one without out-of-band state.
71
+ */
72
+ mock_rules: unknown;
73
+ /**
74
+ * The effective top-level model: the first of the fan-out `models` list when
75
+ * one was given, else the single configured/CLI model, else `null`. Each
76
+ * result's own `model` is authoritative on a fan-out run.
77
+ */
78
+ model: string | null;
79
+ /**
80
+ * The model fan-out list this run multiplied over (repeated `--model` /
81
+ * config `models`), or `null` on an ordinary single-model run. Its presence
82
+ * is the signal a consumer keys on to read each result's own `model`: in
83
+ * `parallel` mode `results` holds one entry per (harness, model) pair; in
84
+ * `fallback` mode the pairs were tried in priority order (harness-major,
85
+ * model-minor).
86
+ */
87
+ models: string[] | null;
88
+ oneharness_version: string;
89
+ /**
90
+ * The normalized approval mode requested for this run (see the README
91
+ * support matrix). Each harness maps it to its own mechanism.
92
+ */
93
+ permission_mode: "read-only" | "plan" | "default" | "edit" | "auto" | "bypass";
94
+ /**
95
+ * The prompt sent. On an ordinary run this is *the* prompt every result
96
+ * shares; on a **batch** run (see `batch`) it repeats the first prompt for
97
+ * back-compat, and each result's own `prompt` field is authoritative.
98
+ */
99
+ prompt: string;
100
+ results: RunResult[];
101
+ /**
102
+ * The session id being continued, when `--resume` was passed; else `null`.
103
+ */
104
+ resume: string | null;
105
+ /**
106
+ * The JSON Schema applied to this run (structured output), or `null` when
107
+ * none was requested. Echoed so a consumer sees the exact constraint each
108
+ * result was validated against.
109
+ */
110
+ schema: unknown;
111
+ /**
112
+ * Maximum retries allowed per harness under the validate/retry loop; `null`
113
+ * when no schema was requested.
114
+ */
115
+ schema_max_retries: number | null;
116
+ schema_version: string;
117
+ /**
118
+ * The uniform session handle in play (`--session <name>`), or `null` when
119
+ * none was requested. Lets a consumer thread one stable name across turns
120
+ * instead of extracting each harness's native session id. Distinct from the
121
+ * low-level `resume` field above, which echoes an explicit `--resume` id.
122
+ */
123
+ session: SessionReport | null;
124
+ /**
125
+ * The spy-log path the mock hook appended tool-call records to (absolute);
126
+ * `null` when none was requested.
127
+ */
128
+ spy_file: string | null;
129
+ [k: string]: unknown;
130
+ }
131
+ /**
132
+ * Metadata for a same-prefix batch run (one harness, N prompts sharing a
133
+ * cacheable prefix). Present on [`RunReport::batch`] only in that mode.
134
+ */
135
+ export interface BatchReport {
136
+ /**
137
+ * Whether the fan-out actually **forked** the warm-up's session to reuse its
138
+ * cached prefix (`min-tokens` on a fork-capable harness whose warm-up exposed
139
+ * a session id). `false` for `speed`, for `min-tokens` on a harness that
140
+ * cannot fork, or when the warm-up exposed no session to fork. When `true`,
141
+ * the fan-out results' `command` carries the resume/fork flags and their
142
+ * `usage.cache_read_tokens` reflect the reused prefix.
143
+ */
144
+ forked: boolean;
145
+ /**
146
+ * How many prompts were run (equals `results.len()`).
147
+ */
148
+ prompt_count: number;
149
+ /**
150
+ * How the prompts were scheduled across the parallel runner.
151
+ */
152
+ strategy: "speed" | "min-tokens";
153
+ [k: string]: unknown;
154
+ }
155
+ /**
156
+ * Metadata for a fallback run (harnesses tried in priority order until one
157
+ * runs). Present on [`RunReport::fallback`] only in that mode. The per-harness
158
+ * detail lives in `results`; this block summarizes the outcome so a consumer
159
+ * need not re-derive it from statuses.
160
+ */
161
+ export interface FallbackReport {
162
+ /**
163
+ * The candidates fallen through because they could not run the task at all,
164
+ * in priority order, each with why (`not-installed`, `spawn-error`, `auth`,
165
+ * `quota`, and — on a model fan-out — `model-not-found` / `rate-limit`; see
166
+ * [`crate::domain::fallback::startup_failure_reason`]).
167
+ */
168
+ fell_through: FallThrough[];
169
+ /**
170
+ * The harness that actually ran the task (the run stopped there), or `null`
171
+ * when no candidate could run at all — every one was a startup failure.
172
+ */
173
+ ran: string | null;
174
+ [k: string]: unknown;
175
+ }
176
+ /**
177
+ * One candidate a fallback run fell through, with the reason it could not run.
178
+ */
179
+ export interface FallThrough {
180
+ /**
181
+ * Canonical harness id.
182
+ */
183
+ harness: string;
184
+ /**
185
+ * Short reason token (`not-installed` / `spawn-error` / `auth` / `quota` /
186
+ * `model-not-found` / `rate-limit`).
187
+ */
188
+ reason: string;
189
+ [k: string]: unknown;
190
+ }
191
+ /**
192
+ * One harness's entry in the report.
193
+ */
194
+ export interface RunResult {
195
+ /**
196
+ * Whether that binary was found.
197
+ */
198
+ available: boolean;
199
+ /**
200
+ * The binary name or path oneharness resolved and would invoke.
201
+ */
202
+ bin: string;
203
+ /**
204
+ * The exact argv oneharness built (argv[0] is the binary).
205
+ */
206
+ command: string[];
207
+ /**
208
+ * Wall-clock duration of the run; `null` when not executed.
209
+ */
210
+ duration_ms: number | null;
211
+ /**
212
+ * Human-readable problem + suggested action; `null` on success.
213
+ */
214
+ error: string | null;
215
+ /**
216
+ * Best-effort normalized tool-call / action events the harness took (shell
217
+ * commands, file edits, tool uses), in order — so consumers can assert on
218
+ * *behavior*, not just the final `text`. `null` when the harness's output
219
+ * exposes no machine-readable trace (a plain-text harness, or Claude Code's
220
+ * single-document `json` result), distinct from `[]` — an empty array is not
221
+ * currently emitted; absence is signalled by `null` + a null `events_source`.
222
+ * Never fabricated. See [`crate::domain::events`].
223
+ */
224
+ events: ActionEvent[] | null;
225
+ /**
226
+ * How `events` was recovered (e.g. `json:opencode-parts`,
227
+ * `stream-json:content-blocks`), parallel to `text_source`; `null` when no
228
+ * events were found. Lets a consumer tell "harness doesn't support it" from
229
+ * "no tools were used."
230
+ */
231
+ events_source: string | null;
232
+ /**
233
+ * Process exit code; `null` when not run, timed out, or signalled.
234
+ */
235
+ exit_code: number | null;
236
+ /**
237
+ * Best-effort failure reason; `null` when unclassified. Distinct from
238
+ * `status`, which records oneharness's relationship to the process. Two
239
+ * families: coarse reasons for a non-zero run (`auth`, `rate_limit`,
240
+ * `model_not_found`, `quota`), and `tool_deferred` — a run that exited
241
+ * *cleanly* but only deferred a builtin tool call instead of executing it
242
+ * (Claude Code bridge/managed deployments), so it did no useful work. The
243
+ * deferred case is the only `failure_kind` that can appear on a `status: ok`
244
+ * run, and it also marks the run as failed for exit-code purposes.
245
+ * Serialized as its snake_case token (see [`FailureKind`]).
246
+ */
247
+ failure_kind: FailureKind | null;
248
+ /**
249
+ * Where `failure_kind` was read (`stderr`/`stdout`); `null` when absent.
250
+ */
251
+ failure_kind_source: string | null;
252
+ /**
253
+ * Canonical harness id (e.g. `claude-code`).
254
+ */
255
+ harness: string;
256
+ /**
257
+ * The model this result ran with (the value oneharness put on the harness's
258
+ * model flag), or `null` when no model was requested and the harness used its
259
+ * own default. On a **model fan-out** run (`RunReport::models`), this is what
260
+ * distinguishes results that share a harness — each entry is one (harness,
261
+ * model) pair. The model is also visible in `command`; this field surfaces it
262
+ * without parsing the argv.
263
+ */
264
+ model: string | null;
265
+ output_format: OutputFormat;
266
+ /**
267
+ * The prompt this result ran, set only on a **batch** run (one harness
268
+ * fanned over N prompts), where each result has its own prompt. `null` on an
269
+ * ordinary run, where the single top-level `prompt` applies to every result.
270
+ */
271
+ prompt: string | null;
272
+ /**
273
+ * Structured-output run only: how many times this harness was invoked under
274
+ * the validate/retry loop (1 + retries). `null` when no schema was
275
+ * requested or the harness did not run.
276
+ */
277
+ schema_attempts: number | null;
278
+ /**
279
+ * Structured-output run only: the validation errors from the final attempt,
280
+ * joined for display; `null` when valid or no schema was requested.
281
+ */
282
+ schema_error: string | null;
283
+ /**
284
+ * Structured-output run only: whether `structured` conformed to the schema
285
+ * on the final attempt. `null` when no schema was requested (or the harness
286
+ * did not run); `false` when a schema was requested but the result never
287
+ * conformed (including "no JSON found").
288
+ */
289
+ schema_valid: boolean | null;
290
+ /**
291
+ * Best-effort harness session id for continuation; `null` when none is
292
+ * exposed. Surfaced for a consumer to thread into `--resume`, and consumed
293
+ * by oneharness itself when `--session` is in play (it is captured into the
294
+ * session store to back the uniform handle — see [`RunReport::session`]).
295
+ */
296
+ session_id: string | null;
297
+ status: Status;
298
+ /**
299
+ * Raw captured stderr (empty for skipped/planned).
300
+ */
301
+ stderr: string;
302
+ /**
303
+ * Raw captured stdout (empty for skipped/planned).
304
+ */
305
+ stdout: string;
306
+ /**
307
+ * Structured-output run only: the JSON value extracted from the final
308
+ * answer and validated against the requested schema. `null` when no schema
309
+ * was requested, or when no JSON value could be extracted. Carries the
310
+ * last-attempted value even when it failed validation, so a consumer can
311
+ * see what the harness produced.
312
+ */
313
+ structured: unknown;
314
+ /**
315
+ * Best-effort final assistant text; `null` when extraction is impossible.
316
+ */
317
+ text: string | null;
318
+ /**
319
+ * How `text` was extracted (e.g. `json:result`, `raw`); `null` when absent.
320
+ */
321
+ text_source: string | null;
322
+ usage: Usage;
323
+ /**
324
+ * How `usage` was read (e.g. `json`); `null` when nothing was found.
325
+ */
326
+ usage_source: string | null;
327
+ [k: string]: unknown;
328
+ }
329
+ /**
330
+ * One normalized action a harness took, harness-agnostic so a single consumer
331
+ * assertion works across harnesses. Every field is always serialized (null when
332
+ * absent) so the shape is stable, mirroring the `usage` contract.
333
+ */
334
+ export interface ActionEvent {
335
+ /**
336
+ * Position of this event within the run, so "≤ N tool calls" and "did X
337
+ * before Y" are expressible from a stable ordering (also array order).
338
+ */
339
+ index: number;
340
+ /**
341
+ * Structured, tool-shaped arguments (the command string, the file path),
342
+ * so a consumer asserts on specific args without re-parsing; `null` when the
343
+ * event carries none (e.g. a `tool_result`).
344
+ */
345
+ input: unknown;
346
+ /**
347
+ * The kind of event: `tool_call` (the model invoked a tool) or
348
+ * `tool_result` (the observation returned to the model). Left open for
349
+ * future kinds rather than an enum, so a new shape never breaks the field.
350
+ */
351
+ kind: string;
352
+ /**
353
+ * Normalized tool name where knowable (e.g. `bash`, `Edit`); `null` for a
354
+ * `tool_result`, or when the harness did not name the tool.
355
+ */
356
+ name: string | null;
357
+ /**
358
+ * The result/observation text, when the trace exposes it; `null` otherwise.
359
+ */
360
+ output: string | null;
361
+ [k: string]: unknown;
362
+ }
363
+ /**
364
+ * Best-effort token/cost accounting; every field is `null` when the harness
365
+ * does not report it. Always present so consumers can read a stable shape.
366
+ */
367
+ export interface Usage {
368
+ /**
369
+ * Prompt tokens served from the provider's prompt cache (a cheap read of a
370
+ * previously-written prefix), when the harness reports them. `None` when the
371
+ * harness does not surface cache counts — never `0` as a guess.
372
+ */
373
+ cache_read_tokens: number | null;
374
+ /**
375
+ * Prompt tokens written to the provider's prompt cache (a.k.a. cache
376
+ * creation), when the harness reports them. `None` when not surfaced.
377
+ */
378
+ cache_write_tokens: number | null;
379
+ /**
380
+ * Total cost in USD, when the harness reports it (often absent on
381
+ * subscription auth, where there is no per-call dollar figure).
382
+ */
383
+ cost_usd: number | null;
384
+ /**
385
+ * Prompt/input tokens billed, when the harness reports them.
386
+ */
387
+ input_tokens: number | null;
388
+ /**
389
+ * Completion/output tokens billed, when the harness reports them.
390
+ */
391
+ output_tokens: number | null;
392
+ [k: string]: unknown;
393
+ }
394
+ /**
395
+ * The uniform session handle for a run (`--session`). Present on
396
+ * [`RunReport::session`] only when `--session <name>` was requested.
397
+ */
398
+ export interface SessionReport {
399
+ /**
400
+ * The caller's stable handle (`--session <name>`, sanitized for the store).
401
+ */
402
+ name: string;
403
+ /**
404
+ * Whether this run created the named session (no prior token) or continued
405
+ * an existing one.
406
+ */
407
+ phase: "create" | "continue";
408
+ /**
409
+ * The session store file backing the handle (absolute); the programmatic
410
+ * handle to the persisted state.
411
+ */
412
+ store_file: string | null;
413
+ /**
414
+ * The harness native token now bound to the name: the id resumed on a
415
+ * continue, or the id captured on a create. `null` only when a create run
416
+ * exposed no session id (the handle then cannot be continued — a warning is
417
+ * emitted), or under `--print-command` on a create (nothing ran).
418
+ */
419
+ token: string | null;
420
+ [k: string]: unknown;
421
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};
@@ -0,0 +1,13 @@
1
+ export interface DetectReport {
2
+ detected: DetectInfo[];
3
+ schema_version: string;
4
+ [k: string]: unknown;
5
+ }
6
+ export interface DetectInfo {
7
+ available: boolean;
8
+ bin: string;
9
+ id: string;
10
+ path: string | null;
11
+ version: string | null;
12
+ [k: string]: unknown;
13
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness. Do not edit. */
2
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Options accepted by `OneHarness.historyList()` in the published Node SDK.
3
+ */
4
+ export interface HistoryListOptions {
5
+ allProjects?: boolean | undefined;
6
+ historyDir?: string | undefined;
7
+ project?: string | undefined;
8
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};
@@ -0,0 +1,37 @@
1
+ export type HistoryList = HistorySessionSummary[];
2
+ /**
3
+ * A one-line summary of a session, for `oneharness history list`. Read from the
4
+ * session's records: `name`/`project`/`started` come from the first record,
5
+ * `harnesses` is the distinct set across all records.
6
+ */
7
+ export interface HistorySessionSummary {
8
+ /**
9
+ * The distinct harness ids the session touched, in first-seen order.
10
+ */
11
+ harnesses: string[];
12
+ /**
13
+ * The session id (the file stem), unique and sortable by start time.
14
+ */
15
+ id: string;
16
+ /**
17
+ * The human-meaningful session name (non-unique).
18
+ */
19
+ name: string;
20
+ /**
21
+ * The absolute path of the session file.
22
+ */
23
+ path: string;
24
+ /**
25
+ * The project directory the run operated in.
26
+ */
27
+ project: string;
28
+ /**
29
+ * How many harness-run records the session holds.
30
+ */
31
+ record_count: number;
32
+ /**
33
+ * The RFC3339 UTC start time (first record's timestamp); empty if unknown.
34
+ */
35
+ started: string;
36
+ [k: string]: unknown;
37
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The session selector accepted by `OneHarness.history()` in the published Node
3
+ * SDK.
4
+ *
5
+ * A lookup must select a session, so the contract is a union of the only two
6
+ * ways to do that: ask for the most recent one ([`HistoryLookupByLast`]), or
7
+ * name one ([`HistoryLookupBySession`]). A lookup that selects nothing — `{}`,
8
+ * `{"session": ""}`, or `{"last": false}` — matches neither variant and fails
9
+ * at the boundary, so `history()` never has to re-check for one.
10
+ *
11
+ * The variants overlap on purpose, and the order is load-bearing: an untagged
12
+ * enum takes the first match, so `Last` coming first is what gives `last: true`
13
+ * priority over a name. `{"session": "x", "last": true}` satisfies *both*
14
+ * variants and resolves to `Last`, selecting the most recent session rather
15
+ * than `x`; `{"session": "x", "last": false}` fails `Last` and resolves to
16
+ * `Session`. That is exactly the reading of the `if (last) … else if (session)`
17
+ * rule this replaces, now decided by the union rather than re-derived after
18
+ * parsing. Zod resolves its generated union in the same order, so the Node SDK
19
+ * agrees with Rust by construction.
20
+ *
21
+ * Because `Last` ignores the name it carries, that name is a plain `String`:
22
+ * `{"session": "", "last": true}` stays valid and still selects the most recent
23
+ * session, as it always has. Only a name that actually selects has to be
24
+ * non-empty.
25
+ */
26
+ export type HistoryLookup = HistoryLookupByLast | HistoryLookupBySession;
27
+ /**
28
+ * Select the most recent session.
29
+ */
30
+ export interface HistoryLookupByLast {
31
+ allProjects?: boolean | undefined;
32
+ historyDir?: string | undefined;
33
+ /**
34
+ * Select the most recent session. Only `true` selects, so this variant
35
+ * accepts no other value.
36
+ */
37
+ last: true;
38
+ project?: string | undefined;
39
+ /**
40
+ * A name may accompany `last: true` — it is what the caller would have
41
+ * looked up otherwise — but `last` takes priority, so it never selects.
42
+ * It is therefore unconstrained: an empty name is meaningless here rather
43
+ * than invalid, so `{"session": "", "last": true}` stays accepted.
44
+ */
45
+ session?: string | undefined;
46
+ }
47
+ /**
48
+ * Select the session named by `session`.
49
+ */
50
+ export interface HistoryLookupBySession {
51
+ allProjects?: boolean | undefined;
52
+ historyDir?: string | undefined;
53
+ /**
54
+ * Whether the most recent session was asked for instead. An ordinary
55
+ * `bool`, so a caller holding a `boolean` can pass it straight through.
56
+ * `true` here also satisfies [`HistoryLookup::Last`], which the union tries
57
+ * first — so a lookup that reaches this variant always meant the name.
58
+ */
59
+ last?: boolean | undefined;
60
+ project?: string | undefined;
61
+ /**
62
+ * The oneharness-derived session name recorded by `run --history`. This is
63
+ * the name that selects, so it must be non-empty.
64
+ */
65
+ session: string;
66
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};