@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
@@ -78,15 +78,6 @@ function parseCursorCatalog(stdout) {
78
78
  }
79
79
  return entries;
80
80
  }
81
- function availabilityFromCursorCatalog(value, stdout) {
82
- const entries = parseCursorCatalog(stdout);
83
- if (entries.length === 0) {
84
- return null;
85
- }
86
- return entries.some((entry) => entry.slug === value)
87
- ? 'valid'
88
- : 'unknown-value';
89
- }
90
81
  const CURSOR_SUBAGENT_PROBE_SENTINEL = 'OAT_CURSOR_SUBAGENT_MODEL_VALID';
91
82
  function hasCursorSubagentProbeSentinel(stdout) {
92
83
  return stdout
@@ -150,6 +141,20 @@ function cursorCatalogContextMessage(value, availability) {
150
141
  }
151
142
  return undefined;
152
143
  }
144
+ function availabilityDependencies(options) {
145
+ return {
146
+ ...DEFAULT_DEPENDENCIES,
147
+ env: options.env ?? DEFAULT_DEPENDENCIES.env,
148
+ ...options.dependencies,
149
+ };
150
+ }
151
+ function cursorCatalogDiagnostic(results) {
152
+ const messages = unique(results
153
+ .flatMap((result) => [result.stderr, result.stdout])
154
+ .map((message) => message.trim())
155
+ .filter((message) => message.length > 0));
156
+ return messages.length > 0 ? messages.join('\n') : null;
157
+ }
153
158
  function isRecord(value) {
154
159
  return typeof value === 'object' && value !== null && !Array.isArray(value);
155
160
  }
@@ -271,18 +276,18 @@ async function validateCodexCell(value, cwd, dependencies, target) {
271
276
  }
272
277
  return { availability: 'valid' };
273
278
  }
274
- export async function validateCursorSubagentModel(value, options) {
275
- const dependencies = {
276
- ...DEFAULT_DEPENDENCIES,
277
- env: options.env ?? DEFAULT_DEPENDENCIES.env,
278
- ...options.dependencies,
279
- };
279
+ export async function probeCursorSubagentModel(value, options) {
280
+ const dependencies = availabilityDependencies(options);
280
281
  const env = dependencies.env ?? process.env;
281
282
  const runOptions = { cwd: options.cwd, env };
282
283
  const probeResult = await dependencies.runCursorAgent(cursorSubagentProbeArgs(value, env), runOptions);
283
284
  const probeOutput = `${probeResult.stdout}\n${probeResult.stderr}`;
284
285
  if (probeResult.ok && hasCursorSubagentProbeSentinel(probeResult.stdout)) {
285
- return { availability: 'valid' };
286
+ return {
287
+ availability: 'valid',
288
+ decisive: true,
289
+ evidence: 'task-probe',
290
+ };
286
291
  }
287
292
  const allowedValues = parseCursorAllowedSubagentModels(probeOutput);
288
293
  if (allowedValues.length > 0) {
@@ -295,28 +300,70 @@ export async function validateCursorSubagentModel(value, options) {
295
300
  message: availability === 'valid'
296
301
  ? cursorAllowedModelsMessage(allowedValues)
297
302
  : cursorRejectedMessage(allowedValues),
303
+ decisive: true,
304
+ evidence: 'subagent-allow-list',
298
305
  };
299
306
  }
307
+ return {
308
+ availability: 'unvalidated',
309
+ decisive: false,
310
+ evidence: 'none',
311
+ };
312
+ }
313
+ export async function resolveCursorModelCatalog(options) {
314
+ const dependencies = availabilityDependencies(options);
315
+ const env = dependencies.env ?? process.env;
316
+ const runOptions = { cwd: options.cwd, env };
317
+ const attempts = [];
300
318
  const modelsResult = await dependencies.runCursorAgent([...apiKeyArgs(env), 'models'], runOptions);
319
+ attempts.push(modelsResult);
301
320
  if (modelsResult.ok) {
302
- const availability = availabilityFromCursorCatalog(value, modelsResult.stdout);
303
- if (availability !== null) {
321
+ const candidates = parseCursorCatalog(modelsResult.stdout).map((entry) => entry.slug);
322
+ if (candidates.length > 0) {
304
323
  return {
305
- availability: availability === 'valid' ? 'unvalidated' : 'unknown-value',
306
- message: cursorCatalogContextMessage(value, availability),
324
+ status: 'resolved',
325
+ candidates,
326
+ sourceCommand: 'models',
327
+ diagnostic: null,
307
328
  };
308
329
  }
309
330
  }
310
331
  const listResult = await dependencies.runCursorAgent([...apiKeyArgs(env), '--list-models'], runOptions);
332
+ attempts.push(listResult);
311
333
  if (listResult.ok) {
312
- const availability = availabilityFromCursorCatalog(value, listResult.stdout);
313
- if (availability !== null) {
334
+ const candidates = parseCursorCatalog(listResult.stdout).map((entry) => entry.slug);
335
+ if (candidates.length > 0) {
314
336
  return {
315
- availability: availability === 'valid' ? 'unvalidated' : 'unknown-value',
316
- message: cursorCatalogContextMessage(value, availability),
337
+ status: 'resolved',
338
+ candidates,
339
+ sourceCommand: 'list-models',
340
+ diagnostic: null,
317
341
  };
318
342
  }
319
343
  }
344
+ return {
345
+ status: attempts.every((result) => !result.ok) ? 'unavailable' : 'failed',
346
+ candidates: [],
347
+ sourceCommand: null,
348
+ diagnostic: cursorCatalogDiagnostic(attempts),
349
+ };
350
+ }
351
+ export async function validateCursorSubagentModel(value, options) {
352
+ const taskProbe = await probeCursorSubagentModel(value, options);
353
+ if (taskProbe.decisive) {
354
+ const { decisive: _decisive, evidence: _evidence, ...result } = taskProbe;
355
+ return result;
356
+ }
357
+ const catalog = await resolveCursorModelCatalog(options);
358
+ if (catalog.status === 'resolved') {
359
+ const availability = catalog.candidates.includes(value)
360
+ ? 'valid'
361
+ : 'unknown-value';
362
+ return {
363
+ availability: availability === 'valid' ? 'unvalidated' : 'unknown-value',
364
+ message: cursorCatalogContextMessage(value, availability),
365
+ };
366
+ }
320
367
  return { availability: 'unvalidated' };
321
368
  }
322
369
  export async function validateMatrixCell(provider, value, options) {
@@ -327,11 +374,7 @@ export async function validateMatrixCell(provider, value, options) {
327
374
  ? { availability: 'unknown-value' }
328
375
  : 'unknown-value';
329
376
  }
330
- const dependencies = {
331
- ...DEFAULT_DEPENDENCIES,
332
- env: options.env ?? DEFAULT_DEPENDENCIES.env,
333
- ...options.dependencies,
334
- };
377
+ const dependencies = availabilityDependencies(options);
335
378
  if (normalizedProvider === 'claude') {
336
379
  const availability = VALID_CLAUDE_DISPATCH_CEILINGS.includes(normalizedValue)
337
380
  ? 'valid'
@@ -0,0 +1,124 @@
1
+ import type { WorkflowDispatchMatrixTier } from '../../config/dispatch-matrix.js';
2
+ import type { IdentityProvenance } from './provenance.js';
3
+ import type { DispatchAction, DispatchRole, DispatchStampRecord } from './stamp.js';
4
+ export type DispatchReportPolicyStatus = 'resolved' | 'unresolved' | 'blocked';
5
+ export type DispatchReportPolicyMode = 'managed' | 'inherit' | null;
6
+ export interface ResolvedDispatchTargetReport {
7
+ harness: string;
8
+ model?: string;
9
+ effort?: string;
10
+ crossHarness: boolean;
11
+ routeIndex: number;
12
+ routeLength: number;
13
+ }
14
+ export interface DispatchControlRequest {
15
+ value: string | null;
16
+ mechanism: 'task-model-argument' | 'materialized-role' | 'base-role' | 'provider-default' | 'host-inherited' | 'not-applicable';
17
+ reason: string;
18
+ }
19
+ export interface DispatchRequestedControls {
20
+ model: DispatchControlRequest;
21
+ effort: DispatchControlRequest;
22
+ }
23
+ export interface DispatchConfiguredDefaults {
24
+ model: string | null;
25
+ modelSource: string | null;
26
+ effort: string | null;
27
+ effortSource: string | null;
28
+ }
29
+ export interface DispatchGateInvocation {
30
+ readonly runId: string;
31
+ readonly targetId: string;
32
+ readonly runtime: string;
33
+ readonly model: string;
34
+ readonly reasoningEffort: string;
35
+ readonly source: 'exec-target-config' | 'unknown';
36
+ }
37
+ export interface DispatchRuntimeIdentity {
38
+ producer: string | null;
39
+ model: string | null;
40
+ effort: string | null;
41
+ provenance: IdentityProvenance;
42
+ confidence: string;
43
+ }
44
+ export interface DispatchReportSelectionInput {
45
+ role: DispatchRole;
46
+ requestedCandidate: {
47
+ model: string;
48
+ effort?: string;
49
+ } | null;
50
+ candidateTier: WorkflowDispatchMatrixTier | null;
51
+ candidateIndex: number | null;
52
+ ceilingTier: WorkflowDispatchMatrixTier | null;
53
+ ceilingTarget: ResolvedDispatchTargetReport | null;
54
+ selectedValue: string | null;
55
+ selectionMode: string;
56
+ selectionBranch: string;
57
+ target: ResolvedDispatchTargetReport | null;
58
+ cellSource: string | null;
59
+ }
60
+ export interface DispatchReportProviderResolution {
61
+ dispatchArgs: {
62
+ variant?: string;
63
+ model?: string;
64
+ } | null;
65
+ selection: DispatchReportSelectionInput;
66
+ }
67
+ export interface DispatchReportResolution {
68
+ status: DispatchReportPolicyStatus;
69
+ provider: string;
70
+ value: string | null;
71
+ policyMode: DispatchReportPolicyMode;
72
+ policy: string | null;
73
+ source: string | null;
74
+ providers: Record<string, DispatchReportProviderResolution>;
75
+ }
76
+ export interface DispatchReportV1 {
77
+ schemaVersion: 1;
78
+ route: {
79
+ scope: string;
80
+ action: DispatchAction;
81
+ role: DispatchRole;
82
+ target: string;
83
+ };
84
+ policy: {
85
+ status: DispatchReportPolicyStatus;
86
+ mode: DispatchReportPolicyMode;
87
+ name: string | null;
88
+ source: string | null;
89
+ };
90
+ selection: {
91
+ requestedCandidate: {
92
+ model: string;
93
+ effort?: string;
94
+ } | null;
95
+ candidateTier: WorkflowDispatchMatrixTier | null;
96
+ candidateIndex: number | null;
97
+ ceilingTier: WorkflowDispatchMatrixTier | null;
98
+ ceilingTarget: ResolvedDispatchTargetReport | null;
99
+ selectedValue: string | null;
100
+ exactSelectedTarget: ResolvedDispatchTargetReport | null;
101
+ selectionMode: string;
102
+ selectionBranch: string;
103
+ cellSource: string | null;
104
+ };
105
+ requestedControls: DispatchRequestedControls;
106
+ configuredDefaults: DispatchConfiguredDefaults;
107
+ gateInvocation: Readonly<DispatchGateInvocation> | null;
108
+ runtimeIdentity: DispatchRuntimeIdentity;
109
+ }
110
+ export interface DispatchReportInput {
111
+ scope: string;
112
+ action: DispatchAction;
113
+ role: DispatchRole;
114
+ resolution: DispatchReportResolution;
115
+ requestedControls: DispatchRequestedControls;
116
+ configuredDefaults: DispatchConfiguredDefaults;
117
+ gateInvocation?: DispatchGateInvocation | null;
118
+ runtimeIdentity?: DispatchRuntimeIdentity;
119
+ }
120
+ export declare function buildDispatchReport(input: DispatchReportInput): DispatchReportV1;
121
+ export declare function serializeDispatchReport(report: DispatchReportV1): string;
122
+ export declare function formatDispatchReport(report: DispatchReportV1): string;
123
+ export declare function toDispatchStampRecord(report: DispatchReportV1): DispatchStampRecord;
124
+ //# sourceMappingURL=dispatch-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-report.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/dispatch-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,285 @@
1
+ const ROLE_BY_ACTION = {
2
+ implementation: 'implementer',
3
+ fix: 'fix',
4
+ review: 'reviewer',
5
+ };
6
+ const NOT_REPORTED_RUNTIME_IDENTITY = {
7
+ producer: null,
8
+ model: null,
9
+ effort: null,
10
+ provenance: 'unknown',
11
+ confidence: 'not-reported',
12
+ };
13
+ function cloneTarget(target) {
14
+ return target ? { ...target } : null;
15
+ }
16
+ function invocationTarget(provider) {
17
+ return (provider.dispatchArgs?.variant ?? provider.dispatchArgs?.model ?? 'unknown');
18
+ }
19
+ function assertActionRole(action, role) {
20
+ if (ROLE_BY_ACTION[action] !== role) {
21
+ throw new Error(`Invalid dispatch report action/role pair: ${action}/${role}`);
22
+ }
23
+ }
24
+ function orderedTarget(target) {
25
+ if (!target) {
26
+ return null;
27
+ }
28
+ return {
29
+ harness: target.harness,
30
+ ...(target.model === undefined ? {} : { model: target.model }),
31
+ ...(target.effort === undefined ? {} : { effort: target.effort }),
32
+ crossHarness: target.crossHarness,
33
+ routeIndex: target.routeIndex,
34
+ routeLength: target.routeLength,
35
+ };
36
+ }
37
+ function orderedReport(report) {
38
+ return {
39
+ schemaVersion: 1,
40
+ route: {
41
+ scope: report.route.scope,
42
+ action: report.route.action,
43
+ role: report.route.role,
44
+ target: report.route.target,
45
+ },
46
+ policy: {
47
+ status: report.policy.status,
48
+ mode: report.policy.mode,
49
+ name: report.policy.name,
50
+ source: report.policy.source,
51
+ },
52
+ selection: {
53
+ requestedCandidate: report.selection.requestedCandidate
54
+ ? {
55
+ model: report.selection.requestedCandidate.model,
56
+ ...(report.selection.requestedCandidate.effort === undefined
57
+ ? {}
58
+ : { effort: report.selection.requestedCandidate.effort }),
59
+ }
60
+ : null,
61
+ candidateTier: report.selection.candidateTier,
62
+ candidateIndex: report.selection.candidateIndex,
63
+ ceilingTier: report.selection.ceilingTier,
64
+ ceilingTarget: orderedTarget(report.selection.ceilingTarget),
65
+ selectedValue: report.selection.selectedValue,
66
+ exactSelectedTarget: orderedTarget(report.selection.exactSelectedTarget),
67
+ selectionMode: report.selection.selectionMode,
68
+ selectionBranch: report.selection.selectionBranch,
69
+ cellSource: report.selection.cellSource,
70
+ },
71
+ requestedControls: {
72
+ model: {
73
+ value: report.requestedControls.model.value,
74
+ mechanism: report.requestedControls.model.mechanism,
75
+ reason: report.requestedControls.model.reason,
76
+ },
77
+ effort: {
78
+ value: report.requestedControls.effort.value,
79
+ mechanism: report.requestedControls.effort.mechanism,
80
+ reason: report.requestedControls.effort.reason,
81
+ },
82
+ },
83
+ configuredDefaults: {
84
+ model: report.configuredDefaults.model,
85
+ modelSource: report.configuredDefaults.modelSource,
86
+ effort: report.configuredDefaults.effort,
87
+ effortSource: report.configuredDefaults.effortSource,
88
+ },
89
+ gateInvocation: report.gateInvocation
90
+ ? {
91
+ runId: report.gateInvocation.runId,
92
+ targetId: report.gateInvocation.targetId,
93
+ runtime: report.gateInvocation.runtime,
94
+ model: report.gateInvocation.model,
95
+ reasoningEffort: report.gateInvocation.reasoningEffort,
96
+ source: report.gateInvocation.source,
97
+ }
98
+ : null,
99
+ runtimeIdentity: {
100
+ producer: report.runtimeIdentity.producer,
101
+ model: report.runtimeIdentity.model,
102
+ effort: report.runtimeIdentity.effort,
103
+ provenance: report.runtimeIdentity.provenance,
104
+ confidence: report.runtimeIdentity.confidence,
105
+ },
106
+ };
107
+ }
108
+ function display(value) {
109
+ return value === null ? 'none' : String(value);
110
+ }
111
+ function formatTarget(target) {
112
+ if (!target) {
113
+ return 'none';
114
+ }
115
+ return [
116
+ `harness=${target.harness}`,
117
+ target.model === undefined ? null : `model=${target.model}`,
118
+ target.effort === undefined ? null : `effort=${target.effort}`,
119
+ `crossHarness=${String(target.crossHarness)}`,
120
+ `routeIndex=${target.routeIndex}`,
121
+ `routeLength=${target.routeLength}`,
122
+ ]
123
+ .filter((part) => part !== null)
124
+ .join(' ');
125
+ }
126
+ function formatCandidate(candidate) {
127
+ if (!candidate) {
128
+ return 'none';
129
+ }
130
+ return [
131
+ `model=${candidate.model}`,
132
+ candidate.effort === undefined ? null : `effort=${candidate.effort}`,
133
+ ]
134
+ .filter((part) => part !== null)
135
+ .join(' ');
136
+ }
137
+ function formatControl(name, control) {
138
+ return ` ${name}: ${display(control.value)} (${control.mechanism}) — ${control.reason}`;
139
+ }
140
+ function controlAxis(control) {
141
+ if (control.mechanism === 'task-model-argument' ||
142
+ control.mechanism === 'materialized-role') {
143
+ return control.value ? `selected:${control.value}` : 'unknown';
144
+ }
145
+ if (control.mechanism === 'host-inherited') {
146
+ return 'inherited';
147
+ }
148
+ if (control.mechanism === 'base-role' ||
149
+ control.mechanism === 'provider-default') {
150
+ return 'provider-default';
151
+ }
152
+ return 'not-applicable';
153
+ }
154
+ function dispatchPolicy(report) {
155
+ if (report.policy.name) {
156
+ return report.policy.name;
157
+ }
158
+ return report.policy.mode === 'inherit' ? 'inherit-host-defaults' : 'unknown';
159
+ }
160
+ function dispatchCeiling(report) {
161
+ return (report.selection.ceilingTarget?.effort ??
162
+ report.selection.ceilingTarget?.model ??
163
+ 'none');
164
+ }
165
+ export function buildDispatchReport(input) {
166
+ assertActionRole(input.action, input.role);
167
+ const provider = input.resolution.providers[input.resolution.provider];
168
+ if (!provider) {
169
+ throw new Error(`Dispatch report resolution is missing provider data for "${input.resolution.provider}".`);
170
+ }
171
+ const { selection } = provider;
172
+ const gateInvocation = input.gateInvocation
173
+ ? Object.freeze({ ...input.gateInvocation })
174
+ : null;
175
+ return {
176
+ schemaVersion: 1,
177
+ route: {
178
+ scope: input.scope,
179
+ action: input.action,
180
+ role: input.role,
181
+ target: invocationTarget(provider),
182
+ },
183
+ policy: {
184
+ status: input.resolution.status,
185
+ mode: input.resolution.policyMode,
186
+ name: input.resolution.policy,
187
+ source: input.resolution.source,
188
+ },
189
+ selection: {
190
+ requestedCandidate: selection.requestedCandidate
191
+ ? { ...selection.requestedCandidate }
192
+ : null,
193
+ candidateTier: selection.candidateTier,
194
+ candidateIndex: selection.candidateIndex,
195
+ ceilingTier: selection.ceilingTier,
196
+ ceilingTarget: cloneTarget(selection.ceilingTarget),
197
+ selectedValue: selection.selectedValue,
198
+ exactSelectedTarget: cloneTarget(selection.target),
199
+ selectionMode: selection.selectionMode,
200
+ selectionBranch: selection.selectionBranch,
201
+ cellSource: selection.cellSource,
202
+ },
203
+ requestedControls: {
204
+ model: { ...input.requestedControls.model },
205
+ effort: { ...input.requestedControls.effort },
206
+ },
207
+ configuredDefaults: { ...input.configuredDefaults },
208
+ gateInvocation,
209
+ runtimeIdentity: input.runtimeIdentity
210
+ ? { ...input.runtimeIdentity }
211
+ : { ...NOT_REPORTED_RUNTIME_IDENTITY },
212
+ };
213
+ }
214
+ export function serializeDispatchReport(report) {
215
+ return JSON.stringify(orderedReport(report), null, 2);
216
+ }
217
+ export function formatDispatchReport(report) {
218
+ const runtimeNotReported = report.runtimeIdentity.producer === null &&
219
+ report.runtimeIdentity.model === null &&
220
+ report.runtimeIdentity.effort === null &&
221
+ report.runtimeIdentity.confidence === 'not-reported';
222
+ const runtimeValue = (value) => value === null ? 'not reported' : value;
223
+ const gateLines = report.gateInvocation
224
+ ? [
225
+ ` Run ID: ${report.gateInvocation.runId}`,
226
+ ` Target ID: ${report.gateInvocation.targetId}`,
227
+ ` Runtime: ${report.gateInvocation.runtime}`,
228
+ ` Model: ${report.gateInvocation.model}`,
229
+ ` Reasoning effort: ${report.gateInvocation.reasoningEffort}`,
230
+ ` Source: ${report.gateInvocation.source}`,
231
+ ]
232
+ : [' Not configured'];
233
+ return [
234
+ 'Dispatch Report V1',
235
+ 'Route',
236
+ ` Scope: ${report.route.scope}`,
237
+ ` Action / role: ${report.route.action} / ${report.route.role}`,
238
+ ` Invocation target: ${report.route.target}`,
239
+ 'Policy',
240
+ ` Status: ${report.policy.status}`,
241
+ ` Mode / name: ${display(report.policy.mode)} / ${display(report.policy.name)}`,
242
+ ` Source: ${display(report.policy.source)}`,
243
+ 'Selection',
244
+ ` Requested candidate: ${formatCandidate(report.selection.requestedCandidate)}`,
245
+ ` Candidate tier / index: ${display(report.selection.candidateTier)} / ${display(report.selection.candidateIndex)}`,
246
+ ` Ceiling tier: ${display(report.selection.ceilingTier)}`,
247
+ ` Ceiling target: ${formatTarget(report.selection.ceilingTarget)}`,
248
+ ` Selected value: ${display(report.selection.selectedValue)}`,
249
+ ` Exact selected target: ${formatTarget(report.selection.exactSelectedTarget)}`,
250
+ ` Mode / branch: ${report.selection.selectionMode} / ${report.selection.selectionBranch}`,
251
+ ` Cell source: ${display(report.selection.cellSource)}`,
252
+ 'Requested controls',
253
+ formatControl('Model', report.requestedControls.model),
254
+ formatControl('Effort', report.requestedControls.effort),
255
+ 'Configured defaults (not runtime observations)',
256
+ ` Model: ${display(report.configuredDefaults.model)}`,
257
+ ` Model source: ${display(report.configuredDefaults.modelSource)}`,
258
+ ` Effort: ${display(report.configuredDefaults.effort)}`,
259
+ ` Effort source: ${display(report.configuredDefaults.effortSource)}`,
260
+ 'Gate invocation (configured, immutable)',
261
+ ...gateLines,
262
+ 'Runtime identity (observed/reported separately)',
263
+ ...(runtimeNotReported ? [' Runtime identity was not reported.'] : []),
264
+ ` Producer: ${runtimeValue(report.runtimeIdentity.producer)}`,
265
+ ` Model: ${runtimeValue(report.runtimeIdentity.model)}`,
266
+ ` Effort: ${runtimeValue(report.runtimeIdentity.effort)}`,
267
+ ` Provenance: ${report.runtimeIdentity.provenance}`,
268
+ ` Confidence: ${report.runtimeIdentity.confidence}`,
269
+ ].join('\n');
270
+ }
271
+ export function toDispatchStampRecord(report) {
272
+ const runtimeReported = report.runtimeIdentity.producer !== null;
273
+ return {
274
+ scope: report.route.scope,
275
+ action: report.route.action,
276
+ role: report.route.role,
277
+ producer: report.runtimeIdentity.producer ?? 'unknown',
278
+ provenance: runtimeReported ? report.runtimeIdentity.provenance : 'unknown',
279
+ modelAxis: controlAxis(report.requestedControls.model),
280
+ effortAxis: controlAxis(report.requestedControls.effort),
281
+ dispatchPolicy: dispatchPolicy(report),
282
+ dispatchCeiling: dispatchCeiling(report),
283
+ target: report.route.target,
284
+ };
285
+ }
@@ -0,0 +1,28 @@
1
+ import type { DispatchMatrixCellRef } from '../../config/dispatch-matrix.js';
2
+ import { probeCursorSubagentModel, resolveCursorModelCatalog, validateMatrixCell, type CursorCatalogResult, type CursorTaskProbeResult, type MatrixCellAvailability, type ValidateMatrixCellOptions } from './availability.js';
3
+ export type DispatchValidationEvidence = 'task-probe' | 'subagent-allow-list' | 'catalog-only' | 'none';
4
+ export interface DispatchMatrixValidationResult {
5
+ ref: DispatchMatrixCellRef;
6
+ status: MatrixCellAvailability;
7
+ evidence: DispatchValidationEvidence;
8
+ catalogPresence: boolean | null;
9
+ diagnostic: string;
10
+ }
11
+ export interface DispatchValidationPassOptions extends Omit<ValidateMatrixCellOptions, 'detailed' | 'target'> {
12
+ validateMatrixCell?: typeof validateMatrixCell;
13
+ probeCursorSubagentModel?: typeof probeCursorSubagentModel;
14
+ resolveCursorModelCatalog?: typeof resolveCursorModelCatalog;
15
+ }
16
+ interface MemoizedCursorTaskProbe {
17
+ result: CursorTaskProbeResult;
18
+ diagnostic: string;
19
+ }
20
+ export interface DispatchValidationPassContext {
21
+ cursorCatalog: Promise<CursorCatalogResult> | null;
22
+ cursorTaskProbes: Map<string, Promise<MemoizedCursorTaskProbe>>;
23
+ options: DispatchValidationPassOptions;
24
+ }
25
+ export declare function createDispatchValidationPassContext(options?: DispatchValidationPassOptions): DispatchValidationPassContext;
26
+ export declare function validateDispatchMatrixRefs(refs: DispatchMatrixCellRef[], context: DispatchValidationPassContext): Promise<DispatchMatrixValidationResult[]>;
27
+ export {};
28
+ //# sourceMappingURL=dispatch-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-validation.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/dispatch-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,OAAO,EAEL,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC/B,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,0BAA0B,GAClC,YAAY,GACZ,qBAAqB,GACrB,cAAc,GACd,MAAM,CAAC;AAEX,MAAM,WAAW,8BAA8B;IAC7C,GAAG,EAAE,qBAAqB,CAAC;IAC3B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,QAAQ,EAAE,0BAA0B,CAAC;IACrC,eAAe,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CACzD,yBAAyB,EACzB,UAAU,GAAG,QAAQ,CACtB;IACC,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,wBAAwB,CAAC,EAAE,OAAO,wBAAwB,CAAC;IAC3D,yBAAyB,CAAC,EAAE,OAAO,yBAAyB,CAAC;CAC9D;AAED,UAAU,uBAAuB;IAC/B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,6BAA6B;IAC5C,aAAa,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC;IACnD,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAChE,OAAO,EAAE,6BAA6B,CAAC;CACxC;AAiMD,wBAAgB,mCAAmC,CACjD,OAAO,GAAE,6BAAsD,GAC9D,6BAA6B,CAM/B;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,qBAAqB,EAAE,EAC7B,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,8BAA8B,EAAE,CAAC,CAE3C"}