oh-my-opencode 3.5.6 → 3.7.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 (137) hide show
  1. package/README.ja.md +6 -6
  2. package/README.ko.md +6 -6
  3. package/README.md +6 -6
  4. package/README.zh-cn.md +6 -6
  5. package/dist/agents/sisyphus-junior/gpt.d.ts +4 -14
  6. package/dist/cli/index.js +450 -116
  7. package/dist/cli/run/event-handlers.d.ts +1 -0
  8. package/dist/cli/run/opencode-bin-path.d.ts +3 -0
  9. package/dist/cli/run/opencode-binary-resolver.d.ts +5 -0
  10. package/dist/cli/run/session-resolver.d.ts +1 -0
  11. package/dist/cli/run/types.d.ts +30 -1
  12. package/dist/config/schema/browser-automation.d.ts +2 -0
  13. package/dist/config/schema/experimental.d.ts +1 -0
  14. package/dist/config/schema/hooks.d.ts +1 -0
  15. package/dist/config/schema/oh-my-opencode-config.d.ts +3 -0
  16. package/dist/create-hooks.d.ts +3 -0
  17. package/dist/create-managers.d.ts +1 -0
  18. package/dist/features/background-agent/constants.d.ts +1 -1
  19. package/dist/features/background-agent/manager.d.ts +3 -0
  20. package/dist/features/background-agent/message-dir.d.ts +1 -1
  21. package/dist/features/background-agent/result-handler.d.ts +1 -1
  22. package/dist/features/builtin-skills/skills/index.d.ts +1 -0
  23. package/dist/features/builtin-skills/skills/playwright-cli.d.ts +10 -0
  24. package/dist/features/claude-code-mcp-loader/loader.d.ts +1 -1
  25. package/dist/features/hook-message-injector/constants.d.ts +1 -3
  26. package/dist/features/hook-message-injector/index.d.ts +1 -1
  27. package/dist/features/hook-message-injector/injector.d.ts +51 -3
  28. package/dist/features/tmux-subagent/action-executor-core.d.ts +21 -0
  29. package/dist/features/tmux-subagent/action-executor.d.ts +3 -12
  30. package/dist/features/tmux-subagent/grid-planning.d.ts +2 -2
  31. package/dist/features/tmux-subagent/manager.d.ts +0 -1
  32. package/dist/features/tmux-subagent/pane-split-availability.d.ts +3 -2
  33. package/dist/features/tmux-subagent/polling-manager.d.ts +1 -0
  34. package/dist/features/tmux-subagent/spawn-target-finder.d.ts +1 -1
  35. package/dist/hooks/agent-usage-reminder/constants.d.ts +0 -1
  36. package/dist/hooks/anthropic-context-window-limit-recovery/client.d.ts +3 -34
  37. package/dist/hooks/anthropic-context-window-limit-recovery/deduplication-recovery.d.ts +4 -1
  38. package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +11 -0
  39. package/dist/hooks/anthropic-context-window-limit-recovery/message-builder.d.ts +4 -1
  40. package/dist/hooks/anthropic-context-window-limit-recovery/message-storage-directory.d.ts +5 -1
  41. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.d.ts +4 -1
  42. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.d.ts +5 -2
  43. package/dist/hooks/anthropic-context-window-limit-recovery/storage-paths.d.ts +2 -2
  44. package/dist/hooks/anthropic-context-window-limit-recovery/storage.d.ts +1 -0
  45. package/dist/hooks/anthropic-context-window-limit-recovery/target-token-truncation.d.ts +4 -1
  46. package/dist/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.d.ts +29 -0
  47. package/dist/hooks/atlas/session-last-agent.d.ts +4 -1
  48. package/dist/hooks/atlas/tool-execute-before.d.ts +2 -0
  49. package/dist/hooks/context-window-monitor.d.ts +5 -1
  50. package/dist/hooks/directory-agents-injector/constants.d.ts +0 -1
  51. package/dist/hooks/directory-agents-injector/hook.d.ts +3 -1
  52. package/dist/hooks/directory-readme-injector/constants.d.ts +0 -1
  53. package/dist/hooks/directory-readme-injector/hook.d.ts +3 -1
  54. package/dist/hooks/hashline-read-enhancer/hook.d.ts +18 -0
  55. package/dist/hooks/hashline-read-enhancer/index.d.ts +1 -0
  56. package/dist/hooks/index.d.ts +1 -0
  57. package/dist/hooks/interactive-bash-session/constants.d.ts +0 -1
  58. package/dist/hooks/preemptive-compaction.d.ts +4 -1
  59. package/dist/hooks/prometheus-md-only/agent-resolution.d.ts +4 -1
  60. package/dist/hooks/ralph-loop/message-storage-directory.d.ts +1 -1
  61. package/dist/hooks/rules-injector/constants.d.ts +0 -1
  62. package/dist/hooks/rules-injector/hook.d.ts +3 -1
  63. package/dist/hooks/session-recovery/constants.d.ts +1 -3
  64. package/dist/hooks/session-recovery/recover-empty-content-message-sdk.d.ts +13 -0
  65. package/dist/hooks/session-recovery/recover-empty-content-message.d.ts +1 -1
  66. package/dist/hooks/session-recovery/recover-thinking-block-order.d.ts +1 -1
  67. package/dist/hooks/session-recovery/recover-thinking-disabled-violation.d.ts +1 -1
  68. package/dist/hooks/session-recovery/storage/empty-text.d.ts +5 -0
  69. package/dist/hooks/session-recovery/storage/message-dir.d.ts +1 -1
  70. package/dist/hooks/session-recovery/storage/messages-reader.d.ts +4 -0
  71. package/dist/hooks/session-recovery/storage/parts-reader.d.ts +4 -0
  72. package/dist/hooks/session-recovery/storage/text-part-injector.d.ts +4 -0
  73. package/dist/hooks/session-recovery/storage/thinking-prepend.d.ts +4 -0
  74. package/dist/hooks/session-recovery/storage/thinking-strip.d.ts +4 -0
  75. package/dist/hooks/session-recovery/storage.d.ts +7 -0
  76. package/dist/hooks/sisyphus-junior-notepad/hook.d.ts +1 -1
  77. package/dist/hooks/think-mode/switcher.d.ts +7 -0
  78. package/dist/hooks/todo-continuation-enforcer/message-directory.d.ts +1 -1
  79. package/dist/hooks/todo-continuation-enforcer/types.d.ts +1 -1
  80. package/dist/hooks/tool-output-truncator.d.ts +3 -0
  81. package/dist/index.js +24207 -22344
  82. package/dist/plugin/hooks/create-core-hooks.d.ts +3 -0
  83. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -0
  84. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +4 -1
  85. package/dist/plugin-config.d.ts +1 -1
  86. package/dist/plugin-handlers/agent-key-remapper.d.ts +1 -0
  87. package/dist/shared/agent-display-names.d.ts +5 -0
  88. package/dist/shared/dynamic-truncator.d.ts +7 -3
  89. package/dist/shared/fallback-model-availability.d.ts +9 -2
  90. package/dist/shared/git-worktree/index.d.ts +2 -0
  91. package/dist/shared/git-worktree/parse-status-porcelain-line.d.ts +6 -0
  92. package/dist/shared/index.d.ts +8 -1
  93. package/dist/shared/model-availability.d.ts +0 -5
  94. package/dist/shared/model-name-matcher.d.ts +0 -1
  95. package/dist/shared/normalize-sdk-response.d.ts +4 -0
  96. package/dist/shared/opencode-http-api.d.ts +3 -0
  97. package/dist/shared/opencode-storage-detection.d.ts +2 -0
  98. package/dist/shared/opencode-storage-paths.d.ts +4 -0
  99. package/dist/shared/opencode-version.d.ts +5 -0
  100. package/dist/shared/session-directory-resolver.d.ts +7 -0
  101. package/dist/shared/session-utils.d.ts +2 -2
  102. package/dist/shared/tmux/tmux-utils/layout.d.ts +2 -2
  103. package/dist/tools/background-task/create-background-cancel.d.ts +1 -1
  104. package/dist/tools/background-task/create-background-task.d.ts +2 -2
  105. package/dist/tools/background-task/message-dir.d.ts +1 -1
  106. package/dist/tools/background-task/modules/background-cancel.d.ts +1 -1
  107. package/dist/tools/background-task/modules/utils.d.ts +2 -1
  108. package/dist/tools/call-omo-agent/background-agent-executor.d.ts +2 -1
  109. package/dist/tools/call-omo-agent/background-executor.d.ts +2 -1
  110. package/dist/tools/call-omo-agent/message-dir.d.ts +1 -1
  111. package/dist/tools/call-omo-agent/message-storage-directory.d.ts +1 -1
  112. package/dist/tools/call-omo-agent/tools.d.ts +1 -1
  113. package/dist/tools/delegate-task/parent-context-resolver.d.ts +2 -1
  114. package/dist/tools/delegate-task/sisyphus-junior-agent.d.ts +1 -1
  115. package/dist/tools/delegate-task/sync-prompt-sender.d.ts +7 -1
  116. package/dist/tools/hashline-edit/constants.d.ts +2 -0
  117. package/dist/tools/hashline-edit/edit-operations.d.ts +6 -0
  118. package/dist/tools/hashline-edit/hash-computation.d.ts +3 -0
  119. package/dist/tools/hashline-edit/index.d.ts +7 -0
  120. package/dist/tools/hashline-edit/tools.d.ts +2 -0
  121. package/dist/tools/hashline-edit/types.d.ts +22 -0
  122. package/dist/tools/hashline-edit/validation.d.ts +6 -0
  123. package/dist/tools/index.d.ts +1 -0
  124. package/dist/tools/session-manager/constants.d.ts +1 -4
  125. package/dist/tools/session-manager/session-formatter.d.ts +1 -1
  126. package/dist/tools/session-manager/storage.d.ts +5 -2
  127. package/dist/tools/session-manager/types.d.ts +1 -1
  128. package/dist/tools/task/todo-sync.d.ts +2 -2
  129. package/package.json +8 -8
  130. package/dist/tools/task/task-action-create.d.ts +0 -4
  131. package/dist/tools/task/task-action-delete.d.ts +0 -2
  132. package/dist/tools/task/task-action-get.d.ts +0 -2
  133. package/dist/tools/task/task-action-list.d.ts +0 -2
  134. package/dist/tools/task/task-action-update.d.ts +0 -2
  135. package/dist/tools/task/task-id-validator.d.ts +0 -1
  136. package/dist/tools/task/task.d.ts +0 -3
  137. /package/dist/{features/background-agent/message-storage-locator.d.ts → shared/opencode-message-dir.d.ts} +0 -0
package/dist/cli/index.js CHANGED
@@ -4905,11 +4905,32 @@ var init_tool_name = () => {};
4905
4905
  // src/shared/file-utils.ts
4906
4906
  var init_file_utils = () => {};
4907
4907
 
4908
+ // src/shared/normalize-sdk-response.ts
4909
+ function normalizeSDKResponse(response, fallback, options) {
4910
+ if (response === null || response === undefined) {
4911
+ return fallback;
4912
+ }
4913
+ if (Array.isArray(response)) {
4914
+ return response;
4915
+ }
4916
+ if (typeof response === "object" && "data" in response) {
4917
+ const data = response.data;
4918
+ if (data !== null && data !== undefined) {
4919
+ return data;
4920
+ }
4921
+ if (options?.preferResponseOnMissingData === true) {
4922
+ return response;
4923
+ }
4924
+ return fallback;
4925
+ }
4926
+ if (options?.preferResponseOnMissingData === true) {
4927
+ return response;
4928
+ }
4929
+ return fallback;
4930
+ }
4931
+
4908
4932
  // src/shared/dynamic-truncator.ts
4909
- var ANTHROPIC_ACTUAL_LIMIT;
4910
- var init_dynamic_truncator = __esm(() => {
4911
- ANTHROPIC_ACTUAL_LIMIT = process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : 200000;
4912
- });
4933
+ var init_dynamic_truncator = () => {};
4913
4934
 
4914
4935
  // src/shared/data-path.ts
4915
4936
  import * as path2 from "path";
@@ -6678,6 +6699,15 @@ var NOT_CACHED;
6678
6699
  var init_opencode_version = __esm(() => {
6679
6700
  NOT_CACHED = Symbol("NOT_CACHED");
6680
6701
  });
6702
+
6703
+ // src/shared/opencode-storage-detection.ts
6704
+ var NOT_CACHED2, FALSE_PENDING_RETRY;
6705
+ var init_opencode_storage_detection = __esm(() => {
6706
+ init_data_path();
6707
+ init_opencode_version();
6708
+ NOT_CACHED2 = Symbol("NOT_CACHED");
6709
+ FALSE_PENDING_RETRY = Symbol("FALSE_PENDING_RETRY");
6710
+ });
6681
6711
  // src/shared/external-plugin-detector.ts
6682
6712
  var init_external_plugin_detector = __esm(() => {
6683
6713
  init_logger();
@@ -6974,20 +7004,29 @@ var init_model_resolver = __esm(() => {
6974
7004
  init_model_resolution_pipeline();
6975
7005
  });
6976
7006
 
7007
+ // src/shared/model-name-matcher.ts
7008
+ var init_model_name_matcher = __esm(() => {
7009
+ init_logger();
7010
+ });
7011
+
7012
+ // src/shared/fallback-model-availability.ts
7013
+ var init_fallback_model_availability = __esm(() => {
7014
+ init_connected_providers_cache();
7015
+ init_logger();
7016
+ init_model_name_matcher();
7017
+ });
7018
+
6977
7019
  // src/features/hook-message-injector/constants.ts
6978
- import { join as join6 } from "path";
6979
- var OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE;
6980
7020
  var init_constants = __esm(() => {
6981
- init_data_path();
6982
- OPENCODE_STORAGE = getOpenCodeStorageDir();
6983
- MESSAGE_STORAGE = join6(OPENCODE_STORAGE, "message");
6984
- PART_STORAGE = join6(OPENCODE_STORAGE, "part");
7021
+ init_shared();
6985
7022
  });
6986
7023
 
6987
7024
  // src/features/hook-message-injector/injector.ts
6988
7025
  var init_injector = __esm(() => {
6989
7026
  init_constants();
6990
7027
  init_logger();
7028
+ init_opencode_storage_detection();
7029
+ init_shared();
6991
7030
  });
6992
7031
 
6993
7032
  // src/features/hook-message-injector/index.ts
@@ -6996,9 +7035,70 @@ var init_hook_message_injector = __esm(() => {
6996
7035
  init_constants();
6997
7036
  });
6998
7037
 
7038
+ // src/shared/opencode-storage-paths.ts
7039
+ import { join as join6 } from "path";
7040
+ var OPENCODE_STORAGE, MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE;
7041
+ var init_opencode_storage_paths = __esm(() => {
7042
+ init_data_path();
7043
+ OPENCODE_STORAGE = getOpenCodeStorageDir();
7044
+ MESSAGE_STORAGE = join6(OPENCODE_STORAGE, "message");
7045
+ PART_STORAGE = join6(OPENCODE_STORAGE, "part");
7046
+ SESSION_STORAGE = join6(OPENCODE_STORAGE, "session");
7047
+ });
7048
+
7049
+ // src/shared/opencode-message-dir.ts
7050
+ var init_opencode_message_dir = __esm(() => {
7051
+ init_opencode_storage_paths();
7052
+ init_opencode_storage_detection();
7053
+ init_logger();
7054
+ });
7055
+
7056
+ // src/shared/agent-display-names.ts
7057
+ function getAgentDisplayName(configKey) {
7058
+ const exactMatch = AGENT_DISPLAY_NAMES[configKey];
7059
+ if (exactMatch !== undefined)
7060
+ return exactMatch;
7061
+ const lowerKey = configKey.toLowerCase();
7062
+ for (const [k, v] of Object.entries(AGENT_DISPLAY_NAMES)) {
7063
+ if (k.toLowerCase() === lowerKey)
7064
+ return v;
7065
+ }
7066
+ return configKey;
7067
+ }
7068
+ function getAgentConfigKey(agentName) {
7069
+ const lower = agentName.toLowerCase();
7070
+ const reversed = REVERSE_DISPLAY_NAMES[lower];
7071
+ if (reversed !== undefined)
7072
+ return reversed;
7073
+ if (AGENT_DISPLAY_NAMES[lower] !== undefined)
7074
+ return lower;
7075
+ return lower;
7076
+ }
7077
+ var AGENT_DISPLAY_NAMES, REVERSE_DISPLAY_NAMES;
7078
+ var init_agent_display_names = __esm(() => {
7079
+ AGENT_DISPLAY_NAMES = {
7080
+ sisyphus: "Sisyphus (Ultraworker)",
7081
+ hephaestus: "Hephaestus (Deep Agent)",
7082
+ prometheus: "Prometheus (Plan Builder)",
7083
+ atlas: "Atlas (Plan Executor)",
7084
+ "sisyphus-junior": "Sisyphus-Junior",
7085
+ metis: "Metis (Plan Consultant)",
7086
+ momus: "Momus (Plan Critic)",
7087
+ oracle: "oracle",
7088
+ librarian: "librarian",
7089
+ explore: "explore",
7090
+ "multimodal-looker": "multimodal-looker"
7091
+ };
7092
+ REVERSE_DISPLAY_NAMES = Object.fromEntries(Object.entries(AGENT_DISPLAY_NAMES).map(([key, displayName]) => [displayName.toLowerCase(), key]));
7093
+ });
7094
+
6999
7095
  // src/shared/session-utils.ts
7000
7096
  var init_session_utils = __esm(() => {
7001
7097
  init_hook_message_injector();
7098
+ init_opencode_message_dir();
7099
+ init_opencode_storage_detection();
7100
+ init_logger();
7101
+ init_agent_display_names();
7002
7102
  });
7003
7103
  // src/shared/tmux/constants.ts
7004
7104
  var SESSION_TIMEOUT_MS;
@@ -7057,6 +7157,11 @@ var init_model_suggestion_retry = __esm(() => {
7057
7157
  var init_opencode_server_auth = __esm(() => {
7058
7158
  init_logger();
7059
7159
  });
7160
+ // src/shared/opencode-http-api.ts
7161
+ var init_opencode_http_api = __esm(() => {
7162
+ init_opencode_server_auth();
7163
+ init_logger();
7164
+ });
7060
7165
 
7061
7166
  // src/shared/port-utils.ts
7062
7167
  async function isPortAvailable(port, hostname = "127.0.0.1") {
@@ -7090,10 +7195,15 @@ async function getAvailableServerPort(preferredPort = DEFAULT_SERVER_PORT, hostn
7090
7195
  }
7091
7196
  var DEFAULT_SERVER_PORT = 4096, MAX_PORT_ATTEMPTS = 20;
7092
7197
  var init_port_utils = () => {};
7198
+ // src/shared/git-worktree/parse-status-porcelain.ts
7199
+ var init_parse_status_porcelain = () => {};
7093
7200
  // src/shared/git-worktree/collect-git-diff-stats.ts
7094
- var init_collect_git_diff_stats = () => {};
7201
+ var init_collect_git_diff_stats = __esm(() => {
7202
+ init_parse_status_porcelain();
7203
+ });
7095
7204
  // src/shared/git-worktree/index.ts
7096
7205
  var init_git_worktree = __esm(() => {
7206
+ init_parse_status_porcelain();
7097
7207
  init_collect_git_diff_stats();
7098
7208
  });
7099
7209
 
@@ -7101,6 +7211,9 @@ var init_git_worktree = __esm(() => {
7101
7211
  var init_safe_create_hook = __esm(() => {
7102
7212
  init_logger();
7103
7213
  });
7214
+ // src/shared/session-directory-resolver.ts
7215
+ var init_session_directory_resolver = () => {};
7216
+
7104
7217
  // src/shared/index.ts
7105
7218
  var init_shared = __esm(() => {
7106
7219
  init_model_resolution_pipeline();
@@ -7120,6 +7233,7 @@ var init_shared = __esm(() => {
7120
7233
  init_migration();
7121
7234
  init_opencode_config_dir();
7122
7235
  init_opencode_version();
7236
+ init_opencode_storage_detection();
7123
7237
  init_external_plugin_detector();
7124
7238
  init_zip_extractor();
7125
7239
  init_binary_downloader();
@@ -7130,14 +7244,19 @@ var init_shared = __esm(() => {
7130
7244
  init_model_requirements();
7131
7245
  init_model_resolver();
7132
7246
  init_model_availability();
7247
+ init_fallback_model_availability();
7133
7248
  init_connected_providers_cache();
7134
7249
  init_session_utils();
7135
7250
  init_tmux();
7136
7251
  init_model_suggestion_retry();
7137
7252
  init_opencode_server_auth();
7253
+ init_opencode_http_api();
7138
7254
  init_port_utils();
7139
7255
  init_git_worktree();
7140
7256
  init_safe_create_hook();
7257
+ init_opencode_storage_paths();
7258
+ init_opencode_message_dir();
7259
+ init_session_directory_resolver();
7141
7260
  });
7142
7261
 
7143
7262
  // src/cli/config-manager/config-context.ts
@@ -8788,6 +8907,7 @@ var init_startup_toasts = __esm(() => {
8788
8907
  // src/hooks/auto-update-checker/hook.ts
8789
8908
  function createAutoUpdateCheckerHook(ctx, options = {}) {
8790
8909
  const { showStartupToast = true, isSisyphusEnabled = false, autoUpdate = true } = options;
8910
+ const isCliRunMode = process.env.OPENCODE_CLI_RUN_MODE === "true";
8791
8911
  const getToastMessage = (isUpdate, latestVersion) => {
8792
8912
  if (isSisyphusEnabled) {
8793
8913
  return isUpdate ? `Sisyphus on steroids is steering OpenCode.
@@ -8801,6 +8921,8 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
8801
8921
  event: ({ event }) => {
8802
8922
  if (event.type !== "session.created")
8803
8923
  return;
8924
+ if (isCliRunMode)
8925
+ return;
8804
8926
  if (hasChecked)
8805
8927
  return;
8806
8928
  const props = event.properties;
@@ -8877,7 +8999,7 @@ var {
8877
8999
  // package.json
8878
9000
  var package_default = {
8879
9001
  name: "oh-my-opencode",
8880
- version: "3.5.6",
9002
+ version: "3.7.0",
8881
9003
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8882
9004
  main: "dist/index.js",
8883
9005
  types: "dist/index.d.ts",
@@ -8951,13 +9073,13 @@ var package_default = {
8951
9073
  typescript: "^5.7.3"
8952
9074
  },
8953
9075
  optionalDependencies: {
8954
- "oh-my-opencode-darwin-arm64": "3.5.6",
8955
- "oh-my-opencode-darwin-x64": "3.5.6",
8956
- "oh-my-opencode-linux-arm64": "3.5.6",
8957
- "oh-my-opencode-linux-arm64-musl": "3.5.6",
8958
- "oh-my-opencode-linux-x64": "3.5.6",
8959
- "oh-my-opencode-linux-x64-musl": "3.5.6",
8960
- "oh-my-opencode-windows-x64": "3.5.6"
9076
+ "oh-my-opencode-darwin-arm64": "3.7.0",
9077
+ "oh-my-opencode-darwin-x64": "3.7.0",
9078
+ "oh-my-opencode-linux-arm64": "3.7.0",
9079
+ "oh-my-opencode-linux-arm64-musl": "3.7.0",
9080
+ "oh-my-opencode-linux-x64": "3.7.0",
9081
+ "oh-my-opencode-linux-x64-musl": "3.7.0",
9082
+ "oh-my-opencode-windows-x64": "3.7.0"
8961
9083
  },
8962
9084
  trustedDependencies: [
8963
9085
  "@ast-grep/cli",
@@ -10065,7 +10187,8 @@ function serializeError(error) {
10065
10187
  function getSessionTag(ctx, payload) {
10066
10188
  const props = payload.properties;
10067
10189
  const info = props?.info;
10068
- const sessionID = props?.sessionID ?? info?.sessionID;
10190
+ const part = props?.part;
10191
+ const sessionID = props?.sessionID ?? props?.sessionId ?? info?.sessionID ?? info?.sessionId ?? part?.sessionID ?? part?.sessionId;
10069
10192
  const isMainSession = sessionID === ctx.sessionID;
10070
10193
  if (isMainSession)
10071
10194
  return import_picocolors5.default.green("[MAIN]");
@@ -10086,9 +10209,9 @@ function logEventVerbose(ctx, payload) {
10086
10209
  case "message.part.updated": {
10087
10210
  const partProps = props;
10088
10211
  const part = partProps?.part;
10089
- if (part?.type === "tool-invocation") {
10090
- const toolPart = part;
10091
- console.error(import_picocolors5.default.dim(`${sessionTag} message.part (tool): ${toolPart.toolName} [${toolPart.state}]`));
10212
+ if (part?.type === "tool") {
10213
+ const status = part.state?.status ?? "unknown";
10214
+ console.error(import_picocolors5.default.dim(`${sessionTag} message.part (tool): ${part.tool ?? part.name ?? "?"} [${status}]`));
10092
10215
  } else if (part?.type === "text" && part.text) {
10093
10216
  const preview = part.text.slice(0, 80).replace(/\n/g, "\\n");
10094
10217
  console.error(import_picocolors5.default.dim(`${sessionTag} message.part (text): "${preview}${part.text.length > 80 ? "..." : ""}"`));
@@ -10145,11 +10268,20 @@ var import_picocolors7 = __toESM(require_picocolors(), 1);
10145
10268
 
10146
10269
  // src/cli/run/event-handlers.ts
10147
10270
  var import_picocolors6 = __toESM(require_picocolors(), 1);
10271
+ function getSessionId(props) {
10272
+ return props?.sessionID ?? props?.sessionId;
10273
+ }
10274
+ function getInfoSessionId(props) {
10275
+ return props?.info?.sessionID ?? props?.info?.sessionId;
10276
+ }
10277
+ function getPartSessionId(props) {
10278
+ return props?.part?.sessionID ?? props?.part?.sessionId;
10279
+ }
10148
10280
  function handleSessionIdle(ctx, payload, state) {
10149
10281
  if (payload.type !== "session.idle")
10150
10282
  return;
10151
10283
  const props = payload.properties;
10152
- if (props?.sessionID === ctx.sessionID) {
10284
+ if (getSessionId(props) === ctx.sessionID) {
10153
10285
  state.mainSessionIdle = true;
10154
10286
  }
10155
10287
  }
@@ -10157,7 +10289,7 @@ function handleSessionStatus(ctx, payload, state) {
10157
10289
  if (payload.type !== "session.status")
10158
10290
  return;
10159
10291
  const props = payload.properties;
10160
- if (props?.sessionID !== ctx.sessionID)
10292
+ if (getSessionId(props) !== ctx.sessionID)
10161
10293
  return;
10162
10294
  if (props?.status?.type === "busy") {
10163
10295
  state.mainSessionIdle = false;
@@ -10171,7 +10303,7 @@ function handleSessionError(ctx, payload, state) {
10171
10303
  if (payload.type !== "session.error")
10172
10304
  return;
10173
10305
  const props = payload.properties;
10174
- if (props?.sessionID === ctx.sessionID) {
10306
+ if (getSessionId(props) === ctx.sessionID) {
10175
10307
  state.mainSessionError = true;
10176
10308
  state.lastError = serializeError(props?.error);
10177
10309
  console.error(import_picocolors6.default.red(`
@@ -10182,11 +10314,11 @@ function handleMessagePartUpdated(ctx, payload, state) {
10182
10314
  if (payload.type !== "message.part.updated")
10183
10315
  return;
10184
10316
  const props = payload.properties;
10185
- if (props?.info?.sessionID !== ctx.sessionID)
10317
+ const partSid = getPartSessionId(props);
10318
+ const infoSid = getInfoSessionId(props);
10319
+ if ((partSid ?? infoSid) !== ctx.sessionID)
10186
10320
  return;
10187
- if (props?.info?.role !== "assistant")
10188
- return;
10189
- const part = props.part;
10321
+ const part = props?.part;
10190
10322
  if (!part)
10191
10323
  return;
10192
10324
  if (part.type === "text" && part.text) {
@@ -10197,12 +10329,53 @@ function handleMessagePartUpdated(ctx, payload, state) {
10197
10329
  }
10198
10330
  state.lastPartText = part.text;
10199
10331
  }
10332
+ if (part.type === "tool") {
10333
+ handleToolPart(ctx, part, state);
10334
+ }
10335
+ }
10336
+ function handleToolPart(_ctx, part, state) {
10337
+ const toolName = part.tool || part.name || "unknown";
10338
+ const status = part.state?.status;
10339
+ if (status === "running") {
10340
+ state.currentTool = toolName;
10341
+ let inputPreview = "";
10342
+ const input = part.state?.input;
10343
+ if (input) {
10344
+ if (input.command) {
10345
+ inputPreview = ` ${import_picocolors6.default.dim(String(input.command).slice(0, 60))}`;
10346
+ } else if (input.pattern) {
10347
+ inputPreview = ` ${import_picocolors6.default.dim(String(input.pattern).slice(0, 40))}`;
10348
+ } else if (input.filePath) {
10349
+ inputPreview = ` ${import_picocolors6.default.dim(String(input.filePath))}`;
10350
+ } else if (input.query) {
10351
+ inputPreview = ` ${import_picocolors6.default.dim(String(input.query).slice(0, 40))}`;
10352
+ }
10353
+ }
10354
+ state.hasReceivedMeaningfulWork = true;
10355
+ process.stdout.write(`
10356
+ ${import_picocolors6.default.cyan(">")} ${import_picocolors6.default.bold(toolName)}${inputPreview}
10357
+ `);
10358
+ }
10359
+ if (status === "completed" || status === "error") {
10360
+ const output = part.state?.output || "";
10361
+ const maxLen = 200;
10362
+ const preview = output.length > maxLen ? output.slice(0, maxLen) + "..." : output;
10363
+ if (preview.trim()) {
10364
+ const lines = preview.split(`
10365
+ `).slice(0, 3);
10366
+ process.stdout.write(import_picocolors6.default.dim(` \u2514\u2500 ${lines.join(`
10367
+ `)}
10368
+ `));
10369
+ }
10370
+ state.currentTool = null;
10371
+ state.lastPartText = "";
10372
+ }
10200
10373
  }
10201
10374
  function handleMessageUpdated(ctx, payload, state) {
10202
10375
  if (payload.type !== "message.updated")
10203
10376
  return;
10204
10377
  const props = payload.properties;
10205
- if (props?.info?.sessionID !== ctx.sessionID)
10378
+ if (getInfoSessionId(props) !== ctx.sessionID)
10206
10379
  return;
10207
10380
  if (props?.info?.role !== "assistant")
10208
10381
  return;
@@ -10214,7 +10387,7 @@ function handleToolExecute(ctx, payload, state) {
10214
10387
  if (payload.type !== "tool.execute")
10215
10388
  return;
10216
10389
  const props = payload.properties;
10217
- if (props?.sessionID !== ctx.sessionID)
10390
+ if (getSessionId(props) !== ctx.sessionID)
10218
10391
  return;
10219
10392
  const toolName = props?.name || "unknown";
10220
10393
  state.currentTool = toolName;
@@ -10240,7 +10413,7 @@ function handleToolResult(ctx, payload, state) {
10240
10413
  if (payload.type !== "tool.result")
10241
10414
  return;
10242
10415
  const props = payload.properties;
10243
- if (props?.sessionID !== ctx.sessionID)
10416
+ if (getSessionId(props) !== ctx.sessionID)
10244
10417
  return;
10245
10418
  const output = props?.output || "";
10246
10419
  const maxLen = 200;
@@ -10255,6 +10428,25 @@ function handleToolResult(ctx, payload, state) {
10255
10428
  state.currentTool = null;
10256
10429
  state.lastPartText = "";
10257
10430
  }
10431
+ function handleTuiToast(_ctx, payload, state) {
10432
+ if (payload.type !== "tui.toast.show")
10433
+ return;
10434
+ const props = payload.properties;
10435
+ const title = props?.title ? `${props.title}: ` : "";
10436
+ const message = props?.message?.trim();
10437
+ const variant = props?.variant ?? "info";
10438
+ if (!message)
10439
+ return;
10440
+ if (variant === "error") {
10441
+ state.mainSessionError = true;
10442
+ state.lastError = `${title}${message}`;
10443
+ console.error(import_picocolors6.default.red(`
10444
+ [tui.toast.error] ${state.lastError}`));
10445
+ return;
10446
+ }
10447
+ const colorize = variant === "warning" ? import_picocolors6.default.yellow : import_picocolors6.default.dim;
10448
+ console.log(colorize(`[toast:${variant}] ${title}${message}`));
10449
+ }
10258
10450
 
10259
10451
  // src/cli/run/event-stream-processor.ts
10260
10452
  async function processEvents(ctx, stream, state) {
@@ -10275,6 +10467,7 @@ async function processEvents(ctx, stream, state) {
10275
10467
  handleMessageUpdated(ctx, payload, state);
10276
10468
  handleToolExecute(ctx, payload, state);
10277
10469
  handleToolResult(ctx, payload, state);
10470
+ handleTuiToast(ctx, payload, state);
10278
10471
  } catch (err) {
10279
10472
  console.error(import_picocolors7.default.red(`[event error] ${err}`));
10280
10473
  }
@@ -22707,7 +22900,8 @@ var BackgroundTaskConfigSchema = exports_external.object({
22707
22900
  var BrowserAutomationProviderSchema = exports_external.enum([
22708
22901
  "playwright",
22709
22902
  "agent-browser",
22710
- "dev-browser"
22903
+ "dev-browser",
22904
+ "playwright-cli"
22711
22905
  ]);
22712
22906
  var BrowserAutomationConfigSchema = exports_external.object({
22713
22907
  provider: BrowserAutomationProviderSchema.default("playwright")
@@ -22806,7 +23000,8 @@ var ExperimentalConfigSchema = exports_external.object({
22806
23000
  dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
22807
23001
  task_system: exports_external.boolean().optional(),
22808
23002
  plugin_load_timeout_ms: exports_external.number().min(1000).optional(),
22809
- safe_hook_creation: exports_external.boolean().optional()
23003
+ safe_hook_creation: exports_external.boolean().optional(),
23004
+ hashline_edit: exports_external.boolean().optional()
22810
23005
  });
22811
23006
  // src/config/schema/git-master.ts
22812
23007
  var GitMasterConfigSchema = exports_external.object({
@@ -22856,7 +23051,8 @@ var HookNameSchema = exports_external.enum([
22856
23051
  "stop-continuation-guard",
22857
23052
  "tasks-todowrite-disabler",
22858
23053
  "write-existing-file-guard",
22859
- "anthropic-effort"
23054
+ "anthropic-effort",
23055
+ "hashline-read-enhancer"
22860
23056
  ]);
22861
23057
  // src/config/schema/notification.ts
22862
23058
  var NotificationConfigSchema = exports_external.object({
@@ -23004,7 +23200,7 @@ function parseConfigPartially(rawConfig) {
23004
23200
  }
23005
23201
  return partialConfig;
23006
23202
  }
23007
- function loadConfigFromPath(configPath, ctx) {
23203
+ function loadConfigFromPath(configPath, _ctx) {
23008
23204
  try {
23009
23205
  if (fs3.existsSync(configPath)) {
23010
23206
  const content = fs3.readFileSync(configPath, "utf-8");
@@ -24544,7 +24740,99 @@ async function createOpencode(options) {
24544
24740
  // src/cli/run/server-connection.ts
24545
24741
  init_port_utils();
24546
24742
  var import_picocolors8 = __toESM(require_picocolors(), 1);
24743
+
24744
+ // src/cli/run/opencode-binary-resolver.ts
24745
+ import { delimiter, dirname, join as join8 } from "path";
24746
+ var OPENCODE_COMMANDS = ["opencode", "opencode-desktop"];
24747
+ var WINDOWS_SUFFIXES = ["", ".exe", ".cmd", ".bat", ".ps1"];
24748
+ function getCommandCandidates(platform) {
24749
+ if (platform !== "win32")
24750
+ return [...OPENCODE_COMMANDS];
24751
+ return OPENCODE_COMMANDS.flatMap((command) => WINDOWS_SUFFIXES.map((suffix) => `${command}${suffix}`));
24752
+ }
24753
+ function collectCandidateBinaryPaths(pathEnv, which = Bun.which, platform = process.platform) {
24754
+ const seen = new Set;
24755
+ const candidates = [];
24756
+ const commandCandidates = getCommandCandidates(platform);
24757
+ const addCandidate = (binaryPath) => {
24758
+ if (!binaryPath || seen.has(binaryPath))
24759
+ return;
24760
+ seen.add(binaryPath);
24761
+ candidates.push(binaryPath);
24762
+ };
24763
+ for (const command of commandCandidates) {
24764
+ addCandidate(which(command));
24765
+ }
24766
+ for (const entry of (pathEnv ?? "").split(delimiter).filter(Boolean)) {
24767
+ for (const command of commandCandidates) {
24768
+ addCandidate(join8(entry, command));
24769
+ }
24770
+ }
24771
+ return candidates;
24772
+ }
24773
+ async function canExecuteBinary(binaryPath) {
24774
+ try {
24775
+ const proc = Bun.spawn([binaryPath, "--version"], {
24776
+ stdout: "pipe",
24777
+ stderr: "pipe"
24778
+ });
24779
+ await proc.exited;
24780
+ return proc.exitCode === 0;
24781
+ } catch {
24782
+ return false;
24783
+ }
24784
+ }
24785
+ async function findWorkingOpencodeBinary(pathEnv = process.env.PATH, probe = canExecuteBinary, which = Bun.which, platform = process.platform) {
24786
+ const candidates = collectCandidateBinaryPaths(pathEnv, which, platform);
24787
+ for (const candidate of candidates) {
24788
+ if (await probe(candidate)) {
24789
+ return candidate;
24790
+ }
24791
+ }
24792
+ return null;
24793
+ }
24794
+ function buildPathWithBinaryFirst(pathEnv, binaryPath) {
24795
+ const preferredDir = dirname(binaryPath);
24796
+ const existing = (pathEnv ?? "").split(delimiter).filter((entry) => entry.length > 0 && entry !== preferredDir);
24797
+ return [preferredDir, ...existing].join(delimiter);
24798
+ }
24799
+ async function withWorkingOpencodePath(startServer, finder = findWorkingOpencodeBinary) {
24800
+ const originalPath = process.env.PATH;
24801
+ const binaryPath = await finder(originalPath);
24802
+ if (!binaryPath) {
24803
+ return startServer();
24804
+ }
24805
+ process.env.PATH = buildPathWithBinaryFirst(originalPath, binaryPath);
24806
+ try {
24807
+ return await startServer();
24808
+ } finally {
24809
+ process.env.PATH = originalPath;
24810
+ }
24811
+ }
24812
+
24813
+ // src/cli/run/opencode-bin-path.ts
24814
+ import { delimiter as delimiter2, dirname as dirname2 } from "path";
24815
+ import { createRequire } from "module";
24816
+ var resolveFromCurrentModule = createRequire(import.meta.url).resolve;
24817
+ function prependResolvedOpencodeBinToPath(env = process.env, resolve2 = resolveFromCurrentModule) {
24818
+ let resolvedPath;
24819
+ try {
24820
+ resolvedPath = resolve2("opencode-ai/bin/opencode");
24821
+ } catch {
24822
+ return;
24823
+ }
24824
+ const opencodeBinDir = dirname2(resolvedPath);
24825
+ const currentPath = env.PATH ?? "";
24826
+ const pathSegments = currentPath ? currentPath.split(delimiter2) : [];
24827
+ if (pathSegments.includes(opencodeBinDir)) {
24828
+ return;
24829
+ }
24830
+ env.PATH = currentPath ? `${opencodeBinDir}${delimiter2}${currentPath}` : opencodeBinDir;
24831
+ }
24832
+
24833
+ // src/cli/run/server-connection.ts
24547
24834
  async function createServerConnection(options) {
24835
+ prependResolvedOpencodeBinToPath();
24548
24836
  const { port, attach, signal } = options;
24549
24837
  if (attach !== undefined) {
24550
24838
  console.log(import_picocolors8.default.dim("Attaching to existing server at"), import_picocolors8.default.cyan(attach));
@@ -24558,7 +24846,7 @@ async function createServerConnection(options) {
24558
24846
  const available = await isPortAvailable(port, "127.0.0.1");
24559
24847
  if (available) {
24560
24848
  console.log(import_picocolors8.default.dim("Starting server on port"), import_picocolors8.default.cyan(port.toString()));
24561
- const { client: client5, server: server3 } = await createOpencode({ signal, port, hostname: "127.0.0.1" });
24849
+ const { client: client5, server: server3 } = await withWorkingOpencodePath(() => createOpencode({ signal, port, hostname: "127.0.0.1" }));
24562
24850
  console.log(import_picocolors8.default.dim("Server listening at"), import_picocolors8.default.cyan(server3.url));
24563
24851
  return { client: client5, cleanup: () => server3.close() };
24564
24852
  }
@@ -24572,7 +24860,7 @@ async function createServerConnection(options) {
24572
24860
  } else {
24573
24861
  console.log(import_picocolors8.default.dim("Starting server on port"), import_picocolors8.default.cyan(selectedPort.toString()));
24574
24862
  }
24575
- const { client: client3, server: server2 } = await createOpencode({ signal, port: selectedPort, hostname: "127.0.0.1" });
24863
+ const { client: client3, server: server2 } = await withWorkingOpencodePath(() => createOpencode({ signal, port: selectedPort, hostname: "127.0.0.1" }));
24576
24864
  console.log(import_picocolors8.default.dim("Server listening at"), import_picocolors8.default.cyan(server2.url));
24577
24865
  return { client: client3, cleanup: () => server2.close() };
24578
24866
  }
@@ -24582,9 +24870,12 @@ var import_picocolors9 = __toESM(require_picocolors(), 1);
24582
24870
  var SESSION_CREATE_MAX_RETRIES = 3;
24583
24871
  var SESSION_CREATE_RETRY_DELAY_MS = 1000;
24584
24872
  async function resolveSession(options) {
24585
- const { client: client3, sessionId } = options;
24873
+ const { client: client3, sessionId, directory } = options;
24586
24874
  if (sessionId) {
24587
- const res = await client3.session.get({ path: { id: sessionId } });
24875
+ const res = await client3.session.get({
24876
+ path: { id: sessionId },
24877
+ query: { directory }
24878
+ });
24588
24879
  if (res.error || !res.data) {
24589
24880
  throw new Error(`Session not found: ${sessionId}`);
24590
24881
  }
@@ -24597,7 +24888,8 @@ async function resolveSession(options) {
24597
24888
  permission: [
24598
24889
  { permission: "question", action: "deny", pattern: "*" }
24599
24890
  ]
24600
- }
24891
+ },
24892
+ query: { directory }
24601
24893
  });
24602
24894
  if (res.error) {
24603
24895
  console.error(import_picocolors9.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
@@ -24684,6 +24976,7 @@ async function executeOnCompleteHook(options) {
24684
24976
  }
24685
24977
 
24686
24978
  // src/cli/run/agent-resolver.ts
24979
+ init_agent_display_names();
24687
24980
  var import_picocolors11 = __toESM(require_picocolors(), 1);
24688
24981
  var CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"];
24689
24982
  var DEFAULT_AGENT = "sisyphus";
@@ -24691,18 +24984,22 @@ var normalizeAgentName = (agent) => {
24691
24984
  if (!agent)
24692
24985
  return;
24693
24986
  const trimmed = agent.trim();
24694
- if (!trimmed)
24987
+ if (trimmed.length === 0)
24695
24988
  return;
24696
- const lowered = trimmed.toLowerCase();
24697
- const coreMatch = CORE_AGENT_ORDER.find((name) => name.toLowerCase() === lowered);
24698
- return coreMatch ?? trimmed;
24989
+ const configKey = getAgentConfigKey(trimmed);
24990
+ const displayName = getAgentDisplayName(configKey);
24991
+ const isKnownAgent = displayName !== configKey;
24992
+ return {
24993
+ configKey,
24994
+ resolvedName: isKnownAgent ? displayName : trimmed
24995
+ };
24699
24996
  };
24700
- var isAgentDisabled = (agent, config2) => {
24701
- const lowered = agent.toLowerCase();
24702
- if (lowered === "sisyphus" && config2.sisyphus_agent?.disabled === true) {
24997
+ var isAgentDisabled = (agentConfigKey, config2) => {
24998
+ const lowered = agentConfigKey.toLowerCase();
24999
+ if (lowered === DEFAULT_AGENT && config2.sisyphus_agent?.disabled === true) {
24703
25000
  return true;
24704
25001
  }
24705
- return (config2.disabled_agents ?? []).some((disabled) => disabled.toLowerCase() === lowered);
25002
+ return (config2.disabled_agents ?? []).some((disabled) => getAgentConfigKey(disabled) === lowered);
24706
25003
  };
24707
25004
  var pickFallbackAgent = (config2) => {
24708
25005
  for (const agent of CORE_AGENT_ORDER) {
@@ -24716,25 +25013,29 @@ var resolveRunAgent = (options, pluginConfig, env = process.env) => {
24716
25013
  const cliAgent = normalizeAgentName(options.agent);
24717
25014
  const envAgent = normalizeAgentName(env.OPENCODE_DEFAULT_AGENT);
24718
25015
  const configAgent = normalizeAgentName(pluginConfig.default_run_agent);
24719
- const resolved = cliAgent ?? envAgent ?? configAgent ?? DEFAULT_AGENT;
24720
- const normalized = normalizeAgentName(resolved) ?? DEFAULT_AGENT;
24721
- if (isAgentDisabled(normalized, pluginConfig)) {
25016
+ const resolved = cliAgent ?? envAgent ?? configAgent ?? {
25017
+ configKey: DEFAULT_AGENT,
25018
+ resolvedName: getAgentDisplayName(DEFAULT_AGENT)
25019
+ };
25020
+ if (isAgentDisabled(resolved.configKey, pluginConfig)) {
24722
25021
  const fallback = pickFallbackAgent(pluginConfig);
25022
+ const fallbackName = getAgentDisplayName(fallback);
24723
25023
  const fallbackDisabled = isAgentDisabled(fallback, pluginConfig);
24724
25024
  if (fallbackDisabled) {
24725
- console.log(import_picocolors11.default.yellow(`Requested agent "${normalized}" is disabled and no enabled core agent was found. Proceeding with "${fallback}".`));
24726
- return fallback;
25025
+ console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled and no enabled core agent was found. Proceeding with "${fallbackName}".`));
25026
+ return fallbackName;
24727
25027
  }
24728
- console.log(import_picocolors11.default.yellow(`Requested agent "${normalized}" is disabled. Falling back to "${fallback}".`));
24729
- return fallback;
25028
+ console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled. Falling back to "${fallbackName}".`));
25029
+ return fallbackName;
24730
25030
  }
24731
- return normalized;
25031
+ return resolved.resolvedName;
24732
25032
  };
24733
25033
 
24734
25034
  // src/cli/run/poll-for-completion.ts
24735
25035
  var import_picocolors13 = __toESM(require_picocolors(), 1);
24736
25036
 
24737
25037
  // src/cli/run/completion.ts
25038
+ init_shared();
24738
25039
  var import_picocolors12 = __toESM(require_picocolors(), 1);
24739
25040
  async function checkCompletionConditions(ctx) {
24740
25041
  try {
@@ -24751,8 +25052,11 @@ async function checkCompletionConditions(ctx) {
24751
25052
  }
24752
25053
  }
24753
25054
  async function areAllTodosComplete(ctx) {
24754
- const todosRes = await ctx.client.session.todo({ path: { id: ctx.sessionID } });
24755
- const todos = todosRes.data ?? [];
25055
+ const todosRes = await ctx.client.session.todo({
25056
+ path: { id: ctx.sessionID },
25057
+ query: { directory: ctx.directory }
25058
+ });
25059
+ const todos = normalizeSDKResponse(todosRes, []);
24756
25060
  const incompleteTodos = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
24757
25061
  if (incompleteTodos.length > 0) {
24758
25062
  console.log(import_picocolors12.default.dim(` Waiting: ${incompleteTodos.length} todos remaining`));
@@ -24765,14 +25069,17 @@ async function areAllChildrenIdle(ctx) {
24765
25069
  return areAllDescendantsIdle(ctx, ctx.sessionID, allStatuses);
24766
25070
  }
24767
25071
  async function fetchAllStatuses(ctx) {
24768
- const statusRes = await ctx.client.session.status();
24769
- return statusRes.data ?? {};
25072
+ const statusRes = await ctx.client.session.status({
25073
+ query: { directory: ctx.directory }
25074
+ });
25075
+ return normalizeSDKResponse(statusRes, {});
24770
25076
  }
24771
25077
  async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
24772
25078
  const childrenRes = await ctx.client.session.children({
24773
- path: { id: sessionID }
25079
+ path: { id: sessionID },
25080
+ query: { directory: ctx.directory }
24774
25081
  });
24775
- const children = childrenRes.data ?? [];
25082
+ const children = normalizeSDKResponse(childrenRes, []);
24776
25083
  for (const child of children) {
24777
25084
  const status = allStatuses[child.id];
24778
25085
  if (status && status.type !== "idle") {
@@ -24788,6 +25095,7 @@ async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
24788
25095
  }
24789
25096
 
24790
25097
  // src/cli/run/poll-for-completion.ts
25098
+ init_shared();
24791
25099
  var DEFAULT_POLL_INTERVAL_MS = 500;
24792
25100
  var DEFAULT_REQUIRED_CONSECUTIVE = 3;
24793
25101
  var ERROR_GRACE_CYCLES = 3;
@@ -24799,6 +25107,7 @@ async function pollForCompletion(ctx, eventState, abortController, options = {})
24799
25107
  let consecutiveCompleteChecks = 0;
24800
25108
  let errorCycleCount = 0;
24801
25109
  let firstWorkTimestamp = null;
25110
+ const pollStartTimestamp = Date.now();
24802
25111
  while (!abortController.signal.aborted) {
24803
25112
  await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
24804
25113
  if (eventState.mainSessionError) {
@@ -24814,6 +25123,12 @@ Session ended with error: ${eventState.lastError}`));
24814
25123
  } else {
24815
25124
  errorCycleCount = 0;
24816
25125
  }
25126
+ const mainSessionStatus = await getMainSessionStatus(ctx);
25127
+ if (mainSessionStatus === "busy" || mainSessionStatus === "retry") {
25128
+ eventState.mainSessionIdle = false;
25129
+ } else if (mainSessionStatus === "idle") {
25130
+ eventState.mainSessionIdle = true;
25131
+ }
24817
25132
  if (!eventState.mainSessionIdle) {
24818
25133
  consecutiveCompleteChecks = 0;
24819
25134
  continue;
@@ -24823,8 +25138,11 @@ Session ended with error: ${eventState.lastError}`));
24823
25138
  continue;
24824
25139
  }
24825
25140
  if (!eventState.hasReceivedMeaningfulWork) {
25141
+ if (Date.now() - pollStartTimestamp < minStabilizationMs) {
25142
+ consecutiveCompleteChecks = 0;
25143
+ continue;
25144
+ }
24826
25145
  consecutiveCompleteChecks = 0;
24827
- continue;
24828
25146
  }
24829
25147
  if (firstWorkTimestamp === null) {
24830
25148
  firstWorkTimestamp = Date.now();
@@ -24848,6 +25166,21 @@ All tasks completed.`));
24848
25166
  }
24849
25167
  return 130;
24850
25168
  }
25169
+ async function getMainSessionStatus(ctx) {
25170
+ try {
25171
+ const statusesRes = await ctx.client.session.status({
25172
+ query: { directory: ctx.directory }
25173
+ });
25174
+ const statuses = normalizeSDKResponse(statusesRes, {});
25175
+ const status = statuses[ctx.sessionID]?.type;
25176
+ if (status === "idle" || status === "busy" || status === "retry") {
25177
+ return status;
25178
+ }
25179
+ return null;
25180
+ } catch {
25181
+ return null;
25182
+ }
25183
+ }
24851
25184
 
24852
25185
  // src/cli/run/runner.ts
24853
25186
  var DEFAULT_TIMEOUT_MS = 600000;
@@ -24903,7 +25236,8 @@ Interrupted. Shutting down...`));
24903
25236
  try {
24904
25237
  const sessionID = await resolveSession({
24905
25238
  client: client3,
24906
- sessionId: options.sessionId
25239
+ sessionId: options.sessionId,
25240
+ directory
24907
25241
  });
24908
25242
  console.log(import_picocolors14.default.dim(`Session: ${sessionID}`));
24909
25243
  const ctx = { client: client3, sessionID, directory, abortController };
@@ -25154,24 +25488,24 @@ import { existsSync as existsSync19, readFileSync as readFileSync20 } from "fs";
25154
25488
  // src/cli/doctor/checks/system-binary.ts
25155
25489
  import { existsSync as existsSync16 } from "fs";
25156
25490
  import { homedir as homedir5 } from "os";
25157
- import { join as join12 } from "path";
25491
+ import { join as join13 } from "path";
25158
25492
  function getDesktopAppPaths(platform) {
25159
25493
  const home = homedir5();
25160
25494
  switch (platform) {
25161
25495
  case "darwin":
25162
25496
  return [
25163
25497
  "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
25164
- join12(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
25498
+ join13(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
25165
25499
  ];
25166
25500
  case "win32": {
25167
25501
  const programFiles = process.env.ProgramFiles;
25168
25502
  const localAppData = process.env.LOCALAPPDATA;
25169
25503
  const paths = [];
25170
25504
  if (programFiles) {
25171
- paths.push(join12(programFiles, "OpenCode", "OpenCode.exe"));
25505
+ paths.push(join13(programFiles, "OpenCode", "OpenCode.exe"));
25172
25506
  }
25173
25507
  if (localAppData) {
25174
- paths.push(join12(localAppData, "OpenCode", "OpenCode.exe"));
25508
+ paths.push(join13(localAppData, "OpenCode", "OpenCode.exe"));
25175
25509
  }
25176
25510
  return paths;
25177
25511
  }
@@ -25179,8 +25513,8 @@ function getDesktopAppPaths(platform) {
25179
25513
  return [
25180
25514
  "/usr/bin/opencode",
25181
25515
  "/usr/lib/opencode/opencode",
25182
- join12(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
25183
- join12(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
25516
+ join13(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
25517
+ join13(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
25184
25518
  ];
25185
25519
  default:
25186
25520
  return [];
@@ -25320,21 +25654,21 @@ init_checker();
25320
25654
  init_auto_update_checker();
25321
25655
  import { existsSync as existsSync18, readFileSync as readFileSync19 } from "fs";
25322
25656
  import { homedir as homedir6 } from "os";
25323
- import { join as join13 } from "path";
25657
+ import { join as join14 } from "path";
25324
25658
  init_shared();
25325
25659
  function getPlatformDefaultCacheDir(platform = process.platform) {
25326
25660
  if (platform === "darwin")
25327
- return join13(homedir6(), "Library", "Caches");
25661
+ return join14(homedir6(), "Library", "Caches");
25328
25662
  if (platform === "win32")
25329
- return process.env.LOCALAPPDATA ?? join13(homedir6(), "AppData", "Local");
25330
- return join13(homedir6(), ".cache");
25663
+ return process.env.LOCALAPPDATA ?? join14(homedir6(), "AppData", "Local");
25664
+ return join14(homedir6(), ".cache");
25331
25665
  }
25332
25666
  function resolveOpenCodeCacheDir() {
25333
25667
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
25334
25668
  if (xdgCacheHome)
25335
- return join13(xdgCacheHome, "opencode");
25669
+ return join14(xdgCacheHome, "opencode");
25336
25670
  const fromShared = getOpenCodeCacheDir();
25337
- const platformDefault = join13(getPlatformDefaultCacheDir(), "opencode");
25671
+ const platformDefault = join14(getPlatformDefaultCacheDir(), "opencode");
25338
25672
  if (existsSync18(fromShared) || !existsSync18(platformDefault))
25339
25673
  return fromShared;
25340
25674
  return platformDefault;
@@ -25357,8 +25691,8 @@ function normalizeVersion(value) {
25357
25691
  }
25358
25692
  function getLoadedPluginVersion() {
25359
25693
  const cacheDir = resolveOpenCodeCacheDir();
25360
- const cachePackagePath = join13(cacheDir, "package.json");
25361
- const installedPackagePath = join13(cacheDir, "node_modules", PACKAGE_NAME4, "package.json");
25694
+ const cachePackagePath = join14(cacheDir, "package.json");
25695
+ const installedPackagePath = join14(cacheDir, "node_modules", PACKAGE_NAME4, "package.json");
25362
25696
  const cachePackage = readPackageJson(cachePackagePath);
25363
25697
  const installedPackage = readPackageJson(installedPackagePath);
25364
25698
  const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME4]);
@@ -25487,22 +25821,22 @@ async function checkSystem() {
25487
25821
 
25488
25822
  // src/cli/doctor/checks/config.ts
25489
25823
  import { readFileSync as readFileSync23 } from "fs";
25490
- import { join as join17 } from "path";
25824
+ import { join as join18 } from "path";
25491
25825
  init_shared();
25492
25826
 
25493
25827
  // src/cli/doctor/checks/model-resolution-cache.ts
25494
25828
  init_shared();
25495
25829
  import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
25496
25830
  import { homedir as homedir7 } from "os";
25497
- import { join as join14 } from "path";
25831
+ import { join as join15 } from "path";
25498
25832
  function getOpenCodeCacheDir2() {
25499
25833
  const xdgCache = process.env.XDG_CACHE_HOME;
25500
25834
  if (xdgCache)
25501
- return join14(xdgCache, "opencode");
25502
- return join14(homedir7(), ".cache", "opencode");
25835
+ return join15(xdgCache, "opencode");
25836
+ return join15(homedir7(), ".cache", "opencode");
25503
25837
  }
25504
25838
  function loadAvailableModelsFromCache() {
25505
- const cacheFile = join14(getOpenCodeCacheDir2(), "models.json");
25839
+ const cacheFile = join15(getOpenCodeCacheDir2(), "models.json");
25506
25840
  if (!existsSync20(cacheFile)) {
25507
25841
  return { providers: [], modelCount: 0, cacheExists: false };
25508
25842
  }
@@ -25529,10 +25863,10 @@ init_model_requirements();
25529
25863
  // src/cli/doctor/checks/model-resolution-config.ts
25530
25864
  init_shared();
25531
25865
  import { readFileSync as readFileSync22 } from "fs";
25532
- import { join as join15 } from "path";
25866
+ import { join as join16 } from "path";
25533
25867
  var PACKAGE_NAME5 = "oh-my-opencode";
25534
- var USER_CONFIG_BASE = join15(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, PACKAGE_NAME5);
25535
- var PROJECT_CONFIG_BASE = join15(process.cwd(), ".opencode", PACKAGE_NAME5);
25868
+ var USER_CONFIG_BASE = join16(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, PACKAGE_NAME5);
25869
+ var PROJECT_CONFIG_BASE = join16(process.cwd(), ".opencode", PACKAGE_NAME5);
25536
25870
  function loadOmoConfig() {
25537
25871
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE);
25538
25872
  if (projectDetected.format !== "none") {
@@ -25557,7 +25891,7 @@ function loadOmoConfig() {
25557
25891
 
25558
25892
  // src/cli/doctor/checks/model-resolution-details.ts
25559
25893
  init_shared();
25560
- import { join as join16 } from "path";
25894
+ import { join as join17 } from "path";
25561
25895
 
25562
25896
  // src/cli/doctor/checks/model-resolution-variant.ts
25563
25897
  function formatModelWithVariant(model, variant) {
@@ -25596,7 +25930,7 @@ function getCategoryEffectiveVariant(categoryName, requirement, config2) {
25596
25930
  // src/cli/doctor/checks/model-resolution-details.ts
25597
25931
  function buildModelResolutionDetails(options) {
25598
25932
  const details = [];
25599
- const cacheFile = join16(getOpenCodeCacheDir(), "models.json");
25933
+ const cacheFile = join17(getOpenCodeCacheDir(), "models.json");
25600
25934
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
25601
25935
  details.push("");
25602
25936
  if (options.available.cacheExists) {
@@ -25708,8 +26042,8 @@ async function checkModels() {
25708
26042
  }
25709
26043
 
25710
26044
  // src/cli/doctor/checks/config.ts
25711
- var USER_CONFIG_BASE2 = join17(getOpenCodeConfigDir({ binary: "opencode" }), PACKAGE_NAME4);
25712
- var PROJECT_CONFIG_BASE2 = join17(process.cwd(), ".opencode", PACKAGE_NAME4);
26045
+ var USER_CONFIG_BASE2 = join18(getOpenCodeConfigDir({ binary: "opencode" }), PACKAGE_NAME4);
26046
+ var PROJECT_CONFIG_BASE2 = join18(process.cwd(), ".opencode", PACKAGE_NAME4);
25713
26047
  function findConfigPath() {
25714
26048
  const projectConfig = detectConfigFile(PROJECT_CONFIG_BASE2);
25715
26049
  if (projectConfig.format !== "none")
@@ -25829,8 +26163,8 @@ async function checkConfig() {
25829
26163
 
25830
26164
  // src/cli/doctor/checks/dependencies.ts
25831
26165
  import { existsSync as existsSync21 } from "fs";
25832
- import { createRequire } from "module";
25833
- import { dirname as dirname3, join as join18 } from "path";
26166
+ import { createRequire as createRequire2 } from "module";
26167
+ import { dirname as dirname5, join as join19 } from "path";
25834
26168
  async function checkBinaryExists(binary2) {
25835
26169
  try {
25836
26170
  const path9 = Bun.which(binary2);
@@ -25887,11 +26221,11 @@ async function checkAstGrepNapi() {
25887
26221
  };
25888
26222
  } catch {
25889
26223
  const { existsSync: existsSync22 } = await import("fs");
25890
- const { join: join19 } = await import("path");
26224
+ const { join: join20 } = await import("path");
25891
26225
  const { homedir: homedir8 } = await import("os");
25892
26226
  const pathsToCheck = [
25893
- join19(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
25894
- join19(process.cwd(), "node_modules", "@ast-grep", "napi")
26227
+ join20(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
26228
+ join20(process.cwd(), "node_modules", "@ast-grep", "napi")
25895
26229
  ];
25896
26230
  for (const napiPath of pathsToCheck) {
25897
26231
  if (existsSync22(napiPath)) {
@@ -25917,9 +26251,9 @@ async function checkAstGrepNapi() {
25917
26251
  function findCommentCheckerPackageBinary() {
25918
26252
  const binaryName = process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
25919
26253
  try {
25920
- const require2 = createRequire(import.meta.url);
26254
+ const require2 = createRequire2(import.meta.url);
25921
26255
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
25922
- const binaryPath = join18(dirname3(pkgPath), "bin", binaryName);
26256
+ const binaryPath = join19(dirname5(pkgPath), "bin", binaryName);
25923
26257
  if (existsSync21(binaryPath))
25924
26258
  return binaryPath;
25925
26259
  } catch {}
@@ -26039,7 +26373,7 @@ init_jsonc_parser();
26039
26373
  // src/tools/lsp/server-installation.ts
26040
26374
  init_shared();
26041
26375
  import { existsSync as existsSync22 } from "fs";
26042
- import { join as join19 } from "path";
26376
+ import { join as join20 } from "path";
26043
26377
  function isServerInstalled(command) {
26044
26378
  if (command.length === 0)
26045
26379
  return false;
@@ -26067,23 +26401,23 @@ function isServerInstalled(command) {
26067
26401
  const paths = pathEnv.split(pathSeparator);
26068
26402
  for (const p2 of paths) {
26069
26403
  for (const suffix of exts) {
26070
- if (existsSync22(join19(p2, cmd + suffix))) {
26404
+ if (existsSync22(join20(p2, cmd + suffix))) {
26071
26405
  return true;
26072
26406
  }
26073
26407
  }
26074
26408
  }
26075
26409
  const cwd = process.cwd();
26076
26410
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
26077
- const dataDir = join19(getDataDir(), "opencode");
26411
+ const dataDir = join20(getDataDir(), "opencode");
26078
26412
  const additionalBases = [
26079
- join19(cwd, "node_modules", ".bin"),
26080
- join19(configDir, "bin"),
26081
- join19(configDir, "node_modules", ".bin"),
26082
- join19(dataDir, "bin")
26413
+ join20(cwd, "node_modules", ".bin"),
26414
+ join20(configDir, "bin"),
26415
+ join20(configDir, "node_modules", ".bin"),
26416
+ join20(dataDir, "bin")
26083
26417
  ];
26084
26418
  for (const base of additionalBases) {
26085
26419
  for (const suffix of exts) {
26086
- if (existsSync22(join19(base, cmd + suffix))) {
26420
+ if (existsSync22(join20(base, cmd + suffix))) {
26087
26421
  return true;
26088
26422
  }
26089
26423
  }
@@ -26119,13 +26453,13 @@ function getLspServerStats(servers) {
26119
26453
  init_shared();
26120
26454
  import { existsSync as existsSync23, readFileSync as readFileSync24 } from "fs";
26121
26455
  import { homedir as homedir8 } from "os";
26122
- import { join as join20 } from "path";
26456
+ import { join as join21 } from "path";
26123
26457
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
26124
26458
  function getMcpConfigPaths() {
26125
26459
  return [
26126
- join20(homedir8(), ".claude", ".mcp.json"),
26127
- join20(process.cwd(), ".mcp.json"),
26128
- join20(process.cwd(), ".claude", ".mcp.json")
26460
+ join21(homedir8(), ".claude", ".mcp.json"),
26461
+ join21(process.cwd(), ".mcp.json"),
26462
+ join21(process.cwd(), ".claude", ".mcp.json")
26129
26463
  ];
26130
26464
  }
26131
26465
  function loadUserMcpConfig() {
@@ -26537,10 +26871,10 @@ async function doctor(options = { mode: "default" }) {
26537
26871
  // src/features/mcp-oauth/storage.ts
26538
26872
  init_shared();
26539
26873
  import { chmodSync, existsSync as existsSync24, mkdirSync as mkdirSync3, readFileSync as readFileSync25, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
26540
- import { dirname as dirname4, join as join21 } from "path";
26874
+ import { dirname as dirname6, join as join22 } from "path";
26541
26875
  var STORAGE_FILE_NAME = "mcp-oauth.json";
26542
26876
  function getMcpOauthStoragePath() {
26543
- return join21(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
26877
+ return join22(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
26544
26878
  }
26545
26879
  function normalizeHost(serverHost) {
26546
26880
  let host = serverHost.trim();
@@ -26590,7 +26924,7 @@ function readStore() {
26590
26924
  function writeStore(store) {
26591
26925
  const filePath = getMcpOauthStoragePath();
26592
26926
  try {
26593
- const dir = dirname4(filePath);
26927
+ const dir = dirname6(filePath);
26594
26928
  if (!existsSync24(dir)) {
26595
26929
  mkdirSync3(dir, { recursive: true });
26596
26930
  }
@@ -26782,7 +27116,7 @@ async function getOrRegisterClient(options) {
26782
27116
  }
26783
27117
  }
26784
27118
  function parseRegistrationResponse(data) {
26785
- if (!isRecord(data))
27119
+ if (!isRecord2(data))
26786
27120
  return null;
26787
27121
  const clientId = data.client_id;
26788
27122
  if (typeof clientId !== "string" || clientId.length === 0)
@@ -26793,7 +27127,7 @@ function parseRegistrationResponse(data) {
26793
27127
  }
26794
27128
  return { clientId };
26795
27129
  }
26796
- function isRecord(value) {
27130
+ function isRecord2(value) {
26797
27131
  return typeof value === "object" && value !== null;
26798
27132
  }
26799
27133