@open-agent-toolkit/cli 0.1.50 → 0.1.51

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 (25) hide show
  1. package/assets/agents/oat-phase-implementer.md +16 -5
  2. package/assets/docs/cli-utilities/workflow-gates.md +1 -1
  3. package/assets/docs/provider-sync/commands.md +29 -1
  4. package/assets/docs/provider-sync/providers.md +13 -4
  5. package/assets/docs/provider-sync/scope-and-surface.md +13 -0
  6. package/assets/docs/workflows/projects/implementation-execution.md +29 -3
  7. package/assets/docs/workflows/projects/reviews.md +18 -1
  8. package/assets/public-package-versions.json +4 -4
  9. package/assets/skills/oat-agent-instructions-analyze/references/docs/provider-reference.md +8 -2
  10. package/assets/skills/oat-agent-instructions-apply/references/docs/provider-reference.md +8 -2
  11. package/assets/skills/oat-project-implement/SKILL.md +93 -38
  12. package/assets/skills/oat-project-review-provide/SKILL.md +27 -9
  13. package/dist/commands/doctor/index.d.ts.map +1 -1
  14. package/dist/commands/doctor/index.js +148 -85
  15. package/dist/commands/gate/index.js +1 -1
  16. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  17. package/dist/commands/project/dispatch-ceiling/index.js +80 -0
  18. package/dist/commands/providers/codex/materialize.d.ts.map +1 -1
  19. package/dist/commands/providers/codex/materialize.js +31 -15
  20. package/dist/providers/codex/codec/config-merge.d.ts +8 -2
  21. package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
  22. package/dist/providers/codex/codec/config-merge.js +17 -2
  23. package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
  24. package/dist/providers/codex/codec/sync-extension.js +14 -4
  25. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-review-provide
3
- version: 1.3.13
3
+ version: 1.3.14
4
4
  description: Use when the user explicitly asks to review an OAT project — e.g. "review project", "review the project", "run project review", or confirms a previously offered review. Do NOT auto-invoke on completed work alone. Resolves a project review scope and offers before running.
5
5
  disable-model-invocation: false
6
6
  user-invocable: true
@@ -555,13 +555,16 @@ fallbacks.
555
555
  A concrete managed Codex target takes precedence over tier availability.
556
556
  Build the actual provider invocation before reporting the target as enforced:
557
557
 
558
- - Codex uses the exact registered reviewer role or variant from
559
- `providers.codex.dispatchArgs.variant` when selectable. If the current host
560
- cannot select it, launch a fresh Codex child with the resolver target's
561
- explicit model, reasoning effort, canonical role instructions from
562
- `.agents/agents/oat-reviewer.md`, and the same Review Scope payload.
563
- If that fresh child is unavailable, use only a verified-equivalent inline
564
- route or block the review.
558
+ - Codex must send the resolver-returned Codex variant first as the native
559
+ `agent_type`. Spawn acceptance plus the complete launcher payload is
560
+ configured invocation evidence; it does not require reviewer self-report or
561
+ separate runtime telemetry. A native role-selection rejection means an
562
+ explicit host rejection of that exact `agent_type` before any reviewer or
563
+ child starts. Only after that pre-start rejection may the workflow launch a
564
+ fresh Codex child with the resolver target's explicit model, reasoning
565
+ effort, canonical role instructions from `.agents/agents/oat-reviewer.md`,
566
+ and the same Review Scope payload. If neither exact route is available, use
567
+ only a verified-equivalent inline route or block the review.
565
568
  - Claude requires a non-empty `providers.claude.dispatchArgs.model`; the actual
566
569
  provider invocation must include that exact value as its `model` argument.
567
570
  - Cursor requires a non-empty `providers.cursor.dispatchArgs.model`; the actual
@@ -573,6 +576,18 @@ candidate ladder, fail closed before review. Route interactive repair through
573
576
  the planning workflow's `Complete Dispatch Ladder Adoption Contract`; do not
574
577
  invent a reviewer target.
575
578
 
579
+ After constructing the complete provider payload, record the launcher-owned
580
+ `target`, `model_axis`, and `effort_axis` with
581
+ `launcher-selected/config-declared` provenance. These fields are immutable:
582
+ missing telemetry, missing reviewer self-report, or contradictory self-report
583
+ must not populate, replace, or overwrite them and must not trigger fallback.
584
+
585
+ Once the native host accepts a reviewer, every terminal result is an
586
+ authoritative review outcome. An accepted reviewer returning `BLOCKED` is a
587
+ terminal blocking review outcome: it blocks the review and does not invoke or
588
+ trigger the fresh-child fallback. Absent findings from that terminal must not
589
+ be parsed, interpreted, or treated as a passing review.
590
+
576
591
  On timeout or retry, reuse the same exact role or complete invocation payload,
577
592
  including the Claude or Cursor model argument. If the host cannot apply a
578
593
  required role or model argument, fail closed or block unless inline execution
@@ -623,7 +638,7 @@ Then spawn the reviewer:
623
638
  - Use provider-appropriate dispatch:
624
639
  - Claude Code: Task tool with `subagent_type: "oat-reviewer"` (resolves from `.claude/agents/oat-reviewer.md`). For a concrete managed target, the payload must also contain `model: providers.claude.dispatchArgs.model` with the resolver-returned value.
625
640
  - Cursor: explicit invocation `/oat-reviewer` (or natural mention) with agent resolved from `.cursor/agents/oat-reviewer.md` or `.claude/agents/oat-reviewer.md` compatibility path. For a concrete managed target, the invocation must also contain `model: providers.cursor.dispatchArgs.model` with the exact opaque resolver-returned string.
626
- - Codex style: for a concrete managed target, spawn the exact resolver-returned `agent_type`; if it cannot be selected, use the explicitly pinned fresh-child route from Step 6.0. Generic auto-selection is permitted only for the documented base-role exceptions.
641
+ - Codex style: for a concrete managed target, first spawn the exact resolver-returned native `agent_type`; only an explicit pre-start native role-selection rejection permits the explicitly pinned fresh-child route from Step 6.0. Generic auto-selection is permitted only for the documented base-role exceptions.
627
642
  - Pass the Review Scope metadata block from Step 5 as the prompt
628
643
  - Include the pre-computed artifact path for the subagent to write to
629
644
  - **If a worktree was resolved in Step 1.5:** include the worktree path in the prompt so the subagent writes the artifact to the worktree directory, not the current session's working directory
@@ -633,6 +648,9 @@ The `oat-reviewer` agent definition contains the full review process, mode contr
633
648
 
634
649
  After the subagent completes:
635
650
 
651
+ - Treat its terminal status as authoritative. An accepted `BLOCKED` result
652
+ blocks the review; do not invoke fallback and do not infer a pass from a
653
+ missing review artifact or absent findings.
636
654
  - Verify the review artifact was written to the expected path
637
655
  - Continue with Step 9 (plan update) and Step 9.5 (commit)
638
656
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAY9B,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO9D,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,KACd,OAAO,CACV,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CACnE,CAAC;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,mCAAmC,EAAE,OAAO,mCAAmC,CAAC;IAChF,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,gBAAgB,KACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5B,kBAAkB,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,KAC3C,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAClC;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,cAAc,EAAE,oBAAoB,EAAE,CAAC;CACxC;AA2pBD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAcT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAY9B,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO9D,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,KACd,OAAO,CACV,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CACnE,CAAC;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,mCAAmC,EAAE,OAAO,mCAAmC,CAAC;IAChF,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,gBAAgB,KACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5B,kBAAkB,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,KAC3C,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAClC;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,cAAc,EAAE,oBAAoB,EAAE,CAAC;CACxC;AA8wBD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAcT"}
@@ -1,6 +1,6 @@
1
1
  import { access, mkdtemp, readdir, readFile, rm, symlink, } from 'node:fs/promises';
2
2
  import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
3
+ import { dirname, join } from 'node:path';
4
4
  import { buildCommandContext, } from '../../app/command-context.js';
5
5
  import { compareVersions } from '../init/tools/shared/version.js';
6
6
  import { createPjmDisabledCheck, runPjmDoctorChecks, } from '../pjm/doctor.js';
@@ -279,6 +279,152 @@ async function isManagedCodexRoleConfig(scopeRoot, roleName, configFile, depende
279
279
  return false;
280
280
  }
281
281
  }
282
+ function getCodexAgents(config) {
283
+ const agents = config.agents;
284
+ return agents && typeof agents === 'object' && !Array.isArray(agents)
285
+ ? agents
286
+ : {};
287
+ }
288
+ function getCodexMaxDepthEntry(config) {
289
+ const agents = getCodexAgents(config);
290
+ return {
291
+ present: Object.prototype.hasOwnProperty.call(agents, 'max_depth'),
292
+ value: agents.max_depth,
293
+ };
294
+ }
295
+ /**
296
+ * Applies Codex config precedence without letting an invalid project value fall
297
+ * through to the lower-precedence user value.
298
+ */
299
+ async function resolveDoctorCodexMaxDepth(scope, parsedConfig, userHome, dependencies) {
300
+ const scopedEntry = getCodexMaxDepthEntry(parsedConfig);
301
+ if (scope !== 'project' || scopedEntry.present) {
302
+ return scopedEntry;
303
+ }
304
+ const userConfigPath = join(userHome, '.codex', 'config.toml');
305
+ if (!(await dependencies.pathExists(userConfigPath))) {
306
+ return scopedEntry;
307
+ }
308
+ try {
309
+ return getCodexMaxDepthEntry(TOML.parse(await dependencies.readFile(userConfigPath)));
310
+ }
311
+ catch {
312
+ return { present: true, value: null };
313
+ }
314
+ }
315
+ function createCodexMaxDepthCheck(scope, entry) {
316
+ const topology = 'root (0) → phase coordinator (1) → task worker (2)';
317
+ const numericDepth = typeof entry.value === 'number' && Number.isFinite(entry.value)
318
+ ? entry.value
319
+ : null;
320
+ const sufficient = numericDepth !== null && numericDepth >= 2;
321
+ let state;
322
+ if (!entry.present) {
323
+ state = 'agents.max_depth is missing';
324
+ }
325
+ else if (numericDepth === null) {
326
+ state = 'agents.max_depth is not a valid number';
327
+ }
328
+ else {
329
+ state = `agents.max_depth is ${numericDepth}`;
330
+ }
331
+ return {
332
+ name: `${scope}:codex_max_depth`,
333
+ description: 'Codex managed-role nested dispatch depth',
334
+ status: sufficient ? 'pass' : 'warn',
335
+ message: sufficient
336
+ ? `${state}; sufficient for ${topology}.`
337
+ : `${state}; OAT managed implementation requires ${topology}.`,
338
+ fix: sufficient
339
+ ? undefined
340
+ : `Run \`oat sync --scope ${scope}\`, or materialize a single role with \`oat providers codex materialize <agent-name> --model <model> --effort <effort> --scope ${scope}\`.`,
341
+ };
342
+ }
343
+ async function runCodexChecksForScope(scope, scopeRoot, userHome, dependencies) {
344
+ const checks = [];
345
+ const codexConfigPath = join(scopeRoot, '.codex', 'config.toml');
346
+ if (!(await dependencies.pathExists(codexConfigPath))) {
347
+ return checks;
348
+ }
349
+ let parsedConfig;
350
+ try {
351
+ parsedConfig = TOML.parse(await dependencies.readFile(codexConfigPath));
352
+ checks.push({
353
+ name: `${scope}:codex_config_toml`,
354
+ description: 'Codex config TOML parseability',
355
+ status: 'pass',
356
+ message: '.codex/config.toml parsed successfully.',
357
+ });
358
+ }
359
+ catch (error) {
360
+ checks.push({
361
+ name: `${scope}:codex_config_toml`,
362
+ description: 'Codex config TOML parseability',
363
+ status: 'fail',
364
+ message: error instanceof Error
365
+ ? `Failed to parse .codex/config.toml: ${error.message}`
366
+ : 'Failed to parse .codex/config.toml.',
367
+ fix: 'Repair .codex/config.toml syntax and rerun doctor.',
368
+ });
369
+ return checks;
370
+ }
371
+ const features = parsedConfig.features &&
372
+ typeof parsedConfig.features === 'object' &&
373
+ !Array.isArray(parsedConfig.features)
374
+ ? parsedConfig.features
375
+ : null;
376
+ const agents = getCodexAgents(parsedConfig);
377
+ const managedRoles = [];
378
+ const roleConfigFiles = new Map();
379
+ for (const [roleName, roleConfig] of Object.entries(agents)) {
380
+ const configFile = getCodexAgentConfigFile(roleConfig);
381
+ if (!configFile) {
382
+ continue;
383
+ }
384
+ roleConfigFiles.set(roleName, configFile);
385
+ if (await isManagedCodexRoleConfig(scopeRoot, roleName, configFile, dependencies)) {
386
+ managedRoles.push(roleName);
387
+ }
388
+ }
389
+ if (managedRoles.length === 0) {
390
+ return checks;
391
+ }
392
+ const multiAgentEnabled = features?.multi_agent === true || features?.multi_agent === 'true';
393
+ checks.push({
394
+ name: `${scope}:codex_multi_agent`,
395
+ description: 'Codex multi-agent feature flag',
396
+ status: multiAgentEnabled ? 'pass' : 'warn',
397
+ message: multiAgentEnabled
398
+ ? 'features.multi_agent is enabled for codex managed roles.'
399
+ : 'Codex managed roles detected but features.multi_agent is not true.',
400
+ fix: multiAgentEnabled
401
+ ? undefined
402
+ : 'Set [features] multi_agent = true in .codex/config.toml.',
403
+ });
404
+ checks.push(createCodexMaxDepthCheck(scope, await resolveDoctorCodexMaxDepth(scope, parsedConfig, userHome, dependencies)));
405
+ const missingRoleFiles = [];
406
+ for (const roleName of managedRoles) {
407
+ const configFile = roleConfigFiles.get(roleName);
408
+ if (!configFile)
409
+ continue;
410
+ const absoluteRolePath = join(scopeRoot, '.codex', configFile);
411
+ if (!(await dependencies.pathExists(absoluteRolePath))) {
412
+ missingRoleFiles.push(configFile);
413
+ }
414
+ }
415
+ checks.push({
416
+ name: `${scope}:codex_role_file_refs`,
417
+ description: 'Codex role config_file references',
418
+ status: missingRoleFiles.length === 0 ? 'pass' : 'warn',
419
+ message: missingRoleFiles.length === 0
420
+ ? 'All codex role config_file references exist.'
421
+ : `Missing codex role files: ${missingRoleFiles.join(', ')}`,
422
+ fix: missingRoleFiles.length === 0
423
+ ? undefined
424
+ : `Regenerate codex roles with \`oat sync --scope ${scope}\`, or materialize a single role with \`oat providers codex materialize <agent-name> --model <model> --effort <effort> --scope ${scope}\`.`,
425
+ });
426
+ return checks;
427
+ }
282
428
  async function runChecksForScope(scope, scopeRoot, userConfigDir, dependencies) {
283
429
  const checks = [];
284
430
  const skillsPath = join(scopeRoot, '.agents', 'skills');
@@ -354,6 +500,7 @@ async function runChecksForScope(scope, scopeRoot, userConfigDir, dependencies)
354
500
  ? undefined
355
501
  : 'Install or enable a provider directory (e.g. .claude, .cursor, .codex).',
356
502
  });
503
+ checks.push(...(await runCodexChecksForScope(scope, scopeRoot, dirname(userConfigDir), dependencies)));
357
504
  if (scope === 'project') {
358
505
  try {
359
506
  const assetsRoot = await dependencies.resolveAssetsRoot();
@@ -403,90 +550,6 @@ async function runChecksForScope(scope, scopeRoot, userConfigDir, dependencies)
403
550
  fix: 'Run `pnpm build` and rerun `oat doctor`.',
404
551
  });
405
552
  }
406
- const codexConfigPath = join(scopeRoot, '.codex', 'config.toml');
407
- const codexConfigExists = await dependencies.pathExists(codexConfigPath);
408
- if (codexConfigExists) {
409
- let parsedConfig = null;
410
- try {
411
- parsedConfig = TOML.parse(await dependencies.readFile(codexConfigPath));
412
- checks.push({
413
- name: `${scope}:codex_config_toml`,
414
- description: 'Codex config TOML parseability',
415
- status: 'pass',
416
- message: '.codex/config.toml parsed successfully.',
417
- });
418
- }
419
- catch (error) {
420
- checks.push({
421
- name: `${scope}:codex_config_toml`,
422
- description: 'Codex config TOML parseability',
423
- status: 'fail',
424
- message: error instanceof Error
425
- ? `Failed to parse .codex/config.toml: ${error.message}`
426
- : 'Failed to parse .codex/config.toml.',
427
- fix: 'Repair .codex/config.toml syntax and rerun doctor.',
428
- });
429
- }
430
- if (parsedConfig) {
431
- const features = parsedConfig.features &&
432
- typeof parsedConfig.features === 'object' &&
433
- !Array.isArray(parsedConfig.features)
434
- ? parsedConfig.features
435
- : null;
436
- const agents = parsedConfig.agents &&
437
- typeof parsedConfig.agents === 'object' &&
438
- !Array.isArray(parsedConfig.agents)
439
- ? parsedConfig.agents
440
- : null;
441
- const managedRoles = [];
442
- const roleConfigFiles = new Map();
443
- for (const [roleName, roleConfig] of Object.entries(agents ?? {})) {
444
- const configFile = getCodexAgentConfigFile(roleConfig);
445
- if (!configFile) {
446
- continue;
447
- }
448
- roleConfigFiles.set(roleName, configFile);
449
- if (await isManagedCodexRoleConfig(scopeRoot, roleName, configFile, dependencies)) {
450
- managedRoles.push(roleName);
451
- }
452
- }
453
- if (managedRoles.length > 0) {
454
- const multiAgentEnabled = features?.multi_agent === true || features?.multi_agent === 'true';
455
- checks.push({
456
- name: `${scope}:codex_multi_agent`,
457
- description: 'Codex multi-agent feature flag',
458
- status: multiAgentEnabled ? 'pass' : 'warn',
459
- message: multiAgentEnabled
460
- ? 'features.multi_agent is enabled for codex managed roles.'
461
- : 'Codex managed roles detected but features.multi_agent is not true.',
462
- fix: multiAgentEnabled
463
- ? undefined
464
- : 'Set [features] multi_agent = true in .codex/config.toml.',
465
- });
466
- const missingRoleFiles = [];
467
- for (const roleName of managedRoles) {
468
- const configFile = roleConfigFiles.get(roleName);
469
- if (!configFile)
470
- continue;
471
- const absoluteRolePath = join(scopeRoot, '.codex', configFile);
472
- if (!(await dependencies.pathExists(absoluteRolePath))) {
473
- missingRoleFiles.push(configFile);
474
- }
475
- }
476
- checks.push({
477
- name: `${scope}:codex_role_file_refs`,
478
- description: 'Codex role config_file references',
479
- status: missingRoleFiles.length === 0 ? 'pass' : 'warn',
480
- message: missingRoleFiles.length === 0
481
- ? 'All codex role config_file references exist.'
482
- : `Missing codex role files: ${missingRoleFiles.join(', ')}`,
483
- fix: missingRoleFiles.length === 0
484
- ? undefined
485
- : 'Regenerate codex roles with `oat sync --scope project`, or materialize a single role with `oat providers codex materialize ...`.',
486
- });
487
- }
488
- }
489
- }
490
553
  const repoReferenceRoot = join(scopeRoot, '.oat', 'repo');
491
554
  const [userConfig, config, localConfig] = await Promise.all([
492
555
  dependencies.readUserConfig(userConfigDir),
@@ -55,7 +55,7 @@ const VALID_IDENTITY_PROVENANCES = [
55
55
  ];
56
56
  const REVIEW_GATE_CONTEXT_NOTE = 'This review is gate-originated. If you run `oat-project-review-provide`, set `oat_review_invocation: gate` in the review artifact. Write a canonical review artifact with `### Critical`, `### Important`, `### Medium`, and `### Minor` headings in that order, using `None` for empty sections.';
57
57
  const GATE_CHECK_TIMEOUT_MS = 5_000;
58
- const GATE_EXEC_TIMEOUT_MS = 10 * 60 * 1_000;
58
+ const GATE_EXEC_TIMEOUT_MS = 15 * 60 * 1_000;
59
59
  function reviewGateProjectContext(project) {
60
60
  return [
61
61
  `Resolved OAT project path: ${project.path}. Run the review for this project path.`,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAa9B,OAAO,EAUL,KAAK,uBAAuB,EAY7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAsBzB,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAiC5C,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA63ED,wBAAgB,mCAAmC,CACjD,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAkGT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAa9B,OAAO,EAUL,KAAK,uBAAuB,EAY7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAsBzB,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAiC5C,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAi/ED,wBAAgB,mCAAmC,CACjD,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAkGT"}
@@ -1175,6 +1175,58 @@ function readCodexDefaultFromToml(content) {
1175
1175
  const value = parsed['model_reasoning_effort'];
1176
1176
  return typeof value === 'string' && value.trim() ? value.trim() : null;
1177
1177
  }
1178
+ function readCodexMaxDepthEntry(content) {
1179
+ let parsed;
1180
+ try {
1181
+ parsed = TOML.parse(content);
1182
+ }
1183
+ catch {
1184
+ return { present: true, value: null };
1185
+ }
1186
+ const agents = parsed.agents;
1187
+ if (!agents || typeof agents !== 'object' || Array.isArray(agents)) {
1188
+ return { present: false, value: undefined };
1189
+ }
1190
+ const record = agents;
1191
+ return {
1192
+ present: Object.prototype.hasOwnProperty.call(record, 'max_depth'),
1193
+ value: record.max_depth,
1194
+ };
1195
+ }
1196
+ async function readCodexMaxDepthAtPath(path, dependencies) {
1197
+ if (!(await dependencies.pathExists(path))) {
1198
+ return { present: false, value: undefined };
1199
+ }
1200
+ try {
1201
+ return readCodexMaxDepthEntry(await dependencies.readFile(path));
1202
+ }
1203
+ catch {
1204
+ return { present: true, value: null };
1205
+ }
1206
+ }
1207
+ /**
1208
+ * Resolves the depth seen by Codex: project config wins whenever it declares a
1209
+ * value, while an absent project value inherits the user config.
1210
+ */
1211
+ async function resolveEffectiveCodexMaxDepth(scope, repoRoot, context, dependencies) {
1212
+ const userPath = join(context.home, '.codex', 'config.toml');
1213
+ if (scope === 'user') {
1214
+ return readCodexMaxDepthAtPath(userPath, dependencies);
1215
+ }
1216
+ const projectEntry = await readCodexMaxDepthAtPath(join(repoRoot, '.codex', 'config.toml'), dependencies);
1217
+ return projectEntry.present
1218
+ ? projectEntry
1219
+ : readCodexMaxDepthAtPath(userPath, dependencies);
1220
+ }
1221
+ function managedCodexDepthBlockMessage(scope, entry) {
1222
+ const validDepth = typeof entry.value === 'number' && Number.isFinite(entry.value);
1223
+ const state = !entry.present
1224
+ ? 'agents.max_depth is missing'
1225
+ : validDepth
1226
+ ? `agents.max_depth is ${entry.value}`
1227
+ : 'agents.max_depth is not a valid number';
1228
+ return `BLOCKED: Codex ${state}; managed implementation requires root (0) → phase coordinator (1) → task worker (2).\nRun \`oat sync --scope ${scope}\`, or materialize a single role with \`oat providers codex materialize <agent-name> --model <model> --effort <effort> --scope ${scope}\`.`;
1229
+ }
1178
1230
  async function resolveCodexProviderDefaultEffort(repoRoot, context, dependencies) {
1179
1231
  const candidates = [
1180
1232
  join(repoRoot, '.codex', 'config.toml'),
@@ -1224,6 +1276,34 @@ async function resolveDispatchCeiling(context, dependencies, options) {
1224
1276
  [provider]: providerResolution,
1225
1277
  };
1226
1278
  if (resolvedValue) {
1279
+ const requiresManagedCodexDepth = options.preflight === true &&
1280
+ provider === 'codex' &&
1281
+ role === 'implementer' &&
1282
+ resolvedValue.mode === 'managed';
1283
+ if (requiresManagedCodexDepth) {
1284
+ const scope = context.scope === 'user' ? 'user' : 'project';
1285
+ const depth = await resolveEffectiveCodexMaxDepth(scope, repoRoot, context, dependencies);
1286
+ const numericDepth = typeof depth.value === 'number' && Number.isFinite(depth.value)
1287
+ ? depth.value
1288
+ : null;
1289
+ if (numericDepth === null || numericDepth < 2) {
1290
+ return {
1291
+ status: 'blocked',
1292
+ provider,
1293
+ value: resolvedValue.value,
1294
+ policyMode: resolvedValue.mode,
1295
+ policy: resolvedValue.policy,
1296
+ source: resolvedValue.source,
1297
+ preset: resolvedValue.preset,
1298
+ unresolved: true,
1299
+ projectPath,
1300
+ providerDefaultEffort,
1301
+ matrix: resolvedValue.matrix,
1302
+ providers,
1303
+ message: managedCodexDepthBlockMessage(scope, depth),
1304
+ };
1305
+ }
1306
+ }
1227
1307
  const incompleteManagedPreflight = options.preflight === true &&
1228
1308
  resolvedValue.mode === 'managed' &&
1229
1309
  providerResolution.mode === 'advisory' &&
@@ -1 +1 @@
1
- {"version":3,"file":"materialize.d.ts","sourceRoot":"","sources":["../../../../src/commands/providers/codex/materialize.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,sBAAsB,EACtB,qCAAqC,EACtC,MAAM,qCAAqC,CAAC;AAU7C,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAsD5C,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,sBAAsB,GAC7B,MAAM,CAaR;AA+GD,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,OAAO,CAAC,qCAAqC,CAAM,GAC7D,OAAO,CAoCT"}
1
+ {"version":3,"file":"materialize.d.ts","sourceRoot":"","sources":["../../../../src/commands/providers/codex/materialize.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,sBAAsB,EACtB,qCAAqC,EACtC,MAAM,qCAAqC,CAAC;AAa7C,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAyD5C,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,sBAAsB,GAC7B,MAAM,CAaR;AAsID,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,OAAO,CAAC,qCAAqC,CAAM,GAC7D,OAAO,CAoCT"}
@@ -6,7 +6,7 @@ import { readGlobalOptions } from '../../shared/shared.utils.js';
6
6
  import { CliError } from '../../../errors/index.js';
7
7
  import { ensureDir, fileExists } from '../../../fs/io.js';
8
8
  import { resolveProjectRoot, resolveScopeRoot } from '../../../fs/paths.js';
9
- import { mergeCodexConfigForRole } from '../../../providers/codex/codec/config-merge.js';
9
+ import { mergeCodexConfigForRole, readCodexMaxDepth, } from '../../../providers/codex/codec/config-merge.js';
10
10
  import { materializeCodexRole } from '../../../providers/codex/codec/materialize.js';
11
11
  import { withOatManagedCodexRoleOwner } from '../../../providers/codex/codec/shared.js';
12
12
  import { Command, Option } from 'commander';
@@ -72,8 +72,29 @@ async function buildCodexMaterializePlan(agentName, options, context, dependenci
72
72
  };
73
73
  const rolePath = join(scopeRoot, '.codex', role.configFile);
74
74
  const configPath = join(scopeRoot, '.codex', 'config.toml');
75
+ const existingRoleContent = await readOptionalFile(rolePath);
76
+ const existingConfigContent = await readOptionalFile(configPath);
77
+ let inheritedMaxDepth;
78
+ if (scope === 'project') {
79
+ const userScopeRoot = await dependencies.resolveScopeRoot('user', context);
80
+ const userConfigContent = await readOptionalFile(join(userScopeRoot, '.codex', 'config.toml'));
81
+ inheritedMaxDepth = readCodexMaxDepth(userConfigContent) ?? undefined;
82
+ }
83
+ const mergedConfig = mergeCodexConfigForRole({
84
+ existingContent: existingConfigContent,
85
+ role: {
86
+ roleName: role.roleName,
87
+ description: role.description,
88
+ configFile: role.configFile,
89
+ },
90
+ inheritedMaxDepth,
91
+ });
75
92
  return {
93
+ configChanged: mergedConfig.changed,
94
+ mergedConfigContent: mergedConfig.mergedContent,
76
95
  role,
96
+ roleChanged: existingRoleContent === null ||
97
+ existingRoleContent.trimEnd() !== role.content.trimEnd(),
77
98
  result: {
78
99
  status: context.dryRun ? 'preview' : 'written',
79
100
  dryRun: context.dryRun,
@@ -93,20 +114,15 @@ async function readOptionalFile(filePath) {
93
114
  }
94
115
  return readFile(filePath, 'utf8');
95
116
  }
96
- async function applyCodexMaterializePlan({ result, role, }) {
97
- await ensureDir(dirname(result.rolePath));
98
- await writeFile(result.rolePath, role.content, 'utf8');
99
- const existingConfig = await readOptionalFile(result.configPath);
100
- const mergedConfig = mergeCodexConfigForRole({
101
- existingContent: existingConfig,
102
- role: {
103
- roleName: role.roleName,
104
- description: role.description,
105
- configFile: role.configFile,
106
- },
107
- });
108
- await ensureDir(dirname(result.configPath));
109
- await writeFile(result.configPath, mergedConfig.mergedContent, 'utf8');
117
+ async function applyCodexMaterializePlan({ configChanged, mergedConfigContent, result, role, roleChanged, }) {
118
+ if (roleChanged) {
119
+ await ensureDir(dirname(result.rolePath));
120
+ await writeFile(result.rolePath, role.content, 'utf8');
121
+ }
122
+ if (configChanged) {
123
+ await ensureDir(dirname(result.configPath));
124
+ await writeFile(result.configPath, mergedConfigContent, 'utf8');
125
+ }
110
126
  }
111
127
  async function runCodexMaterializeCommand(agentName, options, context, dependencies) {
112
128
  try {
@@ -7,17 +7,23 @@ export interface CodexConfigMergeArgs {
7
7
  existingContent: string | null;
8
8
  desiredRoles: CodexManagedRoleConfig[];
9
9
  staleManagedRoles?: string[];
10
+ inheritedMaxDepth?: number;
10
11
  }
11
12
  export interface CodexSingleRoleConfigMergeArgs {
12
13
  existingContent: string | null;
13
14
  role: CodexManagedRoleConfig;
14
15
  staleManagedRoles?: string[];
16
+ inheritedMaxDepth?: number;
15
17
  }
16
18
  export interface CodexConfigMergeResult {
17
19
  mergedContent: string;
18
20
  changed: boolean;
19
21
  removedRoles: string[];
20
22
  }
21
- export declare function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRoles, }: CodexConfigMergeArgs): CodexConfigMergeResult;
22
- export declare function mergeCodexConfigForRole({ existingContent, role, staleManagedRoles, }: CodexSingleRoleConfigMergeArgs): CodexConfigMergeResult;
23
+ /** Reads a valid numeric agents.max_depth value from Codex TOML content. */
24
+ export declare function readCodexMaxDepth(content: string | null): number | null;
25
+ /** Merges managed Codex roles and required shared agent configuration. */
26
+ export declare function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRoles, inheritedMaxDepth, }: CodexConfigMergeArgs): CodexConfigMergeResult;
27
+ /** Merges one managed Codex role using the shared configuration contract. */
28
+ export declare function mergeCodexConfigForRole({ existingContent, role, staleManagedRoles, inheritedMaxDepth, }: CodexSingleRoleConfigMergeArgs): CodexConfigMergeResult;
23
29
  //# sourceMappingURL=config-merge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-merge.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/config-merge.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,sBAAsB,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAiCD,wBAAgB,gBAAgB,CAAC,EAC/B,eAAe,EACf,YAAY,EACZ,iBAAsB,GACvB,EAAE,oBAAoB,GAAG,sBAAsB,CAsC/C;AAED,wBAAgB,uBAAuB,CAAC,EACtC,eAAe,EACf,IAAI,EACJ,iBAAsB,GACvB,EAAE,8BAA8B,GAAG,sBAAsB,CAMzD"}
1
+ {"version":3,"file":"config-merge.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/config-merge.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,sBAAsB,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAqCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,EAC/B,eAAe,EACf,YAAY,EACZ,iBAAsB,EACtB,iBAAiB,GAClB,EAAE,oBAAoB,GAAG,sBAAsB,CA8C/C;AAED,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,EACtC,eAAe,EACf,IAAI,EACJ,iBAAsB,EACtB,iBAAiB,GAClB,EAAE,8BAA8B,GAAG,sBAAsB,CAOzD"}
@@ -25,10 +25,23 @@ function getObject(value) {
25
25
  }
26
26
  return { ...value };
27
27
  }
28
- export function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRoles = [], }) {
28
+ function getFiniteNumber(value) {
29
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
30
+ }
31
+ /** Reads a valid numeric agents.max_depth value from Codex TOML content. */
32
+ export function readCodexMaxDepth(content) {
33
+ const parsed = parseConfig(content);
34
+ const agents = getObject(parsed.agents);
35
+ return getFiniteNumber(agents.max_depth);
36
+ }
37
+ /** Merges managed Codex roles and required shared agent configuration. */
38
+ export function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRoles = [], inheritedMaxDepth, }) {
29
39
  const parsed = parseConfig(existingContent);
30
40
  const features = getObject(parsed.features);
31
41
  const agents = getObject(parsed.agents);
42
+ const targetMaxDepth = getFiniteNumber(agents.max_depth);
43
+ const validInheritedMaxDepth = getFiniteNumber(inheritedMaxDepth);
44
+ agents.max_depth = Math.max(2, targetMaxDepth ?? 2, validInheritedMaxDepth ?? 2);
32
45
  const nextConfig = {
33
46
  ...parsed,
34
47
  features: {
@@ -59,10 +72,12 @@ export function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRo
59
72
  removedRoles,
60
73
  };
61
74
  }
62
- export function mergeCodexConfigForRole({ existingContent, role, staleManagedRoles = [], }) {
75
+ /** Merges one managed Codex role using the shared configuration contract. */
76
+ export function mergeCodexConfigForRole({ existingContent, role, staleManagedRoles = [], inheritedMaxDepth, }) {
63
77
  return mergeCodexConfig({
64
78
  existingContent,
65
79
  desiredRoles: [role],
66
80
  staleManagedRoles,
81
+ inheritedMaxDepth,
67
82
  });
68
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sync-extension.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/sync-extension.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAqBpD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC3E,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,4BAA6B,SAAQ,uBAAuB;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,4BAA4B,EAAE,CAAC;IAC3C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAgBD,UAAU,iCAAiC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAwhBD,wBAAsB,gCAAgC,CACpD,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,EAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,EAChC,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CA+I7B;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,yBAAyB,CAAC,CA6BpC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE1E;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,CAaA;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,kBAAkB,GACvB,uBAAuB,EAAE,CAQ3B"}
1
+ {"version":3,"file":"sync-extension.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/sync-extension.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAyBpD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC3E,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,4BAA6B,SAAQ,uBAAuB;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,4BAA4B,EAAE,CAAC;IAC3C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAgBD,UAAU,iCAAiC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAqiBD,wBAAsB,gCAAgC,CACpD,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,EAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,EAChC,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CAqJ7B;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,yBAAyB,CAAC,CA6BpC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE1E;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,CAaA;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,kBAAkB,GACvB,uBAAuB,EAAE,CAQ3B"}