@open-agent-toolkit/cli 0.1.46 → 0.1.50

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 (98) hide show
  1. package/assets/agents/oat-phase-implementer.md +202 -191
  2. package/assets/agents/oat-reviewer.md +11 -1
  3. package/assets/config/dispatch-matrix-recommendation.json +120 -13
  4. package/assets/docs/cli-utilities/configuration.md +213 -113
  5. package/assets/docs/cli-utilities/workflow-gates.md +178 -27
  6. package/assets/docs/contributing/skills.md +14 -8
  7. package/assets/docs/provider-sync/providers.md +46 -8
  8. package/assets/docs/provider-sync/scope-and-surface.md +2 -2
  9. package/assets/docs/reference/cli-reference.md +3 -1
  10. package/assets/docs/reference/oat-directory-structure.md +27 -26
  11. package/assets/docs/workflows/projects/artifacts.md +31 -1
  12. package/assets/docs/workflows/projects/dispatch-ceiling.md +297 -197
  13. package/assets/docs/workflows/projects/implementation-execution.md +306 -249
  14. package/assets/docs/workflows/projects/lifecycle.md +26 -5
  15. package/assets/docs/workflows/projects/reviews.md +27 -2
  16. package/assets/migration/pjm-restructure.md +1 -1
  17. package/assets/public-package-versions.json +4 -4
  18. package/assets/skills/oat-project-implement/SKILL.md +290 -149
  19. package/assets/skills/oat-project-import-plan/SKILL.md +173 -16
  20. package/assets/skills/oat-project-next/SKILL.md +2 -2
  21. package/assets/skills/oat-project-plan/SKILL.md +122 -92
  22. package/assets/skills/oat-project-plan-writing/SKILL.md +246 -15
  23. package/assets/skills/oat-project-quick-start/SKILL.md +157 -107
  24. package/assets/skills/oat-project-review-provide/SKILL.md +110 -22
  25. package/assets/skills/oat-project-review-provide-remote/SKILL.md +28 -1
  26. package/dist/commands/config/index.d.ts +3 -0
  27. package/dist/commands/config/index.d.ts.map +1 -1
  28. package/dist/commands/config/index.js +92 -125
  29. package/dist/commands/doctor/index.d.ts +3 -0
  30. package/dist/commands/doctor/index.d.ts.map +1 -1
  31. package/dist/commands/doctor/index.js +57 -95
  32. package/dist/commands/gate/index.d.ts +7 -1
  33. package/dist/commands/gate/index.d.ts.map +1 -1
  34. package/dist/commands/gate/index.js +615 -67
  35. package/dist/commands/gate/review-verdict.d.ts +16 -0
  36. package/dist/commands/gate/review-verdict.d.ts.map +1 -1
  37. package/dist/commands/gate/review-verdict.js +72 -9
  38. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  39. package/dist/commands/project/dispatch-ceiling/index.js +567 -99
  40. package/dist/commands/providers/codex/materialize.d.ts.map +1 -1
  41. package/dist/commands/providers/codex/materialize.js +6 -1
  42. package/dist/commands/shared/frontmatter.d.ts +4 -0
  43. package/dist/commands/shared/frontmatter.d.ts.map +1 -1
  44. package/dist/commands/shared/frontmatter.js +23 -0
  45. package/dist/commands/status/index.d.ts +1 -0
  46. package/dist/commands/status/index.d.ts.map +1 -1
  47. package/dist/commands/status/index.js +10 -4
  48. package/dist/commands/sync/index.d.ts.map +1 -1
  49. package/dist/commands/sync/index.js +10 -3
  50. package/dist/commands/sync/sync.types.d.ts +1 -0
  51. package/dist/commands/sync/sync.types.d.ts.map +1 -1
  52. package/dist/config/dispatch-matrix.d.ts +59 -0
  53. package/dist/config/dispatch-matrix.d.ts.map +1 -0
  54. package/dist/config/dispatch-matrix.js +264 -0
  55. package/dist/config/oat-config.d.ts +9 -18
  56. package/dist/config/oat-config.d.ts.map +1 -1
  57. package/dist/config/oat-config.js +99 -120
  58. package/dist/config/resolve.d.ts +8 -0
  59. package/dist/config/resolve.d.ts.map +1 -1
  60. package/dist/config/resolve.js +66 -1
  61. package/dist/engine/index.d.ts +1 -1
  62. package/dist/engine/index.d.ts.map +1 -1
  63. package/dist/engine/index.js +1 -1
  64. package/dist/engine/scanner.d.ts +1 -0
  65. package/dist/engine/scanner.d.ts.map +1 -1
  66. package/dist/engine/scanner.js +17 -1
  67. package/dist/fs/paths.d.ts +4 -0
  68. package/dist/fs/paths.d.ts.map +1 -1
  69. package/dist/fs/paths.js +18 -1
  70. package/dist/providers/ceiling/registry.d.ts +1 -0
  71. package/dist/providers/ceiling/registry.d.ts.map +1 -1
  72. package/dist/providers/ceiling/registry.js +12 -5
  73. package/dist/providers/codex/codec/catalog.d.ts +14 -0
  74. package/dist/providers/codex/codec/catalog.d.ts.map +1 -0
  75. package/dist/providers/codex/codec/catalog.js +21 -0
  76. package/dist/providers/codex/codec/materialize.d.ts.map +1 -1
  77. package/dist/providers/codex/codec/materialize.js +6 -5
  78. package/dist/providers/codex/codec/shared.d.ts +19 -0
  79. package/dist/providers/codex/codec/shared.d.ts.map +1 -1
  80. package/dist/providers/codex/codec/shared.js +98 -5
  81. package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
  82. package/dist/providers/codex/codec/sync-extension.js +142 -32
  83. package/dist/providers/identity/availability.d.ts +12 -0
  84. package/dist/providers/identity/availability.d.ts.map +1 -1
  85. package/dist/providers/identity/availability.js +72 -29
  86. package/dist/providers/identity/dispatch-report.d.ts +124 -0
  87. package/dist/providers/identity/dispatch-report.d.ts.map +1 -0
  88. package/dist/providers/identity/dispatch-report.js +285 -0
  89. package/dist/providers/identity/dispatch-validation.d.ts +28 -0
  90. package/dist/providers/identity/dispatch-validation.d.ts.map +1 -0
  91. package/dist/providers/identity/dispatch-validation.js +149 -0
  92. package/dist/providers/identity/stamp.d.ts +2 -0
  93. package/dist/providers/identity/stamp.d.ts.map +1 -1
  94. package/dist/providers/identity/stamp.js +7 -1
  95. package/dist/shared/types.d.ts +1 -0
  96. package/dist/shared/types.d.ts.map +1 -1
  97. package/dist/shared/types.js +4 -0
  98. package/package.json +2 -2
@@ -1,9 +1,11 @@
1
1
  import { execSync } from 'node:child_process';
2
- import { readFile } from 'node:fs/promises';
2
+ import { lstat, readFile } from 'node:fs/promises';
3
3
  import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
4
  import { atomicWriteJson, dirExists, fileExists } from '../fs/io.js';
5
- import { normalizeToPosixPath } from '../fs/paths.js';
5
+ import { normalizeToPosixPath, validateRealPathWithinScope } from '../fs/paths.js';
6
+ import { normalizeDispatchMatrix, } from './dispatch-matrix.js';
6
7
  import { parseJsonConfig } from './json.js';
8
+ export { VALID_DISPATCH_MATRIX_TIERS, isCodexMaterializedRouteTarget, isWorkflowDispatchCandidateLadder, isWorkflowDispatchFallbackRoute, toWorkflowDispatchCandidateLadder, validateDispatchRouteTarget, } from './dispatch-matrix.js';
7
9
  const VALID_HILL_CHECKPOINT_DEFAULTS = ['every', 'final'];
8
10
  const VALID_POST_IMPLEMENT_SEQUENCES = ['wait', 'summary', 'pr', 'docs-pr'];
9
11
  const VALID_REVIEW_EXECUTION_MODELS = [
@@ -16,12 +18,11 @@ const VALID_DESIGN_MODES = [
16
18
  'selective',
17
19
  'draft',
18
20
  ];
19
- export const VALID_CODEX_DISPATCH_CEILINGS = ['low', 'medium', 'high', 'xhigh'];
21
+ export const VALID_CODEX_DISPATCH_CEILINGS = ['low', 'medium', 'high', 'xhigh', 'max'];
20
22
  export const VALID_CLAUDE_DISPATCH_CEILINGS = ['haiku', 'sonnet', 'opus', 'fable'];
21
23
  export const VALID_DISPATCH_CEILING_PRESETS = ['balanced', 'maximum', 'cost-conscious'];
22
24
  export const VALID_DISPATCH_POLICY_MODES = ['managed', 'inherit'];
23
25
  export const VALID_MANAGED_DISPATCH_POLICIES = ['economy', 'balanced', 'high', 'frontier', 'uncapped'];
24
- export const VALID_DISPATCH_MATRIX_TIERS = ['economy', 'balanced', 'high', 'frontier'];
25
26
  const VALID_GATE_ON_FAILURES = [
26
27
  'block',
27
28
  'prompt',
@@ -31,6 +32,10 @@ export const BUILTIN_EXEC_TARGETS = {
31
32
  'codex-default': {
32
33
  runtime: 'codex',
33
34
  baseCommand: ['codex', 'exec'],
35
+ invocation: {
36
+ model: 'provider-default',
37
+ reasoningEffort: 'provider-default',
38
+ },
34
39
  hostDetectionCommand: [
35
40
  'sh',
36
41
  '-c',
@@ -42,6 +47,10 @@ export const BUILTIN_EXEC_TARGETS = {
42
47
  'claude-default': {
43
48
  runtime: 'claude',
44
49
  baseCommand: ['claude', '-p'],
50
+ invocation: {
51
+ model: 'provider-default',
52
+ reasoningEffort: 'provider-default',
53
+ },
45
54
  hostDetectionCommand: ['sh', '-c', 'test -n "$CLAUDECODE"'],
46
55
  availabilityCommand: ['claude', '--version'],
47
56
  priority: 100,
@@ -49,6 +58,10 @@ export const BUILTIN_EXEC_TARGETS = {
49
58
  'cursor-default': {
50
59
  runtime: 'cursor',
51
60
  baseCommand: ['cursor-agent', '-p'],
61
+ invocation: {
62
+ model: 'provider-default',
63
+ reasoningEffort: 'provider-default',
64
+ },
52
65
  hostDetectionCommand: ['sh', '-c', 'test -n "$CURSOR_AGENT"'],
53
66
  availabilityCommand: [
54
67
  'sh',
@@ -58,21 +71,6 @@ export const BUILTIN_EXEC_TARGETS = {
58
71
  priority: 70,
59
72
  },
60
73
  };
61
- export function isCodexMaterializedRouteTarget(provider, target) {
62
- return (target.harness ?? provider) === 'codex';
63
- }
64
- export function validateDispatchRouteTarget(provider, target) {
65
- if (!isCodexMaterializedRouteTarget(provider, target)) {
66
- return { valid: true };
67
- }
68
- if (!target.model || !target.effort) {
69
- return {
70
- valid: false,
71
- reason: 'Codex materialized dispatch targets must provide both model and effort.',
72
- };
73
- }
74
- return { valid: true };
75
- }
76
74
  function normalizeMaxAttempts(value) {
77
75
  if (typeof value !== 'number' || !Number.isFinite(value)) {
78
76
  return 2;
@@ -124,82 +122,6 @@ function normalizeGateConfig(value) {
124
122
  }
125
123
  return gate;
126
124
  }
127
- function normalizeProviderBareValue(providerKey, value) {
128
- const trimmed = trimNonEmptyString(value);
129
- if (trimmed === undefined) {
130
- return undefined;
131
- }
132
- if (providerKey === 'codex' &&
133
- !VALID_CODEX_DISPATCH_CEILINGS.includes(trimmed)) {
134
- return undefined;
135
- }
136
- if (providerKey === 'claude' &&
137
- !VALID_CLAUDE_DISPATCH_CEILINGS.includes(trimmed)) {
138
- return undefined;
139
- }
140
- return trimmed;
141
- }
142
- function normalizeDispatchRouteTarget(value) {
143
- if (!isRecord(value)) {
144
- return undefined;
145
- }
146
- const target = {};
147
- const harness = trimNonEmptyString(value.harness);
148
- if (harness !== undefined) {
149
- target.harness = harness;
150
- }
151
- const model = trimNonEmptyString(value.model);
152
- if (model !== undefined) {
153
- target.model = model;
154
- }
155
- const effort = trimNonEmptyString(value.effort);
156
- if (effort !== undefined) {
157
- target.effort = effort;
158
- }
159
- return Object.keys(target).length > 0 ? target : undefined;
160
- }
161
- function normalizeDispatchMatrixCell(providerKey, value) {
162
- const bareValue = normalizeProviderBareValue(providerKey, value);
163
- if (bareValue !== undefined) {
164
- return bareValue;
165
- }
166
- if (!Array.isArray(value) || value.length === 0) {
167
- return undefined;
168
- }
169
- const route = [];
170
- for (const entry of value) {
171
- const bareEntry = normalizeProviderBareValue(providerKey, entry);
172
- if (bareEntry !== undefined) {
173
- route.push(bareEntry);
174
- continue;
175
- }
176
- const target = normalizeDispatchRouteTarget(entry);
177
- if (target !== undefined) {
178
- route.push(target);
179
- }
180
- }
181
- return route.length > 0 ? route : undefined;
182
- }
183
- function normalizeDispatchProviderValue(providerKey, value) {
184
- const bareValue = normalizeProviderBareValue(providerKey, value);
185
- if (bareValue !== undefined) {
186
- return bareValue;
187
- }
188
- if (!isRecord(value)) {
189
- return undefined;
190
- }
191
- const tierMap = {};
192
- for (const [tier, rawCell] of Object.entries(value)) {
193
- if (!VALID_DISPATCH_MATRIX_TIERS.includes(tier)) {
194
- continue;
195
- }
196
- const normalized = normalizeDispatchMatrixCell(providerKey, rawCell);
197
- if (normalized !== undefined) {
198
- tierMap[tier] = normalized;
199
- }
200
- }
201
- return Object.keys(tierMap).length > 0 ? tierMap : undefined;
202
- }
203
125
  function normalizeExecTarget(value) {
204
126
  if (value === null) {
205
127
  return null;
@@ -216,6 +138,16 @@ function normalizeExecTarget(value) {
216
138
  if (baseCommand !== undefined) {
217
139
  target.baseCommand = baseCommand;
218
140
  }
141
+ if (isRecord(value.invocation)) {
142
+ const model = trimNonEmptyString(value.invocation.model);
143
+ const reasoningEffort = trimNonEmptyString(value.invocation.reasoningEffort);
144
+ if (model !== undefined || reasoningEffort !== undefined) {
145
+ target.invocation = {
146
+ ...(model !== undefined ? { model } : {}),
147
+ ...(reasoningEffort !== undefined ? { reasoningEffort } : {}),
148
+ };
149
+ }
150
+ }
219
151
  const models = normalizeStringList(value.models);
220
152
  if (models !== undefined) {
221
153
  target.models = models;
@@ -328,15 +260,12 @@ function normalizeWorkflowConfig(parsed) {
328
260
  dispatchCeiling.recommendationVersion = recommendationVersion;
329
261
  }
330
262
  if (isRecord(parsed.dispatchCeiling.providers)) {
331
- const providers = {};
332
- for (const [providerKey, rawProviderValue] of Object.entries(parsed.dispatchCeiling.providers)) {
333
- const normalized = normalizeDispatchProviderValue(providerKey, rawProviderValue);
334
- if (normalized !== undefined) {
335
- providers[providerKey] = normalized;
336
- }
337
- }
338
- if (Object.keys(providers).length > 0) {
339
- dispatchCeiling.providers = providers;
263
+ const normalized = normalizeDispatchMatrix(parsed.dispatchCeiling.providers, {
264
+ pathPrefix: 'workflow.dispatchCeiling.providers',
265
+ compatibilityMode: 'layered-config',
266
+ });
267
+ if (Object.keys(normalized.providers).length > 0) {
268
+ dispatchCeiling.providers = normalized.providers;
340
269
  }
341
270
  }
342
271
  if (Object.keys(dispatchCeiling).length > 0) {
@@ -405,7 +334,7 @@ function normalizeKnownStrays(value) {
405
334
  .filter((pathValue) => pathValue !== undefined);
406
335
  return normalized.length > 0 ? [...new Set(normalized)].sort() : undefined;
407
336
  }
408
- function normalizeProjectPath(repoRoot, pathValue) {
337
+ export function normalizeProjectPath(repoRoot, pathValue) {
409
338
  if (pathValue == null) {
410
339
  return null;
411
340
  }
@@ -413,25 +342,42 @@ function normalizeProjectPath(repoRoot, pathValue) {
413
342
  if (!trimmed) {
414
343
  return null;
415
344
  }
416
- if (!isAbsolute(trimmed)) {
417
- const normalizedRelative = trimPathValue(normalizeToPosixPath(trimmed));
418
- return normalizedRelative && normalizedRelative !== '.'
419
- ? normalizedRelative
420
- : null;
421
- }
422
345
  const repoRootResolved = resolve(repoRoot);
423
- const absoluteResolved = resolve(trimmed);
424
- const isInsideRepo = absoluteResolved === repoRootResolved ||
425
- absoluteResolved.startsWith(`${repoRootResolved}${sep}`);
346
+ const absoluteResolved = resolve(repoRootResolved, trimmed);
347
+ const relativePath = relative(repoRootResolved, absoluteResolved);
348
+ const isInsideRepo = !isAbsolute(relativePath) &&
349
+ relativePath !== '..' &&
350
+ !relativePath.startsWith(`..${sep}`);
426
351
  if (!isInsideRepo) {
427
352
  return null;
428
353
  }
429
- const relativePath = normalizeToPosixPath(relative(repoRootResolved, absoluteResolved));
430
- const normalizedRelative = trimPathValue(relativePath);
354
+ const normalizedRelative = trimPathValue(normalizeToPosixPath(relativePath));
431
355
  return normalizedRelative && normalizedRelative !== '.'
432
356
  ? normalizedRelative
433
357
  : null;
434
358
  }
359
+ async function normalizeReadableProjectPath(repoRoot, pathValue) {
360
+ const normalizedPath = normalizeProjectPath(repoRoot, pathValue);
361
+ if (!normalizedPath) {
362
+ return null;
363
+ }
364
+ const absolutePath = join(repoRoot, normalizedPath);
365
+ try {
366
+ await lstat(absolutePath);
367
+ }
368
+ catch (error) {
369
+ return isMissingFileError(error) ? normalizedPath : null;
370
+ }
371
+ try {
372
+ const validated = await validateRealPathWithinScope(absolutePath, repoRoot);
373
+ return (await dirExists(validated.realPath))
374
+ ? normalizeProjectPath(validated.realScopeRoot, validated.realPath)
375
+ : null;
376
+ }
377
+ catch {
378
+ return null;
379
+ }
380
+ }
435
381
  function normalizeOatConfig(parsed) {
436
382
  const next = { ...DEFAULT_OAT_CONFIG };
437
383
  if (!isRecord(parsed)) {
@@ -598,7 +544,11 @@ export async function readOatLocalConfig(repoRoot) {
598
544
  const configPath = getLocalConfigPath(repoRoot);
599
545
  try {
600
546
  const raw = await readFile(configPath, 'utf8');
601
- return normalizeOatLocalConfig(repoRoot, parseJsonConfig(raw, configPath));
547
+ const normalized = normalizeOatLocalConfig(repoRoot, parseJsonConfig(raw, configPath));
548
+ if (normalized.activeProject !== undefined) {
549
+ normalized.activeProject = await normalizeReadableProjectPath(repoRoot, normalized.activeProject);
550
+ }
551
+ return normalized;
602
552
  }
603
553
  catch (error) {
604
554
  if (isMissingFileError(error)) {
@@ -623,12 +573,29 @@ export async function resolveActiveProject(repoRoot) {
623
573
  if (!projectPath) {
624
574
  return { name: null, path: null, status: 'unset' };
625
575
  }
626
- const absoluteProjectPath = join(repoRoot, projectPath);
576
+ let resolvedProjectPath = projectPath;
577
+ let absoluteProjectPath = join(repoRoot, projectPath);
578
+ try {
579
+ const validated = await validateRealPathWithinScope(absoluteProjectPath, repoRoot);
580
+ const canonicalProjectPath = normalizeProjectPath(validated.realScopeRoot, validated.realPath);
581
+ if (!canonicalProjectPath) {
582
+ throw new Error('Project path resolves to the repository root.');
583
+ }
584
+ resolvedProjectPath = canonicalProjectPath;
585
+ absoluteProjectPath = validated.realPath;
586
+ }
587
+ catch {
588
+ return {
589
+ name: basename(absoluteProjectPath),
590
+ path: projectPath,
591
+ status: 'missing',
592
+ };
593
+ }
627
594
  const statePath = join(absoluteProjectPath, 'state.md');
628
595
  const isValid = (await dirExists(absoluteProjectPath)) && (await fileExists(statePath));
629
596
  return {
630
597
  name: basename(absoluteProjectPath),
631
- path: projectPath,
598
+ path: resolvedProjectPath,
632
599
  status: isValid ? 'active' : 'missing',
633
600
  };
634
601
  }
@@ -637,10 +604,22 @@ export async function setActiveProject(repoRoot, projectRelativePath) {
637
604
  if (!normalizedPath) {
638
605
  throw new Error(`Active project path must be repo-relative or inside repo root: ${projectRelativePath}`);
639
606
  }
607
+ let canonicalPath;
608
+ try {
609
+ const validated = await validateRealPathWithinScope(join(repoRoot, normalizedPath), repoRoot);
610
+ const canonicalProjectPath = normalizeProjectPath(validated.realScopeRoot, validated.realPath);
611
+ if (!canonicalProjectPath || !(await dirExists(validated.realPath))) {
612
+ throw new Error('Project directory is missing.');
613
+ }
614
+ canonicalPath = canonicalProjectPath;
615
+ }
616
+ catch {
617
+ throw new Error(`Active project path must be repo-relative or inside repo root: ${projectRelativePath}`);
618
+ }
640
619
  const localConfig = await readOatLocalConfig(repoRoot);
641
620
  await writeOatLocalConfig(repoRoot, {
642
621
  ...localConfig,
643
- activeProject: normalizedPath,
622
+ activeProject: canonicalPath,
644
623
  });
645
624
  }
646
625
  export async function clearActiveProject(repoRoot, options) {
@@ -18,4 +18,12 @@ export interface ResolveEffectiveConfigDependencies {
18
18
  export declare function resolveEffectiveConfig(repoRoot: string, userConfigDir: string, env?: NodeJS.ProcessEnv, overrides?: Partial<ResolveEffectiveConfigDependencies>): Promise<ResolvedConfig>;
19
19
  export declare function resolveGate(effective: ResolvedConfig, skillName: string): GateConfig | null;
20
20
  export declare function resolveExecTargets(effective: ResolvedConfig): Record<string, ExecTarget>;
21
+ export type ExecTargetOrigin = 'builtin' | 'user' | 'shared' | 'local';
22
+ export interface ResolvedExecTargetView {
23
+ target: ExecTarget;
24
+ origin: ExecTargetOrigin;
25
+ explicitlyConfigured: boolean;
26
+ enabled: boolean;
27
+ }
28
+ export declare function resolveExecTargetViews(effective: ResolvedConfig): Record<string, ResolvedExecTargetView>;
21
29
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,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;CAChE;AAmFD,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,IAAI,CAcnB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAY5B"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,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;CAChE;AAmFD,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,IAAI,CAcnB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAY5B;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAoDxC"}
@@ -1,3 +1,4 @@
1
+ import { isWorkflowDispatchCandidateLadder } from './dispatch-matrix.js';
1
2
  import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig, } from './oat-config.js';
2
3
  const DEFAULT_DEPENDENCIES = {
3
4
  readOatConfig,
@@ -167,6 +168,53 @@ export function resolveExecTargets(effective) {
167
168
  }
168
169
  return targets;
169
170
  }
171
+ export function resolveExecTargetViews(effective) {
172
+ const targets = cloneExecTargetRegistry(BUILTIN_EXEC_TARGETS);
173
+ const views = Object.fromEntries(Object.entries(targets).map(([id, target]) => [
174
+ id,
175
+ {
176
+ target: cloneExecTarget(target),
177
+ origin: 'builtin',
178
+ explicitlyConfigured: false,
179
+ enabled: true,
180
+ },
181
+ ]));
182
+ for (const [origin, layer] of [
183
+ ['user', effective.user.workflow?.gates?.execTargets],
184
+ ['shared', effective.shared.workflow?.gates?.execTargets],
185
+ ['local', effective.local.workflow?.gates?.execTargets],
186
+ ]) {
187
+ if (!layer) {
188
+ continue;
189
+ }
190
+ for (const [id, override] of Object.entries(layer)) {
191
+ if (override === null) {
192
+ const target = targets[id] ?? views[id]?.target;
193
+ delete targets[id];
194
+ if (target) {
195
+ views[id] = {
196
+ target: cloneExecTarget(target),
197
+ origin,
198
+ explicitlyConfigured: true,
199
+ enabled: false,
200
+ };
201
+ }
202
+ continue;
203
+ }
204
+ mergeExecTargetLayer(targets, { [id]: override });
205
+ const target = targets[id];
206
+ if (target) {
207
+ views[id] = {
208
+ target: cloneExecTarget(target),
209
+ origin,
210
+ explicitlyConfigured: true,
211
+ enabled: true,
212
+ };
213
+ }
214
+ }
215
+ }
216
+ return views;
217
+ }
170
218
  function mergeExecTargetLayer(targets, layer) {
171
219
  if (!layer) {
172
220
  return;
@@ -181,6 +229,7 @@ function mergeExecTargetLayer(targets, layer) {
181
229
  targets[id] = cloneExecTarget({
182
230
  runtime: override.runtime ?? existing.runtime,
183
231
  baseCommand: override.baseCommand ?? existing.baseCommand,
232
+ invocation: mergeExecTargetInvocation(existing.invocation, override.invocation),
184
233
  models: override.models ?? existing.models,
185
234
  hostDetectionCommand: override.hostDetectionCommand ?? existing.hostDetectionCommand,
186
235
  availabilityCommand: override.availabilityCommand ?? existing.availabilityCommand,
@@ -209,6 +258,9 @@ function cloneExecTarget(target) {
209
258
  if (target.hostDetectionCommand) {
210
259
  next.hostDetectionCommand = [...target.hostDetectionCommand];
211
260
  }
261
+ if (target.invocation) {
262
+ next.invocation = { ...target.invocation };
263
+ }
212
264
  if (target.availabilityCommand) {
213
265
  next.availabilityCommand = [...target.availabilityCommand];
214
266
  }
@@ -229,6 +281,9 @@ function toCompleteExecTarget(target) {
229
281
  ? target.priority
230
282
  : 0,
231
283
  };
284
+ if (target.invocation) {
285
+ completeTarget.invocation = { ...target.invocation };
286
+ }
232
287
  if (isValidArgv(target.hostDetectionCommand)) {
233
288
  completeTarget.hostDetectionCommand = [...target.hostDetectionCommand];
234
289
  }
@@ -240,6 +295,15 @@ function toCompleteExecTarget(target) {
240
295
  }
241
296
  return completeTarget;
242
297
  }
298
+ function mergeExecTargetInvocation(existing, override) {
299
+ if (!existing && !override) {
300
+ return undefined;
301
+ }
302
+ return {
303
+ ...existing,
304
+ ...override,
305
+ };
306
+ }
243
307
  function isValidStringList(value) {
244
308
  return (Array.isArray(value) &&
245
309
  value.length > 0 &&
@@ -264,7 +328,8 @@ function flattenConfig(value, prefix = '') {
264
328
  continue;
265
329
  }
266
330
  const nextKey = prefix ? `${prefix}.${key}` : key;
267
- if (isRecord(nestedValue)) {
331
+ if (isRecord(nestedValue) &&
332
+ !isWorkflowDispatchCandidateLadder(nestedValue)) {
268
333
  Object.assign(flattened, flattenConfig(nestedValue, nextKey));
269
334
  continue;
270
335
  }
@@ -5,5 +5,5 @@ export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_M
5
5
  export type { HookInstallInfo, HookStatus } from './hook.js';
6
6
  export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
7
7
  export type { CanonicalEntry } from './scanner.js';
8
- export { scanCanonical } from './scanner.js';
8
+ export { scanBundledManagedCodexAgents, scanCanonical } from './scanner.js';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,6BAA6B,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -3,4 +3,4 @@ export { SYNC_OPERATION_TYPES, } from './engine.types.js';
3
3
  export { executeSyncPlan } from './execute-plan.js';
4
4
  export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, HOOK_STRAY_INFO, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
5
5
  export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
6
- export { scanCanonical } from './scanner.js';
6
+ export { scanBundledManagedCodexAgents, scanCanonical } from './scanner.js';
@@ -6,6 +6,7 @@ export interface CanonicalEntry {
6
6
  canonicalPath: string;
7
7
  isFile: boolean;
8
8
  }
9
+ export declare function scanBundledManagedCodexAgents(): Promise<CanonicalEntry[]>;
9
10
  export declare function scanCanonical(basePath: string, scope: ConcreteScope): Promise<CanonicalEntry[]>;
10
11
  export {};
11
12
  //# sourceMappingURL=scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/engine/scanner.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAEhE,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AA0DD,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CA2B3B"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/engine/scanner.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,KAAK,EACX,MAAM,eAAe,CAAC;AAEvB,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AA0DD,wBAAsB,6BAA6B,IAAI,OAAO,CAC5D,cAAc,EAAE,CACjB,CAsBA;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CA2B3B"}
@@ -1,7 +1,8 @@
1
1
  import { readdir } from 'node:fs/promises';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { CliError } from '../errors/index.js';
4
- import { SCOPE_CONTENT_TYPES } from '../shared/types.js';
4
+ import { resolveAssetsRoot } from '../fs/assets.js';
5
+ import { SCOPE_CONTENT_TYPES, USER_SCOPE_MANAGED_AGENT_FILES, } from '../shared/types.js';
5
6
  function canonicalDirectoryName(contentType) {
6
7
  if (contentType === 'skill') {
7
8
  return 'skills';
@@ -42,6 +43,21 @@ async function readEntries(dirPath) {
42
43
  throw error;
43
44
  }
44
45
  }
46
+ export async function scanBundledManagedCodexAgents() {
47
+ const agentsDir = join(await resolveAssetsRoot(), 'agents');
48
+ const entries = await readEntries(agentsDir);
49
+ const available = new Set(entries.filter((entry) => entry.isFile).map((entry) => entry.name));
50
+ const missing = USER_SCOPE_MANAGED_AGENT_FILES.filter((name) => !available.has(name));
51
+ if (missing.length > 0) {
52
+ throw new CliError(`Bundled managed Codex role definitions are unavailable: ${missing.join(', ')}. Reinstall or rebuild OAT before running user sync.`);
53
+ }
54
+ return USER_SCOPE_MANAGED_AGENT_FILES.map((name) => ({
55
+ name,
56
+ type: 'agent',
57
+ canonicalPath: join(agentsDir, name),
58
+ isFile: true,
59
+ }));
60
+ }
45
61
  export async function scanCanonical(basePath, scope) {
46
62
  const scopeRoot = resolve(basePath);
47
63
  const entries = [];
@@ -5,5 +5,9 @@ export declare function resolveScopeRoot(scope: ConcreteScope, cwd: string, home
5
5
  export declare function toPosixPath(pathValue: string): string;
6
6
  export declare function normalizeToPosixPath(pathValue: string): string;
7
7
  export declare function validatePathWithinScope(candidatePath: string, scopeRoot: string): string;
8
+ export declare function validateRealPathWithinScope(candidatePath: string, scopeRoot: string): Promise<{
9
+ realScopeRoot: string;
10
+ realPath: string;
11
+ }>;
8
12
  export {};
9
13
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3C,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBrE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,CAcR"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3C,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBrE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,CAcR;AAED,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBtD"}
package/dist/fs/paths.js CHANGED
@@ -1,4 +1,4 @@
1
- import { access } from 'node:fs/promises';
1
+ import { access, realpath } from 'node:fs/promises';
2
2
  import { dirname, posix, resolve, sep } from 'node:path';
3
3
  import { CliError } from '../errors/index.js';
4
4
  export async function resolveProjectRoot(cwd) {
@@ -40,3 +40,20 @@ export function validatePathWithinScope(candidatePath, scopeRoot) {
40
40
  }
41
41
  return resolvedCandidatePath;
42
42
  }
43
+ export async function validateRealPathWithinScope(candidatePath, scopeRoot) {
44
+ const resolvedCandidatePath = validatePathWithinScope(candidatePath, scopeRoot);
45
+ let realScopeRoot;
46
+ let realCandidatePath;
47
+ try {
48
+ [realScopeRoot, realCandidatePath] = await Promise.all([
49
+ realpath(resolve(scopeRoot)),
50
+ realpath(resolvedCandidatePath),
51
+ ]);
52
+ }
53
+ catch (error) {
54
+ const detail = error instanceof Error ? `: ${error.message}` : '';
55
+ throw new CliError(`Unable to resolve real path for ${candidatePath} within scope root ${scopeRoot}${detail}`);
56
+ }
57
+ validatePathWithinScope(realCandidatePath, realScopeRoot);
58
+ return { realScopeRoot, realPath: realCandidatePath };
59
+ }
@@ -27,6 +27,7 @@ export type CeilingDispatchArgs = {
27
27
  } | {
28
28
  model: string;
29
29
  } | null;
30
+ export declare function isDirectDispatchRoleName(value: string): boolean;
30
31
  export interface ProviderCeilingAdapter {
31
32
  provider: string;
32
33
  supportsCeiling: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;CACV;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAET,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAK9C,CAAC;AAqGF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAE1E"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;CACV;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAKT,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAK9C,CAAC;AA4GF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAE1E"}
@@ -1,5 +1,9 @@
1
1
  import { VALID_CLAUDE_DISPATCH_CEILINGS, VALID_CODEX_DISPATCH_CEILINGS, } from '../../config/oat-config.js';
2
- import { buildCodexMaterializedRoleName } from '../codex/codec/materialize.js';
2
+ import { buildCodexMaterializedTargetRoleName } from '../codex/codec/shared.js';
3
+ const DIRECT_DISPATCH_ROLE_PATTERN = /^oat-(?:phase-implementer|reviewer)(?:-|$)/;
4
+ export function isDirectDispatchRoleName(value) {
5
+ return DIRECT_DISPATCH_ROLE_PATTERN.test(value.trim());
6
+ }
3
7
  /** Codex materialized-role base names (must match sync-extension output). */
4
8
  const CODEX_IMPLEMENTER_ROLE = 'oat-phase-implementer';
5
9
  const CODEX_REVIEWER_ROLE = 'oat-reviewer';
@@ -20,12 +24,14 @@ const codexAdapter = {
20
24
  return null;
21
25
  }
22
26
  const target = ctx.target;
23
- if (!target?.model || !target.effort) {
27
+ if (!target?.model ||
28
+ !target.effort ||
29
+ isDirectDispatchRoleName(target.model)) {
24
30
  return null;
25
31
  }
26
32
  const baseRole = role === 'reviewer' ? CODEX_REVIEWER_ROLE : CODEX_IMPLEMENTER_ROLE;
27
33
  return {
28
- variant: buildCodexMaterializedRoleName({
34
+ variant: buildCodexMaterializedTargetRoleName({
29
35
  agentName: baseRole,
30
36
  model: target.model,
31
37
  effort: target.effort,
@@ -55,7 +61,8 @@ const claudeAdapter = {
55
61
  validValues: [...VALID_CLAUDE_DISPATCH_CEILINGS],
56
62
  mechanism: 'model-arg',
57
63
  compileToDispatchArgs(value) {
58
- if (!VALID_CLAUDE_DISPATCH_CEILINGS.includes(value)) {
64
+ if (isDirectDispatchRoleName(value) ||
65
+ !VALID_CLAUDE_DISPATCH_CEILINGS.includes(value)) {
59
66
  return null;
60
67
  }
61
68
  return { model: value };
@@ -72,7 +79,7 @@ const cursorAdapter = {
72
79
  mechanism: 'model-arg',
73
80
  compileToDispatchArgs(value) {
74
81
  const model = value.trim();
75
- return model ? { model } : null;
82
+ return model && !isDirectDispatchRoleName(model) ? { model } : null;
76
83
  },
77
84
  // Cursor model slugs do not share a total order, so upgrade verification is
78
85
  // not meaningful here; availability is checked by the identity oracle layer.
@@ -0,0 +1,14 @@
1
+ export { SUPPORTED_CODEX_ROLE_TARGETS } from './shared.js';
2
+ export declare const SUPPORTED_CODEX_BASE_ROLES: readonly ["oat-phase-implementer", "oat-reviewer"];
3
+ export interface SupportedCodexRoleCatalogueEntry {
4
+ baseRole: (typeof SUPPORTED_CODEX_BASE_ROLES)[number];
5
+ model: string;
6
+ effort: string;
7
+ roleName: string;
8
+ }
9
+ export declare function isSupportedCodexRoleTarget(target: {
10
+ model: string;
11
+ effort: string;
12
+ }): boolean;
13
+ export declare function expandSupportedCodexRoleCatalogue(): SupportedCodexRoleCatalogueEntry[];
14
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAC;AAExD,eAAO,MAAM,0BAA0B,oDAG7B,CAAC;AAEX,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAKV;AAED,wBAAgB,iCAAiC,IAAI,gCAAgC,EAAE,CAYtF"}