oh-my-opencode 5.1.51 → 5.1.54

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 (890) hide show
  1. package/dist/agents/atlas/agent.d.ts +5 -5
  2. package/dist/agents/dynamic-agent-core-sections.d.ts +0 -1
  3. package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
  4. package/dist/agents/gpt-apply-patch-guard.d.ts +0 -1
  5. package/dist/agents/hephaestus/agent.d.ts +3 -7
  6. package/dist/agents/hephaestus/model-support.d.ts +6 -0
  7. package/dist/agents/metis.d.ts +0 -15
  8. package/dist/agents/native-model-prompt.d.ts +9 -0
  9. package/dist/agents/native-prompt-frame.d.ts +20 -0
  10. package/dist/agents/native-tool-snippet.d.ts +6 -0
  11. package/dist/agents/sisyphus/default.d.ts +0 -1
  12. package/dist/agents/sisyphus-agent-factory.d.ts +2 -11
  13. package/dist/agents/sisyphus-junior/agent.d.ts +2 -20
  14. package/dist/agents/sisyphus-junior/index.d.ts +1 -11
  15. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +6 -0
  16. package/dist/agents/types.d.ts +2 -2
  17. package/dist/cli/index.js +1160 -391
  18. package/dist/cli/service-auth/credential-lock.d.ts +11 -0
  19. package/dist/cli/service-auth/credential-owner.d.ts +10 -0
  20. package/dist/cli/service-auth/index.d.ts +3 -1
  21. package/dist/cli/service-auth/keystore.d.ts +8 -1
  22. package/dist/cli/service-auth/owned-refresh.d.ts +21 -0
  23. package/dist/cli/service-auth/protocol-v2.d.ts +27 -0
  24. package/dist/cli/service-auth/protocol.d.ts +26 -2
  25. package/dist/cli/service-auth/recovery-clock.d.ts +7 -0
  26. package/dist/cli/service-auth/refresh-attempt.d.ts +34 -0
  27. package/dist/cli/service-auth/session.d.ts +9 -2
  28. package/dist/cli-node/index.js +1160 -391
  29. package/dist/hooks/native-edition-nudge/hook.d.ts +3 -4
  30. package/dist/index.js +15519 -8807
  31. package/dist/plugin/session-tool-permissions.d.ts +10 -0
  32. package/dist/plugin/system-transform.d.ts +2 -1
  33. package/dist/plugin/tool-definition.d.ts +1 -0
  34. package/dist/shared/bun-ffi-shim.d.ts +29 -0
  35. package/dist/shared/json-file-cache-store.d.ts +11 -0
  36. package/dist/skills/browser/runtime/omowright/index.js +24 -33
  37. package/dist/skills/browser/runtime/omowright/manifest.json +3 -3
  38. package/dist/skills/frontend/ATTRIBUTION.md +104 -1
  39. package/dist/skills/frontend/SKILL.md +7 -3
  40. package/dist/skills/frontend/references/design/design-system-architecture.md +3 -3
  41. package/dist/skills/frontend/references/perfection/craft-floor.md +59 -0
  42. package/dist/skills/frontend/references/perfection/detect.md +52 -0
  43. package/dist/skills/frontend/scripts/detect/cli.ts +70 -0
  44. package/dist/skills/frontend/scripts/detect/config.test.ts +26 -0
  45. package/dist/skills/frontend/scripts/detect/config.ts +53 -0
  46. package/dist/skills/frontend/scripts/detect/core/characters.ts +2 -0
  47. package/dist/skills/frontend/scripts/detect/core/color.test.ts +29 -0
  48. package/dist/skills/frontend/scripts/detect/core/color.ts +150 -0
  49. package/dist/skills/frontend/scripts/detect/core/page.ts +84 -0
  50. package/dist/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  51. package/dist/skills/frontend/scripts/detect/core/source.ts +33 -0
  52. package/dist/skills/frontend/scripts/detect/detect.ts +77 -0
  53. package/dist/skills/frontend/scripts/detect/index.ts +23 -0
  54. package/dist/skills/frontend/scripts/detect/lint.test.ts +27 -0
  55. package/dist/skills/frontend/scripts/detect/lint.ts +98 -0
  56. package/dist/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
  57. package/dist/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  58. package/dist/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  59. package/dist/skills/frontend/scripts/detect/render/webview.ts +71 -0
  60. package/dist/skills/frontend/scripts/detect/report.ts +29 -0
  61. package/dist/skills/frontend/scripts/detect/rule.ts +42 -0
  62. package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
  63. package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  64. package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
  65. package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  66. package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
  67. package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  68. package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
  69. package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  70. package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
  71. package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  72. package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
  73. package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  74. package/dist/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  75. package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
  76. package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  77. package/dist/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
  78. package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
  79. package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  80. package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
  81. package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  82. package/dist/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  83. package/dist/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  84. package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  85. package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  86. package/dist/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  87. package/dist/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  88. package/dist/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  89. package/dist/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  90. package/dist/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  91. package/dist/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  92. package/dist/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  93. package/dist/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  94. package/dist/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  95. package/dist/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  96. package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
  97. package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  98. package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
  99. package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  100. package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
  101. package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  102. package/dist/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  103. package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
  104. package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  105. package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
  106. package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  107. package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
  108. package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  109. package/dist/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
  110. package/dist/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  111. package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
  112. package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  113. package/dist/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  114. package/dist/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  115. package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
  116. package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  117. package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
  118. package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  119. package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
  120. package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  121. package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
  122. package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  123. package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
  124. package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  125. package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
  126. package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  127. package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
  128. package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  129. package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
  130. package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  131. package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
  132. package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  133. package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
  134. package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  135. package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
  136. package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  137. package/dist/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  138. package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
  139. package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  140. package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
  141. package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  142. package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
  143. package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  144. package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
  145. package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  146. package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
  147. package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  148. package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
  149. package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  150. package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
  151. package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  152. package/dist/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  153. package/dist/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  154. package/dist/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  155. package/dist/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  156. package/dist/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  157. package/dist/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  158. package/dist/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  159. package/dist/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  160. package/dist/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  161. package/dist/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  162. package/dist/skills/frontend/scripts/detect/rules/index.ts +16 -0
  163. package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
  164. package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  165. package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
  166. package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  167. package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
  168. package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  169. package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
  170. package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  171. package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
  172. package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  173. package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
  174. package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  175. package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
  176. package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  177. package/dist/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  178. package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
  179. package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  180. package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
  181. package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  182. package/dist/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
  183. package/dist/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  184. package/dist/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  185. package/dist/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  186. package/dist/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  187. package/dist/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  188. package/dist/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  189. package/dist/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  190. package/dist/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  191. package/dist/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  192. package/dist/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  193. package/dist/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  194. package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
  195. package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  196. package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
  197. package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  198. package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
  199. package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  200. package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
  201. package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  202. package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
  203. package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  204. package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
  205. package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  206. package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
  207. package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  208. package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
  209. package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  210. package/dist/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
  211. package/dist/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  212. package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
  213. package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  214. package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
  215. package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  216. package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
  217. package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  218. package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
  219. package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  220. package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
  221. package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  222. package/dist/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  223. package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
  224. package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  225. package/dist/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
  226. package/dist/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  227. package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
  228. package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  229. package/dist/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
  230. package/dist/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  231. package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
  232. package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  233. package/dist/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
  234. package/dist/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  235. package/dist/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  236. package/dist/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  237. package/dist/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  238. package/dist/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  239. package/dist/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  240. package/dist/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  241. package/dist/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  242. package/dist/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  243. package/dist/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  244. package/dist/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  245. package/dist/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  246. package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
  247. package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  248. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
  249. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  250. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
  251. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  252. package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
  253. package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  254. package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
  255. package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  256. package/dist/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  257. package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
  258. package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  259. package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
  260. package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  261. package/dist/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
  262. package/dist/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  263. package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
  264. package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  265. package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
  266. package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  267. package/dist/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  268. package/dist/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  269. package/dist/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  270. package/dist/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  271. package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
  272. package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  273. package/dist/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  274. package/dist/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  275. package/dist/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  276. package/dist/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  277. package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
  278. package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  279. package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
  280. package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  281. package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
  282. package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  283. package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
  284. package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  285. package/dist/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  286. package/dist/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  287. package/dist/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  288. package/dist/skills/frontend/scripts/detect/tsconfig.json +19 -0
  289. package/dist/skills/frontend/scripts/detect/types.ts +124 -0
  290. package/dist/skills/programming/SKILL.md +15 -74
  291. package/dist/skills/programming/references/go/README.md +1 -1
  292. package/dist/skills/programming/references/go/bootstrap.md +2 -2
  293. package/dist/skills/programming/references/python/README.md +4 -4
  294. package/dist/skills/programming/references/python/one-liners.md +5 -5
  295. package/dist/skills/programming/references/testing/README.md +82 -0
  296. package/dist/skills/programming/references/testing/junk-classes.md +56 -0
  297. package/dist/skills/programming/references/typescript/README.md +1 -2
  298. package/dist/skills/programming/scripts/go/new-project.ts +197 -0
  299. package/dist/skills/programming/scripts/python/new-project.ts +231 -0
  300. package/dist/skills/programming/scripts/python/new-script.ts +134 -0
  301. package/dist/skills/programming/scripts/rust/new-project.ts +215 -0
  302. package/dist/skills/programming/scripts/scaffolders.test.ts +96 -0
  303. package/dist/skills/programming/scripts/shared/run-tool.ts +19 -0
  304. package/dist/skills/visual-qa/SKILL.md +12 -1
  305. package/dist/tui.js +128 -39
  306. package/package.json +20 -19
  307. package/packages/lsp-core/src/lsp/config-loader.ts +18 -2
  308. package/packages/lsp-core/src/lsp/host-js-runtime.test.ts +150 -0
  309. package/packages/lsp-core/src/lsp/host-js-runtime.ts +57 -0
  310. package/packages/lsp-core/src/lsp/server-definitions.ts +10 -0
  311. package/packages/lsp-core/src/lsp/server-resolution.ts +9 -1
  312. package/packages/lsp-core/src/lsp/typescript-server-defaults.test.ts +84 -0
  313. package/packages/lsp-daemon/dist/cli.js +81 -15
  314. package/packages/lsp-daemon/dist/client.js +74 -8
  315. package/packages/lsp-daemon/dist/index.js +76 -10
  316. package/packages/lsp-tools-mcp/dist/cli.js +74 -8
  317. package/packages/lsp-tools-mcp/dist/mcp.js +74 -8
  318. package/packages/lsp-tools-mcp/dist/tools.js +74 -8
  319. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  320. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +20 -4
  321. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  322. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  323. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  324. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  325. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  326. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  327. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  328. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  329. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  330. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +77 -13
  331. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  332. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  333. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  334. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  335. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  336. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  337. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +34 -2
  338. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +34 -2
  339. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  340. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  341. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +14 -1
  342. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  343. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  344. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  345. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  346. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  347. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  348. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  349. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  350. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  351. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  352. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  353. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  354. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  355. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  356. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  357. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  358. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  359. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  360. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  361. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  362. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  363. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  364. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  365. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  366. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  367. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  368. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  369. package/packages/omo-codex/plugin/package-lock.json +12 -12
  370. package/packages/omo-codex/plugin/package.json +1 -1
  371. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +16 -1
  372. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/index.js +24 -33
  373. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +3 -3
  374. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +104 -1
  375. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +7 -3
  376. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +3 -3
  377. package/packages/omo-codex/plugin/skills/frontend/references/perfection/craft-floor.md +59 -0
  378. package/packages/omo-codex/plugin/skills/frontend/references/perfection/detect.md +52 -0
  379. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/cli.ts +70 -0
  380. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/config.ts +53 -0
  381. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/characters.ts +2 -0
  382. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/color.ts +150 -0
  383. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/page.ts +84 -0
  384. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  385. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/source.ts +33 -0
  386. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/detect.ts +77 -0
  387. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/index.ts +23 -0
  388. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/lint.ts +98 -0
  389. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  390. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  391. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/webview.ts +71 -0
  392. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/report.ts +29 -0
  393. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rule.ts +42 -0
  394. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  395. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  396. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  397. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  398. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  399. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  400. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  401. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  402. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  403. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  404. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  405. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  406. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  407. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  408. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  409. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  410. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  411. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  412. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  413. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  414. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  415. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  416. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  417. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  418. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  419. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  420. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  421. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  422. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  423. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  424. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  425. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  426. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  427. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  428. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  429. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  430. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  431. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  432. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  433. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  434. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  435. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  436. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  437. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  438. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  439. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  440. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  441. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  442. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  443. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  444. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  445. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  446. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  447. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  448. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  449. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  450. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  451. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  452. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  453. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  454. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  455. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  456. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  457. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  458. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/index.ts +16 -0
  459. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  460. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  461. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  462. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  463. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  464. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  465. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  466. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  467. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  468. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  469. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  470. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  471. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  472. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  473. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  474. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  475. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  476. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  477. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  478. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  479. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  480. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  481. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  482. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  483. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  484. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  485. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  486. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  487. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  488. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  489. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  490. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  491. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  492. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  493. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  494. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  495. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  496. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  497. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  498. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  499. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  500. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  501. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  502. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  503. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  504. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  505. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  506. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  507. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  508. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  509. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  510. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  511. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  512. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  513. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  514. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  515. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  516. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  517. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  518. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  519. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  520. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  521. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  522. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  523. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  524. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  525. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  526. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  527. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  528. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  529. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  530. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  531. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  532. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  533. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  534. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  535. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  536. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  537. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  538. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  539. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/tsconfig.json +19 -0
  540. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/types.ts +124 -0
  541. package/packages/omo-codex/plugin/skills/programming/SKILL.md +15 -74
  542. package/packages/omo-codex/plugin/skills/programming/references/go/README.md +1 -1
  543. package/packages/omo-codex/plugin/skills/programming/references/go/bootstrap.md +2 -2
  544. package/packages/omo-codex/plugin/skills/programming/references/python/README.md +4 -4
  545. package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +5 -5
  546. package/packages/omo-codex/plugin/skills/programming/references/testing/README.md +82 -0
  547. package/packages/omo-codex/plugin/skills/programming/references/testing/junk-classes.md +56 -0
  548. package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +1 -2
  549. package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.ts +197 -0
  550. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.ts +231 -0
  551. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.ts +134 -0
  552. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.ts +215 -0
  553. package/packages/omo-codex/plugin/skills/programming/scripts/shared/run-tool.ts +19 -0
  554. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +12 -1
  555. package/packages/omo-codex/plugin/test/auto-update.test.mjs +62 -0
  556. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +12 -2
  557. package/packages/omo-codex/scripts/install-dist/install-local.mjs +77 -10
  558. package/packages/shared-skills/skills/browser/runtime/omowright/index.js +24 -33
  559. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +3 -3
  560. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +104 -1
  561. package/packages/shared-skills/skills/frontend/SKILL.md +7 -3
  562. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +3 -3
  563. package/packages/shared-skills/skills/frontend/references/perfection/craft-floor.md +59 -0
  564. package/packages/shared-skills/skills/frontend/references/perfection/detect.md +52 -0
  565. package/packages/shared-skills/skills/frontend/scripts/detect/cli.ts +70 -0
  566. package/packages/shared-skills/skills/frontend/scripts/detect/config.test.ts +26 -0
  567. package/packages/shared-skills/skills/frontend/scripts/detect/config.ts +53 -0
  568. package/packages/shared-skills/skills/frontend/scripts/detect/core/characters.ts +2 -0
  569. package/packages/shared-skills/skills/frontend/scripts/detect/core/color.test.ts +29 -0
  570. package/packages/shared-skills/skills/frontend/scripts/detect/core/color.ts +150 -0
  571. package/packages/shared-skills/skills/frontend/scripts/detect/core/page.ts +84 -0
  572. package/packages/shared-skills/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  573. package/packages/shared-skills/skills/frontend/scripts/detect/core/source.ts +33 -0
  574. package/packages/shared-skills/skills/frontend/scripts/detect/detect.ts +77 -0
  575. package/packages/shared-skills/skills/frontend/scripts/detect/index.ts +23 -0
  576. package/packages/shared-skills/skills/frontend/scripts/detect/lint.test.ts +27 -0
  577. package/packages/shared-skills/skills/frontend/scripts/detect/lint.ts +98 -0
  578. package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
  579. package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  580. package/packages/shared-skills/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  581. package/packages/shared-skills/skills/frontend/scripts/detect/render/webview.ts +71 -0
  582. package/packages/shared-skills/skills/frontend/scripts/detect/report.ts +29 -0
  583. package/packages/shared-skills/skills/frontend/scripts/detect/rule.ts +42 -0
  584. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
  585. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  586. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
  587. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  588. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
  589. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  590. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
  591. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  592. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
  593. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  594. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
  595. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  596. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  597. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
  598. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  599. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
  600. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
  601. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  602. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
  603. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  604. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  605. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  606. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  607. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  608. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  609. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  610. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  611. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  612. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  613. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  614. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  615. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  616. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  617. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  618. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
  619. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  620. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
  621. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  622. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
  623. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  624. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  625. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
  626. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  627. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
  628. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  629. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
  630. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  631. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
  632. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  633. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
  634. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  635. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  636. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  637. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
  638. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  639. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
  640. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  641. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
  642. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  643. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
  644. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  645. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
  646. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  647. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
  648. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  649. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
  650. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  651. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
  652. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  653. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
  654. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  655. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
  656. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  657. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
  658. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  659. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  660. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
  661. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  662. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
  663. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  664. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
  665. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  666. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
  667. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  668. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
  669. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  670. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
  671. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  672. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
  673. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  674. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  675. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  676. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  677. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  678. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  679. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  680. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  681. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  682. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  683. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  684. package/packages/shared-skills/skills/frontend/scripts/detect/rules/index.ts +16 -0
  685. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
  686. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  687. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
  688. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  689. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
  690. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  691. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
  692. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  693. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
  694. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  695. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
  696. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  697. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
  698. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  699. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  700. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
  701. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  702. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
  703. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  704. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
  705. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  706. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  707. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  708. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  709. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  710. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  711. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  712. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  713. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  714. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  715. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  716. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
  717. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  718. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
  719. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  720. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
  721. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  722. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
  723. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  724. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
  725. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  726. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
  727. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  728. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
  729. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  730. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
  731. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  732. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
  733. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  734. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
  735. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  736. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
  737. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  738. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
  739. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  740. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
  741. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  742. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
  743. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  744. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  745. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
  746. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  747. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
  748. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  749. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
  750. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  751. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
  752. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  753. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
  754. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  755. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
  756. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  757. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  758. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  759. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  760. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  761. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  762. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  763. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  764. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  765. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  766. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  767. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  768. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
  769. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  770. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
  771. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  772. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
  773. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  774. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
  775. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  776. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
  777. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  778. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  779. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
  780. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  781. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
  782. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  783. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
  784. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  785. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
  786. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  787. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
  788. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  789. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  790. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  791. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  792. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  793. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
  794. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  795. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  796. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  797. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  798. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  799. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
  800. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  801. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
  802. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  803. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
  804. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  805. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
  806. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  807. package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  808. package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  809. package/packages/shared-skills/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  810. package/packages/shared-skills/skills/frontend/scripts/detect/tsconfig.json +19 -0
  811. package/packages/shared-skills/skills/frontend/scripts/detect/types.ts +124 -0
  812. package/packages/shared-skills/skills/programming/SKILL.md +15 -74
  813. package/packages/shared-skills/skills/programming/references/go/README.md +1 -1
  814. package/packages/shared-skills/skills/programming/references/go/bootstrap.md +2 -2
  815. package/packages/shared-skills/skills/programming/references/python/README.md +4 -4
  816. package/packages/shared-skills/skills/programming/references/python/one-liners.md +5 -5
  817. package/packages/shared-skills/skills/programming/references/testing/README.md +82 -0
  818. package/packages/shared-skills/skills/programming/references/testing/junk-classes.md +56 -0
  819. package/packages/shared-skills/skills/programming/references/typescript/README.md +1 -2
  820. package/packages/shared-skills/skills/programming/scripts/go/new-project.ts +197 -0
  821. package/packages/shared-skills/skills/programming/scripts/python/new-project.ts +231 -0
  822. package/packages/shared-skills/skills/programming/scripts/python/new-script.ts +134 -0
  823. package/packages/shared-skills/skills/programming/scripts/rust/new-project.ts +215 -0
  824. package/packages/shared-skills/skills/programming/scripts/scaffolders.test.ts +96 -0
  825. package/packages/shared-skills/skills/programming/scripts/shared/run-tool.ts +19 -0
  826. package/packages/shared-skills/skills/visual-qa/SKILL.md +12 -1
  827. package/dist/agents/gpt-prompt-identity.d.ts +0 -3
  828. package/dist/agents/hephaestus/gpt-5-4.d.ts +0 -24
  829. package/dist/agents/hephaestus/gpt-5-5.d.ts +0 -2
  830. package/dist/agents/hephaestus/gpt-5-6.d.ts +0 -2
  831. package/dist/agents/kimi-tool-loop-guard.d.ts +0 -1
  832. package/dist/agents/sisyphus/claude-fable-5.d.ts +0 -19
  833. package/dist/agents/sisyphus/claude-opus-4-7.d.ts +0 -22
  834. package/dist/agents/sisyphus/claude-opus-4-8.d.ts +0 -19
  835. package/dist/agents/sisyphus/claude-opus-5.d.ts +0 -33
  836. package/dist/agents/sisyphus/gemini.d.ts +0 -20
  837. package/dist/agents/sisyphus/glm-5-2.d.ts +0 -4
  838. package/dist/agents/sisyphus/gpt-5-4.d.ts +0 -26
  839. package/dist/agents/sisyphus/gpt-5-5.d.ts +0 -6
  840. package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +0 -1
  841. package/dist/agents/sisyphus/grok-4.d.ts +0 -21
  842. package/dist/agents/sisyphus/index.d.ts +0 -31
  843. package/dist/agents/sisyphus/kimi-k2-6.d.ts +0 -32
  844. package/dist/agents/sisyphus/kimi-k2-7.d.ts +0 -17
  845. package/dist/agents/sisyphus/kimi-k3-1.d.ts +0 -9
  846. package/dist/agents/sisyphus/kimi-k3.d.ts +0 -19
  847. package/dist/agents/sisyphus-dynamic-prompt-builder.d.ts +0 -2
  848. package/dist/agents/sisyphus-dynamic-prompt-execution.d.ts +0 -2
  849. package/dist/agents/sisyphus-dynamic-prompt-exploration.d.ts +0 -2
  850. package/dist/agents/sisyphus-dynamic-prompt-role.d.ts +0 -2
  851. package/dist/agents/sisyphus-dynamic-prompt-sections.d.ts +0 -18
  852. package/dist/agents/sisyphus-dynamic-prompt-style.d.ts +0 -2
  853. package/dist/agents/sisyphus-dynamic-prompt.d.ts +0 -3
  854. package/dist/agents/sisyphus-gemini-fallback-overrides.d.ts +0 -1
  855. package/dist/agents/sisyphus-junior/gemini.d.ts +0 -10
  856. package/dist/agents/sisyphus-junior/glm-5-2.d.ts +0 -1
  857. package/dist/agents/sisyphus-junior/gpt-5-4.d.ts +0 -11
  858. package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +0 -5
  859. package/dist/agents/sisyphus-junior/gpt.d.ts +0 -9
  860. package/dist/agents/sisyphus-junior/kimi-k2-6.d.ts +0 -13
  861. package/dist/agents/sisyphus-junior/kimi-k2-7.d.ts +0 -11
  862. package/dist/agents/sisyphus-junior/kimi-k3-1.d.ts +0 -6
  863. package/dist/agents/sisyphus-junior/kimi-k3.d.ts +0 -12
  864. package/dist/features/claude-code-agent-loader/opencode-config-agents-reader.d.ts +0 -1
  865. package/dist/features/claude-code-command-loader/loader-cache.d.ts +0 -1
  866. package/dist/features/claude-code-command-loader/loader.d.ts +0 -1
  867. package/dist/features/opencode-skill-loader/config-source-discovery.d.ts +0 -1
  868. package/dist/features/opencode-skill-loader/merger/config-skill-entry-loader.d.ts +0 -1
  869. package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +0 -1
  870. package/dist/features/team-mode/team-layout-tmux/resolve-caller-tmux-session.d.ts +0 -1
  871. package/dist/features/team-mode/team-registry/team-spec-input-normalizer.d.ts +0 -1
  872. package/dist/shared/git-worktree/collect-git-diff-stats.d.ts +0 -1
  873. package/dist/shared/git-worktree/parse-status-porcelain-line.d.ts +0 -1
  874. package/dist/shared/migration/agent-names.d.ts +0 -1
  875. package/dist/shared/migration/migrations-sidecar.d.ts +0 -1
  876. package/dist/shared/skill-path-resolver.d.ts +0 -1
  877. package/dist/shared/zip-entry-listing/powershell-zip-entry-listing.d.ts +0 -1
  878. package/dist/shared/zip-entry-listing/zipinfo-zip-entry-listing.d.ts +0 -1
  879. package/dist/skills/programming/scripts/go/new-project.py +0 -138
  880. package/dist/skills/programming/scripts/python/new-project.py +0 -172
  881. package/dist/skills/programming/scripts/python/new-script.py +0 -116
  882. package/dist/skills/programming/scripts/rust/new-project.py +0 -178
  883. package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.py +0 -138
  884. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.py +0 -172
  885. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.py +0 -116
  886. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +0 -178
  887. package/packages/shared-skills/skills/programming/scripts/go/new-project.py +0 -138
  888. package/packages/shared-skills/skills/programming/scripts/python/new-project.py +0 -172
  889. package/packages/shared-skills/skills/programming/scripts/python/new-script.py +0 -116
  890. package/packages/shared-skills/skills/programming/scripts/rust/new-project.py +0 -178
package/dist/cli/index.js CHANGED
@@ -2132,7 +2132,7 @@ var package_default;
2132
2132
  var init_package = __esm(() => {
2133
2133
  package_default = {
2134
2134
  name: "oh-my-opencode",
2135
- version: "5.1.51",
2135
+ version: "5.1.54",
2136
2136
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
2137
2137
  main: "./dist/index.js",
2138
2138
  types: "dist/index.d.ts",
@@ -2274,14 +2274,15 @@ var init_package = __esm(() => {
2274
2274
  prepublishOnly: "bun run clean && bun run build:lsp-tools-mcp && bun run build:lsp-daemon && bun run build",
2275
2275
  "test:model-capabilities": "bun test --timeout 20000 packages/model-core/src/model-capability-aliases.test.ts packages/model-core/src/model-capability-guardrails.test.ts packages/model-core/src/model-capabilities.test.ts packages/omo-opencode/src/cli/doctor/checks/model-resolution.test.ts --bail",
2276
2276
  "check:copy": "bun script/check-copy.ts",
2277
- typecheck: "bun run check:copy && tsgo --noEmit && bun run typecheck:script && bun run typecheck:packages",
2278
- "typecheck:packages": "tsgo --noEmit -p packages/rules-engine/tsconfig.json && tsgo --noEmit -p packages/delegate-core/tsconfig.json && tsgo --noEmit -p packages/mcp-stdio-core/tsconfig.json && tsgo --noEmit -p packages/mcp-client-core/tsconfig.json && tsgo --noEmit -p packages/git-bash-mcp/tsconfig.json && tsgo --noEmit -p packages/ast-grep-mcp/tsconfig.json && tsgo --noEmit -p packages/lsp-core/tsconfig.json && tsgo --noEmit -p packages/utils/tsconfig.json && tsgo --noEmit -p packages/model-core/tsconfig.json && tsgo --noEmit -p packages/omo-config-core/tsconfig.json && tsgo --noEmit -p packages/prompts-core/tsconfig.json && tsgo --noEmit -p packages/comment-checker-core/tsconfig.json && tsgo --noEmit -p packages/hashline-core/tsconfig.json && tsgo --noEmit -p packages/tmux-core/tsconfig.json && tsgo --noEmit -p packages/team-core/tsconfig.json && tsgo --noEmit -p packages/openclaw-core/tsconfig.json && tsgo --noEmit -p packages/boulder-state/tsconfig.json && tsgo --noEmit -p packages/isolation-core/tsconfig.json && tsgo --noEmit -p packages/memory-core/tsconfig.json && tsgo --noEmit -p packages/telemetry-core/tsconfig.json && tsgo --noEmit -p packages/claude-code-compat-core/tsconfig.json && tsgo --noEmit -p packages/skills-loader-core/tsconfig.json && tsgo --noEmit -p packages/agents-md-core/tsconfig.json && tsgo --noEmit -p packages/omo-codex/plugin/shared/tsconfig.json && tsgo --noEmit -p packages/omo-codex/tsconfig.json && tsgo --noEmit -p packages/omo-senpi/tsconfig.json && tsgo --noEmit -p packages/senpi-task/tsconfig.json && tsgo --noEmit -p packages/omo-opencode/tsconfig.json && tsgo --noEmit -p packages/omo-native/tsconfig.json && tsgo --noEmit -p packages/senpi-desktop-protocol/tsconfig.json && tsgo --noEmit -p packages/senpi-desktop-engine/tsconfig.json && tsgo --noEmit -p packages/senpi-desktop-prelude/tsconfig.json && tsgo --noEmit -p packages/senpi-desktop-service/tsconfig.json && tsgo --noEmit -p packages/senpi-desktop-tool/tsconfig.json",
2279
- "typecheck:script": "tsgo --noEmit -p script/tsconfig.json",
2277
+ typecheck: "bun run check:copy && bun check --no-script --all -p tsconfig.json && bun run typecheck:script && bun run typecheck:packages && bun run typecheck:skill-scripts",
2278
+ "typecheck:skill-scripts": "bun check --no-script --all -p packages/shared-skills/skills/frontend/scripts/detect/tsconfig.json",
2279
+ "typecheck:packages": "bun check --no-script --all -p packages/rules-engine/tsconfig.json && bun check --no-script --all -p packages/delegate-core/tsconfig.json && bun check --no-script --all -p packages/mcp-stdio-core/tsconfig.json && bun check --no-script --all -p packages/mcp-client-core/tsconfig.json && bun check --no-script --all -p packages/git-bash-mcp/tsconfig.json && bun check --no-script --all -p packages/ast-grep-mcp/tsconfig.json && bun check --no-script --all -p packages/lsp-core/tsconfig.json && bun check --no-script --all -p packages/utils/tsconfig.json && bun check --no-script --all -p packages/model-core/tsconfig.json && bun check --no-script --all -p packages/omo-config-core/tsconfig.json && bun check --no-script --all -p packages/prompts-core/tsconfig.json && bun check --no-script --all -p packages/comment-checker-core/tsconfig.json && bun check --no-script --all -p packages/hashline-core/tsconfig.json && bun check --no-script --all -p packages/tmux-core/tsconfig.json && bun check --no-script --all -p packages/team-core/tsconfig.json && bun check --no-script --all -p packages/openclaw-core/tsconfig.json && bun check --no-script --all -p packages/boulder-state/tsconfig.json && bun check --no-script --all -p packages/isolation-core/tsconfig.json && bun check --no-script --all -p packages/memory-core/tsconfig.json && bun check --no-script --all -p packages/telemetry-core/tsconfig.json && bun check --no-script --all -p packages/claude-code-compat-core/tsconfig.json && bun check --no-script --all -p packages/skills-loader-core/tsconfig.json && bun check --no-script --all -p packages/agents-md-core/tsconfig.json && bun check --no-script --all -p packages/omo-codex/plugin/shared/tsconfig.json && bun check --no-script --all -p packages/omo-codex/tsconfig.json && bun check --no-script --all -p packages/omo-senpi/tsconfig.json && bun check --no-script --all -p packages/senpi-task/tsconfig.json && bun check --no-script --all -p packages/omo-opencode/tsconfig.json && bun check --no-script --all -p packages/omo-native/tsconfig.json && bun check --no-script --all -p packages/senpi-desktop-protocol/tsconfig.json && bun check --no-script --all -p packages/senpi-desktop-engine/tsconfig.json && bun check --no-script --all -p packages/senpi-desktop-prelude/tsconfig.json && bun check --no-script --all -p packages/senpi-desktop-service/tsconfig.json && bun check --no-script --all -p packages/senpi-desktop-tool/tsconfig.json",
2280
+ "typecheck:script": "bun check --no-script --all -p script/tsconfig.json",
2280
2281
  test: "bun test --timeout 20000",
2281
2282
  "changelog:section": "bun script/changelog-section.ts",
2282
2283
  "test:codex": "bun run build:codex-install && bun run build:git-bash-mcp && bun run build:lsp-tools-mcp && bun run build:lsp-daemon && npm --prefix packages/lsp-tools-mcp test && npm --prefix packages/omo-codex/plugin ci && npm --prefix packages/omo-codex/plugin/components/ulw-loop test && bun run --cwd packages/omo-codex/plugin build && node scripts/check-third-party-notices.mjs --ship && bun test --timeout 20000 packages/omo-opencode/src/cli/cli-installer.platform.test.ts packages/omo-codex/src/install/codex-cache.test.ts packages/omo-codex/src/install/codex-cleanup.test.ts packages/omo-codex/src/install/codex-config-agent-cleanup.test.ts packages/omo-codex/src/install/codex-config-autonomous-features.test.ts packages/omo-codex/src/install/codex-config-reasoning.test.ts packages/omo-codex/src/install/codex-config-toml.test.ts packages/omo-codex/src/install/codex-project-local-cleanup.test.ts packages/omo-codex/src/install/install-codex-project-local-cleanup.test.ts packages/omo-codex/src/install/install-codex.test.ts packages/omo-codex/src/install/install-codex-packaged.test.ts packages/omo-codex/src/install/link-cached-plugin-agents.test.ts packages/omo-codex/src/**/*.test.ts packages/utils/src/jsonc-parser.test.ts packages/utils/src/frontmatter.test.ts packages/hashline-core/src/hash-computation.test.ts packages/hashline-core/src/smoke-untested-modules.test.ts packages/rules-engine/src/index.test.ts packages/rules-engine/src/security-boundary.test.ts packages/agents-md-core/src/injector.test.ts packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts && node --test packages/omo-codex/plugin/test/*.test.mjs packages/omo-codex/scripts/install-cache-copy.test.mjs packages/omo-codex/scripts/install-cli-args.test.mjs packages/omo-codex/scripts/install-delegated-command.test.mjs packages/omo-codex/scripts/install-config-autonomous-features.test.mjs packages/omo-codex/scripts/install-config-autonomous.test.mjs packages/omo-codex/scripts/install-config-reasoning.test.mjs packages/omo-codex/scripts/install-config.test.mjs packages/omo-codex/scripts/install-hook-targets.test.mjs packages/omo-codex/scripts/install-project-local-cleanup.test.mjs packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs packages/omo-codex/scripts/install-local-entrypoint.test.mjs packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs packages/omo-codex/scripts/install-local.test.mjs packages/omo-codex/scripts/install-marketplace-cache.test.mjs packages/omo-codex/scripts/install-mcp-context7-runtime.test.mjs packages/omo-codex/scripts/install-mcp-runtime.test.mjs packages/omo-codex/scripts/install-packaged-local.test.mjs packages/omo-codex/scripts/install-generated-bundle.test.mjs packages/omo-codex/scripts/install-agent-links.test.mjs packages/omo-codex/scripts/install-bin-links.test.mjs",
2283
2284
  "test:fast": "bun run script/test-fast.ts",
2284
- "test:senpi": "bun run build:senpi-plugin && tsgo --noEmit -p packages/omo-senpi/tsconfig.json && bun test --timeout 20000 packages/omo-senpi && bun test ./.agents/skills/senpi-qa/scripts/resolve-evidence-dir.test.mjs",
2285
+ "test:senpi": "bun run build:senpi-plugin && bun check --no-script --all -p packages/omo-senpi/tsconfig.json && bun test --timeout 20000 packages/omo-senpi && bun test ./.agents/skills/senpi-qa/scripts/resolve-evidence-dir.test.mjs",
2285
2286
  "test:windows-codex": "bun run test:codex",
2286
2287
  "build:git-bash-mcp": "bun run --cwd packages/git-bash-mcp build",
2287
2288
  "build:ast-grep-mcp": "bun run --cwd packages/ast-grep-mcp build",
@@ -2317,7 +2318,7 @@ var init_package = __esm(() => {
2317
2318
  },
2318
2319
  devDependencies: {
2319
2320
  "@clack/prompts": "^1.8.1",
2320
- "@code-yeongyu/senpi": "2026.10.27-1",
2321
+ "@code-yeongyu/senpi": "2026.10.30-1",
2321
2322
  "@modelcontextprotocol/sdk": "^1.30.0",
2322
2323
  "@oh-my-opencode/agents-md-core": "workspace:*",
2323
2324
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
@@ -2371,7 +2372,7 @@ var init_package = __esm(() => {
2371
2372
  "jsonc-parser": "^3.3.1",
2372
2373
  knip: "6.43.0",
2373
2374
  "node-pty": "^1.1.0",
2374
- omowright: "github:code-yeongyu/omowright#f87ef4d63fe7b56fe117dbab246c8ad88dd8a780",
2375
+ omowright: "github:code-yeongyu/omowright#c06d20337ad942b09dea8757a45f6c848008a68d",
2375
2376
  "oxc-parser": "0.148.0",
2376
2377
  oxlint: "1.89.0",
2377
2378
  picocolors: "^1.1.1",
@@ -2381,18 +2382,18 @@ var init_package = __esm(() => {
2381
2382
  typescript: "^7.0.2"
2382
2383
  },
2383
2384
  optionalDependencies: {
2384
- "oh-my-opencode-darwin-arm64": "5.1.51",
2385
- "oh-my-opencode-darwin-x64": "5.1.51",
2386
- "oh-my-opencode-darwin-x64-baseline": "5.1.51",
2387
- "oh-my-opencode-linux-arm64": "5.1.51",
2388
- "oh-my-opencode-linux-arm64-musl": "5.1.51",
2389
- "oh-my-opencode-linux-x64": "5.1.51",
2390
- "oh-my-opencode-linux-x64-baseline": "5.1.51",
2391
- "oh-my-opencode-linux-x64-musl": "5.1.51",
2392
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.51",
2393
- "oh-my-opencode-windows-arm64": "5.1.51",
2394
- "oh-my-opencode-windows-x64": "5.1.51",
2395
- "oh-my-opencode-windows-x64-baseline": "5.1.51"
2385
+ "oh-my-opencode-darwin-arm64": "5.1.54",
2386
+ "oh-my-opencode-darwin-x64": "5.1.54",
2387
+ "oh-my-opencode-darwin-x64-baseline": "5.1.54",
2388
+ "oh-my-opencode-linux-arm64": "5.1.54",
2389
+ "oh-my-opencode-linux-arm64-musl": "5.1.54",
2390
+ "oh-my-opencode-linux-x64": "5.1.54",
2391
+ "oh-my-opencode-linux-x64-baseline": "5.1.54",
2392
+ "oh-my-opencode-linux-x64-musl": "5.1.54",
2393
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.54",
2394
+ "oh-my-opencode-windows-arm64": "5.1.54",
2395
+ "oh-my-opencode-windows-x64": "5.1.54",
2396
+ "oh-my-opencode-windows-x64-baseline": "5.1.54"
2396
2397
  },
2397
2398
  overrides: {
2398
2399
  hono: "^4.13.8",
@@ -8055,7 +8056,8 @@ var init_latest_models = __esm(() => {
8055
8056
  gptLunaFast: "gpt-6-luna-fast",
8056
8057
  glm: "glm-5.3",
8057
8058
  glmFlash: "glm-5.3-flash",
8058
- kimi: "kimi-k3",
8059
+ kimi: "kimi-k3.1-pro",
8060
+ kimiK3: "kimi-k3",
8059
8061
  geminiPro: "gemini-4-argon"
8060
8062
  };
8061
8063
  });
@@ -9378,9 +9380,13 @@ var init_agent_model_requirements = __esm(() => {
9378
9380
  variant: "max"
9379
9381
  },
9380
9382
  {
9381
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode", "bailian-coding-plan", "moonshotai-cn", "firmware", "ollama-cloud", "aihubmix"],
9383
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai", "moonshotai-cn"],
9382
9384
  model: LATEST_MODEL_BY_FAMILY.kimi
9383
9385
  },
9386
+ {
9387
+ providers: ["opencode", "bailian-coding-plan", "firmware", "ollama-cloud", "aihubmix"],
9388
+ model: LATEST_MODEL_BY_FAMILY.kimiK3
9389
+ },
9384
9390
  {
9385
9391
  providers: ["openai", "chatgpt-subscription", "github-copilot", "opencode"],
9386
9392
  model: "gpt-5.6-sol",
@@ -9475,10 +9481,11 @@ var init_agent_model_requirements = __esm(() => {
9475
9481
  variant: "max"
9476
9482
  },
9477
9483
  {
9478
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode"],
9484
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai"],
9479
9485
  model: LATEST_MODEL_BY_FAMILY.kimi,
9480
9486
  variant: "max"
9481
- }
9487
+ },
9488
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9482
9489
  ])
9483
9490
  },
9484
9491
  metis: {
@@ -9499,10 +9506,11 @@ var init_agent_model_requirements = __esm(() => {
9499
9506
  variant: "max"
9500
9507
  },
9501
9508
  {
9502
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode"],
9509
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai"],
9503
9510
  model: LATEST_MODEL_BY_FAMILY.kimi,
9504
9511
  variant: "max"
9505
- }
9512
+ },
9513
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9506
9514
  ])
9507
9515
  },
9508
9516
  momus: {
@@ -9585,10 +9593,11 @@ var init_category_model_requirements = __esm(() => {
9585
9593
  variant: "max"
9586
9594
  },
9587
9595
  {
9588
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9596
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9589
9597
  model: LATEST_MODEL_BY_FAMILY.kimi,
9590
9598
  variant: "max"
9591
- }
9599
+ },
9600
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9592
9601
  ])
9593
9602
  },
9594
9603
  ultrabrain: {
@@ -9640,10 +9649,11 @@ var init_category_model_requirements = __esm(() => {
9640
9649
  variant: "max"
9641
9650
  },
9642
9651
  {
9643
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9652
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9644
9653
  model: LATEST_MODEL_BY_FAMILY.kimi,
9645
9654
  variant: "max"
9646
- }
9655
+ },
9656
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9647
9657
  ])
9648
9658
  },
9649
9659
  quick: {
@@ -9706,10 +9716,11 @@ var init_category_model_requirements = __esm(() => {
9706
9716
  },
9707
9717
  { providers: ["zai-coding-plan", "opencode-go"], model: LATEST_MODEL_BY_FAMILY.glm, variant: "max" },
9708
9718
  {
9709
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9719
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9710
9720
  model: LATEST_MODEL_BY_FAMILY.kimi,
9711
9721
  variant: "max"
9712
- }
9722
+ },
9723
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9713
9724
  ]
9714
9725
  },
9715
9726
  writing: {
@@ -10273,7 +10284,7 @@ function transformModelForProviderDisplay(provider, model) {
10273
10284
  var CLAUDE_VERSION_DOT, GEMINI_31_PRO_PREVIEW, GEMINI_3_FLASH_PREVIEW;
10274
10285
  var init_provider_model_id_transform = __esm(() => {
10275
10286
  CLAUDE_VERSION_DOT = /claude-(\w+)-(\d+)-(\d+)/g;
10276
- GEMINI_31_PRO_PREVIEW = /gemini-3\.1-pro(?!-)/g;
10287
+ GEMINI_31_PRO_PREVIEW = /(?<!antigravity-)gemini-3\.1-pro(?!-)/g;
10277
10288
  GEMINI_3_FLASH_PREVIEW = /(?<!antigravity-)gemini-3-flash(?!-)/g;
10278
10289
  });
10279
10290
 
@@ -10347,6 +10358,36 @@ var init_supplemental_entries = __esm(() => {
10347
10358
  output: 262144
10348
10359
  }
10349
10360
  },
10361
+ "kimi-k3.1-pro": {
10362
+ id: "kimi-k3.1-pro",
10363
+ family: "kimi",
10364
+ reasoning: true,
10365
+ temperature: true,
10366
+ toolCall: true,
10367
+ modalities: {
10368
+ input: ["text", "image", "video"],
10369
+ output: ["text"]
10370
+ },
10371
+ limit: {
10372
+ context: 1048576,
10373
+ output: 1048576
10374
+ }
10375
+ },
10376
+ "kimi-k3.1-pro-highspeed": {
10377
+ id: "kimi-k3.1-pro-highspeed",
10378
+ family: "kimi",
10379
+ reasoning: true,
10380
+ temperature: true,
10381
+ toolCall: true,
10382
+ modalities: {
10383
+ input: ["text", "image", "video"],
10384
+ output: ["text"]
10385
+ },
10386
+ limit: {
10387
+ context: 1048576,
10388
+ output: 1048576
10389
+ }
10390
+ },
10350
10391
  "kimi-k2.6": {
10351
10392
  id: "kimi-k2.6",
10352
10393
  family: "kimi",
@@ -12431,6 +12472,33 @@ function createJsonFileCacheStore(options) {
12431
12472
  });
12432
12473
  }
12433
12474
  }
12475
+ function writeIfChanged(value) {
12476
+ ensureCacheDir();
12477
+ const cacheFile = getCacheFilePath();
12478
+ const serialized = options.serialize?.(value) ?? JSON.stringify(value, null, 2);
12479
+ try {
12480
+ const existing = existsSync10(cacheFile) ? readFileSync3(cacheFile, "utf-8") : undefined;
12481
+ const unchanged = existing !== undefined && (existing === serialized || options.comparable !== undefined && JSON.stringify(options.comparable(JSON.parse(existing))) === JSON.stringify(options.comparable(value)));
12482
+ if (unchanged) {
12483
+ memoryValue = value;
12484
+ writtenInCurrentProcess = true;
12485
+ log2(`[${options.logPrefix}] ${options.cacheLabel} unchanged; skipped write`, options.describe(value));
12486
+ return false;
12487
+ }
12488
+ } catch {}
12489
+ try {
12490
+ writeFileSync4(cacheFile, serialized);
12491
+ memoryValue = value;
12492
+ writtenInCurrentProcess = true;
12493
+ log2(`[${options.logPrefix}] ${options.cacheLabel} written`, options.describe(value));
12494
+ return true;
12495
+ } catch (error) {
12496
+ log2(`[${options.logPrefix}] Error writing ${toLogLabel(options.cacheLabel)}`, {
12497
+ error: String(error)
12498
+ });
12499
+ return false;
12500
+ }
12501
+ }
12434
12502
  function resetMemory() {
12435
12503
  memoryValue = undefined;
12436
12504
  writtenInCurrentProcess = false;
@@ -12439,6 +12507,7 @@ function createJsonFileCacheStore(options) {
12439
12507
  read,
12440
12508
  has,
12441
12509
  write,
12510
+ writeIfChanged,
12442
12511
  resetMemory
12443
12512
  };
12444
12513
  }
@@ -67503,7 +67572,8 @@ function createModelCapabilitiesCacheStore(getCacheDir = getOmoOpenCodeCacheDir)
67503
67572
  generatedAt: snapshot.generatedAt
67504
67573
  }),
67505
67574
  serialize: (snapshot) => `${JSON.stringify(snapshot, null, 2)}
67506
- `
67575
+ `,
67576
+ comparable: ({ generatedAt: _generatedAt, ...catalog }) => catalog
67507
67577
  });
67508
67578
  function readModelCapabilitiesCache() {
67509
67579
  return snapshotCacheStore.read();
@@ -67516,7 +67586,7 @@ function createModelCapabilitiesCacheStore(getCacheDir = getOmoOpenCodeCacheDir)
67516
67586
  }
67517
67587
  async function refreshModelCapabilitiesCache(args = {}) {
67518
67588
  const snapshot = await fetchModelCapabilitiesSnapshot(args);
67519
- writeModelCapabilitiesCache(snapshot);
67589
+ snapshotCacheStore.writeIfChanged(snapshot);
67520
67590
  return snapshot;
67521
67591
  }
67522
67592
  return {
@@ -77153,8 +77223,8 @@ var init_memory = __esm(() => {
77153
77223
  enabled: boolean2().optional()
77154
77224
  }).strict();
77155
77225
  OmoMemoryProjectionSchema = object({
77156
- max_entries_per_directory: number2().int().min(0).default(40),
77157
- max_bytes: number2().int().min(0).default(24576)
77226
+ max_entries_per_directory: number2().int().min(0).default(0),
77227
+ max_bytes: number2().int().min(0).default(40960)
77158
77228
  }).strict();
77159
77229
  OmoMemoryProjectionLayerSchema = object({
77160
77230
  max_entries_per_directory: number2().int().min(0).optional(),
@@ -77218,7 +77288,7 @@ var init_memory = __esm(() => {
77218
77288
  query_expansion: false
77219
77289
  }),
77220
77290
  project_scope: OmoMemoryProjectScopeSchema.default({ nudge: true, recall: true }),
77221
- projection: OmoMemoryProjectionSchema.default({ max_entries_per_directory: 40, max_bytes: 24576 }),
77291
+ projection: OmoMemoryProjectionSchema.default({ max_entries_per_directory: 0, max_bytes: 40960 }),
77222
77292
  compile_warn_tokens: number2().int().positive().default(30000),
77223
77293
  agents: record(string2(), OmoMemoryAgentOverridesSchema).default({})
77224
77294
  }).strict();
@@ -77266,6 +77336,21 @@ var init_model_catalog = __esm(() => {
77266
77336
  OmoModelCatalogLayerSchema = record(string2(), OmoModelCatalogEntryLayerSchema);
77267
77337
  });
77268
77338
 
77339
+ // packages/omo-config-core/src/schema/model-pad.ts
77340
+ var OmoModelPadLabelsSchema, OmoModelPadSchema;
77341
+ var init_model_pad = __esm(() => {
77342
+ init_zod();
77343
+ OmoModelPadLabelsSchema = object({
77344
+ daily: string2().optional(),
77345
+ geeky: string2().optional(),
77346
+ normal: string2().optional(),
77347
+ heavy: string2().optional()
77348
+ }).strict();
77349
+ OmoModelPadSchema = object({
77350
+ labels: OmoModelPadLabelsSchema.optional()
77351
+ }).strict();
77352
+ });
77353
+
77269
77354
  // packages/omo-config-core/src/schema/model-profile.ts
77270
77355
  function isRecord8(value) {
77271
77356
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -77586,6 +77671,7 @@ var init_config = __esm(() => {
77586
77671
  init_git_master();
77587
77672
  init_memory();
77588
77673
  init_model_catalog();
77674
+ init_model_pad();
77589
77675
  init_model_profile();
77590
77676
  init_side_panel();
77591
77677
  init_task();
@@ -77607,6 +77693,7 @@ var init_config = __esm(() => {
77607
77693
  models: OmoModelCatalogLayerSchema.optional(),
77608
77694
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77609
77695
  model_profile: string2().optional(),
77696
+ model_pad: OmoModelPadSchema.optional(),
77610
77697
  memory: OmoMemorySettingsLayerSchema.optional(),
77611
77698
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77612
77699
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77625,6 +77712,7 @@ var init_config = __esm(() => {
77625
77712
  models: OmoModelCatalogLayerSchema.optional(),
77626
77713
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77627
77714
  model_profile: string2().optional(),
77715
+ model_pad: OmoModelPadSchema.optional(),
77628
77716
  memory: OmoMemorySettingsLayerSchema.optional(),
77629
77717
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77630
77718
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77648,6 +77736,7 @@ var init_config = __esm(() => {
77648
77736
  models: OmoModelCatalogSchema.optional(),
77649
77737
  model_profiles: OmoModelProfilesSchema.optional(),
77650
77738
  model_profile: string2().optional(),
77739
+ model_pad: OmoModelPadSchema.optional(),
77651
77740
  memory: OmoMemorySettingsSchema.optional(),
77652
77741
  telemetry: OmoTelemetrySettingsSchema.optional(),
77653
77742
  side_panel: OmoSidePanelSettingsSchema.optional(),
@@ -77674,6 +77763,7 @@ var init_config = __esm(() => {
77674
77763
  models: OmoModelCatalogLayerSchema.optional(),
77675
77764
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77676
77765
  model_profile: string2().optional(),
77766
+ model_pad: OmoModelPadSchema.optional(),
77677
77767
  memory: OmoMemorySettingsLayerSchema.optional(),
77678
77768
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77679
77769
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77819,6 +77909,7 @@ var init_schema = __esm(() => {
77819
77909
  init_legacy_harness_names();
77820
77910
  init_memory();
77821
77911
  init_model_catalog();
77912
+ init_model_pad();
77822
77913
  init_model_profile();
77823
77914
  init_model_ref();
77824
77915
  init_provenance();
@@ -82839,6 +82930,37 @@ function getDefaultTelemetryOsProvider() {
82839
82930
  }
82840
82931
  var init_machine_id = () => {};
82841
82932
 
82933
+ // packages/telemetry-core/src/terminal-program.ts
82934
+ function isKnownTerminalProgram(value) {
82935
+ return KNOWN_TERMINAL_PROGRAMS.some((known) => known === value);
82936
+ }
82937
+ function toTelemetryTerminalProgram(termProgram) {
82938
+ if (termProgram === undefined || termProgram === "")
82939
+ return;
82940
+ return isKnownTerminalProgram(termProgram) ? termProgram : "other";
82941
+ }
82942
+ var KNOWN_TERMINAL_PROGRAMS;
82943
+ var init_terminal_program = __esm(() => {
82944
+ KNOWN_TERMINAL_PROGRAMS = [
82945
+ "Apple_Terminal",
82946
+ "iTerm.app",
82947
+ "vscode",
82948
+ "cursor",
82949
+ "windsurf",
82950
+ "zed",
82951
+ "WezTerm",
82952
+ "ghostty",
82953
+ "tmux",
82954
+ "Hyper",
82955
+ "WarpTerminal",
82956
+ "kitty",
82957
+ "alacritty",
82958
+ "Tabby",
82959
+ "rio",
82960
+ "mintty"
82961
+ ];
82962
+ });
82963
+
82842
82964
  // packages/telemetry-core/src/injected-client.ts
82843
82965
  function isTelemetryClientEnabled(input) {
82844
82966
  const env = input.env ?? process.env;
@@ -82941,12 +83063,16 @@ function getSharedProperties(input) {
82941
83063
  total_memory_gb: Math.round(osProvider.totalmem() / 1024 / 1024 / 1024),
82942
83064
  locale: Intl.DateTimeFormat().resolvedOptions().locale,
82943
83065
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
82944
- shell: process.env.SHELL,
83066
+ shell: getShellName(process.env.SHELL),
82945
83067
  ci: Boolean(process.env.CI),
82946
- terminal: process.env.TERM_PROGRAM,
83068
+ terminal: toTelemetryTerminalProgram(process.env.TERM_PROGRAM),
82947
83069
  ...input.product.additionalProperties
82948
83070
  };
82949
83071
  }
83072
+ function getShellName(shellPath) {
83073
+ const name = shellPath?.split(/[\\/]/).pop()?.replace(/\.exe$/i, "");
83074
+ return name ? name : undefined;
83075
+ }
82950
83076
  function getSafeCpuInfo(osProvider, input) {
82951
83077
  try {
82952
83078
  const cpuInfo = osProvider.cpus();
@@ -82971,6 +83097,7 @@ var NO_OP_CLIENT;
82971
83097
  var init_injected_client = __esm(() => {
82972
83098
  init_env();
82973
83099
  init_machine_id();
83100
+ init_terminal_program();
82974
83101
  NO_OP_CLIENT = {
82975
83102
  enabled: false,
82976
83103
  trackActive: () => {
@@ -92550,7 +92677,7 @@ var package_default2;
92550
92677
  var init_package2 = __esm(() => {
92551
92678
  package_default2 = {
92552
92679
  name: "@oh-my-opencode/omo-codex",
92553
- version: "5.1.51",
92680
+ version: "5.1.54",
92554
92681
  type: "module",
92555
92682
  private: true,
92556
92683
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -93758,11 +93885,22 @@ init_commander();
93758
93885
  // packages/omo-opencode/src/cli/install.ts
93759
93886
  init_package();
93760
93887
 
93888
+ // packages/omo-opencode/src/cli/cli-installer.ts
93889
+ import { createInterface as createInterface2 } from "readline/promises";
93890
+
93891
+ // packages/telemetry-core/src/install-disclosure.ts
93892
+ var TELEMETRY_PRIVACY_POLICY_URL = "https://github.com/code-yeongyu/oh-my-openagent/blob/dev/docs/legal/privacy-policy.md";
93893
+ var TELEMETRY_INSTALL_DISCLOSURE_LINES = [
93894
+ "OmO sends anonymous usage telemetry (no prompts, code, file paths, or account data) to improve the product.",
93895
+ "The data goes to PostHog in the United States.",
93896
+ "Turn it off with DO_NOT_TRACK=1 (or OMO_DISABLE_TELEMETRY=1).",
93897
+ `Details: ${TELEMETRY_PRIVACY_POLICY_URL}`
93898
+ ];
93899
+
93761
93900
  // packages/omo-opencode/src/cli/cli-installer.ts
93762
93901
  init_shared();
93763
93902
  init_config_manager();
93764
93903
  var import_picocolors3 = __toESM(require_picocolors(), 1);
93765
- import { createInterface as createInterface2 } from "readline/promises";
93766
93904
 
93767
93905
  // packages/omo-opencode/src/cli/install-validators.ts
93768
93906
  var import_picocolors = __toESM(require_picocolors(), 1);
@@ -99923,6 +100061,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
99923
100061
  join66("extensions", "omo-thread-client.js"),
99924
100062
  join66("extensions", "omo-telemetry-recovery.js"),
99925
100063
  join66("extensions", "omo-feedback.js"),
100064
+ join66("extensions", "omo-desktop-toolkit.js"),
99926
100065
  join66("extensions", "omo-claim-receipt.js"),
99927
100066
  join66("extensions", "assets.generated.json"),
99928
100067
  join66("extensions", "omo-member.js"),
@@ -101201,8 +101340,8 @@ async function runCliInstaller(args, version) {
101201
101340
  }
101202
101341
  console.log();
101203
101342
  }
101204
- printInfo("Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.");
101205
- printInfo("Docs: docs/legal/privacy-policy.md and docs/legal/terms-of-service.md");
101343
+ for (const line of TELEMETRY_INSTALL_DISCLOSURE_LINES)
101344
+ printInfo(line);
101206
101345
  console.log();
101207
101346
  printBox(`${import_picocolors3.default.bold("Pro Tip:")} Include ${import_picocolors3.default.cyan("ultrawork")} (or ${import_picocolors3.default.cyan("ulw")}) in your prompt.
101208
101347
  ` + `All features work like magic-parallel agents, background tasks,
@@ -102498,7 +102637,7 @@ async function promptInstallConfig(detected, platform, codexAutonomousOverride)
102498
102637
  message: "Do you have a Kimi For Coding subscription?",
102499
102638
  options: [
102500
102639
  { value: "no", label: "No", hint: "Will use other configured providers" },
102501
- { value: "yes", label: "Yes", hint: "Kimi K3 for Sisyphus/Prometheus fallback" }
102640
+ { value: "yes", label: "Yes", hint: "Kimi K3.1 Pro for Sisyphus/Prometheus fallback" }
102502
102641
  ],
102503
102642
  initialValue: initial.kimiForCoding
102504
102643
  });
@@ -102757,8 +102896,8 @@ async function runTuiInstaller(args, version) {
102757
102896
  if (config.hasOpenCode) {
102758
102897
  log4.message(`Run ${import_picocolors4.default.cyan("opencode")} to start!`);
102759
102898
  }
102760
- log4.info("Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.");
102761
- log4.info("Docs: docs/legal/privacy-policy.md and docs/legal/terms-of-service.md");
102899
+ log4.info(TELEMETRY_INSTALL_DISCLOSURE_LINES.join(`
102900
+ `));
102762
102901
  note(`Include ${import_picocolors4.default.cyan("ultrawork")} (or ${import_picocolors4.default.cyan("ulw")}) in your prompt.
102763
102902
  ` + `All features work like magic-parallel agents, background tasks,
102764
102903
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
@@ -109295,6 +109434,8 @@ var package_default3 = {
109295
109434
  },
109296
109435
  dependencies: {
109297
109436
  "@clack/prompts": "^1.8.1",
109437
+ "@code-yeongyu/senpi": "2026.10.30-1",
109438
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.30-1",
109298
109439
  "@modelcontextprotocol/sdk": "^1.30.0",
109299
109440
  "@oh-my-opencode/agents-md-core": "workspace:*",
109300
109441
  "@oh-my-opencode/boulder-state": "workspace:*",
@@ -110603,6 +110744,8 @@ function isOAuthTokenData(value) {
110603
110744
  if (typeof value !== "object" || value === null || Array.isArray(value))
110604
110745
  return false;
110605
110746
  const record = value;
110747
+ if (record["issuer"] !== undefined && typeof record["issuer"] !== "string")
110748
+ return false;
110606
110749
  if (typeof record["accessToken"] !== "string")
110607
110750
  return false;
110608
110751
  const refreshToken = record["refreshToken"];
@@ -110617,6 +110760,8 @@ function isOAuthTokenData(value) {
110617
110760
  if (typeof clientInfo !== "object" || clientInfo === null || Array.isArray(clientInfo))
110618
110761
  return false;
110619
110762
  const clientRecord = clientInfo;
110763
+ if (clientRecord["issuer"] !== undefined && typeof clientRecord["issuer"] !== "string")
110764
+ return false;
110620
110765
  if (typeof clientRecord["clientId"] !== "string")
110621
110766
  return false;
110622
110767
  const clientSecret = clientRecord["clientSecret"];
@@ -110685,7 +110830,9 @@ function deleteToken(serverHost, resource) {
110685
110830
  return deleteLegacyToken(serverHost, resource);
110686
110831
  try {
110687
110832
  unlinkSync9(filePath);
110688
- return deleteTokenIndexEntry(getMcpOauthStorageDir(), getMcpOauthServerHash(serverHost, resource));
110833
+ const indexDeleted = deleteTokenIndexEntry(getMcpOauthStorageDir(), getMcpOauthServerHash(serverHost, resource));
110834
+ const legacyDeleted = deleteLegacyToken(serverHost, resource);
110835
+ return indexDeleted && legacyDeleted;
110689
110836
  } catch (deleteError) {
110690
110837
  if (!(deleteError instanceof Error))
110691
110838
  throw deleteError;
@@ -110795,19 +110942,26 @@ async function fetchMetadata(url) {
110795
110942
  }
110796
110943
  return { ok: true, json };
110797
110944
  }
110798
- function parseMetadataFields(json, resource) {
110945
+ function parseMetadataFields(json, resource, expectedIssuer) {
110946
+ const issuer = readStringField(json, "issuer");
110947
+ parseHttpsUrl(issuer, "issuer");
110948
+ if (issuer !== expectedIssuer) {
110949
+ throw new Error("OAuth metadata issuer mismatch");
110950
+ }
110799
110951
  const authorizationEndpoint = parseHttpsUrl(readStringField(json, "authorization_endpoint"), "authorization_endpoint").toString();
110800
110952
  const tokenEndpoint = parseHttpsUrl(readStringField(json, "token_endpoint"), "token_endpoint").toString();
110801
110953
  const registrationEndpointValue = json.registration_endpoint;
110802
110954
  const registrationEndpoint = typeof registrationEndpointValue === "string" && registrationEndpointValue.length > 0 ? parseHttpsUrl(registrationEndpointValue, "registration_endpoint").toString() : undefined;
110803
110955
  return {
110956
+ issuer,
110957
+ ...json.authorization_response_iss_parameter_supported === true ? { authorizationResponseIssParameterSupported: true } : {},
110804
110958
  authorizationEndpoint,
110805
110959
  tokenEndpoint,
110806
110960
  registrationEndpoint,
110807
110961
  resource
110808
110962
  };
110809
110963
  }
110810
- async function fetchAuthorizationServerMetadata(issuer, resource) {
110964
+ async function fetchAuthorizationServerMetadata(issuer, resource, allowOriginFallback = false) {
110811
110965
  const issuerUrl = parseHttpsUrl(issuer, "Authorization server URL");
110812
110966
  const issuerPath = issuerUrl.pathname.replace(/\/+$/, "");
110813
110967
  const metadataUrl = new URL(`/.well-known/oauth-authorization-server${issuerPath}`, issuerUrl).toString();
@@ -110817,7 +110971,7 @@ async function fetchAuthorizationServerMetadata(issuer, resource) {
110817
110971
  const rootMetadataUrl = new URL("/.well-known/oauth-authorization-server", issuerUrl).toString();
110818
110972
  const rootMetadata = await fetchMetadata(rootMetadataUrl);
110819
110973
  if (rootMetadata.ok) {
110820
- return parseMetadataFields(rootMetadata.json, resource);
110974
+ return parseMetadataFields(rootMetadata.json, resource, allowOriginFallback ? issuerUrl.origin : issuer);
110821
110975
  }
110822
110976
  }
110823
110977
  if (metadata.status === 404) {
@@ -110825,7 +110979,7 @@ async function fetchAuthorizationServerMetadata(issuer, resource) {
110825
110979
  }
110826
110980
  throw new Error(`OAuth authorization server metadata fetch failed (${metadata.status})`);
110827
110981
  }
110828
- return parseMetadataFields(metadata.json, resource);
110982
+ return parseMetadataFields(metadata.json, resource, issuer);
110829
110983
  }
110830
110984
  function parseAuthorizationServers(metadata) {
110831
110985
  const servers = metadata.authorization_servers;
@@ -110833,11 +110987,11 @@ function parseAuthorizationServers(metadata) {
110833
110987
  return [];
110834
110988
  return servers.filter((server) => typeof server === "string" && server.length > 0);
110835
110989
  }
110836
- async function discoverOAuthServerMetadata(resource) {
110990
+ async function discoverOAuthServerMetadata(resource, forceRefresh = false) {
110837
110991
  const resourceUrl = parseHttpsUrl(resource, "Resource server URL");
110838
110992
  const resourceKey = resourceUrl.toString();
110839
110993
  const cached = discoveryCache.get(resourceKey);
110840
- if (cached)
110994
+ if (cached && !forceRefresh)
110841
110995
  return cached;
110842
110996
  const pending = pendingDiscovery.get(resourceKey);
110843
110997
  if (pending)
@@ -110855,7 +111009,7 @@ async function discoverOAuthServerMetadata(resource) {
110855
111009
  if (prmResponse.status !== 404) {
110856
111010
  throw new Error(`OAuth protected resource metadata fetch failed (${prmResponse.status})`);
110857
111011
  }
110858
- return fetchAuthorizationServerMetadata(resourceKey, resource);
111012
+ return fetchAuthorizationServerMetadata(resource.replace(/\/+$/, ""), resource, true);
110859
111013
  })();
110860
111014
  pendingDiscovery.set(resourceKey, discoveryPromise);
110861
111015
  try {
@@ -110879,6 +111033,10 @@ async function getOrRegisterClient(options) {
110879
111033
  }
110880
111034
  const fetchImpl = options.fetch ?? globalThis.fetch;
110881
111035
  const request = {
111036
+ application_type: options.redirectUris.some((uri) => {
111037
+ const url = new URL(uri);
111038
+ return (url.protocol === "http:" || url.protocol === "https:") && !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname);
111039
+ }) ? "web" : "native",
110882
111040
  redirect_uris: options.redirectUris,
110883
111041
  client_name: options.clientName,
110884
111042
  grant_types: ["authorization_code", "refresh_token"],
@@ -110955,12 +111113,20 @@ function buildAuthorizationUrl(authorizationEndpoint, options) {
110955
111113
  return url.toString();
110956
111114
  }
110957
111115
  var CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
110958
- function startCallbackServer(port) {
111116
+ function startCallbackServer(port, validation) {
110959
111117
  return new Promise((resolve, reject) => {
110960
111118
  let timeoutId;
110961
111119
  const server = createServer2((request, response) => {
110962
111120
  clearTimeout(timeoutId);
110963
111121
  const requestUrl = new URL(request.url ?? "/", `http://localhost:${port}`);
111122
+ const issuer = requestUrl.searchParams.get("iss");
111123
+ if (validation && (issuer !== null && issuer !== validation.issuer || issuer === null && validation.authorizationResponseIssParameterSupported)) {
111124
+ response.writeHead(400, { "content-type": "text/html" });
111125
+ response.end("<html><body><h1>Authorization failed</h1></body></html>");
111126
+ server.close();
111127
+ reject(new Error("OAuth authorization response issuer mismatch or missing issuer"));
111128
+ return;
111129
+ }
110964
111130
  const code = requestUrl.searchParams.get("code");
110965
111131
  const state = requestUrl.searchParams.get("state");
110966
111132
  const error = requestUrl.searchParams.get("error");
@@ -111030,7 +111196,7 @@ async function runAuthorizationCodeRedirect(options) {
111030
111196
  scopes: options.scopes,
111031
111197
  resource: options.resource
111032
111198
  });
111033
- const callbackPromise = startCallbackServer(options.callbackPort);
111199
+ const callbackPromise = startCallbackServer(options.callbackPort, options);
111034
111200
  openBrowser(authorizationUrl);
111035
111201
  const result = await callbackPromise;
111036
111202
  if (result.state !== state) {
@@ -111065,10 +111231,12 @@ function buildOAuthTokenData(tokenData, clientInfo, fallbackRefreshToken) {
111065
111231
  throw new Error("Token response missing access_token");
111066
111232
  }
111067
111233
  return {
111234
+ ...clientInfo.issuer ? { issuer: clientInfo.issuer } : {},
111068
111235
  accessToken,
111069
111236
  refreshToken: typeof tokenData["refresh_token"] === "string" ? tokenData["refresh_token"] : fallbackRefreshToken,
111070
111237
  expiresAt: typeof tokenData["expires_in"] === "number" ? Math.floor(Date.now() / 1000) + tokenData["expires_in"] : undefined,
111071
111238
  clientInfo: {
111239
+ ...clientInfo.issuer ? { issuer: clientInfo.issuer } : {},
111072
111240
  clientId: clientInfo.clientId,
111073
111241
  ...clientInfo.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
111074
111242
  }
@@ -111082,6 +111250,7 @@ class McpOAuthProvider {
111082
111250
  storedCodeVerifier = null;
111083
111251
  storedClientInfo = null;
111084
111252
  callbackPort = null;
111253
+ issuer;
111085
111254
  constructor(options) {
111086
111255
  this.serverUrl = options.serverUrl;
111087
111256
  this.configClientId = options.clientId;
@@ -111091,7 +111260,32 @@ class McpOAuthProvider {
111091
111260
  return loadToken(this.serverUrl, this.serverUrl);
111092
111261
  }
111093
111262
  saveTokens(tokenData) {
111094
- return saveToken(this.serverUrl, this.serverUrl, tokenData);
111263
+ const issuer = tokenData.issuer ?? this.issuer;
111264
+ return saveToken(this.serverUrl, this.serverUrl, issuer ? {
111265
+ ...tokenData,
111266
+ issuer,
111267
+ ...tokenData.clientInfo ? { clientInfo: { ...tokenData.clientInfo, issuer: tokenData.clientInfo.issuer ?? issuer } } : {}
111268
+ } : tokenData);
111269
+ }
111270
+ bindIssuer(issuer) {
111271
+ const token = this.tokens();
111272
+ const stamps = [token?.issuer, token?.clientInfo?.issuer, this.storedClientInfo?.issuer, this.issuer];
111273
+ const changed = stamps.some((stamp) => stamp !== undefined && stamp !== issuer);
111274
+ if (changed) {
111275
+ this.storedClientInfo = null;
111276
+ this.storedCodeVerifier = null;
111277
+ if (!deleteToken(this.serverUrl, this.serverUrl)) {
111278
+ throw new Error("Unable to discard credentials for the previous OAuth issuer");
111279
+ }
111280
+ }
111281
+ this.issuer = issuer;
111282
+ if (!changed && token && !this.saveTokens(token)) {
111283
+ throw new Error("Unable to stamp stored OAuth credentials with their issuer");
111284
+ }
111285
+ const clientInfo = this.clientInformation();
111286
+ if (clientInfo)
111287
+ this.storedClientInfo = { ...clientInfo, issuer };
111288
+ return changed;
111095
111289
  }
111096
111290
  clientInformation() {
111097
111291
  if (this.storedClientInfo)
@@ -111121,6 +111315,8 @@ class McpOAuthProvider {
111121
111315
  this.callbackPort = await findAvailablePort2();
111122
111316
  }
111123
111317
  const result = await runAuthorizationCodeRedirect({
111318
+ issuer: metadata.issuer,
111319
+ authorizationResponseIssParameterSupported: metadata.authorizationResponseIssParameterSupported,
111124
111320
  authorizationEndpoint: metadata.authorizationEndpoint,
111125
111321
  callbackPort: this.callbackPort,
111126
111322
  clientId: clientInfo.clientId,
@@ -111132,16 +111328,19 @@ class McpOAuthProvider {
111132
111328
  return { code: result.code };
111133
111329
  }
111134
111330
  async login() {
111135
- const metadata = await discoverOAuthServerMetadata(this.serverUrl);
111331
+ const metadata = await discoverOAuthServerMetadata(this.serverUrl, true);
111332
+ this.bindIssuer(metadata.issuer);
111333
+ if (this.callbackPort === null)
111334
+ this.callbackPort = await findAvailablePort2();
111136
111335
  const clientRegistrationStorage = {
111137
111336
  getClientRegistration: () => this.storedClientInfo,
111138
111337
  setClientRegistration: (_serverIdentifier, credentials) => {
111139
- this.storedClientInfo = credentials;
111338
+ this.storedClientInfo = { ...credentials, issuer: metadata.issuer };
111140
111339
  }
111141
111340
  };
111142
111341
  const clientInfo = await getOrRegisterClient({
111143
111342
  ...metadata.registrationEndpoint ? { registrationEndpoint: metadata.registrationEndpoint } : {},
111144
- serverIdentifier: this.serverUrl,
111343
+ serverIdentifier: metadata.issuer,
111145
111344
  clientName: PLUGIN_NAME4,
111146
111345
  redirectUris: [this.redirectUrl()],
111147
111346
  tokenEndpointAuthMethod: "none",
@@ -111151,7 +111350,7 @@ class McpOAuthProvider {
111151
111350
  if (!clientInfo) {
111152
111351
  throw new Error("Failed to obtain client credentials. Provide a clientId or ensure the server supports DCR.");
111153
111352
  }
111154
- this.storedClientInfo = clientInfo;
111353
+ this.storedClientInfo = { ...clientInfo, issuer: metadata.issuer };
111155
111354
  const { code } = await this.redirectToAuthorization(metadata);
111156
111355
  const verifier = this.codeVerifier();
111157
111356
  if (!verifier) {
@@ -111170,12 +111369,14 @@ class McpOAuthProvider {
111170
111369
  }).toString()
111171
111370
  });
111172
111371
  const tokenData = await parseTokenResponse(tokenResponse);
111173
- const oauthTokenData = buildOAuthTokenData(tokenData, clientInfo);
111372
+ const oauthTokenData = buildOAuthTokenData(tokenData, { ...clientInfo, issuer: metadata.issuer });
111174
111373
  this.saveTokens(oauthTokenData);
111175
111374
  return oauthTokenData;
111176
111375
  }
111177
111376
  async refresh(refreshToken) {
111178
- const metadata = await discoverOAuthServerMetadata(this.serverUrl);
111377
+ const metadata = await discoverOAuthServerMetadata(this.serverUrl, true);
111378
+ if (this.bindIssuer(metadata.issuer))
111379
+ return this.login();
111179
111380
  const clientInfo = this.clientInformation();
111180
111381
  const clientId = clientInfo?.clientId ?? this.configClientId;
111181
111382
  if (!clientId) {
@@ -111195,6 +111396,7 @@ class McpOAuthProvider {
111195
111396
  const tokenData = await parseTokenResponse(tokenResponse);
111196
111397
  const oauthTokenData = buildOAuthTokenData(tokenData, {
111197
111398
  clientId,
111399
+ issuer: metadata.issuer,
111198
111400
  ...clientInfo?.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
111199
111401
  }, refreshToken);
111200
111402
  this.saveTokens(oauthTokenData);
@@ -112042,6 +112244,17 @@ import { hostname } from "os";
112042
112244
  // packages/omo-opencode/src/cli/service-auth/protocol.ts
112043
112245
  init_zod();
112044
112246
 
112247
+ // packages/omo-opencode/src/cli/service-auth/credential-owner.ts
112248
+ init_zod();
112249
+ var identity = string2().regex(/^[A-Za-z0-9_-]{1,128}$/);
112250
+ var credentialOwnerSchema = object({
112251
+ accountId: identity,
112252
+ deviceId: identity,
112253
+ familyId: identity,
112254
+ generation: number2().int().positive().safe(),
112255
+ ownerHandle: string2().regex(/^[\x21-\x7e]{1,4096}$/)
112256
+ });
112257
+
112045
112258
  // packages/omo-opencode/src/cli/service-auth/terminal-text.ts
112046
112259
  import { stripVTControlCharacters as stripVTControlCharacters4 } from "util";
112047
112260
  function terminalText(value) {
@@ -112060,9 +112273,19 @@ class SignInError extends Error {
112060
112273
 
112061
112274
  class RequestFailure extends SignInError {
112062
112275
  notSent;
112063
- constructor(notSent) {
112276
+ responseStatus;
112277
+ constructor(notSent, responseStatus) {
112064
112278
  super("Unable to complete the service request. Check the connection and retry.", true);
112065
112279
  this.notSent = notSent;
112280
+ this.responseStatus = responseStatus;
112281
+ }
112282
+ }
112283
+
112284
+ class InvalidApiResponse extends SignInError {
112285
+ status;
112286
+ constructor(status) {
112287
+ super("The service returned an invalid error response.");
112288
+ this.status = status;
112066
112289
  }
112067
112290
  }
112068
112291
  var platformSchema = _enum(["macos", "linux", "windows"]);
@@ -112075,12 +112298,18 @@ var tokenSchema = object({
112075
112298
  });
112076
112299
  var grantSchema = tokenSchema.extend({
112077
112300
  device: object({ id: nonempty, name: nonempty }),
112078
- offlineGrant: nonempty.optional()
112301
+ offlineGrant: nonempty.optional(),
112302
+ owner: credentialOwnerSchema.optional(),
112303
+ writerFloor: union([literal(1), literal(2)]).optional(),
112304
+ freshAuthorizationProof: nonempty.optional()
112079
112305
  });
112080
112306
  var credentialSchema = grantSchema.extend({
112081
112307
  signingPrivateKey: nonempty,
112082
112308
  sealingPrivateKey: nonempty,
112083
- refreshState: literal("uncertain").optional()
112309
+ refreshState: literal("uncertain").optional(),
112310
+ credentialGeneration: nonempty.optional(),
112311
+ accountId: nonempty.optional(),
112312
+ refreshAttempt: unknown().optional()
112084
112313
  });
112085
112314
  var deviceCodeSchema = object({
112086
112315
  deviceCode: string2().regex(/^dc\.[A-Za-z0-9_-]{43}$/),
@@ -112108,6 +112337,9 @@ var limitSchema = object({
112108
112337
  var deviceListSchema = object({
112109
112338
  devices: array(object({ id: nonempty, name: nonempty, revokedAt: timestamp.nullable() }))
112110
112339
  });
112340
+ var currentDeviceListSchema = object({
112341
+ devices: array(object({ id: nonempty, current: boolean2(), revokedAt: timestamp.nullable() }))
112342
+ });
112111
112343
  var REFUSAL_CODES = [
112112
112344
  "unauthorized",
112113
112345
  "account_deleted",
@@ -112124,7 +112356,11 @@ var REFUSAL_CODES = [
112124
112356
  "unavailable",
112125
112357
  "forbidden",
112126
112358
  "invalid_request",
112127
- "not_found"
112359
+ "not_found",
112360
+ "client_upgrade_required",
112361
+ "writer_floor_mismatch",
112362
+ "service_upgrade_required",
112363
+ "refresh_recovery_expired"
112128
112364
  ];
112129
112365
  var isKnownRefusal = (code) => REFUSAL_CODES.includes(code);
112130
112366
  function refusalGuidance(code, status) {
@@ -112151,6 +112387,10 @@ function refusalGuidance(code, status) {
112151
112387
  case "access_denied":
112152
112388
  case "authorization_pending":
112153
112389
  return "account_refused";
112390
+ case "client_upgrade_required":
112391
+ case "writer_floor_mismatch":
112392
+ case "service_upgrade_required":
112393
+ case "refresh_recovery_expired":
112154
112394
  case "unknown":
112155
112395
  if (status === 401)
112156
112396
  return "sign_in_again";
@@ -112261,13 +112501,13 @@ async function requestApi(api, path, init, signal) {
112261
112501
  try {
112262
112502
  body = await response.json();
112263
112503
  } catch {
112264
- throw new RequestFailure(false);
112504
+ throw new RequestFailure(false, response.status);
112265
112505
  }
112266
112506
  if (response.ok)
112267
112507
  return body;
112268
112508
  const envelope = envelopeSchema.safeParse(body);
112269
112509
  if (!envelope.success)
112270
- throw new SignInError("The service returned an invalid error response.");
112510
+ throw new InvalidApiResponse(response.status);
112271
112511
  const error = envelope.data.error;
112272
112512
  const detail = limitSchema.safeParse(error.detail);
112273
112513
  throw new ApiRefusal(error.code, response.status, error.code === "entitlement_required" && detail.success ? detail.data : undefined, response.headers.get("retry-after"));
@@ -112371,7 +112611,7 @@ async function loginDevice(session, options) {
112371
112611
  }
112372
112612
 
112373
112613
  // packages/omo-opencode/src/cli/service-auth/keystore.ts
112374
- import { createHash as createHash10 } from "crypto";
112614
+ import { createHash as createHash12, randomUUID as randomUUID7 } from "crypto";
112375
112615
  import { basename as basename15 } from "path";
112376
112616
 
112377
112617
  // packages/omo-opencode/src/cli/service-auth/secret-service-lock.ts
@@ -112415,289 +112655,490 @@ var probeSecretServiceLock = () => new Promise((resolve) => {
112415
112655
  });
112416
112656
  });
112417
112657
 
112418
- // packages/omo-opencode/src/cli/service-auth/keystore.ts
112419
- class CredentialStoreError extends SignInError {
112420
- }
112658
+ // packages/omo-opencode/src/cli/service-auth/credential-lock.ts
112659
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
112660
+ import { createHash as createHash11 } from "crypto";
112661
+ import { mkdir as mkdir11 } from "fs/promises";
112662
+ import { homedir as homedir31 } from "os";
112663
+ import { join as join106 } from "path";
112421
112664
 
112422
- class KeychainLockedError extends CredentialStoreError {
112665
+ // packages/team-core/src/team-state-store/lock-publish.ts
112666
+ import { access as access4, open as open3, unlink as unlink3 } from "fs/promises";
112667
+ import { dirname as dirname42 } from "path";
112668
+
112669
+ // packages/team-core/src/team-state-store/lock-record.ts
112670
+ import { randomUUID as randomUUID6 } from "crypto";
112671
+ import { readFile as readFile34, stat as stat9 } from "fs/promises";
112672
+
112673
+ // packages/memory-core/src/locks/process-identity.ts
112674
+ import { execFile as execFile7 } from "child_process";
112675
+
112676
+ // packages/memory-core/src/fs/resilient.ts
112677
+ import * as fsSync from "fs";
112678
+ import * as fsp from "fs/promises";
112679
+
112680
+ // packages/memory-core/src/fs/retry.ts
112681
+ var EINTR_RETRY_CAP = 128;
112682
+ function fsErrorCode(error) {
112683
+ if (!(error instanceof Error) || !("code" in error))
112684
+ return;
112685
+ return typeof error.code === "string" ? error.code : undefined;
112423
112686
  }
112424
- class InvalidCredentialState extends SignInError {
112687
+ async function retryOnEintr(operation) {
112688
+ for (let attempt = 0;; attempt += 1) {
112689
+ try {
112690
+ return await operation();
112691
+ } catch (error) {
112692
+ if (fsErrorCode(error) !== "EINTR" || attempt >= EINTR_RETRY_CAP)
112693
+ throw error;
112694
+ }
112695
+ }
112696
+ }
112697
+ function retryOnEintrSync(operation) {
112698
+ for (let attempt = 0;; attempt += 1) {
112699
+ try {
112700
+ return operation();
112701
+ } catch (error) {
112702
+ if (fsErrorCode(error) !== "EINTR" || attempt >= EINTR_RETRY_CAP)
112703
+ throw error;
112704
+ }
112705
+ }
112425
112706
  }
112426
112707
 
112427
- class KeychainApprovalPendingError extends CredentialStoreError {
112708
+ // packages/memory-core/src/fs/rename-contention.ts
112709
+ var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
112710
+
112711
+ // packages/memory-core/src/fs/resilient.ts
112712
+ function isFunction2(value) {
112713
+ return typeof value === "function";
112428
112714
  }
112429
- var SESSION_READ_WAIT = { kind: "bounded", deadlineMs: 5000 };
112430
- var INTERACTIVE_READ_WAIT = {
112431
- kind: "interactive",
112432
- noticeAfterMs: 2000,
112433
- notice: (message) => process.stderr.write(`${message}
112434
- `)
112435
- };
112436
- var processReads = new WeakMap;
112437
- var LOCKED = /-25308|errSecInteractionNotAllowed|interaction is not allowed|locked collection/i;
112438
- var UNLOCKED_REUSE_MS = 30000;
112439
- var fallbackNoticed = false;
112440
- var stderrNoticeOncePerProcess = (message) => {
112441
- if (fallbackNoticed)
112715
+ function withAsyncRetry(operation) {
112716
+ return (...args) => retryOnEintr(async () => operation(...args));
112717
+ }
112718
+ function withSyncRetry(operation) {
112719
+ return (...args) => retryOnEintrSync(() => operation(...args));
112720
+ }
112721
+ function resilientNamespace(namespace, kind) {
112722
+ const wrapFunction = kind === "async" ? withAsyncRetry : withSyncRetry;
112723
+ const cache = new Map;
112724
+ return new Proxy(namespace, {
112725
+ get(target, property) {
112726
+ if (cache.has(property))
112727
+ return cache.get(property);
112728
+ const value = Reflect.get(target, property);
112729
+ if (!isFunction2(value))
112730
+ return value;
112731
+ const wrapped = wrapFunction(value);
112732
+ const native = Reflect.get(value, "native");
112733
+ if (isFunction2(native))
112734
+ Object.assign(wrapped, { native: wrapFunction(native) });
112735
+ cache.set(property, wrapped);
112736
+ return wrapped;
112737
+ }
112738
+ });
112739
+ }
112740
+ var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
112741
+ var promises = resilientNamespace(fsp, "async");
112742
+ var sync = resilientNamespace(fsSync, "sync");
112743
+ var {
112744
+ access: access3,
112745
+ chmod: chmod2,
112746
+ copyFile: copyFile4,
112747
+ cp: cp5,
112748
+ link,
112749
+ lstat: lstat18,
112750
+ mkdir: mkdir10,
112751
+ mkdtemp: mkdtemp2,
112752
+ readFile: readFile33,
112753
+ readdir: readdir17,
112754
+ readlink: readlink7,
112755
+ realpath: realpath2,
112756
+ rm: rm16,
112757
+ rmdir: rmdir2,
112758
+ stat: stat8,
112759
+ statfs,
112760
+ unlink: unlink2
112761
+ } = promises;
112762
+ var {
112763
+ accessSync: accessSync5,
112764
+ chmodSync: chmodSync7,
112765
+ fsyncSync: fsyncSync3,
112766
+ linkSync,
112767
+ lstatSync: lstatSync5,
112768
+ mkdirSync: mkdirSync19,
112769
+ readFileSync: readFileSync44,
112770
+ readdirSync: readdirSync14,
112771
+ realpathSync: realpathSync13,
112772
+ statSync: statSync8,
112773
+ unlinkSync: unlinkSync10,
112774
+ writeFileSync: writeFileSync17,
112775
+ writeSync
112776
+ } = sync;
112777
+
112778
+ // packages/memory-core/src/locks/process-start-time.ts
112779
+ var PROC_PIDTBSDINFO = 3;
112780
+ var PROC_BSDINFO_SIZE = 136;
112781
+ var START_TVSEC_OFFSET = 120;
112782
+ var procPidInfoLookup = null;
112783
+ async function openProcPidInfo() {
112784
+ if (process.platform !== "darwin")
112785
+ return null;
112786
+ try {
112787
+ const { dlopen, FFIType } = await import("bun:ffi");
112788
+ const library = dlopen("/usr/lib/libSystem.B.dylib", {
112789
+ proc_pidinfo: {
112790
+ args: [FFIType.i32, FFIType.i32, FFIType.u64, FFIType.ptr, FFIType.i32],
112791
+ returns: FFIType.i32
112792
+ }
112793
+ });
112794
+ return (pid, flavor, arg, buffer, size) => Number(library.symbols.proc_pidinfo(pid, flavor, arg, buffer, size));
112795
+ } catch {
112796
+ return null;
112797
+ }
112798
+ }
112799
+ function loadProcPidInfo() {
112800
+ procPidInfoLookup ??= openProcPidInfo();
112801
+ return procPidInfoLookup;
112802
+ }
112803
+ async function readDarwinProcessStartSeconds(pid) {
112804
+ if (process.platform !== "darwin")
112805
+ return null;
112806
+ if (!Number.isSafeInteger(pid) || pid <= 0)
112807
+ return null;
112808
+ const procPidInfo = await loadProcPidInfo();
112809
+ if (procPidInfo === null)
112810
+ return null;
112811
+ const buffer = new Uint8Array(PROC_BSDINFO_SIZE);
112812
+ let written = 0;
112813
+ try {
112814
+ written = procPidInfo(pid, PROC_PIDTBSDINFO, 0n, buffer, PROC_BSDINFO_SIZE);
112815
+ } catch {
112816
+ return null;
112817
+ }
112818
+ if (written !== PROC_BSDINFO_SIZE)
112819
+ return null;
112820
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
112821
+ const startSeconds = Number(view.getBigUint64(START_TVSEC_OFFSET, true));
112822
+ return startSeconds > 0 ? startSeconds : null;
112823
+ }
112824
+ var PROCESS_QUERY_LIMITED_INFORMATION = 4096;
112825
+ var kernel32Lookup = null;
112826
+ async function openKernel32() {
112827
+ if (process.platform !== "win32")
112828
+ return null;
112829
+ try {
112830
+ const { dlopen, FFIType } = await import("bun:ffi");
112831
+ const library = dlopen("kernel32.dll", {
112832
+ OpenProcess: { args: [FFIType.u32, FFIType.i32, FFIType.u32], returns: FFIType.ptr },
112833
+ GetProcessTimes: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
112834
+ CloseHandle: { args: [FFIType.ptr], returns: FFIType.i32 }
112835
+ });
112836
+ return library.symbols;
112837
+ } catch {
112838
+ return null;
112839
+ }
112840
+ }
112841
+ async function readWin32ProcessCreationFiletime(pid) {
112842
+ if (process.platform !== "win32")
112843
+ return null;
112844
+ if (!Number.isSafeInteger(pid) || pid <= 0)
112845
+ return null;
112846
+ kernel32Lookup ??= openKernel32();
112847
+ const kernel32 = await kernel32Lookup;
112848
+ if (kernel32 === null)
112849
+ return null;
112850
+ const handle = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
112851
+ if (handle === null || handle === 0 || handle === 0n)
112852
+ return null;
112853
+ try {
112854
+ const creation = new BigUint64Array(1);
112855
+ const ok = kernel32.GetProcessTimes(handle, creation, new BigUint64Array(1), new BigUint64Array(1), new BigUint64Array(1));
112856
+ const filetime = creation[0] ?? 0n;
112857
+ return ok === 0 || filetime === 0n ? null : filetime;
112858
+ } finally {
112859
+ kernel32.CloseHandle(handle);
112860
+ }
112861
+ }
112862
+
112863
+ // packages/memory-core/src/locks/process-identity.ts
112864
+ function errorCode(error) {
112865
+ if (!(error instanceof Error) || !("code" in error))
112442
112866
  return;
112443
- fallbackNoticed = true;
112444
- process.stderr.write(`${message}
112445
- `);
112446
- };
112447
- var isLocked = (error) => error instanceof Error && (LOCKED.test(error.message) || LOCKED.test(String(error.code ?? "")));
112448
- function credentialId(api) {
112449
- return createHash10("sha256").update(serviceOrigin(api)).digest("hex");
112867
+ return typeof error.code === "string" ? error.code : undefined;
112450
112868
  }
112451
- function createCredentialStore(api, options = {}) {
112452
- return createSealedStore(api, "omo-cli", credentialSchema, options.secrets, options.platform, options.lockProbe, options.notice, options.wait);
112869
+ async function execFileText(command, args) {
112870
+ return await new Promise((resolve) => {
112871
+ execFile7(command, args, { encoding: "utf8", timeout: 2000, windowsHide: true }, (error, stdout) => {
112872
+ if (error !== null) {
112873
+ resolve(null);
112874
+ return;
112875
+ }
112876
+ const value = stdout.trim();
112877
+ resolve(value.length > 0 ? value : null);
112878
+ });
112879
+ });
112453
112880
  }
112454
- function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT) {
112455
- if (!secrets)
112456
- throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
112457
- const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
112458
- if (platformName === null)
112459
- throw new SignInError("This platform has no supported OS credential store.");
112460
- const key = { service: namespace, name: credentialId(api) };
112461
- const slot = `${key.service}
112462
- ${key.name}`;
112463
- const readsOf = (api) => {
112464
- const known = processReads.get(api);
112465
- if (known !== undefined)
112466
- return known;
112467
- const created = new Map;
112468
- processReads.set(api, created);
112469
- return created;
112470
- };
112471
- const forget = (api) => {
112472
- readsOf(api).delete(slot);
112473
- };
112474
- const sharedRead = (api) => {
112475
- const reads = readsOf(api);
112476
- const pending = reads.get(slot);
112477
- if (pending !== undefined)
112478
- return pending;
112479
- const read = Promise.resolve().then(() => api.get(key));
112480
- const done = () => {
112481
- if (reads.get(slot) === read)
112482
- reads.delete(slot);
112483
- };
112484
- read.then(done, done);
112485
- reads.set(slot, read);
112486
- return read;
112881
+ async function readLinuxStartIdentity(pid) {
112882
+ try {
112883
+ const stat = await readFile33(`/proc/${pid}/stat`, "utf8");
112884
+ const commandEnd = stat.lastIndexOf(")");
112885
+ if (commandEnd < 0)
112886
+ return null;
112887
+ const fieldsAfterCommand = stat.slice(commandEnd + 2).trim().split(/\s+/);
112888
+ const startTicks = fieldsAfterCommand[19];
112889
+ return startTicks === undefined ? null : `linux-proc-start-ticks:${startTicks}`;
112890
+ } catch {
112891
+ return null;
112892
+ }
112893
+ }
112894
+ async function readWin32StartIdentity(pid) {
112895
+ if (getPidLiveness(pid) === "dead")
112896
+ return null;
112897
+ const creationFiletime = await readWin32ProcessCreationFiletime(pid);
112898
+ if (creationFiletime !== null)
112899
+ return `win32-creation-filetime:${creationFiletime}`;
112900
+ const value = await execFileText("powershell.exe", [
112901
+ "-NoProfile",
112902
+ "-Command",
112903
+ `(Get-Process -Id ${pid} -ErrorAction SilentlyContinue).StartTime.ToUniversalTime().ToString('o')`
112904
+ ]);
112905
+ return value === null ? null : `win32-creation-date:${value}`;
112906
+ }
112907
+ function createProcessStartIdentityReader(read, ownPid) {
112908
+ let ownIdentity;
112909
+ return (pid) => {
112910
+ if (pid !== ownPid)
112911
+ return read(pid);
112912
+ ownIdentity ??= read(pid).then((identity) => {
112913
+ if (identity === null)
112914
+ ownIdentity = undefined;
112915
+ return identity;
112916
+ }, (error) => {
112917
+ ownIdentity = undefined;
112918
+ throw error;
112919
+ });
112920
+ return ownIdentity;
112487
112921
  };
112488
- const waiting = platform === "darwin" ? `macOS Keychain is waiting for your approval: answer the "${basename15(process.execPath)} wants to access key ${namespace}" dialog ("Always Allow" stops it asking again)` : `${platformName} has not answered; it may be waiting for your approval or an unlock in a system dialog`;
112489
- const answered = async (api) => {
112490
- const read = sharedRead(api);
112491
- let timer;
112492
- try {
112493
- if (wait.kind === "interactive") {
112494
- timer = setTimeout(() => wait.notice(`omo: ${waiting}.`), wait.noticeAfterMs);
112495
- return await read;
112496
- }
112497
- const expired = new Promise((_, reject) => {
112498
- timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waiting}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
112499
- });
112500
- return await Promise.race([read, expired]);
112501
- } finally {
112502
- clearTimeout(timer);
112503
- }
112922
+ }
112923
+ var getProcessStartIdentity = createProcessStartIdentityReader(readProcessStartIdentity, process.pid);
112924
+ async function readProcessStartIdentity(pid) {
112925
+ if (process.platform === "linux")
112926
+ return await readLinuxStartIdentity(pid);
112927
+ if (process.platform === "darwin" || process.platform === "freebsd") {
112928
+ if (getPidLiveness(pid) === "dead")
112929
+ return null;
112930
+ const startSeconds = await readDarwinProcessStartSeconds(pid);
112931
+ if (startSeconds !== null)
112932
+ return `proc-start-epoch:${startSeconds}`;
112933
+ const value = await execFileText("/bin/ps", ["-o", "lstart=", "-p", String(pid)]);
112934
+ return value === null ? null : `ps-lstart:${value.replace(/\s+/g, " ")}`;
112935
+ }
112936
+ if (process.platform === "win32")
112937
+ return await readWin32StartIdentity(pid);
112938
+ return null;
112939
+ }
112940
+ function identityScheme(identity) {
112941
+ const separator = identity.indexOf(":");
112942
+ return separator <= 0 ? null : identity.slice(0, separator);
112943
+ }
112944
+ function startIdentitiesConflict(recorded, actual) {
112945
+ const recordedScheme = identityScheme(recorded);
112946
+ if (recordedScheme === null || recordedScheme !== identityScheme(actual))
112947
+ return false;
112948
+ return recorded !== actual;
112949
+ }
112950
+ function getPidLiveness(pid) {
112951
+ try {
112952
+ process.kill(pid, 0);
112953
+ return "alive";
112954
+ } catch (error) {
112955
+ const code = errorCode(error);
112956
+ if (code === "ESRCH")
112957
+ return "dead";
112958
+ if (code === "EPERM")
112959
+ return "alive";
112960
+ return "unknown";
112961
+ }
112962
+ }
112963
+
112964
+ // packages/team-core/src/team-state-store/lock-worker-lifetime.ts
112965
+ init_zod();
112966
+ import { randomUUID as randomUUID5 } from "crypto";
112967
+ import { BroadcastChannel, parentPort, threadId } from "worker_threads";
112968
+ var Registration = object({
112969
+ kind: literal("omo-team-lock-register-v1"),
112970
+ incarnation: string2(),
112971
+ challenge: string2()
112972
+ });
112973
+ var Message = discriminatedUnion("kind", [
112974
+ object({ kind: literal("query"), id: string2(), incarnation: string2(), record: string2() }),
112975
+ object({ kind: literal("answer"), id: string2(), released: boolean2() }),
112976
+ object({ kind: literal("hello"), threadId: number2() }),
112977
+ object({ kind: literal("register"), threadId: number2(), challenge: string2() })
112978
+ ]);
112979
+ function createState() {
112980
+ const channel = new BroadcastChannel(`omo-team-lock-lifetime-v1-${process.pid}`);
112981
+ channel.unref();
112982
+ const state = {
112983
+ incarnation: randomUUID5(),
112984
+ records: new Map,
112985
+ exited: new Set,
112986
+ observed: new WeakSet,
112987
+ observing: new Map,
112988
+ pending: new Map,
112989
+ channel,
112990
+ installed: false,
112991
+ registered: parentPort === null,
112992
+ registration: undefined,
112993
+ onRegistered: undefined
112504
112994
  };
112505
- const unavailable = (error) => isLocked(error) ? new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`) : new CredentialStoreError(`Cannot access ${platformName}. Unlock or enable the OS credential store and try again. Credentials are never saved to a file.`);
112506
- let unlockedUntil = 0;
112507
- let noticed = false;
112508
- const assertUsable = async () => {
112509
- if (platform !== "linux" || Date.now() < unlockedUntil)
112510
- return;
112511
- const lock = await lockProbe();
112512
- if (lock === "locked")
112513
- throw new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`);
112514
- if (lock === "unlocked") {
112515
- unlockedUntil = Date.now() + UNLOCKED_REUSE_MS;
112995
+ channel.onmessage = (event) => {
112996
+ const parsed = Message.safeParse(event.data);
112997
+ if (!parsed.success)
112516
112998
  return;
112517
- }
112518
- if (!noticed) {
112519
- noticed = true;
112520
- notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
112521
- }
112522
- };
112523
- return {
112524
- async read() {
112525
- await assertUsable();
112526
- let value;
112527
- try {
112528
- value = await answered(secrets);
112529
- } catch (error) {
112530
- if (error instanceof KeychainApprovalPendingError)
112531
- throw error;
112532
- throw unavailable(error);
112533
- }
112534
- if (value === null)
112535
- return null;
112536
- try {
112537
- return schema.parse(JSON.parse(value));
112538
- } catch {
112539
- throw new InvalidCredentialState(signInRoute() === "cli" ? "Stored sign-in data is invalid. Run omo logout, then omo login." : "The OmO sign-in saved on this computer can't be read, and it can't be reset from the terminal yet.");
112999
+ const message = parsed.data;
113000
+ switch (message.kind) {
113001
+ case "hello": {
113002
+ const observed = state.observing.get(message.threadId);
113003
+ if (observed !== undefined) {
113004
+ channel.postMessage({ kind: "register", threadId: message.threadId, challenge: observed.challenge });
113005
+ }
113006
+ return;
112540
113007
  }
112541
- },
112542
- async write(value) {
112543
- await assertUsable();
112544
- try {
112545
- await secrets.set({ ...key, value: JSON.stringify(schema.parse(value)) });
112546
- } catch (error) {
112547
- throw unavailable(error);
113008
+ case "register":
113009
+ if (message.threadId === threadId) {
113010
+ parentPort?.postMessage({
113011
+ kind: "omo-team-lock-register-v1",
113012
+ incarnation: state.incarnation,
113013
+ challenge: message.challenge
113014
+ });
113015
+ state.registered = true;
113016
+ state.onRegistered?.();
113017
+ }
113018
+ return;
113019
+ case "answer":
113020
+ state.pending.get(message.id)?.(message.released);
113021
+ return;
113022
+ case "query": {
113023
+ const status = message.incarnation === state.incarnation ? state.records.get(message.record) : undefined;
113024
+ if (status !== undefined || state.exited.has(message.incarnation)) {
113025
+ channel.postMessage({
113026
+ kind: "answer",
113027
+ id: message.id,
113028
+ released: status === "released" || state.exited.has(message.incarnation)
113029
+ });
113030
+ }
113031
+ return;
112548
113032
  }
112549
- forget(secrets);
112550
- },
112551
- async clear() {
112552
- await assertUsable();
112553
- try {
112554
- await secrets.delete(key);
112555
- } catch (error) {
112556
- throw unavailable(error);
113033
+ default: {
113034
+ const unexpected = message;
113035
+ throw new Error(`Unexpected lock lifetime message: ${unexpected}`);
112557
113036
  }
112558
- forget(secrets);
112559
113037
  }
112560
113038
  };
113039
+ return state;
112561
113040
  }
112562
-
112563
- // packages/omo-opencode/src/cli/service-auth/loopback.ts
112564
- import { createHash as createHash11, randomBytes as randomBytes5, timingSafeEqual } from "crypto";
112565
- import { createServer as createServer3 } from "http";
112566
- class BrowserUnavailable extends SignInError {
112567
- }
112568
- async function authorize(options) {
112569
- const verifier = randomBytes5(32).toString("base64url");
112570
- const state = randomBytes5(32).toString("base64url");
112571
- const answer = Promise.withResolvers();
112572
- const abort = () => answer.reject(new SignInError("Browser sign-in cancelled or timed out."));
112573
- let accepted = false;
112574
- let origin = "";
112575
- const server = createServer3((request, response) => {
112576
- response.setHeader("cache-control", "no-store");
112577
- response.setHeader("referrer-policy", "no-referrer");
112578
- response.setHeader("content-type", "text/plain; charset=utf-8");
112579
- const url = new URL(request.url ?? "/", origin);
112580
- if (request.method !== "GET" || request.headers.host !== new URL(origin).host || url.origin !== origin || url.pathname !== "/callback" || request.headers.forwarded || request.headers["x-forwarded-for"]) {
112581
- response.writeHead(404).end("Not found");
112582
- return;
112583
- }
112584
- const code = url.searchParams.get("code");
112585
- const suppliedState = Buffer.from(url.searchParams.get("state") ?? "");
112586
- const expectedState = Buffer.from(state);
112587
- if (accepted || url.searchParams.getAll("state").length !== 1 || suppliedState.length !== expectedState.length || !timingSafeEqual(suppliedState, expectedState) || url.searchParams.getAll("code").length !== 1 || !code) {
112588
- response.writeHead(400).end("Invalid sign-in response");
113041
+ var state2 = globalThis.__omoTeamLockLifetimeV1 ??= createState();
113042
+ var lockOwnerInstanceId = state2.incarnation;
113043
+ function attachWorker(worker) {
113044
+ if (state2.observed.has(worker))
113045
+ return;
113046
+ state2.observed.add(worker);
113047
+ const id = worker.threadId;
113048
+ const challenge = randomUUID5();
113049
+ state2.observing.set(id, { worker, challenge });
113050
+ const incarnations = new Set;
113051
+ let exited = false;
113052
+ worker.on("message", (message) => {
113053
+ const parsed = Registration.safeParse(message);
113054
+ if (!parsed.success || parsed.data.challenge !== challenge)
112589
113055
  return;
112590
- }
112591
- accepted = true;
112592
- response.writeHead(200).end("Return to the terminal to finish signing in.");
112593
- answer.resolve(code);
113056
+ incarnations.add(parsed.data.incarnation);
113057
+ if (exited)
113058
+ state2.exited.add(parsed.data.incarnation);
112594
113059
  });
112595
- try {
112596
- await new Promise((resolve, reject) => {
112597
- server.once("error", reject);
112598
- server.listen(0, "127.0.0.1", () => {
112599
- server.off("error", reject);
112600
- resolve();
112601
- });
112602
- });
112603
- const address = server.address();
112604
- if (!address || typeof address === "string")
112605
- throw new SignInError("Unable to start the sign-in callback.");
112606
- origin = `http://127.0.0.1:${address.port}`;
112607
- const url = new URL(serviceOrigin(options.accounts));
112608
- url.search = new URLSearchParams({
112609
- redirect_uri: `${origin}/callback`,
112610
- code_challenge: createHash11("sha256").update(verifier).digest("base64url"),
112611
- code_challenge_method: "S256",
112612
- state
112613
- }).toString();
112614
- const timer = setTimeout(abort, 5 * 60000);
112615
- options.signal?.addEventListener("abort", abort, { once: true });
112616
- try {
112617
- options.signal?.throwIfAborted();
112618
- const openerFailed = () => {
112619
- if (!accepted)
112620
- throw new BrowserUnavailable("No browser is available; use device sign-in.");
112621
- };
112622
- const [code] = await Promise.all([
112623
- answer.promise,
112624
- options.open(url.href).then((opened) => {
112625
- if (!opened)
112626
- openerFailed();
112627
- }, openerFailed)
112628
- ]);
112629
- return { code, codeVerifier: verifier };
112630
- } finally {
113060
+ worker.once("exit", () => {
113061
+ exited = true;
113062
+ if (state2.observing.get(id)?.worker === worker)
113063
+ state2.observing.delete(id);
113064
+ for (const incarnation of incarnations)
113065
+ state2.exited.add(incarnation);
113066
+ });
113067
+ }
113068
+ function installLockWorkerObserver() {
113069
+ if (state2.installed)
113070
+ return;
113071
+ state2.installed = true;
113072
+ process.on("worker", attachWorker);
113073
+ state2.channel.postMessage({ kind: "hello", threadId });
113074
+ }
113075
+ installLockWorkerObserver();
113076
+ async function registerLockWorker() {
113077
+ if (state2.registered)
113078
+ return;
113079
+ state2.registration ??= new Promise((resolve) => {
113080
+ const finish = () => {
112631
113081
  clearTimeout(timer);
112632
- options.signal?.removeEventListener("abort", abort);
112633
- }
112634
- } finally {
112635
- server.closeAllConnections();
112636
- await new Promise((resolve) => server.close(() => resolve()));
112637
- }
113082
+ state2.onRegistered = undefined;
113083
+ resolve();
113084
+ };
113085
+ const timer = setTimeout(finish, 250);
113086
+ state2.onRegistered = finish;
113087
+ state2.channel.postMessage({ kind: "hello", threadId });
113088
+ });
113089
+ await state2.registration;
112638
113090
  }
112639
- async function loginLoopback(session, options) {
112640
- await session.ready();
112641
- const keys = generateDeviceKeys();
112642
- for (;; ) {
112643
- const authorization = await authorize({ accounts: options.accounts, open: options.open, signal: session.signal });
112644
- try {
112645
- const grant = parseReply(grantSchema, await session.request("/v1/session/exchange", jsonRequest({
112646
- ...authorization,
112647
- kind: "cli",
112648
- deviceName: options.name,
112649
- platform: options.platform,
112650
- ...keys.public
112651
- })));
112652
- await session.save({ ...grant, ...keys.private });
112653
- return;
112654
- } catch (error) {
112655
- if (await session.removeForLimit(error, options.chooseDevice))
112656
- continue;
112657
- throw new SignInError("Sign-in cancelled. No device was removed.");
112658
- }
112659
- }
113091
+ function markLockRecordHeld(record) {
113092
+ state2.records.set(record, "held");
113093
+ }
113094
+ function markLockRecordReleased(record) {
113095
+ if (state2.records.has(record))
113096
+ state2.records.set(record, "released");
113097
+ }
113098
+ function forgetLockRecord(record) {
113099
+ state2.records.delete(record);
113100
+ }
113101
+ async function isWorkerLockReleased(incarnation, record) {
113102
+ if (state2.exited.has(incarnation))
113103
+ return true;
113104
+ if (incarnation === state2.incarnation)
113105
+ return state2.records.get(record) === "released";
113106
+ const id = randomUUID5();
113107
+ return await new Promise((resolve) => {
113108
+ const finish = (released) => {
113109
+ clearTimeout(timer);
113110
+ state2.pending.delete(id);
113111
+ resolve(released);
113112
+ };
113113
+ const timer = setTimeout(() => finish(false), 250);
113114
+ state2.pending.set(id, finish);
113115
+ state2.channel.postMessage({ kind: "query", id, incarnation, record });
113116
+ });
112660
113117
  }
112661
-
112662
- // packages/omo-opencode/src/cli/service-auth/session.ts
112663
- import { mkdir as mkdir11 } from "fs/promises";
112664
- import { homedir as homedir31 } from "os";
112665
- import { join as join107 } from "path";
112666
-
112667
- // packages/team-core/src/team-state-store/lock-publish.ts
112668
- import { access as access3, open as open2, unlink as unlink2 } from "fs/promises";
112669
- import { dirname as dirname42 } from "path";
112670
113118
 
112671
113119
  // packages/team-core/src/team-state-store/lock-record.ts
112672
- import { randomUUID as randomUUID5 } from "crypto";
112673
- import { readFile as readFile33, stat as stat8 } from "fs/promises";
112674
- var lockOwnerInstanceId = randomUUID5();
112675
- var heldLockRecords = new Set;
112676
- function buildLockRecord(ownerTag) {
112677
- return `${ownerTag} ${randomUUID5()}
113120
+ async function buildLockRecord(ownerTag) {
113121
+ await registerLockWorker();
113122
+ const processStart = await getProcessStartIdentity(process.pid);
113123
+ return `${ownerTag} ${randomUUID6()}
112678
113124
  ${process.pid}
112679
113125
  ${Date.now()}
112680
113126
  ${lockOwnerInstanceId}
113127
+ ${processStart ?? "unavailable"}
112681
113128
  `;
112682
113129
  }
112683
- function markLockRecordHeld(content) {
112684
- heldLockRecords.add(content);
112685
- }
112686
- function markLockRecordReleased(content) {
112687
- heldLockRecords.delete(content);
112688
- }
112689
- function errorCode(error) {
113130
+ function errorCode2(error) {
112690
113131
  if (!(error instanceof Error) || !("code" in error))
112691
113132
  return null;
112692
113133
  return typeof error.code === "string" ? error.code : null;
112693
113134
  }
112694
113135
  function isPathAbsenceError(error) {
112695
- const code = errorCode(error);
113136
+ const code = errorCode2(error);
112696
113137
  return code === "ENOENT" || code === "ENOTDIR";
112697
113138
  }
112698
113139
  function parseLockOwner(content) {
112699
113140
  const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
112700
- if (lines.length !== 3 && lines.length !== 4)
113141
+ if (lines.length !== 3 && lines.length !== 4 && lines.length !== 5)
112701
113142
  return null;
112702
113143
  const ownerPid = Number.parseInt(lines[1] ?? "", 10);
112703
113144
  const acquiredAtEpochMs = Number.parseInt(lines[2] ?? "", 10);
@@ -112708,24 +113149,14 @@ function parseLockOwner(content) {
112708
113149
  return {
112709
113150
  ownerPid,
112710
113151
  acquiredAtEpochMs,
112711
- instanceId: lines.length === 4 ? lines[3] ?? null : null
113152
+ instanceId: lines[3] ?? null,
113153
+ processStart: lines[4] ?? null
112712
113154
  };
112713
113155
  }
112714
- function isPidAlive(pid) {
112715
- try {
112716
- process.kill(pid, 0);
112717
- return true;
112718
- } catch (error) {
112719
- if (!(error instanceof Error)) {
112720
- throw error;
112721
- }
112722
- return false;
112723
- }
112724
- }
112725
113156
  async function readLockRecord(lockPath) {
112726
113157
  try {
112727
- const content = await readFile33(lockPath, "utf8");
112728
- const { mtimeMs } = await stat8(lockPath);
113158
+ const content = await readFile34(lockPath, "utf8");
113159
+ const { mtimeMs } = await stat9(lockPath);
112729
113160
  return { content, modifiedAtEpochMs: mtimeMs };
112730
113161
  } catch (error) {
112731
113162
  if (!(error instanceof Error))
@@ -112733,23 +113164,30 @@ async function readLockRecord(lockPath) {
112733
113164
  return null;
112734
113165
  }
112735
113166
  }
112736
- function isLockRecordStale(record, staleAfterMs) {
113167
+ async function isLockRecordStale(record, staleAfterMs) {
112737
113168
  const owner = parseLockOwner(record.content);
112738
113169
  if (owner === null)
112739
113170
  return Date.now() - record.modifiedAtEpochMs > staleAfterMs;
112740
- if (owner.instanceId !== null && owner.ownerPid === process.pid) {
112741
- return owner.instanceId !== lockOwnerInstanceId || !heldLockRecords.has(record.content);
113171
+ const liveness = getPidLiveness(owner.ownerPid);
113172
+ if (liveness === "dead") {
113173
+ return owner.instanceId !== null || Date.now() - owner.acquiredAtEpochMs > staleAfterMs;
112742
113174
  }
112743
- if (isPidAlive(owner.ownerPid))
113175
+ if (liveness === "unknown")
112744
113176
  return false;
112745
- if (owner.instanceId !== null)
112746
- return true;
112747
- return Date.now() - owner.acquiredAtEpochMs > staleAfterMs;
113177
+ if (owner.processStart !== null) {
113178
+ const actual = await getProcessStartIdentity(owner.ownerPid);
113179
+ if (actual !== null && startIdentitiesConflict(owner.processStart, actual))
113180
+ return true;
113181
+ }
113182
+ if (owner.instanceId !== null && owner.ownerPid === process.pid) {
113183
+ return await isWorkerLockReleased(owner.instanceId, record.content);
113184
+ }
113185
+ return false;
112748
113186
  }
112749
113187
 
112750
113188
  // packages/team-core/src/team-state-store/lock-publish.ts
112751
113189
  async function pathMayExist(path, deps = {}) {
112752
- const accessPath = deps.access ?? access3;
113190
+ const accessPath = deps.access ?? access4;
112753
113191
  try {
112754
113192
  await accessPath(path);
112755
113193
  return true;
@@ -112760,7 +113198,7 @@ async function pathMayExist(path, deps = {}) {
112760
113198
  }
112761
113199
  }
112762
113200
  async function assertRetryableLockOpenError(lockPath, error, deps) {
112763
- const code = errorCode(error);
113201
+ const code = errorCode2(error);
112764
113202
  if (code === "EEXIST")
112765
113203
  return;
112766
113204
  if (code === "EPERM") {
@@ -112775,9 +113213,9 @@ async function publishLockRecord(lockPath, record) {
112775
113213
  markLockRecordHeld(record);
112776
113214
  let fileHandle;
112777
113215
  try {
112778
- fileHandle = await open2(lockPath, "wx");
113216
+ fileHandle = await open3(lockPath, "wx");
112779
113217
  } catch (error) {
112780
- markLockRecordReleased(record);
113218
+ forgetLockRecord(record);
112781
113219
  await assertRetryableLockOpenError(lockPath, error);
112782
113220
  return false;
112783
113221
  }
@@ -112786,7 +113224,7 @@ async function publishLockRecord(lockPath, record) {
112786
113224
  } catch (error) {
112787
113225
  markLockRecordReleased(record);
112788
113226
  await fileHandle.close();
112789
- await unlink2(lockPath).catch(() => {
113227
+ await unlink3(lockPath).catch(() => {
112790
113228
  return;
112791
113229
  });
112792
113230
  throw error;
@@ -112796,8 +113234,8 @@ async function publishLockRecord(lockPath, record) {
112796
113234
  }
112797
113235
 
112798
113236
  // packages/team-core/src/team-state-store/lock-reclaim.ts
112799
- import { createHash as createHash12 } from "crypto";
112800
- import { unlink as unlink3 } from "fs/promises";
113237
+ import { createHash as createHash10 } from "crypto";
113238
+ import { unlink as unlink4 } from "fs/promises";
112801
113239
  var RECLAIM_UNLINK_ATTEMPTS = 3;
112802
113240
  var RECLAIM_UNLINK_RETRY_MS = 25;
112803
113241
  function delay2(ms) {
@@ -112806,11 +113244,11 @@ function delay2(ms) {
112806
113244
  });
112807
113245
  }
112808
113246
  function reclaimGuardPath(lockPath, record) {
112809
- return `${lockPath}.reclaim-${createHash12("sha256").update(record).digest("hex").slice(0, 16)}`;
113247
+ return `${lockPath}.reclaim-${createHash10("sha256").update(record).digest("hex").slice(0, 16)}`;
112810
113248
  }
112811
113249
  async function unlinkWithRetry(path, deps) {
112812
113250
  const wait = deps.delay ?? delay2;
112813
- const unlinkFile = deps.unlink ?? unlink3;
113251
+ const unlinkFile = deps.unlink ?? unlink4;
112814
113252
  for (let attempt = 1;; attempt += 1) {
112815
113253
  try {
112816
113254
  await unlinkFile(path);
@@ -112820,7 +113258,7 @@ async function unlinkWithRetry(path, deps) {
112820
113258
  throw error;
112821
113259
  if (isPathAbsenceError(error))
112822
113260
  return "absent";
112823
- const code = errorCode(error);
113261
+ const code = errorCode2(error);
112824
113262
  if (code !== "EPERM" && code !== "EBUSY" || attempt === RECLAIM_UNLINK_ATTEMPTS)
112825
113263
  return "stuck";
112826
113264
  await wait(RECLAIM_UNLINK_RETRY_MS);
@@ -112829,10 +113267,10 @@ async function unlinkWithRetry(path, deps) {
112829
113267
  }
112830
113268
  async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterMs, deps = {}) {
112831
113269
  const guardPath = reclaimGuardPath(lockPath, expectedRecord);
112832
- const guardRecord = buildLockRecord("lock-reclaim");
113270
+ const guardRecord = await buildLockRecord("lock-reclaim");
112833
113271
  if (!await publishLockRecord(guardPath, guardRecord)) {
112834
113272
  const guard = await readLockRecord(guardPath);
112835
- if (guard !== null && isLockRecordStale(guard, staleAfterMs)) {
113273
+ if (guard !== null && await isLockRecordStale(guard, staleAfterMs)) {
112836
113274
  await removeLockRecordIfUnchanged(guardPath, guard.content, staleAfterMs, deps);
112837
113275
  }
112838
113276
  return "busy";
@@ -112841,13 +113279,16 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
112841
113279
  const current = await readLockRecord(lockPath);
112842
113280
  if (current === null)
112843
113281
  return "absent";
112844
- if (current.content !== expectedRecord || !isLockRecordStale(current, staleAfterMs))
113282
+ if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
112845
113283
  return "changed";
112846
113284
  const unlinked = await unlinkWithRetry(lockPath, deps);
113285
+ if (unlinked !== "stuck")
113286
+ forgetLockRecord(expectedRecord);
112847
113287
  return unlinked === "absent" ? "absent" : unlinked;
112848
113288
  } finally {
112849
113289
  markLockRecordReleased(guardRecord);
112850
- await unlinkWithRetry(guardPath, deps);
113290
+ if (await unlinkWithRetry(guardPath, deps) !== "stuck")
113291
+ forgetLockRecord(guardRecord);
112851
113292
  }
112852
113293
  }
112853
113294
 
@@ -112866,7 +113307,7 @@ async function acquireLock(lockPath, ownerTag, staleAfterMs) {
112866
113307
  if (Date.now() - startedAt > LOCK_WAIT_TIMEOUT_MS) {
112867
113308
  throw new Error(`Timed out acquiring lock: ${lockPath}`);
112868
113309
  }
112869
- const record = buildLockRecord(ownerTag);
113310
+ const record = await buildLockRecord(ownerTag);
112870
113311
  if (await publishLockRecord(lockPath, record))
112871
113312
  return record;
112872
113313
  const outcome = await reapStaleLock(lockPath, staleAfterMs);
@@ -112883,26 +113324,327 @@ async function withLock(lockPath, fn, opts) {
112883
113324
  return await fn();
112884
113325
  } finally {
112885
113326
  markLockRecordReleased(record);
112886
- await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
113327
+ const outcome = await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
113328
+ if (outcome === "removed" || outcome === "absent" || outcome === "changed")
113329
+ forgetLockRecord(record);
112887
113330
  }
112888
113331
  }
112889
113332
  async function reapStaleLock(lockPath, staleAfterMs = DEFAULT_STALE_AFTER_MS, deps = {}) {
112890
113333
  const observed = await readLockRecord(lockPath);
112891
113334
  if (observed === null)
112892
113335
  return "absent";
112893
- if (!isLockRecordStale(observed, staleAfterMs))
113336
+ if (!await isLockRecordStale(observed, staleAfterMs))
112894
113337
  return "changed";
112895
113338
  return await removeLockRecordIfUnchanged(lockPath, observed.content, staleAfterMs, deps);
112896
113339
  }
112897
113340
 
113341
+ // packages/omo-opencode/src/cli/service-auth/credential-lock.ts
113342
+ var held = new AsyncLocalStorage3;
113343
+ function credentialLockPaths(api, home = homedir31()) {
113344
+ const id = createHash11("sha256").update(serviceOrigin(api)).digest("hex");
113345
+ const directory = join106(home, ".omo", "session-locks");
113346
+ return { directory, lock: join106(directory, `${id}.lock`), desktopRecord: join106(directory, `${id}.desktop-generation.json`) };
113347
+ }
113348
+ async function withCredentialLock(api, action, home = homedir31(), ownerTag = "cli-session") {
113349
+ const { directory, lock } = credentialLockPaths(api, home);
113350
+ const owned = held.getStore();
113351
+ if (owned?.has(lock))
113352
+ return action();
113353
+ await mkdir11(directory, { recursive: true, mode: 448 });
113354
+ return withLock(lock, () => held.run(new Set([...owned ?? [], lock]), action), {
113355
+ ownerTag,
113356
+ staleAfterMs: Number.POSITIVE_INFINITY
113357
+ });
113358
+ }
113359
+
113360
+ // packages/omo-opencode/src/cli/service-auth/keystore.ts
113361
+ class CredentialStoreError extends SignInError {
113362
+ }
113363
+
113364
+ class KeychainLockedError extends CredentialStoreError {
113365
+ }
113366
+ class InvalidCredentialState extends SignInError {
113367
+ }
113368
+
113369
+ class CredentialIdentityChanged extends Error {
113370
+ constructor() {
113371
+ super("The stored sign-in changed; the captured account is no longer current.");
113372
+ }
113373
+ }
113374
+
113375
+ class KeychainApprovalPendingError extends CredentialStoreError {
113376
+ }
113377
+ var SESSION_READ_WAIT = { kind: "bounded", deadlineMs: 5000 };
113378
+ var INTERACTIVE_READ_WAIT = {
113379
+ kind: "interactive",
113380
+ noticeAfterMs: 2000,
113381
+ notice: (message) => process.stderr.write(`${message}
113382
+ `)
113383
+ };
113384
+ var processReads = new WeakMap;
113385
+ var LOCKED = /-25308|errSecInteractionNotAllowed|interaction is not allowed|locked collection/i;
113386
+ var UNLOCKED_REUSE_MS = 30000;
113387
+ var fallbackNoticed = false;
113388
+ var stderrNoticeOncePerProcess = (message) => {
113389
+ if (fallbackNoticed)
113390
+ return;
113391
+ fallbackNoticed = true;
113392
+ process.stderr.write(`${message}
113393
+ `);
113394
+ };
113395
+ var isLocked = (error) => error instanceof Error && (LOCKED.test(error.message) || LOCKED.test(String(error.code ?? "")));
113396
+ function credentialId(api) {
113397
+ return createHash12("sha256").update(serviceOrigin(api)).digest("hex");
113398
+ }
113399
+ function createCredentialStore(api, options = {}) {
113400
+ const store = createSealedStore(api, "omo-cli", credentialSchema, options.secrets, options.platform, options.lockProbe, options.notice, options.wait, (current, value) => {
113401
+ const sameIdentity = current !== null && current.device.id === value.device.id && current.signingPrivateKey === value.signingPrivateKey && current.sealingPrivateKey === value.sealingPrivateKey && (value.accountId === undefined || current.accountId === undefined || current.accountId === value.accountId);
113402
+ const accountId = value.accountId ?? (sameIdentity ? current?.accountId : undefined);
113403
+ return {
113404
+ ...value,
113405
+ ...accountId === undefined ? {} : { accountId },
113406
+ credentialGeneration: sameIdentity ? current?.credentialGeneration ?? randomUUID7() : randomUUID7()
113407
+ };
113408
+ });
113409
+ return {
113410
+ read: store.read,
113411
+ readAuthoritative: store.readAuthoritative,
113412
+ write: (value) => withCredentialLock(api, () => store.write(value), options.home),
113413
+ clear: () => withCredentialLock(api, store.clear, options.home)
113414
+ };
113415
+ }
113416
+ function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT, amendWrite) {
113417
+ if (!secrets)
113418
+ throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
113419
+ const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
113420
+ if (platformName === null)
113421
+ throw new SignInError("This platform has no supported OS credential store.");
113422
+ const key = { service: namespace, name: credentialId(api) };
113423
+ const slot = `${key.service}
113424
+ ${key.name}`;
113425
+ const readsOf = (api) => {
113426
+ const known = processReads.get(api);
113427
+ if (known !== undefined)
113428
+ return known;
113429
+ const created = new Map;
113430
+ processReads.set(api, created);
113431
+ return created;
113432
+ };
113433
+ const forget = (api) => {
113434
+ readsOf(api).delete(slot);
113435
+ };
113436
+ const sharedRead = (api) => {
113437
+ const reads = readsOf(api);
113438
+ const pending = reads.get(slot);
113439
+ if (pending !== undefined)
113440
+ return pending;
113441
+ const read = Promise.resolve().then(() => api.get(key));
113442
+ const done = () => {
113443
+ if (reads.get(slot) === read)
113444
+ reads.delete(slot);
113445
+ };
113446
+ read.then(done, done);
113447
+ reads.set(slot, read);
113448
+ return read;
113449
+ };
113450
+ const waiting = platform === "darwin" ? `macOS Keychain is waiting for your approval: answer the "${basename15(process.execPath)} wants to access key ${namespace}" dialog ("Always Allow" stops it asking again)` : `${platformName} has not answered; it may be waiting for your approval or an unlock in a system dialog`;
113451
+ const answered = async (api, fresh = false) => {
113452
+ const read = fresh ? Promise.resolve().then(() => api.get(key)) : sharedRead(api);
113453
+ let timer;
113454
+ try {
113455
+ if (wait.kind === "interactive") {
113456
+ timer = setTimeout(() => wait.notice(`omo: ${waiting}.`), wait.noticeAfterMs);
113457
+ return await read;
113458
+ }
113459
+ const expired = new Promise((_, reject) => {
113460
+ timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waiting}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
113461
+ });
113462
+ return await Promise.race([read, expired]);
113463
+ } finally {
113464
+ clearTimeout(timer);
113465
+ }
113466
+ };
113467
+ const unavailable = (error) => isLocked(error) ? new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`) : new CredentialStoreError(`Cannot access ${platformName}. Unlock or enable the OS credential store and try again. Credentials are never saved to a file.`);
113468
+ let unlockedUntil = 0;
113469
+ let noticed = false;
113470
+ const assertUsable = async () => {
113471
+ if (platform !== "linux" || Date.now() < unlockedUntil)
113472
+ return;
113473
+ const lock = await lockProbe();
113474
+ if (lock === "locked")
113475
+ throw new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`);
113476
+ if (lock === "unlocked") {
113477
+ unlockedUntil = Date.now() + UNLOCKED_REUSE_MS;
113478
+ return;
113479
+ }
113480
+ if (!noticed) {
113481
+ noticed = true;
113482
+ notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
113483
+ }
113484
+ };
113485
+ const parsedRead = async (fresh) => {
113486
+ await assertUsable();
113487
+ let value;
113488
+ try {
113489
+ value = await answered(secrets, fresh);
113490
+ } catch (error) {
113491
+ if (error instanceof KeychainApprovalPendingError)
113492
+ throw error;
113493
+ throw unavailable(error);
113494
+ }
113495
+ if (value === null)
113496
+ return null;
113497
+ try {
113498
+ return schema.parse(JSON.parse(value));
113499
+ } catch {
113500
+ throw new InvalidCredentialState(signInRoute() === "cli" ? "Stored sign-in data is invalid. Run omo account forget, then omo login." : "The OmO sign-in saved on this computer can't be read. Run omo account forget to remove it, then sign in again in the desktop app.");
113501
+ }
113502
+ };
113503
+ return {
113504
+ read: () => parsedRead(false),
113505
+ readAuthoritative: () => parsedRead(true),
113506
+ async write(value) {
113507
+ await assertUsable();
113508
+ try {
113509
+ let next = value;
113510
+ if (amendWrite !== undefined) {
113511
+ const raw = await answered(secrets, true);
113512
+ let previous = null;
113513
+ if (raw !== null) {
113514
+ try {
113515
+ previous = schema.parse(JSON.parse(raw));
113516
+ } catch {}
113517
+ }
113518
+ next = amendWrite(previous, value);
113519
+ }
113520
+ await secrets.set({ ...key, value: JSON.stringify(schema.parse(next)) });
113521
+ } catch (error) {
113522
+ throw unavailable(error);
113523
+ }
113524
+ forget(secrets);
113525
+ },
113526
+ async clear() {
113527
+ await assertUsable();
113528
+ try {
113529
+ await secrets.delete(key);
113530
+ } catch (error) {
113531
+ throw unavailable(error);
113532
+ }
113533
+ forget(secrets);
113534
+ }
113535
+ };
113536
+ }
113537
+
113538
+ // packages/omo-opencode/src/cli/service-auth/loopback.ts
113539
+ import { createHash as createHash13, randomBytes as randomBytes5, timingSafeEqual } from "crypto";
113540
+ import { createServer as createServer3 } from "http";
113541
+ class BrowserUnavailable extends SignInError {
113542
+ }
113543
+ async function authorize(options) {
113544
+ const verifier = randomBytes5(32).toString("base64url");
113545
+ const state = randomBytes5(32).toString("base64url");
113546
+ const answer = Promise.withResolvers();
113547
+ const abort = () => answer.reject(new SignInError("Browser sign-in cancelled or timed out."));
113548
+ let accepted = false;
113549
+ let origin = "";
113550
+ const server = createServer3((request, response) => {
113551
+ response.setHeader("cache-control", "no-store");
113552
+ response.setHeader("referrer-policy", "no-referrer");
113553
+ response.setHeader("content-type", "text/plain; charset=utf-8");
113554
+ const url = new URL(request.url ?? "/", origin);
113555
+ if (request.method !== "GET" || request.headers.host !== new URL(origin).host || url.origin !== origin || url.pathname !== "/callback" || request.headers.forwarded || request.headers["x-forwarded-for"]) {
113556
+ response.writeHead(404).end("Not found");
113557
+ return;
113558
+ }
113559
+ const code = url.searchParams.get("code");
113560
+ const suppliedState = Buffer.from(url.searchParams.get("state") ?? "");
113561
+ const expectedState = Buffer.from(state);
113562
+ if (accepted || url.searchParams.getAll("state").length !== 1 || suppliedState.length !== expectedState.length || !timingSafeEqual(suppliedState, expectedState) || url.searchParams.getAll("code").length !== 1 || !code) {
113563
+ response.writeHead(400).end("Invalid sign-in response");
113564
+ return;
113565
+ }
113566
+ accepted = true;
113567
+ response.writeHead(200).end("Return to the terminal to finish signing in.");
113568
+ answer.resolve(code);
113569
+ });
113570
+ try {
113571
+ await new Promise((resolve, reject) => {
113572
+ server.once("error", reject);
113573
+ server.listen(0, "127.0.0.1", () => {
113574
+ server.off("error", reject);
113575
+ resolve();
113576
+ });
113577
+ });
113578
+ const address = server.address();
113579
+ if (!address || typeof address === "string")
113580
+ throw new SignInError("Unable to start the sign-in callback.");
113581
+ origin = `http://127.0.0.1:${address.port}`;
113582
+ const url = new URL(serviceOrigin(options.accounts));
113583
+ url.search = new URLSearchParams({
113584
+ redirect_uri: `${origin}/callback`,
113585
+ code_challenge: createHash13("sha256").update(verifier).digest("base64url"),
113586
+ code_challenge_method: "S256",
113587
+ state
113588
+ }).toString();
113589
+ const timer = setTimeout(abort, 5 * 60000);
113590
+ options.signal?.addEventListener("abort", abort, { once: true });
113591
+ try {
113592
+ options.signal?.throwIfAborted();
113593
+ const openerFailed = () => {
113594
+ if (!accepted)
113595
+ throw new BrowserUnavailable("No browser is available; use device sign-in.");
113596
+ };
113597
+ const [code] = await Promise.all([
113598
+ answer.promise,
113599
+ options.open(url.href).then((opened) => {
113600
+ if (!opened)
113601
+ openerFailed();
113602
+ }, openerFailed)
113603
+ ]);
113604
+ return { code, codeVerifier: verifier };
113605
+ } finally {
113606
+ clearTimeout(timer);
113607
+ options.signal?.removeEventListener("abort", abort);
113608
+ }
113609
+ } finally {
113610
+ server.closeAllConnections();
113611
+ await new Promise((resolve) => server.close(() => resolve()));
113612
+ }
113613
+ }
113614
+ async function loginLoopback(session, options) {
113615
+ await session.ready();
113616
+ const keys = generateDeviceKeys();
113617
+ for (;; ) {
113618
+ const authorization = await authorize({ accounts: options.accounts, open: options.open, signal: session.signal });
113619
+ try {
113620
+ const grant = parseReply(grantSchema, await session.request("/v1/session/exchange", jsonRequest({
113621
+ ...authorization,
113622
+ kind: "cli",
113623
+ deviceName: options.name,
113624
+ platform: options.platform,
113625
+ ...keys.public
113626
+ })));
113627
+ await session.save({ ...grant, ...keys.private });
113628
+ return;
113629
+ } catch (error) {
113630
+ if (await session.removeForLimit(error, options.chooseDevice))
113631
+ continue;
113632
+ throw new SignInError("Sign-in cancelled. No device was removed.");
113633
+ }
113634
+ }
113635
+ }
113636
+
113637
+ // packages/omo-opencode/src/cli/service-auth/session.ts
113638
+ import { homedir as homedir32 } from "os";
113639
+
112898
113640
  // packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
112899
113641
  init_zod();
112900
- import { mkdir as mkdir10, readFile as readFile34, rename as rename7, rm as rm16, writeFile as writeFile16 } from "fs/promises";
112901
- import { dirname as dirname43, join as join106 } from "path";
113642
+ import { mkdir as mkdir12, readFile as readFile35, rename as rename8, rm as rm17, writeFile as writeFile17 } from "fs/promises";
113643
+ import { dirname as dirname43, join as join107 } from "path";
112902
113644
  var markerSchema = object({ device: string2().nullable(), at: string2() });
112903
- var signedOutMarkerPath = (home, credential) => join106(home, ".omo", "account-state", `${credential}.signed-out.json`);
113645
+ var signedOutMarkerPath = (home, credential) => join107(home, ".omo", "account-state", `${credential}.signed-out.json`);
112904
113646
  async function readSignedOutMarker(path) {
112905
- const text = await readFile34(path, "utf8").catch(() => null);
113647
+ const text = await readFile35(path, "utf8").catch(() => null);
112906
113648
  if (text === null)
112907
113649
  return null;
112908
113650
  let value;
@@ -112915,12 +113657,12 @@ async function readSignedOutMarker(path) {
112915
113657
  return parsed.success ? parsed.data : null;
112916
113658
  }
112917
113659
  async function writeSignedOutMarker(path, device) {
112918
- await mkdir10(dirname43(path), { recursive: true, mode: 448 });
113660
+ await mkdir12(dirname43(path), { recursive: true, mode: 448 });
112919
113661
  const staging = `${path}.${process.pid}.tmp`;
112920
- await writeFile16(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
112921
- await rename7(staging, path);
113662
+ await writeFile17(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
113663
+ await rename8(staging, path);
112922
113664
  }
112923
- var clearSignedOutMarker = (path) => rm16(path, { force: true });
113665
+ var clearSignedOutMarker = (path) => rm17(path, { force: true });
112924
113666
 
112925
113667
  // packages/omo-opencode/src/cli/service-auth/session.ts
112926
113668
  class SessionEnded extends SignInError {
@@ -112935,30 +113677,29 @@ class SessionEnded extends SignInError {
112935
113677
  var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
112936
113678
  function createSession(options) {
112937
113679
  const api = serviceOrigin(options.api);
113680
+ const now = options.now ?? Date.now;
112938
113681
  const { store, signal } = options;
112939
- const directory = join107(options.home ?? homedir31(), ".omo", "session-locks");
112940
- const lockPath = join107(directory, `${credentialId(api)}.lock`);
112941
- const markerPath = signedOutMarkerPath(options.home ?? homedir31(), credentialId(api));
113682
+ const markerPath = signedOutMarkerPath(options.home ?? homedir32(), credentialId(api));
112942
113683
  async function locked(action) {
112943
- await mkdir11(directory, { recursive: true, mode: 448 });
112944
113684
  signal?.throwIfAborted();
112945
- return withLock(lockPath, async () => {
113685
+ return withCredentialLock(api, async () => {
112946
113686
  signal?.throwIfAborted();
112947
113687
  return action();
112948
- }, { ownerTag: "cli-session", staleAfterMs: Number.POSITIVE_INFINITY });
113688
+ }, options.home);
112949
113689
  }
112950
113690
  const request = (path, init) => requestApi(api, path, init, signal);
112951
- const uncertain = () => new SignInError(`The refresh outcome is unknown. Saved credentials and keys were retained, but this refresh token will not be sent again. ${signInHint("again")}`, true);
112952
- async function refreshedAccess(current) {
112953
- if (current.refreshState === "uncertain")
112954
- throw uncertain();
112955
- if (Date.parse(current.accessTokenExpiresAt) > Date.now() + 30000)
112956
- return current.accessToken;
113691
+ async function refreshed(current) {
113692
+ if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
113693
+ throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
113694
+ }
113695
+ if (Date.parse(current.accessTokenExpiresAt) > now() + 30000)
113696
+ return current;
112957
113697
  await store.write({ ...current, refreshState: "uncertain" });
112958
113698
  try {
112959
113699
  const tokens = parseReply(tokenSchema, await request("/v1/session/refresh", jsonRequest({ refreshToken: current.refreshToken })));
112960
- await store.write({ ...current, ...tokens });
112961
- return tokens.accessToken;
113700
+ const successor = { ...current, ...tokens };
113701
+ await store.write(successor);
113702
+ return successor;
112962
113703
  } catch (error) {
112963
113704
  if (error instanceof CredentialStoreError)
112964
113705
  throw error;
@@ -112970,12 +113711,19 @@ function createSession(options) {
112970
113711
  await store.write(current);
112971
113712
  throw error;
112972
113713
  }
112973
- throw uncertain();
113714
+ throw new SessionEnded(`The refresh outcome is unknown. Saved credentials and keys were retained. ${signInHint("again")}`, false, "refresh_recovery_expired");
112974
113715
  }
112975
113716
  }
113717
+ async function snapshot() {
113718
+ return locked(async () => {
113719
+ const current = await store.read();
113720
+ return current === null ? null : refreshed(current);
113721
+ });
113722
+ }
112976
113723
  return {
112977
113724
  request,
112978
113725
  signal,
113726
+ transaction: locked,
112979
113727
  async ready() {
112980
113728
  await store.read();
112981
113729
  },
@@ -112987,18 +113735,32 @@ function createSession(options) {
112987
113735
  },
112988
113736
  signedOutMarker: () => readSignedOutMarker(markerPath),
112989
113737
  clearSignedOutMarker: () => clearSignedOutMarker(markerPath),
112990
- async update(action) {
112991
- return locked(async () => action(await store.read()));
113738
+ async update(action, options = {}) {
113739
+ return locked(async () => {
113740
+ let current;
113741
+ try {
113742
+ current = await store.readAuthoritative();
113743
+ } catch (error) {
113744
+ if (!options.replaceInvalid || !(error instanceof InvalidCredentialState))
113745
+ throw error;
113746
+ current = null;
113747
+ }
113748
+ return action(current);
113749
+ });
112992
113750
  },
113751
+ async forget() {
113752
+ await locked(() => store.clear());
113753
+ },
113754
+ accessSnapshot: snapshot,
112993
113755
  async logout() {
112994
113756
  return locked(async () => {
112995
113757
  let current = null;
112996
113758
  try {
112997
- current = await store.read();
113759
+ current = await store.readAuthoritative();
112998
113760
  if (current !== null) {
112999
113761
  if (current.refreshState === "uncertain")
113000
113762
  return false;
113001
- const access = Date.parse(current.accessTokenExpiresAt) <= Date.now() ? await refreshedAccess(current) : current.accessToken;
113763
+ const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
113002
113764
  await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
113003
113765
  method: "DELETE",
113004
113766
  headers: { authorization: `Bearer ${access}` }
@@ -113017,12 +113779,19 @@ function createSession(options) {
113017
113779
  }
113018
113780
  });
113019
113781
  },
113020
- async accessToken() {
113782
+ async accessToken(expect) {
113783
+ signal?.throwIfAborted();
113784
+ const snapshot = await store.read();
113785
+ signal?.throwIfAborted();
113786
+ if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)))
113787
+ return snapshot.accessToken;
113021
113788
  return locked(async () => {
113022
- const current = await store.read();
113789
+ const current = await store.readAuthoritative();
113023
113790
  if (current === null)
113024
113791
  throw new SignInError(`Not signed in. ${signInHint("first")}`);
113025
- return refreshedAccess(current);
113792
+ if (expect !== undefined && !expect(current))
113793
+ throw new CredentialIdentityChanged;
113794
+ return (await refreshed(current)).accessToken;
113026
113795
  });
113027
113796
  },
113028
113797
  async removeForLimit(error, choose) {
@@ -113351,12 +114120,12 @@ async function boulder(options) {
113351
114120
  }
113352
114121
  // packages/omo-opencode/src/cli/codex-ulw-loop.ts
113353
114122
  import { spawn as spawn6 } from "child_process";
113354
- import { existsSync as existsSync67, readFileSync as readFileSync44, realpathSync as realpathSync13 } from "fs";
113355
- import { homedir as homedir32 } from "os";
114123
+ import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "fs";
114124
+ import { homedir as homedir33 } from "os";
113356
114125
  var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
113357
114126
  function resolveCodexUlwLoopCommand(input = {}) {
113358
114127
  const env = input.env ?? process.env;
113359
- const homeDir = input.homeDir ?? homedir32();
114128
+ const homeDir = input.homeDir ?? homedir33();
113360
114129
  const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
113361
114130
  if (localComponentBin !== null)
113362
114131
  return { executable: localComponentBin, argsPrefix: [] };
@@ -113401,7 +114170,7 @@ function resolveLegacyLocalOmoBin(env, homeDir, currentExecutablePaths) {
113401
114170
  }
113402
114171
  function isGeneratedRuntimeWrapper(candidate) {
113403
114172
  try {
113404
- return readFileSync44(candidate, "utf8").includes(RUNTIME_WRAPPER_MARKER);
114173
+ return readFileSync45(candidate, "utf8").includes(RUNTIME_WRAPPER_MARKER);
113405
114174
  } catch (error) {
113406
114175
  if (error instanceof Error)
113407
114176
  return false;
@@ -113414,7 +114183,7 @@ function isCurrentExecutable(candidate, currentExecutablePaths) {
113414
114183
  }
113415
114184
  function realpathOrSelf2(path) {
113416
114185
  try {
113417
- return realpathSync13(path);
114186
+ return realpathSync14(path);
113418
114187
  } catch (error) {
113419
114188
  if (error instanceof Error)
113420
114189
  return path;
@@ -113599,7 +114368,7 @@ function linkedWorktrees(records) {
113599
114368
  }
113600
114369
  // packages/omo-opencode/src/cli/worktree-sweep/sweep.ts
113601
114370
  import { existsSync as existsSync68 } from "fs";
113602
- import { stat as stat9 } from "fs/promises";
114371
+ import { stat as stat10 } from "fs/promises";
113603
114372
  import os7 from "os";
113604
114373
  import { normalize as normalize2 } from "path";
113605
114374
 
@@ -113682,7 +114451,7 @@ async function isOlderThan(worktreePath, days, now) {
113682
114451
  if (days <= 0)
113683
114452
  return false;
113684
114453
  try {
113685
- const stats = await stat9(worktreePath);
114454
+ const stats = await stat10(worktreePath);
113686
114455
  return now - stats.mtimeMs > days * DAY_MS;
113687
114456
  } catch {
113688
114457
  return false;
@@ -113929,7 +114698,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Baili
113929
114698
  Copilot github-copilot/ models (fallback)
113930
114699
  OpenCode Zen opencode/ models (opencode/claude-opus-5, etc.)
113931
114700
  Z.ai zai-coding-plan/glm-5.2 (visual-engineering fallback)
113932
- Kimi kimi-for-coding/kimi-k3 (Sisyphus/Prometheus fallback)
114701
+ Kimi kimi-for-coding/kimi-k3.1-pro (Sisyphus/Prometheus fallback)
113933
114702
  Bailian bailian-coding-plan/ models (Qwen, GLM, Kimi fallback)
113934
114703
  MiniMax minimax-coding-plan/MiniMax-M3 (utility fallback)
113935
114704
  MiniMax CN minimax-cn-coding-plan/MiniMax-M3 (utility fallback)