evil-omo 3.15.2 → 3.16.0

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 (70) hide show
  1. package/README.ja.md +27 -16
  2. package/README.ko.md +27 -16
  3. package/README.md +1 -1
  4. package/README.ru.md +20 -9
  5. package/README.zh-cn.md +26 -15
  6. package/bin/evil-omo.js +1 -1
  7. package/bin/platform.js +14 -17
  8. package/dist/agents/dynamic-agent-core-sections.d.ts +7 -0
  9. package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
  10. package/dist/agents/hephaestus/gpt-5-4.d.ts +22 -1
  11. package/dist/cli/config-manager/backup-config.d.ts +6 -0
  12. package/dist/cli/config-manager/config-context.d.ts +0 -1
  13. package/dist/cli/config-manager/version-compatibility.d.ts +9 -0
  14. package/dist/cli/config-manager.d.ts +4 -0
  15. package/dist/cli/doctor/constants.d.ts +1 -1
  16. package/dist/cli/index.js +2065 -805
  17. package/dist/cli/minimum-opencode-version.d.ts +1 -0
  18. package/dist/cli/model-fallback-types.d.ts +3 -0
  19. package/dist/cli/run/continuation-state.d.ts +2 -1
  20. package/dist/cli/types.d.ts +1 -0
  21. package/dist/create-managers.d.ts +14 -0
  22. package/dist/create-runtime-tmux-config.d.ts +1 -0
  23. package/dist/features/background-agent/compaction-aware-message-resolver.d.ts +5 -2
  24. package/dist/features/background-agent/spawner.d.ts +3 -0
  25. package/dist/features/boulder-state/storage.d.ts +8 -1
  26. package/dist/features/boulder-state/types.d.ts +1 -0
  27. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +1 -1
  28. package/dist/features/claude-code-mcp-loader/env-expander.d.ts +5 -2
  29. package/dist/features/claude-code-plugin-loader/discovery.d.ts +2 -1
  30. package/dist/features/claude-code-plugin-loader/loader.d.ts +16 -0
  31. package/dist/features/claude-code-plugin-loader/scope-filter.d.ts +2 -0
  32. package/dist/features/claude-code-plugin-loader/types.d.ts +21 -0
  33. package/dist/features/claude-code-session-state/state.d.ts +1 -0
  34. package/dist/features/mcp-oauth/provider.d.ts +1 -0
  35. package/dist/features/mcp-oauth/refresh-mutex.d.ts +26 -0
  36. package/dist/features/skill-mcp-manager/error-redaction.d.ts +10 -0
  37. package/dist/features/skill-mcp-manager/oauth-handler.d.ts +7 -0
  38. package/dist/features/skill-mcp-manager/types.d.ts +3 -1
  39. package/dist/hooks/atlas/background-launch-session-tracking.d.ts +11 -0
  40. package/dist/hooks/atlas/boulder-continuation-injector.d.ts +2 -1
  41. package/dist/hooks/atlas/task-context.d.ts +7 -0
  42. package/dist/hooks/atlas/types.d.ts +2 -0
  43. package/dist/hooks/auto-update-checker/constants.d.ts +5 -5
  44. package/dist/hooks/comment-checker/downloader.d.ts +1 -1
  45. package/dist/hooks/keyword-detector/hook.d.ts +2 -1
  46. package/dist/hooks/ralph-loop/constants.d.ts +1 -0
  47. package/dist/hooks/ralph-loop/oracle-verification-detector.d.ts +8 -0
  48. package/dist/hooks/read-image-resizer/png-fallback-resizer.d.ts +2 -0
  49. package/dist/hooks/runtime-fallback/auto-retry-signal.d.ts +4 -0
  50. package/dist/hooks/runtime-fallback/error-classifier.d.ts +1 -5
  51. package/dist/hooks/session-recovery/types.d.ts +2 -0
  52. package/dist/hooks/todo-continuation-enforcer/pending-question-detection.d.ts +1 -1
  53. package/dist/hooks/todo-continuation-enforcer/token-limit-detection.d.ts +4 -0
  54. package/dist/hooks/todo-continuation-enforcer/types.d.ts +7 -0
  55. package/dist/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
  56. package/dist/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.d.ts +2 -0
  57. package/dist/index.js +7425 -6114
  58. package/dist/plugin/chat-params.d.ts +1 -0
  59. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
  60. package/dist/plugin/tool-registry.d.ts +1 -0
  61. package/dist/shared/agent-display-names.d.ts +10 -2
  62. package/dist/shared/compaction-marker.d.ts +12 -0
  63. package/dist/shared/index.d.ts +1 -0
  64. package/dist/shared/internal-initiator-marker.d.ts +1 -0
  65. package/dist/shared/session-prompt-params-state.d.ts +1 -0
  66. package/dist/shared/system-directive.d.ts +5 -5
  67. package/dist/tools/background-task/constants.d.ts +1 -1
  68. package/dist/tools/delegate-task/resolve-call-id.d.ts +2 -0
  69. package/package.json +16 -18
  70. package/postinstall.mjs +77 -4
package/dist/cli/index.js CHANGED
@@ -4917,6 +4917,196 @@ var init_command_executor = __esm(() => {
4917
4917
  // src/shared/contains-path.ts
4918
4918
  var init_contains_path = () => {};
4919
4919
 
4920
+ // src/shared/logger.ts
4921
+ import * as fs from "fs";
4922
+ import * as os from "os";
4923
+ import * as path from "path";
4924
+ function flush() {
4925
+ if (buffer.length === 0)
4926
+ return;
4927
+ const data = buffer.join("");
4928
+ buffer = [];
4929
+ try {
4930
+ fs.appendFileSync(logFile, data);
4931
+ } catch {}
4932
+ }
4933
+ function scheduleFlush() {
4934
+ if (flushTimer)
4935
+ return;
4936
+ flushTimer = setTimeout(() => {
4937
+ flushTimer = null;
4938
+ flush();
4939
+ }, FLUSH_INTERVAL_MS);
4940
+ }
4941
+ function log(message, data) {
4942
+ try {
4943
+ const timestamp2 = new Date().toISOString();
4944
+ const logEntry = `[${timestamp2}] ${message} ${data ? JSON.stringify(data) : ""}
4945
+ `;
4946
+ buffer.push(logEntry);
4947
+ if (buffer.length >= BUFFER_SIZE_LIMIT) {
4948
+ flush();
4949
+ } else {
4950
+ scheduleFlush();
4951
+ }
4952
+ } catch {}
4953
+ }
4954
+ var logFile, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
4955
+ var init_logger = __esm(() => {
4956
+ logFile = path.join(os.tmpdir(), "evil-omo.log");
4957
+ buffer = [];
4958
+ });
4959
+
4960
+ // src/shared/file-reference-resolver.ts
4961
+ var init_file_reference_resolver = __esm(() => {
4962
+ init_contains_path();
4963
+ init_logger();
4964
+ });
4965
+ // src/shared/deep-merge.ts
4966
+ function isPlainObject(value) {
4967
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
4968
+ }
4969
+ function deepMerge(base, override, depth = 0) {
4970
+ if (!base && !override)
4971
+ return;
4972
+ if (!base)
4973
+ return override;
4974
+ if (!override)
4975
+ return base;
4976
+ if (depth > MAX_DEPTH)
4977
+ return override ?? base;
4978
+ const result = { ...base };
4979
+ for (const key of Object.keys(override)) {
4980
+ if (DANGEROUS_KEYS.has(key))
4981
+ continue;
4982
+ const baseValue = base[key];
4983
+ const overrideValue = override[key];
4984
+ if (overrideValue === undefined)
4985
+ continue;
4986
+ if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
4987
+ result[key] = deepMerge(baseValue, overrideValue, depth + 1);
4988
+ } else {
4989
+ result[key] = overrideValue;
4990
+ }
4991
+ }
4992
+ return result;
4993
+ }
4994
+ var DANGEROUS_KEYS, MAX_DEPTH = 50;
4995
+ var init_deep_merge = __esm(() => {
4996
+ DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
4997
+ });
4998
+
4999
+ // src/shared/snake-case.ts
5000
+ var init_snake_case = __esm(() => {
5001
+ init_deep_merge();
5002
+ });
5003
+
5004
+ // src/shared/tool-name.ts
5005
+ var init_tool_name = () => {};
5006
+
5007
+ // src/shared/pattern-matcher.ts
5008
+ var regexCache;
5009
+ var init_pattern_matcher = __esm(() => {
5010
+ regexCache = new Map;
5011
+ });
5012
+ // src/shared/file-utils.ts
5013
+ import { lstatSync, realpathSync } from "fs";
5014
+ function normalizeDarwinRealpath(filePath) {
5015
+ return filePath.startsWith("/private/var/") ? filePath.slice("/private".length) : filePath;
5016
+ }
5017
+ function resolveSymlink(filePath) {
5018
+ try {
5019
+ return normalizeDarwinRealpath(realpathSync(filePath));
5020
+ } catch {
5021
+ return filePath;
5022
+ }
5023
+ }
5024
+ var init_file_utils = () => {};
5025
+
5026
+ // src/shared/context-limit-resolver.ts
5027
+ var init_context_limit_resolver = () => {};
5028
+
5029
+ // src/shared/normalize-sdk-response.ts
5030
+ function normalizeSDKResponse(response, fallback, options) {
5031
+ if (response === null || response === undefined) {
5032
+ return fallback;
5033
+ }
5034
+ if (Array.isArray(response)) {
5035
+ return response;
5036
+ }
5037
+ if (typeof response === "object" && "data" in response) {
5038
+ const data = response.data;
5039
+ if (data !== null && data !== undefined) {
5040
+ return data;
5041
+ }
5042
+ if (options?.preferResponseOnMissingData === true) {
5043
+ return response;
5044
+ }
5045
+ return fallback;
5046
+ }
5047
+ if (options?.preferResponseOnMissingData === true) {
5048
+ return response;
5049
+ }
5050
+ return fallback;
5051
+ }
5052
+
5053
+ // src/shared/dynamic-truncator.ts
5054
+ var init_dynamic_truncator = __esm(() => {
5055
+ init_context_limit_resolver();
5056
+ });
5057
+
5058
+ // src/shared/data-path.ts
5059
+ import * as path2 from "path";
5060
+ import * as os2 from "os";
5061
+ import { accessSync, constants, mkdirSync } from "fs";
5062
+ function resolveWritableDirectory(preferredDir, fallbackSuffix) {
5063
+ try {
5064
+ mkdirSync(preferredDir, { recursive: true });
5065
+ accessSync(preferredDir, constants.W_OK);
5066
+ return preferredDir;
5067
+ } catch {
5068
+ const fallbackDir = path2.join(os2.tmpdir(), fallbackSuffix);
5069
+ mkdirSync(fallbackDir, { recursive: true });
5070
+ return fallbackDir;
5071
+ }
5072
+ }
5073
+ function getDataDir() {
5074
+ const preferredDir = process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
5075
+ return resolveWritableDirectory(preferredDir, "opencode-data");
5076
+ }
5077
+ function getOpenCodeStorageDir() {
5078
+ return path2.join(getDataDir(), "opencode", "storage");
5079
+ }
5080
+ function getCacheDir() {
5081
+ const preferredDir = process.env.XDG_CACHE_HOME ?? path2.join(os2.homedir(), ".cache");
5082
+ return resolveWritableDirectory(preferredDir, "opencode-cache");
5083
+ }
5084
+ function getOmoOpenCodeCacheDir() {
5085
+ return path2.join(getCacheDir(), "evil-omo");
5086
+ }
5087
+ function getOpenCodeCacheDir() {
5088
+ return path2.join(getCacheDir(), "opencode");
5089
+ }
5090
+ var init_data_path = () => {};
5091
+
5092
+ // src/shared/config-errors.ts
5093
+ function getConfigLoadErrors() {
5094
+ return configLoadErrors;
5095
+ }
5096
+ function clearConfigLoadErrors() {
5097
+ configLoadErrors = [];
5098
+ }
5099
+ function addConfigLoadError(error) {
5100
+ configLoadErrors.push(error);
5101
+ }
5102
+ var configLoadErrors;
5103
+ var init_config_errors = __esm(() => {
5104
+ configLoadErrors = [];
5105
+ });
5106
+
5107
+ // src/shared/claude-config-dir.ts
5108
+ var init_claude_config_dir = () => {};
5109
+
4920
5110
  // node_modules/jsonc-parser/lib/esm/impl/scanner.js
4921
5111
  function createScanner(text, ignoreTrivia = false) {
4922
5112
  const len = text.length;
@@ -5781,11 +5971,37 @@ var init_main = __esm(() => {
5781
5971
  })(ParseErrorCode || (ParseErrorCode = {}));
5782
5972
  });
5783
5973
 
5974
+ // src/shared/plugin-identity.ts
5975
+ import { join as join3 } from "path";
5976
+ function detectManagedConfigFile(directory) {
5977
+ for (const baseName of ALL_CONFIG_BASENAMES) {
5978
+ const detected = detectConfigFile(join3(directory, baseName));
5979
+ if (detected.format !== "none") {
5980
+ return { ...detected, baseName };
5981
+ }
5982
+ }
5983
+ return {
5984
+ format: "none",
5985
+ path: join3(directory, `${CONFIG_BASENAME}.json`),
5986
+ baseName: CONFIG_BASENAME
5987
+ };
5988
+ }
5989
+ var PLUGIN_NAME = "evil-omo", LEGACY_PLUGIN_NAME = "oh-my-opencode", CONFIG_BASENAME = "evil-omo", LEGACY_CONFIG_BASENAME = "oh-my-opencode", ALL_CONFIG_BASENAMES;
5990
+ var init_plugin_identity = __esm(() => {
5991
+ init_jsonc_parser();
5992
+ ALL_CONFIG_BASENAMES = [CONFIG_BASENAME, LEGACY_CONFIG_BASENAME];
5993
+ });
5994
+
5784
5995
  // src/shared/jsonc-parser.ts
5785
5996
  import { existsSync, readFileSync } from "fs";
5997
+ import { join as join4 } from "path";
5998
+ function stripBom(content) {
5999
+ return content.charCodeAt(0) === 65279 ? content.slice(1) : content;
6000
+ }
5786
6001
  function parseJsonc(content) {
6002
+ content = content.replace(/^\uFEFF/, "");
5787
6003
  const errors = [];
5788
- const result = parse2(content, errors, {
6004
+ const result = parse2(stripBom(content), errors, {
5789
6005
  allowTrailingComma: true,
5790
6006
  disallowComments: false
5791
6007
  });
@@ -5806,202 +6022,25 @@ function detectConfigFile(basePath) {
5806
6022
  }
5807
6023
  return { format: "none", path: jsonPath };
5808
6024
  }
5809
- var init_jsonc_parser = __esm(() => {
5810
- init_main();
5811
- init_plugin_identity();
5812
- });
5813
-
5814
- // src/shared/plugin-identity.ts
5815
- import { join } from "path";
5816
- function matchesManagedName(entry, packageName) {
5817
- return entry === packageName || entry.startsWith(`${packageName}@`);
5818
- }
5819
- function findManagedPluginEntry(plugins) {
5820
- for (const [index, entry] of plugins.entries()) {
5821
- for (const packageName of ALL_PLUGIN_NAMES) {
5822
- if (matchesManagedName(entry, packageName)) {
5823
- return { index, packageName };
5824
- }
5825
- }
5826
- }
5827
- return null;
5828
- }
5829
- function detectManagedConfigFile(directory) {
5830
- for (const baseName of ALL_CONFIG_BASENAMES) {
5831
- const detected = detectConfigFile(join(directory, baseName));
5832
- if (detected.format !== "none") {
5833
- return { ...detected, baseName };
5834
- }
5835
- }
5836
- return {
5837
- format: "none",
5838
- path: join(directory, `${CONFIG_BASENAME}.json`),
5839
- baseName: CONFIG_BASENAME
5840
- };
5841
- }
5842
- var PLUGIN_NAME = "evil-omo", LEGACY_PLUGIN_NAME = "oh-my-opencode", ALL_PLUGIN_NAMES, CONFIG_BASENAME = "evil-omo", LEGACY_CONFIG_BASENAME = "oh-my-opencode", ALL_CONFIG_BASENAMES, LOG_FILENAME = "evil-omo.log", CACHE_DIR_NAME = "evil-omo", SCHEMA_FILENAME = "evil-omo.schema.json";
5843
- var init_plugin_identity = __esm(() => {
5844
- init_jsonc_parser();
5845
- ALL_PLUGIN_NAMES = [PLUGIN_NAME, LEGACY_PLUGIN_NAME];
5846
- ALL_CONFIG_BASENAMES = [CONFIG_BASENAME, LEGACY_CONFIG_BASENAME];
5847
- });
5848
-
5849
- // src/shared/logger.ts
5850
- import * as fs from "fs";
5851
- import * as os from "os";
5852
- import * as path from "path";
5853
- function log(message, data) {
5854
- try {
5855
- const timestamp2 = new Date().toISOString();
5856
- const logEntry = `[${timestamp2}] ${message} ${data ? JSON.stringify(data) : ""}
5857
- `;
5858
- fs.appendFileSync(logFile, logEntry);
5859
- } catch {}
5860
- }
5861
- var logFile;
5862
- var init_logger = __esm(() => {
5863
- init_plugin_identity();
5864
- logFile = path.join(os.tmpdir(), LOG_FILENAME);
5865
- });
5866
-
5867
- // src/shared/file-reference-resolver.ts
5868
- var init_file_reference_resolver = __esm(() => {
5869
- init_contains_path();
5870
- init_logger();
5871
- });
5872
- // src/shared/deep-merge.ts
5873
- function isPlainObject(value) {
5874
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
5875
- }
5876
- function deepMerge(base, override, depth = 0) {
5877
- if (!base && !override)
5878
- return;
5879
- if (!base)
5880
- return override;
5881
- if (!override)
5882
- return base;
5883
- if (depth > MAX_DEPTH)
5884
- return override ?? base;
5885
- const result = { ...base };
5886
- for (const key of Object.keys(override)) {
5887
- if (DANGEROUS_KEYS.has(key))
5888
- continue;
5889
- const baseValue = base[key];
5890
- const overrideValue = override[key];
5891
- if (overrideValue === undefined)
5892
- continue;
5893
- if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
5894
- result[key] = deepMerge(baseValue, overrideValue, depth + 1);
5895
- } else {
5896
- result[key] = overrideValue;
5897
- }
5898
- }
5899
- return result;
5900
- }
5901
- var DANGEROUS_KEYS, MAX_DEPTH = 50;
5902
- var init_deep_merge = __esm(() => {
5903
- DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
5904
- });
5905
-
5906
- // src/shared/snake-case.ts
5907
- var init_snake_case = __esm(() => {
5908
- init_deep_merge();
5909
- });
5910
-
5911
- // src/shared/tool-name.ts
5912
- var init_tool_name = () => {};
5913
-
5914
- // src/shared/pattern-matcher.ts
5915
- var regexCache;
5916
- var init_pattern_matcher = __esm(() => {
5917
- regexCache = new Map;
5918
- });
5919
- // src/shared/file-utils.ts
5920
- import { lstatSync, realpathSync } from "fs";
5921
- function normalizeDarwinRealpath(filePath) {
5922
- return filePath.startsWith("/private/var/") ? filePath.slice("/private".length) : filePath;
5923
- }
5924
- function resolveSymlink(filePath) {
5925
- try {
5926
- return normalizeDarwinRealpath(realpathSync(filePath));
5927
- } catch {
5928
- return filePath;
5929
- }
5930
- }
5931
- var init_file_utils = () => {};
5932
-
5933
- // src/shared/context-limit-resolver.ts
5934
- var init_context_limit_resolver = () => {};
5935
-
5936
- // src/shared/normalize-sdk-response.ts
5937
- function normalizeSDKResponse(response, fallback, options) {
5938
- if (response === null || response === undefined) {
5939
- return fallback;
5940
- }
5941
- if (Array.isArray(response)) {
5942
- return response;
6025
+ function detectPluginConfigFile(dir) {
6026
+ const canonicalResult = detectConfigFile(join4(dir, CONFIG_BASENAME));
6027
+ const legacyResult = detectConfigFile(join4(dir, LEGACY_CONFIG_BASENAME));
6028
+ if (canonicalResult.format !== "none") {
6029
+ return {
6030
+ ...canonicalResult,
6031
+ legacyPath: legacyResult.format !== "none" ? legacyResult.path : undefined
6032
+ };
5943
6033
  }
5944
- if (typeof response === "object" && "data" in response) {
5945
- const data = response.data;
5946
- if (data !== null && data !== undefined) {
5947
- return data;
5948
- }
5949
- if (options?.preferResponseOnMissingData === true) {
5950
- return response;
5951
- }
5952
- return fallback;
6034
+ if (legacyResult.format !== "none") {
6035
+ return legacyResult;
5953
6036
  }
5954
- if (options?.preferResponseOnMissingData === true) {
5955
- return response;
5956
- }
5957
- return fallback;
5958
- }
5959
-
5960
- // src/shared/dynamic-truncator.ts
5961
- var init_dynamic_truncator = __esm(() => {
5962
- init_context_limit_resolver();
5963
- });
5964
-
5965
- // src/shared/data-path.ts
5966
- import * as path2 from "path";
5967
- import * as os2 from "os";
5968
- function getDataDir() {
5969
- return process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
5970
- }
5971
- function getOpenCodeStorageDir() {
5972
- return path2.join(getDataDir(), "opencode", "storage");
5973
- }
5974
- function getCacheDir() {
5975
- return process.env.XDG_CACHE_HOME ?? path2.join(os2.homedir(), ".cache");
5976
- }
5977
- function getOmoOpenCodeCacheDir() {
5978
- return path2.join(getCacheDir(), CACHE_DIR_NAME);
5979
- }
5980
- function getOpenCodeCacheDir() {
5981
- return path2.join(getCacheDir(), "opencode");
6037
+ return { format: "none", path: join4(dir, `${CONFIG_BASENAME}.json`) };
5982
6038
  }
5983
- var init_data_path = __esm(() => {
6039
+ var init_jsonc_parser = __esm(() => {
6040
+ init_main();
5984
6041
  init_plugin_identity();
5985
6042
  });
5986
6043
 
5987
- // src/shared/config-errors.ts
5988
- function getConfigLoadErrors() {
5989
- return configLoadErrors;
5990
- }
5991
- function clearConfigLoadErrors() {
5992
- configLoadErrors = [];
5993
- }
5994
- function addConfigLoadError(error) {
5995
- configLoadErrors.push(error);
5996
- }
5997
- var configLoadErrors;
5998
- var init_config_errors = __esm(() => {
5999
- configLoadErrors = [];
6000
- });
6001
-
6002
- // src/shared/claude-config-dir.ts
6003
- var init_claude_config_dir = () => {};
6004
-
6005
6044
  // src/shared/migration/agent-names.ts
6006
6045
  function migrateAgentNames(agents) {
6007
6046
  const migrated = {};
@@ -6026,15 +6065,15 @@ var init_agent_names = __esm(() => {
6026
6065
  "omo-plan": "prometheus",
6027
6066
  "Planner-Sisyphus": "prometheus",
6028
6067
  "planner-sisyphus": "prometheus",
6029
- "Prometheus (Planner)": "prometheus",
6068
+ "Prometheus - Plan Builder": "prometheus",
6030
6069
  prometheus: "prometheus",
6031
6070
  "orchestrator-sisyphus": "atlas",
6032
6071
  Atlas: "atlas",
6033
6072
  atlas: "atlas",
6034
6073
  "plan-consultant": "metis",
6035
- "Metis (Plan Consultant)": "metis",
6074
+ "Metis - Plan Consultant": "metis",
6036
6075
  metis: "metis",
6037
- "Momus (Plan Reviewer)": "momus",
6076
+ "Momus - Plan Critic": "momus",
6038
6077
  momus: "momus",
6039
6078
  "Sisyphus-Junior": "sisyphus-junior",
6040
6079
  "sisyphus-junior": "sisyphus-junior",
@@ -6277,9 +6316,9 @@ var init_migration = __esm(() => {
6277
6316
  });
6278
6317
 
6279
6318
  // src/shared/opencode-config-dir.ts
6280
- import { existsSync as existsSync2 } from "fs";
6319
+ import { existsSync as existsSync2, realpathSync as realpathSync2 } from "fs";
6281
6320
  import { homedir as homedir2 } from "os";
6282
- import { join as join4, resolve } from "path";
6321
+ import { join as join5, resolve, win32 } from "path";
6283
6322
  function isDevBuild(version) {
6284
6323
  if (!version)
6285
6324
  return false;
@@ -6289,25 +6328,35 @@ function getTauriConfigDir(identifier) {
6289
6328
  const platform = process.platform;
6290
6329
  switch (platform) {
6291
6330
  case "darwin":
6292
- return join4(homedir2(), "Library", "Application Support", identifier);
6331
+ return join5(homedir2(), "Library", "Application Support", identifier);
6293
6332
  case "win32": {
6294
- const appData = process.env.APPDATA || join4(homedir2(), "AppData", "Roaming");
6295
- return join4(appData, identifier);
6333
+ const appData = process.env.APPDATA || join5(homedir2(), "AppData", "Roaming");
6334
+ return win32.join(appData, identifier);
6296
6335
  }
6297
6336
  case "linux":
6298
6337
  default: {
6299
- const xdgConfig = process.env.XDG_CONFIG_HOME || join4(homedir2(), ".config");
6300
- return join4(xdgConfig, identifier);
6338
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join5(homedir2(), ".config");
6339
+ return join5(xdgConfig, identifier);
6301
6340
  }
6302
6341
  }
6303
6342
  }
6343
+ function resolveConfigPath(pathValue) {
6344
+ const resolvedPath = resolve(pathValue);
6345
+ if (!existsSync2(resolvedPath))
6346
+ return resolvedPath;
6347
+ try {
6348
+ return realpathSync2(resolvedPath);
6349
+ } catch {
6350
+ return resolvedPath;
6351
+ }
6352
+ }
6304
6353
  function getCliConfigDir() {
6305
6354
  const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
6306
6355
  if (envConfigDir) {
6307
- return resolve(envConfigDir);
6356
+ return resolveConfigPath(envConfigDir);
6308
6357
  }
6309
- const xdgConfig = process.env.XDG_CONFIG_HOME || join4(homedir2(), ".config");
6310
- return join4(xdgConfig, "opencode");
6358
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join5(homedir2(), ".config");
6359
+ return resolveConfigPath(join5(xdgConfig, "opencode"));
6311
6360
  }
6312
6361
  function getOpenCodeConfigDir(options) {
6313
6362
  const { binary: binary2, version, checkExisting = true } = options;
@@ -6315,11 +6364,12 @@ function getOpenCodeConfigDir(options) {
6315
6364
  return getCliConfigDir();
6316
6365
  }
6317
6366
  const identifier = isDevBuild(version) ? TAURI_APP_IDENTIFIER_DEV : TAURI_APP_IDENTIFIER;
6318
- const tauriDir = getTauriConfigDir(identifier);
6367
+ const tauriDirBase = getTauriConfigDir(identifier);
6368
+ const tauriDir = process.platform === "win32" ? win32.isAbsolute(tauriDirBase) ? win32.normalize(tauriDirBase) : win32.resolve(tauriDirBase) : resolveConfigPath(tauriDirBase);
6319
6369
  if (checkExisting) {
6320
6370
  const legacyDir = getCliConfigDir();
6321
- const legacyConfig = join4(legacyDir, "opencode.json");
6322
- const legacyConfigC = join4(legacyDir, "opencode.jsonc");
6371
+ const legacyConfig = join5(legacyDir, "opencode.json");
6372
+ const legacyConfigC = join5(legacyDir, "opencode.jsonc");
6323
6373
  if (existsSync2(legacyConfig) || existsSync2(legacyConfigC)) {
6324
6374
  return legacyDir;
6325
6375
  }
@@ -6330,10 +6380,10 @@ function getOpenCodeConfigPaths(options) {
6330
6380
  const configDir = getOpenCodeConfigDir(options);
6331
6381
  return {
6332
6382
  configDir,
6333
- configJson: join4(configDir, "opencode.json"),
6334
- configJsonc: join4(configDir, "opencode.jsonc"),
6335
- packageJson: join4(configDir, "package.json"),
6336
- omoConfig: join4(configDir, `${CONFIG_BASENAME}.json`)
6383
+ configJson: join5(configDir, "opencode.json"),
6384
+ configJsonc: join5(configDir, "opencode.jsonc"),
6385
+ packageJson: join5(configDir, "package.json"),
6386
+ omoConfig: join5(configDir, `${CONFIG_BASENAME}.json`)
6337
6387
  };
6338
6388
  }
6339
6389
  var TAURI_APP_IDENTIFIER = "ai.opencode.desktop", TAURI_APP_IDENTIFIER_DEV = "ai.opencode.desktop.dev";
@@ -6342,18 +6392,88 @@ var init_opencode_config_dir = __esm(() => {
6342
6392
  });
6343
6393
 
6344
6394
  // src/shared/opencode-version.ts
6345
- var NOT_CACHED;
6395
+ import { execSync } from "child_process";
6396
+ function parseVersion(version) {
6397
+ const cleaned = version.replace(/^v/, "").split("-")[0];
6398
+ return cleaned.split(".").map((n) => parseInt(n, 10) || 0);
6399
+ }
6400
+ function compareVersions(a, b) {
6401
+ const partsA = parseVersion(a);
6402
+ const partsB = parseVersion(b);
6403
+ const maxLen = Math.max(partsA.length, partsB.length);
6404
+ for (let i2 = 0;i2 < maxLen; i2++) {
6405
+ const numA = partsA[i2] ?? 0;
6406
+ const numB = partsB[i2] ?? 0;
6407
+ if (numA < numB)
6408
+ return -1;
6409
+ if (numA > numB)
6410
+ return 1;
6411
+ }
6412
+ return 0;
6413
+ }
6414
+ function getOpenCodeVersion() {
6415
+ if (cachedVersion !== NOT_CACHED) {
6416
+ return cachedVersion;
6417
+ }
6418
+ try {
6419
+ const result = execSync("opencode --version", {
6420
+ encoding: "utf-8",
6421
+ timeout: 5000,
6422
+ stdio: ["pipe", "pipe", "pipe"]
6423
+ }).trim();
6424
+ const versionMatch = result.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
6425
+ cachedVersion = versionMatch?.[1] ?? null;
6426
+ return cachedVersion;
6427
+ } catch {
6428
+ cachedVersion = null;
6429
+ return null;
6430
+ }
6431
+ }
6432
+ function isOpenCodeVersionAtLeast(version) {
6433
+ const current = getOpenCodeVersion();
6434
+ if (!current)
6435
+ return true;
6436
+ return compareVersions(current, version) >= 0;
6437
+ }
6438
+ var OPENCODE_SQLITE_VERSION = "1.1.53", NOT_CACHED, cachedVersion;
6346
6439
  var init_opencode_version = __esm(() => {
6347
6440
  NOT_CACHED = Symbol("NOT_CACHED");
6441
+ cachedVersion = NOT_CACHED;
6348
6442
  });
6349
6443
 
6350
6444
  // src/shared/opencode-storage-detection.ts
6351
- var NOT_CACHED2, FALSE_PENDING_RETRY;
6445
+ import { existsSync as existsSync3 } from "fs";
6446
+ import { join as join6 } from "path";
6447
+ function isSqliteBackend() {
6448
+ if (cachedResult === true)
6449
+ return true;
6450
+ if (cachedResult === false)
6451
+ return false;
6452
+ const check = () => {
6453
+ const versionOk = isOpenCodeVersionAtLeast(OPENCODE_SQLITE_VERSION);
6454
+ const dbPath = join6(getDataDir(), "opencode", "opencode.db");
6455
+ return versionOk && existsSync3(dbPath);
6456
+ };
6457
+ if (cachedResult === FALSE_PENDING_RETRY) {
6458
+ const result2 = check();
6459
+ cachedResult = result2;
6460
+ return result2;
6461
+ }
6462
+ const result = check();
6463
+ if (result) {
6464
+ cachedResult = true;
6465
+ } else {
6466
+ cachedResult = FALSE_PENDING_RETRY;
6467
+ }
6468
+ return result;
6469
+ }
6470
+ var NOT_CACHED2, FALSE_PENDING_RETRY, cachedResult;
6352
6471
  var init_opencode_storage_detection = __esm(() => {
6353
6472
  init_data_path();
6354
6473
  init_opencode_version();
6355
6474
  NOT_CACHED2 = Symbol("NOT_CACHED");
6356
6475
  FALSE_PENDING_RETRY = Symbol("FALSE_PENDING_RETRY");
6476
+ cachedResult = NOT_CACHED2;
6357
6477
  });
6358
6478
  // src/shared/external-plugin-detector.ts
6359
6479
  var init_external_plugin_detector = __esm(() => {
@@ -6764,20 +6884,20 @@ function normalizeModelID(modelID) {
6764
6884
  }
6765
6885
 
6766
6886
  // src/shared/json-file-cache-store.ts
6767
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
6768
- import { join as join5 } from "path";
6887
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
6888
+ import { join as join7 } from "path";
6769
6889
  function toLogLabel(cacheLabel) {
6770
6890
  return cacheLabel.toLowerCase();
6771
6891
  }
6772
6892
  function createJsonFileCacheStore(options) {
6773
6893
  let memoryValue;
6774
6894
  function getCacheFilePath() {
6775
- return join5(options.getCacheDir(), options.filename);
6895
+ return join7(options.getCacheDir(), options.filename);
6776
6896
  }
6777
6897
  function ensureCacheDir() {
6778
6898
  const cacheDir = options.getCacheDir();
6779
- if (!existsSync3(cacheDir)) {
6780
- mkdirSync(cacheDir, { recursive: true });
6899
+ if (!existsSync4(cacheDir)) {
6900
+ mkdirSync2(cacheDir, { recursive: true });
6781
6901
  }
6782
6902
  }
6783
6903
  function read() {
@@ -6785,7 +6905,7 @@ function createJsonFileCacheStore(options) {
6785
6905
  return memoryValue;
6786
6906
  }
6787
6907
  const cacheFile = getCacheFilePath();
6788
- if (!existsSync3(cacheFile)) {
6908
+ if (!existsSync4(cacheFile)) {
6789
6909
  memoryValue = null;
6790
6910
  log(`[${options.logPrefix}] ${options.cacheLabel} file not found`, { cacheFile });
6791
6911
  return null;
@@ -6805,7 +6925,7 @@ function createJsonFileCacheStore(options) {
6805
6925
  }
6806
6926
  }
6807
6927
  function has() {
6808
- return existsSync3(getCacheFilePath());
6928
+ return existsSync4(getCacheFilePath());
6809
6929
  }
6810
6930
  function write(value) {
6811
6931
  ensureCacheDir();
@@ -6974,14 +7094,14 @@ var init_connected_providers_cache = __esm(() => {
6974
7094
  });
6975
7095
 
6976
7096
  // src/shared/model-availability.ts
6977
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
6978
- import { join as join6 } from "path";
7097
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
7098
+ import { join as join8 } from "path";
6979
7099
  function isModelCacheAvailable() {
6980
7100
  if (hasProviderModelsCache()) {
6981
7101
  return true;
6982
7102
  }
6983
- const cacheFile = join6(getOpenCodeCacheDir(), "models.json");
6984
- return existsSync4(cacheFile);
7103
+ const cacheFile = join8(getOpenCodeCacheDir(), "models.json");
7104
+ return existsSync5(cacheFile);
6985
7105
  }
6986
7106
  var init_model_availability = __esm(() => {
6987
7107
  init_logger();
@@ -48276,6 +48396,57 @@ var init_constants = __esm(() => {
48276
48396
  init_shared();
48277
48397
  });
48278
48398
 
48399
+ // src/shared/opencode-storage-paths.ts
48400
+ import { join as join9 } from "path";
48401
+ var OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE;
48402
+ var init_opencode_storage_paths = __esm(() => {
48403
+ init_data_path();
48404
+ OPENCODE_STORAGE = getOpenCodeStorageDir();
48405
+ MESSAGE_STORAGE = join9(OPENCODE_STORAGE, "message");
48406
+ PART_STORAGE = join9(OPENCODE_STORAGE, "part");
48407
+ SESSION_STORAGE = join9(OPENCODE_STORAGE, "session");
48408
+ });
48409
+
48410
+ // src/shared/compaction-marker.ts
48411
+ import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync4 } from "fs";
48412
+ import { join as join10 } from "path";
48413
+ function isCompactionPart(part) {
48414
+ return typeof part === "object" && part !== null && part.type === "compaction";
48415
+ }
48416
+ function isCompactionAgent(agent) {
48417
+ return typeof agent === "string" && agent.trim().toLowerCase() === "compaction";
48418
+ }
48419
+ function hasCompactionPart(parts) {
48420
+ return Array.isArray(parts) && parts.some((part) => isCompactionPart(part));
48421
+ }
48422
+ function isCompactionMessage(message) {
48423
+ return isCompactionAgent(message.info?.agent ?? message.agent) || hasCompactionPart(message.parts);
48424
+ }
48425
+ function hasCompactionPartInStorage(messageID) {
48426
+ if (!messageID) {
48427
+ return false;
48428
+ }
48429
+ const partDir = join10(PART_STORAGE, messageID);
48430
+ if (!existsSync6(partDir)) {
48431
+ return false;
48432
+ }
48433
+ try {
48434
+ return readdirSync(partDir).filter((fileName) => fileName.endsWith(".json")).some((fileName) => {
48435
+ try {
48436
+ const content = readFileSync4(join10(partDir, fileName), "utf-8");
48437
+ return isCompactionPart(JSON.parse(content));
48438
+ } catch {
48439
+ return false;
48440
+ }
48441
+ });
48442
+ } catch {
48443
+ return false;
48444
+ }
48445
+ }
48446
+ var init_compaction_marker = __esm(() => {
48447
+ init_opencode_storage_paths();
48448
+ });
48449
+
48279
48450
  // src/features/hook-message-injector/injector.ts
48280
48451
  import { randomBytes } from "crypto";
48281
48452
  var processPrefix;
@@ -48284,6 +48455,7 @@ var init_injector = __esm(() => {
48284
48455
  init_logger();
48285
48456
  init_opencode_storage_detection();
48286
48457
  init_shared();
48458
+ init_compaction_marker();
48287
48459
  processPrefix = randomBytes(4).toString("hex");
48288
48460
  });
48289
48461
 
@@ -48293,18 +48465,33 @@ var init_hook_message_injector = __esm(() => {
48293
48465
  init_constants();
48294
48466
  });
48295
48467
 
48296
- // src/shared/opencode-storage-paths.ts
48297
- import { join as join7 } from "path";
48298
- var OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE;
48299
- var init_opencode_storage_paths = __esm(() => {
48300
- init_data_path();
48301
- OPENCODE_STORAGE = getOpenCodeStorageDir();
48302
- MESSAGE_STORAGE = join7(OPENCODE_STORAGE, "message");
48303
- PART_STORAGE = join7(OPENCODE_STORAGE, "part");
48304
- SESSION_STORAGE = join7(OPENCODE_STORAGE, "session");
48305
- });
48306
-
48307
48468
  // src/shared/opencode-message-dir.ts
48469
+ import { existsSync as existsSync7, readdirSync as readdirSync2 } from "fs";
48470
+ import { join as join11 } from "path";
48471
+ function getMessageDir(sessionID) {
48472
+ if (!sessionID.startsWith("ses_"))
48473
+ return null;
48474
+ if (/[/\\]|\.\./.test(sessionID))
48475
+ return null;
48476
+ if (!existsSync7(MESSAGE_STORAGE))
48477
+ return null;
48478
+ const directPath = join11(MESSAGE_STORAGE, sessionID);
48479
+ if (existsSync7(directPath)) {
48480
+ return directPath;
48481
+ }
48482
+ try {
48483
+ for (const dir of readdirSync2(MESSAGE_STORAGE)) {
48484
+ const sessionPath = join11(MESSAGE_STORAGE, dir, sessionID);
48485
+ if (existsSync7(sessionPath)) {
48486
+ return sessionPath;
48487
+ }
48488
+ }
48489
+ } catch (error) {
48490
+ log("[opencode-message-dir] Failed to scan message directories", { sessionID, error: String(error) });
48491
+ return null;
48492
+ }
48493
+ return null;
48494
+ }
48308
48495
  var init_opencode_message_dir = __esm(() => {
48309
48496
  init_opencode_storage_paths();
48310
48497
  init_logger();
@@ -48330,22 +48517,25 @@ function getAgentConfigKey(agentName) {
48330
48517
  const reversed = REVERSE_DISPLAY_NAMES[lower];
48331
48518
  if (reversed !== undefined)
48332
48519
  return reversed;
48520
+ const legacy = LEGACY_DISPLAY_NAMES[lower];
48521
+ if (legacy !== undefined)
48522
+ return legacy;
48333
48523
  if (AGENT_DISPLAY_NAMES[lower] !== undefined)
48334
48524
  return lower;
48335
48525
  return lower;
48336
48526
  }
48337
- var AGENT_DISPLAY_NAMES, REVERSE_DISPLAY_NAMES;
48527
+ var AGENT_DISPLAY_NAMES, REVERSE_DISPLAY_NAMES, LEGACY_DISPLAY_NAMES;
48338
48528
  var init_agent_display_names = __esm(() => {
48339
48529
  AGENT_DISPLAY_NAMES = {
48340
- sisyphus: "Sisyphus (Ultraworker)",
48341
- hephaestus: "Hephaestus (Deep Agent)",
48342
- prometheus: "Prometheus (Plan Builder)",
48343
- atlas: "Atlas (Plan Executor)",
48530
+ sisyphus: "Sisyphus - Ultraworker",
48531
+ hephaestus: "Hephaestus - Deep Agent",
48532
+ prometheus: "Prometheus - Plan Builder",
48533
+ atlas: "Atlas - Plan Executor",
48344
48534
  "sisyphus-junior": "Sisyphus-Junior",
48345
- metis: "Metis (Plan Consultant)",
48346
- momus: "Momus (Plan Critic)",
48347
- athena: "Athena (Council)",
48348
- "athena-junior": "Athena-Junior (Council)",
48535
+ metis: "Metis - Plan Consultant",
48536
+ momus: "Momus - Plan Critic",
48537
+ athena: "Athena - Council",
48538
+ "athena-junior": "Athena-Junior - Council",
48349
48539
  oracle: "oracle",
48350
48540
  librarian: "librarian",
48351
48541
  explore: "explore",
@@ -48353,6 +48543,16 @@ var init_agent_display_names = __esm(() => {
48353
48543
  "council-member": "council-member"
48354
48544
  };
48355
48545
  REVERSE_DISPLAY_NAMES = Object.fromEntries(Object.entries(AGENT_DISPLAY_NAMES).map(([key, displayName]) => [displayName.toLowerCase(), key]));
48546
+ LEGACY_DISPLAY_NAMES = {
48547
+ "sisyphus (ultraworker)": "sisyphus",
48548
+ "hephaestus (deep agent)": "hephaestus",
48549
+ "prometheus (plan builder)": "prometheus",
48550
+ "atlas (plan executor)": "atlas",
48551
+ "metis (plan consultant)": "metis",
48552
+ "momus (plan critic)": "momus",
48553
+ "athena (council)": "athena",
48554
+ "athena-junior (council)": "athena-junior"
48555
+ };
48356
48556
  });
48357
48557
 
48358
48558
  // src/shared/session-utils.ts
@@ -48516,9 +48716,18 @@ var init_session_tools_store = __esm(() => {
48516
48716
  var init_prompt_tools = __esm(() => {
48517
48717
  init_session_tools_store();
48518
48718
  });
48719
+
48720
+ // src/shared/internal-initiator-marker.ts
48721
+ var init_internal_initiator_marker = () => {};
48722
+ // src/features/claude-code-plugin-loader/scope-filter.ts
48723
+ var init_scope_filter = __esm(() => {
48724
+ init_contains_path();
48725
+ });
48726
+
48519
48727
  // src/features/claude-code-plugin-loader/discovery.ts
48520
48728
  var init_discovery = __esm(() => {
48521
48729
  init_logger();
48730
+ init_scope_filter();
48522
48731
  });
48523
48732
 
48524
48733
  // src/features/claude-code-plugin-loader/command-loader.ts
@@ -48569,7 +48778,7 @@ var init_env_expander = __esm(() => {
48569
48778
  });
48570
48779
 
48571
48780
  // src/features/claude-code-mcp-loader/scope-filter.ts
48572
- var init_scope_filter = __esm(() => {
48781
+ var init_scope_filter2 = __esm(() => {
48573
48782
  init_contains_path();
48574
48783
  });
48575
48784
 
@@ -48580,7 +48789,7 @@ var init_transformer = __esm(() => {
48580
48789
  // src/features/claude-code-plugin-loader/mcp-server-loader.ts
48581
48790
  var init_mcp_server_loader = __esm(() => {
48582
48791
  init_env_expander();
48583
- init_scope_filter();
48792
+ init_scope_filter2();
48584
48793
  init_transformer();
48585
48794
  init_logger();
48586
48795
  });
@@ -48591,6 +48800,7 @@ var init_hook_loader = __esm(() => {
48591
48800
  });
48592
48801
 
48593
48802
  // src/features/claude-code-plugin-loader/loader.ts
48803
+ var cachedPluginComponentsByKey;
48594
48804
  var init_loader = __esm(() => {
48595
48805
  init_logger();
48596
48806
  init_discovery();
@@ -48605,6 +48815,7 @@ var init_loader = __esm(() => {
48605
48815
  init_agent_loader();
48606
48816
  init_mcp_server_loader();
48607
48817
  init_hook_loader();
48818
+ cachedPluginComponentsByKey = new Map;
48608
48819
  });
48609
48820
 
48610
48821
  // src/features/claude-code-plugin-loader/index.ts
@@ -48714,6 +48925,8 @@ var init_shared = __esm(() => {
48714
48925
  init_project_discovery_dirs();
48715
48926
  init_session_directory_resolver();
48716
48927
  init_prompt_tools();
48928
+ init_compaction_marker();
48929
+ init_internal_initiator_marker();
48717
48930
  init_plugin_command_discovery();
48718
48931
  init_plugin_identity();
48719
48932
  init_log_legacy_plugin_startup_warning();
@@ -48741,16 +48954,15 @@ function getConfigJsonc() {
48741
48954
  return getConfigContext().paths.configJsonc;
48742
48955
  }
48743
48956
  function getOmoConfigPath() {
48957
+ const configDir = getConfigContext().paths.configDir;
48958
+ const detected = detectPluginConfigFile(configDir);
48959
+ if (detected.format !== "none")
48960
+ return detected.path;
48744
48961
  return getConfigContext().paths.omoConfig;
48745
48962
  }
48746
- function getExistingOmoConfigPath() {
48747
- const detected = detectManagedConfigFile(getConfigDir());
48748
- return detected.format === "none" ? null : detected.path;
48749
- }
48750
48963
  var configContext = null;
48751
48964
  var init_config_context = __esm(() => {
48752
48965
  init_shared();
48753
- init_plugin_identity();
48754
48966
  });
48755
48967
 
48756
48968
  // src/cli/config-manager/npm-dist-tags.ts
@@ -48791,17 +49003,42 @@ async function getPluginNameWithVersion(currentVersion, packageName = DEFAULT_PA
48791
49003
  }
48792
49004
  var DEFAULT_PACKAGE_NAME, PRIORITIZED_TAGS;
48793
49005
  var init_plugin_name_with_version = __esm(() => {
48794
- init_plugin_identity();
49006
+ init_shared();
48795
49007
  DEFAULT_PACKAGE_NAME = PLUGIN_NAME;
48796
49008
  PRIORITIZED_TAGS = ["latest", "beta", "next"];
48797
49009
  });
48798
49010
 
49011
+ // src/cli/config-manager/backup-config.ts
49012
+ import { copyFileSync as copyFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
49013
+ import { dirname } from "path";
49014
+ function backupConfigFile(configPath) {
49015
+ if (!existsSync8(configPath)) {
49016
+ return { success: true };
49017
+ }
49018
+ const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-");
49019
+ const backupPath = `${configPath}.backup-${timestamp2}`;
49020
+ try {
49021
+ const dir = dirname(backupPath);
49022
+ if (!existsSync8(dir)) {
49023
+ mkdirSync3(dir, { recursive: true });
49024
+ }
49025
+ copyFileSync2(configPath, backupPath);
49026
+ return { success: true, backupPath };
49027
+ } catch (err) {
49028
+ return {
49029
+ success: false,
49030
+ error: err instanceof Error ? err.message : "Failed to create backup"
49031
+ };
49032
+ }
49033
+ }
49034
+ var init_backup_config = () => {};
49035
+
48799
49036
  // src/cli/config-manager/ensure-config-directory-exists.ts
48800
- import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
49037
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
48801
49038
  function ensureConfigDirectoryExists() {
48802
49039
  const configDir = getConfigDir();
48803
- if (!existsSync5(configDir)) {
48804
- mkdirSync2(configDir, { recursive: true });
49040
+ if (!existsSync9(configDir)) {
49041
+ mkdirSync4(configDir, { recursive: true });
48805
49042
  }
48806
49043
  }
48807
49044
  var init_ensure_config_directory_exists = __esm(() => {
@@ -48838,14 +49075,14 @@ function formatErrorWithSuggestion(err, context) {
48838
49075
  }
48839
49076
 
48840
49077
  // src/cli/config-manager/opencode-config-format.ts
48841
- import { existsSync as existsSync6 } from "fs";
49078
+ import { existsSync as existsSync10 } from "fs";
48842
49079
  function detectConfigFormat() {
48843
49080
  const configJsonc = getConfigJsonc();
48844
49081
  const configJson = getConfigJson();
48845
- if (existsSync6(configJsonc)) {
49082
+ if (existsSync10(configJsonc)) {
48846
49083
  return { format: "jsonc", path: configJsonc };
48847
49084
  }
48848
- if (existsSync6(configJson)) {
49085
+ if (existsSync10(configJson)) {
48849
49086
  return { format: "json", path: configJson };
48850
49087
  }
48851
49088
  return { format: "none", path: configJson };
@@ -48855,7 +49092,7 @@ var init_opencode_config_format = __esm(() => {
48855
49092
  });
48856
49093
 
48857
49094
  // src/cli/config-manager/parse-opencode-config-file.ts
48858
- import { readFileSync as readFileSync4, statSync } from "fs";
49095
+ import { readFileSync as readFileSync5, statSync } from "fs";
48859
49096
  function isEmptyOrWhitespace(content) {
48860
49097
  return content.trim().length === 0;
48861
49098
  }
@@ -48865,7 +49102,7 @@ function parseOpenCodeConfigFileWithError(path3) {
48865
49102
  if (stat.size === 0) {
48866
49103
  return { config: null, error: `Config file is empty: ${path3}. Delete it or add valid JSON content.` };
48867
49104
  }
48868
- const content = readFileSync4(path3, "utf-8");
49105
+ const content = readFileSync5(path3, "utf-8");
48869
49106
  if (isEmptyOrWhitespace(content)) {
48870
49107
  return { config: null, error: `Config file contains only whitespace: ${path3}. Delete it or add valid JSON content.` };
48871
49108
  }
@@ -48888,8 +49125,90 @@ var init_parse_opencode_config_file = __esm(() => {
48888
49125
  init_shared();
48889
49126
  });
48890
49127
 
49128
+ // src/cli/config-manager/version-compatibility.ts
49129
+ function parseVersion2(version) {
49130
+ const clean = version.replace(/^v/, "").split("-")[0];
49131
+ return clean.split(".").map(Number);
49132
+ }
49133
+ function compareVersions2(a, b) {
49134
+ const partsA = parseVersion2(a);
49135
+ const partsB = parseVersion2(b);
49136
+ const maxLen = Math.max(partsA.length, partsB.length);
49137
+ for (let i2 = 0;i2 < maxLen; i2++) {
49138
+ const numA = partsA[i2] ?? 0;
49139
+ const numB = partsB[i2] ?? 0;
49140
+ if (numA !== numB) {
49141
+ return numA - numB;
49142
+ }
49143
+ }
49144
+ return 0;
49145
+ }
49146
+ function checkVersionCompatibility(currentVersion, newVersion) {
49147
+ if (!currentVersion) {
49148
+ return {
49149
+ canUpgrade: true,
49150
+ isDowngrade: false,
49151
+ isMajorBump: false,
49152
+ requiresMigration: false
49153
+ };
49154
+ }
49155
+ const cleanCurrent = currentVersion.replace(/^v/, "");
49156
+ const cleanNew = newVersion.replace(/^v/, "");
49157
+ try {
49158
+ const comparison = compareVersions2(cleanNew, cleanCurrent);
49159
+ if (comparison < 0) {
49160
+ return {
49161
+ canUpgrade: false,
49162
+ reason: `Downgrade from ${currentVersion} to ${newVersion} is not allowed`,
49163
+ isDowngrade: true,
49164
+ isMajorBump: false,
49165
+ requiresMigration: false
49166
+ };
49167
+ }
49168
+ if (comparison === 0) {
49169
+ return {
49170
+ canUpgrade: true,
49171
+ reason: `Version ${newVersion} is already installed`,
49172
+ isDowngrade: false,
49173
+ isMajorBump: false,
49174
+ requiresMigration: false
49175
+ };
49176
+ }
49177
+ const currentMajor = cleanCurrent.split(".")[0];
49178
+ const newMajor = cleanNew.split(".")[0];
49179
+ const isMajorBump = currentMajor !== newMajor;
49180
+ if (isMajorBump) {
49181
+ return {
49182
+ canUpgrade: true,
49183
+ reason: `Major version upgrade from ${currentVersion} to ${newVersion} - configuration migration may be required`,
49184
+ isDowngrade: false,
49185
+ isMajorBump: true,
49186
+ requiresMigration: true
49187
+ };
49188
+ }
49189
+ return {
49190
+ canUpgrade: true,
49191
+ isDowngrade: false,
49192
+ isMajorBump: false,
49193
+ requiresMigration: false
49194
+ };
49195
+ } catch {
49196
+ return {
49197
+ canUpgrade: true,
49198
+ reason: `Unable to compare versions ${currentVersion} and ${newVersion} - proceeding with caution`,
49199
+ isDowngrade: false,
49200
+ isMajorBump: false,
49201
+ requiresMigration: false
49202
+ };
49203
+ }
49204
+ }
49205
+ function extractVersionFromPluginEntry(entry) {
49206
+ const match = entry.match(/@(.+)$/);
49207
+ return match ? match[1] : null;
49208
+ }
49209
+
48891
49210
  // src/cli/config-manager/add-plugin-to-opencode-config.ts
48892
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
49211
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
48893
49212
  async function addPluginToOpenCodeConfig(currentVersion) {
48894
49213
  try {
48895
49214
  ensureConfigDirectoryExists();
@@ -48901,7 +49220,7 @@ async function addPluginToOpenCodeConfig(currentVersion) {
48901
49220
  };
48902
49221
  }
48903
49222
  const { format: format2, path: path3 } = detectConfigFormat();
48904
- const pluginEntry = await getPluginNameWithVersion(currentVersion, PACKAGE_NAME);
49223
+ const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME);
48905
49224
  try {
48906
49225
  if (format2 === "none") {
48907
49226
  const config2 = { plugin: [pluginEntry] };
@@ -48919,24 +49238,44 @@ async function addPluginToOpenCodeConfig(currentVersion) {
48919
49238
  }
48920
49239
  const config = parseResult.config;
48921
49240
  const plugins = config.plugin ?? [];
48922
- const existingPlugin = findManagedPluginEntry(plugins);
48923
- if (existingPlugin) {
48924
- if (plugins[existingPlugin.index] === pluginEntry) {
48925
- return { success: true, configPath: path3 };
49241
+ const canonicalEntries = plugins.filter((plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`));
49242
+ const legacyEntries = plugins.filter((plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`));
49243
+ const otherPlugins = plugins.filter((plugin) => !(plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)) && !(plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)));
49244
+ const existingEntry = canonicalEntries[0] ?? legacyEntries[0];
49245
+ if (existingEntry) {
49246
+ const installedVersion = extractVersionFromPluginEntry(existingEntry);
49247
+ const compatibility = checkVersionCompatibility(installedVersion, currentVersion);
49248
+ if (!compatibility.canUpgrade) {
49249
+ return {
49250
+ success: false,
49251
+ configPath: path3,
49252
+ error: compatibility.reason ?? "Version compatibility check failed"
49253
+ };
48926
49254
  }
48927
- plugins[existingPlugin.index] = pluginEntry;
49255
+ const backupResult = backupConfigFile(path3);
49256
+ if (!backupResult.success) {
49257
+ return {
49258
+ success: false,
49259
+ configPath: path3,
49260
+ error: `Failed to create backup: ${backupResult.error}`
49261
+ };
49262
+ }
49263
+ }
49264
+ const normalizedPlugins = [...otherPlugins];
49265
+ if (canonicalEntries.length > 0 || legacyEntries.length > 0) {
49266
+ normalizedPlugins.push(pluginEntry);
48928
49267
  } else {
48929
- plugins.push(pluginEntry);
49268
+ normalizedPlugins.push(pluginEntry);
48930
49269
  }
48931
- config.plugin = plugins;
49270
+ config.plugin = normalizedPlugins;
48932
49271
  if (format2 === "jsonc") {
48933
- const content = readFileSync5(path3, "utf-8");
48934
- const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/;
49272
+ const content = readFileSync6(path3, "utf-8");
49273
+ const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/;
48935
49274
  const match = content.match(pluginArrayRegex);
48936
49275
  if (match) {
48937
- const formattedPlugins = plugins.map((p) => `"${p}"`).join(`,
49276
+ const formattedPlugins = normalizedPlugins.map((p) => `"${p}"`).join(`,
48938
49277
  `);
48939
- const newContent = content.replace(pluginArrayRegex, `"plugin": [
49278
+ const newContent = content.replace(pluginArrayRegex, `$1[
48940
49279
  ${formattedPlugins}
48941
49280
  ]`);
48942
49281
  writeFileSync3(path3, newContent);
@@ -48958,15 +49297,14 @@ async function addPluginToOpenCodeConfig(currentVersion) {
48958
49297
  };
48959
49298
  }
48960
49299
  }
48961
- var PACKAGE_NAME;
48962
49300
  var init_add_plugin_to_opencode_config = __esm(() => {
48963
- init_plugin_identity();
49301
+ init_shared();
49302
+ init_backup_config();
48964
49303
  init_config_context();
48965
49304
  init_ensure_config_directory_exists();
48966
49305
  init_opencode_config_format();
48967
49306
  init_parse_opencode_config_file();
48968
49307
  init_plugin_name_with_version();
48969
- PACKAGE_NAME = PLUGIN_NAME;
48970
49308
  });
48971
49309
 
48972
49310
  // src/cli/model-fallback-requirements.ts
@@ -49077,6 +49415,47 @@ var init_fallback_chain_resolution = __esm(() => {
49077
49415
  });
49078
49416
 
49079
49417
  // src/cli/model-fallback.ts
49418
+ function toFallbackModelObject(entry, provider) {
49419
+ return {
49420
+ model: `${provider}/${transformModelForProvider(provider, entry.model)}`,
49421
+ ...entry.variant ? { variant: entry.variant } : {},
49422
+ ...entry.reasoningEffort ? { reasoningEffort: entry.reasoningEffort } : {},
49423
+ ...entry.temperature !== undefined ? { temperature: entry.temperature } : {},
49424
+ ...entry.top_p !== undefined ? { top_p: entry.top_p } : {},
49425
+ ...entry.maxTokens !== undefined ? { maxTokens: entry.maxTokens } : {},
49426
+ ...entry.thinking ? { thinking: entry.thinking } : {}
49427
+ };
49428
+ }
49429
+ function collectAvailableFallbacks(fallbackChain, availability) {
49430
+ const expandedFallbacks = fallbackChain.flatMap((entry) => entry.providers.filter((provider) => isProviderAvailable(provider, availability)).map((provider) => toFallbackModelObject(entry, provider)));
49431
+ return expandedFallbacks.filter((entry, index, allEntries) => allEntries.findIndex((candidate) => candidate.model === entry.model && candidate.variant === entry.variant) === index);
49432
+ }
49433
+ function attachFallbackModels(config, fallbackChain, availability) {
49434
+ const uniqueFallbacks = collectAvailableFallbacks(fallbackChain, availability);
49435
+ const primaryIndex = uniqueFallbacks.findIndex((entry) => entry.model === config.model);
49436
+ if (primaryIndex === -1) {
49437
+ return config;
49438
+ }
49439
+ const fallbackModels = uniqueFallbacks.slice(primaryIndex + 1);
49440
+ if (fallbackModels.length === 0) {
49441
+ return config;
49442
+ }
49443
+ return {
49444
+ ...config,
49445
+ fallback_models: fallbackModels
49446
+ };
49447
+ }
49448
+ function attachAllFallbackModels(config, fallbackChain, availability) {
49449
+ const uniqueFallbacks = collectAvailableFallbacks(fallbackChain, availability);
49450
+ const fallbackModels = uniqueFallbacks.filter((entry) => entry.model !== config.model);
49451
+ if (fallbackModels.length === 0) {
49452
+ return config;
49453
+ }
49454
+ return {
49455
+ ...config,
49456
+ fallback_models: fallbackModels
49457
+ };
49458
+ }
49080
49459
  function generateModelConfig(config) {
49081
49460
  const avail = toProviderAvailability(config);
49082
49461
  const hasAnyProvider = avail.native.claude || avail.native.openai || avail.native.gemini || avail.opencodeZen || avail.copilot || avail.zai || avail.kimiForCoding || avail.opencodeGo;
@@ -49091,25 +49470,31 @@ function generateModelConfig(config) {
49091
49470
  const categories = {};
49092
49471
  for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) {
49093
49472
  if (role === "librarian") {
49473
+ let agentConfig;
49094
49474
  if (avail.opencodeGo) {
49095
- agents[role] = { model: "opencode-go/minimax-m2.5" };
49475
+ agentConfig = { model: "opencode-go/minimax-m2.7" };
49096
49476
  } else if (avail.zai) {
49097
- agents[role] = { model: ZAI_MODEL };
49477
+ agentConfig = { model: ZAI_MODEL };
49478
+ }
49479
+ if (agentConfig) {
49480
+ agents[role] = attachAllFallbackModels(agentConfig, req.fallbackChain, avail);
49098
49481
  }
49099
49482
  continue;
49100
49483
  }
49101
49484
  if (role === "explore") {
49485
+ let agentConfig;
49102
49486
  if (avail.native.claude) {
49103
- agents[role] = { model: "anthropic/claude-haiku-4-5" };
49487
+ agentConfig = { model: "anthropic/claude-haiku-4-5" };
49104
49488
  } else if (avail.opencodeZen) {
49105
- agents[role] = { model: "opencode/claude-haiku-4-5" };
49489
+ agentConfig = { model: "opencode/claude-haiku-4-5" };
49106
49490
  } else if (avail.opencodeGo) {
49107
- agents[role] = { model: "opencode-go/minimax-m2.5" };
49491
+ agentConfig = { model: "opencode-go/minimax-m2.7" };
49108
49492
  } else if (avail.copilot) {
49109
- agents[role] = { model: "github-copilot/gpt-5-mini" };
49493
+ agentConfig = { model: "github-copilot/gpt-5-mini" };
49110
49494
  } else {
49111
- agents[role] = { model: "opencode/gpt-5-nano" };
49495
+ agentConfig = { model: "opencode/gpt-5-nano" };
49112
49496
  }
49497
+ agents[role] = attachAllFallbackModels(agentConfig, req.fallbackChain, avail);
49113
49498
  continue;
49114
49499
  }
49115
49500
  if (role === "sisyphus") {
@@ -49120,7 +49505,8 @@ function generateModelConfig(config) {
49120
49505
  const resolved2 = resolveModelFromChain(fallbackChain, avail);
49121
49506
  if (resolved2) {
49122
49507
  const variant = resolved2.variant ?? req.variant;
49123
- agents[role] = variant ? { model: resolved2.model, variant } : { model: resolved2.model };
49508
+ const agentConfig = variant ? { model: resolved2.model, variant } : { model: resolved2.model };
49509
+ agents[role] = attachFallbackModels(agentConfig, fallbackChain, avail);
49124
49510
  }
49125
49511
  continue;
49126
49512
  }
@@ -49133,7 +49519,8 @@ function generateModelConfig(config) {
49133
49519
  const resolved = resolveModelFromChain(req.fallbackChain, avail);
49134
49520
  if (resolved) {
49135
49521
  const variant = resolved.variant ?? req.variant;
49136
- agents[role] = variant ? { model: resolved.model, variant } : { model: resolved.model };
49522
+ const agentConfig = variant ? { model: resolved.model, variant } : { model: resolved.model };
49523
+ agents[role] = attachFallbackModels(agentConfig, req.fallbackChain, avail);
49137
49524
  } else {
49138
49525
  agents[role] = { model: ULTIMATE_FALLBACK };
49139
49526
  }
@@ -49149,7 +49536,8 @@ function generateModelConfig(config) {
49149
49536
  const resolved = resolveModelFromChain(fallbackChain, avail);
49150
49537
  if (resolved) {
49151
49538
  const variant = resolved.variant ?? req.variant;
49152
- categories[cat] = variant ? { model: resolved.model, variant } : { model: resolved.model };
49539
+ const categoryConfig = variant ? { model: resolved.model, variant } : { model: resolved.model };
49540
+ categories[cat] = attachFallbackModels(categoryConfig, fallbackChain, avail);
49153
49541
  } else {
49154
49542
  categories[cat] = { model: ULTIMATE_FALLBACK };
49155
49543
  }
@@ -49161,13 +49549,12 @@ function generateModelConfig(config) {
49161
49549
  };
49162
49550
  return isOpenAiOnlyAvailability(avail) ? applyOpenAiOnlyModelCatalog(generatedConfig) : generatedConfig;
49163
49551
  }
49164
- var ZAI_MODEL = "zai-coding-plan/glm-4.7", ULTIMATE_FALLBACK = "opencode/glm-4.7-free", SCHEMA_URL;
49552
+ var ZAI_MODEL = "zai-coding-plan/glm-4.7", ULTIMATE_FALLBACK = "opencode/gpt-5-nano", SCHEMA_URL = "https://raw.githubusercontent.com/D4ch1au/evil-oh-my-openagent/dev/assets/evil-omo.schema.json";
49165
49553
  var init_model_fallback = __esm(() => {
49166
49554
  init_model_fallback_requirements();
49167
49555
  init_openai_only_model_catalog();
49168
49556
  init_fallback_chain_resolution();
49169
- init_plugin_identity();
49170
- SCHEMA_URL = `https://raw.githubusercontent.com/D4ch1au/evil-oh-my-openagent/dev/assets/${SCHEMA_FILENAME}`;
49557
+ init_provider_model_id_transform();
49171
49558
  });
49172
49559
 
49173
49560
  // src/cli/config-manager/generate-omo-config.ts
@@ -49196,7 +49583,7 @@ function deepMergeRecord(target, source) {
49196
49583
  }
49197
49584
 
49198
49585
  // src/cli/config-manager/write-omo-config.ts
49199
- import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync2, writeFileSync as writeFileSync4 } from "fs";
49586
+ import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as statSync2, writeFileSync as writeFileSync4 } from "fs";
49200
49587
  function isEmptyOrWhitespace2(content) {
49201
49588
  return content.trim().length === 0;
49202
49589
  }
@@ -49211,13 +49598,20 @@ function writeOmoConfig(installConfig) {
49211
49598
  };
49212
49599
  }
49213
49600
  const omoConfigPath = getOmoConfigPath();
49214
- const existingConfigPath = getExistingOmoConfigPath() ?? omoConfigPath;
49215
49601
  try {
49216
49602
  const newConfig = generateOmoConfig(installConfig);
49217
- if (existsSync7(existingConfigPath)) {
49603
+ if (existsSync11(omoConfigPath)) {
49604
+ const backupResult = backupConfigFile(omoConfigPath);
49605
+ if (!backupResult.success) {
49606
+ return {
49607
+ success: false,
49608
+ configPath: omoConfigPath,
49609
+ error: `Failed to create backup: ${backupResult.error}`
49610
+ };
49611
+ }
49218
49612
  try {
49219
- const stat = statSync2(existingConfigPath);
49220
- const content = readFileSync6(existingConfigPath, "utf-8");
49613
+ const stat = statSync2(omoConfigPath);
49614
+ const content = readFileSync7(omoConfigPath, "utf-8");
49221
49615
  if (stat.size === 0 || isEmptyOrWhitespace2(content)) {
49222
49616
  writeFileSync4(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
49223
49617
  `);
@@ -49230,7 +49624,6 @@ function writeOmoConfig(installConfig) {
49230
49624
  return { success: true, configPath: omoConfigPath };
49231
49625
  }
49232
49626
  const merged = deepMergeRecord(newConfig, existing);
49233
- merged.$schema = newConfig.$schema;
49234
49627
  writeFileSync4(omoConfigPath, JSON.stringify(merged, null, 2) + `
49235
49628
  `);
49236
49629
  } catch (parseErr) {
@@ -49256,6 +49649,7 @@ function writeOmoConfig(installConfig) {
49256
49649
  }
49257
49650
  var init_write_omo_config = __esm(() => {
49258
49651
  init_shared();
49652
+ init_backup_config();
49259
49653
  init_config_context();
49260
49654
  init_ensure_config_directory_exists();
49261
49655
  init_generate_omo_config();
@@ -49346,7 +49740,7 @@ async function isOpenCodeInstalled() {
49346
49740
  const result = await findOpenCodeBinaryWithVersion();
49347
49741
  return result !== null;
49348
49742
  }
49349
- async function getOpenCodeVersion() {
49743
+ async function getOpenCodeVersion2() {
49350
49744
  const result = await findOpenCodeBinaryWithVersion();
49351
49745
  return result?.version ?? null;
49352
49746
  }
@@ -49358,10 +49752,10 @@ var init_opencode_binary = __esm(() => {
49358
49752
  });
49359
49753
 
49360
49754
  // src/cli/config-manager/detect-current-config.ts
49361
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
49755
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
49362
49756
  function detectProvidersFromOmoConfig() {
49363
- const omoConfigPath = getExistingOmoConfigPath();
49364
- if (!omoConfigPath || !existsSync8(omoConfigPath)) {
49757
+ const omoConfigPath = getOmoConfigPath();
49758
+ if (!existsSync12(omoConfigPath)) {
49365
49759
  return {
49366
49760
  hasOpenAI: true,
49367
49761
  hasOpencodeZen: true,
@@ -49371,7 +49765,7 @@ function detectProvidersFromOmoConfig() {
49371
49765
  };
49372
49766
  }
49373
49767
  try {
49374
- const content = readFileSync7(omoConfigPath, "utf-8");
49768
+ const content = readFileSync8(omoConfigPath, "utf-8");
49375
49769
  const omoConfig = parseJsonc(content);
49376
49770
  if (!omoConfig || typeof omoConfig !== "object") {
49377
49771
  return {
@@ -49399,9 +49793,16 @@ function detectProvidersFromOmoConfig() {
49399
49793
  };
49400
49794
  }
49401
49795
  }
49796
+ function isOurPlugin(plugin) {
49797
+ return plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) || plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`);
49798
+ }
49799
+ function findOurPluginEntry(plugins) {
49800
+ return plugins.find(isOurPlugin) ?? null;
49801
+ }
49402
49802
  function detectCurrentConfig() {
49403
49803
  const result = {
49404
49804
  isInstalled: false,
49805
+ installedVersion: null,
49405
49806
  hasClaude: true,
49406
49807
  isMax20: true,
49407
49808
  hasOpenAI: true,
@@ -49422,7 +49823,11 @@ function detectCurrentConfig() {
49422
49823
  }
49423
49824
  const openCodeConfig = parseResult.config;
49424
49825
  const plugins = openCodeConfig.plugin ?? [];
49425
- result.isInstalled = findManagedPluginEntry(plugins) !== null;
49826
+ const ourPluginEntry = findOurPluginEntry(plugins);
49827
+ result.isInstalled = !!ourPluginEntry;
49828
+ if (ourPluginEntry) {
49829
+ result.installedVersion = extractVersionFromPluginEntry(ourPluginEntry);
49830
+ }
49426
49831
  if (!result.isInstalled) {
49427
49832
  return result;
49428
49833
  }
@@ -49438,17 +49843,16 @@ function detectCurrentConfig() {
49438
49843
  }
49439
49844
  var init_detect_current_config = __esm(() => {
49440
49845
  init_shared();
49441
- init_plugin_identity();
49442
49846
  init_config_context();
49443
49847
  init_opencode_config_format();
49444
49848
  init_parse_opencode_config_file();
49445
49849
  });
49446
49850
 
49447
49851
  // src/cli/config-manager/bun-install.ts
49448
- import { existsSync as existsSync9 } from "fs";
49449
- import { join as join8 } from "path";
49852
+ import { existsSync as existsSync13 } from "fs";
49853
+ import { join as join12 } from "path";
49450
49854
  function getDefaultWorkspaceDir() {
49451
- return join8(getOpenCodeCacheDir(), "packages");
49855
+ return join12(getOpenCodeCacheDir(), "packages");
49452
49856
  }
49453
49857
  function readProcessOutput(stream) {
49454
49858
  if (!stream) {
@@ -49474,7 +49878,7 @@ async function runBunInstallWithDetails(options) {
49474
49878
  const outputMode = options?.outputMode ?? "pipe";
49475
49879
  const cacheDir = options?.workspaceDir ?? getDefaultWorkspaceDir();
49476
49880
  const packageJsonPath = `${cacheDir}/package.json`;
49477
- if (!existsSync9(packageJsonPath)) {
49881
+ if (!existsSync13(packageJsonPath)) {
49478
49882
  return {
49479
49883
  success: false,
49480
49884
  error: `Workspace not initialized: ${packageJsonPath} not found. OpenCode should create this on first run.`
@@ -49550,6 +49954,7 @@ var init_config_manager = __esm(() => {
49550
49954
  init_opencode_binary();
49551
49955
  init_detect_current_config();
49552
49956
  init_bun_install();
49957
+ init_backup_config();
49553
49958
  });
49554
49959
 
49555
49960
  // node_modules/sisteransi/src/index.js
@@ -49610,6 +50015,462 @@ var require_src = __commonJS((exports, module) => {
49610
50015
  module.exports = { cursor, scroll, erase, beep };
49611
50016
  });
49612
50017
 
50018
+ // node_modules/isexe/windows.js
50019
+ var require_windows = __commonJS((exports, module) => {
50020
+ module.exports = isexe;
50021
+ isexe.sync = sync;
50022
+ var fs4 = __require("fs");
50023
+ function checkPathExt(path4, options) {
50024
+ var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
50025
+ if (!pathext) {
50026
+ return true;
50027
+ }
50028
+ pathext = pathext.split(";");
50029
+ if (pathext.indexOf("") !== -1) {
50030
+ return true;
50031
+ }
50032
+ for (var i2 = 0;i2 < pathext.length; i2++) {
50033
+ var p2 = pathext[i2].toLowerCase();
50034
+ if (p2 && path4.substr(-p2.length).toLowerCase() === p2) {
50035
+ return true;
50036
+ }
50037
+ }
50038
+ return false;
50039
+ }
50040
+ function checkStat(stat, path4, options) {
50041
+ if (!stat.isSymbolicLink() && !stat.isFile()) {
50042
+ return false;
50043
+ }
50044
+ return checkPathExt(path4, options);
50045
+ }
50046
+ function isexe(path4, options, cb) {
50047
+ fs4.stat(path4, function(er, stat) {
50048
+ cb(er, er ? false : checkStat(stat, path4, options));
50049
+ });
50050
+ }
50051
+ function sync(path4, options) {
50052
+ return checkStat(fs4.statSync(path4), path4, options);
50053
+ }
50054
+ });
50055
+
50056
+ // node_modules/isexe/mode.js
50057
+ var require_mode = __commonJS((exports, module) => {
50058
+ module.exports = isexe;
50059
+ isexe.sync = sync;
50060
+ var fs4 = __require("fs");
50061
+ function isexe(path4, options, cb) {
50062
+ fs4.stat(path4, function(er, stat) {
50063
+ cb(er, er ? false : checkStat(stat, options));
50064
+ });
50065
+ }
50066
+ function sync(path4, options) {
50067
+ return checkStat(fs4.statSync(path4), options);
50068
+ }
50069
+ function checkStat(stat, options) {
50070
+ return stat.isFile() && checkMode(stat, options);
50071
+ }
50072
+ function checkMode(stat, options) {
50073
+ var mod = stat.mode;
50074
+ var uid = stat.uid;
50075
+ var gid = stat.gid;
50076
+ var myUid = options.uid !== undefined ? options.uid : process.getuid && process.getuid();
50077
+ var myGid = options.gid !== undefined ? options.gid : process.getgid && process.getgid();
50078
+ var u2 = parseInt("100", 8);
50079
+ var g2 = parseInt("010", 8);
50080
+ var o2 = parseInt("001", 8);
50081
+ var ug = u2 | g2;
50082
+ var ret = mod & o2 || mod & g2 && gid === myGid || mod & u2 && uid === myUid || mod & ug && myUid === 0;
50083
+ return ret;
50084
+ }
50085
+ });
50086
+
50087
+ // node_modules/isexe/index.js
50088
+ var require_isexe = __commonJS((exports, module) => {
50089
+ var fs4 = __require("fs");
50090
+ var core3;
50091
+ if (process.platform === "win32" || global.TESTING_WINDOWS) {
50092
+ core3 = require_windows();
50093
+ } else {
50094
+ core3 = require_mode();
50095
+ }
50096
+ module.exports = isexe;
50097
+ isexe.sync = sync;
50098
+ function isexe(path4, options, cb) {
50099
+ if (typeof options === "function") {
50100
+ cb = options;
50101
+ options = {};
50102
+ }
50103
+ if (!cb) {
50104
+ if (typeof Promise !== "function") {
50105
+ throw new TypeError("callback not provided");
50106
+ }
50107
+ return new Promise(function(resolve2, reject) {
50108
+ isexe(path4, options || {}, function(er, is) {
50109
+ if (er) {
50110
+ reject(er);
50111
+ } else {
50112
+ resolve2(is);
50113
+ }
50114
+ });
50115
+ });
50116
+ }
50117
+ core3(path4, options || {}, function(er, is) {
50118
+ if (er) {
50119
+ if (er.code === "EACCES" || options && options.ignoreErrors) {
50120
+ er = null;
50121
+ is = false;
50122
+ }
50123
+ }
50124
+ cb(er, is);
50125
+ });
50126
+ }
50127
+ function sync(path4, options) {
50128
+ try {
50129
+ return core3.sync(path4, options || {});
50130
+ } catch (er) {
50131
+ if (options && options.ignoreErrors || er.code === "EACCES") {
50132
+ return false;
50133
+ } else {
50134
+ throw er;
50135
+ }
50136
+ }
50137
+ }
50138
+ });
50139
+
50140
+ // node_modules/which/which.js
50141
+ var require_which = __commonJS((exports, module) => {
50142
+ var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
50143
+ var path4 = __require("path");
50144
+ var COLON = isWindows ? ";" : ":";
50145
+ var isexe = require_isexe();
50146
+ var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
50147
+ var getPathInfo = (cmd, opt) => {
50148
+ const colon = opt.colon || COLON;
50149
+ const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
50150
+ ...isWindows ? [process.cwd()] : [],
50151
+ ...(opt.path || process.env.PATH || "").split(colon)
50152
+ ];
50153
+ const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
50154
+ const pathExt = isWindows ? pathExtExe.split(colon) : [""];
50155
+ if (isWindows) {
50156
+ if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
50157
+ pathExt.unshift("");
50158
+ }
50159
+ return {
50160
+ pathEnv,
50161
+ pathExt,
50162
+ pathExtExe
50163
+ };
50164
+ };
50165
+ var which = (cmd, opt, cb) => {
50166
+ if (typeof opt === "function") {
50167
+ cb = opt;
50168
+ opt = {};
50169
+ }
50170
+ if (!opt)
50171
+ opt = {};
50172
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
50173
+ const found = [];
50174
+ const step = (i2) => new Promise((resolve2, reject) => {
50175
+ if (i2 === pathEnv.length)
50176
+ return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
50177
+ const ppRaw = pathEnv[i2];
50178
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
50179
+ const pCmd = path4.join(pathPart, cmd);
50180
+ const p2 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
50181
+ resolve2(subStep(p2, i2, 0));
50182
+ });
50183
+ const subStep = (p2, i2, ii) => new Promise((resolve2, reject) => {
50184
+ if (ii === pathExt.length)
50185
+ return resolve2(step(i2 + 1));
50186
+ const ext = pathExt[ii];
50187
+ isexe(p2 + ext, { pathExt: pathExtExe }, (er, is) => {
50188
+ if (!er && is) {
50189
+ if (opt.all)
50190
+ found.push(p2 + ext);
50191
+ else
50192
+ return resolve2(p2 + ext);
50193
+ }
50194
+ return resolve2(subStep(p2, i2, ii + 1));
50195
+ });
50196
+ });
50197
+ return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
50198
+ };
50199
+ var whichSync = (cmd, opt) => {
50200
+ opt = opt || {};
50201
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
50202
+ const found = [];
50203
+ for (let i2 = 0;i2 < pathEnv.length; i2++) {
50204
+ const ppRaw = pathEnv[i2];
50205
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
50206
+ const pCmd = path4.join(pathPart, cmd);
50207
+ const p2 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
50208
+ for (let j2 = 0;j2 < pathExt.length; j2++) {
50209
+ const cur = p2 + pathExt[j2];
50210
+ try {
50211
+ const is = isexe.sync(cur, { pathExt: pathExtExe });
50212
+ if (is) {
50213
+ if (opt.all)
50214
+ found.push(cur);
50215
+ else
50216
+ return cur;
50217
+ }
50218
+ } catch (ex) {}
50219
+ }
50220
+ }
50221
+ if (opt.all && found.length)
50222
+ return found;
50223
+ if (opt.nothrow)
50224
+ return null;
50225
+ throw getNotFoundError(cmd);
50226
+ };
50227
+ module.exports = which;
50228
+ which.sync = whichSync;
50229
+ });
50230
+
50231
+ // node_modules/path-key/index.js
50232
+ var require_path_key = __commonJS((exports, module) => {
50233
+ var pathKey = (options = {}) => {
50234
+ const environment = options.env || process.env;
50235
+ const platform = options.platform || process.platform;
50236
+ if (platform !== "win32") {
50237
+ return "PATH";
50238
+ }
50239
+ return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
50240
+ };
50241
+ module.exports = pathKey;
50242
+ module.exports.default = pathKey;
50243
+ });
50244
+
50245
+ // node_modules/cross-spawn/lib/util/resolveCommand.js
50246
+ var require_resolveCommand = __commonJS((exports, module) => {
50247
+ var path4 = __require("path");
50248
+ var which = require_which();
50249
+ var getPathKey = require_path_key();
50250
+ function resolveCommandAttempt(parsed, withoutPathExt) {
50251
+ const env = parsed.options.env || process.env;
50252
+ const cwd = process.cwd();
50253
+ const hasCustomCwd = parsed.options.cwd != null;
50254
+ const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
50255
+ if (shouldSwitchCwd) {
50256
+ try {
50257
+ process.chdir(parsed.options.cwd);
50258
+ } catch (err) {}
50259
+ }
50260
+ let resolved;
50261
+ try {
50262
+ resolved = which.sync(parsed.command, {
50263
+ path: env[getPathKey({ env })],
50264
+ pathExt: withoutPathExt ? path4.delimiter : undefined
50265
+ });
50266
+ } catch (e2) {} finally {
50267
+ if (shouldSwitchCwd) {
50268
+ process.chdir(cwd);
50269
+ }
50270
+ }
50271
+ if (resolved) {
50272
+ resolved = path4.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
50273
+ }
50274
+ return resolved;
50275
+ }
50276
+ function resolveCommand(parsed) {
50277
+ return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
50278
+ }
50279
+ module.exports = resolveCommand;
50280
+ });
50281
+
50282
+ // node_modules/cross-spawn/lib/util/escape.js
50283
+ var require_escape = __commonJS((exports, module) => {
50284
+ var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
50285
+ function escapeCommand(arg) {
50286
+ arg = arg.replace(metaCharsRegExp, "^$1");
50287
+ return arg;
50288
+ }
50289
+ function escapeArgument(arg, doubleEscapeMetaChars) {
50290
+ arg = `${arg}`;
50291
+ arg = arg.replace(/(?=(\\+?)?)\1"/g, "$1$1\\\"");
50292
+ arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
50293
+ arg = `"${arg}"`;
50294
+ arg = arg.replace(metaCharsRegExp, "^$1");
50295
+ if (doubleEscapeMetaChars) {
50296
+ arg = arg.replace(metaCharsRegExp, "^$1");
50297
+ }
50298
+ return arg;
50299
+ }
50300
+ exports.command = escapeCommand;
50301
+ exports.argument = escapeArgument;
50302
+ });
50303
+
50304
+ // node_modules/shebang-regex/index.js
50305
+ var require_shebang_regex = __commonJS((exports, module) => {
50306
+ module.exports = /^#!(.*)/;
50307
+ });
50308
+
50309
+ // node_modules/shebang-command/index.js
50310
+ var require_shebang_command = __commonJS((exports, module) => {
50311
+ var shebangRegex = require_shebang_regex();
50312
+ module.exports = (string4 = "") => {
50313
+ const match = string4.match(shebangRegex);
50314
+ if (!match) {
50315
+ return null;
50316
+ }
50317
+ const [path4, argument] = match[0].replace(/#! ?/, "").split(" ");
50318
+ const binary2 = path4.split("/").pop();
50319
+ if (binary2 === "env") {
50320
+ return argument;
50321
+ }
50322
+ return argument ? `${binary2} ${argument}` : binary2;
50323
+ };
50324
+ });
50325
+
50326
+ // node_modules/cross-spawn/lib/util/readShebang.js
50327
+ var require_readShebang = __commonJS((exports, module) => {
50328
+ var fs4 = __require("fs");
50329
+ var shebangCommand = require_shebang_command();
50330
+ function readShebang(command) {
50331
+ const size = 150;
50332
+ const buffer2 = Buffer.alloc(size);
50333
+ let fd;
50334
+ try {
50335
+ fd = fs4.openSync(command, "r");
50336
+ fs4.readSync(fd, buffer2, 0, size, 0);
50337
+ fs4.closeSync(fd);
50338
+ } catch (e2) {}
50339
+ return shebangCommand(buffer2.toString());
50340
+ }
50341
+ module.exports = readShebang;
50342
+ });
50343
+
50344
+ // node_modules/cross-spawn/lib/parse.js
50345
+ var require_parse = __commonJS((exports, module) => {
50346
+ var path4 = __require("path");
50347
+ var resolveCommand = require_resolveCommand();
50348
+ var escape = require_escape();
50349
+ var readShebang = require_readShebang();
50350
+ var isWin = process.platform === "win32";
50351
+ var isExecutableRegExp = /\.(?:com|exe)$/i;
50352
+ var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
50353
+ function detectShebang(parsed) {
50354
+ parsed.file = resolveCommand(parsed);
50355
+ const shebang = parsed.file && readShebang(parsed.file);
50356
+ if (shebang) {
50357
+ parsed.args.unshift(parsed.file);
50358
+ parsed.command = shebang;
50359
+ return resolveCommand(parsed);
50360
+ }
50361
+ return parsed.file;
50362
+ }
50363
+ function parseNonShell(parsed) {
50364
+ if (!isWin) {
50365
+ return parsed;
50366
+ }
50367
+ const commandFile = detectShebang(parsed);
50368
+ const needsShell = !isExecutableRegExp.test(commandFile);
50369
+ if (parsed.options.forceShell || needsShell) {
50370
+ const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
50371
+ parsed.command = path4.normalize(parsed.command);
50372
+ parsed.command = escape.command(parsed.command);
50373
+ parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
50374
+ const shellCommand = [parsed.command].concat(parsed.args).join(" ");
50375
+ parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
50376
+ parsed.command = process.env.comspec || "cmd.exe";
50377
+ parsed.options.windowsVerbatimArguments = true;
50378
+ }
50379
+ return parsed;
50380
+ }
50381
+ function parse7(command, args, options) {
50382
+ if (args && !Array.isArray(args)) {
50383
+ options = args;
50384
+ args = null;
50385
+ }
50386
+ args = args ? args.slice(0) : [];
50387
+ options = Object.assign({}, options);
50388
+ const parsed = {
50389
+ command,
50390
+ args,
50391
+ options,
50392
+ file: undefined,
50393
+ original: {
50394
+ command,
50395
+ args
50396
+ }
50397
+ };
50398
+ return options.shell ? parsed : parseNonShell(parsed);
50399
+ }
50400
+ module.exports = parse7;
50401
+ });
50402
+
50403
+ // node_modules/cross-spawn/lib/enoent.js
50404
+ var require_enoent = __commonJS((exports, module) => {
50405
+ var isWin = process.platform === "win32";
50406
+ function notFoundError(original, syscall) {
50407
+ return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
50408
+ code: "ENOENT",
50409
+ errno: "ENOENT",
50410
+ syscall: `${syscall} ${original.command}`,
50411
+ path: original.command,
50412
+ spawnargs: original.args
50413
+ });
50414
+ }
50415
+ function hookChildProcess(cp, parsed) {
50416
+ if (!isWin) {
50417
+ return;
50418
+ }
50419
+ const originalEmit = cp.emit;
50420
+ cp.emit = function(name, arg1) {
50421
+ if (name === "exit") {
50422
+ const err = verifyENOENT(arg1, parsed);
50423
+ if (err) {
50424
+ return originalEmit.call(cp, "error", err);
50425
+ }
50426
+ }
50427
+ return originalEmit.apply(cp, arguments);
50428
+ };
50429
+ }
50430
+ function verifyENOENT(status, parsed) {
50431
+ if (isWin && status === 1 && !parsed.file) {
50432
+ return notFoundError(parsed.original, "spawn");
50433
+ }
50434
+ return null;
50435
+ }
50436
+ function verifyENOENTSync(status, parsed) {
50437
+ if (isWin && status === 1 && !parsed.file) {
50438
+ return notFoundError(parsed.original, "spawnSync");
50439
+ }
50440
+ return null;
50441
+ }
50442
+ module.exports = {
50443
+ hookChildProcess,
50444
+ verifyENOENT,
50445
+ verifyENOENTSync,
50446
+ notFoundError
50447
+ };
50448
+ });
50449
+
50450
+ // node_modules/cross-spawn/index.js
50451
+ var require_cross_spawn = __commonJS((exports, module) => {
50452
+ var cp = __require("child_process");
50453
+ var parse7 = require_parse();
50454
+ var enoent = require_enoent();
50455
+ function spawn(command, args, options) {
50456
+ const parsed = parse7(command, args, options);
50457
+ const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
50458
+ enoent.hookChildProcess(spawned, parsed);
50459
+ return spawned;
50460
+ }
50461
+ function spawnSync(command, args, options) {
50462
+ const parsed = parse7(command, args, options);
50463
+ const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
50464
+ result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
50465
+ return result;
50466
+ }
50467
+ module.exports = spawn;
50468
+ module.exports.spawn = spawn;
50469
+ module.exports.sync = spawnSync;
50470
+ module.exports._parse = parse7;
50471
+ module.exports._enoent = enoent;
50472
+ });
50473
+
49613
50474
  // src/hooks/auto-update-checker/constants.ts
49614
50475
  import * as path4 from "path";
49615
50476
  import * as os3 from "os";
@@ -49618,19 +50479,23 @@ function getWindowsAppdataDir() {
49618
50479
  return null;
49619
50480
  return process.env.APPDATA ?? path4.join(os3.homedir(), "AppData", "Roaming");
49620
50481
  }
49621
- var PACKAGE_NAME2, NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_ROOT_DIR, CACHE_DIR, VERSION_FILE, USER_CONFIG_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC, INSTALLED_PACKAGE_JSON;
50482
+ function getUserConfigDir() {
50483
+ return getOpenCodeConfigDir({ binary: "opencode" });
50484
+ }
50485
+ function getUserOpencodeConfig() {
50486
+ return path4.join(getUserConfigDir(), "opencode.json");
50487
+ }
50488
+ function getUserOpencodeConfigJsonc() {
50489
+ return path4.join(getUserConfigDir(), "opencode.jsonc");
50490
+ }
50491
+ var PACKAGE_NAME2 = "oh-my-opencode", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_ROOT_DIR, CACHE_DIR, VERSION_FILE, INSTALLED_PACKAGE_JSON;
49622
50492
  var init_constants3 = __esm(() => {
49623
50493
  init_data_path();
49624
50494
  init_opencode_config_dir();
49625
- init_plugin_identity();
49626
- PACKAGE_NAME2 = PLUGIN_NAME;
49627
50495
  NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME2}/dist-tags`;
49628
50496
  CACHE_ROOT_DIR = getOpenCodeCacheDir();
49629
50497
  CACHE_DIR = path4.join(CACHE_ROOT_DIR, "packages");
49630
50498
  VERSION_FILE = path4.join(CACHE_ROOT_DIR, "version");
49631
- USER_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
49632
- USER_OPENCODE_CONFIG = path4.join(USER_CONFIG_DIR, "opencode.json");
49633
- USER_OPENCODE_CONFIG_JSONC = path4.join(USER_CONFIG_DIR, "opencode.jsonc");
49634
50499
  INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
49635
50500
  });
49636
50501
 
@@ -49638,17 +50503,18 @@ var init_constants3 = __esm(() => {
49638
50503
  import * as os4 from "os";
49639
50504
  import * as path5 from "path";
49640
50505
  function getConfigPaths(directory) {
50506
+ const userConfigDir = getUserConfigDir();
49641
50507
  const paths = [
49642
50508
  path5.join(directory, ".opencode", "opencode.json"),
49643
50509
  path5.join(directory, ".opencode", "opencode.jsonc"),
49644
- USER_OPENCODE_CONFIG,
49645
- USER_OPENCODE_CONFIG_JSONC
50510
+ getUserOpencodeConfig(),
50511
+ getUserOpencodeConfigJsonc()
49646
50512
  ];
49647
50513
  if (process.platform === "win32") {
49648
50514
  const crossPlatformDir = path5.join(os4.homedir(), ".config");
49649
50515
  const appdataDir = getWindowsAppdataDir();
49650
50516
  if (appdataDir) {
49651
- const alternateDir = USER_CONFIG_DIR === crossPlatformDir ? appdataDir : crossPlatformDir;
50517
+ const alternateDir = userConfigDir === crossPlatformDir ? appdataDir : crossPlatformDir;
49652
50518
  const alternateConfig = path5.join(alternateDir, "opencode", "opencode.json");
49653
50519
  const alternateConfigJsonc = path5.join(alternateDir, "opencode", "opencode.jsonc");
49654
50520
  if (!paths.includes(alternateConfig)) {
@@ -49765,15 +50631,17 @@ function findPluginEntry(directory) {
49765
50631
  const content = fs7.readFileSync(configPath, "utf-8");
49766
50632
  const config2 = JSON.parse(stripJsonComments(content));
49767
50633
  const plugins = config2.plugin ?? [];
49768
- const managedEntry = findManagedPluginEntry(plugins);
49769
- if (managedEntry) {
49770
- const entry = plugins[managedEntry.index];
49771
- if (entry === managedEntry.packageName) {
49772
- return { entry, isPinned: false, pinnedVersion: null, configPath };
50634
+ for (const entry of plugins) {
50635
+ for (const pluginName of MATCH_PLUGIN_NAMES) {
50636
+ if (entry === pluginName) {
50637
+ return { entry, isPinned: false, pinnedVersion: null, configPath };
50638
+ }
50639
+ if (entry.startsWith(`${pluginName}@`)) {
50640
+ const pinnedVersion = entry.slice(pluginName.length + 1);
50641
+ const isPinned = EXACT_SEMVER_REGEX.test(pinnedVersion.trim());
50642
+ return { entry, isPinned, pinnedVersion, configPath };
50643
+ }
49773
50644
  }
49774
- const pinnedVersion = entry.slice(managedEntry.packageName.length + 1);
49775
- const isPinned = EXACT_SEMVER_REGEX.test(pinnedVersion.trim());
49776
- return { entry, isPinned, pinnedVersion, configPath };
49777
50645
  }
49778
50646
  } catch {
49779
50647
  continue;
@@ -49781,11 +50649,13 @@ function findPluginEntry(directory) {
49781
50649
  }
49782
50650
  return null;
49783
50651
  }
49784
- var EXACT_SEMVER_REGEX;
50652
+ var EXACT_SEMVER_REGEX, MATCH_PLUGIN_NAMES;
49785
50653
  var init_plugin_entry = __esm(() => {
49786
- init_plugin_identity();
50654
+ init_constants3();
49787
50655
  init_config_paths();
50656
+ init_plugin_identity();
49788
50657
  EXACT_SEMVER_REGEX = /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/;
50658
+ MATCH_PLUGIN_NAMES = [PACKAGE_NAME2, PLUGIN_NAME, LEGACY_PLUGIN_NAME];
49789
50659
  });
49790
50660
 
49791
50661
  // src/hooks/auto-update-checker/checker/cached-version.ts
@@ -49825,6 +50695,23 @@ function getCachedVersion() {
49825
50695
  } catch (err) {
49826
50696
  log("[auto-update-checker] Failed to resolve version from execPath:", err);
49827
50697
  }
50698
+ try {
50699
+ const currentFile = fileURLToPath2(import.meta.url);
50700
+ let dir = path7.dirname(currentFile);
50701
+ for (let i2 = 0;i2 < 10; i2++) {
50702
+ const pkgPath = path7.join(dir, "package.json");
50703
+ if (fs8.existsSync(pkgPath)) {
50704
+ const content = fs8.readFileSync(pkgPath, "utf-8");
50705
+ const pkg = JSON.parse(content);
50706
+ if (pkg.version)
50707
+ return pkg.version;
50708
+ }
50709
+ const parent = path7.dirname(dir);
50710
+ if (parent === dir)
50711
+ break;
50712
+ dir = parent;
50713
+ }
50714
+ } catch {}
49828
50715
  return null;
49829
50716
  }
49830
50717
  var init_cached_version = __esm(() => {
@@ -50105,8 +50992,9 @@ function removeFromBunLock(packageName) {
50105
50992
  }
50106
50993
  function invalidatePackage(packageName = PACKAGE_NAME2) {
50107
50994
  try {
50995
+ const userConfigDir = getUserConfigDir();
50108
50996
  const pkgDirs = [
50109
- path9.join(USER_CONFIG_DIR, "node_modules", packageName),
50997
+ path9.join(userConfigDir, "node_modules", packageName),
50110
50998
  path9.join(CACHE_DIR, "node_modules", packageName)
50111
50999
  ];
50112
51000
  let packageRemoved = false;
@@ -50142,7 +51030,7 @@ var init_cache = __esm(() => {
50142
51030
  async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
50143
51031
  await ctx.client.tui.showToast({
50144
51032
  body: {
50145
- title: `OhMyOpenCode ${latestVersion}`,
51033
+ title: `EvilOMO ${latestVersion}`,
50146
51034
  message: getToastMessage(true, latestVersion),
50147
51035
  variant: "info",
50148
51036
  duration: 8000
@@ -50153,7 +51041,7 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
50153
51041
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
50154
51042
  await ctx.client.tui.showToast({
50155
51043
  body: {
50156
- title: "OhMyOpenCode Updated!",
51044
+ title: "EvilOMO Updated!",
50157
51045
  message: `v${oldVersion} \u2192 v${newVersion}
50158
51046
  Restart OpenCode to apply.`,
50159
51047
  variant: "success",
@@ -50167,8 +51055,8 @@ var init_update_toasts = __esm(() => {
50167
51055
  });
50168
51056
 
50169
51057
  // src/hooks/auto-update-checker/hook/background-update-check.ts
50170
- import { existsSync as existsSync20 } from "fs";
50171
- import { join as join19 } from "path";
51058
+ import { existsSync as existsSync24 } from "fs";
51059
+ import { join as join25 } from "path";
50172
51060
  function getCacheWorkspaceDir(deps) {
50173
51061
  return deps.join(deps.getOpenCodeCacheDir(), "packages");
50174
51062
  }
@@ -50225,8 +51113,8 @@ function createBackgroundUpdateCheckRunner(overrides = {}) {
50225
51113
  deps.log("[auto-update-checker] Plugin not found in config");
50226
51114
  return;
50227
51115
  }
50228
- const cachedVersion = deps.getCachedVersion();
50229
- const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion;
51116
+ const cachedVersion2 = deps.getCachedVersion();
51117
+ const currentVersion = cachedVersion2 ?? pluginInfo.pinnedVersion;
50230
51118
  if (!currentVersion) {
50231
51119
  deps.log("[auto-update-checker] No version found (cached or pinned)");
50232
51120
  return;
@@ -50286,8 +51174,8 @@ var init_background_update_check = __esm(() => {
50286
51174
  init_checker();
50287
51175
  init_update_toasts();
50288
51176
  defaultDeps = {
50289
- existsSync: existsSync20,
50290
- join: join19,
51177
+ existsSync: existsSync24,
51178
+ join: join25,
50291
51179
  runBunInstallWithDetails,
50292
51180
  log,
50293
51181
  getOpenCodeCacheDir,
@@ -50434,7 +51322,7 @@ async function showSpinnerToast(ctx, version2, message) {
50434
51322
  const spinner = SISYPHUS_SPINNER[i2 % SISYPHUS_SPINNER.length];
50435
51323
  await ctx.client.tui.showToast({
50436
51324
  body: {
50437
- title: `${spinner} OhMyOpenCode ${version2}`,
51325
+ title: `${spinner} EvilOMO ${version2}`,
50438
51326
  message,
50439
51327
  variant: "info",
50440
51328
  duration: frameInterval + 50
@@ -50496,9 +51384,9 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
50496
51384
  return;
50497
51385
  hasChecked = true;
50498
51386
  setTimeout(async () => {
50499
- const cachedVersion = getCachedVersion();
51387
+ const cachedVersion2 = getCachedVersion();
50500
51388
  const localDevVersion = getLocalDevVersion(ctx.directory);
50501
- const displayVersion = localDevVersion ?? cachedVersion;
51389
+ const displayVersion = localDevVersion ?? cachedVersion2;
50502
51390
  await showConfigErrorsIfAny(ctx);
50503
51391
  await updateAndShowConnectedProvidersCacheStatus(ctx);
50504
51392
  await refreshModelCapabilitiesOnStartup(modelCapabilities);
@@ -50567,7 +51455,7 @@ var {
50567
51455
  // package.json
50568
51456
  var package_default = {
50569
51457
  name: "evil-omo",
50570
- version: "3.15.2",
51458
+ version: "3.16.0",
50571
51459
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
50572
51460
  main: "./dist/index.js",
50573
51461
  types: "dist/index.d.ts",
@@ -50626,8 +51514,8 @@ var package_default = {
50626
51514
  "@clack/prompts": "^0.11.0",
50627
51515
  "@code-yeongyu/comment-checker": "^0.7.0",
50628
51516
  "@modelcontextprotocol/sdk": "^1.25.2",
50629
- "@opencode-ai/plugin": "^1.2.24",
50630
- "@opencode-ai/sdk": "^1.2.24",
51517
+ "@opencode-ai/plugin": "^1.4.0",
51518
+ "@opencode-ai/sdk": "^1.4.0",
50631
51519
  commander: "^14.0.2",
50632
51520
  "detect-libc": "^2.0.0",
50633
51521
  diff: "^8.0.3",
@@ -50636,7 +51524,7 @@ var package_default = {
50636
51524
  picocolors: "^1.1.1",
50637
51525
  picomatch: "^4.0.2",
50638
51526
  "vscode-jsonrpc": "^8.2.0",
50639
- zod: "^4.1.8"
51527
+ zod: "^4.3.0"
50640
51528
  },
50641
51529
  devDependencies: {
50642
51530
  "@types/js-yaml": "^4.0.9",
@@ -50645,21 +51533,19 @@ var package_default = {
50645
51533
  typescript: "^5.7.3"
50646
51534
  },
50647
51535
  optionalDependencies: {
50648
- "evil-omo-darwin-arm64": "3.15.2",
50649
- "evil-omo-darwin-x64": "3.15.2",
50650
- "evil-omo-darwin-x64-baseline": "3.15.2",
50651
- "evil-omo-linux-x64": "3.15.2",
50652
- "evil-omo-linux-x64-baseline": "3.15.2",
50653
- "evil-omo-linux-arm64": "3.15.2",
50654
- "evil-omo-linux-x64-musl": "3.15.2",
50655
- "evil-omo-linux-x64-musl-baseline": "3.15.2",
50656
- "evil-omo-linux-arm64-musl": "3.15.2",
50657
- "evil-omo-windows-x64": "3.15.2",
50658
- "evil-omo-windows-x64-baseline": "3.15.2"
50659
- },
50660
- overrides: {
50661
- "@opencode-ai/sdk": "^1.2.24"
51536
+ "evil-omo-darwin-arm64": "3.16.0",
51537
+ "evil-omo-darwin-x64": "3.16.0",
51538
+ "evil-omo-darwin-x64-baseline": "3.16.0",
51539
+ "evil-omo-linux-x64": "3.16.0",
51540
+ "evil-omo-linux-x64-baseline": "3.16.0",
51541
+ "evil-omo-linux-arm64": "3.16.0",
51542
+ "evil-omo-linux-x64-musl": "3.16.0",
51543
+ "evil-omo-linux-x64-musl-baseline": "3.16.0",
51544
+ "evil-omo-linux-arm64-musl": "3.16.0",
51545
+ "evil-omo-windows-x64": "3.16.0",
51546
+ "evil-omo-windows-x64-baseline": "3.16.0"
50662
51547
  },
51548
+ overrides: {},
50663
51549
  trustedDependencies: [
50664
51550
  "@ast-grep/cli",
50665
51551
  "@ast-grep/napi",
@@ -50668,8 +51554,9 @@ var package_default = {
50668
51554
  };
50669
51555
 
50670
51556
  // src/cli/cli-installer.ts
51557
+ init_shared();
50671
51558
  init_config_manager();
50672
- var import_picocolors2 = __toESM(require_picocolors(), 1);
51559
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
50673
51560
 
50674
51561
  // src/cli/install-validators.ts
50675
51562
  var import_picocolors = __toESM(require_picocolors(), 1);
@@ -50816,6 +51703,56 @@ function detectedToInitialValues(detected) {
50816
51703
  };
50817
51704
  }
50818
51705
 
51706
+ // src/cli/doctor/constants.ts
51707
+ init_shared();
51708
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
51709
+ var SYMBOLS2 = {
51710
+ check: import_picocolors2.default.green("\u2713"),
51711
+ cross: import_picocolors2.default.red("\u2717"),
51712
+ warn: import_picocolors2.default.yellow("\u26A0"),
51713
+ info: import_picocolors2.default.blue("\u2139"),
51714
+ arrow: import_picocolors2.default.cyan("\u2192"),
51715
+ bullet: import_picocolors2.default.dim("\u2022"),
51716
+ skip: import_picocolors2.default.dim("\u25CB")
51717
+ };
51718
+ var STATUS_COLORS = {
51719
+ pass: import_picocolors2.default.green,
51720
+ fail: import_picocolors2.default.red,
51721
+ warn: import_picocolors2.default.yellow,
51722
+ skip: import_picocolors2.default.dim
51723
+ };
51724
+ var CHECK_IDS = {
51725
+ SYSTEM: "system",
51726
+ CONFIG: "config",
51727
+ TOOLS: "tools",
51728
+ MODELS: "models"
51729
+ };
51730
+ var CHECK_NAMES = {
51731
+ [CHECK_IDS.SYSTEM]: "System",
51732
+ [CHECK_IDS.CONFIG]: "Configuration",
51733
+ [CHECK_IDS.TOOLS]: "Tools",
51734
+ [CHECK_IDS.MODELS]: "Models"
51735
+ };
51736
+ var EXIT_CODES = {
51737
+ SUCCESS: 0,
51738
+ FAILURE: 1
51739
+ };
51740
+ var MIN_OPENCODE_VERSION = "1.4.0";
51741
+ var PACKAGE_NAME = PLUGIN_NAME;
51742
+ var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
51743
+
51744
+ // src/cli/minimum-opencode-version.ts
51745
+ init_opencode_version();
51746
+ function getUnsupportedOpenCodeVersionMessage(openCodeVersion) {
51747
+ if (!openCodeVersion) {
51748
+ return null;
51749
+ }
51750
+ if (compareVersions(openCodeVersion, MIN_OPENCODE_VERSION) >= 0) {
51751
+ return null;
51752
+ }
51753
+ return `Detected OpenCode ${openCodeVersion}, but ${MIN_OPENCODE_VERSION}+ is required. Update OpenCode, then rerun the installer.`;
51754
+ }
51755
+
50819
51756
  // src/cli/cli-installer.ts
50820
51757
  async function runCliInstaller(args, version) {
50821
51758
  const validation = validateNonTuiArgs(args);
@@ -50826,7 +51763,7 @@ async function runCliInstaller(args, version) {
50826
51763
  console.log(` ${SYMBOLS.bullet} ${err}`);
50827
51764
  }
50828
51765
  console.log();
50829
- printInfo("Usage: bunx evil-omo install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>");
51766
+ printInfo(`Usage: bunx ${PLUGIN_NAME} install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>`);
50830
51767
  console.log();
50831
51768
  return 1;
50832
51769
  }
@@ -50837,65 +51774,60 @@ async function runCliInstaller(args, version) {
50837
51774
  let step = 1;
50838
51775
  printStep(step++, totalSteps, "Checking OpenCode installation...");
50839
51776
  const installed = await isOpenCodeInstalled();
50840
- const openCodeVersion = await getOpenCodeVersion();
51777
+ const openCodeVersion = await getOpenCodeVersion2();
50841
51778
  if (!installed) {
50842
51779
  printWarning("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.");
50843
51780
  printInfo("Visit https://opencode.ai/docs for installation instructions");
50844
51781
  } else {
50845
51782
  printSuccess(`OpenCode ${openCodeVersion ?? ""} detected`);
51783
+ const unsupportedVersionMessage = getUnsupportedOpenCodeVersionMessage(openCodeVersion);
51784
+ if (unsupportedVersionMessage) {
51785
+ printWarning(unsupportedVersionMessage);
51786
+ return 1;
51787
+ }
50846
51788
  }
50847
51789
  if (isUpdate) {
50848
51790
  const initial = detectedToInitialValues(detected);
50849
51791
  printInfo(`Current config: Claude=${initial.claude}, Gemini=${initial.gemini}`);
50850
51792
  }
50851
51793
  const config = argsToConfig(args);
50852
- printStep(step++, totalSteps, "Adding evil-omo plugin...");
51794
+ printStep(step++, totalSteps, `Adding ${PLUGIN_NAME} plugin...`);
50853
51795
  const pluginResult = await addPluginToOpenCodeConfig(version);
50854
51796
  if (!pluginResult.success) {
50855
51797
  printError(`Failed: ${pluginResult.error}`);
50856
51798
  return 1;
50857
51799
  }
50858
- printSuccess(`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${import_picocolors2.default.dim(pluginResult.configPath)}`);
50859
- printStep(step++, totalSteps, "Writing evil-omo configuration...");
51800
+ printSuccess(`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${import_picocolors3.default.dim(pluginResult.configPath)}`);
51801
+ printStep(step++, totalSteps, `Writing ${PLUGIN_NAME} configuration...`);
50860
51802
  const omoResult = writeOmoConfig(config);
50861
51803
  if (!omoResult.success) {
50862
51804
  printError(`Failed: ${omoResult.error}`);
50863
51805
  return 1;
50864
51806
  }
50865
- printSuccess(`Config written ${SYMBOLS.arrow} ${import_picocolors2.default.dim(omoResult.configPath)}`);
51807
+ printSuccess(`Config written ${SYMBOLS.arrow} ${import_picocolors3.default.dim(omoResult.configPath)}`);
50866
51808
  printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
50867
51809
  if (!config.hasClaude) {
50868
- console.log();
50869
- console.log(import_picocolors2.default.bgRed(import_picocolors2.default.white(import_picocolors2.default.bold(" CRITICAL WARNING "))));
50870
- console.log();
50871
- console.log(import_picocolors2.default.red(import_picocolors2.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
50872
- console.log(import_picocolors2.default.red(" Without Claude, you may experience significantly degraded performance:"));
50873
- console.log(import_picocolors2.default.dim(" \u2022 Reduced orchestration quality"));
50874
- console.log(import_picocolors2.default.dim(" \u2022 Weaker tool selection and delegation"));
50875
- console.log(import_picocolors2.default.dim(" \u2022 Less reliable task completion"));
50876
- console.log();
50877
- console.log(import_picocolors2.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
50878
- console.log();
51810
+ printInfo("Note: Sisyphus agent performs best with Claude Opus 4.5+. " + "Other models work but may have reduced orchestration quality.");
50879
51811
  }
50880
51812
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
50881
51813
  printWarning("No model providers configured. Using opencode/big-pickle as fallback.");
50882
51814
  }
50883
- console.log(`${SYMBOLS.star} ${import_picocolors2.default.bold(import_picocolors2.default.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`);
50884
- console.log(` Run ${import_picocolors2.default.cyan("opencode")} to start!`);
51815
+ console.log(`${SYMBOLS.star} ${import_picocolors3.default.bold(import_picocolors3.default.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`);
51816
+ console.log(` Run ${import_picocolors3.default.cyan("opencode")} to start!`);
50885
51817
  console.log();
50886
- printBox(`${import_picocolors2.default.bold("Pro Tip:")} Include ${import_picocolors2.default.cyan("ultrawork")} (or ${import_picocolors2.default.cyan("ulw")}) in your prompt.
50887
- ` + `All features work like magic\u2014parallel agents, background tasks,
51818
+ printBox(`${import_picocolors3.default.bold("Pro Tip:")} Include ${import_picocolors3.default.cyan("ultrawork")} (or ${import_picocolors3.default.cyan("ulw")}) in your prompt.
51819
+ ` + `All features work like magic-parallel agents, background tasks,
50888
51820
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
50889
- console.log(`${SYMBOLS.star} ${import_picocolors2.default.yellow("If you found this helpful, consider starring the repo!")}`);
50890
- console.log(` ${import_picocolors2.default.dim("gh api --silent --method PUT /user/starred/D4ch1au/evil-oh-my-openagent >/dev/null 2>&1 || true")}`);
51821
+ console.log(`${SYMBOLS.star} ${import_picocolors3.default.yellow("If you found this helpful, consider starring the repo!")}`);
51822
+ console.log(` ${import_picocolors3.default.dim("gh api --silent --method PUT /user/starred/D4ch1au/evil-oh-my-openagent >/dev/null 2>&1 || true")}`);
50891
51823
  console.log();
50892
- console.log(import_picocolors2.default.dim("oMoMoMoMo... Enjoy!"));
51824
+ console.log(import_picocolors3.default.dim("oMoMoMoMo... Enjoy!"));
50893
51825
  console.log();
50894
51826
  if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
50895
- printBox(`Run ${import_picocolors2.default.cyan("opencode auth login")} and select your provider:
50896
- ` + (config.hasClaude ? ` ${SYMBOLS.bullet} Anthropic ${import_picocolors2.default.gray("\u2192 Claude Pro/Max")}
50897
- ` : "") + (config.hasGemini ? ` ${SYMBOLS.bullet} Google ${import_picocolors2.default.gray("\u2192 Gemini")}
50898
- ` : "") + (config.hasCopilot ? ` ${SYMBOLS.bullet} GitHub ${import_picocolors2.default.gray("\u2192 Copilot")}` : ""), "Authenticate Your Providers");
51827
+ printBox(`Run ${import_picocolors3.default.cyan("opencode auth login")} and select your provider:
51828
+ ` + (config.hasClaude ? ` ${SYMBOLS.bullet} Anthropic ${import_picocolors3.default.gray("\u2192 Claude Pro/Max")}
51829
+ ` : "") + (config.hasGemini ? ` ${SYMBOLS.bullet} Google ${import_picocolors3.default.gray("\u2192 Gemini")}
51830
+ ` : "") + (config.hasCopilot ? ` ${SYMBOLS.bullet} GitHub ${import_picocolors3.default.gray("\u2192 Copilot")}` : ""), "Authenticate Your Providers");
50899
51831
  }
50900
51832
  return 0;
50901
51833
  }
@@ -51290,7 +52222,7 @@ class LD extends x {
51290
52222
  }
51291
52223
 
51292
52224
  // node_modules/@clack/prompts/dist/index.mjs
51293
- var import_picocolors3 = __toESM(require_picocolors(), 1);
52225
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
51294
52226
  var import_sisteransi2 = __toESM(require_src(), 1);
51295
52227
  import y2 from "process";
51296
52228
  function ce() {
@@ -51323,13 +52255,13 @@ var b2 = (t) => {
51323
52255
  switch (t) {
51324
52256
  case "initial":
51325
52257
  case "active":
51326
- return import_picocolors3.default.cyan(le);
52258
+ return import_picocolors4.default.cyan(le);
51327
52259
  case "cancel":
51328
- return import_picocolors3.default.red(L2);
52260
+ return import_picocolors4.default.red(L2);
51329
52261
  case "error":
51330
- return import_picocolors3.default.yellow(W2);
52262
+ return import_picocolors4.default.yellow(W2);
51331
52263
  case "submit":
51332
- return import_picocolors3.default.green(C);
52264
+ return import_picocolors4.default.green(C);
51333
52265
  }
51334
52266
  };
51335
52267
  var G2 = (t) => {
@@ -51339,7 +52271,7 @@ var G2 = (t) => {
51339
52271
  const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
51340
52272
  return r2.slice(l2, l2 + a).map((p2, v, f) => {
51341
52273
  const j2 = v === 0 && $2, E = v === f.length - 1 && g2;
51342
- return j2 || E ? import_picocolors3.default.dim("...") : i2(p2, v + l2 === n);
52274
+ return j2 || E ? import_picocolors4.default.dim("...") : i2(p2, v + l2 === n);
51343
52275
  });
51344
52276
  };
51345
52277
  var ve = (t) => {
@@ -51347,29 +52279,29 @@ var ve = (t) => {
51347
52279
  const s = r2.label ?? String(r2.value);
51348
52280
  switch (i2) {
51349
52281
  case "selected":
51350
- return `${import_picocolors3.default.dim(s)}`;
52282
+ return `${import_picocolors4.default.dim(s)}`;
51351
52283
  case "active":
51352
- return `${import_picocolors3.default.green(k2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}`;
52284
+ return `${import_picocolors4.default.green(k2)} ${s} ${r2.hint ? import_picocolors4.default.dim(`(${r2.hint})`) : ""}`;
51353
52285
  case "cancelled":
51354
- return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
52286
+ return `${import_picocolors4.default.strikethrough(import_picocolors4.default.dim(s))}`;
51355
52287
  default:
51356
- return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
52288
+ return `${import_picocolors4.default.dim(P2)} ${import_picocolors4.default.dim(s)}`;
51357
52289
  }
51358
52290
  };
51359
52291
  return new LD({ options: t.options, initialValue: t.initialValue, render() {
51360
- const r2 = `${import_picocolors3.default.gray(o)}
52292
+ const r2 = `${import_picocolors4.default.gray(o)}
51361
52293
  ${b2(this.state)} ${t.message}
51362
52294
  `;
51363
52295
  switch (this.state) {
51364
52296
  case "submit":
51365
- return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
52297
+ return `${r2}${import_picocolors4.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
51366
52298
  case "cancel":
51367
- return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
51368
- ${import_picocolors3.default.gray(o)}`;
52299
+ return `${r2}${import_picocolors4.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
52300
+ ${import_picocolors4.default.gray(o)}`;
51369
52301
  default:
51370
- return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i2, s) => n(i2, s ? "active" : "inactive") }).join(`
51371
- ${import_picocolors3.default.cyan(o)} `)}
51372
- ${import_picocolors3.default.cyan(d2)}
52302
+ return `${r2}${import_picocolors4.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i2, s) => n(i2, s ? "active" : "inactive") }).join(`
52303
+ ${import_picocolors4.default.cyan(o)} `)}
52304
+ ${import_picocolors4.default.cyan(d2)}
51373
52305
  `;
51374
52306
  }
51375
52307
  } }).prompt();
@@ -51381,53 +52313,53 @@ ${t}
51381
52313
  `), i2 = S2(n).length, s = Math.max(r2.reduce((a, l2) => {
51382
52314
  const $2 = S2(l2);
51383
52315
  return $2.length > a ? $2.length : a;
51384
- }, 0), i2) + 2, c = r2.map((a) => `${import_picocolors3.default.gray(o)} ${import_picocolors3.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors3.default.gray(o)}`).join(`
52316
+ }, 0), i2) + 2, c = r2.map((a) => `${import_picocolors4.default.gray(o)} ${import_picocolors4.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors4.default.gray(o)}`).join(`
51385
52317
  `);
51386
- process.stdout.write(`${import_picocolors3.default.gray(o)}
51387
- ${import_picocolors3.default.green(C)} ${import_picocolors3.default.reset(n)} ${import_picocolors3.default.gray(_2.repeat(Math.max(s - i2 - 1, 1)) + me)}
52318
+ process.stdout.write(`${import_picocolors4.default.gray(o)}
52319
+ ${import_picocolors4.default.green(C)} ${import_picocolors4.default.reset(n)} ${import_picocolors4.default.gray(_2.repeat(Math.max(s - i2 - 1, 1)) + me)}
51388
52320
  ${c}
51389
- ${import_picocolors3.default.gray(de + _2.repeat(s + 2) + pe)}
52321
+ ${import_picocolors4.default.gray(de + _2.repeat(s + 2) + pe)}
51390
52322
  `);
51391
52323
  };
51392
52324
  var xe = (t = "") => {
51393
- process.stdout.write(`${import_picocolors3.default.gray(d2)} ${import_picocolors3.default.red(t)}
52325
+ process.stdout.write(`${import_picocolors4.default.gray(d2)} ${import_picocolors4.default.red(t)}
51394
52326
 
51395
52327
  `);
51396
52328
  };
51397
52329
  var Ie = (t = "") => {
51398
- process.stdout.write(`${import_picocolors3.default.gray(ue)} ${t}
52330
+ process.stdout.write(`${import_picocolors4.default.gray(ue)} ${t}
51399
52331
  `);
51400
52332
  };
51401
52333
  var Se = (t = "") => {
51402
- process.stdout.write(`${import_picocolors3.default.gray(o)}
51403
- ${import_picocolors3.default.gray(d2)} ${t}
52334
+ process.stdout.write(`${import_picocolors4.default.gray(o)}
52335
+ ${import_picocolors4.default.gray(d2)} ${t}
51404
52336
 
51405
52337
  `);
51406
52338
  };
51407
- var M2 = { message: (t = "", { symbol: n = import_picocolors3.default.gray(o) } = {}) => {
51408
- const r2 = [`${import_picocolors3.default.gray(o)}`];
52339
+ var M2 = { message: (t = "", { symbol: n = import_picocolors4.default.gray(o) } = {}) => {
52340
+ const r2 = [`${import_picocolors4.default.gray(o)}`];
51409
52341
  if (t) {
51410
52342
  const [i2, ...s] = t.split(`
51411
52343
  `);
51412
- r2.push(`${n} ${i2}`, ...s.map((c) => `${import_picocolors3.default.gray(o)} ${c}`));
52344
+ r2.push(`${n} ${i2}`, ...s.map((c) => `${import_picocolors4.default.gray(o)} ${c}`));
51413
52345
  }
51414
52346
  process.stdout.write(`${r2.join(`
51415
52347
  `)}
51416
52348
  `);
51417
52349
  }, info: (t) => {
51418
- M2.message(t, { symbol: import_picocolors3.default.blue(q) });
52350
+ M2.message(t, { symbol: import_picocolors4.default.blue(q) });
51419
52351
  }, success: (t) => {
51420
- M2.message(t, { symbol: import_picocolors3.default.green(D) });
52352
+ M2.message(t, { symbol: import_picocolors4.default.green(D) });
51421
52353
  }, step: (t) => {
51422
- M2.message(t, { symbol: import_picocolors3.default.green(C) });
52354
+ M2.message(t, { symbol: import_picocolors4.default.green(C) });
51423
52355
  }, warn: (t) => {
51424
- M2.message(t, { symbol: import_picocolors3.default.yellow(U) });
52356
+ M2.message(t, { symbol: import_picocolors4.default.yellow(U) });
51425
52357
  }, warning: (t) => {
51426
52358
  M2.warn(t);
51427
52359
  }, error: (t) => {
51428
- M2.message(t, { symbol: import_picocolors3.default.red(K2) });
52360
+ M2.message(t, { symbol: import_picocolors4.default.red(K2) });
51429
52361
  } };
51430
- var J2 = `${import_picocolors3.default.gray(o)} `;
52362
+ var J2 = `${import_picocolors4.default.gray(o)} `;
51431
52363
  var Y2 = ({ indicator: t = "dots" } = {}) => {
51432
52364
  const n = V2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], r2 = V2 ? 80 : 120, i2 = process.env.CI === "true";
51433
52365
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
@@ -51450,14 +52382,14 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51450
52382
  const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
51451
52383
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
51452
52384
  }, H = (m2 = "") => {
51453
- a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors3.default.gray(o)}
52385
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors4.default.gray(o)}
51454
52386
  `);
51455
52387
  let h2 = 0, w2 = 0;
51456
52388
  j2(), c = setInterval(() => {
51457
52389
  if (i2 && l2 === $2)
51458
52390
  return;
51459
52391
  B2(), $2 = l2;
51460
- const I2 = import_picocolors3.default.magenta(n[h2]);
52392
+ const I2 = import_picocolors4.default.magenta(n[h2]);
51461
52393
  if (i2)
51462
52394
  process.stdout.write(`${I2} ${l2}...`);
51463
52395
  else if (t === "timer")
@@ -51470,7 +52402,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51470
52402
  }, r2);
51471
52403
  }, N2 = (m2 = "", h2 = 0) => {
51472
52404
  a = false, clearInterval(c), B2();
51473
- const w2 = h2 === 0 ? import_picocolors3.default.green(C) : h2 === 1 ? import_picocolors3.default.red(L2) : import_picocolors3.default.red(W2);
52405
+ const w2 = h2 === 0 ? import_picocolors4.default.green(C) : h2 === 1 ? import_picocolors4.default.red(L2) : import_picocolors4.default.red(W2);
51474
52406
  l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
51475
52407
  `) : process.stdout.write(`${w2} ${l2}
51476
52408
  `), E(), s();
@@ -51481,8 +52413,9 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51481
52413
  };
51482
52414
 
51483
52415
  // src/cli/tui-installer.ts
52416
+ init_shared();
51484
52417
  init_config_manager();
51485
- var import_picocolors4 = __toESM(require_picocolors(), 1);
52418
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
51486
52419
 
51487
52420
  // src/cli/tui-install-prompts.ts
51488
52421
  async function selectOrCancel(params) {
@@ -51603,7 +52536,7 @@ async function runTuiInstaller(args, version) {
51603
52536
  }
51604
52537
  const detected = detectCurrentConfig();
51605
52538
  const isUpdate = detected.isInstalled;
51606
- Ie(import_picocolors4.default.bgMagenta(import_picocolors4.default.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... ")));
52539
+ Ie(import_picocolors5.default.bgMagenta(import_picocolors5.default.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... ")));
51607
52540
  if (isUpdate) {
51608
52541
  const initial = detectedToInitialValues(detected);
51609
52542
  M2.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`);
@@ -51611,70 +52544,67 @@ async function runTuiInstaller(args, version) {
51611
52544
  const spinner = Y2();
51612
52545
  spinner.start("Checking OpenCode installation");
51613
52546
  const installed = await isOpenCodeInstalled();
51614
- const openCodeVersion = await getOpenCodeVersion();
52547
+ const openCodeVersion = await getOpenCodeVersion2();
51615
52548
  if (!installed) {
51616
- spinner.stop(`OpenCode binary not found ${import_picocolors4.default.yellow("[!]")}`);
52549
+ spinner.stop(`OpenCode binary not found ${import_picocolors5.default.yellow("[!]")}`);
51617
52550
  M2.warn("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.");
51618
52551
  Me("Visit https://opencode.ai/docs for installation instructions", "Installation Guide");
51619
52552
  } else {
51620
- spinner.stop(`OpenCode ${openCodeVersion ?? "installed"} ${import_picocolors4.default.green("[OK]")}`);
52553
+ spinner.stop(`OpenCode ${openCodeVersion ?? "installed"} ${import_picocolors5.default.green("[OK]")}`);
52554
+ const unsupportedVersionMessage = getUnsupportedOpenCodeVersionMessage(openCodeVersion);
52555
+ if (unsupportedVersionMessage) {
52556
+ M2.warn(unsupportedVersionMessage);
52557
+ Se(import_picocolors5.default.red("Installation blocked."));
52558
+ return 1;
52559
+ }
51621
52560
  }
51622
52561
  const config = await promptInstallConfig(detected);
51623
52562
  if (!config)
51624
52563
  return 1;
51625
- spinner.start("Adding evil-omo to OpenCode config");
52564
+ spinner.start(`Adding ${PLUGIN_NAME} to OpenCode config`);
51626
52565
  const pluginResult = await addPluginToOpenCodeConfig(version);
51627
52566
  if (!pluginResult.success) {
51628
52567
  spinner.stop(`Failed to add plugin: ${pluginResult.error}`);
51629
- Se(import_picocolors4.default.red("Installation failed."));
52568
+ Se(import_picocolors5.default.red("Installation failed."));
51630
52569
  return 1;
51631
52570
  }
51632
- spinner.stop(`Plugin added to ${import_picocolors4.default.cyan(pluginResult.configPath)}`);
51633
- spinner.start("Writing evil-omo configuration");
52571
+ spinner.stop(`Plugin added to ${import_picocolors5.default.cyan(pluginResult.configPath)}`);
52572
+ spinner.start(`Writing ${PLUGIN_NAME} configuration`);
51634
52573
  const omoResult = writeOmoConfig(config);
51635
52574
  if (!omoResult.success) {
51636
52575
  spinner.stop(`Failed to write config: ${omoResult.error}`);
51637
- Se(import_picocolors4.default.red("Installation failed."));
52576
+ Se(import_picocolors5.default.red("Installation failed."));
51638
52577
  return 1;
51639
52578
  }
51640
- spinner.stop(`Config written to ${import_picocolors4.default.cyan(omoResult.configPath)}`);
52579
+ spinner.stop(`Config written to ${import_picocolors5.default.cyan(omoResult.configPath)}`);
51641
52580
  if (!config.hasClaude) {
51642
- console.log();
51643
- console.log(import_picocolors4.default.bgRed(import_picocolors4.default.white(import_picocolors4.default.bold(" CRITICAL WARNING "))));
51644
- console.log();
51645
- console.log(import_picocolors4.default.red(import_picocolors4.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
51646
- console.log(import_picocolors4.default.red(" Without Claude, you may experience significantly degraded performance:"));
51647
- console.log(import_picocolors4.default.dim(" \u2022 Reduced orchestration quality"));
51648
- console.log(import_picocolors4.default.dim(" \u2022 Weaker tool selection and delegation"));
51649
- console.log(import_picocolors4.default.dim(" \u2022 Less reliable task completion"));
51650
- console.log();
51651
- console.log(import_picocolors4.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
51652
- console.log();
52581
+ M2.info(`${import_picocolors5.default.bold("Note:")} Sisyphus agent performs best with Claude Opus 4.5+.
52582
+ ` + `Other models work but may have reduced orchestration quality.`);
51653
52583
  }
51654
52584
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
51655
52585
  M2.warn("No model providers configured. Using opencode/big-pickle as fallback.");
51656
52586
  }
51657
52587
  Me(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
51658
- M2.success(import_picocolors4.default.bold(isUpdate ? "Configuration updated!" : "Installation complete!"));
51659
- M2.message(`Run ${import_picocolors4.default.cyan("opencode")} to start!`);
51660
- Me(`Include ${import_picocolors4.default.cyan("ultrawork")} (or ${import_picocolors4.default.cyan("ulw")}) in your prompt.
51661
- ` + `All features work like magic\u2014parallel agents, background tasks,
52588
+ M2.success(import_picocolors5.default.bold(isUpdate ? "Configuration updated!" : "Installation complete!"));
52589
+ M2.message(`Run ${import_picocolors5.default.cyan("opencode")} to start!`);
52590
+ Me(`Include ${import_picocolors5.default.cyan("ultrawork")} (or ${import_picocolors5.default.cyan("ulw")}) in your prompt.
52591
+ ` + `All features work like magic-parallel agents, background tasks,
51662
52592
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
51663
- M2.message(`${import_picocolors4.default.yellow("\u2605")} If you found this helpful, consider starring the repo!`);
51664
- M2.message(` ${import_picocolors4.default.dim("gh api --silent --method PUT /user/starred/D4ch1au/evil-oh-my-openagent >/dev/null 2>&1 || true")}`);
51665
- Se(import_picocolors4.default.green("oMoMoMoMo... Enjoy!"));
52593
+ M2.message(`${import_picocolors5.default.yellow("\u2605")} If you found this helpful, consider starring the repo!`);
52594
+ M2.message(` ${import_picocolors5.default.dim("gh api --silent --method PUT /user/starred/D4ch1au/evil-oh-my-openagent >/dev/null 2>&1 || true")}`);
52595
+ Se(import_picocolors5.default.green("oMoMoMoMo... Enjoy!"));
51666
52596
  if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
51667
52597
  const providers = [];
51668
52598
  if (config.hasClaude)
51669
- providers.push(`Anthropic ${import_picocolors4.default.gray("\u2192 Claude Pro/Max")}`);
52599
+ providers.push(`Anthropic ${import_picocolors5.default.gray("\u2192 Claude Pro/Max")}`);
51670
52600
  if (config.hasGemini)
51671
- providers.push(`Google ${import_picocolors4.default.gray("\u2192 Gemini")}`);
52601
+ providers.push(`Google ${import_picocolors5.default.gray("\u2192 Gemini")}`);
51672
52602
  if (config.hasCopilot)
51673
- providers.push(`GitHub ${import_picocolors4.default.gray("\u2192 Copilot")}`);
52603
+ providers.push(`GitHub ${import_picocolors5.default.gray("\u2192 Copilot")}`);
51674
52604
  console.log();
51675
- console.log(import_picocolors4.default.bold("Authenticate Your Providers"));
52605
+ console.log(import_picocolors5.default.bold("Authenticate Your Providers"));
51676
52606
  console.log();
51677
- console.log(` Run ${import_picocolors4.default.cyan("opencode auth login")} and select:`);
52607
+ console.log(` Run ${import_picocolors5.default.cyan("opencode auth login")} and select:`);
51678
52608
  for (const provider of providers) {
51679
52609
  console.log(` ${SYMBOLS.bullet} ${provider}`);
51680
52610
  }
@@ -51690,7 +52620,7 @@ async function install(args) {
51690
52620
  }
51691
52621
 
51692
52622
  // src/cli/run/runner.ts
51693
- var import_picocolors14 = __toESM(require_picocolors(), 1);
52623
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
51694
52624
 
51695
52625
  // src/cli/run/event-state.ts
51696
52626
  function createEventState() {
@@ -51724,7 +52654,7 @@ function createEventState() {
51724
52654
  };
51725
52655
  }
51726
52656
  // src/cli/run/event-formatting.ts
51727
- var import_picocolors5 = __toESM(require_picocolors(), 1);
52657
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
51728
52658
  function serializeError(error) {
51729
52659
  if (!error)
51730
52660
  return "Unknown error";
@@ -51768,10 +52698,10 @@ function getSessionTag(ctx, payload) {
51768
52698
  const sessionID = props?.sessionID ?? props?.sessionId ?? info?.sessionID ?? info?.sessionId ?? part?.sessionID ?? part?.sessionId;
51769
52699
  const isMainSession = sessionID === ctx.sessionID;
51770
52700
  if (isMainSession)
51771
- return import_picocolors5.default.green("[MAIN]");
52701
+ return import_picocolors6.default.green("[MAIN]");
51772
52702
  if (sessionID)
51773
- return import_picocolors5.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
51774
- return import_picocolors5.default.dim("[system]");
52703
+ return import_picocolors6.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
52704
+ return import_picocolors6.default.dim("[system]");
51775
52705
  }
51776
52706
  function logEventVerbose(ctx, payload) {
51777
52707
  const sessionTag = getSessionTag(ctx, payload);
@@ -51780,7 +52710,7 @@ function logEventVerbose(ctx, payload) {
51780
52710
  case "session.idle":
51781
52711
  case "session.status": {
51782
52712
  const status = props?.status?.type ?? "idle";
51783
- console.error(import_picocolors5.default.dim(`${sessionTag} ${payload.type}: ${status}`));
52713
+ console.error(import_picocolors6.default.dim(`${sessionTag} ${payload.type}: ${status}`));
51784
52714
  break;
51785
52715
  }
51786
52716
  case "message.part.updated": {
@@ -51788,10 +52718,10 @@ function logEventVerbose(ctx, payload) {
51788
52718
  const part = partProps?.part;
51789
52719
  if (part?.type === "tool") {
51790
52720
  const status = part.state?.status ?? "unknown";
51791
- console.error(import_picocolors5.default.dim(`${sessionTag} message.part (tool): ${part.tool ?? part.name ?? "?"} [${status}]`));
52721
+ console.error(import_picocolors6.default.dim(`${sessionTag} message.part (tool): ${part.tool ?? part.name ?? "?"} [${status}]`));
51792
52722
  } else if (part?.type === "text" && part.text) {
51793
52723
  const preview = part.text.slice(0, 80).replace(/\n/g, "\\n");
51794
- console.error(import_picocolors5.default.dim(`${sessionTag} message.part (text): "${preview}${part.text.length > 80 ? "..." : ""}"`));
52724
+ console.error(import_picocolors6.default.dim(`${sessionTag} message.part (text): "${preview}${part.text.length > 80 ? "..." : ""}"`));
51795
52725
  }
51796
52726
  break;
51797
52727
  }
@@ -51800,7 +52730,7 @@ function logEventVerbose(ctx, payload) {
51800
52730
  const field = deltaProps?.field ?? "unknown";
51801
52731
  const delta = deltaProps?.delta ?? "";
51802
52732
  const preview = delta.slice(0, 80).replace(/\n/g, "\\n");
51803
- console.error(import_picocolors5.default.dim(`${sessionTag} message.part.delta (${field}): "${preview}${delta.length > 80 ? "..." : ""}"`));
52733
+ console.error(import_picocolors6.default.dim(`${sessionTag} message.part.delta (${field}): "${preview}${delta.length > 80 ? "..." : ""}"`));
51804
52734
  break;
51805
52735
  }
51806
52736
  case "message.updated": {
@@ -51809,7 +52739,7 @@ function logEventVerbose(ctx, payload) {
51809
52739
  const model = msgProps?.info?.modelID;
51810
52740
  const agent = msgProps?.info?.agent;
51811
52741
  const details = [role, agent, model].filter(Boolean).join(", ");
51812
- console.error(import_picocolors5.default.dim(`${sessionTag} message.updated (${details})`));
52742
+ console.error(import_picocolors6.default.dim(`${sessionTag} message.updated (${details})`));
51813
52743
  break;
51814
52744
  }
51815
52745
  case "tool.execute": {
@@ -51827,32 +52757,32 @@ function logEventVerbose(ctx, payload) {
51827
52757
  }
51828
52758
  }
51829
52759
  const inputPreview = inputStr.slice(0, 150);
51830
- console.error(import_picocolors5.default.cyan(`${sessionTag} TOOL.EXECUTE: ${import_picocolors5.default.bold(toolName)}`));
51831
- console.error(import_picocolors5.default.dim(` input: ${inputPreview}${inputStr.length >= 150 ? "..." : ""}`));
52760
+ console.error(import_picocolors6.default.cyan(`${sessionTag} TOOL.EXECUTE: ${import_picocolors6.default.bold(toolName)}`));
52761
+ console.error(import_picocolors6.default.dim(` input: ${inputPreview}${inputStr.length >= 150 ? "..." : ""}`));
51832
52762
  break;
51833
52763
  }
51834
52764
  case "tool.result": {
51835
52765
  const resultProps = props;
51836
52766
  const output = resultProps?.output ?? "";
51837
52767
  const preview = output.slice(0, 200).replace(/\n/g, "\\n");
51838
- console.error(import_picocolors5.default.green(`${sessionTag} TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
52768
+ console.error(import_picocolors6.default.green(`${sessionTag} TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
51839
52769
  break;
51840
52770
  }
51841
52771
  case "session.error": {
51842
52772
  const errorProps = props;
51843
52773
  const errorMsg = serializeError(errorProps?.error);
51844
- console.error(import_picocolors5.default.red(`${sessionTag} SESSION.ERROR: ${errorMsg}`));
52774
+ console.error(import_picocolors6.default.red(`${sessionTag} SESSION.ERROR: ${errorMsg}`));
51845
52775
  break;
51846
52776
  }
51847
52777
  default:
51848
- console.error(import_picocolors5.default.dim(`${sessionTag} ${payload.type}`));
52778
+ console.error(import_picocolors6.default.dim(`${sessionTag} ${payload.type}`));
51849
52779
  }
51850
52780
  }
51851
52781
  // src/cli/run/event-stream-processor.ts
51852
- var import_picocolors8 = __toESM(require_picocolors(), 1);
52782
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
51853
52783
 
51854
52784
  // src/cli/run/event-handlers.ts
51855
- var import_picocolors7 = __toESM(require_picocolors(), 1);
52785
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
51856
52786
 
51857
52787
  // src/cli/run/tool-input-preview.ts
51858
52788
  function formatToolHeader(toolName, input) {
@@ -51988,14 +52918,14 @@ var displayChars = {
51988
52918
  };
51989
52919
 
51990
52920
  // src/cli/run/output-renderer.ts
51991
- var import_picocolors6 = __toESM(require_picocolors(), 1);
52921
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
51992
52922
  function renderAgentHeader(agent, model, variant, agentColorsByName) {
51993
52923
  if (!agent && !model)
51994
52924
  return;
51995
- const agentLabel = agent ? import_picocolors6.default.bold(colorizeWithProfileColor(agent, agentColorsByName[agent])) : "";
52925
+ const agentLabel = agent ? import_picocolors7.default.bold(colorizeWithProfileColor(agent, agentColorsByName[agent])) : "";
51996
52926
  const modelBase = model ?? "";
51997
52927
  const variantSuffix = variant ? ` (${variant})` : "";
51998
- const modelLabel = model ? import_picocolors6.default.dim(`${modelBase}${variantSuffix}`) : "";
52928
+ const modelLabel = model ? import_picocolors7.default.dim(`${modelBase}${variantSuffix}`) : "";
51999
52929
  process.stdout.write(`
52000
52930
  `);
52001
52931
  if (modelLabel) {
@@ -52003,7 +52933,7 @@ function renderAgentHeader(agent, model, variant, agentColorsByName) {
52003
52933
  `);
52004
52934
  }
52005
52935
  if (agentLabel) {
52006
- process.stdout.write(` ${import_picocolors6.default.dim("\u2514\u2500")} ${agentLabel}
52936
+ process.stdout.write(` ${import_picocolors7.default.dim("\u2514\u2500")} ${agentLabel}
52007
52937
  `);
52008
52938
  }
52009
52939
  process.stdout.write(`
@@ -52011,7 +52941,7 @@ function renderAgentHeader(agent, model, variant, agentColorsByName) {
52011
52941
  }
52012
52942
  function openThinkBlock() {
52013
52943
  process.stdout.write(`
52014
- ${import_picocolors6.default.dim("\u2503 Thinking:")} `);
52944
+ ${import_picocolors7.default.dim("\u2503 Thinking:")} `);
52015
52945
  }
52016
52946
  function closeThinkBlock() {
52017
52947
  process.stdout.write(`
@@ -52045,10 +52975,10 @@ function writePaddedText(text, atLineStart) {
52045
52975
  }
52046
52976
  function colorizeWithProfileColor(text, hexColor) {
52047
52977
  if (!hexColor)
52048
- return import_picocolors6.default.magenta(text);
52978
+ return import_picocolors7.default.magenta(text);
52049
52979
  const rgb = parseHexColor(hexColor);
52050
52980
  if (!rgb)
52051
- return import_picocolors6.default.magenta(text);
52981
+ return import_picocolors7.default.magenta(text);
52052
52982
  const [r2, g2, b3] = rgb;
52053
52983
  return `\x1B[38;2;${r2};${g2};${b3}m${text}\x1B[39m`;
52054
52984
  }
@@ -52088,7 +53018,7 @@ function renderCompletionMetaLine(state, messageID) {
52088
53018
  const agent = state.currentAgent ?? "assistant";
52089
53019
  const model = state.currentModel ?? "unknown-model";
52090
53020
  const variant = state.currentVariant ? ` (${state.currentVariant})` : "";
52091
- process.stdout.write(import_picocolors7.default.dim(`
53021
+ process.stdout.write(import_picocolors8.default.dim(`
52092
53022
  ${displayChars.treeEnd} ${agent} \xB7 ${model}${variant} \xB7 ${elapsedSec}s
52093
53023
  `));
52094
53024
  state.completionMetaPrintedByMessageId[messageID] = true;
@@ -52122,7 +53052,7 @@ function handleSessionError(ctx, payload, state) {
52122
53052
  if (getSessionId(props) === ctx.sessionID) {
52123
53053
  state.mainSessionError = true;
52124
53054
  state.lastError = serializeError(props?.error);
52125
- console.error(import_picocolors7.default.red(`
53055
+ console.error(import_picocolors8.default.red(`
52126
53056
  [session.error] ${state.lastError}`));
52127
53057
  }
52128
53058
  }
@@ -52150,7 +53080,7 @@ function handleMessagePartUpdated(ctx, payload, state) {
52150
53080
  const newText = reasoningText.slice(state.lastReasoningText.length);
52151
53081
  if (newText) {
52152
53082
  const padded = writePaddedText(newText, state.thinkingAtLineStart);
52153
- process.stdout.write(import_picocolors7.default.dim(padded.output));
53083
+ process.stdout.write(import_picocolors8.default.dim(padded.output));
52154
53084
  state.thinkingAtLineStart = padded.atLineStart;
52155
53085
  state.hasReceivedMeaningfulWork = true;
52156
53086
  }
@@ -52197,7 +53127,7 @@ function handleMessagePartDelta(ctx, payload, state) {
52197
53127
  if (partType === "reasoning") {
52198
53128
  ensureThinkBlockOpen(state);
52199
53129
  const padded2 = writePaddedText(delta, state.thinkingAtLineStart);
52200
- process.stdout.write(import_picocolors7.default.dim(padded2.output));
53130
+ process.stdout.write(import_picocolors8.default.dim(padded2.output));
52201
53131
  state.thinkingAtLineStart = padded2.atLineStart;
52202
53132
  state.lastReasoningText += delta;
52203
53133
  state.hasReceivedMeaningfulWork = true;
@@ -52218,10 +53148,10 @@ function handleToolPart(_ctx, part, state) {
52218
53148
  return;
52219
53149
  state.currentTool = toolName;
52220
53150
  const header = formatToolHeader(toolName, part.state?.input ?? {});
52221
- const suffix = header.description ? ` ${import_picocolors7.default.dim(header.description)}` : "";
53151
+ const suffix = header.description ? ` ${import_picocolors8.default.dim(header.description)}` : "";
52222
53152
  state.hasReceivedMeaningfulWork = true;
52223
53153
  process.stdout.write(`
52224
- ${import_picocolors7.default.cyan(header.icon)} ${import_picocolors7.default.bold(header.title)}${suffix}
53154
+ ${import_picocolors8.default.cyan(header.icon)} ${import_picocolors8.default.bold(header.title)}${suffix}
52225
53155
  `);
52226
53156
  }
52227
53157
  if (status === "completed" || status === "error") {
@@ -52229,10 +53159,10 @@ function handleToolPart(_ctx, part, state) {
52229
53159
  return;
52230
53160
  const output = part.state?.output || "";
52231
53161
  if (output.trim()) {
52232
- process.stdout.write(import_picocolors7.default.dim(` ${displayChars.treeEnd} output
53162
+ process.stdout.write(import_picocolors8.default.dim(` ${displayChars.treeEnd} output
52233
53163
  `));
52234
53164
  const padded = writePaddedText(output, true);
52235
- process.stdout.write(import_picocolors7.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
53165
+ process.stdout.write(import_picocolors8.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
52236
53166
  process.stdout.write(`
52237
53167
  `);
52238
53168
  }
@@ -52294,10 +53224,10 @@ function handleToolExecute(ctx, payload, state) {
52294
53224
  const toolName = props?.name || "unknown";
52295
53225
  state.currentTool = toolName;
52296
53226
  const header = formatToolHeader(toolName, props?.input ?? {});
52297
- const suffix = header.description ? ` ${import_picocolors7.default.dim(header.description)}` : "";
53227
+ const suffix = header.description ? ` ${import_picocolors8.default.dim(header.description)}` : "";
52298
53228
  state.hasReceivedMeaningfulWork = true;
52299
53229
  process.stdout.write(`
52300
- ${import_picocolors7.default.cyan(header.icon)} ${import_picocolors7.default.bold(header.title)}${suffix}
53230
+ ${import_picocolors8.default.cyan(header.icon)} ${import_picocolors8.default.bold(header.title)}${suffix}
52301
53231
  `);
52302
53232
  }
52303
53233
  function handleToolResult(ctx, payload, state) {
@@ -52311,10 +53241,10 @@ function handleToolResult(ctx, payload, state) {
52311
53241
  return;
52312
53242
  const output = props?.output || "";
52313
53243
  if (output.trim()) {
52314
- process.stdout.write(import_picocolors7.default.dim(` ${displayChars.treeEnd} output
53244
+ process.stdout.write(import_picocolors8.default.dim(` ${displayChars.treeEnd} output
52315
53245
  `));
52316
53246
  const padded = writePaddedText(output, true);
52317
- process.stdout.write(import_picocolors7.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
53247
+ process.stdout.write(import_picocolors8.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
52318
53248
  process.stdout.write(`
52319
53249
  `);
52320
53250
  }
@@ -52363,7 +53293,7 @@ async function processEvents(ctx, stream, state) {
52363
53293
  const payload = event;
52364
53294
  if (!payload?.type) {
52365
53295
  if (ctx.verbose) {
52366
- console.error(import_picocolors8.default.dim(`[event] no type: ${JSON.stringify(event)}`));
53296
+ console.error(import_picocolors9.default.dim(`[event] no type: ${JSON.stringify(event)}`));
52367
53297
  }
52368
53298
  continue;
52369
53299
  }
@@ -52381,7 +53311,7 @@ async function processEvents(ctx, stream, state) {
52381
53311
  handleToolResult(ctx, payload, state);
52382
53312
  handleTuiToast(ctx, payload, state);
52383
53313
  } catch (err) {
52384
- console.error(import_picocolors8.default.red(`[event error] ${err}`));
53314
+ console.error(import_picocolors9.default.red(`[event error] ${err}`));
52385
53315
  }
52386
53316
  }
52387
53317
  }
@@ -66618,7 +67548,7 @@ var createSseClient = ({ onSseError, onSseEvent, responseTransformer, responseVa
66618
67548
  if (!response.body)
66619
67549
  throw new Error("No body in SSE response");
66620
67550
  const reader = response.body.pipeThrough(new TextDecoderStream).getReader();
66621
- let buffer = "";
67551
+ let buffer2 = "";
66622
67552
  const abortHandler = () => {
66623
67553
  try {
66624
67554
  reader.cancel();
@@ -66630,11 +67560,11 @@ var createSseClient = ({ onSseError, onSseEvent, responseTransformer, responseVa
66630
67560
  const { done, value } = await reader.read();
66631
67561
  if (done)
66632
67562
  break;
66633
- buffer += value;
66634
- const chunks = buffer.split(`
67563
+ buffer2 += value;
67564
+ const chunks = buffer2.split(`
66635
67565
 
66636
67566
  `);
66637
- buffer = chunks.pop() ?? "";
67567
+ buffer2 = chunks.pop() ?? "";
66638
67568
  for (const chunk of chunks) {
66639
67569
  const lines = chunk.split(`
66640
67570
  `);
@@ -67934,6 +68864,31 @@ class OpencodeClient extends _HeyApiClient {
67934
68864
  }
67935
68865
 
67936
68866
  // node_modules/@opencode-ai/sdk/dist/client.js
68867
+ function pick2(value, fallback) {
68868
+ if (!value)
68869
+ return;
68870
+ if (!fallback)
68871
+ return value;
68872
+ if (value === fallback)
68873
+ return fallback;
68874
+ if (value === encodeURIComponent(fallback))
68875
+ return fallback;
68876
+ return value;
68877
+ }
68878
+ function rewrite(request, directory) {
68879
+ if (request.method !== "GET" && request.method !== "HEAD")
68880
+ return request;
68881
+ const value = pick2(request.headers.get("x-opencode-directory"), directory);
68882
+ if (!value)
68883
+ return request;
68884
+ const url2 = new URL(request.url);
68885
+ if (!url2.searchParams.has("directory")) {
68886
+ url2.searchParams.set("directory", value);
68887
+ }
68888
+ const next = new Request(url2, request);
68889
+ next.headers.delete("x-opencode-directory");
68890
+ return next;
68891
+ }
67937
68892
  function createOpencodeClient(config2) {
67938
68893
  if (!config2?.fetch) {
67939
68894
  const customFetch = (req) => {
@@ -67952,10 +68907,46 @@ function createOpencodeClient(config2) {
67952
68907
  };
67953
68908
  }
67954
68909
  const client2 = createClient(config2);
68910
+ client2.interceptors.request.use((request) => rewrite(request, config2?.directory));
67955
68911
  return new OpencodeClient({ client: client2 });
67956
68912
  }
67957
68913
  // node_modules/@opencode-ai/sdk/dist/server.js
67958
- import { spawn } from "child_process";
68914
+ var import_cross_spawn = __toESM(require_cross_spawn(), 1);
68915
+
68916
+ // node_modules/@opencode-ai/sdk/dist/process.js
68917
+ import { spawnSync } from "child_process";
68918
+ function stop(proc) {
68919
+ if (proc.exitCode !== null || proc.signalCode !== null)
68920
+ return;
68921
+ if (process.platform === "win32" && proc.pid) {
68922
+ const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true });
68923
+ if (!out.error && out.status === 0)
68924
+ return;
68925
+ }
68926
+ proc.kill();
68927
+ }
68928
+ function bindAbort(proc, signal, onAbort) {
68929
+ if (!signal)
68930
+ return () => {};
68931
+ const abort = () => {
68932
+ clear();
68933
+ stop(proc);
68934
+ onAbort?.();
68935
+ };
68936
+ const clear = () => {
68937
+ signal.removeEventListener("abort", abort);
68938
+ proc.off("exit", clear);
68939
+ proc.off("error", clear);
68940
+ };
68941
+ signal.addEventListener("abort", abort, { once: true });
68942
+ proc.on("exit", clear);
68943
+ proc.on("error", clear);
68944
+ if (signal.aborted)
68945
+ abort();
68946
+ return clear;
68947
+ }
68948
+
68949
+ // node_modules/@opencode-ai/sdk/dist/server.js
67959
68950
  async function createOpencodeServer(options) {
67960
68951
  options = Object.assign({
67961
68952
  hostname: "127.0.0.1",
@@ -67965,19 +68956,24 @@ async function createOpencodeServer(options) {
67965
68956
  const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
67966
68957
  if (options.config?.logLevel)
67967
68958
  args.push(`--log-level=${options.config.logLevel}`);
67968
- const proc = spawn(`opencode`, args, {
67969
- signal: options.signal,
68959
+ const proc = import_cross_spawn.default(`opencode`, args, {
67970
68960
  env: {
67971
68961
  ...process.env,
67972
68962
  OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {})
67973
68963
  }
67974
68964
  });
68965
+ let clear = () => {};
67975
68966
  const url2 = await new Promise((resolve2, reject) => {
67976
68967
  const id = setTimeout(() => {
68968
+ clear();
68969
+ stop(proc);
67977
68970
  reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`));
67978
68971
  }, options.timeout);
67979
68972
  let output = "";
68973
+ let resolved = false;
67980
68974
  proc.stdout?.on("data", (chunk) => {
68975
+ if (resolved)
68976
+ return;
67981
68977
  output += chunk.toString();
67982
68978
  const lines = output.split(`
67983
68979
  `);
@@ -67985,9 +68981,14 @@ async function createOpencodeServer(options) {
67985
68981
  if (line.startsWith("opencode server listening")) {
67986
68982
  const match = line.match(/on\s+(https?:\/\/[^\s]+)/);
67987
68983
  if (!match) {
67988
- throw new Error(`Failed to parse server url from output: ${line}`);
68984
+ clear();
68985
+ stop(proc);
68986
+ clearTimeout(id);
68987
+ reject(new Error(`Failed to parse server url from output: ${line}`));
68988
+ return;
67989
68989
  }
67990
68990
  clearTimeout(id);
68991
+ resolved = true;
67991
68992
  resolve2(match[1]);
67992
68993
  return;
67993
68994
  }
@@ -68009,17 +69010,16 @@ Server output: ${output}`;
68009
69010
  clearTimeout(id);
68010
69011
  reject(error48);
68011
69012
  });
68012
- if (options.signal) {
68013
- options.signal.addEventListener("abort", () => {
68014
- clearTimeout(id);
68015
- reject(new Error("Aborted"));
68016
- });
68017
- }
69013
+ clear = bindAbort(proc, options.signal, () => {
69014
+ clearTimeout(id);
69015
+ reject(options.signal?.reason);
69016
+ });
68018
69017
  });
68019
69018
  return {
68020
69019
  url: url2,
68021
69020
  close() {
68022
- proc.kill();
69021
+ clear();
69022
+ stop(proc);
68023
69023
  }
68024
69024
  };
68025
69025
  }
@@ -68039,11 +69039,11 @@ async function createOpencode(options) {
68039
69039
 
68040
69040
  // src/cli/run/server-connection.ts
68041
69041
  init_port_utils();
68042
- var import_picocolors9 = __toESM(require_picocolors(), 1);
69042
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
68043
69043
 
68044
69044
  // src/cli/run/opencode-binary-resolver.ts
68045
69045
  init_spawn_with_windows_hide();
68046
- import { delimiter, dirname, join as join10 } from "path";
69046
+ import { delimiter, dirname as dirname2, join as join14 } from "path";
68047
69047
  var OPENCODE_COMMANDS = ["opencode", "opencode-desktop"];
68048
69048
  var WINDOWS_SUFFIXES = ["", ".exe", ".cmd", ".bat", ".ps1"];
68049
69049
  function getCommandCandidates(platform) {
@@ -68066,7 +69066,7 @@ function collectCandidateBinaryPaths(pathEnv, which = Bun.which, platform = proc
68066
69066
  }
68067
69067
  for (const entry of (pathEnv ?? "").split(delimiter).filter(Boolean)) {
68068
69068
  for (const command of commandCandidates) {
68069
- addCandidate(join10(entry, command));
69069
+ addCandidate(join14(entry, command));
68070
69070
  }
68071
69071
  }
68072
69072
  return candidates;
@@ -68093,7 +69093,7 @@ async function findWorkingOpencodeBinary(pathEnv = process.env.PATH, probe = can
68093
69093
  return null;
68094
69094
  }
68095
69095
  function buildPathWithBinaryFirst(pathEnv, binaryPath) {
68096
- const preferredDir = dirname(binaryPath);
69096
+ const preferredDir = dirname2(binaryPath);
68097
69097
  const existing = (pathEnv ?? "").split(delimiter).filter((entry) => entry.length > 0 && entry !== preferredDir);
68098
69098
  return [preferredDir, ...existing].join(delimiter);
68099
69099
  }
@@ -68127,13 +69127,13 @@ function isPortRangeExhausted(error48) {
68127
69127
  async function startServer(options) {
68128
69128
  const { signal, port } = options;
68129
69129
  const { client: client3, server: server2 } = await withWorkingOpencodePath(() => createOpencode({ signal, port, hostname: "127.0.0.1" }));
68130
- console.log(import_picocolors9.default.dim("Server listening at"), import_picocolors9.default.cyan(server2.url));
69130
+ console.log(import_picocolors10.default.dim("Server listening at"), import_picocolors10.default.cyan(server2.url));
68131
69131
  return { client: client3, cleanup: () => server2.close() };
68132
69132
  }
68133
69133
  async function createServerConnection(options) {
68134
69134
  const { port, attach, signal } = options;
68135
69135
  if (attach !== undefined) {
68136
- console.log(import_picocolors9.default.dim("Attaching to existing server at"), import_picocolors9.default.cyan(attach));
69136
+ console.log(import_picocolors10.default.dim("Attaching to existing server at"), import_picocolors10.default.cyan(attach));
68137
69137
  const client3 = createOpencodeClient({ baseUrl: attach });
68138
69138
  return { client: client3, cleanup: () => {} };
68139
69139
  }
@@ -68143,7 +69143,7 @@ async function createServerConnection(options) {
68143
69143
  }
68144
69144
  const available = await isPortAvailable(port, "127.0.0.1");
68145
69145
  if (available) {
68146
- console.log(import_picocolors9.default.dim("Starting server on port"), import_picocolors9.default.cyan(port.toString()));
69146
+ console.log(import_picocolors10.default.dim("Starting server on port"), import_picocolors10.default.cyan(port.toString()));
68147
69147
  try {
68148
69148
  return await startServer({ signal, port });
68149
69149
  } catch (error48) {
@@ -68154,12 +69154,12 @@ async function createServerConnection(options) {
68154
69154
  if (stillAvailable) {
68155
69155
  throw error48;
68156
69156
  }
68157
- console.log(import_picocolors9.default.dim("Port"), import_picocolors9.default.cyan(port.toString()), import_picocolors9.default.dim("became occupied, attaching to existing server"));
69157
+ console.log(import_picocolors10.default.dim("Port"), import_picocolors10.default.cyan(port.toString()), import_picocolors10.default.dim("became occupied, attaching to existing server"));
68158
69158
  const client4 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
68159
69159
  return { client: client4, cleanup: () => {} };
68160
69160
  }
68161
69161
  }
68162
- console.log(import_picocolors9.default.dim("Port"), import_picocolors9.default.cyan(port.toString()), import_picocolors9.default.dim("is occupied, attaching to existing server"));
69162
+ console.log(import_picocolors10.default.dim("Port"), import_picocolors10.default.cyan(port.toString()), import_picocolors10.default.dim("is occupied, attaching to existing server"));
68163
69163
  const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
68164
69164
  return { client: client3, cleanup: () => {} };
68165
69165
  }
@@ -68177,14 +69177,14 @@ async function createServerConnection(options) {
68177
69177
  if (defaultPortIsAvailable) {
68178
69178
  throw error48;
68179
69179
  }
68180
- console.log(import_picocolors9.default.dim("Port range exhausted, attaching to existing server on"), import_picocolors9.default.cyan(DEFAULT_SERVER_PORT.toString()));
69180
+ console.log(import_picocolors10.default.dim("Port range exhausted, attaching to existing server on"), import_picocolors10.default.cyan(DEFAULT_SERVER_PORT.toString()));
68181
69181
  const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` });
68182
69182
  return { client: client3, cleanup: () => {} };
68183
69183
  }
68184
69184
  if (wasAutoSelected) {
68185
- console.log(import_picocolors9.default.dim("Auto-selected port"), import_picocolors9.default.cyan(selectedPort.toString()));
69185
+ console.log(import_picocolors10.default.dim("Auto-selected port"), import_picocolors10.default.cyan(selectedPort.toString()));
68186
69186
  } else {
68187
- console.log(import_picocolors9.default.dim("Starting server on port"), import_picocolors9.default.cyan(selectedPort.toString()));
69187
+ console.log(import_picocolors10.default.dim("Starting server on port"), import_picocolors10.default.cyan(selectedPort.toString()));
68188
69188
  }
68189
69189
  try {
68190
69190
  return await startServer({ signal, port: selectedPort });
@@ -68193,14 +69193,13 @@ async function createServerConnection(options) {
68193
69193
  throw error48;
68194
69194
  }
68195
69195
  const { port: retryPort } = await getAvailableServerPort(selectedPort + 1, "127.0.0.1");
68196
- console.log(import_picocolors9.default.dim("Retrying server start on port"), import_picocolors9.default.cyan(retryPort.toString()));
69196
+ console.log(import_picocolors10.default.dim("Retrying server start on port"), import_picocolors10.default.cyan(retryPort.toString()));
68197
69197
  return await startServer({ signal, port: retryPort });
68198
69198
  }
68199
69199
  }
68200
69200
 
68201
69201
  // src/cli/run/session-resolver.ts
68202
- var import_picocolors10 = __toESM(require_picocolors(), 1);
68203
- init_plugin_identity();
69202
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
68204
69203
  var SESSION_CREATE_MAX_RETRIES = 3;
68205
69204
  var SESSION_CREATE_RETRY_DELAY_MS = 1000;
68206
69205
  async function resolveSession(options) {
@@ -68218,7 +69217,7 @@ async function resolveSession(options) {
68218
69217
  for (let attempt = 1;attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) {
68219
69218
  const res = await client3.session.create({
68220
69219
  body: {
68221
- title: `${PLUGIN_NAME} run`,
69220
+ title: "evil-omo run",
68222
69221
  permission: [
68223
69222
  { permission: "question", action: "deny", pattern: "*" }
68224
69223
  ]
@@ -68226,11 +69225,11 @@ async function resolveSession(options) {
68226
69225
  query: { directory }
68227
69226
  });
68228
69227
  if (res.error) {
68229
- console.error(import_picocolors10.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
68230
- console.error(import_picocolors10.default.dim(` Error: ${serializeError(res.error)}`));
69228
+ console.error(import_picocolors11.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
69229
+ console.error(import_picocolors11.default.dim(` Error: ${serializeError(res.error)}`));
68231
69230
  if (attempt < SESSION_CREATE_MAX_RETRIES) {
68232
69231
  const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
68233
- console.log(import_picocolors10.default.dim(` Retrying in ${delay}ms...`));
69232
+ console.log(import_picocolors11.default.dim(` Retrying in ${delay}ms...`));
68234
69233
  await new Promise((resolve2) => setTimeout(resolve2, delay));
68235
69234
  }
68236
69235
  continue;
@@ -68238,10 +69237,10 @@ async function resolveSession(options) {
68238
69237
  if (res.data?.id) {
68239
69238
  return res.data.id;
68240
69239
  }
68241
- console.error(import_picocolors10.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`));
69240
+ console.error(import_picocolors11.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`));
68242
69241
  if (attempt < SESSION_CREATE_MAX_RETRIES) {
68243
69242
  const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
68244
- console.log(import_picocolors10.default.dim(` Retrying in ${delay}ms...`));
69243
+ console.log(import_picocolors11.default.dim(` Retrying in ${delay}ms...`));
68245
69244
  await new Promise((resolve2) => setTimeout(resolve2, delay));
68246
69245
  }
68247
69246
  }
@@ -68359,7 +69358,7 @@ async function executeOnCompleteHook(options) {
68359
69358
 
68360
69359
  // src/cli/run/agent-resolver.ts
68361
69360
  init_agent_display_names();
68362
- var import_picocolors11 = __toESM(require_picocolors(), 1);
69361
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
68363
69362
  var CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"];
68364
69363
  var DEFAULT_AGENT = "sisyphus";
68365
69364
  var normalizeAgentName = (agent) => {
@@ -68404,10 +69403,10 @@ var resolveRunAgent = (options, pluginConfig, env = process.env) => {
68404
69403
  const fallbackName = getAgentDisplayName(fallback);
68405
69404
  const fallbackDisabled = isAgentDisabled(fallback, pluginConfig);
68406
69405
  if (fallbackDisabled) {
68407
- console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled and no enabled core agent was found. Proceeding with "${fallbackName}".`));
69406
+ console.log(import_picocolors12.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled and no enabled core agent was found. Proceeding with "${fallbackName}".`));
68408
69407
  return fallbackName;
68409
69408
  }
68410
- console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled. Falling back to "${fallbackName}".`));
69409
+ console.log(import_picocolors12.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled. Falling back to "${fallbackName}".`));
68411
69410
  return fallbackName;
68412
69411
  }
68413
69412
  return resolved.resolvedName;
@@ -68438,11 +69437,11 @@ function resolveRunModel(modelString) {
68438
69437
  }
68439
69438
 
68440
69439
  // src/cli/run/poll-for-completion.ts
68441
- var import_picocolors13 = __toESM(require_picocolors(), 1);
69440
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
68442
69441
 
68443
69442
  // src/cli/run/completion.ts
68444
69443
  init_shared();
68445
- var import_picocolors12 = __toESM(require_picocolors(), 1);
69444
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
68446
69445
  // src/features/boulder-state/constants.ts
68447
69446
  var BOULDER_DIR = ".sisyphus";
68448
69447
  var BOULDER_FILE = "boulder.json";
@@ -68450,19 +69449,19 @@ var BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}`;
68450
69449
  var NOTEPAD_DIR = "notepads";
68451
69450
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
68452
69451
  // src/features/boulder-state/storage.ts
68453
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, readdirSync } from "fs";
68454
- import { dirname as dirname2, join as join11, basename } from "path";
69452
+ import { existsSync as existsSync15, readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync3 } from "fs";
69453
+ import { dirname as dirname3, join as join15, basename } from "path";
68455
69454
  var RESERVED_KEYS = new Set(["__proto__", "prototype", "constructor"]);
68456
69455
  function getBoulderFilePath(directory) {
68457
- return join11(directory, BOULDER_DIR, BOULDER_FILE);
69456
+ return join15(directory, BOULDER_DIR, BOULDER_FILE);
68458
69457
  }
68459
69458
  function readBoulderState(directory) {
68460
69459
  const filePath = getBoulderFilePath(directory);
68461
- if (!existsSync11(filePath)) {
69460
+ if (!existsSync15(filePath)) {
68462
69461
  return null;
68463
69462
  }
68464
69463
  try {
68465
- const content = readFileSync9(filePath, "utf-8");
69464
+ const content = readFileSync10(filePath, "utf-8");
68466
69465
  const parsed = JSON.parse(content);
68467
69466
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
68468
69467
  return null;
@@ -68470,6 +69469,15 @@ function readBoulderState(directory) {
68470
69469
  if (!Array.isArray(parsed.session_ids)) {
68471
69470
  parsed.session_ids = [];
68472
69471
  }
69472
+ if (!parsed.session_origins || typeof parsed.session_origins !== "object" || Array.isArray(parsed.session_origins)) {
69473
+ parsed.session_origins = {};
69474
+ }
69475
+ if (parsed.session_ids.length === 1) {
69476
+ const soleSessionId = parsed.session_ids[0];
69477
+ if (typeof soleSessionId === "string" && parsed.session_origins[soleSessionId] !== "appended" && parsed.session_origins[soleSessionId] !== "direct") {
69478
+ parsed.session_origins[soleSessionId] = "direct";
69479
+ }
69480
+ }
68473
69481
  if (!parsed.task_sessions || typeof parsed.task_sessions !== "object" || Array.isArray(parsed.task_sessions)) {
68474
69482
  parsed.task_sessions = {};
68475
69483
  }
@@ -68478,39 +69486,101 @@ function readBoulderState(directory) {
68478
69486
  return null;
68479
69487
  }
68480
69488
  }
69489
+ var TODO_HEADING_PATTERN = /^##\s+TODOs\b/i;
69490
+ var FINAL_VERIFICATION_HEADING_PATTERN = /^##\s+Final Verification Wave\b/i;
69491
+ var SECOND_LEVEL_HEADING_PATTERN = /^##\s+/;
69492
+ var UNCHECKED_CHECKBOX_PATTERN = /^(\s*)[-*]\s*\[\s*\]\s*(.+)$/;
69493
+ var CHECKED_CHECKBOX_PATTERN = /^(\s*)[-*]\s*\[[xX]\]\s*(.+)$/;
69494
+ var TODO_TASK_PATTERN = /^\d+\.\s+/;
69495
+ var FINAL_WAVE_TASK_PATTERN = /^F\d+\.\s+/i;
68481
69496
  function getPlanProgress(planPath) {
68482
- if (!existsSync11(planPath)) {
69497
+ if (!existsSync15(planPath)) {
68483
69498
  return { total: 0, completed: 0, isComplete: true };
68484
69499
  }
68485
69500
  try {
68486
- const content = readFileSync9(planPath, "utf-8");
68487
- const uncheckedMatches = content.match(/^\s*[-*]\s*\[\s*\]/gm) || [];
68488
- const checkedMatches = content.match(/^\s*[-*]\s*\[[xX]\]/gm) || [];
68489
- const total = uncheckedMatches.length + checkedMatches.length;
68490
- const completed = checkedMatches.length;
68491
- return {
68492
- total,
68493
- completed,
68494
- isComplete: total > 0 && completed === total
68495
- };
69501
+ const content = readFileSync10(planPath, "utf-8");
69502
+ const lines = content.split(/\r?\n/);
69503
+ const hasStructuredSections = lines.some((line) => TODO_HEADING_PATTERN.test(line) || FINAL_VERIFICATION_HEADING_PATTERN.test(line));
69504
+ if (hasStructuredSections) {
69505
+ return getStructuredPlanProgress(lines);
69506
+ }
69507
+ return getSimplePlanProgress(content);
68496
69508
  } catch {
68497
69509
  return { total: 0, completed: 0, isComplete: true };
68498
69510
  }
68499
69511
  }
69512
+ function getStructuredPlanProgress(lines) {
69513
+ let section = "other";
69514
+ let total = 0;
69515
+ let completed = 0;
69516
+ for (const line of lines) {
69517
+ if (SECOND_LEVEL_HEADING_PATTERN.test(line)) {
69518
+ section = TODO_HEADING_PATTERN.test(line) ? "todo" : FINAL_VERIFICATION_HEADING_PATTERN.test(line) ? "final-wave" : "other";
69519
+ continue;
69520
+ }
69521
+ if (section !== "todo" && section !== "final-wave") {
69522
+ continue;
69523
+ }
69524
+ const checkedMatch = line.match(CHECKED_CHECKBOX_PATTERN);
69525
+ const uncheckedMatch = checkedMatch ? null : line.match(UNCHECKED_CHECKBOX_PATTERN);
69526
+ const match = checkedMatch ?? uncheckedMatch;
69527
+ if (!match) {
69528
+ continue;
69529
+ }
69530
+ if (match[1].length > 0) {
69531
+ continue;
69532
+ }
69533
+ const taskBody = match[2].trim();
69534
+ const labelPattern = section === "todo" ? TODO_TASK_PATTERN : FINAL_WAVE_TASK_PATTERN;
69535
+ if (!labelPattern.test(taskBody)) {
69536
+ continue;
69537
+ }
69538
+ total++;
69539
+ if (checkedMatch) {
69540
+ completed++;
69541
+ }
69542
+ }
69543
+ return {
69544
+ total,
69545
+ completed,
69546
+ isComplete: total > 0 && completed === total
69547
+ };
69548
+ }
69549
+ function getSimplePlanProgress(content) {
69550
+ const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || [];
69551
+ const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || [];
69552
+ const total = uncheckedMatches.length + checkedMatches.length;
69553
+ const completed = checkedMatches.length;
69554
+ return {
69555
+ total,
69556
+ completed,
69557
+ isComplete: total > 0 && completed === total
69558
+ };
69559
+ }
69560
+ // src/features/claude-code-session-state/state.ts
69561
+ init_agent_display_names();
69562
+ var subagentSessions = new Set;
69563
+ var syncSubagentSessions = new Set;
69564
+ var registeredAgentNames = new Set;
69565
+ var registeredAgentAliases = new Map;
69566
+ var sessionAgentMap = new Map;
69567
+ function getSessionAgent(sessionID) {
69568
+ return sessionAgentMap.get(sessionID);
69569
+ }
68500
69570
  // src/features/run-continuation-state/constants.ts
68501
69571
  var CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation";
68502
69572
  // src/features/run-continuation-state/storage.ts
68503
- import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync6 } from "fs";
68504
- import { join as join12 } from "path";
69573
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync6 } from "fs";
69574
+ import { join as join16 } from "path";
68505
69575
  function getMarkerPath(directory, sessionID) {
68506
- return join12(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
69576
+ return join16(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
68507
69577
  }
68508
69578
  function readContinuationMarker(directory, sessionID) {
68509
69579
  const markerPath = getMarkerPath(directory, sessionID);
68510
- if (!existsSync12(markerPath))
69580
+ if (!existsSync16(markerPath))
68511
69581
  return null;
68512
69582
  try {
68513
- const raw = readFileSync10(markerPath, "utf-8");
69583
+ const raw = readFileSync11(markerPath, "utf-8");
68514
69584
  const parsed = JSON.parse(raw);
68515
69585
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
68516
69586
  return null;
@@ -68533,10 +69603,120 @@ function getActiveContinuationMarkerReason(marker) {
68533
69603
  const [source, entry] = active;
68534
69604
  return entry.reason ?? `${source} continuation is active`;
68535
69605
  }
69606
+ // src/hooks/atlas/boulder-session-lineage.ts
69607
+ init_logger();
69608
+
69609
+ // src/hooks/atlas/hook-name.ts
69610
+ var HOOK_NAME = "atlas";
69611
+
69612
+ // src/hooks/atlas/boulder-session-lineage.ts
69613
+ async function isSessionInBoulderLineage(input) {
69614
+ const visitedSessionIDs = new Set;
69615
+ let currentSessionID = input.sessionID;
69616
+ while (!visitedSessionIDs.has(currentSessionID)) {
69617
+ visitedSessionIDs.add(currentSessionID);
69618
+ const sessionResult = await input.client.session.get({ path: { id: currentSessionID } }).catch((error48) => {
69619
+ log(`[${HOOK_NAME}] Failed to resolve session lineage`, {
69620
+ sessionID: input.sessionID,
69621
+ currentSessionID,
69622
+ error: error48
69623
+ });
69624
+ return null;
69625
+ });
69626
+ if (!sessionResult || sessionResult.error) {
69627
+ return false;
69628
+ }
69629
+ const parentSessionID = sessionResult.data?.parentID;
69630
+ if (!parentSessionID) {
69631
+ return false;
69632
+ }
69633
+ if (input.boulderSessionIDs.includes(parentSessionID)) {
69634
+ return true;
69635
+ }
69636
+ currentSessionID = parentSessionID;
69637
+ }
69638
+ return false;
69639
+ }
69640
+
69641
+ // src/hooks/atlas/session-last-agent.ts
69642
+ init_shared();
69643
+ init_compaction_marker();
69644
+ import { readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
69645
+ import { join as join17 } from "path";
69646
+ function getLastAgentFromMessageDir(messageDir) {
69647
+ try {
69648
+ const messages = readdirSync4(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
69649
+ try {
69650
+ const content = readFileSync12(join17(messageDir, fileName), "utf-8");
69651
+ const parsed = JSON.parse(content);
69652
+ return {
69653
+ fileName,
69654
+ id: parsed.id,
69655
+ agent: parsed.agent,
69656
+ createdAt: typeof parsed.time?.created === "number" ? parsed.time.created : Number.NEGATIVE_INFINITY
69657
+ };
69658
+ } catch {
69659
+ return null;
69660
+ }
69661
+ }).filter((message) => message !== null).sort((left, right) => (right?.createdAt ?? 0) - (left?.createdAt ?? 0) || (right?.fileName ?? "").localeCompare(left?.fileName ?? ""));
69662
+ for (const message of messages) {
69663
+ if (!message)
69664
+ continue;
69665
+ if (isCompactionMessage({ agent: message.agent }) || hasCompactionPartInStorage(message?.id)) {
69666
+ continue;
69667
+ }
69668
+ if (typeof message.agent === "string") {
69669
+ return message.agent.toLowerCase();
69670
+ }
69671
+ }
69672
+ } catch {
69673
+ return null;
69674
+ }
69675
+ return null;
69676
+ }
69677
+ async function getLastAgentFromSession(sessionID, client3) {
69678
+ if (isSqliteBackend() && client3) {
69679
+ try {
69680
+ const response = await client3.session.messages({ path: { id: sessionID } });
69681
+ const messages = normalizeSDKResponse(response, [], {
69682
+ preferResponseOnMissingData: true
69683
+ }).sort((left, right) => {
69684
+ const leftTime = left.info?.time?.created ?? Number.NEGATIVE_INFINITY;
69685
+ const rightTime = right.info?.time?.created ?? Number.NEGATIVE_INFINITY;
69686
+ if (leftTime !== rightTime) {
69687
+ return rightTime - leftTime;
69688
+ }
69689
+ const leftId = typeof left.id === "string" ? left.id : "";
69690
+ const rightId = typeof right.id === "string" ? right.id : "";
69691
+ return rightId.localeCompare(leftId);
69692
+ });
69693
+ for (const message of messages) {
69694
+ if (isCompactionMessage(message)) {
69695
+ continue;
69696
+ }
69697
+ const agent = message.info?.agent;
69698
+ if (typeof agent === "string") {
69699
+ return agent.toLowerCase();
69700
+ }
69701
+ }
69702
+ } catch {
69703
+ return null;
69704
+ }
69705
+ return null;
69706
+ }
69707
+ const messageDir = getMessageDir(sessionID);
69708
+ if (!messageDir)
69709
+ return null;
69710
+ return getLastAgentFromMessageDir(messageDir);
69711
+ }
69712
+
69713
+ // src/cli/run/continuation-state.ts
69714
+ init_agent_display_names();
69715
+
68536
69716
  // src/hooks/ralph-loop/storage.ts
68537
69717
  init_frontmatter();
68538
- import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync, mkdirSync as mkdirSync5 } from "fs";
68539
- import { dirname as dirname3, join as join13 } from "path";
69718
+ import { existsSync as existsSync17, readFileSync as readFileSync13, writeFileSync as writeFileSync7, unlinkSync, mkdirSync as mkdirSync7 } from "fs";
69719
+ import { dirname as dirname4, join as join18 } from "path";
68540
69720
 
68541
69721
  // src/hooks/ralph-loop/constants.ts
68542
69722
  var DEFAULT_STATE_FILE = ".sisyphus/ralph-loop.local.md";
@@ -68545,15 +69725,15 @@ var DEFAULT_COMPLETION_PROMISE = "DONE";
68545
69725
 
68546
69726
  // src/hooks/ralph-loop/storage.ts
68547
69727
  function getStateFilePath(directory, customPath) {
68548
- return customPath ? join13(directory, customPath) : join13(directory, DEFAULT_STATE_FILE);
69728
+ return customPath ? join18(directory, customPath) : join18(directory, DEFAULT_STATE_FILE);
68549
69729
  }
68550
69730
  function readState(directory, customPath) {
68551
69731
  const filePath = getStateFilePath(directory, customPath);
68552
- if (!existsSync13(filePath)) {
69732
+ if (!existsSync17(filePath)) {
68553
69733
  return null;
68554
69734
  }
68555
69735
  try {
68556
- const content = readFileSync11(filePath, "utf-8");
69736
+ const content = readFileSync13(filePath, "utf-8");
68557
69737
  const { data, body } = parseFrontmatter(content);
68558
69738
  const active = data.active;
68559
69739
  const iteration = data.iteration;
@@ -68593,10 +69773,10 @@ function readState(directory, customPath) {
68593
69773
  }
68594
69774
 
68595
69775
  // src/cli/run/continuation-state.ts
68596
- function getContinuationState(directory, sessionID) {
69776
+ async function getContinuationState(directory, sessionID, client3) {
68597
69777
  const marker = readContinuationMarker(directory, sessionID);
68598
69778
  return {
68599
- hasActiveBoulder: hasActiveBoulderContinuation(directory, sessionID),
69779
+ hasActiveBoulder: await hasActiveBoulderContinuation(directory, sessionID, client3),
68600
69780
  hasActiveRalphLoop: hasActiveRalphLoopContinuation(directory, sessionID),
68601
69781
  hasHookMarker: marker !== null,
68602
69782
  hasTodoHookMarker: marker?.sources.todo !== undefined,
@@ -68604,20 +69784,54 @@ function getContinuationState(directory, sessionID) {
68604
69784
  activeHookMarkerReason: getActiveContinuationMarkerReason(marker)
68605
69785
  };
68606
69786
  }
68607
- function hasActiveBoulderContinuation(directory, sessionID) {
69787
+ async function hasActiveBoulderContinuation(directory, sessionID, client3) {
68608
69788
  const boulder = readBoulderState(directory);
68609
69789
  if (!boulder)
68610
69790
  return false;
68611
- if (!boulder.session_ids.includes(sessionID))
68612
- return false;
68613
69791
  const progress = getPlanProgress(boulder.active_plan);
68614
- return !progress.isComplete;
69792
+ if (progress.isComplete)
69793
+ return false;
69794
+ if (!client3)
69795
+ return false;
69796
+ const isTrackedSession = boulder.session_ids.includes(sessionID);
69797
+ const sessionOrigin = boulder.session_origins?.[sessionID];
69798
+ if (!isTrackedSession) {
69799
+ return false;
69800
+ }
69801
+ const isTrackedDescendant = await isTrackedDescendantSession(client3, sessionID, boulder.session_ids);
69802
+ if (isTrackedSession && sessionOrigin === "direct") {
69803
+ return true;
69804
+ }
69805
+ if (isTrackedSession && sessionOrigin !== "direct" && !isTrackedDescendant) {
69806
+ return false;
69807
+ }
69808
+ const sessionAgent = await getLastAgentFromSession(sessionID, client3) ?? getSessionAgent(sessionID);
69809
+ if (!sessionAgent) {
69810
+ return false;
69811
+ }
69812
+ const requiredAgentKey = getAgentConfigKey(boulder.agent ?? "atlas");
69813
+ const sessionAgentKey = getAgentConfigKey(sessionAgent);
69814
+ if (sessionAgentKey !== requiredAgentKey && !(requiredAgentKey === getAgentConfigKey("atlas") && sessionAgentKey === getAgentConfigKey("sisyphus"))) {
69815
+ return false;
69816
+ }
69817
+ return isTrackedSession || isTrackedDescendant;
69818
+ }
69819
+ async function isTrackedDescendantSession(client3, sessionID, trackedSessionIDs) {
69820
+ const ancestorSessionIDs = trackedSessionIDs.filter((trackedSessionID) => trackedSessionID !== sessionID);
69821
+ if (ancestorSessionIDs.length === 0) {
69822
+ return false;
69823
+ }
69824
+ return isSessionInBoulderLineage({
69825
+ client: client3,
69826
+ sessionID,
69827
+ boulderSessionIDs: ancestorSessionIDs
69828
+ });
68615
69829
  }
68616
69830
  function hasActiveRalphLoopContinuation(directory, sessionID) {
68617
- const state = readState(directory);
68618
- if (!state || !state.active)
69831
+ const state2 = readState(directory);
69832
+ if (!state2 || !state2.active)
68619
69833
  return false;
68620
- if (state.session_id && state.session_id !== sessionID) {
69834
+ if (state2.session_id && state2.session_id !== sessionID) {
68621
69835
  return false;
68622
69836
  }
68623
69837
  return true;
@@ -68626,7 +69840,7 @@ function hasActiveRalphLoopContinuation(directory, sessionID) {
68626
69840
  // src/cli/run/completion.ts
68627
69841
  async function checkCompletionConditions(ctx) {
68628
69842
  try {
68629
- const continuationState = getContinuationState(ctx.directory, ctx.sessionID);
69843
+ const continuationState = await getContinuationState(ctx.directory, ctx.sessionID, ctx.client);
68630
69844
  if (continuationState.hasActiveHookMarker) {
68631
69845
  const reason = continuationState.activeHookMarkerReason ?? "continuation hook is active";
68632
69846
  logWaiting(ctx, reason);
@@ -68643,7 +69857,7 @@ async function checkCompletionConditions(ctx) {
68643
69857
  }
68644
69858
  return true;
68645
69859
  } catch (err) {
68646
- console.error(import_picocolors12.default.red(`[completion] API error: ${err}`));
69860
+ console.error(import_picocolors13.default.red(`[completion] API error: ${err}`));
68647
69861
  return false;
68648
69862
  }
68649
69863
  }
@@ -68704,7 +69918,7 @@ function logWaiting(ctx, message) {
68704
69918
  if (!ctx.verbose) {
68705
69919
  return;
68706
69920
  }
68707
- console.log(import_picocolors12.default.dim(` Waiting: ${message}`));
69921
+ console.log(import_picocolors13.default.dim(` Waiting: ${message}`));
68708
69922
  }
68709
69923
 
68710
69924
  // src/cli/run/poll-for-completion.ts
@@ -68735,10 +69949,10 @@ async function pollForCompletion(ctx, eventState, abortController, options = {})
68735
69949
  if (eventState.mainSessionError) {
68736
69950
  errorCycleCount++;
68737
69951
  if (errorCycleCount >= ERROR_GRACE_CYCLES) {
68738
- console.error(import_picocolors13.default.red(`
69952
+ console.error(import_picocolors14.default.red(`
68739
69953
 
68740
69954
  Session ended with error: ${eventState.lastError}`));
68741
- console.error(import_picocolors13.default.yellow("Check if todos were completed before the error."));
69955
+ console.error(import_picocolors14.default.yellow("Check if todos were completed before the error."));
68742
69956
  return 1;
68743
69957
  }
68744
69958
  continue;
@@ -68749,7 +69963,7 @@ Session ended with error: ${eventState.lastError}`));
68749
69963
  if (eventState.lastEventTimestamp !== null) {
68750
69964
  const timeSinceLastEvent = Date.now() - eventState.lastEventTimestamp;
68751
69965
  if (timeSinceLastEvent > eventWatchdogMs) {
68752
- console.log(import_picocolors13.default.yellow(`
69966
+ console.log(import_picocolors14.default.yellow(`
68753
69967
  No events for ${Math.round(timeSinceLastEvent / 1000)}s, verifying session status...`));
68754
69968
  mainSessionStatus = await getMainSessionStatus(ctx);
68755
69969
  if (mainSessionStatus === "idle") {
@@ -68798,7 +70012,7 @@ Session ended with error: ${eventState.lastError}`));
68798
70012
  const hasActiveWork = hasActiveChildren || hasActiveTodos;
68799
70013
  if (hasActiveWork) {
68800
70014
  eventState.hasReceivedMeaningfulWork = true;
68801
- console.log(import_picocolors13.default.yellow(`
70015
+ console.log(import_picocolors14.default.yellow(`
68802
70016
  No meaningful work events for ${Math.round(secondaryMeaningfulWorkTimeoutMs / 1000)}s but session has active work - assuming in progress`));
68803
70017
  }
68804
70018
  }
@@ -68818,7 +70032,7 @@ Session ended with error: ${eventState.lastError}`));
68818
70032
  }
68819
70033
  consecutiveCompleteChecks++;
68820
70034
  if (consecutiveCompleteChecks >= requiredConsecutive) {
68821
- console.log(import_picocolors13.default.green(`
70035
+ console.log(import_picocolors14.default.green(`
68822
70036
 
68823
70037
  All tasks completed.`));
68824
70038
  return 0;
@@ -68987,7 +70201,7 @@ async function run(options) {
68987
70201
  };
68988
70202
  const restoreInput = suppressRunInput();
68989
70203
  const handleSigint = () => {
68990
- console.log(import_picocolors14.default.yellow(`
70204
+ console.log(import_picocolors15.default.yellow(`
68991
70205
  Interrupted. Shutting down...`));
68992
70206
  restoreInput();
68993
70207
  cleanup();
@@ -69000,9 +70214,9 @@ Interrupted. Shutting down...`));
69000
70214
  sessionId: options.sessionId,
69001
70215
  directory
69002
70216
  });
69003
- console.log(import_picocolors14.default.dim(`Session: ${sessionID}`));
70217
+ console.log(import_picocolors15.default.dim(`Session: ${sessionID}`));
69004
70218
  if (resolvedModel) {
69005
- console.log(import_picocolors14.default.dim(`Model: ${resolvedModel.providerID}/${resolvedModel.modelID}`));
70219
+ console.log(import_picocolors15.default.dim(`Model: ${resolvedModel.providerID}/${resolvedModel.modelID}`));
69006
70220
  }
69007
70221
  const ctx = {
69008
70222
  client: client3,
@@ -69065,7 +70279,7 @@ Interrupted. Shutting down...`));
69065
70279
  if (err instanceof Error && err.name === "AbortError") {
69066
70280
  return 130;
69067
70281
  }
69068
- console.error(import_picocolors14.default.red(`Error: ${serializeError(err)}`));
70282
+ console.error(import_picocolors15.default.red(`Error: ${serializeError(err)}`));
69069
70283
  return 1;
69070
70284
  } finally {
69071
70285
  timestampOutput?.restore();
@@ -69075,53 +70289,53 @@ Interrupted. Shutting down...`));
69075
70289
  init_checker();
69076
70290
 
69077
70291
  // src/cli/get-local-version/formatter.ts
69078
- var import_picocolors15 = __toESM(require_picocolors(), 1);
69079
- var SYMBOLS2 = {
69080
- check: import_picocolors15.default.green("[OK]"),
69081
- cross: import_picocolors15.default.red("[X]"),
69082
- arrow: import_picocolors15.default.cyan("->"),
69083
- info: import_picocolors15.default.blue("[i]"),
69084
- warn: import_picocolors15.default.yellow("[!]"),
69085
- pin: import_picocolors15.default.magenta("[PINNED]"),
69086
- dev: import_picocolors15.default.cyan("[DEV]")
70292
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
70293
+ var SYMBOLS3 = {
70294
+ check: import_picocolors16.default.green("[OK]"),
70295
+ cross: import_picocolors16.default.red("[X]"),
70296
+ arrow: import_picocolors16.default.cyan("->"),
70297
+ info: import_picocolors16.default.blue("[i]"),
70298
+ warn: import_picocolors16.default.yellow("[!]"),
70299
+ pin: import_picocolors16.default.magenta("[PINNED]"),
70300
+ dev: import_picocolors16.default.cyan("[DEV]")
69087
70301
  };
69088
70302
  function formatVersionOutput(info) {
69089
70303
  const lines = [];
69090
70304
  lines.push("");
69091
- lines.push(import_picocolors15.default.bold(import_picocolors15.default.white("evil-omo Version Information")));
69092
- lines.push(import_picocolors15.default.dim("\u2500".repeat(50)));
70305
+ lines.push(import_picocolors16.default.bold(import_picocolors16.default.white("evil-omo Version Information")));
70306
+ lines.push(import_picocolors16.default.dim("\u2500".repeat(50)));
69093
70307
  lines.push("");
69094
70308
  if (info.currentVersion) {
69095
- lines.push(` Current Version: ${import_picocolors15.default.cyan(info.currentVersion)}`);
70309
+ lines.push(` Current Version: ${import_picocolors16.default.cyan(info.currentVersion)}`);
69096
70310
  } else {
69097
- lines.push(` Current Version: ${import_picocolors15.default.dim("unknown")}`);
70311
+ lines.push(` Current Version: ${import_picocolors16.default.dim("unknown")}`);
69098
70312
  }
69099
70313
  if (!info.isLocalDev && info.latestVersion) {
69100
- lines.push(` Latest Version: ${import_picocolors15.default.cyan(info.latestVersion)}`);
70314
+ lines.push(` Latest Version: ${import_picocolors16.default.cyan(info.latestVersion)}`);
69101
70315
  }
69102
70316
  lines.push("");
69103
70317
  switch (info.status) {
69104
70318
  case "up-to-date":
69105
- lines.push(` ${SYMBOLS2.check} ${import_picocolors15.default.green("You're up to date!")}`);
70319
+ lines.push(` ${SYMBOLS3.check} ${import_picocolors16.default.green("You're up to date!")}`);
69106
70320
  break;
69107
70321
  case "outdated":
69108
- lines.push(` ${SYMBOLS2.warn} ${import_picocolors15.default.yellow("Update available")}`);
69109
- lines.push(` ${import_picocolors15.default.dim("Run:")} ${import_picocolors15.default.cyan("cd ~/.config/opencode && bun update evil-omo")}`);
70322
+ lines.push(` ${SYMBOLS3.warn} ${import_picocolors16.default.yellow("Update available")}`);
70323
+ lines.push(` ${import_picocolors16.default.dim("Run:")} ${import_picocolors16.default.cyan("cd ~/.config/opencode && bun update evil-omo")}`);
69110
70324
  break;
69111
70325
  case "local-dev":
69112
- lines.push(` ${SYMBOLS2.dev} ${import_picocolors15.default.cyan("Running in local development mode")}`);
69113
- lines.push(` ${import_picocolors15.default.dim("Using file:// protocol from config")}`);
70326
+ lines.push(` ${SYMBOLS3.dev} ${import_picocolors16.default.cyan("Running in local development mode")}`);
70327
+ lines.push(` ${import_picocolors16.default.dim("Using file:// protocol from config")}`);
69114
70328
  break;
69115
70329
  case "pinned":
69116
- lines.push(` ${SYMBOLS2.pin} ${import_picocolors15.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
69117
- lines.push(` ${import_picocolors15.default.dim("Update check skipped for pinned versions")}`);
70330
+ lines.push(` ${SYMBOLS3.pin} ${import_picocolors16.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
70331
+ lines.push(` ${import_picocolors16.default.dim("Update check skipped for pinned versions")}`);
69118
70332
  break;
69119
70333
  case "error":
69120
- lines.push(` ${SYMBOLS2.cross} ${import_picocolors15.default.red("Unable to check for updates")}`);
69121
- lines.push(` ${import_picocolors15.default.dim("Network error or npm registry unavailable")}`);
70334
+ lines.push(` ${SYMBOLS3.cross} ${import_picocolors16.default.red("Unable to check for updates")}`);
70335
+ lines.push(` ${import_picocolors16.default.dim("Network error or npm registry unavailable")}`);
69122
70336
  break;
69123
70337
  case "unknown":
69124
- lines.push(` ${SYMBOLS2.info} ${import_picocolors15.default.yellow("Version information unavailable")}`);
70338
+ lines.push(` ${SYMBOLS3.info} ${import_picocolors16.default.yellow("Version information unavailable")}`);
69125
70339
  break;
69126
70340
  }
69127
70341
  lines.push("");
@@ -69220,69 +70434,31 @@ async function getLocalVersion(options = {}) {
69220
70434
  return 1;
69221
70435
  }
69222
70436
  }
69223
- // src/cli/doctor/constants.ts
69224
- init_plugin_identity();
69225
- var import_picocolors16 = __toESM(require_picocolors(), 1);
69226
- var SYMBOLS3 = {
69227
- check: import_picocolors16.default.green("\u2713"),
69228
- cross: import_picocolors16.default.red("\u2717"),
69229
- warn: import_picocolors16.default.yellow("\u26A0"),
69230
- info: import_picocolors16.default.blue("\u2139"),
69231
- arrow: import_picocolors16.default.cyan("\u2192"),
69232
- bullet: import_picocolors16.default.dim("\u2022"),
69233
- skip: import_picocolors16.default.dim("\u25CB")
69234
- };
69235
- var STATUS_COLORS = {
69236
- pass: import_picocolors16.default.green,
69237
- fail: import_picocolors16.default.red,
69238
- warn: import_picocolors16.default.yellow,
69239
- skip: import_picocolors16.default.dim
69240
- };
69241
- var CHECK_IDS = {
69242
- SYSTEM: "system",
69243
- CONFIG: "config",
69244
- TOOLS: "tools",
69245
- MODELS: "models"
69246
- };
69247
- var CHECK_NAMES = {
69248
- [CHECK_IDS.SYSTEM]: "System",
69249
- [CHECK_IDS.CONFIG]: "Configuration",
69250
- [CHECK_IDS.TOOLS]: "Tools",
69251
- [CHECK_IDS.MODELS]: "Models"
69252
- };
69253
- var EXIT_CODES = {
69254
- SUCCESS: 0,
69255
- FAILURE: 1
69256
- };
69257
- var MIN_OPENCODE_VERSION = "1.0.150";
69258
- var PACKAGE_NAME3 = PLUGIN_NAME;
69259
- var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
69260
-
69261
70437
  // src/cli/doctor/checks/system.ts
69262
- import { existsSync as existsSync24, readFileSync as readFileSync21 } from "fs";
70438
+ import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
69263
70439
 
69264
70440
  // src/cli/doctor/checks/system-binary.ts
69265
70441
  init_spawn_with_windows_hide();
69266
- import { existsSync as existsSync21 } from "fs";
70442
+ import { existsSync as existsSync25 } from "fs";
69267
70443
  import { homedir as homedir5 } from "os";
69268
- import { join as join20 } from "path";
70444
+ import { join as join26 } from "path";
69269
70445
  function getDesktopAppPaths(platform) {
69270
70446
  const home = homedir5();
69271
70447
  switch (platform) {
69272
70448
  case "darwin":
69273
70449
  return [
69274
70450
  "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
69275
- join20(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
70451
+ join26(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
69276
70452
  ];
69277
70453
  case "win32": {
69278
70454
  const programFiles = process.env.ProgramFiles;
69279
70455
  const localAppData = process.env.LOCALAPPDATA;
69280
70456
  const paths = [];
69281
70457
  if (programFiles) {
69282
- paths.push(join20(programFiles, "OpenCode", "OpenCode.exe"));
70458
+ paths.push(join26(programFiles, "OpenCode", "OpenCode.exe"));
69283
70459
  }
69284
70460
  if (localAppData) {
69285
- paths.push(join20(localAppData, "OpenCode", "OpenCode.exe"));
70461
+ paths.push(join26(localAppData, "OpenCode", "OpenCode.exe"));
69286
70462
  }
69287
70463
  return paths;
69288
70464
  }
@@ -69290,8 +70466,8 @@ function getDesktopAppPaths(platform) {
69290
70466
  return [
69291
70467
  "/usr/bin/opencode",
69292
70468
  "/usr/lib/opencode/opencode",
69293
- join20(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
69294
- join20(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
70469
+ join26(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
70470
+ join26(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
69295
70471
  ];
69296
70472
  default:
69297
70473
  return [];
@@ -69303,7 +70479,7 @@ function buildVersionCommand(binaryPath, platform) {
69303
70479
  }
69304
70480
  return [binaryPath, "--version"];
69305
70481
  }
69306
- function findDesktopBinary(platform = process.platform, checkExists = existsSync21) {
70482
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync25) {
69307
70483
  for (const desktopPath of getDesktopAppPaths(platform)) {
69308
70484
  if (checkExists(desktopPath)) {
69309
70485
  return { binary: "opencode", path: desktopPath };
@@ -69320,7 +70496,7 @@ async function findOpenCodeBinary() {
69320
70496
  }
69321
70497
  return findDesktopBinary();
69322
70498
  }
69323
- async function getOpenCodeVersion2(binaryPath, platform = process.platform) {
70499
+ async function getOpenCodeVersion3(binaryPath, platform = process.platform) {
69324
70500
  try {
69325
70501
  const command = buildVersionCommand(binaryPath, platform);
69326
70502
  const processResult = spawnWithWindowsHide(command, { stdout: "pipe", stderr: "pipe" });
@@ -69333,10 +70509,10 @@ async function getOpenCodeVersion2(binaryPath, platform = process.platform) {
69333
70509
  return null;
69334
70510
  }
69335
70511
  }
69336
- function compareVersions(current, minimum) {
69337
- const parseVersion = (version2) => version2.replace(/^v/, "").split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
69338
- const currentParts = parseVersion(current);
69339
- const minimumParts = parseVersion(minimum);
70512
+ function compareVersions3(current, minimum) {
70513
+ const parseVersion3 = (version2) => version2.replace(/^v/, "").split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
70514
+ const currentParts = parseVersion3(current);
70515
+ const minimumParts = parseVersion3(minimum);
69340
70516
  const length = Math.max(currentParts.length, minimumParts.length);
69341
70517
  for (let index = 0;index < length; index++) {
69342
70518
  const currentPart = currentParts[index] ?? 0;
@@ -69351,12 +70527,12 @@ function compareVersions(current, minimum) {
69351
70527
 
69352
70528
  // src/cli/doctor/checks/system-plugin.ts
69353
70529
  init_shared();
69354
- import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
70530
+ import { existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
69355
70531
  function detectConfigPath() {
69356
70532
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
69357
- if (existsSync22(paths.configJsonc))
70533
+ if (existsSync26(paths.configJsonc))
69358
70534
  return paths.configJsonc;
69359
- if (existsSync22(paths.configJson))
70535
+ if (existsSync26(paths.configJson))
69360
70536
  return paths.configJson;
69361
70537
  return null;
69362
70538
  }
@@ -69402,7 +70578,7 @@ function getPluginInfo() {
69402
70578
  };
69403
70579
  }
69404
70580
  try {
69405
- const content = readFileSync19(configPath, "utf-8");
70581
+ const content = readFileSync21(configPath, "utf-8");
69406
70582
  const parsedConfig = parseJsonc(content);
69407
70583
  const pluginEntry = findPluginEntry2(parsedConfig.plugin ?? []);
69408
70584
  if (!pluginEntry) {
@@ -69440,37 +70616,37 @@ function getPluginInfo() {
69440
70616
  init_file_utils();
69441
70617
  init_checker();
69442
70618
  init_auto_update_checker();
69443
- import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
70619
+ import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
69444
70620
  import { homedir as homedir6 } from "os";
69445
- import { join as join21 } from "path";
70621
+ import { join as join27 } from "path";
69446
70622
  init_shared();
69447
70623
  function getPlatformDefaultCacheDir(platform = process.platform) {
69448
70624
  if (platform === "darwin")
69449
- return join21(homedir6(), "Library", "Caches");
70625
+ return join27(homedir6(), "Library", "Caches");
69450
70626
  if (platform === "win32")
69451
- return process.env.LOCALAPPDATA ?? join21(homedir6(), "AppData", "Local");
69452
- return join21(homedir6(), ".cache");
70627
+ return process.env.LOCALAPPDATA ?? join27(homedir6(), "AppData", "Local");
70628
+ return join27(homedir6(), ".cache");
69453
70629
  }
69454
70630
  function resolveOpenCodeCacheDir() {
69455
70631
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
69456
70632
  if (xdgCacheHome)
69457
- return join21(xdgCacheHome, "opencode");
70633
+ return join27(xdgCacheHome, "opencode");
69458
70634
  const fromShared = getOpenCodeCacheDir();
69459
- const platformDefault = join21(getPlatformDefaultCacheDir(), "opencode");
69460
- if (existsSync23(fromShared) || !existsSync23(platformDefault))
70635
+ const platformDefault = join27(getPlatformDefaultCacheDir(), "opencode");
70636
+ if (existsSync27(fromShared) || !existsSync27(platformDefault))
69461
70637
  return fromShared;
69462
70638
  return platformDefault;
69463
70639
  }
69464
70640
  function resolveExistingDir(dirPath) {
69465
- if (!existsSync23(dirPath))
70641
+ if (!existsSync27(dirPath))
69466
70642
  return dirPath;
69467
70643
  return resolveSymlink(dirPath);
69468
70644
  }
69469
70645
  function readPackageJson(filePath) {
69470
- if (!existsSync23(filePath))
70646
+ if (!existsSync27(filePath))
69471
70647
  return null;
69472
70648
  try {
69473
- const content = readFileSync20(filePath, "utf-8");
70649
+ const content = readFileSync22(filePath, "utf-8");
69474
70650
  return parseJsonc(content);
69475
70651
  } catch {
69476
70652
  return null;
@@ -69489,20 +70665,20 @@ function getLoadedPluginVersion() {
69489
70665
  const candidates = [
69490
70666
  {
69491
70667
  cacheDir: configDir,
69492
- cachePackagePath: join21(configDir, "package.json"),
69493
- installedPackagePath: join21(configDir, "node_modules", PACKAGE_NAME3, "package.json")
70668
+ cachePackagePath: join27(configDir, "package.json"),
70669
+ installedPackagePath: join27(configDir, "node_modules", PACKAGE_NAME, "package.json")
69494
70670
  },
69495
70671
  {
69496
70672
  cacheDir,
69497
- cachePackagePath: join21(cacheDir, "package.json"),
69498
- installedPackagePath: join21(cacheDir, "node_modules", PACKAGE_NAME3, "package.json")
70673
+ cachePackagePath: join27(cacheDir, "package.json"),
70674
+ installedPackagePath: join27(cacheDir, "node_modules", PACKAGE_NAME, "package.json")
69499
70675
  }
69500
70676
  ];
69501
- const selectedCandidate = candidates.find((candidate) => existsSync23(candidate.installedPackagePath)) ?? candidates[0];
70677
+ const selectedCandidate = candidates.find((candidate) => existsSync27(candidate.installedPackagePath)) ?? candidates[0];
69502
70678
  const { cacheDir: selectedDir, cachePackagePath, installedPackagePath } = selectedCandidate;
69503
70679
  const cachePackage = readPackageJson(cachePackagePath);
69504
70680
  const installedPackage = readPackageJson(installedPackagePath);
69505
- const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME3]);
70681
+ const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME]);
69506
70682
  const loadedVersion = normalizeVersion(installedPackage?.version);
69507
70683
  return {
69508
70684
  cacheDir: selectedDir,
@@ -69522,13 +70698,14 @@ function getSuggestedInstallTag(currentVersion) {
69522
70698
 
69523
70699
  // src/cli/doctor/checks/system.ts
69524
70700
  init_shared();
70701
+ init_plugin_identity();
69525
70702
  function isConfigValid(configPath) {
69526
70703
  if (!configPath)
69527
70704
  return true;
69528
- if (!existsSync24(configPath))
70705
+ if (!existsSync28(configPath))
69529
70706
  return false;
69530
70707
  try {
69531
- parseJsonc(readFileSync21(configPath, "utf-8"));
70708
+ parseJsonc(readFileSync23(configPath, "utf-8"));
69532
70709
  return true;
69533
70710
  } catch {
69534
70711
  return false;
@@ -69551,7 +70728,7 @@ function buildMessage(status, issues) {
69551
70728
  async function gatherSystemInfo() {
69552
70729
  const [binaryInfo, pluginInfo] = await Promise.all([findOpenCodeBinary(), Promise.resolve(getPluginInfo())]);
69553
70730
  const loadedInfo = getLoadedPluginVersion();
69554
- const opencodeVersion = binaryInfo ? await getOpenCodeVersion2(binaryInfo.path) : null;
70731
+ const opencodeVersion = binaryInfo ? await getOpenCodeVersion3(binaryInfo.path) : null;
69555
70732
  const pluginVersion = pluginInfo.pinnedVersion ?? loadedInfo.expectedVersion ?? loadedInfo.loadedVersion;
69556
70733
  return {
69557
70734
  opencodeVersion,
@@ -69579,7 +70756,7 @@ async function checkSystem() {
69579
70756
  affects: ["doctor", "run"]
69580
70757
  });
69581
70758
  }
69582
- if (systemInfo.opencodeVersion && !compareVersions(systemInfo.opencodeVersion, MIN_OPENCODE_VERSION)) {
70759
+ if (systemInfo.opencodeVersion && !compareVersions3(systemInfo.opencodeVersion, MIN_OPENCODE_VERSION)) {
69583
70760
  issues.push({
69584
70761
  title: "OpenCode version below minimum",
69585
70762
  description: `Detected ${systemInfo.opencodeVersion}; required >= ${MIN_OPENCODE_VERSION}.`,
@@ -69590,13 +70767,26 @@ async function checkSystem() {
69590
70767
  }
69591
70768
  if (!pluginInfo.registered) {
69592
70769
  issues.push({
69593
- title: `${PACKAGE_NAME3} is not registered`,
70770
+ title: `${PLUGIN_NAME} is not registered`,
69594
70771
  description: "Plugin entry is missing from OpenCode configuration.",
69595
- fix: `Run: bunx ${PACKAGE_NAME3} install`,
70772
+ fix: `Run: bunx ${PLUGIN_NAME} install`,
69596
70773
  severity: "error",
69597
70774
  affects: ["all agents"]
69598
70775
  });
69599
70776
  }
70777
+ if (pluginInfo.entry && !pluginInfo.isLocalDev) {
70778
+ const isLegacyName = pluginInfo.entry === LEGACY_PLUGIN_NAME || pluginInfo.entry.startsWith(`${LEGACY_PLUGIN_NAME}@`);
70779
+ if (isLegacyName) {
70780
+ const suggestedEntry = pluginInfo.entry.replace(LEGACY_PLUGIN_NAME, PLUGIN_NAME);
70781
+ issues.push({
70782
+ title: "Using legacy package name",
70783
+ description: `Your opencode.json references "${LEGACY_PLUGIN_NAME}" which has been renamed to "${PLUGIN_NAME}". The old name may stop working in a future release.`,
70784
+ fix: `Update your opencode.json plugin entry: "${pluginInfo.entry}" \u2192 "${suggestedEntry}"`,
70785
+ severity: "warning",
70786
+ affects: ["plugin loading"]
70787
+ });
70788
+ }
70789
+ }
69600
70790
  if (loadedInfo.expectedVersion && loadedInfo.loadedVersion && loadedInfo.expectedVersion !== loadedInfo.loadedVersion) {
69601
70791
  issues.push({
69602
70792
  title: "Loaded plugin version mismatch",
@@ -69606,11 +70796,11 @@ async function checkSystem() {
69606
70796
  affects: ["plugin loading"]
69607
70797
  });
69608
70798
  }
69609
- if (systemInfo.loadedVersion && latestVersion && !compareVersions(systemInfo.loadedVersion, latestVersion)) {
70799
+ if (systemInfo.loadedVersion && latestVersion && !compareVersions3(systemInfo.loadedVersion, latestVersion)) {
69610
70800
  issues.push({
69611
70801
  title: "Loaded plugin is outdated",
69612
70802
  description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
69613
- fix: `Update: cd "${loadedInfo.cacheDir}" && bun add ${PACKAGE_NAME3}@${installTag}`,
70803
+ fix: `Update: cd "${loadedInfo.cacheDir}" && bun add ${PLUGIN_NAME}@${installTag}`,
69614
70804
  severity: "warning",
69615
70805
  affects: ["plugin features"]
69616
70806
  });
@@ -69631,29 +70821,28 @@ async function checkSystem() {
69631
70821
  }
69632
70822
 
69633
70823
  // src/cli/doctor/checks/config.ts
69634
- import { readFileSync as readFileSync24 } from "fs";
69635
- import { join as join25 } from "path";
70824
+ import { readFileSync as readFileSync26 } from "fs";
70825
+ import { join as join31 } from "path";
69636
70826
  init_shared();
69637
- init_plugin_identity();
69638
70827
 
69639
70828
  // src/cli/doctor/checks/model-resolution-cache.ts
69640
70829
  init_shared();
69641
- import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
70830
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
69642
70831
  import { homedir as homedir7 } from "os";
69643
- import { join as join22 } from "path";
70832
+ import { join as join28 } from "path";
69644
70833
  function getOpenCodeCacheDir2() {
69645
70834
  const xdgCache = process.env.XDG_CACHE_HOME;
69646
70835
  if (xdgCache)
69647
- return join22(xdgCache, "opencode");
69648
- return join22(homedir7(), ".cache", "opencode");
70836
+ return join28(xdgCache, "opencode");
70837
+ return join28(homedir7(), ".cache", "opencode");
69649
70838
  }
69650
70839
  function loadAvailableModelsFromCache() {
69651
- const cacheFile = join22(getOpenCodeCacheDir2(), "models.json");
69652
- if (!existsSync25(cacheFile)) {
70840
+ const cacheFile = join28(getOpenCodeCacheDir2(), "models.json");
70841
+ if (!existsSync29(cacheFile)) {
69653
70842
  return { providers: [], modelCount: 0, cacheExists: false };
69654
70843
  }
69655
70844
  try {
69656
- const content = readFileSync22(cacheFile, "utf-8");
70845
+ const content = readFileSync24(cacheFile, "utf-8");
69657
70846
  const data = parseJsonc(content);
69658
70847
  const providers = Object.keys(data);
69659
70848
  let modelCount = 0;
@@ -69675,25 +70864,24 @@ init_model_capabilities();
69675
70864
 
69676
70865
  // src/cli/doctor/checks/model-resolution-config.ts
69677
70866
  init_shared();
69678
- init_plugin_identity();
69679
- import { readFileSync as readFileSync23 } from "fs";
69680
- import { join as join23 } from "path";
69681
- var USER_CONFIG_DIR2 = getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir;
69682
- var PROJECT_CONFIG_DIR = join23(process.cwd(), ".opencode");
70867
+ import { readFileSync as readFileSync25 } from "fs";
70868
+ import { join as join29 } from "path";
70869
+ var PROJECT_CONFIG_DIR = join29(process.cwd(), ".opencode");
69683
70870
  function loadOmoConfig() {
69684
- const projectDetected = detectManagedConfigFile(PROJECT_CONFIG_DIR);
70871
+ const projectDetected = detectPluginConfigFile(PROJECT_CONFIG_DIR);
69685
70872
  if (projectDetected.format !== "none") {
69686
70873
  try {
69687
- const content = readFileSync23(projectDetected.path, "utf-8");
70874
+ const content = readFileSync25(projectDetected.path, "utf-8");
69688
70875
  return parseJsonc(content);
69689
70876
  } catch {
69690
70877
  return null;
69691
70878
  }
69692
70879
  }
69693
- const userDetected = detectManagedConfigFile(USER_CONFIG_DIR2);
70880
+ const userConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
70881
+ const userDetected = detectPluginConfigFile(userConfigDir);
69694
70882
  if (userDetected.format !== "none") {
69695
70883
  try {
69696
- const content = readFileSync23(userDetected.path, "utf-8");
70884
+ const content = readFileSync25(userDetected.path, "utf-8");
69697
70885
  return parseJsonc(content);
69698
70886
  } catch {
69699
70887
  return null;
@@ -69704,7 +70892,7 @@ function loadOmoConfig() {
69704
70892
 
69705
70893
  // src/cli/doctor/checks/model-resolution-details.ts
69706
70894
  init_shared();
69707
- import { join as join24 } from "path";
70895
+ import { join as join30 } from "path";
69708
70896
 
69709
70897
  // src/cli/doctor/checks/model-resolution-variant.ts
69710
70898
  function formatModelWithVariant(model, variant) {
@@ -69746,7 +70934,7 @@ function formatCapabilityResolutionLabel(mode) {
69746
70934
  }
69747
70935
  function buildModelResolutionDetails(options) {
69748
70936
  const details = [];
69749
- const cacheFile = join24(getOpenCodeCacheDir(), "models.json");
70937
+ const cacheFile = join30(getOpenCodeCacheDir(), "models.json");
69750
70938
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
69751
70939
  details.push("");
69752
70940
  if (options.available.cacheExists) {
@@ -69901,11 +71089,13 @@ async function checkModels() {
69901
71089
  }
69902
71090
 
69903
71091
  // src/cli/doctor/checks/config.ts
71092
+ var PROJECT_CONFIG_DIR2 = join31(process.cwd(), ".opencode");
69904
71093
  function findConfigPath() {
69905
- const projectConfig = detectManagedConfigFile(join25(process.cwd(), ".opencode"));
71094
+ const projectConfig = detectPluginConfigFile(PROJECT_CONFIG_DIR2);
69906
71095
  if (projectConfig.format !== "none")
69907
71096
  return projectConfig.path;
69908
- const userConfig = detectManagedConfigFile(getOpenCodeConfigDir({ binary: "opencode" }));
71097
+ const userConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
71098
+ const userConfig = detectPluginConfigFile(userConfigDir);
69909
71099
  if (userConfig.format !== "none")
69910
71100
  return userConfig.path;
69911
71101
  return null;
@@ -69916,7 +71106,7 @@ function validateConfig() {
69916
71106
  return { exists: false, path: null, valid: true, config: null, errors: [] };
69917
71107
  }
69918
71108
  try {
69919
- const content = readFileSync24(configPath, "utf-8");
71109
+ const content = readFileSync26(configPath, "utf-8");
69920
71110
  const rawConfig = parseJsonc(content);
69921
71111
  const schemaResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
69922
71112
  if (!schemaResult.success) {
@@ -70020,9 +71210,9 @@ async function checkConfig() {
70020
71210
 
70021
71211
  // src/cli/doctor/checks/dependencies.ts
70022
71212
  init_spawn_with_windows_hide();
70023
- import { existsSync as existsSync26 } from "fs";
71213
+ import { existsSync as existsSync30 } from "fs";
70024
71214
  import { createRequire } from "module";
70025
- import { dirname as dirname7, join as join26 } from "path";
71215
+ import { dirname as dirname8, join as join32 } from "path";
70026
71216
  async function checkBinaryExists(binary2) {
70027
71217
  try {
70028
71218
  const path10 = Bun.which(binary2);
@@ -70078,15 +71268,15 @@ async function checkAstGrepNapi() {
70078
71268
  path: null
70079
71269
  };
70080
71270
  } catch {
70081
- const { existsSync: existsSync27 } = await import("fs");
70082
- const { join: join27 } = await import("path");
71271
+ const { existsSync: existsSync31 } = await import("fs");
71272
+ const { join: join33 } = await import("path");
70083
71273
  const { homedir: homedir8 } = await import("os");
70084
71274
  const pathsToCheck = [
70085
- join27(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
70086
- join27(process.cwd(), "node_modules", "@ast-grep", "napi")
71275
+ join33(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
71276
+ join33(process.cwd(), "node_modules", "@ast-grep", "napi")
70087
71277
  ];
70088
71278
  for (const napiPath of pathsToCheck) {
70089
- if (existsSync27(napiPath)) {
71279
+ if (existsSync31(napiPath)) {
70090
71280
  return {
70091
71281
  name: "AST-Grep NAPI",
70092
71282
  required: false,
@@ -70111,8 +71301,8 @@ function findCommentCheckerPackageBinary() {
70111
71301
  try {
70112
71302
  const require2 = createRequire(import.meta.url);
70113
71303
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
70114
- const binaryPath = join26(dirname7(pkgPath), "bin", binaryName);
70115
- if (existsSync26(binaryPath))
71304
+ const binaryPath = join32(dirname8(pkgPath), "bin", binaryName);
71305
+ if (existsSync30(binaryPath))
70116
71306
  return binaryPath;
70117
71307
  } catch {}
70118
71308
  return null;
@@ -70269,16 +71459,15 @@ var BUILTIN_SERVERS = {
70269
71459
  "kotlin-ls": { command: ["kotlin-lsp"], extensions: [".kt", ".kts"] }
70270
71460
  };
70271
71461
  // src/tools/lsp/server-config-loader.ts
70272
- import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
70273
- import { join as join27 } from "path";
71462
+ import { existsSync as existsSync31, readFileSync as readFileSync27 } from "fs";
71463
+ import { join as join33 } from "path";
70274
71464
  init_shared();
70275
71465
  init_jsonc_parser();
70276
- init_plugin_identity();
70277
71466
  function loadJsonFile(path10) {
70278
- if (!existsSync27(path10))
71467
+ if (!existsSync31(path10))
70279
71468
  return null;
70280
71469
  try {
70281
- return parseJsonc(readFileSync25(path10, "utf-8"));
71470
+ return parseJsonc(readFileSync27(path10, "utf-8"));
70282
71471
  } catch {
70283
71472
  return null;
70284
71473
  }
@@ -70287,9 +71476,9 @@ function getConfigPaths2() {
70287
71476
  const cwd = process.cwd();
70288
71477
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
70289
71478
  return {
70290
- project: detectManagedConfigFile(join27(cwd, ".opencode")).path,
70291
- user: detectManagedConfigFile(configDir).path,
70292
- opencode: detectConfigFile(join27(configDir, "opencode")).path
71479
+ project: detectPluginConfigFile(join33(cwd, ".opencode")).path,
71480
+ user: detectPluginConfigFile(configDir).path,
71481
+ opencode: detectConfigFile(join33(configDir, "opencode")).path
70293
71482
  };
70294
71483
  }
70295
71484
  function loadAllConfigs() {
@@ -70358,21 +71547,21 @@ function getMergedServers() {
70358
71547
  }
70359
71548
 
70360
71549
  // src/tools/lsp/server-installation.ts
70361
- import { existsSync as existsSync28 } from "fs";
70362
- import { delimiter as delimiter2, join as join29 } from "path";
71550
+ import { existsSync as existsSync32 } from "fs";
71551
+ import { delimiter as delimiter2, join as join35 } from "path";
70363
71552
 
70364
71553
  // src/tools/lsp/server-path-bases.ts
70365
71554
  init_shared();
70366
- import { join as join28 } from "path";
71555
+ import { join as join34 } from "path";
70367
71556
  function getLspServerAdditionalPathBases(workingDirectory) {
70368
71557
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
70369
- const dataDir = join28(getDataDir(), "opencode");
71558
+ const dataDir = join34(getDataDir(), "opencode");
70370
71559
  return [
70371
- join28(workingDirectory, "node_modules", ".bin"),
70372
- join28(configDir, "bin"),
70373
- join28(configDir, "node_modules", ".bin"),
70374
- join28(dataDir, "bin"),
70375
- join28(dataDir, "bin", "node_modules", ".bin")
71560
+ join34(workingDirectory, "node_modules", ".bin"),
71561
+ join34(configDir, "bin"),
71562
+ join34(configDir, "node_modules", ".bin"),
71563
+ join34(dataDir, "bin"),
71564
+ join34(dataDir, "bin", "node_modules", ".bin")
70376
71565
  ];
70377
71566
  }
70378
71567
 
@@ -70382,7 +71571,7 @@ function isServerInstalled(command) {
70382
71571
  return false;
70383
71572
  const cmd = command[0];
70384
71573
  if (cmd.includes("/") || cmd.includes("\\")) {
70385
- if (existsSync28(cmd))
71574
+ if (existsSync32(cmd))
70386
71575
  return true;
70387
71576
  }
70388
71577
  const isWindows = process.platform === "win32";
@@ -70403,14 +71592,14 @@ function isServerInstalled(command) {
70403
71592
  const paths = pathEnv.split(delimiter2);
70404
71593
  for (const p2 of paths) {
70405
71594
  for (const suffix of exts) {
70406
- if (existsSync28(join29(p2, cmd + suffix))) {
71595
+ if (existsSync32(join35(p2, cmd + suffix))) {
70407
71596
  return true;
70408
71597
  }
70409
71598
  }
70410
71599
  }
70411
71600
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
70412
71601
  for (const suffix of exts) {
70413
- if (existsSync28(join29(base, cmd + suffix))) {
71602
+ if (existsSync32(join35(base, cmd + suffix))) {
70414
71603
  return true;
70415
71604
  }
70416
71605
  }
@@ -70472,24 +71661,24 @@ function getInstalledLspServers() {
70472
71661
 
70473
71662
  // src/cli/doctor/checks/tools-mcp.ts
70474
71663
  init_shared();
70475
- import { existsSync as existsSync29, readFileSync as readFileSync26 } from "fs";
71664
+ import { existsSync as existsSync33, readFileSync as readFileSync28 } from "fs";
70476
71665
  import { homedir as homedir8 } from "os";
70477
- import { join as join30 } from "path";
71666
+ import { join as join36 } from "path";
70478
71667
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
70479
71668
  function getMcpConfigPaths() {
70480
71669
  return [
70481
- join30(homedir8(), ".claude", ".mcp.json"),
70482
- join30(process.cwd(), ".mcp.json"),
70483
- join30(process.cwd(), ".claude", ".mcp.json")
71670
+ join36(homedir8(), ".claude", ".mcp.json"),
71671
+ join36(process.cwd(), ".mcp.json"),
71672
+ join36(process.cwd(), ".claude", ".mcp.json")
70484
71673
  ];
70485
71674
  }
70486
71675
  function loadUserMcpConfig() {
70487
71676
  const servers = {};
70488
71677
  for (const configPath of getMcpConfigPaths()) {
70489
- if (!existsSync29(configPath))
71678
+ if (!existsSync33(configPath))
70490
71679
  continue;
70491
71680
  try {
70492
- const content = readFileSync26(configPath, "utf-8");
71681
+ const content = readFileSync28(configPath, "utf-8");
70493
71682
  const config2 = parseJsonc(content);
70494
71683
  if (config2.mcpServers) {
70495
71684
  Object.assign(servers, config2.mcpServers);
@@ -70656,17 +71845,17 @@ function formatStatusSymbol(status) {
70656
71845
  const colorFn = STATUS_COLORS[status];
70657
71846
  switch (status) {
70658
71847
  case "pass":
70659
- return colorFn(SYMBOLS3.check);
71848
+ return colorFn(SYMBOLS2.check);
70660
71849
  case "fail":
70661
- return colorFn(SYMBOLS3.cross);
71850
+ return colorFn(SYMBOLS2.cross);
70662
71851
  case "warn":
70663
- return colorFn(SYMBOLS3.warn);
71852
+ return colorFn(SYMBOLS2.warn);
70664
71853
  case "skip":
70665
- return colorFn(SYMBOLS3.skip);
71854
+ return colorFn(SYMBOLS2.skip);
70666
71855
  }
70667
71856
  }
70668
71857
  function formatStatusMark(available) {
70669
- return available ? import_picocolors17.default.green(SYMBOLS3.check) : import_picocolors17.default.red(SYMBOLS3.cross);
71858
+ return available ? import_picocolors17.default.green(SYMBOLS2.check) : import_picocolors17.default.red(SYMBOLS2.cross);
70670
71859
  }
70671
71860
  function formatHeader() {
70672
71861
  return `
@@ -70689,7 +71878,6 @@ function formatIssue(issue2, index) {
70689
71878
  }
70690
71879
 
70691
71880
  // src/cli/doctor/format-default.ts
70692
- init_plugin_identity();
70693
71881
  function formatDefault(result) {
70694
71882
  const lines = [];
70695
71883
  lines.push(formatHeader());
@@ -70697,12 +71885,12 @@ function formatDefault(result) {
70697
71885
  if (allIssues.length === 0) {
70698
71886
  const opencodeVer = result.systemInfo.opencodeVersion ?? "unknown";
70699
71887
  const pluginVer = result.systemInfo.pluginVersion ?? "unknown";
70700
- lines.push(` ${import_picocolors18.default.green(SYMBOLS3.check)} ${import_picocolors18.default.green(`System OK (opencode ${opencodeVer} \xB7 ${PLUGIN_NAME} ${pluginVer})`)}`);
71888
+ lines.push(` ${import_picocolors18.default.green(SYMBOLS2.check)} ${import_picocolors18.default.green(`System OK (opencode ${opencodeVer} \xB7 evil-omo ${pluginVer})`)}`);
70701
71889
  } else {
70702
71890
  const issueCount = allIssues.filter((i2) => i2.severity === "error").length;
70703
71891
  const warnCount = allIssues.filter((i2) => i2.severity === "warning").length;
70704
71892
  const totalStr = `${issueCount + warnCount} ${issueCount + warnCount === 1 ? "issue" : "issues"}`;
70705
- lines.push(` ${import_picocolors18.default.yellow(SYMBOLS3.warn)} ${totalStr} found:
71893
+ lines.push(` ${import_picocolors18.default.yellow(SYMBOLS2.warn)} ${totalStr} found:
70706
71894
  `);
70707
71895
  allIssues.forEach((issue2, index) => {
70708
71896
  lines.push(formatIssue(issue2, index + 1));
@@ -70745,7 +71933,6 @@ function formatStatus(result) {
70745
71933
 
70746
71934
  // src/cli/doctor/format-verbose.ts
70747
71935
  var import_picocolors20 = __toESM(require_picocolors(), 1);
70748
- init_plugin_identity();
70749
71936
  function formatVerbose(result) {
70750
71937
  const lines = [];
70751
71938
  lines.push(formatHeader());
@@ -70753,7 +71940,7 @@ function formatVerbose(result) {
70753
71940
  lines.push(`${import_picocolors20.default.bold("System Information")}`);
70754
71941
  lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
70755
71942
  lines.push(` ${formatStatusSymbol("pass")} opencode ${systemInfo.opencodeVersion ?? "unknown"}`);
70756
- lines.push(` ${formatStatusSymbol("pass")} ${PLUGIN_NAME} ${systemInfo.pluginVersion ?? "unknown"}`);
71943
+ lines.push(` ${formatStatusSymbol("pass")} evil-omo ${systemInfo.pluginVersion ?? "unknown"}`);
70757
71944
  if (systemInfo.loadedVersion) {
70758
71945
  lines.push(` ${formatStatusSymbol("pass")} loaded ${systemInfo.loadedVersion}`);
70759
71946
  }
@@ -70910,13 +72097,45 @@ async function doctor(options = { mode: "default" }) {
70910
72097
  return result.exitCode;
70911
72098
  }
70912
72099
 
72100
+ // src/cli/refresh-model-capabilities.ts
72101
+ init_model_capabilities_cache();
72102
+ async function refreshModelCapabilities(options, deps = {}) {
72103
+ const directory = options.directory ?? process.cwd();
72104
+ const loadConfig = deps.loadConfig ?? loadPluginConfig;
72105
+ const refreshCache = deps.refreshCache ?? refreshModelCapabilitiesCache;
72106
+ const stdout = deps.stdout ?? process.stdout;
72107
+ const stderr = deps.stderr ?? process.stderr;
72108
+ try {
72109
+ const config2 = loadConfig(directory, null);
72110
+ const sourceUrl = options.sourceUrl ?? config2.model_capabilities?.source_url;
72111
+ const snapshot = await refreshCache({ sourceUrl });
72112
+ const summary = {
72113
+ sourceUrl: snapshot.sourceUrl,
72114
+ generatedAt: snapshot.generatedAt,
72115
+ modelCount: Object.keys(snapshot.models).length
72116
+ };
72117
+ if (options.json) {
72118
+ stdout.write(`${JSON.stringify(summary, null, 2)}
72119
+ `);
72120
+ } else {
72121
+ stdout.write(`Refreshed model capabilities cache (${summary.modelCount} models) from ${summary.sourceUrl}
72122
+ `);
72123
+ }
72124
+ return 0;
72125
+ } catch (error48) {
72126
+ stderr.write(`Failed to refresh model capabilities cache: ${String(error48)}
72127
+ `);
72128
+ return 1;
72129
+ }
72130
+ }
72131
+
70913
72132
  // src/features/mcp-oauth/storage.ts
70914
72133
  init_shared();
70915
- import { chmodSync, existsSync as existsSync30, mkdirSync as mkdirSync7, readFileSync as readFileSync27, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
70916
- import { dirname as dirname8, join as join31 } from "path";
72134
+ import { chmodSync, existsSync as existsSync34, mkdirSync as mkdirSync9, readFileSync as readFileSync29, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
72135
+ import { dirname as dirname9, join as join37 } from "path";
70917
72136
  var STORAGE_FILE_NAME = "mcp-oauth.json";
70918
72137
  function getMcpOauthStoragePath() {
70919
- return join31(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
72138
+ return join37(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
70920
72139
  }
70921
72140
  function normalizeHost(serverHost) {
70922
72141
  let host = serverHost.trim();
@@ -70953,11 +72172,11 @@ function buildKey(serverHost, resource) {
70953
72172
  }
70954
72173
  function readStore() {
70955
72174
  const filePath = getMcpOauthStoragePath();
70956
- if (!existsSync30(filePath)) {
72175
+ if (!existsSync34(filePath)) {
70957
72176
  return null;
70958
72177
  }
70959
72178
  try {
70960
- const content = readFileSync27(filePath, "utf-8");
72179
+ const content = readFileSync29(filePath, "utf-8");
70961
72180
  return JSON.parse(content);
70962
72181
  } catch {
70963
72182
  return null;
@@ -70966,12 +72185,14 @@ function readStore() {
70966
72185
  function writeStore(store2) {
70967
72186
  const filePath = getMcpOauthStoragePath();
70968
72187
  try {
70969
- const dir = dirname8(filePath);
70970
- if (!existsSync30(dir)) {
70971
- mkdirSync7(dir, { recursive: true });
70972
- }
70973
- writeFileSync10(filePath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
70974
- chmodSync(filePath, 384);
72188
+ const dir = dirname9(filePath);
72189
+ if (!existsSync34(dir)) {
72190
+ mkdirSync9(dir, { recursive: true });
72191
+ }
72192
+ const tempPath = `${filePath}.tmp.${Date.now()}`;
72193
+ writeFileSync10(tempPath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
72194
+ chmodSync(tempPath, 384);
72195
+ renameSync3(tempPath, filePath);
70975
72196
  return true;
70976
72197
  } catch {
70977
72198
  return false;
@@ -71002,7 +72223,7 @@ function deleteToken(serverHost, resource) {
71002
72223
  if (Object.keys(store2).length === 0) {
71003
72224
  try {
71004
72225
  const filePath = getMcpOauthStoragePath();
71005
- if (existsSync30(filePath)) {
72226
+ if (existsSync34(filePath)) {
71006
72227
  unlinkSync4(filePath);
71007
72228
  }
71008
72229
  return true;
@@ -71192,7 +72413,7 @@ async function findAvailablePort2(startPort = DEFAULT_PORT) {
71192
72413
  }
71193
72414
 
71194
72415
  // src/features/mcp-oauth/oauth-authorization-flow.ts
71195
- import { spawn as spawn2 } from "child_process";
72416
+ import { spawn } from "child_process";
71196
72417
  import { createHash, randomBytes as randomBytes2 } from "crypto";
71197
72418
  import { createServer } from "http";
71198
72419
  function generateCodeVerifier() {
@@ -71225,7 +72446,7 @@ function startCallbackServer(port) {
71225
72446
  clearTimeout(timeoutId);
71226
72447
  const requestUrl = new URL(request.url ?? "/", `http://localhost:${port}`);
71227
72448
  const code = requestUrl.searchParams.get("code");
71228
- const state = requestUrl.searchParams.get("state");
72449
+ const state2 = requestUrl.searchParams.get("state");
71229
72450
  const error48 = requestUrl.searchParams.get("error");
71230
72451
  if (error48) {
71231
72452
  const errorDescription = requestUrl.searchParams.get("error_description") ?? error48;
@@ -71235,7 +72456,7 @@ function startCallbackServer(port) {
71235
72456
  reject(new Error(`OAuth authorization error: ${errorDescription}`));
71236
72457
  return;
71237
72458
  }
71238
- if (!code || !state) {
72459
+ if (!code || !state2) {
71239
72460
  response.writeHead(400, { "content-type": "text/html" });
71240
72461
  response.end("<html><body><h1>Missing code or state</h1></body></html>");
71241
72462
  server2.close();
@@ -71245,7 +72466,7 @@ function startCallbackServer(port) {
71245
72466
  response.writeHead(200, { "content-type": "text/html" });
71246
72467
  response.end("<html><body><h1>Authorization successful. You can close this tab.</h1></body></html>");
71247
72468
  server2.close();
71248
- resolve2({ code, state });
72469
+ resolve2({ code, state: state2 });
71249
72470
  });
71250
72471
  timeoutId = setTimeout(() => {
71251
72472
  server2.close();
@@ -71273,7 +72494,7 @@ function openBrowser(url2) {
71273
72494
  args = [url2];
71274
72495
  }
71275
72496
  try {
71276
- const child = spawn2(command, args, { stdio: "ignore", detached: true });
72497
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
71277
72498
  child.on("error", () => {});
71278
72499
  child.unref();
71279
72500
  } catch {}
@@ -71281,26 +72502,56 @@ function openBrowser(url2) {
71281
72502
  async function runAuthorizationCodeRedirect(options) {
71282
72503
  const verifier = generateCodeVerifier();
71283
72504
  const challenge = generateCodeChallenge(verifier);
71284
- const state = randomBytes2(16).toString("hex");
72505
+ const state2 = randomBytes2(16).toString("hex");
71285
72506
  const authorizationUrl = buildAuthorizationUrl(options.authorizationEndpoint, {
71286
72507
  clientId: options.clientId,
71287
72508
  redirectUri: options.redirectUri,
71288
72509
  codeChallenge: challenge,
71289
- state,
72510
+ state: state2,
71290
72511
  scopes: options.scopes,
71291
72512
  resource: options.resource
71292
72513
  });
71293
72514
  const callbackPromise = startCallbackServer(options.callbackPort);
71294
72515
  openBrowser(authorizationUrl);
71295
72516
  const result = await callbackPromise;
71296
- if (result.state !== state) {
72517
+ if (result.state !== state2) {
71297
72518
  throw new Error("OAuth state mismatch");
71298
72519
  }
71299
72520
  return { code: result.code, verifier };
71300
72521
  }
71301
72522
 
71302
72523
  // src/features/mcp-oauth/provider.ts
71303
- init_plugin_identity();
72524
+ async function parseTokenResponse(tokenResponse) {
72525
+ if (!tokenResponse.ok) {
72526
+ let errorDetail = `${tokenResponse.status}`;
72527
+ try {
72528
+ const body = await tokenResponse.json();
72529
+ if (body.error) {
72530
+ errorDetail = `${tokenResponse.status} ${body.error}`;
72531
+ if (body.error_description) {
72532
+ errorDetail += `: ${body.error_description}`;
72533
+ }
72534
+ }
72535
+ } catch {}
72536
+ throw new Error(`Token exchange failed: ${errorDetail}`);
72537
+ }
72538
+ return await tokenResponse.json();
72539
+ }
72540
+ function buildOAuthTokenData(tokenData, clientInfo, fallbackRefreshToken) {
72541
+ const accessToken = tokenData.access_token;
72542
+ if (typeof accessToken !== "string") {
72543
+ throw new Error("Token response missing access_token");
72544
+ }
72545
+ return {
72546
+ accessToken,
72547
+ refreshToken: typeof tokenData.refresh_token === "string" ? tokenData.refresh_token : fallbackRefreshToken,
72548
+ expiresAt: typeof tokenData.expires_in === "number" ? Math.floor(Date.now() / 1000) + tokenData.expires_in : undefined,
72549
+ clientInfo: {
72550
+ clientId: clientInfo.clientId,
72551
+ ...clientInfo.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
72552
+ }
72553
+ };
72554
+ }
71304
72555
 
71305
72556
  class McpOAuthProvider {
71306
72557
  serverUrl;
@@ -71369,7 +72620,7 @@ class McpOAuthProvider {
71369
72620
  const clientInfo = await getOrRegisterClient({
71370
72621
  registrationEndpoint: metadata.registrationEndpoint,
71371
72622
  serverIdentifier: this.serverUrl,
71372
- clientName: PLUGIN_NAME,
72623
+ clientName: "evil-omo",
71373
72624
  redirectUris: [this.redirectUrl()],
71374
72625
  tokenEndpointAuthMethod: "none",
71375
72626
  clientId: this.configClientId,
@@ -71396,33 +72647,34 @@ class McpOAuthProvider {
71396
72647
  ...metadata.resource ? { resource: metadata.resource } : {}
71397
72648
  }).toString()
71398
72649
  });
71399
- if (!tokenResponse.ok) {
71400
- let errorDetail = `${tokenResponse.status}`;
71401
- try {
71402
- const body = await tokenResponse.json();
71403
- if (body.error) {
71404
- errorDetail = `${tokenResponse.status} ${body.error}`;
71405
- if (body.error_description) {
71406
- errorDetail += `: ${body.error_description}`;
71407
- }
71408
- }
71409
- } catch {}
71410
- throw new Error(`Token exchange failed: ${errorDetail}`);
71411
- }
71412
- const tokenData = await tokenResponse.json();
71413
- const accessToken = tokenData.access_token;
71414
- if (typeof accessToken !== "string") {
71415
- throw new Error("Token response missing access_token");
72650
+ const tokenData = await parseTokenResponse(tokenResponse);
72651
+ const oauthTokenData = buildOAuthTokenData(tokenData, clientInfo);
72652
+ this.saveTokens(oauthTokenData);
72653
+ return oauthTokenData;
72654
+ }
72655
+ async refresh(refreshToken) {
72656
+ const metadata = await discoverOAuthServerMetadata(this.serverUrl);
72657
+ const clientInfo = this.clientInformation();
72658
+ const clientId = clientInfo?.clientId ?? this.configClientId;
72659
+ if (!clientId) {
72660
+ throw new Error("No client information available. Run login() or register a client first.");
71416
72661
  }
71417
- const oauthTokenData = {
71418
- accessToken,
71419
- refreshToken: typeof tokenData.refresh_token === "string" ? tokenData.refresh_token : undefined,
71420
- expiresAt: typeof tokenData.expires_in === "number" ? Math.floor(Date.now() / 1000) + tokenData.expires_in : undefined,
71421
- clientInfo: {
71422
- clientId: clientInfo.clientId,
71423
- clientSecret: clientInfo.clientSecret
71424
- }
71425
- };
72662
+ const tokenResponse = await fetch(metadata.tokenEndpoint, {
72663
+ method: "POST",
72664
+ headers: { "content-type": "application/x-www-form-urlencoded" },
72665
+ body: new URLSearchParams({
72666
+ grant_type: "refresh_token",
72667
+ refresh_token: refreshToken,
72668
+ client_id: clientId,
72669
+ ...clientInfo?.clientSecret ? { client_secret: clientInfo.clientSecret } : {},
72670
+ ...metadata.resource ? { resource: metadata.resource } : {}
72671
+ }).toString()
72672
+ });
72673
+ const tokenData = await parseTokenResponse(tokenResponse);
72674
+ const oauthTokenData = buildOAuthTokenData(tokenData, {
72675
+ clientId,
72676
+ ...clientInfo?.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
72677
+ }, refreshToken);
71426
72678
  this.saveTokens(oauthTokenData);
71427
72679
  return oauthTokenData;
71428
72680
  }
@@ -71560,7 +72812,7 @@ Examples:
71560
72812
  Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
71561
72813
  Claude Native anthropic/ models (Opus, Sonnet, Haiku)
71562
72814
  OpenAI Native openai/ models (GPT-5.4 for Oracle)
71563
- Gemini Native google/ models (Gemini 3 Pro, Flash)
72815
+ Gemini Native google/ models (Gemini 3.1 Pro, Flash)
71564
72816
  Copilot github-copilot/ models (fallback)
71565
72817
  OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.)
71566
72818
  Z.ai zai-coding-plan/glm-5 (visual-engineering fallback)
@@ -71660,6 +72912,14 @@ Examples:
71660
72912
  const exitCode = await doctor(doctorOptions);
71661
72913
  process.exit(exitCode);
71662
72914
  });
72915
+ program2.command("refresh-model-capabilities").description("Refresh the cached models.dev-based model capabilities snapshot").option("-d, --directory <path>", "Working directory to read evil-omo config from").option("--source-url <url>", "Override the models.dev source URL").option("--json", "Output refresh summary as JSON").action(async (options) => {
72916
+ const exitCode = await refreshModelCapabilities({
72917
+ directory: options.directory,
72918
+ sourceUrl: options.sourceUrl,
72919
+ json: options.json ?? false
72920
+ });
72921
+ process.exit(exitCode);
72922
+ });
71663
72923
  program2.command("version").description("Show version information").action(() => {
71664
72924
  console.log(`evil-omo v${VERSION2}`);
71665
72925
  });