@the-open-engine/zeroshot 6.22.0 → 6.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/lib/agent-cli-provider/adapters/omp.d.ts +3 -1
  2. package/lib/agent-cli-provider/adapters/omp.d.ts.map +1 -1
  3. package/lib/agent-cli-provider/adapters/omp.js +252 -269
  4. package/lib/agent-cli-provider/adapters/omp.js.map +1 -1
  5. package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -1
  6. package/lib/agent-cli-provider/contract-invoke.js +68 -14
  7. package/lib/agent-cli-provider/contract-invoke.js.map +1 -1
  8. package/lib/agent-cli-provider/contract-options.d.ts.map +1 -1
  9. package/lib/agent-cli-provider/contract-options.js +5 -3
  10. package/lib/agent-cli-provider/contract-options.js.map +1 -1
  11. package/lib/agent-cli-provider/index.d.ts +6 -0
  12. package/lib/agent-cli-provider/index.d.ts.map +1 -1
  13. package/lib/agent-cli-provider/index.js +12 -1
  14. package/lib/agent-cli-provider/index.js.map +1 -1
  15. package/lib/agent-cli-provider/omp-release.d.ts +3 -1
  16. package/lib/agent-cli-provider/omp-release.d.ts.map +1 -1
  17. package/lib/agent-cli-provider/omp-release.js +22 -2
  18. package/lib/agent-cli-provider/omp-release.js.map +1 -1
  19. package/lib/agent-cli-provider/omp-rpc-bounds.d.ts +7 -0
  20. package/lib/agent-cli-provider/omp-rpc-bounds.d.ts.map +1 -0
  21. package/lib/agent-cli-provider/omp-rpc-bounds.js +27 -0
  22. package/lib/agent-cli-provider/omp-rpc-bounds.js.map +1 -0
  23. package/lib/agent-cli-provider/omp-rpc-driver.d.ts +40 -0
  24. package/lib/agent-cli-provider/omp-rpc-driver.d.ts.map +1 -0
  25. package/lib/agent-cli-provider/omp-rpc-driver.js +494 -0
  26. package/lib/agent-cli-provider/omp-rpc-driver.js.map +1 -0
  27. package/lib/agent-cli-provider/omp-rpc-events.d.ts +28 -0
  28. package/lib/agent-cli-provider/omp-rpc-events.d.ts.map +1 -0
  29. package/lib/agent-cli-provider/omp-rpc-events.js +264 -0
  30. package/lib/agent-cli-provider/omp-rpc-events.js.map +1 -0
  31. package/lib/agent-cli-provider/omp-rpc-protocol.d.ts +1 -1
  32. package/lib/agent-cli-provider/omp-rpc-protocol.d.ts.map +1 -1
  33. package/lib/agent-cli-provider/omp-rpc-protocol.js +8 -3
  34. package/lib/agent-cli-provider/omp-rpc-protocol.js.map +1 -1
  35. package/lib/agent-cli-provider/omp-rpc-session.d.ts +17 -0
  36. package/lib/agent-cli-provider/omp-rpc-session.d.ts.map +1 -0
  37. package/lib/agent-cli-provider/omp-rpc-session.js +6 -0
  38. package/lib/agent-cli-provider/omp-rpc-session.js.map +1 -0
  39. package/lib/agent-cli-provider/provider-registry.d.ts +15 -11
  40. package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
  41. package/lib/agent-cli-provider/provider-registry.js +16 -5
  42. package/lib/agent-cli-provider/provider-registry.js.map +1 -1
  43. package/lib/agent-cli-provider/types.d.ts +13 -11
  44. package/lib/agent-cli-provider/types.d.ts.map +1 -1
  45. package/lib/agent-cli-provider/types.js.map +1 -1
  46. package/package.json +2 -1
  47. package/src/agent-cli-provider/adapters/omp.ts +276 -329
  48. package/src/agent-cli-provider/contract-invoke.ts +86 -15
  49. package/src/agent-cli-provider/contract-options.ts +5 -3
  50. package/src/agent-cli-provider/index.ts +13 -0
  51. package/src/agent-cli-provider/omp-release.ts +24 -1
  52. package/src/agent-cli-provider/omp-rpc-bounds.ts +28 -0
  53. package/src/agent-cli-provider/omp-rpc-driver.ts +611 -0
  54. package/src/agent-cli-provider/omp-rpc-events.ts +318 -0
  55. package/src/agent-cli-provider/omp-rpc-protocol.ts +8 -3
  56. package/src/agent-cli-provider/omp-rpc-session.ts +20 -0
  57. package/src/agent-cli-provider/provider-registry.ts +26 -7
  58. package/src/agent-cli-provider/types.ts +14 -11
  59. package/src/command-cleanup-ownership.js +307 -0
  60. package/src/omp-config-overlay.js +96 -0
  61. package/src/orchestrator.js +20 -5
  62. package/src/preflight.js +35 -3
  63. package/src/watcher-prompt-channel.js +209 -0
  64. package/task-lib/command-spec-cleanup.js +1 -262
  65. package/task-lib/provider-helper-runtime.js +6 -0
  66. package/task-lib/rpc-watcher.js +186 -0
  67. package/task-lib/runner.js +40 -6
  68. package/task-lib/watcher-output-runtime.js +32 -0
@@ -0,0 +1,318 @@
1
+ import { OmpRpcProtocolError, type OmpRpcInboundFrame } from './omp-rpc-protocol';
2
+ import { MAX_NORMALIZED_OUTPUT_BYTES } from './omp-rpc-bounds';
3
+ import {
4
+ getArray,
5
+ getBoolean,
6
+ getNumber,
7
+ getOptionalString,
8
+ getRecord,
9
+ getString,
10
+ isRecord,
11
+ stringifyContent,
12
+ tryParseJson,
13
+ } from './json';
14
+ import type { OutputEvent, ProviderParseResult, ProviderParserState } from './types';
15
+
16
+ export interface OmpRpcEventState {
17
+ lastAssistantText: string;
18
+ lastAssistantThinking: string;
19
+ lastToolId: string | null | undefined;
20
+ normalizedBytes: number;
21
+ }
22
+
23
+ export function createOmpRpcEventState(): OmpRpcEventState {
24
+ return {
25
+ lastAssistantText: '',
26
+ lastAssistantThinking: '',
27
+ lastToolId: undefined,
28
+ normalizedBytes: 0,
29
+ };
30
+ }
31
+
32
+ function assistantSnapshot(message: Record<string, unknown>): { text: string; thinking: string } {
33
+ if (getString(message, 'role') !== 'assistant') return { text: '', thinking: '' };
34
+
35
+ let text = '';
36
+ let thinking = '';
37
+ for (const item of getArray(message, 'content')) {
38
+ if (!isRecord(item)) continue;
39
+ const type = getString(item, 'type');
40
+ if (type === 'text') {
41
+ text += getString(item, 'text') ?? '';
42
+ } else if (type === 'thinking') {
43
+ thinking += getString(item, 'thinking') ?? '';
44
+ }
45
+ }
46
+
47
+ return { text, thinking };
48
+ }
49
+
50
+ function snapshotDelta(previous: string, current: string): string | null {
51
+ if (!current || previous === current) return null;
52
+ if (current.startsWith(previous)) return current.slice(previous.length) || null;
53
+ return current;
54
+ }
55
+
56
+ function chargeBytes(state: OmpRpcEventState, value: unknown): void {
57
+ const byteLength = Buffer.byteLength(stringifyContent(value), 'utf8');
58
+ state.normalizedBytes += byteLength;
59
+ if (state.normalizedBytes > MAX_NORMALIZED_OUTPUT_BYTES) {
60
+ throw new OmpRpcProtocolError(
61
+ 'output-bound-exceeded',
62
+ `Normalized OMP RPC output exceeded the ${MAX_NORMALIZED_OUTPUT_BYTES}-byte cap for this task.`
63
+ );
64
+ }
65
+ }
66
+
67
+ function emitText(state: OmpRpcEventState, text: string): OutputEvent {
68
+ chargeBytes(state, text);
69
+ return { type: 'text', text };
70
+ }
71
+
72
+ function emitThinking(state: OmpRpcEventState, text: string): OutputEvent {
73
+ chargeBytes(state, text);
74
+ return { type: 'thinking', text };
75
+ }
76
+
77
+ function normalizeMessageStart(
78
+ frame: OmpRpcInboundFrame,
79
+ state: OmpRpcEventState
80
+ ): readonly OutputEvent[] {
81
+ const message = getRecord(frame, 'message');
82
+ if (message !== null && getString(message, 'role') === 'assistant') {
83
+ state.lastAssistantText = '';
84
+ state.lastAssistantThinking = '';
85
+ }
86
+ return [];
87
+ }
88
+
89
+ function normalizeAssistantMessageEvent(
90
+ event: Record<string, unknown>,
91
+ state: OmpRpcEventState
92
+ ): readonly OutputEvent[] {
93
+ const type = getString(event, 'type');
94
+ if (type === 'text_delta') {
95
+ const delta = getString(event, 'delta');
96
+ if (!delta) return [];
97
+ state.lastAssistantText += delta;
98
+ return [emitText(state, delta)];
99
+ }
100
+ if (type === 'thinking_delta') {
101
+ const delta = getString(event, 'delta');
102
+ if (!delta) return [];
103
+ state.lastAssistantThinking += delta;
104
+ return [emitThinking(state, delta)];
105
+ }
106
+ return [];
107
+ }
108
+
109
+ function normalizeMessageSnapshot(
110
+ message: Record<string, unknown>,
111
+ state: OmpRpcEventState
112
+ ): readonly OutputEvent[] {
113
+ const snapshot = assistantSnapshot(message);
114
+ const events: OutputEvent[] = [];
115
+
116
+ const textDelta = snapshotDelta(state.lastAssistantText, snapshot.text);
117
+ if (textDelta) events.push(emitText(state, textDelta));
118
+ if (snapshot.text) state.lastAssistantText = snapshot.text;
119
+
120
+ const thinkingDelta = snapshotDelta(state.lastAssistantThinking, snapshot.thinking);
121
+ if (thinkingDelta) events.push(emitThinking(state, thinkingDelta));
122
+ if (snapshot.thinking) state.lastAssistantThinking = snapshot.thinking;
123
+
124
+ return events;
125
+ }
126
+
127
+ function normalizeMessageUpdate(
128
+ frame: OmpRpcInboundFrame,
129
+ state: OmpRpcEventState
130
+ ): readonly OutputEvent[] {
131
+ const assistantMessageEvent = getRecord(frame, 'assistantMessageEvent');
132
+ if (assistantMessageEvent !== null) {
133
+ const events = normalizeAssistantMessageEvent(assistantMessageEvent, state);
134
+ if (events.length > 0) return events;
135
+ }
136
+ const message = getRecord(frame, 'message');
137
+ return message === null ? [] : normalizeMessageSnapshot(message, state);
138
+ }
139
+
140
+ function normalizeMessageEnd(
141
+ frame: OmpRpcInboundFrame,
142
+ state: OmpRpcEventState
143
+ ): readonly OutputEvent[] {
144
+ const message = getRecord(frame, 'message');
145
+ return message === null ? [] : normalizeMessageSnapshot(message, state);
146
+ }
147
+
148
+ function normalizeToolExecutionStart(
149
+ frame: OmpRpcInboundFrame,
150
+ state: OmpRpcEventState
151
+ ): readonly OutputEvent[] {
152
+ const toolId = getOptionalString(frame, 'toolCallId');
153
+ state.lastToolId = toolId;
154
+ const input = frame.args ?? {};
155
+ chargeBytes(state, input);
156
+ return [
157
+ {
158
+ type: 'tool_call',
159
+ toolName: getOptionalString(frame, 'toolName'),
160
+ toolId,
161
+ input,
162
+ },
163
+ ];
164
+ }
165
+
166
+ function normalizeToolExecutionUpdate(
167
+ frame: OmpRpcInboundFrame,
168
+ state: OmpRpcEventState
169
+ ): readonly OutputEvent[] {
170
+ const toolId = getOptionalString(frame, 'toolCallId') ?? state.lastToolId;
171
+ if (toolId !== undefined) state.lastToolId = toolId;
172
+ if (!Object.prototype.hasOwnProperty.call(frame, 'partialResult')) return [];
173
+ chargeBytes(state, frame.partialResult);
174
+ return [
175
+ {
176
+ type: 'tool_result',
177
+ toolId,
178
+ content: frame.partialResult,
179
+ isError: false,
180
+ },
181
+ ];
182
+ }
183
+
184
+ function normalizeToolExecutionEnd(
185
+ frame: OmpRpcInboundFrame,
186
+ state: OmpRpcEventState
187
+ ): readonly OutputEvent[] {
188
+ const toolId = getOptionalString(frame, 'toolCallId') ?? state.lastToolId;
189
+ const content = frame.result ?? '';
190
+ chargeBytes(state, content);
191
+ return [
192
+ {
193
+ type: 'tool_result',
194
+ toolId,
195
+ content,
196
+ isError: getBoolean(frame, 'isError') ?? false,
197
+ },
198
+ ];
199
+ }
200
+
201
+ function normalizeTurnEnd(
202
+ frame: OmpRpcInboundFrame,
203
+ state: OmpRpcEventState
204
+ ): readonly OutputEvent[] {
205
+ const message = getRecord(frame, 'message');
206
+ const usage = message ? (getRecord(message, 'usage') ?? {}) : {};
207
+ const stopReason = message ? getString(message, 'stopReason') : null;
208
+ const errorMessage = message ? getString(message, 'errorMessage') : null;
209
+ const snapshot = message ? assistantSnapshot(message) : { text: '', thinking: '' };
210
+ const success = stopReason !== 'error' && stopReason !== 'aborted' && !errorMessage;
211
+ const result = success ? snapshot.text || state.lastAssistantText || null : null;
212
+ chargeBytes(state, { result, error: errorMessage ?? stopReason ?? null });
213
+ return [
214
+ {
215
+ type: 'result',
216
+ success,
217
+ result,
218
+ error: success ? null : (errorMessage ?? stopReason ?? 'OMP turn failed'),
219
+ inputTokens: getNumber(usage, 'input') ?? 0,
220
+ outputTokens: getNumber(usage, 'output') ?? 0,
221
+ cacheReadInputTokens: getNumber(usage, 'cacheRead') ?? 0,
222
+ cacheCreationInputTokens: getNumber(usage, 'cacheWrite') ?? 0,
223
+ cost: getRecord(usage, 'cost') ?? null,
224
+ modelUsage: usage,
225
+ },
226
+ ];
227
+ }
228
+
229
+ /**
230
+ * Normalize one decoded OMP RPC v2 event frame into zero or more OutputEvents. Only the frame
231
+ * types below produce output; every other known-pre-negotiation frame (agent_start/agent_end,
232
+ * turn_start, ready, response, session_info_update, subagent_*, ...) is protocol/control plumbing
233
+ * the driver consumes directly and must never leak into log/attach/ledger output.
234
+ */
235
+ export function normalizeOmpRpcFrame(
236
+ frame: OmpRpcInboundFrame,
237
+ state: OmpRpcEventState
238
+ ): readonly OutputEvent[] {
239
+ switch (frame.type) {
240
+ case 'message_start':
241
+ return normalizeMessageStart(frame, state);
242
+ case 'message_update':
243
+ return normalizeMessageUpdate(frame, state);
244
+ case 'message_end':
245
+ return normalizeMessageEnd(frame, state);
246
+ case 'tool_execution_start':
247
+ return normalizeToolExecutionStart(frame, state);
248
+ case 'tool_execution_update':
249
+ return normalizeToolExecutionUpdate(frame, state);
250
+ case 'tool_execution_end':
251
+ return normalizeToolExecutionEnd(frame, state);
252
+ case 'turn_end':
253
+ return normalizeTurnEnd(frame, state);
254
+ default:
255
+ return [];
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Parse one line of the rpc-stdio lane's already-normalized OutputEvent JSON stream (produced
261
+ * from `OmpRpcTaskResult.events` by `contract-invoke.ts` / `rpc-watcher.js`). This is the
262
+ * `ProviderAdapter.parseEvent` counterpart to `normalizeOmpRpcFrame` above: the driver normalizes
263
+ * raw RPC frames to OutputEvent once, and this function is a validating passthrough over that
264
+ * already-normalized shape so generic log/attach tooling built on `adapter.parseEvent` keeps
265
+ * working for the omp provider without re-deriving events from raw frames. Each case rebuilds a
266
+ * literal matching its OutputEvent variant instead of casting the parsed record, so an
267
+ * unexpectedly-shaped line fails closed (returns null) rather than passing through untyped.
268
+ */
269
+ export function parseNormalizedOmpRpcEventLine(
270
+ line: string,
271
+ _state: ProviderParserState
272
+ ): ProviderParseResult {
273
+ const parsed = tryParseJson(line);
274
+ if (!isRecord(parsed)) return null;
275
+ switch (parsed.type) {
276
+ case 'text':
277
+ case 'thinking': {
278
+ const text = getString(parsed, 'text');
279
+ return text === null ? null : { type: parsed.type, text };
280
+ }
281
+ case 'tool_call':
282
+ return {
283
+ type: 'tool_call',
284
+ toolName: getOptionalString(parsed, 'toolName'),
285
+ toolId: getOptionalString(parsed, 'toolId'),
286
+ input: parsed.input,
287
+ };
288
+ case 'tool_result':
289
+ return {
290
+ type: 'tool_result',
291
+ toolId: getOptionalString(parsed, 'toolId'),
292
+ content: parsed.content,
293
+ isError: parsed.isError,
294
+ };
295
+ case 'result': {
296
+ if (typeof parsed.success !== 'boolean') return null;
297
+ const inputTokens = getNumber(parsed, 'inputTokens');
298
+ const outputTokens = getNumber(parsed, 'outputTokens');
299
+ const cacheReadInputTokens = getNumber(parsed, 'cacheReadInputTokens');
300
+ const cacheCreationInputTokens = getNumber(parsed, 'cacheCreationInputTokens');
301
+ return {
302
+ type: 'result',
303
+ success: parsed.success,
304
+ result: parsed.result,
305
+ error: parsed.error,
306
+ cost: parsed.cost,
307
+ duration: parsed.duration,
308
+ ...(inputTokens === null ? {} : { inputTokens }),
309
+ ...(outputTokens === null ? {} : { outputTokens }),
310
+ ...(cacheReadInputTokens === null ? {} : { cacheReadInputTokens }),
311
+ ...(cacheCreationInputTokens === null ? {} : { cacheCreationInputTokens }),
312
+ modelUsage: parsed.modelUsage,
313
+ };
314
+ }
315
+ default:
316
+ return null;
317
+ }
318
+ }
@@ -218,7 +218,11 @@ export class OmpRpcFrameDecoder {
218
218
  this.inflightReassemblyBytes = 0;
219
219
  }
220
220
 
221
- push(chunk: Uint8Array): readonly OmpRpcInboundFrame[] {
221
+ // `negotiatedV2` defaults to true so callers that don't care about pre-negotiation gating
222
+ // (e.g. the fixture-replay tests below) see unchanged behavior; the RPC driver passes its
223
+ // live negotiation state so a bare `rpc_chunk` physical frame is rejected before negotiation
224
+ // succeeds, even though the decoder would otherwise buffer it silently pending reassembly.
225
+ push(chunk: Uint8Array, negotiatedV2 = true): readonly OmpRpcInboundFrame[] {
222
226
  if (this.finished) {
223
227
  throw new OmpRpcProtocolError('decoder-finished', 'push() called after finish().');
224
228
  }
@@ -247,7 +251,7 @@ export class OmpRpcFrameDecoder {
247
251
  );
248
252
  }
249
253
 
250
- const frame = this.consumeLine(lineBytes);
254
+ const frame = this.consumeLine(lineBytes, negotiatedV2);
251
255
  if (frame !== null) frames.push(frame);
252
256
  }
253
257
 
@@ -270,7 +274,7 @@ export class OmpRpcFrameDecoder {
270
274
  }
271
275
  }
272
276
 
273
- private consumeLine(lineBytes: Buffer): OmpRpcInboundFrame | null {
277
+ private consumeLine(lineBytes: Buffer, negotiatedV2: boolean): OmpRpcInboundFrame | null {
274
278
  let value: unknown;
275
279
  try {
276
280
  value = JSON.parse(lineBytes.toString('utf8'));
@@ -285,6 +289,7 @@ export class OmpRpcFrameDecoder {
285
289
  }
286
290
 
287
291
  const type = getString(value, 'type');
292
+ assertNoPreNegotiationRpcChunk(type ?? '', negotiatedV2);
288
293
  if (type !== 'rpc_chunk') {
289
294
  if (this.pendingReassemblies.size > 0) {
290
295
  throw new OmpRpcProtocolError(
@@ -0,0 +1,20 @@
1
+ // Session-launch types for the OMP RPC v2 driver. This slice launches sessionless
2
+ // (`--no-session`) only; `fresh`/`resume` are typed for Subissue 4's session-flag activation but
3
+ // are unreachable from any caller in this slice.
4
+
5
+ export interface VerifiedOmpPartition {
6
+ readonly path: string;
7
+ }
8
+
9
+ export interface VerifiedOmpSessionFile {
10
+ readonly path: string;
11
+ }
12
+
13
+ export type OmpSessionLaunch =
14
+ | { readonly kind: 'none' }
15
+ | { readonly kind: 'fresh'; readonly partition: VerifiedOmpPartition }
16
+ | {
17
+ readonly kind: 'resume';
18
+ readonly partition: VerifiedOmpPartition;
19
+ readonly file: VerifiedOmpSessionFile;
20
+ };
@@ -8,7 +8,7 @@ import { opencodeAdapter } from './adapters/opencode';
8
8
  import { ompAdapter } from './adapters/omp';
9
9
  import { piAdapter } from './adapters/pi';
10
10
  import { resolveClaudeCommand } from './claude-command';
11
- import { OMP_INSTALL_COMMAND } from './omp-release';
11
+ import { OMP_AUTH_INSTRUCTIONS, OMP_INSTALL_COMMAND } from './omp-release';
12
12
  import type { ModelLevel, ProviderAdapter, StructuredOutputRecoveryAdapter } from './types';
13
13
 
14
14
  export type ProviderCapabilityState = boolean | 'experimental';
@@ -44,7 +44,15 @@ export interface AcpStdioProviderInvokeSpec {
44
44
  readonly transport: 'stdio';
45
45
  }
46
46
 
47
- export type ProviderInvokeSpec = SpawnProviderInvokeSpec | AcpStdioProviderInvokeSpec;
47
+ export interface RpcStdioProviderInvokeSpec {
48
+ readonly lane: 'rpc-stdio';
49
+ readonly protocol: 'omp-v2';
50
+ }
51
+
52
+ export type ProviderInvokeSpec =
53
+ | SpawnProviderInvokeSpec
54
+ | AcpStdioProviderInvokeSpec
55
+ | RpcStdioProviderInvokeSpec;
48
56
 
49
57
  export type ProviderCommandSpec = FixedProviderCommandSpec | ConfiguredClaudeCommandSpec;
50
58
 
@@ -146,6 +154,10 @@ const ACP_STDIO_INVOKE = Object.freeze({
146
154
  lane: 'acp-stdio',
147
155
  transport: 'stdio',
148
156
  }) as AcpStdioProviderInvokeSpec;
157
+ const RPC_STDIO_INVOKE = Object.freeze({
158
+ lane: 'rpc-stdio',
159
+ protocol: 'omp-v2',
160
+ }) as RpcStdioProviderInvokeSpec;
149
161
 
150
162
  const kiroAdapter = createAcpAdapter({
151
163
  provider: 'kiro',
@@ -428,22 +440,29 @@ export const providerRegistry = [
428
440
  {
429
441
  id: 'omp',
430
442
  default: false,
431
- aliases: [],
432
- displayName: 'OMP',
443
+ aliases: ['oh-my-pi'],
444
+ displayName: 'OMP (Oh My Pi)',
433
445
  binary: 'omp',
434
446
  command: { kind: 'fixed', command: 'omp', args: [] },
435
- invoke: SPAWN_INVOKE,
447
+ invoke: RPC_STDIO_INVOKE,
436
448
  installInstructions: OMP_INSTALL_COMMAND,
437
- authInstructions: 'omp\n/login',
449
+ authInstructions: OMP_AUTH_INSTRUCTIONS,
438
450
  credentialPaths: ['~/.omp'],
439
451
  credentialEnvKeys: ompAdapter.credentialEnvKeys,
440
452
  settingsFields: [],
441
453
  availabilityProbe: 'help-or-version',
454
+ // Written out explicitly rather than spread from STANDARD_CAPABILITIES, which defaults
455
+ // dockerIsolation to true; OMP stays worktree-only until Subissue 6 flips dockerIsolation.
442
456
  capabilities: {
443
- ...STANDARD_CAPABILITIES,
457
+ dockerIsolation: false,
458
+ worktreeIsolation: true,
444
459
  mcpServers: false,
445
460
  jsonSchema: false,
461
+ streamJson: true,
462
+ thinkingMode: true,
446
463
  reasoningEffort: true,
464
+ sessionResume: false,
465
+ webSearch: false,
447
466
  },
448
467
  docs: {
449
468
  label: 'OMP',
@@ -168,16 +168,16 @@ export interface PiCliFeatures extends BaseCliFeatures {
168
168
 
169
169
  export interface OmpCliFeatures extends BaseCliFeatures {
170
170
  readonly provider: 'omp';
171
- readonly supportsModeJson: boolean;
172
- readonly supportsPrint: boolean;
173
- readonly supportsCwd: boolean;
174
- readonly supportsAutoApprove: boolean;
171
+ readonly supportsRpcMode: boolean;
172
+ readonly supportsConfig: boolean;
175
173
  readonly supportsModel: boolean;
176
174
  readonly supportsThinking: boolean;
177
- readonly supportsNoExtensions: boolean;
178
- readonly supportsNoSkills: boolean;
179
- readonly supportsNoRules: boolean;
175
+ readonly supportsApprovalMode: boolean;
180
176
  readonly supportsNoTitle: boolean;
177
+ readonly supportsNoSession: boolean;
178
+ readonly supportsSessionDir: boolean;
179
+ readonly supportsResume: boolean;
180
+ readonly versionMatches: boolean;
181
181
  }
182
182
 
183
183
  export interface CopilotCliFeatures extends BaseCliFeatures {
@@ -256,11 +256,13 @@ export interface CliFeatureOverrides {
256
256
  readonly supportsRecoveryIsolation?: boolean;
257
257
  readonly supportsNoContextFiles?: boolean;
258
258
  readonly supportsNoApprove?: boolean;
259
- readonly supportsModeJson?: boolean;
260
- readonly supportsPrint?: boolean;
259
+ readonly supportsRpcMode?: boolean;
260
+ readonly supportsConfig?: boolean;
261
261
  readonly supportsThinking?: boolean;
262
- readonly supportsNoRules?: boolean;
262
+ readonly supportsApprovalMode?: boolean;
263
263
  readonly supportsNoTitle?: boolean;
264
+ readonly supportsSessionDir?: boolean;
265
+ readonly versionMatches?: boolean;
264
266
  readonly supportsJsonOutput?: boolean;
265
267
  readonly supportsAllowAll?: boolean;
266
268
  readonly supportsNoAskUser?: boolean;
@@ -412,7 +414,8 @@ export type ErrorClassificationKind =
412
414
  | 'code-retryable'
413
415
  | 'permanent-pattern'
414
416
  | 'retryable-pattern'
415
- | 'unknown-retryable';
417
+ | 'unknown-retryable'
418
+ | 'cancelled';
416
419
 
417
420
  export interface ErrorClassification {
418
421
  readonly retryable: boolean;