@open-agent-toolkit/cli 0.1.43 → 0.1.45

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 (47) hide show
  1. package/assets/config/dispatch-matrix-recommendation.json +23 -0
  2. package/assets/docs/cli-utilities/configuration.md +59 -20
  3. package/assets/docs/cli-utilities/workflow-gates.md +79 -16
  4. package/assets/docs/contributing/code.md +10 -4
  5. package/assets/docs/contributing/hooks-and-safety.md +23 -0
  6. package/assets/docs/workflows/projects/dispatch-ceiling.md +80 -10
  7. package/assets/public-package-versions.json +4 -4
  8. package/assets/skills/oat-project-implement/SKILL.md +53 -11
  9. package/assets/skills/oat-project-plan/SKILL.md +22 -3
  10. package/assets/skills/oat-project-quick-start/SKILL.md +22 -3
  11. package/assets/templates/state.md +5 -0
  12. package/dist/commands/config/index.d.ts +6 -0
  13. package/dist/commands/config/index.d.ts.map +1 -1
  14. package/dist/commands/config/index.js +366 -8
  15. package/dist/commands/doctor/index.d.ts +6 -1
  16. package/dist/commands/doctor/index.d.ts.map +1 -1
  17. package/dist/commands/doctor/index.js +138 -4
  18. package/dist/commands/gate/index.d.ts +39 -2
  19. package/dist/commands/gate/index.d.ts.map +1 -1
  20. package/dist/commands/gate/index.js +343 -30
  21. package/dist/commands/internal/cursor-current-target.d.ts +37 -0
  22. package/dist/commands/internal/cursor-current-target.d.ts.map +1 -0
  23. package/dist/commands/internal/cursor-current-target.js +228 -0
  24. package/dist/commands/internal/index.d.ts.map +1 -1
  25. package/dist/commands/internal/index.js +2 -0
  26. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  27. package/dist/commands/project/dispatch-ceiling/index.js +359 -16
  28. package/dist/config/oat-config.d.ts +15 -5
  29. package/dist/config/oat-config.d.ts.map +1 -1
  30. package/dist/config/oat-config.js +103 -10
  31. package/dist/config/resolve.js +12 -0
  32. package/dist/manifest/manifest.types.d.ts +12 -12
  33. package/dist/providers/ceiling/registry.d.ts.map +1 -1
  34. package/dist/providers/ceiling/registry.js +16 -0
  35. package/dist/providers/identity/availability.d.ts +22 -0
  36. package/dist/providers/identity/availability.d.ts.map +1 -0
  37. package/dist/providers/identity/availability.js +119 -0
  38. package/dist/providers/identity/family.d.ts +13 -0
  39. package/dist/providers/identity/family.d.ts.map +1 -0
  40. package/dist/providers/identity/family.js +32 -0
  41. package/dist/providers/identity/provenance.d.ts +21 -0
  42. package/dist/providers/identity/provenance.d.ts.map +1 -0
  43. package/dist/providers/identity/provenance.js +65 -0
  44. package/dist/providers/identity/stamp.d.ts +35 -0
  45. package/dist/providers/identity/stamp.d.ts.map +1 -0
  46. package/dist/providers/identity/stamp.js +171 -0
  47. package/package.json +2 -2
@@ -1,6 +1,8 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
2
2
  import { type ExecTarget, type OatConfig, type OatLocalConfig, type UserConfig } from '../../config/oat-config.js';
3
3
  import { type ResolvedConfig } from '../../config/resolve.js';
4
+ import { type ModelFamily } from '../../providers/identity/family.js';
5
+ import { type IdentityConfidence, type IdentityProvenance } from '../../providers/identity/provenance.js';
4
6
  import { Command } from 'commander';
5
7
  interface GateCommandDependencies {
6
8
  buildCommandContext: (options: GlobalOptions) => CommandContext;
@@ -20,16 +22,51 @@ interface ProcessRunOptions {
20
22
  env: NodeJS.ProcessEnv;
21
23
  purpose: 'host-detection' | 'availability' | 'execute';
22
24
  stdio: 'ignore' | 'inherit';
25
+ timeoutMs: number;
23
26
  }
24
27
  interface ProcessRunResult {
25
28
  exitCode: number;
29
+ timedOut?: boolean;
26
30
  }
27
- type CrossProviderAvoid = 'same-runtime' | 'none';
31
+ type CrossProviderAvoid = 'same-family' | 'same-runtime' | 'none';
32
+ type GateDiversityAchieved = 'different-family' | 'degraded-to-different-slug' | 'same-family - no diverse target available' | 'unknown-producer';
28
33
  export interface SelectedExecTarget {
29
34
  id: string;
30
35
  target: ExecTarget;
36
+ model?: string;
37
+ family: ModelFamily;
38
+ diversity?: GateDiversityMetadata;
39
+ noDiverseFamilyFallback?: boolean;
31
40
  }
32
- export declare function selectExecTarget(registry: Readonly<Record<string, ExecTarget>>, currentRuntime: string, avoid: CrossProviderAvoid): SelectedExecTarget | null;
41
+ interface GateProducerIdentity {
42
+ value: string;
43
+ provenance: IdentityProvenance;
44
+ confidence: IdentityConfidence;
45
+ family: ModelFamily;
46
+ avoidFamilies: ModelFamily[];
47
+ diversityClaimable: boolean;
48
+ source: 'flag' | 'stamp' | 'unknown';
49
+ }
50
+ interface GateDiversityMetadata {
51
+ avoid: CrossProviderAvoid;
52
+ achieved: GateDiversityAchieved;
53
+ producer: {
54
+ value: string;
55
+ provenance: IdentityProvenance;
56
+ confidence: IdentityConfidence;
57
+ family: ModelFamily;
58
+ source: GateProducerIdentity['source'];
59
+ avoidFamilies: ModelFamily[];
60
+ };
61
+ reviewer: {
62
+ target: string;
63
+ runtime: string;
64
+ family: ModelFamily;
65
+ model?: string;
66
+ };
67
+ warning?: string;
68
+ }
69
+ export declare function selectExecTarget(registry: Readonly<Record<string, ExecTarget>>, currentRuntime: string, avoid: CrossProviderAvoid, producerIdentity?: GateProducerIdentity): SelectedExecTarget | null;
33
70
  export declare function createGateCommand(overrides?: Partial<GateCommandDependencies>): Command;
34
71
  export {};
35
72
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAQL,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,CACV,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA0CD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACvD,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,kBAAkB,GAAG,cAAc,GAAG,MAAM,CAAC;AAMlD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAyZD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAC9C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,GAAG,IAAI,CAE3B;AAu7BD,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwKT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,9 @@ import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig
9
9
  import { resolveEffectiveConfig, resolveExecTargets, resolveGate, } from '../../config/resolve.js';
10
10
  import { dirExists, fileExists } from '../../fs/io.js';
11
11
  import { normalizeToPosixPath, resolveProjectRoot } from '../../fs/paths.js';
12
+ import { classifyModelFamily, } from '../../providers/identity/family.js';
13
+ import { resolveIdentityConfidence, } from '../../providers/identity/provenance.js';
14
+ import { parseDispatchStamps } from '../../providers/identity/stamp.js';
12
15
  import { Command } from 'commander';
13
16
  import { parseReviewGateVerdict, severityDisplayName, } from './review-verdict.js';
14
17
  const DEFAULT_DEPENDENCIES = {
@@ -31,6 +34,7 @@ const VALID_WRITE_LAYERS = [
31
34
  'user',
32
35
  ];
33
36
  const VALID_CROSS_PROVIDER_AVOIDS = [
37
+ 'same-family',
34
38
  'same-runtime',
35
39
  'none',
36
40
  ];
@@ -40,7 +44,15 @@ const VALID_REVIEW_GATE_THRESHOLDS = [
40
44
  'medium',
41
45
  'minor',
42
46
  ];
47
+ const VALID_IDENTITY_PROVENANCES = [
48
+ 'declared',
49
+ 'observed',
50
+ 'inferred',
51
+ 'unknown',
52
+ ];
43
53
  const REVIEW_GATE_CONTEXT_NOTE = 'This review is gate-originated. If you run `oat-project-review-provide`, set `oat_review_invocation: gate` in the review artifact. Write a canonical review artifact with `### Critical`, `### Important`, `### Medium`, and `### Minor` headings in that order, using `None` for empty sections.';
54
+ const GATE_CHECK_TIMEOUT_MS = 5_000;
55
+ const GATE_EXEC_TIMEOUT_MS = 10 * 60 * 1_000;
44
56
  function reviewGateProjectContext(projectPath) {
45
57
  return `Resolved OAT project path: ${projectPath}. Run the review for this project path.`;
46
58
  }
@@ -52,14 +64,38 @@ function assembleReviewGatePrompt(segments) {
52
64
  }
53
65
  async function runChildProcess(command, args, options) {
54
66
  return new Promise((resolve, reject) => {
67
+ let timedOut = false;
68
+ let killTimeout = null;
55
69
  const child = spawn(command, args, {
56
70
  cwd: options.cwd,
57
71
  env: options.env,
58
72
  stdio: options.stdio,
59
73
  });
60
- child.on('error', reject);
74
+ const timeout = setTimeout(() => {
75
+ timedOut = true;
76
+ child.kill('SIGTERM');
77
+ killTimeout = setTimeout(() => {
78
+ child.kill('SIGKILL');
79
+ }, 5_000);
80
+ killTimeout.unref();
81
+ }, options.timeoutMs);
82
+ timeout.unref();
83
+ child.on('error', (error) => {
84
+ clearTimeout(timeout);
85
+ if (killTimeout) {
86
+ clearTimeout(killTimeout);
87
+ }
88
+ reject(error);
89
+ });
61
90
  child.on('close', (code) => {
62
- resolve({ exitCode: code ?? 1 });
91
+ clearTimeout(timeout);
92
+ if (killTimeout) {
93
+ clearTimeout(killTimeout);
94
+ }
95
+ resolve({
96
+ exitCode: timedOut ? 124 : (code ?? 1),
97
+ ...(timedOut ? { timedOut: true } : {}),
98
+ });
63
99
  });
64
100
  });
65
101
  }
@@ -105,9 +141,9 @@ function parseLayer(value) {
105
141
  return layer;
106
142
  }
107
143
  function parseCrossProviderAvoid(value) {
108
- const avoid = value?.trim() || 'same-runtime';
144
+ const avoid = value?.trim() || 'same-family';
109
145
  if (!VALID_CROSS_PROVIDER_AVOIDS.includes(avoid)) {
110
- throw new Error('--avoid must be one of same-runtime | none.');
146
+ throw new Error('--avoid must be one of same-family | same-runtime | none.');
111
147
  }
112
148
  return avoid;
113
149
  }
@@ -144,6 +180,17 @@ function parseNumericFlag(value, flag, defaultValue) {
144
180
  }
145
181
  return parsed;
146
182
  }
183
+ function resolveGateExecTimeoutMs(env) {
184
+ const rawValue = env.OAT_GATE_EXEC_TIMEOUT_MS?.trim();
185
+ if (!rawValue) {
186
+ return GATE_EXEC_TIMEOUT_MS;
187
+ }
188
+ const parsed = Number(rawValue);
189
+ if (!Number.isInteger(parsed) || parsed < 1) {
190
+ return GATE_EXEC_TIMEOUT_MS;
191
+ }
192
+ return parsed;
193
+ }
147
194
  function parseArgvJson(value, flag) {
148
195
  let parsed;
149
196
  try {
@@ -275,6 +322,7 @@ function cloneExecTarget(target) {
275
322
  runtime: target.runtime,
276
323
  baseCommand: [...target.baseCommand],
277
324
  priority: target.priority,
325
+ ...(target.models ? { models: [...target.models] } : {}),
278
326
  ...(target.hostDetectionCommand
279
327
  ? { hostDetectionCommand: [...target.hostDetectionCommand] }
280
328
  : {}),
@@ -283,17 +331,236 @@ function cloneExecTarget(target) {
283
331
  : {}),
284
332
  };
285
333
  }
334
+ function identityFromRecords(records, source) {
335
+ const resolved = resolveIdentityConfidence(records);
336
+ const family = classifyModelFamily({ value: resolved.value });
337
+ return {
338
+ value: resolved.value,
339
+ provenance: resolved.provenance,
340
+ confidence: resolved.confidence,
341
+ family,
342
+ avoidFamilies: resolved.diversityClaimable && family !== 'unknown' ? [family] : [],
343
+ diversityClaimable: resolved.diversityClaimable,
344
+ source,
345
+ };
346
+ }
347
+ function unknownProducerIdentity() {
348
+ return identityFromRecords([], 'unknown');
349
+ }
350
+ function parseProducerIdentityOption(value) {
351
+ const trimmed = value?.trim();
352
+ if (!trimmed) {
353
+ return unknownProducerIdentity();
354
+ }
355
+ const separator = trimmed.lastIndexOf(':');
356
+ const producer = separator > 0 ? trimmed.slice(0, separator).trim() : '';
357
+ const provenance = separator > 0 ? trimmed.slice(separator + 1).trim() : '';
358
+ if (!producer || !provenance) {
359
+ throw new Error('--producer-identity must use <value>:<declared|observed|inferred|unknown>.');
360
+ }
361
+ if (!VALID_IDENTITY_PROVENANCES.includes(provenance)) {
362
+ throw new Error('--producer-identity provenance must be one of declared | observed | inferred | unknown.');
363
+ }
364
+ return identityFromRecords([{ value: producer, provenance: provenance }], 'flag');
365
+ }
366
+ function identityFromStamps(stamps) {
367
+ const identities = stamps
368
+ .map((stamp) => identityFromRecords([{ value: stamp.producer, provenance: stamp.provenance }], 'stamp'))
369
+ .filter((identity) => identity.diversityClaimable && identity.family !== 'unknown');
370
+ const latest = identities.at(-1);
371
+ if (!latest) {
372
+ return unknownProducerIdentity();
373
+ }
374
+ return {
375
+ ...latest,
376
+ avoidFamilies: [...new Set(identities.map((identity) => identity.family))],
377
+ };
378
+ }
379
+ function phaseNumber(scope) {
380
+ const match = scope.match(/^p(\d+)(?:$|-t\d+$)/);
381
+ const value = match?.[1];
382
+ return value === undefined ? undefined : Number.parseInt(value, 10);
383
+ }
384
+ function reviewScopeRange(scope) {
385
+ if (scope === 'final') {
386
+ return { start: 1, end: Number.MAX_SAFE_INTEGER };
387
+ }
388
+ const range = scope.match(/^p(\d+)-p(\d+)$/);
389
+ if (!range) {
390
+ return null;
391
+ }
392
+ return {
393
+ start: Number.parseInt(range[1] ?? '0', 10),
394
+ end: Number.parseInt(range[2] ?? '0', 10),
395
+ };
396
+ }
397
+ function stampInReviewScope(stampScope, reviewScope) {
398
+ const range = reviewScopeRange(reviewScope);
399
+ if (!range) {
400
+ return false;
401
+ }
402
+ const stampPhase = phaseNumber(stampScope);
403
+ return (stampPhase !== undefined &&
404
+ stampPhase >= range.start &&
405
+ stampPhase <= range.end);
406
+ }
407
+ async function readStampedProducerIdentity(options) {
408
+ const scope = options.reviewScope?.trim();
409
+ if (!scope) {
410
+ return unknownProducerIdentity();
411
+ }
412
+ let markdown;
413
+ try {
414
+ markdown = await readFile(join(options.repoRoot, options.projectPath, 'implementation.md'), 'utf8');
415
+ }
416
+ catch {
417
+ return unknownProducerIdentity();
418
+ }
419
+ const stamps = parseDispatchStamps(markdown).filter((candidate) => candidate.role === 'implementer' || candidate.role === 'fix');
420
+ const exactStamp = [...stamps]
421
+ .reverse()
422
+ .find((candidate) => candidate.scope === scope);
423
+ if (exactStamp) {
424
+ return identityFromStamps([exactStamp]);
425
+ }
426
+ return identityFromStamps(stamps.filter((candidate) => stampInReviewScope(candidate.scope, scope)));
427
+ }
428
+ async function resolveReviewProducerIdentity(options) {
429
+ if (options.explicit?.trim()) {
430
+ return parseProducerIdentityOption(options.explicit);
431
+ }
432
+ return readStampedProducerIdentity(options);
433
+ }
434
+ function findPinnedModelArg(argv) {
435
+ for (let index = 0; index < argv.length; index += 1) {
436
+ const arg = argv[index];
437
+ if (arg === '--model') {
438
+ const value = argv[index + 1]?.trim();
439
+ return value || undefined;
440
+ }
441
+ if (arg?.startsWith('--model=')) {
442
+ const value = arg.slice('--model='.length).trim();
443
+ return value || undefined;
444
+ }
445
+ }
446
+ return undefined;
447
+ }
448
+ function targetCandidateModels(target) {
449
+ const pinnedModel = findPinnedModelArg(target.baseCommand);
450
+ if (pinnedModel) {
451
+ return [pinnedModel];
452
+ }
453
+ if (target.models && target.models.length > 0) {
454
+ return [...target.models];
455
+ }
456
+ return undefined;
457
+ }
458
+ function candidateFamily(target, model) {
459
+ if (model) {
460
+ return classifyModelFamily({ value: model });
461
+ }
462
+ return classifyModelFamily({ value: '', providerId: target.runtime });
463
+ }
464
+ function expandExecTargetCandidates(id, target) {
465
+ const models = targetCandidateModels(target);
466
+ if (!models) {
467
+ return [
468
+ {
469
+ id,
470
+ target: cloneExecTarget(target),
471
+ family: candidateFamily(target, undefined),
472
+ },
473
+ ];
474
+ }
475
+ return models.map((model) => ({
476
+ id,
477
+ target: cloneExecTarget(target),
478
+ model,
479
+ family: candidateFamily(target, model),
480
+ }));
481
+ }
482
+ function producerHasKnownFamily(identity) {
483
+ return identity.diversityClaimable && identity.avoidFamilies.length > 0;
484
+ }
485
+ function shouldAttemptNoDiverseFallback(avoid) {
486
+ return avoid === 'same-family';
487
+ }
488
+ function achievedDiversity(selected, producerIdentity) {
489
+ if (!producerHasKnownFamily(producerIdentity)) {
490
+ return 'unknown-producer';
491
+ }
492
+ if (selected.family !== 'unknown' &&
493
+ !producerIdentity.avoidFamilies.includes(selected.family)) {
494
+ return 'different-family';
495
+ }
496
+ if (selected.model && selected.model !== producerIdentity.value) {
497
+ return 'degraded-to-different-slug';
498
+ }
499
+ return 'same-family - no diverse target available';
500
+ }
501
+ function diversityFallbackWarning(achieved) {
502
+ if (achieved !== 'unknown-producer' &&
503
+ achieved !== 'degraded-to-different-slug' &&
504
+ achieved !== 'same-family - no diverse target available') {
505
+ return undefined;
506
+ }
507
+ return `No different-family gate target was available; running with achieved=${achieved}.`;
508
+ }
509
+ function attachDiversityMetadata(selected, avoid, producerIdentity) {
510
+ const achieved = achievedDiversity(selected, producerIdentity);
511
+ const warning = selected.noDiverseFamilyFallback
512
+ ? diversityFallbackWarning(achieved)
513
+ : undefined;
514
+ return {
515
+ ...selected,
516
+ diversity: {
517
+ avoid,
518
+ achieved,
519
+ producer: {
520
+ value: producerIdentity.value,
521
+ provenance: producerIdentity.provenance,
522
+ confidence: producerIdentity.confidence,
523
+ family: producerIdentity.family,
524
+ source: producerIdentity.source,
525
+ avoidFamilies: producerIdentity.avoidFamilies,
526
+ },
527
+ reviewer: {
528
+ target: selected.id,
529
+ runtime: selected.target.runtime,
530
+ family: selected.family,
531
+ ...(selected.model ? { model: selected.model } : {}),
532
+ },
533
+ ...(warning ? { warning } : {}),
534
+ },
535
+ };
536
+ }
286
537
  function argvHead(argv) {
287
538
  return [argv[0] ?? '', argv.slice(1)];
288
539
  }
289
- function listExecTargetCandidates(registry, currentRuntime, avoid) {
290
- const shouldAvoidSameRuntime = avoid === 'same-runtime' && currentRuntime !== 'unknown';
540
+ function listExecTargetCandidates(registry, currentRuntime, avoid, producerIdentity = unknownProducerIdentity()) {
541
+ const shouldAvoidSameFamily = avoid === 'same-family' && producerHasKnownFamily(producerIdentity);
542
+ const shouldAvoidSameRuntime = currentRuntime !== 'unknown' &&
543
+ (avoid === 'same-runtime' ||
544
+ (avoid === 'same-family' && !producerHasKnownFamily(producerIdentity)));
291
545
  return sortedExecTargetEntries(registry)
292
546
  .filter(({ target }) => !shouldAvoidSameRuntime || target.runtime !== currentRuntime)
293
- .map(({ id, target }) => ({ id, target: cloneExecTarget(target) }));
547
+ .flatMap(({ id, target }) => expandExecTargetCandidates(id, target))
548
+ .filter((candidate) => !shouldAvoidSameFamily ||
549
+ (candidate.family !== 'unknown' &&
550
+ !producerIdentity.avoidFamilies.includes(candidate.family)));
551
+ }
552
+ export function selectExecTarget(registry, currentRuntime, avoid, producerIdentity) {
553
+ return (listExecTargetCandidates(registry, currentRuntime, avoid, producerIdentity)[0] ?? null);
294
554
  }
295
- export function selectExecTarget(registry, currentRuntime, avoid) {
296
- return listExecTargetCandidates(registry, currentRuntime, avoid)[0] ?? null;
555
+ async function firstAvailableExecTarget(candidates, context, dependencies) {
556
+ for (const candidate of candidates) {
557
+ const availabilityCommand = candidate.target.availabilityCommand;
558
+ if (!availabilityCommand ||
559
+ (await checkArgv(availabilityCommand, 'availability', context, dependencies))) {
560
+ return candidate;
561
+ }
562
+ }
563
+ return null;
297
564
  }
298
565
  async function checkArgv(argv, purpose, context, dependencies) {
299
566
  const [command, args] = argvHead(argv);
@@ -306,6 +573,7 @@ async function checkArgv(argv, purpose, context, dependencies) {
306
573
  env: dependencies.processEnv,
307
574
  purpose,
308
575
  stdio: 'ignore',
576
+ timeoutMs: GATE_CHECK_TIMEOUT_MS,
309
577
  });
310
578
  return result.exitCode === 0;
311
579
  }
@@ -326,52 +594,70 @@ async function resolveCurrentRuntime(currentRuntime, context, dependencies) {
326
594
  }
327
595
  return 'unknown';
328
596
  }
329
- async function selectAvailableExecTarget(registry, currentRuntime, avoid, context, dependencies) {
330
- for (const candidate of listExecTargetCandidates(registry, currentRuntime, avoid)) {
331
- const availabilityCommand = candidate.target.availabilityCommand;
332
- if (!availabilityCommand ||
333
- (await checkArgv(availabilityCommand, 'availability', context, dependencies))) {
334
- return candidate;
335
- }
597
+ async function selectAvailableExecTarget(registry, currentRuntime, avoid, producerIdentity, context, dependencies) {
598
+ const selected = await firstAvailableExecTarget(listExecTargetCandidates(registry, currentRuntime, avoid, producerIdentity), context, dependencies);
599
+ if (selected) {
600
+ return selected;
336
601
  }
337
- return null;
602
+ if (!shouldAttemptNoDiverseFallback(avoid)) {
603
+ return null;
604
+ }
605
+ const fallback = await firstAvailableExecTarget(listExecTargetCandidates(registry, currentRuntime, 'none', unknownProducerIdentity()), context, dependencies);
606
+ return fallback ? { ...fallback, noDiverseFamilyFallback: true } : null;
338
607
  }
339
- async function resolveSelectedExecTarget(targets, options, context, dependencies) {
608
+ async function resolveSelectedExecTarget(targets, options, producerIdentity, context, dependencies) {
340
609
  const explicitTarget = options.target?.trim();
341
610
  if (explicitTarget) {
342
611
  const target = targets[explicitTarget];
343
612
  if (!target) {
344
613
  throw new Error(`Unknown exec target "${explicitTarget}".`);
345
614
  }
346
- return { id: explicitTarget, target: cloneExecTarget(target) };
615
+ return attachDiversityMetadata(expandExecTargetCandidates(explicitTarget, target)[0], 'none', producerIdentity);
347
616
  }
348
617
  const avoid = parseCrossProviderAvoid(options.avoid);
349
618
  const currentRuntime = await resolveCurrentRuntime(options.currentRuntime, context, dependencies);
350
- const selected = await selectAvailableExecTarget(targets, currentRuntime, avoid, context, dependencies);
619
+ const selected = await selectAvailableExecTarget(targets, currentRuntime, avoid, producerIdentity, context, dependencies);
351
620
  if (!selected) {
352
621
  throw new Error(noEligibleTargetMessage(currentRuntime, avoid));
353
622
  }
354
- return selected;
623
+ return attachDiversityMetadata(selected, avoid, producerIdentity);
355
624
  }
356
625
  async function executeTarget(selected, prompt, context, dependencies) {
357
626
  const [command, baseArgs] = argvHead(selected.target.baseCommand);
358
627
  if (!command) {
359
628
  throw new Error(`Exec target "${selected.id}" has an empty base command.`);
360
629
  }
630
+ const modelArgs = selected.model && !findPinnedModelArg(selected.target.baseCommand)
631
+ ? ['--model', selected.model]
632
+ : [];
633
+ const timeoutMs = resolveGateExecTimeoutMs(dependencies.processEnv);
634
+ if (!context.json) {
635
+ context.logger.info(`Running gate target ${selected.id} (${selected.target.runtime}); timeout=${timeoutMs}ms.`);
636
+ }
361
637
  try {
362
- const result = await dependencies.runProcess(command, [...baseArgs, ...prompt], {
638
+ return await dependencies.runProcess(command, [...baseArgs, ...modelArgs, ...prompt], {
363
639
  cwd: context.cwd,
364
640
  env: dependencies.processEnv,
365
641
  purpose: 'execute',
366
642
  stdio: 'inherit',
643
+ timeoutMs,
367
644
  });
368
- return result.exitCode;
369
645
  }
370
646
  catch (error) {
371
647
  const message = error instanceof Error ? error.message : String(error);
372
648
  throw new Error(`Failed to launch exec target "${selected.id}" (${command}): ${message}`, { cause: error });
373
649
  }
374
650
  }
651
+ function logGateDiversity(selected, context) {
652
+ const diversity = selected.diversity;
653
+ if (!diversity || context.json) {
654
+ return;
655
+ }
656
+ if (diversity.warning) {
657
+ context.logger.warn(diversity.warning);
658
+ }
659
+ context.logger.info(`Gate diversity: achieved=${diversity.achieved} producer=${diversity.producer.value} producer_family=${diversity.producer.family} provenance=${diversity.producer.provenance} confidence=${diversity.producer.confidence} reviewer=${diversity.reviewer.target} reviewer_family=${diversity.reviewer.family}`);
660
+ }
375
661
  function noEligibleTargetMessage(currentRuntime, avoid) {
376
662
  return `No eligible gate exec target found for current runtime "${currentRuntime}" with --avoid ${avoid}. Install or configure an alternate runtime, rerun with --avoid none, or pin a target with --target <id>.`;
377
663
  }
@@ -622,10 +908,18 @@ function writeReviewGateResult(context, payload) {
622
908
  context.logger.info(`Artifact normalized: inserted ${payload.normalization.insertedSeverities.map((severity) => severityDisplayName(severity)).join(', ')} empty Findings section(s).`);
623
909
  }
624
910
  context.logger.info(`Verdict: ${payload.status} (critical=${payload.counts.critical}, important=${payload.counts.important}, medium=${payload.counts.medium}, minor=${payload.counts.minor})`);
911
+ if (payload.diversity) {
912
+ if (payload.diversity.warning) {
913
+ context.logger.warn(payload.diversity.warning);
914
+ }
915
+ context.logger.info(`Gate diversity: achieved=${payload.diversity.achieved} producer=${payload.diversity.producer.value} producer_family=${payload.diversity.producer.family} provenance=${payload.diversity.producer.provenance} confidence=${payload.diversity.producer.confidence} reviewer=${payload.diversity.reviewer.target} reviewer_family=${payload.diversity.reviewer.family}`);
916
+ }
625
917
  context.logger.info(payload.handoff);
626
918
  }
627
919
  function writeReviewGateExecutionFailure(context, payload) {
628
- const message = `Review did not complete: target ${payload.target} exited with code ${payload.exitCode}.`;
920
+ const message = payload.timedOut
921
+ ? `Review did not complete: target ${payload.target} timed out after ${payload.timeoutMs}ms.`
922
+ : `Review did not complete: target ${payload.target} exited with code ${payload.exitCode}.`;
629
923
  if (context.json) {
630
924
  context.logger.json({
631
925
  status: 'review_failed',
@@ -634,6 +928,10 @@ function writeReviewGateExecutionFailure(context, payload) {
634
928
  target: payload.target,
635
929
  project: payload.project,
636
930
  exitCode: payload.exitCode,
931
+ timedOut: payload.timedOut ?? false,
932
+ ...(payload.timeoutMs !== undefined
933
+ ? { timeoutMs: payload.timeoutMs }
934
+ : {}),
637
935
  message,
638
936
  });
639
937
  return;
@@ -751,8 +1049,11 @@ async function runCrossProviderExec(prompt, options, context, dependencies) {
751
1049
  try {
752
1050
  const effective = await readEffectiveConfig(context, dependencies);
753
1051
  const targets = resolveExecTargets(effective);
754
- const selected = await resolveSelectedExecTarget(targets, options, context, dependencies);
755
- process.exitCode = await executeTarget(selected, prompt, context, dependencies);
1052
+ const producerIdentity = parseProducerIdentityOption(options.producerIdentity);
1053
+ const selected = await resolveSelectedExecTarget(targets, options, producerIdentity, context, dependencies);
1054
+ logGateDiversity(selected, context);
1055
+ const result = await executeTarget(selected, prompt, context, dependencies);
1056
+ process.exitCode = result.exitCode;
756
1057
  }
757
1058
  catch (error) {
758
1059
  writeError(context, error);
@@ -770,7 +1071,13 @@ async function runReviewGate(prompt, options, context, dependencies) {
770
1071
  project: options.project,
771
1072
  });
772
1073
  const targets = resolveExecTargets(effective);
773
- const selected = await resolveSelectedExecTarget(targets, options, context, dependencies);
1074
+ const producerIdentity = await resolveReviewProducerIdentity({
1075
+ explicit: options.producerIdentity,
1076
+ repoRoot,
1077
+ projectPath,
1078
+ reviewScope: options.reviewScope,
1079
+ });
1080
+ const selected = await resolveSelectedExecTarget(targets, options, producerIdentity, context, dependencies);
774
1081
  const threshold = parseReviewGateThreshold(options.exitNonzeroOn);
775
1082
  const before = await listActiveProjectReviewCandidates({
776
1083
  repoRoot,
@@ -787,13 +1094,16 @@ async function runReviewGate(prompt, options, context, dependencies) {
787
1094
  : []),
788
1095
  prompt.join(' '),
789
1096
  ]);
790
- const childExitCode = await executeTarget(selected, [reviewPrompt], context, dependencies);
1097
+ const childResult = await executeTarget(selected, [reviewPrompt], context, dependencies);
1098
+ const childExitCode = childResult.exitCode;
791
1099
  if (childExitCode !== 0) {
792
1100
  writeReviewGateExecutionFailure(context, {
793
1101
  runId,
794
1102
  target: selected.id,
795
1103
  project: projectPath,
796
1104
  exitCode: childExitCode,
1105
+ timedOut: childResult.timedOut ?? false,
1106
+ timeoutMs: resolveGateExecTimeoutMs(dependencies.processEnv),
797
1107
  });
798
1108
  process.exitCode = childExitCode;
799
1109
  return;
@@ -858,6 +1168,7 @@ async function runReviewGate(prompt, options, context, dependencies) {
858
1168
  invocation: verdict.invocation,
859
1169
  normalization: verdict.normalization,
860
1170
  handoff,
1171
+ diversity: selected.diversity,
861
1172
  });
862
1173
  process.exitCode = blocking ? 1 : 0;
863
1174
  }
@@ -906,8 +1217,9 @@ export function createGateCommand(overrides = {}) {
906
1217
  .command('cross-provider-exec')
907
1218
  .description('Run a prompt through an alternate configured runtime target')
908
1219
  .option('--target <id>', 'Run this exact exec target')
909
- .option('--avoid <mode>', 'Avoidance mode: same-runtime or none')
1220
+ .option('--avoid <mode>', 'Avoidance mode: same-family, same-runtime, or none')
910
1221
  .option('--current-runtime <runtime>', 'Override detected runtime for testing or manual routing')
1222
+ .option('--producer-identity <identity>', 'Producer identity as <value>:<declared|observed|inferred|unknown>')
911
1223
  .argument('<prompt...>', 'Prompt arguments appended to the target command')
912
1224
  .action(async (prompt, options, command) => {
913
1225
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
@@ -917,8 +1229,9 @@ export function createGateCommand(overrides = {}) {
917
1229
  .command('review')
918
1230
  .description('Run a review gate and map review findings to exit status')
919
1231
  .option('--target <id>', 'Run this exact exec target')
920
- .option('--avoid <mode>', 'Avoidance mode: same-runtime or none')
1232
+ .option('--avoid <mode>', 'Avoidance mode: same-family, same-runtime, or none')
921
1233
  .option('--current-runtime <runtime>', 'Override detected runtime for testing or manual routing')
1234
+ .option('--producer-identity <identity>', 'Producer identity as <value>:<declared|observed|inferred|unknown>')
922
1235
  .option('--project <path-or-name>', 'Project path or name to review; defaults to the active project')
923
1236
  .option('--review-scope <scope>', 'Review scope hint for the provider')
924
1237
  .option('--review-type <type>', 'Review type hint for the provider')
@@ -0,0 +1,37 @@
1
+ import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
2
+ import { type ModelFamily } from '../../providers/identity/family.js';
3
+ import type { IdentityProvenance } from '../../providers/identity/provenance.js';
4
+ import { Command } from 'commander';
5
+ export interface CursorAgentRunOptions {
6
+ cwd: string;
7
+ env: NodeJS.ProcessEnv;
8
+ }
9
+ export interface CursorAgentRunResult {
10
+ ok: boolean;
11
+ stdout: string;
12
+ stderr: string;
13
+ }
14
+ export interface CursorProbeDependencies {
15
+ runCursorAgent: (args: string[], options: CursorAgentRunOptions) => Promise<CursorAgentRunResult>;
16
+ readFile: (path: string, encoding: BufferEncoding) => Promise<string>;
17
+ env?: NodeJS.ProcessEnv;
18
+ }
19
+ interface CursorCurrentTargetCommandDependencies extends CursorProbeDependencies {
20
+ buildCommandContext: (options: GlobalOptions) => CommandContext;
21
+ }
22
+ export type CursorCurrentTargetSource = 'cursor-agent models' | '--list-models' | 'init-event' | 'cli-config' | 'unknown';
23
+ export interface CursorCurrentTarget {
24
+ value: string;
25
+ source: CursorCurrentTargetSource;
26
+ provenance: IdentityProvenance;
27
+ family: ModelFamily;
28
+ rawValue?: string;
29
+ }
30
+ export declare function probeCursorCurrentTarget(options: {
31
+ cwd: string;
32
+ home: string;
33
+ dependencies?: Partial<CursorProbeDependencies>;
34
+ }): Promise<CursorCurrentTarget>;
35
+ export declare function createCursorCurrentTargetCommand(overrides?: Partial<CursorCurrentTargetCommandDependencies>): Command;
36
+ export {};
37
+ //# sourceMappingURL=cursor-current-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-current-target.d.ts","sourceRoot":"","sources":["../../../src/commands/internal/cursor-current-target.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,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,uBAAuB;IACtC,cAAc,EAAE,CACd,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,UAAU,sCAAuC,SAAQ,uBAAuB;IAC9E,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;CACjE;AAED,MAAM,MAAM,yBAAyB,GACjC,qBAAqB,GACrB,eAAe,GACf,YAAY,GACZ,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,yBAAyB,CAAC;IAClC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiMD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACjD,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmE/B;AAeD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,sCAAsC,CAAM,GAC9D,OAAO,CAoBT"}