@wlv-zedd/dsh-chatgpt-web 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/assets/demo.gif +0 -0
  4. package/assets/hero-demo.png +0 -0
  5. package/assets/promo-dshmarket-official.png +0 -0
  6. package/cordis.patch.yml +4 -0
  7. package/lib/cli.js +239642 -0
  8. package/lib/plugin.js +195 -0
  9. package/package.json +88 -0
  10. package/screenshots.json +5 -0
  11. package/src/adapters/base.ts +16 -0
  12. package/src/adapters/chatgpt-web/adapter-error.ts +59 -0
  13. package/src/adapters/chatgpt-web/browser-helper-main.ts +513 -0
  14. package/src/adapters/chatgpt-web/browser-helper-prompt-selection.ts +27 -0
  15. package/src/adapters/chatgpt-web/browser-worker.ts +4944 -0
  16. package/src/adapters/chatgpt-web/codex-rollout-environment.ts +628 -0
  17. package/src/adapters/chatgpt-web/compaction-handoff.ts +533 -0
  18. package/src/adapters/chatgpt-web/compaction-transaction.ts +142 -0
  19. package/src/adapters/chatgpt-web/concurrency.ts +6 -0
  20. package/src/adapters/chatgpt-web/conversation-key.ts +58 -0
  21. package/src/adapters/chatgpt-web/environment.ts +669 -0
  22. package/src/adapters/chatgpt-web/index.ts +1544 -0
  23. package/src/adapters/chatgpt-web/input-tokens.ts +74 -0
  24. package/src/adapters/chatgpt-web/launcher-helper-client.ts +695 -0
  25. package/src/adapters/chatgpt-web/markdown.ts +418 -0
  26. package/src/adapters/chatgpt-web/mcp-main.ts +25 -0
  27. package/src/adapters/chatgpt-web/mcp-server.ts +933 -0
  28. package/src/adapters/chatgpt-web/model.ts +70 -0
  29. package/src/adapters/chatgpt-web/native-compaction-control.ts +74 -0
  30. package/src/adapters/chatgpt-web/output-validation.ts +62 -0
  31. package/src/adapters/chatgpt-web/process-line-writer.ts +46 -0
  32. package/src/adapters/chatgpt-web/prompt.ts +702 -0
  33. package/src/adapters/chatgpt-web/retry-policy.ts +73 -0
  34. package/src/adapters/chatgpt-web/rolling-checkpoint.ts +384 -0
  35. package/src/adapters/chatgpt-web/thread-environment.ts +238 -0
  36. package/src/adapters/chatgpt-web/tool-stream-parser.ts +601 -0
  37. package/src/adapters/chatgpt-web/turn-broker.ts +1481 -0
  38. package/src/adapters/chatgpt-web/turn-execution.ts +816 -0
  39. package/src/adapters/chatgpt-web/turn-progress.ts +292 -0
  40. package/src/adapters/chatgpt-web/usage.ts +121 -0
  41. package/src/adapters/image.ts +9 -0
  42. package/src/bridge.ts +1083 -0
  43. package/src/browser-login.ts +521 -0
  44. package/src/chatgpt-session.ts +240 -0
  45. package/src/chatgpt-web-models.ts +400 -0
  46. package/src/cli.ts +568 -0
  47. package/src/codex-integration-document.ts +824 -0
  48. package/src/codex-integration-journal.ts +212 -0
  49. package/src/codex-integration-route.ts +515 -0
  50. package/src/codex-integration-shared.ts +332 -0
  51. package/src/codex-integration.ts +529 -0
  52. package/src/codex-interrupt-hook.ts +158 -0
  53. package/src/config.ts +616 -0
  54. package/src/dev-chat/cli.ts +432 -0
  55. package/src/dev-chat/constants.ts +3 -0
  56. package/src/dev-chat/driver.ts +655 -0
  57. package/src/dev-chat/profile.ts +223 -0
  58. package/src/dev-chat/session.ts +287 -0
  59. package/src/dev-chat/transport.ts +54 -0
  60. package/src/doctor.ts +237 -0
  61. package/src/event-queue.ts +45 -0
  62. package/src/http-body.ts +30 -0
  63. package/src/launcher-browser-host.ts +695 -0
  64. package/src/lib/errors.ts +281 -0
  65. package/src/lib/token-estimate.ts +42 -0
  66. package/src/login-helper.cjs +140 -0
  67. package/src/model-catalog.ts +197 -0
  68. package/src/native-passthrough.ts +261 -0
  69. package/src/plugin.ts +191 -0
  70. package/src/process.ts +45 -0
  71. package/src/responses/compaction.ts +199 -0
  72. package/src/responses/parser.ts +633 -0
  73. package/src/responses/reasoning-envelope.ts +49 -0
  74. package/src/responses/schema.ts +172 -0
  75. package/src/responses/state.ts +230 -0
  76. package/src/server.ts +1111 -0
  77. package/src/service.ts +315 -0
  78. package/src/setup.ts +671 -0
  79. package/src/stall-timeout.ts +23 -0
  80. package/src/tunnel-service.ts +160 -0
  81. package/src/tunnel.ts +417 -0
  82. package/src/turndown-plugin-gfm.d.ts +5 -0
  83. package/src/types.ts +307 -0
  84. package/src/usage/totals.ts +12 -0
  85. package/src/version.ts +1 -0
@@ -0,0 +1,70 @@
1
+ import {
2
+ CHATGPT_WEB_BACKEND_MODEL,
3
+ CHATGPT_WEB_LUNA_BACKEND_MODEL,
4
+ } from "../../chatgpt-web-models";
5
+
6
+ export const CHATGPT_WEB_MODEL_ID = CHATGPT_WEB_BACKEND_MODEL;
7
+ export const CHATGPT_WEB_LUNA_MODEL_ID = CHATGPT_WEB_LUNA_BACKEND_MODEL;
8
+
9
+ export interface ChatGptWebCapabilities {
10
+ localToolsEnabled: boolean;
11
+ solAvailable: boolean;
12
+ proAvailable: boolean;
13
+ }
14
+
15
+ export interface ChatGptWebModelMode {
16
+ modelId: string;
17
+ effort: "low" | "medium" | "high" | "xhigh" | "max";
18
+ displayLabel: "Luna" | "Think" | "Instant" | "Medium" | "High" | "Extra High" | "Pro";
19
+ uiEffortIndex: 0 | 1 | 2 | 3 | 4 | null;
20
+ thinkEnabled: boolean;
21
+ localTools: boolean;
22
+ }
23
+
24
+ export function resolveChatGptWebModelMode(
25
+ modelId: string,
26
+ reasoning: string | undefined,
27
+ capabilities: ChatGptWebCapabilities,
28
+ ): ChatGptWebModelMode {
29
+ if (modelId === CHATGPT_WEB_LUNA_MODEL_ID) {
30
+ if (capabilities.solAvailable) {
31
+ throw new Error("ChatGPT Luna is not available while the account exposes the Sol model selector");
32
+ }
33
+ const effort = reasoning ?? "low";
34
+ if (effort !== "low" && effort !== "medium") {
35
+ throw new Error(`ChatGPT Luna mode is not supported: ${effort}`);
36
+ }
37
+ const thinkEnabled = effort === "medium";
38
+ return {
39
+ modelId,
40
+ effort,
41
+ displayLabel: thinkEnabled ? "Think" : "Luna",
42
+ uiEffortIndex: null,
43
+ thinkEnabled,
44
+ localTools: capabilities.localToolsEnabled,
45
+ };
46
+ }
47
+ if (modelId !== CHATGPT_WEB_MODEL_ID) {
48
+ throw new Error(`ChatGPT web model is not supported: ${modelId}`);
49
+ }
50
+ if (!capabilities.solAvailable) {
51
+ throw new Error("ChatGPT Sol modes are not available for this Luna-only account");
52
+ }
53
+ const effort = reasoning ?? "high";
54
+ switch (effort) {
55
+ case "low":
56
+ return { modelId, effort, displayLabel: "Instant", uiEffortIndex: 0, thinkEnabled: false, localTools: capabilities.localToolsEnabled };
57
+ case "medium":
58
+ return { modelId, effort, displayLabel: "Medium", uiEffortIndex: 1, thinkEnabled: false, localTools: capabilities.localToolsEnabled };
59
+ case "high":
60
+ return { modelId, effort, displayLabel: "High", uiEffortIndex: 2, thinkEnabled: false, localTools: capabilities.localToolsEnabled };
61
+ case "xhigh":
62
+ if (!capabilities.proAvailable) throw new Error("ChatGPT Extra High effort is not available for this account");
63
+ return { modelId, effort, displayLabel: "Extra High", uiEffortIndex: 3, thinkEnabled: false, localTools: capabilities.localToolsEnabled };
64
+ case "max":
65
+ if (!capabilities.proAvailable) throw new Error("ChatGPT Pro effort is not available for this account");
66
+ return { modelId, effort, displayLabel: "Pro", uiEffortIndex: 4, thinkEnabled: false, localTools: capabilities.localToolsEnabled };
67
+ default:
68
+ throw new Error(`ChatGPT web effort is not supported: ${effort}`);
69
+ }
70
+ }
@@ -0,0 +1,74 @@
1
+ import { COMPACT_PROMPT } from "../../responses/compaction";
2
+ import type { CompactionTransactionHandle } from "./compaction-transaction";
3
+
4
+ export const CODEX_COMPACTION_CONTROL_WIRE_NAME = "codex.control.compaction_handoff";
5
+ export const CODEX_ACTIVE_COMPACTION_REQUEST_MARKER = "CODEX_ACTIVE_COMPACTION_REQUEST";
6
+
7
+ function compactionControlBinding(transaction: CompactionTransactionHandle): string[] {
8
+ return [
9
+ "Submit the complete checkpoint through the attached Codex Native control plane by calling codex_tool_call exactly once with the binding below.",
10
+ "This one-shot control token is valid only for the reserved compaction operation; do not use it with codex_exec, codex_tool_inventory, or any outer Codex tool.",
11
+ "<codex_compaction_control>",
12
+ `turn_token ${transaction.token}`,
13
+ `wire_name ${CODEX_COMPACTION_CONTROL_WIRE_NAME}`,
14
+ `handoff_id ${transaction.handoffId}`,
15
+ "</codex_compaction_control>",
16
+ `Call codex_tool_call exactly once with ${JSON.stringify({
17
+ turn_token: transaction.token,
18
+ wire_name: CODEX_COMPACTION_CONTROL_WIRE_NAME,
19
+ arguments: {
20
+ handoff_id: transaction.handoffId,
21
+ summary: "<complete checkpoint summary>",
22
+ },
23
+ })}.`,
24
+ ];
25
+ }
26
+
27
+ /**
28
+ * Stop an active browser response only if it asks for another tool after Codex requested
29
+ * compaction. Results for calls already handed to Codex remain byte-for-byte canonical: when they
30
+ * are enough to finish the task, that ordinary final answer remains publishable. A later tool call
31
+ * is intercepted before execution and receives this instruction; the retained conversation then
32
+ * receives the sole structured checkpoint request on a clean message boundary.
33
+ */
34
+ export function activeCompactionToolResultInstruction(): string {
35
+ return [
36
+ `<${CODEX_ACTIVE_COMPACTION_REQUEST_MARKER}>`,
37
+ "Codex reached its context limit before this newly requested tool could be sent for execution. The tool was not executed.",
38
+ "Stop ordinary task work now, call no more tools, and end this Web response normally.",
39
+ "Do not create or submit a checkpoint in this response. After it settles, the retained conversation will receive exactly one separate structured compaction handoff request.",
40
+ `</${CODEX_ACTIVE_COMPACTION_REQUEST_MARKER}>`,
41
+ ].join("\n");
42
+ }
43
+
44
+ /**
45
+ * Zero Risk cannot submit a second browser message automatically. When Codex compacts at an
46
+ * already-visible native tool boundary, the same manually submitted response returns the
47
+ * checkpoint through the same Zero Risk request instead.
48
+ */
49
+ export function zeroRiskActiveCompactionToolResultInstruction(toolExecuted: boolean): string {
50
+ return [
51
+ `<${CODEX_ACTIVE_COMPACTION_REQUEST_MARKER}>`,
52
+ toolExecuted
53
+ ? "Codex reached its context limit while this Web response was waiting for the tool result above."
54
+ : "Codex reached its context limit before the requested tool could be sent for execution. The tool was not executed.",
55
+ toolExecuted
56
+ ? "Consume that canonical result, stop ordinary task work now, and do not call any more work tools."
57
+ : "Stop ordinary task work now and do not call any more work tools.",
58
+ COMPACT_PROMPT,
59
+ "Call no more work tools. Return only the complete checkpoint summary to Codex with codex_turn_complete.",
60
+ `</${CODEX_ACTIVE_COMPACTION_REQUEST_MARKER}>`,
61
+ ].join("\n");
62
+ }
63
+
64
+ export function structuredCompactionHandoffInstruction(
65
+ transaction: CompactionTransactionHandle,
66
+ ): string {
67
+ return [
68
+ "Automatic Codex context compaction has started. Stop ordinary task work and do not call any more work tools.",
69
+ COMPACT_PROMPT,
70
+ ...compactionControlBinding(transaction),
71
+ "After the control call returns submitted=true, call no more tools. The bridge will close this one-purpose Web response after accepting the checkpoint.",
72
+ "The outer bridge accepts compaction only after the structured checkpoint is valid and its owned browser turn has physically settled.",
73
+ ].join("\n");
74
+ }
@@ -0,0 +1,62 @@
1
+ import Ajv, { type ValidateFunction } from "ajv";
2
+ import addFormats from "ajv-formats";
3
+ import type { CodexJsonSchemaOutputFormat } from "../../types";
4
+ import { ChatGptWebAdapterError } from "./adapter-error";
5
+
6
+ export type ChatGptStructuredOutputValidator = (answer: string) => void;
7
+
8
+ function validationError(message: string): ChatGptWebAdapterError {
9
+ return new ChatGptWebAdapterError(message, {
10
+ status: 502,
11
+ errorType: "server_error",
12
+ code: "structured_output_validation_failed",
13
+ retryable: false,
14
+ });
15
+ }
16
+
17
+ export function createChatGptStructuredOutputValidator(
18
+ format: CodexJsonSchemaOutputFormat | undefined,
19
+ ): ChatGptStructuredOutputValidator | undefined {
20
+ if (!format?.strict) return undefined;
21
+
22
+ const ajv = new Ajv({
23
+ allErrors: true,
24
+ strict: false,
25
+ coerceTypes: false,
26
+ removeAdditional: false,
27
+ useDefaults: false,
28
+ validateFormats: true,
29
+ });
30
+ addFormats(ajv);
31
+
32
+ let validate: ValidateFunction;
33
+ try {
34
+ validate = ajv.compile(format.schema as object | boolean);
35
+ } catch (cause) {
36
+ throw new ChatGptWebAdapterError(
37
+ `Codex supplied an invalid strict JSON schema ${JSON.stringify(format.name)}: ${cause instanceof Error ? cause.message : String(cause)}`,
38
+ {
39
+ status: 400,
40
+ errorType: "invalid_request_error",
41
+ code: "invalid_output_schema",
42
+ retryable: false,
43
+ },
44
+ );
45
+ }
46
+
47
+ return (answer: string): void => {
48
+ let value: unknown;
49
+ try {
50
+ value = JSON.parse(answer);
51
+ } catch {
52
+ throw validationError(
53
+ `ChatGPT Web returned malformed JSON for strict Codex output schema ${JSON.stringify(format.name)}`,
54
+ );
55
+ }
56
+ if (validate(value)) return;
57
+ const detail = ajv.errorsText(validate.errors, { separator: "; " });
58
+ throw validationError(
59
+ `ChatGPT Web returned JSON that does not satisfy strict Codex output schema ${JSON.stringify(format.name)}${detail ? `: ${detail}` : ""}`,
60
+ );
61
+ };
62
+ }
@@ -0,0 +1,46 @@
1
+ import type { Writable } from "node:stream";
2
+
3
+ function asError(error: unknown): Error {
4
+ return error instanceof Error ? error : new Error(String(error));
5
+ }
6
+
7
+ export interface ProcessLineWriter {
8
+ write(line: string): boolean;
9
+ close(): void;
10
+ }
11
+
12
+ export function createProcessLineWriter(
13
+ stream: Writable,
14
+ onFailure: (error: Error) => void,
15
+ ): ProcessLineWriter {
16
+ let writable = true;
17
+
18
+ const fail = (error: unknown): void => {
19
+ if (!writable) return;
20
+ writable = false;
21
+ onFailure(asError(error));
22
+ };
23
+
24
+ // A failed Windows anonymous pipe emits an error even when write() also receives
25
+ // an error callback. Keeping this listener installed prevents an Electron helper
26
+ // from turning an expected parent disconnect into an uncaught main-process error.
27
+ stream.on("error", fail);
28
+
29
+ return {
30
+ write(line: string): boolean {
31
+ if (!writable || stream.destroyed || stream.writableEnded) return false;
32
+ try {
33
+ stream.write(`${line}\n`, error => {
34
+ if (error) fail(error);
35
+ });
36
+ return true;
37
+ } catch (error) {
38
+ fail(error);
39
+ return false;
40
+ }
41
+ },
42
+ close(): void {
43
+ writable = false;
44
+ },
45
+ };
46
+ }