codex-chatgpt-control 0.2.0-alpha.1 → 0.5.0-alpha.1

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 (233) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +42 -2
  3. package/contracts/v1/fixtures/backend-capabilities.json +11 -0
  4. package/contracts/v1/fixtures/command-descriptors.json +289 -7
  5. package/contracts/v1/fixtures/describe-runner-run.json +5 -2
  6. package/contracts/v1/fixtures/doctor-scenario-preflight.json +45 -2
  7. package/contracts/v1/fixtures/help-root.json +1 -1
  8. package/contracts/v1/fixtures/output-json-parse-success.json +9 -0
  9. package/contracts/v1/fixtures/reports-create-redacted.json +1 -1
  10. package/contracts/v1/fixtures/run-timeout-partial.json +15 -4
  11. package/contracts/v1/fixtures/stream-in-progress.ndjson +3 -0
  12. package/contracts/v1/fixtures/stream-submitted-completed.ndjson +1 -1
  13. package/contracts/v1/fixtures/surface-chat-legacy.json +35 -0
  14. package/contracts/v1/fixtures/surface-chat-simplified.json +37 -0
  15. package/contracts/v1/fixtures/surface-sidebar-false-positive.json +29 -0
  16. package/contracts/v1/fixtures/surface-work-advanced.json +45 -0
  17. package/contracts/v1/fixtures/surface-work-basic.json +38 -0
  18. package/contracts/v1/fixtures/workflow-ask-success.json +8 -0
  19. package/contracts/v1/manifest.json +32 -1
  20. package/contracts/v1/parity-suite.json +121 -1
  21. package/contracts/v1/schemas/backend-request.schema.json +15 -0
  22. package/contracts/v1/schemas/manifest.schema.json +6 -3
  23. package/contracts/v1/schemas/surface-profile.schema.json +166 -0
  24. package/dist/codex-chatgpt-control-backend.mjs +3198 -340
  25. package/dist/codex-chatgpt-control.bundle.mjs +4454 -1555
  26. package/dist/src/backend/client.d.ts +26 -1
  27. package/dist/src/backend/client.js +23 -1
  28. package/dist/src/backend/protocol.d.ts +1 -1
  29. package/dist/src/backend/protocol.js +11 -0
  30. package/dist/src/backend/session.js +22 -0
  31. package/dist/src/browser/attach.d.ts +1 -0
  32. package/dist/src/browser/attach.js +3 -3
  33. package/dist/src/browser/clipboard.d.ts +11 -0
  34. package/dist/src/browser/clipboard.js +34 -7
  35. package/dist/src/browser/page-state.js +17 -4
  36. package/dist/src/client.d.ts +32 -1
  37. package/dist/src/client.js +72 -16
  38. package/dist/src/commands/artifacts.js +1 -7
  39. package/dist/src/commands/configuration.d.ts +15 -0
  40. package/dist/src/commands/configuration.js +674 -0
  41. package/dist/src/commands/context.js +3 -1
  42. package/dist/src/commands/conversation.d.ts +15 -0
  43. package/dist/src/commands/conversation.js +44 -0
  44. package/dist/src/commands/deadline.d.ts +8 -0
  45. package/dist/src/commands/deadline.js +14 -0
  46. package/dist/src/commands/doctor.js +47 -3
  47. package/dist/src/commands/experience.d.ts +12 -0
  48. package/dist/src/commands/experience.js +288 -0
  49. package/dist/src/commands/files.js +61 -13
  50. package/dist/src/commands/messages.d.ts +2 -1
  51. package/dist/src/commands/messages.js +349 -87
  52. package/dist/src/commands/modes.d.ts +4 -1
  53. package/dist/src/commands/modes.js +243 -44
  54. package/dist/src/commands/probes.d.ts +15 -0
  55. package/dist/src/commands/probes.js +64 -0
  56. package/dist/src/commands/registry.js +102 -8
  57. package/dist/src/commands/reports.js +1 -1
  58. package/dist/src/commands/response-actions.js +1 -7
  59. package/dist/src/commands/sequence.js +24 -1
  60. package/dist/src/commands/session.d.ts +2 -0
  61. package/dist/src/commands/session.js +50 -1
  62. package/dist/src/commands/threads.js +3 -31
  63. package/dist/src/commands/work.d.ts +6 -0
  64. package/dist/src/commands/work.js +338 -0
  65. package/dist/src/dom/generation-state.d.ts +7 -0
  66. package/dist/src/dom/generation-state.js +7 -1
  67. package/dist/src/dom/label-match.d.ts +3 -0
  68. package/dist/src/dom/label-match.js +25 -0
  69. package/dist/src/dom/locale/am.d.ts +8 -1
  70. package/dist/src/dom/locale/am.js +8 -1
  71. package/dist/src/dom/locale/ar.d.ts +9 -1
  72. package/dist/src/dom/locale/ar.js +9 -1
  73. package/dist/src/dom/locale/bg.d.ts +9 -1
  74. package/dist/src/dom/locale/bg.js +9 -1
  75. package/dist/src/dom/locale/bn.d.ts +9 -1
  76. package/dist/src/dom/locale/bn.js +9 -1
  77. package/dist/src/dom/locale/bs.d.ts +8 -1
  78. package/dist/src/dom/locale/bs.js +8 -1
  79. package/dist/src/dom/locale/ca.d.ts +8 -1
  80. package/dist/src/dom/locale/ca.js +8 -1
  81. package/dist/src/dom/locale/cs.d.ts +8 -1
  82. package/dist/src/dom/locale/cs.js +8 -1
  83. package/dist/src/dom/locale/da.d.ts +7 -1
  84. package/dist/src/dom/locale/da.js +7 -1
  85. package/dist/src/dom/locale/de.d.ts +10 -3
  86. package/dist/src/dom/locale/de.js +10 -3
  87. package/dist/src/dom/locale/el.d.ts +8 -1
  88. package/dist/src/dom/locale/el.js +8 -1
  89. package/dist/src/dom/locale/en.d.ts +40 -1
  90. package/dist/src/dom/locale/en.js +42 -1
  91. package/dist/src/dom/locale/es-419.d.ts +8 -1
  92. package/dist/src/dom/locale/es-419.js +8 -1
  93. package/dist/src/dom/locale/es-ES.d.ts +8 -1
  94. package/dist/src/dom/locale/es-ES.js +8 -1
  95. package/dist/src/dom/locale/et.d.ts +8 -1
  96. package/dist/src/dom/locale/et.js +8 -1
  97. package/dist/src/dom/locale/fa.d.ts +9 -1
  98. package/dist/src/dom/locale/fa.js +9 -1
  99. package/dist/src/dom/locale/fi.d.ts +8 -1
  100. package/dist/src/dom/locale/fi.js +8 -1
  101. package/dist/src/dom/locale/fr-CA.d.ts +8 -1
  102. package/dist/src/dom/locale/fr-CA.js +8 -1
  103. package/dist/src/dom/locale/fr-FR.d.ts +8 -3
  104. package/dist/src/dom/locale/fr-FR.js +8 -3
  105. package/dist/src/dom/locale/gu.d.ts +8 -1
  106. package/dist/src/dom/locale/gu.js +8 -1
  107. package/dist/src/dom/locale/hi.d.ts +8 -1
  108. package/dist/src/dom/locale/hi.js +8 -1
  109. package/dist/src/dom/locale/hr.d.ts +7 -1
  110. package/dist/src/dom/locale/hr.js +7 -1
  111. package/dist/src/dom/locale/hu.d.ts +8 -1
  112. package/dist/src/dom/locale/hu.js +8 -1
  113. package/dist/src/dom/locale/hy.d.ts +9 -1
  114. package/dist/src/dom/locale/hy.js +9 -1
  115. package/dist/src/dom/locale/id.d.ts +8 -1
  116. package/dist/src/dom/locale/id.js +8 -1
  117. package/dist/src/dom/locale/index.d.ts +20 -1
  118. package/dist/src/dom/locale/index.js +102 -0
  119. package/dist/src/dom/locale/is.d.ts +8 -1
  120. package/dist/src/dom/locale/is.js +8 -1
  121. package/dist/src/dom/locale/it.d.ts +8 -1
  122. package/dist/src/dom/locale/it.js +8 -1
  123. package/dist/src/dom/locale/ja.d.ts +8 -1
  124. package/dist/src/dom/locale/ja.js +8 -1
  125. package/dist/src/dom/locale/ka.d.ts +8 -1
  126. package/dist/src/dom/locale/ka.js +8 -1
  127. package/dist/src/dom/locale/kk.d.ts +8 -1
  128. package/dist/src/dom/locale/kk.js +8 -1
  129. package/dist/src/dom/locale/kn.d.ts +9 -1
  130. package/dist/src/dom/locale/kn.js +9 -1
  131. package/dist/src/dom/locale/ko.d.ts +8 -1
  132. package/dist/src/dom/locale/ko.js +8 -1
  133. package/dist/src/dom/locale/lt.d.ts +9 -1
  134. package/dist/src/dom/locale/lt.js +9 -1
  135. package/dist/src/dom/locale/lv.d.ts +8 -1
  136. package/dist/src/dom/locale/lv.js +8 -1
  137. package/dist/src/dom/locale/mk.d.ts +7 -1
  138. package/dist/src/dom/locale/mk.js +7 -1
  139. package/dist/src/dom/locale/ml.d.ts +9 -1
  140. package/dist/src/dom/locale/ml.js +9 -1
  141. package/dist/src/dom/locale/mn.d.ts +9 -1
  142. package/dist/src/dom/locale/mn.js +9 -1
  143. package/dist/src/dom/locale/mr.d.ts +9 -1
  144. package/dist/src/dom/locale/mr.js +9 -1
  145. package/dist/src/dom/locale/ms.d.ts +8 -1
  146. package/dist/src/dom/locale/ms.js +8 -1
  147. package/dist/src/dom/locale/my.d.ts +8 -1
  148. package/dist/src/dom/locale/my.js +8 -1
  149. package/dist/src/dom/locale/nb.d.ts +8 -1
  150. package/dist/src/dom/locale/nb.js +8 -1
  151. package/dist/src/dom/locale/nl.d.ts +8 -1
  152. package/dist/src/dom/locale/nl.js +8 -1
  153. package/dist/src/dom/locale/pa.d.ts +9 -1
  154. package/dist/src/dom/locale/pa.js +9 -1
  155. package/dist/src/dom/locale/pl.d.ts +8 -1
  156. package/dist/src/dom/locale/pl.js +8 -1
  157. package/dist/src/dom/locale/pt-BR.d.ts +8 -1
  158. package/dist/src/dom/locale/pt-BR.js +8 -1
  159. package/dist/src/dom/locale/pt-PT.d.ts +8 -1
  160. package/dist/src/dom/locale/pt-PT.js +8 -1
  161. package/dist/src/dom/locale/ro.d.ts +7 -1
  162. package/dist/src/dom/locale/ro.js +7 -1
  163. package/dist/src/dom/locale/ru.d.ts +5 -1
  164. package/dist/src/dom/locale/ru.js +5 -1
  165. package/dist/src/dom/locale/sk.d.ts +8 -1
  166. package/dist/src/dom/locale/sk.js +8 -1
  167. package/dist/src/dom/locale/sl.d.ts +8 -1
  168. package/dist/src/dom/locale/sl.js +8 -1
  169. package/dist/src/dom/locale/so.d.ts +8 -1
  170. package/dist/src/dom/locale/so.js +8 -1
  171. package/dist/src/dom/locale/sq.d.ts +8 -1
  172. package/dist/src/dom/locale/sq.js +8 -1
  173. package/dist/src/dom/locale/sr.d.ts +5 -1
  174. package/dist/src/dom/locale/sr.js +5 -1
  175. package/dist/src/dom/locale/sv.d.ts +8 -1
  176. package/dist/src/dom/locale/sv.js +8 -1
  177. package/dist/src/dom/locale/sw.d.ts +8 -1
  178. package/dist/src/dom/locale/sw.js +8 -1
  179. package/dist/src/dom/locale/ta.d.ts +9 -1
  180. package/dist/src/dom/locale/ta.js +9 -1
  181. package/dist/src/dom/locale/te.d.ts +9 -1
  182. package/dist/src/dom/locale/te.js +9 -1
  183. package/dist/src/dom/locale/th.d.ts +8 -1
  184. package/dist/src/dom/locale/th.js +8 -1
  185. package/dist/src/dom/locale/tl.d.ts +4 -5
  186. package/dist/src/dom/locale/tl.js +4 -5
  187. package/dist/src/dom/locale/tr.d.ts +8 -1
  188. package/dist/src/dom/locale/tr.js +8 -1
  189. package/dist/src/dom/locale/types.d.ts +25 -1
  190. package/dist/src/dom/locale/uk.d.ts +8 -1
  191. package/dist/src/dom/locale/uk.js +8 -1
  192. package/dist/src/dom/locale/ur.d.ts +8 -1
  193. package/dist/src/dom/locale/ur.js +8 -1
  194. package/dist/src/dom/locale/vi.d.ts +8 -1
  195. package/dist/src/dom/locale/vi.js +8 -1
  196. package/dist/src/dom/locale/zh-HK.d.ts +9 -1
  197. package/dist/src/dom/locale/zh-HK.js +10 -2
  198. package/dist/src/dom/locale/zh-Hans.d.ts +9 -1
  199. package/dist/src/dom/locale/zh-Hans.js +9 -1
  200. package/dist/src/dom/locale/zh-TW.d.ts +9 -1
  201. package/dist/src/dom/locale/zh-TW.js +9 -1
  202. package/dist/src/dom/menus.js +13 -2
  203. package/dist/src/dom/selectors.js +6 -1
  204. package/dist/src/dom/wait-snapshot.d.ts +43 -0
  205. package/dist/src/dom/wait-snapshot.js +127 -0
  206. package/dist/src/index.d.ts +3 -0
  207. package/dist/src/index.js +3 -0
  208. package/dist/src/runner/responses.d.ts +3 -1
  209. package/dist/src/runner/responses.js +16 -1
  210. package/dist/src/runner/result.js +129 -4
  211. package/dist/src/runner/stream.d.ts +1 -1
  212. package/dist/src/runner/stream.js +6 -0
  213. package/dist/src/runner/types.d.ts +35 -1
  214. package/dist/src/safety/risk.d.ts +11 -0
  215. package/dist/src/safety/risk.js +11 -0
  216. package/dist/src/scripts/apply-intelligence-locale-captures.d.ts +6 -0
  217. package/dist/src/scripts/apply-intelligence-locale-captures.js +147 -15
  218. package/dist/src/scripts/capture-intelligence-locales.d.ts +3 -0
  219. package/dist/src/scripts/capture-intelligence-locales.js +372 -3
  220. package/dist/src/scripts/capture-surface-profile.d.ts +23 -0
  221. package/dist/src/scripts/capture-surface-profile.js +304 -0
  222. package/dist/src/scripts/live-smoke/scenarios.js +34 -1
  223. package/dist/src/scripts/live-smoke.js +1 -0
  224. package/dist/src/types.d.ts +273 -2
  225. package/package.json +4 -3
  226. package/references/2026-07-16-chat-work-surfaces.md +87 -0
  227. package/references/agents-runner.md +13 -2
  228. package/references/backend-protocol.md +19 -7
  229. package/references/language-coverage.md +40 -3
  230. package/references/localization.md +48 -10
  231. package/references/python-parity.md +16 -4
  232. package/references/responses-adapter.md +12 -1
  233. package/references/troubleshooting.md +49 -6
@@ -1,4 +1,6 @@
1
1
  export type CommandStatus = "ok" | "partial" | "timeout" | "blocked" | "needs_confirmation" | "not_found" | "unsupported" | "error";
2
+ export type SubmissionState = "not_submitted" | "submitted" | "submitted_unconfirmed" | "submitted_generating";
3
+ export type CompletionState = "complete" | "generating" | "stopped" | "partial" | "unknown";
2
4
  export type BlockerKind = "browser_bridge_unavailable" | "login_required" | "captcha" | "rate_limit" | "modal" | "permission" | "confirmation" | "selector_drift" | "artifact_unavailable" | "artifact_selector_drift" | "artifact_download_unavailable" | "download_unavailable" | "upload_failed" | "not_found" | "unknown";
3
5
  export type CommandContext = {
4
6
  url?: string;
@@ -6,6 +8,8 @@ export type CommandContext = {
6
8
  title?: string;
7
9
  turnCount?: number;
8
10
  assistantTurnCount?: number;
11
+ experience?: ChatGPTExperience;
12
+ selectorProfile?: SurfaceSelectorProfile;
9
13
  browserName?: string;
10
14
  tabId?: string;
11
15
  timestamp: string;
@@ -174,6 +178,10 @@ export type SubmitData = {
174
178
  submitted: boolean;
175
179
  userTurnText?: string;
176
180
  turnCount?: number;
181
+ submissionState?: SubmissionState;
182
+ completionState?: CompletionState;
183
+ generationActive?: boolean;
184
+ generationSignals?: string[];
177
185
  };
178
186
  export type WaitArgs = {
179
187
  afterTurnCount?: number;
@@ -183,12 +191,19 @@ export type WaitArgs = {
183
191
  stableMs?: number;
184
192
  pollMs?: number;
185
193
  mode?: "normal" | "deep_research";
194
+ responseContent?: "include" | "metadata";
186
195
  };
187
196
  export type WaitData = {
188
197
  complete: boolean;
189
198
  responseText?: string;
199
+ responseChars?: number;
200
+ responseSha256?: string;
201
+ responseContent?: "include" | "metadata";
190
202
  assistantTurnCount: number;
191
203
  elapsedMs: number;
204
+ completionState?: CompletionState;
205
+ generationActive?: boolean;
206
+ generationSignals?: string[];
192
207
  };
193
208
  export type ResponseFormat = "markdown" | "text" | "normalized_text" | "visible_text" | "html" | "blocks" | "all";
194
209
  export type ResponseCitation = {
@@ -273,10 +288,14 @@ export type ReadLatestData = {
273
288
  actions?: ResponseAction[];
274
289
  thoughtDurationText?: string;
275
290
  sourcesAvailable?: boolean;
291
+ completionState?: CompletionState;
292
+ generationActive?: boolean;
293
+ generationSignals?: string[];
276
294
  };
277
295
  export type WaitAndReadArgs = WaitArgs & ReadLatestArgs;
278
296
  export type AskArgs = {
279
- text: string;
297
+ text?: string;
298
+ prompt?: string;
280
299
  wait?: boolean | WaitArgs;
281
300
  read?: boolean | ReadLatestArgs;
282
301
  timeoutMs?: number;
@@ -287,10 +306,30 @@ export type AskReadData = {
287
306
  complete?: boolean;
288
307
  conversationId?: string;
289
308
  title?: string;
309
+ submissionState?: SubmissionState;
310
+ completionState?: CompletionState;
311
+ generationActive?: boolean;
312
+ generationSignals?: string[];
313
+ };
314
+ export type MessageStatusArgs = {
315
+ maxPreviewChars?: number;
316
+ };
317
+ export type MessageStatusData = {
318
+ turnCount?: number;
319
+ assistantTurnCount: number;
320
+ latestAssistantTurnIndex?: number;
321
+ latestAssistantText?: string;
322
+ latestAssistantPreview?: string;
323
+ latestAssistantTextLength?: number;
324
+ completionState: CompletionState;
325
+ generationActive: boolean;
326
+ generationSignals: string[];
290
327
  };
291
328
  export type AttachFilesArgs = {
292
329
  paths: string[];
293
330
  timeoutMs?: number;
331
+ includeDiagnostics?: boolean;
332
+ includeHashes?: boolean;
294
333
  };
295
334
  export type AttachedFile = {
296
335
  path: string;
@@ -302,11 +341,13 @@ export type FilePreflightArgs = {
302
341
  paths: string[];
303
342
  maxBytesPerFile?: number;
304
343
  maxTotalBytes?: number;
344
+ includeHashes?: boolean;
305
345
  };
306
346
  export type FilePreflightFile = AttachedFile & {
307
347
  extension: string;
308
348
  mimeType: string;
309
349
  category: FileCategory;
350
+ sha256?: string;
310
351
  };
311
352
  export type FilePreflightData = {
312
353
  files: FilePreflightFile[];
@@ -314,6 +355,20 @@ export type FilePreflightData = {
314
355
  };
315
356
  export type AttachFilesData = {
316
357
  files: AttachedFile[];
358
+ diagnostics?: FileUploadDiagnostics;
359
+ };
360
+ export type BrowserInputFileDiagnostic = {
361
+ name: string;
362
+ size: number;
363
+ type?: string;
364
+ lastModified?: number;
365
+ };
366
+ export type BrowserInputDiagnostic = {
367
+ files: BrowserInputFileDiagnostic[];
368
+ };
369
+ export type FileUploadDiagnostics = {
370
+ preflight: FilePreflightData;
371
+ browserInput?: BrowserInputDiagnostic;
317
372
  };
318
373
  export type ProjectSourceStatus = "ready" | "processing" | "failed" | "unknown";
319
374
  export type ProjectSource = {
@@ -460,6 +515,178 @@ export type SetModeArgs = {
460
515
  version?: string;
461
516
  timeoutMs?: number;
462
517
  };
518
+ export type GetModeArgs = {
519
+ timeoutMs?: number;
520
+ };
521
+ export type GetModeData = {
522
+ modes: string[];
523
+ };
524
+ export type ChatGPTExperience = "chat" | "work" | "unknown";
525
+ export type SurfaceSelectorProfile = "chat_legacy_v1" | "chat_simplified_v1" | "work_basic_v1" | "work_advanced_v1" | "unknown";
526
+ export type SurfaceProfileSupportState = "current" | "compatibility" | "unverified" | "retired";
527
+ export type SurfaceProfileObservation = {
528
+ observedAt: string;
529
+ provenance: string;
530
+ locale: string;
531
+ region: string;
532
+ accountScope: string;
533
+ planScope: string;
534
+ workspaceScope: string;
535
+ supportState: SurfaceProfileSupportState;
536
+ };
537
+ export type ExperienceConfidence = "high" | "medium" | "low";
538
+ export type ExperienceEvidence = {
539
+ source: "url" | "composer" | "control" | "menu" | "heading";
540
+ label: string;
541
+ };
542
+ export type DetectExperienceArgs = {
543
+ timeoutMs?: number;
544
+ };
545
+ export type DetectExperienceData = {
546
+ experience: ChatGPTExperience;
547
+ selectorProfile: SurfaceSelectorProfile;
548
+ confidence: ExperienceConfidence;
549
+ evidence: ExperienceEvidence[];
550
+ };
551
+ export type OpenExperienceArgs = {
552
+ experience: Exclude<ChatGPTExperience, "unknown">;
553
+ timeoutMs?: number;
554
+ };
555
+ export type OpenExperienceData = {
556
+ experience: Exclude<ChatGPTExperience, "unknown">;
557
+ previousExperience: ChatGPTExperience;
558
+ changed: boolean;
559
+ selectorProfile: SurfaceSelectorProfile;
560
+ };
561
+ export type ConfigurationAxis = "model" | "intelligence" | "effort" | "speed" | "modelVersion";
562
+ export type SurfaceProfileFixture = SurfaceProfileObservation & {
563
+ schemaVersion: "chatgpt.browser_control.surface_profile.v1";
564
+ id: string;
565
+ snapshot: {
566
+ url: string;
567
+ composerLabels: string[];
568
+ mainControls: string[];
569
+ mainText: string;
570
+ };
571
+ panel: {
572
+ openerLabel?: string;
573
+ axisRows: Array<{
574
+ axis: ConfigurationAxis;
575
+ label: string;
576
+ value?: string;
577
+ }>;
578
+ advancedVisible: boolean;
579
+ };
580
+ menuItems: Array<{
581
+ label: string;
582
+ normalized: string;
583
+ role?: string;
584
+ checked?: boolean;
585
+ expanded?: boolean;
586
+ hasPopup?: boolean;
587
+ testId?: string;
588
+ ariaLabel?: string;
589
+ }>;
590
+ expected: {
591
+ experience: ChatGPTExperience;
592
+ selectorProfile: SurfaceSelectorProfile;
593
+ availableAxes: ConfigurationAxis[];
594
+ active: Partial<Record<ConfigurationAxis, string>>;
595
+ };
596
+ };
597
+ export type ConfigurationOption = {
598
+ id: string;
599
+ label: string;
600
+ selected: boolean;
601
+ disabled?: boolean;
602
+ description?: string;
603
+ hasSubmenu?: boolean;
604
+ };
605
+ export type ConfigurationSelection = {
606
+ model?: string;
607
+ intelligence?: string;
608
+ effort?: string;
609
+ speed?: string;
610
+ modelVersion?: string;
611
+ /** Backward-compatible alias for modelVersion. */
612
+ version?: string;
613
+ };
614
+ export type InspectConfigurationArgs = {
615
+ experience?: Exclude<ChatGPTExperience, "unknown">;
616
+ includeOptions?: boolean;
617
+ timeoutMs?: number;
618
+ };
619
+ export type ConfigurationInspectionData = {
620
+ experience: ChatGPTExperience;
621
+ selectorProfile: SurfaceSelectorProfile;
622
+ availableAxes: ConfigurationAxis[];
623
+ active: Partial<Record<ConfigurationAxis, string>>;
624
+ options: Partial<Record<ConfigurationAxis, ConfigurationOption[]>>;
625
+ verified: boolean;
626
+ evidence: ExperienceEvidence[];
627
+ };
628
+ export type ApplyConfigurationArgs = {
629
+ experience?: Exclude<ChatGPTExperience, "unknown">;
630
+ desired: ConfigurationSelection;
631
+ strict?: boolean;
632
+ timeoutMs?: number;
633
+ };
634
+ export type AppliedConfigurationSelection = {
635
+ axis: ConfigurationAxis;
636
+ requested: string;
637
+ selected: string;
638
+ };
639
+ export type ApplyConfigurationData = {
640
+ requested: ConfigurationSelection;
641
+ selected: AppliedConfigurationSelection[];
642
+ before: ConfigurationInspectionData;
643
+ after: ConfigurationInspectionData;
644
+ verified: boolean;
645
+ };
646
+ export type WorkTaskRef = {
647
+ url?: string;
648
+ conversationId?: string;
649
+ title?: string;
650
+ baselineTurnCount?: number;
651
+ baselineAssistantTurnCount?: number;
652
+ };
653
+ export type StartWorkArgs = {
654
+ prompt: string;
655
+ /** Start from a blank Work task when possible. Defaults to true. */
656
+ newTask?: boolean;
657
+ files?: string[];
658
+ configuration?: ConfigurationSelection;
659
+ wait?: boolean | WaitArgs;
660
+ read?: boolean | ReadLatestArgs;
661
+ timeoutMs?: number;
662
+ };
663
+ export type StartWorkData = {
664
+ task: WorkTaskRef;
665
+ submitted: SubmitData;
666
+ configuration?: ApplyConfigurationData;
667
+ wait?: WaitData;
668
+ response?: ReadLatestData;
669
+ };
670
+ export type WorkStatusArgs = MessageStatusArgs & {
671
+ includeArtifacts?: boolean;
672
+ };
673
+ export type WorkStatusData = {
674
+ experience: "work";
675
+ task: WorkTaskRef;
676
+ message: MessageStatusData;
677
+ artifacts?: ArtifactListData;
678
+ };
679
+ export type WorkWaitArgs = WaitArgs;
680
+ export type WorkWaitData = WaitData;
681
+ export type SteerWorkArgs = {
682
+ prompt: string;
683
+ wait?: boolean | WaitArgs;
684
+ read?: boolean | ReadLatestArgs;
685
+ timeoutMs?: number;
686
+ };
687
+ export type SteerWorkData = AskReadData;
688
+ export type ReadWorkLatestArgs = ReadLatestArgs;
689
+ export type ReadWorkLatestData = ReadLatestData;
463
690
  export type SelectToolArgs = {
464
691
  tool: "web_search" | "deep_research" | "create_image" | string;
465
692
  timeoutMs?: number;
@@ -468,6 +695,42 @@ export type SequenceStep = {
468
695
  id: string;
469
696
  command: "session.bootstrap";
470
697
  args?: BootstrapArgs;
698
+ } | {
699
+ id: string;
700
+ command: "experience.detect";
701
+ args?: DetectExperienceArgs;
702
+ } | {
703
+ id: string;
704
+ command: "experience.open";
705
+ args: OpenExperienceArgs;
706
+ } | {
707
+ id: string;
708
+ command: "configuration.inspect";
709
+ args?: InspectConfigurationArgs;
710
+ } | {
711
+ id: string;
712
+ command: "configuration.apply";
713
+ args: ApplyConfigurationArgs;
714
+ } | {
715
+ id: string;
716
+ command: "work.start";
717
+ args: StartWorkArgs;
718
+ } | {
719
+ id: string;
720
+ command: "work.status";
721
+ args?: WorkStatusArgs;
722
+ } | {
723
+ id: string;
724
+ command: "work.wait";
725
+ args?: WorkWaitArgs;
726
+ } | {
727
+ id: string;
728
+ command: "work.steer";
729
+ args: SteerWorkArgs;
730
+ } | {
731
+ id: string;
732
+ command: "work.readLatest";
733
+ args?: ReadWorkLatestArgs;
471
734
  } | {
472
735
  id: string;
473
736
  command: "threads.search";
@@ -500,6 +763,10 @@ export type SequenceStep = {
500
763
  id: string;
501
764
  command: "messages.readLatest";
502
765
  args?: ReadLatestArgs;
766
+ } | {
767
+ id: string;
768
+ command: "messages.status";
769
+ args?: MessageStatusArgs;
503
770
  } | {
504
771
  id: string;
505
772
  command: "messages.waitAndRead";
@@ -571,6 +838,7 @@ export type RuntimeEnv = {
571
838
  page?: PageLike;
572
839
  clipboard?: ClipboardLike;
573
840
  now?: () => Date;
841
+ expectedTabId?: string;
574
842
  };
575
843
  export type ClipboardLike = {
576
844
  read: () => Promise<string>;
@@ -628,6 +896,8 @@ export type WaitForEventOptions = {
628
896
  timeoutMs?: number;
629
897
  };
630
898
  export type PageLike = {
899
+ id?: string;
900
+ tabId?: string;
631
901
  url?: () => string | Promise<string>;
632
902
  goto?: (url: string, options?: unknown) => Promise<unknown>;
633
903
  title?: () => Promise<string>;
@@ -666,7 +936,8 @@ export type PageLike = {
666
936
  [key: string]: unknown;
667
937
  };
668
938
  };
669
- export type AskHelperArgs = AskArgs & {
939
+ export type AskHelperArgs = Omit<AskArgs, "text" | "prompt"> & {
940
+ text: string;
670
941
  thread?: ThreadTarget;
671
942
  };
672
943
  export type AskInThreadArgs = AskHelperArgs & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "codex-chatgpt-control",
3
- "version": "0.2.0-alpha.1",
4
- "description": "Unofficial SDK for Codex agents controlling visible ChatGPT web sessions.",
3
+ "version": "0.5.0-alpha.1",
4
+ "description": "Unofficial SDK for controlling visible ChatGPT Chat and Work sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -34,6 +34,7 @@
34
34
  "test": "vitest run",
35
35
  "test:watch": "vitest",
36
36
  "thread": "tsx src/scripts/continue-thread.ts",
37
+ "capture:surface-profile": "tsx src/scripts/capture-surface-profile.ts",
37
38
  "smoke:hi": "tsx src/scripts/smoke-hi.ts",
38
39
  "smoke:search": "tsx src/scripts/smoke-search-open-read.ts",
39
40
  "smoke:attach": "tsx src/scripts/smoke-attach-file.ts",
@@ -74,7 +75,7 @@
74
75
  "devDependencies": {
75
76
  "@types/node": "^24.13.1",
76
77
  "ajv": "^8.17.1",
77
- "esbuild": "^0.28.0",
78
+ "esbuild": "^0.28.1",
78
79
  "tsx": "^4.20.0",
79
80
  "typescript": "^5.8.0",
80
81
  "vitest": "^4.1.8"
@@ -0,0 +1,87 @@
1
+ ---
2
+ title: Chat and Work Surfaces
3
+ date: 2026-07-16
4
+ type: reference
5
+ status: draft
6
+ ---
7
+
8
+ # Chat and Work Surfaces
9
+
10
+ The SDK models visible ChatGPT as capabilities discovered from the active
11
+ composer, controls, and URL—not as one flat model picker.
12
+
13
+ ## Experiences And Profiles
14
+
15
+ Experiences:
16
+
17
+ - `chat`
18
+ - `work`
19
+ - `unknown`
20
+
21
+ Observed selector profiles:
22
+
23
+ - `chat_legacy_v1`
24
+ - `chat_simplified_v1`
25
+ - `work_basic_v1`
26
+ - `work_advanced_v1`
27
+ - `unknown`
28
+
29
+ Profiles describe UI shape. They must not be presented as subscription plans,
30
+ entitlements, regions, or guaranteed underlying models. Sanitized fixtures
31
+ store observed date, locale, provenance, scoped surface evidence, visible
32
+ configuration, and expected semantic output without conversation content.
33
+
34
+ ## Configuration
35
+
36
+ Chat may expose intelligence and nested model/version controls. Work exposes
37
+ model, effort, and speed axes. Inspection reports available axes, active values,
38
+ visible options, selector profile, and evidence.
39
+
40
+ Strict application:
41
+
42
+ 1. detects or opens the requested experience;
43
+ 2. inspects the current state;
44
+ 3. changes only requested axes;
45
+ 4. reopens nested controls as required;
46
+ 5. inspects again;
47
+ 6. blocks if every requested value is not visibly verified.
48
+
49
+ Legacy `modes.set/get` and runner `mode` inputs remain supported. They preserve
50
+ their pre-0.5 warning-oriented behavior. New code requiring a verified
51
+ postcondition should use `configuration.apply({ strict: true })`.
52
+
53
+ ## Work Lifecycle
54
+
55
+ `work.start` defaults to `newTask: true`. If messages are already loaded and a
56
+ unique new-task control cannot be verified, it blocks rather than submitting
57
+ into the current task. `newTask: false` is an explicit request to continue the
58
+ currently visible task.
59
+
60
+ Submission uses matching-turn recovery. A no-op send click may be retried only
61
+ while the prompt remains in the composer and no matching user turn exists.
62
+ After a partial or timeout result, callers must preserve the task/thread
63
+ identity and use:
64
+
65
+ - `work.status`
66
+ - `work.wait`
67
+ - `work.steer`
68
+ - `work.readLatest`
69
+ - `work.artifacts.*`
70
+
71
+ The original prompt must not be blindly resubmitted.
72
+
73
+ ## Locale And Rollout Policy
74
+
75
+ Shared semantic types and profile fixtures make locale and rollout support
76
+ incremental. New labels require sanitized evidence plus locale-registry and
77
+ fixture updates. Unknown or absent controls return structured capability or
78
+ selector-drift results.
79
+
80
+ Use `npm run capture:surface-profile -- --id <normalized-id>` against an
81
+ already-open authorized tab to create a local `unverified` draft. The capture
82
+ is read-only with respect to configuration, strips conversation identity and
83
+ content, and requires explicit normalized metadata before a fixture can be
84
+ promoted to `current` or `compatibility`.
85
+
86
+ The SDK does not spoof regions, guess account plans, infer effective models from
87
+ one label, or claim support for a native desktop surface from web fixtures.
@@ -11,11 +11,14 @@ const chatgpt = createChatGPT({ agent: globalThis.agent });
11
11
  const reviewer = chatgpt.agent({ name: "reviewer", instructions: "Review deeply." });
12
12
  const plan = chatgpt.runner.plan(reviewer, {
13
13
  input: "Review this design.",
14
- thread: { type: "new" }
14
+ thread: { type: "new" },
15
+ experience: "chat"
15
16
  });
16
17
  const result = await chatgpt.runner.run(reviewer, {
17
18
  input: "Review this design.",
18
- thread: { type: "new" }
19
+ thread: { type: "new" },
20
+ experience: "chat",
21
+ configuration: { intelligence: "Pro" }
19
22
  });
20
23
  ```
21
24
 
@@ -27,6 +30,14 @@ const result = await chatgpt.runner.run(reviewer, {
27
30
 
28
31
  `runner.run()` returns a `ChatGPTRunResult` with `output_text`, `finalOutput`, `output`, `interruptions`, and `state`. Browser-control blockers are surfaced as resumable interruptions when the underlying command can be retried after user approval, login, or permission repair.
29
32
 
33
+ `experience` and `configuration` are visible product preferences. When present,
34
+ the plan emits `experience.open` and strict `configuration.apply` steps before
35
+ the prompt. Successful results expose `experience.opened` and
36
+ `configuration.applied` milestone items. The legacy `mode` input remains
37
+ supported, but new callers should use the surface-aware fields. If both are
38
+ present, `configuration` takes precedence and the legacy `mode` request is not
39
+ executed.
40
+
30
41
  For milestone streaming, call `chatgpt.runner.run(agent, input, { stream: true })` and iterate events before awaiting `stream.completed`. This is milestone streaming only, not token-delta streaming.
31
42
 
32
43
  Do not pass API-only model controls such as `temperature`, `logprobs`, `seed`, or hidden system instructions.
@@ -67,7 +67,9 @@ Current protocol error codes are:
67
67
 
68
68
  Browser-control blockers are not protocol errors. They are normal command or runner results with `status: "blocked"`, `status: "partial"`, or `status: "needs_confirmation"` plus blocker/interruption details.
69
69
 
70
- `status: "partial"` is the required result for incomplete response capture. A partial result may still include `output_text` and `data.responseText`, but consumers must treat that text as incomplete until a later wait confirms completion. Common causes are wait timeout after partial assistant text, active generation controls such as `Stop answering`, stopped-generation markers such as `Stopped thinking`, or a read fallback after the wait step could not confirm completion. Intentional capture clipping uses `data.captureLimit` plus warnings; it is separate from ChatGPT generation length.
70
+ `status: "partial"` is the required result for incomplete response capture. A partial result may still include `output_text` and `data.responseText`, but consumers must treat that text as incomplete until a later wait confirms completion. Common causes are wait timeout after partial assistant text, active generation controls such as `Stop answering`, stopped-generation markers such as `Stopped thinking`, or a read fallback after the wait step could not confirm completion. Message command data may include `submissionState`, `completionState`, `generationActive`, and `generationSignals`; `completionState: "generating"` or `generationActive: true` is explicit evidence that the visible ChatGPT turn is still running. For status-only polling, `messages.wait` accepts `responseContent: "metadata"`; partial and completed wait results then omit assistant text and instead return compact metadata such as `data.responseChars` and `data.responseSha256`. Intentional capture clipping uses `data.captureLimit` plus warnings; it is separate from ChatGPT generation length.
71
+
72
+ Use `messages.status({ maxPreviewChars })` for a compact latest-assistant progress snapshot when a host tool-call ceiling is shorter than the expected ChatGPT generation. It returns counts, latest-assistant preview length, `completionState`, `generationActive`, and generation signals without treating partial text as final, and without the cost of a full `readLatest`/`wait` probe.
71
73
 
72
74
  ## Streaming
73
75
 
@@ -78,9 +80,10 @@ Streaming commands emit backend event lines until `completed` or `error`.
78
80
  "schemaVersion": "chatgpt.browser_control.backend_event.v1",
79
81
  "requestId": "req_stream",
80
82
  "type": "run_item_stream_event",
81
- "name": "message_completed",
83
+ "name": "message_in_progress",
82
84
  "item": {
83
- "type": "message.completed"
85
+ "type": "message.in_progress",
86
+ "completionState": "generating"
84
87
  }
85
88
  }
86
89
  ```
@@ -99,7 +102,7 @@ The final event contains a normal runner result:
99
102
  }
100
103
  ```
101
104
 
102
- Streaming is milestone streaming only. It does not promise token deltas or OpenAI API stream-event parity.
105
+ Streaming is milestone streaming only. It does not promise token deltas or OpenAI API stream-event parity. Partial assistant text is emitted as `message_in_progress`; only completion-confirmed output is emitted as `message_completed`.
103
106
 
104
107
  ## Required Backend Commands
105
108
 
@@ -112,7 +115,14 @@ The backend must support:
112
115
  - diagnostics: `doctor`
113
116
  - reports: `createReport`, `reports.create`, `reports.redact`, `reports.summarize`
114
117
  - command discovery: `commands`, `describe`, `help`
115
- - primitives: `session.bootstrap`, `threads.*`, `messages.*`, `artifacts.*`, `files.preflight`, `files.attach`, `files.downloadLatest`, `projects.sources.list`, `projects.sources.planAdd`, `projects.sources.add`, `modes.set`, `tools.select`, `response.copy`
118
+ - primitives: `session.bootstrap`, `experience.detect`, `experience.open`, `configuration.inspect`, `configuration.apply`, `work.start`, `work.status`, `work.wait`, `work.steer`, `work.readLatest`, `threads.*`, `messages.*`, `artifacts.*`, `files.preflight`, `files.attach`, `files.downloadLatest`, `projects.sources.list`, `projects.sources.planAdd`, `projects.sources.add`, `modes.set`, `modes.get`, `tools.select`, `response.copy`
119
+
120
+ `experience.detect` and `configuration.inspect` are non-mutating capability
121
+ discovery. `configuration.apply` is strict by default and must verify the final
122
+ visible state. `work.start` defaults to a fresh task and must not append to a
123
+ loaded task unless the caller explicitly passes `newTask: false`. A partial or
124
+ timeout Work result is recovered through status/wait/read on the same task, not
125
+ by resubmitting the original prompt.
116
126
 
117
127
  `doctor` returns a normal `CommandResult` whose `data.checks` map is extensible. Scenario checks such as `existing_tab`, `artifacts`, `file_preflight`, `localization`, and `reports` may add optional `code`, `blockerKind`, `nextCommand`, and JSON `details` fields to individual check entries while preserving the existing `status`, `message`, and `remediation` fields.
118
128
 
@@ -120,7 +130,9 @@ The backend must support:
120
130
 
121
131
  Attachment paths are interpreted on the machine running the Node backend. Use an absolute path in that host operating system's native form. On macOS/Linux/WSL, use paths such as `/example/user/file.pdf`, `/home/you/file.pdf`, or `/mnt/c/example/user/file.pdf`. On Windows backend hosts, use fully qualified paths such as `C:\Users\you\file.pdf` or UNC paths such as `\\server\share\file.pdf`. Drive-relative paths like `C:Users\you\file.pdf`, root-relative paths like `\tmp\file.pdf`, and Windows-looking paths sent to a POSIX backend are rejected before filesystem access.
122
132
 
123
- Use `files.preflight` for non-mutating local validation before browser upload workflows. It validates absolute paths, existence, readability, file-vs-directory status, configurable per-file and total byte limits, duplicate basenames, duplicate resolved paths, zero-byte files, and extension-based MIME/category guesses. It does not open ChatGPT, perform a live upload, or read file contents for MIME detection. `askWithFiles` and `files.attach` run the same preflight before upload attempts so obvious local file failures stop before browser interaction.
133
+ Use `files.preflight` for non-mutating local validation before browser upload workflows. It validates absolute paths, existence, readability, file-vs-directory status, configurable per-file and total byte limits, duplicate basenames, duplicate resolved paths, zero-byte files, and extension-based MIME/category guesses. Zero-byte files are blocked before browser interaction because ChatGPT rejects empty attachments. By default the command does not open ChatGPT, perform a live upload, read file contents for MIME detection, or return file-content fingerprints. Callers may pass `includeHashes: true` to include SHA-256 metadata for local diagnostics; file contents are never returned. `askWithFiles` and `files.attach` run the same preflight before upload attempts so obvious local file failures stop before browser interaction.
134
+
135
+ `files.attach` accepts `includeDiagnostics: true` to return metadata-only upload diagnostics in `data.diagnostics`: the preflight result plus the browser input's selected file names and sizes when the DOM exposes them. Pair `includeDiagnostics: true` with `includeHashes: true` when diagnosing whether a non-empty local file became an empty browser-side `File`; do not persist these diagnostics in public reports unless the user has approved content fingerprint metadata.
124
136
 
125
137
  ## Project Sources
126
138
 
@@ -213,7 +225,7 @@ Important: in Codex, `globalThis.agent` is not present until the Chrome plugin r
213
225
  The live Chrome bootstrap is:
214
226
 
215
227
  ```js
216
- const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/26.602.40724/scripts/browser-client.mjs");
228
+ const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/latest/scripts/browser-client.mjs");
217
229
  await setupBrowserRuntime({ globals: globalThis });
218
230
  globalThis.browser = await agent.browsers.get("extension");
219
231
  ```
@@ -5,6 +5,13 @@ The full set of languages ChatGPT exposes in **Settings → General → Language
5
5
  localization rollout described in [`localization.md`](./localization.md). Strings are
6
6
  stored per-locale under `src/dom/locale/<bcp47>.ts`.
7
7
 
8
+ The status table covers the pre-existing Chat/localization registry, not the new
9
+ Chat/Work profile graph introduced in July 2026. Work composer,
10
+ experience-switch, configuration-axis, and configuration-option coverage is
11
+ currently verified only for the sanitized English profiles. Do not interpret a
12
+ green row below as full Work support until that locale has matching profile
13
+ evidence.
14
+
8
15
  - Speaker counts are **crude guesstimates** (native + second-language, rounded), not
9
16
  researched figures. They exist only to prioritize the rollout.
10
17
  - `bcp47` is the suggested per-locale file name. Regional variants ChatGPT lists separately
@@ -113,6 +120,18 @@ guesstimate; the tail (≈#11–15) is close and easily reordered.
113
120
 
114
121
  ## Automated capture
115
122
 
123
+ For a single current Chat or Work surface, generate a sanitized, unverified
124
+ profile draft from an already-open authorized tab:
125
+
126
+ ```bash
127
+ npm run capture:surface-profile -- --id work-basic-en --locale en-US
128
+ ```
129
+
130
+ This command does not submit a prompt or change configuration. It opens visible
131
+ menus for inspection, normalizes any conversation URL to `/c/sanitized`, and
132
+ writes only bounded composer/configuration structure under
133
+ `outputs/surface-profiles/`.
134
+
116
135
  Use the repository capture script to drive the visible ChatGPT UI through Settings → General
117
136
  → Language, then open the composer Intelligence picker and record the localized labels:
118
137
 
@@ -120,6 +139,23 @@ Use the repository capture script to drive the visible ChatGPT UI through Settin
120
139
  npm run capture:intelligence-locales -- --auto-switch --all --if-missing open
121
140
  ```
122
141
 
142
+ To also capture localized running-generation controls such as `stopControl`, run the same
143
+ sweep with the bounded generation probe enabled:
144
+
145
+ ```bash
146
+ npm run capture:intelligence-locales -- \
147
+ --auto-switch \
148
+ --all \
149
+ --capture-generation-state \
150
+ --generation-timeout-ms 12000 \
151
+ --if-missing open
152
+ ```
153
+
154
+ The generation-state probe submits one short real prompt per locale in the visible ChatGPT
155
+ session, waits for the localized stop control, stops generation, and records only compact
156
+ control/status labels. Use it only when operating the user's visible ChatGPT session is
157
+ acceptable.
158
+
123
159
  The script uses the native language names from this tracker, verifies the rendered
124
160
  `document.documentElement.lang`, writes JSONL evidence under
125
161
  `outputs/intelligence-locale-captures/`, and restores the initially selected language by
@@ -134,9 +170,10 @@ changes the settings or picker DOM, the run should emit a blocker record instead
134
170
  3. Open the model switcher and the `+` menu with **real** clicks (Radix menus ignore
135
171
  synthetic `.click()`) and read the menu items → mode + tool labels.
136
172
  4. Open search → placeholder; observe a conversation → copy-response + response-actions.
137
- `stopControl` is only present mid-generation; login/captcha/rate-limit copy needs a
138
- logged-out/limited state — these may lag and rely on the English fallback + the
139
- `selector_drift` safety net until captured.
173
+ `stopControl` is present only mid-generation and should be captured with
174
+ `--capture-generation-state`; login/captcha/rate-limit copy needs a logged-out/limited
175
+ state — these may lag and rely on the English fallback + the `selector_drift` safety net
176
+ until captured.
140
177
  5. Write the verified strings to `src/dom/locale/<bcp47>.ts` and register it in
141
178
  `src/dom/locale/index.ts`. Build + test + bundle + sync.
142
179
  6. Restore the account language to English (US) when the run is complete.