oh-my-opencode 4.5.12 → 4.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 (189) hide show
  1. package/.agents/skills/opencode-qa/SKILL.md +194 -0
  2. package/.agents/skills/opencode-qa/references/cli-commands.md +188 -0
  3. package/.agents/skills/opencode-qa/references/db-investigation.md +197 -0
  4. package/.agents/skills/opencode-qa/references/events-hooks.md +110 -0
  5. package/.agents/skills/opencode-qa/references/sdk.md +96 -0
  6. package/.agents/skills/opencode-qa/references/server-api.md +200 -0
  7. package/.agents/skills/opencode-qa/references/testing-harness.md +218 -0
  8. package/.agents/skills/opencode-qa/references/tui-tmux.md +52 -0
  9. package/.agents/skills/opencode-qa/scripts/db-session-by-id.sh +53 -0
  10. package/.agents/skills/opencode-qa/scripts/db-session-by-name.sh +57 -0
  11. package/.agents/skills/opencode-qa/scripts/db-session-by-text.sh +158 -0
  12. package/.agents/skills/opencode-qa/scripts/export-roundtrip.sh +57 -0
  13. package/.agents/skills/opencode-qa/scripts/lib/common.sh +216 -0
  14. package/.agents/skills/opencode-qa/scripts/server-smoke.sh +64 -0
  15. package/.agents/skills/opencode-qa/scripts/sse-hook-probe.sh +106 -0
  16. package/.agents/skills/opencode-qa/scripts/tui-smoke.sh +89 -0
  17. package/README.ja.md +13 -3
  18. package/README.ko.md +13 -3
  19. package/README.md +24 -14
  20. package/README.ru.md +13 -3
  21. package/README.zh-cn.md +13 -3
  22. package/bin/oh-my-opencode.js +4 -3
  23. package/bin/oh-my-opencode.test.ts +35 -7
  24. package/bin/platform.d.ts +1 -1
  25. package/bin/platform.js +4 -4
  26. package/bin/platform.test.ts +31 -9
  27. package/bin/version-mismatch.js +47 -0
  28. package/bin/version-mismatch.test.ts +120 -0
  29. package/dist/cli/cleanup-command.d.ts +4 -0
  30. package/dist/cli/cleanup.d.ts +11 -0
  31. package/dist/cli/cli-program.d.ts +2 -1
  32. package/dist/cli/codex-ulw-loop.d.ts +12 -0
  33. package/dist/cli/doctor/checks/tui-plugin-config.d.ts +2 -0
  34. package/dist/cli/index.js +2189 -529
  35. package/dist/cli/install-codex/codex-cache.d.ts +1 -0
  36. package/dist/cli/install-codex/codex-cleanup-config.d.ts +6 -0
  37. package/dist/cli/install-codex/codex-cleanup.d.ts +21 -0
  38. package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -0
  39. package/dist/cli/install-codex/codex-config-reasoning.d.ts +2 -0
  40. package/dist/cli/install-codex/codex-config-toml.d.ts +2 -1
  41. package/dist/cli/install-codex/codex-installation-detection.d.ts +36 -0
  42. package/dist/cli/install-codex/codex-model-catalog.d.ts +13 -0
  43. package/dist/cli/install-codex/codex-package-layout.d.ts +1 -0
  44. package/dist/cli/install-codex/codex-project-local-cleanup-best-effort.d.ts +7 -0
  45. package/dist/cli/install-codex/codex-project-local-cleanup.d.ts +35 -0
  46. package/dist/cli/install-codex/git-bash.d.ts +35 -0
  47. package/dist/cli/install-codex/index.d.ts +4 -0
  48. package/dist/cli/install-codex/toml-section-editor.d.ts +2 -0
  49. package/dist/cli/install-codex/types.d.ts +20 -0
  50. package/dist/cli/run/event-state.d.ts +1 -0
  51. package/dist/cli/run/poll-for-completion.d.ts +1 -0
  52. package/dist/cli/run/prompt-start.d.ts +7 -0
  53. package/dist/cli/star-request.d.ts +9 -0
  54. package/dist/config/schema/hooks.d.ts +0 -1
  55. package/dist/create-hooks.d.ts +0 -1
  56. package/dist/features/background-agent/concurrency.d.ts +1 -0
  57. package/dist/features/background-agent/process-cleanup.d.ts +6 -0
  58. package/dist/features/builtin-skills/skills/debugging.d.ts +2 -0
  59. package/dist/features/builtin-skills/skills/index.d.ts +1 -0
  60. package/dist/features/claude-code-session-state/state.d.ts +1 -0
  61. package/dist/features/opencode-skill-loader/index.d.ts +1 -0
  62. package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +5 -0
  63. package/dist/features/tmux-subagent/attachable-session-status.d.ts +1 -1
  64. package/dist/features/tmux-subagent/session-status-parser.d.ts +1 -0
  65. package/dist/hooks/comment-checker/cli.d.ts +1 -0
  66. package/dist/hooks/index.d.ts +0 -1
  67. package/dist/hooks/tasks-todowrite-disabler/constants.d.ts +1 -1
  68. package/dist/index.js +1077 -563
  69. package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
  70. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  71. package/dist/plugin/messages-transform.d.ts +8 -1
  72. package/dist/plugin/user-abort-interrupted-recovery-guard.d.ts +6 -0
  73. package/dist/shared/command-executor/execute-hook-command.d.ts +2 -0
  74. package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +14 -0
  75. package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +7 -0
  76. package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +1 -0
  77. package/dist/shared/prompt-async-gate/timing.d.ts +1 -0
  78. package/dist/shared/prompt-async-gate/types.d.ts +2 -0
  79. package/dist/shared/prompt-async-gate.d.ts +1 -1
  80. package/dist/tools/skill/description-formatter.d.ts +5 -1
  81. package/dist/tools/skill/types.d.ts +1 -0
  82. package/package.json +22 -18
  83. package/packages/ast-grep-mcp/dist/cli.js +53 -9
  84. package/packages/git-bash-mcp/dist/cli.js +367 -0
  85. package/packages/lsp-tools-mcp/dist/lsp/process.js +1 -1
  86. package/packages/omo-codex/plugin/.mcp.json +11 -0
  87. package/packages/omo-codex/plugin/components/comment-checker/README.md +1 -1
  88. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +29 -0
  89. package/packages/omo-codex/plugin/components/git-bash/package.json +23 -0
  90. package/packages/omo-codex/plugin/components/git-bash/src/cli.ts +33 -0
  91. package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +180 -0
  92. package/packages/omo-codex/plugin/components/git-bash/src/index.ts +10 -0
  93. package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +195 -0
  94. package/packages/omo-codex/plugin/components/git-bash/tsconfig.build.json +13 -0
  95. package/packages/omo-codex/plugin/components/git-bash/tsconfig.json +25 -0
  96. package/packages/omo-codex/plugin/components/lsp/README.md +1 -1
  97. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +5 -5
  98. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +33 -0
  99. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +19 -27
  100. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-cli.test.ts +28 -0
  101. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-errors.test.ts +55 -0
  102. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +7 -5
  103. package/packages/omo-codex/plugin/components/rules/README.md +1 -1
  104. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +6 -4
  105. package/packages/omo-codex/plugin/components/rules/bundled-rules/windows-git-bash.md +10 -0
  106. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +0 -2
  107. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +3 -1
  108. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +97 -0
  109. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +6 -5
  110. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +22 -0
  111. package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +1 -1
  112. package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
  113. package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +4 -1
  114. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +8 -7
  115. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +9 -8
  116. package/packages/omo-codex/plugin/components/ultrawork/directive.md +32 -6
  117. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +27 -4
  118. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +25 -0
  119. package/packages/omo-codex/plugin/components/ulw-loop/README.md +1 -1
  120. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +28 -205
  121. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +231 -0
  122. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +12 -1
  123. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +19 -1
  124. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +102 -5
  125. package/packages/omo-codex/plugin/hooks/hooks.json +35 -2
  126. package/packages/omo-codex/plugin/model-catalog.json +49 -0
  127. package/packages/omo-codex/plugin/package-lock.json +19 -0
  128. package/packages/omo-codex/plugin/package.json +3 -1
  129. package/packages/omo-codex/plugin/scripts/auto-update.mjs +159 -0
  130. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +16 -1
  131. package/packages/omo-codex/plugin/scripts/build-components.mjs +2 -1
  132. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +269 -0
  133. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +89 -0
  134. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -6
  135. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +6 -6
  136. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +127 -0
  137. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +9 -0
  138. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +6 -6
  139. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +6 -6
  140. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +33 -8
  141. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +25 -5
  142. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +28 -205
  143. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +231 -0
  144. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +17 -17
  145. package/packages/omo-codex/plugin/test/aggregate.test.mjs +188 -20
  146. package/packages/omo-codex/plugin/test/auto-update.test.mjs +129 -0
  147. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +58 -11
  148. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +34 -0
  149. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +21 -0
  150. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +146 -0
  151. package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +48 -0
  152. package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +76 -0
  153. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +67 -0
  154. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +54 -2
  155. package/packages/omo-codex/scripts/install/cache.mjs +5 -3
  156. package/packages/omo-codex/scripts/install/cli-args.mjs +112 -0
  157. package/packages/omo-codex/scripts/install/config.mjs +23 -1
  158. package/packages/omo-codex/scripts/install/delegated-command.mjs +25 -0
  159. package/packages/omo-codex/scripts/install/git-bash.mjs +99 -0
  160. package/packages/omo-codex/scripts/install/git-bash.test.mjs +174 -0
  161. package/packages/omo-codex/scripts/install/legacy-bins.mjs +1 -0
  162. package/packages/omo-codex/scripts/install/mcp-runtime-cache.mjs +5 -1
  163. package/packages/omo-codex/scripts/install/model-catalog.mjs +66 -0
  164. package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +7 -1
  165. package/packages/omo-codex/scripts/install/permissions.d.mts +1 -0
  166. package/packages/omo-codex/scripts/install/permissions.mjs +26 -0
  167. package/packages/omo-codex/scripts/install/project-local-cleanup.mjs +229 -0
  168. package/packages/omo-codex/scripts/install/reasoning-config.mjs +72 -0
  169. package/packages/omo-codex/scripts/install/source-package-build.mjs +20 -0
  170. package/packages/omo-codex/scripts/install/toml-editor.mjs +19 -2
  171. package/packages/omo-codex/scripts/install-bin-links.test.mjs +23 -0
  172. package/packages/omo-codex/scripts/install-cli-args.test.mjs +146 -0
  173. package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +48 -0
  174. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +141 -0
  175. package/packages/omo-codex/scripts/install-config.test.mjs +205 -0
  176. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +157 -0
  177. package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +145 -0
  178. package/packages/omo-codex/scripts/install-local.mjs +91 -8
  179. package/packages/omo-codex/scripts/install-local.test.mjs +15 -0
  180. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +60 -0
  181. package/packages/omo-codex/scripts/install-packaged-local.test.mjs +67 -0
  182. package/packages/omo-codex/scripts/install-project-local-cleanup.test.mjs +277 -0
  183. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +127 -0
  184. package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +9 -0
  185. package/packages/shared-skills/skills/review-work/SKILL.md +33 -8
  186. package/packages/shared-skills/skills/start-work/SKILL.md +25 -5
  187. package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -11
  188. package/postinstall.mjs +36 -3
  189. package/dist/hooks/context-window-monitor.d.ts +0 -19
package/dist/index.js CHANGED
@@ -4503,6 +4503,7 @@ import { spawn } from "child_process";
4503
4503
  async function executeHookCommand(command, stdin, cwd, options) {
4504
4504
  const home = getHomeDirectory();
4505
4505
  const timeoutMs = options?.timeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS;
4506
+ const killGraceMs = options?.killGraceMs ?? SIGKILL_GRACE_MS;
4506
4507
  const expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd);
4507
4508
  let finalCommand = expandedCommand;
4508
4509
  if (options?.forceZsh) {
@@ -4519,6 +4520,7 @@ async function executeHookCommand(command, stdin, cwd, options) {
4519
4520
  }
4520
4521
  return new Promise((resolve2) => {
4521
4522
  let settled = false;
4523
+ let timedOut = false;
4522
4524
  let killTimer = null;
4523
4525
  const isWin32 = process.platform === "win32";
4524
4526
  const PROTECTED_ENV_KEYS = new Set(["HOME", "CLAUDE_PROJECT_DIR"]);
@@ -4566,6 +4568,15 @@ async function executeHookCommand(command, stdin, cwd, options) {
4566
4568
  resolve2(result);
4567
4569
  };
4568
4570
  proc.on("close", (code) => {
4571
+ if (timedOut) {
4572
+ appendTimeoutNotice();
4573
+ settle({
4574
+ exitCode: 124,
4575
+ stdout: stdout.trim(),
4576
+ stderr: stderr.trim()
4577
+ });
4578
+ return;
4579
+ }
4569
4580
  settle({
4570
4581
  exitCode: code ?? 1,
4571
4582
  stdout: stdout.trim(),
@@ -4575,6 +4586,19 @@ async function executeHookCommand(command, stdin, cwd, options) {
4575
4586
  proc.on("error", (err) => {
4576
4587
  settle({ exitCode: 1, stderr: err.message });
4577
4588
  });
4589
+ const killWindowsProcessTree = (onComplete) => {
4590
+ if (!proc.pid) {
4591
+ onComplete?.();
4592
+ return;
4593
+ }
4594
+ const killer = spawn("taskkill", ["/PID", String(proc.pid), "/T", "/F"], {
4595
+ windowsHide: true,
4596
+ stdio: "ignore"
4597
+ });
4598
+ const finish = () => onComplete?.();
4599
+ killer.on("error", finish);
4600
+ killer.on("close", finish);
4601
+ };
4578
4602
  const killProcessGroup = (signal) => {
4579
4603
  try {
4580
4604
  if (!isWin32 && proc.pid) {
@@ -4585,20 +4609,57 @@ async function executeHookCommand(command, stdin, cwd, options) {
4585
4609
  }
4586
4610
  } else {
4587
4611
  proc.kill(signal);
4612
+ if (signal === "SIGKILL") {
4613
+ killWindowsProcessTree();
4614
+ }
4588
4615
  }
4589
4616
  } catch {}
4590
4617
  };
4618
+ const appendTimeoutNotice = () => {
4619
+ if (!stderr.includes("Hook command timed out after")) {
4620
+ stderr += `
4621
+ Hook command timed out after ${timeoutMs}ms`;
4622
+ }
4623
+ };
4591
4624
  const timeoutTimer = setTimeout(() => {
4592
4625
  if (settled)
4593
4626
  return;
4627
+ timedOut = true;
4628
+ appendTimeoutNotice();
4629
+ if (isWin32) {
4630
+ killWindowsProcessTree(() => {
4631
+ settle({
4632
+ exitCode: 124,
4633
+ stdout: stdout.trim(),
4634
+ stderr: stderr.trim()
4635
+ });
4636
+ });
4637
+ return;
4638
+ }
4594
4639
  killProcessGroup("SIGTERM");
4595
4640
  killTimer = setTimeout(() => {
4596
4641
  if (settled)
4597
4642
  return;
4643
+ if (isWin32) {
4644
+ killWindowsProcessTree(() => {
4645
+ settle({
4646
+ exitCode: 124,
4647
+ stdout: stdout.trim(),
4648
+ stderr: stderr.trim()
4649
+ });
4650
+ });
4651
+ return;
4652
+ }
4598
4653
  killProcessGroup("SIGKILL");
4599
- }, SIGKILL_GRACE_MS);
4600
- stderr += `
4601
- Hook command timed out after ${timeoutMs}ms`;
4654
+ settle({
4655
+ exitCode: 124,
4656
+ stdout: stdout.trim(),
4657
+ stderr: stderr.trim()
4658
+ });
4659
+ }, killGraceMs);
4660
+ if (killTimer && typeof killTimer === "object" && "unref" in killTimer) {
4661
+ killTimer.unref();
4662
+ }
4602
4663
  }, timeoutMs);
4603
4664
  if (timeoutTimer && typeof timeoutTimer === "object" && "unref" in timeoutTimer) {
4604
4665
  timeoutTimer.unref();
@@ -4965,8 +5026,8 @@ var init_model_requirements = __esm(() => {
4965
5026
  { providers: ["opencode-go"], model: "qwen3.5-plus" },
4966
5027
  { providers: ["vercel"], model: "minimax-m2.7-highspeed" },
4967
5028
  { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" },
4968
- { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" },
4969
- { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }
5029
+ { providers: ["anthropic", "vercel"], model: "claude-haiku-4-5" },
5030
+ { providers: ["openai", "vercel"], model: "gpt-5.4-nano" }
4970
5031
  ]
4971
5032
  },
4972
5033
  explore: {
@@ -4975,8 +5036,8 @@ var init_model_requirements = __esm(() => {
4975
5036
  { providers: ["opencode-go"], model: "qwen3.5-plus" },
4976
5037
  { providers: ["vercel"], model: "minimax-m2.7-highspeed" },
4977
5038
  { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" },
4978
- { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" },
4979
- { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }
5039
+ { providers: ["anthropic", "vercel"], model: "claude-haiku-4-5" },
5040
+ { providers: ["openai", "vercel"], model: "gpt-5.4-nano" }
4980
5041
  ]
4981
5042
  },
4982
5043
  "multimodal-looker": {
@@ -5155,7 +5216,7 @@ var init_model_requirements = __esm(() => {
5155
5216
  model: "gpt-5.4-mini"
5156
5217
  },
5157
5218
  {
5158
- providers: ["anthropic", "github-copilot", "opencode", "vercel"],
5219
+ providers: ["anthropic", "github-copilot", "vercel"],
5159
5220
  model: "claude-haiku-4-5"
5160
5221
  },
5161
5222
  {
@@ -5432,7 +5493,7 @@ var init_model_capability_heuristics = __esm(() => {
5432
5493
  },
5433
5494
  {
5434
5495
  family: "kimi",
5435
- includes: ["kimi", "k2"],
5496
+ pattern: /(?:kimi|k2(?![-.]?p\d))/,
5436
5497
  variants: ["low", "medium", "high"],
5437
5498
  supportsThinking: false
5438
5499
  },
@@ -5673,7 +5734,7 @@ function claudeVersionDot(model) {
5673
5734
  function applyGatewayTransforms(model) {
5674
5735
  return claudeVersionDot(model).replace(GEMINI_31_PRO_PREVIEW, "gemini-3.1-pro-preview");
5675
5736
  }
5676
- function transformModelForProviderUsingAnthropicBehavior(provider, model, directAnthropicTransform) {
5737
+ function transformModelForProviderUsingAnthropicBehavior(provider, model) {
5677
5738
  if (provider === "vercel") {
5678
5739
  const slashIndex = model.indexOf("/");
5679
5740
  if (slashIndex !== -1) {
@@ -5694,12 +5755,12 @@ function transformModelForProviderUsingAnthropicBehavior(provider, model, direct
5694
5755
  return model.replace(GEMINI_31_PRO_PREVIEW, "gemini-3.1-pro-preview").replace(GEMINI_3_FLASH_PREVIEW, "gemini-3-flash-preview");
5695
5756
  }
5696
5757
  if (provider === "anthropic") {
5697
- return directAnthropicTransform(model);
5758
+ return model;
5698
5759
  }
5699
5760
  return model;
5700
5761
  }
5701
5762
  function transformModelForProvider(provider, model) {
5702
- return transformModelForProviderUsingAnthropicBehavior(provider, model, claudeVersionDot);
5763
+ return transformModelForProviderUsingAnthropicBehavior(provider, model);
5703
5764
  }
5704
5765
  var CLAUDE_VERSION_DOT, GEMINI_31_PRO_PREVIEW, GEMINI_3_FLASH_PREVIEW;
5705
5766
  var init_provider_model_id_transform = __esm(() => {
@@ -8736,8 +8797,30 @@ function resolveConfigPath(pathValue) {
8736
8797
  return resolvedPath;
8737
8798
  }
8738
8799
  }
8800
+ function isWslEnvironment() {
8801
+ return process.platform === "linux" && (Boolean(process.env.WSL_DISTRO_NAME?.trim()) || Boolean(process.env.WSL_INTEROP?.trim()));
8802
+ }
8803
+ function isWindowsUserConfigRoot(pathValue) {
8804
+ const normalizedPath = pathValue.replaceAll("\\", "/").toLowerCase();
8805
+ return /^[a-z]:\/users\//.test(normalizedPath) || /^\/mnt\/[a-z]\/users\//.test(normalizedPath);
8806
+ }
8807
+ function getWindowsUserFromConfigRoot(pathValue) {
8808
+ const normalizedPath = pathValue.replaceAll("\\", "/");
8809
+ const match = /^(?:[a-z]:|\/mnt\/[a-z])\/Users\/([^/]+)/i.exec(normalizedPath);
8810
+ return match?.[1] ?? null;
8811
+ }
8812
+ function getWslLinuxHomeDir(windowsConfigRoot) {
8813
+ const envHome = process.env.HOME?.trim();
8814
+ if (envHome && envHome.startsWith("/") && !isWindowsUserConfigRoot(envHome)) {
8815
+ return envHome;
8816
+ }
8817
+ const user = process.env.USER?.trim() || process.env.LOGNAME?.trim() || process.env.SUDO_USER?.trim() || (windowsConfigRoot ? getWindowsUserFromConfigRoot(windowsConfigRoot) : undefined);
8818
+ return user ? join6("/home", user) : null;
8819
+ }
8739
8820
  function getCliDefaultConfigDir() {
8740
- const xdgConfig = process.env.XDG_CONFIG_HOME || join6(homedir5(), ".config");
8821
+ const envXdgConfig = process.env.XDG_CONFIG_HOME?.trim();
8822
+ const shouldIgnoreWindowsXdg = envXdgConfig !== undefined && envXdgConfig.length > 0 && isWslEnvironment() && isWindowsUserConfigRoot(envXdgConfig);
8823
+ const xdgConfig = shouldIgnoreWindowsXdg ? join6(getWslLinuxHomeDir(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join6(homedir5(), ".config");
8741
8824
  return resolveConfigPath(join6(xdgConfig, "opencode"));
8742
8825
  }
8743
8826
  function getCliCustomConfigDir() {
@@ -54030,7 +54113,7 @@ function buildTmuxAttachCommand(serverUrl, sessionId, directory = process.cwd())
54030
54113
  }
54031
54114
  function buildTmuxPlaceholderCommand(description) {
54032
54115
  const escapedDescription = shellEscapeForDoubleQuotedCommand(description);
54033
- return `${TMUX_COMMAND_SHELL} -c "printf '%s\\n%s\\n' "OMO subagent pane ready: ${escapedDescription}" "Focus this pane to attach."; exec tail -f /dev/null"`;
54116
+ return `${TMUX_COMMAND_SHELL} -c "printf '%s\\n%s\\n' \\"OMO subagent pane ready: ${escapedDescription}\\" \\"Focus this pane to attach.\\"; while :; do sleep 86400; done"`;
54034
54117
  }
54035
54118
  var TMUX_COMMAND_SHELL = "/bin/sh";
54036
54119
  var init_pane_command = () => {};
@@ -55033,7 +55116,7 @@ async function withDispatchTimeout(operation, dispatchTimeoutMs, operationName)
55033
55116
  }
55034
55117
  }
55035
55118
  }
55036
- var DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS = 2000, DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS = 30000, DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS = 5000, DEFAULT_PROMPT_QUEUE_RETRY_MS = 250, promptGateMessagesFetchTimeoutMsForTesting;
55119
+ var DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS = 2000, DEFAULT_PROMPT_SEMANTIC_DEDUPE_HOLD_MS = 15000, DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS = 30000, DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS = 5000, DEFAULT_PROMPT_QUEUE_RETRY_MS = 250, promptGateMessagesFetchTimeoutMsForTesting;
55037
55120
 
55038
55121
  // src/shared/prompt-async-gate/pending-tool-turn.ts
55039
55122
  function getPromptQuery(input) {
@@ -55146,6 +55229,45 @@ var init_pending_tool_turn = __esm(() => {
55146
55229
  init_message_inspection_error();
55147
55230
  });
55148
55231
 
55232
+ // src/shared/prompt-async-gate/recent-dispatches.ts
55233
+ function recentDispatchKey(sessionID, dedupeKey) {
55234
+ return `${sessionID}\x00${dedupeKey}`;
55235
+ }
55236
+ function pruneRecentPromptDispatches(now = Date.now()) {
55237
+ for (const [key, dispatch] of recentPromptDispatches) {
55238
+ if (dispatch.expiresAt <= now) {
55239
+ recentPromptDispatches.delete(key);
55240
+ }
55241
+ }
55242
+ }
55243
+ function getRecentPromptDispatch(sessionID, dedupeKey) {
55244
+ pruneRecentPromptDispatches();
55245
+ return recentPromptDispatches.get(recentDispatchKey(sessionID, dedupeKey));
55246
+ }
55247
+ function rememberRecentPromptDispatch(args) {
55248
+ pruneRecentPromptDispatches();
55249
+ if (args.holdMs <= 0) {
55250
+ return;
55251
+ }
55252
+ recentPromptDispatches.set(recentDispatchKey(args.sessionID, args.dedupeKey), {
55253
+ source: args.source,
55254
+ expiresAt: Date.now() + args.holdMs
55255
+ });
55256
+ log("[prompt-async-gate] remembered semantic prompt dispatch", {
55257
+ sessionID: args.sessionID,
55258
+ source: args.source,
55259
+ holdMs: args.holdMs
55260
+ });
55261
+ }
55262
+ function deleteRecentPromptDispatch(sessionID, dedupeKey) {
55263
+ recentPromptDispatches.delete(recentDispatchKey(sessionID, dedupeKey));
55264
+ }
55265
+ var recentPromptDispatches;
55266
+ var init_recent_dispatches = __esm(() => {
55267
+ init_logger();
55268
+ recentPromptDispatches = new Map;
55269
+ });
55270
+
55149
55271
  // src/shared/prompt-async-gate/reservations.ts
55150
55272
  function setExpiredReservationHandler(handler) {
55151
55273
  expiredReservationHandler = handler;
@@ -55227,6 +55349,7 @@ async function dispatchAfterSessionIdle(args) {
55227
55349
  dedupeKey,
55228
55350
  settleMs,
55229
55351
  postDispatchHoldMs,
55352
+ semanticDedupeHoldMs,
55230
55353
  dispatchTimeoutMs,
55231
55354
  checkStatus,
55232
55355
  checkToolState,
@@ -55284,10 +55407,25 @@ async function dispatchAfterSessionIdle(args) {
55284
55407
  log(`[prompt-async-gate] ${sessionName} dispatching`, { sessionID, source });
55285
55408
  dispatchAttempted = true;
55286
55409
  const response = await withDispatchTimeout(dispatch(input), dispatchTimeoutMs, `[prompt-async-gate] ${sessionName} dispatch`);
55410
+ rememberRecentPromptDispatch({
55411
+ sessionID,
55412
+ dedupeKey,
55413
+ source,
55414
+ holdMs: semanticDedupeHoldMs
55415
+ });
55287
55416
  log(`[prompt-async-gate] ${sessionName} dispatched`, { sessionID, source });
55288
55417
  return { status: "dispatched", response };
55289
55418
  } catch (error) {
55290
- log(`[prompt-async-gate] ${sessionName} failed`, { sessionID, source, error: String(error) });
55419
+ if (dispatchAttempted) {
55420
+ rememberRecentPromptDispatch({
55421
+ sessionID,
55422
+ dedupeKey,
55423
+ source,
55424
+ holdMs: semanticDedupeHoldMs
55425
+ });
55426
+ }
55427
+ const errorText = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
55428
+ log(`[prompt-async-gate] ${sessionName} failed`, { sessionID, source, error: errorText });
55291
55429
  return { status: "failed", error, dispatchAttempted };
55292
55430
  } finally {
55293
55431
  finishPromptReservation(sessionID, reservation, dispatchAttempted, postDispatchHoldMs);
@@ -55297,6 +55435,7 @@ var init_session_idle_dispatch = __esm(() => {
55297
55435
  init_logger();
55298
55436
  init_session_idle_settle();
55299
55437
  init_pending_tool_turn();
55438
+ init_recent_dispatches();
55300
55439
  init_reservations();
55301
55440
  });
55302
55441
 
@@ -55404,6 +55543,7 @@ async function drainPromptQueue(sessionID, awaitedEntry) {
55404
55543
  dedupeKey: entry.dedupeKey,
55405
55544
  settleMs: entry.settleMs,
55406
55545
  postDispatchHoldMs: entry.postDispatchHoldMs,
55546
+ semanticDedupeHoldMs: entry.semanticDedupeHoldMs,
55407
55547
  dispatchTimeoutMs: entry.dispatchTimeoutMs,
55408
55548
  checkStatus: entry.checkStatus,
55409
55549
  checkToolState: entry.checkToolState,
@@ -55487,27 +55627,119 @@ var init_queue = __esm(() => {
55487
55627
  });
55488
55628
  });
55489
55629
 
55490
- // src/shared/prompt-async-gate.ts
55630
+ // src/shared/prompt-async-gate/semantic-dedupe.ts
55631
+ import { createHash } from "crypto";
55632
+ function isPlainRecord(value) {
55633
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
55634
+ return false;
55635
+ }
55636
+ const prototype = Object.getPrototypeOf(value);
55637
+ return prototype === Object.prototype || prototype === null;
55638
+ }
55639
+ function canonicalizePromptInputForDedupe(key, value, seen = new WeakSet, depth = 0) {
55640
+ if (key === "signal") {
55641
+ return "[AbortSignal]";
55642
+ }
55643
+ if (typeof value === "function") {
55644
+ return `[Function:${value.name}]`;
55645
+ }
55646
+ if (depth > MAX_PROMPT_DEDUPE_DEPTH) {
55647
+ return "[MaxDepth]";
55648
+ }
55649
+ if (Array.isArray(value)) {
55650
+ if (seen.has(value)) {
55651
+ return "[Circular]";
55652
+ }
55653
+ seen.add(value);
55654
+ try {
55655
+ return value.map((entry) => canonicalizePromptInputForDedupe("", entry, seen, depth + 1));
55656
+ } finally {
55657
+ seen.delete(value);
55658
+ }
55659
+ }
55660
+ if (!isPlainRecord(value)) {
55661
+ return value;
55662
+ }
55663
+ if (seen.has(value)) {
55664
+ return "[Circular]";
55665
+ }
55666
+ seen.add(value);
55667
+ try {
55668
+ const canonicalEntries = [];
55669
+ for (const entryKey of Object.keys(value).sort()) {
55670
+ canonicalEntries.push([
55671
+ entryKey,
55672
+ canonicalizePromptInputForDedupe(entryKey, value[entryKey], seen, depth + 1)
55673
+ ]);
55674
+ }
55675
+ return Object.fromEntries(canonicalEntries);
55676
+ } finally {
55677
+ seen.delete(value);
55678
+ }
55679
+ }
55680
+ function isContinuationTextPartLike(value) {
55681
+ if (!isPlainRecord(value)) {
55682
+ return false;
55683
+ }
55684
+ if (value.type !== "text" || typeof value.text !== "string") {
55685
+ return false;
55686
+ }
55687
+ if (!hasInternalInitiatorMarker(value.text)) {
55688
+ return false;
55689
+ }
55690
+ if (!isPlainRecord(value.metadata)) {
55691
+ return false;
55692
+ }
55693
+ return value.metadata.compaction_continue === true;
55694
+ }
55695
+ function hasContinuationPromptIntent(input) {
55696
+ if (!isPlainRecord(input) || !isPlainRecord(input.body) || !Array.isArray(input.body.parts)) {
55697
+ return false;
55698
+ }
55699
+ return input.body.parts.some((part) => isContinuationTextPartLike(part));
55700
+ }
55701
+ function normalizePromptInputForSemanticDedupe(input) {
55702
+ if (hasContinuationPromptIntent(input)) {
55703
+ return {
55704
+ __omo_internal_intent: "continuation"
55705
+ };
55706
+ }
55707
+ return canonicalizePromptInputForDedupe("", input);
55708
+ }
55491
55709
  function stringifyPromptInputForDedupe(input) {
55492
55710
  try {
55493
- const serialized = JSON.stringify(input, (key, value) => {
55494
- if (key === "signal") {
55495
- return "[AbortSignal]";
55496
- }
55497
- if (typeof value === "function") {
55498
- return `[Function:${value.name}]`;
55499
- }
55500
- return value;
55501
- });
55711
+ const serialized = JSON.stringify(normalizePromptInputForSemanticDedupe(input));
55502
55712
  return serialized ?? String(input);
55503
- } catch {
55504
- return String(input);
55713
+ } catch (error) {
55714
+ const errorTag = error instanceof Error ? error.name : String(error);
55715
+ return `${String(input)}:[unserializable:${errorTag}]`;
55505
55716
  }
55506
55717
  }
55507
- function createDefaultDedupeKey(source, input) {
55718
+ function createSemanticPromptDedupeKey(input) {
55508
55719
  const fingerprint = stringifyPromptInputForDedupe(input);
55509
- return `${source}:${fingerprint.length}:${fingerprint.slice(0, 8192)}`;
55720
+ const digest = createHash("sha256").update(fingerprint, "utf8").digest("hex");
55721
+ return `semantic:${digest}`;
55510
55722
  }
55723
+ function coalesceRecentSemanticPromptDispatch(args) {
55724
+ const recentDispatch = getRecentPromptDispatch(args.sessionID, args.dedupeKey);
55725
+ if (!recentDispatch) {
55726
+ return;
55727
+ }
55728
+ log("[prompt-async-gate] prompt coalesced with recent semantic dispatch", {
55729
+ sessionID: args.sessionID,
55730
+ source: args.source,
55731
+ queuedBy: recentDispatch.source
55732
+ });
55733
+ return { status: "queued", queuedBy: recentDispatch.source, position: 0 };
55734
+ }
55735
+ var MAX_PROMPT_DEDUPE_DEPTH = 64;
55736
+ var init_semantic_dedupe = __esm(() => {
55737
+ init_internal_initiator_marker();
55738
+ init_logger();
55739
+ init_recent_dispatches();
55740
+ });
55741
+
55742
+ // src/shared/prompt-async-gate.ts
55511
55743
  function hasObjectSessionPath(input) {
55512
55744
  return typeof input === "object" && input !== null && "path" in input && typeof input.path === "object" && input.path !== null && "id" in input.path && typeof input.path.id === "string";
55513
55745
  }
@@ -55537,9 +55769,10 @@ async function dispatchInternalPrompt(args) {
55537
55769
  source,
55538
55770
  settleMs = DEFAULT_SESSION_IDLE_SETTLE_MS
55539
55771
  } = args;
55540
- const dedupeKey = args.dedupeKey ?? createDefaultDedupeKey(source, input);
55772
+ const dedupeKey = args.dedupeKey ?? createSemanticPromptDedupeKey(input);
55541
55773
  const queueRetryMs = args.queueRetryMs ?? DEFAULT_PROMPT_QUEUE_RETRY_MS;
55542
55774
  const postDispatchHoldMs = args.postDispatchHoldMs ?? DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS;
55775
+ const semanticDedupeHoldMs = args.semanticDedupeHoldMs ?? (postDispatchHoldMs > 0 ? DEFAULT_PROMPT_SEMANTIC_DEDUPE_HOLD_MS : 0);
55543
55776
  const dispatchTimeoutMs = args.dispatchTimeoutMs ?? DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS;
55544
55777
  const sessionName = args.mode === "async" ? "promptAsync" : "prompt";
55545
55778
  const dispatch = (() => {
@@ -55572,6 +55805,10 @@ async function dispatchInternalPrompt(args) {
55572
55805
  if (queuedBy !== undefined || isPromptQueueDraining(sessionID)) {
55573
55806
  return { status: "reserved", reservedBy: queuedBy ?? source };
55574
55807
  }
55808
+ const recentDispatchResult2 = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
55809
+ if (recentDispatchResult2) {
55810
+ return recentDispatchResult2;
55811
+ }
55575
55812
  return dispatchAfterSessionIdle({
55576
55813
  sessionName,
55577
55814
  client,
@@ -55581,6 +55818,7 @@ async function dispatchInternalPrompt(args) {
55581
55818
  dedupeKey,
55582
55819
  settleMs,
55583
55820
  postDispatchHoldMs,
55821
+ semanticDedupeHoldMs,
55584
55822
  dispatchTimeoutMs,
55585
55823
  checkStatus: args.checkStatus !== false,
55586
55824
  checkToolState: args.checkToolState !== false,
@@ -55588,6 +55826,10 @@ async function dispatchInternalPrompt(args) {
55588
55826
  });
55589
55827
  }
55590
55828
  if (args.queue !== false) {
55829
+ const recentDispatchResult2 = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
55830
+ if (recentDispatchResult2) {
55831
+ return recentDispatchResult2;
55832
+ }
55591
55833
  return enqueueInternalPrompt({
55592
55834
  id: nextPromptQueueID(),
55593
55835
  sessionID,
@@ -55598,6 +55840,7 @@ async function dispatchInternalPrompt(args) {
55598
55840
  dedupeKey,
55599
55841
  settleMs,
55600
55842
  postDispatchHoldMs,
55843
+ semanticDedupeHoldMs,
55601
55844
  dispatchTimeoutMs,
55602
55845
  queueRetryMs,
55603
55846
  checkStatus: args.checkStatus !== false,
@@ -55605,6 +55848,10 @@ async function dispatchInternalPrompt(args) {
55605
55848
  dispatch: async (_dispatchInput) => dispatchWithPathCompatibility(dispatch, input)
55606
55849
  });
55607
55850
  }
55851
+ const recentDispatchResult = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
55852
+ if (recentDispatchResult) {
55853
+ return recentDispatchResult;
55854
+ }
55608
55855
  return dispatchAfterSessionIdle({
55609
55856
  sessionName,
55610
55857
  client,
@@ -55614,6 +55861,7 @@ async function dispatchInternalPrompt(args) {
55614
55861
  dedupeKey,
55615
55862
  settleMs,
55616
55863
  postDispatchHoldMs,
55864
+ semanticDedupeHoldMs,
55617
55865
  dispatchTimeoutMs,
55618
55866
  checkStatus: args.checkStatus !== false,
55619
55867
  checkToolState: args.checkToolState !== false,
@@ -55638,6 +55886,7 @@ function releasePromptAsyncReservation(sessionID, source, options) {
55638
55886
  return false;
55639
55887
  }
55640
55888
  deletePromptReservation(sessionID);
55889
+ deleteRecentPromptDispatch(sessionID, existing.dedupeKey);
55641
55890
  releaseInFlightPromptMatchingDedupe(sessionID, existing.dedupeKey);
55642
55891
  schedulePromptQueueDrain(sessionID, 0);
55643
55892
  log("[prompt-async-gate] promptAsync reservation released", {
@@ -55651,8 +55900,10 @@ var init_prompt_async_gate = __esm(() => {
55651
55900
  init_logger();
55652
55901
  init_session_idle_settle();
55653
55902
  init_queue();
55903
+ init_recent_dispatches();
55654
55904
  init_reservations();
55655
55905
  init_session_idle_dispatch();
55906
+ init_semantic_dedupe();
55656
55907
  });
55657
55908
 
55658
55909
  // src/shared/prompt-failure-classifier.ts
@@ -63914,8 +64165,8 @@ var require_utils2 = __commonJS((exports, module) => {
63914
64165
  }
63915
64166
  return ind;
63916
64167
  }
63917
- function removeDotSegments(path21) {
63918
- let input = path21;
64168
+ function removeDotSegments(path22) {
64169
+ let input = path22;
63919
64170
  const output = [];
63920
64171
  let nextSlash = -1;
63921
64172
  let len = 0;
@@ -64158,8 +64409,8 @@ var require_schemes = __commonJS((exports, module) => {
64158
64409
  wsComponent.secure = undefined;
64159
64410
  }
64160
64411
  if (wsComponent.resourceName) {
64161
- const [path21, query] = wsComponent.resourceName.split("?");
64162
- wsComponent.path = path21 && path21 !== "/" ? path21 : undefined;
64412
+ const [path22, query] = wsComponent.resourceName.split("?");
64413
+ wsComponent.path = path22 && path22 !== "/" ? path22 : undefined;
64163
64414
  wsComponent.query = query;
64164
64415
  wsComponent.resourceName = undefined;
64165
64416
  }
@@ -67334,12 +67585,12 @@ var require_dist = __commonJS((exports, module) => {
67334
67585
  throw new Error(`Unknown format "${name}"`);
67335
67586
  return f;
67336
67587
  };
67337
- function addFormats(ajv, list, fs22, exportName) {
67588
+ function addFormats(ajv, list, fs23, exportName) {
67338
67589
  var _a;
67339
67590
  var _b;
67340
67591
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
67341
67592
  for (const f of list)
67342
- ajv.addFormat(f, fs22[f]);
67593
+ ajv.addFormat(f, fs23[f]);
67343
67594
  }
67344
67595
  module.exports = exports = formatsPlugin;
67345
67596
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -67350,8 +67601,8 @@ var require_dist = __commonJS((exports, module) => {
67350
67601
  var require_windows = __commonJS((exports, module) => {
67351
67602
  module.exports = isexe;
67352
67603
  isexe.sync = sync;
67353
- var fs22 = __require("fs");
67354
- function checkPathExt(path21, options) {
67604
+ var fs23 = __require("fs");
67605
+ function checkPathExt(path22, options) {
67355
67606
  var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
67356
67607
  if (!pathext) {
67357
67608
  return true;
@@ -67362,25 +67613,25 @@ var require_windows = __commonJS((exports, module) => {
67362
67613
  }
67363
67614
  for (var i2 = 0;i2 < pathext.length; i2++) {
67364
67615
  var p = pathext[i2].toLowerCase();
67365
- if (p && path21.substr(-p.length).toLowerCase() === p) {
67616
+ if (p && path22.substr(-p.length).toLowerCase() === p) {
67366
67617
  return true;
67367
67618
  }
67368
67619
  }
67369
67620
  return false;
67370
67621
  }
67371
- function checkStat(stat7, path21, options) {
67622
+ function checkStat(stat7, path22, options) {
67372
67623
  if (!stat7.isSymbolicLink() && !stat7.isFile()) {
67373
67624
  return false;
67374
67625
  }
67375
- return checkPathExt(path21, options);
67626
+ return checkPathExt(path22, options);
67376
67627
  }
67377
- function isexe(path21, options, cb) {
67378
- fs22.stat(path21, function(er, stat7) {
67379
- cb(er, er ? false : checkStat(stat7, path21, options));
67628
+ function isexe(path22, options, cb) {
67629
+ fs23.stat(path22, function(er, stat7) {
67630
+ cb(er, er ? false : checkStat(stat7, path22, options));
67380
67631
  });
67381
67632
  }
67382
- function sync(path21, options) {
67383
- return checkStat(fs22.statSync(path21), path21, options);
67633
+ function sync(path22, options) {
67634
+ return checkStat(fs23.statSync(path22), path22, options);
67384
67635
  }
67385
67636
  });
67386
67637
 
@@ -67388,14 +67639,14 @@ var require_windows = __commonJS((exports, module) => {
67388
67639
  var require_mode = __commonJS((exports, module) => {
67389
67640
  module.exports = isexe;
67390
67641
  isexe.sync = sync;
67391
- var fs22 = __require("fs");
67392
- function isexe(path21, options, cb) {
67393
- fs22.stat(path21, function(er, stat7) {
67642
+ var fs23 = __require("fs");
67643
+ function isexe(path22, options, cb) {
67644
+ fs23.stat(path22, function(er, stat7) {
67394
67645
  cb(er, er ? false : checkStat(stat7, options));
67395
67646
  });
67396
67647
  }
67397
- function sync(path21, options) {
67398
- return checkStat(fs22.statSync(path21), options);
67648
+ function sync(path22, options) {
67649
+ return checkStat(fs23.statSync(path22), options);
67399
67650
  }
67400
67651
  function checkStat(stat7, options) {
67401
67652
  return stat7.isFile() && checkMode(stat7, options);
@@ -67417,7 +67668,7 @@ var require_mode = __commonJS((exports, module) => {
67417
67668
 
67418
67669
  // node_modules/.bun/isexe@2.0.0/node_modules/isexe/index.js
67419
67670
  var require_isexe = __commonJS((exports, module) => {
67420
- var fs22 = __require("fs");
67671
+ var fs23 = __require("fs");
67421
67672
  var core2;
67422
67673
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
67423
67674
  core2 = require_windows();
@@ -67426,7 +67677,7 @@ var require_isexe = __commonJS((exports, module) => {
67426
67677
  }
67427
67678
  module.exports = isexe;
67428
67679
  isexe.sync = sync;
67429
- function isexe(path21, options, cb) {
67680
+ function isexe(path22, options, cb) {
67430
67681
  if (typeof options === "function") {
67431
67682
  cb = options;
67432
67683
  options = {};
@@ -67436,7 +67687,7 @@ var require_isexe = __commonJS((exports, module) => {
67436
67687
  throw new TypeError("callback not provided");
67437
67688
  }
67438
67689
  return new Promise(function(resolve25, reject) {
67439
- isexe(path21, options || {}, function(er, is) {
67690
+ isexe(path22, options || {}, function(er, is) {
67440
67691
  if (er) {
67441
67692
  reject(er);
67442
67693
  } else {
@@ -67445,7 +67696,7 @@ var require_isexe = __commonJS((exports, module) => {
67445
67696
  });
67446
67697
  });
67447
67698
  }
67448
- core2(path21, options || {}, function(er, is) {
67699
+ core2(path22, options || {}, function(er, is) {
67449
67700
  if (er) {
67450
67701
  if (er.code === "EACCES" || options && options.ignoreErrors) {
67451
67702
  er = null;
@@ -67455,9 +67706,9 @@ var require_isexe = __commonJS((exports, module) => {
67455
67706
  cb(er, is);
67456
67707
  });
67457
67708
  }
67458
- function sync(path21, options) {
67709
+ function sync(path22, options) {
67459
67710
  try {
67460
- return core2.sync(path21, options || {});
67711
+ return core2.sync(path22, options || {});
67461
67712
  } catch (er) {
67462
67713
  if (options && options.ignoreErrors || er.code === "EACCES") {
67463
67714
  return false;
@@ -67471,7 +67722,7 @@ var require_isexe = __commonJS((exports, module) => {
67471
67722
  // node_modules/.bun/which@2.0.2/node_modules/which/which.js
67472
67723
  var require_which = __commonJS((exports, module) => {
67473
67724
  var isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
67474
- var path21 = __require("path");
67725
+ var path22 = __require("path");
67475
67726
  var COLON = isWindows2 ? ";" : ":";
67476
67727
  var isexe = require_isexe();
67477
67728
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -67507,7 +67758,7 @@ var require_which = __commonJS((exports, module) => {
67507
67758
  return opt.all && found.length ? resolve25(found) : reject(getNotFoundError(cmd));
67508
67759
  const ppRaw = pathEnv[i2];
67509
67760
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
67510
- const pCmd = path21.join(pathPart, cmd);
67761
+ const pCmd = path22.join(pathPart, cmd);
67511
67762
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
67512
67763
  resolve25(subStep(p, i2, 0));
67513
67764
  });
@@ -67534,7 +67785,7 @@ var require_which = __commonJS((exports, module) => {
67534
67785
  for (let i2 = 0;i2 < pathEnv.length; i2++) {
67535
67786
  const ppRaw = pathEnv[i2];
67536
67787
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
67537
- const pCmd = path21.join(pathPart, cmd);
67788
+ const pCmd = path22.join(pathPart, cmd);
67538
67789
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
67539
67790
  for (let j = 0;j < pathExt.length; j++) {
67540
67791
  const cur = p + pathExt[j];
@@ -67575,7 +67826,7 @@ var require_path_key = __commonJS((exports, module) => {
67575
67826
 
67576
67827
  // node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
67577
67828
  var require_resolveCommand = __commonJS((exports, module) => {
67578
- var path21 = __require("path");
67829
+ var path22 = __require("path");
67579
67830
  var which = require_which();
67580
67831
  var getPathKey = require_path_key();
67581
67832
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -67592,7 +67843,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
67592
67843
  try {
67593
67844
  resolved = which.sync(parsed.command, {
67594
67845
  path: env[getPathKey({ env })],
67595
- pathExt: withoutPathExt ? path21.delimiter : undefined
67846
+ pathExt: withoutPathExt ? path22.delimiter : undefined
67596
67847
  });
67597
67848
  } catch (e) {} finally {
67598
67849
  if (shouldSwitchCwd) {
@@ -67600,7 +67851,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
67600
67851
  }
67601
67852
  }
67602
67853
  if (resolved) {
67603
- resolved = path21.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
67854
+ resolved = path22.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
67604
67855
  }
67605
67856
  return resolved;
67606
67857
  }
@@ -67645,8 +67896,8 @@ var require_shebang_command = __commonJS((exports, module) => {
67645
67896
  if (!match) {
67646
67897
  return null;
67647
67898
  }
67648
- const [path21, argument] = match[0].replace(/#! ?/, "").split(" ");
67649
- const binary2 = path21.split("/").pop();
67899
+ const [path22, argument] = match[0].replace(/#! ?/, "").split(" ");
67900
+ const binary2 = path22.split("/").pop();
67650
67901
  if (binary2 === "env") {
67651
67902
  return argument;
67652
67903
  }
@@ -67656,16 +67907,16 @@ var require_shebang_command = __commonJS((exports, module) => {
67656
67907
 
67657
67908
  // node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
67658
67909
  var require_readShebang = __commonJS((exports, module) => {
67659
- var fs22 = __require("fs");
67910
+ var fs23 = __require("fs");
67660
67911
  var shebangCommand = require_shebang_command();
67661
67912
  function readShebang(command) {
67662
67913
  const size = 150;
67663
67914
  const buffer2 = Buffer.alloc(size);
67664
67915
  let fd;
67665
67916
  try {
67666
- fd = fs22.openSync(command, "r");
67667
- fs22.readSync(fd, buffer2, 0, size, 0);
67668
- fs22.closeSync(fd);
67917
+ fd = fs23.openSync(command, "r");
67918
+ fs23.readSync(fd, buffer2, 0, size, 0);
67919
+ fs23.closeSync(fd);
67669
67920
  } catch (e) {}
67670
67921
  return shebangCommand(buffer2.toString());
67671
67922
  }
@@ -67674,7 +67925,7 @@ var require_readShebang = __commonJS((exports, module) => {
67674
67925
 
67675
67926
  // node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
67676
67927
  var require_parse2 = __commonJS((exports, module) => {
67677
- var path21 = __require("path");
67928
+ var path22 = __require("path");
67678
67929
  var resolveCommand2 = require_resolveCommand();
67679
67930
  var escape2 = require_escape();
67680
67931
  var readShebang = require_readShebang();
@@ -67699,7 +67950,7 @@ var require_parse2 = __commonJS((exports, module) => {
67699
67950
  const needsShell = !isExecutableRegExp.test(commandFile);
67700
67951
  if (parsed.options.forceShell || needsShell) {
67701
67952
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
67702
- parsed.command = path21.normalize(parsed.command);
67953
+ parsed.command = path22.normalize(parsed.command);
67703
67954
  parsed.command = escape2.command(parsed.command);
67704
67955
  parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
67705
67956
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -68406,6 +68657,10 @@ function registerAgentName(name) {
68406
68657
  }
68407
68658
  }
68408
68659
  }
68660
+ function clearRegisteredAgentNames() {
68661
+ registeredAgentNames.clear();
68662
+ registeredAgentAliases.clear();
68663
+ }
68409
68664
  function isAgentRegistered(name) {
68410
68665
  return registeredAgentNames.has(normalizeRegisteredAgentName(name));
68411
68666
  }
@@ -69458,80 +69713,6 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
69458
69713
  dispose: () => sessionStateStore.shutdown()
69459
69714
  };
69460
69715
  }
69461
- // src/hooks/context-window-monitor.ts
69462
- init_context_limit_resolver2();
69463
- init_compaction_marker();
69464
- init_event_session_id();
69465
- init_system_directive();
69466
- var CONTEXT_WARNING_THRESHOLD = 0.7;
69467
- function createContextReminder(actualLimit) {
69468
- const limitTokens = actualLimit.toLocaleString();
69469
- return `${createSystemDirective(SystemDirectiveTypes.CONTEXT_WINDOW_MONITOR)}
69470
-
69471
- You are using a ${limitTokens}-token context window.
69472
- You still have context remaining - do NOT rush or skip tasks.
69473
- Complete your work thoroughly and methodically.`;
69474
- }
69475
- function createContextWindowMonitorHook(_ctx, modelCacheState) {
69476
- const remindedSessions = new Set;
69477
- const tokenCache = new Map;
69478
- const toolExecuteAfter = async (input, output) => {
69479
- const { sessionID } = input;
69480
- if (remindedSessions.has(sessionID))
69481
- return;
69482
- const cached2 = tokenCache.get(sessionID);
69483
- if (!cached2)
69484
- return;
69485
- const actualLimit = resolveActualContextLimit(cached2.providerID, cached2.modelID, modelCacheState);
69486
- if (!actualLimit)
69487
- return;
69488
- const lastTokens = cached2.tokens;
69489
- const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
69490
- const actualUsagePercentage = totalInputTokens / actualLimit;
69491
- if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD)
69492
- return;
69493
- remindedSessions.add(sessionID);
69494
- const clampedPercentage = Math.min(Math.max(actualUsagePercentage, 0), 1);
69495
- const usedPct = (clampedPercentage * 100).toFixed(1);
69496
- const remainingPct = ((1 - clampedPercentage) * 100).toFixed(1);
69497
- const usedTokens = totalInputTokens.toLocaleString();
69498
- const limitTokens = actualLimit.toLocaleString();
69499
- output.output += `
69500
-
69501
- ${createContextReminder(actualLimit)}
69502
- [Context Status: ${usedPct}% used (${usedTokens}/${limitTokens} tokens), ${remainingPct}% remaining]`;
69503
- };
69504
- const eventHandler = async ({ event }) => {
69505
- const props = event.properties;
69506
- if (event.type === "session.deleted") {
69507
- const sessionID = resolveSessionEventID(props);
69508
- if (sessionID) {
69509
- remindedSessions.delete(sessionID);
69510
- tokenCache.delete(sessionID);
69511
- }
69512
- }
69513
- if (event.type === "message.updated") {
69514
- const info = props?.info;
69515
- const finish = info?.finish;
69516
- if (!info || info.role !== "assistant" || !finish)
69517
- return;
69518
- if (isCompactionAgent(info.agent))
69519
- return;
69520
- const sessionID = resolveMessageEventSessionID(props);
69521
- if (!sessionID || !info.providerID || !info.tokens)
69522
- return;
69523
- tokenCache.set(sessionID, {
69524
- providerID: info.providerID,
69525
- modelID: info.modelID ?? "",
69526
- tokens: info.tokens
69527
- });
69528
- }
69529
- };
69530
- return {
69531
- "tool.execute.after": toolExecuteAfter,
69532
- event: eventHandler
69533
- };
69534
- }
69535
69716
  // src/hooks/session-notification-content.ts
69536
69717
  init_shared();
69537
69718
  function extractMessageText(message) {
@@ -72000,9 +72181,18 @@ function debugLog2(...args) {
72000
72181
  function getBinaryName2() {
72001
72182
  return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
72002
72183
  }
72184
+ function resolveCommentCheckerPathFromPath(binaryName, which = Bun.which) {
72185
+ try {
72186
+ return which(binaryName);
72187
+ } catch (error) {
72188
+ debugLog2("PATH lookup failed:", error);
72189
+ return null;
72190
+ }
72191
+ }
72003
72192
  function findCommentCheckerPathSync() {
72193
+ const binaryName = getBinaryName2();
72004
72194
  const resolvedPath = resolveCommentCheckerBinary({
72005
- binaryName: getBinaryName2(),
72195
+ binaryName,
72006
72196
  cachedBinaryPath: getCachedBinaryPath2(),
72007
72197
  existsSync: existsSync35,
72008
72198
  importMetaUrl: import.meta.url
@@ -72011,6 +72201,11 @@ function findCommentCheckerPathSync() {
72011
72201
  debugLog2("resolved binary path:", resolvedPath);
72012
72202
  return resolvedPath;
72013
72203
  }
72204
+ const pathBinary = resolveCommentCheckerPathFromPath(binaryName);
72205
+ if (pathBinary !== null && existsSync35(pathBinary)) {
72206
+ debugLog2("resolved PATH binary:", pathBinary);
72207
+ return pathBinary;
72208
+ }
72014
72209
  debugLog2("no binary found in known locations");
72015
72210
  return null;
72016
72211
  }
@@ -72900,7 +73095,7 @@ function findClosingDelimiter(content, openingLength) {
72900
73095
  }
72901
73096
  // packages/rules-engine/src/matcher.ts
72902
73097
  var import_picomatch = __toESM(require_picomatch2(), 1);
72903
- import { createHash } from "crypto";
73098
+ import { createHash as createHash2 } from "crypto";
72904
73099
  import { basename as basename6, relative as relative8 } from "path";
72905
73100
  var matcherCache = new Map;
72906
73101
  var MAX_MATCHER_CACHE_ENTRIES = 256;
@@ -72929,7 +73124,7 @@ function shouldApplyRule(metadata, currentFilePath, projectRoot) {
72929
73124
  return { applies: false };
72930
73125
  }
72931
73126
  function createContentHash(content) {
72932
- return createHash("sha256").update(content).digest("hex").slice(0, 16);
73127
+ return createHash2("sha256").update(content).digest("hex").slice(0, 16);
72933
73128
  }
72934
73129
  function isDuplicateByRealPath(realPath, cache) {
72935
73130
  return cache.has(realPath);
@@ -76338,9 +76533,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
76338
76533
  `);
76339
76534
  const cacheEntry = transcriptCache.get(sessionId);
76340
76535
  if (cacheEntry) {
76341
- cacheEntry.baseEntries = allEntries;
76342
76536
  cacheEntry.tempPath = tempPath;
76343
- cacheEntry.createdAt = Date.now();
76344
76537
  }
76345
76538
  return tempPath;
76346
76539
  } catch (error) {
@@ -85262,6 +85455,9 @@ function suppressComboStandalones(detected) {
85262
85455
  return detected;
85263
85456
  return detected.filter((k) => k.type !== "ultrawork" && k.type !== "hyperplan");
85264
85457
  }
85458
+ function filterAlreadyInjectedKeywords(detected, text) {
85459
+ return detected.filter((keyword) => !text.includes(keyword.message));
85460
+ }
85265
85461
  function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultMode) {
85266
85462
  const disabledKeywords = config?.disabled_keywords;
85267
85463
  const enabledExpansions = config?.enabled_expansions;
@@ -85339,6 +85535,11 @@ function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultM
85339
85535
  return;
85340
85536
  }
85341
85537
  }
85538
+ detectedKeywords = filterAlreadyInjectedKeywords(detectedKeywords, cleanText);
85539
+ if (detectedKeywords.length === 0) {
85540
+ log(`[keyword-detector] Skipping already injected keyword messages`, { sessionID: input.sessionID });
85541
+ return;
85542
+ }
85342
85543
  const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork");
85343
85544
  if (hasUltrawork) {
85344
85545
  const runtimeVariant = getRuntimeVariant(input, output.message);
@@ -87513,9 +87714,10 @@ function collectAssistantText(message) {
87513
87714
  if (!Array.isArray(message.parts)) {
87514
87715
  return "";
87515
87716
  }
87717
+ const allowTextParts = message.info?.role === "assistant";
87516
87718
  let text = "";
87517
87719
  for (const part of message.parts) {
87518
- if (part.type !== "text" && part.type !== "tool_result") {
87720
+ if (part.type !== "tool_result" && !(allowTextParts && part.type === "text")) {
87519
87721
  continue;
87520
87722
  }
87521
87723
  text += `${text ? `
@@ -87534,9 +87736,6 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
87534
87736
  const messageArray = Array.isArray(messagesResponse) ? messagesResponse : Array.isArray(responseData) ? responseData : [];
87535
87737
  for (let index = messageArray.length - 1;index >= 0; index -= 1) {
87536
87738
  const message = messageArray[index];
87537
- if (message.info?.role !== "assistant") {
87538
- continue;
87539
- }
87540
87739
  const assistantText = collectAssistantText(message);
87541
87740
  if (!isOracleVerified(assistantText)) {
87542
87741
  continue;
@@ -87555,6 +87754,30 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
87555
87754
  return;
87556
87755
  }
87557
87756
  }
87757
+ function showCompletionToastBestEffort(ctx, state3) {
87758
+ const showToast = ctx.client.tui?.showToast;
87759
+ if (!showToast) {
87760
+ return;
87761
+ }
87762
+ const toastBody = {
87763
+ body: {
87764
+ title: "ULTRAWORK LOOP COMPLETE!",
87765
+ message: `JUST ULW ULW! Task completed after ${state3.iteration} iteration(s)`,
87766
+ variant: "success",
87767
+ duration: 5000
87768
+ }
87769
+ };
87770
+ const logToastError = (error) => {
87771
+ log(`[${HOOK_NAME3}] Failed to show ulw completion toast`, {
87772
+ error: String(error)
87773
+ });
87774
+ };
87775
+ try {
87776
+ Promise.resolve(showToast(toastBody)).catch(logToastError);
87777
+ } catch (error) {
87778
+ logToastError(error);
87779
+ }
87780
+ }
87558
87781
  async function handlePendingVerification(ctx, input) {
87559
87782
  const {
87560
87783
  sessionID,
@@ -87570,6 +87793,15 @@ async function handlePendingVerification(ctx, input) {
87570
87793
  if (!verificationSessionID && state3.session_id) {
87571
87794
  const recoveredVerificationSessionID = await detectOracleVerificationFromParentSession(ctx, state3.session_id, directory, apiTimeoutMs);
87572
87795
  if (recoveredVerificationSessionID) {
87796
+ if (state3.completion_promise === ULTRAWORK_VERIFICATION_PROMISE) {
87797
+ log(`[${HOOK_NAME3}] Oracle verification evidence found in parent session, completing ultrawork loop`, {
87798
+ parentSessionID: state3.session_id,
87799
+ recoveredVerificationSessionID
87800
+ });
87801
+ loopState.clear();
87802
+ showCompletionToastBestEffort(ctx, state3);
87803
+ return;
87804
+ }
87573
87805
  const updatedState = loopState.setVerificationSessionID(state3.session_id, recoveredVerificationSessionID);
87574
87806
  if (updatedState) {
87575
87807
  log(`[${HOOK_NAME3}] Recovered missing verification session from parent evidence`, {
@@ -87657,8 +87889,8 @@ var USER_MESSAGE_IN_PROGRESS_WINDOW_MS = 2000;
87657
87889
  function sleep(ms) {
87658
87890
  return ms > 0 ? new Promise((resolve14) => setTimeout(resolve14, ms)) : Promise.resolve();
87659
87891
  }
87660
- function hasRunningBackgroundTasks(backgroundManager, sessionID) {
87661
- return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
87892
+ function hasActiveBackgroundTasks(backgroundManager, sessionID) {
87893
+ return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "pending" || task.status === "running") : false;
87662
87894
  }
87663
87895
  function getRuntimeRetryActivitySessionID(eventType, props) {
87664
87896
  if (eventType === "message.updated") {
@@ -87841,8 +88073,8 @@ function createRalphLoopEventHandler(ctx, options) {
87841
88073
  if (!state3 || !state3.active) {
87842
88074
  return;
87843
88075
  }
87844
- if (hasRunningBackgroundTasks(options.backgroundManager, sessionID)) {
87845
- log(`[${HOOK_NAME3}] Skipped: background tasks running`, { sessionID });
88076
+ if (hasActiveBackgroundTasks(options.backgroundManager, sessionID)) {
88077
+ log(`[${HOOK_NAME3}] Skipped: background tasks active`, { sessionID });
87846
88078
  return;
87847
88079
  }
87848
88080
  const verificationSessionID = state3.verification_pending ? state3.verification_session_id : undefined;
@@ -88076,8 +88308,8 @@ function createRalphLoopEventHandler(ctx, options) {
88076
88308
  handleErroredLoopSession(props, options.loopState);
88077
88309
  return;
88078
88310
  }
88079
- if (hasRunningBackgroundTasks(options.backgroundManager, sessionID)) {
88080
- log(`[${HOOK_NAME3}] Skipped runtime error retry: background tasks running`, { sessionID });
88311
+ if (hasActiveBackgroundTasks(options.backgroundManager, sessionID)) {
88312
+ log(`[${HOOK_NAME3}] Skipped runtime error retry: background tasks active`, { sessionID });
88081
88313
  return;
88082
88314
  }
88083
88315
  log(`[${HOOK_NAME3}] Retrying after runtime session error`, {
@@ -91169,6 +91401,12 @@ var initDeepSkill = {
91169
91401
  template: loadSharedSkillTemplate("init-deep"),
91170
91402
  argumentHint: "[--create-new] [--max-depth=N]"
91171
91403
  };
91404
+ // src/features/builtin-skills/skills/debugging.ts
91405
+ var debuggingSkill = {
91406
+ name: "debugging",
91407
+ description: "MUST USE for any real runtime debugging across ANY language or binary \u2014 crashes, silent failures, wrong responses, stuck processes, memory leaks, async misbehavior, unexplained timing, reverse engineering. Runs a hypothesis-driven loop: form \u22653 hypotheses, investigate in parallel, after 2 failed rounds spawn Oracles from orthogonal angles, confirm root cause, lock with a failing test, fix minimally, QA by actually USING the system, scrub artifacts. The actual HOW lives in `references/` \u2014 READ THEM. Triggers: 'debug this', 'why is X not working', 'hanging', 'attach a debugger', 'reverse engineer', 'pwndbg', 'gdb', 'lldb', 'node inspect', 'tsx debug', 'pdb', 'dlv', 'delve', 'rust-gdb', 'set a breakpoint', 'context window exploded', 'why is the response empty', 'attach the debugger', 'debug it', 'why is this happening', 'trace this bug', 'reproduce and fix', 'silent failure', 'HTTP 200 but empty', 'why did it stop', 'inspect the binary', 'reverse engineering', 'playwright'.",
91408
+ template: loadSharedSkillTemplate("debugging")
91409
+ };
91172
91410
  // src/features/builtin-skills/security-research/SKILL.md
91173
91411
  var SKILL_default = `# Security Research - Team Mode Vulnerability Audit
91174
91412
 
@@ -91604,6 +91842,7 @@ function createBuiltinSkills(options = {}) {
91604
91842
  reviewWorkSkill,
91605
91843
  removeAiSlopsSkill,
91606
91844
  initDeepSkill,
91845
+ debuggingSkill,
91607
91846
  securityResearchSkill,
91608
91847
  securityReviewSkill
91609
91848
  ];
@@ -92008,7 +92247,6 @@ var GitMasterConfigSchema = z17.object({
92008
92247
  import { z as z18 } from "zod";
92009
92248
  var HookNameSchema = z18.enum([
92010
92249
  "todo-continuation-enforcer",
92011
- "context-window-monitor",
92012
92250
  "session-recovery",
92013
92251
  "session-notification",
92014
92252
  "comment-checker",
@@ -92567,9 +92805,55 @@ async function discoverConfigSourceSkills(options) {
92567
92805
  }));
92568
92806
  return deduplicateSkillsByName(loadedBySource.flat());
92569
92807
  }
92808
+ // src/features/opencode-skill-loader/opencode-config-skills-reader.ts
92809
+ init_jsonc_parser2();
92810
+ init_opencode_config_dir();
92811
+ import * as fs21 from "fs";
92812
+ import * as path17 from "path";
92813
+ function getConfigPaths3(directory) {
92814
+ const globalConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
92815
+ return [
92816
+ path17.join(directory, ".opencode", "opencode.json"),
92817
+ path17.join(directory, ".opencode", "opencode.jsonc"),
92818
+ path17.join(globalConfigDir, "opencode.json"),
92819
+ path17.join(globalConfigDir, "opencode.jsonc")
92820
+ ];
92821
+ }
92822
+ function toStringArray(value) {
92823
+ if (!Array.isArray(value))
92824
+ return [];
92825
+ return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
92826
+ }
92827
+ function readOpencodeConfigSkills(directory) {
92828
+ const paths = [];
92829
+ const urls = [];
92830
+ for (const configPath of getConfigPaths3(directory)) {
92831
+ try {
92832
+ if (!fs21.existsSync(configPath))
92833
+ continue;
92834
+ const content = fs21.readFileSync(configPath, "utf-8");
92835
+ const parseResult = parseJsoncSafe(content);
92836
+ if (!parseResult.data?.skills)
92837
+ continue;
92838
+ for (const p of toStringArray(parseResult.data.skills.paths)) {
92839
+ if (!paths.includes(p))
92840
+ paths.push(p);
92841
+ }
92842
+ for (const u of toStringArray(parseResult.data.skills.urls)) {
92843
+ if (!urls.includes(u))
92844
+ urls.push(u);
92845
+ }
92846
+ } catch {
92847
+ continue;
92848
+ }
92849
+ }
92850
+ if (paths.length === 0 && urls.length === 0)
92851
+ return;
92852
+ return { paths, urls };
92853
+ }
92570
92854
  // src/tools/slashcommand/command-discovery.ts
92571
- import { existsSync as existsSync63, readdirSync as readdirSync19, readFileSync as readFileSync46, statSync as statSync9 } from "fs";
92572
- import { basename as basename9, join as join75 } from "path";
92855
+ import { existsSync as existsSync64, readdirSync as readdirSync19, readFileSync as readFileSync47, statSync as statSync9 } from "fs";
92856
+ import { basename as basename9, join as join76 } from "path";
92573
92857
 
92574
92858
  // src/tools/slashcommand/command-discovery-deps.ts
92575
92859
  init_excluded_dirs();
@@ -94112,7 +94396,7 @@ function loadBuiltinCommands(disabledCommands, options) {
94112
94396
  // src/tools/slashcommand/command-discovery.ts
94113
94397
  var NESTED_COMMAND_SEPARATOR = "/";
94114
94398
  function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
94115
- if (!existsSync63(commandsDir))
94399
+ if (!existsSync64(commandsDir))
94116
94400
  return [];
94117
94401
  if (!statSync9(commandsDir).isDirectory()) {
94118
94402
  log(`[command-discovery] Skipping non-directory path: ${commandsDir}`);
@@ -94127,16 +94411,16 @@ function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
94127
94411
  if (entry.name.startsWith("."))
94128
94412
  continue;
94129
94413
  const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` : entry.name;
94130
- commands2.push(...discoverCommandsFromDir(join75(commandsDir, entry.name), scope, nestedPrefix));
94414
+ commands2.push(...discoverCommandsFromDir(join76(commandsDir, entry.name), scope, nestedPrefix));
94131
94415
  continue;
94132
94416
  }
94133
94417
  if (!isMarkdownFile(entry))
94134
94418
  continue;
94135
- const commandPath = join75(commandsDir, entry.name);
94419
+ const commandPath = join76(commandsDir, entry.name);
94136
94420
  const baseCommandName = basename9(entry.name, ".md");
94137
94421
  const commandName = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` : baseCommandName;
94138
94422
  try {
94139
- const content = readFileSync46(commandPath, "utf-8");
94423
+ const content = readFileSync47(commandPath, "utf-8");
94140
94424
  const { data, body } = parseFrontmatter(content);
94141
94425
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
94142
94426
  const metadata = {
@@ -94188,8 +94472,8 @@ function deduplicateCommandInfosByName(commands2) {
94188
94472
  return deduplicatedCommands;
94189
94473
  }
94190
94474
  function discoverCommandsSync(directory, options) {
94191
- const userCommandsDir = join75(getClaudeConfigDir(), "commands");
94192
- const projectCommandsDir = join75(directory ?? process.cwd(), ".claude", "commands");
94475
+ const userCommandsDir = join76(getClaudeConfigDir(), "commands");
94476
+ const projectCommandsDir = join76(directory ?? process.cwd(), ".claude", "commands");
94193
94477
  const opencodeGlobalDirs = getOpenCodeCommandDirs({ binary: "opencode" });
94194
94478
  const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd());
94195
94479
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
@@ -94689,7 +94973,7 @@ var NOTEPAD_DIR = "notepads";
94689
94973
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
94690
94974
  var PROMETHEUS_PLANS_DIR = ".omo/plans";
94691
94975
  // packages/boulder-state/src/top-level-task.ts
94692
- import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
94976
+ import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
94693
94977
  var TODO_HEADING_PATTERN = /^##\s+TODOs\b/i;
94694
94978
  var FINAL_VERIFICATION_HEADING_PATTERN = /^##\s+Final Verification Wave\b/i;
94695
94979
  var SECOND_LEVEL_HEADING_PATTERN = /^##\s+/;
@@ -94712,11 +94996,11 @@ function buildTaskRef(section, taskLabel) {
94712
94996
  };
94713
94997
  }
94714
94998
  function readCurrentTopLevelTask(planPath) {
94715
- if (!existsSync64(planPath)) {
94999
+ if (!existsSync65(planPath)) {
94716
95000
  return null;
94717
95001
  }
94718
95002
  try {
94719
- const content = readFileSync47(planPath, "utf-8");
95003
+ const content = readFileSync48(planPath, "utf-8");
94720
95004
  const lines = content.split(/\r?\n/);
94721
95005
  let section = "other";
94722
95006
  for (const line of lines) {
@@ -94741,10 +95025,10 @@ function readCurrentTopLevelTask(planPath) {
94741
95025
  }
94742
95026
  }
94743
95027
  // packages/boulder-state/src/storage/path.ts
94744
- import { existsSync as existsSync65 } from "fs";
94745
- import { isAbsolute as isAbsolute13, join as join76, relative as relative11, resolve as resolve15 } from "path";
95028
+ import { existsSync as existsSync66 } from "fs";
95029
+ import { isAbsolute as isAbsolute13, join as join77, relative as relative11, resolve as resolve15 } from "path";
94746
95030
  function getBoulderFilePath(directory) {
94747
- return join76(directory, BOULDER_DIR, BOULDER_FILE);
95031
+ return join77(directory, BOULDER_DIR, BOULDER_FILE);
94748
95032
  }
94749
95033
  function resolveTrackedPath(baseDirectory, trackedPath) {
94750
95034
  return isAbsolute13(trackedPath) ? resolve15(trackedPath) : resolve15(baseDirectory, trackedPath);
@@ -94762,14 +95046,14 @@ function resolveBoulderPlanPath(directory, state3) {
94762
95046
  }
94763
95047
  const absoluteWorktreePath = resolveTrackedPath(directory, worktreePath);
94764
95048
  const worktreePlanPath = resolve15(absoluteWorktreePath, relativePlanPath);
94765
- return existsSync65(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
95049
+ return existsSync66(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
94766
95050
  }
94767
95051
  function resolveBoulderPlanPathForWork(directory, work) {
94768
95052
  return resolveBoulderPlanPath(directory, work);
94769
95053
  }
94770
95054
  // packages/boulder-state/src/storage/plan-progress.ts
94771
- import { existsSync as existsSync66, readFileSync as readFileSync48, readdirSync as readdirSync20, statSync as statSync10 } from "fs";
94772
- import { basename as basename10, join as join77 } from "path";
95055
+ import { existsSync as existsSync67, readFileSync as readFileSync49, readdirSync as readdirSync20, statSync as statSync10 } from "fs";
95056
+ import { basename as basename10, join as join78 } from "path";
94773
95057
  var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
94774
95058
  var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
94775
95059
  var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
@@ -94782,11 +95066,11 @@ var PROMETHEUS_PLAN_DIRS = [PROMETHEUS_PLANS_DIR, LEGACY_PROMETHEUS_PLANS_DIR];
94782
95066
  function findPrometheusPlans(directory) {
94783
95067
  try {
94784
95068
  return PROMETHEUS_PLAN_DIRS.flatMap((planDir) => {
94785
- const plansDir = join77(directory, planDir);
94786
- if (!existsSync66(plansDir)) {
95069
+ const plansDir = join78(directory, planDir);
95070
+ if (!existsSync67(plansDir)) {
94787
95071
  return [];
94788
95072
  }
94789
- return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) => join77(plansDir, file));
95073
+ return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) => join78(plansDir, file));
94790
95074
  }).sort((left, right) => statSync10(right).mtimeMs - statSync10(left).mtimeMs);
94791
95075
  } catch {
94792
95076
  return [];
@@ -94796,11 +95080,11 @@ function getPlanName(planPath) {
94796
95080
  return basename10(planPath, ".md");
94797
95081
  }
94798
95082
  function getPlanProgress(planPath) {
94799
- if (!existsSync66(planPath)) {
95083
+ if (!existsSync67(planPath)) {
94800
95084
  return { total: 0, completed: 0, isComplete: false };
94801
95085
  }
94802
95086
  try {
94803
- const content = readFileSync48(planPath, "utf-8");
95087
+ const content = readFileSync49(planPath, "utf-8");
94804
95088
  const lines = content.split(/\r?\n/);
94805
95089
  const hasStructuredSections = lines.some((line) => TODO_HEADING_PATTERN2.test(line) || FINAL_VERIFICATION_HEADING_PATTERN2.test(line));
94806
95090
  if (hasStructuredSections) {
@@ -94930,14 +95214,14 @@ function selectMirrorWork(state3) {
94930
95214
  return sorted[0] ?? null;
94931
95215
  }
94932
95216
  // packages/boulder-state/src/storage/read-state.ts
94933
- import { existsSync as existsSync67, readFileSync as readFileSync49 } from "fs";
95217
+ import { existsSync as existsSync68, readFileSync as readFileSync50 } from "fs";
94934
95218
  function readBoulderState(directory) {
94935
95219
  const filePath = getBoulderFilePath(directory);
94936
- if (!existsSync67(filePath)) {
95220
+ if (!existsSync68(filePath)) {
94937
95221
  return null;
94938
95222
  }
94939
95223
  try {
94940
- const content = readFileSync49(filePath, "utf-8");
95224
+ const content = readFileSync50(filePath, "utf-8");
94941
95225
  const parsed = JSON.parse(content);
94942
95226
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
94943
95227
  return null;
@@ -95068,13 +95352,13 @@ function getTaskSessionState(directory, taskKey) {
95068
95352
  return state3.task_sessions[taskKey] ?? null;
95069
95353
  }
95070
95354
  // packages/boulder-state/src/storage/write-state.ts
95071
- import { existsSync as existsSync68, mkdirSync as mkdirSync17, unlinkSync as unlinkSync13, writeFileSync as writeFileSync18 } from "fs";
95355
+ import { existsSync as existsSync69, mkdirSync as mkdirSync17, unlinkSync as unlinkSync13, writeFileSync as writeFileSync18 } from "fs";
95072
95356
  import { dirname as dirname25 } from "path";
95073
95357
  function writeBoulderState(directory, state3) {
95074
95358
  const filePath = getBoulderFilePath(directory);
95075
95359
  try {
95076
95360
  const dir = dirname25(filePath);
95077
- if (!existsSync68(dir)) {
95361
+ if (!existsSync69(dir)) {
95078
95362
  mkdirSync17(dir, { recursive: true });
95079
95363
  }
95080
95364
  const stateToWrite = { ...state3 };
@@ -95110,7 +95394,7 @@ function writeBoulderState(directory, state3) {
95110
95394
  function clearBoulderState(directory) {
95111
95395
  const filePath = getBoulderFilePath(directory);
95112
95396
  try {
95113
- if (existsSync68(filePath)) {
95397
+ if (existsSync69(filePath)) {
95114
95398
  unlinkSync13(filePath);
95115
95399
  }
95116
95400
  return true;
@@ -95815,6 +96099,23 @@ function buildExplicitPlanContext(params) {
95815
96099
  const allPlans = findPrometheusPlans(directory);
95816
96100
  const matchedPlan = findPlanByName(allPlans, explicitPlanName);
95817
96101
  if (!matchedPlan) {
96102
+ const incompletePlans = allPlans.filter((planPath) => !getPlanProgress(planPath).isComplete);
96103
+ if (incompletePlans.length === 1) {
96104
+ createNewWorkOrInitialize({
96105
+ directory,
96106
+ planPath: incompletePlans[0],
96107
+ sessionId,
96108
+ activeAgent,
96109
+ worktreePath
96110
+ });
96111
+ return buildAutoSelectedPlanContextInfoOnly({
96112
+ planPath: incompletePlans[0],
96113
+ sessionId,
96114
+ timestamp: timestamp2,
96115
+ worktreeBlock,
96116
+ reason: `Only incomplete plan available after "${explicitPlanName}" did not match any plan`
96117
+ });
96118
+ }
95818
96119
  return buildMissingPlanContext(explicitPlanName, allPlans);
95819
96120
  }
95820
96121
  const progress = getPlanProgress(matchedPlan);
@@ -96221,8 +96522,8 @@ function isAbortError2(error) {
96221
96522
  // src/hooks/atlas/session-last-agent.ts
96222
96523
  init_shared();
96223
96524
  init_compaction_marker();
96224
- import { readFileSync as readFileSync50, readdirSync as readdirSync21 } from "fs";
96225
- import { join as join78 } from "path";
96525
+ import { readFileSync as readFileSync51, readdirSync as readdirSync21 } from "fs";
96526
+ import { join as join79 } from "path";
96226
96527
  var defaultSessionLastAgentDeps = {
96227
96528
  getMessageDir,
96228
96529
  isSqliteBackend,
@@ -96276,7 +96577,7 @@ async function getLastAgentFromSession(sessionID, client, deps = {}) {
96276
96577
  try {
96277
96578
  const messages = readdirSync21(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
96278
96579
  try {
96279
- const content = readFileSync50(join78(messageDir, fileName), "utf-8");
96580
+ const content = readFileSync51(join79(messageDir, fileName), "utf-8");
96280
96581
  const parsed = JSON.parse(content);
96281
96582
  return {
96282
96583
  fileName,
@@ -96796,7 +97097,7 @@ function getTaskLabelSortValue(taskLabel) {
96796
97097
  const parsed = Number.parseInt(taskLabel.replace(/[^0-9]/g, ""), 10);
96797
97098
  return Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed;
96798
97099
  }
96799
- function hasRunningBackgroundTasks2(sessionID, options) {
97100
+ function hasRunningBackgroundTasks(sessionID, options) {
96800
97101
  const backgroundManager = options?.backgroundManager;
96801
97102
  return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
96802
97103
  }
@@ -96925,7 +97226,7 @@ function scheduleRetry(input) {
96925
97226
  });
96926
97227
  if (!canContinueSession)
96927
97228
  return;
96928
- if (hasRunningBackgroundTasks2(sessionID, options)) {
97229
+ if (hasRunningBackgroundTasks(sessionID, options)) {
96929
97230
  scheduleRetry({ ctx, sessionID, sessionState, options });
96930
97231
  return;
96931
97232
  }
@@ -97111,7 +97412,7 @@ async function handleAtlasSessionIdle(input) {
97111
97412
  sessionState.promptFailureCount = 0;
97112
97413
  sessionState.lastFailureAt = undefined;
97113
97414
  }
97114
- if (hasRunningBackgroundTasks2(sessionID, options)) {
97415
+ if (hasRunningBackgroundTasks(sessionID, options)) {
97115
97416
  scheduleRetry({ ctx, sessionID, sessionState, options });
97116
97417
  log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
97117
97418
  return;
@@ -97271,7 +97572,7 @@ function createAtlasEventHandler(input) {
97271
97572
  // src/hooks/atlas/tool-execute-after.ts
97272
97573
  init_logger();
97273
97574
  init_session_utils();
97274
- import { existsSync as existsSync70, readFileSync as readFileSync52 } from "fs";
97575
+ import { existsSync as existsSync71, readFileSync as readFileSync53 } from "fs";
97275
97576
  import { resolve as resolve18 } from "path";
97276
97577
 
97277
97578
  // src/hooks/atlas/background-launch-session-tracking.ts
@@ -97419,7 +97720,7 @@ async function resolveFallbackTrackedSessionId(input) {
97419
97720
  init_git_worktree();
97420
97721
 
97421
97722
  // src/hooks/atlas/final-wave-plan-state.ts
97422
- import { existsSync as existsSync69, readFileSync as readFileSync51 } from "fs";
97723
+ import { existsSync as existsSync70, readFileSync as readFileSync52 } from "fs";
97423
97724
  var TODO_HEADING_PATTERN3 = /^##\s+TODOs\b/i;
97424
97725
  var FINAL_VERIFICATION_HEADING_PATTERN3 = /^##\s+Final Verification Wave\b/i;
97425
97726
  var SECOND_LEVEL_HEADING_PATTERN3 = /^##\s+/;
@@ -97427,11 +97728,11 @@ var UNCHECKED_CHECKBOX_PATTERN3 = /^\s*[-*]\s*\[\s*\]\s*(.+)$/;
97427
97728
  var TODO_TASK_PATTERN3 = /^\d+\./;
97428
97729
  var FINAL_WAVE_TASK_PATTERN3 = /^F\d+\./i;
97429
97730
  function readFinalWavePlanState(planPath) {
97430
- if (!existsSync69(planPath)) {
97731
+ if (!existsSync70(planPath)) {
97431
97732
  return null;
97432
97733
  }
97433
97734
  try {
97434
- const content = readFileSync51(planPath, "utf-8");
97735
+ const content = readFileSync52(planPath, "utf-8");
97435
97736
  const lines = content.split(/\r?\n/);
97436
97737
  let section = "other";
97437
97738
  let pendingImplementationTaskCount = 0;
@@ -97681,7 +97982,7 @@ function isWriteOrEditToolName(toolName) {
97681
97982
 
97682
97983
  // src/hooks/atlas/tool-execute-after.ts
97683
97984
  function isTrackedTaskChecked(planPath, taskKey) {
97684
- if (!existsSync70(planPath)) {
97985
+ if (!existsSync71(planPath)) {
97685
97986
  return false;
97686
97987
  }
97687
97988
  const [section, label] = taskKey.split(":");
@@ -97694,7 +97995,7 @@ function isTrackedTaskChecked(planPath, taskKey) {
97694
97995
  return false;
97695
97996
  }
97696
97997
  try {
97697
- const content = readFileSync52(planPath, "utf-8");
97998
+ const content = readFileSync53(planPath, "utf-8");
97698
97999
  return matcher.test(content);
97699
98000
  } catch {
97700
98001
  return false;
@@ -97738,11 +98039,11 @@ function parseCheckedTopLevelTaskKeys(planContent) {
97738
98039
  return checkedKeys;
97739
98040
  }
97740
98041
  function readCheckedTaskKeysFromPlan(planPath) {
97741
- if (!existsSync70(planPath)) {
98042
+ if (!existsSync71(planPath)) {
97742
98043
  return new Set;
97743
98044
  }
97744
98045
  try {
97745
- return parseCheckedTopLevelTaskKeys(readFileSync52(planPath, "utf-8"));
98046
+ return parseCheckedTopLevelTaskKeys(readFileSync53(planPath, "utf-8"));
97746
98047
  } catch {
97747
98048
  return new Set;
97748
98049
  }
@@ -97949,7 +98250,7 @@ init_logger();
97949
98250
  init_replace_tool_args();
97950
98251
  init_system_directive();
97951
98252
  init_session_utils();
97952
- import { existsSync as existsSync71, readFileSync as readFileSync53 } from "fs";
98253
+ import { existsSync as existsSync72, readFileSync as readFileSync54 } from "fs";
97953
98254
  import { resolve as resolve19 } from "path";
97954
98255
  var TASK_SECTION_HEADER_PATTERN = /^##\s*1\.\s*TASK\s*$/i;
97955
98256
  var TODO_TASK_LINE_PATTERN = /^(?:[-*]\s*\[\s*\]\s*)?(\d+)\.\s+(.+)$/;
@@ -98010,8 +98311,8 @@ function createToolExecuteBeforeHandler2(input) {
98010
98311
  const planPath = sessionWork ? resolveBoulderPlanPathForWork(ctx.directory, sessionWork) : state3 ? resolveBoulderPlanPath(ctx.directory, state3) : null;
98011
98312
  if (planPath && resolve19(filePath) === resolve19(planPath) && pendingPlanSnapshots) {
98012
98313
  try {
98013
- if (existsSync71(planPath)) {
98014
- pendingPlanSnapshots.set(toolInput.callID, readFileSync53(planPath, "utf-8"));
98314
+ if (existsSync72(planPath)) {
98315
+ pendingPlanSnapshots.set(toolInput.callID, readFileSync54(planPath, "utf-8"));
98015
98316
  }
98016
98317
  } catch {
98017
98318
  pendingPlanSnapshots.delete(toolInput.callID);
@@ -99871,16 +100172,16 @@ function createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState) {
99871
100172
  init_shared();
99872
100173
 
99873
100174
  // src/hooks/tasks-todowrite-disabler/constants.ts
99874
- var BLOCKED_TOOLS2 = ["TodoWrite", "TodoRead"];
99875
- var REPLACEMENT_MESSAGE = `TodoRead/TodoWrite are DISABLED because experimental.task_system is enabled.
100175
+ var BLOCKED_TOOLS2 = ["TodoRead"];
100176
+ var REPLACEMENT_MESSAGE = `TodoRead is DISABLED because experimental.task_system is enabled.
99876
100177
 
99877
- **ACTION REQUIRED**: RE-REGISTER what you were about to write as Todo using Task tools NOW. Then ASSIGN yourself and START WORKING immediately.
100178
+ **ACTION REQUIRED**: Use Task tools to inspect work state. TodoWrite is still allowed so the live todo panel keeps updating, but reads belong to the task system.
99878
100179
 
99879
- **Use these tools instead:**
99880
- - TaskCreate: Create new task with auto-generated ID
99881
- - TaskUpdate: Update status, assign owner, add dependencies
100180
+ **Use these tools instead of TodoRead:**
99882
100181
  - TaskList: List active tasks with dependency info
99883
100182
  - TaskGet: Get full task details
100183
+ - TaskCreate: Create new task with auto-generated ID
100184
+ - TaskUpdate: Update status, assign owner, add dependencies
99884
100185
 
99885
100186
  **Workflow:**
99886
100187
  1. TaskCreate({ subject: "your task description" })
@@ -99899,7 +100200,7 @@ Even if the task seems trivial (1 line fix, simple edit, quick change), you MUST
99899
100200
 
99900
100201
  **WHY?** Task tracking = visibility = accountability. Skipping registration = invisible work = chaos.
99901
100202
 
99902
- DO NOT retry TodoWrite. Convert to TaskCreate NOW.`;
100203
+ DO NOT retry TodoRead. Use TaskList or TaskGet NOW.`;
99903
100204
 
99904
100205
  // src/hooks/tasks-todowrite-disabler/hook.ts
99905
100206
  function createTasksTodowriteDisablerHook(config) {
@@ -100345,6 +100646,7 @@ function getLastUserRetryPayload(messagesResponse, sessionID) {
100345
100646
  }
100346
100647
 
100347
100648
  // src/hooks/runtime-fallback/auto-retry.ts
100649
+ init_internal_initiator_marker();
100348
100650
  var SESSION_TTL_MS = 30 * 60 * 1000;
100349
100651
  function createAutoRetryHelpers(deps) {
100350
100652
  const {
@@ -100457,7 +100759,7 @@ function createAutoRetryHelpers(deps) {
100457
100759
  sessionID,
100458
100760
  hint: "This can occur when the working directory contains .git and messages are not yet persisted"
100459
100761
  });
100460
- return [{ type: "text", text: "continue" }];
100762
+ return [createInternalAgentContinuationTextPart("continue")];
100461
100763
  })();
100462
100764
  log(`[${HOOK_NAME11}] Auto-retrying with fallback model (${source})`, {
100463
100765
  sessionID,
@@ -101751,12 +102053,12 @@ function createRuntimeFallbackHook(ctx, options, factoryOverrides = {}) {
101751
102053
  };
101752
102054
  }
101753
102055
  // src/hooks/write-existing-file-guard/hook.ts
101754
- import { existsSync as existsSync73, realpathSync as realpathSync8 } from "fs";
101755
- import { basename as basename11, dirname as dirname26, isAbsolute as isAbsolute16, join as join79, normalize as normalize2, relative as relative13, resolve as resolve20 } from "path";
102056
+ import { existsSync as existsSync74, realpathSync as realpathSync8 } from "fs";
102057
+ import { basename as basename11, dirname as dirname26, isAbsolute as isAbsolute16, join as join80, normalize as normalize2, relative as relative13, resolve as resolve20 } from "path";
101756
102058
 
101757
102059
  // src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
101758
102060
  init_shared();
101759
- import { existsSync as existsSync72 } from "fs";
102061
+ import { existsSync as existsSync73 } from "fs";
101760
102062
 
101761
102063
  // src/hooks/write-existing-file-guard/session-read-permissions.ts
101762
102064
  function touchSession(sessionLastAccess, sessionID) {
@@ -101857,7 +102159,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
101857
102159
  return;
101858
102160
  }
101859
102161
  if (toolName === "read") {
101860
- if (!existsSync72(resolvedPath) || !input.sessionID) {
102162
+ if (!existsSync73(resolvedPath) || !input.sessionID) {
101861
102163
  return;
101862
102164
  }
101863
102165
  registerReadPermission({
@@ -101874,7 +102176,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
101874
102176
  if (argsRecord && "overwrite" in argsRecord) {
101875
102177
  delete argsRecord.overwrite;
101876
102178
  }
101877
- if (!existsSync72(resolvedPath)) {
102179
+ if (!existsSync73(resolvedPath)) {
101878
102180
  return;
101879
102181
  }
101880
102182
  if (isOmoWorkspacePath(canonicalPath)) {
@@ -101933,7 +102235,7 @@ function isPathInsideDirectory(pathToCheck, directory) {
101933
102235
  }
101934
102236
  function toCanonicalPath2(absolutePath) {
101935
102237
  let canonicalPath = absolutePath;
101936
- if (existsSync73(absolutePath)) {
102238
+ if (existsSync74(absolutePath)) {
101937
102239
  try {
101938
102240
  canonicalPath = realpathSync8.native(absolutePath);
101939
102241
  } catch {
@@ -101941,8 +102243,8 @@ function toCanonicalPath2(absolutePath) {
101941
102243
  }
101942
102244
  } else {
101943
102245
  const absoluteDir = dirname26(absolutePath);
101944
- const resolvedDir = existsSync73(absoluteDir) ? realpathSync8.native(absoluteDir) : absoluteDir;
101945
- canonicalPath = join79(resolvedDir, basename11(absolutePath));
102246
+ const resolvedDir = existsSync74(absoluteDir) ? realpathSync8.native(absoluteDir) : absoluteDir;
102247
+ canonicalPath = join80(resolvedDir, basename11(absolutePath));
101946
102248
  }
101947
102249
  return normalize2(canonicalPath);
101948
102250
  }
@@ -102986,16 +103288,16 @@ class Diff {
102986
103288
  }
102987
103289
  }
102988
103290
  }
102989
- addToPath(path17, added, removed, oldPosInc, options) {
102990
- const last = path17.lastComponent;
103291
+ addToPath(path18, added, removed, oldPosInc, options) {
103292
+ const last = path18.lastComponent;
102991
103293
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
102992
103294
  return {
102993
- oldPos: path17.oldPos + oldPosInc,
103295
+ oldPos: path18.oldPos + oldPosInc,
102994
103296
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
102995
103297
  };
102996
103298
  } else {
102997
103299
  return {
102998
- oldPos: path17.oldPos + oldPosInc,
103300
+ oldPos: path18.oldPos + oldPosInc,
102999
103301
  lastComponent: { count: 1, added, removed, previousComponent: last }
103000
103302
  };
103001
103303
  }
@@ -104657,8 +104959,8 @@ init_jsonc_parser2();
104657
104959
  init_opencode_config_dir();
104658
104960
  init_plugin_identity();
104659
104961
  init_plugin_entry_migrator();
104660
- import { existsSync as existsSync74, readFileSync as readFileSync54 } from "fs";
104661
- import { join as join80 } from "path";
104962
+ import { existsSync as existsSync75, readFileSync as readFileSync55 } from "fs";
104963
+ import { join as join81 } from "path";
104662
104964
 
104663
104965
  // src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts
104664
104966
  init_migrate_legacy_plugin_entry();
@@ -104666,18 +104968,18 @@ init_migrate_legacy_plugin_entry();
104666
104968
  // src/hooks/legacy-plugin-toast/auto-migrate.ts
104667
104969
  function detectOpenCodeConfigPath(overrideConfigDir) {
104668
104970
  if (overrideConfigDir) {
104669
- const jsoncPath = join80(overrideConfigDir, "opencode.jsonc");
104670
- const jsonPath = join80(overrideConfigDir, "opencode.json");
104671
- if (existsSync74(jsoncPath))
104971
+ const jsoncPath = join81(overrideConfigDir, "opencode.jsonc");
104972
+ const jsonPath = join81(overrideConfigDir, "opencode.json");
104973
+ if (existsSync75(jsoncPath))
104672
104974
  return jsoncPath;
104673
- if (existsSync74(jsonPath))
104975
+ if (existsSync75(jsonPath))
104674
104976
  return jsonPath;
104675
104977
  return null;
104676
104978
  }
104677
104979
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
104678
- if (existsSync74(paths.configJsonc))
104980
+ if (existsSync75(paths.configJsonc))
104679
104981
  return paths.configJsonc;
104680
- if (existsSync74(paths.configJson))
104982
+ if (existsSync75(paths.configJson))
104681
104983
  return paths.configJson;
104682
104984
  return null;
104683
104985
  }
@@ -104686,7 +104988,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
104686
104988
  if (!configPath)
104687
104989
  return { migrated: false, from: null, to: null, configPath: null };
104688
104990
  try {
104689
- const content = readFileSync54(configPath, "utf-8");
104991
+ const content = readFileSync55(configPath, "utf-8");
104690
104992
  const parseResult = parseJsoncSafe(content);
104691
104993
  if (!parseResult.data?.plugin)
104692
104994
  return { migrated: false, from: null, to: null, configPath };
@@ -104870,7 +105172,7 @@ function createNotepadWriteGuardHook() {
104870
105172
  };
104871
105173
  }
104872
105174
  // src/hooks/plan-format-validator/hook.ts
104873
- import { existsSync as existsSync75, readFileSync as readFileSync55 } from "fs";
105175
+ import { existsSync as existsSync76, readFileSync as readFileSync56 } from "fs";
104874
105176
  import { resolve as resolve21 } from "path";
104875
105177
  init_logger();
104876
105178
  var WRITE_TOOLS = new Set(["Write", "Edit", "write", "edit"]);
@@ -104954,9 +105256,9 @@ function createPlanFormatValidatorHook(_ctx) {
104954
105256
  if (!isPlanFilePath(filePath))
104955
105257
  return;
104956
105258
  const resolvedPath = resolve21(_ctx.directory, filePath);
104957
- if (!existsSync75(resolvedPath))
105259
+ if (!existsSync76(resolvedPath))
104958
105260
  return;
104959
- const content = readFileSync55(resolvedPath, "utf-8");
105261
+ const content = readFileSync56(resolvedPath, "utf-8");
104960
105262
  if (!CHECKBOX_PATTERN.test(content))
104961
105263
  return;
104962
105264
  const rawCount = countRawTopLevelCheckboxes(content);
@@ -105086,21 +105388,21 @@ tool.schema = z36;
105086
105388
 
105087
105389
  // src/shared/ripgrep-cli.ts
105088
105390
  import { spawnSync as spawnSync2 } from "child_process";
105089
- import { existsSync as existsSync77 } from "fs";
105090
- import { dirname as dirname27, join as join82 } from "path";
105391
+ import { existsSync as existsSync78 } from "fs";
105392
+ import { dirname as dirname27, join as join83 } from "path";
105091
105393
 
105092
105394
  // src/tools/grep/downloader.ts
105093
105395
  init_shared();
105094
105396
  init_plugin_identity();
105095
105397
  init_binary_downloader();
105096
- import { existsSync as existsSync76, readdirSync as readdirSync22 } from "fs";
105097
- import { join as join81 } from "path";
105398
+ import { existsSync as existsSync77, readdirSync as readdirSync22 } from "fs";
105399
+ import { join as join82 } from "path";
105098
105400
  function findFileRecursive(dir, filename) {
105099
105401
  try {
105100
105402
  const entries = readdirSync22(dir, { withFileTypes: true, recursive: true });
105101
105403
  for (const entry of entries) {
105102
105404
  if (entry.isFile() && entry.name === filename) {
105103
- return join81(entry.parentPath ?? dir, entry.name);
105405
+ return join82(entry.parentPath ?? dir, entry.name);
105104
105406
  }
105105
105407
  }
105106
105408
  } catch {
@@ -105121,11 +105423,11 @@ function getPlatformKey() {
105121
105423
  }
105122
105424
  function getInstallDir() {
105123
105425
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
105124
- return join81(homeDir, ".cache", CACHE_DIR_NAME, "bin");
105426
+ return join82(homeDir, ".cache", CACHE_DIR_NAME, "bin");
105125
105427
  }
105126
105428
  function getRgPath() {
105127
105429
  const isWindows2 = process.platform === "win32";
105128
- return join81(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
105430
+ return join82(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
105129
105431
  }
105130
105432
  async function extractTarGz2(archivePath, destDir) {
105131
105433
  const platformKey = getPlatformKey();
@@ -105142,7 +105444,7 @@ async function extractZip2(archivePath, destDir) {
105142
105444
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
105143
105445
  const foundPath = findFileRecursive(destDir, binaryName);
105144
105446
  if (foundPath) {
105145
- const destPath = join81(destDir, binaryName);
105447
+ const destPath = join82(destDir, binaryName);
105146
105448
  if (foundPath !== destPath) {
105147
105449
  const { renameSync: renameSync6 } = await import("fs");
105148
105450
  renameSync6(foundPath, destPath);
@@ -105157,13 +105459,13 @@ async function downloadAndInstallRipgrep() {
105157
105459
  }
105158
105460
  const installDir = getInstallDir();
105159
105461
  const rgPath = getRgPath();
105160
- if (existsSync76(rgPath)) {
105462
+ if (existsSync77(rgPath)) {
105161
105463
  return rgPath;
105162
105464
  }
105163
105465
  ensureCacheDir(installDir);
105164
105466
  const filename = `ripgrep-${RG_VERSION}-${config.platform}.${config.extension}`;
105165
105467
  const url = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
105166
- const archivePath = join81(installDir, filename);
105468
+ const archivePath = join82(installDir, filename);
105167
105469
  try {
105168
105470
  await downloadArchive(url, archivePath);
105169
105471
  if (config.extension === "tar.gz") {
@@ -105172,7 +105474,7 @@ async function downloadAndInstallRipgrep() {
105172
105474
  await extractZip2(archivePath, installDir);
105173
105475
  }
105174
105476
  ensureExecutable(rgPath);
105175
- if (!existsSync76(rgPath)) {
105477
+ if (!existsSync77(rgPath)) {
105176
105478
  throw new Error("ripgrep binary not found after extraction");
105177
105479
  }
105178
105480
  return rgPath;
@@ -105184,7 +105486,7 @@ async function downloadAndInstallRipgrep() {
105184
105486
  }
105185
105487
  function getInstalledRipgrepPath() {
105186
105488
  const rgPath = getRgPath();
105187
- return existsSync76(rgPath) ? rgPath : null;
105489
+ return existsSync77(rgPath) ? rgPath : null;
105188
105490
  }
105189
105491
 
105190
105492
  // src/shared/ripgrep-cli.ts
@@ -105220,15 +105522,15 @@ function getOpenCodeBundledRg() {
105220
105522
  const isWindows2 = process.platform === "win32";
105221
105523
  const rgName = isWindows2 ? "rg.exe" : "rg";
105222
105524
  const candidates = [
105223
- join82(getOpenCodeCacheDir(), "bin", rgName),
105224
- join82(getDataDir(), "opencode", "bin", rgName),
105225
- join82(execDir, rgName),
105226
- join82(execDir, "bin", rgName),
105227
- join82(execDir, "..", "bin", rgName),
105228
- join82(execDir, "..", "libexec", rgName)
105525
+ join83(getOpenCodeCacheDir(), "bin", rgName),
105526
+ join83(getDataDir(), "opencode", "bin", rgName),
105527
+ join83(execDir, rgName),
105528
+ join83(execDir, "bin", rgName),
105529
+ join83(execDir, "..", "bin", rgName),
105530
+ join83(execDir, "..", "libexec", rgName)
105229
105531
  ];
105230
105532
  for (const candidate of candidates) {
105231
- if (existsSync77(candidate)) {
105533
+ if (existsSync78(candidate)) {
105232
105534
  return candidate;
105233
105535
  }
105234
105536
  }
@@ -105971,10 +106273,13 @@ function formatSlashCommand(command) {
105971
106273
  return lines.join(`
105972
106274
  `);
105973
106275
  }
105974
- function formatCombinedDescription(skills2, commands2) {
105975
- const availableSkills = skills2 ?? [];
106276
+ function formatCombinedDescription(skills2, commands2, options = {}) {
106277
+ const availableSkills = options.includeSkills ? skills2 ?? [] : [];
105976
106278
  const availableCommands = commands2 ?? [];
105977
106279
  if (availableSkills.length === 0 && availableCommands.length === 0) {
106280
+ if ((skills2?.length ?? 0) > 0) {
106281
+ return TOOL_DESCRIPTION_PREFIX;
106282
+ }
105978
106283
  return TOOL_DESCRIPTION_NO_SKILLS;
105979
106284
  }
105980
106285
  const availableItems = [
@@ -105986,7 +106291,7 @@ function formatCombinedDescription(skills2, commands2) {
105986
106291
  }
105987
106292
  return `${TOOL_DESCRIPTION_PREFIX}
105988
106293
  <available_items>
105989
- Priority: project > user > opencode > builtin/plugin | Skills listed before commands
106294
+ Priority: project > user > opencode > builtin/plugin${options.includeSkills ? " | Skills listed before commands" : ""}
105990
106295
  Invoke via: skill(name="item-name") - omit leading slash for commands.
105991
106296
  ${availableItems.join(`
105992
106297
  `)}
@@ -106228,7 +106533,9 @@ function createSkillTool(options) {
106228
106533
  const commands2 = getCommands();
106229
106534
  const publicSkills = skills2.filter((s) => !s.definition.agent);
106230
106535
  const skillInfos = publicSkills.map(loadedSkillToInfo);
106231
- cachedDescription = formatCombinedDescription(skillInfos, commands2);
106536
+ cachedDescription = formatCombinedDescription(skillInfos, commands2, {
106537
+ includeSkills: options.includeSkillsInDescription
106538
+ });
106232
106539
  return cachedDescription;
106233
106540
  };
106234
106541
  if (options.skills !== undefined) {
@@ -106246,12 +106553,16 @@ function createSkillTool(options) {
106246
106553
  }
106247
106554
  } catch {}
106248
106555
  }
106249
- cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription);
106556
+ cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription, {
106557
+ includeSkills: options.includeSkillsInDescription
106558
+ });
106250
106559
  if (needsAsyncRefresh) {
106251
106560
  buildDescription(true);
106252
106561
  }
106253
106562
  } else if (options.commands !== undefined) {
106254
- cachedDescription = formatCombinedDescription([], options.commands);
106563
+ cachedDescription = formatCombinedDescription([], options.commands, {
106564
+ includeSkills: options.includeSkillsInDescription
106565
+ });
106255
106566
  }
106256
106567
  return tool({
106257
106568
  get description() {
@@ -106267,7 +106578,9 @@ function createSkillTool(options) {
106267
106578
  async execute(args, ctx) {
106268
106579
  const skills2 = await getSkills(ctx);
106269
106580
  const commands2 = getCommands();
106270
- cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2);
106581
+ cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2, {
106582
+ includeSkills: options.includeSkillsInDescription
106583
+ });
106271
106584
  const requestedName = args.name.replace(/^\//, "");
106272
106585
  const matchedSkill = matchSkillByName(skills2, requestedName);
106273
106586
  if (matchedSkill) {
@@ -106328,9 +106641,9 @@ var skill = createSkillTool({ directory: process.cwd() });
106328
106641
  // src/tools/session-manager/constants.ts
106329
106642
  init_shared();
106330
106643
  init_shared();
106331
- import { join as join83 } from "path";
106332
- var TODO_DIR2 = join83(getClaudeConfigDir(), "todos");
106333
- var TRANSCRIPT_DIR2 = join83(getClaudeConfigDir(), "transcripts");
106644
+ import { join as join84 } from "path";
106645
+ var TODO_DIR2 = join84(getClaudeConfigDir(), "todos");
106646
+ var TRANSCRIPT_DIR2 = join84(getClaudeConfigDir(), "transcripts");
106334
106647
  var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
106335
106648
 
106336
106649
  Returns a list of available session IDs with metadata including message count, date range, and agents used.
@@ -106407,12 +106720,12 @@ init_opencode_storage_detection();
106407
106720
  init_shared();
106408
106721
 
106409
106722
  // src/tools/session-manager/file-storage.ts
106410
- import { existsSync as existsSync78 } from "fs";
106723
+ import { existsSync as existsSync79 } from "fs";
106411
106724
  import { readdir as readdir5, readFile as readFile8 } from "fs/promises";
106412
- import { join as join84 } from "path";
106725
+ import { join as join85 } from "path";
106413
106726
  init_opencode_message_dir();
106414
106727
  async function getFileMainSessions(directory) {
106415
- if (!existsSync78(SESSION_STORAGE))
106728
+ if (!existsSync79(SESSION_STORAGE))
106416
106729
  return [];
106417
106730
  const sessions = [];
106418
106731
  try {
@@ -106420,13 +106733,13 @@ async function getFileMainSessions(directory) {
106420
106733
  for (const projectDir of projectDirs) {
106421
106734
  if (!projectDir.isDirectory())
106422
106735
  continue;
106423
- const projectPath = join84(SESSION_STORAGE, projectDir.name);
106736
+ const projectPath = join85(SESSION_STORAGE, projectDir.name);
106424
106737
  const sessionFiles = await readdir5(projectPath);
106425
106738
  for (const file of sessionFiles) {
106426
106739
  if (!file.endsWith(".json"))
106427
106740
  continue;
106428
106741
  try {
106429
- const content = await readFile8(join84(projectPath, file), "utf-8");
106742
+ const content = await readFile8(join85(projectPath, file), "utf-8");
106430
106743
  const meta = JSON.parse(content);
106431
106744
  if (meta.parentID)
106432
106745
  continue;
@@ -106444,7 +106757,7 @@ async function getFileMainSessions(directory) {
106444
106757
  return sessions.sort((a, b) => b.time.updated - a.time.updated);
106445
106758
  }
106446
106759
  async function getFileAllSessions() {
106447
- if (!existsSync78(MESSAGE_STORAGE))
106760
+ if (!existsSync79(MESSAGE_STORAGE))
106448
106761
  return [];
106449
106762
  const sessions = [];
106450
106763
  async function scanDirectory(dir) {
@@ -106453,7 +106766,7 @@ async function getFileAllSessions() {
106453
106766
  for (const entry of entries) {
106454
106767
  if (!entry.isDirectory())
106455
106768
  continue;
106456
- const sessionPath = join84(dir, entry.name);
106769
+ const sessionPath = join85(dir, entry.name);
106457
106770
  const files = await readdir5(sessionPath);
106458
106771
  if (files.some((file) => file.endsWith(".json"))) {
106459
106772
  sessions.push(entry.name);
@@ -106473,7 +106786,7 @@ async function fileSessionExists(sessionID) {
106473
106786
  }
106474
106787
  async function getFileSessionMessages(sessionID) {
106475
106788
  const messageDir = getMessageDir(sessionID);
106476
- if (!messageDir || !existsSync78(messageDir))
106789
+ if (!messageDir || !existsSync79(messageDir))
106477
106790
  return [];
106478
106791
  const messages = [];
106479
106792
  try {
@@ -106482,7 +106795,7 @@ async function getFileSessionMessages(sessionID) {
106482
106795
  if (!file.endsWith(".json"))
106483
106796
  continue;
106484
106797
  try {
106485
- const content = await readFile8(join84(messageDir, file), "utf-8");
106798
+ const content = await readFile8(join85(messageDir, file), "utf-8");
106486
106799
  const meta = JSON.parse(content);
106487
106800
  const parts = await readParts2(meta.id);
106488
106801
  messages.push({
@@ -106508,8 +106821,8 @@ async function getFileSessionMessages(sessionID) {
106508
106821
  });
106509
106822
  }
106510
106823
  async function readParts2(messageID) {
106511
- const partDir = join84(PART_STORAGE, messageID);
106512
- if (!existsSync78(partDir))
106824
+ const partDir = join85(PART_STORAGE, messageID);
106825
+ if (!existsSync79(partDir))
106513
106826
  return [];
106514
106827
  const parts = [];
106515
106828
  try {
@@ -106518,7 +106831,7 @@ async function readParts2(messageID) {
106518
106831
  if (!file.endsWith(".json"))
106519
106832
  continue;
106520
106833
  try {
106521
- const content = await readFile8(join84(partDir, file), "utf-8");
106834
+ const content = await readFile8(join85(partDir, file), "utf-8");
106522
106835
  parts.push(JSON.parse(content));
106523
106836
  } catch {
106524
106837
  continue;
@@ -106530,14 +106843,14 @@ async function readParts2(messageID) {
106530
106843
  return parts.sort((a, b) => a.id.localeCompare(b.id));
106531
106844
  }
106532
106845
  async function getFileSessionTodos(sessionID) {
106533
- if (!existsSync78(TODO_DIR2))
106846
+ if (!existsSync79(TODO_DIR2))
106534
106847
  return [];
106535
106848
  try {
106536
106849
  const allFiles = await readdir5(TODO_DIR2);
106537
106850
  const todoFiles = allFiles.filter((file) => file === `${sessionID}.json`);
106538
106851
  for (const file of todoFiles) {
106539
106852
  try {
106540
- const content = await readFile8(join84(TODO_DIR2, file), "utf-8");
106853
+ const content = await readFile8(join85(TODO_DIR2, file), "utf-8");
106541
106854
  const data = JSON.parse(content);
106542
106855
  if (!Array.isArray(data))
106543
106856
  continue;
@@ -106557,10 +106870,10 @@ async function getFileSessionTodos(sessionID) {
106557
106870
  return [];
106558
106871
  }
106559
106872
  async function getFileSessionTranscript(sessionID) {
106560
- if (!existsSync78(TRANSCRIPT_DIR2))
106873
+ if (!existsSync79(TRANSCRIPT_DIR2))
106561
106874
  return 0;
106562
- const transcriptFile = join84(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
106563
- if (!existsSync78(transcriptFile))
106875
+ const transcriptFile = join85(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
106876
+ if (!existsSync79(transcriptFile))
106564
106877
  return 0;
106565
106878
  try {
106566
106879
  const content = await readFile8(transcriptFile, "utf-8");
@@ -108365,25 +108678,25 @@ init_session_tools_store();
108365
108678
  init_file_utils2();
108366
108679
  init_shared();
108367
108680
  init_opencode_config_dir();
108368
- import { existsSync as existsSync81, readdirSync as readdirSync23 } from "fs";
108369
- import { join as join85 } from "path";
108681
+ import { existsSync as existsSync82, readdirSync as readdirSync23 } from "fs";
108682
+ import { join as join86 } from "path";
108370
108683
 
108371
108684
  // src/features/claude-code-agent-loader/agent-definitions-loader.ts
108372
108685
  init_frontmatter2();
108373
108686
  init_logger();
108374
- import { existsSync as existsSync80, readFileSync as readFileSync57 } from "fs";
108687
+ import { existsSync as existsSync81, readFileSync as readFileSync58 } from "fs";
108375
108688
  import { basename as basename12, extname as extname3 } from "path";
108376
108689
 
108377
108690
  // src/features/claude-code-agent-loader/json-agent-loader.ts
108378
108691
  init_jsonc_parser2();
108379
108692
  init_claude_model_mapper();
108380
- import { existsSync as existsSync79, readFileSync as readFileSync56 } from "fs";
108693
+ import { existsSync as existsSync80, readFileSync as readFileSync57 } from "fs";
108381
108694
  function parseJsonAgentFile(filePath, scope) {
108382
108695
  try {
108383
- if (!existsSync79(filePath)) {
108696
+ if (!existsSync80(filePath)) {
108384
108697
  return null;
108385
108698
  }
108386
- const content = readFileSync56(filePath, "utf-8");
108699
+ const content = readFileSync57(filePath, "utf-8");
108387
108700
  const { data } = parseJsoncSafe(content);
108388
108701
  if (!data) {
108389
108702
  return null;
@@ -108420,10 +108733,10 @@ function parseJsonAgentFile(filePath, scope) {
108420
108733
  init_claude_model_mapper();
108421
108734
  function parseMarkdownAgentFile(filePath, scope) {
108422
108735
  try {
108423
- if (!existsSync80(filePath)) {
108736
+ if (!existsSync81(filePath)) {
108424
108737
  return null;
108425
108738
  }
108426
- const content = readFileSync57(filePath, "utf-8");
108739
+ const content = readFileSync58(filePath, "utf-8");
108427
108740
  const { data, body } = parseFrontmatter(content);
108428
108741
  const fileName = basename12(filePath);
108429
108742
  const agentName = fileName.replace(/\.md$/i, "");
@@ -108455,7 +108768,7 @@ function parseMarkdownAgentFile(filePath, scope) {
108455
108768
  function loadAgentDefinitions(paths, scope) {
108456
108769
  const result = Object.create(null);
108457
108770
  for (const filePath of paths) {
108458
- if (!existsSync80(filePath)) {
108771
+ if (!existsSync81(filePath)) {
108459
108772
  log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
108460
108773
  continue;
108461
108774
  }
@@ -108480,7 +108793,7 @@ function loadAgentDefinitions(paths, scope) {
108480
108793
 
108481
108794
  // src/features/claude-code-agent-loader/loader.ts
108482
108795
  function loadAgentsFromDir(agentsDir, scope) {
108483
- if (!existsSync81(agentsDir)) {
108796
+ if (!existsSync82(agentsDir)) {
108484
108797
  return [];
108485
108798
  }
108486
108799
  const entries = readdirSync23(agentsDir, { withFileTypes: true });
@@ -108488,7 +108801,7 @@ function loadAgentsFromDir(agentsDir, scope) {
108488
108801
  for (const entry of entries) {
108489
108802
  if (!isMarkdownFile(entry))
108490
108803
  continue;
108491
- const agentPath = join85(agentsDir, entry.name);
108804
+ const agentPath = join86(agentsDir, entry.name);
108492
108805
  const agent = parseMarkdownAgentFile(agentPath, scope);
108493
108806
  if (agent) {
108494
108807
  agents.push(agent);
@@ -108497,7 +108810,7 @@ function loadAgentsFromDir(agentsDir, scope) {
108497
108810
  return agents;
108498
108811
  }
108499
108812
  function loadUserAgents() {
108500
- const userAgentsDir = join85(getClaudeConfigDir(), "agents");
108813
+ const userAgentsDir = join86(getClaudeConfigDir(), "agents");
108501
108814
  const agents = loadAgentsFromDir(userAgentsDir, "user");
108502
108815
  const result = Object.create(null);
108503
108816
  for (const agent of agents) {
@@ -108506,7 +108819,7 @@ function loadUserAgents() {
108506
108819
  return result;
108507
108820
  }
108508
108821
  function loadProjectAgents(directory) {
108509
- const projectAgentsDir = join85(directory ?? process.cwd(), ".claude", "agents");
108822
+ const projectAgentsDir = join86(directory ?? process.cwd(), ".claude", "agents");
108510
108823
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
108511
108824
  const result = Object.create(null);
108512
108825
  for (const agent of agents) {
@@ -108518,7 +108831,7 @@ function loadOpencodeGlobalAgents() {
108518
108831
  const result = Object.create(null);
108519
108832
  const configDirs = getOpenCodeConfigDirs({ binary: "opencode" });
108520
108833
  for (const configDir of configDirs) {
108521
- const opencodeAgentsDir = join85(configDir, "agents");
108834
+ const opencodeAgentsDir = join86(configDir, "agents");
108522
108835
  const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
108523
108836
  for (const agent of agents) {
108524
108837
  if (!(agent.name in result)) {
@@ -108529,7 +108842,7 @@ function loadOpencodeGlobalAgents() {
108529
108842
  return result;
108530
108843
  }
108531
108844
  function loadOpencodeProjectAgents(directory) {
108532
- const opencodeProjectDir = join85(directory ?? process.cwd(), ".opencode", "agents");
108845
+ const opencodeProjectDir = join86(directory ?? process.cwd(), ".opencode", "agents");
108533
108846
  const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
108534
108847
  const result = Object.create(null);
108535
108848
  for (const agent of agents) {
@@ -108541,16 +108854,16 @@ function loadOpencodeProjectAgents(directory) {
108541
108854
  init_opencode_config_dir();
108542
108855
  init_jsonc_parser2();
108543
108856
  init_resolve_agent_definition_paths();
108544
- import * as fs21 from "fs";
108545
- import * as path17 from "path";
108857
+ import * as fs22 from "fs";
108858
+ import * as path18 from "path";
108546
108859
  init_claude_model_mapper();
108547
- function getConfigPaths3(directory) {
108860
+ function getConfigPaths4(directory) {
108548
108861
  const globalConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
108549
108862
  const paths = [
108550
- path17.join(directory, ".opencode", "opencode.json"),
108551
- path17.join(directory, ".opencode", "opencode.jsonc"),
108552
- path17.join(globalConfigDir, "opencode.json"),
108553
- path17.join(globalConfigDir, "opencode.jsonc")
108863
+ path18.join(directory, ".opencode", "opencode.json"),
108864
+ path18.join(directory, ".opencode", "opencode.jsonc"),
108865
+ path18.join(globalConfigDir, "opencode.json"),
108866
+ path18.join(globalConfigDir, "opencode.jsonc")
108554
108867
  ];
108555
108868
  return paths;
108556
108869
  }
@@ -108579,15 +108892,15 @@ function convertInlineAgent(agentData) {
108579
108892
  }
108580
108893
  function readOpencodeConfigAgents(directory) {
108581
108894
  const result = Object.create(null);
108582
- for (const configPath of getConfigPaths3(directory)) {
108895
+ for (const configPath of getConfigPaths4(directory)) {
108583
108896
  try {
108584
- if (!fs21.existsSync(configPath))
108897
+ if (!fs22.existsSync(configPath))
108585
108898
  continue;
108586
- const content = fs21.readFileSync(configPath, "utf-8");
108899
+ const content = fs22.readFileSync(configPath, "utf-8");
108587
108900
  const parseResult = parseJsoncSafe(content);
108588
108901
  if (!parseResult.data)
108589
108902
  continue;
108590
- const configDir = path17.dirname(configPath);
108903
+ const configDir = path18.dirname(configPath);
108591
108904
  const agentsToLoad = parseResult.data.agents || parseResult.data.agent;
108592
108905
  if (agentsToLoad && typeof agentsToLoad === "object") {
108593
108906
  for (const [agentName, agentData] of Object.entries(agentsToLoad)) {
@@ -109283,9 +109596,9 @@ import { pathToFileURL } from "url";
109283
109596
  // src/tools/look-at/image-converter.ts
109284
109597
  init_shared();
109285
109598
  import * as childProcess2 from "child_process";
109286
- import { existsSync as existsSync83, mkdtempSync, readFileSync as readFileSync59, rmSync as rmSync4, unlinkSync as unlinkSync14, writeFileSync as writeFileSync19 } from "fs";
109599
+ import { existsSync as existsSync84, mkdtempSync, readFileSync as readFileSync60, rmSync as rmSync4, unlinkSync as unlinkSync14, writeFileSync as writeFileSync19 } from "fs";
109287
109600
  import { tmpdir as tmpdir7 } from "os";
109288
- import { dirname as dirname31, join as join87 } from "path";
109601
+ import { dirname as dirname31, join as join88 } from "path";
109289
109602
  var SUPPORTED_FORMATS = new Set([
109290
109603
  "image/jpeg",
109291
109604
  "image/png",
@@ -109323,11 +109636,11 @@ function needsConversion(mimeType) {
109323
109636
  return mimeType.startsWith("image/");
109324
109637
  }
109325
109638
  function convertImageToJpeg(inputPath, mimeType) {
109326
- if (!existsSync83(inputPath)) {
109639
+ if (!existsSync84(inputPath)) {
109327
109640
  throw new Error(`File not found: ${inputPath}`);
109328
109641
  }
109329
- const tempDir = mkdtempSync(join87(tmpdir7(), "opencode-img-"));
109330
- const outputPath = join87(tempDir, "converted.jpg");
109642
+ const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-img-"));
109643
+ const outputPath = join88(tempDir, "converted.jpg");
109331
109644
  log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
109332
109645
  try {
109333
109646
  if (process.platform === "darwin") {
@@ -109337,7 +109650,7 @@ function convertImageToJpeg(inputPath, mimeType) {
109337
109650
  encoding: "utf-8",
109338
109651
  timeout: CONVERSION_TIMEOUT_MS
109339
109652
  });
109340
- if (existsSync83(outputPath)) {
109653
+ if (existsSync84(outputPath)) {
109341
109654
  log(`[image-converter] Converted using sips: ${outputPath}`);
109342
109655
  return outputPath;
109343
109656
  }
@@ -109352,7 +109665,7 @@ function convertImageToJpeg(inputPath, mimeType) {
109352
109665
  encoding: "utf-8",
109353
109666
  timeout: CONVERSION_TIMEOUT_MS
109354
109667
  });
109355
- if (existsSync83(outputPath)) {
109668
+ if (existsSync84(outputPath)) {
109356
109669
  log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
109357
109670
  return outputPath;
109358
109671
  }
@@ -109365,7 +109678,7 @@ function convertImageToJpeg(inputPath, mimeType) {
109365
109678
  ` + ` RHEL/CentOS: sudo yum install ImageMagick`);
109366
109679
  } catch (error) {
109367
109680
  try {
109368
- if (existsSync83(outputPath)) {
109681
+ if (existsSync84(outputPath)) {
109369
109682
  unlinkSync14(outputPath);
109370
109683
  }
109371
109684
  } catch {}
@@ -109379,11 +109692,11 @@ function convertImageToJpeg(inputPath, mimeType) {
109379
109692
  function cleanupConvertedImage(filePath) {
109380
109693
  try {
109381
109694
  const tempDirectory = dirname31(filePath);
109382
- if (existsSync83(filePath)) {
109695
+ if (existsSync84(filePath)) {
109383
109696
  unlinkSync14(filePath);
109384
109697
  log(`[image-converter] Cleaned up temporary file: ${filePath}`);
109385
109698
  }
109386
- if (existsSync83(tempDirectory)) {
109699
+ if (existsSync84(tempDirectory)) {
109387
109700
  rmSync4(tempDirectory, { recursive: true, force: true });
109388
109701
  log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
109389
109702
  }
@@ -109392,9 +109705,9 @@ function cleanupConvertedImage(filePath) {
109392
109705
  }
109393
109706
  }
109394
109707
  function convertBase64ImageToJpeg(base64Data, mimeType) {
109395
- const tempDir = mkdtempSync(join87(tmpdir7(), "opencode-b64-"));
109708
+ const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-b64-"));
109396
109709
  const inputExt = mimeType.split("/")[1] || "bin";
109397
- const inputPath = join87(tempDir, `input.${inputExt}`);
109710
+ const inputPath = join88(tempDir, `input.${inputExt}`);
109398
109711
  const tempFiles = [inputPath];
109399
109712
  try {
109400
109713
  const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
@@ -109403,14 +109716,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
109403
109716
  log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
109404
109717
  const outputPath = convertImageToJpeg(inputPath, mimeType);
109405
109718
  tempFiles.push(outputPath);
109406
- const convertedBuffer = readFileSync59(outputPath);
109719
+ const convertedBuffer = readFileSync60(outputPath);
109407
109720
  const convertedBase64 = convertedBuffer.toString("base64");
109408
109721
  log(`[image-converter] Base64 conversion successful`);
109409
109722
  return { base64: convertedBase64, tempFiles };
109410
109723
  } catch (error) {
109411
109724
  tempFiles.forEach((file) => {
109412
109725
  try {
109413
- if (existsSync83(file))
109726
+ if (existsSync84(file))
109414
109727
  unlinkSync14(file);
109415
109728
  } catch {}
109416
109729
  });
@@ -109549,13 +109862,68 @@ function asSessionMessage(value) {
109549
109862
  function getCreatedTime(message) {
109550
109863
  return message.info?.time?.created ?? 0;
109551
109864
  }
109865
+ function asText(value) {
109866
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
109867
+ }
109868
+ function collectContentText(value) {
109869
+ const directText = asText(value);
109870
+ if (directText)
109871
+ return [directText];
109872
+ if (!Array.isArray(value))
109873
+ return [];
109874
+ const texts = [];
109875
+ for (const block of value) {
109876
+ if (!isObject2(block))
109877
+ continue;
109878
+ const text = asText(block["text"]) ?? asText(block["content"]);
109879
+ if (text)
109880
+ texts.push(text);
109881
+ }
109882
+ return texts;
109883
+ }
109884
+ function normalizeThinkingText(text) {
109885
+ const answerMatches = [...text.matchAll(/<answer\b[^>]*>([\s\S]*?)<\/answer>/gi)].map((match) => match[1]?.trim()).filter((value) => Boolean(value));
109886
+ const withoutThinking = text.replace(/<think\b[^>]*>[\s\S]*?<\/think>/gi, "").trim();
109887
+ const normalized = answerMatches.length > 0 ? answerMatches.join(`
109888
+ `) : withoutThinking;
109889
+ return normalized.length > 0 ? normalized : null;
109890
+ }
109552
109891
  function getTextParts(message) {
109553
109892
  if (!Array.isArray(message.parts))
109554
109893
  return [];
109555
109894
  return message.parts.filter((part) => isObject2(part)).map((part) => ({
109556
109895
  type: typeof part["type"] === "string" ? part["type"] : undefined,
109557
- text: typeof part["text"] === "string" ? part["text"] : undefined
109558
- })).filter((part) => part.type === "text" && Boolean(part.text));
109896
+ text: typeof part["text"] === "string" ? part["text"] : undefined,
109897
+ content: part["content"],
109898
+ reasoning: typeof part["reasoning"] === "string" ? part["reasoning"] : undefined,
109899
+ reasoningContent: typeof part["reasoning_content"] === "string" ? part["reasoning_content"] : undefined
109900
+ }));
109901
+ }
109902
+ function extractTextFromParts(parts) {
109903
+ const textCandidates = [];
109904
+ const reasoningCandidates = [];
109905
+ for (const part of parts) {
109906
+ const contentTexts = collectContentText(part.content);
109907
+ const directText = asText(part.text);
109908
+ if (part.type === "text") {
109909
+ if (directText)
109910
+ textCandidates.push(directText);
109911
+ textCandidates.push(...contentTexts);
109912
+ } else if (part.type === "reasoning" || part.type === "thinking") {
109913
+ if (directText)
109914
+ reasoningCandidates.push(directText);
109915
+ textCandidates.push(...contentTexts);
109916
+ }
109917
+ const reasoningText = asText(part.reasoningContent) ?? asText(part.reasoning);
109918
+ if (reasoningText)
109919
+ reasoningCandidates.push(reasoningText);
109920
+ }
109921
+ const primaryText = textCandidates.map(normalizeThinkingText).filter((text) => text !== null).join(`
109922
+ `);
109923
+ if (primaryText)
109924
+ return primaryText;
109925
+ return reasoningCandidates.map(normalizeThinkingText).filter((text) => text !== null).join(`
109926
+ `) || null;
109559
109927
  }
109560
109928
  function extractLatestAssistantText(messages) {
109561
109929
  return extractLatestAssistantOutcome(messages).text;
@@ -109571,9 +109939,7 @@ function extractLatestAssistantOutcome(messages) {
109571
109939
  if (!lastAssistantMessage) {
109572
109940
  return { text: null, errorName: null, hasAssistant, completed: false };
109573
109941
  }
109574
- const textParts = getTextParts(lastAssistantMessage);
109575
- const text = textParts.map((part) => part.text).join(`
109576
- `) || null;
109942
+ const text = extractTextFromParts(getTextParts(lastAssistantMessage));
109577
109943
  const allParts = Array.isArray(lastAssistantMessage.parts) ? lastAssistantMessage.parts : [];
109578
109944
  const errorPart = allParts.find((part) => isObject2(part) && typeof part["type"] === "string" && part["type"] === "error");
109579
109945
  const errorName = errorPart && typeof errorPart["error"] === "string" ? errorPart["error"] : null;
@@ -109971,9 +110337,9 @@ function getMissingFilePathFromError(error) {
109971
110337
  if (!(error instanceof Error)) {
109972
110338
  return null;
109973
110339
  }
109974
- const path18 = Reflect.get(error, "path");
109975
- if (typeof path18 === "string" && path18.length > 0) {
109976
- return path18;
110340
+ const path19 = Reflect.get(error, "path");
110341
+ if (typeof path19 === "string" && path19.length > 0) {
110342
+ return path19;
109977
110343
  }
109978
110344
  if (error instanceof Error) {
109979
110345
  const match = /open '([^']+)'/.exec(error.message);
@@ -112948,7 +113314,7 @@ function isExplicitSyncRun(runInBackground) {
112948
113314
  // src/tools/delegate-task/index.ts
112949
113315
  init_constants();
112950
113316
  // src/tools/task/task-create.ts
112951
- import { join as join89 } from "path";
113317
+ import { join as join90 } from "path";
112952
113318
 
112953
113319
  // src/tools/task/types.ts
112954
113320
  import { z as z37 } from "zod";
@@ -113004,18 +113370,18 @@ var TaskDeleteInputSchema = z37.object({
113004
113370
 
113005
113371
  // src/features/claude-tasks/storage.ts
113006
113372
  init_opencode_config_dir();
113007
- import { join as join88, dirname as dirname32, basename as basename14, isAbsolute as isAbsolute17 } from "path";
113008
- import { existsSync as existsSync84, mkdirSync as mkdirSync18, readFileSync as readFileSync60, writeFileSync as writeFileSync20, renameSync as renameSync6, unlinkSync as unlinkSync15, readdirSync as readdirSync24 } from "fs";
113373
+ import { join as join89, dirname as dirname32, basename as basename14, isAbsolute as isAbsolute17 } from "path";
113374
+ import { existsSync as existsSync85, mkdirSync as mkdirSync18, readFileSync as readFileSync61, writeFileSync as writeFileSync20, renameSync as renameSync6, unlinkSync as unlinkSync15, readdirSync as readdirSync24 } from "fs";
113009
113375
  import { randomUUID as randomUUID5 } from "crypto";
113010
113376
  function getTaskDir(config = {}) {
113011
113377
  const tasksConfig = config.sisyphus?.tasks;
113012
113378
  const storagePath = tasksConfig?.storage_path;
113013
113379
  if (storagePath) {
113014
- return isAbsolute17(storagePath) ? storagePath : join88(process.cwd(), storagePath);
113380
+ return isAbsolute17(storagePath) ? storagePath : join89(process.cwd(), storagePath);
113015
113381
  }
113016
113382
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
113017
113383
  const listId = resolveTaskListId(config);
113018
- return join88(configDir, "tasks", listId);
113384
+ return join89(configDir, "tasks", listId);
113019
113385
  }
113020
113386
  function sanitizePathSegment(value) {
113021
113387
  return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
@@ -113033,16 +113399,16 @@ function resolveTaskListId(config = {}) {
113033
113399
  return sanitizePathSegment(basename14(process.cwd()));
113034
113400
  }
113035
113401
  function ensureDir(dirPath) {
113036
- if (!existsSync84(dirPath)) {
113402
+ if (!existsSync85(dirPath)) {
113037
113403
  mkdirSync18(dirPath, { recursive: true });
113038
113404
  }
113039
113405
  }
113040
113406
  function readJsonSafe(filePath, schema2) {
113041
113407
  try {
113042
- if (!existsSync84(filePath)) {
113408
+ if (!existsSync85(filePath)) {
113043
113409
  return null;
113044
113410
  }
113045
- const content = readFileSync60(filePath, "utf-8");
113411
+ const content = readFileSync61(filePath, "utf-8");
113046
113412
  const parsed = JSON.parse(content);
113047
113413
  const result = schema2.safeParse(parsed);
113048
113414
  if (!result.success) {
@@ -113062,7 +113428,7 @@ function writeJsonAtomic(filePath, data) {
113062
113428
  renameSync6(tempPath, filePath);
113063
113429
  } catch (error) {
113064
113430
  try {
113065
- if (existsSync84(tempPath)) {
113431
+ if (existsSync85(tempPath)) {
113066
113432
  unlinkSync15(tempPath);
113067
113433
  }
113068
113434
  } catch {}
@@ -113074,7 +113440,7 @@ function generateTaskId() {
113074
113440
  return `T-${randomUUID5()}`;
113075
113441
  }
113076
113442
  function acquireLock2(dirPath) {
113077
- const lockPath = join88(dirPath, ".lock");
113443
+ const lockPath = join89(dirPath, ".lock");
113078
113444
  const lockId = randomUUID5();
113079
113445
  const createLock = (timestamp2) => {
113080
113446
  writeFileSync20(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
@@ -113084,7 +113450,7 @@ function acquireLock2(dirPath) {
113084
113450
  };
113085
113451
  const isStale = () => {
113086
113452
  try {
113087
- const lockContent = readFileSync60(lockPath, "utf-8");
113453
+ const lockContent = readFileSync61(lockPath, "utf-8");
113088
113454
  const lockData = JSON.parse(lockContent);
113089
113455
  const lockAge = Date.now() - lockData.timestamp;
113090
113456
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -113122,9 +113488,9 @@ function acquireLock2(dirPath) {
113122
113488
  acquired: true,
113123
113489
  release: () => {
113124
113490
  try {
113125
- if (!existsSync84(lockPath))
113491
+ if (!existsSync85(lockPath))
113126
113492
  return;
113127
- const lockContent = readFileSync60(lockPath, "utf-8");
113493
+ const lockContent = readFileSync61(lockPath, "utf-8");
113128
113494
  const lockData = JSON.parse(lockContent);
113129
113495
  if (lockData.id !== lockId)
113130
113496
  return;
@@ -113287,7 +113653,7 @@ async function handleCreate(args, config, ctx, context) {
113287
113653
  threadID: context.sessionID
113288
113654
  };
113289
113655
  const validatedTask = TaskObjectSchema.parse(task);
113290
- writeJsonAtomic(join89(taskDir, `${taskId}.json`), validatedTask);
113656
+ writeJsonAtomic(join90(taskDir, `${taskId}.json`), validatedTask);
113291
113657
  await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
113292
113658
  return JSON.stringify({
113293
113659
  task: {
@@ -113309,7 +113675,7 @@ async function handleCreate(args, config, ctx, context) {
113309
113675
  }
113310
113676
  }
113311
113677
  // src/tools/task/task-get.ts
113312
- import { join as join90 } from "path";
113678
+ import { join as join91 } from "path";
113313
113679
  var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
113314
113680
  function parseTaskId(id) {
113315
113681
  if (!TASK_ID_PATTERN.test(id))
@@ -113334,7 +113700,7 @@ Returns null if the task does not exist or the file is invalid.`,
113334
113700
  return JSON.stringify({ error: "invalid_task_id" });
113335
113701
  }
113336
113702
  const taskDir = getTaskDir(config);
113337
- const taskPath = join90(taskDir, `${taskId}.json`);
113703
+ const taskPath = join91(taskDir, `${taskId}.json`);
113338
113704
  const task = readJsonSafe(taskPath, TaskObjectSchema);
113339
113705
  return JSON.stringify({ task: task ?? null });
113340
113706
  } catch (error) {
@@ -113347,8 +113713,8 @@ Returns null if the task does not exist or the file is invalid.`,
113347
113713
  });
113348
113714
  }
113349
113715
  // src/tools/task/task-list.ts
113350
- import { join as join91 } from "path";
113351
- import { existsSync as existsSync85, readdirSync as readdirSync25 } from "fs";
113716
+ import { join as join92 } from "path";
113717
+ import { existsSync as existsSync86, readdirSync as readdirSync25 } from "fs";
113352
113718
  function createTaskList(config) {
113353
113719
  return tool({
113354
113720
  description: `List all active tasks with summary information.
@@ -113359,7 +113725,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
113359
113725
  args: {},
113360
113726
  execute: async () => {
113361
113727
  const taskDir = getTaskDir(config);
113362
- if (!existsSync85(taskDir)) {
113728
+ if (!existsSync86(taskDir)) {
113363
113729
  return JSON.stringify({ tasks: [] });
113364
113730
  }
113365
113731
  const files = readdirSync25(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
@@ -113368,7 +113734,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
113368
113734
  }
113369
113735
  const allTasks = [];
113370
113736
  for (const fileId of files) {
113371
- const task = readJsonSafe(join91(taskDir, `${fileId}.json`), TaskObjectSchema);
113737
+ const task = readJsonSafe(join92(taskDir, `${fileId}.json`), TaskObjectSchema);
113372
113738
  if (task) {
113373
113739
  allTasks.push(task);
113374
113740
  }
@@ -113396,7 +113762,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
113396
113762
  });
113397
113763
  }
113398
113764
  // src/tools/task/task-update.ts
113399
- import { join as join92 } from "path";
113765
+ import { join as join93 } from "path";
113400
113766
  var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
113401
113767
  function parseTaskId2(id) {
113402
113768
  if (!TASK_ID_PATTERN2.test(id))
@@ -113444,7 +113810,7 @@ async function handleUpdate(args, config, ctx, context) {
113444
113810
  return JSON.stringify({ error: "task_lock_unavailable" });
113445
113811
  }
113446
113812
  try {
113447
- const taskPath = join92(taskDir, `${taskId}.json`);
113813
+ const taskPath = join93(taskDir, `${taskId}.json`);
113448
113814
  const task = readJsonSafe(taskPath, TaskObjectSchema);
113449
113815
  if (!task) {
113450
113816
  return JSON.stringify({ error: "task_not_found" });
@@ -113502,10 +113868,10 @@ init_bun_file_shim();
113502
113868
  // src/tools/hashline-edit/formatter-trigger.ts
113503
113869
  init_shared();
113504
113870
  init_bun_spawn_shim();
113505
- import path18 from "path";
113871
+ import path19 from "path";
113506
113872
  var cachedFormattersByDirectory = new Map;
113507
113873
  function getFormatterCacheKey(directory) {
113508
- return path18.resolve(directory);
113874
+ return path19.resolve(directory);
113509
113875
  }
113510
113876
  async function resolveFormatters(client, directory) {
113511
113877
  const cacheKey = getFormatterCacheKey(directory);
@@ -113556,7 +113922,7 @@ function buildFormatterCommand(command, filePath) {
113556
113922
  return command.map((arg) => arg.replace(/\$FILE/g, filePath));
113557
113923
  }
113558
113924
  async function runFormattersForFile(client, directory, filePath) {
113559
- const ext = path18.extname(filePath);
113925
+ const ext = path19.extname(filePath);
113560
113926
  if (!ext)
113561
113927
  return;
113562
113928
  const formatters = await resolveFormatters(client, directory);
@@ -113876,17 +114242,17 @@ function buildMemberPromptBody(member, text) {
113876
114242
  // src/features/team-mode/team-mailbox/reservation.ts
113877
114243
  init_paths();
113878
114244
  import { mkdir as mkdir3, readdir as readdir6, rename as rename2, stat as stat5 } from "fs/promises";
113879
- import path19 from "path";
114245
+ import path20 from "path";
113880
114246
  var RESERVED_PREFIX = ".delivering-";
113881
114247
  var RESERVED_SUFFIX = ".json";
113882
114248
  function isMissingPathError(error) {
113883
114249
  return error instanceof Error && "code" in error && error.code === "ENOENT";
113884
114250
  }
113885
114251
  function buildReservation(inboxDir, messageId) {
113886
- const inboxPath = path19.join(inboxDir, `${messageId}.json`);
113887
- const reservedPath = path19.join(inboxDir, `${RESERVED_PREFIX}${messageId}${RESERVED_SUFFIX}`);
113888
- const processedDir = path19.join(inboxDir, "processed");
113889
- const processedPath = path19.join(processedDir, `${messageId}.json`);
114252
+ const inboxPath = path20.join(inboxDir, `${messageId}.json`);
114253
+ const reservedPath = path20.join(inboxDir, `${RESERVED_PREFIX}${messageId}${RESERVED_SUFFIX}`);
114254
+ const processedDir = path20.join(inboxDir, "processed");
114255
+ const processedPath = path20.join(processedDir, `${messageId}.json`);
113890
114256
  return { reservedPath, inboxPath, processedPath, processedDir };
113891
114257
  }
113892
114258
  async function reserveMessageForDelivery(teamRunId, recipientName, messageId, config) {
@@ -113922,7 +114288,7 @@ init_store();
113922
114288
  init_locks();
113923
114289
  import { Buffer as Buffer2 } from "buffer";
113924
114290
  import { mkdir as mkdir4, readdir as readdir7, stat as stat6 } from "fs/promises";
113925
- import path20 from "path";
114291
+ import path21 from "path";
113926
114292
 
113927
114293
  class BroadcastNotPermittedError extends Error {
113928
114294
  constructor(message = "broadcast requires lead role") {
@@ -113991,7 +114357,7 @@ async function getUnreadSizeBytes(inboxDir) {
113991
114357
  return !entry.name.startsWith(".");
113992
114358
  });
113993
114359
  const sizes = await Promise.all(unreadEntries.map(async (entry) => {
113994
- const fileStats = await stat6(path20.join(inboxDir, entry.name));
114360
+ const fileStats = await stat6(path21.join(inboxDir, entry.name));
113995
114361
  return fileStats.size;
113996
114362
  }));
113997
114363
  return sizes.reduce((totalBytes, fileSize) => totalBytes + fileSize, 0);
@@ -114037,8 +114403,8 @@ async function sendMessage(message, teamRunId, config, context) {
114037
114403
  if (nextUnreadSizeBytes > config.recipient_unread_max_bytes) {
114038
114404
  throw new RecipientBackpressureError;
114039
114405
  }
114040
- const unreservedPath = path20.join(inboxDir, `${message.messageId}.json`);
114041
- const reservedPath = path20.join(inboxDir, `.delivering-${message.messageId}.json`);
114406
+ const unreservedPath = path21.join(inboxDir, `${message.messageId}.json`);
114407
+ const reservedPath = path21.join(inboxDir, `.delivering-${message.messageId}.json`);
114042
114408
  if (await fileExists(unreservedPath) || await fileExists(reservedPath)) {
114043
114409
  throw new DuplicateMessageIdError;
114044
114410
  }
@@ -114387,7 +114753,6 @@ function createRuntimeTmuxConfig(pluginConfig) {
114387
114753
  function createSessionHooks(args) {
114388
114754
  const { ctx, pluginConfig, modelCacheState, backgroundManager, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args;
114389
114755
  const safeHook = (hookName, factory) => safeCreateHook(hookName, factory, { enabled: safeHookEnabled });
114390
- const contextWindowMonitor = isHookEnabled("context-window-monitor") ? safeHook("context-window-monitor", () => createContextWindowMonitorHook(ctx, modelCacheState)) : null;
114391
114756
  const preemptiveCompaction = isHookEnabled("preemptive-compaction") && pluginConfig.experimental?.preemptive_compaction ? safeHook("preemptive-compaction", () => createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState)) : null;
114392
114757
  const sessionRecovery = isHookEnabled("session-recovery") ? safeHook("session-recovery", () => createSessionRecoveryHook(ctx, { experimental: pluginConfig.experimental })) : null;
114393
114758
  let sessionNotification = null;
@@ -114485,7 +114850,6 @@ function createSessionHooks(args) {
114485
114850
  })) : null;
114486
114851
  const legacyPluginToast = isHookEnabled("legacy-plugin-toast") ? safeHook("legacy-plugin-toast", () => createLegacyPluginToastHook(ctx)) : null;
114487
114852
  return {
114488
- contextWindowMonitor,
114489
114853
  preemptiveCompaction,
114490
114854
  sessionRecovery,
114491
114855
  sessionNotification,
@@ -114794,8 +115158,8 @@ function createUnstableAgentBabysitter(args) {
114794
115158
  directory: ctx.directory,
114795
115159
  client: {
114796
115160
  session: {
114797
- messages: async ({ path: path21 }) => {
114798
- const result = await ctx.client.session.messages({ path: path21 });
115161
+ messages: async ({ path: path22 }) => {
115162
+ const result = await ctx.client.session.messages({ path: path22 });
114799
115163
  if (Array.isArray(result))
114800
115164
  return result;
114801
115165
  if (typeof result === "object" && result !== null) {
@@ -114954,7 +115318,7 @@ function createHooks(args) {
114954
115318
  };
114955
115319
  }
114956
115320
  // src/features/background-agent/manager.ts
114957
- import { join as join94 } from "path";
115321
+ import { join as join95 } from "path";
114958
115322
  init_shared();
114959
115323
  init_event_session_id();
114960
115324
  init_session_category_registry();
@@ -115234,8 +115598,8 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
115234
115598
  }
115235
115599
 
115236
115600
  // src/features/background-agent/compaction-aware-message-resolver.ts
115237
- import { readdirSync as readdirSync26, readFileSync as readFileSync61 } from "fs";
115238
- import { join as join93 } from "path";
115601
+ import { readdirSync as readdirSync26, readFileSync as readFileSync62 } from "fs";
115602
+ import { join as join94 } from "path";
115239
115603
  init_compaction_marker();
115240
115604
  init_compaction_marker();
115241
115605
  function hasFullAgentAndModel(message) {
@@ -115316,7 +115680,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
115316
115680
  const messages = [];
115317
115681
  for (const file of files) {
115318
115682
  try {
115319
- const content = readFileSync61(join93(messageDir, file), "utf-8");
115683
+ const content = readFileSync62(join94(messageDir, file), "utf-8");
115320
115684
  const parsed = JSON.parse(content);
115321
115685
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
115322
115686
  continue;
@@ -115356,6 +115720,16 @@ class ConcurrencyManager {
115356
115720
  }
115357
115721
  return 5;
115358
115722
  }
115723
+ getConcurrencyKey(model) {
115724
+ if (this.config?.modelConcurrency?.[model] !== undefined) {
115725
+ return model;
115726
+ }
115727
+ const provider = model.split("/")[0];
115728
+ if (provider && this.config?.providerConcurrency?.[provider] !== undefined) {
115729
+ return provider;
115730
+ }
115731
+ return model;
115732
+ }
115359
115733
  async acquire(model) {
115360
115734
  const limit = this.getConcurrencyLimit(model);
115361
115735
  if (limit === Infinity) {
@@ -115390,6 +115764,9 @@ class ConcurrencyManager {
115390
115764
  const queue = this.queues.get(model);
115391
115765
  while (queue && queue.length > 0) {
115392
115766
  const next = queue.shift();
115767
+ if (!next) {
115768
+ continue;
115769
+ }
115393
115770
  if (!next.settled) {
115394
115771
  next.resolve();
115395
115772
  return;
@@ -115583,7 +115960,8 @@ async function tryFallbackRetry(args) {
115583
115960
  });
115584
115961
  throw new TeamModeFallbackError(`team-mode fallback denied: cannot preserve team context for task ${task.id} (teamRunId=${task.teamRunId})`);
115585
115962
  }
115586
- const key = task.model ? `${task.model.providerID}/${task.model.modelID}` : task.agent;
115963
+ const rawKey = task.model ? `${task.model.providerID}/${task.model.modelID}` : task.agent;
115964
+ const key = concurrencyManager.getConcurrencyKey(rawKey);
115587
115965
  const queue = queuesByKey.get(key) ?? [];
115588
115966
  const retryInput = {
115589
115967
  description: task.description,
@@ -116063,7 +116441,8 @@ class ParentWakeNotifier {
116063
116441
  const role = this.getParentWakeMessageRole(message);
116064
116442
  if (role === "assistant") {
116065
116443
  const waiting = this.getParentWakeMessageFinish(message) === "tool-calls" || message.parts?.some((part) => this.parentWakePartIsWaitingOnTool(part)) === true;
116066
- return waiting ? { waiting: true, activityAt: getParentWakeMessageActivityAt(message) } : { waiting: false };
116444
+ const activityAt = getParentWakeMessageActivityAt(message);
116445
+ return waiting ? { waiting: true, activityAt } : { waiting: false, activityAt };
116067
116446
  }
116068
116447
  if (role === "user") {
116069
116448
  if (isSyntheticOrInternalUserMessage(message)) {
@@ -116162,16 +116541,18 @@ class ParentWakeNotifier {
116162
116541
  }
116163
116542
  const latestToolWaitAgeMs = toolWaitState.activityAt === undefined ? 0 : now - toolWaitState.activityAt;
116164
116543
  const deferAge = now - wake.toolCallDeferralStartedAt;
116544
+ const latestAssistantActivityAgeMs = toolWaitState.activityAt === undefined ? deferAge : now - toolWaitState.activityAt;
116165
116545
  if (wake.shouldReply && toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs && latestToolWaitAgeMs >= this.options.toolCallDeferMaxMs) {
116166
116546
  log("[background-agent] Sending parent wake after stale tool-call deferral window:", {
116167
116547
  sessionID
116168
116548
  });
116169
116549
  return { defer: false, skipPromptGateToolStateCheck: true };
116170
116550
  }
116171
- if (!toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs) {
116551
+ if (!toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs && latestAssistantActivityAgeMs >= this.options.toolCallDeferMaxMs) {
116172
116552
  log("[background-agent] Sending parent wake after stale assistant-text deferral window:", {
116173
116553
  sessionID,
116174
- deferAgeMs: deferAge
116554
+ deferAgeMs: deferAge,
116555
+ latestAssistantActivityAgeMs
116175
116556
  });
116176
116557
  return { defer: false, skipPromptGateToolStateCheck: true };
116177
116558
  }
@@ -116236,8 +116617,13 @@ function scheduleForcedExit(cleanupResult, exitCode, exitAfterCleanup = false) {
116236
116617
  }
116237
116618
  });
116238
116619
  }
116620
+ var _shutdownInProgress = false;
116621
+ function markShutdownStarted() {
116622
+ _shutdownInProgress = true;
116623
+ }
116239
116624
  function registerProcessSignal(signal, handler, exitAfter) {
116240
116625
  const listener = () => {
116626
+ markShutdownStarted();
116241
116627
  const cleanupResult = handler();
116242
116628
  if (exitAfter) {
116243
116629
  scheduleForcedExit(cleanupResult, 0, true);
@@ -116264,11 +116650,32 @@ function describeProcessCleanupError(error) {
116264
116650
  }
116265
116651
  return { raw: String(error) };
116266
116652
  }
116653
+ var HARMLESS_SHUTDOWN_ERRNO_CODES = new Set(["EPIPE", "ECONNRESET"]);
116654
+ var STDIO_WRITE_FDS = new Set([1, 2]);
116655
+ function isStdioWriteError(error) {
116656
+ const syscall = error.syscall;
116657
+ const fd = error.fd;
116658
+ return syscall === "write" && typeof fd === "number" && STDIO_WRITE_FDS.has(fd);
116659
+ }
116660
+ function isHarmlessShutdownError(error) {
116661
+ if (!error || typeof error !== "object")
116662
+ return false;
116663
+ const code = error.code;
116664
+ if (typeof code !== "string")
116665
+ return false;
116666
+ if (!HARMLESS_SHUTDOWN_ERRNO_CODES.has(code))
116667
+ return false;
116668
+ if (isStdioWriteError(error))
116669
+ return true;
116670
+ return _shutdownInProgress;
116671
+ }
116267
116672
  function registerErrorEvent(signal) {
116268
116673
  let logging = false;
116269
116674
  const listener = (error) => {
116270
116675
  if (logging)
116271
116676
  return;
116677
+ if (isHarmlessShutdownError(error))
116678
+ return;
116272
116679
  logging = true;
116273
116680
  log(`[background-agent] ${signal} observed; keeping host alive and skipping cleanup (signal handlers run on real shutdown)`, describeProcessCleanupError(error));
116274
116681
  logging = false;
@@ -116293,9 +116700,13 @@ function registerManagerForCleanup(manager) {
116293
116700
  for (const m of cleanupManagers) {
116294
116701
  try {
116295
116702
  promises.push(Promise.resolve(m.shutdown()).catch((error) => {
116703
+ if (isHarmlessShutdownError(error))
116704
+ return;
116296
116705
  log("[background-agent] Error during async shutdown cleanup:", error);
116297
116706
  }));
116298
116707
  } catch (error) {
116708
+ if (isHarmlessShutdownError(error))
116709
+ continue;
116299
116710
  log("[background-agent] Error during shutdown cleanup:", error);
116300
116711
  }
116301
116712
  }
@@ -117988,10 +118399,8 @@ The fallback retry session is now created and can be inspected directly.
117988
118399
  };
117989
118400
  }
117990
118401
  getConcurrencyKeyFromInput(input) {
117991
- if (input.model) {
117992
- return `${input.model.providerID}/${input.model.modelID}`;
117993
- }
117994
- return input.agent;
118402
+ const modelKey = input.model ? `${input.model.providerID}/${input.model.modelID}` : input.agent;
118403
+ return this.concurrencyManager.getConcurrencyKey(modelKey);
117995
118404
  }
117996
118405
  async trackTask(input) {
117997
118406
  const existingTask = this.tasks.get(input.taskId);
@@ -118005,7 +118414,7 @@ The fallback retry session is now created and can be inspected directly.
118005
118414
  existingTask.parentAgent = input.parentAgent;
118006
118415
  }
118007
118416
  if (!existingTask.concurrencyGroup) {
118008
- existingTask.concurrencyGroup = input.concurrencyKey ?? existingTask.agent;
118417
+ existingTask.concurrencyGroup = input.concurrencyKey ? this.concurrencyManager.getConcurrencyKey(input.concurrencyKey) : existingTask.agent;
118009
118418
  }
118010
118419
  if (existingTask.sessionId) {
118011
118420
  subagentSessions.add(existingTask.sessionId);
@@ -118021,9 +118430,10 @@ The fallback retry session is now created and can be inspected directly.
118021
118430
  log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.sessionId, status: existingTask.status });
118022
118431
  return existingTask;
118023
118432
  }
118024
- const concurrencyGroup = input.concurrencyKey ?? input.agent ?? "task";
118025
- if (input.concurrencyKey) {
118026
- await this.concurrencyManager.acquire(input.concurrencyKey);
118433
+ const concurrencyKey = input.concurrencyKey ? this.concurrencyManager.getConcurrencyKey(input.concurrencyKey) : undefined;
118434
+ const concurrencyGroup = concurrencyKey ?? input.agent ?? "task";
118435
+ if (concurrencyKey) {
118436
+ await this.concurrencyManager.acquire(concurrencyKey);
118027
118437
  }
118028
118438
  const task = {
118029
118439
  id: input.taskId,
@@ -118040,7 +118450,7 @@ The fallback retry session is now created and can be inspected directly.
118040
118450
  lastUpdate: new Date
118041
118451
  },
118042
118452
  parentAgent: input.parentAgent,
118043
- concurrencyKey: input.concurrencyKey,
118453
+ concurrencyKey,
118044
118454
  concurrencyGroup
118045
118455
  };
118046
118456
  this.addTask(task);
@@ -118076,7 +118486,7 @@ The fallback retry session is now created and can be inspected directly.
118076
118486
  clearTimeout(completionTimer);
118077
118487
  this.completionTimers.delete(existingTask.id);
118078
118488
  }
118079
- const concurrencyKey = existingTask.concurrencyGroup ?? existingTask.agent;
118489
+ const concurrencyKey = this.concurrencyManager.getConcurrencyKey(existingTask.concurrencyGroup ?? existingTask.agent);
118080
118490
  await this.concurrencyManager.acquire(concurrencyKey);
118081
118491
  existingTask.concurrencyKey = concurrencyKey;
118082
118492
  existingTask.concurrencyGroup = concurrencyKey;
@@ -119102,7 +119512,7 @@ The task was re-queued on a fallback model after a retryable failure.
119102
119512
  parentSessionID: task.parentSessionId
119103
119513
  });
119104
119514
  }
119105
- const messageDir = join94(MESSAGE_STORAGE, task.parentSessionId);
119515
+ const messageDir = join95(MESSAGE_STORAGE, task.parentSessionId);
119106
119516
  const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionId) : null;
119107
119517
  agent = currentMessage?.agent ?? task.parentAgent;
119108
119518
  model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
@@ -119445,11 +119855,11 @@ The task was re-queued on a fallback model after a retryable failure.
119445
119855
  }
119446
119856
  // src/features/mcp-oauth/storage.ts
119447
119857
  init_shared();
119448
- import { chmodSync as chmodSync2, existsSync as existsSync86, mkdirSync as mkdirSync19, readFileSync as readFileSync62, renameSync as renameSync7, unlinkSync as unlinkSync16, writeFileSync as writeFileSync21 } from "fs";
119449
- import { dirname as dirname33, join as join95 } from "path";
119858
+ import { chmodSync as chmodSync2, existsSync as existsSync87, mkdirSync as mkdirSync19, readFileSync as readFileSync63, renameSync as renameSync7, unlinkSync as unlinkSync16, writeFileSync as writeFileSync21 } from "fs";
119859
+ import { dirname as dirname33, join as join96 } from "path";
119450
119860
  var STORAGE_FILE_NAME = "mcp-oauth.json";
119451
119861
  function getMcpOauthStoragePath() {
119452
- return join95(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
119862
+ return join96(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
119453
119863
  }
119454
119864
  function normalizeHost(serverHost) {
119455
119865
  let host = serverHost.trim();
@@ -119486,11 +119896,11 @@ function buildKey(serverHost, resource) {
119486
119896
  }
119487
119897
  function readStore() {
119488
119898
  const filePath = getMcpOauthStoragePath();
119489
- if (!existsSync86(filePath)) {
119899
+ if (!existsSync87(filePath)) {
119490
119900
  return null;
119491
119901
  }
119492
119902
  try {
119493
- const content = readFileSync62(filePath, "utf-8");
119903
+ const content = readFileSync63(filePath, "utf-8");
119494
119904
  return JSON.parse(content);
119495
119905
  } catch {
119496
119906
  return null;
@@ -119500,7 +119910,7 @@ function writeStore(store2) {
119500
119910
  const filePath = getMcpOauthStoragePath();
119501
119911
  try {
119502
119912
  const dir = dirname33(filePath);
119503
- if (!existsSync86(dir)) {
119913
+ if (!existsSync87(dir)) {
119504
119914
  mkdirSync19(dir, { recursive: true });
119505
119915
  }
119506
119916
  const tempPath = `${filePath}.tmp.${Date.now()}`;
@@ -119692,13 +120102,13 @@ async function findAvailablePort2(startPort = DEFAULT_PORT) {
119692
120102
 
119693
120103
  // src/features/mcp-oauth/oauth-authorization-flow.ts
119694
120104
  import { spawn as spawn3 } from "child_process";
119695
- import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
120105
+ import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
119696
120106
  import { createServer as createServer2 } from "http";
119697
120107
  function generateCodeVerifier() {
119698
120108
  return randomBytes2(32).toString("base64url");
119699
120109
  }
119700
120110
  function generateCodeChallenge(verifier) {
119701
- return createHash2("sha256").update(verifier).digest("base64url");
120111
+ return createHash3("sha256").update(verifier).digest("base64url");
119702
120112
  }
119703
120113
  function buildAuthorizationUrl(authorizationEndpoint, options) {
119704
120114
  const url = new URL(authorizationEndpoint);
@@ -125389,8 +125799,33 @@ async function executeActions(actions, ctx) {
125389
125799
  // src/features/tmux-subagent/polling-manager.ts
125390
125800
  init_tmux();
125391
125801
  init_shared();
125392
- init_shared();
125393
125802
  init_event_session_id();
125803
+
125804
+ // src/features/tmux-subagent/session-status-parser.ts
125805
+ function parseSessionStatusResponse(response) {
125806
+ if (typeof response === "object" && response !== null && "data" in response) {
125807
+ return parseSessionStatusMap(response.data);
125808
+ }
125809
+ return parseSessionStatusMap(response);
125810
+ }
125811
+ function parseSessionStatusMap(data) {
125812
+ if (typeof data !== "object" || data === null)
125813
+ return {};
125814
+ const record3 = data;
125815
+ const result = {};
125816
+ for (const [sessionId, value] of Object.entries(record3)) {
125817
+ if (typeof value !== "object" || value === null)
125818
+ continue;
125819
+ const valueRecord = value;
125820
+ const type2 = valueRecord["type"];
125821
+ if (typeof type2 !== "string")
125822
+ continue;
125823
+ result[sessionId] = { type: type2 };
125824
+ }
125825
+ return result;
125826
+ }
125827
+
125828
+ // src/features/tmux-subagent/polling-manager.ts
125394
125829
  var MIN_STABILITY_TIME_MS3 = 10 * 1000;
125395
125830
  var STABLE_POLLS_REQUIRED = 3;
125396
125831
 
@@ -125446,7 +125881,7 @@ class TmuxPollingManager {
125446
125881
  }
125447
125882
  await this.activateFocusedPanes();
125448
125883
  const statusResult = await this.client.session.status({ path: undefined });
125449
- const allStatuses = normalizeSDKResponse(statusResult, {});
125884
+ const allStatuses = parseSessionStatusResponse(statusResult);
125450
125885
  log("[tmux-session-manager] pollSessions", {
125451
125886
  trackedSessions: Array.from(this.sessions.keys()),
125452
125887
  allStatusKeys: Object.keys(allStatuses)
@@ -125493,7 +125928,7 @@ class TmuxPollingManager {
125493
125928
  if ((tracked.stableIdlePolls ?? 0) >= STABLE_POLLS_REQUIRED) {
125494
125929
  const stableWindowActivityVersion = tracked.observedIdleActivityVersion ?? activityVersion;
125495
125930
  const recheckResult = await this.client.session.status({ path: undefined });
125496
- const recheckStatuses = normalizeSDKResponse(recheckResult, {});
125931
+ const recheckStatuses = parseSessionStatusResponse(recheckResult);
125497
125932
  const recheckStatus = recheckStatuses[sessionId];
125498
125933
  const latestTracked = this.sessions.get(sessionId) ?? tracked;
125499
125934
  const recheckActivityVersion = latestTracked.activityVersion ?? 0;
@@ -125634,36 +126069,18 @@ init_tmux();
125634
126069
  init_shared();
125635
126070
 
125636
126071
  // src/features/tmux-subagent/attachable-session-status.ts
125637
- var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy"];
126072
+ var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy", "retry"];
125638
126073
  function isAttachableSessionStatus(status) {
125639
126074
  return ATTACHABLE_SESSION_STATUSES.some((attachableSessionStatus) => attachableSessionStatus === status);
125640
126075
  }
125641
126076
 
125642
- // src/features/tmux-subagent/session-status-parser.ts
125643
- function parseSessionStatusMap(data) {
125644
- if (typeof data !== "object" || data === null)
125645
- return {};
125646
- const record3 = data;
125647
- const result = {};
125648
- for (const [sessionId, value] of Object.entries(record3)) {
125649
- if (typeof value !== "object" || value === null)
125650
- continue;
125651
- const valueRecord = value;
125652
- const type2 = valueRecord["type"];
125653
- if (typeof type2 !== "string")
125654
- continue;
125655
- result[sessionId] = { type: type2 };
125656
- }
125657
- return result;
125658
- }
125659
-
125660
126077
  // src/features/tmux-subagent/session-ready-waiter.ts
125661
126078
  async function waitForSessionReady(params) {
125662
126079
  const startTime = Date.now();
125663
126080
  while (Date.now() - startTime < SESSION_READY_TIMEOUT_MS) {
125664
126081
  try {
125665
126082
  const statusResult = await params.client.session.status({ path: undefined });
125666
- const allStatuses = parseSessionStatusMap(statusResult.data);
126083
+ const allStatuses = parseSessionStatusResponse(statusResult);
125667
126084
  const sessionStatus = allStatuses[params.sessionId]?.type;
125668
126085
  if (isAttachableSessionStatus(sessionStatus)) {
125669
126086
  log("[tmux-session-manager] session ready", {
@@ -126172,7 +126589,7 @@ class TmuxSessionManager {
126172
126589
  async getSessionStatusType(sessionId) {
126173
126590
  try {
126174
126591
  const statusResult = await this.client.session.status({ path: undefined });
126175
- const allStatuses = parseSessionStatusMap(statusResult.data);
126592
+ const allStatuses = parseSessionStatusResponse(statusResult);
126176
126593
  return allStatuses[sessionId]?.type;
126177
126594
  } catch (error) {
126178
126595
  this.deps.log("[tmux-session-manager] failed to read session status before spawn", {
@@ -127078,14 +127495,14 @@ async function isTmuxAvailable() {
127078
127495
  }
127079
127496
 
127080
127497
  // src/openclaw/reply-listener.ts
127081
- import { dirname as dirname35, join as join98 } from "path";
127498
+ import { dirname as dirname35, join as join99 } from "path";
127082
127499
 
127083
127500
  // src/openclaw/session-registry.ts
127084
127501
  init_data_path();
127085
127502
  import {
127086
- existsSync as existsSync87,
127503
+ existsSync as existsSync88,
127087
127504
  mkdirSync as mkdirSync20,
127088
- readFileSync as readFileSync63,
127505
+ readFileSync as readFileSync64,
127089
127506
  writeFileSync as writeFileSync22,
127090
127507
  openSync as openSync3,
127091
127508
  closeSync as closeSync3,
@@ -127094,11 +127511,11 @@ import {
127094
127511
  statSync as statSync12,
127095
127512
  constants as constants20
127096
127513
  } from "fs";
127097
- import { join as join96, dirname as dirname34 } from "path";
127514
+ import { join as join97, dirname as dirname34 } from "path";
127098
127515
  import { randomUUID as randomUUID8 } from "crypto";
127099
- var OPENCLAW_STORAGE_DIR = join96(getOpenCodeStorageDir(), "openclaw");
127100
- var REGISTRY_PATH = join96(OPENCLAW_STORAGE_DIR, "reply-session-registry.jsonl");
127101
- var REGISTRY_LOCK_PATH = join96(OPENCLAW_STORAGE_DIR, "reply-session-registry.lock");
127516
+ var OPENCLAW_STORAGE_DIR = join97(getOpenCodeStorageDir(), "openclaw");
127517
+ var REGISTRY_PATH = join97(OPENCLAW_STORAGE_DIR, "reply-session-registry.jsonl");
127518
+ var REGISTRY_LOCK_PATH = join97(OPENCLAW_STORAGE_DIR, "reply-session-registry.lock");
127102
127519
  var SECURE_FILE_MODE = 384;
127103
127520
  var MAX_AGE_MS = 24 * 60 * 60 * 1000;
127104
127521
  var LOCK_TIMEOUT_MS = 2000;
@@ -127107,7 +127524,7 @@ var LOCK_RETRY_MS2 = 20;
127107
127524
  var LOCK_STALE_MS = 1e4;
127108
127525
  function ensureRegistryDir() {
127109
127526
  const registryDir = dirname34(REGISTRY_PATH);
127110
- if (!existsSync87(registryDir)) {
127527
+ if (!existsSync88(registryDir)) {
127111
127528
  mkdirSync20(registryDir, { recursive: true, mode: 448 });
127112
127529
  }
127113
127530
  }
@@ -127126,9 +127543,9 @@ function isPidAlive2(pid) {
127126
127543
  }
127127
127544
  function readLockSnapshot() {
127128
127545
  try {
127129
- if (!existsSync87(REGISTRY_LOCK_PATH))
127546
+ if (!existsSync88(REGISTRY_LOCK_PATH))
127130
127547
  return null;
127131
- const raw = readFileSync63(REGISTRY_LOCK_PATH, "utf-8");
127548
+ const raw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
127132
127549
  const trimmed = raw.trim();
127133
127550
  if (!trimmed)
127134
127551
  return { raw, pid: null, token: null };
@@ -127152,9 +127569,9 @@ function readLockSnapshot() {
127152
127569
  }
127153
127570
  function removeLockIfUnchanged(snapshot) {
127154
127571
  try {
127155
- if (!existsSync87(REGISTRY_LOCK_PATH))
127572
+ if (!existsSync88(REGISTRY_LOCK_PATH))
127156
127573
  return false;
127157
- const currentRaw = readFileSync63(REGISTRY_LOCK_PATH, "utf-8");
127574
+ const currentRaw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
127158
127575
  if (currentRaw !== snapshot.raw)
127159
127576
  return false;
127160
127577
  unlinkSync17(REGISTRY_LOCK_PATH);
@@ -127258,10 +127675,10 @@ function withRegistryLock(onLocked, onLockUnavailable) {
127258
127675
  }
127259
127676
  }
127260
127677
  function readAllMappingsUnsafe() {
127261
- if (!existsSync87(REGISTRY_PATH))
127678
+ if (!existsSync88(REGISTRY_PATH))
127262
127679
  return [];
127263
127680
  try {
127264
- const content = readFileSync63(REGISTRY_PATH, "utf-8");
127681
+ const content = readFileSync64(REGISTRY_PATH, "utf-8");
127265
127682
  return content.split(`
127266
127683
  `).filter((line) => line.trim()).map((line) => {
127267
127684
  try {
@@ -127316,7 +127733,7 @@ function removeSession(sessionId) {
127316
127733
  import {
127317
127734
  appendFileSync as appendFileSync6,
127318
127735
  chmodSync as chmodSync3,
127319
- existsSync as existsSync89,
127736
+ existsSync as existsSync90,
127320
127737
  renameSync as renameSync8,
127321
127738
  statSync as statSync13,
127322
127739
  unlinkSync as unlinkSync18,
@@ -127324,31 +127741,31 @@ import {
127324
127741
  } from "fs";
127325
127742
 
127326
127743
  // src/openclaw/reply-listener-paths.ts
127327
- import { existsSync as existsSync88, mkdirSync as mkdirSync21 } from "fs";
127744
+ import { existsSync as existsSync89, mkdirSync as mkdirSync21 } from "fs";
127328
127745
  import { homedir as homedir19 } from "os";
127329
- import { join as join97 } from "path";
127746
+ import { join as join98 } from "path";
127330
127747
  var REPLY_LISTENER_SECURE_FILE_MODE = 384;
127331
127748
  function resolveReplyListenerHomeDir() {
127332
127749
  return process.env.HOME ?? process.env.USERPROFILE ?? homedir19();
127333
127750
  }
127334
127751
  function getReplyListenerStateDir() {
127335
- return join97(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
127752
+ return join98(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
127336
127753
  }
127337
127754
  function getReplyListenerPidFilePath() {
127338
- return join97(getReplyListenerStateDir(), "reply-listener.pid");
127755
+ return join98(getReplyListenerStateDir(), "reply-listener.pid");
127339
127756
  }
127340
127757
  function getReplyListenerStateFilePath() {
127341
- return join97(getReplyListenerStateDir(), "reply-listener-state.json");
127758
+ return join98(getReplyListenerStateDir(), "reply-listener-state.json");
127342
127759
  }
127343
127760
  function getReplyListenerConfigFilePath() {
127344
- return join97(getReplyListenerStateDir(), "reply-listener-config.json");
127761
+ return join98(getReplyListenerStateDir(), "reply-listener-config.json");
127345
127762
  }
127346
127763
  function getReplyListenerLogFilePath() {
127347
- return join97(getReplyListenerStateDir(), "reply-listener.log");
127764
+ return join98(getReplyListenerStateDir(), "reply-listener.log");
127348
127765
  }
127349
127766
  function ensureReplyListenerStateDir() {
127350
127767
  const stateDir = getReplyListenerStateDir();
127351
- if (!existsSync88(stateDir)) {
127768
+ if (!existsSync89(stateDir)) {
127352
127769
  mkdirSync21(stateDir, { recursive: true, mode: 448 });
127353
127770
  }
127354
127771
  }
@@ -127364,13 +127781,13 @@ function writeSecureReplyListenerFile(filePath, content) {
127364
127781
  }
127365
127782
  function rotateReplyListenerLogIfNeeded(logPath) {
127366
127783
  try {
127367
- if (!existsSync89(logPath))
127784
+ if (!existsSync90(logPath))
127368
127785
  return;
127369
127786
  const stats = statSync13(logPath);
127370
127787
  if (stats.size <= MAX_REPLY_LISTENER_LOG_SIZE_BYTES)
127371
127788
  return;
127372
127789
  const backupPath = `${logPath}.old`;
127373
- if (existsSync89(backupPath)) {
127790
+ if (existsSync90(backupPath)) {
127374
127791
  unlinkSync18(backupPath);
127375
127792
  }
127376
127793
  renameSync8(logPath, backupPath);
@@ -127411,7 +127828,7 @@ class ReplyListenerRateLimiter {
127411
127828
  }
127412
127829
 
127413
127830
  // src/openclaw/reply-listener-state.ts
127414
- import { existsSync as existsSync90, readFileSync as readFileSync64, unlinkSync as unlinkSync19 } from "fs";
127831
+ import { existsSync as existsSync91, readFileSync as readFileSync65, unlinkSync as unlinkSync19 } from "fs";
127415
127832
  var REPLY_LISTENER_STARTUP_TOKEN_ENV = "OMO_OPENCLAW_REPLY_LISTENER_STARTUP_TOKEN";
127416
127833
  function createDefaultReplyListenerState() {
127417
127834
  return {
@@ -127473,9 +127890,9 @@ function createPendingReplyListenerState(startupToken) {
127473
127890
  function readReplyListenerDaemonState() {
127474
127891
  try {
127475
127892
  const stateFilePath = getReplyListenerStateFilePath();
127476
- if (!existsSync90(stateFilePath))
127893
+ if (!existsSync91(stateFilePath))
127477
127894
  return null;
127478
- return normalizeReplyListenerState(JSON.parse(readFileSync64(stateFilePath, "utf-8")));
127895
+ return normalizeReplyListenerState(JSON.parse(readFileSync65(stateFilePath, "utf-8")));
127479
127896
  } catch {
127480
127897
  return null;
127481
127898
  }
@@ -127490,9 +127907,9 @@ function writeReplyListenerDaemonState(state3) {
127490
127907
  function readReplyListenerDaemonConfig() {
127491
127908
  try {
127492
127909
  const configFilePath = getReplyListenerConfigFilePath();
127493
- if (!existsSync90(configFilePath))
127910
+ if (!existsSync91(configFilePath))
127494
127911
  return null;
127495
- return JSON.parse(readFileSync64(configFilePath, "utf-8"));
127912
+ return JSON.parse(readFileSync65(configFilePath, "utf-8"));
127496
127913
  } catch {
127497
127914
  return null;
127498
127915
  }
@@ -127503,9 +127920,9 @@ function writeReplyListenerDaemonConfig(config) {
127503
127920
  function readReplyListenerPid() {
127504
127921
  try {
127505
127922
  const pidFilePath = getReplyListenerPidFilePath();
127506
- if (!existsSync90(pidFilePath))
127923
+ if (!existsSync91(pidFilePath))
127507
127924
  return null;
127508
- const pid = Number.parseInt(readFileSync64(pidFilePath, "utf-8").trim(), 10);
127925
+ const pid = Number.parseInt(readFileSync65(pidFilePath, "utf-8").trim(), 10);
127509
127926
  return Number.isNaN(pid) ? null : pid;
127510
127927
  } catch {
127511
127928
  return null;
@@ -127516,7 +127933,7 @@ function writeReplyListenerPid(pid) {
127516
127933
  }
127517
127934
  function removeReplyListenerPid() {
127518
127935
  const pidFilePath = getReplyListenerPidFilePath();
127519
- if (existsSync90(pidFilePath)) {
127936
+ if (existsSync91(pidFilePath)) {
127520
127937
  unlinkSync19(pidFilePath);
127521
127938
  }
127522
127939
  }
@@ -127533,7 +127950,7 @@ function markReplyListenerStopped(state3, error) {
127533
127950
 
127534
127951
  // src/openclaw/reply-listener-process.ts
127535
127952
  init_bun_spawn_shim();
127536
- import { readFileSync as readFileSync65 } from "fs";
127953
+ import { readFileSync as readFileSync66 } from "fs";
127537
127954
  var REPLY_LISTENER_DAEMON_IDENTITY_MARKER = "--openclaw-reply-listener-daemon";
127538
127955
  var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
127539
127956
  "PATH",
@@ -127588,7 +128005,7 @@ function isReplyListenerProcessRunning(pid) {
127588
128005
  async function isReplyListenerDaemonProcess(pid) {
127589
128006
  try {
127590
128007
  if (process.platform === "linux") {
127591
- const cmdline = readFileSync65(`/proc/${pid}/cmdline`, "utf-8");
128008
+ const cmdline = readFileSync66(`/proc/${pid}/cmdline`, "utf-8");
127592
128009
  return cmdline.includes(REPLY_LISTENER_DAEMON_IDENTITY_MARKER);
127593
128010
  }
127594
128011
  const processInfo = spawn2(["ps", "-p", String(pid), "-o", "args="], {
@@ -127750,7 +128167,7 @@ async function startReplyListener(config) {
127750
128167
  pendingState.configSignature = getReplyListenerRuntimeSignature(normalizedConfig);
127751
128168
  writeReplyListenerDaemonState(pendingState);
127752
128169
  const currentFile = import.meta.url;
127753
- const daemonScript = currentFile.endsWith(".ts") ? join98(dirname35(new URL(currentFile).pathname), "daemon.ts") : join98(dirname35(new URL(currentFile).pathname), "daemon.js");
128170
+ const daemonScript = currentFile.endsWith(".ts") ? join99(dirname35(new URL(currentFile).pathname), "daemon.ts") : join99(dirname35(new URL(currentFile).pathname), "daemon.js");
127754
128171
  try {
127755
128172
  const processInfo = spawnReplyListenerDaemon(daemonScript, startupToken);
127756
128173
  processInfo.unref();
@@ -128134,21 +128551,21 @@ init_transformer();
128134
128551
  init_logger();
128135
128552
  init_scope_filter2();
128136
128553
  init_bun_file_shim();
128137
- import { existsSync as existsSync91, readFileSync as readFileSync66 } from "fs";
128138
- import { join as join99 } from "path";
128554
+ import { existsSync as existsSync92, readFileSync as readFileSync67 } from "fs";
128555
+ import { join as join100 } from "path";
128139
128556
  import { homedir as homedir20 } from "os";
128140
128557
  function getMcpConfigPaths() {
128141
128558
  const claudeConfigDir = getClaudeConfigDir();
128142
128559
  const cwd = process.cwd();
128143
128560
  return [
128144
- { path: join99(homedir20(), ".claude.json"), scope: "user" },
128145
- { path: join99(claudeConfigDir, ".mcp.json"), scope: "user" },
128146
- { path: join99(cwd, ".mcp.json"), scope: "project" },
128147
- { path: join99(cwd, ".claude", ".mcp.json"), scope: "local" }
128561
+ { path: join100(homedir20(), ".claude.json"), scope: "user" },
128562
+ { path: join100(claudeConfigDir, ".mcp.json"), scope: "user" },
128563
+ { path: join100(cwd, ".mcp.json"), scope: "project" },
128564
+ { path: join100(cwd, ".claude", ".mcp.json"), scope: "local" }
128148
128565
  ];
128149
128566
  }
128150
128567
  async function loadMcpConfigFile(filePath) {
128151
- if (!existsSync91(filePath)) {
128568
+ if (!existsSync92(filePath)) {
128152
128569
  return null;
128153
128570
  }
128154
128571
  try {
@@ -128163,11 +128580,11 @@ function getSystemMcpServerNames() {
128163
128580
  const names = new Set;
128164
128581
  const paths = getMcpConfigPaths();
128165
128582
  const cwd = process.cwd();
128166
- for (const { path: path21 } of paths) {
128167
- if (!existsSync91(path21))
128583
+ for (const { path: path22 } of paths) {
128584
+ if (!existsSync92(path22))
128168
128585
  continue;
128169
128586
  try {
128170
- const content = readFileSync66(path21, "utf-8");
128587
+ const content = readFileSync67(path22, "utf-8");
128171
128588
  const config = JSON.parse(content);
128172
128589
  if (!config?.mcpServers)
128173
128590
  continue;
@@ -128192,30 +128609,30 @@ async function loadMcpConfigs(disabledMcps = []) {
128192
128609
  const paths = getMcpConfigPaths();
128193
128610
  const disabledSet = new Set(disabledMcps);
128194
128611
  const cwd = process.cwd();
128195
- for (const { path: path21, scope } of paths) {
128196
- const config = await loadMcpConfigFile(path21);
128612
+ for (const { path: path22, scope } of paths) {
128613
+ const config = await loadMcpConfigFile(path22);
128197
128614
  if (!config?.mcpServers)
128198
128615
  continue;
128199
128616
  for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
128200
128617
  if (disabledSet.has(name)) {
128201
- log(`Skipping MCP "${name}" (in disabled_mcps)`, { path: path21 });
128618
+ log(`Skipping MCP "${name}" (in disabled_mcps)`, { path: path22 });
128202
128619
  continue;
128203
128620
  }
128204
128621
  if (!shouldLoadMcpServer(serverConfig, cwd)) {
128205
128622
  log(`Skipping MCP server "${name}" because local scope does not match cwd`, {
128206
- path: path21,
128623
+ path: path22,
128207
128624
  projectPath: serverConfig.projectPath,
128208
128625
  cwd
128209
128626
  });
128210
128627
  continue;
128211
128628
  }
128212
128629
  if (serverConfig.disabled) {
128213
- log(`Disabling MCP server "${name}"`, { path: path21 });
128630
+ log(`Disabling MCP server "${name}"`, { path: path22 });
128214
128631
  delete servers[name];
128215
128632
  const existingIndex = loadedServers.findIndex((s) => s.name === name);
128216
128633
  if (existingIndex !== -1) {
128217
128634
  loadedServers.splice(existingIndex, 1);
128218
- log(`Removed previously loaded MCP server "${name}"`, { path: path21 });
128635
+ log(`Removed previously loaded MCP server "${name}"`, { path: path22 });
128219
128636
  }
128220
128637
  continue;
128221
128638
  }
@@ -128227,7 +128644,7 @@ async function loadMcpConfigs(disabledMcps = []) {
128227
128644
  loadedServers.splice(existingIndex, 1);
128228
128645
  }
128229
128646
  loadedServers.push({ name, scope, config: transformed });
128230
- log(`Loaded MCP server "${name}" from ${scope}`, { path: path21 });
128647
+ log(`Loaded MCP server "${name}" from ${scope}`, { path: path22 });
128231
128648
  } catch (error) {
128232
128649
  log(`Failed to transform MCP server "${name}"`, error);
128233
128650
  }
@@ -130007,6 +130424,8 @@ Each exploration prompt should include four fields: **CONTEXT** (what task, whic
130007
130424
 
130008
130425
  After firing exploration agents, keep the returned background task IDs (\`bg_...\`) for result collection and continuation session IDs (\`ses_...\`) for follow-ups. Continue only with non-overlapping preparation: setting up files, reading known-path files, drafting questions. If no non-overlapping work exists, end your response and wait for the completion notification; then use \`background_output(task_id="bg_...")\`, not \`task(task_id="ses_...")\`, to collect results.
130009
130426
 
130427
+ System reminders are input-only signals from the harness. Never write, quote, simulate, or pre-emptively emit \`<system-reminder>\` blocks yourself, and never call \`background_output\` merely because you imagined such a reminder. Only collect a background task after an actual harness-provided completion notification arrives.
130428
+
130010
130429
  Stop searching when you have enough context to proceed confidently, when the same information keeps appearing across sources, when two iterations yield no new useful data, or when you found a direct answer.
130011
130430
 
130012
130431
  ### Tool persistence
@@ -134516,7 +134935,7 @@ createHephaestusAgent2.mode = MODE10;
134516
134935
  // src/agents/builtin-agents/resolve-file-uri.ts
134517
134936
  init_contains_path2();
134518
134937
  init_logger();
134519
- import { existsSync as existsSync92, readFileSync as readFileSync67 } from "fs";
134938
+ import { existsSync as existsSync93, readFileSync as readFileSync68 } from "fs";
134520
134939
  import { homedir as homedir21 } from "os";
134521
134940
  import { isAbsolute as isAbsolute18, resolve as resolve25 } from "path";
134522
134941
  function resolvePromptAppend(promptAppend, configDir) {
@@ -134540,11 +134959,11 @@ function resolvePromptAppend(promptAppend, configDir) {
134540
134959
  });
134541
134960
  return `[WARNING: Path rejected: ${promptAppend} (resolved outside project root ${projectRoot}; file:// prompts must reside within the project boundary)]`;
134542
134961
  }
134543
- if (!existsSync92(filePath)) {
134962
+ if (!existsSync93(filePath)) {
134544
134963
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
134545
134964
  }
134546
134965
  try {
134547
- return readFileSync67(filePath, "utf8");
134966
+ return readFileSync68(filePath, "utf8");
134548
134967
  } catch {
134549
134968
  return `[WARNING: Could not read file: ${promptAppend}]`;
134550
134969
  }
@@ -135820,7 +136239,7 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
135820
136239
  location: "plugin"
135821
136240
  }));
135822
136241
  const discoveredAvailable = discoveredSkills.filter((s) => {
135823
- if (builtinSkillNames.has(s.name) || disabledSkills?.has(s.name))
136242
+ if (disabledSkills?.has(s.name))
135824
136243
  return false;
135825
136244
  if (agentName && s.definition.agent && s.definition.agent !== agentName)
135826
136245
  return false;
@@ -135830,7 +136249,10 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
135830
136249
  description: skill2.definition.description ?? "",
135831
136250
  location: mapScopeToLocation(skill2.scope)
135832
136251
  }));
135833
- return [...builtinAvailable, ...discoveredAvailable];
136252
+ const skillMap = new Map;
136253
+ builtinAvailable.forEach((skill2) => skillMap.set(skill2.name, skill2));
136254
+ discoveredAvailable.forEach((skill2) => skillMap.set(skill2.name, skill2));
136255
+ return Array.from(skillMap.values());
135834
136256
  }
135835
136257
 
135836
136258
  // src/agents/builtin-agents/general-agents.ts
@@ -136705,7 +137127,7 @@ function buildPlanDemoteConfig(prometheusConfig, planOverride) {
136705
137127
  }
136706
137128
 
136707
137129
  // src/shared/host-skill-config.ts
136708
- function toStringArray(value) {
137130
+ function toStringArray2(value) {
136709
137131
  if (!Array.isArray(value))
136710
137132
  return [];
136711
137133
  return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
@@ -136714,10 +137136,7 @@ function adaptHostSkillConfig(value) {
136714
137136
  if (!value || typeof value !== "object")
136715
137137
  return;
136716
137138
  const hostSkillConfig = value;
136717
- const sources = [
136718
- ...toStringArray(hostSkillConfig.paths),
136719
- ...toStringArray(hostSkillConfig.urls)
136720
- ];
137139
+ const sources = toStringArray2(hostSkillConfig.paths);
136721
137140
  if (sources.length === 0)
136722
137141
  return;
136723
137142
  return { sources };
@@ -136762,7 +137181,7 @@ async function applyAgentConfig(params) {
136762
137181
  discoverOpencodeProjectSkills(params.ctx.directory),
136763
137182
  includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
136764
137183
  ]);
136765
- const allDiscoveredSkills = [
137184
+ const allDiscoveredSkills = deduplicateSkillsByName([
136766
137185
  ...discoveredConfigSourceSkills,
136767
137186
  ...discoveredHostConfigSkills,
136768
137187
  ...discoveredOpencodeProjectSkills,
@@ -136771,7 +137190,7 @@ async function applyAgentConfig(params) {
136771
137190
  ...discoveredOpencodeGlobalSkills,
136772
137191
  ...discoveredUserSkills,
136773
137192
  ...discoveredGlobalAgentsSkills
136774
- ];
137193
+ ]);
136775
137194
  const browserProvider = params.pluginConfig.browser_automation_engine?.provider ?? "playwright";
136776
137195
  const currentModel = params.config.model;
136777
137196
  const disabledSkills = new Set(params.pluginConfig.disabled_skills ?? []);
@@ -136944,6 +137363,7 @@ async function applyAgentConfig(params) {
136944
137363
  setDefaultAgentForSort(params.config.default_agent ?? configuredDefaultAgent);
136945
137364
  }
136946
137365
  const agentResult = params.config.agent;
137366
+ clearRegisteredAgentNames();
136947
137367
  for (const name of Object.keys(agentResult)) {
136948
137368
  registerAgentName(name);
136949
137369
  }
@@ -136959,8 +137379,8 @@ init_model_sanitizer();
136959
137379
  init_file_utils2();
136960
137380
  init_shared();
136961
137381
  init_logger();
136962
- import { promises as fs22 } from "fs";
136963
- import { join as join100, basename as basename16 } from "path";
137382
+ import { promises as fs23 } from "fs";
137383
+ import { join as join101, basename as basename16 } from "path";
136964
137384
 
136965
137385
  // src/features/claude-code-command-loader/loader-cache.ts
136966
137386
  var commandLoaderCache = new Map;
@@ -136968,13 +137388,13 @@ var commandLoaderCache = new Map;
136968
137388
  // src/features/claude-code-command-loader/loader.ts
136969
137389
  async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
136970
137390
  try {
136971
- await fs22.access(commandsDir);
137391
+ await fs23.access(commandsDir);
136972
137392
  } catch {
136973
137393
  return [];
136974
137394
  }
136975
137395
  let realPath;
136976
137396
  try {
136977
- realPath = await fs22.realpath(commandsDir);
137397
+ realPath = await fs23.realpath(commandsDir);
136978
137398
  } catch (error) {
136979
137399
  log(`Failed to resolve command directory: ${commandsDir}`, error);
136980
137400
  return [];
@@ -136985,7 +137405,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
136985
137405
  visited.add(realPath);
136986
137406
  let entries;
136987
137407
  try {
136988
- entries = await fs22.readdir(commandsDir, { withFileTypes: true });
137408
+ entries = await fs23.readdir(commandsDir, { withFileTypes: true });
136989
137409
  } catch (error) {
136990
137410
  log(`Failed to read command directory: ${commandsDir}`, error);
136991
137411
  return [];
@@ -136997,7 +137417,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
136997
137417
  continue;
136998
137418
  if (entry.name.startsWith("."))
136999
137419
  continue;
137000
- const subDirPath = join100(commandsDir, entry.name);
137420
+ const subDirPath = join101(commandsDir, entry.name);
137001
137421
  const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
137002
137422
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
137003
137423
  commands2.push(...subCommands);
@@ -137005,11 +137425,11 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
137005
137425
  }
137006
137426
  if (!isMarkdownFile(entry))
137007
137427
  continue;
137008
- const commandPath = join100(commandsDir, entry.name);
137428
+ const commandPath = join101(commandsDir, entry.name);
137009
137429
  const baseCommandName = basename16(entry.name, ".md");
137010
137430
  const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
137011
137431
  try {
137012
- const content = await fs22.readFile(commandPath, "utf-8");
137432
+ const content = await fs23.readFile(commandPath, "utf-8");
137013
137433
  const { data, body } = parseFrontmatter(content);
137014
137434
  const wrappedTemplate = `<command-instruction>
137015
137435
  ${body.trim()}
@@ -137064,12 +137484,12 @@ function commandsToRecord(commands2) {
137064
137484
  return result;
137065
137485
  }
137066
137486
  async function loadUserCommands() {
137067
- const userCommandsDir = join100(getClaudeConfigDir(), "commands");
137487
+ const userCommandsDir = join101(getClaudeConfigDir(), "commands");
137068
137488
  const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
137069
137489
  return commandsToRecord(commands2);
137070
137490
  }
137071
137491
  async function loadProjectCommands(directory) {
137072
- const projectCommandsDir = join100(directory ?? process.cwd(), ".claude", "commands");
137492
+ const projectCommandsDir = join101(directory ?? process.cwd(), ".claude", "commands");
137073
137493
  const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
137074
137494
  return commandsToRecord(commands2);
137075
137495
  }
@@ -137220,13 +137640,13 @@ var grep_app = {
137220
137640
  };
137221
137641
 
137222
137642
  // src/mcp/ast-grep.ts
137223
- import { existsSync as existsSync93 } from "fs";
137643
+ import { existsSync as existsSync94 } from "fs";
137224
137644
  import { dirname as dirname36, resolve as resolve26 } from "path";
137225
137645
  import { fileURLToPath as fileURLToPath5 } from "url";
137226
137646
 
137227
137647
  // src/mcp/cli-suffix.ts
137228
- function normalizeCliPath(path21) {
137229
- return path21.replaceAll("\\", "/");
137648
+ function normalizeCliPath(path22) {
137649
+ return path22.replaceAll("\\", "/");
137230
137650
  }
137231
137651
  function hasCliSuffix(candidatePath, suffix) {
137232
137652
  return normalizeCliPath(candidatePath).endsWith(normalizeCliPath(suffix));
@@ -137320,11 +137740,11 @@ function getModuleDirectory(moduleUrl) {
137320
137740
  }
137321
137741
  function createFallbackCandidate(resolveExecutable) {
137322
137742
  const runtime6 = resolveJavaScriptRuntime(resolveExecutable);
137323
- const path21 = resolve26(PACKAGE_REL, DIST_CLI_REL);
137324
- return { command: [runtime6.command, path21, "mcp"], path: path21, exists: runtime6.available, runtimeAvailable: runtime6.available };
137743
+ const path22 = resolve26(PACKAGE_REL, DIST_CLI_REL);
137744
+ return { command: [runtime6.command, path22, "mcp"], path: path22, exists: runtime6.available, runtimeAvailable: runtime6.available };
137325
137745
  }
137326
137746
  function resolveAstGrepCommand(options = {}) {
137327
- const pathExists = options.exists ?? existsSync93;
137747
+ const pathExists = options.exists ?? existsSync94;
137328
137748
  const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
137329
137749
  const candidates = [];
137330
137750
  const seenPaths = new Set;
@@ -137360,7 +137780,7 @@ function createAstGrepMcpConfig(options = {}) {
137360
137780
  }
137361
137781
 
137362
137782
  // src/mcp/lsp.ts
137363
- import { existsSync as existsSync94 } from "fs";
137783
+ import { existsSync as existsSync95 } from "fs";
137364
137784
  import { dirname as dirname37, resolve as resolve27 } from "path";
137365
137785
  import { fileURLToPath as fileURLToPath6 } from "url";
137366
137786
  var SUBMODULE_REL = "packages/lsp-tools-mcp";
@@ -137449,7 +137869,7 @@ function createBootstrapCandidate(root, resolveExecutable) {
137449
137869
  };
137450
137870
  }
137451
137871
  function resolveLspCommand(options = {}) {
137452
- const pathExists = options.exists ?? existsSync94;
137872
+ const pathExists = options.exists ?? existsSync95;
137453
137873
  const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
137454
137874
  const candidates = [];
137455
137875
  const seenPaths = new Set;
@@ -137981,11 +138401,25 @@ async function createSkillContext(args) {
137981
138401
  return true;
137982
138402
  });
137983
138403
  const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
137984
- const [configSourceSkills, userSkills, globalSkills, projectSkills, opencodeProjectSkills, agentsProjectSkills, agentsGlobalSkills] = await Promise.all([
138404
+ const hostSkillConfig = adaptHostSkillConfig(readOpencodeConfigSkills(directory));
138405
+ const [
138406
+ configSourceSkills,
138407
+ hostConfigSkills,
138408
+ userSkills,
138409
+ globalSkills,
138410
+ projectSkills,
138411
+ opencodeProjectSkills,
138412
+ agentsProjectSkills,
138413
+ agentsGlobalSkills
138414
+ ] = await Promise.all([
137985
138415
  discoverConfigSourceSkills({
137986
138416
  config: pluginConfig.skills,
137987
138417
  configDir: directory
137988
138418
  }),
138419
+ discoverConfigSourceSkills({
138420
+ config: hostSkillConfig,
138421
+ configDir: directory
138422
+ }),
137989
138423
  includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
137990
138424
  discoverOpencodeGlobalSkills(),
137991
138425
  includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
@@ -137993,7 +138427,12 @@ async function createSkillContext(args) {
137993
138427
  discoverProjectAgentsSkills(directory),
137994
138428
  discoverGlobalAgentsSkills()
137995
138429
  ]);
137996
- const filteredConfigSourceSkills = filterProviderGatedSkills(configSourceSkills, browserProvider);
138430
+ const configSkillsHostWins = new Map;
138431
+ for (const skill2 of configSourceSkills)
138432
+ configSkillsHostWins.set(skill2.name, skill2);
138433
+ for (const skill2 of hostConfigSkills)
138434
+ configSkillsHostWins.set(skill2.name, skill2);
138435
+ const filteredConfigSourceSkills = filterProviderGatedSkills(Array.from(configSkillsHostWins.values()), browserProvider);
137997
138436
  const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
137998
138437
  const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
137999
138438
  const filteredProjectSkills = filterProviderGatedSkills(projectSkills, browserProvider);
@@ -138434,7 +138873,7 @@ async function loadTeamSpec(teamName, config, projectRoot, options) {
138434
138873
 
138435
138874
  // src/features/team-mode/team-runtime/create.ts
138436
138875
  import { access as access4, mkdir as mkdir5 } from "fs/promises";
138437
- import path21 from "path";
138876
+ import path22 from "path";
138438
138877
  init_paths();
138439
138878
  init_store();
138440
138879
  init_team_session_registry();
@@ -138708,7 +139147,7 @@ async function findExistingRuntime(spec, leadSessionId, config) {
138708
139147
  }
138709
139148
  }
138710
139149
  async function createMemberWorktree(memberWorktreePath, projectRoot) {
138711
- const absolutePath = path21.isAbsolute(memberWorktreePath) ? memberWorktreePath : path21.resolve(projectRoot, memberWorktreePath);
139150
+ const absolutePath = path22.isAbsolute(memberWorktreePath) ? memberWorktreePath : path22.resolve(projectRoot, memberWorktreePath);
138712
139151
  await mkdir5(absolutePath, { recursive: true });
138713
139152
  return absolutePath;
138714
139153
  }
@@ -138979,6 +139418,29 @@ var TeamCreateArgsSchema = z41.object({
138979
139418
  ctx.addIssue({ code: "custom", message: "Provide exactly one of teamName or inline_spec." });
138980
139419
  }
138981
139420
  });
139421
+ var TeamCreateInlineMemberToolSchema = tool.schema.object({
139422
+ name: tool.schema.string().optional().describe("Member name, kebab-case or natural text; normalized before team creation."),
139423
+ kind: tool.schema.enum(["category", "subagent_type"]).optional().describe("Member kind. Use category for category-routed workers, or subagent_type for a specific eligible agent."),
139424
+ category: tool.schema.string().optional().describe("Required for category members unless a fallback category can be inferred. Examples: quick, unspecified-low, unspecified-high, deep, ultrabrain, visual-engineering, writing, artistry, git, data-analysis."),
139425
+ subagent_type: tool.schema.string().optional().describe("Required for subagent_type members. Eligible examples: sisyphus, atlas, sisyphus-junior."),
139426
+ prompt: tool.schema.string().optional().describe("Task prompt for this member. Category members need a concrete work prompt."),
139427
+ systemPrompt: tool.schema.string().optional().describe("Legacy alias for prompt; normalized before team creation."),
139428
+ loadSkills: tool.schema.array(tool.schema.string()).optional().describe("Optional skills to load for this member."),
139429
+ role: tool.schema.string().optional().describe("Optional natural-language role used to build a prompt when prompt is omitted."),
139430
+ description: tool.schema.string().optional().describe("Optional natural-language description used to build a prompt when prompt is omitted.")
139431
+ });
139432
+ var TeamCreateInlineSpecToolSchema = tool.schema.union([
139433
+ tool.schema.object({
139434
+ name: tool.schema.string().describe("Team name, kebab-case or natural text; normalized before team creation."),
139435
+ description: tool.schema.string().optional().describe("Optional team description."),
139436
+ leadAgentId: tool.schema.string().optional().describe("Optional member name to use as team lead."),
139437
+ lead: TeamCreateInlineMemberToolSchema.optional().describe("Optional explicit lead member."),
139438
+ members: tool.schema.array(TeamCreateInlineMemberToolSchema).describe("Team members; members must be a flat array, not an object or nested groups. Provide 1-8 members."),
139439
+ teamAllowedPaths: tool.schema.array(tool.schema.string()).optional().describe("Optional paths the team may access."),
139440
+ sessionPermission: tool.schema.string().optional().describe("Optional session permission policy.")
139441
+ }),
139442
+ tool.schema.string().describe("JSON string containing the same inline team spec object.")
139443
+ ]);
138982
139444
  var TeamDeleteArgsSchema = z41.object({ teamRunId: z41.string().min(1), force: z41.boolean().optional() });
138983
139445
  var TeamShutdownRequestArgsSchema = z41.object({ teamRunId: z41.string().min(1), targetMemberName: z41.string().min(1) });
138984
139446
  var TeamApproveShutdownArgsSchema = z41.object({ teamRunId: z41.string().min(1), memberName: z41.string().min(1) });
@@ -139013,8 +139475,8 @@ function parseTeamCreateArgs(rawArgs) {
139013
139475
  }
139014
139476
  return result.data;
139015
139477
  }
139016
- function formatZodIssuePath(path22) {
139017
- return path22.length > 0 ? path22.join(".") : "<root>";
139478
+ function formatZodIssuePath(path23) {
139479
+ return path23.length > 0 ? path23.join(".") : "<root>";
139018
139480
  }
139019
139481
  function formatTeamSpecIssues(error) {
139020
139482
  return error.issues.slice(0, 5).map((issue) => `${formatZodIssuePath(issue.path)}: ${issue.message}`).join("; ");
@@ -139077,7 +139539,7 @@ function createTeamCreateTool(config, client, bgMgr, tmuxMgr, executorConfig, de
139077
139539
  description: "Create a team run from a named or inline team spec.",
139078
139540
  args: {
139079
139541
  teamName: tool.schema.string().optional().describe("Named team spec to load. Provide exactly one of teamName or inline_spec."),
139080
- inline_spec: tool.schema.unknown().optional().describe("Inline team spec object or JSON string. Provide exactly one of teamName or inline_spec."),
139542
+ inline_spec: TeamCreateInlineSpecToolSchema.optional().describe('Inline team spec object or JSON string. Provide exactly one of teamName or inline_spec; members must be a flat array, e.g. { name: "project-analysis-team", members: [{ name: "structure-analyst", category: "quick", prompt: "Analyze project structure." }] }.'),
139081
139543
  leadSessionId: tool.schema.string().optional().describe("Optional non-empty session ID override. Usually omit this and let team_create use the current session.")
139082
139544
  },
139083
139545
  async execute(rawArgs, toolContext) {
@@ -139187,7 +139649,7 @@ init_store();
139187
139649
  // src/features/team-mode/team-tasklist/list.ts
139188
139650
  init_logger();
139189
139651
  import { readdir as readdir8, readFile as readFile10 } from "fs/promises";
139190
- import path22 from "path";
139652
+ import path23 from "path";
139191
139653
 
139192
139654
  // src/features/team-mode/team-registry/index.ts
139193
139655
  init_paths();
@@ -139206,7 +139668,7 @@ async function listTasks(teamRunId, config, filter) {
139206
139668
  for (const entry of entries) {
139207
139669
  if (entry.isDirectory() || entry.name.startsWith(".") || !entry.name.endsWith(".json"))
139208
139670
  continue;
139209
- const taskPath = path22.join(tasksDirectory, entry.name);
139671
+ const taskPath = path23.join(tasksDirectory, entry.name);
139210
139672
  try {
139211
139673
  const taskContent = await readFile10(taskPath, "utf8");
139212
139674
  const parsedTask = TaskSchema.safeParse(JSON.parse(taskContent));
@@ -139238,7 +139700,7 @@ async function listTasks(teamRunId, config, filter) {
139238
139700
  // src/features/team-mode/team-runtime/status.ts
139239
139701
  init_paths();
139240
139702
  import { readdir as readdir9 } from "fs/promises";
139241
- import path23 from "path";
139703
+ import path24 from "path";
139242
139704
  function getPrimaryModelKey(bgMgr, leadSessionId) {
139243
139705
  if (!bgMgr || !leadSessionId)
139244
139706
  return;
@@ -139289,10 +139751,10 @@ async function aggregateStatus(teamRunId, config, bgMgr) {
139289
139751
  const concurrencyCounts = resolveConcurrencyCounts(teamBackgroundManager, runtimeState.leadSessionId);
139290
139752
  const teamRunIdSpecific = teamBackgroundManager?.listTasksByParentSession?.(runtimeState.leadSessionId ?? teamRunId)?.length;
139291
139753
  const baseDir = resolveBaseDir(config);
139292
- const claimsDir = path23.join(getTasksDir(baseDir, teamRunId), "claims");
139754
+ const claimsDir = path24.join(getTasksDir(baseDir, teamRunId), "claims");
139293
139755
  const staleLockEntries = await readdir9(claimsDir, { withFileTypes: true }).catch(() => []);
139294
139756
  const staleLockPaths = await Promise.all(staleLockEntries.filter((entry) => entry.isFile() && entry.name.endsWith(".lock")).map(async (entry) => {
139295
- const lockPath = path23.join(claimsDir, entry.name);
139757
+ const lockPath = path24.join(claimsDir, entry.name);
139296
139758
  return await detectStaleLock(lockPath, 300000) ? lockPath : undefined;
139297
139759
  }));
139298
139760
  return {
@@ -139391,7 +139853,7 @@ function createTeamListTool(config, client, deps = defaultDeps7) {
139391
139853
 
139392
139854
  // src/features/team-mode/team-tasklist/claim.ts
139393
139855
  import { access as access5, mkdir as mkdir6 } from "fs/promises";
139394
- import path25 from "path";
139856
+ import path26 from "path";
139395
139857
  init_locks();
139396
139858
  init_types2();
139397
139859
 
@@ -139405,11 +139867,11 @@ function canClaim(task, allTasks) {
139405
139867
 
139406
139868
  // src/features/team-mode/team-tasklist/get.ts
139407
139869
  import { readFile as readFile11 } from "fs/promises";
139408
- import path24 from "path";
139870
+ import path25 from "path";
139409
139871
  init_types2();
139410
139872
  async function getTask(teamRunId, taskId, config) {
139411
139873
  const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
139412
- const taskContent = await readFile11(path24.join(tasksDirectory, `${taskId}.json`), "utf8");
139874
+ const taskContent = await readFile11(path25.join(tasksDirectory, `${taskId}.json`), "utf8");
139413
139875
  return TaskSchema.parse(JSON.parse(taskContent));
139414
139876
  }
139415
139877
 
@@ -139448,9 +139910,9 @@ class BlockedByError extends Error {
139448
139910
  async function claimTask(teamRunId, taskId, memberName, config) {
139449
139911
  const baseDirectory = resolveBaseDir(config);
139450
139912
  const tasksDirectory = getTasksDir(baseDirectory, teamRunId);
139451
- const claimsDirectory = path25.join(tasksDirectory, "claims");
139452
- const taskPath = path25.join(tasksDirectory, `${taskId}.json`);
139453
- const claimLockPath = path25.join(claimsDirectory, `${taskId}.lock`);
139913
+ const claimsDirectory = path26.join(tasksDirectory, "claims");
139914
+ const taskPath = path26.join(tasksDirectory, `${taskId}.json`);
139915
+ const claimLockPath = path26.join(claimsDirectory, `${taskId}.lock`);
139454
139916
  await mkdir6(claimsDirectory, { recursive: true, mode: 448 });
139455
139917
  const task = await getTask(teamRunId, taskId, config);
139456
139918
  if (task.status !== "pending") {
@@ -139489,7 +139951,7 @@ async function claimTask(teamRunId, taskId, memberName, config) {
139489
139951
  }
139490
139952
  // src/features/team-mode/team-tasklist/store.ts
139491
139953
  import { mkdir as mkdir7, readFile as readFile12 } from "fs/promises";
139492
- import path26 from "path";
139954
+ import path27 from "path";
139493
139955
  init_locks();
139494
139956
  init_types2();
139495
139957
  var HIGH_WATERMARK_FILE = ".highwatermark";
@@ -139506,9 +139968,9 @@ async function readHighWatermark(watermarkPath) {
139506
139968
  async function createTask(teamRunId, taskInput, config) {
139507
139969
  const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
139508
139970
  await mkdir7(tasksDirectory, { recursive: true, mode: 448 });
139509
- await mkdir7(path26.join(tasksDirectory, "claims"), { recursive: true, mode: 448 });
139510
- return withLock(path26.join(tasksDirectory, ".lock"), async () => {
139511
- const watermarkPath = path26.join(tasksDirectory, HIGH_WATERMARK_FILE);
139971
+ await mkdir7(path27.join(tasksDirectory, "claims"), { recursive: true, mode: 448 });
139972
+ return withLock(path27.join(tasksDirectory, ".lock"), async () => {
139973
+ const watermarkPath = path27.join(tasksDirectory, HIGH_WATERMARK_FILE);
139512
139974
  const nextTaskId = await readHighWatermark(watermarkPath) + 1;
139513
139975
  await atomicWrite(watermarkPath, String(nextTaskId));
139514
139976
  const now = Date.now();
@@ -139519,13 +139981,13 @@ async function createTask(teamRunId, taskInput, config) {
139519
139981
  createdAt: now,
139520
139982
  updatedAt: now
139521
139983
  });
139522
- await atomicWrite(path26.join(tasksDirectory, `${task.id}.json`), `${JSON.stringify(task, null, 2)}
139984
+ await atomicWrite(path27.join(tasksDirectory, `${task.id}.json`), `${JSON.stringify(task, null, 2)}
139523
139985
  `);
139524
139986
  return task;
139525
139987
  }, { ownerTag: `create-task:${teamRunId}` });
139526
139988
  }
139527
139989
  // src/features/team-mode/team-tasklist/update.ts
139528
- import path27 from "path";
139990
+ import path28 from "path";
139529
139991
  init_locks();
139530
139992
  init_types2();
139531
139993
  var ALLOWED_TRANSITIONS = {
@@ -139574,7 +140036,7 @@ async function updateTaskStatus(teamRunId, taskId, newStatus, memberName, config
139574
140036
  updatedAt: Date.now()
139575
140037
  });
139576
140038
  const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
139577
- await atomicWrite(path27.join(tasksDirectory, `${taskId}.json`), `${JSON.stringify(updatedTask, null, 2)}
140039
+ await atomicWrite(path28.join(tasksDirectory, `${taskId}.json`), `${JSON.stringify(updatedTask, null, 2)}
139578
140040
  `);
139579
140041
  return updatedTask;
139580
140042
  }
@@ -140306,8 +140768,8 @@ init_agent_display_names();
140306
140768
  // src/plugin/ultrawork-db-model-override.ts
140307
140769
  init_data_path();
140308
140770
  init_shared();
140309
- import { join as join101 } from "path";
140310
- import { existsSync as existsSync95 } from "fs";
140771
+ import { join as join102 } from "path";
140772
+ import { existsSync as existsSync96 } from "fs";
140311
140773
  async function importBunSqlite() {
140312
140774
  if (typeof globalThis.Bun === "undefined") {
140313
140775
  return null;
@@ -140320,7 +140782,7 @@ async function importBunSqlite() {
140320
140782
  }
140321
140783
  }
140322
140784
  function getDbPath() {
140323
- return join101(getDataDir(), "opencode", "opencode.db");
140785
+ return join102(getDataDir(), "opencode", "opencode.db");
140324
140786
  }
140325
140787
  var MAX_MICROTASK_RETRIES = 10;
140326
140788
  function tryUpdateMessageModel(db, messageId, targetModel, variant) {
@@ -140403,7 +140865,7 @@ function scheduleDeferredModelOverride(messageId, targetModel, variant) {
140403
140865
  return;
140404
140866
  }
140405
140867
  const dbPath = getDbPath();
140406
- if (!existsSync95(dbPath)) {
140868
+ if (!existsSync96(dbPath)) {
140407
140869
  log("[ultrawork-db-override] DB not found, skipping deferred override");
140408
140870
  return;
140409
140871
  }
@@ -140762,11 +141224,17 @@ init_model_normalization();
140762
141224
  var ASSISTANT_PREFILL_RECOVERY_TEXT = "[internal] Continue from the previous assistant state.";
140763
141225
  var ASSISTANT_PREFILL_UNSUPPORTED_PROVIDERS = new Set([
140764
141226
  "anthropic",
140765
- "google-vertex-anthropic"
141227
+ "aws-bedrock-anthropic",
141228
+ "github-copilot",
141229
+ "github-copilot-enterprise",
141230
+ "google-vertex-anthropic",
141231
+ "opencode",
141232
+ "opencode-go",
141233
+ "opencode-zen-proxy",
141234
+ "vercel"
140766
141235
  ]);
140767
141236
  var ASSISTANT_PREFILL_UNSUPPORTED_MODEL_PREFIXES = [
140768
- "claude-opus-4-7",
140769
- "claude-opus-4-6",
141237
+ "claude-opus-4",
140770
141238
  "claude-sonnet-4-6",
140771
141239
  "claude-mythos"
140772
141240
  ];
@@ -140817,15 +141285,26 @@ function findLastUserModel(messages) {
140817
141285
  }
140818
141286
  return;
140819
141287
  }
141288
+ function normalizeAssistantPrefillModelID(modelID) {
141289
+ const normalizedModelID = normalizeModelID(modelID.toLowerCase());
141290
+ return normalizedModelID.split(/[/.~:@]+/).find((segment) => segment.startsWith("claude-")) ?? normalizedModelID;
141291
+ }
141292
+ function hasAnthropicModelNamespace(modelID) {
141293
+ const normalizedModelID = normalizeModelID(modelID.toLowerCase());
141294
+ return /(?:^|[/.~:@])anthropic(?:$|[/.~:@])/.test(normalizedModelID);
141295
+ }
141296
+ function providerCanExposeUnsupportedAssistantPrefill(providerID, modelID) {
141297
+ return ASSISTANT_PREFILL_UNSUPPORTED_PROVIDERS.has(providerID) || hasAnthropicModelNamespace(modelID);
141298
+ }
140820
141299
  function shouldRepairAssistantPrefillForModel(model) {
140821
141300
  if (!model) {
140822
141301
  return false;
140823
141302
  }
140824
141303
  const providerID = model.providerID.toLowerCase();
140825
- if (!ASSISTANT_PREFILL_UNSUPPORTED_PROVIDERS.has(providerID)) {
141304
+ if (!providerCanExposeUnsupportedAssistantPrefill(providerID, model.modelID)) {
140826
141305
  return false;
140827
141306
  }
140828
- const modelID = normalizeModelID(model.modelID.toLowerCase());
141307
+ const modelID = normalizeAssistantPrefillModelID(model.modelID);
140829
141308
  return ASSISTANT_PREFILL_UNSUPPORTED_MODEL_PREFIXES.some((prefix) => modelID.startsWith(prefix));
140830
141309
  }
140831
141310
  function isCompactionContinuationPart(part) {
@@ -140886,9 +141365,10 @@ async function runMessagesTransformHookSafely(hookName, handler, input, output)
140886
141365
  try {
140887
141366
  await Promise.resolve(handler(input, output));
140888
141367
  } catch (error) {
141368
+ const hookError = error instanceof Error ? error : new Error(String(error));
140889
141369
  log("[messages-transform] hook execution failed", {
140890
141370
  hook: hookName,
140891
- error
141371
+ error: hookError
140892
141372
  });
140893
141373
  }
140894
141374
  }
@@ -140930,19 +141410,19 @@ init_session_tools_store();
140930
141410
  // src/features/team-mode/team-mailbox/ack.ts
140931
141411
  init_paths();
140932
141412
  import { mkdir as mkdir8, rename as rename3 } from "fs/promises";
140933
- import path28 from "path";
141413
+ import path29 from "path";
140934
141414
  async function ackMessages(teamRunId, memberName, messageIds, config) {
140935
141415
  const baseDir = resolveBaseDir(config);
140936
141416
  const inboxDir = getInboxDir(baseDir, teamRunId, memberName);
140937
- const processedDir = path28.join(inboxDir, "processed");
141417
+ const processedDir = path29.join(inboxDir, "processed");
140938
141418
  await mkdir8(processedDir, { recursive: true, mode: 448 });
140939
141419
  for (const messageId of messageIds) {
140940
141420
  const messageFileName = `${messageId}.json`;
140941
141421
  const sourcePaths = [
140942
- path28.join(inboxDir, messageFileName),
140943
- path28.join(inboxDir, `.delivering-${messageFileName}`)
141422
+ path29.join(inboxDir, messageFileName),
141423
+ path29.join(inboxDir, `.delivering-${messageFileName}`)
140944
141424
  ];
140945
- const targetPath = path28.join(processedDir, messageFileName);
141425
+ const targetPath = path29.join(processedDir, messageFileName);
140946
141426
  for (const sourcePath of sourcePaths) {
140947
141427
  try {
140948
141428
  await rename3(sourcePath, targetPath);
@@ -141514,6 +141994,33 @@ function normalizeSessionStatusToIdle(input) {
141514
141994
 
141515
141995
  // src/plugin/event.ts
141516
141996
  init_event_session_id();
141997
+
141998
+ // src/plugin/user-abort-interrupted-recovery-guard.ts
141999
+ var USER_ABORT_ERROR_NAMES = new Set(["MessageAbortedError", "AbortError"]);
142000
+ function createUserAbortInterruptedRecoveryGuard() {
142001
+ const abortedSessions = new Set;
142002
+ return {
142003
+ noteSessionError(sessionID, errorName) {
142004
+ if (!errorName || !USER_ABORT_ERROR_NAMES.has(errorName)) {
142005
+ return false;
142006
+ }
142007
+ abortedSessions.add(sessionID);
142008
+ return true;
142009
+ },
142010
+ shouldSkipRecovery(sessionID) {
142011
+ const shouldSkip = abortedSessions.has(sessionID);
142012
+ if (shouldSkip) {
142013
+ abortedSessions.delete(sessionID);
142014
+ }
142015
+ return shouldSkip;
142016
+ },
142017
+ clear(sessionID) {
142018
+ abortedSessions.delete(sessionID);
142019
+ }
142020
+ };
142021
+ }
142022
+
142023
+ // src/plugin/event.ts
141517
142024
  function isRecord26(value) {
141518
142025
  return typeof value === "object" && value !== null;
141519
142026
  }
@@ -141598,6 +142105,7 @@ function createEventHandler2(args) {
141598
142105
  const lastKnownModelBySession = new Map;
141599
142106
  const modelFallbackContinuationsInFlight = new Set;
141600
142107
  const lastDispatchedModelFallbackContinuationKeys = new Map;
142108
+ const userAbortInterruptedRecoveryGuard = createUserAbortInterruptedRecoveryGuard();
141601
142109
  const resolveFallbackProviderID = (sessionID, providerHint) => {
141602
142110
  const normalizedProviderHint = providerHint?.trim();
141603
142111
  if (normalizedProviderHint) {
@@ -141651,7 +142159,6 @@ function createEventHandler2(args) {
141651
142159
  await runEventHookSafely("sessionNotification", hooks2.sessionNotification, input);
141652
142160
  await runEventHookSafely("todoContinuationEnforcer", hooks2.todoContinuationEnforcer?.handler, input);
141653
142161
  await runEventHookSafely("unstableAgentBabysitter", hooks2.unstableAgentBabysitter?.event, input);
141654
- await runEventHookSafely("contextWindowMonitor", hooks2.contextWindowMonitor?.event, input);
141655
142162
  await runEventHookSafely("preemptiveCompaction", hooks2.preemptiveCompaction?.event, input);
141656
142163
  await runEventHookSafely("directoryAgentsInjector", hooks2.directoryAgentsInjector?.event, input);
141657
142164
  await runEventHookSafely("directoryReadmeInjector", hooks2.directoryReadmeInjector?.event, input);
@@ -141713,6 +142220,10 @@ function createEventHandler2(args) {
141713
142220
  if (!sessionID || !hooks2.sessionRecovery?.handleInterruptedToolResultsOnIdle) {
141714
142221
  return false;
141715
142222
  }
142223
+ if (userAbortInterruptedRecoveryGuard.shouldSkipRecovery(sessionID)) {
142224
+ log("[event] interrupted tool recovery skipped after user abort", { sessionID });
142225
+ return false;
142226
+ }
141716
142227
  return hooks2.sessionRecovery.handleInterruptedToolResultsOnIdle(sessionID);
141717
142228
  };
141718
142229
  const dispatchIdleOnlyHooks = async (input) => {
@@ -141872,10 +142383,6 @@ function createEventHandler2(args) {
141872
142383
  const emittedAt = recentSyntheticIdles.get(sessionID);
141873
142384
  if (emittedAt !== undefined && now - emittedAt < DEDUP_WINDOW_MS2) {
141874
142385
  recentSyntheticIdles.delete(sessionID);
141875
- const lastAnyIdleAt = recentAnyIdles.get(sessionID);
141876
- if (lastAnyIdleAt === emittedAt) {
141877
- recentAnyIdles.delete(sessionID);
141878
- }
141879
142386
  }
141880
142387
  }
141881
142388
  const recovered = await recoverInterruptedToolResultsOnIdleEvent(input);
@@ -141964,6 +142471,7 @@ function createEventHandler2(args) {
141964
142471
  lastKnownModelBySession.delete(sessionID);
141965
142472
  modelFallbackContinuationsInFlight.delete(sessionID);
141966
142473
  lastDispatchedModelFallbackContinuationKeys.delete(sessionID);
142474
+ userAbortInterruptedRecoveryGuard.clear(sessionID);
141967
142475
  if (modelFallback) {
141968
142476
  clearPendingModelFallback(modelFallback, sessionID);
141969
142477
  clearSessionFallbackChain(modelFallback, sessionID);
@@ -142042,6 +142550,10 @@ function createEventHandler2(args) {
142042
142550
  lastKnownModelBySession.set(sessionID, { providerID, modelID });
142043
142551
  setSessionModel(sessionID, { providerID, modelID });
142044
142552
  }
142553
+ userAbortInterruptedRecoveryGuard.clear(sessionID);
142554
+ }
142555
+ if (sessionID && role === "assistant") {
142556
+ userAbortInterruptedRecoveryGuard.noteSessionError(sessionID, extractErrorName3(info?.error));
142045
142557
  }
142046
142558
  if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
142047
142559
  try {
@@ -142157,6 +142669,9 @@ function createEventHandler2(args) {
142157
142669
  const errorName = extractErrorName3(error);
142158
142670
  const errorMessage = extractErrorMessage3(error);
142159
142671
  const errorInfo = { name: errorName, message: errorMessage };
142672
+ if (sessionID) {
142673
+ userAbortInterruptedRecoveryGuard.noteSessionError(sessionID, errorName);
142674
+ }
142160
142675
  if (hooks2.sessionRecovery?.isRecoverableError(error)) {
142161
142676
  const messageInfo = {
142162
142677
  id: props?.messageID,
@@ -142356,7 +142871,6 @@ function createToolExecuteAfterHandler3(args) {
142356
142871
  await hooks2.toolOutputTruncator?.["tool.execute.after"]?.(hookInput, output);
142357
142872
  await hooks2.claudeCodeHooks?.["tool.execute.after"]?.(hookInput, output);
142358
142873
  await hooks2.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output);
142359
- await hooks2.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output);
142360
142874
  await hooks2.commentChecker?.["tool.execute.after"]?.(hookInput, output);
142361
142875
  await hooks2.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output);
142362
142876
  await hooks2.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output);
@@ -142656,9 +143170,9 @@ function createPluginInterface(args) {
142656
143170
  }
142657
143171
 
142658
143172
  // src/plugin-config.ts
142659
- import * as fs23 from "fs";
143173
+ import * as fs24 from "fs";
142660
143174
  import { homedir as homedir22 } from "os";
142661
- import * as path29 from "path";
143175
+ import * as path30 from "path";
142662
143176
  init_shared();
142663
143177
  init_plugin_identity();
142664
143178
 
@@ -142788,22 +143302,22 @@ function resolveHomeDirectory() {
142788
143302
  return process.env.HOME ?? process.env.USERPROFILE ?? homedir22();
142789
143303
  }
142790
143304
  function resolveConfigPathAfterLegacyMigration(detectedPath) {
142791
- if (!path29.basename(detectedPath).startsWith(LEGACY_CONFIG_BASENAME)) {
143305
+ if (!path30.basename(detectedPath).startsWith(LEGACY_CONFIG_BASENAME)) {
142792
143306
  return detectedPath;
142793
143307
  }
142794
143308
  const migrated = migrateLegacyConfigFile(detectedPath);
142795
- const canonicalPath = path29.join(path29.dirname(detectedPath), `${CONFIG_BASENAME}${path29.extname(detectedPath)}`);
142796
- if (migrated || fs23.existsSync(canonicalPath)) {
143309
+ const canonicalPath = path30.join(path30.dirname(detectedPath), `${CONFIG_BASENAME}${path30.extname(detectedPath)}`);
143310
+ if (migrated || fs24.existsSync(canonicalPath)) {
142797
143311
  return canonicalPath;
142798
143312
  }
142799
143313
  return detectedPath;
142800
143314
  }
142801
143315
  function loadExplicitGitMasterOverrides(configPath) {
142802
143316
  try {
142803
- if (!fs23.existsSync(configPath)) {
143317
+ if (!fs24.existsSync(configPath)) {
142804
143318
  return;
142805
143319
  }
142806
- const content = fs23.readFileSync(configPath, "utf-8");
143320
+ const content = fs24.readFileSync(configPath, "utf-8");
142807
143321
  const rawConfig = parseJsonc(content);
142808
143322
  const gitMaster = rawConfig.git_master;
142809
143323
  if (gitMaster && typeof gitMaster === "object" && !Array.isArray(gitMaster)) {
@@ -142860,8 +143374,8 @@ function parseConfigPartially(rawConfig) {
142860
143374
  }
142861
143375
  function loadConfigFromPath2(configPath, _ctx) {
142862
143376
  try {
142863
- if (fs23.existsSync(configPath)) {
142864
- const content = fs23.readFileSync(configPath, "utf-8");
143377
+ if (fs24.existsSync(configPath)) {
143378
+ const content = fs24.readFileSync(configPath, "utf-8");
142865
143379
  const rawConfig = parseJsonc(content);
142866
143380
  migrateConfigFile(configPath, rawConfig);
142867
143381
  const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
@@ -142996,7 +143510,7 @@ function loadPluginConfig(directory, ctx) {
142996
143510
  stopDirectory
142997
143511
  });
142998
143512
  const canonicalAncestorPathsNearestFirst = ancestorConfigPathsNearestFirst.map((ancestorPath) => {
142999
- const opencodeDir = path29.dirname(ancestorPath);
143513
+ const opencodeDir = path30.dirname(ancestorPath);
143000
143514
  const ancestorDetected = detectPluginConfigFile(opencodeDir, {
143001
143515
  basenames: [CONFIG_BASENAME],
143002
143516
  legacyBasenames: [LEGACY_CONFIG_BASENAME]
@@ -143037,8 +143551,8 @@ function loadPluginConfig(directory, ctx) {
143037
143551
  const ancestorConfig = loadConfigFromPath2(ancestorPath, ctx);
143038
143552
  const ancestorOverrides = loadExplicitGitMasterOverrides(ancestorPath);
143039
143553
  if (ancestorConfig?.agent_definitions) {
143040
- const ancestorBasePath = path29.dirname(ancestorPath);
143041
- const ancestorDir = path29.dirname(ancestorBasePath);
143554
+ const ancestorBasePath = path30.dirname(ancestorPath);
143555
+ const ancestorDir = path30.dirname(ancestorBasePath);
143042
143556
  ancestorConfig.agent_definitions = resolveAgentDefinitionPaths(ancestorConfig.agent_definitions, ancestorBasePath, ancestorDir);
143043
143557
  }
143044
143558
  if (ancestorConfig) {