@scotthuang/agent-knock-knock 0.13.11 → 0.13.12

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 (125) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +8 -9
  3. package/dist/src/codex-app-server-interaction-client.d.ts +72 -0
  4. package/dist/src/codex-app-server-interaction-client.js +310 -0
  5. package/dist/src/codex-app-server-interaction-client.js.map +1 -0
  6. package/dist/src/codex-app-server-questionnaire.d.ts +73 -0
  7. package/dist/src/codex-app-server-questionnaire.js +366 -0
  8. package/dist/src/codex-app-server-questionnaire.js.map +1 -0
  9. package/dist/src/codex-app-server-read-client.d.ts +118 -0
  10. package/dist/src/codex-app-server-read-client.js +300 -0
  11. package/dist/src/codex-app-server-read-client.js.map +1 -0
  12. package/dist/src/codex-app-server-transport.d.ts +11 -0
  13. package/dist/src/codex-app-server-transport.js +47 -0
  14. package/dist/src/codex-app-server-transport.js.map +1 -0
  15. package/dist/src/codex-async-question-adapter.d.ts +5 -0
  16. package/dist/src/codex-async-question-adapter.js +58 -17
  17. package/dist/src/codex-async-question-adapter.js.map +1 -1
  18. package/dist/src/codex-fullscreen-composer-proof.d.ts +23 -0
  19. package/dist/src/codex-fullscreen-composer-proof.js +124 -0
  20. package/dist/src/codex-fullscreen-composer-proof.js.map +1 -0
  21. package/dist/src/codex-lifecycle-compatibility.d.ts +2 -0
  22. package/dist/src/codex-lifecycle-compatibility.js +8 -1
  23. package/dist/src/codex-lifecycle-compatibility.js.map +1 -1
  24. package/dist/src/codex-paginated-answer-proof.d.ts +25 -0
  25. package/dist/src/codex-paginated-answer-proof.js +189 -0
  26. package/dist/src/codex-paginated-answer-proof.js.map +1 -0
  27. package/dist/src/codex-paginated-async-answer.d.ts +36 -0
  28. package/dist/src/codex-paginated-async-answer.js +321 -0
  29. package/dist/src/codex-paginated-async-answer.js.map +1 -0
  30. package/dist/src/codex-paginated-async-response.d.ts +21 -0
  31. package/dist/src/codex-paginated-async-response.js +116 -0
  32. package/dist/src/codex-paginated-async-response.js.map +1 -0
  33. package/dist/src/codex-paginated-observation.d.ts +30 -0
  34. package/dist/src/codex-paginated-observation.js +139 -0
  35. package/dist/src/codex-paginated-observation.js.map +1 -0
  36. package/dist/src/codex-paginated-questionnaire-runtime.d.ts +33 -0
  37. package/dist/src/codex-paginated-questionnaire-runtime.js +157 -0
  38. package/dist/src/codex-paginated-questionnaire-runtime.js.map +1 -0
  39. package/dist/src/codex-paginated-task.d.ts +77 -0
  40. package/dist/src/codex-paginated-task.js +440 -0
  41. package/dist/src/codex-paginated-task.js.map +1 -0
  42. package/dist/src/codex-paginated-thread-binding.d.ts +18 -0
  43. package/dist/src/codex-paginated-thread-binding.js +55 -0
  44. package/dist/src/codex-paginated-thread-binding.js.map +1 -0
  45. package/dist/src/codex-paginated-thread-facts.d.ts +10 -0
  46. package/dist/src/codex-paginated-thread-facts.js +2 -0
  47. package/dist/src/codex-paginated-thread-facts.js.map +1 -0
  48. package/dist/src/codex-paginated-watch.d.ts +29 -0
  49. package/dist/src/codex-paginated-watch.js +107 -0
  50. package/dist/src/codex-paginated-watch.js.map +1 -0
  51. package/dist/src/codex-terminal-agent-adapter.js +7 -6
  52. package/dist/src/codex-terminal-agent-adapter.js.map +1 -1
  53. package/dist/src/store.d.ts +1 -1
  54. package/dist/src/store.js +2 -2
  55. package/dist/src/store.js.map +1 -1
  56. package/dist/src/terminal-agent-adapter.d.ts +3 -0
  57. package/dist/src/terminal-agent-adapter.js.map +1 -1
  58. package/dist/src/terminal-agent-bridge.d.ts +13 -5
  59. package/dist/src/terminal-agent-bridge.js +27 -103
  60. package/dist/src/terminal-agent-bridge.js.map +1 -1
  61. package/dist/src/terminal-approval-fingerprint.d.ts +7 -0
  62. package/dist/src/terminal-approval-fingerprint.js +107 -0
  63. package/dist/src/terminal-approval-fingerprint.js.map +1 -0
  64. package/dist/src/terminal-command-cli-ports.d.ts +1 -0
  65. package/dist/src/terminal-composer-classifier.js +38 -1
  66. package/dist/src/terminal-composer-classifier.js.map +1 -1
  67. package/dist/src/terminal-control-provider.d.ts +6 -2
  68. package/dist/src/terminal-control-provider.js +4 -4
  69. package/dist/src/terminal-control-provider.js.map +1 -1
  70. package/dist/src/terminal-human-explicit-send-cli-adapter.js +22 -15
  71. package/dist/src/terminal-human-explicit-send-cli-adapter.js.map +1 -1
  72. package/dist/src/terminal-interaction-core.js +2 -1
  73. package/dist/src/terminal-interaction-core.js.map +1 -1
  74. package/dist/src/terminal-interaction-response-bridge.d.ts +21 -1
  75. package/dist/src/terminal-interaction-response-bridge.js +147 -3
  76. package/dist/src/terminal-interaction-response-bridge.js.map +1 -1
  77. package/dist/src/terminal-list-cli-adapter.js +4 -4
  78. package/dist/src/terminal-list-cli-adapter.js.map +1 -1
  79. package/dist/src/terminal-list-facts.d.ts +1 -1
  80. package/dist/src/terminal-list-facts.js +1 -1
  81. package/dist/src/terminal-list-facts.js.map +1 -1
  82. package/dist/src/terminal-managed-send-cli-adapter.d.ts +1 -1
  83. package/dist/src/terminal-managed-send-cli-adapter.js +27 -0
  84. package/dist/src/terminal-managed-send-cli-adapter.js.map +1 -1
  85. package/dist/src/terminal-model-control-bridge.d.ts +1 -1
  86. package/dist/src/terminal-model-control-bridge.js +1 -1
  87. package/dist/src/terminal-model-control-bridge.js.map +1 -1
  88. package/dist/src/terminal-model-control-profile.d.ts +2 -1
  89. package/dist/src/terminal-model-control-profile.js +24 -1
  90. package/dist/src/terminal-model-control-profile.js.map +1 -1
  91. package/dist/src/terminal-model-control.js +61 -21
  92. package/dist/src/terminal-model-control.js.map +1 -1
  93. package/dist/src/terminal-native-inspection-bridge.d.ts +6 -1
  94. package/dist/src/terminal-native-inspection-bridge.js +116 -79
  95. package/dist/src/terminal-native-inspection-bridge.js.map +1 -1
  96. package/dist/src/terminal-questionnaire-adapter.js +19 -16
  97. package/dist/src/terminal-questionnaire-adapter.js.map +1 -1
  98. package/dist/src/terminal-runtime-cli-adapter.js +16 -0
  99. package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
  100. package/dist/src/terminal-send-watch-policy.d.ts +38 -0
  101. package/dist/src/terminal-send-watch-policy.js +77 -0
  102. package/dist/src/terminal-send-watch-policy.js.map +1 -0
  103. package/dist/src/terminal-submission-facts.d.ts +1 -1
  104. package/dist/src/terminal-submission-facts.js +11 -9
  105. package/dist/src/terminal-submission-facts.js.map +1 -1
  106. package/dist/src/terminal-watch-cli-adapter.d.ts +9 -1
  107. package/dist/src/terminal-watch-cli-adapter.js +198 -210
  108. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  109. package/dist/src/terminal-watch-codec.js +23 -1
  110. package/dist/src/terminal-watch-codec.js.map +1 -1
  111. package/dist/src/terminal-watch-interaction-runtime.js +27 -6
  112. package/dist/src/terminal-watch-interaction-runtime.js.map +1 -1
  113. package/dist/src/terminal-watch-presentation.d.ts +4 -0
  114. package/dist/src/terminal-watch-presentation.js +153 -0
  115. package/dist/src/terminal-watch-presentation.js.map +1 -0
  116. package/dist/src/terminal-watch-record.d.ts +4 -2
  117. package/dist/src/terminal-watch-record.js +15 -10
  118. package/dist/src/terminal-watch-record.js.map +1 -1
  119. package/dist/src/terminal-watch-service.js +13 -1
  120. package/dist/src/terminal-watch-service.js.map +1 -1
  121. package/docs/codex-0.158.0-compatibility.md +129 -0
  122. package/docs/quickstart-herdr.md +3 -3
  123. package/docs/quickstart-tmux.md +4 -4
  124. package/package.json +6 -3
  125. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +14 -12
@@ -1,10 +1,14 @@
1
+ import { respondCodexPaginatedAsyncQuestion } from "./codex-paginated-async-response.js";
2
+ import { publicTerminalWatch, terminalWatchCapturedAgentVersion } from "./terminal-watch-presentation.js";
1
3
  import { createHash } from "node:crypto";
2
4
  import path from "node:path";
5
+ import { CodexLegacyThreadHistoryError } from "./codex-paginated-observation.js";
6
+ import { capturePaginatedWatchAnchor as capturePaginatedAnchor, isPaginatedSendWatch, paginatedWatchProcessMatches, observePaginatedWatch, refreshPaginatedResponseForeground } from "./codex-paginated-watch.js";
7
+ import { observeCodexPaginatedBlockingQuestion, respondCodexPaginatedBlockingQuestion } from "./codex-paginated-questionnaire-runtime.js";
8
+ import { selectCodexUserExplicitSendWatchSource } from "./terminal-send-watch-policy.js";
3
9
  import { callbackRouteFingerprint } from "./callback-route-authority.js";
4
10
  import { createTerminalWatchOpenClawCallbackRoute, parseCallbackRoute } from "./callback-transport.js";
5
11
  import { captureClaudeTranscriptAnchor, captureClaudeHumanStartedActiveTaskAnchor, observeClaudeUserExplicitFallbackTranscript, observeClaudeHumanStartedActiveTask } from "./claude-local-transcript-provider.js";
6
- import { claudeRuntimeCompatibilityWarning } from "./claude-lifecycle-compatibility.js";
7
- import { codexRuntimeCompatibilityProfile } from "./codex-lifecycle-compatibility.js";
8
12
  import { codexAsyncQuestionMainComposerVisible } from "./codex-async-question-adapter.js";
9
13
  import { hostProfileCallbackRouteMatchesRuntime } from "./host-profile-callback-transport.js";
10
14
  import { captureTerminalInteractionRuntimeOffer, TerminalInteractionDispatchReservedError, TerminalInteractionInputNotStartedError } from "./terminal-agent-bridge.js";
@@ -120,46 +124,9 @@ export function createTerminalWatchCliAdapter(dependencies) {
120
124
  const rawTerminal = observed.rawTerminal;
121
125
  assertSameUserExplicitFallbackTerminal(input.terminal, rawTerminal);
122
126
  const agentVersion = requiredString(rawTerminal.agent_version, "running coding-agent version");
123
- let anchor;
124
- if (input.terminal.agent === "codex") {
125
- const inventory = rawTerminal._codex_open_root_rollout_inventory;
126
- const acceptanceAnchor = isRecord(inventory)
127
- ? captureCodexCandidateSetRolloutAcceptanceAnchor({
128
- inventory: inventory,
129
- now: dependencies.now()
130
- })
131
- : captureCodexRolloutAcceptanceAnchor({
132
- nativeThreadId: requiredString(rawTerminal.native_agent_session_id, "Codex native thread id"),
133
- processUuid: requiredString(rawTerminal.native_agent_process_uuid, "Codex process UUID"),
134
- processBirth: requiredString(rawTerminal.native_agent_process_birth, "Codex process birth"),
135
- mode: "existing",
136
- rollout: codexIdentity(rawTerminal).rollout,
137
- now: dependencies.now()
138
- });
139
- anchor = createCodexUserExplicitFallbackWatchAnchor({
140
- acceptanceAnchor,
141
- requestHash: input.requestHash,
142
- codexVersion: agentVersion
143
- });
144
- }
145
- else {
146
- const transcriptAnchor = captureClaudeTranscriptAnchor({
147
- sessionId: requiredString(rawTerminal.native_agent_session_id, "Claude native session id"),
148
- cwd: terminalWorkspace(rawTerminal),
149
- pid: positiveInteger(rawTerminal.pid, "Claude PID"),
150
- claudeHome: stringValue(input.options.claudeHome),
151
- agentRows: dependencies.loadClaudeAgentRows(input.options, { required: true }),
152
- now: dependencies.now()
153
- });
154
- if (!transcriptAnchor) {
155
- throw new Error("Claude transcript anchor is unavailable before terminal input");
156
- }
157
- anchor = createClaudeUserExplicitFallbackWatchAnchor({
158
- transcriptAnchor,
159
- requestHash: input.requestHash,
160
- claudeVersion: agentVersion
161
- });
162
- }
127
+ const anchor = input.terminal.agent === "codex"
128
+ ? await captureCodexFallbackWatchAnchor(input, rawTerminal, agentVersion, dependencies)
129
+ : captureClaudeFallbackWatchAnchor(input, rawTerminal, agentVersion, dependencies);
163
130
  return {
164
131
  watchId: terminalUserExplicitFallbackWatchId({
165
132
  messageId: input.messageId,
@@ -217,7 +184,7 @@ export function createTerminalWatchCliAdapter(dependencies) {
217
184
  catch (error) {
218
185
  const existing = service.list().find((candidate) => candidate.watch_id === input.prepared.watchId);
219
186
  if (!existing ||
220
- !isUserExplicitFallbackWatch(existing) ||
187
+ !(isUserExplicitFallbackWatch(existing) || isPaginatedSendWatch(existing)) ||
221
188
  existing.anchor.anchor_fingerprint !==
222
189
  input.prepared.anchor.anchor_fingerprint) {
223
190
  throw error;
@@ -227,7 +194,9 @@ export function createTerminalWatchCliAdapter(dependencies) {
227
194
  return {
228
195
  callback_expected: true,
229
196
  callback_mode: "terminal_watch",
230
- watch_id: watch.watch_id
197
+ watch_id: watch.watch_id,
198
+ watch_mode: "exact_task",
199
+ confidence: "exact"
231
200
  };
232
201
  }
233
202
  async function bestEffortStabilizePriorFallbackWatch(options, terminalId, requestHash) {
@@ -254,13 +223,15 @@ export function createTerminalWatchCliAdapter(dependencies) {
254
223
  function userExplicitFallbackWatchReceipt(input) {
255
224
  try {
256
225
  const watch = serviceFor(input.options).get(input.watchId);
257
- if (!isUserExplicitFallbackWatch(watch) || !watch.callback_route) {
226
+ if (!(isUserExplicitFallbackWatch(watch) || isPaginatedSendWatch(watch)) || !watch.callback_route) {
258
227
  return undefined;
259
228
  }
260
229
  return {
261
230
  callback_expected: true,
262
231
  callback_mode: "terminal_watch",
263
- watch_id: watch.watch_id
232
+ watch_id: watch.watch_id,
233
+ watch_mode: "exact_task",
234
+ confidence: "exact"
264
235
  };
265
236
  }
266
237
  catch {
@@ -285,7 +256,9 @@ export function createTerminalWatchCliAdapter(dependencies) {
285
256
  const warnings = [];
286
257
  let anchor;
287
258
  try {
288
- anchor = captureTerminalWatchAnchor(agent, rawTerminal, options, dependencies);
259
+ anchor = agent === "codex" && rawTerminal.agent_version === "0.158.0"
260
+ ? await capturePaginatedWatchAnchorWithLock(rawTerminal, options, dependencies)
261
+ : captureTerminalWatchAnchor(agent, rawTerminal, options, dependencies);
289
262
  }
290
263
  catch (error) {
291
264
  warnings.push(`exact_task_anchor_unavailable: ${safeDiagnostic(error)}`);
@@ -481,20 +454,57 @@ function createTerminalWatchInteractionResponder(dependencies, serviceFor) {
481
454
  if (!bridge) {
482
455
  throw new Error("terminal interaction bridge is unavailable");
483
456
  }
457
+ if (runtime.codexPaginatedThread && executableInteraction.projection.kind === "async_question") {
458
+ await refreshPaginatedResponseForeground(bridge, terminalControl, runtime, dependencies.now);
459
+ }
484
460
  const attemptId = dependencies.randomUUID();
485
461
  const responseHash = hashTerminalInteractionResponse(response);
486
462
  const reservation = { attemptId, responseHash };
487
463
  const result = await executeTerminalInteractionResponseTransaction({
488
464
  reservationFailureFence: "confirmed",
489
- dispatch: (hooks) => bridge.respondInteraction(current.agent, terminalControl, response, {
490
- agentVersion: version,
491
- expectedFingerprint,
492
- expectedExpiresAt,
493
- scrollbackLines: Number(options.scrollbackLines ?? 120),
494
- runtime,
495
- authorize: hooks.authorize,
496
- beforeDispatch: hooks.beforeDispatch
497
- }),
465
+ dispatch: (hooks) => "schema" in current.observation_checkpoint &&
466
+ current.observation_checkpoint.schema === "agent-knock-knock/codex-paginated-task-checkpoint" &&
467
+ executableInteraction.projection.kind === "questionnaire"
468
+ ? respondCodexPaginatedBlockingQuestion({
469
+ watch: current, checkpoint: current.observation_checkpoint, terminalControl,
470
+ response, expectedFingerprint, now: dependencies.now,
471
+ authorize: hooks.authorize, beforeDispatch: hooks.beforeDispatch,
472
+ persistDraft: (draft) => {
473
+ current = repository.withWriterLease((scope) => scope.withWatchLock(watchId, () => {
474
+ const latest = scope.load(watchId);
475
+ const checkpoint = latest.observation_checkpoint;
476
+ if (!("schema" in checkpoint) || checkpoint.schema !== "agent-knock-knock/codex-paginated-task-checkpoint") {
477
+ throw new Error("Codex blocking question checkpoint changed");
478
+ }
479
+ const nextCheckpoint = { ...checkpoint };
480
+ if (draft)
481
+ nextCheckpoint.blocking_question_draft = draft;
482
+ else
483
+ delete nextCheckpoint.blocking_question_draft;
484
+ return scope.save({ ...latest,
485
+ observation_checkpoint: nextCheckpoint,
486
+ updated_at: dependencies.now().toISOString()
487
+ }, { expectedRevision: terminalWatchRevision(latest) });
488
+ }));
489
+ }
490
+ })
491
+ : runtime.codexPaginatedThread && executableInteraction.projection.kind === "async_question"
492
+ ? respondCodexPaginatedAsyncQuestion({
493
+ bridge, terminalControl, terminalEvidence: current.terminal.terminal_endpoint,
494
+ runtime, response, now: dependencies.now,
495
+ options: { agentVersion: version, expectedFingerprint, expectedExpiresAt,
496
+ scrollbackLines: Number(options.scrollbackLines ?? 120), runtime,
497
+ authorize: hooks.authorize, beforeDispatch: hooks.beforeDispatch }
498
+ })
499
+ : bridge.respondInteraction(current.agent, terminalControl, response, {
500
+ agentVersion: version,
501
+ expectedFingerprint,
502
+ expectedExpiresAt,
503
+ scrollbackLines: Number(options.scrollbackLines ?? 120),
504
+ runtime,
505
+ authorize: hooks.authorize,
506
+ beforeDispatch: hooks.beforeDispatch
507
+ }),
498
508
  authorize: ({ projection, fingerprint }) => {
499
509
  const latest = repository.load(watchId);
500
510
  const interaction = requiredExecutableWatchInteraction(latest, interactionId, expectedFingerprint);
@@ -743,6 +753,9 @@ function sameManualWatchTarget(watch, agent, terminal, anchor) {
743
753
  function sameManualWatchAnchorTarget(left, right) {
744
754
  if (left.schema !== right.schema)
745
755
  return false;
756
+ if (left.schema === "agent-knock-knock/codex-paginated-task-anchor" && right.schema === left.schema) {
757
+ return samePaginatedWatchTask(left, right);
758
+ }
746
759
  if (left.schema ===
747
760
  "agent-knock-knock/codex-human-started-active-task-anchor" &&
748
761
  right.schema === left.schema) {
@@ -755,11 +768,7 @@ function sameManualWatchAnchorTarget(left, right) {
755
768
  if (left.schema ===
756
769
  "agent-knock-knock/claude-human-started-active-task-anchor" &&
757
770
  right.schema === left.schema) {
758
- return left.prompt_uuid === right.prompt_uuid &&
759
- left.pid === right.pid &&
760
- left.agent_started_at_ms === right.agent_started_at_ms &&
761
- left.device === right.device &&
762
- left.inode === right.inode;
771
+ return sameClaudeWatchTask(left, right);
763
772
  }
764
773
  if (left.schema === "agent-knock-knock/terminal-activity-watch-anchor" &&
765
774
  right.schema === left.schema) {
@@ -769,6 +778,18 @@ function sameManualWatchAnchorTarget(left, right) {
769
778
  }
770
779
  return left.anchor_fingerprint === right.anchor_fingerprint;
771
780
  }
781
+ function sameClaudeWatchTask(left, right) {
782
+ return left.prompt_uuid === right.prompt_uuid &&
783
+ left.pid === right.pid &&
784
+ left.agent_started_at_ms === right.agent_started_at_ms &&
785
+ left.device === right.device &&
786
+ left.inode === right.inode;
787
+ }
788
+ function samePaginatedWatchTask(left, right) {
789
+ return left.native_thread_id === right.native_thread_id && left.turn_id === right.turn_id &&
790
+ left.process_uuid === right.process_uuid && left.process_birth === right.process_birth &&
791
+ left.origin === right.origin && left.codex_home === right.codex_home;
792
+ }
772
793
  function optionalIdentityCompatible(left, right) {
773
794
  return left === undefined || right === undefined || left === right;
774
795
  }
@@ -794,6 +815,92 @@ function terminalControlForWatch(terminal) {
794
815
  }
795
816
  return terminal.terminal_control;
796
817
  }
818
+ async function captureCodexFallbackWatchAnchor(input, rawTerminal, agentVersion, dependencies) {
819
+ let inventory = rawTerminal._codex_open_root_rollout_inventory;
820
+ let paginated;
821
+ if (agentVersion === "0.158.0") {
822
+ try {
823
+ paginated = await capturePaginatedWatchAnchor(rawTerminal, input.options, dependencies, input.requestText === undefined ? input.requestHash
824
+ : createHash("sha256").update(input.requestText.replace(/\r\n?/gu, "\n").trim()).digest("hex"));
825
+ }
826
+ catch (error) {
827
+ if (!(error instanceof CodexLegacyThreadHistoryError) || !isRecord(inventory) || !Array.isArray(inventory.roots))
828
+ throw error;
829
+ const roots = inventory.roots.filter((root) => root.sessionId === error.threadId);
830
+ if (roots.length !== 1)
831
+ throw error;
832
+ inventory = { ...inventory, roots };
833
+ }
834
+ }
835
+ const source = selectCodexUserExplicitSendWatchSource({
836
+ agentVersion,
837
+ legacyRootCount: isRecord(inventory) && Array.isArray(inventory.roots) ? inventory.roots.length : 0,
838
+ paginatedAnchorAvailable: paginated !== undefined
839
+ });
840
+ if (source.source === "none")
841
+ throw new Error(source.warning);
842
+ if (paginated) {
843
+ return paginated;
844
+ }
845
+ else {
846
+ const acceptanceAnchor = isRecord(inventory)
847
+ ? captureCodexCandidateSetRolloutAcceptanceAnchor({
848
+ inventory: inventory,
849
+ now: dependencies.now()
850
+ })
851
+ : captureCodexRolloutAcceptanceAnchor({
852
+ nativeThreadId: requiredString(rawTerminal.native_agent_session_id, "Codex native thread id"),
853
+ processUuid: requiredString(rawTerminal.native_agent_process_uuid, "Codex process UUID"),
854
+ processBirth: requiredString(rawTerminal.native_agent_process_birth, "Codex process birth"),
855
+ mode: "existing",
856
+ rollout: codexIdentity(rawTerminal).rollout,
857
+ now: dependencies.now()
858
+ });
859
+ return createCodexUserExplicitFallbackWatchAnchor({
860
+ acceptanceAnchor,
861
+ requestHash: input.requestHash,
862
+ codexVersion: agentVersion
863
+ });
864
+ }
865
+ }
866
+ function captureClaudeFallbackWatchAnchor(input, rawTerminal, agentVersion, dependencies) {
867
+ const transcriptAnchor = captureClaudeTranscriptAnchor({
868
+ sessionId: requiredString(rawTerminal.native_agent_session_id, "Claude native session id"),
869
+ cwd: terminalWorkspace(rawTerminal),
870
+ pid: positiveInteger(rawTerminal.pid, "Claude PID"),
871
+ claudeHome: stringValue(input.options.claudeHome),
872
+ agentRows: dependencies.loadClaudeAgentRows(input.options, { required: true }),
873
+ now: dependencies.now()
874
+ });
875
+ if (!transcriptAnchor) {
876
+ throw new Error("Claude transcript anchor is unavailable before terminal input");
877
+ }
878
+ return createClaudeUserExplicitFallbackWatchAnchor({
879
+ transcriptAnchor,
880
+ requestHash: input.requestHash,
881
+ claudeVersion: agentVersion
882
+ });
883
+ }
884
+ async function capturePaginatedWatchAnchor(terminal, options, dependencies, requestHash) {
885
+ const bridge = dependencies.createBridge?.(options);
886
+ if (dependencies.capturePaginatedAnchor) {
887
+ return dependencies.capturePaginatedAnchor({ terminal, bridge: bridge, requestHash,
888
+ codexHome: stringValue(options.codexHome), now: dependencies.now });
889
+ }
890
+ if (!bridge)
891
+ throw new Error("Codex paginated terminal inspection is unavailable");
892
+ return capturePaginatedAnchor({ terminal, bridge, requestHash,
893
+ codexHome: stringValue(options.codexHome), now: dependencies.now });
894
+ }
895
+ async function capturePaginatedWatchAnchorWithLock(terminal, options, dependencies) {
896
+ const release = dependencies.acquireTerminalLock(dependencies.storeDirFromOptions(options), terminalControlForWatch(terminal));
897
+ try {
898
+ return await capturePaginatedWatchAnchor(terminal, options, dependencies);
899
+ }
900
+ finally {
901
+ release();
902
+ }
903
+ }
797
904
  function captureTerminalWatchAnchor(agent, terminal, options, dependencies) {
798
905
  if (agent === "codex") {
799
906
  return captureCodexHumanStartedActiveTaskAnchor({
@@ -817,6 +924,23 @@ async function observeTerminalWatch(watch, options, dependencies) {
817
924
  const rawTerminal = exactTerminal.state === "available"
818
925
  ? exactTerminal.rawTerminal
819
926
  : undefined;
927
+ if (watch.anchor.schema === "agent-knock-knock/codex-paginated-task-anchor") {
928
+ const terminalMatches = Boolean(rawTerminal && terminalMatchesWatch(rawTerminal, watch) && paginatedWatchProcessMatches(rawTerminal, watch.anchor));
929
+ return observePaginatedWatch({ watch, observedAt, terminalMatches,
930
+ terminalAvailable: exactTerminal.state === "available",
931
+ readSnapshot: dependencies.readPaginatedSnapshot,
932
+ blockingQuestionnaire: (checkpoint) => observeCodexPaginatedBlockingQuestion({
933
+ watch, checkpoint, now: new Date(observedAt),
934
+ responseDecision: (surfaceId, fingerprint) => rawTerminal
935
+ ? terminalWatchResponseDecision({ ...watch, observation_checkpoint: checkpoint }, rawTerminal, surfaceId, fingerprint, options, dependencies)
936
+ : { executable: false, suppress: false }
937
+ }),
938
+ questionnaire: (checkpoint, questions) => exactTerminal.state === "available"
939
+ ? terminalWatchQuestionnaireObservation({ watch, observedAt, options, dependencies,
940
+ rawTerminal, projectedTerminal: exactTerminal.terminal, terminalMatches,
941
+ observationCheckpoint: checkpoint, codexAsyncQuestionEvidence: questions })
942
+ : undefined });
943
+ }
820
944
  const projectedTerminal = exactTerminal.state === "available"
821
945
  ? exactTerminal.terminal
822
946
  : undefined;
@@ -1331,7 +1455,8 @@ function terminalWatchQuestionnaireObservation(input, requireFallbackAttribution
1331
1455
  }),
1332
1456
  now: new Date(input.observedAt),
1333
1457
  approvalBlocked: Boolean(approvalFingerprint(input.projectedTerminal)),
1334
- trustedTerminalEvidence: input.watch.terminal.terminal_endpoint
1458
+ trustedTerminalEvidence: input.watch.terminal.terminal_endpoint,
1459
+ codexAsyncQuestionEvidence: input.codexAsyncQuestionEvidence
1335
1460
  });
1336
1461
  let offer = captureOffer("notify_only");
1337
1462
  if (!offer)
@@ -1346,7 +1471,7 @@ function terminalWatchQuestionnaireObservation(input, requireFallbackAttribution
1346
1471
  return undefined;
1347
1472
  }
1348
1473
  const responseDecision = terminalWatchResponseDecision(responseWatch, rawTerminal, offer.surfaceId, offer.promptFingerprint, input.options, input.dependencies);
1349
- if (responseDecision.executable) {
1474
+ if (responseDecision.executable && !(responseWatch.anchor.schema === "agent-knock-knock/codex-paginated-task-anchor" && offer.projection.kind === "questionnaire")) {
1350
1475
  const executableOffer = captureOffer("executable");
1351
1476
  if (!executableOffer ||
1352
1477
  executableOffer.surfaceId !== offer.surfaceId ||
@@ -1603,6 +1728,13 @@ function terminalWatchesShareExactTask(left, right) {
1603
1728
  }
1604
1729
  function terminalWatchExactTaskKey(watch) {
1605
1730
  const anchor = watch.anchor;
1731
+ if (anchor.schema === "agent-knock-knock/codex-paginated-task-anchor") {
1732
+ const checkpoint = watch.observation_checkpoint;
1733
+ const turnId = "schema" in checkpoint && checkpoint.schema === "agent-knock-knock/codex-paginated-task-checkpoint"
1734
+ ? checkpoint.acceptance_evidence?.acceptanceId ?? anchor.turn_id : anchor.turn_id;
1735
+ return turnId ? sha256({ source: "codex_paginated", thread: anchor.native_thread_id,
1736
+ task: turnId, home: anchor.codex_home, process: anchor.process_uuid }) : undefined;
1737
+ }
1606
1738
  if (anchor.schema ===
1607
1739
  "agent-knock-knock/codex-human-started-active-task-anchor") {
1608
1740
  return codexWatchTaskKey({
@@ -1808,6 +1940,9 @@ function managedTerminalInteractionEvidence(turn, surfaceId, promptFingerprint,
1808
1940
  function terminalWatchCandidateMatchesLiveContext(watch, terminal) {
1809
1941
  if (!terminalMatchesWatch(terminal, watch))
1810
1942
  return false;
1943
+ if (watch.anchor.schema === "agent-knock-knock/codex-paginated-task-anchor") {
1944
+ return paginatedWatchProcessMatches(terminal, watch.anchor);
1945
+ }
1811
1946
  const sessionId = stringValue(terminal.native_agent_session_id);
1812
1947
  if (watch.anchor.schema ===
1813
1948
  "agent-knock-knock/codex-human-started-active-task-anchor") {
@@ -2160,125 +2295,6 @@ function codexIdentityForWatch(watch) {
2160
2295
  rollout: watch.anchor.rollout
2161
2296
  };
2162
2297
  }
2163
- function publicTerminalWatch(watch, additionalWarnings = [], exposeInteraction = false) {
2164
- const pending = watch.notification_outbox.filter(({ status }) => status === "pending" || status === "delivering" || status === "failed").length;
2165
- const capturedAgentVersion = terminalWatchCapturedAgentVersion(watch);
2166
- const compatibilityWarning = capturedAgentVersion === undefined
2167
- ? undefined
2168
- : watch.agent === "codex"
2169
- ? codexRuntimeCompatibilityProfile(capturedAgentVersion)
2170
- ?.compatibilityWarning
2171
- : claudeRuntimeCompatibilityWarning(capturedAgentVersion);
2172
- const userExplicitFallback = isUserExplicitFallbackWatch(watch);
2173
- const terminalActivityFallback = isTerminalActivityWatch(watch);
2174
- const warnings = [...new Set([
2175
- ...(watch.warnings ?? []),
2176
- ...additionalWarnings
2177
- ])];
2178
- const latestFailedCallback = [...watch.notification_outbox]
2179
- .reverse()
2180
- .find(({ status }) => status === "failed");
2181
- const currentInteraction = exposeInteraction && watch.status === "active" &&
2182
- watch.current_interaction &&
2183
- ["pending", "reserved", "response_uncertain"].includes(watch.current_interaction.aggregate.state)
2184
- ? watch.current_interaction
2185
- : undefined;
2186
- const interactionProjection = currentInteraction?.aggregate.state ===
2187
- "reserved"
2188
- ? {
2189
- ...currentInteraction.projection,
2190
- state: "response_uncertain",
2191
- capabilities: {
2192
- ...currentInteraction.projection.capabilities,
2193
- respond: false
2194
- }
2195
- }
2196
- : currentInteraction?.projection;
2197
- return {
2198
- watch_id: watch.watch_id,
2199
- source: userExplicitFallback
2200
- ? "terminal_user_explicit_fallback_watch"
2201
- : terminalActivityFallback
2202
- ? "terminal_activity_watch"
2203
- : "user_selected_terminal_watch",
2204
- watch_mode: terminalActivityFallback ? "terminal_activity" : "exact_task",
2205
- confidence: terminalActivityFallback ? "best_effort" : "exact",
2206
- interaction_policy: watch.interaction_policy,
2207
- capabilities: {
2208
- interaction_notify: true,
2209
- interaction_respond: Boolean(interactionProjection?.state === "pending" &&
2210
- interactionProjection.capabilities.respond)
2211
- },
2212
- agent: watch.agent,
2213
- terminal_id: watch.terminal.terminal_id,
2214
- native_thread_id: terminalWatchNativeThreadId(watch),
2215
- workspace: watch.terminal.workspace,
2216
- status: watch.status,
2217
- activity_state: watch.status === "active" ? "watching" : "settled",
2218
- created_at: watch.created_at,
2219
- deadline_at: watch.deadline_at,
2220
- updated_at: watch.updated_at,
2221
- last_activity_at: watch.last_activity_at,
2222
- ...(compatibilityWarning
2223
- ? { compatibility_warning: compatibilityWarning }
2224
- : {}),
2225
- ...(warnings.length > 0
2226
- ? { warnings }
2227
- : {}),
2228
- callback: {
2229
- pending,
2230
- delivered: watch.notification_outbox.filter(({ status }) => status === "delivered").length,
2231
- failed: watch.notification_outbox.filter(({ status }) => status === "failed").length,
2232
- superseded: watch.notification_outbox.filter(({ status }) => status === "superseded").length,
2233
- ...(latestFailedCallback?.last_error_code
2234
- ? { last_error_code: latestFailedCallback.last_error_code }
2235
- : {})
2236
- },
2237
- ...(interactionProjection
2238
- ? {
2239
- interaction_state: interactionProjection,
2240
- interaction_prompt_fingerprint: interactionProjection.prompt_fingerprint
2241
- }
2242
- : {}),
2243
- ...(watch.settlement
2244
- ? {
2245
- settlement: {
2246
- kind: watch.settlement.kind,
2247
- observed_at: watch.settlement.observed_at,
2248
- reason_code: watch.settlement.reason_code,
2249
- completion_text: watch.settlement.completion_text,
2250
- completion_id: watch.settlement.completion_id,
2251
- completion_timestamp: watch.settlement.completion_timestamp
2252
- }
2253
- }
2254
- : {}),
2255
- available_actions: {
2256
- status: {
2257
- tool: "agent_knock_knock_status",
2258
- arguments: { watch_id: watch.watch_id }
2259
- },
2260
- ...(watch.status === "active"
2261
- ? {
2262
- unwatch: {
2263
- tool: "agent_knock_knock_unwatch",
2264
- arguments: { watch_id: watch.watch_id },
2265
- requires_user_intent: true
2266
- }
2267
- }
2268
- : {}),
2269
- ...(interactionProjection?.state === "pending" &&
2270
- interactionProjection.capabilities.respond
2271
- ? {
2272
- respond_interaction: {
2273
- tool: "agent_knock_knock_respond_interaction",
2274
- arguments: { watch_id: watch.watch_id },
2275
- requires_user_intent: true
2276
- }
2277
- }
2278
- : {})
2279
- }
2280
- };
2281
- }
2282
2298
  function watchStatusInteractionAccess(watch, options) {
2283
2299
  if (!Object.hasOwn(options, "openclawSession"))
2284
2300
  return false;
@@ -2288,34 +2304,6 @@ function watchStatusInteractionAccess(watch, options) {
2288
2304
  }
2289
2305
  return true;
2290
2306
  }
2291
- function terminalWatchCapturedAgentVersion(watch) {
2292
- switch (watch.anchor.schema) {
2293
- case "agent-knock-knock/codex-human-started-active-task-anchor":
2294
- case "agent-knock-knock/codex-user-explicit-fallback-watch-anchor":
2295
- return watch.anchor.codex_version;
2296
- case "agent-knock-knock/claude-human-started-active-task-anchor":
2297
- case "agent-knock-knock/claude-user-explicit-fallback-watch-anchor":
2298
- return watch.anchor.claude_version;
2299
- case "agent-knock-knock/terminal-activity-watch-anchor":
2300
- return watch.anchor.agent_version;
2301
- }
2302
- }
2303
- function terminalWatchNativeThreadId(watch) {
2304
- switch (watch.anchor.schema) {
2305
- case "agent-knock-knock/codex-human-started-active-task-anchor":
2306
- return watch.anchor.native_thread_id;
2307
- case "agent-knock-knock/claude-human-started-active-task-anchor":
2308
- return watch.anchor.session_id;
2309
- case "agent-knock-knock/codex-user-explicit-fallback-watch-anchor":
2310
- return watch.anchor.acceptance_anchor.version === 1
2311
- ? watch.anchor.acceptance_anchor.native_thread_id
2312
- : undefined;
2313
- case "agent-knock-knock/claude-user-explicit-fallback-watch-anchor":
2314
- return watch.anchor.transcript_anchor.session_id;
2315
- case "agent-knock-knock/terminal-activity-watch-anchor":
2316
- return undefined;
2317
- }
2318
- }
2319
2307
  function approvalFingerprint(terminal) {
2320
2308
  if (terminal.activity_state !== "awaiting_approval")
2321
2309
  return undefined;