@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
|
@@ -21,6 +21,7 @@ export const VALID_CLAUDE_DISPATCH_CEILINGS = ['haiku', 'sonnet', 'opus', 'fable
|
|
|
21
21
|
export const VALID_DISPATCH_CEILING_PRESETS = ['balanced', 'maximum', 'cost-conscious'];
|
|
22
22
|
export const VALID_DISPATCH_POLICY_MODES = ['managed', 'inherit'];
|
|
23
23
|
export const VALID_MANAGED_DISPATCH_POLICIES = ['economy', 'balanced', 'high', 'frontier', 'uncapped'];
|
|
24
|
+
export const VALID_DISPATCH_MATRIX_TIERS = ['economy', 'balanced', 'high', 'frontier'];
|
|
24
25
|
const VALID_GATE_ON_FAILURES = [
|
|
25
26
|
'block',
|
|
26
27
|
'prompt',
|
|
@@ -49,7 +50,11 @@ export const BUILTIN_EXEC_TARGETS = {
|
|
|
49
50
|
runtime: 'cursor',
|
|
50
51
|
baseCommand: ['cursor-agent', '-p'],
|
|
51
52
|
hostDetectionCommand: ['sh', '-c', 'test -n "$CURSOR_AGENT"'],
|
|
52
|
-
availabilityCommand: [
|
|
53
|
+
availabilityCommand: [
|
|
54
|
+
'sh',
|
|
55
|
+
'-c',
|
|
56
|
+
'command -v cursor-agent || command -v agent',
|
|
57
|
+
],
|
|
53
58
|
priority: 70,
|
|
54
59
|
},
|
|
55
60
|
};
|
|
@@ -72,6 +77,14 @@ function normalizeArgv(value) {
|
|
|
72
77
|
}
|
|
73
78
|
return [...value];
|
|
74
79
|
}
|
|
80
|
+
function normalizeStringList(value) {
|
|
81
|
+
if (!Array.isArray(value) ||
|
|
82
|
+
value.length === 0 ||
|
|
83
|
+
!value.every((item) => typeof item === 'string' && item.trim().length > 0)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return value.map((item) => item.trim());
|
|
87
|
+
}
|
|
75
88
|
function normalizeGateConfig(value) {
|
|
76
89
|
if (value === null) {
|
|
77
90
|
return null;
|
|
@@ -96,6 +109,82 @@ function normalizeGateConfig(value) {
|
|
|
96
109
|
}
|
|
97
110
|
return gate;
|
|
98
111
|
}
|
|
112
|
+
function normalizeProviderBareValue(providerKey, value) {
|
|
113
|
+
const trimmed = trimNonEmptyString(value);
|
|
114
|
+
if (trimmed === undefined) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
if (providerKey === 'codex' &&
|
|
118
|
+
!VALID_CODEX_DISPATCH_CEILINGS.includes(trimmed)) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
if (providerKey === 'claude' &&
|
|
122
|
+
!VALID_CLAUDE_DISPATCH_CEILINGS.includes(trimmed)) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return trimmed;
|
|
126
|
+
}
|
|
127
|
+
function normalizeDispatchRouteTarget(value) {
|
|
128
|
+
if (!isRecord(value)) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
const target = {};
|
|
132
|
+
const harness = trimNonEmptyString(value.harness);
|
|
133
|
+
if (harness !== undefined) {
|
|
134
|
+
target.harness = harness;
|
|
135
|
+
}
|
|
136
|
+
const model = trimNonEmptyString(value.model);
|
|
137
|
+
if (model !== undefined) {
|
|
138
|
+
target.model = model;
|
|
139
|
+
}
|
|
140
|
+
const effort = trimNonEmptyString(value.effort);
|
|
141
|
+
if (effort !== undefined) {
|
|
142
|
+
target.effort = effort;
|
|
143
|
+
}
|
|
144
|
+
return Object.keys(target).length > 0 ? target : undefined;
|
|
145
|
+
}
|
|
146
|
+
function normalizeDispatchMatrixCell(providerKey, value) {
|
|
147
|
+
const bareValue = normalizeProviderBareValue(providerKey, value);
|
|
148
|
+
if (bareValue !== undefined) {
|
|
149
|
+
return bareValue;
|
|
150
|
+
}
|
|
151
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const route = [];
|
|
155
|
+
for (const entry of value) {
|
|
156
|
+
const bareEntry = normalizeProviderBareValue(providerKey, entry);
|
|
157
|
+
if (bareEntry !== undefined) {
|
|
158
|
+
route.push(bareEntry);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const target = normalizeDispatchRouteTarget(entry);
|
|
162
|
+
if (target !== undefined) {
|
|
163
|
+
route.push(target);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return route.length > 0 ? route : undefined;
|
|
167
|
+
}
|
|
168
|
+
function normalizeDispatchProviderValue(providerKey, value) {
|
|
169
|
+
const bareValue = normalizeProviderBareValue(providerKey, value);
|
|
170
|
+
if (bareValue !== undefined) {
|
|
171
|
+
return bareValue;
|
|
172
|
+
}
|
|
173
|
+
if (!isRecord(value)) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
const tierMap = {};
|
|
177
|
+
for (const [tier, rawCell] of Object.entries(value)) {
|
|
178
|
+
if (!VALID_DISPATCH_MATRIX_TIERS.includes(tier)) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const normalized = normalizeDispatchMatrixCell(providerKey, rawCell);
|
|
182
|
+
if (normalized !== undefined) {
|
|
183
|
+
tierMap[tier] = normalized;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return Object.keys(tierMap).length > 0 ? tierMap : undefined;
|
|
187
|
+
}
|
|
99
188
|
function normalizeExecTarget(value) {
|
|
100
189
|
if (value === null) {
|
|
101
190
|
return null;
|
|
@@ -112,6 +201,10 @@ function normalizeExecTarget(value) {
|
|
|
112
201
|
if (baseCommand !== undefined) {
|
|
113
202
|
target.baseCommand = baseCommand;
|
|
114
203
|
}
|
|
204
|
+
const models = normalizeStringList(value.models);
|
|
205
|
+
if (models !== undefined) {
|
|
206
|
+
target.models = models;
|
|
207
|
+
}
|
|
115
208
|
if ('priority' in value) {
|
|
116
209
|
if (typeof value.priority === 'number' && Number.isFinite(value.priority)) {
|
|
117
210
|
target.priority = value.priority;
|
|
@@ -215,17 +308,17 @@ function normalizeWorkflowConfig(parsed) {
|
|
|
215
308
|
dispatchCeiling.preset = parsed.dispatchCeiling
|
|
216
309
|
.preset;
|
|
217
310
|
}
|
|
311
|
+
const recommendationVersion = trimNonEmptyString(parsed.dispatchCeiling.recommendationVersion);
|
|
312
|
+
if (recommendationVersion !== undefined) {
|
|
313
|
+
dispatchCeiling.recommendationVersion = recommendationVersion;
|
|
314
|
+
}
|
|
218
315
|
if (isRecord(parsed.dispatchCeiling.providers)) {
|
|
219
316
|
const providers = {};
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (typeof parsed.dispatchCeiling.providers.claude === 'string' &&
|
|
226
|
-
VALID_CLAUDE_DISPATCH_CEILINGS.includes(parsed.dispatchCeiling.providers.claude)) {
|
|
227
|
-
providers.claude = parsed.dispatchCeiling.providers
|
|
228
|
-
.claude;
|
|
317
|
+
for (const [providerKey, rawProviderValue] of Object.entries(parsed.dispatchCeiling.providers)) {
|
|
318
|
+
const normalized = normalizeDispatchProviderValue(providerKey, rawProviderValue);
|
|
319
|
+
if (normalized !== undefined) {
|
|
320
|
+
providers[providerKey] = normalized;
|
|
321
|
+
}
|
|
229
322
|
}
|
|
230
323
|
if (Object.keys(providers).length > 0) {
|
|
231
324
|
dispatchCeiling.providers = providers;
|
package/dist/config/resolve.js
CHANGED
|
@@ -181,6 +181,7 @@ function mergeExecTargetLayer(targets, layer) {
|
|
|
181
181
|
targets[id] = cloneExecTarget({
|
|
182
182
|
runtime: override.runtime ?? existing.runtime,
|
|
183
183
|
baseCommand: override.baseCommand ?? existing.baseCommand,
|
|
184
|
+
models: override.models ?? existing.models,
|
|
184
185
|
hostDetectionCommand: override.hostDetectionCommand ?? existing.hostDetectionCommand,
|
|
185
186
|
availabilityCommand: override.availabilityCommand ?? existing.availabilityCommand,
|
|
186
187
|
priority: override.priority ?? existing.priority,
|
|
@@ -211,6 +212,9 @@ function cloneExecTarget(target) {
|
|
|
211
212
|
if (target.availabilityCommand) {
|
|
212
213
|
next.availabilityCommand = [...target.availabilityCommand];
|
|
213
214
|
}
|
|
215
|
+
if (target.models) {
|
|
216
|
+
next.models = [...target.models];
|
|
217
|
+
}
|
|
214
218
|
return next;
|
|
215
219
|
}
|
|
216
220
|
function toCompleteExecTarget(target) {
|
|
@@ -231,8 +235,16 @@ function toCompleteExecTarget(target) {
|
|
|
231
235
|
if (isValidArgv(target.availabilityCommand)) {
|
|
232
236
|
completeTarget.availabilityCommand = [...target.availabilityCommand];
|
|
233
237
|
}
|
|
238
|
+
if (isValidStringList(target.models)) {
|
|
239
|
+
completeTarget.models = target.models.map((model) => model.trim());
|
|
240
|
+
}
|
|
234
241
|
return completeTarget;
|
|
235
242
|
}
|
|
243
|
+
function isValidStringList(value) {
|
|
244
|
+
return (Array.isArray(value) &&
|
|
245
|
+
value.length > 0 &&
|
|
246
|
+
value.every((part) => typeof part === 'string' && part.trim().length > 0));
|
|
247
|
+
}
|
|
236
248
|
function isValidArgv(value) {
|
|
237
249
|
if (!Array.isArray(value) ||
|
|
238
250
|
value.length === 0 ||
|
|
@@ -9,36 +9,36 @@ export declare const ManifestEntrySchema: z.ZodEffects<z.ZodObject<{
|
|
|
9
9
|
isFile: z.ZodDefault<z.ZodBoolean>;
|
|
10
10
|
lastSynced: z.ZodString;
|
|
11
11
|
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
provider: string;
|
|
12
13
|
canonicalPath: string;
|
|
13
14
|
providerPath: string;
|
|
14
|
-
provider: string;
|
|
15
15
|
contentType: "skill" | "agent" | "rule";
|
|
16
16
|
strategy: "symlink" | "copy";
|
|
17
17
|
contentHash: string | null;
|
|
18
18
|
isFile: boolean;
|
|
19
19
|
lastSynced: string;
|
|
20
20
|
}, {
|
|
21
|
+
provider: string;
|
|
21
22
|
canonicalPath: string;
|
|
22
23
|
providerPath: string;
|
|
23
|
-
provider: string;
|
|
24
24
|
contentType: "skill" | "agent" | "rule";
|
|
25
25
|
strategy: "symlink" | "copy";
|
|
26
26
|
contentHash: string | null;
|
|
27
27
|
lastSynced: string;
|
|
28
28
|
isFile?: boolean | undefined;
|
|
29
29
|
}>, {
|
|
30
|
+
provider: string;
|
|
30
31
|
canonicalPath: string;
|
|
31
32
|
providerPath: string;
|
|
32
|
-
provider: string;
|
|
33
33
|
contentType: "skill" | "agent" | "rule";
|
|
34
34
|
strategy: "symlink" | "copy";
|
|
35
35
|
contentHash: string | null;
|
|
36
36
|
isFile: boolean;
|
|
37
37
|
lastSynced: string;
|
|
38
38
|
}, {
|
|
39
|
+
provider: string;
|
|
39
40
|
canonicalPath: string;
|
|
40
41
|
providerPath: string;
|
|
41
|
-
provider: string;
|
|
42
42
|
contentType: "skill" | "agent" | "rule";
|
|
43
43
|
strategy: "symlink" | "copy";
|
|
44
44
|
contentHash: string | null;
|
|
@@ -58,36 +58,36 @@ export declare const ManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
58
58
|
isFile: z.ZodDefault<z.ZodBoolean>;
|
|
59
59
|
lastSynced: z.ZodString;
|
|
60
60
|
}, "strip", z.ZodTypeAny, {
|
|
61
|
+
provider: string;
|
|
61
62
|
canonicalPath: string;
|
|
62
63
|
providerPath: string;
|
|
63
|
-
provider: string;
|
|
64
64
|
contentType: "skill" | "agent" | "rule";
|
|
65
65
|
strategy: "symlink" | "copy";
|
|
66
66
|
contentHash: string | null;
|
|
67
67
|
isFile: boolean;
|
|
68
68
|
lastSynced: string;
|
|
69
69
|
}, {
|
|
70
|
+
provider: string;
|
|
70
71
|
canonicalPath: string;
|
|
71
72
|
providerPath: string;
|
|
72
|
-
provider: string;
|
|
73
73
|
contentType: "skill" | "agent" | "rule";
|
|
74
74
|
strategy: "symlink" | "copy";
|
|
75
75
|
contentHash: string | null;
|
|
76
76
|
lastSynced: string;
|
|
77
77
|
isFile?: boolean | undefined;
|
|
78
78
|
}>, {
|
|
79
|
+
provider: string;
|
|
79
80
|
canonicalPath: string;
|
|
80
81
|
providerPath: string;
|
|
81
|
-
provider: string;
|
|
82
82
|
contentType: "skill" | "agent" | "rule";
|
|
83
83
|
strategy: "symlink" | "copy";
|
|
84
84
|
contentHash: string | null;
|
|
85
85
|
isFile: boolean;
|
|
86
86
|
lastSynced: string;
|
|
87
87
|
}, {
|
|
88
|
+
provider: string;
|
|
88
89
|
canonicalPath: string;
|
|
89
90
|
providerPath: string;
|
|
90
|
-
provider: string;
|
|
91
91
|
contentType: "skill" | "agent" | "rule";
|
|
92
92
|
strategy: "symlink" | "copy";
|
|
93
93
|
contentHash: string | null;
|
|
@@ -97,9 +97,9 @@ export declare const ManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
97
97
|
lastUpdated: z.ZodString;
|
|
98
98
|
}, "strip", z.ZodTypeAny, {
|
|
99
99
|
entries: {
|
|
100
|
+
provider: string;
|
|
100
101
|
canonicalPath: string;
|
|
101
102
|
providerPath: string;
|
|
102
|
-
provider: string;
|
|
103
103
|
contentType: "skill" | "agent" | "rule";
|
|
104
104
|
strategy: "symlink" | "copy";
|
|
105
105
|
contentHash: string | null;
|
|
@@ -111,9 +111,9 @@ export declare const ManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
111
111
|
lastUpdated: string;
|
|
112
112
|
}, {
|
|
113
113
|
entries: {
|
|
114
|
+
provider: string;
|
|
114
115
|
canonicalPath: string;
|
|
115
116
|
providerPath: string;
|
|
116
|
-
provider: string;
|
|
117
117
|
contentType: "skill" | "agent" | "rule";
|
|
118
118
|
strategy: "symlink" | "copy";
|
|
119
119
|
contentHash: string | null;
|
|
@@ -125,9 +125,9 @@ export declare const ManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
125
125
|
lastUpdated: string;
|
|
126
126
|
}>, {
|
|
127
127
|
entries: {
|
|
128
|
+
provider: string;
|
|
128
129
|
canonicalPath: string;
|
|
129
130
|
providerPath: string;
|
|
130
|
-
provider: string;
|
|
131
131
|
contentType: "skill" | "agent" | "rule";
|
|
132
132
|
strategy: "symlink" | "copy";
|
|
133
133
|
contentHash: string | null;
|
|
@@ -139,9 +139,9 @@ export declare const ManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
139
139
|
lastUpdated: string;
|
|
140
140
|
}, {
|
|
141
141
|
entries: {
|
|
142
|
+
provider: string;
|
|
142
143
|
canonicalPath: string;
|
|
143
144
|
providerPath: string;
|
|
144
|
-
provider: string;
|
|
145
145
|
contentType: "skill" | "agent" | "rule";
|
|
146
146
|
strategy: "symlink" | "copy";
|
|
147
147
|
contentHash: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAET,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAK9C,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAET,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAK9C,CAAC;AA2FF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAE1E"}
|
|
@@ -54,6 +54,21 @@ const claudeAdapter = {
|
|
|
54
54
|
return isAboveOrchestrator(value, ctx.orchestratorTier);
|
|
55
55
|
},
|
|
56
56
|
};
|
|
57
|
+
const cursorAdapter = {
|
|
58
|
+
provider: 'cursor',
|
|
59
|
+
supportsCeiling: true,
|
|
60
|
+
validValues: [],
|
|
61
|
+
mechanism: 'model-arg',
|
|
62
|
+
compileToDispatchArgs(value) {
|
|
63
|
+
const model = value.trim();
|
|
64
|
+
return model ? { model } : null;
|
|
65
|
+
},
|
|
66
|
+
// Cursor model slugs do not share a total order, so upgrade verification is
|
|
67
|
+
// not meaningful here; availability is checked by the identity oracle layer.
|
|
68
|
+
verifyOnDispatch() {
|
|
69
|
+
return false;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
57
72
|
function advisoryAdapter(provider) {
|
|
58
73
|
return {
|
|
59
74
|
provider,
|
|
@@ -71,6 +86,7 @@ function advisoryAdapter(provider) {
|
|
|
71
86
|
const REGISTERED_ADAPTERS = {
|
|
72
87
|
codex: codexAdapter,
|
|
73
88
|
claude: claudeAdapter,
|
|
89
|
+
cursor: cursorAdapter,
|
|
74
90
|
};
|
|
75
91
|
/**
|
|
76
92
|
* Look up the ceiling adapter for a provider. Unknown providers fall back to an
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type MatrixCellAvailability = 'valid' | 'unknown-value' | 'unvalidated';
|
|
2
|
+
export interface CursorAgentRunOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
env: NodeJS.ProcessEnv;
|
|
5
|
+
}
|
|
6
|
+
export interface CursorAgentRunResult {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
stdout: string;
|
|
9
|
+
stderr: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AvailabilityOracleDependencies {
|
|
12
|
+
pathExists: (path: string) => Promise<boolean>;
|
|
13
|
+
runCursorAgent: (args: string[], options: CursorAgentRunOptions) => Promise<CursorAgentRunResult>;
|
|
14
|
+
env?: NodeJS.ProcessEnv;
|
|
15
|
+
}
|
|
16
|
+
export interface ValidateMatrixCellOptions {
|
|
17
|
+
cwd: string;
|
|
18
|
+
env?: NodeJS.ProcessEnv;
|
|
19
|
+
dependencies?: Partial<AvailabilityOracleDependencies>;
|
|
20
|
+
}
|
|
21
|
+
export declare function validateMatrixCell(provider: string, value: string, options: ValidateMatrixCellOptions): Promise<MatrixCellAvailability>;
|
|
22
|
+
//# sourceMappingURL=availability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/availability.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,CAAC;AAE/E,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,8BAA8B;IAC7C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,cAAc,EAAE,CACd,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;CACxD;AAwID,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,sBAAsB,CAAC,CA8BjC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { VALID_CLAUDE_DISPATCH_CEILINGS, VALID_CODEX_DISPATCH_CEILINGS, } from '../../config/oat-config.js';
|
|
5
|
+
import { fileExists } from '../../fs/io.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
async function runCursorAgent(args, options) {
|
|
8
|
+
try {
|
|
9
|
+
const { stdout, stderr } = await execFileAsync('cursor-agent', args, {
|
|
10
|
+
cwd: options.cwd,
|
|
11
|
+
env: options.env,
|
|
12
|
+
maxBuffer: 1024 * 1024,
|
|
13
|
+
timeout: 10_000,
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
stdout: String(stdout),
|
|
18
|
+
stderr: String(stderr),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const failure = error;
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
stdout: String(failure.stdout ?? ''),
|
|
26
|
+
stderr: String(failure.stderr ?? failure.message),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const DEFAULT_DEPENDENCIES = {
|
|
31
|
+
pathExists: fileExists,
|
|
32
|
+
runCursorAgent,
|
|
33
|
+
env: process.env,
|
|
34
|
+
};
|
|
35
|
+
function apiKeyArgs(env) {
|
|
36
|
+
const apiKey = env.CURSOR_API_KEY;
|
|
37
|
+
return typeof apiKey === 'string' && apiKey.length > 0
|
|
38
|
+
? ['--api-key', apiKey]
|
|
39
|
+
: [];
|
|
40
|
+
}
|
|
41
|
+
function parseCursorCatalog(stdout) {
|
|
42
|
+
const entries = [];
|
|
43
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
44
|
+
const match = line.match(/^(\S+)\s+-\s+(.+)$/);
|
|
45
|
+
if (!match) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const [, slug] = match;
|
|
49
|
+
if (slug) {
|
|
50
|
+
entries.push({ slug });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return entries;
|
|
54
|
+
}
|
|
55
|
+
function availabilityFromCursorCatalog(value, stdout) {
|
|
56
|
+
const entries = parseCursorCatalog(stdout);
|
|
57
|
+
if (entries.length === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return entries.some((entry) => entry.slug === value)
|
|
61
|
+
? 'valid'
|
|
62
|
+
: 'unknown-value';
|
|
63
|
+
}
|
|
64
|
+
async function validateCodexCell(value, cwd, dependencies) {
|
|
65
|
+
if (!VALID_CODEX_DISPATCH_CEILINGS.includes(value)) {
|
|
66
|
+
return 'unknown-value';
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const implementerExists = await dependencies.pathExists(join(cwd, '.codex', 'agents', `oat-phase-implementer-${value}.toml`));
|
|
70
|
+
const reviewerExists = await dependencies.pathExists(join(cwd, '.codex', 'agents', `oat-reviewer-${value}.toml`));
|
|
71
|
+
return implementerExists && reviewerExists ? 'valid' : 'unknown-value';
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return 'unvalidated';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function validateCursorCell(value, cwd, dependencies) {
|
|
78
|
+
const env = dependencies.env ?? process.env;
|
|
79
|
+
const runOptions = { cwd, env };
|
|
80
|
+
const modelsResult = await dependencies.runCursorAgent([...apiKeyArgs(env), 'models'], runOptions);
|
|
81
|
+
if (modelsResult.ok) {
|
|
82
|
+
const availability = availabilityFromCursorCatalog(value, modelsResult.stdout);
|
|
83
|
+
if (availability !== null) {
|
|
84
|
+
return availability;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const listResult = await dependencies.runCursorAgent([...apiKeyArgs(env), '--list-models'], runOptions);
|
|
88
|
+
if (listResult.ok) {
|
|
89
|
+
const availability = availabilityFromCursorCatalog(value, listResult.stdout);
|
|
90
|
+
if (availability !== null) {
|
|
91
|
+
return availability;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return 'unvalidated';
|
|
95
|
+
}
|
|
96
|
+
export async function validateMatrixCell(provider, value, options) {
|
|
97
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
98
|
+
const normalizedValue = value.trim();
|
|
99
|
+
if (!normalizedProvider || !normalizedValue) {
|
|
100
|
+
return 'unknown-value';
|
|
101
|
+
}
|
|
102
|
+
const dependencies = {
|
|
103
|
+
...DEFAULT_DEPENDENCIES,
|
|
104
|
+
env: options.env ?? DEFAULT_DEPENDENCIES.env,
|
|
105
|
+
...options.dependencies,
|
|
106
|
+
};
|
|
107
|
+
if (normalizedProvider === 'claude') {
|
|
108
|
+
return VALID_CLAUDE_DISPATCH_CEILINGS.includes(normalizedValue)
|
|
109
|
+
? 'valid'
|
|
110
|
+
: 'unknown-value';
|
|
111
|
+
}
|
|
112
|
+
if (normalizedProvider === 'codex') {
|
|
113
|
+
return validateCodexCell(normalizedValue, options.cwd, dependencies);
|
|
114
|
+
}
|
|
115
|
+
if (normalizedProvider === 'cursor') {
|
|
116
|
+
return validateCursorCell(normalizedValue, options.cwd, dependencies);
|
|
117
|
+
}
|
|
118
|
+
return 'unvalidated';
|
|
119
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ModelFamily = 'claude' | 'openai' | 'composer' | 'glm' | 'unknown';
|
|
2
|
+
interface ClassifyModelFamilyInput {
|
|
3
|
+
value: string;
|
|
4
|
+
/**
|
|
5
|
+
* Structured model-provider identifier, when a harness exposes one. This is
|
|
6
|
+
* not the orchestration/runtime harness id; e.g. Cursor can run several model
|
|
7
|
+
* families and must be classified from the concrete model value.
|
|
8
|
+
*/
|
|
9
|
+
providerId?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function classifyModelFamily(input: ClassifyModelFamilyInput): ModelFamily;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=family.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"family.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/family.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;AAE/E,UAAU,wBAAwB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgCD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,WAAW,CASb"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const PROVIDER_ID_FAMILIES = [
|
|
2
|
+
[/^(anthropic|claude)$/i, 'claude'],
|
|
3
|
+
[/^(openai|codex)$/i, 'openai'],
|
|
4
|
+
[/^composer$/i, 'composer'],
|
|
5
|
+
[/^(glm|zai|zhipu)$/i, 'glm'],
|
|
6
|
+
];
|
|
7
|
+
const VALUE_FAMILIES = [
|
|
8
|
+
[/\b(claude|sonnet|opus|haiku|fable)\b/i, 'claude'],
|
|
9
|
+
[/\b(gpt|openai|codex|o[1-9])[-\w.]*\b/i, 'openai'],
|
|
10
|
+
[/\bcomposer\b/i, 'composer'],
|
|
11
|
+
[/\bglm\b/i, 'glm'],
|
|
12
|
+
];
|
|
13
|
+
function normalize(value) {
|
|
14
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
15
|
+
}
|
|
16
|
+
function firstMatchingFamily(value, patterns) {
|
|
17
|
+
for (const [pattern, family] of patterns) {
|
|
18
|
+
if (pattern.test(value)) {
|
|
19
|
+
return family;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
export function classifyModelFamily(input) {
|
|
25
|
+
const providerId = normalize(input?.providerId);
|
|
26
|
+
const providerFamily = firstMatchingFamily(providerId, PROVIDER_ID_FAMILIES);
|
|
27
|
+
if (providerFamily) {
|
|
28
|
+
return providerFamily;
|
|
29
|
+
}
|
|
30
|
+
const value = normalize(input?.value);
|
|
31
|
+
return firstMatchingFamily(value, VALUE_FAMILIES) ?? 'unknown';
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type IdentityProvenance = 'declared' | 'observed' | 'inferred' | 'unknown';
|
|
2
|
+
export type IdentityConfidence = 'high' | 'medium' | 'low' | 'unknown';
|
|
3
|
+
export interface IdentityRecord {
|
|
4
|
+
value: string;
|
|
5
|
+
provenance: IdentityProvenance;
|
|
6
|
+
/**
|
|
7
|
+
* True when the harness has been proven to reject invalid model selections
|
|
8
|
+
* instead of silently falling back to another model.
|
|
9
|
+
*/
|
|
10
|
+
rejectOnInvalid?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface ResolvedIdentity {
|
|
13
|
+
value: string;
|
|
14
|
+
provenance: IdentityProvenance;
|
|
15
|
+
confidence: IdentityConfidence;
|
|
16
|
+
mismatch: boolean;
|
|
17
|
+
diversityClaimable: boolean;
|
|
18
|
+
records: IdentityRecord[];
|
|
19
|
+
}
|
|
20
|
+
export declare function resolveIdentityConfidence(records: IdentityRecord[]): ResolvedIdentity;
|
|
21
|
+
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../../src/providers/identity/provenance.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,UAAU,GACV,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AA+DD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,cAAc,EAAE,GACxB,gBAAgB,CAmClB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const PROVENANCE_PRIORITY = {
|
|
2
|
+
declared: 4,
|
|
3
|
+
observed: 3,
|
|
4
|
+
inferred: 2,
|
|
5
|
+
unknown: 1,
|
|
6
|
+
};
|
|
7
|
+
function normalizedValue(value) {
|
|
8
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
9
|
+
? value.trim()
|
|
10
|
+
: 'unknown';
|
|
11
|
+
}
|
|
12
|
+
function normalizeRecord(record) {
|
|
13
|
+
return {
|
|
14
|
+
...record,
|
|
15
|
+
value: normalizedValue(record.value),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function strongestRecord(records, provenance) {
|
|
19
|
+
return records.find((record) => record.provenance === provenance && record.value !== 'unknown');
|
|
20
|
+
}
|
|
21
|
+
function strongestKnownRecord(records) {
|
|
22
|
+
return records
|
|
23
|
+
.filter((record) => record.value !== 'unknown')
|
|
24
|
+
.sort((left, right) => PROVENANCE_PRIORITY[right.provenance] -
|
|
25
|
+
PROVENANCE_PRIORITY[left.provenance])[0];
|
|
26
|
+
}
|
|
27
|
+
function resolved(record, confidence, mismatch, records) {
|
|
28
|
+
const value = record.value;
|
|
29
|
+
return {
|
|
30
|
+
value,
|
|
31
|
+
provenance: record.provenance,
|
|
32
|
+
confidence,
|
|
33
|
+
mismatch,
|
|
34
|
+
diversityClaimable: value !== 'unknown' &&
|
|
35
|
+
record.provenance !== 'unknown' &&
|
|
36
|
+
confidence !== 'unknown',
|
|
37
|
+
records,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function resolveIdentityConfidence(records) {
|
|
41
|
+
const normalizedRecords = records.map(normalizeRecord);
|
|
42
|
+
const declared = strongestRecord(normalizedRecords, 'declared');
|
|
43
|
+
const observed = strongestRecord(normalizedRecords, 'observed');
|
|
44
|
+
if (declared && observed) {
|
|
45
|
+
if (declared.value === observed.value) {
|
|
46
|
+
return resolved(declared, 'high', false, normalizedRecords);
|
|
47
|
+
}
|
|
48
|
+
return resolved(observed, 'low', true, normalizedRecords);
|
|
49
|
+
}
|
|
50
|
+
if (declared) {
|
|
51
|
+
return resolved(declared, declared.rejectOnInvalid === true ? 'high' : 'medium', false, normalizedRecords);
|
|
52
|
+
}
|
|
53
|
+
if (observed) {
|
|
54
|
+
return resolved(observed, 'low', false, normalizedRecords);
|
|
55
|
+
}
|
|
56
|
+
const inferred = strongestRecord(normalizedRecords, 'inferred');
|
|
57
|
+
if (inferred) {
|
|
58
|
+
return resolved(inferred, 'low', false, normalizedRecords);
|
|
59
|
+
}
|
|
60
|
+
const fallback = strongestKnownRecord(normalizedRecords) ?? {
|
|
61
|
+
value: 'unknown',
|
|
62
|
+
provenance: 'unknown',
|
|
63
|
+
};
|
|
64
|
+
return resolved(fallback, 'unknown', false, normalizedRecords);
|
|
65
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IdentityProvenance } from './provenance.js';
|
|
2
|
+
export type DispatchAction = 'implementation' | 'fix' | 'review';
|
|
3
|
+
export type DispatchRole = 'implementer' | 'fix' | 'reviewer';
|
|
4
|
+
export interface DispatchStampRecord {
|
|
5
|
+
scope: string;
|
|
6
|
+
action: DispatchAction;
|
|
7
|
+
role: DispatchRole;
|
|
8
|
+
producer: string;
|
|
9
|
+
provenance: IdentityProvenance;
|
|
10
|
+
modelAxis: string;
|
|
11
|
+
effortAxis: string;
|
|
12
|
+
dispatchPolicy: string;
|
|
13
|
+
dispatchCeiling: string;
|
|
14
|
+
target: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DispatchStamp extends DispatchStampRecord {
|
|
17
|
+
line: string;
|
|
18
|
+
lineNumber: number;
|
|
19
|
+
legacy: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ProducerIdentity {
|
|
22
|
+
scope: string;
|
|
23
|
+
action: DispatchAction;
|
|
24
|
+
role: DispatchRole;
|
|
25
|
+
producer: string;
|
|
26
|
+
provenance: IdentityProvenance;
|
|
27
|
+
target: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ParseDispatchStampsOptions {
|
|
30
|
+
onWarning?: (warning: string) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare function formatDispatchStamp(record: DispatchStampRecord): string;
|
|
33
|
+
export declare function parseDispatchStamps(markdown: string, options?: ParseDispatchStampsOptions): DispatchStamp[];
|
|
34
|
+
export declare function getProducerIdentitiesByScope(markdown: string, options?: ParseDispatchStampsOptions): Record<string, ProducerIdentity[]>;
|
|
35
|
+
//# sourceMappingURL=stamp.d.ts.map
|