@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.
- package/assets/config/dispatch-matrix-recommendation.json +23 -0
- package/assets/docs/cli-utilities/configuration.md +59 -20
- package/assets/docs/cli-utilities/workflow-gates.md +79 -16
- package/assets/docs/contributing/code.md +10 -4
- package/assets/docs/contributing/hooks-and-safety.md +23 -0
- package/assets/docs/workflows/projects/dispatch-ceiling.md +80 -10
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-implement/SKILL.md +53 -11
- package/assets/skills/oat-project-plan/SKILL.md +22 -3
- package/assets/skills/oat-project-quick-start/SKILL.md +22 -3
- package/assets/templates/state.md +5 -0
- package/dist/commands/config/index.d.ts +6 -0
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +366 -8
- package/dist/commands/doctor/index.d.ts +6 -1
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +138 -4
- package/dist/commands/gate/index.d.ts +39 -2
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +343 -30
- package/dist/commands/internal/cursor-current-target.d.ts +37 -0
- package/dist/commands/internal/cursor-current-target.d.ts.map +1 -0
- package/dist/commands/internal/cursor-current-target.js +228 -0
- package/dist/commands/internal/index.d.ts.map +1 -1
- package/dist/commands/internal/index.js +2 -0
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +359 -16
- package/dist/config/oat-config.d.ts +15 -5
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +103 -10
- package/dist/config/resolve.js +12 -0
- package/dist/manifest/manifest.types.d.ts +12 -12
- package/dist/providers/ceiling/registry.d.ts.map +1 -1
- package/dist/providers/ceiling/registry.js +16 -0
- package/dist/providers/identity/availability.d.ts +22 -0
- package/dist/providers/identity/availability.d.ts.map +1 -0
- package/dist/providers/identity/availability.js +119 -0
- package/dist/providers/identity/family.d.ts +13 -0
- package/dist/providers/identity/family.d.ts.map +1 -0
- package/dist/providers/identity/family.js +32 -0
- package/dist/providers/identity/provenance.d.ts +21 -0
- package/dist/providers/identity/provenance.d.ts.map +1 -0
- package/dist/providers/identity/provenance.js +65 -0
- package/dist/providers/identity/stamp.d.ts +35 -0
- package/dist/providers/identity/stamp.d.ts.map +1 -0
- package/dist/providers/identity/stamp.js +171 -0
- 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
|
-
|
|
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;
|
|
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,EAEL,KAAK,WAAW,EACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAExB,MAAM,gCAAgC,CAAC;AAExC,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;AA2CD,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;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,KAAK,kBAAkB,GAAG,aAAa,GAAG,cAAc,GAAG,MAAM,CAAC;AAClE,KAAK,qBAAqB,GACtB,kBAAkB,GAClB,4BAA4B,GAC5B,2CAA2C,GAC3C,kBAAkB,CAAC;AAMvB,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACtC;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,kBAAkB,CAAC;QAC/B,UAAU,EAAE,kBAAkB,CAAC;QAC/B,MAAM,EAAE,WAAW,CAAC;QACpB,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QACvC,aAAa,EAAE,WAAW,EAAE,CAAC;KAC9B,CAAC;IACF,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,WAAW,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAowBD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAC9C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,kBAAkB,EACzB,gBAAgB,CAAC,EAAE,oBAAoB,GACtC,kBAAkB,GAAG,IAAI,CAS3B;AAshCD,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAsLT"}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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
|
-
.
|
|
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
|
-
|
|
296
|
-
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
755
|
-
|
|
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
|
|
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
|
|
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"}
|