@wlv-zedd/dsh-chatgpt-web 1.0.0 → 1.0.2

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 (81) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +140 -140
  3. package/cordis.patch.yml +4 -4
  4. package/lib/cli.js +13269 -11860
  5. package/lib/plugin.js +3 -50
  6. package/package.json +89 -88
  7. package/src/adapters/base.ts +16 -16
  8. package/src/adapters/chatgpt-web/adapter-error.ts +59 -59
  9. package/src/adapters/chatgpt-web/browser-helper-main.ts +513 -513
  10. package/src/adapters/chatgpt-web/browser-helper-prompt-selection.ts +27 -27
  11. package/src/adapters/chatgpt-web/browser-worker.ts +4944 -4944
  12. package/src/adapters/chatgpt-web/codex-rollout-environment.ts +628 -628
  13. package/src/adapters/chatgpt-web/compaction-handoff.ts +533 -533
  14. package/src/adapters/chatgpt-web/compaction-transaction.ts +142 -142
  15. package/src/adapters/chatgpt-web/concurrency.ts +6 -6
  16. package/src/adapters/chatgpt-web/conversation-key.ts +58 -58
  17. package/src/adapters/chatgpt-web/environment.ts +669 -669
  18. package/src/adapters/chatgpt-web/index.ts +1544 -1544
  19. package/src/adapters/chatgpt-web/input-tokens.ts +74 -74
  20. package/src/adapters/chatgpt-web/launcher-helper-client.ts +695 -695
  21. package/src/adapters/chatgpt-web/markdown.ts +418 -418
  22. package/src/adapters/chatgpt-web/mcp-main.ts +25 -25
  23. package/src/adapters/chatgpt-web/mcp-server.ts +933 -933
  24. package/src/adapters/chatgpt-web/model.ts +70 -70
  25. package/src/adapters/chatgpt-web/native-compaction-control.ts +74 -74
  26. package/src/adapters/chatgpt-web/output-validation.ts +62 -62
  27. package/src/adapters/chatgpt-web/process-line-writer.ts +46 -46
  28. package/src/adapters/chatgpt-web/prompt.ts +702 -702
  29. package/src/adapters/chatgpt-web/retry-policy.ts +73 -73
  30. package/src/adapters/chatgpt-web/rolling-checkpoint.ts +384 -384
  31. package/src/adapters/chatgpt-web/thread-environment.ts +238 -238
  32. package/src/adapters/chatgpt-web/tool-stream-parser.ts +1 -1
  33. package/src/adapters/chatgpt-web/turn-broker.ts +1481 -1481
  34. package/src/adapters/chatgpt-web/turn-execution.ts +816 -816
  35. package/src/adapters/chatgpt-web/turn-progress.ts +292 -292
  36. package/src/adapters/chatgpt-web/usage.ts +121 -121
  37. package/src/adapters/image.ts +9 -9
  38. package/src/bridge.ts +1083 -1083
  39. package/src/browser-login.ts +521 -521
  40. package/src/chatgpt-session.ts +240 -240
  41. package/src/chatgpt-web-models.ts +400 -400
  42. package/src/cli.ts +568 -568
  43. package/src/codex-integration-document.ts +824 -824
  44. package/src/codex-integration-journal.ts +212 -212
  45. package/src/codex-integration-route.ts +515 -515
  46. package/src/codex-integration-shared.ts +332 -332
  47. package/src/codex-integration.ts +529 -529
  48. package/src/codex-interrupt-hook.ts +158 -158
  49. package/src/config.ts +616 -616
  50. package/src/dev-chat/cli.ts +432 -432
  51. package/src/dev-chat/constants.ts +3 -3
  52. package/src/dev-chat/driver.ts +655 -655
  53. package/src/dev-chat/profile.ts +223 -223
  54. package/src/dev-chat/session.ts +287 -287
  55. package/src/dev-chat/transport.ts +54 -54
  56. package/src/doctor.ts +237 -237
  57. package/src/event-queue.ts +45 -45
  58. package/src/http-body.ts +30 -30
  59. package/src/launcher-browser-host.ts +695 -695
  60. package/src/lib/errors.ts +281 -281
  61. package/src/lib/token-estimate.ts +42 -42
  62. package/src/login-helper.cjs +1 -1
  63. package/src/model-catalog.ts +197 -197
  64. package/src/native-passthrough.ts +261 -261
  65. package/src/plugin.ts +191 -191
  66. package/src/process.ts +45 -45
  67. package/src/responses/compaction.ts +199 -199
  68. package/src/responses/parser.ts +633 -633
  69. package/src/responses/reasoning-envelope.ts +49 -49
  70. package/src/responses/schema.ts +172 -172
  71. package/src/responses/state.ts +230 -230
  72. package/src/server.ts +1111 -1111
  73. package/src/service.ts +315 -315
  74. package/src/setup.ts +671 -671
  75. package/src/stall-timeout.ts +23 -23
  76. package/src/tunnel-service.ts +160 -160
  77. package/src/tunnel.ts +417 -417
  78. package/src/turndown-plugin-gfm.d.ts +5 -5
  79. package/src/types.ts +307 -307
  80. package/src/usage/totals.ts +12 -12
  81. package/src/version.ts +1 -1
@@ -1,212 +1,212 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
- import { atomicWriteFile, stripUtf8Bom } from "./config";
4
- import {
5
- CODEX_REALTIME_WEBRTC_CALL_BASE_URL,
6
- getCodexConfigPath,
7
- getCodexJournalPath,
8
- getCodexJournalRecoveryPath,
9
- serializeJournal,
10
- writeFilesWithCompensation,
11
- } from "./codex-integration-shared";
12
- import type {
13
- AnyCodexIntegrationJournal,
14
- CodexIntegrationJournal,
15
- LegacyCodexIntegrationJournal,
16
- LegacyCodexIntegrationJournalV9,
17
- LegacyCodexIntegrationJournalV3,
18
- LegacyCodexIntegrationJournalV4,
19
- LegacyCodexIntegrationJournalV5,
20
- LegacyCodexIntegrationJournalV6,
21
- LegacyCodexIntegrationJournalV7,
22
- LegacyCodexIntegrationJournalV8,
23
- } from "./codex-integration-shared";
24
- import { verifyManagedJournalState } from "./codex-integration-route";
25
-
26
- function isPreviousAssignment(value: unknown): boolean {
27
- if (!value || typeof value !== "object") return false;
28
- const assignment = value as Record<string, unknown>;
29
- if (typeof assignment.present !== "boolean") return false;
30
- return !assignment.present
31
- || (typeof assignment.rawLine === "string" && typeof assignment.value === "string");
32
- }
33
-
34
- function isInstalledInterruptHook(value: unknown): boolean {
35
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
36
- const hook = value as Record<string, unknown>;
37
- return typeof hook.command === "string" && hook.command.length > 0
38
- && Number.isSafeInteger(hook.groupIndex) && (hook.groupIndex as number) >= 0
39
- && typeof hook.stateKey === "string" && hook.stateKey.length > 0
40
- && typeof hook.trustedHash === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.trustedHash)
41
- && typeof hook.fragment === "string" && hook.fragment.length > 0;
42
- }
43
-
44
- function parseJournal(path: string): AnyCodexIntegrationJournal {
45
- const value = JSON.parse(stripUtf8Bom(readFileSync(path, "utf8"))) as Record<string, unknown>;
46
- const installed = value.installed as Record<string, unknown> | undefined;
47
- if (value.version === 10
48
- && typeof value.active === "boolean"
49
- && installed
50
- && typeof installed.openai_base_url === "string"
51
- && installed.experimental_realtime_webrtc_call_base_url === CODEX_REALTIME_WEBRTC_CALL_BASE_URL
52
- && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
53
- && (installed.subagent_protocol !== "compatibility-v1"
54
- || (value.previousMultiAgent && value.previousMultiAgentV2
55
- && value.previousAgentMaxDepth
56
- && typeof installed.agent_max_depth === "number"
57
- && Number.isSafeInteger(installed.agent_max_depth)
58
- && installed.agent_max_depth >= 2))
59
- && value.previous
60
- && isPreviousAssignment(value.previousRealtimeWebrtcCallBaseUrl)
61
- && isInstalledInterruptHook(value.interruptHook)
62
- && typeof value.configPath === "string") {
63
- return value as unknown as CodexIntegrationJournal;
64
- }
65
- if (value.version === 9
66
- && typeof value.active === "boolean"
67
- && installed
68
- && typeof installed.openai_base_url === "string"
69
- && installed.experimental_realtime_webrtc_call_base_url === CODEX_REALTIME_WEBRTC_CALL_BASE_URL
70
- && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
71
- && (installed.subagent_protocol !== "compatibility-v1"
72
- || (value.previousMultiAgent && value.previousMultiAgentV2
73
- && value.previousAgentMaxDepth
74
- && typeof installed.agent_max_depth === "number"
75
- && Number.isSafeInteger(installed.agent_max_depth)
76
- && installed.agent_max_depth >= 2))
77
- && value.previous
78
- && isPreviousAssignment(value.previousRealtimeWebrtcCallBaseUrl)
79
- && typeof value.configPath === "string") {
80
- return value as unknown as LegacyCodexIntegrationJournalV9;
81
- }
82
- if (value.version === 8
83
- && typeof value.active === "boolean"
84
- && installed
85
- && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
86
- && (installed.subagent_protocol !== "compatibility-v1"
87
- || (value.previousMultiAgent && value.previousMultiAgentV2
88
- && value.previousAgentMaxDepth
89
- && typeof installed.agent_max_depth === "number"
90
- && Number.isSafeInteger(installed.agent_max_depth)
91
- && installed.agent_max_depth >= 2))
92
- && value.previous
93
- && typeof value.configPath === "string") {
94
- return value as unknown as LegacyCodexIntegrationJournalV8;
95
- }
96
- if (value.version === 7
97
- && typeof value.active === "boolean"
98
- && value.installed
99
- && value.previous
100
- && typeof value.configPath === "string") {
101
- return value as unknown as LegacyCodexIntegrationJournalV7;
102
- }
103
- if (value.version === 6
104
- && typeof value.active === "boolean"
105
- && value.installed
106
- && value.previous
107
- && value.previousRemoteCompactionV2
108
- && value.previousMultiAgent
109
- && value.previousMultiAgentV2
110
- && typeof value.configPath === "string") {
111
- return value as unknown as LegacyCodexIntegrationJournalV6;
112
- }
113
- if (value.version === 5
114
- && typeof value.active === "boolean"
115
- && value.installed
116
- && value.previous
117
- && value.previousRemoteCompactionV2
118
- && value.previousMultiAgent
119
- && typeof value.configPath === "string") {
120
- return value as unknown as LegacyCodexIntegrationJournalV5;
121
- }
122
- if (value.version === 4
123
- && typeof value.active === "boolean"
124
- && value.installed
125
- && value.previous
126
- && typeof value.configPath === "string") {
127
- return value as unknown as LegacyCodexIntegrationJournalV4;
128
- }
129
- if (value.version === 3 && value.installed && value.previous && typeof value.configPath === "string") {
130
- return value as unknown as LegacyCodexIntegrationJournalV3;
131
- }
132
- if (value.version === 2 && value.installed && value.previous && typeof value.providerBlock === "string") {
133
- return value as unknown as LegacyCodexIntegrationJournal;
134
- }
135
- throw new Error(`Invalid Codex integration journal: ${path}`);
136
- }
137
- function journalMatchesConfig(journal: AnyCodexIntegrationJournal): boolean {
138
- try {
139
- assertJournalTargetsConfig(journal, getCodexConfigPath());
140
- if (!existsSync(journal.configPath)) return false;
141
- const text = readFileSync(journal.configPath, "utf8");
142
- if (journal.version === 2) return text.includes(journal.providerBlock);
143
- verifyManagedJournalState(text, journal);
144
- return true;
145
- } catch {
146
- return false;
147
- }
148
- }
149
-
150
- export function readJournal(): AnyCodexIntegrationJournal | undefined {
151
- const primaryPath = getCodexJournalPath();
152
- const recoveryPath = getCodexJournalRecoveryPath();
153
- let primary: AnyCodexIntegrationJournal | undefined;
154
- let recovery: AnyCodexIntegrationJournal | undefined;
155
- let primaryError: unknown;
156
- let recoveryError: unknown;
157
- if (existsSync(primaryPath)) {
158
- try { primary = parseJournal(primaryPath); } catch (error) { primaryError = error; }
159
- }
160
- if (existsSync(recoveryPath)) {
161
- try { recovery = parseJournal(recoveryPath); } catch (error) { recoveryError = error; }
162
- }
163
- if (!primary && !recovery) {
164
- if (primaryError) throw primaryError;
165
- if (recoveryError) throw recoveryError;
166
- return undefined;
167
- }
168
- if (primary && recovery && serializeJournal(primary) === serializeJournal(recovery)) return primary;
169
- if (primary && !recovery && !recoveryError) {
170
- atomicWriteFile(recoveryPath, serializeJournal(primary));
171
- return primary;
172
- }
173
- if (recovery && !primary && !primaryError) {
174
- if (!journalMatchesConfig(recovery)) {
175
- throw new Error("Codex integration recovery journal does not match the active config");
176
- }
177
- atomicWriteFile(primaryPath, serializeJournal(recovery));
178
- return recovery;
179
- }
180
-
181
- const primaryMatches = primary ? journalMatchesConfig(primary) : false;
182
- const recoveryMatches = recovery ? journalMatchesConfig(recovery) : false;
183
- if (primaryMatches === recoveryMatches) {
184
- throw new Error(
185
- primaryMatches
186
- ? "Codex integration journal copies contain different baselines for the same config"
187
- : "Codex integration journal copies do not match the active config",
188
- );
189
- }
190
- const selected = primaryMatches ? primary! : recovery!;
191
- const data = serializeJournal(selected);
192
- writeFilesWithCompensation([
193
- { path: recoveryPath, data },
194
- { path: primaryPath, data },
195
- ]);
196
- return selected;
197
- }
198
-
199
- export function assertJournalTargetsConfig(
200
- journal: AnyCodexIntegrationJournal,
201
- configPath: string,
202
- ): void {
203
- const pathIdentity = (value: string): string => {
204
- const normalized = resolve(value);
205
- return process.platform === "win32" ? normalized.toLowerCase() : normalized;
206
- };
207
- if (pathIdentity(journal.configPath) !== pathIdentity(configPath)) {
208
- throw new Error(
209
- `Codex integration journal belongs to ${journal.configPath}, not the active config ${configPath}`,
210
- );
211
- }
212
- }
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { atomicWriteFile, stripUtf8Bom } from "./config";
4
+ import {
5
+ CODEX_REALTIME_WEBRTC_CALL_BASE_URL,
6
+ getCodexConfigPath,
7
+ getCodexJournalPath,
8
+ getCodexJournalRecoveryPath,
9
+ serializeJournal,
10
+ writeFilesWithCompensation,
11
+ } from "./codex-integration-shared";
12
+ import type {
13
+ AnyCodexIntegrationJournal,
14
+ CodexIntegrationJournal,
15
+ LegacyCodexIntegrationJournal,
16
+ LegacyCodexIntegrationJournalV9,
17
+ LegacyCodexIntegrationJournalV3,
18
+ LegacyCodexIntegrationJournalV4,
19
+ LegacyCodexIntegrationJournalV5,
20
+ LegacyCodexIntegrationJournalV6,
21
+ LegacyCodexIntegrationJournalV7,
22
+ LegacyCodexIntegrationJournalV8,
23
+ } from "./codex-integration-shared";
24
+ import { verifyManagedJournalState } from "./codex-integration-route";
25
+
26
+ function isPreviousAssignment(value: unknown): boolean {
27
+ if (!value || typeof value !== "object") return false;
28
+ const assignment = value as Record<string, unknown>;
29
+ if (typeof assignment.present !== "boolean") return false;
30
+ return !assignment.present
31
+ || (typeof assignment.rawLine === "string" && typeof assignment.value === "string");
32
+ }
33
+
34
+ function isInstalledInterruptHook(value: unknown): boolean {
35
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
36
+ const hook = value as Record<string, unknown>;
37
+ return typeof hook.command === "string" && hook.command.length > 0
38
+ && Number.isSafeInteger(hook.groupIndex) && (hook.groupIndex as number) >= 0
39
+ && typeof hook.stateKey === "string" && hook.stateKey.length > 0
40
+ && typeof hook.trustedHash === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.trustedHash)
41
+ && typeof hook.fragment === "string" && hook.fragment.length > 0;
42
+ }
43
+
44
+ function parseJournal(path: string): AnyCodexIntegrationJournal {
45
+ const value = JSON.parse(stripUtf8Bom(readFileSync(path, "utf8"))) as Record<string, unknown>;
46
+ const installed = value.installed as Record<string, unknown> | undefined;
47
+ if (value.version === 10
48
+ && typeof value.active === "boolean"
49
+ && installed
50
+ && typeof installed.openai_base_url === "string"
51
+ && installed.experimental_realtime_webrtc_call_base_url === CODEX_REALTIME_WEBRTC_CALL_BASE_URL
52
+ && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
53
+ && (installed.subagent_protocol !== "compatibility-v1"
54
+ || (value.previousMultiAgent && value.previousMultiAgentV2
55
+ && value.previousAgentMaxDepth
56
+ && typeof installed.agent_max_depth === "number"
57
+ && Number.isSafeInteger(installed.agent_max_depth)
58
+ && installed.agent_max_depth >= 2))
59
+ && value.previous
60
+ && isPreviousAssignment(value.previousRealtimeWebrtcCallBaseUrl)
61
+ && isInstalledInterruptHook(value.interruptHook)
62
+ && typeof value.configPath === "string") {
63
+ return value as unknown as CodexIntegrationJournal;
64
+ }
65
+ if (value.version === 9
66
+ && typeof value.active === "boolean"
67
+ && installed
68
+ && typeof installed.openai_base_url === "string"
69
+ && installed.experimental_realtime_webrtc_call_base_url === CODEX_REALTIME_WEBRTC_CALL_BASE_URL
70
+ && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
71
+ && (installed.subagent_protocol !== "compatibility-v1"
72
+ || (value.previousMultiAgent && value.previousMultiAgentV2
73
+ && value.previousAgentMaxDepth
74
+ && typeof installed.agent_max_depth === "number"
75
+ && Number.isSafeInteger(installed.agent_max_depth)
76
+ && installed.agent_max_depth >= 2))
77
+ && value.previous
78
+ && isPreviousAssignment(value.previousRealtimeWebrtcCallBaseUrl)
79
+ && typeof value.configPath === "string") {
80
+ return value as unknown as LegacyCodexIntegrationJournalV9;
81
+ }
82
+ if (value.version === 8
83
+ && typeof value.active === "boolean"
84
+ && installed
85
+ && (installed.subagent_protocol === "compatibility-v1" || installed.subagent_protocol === "native")
86
+ && (installed.subagent_protocol !== "compatibility-v1"
87
+ || (value.previousMultiAgent && value.previousMultiAgentV2
88
+ && value.previousAgentMaxDepth
89
+ && typeof installed.agent_max_depth === "number"
90
+ && Number.isSafeInteger(installed.agent_max_depth)
91
+ && installed.agent_max_depth >= 2))
92
+ && value.previous
93
+ && typeof value.configPath === "string") {
94
+ return value as unknown as LegacyCodexIntegrationJournalV8;
95
+ }
96
+ if (value.version === 7
97
+ && typeof value.active === "boolean"
98
+ && value.installed
99
+ && value.previous
100
+ && typeof value.configPath === "string") {
101
+ return value as unknown as LegacyCodexIntegrationJournalV7;
102
+ }
103
+ if (value.version === 6
104
+ && typeof value.active === "boolean"
105
+ && value.installed
106
+ && value.previous
107
+ && value.previousRemoteCompactionV2
108
+ && value.previousMultiAgent
109
+ && value.previousMultiAgentV2
110
+ && typeof value.configPath === "string") {
111
+ return value as unknown as LegacyCodexIntegrationJournalV6;
112
+ }
113
+ if (value.version === 5
114
+ && typeof value.active === "boolean"
115
+ && value.installed
116
+ && value.previous
117
+ && value.previousRemoteCompactionV2
118
+ && value.previousMultiAgent
119
+ && typeof value.configPath === "string") {
120
+ return value as unknown as LegacyCodexIntegrationJournalV5;
121
+ }
122
+ if (value.version === 4
123
+ && typeof value.active === "boolean"
124
+ && value.installed
125
+ && value.previous
126
+ && typeof value.configPath === "string") {
127
+ return value as unknown as LegacyCodexIntegrationJournalV4;
128
+ }
129
+ if (value.version === 3 && value.installed && value.previous && typeof value.configPath === "string") {
130
+ return value as unknown as LegacyCodexIntegrationJournalV3;
131
+ }
132
+ if (value.version === 2 && value.installed && value.previous && typeof value.providerBlock === "string") {
133
+ return value as unknown as LegacyCodexIntegrationJournal;
134
+ }
135
+ throw new Error(`Invalid Codex integration journal: ${path}`);
136
+ }
137
+ function journalMatchesConfig(journal: AnyCodexIntegrationJournal): boolean {
138
+ try {
139
+ assertJournalTargetsConfig(journal, getCodexConfigPath());
140
+ if (!existsSync(journal.configPath)) return false;
141
+ const text = readFileSync(journal.configPath, "utf8");
142
+ if (journal.version === 2) return text.includes(journal.providerBlock);
143
+ verifyManagedJournalState(text, journal);
144
+ return true;
145
+ } catch {
146
+ return false;
147
+ }
148
+ }
149
+
150
+ export function readJournal(): AnyCodexIntegrationJournal | undefined {
151
+ const primaryPath = getCodexJournalPath();
152
+ const recoveryPath = getCodexJournalRecoveryPath();
153
+ let primary: AnyCodexIntegrationJournal | undefined;
154
+ let recovery: AnyCodexIntegrationJournal | undefined;
155
+ let primaryError: unknown;
156
+ let recoveryError: unknown;
157
+ if (existsSync(primaryPath)) {
158
+ try { primary = parseJournal(primaryPath); } catch (error) { primaryError = error; }
159
+ }
160
+ if (existsSync(recoveryPath)) {
161
+ try { recovery = parseJournal(recoveryPath); } catch (error) { recoveryError = error; }
162
+ }
163
+ if (!primary && !recovery) {
164
+ if (primaryError) throw primaryError;
165
+ if (recoveryError) throw recoveryError;
166
+ return undefined;
167
+ }
168
+ if (primary && recovery && serializeJournal(primary) === serializeJournal(recovery)) return primary;
169
+ if (primary && !recovery && !recoveryError) {
170
+ atomicWriteFile(recoveryPath, serializeJournal(primary));
171
+ return primary;
172
+ }
173
+ if (recovery && !primary && !primaryError) {
174
+ if (!journalMatchesConfig(recovery)) {
175
+ throw new Error("Codex integration recovery journal does not match the active config");
176
+ }
177
+ atomicWriteFile(primaryPath, serializeJournal(recovery));
178
+ return recovery;
179
+ }
180
+
181
+ const primaryMatches = primary ? journalMatchesConfig(primary) : false;
182
+ const recoveryMatches = recovery ? journalMatchesConfig(recovery) : false;
183
+ if (primaryMatches === recoveryMatches) {
184
+ throw new Error(
185
+ primaryMatches
186
+ ? "Codex integration journal copies contain different baselines for the same config"
187
+ : "Codex integration journal copies do not match the active config",
188
+ );
189
+ }
190
+ const selected = primaryMatches ? primary! : recovery!;
191
+ const data = serializeJournal(selected);
192
+ writeFilesWithCompensation([
193
+ { path: recoveryPath, data },
194
+ { path: primaryPath, data },
195
+ ]);
196
+ return selected;
197
+ }
198
+
199
+ export function assertJournalTargetsConfig(
200
+ journal: AnyCodexIntegrationJournal,
201
+ configPath: string,
202
+ ): void {
203
+ const pathIdentity = (value: string): string => {
204
+ const normalized = resolve(value);
205
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
206
+ };
207
+ if (pathIdentity(journal.configPath) !== pathIdentity(configPath)) {
208
+ throw new Error(
209
+ `Codex integration journal belongs to ${journal.configPath}, not the active config ${configPath}`,
210
+ );
211
+ }
212
+ }