@hiai-gg/hiai-opencode 0.1.2 → 0.1.4

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 (58) hide show
  1. package/.env.example +28 -21
  2. package/AGENTS.md +183 -28
  3. package/ARCHITECTURE.md +17 -20
  4. package/LICENSE.md +1 -0
  5. package/README.md +269 -66
  6. package/assets/cli/hiai-opencode.mjs +276 -0
  7. package/assets/mcp/mempalace.mjs +47 -4
  8. package/assets/mcp/playwright.mjs +83 -0
  9. package/config/hiai-opencode.schema.json +113 -1
  10. package/dist/config/index.d.ts +0 -1
  11. package/dist/config/platform-schema.d.ts +72 -0
  12. package/dist/config/schema/agent-overrides.d.ts +256 -0
  13. package/dist/config/schema/categories.d.ts +2 -2
  14. package/dist/config/schema/commands.d.ts +1 -0
  15. package/dist/config/schema/index.d.ts +2 -0
  16. package/dist/config/schema/oh-my-opencode-config.d.ts +267 -0
  17. package/dist/config/schema/skill-discovery.d.ts +11 -0
  18. package/dist/config/types.d.ts +12 -1
  19. package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
  20. package/dist/features/builtin-commands/types.d.ts +1 -1
  21. package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
  22. package/dist/index.js +617 -421
  23. package/dist/mcp/registry.d.ts +14 -0
  24. package/dist/mcp/types.d.ts +6 -0
  25. package/dist/plugin/skill-discovery-config.d.ts +4 -0
  26. package/dist/shared/startup-diagnostics.d.ts +6 -0
  27. package/hiai-opencode.json +192 -36
  28. package/package.json +4 -1
  29. package/src/agents/AGENTS.md +3 -4
  30. package/src/config/defaults.ts +55 -133
  31. package/src/config/index.ts +0 -1
  32. package/src/config/loader.ts +4 -1
  33. package/src/config/platform-schema.ts +18 -2
  34. package/src/config/schema/agent-overrides.ts +2 -0
  35. package/src/config/schema/commands.ts +1 -0
  36. package/src/config/schema/fast-apply.ts +4 -4
  37. package/src/config/schema/index.ts +2 -0
  38. package/src/config/schema/oh-my-opencode-config.ts +3 -0
  39. package/src/config/schema/skill-discovery.ts +25 -0
  40. package/src/config/types.ts +16 -0
  41. package/src/features/builtin-commands/commands.ts +7 -0
  42. package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
  43. package/src/features/builtin-commands/types.ts +1 -1
  44. package/src/features/builtin-skills/skills/playwright.ts +24 -2
  45. package/src/features/opencode-skill-loader/loader.ts +11 -0
  46. package/src/index.ts +15 -13
  47. package/src/mcp/index.ts +0 -33
  48. package/src/mcp/omo-mcp-index.ts +0 -5
  49. package/src/mcp/registry.ts +132 -0
  50. package/src/mcp/types.ts +11 -1
  51. package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
  52. package/src/plugin/skill-context.ts +31 -13
  53. package/src/plugin/skill-discovery-config.ts +32 -0
  54. package/src/plugin-handlers/agent-config-handler.ts +20 -13
  55. package/src/plugin-handlers/command-config-handler.ts +22 -12
  56. package/src/shared/migration/agent-names.ts +5 -5
  57. package/src/shared/startup-diagnostics.ts +77 -0
  58. package/src/config/models.ts +0 -32
@@ -0,0 +1,276 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from "node:child_process"
4
+ import { existsSync, readFileSync } from "node:fs"
5
+ import { dirname, join } from "node:path"
6
+ import { homedir } from "node:os"
7
+ import { parse } from "jsonc-parser"
8
+
9
+ const DEFAULT_RAG_URL = "http://localhost:9002/tools/search"
10
+
11
+ const MCP_REGISTRY = {
12
+ playwright: {
13
+ defaultEnabled: true,
14
+ requiredEnv: [],
15
+ check: checkNodeNpx,
16
+ },
17
+ rag: {
18
+ defaultEnabled: true,
19
+ requiredEnv: [],
20
+ check: checkRag,
21
+ },
22
+ firecrawl: {
23
+ defaultEnabled: true,
24
+ requiredEnv: ["FIRECRAWL_API_KEY"],
25
+ authFallback: "firecrawl",
26
+ check: checkNodeNpx,
27
+ },
28
+ mempalace: {
29
+ defaultEnabled: true,
30
+ requiredEnv: [],
31
+ check: checkMempalace,
32
+ },
33
+ stitch: {
34
+ defaultEnabled: true,
35
+ requiredEnv: ["STITCH_AI_API_KEY"],
36
+ authFallback: "stitch",
37
+ check: checkRemoteKeyOnly,
38
+ },
39
+ context7: {
40
+ defaultEnabled: true,
41
+ requiredEnv: [],
42
+ check: checkRemoteOptionalKey,
43
+ },
44
+ "sequential-thinking": {
45
+ defaultEnabled: true,
46
+ requiredEnv: [],
47
+ check: checkNodeNpx,
48
+ },
49
+ }
50
+
51
+ function usage() {
52
+ console.log(`hiai-opencode
53
+
54
+ Usage:
55
+ hiai-opencode mcp-status
56
+
57
+ Commands:
58
+ mcp-status Check hiai-opencode MCP configuration, keys, and local runtimes.
59
+ `)
60
+ }
61
+
62
+ function resolveEnvTemplate(value) {
63
+ if (typeof value !== "string") return value
64
+ return value.replace(/\{env:([^}]+)\}/g, (_match, expression) => {
65
+ const [name, fallback] = String(expression).split(":-", 2)
66
+ return process.env[name] || fallback || ""
67
+ })
68
+ }
69
+
70
+ function candidateConfigPaths() {
71
+ const cwd = process.cwd()
72
+ const paths = [
73
+ join(cwd, "hiai-opencode.json"),
74
+ join(cwd, "hiai-opencode.jsonc"),
75
+ join(cwd, ".opencode", "hiai-opencode.json"),
76
+ join(cwd, ".opencode", "hiai-opencode.jsonc"),
77
+ join(homedir(), ".config", "opencode", "hiai-opencode.json"),
78
+ join(homedir(), ".config", "opencode", "hiai-opencode.jsonc"),
79
+ ]
80
+
81
+ if (process.platform === "win32" && process.env.APPDATA) {
82
+ paths.push(join(process.env.APPDATA, "opencode", "hiai-opencode.json"))
83
+ paths.push(join(process.env.APPDATA, "opencode", "hiai-opencode.jsonc"))
84
+ }
85
+
86
+ return paths
87
+ }
88
+
89
+ function loadConfig() {
90
+ for (const path of candidateConfigPaths()) {
91
+ if (!existsSync(path)) continue
92
+ try {
93
+ return {
94
+ path,
95
+ config: parse(readFileSync(path, "utf-8")) ?? {},
96
+ }
97
+ } catch (error) {
98
+ return {
99
+ path,
100
+ config: {},
101
+ error: error instanceof Error ? error.message : String(error),
102
+ }
103
+ }
104
+ }
105
+
106
+ return { path: null, config: {} }
107
+ }
108
+
109
+ function hasCommand(command, args = ["--version"]) {
110
+ const result = spawnSync(command, args, {
111
+ stdio: "ignore",
112
+ timeout: 10000,
113
+ shell: process.platform === "win32",
114
+ })
115
+ return result.status === 0
116
+ }
117
+
118
+ function hasNode() {
119
+ return hasCommand(process.platform === "win32" ? "node.exe" : "node")
120
+ }
121
+
122
+ function hasNpx() {
123
+ return hasCommand(process.platform === "win32" ? "npx.cmd" : "npx")
124
+ }
125
+
126
+ function checkNodeNpx() {
127
+ const node = hasNode()
128
+ const npx = hasNpx()
129
+ if (node && npx) return { level: "ok", detail: "backend ok" }
130
+ return {
131
+ level: "error",
132
+ detail: `${node ? "node ok" : "node not found"}, ${npx ? "npx ok" : "npx not found"}`,
133
+ }
134
+ }
135
+
136
+ function pythonCandidates() {
137
+ const configured = process.env.MEMPALACE_PYTHON?.trim()
138
+ const candidates = []
139
+ if (configured) candidates.push(configured)
140
+ if (process.platform === "win32") {
141
+ candidates.push("py", "python", "python3")
142
+ } else {
143
+ candidates.push("python3", "python")
144
+ }
145
+ return [...new Set(candidates)]
146
+ }
147
+
148
+ function canImportMempalace(command) {
149
+ const args =
150
+ command === "py"
151
+ ? ["-3", "-c", "import mempalace.mcp_server"]
152
+ : ["-c", "import mempalace.mcp_server"]
153
+ const result = spawnSync(command, args, {
154
+ stdio: "ignore",
155
+ timeout: 10000,
156
+ shell: process.platform === "win32",
157
+ })
158
+ return result.status === 0
159
+ }
160
+
161
+ function checkMempalace() {
162
+ if (hasCommand(process.platform === "win32" ? "uv.exe" : "uv")) {
163
+ return { level: "ok", detail: "uv available" }
164
+ }
165
+
166
+ for (const candidate of pythonCandidates()) {
167
+ if (canImportMempalace(candidate)) {
168
+ return { level: "ok", detail: `${candidate} with mempalace available` }
169
+ }
170
+ }
171
+
172
+ const hasPython = pythonCandidates().some((candidate) =>
173
+ hasCommand(candidate, candidate === "py" ? ["-3", "--version"] : ["--version"]),
174
+ )
175
+
176
+ return {
177
+ level: "error",
178
+ detail: hasPython ? "mempalace Python package not found" : "python not found",
179
+ }
180
+ }
181
+
182
+ async function checkRag(config) {
183
+ const url =
184
+ process.env.OPENCODE_RAG_URL?.trim()
185
+ || resolveEnvTemplate(config?.mcp?.rag?.environment?.OPENCODE_RAG_URL)
186
+ || DEFAULT_RAG_URL
187
+
188
+ try {
189
+ const controller = new AbortController()
190
+ const timeout = setTimeout(() => controller.abort(), 2500)
191
+ const response = await fetch(url, { method: "GET", signal: controller.signal })
192
+ clearTimeout(timeout)
193
+
194
+ if (response.status < 500) {
195
+ return { level: "ok", detail: `enabled, ${url} reachable` }
196
+ }
197
+ return { level: "warn", detail: `enabled, ${url} returned ${response.status}` }
198
+ } catch {
199
+ return { level: "warn", detail: `enabled, ${url} not reachable` }
200
+ }
201
+ }
202
+
203
+ function checkRemoteKeyOnly() {
204
+ return { level: "ok", detail: "remote endpoint configured" }
205
+ }
206
+
207
+ function checkRemoteOptionalKey(_config, name) {
208
+ if (name === "context7" && !process.env.CONTEXT7_API_KEY?.trim()) {
209
+ return { level: "ok", detail: "remote endpoint configured, API key optional/missing" }
210
+ }
211
+ return { level: "ok", detail: "remote endpoint configured" }
212
+ }
213
+
214
+ function hasEnvOrAuth(config, envName, authKey) {
215
+ if (process.env[envName]?.trim()) return true
216
+ if (authKey && config?.auth?.[authKey]?.trim()) return true
217
+ return false
218
+ }
219
+
220
+ function statusIcon(level) {
221
+ if (level === "ok") return "✅"
222
+ if (level === "warn") return "⚠️ "
223
+ return "❌"
224
+ }
225
+
226
+ async function mcpStatus() {
227
+ const { path, config, error } = loadConfig()
228
+ console.log("hiai-opencode mcp-status")
229
+ console.log(`Config: ${path ?? "not found; using defaults"}`)
230
+ if (error) console.log(`Config parse warning: ${error}`)
231
+ console.log("")
232
+ console.log("MCP Servers:")
233
+
234
+ for (const [name, entry] of Object.entries(MCP_REGISTRY)) {
235
+ const userEntry = config?.mcp?.[name]
236
+ const enabled = userEntry?.enabled ?? entry.defaultEnabled
237
+ if (!enabled) {
238
+ console.log(`⚪ ${name.padEnd(20)} - disabled`)
239
+ continue
240
+ }
241
+
242
+ const missingEnv = entry.requiredEnv.filter((envName) =>
243
+ !hasEnvOrAuth(config, envName, entry.authFallback),
244
+ )
245
+
246
+ if (missingEnv.length > 0) {
247
+ console.log(`⚠️ ${name.padEnd(20)} - enabled, API key missing (${missingEnv.join(", ")})`)
248
+ continue
249
+ }
250
+
251
+ const result = await entry.check(config, name)
252
+ console.log(`${statusIcon(result.level)} ${name.padEnd(20)} - ${result.detail}`)
253
+ }
254
+ }
255
+
256
+ async function main() {
257
+ const command = process.argv[2]
258
+ if (!command || command === "-h" || command === "--help") {
259
+ usage()
260
+ return
261
+ }
262
+
263
+ if (command === "mcp-status") {
264
+ await mcpStatus()
265
+ return
266
+ }
267
+
268
+ console.error(`Unknown command: ${command}`)
269
+ usage()
270
+ process.exit(1)
271
+ }
272
+
273
+ main().catch((error) => {
274
+ console.error(error instanceof Error ? error.message : String(error))
275
+ process.exit(1)
276
+ })
@@ -74,6 +74,37 @@ function resolvePythonForMempalace() {
74
74
  return null;
75
75
  }
76
76
 
77
+ function resolvePythonForPip() {
78
+ for (const candidate of pythonCandidates()) {
79
+ const probe = spawnSync(
80
+ candidate.command,
81
+ [...candidate.args, "-m", "pip", "--version"],
82
+ { stdio: "ignore", timeout: 10000 },
83
+ );
84
+
85
+ if (probe.status === 0) {
86
+ return candidate;
87
+ }
88
+ }
89
+
90
+ return null;
91
+ }
92
+
93
+ function shouldAutoInstall() {
94
+ const value = process.env.HIAI_MCP_AUTO_INSTALL?.trim().toLowerCase();
95
+ return value !== "0" && value !== "false" && value !== "no";
96
+ }
97
+
98
+ function installMempalaceWithPip(candidate) {
99
+ const result = spawnSync(
100
+ candidate.command,
101
+ [...candidate.args, "-m", "pip", "install", "--user", "mempalace"],
102
+ { stdio: "inherit", timeout: 300000 },
103
+ );
104
+
105
+ return result.status === 0 && canRunModule(candidate, "mempalace.mcp_server");
106
+ }
107
+
77
108
  function resolveUvCacheRoot() {
78
109
  return process.env.UV_CACHE_DIR
79
110
  || join(resolveCacheRoot(), "hiai-opencode", "uv");
@@ -128,16 +159,28 @@ function main() {
128
159
  }
129
160
 
130
161
  const python = resolvePythonForMempalace();
131
- if (!python) {
162
+ const fallbackPython =
163
+ python
164
+ || (shouldAutoInstall()
165
+ ? (() => {
166
+ const pipPython = resolvePythonForPip();
167
+ if (pipPython && installMempalaceWithPip(pipPython)) {
168
+ return pipPython;
169
+ }
170
+ return null;
171
+ })()
172
+ : null);
173
+
174
+ if (!fallbackPython) {
132
175
  console.error(
133
- "[hiai-opencode] mempalace skipped: install uv or Python 3.9+ with `pip install mempalace`",
176
+ "[hiai-opencode] mempalace skipped: install uv or Python 3.9+ with `pip install --user mempalace`",
134
177
  );
135
178
  process.exit(0);
136
179
  }
137
180
 
138
181
  const child = spawn(
139
- python.command,
140
- [...python.args, "-m", "mempalace.mcp_server", "--palace", palacePath],
182
+ fallbackPython.command,
183
+ [...fallbackPython.args, "-m", "mempalace.mcp_server", "--palace", palacePath],
141
184
  {
142
185
  stdio: "inherit",
143
186
  env: {
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { mkdirSync } from "node:fs"
4
+ import { dirname, join } from "node:path"
5
+ import { fileURLToPath } from "node:url"
6
+ import { spawn, spawnSync } from "node:child_process"
7
+
8
+ function resolveCacheRoot() {
9
+ const xdgCache = process.env.XDG_CACHE_HOME?.trim()
10
+ if (xdgCache) return xdgCache
11
+
12
+ const scriptDir = dirname(fileURLToPath(import.meta.url))
13
+ const pluginRoot = join(scriptDir, "..", "..")
14
+ return join(pluginRoot, ".runtime-cache")
15
+ }
16
+
17
+ function runNpx(args, stdio = "inherit") {
18
+ const cacheRoot = join(resolveCacheRoot(), "hiai-opencode", "npm")
19
+ const tempRoot = join(cacheRoot, "tmp")
20
+ mkdirSync(tempRoot, { recursive: true })
21
+
22
+ const npxCommand = process.platform === "win32" ? "npx.cmd" : "npx"
23
+ return spawnSync(npxCommand, args, {
24
+ stdio,
25
+ shell: process.platform === "win32",
26
+ env: {
27
+ ...process.env,
28
+ npm_config_cache: cacheRoot,
29
+ NPM_CONFIG_CACHE: cacheRoot,
30
+ TEMP: tempRoot,
31
+ TMP: tempRoot,
32
+ },
33
+ })
34
+ }
35
+
36
+ function shouldInstallBrowsers() {
37
+ const value = process.env.HIAI_PLAYWRIGHT_INSTALL_BROWSERS?.trim().toLowerCase()
38
+ return value === "1" || value === "true" || value === "yes"
39
+ }
40
+
41
+ if (shouldInstallBrowsers()) {
42
+ const result = runNpx(["-y", "playwright@latest", "install", "chromium"])
43
+ if (result.status !== 0) {
44
+ console.error("[hiai-opencode] playwright browser install failed")
45
+ console.error("[hiai-opencode] Try: npx playwright install chromium")
46
+ }
47
+
48
+ if (process.platform === "linux") {
49
+ console.error("[hiai-opencode] Playwright Chromium may also need Linux system libraries.")
50
+ console.error("[hiai-opencode] If browser launch fails with libnspr4/libnss3/libgtk errors, run: sudo npx playwright install-deps chromium")
51
+ console.error("[hiai-opencode] Without sudo, use an existing browser by adding args in hiai-opencode.json, e.g. --browser chrome")
52
+ }
53
+ }
54
+
55
+ const cacheRoot = join(resolveCacheRoot(), "hiai-opencode", "npm")
56
+ const tempRoot = join(cacheRoot, "tmp")
57
+ mkdirSync(tempRoot, { recursive: true })
58
+
59
+ const npxCommand = process.platform === "win32" ? "npx.cmd" : "npx"
60
+ const child = spawn(npxCommand, ["-y", "@playwright/mcp@latest", ...process.argv.slice(2)], {
61
+ stdio: "inherit",
62
+ shell: process.platform === "win32",
63
+ env: {
64
+ ...process.env,
65
+ npm_config_cache: cacheRoot,
66
+ NPM_CONFIG_CACHE: cacheRoot,
67
+ TEMP: tempRoot,
68
+ TMP: tempRoot,
69
+ },
70
+ })
71
+
72
+ child.on("exit", (code, signal) => {
73
+ if (signal) {
74
+ process.kill(process.pid, signal)
75
+ return
76
+ }
77
+ process.exit(code ?? 0)
78
+ })
79
+
80
+ child.on("error", (error) => {
81
+ console.error("[hiai-opencode] playwright launcher failed:", error)
82
+ process.exit(1)
83
+ })
@@ -16,6 +16,23 @@
16
16
  "required": ["model"]
17
17
  }
18
18
  },
19
+ "agentRequirements": {
20
+ "type": "object",
21
+ "additionalProperties": {
22
+ "type": "object",
23
+ "properties": {
24
+ "fallbackChain": {
25
+ "type": "array",
26
+ "items": { "$ref": "#/definitions/fallbackEntry" }
27
+ },
28
+ "variant": { "type": "string" },
29
+ "requiresModel": { "type": "string" },
30
+ "requiresAnyModel": { "type": "boolean" },
31
+ "requiresProvider": { "type": "array", "items": { "type": "string" } }
32
+ },
33
+ "required": ["fallbackChain"]
34
+ }
35
+ },
19
36
  "categories": {
20
37
  "type": "object",
21
38
  "additionalProperties": {
@@ -23,11 +40,47 @@
23
40
  "properties": {
24
41
  "model": { "type": "string" },
25
42
  "variant": { "type": "string" },
26
- "description": { "type": "string" }
43
+ "description": { "type": "string" },
44
+ "fallbackChain": {
45
+ "type": "array",
46
+ "items": { "$ref": "#/definitions/fallbackEntry" }
47
+ }
27
48
  },
28
49
  "required": ["model"]
29
50
  }
30
51
  },
52
+ "categoryRequirements": {
53
+ "type": "object",
54
+ "additionalProperties": {
55
+ "type": "object",
56
+ "properties": {
57
+ "fallbackChain": {
58
+ "type": "array",
59
+ "items": { "$ref": "#/definitions/fallbackEntry" }
60
+ },
61
+ "variant": { "type": "string" },
62
+ "requiresModel": { "type": "string" },
63
+ "requiresAnyModel": { "type": "boolean" },
64
+ "requiresProvider": { "type": "array", "items": { "type": "string" } }
65
+ },
66
+ "required": ["fallbackChain"]
67
+ }
68
+ },
69
+ "modelFamilies": {
70
+ "type": "array",
71
+ "items": {
72
+ "type": "object",
73
+ "properties": {
74
+ "family": { "type": "string" },
75
+ "includes": { "type": "array", "items": { "type": "string" } },
76
+ "pattern": { "type": "string" },
77
+ "variants": { "type": "array", "items": { "type": "string" } },
78
+ "reasoningEfforts": { "type": "array", "items": { "type": "string" } },
79
+ "supportsThinking": { "type": "boolean" }
80
+ },
81
+ "required": ["family"]
82
+ }
83
+ },
31
84
  "mcp": {
32
85
  "type": "object",
33
86
  "additionalProperties": {
@@ -36,6 +89,7 @@
36
89
  "enabled": { "type": "boolean", "default": true },
37
90
  "type": { "enum": ["remote", "local"] },
38
91
  "url": { "type": "string" },
92
+ "headers": { "type": "object", "additionalProperties": { "type": "string" } },
39
93
  "command": { "type": "array", "items": { "type": "string" } },
40
94
  "timeout": { "type": "number" },
41
95
  "environment": { "type": "object", "additionalProperties": { "type": "string" } }
@@ -69,6 +123,19 @@
69
123
  "disabled": { "type": "array", "items": { "type": "string" } }
70
124
  }
71
125
  },
126
+ "skill_discovery": {
127
+ "type": "object",
128
+ "description": "Controls which external skill directories are scanned. Defaults keep installs deterministic: hiai-opencode skills plus project .opencode/skills only.",
129
+ "properties": {
130
+ "config_sources": { "type": "boolean", "default": true },
131
+ "project_opencode": { "type": "boolean", "default": true },
132
+ "global_opencode": { "type": "boolean", "default": false },
133
+ "project_claude": { "type": "boolean", "default": false },
134
+ "global_claude": { "type": "boolean", "default": false },
135
+ "project_agents": { "type": "boolean", "default": false },
136
+ "global_agents": { "type": "boolean", "default": false }
137
+ }
138
+ },
72
139
  "permissions": {
73
140
  "type": "object",
74
141
  "properties": {
@@ -77,6 +144,51 @@
77
144
  "bash": { "type": "object", "additionalProperties": { "type": "string" } },
78
145
  "deny_paths": { "type": "array", "items": { "type": "string" } }
79
146
  }
147
+ },
148
+ "auth": {
149
+ "type": "object",
150
+ "additionalProperties": { "type": "string" }
151
+ },
152
+ "ollama": {
153
+ "type": "object",
154
+ "properties": {
155
+ "enabled": { "type": "boolean", "default": false },
156
+ "model": { "type": "string" },
157
+ "baseUrl": { "type": "string" },
158
+ "purpose": { "enum": ["verification", "helper", "fallback"] }
159
+ }
160
+ },
161
+ "fast_apply": {
162
+ "type": "object",
163
+ "properties": {
164
+ "enabled": { "type": "boolean", "default": false },
165
+ "ollama_url": { "type": "string" },
166
+ "model": { "type": "string" },
167
+ "timeout": { "type": "number" }
168
+ }
169
+ }
170
+ },
171
+ "definitions": {
172
+ "fallbackEntry": {
173
+ "type": "object",
174
+ "properties": {
175
+ "providers": { "type": "array", "items": { "type": "string" } },
176
+ "model": { "type": "string" },
177
+ "variant": { "type": "string" },
178
+ "reasoningEffort": { "type": "string" },
179
+ "temperature": { "type": "number" },
180
+ "top_p": { "type": "number" },
181
+ "maxTokens": { "type": "number" },
182
+ "thinking": {
183
+ "type": "object",
184
+ "properties": {
185
+ "type": { "enum": ["enabled", "disabled"] },
186
+ "budgetTokens": { "type": "number" }
187
+ },
188
+ "required": ["type"]
189
+ }
190
+ },
191
+ "required": ["providers", "model"]
80
192
  }
81
193
  }
82
194
  }
@@ -9,7 +9,6 @@
9
9
  export { loadConfig, resolveEnvVars, resolveMcpEnv } from "./loader.js";
10
10
  export { HiaiOpencodeConfigSchema } from "./platform-schema.js";
11
11
  export { defaultConfig } from "./defaults.js";
12
- export { MODEL_PRESETS, MODEL_ROLE_GUIDE, PROVIDER_MODEL_RULES } from "./models.js";
13
12
  export type { HiaiOpencodeConfig, AgentConfig, CategoryConfig, McpServerConfig, LspServerConfig, Subtask2Config, SkillsConfig as PlatformSkillsConfig, PermissionsConfig as PlatformPermissionsConfig, } from "./types.js";
14
13
  export { HiaiOpenCodeConfigSchema } from "./schema/oh-my-opencode-config.js";
15
14
  export type { HiaiOpenCodeConfig } from "./schema/oh-my-opencode-config.js";