@scotthuang/agent-knock-knock 0.11.4 → 0.11.6

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.
@@ -117,6 +117,15 @@ export interface TerminalRuntimeIdentity {
117
117
  * authorize terminal side effects by itself.
118
118
  */
119
119
  requireNativeProcessUuid?: boolean;
120
+ /**
121
+ * Native inspection of Claude requires the same unique interactive
122
+ * `claude agents --json --all` row to remain idle at every bridge identity
123
+ * fence. The process-incarnation timestamp is part of that exact row.
124
+ */
125
+ requireExactClaudeAgentRow?: boolean;
126
+ nativeProcessStartedAt?: number;
127
+ /** Exact Claude agents state permitted at this bridge phase. */
128
+ exactClaudeAgentState?: "idle" | "status_dialog";
120
129
  /**
121
130
  * Current Codex turns require the exact open root rollout descriptor and
122
131
  * process-birth evidence. A session id by itself is not an incarnation
@@ -283,9 +292,18 @@ export interface TerminalNativeInspectionPlan {
283
292
  composer: {
284
293
  kind: "exact";
285
294
  minimumStableMs: number;
295
+ /** Version-profiled upper bound for exact composer materialization. */
296
+ maximumSettleMs: number;
286
297
  };
287
298
  expectedResult: {
288
299
  kind: "native_status";
300
+ /** Inline cards remain at the prompt; modal panels must be dismissed. */
301
+ presentation: "inline" | "modal";
302
+ /** Closed adapter-owned dismissal sequence for a verified modal result. */
303
+ dismissal?: {
304
+ keys: readonly string[];
305
+ expected: "idle_empty_composer";
306
+ };
289
307
  };
290
308
  }
291
309
  export interface TerminalNativeInspectionField {
@@ -328,6 +346,8 @@ export interface TerminalNativeInspectionObservationRequest {
328
346
  expectedNativeThreadId?: string;
329
347
  /** Optional exact running version that the status surface must confirm. */
330
348
  expectedAgentVersion?: string;
349
+ /** Optional exact working directory that the status surface must confirm. */
350
+ expectedCwd?: string;
331
351
  }
332
352
  export interface TerminalNativeInspectionObservation {
333
353
  status: "observed" | "missing" | "ambiguous" | "stale" | "mismatch";
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-agent-adapter.js","sourceRoot":"","sources":["../../src/terminal-agent-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-agent-adapter.js","sourceRoot":"","sources":["../../src/terminal-agent-adapter.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,14 @@ export declare class NativeInspectionSubmissionError extends Error {
24
24
  cause?: unknown;
25
25
  });
26
26
  }
27
+ /** A verified modal could not be dismissed across one exact key attempt. */
28
+ export declare class NativeInspectionDismissalError extends Error {
29
+ readonly code = "AKK_NATIVE_INSPECTION_DISMISSAL_FAILED";
30
+ readonly doNotRetry = true;
31
+ constructor(message: string, options?: {
32
+ cause?: unknown;
33
+ });
34
+ }
27
35
  export interface TerminalBridgeStatus {
28
36
  provider: "tmux";
29
37
  target: string;
@@ -129,7 +137,7 @@ export interface TerminalNativeInspectionMaterializationEvidence {
129
137
  stableCaptures: number;
130
138
  }
131
139
  export interface TerminalNativeInspectionBeforeEnterContext {
132
- agent: "codex";
140
+ agent: ExecutorKind;
133
141
  terminalControl: TerminalControlRef;
134
142
  plan: TerminalNativeInspectionPlan;
135
143
  preEnterScreenDigest: string;
@@ -146,15 +154,33 @@ export interface TerminalNativeInspectionOptions {
146
154
  }
147
155
  export interface TerminalNativeInspectionResult {
148
156
  stage: "enter_dispatched";
149
- agent: "codex";
157
+ agent: ExecutorKind;
150
158
  terminalControl: TerminalControlRef;
151
- command: "/status";
159
+ command: string;
152
160
  behaviorProfile: string;
153
161
  preEnterScreenDigest: string;
154
162
  preEnterEvidenceInventory: readonly TerminalNativeInspectionEvidenceInventoryEntry[];
155
163
  materialization: TerminalNativeInspectionMaterializationEvidence;
156
164
  enterCount: 1;
157
165
  }
166
+ export interface TerminalNativeInspectionBeforeDismissContext {
167
+ agent: ExecutorKind;
168
+ terminalControl: TerminalControlRef;
169
+ plan: TerminalNativeInspectionPlan;
170
+ evidenceFingerprint: string;
171
+ }
172
+ export interface TerminalNativeInspectionDismissalOptions {
173
+ runtime?: TerminalRuntimeIdentity;
174
+ scrollbackLines?: number;
175
+ beforeDismiss?: (context: TerminalNativeInspectionBeforeDismissContext) => void | Promise<void>;
176
+ }
177
+ export interface TerminalNativeInspectionDismissalResult {
178
+ stage: "dismiss_dispatched";
179
+ agent: ExecutorKind;
180
+ terminalControl: TerminalControlRef;
181
+ keys: readonly string[];
182
+ dismissCount: 1;
183
+ }
158
184
  export interface TerminalNativeInspectionObservationResult {
159
185
  terminalControl: TerminalControlRef;
160
186
  status: TerminalBridgeStatus;
@@ -221,8 +247,14 @@ export declare class TerminalAgentBridge {
221
247
  runtime?: TerminalRuntimeIdentity;
222
248
  scrollbackLines?: number;
223
249
  }): Promise<TerminalNativeInspectionObservationResult>;
224
- private settleCodexNativeInspectionComposer;
225
- private revalidateCodexNativeInspectionComposer;
250
+ /**
251
+ * Dismiss one exact adapter-owned modal result after re-observing the same
252
+ * evidence under the terminal identity fence. There is exactly one key
253
+ * attempt and no automated retry across an uncertain dismissal boundary.
254
+ */
255
+ dismissNativeInspection(agent: ExecutorKind, terminalControl: TerminalControlRef, plan: TerminalNativeInspectionPlan, request: TerminalNativeInspectionObservationRequest, expectedEvidenceFingerprint: string, options?: TerminalNativeInspectionDismissalOptions): Promise<TerminalNativeInspectionDismissalResult>;
256
+ private settleNativeInspectionComposer;
257
+ private revalidateNativeInspectionComposer;
226
258
  private settleCodexMultilineComposer;
227
259
  /**
228
260
  * Prove that the exact managed draft is still present after Enter dispatch.
@@ -281,6 +313,12 @@ export declare class TerminalAgentBridge {
281
313
  private captureInspection;
282
314
  private verifyTerminalIdentity;
283
315
  }
316
+ /**
317
+ * Prove the exact idle input frame from a verified Claude Code native-status
318
+ * profile. A loose or historical `❯` prompt is not enough to authorize even
319
+ * the initial literal `/status` injection.
320
+ */
321
+ export declare function isExactClaudeNativeInspectionIdleComposer(screen: string): boolean;
284
322
  export declare function terminalApprovalFingerprint(agent: ExecutorKind, terminalControl: TerminalControlRef, inspection: TerminalScreenInspection, options?: {
285
323
  screen?: string;
286
324
  runtime?: TerminalRuntimeIdentity;
@@ -1,9 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { formatTerminalConversationId, parseTerminalConversationId, terminalControlCapabilitiesForAdapter } from "./terminal-agent-adapter.js";
3
3
  import { enrichActiveProcessesWithTerminalControl, TerminalControlInputNotSentError, terminalRefFromPane } from "./terminal-control-provider.js";
4
- // Codex 0.146.x keeps Enter in paste/newline mode for 120ms after burst input.
5
- // Cross that boundary rather than landing on it, and also require observable
6
- // composer stability instead of treating this delay alone as acceptance.
4
+ // Verified Codex profiles through 0.147.0 keep Enter in paste/newline mode for
5
+ // 120ms after burst input. Cross that boundary rather than landing on it, and
6
+ // also require observable composer stability instead of treating this delay
7
+ // alone as acceptance.
7
8
  const CODEX_PASTE_ENTER_SETTLE_MS = 121;
8
9
  const CODEX_MULTILINE_SETTLE_POLL_MS = 30;
9
10
  const CODEX_MULTILINE_SETTLE_TIMEOUT_MS = 2_000;
@@ -11,12 +12,34 @@ const CODEX_MULTILINE_STABLE_CAPTURES = 2;
11
12
  const CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES = 240;
12
13
  const CODEX_COMPOSER_MARKER = /^[›»](?:\s|$)/u;
13
14
  const CODEX_COMPOSER_FOOTER = /^(?:gpt-[\w.-]+(?:\s|$)|[-\w.]+ default ·)/u;
14
- // Codex 0.146.0 and 0.146.1 render the same verified slash-completion row.
15
- // Keep it closed per behavior profile so changed text cannot silently become
16
- // a newly authorized native command surface.
15
+ // Keep every exact slash-completion shape closed per behavior profile so a
16
+ // version adding another matching command cannot silently become an authorized
17
+ // native command surface.
17
18
  const CODEX_NATIVE_STATUS_POPUP_BY_PROFILE = {
18
- "codex-tui-0.146.0": " /status show current session configuration and token usage",
19
- "codex-tui-0.146.1": " /status show current session configuration and token usage"
19
+ "codex-tui-0.146.0": [
20
+ " /status show current session configuration and token usage"
21
+ ],
22
+ "codex-tui-0.146.1": [
23
+ " /status show current session configuration and token usage"
24
+ ],
25
+ "codex-tui-0.147.0": [
26
+ " /status show current session configuration and token usage",
27
+ " /statusline configure which items appear in the status line"
28
+ ]
29
+ };
30
+ const CLAUDE_NATIVE_STATUS_POPUP_BY_PROFILE = {
31
+ "claude-code-2.1.218-native-status": [
32
+ "/status Show Claude Code status including version, model, account, API connectivity, and tool statuses",
33
+ "/statusline Set up Claude Code's status line UI",
34
+ "/ide Manage IDE integrations and show status",
35
+ "/usage Show session cost, plan usage, and activity stats"
36
+ ],
37
+ "claude-code-2.1.226-native-status": [
38
+ "/status Show Claude Code status including version, model, account, API connectivity, and tool statuses",
39
+ "/statusline Set up Claude Code's status line UI",
40
+ "/ide Manage IDE integrations and show status",
41
+ "/usage Show session cost, plan usage, and activity stats"
42
+ ]
20
43
  };
21
44
  const CODEX_LARGE_PASTE_CHAR_THRESHOLD = 1_000;
22
45
  /** A terminal send failed at a boundary that proves input never started. */
@@ -45,6 +68,15 @@ export class NativeInspectionSubmissionError extends Error {
45
68
  this.doNotRetry = stage !== "not_started";
46
69
  }
47
70
  }
71
+ /** A verified modal could not be dismissed across one exact key attempt. */
72
+ export class NativeInspectionDismissalError extends Error {
73
+ code = "AKK_NATIVE_INSPECTION_DISMISSAL_FAILED";
74
+ doNotRetry = true;
75
+ constructor(message, options = {}) {
76
+ super(message, options);
77
+ this.name = "NativeInspectionDismissalError";
78
+ }
79
+ }
48
80
  export class TerminalAgentBridge {
49
81
  registry;
50
82
  terminalProvider;
@@ -254,7 +286,7 @@ export class TerminalAgentBridge {
254
286
  async submitNativeInspection(agent, terminalControl, plan, options = {}) {
255
287
  const adapter = this.registry.require(agent);
256
288
  try {
257
- assertCodexStatusInspectionPlan(adapter, terminalControl, plan);
289
+ assertClosedStatusInspectionPlan(adapter, terminalControl, plan);
258
290
  }
259
291
  catch (error) {
260
292
  throw nativeInspectionSubmissionError("not_started", error);
@@ -279,15 +311,15 @@ export class TerminalAgentBridge {
279
311
  }
280
312
  let settled;
281
313
  try {
282
- settled = await this.settleCodexNativeInspectionComposer(adapter, terminalControl, plan, options.runtime);
314
+ settled = await this.settleNativeInspectionComposer(adapter, terminalControl, plan, options.runtime);
283
315
  await options.beforeEnter?.({
284
- agent: "codex",
316
+ agent: adapter.agent,
285
317
  terminalControl: settled.terminalControl,
286
318
  plan,
287
319
  preEnterScreenDigest: settled.screenDigest,
288
320
  materialization: settled.materialization
289
321
  });
290
- settled = await this.revalidateCodexNativeInspectionComposer(adapter, settled.terminalControl, plan, settled.materialization, options.runtime);
322
+ settled = await this.revalidateNativeInspectionComposer(adapter, settled.terminalControl, plan, settled.materialization, options.runtime);
291
323
  }
292
324
  catch (error) {
293
325
  throw nativeInspectionSubmissionError("text_injected", error);
@@ -302,9 +334,9 @@ export class TerminalAgentBridge {
302
334
  }
303
335
  return {
304
336
  stage: "enter_dispatched",
305
- agent: "codex",
337
+ agent: adapter.agent,
306
338
  terminalControl: settled.terminalControl,
307
- command: "/status",
339
+ command: plan.command,
308
340
  behaviorProfile: plan.behaviorProfile,
309
341
  preEnterScreenDigest: settled.screenDigest,
310
342
  preEnterEvidenceInventory: settled.evidenceInventory,
@@ -322,14 +354,24 @@ export class TerminalAgentBridge {
322
354
  scrollbackLines: options.scrollbackLines
323
355
  });
324
356
  const screenDigest = nativeInspectionScreenFingerprint(captured.screen);
325
- const observation = adapter.observeNativeInspection({
357
+ const adapterObservation = adapter.observeNativeInspection({
326
358
  operation: request.operation,
327
359
  previousScreenFingerprint: request.previousScreenFingerprint,
328
360
  preEnterEvidenceInventory: request.preEnterEvidenceInventory,
329
361
  expectedNativeThreadId: request.expectedNativeThreadId,
330
362
  expectedAgentVersion: request.expectedAgentVersion,
363
+ expectedCwd: request.expectedCwd,
331
364
  screen: captured.screen
332
365
  });
366
+ const observation = adapter.agent === "claude" &&
367
+ options.runtime?.requireExactClaudeAgentRow === true &&
368
+ adapterObservation.status === "observed" &&
369
+ adapterObservation.evidence === "claude_status_panel"
370
+ ? {
371
+ ...adapterObservation,
372
+ evidence: "claude_status_panel+claude_agents_exact_pid"
373
+ }
374
+ : adapterObservation;
333
375
  return {
334
376
  terminalControl: captured.terminalControl,
335
377
  status: statusFromInspection(adapter, captured.terminalControl, captured.inspection, { screen: captured.screen, runtime: options.runtime }),
@@ -337,19 +379,91 @@ export class TerminalAgentBridge {
337
379
  observation
338
380
  };
339
381
  }
340
- async settleCodexNativeInspectionComposer(adapter, terminalControl, plan, runtime) {
382
+ /**
383
+ * Dismiss one exact adapter-owned modal result after re-observing the same
384
+ * evidence under the terminal identity fence. There is exactly one key
385
+ * attempt and no automated retry across an uncertain dismissal boundary.
386
+ */
387
+ async dismissNativeInspection(agent, terminalControl, plan, request, expectedEvidenceFingerprint, options = {}) {
388
+ const adapter = this.registry.require(agent);
389
+ try {
390
+ assertClosedStatusInspectionPlan(adapter, terminalControl, plan);
391
+ assertClosedNativeInspectionDismissal(plan);
392
+ }
393
+ catch (error) {
394
+ throw new NativeInspectionDismissalError(error instanceof Error ? error.message : String(error), { cause: error });
395
+ }
396
+ const observeExactPanel = async (control) => {
397
+ const captured = await this.captureInspection(adapter, control, {
398
+ runtime: options.runtime,
399
+ scrollbackLines: options.scrollbackLines
400
+ });
401
+ const observation = adapter.observeNativeInspection?.({
402
+ operation: request.operation,
403
+ previousScreenFingerprint: request.previousScreenFingerprint,
404
+ preEnterEvidenceInventory: request.preEnterEvidenceInventory,
405
+ expectedNativeThreadId: request.expectedNativeThreadId,
406
+ expectedAgentVersion: request.expectedAgentVersion,
407
+ expectedCwd: request.expectedCwd,
408
+ screen: captured.screen
409
+ });
410
+ if (!observation ||
411
+ observation.status !== "observed" ||
412
+ observation.result?.kind !== "native_status" ||
413
+ observation.evidenceFingerprint !== expectedEvidenceFingerprint) {
414
+ throw new Error(observation?.reason ??
415
+ "the exact fresh native status panel changed before dismissal");
416
+ }
417
+ const verified = await this.verifyTerminalIdentity(adapter.agent, captured.terminalControl, options.runtime);
418
+ if (!sameTerminalControlIdentity(captured.terminalControl, verified)) {
419
+ throw new Error("terminal control identity changed before native status dismissal");
420
+ }
421
+ return verified;
422
+ };
423
+ try {
424
+ let verified = await observeExactPanel(terminalControl);
425
+ await options.beforeDismiss?.({
426
+ agent: adapter.agent,
427
+ terminalControl: verified,
428
+ plan,
429
+ evidenceFingerprint: expectedEvidenceFingerprint
430
+ });
431
+ verified = await observeExactPanel(verified);
432
+ try {
433
+ await this.terminalProvider.sendKeys(verified.target, plan.expectedResult.dismissal.keys, { socketPath: verified.socketPath });
434
+ }
435
+ catch (error) {
436
+ throw new NativeInspectionDismissalError("native status modal dismissal outcome is uncertain; do not retry automatically", { cause: error });
437
+ }
438
+ return {
439
+ stage: "dismiss_dispatched",
440
+ agent: adapter.agent,
441
+ terminalControl: verified,
442
+ keys: plan.expectedResult.dismissal.keys,
443
+ dismissCount: 1
444
+ };
445
+ }
446
+ catch (error) {
447
+ if (error instanceof NativeInspectionDismissalError) {
448
+ throw error;
449
+ }
450
+ throw new NativeInspectionDismissalError(error instanceof Error ? error.message : String(error), { cause: error });
451
+ }
452
+ }
453
+ async settleNativeInspectionComposer(adapter, terminalControl, plan, runtime) {
341
454
  const startedAt = performance.now();
455
+ const settleTimeoutMs = plan.composer.maximumSettleMs;
342
456
  let stableDigest;
343
457
  let stableKind;
344
458
  let stableSince;
345
459
  let stableCaptures = 0;
346
- while (performance.now() - startedAt <= CODEX_MULTILINE_SETTLE_TIMEOUT_MS) {
460
+ while (performance.now() - startedAt <= settleTimeoutMs) {
347
461
  const captured = await this.captureInspection(adapter, terminalControl, {
348
462
  runtime,
349
463
  scrollbackLines: CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES
350
464
  });
351
465
  assertNativeInspectionComposerSafe(captured.inspection);
352
- const materialized = exactCodexNativeInspectionComposerCapture(captured.screen, plan);
466
+ const materialized = exactNativeInspectionComposerCapture(adapter.agent, captured.screen, plan);
353
467
  const now = performance.now();
354
468
  if (materialized) {
355
469
  if (materialized.digest === stableDigest &&
@@ -371,7 +485,7 @@ export class TerminalAgentBridge {
371
485
  stableForMs,
372
486
  stableCaptures
373
487
  };
374
- return this.revalidateCodexNativeInspectionComposer(adapter, captured.terminalControl, plan, evidence, runtime);
488
+ return this.revalidateNativeInspectionComposer(adapter, captured.terminalControl, plan, evidence, runtime);
375
489
  }
376
490
  }
377
491
  else {
@@ -381,25 +495,25 @@ export class TerminalAgentBridge {
381
495
  stableCaptures = 0;
382
496
  }
383
497
  const elapsed = performance.now() - startedAt;
384
- const remaining = CODEX_MULTILINE_SETTLE_TIMEOUT_MS - elapsed;
498
+ const remaining = settleTimeoutMs - elapsed;
385
499
  if (remaining <= 0) {
386
500
  break;
387
501
  }
388
502
  await terminalSettleDelay(Math.min(CODEX_MULTILINE_SETTLE_POLL_MS, remaining));
389
503
  }
390
- throw new Error("Codex /status composer did not become exact, idle, and stable before the bounded submit deadline");
504
+ throw new Error(`${adapter.displayName} /status composer did not become exact, idle, and stable before the bounded submit deadline`);
391
505
  }
392
- async revalidateCodexNativeInspectionComposer(adapter, terminalControl, plan, expected, runtime) {
506
+ async revalidateNativeInspectionComposer(adapter, terminalControl, plan, expected, runtime) {
393
507
  const captured = await this.captureInspection(adapter, terminalControl, {
394
508
  runtime,
395
509
  scrollbackLines: CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES
396
510
  });
397
511
  assertNativeInspectionComposerSafe(captured.inspection);
398
- const materialized = exactCodexNativeInspectionComposerCapture(captured.screen, plan);
512
+ const materialized = exactNativeInspectionComposerCapture(adapter.agent, captured.screen, plan);
399
513
  if (!materialized ||
400
514
  materialized.digest !== expected.digest ||
401
515
  materialized.kind !== expected.kind) {
402
- throw new Error("Codex /status composer changed after its stable pre-submit capture");
516
+ throw new Error(`${adapter.displayName} /status composer changed after its stable pre-submit capture`);
403
517
  }
404
518
  const baseline = adapter.observeNativeInspection?.({
405
519
  operation: plan.operation,
@@ -409,11 +523,11 @@ export class TerminalAgentBridge {
409
523
  baseline.status === "ambiguous" ||
410
524
  !Array.isArray(baseline.evidenceInventory)) {
411
525
  throw new Error(baseline?.reason ??
412
- "Codex /status pre-Enter evidence inventory was not proven");
526
+ `${adapter.displayName} /status pre-Enter evidence inventory was not proven`);
413
527
  }
414
528
  const verifiedImmediatelyBeforeEnter = await this.verifyTerminalIdentity(adapter.agent, captured.terminalControl, runtime);
415
529
  if (!sameTerminalControlIdentity(captured.terminalControl, verifiedImmediatelyBeforeEnter)) {
416
- throw new Error("terminal control identity changed after the final Codex /status composer capture");
530
+ throw new Error(`terminal control identity changed after the final ${adapter.displayName} /status composer capture`);
417
531
  }
418
532
  return {
419
533
  terminalControl: verifiedImmediatelyBeforeEnter,
@@ -958,36 +1072,64 @@ function nativeInspectionSubmissionError(stage, error) {
958
1072
  }
959
1073
  return new NativeInspectionSubmissionError(stage, error instanceof Error ? error.message : String(error), { cause: error });
960
1074
  }
961
- function assertCodexStatusInspectionPlan(adapter, terminalControl, plan) {
962
- if (adapter.agent !== "codex") {
963
- throw new Error("native /status inspection is currently supported only for Codex");
964
- }
1075
+ function assertClosedStatusInspectionPlan(adapter, terminalControl, plan) {
965
1076
  if (!terminalControl.capabilities.includes("send_keys")) {
966
- throw new Error("Codex terminal input is not supported");
1077
+ throw new Error(`${adapter.displayName} terminal input is not supported`);
967
1078
  }
968
1079
  if (!terminalControl.capabilities.includes("screen_status")) {
969
- throw new Error("Codex terminal screen inspection is not supported");
1080
+ throw new Error(`${adapter.displayName} terminal screen inspection is not supported`);
970
1081
  }
1082
+ const codexProfile = adapter.agent === "codex" &&
1083
+ CODEX_NATIVE_STATUS_POPUP_BY_PROFILE[plan.behaviorProfile] !== undefined;
1084
+ const claudeProfile = adapter.agent === "claude" &&
1085
+ CLAUDE_NATIVE_STATUS_POPUP_BY_PROFILE[plan.behaviorProfile] !== undefined;
1086
+ const expectedSettle = codexProfile
1087
+ ? { minimumStableMs: CODEX_PASTE_ENTER_SETTLE_MS, maximumSettleMs: 2_000 }
1088
+ : plan.behaviorProfile === "claude-code-2.1.218-native-status"
1089
+ ? { minimumStableMs: 80, maximumSettleMs: 2_000 }
1090
+ : plan.behaviorProfile === "claude-code-2.1.226-native-status"
1091
+ ? { minimumStableMs: 80, maximumSettleMs: 5_000 }
1092
+ : undefined;
1093
+ const exactPresentation = codexProfile
1094
+ ? plan.expectedResult.presentation === "inline" &&
1095
+ plan.expectedResult.dismissal === undefined &&
1096
+ plan.composer.minimumStableMs === expectedSettle?.minimumStableMs &&
1097
+ plan.composer.maximumSettleMs === expectedSettle.maximumSettleMs
1098
+ : claudeProfile
1099
+ ? plan.expectedResult.presentation === "modal" &&
1100
+ plan.composer.minimumStableMs === expectedSettle?.minimumStableMs &&
1101
+ plan.composer.maximumSettleMs === expectedSettle.maximumSettleMs &&
1102
+ plan.expectedResult.dismissal?.expected === "idle_empty_composer" &&
1103
+ JSON.stringify(plan.expectedResult.dismissal.keys) ===
1104
+ JSON.stringify(["Escape"])
1105
+ : false;
971
1106
  if (plan.operation.kind !== "status" ||
972
1107
  plan.command !== "/status" ||
973
1108
  plan.effect !== "read_only" ||
974
1109
  plan.requiresIdle !== true ||
975
1110
  plan.composer.kind !== "exact" ||
976
1111
  !Number.isFinite(plan.composer.minimumStableMs) ||
977
- plan.composer.minimumStableMs < CODEX_PASTE_ENTER_SETTLE_MS ||
1112
+ plan.composer.minimumStableMs < 0 ||
1113
+ !Number.isFinite(plan.composer.maximumSettleMs) ||
1114
+ plan.composer.maximumSettleMs < plan.composer.minimumStableMs ||
978
1115
  plan.expectedResult.kind !== "native_status" ||
979
- ![
980
- "codex-tui-0.146.0",
981
- "codex-tui-0.146.1"
982
- ].includes(plan.behaviorProfile)) {
1116
+ !exactPresentation) {
983
1117
  throw new Error("refusing a non-closed or unverified native inspection plan");
984
1118
  }
985
1119
  }
986
- function assertNativeInspectionComposerSafe(inspection) {
1120
+ function assertClosedNativeInspectionDismissal(plan) {
1121
+ if (plan.expectedResult.presentation !== "modal" ||
1122
+ plan.expectedResult.dismissal?.expected !== "idle_empty_composer" ||
1123
+ JSON.stringify(plan.expectedResult.dismissal.keys) !==
1124
+ JSON.stringify(["Escape"])) {
1125
+ throw new Error("native inspection has no closed verified modal dismissal plan");
1126
+ }
1127
+ }
1128
+ function assertNativeInspectionComposerSafe(inspection, displayName = "terminal agent") {
987
1129
  if (inspection.approval.blocked ||
988
1130
  inspection.activity.state === "awaiting_approval" ||
989
1131
  inspection.activity.state === "working") {
990
- throw new Error("Codex became busy or blocked while its /status composer was settling");
1132
+ throw new Error(`${displayName} became busy or blocked while its /status composer was settling`);
991
1133
  }
992
1134
  // Codex's generic activity parser deliberately reports a non-empty slash
993
1135
  // composer as unknown. At this stage the caller has already proved an idle,
@@ -995,6 +1137,11 @@ function assertNativeInspectionComposerSafe(inspection) {
995
1137
  // capture below is the stronger continuation proof after AKK injected only
996
1138
  // the adapter-owned /status command.
997
1139
  }
1140
+ function exactNativeInspectionComposerCapture(agent, screen, plan) {
1141
+ return agent === "codex"
1142
+ ? exactCodexNativeInspectionComposerCapture(screen, plan)
1143
+ : exactClaudeNativeInspectionComposerCapture(screen, plan);
1144
+ }
998
1145
  function exactCodexNativeInspectionComposerCapture(screen, plan) {
999
1146
  const lines = screen.replace(/\r\n?/gu, "\n").split("\n");
1000
1147
  let currentComposerIndex = -1;
@@ -1024,9 +1171,8 @@ function exactCodexNativeInspectionComposerCapture(screen, plan) {
1024
1171
  if (popupRows.length === 0) {
1025
1172
  kind = "exact_slash_composer";
1026
1173
  }
1027
- else if (popupRows.length === 1 &&
1028
- popupRows[0].trimEnd() ===
1029
- CODEX_NATIVE_STATUS_POPUP_BY_PROFILE[plan.behaviorProfile]) {
1174
+ else if (JSON.stringify(popupRows.map((line) => line.trimEnd())) ===
1175
+ JSON.stringify(CODEX_NATIVE_STATUS_POPUP_BY_PROFILE[plan.behaviorProfile])) {
1030
1176
  kind = "exact_slash_popup";
1031
1177
  }
1032
1178
  else {
@@ -1037,6 +1183,114 @@ function exactCodexNativeInspectionComposerCapture(screen, plan) {
1037
1183
  digest: createHash("sha256").update(region.join("\n")).digest("hex")
1038
1184
  };
1039
1185
  }
1186
+ function exactClaudeNativeInspectionComposerCapture(screen, plan) {
1187
+ const frame = exactClaudeNativeInspectionComposerFrame(screen);
1188
+ if (!frame) {
1189
+ return undefined;
1190
+ }
1191
+ const { lines, openIndex, closeIndex, composerRows, trailing } = frame;
1192
+ if (composerRows.length !== 1 ||
1193
+ !/^\s*❯(?:\s|$)/u.test(composerRows[0]) ||
1194
+ composerRows[0].replace(/^\s*❯\s?/u, "").trimEnd() !== plan.command) {
1195
+ return undefined;
1196
+ }
1197
+ let kind;
1198
+ if (trailing.length === 0 || claudeNativeInspectionTrailingIsFooter(trailing)) {
1199
+ kind = "exact_slash_composer";
1200
+ }
1201
+ else {
1202
+ const suggestions = [];
1203
+ for (const line of trailing) {
1204
+ const trimmed = line.trim();
1205
+ if (trimmed.startsWith("/")) {
1206
+ suggestions.push(trimmed.replace(/\s+/gu, " "));
1207
+ }
1208
+ else if (suggestions.length > 0) {
1209
+ suggestions[suggestions.length - 1] +=
1210
+ ` ${trimmed.replace(/\s+/gu, " ")}`;
1211
+ }
1212
+ else {
1213
+ return undefined;
1214
+ }
1215
+ }
1216
+ if (!closedClaudeNativeStatusSuggestionsMatch(suggestions, CLAUDE_NATIVE_STATUS_POPUP_BY_PROFILE[plan.behaviorProfile])) {
1217
+ return undefined;
1218
+ }
1219
+ kind = "exact_slash_popup";
1220
+ }
1221
+ return {
1222
+ kind,
1223
+ digest: createHash("sha256")
1224
+ .update(lines.slice(openIndex, closeIndex + 1).concat(trailing).join("\n"))
1225
+ .digest("hex")
1226
+ };
1227
+ }
1228
+ /**
1229
+ * Claude truncates a suggestion row with a Unicode ellipsis at narrow pane
1230
+ * widths. Keep authorization closed by accepting only an exact ordered row or
1231
+ * an explicit ellipsis whose preceding text is an exact, non-trivial prefix of
1232
+ * that same profiled row. A caller still cannot introduce, omit, or reorder a
1233
+ * slash command.
1234
+ */
1235
+ function closedClaudeNativeStatusSuggestionsMatch(observed, expected) {
1236
+ if (!expected || observed.length !== expected.length) {
1237
+ return false;
1238
+ }
1239
+ return observed.every((row, index) => {
1240
+ const exact = expected[index];
1241
+ if (row === exact) {
1242
+ return true;
1243
+ }
1244
+ if (!row.endsWith("…")) {
1245
+ return false;
1246
+ }
1247
+ const prefix = row.slice(0, -1);
1248
+ const commandEnd = exact.indexOf(" ");
1249
+ return (commandEnd > 0 &&
1250
+ prefix.length >= commandEnd + 12 &&
1251
+ exact.startsWith(prefix));
1252
+ });
1253
+ }
1254
+ /**
1255
+ * Prove the exact idle input frame from a verified Claude Code native-status
1256
+ * profile. A loose or historical `❯` prompt is not enough to authorize even
1257
+ * the initial literal `/status` injection.
1258
+ */
1259
+ export function isExactClaudeNativeInspectionIdleComposer(screen) {
1260
+ const frame = exactClaudeNativeInspectionComposerFrame(screen);
1261
+ if (!frame) {
1262
+ return false;
1263
+ }
1264
+ return (frame.composerRows.length === 1 &&
1265
+ /^\s*❯\s*$/u.test(frame.composerRows[0]) &&
1266
+ (frame.trailing.length === 0 ||
1267
+ claudeNativeInspectionTrailingIsFooter(frame.trailing)));
1268
+ }
1269
+ function exactClaudeNativeInspectionComposerFrame(screen) {
1270
+ const lines = screen.replace(/\r\n?/gu, "\n").replace(/\u00a0/gu, " ")
1271
+ .split("\n");
1272
+ const dividerIndexes = lines
1273
+ .map((line, index) => /^\s*[─━]{8,}\s*$/u.test(line) ? index : -1)
1274
+ .filter((index) => index >= 0);
1275
+ if (dividerIndexes.length < 2) {
1276
+ return undefined;
1277
+ }
1278
+ const closeIndex = dividerIndexes.at(-1);
1279
+ const openIndex = dividerIndexes.at(-2);
1280
+ return {
1281
+ lines,
1282
+ openIndex,
1283
+ closeIndex,
1284
+ composerRows: lines.slice(openIndex + 1, closeIndex)
1285
+ .filter((line) => line.trim().length > 0),
1286
+ trailing: lines.slice(closeIndex + 1)
1287
+ .filter((line) => line.trim().length > 0)
1288
+ };
1289
+ }
1290
+ function claudeNativeInspectionTrailingIsFooter(lines) {
1291
+ return lines.length <= 2 && lines.every((line) => /^\s*(?:[⏵⏴]{1,2}|\?)\s*.*(?:shift\+tab|accept edits|bypass permissions|for shortcuts|← for agents)/iu
1292
+ .test(line));
1293
+ }
1040
1294
  function nativeInspectionScreenFingerprint(screen) {
1041
1295
  return `sha256:${createHash("sha256").update(screen).digest("hex")}`;
1042
1296
  }