codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.4

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 (231) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +43 -0
  3. package/contracts/v1/fixtures/backend-capabilities.json +40 -1
  4. package/contracts/v1/fixtures/backend-compatibility.json +21 -0
  5. package/contracts/v1/fixtures/backend-version.json +6 -1
  6. package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
  7. package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
  8. package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
  9. package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
  10. package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
  11. package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
  12. package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
  13. package/contracts/v1/fixtures/operation-action.json +13 -0
  14. package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
  15. package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
  16. package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
  17. package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
  18. package/contracts/v1/fixtures/operation-blocker.json +10 -0
  19. package/contracts/v1/fixtures/operation-collect-request.json +17 -0
  20. package/contracts/v1/fixtures/operation-collect-result.json +42 -0
  21. package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
  22. package/contracts/v1/fixtures/operation-control-request.json +18 -0
  23. package/contracts/v1/fixtures/operation-control-result.json +31 -0
  24. package/contracts/v1/fixtures/operation-event.json +18 -0
  25. package/contracts/v1/fixtures/operation-handle.json +10 -0
  26. package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
  27. package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
  28. package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
  29. package/contracts/v1/fixtures/operation-receipt.json +32 -0
  30. package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
  31. package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
  32. package/contracts/v1/fixtures/operation-request.json +33 -0
  33. package/contracts/v1/fixtures/operation-state.json +144 -0
  34. package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
  35. package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
  36. package/contracts/v1/fixtures/operation-submit-result.json +16 -0
  37. package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
  38. package/contracts/v1/manifest.json +185 -1
  39. package/contracts/v1/parity-suite.json +106 -8
  40. package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
  41. package/contracts/v1/schemas/backend-request.schema.json +8 -2
  42. package/contracts/v1/schemas/capabilities.schema.json +81 -1
  43. package/contracts/v1/schemas/manifest.schema.json +57 -0
  44. package/contracts/v1/schemas/operation-action.schema.json +155 -0
  45. package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
  46. package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
  47. package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
  48. package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
  49. package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
  50. package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
  51. package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
  52. package/contracts/v1/schemas/operation-event.schema.json +756 -0
  53. package/contracts/v1/schemas/operation-handle.schema.json +55 -0
  54. package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
  55. package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
  56. package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
  57. package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
  58. package/contracts/v1/schemas/operation-request.schema.json +158 -0
  59. package/contracts/v1/schemas/operation-state.schema.json +691 -0
  60. package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
  61. package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
  62. package/contracts/v1/surface-drift-policy.json +50 -0
  63. package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
  64. package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
  65. package/dist/codex-chatgpt-control-journal.mjs +5547 -0
  66. package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
  67. package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
  68. package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
  69. package/dist/src/backend/client.d.ts +103 -2
  70. package/dist/src/backend/client.js +1436 -97
  71. package/dist/src/backend/compatibility.d.ts +12 -0
  72. package/dist/src/backend/compatibility.js +208 -0
  73. package/dist/src/backend/protocol.d.ts +84 -1
  74. package/dist/src/backend/protocol.js +31 -5
  75. package/dist/src/backend/runtime-identity.d.ts +10 -0
  76. package/dist/src/backend/runtime-identity.js +141 -0
  77. package/dist/src/backend/session.d.ts +10 -2
  78. package/dist/src/backend/session.js +478 -7
  79. package/dist/src/backend/stdio-server.d.ts +4 -1
  80. package/dist/src/backend/stdio-server.js +240 -28
  81. package/dist/src/browser/active-composer-file-input.d.ts +9 -0
  82. package/dist/src/browser/active-composer-file-input.js +33 -0
  83. package/dist/src/browser/attach.d.ts +4 -1
  84. package/dist/src/browser/attach.js +136 -28
  85. package/dist/src/browser/chatgpt-url.d.ts +2 -0
  86. package/dist/src/browser/chatgpt-url.js +9 -0
  87. package/dist/src/browser/downloads.d.ts +17 -1
  88. package/dist/src/browser/downloads.js +150 -28
  89. package/dist/src/browser/page-state.js +6 -0
  90. package/dist/src/client.d.ts +43 -0
  91. package/dist/src/client.js +1279 -59
  92. package/dist/src/commands/artifacts.js +6 -4
  93. package/dist/src/commands/chat-popover.d.ts +37 -0
  94. package/dist/src/commands/chat-popover.js +537 -0
  95. package/dist/src/commands/configuration.d.ts +5 -0
  96. package/dist/src/commands/configuration.js +134 -21
  97. package/dist/src/commands/context.js +10 -3
  98. package/dist/src/commands/doctor.d.ts +1 -1
  99. package/dist/src/commands/doctor.js +27 -4
  100. package/dist/src/commands/experience.d.ts +5 -0
  101. package/dist/src/commands/experience.js +104 -21
  102. package/dist/src/commands/files.js +14 -33
  103. package/dist/src/commands/modes.js +85 -21
  104. package/dist/src/commands/power-discovery.d.ts +130 -0
  105. package/dist/src/commands/power-discovery.js +669 -0
  106. package/dist/src/commands/project-sources.js +325 -31
  107. package/dist/src/commands/sequence.js +59 -32
  108. package/dist/src/commands/session.js +19 -6
  109. package/dist/src/commands/work.js +31 -0
  110. package/dist/src/dom/composer-text.d.ts +6 -0
  111. package/dist/src/dom/composer-text.js +85 -0
  112. package/dist/src/errors.d.ts +9 -0
  113. package/dist/src/errors.js +22 -0
  114. package/dist/src/index.d.ts +6 -0
  115. package/dist/src/index.js +9 -0
  116. package/dist/src/operations/artifact-output.d.ts +69 -0
  117. package/dist/src/operations/artifact-output.js +1748 -0
  118. package/dist/src/operations/artifact-stream.d.ts +19 -0
  119. package/dist/src/operations/artifact-stream.js +35 -0
  120. package/dist/src/operations/artifact-transfer.d.ts +149 -0
  121. package/dist/src/operations/artifact-transfer.js +1312 -0
  122. package/dist/src/operations/browser-adapter.d.ts +167 -0
  123. package/dist/src/operations/browser-adapter.js +2103 -0
  124. package/dist/src/operations/browser-observation.d.ts +110 -0
  125. package/dist/src/operations/browser-observation.js +1256 -0
  126. package/dist/src/operations/browser-target.d.ts +105 -0
  127. package/dist/src/operations/browser-target.js +531 -0
  128. package/dist/src/operations/canonical.d.ts +4 -0
  129. package/dist/src/operations/canonical.js +412 -0
  130. package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
  131. package/dist/src/operations/chatgpt-runtime.js +1232 -0
  132. package/dist/src/operations/client.d.ts +138 -0
  133. package/dist/src/operations/client.js +1145 -0
  134. package/dist/src/operations/collector.d.ts +195 -0
  135. package/dist/src/operations/collector.js +1039 -0
  136. package/dist/src/operations/configuration-routing.d.ts +4 -0
  137. package/dist/src/operations/configuration-routing.js +14 -0
  138. package/dist/src/operations/control.d.ts +372 -0
  139. package/dist/src/operations/control.js +1498 -0
  140. package/dist/src/operations/file-identity.d.ts +33 -0
  141. package/dist/src/operations/file-identity.js +153 -0
  142. package/dist/src/operations/handle.d.ts +19 -0
  143. package/dist/src/operations/handle.js +727 -0
  144. package/dist/src/operations/index.d.ts +25 -0
  145. package/dist/src/operations/index.js +25 -0
  146. package/dist/src/operations/journal-authority.d.ts +12 -0
  147. package/dist/src/operations/journal-authority.js +1 -0
  148. package/dist/src/operations/journal-rpc-client.d.ts +12 -0
  149. package/dist/src/operations/journal-rpc-client.js +225 -0
  150. package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
  151. package/dist/src/operations/journal-rpc-protocol.js +214 -0
  152. package/dist/src/operations/journal-rpc-server.d.ts +15 -0
  153. package/dist/src/operations/journal-rpc-server.js +272 -0
  154. package/dist/src/operations/journal.d.ts +143 -0
  155. package/dist/src/operations/journal.js +1957 -0
  156. package/dist/src/operations/production-attachments.d.ts +118 -0
  157. package/dist/src/operations/production-attachments.js +1035 -0
  158. package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
  159. package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
  160. package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
  161. package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
  162. package/dist/src/operations/production-configuration.d.ts +42 -0
  163. package/dist/src/operations/production-configuration.js +1544 -0
  164. package/dist/src/operations/production-primitives.d.ts +53 -0
  165. package/dist/src/operations/production-primitives.js +856 -0
  166. package/dist/src/operations/production-work-steer.d.ts +203 -0
  167. package/dist/src/operations/production-work-steer.js +1218 -0
  168. package/dist/src/operations/recovery.d.ts +80 -0
  169. package/dist/src/operations/recovery.js +174 -0
  170. package/dist/src/operations/runtime-adapter.d.ts +126 -0
  171. package/dist/src/operations/runtime-adapter.js +802 -0
  172. package/dist/src/operations/send-once.d.ts +224 -0
  173. package/dist/src/operations/send-once.js +1081 -0
  174. package/dist/src/operations/service.d.ts +286 -0
  175. package/dist/src/operations/service.js +2831 -0
  176. package/dist/src/operations/staging.d.ts +136 -0
  177. package/dist/src/operations/staging.js +630 -0
  178. package/dist/src/operations/state-machine.d.ts +29 -0
  179. package/dist/src/operations/state-machine.js +2047 -0
  180. package/dist/src/operations/submission.d.ts +423 -0
  181. package/dist/src/operations/submission.js +1676 -0
  182. package/dist/src/operations/transactional-chat-power.d.ts +17 -0
  183. package/dist/src/operations/transactional-chat-power.js +212 -0
  184. package/dist/src/operations/turn-ownership.d.ts +202 -0
  185. package/dist/src/operations/turn-ownership.js +700 -0
  186. package/dist/src/operations/types.d.ts +454 -0
  187. package/dist/src/operations/types.js +20 -0
  188. package/dist/src/operations/wire-requests.d.ts +21 -0
  189. package/dist/src/operations/wire-requests.js +396 -0
  190. package/dist/src/operations/wire-results.d.ts +97 -0
  191. package/dist/src/operations/wire-results.js +818 -0
  192. package/dist/src/runner/responses.d.ts +3 -1
  193. package/dist/src/runner/responses.js +19 -1
  194. package/dist/src/runner/result.js +227 -55
  195. package/dist/src/runner/types.d.ts +12 -0
  196. package/dist/src/runtime/command-routing.d.ts +149 -0
  197. package/dist/src/runtime/command-routing.js +431 -0
  198. package/dist/src/runtime/coordinated-browser.d.ts +24 -0
  199. package/dist/src/runtime/coordinated-browser.js +315 -0
  200. package/dist/src/runtime/coordinated-page.d.ts +41 -0
  201. package/dist/src/runtime/coordinated-page.js +651 -0
  202. package/dist/src/runtime/operation-context.d.ts +142 -0
  203. package/dist/src/runtime/operation-context.js +410 -0
  204. package/dist/src/runtime/runtime-session.d.ts +95 -0
  205. package/dist/src/runtime/runtime-session.js +314 -0
  206. package/dist/src/runtime/tab-coordinator.d.ts +200 -0
  207. package/dist/src/runtime/tab-coordinator.js +1200 -0
  208. package/dist/src/runtime/value-boundaries.d.ts +18 -0
  209. package/dist/src/runtime/value-boundaries.js +49 -0
  210. package/dist/src/safety/blockers.js +8 -1
  211. package/dist/src/safety/untrusted-output.js +2 -1
  212. package/dist/src/scripts/backend-server.js +4 -1
  213. package/dist/src/scripts/capture-surface-profile.js +7 -2
  214. package/dist/src/scripts/journal-server.d.ts +2 -0
  215. package/dist/src/scripts/journal-server.js +37 -0
  216. package/dist/src/scripts/live-smoke/harness.js +79 -7
  217. package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
  218. package/dist/src/scripts/live-smoke/scenarios.js +147 -30
  219. package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
  220. package/dist/src/scripts/live-smoke/transactional.js +254 -0
  221. package/dist/src/scripts/live-smoke/types.d.ts +3 -0
  222. package/dist/src/scripts/release-canary-module.js +17 -4
  223. package/dist/src/types.d.ts +38 -1
  224. package/package.json +8 -3
  225. package/references/2026-08-16-transactional-operations.md +459 -0
  226. package/references/2026-09-06-journal-service.md +140 -0
  227. package/references/agents-runner.md +34 -0
  228. package/references/backend-protocol.md +176 -0
  229. package/references/python-parity.md +137 -0
  230. package/references/responses-adapter.md +19 -0
  231. package/references/streaming.md +6 -0
@@ -0,0 +1,80 @@
1
+ import type { OperationActionRecordV1, OperationReceiptV1, OperationStateV1 } from "./types.js";
2
+ import { OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, OPERATION_RECOVERY_OBSERVATION_SCHEMA_VERSION } from "./types.js";
3
+ export type OperationTargetObservation = {
4
+ status: "matches";
5
+ } | {
6
+ status: "mismatch";
7
+ evidenceDigest?: string;
8
+ } | {
9
+ status: "unavailable";
10
+ evidenceDigest?: string;
11
+ };
12
+ export type OperationTurnObservation = {
13
+ status: "not_observed";
14
+ } | {
15
+ status: "owned_user_turn";
16
+ userTurnId: string;
17
+ evidenceDigest: string;
18
+ } | {
19
+ status: "owned_assistant_generating";
20
+ userTurnId: string;
21
+ assistantTurnId: string;
22
+ evidenceDigest: string;
23
+ } | {
24
+ status: "owned_assistant_terminal";
25
+ userTurnId: string;
26
+ assistantTurnId: string;
27
+ evidenceDigest: string;
28
+ } | {
29
+ status: "ambiguous";
30
+ evidenceDigest?: string;
31
+ };
32
+ export type OperationRecoveryObservationV1 = {
33
+ schemaVersion: typeof OPERATION_RECOVERY_OBSERVATION_SCHEMA_VERSION;
34
+ target: OperationTargetObservation;
35
+ turn: OperationTurnObservation;
36
+ };
37
+ export type OperationRecoveryDecisionV1 = {
38
+ kind: "return_completed_receipt";
39
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
40
+ receipt: OperationReceiptV1;
41
+ } | {
42
+ kind: "continue_preparation";
43
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
44
+ phase: "prepared" | "ready";
45
+ nonRepeatableActionMayStart: true;
46
+ } | {
47
+ kind: "observe_action_postcondition";
48
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
49
+ actionId: string;
50
+ actionKind: OperationActionRecordV1["kind"];
51
+ mayRepeatAction: false;
52
+ } | {
53
+ kind: "continue_owned_turn_observation";
54
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
55
+ phase: "submitted" | "generating";
56
+ userTurnId?: string;
57
+ assistantTurnId?: string;
58
+ evidenceDigest?: string;
59
+ } | {
60
+ kind: "capture_owned_turn";
61
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
62
+ assistantTurnId: string;
63
+ evidenceDigest: string;
64
+ } | {
65
+ kind: "enter_uncertain";
66
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
67
+ code: "target_evidence_unavailable" | "turn_ownership_ambiguous" | "capture_ownership_lost";
68
+ mayRepeatAction: false;
69
+ } | {
70
+ kind: "block";
71
+ schemaVersion: typeof OPERATION_RECOVERY_DECISION_SCHEMA_VERSION;
72
+ code: "target_binding_mismatch" | "target_evidence_unavailable" | "operation_state_inconsistent";
73
+ mayRepeatAction: false;
74
+ };
75
+ /**
76
+ * Decide what a restarted caller may do from durable state and a fresh,
77
+ * operation-bound observation. This function never authorizes replay of an
78
+ * action whose intent is already durable.
79
+ */
80
+ export declare function decideOperationRecovery(state: OperationStateV1, observation: OperationRecoveryObservationV1): OperationRecoveryDecisionV1;
@@ -0,0 +1,174 @@
1
+ import { OPERATION_RECOVERY_DECISION_SCHEMA_VERSION } from "./types.js";
2
+ /**
3
+ * Decide what a restarted caller may do from durable state and a fresh,
4
+ * operation-bound observation. This function never authorizes replay of an
5
+ * action whose intent is already durable.
6
+ */
7
+ export function decideOperationRecovery(state, observation) {
8
+ if (state.phase === "completed") {
9
+ if (state.receipt === undefined) {
10
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "operation_state_inconsistent", mayRepeatAction: false };
11
+ }
12
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "return_completed_receipt", receipt: state.receipt };
13
+ }
14
+ if (observation.target.status === "mismatch") {
15
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "target_binding_mismatch", mayRepeatAction: false };
16
+ }
17
+ if (observation.target.status === "unavailable") {
18
+ if (state.mutationBoundary === "none") {
19
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "target_evidence_unavailable", mayRepeatAction: false };
20
+ }
21
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "enter_uncertain", code: "target_evidence_unavailable", mayRepeatAction: false };
22
+ }
23
+ // The process can stop after fsyncing an intent (or its receipt) but before
24
+ // appending the corresponding phase event. Phase alone therefore never
25
+ // authorizes a second non-repeatable browser action.
26
+ const pendingIntent = pendingNonRepeatableAction(state);
27
+ if (pendingIntent !== undefined) {
28
+ return decisionForPendingAction(state, pendingIntent, observation.turn);
29
+ }
30
+ if (state.phase === "prepared" || state.phase === "ready") {
31
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "continue_preparation", phase: state.phase, nonRepeatableActionMayStart: true };
32
+ }
33
+ if (state.phase === "handoff_pending" || state.phase === "send_pending") {
34
+ const expectedKind = state.phase === "handoff_pending" ? "file_handoff" : "send";
35
+ const action = latestAction(state, candidate => candidate.kind === expectedKind);
36
+ if (action === undefined) {
37
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "operation_state_inconsistent", mayRepeatAction: false };
38
+ }
39
+ return {
40
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
41
+ kind: "observe_action_postcondition",
42
+ actionId: action.actionId,
43
+ actionKind: action.kind,
44
+ mayRepeatAction: false
45
+ };
46
+ }
47
+ if (state.phase === "capturing") {
48
+ if (observation.turn.status === "owned_assistant_terminal") {
49
+ return {
50
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
51
+ kind: "capture_owned_turn",
52
+ assistantTurnId: observation.turn.assistantTurnId,
53
+ evidenceDigest: observation.turn.evidenceDigest
54
+ };
55
+ }
56
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "enter_uncertain", code: "capture_ownership_lost", mayRepeatAction: false };
57
+ }
58
+ if (state.phase === "submitted" || state.phase === "generating") {
59
+ return ownedTurnDecision(state.phase, observation.turn);
60
+ }
61
+ // An uncertain operation can only observe the most advanced durable
62
+ // boundary. It cannot return to a mutation path merely because the page
63
+ // looks plausible.
64
+ if (state.phase === "uncertain") {
65
+ if (state.mutationBoundary === "handoff_may_have_occurred") {
66
+ const action = latestAction(state, candidate => candidate.kind === "file_handoff");
67
+ if (action === undefined) {
68
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "operation_state_inconsistent", mayRepeatAction: false };
69
+ }
70
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "observe_action_postcondition", actionId: action.actionId, actionKind: action.kind, mayRepeatAction: false };
71
+ }
72
+ if (state.mutationBoundary === "send_may_have_occurred" || state.mutationBoundary === "control_may_have_occurred") {
73
+ if (observation.turn.status === "not_observed") {
74
+ const action = latestAction(state, candidate => candidate.kind === "send" || candidate.kind === "work_steer" || candidate.kind === "stop");
75
+ if (action !== undefined) {
76
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "observe_action_postcondition", actionId: action.actionId, actionKind: action.kind, mayRepeatAction: false };
77
+ }
78
+ }
79
+ const turnDecision = ownedTurnDecision("generating", observation.turn);
80
+ if (turnDecision.kind === "enter_uncertain") {
81
+ const action = latestAction(state, candidate => candidate.kind === "send" || candidate.kind === "work_steer" || candidate.kind === "stop");
82
+ if (action !== undefined) {
83
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "observe_action_postcondition", actionId: action.actionId, actionKind: action.kind, mayRepeatAction: false };
84
+ }
85
+ }
86
+ return turnDecision;
87
+ }
88
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "operation_state_inconsistent", mayRepeatAction: false };
89
+ }
90
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "block", code: "operation_state_inconsistent", mayRepeatAction: false };
91
+ }
92
+ function decisionForPendingAction(state, action, turn) {
93
+ // Attachment ownership is established by the exact manifest
94
+ // postcondition, not by turn state. A durable handoff intent therefore
95
+ // always remains observation-only until that postcondition is reconciled.
96
+ if (action.kind === "file_handoff")
97
+ return observeAction(action);
98
+ // Send/steer/stop can be reconciled directly when an operation-owned turn
99
+ // is already proven. This matters for the crash gap after the browser
100
+ // acted but before the action receipt or phase event was appended. Merely
101
+ // having a durable intent still never authorizes a second mutation.
102
+ if (turn.status === "not_observed")
103
+ return observeAction(action);
104
+ if (turn.status === "ambiguous") {
105
+ return {
106
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
107
+ kind: "enter_uncertain",
108
+ code: "turn_ownership_ambiguous",
109
+ mayRepeatAction: false
110
+ };
111
+ }
112
+ const phase = action.kind === "stop"
113
+ ? "generating"
114
+ : state.phase === "generating"
115
+ ? "generating"
116
+ : "submitted";
117
+ return ownedTurnDecision(phase, turn);
118
+ }
119
+ function observeAction(action) {
120
+ return {
121
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
122
+ kind: "observe_action_postcondition",
123
+ actionId: action.actionId,
124
+ actionKind: action.kind,
125
+ mayRepeatAction: false
126
+ };
127
+ }
128
+ function ownedTurnDecision(phase, turn) {
129
+ if (turn.status === "ambiguous") {
130
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "enter_uncertain", code: "turn_ownership_ambiguous", mayRepeatAction: false };
131
+ }
132
+ if (turn.status === "owned_assistant_terminal") {
133
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "capture_owned_turn", assistantTurnId: turn.assistantTurnId, evidenceDigest: turn.evidenceDigest };
134
+ }
135
+ if (turn.status === "owned_assistant_generating") {
136
+ return {
137
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
138
+ kind: "continue_owned_turn_observation",
139
+ phase: "generating",
140
+ userTurnId: turn.userTurnId,
141
+ assistantTurnId: turn.assistantTurnId,
142
+ evidenceDigest: turn.evidenceDigest
143
+ };
144
+ }
145
+ if (turn.status === "owned_user_turn") {
146
+ return {
147
+ schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION,
148
+ kind: "continue_owned_turn_observation",
149
+ phase,
150
+ userTurnId: turn.userTurnId,
151
+ evidenceDigest: turn.evidenceDigest
152
+ };
153
+ }
154
+ return { schemaVersion: OPERATION_RECOVERY_DECISION_SCHEMA_VERSION, kind: "continue_owned_turn_observation", phase };
155
+ }
156
+ function latestAction(state, predicate) {
157
+ return Object.values(state.actions)
158
+ .filter(predicate)
159
+ .sort((left, right) => right.intentRevision - left.intentRevision)[0];
160
+ }
161
+ function pendingNonRepeatableAction(state) {
162
+ return latestAction(state, action => {
163
+ if (action.kind === "file_handoff") {
164
+ return state.phase === "prepared" || state.phase === "handoff_pending" || state.phase === "uncertain";
165
+ }
166
+ if (action.kind === "send") {
167
+ return state.phase === "ready" || state.phase === "send_pending" || state.phase === "uncertain";
168
+ }
169
+ if (action.kind === "work_steer" || action.kind === "stop") {
170
+ return state.phase === "generating" || state.phase === "uncertain";
171
+ }
172
+ return false;
173
+ });
174
+ }
@@ -0,0 +1,126 @@
1
+ import type { PageLike } from "../types.js";
2
+ import type { CoordinatorOwner, ProcessTabCoordinator } from "../runtime/tab-coordinator.js";
3
+ import { OperationRuntimeContext, type OperationRuntimeCapabilities } from "../runtime/operation-context.js";
4
+ import { type ComposedOperationBrowserAdapter, type OperationBrowserAdapterOptions, type OperationBrowserCollectorPrimitive, type OperationBrowserControlPrimitive, type OperationBrowserArtifactPrimitive, type OperationBrowserCurrentTargetResult, type OperationBrowserStagingPrimitive, type OperationBrowserSubmissionPrimitive, type OperationBrowserTargetProbe, type OperationBrowserTargetProbeRequest } from "./browser-adapter.js";
5
+ import type { OperationCollectorAdapter, OperationSubmissionAdapter } from "./service.js";
6
+ import type { SubmissionFinalTransactionResult } from "./submission.js";
7
+ import type { BrowserTargetClaim, BrowserTargetEvidenceDigest } from "./browser-target.js";
8
+ import type { OwnershipTargetEvidence } from "./turn-ownership.js";
9
+ import type { OperationFileIdentity } from "./file-identity.js";
10
+ import type { OperationSurface, OperationTargetBindingV1, OperationTargetRequestV1 } from "./types.js";
11
+ /**
12
+ * Browser primitives that are safe to pass into an operation adapter.
13
+ *
14
+ * The callbacks receive the captured page explicitly. They must perform one
15
+ * bounded DOM transaction and return an already-redacted observation. In
16
+ * particular, a callback must not poll for generation, wait for attachment
17
+ * processing, read a mutable RuntimeEnv, or retry a non-repeatable browser
18
+ * action. Those waits belong to the operation collector and are deliberately
19
+ * outside the tab actor.
20
+ */
21
+ export type OperationRuntimeBrowserPrimitives = Readonly<{
22
+ submission?: OperationBrowserSubmissionPrimitive;
23
+ staging?: OperationBrowserStagingPrimitive;
24
+ collector?: OperationBrowserCollectorPrimitive;
25
+ control?: OperationBrowserControlPrimitive;
26
+ artifacts?: OperationBrowserArtifactPrimitive;
27
+ }>;
28
+ /**
29
+ * One request-scoped capture. The capture factory is invoked lazily from
30
+ * `resolveTarget`, after OperationService has created the durable operation
31
+ * record. It is the only place that may attach/claim/create a browser page.
32
+ *
33
+ * `targetEvidence` is required when no resolver is supplied. A resolver is
34
+ * useful for an explicit target policy (for example a selected tab versus a
35
+ * caller-provided tab id), but it must remain read-only and return the same
36
+ * captured page object.
37
+ */
38
+ export type OperationRuntimeBrowserCapture = Readonly<{
39
+ page: Readonly<PageLike>;
40
+ /** Optional immutable context captured by the provider bridge. */
41
+ runtimeContext?: OperationRuntimeContext<PageLike>;
42
+ targetEvidence?: OwnershipTargetEvidence;
43
+ authoritativeClaim?: BrowserTargetClaim;
44
+ capabilities?: Partial<OperationRuntimeCapabilities>;
45
+ /** Provider-proofed anchor evidence for a target whose ID is allocated by Send. */
46
+ newTargetAnchorDigest?: string;
47
+ blankTaskEvidenceDigest?: string;
48
+ resolveTargetEvidence?: (request: OperationBrowserTargetProbeRequest) => Promise<OperationBrowserTargetProbe> | OperationBrowserTargetProbe;
49
+ observeCurrentTarget?: (request: Parameters<NonNullable<OperationBrowserAdapterOptions["observeCurrentTarget"]>>[0]) => Promise<OperationBrowserCurrentTargetResult> | OperationBrowserCurrentTargetResult;
50
+ /** Request-local output destination; intentionally absent on recovery. */
51
+ outputDirectory?: string;
52
+ primitives?: OperationRuntimeBrowserPrimitives;
53
+ }>;
54
+ export type OperationRuntimeBrowserCaptureRequest = Readonly<{
55
+ operationId: string;
56
+ requestDigest: string;
57
+ surface: OperationSurface;
58
+ target: OperationTargetRequestV1;
59
+ signal: AbortSignal;
60
+ }>;
61
+ /**
62
+ * Frozen locator and complete durable target supplied by an authenticated
63
+ * post-restart handle factory. `targetRequest` is explicit because a durable
64
+ * binding must never be reconstructed by guessing a selected/replacement tab.
65
+ */
66
+ export type OperationRuntimeBrowserRecoveryContext = Readonly<{
67
+ operationId: string;
68
+ requestDigest: string;
69
+ surface: OperationSurface;
70
+ target: OperationTargetBindingV1;
71
+ targetRequest: OperationTargetRequestV1;
72
+ }>;
73
+ export type OperationRuntimeAdapterOptions = Readonly<{
74
+ /** Backend process owner used by the process/tab coordinator. */
75
+ owner: CoordinatorOwner;
76
+ /** Journal-keyed evidence digest. It must never be a bare public hash. */
77
+ evidenceDigest: BrowserTargetEvidenceDigest;
78
+ /** Lazy, request-scoped page/context capture. */
79
+ capture: (request: OperationRuntimeBrowserCaptureRequest) => Promise<OperationRuntimeBrowserCapture> | OperationRuntimeBrowserCapture;
80
+ /** Static operation closures may safely retain request-local private input. */
81
+ primitives?: OperationRuntimeBrowserPrimitives;
82
+ /** Set when the lazy capture will return the corresponding optional port.
83
+ * Leaving this false keeps OperationService on its read-only submission
84
+ * precondition path; exposing an absent staging port would otherwise turn a
85
+ * safe pre-populated composer into an artificial mutation blocker. */
86
+ exposeStaging?: boolean;
87
+ /** Set when callers want structured unavailable control results. */
88
+ exposeControl?: boolean;
89
+ /** Set only for a request-local submit capture with an absolute destination. */
90
+ exposeArtifacts?: boolean;
91
+ coordinator?: ProcessTabCoordinator;
92
+ transactionTimeoutMs?: number;
93
+ files?: readonly OperationFileIdentity[];
94
+ fileManifestDigest?: OperationBrowserAdapterOptions["fileManifestDigest"];
95
+ /** Explicit lazy recovery path; submit adapters do not use this option. */
96
+ recovery?: OperationRuntimeBrowserRecoveryContext;
97
+ /** Separate read-only restart callback; cannot initialize a target:new capture. */
98
+ recoverAuthenticatedSend?: (request: Parameters<NonNullable<OperationSubmissionAdapter["recoverAuthenticatedSend"]>>[0]) => Promise<Readonly<{
99
+ result: SubmissionFinalTransactionResult;
100
+ /** Only read ports may survive recovery; no target resolution or mutation. */
101
+ collector?: OperationCollectorAdapter;
102
+ }>>;
103
+ }>;
104
+ export type OperationRuntimeAdapterErrorCode = "adapter_incomplete" | "capture_failed" | "capture_incomplete" | "target_evidence_unavailable" | "target_binding_mismatch" | "page_affinity_mismatch" | "unsupported_browser_primitive" | "not_initialized" | "backend_unavailable" | "browser_bridge_unavailable" | "login_required" | "captcha" | "rate_limited" | "permission_required" | "needs_confirmation" | "runtime_incompatible";
105
+ /** Stable, redacted error boundary for a request-scoped runtime adapter. */
106
+ export declare class OperationRuntimeAdapterError extends Error {
107
+ readonly code: OperationRuntimeAdapterErrorCode;
108
+ constructor(code: OperationRuntimeAdapterErrorCode);
109
+ }
110
+ /**
111
+ * This is the generic adapter's injection inventory, retained for compatibility
112
+ * with integrations that assemble their own provider runtime. It does not
113
+ * describe the default ChatGPT composite: `chatgpt-runtime.ts` injects the
114
+ * proven production modules for these seams. The generic adapter itself never
115
+ * guesses selectors or routes legacy polling helpers through a tab actor.
116
+ */
117
+ export declare const UNWIRED_OPERATION_RUNTIME_PRIMITIVES: readonly ["new_thread_creation", "configuration_set", "tool_selection", "composer_population", "file_chooser_handoff", "send_activation", "stop_activation", "work_steer_activation"];
118
+ /**
119
+ * Compose one lazy runtime capture over the existing operation browser
120
+ * adapter. The returned object is intentionally request-scoped: a caller
121
+ * should construct it in `OperationClient.adapterFactory` and retain it only
122
+ * for the resulting operation handle.
123
+ */
124
+ export declare function createRuntimeOperationBrowserAdapter(options: OperationRuntimeAdapterOptions): ComposedOperationBrowserAdapter;
125
+ /** Alias for callers that put the runtime qualifier first. */
126
+ export declare const createOperationRuntimeAdapter: typeof createRuntimeOperationBrowserAdapter;