@oneharness/sdk 0.6.9 → 0.6.11

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.
@@ -1,3 +1,52 @@
1
+ /**
2
+ * One control request the run handled, recorded in the report so a consumer
3
+ * can tell an interrupted turn from one that simply ended.
4
+ *
5
+ * A sum type discriminated by `outcome`, so a record can never say "served,
6
+ * and here is the refusal reason": the reason exists exactly when there was a
7
+ * refusal. Serialized flat — `{"outcome":"served","verb":…,"at":…}` /
8
+ * `{"outcome":"refused","verb":…,"at":…,"reason":…}`.
9
+ */
10
+ export type ControlEvent = {
11
+ /**
12
+ * When the request was handled.
13
+ */
14
+ at: string;
15
+ outcome: "served";
16
+ /**
17
+ * Whether a redirection was committed with the abort. Omitted when it
18
+ * was a plain stop, so an older consumer reads the same record it
19
+ * always did.
20
+ */
21
+ redirected?: boolean | undefined;
22
+ /**
23
+ * The verb requested.
24
+ */
25
+ verb: "interrupt";
26
+ [k: string]: unknown;
27
+ } | {
28
+ at: UtcInstant;
29
+ outcome: "refused";
30
+ reason: ControlReason;
31
+ verb: ControlVerb;
32
+ [k: string]: unknown;
33
+ };
34
+ /**
35
+ * An RFC 3339 timestamp in UTC (`Z`), in oneharness's canonical spelling.
36
+ */
37
+ export type UtcInstant = string;
38
+ /**
39
+ * Why a control request could not be served. Distinct reasons because a
40
+ * supervisor reacts differently to each: `unsupported` is permanent for the
41
+ * harness, `not_running` means the dispatch is gone, `no_active_turn` means
42
+ * the run is alive but between turns.
43
+ */
44
+ export type ControlReason = "unsupported" | "no_active_turn" | "not_running";
45
+ /**
46
+ * The control verb a supervisor sends. Only `interrupt` exists today; the
47
+ * frame's `v` is what leaves room for `steer` later.
48
+ */
49
+ export type ControlVerb = "interrupt";
1
50
  export type ToolCallStatus = "completed" | "failed" | "timeout" | "interrupted";
2
51
  /**
3
52
  * How a normalized tool interval was obtained.
@@ -7,13 +56,14 @@ export type TimingSource = "provider_measured" | "stdout_observed";
7
56
  * The normalized, closed set of failure reasons oneharness can classify from a
8
57
  * harness's output. It is the single source for the `failure_kind` contract
9
58
  * value: serialized as the snake_case token a consumer reads in the report
10
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
11
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
12
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
13
- * `is_failure`, the fallback fall-through rule, the report, history) one
14
- * definition to share instead of scattered string literals.
59
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
60
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
61
+ * keeps a misspelled or invalid kind unrepresentable and gives every
62
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
63
+ * the report, history) one definition to share instead of scattered string
64
+ * literals.
15
65
  */
16
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
66
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
17
67
  /**
18
68
  * How a harness emits its result, which decides how `text` is extracted.
19
69
  *
@@ -79,6 +129,14 @@ export interface RunReport {
79
129
  * project last); empty under `--no-config` or when none exist.
80
130
  */
81
131
  config_files: string[];
132
+ /**
133
+ * Out-of-band turn control for this run (`--control`), or `null` when none
134
+ * was requested — which is every ordinary run. It records the socket a
135
+ * separate `oneharness interrupt` process could address, the harness
136
+ * mechanism behind it, and each request served, so a consumer can tell an
137
+ * interrupted turn from one that simply ended.
138
+ */
139
+ control: ControlReport | null;
82
140
  dry_run: boolean;
83
141
  /**
84
142
  * Fallback-mode metadata when this run drove the selected harnesses in
@@ -189,6 +247,25 @@ export interface BatchReport {
189
247
  strategy: "speed" | "min-tokens";
190
248
  [k: string]: unknown;
191
249
  }
250
+ /**
251
+ * The run report's `control` block: where the socket lived, which mechanism
252
+ * backed it, and every request served over the run's lifetime.
253
+ */
254
+ export interface ControlReport {
255
+ /**
256
+ * Every control request served, in order.
257
+ */
258
+ interrupts: ControlEvent[];
259
+ /**
260
+ * The harness mechanism backing it.
261
+ */
262
+ mechanism: "claude-control-request" | "codex-app-server" | "opencode-http" | "acp-cancel" | "crush-http";
263
+ /**
264
+ * Absolute path of the socket this run listened on.
265
+ */
266
+ socket: string;
267
+ [k: string]: unknown;
268
+ }
192
269
  /**
193
270
  * Metadata for a fallback run (harnesses tried in priority order until one
194
271
  * runs). Present on [`RunReport::fallback`] only in that mode. The per-harness
@@ -274,7 +351,7 @@ export interface RunResult {
274
351
  * Best-effort failure reason; `null` when unclassified. Distinct from
275
352
  * `status`, which records oneharness's relationship to the process. Two
276
353
  * families: coarse reasons for a non-zero run (`auth`, `rate_limit`,
277
- * `model_not_found`, `quota`), and `tool_deferred` — a run that exited
354
+ * `model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited
278
355
  * *cleanly* but only deferred a builtin tool call instead of executing it
279
356
  * (Claude Code bridge/managed deployments), so it did no useful work. The
280
357
  * deferred case is the only `failure_kind` that can appear on a `status: ok`
@@ -6,7 +6,7 @@ export type HistoryLine = ({
6
6
  harness: string;
7
7
  harness_id?: string | null | undefined;
8
8
  run_id: string;
9
- schema_version: "1.2" | "1.3" | "1.4";
9
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
10
10
  type: "event";
11
11
  variant?: string | null | undefined;
12
12
  [k: string]: unknown;
@@ -27,7 +27,7 @@ export type HistoryLine = ({
27
27
  [k: string]: unknown;
28
28
  } | ({
29
29
  error: string;
30
- schema_version?: "1.3" | "1.4" | undefined;
30
+ schema_version?: "1.3" | "1.4" | "1.5" | undefined;
31
31
  [k: string]: unknown;
32
32
  } & ({
33
33
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -39,7 +39,13 @@ export type HistoryLine = ({
39
39
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
40
40
  [k: string]: unknown;
41
41
  } | {
42
- schema_version?: "1.4" | undefined;
42
+ schema_version?: "1.4" | "1.5" | undefined;
43
+ [k: string]: unknown;
44
+ }) & ({
45
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | null | undefined;
46
+ [k: string]: unknown;
47
+ } | {
48
+ schema_version?: "1.5" | undefined;
43
49
  [k: string]: unknown;
44
50
  }) & ({
45
51
  duration_ms: number;
@@ -62,7 +68,7 @@ export type HistoryLine = ({
62
68
  permission_mode: PermissionMode;
63
69
  project: string;
64
70
  prompt: string;
65
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4";
71
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5";
66
72
  session: string;
67
73
  session_id: string | null;
68
74
  started_at: string;
@@ -97,7 +103,7 @@ export type HistoryLine = ({
97
103
  permission_mode: PermissionMode;
98
104
  project: string;
99
105
  prompt: string;
100
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4";
106
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5";
101
107
  session: string;
102
108
  session_id: string | null;
103
109
  started_at: string;
@@ -132,7 +138,7 @@ export type HistoryLine = ({
132
138
  permission_mode: PermissionMode;
133
139
  project: string;
134
140
  prompt: string;
135
- schema_version: "1.2" | "1.3" | "1.4";
141
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
136
142
  session: string;
137
143
  session_id: string | null;
138
144
  started_at?: never | undefined;
@@ -167,7 +173,7 @@ export type HistoryLine = ({
167
173
  permission_mode: PermissionMode;
168
174
  project: string;
169
175
  prompt: string;
170
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4";
176
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5";
171
177
  session: string;
172
178
  session_id: string | null;
173
179
  started_at?: never | undefined;
@@ -202,7 +208,7 @@ export type HistoryLine = ({
202
208
  permission_mode: PermissionMode;
203
209
  project: string;
204
210
  prompt: string;
205
- schema_version: "1.3" | "1.4";
211
+ schema_version: "1.3" | "1.4" | "1.5";
206
212
  session: string;
207
213
  session_id: string | null;
208
214
  started_at: string;
@@ -237,7 +243,7 @@ export type HistoryLine = ({
237
243
  permission_mode: PermissionMode;
238
244
  project: string;
239
245
  prompt: string;
240
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4";
246
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5";
241
247
  session: string;
242
248
  session_id: string | null;
243
249
  started_at?: never | undefined;
@@ -261,13 +267,14 @@ export type TimingSource = "provider_measured" | "stdout_observed";
261
267
  * The normalized, closed set of failure reasons oneharness can classify from a
262
268
  * harness's output. It is the single source for the `failure_kind` contract
263
269
  * value: serialized as the snake_case token a consumer reads in the report
264
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
265
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
266
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
267
- * `is_failure`, the fallback fall-through rule, the report, history) one
268
- * definition to share instead of scattered string literals.
270
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
271
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
272
+ * keeps a misspelled or invalid kind unrepresentable and gives every
273
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
274
+ * the report, history) one definition to share instead of scattered string
275
+ * literals.
269
276
  */
270
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
277
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
271
278
  /**
272
279
  * The unified approval mode, from least to most autonomy. A harness may not
273
280
  * support every value (see [`crate::domain::harness::HarnessSpec::mode`]); the
@@ -93,7 +93,7 @@ export type HistoryRecord = {
93
93
  * run's single prompt).
94
94
  */
95
95
  prompt: string;
96
- schema_version: "1.2" | "1.3" | "1.4";
96
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
97
97
  /**
98
98
  * The oneharness session id this run belongs to (the history file's stem).
99
99
  */
@@ -323,7 +323,7 @@ export type HistoryRecord = {
323
323
  * run's single prompt).
324
324
  */
325
325
  prompt: string;
326
- schema_version: "1.2" | "1.3" | "1.4";
326
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
327
327
  /**
328
328
  * The oneharness session id this run belongs to (the history file's stem).
329
329
  */
@@ -415,7 +415,7 @@ export type HistoryRecord = {
415
415
  * run's single prompt).
416
416
  */
417
417
  prompt: string;
418
- schema_version: "1.2" | "1.3" | "1.4";
418
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
419
419
  /**
420
420
  * The oneharness session id this run belongs to (the history file's stem).
421
421
  */
@@ -507,7 +507,7 @@ export type HistoryRecord = {
507
507
  * run's single prompt).
508
508
  */
509
509
  prompt: string;
510
- schema_version: "1.2" | "1.3" | "1.4";
510
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
511
511
  /**
512
512
  * The oneharness session id this run belongs to (the history file's stem).
513
513
  */
@@ -599,7 +599,7 @@ export type HistoryRecord = {
599
599
  * run's single prompt).
600
600
  */
601
601
  prompt: string;
602
- schema_version: "1.3" | "1.4";
602
+ schema_version: "1.3" | "1.4" | "1.5";
603
603
  /**
604
604
  * The oneharness session id this run belongs to (the history file's stem).
605
605
  */
@@ -944,13 +944,14 @@ export type TimingSource = "provider_measured" | "stdout_observed";
944
944
  * The normalized, closed set of failure reasons oneharness can classify from a
945
945
  * harness's output. It is the single source for the `failure_kind` contract
946
946
  * value: serialized as the snake_case token a consumer reads in the report
947
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
948
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
949
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
950
- * `is_failure`, the fallback fall-through rule, the report, history) one
951
- * definition to share instead of scattered string literals.
947
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
948
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
949
+ * keeps a misspelled or invalid kind unrepresentable and gives every
950
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
951
+ * the report, history) one definition to share instead of scattered string
952
+ * literals.
952
953
  */
953
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
954
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
954
955
  /**
955
956
  * The outcome of attempting to run one harness.
956
957
  */
@@ -960,7 +961,7 @@ export type HistoryRecords = (({
960
961
  [k: string]: unknown;
961
962
  } | ({
962
963
  error: string;
963
- schema_version?: "1.3" | "1.4" | undefined;
964
+ schema_version?: "1.3" | "1.4" | "1.5" | undefined;
964
965
  [k: string]: unknown;
965
966
  } & ({
966
967
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -972,7 +973,13 @@ export type HistoryRecords = (({
972
973
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
973
974
  [k: string]: unknown;
974
975
  } | {
975
- schema_version?: "1.4" | undefined;
976
+ schema_version?: "1.4" | "1.5" | undefined;
977
+ [k: string]: unknown;
978
+ }) & ({
979
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | null | undefined;
980
+ [k: string]: unknown;
981
+ } | {
982
+ schema_version?: "1.5" | undefined;
976
983
  [k: string]: unknown;
977
984
  }) & HistoryRecord)[];
978
985
  /**
@@ -14,7 +14,7 @@ export type HistoryStreamEnvelope = {
14
14
  [k: string]: unknown;
15
15
  } | ({
16
16
  error: string;
17
- schema_version?: "1.3" | "1.4" | undefined;
17
+ schema_version?: "1.3" | "1.4" | "1.5" | undefined;
18
18
  [k: string]: unknown;
19
19
  } & ({
20
20
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -26,7 +26,13 @@ export type HistoryStreamEnvelope = {
26
26
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
27
27
  [k: string]: unknown;
28
28
  } | {
29
- schema_version?: "1.4" | undefined;
29
+ schema_version?: "1.4" | "1.5" | undefined;
30
+ [k: string]: unknown;
31
+ }) & ({
32
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | null | undefined;
33
+ [k: string]: unknown;
34
+ } | {
35
+ schema_version?: "1.5" | undefined;
30
36
  [k: string]: unknown;
31
37
  }) & HistoryRecord;
32
38
  type: "record";
@@ -131,7 +137,7 @@ export type HistoryRecord = {
131
137
  * run's single prompt).
132
138
  */
133
139
  prompt: string;
134
- schema_version: "1.2" | "1.3" | "1.4";
140
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
135
141
  /**
136
142
  * The oneharness session id this run belongs to (the history file's stem).
137
143
  */
@@ -361,7 +367,7 @@ export type HistoryRecord = {
361
367
  * run's single prompt).
362
368
  */
363
369
  prompt: string;
364
- schema_version: "1.2" | "1.3" | "1.4";
370
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
365
371
  /**
366
372
  * The oneharness session id this run belongs to (the history file's stem).
367
373
  */
@@ -453,7 +459,7 @@ export type HistoryRecord = {
453
459
  * run's single prompt).
454
460
  */
455
461
  prompt: string;
456
- schema_version: "1.2" | "1.3" | "1.4";
462
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
457
463
  /**
458
464
  * The oneharness session id this run belongs to (the history file's stem).
459
465
  */
@@ -545,7 +551,7 @@ export type HistoryRecord = {
545
551
  * run's single prompt).
546
552
  */
547
553
  prompt: string;
548
- schema_version: "1.2" | "1.3" | "1.4";
554
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
549
555
  /**
550
556
  * The oneharness session id this run belongs to (the history file's stem).
551
557
  */
@@ -637,7 +643,7 @@ export type HistoryRecord = {
637
643
  * run's single prompt).
638
644
  */
639
645
  prompt: string;
640
- schema_version: "1.3" | "1.4";
646
+ schema_version: "1.3" | "1.4" | "1.5";
641
647
  /**
642
648
  * The oneharness session id this run belongs to (the history file's stem).
643
649
  */
@@ -982,13 +988,14 @@ export type TimingSource = "provider_measured" | "stdout_observed";
982
988
  * The normalized, closed set of failure reasons oneharness can classify from a
983
989
  * harness's output. It is the single source for the `failure_kind` contract
984
990
  * value: serialized as the snake_case token a consumer reads in the report
985
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
986
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
987
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
988
- * `is_failure`, the fallback fall-through rule, the report, history) one
989
- * definition to share instead of scattered string literals.
991
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
992
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
993
+ * keeps a misspelled or invalid kind unrepresentable and gives every
994
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
995
+ * the report, history) one definition to share instead of scattered string
996
+ * literals.
990
997
  */
991
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
998
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
992
999
  /**
993
1000
  * The outcome of attempting to run one harness.
994
1001
  */
@@ -998,7 +1005,7 @@ export type HistoryEventLine = {
998
1005
  harness: string;
999
1006
  harness_id?: string | null | undefined;
1000
1007
  run_id: string;
1001
- schema_version: "1.2" | "1.3" | "1.4";
1008
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
1002
1009
  variant?: string | null | undefined;
1003
1010
  [k: string]: unknown;
1004
1011
  } | {
@@ -8,7 +8,7 @@ export type HistoryRecord = ({
8
8
  [k: string]: unknown;
9
9
  } | ({
10
10
  error: string;
11
- schema_version?: "1.3" | "1.4" | undefined;
11
+ schema_version?: "1.3" | "1.4" | "1.5" | undefined;
12
12
  [k: string]: unknown;
13
13
  } & ({
14
14
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -20,7 +20,13 @@ export type HistoryRecord = ({
20
20
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
21
21
  [k: string]: unknown;
22
22
  } | {
23
- schema_version?: "1.4" | undefined;
23
+ schema_version?: "1.4" | "1.5" | undefined;
24
+ [k: string]: unknown;
25
+ }) & ({
26
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | null | undefined;
27
+ [k: string]: unknown;
28
+ } | {
29
+ schema_version?: "1.5" | undefined;
24
30
  [k: string]: unknown;
25
31
  }) & ({
26
32
  duration_ms: number;
@@ -117,7 +123,7 @@ export type HistoryRecord = ({
117
123
  * run's single prompt).
118
124
  */
119
125
  prompt: string;
120
- schema_version: "1.2" | "1.3" | "1.4";
126
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
121
127
  /**
122
128
  * The oneharness session id this run belongs to (the history file's stem).
123
129
  */
@@ -347,7 +353,7 @@ export type HistoryRecord = ({
347
353
  * run's single prompt).
348
354
  */
349
355
  prompt: string;
350
- schema_version: "1.2" | "1.3" | "1.4";
356
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
351
357
  /**
352
358
  * The oneharness session id this run belongs to (the history file's stem).
353
359
  */
@@ -439,7 +445,7 @@ export type HistoryRecord = ({
439
445
  * run's single prompt).
440
446
  */
441
447
  prompt: string;
442
- schema_version: "1.2" | "1.3" | "1.4";
448
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
443
449
  /**
444
450
  * The oneharness session id this run belongs to (the history file's stem).
445
451
  */
@@ -531,7 +537,7 @@ export type HistoryRecord = ({
531
537
  * run's single prompt).
532
538
  */
533
539
  prompt: string;
534
- schema_version: "1.2" | "1.3" | "1.4";
540
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5";
535
541
  /**
536
542
  * The oneharness session id this run belongs to (the history file's stem).
537
543
  */
@@ -623,7 +629,7 @@ export type HistoryRecord = ({
623
629
  * run's single prompt).
624
630
  */
625
631
  prompt: string;
626
- schema_version: "1.3" | "1.4";
632
+ schema_version: "1.3" | "1.4" | "1.5";
627
633
  /**
628
634
  * The oneharness session id this run belongs to (the history file's stem).
629
635
  */
@@ -968,13 +974,14 @@ export type TimingSource = "provider_measured" | "stdout_observed";
968
974
  * The normalized, closed set of failure reasons oneharness can classify from a
969
975
  * harness's output. It is the single source for the `failure_kind` contract
970
976
  * value: serialized as the snake_case token a consumer reads in the report
971
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
972
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
973
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
974
- * `is_failure`, the fallback fall-through rule, the report, history) one
975
- * definition to share instead of scattered string literals.
977
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
978
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
979
+ * keeps a misspelled or invalid kind unrepresentable and gives every
980
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
981
+ * the report, history) one definition to share instead of scattered string
982
+ * literals.
976
983
  */
977
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
984
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
978
985
  /**
979
986
  * The outcome of attempting to run one harness.
980
987
  */
@@ -1,3 +1,13 @@
1
+ /**
2
+ * How a harness accepts an out-of-band interrupt for an in-flight turn.
3
+ *
4
+ * Registry data on [`crate::domain::harness::HarnessSpec::control`], sourced
5
+ * from a live interrupt against the real CLI — never guessed. `None` there
6
+ * means `oneharness interrupt` is a loud usage error for the harness, never a
7
+ * silent no-op: a supervisor that is told "ok" while the turn keeps running is
8
+ * worse off than one told the lever does not exist.
9
+ */
10
+ export type ControlShape = "claude-control-request" | "codex-app-server" | "opencode-http" | "acp-cancel" | "crush-http";
1
11
  /**
2
12
  * The unified approval mode, from least to most autonomy. A harness may not
3
13
  * support every value (see [`crate::domain::harness::HarnessSpec::mode`]); the
@@ -19,6 +29,13 @@ export interface ListReport {
19
29
  [k: string]: unknown;
20
30
  }
21
31
  export interface HarnessInfo {
32
+ /**
33
+ * How `run --control` + `oneharness interrupt` abort an in-flight turn on
34
+ * this harness (the mechanism id), or `null` when it has no out-of-band
35
+ * turn control at all — in which case `--control` is a loud usage error for
36
+ * it, never a socket that reports success while the turn keeps running.
37
+ */
38
+ control: ControlShape | null;
22
39
  default_bin: string;
23
40
  display: string;
24
41
  /**
@@ -20,17 +20,67 @@ export type ToolCallStatus = "completed" | "failed" | "timeout" | "interrupted";
20
20
  * How a normalized tool interval was obtained.
21
21
  */
22
22
  export type TimingSource = "provider_measured" | "stdout_observed";
23
+ /**
24
+ * One control request the run handled, recorded in the report so a consumer
25
+ * can tell an interrupted turn from one that simply ended.
26
+ *
27
+ * A sum type discriminated by `outcome`, so a record can never say "served,
28
+ * and here is the refusal reason": the reason exists exactly when there was a
29
+ * refusal. Serialized flat — `{"outcome":"served","verb":…,"at":…}` /
30
+ * `{"outcome":"refused","verb":…,"at":…,"reason":…}`.
31
+ */
32
+ export type ControlEvent = {
33
+ /**
34
+ * When the request was handled.
35
+ */
36
+ at: string;
37
+ outcome: "served";
38
+ /**
39
+ * Whether a redirection was committed with the abort. Omitted when it
40
+ * was a plain stop, so an older consumer reads the same record it
41
+ * always did.
42
+ */
43
+ redirected?: boolean | undefined;
44
+ /**
45
+ * The verb requested.
46
+ */
47
+ verb: "interrupt";
48
+ [k: string]: unknown;
49
+ } | {
50
+ at: UtcInstant;
51
+ outcome: "refused";
52
+ reason: ControlReason;
53
+ verb: ControlVerb;
54
+ [k: string]: unknown;
55
+ };
56
+ /**
57
+ * An RFC 3339 timestamp in UTC (`Z`), in oneharness's canonical spelling.
58
+ */
59
+ export type UtcInstant = string;
60
+ /**
61
+ * Why a control request could not be served. Distinct reasons because a
62
+ * supervisor reacts differently to each: `unsupported` is permanent for the
63
+ * harness, `not_running` means the dispatch is gone, `no_active_turn` means
64
+ * the run is alive but between turns.
65
+ */
66
+ export type ControlReason = "unsupported" | "no_active_turn" | "not_running";
67
+ /**
68
+ * The control verb a supervisor sends. Only `interrupt` exists today; the
69
+ * frame's `v` is what leaves room for `steer` later.
70
+ */
71
+ export type ControlVerb = "interrupt";
23
72
  /**
24
73
  * The normalized, closed set of failure reasons oneharness can classify from a
25
74
  * harness's output. It is the single source for the `failure_kind` contract
26
75
  * value: serialized as the snake_case token a consumer reads in the report
27
- * (`auth`, `rate_limit`, `model_not_found`, `quota`, `tool_deferred`), so the
28
- * wire shape is unchanged — modeling it as an enum keeps a misspelled or
29
- * invalid kind unrepresentable and gives every producer/consumer (classifier,
30
- * `is_failure`, the fallback fall-through rule, the report, history) one
31
- * definition to share instead of scattered string literals.
76
+ * (`auth`, `rate_limit`, `model_not_found`, `quota`, `session_not_found`,
77
+ * `tool_deferred`), so the wire shape is unchanged — modeling it as an enum
78
+ * keeps a misspelled or invalid kind unrepresentable and gives every
79
+ * producer/consumer (classifier, `is_failure`, the fallback fall-through rule,
80
+ * the report, history) one definition to share instead of scattered string
81
+ * literals.
32
82
  */
33
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred";
83
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred";
34
84
  /**
35
85
  * How a harness emits its result, which decides how `text` is extracted.
36
86
  *
@@ -153,6 +203,14 @@ export interface RunReport {
153
203
  * project last); empty under `--no-config` or when none exist.
154
204
  */
155
205
  config_files: string[];
206
+ /**
207
+ * Out-of-band turn control for this run (`--control`), or `null` when none
208
+ * was requested — which is every ordinary run. It records the socket a
209
+ * separate `oneharness interrupt` process could address, the harness
210
+ * mechanism behind it, and each request served, so a consumer can tell an
211
+ * interrupted turn from one that simply ended.
212
+ */
213
+ control: ControlReport | null;
156
214
  dry_run: boolean;
157
215
  /**
158
216
  * Fallback-mode metadata when this run drove the selected harnesses in
@@ -263,6 +321,25 @@ export interface BatchReport {
263
321
  strategy: "speed" | "min-tokens";
264
322
  [k: string]: unknown;
265
323
  }
324
+ /**
325
+ * The run report's `control` block: where the socket lived, which mechanism
326
+ * backed it, and every request served over the run's lifetime.
327
+ */
328
+ export interface ControlReport {
329
+ /**
330
+ * Every control request served, in order.
331
+ */
332
+ interrupts: ControlEvent[];
333
+ /**
334
+ * The harness mechanism backing it.
335
+ */
336
+ mechanism: "claude-control-request" | "codex-app-server" | "opencode-http" | "acp-cancel" | "crush-http";
337
+ /**
338
+ * Absolute path of the socket this run listened on.
339
+ */
340
+ socket: string;
341
+ [k: string]: unknown;
342
+ }
266
343
  /**
267
344
  * Metadata for a fallback run (harnesses tried in priority order until one
268
345
  * runs). Present on [`RunReport::fallback`] only in that mode. The per-harness
@@ -348,7 +425,7 @@ export interface RunResult {
348
425
  * Best-effort failure reason; `null` when unclassified. Distinct from
349
426
  * `status`, which records oneharness's relationship to the process. Two
350
427
  * families: coarse reasons for a non-zero run (`auth`, `rate_limit`,
351
- * `model_not_found`, `quota`), and `tool_deferred` — a run that exited
428
+ * `model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited
352
429
  * *cleanly* but only deferred a builtin tool call instead of executing it
353
430
  * (Claude Code bridge/managed deployments), so it did no useful work. The
354
431
  * deferred case is the only `failure_kind` that can appear on a `status: ok`