@open-agent-toolkit/cli 0.1.45 → 0.1.48
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 +202 -191
- package/assets/agents/oat-reviewer.md +12 -2
- package/assets/config/dispatch-matrix-recommendation.json +120 -13
- package/assets/docs/cli-utilities/config-and-local-state.md +7 -0
- package/assets/docs/cli-utilities/configuration.md +183 -84
- package/assets/docs/cli-utilities/workflow-gates.md +161 -27
- package/assets/docs/contributing/skills.md +14 -8
- package/assets/docs/provider-sync/config.md +5 -1
- package/assets/docs/provider-sync/manifest-and-drift.md +6 -1
- package/assets/docs/provider-sync/providers.md +42 -5
- package/assets/docs/provider-sync/scope-and-surface.md +3 -2
- package/assets/docs/reference/cli-reference.md +3 -1
- package/assets/docs/reference/oat-directory-structure.md +27 -26
- package/assets/docs/workflows/projects/artifacts.md +31 -1
- package/assets/docs/workflows/projects/dispatch-ceiling.md +235 -174
- package/assets/docs/workflows/projects/implementation-execution.md +283 -253
- package/assets/docs/workflows/projects/lifecycle.md +26 -5
- package/assets/docs/workflows/projects/reviews.md +27 -2
- package/assets/migration/pjm-restructure.md +1 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-implement/SKILL.md +347 -178
- package/assets/skills/oat-project-import-plan/SKILL.md +173 -16
- package/assets/skills/oat-project-next/SKILL.md +2 -2
- package/assets/skills/oat-project-plan/SKILL.md +122 -92
- package/assets/skills/oat-project-plan-writing/SKILL.md +246 -15
- package/assets/skills/oat-project-quick-start/SKILL.md +156 -94
- package/assets/skills/oat-project-review-provide/SKILL.md +94 -22
- package/dist/commands/config/index.d.ts +2 -2
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +129 -53
- package/dist/commands/doctor/index.d.ts +2 -2
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +102 -31
- package/dist/commands/gate/index.d.ts +7 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +544 -67
- package/dist/commands/gate/review-verdict.d.ts +16 -0
- package/dist/commands/gate/review-verdict.d.ts.map +1 -1
- package/dist/commands/gate/review-verdict.js +72 -9
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +586 -23
- package/dist/commands/providers/codex/index.d.ts +4 -0
- package/dist/commands/providers/codex/index.d.ts.map +1 -0
- package/dist/commands/providers/codex/index.js +7 -0
- package/dist/commands/providers/codex/materialize.d.ts +5 -0
- package/dist/commands/providers/codex/materialize.d.ts.map +1 -0
- package/dist/commands/providers/codex/materialize.js +157 -0
- package/dist/commands/providers/index.d.ts +2 -2
- package/dist/commands/providers/index.d.ts.map +1 -1
- package/dist/commands/providers/index.js +4 -2
- package/dist/commands/providers/providers.types.d.ts +23 -0
- package/dist/commands/providers/providers.types.d.ts.map +1 -1
- package/dist/commands/shared/codex-strays.d.ts.map +1 -1
- package/dist/commands/shared/codex-strays.js +11 -1
- package/dist/commands/shared/frontmatter.d.ts +4 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +23 -0
- package/dist/commands/status/index.d.ts +5 -1
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +10 -4
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +10 -3
- package/dist/commands/sync/sync.types.d.ts +5 -1
- package/dist/commands/sync/sync.types.d.ts.map +1 -1
- package/dist/config/dispatch-ceiling-preset.d.ts +4 -0
- package/dist/config/dispatch-ceiling-preset.d.ts.map +1 -1
- package/dist/config/dispatch-ceiling-preset.js +3 -0
- package/dist/config/dispatch-policy-options.d.ts +20 -0
- package/dist/config/dispatch-policy-options.d.ts.map +1 -0
- package/dist/config/dispatch-policy-options.js +96 -0
- package/dist/config/oat-config.d.ts +25 -2
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +154 -24
- package/dist/config/resolve.d.ts +8 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +66 -2
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -1
- package/dist/engine/scanner.d.ts +1 -0
- package/dist/engine/scanner.d.ts.map +1 -1
- package/dist/engine/scanner.js +17 -1
- package/dist/fs/paths.d.ts +4 -0
- package/dist/fs/paths.d.ts.map +1 -1
- package/dist/fs/paths.js +18 -1
- package/dist/providers/ceiling/registry.d.ts +8 -5
- package/dist/providers/ceiling/registry.d.ts.map +1 -1
- package/dist/providers/ceiling/registry.js +25 -7
- package/dist/providers/codex/codec/catalog.d.ts +14 -0
- package/dist/providers/codex/codec/catalog.d.ts.map +1 -0
- package/dist/providers/codex/codec/catalog.js +21 -0
- package/dist/providers/codex/codec/config-merge.d.ts +6 -0
- package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
- package/dist/providers/codex/codec/config-merge.js +7 -0
- package/dist/providers/codex/codec/materialize.d.ts +16 -0
- package/dist/providers/codex/codec/materialize.d.ts.map +1 -0
- package/dist/providers/codex/codec/materialize.js +58 -0
- package/dist/providers/codex/codec/shared.d.ts +20 -0
- package/dist/providers/codex/codec/shared.d.ts.map +1 -1
- package/dist/providers/codex/codec/shared.js +107 -6
- package/dist/providers/codex/codec/sync-extension.d.ts +7 -1
- package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
- package/dist/providers/codex/codec/sync-extension.js +299 -52
- package/dist/providers/identity/availability.d.ts +24 -1
- package/dist/providers/identity/availability.d.ts.map +1 -1
- package/dist/providers/identity/availability.js +253 -19
- package/dist/providers/identity/stamp.d.ts.map +1 -1
- package/dist/providers/identity/stamp.js +4 -0
- package/dist/shared/types.d.ts +1 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +4 -0
- package/package.json +2 -2
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
2
|
+
import { readdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
4
4
|
import { parseCanonicalAgentFile } from '../../../agents/canonical/index.js';
|
|
5
|
+
import { isCodexMaterializedRouteTarget, isWorkflowDispatchCandidateLadder, isWorkflowDispatchFallbackRoute, normalizeProjectPath, resolveActiveProject, validateDispatchRouteTarget, } from '../../../config/oat-config.js';
|
|
6
|
+
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
7
|
+
import { CliError } from '../../../errors/index.js';
|
|
5
8
|
import { ensureDir, fileExists } from '../../../fs/io.js';
|
|
9
|
+
import { validateRealPathWithinScope } from '../../../fs/paths.js';
|
|
6
10
|
import TOML from '@iarna/toml';
|
|
11
|
+
import YAML from 'yaml';
|
|
12
|
+
import { SUPPORTED_CODEX_BASE_ROLES, SUPPORTED_CODEX_ROLE_TARGETS, } from './catalog.js';
|
|
7
13
|
import { mergeCodexConfig } from './config-merge.js';
|
|
8
14
|
import { exportCanonicalAgentToCodexRole } from './export-to-codex.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
'oat-phase-implementer',
|
|
13
|
-
'oat-reviewer',
|
|
14
|
-
]);
|
|
15
|
+
import { materializeCodexRole } from './materialize.js';
|
|
16
|
+
import { isOatManagedCodexRoleFile, readOatManagedCodexRoleOwner, withOatManagedCodexRoleOwner, } from './shared.js';
|
|
17
|
+
const CODEX_MATERIALIZED_BASE_ROLES = new Set(SUPPORTED_CODEX_BASE_ROLES);
|
|
15
18
|
function hashContent(content) {
|
|
16
19
|
return createHash('sha256').update(content).digest('hex');
|
|
17
20
|
}
|
|
@@ -42,41 +45,7 @@ function normalizeManagedRolesConfig(desiredRoles) {
|
|
|
42
45
|
configFile: role.configFile,
|
|
43
46
|
}));
|
|
44
47
|
}
|
|
45
|
-
function
|
|
46
|
-
return baseContent
|
|
47
|
-
.replace(`# oat-role: ${baseRoleName}`, `# oat-role: ${variantRoleName}`)
|
|
48
|
-
.replace('developer_instructions =', `model_reasoning_effort = "${effort}"\ndeveloper_instructions =`);
|
|
49
|
-
}
|
|
50
|
-
function codexEffortVariantDescription(baseRoleName, effort) {
|
|
51
|
-
const roleLabel = baseRoleName === 'oat-reviewer' ? 'reviewer' : 'phase implementer';
|
|
52
|
-
if (effort === 'low') {
|
|
53
|
-
return `OAT ${roleLabel} pinned to low reasoning effort for narrow mechanical implementation, fix, or review phases.`;
|
|
54
|
-
}
|
|
55
|
-
if (effort === 'medium') {
|
|
56
|
-
return `OAT ${roleLabel} pinned to medium reasoning effort for normal multi-file implementation, fix, or review phases.`;
|
|
57
|
-
}
|
|
58
|
-
if (effort === 'high') {
|
|
59
|
-
return `OAT ${roleLabel} pinned to high reasoning effort for broad, subtle, or higher-risk implementation, fix, or review phases.`;
|
|
60
|
-
}
|
|
61
|
-
return `OAT ${roleLabel} pinned to xhigh reasoning effort for the highest configured Codex dispatch policy cap.`;
|
|
62
|
-
}
|
|
63
|
-
function codexEffortVariantsFromBase(exported) {
|
|
64
|
-
if (!CODEX_EFFORT_VARIANT_BASE_ROLES.has(exported.roleName)) {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
return CODEX_EFFORT_VARIANTS.map((effort) => {
|
|
68
|
-
const variantRoleName = `${exported.roleName}-${effort}`;
|
|
69
|
-
const configFile = `agents/${variantRoleName}.toml`;
|
|
70
|
-
return {
|
|
71
|
-
roleName: variantRoleName,
|
|
72
|
-
description: codexEffortVariantDescription(exported.roleName, effort),
|
|
73
|
-
configFile,
|
|
74
|
-
rolePath: join(dirname(exported.rolePath), `${variantRoleName}.toml`),
|
|
75
|
-
content: codexEffortVariantContent(exported.content, exported.roleName, variantRoleName, effort),
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
async function desiredRolesFromCanonical(canonicalEntries, scopeRoot) {
|
|
48
|
+
async function desiredRolesFromCanonical(canonicalEntries, scopeRoot, materializationTargets) {
|
|
80
49
|
const roles = [];
|
|
81
50
|
for (const entry of canonicalEntries) {
|
|
82
51
|
if (entry.type !== 'agent' ||
|
|
@@ -93,10 +62,239 @@ async function desiredRolesFromCanonical(canonicalEntries, scopeRoot) {
|
|
|
93
62
|
rolePath: join(scopeRoot, '.codex', exported.configFile),
|
|
94
63
|
content: exported.content,
|
|
95
64
|
});
|
|
96
|
-
|
|
65
|
+
if (CODEX_MATERIALIZED_BASE_ROLES.has(exported.roleName)) {
|
|
66
|
+
for (const target of materializationTargets) {
|
|
67
|
+
const materialized = materializeCodexRole({
|
|
68
|
+
agent: parsed,
|
|
69
|
+
model: target.model,
|
|
70
|
+
effort: target.effort,
|
|
71
|
+
});
|
|
72
|
+
roles.push({
|
|
73
|
+
roleName: materialized.roleName,
|
|
74
|
+
description: materialized.description,
|
|
75
|
+
configFile: materialized.configFile,
|
|
76
|
+
rolePath: join(scopeRoot, '.codex', materialized.configFile),
|
|
77
|
+
content: withOatManagedCodexRoleOwner(materialized.content, target.owner),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const roleContents = new Map();
|
|
83
|
+
for (const role of roles) {
|
|
84
|
+
const existing = roleContents.get(role.roleName);
|
|
85
|
+
if (existing !== undefined && existing !== role.content) {
|
|
86
|
+
throw new CliError(`Distinct Codex targets produced the same role name ${role.roleName}. Refusing ambiguous role writes.`);
|
|
87
|
+
}
|
|
88
|
+
roleContents.set(role.roleName, role.content);
|
|
97
89
|
}
|
|
98
90
|
return roles.sort((left, right) => left.roleName.localeCompare(right.roleName));
|
|
99
91
|
}
|
|
92
|
+
function collectCodexTargetFromEntry(entry, targets, owner) {
|
|
93
|
+
if (typeof entry === 'string') {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!isCodexMaterializedRouteTarget('codex', entry)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const validation = validateDispatchRouteTarget('codex', entry);
|
|
100
|
+
if (!validation.valid || !entry.model || !entry.effort) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const key = `${entry.model}\0${entry.effort}`;
|
|
104
|
+
if (!targets.has(key)) {
|
|
105
|
+
targets.set(key, {
|
|
106
|
+
model: entry.model,
|
|
107
|
+
effort: entry.effort,
|
|
108
|
+
owner,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function collectCodexTargetsFromCell(cell, targets, owner) {
|
|
113
|
+
if (typeof cell === 'string') {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (isWorkflowDispatchCandidateLadder(cell)) {
|
|
117
|
+
for (const candidate of cell.candidates) {
|
|
118
|
+
if (isWorkflowDispatchFallbackRoute(candidate)) {
|
|
119
|
+
for (const entry of candidate.route) {
|
|
120
|
+
collectCodexTargetFromEntry(entry, targets, owner);
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
collectCodexTargetFromEntry(candidate, targets, owner);
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const entry of cell) {
|
|
129
|
+
collectCodexTargetFromEntry(entry, targets, owner);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function collectCodexMaterializationTargetsFromProvider(providerValue, targets, owner) {
|
|
133
|
+
if (providerValue === undefined || typeof providerValue === 'string') {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
for (const cell of Object.values(providerValue)) {
|
|
137
|
+
if (cell !== undefined) {
|
|
138
|
+
collectCodexTargetsFromCell(cell, targets, owner);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function sortCodexMaterializationTargets(targets) {
|
|
143
|
+
return [...targets.values()].sort((left, right) => {
|
|
144
|
+
const modelOrder = left.model.localeCompare(right.model);
|
|
145
|
+
return modelOrder === 0
|
|
146
|
+
? left.effort.localeCompare(right.effort)
|
|
147
|
+
: modelOrder;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function routeTargetFromUnknown(value) {
|
|
151
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const record = value;
|
|
155
|
+
const target = {};
|
|
156
|
+
for (const key of ['harness', 'model', 'effort']) {
|
|
157
|
+
const rawValue = record[key];
|
|
158
|
+
if (typeof rawValue === 'string' && rawValue.trim()) {
|
|
159
|
+
target[key] = rawValue.trim();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return Object.keys(target).length > 0 ? target : null;
|
|
163
|
+
}
|
|
164
|
+
function collectCodexTargetsFromUnknownCell(value, targets, owner) {
|
|
165
|
+
const collectCandidate = (candidate) => {
|
|
166
|
+
if (!candidate ||
|
|
167
|
+
typeof candidate !== 'object' ||
|
|
168
|
+
Array.isArray(candidate)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const route = candidate['route'];
|
|
172
|
+
if (Array.isArray(route)) {
|
|
173
|
+
for (const entry of route) {
|
|
174
|
+
const target = routeTargetFromUnknown(entry);
|
|
175
|
+
if (target) {
|
|
176
|
+
collectCodexTargetFromEntry(target, targets, owner);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const target = routeTargetFromUnknown(candidate);
|
|
182
|
+
if (target) {
|
|
183
|
+
collectCodexTargetFromEntry(target, targets, owner);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
if (Array.isArray(value)) {
|
|
187
|
+
for (const entry of value) {
|
|
188
|
+
collectCandidate(entry);
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!value || typeof value !== 'object') {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const candidates = value['candidates'];
|
|
196
|
+
if (!Array.isArray(candidates)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (const entry of candidates) {
|
|
200
|
+
if (typeof entry === 'string') {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
collectCandidate(entry);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function collectCodexTargetsFromUnknownProvider(value, targets, owner) {
|
|
207
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
for (const cell of Object.values(value)) {
|
|
211
|
+
collectCodexTargetsFromUnknownCell(cell, targets, owner);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function frontmatterBlock(content) {
|
|
215
|
+
const normalized = content.startsWith('\uFEFF') ? content.slice(1) : content;
|
|
216
|
+
if (!normalized.startsWith('---\n')) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const end = normalized.indexOf('\n---', 4);
|
|
220
|
+
return end > 0 ? normalized.slice(4, end) : null;
|
|
221
|
+
}
|
|
222
|
+
async function collectProjectStateCodexTargets(scopeRoot, options, targets) {
|
|
223
|
+
const projectPathCandidate = options.projectPath === undefined
|
|
224
|
+
? (await resolveActiveProject(scopeRoot)).path
|
|
225
|
+
: options.projectPath;
|
|
226
|
+
if (!projectPathCandidate) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const projectPath = normalizeProjectPath(scopeRoot, projectPathCandidate);
|
|
230
|
+
if (!projectPath) {
|
|
231
|
+
if (options.projectPath !== undefined) {
|
|
232
|
+
throw new CliError(`Project-scoped Codex materialization path must be repo-relative or inside repo root: ${projectPathCandidate}`);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
let realProjectPath;
|
|
237
|
+
try {
|
|
238
|
+
const validated = await validateRealPathWithinScope(join(scopeRoot, projectPath), scopeRoot);
|
|
239
|
+
realProjectPath = validated.realPath;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
if (options.projectPath !== undefined) {
|
|
243
|
+
throw new CliError(`Project-scoped Codex materialization path must be repo-relative or inside repo root: ${projectPathCandidate}`);
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const statePath = join(realProjectPath, 'state.md');
|
|
248
|
+
const stateContent = await readOptionalFile(statePath);
|
|
249
|
+
if (!stateContent) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const frontmatter = frontmatterBlock(stateContent);
|
|
253
|
+
if (!frontmatter) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const parsed = YAML.parse(frontmatter);
|
|
257
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const policy = parsed['oat_dispatch_policy'];
|
|
261
|
+
if (!policy || typeof policy !== 'object' || Array.isArray(policy)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const matrix = policy['matrix'];
|
|
265
|
+
if (!matrix || typeof matrix !== 'object' || Array.isArray(matrix)) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
collectCodexTargetsFromUnknownProvider(matrix['codex'], targets, 'project-config');
|
|
269
|
+
}
|
|
270
|
+
function isUserCodexScope(scopeRoot, options) {
|
|
271
|
+
if (!options.userConfigDir) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
return resolve(scopeRoot) === resolve(options.userConfigDir, '..');
|
|
275
|
+
}
|
|
276
|
+
async function readCodexMaterializationTargets(scopeRoot, options = {}) {
|
|
277
|
+
const targets = new Map();
|
|
278
|
+
const effectiveConfig = await resolveEffectiveConfig(scopeRoot, options.userConfigDir ?? join(scopeRoot, '.oat', '__no-user-config__'), options.env);
|
|
279
|
+
if (isUserCodexScope(scopeRoot, options)) {
|
|
280
|
+
collectCodexMaterializationTargetsFromProvider(effectiveConfig.user.workflow?.dispatchCeiling?.providers?.codex, targets, 'user-config');
|
|
281
|
+
return sortCodexMaterializationTargets(targets);
|
|
282
|
+
}
|
|
283
|
+
for (const target of SUPPORTED_CODEX_ROLE_TARGETS) {
|
|
284
|
+
targets.set(`${target.model}\0${target.effort}`, {
|
|
285
|
+
...target,
|
|
286
|
+
owner: 'supported-catalogue',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
for (const providerValue of [
|
|
290
|
+
effectiveConfig.shared.workflow?.dispatchCeiling?.providers?.codex,
|
|
291
|
+
effectiveConfig.local.workflow?.dispatchCeiling?.providers?.codex,
|
|
292
|
+
]) {
|
|
293
|
+
collectCodexMaterializationTargetsFromProvider(providerValue, targets, 'project-config');
|
|
294
|
+
}
|
|
295
|
+
await collectProjectStateCodexTargets(scopeRoot, options, targets);
|
|
296
|
+
return sortCodexMaterializationTargets(targets);
|
|
297
|
+
}
|
|
100
298
|
function parseConfigAgentTable(content) {
|
|
101
299
|
if (!content || content.trim() === '') {
|
|
102
300
|
return {};
|
|
@@ -122,9 +320,9 @@ function parseConfigAgentTable(content) {
|
|
|
122
320
|
return {};
|
|
123
321
|
}
|
|
124
322
|
}
|
|
125
|
-
async function collectStaleManagedRoles(scopeRoot, existingConfigContent, desiredRoleNames) {
|
|
323
|
+
async function collectStaleManagedRoles(scopeRoot, existingConfigContent, desiredRoleNames, cleanupOwner, removeLegacyProjectRoles) {
|
|
126
324
|
const agents = parseConfigAgentTable(existingConfigContent);
|
|
127
|
-
const stale =
|
|
325
|
+
const stale = new Set();
|
|
128
326
|
for (const [roleName, roleConfig] of Object.entries(agents)) {
|
|
129
327
|
if (desiredRoleNames.has(roleName)) {
|
|
130
328
|
continue;
|
|
@@ -138,19 +336,68 @@ async function collectStaleManagedRoles(scopeRoot, existingConfigContent, desire
|
|
|
138
336
|
if (!roleContent || !isOatManagedCodexRoleFile(roleContent, roleName)) {
|
|
139
337
|
continue;
|
|
140
338
|
}
|
|
141
|
-
|
|
339
|
+
const owner = readOatManagedCodexRoleOwner(roleContent);
|
|
340
|
+
const legacyProjectRole = removeLegacyProjectRoles &&
|
|
341
|
+
owner === null &&
|
|
342
|
+
SUPPORTED_CODEX_BASE_ROLES.some((baseRole) => roleName.startsWith(`${baseRole}-`));
|
|
343
|
+
if (owner !== cleanupOwner && !legacyProjectRole) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
stale.add(roleName);
|
|
347
|
+
}
|
|
348
|
+
const agentsDir = join(scopeRoot, '.codex', 'agents');
|
|
349
|
+
let roleFiles;
|
|
350
|
+
try {
|
|
351
|
+
roleFiles = await readdir(agentsDir);
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
roleFiles = [];
|
|
355
|
+
}
|
|
356
|
+
for (const roleFile of roleFiles) {
|
|
357
|
+
if (!roleFile.endsWith('.toml')) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const roleName = basename(roleFile, '.toml');
|
|
361
|
+
if (desiredRoleNames.has(roleName) || stale.has(roleName)) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const rolePath = join(agentsDir, roleFile);
|
|
365
|
+
const roleContent = await readOptionalFile(rolePath);
|
|
366
|
+
if (!roleContent || !isOatManagedCodexRoleFile(roleContent, roleName)) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const owner = readOatManagedCodexRoleOwner(roleContent);
|
|
370
|
+
const legacyProjectRole = removeLegacyProjectRoles &&
|
|
371
|
+
owner === null &&
|
|
372
|
+
SUPPORTED_CODEX_BASE_ROLES.some((baseRole) => roleName.startsWith(`${baseRole}-`));
|
|
373
|
+
if (owner !== cleanupOwner && !legacyProjectRole) {
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
stale.add(roleName);
|
|
142
377
|
}
|
|
143
|
-
return stale.sort((left, right) => left.localeCompare(right));
|
|
378
|
+
return [...stale].sort((left, right) => left.localeCompare(right));
|
|
144
379
|
}
|
|
145
|
-
export async function computeCodexProjectExtensionPlan(scopeRoot, canonicalEntries, allowedCanonicalPaths) {
|
|
380
|
+
export async function computeCodexProjectExtensionPlan(scopeRoot, canonicalEntries, allowedCanonicalPaths, options = {}) {
|
|
146
381
|
const isPartialSync = allowedCanonicalPaths !== undefined && allowedCanonicalPaths.length > 0;
|
|
147
|
-
const
|
|
382
|
+
const materializationTargets = await readCodexMaterializationTargets(scopeRoot, options);
|
|
383
|
+
if (!isPartialSync &&
|
|
384
|
+
isUserCodexScope(scopeRoot, options) &&
|
|
385
|
+
materializationTargets.length > 0) {
|
|
386
|
+
const canonicalBaseRoles = new Set(canonicalEntries
|
|
387
|
+
.filter((entry) => entry.type === 'agent' && entry.isFile)
|
|
388
|
+
.map((entry) => entry.name.replace(/\.md$/i, '')));
|
|
389
|
+
const missingBaseRoles = SUPPORTED_CODEX_BASE_ROLES.filter((role) => !canonicalBaseRoles.has(role));
|
|
390
|
+
if (missingBaseRoles.length > 0) {
|
|
391
|
+
throw new CliError(`Bundled managed Codex role definitions are unavailable for user sync: ${missingBaseRoles.join(', ')}. Refusing stale user-role cleanup.`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const desiredRoles = await desiredRolesFromCanonical(canonicalEntries.filter((entry) => canonicalPathAllowed(scopeRoot, entry, allowedCanonicalPaths)), scopeRoot, materializationTargets);
|
|
148
395
|
const desiredRoleNames = new Set(desiredRoles.map((role) => role.roleName));
|
|
149
396
|
const existingConfigPath = configPath(scopeRoot);
|
|
150
397
|
const existingConfigContent = await readOptionalFile(existingConfigPath);
|
|
151
398
|
const staleRoles = isPartialSync
|
|
152
399
|
? []
|
|
153
|
-
: await collectStaleManagedRoles(scopeRoot, existingConfigContent, desiredRoleNames);
|
|
400
|
+
: await collectStaleManagedRoles(scopeRoot, existingConfigContent, desiredRoleNames, isUserCodexScope(scopeRoot, options) ? 'user-config' : 'project-config', !isUserCodexScope(scopeRoot, options));
|
|
154
401
|
if (isPartialSync && desiredRoles.length === 0) {
|
|
155
402
|
return {
|
|
156
403
|
operations: [],
|
|
@@ -227,7 +474,7 @@ export async function computeCodexProjectExtensionPlan(scopeRoot, canonicalEntri
|
|
|
227
474
|
});
|
|
228
475
|
return {
|
|
229
476
|
operations,
|
|
230
|
-
managedRoles: desiredRoles.map((role) => role.roleName),
|
|
477
|
+
managedRoles: [...desiredRoles.map((role) => role.roleName), ...staleRoles],
|
|
231
478
|
aggregateConfigHash: hashContent(configMerge.mergedContent),
|
|
232
479
|
};
|
|
233
480
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export type MatrixCellAvailability = 'valid' | 'unknown-value' | 'unvalidated';
|
|
2
|
+
export interface MatrixCellAvailabilityResult {
|
|
3
|
+
availability: MatrixCellAvailability;
|
|
4
|
+
allowedValues?: string[];
|
|
5
|
+
message?: string;
|
|
6
|
+
}
|
|
7
|
+
export type MatrixCellAvailabilityResponse = MatrixCellAvailability | MatrixCellAvailabilityResult;
|
|
2
8
|
export interface CursorAgentRunOptions {
|
|
3
9
|
cwd: string;
|
|
4
10
|
env: NodeJS.ProcessEnv;
|
|
@@ -8,15 +14,32 @@ export interface CursorAgentRunResult {
|
|
|
8
14
|
stdout: string;
|
|
9
15
|
stderr: string;
|
|
10
16
|
}
|
|
17
|
+
export interface CodexRunOptions {
|
|
18
|
+
cwd: string;
|
|
19
|
+
env: NodeJS.ProcessEnv;
|
|
20
|
+
}
|
|
21
|
+
export interface CodexRunResult {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
stdout: string;
|
|
24
|
+
stderr: string;
|
|
25
|
+
}
|
|
11
26
|
export interface AvailabilityOracleDependencies {
|
|
12
27
|
pathExists: (path: string) => Promise<boolean>;
|
|
13
28
|
runCursorAgent: (args: string[], options: CursorAgentRunOptions) => Promise<CursorAgentRunResult>;
|
|
29
|
+
runCodex: (args: string[], options: CodexRunOptions) => Promise<CodexRunResult>;
|
|
14
30
|
env?: NodeJS.ProcessEnv;
|
|
15
31
|
}
|
|
16
32
|
export interface ValidateMatrixCellOptions {
|
|
17
33
|
cwd: string;
|
|
34
|
+
detailed?: boolean;
|
|
18
35
|
env?: NodeJS.ProcessEnv;
|
|
19
36
|
dependencies?: Partial<AvailabilityOracleDependencies>;
|
|
37
|
+
target?: {
|
|
38
|
+
model?: string;
|
|
39
|
+
effort?: string;
|
|
40
|
+
} | null;
|
|
20
41
|
}
|
|
21
|
-
export declare function
|
|
42
|
+
export declare function normalizeMatrixCellAvailability(result: MatrixCellAvailabilityResponse): MatrixCellAvailabilityResult;
|
|
43
|
+
export declare function validateCursorSubagentModel(value: string, options: ValidateMatrixCellOptions): Promise<MatrixCellAvailabilityResult>;
|
|
44
|
+
export declare function validateMatrixCell(provider: string, value: string, options: ValidateMatrixCellOptions): Promise<MatrixCellAvailabilityResponse>;
|
|
22
45
|
//# sourceMappingURL=availability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/availability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/availability.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,CAAC;AAE/E,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,sBAAsB,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,8BAA8B,GACtC,sBAAsB,GACtB,4BAA4B,CAAC;AAEjC,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC7C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,cAAc,EAAE,CACd,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,eAAe,KACrB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;IACvD,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;CACV;AAWD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,8BAA8B,GACrC,4BAA4B,CAE9B;AA+VD,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,4BAA4B,CAAC,CAsEvC;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,8BAA8B,CAAC,CA2CzC"}
|