@oneharness/sdk 0.3.24 → 0.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @oneharness/sdk
2
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.
3
+ Typed Node.js access to the `oneharness` engine. The SDK launches its exact-version packaged CLI dependency and validates every response and stream envelope with named Zod schemas generated from the Rust wire types. The corresponding TypeScript declarations come from the same Rust JSON Schema bundle.
4
4
 
5
5
  ```ts
6
6
  import { OneHarness, RunReportSchema, type RunReport } from "@oneharness/sdk";
@@ -11,11 +11,31 @@ const checked: RunReport = RunReportSchema.parse(report);
11
11
  console.log(checked.results[0]?.text, checked.results[0]?.usage.input_tokens);
12
12
  ```
13
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.
14
+ The complete client surface is `run`, `runStream`, `list`, `detect`, `history`, `historyList`, and `historyWatch`. Both streaming methods return async iterators:
15
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.
16
+ ```ts
17
+ for await (const envelope of oneharness.runStream({
18
+ prompt: "Inspect this repository",
19
+ harnesses: ["codex"],
20
+ })) {
21
+ if (envelope.type === "event" && envelope.event.name === "shell") break;
22
+ }
23
+
24
+ for await (const envelope of oneharness.historyWatch({
25
+ labels: { graph: "release" },
26
+ after: lastHistoryId,
27
+ })) {
28
+ console.log(envelope.record.history_id, envelope.record.status);
29
+ }
30
+ ```
31
+
32
+ Breaking or returning from either iterator terminates its oneharness subprocess. Every line is validated before it is yielded; malformed or unknown envelope variants fail the iterator. Additive fields within known output envelopes are accepted and preserved.
33
+
34
+ `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. `history` and `historyWatch` raise the exported `HistoryNotFoundError` when a session, record, or watch cursor cannot be resolved.
35
+
36
+ Named exports include `RunOptionsSchema`, `HistoryLookupSchema`, `HistoryListOptionsSchema`, `HistoryWatchOptionsSchema`, `RunReportSchema`, `RunStreamEnvelopeSchema`, `RunResultSchema`, `ActionEventSchema`, `UsageSchema`, `HistoryRecordSchema`, `HistoryStreamEnvelopeSchema`, `HistoryRecordsSchema`, `HistoryListSchema`, `HistorySessionSummarySchema`, `ListReportSchema`, `HarnessInfoSchema`, and the registry/detection enum and object schemas. `RunStreamEnvelope` and `HistoryStreamEnvelope` are also exported TypeScript types for consumers building JSONL clients. Each schema's `z.infer` type is compile-time checked against its generated TypeScript type.
17
37
 
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.
38
+ 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`, `HistoryListOptionsSchema`, and `HistoryWatchOptionsSchema` 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. Every method validates its input before spawning the CLI.
19
39
 
20
40
  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
41
 
@@ -13,6 +13,7 @@ export interface HistorySessionSummary {
13
13
  * The session id (the file stem), unique and sortable by start time.
14
14
  */
15
15
  id: string;
16
+ labels?: HistoryLabels | undefined;
16
17
  /**
17
18
  * The human-meaningful session name (non-unique).
18
19
  */
@@ -35,3 +36,9 @@ export interface HistorySessionSummary {
35
36
  started: string;
36
37
  [k: string]: unknown;
37
38
  }
39
+ /**
40
+ * Labels shared by every record in the session. Omitted when empty.
41
+ */
42
+ export interface HistoryLabels {
43
+ [k: string]: string;
44
+ }
@@ -36,6 +36,12 @@ export interface HistoryRecord {
36
36
  * Canonical harness id (e.g. `claude-code`).
37
37
  */
38
38
  harness: string;
39
+ /**
40
+ * Globally unique, time-ordered record id. This is also the cursor accepted
41
+ * by `history watch --after` and the exact id accepted by history lookup.
42
+ */
43
+ history_id: string;
44
+ labels?: HistoryLabels | undefined;
39
45
  /**
40
46
  * The effective top-level model for the run, if any.
41
47
  */
@@ -118,6 +124,13 @@ export interface ActionEvent {
118
124
  output: string | null;
119
125
  [k: string]: unknown;
120
126
  }
127
+ /**
128
+ * Caller-supplied metadata used to select related task-graph records.
129
+ * Omitted on the wire when empty for additive compatibility.
130
+ */
131
+ export interface HistoryLabels {
132
+ [k: string]: string;
133
+ }
121
134
  /**
122
135
  * Best-effort token/cost accounting (every field `null` when unreported).
123
136
  */
@@ -0,0 +1,172 @@
1
+ /**
2
+ * One line emitted by `history watch --format jsonl`. The tagged envelope lets
3
+ * SDKs distinguish the stream from other NDJSON surfaces while the record's
4
+ * `history_id` remains the resumable cursor.
5
+ */
6
+ export type HistoryStreamEnvelope = {
7
+ record: HistoryRecord;
8
+ type: "record";
9
+ [k: string]: unknown;
10
+ };
11
+ /**
12
+ * The normalized, closed set of failure reasons oneharness can classify from a
13
+ * harness's output. It is the single source for the `failure_kind` contract
14
+ * value: serialized as the snake_case token a consumer reads in the report
15
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
16
+ * wire shape is unchanged — modeling it as an enum keeps a misspelled or
17
+ * invalid kind unrepresentable and gives every producer/consumer (classifier,
18
+ * `is_failure`, the fallback fall-through rule, the report, history) one
19
+ * definition to share instead of scattered string literals.
20
+ */
21
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
22
+ /**
23
+ * The outcome of attempting to run one harness.
24
+ */
25
+ export type Status = "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned";
26
+ /**
27
+ * One harness run, normalized and frozen for the history log. Serialized as one
28
+ * JSONL line per harness run, appended as the run finalizes. Carries only the
29
+ * normalized cross-harness signals — no raw stdout/stderr.
30
+ */
31
+ export interface HistoryRecord {
32
+ duration_ms: number | null;
33
+ /**
34
+ * Best-effort normalized tool-call events; `null` when the harness exposes
35
+ * no machine-readable trace.
36
+ */
37
+ events: ActionEvent[] | null;
38
+ exit_code: number | null;
39
+ /**
40
+ * Best-effort classified failure reason (see [`FailureKind`]); `null` when
41
+ * unclassified.
42
+ */
43
+ failure_kind: FailureKind | null;
44
+ /**
45
+ * Canonical harness id (e.g. `claude-code`).
46
+ */
47
+ harness: string;
48
+ /**
49
+ * Globally unique, time-ordered record id. This is also the cursor accepted
50
+ * by `history watch --after` and the exact id accepted by history lookup.
51
+ */
52
+ history_id: string;
53
+ labels?: HistoryLabels | undefined;
54
+ /**
55
+ * The effective top-level model for the run, if any.
56
+ */
57
+ model: string | null;
58
+ /**
59
+ * The human-meaningful session name (see [`session_name`]); repeated on
60
+ * every record so a reader can resolve a session by name from any line.
61
+ */
62
+ name: string;
63
+ /**
64
+ * The normalized approval mode requested for the run.
65
+ */
66
+ permission_mode: "read-only" | "plan" | "default" | "edit" | "auto" | "bypass";
67
+ /**
68
+ * The project directory the run operated in (the real path, not the
69
+ * on-disk slug), so the list view can show where a session ran.
70
+ */
71
+ project: string;
72
+ /**
73
+ * The prompt this harness run received (its own, on a batch run; else the
74
+ * run's single prompt).
75
+ */
76
+ prompt: string;
77
+ schema_version: string;
78
+ /**
79
+ * The oneharness session id this run belongs to (the history file's stem).
80
+ */
81
+ session: string;
82
+ /**
83
+ * The harness's own continuation id, when it exposed one; `null` otherwise.
84
+ */
85
+ session_id: string | null;
86
+ status: Status;
87
+ /**
88
+ * Best-effort final assistant text; `null` when extraction was impossible.
89
+ */
90
+ text: string | null;
91
+ /**
92
+ * How `text` was extracted; `null` when absent.
93
+ */
94
+ text_source: string | null;
95
+ /**
96
+ * RFC3339 UTC instant the record was written (append time).
97
+ */
98
+ timestamp: string;
99
+ usage: Usage;
100
+ [k: string]: unknown;
101
+ }
102
+ /**
103
+ * One normalized action a harness took, harness-agnostic so a single consumer
104
+ * assertion works across harnesses. Every field is always serialized (null when
105
+ * absent) so the shape is stable, mirroring the `usage` contract.
106
+ */
107
+ export interface ActionEvent {
108
+ /**
109
+ * Position of this event within the run, so "≤ N tool calls" and "did X
110
+ * before Y" are expressible from a stable ordering (also array order).
111
+ */
112
+ index: number;
113
+ /**
114
+ * Structured, tool-shaped arguments (the command string, the file path),
115
+ * so a consumer asserts on specific args without re-parsing; `null` when the
116
+ * event carries none (e.g. a `tool_result`).
117
+ */
118
+ input: unknown;
119
+ /**
120
+ * The kind of event: `tool_call` (the model invoked a tool) or
121
+ * `tool_result` (the observation returned to the model). Left open for
122
+ * future kinds rather than an enum, so a new shape never breaks the field.
123
+ */
124
+ kind: string;
125
+ /**
126
+ * Normalized tool name where knowable (e.g. `bash`, `Edit`); `null` for a
127
+ * `tool_result`, or when the harness did not name the tool.
128
+ */
129
+ name: string | null;
130
+ /**
131
+ * The result/observation text, when the trace exposes it; `null` otherwise.
132
+ */
133
+ output: string | null;
134
+ [k: string]: unknown;
135
+ }
136
+ /**
137
+ * Caller-supplied metadata used to select related task-graph records.
138
+ * Omitted on the wire when empty for additive compatibility.
139
+ */
140
+ export interface HistoryLabels {
141
+ [k: string]: string;
142
+ }
143
+ /**
144
+ * Best-effort token/cost accounting (every field `null` when unreported).
145
+ */
146
+ export interface Usage {
147
+ /**
148
+ * Prompt tokens served from the provider's prompt cache (a cheap read of a
149
+ * previously-written prefix), when the harness reports them. `None` when the
150
+ * harness does not surface cache counts — never `0` as a guess.
151
+ */
152
+ cache_read_tokens: number | null;
153
+ /**
154
+ * Prompt tokens written to the provider's prompt cache (a.k.a. cache
155
+ * creation), when the harness reports them. `None` when not surfaced.
156
+ */
157
+ cache_write_tokens: number | null;
158
+ /**
159
+ * Total cost in USD, when the harness reports it (often absent on
160
+ * subscription auth, where there is no per-call dollar figure).
161
+ */
162
+ cost_usd: number | null;
163
+ /**
164
+ * Prompt/input tokens billed, when the harness reports them.
165
+ */
166
+ input_tokens: number | null;
167
+ /**
168
+ * Completion/output tokens billed, when the harness reports them.
169
+ */
170
+ output_tokens: number | null;
171
+ [k: string]: unknown;
172
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Options accepted by the language SDKs' continuous history iterators.
3
+ *
4
+ * The CLI spells `labels` as repeated `--label key=value` arguments, while an
5
+ * SDK can expose the validated map directly. Unknown fields remain a boundary
6
+ * error, as they are for every other SDK input contract.
7
+ */
8
+ export interface HistoryWatchOptions {
9
+ after?: string | undefined;
10
+ allProjects?: boolean | undefined;
11
+ historyDir?: string | undefined;
12
+ labels?: HistoryLabels | undefined;
13
+ project?: string | undefined;
14
+ }
15
+ export interface HistoryLabels {
16
+ [k: string]: string;
17
+ }
@@ -0,0 +1,2 @@
1
+ /* Generated from oneharness-core. Do not edit. */
2
+ export {};
@@ -35,6 +35,12 @@ export interface HistoryRecord {
35
35
  * Canonical harness id (e.g. `claude-code`).
36
36
  */
37
37
  harness: string;
38
+ /**
39
+ * Globally unique, time-ordered record id. This is also the cursor accepted
40
+ * by `history watch --after` and the exact id accepted by history lookup.
41
+ */
42
+ history_id: string;
43
+ labels?: HistoryLabels | undefined;
38
44
  /**
39
45
  * The effective top-level model for the run, if any.
40
46
  */
@@ -117,6 +123,13 @@ export interface ActionEvent {
117
123
  output: string | null;
118
124
  [k: string]: unknown;
119
125
  }
126
+ /**
127
+ * Caller-supplied metadata used to select related task-graph records.
128
+ * Omitted on the wire when empty for additive compatibility.
129
+ */
130
+ export interface HistoryLabels {
131
+ [k: string]: string;
132
+ }
120
133
  /**
121
134
  * Best-effort token/cost accounting (every field `null` when unreported).
122
135
  */
@@ -25,6 +25,7 @@ export interface RunOptions {
25
25
  harnesses?: readonly string[] | undefined;
26
26
  history?: boolean | undefined;
27
27
  historyDir?: string | undefined;
28
+ historyLabels?: HistoryLabels | undefined;
28
29
  historyName?: string | undefined;
29
30
  mode?: PermissionMode | undefined;
30
31
  models?: readonly string[] | undefined;
@@ -38,3 +39,6 @@ export interface RunOptions {
38
39
  system?: string | undefined;
39
40
  timeoutSeconds?: number | undefined;
40
41
  }
42
+ export interface HistoryLabels {
43
+ [k: string]: string;
44
+ }