codex-multi-auth 0.1.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/LICENSE +1 -0
- package/README.md +162 -0
- package/assets/opencode-logo-ornate-dark.svg +18 -0
- package/assets/readme-hero.svg +31 -0
- package/config/README.md +87 -0
- package/config/minimal-opencode.json +13 -0
- package/config/opencode-legacy.json +571 -0
- package/config/opencode-modern.json +239 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3160 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accounts/rate-limits.d.ts +22 -0
- package/dist/lib/accounts/rate-limits.d.ts.map +1 -0
- package/dist/lib/accounts/rate-limits.js +63 -0
- package/dist/lib/accounts/rate-limits.js.map +1 -0
- package/dist/lib/accounts.d.ts +95 -0
- package/dist/lib/accounts.d.ts.map +1 -0
- package/dist/lib/accounts.js +668 -0
- package/dist/lib/accounts.js.map +1 -0
- package/dist/lib/audit.d.ts +45 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +131 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +56 -0
- package/dist/lib/auth/auth.d.ts.map +1 -0
- package/dist/lib/auth/auth.js +214 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/browser.d.ts +34 -0
- package/dist/lib/auth/browser.d.ts.map +1 -0
- package/dist/lib/auth/browser.js +185 -0
- package/dist/lib/auth/browser.js.map +1 -0
- package/dist/lib/auth/server.d.ts +24 -0
- package/dist/lib/auth/server.d.ts.map +1 -0
- package/dist/lib/auth/server.js +116 -0
- package/dist/lib/auth/server.js.map +1 -0
- package/dist/lib/auth/token-utils.d.ts +59 -0
- package/dist/lib/auth/token-utils.d.ts.map +1 -0
- package/dist/lib/auth/token-utils.js +331 -0
- package/dist/lib/auth/token-utils.js.map +1 -0
- package/dist/lib/auth-rate-limit.d.ts +20 -0
- package/dist/lib/auth-rate-limit.d.ts.map +1 -0
- package/dist/lib/auth-rate-limit.js +91 -0
- package/dist/lib/auth-rate-limit.js.map +1 -0
- package/dist/lib/auto-update-checker.d.ts +10 -0
- package/dist/lib/auto-update-checker.d.ts.map +1 -0
- package/dist/lib/auto-update-checker.js +216 -0
- package/dist/lib/auto-update-checker.js.map +1 -0
- package/dist/lib/capability-policy.d.ts +18 -0
- package/dist/lib/capability-policy.d.ts.map +1 -0
- package/dist/lib/capability-policy.js +150 -0
- package/dist/lib/capability-policy.js.map +1 -0
- package/dist/lib/circuit-breaker.d.ts +34 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +124 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/cli.d.ts +64 -0
- package/dist/lib/cli.d.ts.map +1 -0
- package/dist/lib/cli.js +274 -0
- package/dist/lib/cli.js.map +1 -0
- package/dist/lib/codex-cli/observability.d.ts +22 -0
- package/dist/lib/codex-cli/observability.d.ts.map +1 -0
- package/dist/lib/codex-cli/observability.js +36 -0
- package/dist/lib/codex-cli/observability.js.map +1 -0
- package/dist/lib/codex-cli/state.d.ts +86 -0
- package/dist/lib/codex-cli/state.d.ts.map +1 -0
- package/dist/lib/codex-cli/state.js +470 -0
- package/dist/lib/codex-cli/state.js.map +1 -0
- package/dist/lib/codex-cli/sync.d.ts +27 -0
- package/dist/lib/codex-cli/sync.d.ts.map +1 -0
- package/dist/lib/codex-cli/sync.js +325 -0
- package/dist/lib/codex-cli/sync.js.map +1 -0
- package/dist/lib/codex-cli/writer.d.ts +12 -0
- package/dist/lib/codex-cli/writer.d.ts.map +1 -0
- package/dist/lib/codex-cli/writer.js +388 -0
- package/dist/lib/codex-cli/writer.js.map +1 -0
- package/dist/lib/codex-manager.d.ts +2 -0
- package/dist/lib/codex-manager.d.ts.map +1 -0
- package/dist/lib/codex-manager.js +4841 -0
- package/dist/lib/codex-manager.js.map +1 -0
- package/dist/lib/config.d.ts +269 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +789 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +78 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +78 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/context-overflow.d.ts +27 -0
- package/dist/lib/context-overflow.d.ts.map +1 -0
- package/dist/lib/context-overflow.js +124 -0
- package/dist/lib/context-overflow.js.map +1 -0
- package/dist/lib/dashboard-settings.d.ts +90 -0
- package/dist/lib/dashboard-settings.d.ts.map +1 -0
- package/dist/lib/dashboard-settings.js +327 -0
- package/dist/lib/dashboard-settings.js.map +1 -0
- package/dist/lib/entitlement-cache.d.ts +41 -0
- package/dist/lib/entitlement-cache.d.ts.map +1 -0
- package/dist/lib/entitlement-cache.js +137 -0
- package/dist/lib/entitlement-cache.js.map +1 -0
- package/dist/lib/errors.d.ts +113 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +103 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/forecast.d.ts +42 -0
- package/dist/lib/forecast.d.ts.map +1 -0
- package/dist/lib/forecast.js +256 -0
- package/dist/lib/forecast.js.map +1 -0
- package/dist/lib/health.d.ts +33 -0
- package/dist/lib/health.d.ts.map +1 -0
- package/dist/lib/health.js +70 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/index.d.ts +32 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +32 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/live-account-sync.d.ts +39 -0
- package/dist/lib/live-account-sync.d.ts.map +1 -0
- package/dist/lib/live-account-sync.js +196 -0
- package/dist/lib/live-account-sync.js.map +1 -0
- package/dist/lib/logger.d.ts +40 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +364 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/oauth-success.html +338 -0
- package/dist/lib/parallel-probe.d.ts +28 -0
- package/dist/lib/parallel-probe.d.ts.map +1 -0
- package/dist/lib/parallel-probe.js +97 -0
- package/dist/lib/parallel-probe.js.map +1 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts +53 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -0
- package/dist/lib/preemptive-quota-scheduler.js +220 -0
- package/dist/lib/preemptive-quota-scheduler.js.map +1 -0
- package/dist/lib/proactive-refresh.d.ts +66 -0
- package/dist/lib/proactive-refresh.d.ts.map +1 -0
- package/dist/lib/proactive-refresh.js +143 -0
- package/dist/lib/proactive-refresh.js.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts +19 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.js +169 -0
- package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
- package/dist/lib/prompts/codex.d.ts +41 -0
- package/dist/lib/prompts/codex.d.ts.map +1 -0
- package/dist/lib/prompts/codex.js +383 -0
- package/dist/lib/prompts/codex.js.map +1 -0
- package/dist/lib/prompts/opencode-codex.d.ts +25 -0
- package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
- package/dist/lib/prompts/opencode-codex.js +270 -0
- package/dist/lib/prompts/opencode-codex.js.map +1 -0
- package/dist/lib/quota-cache.d.ts +68 -0
- package/dist/lib/quota-cache.d.ts.map +1 -0
- package/dist/lib/quota-cache.js +224 -0
- package/dist/lib/quota-cache.js.map +1 -0
- package/dist/lib/quota-probe.d.ts +49 -0
- package/dist/lib/quota-probe.d.ts.map +1 -0
- package/dist/lib/quota-probe.js +368 -0
- package/dist/lib/quota-probe.js.map +1 -0
- package/dist/lib/recovery/constants.d.ts +12 -0
- package/dist/lib/recovery/constants.d.ts.map +1 -0
- package/dist/lib/recovery/constants.js +31 -0
- package/dist/lib/recovery/constants.js.map +1 -0
- package/dist/lib/recovery/index.d.ts +12 -0
- package/dist/lib/recovery/index.d.ts.map +1 -0
- package/dist/lib/recovery/index.js +12 -0
- package/dist/lib/recovery/index.js.map +1 -0
- package/dist/lib/recovery/storage.d.ts +24 -0
- package/dist/lib/recovery/storage.d.ts.map +1 -0
- package/dist/lib/recovery/storage.js +362 -0
- package/dist/lib/recovery/storage.js.map +1 -0
- package/dist/lib/recovery/types.d.ts +116 -0
- package/dist/lib/recovery/types.d.ts.map +1 -0
- package/dist/lib/recovery/types.js +7 -0
- package/dist/lib/recovery/types.js.map +1 -0
- package/dist/lib/recovery.d.ts +31 -0
- package/dist/lib/recovery.d.ts.map +1 -0
- package/dist/lib/recovery.js +313 -0
- package/dist/lib/recovery.js.map +1 -0
- package/dist/lib/refresh-guardian.d.ts +31 -0
- package/dist/lib/refresh-guardian.d.ts.map +1 -0
- package/dist/lib/refresh-guardian.js +151 -0
- package/dist/lib/refresh-guardian.js.map +1 -0
- package/dist/lib/refresh-lease.d.ts +37 -0
- package/dist/lib/refresh-lease.d.ts.map +1 -0
- package/dist/lib/refresh-lease.js +335 -0
- package/dist/lib/refresh-lease.js.map +1 -0
- package/dist/lib/refresh-queue.d.ts +117 -0
- package/dist/lib/refresh-queue.d.ts.map +1 -0
- package/dist/lib/refresh-queue.js +297 -0
- package/dist/lib/refresh-queue.js.map +1 -0
- package/dist/lib/request/failure-policy.d.ts +42 -0
- package/dist/lib/request/failure-policy.d.ts.map +1 -0
- package/dist/lib/request/failure-policy.js +133 -0
- package/dist/lib/request/failure-policy.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +152 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/request/fetch-helpers.js +704 -0
- package/dist/lib/request/fetch-helpers.js.map +1 -0
- package/dist/lib/request/helpers/input-utils.d.ts +7 -0
- package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/input-utils.js +214 -0
- package/dist/lib/request/helpers/input-utils.js.map +1 -0
- package/dist/lib/request/helpers/model-map.d.ts +28 -0
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
- package/dist/lib/request/helpers/model-map.js +133 -0
- package/dist/lib/request/helpers/model-map.js.map +1 -0
- package/dist/lib/request/helpers/tool-utils.d.ts +29 -0
- package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/tool-utils.js +117 -0
- package/dist/lib/request/helpers/tool-utils.js.map +1 -0
- package/dist/lib/request/rate-limit-backoff.d.ts +17 -0
- package/dist/lib/request/rate-limit-backoff.d.ts.map +1 -0
- package/dist/lib/request/rate-limit-backoff.js +83 -0
- package/dist/lib/request/rate-limit-backoff.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +107 -0
- package/dist/lib/request/request-transformer.d.ts.map +1 -0
- package/dist/lib/request/request-transformer.js +814 -0
- package/dist/lib/request/request-transformer.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +23 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -0
- package/dist/lib/request/response-handler.js +155 -0
- package/dist/lib/request/response-handler.js.map +1 -0
- package/dist/lib/request/stream-failover.d.ts +21 -0
- package/dist/lib/request/stream-failover.d.ts.map +1 -0
- package/dist/lib/request/stream-failover.js +204 -0
- package/dist/lib/request/stream-failover.js.map +1 -0
- package/dist/lib/rotation.d.ts +146 -0
- package/dist/lib/rotation.d.ts.map +1 -0
- package/dist/lib/rotation.js +321 -0
- package/dist/lib/rotation.js.map +1 -0
- package/dist/lib/runtime-paths.d.ts +58 -0
- package/dist/lib/runtime-paths.d.ts.map +1 -0
- package/dist/lib/runtime-paths.js +164 -0
- package/dist/lib/runtime-paths.js.map +1 -0
- package/dist/lib/schemas.d.ts +435 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/lib/schemas.js +268 -0
- package/dist/lib/schemas.js.map +1 -0
- package/dist/lib/session-affinity.d.ts +23 -0
- package/dist/lib/session-affinity.d.ts.map +1 -0
- package/dist/lib/session-affinity.js +127 -0
- package/dist/lib/session-affinity.js.map +1 -0
- package/dist/lib/shutdown.d.ts +7 -0
- package/dist/lib/shutdown.d.ts.map +1 -0
- package/dist/lib/shutdown.js +43 -0
- package/dist/lib/shutdown.js.map +1 -0
- package/dist/lib/storage/migrations.d.ts +59 -0
- package/dist/lib/storage/migrations.d.ts.map +1 -0
- package/dist/lib/storage/migrations.js +41 -0
- package/dist/lib/storage/migrations.js.map +1 -0
- package/dist/lib/storage/paths.d.ts +51 -0
- package/dist/lib/storage/paths.d.ts.map +1 -0
- package/dist/lib/storage/paths.js +152 -0
- package/dist/lib/storage/paths.js.map +1 -0
- package/dist/lib/storage.d.ts +106 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/storage.js +896 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/lib/table-formatter.d.ts +32 -0
- package/dist/lib/table-formatter.d.ts.map +1 -0
- package/dist/lib/table-formatter.js +44 -0
- package/dist/lib/table-formatter.js.map +1 -0
- package/dist/lib/tools/hashline-tools.d.ts +51 -0
- package/dist/lib/tools/hashline-tools.d.ts.map +1 -0
- package/dist/lib/tools/hashline-tools.js +456 -0
- package/dist/lib/tools/hashline-tools.js.map +1 -0
- package/dist/lib/types.d.ts +130 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/ui/ansi.d.ts +40 -0
- package/dist/lib/ui/ansi.d.ts.map +1 -0
- package/dist/lib/ui/ansi.js +68 -0
- package/dist/lib/ui/ansi.js.map +1 -0
- package/dist/lib/ui/auth-menu.d.ts +76 -0
- package/dist/lib/ui/auth-menu.d.ts.map +1 -0
- package/dist/lib/ui/auth-menu.js +590 -0
- package/dist/lib/ui/auth-menu.js.map +1 -0
- package/dist/lib/ui/confirm.d.ts +11 -0
- package/dist/lib/ui/confirm.d.ts.map +1 -0
- package/dist/lib/ui/confirm.js +29 -0
- package/dist/lib/ui/confirm.js.map +1 -0
- package/dist/lib/ui/copy.d.ts +123 -0
- package/dist/lib/ui/copy.d.ts.map +1 -0
- package/dist/lib/ui/copy.js +127 -0
- package/dist/lib/ui/copy.js.map +1 -0
- package/dist/lib/ui/format.d.ts +62 -0
- package/dist/lib/ui/format.d.ts.map +1 -0
- package/dist/lib/ui/format.js +205 -0
- package/dist/lib/ui/format.js.map +1 -0
- package/dist/lib/ui/runtime.d.ts +43 -0
- package/dist/lib/ui/runtime.d.ts.map +1 -0
- package/dist/lib/ui/runtime.js +69 -0
- package/dist/lib/ui/runtime.js.map +1 -0
- package/dist/lib/ui/select.d.ts +60 -0
- package/dist/lib/ui/select.d.ts.map +1 -0
- package/dist/lib/ui/select.js +467 -0
- package/dist/lib/ui/select.js.map +1 -0
- package/dist/lib/ui/theme.d.ts +56 -0
- package/dist/lib/ui/theme.d.ts.map +1 -0
- package/dist/lib/ui/theme.js +186 -0
- package/dist/lib/ui/theme.js.map +1 -0
- package/dist/lib/unified-settings.d.ts +71 -0
- package/dist/lib/unified-settings.d.ts.map +1 -0
- package/dist/lib/unified-settings.js +299 -0
- package/dist/lib/unified-settings.js.map +1 -0
- package/dist/lib/utils.d.ts +29 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +54 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +115 -0
- package/scripts/audit-dev-allowlist.js +128 -0
- package/scripts/bench-format/hashline-v2.mjs +642 -0
- package/scripts/bench-format/models.mjs +105 -0
- package/scripts/bench-format/opencode.mjs +205 -0
- package/scripts/bench-format/render.mjs +496 -0
- package/scripts/bench-format/stats.mjs +54 -0
- package/scripts/bench-format/tasks.mjs +151 -0
- package/scripts/benchmark-edit-formats.mjs +1161 -0
- package/scripts/benchmark-render-dashboard.mjs +49 -0
- package/scripts/codex-multi-auth.js +6 -0
- package/scripts/codex-routing.js +34 -0
- package/scripts/codex.js +122 -0
- package/scripts/copy-oauth-success.js +37 -0
- package/scripts/install-opencode-codex-auth.js +193 -0
- package/scripts/test-all-models.sh +7 -0
- package/scripts/test-model-matrix.js +424 -0
- package/scripts/validate-model-map.sh +7 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { readFile, writeFile, rm, mkdir } from "node:fs/promises";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import process from "node:process";
|
|
9
|
+
|
|
10
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const repoRoot = resolve(scriptDir, "..");
|
|
12
|
+
const localConfigPaths = [join(repoRoot, ".opencode.json"), join(repoRoot, "opencode.json")];
|
|
13
|
+
const scenarioTemplates = {
|
|
14
|
+
legacy: join(repoRoot, "config", "opencode-legacy.json"),
|
|
15
|
+
modern: join(repoRoot, "config", "opencode-modern.json"),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const defaultPromptPrefix = "Reply exactly:";
|
|
19
|
+
const modelProviderId = "openai";
|
|
20
|
+
const pluginPackageName = "codex-multi-auth";
|
|
21
|
+
|
|
22
|
+
function resolveOpencodeExecutable() {
|
|
23
|
+
const envOverride = process.env.OPENCODE_BIN;
|
|
24
|
+
if (envOverride && envOverride.trim().length > 0) {
|
|
25
|
+
const command = envOverride.trim();
|
|
26
|
+
return { command, shell: /\.cmd$/i.test(command) };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (process.platform !== "win32") {
|
|
30
|
+
return { command: "opencode", shell: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const whereResult = spawnSync("where", ["opencode"], {
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
windowsHide: true,
|
|
36
|
+
});
|
|
37
|
+
const candidates = `${whereResult.stdout ?? ""}\n${whereResult.stderr ?? ""}`
|
|
38
|
+
.split(/\r?\n/)
|
|
39
|
+
.map((line) => line.trim())
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
|
|
42
|
+
if (candidates.length === 0) {
|
|
43
|
+
return { command: "opencode", shell: false };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const exactExe = candidates.find((candidate) =>
|
|
47
|
+
/npm\\opencode\.exe$/i.test(candidate),
|
|
48
|
+
);
|
|
49
|
+
if (exactExe) {
|
|
50
|
+
return { command: exactExe, shell: false };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const exactCmd = candidates.find((candidate) =>
|
|
54
|
+
/npm\\opencode\.cmd$/i.test(candidate),
|
|
55
|
+
);
|
|
56
|
+
if (exactCmd) {
|
|
57
|
+
return { command: exactCmd, shell: true };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const anyCmd = candidates.find((candidate) => /\.cmd$/i.test(candidate));
|
|
61
|
+
if (anyCmd) {
|
|
62
|
+
return { command: anyCmd, shell: true };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { command: candidates[0], shell: false };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const opencodeExecutable = resolveOpencodeExecutable();
|
|
69
|
+
|
|
70
|
+
function printUsage() {
|
|
71
|
+
console.log(
|
|
72
|
+
[
|
|
73
|
+
"Usage: node scripts/test-model-matrix.js [options]",
|
|
74
|
+
"",
|
|
75
|
+
"Options:",
|
|
76
|
+
" --scenario=legacy|modern|all Which template(s) to audit (default: all)",
|
|
77
|
+
" --smoke Run reduced per-model checks",
|
|
78
|
+
" --plugin=dist|package Load plugin from local dist URI or package name (default: dist)",
|
|
79
|
+
" --max-cases=N Hard cap number of cases per scenario",
|
|
80
|
+
" --report-json=PATH Write JSON report to PATH (relative to repo root)",
|
|
81
|
+
" --no-restore Keep generated local config files after run",
|
|
82
|
+
" -h, --help Show help",
|
|
83
|
+
].join("\n"),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseArgValue(args, name) {
|
|
88
|
+
const prefix = `${name}=`;
|
|
89
|
+
const hit = args.find((arg) => arg.startsWith(prefix));
|
|
90
|
+
if (!hit) return undefined;
|
|
91
|
+
return hit.slice(prefix.length);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function toFileUri(pathValue) {
|
|
95
|
+
const normalized = pathValue.replace(/\\/g, "/");
|
|
96
|
+
if (/^[A-Za-z]:\//.test(normalized)) {
|
|
97
|
+
return `file:///${normalized}`;
|
|
98
|
+
}
|
|
99
|
+
if (normalized.startsWith("/")) {
|
|
100
|
+
return `file://${normalized}`;
|
|
101
|
+
}
|
|
102
|
+
return `file:///${normalized}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function runQuiet(command, commandArgs) {
|
|
106
|
+
try {
|
|
107
|
+
spawnSync(command, commandArgs, {
|
|
108
|
+
stdio: "ignore",
|
|
109
|
+
windowsHide: true,
|
|
110
|
+
});
|
|
111
|
+
} catch {
|
|
112
|
+
// Ignore cleanup failures.
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function stopOpencodeServers() {
|
|
117
|
+
if (process.platform === "win32") {
|
|
118
|
+
runQuiet("taskkill", ["/F", "/IM", "opencode.exe"]);
|
|
119
|
+
}
|
|
120
|
+
runQuiet("pkill", ["-f", "opencode"]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizePluginList(value, pluginRef) {
|
|
124
|
+
const entries = Array.isArray(value) ? value.filter(Boolean) : [];
|
|
125
|
+
const filtered = entries.filter((entry) => {
|
|
126
|
+
if (typeof entry !== "string") return true;
|
|
127
|
+
return !entry.startsWith(pluginPackageName);
|
|
128
|
+
});
|
|
129
|
+
return [...filtered, pluginRef];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function enumerateCases(models, smoke, maxCases) {
|
|
133
|
+
const modelEntries = Object.entries(models).sort(([left], [right]) =>
|
|
134
|
+
left.localeCompare(right),
|
|
135
|
+
);
|
|
136
|
+
const cases = [];
|
|
137
|
+
|
|
138
|
+
for (const [modelId, modelDef] of modelEntries) {
|
|
139
|
+
const variants =
|
|
140
|
+
modelDef && typeof modelDef === "object" && modelDef !== null
|
|
141
|
+
? modelDef.variants
|
|
142
|
+
: undefined;
|
|
143
|
+
const variantNames =
|
|
144
|
+
variants && typeof variants === "object"
|
|
145
|
+
? Object.keys(variants).sort()
|
|
146
|
+
: [];
|
|
147
|
+
|
|
148
|
+
cases.push({ model: modelId, variant: undefined });
|
|
149
|
+
for (const variant of variantNames) {
|
|
150
|
+
cases.push({ model: modelId, variant });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let selected = cases;
|
|
155
|
+
if (smoke) {
|
|
156
|
+
const reduced = [];
|
|
157
|
+
for (const [modelId, modelDef] of modelEntries) {
|
|
158
|
+
reduced.push({ model: modelId, variant: undefined });
|
|
159
|
+
const variants =
|
|
160
|
+
modelDef && typeof modelDef === "object" && modelDef !== null
|
|
161
|
+
? modelDef.variants
|
|
162
|
+
: undefined;
|
|
163
|
+
const variantNames =
|
|
164
|
+
variants && typeof variants === "object"
|
|
165
|
+
? Object.keys(variants).sort()
|
|
166
|
+
: [];
|
|
167
|
+
if (variantNames.length > 0) {
|
|
168
|
+
if (variantNames.includes("high")) {
|
|
169
|
+
reduced.push({ model: modelId, variant: "high" });
|
|
170
|
+
} else if (variantNames.includes("medium")) {
|
|
171
|
+
reduced.push({ model: modelId, variant: "medium" });
|
|
172
|
+
} else {
|
|
173
|
+
reduced.push({ model: modelId, variant: variantNames[0] });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
selected = reduced;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (maxCases > 0 && selected.length > maxCases) {
|
|
181
|
+
return selected.slice(0, maxCases);
|
|
182
|
+
}
|
|
183
|
+
return selected;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function executeModelCase(caseInfo, index, port) {
|
|
187
|
+
const token = `MODEL_MATRIX_OK_${index}`;
|
|
188
|
+
const message = `${defaultPromptPrefix} ${token}`;
|
|
189
|
+
const args = [
|
|
190
|
+
"run",
|
|
191
|
+
message,
|
|
192
|
+
"--model",
|
|
193
|
+
`${modelProviderId}/${caseInfo.model}`,
|
|
194
|
+
"--port",
|
|
195
|
+
String(port),
|
|
196
|
+
];
|
|
197
|
+
if (caseInfo.variant) {
|
|
198
|
+
args.push("--variant", caseInfo.variant);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const finalized = spawnSync(opencodeExecutable.command, args, {
|
|
202
|
+
cwd: repoRoot,
|
|
203
|
+
encoding: "utf8",
|
|
204
|
+
windowsHide: true,
|
|
205
|
+
shell: opencodeExecutable.shell,
|
|
206
|
+
env: {
|
|
207
|
+
...process.env,
|
|
208
|
+
ENABLE_PLUGIN_REQUEST_LOGGING: "0",
|
|
209
|
+
CODEX_PLUGIN_LOG_BODIES: "0",
|
|
210
|
+
DEBUG_CODEX_PLUGIN: "0",
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const combinedOutput = `${finalized.stdout ?? ""}\n${finalized.stderr ?? ""}`.trim();
|
|
215
|
+
const hasToken = combinedOutput.includes(token);
|
|
216
|
+
const hasFatalError = /ProviderModelNotFoundError|Model not found/i.test(combinedOutput);
|
|
217
|
+
const exitCode = finalized.status ?? 1;
|
|
218
|
+
const ok = exitCode === 0 && hasToken && !hasFatalError;
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
...caseInfo,
|
|
222
|
+
ok,
|
|
223
|
+
exitCode,
|
|
224
|
+
hasToken,
|
|
225
|
+
output: combinedOutput,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function readJson(pathValue) {
|
|
230
|
+
return JSON.parse(await readFile(pathValue, "utf8"));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function writeJson(pathValue, value) {
|
|
234
|
+
await writeFile(pathValue, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function backupLocalConfigs() {
|
|
238
|
+
const backups = new Map();
|
|
239
|
+
for (const configPath of localConfigPaths) {
|
|
240
|
+
if (existsSync(configPath)) {
|
|
241
|
+
backups.set(configPath, await readFile(configPath, "utf8"));
|
|
242
|
+
} else {
|
|
243
|
+
backups.set(configPath, null);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return backups;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function restoreLocalConfigs(backups) {
|
|
250
|
+
for (const [configPath, content] of backups.entries()) {
|
|
251
|
+
if (content === null) {
|
|
252
|
+
if (existsSync(configPath)) {
|
|
253
|
+
await rm(configPath, { force: true });
|
|
254
|
+
}
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
await writeFile(configPath, content, "utf8");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function resolvePluginReference(mode) {
|
|
262
|
+
if (mode === "package") {
|
|
263
|
+
return pluginPackageName;
|
|
264
|
+
}
|
|
265
|
+
const distEntry = join(repoRoot, "dist", "index.js");
|
|
266
|
+
if (!existsSync(distEntry)) {
|
|
267
|
+
throw new Error(
|
|
268
|
+
`dist build missing at ${distEntry}. Run 'npm run build' before matrix audit.`,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return toFileUri(join(repoRoot, "dist"));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function prepareScenarioConfig(templatePath, pluginRef) {
|
|
275
|
+
const config = await readJson(templatePath);
|
|
276
|
+
config.plugin = normalizePluginList(config.plugin, pluginRef);
|
|
277
|
+
for (const configPath of localConfigPaths) {
|
|
278
|
+
await writeJson(configPath, config);
|
|
279
|
+
}
|
|
280
|
+
return config;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function runScenario(scenario, options) {
|
|
284
|
+
const templatePath = scenarioTemplates[scenario];
|
|
285
|
+
if (!templatePath || !existsSync(templatePath)) {
|
|
286
|
+
throw new Error(`Template not found for scenario '${scenario}': ${templatePath}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const config = await prepareScenarioConfig(templatePath, options.pluginRef);
|
|
290
|
+
const models = config?.provider?.openai?.models;
|
|
291
|
+
if (!models || typeof models !== "object") {
|
|
292
|
+
throw new Error(`Scenario '${scenario}' has no provider.openai.models object`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const cases = enumerateCases(models, options.smoke, options.maxCases);
|
|
296
|
+
console.log(`\n=== ${scenario.toUpperCase()} (${cases.length} cases) ===`);
|
|
297
|
+
|
|
298
|
+
const results = [];
|
|
299
|
+
for (let i = 0; i < cases.length; i += 1) {
|
|
300
|
+
const caseInfo = cases[i];
|
|
301
|
+
const result = executeModelCase(
|
|
302
|
+
caseInfo,
|
|
303
|
+
i + 1,
|
|
304
|
+
options.portStart + i,
|
|
305
|
+
);
|
|
306
|
+
results.push(result);
|
|
307
|
+
const variantLabel = result.variant ? ` [variant=${result.variant}]` : "";
|
|
308
|
+
if (result.ok) {
|
|
309
|
+
console.log(`PASS ${result.model}${variantLabel}`);
|
|
310
|
+
} else {
|
|
311
|
+
console.log(`FAIL ${result.model}${variantLabel} (exit=${result.exitCode}, token=${result.hasToken})`);
|
|
312
|
+
const tail = result.output.split(/\r?\n/).slice(-12).join("\n");
|
|
313
|
+
if (tail.trim().length > 0) {
|
|
314
|
+
console.log(tail);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return results;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function main() {
|
|
323
|
+
const args = process.argv.slice(2);
|
|
324
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
325
|
+
printUsage();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const scenarioValue = parseArgValue(args, "--scenario") ?? "all";
|
|
330
|
+
const smoke = args.includes("--smoke");
|
|
331
|
+
const pluginMode = parseArgValue(args, "--plugin") ?? "dist";
|
|
332
|
+
const noRestore = args.includes("--no-restore");
|
|
333
|
+
const maxCasesRaw = parseArgValue(args, "--max-cases");
|
|
334
|
+
const maxCases = maxCasesRaw ? Number.parseInt(maxCasesRaw, 10) : 0;
|
|
335
|
+
const reportJsonPathRaw = parseArgValue(args, "--report-json");
|
|
336
|
+
const reportJsonPath = reportJsonPathRaw
|
|
337
|
+
? resolve(repoRoot, reportJsonPathRaw)
|
|
338
|
+
: undefined;
|
|
339
|
+
|
|
340
|
+
if (!["all", "legacy", "modern"].includes(scenarioValue)) {
|
|
341
|
+
throw new Error(`Invalid --scenario value '${scenarioValue}'. Use legacy, modern, or all.`);
|
|
342
|
+
}
|
|
343
|
+
if (!["dist", "package"].includes(pluginMode)) {
|
|
344
|
+
throw new Error(`Invalid --plugin value '${pluginMode}'. Use dist or package.`);
|
|
345
|
+
}
|
|
346
|
+
if (Number.isNaN(maxCases) || maxCases < 0) {
|
|
347
|
+
throw new Error(`Invalid --max-cases value '${maxCasesRaw}'. Use a non-negative integer.`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const pluginRef = resolvePluginReference(pluginMode);
|
|
351
|
+
const scenarios =
|
|
352
|
+
scenarioValue === "all" ? ["legacy", "modern"] : [scenarioValue];
|
|
353
|
+
|
|
354
|
+
console.log("OpenCode Model Matrix Audit");
|
|
355
|
+
console.log(`Repo: ${repoRoot}`);
|
|
356
|
+
console.log(`Scenarios: ${scenarios.join(", ")}`);
|
|
357
|
+
console.log(`Mode: ${smoke ? "smoke" : "full"}`);
|
|
358
|
+
console.log(`Plugin: ${pluginRef}`);
|
|
359
|
+
console.log(`OpenCode command: ${opencodeExecutable.command}`);
|
|
360
|
+
|
|
361
|
+
const backups = await backupLocalConfigs();
|
|
362
|
+
const allResults = [];
|
|
363
|
+
try {
|
|
364
|
+
for (let i = 0; i < scenarios.length; i += 1) {
|
|
365
|
+
const scenario = scenarios[i];
|
|
366
|
+
stopOpencodeServers();
|
|
367
|
+
const scenarioResults = await runScenario(scenario, {
|
|
368
|
+
smoke,
|
|
369
|
+
maxCases,
|
|
370
|
+
pluginRef,
|
|
371
|
+
portStart: 47000 + i * 500,
|
|
372
|
+
});
|
|
373
|
+
allResults.push(...scenarioResults.map((item) => ({ ...item, scenario })));
|
|
374
|
+
}
|
|
375
|
+
} finally {
|
|
376
|
+
if (!noRestore) {
|
|
377
|
+
await restoreLocalConfigs(backups);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const failed = allResults.filter((result) => !result.ok);
|
|
382
|
+
const passed = allResults.length - failed.length;
|
|
383
|
+
console.log("\n=== SUMMARY ===");
|
|
384
|
+
console.log(`Total: ${allResults.length}`);
|
|
385
|
+
console.log(`Passed: ${passed}`);
|
|
386
|
+
console.log(`Failed: ${failed.length}`);
|
|
387
|
+
|
|
388
|
+
if (reportJsonPath) {
|
|
389
|
+
const report = {
|
|
390
|
+
generatedAt: new Date().toISOString(),
|
|
391
|
+
repoRoot,
|
|
392
|
+
scenarios,
|
|
393
|
+
mode: smoke ? "smoke" : "full",
|
|
394
|
+
plugin: pluginRef,
|
|
395
|
+
opencodeCommand: opencodeExecutable.command,
|
|
396
|
+
totals: {
|
|
397
|
+
total: allResults.length,
|
|
398
|
+
passed,
|
|
399
|
+
failed: failed.length,
|
|
400
|
+
},
|
|
401
|
+
results: allResults,
|
|
402
|
+
};
|
|
403
|
+
await mkdir(dirname(reportJsonPath), { recursive: true });
|
|
404
|
+
await writeFile(reportJsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
405
|
+
console.log(`Report written: ${reportJsonPath}`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (failed.length > 0) {
|
|
409
|
+
console.log("\nFailed cases:");
|
|
410
|
+
for (const result of failed) {
|
|
411
|
+
const variantLabel = result.variant ? ` [variant=${result.variant}]` : "";
|
|
412
|
+
console.log(`- ${result.scenario}: ${result.model}${variantLabel}`);
|
|
413
|
+
}
|
|
414
|
+
process.exitCode = 1;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
main().catch((error) => {
|
|
419
|
+
console.error(
|
|
420
|
+
`Model matrix audit failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
421
|
+
);
|
|
422
|
+
process.exit(1);
|
|
423
|
+
});
|
|
424
|
+
|