@bitkyc08/opencodex 2.12.0 → 2.13.0
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/README.md +1 -1
- package/gui/dist/assets/index-BHldBl6_.js +76 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +15 -0
- package/src/adapters/google-antigravity-replay.ts +269 -5
- package/src/adapters/openai-chat.ts +25 -18
- package/src/adapters/openai-responses.ts +63 -17
- package/src/bridge.ts +11 -5
- package/src/claude/inbound.ts +24 -3
- package/src/cli/account-api.ts +2 -0
- package/src/cli/account-extended.ts +262 -1
- package/src/cli/account.ts +3 -1
- package/src/cli/dispatch.ts +532 -0
- package/src/cli/doctor.ts +26 -21
- package/src/cli/help.ts +9 -278
- package/src/cli/index.ts +45 -506
- package/src/cli/lab.ts +171 -65
- package/src/cli/registry.ts +384 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/status.ts +9 -2
- package/src/cli/v2.ts +37 -2
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-store.ts +12 -1
- package/src/codex/admission.ts +2 -1
- package/src/codex/auth-api.ts +3 -2
- package/src/codex/catalog/metadata.ts +6 -4
- package/src/codex/catalog/parsing.ts +31 -7
- package/src/codex/catalog/provider-fetch.ts +2 -1
- package/src/codex/catalog/sync.ts +65 -11
- package/src/codex/features.ts +437 -31
- package/src/codex/history-job.ts +6 -11
- package/src/codex/history-provider.ts +10 -9
- package/src/codex/inject.ts +14 -1
- package/src/codex/native-profile-startup.ts +49 -3
- package/src/codex/native-residue.ts +14 -2
- package/src/codex/paths.ts +75 -1
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/shim.ts +876 -16
- package/src/codex/sync.ts +27 -2
- package/src/config.ts +148 -10
- package/src/generated/compatibility-version.json +2572 -0
- package/src/images/loop.ts +1 -1
- package/src/lab/artifacts/sanitize.ts +3 -3
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +480 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/types.ts +23 -0
- package/src/lab/events/types.ts +2 -1
- package/src/lab/events/validate.ts +2 -1
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +454 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +2 -0
- package/src/lab/ledger/store.ts +173 -0
- package/src/lab/live/executor.ts +29 -4
- package/src/lab/live/transport.ts +3 -1
- package/src/lab/observe/from-conformance.ts +12 -57
- package/src/lab/observe/from-live.ts +9 -1
- package/src/lab/paths.ts +74 -9
- package/src/lab/projection/schema.ts +14 -1
- package/src/lab/projection/verdicts.ts +89 -53
- package/src/lab/projection/verification.ts +83 -3
- package/src/lab/query/catalog.ts +34 -5
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +11 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/subject/installation-salt.ts +24 -4
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +2 -1
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/windows-elevation.ts +8 -1
- package/src/lib/windows-user-principal.ts +62 -2
- package/src/lib/winsw.ts +8 -2
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/google-antigravity.ts +27 -0
- package/src/oauth/health.ts +12 -48
- package/src/oauth/index.ts +122 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/nous.ts +749 -0
- package/src/oauth/store.ts +56 -3
- package/src/providers/codex-capacity.ts +1 -0
- package/src/providers/registry.ts +161 -16
- package/src/responses/custom-tool-compat.ts +182 -0
- package/src/responses/parser.ts +22 -0
- package/src/responses/reasoning-replay-cache.ts +168 -11
- package/src/responses/schema.ts +1 -1
- package/src/router.ts +5 -20
- package/src/routing/capability.ts +9 -3
- package/src/routing/compatibility/assemble.ts +159 -0
- package/src/routing/compatibility/behavior.ts +224 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/evaluator.ts +27 -32
- package/src/routing/profile.ts +118 -4
- package/src/routing/trace.ts +82 -28
- package/src/server/auth-cors.ts +7 -0
- package/src/server/background-lifecycle.ts +20 -7
- package/src/server/chat-completions.ts +2 -2
- package/src/server/claude-messages.ts +6 -3
- package/src/server/direct-local-http.ts +343 -0
- package/src/server/index.ts +80 -18
- package/src/server/lifecycle.ts +12 -4
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/management/agent-settings-routes.ts +27 -3
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +13 -0
- package/src/server/management/logs-usage-routes.ts +1 -0
- package/src/server/management/oauth-account-routes.ts +57 -1
- package/src/server/management/provider-routes.ts +16 -0
- package/src/server/management/routing-profile-routes.ts +12 -24
- package/src/server/management-api.ts +2 -0
- package/src/server/management-auth.ts +68 -3
- package/src/server/proxy-liveness.ts +3 -2
- package/src/server/request-decompress.ts +9 -3
- package/src/server/request-log.ts +53 -4
- package/src/server/responses/collaboration.ts +93 -17
- package/src/server/responses/compact.ts +3 -0
- package/src/server/responses/core.ts +202 -15
- package/src/server/responses/policy-fallback.ts +1 -0
- package/src/server/responses-custom-tool-repair.ts +280 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/startup-action-control.ts +8 -1
- package/src/service.ts +278 -12
- package/src/types.ts +49 -3
- package/src/usage/expected-prices.ts +30 -0
- package/src/usage/log.ts +30 -4
- package/src/usage/summary.ts +153 -2
- package/src/web-search/loop.ts +1 -1
- package/gui/dist/assets/index-Cw1_mxO8.js +0 -70
- package/src/cli/internal-dispatch.ts +0 -20
package/src/cli/lab.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `ocx lab` —
|
|
2
|
+
* `ocx lab` — Compatibility Lab inspection and explicit CL-08 automation controls.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Read commands use the local SQLite projection. Automation mutations and manual runs are
|
|
5
|
+
* explicit operator actions; read commands never start probes or scheduler ticks.
|
|
5
6
|
*/
|
|
6
|
-
import { getConfigDir } from "../config";
|
|
7
|
+
import { getConfigDir, readConfigDiagnostics } from "../config";
|
|
7
8
|
import {
|
|
8
9
|
ARTIFACT_CLASSES,
|
|
9
10
|
EVIDENCE_LAYERS,
|
|
@@ -32,6 +33,8 @@ import {
|
|
|
32
33
|
queryLabSubjectById,
|
|
33
34
|
queryLabSubjects,
|
|
34
35
|
queryLabVerdicts,
|
|
36
|
+
queryPassiveProductionSignals,
|
|
37
|
+
type PassiveProductionQueryResultV1,
|
|
35
38
|
} from "../lab/query";
|
|
36
39
|
import {
|
|
37
40
|
CliUsageError,
|
|
@@ -43,9 +46,27 @@ import {
|
|
|
43
46
|
takeIntegerOption,
|
|
44
47
|
takeOption,
|
|
45
48
|
} from "./runtime-api";
|
|
49
|
+
import {
|
|
50
|
+
buildLabAutomationStatus,
|
|
51
|
+
enqueueManualLabRun,
|
|
52
|
+
reconcileLabAutomationQueue,
|
|
53
|
+
setLabAutomationDispatchDeps,
|
|
54
|
+
startLabAutomationScheduler,
|
|
55
|
+
stopLabAutomationScheduler,
|
|
56
|
+
} from "../lab/automation/orchestrator";
|
|
57
|
+
import { loadLabAutomationState } from "../lab/automation/persistence";
|
|
58
|
+
import {
|
|
59
|
+
loadLabAutomationConfig,
|
|
60
|
+
saveLabAutomationPolicyConfig,
|
|
61
|
+
} from "../lab/automation/config-persistence";
|
|
62
|
+
import { planManualLabRun } from "../lab/automation/planner";
|
|
63
|
+
import { listLabAutomationRuns } from "../lab/automation/runs-query";
|
|
64
|
+
import { LabAutomationError, type LabAutomationLayer } from "../lab/automation/types";
|
|
65
|
+
import { createProductionLabRouteExecutor } from "../lib/lab-live-route-production";
|
|
46
66
|
|
|
47
67
|
const USAGE = `Usage:
|
|
48
68
|
ocx lab status [--json]
|
|
69
|
+
ocx lab production-signals --subject <id> [--limit <n>] [--json]
|
|
49
70
|
ocx lab verdicts [--subject <id>] [--layer <layer>] [--suite <id>] [--verdict <v>] [--from <ms>] [--to <ms>] [--limit <n>] [--cursor <c>] [--json]
|
|
50
71
|
ocx lab subjects [--kind <kind>] [--limit <n>] [--cursor <c>] [--json]
|
|
51
72
|
ocx lab subject <subjectId> [--json]
|
|
@@ -54,7 +75,12 @@ const USAGE = `Usage:
|
|
|
54
75
|
ocx lab event <eventId> [--json]
|
|
55
76
|
ocx lab artifacts [--status <s>] [--artifact-class <c>] [--limit <n>] [--cursor <c>] [--json]
|
|
56
77
|
ocx lab artifact <digest> [--json]
|
|
57
|
-
ocx lab catalog [--layer <layer>] [--suite <id>] [--json]
|
|
78
|
+
ocx lab catalog [--layer <layer>] [--suite <id>] [--json]
|
|
79
|
+
ocx lab automation status [--json]
|
|
80
|
+
ocx lab automation enable [--protocol] [--live] [--json]
|
|
81
|
+
ocx lab automation disable [--json]
|
|
82
|
+
ocx lab automation runs [--limit <n>] [--cursor <c>] [--json]
|
|
83
|
+
ocx lab run --layer <layer> --scenario <id> [--provider <name>] [--model <id>] [--json]`;
|
|
58
84
|
|
|
59
85
|
const ARTIFACT_STATUSES = ["present", "corrupt", "purged_unavailable"] as const;
|
|
60
86
|
type ArtifactStatus = (typeof ARTIFACT_STATUSES)[number];
|
|
@@ -74,6 +100,7 @@ function labErrorMessage(err: unknown): string {
|
|
|
74
100
|
if (err instanceof LabProjectionUnavailableError) return "lab projection is not available";
|
|
75
101
|
if (err instanceof LabProjectionIncompatibleError) return "lab projection schema or spec version is incompatible";
|
|
76
102
|
if (err instanceof InvalidCursorError) return "invalid cursor";
|
|
103
|
+
if (err instanceof LabAutomationError && err.code === "invalid_cursor") return "invalid cursor";
|
|
77
104
|
return "lab read failed";
|
|
78
105
|
}
|
|
79
106
|
|
|
@@ -163,6 +190,39 @@ function catalogLines(scenarios: ReturnType<typeof queryLabCatalogEntries>): str
|
|
|
163
190
|
return lines.length > 0 ? lines : ["No catalog scenarios"];
|
|
164
191
|
}
|
|
165
192
|
|
|
193
|
+
function passiveProductionLines(result: PassiveProductionQueryResultV1): string[] {
|
|
194
|
+
const summary = result.summary;
|
|
195
|
+
return [
|
|
196
|
+
"Observed production traffic (not Lab verification)",
|
|
197
|
+
`Attempts: ${summary.recentProductionAttempts} | Successes: ${summary.recentSuccessfulAttempts} | Route errors: ${summary.recentRouteErrorSignals}`,
|
|
198
|
+
...(summary.lastObservedProductionAttempt !== undefined
|
|
199
|
+
? [`Last observed: ${summary.lastObservedProductionAttempt}`]
|
|
200
|
+
: []),
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function automationStatusLines(status: ReturnType<typeof buildLabAutomationStatus>): string[] {
|
|
205
|
+
return [
|
|
206
|
+
`Automation enabled: ${status.policy.enabled}`,
|
|
207
|
+
`Scheduler intent: ${status.policy.enabled ? "enabled" : "disabled"}`,
|
|
208
|
+
`Layers: protocol=${status.policy.layers.protocolConformance} live=${status.policy.layers.liveRouteCompatibility} task=${status.policy.layers.taskEffectiveness}`,
|
|
209
|
+
`Queued: ${status.counters.queued} | Running: ${status.counters.running}`,
|
|
210
|
+
`Run budget remaining: ${status.counters.remainingRunBudget} | Live request budget: ${status.counters.remainingLiveRequestBudget}`,
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function automationCliStatus(status: ReturnType<typeof buildLabAutomationStatus>) {
|
|
215
|
+
const { schedulerRunning: _processLocalSchedulerState, ...stable } = status;
|
|
216
|
+
return { ...stable, schedulerIntentEnabled: status.policy.enabled };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function runListLines(page: ReturnType<typeof listLabAutomationRuns>): string[] {
|
|
220
|
+
const lines = page.items.map((row) =>
|
|
221
|
+
`${row.runId} ${row.state} ${row.evidenceLayer} ${row.scenarioId} trigger=${row.trigger}`,
|
|
222
|
+
);
|
|
223
|
+
return lines.length > 0 ? lines : ["No automation runs"];
|
|
224
|
+
}
|
|
225
|
+
|
|
166
226
|
export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): Promise<number> {
|
|
167
227
|
return runCliAction(async () => {
|
|
168
228
|
const configDir = deps.configDir ?? getConfigDir();
|
|
@@ -178,6 +238,15 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
178
238
|
printData(status, wantsJson, statusSummary(status));
|
|
179
239
|
return;
|
|
180
240
|
}
|
|
241
|
+
case "production-signals": {
|
|
242
|
+
const subjectId = takeOption(rest, "--subject");
|
|
243
|
+
const limit = takeIntegerOption(rest, "--limit", { min: 1 });
|
|
244
|
+
rejectArgs(rest, USAGE);
|
|
245
|
+
if (!subjectId) throw new CliUsageError("--subject is required", USAGE);
|
|
246
|
+
const result = queryPassiveProductionSignals(subjectId, limit, configDir);
|
|
247
|
+
printData(result, wantsJson, passiveProductionLines(result));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
181
250
|
case "verdicts": {
|
|
182
251
|
const subjectId = takeOption(rest, "--subject");
|
|
183
252
|
const layer = takeEnumOption<EvidenceLayer>(
|
|
@@ -199,14 +268,7 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
199
268
|
const limit = takeIntegerOption(rest, "--limit", { min: 1 });
|
|
200
269
|
const cursor = takeOption(rest, "--cursor");
|
|
201
270
|
rejectArgs(rest, USAGE);
|
|
202
|
-
const page = queryLabVerdicts({
|
|
203
|
-
subjectId,
|
|
204
|
-
layer,
|
|
205
|
-
suiteId,
|
|
206
|
-
verdict,
|
|
207
|
-
from,
|
|
208
|
-
to,
|
|
209
|
-
}, cursor, limit, configDir);
|
|
271
|
+
const page = queryLabVerdicts({ subjectId, layer, suiteId, verdict, from, to }, cursor, limit, configDir);
|
|
210
272
|
printData(page, wantsJson, verdictLines(page));
|
|
211
273
|
return;
|
|
212
274
|
}
|
|
@@ -231,52 +293,23 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
231
293
|
}
|
|
232
294
|
case "observations": {
|
|
233
295
|
const subjectId = takeOption(rest, "--subject");
|
|
234
|
-
const layer = takeEnumOption<EvidenceLayer>(
|
|
235
|
-
rest,
|
|
236
|
-
"--layer",
|
|
237
|
-
EVIDENCE_LAYERS,
|
|
238
|
-
"--layer must be a supported evidence layer",
|
|
239
|
-
);
|
|
296
|
+
const layer = takeEnumOption<EvidenceLayer>(rest, "--layer", EVIDENCE_LAYERS, "--layer must be a supported evidence layer");
|
|
240
297
|
const suiteId = takeOption(rest, "--suite");
|
|
241
298
|
const scenarioId = takeOption(rest, "--scenario");
|
|
242
|
-
const outcome = takeEnumOption<ObservationOutcome>(
|
|
243
|
-
|
|
244
|
-
"--outcome",
|
|
245
|
-
OUTCOMES,
|
|
246
|
-
"--outcome must be a supported observation outcome",
|
|
247
|
-
);
|
|
248
|
-
const executionMode = takeEnumOption<ExecutionMode>(
|
|
249
|
-
rest,
|
|
250
|
-
"--execution-mode",
|
|
251
|
-
EXECUTION_MODES,
|
|
252
|
-
"--execution-mode must be a supported execution mode",
|
|
253
|
-
);
|
|
299
|
+
const outcome = takeEnumOption<ObservationOutcome>(rest, "--outcome", OUTCOMES, "--outcome must be a supported observation outcome");
|
|
300
|
+
const executionMode = takeEnumOption<ExecutionMode>(rest, "--execution-mode", EXECUTION_MODES, "--execution-mode must be a supported execution mode");
|
|
254
301
|
const from = takeIntegerOption(rest, "--from", { min: 0 });
|
|
255
302
|
const to = takeIntegerOption(rest, "--to", { min: 0 });
|
|
256
303
|
assertRange(from, to);
|
|
257
304
|
const limit = takeIntegerOption(rest, "--limit", { min: 1 });
|
|
258
305
|
const cursor = takeOption(rest, "--cursor");
|
|
259
306
|
rejectArgs(rest, USAGE);
|
|
260
|
-
const page = queryLabObservations({
|
|
261
|
-
subjectId,
|
|
262
|
-
layer,
|
|
263
|
-
suiteId,
|
|
264
|
-
scenarioId,
|
|
265
|
-
outcome,
|
|
266
|
-
executionMode,
|
|
267
|
-
from,
|
|
268
|
-
to,
|
|
269
|
-
}, cursor, limit, configDir);
|
|
307
|
+
const page = queryLabObservations({ subjectId, layer, suiteId, scenarioId, outcome, executionMode, from, to }, cursor, limit, configDir);
|
|
270
308
|
printData(page, wantsJson, observationLines(page));
|
|
271
309
|
return;
|
|
272
310
|
}
|
|
273
311
|
case "events": {
|
|
274
|
-
const eventKind = takeEnumOption<LabEventKind>(
|
|
275
|
-
rest,
|
|
276
|
-
"--event-kind",
|
|
277
|
-
EVENT_KINDS,
|
|
278
|
-
"--event-kind must be a supported lab event kind",
|
|
279
|
-
);
|
|
312
|
+
const eventKind = takeEnumOption<LabEventKind>(rest, "--event-kind", EVENT_KINDS, "--event-kind must be a supported lab event kind");
|
|
280
313
|
const subjectId = takeOption(rest, "--subject");
|
|
281
314
|
const from = takeIntegerOption(rest, "--from", { min: 0 });
|
|
282
315
|
const to = takeIntegerOption(rest, "--to", { min: 0 });
|
|
@@ -309,18 +342,8 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
309
342
|
return;
|
|
310
343
|
}
|
|
311
344
|
case "artifacts": {
|
|
312
|
-
const status = takeEnumOption<ArtifactStatus>(
|
|
313
|
-
|
|
314
|
-
"--status",
|
|
315
|
-
ARTIFACT_STATUSES,
|
|
316
|
-
"--status must be present, corrupt, or purged_unavailable",
|
|
317
|
-
);
|
|
318
|
-
const artifactClass = takeEnumOption<ArtifactClass>(
|
|
319
|
-
rest,
|
|
320
|
-
"--artifact-class",
|
|
321
|
-
ARTIFACT_CLASSES,
|
|
322
|
-
"--artifact-class must be a supported artifact class",
|
|
323
|
-
);
|
|
345
|
+
const status = takeEnumOption<ArtifactStatus>(rest, "--status", ARTIFACT_STATUSES, "--status must be present, corrupt, or purged_unavailable");
|
|
346
|
+
const artifactClass = takeEnumOption<ArtifactClass>(rest, "--artifact-class", ARTIFACT_CLASSES, "--artifact-class must be a supported artifact class");
|
|
324
347
|
const limit = takeIntegerOption(rest, "--limit", { min: 1 });
|
|
325
348
|
const cursor = takeOption(rest, "--cursor");
|
|
326
349
|
rejectArgs(rest, USAGE);
|
|
@@ -339,18 +362,101 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
339
362
|
return;
|
|
340
363
|
}
|
|
341
364
|
case "catalog": {
|
|
342
|
-
const layer = takeEnumOption<EvidenceLayer>(
|
|
343
|
-
rest,
|
|
344
|
-
"--layer",
|
|
345
|
-
EVIDENCE_LAYERS,
|
|
346
|
-
"--layer must be a supported evidence layer",
|
|
347
|
-
);
|
|
365
|
+
const layer = takeEnumOption<EvidenceLayer>(rest, "--layer", EVIDENCE_LAYERS, "--layer must be a supported evidence layer");
|
|
348
366
|
const suiteId = takeOption(rest, "--suite");
|
|
349
367
|
rejectArgs(rest, USAGE);
|
|
350
368
|
const scenarios = queryLabCatalogEntries({ layer, suiteId });
|
|
351
369
|
printData({ scenarios }, wantsJson, catalogLines(scenarios));
|
|
352
370
|
return;
|
|
353
371
|
}
|
|
372
|
+
case "automation": {
|
|
373
|
+
const [automationSub = "status", ...automationRest] = rest;
|
|
374
|
+
switch (automationSub) {
|
|
375
|
+
case "status": {
|
|
376
|
+
rejectArgs(automationRest, USAGE);
|
|
377
|
+
const status = buildLabAutomationStatus(configDir);
|
|
378
|
+
printData(automationCliStatus(status), wantsJson, automationStatusLines(status));
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
case "enable": {
|
|
382
|
+
const enableProtocol = takeFlag(automationRest, "--protocol");
|
|
383
|
+
const enableLive = takeFlag(automationRest, "--live");
|
|
384
|
+
rejectArgs(automationRest, USAGE);
|
|
385
|
+
const selectionExplicit = enableProtocol || enableLive;
|
|
386
|
+
const current = loadLabAutomationConfig(configDir).policy;
|
|
387
|
+
const policy = {
|
|
388
|
+
...current,
|
|
389
|
+
enabled: true,
|
|
390
|
+
layers: {
|
|
391
|
+
protocolConformance: selectionExplicit ? enableProtocol : current.layers.protocolConformance,
|
|
392
|
+
liveRouteCompatibility: selectionExplicit ? enableLive : current.layers.liveRouteCompatibility,
|
|
393
|
+
taskEffectiveness: false,
|
|
394
|
+
},
|
|
395
|
+
taskEffectivenessBackgroundEnabled: false,
|
|
396
|
+
};
|
|
397
|
+
saveLabAutomationPolicyConfig(policy, configDir);
|
|
398
|
+
reconcileLabAutomationQueue(configDir);
|
|
399
|
+
startLabAutomationScheduler(configDir);
|
|
400
|
+
const status = buildLabAutomationStatus(configDir);
|
|
401
|
+
printData(automationCliStatus(status), wantsJson, automationStatusLines(status));
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
case "disable": {
|
|
405
|
+
rejectArgs(automationRest, USAGE);
|
|
406
|
+
const policy = { ...loadLabAutomationConfig(configDir).policy, enabled: false };
|
|
407
|
+
saveLabAutomationPolicyConfig(policy, configDir);
|
|
408
|
+
reconcileLabAutomationQueue(configDir);
|
|
409
|
+
stopLabAutomationScheduler(configDir);
|
|
410
|
+
const status = buildLabAutomationStatus(configDir);
|
|
411
|
+
printData(automationCliStatus(status), wantsJson, automationStatusLines(status));
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
case "runs": {
|
|
415
|
+
const limit = takeIntegerOption(automationRest, "--limit", { min: 1 });
|
|
416
|
+
const cursor = takeOption(automationRest, "--cursor");
|
|
417
|
+
rejectArgs(automationRest, USAGE);
|
|
418
|
+
const page = listLabAutomationRuns(loadLabAutomationState(configDir), limit ?? 50, cursor);
|
|
419
|
+
printData(page, wantsJson, runListLines(page));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
default:
|
|
423
|
+
throw new CliUsageError(`unknown automation subcommand: ${automationSub}`, USAGE);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
case "run": {
|
|
427
|
+
const layer = takeEnumOption<LabAutomationLayer>(
|
|
428
|
+
rest,
|
|
429
|
+
"--layer",
|
|
430
|
+
["protocol_conformance", "live_route_compatibility", "task_effectiveness"] as const,
|
|
431
|
+
"--layer must be protocol_conformance, live_route_compatibility, or task_effectiveness",
|
|
432
|
+
);
|
|
433
|
+
const scenarioId = takeOption(rest, "--scenario");
|
|
434
|
+
const providerName = takeOption(rest, "--provider");
|
|
435
|
+
const modelId = takeOption(rest, "--model");
|
|
436
|
+
rejectArgs(rest, USAGE);
|
|
437
|
+
if (!layer || !scenarioId) throw new CliUsageError("--layer and --scenario are required", USAGE);
|
|
438
|
+
const configSnapshot = readConfigDiagnostics().config;
|
|
439
|
+
if (layer === "live_route_compatibility") {
|
|
440
|
+
const loadConfig = () => configSnapshot;
|
|
441
|
+
setLabAutomationDispatchDeps({
|
|
442
|
+
configDir,
|
|
443
|
+
loadConfig,
|
|
444
|
+
routeExecutor: createProductionLabRouteExecutor({ configDir, loadConfig }),
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
const planned = planManualLabRun({
|
|
448
|
+
evidenceLayer: layer,
|
|
449
|
+
scenarioId,
|
|
450
|
+
providerName,
|
|
451
|
+
modelId,
|
|
452
|
+
config: configSnapshot,
|
|
453
|
+
configDir,
|
|
454
|
+
});
|
|
455
|
+
const record = await enqueueManualLabRun(planned, configDir);
|
|
456
|
+
if (!record) throw new CliUsageError("manual run enqueue failed", USAGE);
|
|
457
|
+
printData({ run: record }, wantsJson, [`Manual run ${record.runId} -> ${record.state}`]);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
354
460
|
default:
|
|
355
461
|
throw new CliUsageError(`unknown lab subcommand: ${sub}`, USAGE);
|
|
356
462
|
}
|
|
@@ -364,4 +470,4 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
|
|
|
364
470
|
});
|
|
365
471
|
}
|
|
366
472
|
|
|
367
|
-
export const LAB_USAGE = USAGE;
|
|
473
|
+
export const LAB_USAGE = USAGE;
|