@scotthuang/agent-knock-knock 0.12.36 → 0.13.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 (146) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +3 -0
  3. package/dist/src/agent-session-provider.d.ts +5 -0
  4. package/dist/src/agent-session-provider.js +10 -1
  5. package/dist/src/agent-session-provider.js.map +1 -1
  6. package/dist/src/callback-outbox-service.d.ts +2 -0
  7. package/dist/src/callback-outbox-service.js +1 -1
  8. package/dist/src/callback-outbox-service.js.map +1 -1
  9. package/dist/src/callback-transport.d.ts +7 -0
  10. package/dist/src/callback-transport.js +1 -1
  11. package/dist/src/callback-transport.js.map +1 -1
  12. package/dist/src/cli-core.js +35 -32
  13. package/dist/src/cli-core.js.map +1 -1
  14. package/dist/src/codex-store-adapter.d.ts +1 -1
  15. package/dist/src/codex-store-adapter.js +35 -8
  16. package/dist/src/codex-store-adapter.js.map +1 -1
  17. package/dist/src/deferred-foreground-authority-cli-adapter.d.ts +20 -0
  18. package/dist/src/deferred-foreground-authority-cli-adapter.js +216 -8
  19. package/dist/src/deferred-foreground-authority-cli-adapter.js.map +1 -1
  20. package/dist/src/host-adapter.d.ts +1 -1
  21. package/dist/src/host-adapter.js +1 -1
  22. package/dist/src/host-bridge-tools.js +2 -2
  23. package/dist/src/managed-turn-recovery-service.d.ts +8 -1
  24. package/dist/src/managed-turn-recovery-service.js +55 -13
  25. package/dist/src/managed-turn-recovery-service.js.map +1 -1
  26. package/dist/src/mutation-transaction.d.ts +1 -0
  27. package/dist/src/mutation-transaction.js +19 -15
  28. package/dist/src/mutation-transaction.js.map +1 -1
  29. package/dist/src/native-thread-lifecycle-cli-adapter.d.ts +39 -3
  30. package/dist/src/native-thread-lifecycle-cli-adapter.js +307 -7
  31. package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -1
  32. package/dist/src/openclaw-plugin-callback-adapter.js +17 -7
  33. package/dist/src/openclaw-plugin-callback-adapter.js.map +1 -1
  34. package/dist/src/openclaw-plugin-command-adapter.js +299 -79
  35. package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
  36. package/dist/src/openclaw-plugin-schemas.d.ts +57 -0
  37. package/dist/src/openclaw-plugin-schemas.js +59 -1
  38. package/dist/src/openclaw-plugin-schemas.js.map +1 -1
  39. package/dist/src/openclaw-private-authority-offers.d.ts +17 -0
  40. package/dist/src/openclaw-private-authority-offers.js +75 -3
  41. package/dist/src/openclaw-private-authority-offers.js.map +1 -1
  42. package/dist/src/store.d.ts +1 -1
  43. package/dist/src/store.js +6 -4
  44. package/dist/src/store.js.map +1 -1
  45. package/dist/src/terminal-acceptance-application-service.js +2 -2
  46. package/dist/src/terminal-acceptance-application-service.js.map +1 -1
  47. package/dist/src/terminal-acceptance-cli-adapter.d.ts +11 -1
  48. package/dist/src/terminal-acceptance-cli-adapter.js +290 -16
  49. package/dist/src/terminal-acceptance-cli-adapter.js.map +1 -1
  50. package/dist/src/terminal-action-projection.d.ts +1 -1
  51. package/dist/src/terminal-action-projection.js +6 -0
  52. package/dist/src/terminal-action-projection.js.map +1 -1
  53. package/dist/src/terminal-agent-adapter.d.ts +9 -0
  54. package/dist/src/terminal-agent-adapter.js.map +1 -1
  55. package/dist/src/terminal-agent-bridge.d.ts +52 -8
  56. package/dist/src/terminal-agent-bridge.js +133 -104
  57. package/dist/src/terminal-agent-bridge.js.map +1 -1
  58. package/dist/src/terminal-authority-policy.js +3 -0
  59. package/dist/src/terminal-authority-policy.js.map +1 -1
  60. package/dist/src/terminal-binding-authority.d.ts +2 -0
  61. package/dist/src/terminal-binding-authority.js +8 -0
  62. package/dist/src/terminal-binding-authority.js.map +1 -1
  63. package/dist/src/terminal-command-cli-adapter.d.ts +17 -1
  64. package/dist/src/terminal-command-cli-adapter.js +784 -286
  65. package/dist/src/terminal-command-cli-adapter.js.map +1 -1
  66. package/dist/src/terminal-delegate-cli-adapter.js +21 -7
  67. package/dist/src/terminal-delegate-cli-adapter.js.map +1 -1
  68. package/dist/src/terminal-dispatch-application.d.ts +3 -1
  69. package/dist/src/terminal-dispatch-application.js +13 -5
  70. package/dist/src/terminal-dispatch-application.js.map +1 -1
  71. package/dist/src/terminal-dispatch-composition.d.ts +43 -0
  72. package/dist/src/terminal-dispatch-execution.d.ts +2 -2
  73. package/dist/src/terminal-dispatch-execution.js +53 -3
  74. package/dist/src/terminal-dispatch-execution.js.map +1 -1
  75. package/dist/src/terminal-dispatch-policy.d.ts +20 -0
  76. package/dist/src/terminal-dispatch-policy.js +33 -1
  77. package/dist/src/terminal-dispatch-policy.js.map +1 -1
  78. package/dist/src/terminal-dispatch-presenter.d.ts +45 -0
  79. package/dist/src/terminal-dispatch-presenter.js +220 -18
  80. package/dist/src/terminal-dispatch-presenter.js.map +1 -1
  81. package/dist/src/terminal-dispatch-receipt.d.ts +5 -1
  82. package/dist/src/terminal-dispatch-receipt.js +26 -3
  83. package/dist/src/terminal-dispatch-receipt.js.map +1 -1
  84. package/dist/src/terminal-identity-authority-cli-adapter.js +103 -4
  85. package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -1
  86. package/dist/src/terminal-interaction-authority.d.ts +48 -1
  87. package/dist/src/terminal-interaction-authority.js +30 -0
  88. package/dist/src/terminal-interaction-authority.js.map +1 -1
  89. package/dist/src/terminal-interaction-cli-adapter.js +19 -9
  90. package/dist/src/terminal-interaction-cli-adapter.js.map +1 -1
  91. package/dist/src/terminal-interaction-core.d.ts +104 -0
  92. package/dist/src/terminal-interaction-core.js +407 -0
  93. package/dist/src/terminal-interaction-core.js.map +1 -0
  94. package/dist/src/terminal-interaction-protocol.d.ts +95 -0
  95. package/dist/src/terminal-interaction-protocol.js +201 -1
  96. package/dist/src/terminal-interaction-protocol.js.map +1 -1
  97. package/dist/src/terminal-list-cli-adapter.d.ts +5 -0
  98. package/dist/src/terminal-list-cli-adapter.js +190 -40
  99. package/dist/src/terminal-list-cli-adapter.js.map +1 -1
  100. package/dist/src/terminal-list-renderer.js +60 -7
  101. package/dist/src/terminal-list-renderer.js.map +1 -1
  102. package/dist/src/terminal-maintenance-cli-adapter.js +14 -3
  103. package/dist/src/terminal-maintenance-cli-adapter.js.map +1 -1
  104. package/dist/src/terminal-monitor-application-service.d.ts +1 -0
  105. package/dist/src/terminal-monitor-application-service.js +72 -10
  106. package/dist/src/terminal-monitor-application-service.js.map +1 -1
  107. package/dist/src/terminal-monitor-cli-adapter.d.ts +3 -0
  108. package/dist/src/terminal-monitor-cli-adapter.js +24 -8
  109. package/dist/src/terminal-monitor-cli-adapter.js.map +1 -1
  110. package/dist/src/terminal-monitor-state-cli-adapter.js +15 -2
  111. package/dist/src/terminal-monitor-state-cli-adapter.js.map +1 -1
  112. package/dist/src/terminal-mutation-cli-runtime.d.ts +11 -1
  113. package/dist/src/terminal-mutation-cli-runtime.js +9 -4
  114. package/dist/src/terminal-mutation-cli-runtime.js.map +1 -1
  115. package/dist/src/terminal-questionnaire-adapter.d.ts +1 -1
  116. package/dist/src/terminal-questionnaire-adapter.js +106 -39
  117. package/dist/src/terminal-questionnaire-adapter.js.map +1 -1
  118. package/dist/src/terminal-status-cli-adapter.d.ts +1 -7
  119. package/dist/src/terminal-status-cli-adapter.js +29 -3
  120. package/dist/src/terminal-status-cli-adapter.js.map +1 -1
  121. package/dist/src/terminal-status-facts.d.ts +17 -1
  122. package/dist/src/terminal-status-facts.js +59 -0
  123. package/dist/src/terminal-status-facts.js.map +1 -1
  124. package/dist/src/terminal-submission-acceptance.d.ts +37 -2
  125. package/dist/src/terminal-submission-acceptance.js +633 -30
  126. package/dist/src/terminal-submission-acceptance.js.map +1 -1
  127. package/dist/src/terminal-submission-facts.d.ts +5 -0
  128. package/dist/src/terminal-submission-facts.js.map +1 -1
  129. package/dist/src/terminal-watch-callback-cli-adapter.d.ts +2 -1
  130. package/dist/src/terminal-watch-callback-cli-adapter.js +2 -1
  131. package/dist/src/terminal-watch-callback-cli-adapter.js.map +1 -1
  132. package/dist/src/terminal-watch-cli-adapter.d.ts +6 -2
  133. package/dist/src/terminal-watch-cli-adapter.js +1051 -15
  134. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  135. package/dist/src/terminal-watch-service.d.ts +15 -1
  136. package/dist/src/terminal-watch-service.js +169 -13
  137. package/dist/src/terminal-watch-service.js.map +1 -1
  138. package/dist/src/terminal-watch-store.d.ts +72 -3
  139. package/dist/src/terminal-watch-store.js +407 -27
  140. package/dist/src/terminal-watch-store.js.map +1 -1
  141. package/docs/host-bridge-profiles.md +2 -2
  142. package/docs/quickstart-herdr.md +5 -3
  143. package/docs/quickstart-tmux.md +7 -5
  144. package/openclaw.plugin.json +8 -0
  145. package/package.json +1 -1
  146. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +15 -11
@@ -49,21 +49,25 @@ export function capabilityGatedRepositoryPairOperation(required, bound, operatio
49
49
  /** Acquire terminal -> writer -> optional state and release in reverse. */
50
50
  export async function withCanonicalMutationLocks(ports, operation) {
51
51
  const transaction = {};
52
- return withAcquiredScope(transaction, "terminal", ports.resources.terminal, ports.acquireTerminal, (terminal) => ports.withStoreWriter(async () => {
53
- const storeWriter = createScope(transaction, "storeWriter", ports.resources.storeWriter);
54
- const invoke = (state) => operation({ terminal, storeWriter, ...(state ? { state } : {}) }, ports.resources);
55
- try {
56
- if (!ports.acquireState)
57
- return await invoke();
58
- const stateResource = ports.resources.state;
59
- if (!stateResource)
60
- throw new Error("state mutation lock requires a canonical resource");
61
- return await withAcquiredScope(transaction, "state", stateResource, ports.acquireState, invoke);
62
- }
63
- finally {
64
- expireScope(storeWriter);
65
- }
66
- }));
52
+ return withAcquiredScope(transaction, "terminal", ports.resources.terminal, ports.acquireTerminal, async (terminal) => {
53
+ await ports.afterTerminalAcquired?.();
54
+ return ports.withStoreWriter(async () => {
55
+ const storeWriter = createScope(transaction, "storeWriter", ports.resources.storeWriter);
56
+ const invoke = (state) => operation({ terminal, storeWriter, ...(state ? { state } : {}) }, ports.resources);
57
+ try {
58
+ if (!ports.acquireState)
59
+ return await invoke();
60
+ const stateResource = ports.resources.state;
61
+ if (!stateResource) {
62
+ throw new Error("state mutation lock requires a canonical resource");
63
+ }
64
+ return await withAcquiredScope(transaction, "state", stateResource, ports.acquireState, invoke);
65
+ }
66
+ finally {
67
+ expireScope(storeWriter);
68
+ }
69
+ });
70
+ });
67
71
  }
68
72
  /** Add one state scope to the currently active terminal + writer transaction. */
69
73
  export async function withCanonicalStateMutationLock(scopes, resources, state, operation) {
@@ -1 +1 @@
1
- {"version":3,"file":"mutation-transaction.js","sourceRoot":"","sources":["../../src/mutation-transaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutation-transaction.js","sourceRoot":"","sources":["../../src/mutation-transaction.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,41 @@ import { type ManagedSessionState } from "./managed-session.js";
4
4
  import { type LifecycleTerminalObservation, type NativeThreadLifecycleQueryPorts } from "./native-thread-lifecycle-query-service.js";
5
5
  import { type Conversation } from "./protocol.js";
6
6
  import type { TerminalAgentAdapter, TerminalControlRef, TerminalRuntimeIdentity, TerminalThreadLifecycleCapabilities } from "./terminal-agent-adapter.js";
7
- import { type ResolvedTerminalConversation } from "./terminal-agent-bridge.js";
7
+ import { type ResolvedTerminalConversation, type TerminalAgentBridge } from "./terminal-agent-bridge.js";
8
8
  import { type CodexAllowedCompanionSet } from "./terminal-authority-policy.js";
9
9
  import type { TerminalNativeIdentity } from "./terminal-binding-authority.js";
10
10
  import type { TerminalDispatchLedgerDocument } from "./terminal-dispatch-ledger-codec.js";
11
11
  import type { TerminalRuntimeCliAdapter } from "./terminal-runtime-cli-adapter.js";
12
12
  export type NativeLifecycleCliOptions = Readonly<Record<string, unknown>>;
13
+ export declare const CODEX_FOREGROUND_IDENTIFICATION_TTL_MS = 30000;
14
+ export declare const CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES = 240;
15
+ /**
16
+ * Short-lived diagnostic evidence returned only to the in-process caller.
17
+ *
18
+ * This is deliberately not a Store binding or an authorization token. The
19
+ * caller must remain inside the same terminal lock and must still use the
20
+ * ordinary request-acceptance path before creating durable Session authority.
21
+ */
22
+ export interface CodexForegroundIdentificationProof {
23
+ readonly terminalId: string;
24
+ readonly pid: number;
25
+ readonly processUuid: string;
26
+ readonly processBirth: string;
27
+ readonly realCwd: string;
28
+ readonly nativeThreadId: string;
29
+ readonly agentVersion: string;
30
+ readonly behaviorProfile: string;
31
+ readonly evidenceFingerprint: string;
32
+ readonly postProbeScreenDigest: string;
33
+ readonly observationScrollbackLines: typeof CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES;
34
+ readonly observedAt: string;
35
+ readonly expiresAt: string;
36
+ readonly terminalSubmission: {
37
+ readonly command: "/status";
38
+ readonly enterCount: 1;
39
+ readonly materialization: NativeInspectionSubmission["materialization"];
40
+ };
41
+ }
13
42
  export interface NativeLifecycleSnapshot {
14
43
  readonly identity?: TerminalNativeIdentity;
15
44
  readonly runtimeIdentity?: TerminalNativeIdentity;
@@ -67,7 +96,7 @@ interface NativeLifecycleIdentityPorts {
67
96
  processBirth: string;
68
97
  };
69
98
  runtimeForLiveIdentity(input: {
70
- terminal: ResolvedTerminalConversation;
99
+ terminal: LifecycleTerminalObservation;
71
100
  identity?: TerminalNativeIdentity;
72
101
  expectedEmptyNativeSession?: boolean;
73
102
  physicalOnly?: boolean;
@@ -140,7 +169,13 @@ export interface NativeThreadLifecycleCliFacade {
140
169
  agentAdapter(options: NativeLifecycleCliOptions, agent: ExecutorKind): TerminalAgentAdapter;
141
170
  runList(options: NativeLifecycleCliOptions): Promise<void>;
142
171
  runInspect(options: NativeLifecycleCliOptions): Promise<void>;
143
- assertSameInspectionTerminal(expected: ResolvedTerminalConversation, actual: ResolvedTerminalConversation, stage: string): void;
172
+ runIdentifyForeground(options: NativeLifecycleCliOptions): Promise<void>;
173
+ identifyCodexForegroundWhileLocked(input: {
174
+ options: NativeLifecycleCliOptions;
175
+ terminal: LifecycleTerminalObservation;
176
+ expectedTerminalToken: string;
177
+ }): Promise<CodexForegroundIdentificationProof>;
178
+ assertSameInspectionTerminal(expected: LifecycleTerminalObservation, actual: LifecycleTerminalObservation, stage: string): void;
144
179
  codexLatentClearResumeObservation(input: {
145
180
  screen?: string;
146
181
  agentVersion?: string;
@@ -151,4 +186,5 @@ export interface NativeThreadLifecycleCliFacade {
151
186
  nativeInspectionComposerEmpty(agent: ExecutorKind, screen?: string): boolean;
152
187
  }
153
188
  export declare function createNativeThreadLifecycleCliAdapter(ports: CreateNativeThreadLifecycleCliAdapterInput): NativeThreadLifecycleCliFacade;
189
+ type NativeInspectionSubmission = Awaited<ReturnType<TerminalAgentBridge["submitNativeInspection"]>>;
154
190
  export {};
@@ -13,6 +13,8 @@ import { listManagedSessions, loadNativeThreadTransition } from "./session-store
13
13
  import { isExactClaudeNativeInspectionIdleComposer, NativeInspectionSubmissionError } from "./terminal-agent-bridge.js";
14
14
  import { terminalControlAliasMatches, selectRootTerminalProcesses, withCodexCompanionFences } from "./terminal-authority-policy.js";
15
15
  import { nonBlankString } from "./value-guards.js";
16
+ export const CODEX_FOREGROUND_IDENTIFICATION_TTL_MS = 30_000;
17
+ export const CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES = 240;
16
18
  export function createNativeThreadLifecycleCliAdapter(ports) {
17
19
  const app = new NativeThreadLifecycleCliApplication(ports);
18
20
  return Object.freeze({
@@ -24,6 +26,8 @@ export function createNativeThreadLifecycleCliAdapter(ports) {
24
26
  agentAdapter: (options, agent) => app.agentAdapter(options, agent),
25
27
  runList: (options) => app.runList(options),
26
28
  runInspect: (options) => app.runInspect(options),
29
+ runIdentifyForeground: (options) => app.runIdentifyForeground(options),
30
+ identifyCodexForegroundWhileLocked: (input) => app.identifyCodexForegroundWhileLocked(input),
27
31
  assertSameInspectionTerminal: (expected, actual, stage) => app.assertSameInspectionTerminal(expected, actual, stage),
28
32
  codexLatentClearResumeObservation,
29
33
  nativeInspectionComposerEmpty
@@ -323,6 +327,10 @@ class NativeThreadLifecycleCliApplication {
323
327
  }
324
328
  assertInspectionReady(input) {
325
329
  const { options, terminal, terminalStatus, session } = input;
330
+ if (terminalStatus?.interaction_state !== undefined) {
331
+ throw new Error(`terminal ${terminal.terminalControl.target} is waiting for a native ` +
332
+ "questionnaire response; answer or cancel it before native inspection");
333
+ }
326
334
  if (terminalStatus && (terminalStatus.reachable !== true ||
327
335
  terminalStatus.activity_state !== "idle" ||
328
336
  terminalStatus.approval_state.blocked === true)) {
@@ -462,6 +470,271 @@ class NativeThreadLifecycleCliApplication {
462
470
  throw new Error("Claude composer contains input or is not at the exact idle frame; refusing automated terminal input");
463
471
  }
464
472
  }
473
+ validateForegroundIdentificationOptions(options) {
474
+ if (options.command !== undefined || options.message !== undefined) {
475
+ throw new Error("foreground identification does not accept a command or message payload");
476
+ }
477
+ return required(nonBlankString(options.expectedTerminalToken), "--expected-terminal-token is required");
478
+ }
479
+ async runIdentifyForeground(options) {
480
+ const expectedTerminalToken = this.validateForegroundIdentificationOptions(options);
481
+ const terminal = await this.resolveLifecycleTerminal(options);
482
+ if (terminal.agent !== "codex") {
483
+ throw new Error("foreground identification currently supports only Codex terminals");
484
+ }
485
+ const storeDir = this.ports.state.storeDir(options);
486
+ const release = this.ports.state.acquireTerminal(storeDir, terminal.terminalControl, { timeoutMs: 30_000 });
487
+ try {
488
+ const proof = await this.identifyCodexForegroundWhileLocked({
489
+ options,
490
+ terminal,
491
+ expectedTerminalToken
492
+ });
493
+ this.ports.output.print({
494
+ status: "observed",
495
+ inspection: "identify_foreground",
496
+ terminal_id: proof.terminalId,
497
+ agent: "codex",
498
+ agent_version: proof.agentVersion,
499
+ behavior_profile: proof.behaviorProfile,
500
+ native_thread_id: proof.nativeThreadId,
501
+ foreground_proof: {
502
+ scope: "ephemeral_diagnostic_only",
503
+ observed_at: proof.observedAt,
504
+ expires_at: proof.expiresAt,
505
+ ttl_ms: CODEX_FOREGROUND_IDENTIFICATION_TTL_MS,
506
+ grants_authority: false
507
+ },
508
+ terminal_submission: {
509
+ command: proof.terminalSubmission.command,
510
+ enter_count: proof.terminalSubmission.enterCount,
511
+ materialization_kind: proof.terminalSubmission.materialization.kind
512
+ },
513
+ store_mutation: false,
514
+ session_created: false,
515
+ turn_created: false,
516
+ receipt_created: false,
517
+ monitor_created: false,
518
+ callback_created: false
519
+ });
520
+ }
521
+ finally {
522
+ release();
523
+ }
524
+ }
525
+ async identifyCodexForegroundWhileLocked(input) {
526
+ if (input.terminal.agent !== "codex") {
527
+ throw new Error("foreground identification currently supports only Codex terminals");
528
+ }
529
+ if (!nonBlankString(input.expectedTerminalToken)) {
530
+ throw new Error("foreground identification requires a terminal token");
531
+ }
532
+ const bridge = this.ports.runtime.forOptions(input.options).createBridge();
533
+ const physicalRuntime = this.ports.identity.runtimeForLiveIdentity({
534
+ terminal: input.terminal,
535
+ physicalOnly: true
536
+ });
537
+ const terminal = await bridge.resolveStoredTerminal("codex", input.terminal.pid, input.terminal.terminalControl, physicalRuntime);
538
+ this.assertSameInspectionTerminal(input.terminal, terminal, "while waiting for foreground-identification control");
539
+ const realCwd = this.realForegroundWorkspace(terminal);
540
+ const processIncarnation = this.ports.identity.processIncarnation(terminal.pid);
541
+ this.assertForegroundPhysicalToken({
542
+ terminal,
543
+ processIncarnation,
544
+ expectedTerminalToken: input.expectedTerminalToken
545
+ });
546
+ const runtimeFacade = this.ports.runtime.forOptions(input.options);
547
+ const agentVersion = required(nonBlankString(runtimeFacade.agentVersionForRunningProcess("codex", terminal.pid)), "Codex foreground identification requires a verified running version");
548
+ const adapter = runtimeFacade.createAgentRegistry().require("codex");
549
+ const capability = adapter.probeNativeInspection?.(agentVersion);
550
+ if (capability?.status !== "supported" ||
551
+ capability.statusInspection !== true) {
552
+ throw new Error(capability?.reason ??
553
+ "Codex foreground identification has no supported /status profile");
554
+ }
555
+ const plan = adapter.planNativeInspection?.({ kind: "status" }, capability);
556
+ if (!plan ||
557
+ plan.operation.kind !== "status" ||
558
+ plan.command !== "/status" ||
559
+ plan.effect !== "read_only" ||
560
+ plan.expectedResult.presentation !== "inline") {
561
+ throw new Error("the Codex adapter did not produce the closed inline /status plan");
562
+ }
563
+ const initialStatus = await bridge.status("codex", terminal.terminalControl, {
564
+ runtime: physicalRuntime,
565
+ scrollbackLines: CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES
566
+ });
567
+ this.assertInspectionReady({
568
+ options: input.options,
569
+ terminal,
570
+ terminalStatus: initialStatus
571
+ });
572
+ this.assertForegroundHasNoLifecycleTransition(input.options, terminal);
573
+ await this.assertInspectionComposerReady({
574
+ options: input.options,
575
+ terminal
576
+ });
577
+ const context = {
578
+ options: input.options,
579
+ terminal,
580
+ snapshot: {
581
+ codexCompanions: { additional: [] },
582
+ capabilities: adapter.probeThreadLifecycle?.(agentVersion) ?? {
583
+ status: "unknown",
584
+ agentVersion,
585
+ newThread: false,
586
+ resumeExact: false,
587
+ reason: "thread lifecycle capability is outside this diagnostic"
588
+ },
589
+ version: agentVersion,
590
+ bindingToken: input.expectedTerminalToken,
591
+ bindingTokens: [input.expectedTerminalToken]
592
+ },
593
+ bridge,
594
+ plan,
595
+ runtime: physicalRuntime,
596
+ expectedBindingToken: input.expectedTerminalToken,
597
+ foregroundBoundary: {
598
+ processUuid: processIncarnation.processUuid,
599
+ processBirth: processIncarnation.processBirth,
600
+ realCwd,
601
+ agentVersion,
602
+ expectedTerminalToken: input.expectedTerminalToken
603
+ }
604
+ };
605
+ const submission = await this.submitInspection(context);
606
+ try {
607
+ const observed = await this.observeStableInspection(context, submission);
608
+ const finalTerminal = await bridge.resolveStoredTerminal("codex", terminal.pid, terminal.terminalControl, physicalRuntime);
609
+ const finalStatus = required(await this.assertFreshForegroundBoundary({
610
+ context,
611
+ terminal: finalTerminal,
612
+ stage: "after foreground identification",
613
+ requireReadyScreen: true
614
+ }), "Codex foreground status revalidation is unavailable");
615
+ const nativeThreadId = required(isExactNativeThreadId(observed.observation.nativeThreadId)
616
+ ? observed.observation.nativeThreadId
617
+ : undefined, "Codex /status did not prove one exact foreground native thread");
618
+ const evidenceFingerprint = required(nonBlankString(observed.observation.evidenceFingerprint), "Codex /status did not produce exact evidence");
619
+ const postProbeScreenDigest = required(nonBlankString(finalStatus.screen.digest), "Codex foreground screen digest is unavailable");
620
+ const observedScreenDigest = required(bareNativeInspectionScreenDigest(observed.screenDigest), "Codex foreground observation screen digest is malformed");
621
+ if (observedScreenDigest !== postProbeScreenDigest) {
622
+ throw new Error("Codex screen changed after the stable /status observation");
623
+ }
624
+ const observedAt = new Date();
625
+ const proof = {
626
+ terminalId: terminal.conversationId,
627
+ pid: terminal.pid,
628
+ processUuid: processIncarnation.processUuid,
629
+ processBirth: processIncarnation.processBirth,
630
+ realCwd,
631
+ nativeThreadId,
632
+ agentVersion,
633
+ behaviorProfile: plan.behaviorProfile,
634
+ evidenceFingerprint,
635
+ postProbeScreenDigest,
636
+ observationScrollbackLines: CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES,
637
+ observedAt: observedAt.toISOString(),
638
+ expiresAt: new Date(observedAt.getTime() + CODEX_FOREGROUND_IDENTIFICATION_TTL_MS).toISOString(),
639
+ terminalSubmission: Object.freeze({
640
+ command: "/status",
641
+ enterCount: 1,
642
+ materialization: submission.materialization
643
+ })
644
+ };
645
+ return Object.freeze(proof);
646
+ }
647
+ catch (error) {
648
+ const detail = error instanceof Error ? error.message : String(error);
649
+ if (/do not retry automatically/iu.test(detail))
650
+ throw error;
651
+ throw new Error("Codex foreground-identification Enter was dispatched exactly once, " +
652
+ "but its postcondition became uncertain; do not retry automatically: " +
653
+ detail);
654
+ }
655
+ }
656
+ async assertFreshForegroundBoundary(input) {
657
+ const boundary = required(input.context.foregroundBoundary, "foreground-identification boundary is missing");
658
+ this.assertSameInspectionTerminal(input.context.terminal, input.terminal, input.stage);
659
+ if (this.realForegroundWorkspace(input.terminal) !== boundary.realCwd) {
660
+ throw new Error(`terminal real cwd changed ${input.stage}; refresh AKK list`);
661
+ }
662
+ const processIncarnation = this.ports.identity.processIncarnation(input.terminal.pid);
663
+ if (processIncarnation.processUuid !== boundary.processUuid ||
664
+ processIncarnation.processBirth !== boundary.processBirth) {
665
+ throw new Error(`Codex process incarnation changed ${input.stage}; refresh AKK list`);
666
+ }
667
+ this.assertForegroundPhysicalToken({
668
+ terminal: input.terminal,
669
+ processIncarnation,
670
+ expectedTerminalToken: boundary.expectedTerminalToken
671
+ });
672
+ const currentVersion = this.ports.runtime.forOptions(input.context.options)
673
+ .agentVersionForRunningProcess("codex", input.terminal.pid);
674
+ if (currentVersion !== boundary.agentVersion) {
675
+ throw new Error(`Codex version changed ${input.stage}; refresh AKK list`);
676
+ }
677
+ this.assertInspectionReady({
678
+ options: input.context.options,
679
+ terminal: input.terminal
680
+ });
681
+ this.assertForegroundHasNoLifecycleTransition(input.context.options, input.terminal);
682
+ if (!input.requireReadyScreen) {
683
+ return undefined;
684
+ }
685
+ const status = await input.context.bridge.status("codex", input.terminal.terminalControl, {
686
+ runtime: input.context.runtime,
687
+ scrollbackLines: CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES
688
+ });
689
+ this.assertInspectionReady({
690
+ options: input.context.options,
691
+ terminal: input.terminal,
692
+ terminalStatus: status
693
+ });
694
+ await this.assertInspectionComposerReady({
695
+ options: input.context.options,
696
+ terminal: input.terminal
697
+ });
698
+ return status;
699
+ }
700
+ assertForegroundPhysicalToken(input) {
701
+ const actual = unmanagedTerminalBindingToken({
702
+ terminalId: input.terminal.conversationId,
703
+ terminalControl: input.terminal.terminalControl,
704
+ agent: "codex",
705
+ pid: input.terminal.pid,
706
+ workspace: input.terminal.terminalControl.currentPath ?? "",
707
+ processUuid: input.processIncarnation.processUuid,
708
+ processBirth: input.processIncarnation.processBirth
709
+ });
710
+ if (actual !== input.expectedTerminalToken) {
711
+ throw new Error("the physical terminal token is stale; refresh AKK list");
712
+ }
713
+ }
714
+ realForegroundWorkspace(terminal) {
715
+ const cwd = required(nonBlankString(terminal.terminalControl.currentPath), "Codex terminal cwd is unavailable");
716
+ let realCwd;
717
+ try {
718
+ realCwd = fs.realpathSync(cwd);
719
+ }
720
+ catch {
721
+ throw new Error("Codex terminal cwd cannot be resolved exactly");
722
+ }
723
+ if (!fs.statSync(realCwd).isDirectory()) {
724
+ throw new Error("Codex terminal cwd is not a directory");
725
+ }
726
+ return realCwd;
727
+ }
728
+ assertForegroundHasNoLifecycleTransition(options, terminal) {
729
+ const storeDir = this.ports.state.storeDir(options);
730
+ const related = listManagedSessions(storeDir).filter((session) => Boolean(session.binding && terminalControlAliasMatches(session.binding.terminal_id, session.binding.terminal_control, terminal.conversationId, terminal.terminalControl)));
731
+ const unresolved = related.find((session) => ["transitioning", "quarantined"].includes(session.status) ||
732
+ this.ports.state.hasUnresolvedTransition(storeDir, session));
733
+ if (unresolved) {
734
+ throw new Error(`managed Session ${unresolved.session_id} has an unresolved ` +
735
+ "native-thread transition");
736
+ }
737
+ }
465
738
  validateInspectionOptions(options) {
466
739
  const inspection = required(nonBlankString(options.inspection), "--inspection is required");
467
740
  if (inspection !== "status") {
@@ -551,10 +824,20 @@ class NativeThreadLifecycleCliApplication {
551
824
  runtime: context.runtime,
552
825
  beforeEnter: async () => {
553
826
  const terminal = await context.bridge.resolveStoredTerminal(context.terminal.agent, context.terminal.pid, context.terminal.terminalControl, context.runtime);
554
- await this.assertFreshInspectionBoundary({
555
- context, terminal,
556
- stage: "immediately before native status submission"
557
- });
827
+ if (context.foregroundBoundary) {
828
+ await this.assertFreshForegroundBoundary({
829
+ context,
830
+ terminal,
831
+ stage: "immediately before native status submission",
832
+ requireReadyScreen: false
833
+ });
834
+ }
835
+ else {
836
+ await this.assertFreshInspectionBoundary({
837
+ context, terminal,
838
+ stage: "immediately before native status submission"
839
+ });
840
+ }
558
841
  }
559
842
  });
560
843
  }
@@ -610,9 +893,15 @@ class NativeThreadLifecycleCliApplication {
610
893
  : context.runtime;
611
894
  let fingerprint;
612
895
  let stable;
896
+ let stableScreenDigest;
613
897
  let count = 0;
614
898
  for (let attempt = 0; attempt < 50; attempt += 1) {
615
- const observed = await context.bridge.observeNativeInspection(context.terminal.agent, context.terminal.terminalControl, request, { runtime: postEnterRuntime, scrollbackLines: 240 });
899
+ const observed = await context.bridge.observeNativeInspection(context.terminal.agent, context.terminal.terminalControl, request, {
900
+ runtime: postEnterRuntime,
901
+ scrollbackLines: context.foregroundBoundary
902
+ ? CODEX_FOREGROUND_IDENTIFICATION_SCROLLBACK_LINES
903
+ : 240
904
+ });
616
905
  if (freshInspectionObservation(context.plan, submission.preEnterScreenDigest, observed)) {
617
906
  if (fingerprint === observed.observation.evidenceFingerprint)
618
907
  count += 1;
@@ -621,20 +910,27 @@ class NativeThreadLifecycleCliApplication {
621
910
  count = 1;
622
911
  }
623
912
  stable = observed.observation;
913
+ stableScreenDigest = observed.screenDigest;
624
914
  if (count >= 2)
625
915
  break;
626
916
  }
627
917
  else {
628
918
  fingerprint = undefined;
629
919
  stable = undefined;
920
+ stableScreenDigest = undefined;
630
921
  count = 0;
631
922
  }
632
923
  await this.ports.runtime.sleep(100);
633
924
  }
634
- if (!stable || count < 2) {
925
+ if (!stable || !stableScreenDigest || count < 2) {
635
926
  throw new Error("native status inspection Enter was dispatched exactly once, but a fresh exact status result was not proven; do not retry automatically");
636
927
  }
637
- return { observation: stable, request, postEnterRuntime };
928
+ return {
929
+ observation: stable,
930
+ request,
931
+ postEnterRuntime,
932
+ screenDigest: stableScreenDigest
933
+ };
638
934
  }
639
935
  async dismissInspection(context, observed) {
640
936
  if (context.plan.expectedResult.presentation !== "modal")
@@ -724,12 +1020,16 @@ class NativeThreadLifecycleCliApplication {
724
1020
  });
725
1021
  }
726
1022
  }
1023
+ function bareNativeInspectionScreenDigest(fingerprint) {
1024
+ return /^sha256:([0-9a-f]{64})$/u.exec(fingerprint)?.[1];
1025
+ }
727
1026
  function freshInspectionObservation(plan, preEnterScreenDigest, observed) {
728
1027
  return observed.status.reachable === true &&
729
1028
  (plan.expectedResult.presentation === "inline"
730
1029
  ? observed.status.activity_state === "idle"
731
1030
  : !["working", "awaiting_approval"].includes(observed.status.activity_state)) &&
732
1031
  observed.status.approval_state.blocked !== true &&
1032
+ observed.status.interaction_state === undefined &&
733
1033
  observed.screenDigest !== preEnterScreenDigest &&
734
1034
  observed.observation.status === "observed" &&
735
1035
  observed.observation.result?.kind === "native_status" &&