@hiai-gg/hiai-opencode 0.1.3 → 0.1.5
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 +14 -18
- package/AGENTS.md +77 -23
- package/ARCHITECTURE.md +15 -17
- package/LICENSE.md +1 -0
- package/README.md +189 -94
- package/assets/cli/hiai-opencode.mjs +276 -0
- package/assets/mcp/playwright.mjs +7 -0
- package/config/hiai-opencode.schema.json +85 -50
- package/dist/config/defaults.d.ts +1 -3
- package/dist/config/index.d.ts +0 -1
- package/dist/config/platform-schema.d.ts +343 -4
- package/dist/config/schema/agent-overrides.d.ts +256 -0
- package/dist/config/schema/categories.d.ts +1 -1
- 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 +33 -3
- package/dist/create-tools.d.ts +2 -0
- 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 +744 -358
- package/dist/internals/plugins/websearch-cited/index.d.ts +7 -1
- package/dist/mcp/types.d.ts +1 -1
- package/dist/plugin/skill-discovery-config.d.ts +4 -0
- package/dist/plugin/tool-registry.d.ts +2 -0
- package/dist/shared/startup-diagnostics.d.ts +6 -0
- package/dist/tools/skill-mcp/tools.d.ts +2 -0
- package/hiai-opencode.json +55 -33
- package/package.json +4 -1
- package/src/agents/AGENTS.md +3 -4
- package/src/config/defaults.ts +186 -77
- package/src/config/index.ts +0 -1
- package/src/config/loader.test.ts +16 -1
- package/src/config/loader.ts +4 -2
- package/src/config/platform-schema.ts +53 -4
- 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 +49 -2
- package/src/create-tools.ts +4 -1
- 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 +53 -14
- package/src/internals/plugins/websearch-cited/index.ts +10 -5
- package/src/lsp/index.ts +1 -0
- package/src/mcp/registry.ts +6 -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/tool-registry.ts +4 -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/tools/skill-mcp/tools.ts +45 -7
- package/src/config/models.ts +0 -32
package/dist/index.js
CHANGED
|
@@ -146,9 +146,9 @@ var init_agent_names = __esm(() => {
|
|
|
146
146
|
subagent: "coder",
|
|
147
147
|
sub: "coder",
|
|
148
148
|
designer: "designer",
|
|
149
|
-
ui: "
|
|
150
|
-
vision: "
|
|
151
|
-
multimodal: "
|
|
149
|
+
ui: "multimodal",
|
|
150
|
+
vision: "multimodal",
|
|
151
|
+
multimodal: "multimodal"
|
|
152
152
|
};
|
|
153
153
|
BUILTIN_AGENT_NAMES = new Set([
|
|
154
154
|
"bob",
|
|
@@ -157,7 +157,7 @@ var init_agent_names = __esm(() => {
|
|
|
157
157
|
"critic",
|
|
158
158
|
"designer",
|
|
159
159
|
"researcher",
|
|
160
|
-
"
|
|
160
|
+
"multimodal",
|
|
161
161
|
"platform-manager",
|
|
162
162
|
"guard"
|
|
163
163
|
]);
|
|
@@ -20778,8 +20778,8 @@ var require_resolve = __commonJS((exports) => {
|
|
|
20778
20778
|
}
|
|
20779
20779
|
return count;
|
|
20780
20780
|
}
|
|
20781
|
-
function getFullPath(resolver, id = "",
|
|
20782
|
-
if (
|
|
20781
|
+
function getFullPath(resolver, id = "", normalize4) {
|
|
20782
|
+
if (normalize4 !== false)
|
|
20783
20783
|
id = normalizeId(id);
|
|
20784
20784
|
const p = resolver.parse(id);
|
|
20785
20785
|
return _getFullPath(resolver, p);
|
|
@@ -22066,7 +22066,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
22066
22066
|
var require_fast_uri = __commonJS((exports, module) => {
|
|
22067
22067
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils2();
|
|
22068
22068
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
22069
|
-
function
|
|
22069
|
+
function normalize4(uri, options) {
|
|
22070
22070
|
if (typeof uri === "string") {
|
|
22071
22071
|
uri = serialize(parse11(uri, options), options);
|
|
22072
22072
|
} else if (typeof uri === "object") {
|
|
@@ -22301,7 +22301,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
22301
22301
|
}
|
|
22302
22302
|
var fastUri = {
|
|
22303
22303
|
SCHEMES,
|
|
22304
|
-
normalize:
|
|
22304
|
+
normalize: normalize4,
|
|
22305
22305
|
resolve: resolve22,
|
|
22306
22306
|
resolveComponent,
|
|
22307
22307
|
equal,
|
|
@@ -33657,9 +33657,9 @@ function parseOpenAIOptions(providerConfig, model) {
|
|
|
33657
33657
|
}
|
|
33658
33658
|
return result;
|
|
33659
33659
|
}
|
|
33660
|
-
var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PROVIDER_ID = "openrouter", CITED_SEARCH_TOOL_DESCRIPTION = "Performs a Gemini-style grounded web search: returns a concise digest with inline citations and a Sources list of URLs. NOTE: for LLM rate limits, DO NOT parallel this tool > 5", WEBSEARCH_ARGS, WEBSEARCH_ALLOWED_KEYS, WEBSEARCH_ALLOWED_KEYS_DESCRIPTION, authRegistry, WebsearchCitedPlugin = () => {
|
|
33661
|
-
let selectedProvider;
|
|
33662
|
-
let selectedModel;
|
|
33660
|
+
var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PROVIDER_ID = "openrouter", CITED_SEARCH_TOOL_DESCRIPTION = "Performs a Gemini-style grounded web search: returns a concise digest with inline citations and a Sources list of URLs. NOTE: for LLM rate limits, DO NOT parallel this tool > 5", WEBSEARCH_ARGS, WEBSEARCH_ALLOWED_KEYS, WEBSEARCH_ALLOWED_KEYS_DESCRIPTION, authRegistry, WebsearchCitedPlugin = (_ctx, fallback) => {
|
|
33661
|
+
let selectedProvider = fallback?.providerID;
|
|
33662
|
+
let selectedModel = fallback?.model;
|
|
33663
33663
|
let openaiConfig = {};
|
|
33664
33664
|
let configError;
|
|
33665
33665
|
return Promise.resolve({
|
|
@@ -33689,6 +33689,9 @@ var GOOGLE_PROVIDER_ID = "google", OPENAI_PROVIDER_ID = "openai", OPENROUTER_PRO
|
|
|
33689
33689
|
const openaiProvider = config4.provider?.openai;
|
|
33690
33690
|
openaiConfig = parseOpenAIOptions(openaiProvider, selectedModel);
|
|
33691
33691
|
}
|
|
33692
|
+
} else if (!error92 && fallback) {
|
|
33693
|
+
selectedProvider = fallback.providerID;
|
|
33694
|
+
selectedModel = fallback.model;
|
|
33692
33695
|
}
|
|
33693
33696
|
return Promise.resolve();
|
|
33694
33697
|
},
|
|
@@ -33808,8 +33811,8 @@ class EventEmitter {
|
|
|
33808
33811
|
// node_modules/bun-pty/src/terminal.ts
|
|
33809
33812
|
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
33810
33813
|
import { Buffer as Buffer2 } from "buffer";
|
|
33811
|
-
import { join as
|
|
33812
|
-
import { existsSync as
|
|
33814
|
+
import { join as join104, dirname as dirname31, basename as basename16 } from "path";
|
|
33815
|
+
import { existsSync as existsSync92 } from "fs";
|
|
33813
33816
|
function shQuote(s) {
|
|
33814
33817
|
if (s.length === 0)
|
|
33815
33818
|
return "''";
|
|
@@ -33817,7 +33820,7 @@ function shQuote(s) {
|
|
|
33817
33820
|
}
|
|
33818
33821
|
function resolveLibPath() {
|
|
33819
33822
|
const env = process.env.BUN_PTY_LIB;
|
|
33820
|
-
if (env &&
|
|
33823
|
+
if (env && existsSync92(env))
|
|
33821
33824
|
return env;
|
|
33822
33825
|
try {
|
|
33823
33826
|
const embeddedPath = __require(`../rust-pty/target/release/${process.platform === "win32" ? "rust_pty.dll" : process.platform === "darwin" ? process.arch === "arm64" ? "librust_pty_arm64.dylib" : "librust_pty.dylib" : process.arch === "arm64" ? "librust_pty_arm64.so" : "librust_pty.so"}`);
|
|
@@ -33828,22 +33831,22 @@ function resolveLibPath() {
|
|
|
33828
33831
|
const arch = process.arch;
|
|
33829
33832
|
const filenames = platform2 === "darwin" ? arch === "arm64" ? ["librust_pty_arm64.dylib", "librust_pty.dylib"] : ["librust_pty.dylib"] : platform2 === "win32" ? ["rust_pty.dll"] : arch === "arm64" ? ["librust_pty_arm64.so", "librust_pty.so"] : ["librust_pty.so"];
|
|
33830
33833
|
const base = Bun.fileURLToPath(import.meta.url);
|
|
33831
|
-
const fileDir =
|
|
33834
|
+
const fileDir = dirname31(base);
|
|
33832
33835
|
const dirName = basename16(fileDir);
|
|
33833
|
-
const here = dirName === "src" || dirName === "dist" ?
|
|
33836
|
+
const here = dirName === "src" || dirName === "dist" ? dirname31(fileDir) : fileDir;
|
|
33834
33837
|
const basePaths = [
|
|
33835
|
-
|
|
33836
|
-
|
|
33837
|
-
|
|
33838
|
+
join104(here, "rust-pty", "target", "release"),
|
|
33839
|
+
join104(here, "..", "bun-pty", "rust-pty", "target", "release"),
|
|
33840
|
+
join104(process.cwd(), "node_modules", "bun-pty", "rust-pty", "target", "release")
|
|
33838
33841
|
];
|
|
33839
33842
|
const fallbackPaths = [];
|
|
33840
33843
|
for (const basePath of basePaths) {
|
|
33841
33844
|
for (const filename of filenames) {
|
|
33842
|
-
fallbackPaths.push(
|
|
33845
|
+
fallbackPaths.push(join104(basePath, filename));
|
|
33843
33846
|
}
|
|
33844
33847
|
}
|
|
33845
33848
|
for (const path10 of fallbackPaths) {
|
|
33846
|
-
if (
|
|
33849
|
+
if (existsSync92(path10))
|
|
33847
33850
|
return path10;
|
|
33848
33851
|
}
|
|
33849
33852
|
throw new Error(`librust_pty shared library not found.
|
|
@@ -35060,8 +35063,8 @@ var init_plugin = __esm(() => {
|
|
|
35060
35063
|
});
|
|
35061
35064
|
|
|
35062
35065
|
// src/index.ts
|
|
35063
|
-
import { existsSync as
|
|
35064
|
-
import { join as
|
|
35066
|
+
import { existsSync as existsSync93 } from "fs";
|
|
35067
|
+
import { join as join105 } from "path";
|
|
35065
35068
|
|
|
35066
35069
|
// src/hooks/todo-continuation-enforcer/index.ts
|
|
35067
35070
|
init_logger();
|
|
@@ -110591,6 +110594,11 @@ async function loadGlobalAgentsSkills() {
|
|
|
110591
110594
|
const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
|
|
110592
110595
|
return skillsToCommandDefinitionRecord(skills);
|
|
110593
110596
|
}
|
|
110597
|
+
async function loadManagedPluginSkills() {
|
|
110598
|
+
const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
|
|
110599
|
+
const skills = await loadSkillsFromDir({ skillsDir, scope: "builtin" });
|
|
110600
|
+
return skillsToCommandDefinitionRecord(skills);
|
|
110601
|
+
}
|
|
110594
110602
|
async function discoverAllSkills(directory) {
|
|
110595
110603
|
const [opencodeProjectSkills, opencodeGlobalSkills, projectSkills, userSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
|
|
110596
110604
|
discoverOpencodeProjectSkills(directory),
|
|
@@ -110661,6 +110669,10 @@ async function discoverGlobalAgentsSkills() {
|
|
|
110661
110669
|
const agentsGlobalDir = join60(getAgentsConfigDir(), "skills");
|
|
110662
110670
|
return loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
|
|
110663
110671
|
}
|
|
110672
|
+
async function discoverManagedPluginSkills() {
|
|
110673
|
+
const skillsDir = join60(getOpenCodeConfigDir({ binary: "opencode" }), ".hiai", "skills", "plugin");
|
|
110674
|
+
return loadSkillsFromDir({ skillsDir, scope: "builtin" });
|
|
110675
|
+
}
|
|
110664
110676
|
// src/features/opencode-skill-loader/merger/builtin-skill-converter.ts
|
|
110665
110677
|
function builtinToLoadedSkill(builtin) {
|
|
110666
110678
|
const definition = {
|
|
@@ -110893,11 +110905,33 @@ var playwrightSkill = {
|
|
|
110893
110905
|
description: "MUST USE for any browser-related tasks. Browser automation via Playwright MCP - verification, browsing, information gathering, web scraping, testing, screenshots, and all browser interactions.",
|
|
110894
110906
|
template: `# Playwright Browser Automation
|
|
110895
110907
|
|
|
110896
|
-
This skill provides browser automation capabilities via the Playwright MCP server
|
|
110908
|
+
This skill provides browser automation capabilities via the Playwright MCP server.
|
|
110909
|
+
|
|
110910
|
+
## Required workflow
|
|
110911
|
+
|
|
110912
|
+
1. Load this skill before calling \`skill_mcp\`.
|
|
110913
|
+
2. Use \`skill_mcp\` with \`mcp_name="playwright"\` for browser navigation, interaction, screenshots, and visual verification.
|
|
110914
|
+
3. If the host says \`MCP server "playwright" not found\`, do not conclude that Playwright is impossible. First report that the skill was not loaded or the Playwright MCP server was not registered in this session.
|
|
110915
|
+
4. If Chromium starts but fails with missing Linux libraries such as \`libnspr4\`, \`libnss3\`, \`libatk-bridge\`, \`libgtk-3\`, or similar, distinguish browser OS dependencies from MCP availability.
|
|
110916
|
+
|
|
110917
|
+
## Linux dependency fallback
|
|
110918
|
+
|
|
110919
|
+
Playwright has two dependency layers:
|
|
110920
|
+
|
|
110921
|
+
- Browser binary: installable without sudo with \`npx playwright install chromium\` or by setting \`HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1\` before OpenCode starts.
|
|
110922
|
+
- System libraries: on minimal Linux images these usually require admin rights via \`sudo npx playwright install-deps chromium\` or OS package manager equivalents.
|
|
110923
|
+
|
|
110924
|
+
If sudo is unavailable, try these alternatives before falling back to curl-only checks:
|
|
110925
|
+
|
|
110926
|
+
- Use an already installed Chrome/Chromium/Edge by adding Playwright MCP args in \`hiai-opencode.json\`, for example \`--browser chrome\` or \`--browser msedge\`.
|
|
110927
|
+
- Use a remote/browser service or CDP-backed browser when available.
|
|
110928
|
+
- Switch the browser automation provider to \`agent-browser\` or \`playwright-cli\` if the workspace has those tools installed.
|
|
110929
|
+
|
|
110930
|
+
Only use \`curl\` as a final degraded check. Clearly say that HTTP checks do not replace interactive browser verification.`,
|
|
110897
110931
|
mcpConfig: {
|
|
110898
110932
|
playwright: {
|
|
110899
110933
|
command: "npx",
|
|
110900
|
-
args: ["@playwright/mcp@latest"]
|
|
110934
|
+
args: ["-y", "@playwright/mcp@latest"]
|
|
110901
110935
|
}
|
|
110902
110936
|
}
|
|
110903
110937
|
};
|
|
@@ -113926,6 +113960,8 @@ var AgentOverridesSchema = exports_external.object({
|
|
|
113926
113960
|
general: AgentOverrideConfigSchema.optional(),
|
|
113927
113961
|
zoe: AgentOverrideConfigSchema.optional(),
|
|
113928
113962
|
"pre-plan": AgentOverrideConfigSchema.optional(),
|
|
113963
|
+
manager: AgentOverrideConfigSchema.optional(),
|
|
113964
|
+
vision: AgentOverrideConfigSchema.optional(),
|
|
113929
113965
|
logician: AgentOverrideConfigSchema.optional(),
|
|
113930
113966
|
librarian: AgentOverrideConfigSchema.optional(),
|
|
113931
113967
|
explore: AgentOverrideConfigSchema.optional(),
|
|
@@ -114022,7 +114058,8 @@ var BuiltinCommandNameSchema = exports_external.enum([
|
|
|
114022
114058
|
"refactor",
|
|
114023
114059
|
"start-work",
|
|
114024
114060
|
"stop-continuation",
|
|
114025
|
-
"remove-ai-slops"
|
|
114061
|
+
"remove-ai-slops",
|
|
114062
|
+
"mcp-status"
|
|
114026
114063
|
]);
|
|
114027
114064
|
// src/config/schema/comment-checker.ts
|
|
114028
114065
|
var CommentCheckerConfigSchema = exports_external.object({
|
|
@@ -114077,8 +114114,8 @@ var ExperimentalConfigSchema = exports_external.object({
|
|
|
114077
114114
|
// src/config/schema/fast-apply.ts
|
|
114078
114115
|
var FastApplyConfigSchema = exports_external.object({
|
|
114079
114116
|
enabled: exports_external.boolean().optional().default(false),
|
|
114080
|
-
ollama_url: exports_external.string().optional().default("
|
|
114081
|
-
model: exports_external.string().optional().default("
|
|
114117
|
+
ollama_url: exports_external.string().optional().default(""),
|
|
114118
|
+
model: exports_external.string().optional().default(""),
|
|
114082
114119
|
timeout: exports_external.number().int().positive().optional().default(30000)
|
|
114083
114120
|
});
|
|
114084
114121
|
// src/config/schema/git-env-prefix.ts
|
|
@@ -114235,6 +114272,17 @@ var SkillsConfigSchema = exports_external.union([
|
|
|
114235
114272
|
}).catchall(SkillEntrySchema)
|
|
114236
114273
|
]);
|
|
114237
114274
|
|
|
114275
|
+
// src/config/schema/skill-discovery.ts
|
|
114276
|
+
var SkillDiscoveryConfigSchema = exports_external.object({
|
|
114277
|
+
config_sources: exports_external.boolean().default(true),
|
|
114278
|
+
project_opencode: exports_external.boolean().default(true),
|
|
114279
|
+
global_opencode: exports_external.boolean().default(false),
|
|
114280
|
+
project_claude: exports_external.boolean().default(false),
|
|
114281
|
+
global_claude: exports_external.boolean().default(false),
|
|
114282
|
+
project_agents: exports_external.boolean().default(false),
|
|
114283
|
+
global_agents: exports_external.boolean().default(false)
|
|
114284
|
+
});
|
|
114285
|
+
|
|
114238
114286
|
// src/config/schema/bob.ts
|
|
114239
114287
|
var BobTasksConfigSchema = exports_external.object({
|
|
114240
114288
|
storage_path: exports_external.string().optional(),
|
|
@@ -114293,7 +114341,8 @@ var AuthConfigSchema = exports_external.object({
|
|
|
114293
114341
|
openai: exports_external.string().optional(),
|
|
114294
114342
|
openrouter: exports_external.string().optional(),
|
|
114295
114343
|
stitch: exports_external.string().optional(),
|
|
114296
|
-
firecrawl: exports_external.string().optional()
|
|
114344
|
+
firecrawl: exports_external.string().optional(),
|
|
114345
|
+
context7: exports_external.string().optional()
|
|
114297
114346
|
}).optional();
|
|
114298
114347
|
var HiaiOpenCodeConfigSchema = exports_external.object({
|
|
114299
114348
|
$schema: exports_external.string().optional(),
|
|
@@ -114317,6 +114366,7 @@ var HiaiOpenCodeConfigSchema = exports_external.object({
|
|
|
114317
114366
|
experimental: ExperimentalConfigSchema.optional(),
|
|
114318
114367
|
auto_update: exports_external.boolean().optional(),
|
|
114319
114368
|
skills: SkillsConfigSchema.optional(),
|
|
114369
|
+
skill_discovery: SkillDiscoveryConfigSchema.optional(),
|
|
114320
114370
|
ralph_loop: RalphLoopConfigSchema.optional(),
|
|
114321
114371
|
runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
|
|
114322
114372
|
background_task: BackgroundTaskConfigSchema.optional(),
|
|
@@ -116004,6 +116054,44 @@ If any issues are found during critical review:
|
|
|
116004
116054
|
- ALWAYS preserve test coverage
|
|
116005
116055
|
- If uncertain about a change, err on the side of keeping the original code`;
|
|
116006
116056
|
|
|
116057
|
+
// src/features/builtin-commands/templates/mcp-status.ts
|
|
116058
|
+
var MCP_STATUS_TEMPLATE = `# MCP Status Command
|
|
116059
|
+
|
|
116060
|
+
## Purpose
|
|
116061
|
+
|
|
116062
|
+
Use /mcp-status to show the effective hiai-opencode MCP setup without relying on OpenCode's mcp list output.
|
|
116063
|
+
|
|
116064
|
+
## Execute
|
|
116065
|
+
|
|
116066
|
+
Run:
|
|
116067
|
+
|
|
116068
|
+
\`\`\`bash
|
|
116069
|
+
hiai-opencode mcp-status
|
|
116070
|
+
\`\`\`
|
|
116071
|
+
|
|
116072
|
+
If the binary is not on PATH, try the package-local fallback:
|
|
116073
|
+
|
|
116074
|
+
\`\`\`bash
|
|
116075
|
+
node ./node_modules/@hiai-gg/hiai-opencode/assets/cli/hiai-opencode.mjs mcp-status
|
|
116076
|
+
\`\`\`
|
|
116077
|
+
|
|
116078
|
+
## Report
|
|
116079
|
+
|
|
116080
|
+
Summarize the output in a compact status table:
|
|
116081
|
+
|
|
116082
|
+
- MCP server name
|
|
116083
|
+
- status: ok, warning, error, disabled
|
|
116084
|
+
- cause or next action
|
|
116085
|
+
|
|
116086
|
+
Rules:
|
|
116087
|
+
|
|
116088
|
+
- Do not print API key values.
|
|
116089
|
+
- If a key is missing, name the env var only.
|
|
116090
|
+
- If a runtime is missing, give the exact install hint from the command output or the shortest safe next command.
|
|
116091
|
+
- Do not edit config unless the user explicitly asks.
|
|
116092
|
+
- Do not run package installs unless the user explicitly asks.
|
|
116093
|
+
`;
|
|
116094
|
+
|
|
116007
116095
|
// src/features/builtin-commands/commands.ts
|
|
116008
116096
|
function resolveStartWorkAgent(options) {
|
|
116009
116097
|
if (options?.useRegisteredAgents) {
|
|
@@ -116107,6 +116195,12 @@ Timestamp: $TIMESTAMP
|
|
|
116107
116195
|
$ARGUMENTS
|
|
116108
116196
|
</user-request>`,
|
|
116109
116197
|
argumentHint: "[goal]"
|
|
116198
|
+
},
|
|
116199
|
+
"mcp-status": {
|
|
116200
|
+
description: "(builtin) Show hiai-opencode MCP server status, missing keys, and local runtime availability",
|
|
116201
|
+
template: `<command-instruction>
|
|
116202
|
+
${MCP_STATUS_TEMPLATE}
|
|
116203
|
+
</command-instruction>`
|
|
116110
116204
|
}
|
|
116111
116205
|
};
|
|
116112
116206
|
}
|
|
@@ -120443,7 +120537,7 @@ import * as fs12 from "fs";
|
|
|
120443
120537
|
import * as path6 from "path";
|
|
120444
120538
|
|
|
120445
120539
|
// src/config/loader.ts
|
|
120446
|
-
import { existsSync as
|
|
120540
|
+
import { existsSync as existsSync58, readFileSync as readFileSync43 } from "fs";
|
|
120447
120541
|
import { join as join67 } from "path";
|
|
120448
120542
|
|
|
120449
120543
|
// src/config/platform-schema.ts
|
|
@@ -120451,6 +120545,34 @@ var AgentConfigSchema = exports_external.object({
|
|
|
120451
120545
|
model: exports_external.string(),
|
|
120452
120546
|
description: exports_external.string().optional()
|
|
120453
120547
|
});
|
|
120548
|
+
var ModelRecommendationSchema = exports_external.enum([
|
|
120549
|
+
"xhigh",
|
|
120550
|
+
"high",
|
|
120551
|
+
"middle",
|
|
120552
|
+
"fast",
|
|
120553
|
+
"vision",
|
|
120554
|
+
"writing",
|
|
120555
|
+
"design"
|
|
120556
|
+
]);
|
|
120557
|
+
var ModelSlotConfigSchema = exports_external.union([
|
|
120558
|
+
exports_external.string(),
|
|
120559
|
+
exports_external.object({
|
|
120560
|
+
model: exports_external.string(),
|
|
120561
|
+
recommended: ModelRecommendationSchema.optional()
|
|
120562
|
+
})
|
|
120563
|
+
]);
|
|
120564
|
+
var ModelSlotsConfigSchema = exports_external.object({
|
|
120565
|
+
bob: ModelSlotConfigSchema.optional(),
|
|
120566
|
+
coder: ModelSlotConfigSchema.optional(),
|
|
120567
|
+
strategist: ModelSlotConfigSchema.optional(),
|
|
120568
|
+
guard: ModelSlotConfigSchema.optional(),
|
|
120569
|
+
critic: ModelSlotConfigSchema.optional(),
|
|
120570
|
+
designer: ModelSlotConfigSchema.optional(),
|
|
120571
|
+
researcher: ModelSlotConfigSchema.optional(),
|
|
120572
|
+
manager: ModelSlotConfigSchema.optional(),
|
|
120573
|
+
brainstormer: ModelSlotConfigSchema.optional(),
|
|
120574
|
+
vision: ModelSlotConfigSchema.optional()
|
|
120575
|
+
});
|
|
120454
120576
|
var FallbackEntrySchema = exports_external.object({
|
|
120455
120577
|
providers: exports_external.array(exports_external.string()),
|
|
120456
120578
|
model: exports_external.string(),
|
|
@@ -120487,8 +120609,9 @@ var McpServerConfigSchema = exports_external.object({
|
|
|
120487
120609
|
environment: exports_external.record(exports_external.string(), exports_external.string()).optional()
|
|
120488
120610
|
});
|
|
120489
120611
|
var LspServerConfigSchema = exports_external.object({
|
|
120490
|
-
|
|
120491
|
-
|
|
120612
|
+
enabled: exports_external.boolean().optional(),
|
|
120613
|
+
command: exports_external.array(exports_external.string()).optional(),
|
|
120614
|
+
extensions: exports_external.array(exports_external.string()).optional(),
|
|
120492
120615
|
initialization: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
120493
120616
|
});
|
|
120494
120617
|
var Subtask2ConfigSchema = exports_external.object({
|
|
@@ -120499,6 +120622,15 @@ var SkillsConfigSchema2 = exports_external.object({
|
|
|
120499
120622
|
enabled: exports_external.boolean().optional(),
|
|
120500
120623
|
disabled: exports_external.array(exports_external.string()).optional()
|
|
120501
120624
|
});
|
|
120625
|
+
var SkillDiscoveryConfigSchema2 = exports_external.object({
|
|
120626
|
+
config_sources: exports_external.boolean().optional(),
|
|
120627
|
+
project_opencode: exports_external.boolean().optional(),
|
|
120628
|
+
global_opencode: exports_external.boolean().optional(),
|
|
120629
|
+
project_claude: exports_external.boolean().optional(),
|
|
120630
|
+
global_claude: exports_external.boolean().optional(),
|
|
120631
|
+
project_agents: exports_external.boolean().optional(),
|
|
120632
|
+
global_agents: exports_external.boolean().optional()
|
|
120633
|
+
});
|
|
120502
120634
|
var PermissionsConfigSchema = exports_external.object({
|
|
120503
120635
|
read: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
120504
120636
|
edit: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
@@ -120526,12 +120658,13 @@ var AuthKeysSchema = exports_external.object({
|
|
|
120526
120658
|
openai: exports_external.string().optional(),
|
|
120527
120659
|
openrouter: exports_external.string().optional(),
|
|
120528
120660
|
stitch: exports_external.string().optional(),
|
|
120529
|
-
firecrawl: exports_external.string().optional()
|
|
120661
|
+
firecrawl: exports_external.string().optional(),
|
|
120662
|
+
context7: exports_external.string().optional()
|
|
120530
120663
|
});
|
|
120531
120664
|
var OllamaConfigSchema = exports_external.object({
|
|
120532
120665
|
enabled: exports_external.boolean().default(false),
|
|
120533
|
-
model: exports_external.string().default("
|
|
120534
|
-
baseUrl: exports_external.string().default("
|
|
120666
|
+
model: exports_external.string().default(""),
|
|
120667
|
+
baseUrl: exports_external.string().default(""),
|
|
120535
120668
|
purpose: exports_external.enum(["verification", "helper", "fallback"]).default("helper")
|
|
120536
120669
|
});
|
|
120537
120670
|
var ModelFamilySchema = exports_external.object({
|
|
@@ -120560,6 +120693,8 @@ var AgentsConfigSchema = exports_external.object({
|
|
|
120560
120693
|
zoe: AgentConfigSchema.optional(),
|
|
120561
120694
|
build: AgentConfigSchema.optional(),
|
|
120562
120695
|
"pre-plan": AgentConfigSchema.optional(),
|
|
120696
|
+
manager: AgentConfigSchema.optional(),
|
|
120697
|
+
vision: AgentConfigSchema.optional(),
|
|
120563
120698
|
logician: AgentConfigSchema.optional(),
|
|
120564
120699
|
librarian: AgentConfigSchema.optional(),
|
|
120565
120700
|
explore: AgentConfigSchema.optional(),
|
|
@@ -120589,6 +120724,8 @@ var AgentRequirementsConfigSchema = exports_external.object({
|
|
|
120589
120724
|
zoe: ModelRequirementSchema.optional(),
|
|
120590
120725
|
build: ModelRequirementSchema.optional(),
|
|
120591
120726
|
"pre-plan": ModelRequirementSchema.optional(),
|
|
120727
|
+
manager: ModelRequirementSchema.optional(),
|
|
120728
|
+
vision: ModelRequirementSchema.optional(),
|
|
120592
120729
|
logician: ModelRequirementSchema.optional(),
|
|
120593
120730
|
librarian: ModelRequirementSchema.optional(),
|
|
120594
120731
|
explore: ModelRequirementSchema.optional(),
|
|
@@ -120602,6 +120739,7 @@ var AgentRequirementsConfigSchema = exports_external.object({
|
|
|
120602
120739
|
}).catchall(ModelRequirementSchema);
|
|
120603
120740
|
var HiaiOpencodeConfigSchema = exports_external.object({
|
|
120604
120741
|
$schema: exports_external.string().optional(),
|
|
120742
|
+
models: ModelSlotsConfigSchema.optional(),
|
|
120605
120743
|
agents: AgentsConfigSchema.optional(),
|
|
120606
120744
|
agentRequirements: AgentRequirementsConfigSchema.optional(),
|
|
120607
120745
|
categories: exports_external.record(exports_external.string(), CategoryConfigSchema2).optional(),
|
|
@@ -120611,28 +120749,25 @@ var HiaiOpencodeConfigSchema = exports_external.object({
|
|
|
120611
120749
|
lsp: exports_external.record(exports_external.string(), LspServerConfigSchema).optional(),
|
|
120612
120750
|
subtask2: Subtask2ConfigSchema.optional(),
|
|
120613
120751
|
skills: SkillsConfigSchema2.optional(),
|
|
120752
|
+
skill_discovery: SkillDiscoveryConfigSchema2.optional(),
|
|
120614
120753
|
permissions: PermissionsConfigSchema.optional(),
|
|
120615
120754
|
auth: AuthKeysSchema.optional(),
|
|
120616
120755
|
ollama: OllamaConfigSchema.optional()
|
|
120617
120756
|
});
|
|
120618
120757
|
|
|
120619
|
-
// src/config/
|
|
120620
|
-
|
|
120621
|
-
|
|
120622
|
-
mid: "openrouter/anthropic/claude-3.5-sonnet",
|
|
120623
|
-
high: "openrouter/anthropic/claude-3.5-opus",
|
|
120624
|
-
ultrahigh: "openrouter/openai/gpt-4o",
|
|
120625
|
-
vision: "openrouter/google/gemini-2.0-pro-exp-02-05",
|
|
120626
|
-
reasoning: "openrouter/openai/o1",
|
|
120627
|
-
strategist: "openrouter/z-ai/glm-5.1",
|
|
120628
|
-
critic: "openrouter/qwen/qwen2.5-72b-instruct",
|
|
120629
|
-
writing: "openrouter/kimi/kimi-latest"
|
|
120630
|
-
};
|
|
120758
|
+
// src/config/defaults.ts
|
|
120759
|
+
import { existsSync as existsSync57, readFileSync as readFileSync42 } from "fs";
|
|
120760
|
+
import { dirname as dirname18, join as join66, normalize as normalize2 } from "path";
|
|
120631
120761
|
|
|
120632
120762
|
// src/mcp/registry.ts
|
|
120633
120763
|
import { join as join65 } from "path";
|
|
120764
|
+
import { existsSync as existsSync56 } from "fs";
|
|
120634
120765
|
function resolveAssetScript(...segments) {
|
|
120635
|
-
|
|
120766
|
+
const candidates = [
|
|
120767
|
+
join65(import.meta.dirname, "..", "assets", ...segments),
|
|
120768
|
+
join65(import.meta.dirname, "..", "..", "assets", ...segments)
|
|
120769
|
+
];
|
|
120770
|
+
return candidates.find((candidate) => existsSync56(candidate)) ?? candidates[0];
|
|
120636
120771
|
}
|
|
120637
120772
|
function createNpmPackageCommand(pkg, ...args) {
|
|
120638
120773
|
return ["node", resolveAssetScript("runtime", "npm-package-runner.mjs"), pkg, ...args];
|
|
@@ -120733,83 +120868,170 @@ function createDefaultMcpConfig() {
|
|
|
120733
120868
|
}
|
|
120734
120869
|
|
|
120735
120870
|
// src/config/defaults.ts
|
|
120736
|
-
|
|
120737
|
-
|
|
120738
|
-
|
|
120739
|
-
|
|
120740
|
-
|
|
120741
|
-
|
|
120742
|
-
|
|
120743
|
-
|
|
120744
|
-
|
|
120745
|
-
|
|
120746
|
-
|
|
120747
|
-
|
|
120748
|
-
|
|
120749
|
-
|
|
120750
|
-
|
|
120751
|
-
"
|
|
120752
|
-
"
|
|
120753
|
-
brainstormer: { model: MODEL_PRESETS.fast },
|
|
120754
|
-
"agent-skills": { model: MODEL_PRESETS.fast }
|
|
120755
|
-
},
|
|
120756
|
-
agentRequirements: {},
|
|
120757
|
-
categories: {
|
|
120758
|
-
"visual-engineering": { model: MODEL_PRESETS.vision, variant: "high" },
|
|
120759
|
-
artistry: { model: MODEL_PRESETS.vision, variant: "high" },
|
|
120760
|
-
ultrabrain: { model: MODEL_PRESETS.ultrahigh, variant: "xhigh" },
|
|
120761
|
-
deep: { model: MODEL_PRESETS.reasoning, variant: "medium" },
|
|
120762
|
-
quick: { model: MODEL_PRESETS.fast },
|
|
120763
|
-
writing: { model: MODEL_PRESETS.writing },
|
|
120764
|
-
git: { model: MODEL_PRESETS.fast },
|
|
120765
|
-
"unspecified-low": { model: MODEL_PRESETS.mid },
|
|
120766
|
-
"unspecified-high": { model: MODEL_PRESETS.high, variant: "max" }
|
|
120767
|
-
},
|
|
120768
|
-
categoryRequirements: {},
|
|
120769
|
-
mcp: createDefaultMcpConfig(),
|
|
120770
|
-
lsp: {
|
|
120771
|
-
typescript: {
|
|
120772
|
-
command: ["typescript-language-server", "--stdio"],
|
|
120773
|
-
extensions: [".ts", ".tsx", ".mts", ".cts"]
|
|
120774
|
-
},
|
|
120775
|
-
svelte: {
|
|
120776
|
-
command: ["svelteserver", "--stdio"],
|
|
120777
|
-
extensions: [".svelte"]
|
|
120778
|
-
},
|
|
120779
|
-
eslint: {
|
|
120780
|
-
command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "eslint-lsp", "--stdio"],
|
|
120781
|
-
extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
|
|
120782
|
-
},
|
|
120783
|
-
bash: {
|
|
120784
|
-
command: ["node", join66(import.meta.dirname, "..", "assets", "runtime", "npm-package-runner.mjs"), "bash-language-server", "start"],
|
|
120785
|
-
extensions: [".sh", ".bash"]
|
|
120786
|
-
},
|
|
120787
|
-
pyright: {
|
|
120788
|
-
command: ["pyright-langserver", "--stdio"],
|
|
120789
|
-
extensions: [".py"]
|
|
120790
|
-
}
|
|
120871
|
+
var REQUIRED_MODEL_SLOTS = [
|
|
120872
|
+
"bob",
|
|
120873
|
+
"coder",
|
|
120874
|
+
"strategist",
|
|
120875
|
+
"guard",
|
|
120876
|
+
"critic",
|
|
120877
|
+
"designer",
|
|
120878
|
+
"researcher",
|
|
120879
|
+
"manager",
|
|
120880
|
+
"brainstormer",
|
|
120881
|
+
"vision"
|
|
120882
|
+
];
|
|
120883
|
+
var DEFAULT_LSP = {
|
|
120884
|
+
typescript: {
|
|
120885
|
+
enabled: true,
|
|
120886
|
+
command: ["typescript-language-server", "--stdio"],
|
|
120887
|
+
extensions: [".ts", ".tsx", ".mts", ".cts"]
|
|
120791
120888
|
},
|
|
120792
|
-
|
|
120793
|
-
|
|
120794
|
-
|
|
120889
|
+
svelte: {
|
|
120890
|
+
enabled: true,
|
|
120891
|
+
command: ["svelteserver", "--stdio"],
|
|
120892
|
+
extensions: [".svelte"]
|
|
120795
120893
|
},
|
|
120796
|
-
|
|
120894
|
+
eslint: {
|
|
120797
120895
|
enabled: true,
|
|
120798
|
-
|
|
120896
|
+
command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "eslint-lsp", "--stdio"],
|
|
120897
|
+
extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".svelte"]
|
|
120799
120898
|
},
|
|
120800
|
-
|
|
120801
|
-
|
|
120802
|
-
|
|
120803
|
-
|
|
120804
|
-
deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"]
|
|
120899
|
+
bash: {
|
|
120900
|
+
enabled: true,
|
|
120901
|
+
command: ["node", "{pluginRoot}/assets/runtime/npm-package-runner.mjs", "bash-language-server", "start"],
|
|
120902
|
+
extensions: [".sh", ".bash"]
|
|
120805
120903
|
},
|
|
120806
|
-
|
|
120807
|
-
enabled:
|
|
120808
|
-
|
|
120809
|
-
|
|
120810
|
-
purpose: "helper"
|
|
120904
|
+
pyright: {
|
|
120905
|
+
enabled: true,
|
|
120906
|
+
command: ["pyright-langserver", "--stdio"],
|
|
120907
|
+
extensions: [".py"]
|
|
120811
120908
|
}
|
|
120812
120909
|
};
|
|
120910
|
+
function findPluginRoot() {
|
|
120911
|
+
const candidates = [
|
|
120912
|
+
join66(import.meta.dirname, "..", ".."),
|
|
120913
|
+
join66(import.meta.dirname, ".."),
|
|
120914
|
+
join66(import.meta.dirname, "..", ".."),
|
|
120915
|
+
dirname18(process.argv[1] ?? ""),
|
|
120916
|
+
process.cwd()
|
|
120917
|
+
];
|
|
120918
|
+
for (const candidate of candidates) {
|
|
120919
|
+
const root = normalize2(candidate);
|
|
120920
|
+
if (existsSync57(join66(root, "hiai-opencode.json")))
|
|
120921
|
+
return root;
|
|
120922
|
+
}
|
|
120923
|
+
throw new Error("[hiai-opencode] Cannot find bundled hiai-opencode.json. The package is incomplete.");
|
|
120924
|
+
}
|
|
120925
|
+
function expandPluginRootPlaceholders(value, pluginRoot) {
|
|
120926
|
+
if (typeof value === "string")
|
|
120927
|
+
return value.replaceAll("{pluginRoot}", pluginRoot);
|
|
120928
|
+
if (Array.isArray(value))
|
|
120929
|
+
return value.map((item) => expandPluginRootPlaceholders(item, pluginRoot));
|
|
120930
|
+
if (value && typeof value === "object") {
|
|
120931
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, expandPluginRootPlaceholders(entry, pluginRoot)]));
|
|
120932
|
+
}
|
|
120933
|
+
return value;
|
|
120934
|
+
}
|
|
120935
|
+
function requireModelSlots(config2) {
|
|
120936
|
+
const models = config2.models ?? {};
|
|
120937
|
+
const resolved = Object.fromEntries(REQUIRED_MODEL_SLOTS.map((slot) => {
|
|
120938
|
+
const value = models[slot];
|
|
120939
|
+
const model = typeof value === "string" ? value : value?.model;
|
|
120940
|
+
return [slot, model?.trim() ?? ""];
|
|
120941
|
+
}));
|
|
120942
|
+
const missing = REQUIRED_MODEL_SLOTS.filter((slot) => !resolved[slot]);
|
|
120943
|
+
if (missing.length > 0) {
|
|
120944
|
+
throw new Error(`[hiai-opencode] Missing required model slot(s) in hiai-opencode.json: ${missing.join(", ")}`);
|
|
120945
|
+
}
|
|
120946
|
+
return resolved;
|
|
120947
|
+
}
|
|
120948
|
+
function deriveAgents(models) {
|
|
120949
|
+
return {
|
|
120950
|
+
bob: { model: models.bob },
|
|
120951
|
+
coder: { model: models.coder },
|
|
120952
|
+
strategist: { model: models.strategist },
|
|
120953
|
+
guard: { model: models.guard },
|
|
120954
|
+
critic: { model: models.critic },
|
|
120955
|
+
designer: { model: models.designer },
|
|
120956
|
+
researcher: { model: models.researcher },
|
|
120957
|
+
"platform-manager": { model: models.manager },
|
|
120958
|
+
brainstormer: { model: models.brainstormer },
|
|
120959
|
+
multimodal: { model: models.vision },
|
|
120960
|
+
sub: { model: models.coder },
|
|
120961
|
+
"quality-guardian": { model: models.critic },
|
|
120962
|
+
"agent-skills": { model: models.manager }
|
|
120963
|
+
};
|
|
120964
|
+
}
|
|
120965
|
+
function deriveCategories(models) {
|
|
120966
|
+
return {
|
|
120967
|
+
"visual-engineering": { model: models.designer, variant: "high" },
|
|
120968
|
+
artistry: { model: models.designer, variant: "high" },
|
|
120969
|
+
ultrabrain: { model: models.strategist, variant: "xhigh" },
|
|
120970
|
+
deep: { model: models.coder, variant: "medium" },
|
|
120971
|
+
quick: { model: models.researcher },
|
|
120972
|
+
writing: { model: models.brainstormer },
|
|
120973
|
+
git: { model: models.manager },
|
|
120974
|
+
"unspecified-low": { model: models.coder },
|
|
120975
|
+
"unspecified-high": { model: models.bob, variant: "max" }
|
|
120976
|
+
};
|
|
120977
|
+
}
|
|
120978
|
+
function deriveMcp(config2) {
|
|
120979
|
+
const defaults = createDefaultMcpConfig();
|
|
120980
|
+
const userMcp = config2.mcp ?? {};
|
|
120981
|
+
return Object.fromEntries(Object.entries(defaults).map(([name, entry]) => {
|
|
120982
|
+
const override = userMcp[name] ?? {};
|
|
120983
|
+
return [name, { ...entry, ...override }];
|
|
120984
|
+
}));
|
|
120985
|
+
}
|
|
120986
|
+
function deriveLsp(config2) {
|
|
120987
|
+
const userLsp = config2.lsp ?? {};
|
|
120988
|
+
return Object.fromEntries(Object.entries(DEFAULT_LSP).map(([name, entry]) => {
|
|
120989
|
+
const override = userLsp[name] ?? {};
|
|
120990
|
+
return [name, { ...entry, ...override }];
|
|
120991
|
+
}));
|
|
120992
|
+
}
|
|
120993
|
+
function materializeConfig(rawConfig) {
|
|
120994
|
+
const models = requireModelSlots(rawConfig);
|
|
120995
|
+
return {
|
|
120996
|
+
...rawConfig,
|
|
120997
|
+
agents: deriveAgents(models),
|
|
120998
|
+
agentRequirements: {},
|
|
120999
|
+
categories: deriveCategories(models),
|
|
121000
|
+
categoryRequirements: {},
|
|
121001
|
+
modelFamilies: [],
|
|
121002
|
+
mcp: deriveMcp(rawConfig),
|
|
121003
|
+
lsp: deriveLsp(rawConfig),
|
|
121004
|
+
subtask2: {
|
|
121005
|
+
replace_generic: true,
|
|
121006
|
+
generic_return: null,
|
|
121007
|
+
...rawConfig.subtask2 ?? {}
|
|
121008
|
+
},
|
|
121009
|
+
skills: {
|
|
121010
|
+
enabled: true,
|
|
121011
|
+
disabled: [],
|
|
121012
|
+
...rawConfig.skills ?? {}
|
|
121013
|
+
},
|
|
121014
|
+
permissions: {
|
|
121015
|
+
read: { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" },
|
|
121016
|
+
edit: { "*": "allow" },
|
|
121017
|
+
bash: { "*": "allow" },
|
|
121018
|
+
deny_paths: ["**/backup/**", "**/secrets.*", "**/.env", "**/.env.*"],
|
|
121019
|
+
...rawConfig.permissions ?? {}
|
|
121020
|
+
}
|
|
121021
|
+
};
|
|
121022
|
+
}
|
|
121023
|
+
function loadBundledDefaultConfig() {
|
|
121024
|
+
const pluginRoot = findPluginRoot();
|
|
121025
|
+
const configPath = join66(pluginRoot, "hiai-opencode.json");
|
|
121026
|
+
const raw = readFileSync42(configPath, "utf-8");
|
|
121027
|
+
const parsed = JSON.parse(raw);
|
|
121028
|
+
const materialized = materializeConfig(parsed);
|
|
121029
|
+
return expandPluginRootPlaceholders(materialized, pluginRoot);
|
|
121030
|
+
}
|
|
121031
|
+
function applyModelSlots(config2) {
|
|
121032
|
+
return materializeConfig(config2);
|
|
121033
|
+
}
|
|
121034
|
+
var defaultConfig = loadBundledDefaultConfig();
|
|
120813
121035
|
|
|
120814
121036
|
// src/config/types.ts
|
|
120815
121037
|
var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
|
|
@@ -120817,6 +121039,8 @@ var LEGACY_AGENT_ALIAS_TO_CANONICAL2 = {
|
|
|
120817
121039
|
zoe: "bob",
|
|
120818
121040
|
build: "bob",
|
|
120819
121041
|
"pre-plan": "strategist",
|
|
121042
|
+
manager: "platform-manager",
|
|
121043
|
+
vision: "multimodal",
|
|
120820
121044
|
logician: "strategist",
|
|
120821
121045
|
librarian: "researcher",
|
|
120822
121046
|
explore: "researcher",
|
|
@@ -120855,7 +121079,7 @@ function findConfigFile(searchDirs) {
|
|
|
120855
121079
|
for (const dir of searchDirs) {
|
|
120856
121080
|
for (const filename of CONFIG_FILENAMES) {
|
|
120857
121081
|
const candidate = join67(dir, filename);
|
|
120858
|
-
if (
|
|
121082
|
+
if (existsSync58(candidate))
|
|
120859
121083
|
return candidate;
|
|
120860
121084
|
}
|
|
120861
121085
|
}
|
|
@@ -120933,12 +121157,13 @@ function loadConfig(projectDir) {
|
|
|
120933
121157
|
const configPath = findConfigFile(searchDirs);
|
|
120934
121158
|
if (!configPath)
|
|
120935
121159
|
return BASE_CONFIG;
|
|
120936
|
-
const raw =
|
|
121160
|
+
const raw = readFileSync43(configPath, "utf-8");
|
|
120937
121161
|
const parsed = parse2(raw);
|
|
120938
121162
|
const normalizedParsed = normalizeCompactLspConfig(parsed);
|
|
120939
121163
|
const validated = HiaiOpencodeConfigSchema.parse(normalizedParsed);
|
|
120940
121164
|
const normalized = normalizeAgentAliases(validated);
|
|
120941
|
-
|
|
121165
|
+
const merged = deepMerge2(BASE_CONFIG, normalized);
|
|
121166
|
+
return applyModelSlots(merged);
|
|
120942
121167
|
}
|
|
120943
121168
|
function resolveEnvVars(value) {
|
|
120944
121169
|
return value.replace(/\{env:([^}]+)\}/g, (_, expression) => {
|
|
@@ -120949,10 +121174,10 @@ function resolveEnvVars(value) {
|
|
|
120949
121174
|
// src/shared/migrate-legacy-config-file.ts
|
|
120950
121175
|
init_logger();
|
|
120951
121176
|
init_plugin_identity();
|
|
120952
|
-
import { existsSync as
|
|
120953
|
-
import { join as join68, dirname as
|
|
121177
|
+
import { existsSync as existsSync59, readFileSync as readFileSync44, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
|
|
121178
|
+
import { join as join68, dirname as dirname19, basename as basename9 } from "path";
|
|
120954
121179
|
function buildCanonicalPath(legacyPath) {
|
|
120955
|
-
const dir =
|
|
121180
|
+
const dir = dirname19(legacyPath);
|
|
120956
121181
|
const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
|
|
120957
121182
|
return join68(dir, `${CONFIG_BASENAME}${ext}`);
|
|
120958
121183
|
}
|
|
@@ -120986,15 +121211,15 @@ function archiveLegacyConfigFile(legacyPath) {
|
|
|
120986
121211
|
}
|
|
120987
121212
|
}
|
|
120988
121213
|
function migrateLegacyConfigFile(legacyPath) {
|
|
120989
|
-
if (!
|
|
121214
|
+
if (!existsSync59(legacyPath))
|
|
120990
121215
|
return false;
|
|
120991
121216
|
if (!basename9(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
|
|
120992
121217
|
return false;
|
|
120993
121218
|
const canonicalPath = buildCanonicalPath(legacyPath);
|
|
120994
|
-
if (
|
|
121219
|
+
if (existsSync59(canonicalPath))
|
|
120995
121220
|
return false;
|
|
120996
121221
|
try {
|
|
120997
|
-
const content =
|
|
121222
|
+
const content = readFileSync44(legacyPath, "utf-8");
|
|
120998
121223
|
writeFileAtomically(canonicalPath, content);
|
|
120999
121224
|
const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
|
|
121000
121225
|
log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
|
|
@@ -122514,11 +122739,11 @@ function createRuntimeFallbackHook(ctx, options) {
|
|
|
122514
122739
|
};
|
|
122515
122740
|
}
|
|
122516
122741
|
// src/hooks/write-existing-file-guard/hook.ts
|
|
122517
|
-
import { existsSync as
|
|
122518
|
-
import { basename as basename11, dirname as
|
|
122742
|
+
import { existsSync as existsSync62, realpathSync as realpathSync6 } from "fs";
|
|
122743
|
+
import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute11, join as join70, normalize as normalize3, relative as relative8, resolve as resolve14 } from "path";
|
|
122519
122744
|
|
|
122520
122745
|
// src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
|
|
122521
|
-
import { existsSync as
|
|
122746
|
+
import { existsSync as existsSync61 } from "fs";
|
|
122522
122747
|
|
|
122523
122748
|
// src/hooks/write-existing-file-guard/session-read-permissions.ts
|
|
122524
122749
|
function touchSession(sessionLastAccess, sessionID) {
|
|
@@ -122606,7 +122831,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
122606
122831
|
return;
|
|
122607
122832
|
}
|
|
122608
122833
|
if (toolName === "read") {
|
|
122609
|
-
if (!
|
|
122834
|
+
if (!existsSync61(resolvedPath) || !input.sessionID) {
|
|
122610
122835
|
return;
|
|
122611
122836
|
}
|
|
122612
122837
|
registerReadPermission({
|
|
@@ -122622,7 +122847,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
122622
122847
|
if (argsRecord && "overwrite" in argsRecord) {
|
|
122623
122848
|
delete argsRecord.overwrite;
|
|
122624
122849
|
}
|
|
122625
|
-
if (!
|
|
122850
|
+
if (!existsSync61(resolvedPath)) {
|
|
122626
122851
|
return;
|
|
122627
122852
|
}
|
|
122628
122853
|
const isBobPath2 = canonicalPath.includes("/.bob/");
|
|
@@ -122673,7 +122898,7 @@ function getPathFromArgs(args) {
|
|
|
122673
122898
|
return args?.filePath ?? args?.path ?? args?.file_path;
|
|
122674
122899
|
}
|
|
122675
122900
|
function resolveInputPath(ctx, inputPath) {
|
|
122676
|
-
return
|
|
122901
|
+
return normalize3(isAbsolute11(inputPath) ? inputPath : resolve14(ctx.directory, inputPath));
|
|
122677
122902
|
}
|
|
122678
122903
|
function isPathInsideDirectory(pathToCheck, directory) {
|
|
122679
122904
|
const relativePath = relative8(directory, pathToCheck);
|
|
@@ -122681,18 +122906,18 @@ function isPathInsideDirectory(pathToCheck, directory) {
|
|
|
122681
122906
|
}
|
|
122682
122907
|
function toCanonicalPath2(absolutePath) {
|
|
122683
122908
|
let canonicalPath = absolutePath;
|
|
122684
|
-
if (
|
|
122909
|
+
if (existsSync62(absolutePath)) {
|
|
122685
122910
|
try {
|
|
122686
122911
|
canonicalPath = realpathSync6.native(absolutePath);
|
|
122687
122912
|
} catch {
|
|
122688
122913
|
canonicalPath = absolutePath;
|
|
122689
122914
|
}
|
|
122690
122915
|
} else {
|
|
122691
|
-
const absoluteDir =
|
|
122692
|
-
const resolvedDir =
|
|
122916
|
+
const absoluteDir = dirname21(absolutePath);
|
|
122917
|
+
const resolvedDir = existsSync62(absoluteDir) ? realpathSync6.native(absoluteDir) : absoluteDir;
|
|
122693
122918
|
canonicalPath = join70(resolvedDir, basename11(absolutePath));
|
|
122694
122919
|
}
|
|
122695
|
-
return
|
|
122920
|
+
return normalize3(canonicalPath);
|
|
122696
122921
|
}
|
|
122697
122922
|
function isOverwriteEnabled(value) {
|
|
122698
122923
|
if (value === true) {
|
|
@@ -123966,23 +124191,23 @@ init_logger();
|
|
|
123966
124191
|
init_plugin_identity();
|
|
123967
124192
|
|
|
123968
124193
|
// src/hooks/legacy-plugin-toast/auto-migrate.ts
|
|
123969
|
-
import { existsSync as
|
|
124194
|
+
import { existsSync as existsSync63, readFileSync as readFileSync46 } from "fs";
|
|
123970
124195
|
import { join as join71 } from "path";
|
|
123971
124196
|
init_plugin_identity();
|
|
123972
124197
|
function detectOpenCodeConfigPath(overrideConfigDir) {
|
|
123973
124198
|
if (overrideConfigDir) {
|
|
123974
124199
|
const jsoncPath = join71(overrideConfigDir, "opencode.jsonc");
|
|
123975
124200
|
const jsonPath = join71(overrideConfigDir, "opencode.json");
|
|
123976
|
-
if (
|
|
124201
|
+
if (existsSync63(jsoncPath))
|
|
123977
124202
|
return jsoncPath;
|
|
123978
|
-
if (
|
|
124203
|
+
if (existsSync63(jsonPath))
|
|
123979
124204
|
return jsonPath;
|
|
123980
124205
|
return null;
|
|
123981
124206
|
}
|
|
123982
124207
|
const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
123983
|
-
if (
|
|
124208
|
+
if (existsSync63(paths.configJsonc))
|
|
123984
124209
|
return paths.configJsonc;
|
|
123985
|
-
if (
|
|
124210
|
+
if (existsSync63(paths.configJson))
|
|
123986
124211
|
return paths.configJson;
|
|
123987
124212
|
return null;
|
|
123988
124213
|
}
|
|
@@ -123991,7 +124216,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
|
|
|
123991
124216
|
if (!configPath)
|
|
123992
124217
|
return { migrated: false, from: null, to: null, configPath: null };
|
|
123993
124218
|
try {
|
|
123994
|
-
const content =
|
|
124219
|
+
const content = readFileSync46(configPath, "utf-8");
|
|
123995
124220
|
const parseResult = parseJsoncSafe(content);
|
|
123996
124221
|
if (!parseResult.data?.plugin)
|
|
123997
124222
|
return { migrated: false, from: null, to: null, configPath };
|
|
@@ -124109,7 +124334,7 @@ async function queryOllama(args) {
|
|
|
124109
124334
|
}
|
|
124110
124335
|
|
|
124111
124336
|
// src/hooks/fast-apply/tool-execute-before-handler.ts
|
|
124112
|
-
import { existsSync as
|
|
124337
|
+
import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
|
|
124113
124338
|
async function handleFastApplyToolExecuteBefore(args) {
|
|
124114
124339
|
const { input, output, config: config2 } = args;
|
|
124115
124340
|
const normalizedTool = input.tool.toLowerCase();
|
|
@@ -124128,7 +124353,7 @@ async function handleFastApplyToolExecuteBefore(args) {
|
|
|
124128
124353
|
});
|
|
124129
124354
|
return;
|
|
124130
124355
|
}
|
|
124131
|
-
if (!
|
|
124356
|
+
if (!existsSync64(filePath)) {
|
|
124132
124357
|
log("[fast-apply] Skipping: file does not exist (new file)", {
|
|
124133
124358
|
sessionID: input.sessionID,
|
|
124134
124359
|
callID: input.callID,
|
|
@@ -124138,7 +124363,7 @@ async function handleFastApplyToolExecuteBefore(args) {
|
|
|
124138
124363
|
}
|
|
124139
124364
|
let originalContent;
|
|
124140
124365
|
try {
|
|
124141
|
-
originalContent =
|
|
124366
|
+
originalContent = readFileSync47(filePath, "utf-8");
|
|
124142
124367
|
} catch (err) {
|
|
124143
124368
|
log("[fast-apply] Failed to read file, falling back to default", {
|
|
124144
124369
|
sessionID: input.sessionID,
|
|
@@ -124517,13 +124742,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
|
|
|
124517
124742
|
var DEFAULT_MAX_DIAGNOSTICS = 200;
|
|
124518
124743
|
var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
124519
124744
|
// src/tools/lsp/server-config-loader.ts
|
|
124520
|
-
import { existsSync as
|
|
124745
|
+
import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
|
|
124521
124746
|
import { join as join72 } from "path";
|
|
124522
124747
|
function loadJsonFile(path7) {
|
|
124523
|
-
if (!
|
|
124748
|
+
if (!existsSync65(path7))
|
|
124524
124749
|
return null;
|
|
124525
124750
|
try {
|
|
124526
|
-
return parseJsonc(
|
|
124751
|
+
return parseJsonc(readFileSync48(path7, "utf-8"));
|
|
124527
124752
|
} catch {
|
|
124528
124753
|
return null;
|
|
124529
124754
|
}
|
|
@@ -124603,7 +124828,7 @@ function getMergedServers() {
|
|
|
124603
124828
|
}
|
|
124604
124829
|
|
|
124605
124830
|
// src/tools/lsp/server-installation.ts
|
|
124606
|
-
import { existsSync as
|
|
124831
|
+
import { existsSync as existsSync66 } from "fs";
|
|
124607
124832
|
import { delimiter, join as join74 } from "path";
|
|
124608
124833
|
|
|
124609
124834
|
// src/tools/lsp/server-path-bases.ts
|
|
@@ -124626,7 +124851,7 @@ function isServerInstalled(command) {
|
|
|
124626
124851
|
return false;
|
|
124627
124852
|
const cmd = command[0];
|
|
124628
124853
|
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
124629
|
-
if (
|
|
124854
|
+
if (existsSync66(cmd))
|
|
124630
124855
|
return true;
|
|
124631
124856
|
}
|
|
124632
124857
|
const isWindows2 = process.platform === "win32";
|
|
@@ -124647,14 +124872,14 @@ function isServerInstalled(command) {
|
|
|
124647
124872
|
const paths = pathEnv.split(delimiter);
|
|
124648
124873
|
for (const p of paths) {
|
|
124649
124874
|
for (const suffix of exts) {
|
|
124650
|
-
if (
|
|
124875
|
+
if (existsSync66(join74(p, cmd + suffix))) {
|
|
124651
124876
|
return true;
|
|
124652
124877
|
}
|
|
124653
124878
|
}
|
|
124654
124879
|
}
|
|
124655
124880
|
for (const base of getLspServerAdditionalPathBases(process.cwd())) {
|
|
124656
124881
|
for (const suffix of exts) {
|
|
124657
|
-
if (
|
|
124882
|
+
if (existsSync66(join74(base, cmd + suffix))) {
|
|
124658
124883
|
return true;
|
|
124659
124884
|
}
|
|
124660
124885
|
}
|
|
@@ -124712,13 +124937,13 @@ function getLanguageId(ext) {
|
|
|
124712
124937
|
init_logger();
|
|
124713
124938
|
var {spawn: bunSpawn2 } = globalThis.Bun;
|
|
124714
124939
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
124715
|
-
import { existsSync as
|
|
124940
|
+
import { existsSync as existsSync67, statSync as statSync7 } from "fs";
|
|
124716
124941
|
function shouldUseNodeSpawn() {
|
|
124717
124942
|
return process.platform === "win32";
|
|
124718
124943
|
}
|
|
124719
124944
|
function validateCwd(cwd) {
|
|
124720
124945
|
try {
|
|
124721
|
-
if (!
|
|
124946
|
+
if (!existsSync67(cwd)) {
|
|
124722
124947
|
return { valid: false, error: `Working directory does not exist: ${cwd}` };
|
|
124723
124948
|
}
|
|
124724
124949
|
const stats = statSync7(cwd);
|
|
@@ -124850,7 +125075,7 @@ function spawnProcess(command, options) {
|
|
|
124850
125075
|
return proc;
|
|
124851
125076
|
}
|
|
124852
125077
|
// src/tools/lsp/lsp-client.ts
|
|
124853
|
-
import { readFileSync as
|
|
125078
|
+
import { readFileSync as readFileSync49 } from "fs";
|
|
124854
125079
|
import { extname as extname4, resolve as resolve15 } from "path";
|
|
124855
125080
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
124856
125081
|
|
|
@@ -125122,7 +125347,7 @@ class LSPClient extends LSPClientConnection {
|
|
|
125122
125347
|
async openFile(filePath) {
|
|
125123
125348
|
const absPath = resolve15(filePath);
|
|
125124
125349
|
const uri = pathToFileURL2(absPath).href;
|
|
125125
|
-
const text =
|
|
125350
|
+
const text = readFileSync49(absPath, "utf-8");
|
|
125126
125351
|
if (!this.openedFiles.has(absPath)) {
|
|
125127
125352
|
const ext = extname4(absPath);
|
|
125128
125353
|
const languageId = getLanguageId(ext);
|
|
@@ -125480,10 +125705,10 @@ var lspManager = LSPServerManager.getInstance();
|
|
|
125480
125705
|
// src/tools/lsp/lsp-client-wrapper.ts
|
|
125481
125706
|
import { extname as extname5, resolve as resolve16 } from "path";
|
|
125482
125707
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
125483
|
-
import { existsSync as
|
|
125708
|
+
import { existsSync as existsSync68, statSync as statSync8 } from "fs";
|
|
125484
125709
|
init_plugin_identity();
|
|
125485
125710
|
function isDirectoryPath(filePath) {
|
|
125486
|
-
if (!
|
|
125711
|
+
if (!existsSync68(filePath)) {
|
|
125487
125712
|
return false;
|
|
125488
125713
|
}
|
|
125489
125714
|
return statSync8(filePath).isDirectory();
|
|
@@ -125493,14 +125718,14 @@ function uriToPath(uri) {
|
|
|
125493
125718
|
}
|
|
125494
125719
|
function findWorkspaceRoot(filePath) {
|
|
125495
125720
|
let dir = resolve16(filePath);
|
|
125496
|
-
if (!
|
|
125721
|
+
if (!existsSync68(dir) || !isDirectoryPath(dir)) {
|
|
125497
125722
|
dir = __require("path").dirname(dir);
|
|
125498
125723
|
}
|
|
125499
125724
|
const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
125500
125725
|
let prevDir = "";
|
|
125501
125726
|
while (dir !== prevDir) {
|
|
125502
125727
|
for (const marker of markers) {
|
|
125503
|
-
if (
|
|
125728
|
+
if (existsSync68(__require("path").join(dir, marker))) {
|
|
125504
125729
|
return dir;
|
|
125505
125730
|
}
|
|
125506
125731
|
}
|
|
@@ -125675,10 +125900,10 @@ function formatApplyResult(result) {
|
|
|
125675
125900
|
`);
|
|
125676
125901
|
}
|
|
125677
125902
|
// src/tools/lsp/workspace-edit.ts
|
|
125678
|
-
import { readFileSync as
|
|
125903
|
+
import { readFileSync as readFileSync50, writeFileSync as writeFileSync17 } from "fs";
|
|
125679
125904
|
function applyTextEditsToFile(filePath, edits) {
|
|
125680
125905
|
try {
|
|
125681
|
-
let content =
|
|
125906
|
+
let content = readFileSync50(filePath, "utf-8");
|
|
125682
125907
|
const lines = content.split(`
|
|
125683
125908
|
`);
|
|
125684
125909
|
const sortedEdits = [...edits].sort((a, b) => {
|
|
@@ -125744,7 +125969,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
125744
125969
|
try {
|
|
125745
125970
|
const oldPath = uriToPath(change.oldUri);
|
|
125746
125971
|
const newPath = uriToPath(change.newUri);
|
|
125747
|
-
const content =
|
|
125972
|
+
const content = readFileSync50(oldPath, "utf-8");
|
|
125748
125973
|
writeFileSync17(newPath, content, "utf-8");
|
|
125749
125974
|
__require("fs").unlinkSync(oldPath);
|
|
125750
125975
|
result.filesModified.push(newPath);
|
|
@@ -125910,7 +126135,7 @@ init_tool();
|
|
|
125910
126135
|
import { resolve as resolve18 } from "path";
|
|
125911
126136
|
|
|
125912
126137
|
// src/tools/lsp/directory-diagnostics.ts
|
|
125913
|
-
import { existsSync as
|
|
126138
|
+
import { existsSync as existsSync69, lstatSync as lstatSync2, readdirSync as readdirSync19 } from "fs";
|
|
125914
126139
|
import { extname as extname6, join as join75, resolve as resolve17 } from "path";
|
|
125915
126140
|
var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
125916
126141
|
function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
@@ -125956,7 +126181,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
125956
126181
|
throw new Error(`Extension must start with a dot (e.g., ".ts", not "${extension}"). ` + `Use ".${extension}" instead.`);
|
|
125957
126182
|
}
|
|
125958
126183
|
const absDir = resolve17(directory);
|
|
125959
|
-
if (!
|
|
126184
|
+
if (!existsSync69(absDir)) {
|
|
125960
126185
|
throw new Error(`Directory does not exist: ${absDir}`);
|
|
125961
126186
|
}
|
|
125962
126187
|
const serverResult = findServerForExtension(extension);
|
|
@@ -126217,11 +126442,11 @@ var DEFAULT_MAX_MATCHES = 500;
|
|
|
126217
126442
|
|
|
126218
126443
|
// src/tools/ast-grep/sg-cli-path.ts
|
|
126219
126444
|
import { createRequire as createRequire4 } from "module";
|
|
126220
|
-
import { dirname as
|
|
126221
|
-
import { existsSync as
|
|
126445
|
+
import { dirname as dirname22, join as join78 } from "path";
|
|
126446
|
+
import { existsSync as existsSync71, statSync as statSync9 } from "fs";
|
|
126222
126447
|
|
|
126223
126448
|
// src/tools/ast-grep/downloader.ts
|
|
126224
|
-
import { existsSync as
|
|
126449
|
+
import { existsSync as existsSync70 } from "fs";
|
|
126225
126450
|
import { join as join77 } from "path";
|
|
126226
126451
|
import { homedir as homedir14 } from "os";
|
|
126227
126452
|
import { createRequire as createRequire3 } from "module";
|
|
@@ -126273,7 +126498,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
126273
126498
|
const cacheDir = getCacheDir3();
|
|
126274
126499
|
const binaryName = getBinaryName3();
|
|
126275
126500
|
const binaryPath = join77(cacheDir, binaryName);
|
|
126276
|
-
if (
|
|
126501
|
+
if (existsSync70(binaryPath)) {
|
|
126277
126502
|
return binaryPath;
|
|
126278
126503
|
}
|
|
126279
126504
|
const { arch, os: os4 } = platformInfo;
|
|
@@ -126334,9 +126559,9 @@ function findSgCliPathSync() {
|
|
|
126334
126559
|
try {
|
|
126335
126560
|
const require2 = createRequire4(import.meta.url);
|
|
126336
126561
|
const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
|
|
126337
|
-
const cliDirectory =
|
|
126562
|
+
const cliDirectory = dirname22(cliPackageJsonPath);
|
|
126338
126563
|
const sgPath = join78(cliDirectory, binaryName);
|
|
126339
|
-
if (
|
|
126564
|
+
if (existsSync71(sgPath) && isValidBinary(sgPath)) {
|
|
126340
126565
|
return sgPath;
|
|
126341
126566
|
}
|
|
126342
126567
|
} catch {}
|
|
@@ -126345,10 +126570,10 @@ function findSgCliPathSync() {
|
|
|
126345
126570
|
try {
|
|
126346
126571
|
const require2 = createRequire4(import.meta.url);
|
|
126347
126572
|
const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
|
|
126348
|
-
const packageDirectory =
|
|
126573
|
+
const packageDirectory = dirname22(packageJsonPath);
|
|
126349
126574
|
const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
126350
126575
|
const binaryPath = join78(packageDirectory, astGrepBinaryName);
|
|
126351
|
-
if (
|
|
126576
|
+
if (existsSync71(binaryPath) && isValidBinary(binaryPath)) {
|
|
126352
126577
|
return binaryPath;
|
|
126353
126578
|
}
|
|
126354
126579
|
} catch {}
|
|
@@ -126356,7 +126581,7 @@ function findSgCliPathSync() {
|
|
|
126356
126581
|
if (process.platform === "darwin") {
|
|
126357
126582
|
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
|
|
126358
126583
|
for (const path7 of homebrewPaths) {
|
|
126359
|
-
if (
|
|
126584
|
+
if (existsSync71(path7) && isValidBinary(path7)) {
|
|
126360
126585
|
return path7;
|
|
126361
126586
|
}
|
|
126362
126587
|
}
|
|
@@ -126380,14 +126605,14 @@ function setSgCliPath(path7) {
|
|
|
126380
126605
|
}
|
|
126381
126606
|
// src/tools/ast-grep/cli.ts
|
|
126382
126607
|
var {spawn: spawn17 } = globalThis.Bun;
|
|
126383
|
-
import { existsSync as
|
|
126608
|
+
import { existsSync as existsSync73 } from "fs";
|
|
126384
126609
|
|
|
126385
126610
|
// src/tools/ast-grep/cli-binary-path-resolution.ts
|
|
126386
|
-
import { existsSync as
|
|
126611
|
+
import { existsSync as existsSync72 } from "fs";
|
|
126387
126612
|
var resolvedCliPath3 = null;
|
|
126388
126613
|
var initPromise3 = null;
|
|
126389
126614
|
async function getAstGrepPath() {
|
|
126390
|
-
if (resolvedCliPath3 !== null &&
|
|
126615
|
+
if (resolvedCliPath3 !== null && existsSync72(resolvedCliPath3)) {
|
|
126391
126616
|
return resolvedCliPath3;
|
|
126392
126617
|
}
|
|
126393
126618
|
if (initPromise3) {
|
|
@@ -126395,7 +126620,7 @@ async function getAstGrepPath() {
|
|
|
126395
126620
|
}
|
|
126396
126621
|
initPromise3 = (async () => {
|
|
126397
126622
|
const syncPath = findSgCliPathSync();
|
|
126398
|
-
if (syncPath &&
|
|
126623
|
+
if (syncPath && existsSync72(syncPath)) {
|
|
126399
126624
|
resolvedCliPath3 = syncPath;
|
|
126400
126625
|
setSgCliPath(syncPath);
|
|
126401
126626
|
return syncPath;
|
|
@@ -126494,7 +126719,7 @@ async function runSg(options) {
|
|
|
126494
126719
|
const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
|
|
126495
126720
|
args.push(...paths);
|
|
126496
126721
|
let cliPath = getSgCliPath();
|
|
126497
|
-
if (!cliPath || !
|
|
126722
|
+
if (!cliPath || !existsSync73(cliPath)) {
|
|
126498
126723
|
const downloadedPath = await getAstGrepPath();
|
|
126499
126724
|
if (downloadedPath) {
|
|
126500
126725
|
cliPath = downloadedPath;
|
|
@@ -126749,12 +126974,12 @@ import { resolve as resolve19 } from "path";
|
|
|
126749
126974
|
var {spawn: spawn18 } = globalThis.Bun;
|
|
126750
126975
|
|
|
126751
126976
|
// src/tools/grep/constants.ts
|
|
126752
|
-
import { existsSync as
|
|
126753
|
-
import { join as join80, dirname as
|
|
126977
|
+
import { existsSync as existsSync75 } from "fs";
|
|
126978
|
+
import { join as join80, dirname as dirname23 } from "path";
|
|
126754
126979
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
126755
126980
|
|
|
126756
126981
|
// src/tools/grep/downloader.ts
|
|
126757
|
-
import { existsSync as
|
|
126982
|
+
import { existsSync as existsSync74, readdirSync as readdirSync21 } from "fs";
|
|
126758
126983
|
import { join as join79 } from "path";
|
|
126759
126984
|
init_plugin_identity();
|
|
126760
126985
|
function findFileRecursive(dir, filename) {
|
|
@@ -126819,7 +127044,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
126819
127044
|
}
|
|
126820
127045
|
const installDir = getInstallDir();
|
|
126821
127046
|
const rgPath = getRgPath();
|
|
126822
|
-
if (
|
|
127047
|
+
if (existsSync74(rgPath)) {
|
|
126823
127048
|
return rgPath;
|
|
126824
127049
|
}
|
|
126825
127050
|
ensureCacheDir(installDir);
|
|
@@ -126834,7 +127059,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
126834
127059
|
await extractZip2(archivePath, installDir);
|
|
126835
127060
|
}
|
|
126836
127061
|
ensureExecutable(rgPath);
|
|
126837
|
-
if (!
|
|
127062
|
+
if (!existsSync74(rgPath)) {
|
|
126838
127063
|
throw new Error("ripgrep binary not found after extraction");
|
|
126839
127064
|
}
|
|
126840
127065
|
return rgPath;
|
|
@@ -126846,7 +127071,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
126846
127071
|
}
|
|
126847
127072
|
function getInstalledRipgrepPath() {
|
|
126848
127073
|
const rgPath = getRgPath();
|
|
126849
|
-
return
|
|
127074
|
+
return existsSync74(rgPath) ? rgPath : null;
|
|
126850
127075
|
}
|
|
126851
127076
|
|
|
126852
127077
|
// src/tools/grep/constants.ts
|
|
@@ -126868,7 +127093,7 @@ function findExecutable(name) {
|
|
|
126868
127093
|
}
|
|
126869
127094
|
function getOpenCodeBundledRg() {
|
|
126870
127095
|
const execPath = process.execPath;
|
|
126871
|
-
const execDir =
|
|
127096
|
+
const execDir = dirname23(execPath);
|
|
126872
127097
|
const isWindows2 = process.platform === "win32";
|
|
126873
127098
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
126874
127099
|
const candidates = [
|
|
@@ -126879,7 +127104,7 @@ function getOpenCodeBundledRg() {
|
|
|
126879
127104
|
join80(execDir, "..", "libexec", rgName)
|
|
126880
127105
|
];
|
|
126881
127106
|
for (const candidate of candidates) {
|
|
126882
|
-
if (
|
|
127107
|
+
if (existsSync75(candidate)) {
|
|
126883
127108
|
return candidate;
|
|
126884
127109
|
}
|
|
126885
127110
|
}
|
|
@@ -127531,10 +127756,10 @@ Use this when a task matches an available skill's or command's description.
|
|
|
127531
127756
|
`;
|
|
127532
127757
|
// src/tools/skill/tools.ts
|
|
127533
127758
|
init_dist();
|
|
127534
|
-
import { dirname as
|
|
127759
|
+
import { dirname as dirname25 } from "path";
|
|
127535
127760
|
|
|
127536
127761
|
// src/tools/slashcommand/command-output-formatter.ts
|
|
127537
|
-
import { dirname as
|
|
127762
|
+
import { dirname as dirname24 } from "path";
|
|
127538
127763
|
async function formatLoadedCommand(command, userMessage) {
|
|
127539
127764
|
const sections = [];
|
|
127540
127765
|
sections.push(`# /${command.name} Command
|
|
@@ -127573,7 +127798,7 @@ async function formatLoadedCommand(command, userMessage) {
|
|
|
127573
127798
|
if (!content && command.lazyContentLoader) {
|
|
127574
127799
|
content = await command.lazyContentLoader.load();
|
|
127575
127800
|
}
|
|
127576
|
-
const commandDir = command.path ?
|
|
127801
|
+
const commandDir = command.path ? dirname24(command.path) : process.cwd();
|
|
127577
127802
|
const withFileReferences = await resolveFileReferencesInText(content, commandDir);
|
|
127578
127803
|
const resolvedContent = await resolveCommandsInText(withFileReferences);
|
|
127579
127804
|
let finalContent = resolvedContent.trim();
|
|
@@ -127963,7 +128188,7 @@ function createSkillTool(options = {}) {
|
|
|
127963
128188
|
if (matchedSkill.name === "git-master") {
|
|
127964
128189
|
body = injectGitMasterConfig(body, options.gitMasterConfig);
|
|
127965
128190
|
}
|
|
127966
|
-
const dir = matchedSkill.path ?
|
|
128191
|
+
const dir = matchedSkill.path ? dirname25(matchedSkill.path) : matchedSkill.resolvedPath || process.cwd();
|
|
127967
128192
|
const output = [
|
|
127968
128193
|
`## Skill: ${matchedSkill.name}`,
|
|
127969
128194
|
"",
|
|
@@ -128081,11 +128306,11 @@ Has Todos: Yes (12 items, 8 completed)
|
|
|
128081
128306
|
Has Transcript: Yes (234 entries)`;
|
|
128082
128307
|
|
|
128083
128308
|
// src/tools/session-manager/file-storage.ts
|
|
128084
|
-
import { existsSync as
|
|
128309
|
+
import { existsSync as existsSync76 } from "fs";
|
|
128085
128310
|
import { readdir, readFile } from "fs/promises";
|
|
128086
128311
|
import { join as join82 } from "path";
|
|
128087
128312
|
async function getFileMainSessions(directory) {
|
|
128088
|
-
if (!
|
|
128313
|
+
if (!existsSync76(SESSION_STORAGE))
|
|
128089
128314
|
return [];
|
|
128090
128315
|
const sessions = [];
|
|
128091
128316
|
try {
|
|
@@ -128117,7 +128342,7 @@ async function getFileMainSessions(directory) {
|
|
|
128117
128342
|
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
128118
128343
|
}
|
|
128119
128344
|
async function getFileAllSessions() {
|
|
128120
|
-
if (!
|
|
128345
|
+
if (!existsSync76(MESSAGE_STORAGE))
|
|
128121
128346
|
return [];
|
|
128122
128347
|
const sessions = [];
|
|
128123
128348
|
async function scanDirectory(dir) {
|
|
@@ -128146,7 +128371,7 @@ async function fileSessionExists(sessionID) {
|
|
|
128146
128371
|
}
|
|
128147
128372
|
async function getFileSessionMessages(sessionID) {
|
|
128148
128373
|
const messageDir = getMessageDir(sessionID);
|
|
128149
|
-
if (!messageDir || !
|
|
128374
|
+
if (!messageDir || !existsSync76(messageDir))
|
|
128150
128375
|
return [];
|
|
128151
128376
|
const messages = [];
|
|
128152
128377
|
try {
|
|
@@ -128182,7 +128407,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
128182
128407
|
}
|
|
128183
128408
|
async function readParts2(messageID) {
|
|
128184
128409
|
const partDir = join82(PART_STORAGE, messageID);
|
|
128185
|
-
if (!
|
|
128410
|
+
if (!existsSync76(partDir))
|
|
128186
128411
|
return [];
|
|
128187
128412
|
const parts = [];
|
|
128188
128413
|
try {
|
|
@@ -128203,7 +128428,7 @@ async function readParts2(messageID) {
|
|
|
128203
128428
|
return parts.sort((a, b) => a.id.localeCompare(b.id));
|
|
128204
128429
|
}
|
|
128205
128430
|
async function getFileSessionTodos(sessionID) {
|
|
128206
|
-
if (!
|
|
128431
|
+
if (!existsSync76(TODO_DIR2))
|
|
128207
128432
|
return [];
|
|
128208
128433
|
try {
|
|
128209
128434
|
const allFiles = await readdir(TODO_DIR2);
|
|
@@ -128230,10 +128455,10 @@ async function getFileSessionTodos(sessionID) {
|
|
|
128230
128455
|
return [];
|
|
128231
128456
|
}
|
|
128232
128457
|
async function getFileSessionTranscript(sessionID) {
|
|
128233
|
-
if (!
|
|
128458
|
+
if (!existsSync76(TRANSCRIPT_DIR2))
|
|
128234
128459
|
return 0;
|
|
128235
128460
|
const transcriptFile = join82(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
128236
|
-
if (!
|
|
128461
|
+
if (!existsSync76(transcriptFile))
|
|
128237
128462
|
return 0;
|
|
128238
128463
|
try {
|
|
128239
128464
|
const content = await readFile(transcriptFile, "utf-8");
|
|
@@ -128998,6 +129223,26 @@ function findMcpServer(mcpName, skills) {
|
|
|
128998
129223
|
}
|
|
128999
129224
|
return null;
|
|
129000
129225
|
}
|
|
129226
|
+
function convertBuiltinMcpConfig(config4) {
|
|
129227
|
+
if (config4.enabled === false)
|
|
129228
|
+
return null;
|
|
129229
|
+
if (config4.type === "remote") {
|
|
129230
|
+
return {
|
|
129231
|
+
type: "http",
|
|
129232
|
+
url: config4.url,
|
|
129233
|
+
headers: config4.headers
|
|
129234
|
+
};
|
|
129235
|
+
}
|
|
129236
|
+
const [command, ...args] = config4.command ?? [];
|
|
129237
|
+
if (!command)
|
|
129238
|
+
return null;
|
|
129239
|
+
return {
|
|
129240
|
+
type: "stdio",
|
|
129241
|
+
command,
|
|
129242
|
+
args,
|
|
129243
|
+
env: config4.environment
|
|
129244
|
+
};
|
|
129245
|
+
}
|
|
129001
129246
|
function formatAvailableMcps(skills) {
|
|
129002
129247
|
const mcps = [];
|
|
129003
129248
|
for (const skill2 of skills) {
|
|
@@ -129010,6 +129255,11 @@ function formatAvailableMcps(skills) {
|
|
|
129010
129255
|
return mcps.length > 0 ? mcps.join(`
|
|
129011
129256
|
`) : " (none found)";
|
|
129012
129257
|
}
|
|
129258
|
+
function formatAvailableBuiltinMcps(builtinMcp) {
|
|
129259
|
+
const names = Object.entries(builtinMcp ?? {}).filter(([, config4]) => config4.enabled !== false).map(([name]) => ` - "${name}" from hiai-opencode config`);
|
|
129260
|
+
return names.length > 0 ? names.join(`
|
|
129261
|
+
`) : " (none found)";
|
|
129262
|
+
}
|
|
129013
129263
|
function formatBuiltinMcpHint(mcpName) {
|
|
129014
129264
|
const nativeTools = BUILTIN_MCP_TOOL_HINTS[mcpName];
|
|
129015
129265
|
if (!nativeTools)
|
|
@@ -129055,7 +129305,7 @@ function applyGrepFilter(output, pattern) {
|
|
|
129055
129305
|
}
|
|
129056
129306
|
}
|
|
129057
129307
|
function createSkillMcpTool(options) {
|
|
129058
|
-
const { manager, getLoadedSkills, getSessionID } = options;
|
|
129308
|
+
const { manager, getLoadedSkills, getSessionID, builtinMcp } = options;
|
|
129059
129309
|
return tool({
|
|
129060
129310
|
description: SKILL_MCP_DESCRIPTION,
|
|
129061
129311
|
args: {
|
|
@@ -129070,7 +129320,9 @@ function createSkillMcpTool(options) {
|
|
|
129070
129320
|
const operation = validateOperationParams(args);
|
|
129071
129321
|
const skills = getLoadedSkills();
|
|
129072
129322
|
const found = findMcpServer(args.mcp_name, skills);
|
|
129073
|
-
|
|
129323
|
+
const builtinConfig = builtinMcp?.[args.mcp_name];
|
|
129324
|
+
const convertedBuiltinConfig = builtinConfig ? convertBuiltinMcpConfig(builtinConfig) : null;
|
|
129325
|
+
if (!found && !convertedBuiltinConfig) {
|
|
129074
129326
|
const builtinHint = formatBuiltinMcpHint(args.mcp_name);
|
|
129075
129327
|
if (builtinHint) {
|
|
129076
129328
|
throw new Error(builtinHint);
|
|
@@ -129080,7 +129332,10 @@ function createSkillMcpTool(options) {
|
|
|
129080
129332
|
` + `Available MCP servers in loaded skills:
|
|
129081
129333
|
` + formatAvailableMcps(skills) + `
|
|
129082
129334
|
|
|
129083
|
-
` + `
|
|
129335
|
+
` + `Available MCP servers in hiai-opencode config:
|
|
129336
|
+
` + formatAvailableBuiltinMcps(builtinMcp) + `
|
|
129337
|
+
|
|
129338
|
+
` + `Hint: Load the skill first for skill-embedded MCPs. Builtin hiai-opencode MCPs can be called directly when enabled in hiai-opencode.json.`);
|
|
129084
129339
|
}
|
|
129085
129340
|
const sessionID = toolContext.sessionID || getSessionID?.();
|
|
129086
129341
|
if (!sessionID) {
|
|
@@ -129088,13 +129343,13 @@ function createSkillMcpTool(options) {
|
|
|
129088
129343
|
}
|
|
129089
129344
|
const info = {
|
|
129090
129345
|
serverName: args.mcp_name,
|
|
129091
|
-
skillName: found
|
|
129346
|
+
skillName: found?.skill.name ?? "hiai-opencode",
|
|
129092
129347
|
sessionID,
|
|
129093
|
-
scope: found
|
|
129348
|
+
scope: found?.skill.scope ?? "user"
|
|
129094
129349
|
};
|
|
129095
129350
|
const context = {
|
|
129096
|
-
config: found
|
|
129097
|
-
skillName: found
|
|
129351
|
+
config: found?.config ?? convertedBuiltinConfig,
|
|
129352
|
+
skillName: found?.skill.name ?? "hiai-opencode"
|
|
129098
129353
|
};
|
|
129099
129354
|
const parsedArgs = parseArguments(args.arguments);
|
|
129100
129355
|
let output;
|
|
@@ -130613,9 +130868,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
|
|
|
130613
130868
|
|
|
130614
130869
|
// src/tools/look-at/image-converter.ts
|
|
130615
130870
|
import * as childProcess from "child_process";
|
|
130616
|
-
import { existsSync as
|
|
130871
|
+
import { existsSync as existsSync77, mkdtempSync, readFileSync as readFileSync51, rmSync as rmSync3, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
|
|
130617
130872
|
import { tmpdir as tmpdir7 } from "os";
|
|
130618
|
-
import { dirname as
|
|
130873
|
+
import { dirname as dirname26, join as join83 } from "path";
|
|
130619
130874
|
var SUPPORTED_FORMATS = new Set([
|
|
130620
130875
|
"image/jpeg",
|
|
130621
130876
|
"image/png",
|
|
@@ -130653,7 +130908,7 @@ function needsConversion(mimeType) {
|
|
|
130653
130908
|
return mimeType.startsWith("image/");
|
|
130654
130909
|
}
|
|
130655
130910
|
function convertImageToJpeg(inputPath, mimeType) {
|
|
130656
|
-
if (!
|
|
130911
|
+
if (!existsSync77(inputPath)) {
|
|
130657
130912
|
throw new Error(`File not found: ${inputPath}`);
|
|
130658
130913
|
}
|
|
130659
130914
|
const tempDir = mkdtempSync(join83(tmpdir7(), "opencode-img-"));
|
|
@@ -130667,7 +130922,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130667
130922
|
encoding: "utf-8",
|
|
130668
130923
|
timeout: CONVERSION_TIMEOUT_MS
|
|
130669
130924
|
});
|
|
130670
|
-
if (
|
|
130925
|
+
if (existsSync77(outputPath)) {
|
|
130671
130926
|
log(`[image-converter] Converted using sips: ${outputPath}`);
|
|
130672
130927
|
return outputPath;
|
|
130673
130928
|
}
|
|
@@ -130682,7 +130937,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130682
130937
|
encoding: "utf-8",
|
|
130683
130938
|
timeout: CONVERSION_TIMEOUT_MS
|
|
130684
130939
|
});
|
|
130685
|
-
if (
|
|
130940
|
+
if (existsSync77(outputPath)) {
|
|
130686
130941
|
log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
|
|
130687
130942
|
return outputPath;
|
|
130688
130943
|
}
|
|
@@ -130695,7 +130950,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130695
130950
|
` + ` RHEL/CentOS: sudo yum install ImageMagick`);
|
|
130696
130951
|
} catch (error92) {
|
|
130697
130952
|
try {
|
|
130698
|
-
if (
|
|
130953
|
+
if (existsSync77(outputPath)) {
|
|
130699
130954
|
unlinkSync10(outputPath);
|
|
130700
130955
|
}
|
|
130701
130956
|
} catch {}
|
|
@@ -130708,12 +130963,12 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
130708
130963
|
}
|
|
130709
130964
|
function cleanupConvertedImage(filePath) {
|
|
130710
130965
|
try {
|
|
130711
|
-
const tempDirectory =
|
|
130712
|
-
if (
|
|
130966
|
+
const tempDirectory = dirname26(filePath);
|
|
130967
|
+
if (existsSync77(filePath)) {
|
|
130713
130968
|
unlinkSync10(filePath);
|
|
130714
130969
|
log(`[image-converter] Cleaned up temporary file: ${filePath}`);
|
|
130715
130970
|
}
|
|
130716
|
-
if (
|
|
130971
|
+
if (existsSync77(tempDirectory)) {
|
|
130717
130972
|
rmSync3(tempDirectory, { recursive: true, force: true });
|
|
130718
130973
|
log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
|
|
130719
130974
|
}
|
|
@@ -130733,14 +130988,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
|
130733
130988
|
log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
|
|
130734
130989
|
const outputPath = convertImageToJpeg(inputPath, mimeType);
|
|
130735
130990
|
tempFiles.push(outputPath);
|
|
130736
|
-
const convertedBuffer =
|
|
130991
|
+
const convertedBuffer = readFileSync51(outputPath);
|
|
130737
130992
|
const convertedBase64 = convertedBuffer.toString("base64");
|
|
130738
130993
|
log(`[image-converter] Base64 conversion successful`);
|
|
130739
130994
|
return { base64: convertedBase64, tempFiles };
|
|
130740
130995
|
} catch (error92) {
|
|
130741
130996
|
tempFiles.forEach((file3) => {
|
|
130742
130997
|
try {
|
|
130743
|
-
if (
|
|
130998
|
+
if (existsSync77(file3))
|
|
130744
130999
|
unlinkSync10(file3);
|
|
130745
131000
|
} catch {}
|
|
130746
131001
|
});
|
|
@@ -132921,22 +133176,22 @@ function applyFallbackEntrySettings(input) {
|
|
|
132921
133176
|
// src/tools/delegate-task/subagent-discovery.ts
|
|
132922
133177
|
init_agent_display_names();
|
|
132923
133178
|
// src/features/claude-code-agent-loader/loader.ts
|
|
132924
|
-
import { existsSync as
|
|
133179
|
+
import { existsSync as existsSync80, readdirSync as readdirSync22 } from "fs";
|
|
132925
133180
|
import { join as join84 } from "path";
|
|
132926
133181
|
|
|
132927
133182
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
132928
|
-
import { existsSync as
|
|
133183
|
+
import { existsSync as existsSync79, readFileSync as readFileSync53 } from "fs";
|
|
132929
133184
|
import { basename as basename13, extname as extname8 } from "path";
|
|
132930
133185
|
init_logger();
|
|
132931
133186
|
|
|
132932
133187
|
// src/features/claude-code-agent-loader/json-agent-loader.ts
|
|
132933
|
-
import { existsSync as
|
|
133188
|
+
import { existsSync as existsSync78, readFileSync as readFileSync52 } from "fs";
|
|
132934
133189
|
function parseJsonAgentFile(filePath, scope) {
|
|
132935
133190
|
try {
|
|
132936
|
-
if (!
|
|
133191
|
+
if (!existsSync78(filePath)) {
|
|
132937
133192
|
return null;
|
|
132938
133193
|
}
|
|
132939
|
-
const content =
|
|
133194
|
+
const content = readFileSync52(filePath, "utf-8");
|
|
132940
133195
|
const { data } = parseJsoncSafe(content);
|
|
132941
133196
|
if (!data) {
|
|
132942
133197
|
return null;
|
|
@@ -132972,10 +133227,10 @@ function parseJsonAgentFile(filePath, scope) {
|
|
|
132972
133227
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
132973
133228
|
function parseMarkdownAgentFile(filePath, scope) {
|
|
132974
133229
|
try {
|
|
132975
|
-
if (!
|
|
133230
|
+
if (!existsSync79(filePath)) {
|
|
132976
133231
|
return null;
|
|
132977
133232
|
}
|
|
132978
|
-
const content =
|
|
133233
|
+
const content = readFileSync53(filePath, "utf-8");
|
|
132979
133234
|
const { data, body } = parseFrontmatter(content);
|
|
132980
133235
|
const fileName = basename13(filePath);
|
|
132981
133236
|
const agentName = fileName.replace(/\.md$/i, "");
|
|
@@ -133007,7 +133262,7 @@ function parseMarkdownAgentFile(filePath, scope) {
|
|
|
133007
133262
|
function loadAgentDefinitions(paths, scope) {
|
|
133008
133263
|
const result = Object.create(null);
|
|
133009
133264
|
for (const filePath of paths) {
|
|
133010
|
-
if (!
|
|
133265
|
+
if (!existsSync79(filePath)) {
|
|
133011
133266
|
log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
|
|
133012
133267
|
continue;
|
|
133013
133268
|
}
|
|
@@ -133032,7 +133287,7 @@ function loadAgentDefinitions(paths, scope) {
|
|
|
133032
133287
|
|
|
133033
133288
|
// src/features/claude-code-agent-loader/loader.ts
|
|
133034
133289
|
function loadAgentsFromDir(agentsDir, scope) {
|
|
133035
|
-
if (!
|
|
133290
|
+
if (!existsSync80(agentsDir)) {
|
|
133036
133291
|
return [];
|
|
133037
133292
|
}
|
|
133038
133293
|
const entries = readdirSync22(agentsDir, { withFileTypes: true });
|
|
@@ -133674,8 +133929,8 @@ var TaskDeleteInputSchema = exports_external.object({
|
|
|
133674
133929
|
});
|
|
133675
133930
|
|
|
133676
133931
|
// src/features/claude-tasks/storage.ts
|
|
133677
|
-
import { join as join86, dirname as
|
|
133678
|
-
import { existsSync as
|
|
133932
|
+
import { join as join86, dirname as dirname28, basename as basename14, isAbsolute as isAbsolute12 } from "path";
|
|
133933
|
+
import { existsSync as existsSync82, mkdirSync as mkdirSync16, readFileSync as readFileSync55, writeFileSync as writeFileSync19, renameSync as renameSync4, unlinkSync as unlinkSync11, readdirSync as readdirSync23 } from "fs";
|
|
133679
133934
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
133680
133935
|
function getTaskDir(config4 = {}) {
|
|
133681
133936
|
const tasksConfig = config4.bob?.tasks;
|
|
@@ -133703,16 +133958,16 @@ function resolveTaskListId(config4 = {}) {
|
|
|
133703
133958
|
return sanitizePathSegment(basename14(process.cwd()));
|
|
133704
133959
|
}
|
|
133705
133960
|
function ensureDir(dirPath) {
|
|
133706
|
-
if (!
|
|
133961
|
+
if (!existsSync82(dirPath)) {
|
|
133707
133962
|
mkdirSync16(dirPath, { recursive: true });
|
|
133708
133963
|
}
|
|
133709
133964
|
}
|
|
133710
133965
|
function readJsonSafe(filePath, schema2) {
|
|
133711
133966
|
try {
|
|
133712
|
-
if (!
|
|
133967
|
+
if (!existsSync82(filePath)) {
|
|
133713
133968
|
return null;
|
|
133714
133969
|
}
|
|
133715
|
-
const content =
|
|
133970
|
+
const content = readFileSync55(filePath, "utf-8");
|
|
133716
133971
|
const parsed = JSON.parse(content);
|
|
133717
133972
|
const result = schema2.safeParse(parsed);
|
|
133718
133973
|
if (!result.success) {
|
|
@@ -133724,7 +133979,7 @@ function readJsonSafe(filePath, schema2) {
|
|
|
133724
133979
|
}
|
|
133725
133980
|
}
|
|
133726
133981
|
function writeJsonAtomic(filePath, data) {
|
|
133727
|
-
const dir =
|
|
133982
|
+
const dir = dirname28(filePath);
|
|
133728
133983
|
ensureDir(dir);
|
|
133729
133984
|
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
133730
133985
|
try {
|
|
@@ -133732,7 +133987,7 @@ function writeJsonAtomic(filePath, data) {
|
|
|
133732
133987
|
renameSync4(tempPath, filePath);
|
|
133733
133988
|
} catch (error92) {
|
|
133734
133989
|
try {
|
|
133735
|
-
if (
|
|
133990
|
+
if (existsSync82(tempPath)) {
|
|
133736
133991
|
unlinkSync11(tempPath);
|
|
133737
133992
|
}
|
|
133738
133993
|
} catch {}
|
|
@@ -133754,7 +134009,7 @@ function acquireLock(dirPath) {
|
|
|
133754
134009
|
};
|
|
133755
134010
|
const isStale = () => {
|
|
133756
134011
|
try {
|
|
133757
|
-
const lockContent =
|
|
134012
|
+
const lockContent = readFileSync55(lockPath, "utf-8");
|
|
133758
134013
|
const lockData = JSON.parse(lockContent);
|
|
133759
134014
|
const lockAge = Date.now() - lockData.timestamp;
|
|
133760
134015
|
return lockAge > STALE_LOCK_THRESHOLD_MS;
|
|
@@ -133792,9 +134047,9 @@ function acquireLock(dirPath) {
|
|
|
133792
134047
|
acquired: true,
|
|
133793
134048
|
release: () => {
|
|
133794
134049
|
try {
|
|
133795
|
-
if (!
|
|
134050
|
+
if (!existsSync82(lockPath))
|
|
133796
134051
|
return;
|
|
133797
|
-
const lockContent =
|
|
134052
|
+
const lockContent = readFileSync55(lockPath, "utf-8");
|
|
133798
134053
|
const lockData = JSON.parse(lockContent);
|
|
133799
134054
|
if (lockData.id !== lockId)
|
|
133800
134055
|
return;
|
|
@@ -134020,7 +134275,7 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
134020
134275
|
// src/tools/task/task-list.ts
|
|
134021
134276
|
init_tool();
|
|
134022
134277
|
import { join as join89 } from "path";
|
|
134023
|
-
import { existsSync as
|
|
134278
|
+
import { existsSync as existsSync83, readdirSync as readdirSync24 } from "fs";
|
|
134024
134279
|
function createTaskList(config4) {
|
|
134025
134280
|
return tool({
|
|
134026
134281
|
description: `List all active tasks with summary information.
|
|
@@ -134031,7 +134286,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
134031
134286
|
args: {},
|
|
134032
134287
|
execute: async () => {
|
|
134033
134288
|
const taskDir = getTaskDir(config4);
|
|
134034
|
-
if (!
|
|
134289
|
+
if (!existsSync83(taskDir)) {
|
|
134035
134290
|
return JSON.stringify({ tasks: [] });
|
|
134036
134291
|
}
|
|
134037
134292
|
const files = readdirSync24(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
|
|
@@ -136334,7 +136589,7 @@ function createToolGuardHooks(args) {
|
|
|
136334
136589
|
const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null;
|
|
136335
136590
|
const todoDescriptionOverride = isHookEnabled("todo-description-override") ? safeHook("todo-description-override", () => createTodoDescriptionOverrideHook()) : null;
|
|
136336
136591
|
const webfetchRedirectGuard = isHookEnabled("webfetch-redirect-guard") ? safeHook("webfetch-redirect-guard", () => createWebFetchRedirectGuardHook(ctx)) : null;
|
|
136337
|
-
const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "
|
|
136592
|
+
const fastApply = isHookEnabled("fast-apply") ? safeHook("fast-apply", () => createFastApplyHook(pluginConfig.fast_apply ?? { enabled: false, ollama_url: "", model: "", timeout: 30000 })) : null;
|
|
136338
136593
|
return {
|
|
136339
136594
|
commentChecker,
|
|
136340
136595
|
toolOutputTruncator,
|
|
@@ -137247,7 +137502,7 @@ function unregisterManagerForCleanup(manager) {
|
|
|
137247
137502
|
}
|
|
137248
137503
|
|
|
137249
137504
|
// src/features/background-agent/compaction-aware-message-resolver.ts
|
|
137250
|
-
import { readdirSync as readdirSync25, readFileSync as
|
|
137505
|
+
import { readdirSync as readdirSync25, readFileSync as readFileSync56 } from "fs";
|
|
137251
137506
|
import { join as join92 } from "path";
|
|
137252
137507
|
function hasFullAgentAndModel(message) {
|
|
137253
137508
|
return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
|
|
@@ -137327,7 +137582,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
|
|
|
137327
137582
|
const messages = [];
|
|
137328
137583
|
for (const file3 of files) {
|
|
137329
137584
|
try {
|
|
137330
|
-
const content =
|
|
137585
|
+
const content = readFileSync56(join92(messageDir, file3), "utf-8");
|
|
137331
137586
|
const parsed = JSON.parse(content);
|
|
137332
137587
|
if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
|
|
137333
137588
|
continue;
|
|
@@ -139424,8 +139679,8 @@ ${originalText}`;
|
|
|
139424
139679
|
}
|
|
139425
139680
|
}
|
|
139426
139681
|
// src/features/mcp-oauth/storage.ts
|
|
139427
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
139428
|
-
import { dirname as
|
|
139682
|
+
import { chmodSync as chmodSync2, existsSync as existsSync84, mkdirSync as mkdirSync17, readFileSync as readFileSync57, renameSync as renameSync5, unlinkSync as unlinkSync12, writeFileSync as writeFileSync20 } from "fs";
|
|
139683
|
+
import { dirname as dirname29, join as join94 } from "path";
|
|
139429
139684
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
139430
139685
|
function getMcpOauthStoragePath() {
|
|
139431
139686
|
return join94(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
|
|
@@ -139465,11 +139720,11 @@ function buildKey(serverHost, resource) {
|
|
|
139465
139720
|
}
|
|
139466
139721
|
function readStore() {
|
|
139467
139722
|
const filePath = getMcpOauthStoragePath();
|
|
139468
|
-
if (!
|
|
139723
|
+
if (!existsSync84(filePath)) {
|
|
139469
139724
|
return null;
|
|
139470
139725
|
}
|
|
139471
139726
|
try {
|
|
139472
|
-
const content =
|
|
139727
|
+
const content = readFileSync57(filePath, "utf-8");
|
|
139473
139728
|
return JSON.parse(content);
|
|
139474
139729
|
} catch {
|
|
139475
139730
|
return null;
|
|
@@ -139478,8 +139733,8 @@ function readStore() {
|
|
|
139478
139733
|
function writeStore(store2) {
|
|
139479
139734
|
const filePath = getMcpOauthStoragePath();
|
|
139480
139735
|
try {
|
|
139481
|
-
const dir =
|
|
139482
|
-
if (!
|
|
139736
|
+
const dir = dirname29(filePath);
|
|
139737
|
+
if (!existsSync84(dir)) {
|
|
139483
139738
|
mkdirSync17(dir, { recursive: true });
|
|
139484
139739
|
}
|
|
139485
139740
|
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
@@ -146126,7 +146381,7 @@ class TmuxSessionManager {
|
|
|
146126
146381
|
var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
|
|
146127
146382
|
var MIN_STABILITY_TIME_MS4 = 10 * 1000;
|
|
146128
146383
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
146129
|
-
import { existsSync as
|
|
146384
|
+
import { existsSync as existsSync85, readFileSync as readFileSync58 } from "fs";
|
|
146130
146385
|
import { join as join95 } from "path";
|
|
146131
146386
|
import { homedir as homedir15 } from "os";
|
|
146132
146387
|
init_logger();
|
|
@@ -146149,7 +146404,7 @@ function getMcpConfigPaths() {
|
|
|
146149
146404
|
});
|
|
146150
146405
|
}
|
|
146151
146406
|
async function loadMcpConfigFile(filePath) {
|
|
146152
|
-
if (!
|
|
146407
|
+
if (!existsSync85(filePath)) {
|
|
146153
146408
|
return null;
|
|
146154
146409
|
}
|
|
146155
146410
|
try {
|
|
@@ -146165,10 +146420,10 @@ function getSystemMcpServerNames() {
|
|
|
146165
146420
|
const paths = getMcpConfigPaths();
|
|
146166
146421
|
const cwd = process.cwd();
|
|
146167
146422
|
for (const { path: path9 } of paths) {
|
|
146168
|
-
if (!
|
|
146423
|
+
if (!existsSync85(path9))
|
|
146169
146424
|
continue;
|
|
146170
146425
|
try {
|
|
146171
|
-
const content =
|
|
146426
|
+
const content = readFileSync58(path9, "utf-8");
|
|
146172
146427
|
const config4 = JSON.parse(content);
|
|
146173
146428
|
if (!config4?.mcpServers)
|
|
146174
146429
|
continue;
|
|
@@ -150513,7 +150768,7 @@ var researcherPromptMetadata = {
|
|
|
150513
150768
|
};
|
|
150514
150769
|
|
|
150515
150770
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
150516
|
-
import { existsSync as
|
|
150771
|
+
import { existsSync as existsSync86, readFileSync as readFileSync59 } from "fs";
|
|
150517
150772
|
import { homedir as homedir16 } from "os";
|
|
150518
150773
|
import { isAbsolute as isAbsolute13, resolve as resolve22 } from "path";
|
|
150519
150774
|
init_logger();
|
|
@@ -150538,11 +150793,11 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
150538
150793
|
});
|
|
150539
150794
|
return `[WARNING: Path rejected: ${promptAppend}]`;
|
|
150540
150795
|
}
|
|
150541
|
-
if (!
|
|
150796
|
+
if (!existsSync86(filePath)) {
|
|
150542
150797
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
150543
150798
|
}
|
|
150544
150799
|
try {
|
|
150545
|
-
return
|
|
150800
|
+
return readFileSync59(filePath, "utf8");
|
|
150546
150801
|
} catch {
|
|
150547
150802
|
return `[WARNING: Could not read file: ${promptAppend}]`;
|
|
150548
150803
|
}
|
|
@@ -154176,6 +154431,28 @@ async function buildStrategistAgentConfig(params) {
|
|
|
154176
154431
|
return merged;
|
|
154177
154432
|
}
|
|
154178
154433
|
|
|
154434
|
+
// src/plugin/skill-discovery-config.ts
|
|
154435
|
+
var DEFAULT_SKILL_DISCOVERY = {
|
|
154436
|
+
config_sources: true,
|
|
154437
|
+
project_opencode: true,
|
|
154438
|
+
global_opencode: false,
|
|
154439
|
+
project_claude: false,
|
|
154440
|
+
global_claude: false,
|
|
154441
|
+
project_agents: false,
|
|
154442
|
+
global_agents: false
|
|
154443
|
+
};
|
|
154444
|
+
function resolveSkillDiscoveryConfig(pluginConfig) {
|
|
154445
|
+
const resolved = {
|
|
154446
|
+
...DEFAULT_SKILL_DISCOVERY,
|
|
154447
|
+
...pluginConfig.skill_discovery ?? {}
|
|
154448
|
+
};
|
|
154449
|
+
if (pluginConfig.claude_code?.skills === false) {
|
|
154450
|
+
resolved.project_claude = false;
|
|
154451
|
+
resolved.global_claude = false;
|
|
154452
|
+
}
|
|
154453
|
+
return resolved;
|
|
154454
|
+
}
|
|
154455
|
+
|
|
154179
154456
|
// src/plugin-handlers/agent-config-handler.ts
|
|
154180
154457
|
var CANONICAL_VISIBLE_AGENT_NAMES = [
|
|
154181
154458
|
"Bob",
|
|
@@ -154238,8 +154515,9 @@ async function applyAgentConfig(params) {
|
|
|
154238
154515
|
const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map((agent) => {
|
|
154239
154516
|
return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
|
|
154240
154517
|
});
|
|
154241
|
-
const
|
|
154518
|
+
const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
|
|
154242
154519
|
const [
|
|
154520
|
+
discoveredManagedPluginSkills,
|
|
154243
154521
|
discoveredConfigSourceSkills,
|
|
154244
154522
|
discoveredUserSkills,
|
|
154245
154523
|
discoveredProjectSkills,
|
|
@@ -154248,18 +154526,20 @@ async function applyAgentConfig(params) {
|
|
|
154248
154526
|
discoveredOpencodeProjectSkills,
|
|
154249
154527
|
discoveredGlobalAgentsSkills
|
|
154250
154528
|
] = await Promise.all([
|
|
154251
|
-
|
|
154529
|
+
discoverManagedPluginSkills(),
|
|
154530
|
+
discovery2.config_sources ? discoverConfigSourceSkills({
|
|
154252
154531
|
config: params.pluginConfig.skills,
|
|
154253
154532
|
configDir: params.ctx.directory
|
|
154254
|
-
}),
|
|
154255
|
-
|
|
154256
|
-
|
|
154257
|
-
|
|
154258
|
-
discoverOpencodeGlobalSkills(),
|
|
154259
|
-
discoverOpencodeProjectSkills(params.ctx.directory),
|
|
154260
|
-
|
|
154533
|
+
}) : Promise.resolve([]),
|
|
154534
|
+
discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
154535
|
+
discovery2.project_claude ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]),
|
|
154536
|
+
discovery2.project_agents ? discoverProjectAgentsSkills(params.ctx.directory) : Promise.resolve([]),
|
|
154537
|
+
discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
|
|
154538
|
+
discovery2.project_opencode ? discoverOpencodeProjectSkills(params.ctx.directory) : Promise.resolve([]),
|
|
154539
|
+
discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
|
|
154261
154540
|
]);
|
|
154262
154541
|
const allDiscoveredSkills = [
|
|
154542
|
+
...discoveredManagedPluginSkills,
|
|
154263
154543
|
...discoveredConfigSourceSkills,
|
|
154264
154544
|
...discoveredOpencodeProjectSkills,
|
|
154265
154545
|
...discoveredProjectSkills,
|
|
@@ -154592,9 +154872,9 @@ async function applyCommandConfig(params) {
|
|
|
154592
154872
|
});
|
|
154593
154873
|
const systemCommands = params.config.command ?? {};
|
|
154594
154874
|
const includeClaudeCommands = params.pluginConfig.claude_code?.commands ?? true;
|
|
154595
|
-
const
|
|
154875
|
+
const discovery2 = resolveSkillDiscoveryConfig(params.pluginConfig);
|
|
154596
154876
|
const externalSkillPlugin = detectExternalSkillPlugin(params.ctx.directory);
|
|
154597
|
-
if (
|
|
154877
|
+
if ((discovery2.project_claude || discovery2.global_claude || discovery2.global_opencode) && externalSkillPlugin.detected) {
|
|
154598
154878
|
log(getSkillPluginConflictWarning(externalSkillPlugin.pluginName));
|
|
154599
154879
|
}
|
|
154600
154880
|
const [
|
|
@@ -154603,6 +154883,7 @@ async function applyCommandConfig(params) {
|
|
|
154603
154883
|
projectCommands,
|
|
154604
154884
|
opencodeGlobalCommands,
|
|
154605
154885
|
opencodeProjectCommands,
|
|
154886
|
+
managedPluginSkills,
|
|
154606
154887
|
userSkills,
|
|
154607
154888
|
globalAgentsSkills,
|
|
154608
154889
|
projectSkills,
|
|
@@ -154610,23 +154891,25 @@ async function applyCommandConfig(params) {
|
|
|
154610
154891
|
opencodeGlobalSkills,
|
|
154611
154892
|
opencodeProjectSkills
|
|
154612
154893
|
] = await Promise.all([
|
|
154613
|
-
discoverConfigSourceSkills({
|
|
154894
|
+
discovery2.config_sources ? discoverConfigSourceSkills({
|
|
154614
154895
|
config: params.pluginConfig.skills,
|
|
154615
154896
|
configDir: params.ctx.directory
|
|
154616
|
-
}),
|
|
154897
|
+
}) : Promise.resolve([]),
|
|
154617
154898
|
includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
|
|
154618
154899
|
includeClaudeCommands ? loadProjectCommands(params.ctx.directory) : Promise.resolve({}),
|
|
154619
154900
|
loadOpencodeGlobalCommands(),
|
|
154620
154901
|
loadOpencodeProjectCommands(params.ctx.directory),
|
|
154621
|
-
|
|
154622
|
-
|
|
154623
|
-
|
|
154624
|
-
|
|
154625
|
-
|
|
154626
|
-
|
|
154902
|
+
loadManagedPluginSkills(),
|
|
154903
|
+
discovery2.global_claude ? loadUserSkills() : Promise.resolve({}),
|
|
154904
|
+
discovery2.global_agents ? loadGlobalAgentsSkills() : Promise.resolve({}),
|
|
154905
|
+
discovery2.project_claude ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
|
|
154906
|
+
discovery2.project_agents ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
|
|
154907
|
+
discovery2.global_opencode ? loadOpencodeGlobalSkills() : Promise.resolve({}),
|
|
154908
|
+
discovery2.project_opencode ? loadOpencodeProjectSkills(params.ctx.directory) : Promise.resolve({})
|
|
154627
154909
|
]);
|
|
154628
154910
|
params.config.command = {
|
|
154629
154911
|
...builtinCommands,
|
|
154912
|
+
...managedPluginSkills,
|
|
154630
154913
|
...skillsToCommandDefinitionRecord(configSourceSkills),
|
|
154631
154914
|
...userCommands,
|
|
154632
154915
|
...userSkills,
|
|
@@ -154654,7 +154937,7 @@ function remapCommandAgentFields(commands2) {
|
|
|
154654
154937
|
|
|
154655
154938
|
// src/plugin-handlers/mcp-config-handler.ts
|
|
154656
154939
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
154657
|
-
import { existsSync as
|
|
154940
|
+
import { existsSync as existsSync87 } from "fs";
|
|
154658
154941
|
|
|
154659
154942
|
// src/mcp/websearch.ts
|
|
154660
154943
|
init_logger();
|
|
@@ -154807,7 +155090,7 @@ function hasUsableLocalMcpRuntime(name, entry) {
|
|
|
154807
155090
|
return false;
|
|
154808
155091
|
}
|
|
154809
155092
|
if (binary2 === "node" && typeof args[0] === "string" && args[0].endsWith(".mjs")) {
|
|
154810
|
-
if (!
|
|
155093
|
+
if (!existsSync87(args[0])) {
|
|
154811
155094
|
return false;
|
|
154812
155095
|
}
|
|
154813
155096
|
const probe2 = spawnSync5(binary2, ["--version"], {
|
|
@@ -155126,6 +155409,8 @@ function applyToolConfig(params) {
|
|
|
155126
155409
|
function buildLspConfig(lsp) {
|
|
155127
155410
|
const result = {};
|
|
155128
155411
|
for (const [name, server] of Object.entries(lsp)) {
|
|
155412
|
+
if (server.enabled === false)
|
|
155413
|
+
continue;
|
|
155129
155414
|
result[name] = {
|
|
155130
155415
|
command: server.command,
|
|
155131
155416
|
extensions: server.extensions,
|
|
@@ -155281,19 +155566,30 @@ async function createSkillContext(args) {
|
|
|
155281
155566
|
}
|
|
155282
155567
|
return true;
|
|
155283
155568
|
});
|
|
155284
|
-
const
|
|
155285
|
-
const [
|
|
155286
|
-
|
|
155569
|
+
const discovery2 = resolveSkillDiscoveryConfig(pluginConfig);
|
|
155570
|
+
const [
|
|
155571
|
+
managedPluginSkills,
|
|
155572
|
+
configSourceSkills,
|
|
155573
|
+
userSkills,
|
|
155574
|
+
globalSkills,
|
|
155575
|
+
projectSkills,
|
|
155576
|
+
opencodeProjectSkills,
|
|
155577
|
+
agentsProjectSkills,
|
|
155578
|
+
agentsGlobalSkills
|
|
155579
|
+
] = await Promise.all([
|
|
155580
|
+
discoverManagedPluginSkills(),
|
|
155581
|
+
discovery2.config_sources ? discoverConfigSourceSkills({
|
|
155287
155582
|
config: pluginConfig.skills,
|
|
155288
155583
|
configDir: directory
|
|
155289
|
-
}),
|
|
155290
|
-
|
|
155291
|
-
discoverOpencodeGlobalSkills(),
|
|
155292
|
-
|
|
155293
|
-
discoverOpencodeProjectSkills(directory),
|
|
155294
|
-
discoverProjectAgentsSkills(directory),
|
|
155295
|
-
discoverGlobalAgentsSkills()
|
|
155584
|
+
}) : Promise.resolve([]),
|
|
155585
|
+
discovery2.global_claude ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
155586
|
+
discovery2.global_opencode ? discoverOpencodeGlobalSkills() : Promise.resolve([]),
|
|
155587
|
+
discovery2.project_claude ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
|
|
155588
|
+
discovery2.project_opencode ? discoverOpencodeProjectSkills(directory) : Promise.resolve([]),
|
|
155589
|
+
discovery2.project_agents ? discoverProjectAgentsSkills(directory) : Promise.resolve([]),
|
|
155590
|
+
discovery2.global_agents ? discoverGlobalAgentsSkills() : Promise.resolve([])
|
|
155296
155591
|
]);
|
|
155592
|
+
const filteredManagedPluginSkills = filterProviderGatedSkills(managedPluginSkills, browserProvider);
|
|
155297
155593
|
const filteredConfigSourceSkills = filterProviderGatedSkills(configSourceSkills, browserProvider);
|
|
155298
155594
|
const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
|
|
155299
155595
|
const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
|
|
@@ -155301,7 +155597,7 @@ async function createSkillContext(args) {
|
|
|
155301
155597
|
const filteredOpencodeProjectSkills = filterProviderGatedSkills(opencodeProjectSkills, browserProvider);
|
|
155302
155598
|
const filteredAgentsProjectSkills = filterProviderGatedSkills(agentsProjectSkills, browserProvider);
|
|
155303
155599
|
const filteredAgentsGlobalSkills = filterProviderGatedSkills(agentsGlobalSkills, browserProvider);
|
|
155304
|
-
const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, filteredConfigSourceSkills, [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
|
|
155600
|
+
const mergedSkills = mergeSkills(builtinSkills, pluginConfig.skills, [...filteredManagedPluginSkills, ...filteredConfigSourceSkills], [...filteredUserSkills, ...filteredAgentsGlobalSkills], filteredGlobalSkills, [...filteredProjectSkills, ...filteredAgentsProjectSkills], filteredOpencodeProjectSkills, { configDir: directory });
|
|
155305
155601
|
const availableSkills = mergedSkills.map((skill2) => ({
|
|
155306
155602
|
name: skill2.name,
|
|
155307
155603
|
description: skill2.definition.description ?? "",
|
|
@@ -155408,6 +155704,7 @@ function createToolRegistry(args) {
|
|
|
155408
155704
|
managers,
|
|
155409
155705
|
skillContext,
|
|
155410
155706
|
availableCategories,
|
|
155707
|
+
builtinMcp,
|
|
155411
155708
|
interactiveBashEnabled = isInteractiveBashEnabled(),
|
|
155412
155709
|
toolFactories
|
|
155413
155710
|
} = args;
|
|
@@ -155455,7 +155752,8 @@ function createToolRegistry(args) {
|
|
|
155455
155752
|
const skillMcpTool = factories.createSkillMcpTool({
|
|
155456
155753
|
manager: managers.skillMcpManager,
|
|
155457
155754
|
getLoadedSkills: () => skillContext.mergedSkills,
|
|
155458
|
-
getSessionID: getSessionIDForMcp
|
|
155755
|
+
getSessionID: getSessionIDForMcp,
|
|
155756
|
+
builtinMcp
|
|
155459
155757
|
});
|
|
155460
155758
|
const commands2 = factories.discoverCommandsSync(ctx.directory, {
|
|
155461
155759
|
pluginsEnabled: pluginConfig.claude_code?.plugins ?? true,
|
|
@@ -155511,7 +155809,7 @@ function createToolRegistry(args) {
|
|
|
155511
155809
|
|
|
155512
155810
|
// src/create-tools.ts
|
|
155513
155811
|
async function createTools(args) {
|
|
155514
|
-
const { ctx, pluginConfig, managers } = args;
|
|
155812
|
+
const { ctx, pluginConfig, platformConfig, managers } = args;
|
|
155515
155813
|
const skillContext = await createSkillContext({
|
|
155516
155814
|
directory: ctx.directory,
|
|
155517
155815
|
pluginConfig
|
|
@@ -155522,7 +155820,8 @@ async function createTools(args) {
|
|
|
155522
155820
|
pluginConfig,
|
|
155523
155821
|
managers,
|
|
155524
155822
|
skillContext,
|
|
155525
|
-
availableCategories
|
|
155823
|
+
availableCategories,
|
|
155824
|
+
builtinMcp: platformConfig?.mcp
|
|
155526
155825
|
});
|
|
155527
155826
|
return {
|
|
155528
155827
|
filteredTools,
|
|
@@ -155792,7 +156091,7 @@ init_agent_display_names();
|
|
|
155792
156091
|
// src/plugin/ultrawork-db-model-override.ts
|
|
155793
156092
|
import { Database } from "bun:sqlite";
|
|
155794
156093
|
import { join as join97 } from "path";
|
|
155795
|
-
import { existsSync as
|
|
156094
|
+
import { existsSync as existsSync88 } from "fs";
|
|
155796
156095
|
function getDbPath() {
|
|
155797
156096
|
return join97(getDataDir(), "opencode", "opencode.db");
|
|
155798
156097
|
}
|
|
@@ -155871,7 +156170,7 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
|
|
|
155871
156170
|
function scheduleDeferredModelOverride(messageId, targetModel, variant) {
|
|
155872
156171
|
queueMicrotask(() => {
|
|
155873
156172
|
const dbPath = getDbPath();
|
|
155874
|
-
if (!
|
|
156173
|
+
if (!existsSync88(dbPath)) {
|
|
155875
156174
|
log("[ultrawork-db-override] DB not found, skipping deferred override");
|
|
155876
156175
|
return;
|
|
155877
156176
|
}
|
|
@@ -157213,6 +157512,64 @@ function createFirstMessageVariantGate() {
|
|
|
157213
157512
|
// src/index.ts
|
|
157214
157513
|
init_plugin_identity();
|
|
157215
157514
|
|
|
157515
|
+
// src/shared/startup-diagnostics.ts
|
|
157516
|
+
import { existsSync as existsSync89, readFileSync as readFileSync60 } from "fs";
|
|
157517
|
+
import { join as join98 } from "path";
|
|
157518
|
+
init_plugin_identity();
|
|
157519
|
+
function readPlugins(configPath) {
|
|
157520
|
+
if (!existsSync89(configPath))
|
|
157521
|
+
return [];
|
|
157522
|
+
try {
|
|
157523
|
+
const content = readFileSync60(configPath, "utf-8");
|
|
157524
|
+
const parsed = parseJsoncSafe(content);
|
|
157525
|
+
return (parsed.data?.plugin ?? []).map((entry) => typeof entry === "string" ? entry : Array.isArray(entry) ? entry[0] : "").filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
157526
|
+
} catch {
|
|
157527
|
+
return [];
|
|
157528
|
+
}
|
|
157529
|
+
}
|
|
157530
|
+
function warnIfListPluginEntry(directory) {
|
|
157531
|
+
const globalPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
157532
|
+
const candidates = [
|
|
157533
|
+
join98(directory, ".opencode", "opencode.json"),
|
|
157534
|
+
join98(directory, ".opencode", "opencode.jsonc"),
|
|
157535
|
+
globalPaths.configJson,
|
|
157536
|
+
globalPaths.configJsonc
|
|
157537
|
+
];
|
|
157538
|
+
for (const configPath of candidates) {
|
|
157539
|
+
const plugins = readPlugins(configPath);
|
|
157540
|
+
if (!plugins.includes("list"))
|
|
157541
|
+
continue;
|
|
157542
|
+
console.warn(`[hiai-opencode] WARNING: ${configPath} contains plugin: ["list"].`);
|
|
157543
|
+
console.warn("[hiai-opencode] This can prevent hiai-opencode MCP servers from loading from that config scope.");
|
|
157544
|
+
console.warn(`[hiai-opencode] Update it to: plugin: ["${PLUGIN_NAME}"]`);
|
|
157545
|
+
}
|
|
157546
|
+
}
|
|
157547
|
+
function hasConfigAuthFallback(pluginConfig, envName) {
|
|
157548
|
+
if (envName === "FIRECRAWL_API_KEY")
|
|
157549
|
+
return !!pluginConfig.auth?.firecrawl?.trim();
|
|
157550
|
+
if (envName === "STITCH_AI_API_KEY")
|
|
157551
|
+
return !!pluginConfig.auth?.stitch?.trim();
|
|
157552
|
+
if (envName === "CONTEXT7_API_KEY")
|
|
157553
|
+
return !!pluginConfig.auth?.context7?.trim();
|
|
157554
|
+
return false;
|
|
157555
|
+
}
|
|
157556
|
+
function warnMissingRequiredMcpEnv(args) {
|
|
157557
|
+
const disabled = new Set(args.pluginConfig.disabled_mcps ?? []);
|
|
157558
|
+
const mcpConfig = args.platformConfig.mcp ?? {};
|
|
157559
|
+
for (const [name, entry] of Object.entries(HIAI_MCP_REGISTRY)) {
|
|
157560
|
+
if (disabled.has(name))
|
|
157561
|
+
continue;
|
|
157562
|
+
if (mcpConfig[name]?.enabled === false)
|
|
157563
|
+
continue;
|
|
157564
|
+
if (!entry.requiredEnv || entry.requiredEnv.length === 0)
|
|
157565
|
+
continue;
|
|
157566
|
+
const missing = entry.requiredEnv.filter((envName) => !process.env[envName]?.trim() && !hasConfigAuthFallback(args.pluginConfig, envName));
|
|
157567
|
+
if (missing.length === 0)
|
|
157568
|
+
continue;
|
|
157569
|
+
console.warn(`[hiai-opencode] MCP "${name}" is enabled but missing required env: ${missing.join(", ")}.` + " The plugin will continue to load; set the key or disable this MCP in hiai-opencode.json.");
|
|
157570
|
+
}
|
|
157571
|
+
}
|
|
157572
|
+
|
|
157216
157573
|
// src/internals/plugins/subtask2/core/state.ts
|
|
157217
157574
|
var configs = {};
|
|
157218
157575
|
var pluginConfig = { replace_generic: true };
|
|
@@ -157528,7 +157885,7 @@ function resolveResultReferences(text, sessionID) {
|
|
|
157528
157885
|
|
|
157529
157886
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157530
157887
|
import { mkdirSync as mkdirSync18 } from "fs";
|
|
157531
|
-
import { dirname as
|
|
157888
|
+
import { dirname as dirname30, join as join99 } from "path";
|
|
157532
157889
|
|
|
157533
157890
|
// src/internals/plugins/subtask2/utils/prompts.ts
|
|
157534
157891
|
var DEFAULT_RETURN_PROMPT = "Review, challenge and verify the task tool output above against the codebase. Then validate or revise it, before continuing with the next logical step.";
|
|
@@ -157594,15 +157951,15 @@ async function getAutoWorkflowPrompt() {
|
|
|
157594
157951
|
var AUTO_WORKFLOW_PROMPT = AUTO_WORKFLOW_PROMPT_TEMPLATE.replace(README_PLACEHOLDER, "[Use getAutoWorkflowPrompt() to get full documentation]");
|
|
157595
157952
|
|
|
157596
157953
|
// src/internals/plugins/subtask2/utils/config.ts
|
|
157597
|
-
var CONFIG_PATH =
|
|
157954
|
+
var CONFIG_PATH = join99(getOpenCodeConfigDir({ binary: "opencode" }), "subtask2.jsonc");
|
|
157598
157955
|
var cachedReadmeContent = null;
|
|
157599
157956
|
async function loadReadmeContent() {
|
|
157600
157957
|
if (cachedReadmeContent !== null) {
|
|
157601
157958
|
return cachedReadmeContent;
|
|
157602
157959
|
}
|
|
157603
157960
|
try {
|
|
157604
|
-
const pluginRoot =
|
|
157605
|
-
const readmePath =
|
|
157961
|
+
const pluginRoot = join99(dirname30(import.meta.path), "..", "..");
|
|
157962
|
+
const readmePath = join99(pluginRoot, "README.md");
|
|
157606
157963
|
const file3 = Bun.file(readmePath);
|
|
157607
157964
|
if (await file3.exists()) {
|
|
157608
157965
|
cachedReadmeContent = await file3.text();
|
|
@@ -157637,7 +157994,7 @@ async function loadConfig2() {
|
|
|
157637
157994
|
}
|
|
157638
157995
|
}
|
|
157639
157996
|
} catch {}
|
|
157640
|
-
mkdirSync18(
|
|
157997
|
+
mkdirSync18(dirname30(CONFIG_PATH), { recursive: true });
|
|
157641
157998
|
await Bun.write(CONFIG_PATH, `{
|
|
157642
157999
|
// Replace OpenCode's generic "Summarize..." prompt when no return is specified
|
|
157643
158000
|
"replace_generic": true,
|
|
@@ -157709,7 +158066,7 @@ function clearLog() {
|
|
|
157709
158066
|
}
|
|
157710
158067
|
|
|
157711
158068
|
// src/internals/plugins/subtask2/commands/manifest.ts
|
|
157712
|
-
import { join as
|
|
158069
|
+
import { join as join101 } from "path";
|
|
157713
158070
|
|
|
157714
158071
|
// src/internals/plugins/subtask2/parsing/frontmatter.ts
|
|
157715
158072
|
var import_yaml = __toESM(require_dist2(), 1);
|
|
@@ -157965,8 +158322,8 @@ function parseAutoWorkflowOutput(text) {
|
|
|
157965
158322
|
async function buildManifest() {
|
|
157966
158323
|
const manifest = {};
|
|
157967
158324
|
const dirs = [
|
|
157968
|
-
|
|
157969
|
-
|
|
158325
|
+
join101(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
158326
|
+
join101(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
157970
158327
|
];
|
|
157971
158328
|
for (const dir of dirs) {
|
|
157972
158329
|
try {
|
|
@@ -158129,11 +158486,11 @@ async function resolveTurnReferences(text, sessionID) {
|
|
|
158129
158486
|
}
|
|
158130
158487
|
|
|
158131
158488
|
// src/internals/plugins/subtask2/commands/loader.ts
|
|
158132
|
-
import { join as
|
|
158489
|
+
import { join as join102 } from "path";
|
|
158133
158490
|
async function loadCommandFile(name) {
|
|
158134
158491
|
const dirs = [
|
|
158135
|
-
|
|
158136
|
-
|
|
158492
|
+
join102(getOpenCodeConfigDir({ binary: "opencode" }), "command"),
|
|
158493
|
+
join102(Bun.env.PWD ?? ".", ".opencode", "command")
|
|
158137
158494
|
];
|
|
158138
158495
|
for (const dir of dirs) {
|
|
158139
158496
|
const directPath = `${dir}/${name}.md`;
|
|
@@ -159413,14 +159770,14 @@ init_websearch_cited();
|
|
|
159413
159770
|
// src/features/builtin-skills/materialize.ts
|
|
159414
159771
|
import {
|
|
159415
159772
|
cpSync,
|
|
159416
|
-
existsSync as
|
|
159773
|
+
existsSync as existsSync91,
|
|
159417
159774
|
mkdirSync as mkdirSync20,
|
|
159418
159775
|
readdirSync as readdirSync26,
|
|
159419
|
-
readFileSync as
|
|
159776
|
+
readFileSync as readFileSync61,
|
|
159420
159777
|
rmSync as rmSync4,
|
|
159421
159778
|
writeFileSync as writeFileSync22
|
|
159422
159779
|
} from "fs";
|
|
159423
|
-
import { join as
|
|
159780
|
+
import { join as join103 } from "path";
|
|
159424
159781
|
var GENERATED_MARKER = "<!-- Generated by hiai-opencode builtin skill materializer. -->";
|
|
159425
159782
|
var MANAGED_SKILL_METADATA = ".hiai-skill.json";
|
|
159426
159783
|
var LEGACY_MANAGED_DIR_MARKER = ".hiai-plugin-skill";
|
|
@@ -159447,10 +159804,10 @@ function buildSkillFrontmatter(skill2) {
|
|
|
159447
159804
|
`);
|
|
159448
159805
|
}
|
|
159449
159806
|
function shouldWriteSkillFile(skillFilePath) {
|
|
159450
|
-
if (!
|
|
159807
|
+
if (!existsSync91(skillFilePath))
|
|
159451
159808
|
return true;
|
|
159452
159809
|
try {
|
|
159453
|
-
const existing =
|
|
159810
|
+
const existing = readFileSync61(skillFilePath, "utf-8");
|
|
159454
159811
|
return existing.includes(GENERATED_MARKER);
|
|
159455
159812
|
} catch {
|
|
159456
159813
|
return false;
|
|
@@ -159458,10 +159815,10 @@ function shouldWriteSkillFile(skillFilePath) {
|
|
|
159458
159815
|
}
|
|
159459
159816
|
function getSkillLayout() {
|
|
159460
159817
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
159461
|
-
const assembledSkillsDir =
|
|
159462
|
-
const sourceRootDir =
|
|
159463
|
-
const builtinSourceDir =
|
|
159464
|
-
const pluginSourceDir =
|
|
159818
|
+
const assembledSkillsDir = join103(configDir, "skills");
|
|
159819
|
+
const sourceRootDir = join103(configDir, ".hiai", "skills");
|
|
159820
|
+
const builtinSourceDir = join103(sourceRootDir, "builtin");
|
|
159821
|
+
const pluginSourceDir = join103(sourceRootDir, "plugin");
|
|
159465
159822
|
mkdirSync20(assembledSkillsDir, { recursive: true });
|
|
159466
159823
|
mkdirSync20(builtinSourceDir, { recursive: true });
|
|
159467
159824
|
mkdirSync20(pluginSourceDir, { recursive: true });
|
|
@@ -159474,31 +159831,31 @@ function getSkillLayout() {
|
|
|
159474
159831
|
};
|
|
159475
159832
|
}
|
|
159476
159833
|
function writeManagedSkillMetadata(targetDir, metadata) {
|
|
159477
|
-
writeFileSync22(
|
|
159834
|
+
writeFileSync22(join103(targetDir, MANAGED_SKILL_METADATA), `${JSON.stringify(metadata, null, 2)}
|
|
159478
159835
|
`, "utf-8");
|
|
159479
159836
|
}
|
|
159480
159837
|
function readManagedSkillMetadata(targetDir) {
|
|
159481
|
-
const metadataPath =
|
|
159482
|
-
if (!
|
|
159838
|
+
const metadataPath = join103(targetDir, MANAGED_SKILL_METADATA);
|
|
159839
|
+
if (!existsSync91(metadataPath)) {
|
|
159483
159840
|
return null;
|
|
159484
159841
|
}
|
|
159485
159842
|
try {
|
|
159486
|
-
return JSON.parse(
|
|
159843
|
+
return JSON.parse(readFileSync61(metadataPath, "utf-8"));
|
|
159487
159844
|
} catch {
|
|
159488
159845
|
return null;
|
|
159489
159846
|
}
|
|
159490
159847
|
}
|
|
159491
159848
|
function isLegacyManagedSkillDir(targetDir, origin) {
|
|
159492
|
-
if (origin === "plugin" &&
|
|
159849
|
+
if (origin === "plugin" && existsSync91(join103(targetDir, LEGACY_MANAGED_DIR_MARKER))) {
|
|
159493
159850
|
return true;
|
|
159494
159851
|
}
|
|
159495
159852
|
if (origin === "builtin") {
|
|
159496
|
-
const skillFilePath =
|
|
159497
|
-
if (!
|
|
159853
|
+
const skillFilePath = join103(targetDir, "SKILL.md");
|
|
159854
|
+
if (!existsSync91(skillFilePath)) {
|
|
159498
159855
|
return false;
|
|
159499
159856
|
}
|
|
159500
159857
|
try {
|
|
159501
|
-
return
|
|
159858
|
+
return readFileSync61(skillFilePath, "utf-8").includes(GENERATED_MARKER);
|
|
159502
159859
|
} catch {
|
|
159503
159860
|
return false;
|
|
159504
159861
|
}
|
|
@@ -159506,7 +159863,7 @@ function isLegacyManagedSkillDir(targetDir, origin) {
|
|
|
159506
159863
|
return false;
|
|
159507
159864
|
}
|
|
159508
159865
|
function shouldSyncManagedSkillDir(targetDir, origin) {
|
|
159509
|
-
if (!
|
|
159866
|
+
if (!existsSync91(targetDir))
|
|
159510
159867
|
return true;
|
|
159511
159868
|
const metadata = readManagedSkillMetadata(targetDir);
|
|
159512
159869
|
if (metadata?.generatedBy === "hiai-opencode" && metadata.origin === origin) {
|
|
@@ -159522,7 +159879,7 @@ function shouldCleanupManagedSkillDir(targetDir, origin) {
|
|
|
159522
159879
|
return isLegacyManagedSkillDir(targetDir, origin);
|
|
159523
159880
|
}
|
|
159524
159881
|
function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
159525
|
-
if (!
|
|
159882
|
+
if (!existsSync91(rootDir)) {
|
|
159526
159883
|
return;
|
|
159527
159884
|
}
|
|
159528
159885
|
for (const entry of readdirSync26(rootDir, { withFileTypes: true })) {
|
|
@@ -159530,15 +159887,15 @@ function cleanupRemovedManagedSkillDirs(rootDir, origin, expectedSkillNames) {
|
|
|
159530
159887
|
continue;
|
|
159531
159888
|
if (expectedSkillNames.has(entry.name))
|
|
159532
159889
|
continue;
|
|
159533
|
-
const targetDir =
|
|
159890
|
+
const targetDir = join103(rootDir, entry.name);
|
|
159534
159891
|
if (shouldCleanupManagedSkillDir(targetDir, origin)) {
|
|
159535
159892
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
159536
159893
|
}
|
|
159537
159894
|
}
|
|
159538
159895
|
}
|
|
159539
159896
|
function writeSkillRegistry(configDir, entries) {
|
|
159540
|
-
const registryDir =
|
|
159541
|
-
const assembledSkillsDir =
|
|
159897
|
+
const registryDir = join103(configDir, ".hiai");
|
|
159898
|
+
const assembledSkillsDir = join103(configDir, "skills");
|
|
159542
159899
|
mkdirSync20(registryDir, { recursive: true });
|
|
159543
159900
|
mkdirSync20(assembledSkillsDir, { recursive: true });
|
|
159544
159901
|
const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
|
|
@@ -159552,12 +159909,12 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159552
159909
|
},
|
|
159553
159910
|
layout: {
|
|
159554
159911
|
assembledSkillsDir,
|
|
159555
|
-
builtinSourceDir:
|
|
159556
|
-
pluginSourceDir:
|
|
159912
|
+
builtinSourceDir: join103(registryDir, "skills", "builtin"),
|
|
159913
|
+
pluginSourceDir: join103(registryDir, "skills", "plugin")
|
|
159557
159914
|
},
|
|
159558
159915
|
entries: sortedEntries
|
|
159559
159916
|
};
|
|
159560
|
-
writeFileSync22(
|
|
159917
|
+
writeFileSync22(join103(registryDir, "skill-registry.json"), `${JSON.stringify(payload, null, 2)}
|
|
159561
159918
|
`, "utf-8");
|
|
159562
159919
|
const readme = [
|
|
159563
159920
|
"# Hiai Skill Layout",
|
|
@@ -159572,16 +159929,16 @@ function writeSkillRegistry(configDir, entries) {
|
|
|
159572
159929
|
""
|
|
159573
159930
|
].join(`
|
|
159574
159931
|
`);
|
|
159575
|
-
writeFileSync22(
|
|
159932
|
+
writeFileSync22(join103(assembledSkillsDir, "README.md"), readme, "utf-8");
|
|
159576
159933
|
}
|
|
159577
159934
|
function materializeBuiltinSkills(skills) {
|
|
159578
159935
|
const { assembledSkillsDir, builtinSourceDir } = getSkillLayout();
|
|
159579
159936
|
const expectedSkillNames = new Set(skills.map((skill2) => skill2.name));
|
|
159580
159937
|
for (const skill2 of skills) {
|
|
159581
|
-
const sourceSkillDir =
|
|
159582
|
-
const sourceSkillFilePath =
|
|
159583
|
-
const assembledSkillDir =
|
|
159584
|
-
const assembledSkillFilePath =
|
|
159938
|
+
const sourceSkillDir = join103(builtinSourceDir, skill2.name);
|
|
159939
|
+
const sourceSkillFilePath = join103(sourceSkillDir, "SKILL.md");
|
|
159940
|
+
const assembledSkillDir = join103(assembledSkillsDir, skill2.name);
|
|
159941
|
+
const assembledSkillFilePath = join103(assembledSkillDir, "SKILL.md");
|
|
159585
159942
|
const content = buildSkillFrontmatter(skill2);
|
|
159586
159943
|
mkdirSync20(sourceSkillDir, { recursive: true });
|
|
159587
159944
|
mkdirSync20(assembledSkillDir, { recursive: true });
|
|
@@ -159609,8 +159966,8 @@ function materializeBuiltinSkills(skills) {
|
|
|
159609
159966
|
cleanupRemovedManagedSkillDirs(assembledSkillsDir, "builtin", expectedSkillNames);
|
|
159610
159967
|
}
|
|
159611
159968
|
function materializePluginSkillDirectories(pluginRootDir) {
|
|
159612
|
-
const sourceSkillsDir =
|
|
159613
|
-
if (!
|
|
159969
|
+
const sourceSkillsDir = join103(pluginRootDir, "skills");
|
|
159970
|
+
if (!existsSync91(sourceSkillsDir)) {
|
|
159614
159971
|
return;
|
|
159615
159972
|
}
|
|
159616
159973
|
const { assembledSkillsDir, pluginSourceDir, configDir } = getSkillLayout();
|
|
@@ -159622,9 +159979,9 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159622
159979
|
if (entry.name === "tmp")
|
|
159623
159980
|
continue;
|
|
159624
159981
|
expectedSkillNames.add(entry.name);
|
|
159625
|
-
const sourceDir =
|
|
159626
|
-
const mirroredSourceDir =
|
|
159627
|
-
const assembledDir =
|
|
159982
|
+
const sourceDir = join103(sourceSkillsDir, entry.name);
|
|
159983
|
+
const mirroredSourceDir = join103(pluginSourceDir, entry.name);
|
|
159984
|
+
const assembledDir = join103(assembledSkillsDir, entry.name);
|
|
159628
159985
|
if (!shouldSyncManagedSkillDir(mirroredSourceDir, "plugin") || !shouldSyncManagedSkillDir(assembledDir, "plugin")) {
|
|
159629
159986
|
continue;
|
|
159630
159987
|
}
|
|
@@ -159658,7 +160015,7 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159658
160015
|
for (const builtinEntry of readdirSync26(assembledSkillsDir, { withFileTypes: true })) {
|
|
159659
160016
|
if (!builtinEntry.isDirectory())
|
|
159660
160017
|
continue;
|
|
159661
|
-
const assembledDir =
|
|
160018
|
+
const assembledDir = join103(assembledSkillsDir, builtinEntry.name);
|
|
159662
160019
|
const metadata = readManagedSkillMetadata(assembledDir);
|
|
159663
160020
|
if (metadata?.generatedBy !== "hiai-opencode" || metadata.origin !== "builtin") {
|
|
159664
160021
|
continue;
|
|
@@ -159675,17 +160032,45 @@ function materializePluginSkillDirectories(pluginRootDir) {
|
|
|
159675
160032
|
|
|
159676
160033
|
// src/index.ts
|
|
159677
160034
|
var activePluginDispose = null;
|
|
160035
|
+
function createWebsearchFallback(config4) {
|
|
160036
|
+
const model = config4.agents?.researcher?.model?.trim();
|
|
160037
|
+
if (!model) {
|
|
160038
|
+
return;
|
|
160039
|
+
}
|
|
160040
|
+
if (model.startsWith("openrouter/")) {
|
|
160041
|
+
return {
|
|
160042
|
+
providerID: OPENROUTER_PROVIDER_ID,
|
|
160043
|
+
model: model.slice("openrouter/".length)
|
|
160044
|
+
};
|
|
160045
|
+
}
|
|
160046
|
+
if (model.startsWith("openai/")) {
|
|
160047
|
+
return {
|
|
160048
|
+
providerID: OPENAI_PROVIDER_ID,
|
|
160049
|
+
model: model.slice("openai/".length)
|
|
160050
|
+
};
|
|
160051
|
+
}
|
|
160052
|
+
if (model.startsWith("google/")) {
|
|
160053
|
+
return {
|
|
160054
|
+
providerID: GOOGLE_PROVIDER_ID,
|
|
160055
|
+
model: model.slice("google/".length)
|
|
160056
|
+
};
|
|
160057
|
+
}
|
|
160058
|
+
return {
|
|
160059
|
+
providerID: OPENROUTER_PROVIDER_ID,
|
|
160060
|
+
model
|
|
160061
|
+
};
|
|
160062
|
+
}
|
|
159678
160063
|
function configureBundledBunPtyLibrary() {
|
|
159679
160064
|
if (process.env.BUN_PTY_LIB?.trim()) {
|
|
159680
160065
|
return;
|
|
159681
160066
|
}
|
|
159682
160067
|
const libraryName = process.platform === "win32" ? "rust_pty.dll" : process.platform === "darwin" ? process.arch === "arm64" ? "librust_pty_arm64.dylib" : "librust_pty.dylib" : process.arch === "arm64" ? "librust_pty_arm64.so" : "librust_pty.so";
|
|
159683
160068
|
const candidates = [
|
|
159684
|
-
|
|
159685
|
-
|
|
159686
|
-
|
|
160069
|
+
join105(import.meta.dirname, "..", "node_modules", "bun-pty", "rust-pty", "target", "release", libraryName),
|
|
160070
|
+
join105(import.meta.dirname, "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName),
|
|
160071
|
+
join105(import.meta.dirname, "..", "..", "..", "bun-pty", "rust-pty", "target", "release", libraryName)
|
|
159687
160072
|
];
|
|
159688
|
-
const resolved = candidates.find((candidate) =>
|
|
160073
|
+
const resolved = candidates.find((candidate) => existsSync93(candidate));
|
|
159689
160074
|
if (resolved) {
|
|
159690
160075
|
process.env.BUN_PTY_LIB = resolved;
|
|
159691
160076
|
}
|
|
@@ -159694,6 +160079,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159694
160079
|
log("[HiaiOpenCodePlugin] ENTRY - plugin loading", {
|
|
159695
160080
|
directory: ctx.directory
|
|
159696
160081
|
});
|
|
160082
|
+
warnIfListPluginEntry(ctx.directory);
|
|
159697
160083
|
const skillPluginCheck = detectExternalSkillPlugin(ctx.directory);
|
|
159698
160084
|
if (skillPluginCheck.detected && skillPluginCheck.pluginName) {
|
|
159699
160085
|
console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName));
|
|
@@ -159702,11 +160088,15 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159702
160088
|
await activePluginDispose?.();
|
|
159703
160089
|
const internalConfig = loadConfig(ctx.directory);
|
|
159704
160090
|
const pluginConfig2 = hydratePluginConfigWithPlatformDefaults(loadPluginConfig(ctx.directory, ctx), internalConfig);
|
|
160091
|
+
warnMissingRequiredMcpEnv({
|
|
160092
|
+
pluginConfig: pluginConfig2,
|
|
160093
|
+
platformConfig: internalConfig
|
|
160094
|
+
});
|
|
159705
160095
|
materializeBuiltinSkills(createBuiltinSkills({
|
|
159706
160096
|
browserProvider: pluginConfig2.browser_automation_engine?.provider ?? "playwright",
|
|
159707
160097
|
disabledSkills: new Set(pluginConfig2.disabled_skills ?? [])
|
|
159708
160098
|
}));
|
|
159709
|
-
materializePluginSkillDirectories(
|
|
160099
|
+
materializePluginSkillDirectories(join105(import.meta.dirname, ".."));
|
|
159710
160100
|
const { initializeModelRequirements: initializeModelRequirements2 } = await Promise.resolve().then(() => (init_model_requirements(), exports_model_requirements));
|
|
159711
160101
|
initializeModelRequirements2(internalConfig);
|
|
159712
160102
|
const { initializeModelHeuristics: initializeModelHeuristics2 } = await Promise.resolve().then(() => (init_model_capability_heuristics(), exports_model_capability_heuristics));
|
|
@@ -159731,6 +160121,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159731
160121
|
const toolsResult = await createTools({
|
|
159732
160122
|
ctx,
|
|
159733
160123
|
pluginConfig: pluginConfig2,
|
|
160124
|
+
platformConfig: internalConfig,
|
|
159734
160125
|
managers
|
|
159735
160126
|
});
|
|
159736
160127
|
const hooks = createHooks({
|
|
@@ -159766,7 +160157,7 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159766
160157
|
} catch (err) {
|
|
159767
160158
|
console.error("[hiai-opencode] PTYPlugin failed to load:", err);
|
|
159768
160159
|
}
|
|
159769
|
-
const websearchResult = await websearch_cited_default(ctx);
|
|
160160
|
+
const websearchResult = await websearch_cited_default(ctx, createWebsearchFallback(internalConfig));
|
|
159770
160161
|
const websearchGoogleResult = await WebsearchCitedGooglePlugin(ctx);
|
|
159771
160162
|
const websearchOpenAIResult = await WebsearchCitedOpenAIPlugin(ctx);
|
|
159772
160163
|
const combinedResult = {
|
|
@@ -159806,30 +160197,25 @@ var HiaiOpenCodePlugin = async (ctx) => {
|
|
|
159806
160197
|
auth: {
|
|
159807
160198
|
provider: "hiai-opencode",
|
|
159808
160199
|
methods: [
|
|
159809
|
-
{ type: "api", label: "Google API key" }
|
|
159810
|
-
{ type: "api", label: "OpenAI API key" },
|
|
159811
|
-
{ type: "api", label: "OpenRouter API key" }
|
|
160200
|
+
{ type: "api", label: "Google Search API key" }
|
|
159812
160201
|
],
|
|
159813
160202
|
loader: async (getAuth) => {
|
|
159814
160203
|
const authData = await getAuth();
|
|
159815
160204
|
const { registerGetAuth: registerGetAuth2, GOOGLE_PROVIDER_ID: GOOGLE_PROVIDER_ID2, OPENAI_PROVIDER_ID: OPENAI_PROVIDER_ID2, OPENROUTER_PROVIDER_ID: OPENROUTER_PROVIDER_ID2 } = await Promise.resolve().then(() => (init_websearch_cited(), exports_websearch_cited));
|
|
159816
|
-
const
|
|
159817
|
-
const fromAuth = authData[label];
|
|
159818
|
-
if (fromAuth)
|
|
159819
|
-
return fromAuth;
|
|
160205
|
+
const getConfiguredKey = (configKey) => {
|
|
159820
160206
|
if (configKey)
|
|
159821
160207
|
return resolveEnvVars(configKey);
|
|
159822
160208
|
return;
|
|
159823
160209
|
};
|
|
159824
|
-
const googleKey =
|
|
159825
|
-
const openaiKey =
|
|
159826
|
-
const openRouterKey =
|
|
160210
|
+
const googleKey = authData["Google Search API key"] || getConfiguredKey(internalConfig.auth?.googleSearch);
|
|
160211
|
+
const openaiKey = getConfiguredKey(internalConfig.auth?.openai);
|
|
160212
|
+
const openRouterKey = getConfiguredKey(internalConfig.auth?.openrouter);
|
|
159827
160213
|
if (googleKey)
|
|
159828
|
-
registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve(googleKey));
|
|
160214
|
+
registerGetAuth2(GOOGLE_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: googleKey }));
|
|
159829
160215
|
if (openaiKey)
|
|
159830
|
-
registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve(openaiKey));
|
|
160216
|
+
registerGetAuth2(OPENAI_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openaiKey }));
|
|
159831
160217
|
if (openRouterKey)
|
|
159832
|
-
registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve(openRouterKey));
|
|
160218
|
+
registerGetAuth2(OPENROUTER_PROVIDER_ID2, () => Promise.resolve({ type: "api", key: openRouterKey }));
|
|
159833
160219
|
return {};
|
|
159834
160220
|
}
|
|
159835
160221
|
},
|