oh-my-opencode 2.12.2 → 2.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.ja.md +32 -7
  2. package/README.ko.md +32 -7
  3. package/README.md +17 -8
  4. package/README.zh-cn.md +32 -7
  5. package/dist/agents/sisyphus-prompt-builder.d.ts +1 -0
  6. package/dist/cli/config-manager.d.ts +9 -0
  7. package/dist/cli/index.js +185 -81
  8. package/dist/features/claude-code-command-loader/loader.d.ts +5 -0
  9. package/dist/features/context-injector/collector.d.ts +11 -0
  10. package/dist/features/context-injector/collector.test.d.ts +1 -0
  11. package/dist/features/context-injector/index.d.ts +3 -0
  12. package/dist/features/context-injector/injector.d.ts +39 -0
  13. package/dist/features/context-injector/injector.test.d.ts +1 -0
  14. package/dist/features/context-injector/types.d.ts +83 -0
  15. package/dist/features/opencode-skill-loader/async-loader.d.ts +6 -0
  16. package/dist/features/opencode-skill-loader/async-loader.test.d.ts +1 -0
  17. package/dist/features/opencode-skill-loader/blocking.d.ts +2 -0
  18. package/dist/features/opencode-skill-loader/blocking.test.d.ts +1 -0
  19. package/dist/features/opencode-skill-loader/discover-worker.d.ts +1 -0
  20. package/dist/features/opencode-skill-loader/loader.d.ts +5 -0
  21. package/dist/features/opencode-skill-loader/types.d.ts +6 -0
  22. package/dist/features/skill-mcp-manager/env-cleaner.d.ts +2 -0
  23. package/dist/features/skill-mcp-manager/env-cleaner.test.d.ts +1 -0
  24. package/dist/features/skill-mcp-manager/manager.d.ts +8 -0
  25. package/dist/hooks/ralph-loop/types.d.ts +1 -0
  26. package/dist/hooks/tool-output-truncator.test.d.ts +1 -0
  27. package/dist/index.js +1143 -444
  28. package/dist/shared/frontmatter.d.ts +2 -0
  29. package/dist/shared/index.d.ts +3 -0
  30. package/dist/shared/opencode-config-dir.d.ts +19 -0
  31. package/dist/shared/opencode-config-dir.test.d.ts +1 -0
  32. package/dist/shared/opencode-version.d.ts +10 -0
  33. package/dist/shared/opencode-version.test.d.ts +1 -0
  34. package/dist/shared/permission-compat.d.ts +12 -0
  35. package/dist/shared/permission-compat.test.d.ts +1 -0
  36. package/dist/tools/index.d.ts +1 -0
  37. package/package.json +3 -3
package/dist/cli/index.js CHANGED
@@ -2657,7 +2657,7 @@ var require_napi = __commonJS((exports, module) => {
2657
2657
  var require_package = __commonJS((exports, module) => {
2658
2658
  module.exports = {
2659
2659
  name: "oh-my-opencode",
2660
- version: "2.12.1",
2660
+ version: "2.12.2",
2661
2661
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2662
2662
  main: "dist/index.js",
2663
2663
  types: "dist/index.d.ts",
@@ -2713,8 +2713,8 @@ var require_package = __commonJS((exports, module) => {
2713
2713
  "@code-yeongyu/comment-checker": "^0.6.1",
2714
2714
  "@modelcontextprotocol/sdk": "^1.25.1",
2715
2715
  "@openauthjs/openauth": "^0.4.3",
2716
- "@opencode-ai/plugin": "^1.0.162",
2717
- "@opencode-ai/sdk": "^1.0.162",
2716
+ "@opencode-ai/plugin": "^1.1.1",
2717
+ "@opencode-ai/sdk": "^1.1.1",
2718
2718
  commander: "^14.0.2",
2719
2719
  hono: "^4.10.4",
2720
2720
  "js-yaml": "^4.1.1",
@@ -3338,9 +3338,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
3338
3338
  var import_picocolors2 = __toESM(require_picocolors(), 1);
3339
3339
 
3340
3340
  // src/cli/config-manager.ts
3341
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync } from "fs";
3342
- import { homedir } from "os";
3343
- import { join as join2 } from "path";
3341
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync } from "fs";
3344
3342
 
3345
3343
  // node_modules/js-yaml/dist/js-yaml.mjs
3346
3344
  /*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
@@ -6007,6 +6005,8 @@ function log(message, data) {
6007
6005
  }
6008
6006
  // src/shared/deep-merge.ts
6009
6007
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
6008
+ // src/shared/dynamic-truncator.ts
6009
+ var ANTHROPIC_ACTUAL_LIMIT = process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : 200000;
6010
6010
  // src/shared/jsonc-parser.ts
6011
6011
  import { existsSync, readFileSync } from "fs";
6012
6012
 
@@ -6875,13 +6875,109 @@ function detectConfigFile(basePath) {
6875
6875
  }
6876
6876
  return { format: "none", path: jsonPath };
6877
6877
  }
6878
+ // src/shared/opencode-config-dir.ts
6879
+ import { existsSync as existsSync2 } from "fs";
6880
+ import { homedir } from "os";
6881
+ import { join as join2 } from "path";
6882
+ var TAURI_APP_IDENTIFIER = "ai.opencode.desktop";
6883
+ var TAURI_APP_IDENTIFIER_DEV = "ai.opencode.desktop.dev";
6884
+ function isDevBuild(version) {
6885
+ if (!version)
6886
+ return false;
6887
+ return version.includes("-dev") || version.includes(".dev");
6888
+ }
6889
+ function getTauriConfigDir(identifier) {
6890
+ const platform = process.platform;
6891
+ switch (platform) {
6892
+ case "darwin":
6893
+ return join2(homedir(), "Library", "Application Support", identifier);
6894
+ case "win32": {
6895
+ const appData = process.env.APPDATA || join2(homedir(), "AppData", "Roaming");
6896
+ return join2(appData, identifier);
6897
+ }
6898
+ case "linux":
6899
+ default: {
6900
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir(), ".config");
6901
+ return join2(xdgConfig, identifier);
6902
+ }
6903
+ }
6904
+ }
6905
+ function getCliConfigDir() {
6906
+ if (process.platform === "win32") {
6907
+ const crossPlatformDir = join2(homedir(), ".config", "opencode");
6908
+ const crossPlatformConfig = join2(crossPlatformDir, "opencode.json");
6909
+ if (existsSync2(crossPlatformConfig)) {
6910
+ return crossPlatformDir;
6911
+ }
6912
+ const appData = process.env.APPDATA || join2(homedir(), "AppData", "Roaming");
6913
+ const appdataDir = join2(appData, "opencode");
6914
+ const appdataConfig = join2(appdataDir, "opencode.json");
6915
+ if (existsSync2(appdataConfig)) {
6916
+ return appdataDir;
6917
+ }
6918
+ return crossPlatformDir;
6919
+ }
6920
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir(), ".config");
6921
+ return join2(xdgConfig, "opencode");
6922
+ }
6923
+ function getOpenCodeConfigDir(options) {
6924
+ const { binary: binary2, version, checkExisting = true } = options;
6925
+ if (binary2 === "opencode") {
6926
+ return getCliConfigDir();
6927
+ }
6928
+ const identifier = isDevBuild(version) ? TAURI_APP_IDENTIFIER_DEV : TAURI_APP_IDENTIFIER;
6929
+ const tauriDir = getTauriConfigDir(identifier);
6930
+ if (checkExisting) {
6931
+ const legacyDir = getCliConfigDir();
6932
+ const legacyConfig = join2(legacyDir, "opencode.json");
6933
+ const legacyConfigC = join2(legacyDir, "opencode.jsonc");
6934
+ if (existsSync2(legacyConfig) || existsSync2(legacyConfigC)) {
6935
+ return legacyDir;
6936
+ }
6937
+ }
6938
+ return tauriDir;
6939
+ }
6940
+ function getOpenCodeConfigPaths(options) {
6941
+ const configDir = getOpenCodeConfigDir(options);
6942
+ return {
6943
+ configDir,
6944
+ configJson: join2(configDir, "opencode.json"),
6945
+ configJsonc: join2(configDir, "opencode.jsonc"),
6946
+ packageJson: join2(configDir, "package.json"),
6947
+ omoConfig: join2(configDir, "oh-my-opencode.json")
6948
+ };
6949
+ }
6950
+ // src/shared/opencode-version.ts
6951
+ var NOT_CACHED = Symbol("NOT_CACHED");
6878
6952
  // src/cli/config-manager.ts
6879
- var OPENCODE_CONFIG_DIR = join2(homedir(), ".config", "opencode");
6880
- var OPENCODE_JSON = join2(OPENCODE_CONFIG_DIR, "opencode.json");
6881
- var OPENCODE_JSONC = join2(OPENCODE_CONFIG_DIR, "opencode.jsonc");
6882
- var OPENCODE_PACKAGE_JSON = join2(OPENCODE_CONFIG_DIR, "package.json");
6883
- var OMO_CONFIG = join2(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
6884
6953
  var OPENCODE_BINARIES = ["opencode", "opencode-desktop"];
6954
+ var configContext = null;
6955
+ function initConfigContext(binary2, version) {
6956
+ const paths = getOpenCodeConfigPaths({ binary: binary2, version });
6957
+ configContext = { binary: binary2, version, paths };
6958
+ }
6959
+ function getConfigContext() {
6960
+ if (!configContext) {
6961
+ const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
6962
+ configContext = { binary: "opencode", version: null, paths };
6963
+ }
6964
+ return configContext;
6965
+ }
6966
+ function getConfigDir() {
6967
+ return getConfigContext().paths.configDir;
6968
+ }
6969
+ function getConfigJson() {
6970
+ return getConfigContext().paths.configJson;
6971
+ }
6972
+ function getConfigJsonc() {
6973
+ return getConfigContext().paths.configJsonc;
6974
+ }
6975
+ function getPackageJson() {
6976
+ return getConfigContext().paths.packageJson;
6977
+ }
6978
+ function getOmoConfig() {
6979
+ return getConfigContext().paths.omoConfig;
6980
+ }
6885
6981
  var CHATGPT_HOTFIX_REPO = "code-yeongyu/opencode-openai-codex-auth#fix/orphaned-function-call-output-with-tools";
6886
6982
  var BUN_INSTALL_TIMEOUT_SECONDS = 60;
6887
6983
  var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
@@ -6924,13 +7020,15 @@ async function fetchLatestVersion(packageName) {
6924
7020
  }
6925
7021
  }
6926
7022
  function detectConfigFormat() {
6927
- if (existsSync2(OPENCODE_JSONC)) {
6928
- return { format: "jsonc", path: OPENCODE_JSONC };
7023
+ const configJsonc = getConfigJsonc();
7024
+ const configJson = getConfigJson();
7025
+ if (existsSync3(configJsonc)) {
7026
+ return { format: "jsonc", path: configJsonc };
6929
7027
  }
6930
- if (existsSync2(OPENCODE_JSON)) {
6931
- return { format: "json", path: OPENCODE_JSON };
7028
+ if (existsSync3(configJson)) {
7029
+ return { format: "json", path: configJson };
6932
7030
  }
6933
- return { format: "none", path: OPENCODE_JSON };
7031
+ return { format: "none", path: configJson };
6934
7032
  }
6935
7033
  function isEmptyOrWhitespace(content) {
6936
7034
  return content.trim().length === 0;
@@ -6958,15 +7056,16 @@ function parseConfigWithError(path2) {
6958
7056
  }
6959
7057
  }
6960
7058
  function ensureConfigDir() {
6961
- if (!existsSync2(OPENCODE_CONFIG_DIR)) {
6962
- mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
7059
+ const configDir = getConfigDir();
7060
+ if (!existsSync3(configDir)) {
7061
+ mkdirSync(configDir, { recursive: true });
6963
7062
  }
6964
7063
  }
6965
7064
  function addPluginToOpenCodeConfig() {
6966
7065
  try {
6967
7066
  ensureConfigDir();
6968
7067
  } catch (err) {
6969
- return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
7068
+ return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
6970
7069
  }
6971
7070
  const { format: format2, path: path2 } = detectConfigFormat();
6972
7071
  const pluginName = "oh-my-opencode";
@@ -7070,44 +7169,45 @@ function writeOmoConfig(installConfig) {
7070
7169
  try {
7071
7170
  ensureConfigDir();
7072
7171
  } catch (err) {
7073
- return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
7172
+ return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
7074
7173
  }
7174
+ const omoConfigPath = getOmoConfig();
7075
7175
  try {
7076
7176
  const newConfig = generateOmoConfig(installConfig);
7077
- if (existsSync2(OMO_CONFIG)) {
7177
+ if (existsSync3(omoConfigPath)) {
7078
7178
  try {
7079
- const stat = statSync(OMO_CONFIG);
7080
- const content = readFileSync2(OMO_CONFIG, "utf-8");
7179
+ const stat = statSync(omoConfigPath);
7180
+ const content = readFileSync2(omoConfigPath, "utf-8");
7081
7181
  if (stat.size === 0 || isEmptyOrWhitespace(content)) {
7082
- writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
7182
+ writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
7083
7183
  `);
7084
- return { success: true, configPath: OMO_CONFIG };
7184
+ return { success: true, configPath: omoConfigPath };
7085
7185
  }
7086
7186
  const existing = parseJsonc(content);
7087
7187
  if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
7088
- writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
7188
+ writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
7089
7189
  `);
7090
- return { success: true, configPath: OMO_CONFIG };
7190
+ return { success: true, configPath: omoConfigPath };
7091
7191
  }
7092
7192
  delete existing.agents;
7093
7193
  const merged = deepMerge(existing, newConfig);
7094
- writeFileSync(OMO_CONFIG, JSON.stringify(merged, null, 2) + `
7194
+ writeFileSync(omoConfigPath, JSON.stringify(merged, null, 2) + `
7095
7195
  `);
7096
7196
  } catch (parseErr) {
7097
7197
  if (parseErr instanceof SyntaxError) {
7098
- writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
7198
+ writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
7099
7199
  `);
7100
- return { success: true, configPath: OMO_CONFIG };
7200
+ return { success: true, configPath: omoConfigPath };
7101
7201
  }
7102
7202
  throw parseErr;
7103
7203
  }
7104
7204
  } else {
7105
- writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
7205
+ writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
7106
7206
  `);
7107
7207
  }
7108
- return { success: true, configPath: OMO_CONFIG };
7208
+ return { success: true, configPath: omoConfigPath };
7109
7209
  } catch (err) {
7110
- return { success: false, configPath: OMO_CONFIG, error: formatErrorWithSuggestion(err, "write oh-my-opencode config") };
7210
+ return { success: false, configPath: omoConfigPath, error: formatErrorWithSuggestion(err, "write oh-my-opencode config") };
7111
7211
  }
7112
7212
  }
7113
7213
  async function findOpenCodeBinaryWithVersion() {
@@ -7120,7 +7220,9 @@ async function findOpenCodeBinaryWithVersion() {
7120
7220
  const output = await new Response(proc.stdout).text();
7121
7221
  await proc.exited;
7122
7222
  if (proc.exitCode === 0) {
7123
- return { binary: binary2, version: output.trim() };
7223
+ const version = output.trim();
7224
+ initConfigContext(binary2, version);
7225
+ return { binary: binary2, version };
7124
7226
  }
7125
7227
  } catch {
7126
7228
  continue;
@@ -7140,7 +7242,7 @@ async function addAuthPlugins(config) {
7140
7242
  try {
7141
7243
  ensureConfigDir();
7142
7244
  } catch (err) {
7143
- return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
7245
+ return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
7144
7246
  }
7145
7247
  const { format: format2, path: path2 } = detectConfigFormat();
7146
7248
  try {
@@ -7178,14 +7280,15 @@ function setupChatGPTHotfix() {
7178
7280
  try {
7179
7281
  ensureConfigDir();
7180
7282
  } catch (err) {
7181
- return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
7283
+ return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
7182
7284
  }
7285
+ const packageJsonPath = getPackageJson();
7183
7286
  try {
7184
7287
  let packageJson = {};
7185
- if (existsSync2(OPENCODE_PACKAGE_JSON)) {
7288
+ if (existsSync3(packageJsonPath)) {
7186
7289
  try {
7187
- const stat = statSync(OPENCODE_PACKAGE_JSON);
7188
- const content = readFileSync2(OPENCODE_PACKAGE_JSON, "utf-8");
7290
+ const stat = statSync(packageJsonPath);
7291
+ const content = readFileSync2(packageJsonPath, "utf-8");
7189
7292
  if (stat.size > 0 && !isEmptyOrWhitespace(content)) {
7190
7293
  packageJson = JSON.parse(content);
7191
7294
  if (typeof packageJson !== "object" || packageJson === null || Array.isArray(packageJson)) {
@@ -7203,11 +7306,11 @@ function setupChatGPTHotfix() {
7203
7306
  const deps = packageJson.dependencies ?? {};
7204
7307
  deps["opencode-openai-codex-auth"] = CHATGPT_HOTFIX_REPO;
7205
7308
  packageJson.dependencies = deps;
7206
- writeFileSync(OPENCODE_PACKAGE_JSON, JSON.stringify(packageJson, null, 2) + `
7309
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + `
7207
7310
  `);
7208
- return { success: true, configPath: OPENCODE_PACKAGE_JSON };
7311
+ return { success: true, configPath: packageJsonPath };
7209
7312
  } catch (err) {
7210
- return { success: false, configPath: OPENCODE_PACKAGE_JSON, error: formatErrorWithSuggestion(err, "setup ChatGPT hotfix in package.json") };
7313
+ return { success: false, configPath: packageJsonPath, error: formatErrorWithSuggestion(err, "setup ChatGPT hotfix in package.json") };
7211
7314
  }
7212
7315
  }
7213
7316
  async function runBunInstall() {
@@ -7217,7 +7320,7 @@ async function runBunInstall() {
7217
7320
  async function runBunInstallWithDetails() {
7218
7321
  try {
7219
7322
  const proc = Bun.spawn(["bun", "install"], {
7220
- cwd: OPENCODE_CONFIG_DIR,
7323
+ cwd: getConfigDir(),
7221
7324
  stdout: "pipe",
7222
7325
  stderr: "pipe"
7223
7326
  });
@@ -7306,7 +7409,7 @@ function addProviderConfig(config) {
7306
7409
  try {
7307
7410
  ensureConfigDir();
7308
7411
  } catch (err) {
7309
- return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
7412
+ return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
7310
7413
  }
7311
7414
  const { format: format2, path: path2 } = detectConfigFormat();
7312
7415
  try {
@@ -7361,15 +7464,16 @@ function detectCurrentConfig() {
7361
7464
  }
7362
7465
  result.hasGemini = plugins.some((p2) => p2.startsWith("opencode-antigravity-auth"));
7363
7466
  result.hasChatGPT = plugins.some((p2) => p2.startsWith("opencode-openai-codex-auth"));
7364
- if (!existsSync2(OMO_CONFIG)) {
7467
+ const omoConfigPath = getOmoConfig();
7468
+ if (!existsSync3(omoConfigPath)) {
7365
7469
  return result;
7366
7470
  }
7367
7471
  try {
7368
- const stat = statSync(OMO_CONFIG);
7472
+ const stat = statSync(omoConfigPath);
7369
7473
  if (stat.size === 0) {
7370
7474
  return result;
7371
7475
  }
7372
- const content = readFileSync2(OMO_CONFIG, "utf-8");
7476
+ const content = readFileSync2(omoConfigPath, "utf-8");
7373
7477
  if (isEmptyOrWhitespace(content)) {
7374
7478
  return result;
7375
7479
  }
@@ -9147,7 +9251,10 @@ async function createOpencodeServer(options) {
9147
9251
  port: 4096,
9148
9252
  timeout: 5000
9149
9253
  }, options ?? {});
9150
- const proc = spawn(`opencode`, [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`], {
9254
+ const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
9255
+ if (options.config?.logLevel)
9256
+ args.push(`--log-level=${options.config.logLevel}`);
9257
+ const proc = spawn(`opencode`, args, {
9151
9258
  signal: options.signal,
9152
9259
  env: {
9153
9260
  ...process.env,
@@ -10078,18 +10185,14 @@ function getOpenCodeCheckDefinition() {
10078
10185
  }
10079
10186
 
10080
10187
  // src/cli/doctor/checks/plugin.ts
10081
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
10082
- import { homedir as homedir4 } from "os";
10083
- import { join as join5 } from "path";
10084
- var OPENCODE_CONFIG_DIR2 = join5(homedir4(), ".config", "opencode");
10085
- var OPENCODE_JSON2 = join5(OPENCODE_CONFIG_DIR2, "opencode.json");
10086
- var OPENCODE_JSONC2 = join5(OPENCODE_CONFIG_DIR2, "opencode.jsonc");
10188
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
10087
10189
  function detectConfigPath() {
10088
- if (existsSync5(OPENCODE_JSONC2)) {
10089
- return { path: OPENCODE_JSONC2, format: "jsonc" };
10190
+ const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
10191
+ if (existsSync6(paths.configJsonc)) {
10192
+ return { path: paths.configJsonc, format: "jsonc" };
10090
10193
  }
10091
- if (existsSync5(OPENCODE_JSON2)) {
10092
- return { path: OPENCODE_JSON2, format: "json" };
10194
+ if (existsSync6(paths.configJson)) {
10195
+ return { path: paths.configJson, format: "json" };
10093
10196
  }
10094
10197
  return null;
10095
10198
  }
@@ -10148,13 +10251,14 @@ function getPluginInfo() {
10148
10251
  async function checkPluginRegistration() {
10149
10252
  const info = getPluginInfo();
10150
10253
  if (!info.configPath) {
10254
+ const expectedPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
10151
10255
  return {
10152
10256
  name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
10153
10257
  status: "fail",
10154
10258
  message: "OpenCode config file not found",
10155
10259
  details: [
10156
10260
  "Run: bunx oh-my-opencode install",
10157
- `Expected: ${OPENCODE_JSON2} or ${OPENCODE_JSONC2}`
10261
+ `Expected: ${expectedPaths.configJson} or ${expectedPaths.configJsonc}`
10158
10262
  ]
10159
10263
  };
10160
10264
  }
@@ -10188,9 +10292,9 @@ function getPluginCheckDefinition() {
10188
10292
  }
10189
10293
 
10190
10294
  // src/cli/doctor/checks/config.ts
10191
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
10192
- import { homedir as homedir5 } from "os";
10193
- import { join as join6 } from "path";
10295
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
10296
+ import { homedir as homedir4 } from "os";
10297
+ import { join as join5 } from "path";
10194
10298
 
10195
10299
  // node_modules/zod/v4/classic/external.js
10196
10300
  var exports_external = {};
@@ -22722,9 +22826,9 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
22722
22826
  ralph_loop: RalphLoopConfigSchema.optional()
22723
22827
  });
22724
22828
  // src/cli/doctor/checks/config.ts
22725
- var USER_CONFIG_DIR2 = join6(homedir5(), ".config", "opencode");
22726
- var USER_CONFIG_BASE = join6(USER_CONFIG_DIR2, `${PACKAGE_NAME2}`);
22727
- var PROJECT_CONFIG_BASE = join6(process.cwd(), ".opencode", PACKAGE_NAME2);
22829
+ var USER_CONFIG_DIR2 = join5(homedir4(), ".config", "opencode");
22830
+ var USER_CONFIG_BASE = join5(USER_CONFIG_DIR2, `${PACKAGE_NAME2}`);
22831
+ var PROJECT_CONFIG_BASE = join5(process.cwd(), ".opencode", PACKAGE_NAME2);
22728
22832
  function findConfigPath() {
22729
22833
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE);
22730
22834
  if (projectDetected.format !== "none") {
@@ -22764,7 +22868,7 @@ function getConfigInfo() {
22764
22868
  errors: []
22765
22869
  };
22766
22870
  }
22767
- if (!existsSync6(configPath.path)) {
22871
+ if (!existsSync7(configPath.path)) {
22768
22872
  return {
22769
22873
  exists: false,
22770
22874
  path: configPath.path,
@@ -22821,20 +22925,20 @@ function getConfigCheckDefinition() {
22821
22925
  }
22822
22926
 
22823
22927
  // src/cli/doctor/checks/auth.ts
22824
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
22825
- import { homedir as homedir6 } from "os";
22826
- import { join as join7 } from "path";
22827
- var OPENCODE_CONFIG_DIR3 = join7(homedir6(), ".config", "opencode");
22828
- var OPENCODE_JSON3 = join7(OPENCODE_CONFIG_DIR3, "opencode.json");
22829
- var OPENCODE_JSONC3 = join7(OPENCODE_CONFIG_DIR3, "opencode.jsonc");
22928
+ import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
22929
+ import { homedir as homedir5 } from "os";
22930
+ import { join as join6 } from "path";
22931
+ var OPENCODE_CONFIG_DIR = join6(homedir5(), ".config", "opencode");
22932
+ var OPENCODE_JSON = join6(OPENCODE_CONFIG_DIR, "opencode.json");
22933
+ var OPENCODE_JSONC = join6(OPENCODE_CONFIG_DIR, "opencode.jsonc");
22830
22934
  var AUTH_PLUGINS = {
22831
22935
  anthropic: { plugin: "builtin", name: "Anthropic (Claude)" },
22832
22936
  openai: { plugin: "opencode-openai-codex-auth", name: "OpenAI (ChatGPT)" },
22833
22937
  google: { plugin: "opencode-antigravity-auth", name: "Google (Gemini)" }
22834
22938
  };
22835
22939
  function getOpenCodeConfig() {
22836
- const configPath = existsSync7(OPENCODE_JSONC3) ? OPENCODE_JSONC3 : OPENCODE_JSON3;
22837
- if (!existsSync7(configPath))
22940
+ const configPath = existsSync8(OPENCODE_JSONC) ? OPENCODE_JSONC : OPENCODE_JSON;
22941
+ if (!existsSync8(configPath))
22838
22942
  return null;
22839
22943
  try {
22840
22944
  const content = readFileSync6(configPath, "utf-8");
@@ -23266,19 +23370,19 @@ function getLspCheckDefinition() {
23266
23370
  }
23267
23371
 
23268
23372
  // src/cli/doctor/checks/mcp.ts
23269
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
23270
- import { homedir as homedir7 } from "os";
23271
- import { join as join8 } from "path";
23373
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
23374
+ import { homedir as homedir6 } from "os";
23375
+ import { join as join7 } from "path";
23272
23376
  var BUILTIN_MCP_SERVERS = ["context7", "websearch_exa", "grep_app"];
23273
23377
  var MCP_CONFIG_PATHS = [
23274
- join8(homedir7(), ".claude", ".mcp.json"),
23275
- join8(process.cwd(), ".mcp.json"),
23276
- join8(process.cwd(), ".claude", ".mcp.json")
23378
+ join7(homedir6(), ".claude", ".mcp.json"),
23379
+ join7(process.cwd(), ".mcp.json"),
23380
+ join7(process.cwd(), ".claude", ".mcp.json")
23277
23381
  ];
23278
23382
  function loadUserMcpConfig() {
23279
23383
  const servers = {};
23280
23384
  for (const configPath of MCP_CONFIG_PATHS) {
23281
- if (!existsSync8(configPath))
23385
+ if (!existsSync9(configPath))
23282
23386
  continue;
23283
23387
  try {
23284
23388
  const content = readFileSync7(configPath, "utf-8");
@@ -3,3 +3,8 @@ export declare function loadUserCommands(): Record<string, CommandDefinition>;
3
3
  export declare function loadProjectCommands(): Record<string, CommandDefinition>;
4
4
  export declare function loadOpencodeGlobalCommands(): Record<string, CommandDefinition>;
5
5
  export declare function loadOpencodeProjectCommands(): Record<string, CommandDefinition>;
6
+ export declare function loadUserCommandsAsync(): Promise<Record<string, CommandDefinition>>;
7
+ export declare function loadProjectCommandsAsync(): Promise<Record<string, CommandDefinition>>;
8
+ export declare function loadOpencodeGlobalCommandsAsync(): Promise<Record<string, CommandDefinition>>;
9
+ export declare function loadOpencodeProjectCommandsAsync(): Promise<Record<string, CommandDefinition>>;
10
+ export declare function loadAllCommandsAsync(): Promise<Record<string, CommandDefinition>>;
@@ -0,0 +1,11 @@
1
+ import type { PendingContext, RegisterContextOptions } from "./types";
2
+ export declare class ContextCollector {
3
+ private sessions;
4
+ register(sessionID: string, options: RegisterContextOptions): void;
5
+ getPending(sessionID: string): PendingContext;
6
+ consume(sessionID: string): PendingContext;
7
+ clear(sessionID: string): void;
8
+ hasPending(sessionID: string): boolean;
9
+ private sortEntries;
10
+ }
11
+ export declare const contextCollector: ContextCollector;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export { ContextCollector, contextCollector } from "./collector";
2
+ export { injectPendingContext, createContextInjectorHook, createContextInjectorMessagesTransformHook, } from "./injector";
3
+ export type { ContextSourceType, ContextPriority, ContextEntry, RegisterContextOptions, PendingContext, MessageContext, OutputParts, InjectionStrategy, } from "./types";
@@ -0,0 +1,39 @@
1
+ import type { ContextCollector } from "./collector";
2
+ import type { Message, Part } from "@opencode-ai/sdk";
3
+ interface OutputPart {
4
+ type: string;
5
+ text?: string;
6
+ [key: string]: unknown;
7
+ }
8
+ interface InjectionResult {
9
+ injected: boolean;
10
+ contextLength: number;
11
+ }
12
+ export declare function injectPendingContext(collector: ContextCollector, sessionID: string, parts: OutputPart[]): InjectionResult;
13
+ interface ChatMessageInput {
14
+ sessionID: string;
15
+ agent?: string;
16
+ model?: {
17
+ providerID: string;
18
+ modelID: string;
19
+ };
20
+ messageID?: string;
21
+ }
22
+ interface ChatMessageOutput {
23
+ message: Record<string, unknown>;
24
+ parts: OutputPart[];
25
+ }
26
+ export declare function createContextInjectorHook(collector: ContextCollector): {
27
+ "chat.message": (_input: ChatMessageInput, _output: ChatMessageOutput) => Promise<void>;
28
+ };
29
+ interface MessageWithParts {
30
+ info: Message;
31
+ parts: Part[];
32
+ }
33
+ type MessagesTransformHook = {
34
+ "experimental.chat.messages.transform"?: (input: Record<string, never>, output: {
35
+ messages: MessageWithParts[];
36
+ }) => Promise<void>;
37
+ };
38
+ export declare function createContextInjectorMessagesTransformHook(collector: ContextCollector): MessagesTransformHook;
39
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Source identifier for context injection
3
+ * Each source registers context that will be merged and injected together
4
+ */
5
+ export type ContextSourceType = "keyword-detector" | "rules-injector" | "directory-agents" | "directory-readme" | "custom";
6
+ /**
7
+ * Priority levels for context ordering
8
+ * Higher priority contexts appear first in the merged output
9
+ */
10
+ export type ContextPriority = "critical" | "high" | "normal" | "low";
11
+ /**
12
+ * A single context entry registered by a source
13
+ */
14
+ export interface ContextEntry {
15
+ /** Unique identifier for this entry within the source */
16
+ id: string;
17
+ /** The source that registered this context */
18
+ source: ContextSourceType;
19
+ /** The actual context content to inject */
20
+ content: string;
21
+ /** Priority for ordering (default: normal) */
22
+ priority: ContextPriority;
23
+ /** Timestamp when registered */
24
+ timestamp: number;
25
+ /** Optional metadata for debugging/logging */
26
+ metadata?: Record<string, unknown>;
27
+ }
28
+ /**
29
+ * Options for registering context
30
+ */
31
+ export interface RegisterContextOptions {
32
+ /** Unique ID for this context entry (used for deduplication) */
33
+ id: string;
34
+ /** Source identifier */
35
+ source: ContextSourceType;
36
+ /** The content to inject */
37
+ content: string;
38
+ /** Priority for ordering (default: normal) */
39
+ priority?: ContextPriority;
40
+ /** Optional metadata */
41
+ metadata?: Record<string, unknown>;
42
+ }
43
+ /**
44
+ * Result of getting pending context for a session
45
+ */
46
+ export interface PendingContext {
47
+ /** Merged context string, ready for injection */
48
+ merged: string;
49
+ /** Individual entries that were merged */
50
+ entries: ContextEntry[];
51
+ /** Whether there's any content to inject */
52
+ hasContent: boolean;
53
+ }
54
+ /**
55
+ * Message context from the original user message
56
+ * Used when injecting to match the message format
57
+ */
58
+ export interface MessageContext {
59
+ agent?: string;
60
+ model?: {
61
+ providerID?: string;
62
+ modelID?: string;
63
+ };
64
+ path?: {
65
+ cwd?: string;
66
+ root?: string;
67
+ };
68
+ tools?: Record<string, boolean>;
69
+ }
70
+ /**
71
+ * Output parts from chat.message hook
72
+ */
73
+ export interface OutputParts {
74
+ parts: Array<{
75
+ type: string;
76
+ text?: string;
77
+ [key: string]: unknown;
78
+ }>;
79
+ }
80
+ /**
81
+ * Injection strategy
82
+ */
83
+ export type InjectionStrategy = "prepend-parts" | "storage" | "auto";
@@ -0,0 +1,6 @@
1
+ import type { SkillScope, LoadedSkill } from "./types";
2
+ import type { SkillMcpConfig } from "../skill-mcp-manager/types";
3
+ export declare function mapWithConcurrency<T, R>(items: T[], mapper: (item: T) => Promise<R>, concurrency: number): Promise<R[]>;
4
+ export declare function loadMcpJsonFromDirAsync(skillDir: string): Promise<SkillMcpConfig | undefined>;
5
+ export declare function loadSkillFromPathAsync(skillPath: string, resolvedPath: string, defaultName: string, scope: SkillScope): Promise<LoadedSkill | null>;
6
+ export declare function discoverSkillsInDirAsync(skillsDir: string): Promise<LoadedSkill[]>;
@@ -0,0 +1,2 @@
1
+ import type { LoadedSkill, SkillScope } from "./types";
2
+ export declare function discoverAllSkillsBlocking(dirs: string[], scopes: SkillScope[]): LoadedSkill[];