open-multi-agent-kit 0.90.5 → 0.90.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +9 -9
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/codexbar-cli.d.ts +39 -0
  7. package/dist/codexbar-cli.d.ts.map +1 -0
  8. package/dist/codexbar-cli.js +230 -0
  9. package/dist/codexbar-cli.js.map +1 -0
  10. package/dist/commands/doctor-provider.d.ts.map +1 -1
  11. package/dist/commands/doctor-provider.js +16 -3
  12. package/dist/commands/doctor-provider.js.map +1 -1
  13. package/dist/core/agent-session.d.ts.map +1 -1
  14. package/dist/core/agent-session.js +30 -8
  15. package/dist/core/agent-session.js.map +1 -1
  16. package/dist/core/codexbar-adapter.d.ts +44 -0
  17. package/dist/core/codexbar-adapter.d.ts.map +1 -0
  18. package/dist/core/codexbar-adapter.js +211 -0
  19. package/dist/core/codexbar-adapter.js.map +1 -0
  20. package/dist/core/compaction/index.d.ts +2 -0
  21. package/dist/core/compaction/index.d.ts.map +1 -1
  22. package/dist/core/compaction/index.js +2 -0
  23. package/dist/core/compaction/index.js.map +1 -1
  24. package/dist/core/compaction/model-policy.d.ts +9 -0
  25. package/dist/core/compaction/model-policy.d.ts.map +1 -0
  26. package/dist/core/compaction/model-policy.js +37 -0
  27. package/dist/core/compaction/model-policy.js.map +1 -0
  28. package/dist/core/compaction/resume-policy.d.ts +6 -0
  29. package/dist/core/compaction/resume-policy.d.ts.map +1 -0
  30. package/dist/core/compaction/resume-policy.js +8 -0
  31. package/dist/core/compaction/resume-policy.js.map +1 -0
  32. package/dist/core/domain-loadouts.d.ts.map +1 -1
  33. package/dist/core/domain-loadouts.js +68 -1
  34. package/dist/core/domain-loadouts.js.map +1 -1
  35. package/dist/core/extensions/loader.d.ts.map +1 -1
  36. package/dist/core/extensions/loader.js +12 -0
  37. package/dist/core/extensions/loader.js.map +1 -1
  38. package/dist/core/extensions/runner.d.ts.map +1 -1
  39. package/dist/core/extensions/runner.js +3 -0
  40. package/dist/core/extensions/runner.js.map +1 -1
  41. package/dist/core/extensions/types.d.ts +15 -0
  42. package/dist/core/extensions/types.d.ts.map +1 -1
  43. package/dist/core/extensions/types.js.map +1 -1
  44. package/dist/core/grok-harness-dispatch.d.ts +22 -0
  45. package/dist/core/grok-harness-dispatch.d.ts.map +1 -0
  46. package/dist/core/grok-harness-dispatch.js +44 -0
  47. package/dist/core/grok-harness-dispatch.js.map +1 -0
  48. package/dist/core/grok-harness.d.ts +25 -0
  49. package/dist/core/grok-harness.d.ts.map +1 -0
  50. package/dist/core/grok-harness.js +61 -0
  51. package/dist/core/grok-harness.js.map +1 -0
  52. package/dist/core/grok-playbook.d.ts +7 -0
  53. package/dist/core/grok-playbook.d.ts.map +1 -0
  54. package/dist/core/grok-playbook.js +34 -0
  55. package/dist/core/grok-playbook.js.map +1 -0
  56. package/dist/core/sdk.d.ts.map +1 -1
  57. package/dist/core/sdk.js +31 -12
  58. package/dist/core/sdk.js.map +1 -1
  59. package/dist/main.d.ts.map +1 -1
  60. package/dist/main.js +4 -0
  61. package/dist/main.js.map +1 -1
  62. package/dist/utils/tools-manager.d.ts +3 -2
  63. package/dist/utils/tools-manager.d.ts.map +1 -1
  64. package/dist/utils/tools-manager.js +42 -17
  65. package/dist/utils/tools-manager.js.map +1 -1
  66. package/docs/correctness-wall.md +117 -0
  67. package/docs/grok-harness.md +63 -0
  68. package/docs/loadout-domains/README.md +2 -1
  69. package/docs/loadout-domains/ai-agent-ops.md +8 -1
  70. package/docs/loadout-domains/grok-harness.md +74 -0
  71. package/docs/providers.md +4 -0
  72. package/examples/extensions/correctness-wall/LOADOUT.md +87 -0
  73. package/examples/extensions/correctness-wall/README.md +111 -0
  74. package/examples/extensions/correctness-wall/adjudication-fixture.ts +151 -0
  75. package/examples/extensions/correctness-wall/index.ts +470 -0
  76. package/examples/extensions/correctness-wall/repair-state.ts +77 -0
  77. package/examples/extensions/correctness-wall/wall-cache.ts +81 -0
  78. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  79. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  80. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  81. package/examples/extensions/gondolin/package-lock.json +2 -2
  82. package/examples/extensions/gondolin/package.json +1 -1
  83. package/examples/extensions/sandbox/package-lock.json +2 -2
  84. package/examples/extensions/sandbox/package.json +1 -1
  85. package/examples/extensions/with-deps/package-lock.json +2 -2
  86. package/examples/extensions/with-deps/package.json +1 -1
  87. package/npm-shrinkwrap.json +12 -12
  88. package/package.json +5 -5
@@ -0,0 +1,230 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import chalk from "chalk";
4
+ import { APP_NAME, getAgentDir } from "./config.js";
5
+ import { CodexBarJsonError, CodexBarUnsafeOutputError, parseCodexBarCostJson, parseCodexBarUsageJson, } from "./core/codexbar-adapter.js";
6
+ import { spawnProcessSync } from "./utils/child-process.js";
7
+ import { ensureTool } from "./utils/tools-manager.js";
8
+ const CONNECTOR_FILE = "codexbar-connector.json";
9
+ const PRIVACY_ACK_VERSION = 1;
10
+ const USAGE = `${APP_NAME} quota <connect|disconnect|status|usage|cost> ...`;
11
+ const DEFAULT_DEPS = {
12
+ getAgentDir,
13
+ exists: existsSync,
14
+ read: (path) => readFileSync(path, "utf8"),
15
+ write: (path, value) => writeFileSync(path, value, "utf8"),
16
+ mkdir: (path) => mkdirSync(path, { recursive: true }),
17
+ remove: (path) => rmSync(path, { force: true }),
18
+ ensure: ensureTool,
19
+ spawn: (command, args) => spawnProcessSync(command, [...args], { encoding: "utf8", stdio: "pipe", shell: false, windowsHide: true }),
20
+ stdout: (text) => process.stdout.write(text),
21
+ stderr: (text) => process.stderr.write(text),
22
+ };
23
+ export function parseCodexBarQuotaCommand(args) {
24
+ if (args[0] !== "quota")
25
+ return undefined;
26
+ const subcommand = args[1];
27
+ const rest = args.slice(2);
28
+ if (subcommand === undefined)
29
+ return { kind: "error", message: "Missing quota command." };
30
+ if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
31
+ return rest.length === 0 ? { kind: "help" } : { kind: "error", message: "Unexpected argument." };
32
+ }
33
+ if (subcommand === "connect" || subcommand === "disconnect") {
34
+ if (rest[0] === undefined)
35
+ return { kind: "error", message: `Missing target for quota ${subcommand}. Expected codexbar.` };
36
+ if (rest[0] !== "codexbar")
37
+ return { kind: "error", message: "Unexpected quota target. Expected codexbar." };
38
+ return rest[1] === undefined ? { kind: subcommand } : { kind: "error", message: "Unexpected argument." };
39
+ }
40
+ if (subcommand === "status" || subcommand === "usage" || subcommand === "cost") {
41
+ return parseRunCommand(subcommand === "cost" ? "cost" : "usage", rest);
42
+ }
43
+ return { kind: "error", message: "Unexpected quota command." };
44
+ }
45
+ export async function handleCodexBarQuotaCommand(args, deps = {}) {
46
+ const command = parseCodexBarQuotaCommand(args);
47
+ if (command === undefined)
48
+ return false;
49
+ const d = { ...DEFAULT_DEPS, ...deps };
50
+ try {
51
+ switch (command.kind) {
52
+ case "help":
53
+ printHelp(d);
54
+ return true;
55
+ case "error":
56
+ return fail(d, 1, `${command.message}\n${chalk.dim(`Usage: ${USAGE}`)}`);
57
+ case "connect":
58
+ return connect(d);
59
+ case "disconnect":
60
+ return disconnect(d);
61
+ case "run":
62
+ return await run(command, d);
63
+ }
64
+ }
65
+ catch (error) {
66
+ if (error instanceof Error)
67
+ return fail(d, 1, "CodexBar quota command failed.");
68
+ throw error;
69
+ }
70
+ }
71
+ function parseRunCommand(metric, args) {
72
+ let provider;
73
+ let json = false;
74
+ for (let index = 0; index < args.length; index++) {
75
+ const arg = args[index];
76
+ if (arg === "--json") {
77
+ json = true;
78
+ continue;
79
+ }
80
+ if (arg === "--provider") {
81
+ const value = args[index + 1];
82
+ if (value === undefined || value.startsWith("-") || value.trim().length === 0) {
83
+ return { kind: "error", message: "Missing value for --provider." };
84
+ }
85
+ if (provider !== undefined)
86
+ return { kind: "error", message: "--provider can only be provided once." };
87
+ provider = value;
88
+ index++;
89
+ continue;
90
+ }
91
+ if (arg.startsWith("-"))
92
+ return { kind: "error", message: "Unknown option for quota command." };
93
+ return { kind: "error", message: "Unexpected argument." };
94
+ }
95
+ return { kind: "run", metric, provider, json };
96
+ }
97
+ function connect(d) {
98
+ const dir = d.getAgentDir();
99
+ const acknowledgement = {
100
+ codexbar: { enabled: true, privacyAck: PRIVACY_ACK_VERSION, connectedAt: new Date().toISOString() },
101
+ };
102
+ d.mkdir(dir);
103
+ d.write(connectorPath(d), `${JSON.stringify(acknowledgement, null, 2)}\n`);
104
+ d.stdout(`${chalk.green("CodexBar quota connector enabled.")}\n`);
105
+ return true;
106
+ }
107
+ function disconnect(d) {
108
+ d.remove(connectorPath(d));
109
+ d.stdout(`${chalk.green("CodexBar quota connector disabled.")}\n`);
110
+ return true;
111
+ }
112
+ async function run(command, d) {
113
+ if (!connectorEnabled(d)) {
114
+ return fail(d, 1, `CodexBar quota connector is not enabled.\nRun \`${APP_NAME} quota connect codexbar\` to opt in before checking CodexBar quota.`);
115
+ }
116
+ const codexbar = await d.ensure("codexbar", true);
117
+ if (codexbar === undefined)
118
+ return fail(d, 2, "CodexBar binary was not found.\nInstall codexbar on PATH, then rerun this command.");
119
+ const result = d.spawn(codexbar, codexbarArgs(command));
120
+ if (result.error !== undefined)
121
+ return fail(d, 1, "Failed to run CodexBar.");
122
+ if (result.status !== 0) {
123
+ const reason = result.status === null ? `signal ${result.signal ?? "unknown"}` : `exit code ${result.status}`;
124
+ return fail(d, 1, `CodexBar command failed (${reason}).`);
125
+ }
126
+ return printSummary(command, result.stdout, d);
127
+ }
128
+ function connectorPath(d) {
129
+ return join(d.getAgentDir(), CONNECTOR_FILE);
130
+ }
131
+ function connectorEnabled(d) {
132
+ const path = connectorPath(d);
133
+ if (!d.exists(path))
134
+ return false;
135
+ let parsed;
136
+ try {
137
+ parsed = JSON.parse(d.read(path));
138
+ }
139
+ catch (error) {
140
+ if (error instanceof SyntaxError)
141
+ return false;
142
+ throw error;
143
+ }
144
+ return (isRecord(parsed) &&
145
+ isRecord(parsed.codexbar) &&
146
+ parsed.codexbar.enabled === true &&
147
+ parsed.codexbar.privacyAck === PRIVACY_ACK_VERSION);
148
+ }
149
+ function codexbarArgs(command) {
150
+ const args = command.metric === "cost" ? ["cost", "--format", "json"] : ["--format", "json"];
151
+ return command.provider === undefined ? args : [...args, "--provider", command.provider];
152
+ }
153
+ function printSummary(command, stdout, d) {
154
+ try {
155
+ if (command.metric === "usage") {
156
+ const summary = parseCodexBarUsageJson(stdout);
157
+ d.stdout(command.json ? `${JSON.stringify(summary, null, 2)}\n` : usageText(summary));
158
+ return true;
159
+ }
160
+ const summary = parseCodexBarCostJson(stdout);
161
+ d.stdout(command.json ? `${JSON.stringify(summary, null, 2)}\n` : costText(summary));
162
+ return true;
163
+ }
164
+ catch (error) {
165
+ if (error instanceof CodexBarUnsafeOutputError)
166
+ return fail(d, 3, "CodexBar returned unsafe output; refusing to display it.");
167
+ if (error instanceof CodexBarJsonError)
168
+ return fail(d, 3, "CodexBar returned invalid JSON.");
169
+ throw error;
170
+ }
171
+ }
172
+ function usageText(summary) {
173
+ const lines = ["CodexBar usage", `Provider: ${summary.provider}`];
174
+ if (summary.primary !== undefined)
175
+ lines.push(windowText("Primary", summary.primary));
176
+ if (summary.secondary !== undefined)
177
+ lines.push(windowText("Secondary", summary.secondary));
178
+ if (summary.creditsRemaining !== undefined)
179
+ lines.push(`Credits remaining: ${summary.creditsRemaining}`);
180
+ if (summary.status?.indicator !== undefined)
181
+ lines.push(`Status: ${summary.status.indicator}`);
182
+ if (summary.updatedAt !== undefined)
183
+ lines.push(`Updated: ${summary.updatedAt}`);
184
+ return `${lines.join("\n")}\n`;
185
+ }
186
+ function windowText(label, window) {
187
+ const used = window.usedPercent === undefined ? "n/a" : `${window.usedPercent}% used`;
188
+ return `${label}: ${used}${window.resetsAt === undefined ? "" : `, resets at ${window.resetsAt}`}`;
189
+ }
190
+ function costText(summary) {
191
+ if (summary.length === 0)
192
+ return "CodexBar cost\nNo cost records reported.\n";
193
+ const lines = ["CodexBar cost"];
194
+ for (const entry of summary) {
195
+ lines.push(`Provider: ${entry.provider}`);
196
+ if (entry.sessionCostUSD !== undefined)
197
+ lines.push(` Session: $${entry.sessionCostUSD.toFixed(2)}`);
198
+ if (entry.last30DaysCostUSD !== undefined)
199
+ lines.push(` Last 30 days: $${entry.last30DaysCostUSD.toFixed(2)}`);
200
+ if (entry.totalCostUSD !== undefined)
201
+ lines.push(` Total: $${entry.totalCostUSD.toFixed(2)}`);
202
+ if (entry.totalTokens !== undefined)
203
+ lines.push(` Total tokens: ${entry.totalTokens}`);
204
+ if (entry.updatedAt !== undefined)
205
+ lines.push(` Updated: ${entry.updatedAt}`);
206
+ }
207
+ return `${lines.join("\n")}\n`;
208
+ }
209
+ function fail(d, exitCode, message) {
210
+ d.stderr(`${chalk.red(message)}\n`);
211
+ process.exitCode = exitCode;
212
+ return true;
213
+ }
214
+ function isRecord(value) {
215
+ return typeof value === "object" && value !== null && !Array.isArray(value);
216
+ }
217
+ function printHelp(d) {
218
+ d.stdout(`${chalk.bold("Usage:")}
219
+ ${APP_NAME} quota --help
220
+ ${APP_NAME} quota connect codexbar
221
+ ${APP_NAME} quota disconnect codexbar
222
+ ${APP_NAME} quota status [--provider <id|both|all>] [--json]
223
+ ${APP_NAME} quota usage [--provider <id|both|all>] [--json]
224
+ ${APP_NAME} quota cost [--provider <id|both|all>] [--json]
225
+
226
+ CodexBar quota commands require an explicit local opt-in acknowledgement.
227
+ The acknowledgement stores no secrets and OMK does not read or write CodexBar config.
228
+ `);
229
+ }
230
+ //# sourceMappingURL=codexbar-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexbar-cli.js","sourceRoot":"","sources":["../src/codexbar-cli.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { APP_NAME, getAgentDir } from \"./config.ts\";\nimport {\n\tCodexBarJsonError,\n\tCodexBarUnsafeOutputError,\n\ttype CodexBarUsageWindowSummary,\n\tparseCodexBarCostJson,\n\tparseCodexBarUsageJson,\n} from \"./core/codexbar-adapter.ts\";\nimport { spawnProcessSync } from \"./utils/child-process.ts\";\nimport { ensureTool } from \"./utils/tools-manager.ts\";\n\nconst CONNECTOR_FILE = \"codexbar-connector.json\";\nconst PRIVACY_ACK_VERSION = 1;\nconst USAGE = `${APP_NAME} quota <connect|disconnect|status|usage|cost> ...`;\n\ntype RunCommand = {\n\treadonly kind: \"run\";\n\treadonly metric: \"usage\" | \"cost\";\n\treadonly provider?: string;\n\treadonly json: boolean;\n};\n\nexport type CodexBarQuotaCommand =\n\t| { readonly kind: \"help\" }\n\t| { readonly kind: \"connect\" }\n\t| { readonly kind: \"disconnect\" }\n\t| RunCommand\n\t| { readonly kind: \"error\"; readonly message: string };\n\nexport type CodexBarQuotaSpawnResult = {\n\treadonly stdout: string;\n\treadonly status: number | null;\n\treadonly signal: string | null;\n\treadonly error?: Error;\n};\n\ntype CodexBarQuotaDeps = {\n\treadonly getAgentDir: () => string;\n\treadonly exists: (path: string) => boolean;\n\treadonly read: (path: string) => string;\n\treadonly write: (path: string, value: string) => void;\n\treadonly mkdir: (path: string) => void;\n\treadonly remove: (path: string) => void;\n\treadonly ensure: (tool: \"codexbar\", silent: true) => Promise<string | undefined>;\n\treadonly spawn: (command: string, args: readonly string[]) => CodexBarQuotaSpawnResult;\n\treadonly stdout: (text: string) => void;\n\treadonly stderr: (text: string) => void;\n};\n\nexport type CodexBarQuotaCommandDeps = Partial<CodexBarQuotaDeps>;\n\nconst DEFAULT_DEPS: CodexBarQuotaDeps = {\n\tgetAgentDir,\n\texists: existsSync,\n\tread: (path) => readFileSync(path, \"utf8\"),\n\twrite: (path, value) => writeFileSync(path, value, \"utf8\"),\n\tmkdir: (path) => mkdirSync(path, { recursive: true }),\n\tremove: (path) => rmSync(path, { force: true }),\n\tensure: ensureTool,\n\tspawn: (command, args) =>\n\t\tspawnProcessSync(command, [...args], { encoding: \"utf8\", stdio: \"pipe\", shell: false, windowsHide: true }),\n\tstdout: (text) => process.stdout.write(text),\n\tstderr: (text) => process.stderr.write(text),\n};\n\nexport function parseCodexBarQuotaCommand(args: readonly string[]): CodexBarQuotaCommand | undefined {\n\tif (args[0] !== \"quota\") return undefined;\n\tconst subcommand = args[1];\n\tconst rest = args.slice(2);\n\tif (subcommand === undefined) return { kind: \"error\", message: \"Missing quota command.\" };\n\tif (subcommand === \"--help\" || subcommand === \"-h\" || subcommand === \"help\") {\n\t\treturn rest.length === 0 ? { kind: \"help\" } : { kind: \"error\", message: \"Unexpected argument.\" };\n\t}\n\tif (subcommand === \"connect\" || subcommand === \"disconnect\") {\n\t\tif (rest[0] === undefined)\n\t\t\treturn { kind: \"error\", message: `Missing target for quota ${subcommand}. Expected codexbar.` };\n\t\tif (rest[0] !== \"codexbar\") return { kind: \"error\", message: \"Unexpected quota target. Expected codexbar.\" };\n\t\treturn rest[1] === undefined ? { kind: subcommand } : { kind: \"error\", message: \"Unexpected argument.\" };\n\t}\n\tif (subcommand === \"status\" || subcommand === \"usage\" || subcommand === \"cost\") {\n\t\treturn parseRunCommand(subcommand === \"cost\" ? \"cost\" : \"usage\", rest);\n\t}\n\treturn { kind: \"error\", message: \"Unexpected quota command.\" };\n}\n\nexport async function handleCodexBarQuotaCommand(\n\targs: readonly string[],\n\tdeps: CodexBarQuotaCommandDeps = {},\n): Promise<boolean> {\n\tconst command = parseCodexBarQuotaCommand(args);\n\tif (command === undefined) return false;\n\tconst d: CodexBarQuotaDeps = { ...DEFAULT_DEPS, ...deps };\n\n\ttry {\n\t\tswitch (command.kind) {\n\t\t\tcase \"help\":\n\t\t\t\tprintHelp(d);\n\t\t\t\treturn true;\n\t\t\tcase \"error\":\n\t\t\t\treturn fail(d, 1, `${command.message}\\n${chalk.dim(`Usage: ${USAGE}`)}`);\n\t\t\tcase \"connect\":\n\t\t\t\treturn connect(d);\n\t\t\tcase \"disconnect\":\n\t\t\t\treturn disconnect(d);\n\t\t\tcase \"run\":\n\t\t\t\treturn await run(command, d);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error) return fail(d, 1, \"CodexBar quota command failed.\");\n\t\tthrow error;\n\t}\n}\n\nfunction parseRunCommand(metric: RunCommand[\"metric\"], args: readonly string[]): CodexBarQuotaCommand {\n\tlet provider: string | undefined;\n\tlet json = false;\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst arg = args[index];\n\t\tif (arg === \"--json\") {\n\t\t\tjson = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--provider\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined || value.startsWith(\"-\") || value.trim().length === 0) {\n\t\t\t\treturn { kind: \"error\", message: \"Missing value for --provider.\" };\n\t\t\t}\n\t\t\tif (provider !== undefined) return { kind: \"error\", message: \"--provider can only be provided once.\" };\n\t\t\tprovider = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg.startsWith(\"-\")) return { kind: \"error\", message: \"Unknown option for quota command.\" };\n\t\treturn { kind: \"error\", message: \"Unexpected argument.\" };\n\t}\n\treturn { kind: \"run\", metric, provider, json };\n}\n\nfunction connect(d: CodexBarQuotaDeps): boolean {\n\tconst dir = d.getAgentDir();\n\tconst acknowledgement = {\n\t\tcodexbar: { enabled: true, privacyAck: PRIVACY_ACK_VERSION, connectedAt: new Date().toISOString() },\n\t};\n\td.mkdir(dir);\n\td.write(connectorPath(d), `${JSON.stringify(acknowledgement, null, 2)}\\n`);\n\td.stdout(`${chalk.green(\"CodexBar quota connector enabled.\")}\\n`);\n\treturn true;\n}\n\nfunction disconnect(d: CodexBarQuotaDeps): boolean {\n\td.remove(connectorPath(d));\n\td.stdout(`${chalk.green(\"CodexBar quota connector disabled.\")}\\n`);\n\treturn true;\n}\n\nasync function run(command: RunCommand, d: CodexBarQuotaDeps): Promise<boolean> {\n\tif (!connectorEnabled(d)) {\n\t\treturn fail(\n\t\t\td,\n\t\t\t1,\n\t\t\t`CodexBar quota connector is not enabled.\\nRun \\`${APP_NAME} quota connect codexbar\\` to opt in before checking CodexBar quota.`,\n\t\t);\n\t}\n\n\tconst codexbar = await d.ensure(\"codexbar\", true);\n\tif (codexbar === undefined)\n\t\treturn fail(d, 2, \"CodexBar binary was not found.\\nInstall codexbar on PATH, then rerun this command.\");\n\n\tconst result = d.spawn(codexbar, codexbarArgs(command));\n\tif (result.error !== undefined) return fail(d, 1, \"Failed to run CodexBar.\");\n\tif (result.status !== 0) {\n\t\tconst reason = result.status === null ? `signal ${result.signal ?? \"unknown\"}` : `exit code ${result.status}`;\n\t\treturn fail(d, 1, `CodexBar command failed (${reason}).`);\n\t}\n\treturn printSummary(command, result.stdout, d);\n}\n\nfunction connectorPath(d: CodexBarQuotaDeps): string {\n\treturn join(d.getAgentDir(), CONNECTOR_FILE);\n}\n\nfunction connectorEnabled(d: CodexBarQuotaDeps): boolean {\n\tconst path = connectorPath(d);\n\tif (!d.exists(path)) return false;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(d.read(path));\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) return false;\n\t\tthrow error;\n\t}\n\treturn (\n\t\tisRecord(parsed) &&\n\t\tisRecord(parsed.codexbar) &&\n\t\tparsed.codexbar.enabled === true &&\n\t\tparsed.codexbar.privacyAck === PRIVACY_ACK_VERSION\n\t);\n}\n\nfunction codexbarArgs(command: RunCommand): readonly string[] {\n\tconst args = command.metric === \"cost\" ? [\"cost\", \"--format\", \"json\"] : [\"--format\", \"json\"];\n\treturn command.provider === undefined ? args : [...args, \"--provider\", command.provider];\n}\n\nfunction printSummary(command: RunCommand, stdout: string, d: CodexBarQuotaDeps): boolean {\n\ttry {\n\t\tif (command.metric === \"usage\") {\n\t\t\tconst summary = parseCodexBarUsageJson(stdout);\n\t\t\td.stdout(command.json ? `${JSON.stringify(summary, null, 2)}\\n` : usageText(summary));\n\t\t\treturn true;\n\t\t}\n\t\tconst summary = parseCodexBarCostJson(stdout);\n\t\td.stdout(command.json ? `${JSON.stringify(summary, null, 2)}\\n` : costText(summary));\n\t\treturn true;\n\t} catch (error) {\n\t\tif (error instanceof CodexBarUnsafeOutputError)\n\t\t\treturn fail(d, 3, \"CodexBar returned unsafe output; refusing to display it.\");\n\t\tif (error instanceof CodexBarJsonError) return fail(d, 3, \"CodexBar returned invalid JSON.\");\n\t\tthrow error;\n\t}\n}\n\nfunction usageText(summary: ReturnType<typeof parseCodexBarUsageJson>): string {\n\tconst lines = [\"CodexBar usage\", `Provider: ${summary.provider}`];\n\tif (summary.primary !== undefined) lines.push(windowText(\"Primary\", summary.primary));\n\tif (summary.secondary !== undefined) lines.push(windowText(\"Secondary\", summary.secondary));\n\tif (summary.creditsRemaining !== undefined) lines.push(`Credits remaining: ${summary.creditsRemaining}`);\n\tif (summary.status?.indicator !== undefined) lines.push(`Status: ${summary.status.indicator}`);\n\tif (summary.updatedAt !== undefined) lines.push(`Updated: ${summary.updatedAt}`);\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction windowText(label: string, window: CodexBarUsageWindowSummary): string {\n\tconst used = window.usedPercent === undefined ? \"n/a\" : `${window.usedPercent}% used`;\n\treturn `${label}: ${used}${window.resetsAt === undefined ? \"\" : `, resets at ${window.resetsAt}`}`;\n}\n\nfunction costText(summary: ReturnType<typeof parseCodexBarCostJson>): string {\n\tif (summary.length === 0) return \"CodexBar cost\\nNo cost records reported.\\n\";\n\tconst lines = [\"CodexBar cost\"];\n\tfor (const entry of summary) {\n\t\tlines.push(`Provider: ${entry.provider}`);\n\t\tif (entry.sessionCostUSD !== undefined) lines.push(` Session: $${entry.sessionCostUSD.toFixed(2)}`);\n\t\tif (entry.last30DaysCostUSD !== undefined) lines.push(` Last 30 days: $${entry.last30DaysCostUSD.toFixed(2)}`);\n\t\tif (entry.totalCostUSD !== undefined) lines.push(` Total: $${entry.totalCostUSD.toFixed(2)}`);\n\t\tif (entry.totalTokens !== undefined) lines.push(` Total tokens: ${entry.totalTokens}`);\n\t\tif (entry.updatedAt !== undefined) lines.push(` Updated: ${entry.updatedAt}`);\n\t}\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction fail(d: CodexBarQuotaDeps, exitCode: number, message: string): boolean {\n\td.stderr(`${chalk.red(message)}\\n`);\n\tprocess.exitCode = exitCode;\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction printHelp(d: CodexBarQuotaDeps): void {\n\td.stdout(`${chalk.bold(\"Usage:\")}\n ${APP_NAME} quota --help\n ${APP_NAME} quota connect codexbar\n ${APP_NAME} quota disconnect codexbar\n ${APP_NAME} quota status [--provider <id|both|all>] [--json]\n ${APP_NAME} quota usage [--provider <id|both|all>] [--json]\n ${APP_NAME} quota cost [--provider <id|both|all>] [--json]\n\nCodexBar quota commands require an explicit local opt-in acknowledgement.\nThe acknowledgement stores no secrets and OMK does not read or write CodexBar config.\n`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-provider.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-provider.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtF,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE;QACP,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;CACF;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAgCD,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2FxF","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type DoctorErrorCategory = \"network\" | \"auth\" | \"model\" | \"config\" | \"unknown\";\n\nexport interface ProviderDoctorResult {\n\tprovider: string;\n\tstatus: \"ok\" | \"fail\";\n\tbaseUrl?: string;\n\tchecks: ProviderDoctorCheck[];\n\terror?: {\n\t\tcategory: DoctorErrorCategory;\n\t\tmessage: string;\n\t};\n}\n\nexport interface ProviderDoctorCheck {\n\tname: string;\n\tstatus: \"ok\" | \"fail\" | \"skipped\";\n\tmessage?: string;\n}\n\ninterface ProviderConfig {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n}\n\nexport function getAgentDir(): string {\n\treturn join(homedir(), \".omk\", \"agent\");\n}\n\nfunction loadJson<T>(path: string): T | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction resolveConfig(providerId: string): { config: ProviderConfig; source: string } | undefined {\n\tconst agentDir = getAgentDir();\n\n\tconst modelsPath = join(agentDir, \"models.json\");\n\tconst models = loadJson<{ providers?: Record<string, ProviderConfig> }>(modelsPath);\n\tif (models?.providers?.[providerId]) {\n\t\treturn { config: models.providers[providerId], source: \"models.json\" };\n\t}\n\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst auth = loadJson<Record<string, { type: string; key?: string }>>(authPath);\n\tif (auth?.[providerId]) {\n\t\treturn {\n\t\t\tconfig: { apiKey: auth[providerId].key },\n\t\t\tsource: \"auth.json\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\nexport async function diagnoseProvider(providerId: string): Promise<ProviderDoctorResult> {\n\tconst resolved = resolveConfig(providerId);\n\tif (!resolved) {\n\t\treturn {\n\t\t\tprovider: providerId,\n\t\t\tstatus: \"fail\",\n\t\t\tchecks: [],\n\t\t\terror: { category: \"config\", message: `Provider \"${providerId}\" not found in models.json or auth.json` },\n\t\t};\n\t}\n\n\tconst { config } = resolved;\n\tconst checks: ProviderDoctorCheck[] = [];\n\n\t// 1. Config presence\n\tchecks.push({\n\t\tname: \"config-present\",\n\t\tstatus: \"ok\",\n\t\tmessage: `Found provider config in ${resolved.source}`,\n\t});\n\n\t// 2. Base URL reachability\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst res = await fetch(config.baseUrl, { method: \"GET\" });\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"base-url-reachable\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\t// 3. API key presence (never log the value)\n\tchecks.push({\n\t\tname: \"api-key-present\",\n\t\tstatus: config.apiKey ? \"ok\" : \"skipped\",\n\t\tmessage: config.apiKey ? \"API key is configured\" : \"No API key configured\",\n\t});\n\n\t// 4. Models endpoint probe\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst headers: Record<string, string> = {};\n\t\t\tif (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;\n\t\t\tconst res = await fetch(`${config.baseUrl.replace(/\\/$/, \"\")}/models`, { headers });\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"models-endpoint\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\tconst failed = checks.find((c) => c.status === \"fail\");\n\tlet error: ProviderDoctorResult[\"error\"];\n\tif (failed) {\n\t\tconst category: DoctorErrorCategory =\n\t\t\tfailed.name === \"base-url-reachable\"\n\t\t\t\t? \"network\"\n\t\t\t\t: failed.name === \"api-key-present\"\n\t\t\t\t\t? \"auth\"\n\t\t\t\t\t: failed.name === \"models-endpoint\"\n\t\t\t\t\t\t? \"model\"\n\t\t\t\t\t\t: \"unknown\";\n\t\terror = { category, message: failed.message ?? `${failed.name} failed` };\n\t}\n\n\treturn {\n\t\tprovider: providerId,\n\t\tstatus: failed ? \"fail\" : \"ok\",\n\t\tbaseUrl: config.baseUrl,\n\t\tchecks,\n\t\terror,\n\t};\n}\n"]}
1
+ {"version":3,"file":"doctor-provider.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-provider.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtF,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE;QACP,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;CACF;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AA4CD,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA6FxF","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type DoctorErrorCategory = \"network\" | \"auth\" | \"model\" | \"config\" | \"unknown\";\n\nexport interface ProviderDoctorResult {\n\tprovider: string;\n\tstatus: \"ok\" | \"fail\";\n\tbaseUrl?: string;\n\tchecks: ProviderDoctorCheck[];\n\terror?: {\n\t\tcategory: DoctorErrorCategory;\n\t\tmessage: string;\n\t};\n}\n\nexport interface ProviderDoctorCheck {\n\tname: string;\n\tstatus: \"ok\" | \"fail\" | \"skipped\";\n\tmessage?: string;\n}\n\ninterface ProviderConfig {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n}\n\nexport function getAgentDir(): string {\n\treturn join(homedir(), \".omk\", \"agent\");\n}\n\nfunction loadJson<T>(path: string): T | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction resolveConfig(providerId: string): { config: ProviderConfig; source: string } | undefined {\n\tconst agentDir = getAgentDir();\n\n\tconst modelsPath = join(agentDir, \"models.json\");\n\tconst models = loadJson<{ providers?: Record<string, ProviderConfig> }>(modelsPath);\n\tif (models?.providers?.[providerId]) {\n\t\treturn { config: models.providers[providerId], source: \"models.json\" };\n\t}\n\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst auth = loadJson<Record<string, { type: string; key?: string }>>(authPath);\n\tif (auth?.[providerId]) {\n\t\treturn {\n\t\t\tconfig: { apiKey: auth[providerId].key },\n\t\t\tsource: \"auth.json\",\n\t\t};\n\t}\n\n\t// Built-in local Grok OAuth proxy defaults (no secrets; loopback only).\n\tif (providerId === \"grok-oauth-proxy\") {\n\t\treturn {\n\t\t\tconfig: {\n\t\t\t\tbaseUrl: \"http://127.0.0.1:9996/v1\",\n\t\t\t\tapi: \"openai-completions\",\n\t\t\t\tapiKey: \"dummy\",\n\t\t\t},\n\t\t\tsource: \"built-in-grok-oauth-proxy-defaults\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\nexport async function diagnoseProvider(providerId: string): Promise<ProviderDoctorResult> {\n\tconst resolved = resolveConfig(providerId);\n\tif (!resolved) {\n\t\treturn {\n\t\t\tprovider: providerId,\n\t\t\tstatus: \"fail\",\n\t\t\tchecks: [],\n\t\t\terror: { category: \"config\", message: `Provider \"${providerId}\" not found in models.json or auth.json` },\n\t\t};\n\t}\n\n\tconst { config } = resolved;\n\tconst checks: ProviderDoctorCheck[] = [];\n\n\t// 1. Config presence\n\tchecks.push({\n\t\tname: \"config-present\",\n\t\tstatus: \"ok\",\n\t\tmessage: `Found provider config in ${resolved.source}`,\n\t});\n\n\t// 2. Base URL / health reachability\n\t// OpenAI-compatible roots often 404 on GET /v1; prefer /health for local Grok proxy.\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst probeUrl = providerId === \"grok-oauth-proxy\" ? new URL(\"/health\", config.baseUrl).href : config.baseUrl;\n\t\t\tconst res = await fetch(probeUrl, { method: \"GET\" });\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `${probeUrl} → HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"base-url-reachable\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\t// 3. API key presence (never log the value)\n\tchecks.push({\n\t\tname: \"api-key-present\",\n\t\tstatus: config.apiKey ? \"ok\" : \"skipped\",\n\t\tmessage: config.apiKey ? \"API key is configured\" : \"No API key configured\",\n\t});\n\n\t// 4. Models endpoint probe\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst headers: Record<string, string> = {};\n\t\t\tif (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;\n\t\t\tconst res = await fetch(`${config.baseUrl.replace(/\\/$/, \"\")}/models`, { headers });\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"models-endpoint\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\tconst failed = checks.find((c) => c.status === \"fail\");\n\tlet error: ProviderDoctorResult[\"error\"];\n\tif (failed) {\n\t\tconst category: DoctorErrorCategory =\n\t\t\tfailed.name === \"base-url-reachable\"\n\t\t\t\t? \"network\"\n\t\t\t\t: failed.name === \"api-key-present\"\n\t\t\t\t\t? \"auth\"\n\t\t\t\t\t: failed.name === \"models-endpoint\"\n\t\t\t\t\t\t? \"model\"\n\t\t\t\t\t\t: \"unknown\";\n\t\terror = { category, message: failed.message ?? `${failed.name} failed` };\n\t}\n\n\treturn {\n\t\tprovider: providerId,\n\t\tstatus: failed ? \"fail\" : \"ok\",\n\t\tbaseUrl: config.baseUrl,\n\t\tchecks,\n\t\terror,\n\t};\n}\n"]}
@@ -29,6 +29,17 @@ function resolveConfig(providerId) {
29
29
  source: "auth.json",
30
30
  };
31
31
  }
32
+ // Built-in local Grok OAuth proxy defaults (no secrets; loopback only).
33
+ if (providerId === "grok-oauth-proxy") {
34
+ return {
35
+ config: {
36
+ baseUrl: "http://127.0.0.1:9996/v1",
37
+ api: "openai-completions",
38
+ apiKey: "dummy",
39
+ },
40
+ source: "built-in-grok-oauth-proxy-defaults",
41
+ };
42
+ }
32
43
  return undefined;
33
44
  }
34
45
  export async function diagnoseProvider(providerId) {
@@ -49,14 +60,16 @@ export async function diagnoseProvider(providerId) {
49
60
  status: "ok",
50
61
  message: `Found provider config in ${resolved.source}`,
51
62
  });
52
- // 2. Base URL reachability
63
+ // 2. Base URL / health reachability
64
+ // OpenAI-compatible roots often 404 on GET /v1; prefer /health for local Grok proxy.
53
65
  if (config.baseUrl) {
54
66
  try {
55
- const res = await fetch(config.baseUrl, { method: "GET" });
67
+ const probeUrl = providerId === "grok-oauth-proxy" ? new URL("/health", config.baseUrl).href : config.baseUrl;
68
+ const res = await fetch(probeUrl, { method: "GET" });
56
69
  checks.push({
57
70
  name: "base-url-reachable",
58
71
  status: res.ok ? "ok" : "fail",
59
- message: `HTTP ${res.status}`,
72
+ message: `${probeUrl} → HTTP ${res.status}`,
60
73
  });
61
74
  }
62
75
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-provider.js","sourceRoot":"","sources":["../../src/commands/doctor-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA2BjC,MAAM,UAAU,WAAW,GAAW;IACrC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAAA,CACxC;AAED,SAAS,QAAQ,CAAI,IAAY,EAAiB;IACjD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAM,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,SAAS,aAAa,CAAC,UAAkB,EAA0D;IAClG,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAiD,UAAU,CAAC,CAAC;IACpF,IAAI,MAAM,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAiD,QAAQ,CAAC,CAAC;IAChF,IAAI,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACxB,OAAO;YACN,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE;YACxC,MAAM,EAAE,WAAW;SACnB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB,EAAiC;IACzF,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,OAAO;YACN,QAAQ,EAAE,UAAU;YACpB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,UAAU,yCAAyC,EAAE;SACxG,CAAC;IACH,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,MAAM,MAAM,GAA0B,EAAE,CAAC;IAEzC,qBAAqB;IACrB,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,4BAA4B,QAAQ,CAAC,MAAM,EAAE;KACtD,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;gBAC9B,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE;aAC7B,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,4CAA4C;IAC5C,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACxC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB;KAC1E,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM;gBAAE,OAAO,CAAC,aAAa,GAAG,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YACpF,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;gBAC9B,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE;aAC7B,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACvD,IAAI,KAAoC,CAAC;IACzC,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,QAAQ,GACb,MAAM,CAAC,IAAI,KAAK,oBAAoB;YACnC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,iBAAiB;gBAClC,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,iBAAiB;oBAClC,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,SAAS,CAAC;QAChB,KAAK,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,GAAG,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO;QACN,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM;QACN,KAAK;KACL,CAAC;AAAA,CACF","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type DoctorErrorCategory = \"network\" | \"auth\" | \"model\" | \"config\" | \"unknown\";\n\nexport interface ProviderDoctorResult {\n\tprovider: string;\n\tstatus: \"ok\" | \"fail\";\n\tbaseUrl?: string;\n\tchecks: ProviderDoctorCheck[];\n\terror?: {\n\t\tcategory: DoctorErrorCategory;\n\t\tmessage: string;\n\t};\n}\n\nexport interface ProviderDoctorCheck {\n\tname: string;\n\tstatus: \"ok\" | \"fail\" | \"skipped\";\n\tmessage?: string;\n}\n\ninterface ProviderConfig {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n}\n\nexport function getAgentDir(): string {\n\treturn join(homedir(), \".omk\", \"agent\");\n}\n\nfunction loadJson<T>(path: string): T | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction resolveConfig(providerId: string): { config: ProviderConfig; source: string } | undefined {\n\tconst agentDir = getAgentDir();\n\n\tconst modelsPath = join(agentDir, \"models.json\");\n\tconst models = loadJson<{ providers?: Record<string, ProviderConfig> }>(modelsPath);\n\tif (models?.providers?.[providerId]) {\n\t\treturn { config: models.providers[providerId], source: \"models.json\" };\n\t}\n\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst auth = loadJson<Record<string, { type: string; key?: string }>>(authPath);\n\tif (auth?.[providerId]) {\n\t\treturn {\n\t\t\tconfig: { apiKey: auth[providerId].key },\n\t\t\tsource: \"auth.json\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\nexport async function diagnoseProvider(providerId: string): Promise<ProviderDoctorResult> {\n\tconst resolved = resolveConfig(providerId);\n\tif (!resolved) {\n\t\treturn {\n\t\t\tprovider: providerId,\n\t\t\tstatus: \"fail\",\n\t\t\tchecks: [],\n\t\t\terror: { category: \"config\", message: `Provider \"${providerId}\" not found in models.json or auth.json` },\n\t\t};\n\t}\n\n\tconst { config } = resolved;\n\tconst checks: ProviderDoctorCheck[] = [];\n\n\t// 1. Config presence\n\tchecks.push({\n\t\tname: \"config-present\",\n\t\tstatus: \"ok\",\n\t\tmessage: `Found provider config in ${resolved.source}`,\n\t});\n\n\t// 2. Base URL reachability\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst res = await fetch(config.baseUrl, { method: \"GET\" });\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"base-url-reachable\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\t// 3. API key presence (never log the value)\n\tchecks.push({\n\t\tname: \"api-key-present\",\n\t\tstatus: config.apiKey ? \"ok\" : \"skipped\",\n\t\tmessage: config.apiKey ? \"API key is configured\" : \"No API key configured\",\n\t});\n\n\t// 4. Models endpoint probe\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst headers: Record<string, string> = {};\n\t\t\tif (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;\n\t\t\tconst res = await fetch(`${config.baseUrl.replace(/\\/$/, \"\")}/models`, { headers });\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"models-endpoint\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\tconst failed = checks.find((c) => c.status === \"fail\");\n\tlet error: ProviderDoctorResult[\"error\"];\n\tif (failed) {\n\t\tconst category: DoctorErrorCategory =\n\t\t\tfailed.name === \"base-url-reachable\"\n\t\t\t\t? \"network\"\n\t\t\t\t: failed.name === \"api-key-present\"\n\t\t\t\t\t? \"auth\"\n\t\t\t\t\t: failed.name === \"models-endpoint\"\n\t\t\t\t\t\t? \"model\"\n\t\t\t\t\t\t: \"unknown\";\n\t\terror = { category, message: failed.message ?? `${failed.name} failed` };\n\t}\n\n\treturn {\n\t\tprovider: providerId,\n\t\tstatus: failed ? \"fail\" : \"ok\",\n\t\tbaseUrl: config.baseUrl,\n\t\tchecks,\n\t\terror,\n\t};\n}\n"]}
1
+ {"version":3,"file":"doctor-provider.js","sourceRoot":"","sources":["../../src/commands/doctor-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA2BjC,MAAM,UAAU,WAAW,GAAW;IACrC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAAA,CACxC;AAED,SAAS,QAAQ,CAAI,IAAY,EAAiB;IACjD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAM,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,SAAS,aAAa,CAAC,UAAkB,EAA0D;IAClG,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAiD,UAAU,CAAC,CAAC;IACpF,IAAI,MAAM,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAiD,QAAQ,CAAC,CAAC;IAChF,IAAI,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACxB,OAAO;YACN,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE;YACxC,MAAM,EAAE,WAAW;SACnB,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,IAAI,UAAU,KAAK,kBAAkB,EAAE,CAAC;QACvC,OAAO;YACN,MAAM,EAAE;gBACP,OAAO,EAAE,0BAA0B;gBACnC,GAAG,EAAE,oBAAoB;gBACzB,MAAM,EAAE,OAAO;aACf;YACD,MAAM,EAAE,oCAAoC;SAC5C,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB,EAAiC;IACzF,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,OAAO;YACN,QAAQ,EAAE,UAAU;YACpB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,UAAU,yCAAyC,EAAE;SACxG,CAAC;IACH,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,MAAM,MAAM,GAA0B,EAAE,CAAC;IAEzC,qBAAqB;IACrB,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,4BAA4B,QAAQ,CAAC,MAAM,EAAE;KACtD,CAAC,CAAC;IAEH,oCAAoC;IACpC,qFAAqF;IACrF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,UAAU,KAAK,kBAAkB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;YAC9G,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;gBAC9B,OAAO,EAAE,GAAG,QAAQ,aAAW,GAAG,CAAC,MAAM,EAAE;aAC3C,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,4CAA4C;IAC5C,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACxC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB;KAC1E,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM;gBAAE,OAAO,CAAC,aAAa,GAAG,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YACpF,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;gBAC9B,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE;aAC7B,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACvD,IAAI,KAAoC,CAAC;IACzC,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,QAAQ,GACb,MAAM,CAAC,IAAI,KAAK,oBAAoB;YACnC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,iBAAiB;gBAClC,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,iBAAiB;oBAClC,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,SAAS,CAAC;QAChB,KAAK,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,GAAG,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO;QACN,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM;QACN,KAAK;KACL,CAAC;AAAA,CACF","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type DoctorErrorCategory = \"network\" | \"auth\" | \"model\" | \"config\" | \"unknown\";\n\nexport interface ProviderDoctorResult {\n\tprovider: string;\n\tstatus: \"ok\" | \"fail\";\n\tbaseUrl?: string;\n\tchecks: ProviderDoctorCheck[];\n\terror?: {\n\t\tcategory: DoctorErrorCategory;\n\t\tmessage: string;\n\t};\n}\n\nexport interface ProviderDoctorCheck {\n\tname: string;\n\tstatus: \"ok\" | \"fail\" | \"skipped\";\n\tmessage?: string;\n}\n\ninterface ProviderConfig {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n}\n\nexport function getAgentDir(): string {\n\treturn join(homedir(), \".omk\", \"agent\");\n}\n\nfunction loadJson<T>(path: string): T | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction resolveConfig(providerId: string): { config: ProviderConfig; source: string } | undefined {\n\tconst agentDir = getAgentDir();\n\n\tconst modelsPath = join(agentDir, \"models.json\");\n\tconst models = loadJson<{ providers?: Record<string, ProviderConfig> }>(modelsPath);\n\tif (models?.providers?.[providerId]) {\n\t\treturn { config: models.providers[providerId], source: \"models.json\" };\n\t}\n\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst auth = loadJson<Record<string, { type: string; key?: string }>>(authPath);\n\tif (auth?.[providerId]) {\n\t\treturn {\n\t\t\tconfig: { apiKey: auth[providerId].key },\n\t\t\tsource: \"auth.json\",\n\t\t};\n\t}\n\n\t// Built-in local Grok OAuth proxy defaults (no secrets; loopback only).\n\tif (providerId === \"grok-oauth-proxy\") {\n\t\treturn {\n\t\t\tconfig: {\n\t\t\t\tbaseUrl: \"http://127.0.0.1:9996/v1\",\n\t\t\t\tapi: \"openai-completions\",\n\t\t\t\tapiKey: \"dummy\",\n\t\t\t},\n\t\t\tsource: \"built-in-grok-oauth-proxy-defaults\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\nexport async function diagnoseProvider(providerId: string): Promise<ProviderDoctorResult> {\n\tconst resolved = resolveConfig(providerId);\n\tif (!resolved) {\n\t\treturn {\n\t\t\tprovider: providerId,\n\t\t\tstatus: \"fail\",\n\t\t\tchecks: [],\n\t\t\terror: { category: \"config\", message: `Provider \"${providerId}\" not found in models.json or auth.json` },\n\t\t};\n\t}\n\n\tconst { config } = resolved;\n\tconst checks: ProviderDoctorCheck[] = [];\n\n\t// 1. Config presence\n\tchecks.push({\n\t\tname: \"config-present\",\n\t\tstatus: \"ok\",\n\t\tmessage: `Found provider config in ${resolved.source}`,\n\t});\n\n\t// 2. Base URL / health reachability\n\t// OpenAI-compatible roots often 404 on GET /v1; prefer /health for local Grok proxy.\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst probeUrl = providerId === \"grok-oauth-proxy\" ? new URL(\"/health\", config.baseUrl).href : config.baseUrl;\n\t\t\tconst res = await fetch(probeUrl, { method: \"GET\" });\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `${probeUrl} → HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"base-url-reachable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"base-url-reachable\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\t// 3. API key presence (never log the value)\n\tchecks.push({\n\t\tname: \"api-key-present\",\n\t\tstatus: config.apiKey ? \"ok\" : \"skipped\",\n\t\tmessage: config.apiKey ? \"API key is configured\" : \"No API key configured\",\n\t});\n\n\t// 4. Models endpoint probe\n\tif (config.baseUrl) {\n\t\ttry {\n\t\t\tconst headers: Record<string, string> = {};\n\t\t\tif (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;\n\t\t\tconst res = await fetch(`${config.baseUrl.replace(/\\/$/, \"\")}/models`, { headers });\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: res.ok ? \"ok\" : \"fail\",\n\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"models-endpoint\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} else {\n\t\tchecks.push({ name: \"models-endpoint\", status: \"skipped\", message: \"No baseUrl configured\" });\n\t}\n\n\tconst failed = checks.find((c) => c.status === \"fail\");\n\tlet error: ProviderDoctorResult[\"error\"];\n\tif (failed) {\n\t\tconst category: DoctorErrorCategory =\n\t\t\tfailed.name === \"base-url-reachable\"\n\t\t\t\t? \"network\"\n\t\t\t\t: failed.name === \"api-key-present\"\n\t\t\t\t\t? \"auth\"\n\t\t\t\t\t: failed.name === \"models-endpoint\"\n\t\t\t\t\t\t? \"model\"\n\t\t\t\t\t\t: \"unknown\";\n\t\terror = { category, message: failed.message ?? `${failed.name} failed` };\n\t}\n\n\treturn {\n\t\tprovider: providerId,\n\t\tstatus: failed ? \"fail\" : \"ok\",\n\t\tbaseUrl: config.baseUrl,\n\t\tchecks,\n\t\terror,\n\t};\n}\n"]}