oh-my-opencode 5.0.0-beta.86 → 5.0.0-beta.88

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 (242) hide show
  1. package/.agents/skills/hyperplan/SKILL.md +1 -1
  2. package/.opencode/skills/hyperplan/SKILL.md +1 -1
  3. package/dist/cli/index.js +102 -79
  4. package/dist/cli-node/index.js +102 -79
  5. package/dist/index.js +439 -420
  6. package/dist/skills/browser/ATTRIBUTION.md +26 -14
  7. package/dist/skills/browser/SKILL.md +65 -52
  8. package/dist/skills/browser/references/commands.md +81 -66
  9. package/dist/skills/browser/references/install.md +31 -34
  10. package/dist/skills/browser/references/owned-engine/README.md +41 -21
  11. package/dist/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
  12. package/dist/skills/browser/references/owned-engine/ladder.md +24 -22
  13. package/dist/skills/browser/references/owned-engine/network.md +35 -15
  14. package/dist/skills/browser/references/recipes/1password.md +13 -11
  15. package/dist/skills/browser/references/remote.md +5 -4
  16. package/dist/skills/browser/runtime/omowright/index.js +1534 -0
  17. package/dist/skills/browser/runtime/omowright/manifest.json +9 -0
  18. package/dist/skills/browser/runtime/omowright/page-bundle.js +1395 -0
  19. package/dist/skills/browser/scripts/browser-doctor.mjs +37 -32
  20. package/dist/skills/browser/scripts/browser-install.mjs +31 -44
  21. package/dist/skills/browser/scripts/omowright.mjs +25 -0
  22. package/dist/skills/debugging/SKILL.md +2 -2
  23. package/dist/skills/debugging/references/methodology/06-fix.md +3 -3
  24. package/dist/skills/debugging/references/methodology/08-qa.md +1 -1
  25. package/dist/skills/debugging/references/tools/browser-qa.md +104 -0
  26. package/dist/skills/frontend/SKILL.md +1 -1
  27. package/dist/skills/frontend/references/design/ambience-skill.md +2 -1
  28. package/dist/skills/frontend/references/design/clone-from-url.md +1 -1
  29. package/dist/skills/frontend/references/design/design-system-architecture.md +30 -7
  30. package/dist/skills/frontend/references/design/interaction-skill.md +17 -5
  31. package/dist/skills/programming/SKILL.md +12 -18
  32. package/dist/skills/programming/references/rust/README.md +43 -15
  33. package/dist/skills/programming/references/rust/api-design.md +81 -0
  34. package/dist/skills/programming/references/rust/async-tokio.md +60 -28
  35. package/dist/skills/programming/references/rust/axum-stack.md +1 -13
  36. package/dist/skills/programming/references/rust/cargo-strict.md +44 -8
  37. package/dist/skills/programming/references/rust/clap-stack.md +8 -3
  38. package/dist/skills/programming/references/rust/concurrency.md +66 -52
  39. package/dist/skills/programming/references/rust/libraries.md +35 -25
  40. package/dist/skills/programming/references/rust/macros.md +63 -0
  41. package/dist/skills/programming/references/rust/one-liners.md +5 -3
  42. package/dist/skills/programming/references/rust/proptest-insta.md +8 -0
  43. package/dist/skills/programming/references/rust/type-state.md +50 -12
  44. package/dist/skills/programming/references/rust/unsafe-discipline.md +34 -6
  45. package/dist/skills/programming/references/rust/zero-cost-safety.md +62 -52
  46. package/dist/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
  47. package/dist/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
  48. package/dist/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
  49. package/dist/skills/programming/scripts/rust/check-no-excuse-rules.test.ts +83 -0
  50. package/dist/skills/programming/scripts/rust/new-project.py +31 -28
  51. package/dist/skills/review-work/SKILL.md +1 -1
  52. package/dist/skills/ultimate-browsing/SKILL.md +27 -20
  53. package/dist/skills/ultimate-browsing/engine/AGENTS.md +1 -1
  54. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
  55. package/dist/skills/ultimate-browsing/references/insane-search/README.md +5 -11
  56. package/dist/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
  57. package/dist/skills/ulw-execute/SKILL.md +4 -4
  58. package/dist/skills/visual-qa/SKILL.md +1 -1
  59. package/dist/skills/visual-qa/references/browser-setup.md +46 -46
  60. package/dist/tui.js +6 -3
  61. package/package.json +15 -14
  62. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  63. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -0
  64. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  65. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  66. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  67. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  68. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  69. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  70. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  71. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  72. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  73. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  74. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  75. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +1 -1
  76. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  77. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  78. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  79. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  80. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  81. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  82. package/packages/omo-codex/plugin/components/ultrawork/README.md +1 -1
  83. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  84. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +63 -89
  85. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  86. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  88. package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +2 -2
  89. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  90. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +63 -89
  92. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  93. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  94. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +2 -3
  95. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -2
  96. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  97. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  98. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  99. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  100. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  101. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  102. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  103. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  104. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  105. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  106. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  107. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  108. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  109. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  110. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  111. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  112. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  113. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  117. package/packages/omo-codex/plugin/package-lock.json +12 -12
  118. package/packages/omo-codex/plugin/package.json +1 -1
  119. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +8 -2
  120. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +2 -2
  121. package/packages/omo-codex/plugin/skills/browser/ATTRIBUTION.md +26 -14
  122. package/packages/omo-codex/plugin/skills/browser/SKILL.md +65 -52
  123. package/packages/omo-codex/plugin/skills/browser/references/commands.md +81 -66
  124. package/packages/omo-codex/plugin/skills/browser/references/install.md +31 -34
  125. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +41 -21
  126. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
  127. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/ladder.md +24 -22
  128. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/network.md +35 -15
  129. package/packages/omo-codex/plugin/skills/browser/references/recipes/1password.md +13 -11
  130. package/packages/omo-codex/plugin/skills/browser/references/remote.md +5 -4
  131. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/index.js +1534 -0
  132. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +9 -0
  133. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/page-bundle.js +1395 -0
  134. package/packages/omo-codex/plugin/skills/browser/scripts/browser-doctor.mjs +37 -32
  135. package/packages/omo-codex/plugin/skills/browser/scripts/browser-install.mjs +31 -44
  136. package/packages/omo-codex/plugin/skills/browser/scripts/omowright.mjs +25 -0
  137. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -2
  138. package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +3 -3
  139. package/packages/omo-codex/plugin/skills/debugging/references/methodology/08-qa.md +1 -1
  140. package/packages/omo-codex/plugin/skills/debugging/references/tools/browser-qa.md +104 -0
  141. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
  142. package/packages/omo-codex/plugin/skills/frontend/references/design/ambience-skill.md +2 -1
  143. package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
  144. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +30 -7
  145. package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +17 -5
  146. package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -18
  147. package/packages/omo-codex/plugin/skills/programming/references/rust/README.md +43 -15
  148. package/packages/omo-codex/plugin/skills/programming/references/rust/api-design.md +81 -0
  149. package/packages/omo-codex/plugin/skills/programming/references/rust/async-tokio.md +60 -28
  150. package/packages/omo-codex/plugin/skills/programming/references/rust/axum-stack.md +1 -13
  151. package/packages/omo-codex/plugin/skills/programming/references/rust/cargo-strict.md +44 -8
  152. package/packages/omo-codex/plugin/skills/programming/references/rust/clap-stack.md +8 -3
  153. package/packages/omo-codex/plugin/skills/programming/references/rust/concurrency.md +66 -52
  154. package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +35 -25
  155. package/packages/omo-codex/plugin/skills/programming/references/rust/macros.md +63 -0
  156. package/packages/omo-codex/plugin/skills/programming/references/rust/one-liners.md +5 -3
  157. package/packages/omo-codex/plugin/skills/programming/references/rust/proptest-insta.md +8 -0
  158. package/packages/omo-codex/plugin/skills/programming/references/rust/type-state.md +50 -12
  159. package/packages/omo-codex/plugin/skills/programming/references/rust/unsafe-discipline.md +34 -6
  160. package/packages/omo-codex/plugin/skills/programming/references/rust/zero-cost-safety.md +62 -52
  161. package/packages/omo-codex/plugin/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
  162. package/packages/omo-codex/plugin/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
  163. package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
  164. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +31 -28
  165. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
  166. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +27 -20
  167. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +1 -1
  168. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
  169. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +5 -11
  170. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
  171. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +63 -89
  172. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +4 -4
  173. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +2 -3
  174. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -2
  175. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +1 -1
  176. package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +46 -46
  177. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -2
  178. package/packages/omo-codex/scripts/install-dist/install-local.mjs +4 -2
  179. package/packages/prompts-core/prompts/ultrawork/codex.md +63 -89
  180. package/packages/shared-skills/skills/browser/ATTRIBUTION.md +26 -14
  181. package/packages/shared-skills/skills/browser/SKILL.md +65 -52
  182. package/packages/shared-skills/skills/browser/references/commands.md +81 -66
  183. package/packages/shared-skills/skills/browser/references/install.md +31 -34
  184. package/packages/shared-skills/skills/browser/references/owned-engine/README.md +41 -21
  185. package/packages/shared-skills/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
  186. package/packages/shared-skills/skills/browser/references/owned-engine/ladder.md +24 -22
  187. package/packages/shared-skills/skills/browser/references/owned-engine/network.md +35 -15
  188. package/packages/shared-skills/skills/browser/references/recipes/1password.md +13 -11
  189. package/packages/shared-skills/skills/browser/references/remote.md +5 -4
  190. package/packages/shared-skills/skills/browser/runtime/omowright/index.js +1534 -0
  191. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +9 -0
  192. package/packages/shared-skills/skills/browser/runtime/omowright/page-bundle.js +1395 -0
  193. package/packages/shared-skills/skills/browser/scripts/browser-doctor.mjs +37 -32
  194. package/packages/shared-skills/skills/browser/scripts/browser-install.mjs +31 -44
  195. package/packages/shared-skills/skills/browser/scripts/omowright.mjs +25 -0
  196. package/packages/shared-skills/skills/debugging/SKILL.md +2 -2
  197. package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +3 -3
  198. package/packages/shared-skills/skills/debugging/references/methodology/08-qa.md +1 -1
  199. package/packages/shared-skills/skills/debugging/references/tools/browser-qa.md +104 -0
  200. package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
  201. package/packages/shared-skills/skills/frontend/references/design/ambience-skill.md +2 -1
  202. package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
  203. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +30 -7
  204. package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +17 -5
  205. package/packages/shared-skills/skills/programming/SKILL.md +12 -18
  206. package/packages/shared-skills/skills/programming/references/rust/README.md +43 -15
  207. package/packages/shared-skills/skills/programming/references/rust/api-design.md +81 -0
  208. package/packages/shared-skills/skills/programming/references/rust/async-tokio.md +60 -28
  209. package/packages/shared-skills/skills/programming/references/rust/axum-stack.md +1 -13
  210. package/packages/shared-skills/skills/programming/references/rust/cargo-strict.md +44 -8
  211. package/packages/shared-skills/skills/programming/references/rust/clap-stack.md +8 -3
  212. package/packages/shared-skills/skills/programming/references/rust/concurrency.md +66 -52
  213. package/packages/shared-skills/skills/programming/references/rust/libraries.md +35 -25
  214. package/packages/shared-skills/skills/programming/references/rust/macros.md +63 -0
  215. package/packages/shared-skills/skills/programming/references/rust/one-liners.md +5 -3
  216. package/packages/shared-skills/skills/programming/references/rust/proptest-insta.md +8 -0
  217. package/packages/shared-skills/skills/programming/references/rust/type-state.md +50 -12
  218. package/packages/shared-skills/skills/programming/references/rust/unsafe-discipline.md +34 -6
  219. package/packages/shared-skills/skills/programming/references/rust/zero-cost-safety.md +62 -52
  220. package/packages/shared-skills/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
  221. package/packages/shared-skills/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
  222. package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
  223. package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.test.ts +83 -0
  224. package/packages/shared-skills/skills/programming/scripts/rust/new-project.py +31 -28
  225. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  226. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +27 -20
  227. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +1 -1
  228. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
  229. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +5 -11
  230. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
  231. package/packages/shared-skills/skills/ulw-execute/SKILL.md +4 -4
  232. package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
  233. package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +46 -46
  234. package/dist/skills/browser/scripts/browser-env.mjs +0 -41
  235. package/dist/skills/debugging/references/tools/playwright-cli.md +0 -112
  236. package/dist/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
  237. package/packages/omo-codex/plugin/skills/browser/scripts/browser-env.mjs +0 -41
  238. package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +0 -112
  239. package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
  240. package/packages/shared-skills/skills/browser/scripts/browser-env.mjs +0 -41
  241. package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +0 -112
  242. package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
package/dist/index.js CHANGED
@@ -20238,7 +20238,7 @@ var CATEGORY_MODEL_REQUIREMENTS = {
20238
20238
  },
20239
20239
  quick: {
20240
20240
  fallbackChain: [
20241
- { providers: ["chatgpt-subscription"], model: "gpt-6-luna-fast", variant: "low" },
20241
+ { providers: ["openai", "chatgpt-subscription"], model: "gpt-6-luna-fast", variant: "low" },
20242
20242
  { providers: ["deepseek"], model: "deepseek-flash", variant: "off" },
20243
20243
  {
20244
20244
  providers: ["qwen-token-plan", "alibaba-token-plan", "bailian-coding-plan"],
@@ -20283,7 +20283,7 @@ var CATEGORY_MODEL_REQUIREMENTS = {
20283
20283
  {
20284
20284
  providers: ["anthropic", "anthropic-api", "github-copilot", "opencode"],
20285
20285
  model: "claude-opus-5-5",
20286
- variant: "max"
20286
+ variant: "medium"
20287
20287
  },
20288
20288
  { providers: ["zai-coding-plan", "opencode-go"], model: "glm-5.3", variant: "max" },
20289
20289
  {
@@ -20294,6 +20294,7 @@ var CATEGORY_MODEL_REQUIREMENTS = {
20294
20294
  ]
20295
20295
  },
20296
20296
  writing: {
20297
+ requiresAnyModel: true,
20297
20298
  fallbackChain: [
20298
20299
  {
20299
20300
  providers: ["anthropic", "anthropic-api", "github-copilot", "opencode"],
@@ -23561,6 +23562,8 @@ function isRecord9(value) {
23561
23562
  }
23562
23563
  var OmoModelProfileInputSchema = z9.object({
23563
23564
  display_name: z9.string().optional(),
23565
+ family: z9.enum(["daily", "geeky"]).optional(),
23566
+ tier: z9.enum(["normal", "heavy"]).optional(),
23564
23567
  models: z9.array(z9.union([z9.string(), OmoFallbackModelObjectSchema])).optional()
23565
23568
  }).strict();
23566
23569
  var OmoModelProfileSchema = z9.preprocess((value) => isRecord9(value) ? normalizeLegacyModelFields(value) : value, OmoModelProfileInputSchema);
@@ -27357,7 +27360,7 @@ var OPENAI_CATEGORIES = [
27357
27360
  },
27358
27361
  {
27359
27362
  name: "unspecified-high",
27360
- config: { model: "anthropic/claude-opus-5-5", variant: "max" },
27363
+ config: { model: "anthropic/claude-opus-5-5", variant: "medium" },
27361
27364
  description: "Tasks that don't fit other categories, high effort required",
27362
27365
  callerGuidance: UNSPECIFIED_HIGH_CATEGORY_CALLER_GUIDANCE,
27363
27366
  promptAppend: UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND,
@@ -89863,7 +89866,7 @@ import { existsSync as existsSync36 } from "fs";
89863
89866
  // packages/omo-opencode/src/hooks/comment-checker/cli.ts
89864
89867
  init_bun_spawn_shim();
89865
89868
  init_bun_which_shim();
89866
- import { join as join44 } from "path";
89869
+ import { join as join45 } from "path";
89867
89870
  import { existsSync as existsSync35 } from "fs";
89868
89871
  import * as fs6 from "fs";
89869
89872
  import { tmpdir as tmpdir4 } from "os";
@@ -90004,9 +90007,45 @@ function joinPatchLines(lines) {
90004
90007
  `)}
90005
90008
  `;
90006
90009
  }
90010
+ // packages/comment-checker-core/src/release.ts
90011
+ import { join as join42 } from "path";
90012
+ var COMMENT_CHECKER_RELEASE_VERSION = "0.8.0";
90013
+ var COMMENT_CHECKER_RELEASE_REPO = "code-yeongyu/go-claude-code-comment-checker";
90014
+ var RELEASE_PLATFORMS = {
90015
+ "darwin-arm64": { os: "darwin", arch: "arm64", ext: "tar.gz" },
90016
+ "darwin-x64": { os: "darwin", arch: "amd64", ext: "tar.gz" },
90017
+ "linux-arm64": { os: "linux", arch: "arm64", ext: "tar.gz" },
90018
+ "linux-x64": { os: "linux", arch: "amd64", ext: "tar.gz" },
90019
+ "win32-x64": { os: "windows", arch: "amd64", ext: "zip" }
90020
+ };
90021
+ function resolveCommentCheckerReleaseAsset(platform, arch, version = COMMENT_CHECKER_RELEASE_VERSION) {
90022
+ const target = RELEASE_PLATFORMS[`${platform}-${arch}`];
90023
+ if (target === undefined)
90024
+ return null;
90025
+ const assetName = `comment-checker_v${version}_${target.os}_${target.arch}.${target.ext}`;
90026
+ return {
90027
+ os: target.os,
90028
+ arch: target.arch,
90029
+ ext: target.ext,
90030
+ assetName,
90031
+ url: `https://github.com/${COMMENT_CHECKER_RELEASE_REPO}/releases/download/v${version}/${assetName}`
90032
+ };
90033
+ }
90034
+ function commentCheckerBinaryName(platform) {
90035
+ return platform === "win32" ? "comment-checker.exe" : "comment-checker";
90036
+ }
90037
+ function commentCheckerCacheDir(input) {
90038
+ if (input.platform === "win32") {
90039
+ const localAppData = input.env.LOCALAPPDATA || input.env.APPDATA;
90040
+ const base = localAppData || join42(input.homedir, "AppData", "Local");
90041
+ return join42(base, input.cacheDirName, "bin");
90042
+ }
90043
+ const base = input.env.XDG_CACHE_HOME || join42(input.homedir, ".cache");
90044
+ return join42(base, input.cacheDirName, "bin");
90045
+ }
90007
90046
  // packages/comment-checker-core/src/runner.ts
90008
90047
  import { createRequire } from "module";
90009
- import { dirname as dirname13, join as join42 } from "path";
90048
+ import { dirname as dirname13, join as join43 } from "path";
90010
90049
  var EMPTY_RESULT = { hasComments: false, message: "" };
90011
90050
  function normalizeMessage(message) {
90012
90051
  return message.replace(/\r\n/g, `
@@ -90032,7 +90071,7 @@ function resolveCommentCheckerBinary(input) {
90032
90071
  try {
90033
90072
  const require2 = createRequire(input.importMetaUrl);
90034
90073
  const packageJsonPath = require2.resolve(`${packageName}/package.json`);
90035
- const binaryPath = join42(dirname13(packageJsonPath), "bin", input.binaryName);
90074
+ const binaryPath = join43(dirname13(packageJsonPath), "bin", input.binaryName);
90036
90075
  return input.existsSync(binaryPath) ? binaryPath : null;
90037
90076
  } catch (error) {
90038
90077
  if (error instanceof Error || typeof error === "object" && error !== null && "name" in error && error.name === "ResolveMessage") {
@@ -90100,12 +90139,12 @@ async function runCommentChecker(input, options) {
90100
90139
  }
90101
90140
  // packages/omo-opencode/src/hooks/comment-checker/downloader.ts
90102
90141
  import { existsSync as existsSync34, appendFileSync as appendFileSync2 } from "fs";
90103
- import { join as join43 } from "path";
90142
+ import { join as join44 } from "path";
90104
90143
  import { homedir as homedir10, tmpdir as tmpdir3 } from "os";
90105
90144
  init_logger2();
90106
90145
  init_plugin_identity();
90107
90146
  var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
90108
- var DEBUG_FILE = join43(tmpdir3(), "comment-checker-debug.log");
90147
+ var DEBUG_FILE = join44(tmpdir3(), "comment-checker-debug.log");
90109
90148
  function debugLog(...args) {
90110
90149
  if (DEBUG) {
90111
90150
  const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -90113,54 +90152,39 @@ function debugLog(...args) {
90113
90152
  appendFileSync2(DEBUG_FILE, msg);
90114
90153
  }
90115
90154
  }
90116
- var REPO = "code-yeongyu/go-claude-code-comment-checker";
90117
- var COMMENT_CHECKER_VERSION = "0.8.0";
90118
- var PLATFORM_MAP = {
90119
- "darwin-arm64": { os: "darwin", arch: "arm64", ext: "tar.gz" },
90120
- "darwin-x64": { os: "darwin", arch: "amd64", ext: "tar.gz" },
90121
- "linux-arm64": { os: "linux", arch: "arm64", ext: "tar.gz" },
90122
- "linux-x64": { os: "linux", arch: "amd64", ext: "tar.gz" },
90123
- "win32-x64": { os: "windows", arch: "amd64", ext: "zip" }
90124
- };
90125
90155
  function getCacheDir2() {
90126
- if (process.platform === "win32") {
90127
- const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
90128
- const base = localAppData || join43(homedir10(), "AppData", "Local");
90129
- return join43(base, CACHE_DIR_NAME, "bin");
90130
- }
90131
- const xdgCache = process.env.XDG_CACHE_HOME;
90132
- const base = xdgCache || join43(homedir10(), ".cache");
90133
- return join43(base, CACHE_DIR_NAME, "bin");
90156
+ return commentCheckerCacheDir({
90157
+ platform: process.platform,
90158
+ env: process.env,
90159
+ homedir: homedir10(),
90160
+ cacheDirName: CACHE_DIR_NAME
90161
+ });
90134
90162
  }
90135
90163
  function getBinaryName() {
90136
- return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
90164
+ return commentCheckerBinaryName(process.platform);
90137
90165
  }
90138
90166
  function getCachedBinaryPath2() {
90139
90167
  return getCachedBinaryPath(getCacheDir2(), getBinaryName());
90140
90168
  }
90141
90169
  async function downloadCommentChecker() {
90142
- const platformKey = `${process.platform}-${process.arch}`;
90143
- const platformInfo = PLATFORM_MAP[platformKey];
90144
- if (!platformInfo) {
90145
- debugLog(`Unsupported platform: ${platformKey}`);
90170
+ const asset = resolveCommentCheckerReleaseAsset(process.platform, process.arch);
90171
+ if (!asset) {
90172
+ debugLog(`Unsupported platform: ${process.platform}-${process.arch}`);
90146
90173
  return null;
90147
90174
  }
90148
90175
  const cacheDir = getCacheDir2();
90149
90176
  const binaryName = getBinaryName();
90150
- const binaryPath = join43(cacheDir, binaryName);
90177
+ const binaryPath = join44(cacheDir, binaryName);
90151
90178
  if (existsSync34(binaryPath)) {
90152
90179
  debugLog("Binary already cached at:", binaryPath);
90153
90180
  return binaryPath;
90154
90181
  }
90155
- const version = COMMENT_CHECKER_VERSION;
90156
- const { os, arch, ext } = platformInfo;
90157
- const assetName = `comment-checker_v${version}_${os}_${arch}.${ext}`;
90158
- const downloadUrl = `https://github.com/${REPO}/releases/download/v${version}/${assetName}`;
90182
+ const { assetName, url: downloadUrl, ext } = asset;
90159
90183
  debugLog(`Downloading from: ${downloadUrl}`);
90160
90184
  log2(`[${PUBLISHED_PACKAGE_NAME}] Downloading comment-checker binary...`);
90161
90185
  try {
90162
90186
  ensureCacheDir(cacheDir);
90163
- const archivePath = join43(cacheDir, assetName);
90187
+ const archivePath = join44(cacheDir, assetName);
90164
90188
  await downloadArchive(downloadUrl, archivePath);
90165
90189
  debugLog(`Downloaded archive to: ${archivePath}`);
90166
90190
  if (ext === "tar.gz") {
@@ -90192,7 +90216,7 @@ async function ensureCommentCheckerBinary() {
90192
90216
 
90193
90217
  // packages/omo-opencode/src/hooks/comment-checker/cli.ts
90194
90218
  var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
90195
- var DEBUG_FILE2 = join44(tmpdir4(), "comment-checker-debug.log");
90219
+ var DEBUG_FILE2 = join45(tmpdir4(), "comment-checker-debug.log");
90196
90220
  function debugLog2(...args) {
90197
90221
  if (DEBUG2) {
90198
90222
  const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -90464,9 +90488,9 @@ function ensureCommentCheckerInitialization(initializer) {
90464
90488
  // packages/omo-opencode/src/hooks/comment-checker/hook.ts
90465
90489
  import * as fs7 from "fs";
90466
90490
  import { tmpdir as tmpdir5 } from "os";
90467
- import { join as join45 } from "path";
90491
+ import { join as join46 } from "path";
90468
90492
  var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
90469
- var DEBUG_FILE3 = join45(tmpdir5(), "comment-checker-debug.log");
90493
+ var DEBUG_FILE3 = join46(tmpdir5(), "comment-checker-debug.log");
90470
90494
  function debugLog3(...args) {
90471
90495
  if (DEBUG3) {
90472
90496
  const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
@@ -90647,7 +90671,7 @@ function createAgentsMdCache() {
90647
90671
  }
90648
90672
  // packages/rules-engine/src/agents-md.ts
90649
90673
  import { existsSync as existsSync37, realpathSync as realpathSync7, statSync as statSync5 } from "fs";
90650
- import { dirname as dirname14, isAbsolute as isAbsolute6, join as join46, relative as relative7, resolve as resolve10 } from "path";
90674
+ import { dirname as dirname14, isAbsolute as isAbsolute6, join as join47, relative as relative7, resolve as resolve10 } from "path";
90651
90675
 
90652
90676
  // packages/rules-engine/src/constants.ts
90653
90677
  var PROJECT_MARKERS = [".git", "pyproject.toml", "package.json", "Cargo.toml", "go.mod", ".venv"];
@@ -90696,7 +90720,7 @@ async function findAgentsMdUp(input) {
90696
90720
  while (true) {
90697
90721
  const isRootDir = current === rootDir;
90698
90722
  if (!(skipRoot && isRootDir)) {
90699
- const agentsPath = resolveAgentsFilePath(join46(current, AGENTS_FILENAME), rootDir);
90723
+ const agentsPath = resolveAgentsFilePath(join47(current, AGENTS_FILENAME), rootDir);
90700
90724
  if (agentsPath)
90701
90725
  found.push(agentsPath);
90702
90726
  }
@@ -90739,7 +90763,7 @@ function isSameOrChildPath(childPath, parentPath) {
90739
90763
  // packages/rules-engine/src/finder.ts
90740
90764
  import { existsSync as existsSync39, statSync as statSync6 } from "fs";
90741
90765
  import { homedir as homedir11 } from "os";
90742
- import { dirname as dirname16, isAbsolute as isAbsolute8, join as join48, relative as relative9, resolve as resolve11 } from "path";
90766
+ import { dirname as dirname16, isAbsolute as isAbsolute8, join as join49, relative as relative9, resolve as resolve11 } from "path";
90743
90767
 
90744
90768
  // packages/rules-engine/src/ordering.ts
90745
90769
  function sortCandidates(candidates) {
@@ -90758,7 +90782,7 @@ function compareString(left, right) {
90758
90782
 
90759
90783
  // packages/rules-engine/src/scanner.ts
90760
90784
  import { existsSync as existsSync38, readdirSync as readdirSync10, realpathSync as realpathSync8 } from "fs";
90761
- import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute7, join as join47, relative as relative8 } from "path";
90785
+ import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute7, join as join48, relative as relative8 } from "path";
90762
90786
  function isGitHubInstructionsDir(dir) {
90763
90787
  const normalizedDir = dir.replaceAll("\\", "/");
90764
90788
  return normalizedDir.includes(".github/instructions") || normalizedDir.endsWith(".github/instructions");
@@ -90777,7 +90801,7 @@ function safeRealpathSync(filePath) {
90777
90801
  const parentPath = dirname15(filePath);
90778
90802
  if (parentPath === filePath)
90779
90803
  return filePath;
90780
- return join47(safeRealpathSync(parentPath), basename8(filePath));
90804
+ return join48(safeRealpathSync(parentPath), basename8(filePath));
90781
90805
  }
90782
90806
  }
90783
90807
  function isPathWithinRoot(candidate, root) {
@@ -90801,7 +90825,7 @@ function findRuleFilesRecursive(dir, results, visited = new Set, boundaryRoot) {
90801
90825
  return;
90802
90826
  }
90803
90827
  for (const entry of entries) {
90804
- const fullPath = join47(dir, entry.name);
90828
+ const fullPath = join48(dir, entry.name);
90805
90829
  if (entry.isDirectory()) {
90806
90830
  if (!EXCLUDED_DIRS2.has(entry.name))
90807
90831
  findRuleFilesRecursive(fullPath, results, visited, effectiveBoundary);
@@ -90857,7 +90881,7 @@ function addProjectRuleCandidates(projectRoot, startDir, candidates, seenRealPat
90857
90881
  while (true) {
90858
90882
  for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
90859
90883
  const source = `${parent}/${subdir}`;
90860
- const ruleDir = join48(currentDir, parent, subdir);
90884
+ const ruleDir = join49(currentDir, parent, subdir);
90861
90885
  for (const entry of scanDirectoryWithCache(ruleDir, cache, projectRootRealPath)) {
90862
90886
  if (seenRealPaths.has(entry.realPath))
90863
90887
  continue;
@@ -90885,7 +90909,7 @@ function addProjectRuleCandidates(projectRoot, startDir, candidates, seenRealPat
90885
90909
  function addProjectSingleFileCandidates(projectRoot, candidates, seenRealPaths) {
90886
90910
  const projectRootRealPath = safeRealpathSync(projectRoot);
90887
90911
  for (const ruleFile of PROJECT_RULE_FILES) {
90888
- const filePath = join48(projectRoot, ruleFile);
90912
+ const filePath = join49(projectRoot, ruleFile);
90889
90913
  const realPath = validFileRealPath(filePath, projectRootRealPath);
90890
90914
  if (realPath === null || seenRealPaths.has(realPath))
90891
90915
  continue;
@@ -90902,9 +90926,9 @@ function addProjectSingleFileCandidates(projectRoot, candidates, seenRealPaths)
90902
90926
  }
90903
90927
  }
90904
90928
  function addUserRuleCandidates(homeDir, skipClaudeUserRules, candidates, seenRealPaths, cache) {
90905
- const userRuleDirs = OPENCODE_USER_RULE_DIRS.map((dir) => [join48(homeDir, dir), `~/${dir}`]);
90929
+ const userRuleDirs = OPENCODE_USER_RULE_DIRS.map((dir) => [join49(homeDir, dir), `~/${dir}`]);
90906
90930
  if (!skipClaudeUserRules)
90907
- userRuleDirs.push([join48(homeDir, USER_RULE_DIR), "~/.claude/rules"]);
90931
+ userRuleDirs.push([join49(homeDir, USER_RULE_DIR), "~/.claude/rules"]);
90908
90932
  for (const [userRuleDir, source] of userRuleDirs) {
90909
90933
  for (const entry of scanDirectoryWithCache(userRuleDir, cache)) {
90910
90934
  if (seenRealPaths.has(entry.realPath))
@@ -91039,7 +91063,7 @@ function toPosix(path) {
91039
91063
  }
91040
91064
  // packages/rules-engine/src/project-root.ts
91041
91065
  import { existsSync as existsSync40, statSync as statSync7 } from "fs";
91042
- import { dirname as dirname17, join as join49 } from "path";
91066
+ import { dirname as dirname17, join as join50 } from "path";
91043
91067
  var projectRootCache = new Map;
91044
91068
  function clearProjectRootCache() {
91045
91069
  projectRootCache.clear();
@@ -91086,7 +91110,7 @@ function resolveStartDir(startPath) {
91086
91110
  }
91087
91111
  }
91088
91112
  function hasProjectMarker(directory) {
91089
- return PROJECT_MARKERS.some((marker) => existsSync40(join49(directory, marker)));
91113
+ return PROJECT_MARKERS.some((marker) => existsSync40(join50(directory, marker)));
91090
91114
  }
91091
91115
  // packages/agents-md-core/src/constants.ts
91092
91116
  var TRUNCATION_NOTICE_PREFIX = `
@@ -91178,8 +91202,8 @@ async function processFilePathForAgentsInjection(input) {
91178
91202
  }
91179
91203
  }
91180
91204
  // packages/omo-opencode/src/hooks/directory-agents-injector/constants.ts
91181
- import { join as join50 } from "path";
91182
- var AGENTS_INJECTOR_STORAGE = join50(OPENCODE_STORAGE, "directory-agents");
91205
+ import { join as join51 } from "path";
91206
+ var AGENTS_INJECTOR_STORAGE = join51(OPENCODE_STORAGE, "directory-agents");
91183
91207
 
91184
91208
  // packages/omo-opencode/src/shared/session-injected-paths.ts
91185
91209
  import {
@@ -91189,9 +91213,9 @@ import {
91189
91213
  unlinkSync as unlinkSync6,
91190
91214
  writeFileSync as writeFileSync7
91191
91215
  } from "fs";
91192
- import { join as join51 } from "path";
91216
+ import { join as join52 } from "path";
91193
91217
  function createInjectedPathsStorage(storageDir) {
91194
- const getStoragePath = (sessionID) => join51(storageDir, `${sessionID}.json`);
91218
+ const getStoragePath = (sessionID) => join52(storageDir, `${sessionID}.json`);
91195
91219
  const loadInjectedPaths = (sessionID) => {
91196
91220
  const filePath = getStoragePath(sessionID);
91197
91221
  if (!existsSync41(filePath))
@@ -91289,11 +91313,11 @@ import { dirname as dirname20 } from "path";
91289
91313
 
91290
91314
  // packages/omo-opencode/src/hooks/directory-readme-injector/finder.ts
91291
91315
  import { access as access2 } from "fs/promises";
91292
- import { dirname as dirname19, isAbsolute as isAbsolute10, join as join53, resolve as resolve13 } from "path";
91316
+ import { dirname as dirname19, isAbsolute as isAbsolute10, join as join54, resolve as resolve13 } from "path";
91293
91317
 
91294
91318
  // packages/omo-opencode/src/hooks/directory-readme-injector/constants.ts
91295
- import { join as join52 } from "path";
91296
- var README_INJECTOR_STORAGE = join52(OPENCODE_STORAGE, "directory-readme");
91319
+ import { join as join53 } from "path";
91320
+ var README_INJECTOR_STORAGE = join53(OPENCODE_STORAGE, "directory-readme");
91297
91321
  var README_FILENAME = "README.md";
91298
91322
 
91299
91323
  // packages/omo-opencode/src/hooks/directory-readme-injector/finder.ts
@@ -91308,7 +91332,7 @@ async function findReadmeMdUp(input) {
91308
91332
  const found = [];
91309
91333
  let current = input.startDir;
91310
91334
  while (true) {
91311
- const readmePath = join53(current, README_FILENAME);
91335
+ const readmePath = join54(current, README_FILENAME);
91312
91336
  try {
91313
91337
  await access2(readmePath);
91314
91338
  found.push(readmePath);
@@ -91773,7 +91797,7 @@ function incrementEmptyContentAttempt(autoCompactState, sessionID) {
91773
91797
 
91774
91798
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts
91775
91799
  import { existsSync as existsSync43, readdirSync as readdirSync12, readFileSync as readFileSync25, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
91776
- import { join as join54 } from "path";
91800
+ import { join as join55 } from "path";
91777
91801
 
91778
91802
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts
91779
91803
  import { existsSync as existsSync42, readdirSync as readdirSync11 } from "fs";
@@ -91801,14 +91825,14 @@ function findToolResultsBySize(sessionID) {
91801
91825
  const messageIds = getMessageIds(sessionID);
91802
91826
  const results = [];
91803
91827
  for (const messageID of messageIds) {
91804
- const partDir = join54(PART_STORAGE, messageID);
91828
+ const partDir = join55(PART_STORAGE, messageID);
91805
91829
  if (!existsSync43(partDir))
91806
91830
  continue;
91807
91831
  for (const file of readdirSync12(partDir)) {
91808
91832
  if (!file.endsWith(".json"))
91809
91833
  continue;
91810
91834
  try {
91811
- const partPath = join54(partDir, file);
91835
+ const partPath = join55(partDir, file);
91812
91836
  const content = readFileSync25(partPath, "utf-8");
91813
91837
  const part = JSON.parse(content);
91814
91838
  if (part.type === "tool" && part.state?.output && !part.truncated) {
@@ -92040,11 +92064,11 @@ var META_TYPES = new Set(["step-start", "step-finish"]);
92040
92064
 
92041
92065
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/storage/parts-reader.ts
92042
92066
  import { existsSync as existsSync44, readdirSync as readdirSync13, readFileSync as readFileSync26 } from "fs";
92043
- import { join as join55 } from "path";
92067
+ import { join as join56 } from "path";
92044
92068
  function readParts(messageID) {
92045
92069
  if (isSqliteBackend())
92046
92070
  return [];
92047
- const partDir = join55(PART_STORAGE, messageID);
92071
+ const partDir = join56(PART_STORAGE, messageID);
92048
92072
  if (!existsSync44(partDir))
92049
92073
  return [];
92050
92074
  const parts = [];
@@ -92052,7 +92076,7 @@ function readParts(messageID) {
92052
92076
  if (!file.endsWith(".json"))
92053
92077
  continue;
92054
92078
  try {
92055
- const content = readFileSync26(join55(partDir, file), "utf-8");
92079
+ const content = readFileSync26(join56(partDir, file), "utf-8");
92056
92080
  parts.push(JSON.parse(content));
92057
92081
  } catch (error) {
92058
92082
  if (!(error instanceof Error)) {
@@ -92089,7 +92113,7 @@ function messageHasContent(messageID) {
92089
92113
 
92090
92114
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/storage/messages-reader.ts
92091
92115
  import { existsSync as existsSync45, readdirSync as readdirSync14, readFileSync as readFileSync27 } from "fs";
92092
- import { join as join56 } from "path";
92116
+ import { join as join57 } from "path";
92093
92117
  function readMessages(sessionID) {
92094
92118
  if (isSqliteBackend())
92095
92119
  return [];
@@ -92101,7 +92125,7 @@ function readMessages(sessionID) {
92101
92125
  if (!file.endsWith(".json"))
92102
92126
  continue;
92103
92127
  try {
92104
- const content = readFileSync27(join56(messageDir, file), "utf-8");
92128
+ const content = readFileSync27(join57(messageDir, file), "utf-8");
92105
92129
  messages.push(JSON.parse(content));
92106
92130
  } catch (error) {
92107
92131
  if (!(error instanceof Error)) {
@@ -92155,13 +92179,13 @@ function findEmptyMessageByIndex(sessionID, targetIndex) {
92155
92179
 
92156
92180
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/storage/empty-text.ts
92157
92181
  import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync28, writeFileSync as writeFileSync9 } from "fs";
92158
- import { join as join57 } from "path";
92182
+ import { join as join58 } from "path";
92159
92183
  function replaceEmptyTextParts(messageID, replacementText) {
92160
92184
  if (isSqliteBackend()) {
92161
92185
  log2("[auto-compact] Disabled on SQLite backend: replaceEmptyTextParts (use async variant)");
92162
92186
  return false;
92163
92187
  }
92164
- const partDir = join57(PART_STORAGE, messageID);
92188
+ const partDir = join58(PART_STORAGE, messageID);
92165
92189
  if (!existsSync46(partDir))
92166
92190
  return false;
92167
92191
  let anyReplaced = false;
@@ -92169,7 +92193,7 @@ function replaceEmptyTextParts(messageID, replacementText) {
92169
92193
  if (!file.endsWith(".json"))
92170
92194
  continue;
92171
92195
  try {
92172
- const filePath = join57(partDir, file);
92196
+ const filePath = join58(partDir, file);
92173
92197
  const content = readFileSync28(filePath, "utf-8");
92174
92198
  const part = JSON.parse(content);
92175
92199
  if (part.type === "text") {
@@ -92258,7 +92282,7 @@ async function findMessagesWithEmptyTextPartsFromSDK(client, sessionID) {
92258
92282
 
92259
92283
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/storage/text-part-injector.ts
92260
92284
  import { existsSync as existsSync47, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
92261
- import { join as join58 } from "path";
92285
+ import { join as join59 } from "path";
92262
92286
 
92263
92287
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/storage/part-id.ts
92264
92288
  function generatePartId2() {
@@ -92273,7 +92297,7 @@ function injectTextPart(sessionID, messageID, text) {
92273
92297
  log2("[auto-compact] Disabled on SQLite backend: injectTextPart (use async variant)");
92274
92298
  return false;
92275
92299
  }
92276
- const partDir = join58(PART_STORAGE, messageID);
92300
+ const partDir = join59(PART_STORAGE, messageID);
92277
92301
  if (!existsSync47(partDir)) {
92278
92302
  mkdirSync10(partDir, { recursive: true });
92279
92303
  }
@@ -92287,7 +92311,7 @@ function injectTextPart(sessionID, messageID, text) {
92287
92311
  synthetic: true
92288
92312
  };
92289
92313
  try {
92290
- writeFileSync10(join58(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
92314
+ writeFileSync10(join59(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
92291
92315
  return true;
92292
92316
  } catch (error) {
92293
92317
  if (!(error instanceof Error)) {
@@ -93002,7 +93026,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
93002
93026
 
93003
93027
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts
93004
93028
  import { readdirSync as readdirSync16, readFileSync as readFileSync29 } from "fs";
93005
- import { join as join59 } from "path";
93029
+ import { join as join60 } from "path";
93006
93030
 
93007
93031
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts
93008
93032
  var CHARS_PER_TOKEN = 4;
@@ -93038,7 +93062,7 @@ function readMessages2(sessionID) {
93038
93062
  try {
93039
93063
  const files = readdirSync16(messageDir).filter((f) => f.endsWith(".json"));
93040
93064
  for (const file of files) {
93041
- const content = readFileSync29(join59(messageDir, file), "utf-8");
93065
+ const content = readFileSync29(join60(messageDir, file), "utf-8");
93042
93066
  const data = JSON.parse(content);
93043
93067
  if (data.parts) {
93044
93068
  messages.push(data);
@@ -93154,10 +93178,10 @@ function findToolOutput(messages, callID) {
93154
93178
 
93155
93179
  // packages/omo-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts
93156
93180
  import { existsSync as existsSync48, readdirSync as readdirSync17, readFileSync as readFileSync30 } from "fs";
93157
- import { join as join60 } from "path";
93181
+ import { join as join61 } from "path";
93158
93182
  init_logger2();
93159
93183
  function getPartStorage() {
93160
- return join60(getOpenCodeStorageDir(), "part");
93184
+ return join61(getOpenCodeStorageDir(), "part");
93161
93185
  }
93162
93186
  function getMessageIds2(sessionID) {
93163
93187
  const messageDir = getMessageDir(sessionID);
@@ -93182,13 +93206,13 @@ async function truncateToolOutputsByCallId(sessionID, callIds, client) {
93182
93206
  return { truncatedCount: 0 };
93183
93207
  let truncatedCount = 0;
93184
93208
  for (const messageID of messageIds) {
93185
- const partDir = join60(getPartStorage(), messageID);
93209
+ const partDir = join61(getPartStorage(), messageID);
93186
93210
  if (!existsSync48(partDir))
93187
93211
  continue;
93188
93212
  for (const file of readdirSync17(partDir)) {
93189
93213
  if (!file.endsWith(".json"))
93190
93214
  continue;
93191
- const partPath = join60(partDir, file);
93215
+ const partPath = join61(partDir, file);
93192
93216
  try {
93193
93217
  const content = readFileSync30(partPath, "utf-8");
93194
93218
  const part = JSON.parse(content);
@@ -94138,7 +94162,7 @@ function createModelFallbackHook(args) {
94138
94162
  };
94139
94163
  }
94140
94164
  // packages/omo-opencode/src/hooks/claude-code-hooks/config.ts
94141
- import { join as join61 } from "path";
94165
+ import { join as join62 } from "path";
94142
94166
  import { existsSync as existsSync49 } from "fs";
94143
94167
  init_logger2();
94144
94168
  var CONFIG_CACHE_TTL_MS = 30000;
@@ -94175,9 +94199,9 @@ function normalizeHooksConfig(raw) {
94175
94199
  function getClaudeSettingsPaths(customPath) {
94176
94200
  const claudeConfigDir = getClaudeConfigDir();
94177
94201
  const paths = [
94178
- join61(claudeConfigDir, "settings.json"),
94179
- join61(process.cwd(), ".claude", "settings.json"),
94180
- join61(process.cwd(), ".claude", "settings.local.json")
94202
+ join62(claudeConfigDir, "settings.json"),
94203
+ join62(process.cwd(), ".claude", "settings.json"),
94204
+ join62(process.cwd(), ".claude", "settings.local.json")
94181
94205
  ];
94182
94206
  if (customPath && existsSync49(customPath)) {
94183
94207
  paths.unshift(customPath);
@@ -94316,14 +94340,14 @@ async function loadClaudeHooksConfig(customSettingsPath) {
94316
94340
  // packages/omo-opencode/src/hooks/claude-code-hooks/config-loader.ts
94317
94341
  init_logger2();
94318
94342
  import { existsSync as existsSync50 } from "fs";
94319
- import { join as join62 } from "path";
94343
+ import { join as join63 } from "path";
94320
94344
  var CONFIG_CACHE_TTL_MS2 = 30000;
94321
94345
  var configCache2 = new Map;
94322
94346
  function getUserConfigPaths() {
94323
- return getOpenCodeConfigDirs({ binary: "opencode" }).map((dir) => join62(dir, "opencode-cc-plugin.json"));
94347
+ return getOpenCodeConfigDirs({ binary: "opencode" }).map((dir) => join63(dir, "opencode-cc-plugin.json"));
94324
94348
  }
94325
94349
  function getProjectConfigPath() {
94326
- return join62(process.cwd(), ".opencode", "opencode-cc-plugin.json");
94350
+ return join63(process.cwd(), ".opencode", "opencode-cc-plugin.json");
94327
94351
  }
94328
94352
  function getCacheKey2() {
94329
94353
  return `${process.cwd()}::${getUserConfigPaths().join("|")}`;
@@ -94674,13 +94698,13 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
94674
94698
  }
94675
94699
 
94676
94700
  // packages/omo-opencode/src/hooks/claude-code-hooks/transcript.ts
94677
- import { join as join63 } from "path";
94701
+ import { join as join64 } from "path";
94678
94702
  import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync5, existsSync as existsSync51, writeFileSync as writeFileSync11, unlinkSync as unlinkSync7 } from "fs";
94679
94703
  import { tmpdir as tmpdir6 } from "os";
94680
94704
  import { randomUUID as randomUUID4 } from "crypto";
94681
- var TRANSCRIPT_DIR = join63(getClaudeConfigDir(), "transcripts");
94705
+ var TRANSCRIPT_DIR = join64(getClaudeConfigDir(), "transcripts");
94682
94706
  function getTranscriptPath(sessionId) {
94683
- return join63(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
94707
+ return join64(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
94684
94708
  }
94685
94709
  function ensureTranscriptDir() {
94686
94710
  if (!existsSync51(TRANSCRIPT_DIR)) {
@@ -94847,7 +94871,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
94847
94871
  }
94848
94872
  }
94849
94873
  }
94850
- const tempPath = join63(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID4()}.jsonl`);
94874
+ const tempPath = join64(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID4()}.jsonl`);
94851
94875
  writeFileSync11(tempPath, allEntries.join(`
94852
94876
  `) + `
94853
94877
  `);
@@ -94863,7 +94887,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
94863
94887
  logTranscriptError("[transcript] failed to build transcript from session", { thrown: error });
94864
94888
  }
94865
94889
  try {
94866
- const tempPath = join63(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID4()}.jsonl`);
94890
+ const tempPath = join64(tmpdir6(), `opencode-transcript-${sessionId}-${randomUUID4()}.jsonl`);
94867
94891
  writeFileSync11(tempPath, buildCurrentEntry(currentToolName, currentToolInput) + `
94868
94892
  `);
94869
94893
  return tempPath;
@@ -94892,10 +94916,10 @@ function deleteTempTranscript(path) {
94892
94916
  }
94893
94917
 
94894
94918
  // packages/omo-opencode/src/hooks/claude-code-hooks/todo.ts
94895
- import { join as join64 } from "path";
94896
- var TODO_DIR = join64(getClaudeConfigDir(), "todos");
94919
+ import { join as join65 } from "path";
94920
+ var TODO_DIR = join65(getClaudeConfigDir(), "todos");
94897
94921
  function getTodoPath(sessionId) {
94898
- return join64(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
94922
+ return join65(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
94899
94923
  }
94900
94924
 
94901
94925
  // packages/omo-opencode/src/hooks/claude-code-hooks/stop.ts
@@ -96024,9 +96048,9 @@ function readCurrentTopLevelTask(planPath) {
96024
96048
  }
96025
96049
  // packages/boulder-state/src/storage/path.ts
96026
96050
  import { existsSync as existsSync53 } from "fs";
96027
- import { isAbsolute as isAbsolute11, join as join65, relative as relative12, resolve as resolve14 } from "path";
96051
+ import { isAbsolute as isAbsolute11, join as join66, relative as relative12, resolve as resolve14 } from "path";
96028
96052
  function getBoulderFilePath(directory) {
96029
- return join65(directory, BOULDER_DIR, BOULDER_FILE);
96053
+ return join66(directory, BOULDER_DIR, BOULDER_FILE);
96030
96054
  }
96031
96055
  function resolveTrackedPath(baseDirectory, trackedPath) {
96032
96056
  return isAbsolute11(trackedPath) ? resolve14(trackedPath) : resolve14(baseDirectory, trackedPath);
@@ -96051,17 +96075,17 @@ function resolveBoulderPlanPathForWork(directory, work) {
96051
96075
  }
96052
96076
  // packages/boulder-state/src/storage/plan-progress.ts
96053
96077
  import { existsSync as existsSync54, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync8 } from "fs";
96054
- import { basename as basename10, join as join66 } from "path";
96078
+ import { basename as basename10, join as join67 } from "path";
96055
96079
  var LEGACY_PROMETHEUS_PLANS_DIR = ".sisyphus/plans";
96056
96080
  var PROMETHEUS_PLAN_DIRS = [PROMETHEUS_PLANS_DIR, LEGACY_PROMETHEUS_PLANS_DIR];
96057
96081
  function findPrometheusPlans(directory) {
96058
96082
  try {
96059
96083
  return PROMETHEUS_PLAN_DIRS.flatMap((planDir) => {
96060
- const plansDir = join66(directory, planDir);
96084
+ const plansDir = join67(directory, planDir);
96061
96085
  if (!existsSync54(plansDir)) {
96062
96086
  return [];
96063
96087
  }
96064
- return readdirSync18(plansDir).filter((file) => file.endsWith(".md")).map((file) => join66(plansDir, file));
96088
+ return readdirSync18(plansDir).filter((file) => file.endsWith(".md")).map((file) => join67(plansDir, file));
96065
96089
  }).sort((left, right) => statSync8(right).mtimeMs - statSync8(left).mtimeMs);
96066
96090
  } catch {
96067
96091
  return [];
@@ -96335,14 +96359,14 @@ function getTaskSessionState(directory, taskKey) {
96335
96359
  }
96336
96360
  // packages/boulder-state/src/storage/write-state.ts
96337
96361
  import { existsSync as existsSync56, mkdirSync as mkdirSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync12 } from "fs";
96338
- import { dirname as dirname21, join as join67 } from "path";
96362
+ import { dirname as dirname21, join as join68 } from "path";
96339
96363
  function writeBoulderState(directory, state) {
96340
96364
  const filePath = getBoulderFilePath(directory);
96341
96365
  try {
96342
96366
  const dir = dirname21(filePath);
96343
96367
  if (!existsSync56(dir)) {
96344
96368
  mkdirSync12(dir, { recursive: true });
96345
- writeFileSync12(join67(dir, ".gitignore"), ["*", "!/rules/", "!/rules/**", ""].join(`
96369
+ writeFileSync12(join68(dir, ".gitignore"), ["*", "!/rules/", "!/rules/**", ""].join(`
96346
96370
  `), "utf-8");
96347
96371
  }
96348
96372
  const stateToWrite = { ...state };
@@ -96570,7 +96594,7 @@ function appendSessionIdForWork(directory, workId, sessionId, origin = "direct")
96570
96594
  }
96571
96595
  // packages/boulder-state/src/storage/stale-work.ts
96572
96596
  import { readdirSync as readdirSync19, statSync as statSync9 } from "fs";
96573
- import { join as join68 } from "path";
96597
+ import { join as join69 } from "path";
96574
96598
  var DEFAULT_STALE_WORK_THRESHOLD_MS = 6 * 60 * 60 * 1000;
96575
96599
  var STALE_WORK_THRESHOLD_ENV_KEY = "OMO_BOULDER_STALE_WORK_THRESHOLD_MS";
96576
96600
  var SESSION_TRANSCRIPT_SUFFIX = ".jsonl";
@@ -96678,14 +96702,14 @@ function findNewestSessionTranscriptMs(input) {
96678
96702
  for (const entry of entries) {
96679
96703
  if (entry.isFile) {
96680
96704
  if (isTranscriptOf(entry.name, sessionIds)) {
96681
- newest = newestMs([newest, mtimeMs(join68(input.sessionsDirectory, entry.name))]);
96705
+ newest = newestMs([newest, mtimeMs(join69(input.sessionsDirectory, entry.name))]);
96682
96706
  }
96683
96707
  continue;
96684
96708
  }
96685
96709
  if (!entry.isDirectory || !matchesSessionCwd(entry.name, needles)) {
96686
96710
  continue;
96687
96711
  }
96688
- const sessionDirectory = join68(input.sessionsDirectory, entry.name);
96712
+ const sessionDirectory = join69(input.sessionsDirectory, entry.name);
96689
96713
  let fileNames;
96690
96714
  try {
96691
96715
  fileNames = readdirSync19(sessionDirectory);
@@ -96694,7 +96718,7 @@ function findNewestSessionTranscriptMs(input) {
96694
96718
  }
96695
96719
  for (const fileName of fileNames) {
96696
96720
  if (isTranscriptOf(fileName, sessionIds)) {
96697
- newest = newestMs([newest, mtimeMs(join68(sessionDirectory, fileName))]);
96721
+ newest = newestMs([newest, mtimeMs(join69(sessionDirectory, fileName))]);
96698
96722
  }
96699
96723
  }
96700
96724
  }
@@ -96952,15 +96976,15 @@ import {
96952
96976
  writeFileSync as writeFileSync13,
96953
96977
  unlinkSync as unlinkSync9
96954
96978
  } from "fs";
96955
- import { join as join70 } from "path";
96979
+ import { join as join71 } from "path";
96956
96980
 
96957
96981
  // packages/omo-opencode/src/hooks/rules-injector/constants.ts
96958
- import { join as join69 } from "path";
96959
- var RULES_INJECTOR_STORAGE = join69(OPENCODE_STORAGE, "rules-injector");
96982
+ import { join as join70 } from "path";
96983
+ var RULES_INJECTOR_STORAGE = join70(OPENCODE_STORAGE, "rules-injector");
96960
96984
 
96961
96985
  // packages/omo-opencode/src/hooks/rules-injector/storage.ts
96962
96986
  function getStoragePath(sessionID) {
96963
- return join70(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
96987
+ return join71(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
96964
96988
  }
96965
96989
  function loadInjectedRules(sessionID) {
96966
96990
  const filePath = getStoragePath(sessionID);
@@ -97712,7 +97736,7 @@ function getCachedVersion(options = {}) {
97712
97736
  // package.json
97713
97737
  var package_default = {
97714
97738
  name: "oh-my-opencode",
97715
- version: "5.0.0-beta.86",
97739
+ version: "5.0.0-beta.88",
97716
97740
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
97717
97741
  main: "./dist/index.js",
97718
97742
  types: "dist/index.d.ts",
@@ -97895,7 +97919,7 @@ var package_default = {
97895
97919
  zod: "^4.6.5"
97896
97920
  },
97897
97921
  devDependencies: {
97898
- "@code-yeongyu/senpi": "2026.9.23-2",
97922
+ "@code-yeongyu/senpi": "2026.9.23-5",
97899
97923
  "@oh-my-opencode/agents-md-core": "workspace:*",
97900
97924
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
97901
97925
  "@oh-my-opencode/boulder-state": "workspace:*",
@@ -97931,22 +97955,23 @@ var package_default = {
97931
97955
  "@xterm/xterm": "^6.0.0",
97932
97956
  "bun-types": "1.4.2",
97933
97957
  "node-pty": "^1.1.0",
97958
+ omowright: "github:code-yeongyu/omowright#25781c8ac04f9aae358b06551520b792ac45c6ed",
97934
97959
  "puppeteer-core": "^25.11.0",
97935
97960
  typescript: "^7.0.2"
97936
97961
  },
97937
97962
  optionalDependencies: {
97938
- "oh-my-opencode-darwin-arm64": "5.0.0-beta.86",
97939
- "oh-my-opencode-darwin-x64": "5.0.0-beta.86",
97940
- "oh-my-opencode-darwin-x64-baseline": "5.0.0-beta.86",
97941
- "oh-my-opencode-linux-arm64": "5.0.0-beta.86",
97942
- "oh-my-opencode-linux-arm64-musl": "5.0.0-beta.86",
97943
- "oh-my-opencode-linux-x64": "5.0.0-beta.86",
97944
- "oh-my-opencode-linux-x64-baseline": "5.0.0-beta.86",
97945
- "oh-my-opencode-linux-x64-musl": "5.0.0-beta.86",
97946
- "oh-my-opencode-linux-x64-musl-baseline": "5.0.0-beta.86",
97947
- "oh-my-opencode-windows-arm64": "5.0.0-beta.86",
97948
- "oh-my-opencode-windows-x64": "5.0.0-beta.86",
97949
- "oh-my-opencode-windows-x64-baseline": "5.0.0-beta.86"
97963
+ "oh-my-opencode-darwin-arm64": "5.0.0-beta.88",
97964
+ "oh-my-opencode-darwin-x64": "5.0.0-beta.88",
97965
+ "oh-my-opencode-darwin-x64-baseline": "5.0.0-beta.88",
97966
+ "oh-my-opencode-linux-arm64": "5.0.0-beta.88",
97967
+ "oh-my-opencode-linux-arm64-musl": "5.0.0-beta.88",
97968
+ "oh-my-opencode-linux-x64": "5.0.0-beta.88",
97969
+ "oh-my-opencode-linux-x64-baseline": "5.0.0-beta.88",
97970
+ "oh-my-opencode-linux-x64-musl": "5.0.0-beta.88",
97971
+ "oh-my-opencode-linux-x64-musl-baseline": "5.0.0-beta.88",
97972
+ "oh-my-opencode-windows-arm64": "5.0.0-beta.88",
97973
+ "oh-my-opencode-windows-x64": "5.0.0-beta.88",
97974
+ "oh-my-opencode-windows-x64-baseline": "5.0.0-beta.88"
97950
97975
  },
97951
97976
  overrides: {
97952
97977
  "@earendil-works/pi-agent-core": "0.84.2",
@@ -98128,7 +98153,7 @@ function syncCachePackageJsonToIntent(pluginInfo) {
98128
98153
  }
98129
98154
  // packages/omo-opencode/src/hooks/auto-update-checker/hook/background-update-check.ts
98130
98155
  import { existsSync as existsSync66 } from "fs";
98131
- import { dirname as dirname25, join as join77 } from "path";
98156
+ import { dirname as dirname25, join as join78 } from "path";
98132
98157
  import { fileURLToPath as fileURLToPath4 } from "url";
98133
98158
  // packages/omo-opencode/src/cli/config-manager/add-plugin-to-opencode-config.ts
98134
98159
  init_main();
@@ -99144,12 +99169,12 @@ function spawnWithWindowsHide(command, options) {
99144
99169
  }
99145
99170
  // packages/omo-opencode/src/cli/config-manager/bun-install.ts
99146
99171
  import { existsSync as existsSync64 } from "fs";
99147
- import { join as join75 } from "path";
99172
+ import { join as join76 } from "path";
99148
99173
  init_logger2();
99149
99174
  var BUN_INSTALL_TIMEOUT_SECONDS = 60;
99150
99175
  var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
99151
99176
  function getDefaultWorkspaceDir() {
99152
- return join75(getOpenCodeCacheDir(), "packages");
99177
+ return join76(getOpenCodeCacheDir(), "packages");
99153
99178
  }
99154
99179
  function readProcessOutput(stream) {
99155
99180
  if (!stream) {
@@ -99413,7 +99438,7 @@ function getCacheWorkspaceDir(deps) {
99413
99438
  }
99414
99439
  var defaultDeps2 = {
99415
99440
  existsSync: existsSync66,
99416
- join: join77,
99441
+ join: join78,
99417
99442
  runBunInstallWithDetails,
99418
99443
  log: log2,
99419
99444
  getOpenCodeCacheDir,
@@ -99785,7 +99810,7 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
99785
99810
  // packages/omo-opencode/src/hooks/ast-grep-sg-provision/hook.ts
99786
99811
  init_src();
99787
99812
  import { homedir as homedir15 } from "os";
99788
- import { join as join78 } from "path";
99813
+ import { join as join79 } from "path";
99789
99814
  var provisionedTargets = new Set;
99790
99815
  function defaultSchedule(task) {
99791
99816
  const timer = setTimeout(() => {
@@ -99812,7 +99837,7 @@ var defaultDeps4 = {
99812
99837
  function createAstGrepSgProvisionHook(depsOverride = {}) {
99813
99838
  const deps = { ...defaultDeps4, ...depsOverride };
99814
99839
  const platform = deps.platform ?? process.platform;
99815
- const targetDir = astGrepRuntimeDir(join78(deps.homeDir(), ".omo"), platform, deps.arch ?? process.arch);
99840
+ const targetDir = astGrepRuntimeDir(join79(deps.homeDir(), ".omo"), platform, deps.arch ?? process.arch);
99816
99841
  return {
99817
99842
  event(input) {
99818
99843
  try {
@@ -99839,11 +99864,11 @@ import {
99839
99864
  writeFileSync as writeFileSync16,
99840
99865
  unlinkSync as unlinkSync12
99841
99866
  } from "fs";
99842
- import { join as join80 } from "path";
99867
+ import { join as join81 } from "path";
99843
99868
 
99844
99869
  // packages/omo-opencode/src/hooks/agent-usage-reminder/constants.ts
99845
- import { join as join79 } from "path";
99846
- var AGENT_USAGE_REMINDER_STORAGE = join79(OPENCODE_STORAGE, "agent-usage-reminder");
99870
+ import { join as join80 } from "path";
99871
+ var AGENT_USAGE_REMINDER_STORAGE = join80(OPENCODE_STORAGE, "agent-usage-reminder");
99847
99872
  var TARGET_TOOLS = new Set([
99848
99873
  "grep",
99849
99874
  "safe_grep",
@@ -99887,7 +99912,7 @@ ALWAYS prefer: Multiple parallel task calls > Direct tool calls
99887
99912
 
99888
99913
  // packages/omo-opencode/src/hooks/agent-usage-reminder/storage.ts
99889
99914
  function getStoragePath2(sessionID) {
99890
- return join80(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
99915
+ return join81(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
99891
99916
  }
99892
99917
  function loadAgentUsageState(sessionID) {
99893
99918
  const filePath = getStoragePath2(sessionID);
@@ -103787,9 +103812,9 @@ task(category="quick", load_skills=["git-master"], run_in_background=true)
103787
103812
 
103788
103813
  ## EXECUTION RULES
103789
103814
  - **TODO format**: \`path: <action> for <scenario-id> \u2014 verify by <check>\` encoding WHERE / WHY (which scenario it advances) / HOW / VERIFY. Exactly ONE in_progress at a time. Mark completed IMMEDIATELY \u2014 never batch.
103790
- - GOOD pair (test-first, ordered): \`module.test: Write FAILING case invalid-email\u2192ValidationError for S2 - verify by RED with assertion msg\` \u2192 \`src/module: Implement validateEmail() for S2 - verify by module.test GREEN + curl 400 body\`
103791
- - BAD: "Implement feature" / "Fix bug" / "Add tests later" / production code before its failing test \u2192 rewrite.
103792
- - **PARALLEL**: Fire independent agent calls simultaneously via task(run_in_background=true) \u2014 NEVER wait sequentially. But NEVER parallelise RED and GREEN of the same scenario.
103815
+ - GOOD pair (ordered): \`test/module.test: read the validateEmail cases for S2 - verify by noting intent / coverage / pass in the notepad\` \u2192 \`src/module: Implement validateEmail() for S2 - verify by curl 400 body + module.test green\`
103816
+ - BAD: "Implement feature" / "Fix bug" / "Add tests later" \u2192 rewrite.
103817
+ - **PARALLEL**: Fire independent agent calls simultaneously via task(run_in_background=true) \u2014 NEVER wait sequentially. But READ before CHANGE, never in parallel with it.
103793
103818
  - **BACKGROUND FIRST**: Use task for exploration/research agents (10+ concurrent if needed).
103794
103819
  - **VERIFY**: Re-read request after completion. Check every scenario PASS with both artifacts captured.
103795
103820
  - **DELEGATE**: Don't do everything yourself \u2014 orchestrate specialized agents for their strengths.
@@ -103820,10 +103845,10 @@ BEFORE writing ANY code, define realistic scenarios sized to the change \u2014 *
103820
103845
 
103821
103846
  Each scenario MUST specify, upfront:
103822
103847
  - Pass condition as a binary observable ("returns 200 + body matches schema"), not "should work".
103823
- - The REAL surface that proves it: tmux transcript, curl status+body, browser/Playwright assertion, computer-use action log, CLI stdout, parsed config dump, DB state diff. Asserting "tests pass" alone is NOT evidence.
103824
- - The cheapest faithful proof: a test file + test id at a code seam (written test-first \u2014 see TDD below), or the real-surface scenario itself when no seam exists. Prose, docs, prompt, and visual-only changes take review + real-surface QA \u2014 a test pinning their text is pretend-coverage, not proof.
103848
+ - The REAL surface that proves it: tmux transcript, curl status+body, browser (omowright) assertion, computer-use action log, CLI stdout, parsed config dump, DB state diff. Asserting "tests pass" alone is NOT evidence.
103849
+ - The existing tests that cover it (read first \u2014 see Test Decision below) and the real-surface scenario that proves it. Prose, docs, prompt, and visual-only changes take review + real-surface QA \u2014 a test pinning their text is pretend-coverage, not proof.
103825
103850
 
103826
- **These scenarios are the CONTRACT.** Record them in your TODO/notepad. You are not done until every one PASSES with both pieces of evidence captured (RED\u2192GREEN proof + real-surface artifact).
103851
+ **These scenarios are the CONTRACT.** Record them in your TODO/notepad. You are not done until every one PASSES with its real-surface artifact captured and the tests the repository keeps for it green.
103827
103852
 
103828
103853
  ### Durable Notepad (survives context loss)
103829
103854
 
@@ -103849,12 +103874,12 @@ Every scenario requires TWO captured artifacts \u2014 both mandatory:
103849
103874
 
103850
103875
  | Artifact | Source | Captures |
103851
103876
  |----------|--------|----------|
103852
- | **RED\u2192GREEN proof** | Test runner output before AND after the change | Test id + assertion message in both states |
103853
- | **Real-surface artifact** | tmux / curl / browser / Playwright / computer-use / CLI / DB | What the user actually sees |
103877
+ | **Tests of record** | The existing suite for the area, read before the change and green after it | Intent / coverage / pass noted; stale expectations updated |
103878
+ | **Real-surface artifact** | tmux / curl / browser (omowright) / computer-use / CLI / DB | What the user actually sees |
103854
103879
 
103855
103880
  Supporting (necessary, not sufficient): build exit 0, full suite green, lsp_diagnostics clean on changed files, regression scenarios still PASS.
103856
103881
 
103857
- The real-surface artifact is always required. A test is required only where a code seam exists. "tests pass" alone is NOT done, and a test pinning prose or visual text is NOT evidence.
103882
+ The real-surface artifact is always required. A new test only where the repository keeps tests for this behavior and a regression would otherwise pass unnoticed. "tests pass" alone is NOT done, and a test pinning prose or visual text is NOT evidence.
103858
103883
 
103859
103884
  <MANUAL_QA_MANDATE>
103860
103885
  ### YOU MUST EXECUTE MANUAL QA YOURSELF. THIS IS NOT OPTIONAL.
@@ -103868,7 +103893,7 @@ The real-surface artifact is always required. A test is required only where a co
103868
103893
  | Adds/modifies a CLI command | Run the command with Bash. Show the output. |
103869
103894
  | Changes build output | Run the build. Verify the output files exist and are correct. |
103870
103895
  | Modifies API behavior | Call the endpoint. Show the response. |
103871
- | Changes UI rendering | Drive the REAL page from js eval: (1) \`new Bun.WebView()\` on Bun >= 1.4 (macOS default; Linux/Windows need installed Chrome/Chromium/Edge). (2) Otherwise, or for Chrome semantics, stealth, trace, or auth, WRITE a \`playwright-core\` script and run it from the kernel against local Chrome (\`chromium.launch({ channel: "chrome" })\` / \`launchPersistentContext\`). Capture screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile. For login state, CLONE the profile first (\`rsync -a <profile>/ <tmp-clone>/\`) and use only the clone as the persistent user-data-dir; clear data only there. |
103896
+ | Changes UI rendering | Drive the REAL page from js eval with omowright (staged in the \`browser\` skill): the owned engine (\`connectPipe\` on a task-owned profile, \`connectCloakProfile\` for bot-scored targets) for unauthenticated pages, the attached engine (\`connectBrowserSkill()\` in the user's own signed-in browser) when the page needs their login. Capture screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile, and never clone it; if the attached engine is missing, run the browser skill's onboarding script and relay its one human step instead of launching a headless browser. |
103872
103897
  | Changes UI rendering or a TUI/terminal layout (incl. CJK/Korean/Japanese/Chinese text) | Load the visual-qa skill: capture reference + actual screenshots (web) or the xterm.js web terminal render (TUI; NEVER \`tmux capture-pane\` - it degrades color and CJK width), run its bundled pixel-diff / column-width script, and get the dual read-only verdict (design-system + functional integrity, and visual fidelity + CJK precision). Record the diff/score artifact. |
103873
103898
  | Changes a desktop/GUI (non-page) surface | Computer use: OS-level GUI automation against the running app. Capture action log + screenshot. |
103874
103899
  | Adds a new tool/hook/feature | Test it end-to-end in a real scenario. |
@@ -103888,36 +103913,29 @@ The real-surface artifact is always required. A test is required only where a co
103888
103913
  **CLEANUP IS PART OF QA \u2014 TRACK IT AS TODOS.** The moment a QA scenario spawns any resource, add a teardown todo for it (QA scripts, tmux assets, browser contexts, PIDs, ports, containers, temp dirs). Execute every teardown todo and capture the receipt before declaring done. A leftover process / tmux session / browser context / bound port / temp dir = NOT done.
103889
103914
  </MANUAL_QA_MANDATE>
103890
103915
 
103891
- ### TDD Workflow (MANDATORY on every production code change with a test seam)
103892
-
103893
- Test-first is not optional for code. Every code behavior change \u2014 features, fixes, refactors, perf, glue, config-with-logic \u2014 follows RED \u2192 GREEN \u2192 SURFACE. Prose, docs, and visual-only changes have no seam: skip RED\u2192GREEN and prove them through the surface channel.
103916
+ ### Test Decision (every production code change)
103894
103917
 
103895
- 1. **RED**: Write the failing test FIRST. Run it. Capture the assertion message proving it fails for the RIGHT reason (not syntax, not import). Paste RED output into the notepad. No production code yet.
103896
- 2. **GREEN**: Write the SMALLEST change that flips RED\u2192GREEN. Re-run. Capture GREEN output. If GREEN required ~20+ lines, your test was too coarse \u2014 split it.
103897
- 3. **SURFACE**: Exercise the real user-facing surface named by the scenario. Capture artifact path into the notepad.
103898
- 4. **REFACTOR**: Optional, only if needed. Tests MUST stay green throughout.
103899
- 5. **REGRESSION**: Re-run the FULL scenario list. Record PASS/FAIL inline with both evidence paths.
103918
+ 1. **READ** the tests covering the area BEFORE touching it \u2014 they are the behavior of record. Note in the notepad: do they encode the intent, cover this path, pass? One WRONG before your change is a FINDING to report \u2014 NEVER edit a test green. A bug: reproduce it first and capture the failure. A refactor: the existing tests are green on the unchanged code first.
103919
+ 2. **CHANGE**: the SMALLEST change that meets the scenario; update the tests your change makes stale. Add a test ONLY when BOTH hold: the repository keeps tests for this behavior AND a regression would otherwise pass unnoticed by the run and the existing tests \u2014 sized like its neighbors, one case per stated behavior, failing when that behavior breaks. A test that restates the change (a constant, a string, a rename, a call) is NOT evidence; the run is.
103920
+ 3. **SURFACE**: Exercise the real user-facing surface named by the scenario; a reproduction now passes. Capture the artifact path into the notepad.
103921
+ 4. **REGRESSION**: Re-run the FULL scenario list plus the step-1 tests. Record PASS/FAIL inline with evidence paths.
103900
103922
 
103901
- **Refactor exception**: when refactoring behavior whose regressions the change could hide, write characterization tests pinning current observable behavior FIRST, watch them go GREEN against old code, THEN refactor. They remain green throughout.
103902
-
103903
- **Exemption whitelist** (no new test required): pure formatting, comment-only edits, dependency version bumps with no behavior delta, rename-only moves. Each exemption MUST be justified in \`## Findings\` with the exact reason. Unjustified exemption is rejection.
103904
-
103905
- **If you typed production code without a failing test preceding it in the notepad: STOP, revert, write the test, watch it fail, then redo.**
103923
+ Prose, docs, prompt, and visual-only changes have no test seam: review + real-surface QA, NO test \u2014 a test pinning their text is pretend-coverage.
103906
103924
 
103907
103925
  ### Commit Discipline (MANDATORY)
103908
103926
 
103909
- Commit frequently: one atomic commit per verified increment (RED\u2192GREEN + evidence captured), never one end-of-run omnibus. BEFORE composing each message, study the history and mimic it \u2014 run \`git log --oneline -20\` plus \`git log -5 -- <touched paths>\` \u2014 matching subject shape, scope names, message language, body style, and typical commit size. Load the \`git-master\` skill for the commit workflow when available. Skip committing only when the user forbade commits this session.
103927
+ Commit frequently: one atomic commit per verified increment (change + evidence captured), never one end-of-run omnibus. BEFORE composing each message, study the history and mimic it \u2014 run \`git log --oneline -20\` plus \`git log -5 -- <touched paths>\` \u2014 matching subject shape, scope names, message language, body style, and typical commit size. Load the \`git-master\` skill for the commit workflow when available. Skip committing only when the user forbade commits this session.
103910
103928
 
103911
103929
  ### Verification Anti-Patterns (BLOCKING)
103912
103930
 
103913
103931
  | Violation | Why It Fails |
103914
103932
  |-----------|--------------|
103915
103933
  | "It should work now" | No evidence. Run it. |
103916
- | "I added the tests" | Did they go RED first, then GREEN? Show both. |
103934
+ | "I added the tests" | Did the repository keep tests here, and would the regression have passed unnoticed without them? Otherwise the run is the proof. |
103917
103935
  | "Fixed the bug" | What scenario proves it? Where's the artifact? |
103918
103936
  | "Implementation complete" | Every scenario PASS with both artifacts captured? |
103919
103937
  | Skipping test execution | Tests exist to be RUN, not just written |
103920
- | Writing code before its failing test | TDD floor violated \u2014 revert, write test, redo |
103938
+ | A test that restates the change | Cannot fail for any regression \u2014 delete it; the run is the proof |
103921
103939
 
103922
103940
  **CLAIM NOTHING WITHOUT PROOF. EXECUTE. VERIFY. SHOW EVIDENCE.**
103923
103941
 
@@ -104165,43 +104183,37 @@ When the \`create_goal\` tool exists, you MUST register the run's goal with it B
104165
104183
 
104166
104184
  ### SCENARIO CONTRACT (binding, defined BEFORE coding)
104167
104185
 
104168
- Define scenarios sized to the change \u2014 1-2 for a small single-surface change, 3+ for risky or multi-surface work \u2014 each with a binary pass condition and the cheapest faithful proof: a test file+test id at a code seam (test-first), or the real-surface scenario itself when no seam exists (prose, docs, visual-only: review + real-surface QA, no test). Classes:
104186
+ Define scenarios sized to the change \u2014 1-2 for a small single-surface change, 3+ for risky or multi-surface work \u2014 each with a binary pass condition and the existing tests that cover it (read first) and the real-surface scenario that proves it (prose, docs, visual-only: review + real-surface QA, no test). Classes:
104169
104187
  - **Happy path** (always)
104170
104188
  - **Edge** (boundary, empty, malformed, concurrent \u2014 when risky)
104171
104189
  - **Adjacent-surface regression** (callers, sibling endpoints, related modules \u2014 when multi-surface)
104172
104190
 
104173
- Scenarios are the contract. Done = every scenario PASSES with both artifacts (RED\u2192GREEN proof AND real-surface artifact).
104191
+ Scenarios are the contract. Done = every scenario PASSES with its real-surface artifact captured and the tests of record green.
104174
104192
 
104175
104193
  ### DURABLE NOTEPAD
104176
104194
 
104177
104195
  At start: \`NOTE=$(mktemp -t ulw-$(date +%Y%m%d-%H%M%S).XXXXXX.md)\`. Echo the path. APPEND-ONLY sections: Plan, Scenarios, Now, Todo, Findings (file:line), Learnings. If context is lost, re-read and resume \u2014 this is your only durable memory.
104178
104196
 
104179
- ### TDD (MANDATORY for code with a test seam)
104180
-
104181
- Every production code change \u2014 features, fixes, refactors, perf, glue, config-with-logic \u2014 follows RED\u2192GREEN\u2192SURFACE. Prose, docs, and visual-only changes have no seam: skip RED\u2192GREEN, prove them through the surface channel.
104182
-
104183
- 1. **RED**: Write the failing test FIRST. Run it. Capture the assertion message that proves it fails for the RIGHT reason (not syntax, not import). Paste RED output into the notepad. No production code yet.
104184
- 2. **GREEN**: Smallest change to flip RED\u2192GREEN. Re-run, capture GREEN output. If GREEN required ~20+ lines, your test was too coarse \u2014 split it.
104185
- 3. **SURFACE**: Exercise the real user-facing surface (CLI / API / build / UI / config). Capture artifact path.
104186
- 4. **REGRESSION**: Re-run the FULL scenario list every increment. Record PASS/FAIL with both artifact paths.
104197
+ ### TEST DECISION (every production code change)
104187
104198
 
104188
- **Refactors**: write characterization tests pinning current observable behavior FIRST, watch them GREEN against the old code, THEN refactor. Stay green throughout.
104199
+ 1. **READ** the tests covering the area BEFORE touching it \u2014 the behavior of record: do they encode the intent, cover this path, pass? One WRONG before your change is a FINDING to report \u2014 NEVER edit a test green. A bug: reproduce it first and capture the failure. A refactor: the existing tests are green on the unchanged code first.
104200
+ 2. **CHANGE**: the SMALLEST change that meets the scenario; update the tests it makes stale. Add a test ONLY when BOTH hold: the repository keeps tests for this behavior AND a regression would otherwise pass unnoticed by the run and the existing tests \u2014 sized like its neighbors, never one that restates the change. The run is the proof, not a test that certifies the diff.
104201
+ 3. **SURFACE**: Exercise the real user-facing surface (CLI / API / build / UI / config); a reproduction now passes. Capture artifact path.
104202
+ 4. **REGRESSION**: Re-run the FULL scenario list plus the step-1 tests every increment. Record PASS/FAIL with artifact paths.
104189
104203
 
104190
- **Exemption whitelist**: pure formatting, comment-only edits, version bumps with no behavior delta, rename-only moves. Each MUST be justified in writing. Unjustified exemption = rejection.
104191
-
104192
- **If you typed production code without a failing test preceding it: STOP, revert, write the test, watch it fail, then redo.** No exceptions \u2014 "obvious" / "one-liner" / "too small" do NOT exempt you.
104204
+ Prose, docs, and visual-only changes have no seam: prove them through the surface channel, NO test.
104193
104205
 
104194
104206
  ### COMMIT DISCIPLINE (MANDATORY)
104195
104207
 
104196
- Commit frequently: one atomic commit per verified increment (RED\u2192GREEN + evidence captured), never one end-of-run omnibus. BEFORE composing each message, study the history and mimic it \u2014 run \`git log --oneline -20\` plus \`git log -5 -- <touched paths>\` \u2014 matching subject shape, scope names, message language, body style, and typical commit size. Skip committing only when the user forbade commits this session.
104208
+ Commit frequently: one atomic commit per verified increment (change + evidence captured), never one end-of-run omnibus. BEFORE composing each message, study the history and mimic it \u2014 run \`git log --oneline -20\` plus \`git log -5 -- <touched paths>\` \u2014 matching subject shape, scope names, message language, body style, and typical commit size. Skip committing only when the user forbade commits this session.
104197
104209
 
104198
104210
  ### Evidence Gates
104199
104211
 
104200
104212
  | Gate | Required Evidence |
104201
104213
  |------|-------------------|
104202
- | **RED** | Failing assertion msg before any production code |
104203
- | **GREEN** | Same test now passing |
104204
- | **Surface** | tmux / curl / browser / Playwright / computer-use / CLI / DB diff artifact path |
104214
+ | **Read** | Existing tests for the area noted (intent / coverage / pass) before the change |
104215
+ | **Run** | Tests of record green after it; stale expectations updated |
104216
+ | **Surface** | tmux / curl / browser (omowright) / computer-use / CLI / DB diff artifact path |
104205
104217
  | **Build** | Exit code 0 |
104206
104218
  | **Suite** | Full run green; no skip/.only/xfail added this turn |
104207
104219
  | **Lint** | lsp_diagnostics clean on changed files |
@@ -104209,13 +104221,13 @@ Commit frequently: one atomic commit per verified increment (RED\u2192GREEN + ev
104209
104221
  <ANTI_OPTIMISM_CHECKPOINT>
104210
104222
  ## BEFORE YOU CLAIM DONE, ANSWER HONESTLY:
104211
104223
 
104212
- 1. Did EVERY scenario reach RED captured \u2192 GREEN captured \u2192 surface artifact captured? (paths in notepad)
104224
+ 1. Did EVERY scenario reach surface artifact captured with the tests of record green? (paths in notepad)
104213
104225
  2. Did I run \`lsp_diagnostics\` and see ZERO errors on changed files? (not "I'm sure")
104214
104226
  3. Did I run the FULL suite and see it PASS? (not "they should pass")
104215
104227
  4. Did I read the actual output of every command? (not skim)
104216
104228
  5. Is EVERY requirement from the request actually implemented? (re-read the request NOW)
104217
104229
  6. Did I classify intent at the start? (if not, my entire approach may be wrong)
104218
- 7. Did I write code BEFORE its failing test, anywhere? (if yes, REVERT and redo via TDD)
104230
+ 7. Did I add a test that only restates the change, or edit a wrong test green? (if yes, delete it / report the finding)
104219
104231
 
104220
104232
  If ANY answer is no \u2192 GO BACK AND DO IT. Do not claim completion.
104221
104233
  </ANTI_OPTIMISM_CHECKPOINT>
@@ -104240,7 +104252,7 @@ Trigger if user said "\uC5C4\uBC00"/"strictly"/"rigorously"/"properly review", o
104240
104252
  | Adds/modifies a CLI command | Run the command with Bash. Show the output. |
104241
104253
  | Changes build output | Run the build. Verify output files exist and are correct. |
104242
104254
  | Modifies API behavior | Call the endpoint. Show the response. |
104243
- | Renders/changes a page | Drive the REAL page from js eval: (1) \`new Bun.WebView()\` on Bun >= 1.4 (macOS default; Linux/Windows need installed Chrome/Chromium/Edge). (2) Otherwise, or for Chrome semantics, stealth, trace, or auth, WRITE a \`playwright-core\` script and run it from the kernel against local Chrome (\`chromium.launch({ channel: "chrome" })\` / \`launchPersistentContext\`). Capture screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile. For login state, CLONE it first (\`rsync -a <profile>/ <tmp-clone>/\`) and use only the clone as the persistent user-data-dir; clear data only there. |
104255
+ | Renders/changes a page | Drive the REAL page from js eval with omowright (staged in the \`browser\` skill): the owned engine (\`connectPipe\` on a task-owned profile, \`connectCloakProfile\` for bot-scored targets) for unauthenticated pages, the attached engine (\`connectBrowserSkill()\` in the user's own signed-in browser) when the page needs their login. Capture screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile, and never clone it; if the attached engine is missing, run the browser skill's onboarding script and relay its one human step instead of launching a headless browser. |
104244
104256
  | Changes UI rendering or a TUI/terminal layout (incl. CJK/Korean/Japanese/Chinese text) | Load the visual-qa skill: capture reference + actual screenshots (web) or the xterm.js web terminal render (TUI; NEVER \`tmux capture-pane\` - it degrades color and CJK width), run its bundled pixel-diff / column-width script, and get the dual read-only verdict (design-system + functional integrity, and visual fidelity + CJK precision). Record the diff/score artifact. |
104245
104257
  | Drives a desktop/GUI (non-page) surface | Computer use: OS-level GUI automation against the running app. Capture action log + screenshot. |
104246
104258
  | Adds a new tool/hook/feature | Test it end-to-end in a real scenario. |
@@ -104448,17 +104460,14 @@ Before production changes, define scenarios covering:
104448
104460
 
104449
104461
  Each scenario needs a binary pass condition. "Looks good" is not a pass condition.
104450
104462
 
104451
- ## TDD WORKFLOW
104452
-
104453
- TDD is mandatory on production code changes with a test seam; prose, docs, and visual-only changes take review + real-surface QA instead (a test pinning their text is pretend-coverage).
104463
+ ## TEST DECISION
104454
104464
 
104455
- 1. RED: write or identify a failing test that proves the needed behavior.
104456
- 2. GREEN: make the smallest change that flips the test to passing.
104457
- 3. SURFACE: exercise the real user path and capture the artifact.
104458
- 4. REFACTOR: improve structure only while tests stay green.
104459
- 5. REGRESSION: rerun the scenario list.
104465
+ 1. READ: the tests covering the area, before any edit \u2014 intent, coverage, pass. One wrong before your change is a finding, never edited green. A bug: reproduce it first.
104466
+ 2. CHANGE: the smallest change; update tests it makes stale. A new test only where the repository keeps tests for this behavior AND a regression would otherwise pass unnoticed \u2014 never one that restates the change.
104467
+ 3. SURFACE: exercise the real user path and capture the artifact; a reproduction now passes.
104468
+ 4. REGRESSION: rerun the scenario list and the step-1 tests.
104460
104469
 
104461
- Exemptions: pure prompt text, formatting, comment-only edits, version bumps with no behavior delta, and rename-only moves. Justify every exemption in the final report.
104470
+ Prose, docs, and visual-only changes take review + real-surface QA, no test (a test pinning their text is pretend-coverage).
104462
104471
 
104463
104472
  ## COMMIT DISCIPLINE
104464
104473
 
@@ -104620,8 +104629,8 @@ deep_context = background_output(task_id=...)
104620
104629
  - If delegating: every child prompt carries GOAL, STOP WHEN (the exact observable condition that ends its run \u2014 the child stops the moment it holds), and EVIDENCE (what it returns so you can verify, not trust) \u2014 plus exhaustive context. Judge the child by its returned EVIDENCE against its STOP WHEN, never by its self-report.
104621
104630
 
104622
104631
  **Verify (per-scenario, not just "at the end"):**
104623
- - RED\u2192GREEN proof captured (test id + assertion msg in both states)
104624
- - Real-surface artifact (tmux / curl / browser / Playwright / computer-use / CLI / DB diff)
104632
+ - Existing tests read (intent / coverage / pass), stale expectations updated
104633
+ - Real-surface artifact (tmux / curl / browser (omowright) / computer-use / CLI / DB diff)
104625
104634
  - \`lsp_diagnostics\` clean on modified files
104626
104635
  - Full suite green, regression scenarios still PASS
104627
104636
 
@@ -104642,17 +104651,13 @@ Maintain a live todo list for every multi-step task: one atomic item per action
104642
104651
  Define scenarios sized to the change \u2014 1-2 for small single-surface work, 3+ for risky or multi-surface work \u2014 covering: **happy path**, plus **edge** (boundary / empty / malformed / concurrent) and **adjacent-surface regression** when the change is risky or multi-surface. For each, write:
104643
104652
  - Binary pass condition ("returns 200 with schema-matching body"), not "should work".
104644
104653
  - The real surface that proves it.
104645
- - The cheapest faithful proof: a test file + test id at a code seam (test-first; see TDD), or the real-surface scenario itself when no seam exists (prose, docs, visual-only: review + real-surface QA, no test).
104646
-
104647
- Scenarios are the contract. Done = every scenario PASSES with RED\u2192GREEN proof AND real-surface artifact captured. Then declare WHEN TO STOP for the whole run, in one line: "I'll stop right away when <the exact observable state that ends this run>" \u2014 its end state MUST be the full STOP GOAL from the Stop rules, never scenario completion alone. The Stop rules bind to this line \u2014 the moment it holds, you stop.
104648
-
104649
- ## TDD (MANDATORY on every production code change with a test seam)
104654
+ - The existing tests that cover it (see TEST DECISION) and the real-surface scenario that proves it (prose, docs, visual-only: review + real-surface QA, no test).
104650
104655
 
104651
- Code features, fixes, refactors, perf, glue, config-with-logic \u2014 all follow RED\u2192GREEN\u2192SURFACE. Prose, docs, and visual-only changes have no test seam: prove them through the real-surface channel; a test pinning their text is pretend-coverage. Write the failing test FIRST; capture the assertion proving it fails for the right reason; write the SMALLEST change to flip it green; exercise the real surface; capture both artifacts. **If you wrote production code without a failing test preceding it: STOP, revert, write the test, redo.**
104656
+ Scenarios are the contract. Done = every scenario PASSES with its real-surface artifact captured and the tests of record green. Then declare WHEN TO STOP for the whole run, in one line: "I'll stop right away when <the exact observable state that ends this run>" \u2014 its end state MUST be the full STOP GOAL from the Stop rules, never scenario completion alone. The Stop rules bind to this line \u2014 the moment it holds, you stop.
104652
104657
 
104653
- Refactors of behavior whose regressions the change could hide: write characterization tests pinning current behavior FIRST, watch them GREEN against old code, THEN refactor. They stay green throughout.
104658
+ ## TEST DECISION
104654
104659
 
104655
- Exemption whitelist (no new test required): formatting, comment-only, version bumps with no behavior delta, rename-only. Each must be justified in writing. Unjustified exemption is rejection.
104660
+ READ the tests covering the area BEFORE touching it \u2014 they are the behavior of record: intent, coverage, pass. One WRONG before your change is a FINDING \u2014 never edit a test green. Reproduce a bug before fixing it; a refactor starts with the existing tests green on the unchanged code. The run proves the change: add a test ONLY where the repository keeps tests for this behavior AND a regression would otherwise pass unnoticed \u2014 sized like its neighbors, never one that restates the change. Prose, docs, and visual-only changes have no test seam: real-surface channel, no test; a test pinning their text is pretend-coverage.
104656
104661
 
104657
104662
  ## COMMIT DISCIPLINE
104658
104663
 
@@ -104662,8 +104667,8 @@ Commit one atomic commit per verified increment; never one end-of-run omnibus. B
104662
104667
 
104663
104668
  | Phase | Action | Required Evidence |
104664
104669
  |-------|--------|-------------------|
104665
- | RED | Run new test before impl | Failing assertion with msg |
104666
- | GREEN | Re-run after smallest change | Passing assertion |
104670
+ | Read | Existing tests for the area, before the change | Intent / coverage / pass noted |
104671
+ | Run | Tests of record after the change | Green; stale expectations updated |
104667
104672
  | Surface | Exercise real user path | Artifact path (tmux/curl/browser/...) |
104668
104673
  | Build | Run build command | Exit code 0 |
104669
104674
  | Suite | Full test run | All green; no skip/.only/xfail added |
@@ -104679,7 +104684,7 @@ lsp_diagnostics catches type errors only. Logic bugs, missing behavior, broken f
104679
104684
  | Adds/modifies a CLI command | Run it with Bash. Show output. |
104680
104685
  | Changes build output | Run build. Verify output files. |
104681
104686
  | Modifies API behavior | Call the endpoint. Show response. |
104682
- | Renders/changes a page | Drive the page from js eval: (1) \`new Bun.WebView()\` on Bun >= 1.4 (macOS default; Linux/Windows need installed Chrome/Chromium/Edge). (2) Otherwise, or for Chrome semantics, stealth, trace, or auth, WRITE a \`playwright-core\` script and run it from the kernel against local Chrome (\`chromium.launch({ channel: "chrome" })\` / \`launchPersistentContext\`). Screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile. For login state, CLONE it first (\`rsync -a <profile>/ <tmp-clone>/\`) and use only the clone as the persistent user-data-dir; clear data only there. |
104687
+ | Renders/changes a page | Drive the REAL page from js eval with omowright (staged in the \`browser\` skill): the owned engine (\`connectPipe\` on a task-owned profile, \`connectCloakProfile\` for bot-scored targets) for unauthenticated pages, the attached engine (\`connectBrowserSkill()\` in the user's own signed-in browser) when the page needs their login. Screenshot + action log. NEVER clear cookies, cache, or site data on the user's live profile, and never clone it; if the attached engine is missing, run the browser skill's onboarding script and relay its one human step instead of launching a headless browser. |
104683
104688
  | Changes UI rendering or a TUI/terminal layout (incl. CJK/Korean/Japanese/Chinese text) | Load the visual-qa skill: capture reference + actual screenshots (web) or the xterm.js web terminal render (TUI; NEVER \`tmux capture-pane\` - it degrades color and CJK width), run its bundled pixel-diff / column-width script, and get the dual read-only verdict (design-system + functional integrity, and visual fidelity + CJK precision). Record the diff/score artifact. |
104684
104689
  | Drives a desktop GUI | Computer use: OS-level GUI automation against the running app. Action log + screenshot. |
104685
104690
  | Adds tool/hook/feature | Test end-to-end in a real scenario. |
@@ -104695,7 +104700,7 @@ Trigger if user said "\uC5C4\uBC00"/"strictly"/"rigorously"/"properly review", o
104695
104700
  ## STOP RULES
104696
104701
 
104697
104702
  - After each result, ask whether the user's core request can now be answered with useful evidence in hand. If yes, answer now \u2014 skip any remaining retrieval, ceremony, or verification that adds no evidence.
104698
- - The STOP GOAL: every scenario PASSES with RED\u2192GREEN proof AND real-surface artifact captured; full suite green and \`lsp_diagnostics\` clean on changed files; QA teardown receipts recorded; no scope creep; and (if triggered) the reviewer gate approved unconditionally. Above ALL of that, the decisive test \u2014 outranking every other consideration \u2014 is: is the user's problem ACTUALLY SOLVED in observable behavior? If no, you are NOT done, whatever the checklist says. If yes, deliver the final message and STOP \u2014 no hesitation, no extra verification pass, no polish loop. Work past the stop goal is scope creep, not diligence.
104703
+ - The STOP GOAL: every scenario PASSES with its real-surface artifact captured and the tests of record green; full suite green and \`lsp_diagnostics\` clean on changed files; QA teardown receipts recorded; no scope creep; and (if triggered) the reviewer gate approved unconditionally. Above ALL of that, the decisive test \u2014 outranking every other consideration \u2014 is: is the user's problem ACTUALLY SOLVED in observable behavior? If no, you are NOT done, whatever the checklist says. If yes, deliver the final message and STOP \u2014 no hesitation, no extra verification pass, no polish loop. Work past the stop goal is scope creep, not diligence.
104699
104704
  - After 2 identical failed attempts at one step, surface what was tried and ask the user before another retry.
104700
104705
  - After 2 parallel exploration waves yield no new useful facts, stop exploring and act.
104701
104706
 
@@ -105338,11 +105343,11 @@ import {
105338
105343
  writeFileSync as writeFileSync17,
105339
105344
  unlinkSync as unlinkSync13
105340
105345
  } from "fs";
105341
- import { join as join82 } from "path";
105346
+ import { join as join83 } from "path";
105342
105347
 
105343
105348
  // packages/omo-opencode/src/hooks/interactive-bash-session/constants.ts
105344
- import { join as join81 } from "path";
105345
- var INTERACTIVE_BASH_SESSION_STORAGE = join81(OPENCODE_STORAGE, "interactive-bash-session");
105349
+ import { join as join82 } from "path";
105350
+ var INTERACTIVE_BASH_SESSION_STORAGE = join82(OPENCODE_STORAGE, "interactive-bash-session");
105346
105351
  var OMO_SESSION_PREFIX = "omo-";
105347
105352
  function buildSessionReminderMessage(sessions) {
105348
105353
  if (sessions.length === 0)
@@ -105354,7 +105359,7 @@ function buildSessionReminderMessage(sessions) {
105354
105359
 
105355
105360
  // packages/omo-opencode/src/hooks/interactive-bash-session/storage.ts
105356
105361
  function getStoragePath3(sessionID) {
105357
- return join82(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
105362
+ return join83(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
105358
105363
  }
105359
105364
  function loadInteractiveBashSessionState(sessionID) {
105360
105365
  const filePath = getStoragePath3(sessionID);
@@ -106574,12 +106579,12 @@ init_logger2();
106574
106579
  init_logger2();
106575
106580
  // packages/omo-opencode/src/hooks/goal/controller.ts
106576
106581
  import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync19 } from "fs";
106577
- import { dirname as dirname27, join as join84 } from "path";
106582
+ import { dirname as dirname27, join as join85 } from "path";
106578
106583
 
106579
106584
  // packages/omo-opencode/src/hooks/goal/store.ts
106580
106585
  import { randomUUID as randomUUID8 } from "crypto";
106581
106586
  import { mkdirSync as mkdirSync17, readFileSync as readFileSync45, renameSync as renameSync7, unlinkSync as unlinkSync14, writeFileSync as writeFileSync18 } from "fs";
106582
- import { join as join83 } from "path";
106587
+ import { join as join84 } from "path";
106583
106588
 
106584
106589
  // packages/omo-opencode/src/hooks/goal/types.ts
106585
106590
  import { z as z52 } from "zod";
@@ -106617,7 +106622,7 @@ var GoalToolResponseSchema = z52.object({
106617
106622
  // packages/omo-opencode/src/hooks/goal/store.ts
106618
106623
  var STORE_VERSION = 1;
106619
106624
  function goalFilePath(ref) {
106620
- return join83(ref.baseDir, `${encodeURIComponent(ref.sessionID)}.json`);
106625
+ return join84(ref.baseDir, `${encodeURIComponent(ref.sessionID)}.json`);
106621
106626
  }
106622
106627
  function ensureGoalStoreDir(baseDir) {
106623
106628
  mkdirSync17(baseDir, { recursive: true });
@@ -106738,9 +106743,9 @@ function validateObjective(objective) {
106738
106743
  // packages/omo-opencode/src/hooks/goal/controller.ts
106739
106744
  function createGoalController(options) {
106740
106745
  const { projectDir } = options;
106741
- const baseDir = join84(projectDir, ".omo", "goal");
106746
+ const baseDir = join85(projectDir, ".omo", "goal");
106742
106747
  const storeRef = (sessionID) => ({ baseDir, sessionID });
106743
- const tuiMirrorPath = (sessionID) => join84(projectDir, ".omo", "ulw-loop", sessionID, "goals.json");
106748
+ const tuiMirrorPath = (sessionID) => join85(projectDir, ".omo", "ulw-loop", sessionID, "goals.json");
106744
106749
  const writeTuiMirror = (sessionID, goal) => {
106745
106750
  const path = tuiMirrorPath(sessionID);
106746
106751
  const snapshot = {
@@ -107173,7 +107178,7 @@ import { dirname as dirname33 } from "path";
107173
107178
  init_resolve_commands_in_text();
107174
107179
  // packages/skills-loader-core/src/features/opencode-skill-loader/loader.ts
107175
107180
  init_src();
107176
- import { join as join91 } from "path";
107181
+ import { join as join92 } from "path";
107177
107182
 
107178
107183
  // packages/shared-skills/index.mjs
107179
107184
  import { existsSync as existsSync69 } from "fs";
@@ -107186,21 +107191,21 @@ function sharedSkillsRootPath() {
107186
107191
 
107187
107192
  // packages/skills-loader-core/src/shared/claude-config-dir.ts
107188
107193
  init_src();
107189
- import { join as join85 } from "path";
107194
+ import { join as join86 } from "path";
107190
107195
  function getClaudeConfigDir2() {
107191
107196
  const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
107192
107197
  if (envConfigDir) {
107193
107198
  return envConfigDir;
107194
107199
  }
107195
- return join85(getHomeDirectory(), ".claude");
107200
+ return join86(getHomeDirectory(), ".claude");
107196
107201
  }
107197
107202
  // packages/skills-loader-core/src/shared/opencode-command-dirs.ts
107198
- import { basename as basename11, dirname as dirname28, join as join87 } from "path";
107203
+ import { basename as basename11, dirname as dirname28, join as join88 } from "path";
107199
107204
 
107200
107205
  // packages/skills-loader-core/src/shared/opencode-config-dir.ts
107201
107206
  import { existsSync as existsSync70, realpathSync as realpathSync12 } from "fs";
107202
107207
  import { homedir as homedir17 } from "os";
107203
- import { join as join86, posix as posix8, resolve as resolve16, win32 as win327 } from "path";
107208
+ import { join as join87, posix as posix8, resolve as resolve16, win32 as win327 } from "path";
107204
107209
 
107205
107210
  // packages/skills-loader-core/src/shared/plugin-identity.ts
107206
107211
  init_src();
@@ -107233,15 +107238,15 @@ function getTauriConfigDir2(identifier) {
107233
107238
  const platform = process.platform;
107234
107239
  switch (platform) {
107235
107240
  case "darwin":
107236
- return join86(homedir17(), "Library", "Application Support", identifier);
107241
+ return join87(homedir17(), "Library", "Application Support", identifier);
107237
107242
  case "win32": {
107238
- const appData = process.env.APPDATA || join86(homedir17(), "AppData", "Roaming");
107243
+ const appData = process.env.APPDATA || join87(homedir17(), "AppData", "Roaming");
107239
107244
  return win327.join(appData, identifier);
107240
107245
  }
107241
107246
  case "linux":
107242
107247
  default: {
107243
- const xdgConfig = process.env.XDG_CONFIG_HOME || join86(homedir17(), ".config");
107244
- return join86(xdgConfig, identifier);
107248
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join87(homedir17(), ".config");
107249
+ return join87(xdgConfig, identifier);
107245
107250
  }
107246
107251
  }
107247
107252
  }
@@ -107284,8 +107289,8 @@ function getWslLinuxHomeDir2(windowsConfigRoot) {
107284
107289
  function getCliDefaultConfigDir2() {
107285
107290
  const envXdgConfig = process.env.XDG_CONFIG_HOME?.trim();
107286
107291
  const shouldIgnoreWindowsXdg = envXdgConfig !== undefined && envXdgConfig.length > 0 && isWslEnvironment2() && isWindowsUserConfigRoot2(envXdgConfig);
107287
- const xdgConfig = shouldIgnoreWindowsXdg ? posix8.join(getWslLinuxHomeDir2(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join86(homedir17(), ".config");
107288
- const configDir = isWslEnvironment2() ? posix8.join(xdgConfig, "opencode") : join86(xdgConfig, "opencode");
107292
+ const xdgConfig = shouldIgnoreWindowsXdg ? posix8.join(getWslLinuxHomeDir2(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join87(homedir17(), ".config");
107293
+ const configDir = isWslEnvironment2() ? posix8.join(xdgConfig, "opencode") : join87(xdgConfig, "opencode");
107289
107294
  return resolveConfigPath2(configDir);
107290
107295
  }
107291
107296
  function getCliCustomConfigDir2() {
@@ -107318,8 +107323,8 @@ function getOpenCodeConfigDir2(options) {
107318
107323
  const tauriDir = process.platform === "win32" ? win327.isAbsolute(tauriDirBase) ? win327.normalize(tauriDirBase) : win327.resolve(tauriDirBase) : resolveConfigPath2(tauriDirBase);
107319
107324
  if (checkExisting) {
107320
107325
  const legacyDir = getCliConfigDir2();
107321
- const legacyConfig = join86(legacyDir, "opencode.json");
107322
- const legacyConfigC = join86(legacyDir, "opencode.jsonc");
107326
+ const legacyConfig = join87(legacyDir, "opencode.json");
107327
+ const legacyConfigC = join87(legacyDir, "opencode.jsonc");
107323
107328
  if (existsSync70(legacyConfig) || existsSync70(legacyConfigC)) {
107324
107329
  return legacyDir;
107325
107330
  }
@@ -107341,9 +107346,9 @@ function getOpenCodeSkillDirs(options) {
107341
107346
  ...configDirs.flatMap((configDir) => {
107342
107347
  const parentConfigDir = getParentOpencodeConfigDir2(configDir);
107343
107348
  return [
107344
- join87(configDir, "skills"),
107345
- join87(configDir, "skill"),
107346
- ...parentConfigDir ? [join87(parentConfigDir, "skills"), join87(parentConfigDir, "skill")] : []
107349
+ join88(configDir, "skills"),
107350
+ join88(configDir, "skill"),
107351
+ ...parentConfigDir ? [join88(parentConfigDir, "skills"), join88(parentConfigDir, "skill")] : []
107347
107352
  ];
107348
107353
  })
107349
107354
  ]));
@@ -107351,7 +107356,7 @@ function getOpenCodeSkillDirs(options) {
107351
107356
  // packages/skills-loader-core/src/shared/project-discovery-dirs.ts
107352
107357
  import { execFileSync as execFileSync4 } from "child_process";
107353
107358
  import { existsSync as existsSync71, realpathSync as realpathSync13 } from "fs";
107354
- import { dirname as dirname29, join as join88, resolve as resolve17, win32 as win328 } from "path";
107359
+ import { dirname as dirname29, join as join89, resolve as resolve17, win32 as win328 } from "path";
107355
107360
  var worktreePathCache2 = new Map;
107356
107361
  function normalizePath4(path) {
107357
107362
  const resolvedPath = process.platform !== "win32" && win328.isAbsolute(path) ? path : resolve17(path);
@@ -107386,7 +107391,7 @@ function findAncestorDirectories2(startDirectory, targetPaths, stopDirectory) {
107386
107391
  const stopDirectoryKey = resolvedStopDirectory ? pathKey3(resolvedStopDirectory) : undefined;
107387
107392
  while (true) {
107388
107393
  for (const targetPath of targetPaths) {
107389
- const candidateDirectory = join88(currentDirectory, ...targetPath);
107394
+ const candidateDirectory = join89(currentDirectory, ...targetPath);
107390
107395
  if (!existsSync71(candidateDirectory)) {
107391
107396
  continue;
107392
107397
  }
@@ -107541,7 +107546,7 @@ function deduplicateSkillsByName(skills) {
107541
107546
  // packages/skills-loader-core/src/features/opencode-skill-loader/skill-directory-loader.ts
107542
107547
  init_src();
107543
107548
  import * as fs17 from "fs/promises";
107544
- import { join as join90 } from "path";
107549
+ import { join as join91 } from "path";
107545
107550
 
107546
107551
  // packages/skills-loader-core/src/features/opencode-skill-loader/loaded-skill-from-path.ts
107547
107552
  init_src();
@@ -107561,7 +107566,7 @@ function parseAllowedTools(allowedTools) {
107561
107566
  // packages/skills-loader-core/src/features/opencode-skill-loader/skill-mcp-config.ts
107562
107567
  init_js_yaml();
107563
107568
  import * as fs15 from "fs/promises";
107564
- import { join as join89 } from "path";
107569
+ import { join as join90 } from "path";
107565
107570
  function parseSkillMcpConfigFromFrontmatter(content) {
107566
107571
  const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
107567
107572
  if (!frontmatterMatch)
@@ -107580,7 +107585,7 @@ function parseSkillMcpConfigFromFrontmatter(content) {
107580
107585
  return;
107581
107586
  }
107582
107587
  async function loadMcpJsonFromDir(skillDir) {
107583
- const mcpJsonPath = join89(skillDir, "mcp.json");
107588
+ const mcpJsonPath = join90(skillDir, "mcp.json");
107584
107589
  try {
107585
107590
  const content = await fs15.readFile(mcpJsonPath, "utf-8");
107586
107591
  const parsed = JSON.parse(content);
@@ -107696,10 +107701,10 @@ async function loadSkillsFromDir(options) {
107696
107701
  const directories = entries.filter((entry) => !entry.name.startsWith(".") && (entry.isDirectory() || entry.isSymbolicLink()));
107697
107702
  const files = entries.filter((entry) => !entry.name.startsWith(".") && !entry.isDirectory() && !entry.isSymbolicLink() && isMarkdownFile(entry));
107698
107703
  for (const entry of directories) {
107699
- const entryPath = join90(options.skillsDir, entry.name);
107704
+ const entryPath = join91(options.skillsDir, entry.name);
107700
107705
  const resolvedPath = await resolveSymlinkAsync(entryPath);
107701
107706
  const dirName = entry.name;
107702
- const skillMdPath = join90(resolvedPath, "SKILL.md");
107707
+ const skillMdPath = join91(resolvedPath, "SKILL.md");
107703
107708
  if (await canAccessFile(skillMdPath)) {
107704
107709
  const skill = await loadSkillFromPath({
107705
107710
  skillPath: skillMdPath,
@@ -107713,7 +107718,7 @@ async function loadSkillsFromDir(options) {
107713
107718
  }
107714
107719
  continue;
107715
107720
  }
107716
- const namedSkillMdPath = join90(resolvedPath, `${dirName}.md`);
107721
+ const namedSkillMdPath = join91(resolvedPath, `${dirName}.md`);
107717
107722
  if (await canAccessFile(namedSkillMdPath)) {
107718
107723
  const skill = await loadSkillFromPath({
107719
107724
  skillPath: namedSkillMdPath,
@@ -107744,7 +107749,7 @@ async function loadSkillsFromDir(options) {
107744
107749
  }
107745
107750
  }
107746
107751
  for (const entry of files) {
107747
- const entryPath = join90(options.skillsDir, entry.name);
107752
+ const entryPath = join91(options.skillsDir, entry.name);
107748
107753
  const baseName = inferSkillNameFromFileName(entryPath);
107749
107754
  const skill = await loadSkillFromPath({
107750
107755
  skillPath: entryPath,
@@ -107762,7 +107767,7 @@ async function loadSkillsFromDir(options) {
107762
107767
 
107763
107768
  // packages/skills-loader-core/src/features/opencode-skill-loader/loader.ts
107764
107769
  async function loadUserSkills() {
107765
- const userSkillsDir = join91(getClaudeConfigDir2(), "skills");
107770
+ const userSkillsDir = join92(getClaudeConfigDir2(), "skills");
107766
107771
  const skills = await loadSkillsFromDir({ skillsDir: userSkillsDir, scope: "user" });
107767
107772
  return skillsToCommandDefinitionRecord(skills);
107768
107773
  }
@@ -107787,7 +107792,7 @@ async function loadProjectAgentsSkills(directory) {
107787
107792
  return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat()));
107788
107793
  }
107789
107794
  async function loadGlobalAgentsSkills(homeDirectory = getHomeDirectory()) {
107790
- const agentsGlobalDir = join91(homeDirectory, ".agents", "skills");
107795
+ const agentsGlobalDir = join92(homeDirectory, ".agents", "skills");
107791
107796
  const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
107792
107797
  return skillsToCommandDefinitionRecord(skills);
107793
107798
  }
@@ -107842,7 +107847,7 @@ async function discoverSkills(options = {}) {
107842
107847
  ]);
107843
107848
  }
107844
107849
  async function discoverUserClaudeSkills() {
107845
- const userSkillsDir = join91(getClaudeConfigDir2(), "skills");
107850
+ const userSkillsDir = join92(getClaudeConfigDir2(), "skills");
107846
107851
  return loadSkillsFromDir({ skillsDir: userSkillsDir, scope: "user" });
107847
107852
  }
107848
107853
  async function discoverProjectClaudeSkills(directory) {
@@ -107869,16 +107874,16 @@ async function discoverProjectAgentsSkills(directory) {
107869
107874
  return deduplicateSkillsByName(allSkills.flat());
107870
107875
  }
107871
107876
  async function discoverGlobalAgentsSkills(homeDirectory = getHomeDirectory()) {
107872
- const agentsGlobalDir = join91(homeDirectory, ".agents", "skills");
107877
+ const agentsGlobalDir = join92(homeDirectory, ".agents", "skills");
107873
107878
  return loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" });
107874
107879
  }
107875
107880
  // packages/skills-loader-core/src/features/opencode-skill-loader/merger/builtin-skill-converter.ts
107876
107881
  import { existsSync as existsSync72 } from "fs";
107877
- import { join as join92 } from "path";
107882
+ import { join as join93 } from "path";
107878
107883
  function resolveBuiltinSkillPath(builtin) {
107879
107884
  if (builtin.resolvedPath !== undefined)
107880
107885
  return builtin.resolvedPath;
107881
- const sharedSkillPath = join92(sharedSkillsRootPath(), builtin.name);
107886
+ const sharedSkillPath = join93(sharedSkillsRootPath(), builtin.name);
107882
107887
  return existsSync72(sharedSkillPath) ? sharedSkillPath : undefined;
107883
107888
  }
107884
107889
  function builtinToLoadedSkill(builtin) {
@@ -108331,7 +108336,7 @@ playwright-cli close
108331
108336
  };
108332
108337
  // packages/skills-loader-core/src/features/builtin-skills/skill-file-loader.ts
108333
108338
  import { readFileSync as readFileSync47 } from "fs";
108334
- import { join as join93 } from "path";
108339
+ import { join as join94 } from "path";
108335
108340
  init_src();
108336
108341
  function createSharedSkillTemplateLoader(readFile = readFileSync47, skillsRootPath = sharedSkillsRootPath()) {
108337
108342
  const cache = new Map;
@@ -108340,7 +108345,7 @@ function createSharedSkillTemplateLoader(readFile = readFileSync47, skillsRootPa
108340
108345
  if (cached !== undefined)
108341
108346
  return cached;
108342
108347
  try {
108343
- const { body } = parseFrontmatter(readFile(join93(skillsRootPath, skillName, "SKILL.md"), "utf8"));
108348
+ const { body } = parseFrontmatter(readFile(join94(skillsRootPath, skillName, "SKILL.md"), "utf8"));
108344
108349
  cache.set(skillName, body);
108345
108350
  return body;
108346
108351
  } catch (error) {
@@ -109477,7 +109482,7 @@ var gitMasterSkill = {
109477
109482
  template: GIT_MASTER_TEMPLATE
109478
109483
  };
109479
109484
  // packages/skills-loader-core/src/features/builtin-skills/skills/dev-browser.ts
109480
- import { dirname as dirname31, join as join94 } from "path";
109485
+ import { dirname as dirname31, join as join95 } from "path";
109481
109486
  import { fileURLToPath as fileURLToPath6 } from "url";
109482
109487
  var CURRENT_DIR = dirname31(fileURLToPath6(import.meta.url));
109483
109488
  var devBrowserSkill = {
@@ -109697,7 +109702,7 @@ console.log({
109697
109702
  await client.disconnect();
109698
109703
  EOF
109699
109704
  \`\`\``,
109700
- resolvedPath: join94(CURRENT_DIR, "..", "dev-browser")
109705
+ resolvedPath: join95(CURRENT_DIR, "..", "dev-browser")
109701
109706
  };
109702
109707
  // packages/skills-loader-core/src/features/builtin-skills/skills/review-work.ts
109703
109708
  var reviewWorkSkill = {
@@ -110639,7 +110644,7 @@ init_src();
110639
110644
  var import_picomatch2 = __toESM(require_picomatch2(), 1);
110640
110645
  import * as fs18 from "fs/promises";
110641
110646
  import { homedir as homedir19 } from "os";
110642
- import { dirname as dirname32, extname, isAbsolute as isAbsolute13, join as join95, relative as relative13 } from "path";
110647
+ import { dirname as dirname32, extname, isAbsolute as isAbsolute13, join as join96, relative as relative13 } from "path";
110643
110648
  var MAX_RECURSIVE_DEPTH = 10;
110644
110649
  function isHttpUrl(path) {
110645
110650
  return path.startsWith("http://") || path.startsWith("https://");
@@ -110649,12 +110654,12 @@ function toAbsolutePath(path, configDir) {
110649
110654
  return homedir19();
110650
110655
  }
110651
110656
  if (path.startsWith("~/")) {
110652
- return join95(homedir19(), path.slice(2));
110657
+ return join96(homedir19(), path.slice(2));
110653
110658
  }
110654
110659
  if (isAbsolute13(path)) {
110655
110660
  return path;
110656
110661
  }
110657
- return join95(configDir, path);
110662
+ return join96(configDir, path);
110658
110663
  }
110659
110664
  function isMarkdownPath(path) {
110660
110665
  return extname(path).toLowerCase() === ".md";
@@ -110784,7 +110789,7 @@ function readOpencodeConfigSkills(directory) {
110784
110789
  }
110785
110790
  // packages/omo-opencode/src/tools/slashcommand/command-discovery.ts
110786
110791
  import { existsSync as existsSync75, readdirSync as readdirSync22, readFileSync as readFileSync50, statSync as statSync12 } from "fs";
110787
- import { basename as basename13, join as join97 } from "path";
110792
+ import { basename as basename13, join as join98 } from "path";
110788
110793
  init_logger2();
110789
110794
 
110790
110795
  // packages/omo-opencode/src/features/builtin-commands/templates/goal.ts
@@ -112313,12 +112318,12 @@ function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
112313
112318
  if (entry.name.startsWith("."))
112314
112319
  continue;
112315
112320
  const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` : entry.name;
112316
- commands.push(...discoverCommandsFromDir(join97(commandsDir, entry.name), scope, nestedPrefix));
112321
+ commands.push(...discoverCommandsFromDir(join98(commandsDir, entry.name), scope, nestedPrefix));
112317
112322
  continue;
112318
112323
  }
112319
112324
  if (!isMarkdownFile(entry))
112320
112325
  continue;
112321
- const commandPath = join97(commandsDir, entry.name);
112326
+ const commandPath = join98(commandsDir, entry.name);
112322
112327
  const baseCommandName = basename13(entry.name, ".md");
112323
112328
  const commandName = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` : baseCommandName;
112324
112329
  try {
@@ -112377,8 +112382,8 @@ function deduplicateCommandInfosByName(commands) {
112377
112382
  return deduplicatedCommands;
112378
112383
  }
112379
112384
  function discoverCommandsSync(directory, options) {
112380
- const userCommandsDir = join97(getClaudeConfigDir(), "commands");
112381
- const projectCommandsDir = join97(directory ?? process.cwd(), ".claude", "commands");
112385
+ const userCommandsDir = join98(getClaudeConfigDir(), "commands");
112386
+ const projectCommandsDir = join98(directory ?? process.cwd(), ".claude", "commands");
112382
112387
  const opencodeGlobalDirs = getOpenCodeCommandDirs({ binary: "opencode" });
112383
112388
  const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd());
112384
112389
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
@@ -113079,7 +113084,7 @@ to continue: task(task_id="${taskId}", load_skills=[], run_in_background=true, p
113079
113084
  // packages/omo-senpi/src/components/agent-home/resolve-agent-home.ts
113080
113085
  import { existsSync as existsSync76 } from "fs";
113081
113086
  import { homedir as homedir20 } from "os";
113082
- import { join as join98, resolve as resolve20 } from "path";
113087
+ import { join as join99, resolve as resolve20 } from "path";
113083
113088
  var AGENT_DIR_ENV_NAMES = [
113084
113089
  "OMO_CODING_AGENT_DIR",
113085
113090
  "SENPI_CODING_AGENT_DIR",
@@ -113093,16 +113098,16 @@ function resolveAgentHome(options) {
113093
113098
  if (configured)
113094
113099
  return resolve20(configured);
113095
113100
  }
113096
- const brandedHome = join98(homeDir, ".omo");
113097
- const canonical = join98(brandedHome, "agent");
113098
- if (exists(join98(canonical, AGENT_HOME_SENTINEL)))
113101
+ const brandedHome = join99(homeDir, ".omo");
113102
+ const canonical = join99(brandedHome, "agent");
113103
+ if (exists(join99(canonical, AGENT_HOME_SENTINEL)))
113099
113104
  return canonical;
113100
- if (exists(join98(brandedHome, AGENT_HOME_SENTINEL)))
113105
+ if (exists(join99(brandedHome, AGENT_HOME_SENTINEL)))
113101
113106
  return brandedHome;
113102
- return join98(homeDir, ".senpi", "agent");
113107
+ return join99(homeDir, ".senpi", "agent");
113103
113108
  }
113104
113109
  function resolveAgentSessionsDirectory(options) {
113105
- return join98(resolveAgentHome(options), "sessions");
113110
+ return join99(resolveAgentHome(options), "sessions");
113106
113111
  }
113107
113112
 
113108
113113
  // packages/omo-opencode/src/hooks/ulw-execute/ulw-execute-hook.ts
@@ -113221,7 +113226,7 @@ ${completionInstruction}`;
113221
113226
  // packages/omo-opencode/src/hooks/ulw-execute/notepad-scaffold.ts
113222
113227
  init_logger2();
113223
113228
  import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync20 } from "fs";
113224
- import { join as join99 } from "path";
113229
+ import { join as join100 } from "path";
113225
113230
  var NOTEPAD_FILES = [
113226
113231
  "learnings.md",
113227
113232
  "decisions.md",
@@ -113255,14 +113260,14 @@ ${NOTEPAD_FOOTER}
113255
113260
  }
113256
113261
  function ensureNotepadScaffold(params) {
113257
113262
  const { directory, planName, timestamp = new Date().toISOString() } = params;
113258
- const notepadDir = join99(directory, ".omo", "notepads", planName);
113263
+ const notepadDir = join100(directory, ".omo", "notepads", planName);
113259
113264
  mkdirSync19(notepadDir, { recursive: true });
113260
113265
  const created = [];
113261
113266
  const skipped = [];
113262
113267
  for (const fileName of NOTEPAD_FILES) {
113263
113268
  const header = buildHeader(fileName, planName, timestamp);
113264
113269
  try {
113265
- writeFileSync20(join99(notepadDir, fileName), header, { flag: "wx" });
113270
+ writeFileSync20(join100(notepadDir, fileName), header, { flag: "wx" });
113266
113271
  created.push(fileName);
113267
113272
  } catch (err) {
113268
113273
  if (err.code === "EEXIST") {
@@ -114576,7 +114581,7 @@ async function isSessionInBoulderLineage(input) {
114576
114581
 
114577
114582
  // packages/omo-opencode/src/hooks/atlas/session-last-agent.ts
114578
114583
  import { readFileSync as readFileSync51, readdirSync as readdirSync23 } from "fs";
114579
- import { join as join100 } from "path";
114584
+ import { join as join101 } from "path";
114580
114585
  var defaultSessionLastAgentDeps = {
114581
114586
  getMessageDir,
114582
114587
  isSqliteBackend,
@@ -114636,7 +114641,7 @@ async function getLastAgentFromSession(sessionID, client, deps = {}) {
114636
114641
  try {
114637
114642
  const messages = readdirSync23(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
114638
114643
  try {
114639
- const content = readFileSync51(join100(messageDir, fileName), "utf-8");
114644
+ const content = readFileSync51(join101(messageDir, fileName), "utf-8");
114640
114645
  const parsed = JSON.parse(content);
114641
114646
  return {
114642
114647
  fileName,
@@ -120265,7 +120270,7 @@ function createRuntimeFallbackHook(ctx, options, factoryOverrides = {}) {
120265
120270
  }
120266
120271
  // packages/omo-opencode/src/hooks/write-existing-file-guard/hook.ts
120267
120272
  import { existsSync as existsSync82, realpathSync as realpathSync15 } from "fs";
120268
- import { basename as basename14, dirname as dirname34, isAbsolute as isAbsolute15, join as join101, normalize as normalize2, relative as relative15, resolve as resolve24 } from "path";
120273
+ import { basename as basename14, dirname as dirname34, isAbsolute as isAbsolute15, join as join102, normalize as normalize2, relative as relative15, resolve as resolve24 } from "path";
120269
120274
 
120270
120275
  // packages/omo-opencode/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
120271
120276
  import { existsSync as existsSync81 } from "fs";
@@ -120454,7 +120459,7 @@ function toCanonicalPath2(absolutePath) {
120454
120459
  } else {
120455
120460
  const absoluteDir = dirname34(absolutePath);
120456
120461
  const resolvedDir = existsSync82(absoluteDir) ? realpathSync15.native(absoluteDir) : absoluteDir;
120457
- canonicalPath = join101(resolvedDir, basename14(absolutePath));
120462
+ canonicalPath = join102(resolvedDir, basename14(absolutePath));
120458
120463
  }
120459
120464
  return normalize2(canonicalPath);
120460
120465
  }
@@ -123216,12 +123221,12 @@ init_plugin_identity();
123216
123221
 
123217
123222
  // packages/omo-opencode/src/hooks/legacy-plugin-toast/auto-migrate.ts
123218
123223
  import { existsSync as existsSync83, readFileSync as readFileSync55 } from "fs";
123219
- import { join as join102 } from "path";
123224
+ import { join as join103 } from "path";
123220
123225
  init_plugin_identity();
123221
123226
  function detectOpenCodeConfigPath(overrideConfigDir) {
123222
123227
  if (overrideConfigDir) {
123223
- const jsoncPath = join102(overrideConfigDir, "opencode.jsonc");
123224
- const jsonPath = join102(overrideConfigDir, "opencode.json");
123228
+ const jsoncPath = join103(overrideConfigDir, "opencode.jsonc");
123229
+ const jsonPath = join103(overrideConfigDir, "opencode.json");
123225
123230
  if (existsSync83(jsoncPath))
123226
123231
  return jsoncPath;
123227
123232
  if (existsSync83(jsonPath))
@@ -123384,7 +123389,7 @@ function decideNativeEditionNudge(input) {
123384
123389
  // packages/omo-opencode/src/hooks/native-edition-nudge/hook.ts
123385
123390
  import { existsSync as existsSync84 } from "fs";
123386
123391
  import { homedir as homedir21 } from "os";
123387
- import { join as join104 } from "path";
123392
+ import { join as join105 } from "path";
123388
123393
 
123389
123394
  // packages/omo-opencode/src/cli/native-edition-hint.ts
123390
123395
  var NATIVE_EDITION_INSTALL_COMMAND = "bun add -g omo-ai@beta";
@@ -123394,7 +123399,7 @@ init_logger2();
123394
123399
 
123395
123400
  // packages/omo-opencode/src/hooks/native-edition-nudge/state.ts
123396
123401
  import { mkdirSync as mkdirSync20, readFileSync as readFileSync56, unlinkSync as unlinkSync15, writeFileSync as writeFileSync21 } from "fs";
123397
- import { join as join103 } from "path";
123402
+ import { join as join104 } from "path";
123398
123403
  var NUDGE_STATE_FILE = "native-nudge.json";
123399
123404
  function isDecision(value) {
123400
123405
  return value === "none" || value === "snoozed" || value === "never" || value === "migrated";
@@ -123428,7 +123433,7 @@ function parseNudgeState(raw) {
123428
123433
  };
123429
123434
  }
123430
123435
  function createNudgeStateStore(stateDir) {
123431
- const path = join103(stateDir, NUDGE_STATE_FILE);
123436
+ const path = join104(stateDir, NUDGE_STATE_FILE);
123432
123437
  return {
123433
123438
  read: () => {
123434
123439
  let raw;
@@ -123450,7 +123455,7 @@ function createNudgeStateStore(stateDir) {
123450
123455
  }
123451
123456
  },
123452
123457
  probeWritable: () => {
123453
- const probe = join103(stateDir, `.${NUDGE_STATE_FILE}.probe`);
123458
+ const probe = join104(stateDir, `.${NUDGE_STATE_FILE}.probe`);
123454
123459
  try {
123455
123460
  mkdirSync20(stateDir, { recursive: true });
123456
123461
  writeFileSync21(probe, "", { mode: 384 });
@@ -123470,10 +123475,10 @@ var NATIVE_NUDGE_TOAST_TITLE = "Try OmO Native: no host app needed";
123470
123475
  var NATIVE_NUDGE_TOAST_MESSAGE = `Same agent, one binary, nothing else to keep updated.
123471
123476
  Install: ${NATIVE_EDITION_INSTALL_COMMAND}`;
123472
123477
  function nativeEditionStateDir() {
123473
- return join104(getUserConfigDir(), "oh-my-openagent");
123478
+ return join105(getUserConfigDir(), "oh-my-openagent");
123474
123479
  }
123475
123480
  function detectNativeEdition() {
123476
- return existsSync84(join104(homedir21(), ".omo", "agent"));
123481
+ return existsSync84(join105(homedir21(), ".omo", "agent"));
123477
123482
  }
123478
123483
  function defaultInteractive() {
123479
123484
  if (process.env["CI"] !== undefined && process.env["CI"] !== "")
@@ -123980,18 +123985,18 @@ tool.schema = z53;
123980
123985
  // packages/omo-opencode/src/shared/ripgrep-cli.ts
123981
123986
  import { spawnSync as spawnSync2 } from "child_process";
123982
123987
  import { existsSync as existsSync87 } from "fs";
123983
- import { dirname as dirname35, join as join106 } from "path";
123988
+ import { dirname as dirname35, join as join107 } from "path";
123984
123989
 
123985
123990
  // packages/omo-opencode/src/tools/grep/downloader.ts
123986
123991
  import { existsSync as existsSync86, readdirSync as readdirSync24 } from "fs";
123987
- import { join as join105 } from "path";
123992
+ import { join as join106 } from "path";
123988
123993
  init_plugin_identity();
123989
123994
  function findFileRecursive(dir, filename) {
123990
123995
  try {
123991
123996
  const entries = readdirSync24(dir, { withFileTypes: true, recursive: true });
123992
123997
  for (const entry of entries) {
123993
123998
  if (entry.isFile() && entry.name === filename) {
123994
- return join105(entry.parentPath ?? dir, entry.name);
123999
+ return join106(entry.parentPath ?? dir, entry.name);
123995
124000
  }
123996
124001
  }
123997
124002
  } catch (error) {
@@ -124015,11 +124020,11 @@ function getPlatformKey() {
124015
124020
  }
124016
124021
  function getInstallDir() {
124017
124022
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
124018
- return join105(homeDir, ".cache", CACHE_DIR_NAME, "bin");
124023
+ return join106(homeDir, ".cache", CACHE_DIR_NAME, "bin");
124019
124024
  }
124020
124025
  function getRgPath() {
124021
124026
  const isWindows = process.platform === "win32";
124022
- return join105(getInstallDir(), isWindows ? "rg.exe" : "rg");
124027
+ return join106(getInstallDir(), isWindows ? "rg.exe" : "rg");
124023
124028
  }
124024
124029
  async function extractTarGz2(archivePath, destDir) {
124025
124030
  const platformKey = getPlatformKey();
@@ -124036,7 +124041,7 @@ async function extractZip2(archivePath, destDir) {
124036
124041
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
124037
124042
  const foundPath = findFileRecursive(destDir, binaryName);
124038
124043
  if (foundPath) {
124039
- const destPath = join105(destDir, binaryName);
124044
+ const destPath = join106(destDir, binaryName);
124040
124045
  if (foundPath !== destPath) {
124041
124046
  const { renameSync } = await import("fs");
124042
124047
  renameSync(foundPath, destPath);
@@ -124057,7 +124062,7 @@ async function downloadAndInstallRipgrep() {
124057
124062
  ensureCacheDir(installDir);
124058
124063
  const filename = `ripgrep-${RG_VERSION}-${config.platform}.${config.extension}`;
124059
124064
  const url = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
124060
- const archivePath = join105(installDir, filename);
124065
+ const archivePath = join106(installDir, filename);
124061
124066
  try {
124062
124067
  await downloadArchive(url, archivePath);
124063
124068
  if (config.extension === "tar.gz") {
@@ -124122,12 +124127,12 @@ function getOpenCodeBundledRg() {
124122
124127
  const isWindows = process.platform === "win32";
124123
124128
  const rgName = isWindows ? "rg.exe" : "rg";
124124
124129
  const candidates = [
124125
- join106(getOpenCodeCacheDir(), "bin", rgName),
124126
- join106(getDataDir(), "opencode", "bin", rgName),
124127
- join106(execDir, rgName),
124128
- join106(execDir, "bin", rgName),
124129
- join106(execDir, "..", "bin", rgName),
124130
- join106(execDir, "..", "libexec", rgName)
124130
+ join107(getOpenCodeCacheDir(), "bin", rgName),
124131
+ join107(getDataDir(), "opencode", "bin", rgName),
124132
+ join107(execDir, rgName),
124133
+ join107(execDir, "bin", rgName),
124134
+ join107(execDir, "..", "bin", rgName),
124135
+ join107(execDir, "..", "libexec", rgName)
124131
124136
  ];
124132
124137
  for (const candidate of candidates) {
124133
124138
  if (existsSync87(candidate)) {
@@ -125304,9 +125309,9 @@ function createSkillTool(options) {
125304
125309
  }
125305
125310
  var skill = createSkillTool({ directory: process.cwd() });
125306
125311
  // packages/omo-opencode/src/tools/session-manager/constants.ts
125307
- import { join as join107 } from "path";
125308
- var TODO_DIR2 = join107(getClaudeConfigDir(), "todos");
125309
- var TRANSCRIPT_DIR2 = join107(getClaudeConfigDir(), "transcripts");
125312
+ import { join as join108 } from "path";
125313
+ var TODO_DIR2 = join108(getClaudeConfigDir(), "todos");
125314
+ var TRANSCRIPT_DIR2 = join108(getClaudeConfigDir(), "transcripts");
125310
125315
  var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
125311
125316
 
125312
125317
  Returns a list of available session IDs with metadata including message count, date range, and agents used.
@@ -125381,7 +125386,7 @@ Has Transcript: Yes (234 entries)`;
125381
125386
  // packages/omo-opencode/src/tools/session-manager/file-storage.ts
125382
125387
  import { existsSync as existsSync88 } from "fs";
125383
125388
  import { readdir as readdir6, readFile as readFile8 } from "fs/promises";
125384
- import { join as join108 } from "path";
125389
+ import { join as join109 } from "path";
125385
125390
 
125386
125391
  // packages/omo-opencode/src/tools/session-manager/directory-filter.ts
125387
125392
  import { normalize as normalize4, parse as parse3, sep as sep3 } from "path";
@@ -125413,13 +125418,13 @@ async function getFileMainSessions(directory) {
125413
125418
  for (const projectDir of projectDirs) {
125414
125419
  if (!projectDir.isDirectory())
125415
125420
  continue;
125416
- const projectPath = join108(SESSION_STORAGE, projectDir.name);
125421
+ const projectPath = join109(SESSION_STORAGE, projectDir.name);
125417
125422
  const sessionFiles = await readdir6(projectPath);
125418
125423
  for (const file of sessionFiles) {
125419
125424
  if (!file.endsWith(".json"))
125420
125425
  continue;
125421
125426
  try {
125422
- const content = await readFile8(join108(projectPath, file), "utf-8");
125427
+ const content = await readFile8(join109(projectPath, file), "utf-8");
125423
125428
  const meta = JSON.parse(content);
125424
125429
  if (meta.parentID)
125425
125430
  continue;
@@ -125448,7 +125453,7 @@ async function getFileAllSessions() {
125448
125453
  for (const entry of entries) {
125449
125454
  if (!entry.isDirectory())
125450
125455
  continue;
125451
- const sessionPath = join108(dir, entry.name);
125456
+ const sessionPath = join109(dir, entry.name);
125452
125457
  const files = await readdir6(sessionPath);
125453
125458
  if (files.some((file) => file.endsWith(".json"))) {
125454
125459
  sessions.push(entry.name);
@@ -125478,7 +125483,7 @@ async function getFileSessionMessages(sessionID) {
125478
125483
  if (!file.endsWith(".json"))
125479
125484
  continue;
125480
125485
  try {
125481
- const content = await readFile8(join108(messageDir, file), "utf-8");
125486
+ const content = await readFile8(join109(messageDir, file), "utf-8");
125482
125487
  const meta = JSON.parse(content);
125483
125488
  const parts = await readParts2(meta.id);
125484
125489
  messages.push({
@@ -125506,7 +125511,7 @@ async function getFileSessionMessages(sessionID) {
125506
125511
  });
125507
125512
  }
125508
125513
  async function readParts2(messageID) {
125509
- const partDir = join108(PART_STORAGE, messageID);
125514
+ const partDir = join109(PART_STORAGE, messageID);
125510
125515
  if (!existsSync88(partDir))
125511
125516
  return [];
125512
125517
  const parts = [];
@@ -125516,7 +125521,7 @@ async function readParts2(messageID) {
125516
125521
  if (!file.endsWith(".json"))
125517
125522
  continue;
125518
125523
  try {
125519
- const content = await readFile8(join108(partDir, file), "utf-8");
125524
+ const content = await readFile8(join109(partDir, file), "utf-8");
125520
125525
  parts.push(JSON.parse(content));
125521
125526
  } catch (error) {
125522
125527
  ignoreFileStorageError(error);
@@ -125537,7 +125542,7 @@ async function getFileSessionTodos(sessionID) {
125537
125542
  const todoFiles = allFiles.filter((file) => file === `${sessionID}.json`);
125538
125543
  for (const file of todoFiles) {
125539
125544
  try {
125540
- const content = await readFile8(join108(TODO_DIR2, file), "utf-8");
125545
+ const content = await readFile8(join109(TODO_DIR2, file), "utf-8");
125541
125546
  const data = JSON.parse(content);
125542
125547
  if (!Array.isArray(data))
125543
125548
  continue;
@@ -125561,7 +125566,7 @@ async function getFileSessionTodos(sessionID) {
125561
125566
  async function getFileSessionTranscript(sessionID) {
125562
125567
  if (!existsSync88(TRANSCRIPT_DIR2))
125563
125568
  return 0;
125564
- const transcriptFile = join108(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
125569
+ const transcriptFile = join109(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
125565
125570
  if (!existsSync88(transcriptFile))
125566
125571
  return 0;
125567
125572
  try {
@@ -127425,22 +127430,22 @@ Other built-in agents, custom agents, and task categories are intentionally not
127425
127430
  Pass \`session_id=<id>\` to continue previous agent with full context. Nested subagent depth is tracked automatically and blocked past the configured limit. Prompts MUST be in English. Use \`background_output\` for async results.`;
127426
127431
  // packages/claude-code-compat-core/src/features/claude-code-agent-loader/loader.ts
127427
127432
  import { existsSync as existsSync93, readdirSync as readdirSync25 } from "fs";
127428
- import { join as join114 } from "path";
127433
+ import { join as join115 } from "path";
127429
127434
 
127430
127435
  // packages/claude-code-compat-core/src/shared/claude-config-dir.ts
127431
127436
  import { homedir as homedir22 } from "os";
127432
- import { join as join109 } from "path";
127437
+ import { join as join110 } from "path";
127433
127438
  function getClaudeConfigDir3() {
127434
127439
  const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
127435
127440
  if (envConfigDir) {
127436
127441
  return envConfigDir;
127437
127442
  }
127438
- return join109(process.env.HOME || process.env.USERPROFILE || homedir22(), ".claude");
127443
+ return join110(process.env.HOME || process.env.USERPROFILE || homedir22(), ".claude");
127439
127444
  }
127440
127445
  // packages/claude-code-compat-core/src/shared/opencode-config-dir.ts
127441
127446
  import { existsSync as existsSync89, realpathSync as realpathSync16 } from "fs";
127442
127447
  import { homedir as homedir23 } from "os";
127443
- import { join as join110, posix as posix10, resolve as resolve29, win32 as win3211 } from "path";
127448
+ import { join as join111, posix as posix10, resolve as resolve29, win32 as win3211 } from "path";
127444
127449
  var TAURI_APP_IDENTIFIER3 = "ai.opencode.desktop";
127445
127450
  var TAURI_APP_IDENTIFIER_DEV3 = "ai.opencode.desktop.dev";
127446
127451
  function isDevBuild3(version) {
@@ -127452,15 +127457,15 @@ function getTauriConfigDir3(identifier) {
127452
127457
  const platform = process.platform;
127453
127458
  switch (platform) {
127454
127459
  case "darwin":
127455
- return join110(homedir23(), "Library", "Application Support", identifier);
127460
+ return join111(homedir23(), "Library", "Application Support", identifier);
127456
127461
  case "win32": {
127457
- const appData = process.env.APPDATA || join110(homedir23(), "AppData", "Roaming");
127462
+ const appData = process.env.APPDATA || join111(homedir23(), "AppData", "Roaming");
127458
127463
  return win3211.join(appData, identifier);
127459
127464
  }
127460
127465
  case "linux":
127461
127466
  default: {
127462
- const xdgConfig = process.env.XDG_CONFIG_HOME || join110(homedir23(), ".config");
127463
- return join110(xdgConfig, identifier);
127467
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join111(homedir23(), ".config");
127468
+ return join111(xdgConfig, identifier);
127464
127469
  }
127465
127470
  }
127466
127471
  }
@@ -127503,8 +127508,8 @@ function getWslLinuxHomeDir3(windowsConfigRoot) {
127503
127508
  function getCliDefaultConfigDir3() {
127504
127509
  const envXdgConfig = process.env.XDG_CONFIG_HOME?.trim();
127505
127510
  const shouldIgnoreWindowsXdg = envXdgConfig !== undefined && envXdgConfig.length > 0 && isWslEnvironment3() && isWindowsUserConfigRoot3(envXdgConfig);
127506
- const xdgConfig = shouldIgnoreWindowsXdg ? posix10.join(getWslLinuxHomeDir3(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join110(homedir23(), ".config");
127507
- const configDir = isWslEnvironment3() ? posix10.join(xdgConfig, "opencode") : join110(xdgConfig, "opencode");
127511
+ const xdgConfig = shouldIgnoreWindowsXdg ? posix10.join(getWslLinuxHomeDir3(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join111(homedir23(), ".config");
127512
+ const configDir = isWslEnvironment3() ? posix10.join(xdgConfig, "opencode") : join111(xdgConfig, "opencode");
127508
127513
  return resolveConfigPath3(configDir);
127509
127514
  }
127510
127515
  function getCliCustomConfigDir3() {
@@ -127537,8 +127542,8 @@ function getOpenCodeConfigDir3(options) {
127537
127542
  const tauriDir = process.platform === "win32" ? win3211.isAbsolute(tauriDirBase) ? win3211.normalize(tauriDirBase) : win3211.resolve(tauriDirBase) : resolveConfigPath3(tauriDirBase);
127538
127543
  if (checkExisting) {
127539
127544
  const legacyDir = getCliConfigDir3();
127540
- const legacyConfig = join110(legacyDir, "opencode.json");
127541
- const legacyConfigC = join110(legacyDir, "opencode.jsonc");
127545
+ const legacyConfig = join111(legacyDir, "opencode.json");
127546
+ const legacyConfigC = join111(legacyDir, "opencode.jsonc");
127542
127547
  if (existsSync89(legacyConfig) || existsSync89(legacyConfigC)) {
127543
127548
  return legacyDir;
127544
127549
  }
@@ -127549,10 +127554,10 @@ function getOpenCodeConfigDir3(options) {
127549
127554
  init_src();
127550
127555
  // packages/claude-code-compat-core/src/shared/resolve-agent-definition-paths.ts
127551
127556
  import { homedir as homedir24 } from "os";
127552
- import { isAbsolute as isAbsolute16, join as join111, resolve as resolve30 } from "path";
127557
+ import { isAbsolute as isAbsolute16, join as join112, resolve as resolve30 } from "path";
127553
127558
  function resolveAgentDefinitionPaths(paths, baseDir, containmentDir) {
127554
127559
  return paths.flatMap((p) => {
127555
- const expanded = p.startsWith("~/") ? join111(homedir24(), p.slice(2)) : p;
127560
+ const expanded = p.startsWith("~/") ? join112(homedir24(), p.slice(2)) : p;
127556
127561
  const resolved = isAbsolute16(expanded) ? expanded : resolve30(baseDir, expanded);
127557
127562
  if (containmentDir !== null && !isWithinProject(resolved, containmentDir)) {
127558
127563
  log4(`agent_definitions path rejected (outside project boundary): ${p} -> ${resolved}`);
@@ -127580,7 +127585,7 @@ var EXCLUDED_DIR_NAMES2 = [
127580
127585
  ];
127581
127586
  var EXCLUDED_DIRS3 = Object.freeze(new Set(EXCLUDED_DIR_NAMES2));
127582
127587
  // packages/claude-code-compat-core/src/shared/opencode-command-dirs.ts
127583
- import { basename as basename15, dirname as dirname38, join as join112 } from "path";
127588
+ import { basename as basename15, dirname as dirname38, join as join113 } from "path";
127584
127589
  function getParentOpencodeConfigDir3(configDir) {
127585
127590
  const parentDir = dirname38(configDir);
127586
127591
  if (basename15(parentDir) !== "profiles") {
@@ -127594,9 +127599,9 @@ function getOpenCodeCommandDirs2(options) {
127594
127599
  ...configDirs.flatMap((configDir) => {
127595
127600
  const parentConfigDir = getParentOpencodeConfigDir3(configDir);
127596
127601
  return [
127597
- join112(configDir, "commands"),
127598
- join112(configDir, "command"),
127599
- ...parentConfigDir ? [join112(parentConfigDir, "commands"), join112(parentConfigDir, "command")] : []
127602
+ join113(configDir, "commands"),
127603
+ join113(configDir, "command"),
127604
+ ...parentConfigDir ? [join113(parentConfigDir, "commands"), join113(parentConfigDir, "command")] : []
127600
127605
  ];
127601
127606
  })
127602
127607
  ]));
@@ -127604,7 +127609,7 @@ function getOpenCodeCommandDirs2(options) {
127604
127609
  // packages/claude-code-compat-core/src/shared/project-discovery-dirs.ts
127605
127610
  import { execFileSync as execFileSync6 } from "child_process";
127606
127611
  import { existsSync as existsSync90, realpathSync as realpathSync17 } from "fs";
127607
- import { dirname as dirname39, join as join113, resolve as resolve31, win32 as win3212 } from "path";
127612
+ import { dirname as dirname39, join as join114, resolve as resolve31, win32 as win3212 } from "path";
127608
127613
  var worktreePathCache3 = new Map;
127609
127614
  function normalizePath6(path) {
127610
127615
  const resolvedPath = process.platform !== "win32" && win3212.isAbsolute(path) ? path : resolve31(path);
@@ -127663,7 +127668,7 @@ function detectWorktreePath4(directory) {
127663
127668
  function findGitMarkerAncestor(directory) {
127664
127669
  let currentDirectory = normalizePath6(directory);
127665
127670
  while (true) {
127666
- if (existsSync90(join113(currentDirectory, ".git"))) {
127671
+ if (existsSync90(join114(currentDirectory, ".git"))) {
127667
127672
  return currentDirectory;
127668
127673
  }
127669
127674
  const parentDirectory = dirname39(currentDirectory);
@@ -127681,7 +127686,7 @@ function findAncestorDirectories3(startDirectory, targetPaths, stopDirectory) {
127681
127686
  const stopDirectoryKey = resolvedStopDirectory ? pathKey4(resolvedStopDirectory) : undefined;
127682
127687
  while (true) {
127683
127688
  for (const targetPath of targetPaths) {
127684
- const candidateDirectory = join113(currentDirectory, ...targetPath);
127689
+ const candidateDirectory = join114(currentDirectory, ...targetPath);
127685
127690
  if (!existsSync90(candidateDirectory)) {
127686
127691
  continue;
127687
127692
  }
@@ -127829,7 +127834,7 @@ function loadAgentsFromDir(agentsDir, scope, anthropicProvider) {
127829
127834
  for (const entry of entries) {
127830
127835
  if (!isMarkdownFile(entry))
127831
127836
  continue;
127832
- const agentPath = join114(agentsDir, entry.name);
127837
+ const agentPath = join115(agentsDir, entry.name);
127833
127838
  const agent = parseMarkdownAgentFile(agentPath, scope, anthropicProvider);
127834
127839
  if (agent) {
127835
127840
  agents.push(agent);
@@ -127838,7 +127843,7 @@ function loadAgentsFromDir(agentsDir, scope, anthropicProvider) {
127838
127843
  return agents;
127839
127844
  }
127840
127845
  function loadUserAgents(anthropicProvider) {
127841
- const userAgentsDir = join114(getClaudeConfigDir3(), "agents");
127846
+ const userAgentsDir = join115(getClaudeConfigDir3(), "agents");
127842
127847
  const agents = loadAgentsFromDir(userAgentsDir, "user", anthropicProvider);
127843
127848
  const result = Object.create(null);
127844
127849
  for (const agent of agents) {
@@ -127847,7 +127852,7 @@ function loadUserAgents(anthropicProvider) {
127847
127852
  return result;
127848
127853
  }
127849
127854
  function loadProjectAgents(directory, anthropicProvider) {
127850
- const projectAgentsDir = join114(directory ?? process.cwd(), ".claude", "agents");
127855
+ const projectAgentsDir = join115(directory ?? process.cwd(), ".claude", "agents");
127851
127856
  const agents = loadAgentsFromDir(projectAgentsDir, "project", anthropicProvider);
127852
127857
  const result = Object.create(null);
127853
127858
  for (const agent of agents) {
@@ -127859,7 +127864,7 @@ function loadOpencodeGlobalAgents() {
127859
127864
  const result = Object.create(null);
127860
127865
  const configDirs = getOpenCodeConfigDirs3({ binary: "opencode" });
127861
127866
  for (const configDir of configDirs) {
127862
- const opencodeAgentsDir = join114(configDir, "agents");
127867
+ const opencodeAgentsDir = join115(configDir, "agents");
127863
127868
  const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
127864
127869
  for (const agent of agents) {
127865
127870
  if (!(agent.name in result)) {
@@ -127870,7 +127875,7 @@ function loadOpencodeGlobalAgents() {
127870
127875
  return result;
127871
127876
  }
127872
127877
  function loadOpencodeProjectAgents(directory) {
127873
- const opencodeProjectDir = join114(directory ?? process.cwd(), ".opencode", "agents");
127878
+ const opencodeProjectDir = join115(directory ?? process.cwd(), ".opencode", "agents");
127874
127879
  const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
127875
127880
  const result = Object.create(null);
127876
127881
  for (const agent of agents) {
@@ -128700,7 +128705,7 @@ import { pathToFileURL } from "url";
128700
128705
  import * as childProcess2 from "child_process";
128701
128706
  import { existsSync as existsSync95, mkdtempSync, readFileSync as readFileSync61, rmSync as rmSync5, unlinkSync as unlinkSync16, writeFileSync as writeFileSync23 } from "fs";
128702
128707
  import { tmpdir as tmpdir7 } from "os";
128703
- import { dirname as dirname41, join as join116 } from "path";
128708
+ import { dirname as dirname41, join as join117 } from "path";
128704
128709
  var SUPPORTED_FORMATS = new Set([
128705
128710
  "image/jpeg",
128706
128711
  "image/png",
@@ -128751,8 +128756,8 @@ function convertImageToJpeg(inputPath, mimeType) {
128751
128756
  if (!existsSync95(inputPath)) {
128752
128757
  throw new Error(`File not found: ${inputPath}`);
128753
128758
  }
128754
- const tempDir = mkdtempSync(join116(tmpdir7(), "opencode-img-"));
128755
- const outputPath = join116(tempDir, "converted.jpg");
128759
+ const tempDir = mkdtempSync(join117(tmpdir7(), "opencode-img-"));
128760
+ const outputPath = join117(tempDir, "converted.jpg");
128756
128761
  log2(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
128757
128762
  try {
128758
128763
  if (process.platform === "darwin") {
@@ -128816,9 +128821,9 @@ function cleanupConvertedImage(filePath) {
128816
128821
  }
128817
128822
  }
128818
128823
  function convertBase64ImageToJpeg(base64Data, mimeType) {
128819
- const tempDir = mkdtempSync(join116(tmpdir7(), "opencode-b64-"));
128824
+ const tempDir = mkdtempSync(join117(tmpdir7(), "opencode-b64-"));
128820
128825
  const inputExt = mimeType.split("/")[1] || "bin";
128821
- const inputPath = join116(tempDir, `input.${inputExt}`);
128826
+ const inputPath = join117(tempDir, `input.${inputExt}`);
128822
128827
  const tempFiles = [inputPath];
128823
128828
  try {
128824
128829
  const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
@@ -132222,6 +132227,10 @@ function resolveCategoryConfig(categoryName, options) {
132222
132227
  return null;
132223
132228
  }
132224
132229
  }
132230
+ if (categoryReq?.requiresAnyModel && availableModels && !hasExplicitUserConfig && !isAnyFallbackModelAvailable(categoryReq.fallbackChain, availableModels)) {
132231
+ log2(`[resolveCategoryConfig] Category ${categoryName} has no available model in its fallback chain`);
132232
+ return null;
132233
+ }
132225
132234
  const defaultPromptAppend = CATEGORY_PROMPT_APPENDS[categoryName] ?? "";
132226
132235
  if (!defaultConfig && !userConfig) {
132227
132236
  return null;
@@ -132412,6 +132421,16 @@ To use this category:
132412
132421
  1. Connect a provider with this model: ${requiredModel}
132413
132422
  2. Or configure an alternative model in your .omo/omo.jsonc for this category
132414
132423
 
132424
+ Available categories: ${allCategoryNames}`);
132425
+ }
132426
+ if (categoryExists && requirement?.requiresAnyModel && userCategories?.[categoryName] === undefined) {
132427
+ const chainModels = [...new Set(requirement.fallbackChain.map((entry) => entry.model))].join(", ");
132428
+ return categoryResolutionError(`Category "${categoryName}" has no available model: none of its fallback-chain models (${chainModels}) is available.
132429
+
132430
+ To use this category:
132431
+ 1. Connect a provider that serves one of: ${chainModels}
132432
+ 2. Or configure a model for this category in your .omo/omo.jsonc
132433
+
132415
132434
  Available categories: ${allCategoryNames}`);
132416
132435
  }
132417
132436
  return categoryResolutionError(`Unknown category: "${categoryName}". Available: ${allCategoryNames}`);
@@ -133089,7 +133108,7 @@ function isExplicitSyncRun(runInBackground) {
133089
133108
  return runInBackground === false || runInBackground === "false";
133090
133109
  }
133091
133110
  // packages/omo-opencode/src/tools/task/task-create.ts
133092
- import { join as join118 } from "path";
133111
+ import { join as join119 } from "path";
133093
133112
 
133094
133113
  // packages/omo-opencode/src/tools/task/types.ts
133095
133114
  import { z as z54 } from "zod";
@@ -133144,7 +133163,7 @@ var TaskDeleteInputSchema = z54.object({
133144
133163
  });
133145
133164
 
133146
133165
  // packages/omo-opencode/src/features/claude-tasks/storage.ts
133147
- import { join as join117, dirname as dirname42, basename as basename18, isAbsolute as isAbsolute17 } from "path";
133166
+ import { join as join118, dirname as dirname42, basename as basename18, isAbsolute as isAbsolute17 } from "path";
133148
133167
  import { existsSync as existsSync96, mkdirSync as mkdirSync21, readFileSync as readFileSync63, writeFileSync as writeFileSync24, renameSync as renameSync8, unlinkSync as unlinkSync17, readdirSync as readdirSync26 } from "fs";
133149
133168
  import { randomUUID as randomUUID9 } from "crypto";
133150
133169
  function ignoreClaudeTaskStorageError(error) {
@@ -133156,11 +133175,11 @@ function getTaskDir(config = {}) {
133156
133175
  const tasksConfig = config.sisyphus?.tasks;
133157
133176
  const storagePath = tasksConfig?.storage_path;
133158
133177
  if (storagePath) {
133159
- return isAbsolute17(storagePath) ? storagePath : join117(process.cwd(), storagePath);
133178
+ return isAbsolute17(storagePath) ? storagePath : join118(process.cwd(), storagePath);
133160
133179
  }
133161
133180
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
133162
133181
  const listId = resolveTaskListId(config);
133163
- return join117(configDir, "tasks", listId);
133182
+ return join118(configDir, "tasks", listId);
133164
133183
  }
133165
133184
  function sanitizePathSegment(value) {
133166
133185
  return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
@@ -133239,7 +133258,7 @@ function generateTaskId() {
133239
133258
  return `T-${randomUUID9()}`;
133240
133259
  }
133241
133260
  async function acquireLock2(dirPath, options = {}) {
133242
- const lockPath = join117(dirPath, ".lock");
133261
+ const lockPath = join118(dirPath, ".lock");
133243
133262
  const lockId = randomUUID9();
133244
133263
  const waitTimeoutMs = options.waitTimeoutMs ?? resolveLockWaitTimeoutMs();
133245
133264
  const baseRetryDelayMs = options.retryDelayMs ?? DEFAULT_LOCK_RETRY_DELAY_MS;
@@ -133490,7 +133509,7 @@ async function handleCreate(args, config, ctx, context) {
133490
133509
  threadID: context.sessionID
133491
133510
  };
133492
133511
  validatedTask = TaskObjectSchema.parse(task);
133493
- writeJsonAtomic(join118(taskDir, `${taskId}.json`), validatedTask);
133512
+ writeJsonAtomic(join119(taskDir, `${taskId}.json`), validatedTask);
133494
133513
  } finally {
133495
133514
  lock.release();
133496
133515
  }
@@ -133512,7 +133531,7 @@ async function handleCreate(args, config, ctx, context) {
133512
133531
  }
133513
133532
  }
133514
133533
  // packages/omo-opencode/src/tools/task/task-get.ts
133515
- import { join as join119 } from "path";
133534
+ import { join as join120 } from "path";
133516
133535
  var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
133517
133536
  function parseTaskId(id) {
133518
133537
  if (!TASK_ID_PATTERN.test(id))
@@ -133537,7 +133556,7 @@ Returns null if the task does not exist or the file is invalid.`,
133537
133556
  return JSON.stringify({ error: "invalid_task_id" });
133538
133557
  }
133539
133558
  const taskDir = getTaskDir(config);
133540
- const taskPath = join119(taskDir, `${taskId}.json`);
133559
+ const taskPath = join120(taskDir, `${taskId}.json`);
133541
133560
  const task = readJsonSafe(taskPath, TaskObjectSchema);
133542
133561
  return JSON.stringify({ task: task ?? null });
133543
133562
  } catch (error) {
@@ -133550,7 +133569,7 @@ Returns null if the task does not exist or the file is invalid.`,
133550
133569
  });
133551
133570
  }
133552
133571
  // packages/omo-opencode/src/tools/task/task-list.ts
133553
- import { join as join120 } from "path";
133572
+ import { join as join121 } from "path";
133554
133573
  import { existsSync as existsSync97, readdirSync as readdirSync27 } from "fs";
133555
133574
  function createTaskList(config) {
133556
133575
  return tool({
@@ -133571,7 +133590,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
133571
133590
  }
133572
133591
  const allTasks = [];
133573
133592
  for (const fileId of files) {
133574
- const task = readJsonSafe(join120(taskDir, `${fileId}.json`), TaskObjectSchema);
133593
+ const task = readJsonSafe(join121(taskDir, `${fileId}.json`), TaskObjectSchema);
133575
133594
  if (task) {
133576
133595
  allTasks.push(task);
133577
133596
  }
@@ -133599,7 +133618,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
133599
133618
  });
133600
133619
  }
133601
133620
  // packages/omo-opencode/src/tools/task/task-update.ts
133602
- import { join as join121 } from "path";
133621
+ import { join as join122 } from "path";
133603
133622
  var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
133604
133623
  function parseTaskId2(id) {
133605
133624
  if (!TASK_ID_PATTERN2.test(id))
@@ -133686,7 +133705,7 @@ async function handleUpdate(args, config, ctx, context) {
133686
133705
  }
133687
133706
  let updatedTask = null;
133688
133707
  try {
133689
- updatedTask = applyTaskUpdate(join121(taskDir, `${taskId}.json`), validatedArgs);
133708
+ updatedTask = applyTaskUpdate(join122(taskDir, `${taskId}.json`), validatedArgs);
133690
133709
  } finally {
133691
133710
  lock.release();
133692
133711
  }
@@ -135560,7 +135579,7 @@ function createHooks(args) {
135560
135579
  };
135561
135580
  }
135562
135581
  // packages/omo-opencode/src/features/background-agent/manager.ts
135563
- import { join as join123 } from "path";
135582
+ import { join as join124 } from "path";
135564
135583
 
135565
135584
  // packages/omo-opencode/src/features/background-agent/abort-with-timeout.ts
135566
135585
  function getAbortResponseError(response) {
@@ -135848,7 +135867,7 @@ function writeBackgroundTaskMarker(input) {
135848
135867
 
135849
135868
  // packages/omo-opencode/src/features/background-agent/compaction-aware-message-resolver.ts
135850
135869
  import { readdirSync as readdirSync28, readFileSync as readFileSync64 } from "fs";
135851
- import { join as join122 } from "path";
135870
+ import { join as join123 } from "path";
135852
135871
  function hasFullAgentAndModel(message) {
135853
135872
  return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
135854
135873
  }
@@ -135932,7 +135951,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
135932
135951
  const messages = [];
135933
135952
  for (const file of files) {
135934
135953
  try {
135935
- const content = readFileSync64(join122(messageDir, file), "utf-8");
135954
+ const content = readFileSync64(join123(messageDir, file), "utf-8");
135936
135955
  const parsed = JSON.parse(content);
135937
135956
  if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
135938
135957
  continue;
@@ -140730,7 +140749,7 @@ The task was re-queued on a fallback model after a retryable failure.
140730
140749
  parentSessionID: task.parentSessionId
140731
140750
  });
140732
140751
  }
140733
- const messageDir = join123(MESSAGE_STORAGE, task.parentSessionId);
140752
+ const messageDir = join124(MESSAGE_STORAGE, task.parentSessionId);
140734
140753
  const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionId) : null;
140735
140754
  agent = currentMessage?.agent ?? task.parentAgent;
140736
140755
  model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
@@ -142417,12 +142436,12 @@ import {
142417
142436
  unlinkSync as unlinkSync18,
142418
142437
  writeFileSync as writeFileSync26
142419
142438
  } from "fs";
142420
- import { basename as basename19, dirname as dirname43, join as join126 } from "path";
142439
+ import { basename as basename19, dirname as dirname43, join as join127 } from "path";
142421
142440
 
142422
142441
  // packages/mcp-client-core/src/config-dir.ts
142423
142442
  import { existsSync as existsSync98, realpathSync as realpathSync18 } from "fs";
142424
142443
  import { homedir as homedir25 } from "os";
142425
- import { join as join124, resolve as resolve32 } from "path";
142444
+ import { join as join125, resolve as resolve32 } from "path";
142426
142445
  function resolveConfigPath4(pathValue) {
142427
142446
  const resolvedPath = resolve32(pathValue);
142428
142447
  if (!existsSync98(resolvedPath))
@@ -142440,13 +142459,13 @@ function getOpenCodeCliConfigDir(env = process.env) {
142440
142459
  if (customConfigDir) {
142441
142460
  return resolveConfigPath4(customConfigDir);
142442
142461
  }
142443
- const xdgConfigDir = env["XDG_CONFIG_HOME"]?.trim() || join124(homedir25(), ".config");
142444
- return resolveConfigPath4(join124(xdgConfigDir, "opencode"));
142462
+ const xdgConfigDir = env["XDG_CONFIG_HOME"]?.trim() || join125(homedir25(), ".config");
142463
+ return resolveConfigPath4(join125(xdgConfigDir, "opencode"));
142445
142464
  }
142446
142465
 
142447
142466
  // packages/mcp-client-core/src/mcp-oauth/storage-index.ts
142448
142467
  import { chmodSync as chmodSync3, existsSync as existsSync99, readFileSync as readFileSync65, renameSync as renameSync9, writeFileSync as writeFileSync25 } from "fs";
142449
- import { join as join125 } from "path";
142468
+ import { join as join126 } from "path";
142450
142469
  var INDEX_FILE_NAME = "index.json";
142451
142470
  function isTokenIndex(value) {
142452
142471
  if (typeof value !== "object" || value === null || Array.isArray(value))
@@ -142454,7 +142473,7 @@ function isTokenIndex(value) {
142454
142473
  return Object.values(value).every((entry) => typeof entry === "string");
142455
142474
  }
142456
142475
  function getIndexPath(storageDir) {
142457
- return join125(storageDir, INDEX_FILE_NAME);
142476
+ return join126(storageDir, INDEX_FILE_NAME);
142458
142477
  }
142459
142478
  function readTokenIndex(storageDir) {
142460
142479
  const indexPath = getIndexPath(storageDir);
@@ -142491,16 +142510,16 @@ function saveTokenIndexEntry(storageDir, hash, key) {
142491
142510
  var STORAGE_DIR_NAME = "mcp-oauth";
142492
142511
  var LEGACY_STORAGE_FILE_NAME = "mcp-oauth.json";
142493
142512
  function getMcpOauthStorageDir() {
142494
- return join126(getOpenCodeCliConfigDir(), STORAGE_DIR_NAME);
142513
+ return join127(getOpenCodeCliConfigDir(), STORAGE_DIR_NAME);
142495
142514
  }
142496
142515
  function getMcpOauthServerHash(serverHost, resource) {
142497
142516
  return createHash4("sha256").update(buildKey(serverHost, resource)).digest("hex").slice(0, 32);
142498
142517
  }
142499
142518
  function getMcpOauthStoragePath(serverHost, resource) {
142500
- return join126(getMcpOauthStorageDir(), `${getMcpOauthServerHash(serverHost, resource)}.json`);
142519
+ return join127(getMcpOauthStorageDir(), `${getMcpOauthServerHash(serverHost, resource)}.json`);
142501
142520
  }
142502
142521
  function getLegacyStoragePath() {
142503
- return join126(getOpenCodeCliConfigDir(), LEGACY_STORAGE_FILE_NAME);
142522
+ return join127(getOpenCodeCliConfigDir(), LEGACY_STORAGE_FILE_NAME);
142504
142523
  }
142505
142524
  function normalizeHost(serverHost) {
142506
142525
  let host = serverHost.trim();
@@ -148084,9 +148103,9 @@ import { dirname as dirname44 } from "path";
148084
148103
  import { createHash as createHash6 } from "crypto";
148085
148104
  import { realpathSync as realpathSync19 } from "fs";
148086
148105
  import { homedir as homedir26 } from "os";
148087
- import { join as join127, resolve as resolve33 } from "path";
148106
+ import { join as join128, resolve as resolve33 } from "path";
148088
148107
  function mirrorStorageDir() {
148089
- return join127(process.env.XDG_DATA_HOME ?? join127(homedir26(), ".local", "share"), "opencode", "storage", "oh-my-openagent", MIRROR_DIR_NAME);
148108
+ return join128(process.env.XDG_DATA_HOME ?? join128(homedir26(), ".local", "share"), "opencode", "storage", "oh-my-openagent", MIRROR_DIR_NAME);
148090
148109
  }
148091
148110
  function canonicalProjectDir(projectDir) {
148092
148111
  try {
@@ -148100,7 +148119,7 @@ function canonicalProjectDir(projectDir) {
148100
148119
  }
148101
148120
  function mirrorFilePath(projectDir) {
148102
148121
  const projectHash = createHash6("sha1").update(canonicalProjectDir(projectDir)).digest("hex").slice(0, 16);
148103
- return join127(mirrorStorageDir(), `${projectHash}.json`);
148122
+ return join128(mirrorStorageDir(), `${projectHash}.json`);
148104
148123
  }
148105
148124
 
148106
148125
  // packages/omo-opencode/src/features/tui-sidebar/snapshot-schema.ts
@@ -148159,7 +148178,7 @@ function writeMirror(projectDir, snapshot) {
148159
148178
 
148160
148179
  // packages/omo-opencode/src/features/tui-sidebar/loop-reader.ts
148161
148180
  import { readdirSync as readdirSync30, readFileSync as readFileSync68, statSync as statSync14 } from "fs";
148162
- import { join as join128 } from "path";
148181
+ import { join as join129 } from "path";
148163
148182
  import { z as z59 } from "zod";
148164
148183
  var CriterionSchema = z59.object({
148165
148184
  status: z59.string()
@@ -148189,7 +148208,7 @@ function enumerateCandidates(projectDir) {
148189
148208
  return [...currentLoopCandidates(projectDir), legacyLoopCandidate(projectDir)].filter((candidate) => candidate !== null);
148190
148209
  }
148191
148210
  function currentLoopCandidates(projectDir) {
148192
- const loopRoot = join128(projectDir, ".omo", "ulw-loop");
148211
+ const loopRoot = join129(projectDir, ".omo", "ulw-loop");
148193
148212
  let entries;
148194
148213
  try {
148195
148214
  entries = readdirSync30(loopRoot, { withFileTypes: true });
@@ -148199,10 +148218,10 @@ function currentLoopCandidates(projectDir) {
148199
148218
  }
148200
148219
  throw error;
148201
148220
  }
148202
- return entries.filter((entry) => entry.isDirectory()).map((entry) => statCandidate(join128(loopRoot, entry.name, "goals.json"))).filter((candidate) => candidate !== null);
148221
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => statCandidate(join129(loopRoot, entry.name, "goals.json"))).filter((candidate) => candidate !== null);
148203
148222
  }
148204
148223
  function legacyLoopCandidate(projectDir) {
148205
- return statCandidate(join128(projectDir, ".omo", "loop", "goals.json"));
148224
+ return statCandidate(join129(projectDir, ".omo", "loop", "goals.json"));
148206
148225
  }
148207
148226
  function statCandidate(path) {
148208
148227
  try {
@@ -150997,25 +151016,25 @@ import {
150997
151016
  // packages/openclaw-core/src/reply-listener-paths.ts
150998
151017
  import { existsSync as existsSync101, mkdirSync as mkdirSync24 } from "fs";
150999
151018
  import { homedir as homedir27 } from "os";
151000
- import { join as join129 } from "path";
151019
+ import { join as join130 } from "path";
151001
151020
  var REPLY_LISTENER_SECURE_FILE_MODE = 384;
151002
151021
  function resolveReplyListenerHomeDir() {
151003
151022
  return process.env.HOME ?? process.env.USERPROFILE ?? homedir27();
151004
151023
  }
151005
151024
  function getReplyListenerStateDir() {
151006
- return join129(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
151025
+ return join130(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
151007
151026
  }
151008
151027
  function getReplyListenerPidFilePath() {
151009
- return join129(getReplyListenerStateDir(), "reply-listener.pid");
151028
+ return join130(getReplyListenerStateDir(), "reply-listener.pid");
151010
151029
  }
151011
151030
  function getReplyListenerStateFilePath() {
151012
- return join129(getReplyListenerStateDir(), "reply-listener-state.json");
151031
+ return join130(getReplyListenerStateDir(), "reply-listener-state.json");
151013
151032
  }
151014
151033
  function getReplyListenerConfigFilePath() {
151015
- return join129(getReplyListenerStateDir(), "reply-listener-config.json");
151034
+ return join130(getReplyListenerStateDir(), "reply-listener-config.json");
151016
151035
  }
151017
151036
  function getReplyListenerLogFilePath() {
151018
- return join129(getReplyListenerStateDir(), "reply-listener.log");
151037
+ return join130(getReplyListenerStateDir(), "reply-listener.log");
151019
151038
  }
151020
151039
  function ensureReplyListenerStateDir() {
151021
151040
  const stateDir = getReplyListenerStateDir();
@@ -151075,7 +151094,7 @@ import { constants as constants24, closeSync as closeSync5, openSync as openSync
151075
151094
 
151076
151095
  // packages/openclaw-core/src/session-registry-paths.ts
151077
151096
  init_src();
151078
- import { join as join130 } from "path";
151097
+ import { join as join131 } from "path";
151079
151098
  var SECURE_FILE_MODE = 384;
151080
151099
  var MAX_AGE_MS = 24 * 60 * 60 * 1000;
151081
151100
  var LOCK_TIMEOUT_MS = 2000;
@@ -151086,16 +151105,16 @@ var cachedRegistryPaths = null;
151086
151105
  function resolveRegistryPaths() {
151087
151106
  if (cachedRegistryPaths !== null)
151088
151107
  return cachedRegistryPaths;
151089
- const openClawStorageDir = join130(getOpenCodeStorageDir2(), "openclaw");
151108
+ const openClawStorageDir = join131(getOpenCodeStorageDir2(), "openclaw");
151090
151109
  cachedRegistryPaths = {
151091
151110
  openClawStorageDir,
151092
- registryPath: join130(openClawStorageDir, "reply-session-registry.jsonl"),
151093
- registryLockPath: join130(openClawStorageDir, "reply-session-registry.lock")
151111
+ registryPath: join131(openClawStorageDir, "reply-session-registry.jsonl"),
151112
+ registryLockPath: join131(openClawStorageDir, "reply-session-registry.lock")
151094
151113
  };
151095
151114
  return cachedRegistryPaths;
151096
151115
  }
151097
151116
  function getOpenCodeStorageDir2() {
151098
- return join130(resolveXdgDataDir("opencode"), "opencode", "storage");
151117
+ return join131(resolveXdgDataDir("opencode"), "opencode", "storage");
151099
151118
  }
151100
151119
  function getRegistryPath() {
151101
151120
  return resolveRegistryPaths().registryPath;
@@ -151515,7 +151534,7 @@ function getReplyListenerRuntimeSignature(config) {
151515
151534
  // packages/openclaw-core/src/reply-listener-poll-loop.ts
151516
151535
  var PRUNE_INTERVAL_MS = 60 * 60 * 1000;
151517
151536
  // packages/openclaw-core/src/reply-listener-start.ts
151518
- import { dirname as dirname46, join as join132 } from "path";
151537
+ import { dirname as dirname46, join as join133 } from "path";
151519
151538
  import { fileURLToPath as fileURLToPath7 } from "url";
151520
151539
 
151521
151540
  // packages/openclaw-core/src/reply-listener-spawn.ts
@@ -151524,7 +151543,7 @@ init_runtime();
151524
151543
  // packages/openclaw-core/src/reply-listener-process.ts
151525
151544
  init_runtime();
151526
151545
  import { readFileSync as readFileSync72 } from "fs";
151527
- import { join as join131 } from "path";
151546
+ import { join as join132 } from "path";
151528
151547
  var REPLY_LISTENER_DAEMON_IDENTITY_MARKER = "--openclaw-reply-listener-daemon";
151529
151548
  var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
151530
151549
  "PATH",
@@ -151560,7 +151579,7 @@ var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
151560
151579
  ];
151561
151580
  async function windowsProcessCommandLineHasMarker(pid, deps) {
151562
151581
  const systemRoot = process.env.SystemRoot ?? process.env.SYSTEMROOT ?? "C:\\Windows";
151563
- const powershell = join131(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
151582
+ const powershell = join132(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
151564
151583
  const processInfo = deps.spawn([
151565
151584
  powershell,
151566
151585
  "-NoProfile",
@@ -151777,7 +151796,7 @@ function createStartFailureResult(message, state) {
151777
151796
  }
151778
151797
  function resolveReplyListenerDaemonScript(currentFileUrl) {
151779
151798
  const currentFilePath = fileURLToPath7(currentFileUrl);
151780
- return currentFilePath.endsWith(".ts") ? join132(dirname46(currentFilePath), "daemon.ts") : join132(dirname46(currentFilePath), "daemon.js");
151799
+ return currentFilePath.endsWith(".ts") ? join133(dirname46(currentFilePath), "daemon.ts") : join133(dirname46(currentFilePath), "daemon.js");
151781
151800
  }
151782
151801
  async function startReplyListener(config) {
151783
151802
  const normalizedConfig = getNormalizedReplyListenerConfig(config);
@@ -152201,12 +152220,12 @@ async function createRuntimeSkillSourceServer(options, runtimeEnv = runtime6) {
152201
152220
  }
152202
152221
  // packages/claude-code-compat-core/src/features/claude-code-mcp-loader/loader.ts
152203
152222
  import { existsSync as existsSync106, readFileSync as readFileSync73 } from "fs";
152204
- import { join as join133 } from "path";
152223
+ import { join as join134 } from "path";
152205
152224
  import { homedir as homedir28 } from "os";
152206
152225
  function resolveMcpLoaderContext(options = {}) {
152207
152226
  const cwd = options.cwd ?? process.cwd();
152208
152227
  const homeDir = options.homeDir ?? getHomeDir();
152209
- const claudeConfigDir = options.claudeConfigDir ?? (options.homeDir === undefined ? getClaudeConfigDir3() : join133(homeDir, ".claude"));
152228
+ const claudeConfigDir = options.claudeConfigDir ?? (options.homeDir === undefined ? getClaudeConfigDir3() : join134(homeDir, ".claude"));
152210
152229
  return { cwd, homeDir, claudeConfigDir };
152211
152230
  }
152212
152231
  var mcpLoaderInternals = {
@@ -152215,10 +152234,10 @@ var mcpLoaderInternals = {
152215
152234
  function getMcpConfigPaths(context) {
152216
152235
  const { claudeConfigDir, homeDir, cwd } = context;
152217
152236
  return [
152218
- { path: join133(homeDir, ".claude.json"), scope: "user" },
152219
- { path: join133(claudeConfigDir, ".mcp.json"), scope: "user" },
152220
- { path: join133(cwd, ".mcp.json"), scope: "project" },
152221
- { path: join133(cwd, ".claude", ".mcp.json"), scope: "local" }
152237
+ { path: join134(homeDir, ".claude.json"), scope: "user" },
152238
+ { path: join134(claudeConfigDir, ".mcp.json"), scope: "user" },
152239
+ { path: join134(cwd, ".mcp.json"), scope: "project" },
152240
+ { path: join134(cwd, ".claude", ".mcp.json"), scope: "local" }
152222
152241
  ];
152223
152242
  }
152224
152243
  function getHomeDir() {
@@ -161746,13 +161765,13 @@ createHephaestusAgent.mode = MODE9;
161746
161765
  // packages/omo-opencode/src/agents/builtin-agents/resolve-file-uri.ts
161747
161766
  import { existsSync as existsSync107, readFileSync as readFileSync74 } from "fs";
161748
161767
  import { homedir as homedir29 } from "os";
161749
- import { isAbsolute as isAbsolute18, join as join134, resolve as resolve34 } from "path";
161768
+ import { isAbsolute as isAbsolute18, join as join135, resolve as resolve34 } from "path";
161750
161769
  init_logger2();
161751
161770
  var ALLOWED_HOME_SUBDIRS = [
161752
- join134(homedir29(), ".config", "opencode"),
161753
- join134(homedir29(), ".config", "oh-my-openagent"),
161754
- join134(homedir29(), ".omo"),
161755
- join134(homedir29(), ".opencode")
161771
+ join135(homedir29(), ".config", "opencode"),
161772
+ join135(homedir29(), ".config", "oh-my-openagent"),
161773
+ join135(homedir29(), ".omo"),
161774
+ join135(homedir29(), ".opencode")
161756
161775
  ];
161757
161776
  function isWithinAllowedPaths(filePath, projectRoot) {
161758
161777
  if (isWithinProject(filePath, projectRoot))
@@ -164510,7 +164529,7 @@ async function applyAgentConfig(params) {
164510
164529
  }
164511
164530
  // packages/claude-code-compat-core/src/features/claude-code-command-loader/loader.ts
164512
164531
  import { promises as fs21 } from "fs";
164513
- import { join as join135, basename as basename21 } from "path";
164532
+ import { join as join136, basename as basename21 } from "path";
164514
164533
 
164515
164534
  // packages/claude-code-compat-core/src/features/claude-code-command-loader/loader-cache.ts
164516
164535
  var commandLoaderCache = new Map;
@@ -164558,7 +164577,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
164558
164577
  continue;
164559
164578
  if (entry.name.startsWith("."))
164560
164579
  continue;
164561
- const subDirPath = join135(commandsDir, entry.name);
164580
+ const subDirPath = join136(commandsDir, entry.name);
164562
164581
  const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
164563
164582
  const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
164564
164583
  commands.push(...subCommands);
@@ -164566,7 +164585,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
164566
164585
  }
164567
164586
  if (!isMarkdownFile(entry))
164568
164587
  continue;
164569
- const commandPath = join135(commandsDir, entry.name);
164588
+ const commandPath = join136(commandsDir, entry.name);
164570
164589
  const baseCommandName = basename21(entry.name, ".md");
164571
164590
  const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
164572
164591
  try {
@@ -164629,12 +164648,12 @@ function commandsToRecord(commands) {
164629
164648
  return result;
164630
164649
  }
164631
164650
  async function loadUserCommands() {
164632
- const userCommandsDir = join135(getClaudeConfigDir3(), "commands");
164651
+ const userCommandsDir = join136(getClaudeConfigDir3(), "commands");
164633
164652
  const commands = await loadCommandsFromDir(userCommandsDir, "user");
164634
164653
  return commandsToRecord(commands);
164635
164654
  }
164636
164655
  async function loadProjectCommands(directory) {
164637
- const projectCommandsDir = join135(directory ?? process.cwd(), ".claude", "commands");
164656
+ const projectCommandsDir = join136(directory ?? process.cwd(), ".claude", "commands");
164638
164657
  const commands = await loadCommandsFromDir(projectCommandsDir, "project");
164639
164658
  return commandsToRecord(commands);
164640
164659
  }
@@ -172576,7 +172595,7 @@ function createChatHeadersHandler(args) {
172576
172595
  }
172577
172596
 
172578
172597
  // packages/omo-opencode/src/plugin/ultrawork-db-model-override.ts
172579
- import { join as join136 } from "path";
172598
+ import { join as join137 } from "path";
172580
172599
  import { existsSync as existsSync109 } from "fs";
172581
172600
  async function importBunSqlite() {
172582
172601
  if (typeof globalThis.Bun === "undefined") {
@@ -172593,7 +172612,7 @@ async function importBunSqlite() {
172593
172612
  }
172594
172613
  }
172595
172614
  function getDbPath() {
172596
- return join136(getDataDir(), "opencode", "opencode.db");
172615
+ return join137(getDataDir(), "opencode", "opencode.db");
172597
172616
  }
172598
172617
  var MAX_MICROTASK_RETRIES = 10;
172599
172618
  function logCaughtDbError(message, metadata, error) {
@@ -175528,7 +175547,7 @@ function processKillErrorMeansAlive(error) {
175528
175547
  // packages/utils/src/process-sweep/lsp-daemon-family.ts
175529
175548
  import { readFileSync as readFileSync76, readdirSync as readdirSync31 } from "fs";
175530
175549
  import { homedir as homedir30 } from "os";
175531
- import { basename as basename23, join as join137, resolve as resolve37 } from "path";
175550
+ import { basename as basename23, join as join138, resolve as resolve37 } from "path";
175532
175551
 
175533
175552
  // packages/utils/src/process-sweep/lsp-daemon-owner-attestation.ts
175534
175553
  import { readFile as readFile13 } from "fs/promises";
@@ -175645,7 +175664,7 @@ function resolveLspDaemonBaseDir(options = {}) {
175645
175664
  if (override !== undefined && override.trim().length > 0)
175646
175665
  return resolve37(override);
175647
175666
  const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir30();
175648
- return join137(homeDir, ".omo", "lsp-daemon");
175667
+ return join138(homeDir, ".omo", "lsp-daemon");
175649
175668
  }
175650
175669
  var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
175651
175670
  function listLspDaemonVersionDirs(baseDir) {
@@ -175664,12 +175683,12 @@ function listLspDaemonVersionDirs(baseDir) {
175664
175683
  const version = VERSION_ENTRY_PATTERN.exec(entry.name)?.[1];
175665
175684
  if (version === undefined)
175666
175685
  continue;
175667
- versions.push({ dir: join137(baseDir, entry.name), version });
175686
+ versions.push({ dir: join138(baseDir, entry.name), version });
175668
175687
  }
175669
175688
  return versions.sort((left, right) => left.version.localeCompare(right.version));
175670
175689
  }
175671
175690
  function readLspDaemonOwnerTarget(versionDir) {
175672
- const ownerPath = join137(versionDir, "daemon.owner");
175691
+ const ownerPath = join138(versionDir, "daemon.owner");
175673
175692
  let raw;
175674
175693
  try {
175675
175694
  raw = requireOwnerText(ownerPath);
@@ -175680,7 +175699,7 @@ function readLspDaemonOwnerTarget(versionDir) {
175680
175699
  const owner = parseLspDaemonOwner(JSON.parse(raw));
175681
175700
  if (owner === null)
175682
175701
  return null;
175683
- return { authPath: join137(versionDir, "daemon.auth"), owner, ownerPath, pid: owner.pid };
175702
+ return { authPath: join138(versionDir, "daemon.auth"), owner, ownerPath, pid: owner.pid };
175684
175703
  } catch {
175685
175704
  return null;
175686
175705
  }
@@ -175755,33 +175774,33 @@ function matchLspDaemonProxyCommand(command, roots, platform) {
175755
175774
  // packages/utils/src/process-sweep/roots.ts
175756
175775
  import { existsSync as existsSync110, readdirSync as readdirSync32, realpathSync as realpathSync20 } from "fs";
175757
175776
  import { homedir as homedir31 } from "os";
175758
- import { join as join138, resolve as resolve38 } from "path";
175777
+ import { join as join139, resolve as resolve38 } from "path";
175759
175778
  function discoverOmoOwnedRoots(options = {}) {
175760
175779
  const env = options.env ?? process.env;
175761
175780
  const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir31();
175762
175781
  const roots = new Set;
175763
- addRoot(roots, join138(homeDir, ".claude", "omo"));
175782
+ addRoot(roots, join139(homeDir, ".claude", "omo"));
175764
175783
  addRoot(roots, options.pluginRoot);
175765
175784
  for (const root of options.extraRoots ?? [])
175766
175785
  addRoot(roots, root);
175767
- for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join138(homeDir, ".codex"))) {
175786
+ for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join139(homeDir, ".codex"))) {
175768
175787
  addRoot(roots, root);
175769
175788
  }
175770
175789
  return [...roots];
175771
175790
  }
175772
175791
  function readCodexPluginCacheRoots(codexHome) {
175773
- const cacheRoot = join138(codexHome, "plugins", "cache");
175792
+ const cacheRoot = join139(codexHome, "plugins", "cache");
175774
175793
  if (!existsSync110(cacheRoot))
175775
175794
  return [];
175776
175795
  const roots = [];
175777
175796
  for (const publisher of safeReadDir(cacheRoot)) {
175778
175797
  if (!OMO_CODEX_PLUGIN_CACHE_PUBLISHERS.has(publisher))
175779
175798
  continue;
175780
- const omoRoot = join138(cacheRoot, publisher, "omo");
175799
+ const omoRoot = join139(cacheRoot, publisher, "omo");
175781
175800
  if (!existsSync110(omoRoot))
175782
175801
  continue;
175783
175802
  for (const version of safeReadDir(omoRoot))
175784
- roots.push(join138(omoRoot, version));
175803
+ roots.push(join139(omoRoot, version));
175785
175804
  }
175786
175805
  return roots;
175787
175806
  }
@@ -175819,7 +175838,7 @@ function isNonFatalFsError(error) {
175819
175838
  var OMO_CODEX_PLUGIN_CACHE_PUBLISHERS = new Set(["sisyphuslabs"]);
175820
175839
 
175821
175840
  // packages/utils/src/process-sweep/sweeper.ts
175822
- import { join as join139 } from "path";
175841
+ import { join as join140 } from "path";
175823
175842
 
175824
175843
  // packages/utils/src/process-sweep/family-sweeper.ts
175825
175844
  import { existsSync as existsSync111, mkdirSync as mkdirSync26, statSync as statSync17, utimesSync, writeFileSync as writeFileSync29 } from "fs";
@@ -175936,7 +175955,7 @@ function delay6(ms) {
175936
175955
  // packages/utils/src/process-sweep/sweeper.ts
175937
175956
  var LSP_PROXY_SWEEP_STAMP_FILE = "lsp-proxy-sweep.stamp";
175938
175957
  async function sweepOrphanedLspDaemonProxies(options = {}) {
175939
- const stampFile = join139(resolveLspDaemonBaseDir(options), LSP_PROXY_SWEEP_STAMP_FILE);
175958
+ const stampFile = join140(resolveLspDaemonBaseDir(options), LSP_PROXY_SWEEP_STAMP_FILE);
175940
175959
  const ownedRoots = options.ownedRoots ?? discoverOmoOwnedRoots(options);
175941
175960
  const result = await runProcessFamilySweep({
175942
175961
  familyLabel: "lsp-daemon proxy sweep",
@@ -175955,7 +175974,7 @@ async function sweepOrphanedLspDaemonProxies(options = {}) {
175955
175974
  var LSP_DAEMON_SWEEP_STAMP_FILE = "lsp-daemon-sweep.stamp";
175956
175975
  async function sweepStaleLspDaemonVersions(options = {}) {
175957
175976
  const baseDir = resolveLspDaemonBaseDir(options);
175958
- const stampFile = join139(baseDir, LSP_DAEMON_SWEEP_STAMP_FILE);
175977
+ const stampFile = join140(baseDir, LSP_DAEMON_SWEEP_STAMP_FILE);
175959
175978
  const currentVersion = resolveCurrentLspDaemonVersion(options);
175960
175979
  const dryRun = options.dryRun === true;
175961
175980
  if (currentVersion === undefined) {
@@ -176028,15 +176047,15 @@ function defaultPluginRoot() {
176028
176047
  init_atomic_write();
176029
176048
  init_xdg_data_dir();
176030
176049
  import { existsSync as existsSync112, mkdirSync as mkdirSync28, readFileSync as readFileSync77 } from "fs";
176031
- import { basename as basename24, join as join141 } from "path";
176050
+ import { basename as basename24, join as join142 } from "path";
176032
176051
 
176033
176052
  // packages/telemetry-core/src/day-claim.ts
176034
176053
  import { closeSync as closeSync6, mkdirSync as mkdirSync27, openSync as openSync6, readdirSync as readdirSync33, rmSync as rmSync6 } from "fs";
176035
- import { join as join140 } from "path";
176054
+ import { join as join141 } from "path";
176036
176055
  var CLAIM_PREFIX = "daily-active.";
176037
176056
  var CLAIM_SUFFIX = ".claim";
176038
176057
  function getTelemetryDayClaimFilePath(stateDir, dayUTC) {
176039
- return join140(stateDir, `${CLAIM_PREFIX}${dayUTC}${CLAIM_SUFFIX}`);
176058
+ return join141(stateDir, `${CLAIM_PREFIX}${dayUTC}${CLAIM_SUFFIX}`);
176040
176059
  }
176041
176060
  function claimUtcDay(stateDir, dayUTC) {
176042
176061
  try {
@@ -176062,7 +176081,7 @@ function pruneSupersededClaims(stateDir, dayUTC) {
176062
176081
  if (!entry.startsWith(CLAIM_PREFIX) || !entry.endsWith(CLAIM_SUFFIX))
176063
176082
  continue;
176064
176083
  try {
176065
- rmSync6(join140(stateDir, entry), { force: true });
176084
+ rmSync6(join141(stateDir, entry), { force: true });
176066
176085
  } catch {}
176067
176086
  }
176068
176087
  }
@@ -176075,14 +176094,14 @@ function resolveTelemetryStateDir(product, options = {}) {
176075
176094
  env: options.env,
176076
176095
  osProvider: options.osProvider
176077
176096
  });
176078
- const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join141(options.env.XDG_DATA_HOME, product.cacheDirName);
176097
+ const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join142(options.env.XDG_DATA_HOME, product.cacheDirName);
176079
176098
  if (dataDir === xdgStateDir || xdgStateDir === undefined && basename24(dataDir) === product.cacheDirName) {
176080
176099
  return dataDir;
176081
176100
  }
176082
- return join141(dataDir, product.cacheDirName);
176101
+ return join142(dataDir, product.cacheDirName);
176083
176102
  }
176084
176103
  function getTelemetryActivityStateFilePath(stateDir) {
176085
- return join141(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
176104
+ return join142(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
176086
176105
  }
176087
176106
  function getDailyActiveCaptureState(input) {
176088
176107
  const dayUTC = getUtcDayString(input.now ?? new Date);