@iam-brain/opencode-codex-auth 0.3.1 → 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 (215) hide show
  1. package/README.md +4 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +45 -6
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/accounts-tools.d.ts.map +1 -1
  6. package/dist/lib/accounts-tools.js +88 -4
  7. package/dist/lib/accounts-tools.js.map +1 -1
  8. package/dist/lib/auth-refresh.d.ts +2 -0
  9. package/dist/lib/auth-refresh.d.ts.map +1 -0
  10. package/dist/lib/auth-refresh.js +2 -0
  11. package/dist/lib/auth-refresh.js.map +1 -0
  12. package/dist/lib/cache-io.d.ts +24 -0
  13. package/dist/lib/cache-io.d.ts.map +1 -0
  14. package/dist/lib/cache-io.js +95 -0
  15. package/dist/lib/cache-io.js.map +1 -0
  16. package/dist/lib/cache-lock.d.ts +7 -0
  17. package/dist/lib/cache-lock.d.ts.map +1 -0
  18. package/dist/lib/cache-lock.js +37 -0
  19. package/dist/lib/cache-lock.js.map +1 -0
  20. package/dist/lib/claims.d.ts.map +1 -1
  21. package/dist/lib/claims.js +4 -1
  22. package/dist/lib/claims.js.map +1 -1
  23. package/dist/lib/codex-cache-layout.d.ts +15 -0
  24. package/dist/lib/codex-cache-layout.d.ts.map +1 -0
  25. package/dist/lib/codex-cache-layout.js +52 -0
  26. package/dist/lib/codex-cache-layout.js.map +1 -0
  27. package/dist/lib/codex-native/accounts.d.ts +21 -0
  28. package/dist/lib/codex-native/accounts.d.ts.map +1 -0
  29. package/dist/lib/codex-native/accounts.js +203 -0
  30. package/dist/lib/codex-native/accounts.js.map +1 -0
  31. package/dist/lib/codex-native/acquire-auth.d.ts +22 -0
  32. package/dist/lib/codex-native/acquire-auth.d.ts.map +1 -0
  33. package/dist/lib/codex-native/acquire-auth.js +389 -0
  34. package/dist/lib/codex-native/acquire-auth.js.map +1 -0
  35. package/dist/lib/codex-native/auth-menu-flow.d.ts +9 -0
  36. package/dist/lib/codex-native/auth-menu-flow.d.ts.map +1 -0
  37. package/dist/lib/codex-native/auth-menu-flow.js +304 -0
  38. package/dist/lib/codex-native/auth-menu-flow.js.map +1 -0
  39. package/dist/lib/codex-native/auth-menu-quotas.d.ts +9 -0
  40. package/dist/lib/codex-native/auth-menu-quotas.d.ts.map +1 -0
  41. package/dist/lib/codex-native/auth-menu-quotas.js +213 -0
  42. package/dist/lib/codex-native/auth-menu-quotas.js.map +1 -0
  43. package/dist/lib/codex-native/catalog-auth.d.ts.map +1 -1
  44. package/dist/lib/codex-native/catalog-auth.js +4 -1
  45. package/dist/lib/codex-native/catalog-auth.js.map +1 -1
  46. package/dist/lib/codex-native/catalog-sync.d.ts +28 -0
  47. package/dist/lib/codex-native/catalog-sync.d.ts.map +1 -0
  48. package/dist/lib/codex-native/catalog-sync.js +36 -0
  49. package/dist/lib/codex-native/catalog-sync.js.map +1 -0
  50. package/dist/lib/codex-native/chat-hooks.d.ts +85 -0
  51. package/dist/lib/codex-native/chat-hooks.d.ts.map +1 -0
  52. package/dist/lib/codex-native/chat-hooks.js +175 -0
  53. package/dist/lib/codex-native/chat-hooks.js.map +1 -0
  54. package/dist/lib/codex-native/client-identity.d.ts.map +1 -1
  55. package/dist/lib/codex-native/client-identity.js +55 -40
  56. package/dist/lib/codex-native/client-identity.js.map +1 -1
  57. package/dist/lib/codex-native/collaboration.d.ts +25 -0
  58. package/dist/lib/codex-native/collaboration.d.ts.map +1 -0
  59. package/dist/lib/codex-native/collaboration.js +306 -0
  60. package/dist/lib/codex-native/collaboration.js.map +1 -0
  61. package/dist/lib/codex-native/oauth-auth-methods.d.ts +45 -0
  62. package/dist/lib/codex-native/oauth-auth-methods.d.ts.map +1 -0
  63. package/dist/lib/codex-native/oauth-auth-methods.js +182 -0
  64. package/dist/lib/codex-native/oauth-auth-methods.js.map +1 -0
  65. package/dist/lib/codex-native/oauth-persistence.d.ts +4 -0
  66. package/dist/lib/codex-native/oauth-persistence.d.ts.map +1 -0
  67. package/dist/lib/codex-native/oauth-persistence.js +28 -0
  68. package/dist/lib/codex-native/oauth-persistence.js.map +1 -0
  69. package/dist/lib/codex-native/oauth-server.d.ts.map +1 -1
  70. package/dist/lib/codex-native/oauth-server.js +63 -5
  71. package/dist/lib/codex-native/oauth-server.js.map +1 -1
  72. package/dist/lib/codex-native/oauth-utils.d.ts +51 -0
  73. package/dist/lib/codex-native/oauth-utils.d.ts.map +1 -0
  74. package/dist/lib/codex-native/oauth-utils.js +265 -0
  75. package/dist/lib/codex-native/oauth-utils.js.map +1 -0
  76. package/dist/lib/codex-native/openai-loader-fetch.d.ts +39 -0
  77. package/dist/lib/codex-native/openai-loader-fetch.d.ts.map +1 -0
  78. package/dist/lib/codex-native/openai-loader-fetch.js +337 -0
  79. package/dist/lib/codex-native/openai-loader-fetch.js.map +1 -0
  80. package/dist/lib/codex-native/rate-limit-snapshots.d.ts +2 -0
  81. package/dist/lib/codex-native/rate-limit-snapshots.d.ts.map +1 -0
  82. package/dist/lib/codex-native/rate-limit-snapshots.js +28 -0
  83. package/dist/lib/codex-native/rate-limit-snapshots.js.map +1 -0
  84. package/dist/lib/codex-native/request-routing.d.ts +3 -0
  85. package/dist/lib/codex-native/request-routing.d.ts.map +1 -0
  86. package/dist/lib/codex-native/request-routing.js +41 -0
  87. package/dist/lib/codex-native/request-routing.js.map +1 -0
  88. package/dist/lib/codex-native/request-transform-pipeline.d.ts +20 -0
  89. package/dist/lib/codex-native/request-transform-pipeline.d.ts.map +1 -0
  90. package/dist/lib/codex-native/request-transform-pipeline.js +25 -0
  91. package/dist/lib/codex-native/request-transform-pipeline.js.map +1 -0
  92. package/dist/lib/codex-native/request-transform.d.ts +28 -4
  93. package/dist/lib/codex-native/request-transform.d.ts.map +1 -1
  94. package/dist/lib/codex-native/request-transform.js +347 -41
  95. package/dist/lib/codex-native/request-transform.js.map +1 -1
  96. package/dist/lib/codex-native/session-affinity-state.d.ts +17 -0
  97. package/dist/lib/codex-native/session-affinity-state.d.ts.map +1 -0
  98. package/dist/lib/codex-native/session-affinity-state.js +56 -0
  99. package/dist/lib/codex-native/session-affinity-state.js.map +1 -0
  100. package/dist/lib/codex-native/session-messages.d.ts +8 -0
  101. package/dist/lib/codex-native/session-messages.d.ts.map +1 -0
  102. package/dist/lib/codex-native/session-messages.js +58 -0
  103. package/dist/lib/codex-native/session-messages.js.map +1 -0
  104. package/dist/lib/codex-native.d.ts +12 -30
  105. package/dist/lib/codex-native.d.ts.map +1 -1
  106. package/dist/lib/codex-native.js +141 -1644
  107. package/dist/lib/codex-native.js.map +1 -1
  108. package/dist/lib/codex-prompts-cache.d.ts +17 -0
  109. package/dist/lib/codex-prompts-cache.d.ts.map +1 -0
  110. package/dist/lib/codex-prompts-cache.js +184 -0
  111. package/dist/lib/codex-prompts-cache.js.map +1 -0
  112. package/dist/lib/codex-status-storage.d.ts.map +1 -1
  113. package/dist/lib/codex-status-storage.js +8 -43
  114. package/dist/lib/codex-status-storage.js.map +1 -1
  115. package/dist/lib/codex-status-tool.js +1 -1
  116. package/dist/lib/codex-status-tool.js.map +1 -1
  117. package/dist/lib/codex-status-ui.d.ts.map +1 -1
  118. package/dist/lib/codex-status-ui.js +14 -8
  119. package/dist/lib/codex-status-ui.js.map +1 -1
  120. package/dist/lib/codex-status.d.ts.map +1 -1
  121. package/dist/lib/codex-status.js +28 -2
  122. package/dist/lib/codex-status.js.map +1 -1
  123. package/dist/lib/compat-sanitizer.d.ts.map +1 -1
  124. package/dist/lib/compat-sanitizer.js +5 -4
  125. package/dist/lib/compat-sanitizer.js.map +1 -1
  126. package/dist/lib/config-dir-gitignore.d.ts +3 -0
  127. package/dist/lib/config-dir-gitignore.d.ts.map +1 -0
  128. package/dist/lib/config-dir-gitignore.js +45 -0
  129. package/dist/lib/config-dir-gitignore.js.map +1 -0
  130. package/dist/lib/config.d.ts +30 -11
  131. package/dist/lib/config.d.ts.map +1 -1
  132. package/dist/lib/config.js +359 -153
  133. package/dist/lib/config.js.map +1 -1
  134. package/dist/lib/fetch-orchestrator.d.ts +19 -0
  135. package/dist/lib/fetch-orchestrator.d.ts.map +1 -1
  136. package/dist/lib/fetch-orchestrator.js +33 -6
  137. package/dist/lib/fetch-orchestrator.js.map +1 -1
  138. package/dist/lib/installer-cli.d.ts.map +1 -1
  139. package/dist/lib/installer-cli.js +14 -1
  140. package/dist/lib/installer-cli.js.map +1 -1
  141. package/dist/lib/logger.d.ts.map +1 -1
  142. package/dist/lib/logger.js +4 -1
  143. package/dist/lib/logger.js.map +1 -1
  144. package/dist/lib/model-catalog.d.ts +1 -0
  145. package/dist/lib/model-catalog.d.ts.map +1 -1
  146. package/dist/lib/model-catalog.js +198 -103
  147. package/dist/lib/model-catalog.js.map +1 -1
  148. package/dist/lib/opencode-install.d.ts.map +1 -1
  149. package/dist/lib/opencode-install.js +30 -6
  150. package/dist/lib/opencode-install.js.map +1 -1
  151. package/dist/lib/orchestrator-agent.d.ts +31 -0
  152. package/dist/lib/orchestrator-agent.d.ts.map +1 -0
  153. package/dist/lib/orchestrator-agent.js +268 -0
  154. package/dist/lib/orchestrator-agent.js.map +1 -0
  155. package/dist/lib/paths.d.ts +1 -1
  156. package/dist/lib/paths.d.ts.map +1 -1
  157. package/dist/lib/paths.js +1 -1
  158. package/dist/lib/paths.js.map +1 -1
  159. package/dist/lib/persona-tool-cli.d.ts.map +1 -1
  160. package/dist/lib/persona-tool-cli.js +4 -1
  161. package/dist/lib/persona-tool-cli.js.map +1 -1
  162. package/dist/lib/personalities.d.ts.map +1 -1
  163. package/dist/lib/personalities.js +9 -2
  164. package/dist/lib/personalities.js.map +1 -1
  165. package/dist/lib/personality-command.d.ts.map +1 -1
  166. package/dist/lib/personality-command.js +4 -1
  167. package/dist/lib/personality-command.js.map +1 -1
  168. package/dist/lib/personality-create.d.ts.map +1 -1
  169. package/dist/lib/personality-create.js +5 -1
  170. package/dist/lib/personality-create.js.map +1 -1
  171. package/dist/lib/personality-skill.d.ts.map +1 -1
  172. package/dist/lib/personality-skill.js +4 -1
  173. package/dist/lib/personality-skill.js.map +1 -1
  174. package/dist/lib/prompt-cache-key.d.ts +7 -0
  175. package/dist/lib/prompt-cache-key.d.ts.map +1 -0
  176. package/dist/lib/prompt-cache-key.js +17 -0
  177. package/dist/lib/prompt-cache-key.js.map +1 -0
  178. package/dist/lib/quarantine.d.ts.map +1 -1
  179. package/dist/lib/quarantine.js +22 -5
  180. package/dist/lib/quarantine.js.map +1 -1
  181. package/dist/lib/quota-threshold-alerts.d.ts +31 -0
  182. package/dist/lib/quota-threshold-alerts.d.ts.map +1 -0
  183. package/dist/lib/quota-threshold-alerts.js +97 -0
  184. package/dist/lib/quota-threshold-alerts.js.map +1 -0
  185. package/dist/lib/refresh-queue.d.ts.map +1 -1
  186. package/dist/lib/refresh-queue.js +9 -2
  187. package/dist/lib/refresh-queue.js.map +1 -1
  188. package/dist/lib/remote-cache-fetch.d.ts +28 -0
  189. package/dist/lib/remote-cache-fetch.d.ts.map +1 -0
  190. package/dist/lib/remote-cache-fetch.js +67 -0
  191. package/dist/lib/remote-cache-fetch.js.map +1 -0
  192. package/dist/lib/request-snapshots.d.ts +3 -0
  193. package/dist/lib/request-snapshots.d.ts.map +1 -1
  194. package/dist/lib/request-snapshots.js +88 -13
  195. package/dist/lib/request-snapshots.js.map +1 -1
  196. package/dist/lib/rotation.d.ts +4 -0
  197. package/dist/lib/rotation.d.ts.map +1 -1
  198. package/dist/lib/rotation.js +57 -10
  199. package/dist/lib/rotation.js.map +1 -1
  200. package/dist/lib/session-affinity.d.ts.map +1 -1
  201. package/dist/lib/session-affinity.js +22 -36
  202. package/dist/lib/session-affinity.js.map +1 -1
  203. package/dist/lib/storage.d.ts +8 -5
  204. package/dist/lib/storage.d.ts.map +1 -1
  205. package/dist/lib/storage.js +50 -39
  206. package/dist/lib/storage.js.map +1 -1
  207. package/dist/lib/ui/tty/select.d.ts.map +1 -1
  208. package/dist/lib/ui/tty/select.js +8 -2
  209. package/dist/lib/ui/tty/select.js.map +1 -1
  210. package/dist/lib/util.d.ts +2 -0
  211. package/dist/lib/util.d.ts.map +1 -0
  212. package/dist/lib/util.js +4 -0
  213. package/dist/lib/util.js.map +1 -0
  214. package/package.json +8 -5
  215. package/schemas/codex-config.schema.json +29 -43
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import fsPromises from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
+ import { isRecord } from "./util";
5
6
  const CONFIG_FILE = "codex-config.json";
6
7
  export const DEFAULT_CODEX_CONFIG = {
7
8
  $schema: "https://schemas.iam-brain.dev/opencode-codex-auth/codex-config.schema.json",
@@ -16,12 +17,16 @@ export const DEFAULT_CODEX_CONFIG = {
16
17
  rotationStrategy: "sticky",
17
18
  sanitizeInputs: false,
18
19
  developerMessagesToUser: true,
20
+ promptCacheKeyStrategy: "default",
19
21
  headerSnapshots: false,
22
+ headerSnapshotBodies: false,
20
23
  headerTransformDebug: false,
21
24
  pidOffset: false
22
25
  },
23
26
  global: {
24
- personality: "pragmatic"
27
+ personality: "pragmatic",
28
+ verbosityEnabled: true,
29
+ verbosity: "default"
25
30
  },
26
31
  perModel: {}
27
32
  };
@@ -71,11 +76,23 @@ const DEFAULT_CODEX_CONFIG_TEMPLATE = `{
71
76
  // default: true
72
77
  "developerMessagesToUser": true,
73
78
 
79
+ // Prompt cache key policy.
80
+ // "default" keeps upstream session-based keys.
81
+ // "project" overrides with a hashed project path + runtime mode key.
82
+ // options: "default" | "project"
83
+ // default: "default"
84
+ "promptCacheKeyStrategy": "default",
85
+
74
86
  // Write request header snapshots to plugin logs.
75
87
  // options: true | false
76
88
  // default: false
77
89
  "headerSnapshots": false,
78
90
 
91
+ // Capture request bodies in snapshot files.
92
+ // options: true | false
93
+ // default: false
94
+ "headerSnapshotBodies": false,
95
+
79
96
  // Capture inbound/outbound header transforms for message requests.
80
97
  // options: true | false
81
98
  // default: false
@@ -85,6 +102,11 @@ const DEFAULT_CODEX_CONFIG_TEMPLATE = `{
85
102
  // options: true | false
86
103
  // default: false
87
104
  "pidOffset": false
105
+
106
+ // Experimental collaboration controls (optional):
107
+ // "collaborationProfile": true,
108
+ // "orchestratorSubagents": true,
109
+ // "collaborationToolProfile": "opencode" // "opencode" | "codex"
88
110
  },
89
111
 
90
112
  "global": {
@@ -92,33 +114,204 @@ const DEFAULT_CODEX_CONFIG_TEMPLATE = `{
92
114
  // built-ins: "pragmatic", "friendly"
93
115
  // custom: any lowercase key from personalities/<key>.md
94
116
  // default: "pragmatic"
95
- "personality": "pragmatic"
117
+ "personality": "pragmatic",
96
118
 
97
119
  // Thinking summaries behavior:
98
120
  // true => force on
99
121
  // false => force off
100
122
  // omit => use model default from catalog cache (recommended)
101
123
  // "thinkingSummaries": true
124
+
125
+ // Text verbosity behavior:
126
+ // verbosityEnabled: true => apply verbosity setting/default
127
+ // verbosityEnabled: false => do not send textVerbosity
128
+ // default: true
129
+ "verbosityEnabled": true,
130
+
131
+ // options: "default" | "low" | "medium" | "high"
132
+ // "default" uses each model's catalog default verbosity.
133
+ // default: "default"
134
+ "verbosity": "default"
102
135
  },
103
136
 
104
137
  // Optional model-specific overrides.
105
138
  // Supports same fields as global plus nested variants.
106
139
  "perModel": {
107
- // "gpt-5.3-codex": {
108
- // "personality": "friendly",
109
- // "thinkingSummaries": true,
110
- // "variants": {
111
- // "high": {
112
- // "personality": "pragmatic",
113
- // "thinkingSummaries": false
114
- // }
115
- // }
116
- // }
140
+ // "gpt-5.3-codex": {
141
+ // "personality": "friendly",
142
+ // "thinkingSummaries": true,
143
+ // "verbosityEnabled": true,
144
+ // "verbosity": "default",
145
+ // "variants": {
146
+ // "high": {
147
+ // "personality": "pragmatic",
148
+ // "thinkingSummaries": false,
149
+ // "verbosityEnabled": true,
150
+ // "verbosity": "high"
151
+ // }
152
+ // }
153
+ // }
117
154
  }
118
155
  }
119
156
  `;
120
- function isRecord(value) {
121
- return typeof value === "object" && value !== null && !Array.isArray(value);
157
+ function describeValueType(value) {
158
+ if (Array.isArray(value))
159
+ return "array";
160
+ if (value === null)
161
+ return "null";
162
+ return typeof value;
163
+ }
164
+ function pushValidationIssue(issues, input) {
165
+ issues.push(`${input.path}: expected ${input.expected}, got ${describeValueType(input.actual)}`);
166
+ }
167
+ function validateModelBehaviorShape(value, pathPrefix, issues) {
168
+ if (!isRecord(value)) {
169
+ pushValidationIssue(issues, { path: pathPrefix, expected: "object", actual: value });
170
+ return;
171
+ }
172
+ if ("personality" in value && typeof value.personality !== "string") {
173
+ pushValidationIssue(issues, { path: `${pathPrefix}.personality`, expected: "string", actual: value.personality });
174
+ }
175
+ if ("thinkingSummaries" in value && typeof value.thinkingSummaries !== "boolean") {
176
+ pushValidationIssue(issues, {
177
+ path: `${pathPrefix}.thinkingSummaries`,
178
+ expected: "boolean",
179
+ actual: value.thinkingSummaries
180
+ });
181
+ }
182
+ if ("verbosityEnabled" in value && typeof value.verbosityEnabled !== "boolean") {
183
+ pushValidationIssue(issues, {
184
+ path: `${pathPrefix}.verbosityEnabled`,
185
+ expected: "boolean",
186
+ actual: value.verbosityEnabled
187
+ });
188
+ }
189
+ if ("verbosity" in value) {
190
+ const verbosity = value.verbosity;
191
+ const normalized = typeof verbosity === "string" ? verbosity.trim().toLowerCase() : "";
192
+ if (!(normalized === "default" || normalized === "low" || normalized === "medium" || normalized === "high")) {
193
+ pushValidationIssue(issues, {
194
+ path: `${pathPrefix}.verbosity`,
195
+ expected: '"default" | "low" | "medium" | "high"',
196
+ actual: verbosity
197
+ });
198
+ }
199
+ }
200
+ }
201
+ export function validateConfigFileObject(raw) {
202
+ const issues = [];
203
+ if (!isRecord(raw)) {
204
+ pushValidationIssue(issues, { path: "$", expected: "object", actual: raw });
205
+ return { valid: false, issues };
206
+ }
207
+ if ("$schema" in raw && typeof raw.$schema !== "string") {
208
+ pushValidationIssue(issues, { path: "$schema", expected: "string", actual: raw.$schema });
209
+ }
210
+ if ("debug" in raw && typeof raw.debug !== "boolean") {
211
+ pushValidationIssue(issues, { path: "debug", expected: "boolean", actual: raw.debug });
212
+ }
213
+ if ("quiet" in raw && typeof raw.quiet !== "boolean") {
214
+ pushValidationIssue(issues, { path: "quiet", expected: "boolean", actual: raw.quiet });
215
+ }
216
+ if ("refreshAhead" in raw) {
217
+ if (!isRecord(raw.refreshAhead)) {
218
+ pushValidationIssue(issues, { path: "refreshAhead", expected: "object", actual: raw.refreshAhead });
219
+ }
220
+ else {
221
+ if ("enabled" in raw.refreshAhead && typeof raw.refreshAhead.enabled !== "boolean") {
222
+ pushValidationIssue(issues, {
223
+ path: "refreshAhead.enabled",
224
+ expected: "boolean",
225
+ actual: raw.refreshAhead.enabled
226
+ });
227
+ }
228
+ if ("bufferMs" in raw.refreshAhead &&
229
+ (typeof raw.refreshAhead.bufferMs !== "number" || !Number.isFinite(raw.refreshAhead.bufferMs))) {
230
+ pushValidationIssue(issues, {
231
+ path: "refreshAhead.bufferMs",
232
+ expected: "number",
233
+ actual: raw.refreshAhead.bufferMs
234
+ });
235
+ }
236
+ }
237
+ }
238
+ if ("runtime" in raw) {
239
+ if (!isRecord(raw.runtime)) {
240
+ pushValidationIssue(issues, { path: "runtime", expected: "object", actual: raw.runtime });
241
+ }
242
+ else {
243
+ const runtime = raw.runtime;
244
+ const enumChecks = [
245
+ { field: "mode", allowed: ["native", "codex"] },
246
+ { field: "rotationStrategy", allowed: ["sticky", "hybrid", "round_robin"] },
247
+ { field: "promptCacheKeyStrategy", allowed: ["default", "project"] },
248
+ { field: "collaborationToolProfile", allowed: ["opencode", "codex"] }
249
+ ];
250
+ for (const check of enumChecks) {
251
+ const value = runtime[check.field];
252
+ if (value === undefined)
253
+ continue;
254
+ const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
255
+ if (!check.allowed.includes(normalized)) {
256
+ pushValidationIssue(issues, {
257
+ path: `runtime.${check.field}`,
258
+ expected: check.allowed.map((item) => `"${item}"`).join(" | "),
259
+ actual: value
260
+ });
261
+ }
262
+ }
263
+ const boolFields = [
264
+ "sanitizeInputs",
265
+ "developerMessagesToUser",
266
+ "codexCompactionOverride",
267
+ "headerSnapshots",
268
+ "headerSnapshotBodies",
269
+ "headerTransformDebug",
270
+ "pidOffset",
271
+ "collaborationProfile",
272
+ "orchestratorSubagents"
273
+ ];
274
+ for (const field of boolFields) {
275
+ if (field in runtime && typeof runtime[field] !== "boolean") {
276
+ pushValidationIssue(issues, {
277
+ path: `runtime.${field}`,
278
+ expected: "boolean",
279
+ actual: runtime[field]
280
+ });
281
+ }
282
+ }
283
+ }
284
+ }
285
+ if ("global" in raw) {
286
+ validateModelBehaviorShape(raw.global, "global", issues);
287
+ }
288
+ if ("perModel" in raw) {
289
+ if (!isRecord(raw.perModel)) {
290
+ pushValidationIssue(issues, { path: "perModel", expected: "object", actual: raw.perModel });
291
+ }
292
+ else {
293
+ for (const [modelName, modelValue] of Object.entries(raw.perModel)) {
294
+ validateModelBehaviorShape(modelValue, `perModel.${modelName}`, issues);
295
+ if (!isRecord(modelValue))
296
+ continue;
297
+ if (!("variants" in modelValue))
298
+ continue;
299
+ const variants = modelValue.variants;
300
+ if (!isRecord(variants)) {
301
+ pushValidationIssue(issues, {
302
+ path: `perModel.${modelName}.variants`,
303
+ expected: "object",
304
+ actual: variants
305
+ });
306
+ continue;
307
+ }
308
+ for (const [variantName, variantValue] of Object.entries(variants)) {
309
+ validateModelBehaviorShape(variantValue, `perModel.${modelName}.variants.${variantName}`, issues);
310
+ }
311
+ }
312
+ }
313
+ }
314
+ return { valid: issues.length === 0, issues };
122
315
  }
123
316
  function parseEnvBoolean(value) {
124
317
  if (value === undefined)
@@ -237,48 +430,53 @@ function parseRotationStrategy(value) {
237
430
  }
238
431
  return undefined;
239
432
  }
240
- function normalizeCustomSettings(raw) {
241
- if (!isRecord(raw))
433
+ function parsePromptCacheKeyStrategy(value) {
434
+ if (typeof value !== "string")
242
435
  return undefined;
243
- const out = {};
244
- if (typeof raw.thinkingSummaries === "boolean") {
245
- out.thinkingSummaries = raw.thinkingSummaries;
246
- }
247
- const rawOptions = isRecord(raw.options) ? raw.options : undefined;
248
- const globalPersonality = normalizePersonalityOption(rawOptions?.personality);
249
- if (globalPersonality) {
250
- out.options = { personality: globalPersonality };
251
- }
252
- const rawModels = isRecord(raw.models) ? raw.models : undefined;
253
- if (rawModels) {
254
- const models = {};
255
- for (const [modelName, value] of Object.entries(rawModels)) {
256
- const normalized = normalizeModelConfigOverride(value);
257
- if (!normalized)
258
- continue;
259
- models[modelName] = normalized;
260
- }
261
- if (Object.keys(models).length > 0) {
262
- out.models = models;
263
- }
436
+ const normalized = value.trim().toLowerCase();
437
+ if (normalized === "default" || normalized === "project")
438
+ return normalized;
439
+ return undefined;
440
+ }
441
+ function parseCollaborationToolProfile(value) {
442
+ if (typeof value !== "string")
443
+ return undefined;
444
+ const normalized = value.trim().toLowerCase();
445
+ if (normalized === "opencode" || normalized === "codex") {
446
+ return normalized;
264
447
  }
265
- if (out.thinkingSummaries === undefined && !out.options && !out.models) {
448
+ return undefined;
449
+ }
450
+ function normalizeVerbosityOption(value) {
451
+ if (typeof value !== "string")
266
452
  return undefined;
453
+ const normalized = value.trim().toLowerCase();
454
+ if (normalized === "default" || normalized === "low" || normalized === "medium" || normalized === "high") {
455
+ return normalized;
267
456
  }
268
- return out;
457
+ return undefined;
269
458
  }
270
459
  function normalizeModelBehaviorSettings(raw) {
271
460
  if (!isRecord(raw))
272
461
  return undefined;
273
462
  const out = {};
274
- const options = isRecord(raw.options) ? raw.options : undefined;
275
- const personality = normalizePersonalityOption(raw.personality) ?? normalizePersonalityOption(options?.personality);
463
+ const personality = normalizePersonalityOption(raw.personality);
276
464
  if (personality)
277
465
  out.personality = personality;
278
466
  if (typeof raw.thinkingSummaries === "boolean") {
279
467
  out.thinkingSummaries = raw.thinkingSummaries;
280
468
  }
281
- if (!out.personality && out.thinkingSummaries === undefined) {
469
+ if (typeof raw.verbosityEnabled === "boolean") {
470
+ out.verbosityEnabled = raw.verbosityEnabled;
471
+ }
472
+ const verbosity = normalizeVerbosityOption(raw.verbosity);
473
+ if (verbosity) {
474
+ out.verbosity = verbosity;
475
+ }
476
+ if (!out.personality &&
477
+ out.thinkingSummaries === undefined &&
478
+ out.verbosityEnabled === undefined &&
479
+ out.verbosity === undefined) {
282
480
  return undefined;
283
481
  }
284
482
  return out;
@@ -296,8 +494,10 @@ function normalizeModelConfigOverride(raw) {
296
494
  if (!normalized)
297
495
  continue;
298
496
  variantMap[variantName] = {
299
- ...(normalized.personality ? { options: { personality: normalized.personality } } : {}),
300
- ...(normalized.thinkingSummaries !== undefined ? { thinkingSummaries: normalized.thinkingSummaries } : {})
497
+ ...(normalized.personality ? { personality: normalized.personality } : {}),
498
+ ...(normalized.thinkingSummaries !== undefined ? { thinkingSummaries: normalized.thinkingSummaries } : {}),
499
+ ...(normalized.verbosityEnabled !== undefined ? { verbosityEnabled: normalized.verbosityEnabled } : {}),
500
+ ...(normalized.verbosity ? { verbosity: normalized.verbosity } : {})
301
501
  };
302
502
  }
303
503
  if (Object.keys(variantMap).length > 0) {
@@ -308,15 +508,17 @@ function normalizeModelConfigOverride(raw) {
308
508
  return undefined;
309
509
  }
310
510
  return {
311
- ...(modelBehavior?.personality ? { options: { personality: modelBehavior.personality } } : {}),
511
+ ...(modelBehavior?.personality ? { personality: modelBehavior.personality } : {}),
312
512
  ...(modelBehavior?.thinkingSummaries !== undefined ? { thinkingSummaries: modelBehavior.thinkingSummaries } : {}),
513
+ ...(modelBehavior?.verbosityEnabled !== undefined ? { verbosityEnabled: modelBehavior.verbosityEnabled } : {}),
514
+ ...(modelBehavior?.verbosity ? { verbosity: modelBehavior.verbosity } : {}),
313
515
  ...(variants ? { variants } : {})
314
516
  };
315
517
  }
316
518
  function normalizeNewBehaviorSections(raw) {
317
519
  const global = normalizeModelBehaviorSettings(raw.global);
318
520
  const perModelRaw = isRecord(raw.perModel) ? raw.perModel : undefined;
319
- let models;
521
+ let perModel;
320
522
  if (perModelRaw) {
321
523
  const modelMap = {};
322
524
  for (const [modelName, value] of Object.entries(perModelRaw)) {
@@ -326,94 +528,49 @@ function normalizeNewBehaviorSections(raw) {
326
528
  modelMap[modelName] = normalized;
327
529
  }
328
530
  if (Object.keys(modelMap).length > 0) {
329
- models = modelMap;
531
+ perModel = modelMap;
330
532
  }
331
533
  }
332
- if (!global && !models) {
534
+ if (!global && !perModel) {
333
535
  return undefined;
334
536
  }
335
537
  return {
336
- ...(global?.personality ? { options: { personality: global.personality } } : {}),
337
- ...(global?.thinkingSummaries !== undefined ? { thinkingSummaries: global.thinkingSummaries } : {}),
338
- ...(models ? { models } : {})
538
+ ...(global ? { global } : {}),
539
+ ...(perModel ? { perModel } : {})
339
540
  };
340
541
  }
341
- function mergeCustomSettings(primary, secondary) {
342
- if (!primary && !secondary)
343
- return undefined;
344
- if (!primary)
345
- return secondary;
346
- if (!secondary)
347
- return primary;
348
- const modelKeys = new Set([...Object.keys(primary.models ?? {}), ...Object.keys(secondary.models ?? {})]);
349
- let models;
350
- if (modelKeys.size > 0) {
351
- const merged = {};
352
- for (const key of modelKeys) {
353
- const a = primary.models?.[key];
354
- const b = secondary.models?.[key];
355
- const personality = b?.options?.personality !== undefined ? b.options.personality : a?.options?.personality;
356
- const thinkingSummaries = b?.thinkingSummaries !== undefined ? b.thinkingSummaries : a?.thinkingSummaries;
357
- const variantKeys = new Set([...Object.keys(a?.variants ?? {}), ...Object.keys(b?.variants ?? {})]);
358
- let variants;
359
- if (variantKeys.size > 0) {
360
- const variantMap = {};
361
- for (const variantKey of variantKeys) {
362
- const base = a?.variants?.[variantKey];
363
- const override = b?.variants?.[variantKey];
364
- const variantPersonality = override?.options?.personality !== undefined ? override.options.personality : base?.options?.personality;
365
- const variantThinkingSummaries = override?.thinkingSummaries !== undefined ? override.thinkingSummaries : base?.thinkingSummaries;
366
- if (variantPersonality === undefined && variantThinkingSummaries === undefined)
367
- continue;
368
- variantMap[variantKey] = {
369
- ...(variantPersonality ? { options: { personality: variantPersonality } } : {}),
370
- ...(variantThinkingSummaries !== undefined ? { thinkingSummaries: variantThinkingSummaries } : {})
371
- };
372
- }
373
- if (Object.keys(variantMap).length > 0) {
374
- variants = variantMap;
375
- }
376
- }
377
- if (personality === undefined && thinkingSummaries === undefined && !variants)
378
- continue;
379
- merged[key] = {
380
- ...(personality ? { options: { personality } } : {}),
381
- ...(thinkingSummaries !== undefined ? { thinkingSummaries } : {}),
382
- ...(variants ? { variants } : {})
383
- };
384
- }
385
- if (Object.keys(merged).length > 0) {
386
- models = merged;
387
- }
388
- }
389
- const mergedPersonality = secondary.options?.personality !== undefined ? secondary.options.personality : primary.options?.personality;
390
- return {
391
- thinkingSummaries: secondary.thinkingSummaries !== undefined ? secondary.thinkingSummaries : primary.thinkingSummaries,
392
- ...(mergedPersonality ? { options: { personality: mergedPersonality } } : {}),
393
- ...(models ? { models } : {})
394
- };
395
- }
396
- function cloneCustomSettings(input) {
542
+ function cloneBehaviorSettings(input) {
397
543
  if (!input)
398
544
  return undefined;
399
545
  return {
400
- thinkingSummaries: input.thinkingSummaries,
401
- options: input.options ? { ...input.options } : undefined,
402
- models: input.models
403
- ? Object.fromEntries(Object.entries(input.models).map(([key, value]) => [
546
+ ...(input.global
547
+ ? {
548
+ global: {
549
+ ...input.global
550
+ }
551
+ }
552
+ : {}),
553
+ perModel: input.perModel
554
+ ? Object.fromEntries(Object.entries(input.perModel).map(([key, value]) => [
404
555
  key,
405
556
  {
406
- ...(value.options ? { options: { ...value.options } } : {}),
557
+ ...(value.personality !== undefined ? { personality: value.personality } : {}),
407
558
  ...(value.thinkingSummaries !== undefined ? { thinkingSummaries: value.thinkingSummaries } : {}),
559
+ ...(value.verbosityEnabled !== undefined ? { verbosityEnabled: value.verbosityEnabled } : {}),
560
+ ...(value.verbosity !== undefined ? { verbosity: value.verbosity } : {}),
408
561
  ...(value.variants
409
562
  ? {
410
563
  variants: Object.fromEntries(Object.entries(value.variants).map(([variantKey, variantValue]) => [
411
564
  variantKey,
412
565
  {
413
- ...(variantValue.options ? { options: { ...variantValue.options } } : {}),
566
+ ...(variantValue.personality !== undefined ? { personality: variantValue.personality } : {}),
414
567
  ...(variantValue.thinkingSummaries !== undefined
415
568
  ? { thinkingSummaries: variantValue.thinkingSummaries }
416
- : {})
569
+ : {}),
570
+ ...(variantValue.verbosityEnabled !== undefined
571
+ ? { verbosityEnabled: variantValue.verbosityEnabled }
572
+ : {}),
573
+ ...(variantValue.verbosity !== undefined ? { verbosity: variantValue.verbosity } : {})
417
574
  }
418
575
  ]))
419
576
  }
@@ -426,17 +583,15 @@ function cloneCustomSettings(input) {
426
583
  function parseConfigFileObject(raw) {
427
584
  if (!isRecord(raw))
428
585
  return {};
429
- const explicitCustomSettings = normalizeCustomSettings(raw.customSettings);
430
- const newCustomSettings = normalizeNewBehaviorSections(raw);
431
- const customSettings = mergeCustomSettings(explicitCustomSettings, newCustomSettings);
432
- const personalityFromTopLevel = normalizePersonalityOption(raw.personality);
433
- const personalityFromCustom = customSettings?.options?.personality;
586
+ const behaviorSettings = normalizeNewBehaviorSections(raw);
587
+ const personalityFromBehavior = behaviorSettings?.global?.personality;
434
588
  const debug = typeof raw.debug === "boolean" ? raw.debug : undefined;
435
589
  const proactiveRefresh = isRecord(raw.refreshAhead) && typeof raw.refreshAhead.enabled === "boolean" ? raw.refreshAhead.enabled : undefined;
436
590
  const proactiveRefreshBufferMs = isRecord(raw.refreshAhead) && typeof raw.refreshAhead.bufferMs === "number" ? raw.refreshAhead.bufferMs : undefined;
437
591
  const quietMode = typeof raw.quiet === "boolean" ? raw.quiet : undefined;
438
592
  const mode = parseRuntimeMode(isRecord(raw.runtime) ? raw.runtime.mode : undefined);
439
593
  const rotationStrategy = parseRotationStrategy(isRecord(raw.runtime) ? raw.runtime.rotationStrategy : undefined);
594
+ const promptCacheKeyStrategy = parsePromptCacheKeyStrategy(isRecord(raw.runtime) ? raw.runtime.promptCacheKeyStrategy : undefined);
440
595
  const spoofMode = mode === "native" ? "native" : mode === "codex" ? "codex" : undefined;
441
596
  const compatInputSanitizer = isRecord(raw.runtime) && typeof raw.runtime.sanitizeInputs === "boolean" ? raw.runtime.sanitizeInputs : undefined;
442
597
  const remapDeveloperMessagesToUser = isRecord(raw.runtime) && typeof raw.runtime.developerMessagesToUser === "boolean"
@@ -446,26 +601,41 @@ function parseConfigFileObject(raw) {
446
601
  ? raw.runtime.codexCompactionOverride
447
602
  : undefined;
448
603
  const headerSnapshots = isRecord(raw.runtime) && typeof raw.runtime.headerSnapshots === "boolean" ? raw.runtime.headerSnapshots : undefined;
604
+ const headerSnapshotBodies = isRecord(raw.runtime) && typeof raw.runtime.headerSnapshotBodies === "boolean"
605
+ ? raw.runtime.headerSnapshotBodies
606
+ : undefined;
449
607
  const headerTransformDebug = isRecord(raw.runtime) && typeof raw.runtime.headerTransformDebug === "boolean"
450
608
  ? raw.runtime.headerTransformDebug
451
609
  : undefined;
452
610
  const pidOffsetEnabled = isRecord(raw.runtime) && typeof raw.runtime.pidOffset === "boolean" ? raw.runtime.pidOffset : undefined;
611
+ const collaborationProfileEnabled = isRecord(raw.runtime) && typeof raw.runtime.collaborationProfile === "boolean"
612
+ ? raw.runtime.collaborationProfile
613
+ : undefined;
614
+ const orchestratorSubagentsEnabled = isRecord(raw.runtime) && typeof raw.runtime.orchestratorSubagents === "boolean"
615
+ ? raw.runtime.orchestratorSubagents
616
+ : undefined;
617
+ const collaborationToolProfile = parseCollaborationToolProfile(isRecord(raw.runtime) ? raw.runtime.collaborationToolProfile : undefined);
453
618
  return {
454
619
  debug,
455
620
  proactiveRefresh,
456
621
  proactiveRefreshBufferMs,
457
622
  quietMode,
458
623
  pidOffsetEnabled,
459
- personality: personalityFromTopLevel ?? personalityFromCustom,
624
+ personality: personalityFromBehavior,
460
625
  mode,
461
626
  rotationStrategy,
627
+ promptCacheKeyStrategy,
462
628
  spoofMode,
463
629
  compatInputSanitizer,
464
630
  remapDeveloperMessagesToUser,
465
631
  codexCompactionOverride,
466
632
  headerSnapshots,
633
+ headerSnapshotBodies,
467
634
  headerTransformDebug,
468
- customSettings
635
+ collaborationProfileEnabled,
636
+ orchestratorSubagentsEnabled,
637
+ collaborationToolProfile,
638
+ behaviorSettings
469
639
  };
470
640
  }
471
641
  export function resolveDefaultConfigPath(env) {
@@ -499,9 +669,16 @@ export function loadConfigFile(input = {}) {
499
669
  try {
500
670
  const raw = fs.readFileSync(filePath, "utf8");
501
671
  const parsed = parseConfigJsonWithComments(raw);
672
+ const validation = validateConfigFileObject(parsed);
673
+ if (!validation.valid) {
674
+ console.warn(`[opencode-codex-auth] Invalid codex-config at ${filePath}; ignoring file. ${validation.issues.join("; ")}`);
675
+ return {};
676
+ }
502
677
  return parseConfigFileObject(parsed);
503
678
  }
504
- catch {
679
+ catch (error) {
680
+ const detail = error instanceof Error ? error.message : String(error);
681
+ console.warn(`[opencode-codex-auth] Failed to read codex-config at ${filePath}; ignoring file. ${detail}`);
505
682
  return {};
506
683
  }
507
684
  }
@@ -510,15 +687,18 @@ export function loadConfigFile(input = {}) {
510
687
  export function resolveConfig(input) {
511
688
  const env = input.env;
512
689
  const file = input.file ?? {};
513
- const fileCustom = normalizeCustomSettings(file.customSettings);
690
+ const fileBehavior = cloneBehaviorSettings(file.behaviorSettings);
514
691
  const envDebug = env.OPENCODE_OPENAI_MULTI_DEBUG === "1" || env.DEBUG_CODEX_PLUGIN === "1";
515
692
  const proactiveRefresh = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_PROACTIVE_REFRESH) ?? file.proactiveRefresh;
516
693
  const proactiveRefreshBufferMs = parseEnvNumber(env.OPENCODE_OPENAI_MULTI_PROACTIVE_REFRESH_BUFFER_MS) ?? file.proactiveRefreshBufferMs;
517
694
  const quietMode = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_QUIET) ?? file.quietMode;
518
695
  const pidOffsetEnabled = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_PID_OFFSET) ?? file.pidOffsetEnabled;
519
696
  const rotationStrategy = parseRotationStrategy(env.OPENCODE_OPENAI_MULTI_ROTATION_STRATEGY) ?? file.rotationStrategy;
697
+ const promptCacheKeyStrategy = parsePromptCacheKeyStrategy(env.OPENCODE_OPENAI_MULTI_PROMPT_CACHE_KEY_STRATEGY) ?? file.promptCacheKeyStrategy;
520
698
  const envPersonality = normalizePersonalityOption(env.OPENCODE_OPENAI_MULTI_PERSONALITY);
521
699
  const envThinkingSummaries = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_THINKING_SUMMARIES);
700
+ const envVerbosityEnabled = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_VERBOSITY_ENABLED);
701
+ const envVerbosity = normalizeVerbosityOption(env.OPENCODE_OPENAI_MULTI_VERBOSITY);
522
702
  const spoofModeFromEnv = parseSpoofMode(env.OPENCODE_OPENAI_MULTI_SPOOF_MODE);
523
703
  const modeFromEnv = parseRuntimeMode(env.OPENCODE_OPENAI_MULTI_MODE);
524
704
  const modeFromSpoofEnv = modeFromEnv === undefined && spoofModeFromEnv !== undefined
@@ -530,36 +710,30 @@ export function resolveConfig(input) {
530
710
  modeFromSpoofEnv ??
531
711
  file.mode ??
532
712
  (spoofModeFromEnv === "codex" || file.spoofMode === "codex" ? "codex" : "native");
533
- const customSettings = cloneCustomSettings(fileCustom);
713
+ const behaviorSettings = cloneBehaviorSettings(fileBehavior) ?? {};
714
+ const globalBehavior = {
715
+ ...(behaviorSettings.global ?? {})
716
+ };
534
717
  if (envPersonality) {
535
- if (!customSettings) {
536
- // Keep behavior deterministic by ensuring one source of truth for runtime resolution.
537
- input.file = { ...file, customSettings: { options: { personality: envPersonality } } };
538
- }
539
- else {
540
- customSettings.options = { ...(customSettings.options ?? {}), personality: envPersonality };
541
- }
718
+ globalBehavior.personality = envPersonality;
542
719
  }
543
720
  if (envThinkingSummaries !== undefined) {
544
- if (!customSettings) {
545
- input.file = {
546
- ...file,
547
- customSettings: { ...(input.file?.customSettings ?? {}), thinkingSummaries: envThinkingSummaries }
548
- };
549
- }
550
- else {
551
- customSettings.thinkingSummaries = envThinkingSummaries;
552
- }
721
+ globalBehavior.thinkingSummaries = envThinkingSummaries;
553
722
  }
554
- const resolvedCustomSettings = customSettings ??
555
- cloneCustomSettings(normalizeCustomSettings(input.file?.customSettings)) ??
556
- (envPersonality || envThinkingSummaries !== undefined
557
- ? {
558
- ...(envPersonality ? { options: { personality: envPersonality } } : {}),
559
- ...(envThinkingSummaries !== undefined ? { thinkingSummaries: envThinkingSummaries } : {})
560
- }
561
- : undefined);
562
- const personality = envPersonality ?? file.personality ?? resolvedCustomSettings?.options?.personality;
723
+ if (envVerbosityEnabled !== undefined) {
724
+ globalBehavior.verbosityEnabled = envVerbosityEnabled;
725
+ }
726
+ if (envVerbosity) {
727
+ globalBehavior.verbosity = envVerbosity;
728
+ }
729
+ if (globalBehavior.personality !== undefined ||
730
+ globalBehavior.thinkingSummaries !== undefined ||
731
+ globalBehavior.verbosityEnabled !== undefined ||
732
+ globalBehavior.verbosity !== undefined) {
733
+ behaviorSettings.global = globalBehavior;
734
+ }
735
+ const resolvedBehaviorSettings = behaviorSettings.global !== undefined || behaviorSettings.perModel !== undefined ? behaviorSettings : undefined;
736
+ const personality = envPersonality ?? resolvedBehaviorSettings?.global?.personality;
563
737
  // Runtime mode is canonical; spoofMode remains a compatibility input only.
564
738
  // If runtime mode is explicitly set via env, ignore spoof env for consistency.
565
739
  const spoofMode = modeFromEnv !== undefined
@@ -571,7 +745,11 @@ export function resolveConfig(input) {
571
745
  const remapDeveloperMessagesToUser = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_REMAP_DEVELOPER_MESSAGES_TO_USER) ?? file.remapDeveloperMessagesToUser;
572
746
  const codexCompactionOverride = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_CODEX_COMPACTION_OVERRIDE) ?? file.codexCompactionOverride;
573
747
  const headerSnapshots = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_HEADER_SNAPSHOTS) ?? file.headerSnapshots;
748
+ const headerSnapshotBodies = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_HEADER_SNAPSHOT_BODIES) ?? file.headerSnapshotBodies;
574
749
  const headerTransformDebug = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_HEADER_TRANSFORM_DEBUG) ?? file.headerTransformDebug;
750
+ const collaborationProfileEnabled = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_COLLABORATION_PROFILE) ?? file.collaborationProfileEnabled;
751
+ const orchestratorSubagentsEnabled = parseEnvBoolean(env.OPENCODE_OPENAI_MULTI_ORCHESTRATOR_SUBAGENTS) ?? file.orchestratorSubagentsEnabled;
752
+ const collaborationToolProfile = parseCollaborationToolProfile(env.OPENCODE_OPENAI_MULTI_COLLABORATION_TOOL_PROFILE) ?? file.collaborationToolProfile;
575
753
  return {
576
754
  ...file,
577
755
  debug: envDebug || file.debug === true,
@@ -582,13 +760,18 @@ export function resolveConfig(input) {
582
760
  personality,
583
761
  mode,
584
762
  rotationStrategy,
763
+ promptCacheKeyStrategy,
585
764
  spoofMode,
586
765
  compatInputSanitizer,
587
766
  remapDeveloperMessagesToUser,
588
767
  codexCompactionOverride,
589
768
  headerSnapshots,
769
+ headerSnapshotBodies,
590
770
  headerTransformDebug,
591
- customSettings: resolvedCustomSettings
771
+ collaborationProfileEnabled,
772
+ orchestratorSubagentsEnabled,
773
+ collaborationToolProfile,
774
+ behaviorSettings: resolvedBehaviorSettings
592
775
  };
593
776
  }
594
777
  export function getDebugEnabled(cfg) {
@@ -622,6 +805,9 @@ export function getMode(cfg) {
622
805
  export function getRotationStrategy(cfg) {
623
806
  return cfg.rotationStrategy === "hybrid" || cfg.rotationStrategy === "round_robin" ? cfg.rotationStrategy : "sticky";
624
807
  }
808
+ export function getPromptCacheKeyStrategy(cfg) {
809
+ return cfg.promptCacheKeyStrategy === "project" ? "project" : "default";
810
+ }
625
811
  export function getCompatInputSanitizerEnabled(cfg) {
626
812
  return cfg.compatInputSanitizer === true;
627
813
  }
@@ -643,10 +829,30 @@ export function getHeaderSnapshotsEnabled(cfg) {
643
829
  export function getHeaderTransformDebugEnabled(cfg) {
644
830
  return cfg.headerTransformDebug === true;
645
831
  }
646
- export function getCustomSettings(cfg) {
647
- return cfg.customSettings;
832
+ export function getHeaderSnapshotBodiesEnabled(cfg) {
833
+ return cfg.headerSnapshotBodies === true;
834
+ }
835
+ export function getCollaborationProfileEnabled(cfg) {
836
+ if (cfg.collaborationProfileEnabled === true)
837
+ return true;
838
+ if (cfg.collaborationProfileEnabled === false)
839
+ return false;
840
+ return getMode(cfg) === "codex";
841
+ }
842
+ export function getOrchestratorSubagentsEnabled(cfg) {
843
+ if (cfg.orchestratorSubagentsEnabled === true)
844
+ return true;
845
+ if (cfg.orchestratorSubagentsEnabled === false)
846
+ return false;
847
+ return getCollaborationProfileEnabled(cfg);
848
+ }
849
+ export function getCollaborationToolProfile(cfg) {
850
+ return cfg.collaborationToolProfile === "codex" ? "codex" : "opencode";
851
+ }
852
+ export function getBehaviorSettings(cfg) {
853
+ return cfg.behaviorSettings;
648
854
  }
649
855
  export function getThinkingSummariesOverride(cfg) {
650
- return cfg.customSettings?.thinkingSummaries;
856
+ return cfg.behaviorSettings?.global?.thinkingSummaries;
651
857
  }
652
858
  //# sourceMappingURL=config.js.map