evil-omo 3.15.3 → 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 (49) hide show
  1. package/dist/agents/dynamic-agent-core-sections.d.ts +7 -0
  2. package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
  3. package/dist/cli/config-manager/backup-config.d.ts +6 -0
  4. package/dist/cli/config-manager/version-compatibility.d.ts +9 -0
  5. package/dist/cli/config-manager.d.ts +4 -0
  6. package/dist/cli/doctor/constants.d.ts +1 -1
  7. package/dist/cli/index.js +1435 -529
  8. package/dist/cli/minimum-opencode-version.d.ts +1 -0
  9. package/dist/cli/model-fallback-types.d.ts +3 -0
  10. package/dist/cli/types.d.ts +1 -0
  11. package/dist/create-managers.d.ts +14 -0
  12. package/dist/features/background-agent/compaction-aware-message-resolver.d.ts +5 -2
  13. package/dist/features/boulder-state/storage.d.ts +7 -0
  14. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +1 -1
  15. package/dist/features/claude-code-mcp-loader/env-expander.d.ts +5 -2
  16. package/dist/features/claude-code-plugin-loader/loader.d.ts +15 -0
  17. package/dist/features/claude-code-plugin-loader/scope-filter.d.ts +2 -0
  18. package/dist/features/claude-code-plugin-loader/types.d.ts +11 -0
  19. package/dist/features/claude-code-session-state/state.d.ts +1 -0
  20. package/dist/features/mcp-oauth/provider.d.ts +1 -0
  21. package/dist/features/mcp-oauth/refresh-mutex.d.ts +26 -0
  22. package/dist/features/skill-mcp-manager/error-redaction.d.ts +10 -0
  23. package/dist/features/skill-mcp-manager/oauth-handler.d.ts +7 -0
  24. package/dist/features/skill-mcp-manager/types.d.ts +3 -1
  25. package/dist/hooks/atlas/types.d.ts +1 -0
  26. package/dist/hooks/auto-update-checker/constants.d.ts +2 -2
  27. package/dist/hooks/keyword-detector/hook.d.ts +2 -1
  28. package/dist/hooks/ralph-loop/constants.d.ts +1 -0
  29. package/dist/hooks/ralph-loop/oracle-verification-detector.d.ts +8 -0
  30. package/dist/hooks/read-image-resizer/png-fallback-resizer.d.ts +2 -0
  31. package/dist/hooks/runtime-fallback/auto-retry-signal.d.ts +4 -0
  32. package/dist/hooks/runtime-fallback/error-classifier.d.ts +1 -5
  33. package/dist/hooks/session-recovery/types.d.ts +2 -0
  34. package/dist/hooks/todo-continuation-enforcer/pending-question-detection.d.ts +1 -1
  35. package/dist/hooks/todo-continuation-enforcer/token-limit-detection.d.ts +4 -0
  36. package/dist/hooks/todo-continuation-enforcer/types.d.ts +7 -0
  37. package/dist/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
  38. package/dist/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.d.ts +2 -0
  39. package/dist/index.js +1923 -997
  40. package/dist/plugin/chat-params.d.ts +1 -0
  41. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
  42. package/dist/shared/agent-display-names.d.ts +9 -2
  43. package/dist/shared/compaction-marker.d.ts +12 -0
  44. package/dist/shared/index.d.ts +1 -0
  45. package/dist/shared/internal-initiator-marker.d.ts +1 -0
  46. package/dist/shared/session-prompt-params-state.d.ts +1 -0
  47. package/dist/tools/background-task/constants.d.ts +1 -1
  48. package/package.json +16 -18
  49. package/postinstall.mjs +63 -1
package/dist/cli/index.js CHANGED
@@ -5995,9 +5995,13 @@ var init_plugin_identity = __esm(() => {
5995
5995
  // src/shared/jsonc-parser.ts
5996
5996
  import { existsSync, readFileSync } from "fs";
5997
5997
  import { join as join4 } from "path";
5998
+ function stripBom(content) {
5999
+ return content.charCodeAt(0) === 65279 ? content.slice(1) : content;
6000
+ }
5998
6001
  function parseJsonc(content) {
6002
+ content = content.replace(/^\uFEFF/, "");
5999
6003
  const errors = [];
6000
- const result = parse2(content, errors, {
6004
+ const result = parse2(stripBom(content), errors, {
6001
6005
  allowTrailingComma: true,
6002
6006
  disallowComments: false
6003
6007
  });
@@ -6061,15 +6065,15 @@ var init_agent_names = __esm(() => {
6061
6065
  "omo-plan": "prometheus",
6062
6066
  "Planner-Sisyphus": "prometheus",
6063
6067
  "planner-sisyphus": "prometheus",
6064
- "Prometheus (Planner)": "prometheus",
6068
+ "Prometheus - Plan Builder": "prometheus",
6065
6069
  prometheus: "prometheus",
6066
6070
  "orchestrator-sisyphus": "atlas",
6067
6071
  Atlas: "atlas",
6068
6072
  atlas: "atlas",
6069
6073
  "plan-consultant": "metis",
6070
- "Metis (Plan Consultant)": "metis",
6074
+ "Metis - Plan Consultant": "metis",
6071
6075
  metis: "metis",
6072
- "Momus (Plan Reviewer)": "momus",
6076
+ "Momus - Plan Critic": "momus",
6073
6077
  momus: "momus",
6074
6078
  "Sisyphus-Junior": "sisyphus-junior",
6075
6079
  "sisyphus-junior": "sisyphus-junior",
@@ -48392,6 +48396,57 @@ var init_constants = __esm(() => {
48392
48396
  init_shared();
48393
48397
  });
48394
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
+
48395
48450
  // src/features/hook-message-injector/injector.ts
48396
48451
  import { randomBytes } from "crypto";
48397
48452
  var processPrefix;
@@ -48400,6 +48455,7 @@ var init_injector = __esm(() => {
48400
48455
  init_logger();
48401
48456
  init_opencode_storage_detection();
48402
48457
  init_shared();
48458
+ init_compaction_marker();
48403
48459
  processPrefix = randomBytes(4).toString("hex");
48404
48460
  });
48405
48461
 
@@ -48409,35 +48465,24 @@ var init_hook_message_injector = __esm(() => {
48409
48465
  init_constants();
48410
48466
  });
48411
48467
 
48412
- // src/shared/opencode-storage-paths.ts
48413
- import { join as join9 } from "path";
48414
- var OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE;
48415
- var init_opencode_storage_paths = __esm(() => {
48416
- init_data_path();
48417
- OPENCODE_STORAGE = getOpenCodeStorageDir();
48418
- MESSAGE_STORAGE = join9(OPENCODE_STORAGE, "message");
48419
- PART_STORAGE = join9(OPENCODE_STORAGE, "part");
48420
- SESSION_STORAGE = join9(OPENCODE_STORAGE, "session");
48421
- });
48422
-
48423
48468
  // src/shared/opencode-message-dir.ts
48424
- import { existsSync as existsSync6, readdirSync } from "fs";
48425
- import { join as join10 } from "path";
48469
+ import { existsSync as existsSync7, readdirSync as readdirSync2 } from "fs";
48470
+ import { join as join11 } from "path";
48426
48471
  function getMessageDir(sessionID) {
48427
48472
  if (!sessionID.startsWith("ses_"))
48428
48473
  return null;
48429
48474
  if (/[/\\]|\.\./.test(sessionID))
48430
48475
  return null;
48431
- if (!existsSync6(MESSAGE_STORAGE))
48476
+ if (!existsSync7(MESSAGE_STORAGE))
48432
48477
  return null;
48433
- const directPath = join10(MESSAGE_STORAGE, sessionID);
48434
- if (existsSync6(directPath)) {
48478
+ const directPath = join11(MESSAGE_STORAGE, sessionID);
48479
+ if (existsSync7(directPath)) {
48435
48480
  return directPath;
48436
48481
  }
48437
48482
  try {
48438
- for (const dir of readdirSync(MESSAGE_STORAGE)) {
48439
- const sessionPath = join10(MESSAGE_STORAGE, dir, sessionID);
48440
- if (existsSync6(sessionPath)) {
48483
+ for (const dir of readdirSync2(MESSAGE_STORAGE)) {
48484
+ const sessionPath = join11(MESSAGE_STORAGE, dir, sessionID);
48485
+ if (existsSync7(sessionPath)) {
48441
48486
  return sessionPath;
48442
48487
  }
48443
48488
  }
@@ -48472,22 +48517,25 @@ function getAgentConfigKey(agentName) {
48472
48517
  const reversed = REVERSE_DISPLAY_NAMES[lower];
48473
48518
  if (reversed !== undefined)
48474
48519
  return reversed;
48520
+ const legacy = LEGACY_DISPLAY_NAMES[lower];
48521
+ if (legacy !== undefined)
48522
+ return legacy;
48475
48523
  if (AGENT_DISPLAY_NAMES[lower] !== undefined)
48476
48524
  return lower;
48477
48525
  return lower;
48478
48526
  }
48479
- var AGENT_DISPLAY_NAMES, REVERSE_DISPLAY_NAMES;
48527
+ var AGENT_DISPLAY_NAMES, REVERSE_DISPLAY_NAMES, LEGACY_DISPLAY_NAMES;
48480
48528
  var init_agent_display_names = __esm(() => {
48481
48529
  AGENT_DISPLAY_NAMES = {
48482
- sisyphus: "Sisyphus (Ultraworker)",
48483
- hephaestus: "Hephaestus (Deep Agent)",
48484
- prometheus: "Prometheus (Plan Builder)",
48485
- atlas: "Atlas (Plan Executor)",
48530
+ sisyphus: "Sisyphus - Ultraworker",
48531
+ hephaestus: "Hephaestus - Deep Agent",
48532
+ prometheus: "Prometheus - Plan Builder",
48533
+ atlas: "Atlas - Plan Executor",
48486
48534
  "sisyphus-junior": "Sisyphus-Junior",
48487
- metis: "Metis (Plan Consultant)",
48488
- momus: "Momus (Plan Critic)",
48489
- athena: "Athena (Council)",
48490
- "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",
48491
48539
  oracle: "oracle",
48492
48540
  librarian: "librarian",
48493
48541
  explore: "explore",
@@ -48495,6 +48543,16 @@ var init_agent_display_names = __esm(() => {
48495
48543
  "council-member": "council-member"
48496
48544
  };
48497
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
+ };
48498
48556
  });
48499
48557
 
48500
48558
  // src/shared/session-utils.ts
@@ -48658,9 +48716,18 @@ var init_session_tools_store = __esm(() => {
48658
48716
  var init_prompt_tools = __esm(() => {
48659
48717
  init_session_tools_store();
48660
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
+
48661
48727
  // src/features/claude-code-plugin-loader/discovery.ts
48662
48728
  var init_discovery = __esm(() => {
48663
48729
  init_logger();
48730
+ init_scope_filter();
48664
48731
  });
48665
48732
 
48666
48733
  // src/features/claude-code-plugin-loader/command-loader.ts
@@ -48711,7 +48778,7 @@ var init_env_expander = __esm(() => {
48711
48778
  });
48712
48779
 
48713
48780
  // src/features/claude-code-mcp-loader/scope-filter.ts
48714
- var init_scope_filter = __esm(() => {
48781
+ var init_scope_filter2 = __esm(() => {
48715
48782
  init_contains_path();
48716
48783
  });
48717
48784
 
@@ -48722,7 +48789,7 @@ var init_transformer = __esm(() => {
48722
48789
  // src/features/claude-code-plugin-loader/mcp-server-loader.ts
48723
48790
  var init_mcp_server_loader = __esm(() => {
48724
48791
  init_env_expander();
48725
- init_scope_filter();
48792
+ init_scope_filter2();
48726
48793
  init_transformer();
48727
48794
  init_logger();
48728
48795
  });
@@ -48858,6 +48925,8 @@ var init_shared = __esm(() => {
48858
48925
  init_project_discovery_dirs();
48859
48926
  init_session_directory_resolver();
48860
48927
  init_prompt_tools();
48928
+ init_compaction_marker();
48929
+ init_internal_initiator_marker();
48861
48930
  init_plugin_command_discovery();
48862
48931
  init_plugin_identity();
48863
48932
  init_log_legacy_plugin_startup_warning();
@@ -48939,12 +49008,37 @@ var init_plugin_name_with_version = __esm(() => {
48939
49008
  PRIORITIZED_TAGS = ["latest", "beta", "next"];
48940
49009
  });
48941
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
+
48942
49036
  // src/cli/config-manager/ensure-config-directory-exists.ts
48943
- import { existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
49037
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
48944
49038
  function ensureConfigDirectoryExists() {
48945
49039
  const configDir = getConfigDir();
48946
- if (!existsSync7(configDir)) {
48947
- mkdirSync3(configDir, { recursive: true });
49040
+ if (!existsSync9(configDir)) {
49041
+ mkdirSync4(configDir, { recursive: true });
48948
49042
  }
48949
49043
  }
48950
49044
  var init_ensure_config_directory_exists = __esm(() => {
@@ -48981,14 +49075,14 @@ function formatErrorWithSuggestion(err, context) {
48981
49075
  }
48982
49076
 
48983
49077
  // src/cli/config-manager/opencode-config-format.ts
48984
- import { existsSync as existsSync8 } from "fs";
49078
+ import { existsSync as existsSync10 } from "fs";
48985
49079
  function detectConfigFormat() {
48986
49080
  const configJsonc = getConfigJsonc();
48987
49081
  const configJson = getConfigJson();
48988
- if (existsSync8(configJsonc)) {
49082
+ if (existsSync10(configJsonc)) {
48989
49083
  return { format: "jsonc", path: configJsonc };
48990
49084
  }
48991
- if (existsSync8(configJson)) {
49085
+ if (existsSync10(configJson)) {
48992
49086
  return { format: "json", path: configJson };
48993
49087
  }
48994
49088
  return { format: "none", path: configJson };
@@ -48998,7 +49092,7 @@ var init_opencode_config_format = __esm(() => {
48998
49092
  });
48999
49093
 
49000
49094
  // src/cli/config-manager/parse-opencode-config-file.ts
49001
- import { readFileSync as readFileSync4, statSync } from "fs";
49095
+ import { readFileSync as readFileSync5, statSync } from "fs";
49002
49096
  function isEmptyOrWhitespace(content) {
49003
49097
  return content.trim().length === 0;
49004
49098
  }
@@ -49008,7 +49102,7 @@ function parseOpenCodeConfigFileWithError(path3) {
49008
49102
  if (stat.size === 0) {
49009
49103
  return { config: null, error: `Config file is empty: ${path3}. Delete it or add valid JSON content.` };
49010
49104
  }
49011
- const content = readFileSync4(path3, "utf-8");
49105
+ const content = readFileSync5(path3, "utf-8");
49012
49106
  if (isEmptyOrWhitespace(content)) {
49013
49107
  return { config: null, error: `Config file contains only whitespace: ${path3}. Delete it or add valid JSON content.` };
49014
49108
  }
@@ -49031,8 +49125,90 @@ var init_parse_opencode_config_file = __esm(() => {
49031
49125
  init_shared();
49032
49126
  });
49033
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
+
49034
49210
  // src/cli/config-manager/add-plugin-to-opencode-config.ts
49035
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
49211
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
49036
49212
  async function addPluginToOpenCodeConfig(currentVersion) {
49037
49213
  try {
49038
49214
  ensureConfigDirectoryExists();
@@ -49065,19 +49241,35 @@ async function addPluginToOpenCodeConfig(currentVersion) {
49065
49241
  const canonicalEntries = plugins.filter((plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`));
49066
49242
  const legacyEntries = plugins.filter((plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`));
49067
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
+ };
49254
+ }
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
+ }
49068
49264
  const normalizedPlugins = [...otherPlugins];
49069
- if (canonicalEntries.length > 0) {
49070
- normalizedPlugins.push(canonicalEntries[0]);
49071
- } else if (legacyEntries.length > 0) {
49072
- const versionMatch = legacyEntries[0].match(/@(.+)$/);
49073
- const preservedVersion = versionMatch ? versionMatch[1] : null;
49074
- normalizedPlugins.push(preservedVersion ? `${PLUGIN_NAME}@${preservedVersion}` : pluginEntry);
49265
+ if (canonicalEntries.length > 0 || legacyEntries.length > 0) {
49266
+ normalizedPlugins.push(pluginEntry);
49075
49267
  } else {
49076
49268
  normalizedPlugins.push(pluginEntry);
49077
49269
  }
49078
49270
  config.plugin = normalizedPlugins;
49079
49271
  if (format2 === "jsonc") {
49080
- const content = readFileSync5(path3, "utf-8");
49272
+ const content = readFileSync6(path3, "utf-8");
49081
49273
  const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/;
49082
49274
  const match = content.match(pluginArrayRegex);
49083
49275
  if (match) {
@@ -49107,6 +49299,7 @@ async function addPluginToOpenCodeConfig(currentVersion) {
49107
49299
  }
49108
49300
  var init_add_plugin_to_opencode_config = __esm(() => {
49109
49301
  init_shared();
49302
+ init_backup_config();
49110
49303
  init_config_context();
49111
49304
  init_ensure_config_directory_exists();
49112
49305
  init_opencode_config_format();
@@ -49222,6 +49415,47 @@ var init_fallback_chain_resolution = __esm(() => {
49222
49415
  });
49223
49416
 
49224
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
+ }
49225
49459
  function generateModelConfig(config) {
49226
49460
  const avail = toProviderAvailability(config);
49227
49461
  const hasAnyProvider = avail.native.claude || avail.native.openai || avail.native.gemini || avail.opencodeZen || avail.copilot || avail.zai || avail.kimiForCoding || avail.opencodeGo;
@@ -49236,25 +49470,31 @@ function generateModelConfig(config) {
49236
49470
  const categories = {};
49237
49471
  for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) {
49238
49472
  if (role === "librarian") {
49473
+ let agentConfig;
49239
49474
  if (avail.opencodeGo) {
49240
- agents[role] = { model: "opencode-go/minimax-m2.7" };
49475
+ agentConfig = { model: "opencode-go/minimax-m2.7" };
49241
49476
  } else if (avail.zai) {
49242
- agents[role] = { model: ZAI_MODEL };
49477
+ agentConfig = { model: ZAI_MODEL };
49478
+ }
49479
+ if (agentConfig) {
49480
+ agents[role] = attachAllFallbackModels(agentConfig, req.fallbackChain, avail);
49243
49481
  }
49244
49482
  continue;
49245
49483
  }
49246
49484
  if (role === "explore") {
49485
+ let agentConfig;
49247
49486
  if (avail.native.claude) {
49248
- agents[role] = { model: "anthropic/claude-haiku-4-5" };
49487
+ agentConfig = { model: "anthropic/claude-haiku-4-5" };
49249
49488
  } else if (avail.opencodeZen) {
49250
- agents[role] = { model: "opencode/claude-haiku-4-5" };
49489
+ agentConfig = { model: "opencode/claude-haiku-4-5" };
49251
49490
  } else if (avail.opencodeGo) {
49252
- agents[role] = { model: "opencode-go/minimax-m2.7" };
49491
+ agentConfig = { model: "opencode-go/minimax-m2.7" };
49253
49492
  } else if (avail.copilot) {
49254
- agents[role] = { model: "github-copilot/gpt-5-mini" };
49493
+ agentConfig = { model: "github-copilot/gpt-5-mini" };
49255
49494
  } else {
49256
- agents[role] = { model: "opencode/gpt-5-nano" };
49495
+ agentConfig = { model: "opencode/gpt-5-nano" };
49257
49496
  }
49497
+ agents[role] = attachAllFallbackModels(agentConfig, req.fallbackChain, avail);
49258
49498
  continue;
49259
49499
  }
49260
49500
  if (role === "sisyphus") {
@@ -49265,7 +49505,8 @@ function generateModelConfig(config) {
49265
49505
  const resolved2 = resolveModelFromChain(fallbackChain, avail);
49266
49506
  if (resolved2) {
49267
49507
  const variant = resolved2.variant ?? req.variant;
49268
- 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);
49269
49510
  }
49270
49511
  continue;
49271
49512
  }
@@ -49278,7 +49519,8 @@ function generateModelConfig(config) {
49278
49519
  const resolved = resolveModelFromChain(req.fallbackChain, avail);
49279
49520
  if (resolved) {
49280
49521
  const variant = resolved.variant ?? req.variant;
49281
- 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);
49282
49524
  } else {
49283
49525
  agents[role] = { model: ULTIMATE_FALLBACK };
49284
49526
  }
@@ -49294,7 +49536,8 @@ function generateModelConfig(config) {
49294
49536
  const resolved = resolveModelFromChain(fallbackChain, avail);
49295
49537
  if (resolved) {
49296
49538
  const variant = resolved.variant ?? req.variant;
49297
- 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);
49298
49541
  } else {
49299
49542
  categories[cat] = { model: ULTIMATE_FALLBACK };
49300
49543
  }
@@ -49311,6 +49554,7 @@ var init_model_fallback = __esm(() => {
49311
49554
  init_model_fallback_requirements();
49312
49555
  init_openai_only_model_catalog();
49313
49556
  init_fallback_chain_resolution();
49557
+ init_provider_model_id_transform();
49314
49558
  });
49315
49559
 
49316
49560
  // src/cli/config-manager/generate-omo-config.ts
@@ -49339,7 +49583,7 @@ function deepMergeRecord(target, source) {
49339
49583
  }
49340
49584
 
49341
49585
  // src/cli/config-manager/write-omo-config.ts
49342
- import { existsSync as existsSync9, 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";
49343
49587
  function isEmptyOrWhitespace2(content) {
49344
49588
  return content.trim().length === 0;
49345
49589
  }
@@ -49356,10 +49600,18 @@ function writeOmoConfig(installConfig) {
49356
49600
  const omoConfigPath = getOmoConfigPath();
49357
49601
  try {
49358
49602
  const newConfig = generateOmoConfig(installConfig);
49359
- if (existsSync9(omoConfigPath)) {
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
+ }
49360
49612
  try {
49361
49613
  const stat = statSync2(omoConfigPath);
49362
- const content = readFileSync6(omoConfigPath, "utf-8");
49614
+ const content = readFileSync7(omoConfigPath, "utf-8");
49363
49615
  if (stat.size === 0 || isEmptyOrWhitespace2(content)) {
49364
49616
  writeFileSync4(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
49365
49617
  `);
@@ -49397,6 +49649,7 @@ function writeOmoConfig(installConfig) {
49397
49649
  }
49398
49650
  var init_write_omo_config = __esm(() => {
49399
49651
  init_shared();
49652
+ init_backup_config();
49400
49653
  init_config_context();
49401
49654
  init_ensure_config_directory_exists();
49402
49655
  init_generate_omo_config();
@@ -49499,10 +49752,10 @@ var init_opencode_binary = __esm(() => {
49499
49752
  });
49500
49753
 
49501
49754
  // src/cli/config-manager/detect-current-config.ts
49502
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
49755
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
49503
49756
  function detectProvidersFromOmoConfig() {
49504
49757
  const omoConfigPath = getOmoConfigPath();
49505
- if (!existsSync10(omoConfigPath)) {
49758
+ if (!existsSync12(omoConfigPath)) {
49506
49759
  return {
49507
49760
  hasOpenAI: true,
49508
49761
  hasOpencodeZen: true,
@@ -49512,7 +49765,7 @@ function detectProvidersFromOmoConfig() {
49512
49765
  };
49513
49766
  }
49514
49767
  try {
49515
- const content = readFileSync7(omoConfigPath, "utf-8");
49768
+ const content = readFileSync8(omoConfigPath, "utf-8");
49516
49769
  const omoConfig = parseJsonc(content);
49517
49770
  if (!omoConfig || typeof omoConfig !== "object") {
49518
49771
  return {
@@ -49543,9 +49796,13 @@ function detectProvidersFromOmoConfig() {
49543
49796
  function isOurPlugin(plugin) {
49544
49797
  return plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) || plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`);
49545
49798
  }
49799
+ function findOurPluginEntry(plugins) {
49800
+ return plugins.find(isOurPlugin) ?? null;
49801
+ }
49546
49802
  function detectCurrentConfig() {
49547
49803
  const result = {
49548
49804
  isInstalled: false,
49805
+ installedVersion: null,
49549
49806
  hasClaude: true,
49550
49807
  isMax20: true,
49551
49808
  hasOpenAI: true,
@@ -49566,7 +49823,11 @@ function detectCurrentConfig() {
49566
49823
  }
49567
49824
  const openCodeConfig = parseResult.config;
49568
49825
  const plugins = openCodeConfig.plugin ?? [];
49569
- result.isInstalled = plugins.some(isOurPlugin);
49826
+ const ourPluginEntry = findOurPluginEntry(plugins);
49827
+ result.isInstalled = !!ourPluginEntry;
49828
+ if (ourPluginEntry) {
49829
+ result.installedVersion = extractVersionFromPluginEntry(ourPluginEntry);
49830
+ }
49570
49831
  if (!result.isInstalled) {
49571
49832
  return result;
49572
49833
  }
@@ -49588,10 +49849,10 @@ var init_detect_current_config = __esm(() => {
49588
49849
  });
49589
49850
 
49590
49851
  // src/cli/config-manager/bun-install.ts
49591
- import { existsSync as existsSync11 } from "fs";
49592
- import { join as join11 } from "path";
49852
+ import { existsSync as existsSync13 } from "fs";
49853
+ import { join as join12 } from "path";
49593
49854
  function getDefaultWorkspaceDir() {
49594
- return join11(getOpenCodeCacheDir(), "packages");
49855
+ return join12(getOpenCodeCacheDir(), "packages");
49595
49856
  }
49596
49857
  function readProcessOutput(stream) {
49597
49858
  if (!stream) {
@@ -49617,7 +49878,7 @@ async function runBunInstallWithDetails(options) {
49617
49878
  const outputMode = options?.outputMode ?? "pipe";
49618
49879
  const cacheDir = options?.workspaceDir ?? getDefaultWorkspaceDir();
49619
49880
  const packageJsonPath = `${cacheDir}/package.json`;
49620
- if (!existsSync11(packageJsonPath)) {
49881
+ if (!existsSync13(packageJsonPath)) {
49621
49882
  return {
49622
49883
  success: false,
49623
49884
  error: `Workspace not initialized: ${packageJsonPath} not found. OpenCode should create this on first run.`
@@ -49693,6 +49954,7 @@ var init_config_manager = __esm(() => {
49693
49954
  init_opencode_binary();
49694
49955
  init_detect_current_config();
49695
49956
  init_bun_install();
49957
+ init_backup_config();
49696
49958
  });
49697
49959
 
49698
49960
  // node_modules/sisteransi/src/index.js
@@ -49753,6 +50015,462 @@ var require_src = __commonJS((exports, module) => {
49753
50015
  module.exports = { cursor, scroll, erase, beep };
49754
50016
  });
49755
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
+
49756
50474
  // src/hooks/auto-update-checker/constants.ts
49757
50475
  import * as path4 from "path";
49758
50476
  import * as os3 from "os";
@@ -49770,15 +50488,15 @@ function getUserOpencodeConfig() {
49770
50488
  function getUserOpencodeConfigJsonc() {
49771
50489
  return path4.join(getUserConfigDir(), "opencode.jsonc");
49772
50490
  }
49773
- var PACKAGE_NAME = "oh-my-openagent", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_ROOT_DIR, CACHE_DIR, VERSION_FILE, INSTALLED_PACKAGE_JSON;
50491
+ var PACKAGE_NAME2 = "oh-my-opencode", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_ROOT_DIR, CACHE_DIR, VERSION_FILE, INSTALLED_PACKAGE_JSON;
49774
50492
  var init_constants3 = __esm(() => {
49775
50493
  init_data_path();
49776
50494
  init_opencode_config_dir();
49777
- NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
50495
+ NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME2}/dist-tags`;
49778
50496
  CACHE_ROOT_DIR = getOpenCodeCacheDir();
49779
50497
  CACHE_DIR = path4.join(CACHE_ROOT_DIR, "packages");
49780
50498
  VERSION_FILE = path4.join(CACHE_ROOT_DIR, "version");
49781
- INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
50499
+ INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
49782
50500
  });
49783
50501
 
49784
50502
  // src/hooks/auto-update-checker/checker/config-paths.ts
@@ -49833,7 +50551,7 @@ function getLocalDevPath(directory) {
49833
50551
  const config2 = JSON.parse(stripJsonComments(content));
49834
50552
  const plugins = config2.plugin ?? [];
49835
50553
  for (const entry of plugins) {
49836
- if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
50554
+ if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME2)) {
49837
50555
  try {
49838
50556
  return fileURLToPath(entry);
49839
50557
  } catch {
@@ -49865,7 +50583,7 @@ function findPackageJsonUp(startPath) {
49865
50583
  try {
49866
50584
  const content = fs5.readFileSync(pkgPath, "utf-8");
49867
50585
  const pkg = JSON.parse(content);
49868
- if (pkg.name === PACKAGE_NAME)
50586
+ if (pkg.name === PACKAGE_NAME2)
49869
50587
  return pkgPath;
49870
50588
  } catch {}
49871
50589
  }
@@ -49914,13 +50632,15 @@ function findPluginEntry(directory) {
49914
50632
  const config2 = JSON.parse(stripJsonComments(content));
49915
50633
  const plugins = config2.plugin ?? [];
49916
50634
  for (const entry of plugins) {
49917
- if (entry === PACKAGE_NAME) {
49918
- return { entry, isPinned: false, pinnedVersion: null, configPath };
49919
- }
49920
- if (entry.startsWith(`${PACKAGE_NAME}@`)) {
49921
- const pinnedVersion = entry.slice(PACKAGE_NAME.length + 1);
49922
- const isPinned = EXACT_SEMVER_REGEX.test(pinnedVersion.trim());
49923
- return { entry, isPinned, pinnedVersion, configPath };
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
+ }
49924
50644
  }
49925
50645
  }
49926
50646
  } catch {
@@ -49929,11 +50649,13 @@ function findPluginEntry(directory) {
49929
50649
  }
49930
50650
  return null;
49931
50651
  }
49932
- var EXACT_SEMVER_REGEX;
50652
+ var EXACT_SEMVER_REGEX, MATCH_PLUGIN_NAMES;
49933
50653
  var init_plugin_entry = __esm(() => {
49934
50654
  init_constants3();
49935
50655
  init_config_paths();
50656
+ init_plugin_identity();
49936
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];
49937
50659
  });
49938
50660
 
49939
50661
  // src/hooks/auto-update-checker/checker/cached-version.ts
@@ -49973,6 +50695,23 @@ function getCachedVersion() {
49973
50695
  } catch (err) {
49974
50696
  log("[auto-update-checker] Failed to resolve version from execPath:", err);
49975
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 {}
49976
50715
  return null;
49977
50716
  }
49978
50717
  var init_cached_version = __esm(() => {
@@ -50141,7 +50880,7 @@ function syncCachePackageJsonToIntent(pluginInfo) {
50141
50880
  if (!fs9.existsSync(cachePackageJsonPath)) {
50142
50881
  log("[auto-update-checker] Cache package.json missing, creating workspace package.json", { intentVersion });
50143
50882
  return {
50144
- ...writeCachePackageJson(cachePackageJsonPath, { dependencies: { [PACKAGE_NAME]: intentVersion } }),
50883
+ ...writeCachePackageJson(cachePackageJsonPath, { dependencies: { [PACKAGE_NAME2]: intentVersion } }),
50145
50884
  message: `Created cache package.json with: ${intentVersion}`
50146
50885
  };
50147
50886
  }
@@ -50159,21 +50898,21 @@ function syncCachePackageJsonToIntent(pluginInfo) {
50159
50898
  log("[auto-update-checker] Failed to parse cache package.json:", err);
50160
50899
  return { synced: false, error: "parse_error", message: "Failed to parse cache package.json (malformed JSON)" };
50161
50900
  }
50162
- if (!pkgJson || !pkgJson.dependencies?.[PACKAGE_NAME]) {
50901
+ if (!pkgJson || !pkgJson.dependencies?.[PACKAGE_NAME2]) {
50163
50902
  log("[auto-update-checker] Plugin missing from cache package.json dependencies, adding dependency", { intentVersion });
50164
50903
  const nextPkgJson = {
50165
50904
  ...pkgJson ?? {},
50166
50905
  dependencies: {
50167
50906
  ...pkgJson?.dependencies ?? {},
50168
- [PACKAGE_NAME]: intentVersion
50907
+ [PACKAGE_NAME2]: intentVersion
50169
50908
  }
50170
50909
  };
50171
50910
  return {
50172
50911
  ...writeCachePackageJson(cachePackageJsonPath, nextPkgJson),
50173
- message: `Added ${PACKAGE_NAME}: ${intentVersion}`
50912
+ message: `Added ${PACKAGE_NAME2}: ${intentVersion}`
50174
50913
  };
50175
50914
  }
50176
- const currentVersion = pkgJson.dependencies[PACKAGE_NAME];
50915
+ const currentVersion = pkgJson.dependencies[PACKAGE_NAME2];
50177
50916
  if (currentVersion === intentVersion) {
50178
50917
  log("[auto-update-checker] Cache package.json already matches intent:", intentVersion);
50179
50918
  return { synced: false, error: null, message: `Already matches intent: ${intentVersion}` };
@@ -50185,7 +50924,7 @@ function syncCachePackageJsonToIntent(pluginInfo) {
50185
50924
  } else {
50186
50925
  log(`[auto-update-checker] Updating cache package.json: "${currentVersion}" \u2192 "${intentVersion}"`);
50187
50926
  }
50188
- pkgJson.dependencies[PACKAGE_NAME] = intentVersion;
50927
+ pkgJson.dependencies[PACKAGE_NAME2] = intentVersion;
50189
50928
  return {
50190
50929
  ...writeCachePackageJson(cachePackageJsonPath, pkgJson),
50191
50930
  message: `Updated: "${currentVersion}" \u2192 "${intentVersion}"`
@@ -50251,7 +50990,7 @@ function removeFromBunLock(packageName) {
50251
50990
  }
50252
50991
  return false;
50253
50992
  }
50254
- function invalidatePackage(packageName = PACKAGE_NAME) {
50993
+ function invalidatePackage(packageName = PACKAGE_NAME2) {
50255
50994
  try {
50256
50995
  const userConfigDir = getUserConfigDir();
50257
50996
  const pkgDirs = [
@@ -50291,7 +51030,7 @@ var init_cache = __esm(() => {
50291
51030
  async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
50292
51031
  await ctx.client.tui.showToast({
50293
51032
  body: {
50294
- title: `OhMyOpenCode ${latestVersion}`,
51033
+ title: `EvilOMO ${latestVersion}`,
50295
51034
  message: getToastMessage(true, latestVersion),
50296
51035
  variant: "info",
50297
51036
  duration: 8000
@@ -50302,7 +51041,7 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
50302
51041
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
50303
51042
  await ctx.client.tui.showToast({
50304
51043
  body: {
50305
- title: "OhMyOpenCode Updated!",
51044
+ title: "EvilOMO Updated!",
50306
51045
  message: `v${oldVersion} \u2192 v${newVersion}
50307
51046
  Restart OpenCode to apply.`,
50308
51047
  variant: "success",
@@ -50316,8 +51055,8 @@ var init_update_toasts = __esm(() => {
50316
51055
  });
50317
51056
 
50318
51057
  // src/hooks/auto-update-checker/hook/background-update-check.ts
50319
- import { existsSync as existsSync22 } from "fs";
50320
- import { join as join23 } from "path";
51058
+ import { existsSync as existsSync24 } from "fs";
51059
+ import { join as join25 } from "path";
50321
51060
  function getCacheWorkspaceDir(deps) {
50322
51061
  return deps.join(deps.getOpenCodeCacheDir(), "packages");
50323
51062
  }
@@ -50327,8 +51066,8 @@ function getPinnedVersionToastMessage(latestVersion) {
50327
51066
  function resolveActiveInstallWorkspace(deps) {
50328
51067
  const configPaths = deps.getOpenCodeConfigPaths({ binary: "opencode" });
50329
51068
  const cacheDir = getCacheWorkspaceDir(deps);
50330
- const configInstallPath = deps.join(configPaths.configDir, "node_modules", PACKAGE_NAME, "package.json");
50331
- const cacheInstallPath = deps.join(cacheDir, "node_modules", PACKAGE_NAME, "package.json");
51069
+ const configInstallPath = deps.join(configPaths.configDir, "node_modules", PACKAGE_NAME2, "package.json");
51070
+ const cacheInstallPath = deps.join(cacheDir, "node_modules", PACKAGE_NAME2, "package.json");
50332
51071
  if (deps.existsSync(configInstallPath)) {
50333
51072
  deps.log(`[auto-update-checker] Active workspace: config-dir (${configPaths.configDir})`);
50334
51073
  return configPaths.configDir;
@@ -50407,7 +51146,7 @@ function createBackgroundUpdateCheckRunner(overrides = {}) {
50407
51146
  await deps.showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
50408
51147
  return;
50409
51148
  }
50410
- deps.invalidatePackage(PACKAGE_NAME);
51149
+ deps.invalidatePackage(PACKAGE_NAME2);
50411
51150
  const activeWorkspace = resolveActiveInstallWorkspace(deps);
50412
51151
  const installSuccess = await runBunInstallSafe(activeWorkspace, deps);
50413
51152
  if (installSuccess) {
@@ -50435,8 +51174,8 @@ var init_background_update_check = __esm(() => {
50435
51174
  init_checker();
50436
51175
  init_update_toasts();
50437
51176
  defaultDeps = {
50438
- existsSync: existsSync22,
50439
- join: join23,
51177
+ existsSync: existsSync24,
51178
+ join: join25,
50440
51179
  runBunInstallWithDetails,
50441
51180
  log,
50442
51181
  getOpenCodeCacheDir,
@@ -50583,7 +51322,7 @@ async function showSpinnerToast(ctx, version2, message) {
50583
51322
  const spinner = SISYPHUS_SPINNER[i2 % SISYPHUS_SPINNER.length];
50584
51323
  await ctx.client.tui.showToast({
50585
51324
  body: {
50586
- title: `${spinner} OhMyOpenCode ${version2}`,
51325
+ title: `${spinner} EvilOMO ${version2}`,
50587
51326
  message,
50588
51327
  variant: "info",
50589
51328
  duration: frameInterval + 50
@@ -50716,7 +51455,7 @@ var {
50716
51455
  // package.json
50717
51456
  var package_default = {
50718
51457
  name: "evil-omo",
50719
- version: "3.15.3",
51458
+ version: "3.16.0",
50720
51459
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
50721
51460
  main: "./dist/index.js",
50722
51461
  types: "dist/index.d.ts",
@@ -50775,8 +51514,8 @@ var package_default = {
50775
51514
  "@clack/prompts": "^0.11.0",
50776
51515
  "@code-yeongyu/comment-checker": "^0.7.0",
50777
51516
  "@modelcontextprotocol/sdk": "^1.25.2",
50778
- "@opencode-ai/plugin": "^1.2.24",
50779
- "@opencode-ai/sdk": "^1.2.24",
51517
+ "@opencode-ai/plugin": "^1.4.0",
51518
+ "@opencode-ai/sdk": "^1.4.0",
50780
51519
  commander: "^14.0.2",
50781
51520
  "detect-libc": "^2.0.0",
50782
51521
  diff: "^8.0.3",
@@ -50785,7 +51524,7 @@ var package_default = {
50785
51524
  picocolors: "^1.1.1",
50786
51525
  picomatch: "^4.0.2",
50787
51526
  "vscode-jsonrpc": "^8.2.0",
50788
- zod: "^4.1.8"
51527
+ zod: "^4.3.0"
50789
51528
  },
50790
51529
  devDependencies: {
50791
51530
  "@types/js-yaml": "^4.0.9",
@@ -50794,21 +51533,19 @@ var package_default = {
50794
51533
  typescript: "^5.7.3"
50795
51534
  },
50796
51535
  optionalDependencies: {
50797
- "evil-omo-darwin-arm64": "3.15.3",
50798
- "evil-omo-darwin-x64": "3.15.3",
50799
- "evil-omo-darwin-x64-baseline": "3.15.3",
50800
- "evil-omo-linux-x64": "3.15.3",
50801
- "evil-omo-linux-x64-baseline": "3.15.3",
50802
- "evil-omo-linux-arm64": "3.15.3",
50803
- "evil-omo-linux-x64-musl": "3.15.3",
50804
- "evil-omo-linux-x64-musl-baseline": "3.15.3",
50805
- "evil-omo-linux-arm64-musl": "3.15.3",
50806
- "evil-omo-windows-x64": "3.15.3",
50807
- "evil-omo-windows-x64-baseline": "3.15.3"
50808
- },
50809
- overrides: {
50810
- "@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"
50811
51547
  },
51548
+ overrides: {},
50812
51549
  trustedDependencies: [
50813
51550
  "@ast-grep/cli",
50814
51551
  "@ast-grep/napi",
@@ -50819,7 +51556,7 @@ var package_default = {
50819
51556
  // src/cli/cli-installer.ts
50820
51557
  init_shared();
50821
51558
  init_config_manager();
50822
- var import_picocolors2 = __toESM(require_picocolors(), 1);
51559
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
50823
51560
 
50824
51561
  // src/cli/install-validators.ts
50825
51562
  var import_picocolors = __toESM(require_picocolors(), 1);
@@ -50966,6 +51703,56 @@ function detectedToInitialValues(detected) {
50966
51703
  };
50967
51704
  }
50968
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
+
50969
51756
  // src/cli/cli-installer.ts
50970
51757
  async function runCliInstaller(args, version) {
50971
51758
  const validation = validateNonTuiArgs(args);
@@ -50993,6 +51780,11 @@ async function runCliInstaller(args, version) {
50993
51780
  printInfo("Visit https://opencode.ai/docs for installation instructions");
50994
51781
  } else {
50995
51782
  printSuccess(`OpenCode ${openCodeVersion ?? ""} detected`);
51783
+ const unsupportedVersionMessage = getUnsupportedOpenCodeVersionMessage(openCodeVersion);
51784
+ if (unsupportedVersionMessage) {
51785
+ printWarning(unsupportedVersionMessage);
51786
+ return 1;
51787
+ }
50996
51788
  }
50997
51789
  if (isUpdate) {
50998
51790
  const initial = detectedToInitialValues(detected);
@@ -51005,47 +51797,37 @@ async function runCliInstaller(args, version) {
51005
51797
  printError(`Failed: ${pluginResult.error}`);
51006
51798
  return 1;
51007
51799
  }
51008
- printSuccess(`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${import_picocolors2.default.dim(pluginResult.configPath)}`);
51800
+ printSuccess(`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${import_picocolors3.default.dim(pluginResult.configPath)}`);
51009
51801
  printStep(step++, totalSteps, `Writing ${PLUGIN_NAME} configuration...`);
51010
51802
  const omoResult = writeOmoConfig(config);
51011
51803
  if (!omoResult.success) {
51012
51804
  printError(`Failed: ${omoResult.error}`);
51013
51805
  return 1;
51014
51806
  }
51015
- printSuccess(`Config written ${SYMBOLS.arrow} ${import_picocolors2.default.dim(omoResult.configPath)}`);
51807
+ printSuccess(`Config written ${SYMBOLS.arrow} ${import_picocolors3.default.dim(omoResult.configPath)}`);
51016
51808
  printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
51017
51809
  if (!config.hasClaude) {
51018
- console.log();
51019
- console.log(import_picocolors2.default.bgRed(import_picocolors2.default.white(import_picocolors2.default.bold(" CRITICAL WARNING "))));
51020
- console.log();
51021
- console.log(import_picocolors2.default.red(import_picocolors2.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
51022
- console.log(import_picocolors2.default.red(" Without Claude, you may experience significantly degraded performance:"));
51023
- console.log(import_picocolors2.default.dim(" \u2022 Reduced orchestration quality"));
51024
- console.log(import_picocolors2.default.dim(" \u2022 Weaker tool selection and delegation"));
51025
- console.log(import_picocolors2.default.dim(" \u2022 Less reliable task completion"));
51026
- console.log();
51027
- console.log(import_picocolors2.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
51028
- console.log();
51810
+ printInfo("Note: Sisyphus agent performs best with Claude Opus 4.5+. " + "Other models work but may have reduced orchestration quality.");
51029
51811
  }
51030
51812
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
51031
51813
  printWarning("No model providers configured. Using opencode/big-pickle as fallback.");
51032
51814
  }
51033
- console.log(`${SYMBOLS.star} ${import_picocolors2.default.bold(import_picocolors2.default.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`);
51034
- 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!`);
51035
51817
  console.log();
51036
- printBox(`${import_picocolors2.default.bold("Pro Tip:")} Include ${import_picocolors2.default.cyan("ultrawork")} (or ${import_picocolors2.default.cyan("ulw")}) in your prompt.
51818
+ printBox(`${import_picocolors3.default.bold("Pro Tip:")} Include ${import_picocolors3.default.cyan("ultrawork")} (or ${import_picocolors3.default.cyan("ulw")}) in your prompt.
51037
51819
  ` + `All features work like magic-parallel agents, background tasks,
51038
51820
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
51039
- console.log(`${SYMBOLS.star} ${import_picocolors2.default.yellow("If you found this helpful, consider starring the repo!")}`);
51040
- 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")}`);
51041
51823
  console.log();
51042
- console.log(import_picocolors2.default.dim("oMoMoMoMo... Enjoy!"));
51824
+ console.log(import_picocolors3.default.dim("oMoMoMoMo... Enjoy!"));
51043
51825
  console.log();
51044
51826
  if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
51045
- printBox(`Run ${import_picocolors2.default.cyan("opencode auth login")} and select your provider:
51046
- ` + (config.hasClaude ? ` ${SYMBOLS.bullet} Anthropic ${import_picocolors2.default.gray("\u2192 Claude Pro/Max")}
51047
- ` : "") + (config.hasGemini ? ` ${SYMBOLS.bullet} Google ${import_picocolors2.default.gray("\u2192 Gemini")}
51048
- ` : "") + (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");
51049
51831
  }
51050
51832
  return 0;
51051
51833
  }
@@ -51440,7 +52222,7 @@ class LD extends x {
51440
52222
  }
51441
52223
 
51442
52224
  // node_modules/@clack/prompts/dist/index.mjs
51443
- var import_picocolors3 = __toESM(require_picocolors(), 1);
52225
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
51444
52226
  var import_sisteransi2 = __toESM(require_src(), 1);
51445
52227
  import y2 from "process";
51446
52228
  function ce() {
@@ -51473,13 +52255,13 @@ var b2 = (t) => {
51473
52255
  switch (t) {
51474
52256
  case "initial":
51475
52257
  case "active":
51476
- return import_picocolors3.default.cyan(le);
52258
+ return import_picocolors4.default.cyan(le);
51477
52259
  case "cancel":
51478
- return import_picocolors3.default.red(L2);
52260
+ return import_picocolors4.default.red(L2);
51479
52261
  case "error":
51480
- return import_picocolors3.default.yellow(W2);
52262
+ return import_picocolors4.default.yellow(W2);
51481
52263
  case "submit":
51482
- return import_picocolors3.default.green(C);
52264
+ return import_picocolors4.default.green(C);
51483
52265
  }
51484
52266
  };
51485
52267
  var G2 = (t) => {
@@ -51489,7 +52271,7 @@ var G2 = (t) => {
51489
52271
  const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
51490
52272
  return r2.slice(l2, l2 + a).map((p2, v, f) => {
51491
52273
  const j2 = v === 0 && $2, E = v === f.length - 1 && g2;
51492
- 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);
51493
52275
  });
51494
52276
  };
51495
52277
  var ve = (t) => {
@@ -51497,29 +52279,29 @@ var ve = (t) => {
51497
52279
  const s = r2.label ?? String(r2.value);
51498
52280
  switch (i2) {
51499
52281
  case "selected":
51500
- return `${import_picocolors3.default.dim(s)}`;
52282
+ return `${import_picocolors4.default.dim(s)}`;
51501
52283
  case "active":
51502
- 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})`) : ""}`;
51503
52285
  case "cancelled":
51504
- return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
52286
+ return `${import_picocolors4.default.strikethrough(import_picocolors4.default.dim(s))}`;
51505
52287
  default:
51506
- return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
52288
+ return `${import_picocolors4.default.dim(P2)} ${import_picocolors4.default.dim(s)}`;
51507
52289
  }
51508
52290
  };
51509
52291
  return new LD({ options: t.options, initialValue: t.initialValue, render() {
51510
- const r2 = `${import_picocolors3.default.gray(o)}
52292
+ const r2 = `${import_picocolors4.default.gray(o)}
51511
52293
  ${b2(this.state)} ${t.message}
51512
52294
  `;
51513
52295
  switch (this.state) {
51514
52296
  case "submit":
51515
- 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")}`;
51516
52298
  case "cancel":
51517
- return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
51518
- ${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)}`;
51519
52301
  default:
51520
- 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(`
51521
- ${import_picocolors3.default.cyan(o)} `)}
51522
- ${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)}
51523
52305
  `;
51524
52306
  }
51525
52307
  } }).prompt();
@@ -51531,53 +52313,53 @@ ${t}
51531
52313
  `), i2 = S2(n).length, s = Math.max(r2.reduce((a, l2) => {
51532
52314
  const $2 = S2(l2);
51533
52315
  return $2.length > a ? $2.length : a;
51534
- }, 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(`
51535
52317
  `);
51536
- process.stdout.write(`${import_picocolors3.default.gray(o)}
51537
- ${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)}
51538
52320
  ${c}
51539
- ${import_picocolors3.default.gray(de + _2.repeat(s + 2) + pe)}
52321
+ ${import_picocolors4.default.gray(de + _2.repeat(s + 2) + pe)}
51540
52322
  `);
51541
52323
  };
51542
52324
  var xe = (t = "") => {
51543
- 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)}
51544
52326
 
51545
52327
  `);
51546
52328
  };
51547
52329
  var Ie = (t = "") => {
51548
- process.stdout.write(`${import_picocolors3.default.gray(ue)} ${t}
52330
+ process.stdout.write(`${import_picocolors4.default.gray(ue)} ${t}
51549
52331
  `);
51550
52332
  };
51551
52333
  var Se = (t = "") => {
51552
- process.stdout.write(`${import_picocolors3.default.gray(o)}
51553
- ${import_picocolors3.default.gray(d2)} ${t}
52334
+ process.stdout.write(`${import_picocolors4.default.gray(o)}
52335
+ ${import_picocolors4.default.gray(d2)} ${t}
51554
52336
 
51555
52337
  `);
51556
52338
  };
51557
- var M2 = { message: (t = "", { symbol: n = import_picocolors3.default.gray(o) } = {}) => {
51558
- 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)}`];
51559
52341
  if (t) {
51560
52342
  const [i2, ...s] = t.split(`
51561
52343
  `);
51562
- 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}`));
51563
52345
  }
51564
52346
  process.stdout.write(`${r2.join(`
51565
52347
  `)}
51566
52348
  `);
51567
52349
  }, info: (t) => {
51568
- M2.message(t, { symbol: import_picocolors3.default.blue(q) });
52350
+ M2.message(t, { symbol: import_picocolors4.default.blue(q) });
51569
52351
  }, success: (t) => {
51570
- M2.message(t, { symbol: import_picocolors3.default.green(D) });
52352
+ M2.message(t, { symbol: import_picocolors4.default.green(D) });
51571
52353
  }, step: (t) => {
51572
- M2.message(t, { symbol: import_picocolors3.default.green(C) });
52354
+ M2.message(t, { symbol: import_picocolors4.default.green(C) });
51573
52355
  }, warn: (t) => {
51574
- M2.message(t, { symbol: import_picocolors3.default.yellow(U) });
52356
+ M2.message(t, { symbol: import_picocolors4.default.yellow(U) });
51575
52357
  }, warning: (t) => {
51576
52358
  M2.warn(t);
51577
52359
  }, error: (t) => {
51578
- M2.message(t, { symbol: import_picocolors3.default.red(K2) });
52360
+ M2.message(t, { symbol: import_picocolors4.default.red(K2) });
51579
52361
  } };
51580
- var J2 = `${import_picocolors3.default.gray(o)} `;
52362
+ var J2 = `${import_picocolors4.default.gray(o)} `;
51581
52363
  var Y2 = ({ indicator: t = "dots" } = {}) => {
51582
52364
  const n = V2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], r2 = V2 ? 80 : 120, i2 = process.env.CI === "true";
51583
52365
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
@@ -51600,14 +52382,14 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51600
52382
  const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
51601
52383
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
51602
52384
  }, H = (m2 = "") => {
51603
- 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)}
51604
52386
  `);
51605
52387
  let h2 = 0, w2 = 0;
51606
52388
  j2(), c = setInterval(() => {
51607
52389
  if (i2 && l2 === $2)
51608
52390
  return;
51609
52391
  B2(), $2 = l2;
51610
- const I2 = import_picocolors3.default.magenta(n[h2]);
52392
+ const I2 = import_picocolors4.default.magenta(n[h2]);
51611
52393
  if (i2)
51612
52394
  process.stdout.write(`${I2} ${l2}...`);
51613
52395
  else if (t === "timer")
@@ -51620,7 +52402,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51620
52402
  }, r2);
51621
52403
  }, N2 = (m2 = "", h2 = 0) => {
51622
52404
  a = false, clearInterval(c), B2();
51623
- 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);
51624
52406
  l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
51625
52407
  `) : process.stdout.write(`${w2} ${l2}
51626
52408
  `), E(), s();
@@ -51633,7 +52415,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
51633
52415
  // src/cli/tui-installer.ts
51634
52416
  init_shared();
51635
52417
  init_config_manager();
51636
- var import_picocolors4 = __toESM(require_picocolors(), 1);
52418
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
51637
52419
 
51638
52420
  // src/cli/tui-install-prompts.ts
51639
52421
  async function selectOrCancel(params) {
@@ -51754,7 +52536,7 @@ async function runTuiInstaller(args, version) {
51754
52536
  }
51755
52537
  const detected = detectCurrentConfig();
51756
52538
  const isUpdate = detected.isInstalled;
51757
- 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... ")));
51758
52540
  if (isUpdate) {
51759
52541
  const initial = detectedToInitialValues(detected);
51760
52542
  M2.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`);
@@ -51764,11 +52546,17 @@ async function runTuiInstaller(args, version) {
51764
52546
  const installed = await isOpenCodeInstalled();
51765
52547
  const openCodeVersion = await getOpenCodeVersion2();
51766
52548
  if (!installed) {
51767
- spinner.stop(`OpenCode binary not found ${import_picocolors4.default.yellow("[!]")}`);
52549
+ spinner.stop(`OpenCode binary not found ${import_picocolors5.default.yellow("[!]")}`);
51768
52550
  M2.warn("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.");
51769
52551
  Me("Visit https://opencode.ai/docs for installation instructions", "Installation Guide");
51770
52552
  } else {
51771
- 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
+ }
51772
52560
  }
51773
52561
  const config = await promptInstallConfig(detected);
51774
52562
  if (!config)
@@ -51777,55 +52565,46 @@ async function runTuiInstaller(args, version) {
51777
52565
  const pluginResult = await addPluginToOpenCodeConfig(version);
51778
52566
  if (!pluginResult.success) {
51779
52567
  spinner.stop(`Failed to add plugin: ${pluginResult.error}`);
51780
- Se(import_picocolors4.default.red("Installation failed."));
52568
+ Se(import_picocolors5.default.red("Installation failed."));
51781
52569
  return 1;
51782
52570
  }
51783
- spinner.stop(`Plugin added to ${import_picocolors4.default.cyan(pluginResult.configPath)}`);
52571
+ spinner.stop(`Plugin added to ${import_picocolors5.default.cyan(pluginResult.configPath)}`);
51784
52572
  spinner.start(`Writing ${PLUGIN_NAME} configuration`);
51785
52573
  const omoResult = writeOmoConfig(config);
51786
52574
  if (!omoResult.success) {
51787
52575
  spinner.stop(`Failed to write config: ${omoResult.error}`);
51788
- Se(import_picocolors4.default.red("Installation failed."));
52576
+ Se(import_picocolors5.default.red("Installation failed."));
51789
52577
  return 1;
51790
52578
  }
51791
- spinner.stop(`Config written to ${import_picocolors4.default.cyan(omoResult.configPath)}`);
52579
+ spinner.stop(`Config written to ${import_picocolors5.default.cyan(omoResult.configPath)}`);
51792
52580
  if (!config.hasClaude) {
51793
- console.log();
51794
- console.log(import_picocolors4.default.bgRed(import_picocolors4.default.white(import_picocolors4.default.bold(" CRITICAL WARNING "))));
51795
- console.log();
51796
- console.log(import_picocolors4.default.red(import_picocolors4.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
51797
- console.log(import_picocolors4.default.red(" Without Claude, you may experience significantly degraded performance:"));
51798
- console.log(import_picocolors4.default.dim(" \u2022 Reduced orchestration quality"));
51799
- console.log(import_picocolors4.default.dim(" \u2022 Weaker tool selection and delegation"));
51800
- console.log(import_picocolors4.default.dim(" \u2022 Less reliable task completion"));
51801
- console.log();
51802
- console.log(import_picocolors4.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
51803
- 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.`);
51804
52583
  }
51805
52584
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
51806
52585
  M2.warn("No model providers configured. Using opencode/big-pickle as fallback.");
51807
52586
  }
51808
52587
  Me(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
51809
- M2.success(import_picocolors4.default.bold(isUpdate ? "Configuration updated!" : "Installation complete!"));
51810
- M2.message(`Run ${import_picocolors4.default.cyan("opencode")} to start!`);
51811
- Me(`Include ${import_picocolors4.default.cyan("ultrawork")} (or ${import_picocolors4.default.cyan("ulw")}) in your prompt.
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.
51812
52591
  ` + `All features work like magic-parallel agents, background tasks,
51813
52592
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
51814
- M2.message(`${import_picocolors4.default.yellow("\u2605")} If you found this helpful, consider starring the repo!`);
51815
- M2.message(` ${import_picocolors4.default.dim("gh api --silent --method PUT /user/starred/D4ch1au/evil-oh-my-openagent >/dev/null 2>&1 || true")}`);
51816
- 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!"));
51817
52596
  if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
51818
52597
  const providers = [];
51819
52598
  if (config.hasClaude)
51820
- providers.push(`Anthropic ${import_picocolors4.default.gray("\u2192 Claude Pro/Max")}`);
52599
+ providers.push(`Anthropic ${import_picocolors5.default.gray("\u2192 Claude Pro/Max")}`);
51821
52600
  if (config.hasGemini)
51822
- providers.push(`Google ${import_picocolors4.default.gray("\u2192 Gemini")}`);
52601
+ providers.push(`Google ${import_picocolors5.default.gray("\u2192 Gemini")}`);
51823
52602
  if (config.hasCopilot)
51824
- providers.push(`GitHub ${import_picocolors4.default.gray("\u2192 Copilot")}`);
52603
+ providers.push(`GitHub ${import_picocolors5.default.gray("\u2192 Copilot")}`);
51825
52604
  console.log();
51826
- console.log(import_picocolors4.default.bold("Authenticate Your Providers"));
52605
+ console.log(import_picocolors5.default.bold("Authenticate Your Providers"));
51827
52606
  console.log();
51828
- 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:`);
51829
52608
  for (const provider of providers) {
51830
52609
  console.log(` ${SYMBOLS.bullet} ${provider}`);
51831
52610
  }
@@ -51841,7 +52620,7 @@ async function install(args) {
51841
52620
  }
51842
52621
 
51843
52622
  // src/cli/run/runner.ts
51844
- var import_picocolors14 = __toESM(require_picocolors(), 1);
52623
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
51845
52624
 
51846
52625
  // src/cli/run/event-state.ts
51847
52626
  function createEventState() {
@@ -51875,7 +52654,7 @@ function createEventState() {
51875
52654
  };
51876
52655
  }
51877
52656
  // src/cli/run/event-formatting.ts
51878
- var import_picocolors5 = __toESM(require_picocolors(), 1);
52657
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
51879
52658
  function serializeError(error) {
51880
52659
  if (!error)
51881
52660
  return "Unknown error";
@@ -51919,10 +52698,10 @@ function getSessionTag(ctx, payload) {
51919
52698
  const sessionID = props?.sessionID ?? props?.sessionId ?? info?.sessionID ?? info?.sessionId ?? part?.sessionID ?? part?.sessionId;
51920
52699
  const isMainSession = sessionID === ctx.sessionID;
51921
52700
  if (isMainSession)
51922
- return import_picocolors5.default.green("[MAIN]");
52701
+ return import_picocolors6.default.green("[MAIN]");
51923
52702
  if (sessionID)
51924
- return import_picocolors5.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
51925
- return import_picocolors5.default.dim("[system]");
52703
+ return import_picocolors6.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
52704
+ return import_picocolors6.default.dim("[system]");
51926
52705
  }
51927
52706
  function logEventVerbose(ctx, payload) {
51928
52707
  const sessionTag = getSessionTag(ctx, payload);
@@ -51931,7 +52710,7 @@ function logEventVerbose(ctx, payload) {
51931
52710
  case "session.idle":
51932
52711
  case "session.status": {
51933
52712
  const status = props?.status?.type ?? "idle";
51934
- console.error(import_picocolors5.default.dim(`${sessionTag} ${payload.type}: ${status}`));
52713
+ console.error(import_picocolors6.default.dim(`${sessionTag} ${payload.type}: ${status}`));
51935
52714
  break;
51936
52715
  }
51937
52716
  case "message.part.updated": {
@@ -51939,10 +52718,10 @@ function logEventVerbose(ctx, payload) {
51939
52718
  const part = partProps?.part;
51940
52719
  if (part?.type === "tool") {
51941
52720
  const status = part.state?.status ?? "unknown";
51942
- 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}]`));
51943
52722
  } else if (part?.type === "text" && part.text) {
51944
52723
  const preview = part.text.slice(0, 80).replace(/\n/g, "\\n");
51945
- 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 ? "..." : ""}"`));
51946
52725
  }
51947
52726
  break;
51948
52727
  }
@@ -51951,7 +52730,7 @@ function logEventVerbose(ctx, payload) {
51951
52730
  const field = deltaProps?.field ?? "unknown";
51952
52731
  const delta = deltaProps?.delta ?? "";
51953
52732
  const preview = delta.slice(0, 80).replace(/\n/g, "\\n");
51954
- 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 ? "..." : ""}"`));
51955
52734
  break;
51956
52735
  }
51957
52736
  case "message.updated": {
@@ -51960,7 +52739,7 @@ function logEventVerbose(ctx, payload) {
51960
52739
  const model = msgProps?.info?.modelID;
51961
52740
  const agent = msgProps?.info?.agent;
51962
52741
  const details = [role, agent, model].filter(Boolean).join(", ");
51963
- console.error(import_picocolors5.default.dim(`${sessionTag} message.updated (${details})`));
52742
+ console.error(import_picocolors6.default.dim(`${sessionTag} message.updated (${details})`));
51964
52743
  break;
51965
52744
  }
51966
52745
  case "tool.execute": {
@@ -51978,32 +52757,32 @@ function logEventVerbose(ctx, payload) {
51978
52757
  }
51979
52758
  }
51980
52759
  const inputPreview = inputStr.slice(0, 150);
51981
- console.error(import_picocolors5.default.cyan(`${sessionTag} TOOL.EXECUTE: ${import_picocolors5.default.bold(toolName)}`));
51982
- 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 ? "..." : ""}`));
51983
52762
  break;
51984
52763
  }
51985
52764
  case "tool.result": {
51986
52765
  const resultProps = props;
51987
52766
  const output = resultProps?.output ?? "";
51988
52767
  const preview = output.slice(0, 200).replace(/\n/g, "\\n");
51989
- 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 ? "..." : ""}"`));
51990
52769
  break;
51991
52770
  }
51992
52771
  case "session.error": {
51993
52772
  const errorProps = props;
51994
52773
  const errorMsg = serializeError(errorProps?.error);
51995
- console.error(import_picocolors5.default.red(`${sessionTag} SESSION.ERROR: ${errorMsg}`));
52774
+ console.error(import_picocolors6.default.red(`${sessionTag} SESSION.ERROR: ${errorMsg}`));
51996
52775
  break;
51997
52776
  }
51998
52777
  default:
51999
- console.error(import_picocolors5.default.dim(`${sessionTag} ${payload.type}`));
52778
+ console.error(import_picocolors6.default.dim(`${sessionTag} ${payload.type}`));
52000
52779
  }
52001
52780
  }
52002
52781
  // src/cli/run/event-stream-processor.ts
52003
- var import_picocolors8 = __toESM(require_picocolors(), 1);
52782
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
52004
52783
 
52005
52784
  // src/cli/run/event-handlers.ts
52006
- var import_picocolors7 = __toESM(require_picocolors(), 1);
52785
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
52007
52786
 
52008
52787
  // src/cli/run/tool-input-preview.ts
52009
52788
  function formatToolHeader(toolName, input) {
@@ -52139,14 +52918,14 @@ var displayChars = {
52139
52918
  };
52140
52919
 
52141
52920
  // src/cli/run/output-renderer.ts
52142
- var import_picocolors6 = __toESM(require_picocolors(), 1);
52921
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
52143
52922
  function renderAgentHeader(agent, model, variant, agentColorsByName) {
52144
52923
  if (!agent && !model)
52145
52924
  return;
52146
- const agentLabel = agent ? import_picocolors6.default.bold(colorizeWithProfileColor(agent, agentColorsByName[agent])) : "";
52925
+ const agentLabel = agent ? import_picocolors7.default.bold(colorizeWithProfileColor(agent, agentColorsByName[agent])) : "";
52147
52926
  const modelBase = model ?? "";
52148
52927
  const variantSuffix = variant ? ` (${variant})` : "";
52149
- const modelLabel = model ? import_picocolors6.default.dim(`${modelBase}${variantSuffix}`) : "";
52928
+ const modelLabel = model ? import_picocolors7.default.dim(`${modelBase}${variantSuffix}`) : "";
52150
52929
  process.stdout.write(`
52151
52930
  `);
52152
52931
  if (modelLabel) {
@@ -52154,7 +52933,7 @@ function renderAgentHeader(agent, model, variant, agentColorsByName) {
52154
52933
  `);
52155
52934
  }
52156
52935
  if (agentLabel) {
52157
- process.stdout.write(` ${import_picocolors6.default.dim("\u2514\u2500")} ${agentLabel}
52936
+ process.stdout.write(` ${import_picocolors7.default.dim("\u2514\u2500")} ${agentLabel}
52158
52937
  `);
52159
52938
  }
52160
52939
  process.stdout.write(`
@@ -52162,7 +52941,7 @@ function renderAgentHeader(agent, model, variant, agentColorsByName) {
52162
52941
  }
52163
52942
  function openThinkBlock() {
52164
52943
  process.stdout.write(`
52165
- ${import_picocolors6.default.dim("\u2503 Thinking:")} `);
52944
+ ${import_picocolors7.default.dim("\u2503 Thinking:")} `);
52166
52945
  }
52167
52946
  function closeThinkBlock() {
52168
52947
  process.stdout.write(`
@@ -52196,10 +52975,10 @@ function writePaddedText(text, atLineStart) {
52196
52975
  }
52197
52976
  function colorizeWithProfileColor(text, hexColor) {
52198
52977
  if (!hexColor)
52199
- return import_picocolors6.default.magenta(text);
52978
+ return import_picocolors7.default.magenta(text);
52200
52979
  const rgb = parseHexColor(hexColor);
52201
52980
  if (!rgb)
52202
- return import_picocolors6.default.magenta(text);
52981
+ return import_picocolors7.default.magenta(text);
52203
52982
  const [r2, g2, b3] = rgb;
52204
52983
  return `\x1B[38;2;${r2};${g2};${b3}m${text}\x1B[39m`;
52205
52984
  }
@@ -52239,7 +53018,7 @@ function renderCompletionMetaLine(state, messageID) {
52239
53018
  const agent = state.currentAgent ?? "assistant";
52240
53019
  const model = state.currentModel ?? "unknown-model";
52241
53020
  const variant = state.currentVariant ? ` (${state.currentVariant})` : "";
52242
- process.stdout.write(import_picocolors7.default.dim(`
53021
+ process.stdout.write(import_picocolors8.default.dim(`
52243
53022
  ${displayChars.treeEnd} ${agent} \xB7 ${model}${variant} \xB7 ${elapsedSec}s
52244
53023
  `));
52245
53024
  state.completionMetaPrintedByMessageId[messageID] = true;
@@ -52273,7 +53052,7 @@ function handleSessionError(ctx, payload, state) {
52273
53052
  if (getSessionId(props) === ctx.sessionID) {
52274
53053
  state.mainSessionError = true;
52275
53054
  state.lastError = serializeError(props?.error);
52276
- console.error(import_picocolors7.default.red(`
53055
+ console.error(import_picocolors8.default.red(`
52277
53056
  [session.error] ${state.lastError}`));
52278
53057
  }
52279
53058
  }
@@ -52301,7 +53080,7 @@ function handleMessagePartUpdated(ctx, payload, state) {
52301
53080
  const newText = reasoningText.slice(state.lastReasoningText.length);
52302
53081
  if (newText) {
52303
53082
  const padded = writePaddedText(newText, state.thinkingAtLineStart);
52304
- process.stdout.write(import_picocolors7.default.dim(padded.output));
53083
+ process.stdout.write(import_picocolors8.default.dim(padded.output));
52305
53084
  state.thinkingAtLineStart = padded.atLineStart;
52306
53085
  state.hasReceivedMeaningfulWork = true;
52307
53086
  }
@@ -52348,7 +53127,7 @@ function handleMessagePartDelta(ctx, payload, state) {
52348
53127
  if (partType === "reasoning") {
52349
53128
  ensureThinkBlockOpen(state);
52350
53129
  const padded2 = writePaddedText(delta, state.thinkingAtLineStart);
52351
- process.stdout.write(import_picocolors7.default.dim(padded2.output));
53130
+ process.stdout.write(import_picocolors8.default.dim(padded2.output));
52352
53131
  state.thinkingAtLineStart = padded2.atLineStart;
52353
53132
  state.lastReasoningText += delta;
52354
53133
  state.hasReceivedMeaningfulWork = true;
@@ -52369,10 +53148,10 @@ function handleToolPart(_ctx, part, state) {
52369
53148
  return;
52370
53149
  state.currentTool = toolName;
52371
53150
  const header = formatToolHeader(toolName, part.state?.input ?? {});
52372
- const suffix = header.description ? ` ${import_picocolors7.default.dim(header.description)}` : "";
53151
+ const suffix = header.description ? ` ${import_picocolors8.default.dim(header.description)}` : "";
52373
53152
  state.hasReceivedMeaningfulWork = true;
52374
53153
  process.stdout.write(`
52375
- ${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}
52376
53155
  `);
52377
53156
  }
52378
53157
  if (status === "completed" || status === "error") {
@@ -52380,10 +53159,10 @@ function handleToolPart(_ctx, part, state) {
52380
53159
  return;
52381
53160
  const output = part.state?.output || "";
52382
53161
  if (output.trim()) {
52383
- process.stdout.write(import_picocolors7.default.dim(` ${displayChars.treeEnd} output
53162
+ process.stdout.write(import_picocolors8.default.dim(` ${displayChars.treeEnd} output
52384
53163
  `));
52385
53164
  const padded = writePaddedText(output, true);
52386
- process.stdout.write(import_picocolors7.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
53165
+ process.stdout.write(import_picocolors8.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
52387
53166
  process.stdout.write(`
52388
53167
  `);
52389
53168
  }
@@ -52445,10 +53224,10 @@ function handleToolExecute(ctx, payload, state) {
52445
53224
  const toolName = props?.name || "unknown";
52446
53225
  state.currentTool = toolName;
52447
53226
  const header = formatToolHeader(toolName, props?.input ?? {});
52448
- const suffix = header.description ? ` ${import_picocolors7.default.dim(header.description)}` : "";
53227
+ const suffix = header.description ? ` ${import_picocolors8.default.dim(header.description)}` : "";
52449
53228
  state.hasReceivedMeaningfulWork = true;
52450
53229
  process.stdout.write(`
52451
- ${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}
52452
53231
  `);
52453
53232
  }
52454
53233
  function handleToolResult(ctx, payload, state) {
@@ -52462,10 +53241,10 @@ function handleToolResult(ctx, payload, state) {
52462
53241
  return;
52463
53242
  const output = props?.output || "";
52464
53243
  if (output.trim()) {
52465
- process.stdout.write(import_picocolors7.default.dim(` ${displayChars.treeEnd} output
53244
+ process.stdout.write(import_picocolors8.default.dim(` ${displayChars.treeEnd} output
52466
53245
  `));
52467
53246
  const padded = writePaddedText(output, true);
52468
- process.stdout.write(import_picocolors7.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
53247
+ process.stdout.write(import_picocolors8.default.dim(padded.output + (padded.atLineStart ? "" : " ")));
52469
53248
  process.stdout.write(`
52470
53249
  `);
52471
53250
  }
@@ -52514,7 +53293,7 @@ async function processEvents(ctx, stream, state) {
52514
53293
  const payload = event;
52515
53294
  if (!payload?.type) {
52516
53295
  if (ctx.verbose) {
52517
- 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)}`));
52518
53297
  }
52519
53298
  continue;
52520
53299
  }
@@ -52532,7 +53311,7 @@ async function processEvents(ctx, stream, state) {
52532
53311
  handleToolResult(ctx, payload, state);
52533
53312
  handleTuiToast(ctx, payload, state);
52534
53313
  } catch (err) {
52535
- console.error(import_picocolors8.default.red(`[event error] ${err}`));
53314
+ console.error(import_picocolors9.default.red(`[event error] ${err}`));
52536
53315
  }
52537
53316
  }
52538
53317
  }
@@ -68085,6 +68864,31 @@ class OpencodeClient extends _HeyApiClient {
68085
68864
  }
68086
68865
 
68087
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
+ }
68088
68892
  function createOpencodeClient(config2) {
68089
68893
  if (!config2?.fetch) {
68090
68894
  const customFetch = (req) => {
@@ -68103,10 +68907,46 @@ function createOpencodeClient(config2) {
68103
68907
  };
68104
68908
  }
68105
68909
  const client2 = createClient(config2);
68910
+ client2.interceptors.request.use((request) => rewrite(request, config2?.directory));
68106
68911
  return new OpencodeClient({ client: client2 });
68107
68912
  }
68108
68913
  // node_modules/@opencode-ai/sdk/dist/server.js
68109
- 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
68110
68950
  async function createOpencodeServer(options) {
68111
68951
  options = Object.assign({
68112
68952
  hostname: "127.0.0.1",
@@ -68116,19 +68956,24 @@ async function createOpencodeServer(options) {
68116
68956
  const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
68117
68957
  if (options.config?.logLevel)
68118
68958
  args.push(`--log-level=${options.config.logLevel}`);
68119
- const proc = spawn(`opencode`, args, {
68120
- signal: options.signal,
68959
+ const proc = import_cross_spawn.default(`opencode`, args, {
68121
68960
  env: {
68122
68961
  ...process.env,
68123
68962
  OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {})
68124
68963
  }
68125
68964
  });
68965
+ let clear = () => {};
68126
68966
  const url2 = await new Promise((resolve2, reject) => {
68127
68967
  const id = setTimeout(() => {
68968
+ clear();
68969
+ stop(proc);
68128
68970
  reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`));
68129
68971
  }, options.timeout);
68130
68972
  let output = "";
68973
+ let resolved = false;
68131
68974
  proc.stdout?.on("data", (chunk) => {
68975
+ if (resolved)
68976
+ return;
68132
68977
  output += chunk.toString();
68133
68978
  const lines = output.split(`
68134
68979
  `);
@@ -68136,9 +68981,14 @@ async function createOpencodeServer(options) {
68136
68981
  if (line.startsWith("opencode server listening")) {
68137
68982
  const match = line.match(/on\s+(https?:\/\/[^\s]+)/);
68138
68983
  if (!match) {
68139
- 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;
68140
68989
  }
68141
68990
  clearTimeout(id);
68991
+ resolved = true;
68142
68992
  resolve2(match[1]);
68143
68993
  return;
68144
68994
  }
@@ -68160,17 +69010,16 @@ Server output: ${output}`;
68160
69010
  clearTimeout(id);
68161
69011
  reject(error48);
68162
69012
  });
68163
- if (options.signal) {
68164
- options.signal.addEventListener("abort", () => {
68165
- clearTimeout(id);
68166
- reject(new Error("Aborted"));
68167
- });
68168
- }
69013
+ clear = bindAbort(proc, options.signal, () => {
69014
+ clearTimeout(id);
69015
+ reject(options.signal?.reason);
69016
+ });
68169
69017
  });
68170
69018
  return {
68171
69019
  url: url2,
68172
69020
  close() {
68173
- proc.kill();
69021
+ clear();
69022
+ stop(proc);
68174
69023
  }
68175
69024
  };
68176
69025
  }
@@ -68190,11 +69039,11 @@ async function createOpencode(options) {
68190
69039
 
68191
69040
  // src/cli/run/server-connection.ts
68192
69041
  init_port_utils();
68193
- var import_picocolors9 = __toESM(require_picocolors(), 1);
69042
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
68194
69043
 
68195
69044
  // src/cli/run/opencode-binary-resolver.ts
68196
69045
  init_spawn_with_windows_hide();
68197
- import { delimiter, dirname, join as join13 } from "path";
69046
+ import { delimiter, dirname as dirname2, join as join14 } from "path";
68198
69047
  var OPENCODE_COMMANDS = ["opencode", "opencode-desktop"];
68199
69048
  var WINDOWS_SUFFIXES = ["", ".exe", ".cmd", ".bat", ".ps1"];
68200
69049
  function getCommandCandidates(platform) {
@@ -68217,7 +69066,7 @@ function collectCandidateBinaryPaths(pathEnv, which = Bun.which, platform = proc
68217
69066
  }
68218
69067
  for (const entry of (pathEnv ?? "").split(delimiter).filter(Boolean)) {
68219
69068
  for (const command of commandCandidates) {
68220
- addCandidate(join13(entry, command));
69069
+ addCandidate(join14(entry, command));
68221
69070
  }
68222
69071
  }
68223
69072
  return candidates;
@@ -68244,7 +69093,7 @@ async function findWorkingOpencodeBinary(pathEnv = process.env.PATH, probe = can
68244
69093
  return null;
68245
69094
  }
68246
69095
  function buildPathWithBinaryFirst(pathEnv, binaryPath) {
68247
- const preferredDir = dirname(binaryPath);
69096
+ const preferredDir = dirname2(binaryPath);
68248
69097
  const existing = (pathEnv ?? "").split(delimiter).filter((entry) => entry.length > 0 && entry !== preferredDir);
68249
69098
  return [preferredDir, ...existing].join(delimiter);
68250
69099
  }
@@ -68278,13 +69127,13 @@ function isPortRangeExhausted(error48) {
68278
69127
  async function startServer(options) {
68279
69128
  const { signal, port } = options;
68280
69129
  const { client: client3, server: server2 } = await withWorkingOpencodePath(() => createOpencode({ signal, port, hostname: "127.0.0.1" }));
68281
- 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));
68282
69131
  return { client: client3, cleanup: () => server2.close() };
68283
69132
  }
68284
69133
  async function createServerConnection(options) {
68285
69134
  const { port, attach, signal } = options;
68286
69135
  if (attach !== undefined) {
68287
- 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));
68288
69137
  const client3 = createOpencodeClient({ baseUrl: attach });
68289
69138
  return { client: client3, cleanup: () => {} };
68290
69139
  }
@@ -68294,7 +69143,7 @@ async function createServerConnection(options) {
68294
69143
  }
68295
69144
  const available = await isPortAvailable(port, "127.0.0.1");
68296
69145
  if (available) {
68297
- 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()));
68298
69147
  try {
68299
69148
  return await startServer({ signal, port });
68300
69149
  } catch (error48) {
@@ -68305,12 +69154,12 @@ async function createServerConnection(options) {
68305
69154
  if (stillAvailable) {
68306
69155
  throw error48;
68307
69156
  }
68308
- 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"));
68309
69158
  const client4 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
68310
69159
  return { client: client4, cleanup: () => {} };
68311
69160
  }
68312
69161
  }
68313
- 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"));
68314
69163
  const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
68315
69164
  return { client: client3, cleanup: () => {} };
68316
69165
  }
@@ -68328,14 +69177,14 @@ async function createServerConnection(options) {
68328
69177
  if (defaultPortIsAvailable) {
68329
69178
  throw error48;
68330
69179
  }
68331
- 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()));
68332
69181
  const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` });
68333
69182
  return { client: client3, cleanup: () => {} };
68334
69183
  }
68335
69184
  if (wasAutoSelected) {
68336
- 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()));
68337
69186
  } else {
68338
- 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()));
68339
69188
  }
68340
69189
  try {
68341
69190
  return await startServer({ signal, port: selectedPort });
@@ -68344,13 +69193,13 @@ async function createServerConnection(options) {
68344
69193
  throw error48;
68345
69194
  }
68346
69195
  const { port: retryPort } = await getAvailableServerPort(selectedPort + 1, "127.0.0.1");
68347
- 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()));
68348
69197
  return await startServer({ signal, port: retryPort });
68349
69198
  }
68350
69199
  }
68351
69200
 
68352
69201
  // src/cli/run/session-resolver.ts
68353
- var import_picocolors10 = __toESM(require_picocolors(), 1);
69202
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
68354
69203
  var SESSION_CREATE_MAX_RETRIES = 3;
68355
69204
  var SESSION_CREATE_RETRY_DELAY_MS = 1000;
68356
69205
  async function resolveSession(options) {
@@ -68376,11 +69225,11 @@ async function resolveSession(options) {
68376
69225
  query: { directory }
68377
69226
  });
68378
69227
  if (res.error) {
68379
- console.error(import_picocolors10.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
68380
- 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)}`));
68381
69230
  if (attempt < SESSION_CREATE_MAX_RETRIES) {
68382
69231
  const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
68383
- console.log(import_picocolors10.default.dim(` Retrying in ${delay}ms...`));
69232
+ console.log(import_picocolors11.default.dim(` Retrying in ${delay}ms...`));
68384
69233
  await new Promise((resolve2) => setTimeout(resolve2, delay));
68385
69234
  }
68386
69235
  continue;
@@ -68388,10 +69237,10 @@ async function resolveSession(options) {
68388
69237
  if (res.data?.id) {
68389
69238
  return res.data.id;
68390
69239
  }
68391
- 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`));
68392
69241
  if (attempt < SESSION_CREATE_MAX_RETRIES) {
68393
69242
  const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
68394
- console.log(import_picocolors10.default.dim(` Retrying in ${delay}ms...`));
69243
+ console.log(import_picocolors11.default.dim(` Retrying in ${delay}ms...`));
68395
69244
  await new Promise((resolve2) => setTimeout(resolve2, delay));
68396
69245
  }
68397
69246
  }
@@ -68509,7 +69358,7 @@ async function executeOnCompleteHook(options) {
68509
69358
 
68510
69359
  // src/cli/run/agent-resolver.ts
68511
69360
  init_agent_display_names();
68512
- var import_picocolors11 = __toESM(require_picocolors(), 1);
69361
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
68513
69362
  var CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"];
68514
69363
  var DEFAULT_AGENT = "sisyphus";
68515
69364
  var normalizeAgentName = (agent) => {
@@ -68554,10 +69403,10 @@ var resolveRunAgent = (options, pluginConfig, env = process.env) => {
68554
69403
  const fallbackName = getAgentDisplayName(fallback);
68555
69404
  const fallbackDisabled = isAgentDisabled(fallback, pluginConfig);
68556
69405
  if (fallbackDisabled) {
68557
- 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}".`));
68558
69407
  return fallbackName;
68559
69408
  }
68560
- 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}".`));
68561
69410
  return fallbackName;
68562
69411
  }
68563
69412
  return resolved.resolvedName;
@@ -68588,11 +69437,11 @@ function resolveRunModel(modelString) {
68588
69437
  }
68589
69438
 
68590
69439
  // src/cli/run/poll-for-completion.ts
68591
- var import_picocolors13 = __toESM(require_picocolors(), 1);
69440
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
68592
69441
 
68593
69442
  // src/cli/run/completion.ts
68594
69443
  init_shared();
68595
- var import_picocolors12 = __toESM(require_picocolors(), 1);
69444
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
68596
69445
  // src/features/boulder-state/constants.ts
68597
69446
  var BOULDER_DIR = ".sisyphus";
68598
69447
  var BOULDER_FILE = "boulder.json";
@@ -68600,19 +69449,19 @@ var BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}`;
68600
69449
  var NOTEPAD_DIR = "notepads";
68601
69450
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
68602
69451
  // src/features/boulder-state/storage.ts
68603
- import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
68604
- import { dirname as dirname2, join as join14, 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";
68605
69454
  var RESERVED_KEYS = new Set(["__proto__", "prototype", "constructor"]);
68606
69455
  function getBoulderFilePath(directory) {
68607
- return join14(directory, BOULDER_DIR, BOULDER_FILE);
69456
+ return join15(directory, BOULDER_DIR, BOULDER_FILE);
68608
69457
  }
68609
69458
  function readBoulderState(directory) {
68610
69459
  const filePath = getBoulderFilePath(directory);
68611
- if (!existsSync13(filePath)) {
69460
+ if (!existsSync15(filePath)) {
68612
69461
  return null;
68613
69462
  }
68614
69463
  try {
68615
- const content = readFileSync9(filePath, "utf-8");
69464
+ const content = readFileSync10(filePath, "utf-8");
68616
69465
  const parsed = JSON.parse(content);
68617
69466
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
68618
69467
  return null;
@@ -68637,30 +69486,83 @@ function readBoulderState(directory) {
68637
69486
  return null;
68638
69487
  }
68639
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;
68640
69496
  function getPlanProgress(planPath) {
68641
- if (!existsSync13(planPath)) {
69497
+ if (!existsSync15(planPath)) {
68642
69498
  return { total: 0, completed: 0, isComplete: true };
68643
69499
  }
68644
69500
  try {
68645
- const content = readFileSync9(planPath, "utf-8");
68646
- const uncheckedMatches = content.match(/^\s*[-*]\s*\[\s*\]/gm) || [];
68647
- const checkedMatches = content.match(/^\s*[-*]\s*\[[xX]\]/gm) || [];
68648
- const total = uncheckedMatches.length + checkedMatches.length;
68649
- const completed = checkedMatches.length;
68650
- return {
68651
- total,
68652
- completed,
68653
- isComplete: total > 0 && completed === total
68654
- };
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);
68655
69508
  } catch {
68656
69509
  return { total: 0, completed: 0, isComplete: true };
68657
69510
  }
68658
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
+ }
68659
69560
  // src/features/claude-code-session-state/state.ts
68660
69561
  init_agent_display_names();
68661
69562
  var subagentSessions = new Set;
68662
69563
  var syncSubagentSessions = new Set;
68663
69564
  var registeredAgentNames = new Set;
69565
+ var registeredAgentAliases = new Map;
68664
69566
  var sessionAgentMap = new Map;
68665
69567
  function getSessionAgent(sessionID) {
68666
69568
  return sessionAgentMap.get(sessionID);
@@ -68668,17 +69570,17 @@ function getSessionAgent(sessionID) {
68668
69570
  // src/features/run-continuation-state/constants.ts
68669
69571
  var CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation";
68670
69572
  // src/features/run-continuation-state/storage.ts
68671
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync6 } from "fs";
68672
- import { join as join15 } 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";
68673
69575
  function getMarkerPath(directory, sessionID) {
68674
- return join15(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
69576
+ return join16(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
68675
69577
  }
68676
69578
  function readContinuationMarker(directory, sessionID) {
68677
69579
  const markerPath = getMarkerPath(directory, sessionID);
68678
- if (!existsSync14(markerPath))
69580
+ if (!existsSync16(markerPath))
68679
69581
  return null;
68680
69582
  try {
68681
- const raw = readFileSync10(markerPath, "utf-8");
69583
+ const raw = readFileSync11(markerPath, "utf-8");
68682
69584
  const parsed = JSON.parse(raw);
68683
69585
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
68684
69586
  return null;
@@ -68738,28 +69640,32 @@ async function isSessionInBoulderLineage(input) {
68738
69640
 
68739
69641
  // src/hooks/atlas/session-last-agent.ts
68740
69642
  init_shared();
68741
- import { readFileSync as readFileSync11, readdirSync as readdirSync3 } from "fs";
68742
- import { join as join16 } from "path";
68743
- function isCompactionAgent(agent) {
68744
- return typeof agent === "string" && agent.toLowerCase() === "compaction";
68745
- }
69643
+ init_compaction_marker();
69644
+ import { readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
69645
+ import { join as join17 } from "path";
68746
69646
  function getLastAgentFromMessageDir(messageDir) {
68747
69647
  try {
68748
- const messages = readdirSync3(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
69648
+ const messages = readdirSync4(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
68749
69649
  try {
68750
- const content = readFileSync11(join16(messageDir, fileName), "utf-8");
69650
+ const content = readFileSync12(join17(messageDir, fileName), "utf-8");
68751
69651
  const parsed = JSON.parse(content);
68752
69652
  return {
68753
69653
  fileName,
69654
+ id: parsed.id,
68754
69655
  agent: parsed.agent,
68755
69656
  createdAt: typeof parsed.time?.created === "number" ? parsed.time.created : Number.NEGATIVE_INFINITY
68756
69657
  };
68757
69658
  } catch {
68758
69659
  return null;
68759
69660
  }
68760
- }).filter((message) => message !== null).sort((left, right) => right.createdAt - left.createdAt || right.fileName.localeCompare(left.fileName));
69661
+ }).filter((message) => message !== null).sort((left, right) => (right?.createdAt ?? 0) - (left?.createdAt ?? 0) || (right?.fileName ?? "").localeCompare(left?.fileName ?? ""));
68761
69662
  for (const message of messages) {
68762
- if (typeof message.agent === "string" && !isCompactionAgent(message.agent)) {
69663
+ if (!message)
69664
+ continue;
69665
+ if (isCompactionMessage({ agent: message.agent }) || hasCompactionPartInStorage(message?.id)) {
69666
+ continue;
69667
+ }
69668
+ if (typeof message.agent === "string") {
68763
69669
  return message.agent.toLowerCase();
68764
69670
  }
68765
69671
  }
@@ -68785,8 +69691,11 @@ async function getLastAgentFromSession(sessionID, client3) {
68785
69691
  return rightId.localeCompare(leftId);
68786
69692
  });
68787
69693
  for (const message of messages) {
69694
+ if (isCompactionMessage(message)) {
69695
+ continue;
69696
+ }
68788
69697
  const agent = message.info?.agent;
68789
- if (typeof agent === "string" && !isCompactionAgent(agent)) {
69698
+ if (typeof agent === "string") {
68790
69699
  return agent.toLowerCase();
68791
69700
  }
68792
69701
  }
@@ -68806,8 +69715,8 @@ init_agent_display_names();
68806
69715
 
68807
69716
  // src/hooks/ralph-loop/storage.ts
68808
69717
  init_frontmatter();
68809
- import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync7, unlinkSync, mkdirSync as mkdirSync6 } from "fs";
68810
- import { dirname as dirname3, join as join17 } 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";
68811
69720
 
68812
69721
  // src/hooks/ralph-loop/constants.ts
68813
69722
  var DEFAULT_STATE_FILE = ".sisyphus/ralph-loop.local.md";
@@ -68816,15 +69725,15 @@ var DEFAULT_COMPLETION_PROMISE = "DONE";
68816
69725
 
68817
69726
  // src/hooks/ralph-loop/storage.ts
68818
69727
  function getStateFilePath(directory, customPath) {
68819
- return customPath ? join17(directory, customPath) : join17(directory, DEFAULT_STATE_FILE);
69728
+ return customPath ? join18(directory, customPath) : join18(directory, DEFAULT_STATE_FILE);
68820
69729
  }
68821
69730
  function readState(directory, customPath) {
68822
69731
  const filePath = getStateFilePath(directory, customPath);
68823
- if (!existsSync15(filePath)) {
69732
+ if (!existsSync17(filePath)) {
68824
69733
  return null;
68825
69734
  }
68826
69735
  try {
68827
- const content = readFileSync12(filePath, "utf-8");
69736
+ const content = readFileSync13(filePath, "utf-8");
68828
69737
  const { data, body } = parseFrontmatter(content);
68829
69738
  const active = data.active;
68830
69739
  const iteration = data.iteration;
@@ -68948,7 +69857,7 @@ async function checkCompletionConditions(ctx) {
68948
69857
  }
68949
69858
  return true;
68950
69859
  } catch (err) {
68951
- console.error(import_picocolors12.default.red(`[completion] API error: ${err}`));
69860
+ console.error(import_picocolors13.default.red(`[completion] API error: ${err}`));
68952
69861
  return false;
68953
69862
  }
68954
69863
  }
@@ -69009,7 +69918,7 @@ function logWaiting(ctx, message) {
69009
69918
  if (!ctx.verbose) {
69010
69919
  return;
69011
69920
  }
69012
- console.log(import_picocolors12.default.dim(` Waiting: ${message}`));
69921
+ console.log(import_picocolors13.default.dim(` Waiting: ${message}`));
69013
69922
  }
69014
69923
 
69015
69924
  // src/cli/run/poll-for-completion.ts
@@ -69040,10 +69949,10 @@ async function pollForCompletion(ctx, eventState, abortController, options = {})
69040
69949
  if (eventState.mainSessionError) {
69041
69950
  errorCycleCount++;
69042
69951
  if (errorCycleCount >= ERROR_GRACE_CYCLES) {
69043
- console.error(import_picocolors13.default.red(`
69952
+ console.error(import_picocolors14.default.red(`
69044
69953
 
69045
69954
  Session ended with error: ${eventState.lastError}`));
69046
- 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."));
69047
69956
  return 1;
69048
69957
  }
69049
69958
  continue;
@@ -69054,7 +69963,7 @@ Session ended with error: ${eventState.lastError}`));
69054
69963
  if (eventState.lastEventTimestamp !== null) {
69055
69964
  const timeSinceLastEvent = Date.now() - eventState.lastEventTimestamp;
69056
69965
  if (timeSinceLastEvent > eventWatchdogMs) {
69057
- console.log(import_picocolors13.default.yellow(`
69966
+ console.log(import_picocolors14.default.yellow(`
69058
69967
  No events for ${Math.round(timeSinceLastEvent / 1000)}s, verifying session status...`));
69059
69968
  mainSessionStatus = await getMainSessionStatus(ctx);
69060
69969
  if (mainSessionStatus === "idle") {
@@ -69103,7 +70012,7 @@ Session ended with error: ${eventState.lastError}`));
69103
70012
  const hasActiveWork = hasActiveChildren || hasActiveTodos;
69104
70013
  if (hasActiveWork) {
69105
70014
  eventState.hasReceivedMeaningfulWork = true;
69106
- console.log(import_picocolors13.default.yellow(`
70015
+ console.log(import_picocolors14.default.yellow(`
69107
70016
  No meaningful work events for ${Math.round(secondaryMeaningfulWorkTimeoutMs / 1000)}s but session has active work - assuming in progress`));
69108
70017
  }
69109
70018
  }
@@ -69123,7 +70032,7 @@ Session ended with error: ${eventState.lastError}`));
69123
70032
  }
69124
70033
  consecutiveCompleteChecks++;
69125
70034
  if (consecutiveCompleteChecks >= requiredConsecutive) {
69126
- console.log(import_picocolors13.default.green(`
70035
+ console.log(import_picocolors14.default.green(`
69127
70036
 
69128
70037
  All tasks completed.`));
69129
70038
  return 0;
@@ -69292,7 +70201,7 @@ async function run(options) {
69292
70201
  };
69293
70202
  const restoreInput = suppressRunInput();
69294
70203
  const handleSigint = () => {
69295
- console.log(import_picocolors14.default.yellow(`
70204
+ console.log(import_picocolors15.default.yellow(`
69296
70205
  Interrupted. Shutting down...`));
69297
70206
  restoreInput();
69298
70207
  cleanup();
@@ -69305,9 +70214,9 @@ Interrupted. Shutting down...`));
69305
70214
  sessionId: options.sessionId,
69306
70215
  directory
69307
70216
  });
69308
- console.log(import_picocolors14.default.dim(`Session: ${sessionID}`));
70217
+ console.log(import_picocolors15.default.dim(`Session: ${sessionID}`));
69309
70218
  if (resolvedModel) {
69310
- console.log(import_picocolors14.default.dim(`Model: ${resolvedModel.providerID}/${resolvedModel.modelID}`));
70219
+ console.log(import_picocolors15.default.dim(`Model: ${resolvedModel.providerID}/${resolvedModel.modelID}`));
69311
70220
  }
69312
70221
  const ctx = {
69313
70222
  client: client3,
@@ -69370,7 +70279,7 @@ Interrupted. Shutting down...`));
69370
70279
  if (err instanceof Error && err.name === "AbortError") {
69371
70280
  return 130;
69372
70281
  }
69373
- console.error(import_picocolors14.default.red(`Error: ${serializeError(err)}`));
70282
+ console.error(import_picocolors15.default.red(`Error: ${serializeError(err)}`));
69374
70283
  return 1;
69375
70284
  } finally {
69376
70285
  timestampOutput?.restore();
@@ -69380,53 +70289,53 @@ Interrupted. Shutting down...`));
69380
70289
  init_checker();
69381
70290
 
69382
70291
  // src/cli/get-local-version/formatter.ts
69383
- var import_picocolors15 = __toESM(require_picocolors(), 1);
69384
- var SYMBOLS2 = {
69385
- check: import_picocolors15.default.green("[OK]"),
69386
- cross: import_picocolors15.default.red("[X]"),
69387
- arrow: import_picocolors15.default.cyan("->"),
69388
- info: import_picocolors15.default.blue("[i]"),
69389
- warn: import_picocolors15.default.yellow("[!]"),
69390
- pin: import_picocolors15.default.magenta("[PINNED]"),
69391
- 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]")
69392
70301
  };
69393
70302
  function formatVersionOutput(info) {
69394
70303
  const lines = [];
69395
70304
  lines.push("");
69396
- lines.push(import_picocolors15.default.bold(import_picocolors15.default.white("evil-omo Version Information")));
69397
- 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)));
69398
70307
  lines.push("");
69399
70308
  if (info.currentVersion) {
69400
- lines.push(` Current Version: ${import_picocolors15.default.cyan(info.currentVersion)}`);
70309
+ lines.push(` Current Version: ${import_picocolors16.default.cyan(info.currentVersion)}`);
69401
70310
  } else {
69402
- lines.push(` Current Version: ${import_picocolors15.default.dim("unknown")}`);
70311
+ lines.push(` Current Version: ${import_picocolors16.default.dim("unknown")}`);
69403
70312
  }
69404
70313
  if (!info.isLocalDev && info.latestVersion) {
69405
- lines.push(` Latest Version: ${import_picocolors15.default.cyan(info.latestVersion)}`);
70314
+ lines.push(` Latest Version: ${import_picocolors16.default.cyan(info.latestVersion)}`);
69406
70315
  }
69407
70316
  lines.push("");
69408
70317
  switch (info.status) {
69409
70318
  case "up-to-date":
69410
- 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!")}`);
69411
70320
  break;
69412
70321
  case "outdated":
69413
- lines.push(` ${SYMBOLS2.warn} ${import_picocolors15.default.yellow("Update available")}`);
69414
- 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")}`);
69415
70324
  break;
69416
70325
  case "local-dev":
69417
- lines.push(` ${SYMBOLS2.dev} ${import_picocolors15.default.cyan("Running in local development mode")}`);
69418
- 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")}`);
69419
70328
  break;
69420
70329
  case "pinned":
69421
- lines.push(` ${SYMBOLS2.pin} ${import_picocolors15.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
69422
- 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")}`);
69423
70332
  break;
69424
70333
  case "error":
69425
- lines.push(` ${SYMBOLS2.cross} ${import_picocolors15.default.red("Unable to check for updates")}`);
69426
- 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")}`);
69427
70336
  break;
69428
70337
  case "unknown":
69429
- lines.push(` ${SYMBOLS2.info} ${import_picocolors15.default.yellow("Version information unavailable")}`);
70338
+ lines.push(` ${SYMBOLS3.info} ${import_picocolors16.default.yellow("Version information unavailable")}`);
69430
70339
  break;
69431
70340
  }
69432
70341
  lines.push("");
@@ -69525,69 +70434,31 @@ async function getLocalVersion(options = {}) {
69525
70434
  return 1;
69526
70435
  }
69527
70436
  }
69528
- // src/cli/doctor/constants.ts
69529
- init_shared();
69530
- var import_picocolors16 = __toESM(require_picocolors(), 1);
69531
- var SYMBOLS3 = {
69532
- check: import_picocolors16.default.green("\u2713"),
69533
- cross: import_picocolors16.default.red("\u2717"),
69534
- warn: import_picocolors16.default.yellow("\u26A0"),
69535
- info: import_picocolors16.default.blue("\u2139"),
69536
- arrow: import_picocolors16.default.cyan("\u2192"),
69537
- bullet: import_picocolors16.default.dim("\u2022"),
69538
- skip: import_picocolors16.default.dim("\u25CB")
69539
- };
69540
- var STATUS_COLORS = {
69541
- pass: import_picocolors16.default.green,
69542
- fail: import_picocolors16.default.red,
69543
- warn: import_picocolors16.default.yellow,
69544
- skip: import_picocolors16.default.dim
69545
- };
69546
- var CHECK_IDS = {
69547
- SYSTEM: "system",
69548
- CONFIG: "config",
69549
- TOOLS: "tools",
69550
- MODELS: "models"
69551
- };
69552
- var CHECK_NAMES = {
69553
- [CHECK_IDS.SYSTEM]: "System",
69554
- [CHECK_IDS.CONFIG]: "Configuration",
69555
- [CHECK_IDS.TOOLS]: "Tools",
69556
- [CHECK_IDS.MODELS]: "Models"
69557
- };
69558
- var EXIT_CODES = {
69559
- SUCCESS: 0,
69560
- FAILURE: 1
69561
- };
69562
- var MIN_OPENCODE_VERSION = "1.0.150";
69563
- var PACKAGE_NAME2 = PLUGIN_NAME;
69564
- var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
69565
-
69566
70437
  // src/cli/doctor/checks/system.ts
69567
- import { existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
70438
+ import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
69568
70439
 
69569
70440
  // src/cli/doctor/checks/system-binary.ts
69570
70441
  init_spawn_with_windows_hide();
69571
- import { existsSync as existsSync23 } from "fs";
70442
+ import { existsSync as existsSync25 } from "fs";
69572
70443
  import { homedir as homedir5 } from "os";
69573
- import { join as join24 } from "path";
70444
+ import { join as join26 } from "path";
69574
70445
  function getDesktopAppPaths(platform) {
69575
70446
  const home = homedir5();
69576
70447
  switch (platform) {
69577
70448
  case "darwin":
69578
70449
  return [
69579
70450
  "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
69580
- join24(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
70451
+ join26(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
69581
70452
  ];
69582
70453
  case "win32": {
69583
70454
  const programFiles = process.env.ProgramFiles;
69584
70455
  const localAppData = process.env.LOCALAPPDATA;
69585
70456
  const paths = [];
69586
70457
  if (programFiles) {
69587
- paths.push(join24(programFiles, "OpenCode", "OpenCode.exe"));
70458
+ paths.push(join26(programFiles, "OpenCode", "OpenCode.exe"));
69588
70459
  }
69589
70460
  if (localAppData) {
69590
- paths.push(join24(localAppData, "OpenCode", "OpenCode.exe"));
70461
+ paths.push(join26(localAppData, "OpenCode", "OpenCode.exe"));
69591
70462
  }
69592
70463
  return paths;
69593
70464
  }
@@ -69595,8 +70466,8 @@ function getDesktopAppPaths(platform) {
69595
70466
  return [
69596
70467
  "/usr/bin/opencode",
69597
70468
  "/usr/lib/opencode/opencode",
69598
- join24(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
69599
- join24(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")
69600
70471
  ];
69601
70472
  default:
69602
70473
  return [];
@@ -69608,7 +70479,7 @@ function buildVersionCommand(binaryPath, platform) {
69608
70479
  }
69609
70480
  return [binaryPath, "--version"];
69610
70481
  }
69611
- function findDesktopBinary(platform = process.platform, checkExists = existsSync23) {
70482
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync25) {
69612
70483
  for (const desktopPath of getDesktopAppPaths(platform)) {
69613
70484
  if (checkExists(desktopPath)) {
69614
70485
  return { binary: "opencode", path: desktopPath };
@@ -69638,10 +70509,10 @@ async function getOpenCodeVersion3(binaryPath, platform = process.platform) {
69638
70509
  return null;
69639
70510
  }
69640
70511
  }
69641
- function compareVersions2(current, minimum) {
69642
- const parseVersion2 = (version2) => version2.replace(/^v/, "").split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
69643
- const currentParts = parseVersion2(current);
69644
- const minimumParts = parseVersion2(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);
69645
70516
  const length = Math.max(currentParts.length, minimumParts.length);
69646
70517
  for (let index = 0;index < length; index++) {
69647
70518
  const currentPart = currentParts[index] ?? 0;
@@ -69656,12 +70527,12 @@ function compareVersions2(current, minimum) {
69656
70527
 
69657
70528
  // src/cli/doctor/checks/system-plugin.ts
69658
70529
  init_shared();
69659
- import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
70530
+ import { existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
69660
70531
  function detectConfigPath() {
69661
70532
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
69662
- if (existsSync24(paths.configJsonc))
70533
+ if (existsSync26(paths.configJsonc))
69663
70534
  return paths.configJsonc;
69664
- if (existsSync24(paths.configJson))
70535
+ if (existsSync26(paths.configJson))
69665
70536
  return paths.configJson;
69666
70537
  return null;
69667
70538
  }
@@ -69707,7 +70578,7 @@ function getPluginInfo() {
69707
70578
  };
69708
70579
  }
69709
70580
  try {
69710
- const content = readFileSync20(configPath, "utf-8");
70581
+ const content = readFileSync21(configPath, "utf-8");
69711
70582
  const parsedConfig = parseJsonc(content);
69712
70583
  const pluginEntry = findPluginEntry2(parsedConfig.plugin ?? []);
69713
70584
  if (!pluginEntry) {
@@ -69745,37 +70616,37 @@ function getPluginInfo() {
69745
70616
  init_file_utils();
69746
70617
  init_checker();
69747
70618
  init_auto_update_checker();
69748
- import { existsSync as existsSync25, readFileSync as readFileSync21 } from "fs";
70619
+ import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
69749
70620
  import { homedir as homedir6 } from "os";
69750
- import { join as join25 } from "path";
70621
+ import { join as join27 } from "path";
69751
70622
  init_shared();
69752
70623
  function getPlatformDefaultCacheDir(platform = process.platform) {
69753
70624
  if (platform === "darwin")
69754
- return join25(homedir6(), "Library", "Caches");
70625
+ return join27(homedir6(), "Library", "Caches");
69755
70626
  if (platform === "win32")
69756
- return process.env.LOCALAPPDATA ?? join25(homedir6(), "AppData", "Local");
69757
- return join25(homedir6(), ".cache");
70627
+ return process.env.LOCALAPPDATA ?? join27(homedir6(), "AppData", "Local");
70628
+ return join27(homedir6(), ".cache");
69758
70629
  }
69759
70630
  function resolveOpenCodeCacheDir() {
69760
70631
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
69761
70632
  if (xdgCacheHome)
69762
- return join25(xdgCacheHome, "opencode");
70633
+ return join27(xdgCacheHome, "opencode");
69763
70634
  const fromShared = getOpenCodeCacheDir();
69764
- const platformDefault = join25(getPlatformDefaultCacheDir(), "opencode");
69765
- if (existsSync25(fromShared) || !existsSync25(platformDefault))
70635
+ const platformDefault = join27(getPlatformDefaultCacheDir(), "opencode");
70636
+ if (existsSync27(fromShared) || !existsSync27(platformDefault))
69766
70637
  return fromShared;
69767
70638
  return platformDefault;
69768
70639
  }
69769
70640
  function resolveExistingDir(dirPath) {
69770
- if (!existsSync25(dirPath))
70641
+ if (!existsSync27(dirPath))
69771
70642
  return dirPath;
69772
70643
  return resolveSymlink(dirPath);
69773
70644
  }
69774
70645
  function readPackageJson(filePath) {
69775
- if (!existsSync25(filePath))
70646
+ if (!existsSync27(filePath))
69776
70647
  return null;
69777
70648
  try {
69778
- const content = readFileSync21(filePath, "utf-8");
70649
+ const content = readFileSync22(filePath, "utf-8");
69779
70650
  return parseJsonc(content);
69780
70651
  } catch {
69781
70652
  return null;
@@ -69794,20 +70665,20 @@ function getLoadedPluginVersion() {
69794
70665
  const candidates = [
69795
70666
  {
69796
70667
  cacheDir: configDir,
69797
- cachePackagePath: join25(configDir, "package.json"),
69798
- installedPackagePath: join25(configDir, "node_modules", PACKAGE_NAME2, "package.json")
70668
+ cachePackagePath: join27(configDir, "package.json"),
70669
+ installedPackagePath: join27(configDir, "node_modules", PACKAGE_NAME, "package.json")
69799
70670
  },
69800
70671
  {
69801
70672
  cacheDir,
69802
- cachePackagePath: join25(cacheDir, "package.json"),
69803
- installedPackagePath: join25(cacheDir, "node_modules", PACKAGE_NAME2, "package.json")
70673
+ cachePackagePath: join27(cacheDir, "package.json"),
70674
+ installedPackagePath: join27(cacheDir, "node_modules", PACKAGE_NAME, "package.json")
69804
70675
  }
69805
70676
  ];
69806
- const selectedCandidate = candidates.find((candidate) => existsSync25(candidate.installedPackagePath)) ?? candidates[0];
70677
+ const selectedCandidate = candidates.find((candidate) => existsSync27(candidate.installedPackagePath)) ?? candidates[0];
69807
70678
  const { cacheDir: selectedDir, cachePackagePath, installedPackagePath } = selectedCandidate;
69808
70679
  const cachePackage = readPackageJson(cachePackagePath);
69809
70680
  const installedPackage = readPackageJson(installedPackagePath);
69810
- const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME2]);
70681
+ const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME]);
69811
70682
  const loadedVersion = normalizeVersion(installedPackage?.version);
69812
70683
  return {
69813
70684
  cacheDir: selectedDir,
@@ -69831,10 +70702,10 @@ init_plugin_identity();
69831
70702
  function isConfigValid(configPath) {
69832
70703
  if (!configPath)
69833
70704
  return true;
69834
- if (!existsSync26(configPath))
70705
+ if (!existsSync28(configPath))
69835
70706
  return false;
69836
70707
  try {
69837
- parseJsonc(readFileSync22(configPath, "utf-8"));
70708
+ parseJsonc(readFileSync23(configPath, "utf-8"));
69838
70709
  return true;
69839
70710
  } catch {
69840
70711
  return false;
@@ -69885,7 +70756,7 @@ async function checkSystem() {
69885
70756
  affects: ["doctor", "run"]
69886
70757
  });
69887
70758
  }
69888
- if (systemInfo.opencodeVersion && !compareVersions2(systemInfo.opencodeVersion, MIN_OPENCODE_VERSION)) {
70759
+ if (systemInfo.opencodeVersion && !compareVersions3(systemInfo.opencodeVersion, MIN_OPENCODE_VERSION)) {
69889
70760
  issues.push({
69890
70761
  title: "OpenCode version below minimum",
69891
70762
  description: `Detected ${systemInfo.opencodeVersion}; required >= ${MIN_OPENCODE_VERSION}.`,
@@ -69925,7 +70796,7 @@ async function checkSystem() {
69925
70796
  affects: ["plugin loading"]
69926
70797
  });
69927
70798
  }
69928
- if (systemInfo.loadedVersion && latestVersion && !compareVersions2(systemInfo.loadedVersion, latestVersion)) {
70799
+ if (systemInfo.loadedVersion && latestVersion && !compareVersions3(systemInfo.loadedVersion, latestVersion)) {
69929
70800
  issues.push({
69930
70801
  title: "Loaded plugin is outdated",
69931
70802
  description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
@@ -69950,28 +70821,28 @@ async function checkSystem() {
69950
70821
  }
69951
70822
 
69952
70823
  // src/cli/doctor/checks/config.ts
69953
- import { readFileSync as readFileSync25 } from "fs";
69954
- import { join as join29 } from "path";
70824
+ import { readFileSync as readFileSync26 } from "fs";
70825
+ import { join as join31 } from "path";
69955
70826
  init_shared();
69956
70827
 
69957
70828
  // src/cli/doctor/checks/model-resolution-cache.ts
69958
70829
  init_shared();
69959
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
70830
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
69960
70831
  import { homedir as homedir7 } from "os";
69961
- import { join as join26 } from "path";
70832
+ import { join as join28 } from "path";
69962
70833
  function getOpenCodeCacheDir2() {
69963
70834
  const xdgCache = process.env.XDG_CACHE_HOME;
69964
70835
  if (xdgCache)
69965
- return join26(xdgCache, "opencode");
69966
- return join26(homedir7(), ".cache", "opencode");
70836
+ return join28(xdgCache, "opencode");
70837
+ return join28(homedir7(), ".cache", "opencode");
69967
70838
  }
69968
70839
  function loadAvailableModelsFromCache() {
69969
- const cacheFile = join26(getOpenCodeCacheDir2(), "models.json");
69970
- if (!existsSync27(cacheFile)) {
70840
+ const cacheFile = join28(getOpenCodeCacheDir2(), "models.json");
70841
+ if (!existsSync29(cacheFile)) {
69971
70842
  return { providers: [], modelCount: 0, cacheExists: false };
69972
70843
  }
69973
70844
  try {
69974
- const content = readFileSync23(cacheFile, "utf-8");
70845
+ const content = readFileSync24(cacheFile, "utf-8");
69975
70846
  const data = parseJsonc(content);
69976
70847
  const providers = Object.keys(data);
69977
70848
  let modelCount = 0;
@@ -69993,14 +70864,14 @@ init_model_capabilities();
69993
70864
 
69994
70865
  // src/cli/doctor/checks/model-resolution-config.ts
69995
70866
  init_shared();
69996
- import { readFileSync as readFileSync24 } from "fs";
69997
- import { join as join27 } from "path";
69998
- var PROJECT_CONFIG_DIR = join27(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");
69999
70870
  function loadOmoConfig() {
70000
70871
  const projectDetected = detectPluginConfigFile(PROJECT_CONFIG_DIR);
70001
70872
  if (projectDetected.format !== "none") {
70002
70873
  try {
70003
- const content = readFileSync24(projectDetected.path, "utf-8");
70874
+ const content = readFileSync25(projectDetected.path, "utf-8");
70004
70875
  return parseJsonc(content);
70005
70876
  } catch {
70006
70877
  return null;
@@ -70010,7 +70881,7 @@ function loadOmoConfig() {
70010
70881
  const userDetected = detectPluginConfigFile(userConfigDir);
70011
70882
  if (userDetected.format !== "none") {
70012
70883
  try {
70013
- const content = readFileSync24(userDetected.path, "utf-8");
70884
+ const content = readFileSync25(userDetected.path, "utf-8");
70014
70885
  return parseJsonc(content);
70015
70886
  } catch {
70016
70887
  return null;
@@ -70021,7 +70892,7 @@ function loadOmoConfig() {
70021
70892
 
70022
70893
  // src/cli/doctor/checks/model-resolution-details.ts
70023
70894
  init_shared();
70024
- import { join as join28 } from "path";
70895
+ import { join as join30 } from "path";
70025
70896
 
70026
70897
  // src/cli/doctor/checks/model-resolution-variant.ts
70027
70898
  function formatModelWithVariant(model, variant) {
@@ -70063,7 +70934,7 @@ function formatCapabilityResolutionLabel(mode) {
70063
70934
  }
70064
70935
  function buildModelResolutionDetails(options) {
70065
70936
  const details = [];
70066
- const cacheFile = join28(getOpenCodeCacheDir(), "models.json");
70937
+ const cacheFile = join30(getOpenCodeCacheDir(), "models.json");
70067
70938
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
70068
70939
  details.push("");
70069
70940
  if (options.available.cacheExists) {
@@ -70218,7 +71089,7 @@ async function checkModels() {
70218
71089
  }
70219
71090
 
70220
71091
  // src/cli/doctor/checks/config.ts
70221
- var PROJECT_CONFIG_DIR2 = join29(process.cwd(), ".opencode");
71092
+ var PROJECT_CONFIG_DIR2 = join31(process.cwd(), ".opencode");
70222
71093
  function findConfigPath() {
70223
71094
  const projectConfig = detectPluginConfigFile(PROJECT_CONFIG_DIR2);
70224
71095
  if (projectConfig.format !== "none")
@@ -70235,7 +71106,7 @@ function validateConfig() {
70235
71106
  return { exists: false, path: null, valid: true, config: null, errors: [] };
70236
71107
  }
70237
71108
  try {
70238
- const content = readFileSync25(configPath, "utf-8");
71109
+ const content = readFileSync26(configPath, "utf-8");
70239
71110
  const rawConfig = parseJsonc(content);
70240
71111
  const schemaResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
70241
71112
  if (!schemaResult.success) {
@@ -70339,9 +71210,9 @@ async function checkConfig() {
70339
71210
 
70340
71211
  // src/cli/doctor/checks/dependencies.ts
70341
71212
  init_spawn_with_windows_hide();
70342
- import { existsSync as existsSync28 } from "fs";
71213
+ import { existsSync as existsSync30 } from "fs";
70343
71214
  import { createRequire } from "module";
70344
- import { dirname as dirname7, join as join30 } from "path";
71215
+ import { dirname as dirname8, join as join32 } from "path";
70345
71216
  async function checkBinaryExists(binary2) {
70346
71217
  try {
70347
71218
  const path10 = Bun.which(binary2);
@@ -70397,15 +71268,15 @@ async function checkAstGrepNapi() {
70397
71268
  path: null
70398
71269
  };
70399
71270
  } catch {
70400
- const { existsSync: existsSync29 } = await import("fs");
70401
- const { join: join31 } = await import("path");
71271
+ const { existsSync: existsSync31 } = await import("fs");
71272
+ const { join: join33 } = await import("path");
70402
71273
  const { homedir: homedir8 } = await import("os");
70403
71274
  const pathsToCheck = [
70404
- join31(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
70405
- join31(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")
70406
71277
  ];
70407
71278
  for (const napiPath of pathsToCheck) {
70408
- if (existsSync29(napiPath)) {
71279
+ if (existsSync31(napiPath)) {
70409
71280
  return {
70410
71281
  name: "AST-Grep NAPI",
70411
71282
  required: false,
@@ -70430,8 +71301,8 @@ function findCommentCheckerPackageBinary() {
70430
71301
  try {
70431
71302
  const require2 = createRequire(import.meta.url);
70432
71303
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
70433
- const binaryPath = join30(dirname7(pkgPath), "bin", binaryName);
70434
- if (existsSync28(binaryPath))
71304
+ const binaryPath = join32(dirname8(pkgPath), "bin", binaryName);
71305
+ if (existsSync30(binaryPath))
70435
71306
  return binaryPath;
70436
71307
  } catch {}
70437
71308
  return null;
@@ -70588,15 +71459,15 @@ var BUILTIN_SERVERS = {
70588
71459
  "kotlin-ls": { command: ["kotlin-lsp"], extensions: [".kt", ".kts"] }
70589
71460
  };
70590
71461
  // src/tools/lsp/server-config-loader.ts
70591
- import { existsSync as existsSync29, readFileSync as readFileSync26 } from "fs";
70592
- import { join as join31 } from "path";
71462
+ import { existsSync as existsSync31, readFileSync as readFileSync27 } from "fs";
71463
+ import { join as join33 } from "path";
70593
71464
  init_shared();
70594
71465
  init_jsonc_parser();
70595
71466
  function loadJsonFile(path10) {
70596
- if (!existsSync29(path10))
71467
+ if (!existsSync31(path10))
70597
71468
  return null;
70598
71469
  try {
70599
- return parseJsonc(readFileSync26(path10, "utf-8"));
71470
+ return parseJsonc(readFileSync27(path10, "utf-8"));
70600
71471
  } catch {
70601
71472
  return null;
70602
71473
  }
@@ -70605,9 +71476,9 @@ function getConfigPaths2() {
70605
71476
  const cwd = process.cwd();
70606
71477
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
70607
71478
  return {
70608
- project: detectPluginConfigFile(join31(cwd, ".opencode")).path,
71479
+ project: detectPluginConfigFile(join33(cwd, ".opencode")).path,
70609
71480
  user: detectPluginConfigFile(configDir).path,
70610
- opencode: detectConfigFile(join31(configDir, "opencode")).path
71481
+ opencode: detectConfigFile(join33(configDir, "opencode")).path
70611
71482
  };
70612
71483
  }
70613
71484
  function loadAllConfigs() {
@@ -70676,21 +71547,21 @@ function getMergedServers() {
70676
71547
  }
70677
71548
 
70678
71549
  // src/tools/lsp/server-installation.ts
70679
- import { existsSync as existsSync30 } from "fs";
70680
- import { delimiter as delimiter2, join as join33 } from "path";
71550
+ import { existsSync as existsSync32 } from "fs";
71551
+ import { delimiter as delimiter2, join as join35 } from "path";
70681
71552
 
70682
71553
  // src/tools/lsp/server-path-bases.ts
70683
71554
  init_shared();
70684
- import { join as join32 } from "path";
71555
+ import { join as join34 } from "path";
70685
71556
  function getLspServerAdditionalPathBases(workingDirectory) {
70686
71557
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
70687
- const dataDir = join32(getDataDir(), "opencode");
71558
+ const dataDir = join34(getDataDir(), "opencode");
70688
71559
  return [
70689
- join32(workingDirectory, "node_modules", ".bin"),
70690
- join32(configDir, "bin"),
70691
- join32(configDir, "node_modules", ".bin"),
70692
- join32(dataDir, "bin"),
70693
- join32(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")
70694
71565
  ];
70695
71566
  }
70696
71567
 
@@ -70700,7 +71571,7 @@ function isServerInstalled(command) {
70700
71571
  return false;
70701
71572
  const cmd = command[0];
70702
71573
  if (cmd.includes("/") || cmd.includes("\\")) {
70703
- if (existsSync30(cmd))
71574
+ if (existsSync32(cmd))
70704
71575
  return true;
70705
71576
  }
70706
71577
  const isWindows = process.platform === "win32";
@@ -70721,14 +71592,14 @@ function isServerInstalled(command) {
70721
71592
  const paths = pathEnv.split(delimiter2);
70722
71593
  for (const p2 of paths) {
70723
71594
  for (const suffix of exts) {
70724
- if (existsSync30(join33(p2, cmd + suffix))) {
71595
+ if (existsSync32(join35(p2, cmd + suffix))) {
70725
71596
  return true;
70726
71597
  }
70727
71598
  }
70728
71599
  }
70729
71600
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
70730
71601
  for (const suffix of exts) {
70731
- if (existsSync30(join33(base, cmd + suffix))) {
71602
+ if (existsSync32(join35(base, cmd + suffix))) {
70732
71603
  return true;
70733
71604
  }
70734
71605
  }
@@ -70790,24 +71661,24 @@ function getInstalledLspServers() {
70790
71661
 
70791
71662
  // src/cli/doctor/checks/tools-mcp.ts
70792
71663
  init_shared();
70793
- import { existsSync as existsSync31, readFileSync as readFileSync27 } from "fs";
71664
+ import { existsSync as existsSync33, readFileSync as readFileSync28 } from "fs";
70794
71665
  import { homedir as homedir8 } from "os";
70795
- import { join as join34 } from "path";
71666
+ import { join as join36 } from "path";
70796
71667
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
70797
71668
  function getMcpConfigPaths() {
70798
71669
  return [
70799
- join34(homedir8(), ".claude", ".mcp.json"),
70800
- join34(process.cwd(), ".mcp.json"),
70801
- join34(process.cwd(), ".claude", ".mcp.json")
71670
+ join36(homedir8(), ".claude", ".mcp.json"),
71671
+ join36(process.cwd(), ".mcp.json"),
71672
+ join36(process.cwd(), ".claude", ".mcp.json")
70802
71673
  ];
70803
71674
  }
70804
71675
  function loadUserMcpConfig() {
70805
71676
  const servers = {};
70806
71677
  for (const configPath of getMcpConfigPaths()) {
70807
- if (!existsSync31(configPath))
71678
+ if (!existsSync33(configPath))
70808
71679
  continue;
70809
71680
  try {
70810
- const content = readFileSync27(configPath, "utf-8");
71681
+ const content = readFileSync28(configPath, "utf-8");
70811
71682
  const config2 = parseJsonc(content);
70812
71683
  if (config2.mcpServers) {
70813
71684
  Object.assign(servers, config2.mcpServers);
@@ -70974,17 +71845,17 @@ function formatStatusSymbol(status) {
70974
71845
  const colorFn = STATUS_COLORS[status];
70975
71846
  switch (status) {
70976
71847
  case "pass":
70977
- return colorFn(SYMBOLS3.check);
71848
+ return colorFn(SYMBOLS2.check);
70978
71849
  case "fail":
70979
- return colorFn(SYMBOLS3.cross);
71850
+ return colorFn(SYMBOLS2.cross);
70980
71851
  case "warn":
70981
- return colorFn(SYMBOLS3.warn);
71852
+ return colorFn(SYMBOLS2.warn);
70982
71853
  case "skip":
70983
- return colorFn(SYMBOLS3.skip);
71854
+ return colorFn(SYMBOLS2.skip);
70984
71855
  }
70985
71856
  }
70986
71857
  function formatStatusMark(available) {
70987
- 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);
70988
71859
  }
70989
71860
  function formatHeader() {
70990
71861
  return `
@@ -71014,12 +71885,12 @@ function formatDefault(result) {
71014
71885
  if (allIssues.length === 0) {
71015
71886
  const opencodeVer = result.systemInfo.opencodeVersion ?? "unknown";
71016
71887
  const pluginVer = result.systemInfo.pluginVersion ?? "unknown";
71017
- lines.push(` ${import_picocolors18.default.green(SYMBOLS3.check)} ${import_picocolors18.default.green(`System OK (opencode ${opencodeVer} \xB7 evil-omo ${pluginVer})`)}`);
71888
+ lines.push(` ${import_picocolors18.default.green(SYMBOLS2.check)} ${import_picocolors18.default.green(`System OK (opencode ${opencodeVer} \xB7 evil-omo ${pluginVer})`)}`);
71018
71889
  } else {
71019
71890
  const issueCount = allIssues.filter((i2) => i2.severity === "error").length;
71020
71891
  const warnCount = allIssues.filter((i2) => i2.severity === "warning").length;
71021
71892
  const totalStr = `${issueCount + warnCount} ${issueCount + warnCount === 1 ? "issue" : "issues"}`;
71022
- lines.push(` ${import_picocolors18.default.yellow(SYMBOLS3.warn)} ${totalStr} found:
71893
+ lines.push(` ${import_picocolors18.default.yellow(SYMBOLS2.warn)} ${totalStr} found:
71023
71894
  `);
71024
71895
  allIssues.forEach((issue2, index) => {
71025
71896
  lines.push(formatIssue(issue2, index + 1));
@@ -71260,11 +72131,11 @@ async function refreshModelCapabilities(options, deps = {}) {
71260
72131
 
71261
72132
  // src/features/mcp-oauth/storage.ts
71262
72133
  init_shared();
71263
- import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync8, readFileSync as readFileSync28, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
71264
- import { dirname as dirname8, join as join35 } 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";
71265
72136
  var STORAGE_FILE_NAME = "mcp-oauth.json";
71266
72137
  function getMcpOauthStoragePath() {
71267
- return join35(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
72138
+ return join37(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
71268
72139
  }
71269
72140
  function normalizeHost(serverHost) {
71270
72141
  let host = serverHost.trim();
@@ -71301,11 +72172,11 @@ function buildKey(serverHost, resource) {
71301
72172
  }
71302
72173
  function readStore() {
71303
72174
  const filePath = getMcpOauthStoragePath();
71304
- if (!existsSync32(filePath)) {
72175
+ if (!existsSync34(filePath)) {
71305
72176
  return null;
71306
72177
  }
71307
72178
  try {
71308
- const content = readFileSync28(filePath, "utf-8");
72179
+ const content = readFileSync29(filePath, "utf-8");
71309
72180
  return JSON.parse(content);
71310
72181
  } catch {
71311
72182
  return null;
@@ -71314,12 +72185,14 @@ function readStore() {
71314
72185
  function writeStore(store2) {
71315
72186
  const filePath = getMcpOauthStoragePath();
71316
72187
  try {
71317
- const dir = dirname8(filePath);
71318
- if (!existsSync32(dir)) {
71319
- mkdirSync8(dir, { recursive: true });
71320
- }
71321
- writeFileSync10(filePath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
71322
- 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);
71323
72196
  return true;
71324
72197
  } catch {
71325
72198
  return false;
@@ -71350,7 +72223,7 @@ function deleteToken(serverHost, resource) {
71350
72223
  if (Object.keys(store2).length === 0) {
71351
72224
  try {
71352
72225
  const filePath = getMcpOauthStoragePath();
71353
- if (existsSync32(filePath)) {
72226
+ if (existsSync34(filePath)) {
71354
72227
  unlinkSync4(filePath);
71355
72228
  }
71356
72229
  return true;
@@ -71540,7 +72413,7 @@ async function findAvailablePort2(startPort = DEFAULT_PORT) {
71540
72413
  }
71541
72414
 
71542
72415
  // src/features/mcp-oauth/oauth-authorization-flow.ts
71543
- import { spawn as spawn2 } from "child_process";
72416
+ import { spawn } from "child_process";
71544
72417
  import { createHash, randomBytes as randomBytes2 } from "crypto";
71545
72418
  import { createServer } from "http";
71546
72419
  function generateCodeVerifier() {
@@ -71621,7 +72494,7 @@ function openBrowser(url2) {
71621
72494
  args = [url2];
71622
72495
  }
71623
72496
  try {
71624
- const child = spawn2(command, args, { stdio: "ignore", detached: true });
72497
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
71625
72498
  child.on("error", () => {});
71626
72499
  child.unref();
71627
72500
  } catch {}
@@ -71648,6 +72521,38 @@ async function runAuthorizationCodeRedirect(options) {
71648
72521
  }
71649
72522
 
71650
72523
  // src/features/mcp-oauth/provider.ts
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
+ }
72555
+
71651
72556
  class McpOAuthProvider {
71652
72557
  serverUrl;
71653
72558
  configClientId;
@@ -71742,33 +72647,34 @@ class McpOAuthProvider {
71742
72647
  ...metadata.resource ? { resource: metadata.resource } : {}
71743
72648
  }).toString()
71744
72649
  });
71745
- if (!tokenResponse.ok) {
71746
- let errorDetail = `${tokenResponse.status}`;
71747
- try {
71748
- const body = await tokenResponse.json();
71749
- if (body.error) {
71750
- errorDetail = `${tokenResponse.status} ${body.error}`;
71751
- if (body.error_description) {
71752
- errorDetail += `: ${body.error_description}`;
71753
- }
71754
- }
71755
- } catch {}
71756
- throw new Error(`Token exchange failed: ${errorDetail}`);
71757
- }
71758
- const tokenData = await tokenResponse.json();
71759
- const accessToken = tokenData.access_token;
71760
- if (typeof accessToken !== "string") {
71761
- 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.");
71762
72661
  }
71763
- const oauthTokenData = {
71764
- accessToken,
71765
- refreshToken: typeof tokenData.refresh_token === "string" ? tokenData.refresh_token : undefined,
71766
- expiresAt: typeof tokenData.expires_in === "number" ? Math.floor(Date.now() / 1000) + tokenData.expires_in : undefined,
71767
- clientInfo: {
71768
- clientId: clientInfo.clientId,
71769
- clientSecret: clientInfo.clientSecret
71770
- }
71771
- };
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);
71772
72678
  this.saveTokens(oauthTokenData);
71773
72679
  return oauthTokenData;
71774
72680
  }