@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.
- package/.env.example +28 -21
- package/AGENTS.md +183 -28
- package/ARCHITECTURE.md +17 -20
- package/LICENSE.md +1 -0
- package/README.md +269 -66
- package/assets/cli/hiai-opencode.mjs +276 -0
- package/assets/mcp/mempalace.mjs +47 -4
- package/assets/mcp/playwright.mjs +83 -0
- package/config/hiai-opencode.schema.json +113 -1
- package/dist/config/index.d.ts +0 -1
- package/dist/config/platform-schema.d.ts +72 -0
- package/dist/config/schema/agent-overrides.d.ts +256 -0
- package/dist/config/schema/categories.d.ts +2 -2
- package/dist/config/schema/commands.d.ts +1 -0
- package/dist/config/schema/index.d.ts +2 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +267 -0
- package/dist/config/schema/skill-discovery.d.ts +11 -0
- package/dist/config/types.d.ts +12 -1
- package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
- package/dist/index.js +617 -421
- package/dist/mcp/registry.d.ts +14 -0
- package/dist/mcp/types.d.ts +6 -0
- package/dist/plugin/skill-discovery-config.d.ts +4 -0
- package/dist/shared/startup-diagnostics.d.ts +6 -0
- package/hiai-opencode.json +192 -36
- package/package.json +4 -1
- package/src/agents/AGENTS.md +3 -4
- package/src/config/defaults.ts +55 -133
- package/src/config/index.ts +0 -1
- package/src/config/loader.ts +4 -1
- package/src/config/platform-schema.ts +18 -2
- package/src/config/schema/agent-overrides.ts +2 -0
- package/src/config/schema/commands.ts +1 -0
- package/src/config/schema/fast-apply.ts +4 -4
- package/src/config/schema/index.ts +2 -0
- package/src/config/schema/oh-my-opencode-config.ts +3 -0
- package/src/config/schema/skill-discovery.ts +25 -0
- package/src/config/types.ts +16 -0
- package/src/features/builtin-commands/commands.ts +7 -0
- package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
- package/src/features/builtin-commands/types.ts +1 -1
- package/src/features/builtin-skills/skills/playwright.ts +24 -2
- package/src/features/opencode-skill-loader/loader.ts +11 -0
- package/src/index.ts +15 -13
- package/src/mcp/index.ts +0 -33
- package/src/mcp/omo-mcp-index.ts +0 -5
- package/src/mcp/registry.ts +132 -0
- package/src/mcp/types.ts +11 -1
- package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
- package/src/plugin/skill-context.ts +31 -13
- package/src/plugin/skill-discovery-config.ts +32 -0
- package/src/plugin-handlers/agent-config-handler.ts +20 -13
- package/src/plugin-handlers/command-config-handler.ts +22 -12
- package/src/shared/migration/agent-names.ts +5 -5
- package/src/shared/startup-diagnostics.ts +77 -0
- 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
|
+
})
|
package/assets/mcp/mempalace.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
140
|
-
[...
|
|
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
|
}
|
package/dist/config/index.d.ts
CHANGED
|
@@ -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";
|