@open-agent-toolkit/cli 0.1.50 → 0.1.52
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.
- package/assets/agents/oat-phase-implementer.md +16 -5
- package/assets/docs/cli-utilities/configuration.md +1 -1
- package/assets/docs/cli-utilities/workflow-gates.md +1 -1
- package/assets/docs/provider-sync/commands.md +29 -1
- package/assets/docs/provider-sync/providers.md +13 -4
- package/assets/docs/provider-sync/scope-and-surface.md +13 -0
- package/assets/docs/reference/cli-reference.md +2 -2
- package/assets/docs/workflows/projects/hill-checkpoints.md +1 -1
- package/assets/docs/workflows/projects/implementation-execution.md +34 -3
- package/assets/docs/workflows/projects/lifecycle.md +9 -0
- package/assets/docs/workflows/projects/reviews.md +18 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-agent-instructions-analyze/references/docs/provider-reference.md +8 -2
- package/assets/skills/oat-agent-instructions-apply/references/docs/provider-reference.md +8 -2
- package/assets/skills/oat-project-implement/SKILL.md +196 -67
- package/assets/skills/oat-project-import-plan/SKILL.md +6 -6
- package/assets/skills/oat-project-next/SKILL.md +8 -1
- package/assets/skills/oat-project-plan/SKILL.md +6 -6
- package/assets/skills/oat-project-plan-writing/SKILL.md +13 -10
- package/assets/skills/oat-project-pr-final/SKILL.md +8 -1
- package/assets/skills/oat-project-quick-start/SKILL.md +5 -5
- package/assets/skills/oat-project-review-provide/SKILL.md +27 -9
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +34 -9
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +148 -85
- package/dist/commands/gate/index.js +1 -1
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +80 -0
- package/dist/commands/providers/codex/materialize.d.ts.map +1 -1
- package/dist/commands/providers/codex/materialize.js +31 -15
- package/dist/config/oat-config.d.ts +9 -1
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +55 -4
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +7 -3
- package/dist/providers/codex/codec/config-merge.d.ts +8 -2
- package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
- package/dist/providers/codex/codec/config-merge.js +17 -2
- package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
- package/dist/providers/codex/codec/sync-extension.js +14 -4
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-pr-final
|
|
3
|
-
version: 1.4.
|
|
3
|
+
version: 1.4.2
|
|
4
4
|
description: Use when the user requests or confirms opening the final PR for an active OAT project — e.g. "open the final PR", "ship it", "run oat-project-pr-final", or confirms a previously offered final-PR step. Do NOT auto-invoke when phases are marked complete. Generates the final lifecycle PR description from artifacts and creates the PR.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -168,6 +168,13 @@ If `FINAL_ROW` is missing or does not contain `passed`:
|
|
|
168
168
|
|
|
169
169
|
### Step 3: Collect Project Summary
|
|
170
170
|
|
|
171
|
+
Before generating a summary, inspect `oat_post_implement_sequence`. Reuse a
|
|
172
|
+
completed `summary` step instead of regenerating it; when no completed sequence
|
|
173
|
+
summary exists, retain normal summary generation. Every state update in this
|
|
174
|
+
skill must merge with, never replace, `oat_post_implement_sequence`. If a PR
|
|
175
|
+
was partially created, reconcile the durable PR state before retrying its `pr`
|
|
176
|
+
sequence step.
|
|
177
|
+
|
|
171
178
|
**Step 3.0: Check for summary.md**
|
|
172
179
|
|
|
173
180
|
Check if `{PROJECT_PATH}/summary.md` exists:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-quick-start
|
|
3
|
-
version: 2.1.
|
|
3
|
+
version: 2.1.14
|
|
4
4
|
description: Use when a task is small enough for quick mode or rapid iteration is preferred. Scaffolds a lightweight OAT project from discovery directly to a runnable plan, with optional brainstorming and lightweight design.
|
|
5
5
|
argument-hint: '<project-name> ["project description"]'
|
|
6
6
|
oat_gateable: true
|
|
@@ -563,20 +563,20 @@ copy compiled provider targets into this shape or user config. `Uncapped` and
|
|
|
563
563
|
`Inherit Host Defaults` remain explicit modes; `Leave Unresolved` and
|
|
564
564
|
non-interactive unresolved state are not implementation-ready.
|
|
565
565
|
|
|
566
|
-
### Step 3.55: Configure Optional Phase Review
|
|
566
|
+
### Step 3.55: Configure Optional Phase Gate Review
|
|
567
567
|
|
|
568
568
|
After the generated quick plan has stable phase IDs and before Step 3.6 starts
|
|
569
|
-
the plan artifact review, invoke the `Shared Phase
|
|
569
|
+
the plan artifact review, invoke the `Shared Phase Gate Review Setup Contract` from
|
|
570
570
|
`oat-project-plan-writing`.
|
|
571
571
|
|
|
572
572
|
If `plan.md` already contains an explicit `oat_phase_review_gate`, preserve it
|
|
573
573
|
through the shared contract without probing, prompting, or mutation. Otherwise
|
|
574
574
|
let the contract probe qualifying targets and offer all phases, selected
|
|
575
575
|
phases, or disabled. If the probe fails, no target qualifies, or the user
|
|
576
|
-
declines, leave
|
|
576
|
+
declines, leave Phase gate review disabled and continue with the contract's concise
|
|
577
577
|
status output.
|
|
578
578
|
|
|
579
|
-
This
|
|
579
|
+
This Phase gate review setup is independent from HiLL checkpoints. Do not read or
|
|
580
580
|
change HiLL fields here, and do not add a provider/model `--target` to any
|
|
581
581
|
lifecycle command.
|
|
582
582
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-review-provide
|
|
3
|
-
version: 1.3.
|
|
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
|
|
559
|
-
`
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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`;
|
|
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/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAezC,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAezC,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAehB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkFpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,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;CAC/B;AAq2DD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsKT"}
|
|
@@ -7,7 +7,7 @@ import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
|
7
7
|
import { compileDispatchCeilingPreset } from '../../config/dispatch-ceiling-preset.js';
|
|
8
8
|
import { normalizeDispatchMatrix, validateDispatchRouteTarget, walkDispatchMatrix, } from '../../config/dispatch-matrix.js';
|
|
9
9
|
import { dispatchPolicyModeDescription, dispatchPolicyPolicyDescription, managedDispatchPolicyValueList, } from '../../config/dispatch-policy-options.js';
|
|
10
|
-
import { VALID_DISPATCH_POLICY_MODES, VALID_MANAGED_DISPATCH_POLICIES, readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
10
|
+
import { VALID_DISPATCH_POLICY_MODES, VALID_MANAGED_DISPATCH_POLICIES, normalizeWorkflowPostImplementSequence, readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
11
11
|
import { resolveEffectiveConfig, } from '../../config/resolve.js';
|
|
12
12
|
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
13
13
|
import { resolveProjectRoot } from '../../fs/paths.js';
|
|
@@ -389,11 +389,11 @@ const CONFIG_CATALOG = [
|
|
|
389
389
|
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
390
390
|
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
391
391
|
scope: 'workflow',
|
|
392
|
-
type: 'wait | summary | pr | docs-pr',
|
|
392
|
+
type: 'legacy string (wait | summary | pr | docs-pr) | structured JSON object',
|
|
393
393
|
defaultValue: 'unset',
|
|
394
394
|
mutability: 'read/write',
|
|
395
|
-
owningCommand:
|
|
396
|
-
description: 'Default post-implementation chaining
|
|
395
|
+
owningCommand: "oat config set workflow.postImplementSequence '<legacy-or-json>'",
|
|
396
|
+
description: 'Default post-implementation chaining. Legacy strings remain supported unchanged. Structured JSON uses {"preApproval":[...],"postApproval":[...]} with the canonical sequence steps. Plain get/list/dump output serializes structured values as compact JSON; get --json preserves the object value. When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
397
397
|
},
|
|
398
398
|
{
|
|
399
399
|
key: 'workflow.reviewExecutionModel',
|
|
@@ -717,6 +717,23 @@ function parseWorkflowValue(key, rawValue) {
|
|
|
717
717
|
}
|
|
718
718
|
return normalized === 'true';
|
|
719
719
|
}
|
|
720
|
+
if (key === 'workflow.postImplementSequence') {
|
|
721
|
+
const normalized = rawValue.trim();
|
|
722
|
+
if (normalized.startsWith('{') || normalized.startsWith('[')) {
|
|
723
|
+
let parsed;
|
|
724
|
+
try {
|
|
725
|
+
parsed = JSON.parse(normalized);
|
|
726
|
+
}
|
|
727
|
+
catch {
|
|
728
|
+
throw new Error(`Invalid value for ${key}: expected valid structured JSON`);
|
|
729
|
+
}
|
|
730
|
+
const sequence = normalizeWorkflowPostImplementSequence(parsed);
|
|
731
|
+
if (!sequence || Array.isArray(parsed)) {
|
|
732
|
+
throw new Error(`Invalid value for ${key}: structured JSON must match {"preApproval":[...],"postApproval":[...]}`);
|
|
733
|
+
}
|
|
734
|
+
return sequence;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
720
737
|
const allowed = WORKFLOW_ENUM_VALUES[key];
|
|
721
738
|
if (allowed) {
|
|
722
739
|
const normalized = rawValue.trim();
|
|
@@ -828,6 +845,12 @@ function toAvailabilityRef(ref) {
|
|
|
828
845
|
}
|
|
829
846
|
function applyWorkflowValue(workflow, key, value) {
|
|
830
847
|
const subKey = key.slice('workflow.'.length);
|
|
848
|
+
if (subKey === 'postImplementSequence') {
|
|
849
|
+
return {
|
|
850
|
+
...workflow,
|
|
851
|
+
postImplementSequence: value,
|
|
852
|
+
};
|
|
853
|
+
}
|
|
831
854
|
if (subKey === 'dispatchPolicy.mode') {
|
|
832
855
|
const mode = value;
|
|
833
856
|
if (mode === 'inherit') {
|
|
@@ -940,7 +963,7 @@ function formatResolvedValue(value) {
|
|
|
940
963
|
}
|
|
941
964
|
return String(value);
|
|
942
965
|
}
|
|
943
|
-
async function getConfigValue(repoRoot, userConfigDir, key, dependencies) {
|
|
966
|
+
async function getConfigValue(repoRoot, userConfigDir, key, dependencies, preserveRawObject = false) {
|
|
944
967
|
const resolved = await dependencies.resolveEffectiveConfig(repoRoot, userConfigDir, dependencies.processEnv);
|
|
945
968
|
const entry = resolved.resolved[key];
|
|
946
969
|
if (!entry) {
|
|
@@ -948,7 +971,9 @@ async function getConfigValue(repoRoot, userConfigDir, key, dependencies) {
|
|
|
948
971
|
}
|
|
949
972
|
return {
|
|
950
973
|
key,
|
|
951
|
-
value:
|
|
974
|
+
value: preserveRawObject && typeof entry.value === 'object'
|
|
975
|
+
? entry.value
|
|
976
|
+
: formatResolvedValue(entry.value),
|
|
952
977
|
source: entry.source,
|
|
953
978
|
};
|
|
954
979
|
}
|
|
@@ -966,7 +991,7 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
|
|
|
966
991
|
const effectiveSurface = surface === 'auto' ? defaultSurfaceForKey(key) : surface;
|
|
967
992
|
if (isWorkflowKey(key)) {
|
|
968
993
|
const parsedValue = parseWorkflowValue(key, rawValue);
|
|
969
|
-
const displayValue =
|
|
994
|
+
const displayValue = formatResolvedValue(parsedValue);
|
|
970
995
|
if (typeof parsedValue === 'string' && isDispatchCeilingProviderKey(key)) {
|
|
971
996
|
const availability = await dependencies.validateMatrixCell(providerNameFromConfigKey(key), parsedValue, {
|
|
972
997
|
cwd: repoRoot,
|
|
@@ -1322,7 +1347,7 @@ async function runGet(keyArg, context, dependencies) {
|
|
|
1322
1347
|
}
|
|
1323
1348
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
1324
1349
|
const userConfigDir = join(context.home, '.oat');
|
|
1325
|
-
const value = await getConfigValue(repoRoot, userConfigDir, keyArg, dependencies);
|
|
1350
|
+
const value = await getConfigValue(repoRoot, userConfigDir, keyArg, dependencies, context.json);
|
|
1326
1351
|
if (context.json) {
|
|
1327
1352
|
context.logger.json({
|
|
1328
1353
|
status: 'ok',
|
|
@@ -1330,7 +1355,7 @@ async function runGet(keyArg, context, dependencies) {
|
|
|
1330
1355
|
});
|
|
1331
1356
|
}
|
|
1332
1357
|
else {
|
|
1333
|
-
context.logger.info(value.value ?? '');
|
|
1358
|
+
context.logger.info(formatResolvedValue(value.value) ?? '');
|
|
1334
1359
|
}
|
|
1335
1360
|
process.exitCode = 0;
|
|
1336
1361
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 =
|
|
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;
|
|
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;
|
|
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"}
|