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
@@ -2133,7 +2133,7 @@ var package_default;
2133
2133
  var init_package = __esm(() => {
2134
2134
  package_default = {
2135
2135
  name: "oh-my-opencode",
2136
- version: "5.1.51",
2136
+ version: "5.1.54",
2137
2137
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
2138
2138
  main: "./dist/index.js",
2139
2139
  types: "dist/index.d.ts",
@@ -2275,14 +2275,15 @@ var init_package = __esm(() => {
2275
2275
  prepublishOnly: "bun run clean && bun run build:lsp-tools-mcp && bun run build:lsp-daemon && bun run build",
2276
2276
  "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",
2277
2277
  "check:copy": "bun script/check-copy.ts",
2278
- typecheck: "bun run check:copy && tsgo --noEmit && bun run typecheck:script && bun run typecheck:packages",
2279
- "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",
2280
- "typecheck:script": "tsgo --noEmit -p script/tsconfig.json",
2278
+ 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",
2279
+ "typecheck:skill-scripts": "bun check --no-script --all -p packages/shared-skills/skills/frontend/scripts/detect/tsconfig.json",
2280
+ "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",
2281
+ "typecheck:script": "bun check --no-script --all -p script/tsconfig.json",
2281
2282
  test: "bun test --timeout 20000",
2282
2283
  "changelog:section": "bun script/changelog-section.ts",
2283
2284
  "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",
2284
2285
  "test:fast": "bun run script/test-fast.ts",
2285
- "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",
2286
+ "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",
2286
2287
  "test:windows-codex": "bun run test:codex",
2287
2288
  "build:git-bash-mcp": "bun run --cwd packages/git-bash-mcp build",
2288
2289
  "build:ast-grep-mcp": "bun run --cwd packages/ast-grep-mcp build",
@@ -2318,7 +2319,7 @@ var init_package = __esm(() => {
2318
2319
  },
2319
2320
  devDependencies: {
2320
2321
  "@clack/prompts": "^1.8.1",
2321
- "@code-yeongyu/senpi": "2026.10.27-1",
2322
+ "@code-yeongyu/senpi": "2026.10.30-1",
2322
2323
  "@modelcontextprotocol/sdk": "^1.30.0",
2323
2324
  "@oh-my-opencode/agents-md-core": "workspace:*",
2324
2325
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
@@ -2372,7 +2373,7 @@ var init_package = __esm(() => {
2372
2373
  "jsonc-parser": "^3.3.1",
2373
2374
  knip: "6.43.0",
2374
2375
  "node-pty": "^1.1.0",
2375
- omowright: "github:code-yeongyu/omowright#f87ef4d63fe7b56fe117dbab246c8ad88dd8a780",
2376
+ omowright: "github:code-yeongyu/omowright#c06d20337ad942b09dea8757a45f6c848008a68d",
2376
2377
  "oxc-parser": "0.148.0",
2377
2378
  oxlint: "1.89.0",
2378
2379
  picocolors: "^1.1.1",
@@ -2382,18 +2383,18 @@ var init_package = __esm(() => {
2382
2383
  typescript: "^7.0.2"
2383
2384
  },
2384
2385
  optionalDependencies: {
2385
- "oh-my-opencode-darwin-arm64": "5.1.51",
2386
- "oh-my-opencode-darwin-x64": "5.1.51",
2387
- "oh-my-opencode-darwin-x64-baseline": "5.1.51",
2388
- "oh-my-opencode-linux-arm64": "5.1.51",
2389
- "oh-my-opencode-linux-arm64-musl": "5.1.51",
2390
- "oh-my-opencode-linux-x64": "5.1.51",
2391
- "oh-my-opencode-linux-x64-baseline": "5.1.51",
2392
- "oh-my-opencode-linux-x64-musl": "5.1.51",
2393
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.51",
2394
- "oh-my-opencode-windows-arm64": "5.1.51",
2395
- "oh-my-opencode-windows-x64": "5.1.51",
2396
- "oh-my-opencode-windows-x64-baseline": "5.1.51"
2386
+ "oh-my-opencode-darwin-arm64": "5.1.54",
2387
+ "oh-my-opencode-darwin-x64": "5.1.54",
2388
+ "oh-my-opencode-darwin-x64-baseline": "5.1.54",
2389
+ "oh-my-opencode-linux-arm64": "5.1.54",
2390
+ "oh-my-opencode-linux-arm64-musl": "5.1.54",
2391
+ "oh-my-opencode-linux-x64": "5.1.54",
2392
+ "oh-my-opencode-linux-x64-baseline": "5.1.54",
2393
+ "oh-my-opencode-linux-x64-musl": "5.1.54",
2394
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.54",
2395
+ "oh-my-opencode-windows-arm64": "5.1.54",
2396
+ "oh-my-opencode-windows-x64": "5.1.54",
2397
+ "oh-my-opencode-windows-x64-baseline": "5.1.54"
2397
2398
  },
2398
2399
  overrides: {
2399
2400
  hono: "^4.13.8",
@@ -8056,7 +8057,8 @@ var init_latest_models = __esm(() => {
8056
8057
  gptLunaFast: "gpt-6-luna-fast",
8057
8058
  glm: "glm-5.3",
8058
8059
  glmFlash: "glm-5.3-flash",
8059
- kimi: "kimi-k3",
8060
+ kimi: "kimi-k3.1-pro",
8061
+ kimiK3: "kimi-k3",
8060
8062
  geminiPro: "gemini-4-argon"
8061
8063
  };
8062
8064
  });
@@ -9379,9 +9381,13 @@ var init_agent_model_requirements = __esm(() => {
9379
9381
  variant: "max"
9380
9382
  },
9381
9383
  {
9382
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode", "bailian-coding-plan", "moonshotai-cn", "firmware", "ollama-cloud", "aihubmix"],
9384
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai", "moonshotai-cn"],
9383
9385
  model: LATEST_MODEL_BY_FAMILY.kimi
9384
9386
  },
9387
+ {
9388
+ providers: ["opencode", "bailian-coding-plan", "firmware", "ollama-cloud", "aihubmix"],
9389
+ model: LATEST_MODEL_BY_FAMILY.kimiK3
9390
+ },
9385
9391
  {
9386
9392
  providers: ["openai", "chatgpt-subscription", "github-copilot", "opencode"],
9387
9393
  model: "gpt-5.6-sol",
@@ -9476,10 +9482,11 @@ var init_agent_model_requirements = __esm(() => {
9476
9482
  variant: "max"
9477
9483
  },
9478
9484
  {
9479
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode"],
9485
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai"],
9480
9486
  model: LATEST_MODEL_BY_FAMILY.kimi,
9481
9487
  variant: "max"
9482
- }
9488
+ },
9489
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9483
9490
  ])
9484
9491
  },
9485
9492
  metis: {
@@ -9500,10 +9507,11 @@ var init_agent_model_requirements = __esm(() => {
9500
9507
  variant: "max"
9501
9508
  },
9502
9509
  {
9503
- providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode"],
9510
+ providers: ["opencode-go", "kimi-for-coding", "moonshotai"],
9504
9511
  model: LATEST_MODEL_BY_FAMILY.kimi,
9505
9512
  variant: "max"
9506
- }
9513
+ },
9514
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9507
9515
  ])
9508
9516
  },
9509
9517
  momus: {
@@ -9586,10 +9594,11 @@ var init_category_model_requirements = __esm(() => {
9586
9594
  variant: "max"
9587
9595
  },
9588
9596
  {
9589
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9597
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9590
9598
  model: LATEST_MODEL_BY_FAMILY.kimi,
9591
9599
  variant: "max"
9592
- }
9600
+ },
9601
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9593
9602
  ])
9594
9603
  },
9595
9604
  ultrabrain: {
@@ -9641,10 +9650,11 @@ var init_category_model_requirements = __esm(() => {
9641
9650
  variant: "max"
9642
9651
  },
9643
9652
  {
9644
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9653
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9645
9654
  model: LATEST_MODEL_BY_FAMILY.kimi,
9646
9655
  variant: "max"
9647
- }
9656
+ },
9657
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9648
9658
  ])
9649
9659
  },
9650
9660
  quick: {
@@ -9707,10 +9717,11 @@ var init_category_model_requirements = __esm(() => {
9707
9717
  },
9708
9718
  { providers: ["zai-coding-plan", "opencode-go"], model: LATEST_MODEL_BY_FAMILY.glm, variant: "max" },
9709
9719
  {
9710
- providers: ["kimi-for-coding", "moonshotai", "opencode-go", "opencode"],
9720
+ providers: ["kimi-for-coding", "moonshotai", "opencode-go"],
9711
9721
  model: LATEST_MODEL_BY_FAMILY.kimi,
9712
9722
  variant: "max"
9713
- }
9723
+ },
9724
+ { providers: ["opencode"], model: LATEST_MODEL_BY_FAMILY.kimiK3, variant: "max" }
9714
9725
  ]
9715
9726
  },
9716
9727
  writing: {
@@ -10274,7 +10285,7 @@ function transformModelForProviderDisplay(provider, model) {
10274
10285
  var CLAUDE_VERSION_DOT, GEMINI_31_PRO_PREVIEW, GEMINI_3_FLASH_PREVIEW;
10275
10286
  var init_provider_model_id_transform = __esm(() => {
10276
10287
  CLAUDE_VERSION_DOT = /claude-(\w+)-(\d+)-(\d+)/g;
10277
- GEMINI_31_PRO_PREVIEW = /gemini-3\.1-pro(?!-)/g;
10288
+ GEMINI_31_PRO_PREVIEW = /(?<!antigravity-)gemini-3\.1-pro(?!-)/g;
10278
10289
  GEMINI_3_FLASH_PREVIEW = /(?<!antigravity-)gemini-3-flash(?!-)/g;
10279
10290
  });
10280
10291
 
@@ -10348,6 +10359,36 @@ var init_supplemental_entries = __esm(() => {
10348
10359
  output: 262144
10349
10360
  }
10350
10361
  },
10362
+ "kimi-k3.1-pro": {
10363
+ id: "kimi-k3.1-pro",
10364
+ family: "kimi",
10365
+ reasoning: true,
10366
+ temperature: true,
10367
+ toolCall: true,
10368
+ modalities: {
10369
+ input: ["text", "image", "video"],
10370
+ output: ["text"]
10371
+ },
10372
+ limit: {
10373
+ context: 1048576,
10374
+ output: 1048576
10375
+ }
10376
+ },
10377
+ "kimi-k3.1-pro-highspeed": {
10378
+ id: "kimi-k3.1-pro-highspeed",
10379
+ family: "kimi",
10380
+ reasoning: true,
10381
+ temperature: true,
10382
+ toolCall: true,
10383
+ modalities: {
10384
+ input: ["text", "image", "video"],
10385
+ output: ["text"]
10386
+ },
10387
+ limit: {
10388
+ context: 1048576,
10389
+ output: 1048576
10390
+ }
10391
+ },
10351
10392
  "kimi-k2.6": {
10352
10393
  id: "kimi-k2.6",
10353
10394
  family: "kimi",
@@ -12432,6 +12473,33 @@ function createJsonFileCacheStore(options) {
12432
12473
  });
12433
12474
  }
12434
12475
  }
12476
+ function writeIfChanged(value) {
12477
+ ensureCacheDir();
12478
+ const cacheFile = getCacheFilePath();
12479
+ const serialized = options.serialize?.(value) ?? JSON.stringify(value, null, 2);
12480
+ try {
12481
+ const existing = existsSync10(cacheFile) ? readFileSync3(cacheFile, "utf-8") : undefined;
12482
+ const unchanged = existing !== undefined && (existing === serialized || options.comparable !== undefined && JSON.stringify(options.comparable(JSON.parse(existing))) === JSON.stringify(options.comparable(value)));
12483
+ if (unchanged) {
12484
+ memoryValue = value;
12485
+ writtenInCurrentProcess = true;
12486
+ log2(`[${options.logPrefix}] ${options.cacheLabel} unchanged; skipped write`, options.describe(value));
12487
+ return false;
12488
+ }
12489
+ } catch {}
12490
+ try {
12491
+ writeFileSync4(cacheFile, serialized);
12492
+ memoryValue = value;
12493
+ writtenInCurrentProcess = true;
12494
+ log2(`[${options.logPrefix}] ${options.cacheLabel} written`, options.describe(value));
12495
+ return true;
12496
+ } catch (error) {
12497
+ log2(`[${options.logPrefix}] Error writing ${toLogLabel(options.cacheLabel)}`, {
12498
+ error: String(error)
12499
+ });
12500
+ return false;
12501
+ }
12502
+ }
12435
12503
  function resetMemory() {
12436
12504
  memoryValue = undefined;
12437
12505
  writtenInCurrentProcess = false;
@@ -12440,6 +12508,7 @@ function createJsonFileCacheStore(options) {
12440
12508
  read,
12441
12509
  has,
12442
12510
  write,
12511
+ writeIfChanged,
12443
12512
  resetMemory
12444
12513
  };
12445
12514
  }
@@ -67504,7 +67573,8 @@ function createModelCapabilitiesCacheStore(getCacheDir = getOmoOpenCodeCacheDir)
67504
67573
  generatedAt: snapshot.generatedAt
67505
67574
  }),
67506
67575
  serialize: (snapshot) => `${JSON.stringify(snapshot, null, 2)}
67507
- `
67576
+ `,
67577
+ comparable: ({ generatedAt: _generatedAt, ...catalog }) => catalog
67508
67578
  });
67509
67579
  function readModelCapabilitiesCache() {
67510
67580
  return snapshotCacheStore.read();
@@ -67517,7 +67587,7 @@ function createModelCapabilitiesCacheStore(getCacheDir = getOmoOpenCodeCacheDir)
67517
67587
  }
67518
67588
  async function refreshModelCapabilitiesCache(args = {}) {
67519
67589
  const snapshot = await fetchModelCapabilitiesSnapshot(args);
67520
- writeModelCapabilitiesCache(snapshot);
67590
+ snapshotCacheStore.writeIfChanged(snapshot);
67521
67591
  return snapshot;
67522
67592
  }
67523
67593
  return {
@@ -77232,8 +77302,8 @@ var init_memory = __esm(() => {
77232
77302
  enabled: boolean2().optional()
77233
77303
  }).strict();
77234
77304
  OmoMemoryProjectionSchema = object({
77235
- max_entries_per_directory: number2().int().min(0).default(40),
77236
- max_bytes: number2().int().min(0).default(24576)
77305
+ max_entries_per_directory: number2().int().min(0).default(0),
77306
+ max_bytes: number2().int().min(0).default(40960)
77237
77307
  }).strict();
77238
77308
  OmoMemoryProjectionLayerSchema = object({
77239
77309
  max_entries_per_directory: number2().int().min(0).optional(),
@@ -77297,7 +77367,7 @@ var init_memory = __esm(() => {
77297
77367
  query_expansion: false
77298
77368
  }),
77299
77369
  project_scope: OmoMemoryProjectScopeSchema.default({ nudge: true, recall: true }),
77300
- projection: OmoMemoryProjectionSchema.default({ max_entries_per_directory: 40, max_bytes: 24576 }),
77370
+ projection: OmoMemoryProjectionSchema.default({ max_entries_per_directory: 0, max_bytes: 40960 }),
77301
77371
  compile_warn_tokens: number2().int().positive().default(30000),
77302
77372
  agents: record(string2(), OmoMemoryAgentOverridesSchema).default({})
77303
77373
  }).strict();
@@ -77345,6 +77415,21 @@ var init_model_catalog = __esm(() => {
77345
77415
  OmoModelCatalogLayerSchema = record(string2(), OmoModelCatalogEntryLayerSchema);
77346
77416
  });
77347
77417
 
77418
+ // packages/omo-config-core/src/schema/model-pad.ts
77419
+ var OmoModelPadLabelsSchema, OmoModelPadSchema;
77420
+ var init_model_pad = __esm(() => {
77421
+ init_zod();
77422
+ OmoModelPadLabelsSchema = object({
77423
+ daily: string2().optional(),
77424
+ geeky: string2().optional(),
77425
+ normal: string2().optional(),
77426
+ heavy: string2().optional()
77427
+ }).strict();
77428
+ OmoModelPadSchema = object({
77429
+ labels: OmoModelPadLabelsSchema.optional()
77430
+ }).strict();
77431
+ });
77432
+
77348
77433
  // packages/omo-config-core/src/schema/model-profile.ts
77349
77434
  function isRecord8(value) {
77350
77435
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -77665,6 +77750,7 @@ var init_config = __esm(() => {
77665
77750
  init_git_master();
77666
77751
  init_memory();
77667
77752
  init_model_catalog();
77753
+ init_model_pad();
77668
77754
  init_model_profile();
77669
77755
  init_side_panel();
77670
77756
  init_task();
@@ -77686,6 +77772,7 @@ var init_config = __esm(() => {
77686
77772
  models: OmoModelCatalogLayerSchema.optional(),
77687
77773
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77688
77774
  model_profile: string2().optional(),
77775
+ model_pad: OmoModelPadSchema.optional(),
77689
77776
  memory: OmoMemorySettingsLayerSchema.optional(),
77690
77777
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77691
77778
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77704,6 +77791,7 @@ var init_config = __esm(() => {
77704
77791
  models: OmoModelCatalogLayerSchema.optional(),
77705
77792
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77706
77793
  model_profile: string2().optional(),
77794
+ model_pad: OmoModelPadSchema.optional(),
77707
77795
  memory: OmoMemorySettingsLayerSchema.optional(),
77708
77796
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77709
77797
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77727,6 +77815,7 @@ var init_config = __esm(() => {
77727
77815
  models: OmoModelCatalogSchema.optional(),
77728
77816
  model_profiles: OmoModelProfilesSchema.optional(),
77729
77817
  model_profile: string2().optional(),
77818
+ model_pad: OmoModelPadSchema.optional(),
77730
77819
  memory: OmoMemorySettingsSchema.optional(),
77731
77820
  telemetry: OmoTelemetrySettingsSchema.optional(),
77732
77821
  side_panel: OmoSidePanelSettingsSchema.optional(),
@@ -77753,6 +77842,7 @@ var init_config = __esm(() => {
77753
77842
  models: OmoModelCatalogLayerSchema.optional(),
77754
77843
  model_profiles: OmoModelProfilesLayerSchema.optional(),
77755
77844
  model_profile: string2().optional(),
77845
+ model_pad: OmoModelPadSchema.optional(),
77756
77846
  memory: OmoMemorySettingsLayerSchema.optional(),
77757
77847
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77758
77848
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
@@ -77898,6 +77988,7 @@ var init_schema = __esm(() => {
77898
77988
  init_legacy_harness_names();
77899
77989
  init_memory();
77900
77990
  init_model_catalog();
77991
+ init_model_pad();
77901
77992
  init_model_profile();
77902
77993
  init_model_ref();
77903
77994
  init_provenance();
@@ -82918,6 +83009,37 @@ function getDefaultTelemetryOsProvider() {
82918
83009
  }
82919
83010
  var init_machine_id = () => {};
82920
83011
 
83012
+ // packages/telemetry-core/src/terminal-program.ts
83013
+ function isKnownTerminalProgram(value) {
83014
+ return KNOWN_TERMINAL_PROGRAMS.some((known) => known === value);
83015
+ }
83016
+ function toTelemetryTerminalProgram(termProgram) {
83017
+ if (termProgram === undefined || termProgram === "")
83018
+ return;
83019
+ return isKnownTerminalProgram(termProgram) ? termProgram : "other";
83020
+ }
83021
+ var KNOWN_TERMINAL_PROGRAMS;
83022
+ var init_terminal_program = __esm(() => {
83023
+ KNOWN_TERMINAL_PROGRAMS = [
83024
+ "Apple_Terminal",
83025
+ "iTerm.app",
83026
+ "vscode",
83027
+ "cursor",
83028
+ "windsurf",
83029
+ "zed",
83030
+ "WezTerm",
83031
+ "ghostty",
83032
+ "tmux",
83033
+ "Hyper",
83034
+ "WarpTerminal",
83035
+ "kitty",
83036
+ "alacritty",
83037
+ "Tabby",
83038
+ "rio",
83039
+ "mintty"
83040
+ ];
83041
+ });
83042
+
82921
83043
  // packages/telemetry-core/src/injected-client.ts
82922
83044
  function isTelemetryClientEnabled(input) {
82923
83045
  const env = input.env ?? process.env;
@@ -83020,12 +83142,16 @@ function getSharedProperties(input) {
83020
83142
  total_memory_gb: Math.round(osProvider.totalmem() / 1024 / 1024 / 1024),
83021
83143
  locale: Intl.DateTimeFormat().resolvedOptions().locale,
83022
83144
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
83023
- shell: process.env.SHELL,
83145
+ shell: getShellName(process.env.SHELL),
83024
83146
  ci: Boolean(process.env.CI),
83025
- terminal: process.env.TERM_PROGRAM,
83147
+ terminal: toTelemetryTerminalProgram(process.env.TERM_PROGRAM),
83026
83148
  ...input.product.additionalProperties
83027
83149
  };
83028
83150
  }
83151
+ function getShellName(shellPath) {
83152
+ const name = shellPath?.split(/[\\/]/).pop()?.replace(/\.exe$/i, "");
83153
+ return name ? name : undefined;
83154
+ }
83029
83155
  function getSafeCpuInfo(osProvider, input) {
83030
83156
  try {
83031
83157
  const cpuInfo = osProvider.cpus();
@@ -83050,6 +83176,7 @@ var NO_OP_CLIENT;
83050
83176
  var init_injected_client = __esm(() => {
83051
83177
  init_env();
83052
83178
  init_machine_id();
83179
+ init_terminal_program();
83053
83180
  NO_OP_CLIENT = {
83054
83181
  enabled: false,
83055
83182
  trackActive: () => {
@@ -92629,7 +92756,7 @@ var package_default2;
92629
92756
  var init_package2 = __esm(() => {
92630
92757
  package_default2 = {
92631
92758
  name: "@oh-my-opencode/omo-codex",
92632
- version: "5.1.51",
92759
+ version: "5.1.54",
92633
92760
  type: "module",
92634
92761
  private: true,
92635
92762
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -93837,11 +93964,22 @@ init_commander();
93837
93964
  // packages/omo-opencode/src/cli/install.ts
93838
93965
  init_package();
93839
93966
 
93967
+ // packages/omo-opencode/src/cli/cli-installer.ts
93968
+ import { createInterface as createInterface2 } from "node:readline/promises";
93969
+
93970
+ // packages/telemetry-core/src/install-disclosure.ts
93971
+ var TELEMETRY_PRIVACY_POLICY_URL = "https://github.com/code-yeongyu/oh-my-openagent/blob/dev/docs/legal/privacy-policy.md";
93972
+ var TELEMETRY_INSTALL_DISCLOSURE_LINES = [
93973
+ "OmO sends anonymous usage telemetry (no prompts, code, file paths, or account data) to improve the product.",
93974
+ "The data goes to PostHog in the United States.",
93975
+ "Turn it off with DO_NOT_TRACK=1 (or OMO_DISABLE_TELEMETRY=1).",
93976
+ `Details: ${TELEMETRY_PRIVACY_POLICY_URL}`
93977
+ ];
93978
+
93840
93979
  // packages/omo-opencode/src/cli/cli-installer.ts
93841
93980
  init_shared();
93842
93981
  init_config_manager();
93843
93982
  var import_picocolors3 = __toESM(require_picocolors(), 1);
93844
- import { createInterface as createInterface2 } from "node:readline/promises";
93845
93983
 
93846
93984
  // packages/omo-opencode/src/cli/install-validators.ts
93847
93985
  var import_picocolors = __toESM(require_picocolors(), 1);
@@ -100002,6 +100140,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
100002
100140
  join66("extensions", "omo-thread-client.js"),
100003
100141
  join66("extensions", "omo-telemetry-recovery.js"),
100004
100142
  join66("extensions", "omo-feedback.js"),
100143
+ join66("extensions", "omo-desktop-toolkit.js"),
100005
100144
  join66("extensions", "omo-claim-receipt.js"),
100006
100145
  join66("extensions", "assets.generated.json"),
100007
100146
  join66("extensions", "omo-member.js"),
@@ -101280,8 +101419,8 @@ async function runCliInstaller(args, version) {
101280
101419
  }
101281
101420
  console.log();
101282
101421
  }
101283
- printInfo("Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.");
101284
- printInfo("Docs: docs/legal/privacy-policy.md and docs/legal/terms-of-service.md");
101422
+ for (const line of TELEMETRY_INSTALL_DISCLOSURE_LINES)
101423
+ printInfo(line);
101285
101424
  console.log();
101286
101425
  printBox(`${import_picocolors3.default.bold("Pro Tip:")} Include ${import_picocolors3.default.cyan("ultrawork")} (or ${import_picocolors3.default.cyan("ulw")}) in your prompt.
101287
101426
  ` + `All features work like magic-parallel agents, background tasks,
@@ -102577,7 +102716,7 @@ async function promptInstallConfig(detected, platform, codexAutonomousOverride)
102577
102716
  message: "Do you have a Kimi For Coding subscription?",
102578
102717
  options: [
102579
102718
  { value: "no", label: "No", hint: "Will use other configured providers" },
102580
- { value: "yes", label: "Yes", hint: "Kimi K3 for Sisyphus/Prometheus fallback" }
102719
+ { value: "yes", label: "Yes", hint: "Kimi K3.1 Pro for Sisyphus/Prometheus fallback" }
102581
102720
  ],
102582
102721
  initialValue: initial.kimiForCoding
102583
102722
  });
@@ -102836,8 +102975,8 @@ async function runTuiInstaller(args, version) {
102836
102975
  if (config.hasOpenCode) {
102837
102976
  log4.message(`Run ${import_picocolors4.default.cyan("opencode")} to start!`);
102838
102977
  }
102839
- log4.info("Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.");
102840
- log4.info("Docs: docs/legal/privacy-policy.md and docs/legal/terms-of-service.md");
102978
+ log4.info(TELEMETRY_INSTALL_DISCLOSURE_LINES.join(`
102979
+ `));
102841
102980
  note(`Include ${import_picocolors4.default.cyan("ultrawork")} (or ${import_picocolors4.default.cyan("ulw")}) in your prompt.
102842
102981
  ` + `All features work like magic-parallel agents, background tasks,
102843
102982
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
@@ -109374,6 +109513,8 @@ var package_default3 = {
109374
109513
  },
109375
109514
  dependencies: {
109376
109515
  "@clack/prompts": "^1.8.1",
109516
+ "@code-yeongyu/senpi": "2026.10.30-1",
109517
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.30-1",
109377
109518
  "@modelcontextprotocol/sdk": "^1.30.0",
109378
109519
  "@oh-my-opencode/agents-md-core": "workspace:*",
109379
109520
  "@oh-my-opencode/boulder-state": "workspace:*",
@@ -110682,6 +110823,8 @@ function isOAuthTokenData(value) {
110682
110823
  if (typeof value !== "object" || value === null || Array.isArray(value))
110683
110824
  return false;
110684
110825
  const record = value;
110826
+ if (record["issuer"] !== undefined && typeof record["issuer"] !== "string")
110827
+ return false;
110685
110828
  if (typeof record["accessToken"] !== "string")
110686
110829
  return false;
110687
110830
  const refreshToken = record["refreshToken"];
@@ -110696,6 +110839,8 @@ function isOAuthTokenData(value) {
110696
110839
  if (typeof clientInfo !== "object" || clientInfo === null || Array.isArray(clientInfo))
110697
110840
  return false;
110698
110841
  const clientRecord = clientInfo;
110842
+ if (clientRecord["issuer"] !== undefined && typeof clientRecord["issuer"] !== "string")
110843
+ return false;
110699
110844
  if (typeof clientRecord["clientId"] !== "string")
110700
110845
  return false;
110701
110846
  const clientSecret = clientRecord["clientSecret"];
@@ -110764,7 +110909,9 @@ function deleteToken(serverHost, resource) {
110764
110909
  return deleteLegacyToken(serverHost, resource);
110765
110910
  try {
110766
110911
  unlinkSync9(filePath);
110767
- return deleteTokenIndexEntry(getMcpOauthStorageDir(), getMcpOauthServerHash(serverHost, resource));
110912
+ const indexDeleted = deleteTokenIndexEntry(getMcpOauthStorageDir(), getMcpOauthServerHash(serverHost, resource));
110913
+ const legacyDeleted = deleteLegacyToken(serverHost, resource);
110914
+ return indexDeleted && legacyDeleted;
110768
110915
  } catch (deleteError) {
110769
110916
  if (!(deleteError instanceof Error))
110770
110917
  throw deleteError;
@@ -110874,19 +111021,26 @@ async function fetchMetadata(url) {
110874
111021
  }
110875
111022
  return { ok: true, json };
110876
111023
  }
110877
- function parseMetadataFields(json, resource) {
111024
+ function parseMetadataFields(json, resource, expectedIssuer) {
111025
+ const issuer = readStringField(json, "issuer");
111026
+ parseHttpsUrl(issuer, "issuer");
111027
+ if (issuer !== expectedIssuer) {
111028
+ throw new Error("OAuth metadata issuer mismatch");
111029
+ }
110878
111030
  const authorizationEndpoint = parseHttpsUrl(readStringField(json, "authorization_endpoint"), "authorization_endpoint").toString();
110879
111031
  const tokenEndpoint = parseHttpsUrl(readStringField(json, "token_endpoint"), "token_endpoint").toString();
110880
111032
  const registrationEndpointValue = json.registration_endpoint;
110881
111033
  const registrationEndpoint = typeof registrationEndpointValue === "string" && registrationEndpointValue.length > 0 ? parseHttpsUrl(registrationEndpointValue, "registration_endpoint").toString() : undefined;
110882
111034
  return {
111035
+ issuer,
111036
+ ...json.authorization_response_iss_parameter_supported === true ? { authorizationResponseIssParameterSupported: true } : {},
110883
111037
  authorizationEndpoint,
110884
111038
  tokenEndpoint,
110885
111039
  registrationEndpoint,
110886
111040
  resource
110887
111041
  };
110888
111042
  }
110889
- async function fetchAuthorizationServerMetadata(issuer, resource) {
111043
+ async function fetchAuthorizationServerMetadata(issuer, resource, allowOriginFallback = false) {
110890
111044
  const issuerUrl = parseHttpsUrl(issuer, "Authorization server URL");
110891
111045
  const issuerPath = issuerUrl.pathname.replace(/\/+$/, "");
110892
111046
  const metadataUrl = new URL(`/.well-known/oauth-authorization-server${issuerPath}`, issuerUrl).toString();
@@ -110896,7 +111050,7 @@ async function fetchAuthorizationServerMetadata(issuer, resource) {
110896
111050
  const rootMetadataUrl = new URL("/.well-known/oauth-authorization-server", issuerUrl).toString();
110897
111051
  const rootMetadata = await fetchMetadata(rootMetadataUrl);
110898
111052
  if (rootMetadata.ok) {
110899
- return parseMetadataFields(rootMetadata.json, resource);
111053
+ return parseMetadataFields(rootMetadata.json, resource, allowOriginFallback ? issuerUrl.origin : issuer);
110900
111054
  }
110901
111055
  }
110902
111056
  if (metadata.status === 404) {
@@ -110904,7 +111058,7 @@ async function fetchAuthorizationServerMetadata(issuer, resource) {
110904
111058
  }
110905
111059
  throw new Error(`OAuth authorization server metadata fetch failed (${metadata.status})`);
110906
111060
  }
110907
- return parseMetadataFields(metadata.json, resource);
111061
+ return parseMetadataFields(metadata.json, resource, issuer);
110908
111062
  }
110909
111063
  function parseAuthorizationServers(metadata) {
110910
111064
  const servers = metadata.authorization_servers;
@@ -110912,11 +111066,11 @@ function parseAuthorizationServers(metadata) {
110912
111066
  return [];
110913
111067
  return servers.filter((server) => typeof server === "string" && server.length > 0);
110914
111068
  }
110915
- async function discoverOAuthServerMetadata(resource) {
111069
+ async function discoverOAuthServerMetadata(resource, forceRefresh = false) {
110916
111070
  const resourceUrl = parseHttpsUrl(resource, "Resource server URL");
110917
111071
  const resourceKey = resourceUrl.toString();
110918
111072
  const cached = discoveryCache.get(resourceKey);
110919
- if (cached)
111073
+ if (cached && !forceRefresh)
110920
111074
  return cached;
110921
111075
  const pending = pendingDiscovery.get(resourceKey);
110922
111076
  if (pending)
@@ -110934,7 +111088,7 @@ async function discoverOAuthServerMetadata(resource) {
110934
111088
  if (prmResponse.status !== 404) {
110935
111089
  throw new Error(`OAuth protected resource metadata fetch failed (${prmResponse.status})`);
110936
111090
  }
110937
- return fetchAuthorizationServerMetadata(resourceKey, resource);
111091
+ return fetchAuthorizationServerMetadata(resource.replace(/\/+$/, ""), resource, true);
110938
111092
  })();
110939
111093
  pendingDiscovery.set(resourceKey, discoveryPromise);
110940
111094
  try {
@@ -110958,6 +111112,10 @@ async function getOrRegisterClient(options) {
110958
111112
  }
110959
111113
  const fetchImpl = options.fetch ?? globalThis.fetch;
110960
111114
  const request = {
111115
+ application_type: options.redirectUris.some((uri) => {
111116
+ const url = new URL(uri);
111117
+ return (url.protocol === "http:" || url.protocol === "https:") && !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname);
111118
+ }) ? "web" : "native",
110961
111119
  redirect_uris: options.redirectUris,
110962
111120
  client_name: options.clientName,
110963
111121
  grant_types: ["authorization_code", "refresh_token"],
@@ -111034,12 +111192,20 @@ function buildAuthorizationUrl(authorizationEndpoint, options) {
111034
111192
  return url.toString();
111035
111193
  }
111036
111194
  var CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
111037
- function startCallbackServer(port) {
111195
+ function startCallbackServer(port, validation) {
111038
111196
  return new Promise((resolve, reject) => {
111039
111197
  let timeoutId;
111040
111198
  const server = createServer2((request, response) => {
111041
111199
  clearTimeout(timeoutId);
111042
111200
  const requestUrl = new URL(request.url ?? "/", `http://localhost:${port}`);
111201
+ const issuer = requestUrl.searchParams.get("iss");
111202
+ if (validation && (issuer !== null && issuer !== validation.issuer || issuer === null && validation.authorizationResponseIssParameterSupported)) {
111203
+ response.writeHead(400, { "content-type": "text/html" });
111204
+ response.end("<html><body><h1>Authorization failed</h1></body></html>");
111205
+ server.close();
111206
+ reject(new Error("OAuth authorization response issuer mismatch or missing issuer"));
111207
+ return;
111208
+ }
111043
111209
  const code = requestUrl.searchParams.get("code");
111044
111210
  const state = requestUrl.searchParams.get("state");
111045
111211
  const error = requestUrl.searchParams.get("error");
@@ -111109,7 +111275,7 @@ async function runAuthorizationCodeRedirect(options) {
111109
111275
  scopes: options.scopes,
111110
111276
  resource: options.resource
111111
111277
  });
111112
- const callbackPromise = startCallbackServer(options.callbackPort);
111278
+ const callbackPromise = startCallbackServer(options.callbackPort, options);
111113
111279
  openBrowser(authorizationUrl);
111114
111280
  const result = await callbackPromise;
111115
111281
  if (result.state !== state) {
@@ -111144,10 +111310,12 @@ function buildOAuthTokenData(tokenData, clientInfo, fallbackRefreshToken) {
111144
111310
  throw new Error("Token response missing access_token");
111145
111311
  }
111146
111312
  return {
111313
+ ...clientInfo.issuer ? { issuer: clientInfo.issuer } : {},
111147
111314
  accessToken,
111148
111315
  refreshToken: typeof tokenData["refresh_token"] === "string" ? tokenData["refresh_token"] : fallbackRefreshToken,
111149
111316
  expiresAt: typeof tokenData["expires_in"] === "number" ? Math.floor(Date.now() / 1000) + tokenData["expires_in"] : undefined,
111150
111317
  clientInfo: {
111318
+ ...clientInfo.issuer ? { issuer: clientInfo.issuer } : {},
111151
111319
  clientId: clientInfo.clientId,
111152
111320
  ...clientInfo.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
111153
111321
  }
@@ -111161,6 +111329,7 @@ class McpOAuthProvider {
111161
111329
  storedCodeVerifier = null;
111162
111330
  storedClientInfo = null;
111163
111331
  callbackPort = null;
111332
+ issuer;
111164
111333
  constructor(options) {
111165
111334
  this.serverUrl = options.serverUrl;
111166
111335
  this.configClientId = options.clientId;
@@ -111170,7 +111339,32 @@ class McpOAuthProvider {
111170
111339
  return loadToken(this.serverUrl, this.serverUrl);
111171
111340
  }
111172
111341
  saveTokens(tokenData) {
111173
- return saveToken(this.serverUrl, this.serverUrl, tokenData);
111342
+ const issuer = tokenData.issuer ?? this.issuer;
111343
+ return saveToken(this.serverUrl, this.serverUrl, issuer ? {
111344
+ ...tokenData,
111345
+ issuer,
111346
+ ...tokenData.clientInfo ? { clientInfo: { ...tokenData.clientInfo, issuer: tokenData.clientInfo.issuer ?? issuer } } : {}
111347
+ } : tokenData);
111348
+ }
111349
+ bindIssuer(issuer) {
111350
+ const token = this.tokens();
111351
+ const stamps = [token?.issuer, token?.clientInfo?.issuer, this.storedClientInfo?.issuer, this.issuer];
111352
+ const changed = stamps.some((stamp) => stamp !== undefined && stamp !== issuer);
111353
+ if (changed) {
111354
+ this.storedClientInfo = null;
111355
+ this.storedCodeVerifier = null;
111356
+ if (!deleteToken(this.serverUrl, this.serverUrl)) {
111357
+ throw new Error("Unable to discard credentials for the previous OAuth issuer");
111358
+ }
111359
+ }
111360
+ this.issuer = issuer;
111361
+ if (!changed && token && !this.saveTokens(token)) {
111362
+ throw new Error("Unable to stamp stored OAuth credentials with their issuer");
111363
+ }
111364
+ const clientInfo = this.clientInformation();
111365
+ if (clientInfo)
111366
+ this.storedClientInfo = { ...clientInfo, issuer };
111367
+ return changed;
111174
111368
  }
111175
111369
  clientInformation() {
111176
111370
  if (this.storedClientInfo)
@@ -111200,6 +111394,8 @@ class McpOAuthProvider {
111200
111394
  this.callbackPort = await findAvailablePort2();
111201
111395
  }
111202
111396
  const result = await runAuthorizationCodeRedirect({
111397
+ issuer: metadata.issuer,
111398
+ authorizationResponseIssParameterSupported: metadata.authorizationResponseIssParameterSupported,
111203
111399
  authorizationEndpoint: metadata.authorizationEndpoint,
111204
111400
  callbackPort: this.callbackPort,
111205
111401
  clientId: clientInfo.clientId,
@@ -111211,16 +111407,19 @@ class McpOAuthProvider {
111211
111407
  return { code: result.code };
111212
111408
  }
111213
111409
  async login() {
111214
- const metadata = await discoverOAuthServerMetadata(this.serverUrl);
111410
+ const metadata = await discoverOAuthServerMetadata(this.serverUrl, true);
111411
+ this.bindIssuer(metadata.issuer);
111412
+ if (this.callbackPort === null)
111413
+ this.callbackPort = await findAvailablePort2();
111215
111414
  const clientRegistrationStorage = {
111216
111415
  getClientRegistration: () => this.storedClientInfo,
111217
111416
  setClientRegistration: (_serverIdentifier, credentials) => {
111218
- this.storedClientInfo = credentials;
111417
+ this.storedClientInfo = { ...credentials, issuer: metadata.issuer };
111219
111418
  }
111220
111419
  };
111221
111420
  const clientInfo = await getOrRegisterClient({
111222
111421
  ...metadata.registrationEndpoint ? { registrationEndpoint: metadata.registrationEndpoint } : {},
111223
- serverIdentifier: this.serverUrl,
111422
+ serverIdentifier: metadata.issuer,
111224
111423
  clientName: PLUGIN_NAME4,
111225
111424
  redirectUris: [this.redirectUrl()],
111226
111425
  tokenEndpointAuthMethod: "none",
@@ -111230,7 +111429,7 @@ class McpOAuthProvider {
111230
111429
  if (!clientInfo) {
111231
111430
  throw new Error("Failed to obtain client credentials. Provide a clientId or ensure the server supports DCR.");
111232
111431
  }
111233
- this.storedClientInfo = clientInfo;
111432
+ this.storedClientInfo = { ...clientInfo, issuer: metadata.issuer };
111234
111433
  const { code } = await this.redirectToAuthorization(metadata);
111235
111434
  const verifier = this.codeVerifier();
111236
111435
  if (!verifier) {
@@ -111249,12 +111448,14 @@ class McpOAuthProvider {
111249
111448
  }).toString()
111250
111449
  });
111251
111450
  const tokenData = await parseTokenResponse(tokenResponse);
111252
- const oauthTokenData = buildOAuthTokenData(tokenData, clientInfo);
111451
+ const oauthTokenData = buildOAuthTokenData(tokenData, { ...clientInfo, issuer: metadata.issuer });
111253
111452
  this.saveTokens(oauthTokenData);
111254
111453
  return oauthTokenData;
111255
111454
  }
111256
111455
  async refresh(refreshToken) {
111257
- const metadata = await discoverOAuthServerMetadata(this.serverUrl);
111456
+ const metadata = await discoverOAuthServerMetadata(this.serverUrl, true);
111457
+ if (this.bindIssuer(metadata.issuer))
111458
+ return this.login();
111258
111459
  const clientInfo = this.clientInformation();
111259
111460
  const clientId = clientInfo?.clientId ?? this.configClientId;
111260
111461
  if (!clientId) {
@@ -111274,6 +111475,7 @@ class McpOAuthProvider {
111274
111475
  const tokenData = await parseTokenResponse(tokenResponse);
111275
111476
  const oauthTokenData = buildOAuthTokenData(tokenData, {
111276
111477
  clientId,
111478
+ issuer: metadata.issuer,
111277
111479
  ...clientInfo?.clientSecret ? { clientSecret: clientInfo.clientSecret } : {}
111278
111480
  }, refreshToken);
111279
111481
  this.saveTokens(oauthTokenData);
@@ -112121,6 +112323,17 @@ import { hostname } from "node:os";
112121
112323
  // packages/omo-opencode/src/cli/service-auth/protocol.ts
112122
112324
  init_zod();
112123
112325
 
112326
+ // packages/omo-opencode/src/cli/service-auth/credential-owner.ts
112327
+ init_zod();
112328
+ var identity = string2().regex(/^[A-Za-z0-9_-]{1,128}$/);
112329
+ var credentialOwnerSchema = object({
112330
+ accountId: identity,
112331
+ deviceId: identity,
112332
+ familyId: identity,
112333
+ generation: number2().int().positive().safe(),
112334
+ ownerHandle: string2().regex(/^[\x21-\x7e]{1,4096}$/)
112335
+ });
112336
+
112124
112337
  // packages/omo-opencode/src/cli/service-auth/terminal-text.ts
112125
112338
  import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
112126
112339
  function terminalText(value) {
@@ -112139,9 +112352,19 @@ class SignInError extends Error {
112139
112352
 
112140
112353
  class RequestFailure extends SignInError {
112141
112354
  notSent;
112142
- constructor(notSent) {
112355
+ responseStatus;
112356
+ constructor(notSent, responseStatus) {
112143
112357
  super("Unable to complete the service request. Check the connection and retry.", true);
112144
112358
  this.notSent = notSent;
112359
+ this.responseStatus = responseStatus;
112360
+ }
112361
+ }
112362
+
112363
+ class InvalidApiResponse extends SignInError {
112364
+ status;
112365
+ constructor(status) {
112366
+ super("The service returned an invalid error response.");
112367
+ this.status = status;
112145
112368
  }
112146
112369
  }
112147
112370
  var platformSchema = _enum(["macos", "linux", "windows"]);
@@ -112154,12 +112377,18 @@ var tokenSchema = object({
112154
112377
  });
112155
112378
  var grantSchema = tokenSchema.extend({
112156
112379
  device: object({ id: nonempty, name: nonempty }),
112157
- offlineGrant: nonempty.optional()
112380
+ offlineGrant: nonempty.optional(),
112381
+ owner: credentialOwnerSchema.optional(),
112382
+ writerFloor: union([literal(1), literal(2)]).optional(),
112383
+ freshAuthorizationProof: nonempty.optional()
112158
112384
  });
112159
112385
  var credentialSchema = grantSchema.extend({
112160
112386
  signingPrivateKey: nonempty,
112161
112387
  sealingPrivateKey: nonempty,
112162
- refreshState: literal("uncertain").optional()
112388
+ refreshState: literal("uncertain").optional(),
112389
+ credentialGeneration: nonempty.optional(),
112390
+ accountId: nonempty.optional(),
112391
+ refreshAttempt: unknown().optional()
112163
112392
  });
112164
112393
  var deviceCodeSchema = object({
112165
112394
  deviceCode: string2().regex(/^dc\.[A-Za-z0-9_-]{43}$/),
@@ -112187,6 +112416,9 @@ var limitSchema = object({
112187
112416
  var deviceListSchema = object({
112188
112417
  devices: array(object({ id: nonempty, name: nonempty, revokedAt: timestamp.nullable() }))
112189
112418
  });
112419
+ var currentDeviceListSchema = object({
112420
+ devices: array(object({ id: nonempty, current: boolean2(), revokedAt: timestamp.nullable() }))
112421
+ });
112190
112422
  var REFUSAL_CODES = [
112191
112423
  "unauthorized",
112192
112424
  "account_deleted",
@@ -112203,7 +112435,11 @@ var REFUSAL_CODES = [
112203
112435
  "unavailable",
112204
112436
  "forbidden",
112205
112437
  "invalid_request",
112206
- "not_found"
112438
+ "not_found",
112439
+ "client_upgrade_required",
112440
+ "writer_floor_mismatch",
112441
+ "service_upgrade_required",
112442
+ "refresh_recovery_expired"
112207
112443
  ];
112208
112444
  var isKnownRefusal = (code) => REFUSAL_CODES.includes(code);
112209
112445
  function refusalGuidance(code, status) {
@@ -112230,6 +112466,10 @@ function refusalGuidance(code, status) {
112230
112466
  case "access_denied":
112231
112467
  case "authorization_pending":
112232
112468
  return "account_refused";
112469
+ case "client_upgrade_required":
112470
+ case "writer_floor_mismatch":
112471
+ case "service_upgrade_required":
112472
+ case "refresh_recovery_expired":
112233
112473
  case "unknown":
112234
112474
  if (status === 401)
112235
112475
  return "sign_in_again";
@@ -112340,13 +112580,13 @@ async function requestApi(api, path, init, signal) {
112340
112580
  try {
112341
112581
  body = await response.json();
112342
112582
  } catch {
112343
- throw new RequestFailure(false);
112583
+ throw new RequestFailure(false, response.status);
112344
112584
  }
112345
112585
  if (response.ok)
112346
112586
  return body;
112347
112587
  const envelope = envelopeSchema.safeParse(body);
112348
112588
  if (!envelope.success)
112349
- throw new SignInError("The service returned an invalid error response.");
112589
+ throw new InvalidApiResponse(response.status);
112350
112590
  const error = envelope.data.error;
112351
112591
  const detail = limitSchema.safeParse(error.detail);
112352
112592
  throw new ApiRefusal(error.code, response.status, error.code === "entitlement_required" && detail.success ? detail.data : undefined, response.headers.get("retry-after"));
@@ -112450,7 +112690,7 @@ async function loginDevice(session, options) {
112450
112690
  }
112451
112691
 
112452
112692
  // packages/omo-opencode/src/cli/service-auth/keystore.ts
112453
- import { createHash as createHash10 } from "node:crypto";
112693
+ import { createHash as createHash12, randomUUID as randomUUID7 } from "node:crypto";
112454
112694
  import { basename as basename15 } from "node:path";
112455
112695
 
112456
112696
  // packages/omo-opencode/src/cli/service-auth/secret-service-lock.ts
@@ -112494,289 +112734,490 @@ var probeSecretServiceLock = () => new Promise((resolve) => {
112494
112734
  });
112495
112735
  });
112496
112736
 
112497
- // packages/omo-opencode/src/cli/service-auth/keystore.ts
112498
- class CredentialStoreError extends SignInError {
112499
- }
112737
+ // packages/omo-opencode/src/cli/service-auth/credential-lock.ts
112738
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
112739
+ import { createHash as createHash11 } from "node:crypto";
112740
+ import { mkdir as mkdir11 } from "node:fs/promises";
112741
+ import { homedir as homedir31 } from "node:os";
112742
+ import { join as join106 } from "node:path";
112500
112743
 
112501
- class KeychainLockedError extends CredentialStoreError {
112744
+ // packages/team-core/src/team-state-store/lock-publish.ts
112745
+ import { access as access4, open as open3, unlink as unlink3 } from "node:fs/promises";
112746
+ import { dirname as dirname42 } from "node:path";
112747
+
112748
+ // packages/team-core/src/team-state-store/lock-record.ts
112749
+ import { randomUUID as randomUUID6 } from "node:crypto";
112750
+ import { readFile as readFile34, stat as stat9 } from "node:fs/promises";
112751
+
112752
+ // packages/memory-core/src/locks/process-identity.ts
112753
+ import { execFile as execFile7 } from "node:child_process";
112754
+
112755
+ // packages/memory-core/src/fs/resilient.ts
112756
+ import * as fsSync from "node:fs";
112757
+ import * as fsp from "node:fs/promises";
112758
+
112759
+ // packages/memory-core/src/fs/retry.ts
112760
+ var EINTR_RETRY_CAP = 128;
112761
+ function fsErrorCode(error) {
112762
+ if (!(error instanceof Error) || !("code" in error))
112763
+ return;
112764
+ return typeof error.code === "string" ? error.code : undefined;
112502
112765
  }
112503
- class InvalidCredentialState extends SignInError {
112766
+ async function retryOnEintr(operation) {
112767
+ for (let attempt = 0;; attempt += 1) {
112768
+ try {
112769
+ return await operation();
112770
+ } catch (error) {
112771
+ if (fsErrorCode(error) !== "EINTR" || attempt >= EINTR_RETRY_CAP)
112772
+ throw error;
112773
+ }
112774
+ }
112775
+ }
112776
+ function retryOnEintrSync(operation) {
112777
+ for (let attempt = 0;; attempt += 1) {
112778
+ try {
112779
+ return operation();
112780
+ } catch (error) {
112781
+ if (fsErrorCode(error) !== "EINTR" || attempt >= EINTR_RETRY_CAP)
112782
+ throw error;
112783
+ }
112784
+ }
112504
112785
  }
112505
112786
 
112506
- class KeychainApprovalPendingError extends CredentialStoreError {
112787
+ // packages/memory-core/src/fs/rename-contention.ts
112788
+ var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
112789
+
112790
+ // packages/memory-core/src/fs/resilient.ts
112791
+ function isFunction2(value) {
112792
+ return typeof value === "function";
112507
112793
  }
112508
- var SESSION_READ_WAIT = { kind: "bounded", deadlineMs: 5000 };
112509
- var INTERACTIVE_READ_WAIT = {
112510
- kind: "interactive",
112511
- noticeAfterMs: 2000,
112512
- notice: (message) => process.stderr.write(`${message}
112513
- `)
112514
- };
112515
- var processReads = new WeakMap;
112516
- var LOCKED = /-25308|errSecInteractionNotAllowed|interaction is not allowed|locked collection/i;
112517
- var UNLOCKED_REUSE_MS = 30000;
112518
- var fallbackNoticed = false;
112519
- var stderrNoticeOncePerProcess = (message) => {
112520
- if (fallbackNoticed)
112794
+ function withAsyncRetry(operation) {
112795
+ return (...args) => retryOnEintr(async () => operation(...args));
112796
+ }
112797
+ function withSyncRetry(operation) {
112798
+ return (...args) => retryOnEintrSync(() => operation(...args));
112799
+ }
112800
+ function resilientNamespace(namespace, kind) {
112801
+ const wrapFunction = kind === "async" ? withAsyncRetry : withSyncRetry;
112802
+ const cache = new Map;
112803
+ return new Proxy(namespace, {
112804
+ get(target, property) {
112805
+ if (cache.has(property))
112806
+ return cache.get(property);
112807
+ const value = Reflect.get(target, property);
112808
+ if (!isFunction2(value))
112809
+ return value;
112810
+ const wrapped = wrapFunction(value);
112811
+ const native = Reflect.get(value, "native");
112812
+ if (isFunction2(native))
112813
+ Object.assign(wrapped, { native: wrapFunction(native) });
112814
+ cache.set(property, wrapped);
112815
+ return wrapped;
112816
+ }
112817
+ });
112818
+ }
112819
+ var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
112820
+ var promises = resilientNamespace(fsp, "async");
112821
+ var sync = resilientNamespace(fsSync, "sync");
112822
+ var {
112823
+ access: access3,
112824
+ chmod: chmod2,
112825
+ copyFile: copyFile4,
112826
+ cp: cp5,
112827
+ link,
112828
+ lstat: lstat18,
112829
+ mkdir: mkdir10,
112830
+ mkdtemp: mkdtemp2,
112831
+ readFile: readFile33,
112832
+ readdir: readdir17,
112833
+ readlink: readlink7,
112834
+ realpath: realpath2,
112835
+ rm: rm16,
112836
+ rmdir: rmdir2,
112837
+ stat: stat8,
112838
+ statfs,
112839
+ unlink: unlink2
112840
+ } = promises;
112841
+ var {
112842
+ accessSync: accessSync5,
112843
+ chmodSync: chmodSync7,
112844
+ fsyncSync: fsyncSync3,
112845
+ linkSync,
112846
+ lstatSync: lstatSync5,
112847
+ mkdirSync: mkdirSync19,
112848
+ readFileSync: readFileSync44,
112849
+ readdirSync: readdirSync14,
112850
+ realpathSync: realpathSync13,
112851
+ statSync: statSync8,
112852
+ unlinkSync: unlinkSync10,
112853
+ writeFileSync: writeFileSync17,
112854
+ writeSync
112855
+ } = sync;
112856
+
112857
+ // packages/memory-core/src/locks/process-start-time.ts
112858
+ var PROC_PIDTBSDINFO = 3;
112859
+ var PROC_BSDINFO_SIZE = 136;
112860
+ var START_TVSEC_OFFSET = 120;
112861
+ var procPidInfoLookup = null;
112862
+ async function openProcPidInfo() {
112863
+ if (process.platform !== "darwin")
112864
+ return null;
112865
+ try {
112866
+ const { dlopen, FFIType } = await import("bun:ffi");
112867
+ const library = dlopen("/usr/lib/libSystem.B.dylib", {
112868
+ proc_pidinfo: {
112869
+ args: [FFIType.i32, FFIType.i32, FFIType.u64, FFIType.ptr, FFIType.i32],
112870
+ returns: FFIType.i32
112871
+ }
112872
+ });
112873
+ return (pid, flavor, arg, buffer, size) => Number(library.symbols.proc_pidinfo(pid, flavor, arg, buffer, size));
112874
+ } catch {
112875
+ return null;
112876
+ }
112877
+ }
112878
+ function loadProcPidInfo() {
112879
+ procPidInfoLookup ??= openProcPidInfo();
112880
+ return procPidInfoLookup;
112881
+ }
112882
+ async function readDarwinProcessStartSeconds(pid) {
112883
+ if (process.platform !== "darwin")
112884
+ return null;
112885
+ if (!Number.isSafeInteger(pid) || pid <= 0)
112886
+ return null;
112887
+ const procPidInfo = await loadProcPidInfo();
112888
+ if (procPidInfo === null)
112889
+ return null;
112890
+ const buffer = new Uint8Array(PROC_BSDINFO_SIZE);
112891
+ let written = 0;
112892
+ try {
112893
+ written = procPidInfo(pid, PROC_PIDTBSDINFO, 0n, buffer, PROC_BSDINFO_SIZE);
112894
+ } catch {
112895
+ return null;
112896
+ }
112897
+ if (written !== PROC_BSDINFO_SIZE)
112898
+ return null;
112899
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
112900
+ const startSeconds = Number(view.getBigUint64(START_TVSEC_OFFSET, true));
112901
+ return startSeconds > 0 ? startSeconds : null;
112902
+ }
112903
+ var PROCESS_QUERY_LIMITED_INFORMATION = 4096;
112904
+ var kernel32Lookup = null;
112905
+ async function openKernel32() {
112906
+ if (process.platform !== "win32")
112907
+ return null;
112908
+ try {
112909
+ const { dlopen, FFIType } = await import("bun:ffi");
112910
+ const library = dlopen("kernel32.dll", {
112911
+ OpenProcess: { args: [FFIType.u32, FFIType.i32, FFIType.u32], returns: FFIType.ptr },
112912
+ GetProcessTimes: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
112913
+ CloseHandle: { args: [FFIType.ptr], returns: FFIType.i32 }
112914
+ });
112915
+ return library.symbols;
112916
+ } catch {
112917
+ return null;
112918
+ }
112919
+ }
112920
+ async function readWin32ProcessCreationFiletime(pid) {
112921
+ if (process.platform !== "win32")
112922
+ return null;
112923
+ if (!Number.isSafeInteger(pid) || pid <= 0)
112924
+ return null;
112925
+ kernel32Lookup ??= openKernel32();
112926
+ const kernel32 = await kernel32Lookup;
112927
+ if (kernel32 === null)
112928
+ return null;
112929
+ const handle = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
112930
+ if (handle === null || handle === 0 || handle === 0n)
112931
+ return null;
112932
+ try {
112933
+ const creation = new BigUint64Array(1);
112934
+ const ok = kernel32.GetProcessTimes(handle, creation, new BigUint64Array(1), new BigUint64Array(1), new BigUint64Array(1));
112935
+ const filetime = creation[0] ?? 0n;
112936
+ return ok === 0 || filetime === 0n ? null : filetime;
112937
+ } finally {
112938
+ kernel32.CloseHandle(handle);
112939
+ }
112940
+ }
112941
+
112942
+ // packages/memory-core/src/locks/process-identity.ts
112943
+ function errorCode(error) {
112944
+ if (!(error instanceof Error) || !("code" in error))
112521
112945
  return;
112522
- fallbackNoticed = true;
112523
- process.stderr.write(`${message}
112524
- `);
112525
- };
112526
- var isLocked = (error) => error instanceof Error && (LOCKED.test(error.message) || LOCKED.test(String(error.code ?? "")));
112527
- function credentialId(api) {
112528
- return createHash10("sha256").update(serviceOrigin(api)).digest("hex");
112946
+ return typeof error.code === "string" ? error.code : undefined;
112529
112947
  }
112530
- function createCredentialStore(api, options = {}) {
112531
- return createSealedStore(api, "omo-cli", credentialSchema, options.secrets, options.platform, options.lockProbe, options.notice, options.wait);
112948
+ async function execFileText(command, args) {
112949
+ return await new Promise((resolve) => {
112950
+ execFile7(command, args, { encoding: "utf8", timeout: 2000, windowsHide: true }, (error, stdout) => {
112951
+ if (error !== null) {
112952
+ resolve(null);
112953
+ return;
112954
+ }
112955
+ const value = stdout.trim();
112956
+ resolve(value.length > 0 ? value : null);
112957
+ });
112958
+ });
112532
112959
  }
112533
- function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT) {
112534
- if (!secrets)
112535
- throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
112536
- const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
112537
- if (platformName === null)
112538
- throw new SignInError("This platform has no supported OS credential store.");
112539
- const key = { service: namespace, name: credentialId(api) };
112540
- const slot = `${key.service}
112541
- ${key.name}`;
112542
- const readsOf = (api) => {
112543
- const known = processReads.get(api);
112544
- if (known !== undefined)
112545
- return known;
112546
- const created = new Map;
112547
- processReads.set(api, created);
112548
- return created;
112549
- };
112550
- const forget = (api) => {
112551
- readsOf(api).delete(slot);
112552
- };
112553
- const sharedRead = (api) => {
112554
- const reads = readsOf(api);
112555
- const pending = reads.get(slot);
112556
- if (pending !== undefined)
112557
- return pending;
112558
- const read = Promise.resolve().then(() => api.get(key));
112559
- const done = () => {
112560
- if (reads.get(slot) === read)
112561
- reads.delete(slot);
112562
- };
112563
- read.then(done, done);
112564
- reads.set(slot, read);
112565
- return read;
112960
+ async function readLinuxStartIdentity(pid) {
112961
+ try {
112962
+ const stat = await readFile33(`/proc/${pid}/stat`, "utf8");
112963
+ const commandEnd = stat.lastIndexOf(")");
112964
+ if (commandEnd < 0)
112965
+ return null;
112966
+ const fieldsAfterCommand = stat.slice(commandEnd + 2).trim().split(/\s+/);
112967
+ const startTicks = fieldsAfterCommand[19];
112968
+ return startTicks === undefined ? null : `linux-proc-start-ticks:${startTicks}`;
112969
+ } catch {
112970
+ return null;
112971
+ }
112972
+ }
112973
+ async function readWin32StartIdentity(pid) {
112974
+ if (getPidLiveness(pid) === "dead")
112975
+ return null;
112976
+ const creationFiletime = await readWin32ProcessCreationFiletime(pid);
112977
+ if (creationFiletime !== null)
112978
+ return `win32-creation-filetime:${creationFiletime}`;
112979
+ const value = await execFileText("powershell.exe", [
112980
+ "-NoProfile",
112981
+ "-Command",
112982
+ `(Get-Process -Id ${pid} -ErrorAction SilentlyContinue).StartTime.ToUniversalTime().ToString('o')`
112983
+ ]);
112984
+ return value === null ? null : `win32-creation-date:${value}`;
112985
+ }
112986
+ function createProcessStartIdentityReader(read, ownPid) {
112987
+ let ownIdentity;
112988
+ return (pid) => {
112989
+ if (pid !== ownPid)
112990
+ return read(pid);
112991
+ ownIdentity ??= read(pid).then((identity) => {
112992
+ if (identity === null)
112993
+ ownIdentity = undefined;
112994
+ return identity;
112995
+ }, (error) => {
112996
+ ownIdentity = undefined;
112997
+ throw error;
112998
+ });
112999
+ return ownIdentity;
112566
113000
  };
112567
- 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`;
112568
- const answered = async (api) => {
112569
- const read = sharedRead(api);
112570
- let timer;
112571
- try {
112572
- if (wait.kind === "interactive") {
112573
- timer = setTimeout(() => wait.notice(`omo: ${waiting}.`), wait.noticeAfterMs);
112574
- return await read;
112575
- }
112576
- const expired = new Promise((_, reject) => {
112577
- timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waiting}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
112578
- });
112579
- return await Promise.race([read, expired]);
112580
- } finally {
112581
- clearTimeout(timer);
112582
- }
113001
+ }
113002
+ var getProcessStartIdentity = createProcessStartIdentityReader(readProcessStartIdentity, process.pid);
113003
+ async function readProcessStartIdentity(pid) {
113004
+ if (process.platform === "linux")
113005
+ return await readLinuxStartIdentity(pid);
113006
+ if (process.platform === "darwin" || process.platform === "freebsd") {
113007
+ if (getPidLiveness(pid) === "dead")
113008
+ return null;
113009
+ const startSeconds = await readDarwinProcessStartSeconds(pid);
113010
+ if (startSeconds !== null)
113011
+ return `proc-start-epoch:${startSeconds}`;
113012
+ const value = await execFileText("/bin/ps", ["-o", "lstart=", "-p", String(pid)]);
113013
+ return value === null ? null : `ps-lstart:${value.replace(/\s+/g, " ")}`;
113014
+ }
113015
+ if (process.platform === "win32")
113016
+ return await readWin32StartIdentity(pid);
113017
+ return null;
113018
+ }
113019
+ function identityScheme(identity) {
113020
+ const separator = identity.indexOf(":");
113021
+ return separator <= 0 ? null : identity.slice(0, separator);
113022
+ }
113023
+ function startIdentitiesConflict(recorded, actual) {
113024
+ const recordedScheme = identityScheme(recorded);
113025
+ if (recordedScheme === null || recordedScheme !== identityScheme(actual))
113026
+ return false;
113027
+ return recorded !== actual;
113028
+ }
113029
+ function getPidLiveness(pid) {
113030
+ try {
113031
+ process.kill(pid, 0);
113032
+ return "alive";
113033
+ } catch (error) {
113034
+ const code = errorCode(error);
113035
+ if (code === "ESRCH")
113036
+ return "dead";
113037
+ if (code === "EPERM")
113038
+ return "alive";
113039
+ return "unknown";
113040
+ }
113041
+ }
113042
+
113043
+ // packages/team-core/src/team-state-store/lock-worker-lifetime.ts
113044
+ init_zod();
113045
+ import { randomUUID as randomUUID5 } from "node:crypto";
113046
+ import { BroadcastChannel, parentPort, threadId } from "node:worker_threads";
113047
+ var Registration = object({
113048
+ kind: literal("omo-team-lock-register-v1"),
113049
+ incarnation: string2(),
113050
+ challenge: string2()
113051
+ });
113052
+ var Message = discriminatedUnion("kind", [
113053
+ object({ kind: literal("query"), id: string2(), incarnation: string2(), record: string2() }),
113054
+ object({ kind: literal("answer"), id: string2(), released: boolean2() }),
113055
+ object({ kind: literal("hello"), threadId: number2() }),
113056
+ object({ kind: literal("register"), threadId: number2(), challenge: string2() })
113057
+ ]);
113058
+ function createState() {
113059
+ const channel = new BroadcastChannel(`omo-team-lock-lifetime-v1-${process.pid}`);
113060
+ channel.unref();
113061
+ const state = {
113062
+ incarnation: randomUUID5(),
113063
+ records: new Map,
113064
+ exited: new Set,
113065
+ observed: new WeakSet,
113066
+ observing: new Map,
113067
+ pending: new Map,
113068
+ channel,
113069
+ installed: false,
113070
+ registered: parentPort === null,
113071
+ registration: undefined,
113072
+ onRegistered: undefined
112583
113073
  };
112584
- 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.`);
112585
- let unlockedUntil = 0;
112586
- let noticed = false;
112587
- const assertUsable = async () => {
112588
- if (platform !== "linux" || Date.now() < unlockedUntil)
112589
- return;
112590
- const lock = await lockProbe();
112591
- if (lock === "locked")
112592
- throw new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`);
112593
- if (lock === "unlocked") {
112594
- unlockedUntil = Date.now() + UNLOCKED_REUSE_MS;
113074
+ channel.onmessage = (event) => {
113075
+ const parsed = Message.safeParse(event.data);
113076
+ if (!parsed.success)
112595
113077
  return;
112596
- }
112597
- if (!noticed) {
112598
- noticed = true;
112599
- notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
112600
- }
112601
- };
112602
- return {
112603
- async read() {
112604
- await assertUsable();
112605
- let value;
112606
- try {
112607
- value = await answered(secrets);
112608
- } catch (error) {
112609
- if (error instanceof KeychainApprovalPendingError)
112610
- throw error;
112611
- throw unavailable(error);
112612
- }
112613
- if (value === null)
112614
- return null;
112615
- try {
112616
- return schema.parse(JSON.parse(value));
112617
- } catch {
112618
- 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.");
113078
+ const message = parsed.data;
113079
+ switch (message.kind) {
113080
+ case "hello": {
113081
+ const observed = state.observing.get(message.threadId);
113082
+ if (observed !== undefined) {
113083
+ channel.postMessage({ kind: "register", threadId: message.threadId, challenge: observed.challenge });
113084
+ }
113085
+ return;
112619
113086
  }
112620
- },
112621
- async write(value) {
112622
- await assertUsable();
112623
- try {
112624
- await secrets.set({ ...key, value: JSON.stringify(schema.parse(value)) });
112625
- } catch (error) {
112626
- throw unavailable(error);
113087
+ case "register":
113088
+ if (message.threadId === threadId) {
113089
+ parentPort?.postMessage({
113090
+ kind: "omo-team-lock-register-v1",
113091
+ incarnation: state.incarnation,
113092
+ challenge: message.challenge
113093
+ });
113094
+ state.registered = true;
113095
+ state.onRegistered?.();
113096
+ }
113097
+ return;
113098
+ case "answer":
113099
+ state.pending.get(message.id)?.(message.released);
113100
+ return;
113101
+ case "query": {
113102
+ const status = message.incarnation === state.incarnation ? state.records.get(message.record) : undefined;
113103
+ if (status !== undefined || state.exited.has(message.incarnation)) {
113104
+ channel.postMessage({
113105
+ kind: "answer",
113106
+ id: message.id,
113107
+ released: status === "released" || state.exited.has(message.incarnation)
113108
+ });
113109
+ }
113110
+ return;
112627
113111
  }
112628
- forget(secrets);
112629
- },
112630
- async clear() {
112631
- await assertUsable();
112632
- try {
112633
- await secrets.delete(key);
112634
- } catch (error) {
112635
- throw unavailable(error);
113112
+ default: {
113113
+ const unexpected = message;
113114
+ throw new Error(`Unexpected lock lifetime message: ${unexpected}`);
112636
113115
  }
112637
- forget(secrets);
112638
113116
  }
112639
113117
  };
113118
+ return state;
112640
113119
  }
112641
-
112642
- // packages/omo-opencode/src/cli/service-auth/loopback.ts
112643
- import { createHash as createHash11, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
112644
- import { createServer as createServer3 } from "node:http";
112645
- class BrowserUnavailable extends SignInError {
112646
- }
112647
- async function authorize(options) {
112648
- const verifier = randomBytes5(32).toString("base64url");
112649
- const state = randomBytes5(32).toString("base64url");
112650
- const answer = Promise.withResolvers();
112651
- const abort = () => answer.reject(new SignInError("Browser sign-in cancelled or timed out."));
112652
- let accepted = false;
112653
- let origin = "";
112654
- const server = createServer3((request, response) => {
112655
- response.setHeader("cache-control", "no-store");
112656
- response.setHeader("referrer-policy", "no-referrer");
112657
- response.setHeader("content-type", "text/plain; charset=utf-8");
112658
- const url = new URL(request.url ?? "/", origin);
112659
- 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"]) {
112660
- response.writeHead(404).end("Not found");
112661
- return;
112662
- }
112663
- const code = url.searchParams.get("code");
112664
- const suppliedState = Buffer.from(url.searchParams.get("state") ?? "");
112665
- const expectedState = Buffer.from(state);
112666
- if (accepted || url.searchParams.getAll("state").length !== 1 || suppliedState.length !== expectedState.length || !timingSafeEqual(suppliedState, expectedState) || url.searchParams.getAll("code").length !== 1 || !code) {
112667
- response.writeHead(400).end("Invalid sign-in response");
113120
+ var state2 = globalThis.__omoTeamLockLifetimeV1 ??= createState();
113121
+ var lockOwnerInstanceId = state2.incarnation;
113122
+ function attachWorker(worker) {
113123
+ if (state2.observed.has(worker))
113124
+ return;
113125
+ state2.observed.add(worker);
113126
+ const id = worker.threadId;
113127
+ const challenge = randomUUID5();
113128
+ state2.observing.set(id, { worker, challenge });
113129
+ const incarnations = new Set;
113130
+ let exited = false;
113131
+ worker.on("message", (message) => {
113132
+ const parsed = Registration.safeParse(message);
113133
+ if (!parsed.success || parsed.data.challenge !== challenge)
112668
113134
  return;
112669
- }
112670
- accepted = true;
112671
- response.writeHead(200).end("Return to the terminal to finish signing in.");
112672
- answer.resolve(code);
113135
+ incarnations.add(parsed.data.incarnation);
113136
+ if (exited)
113137
+ state2.exited.add(parsed.data.incarnation);
112673
113138
  });
112674
- try {
112675
- await new Promise((resolve, reject) => {
112676
- server.once("error", reject);
112677
- server.listen(0, "127.0.0.1", () => {
112678
- server.off("error", reject);
112679
- resolve();
112680
- });
112681
- });
112682
- const address = server.address();
112683
- if (!address || typeof address === "string")
112684
- throw new SignInError("Unable to start the sign-in callback.");
112685
- origin = `http://127.0.0.1:${address.port}`;
112686
- const url = new URL(serviceOrigin(options.accounts));
112687
- url.search = new URLSearchParams({
112688
- redirect_uri: `${origin}/callback`,
112689
- code_challenge: createHash11("sha256").update(verifier).digest("base64url"),
112690
- code_challenge_method: "S256",
112691
- state
112692
- }).toString();
112693
- const timer = setTimeout(abort, 5 * 60000);
112694
- options.signal?.addEventListener("abort", abort, { once: true });
112695
- try {
112696
- options.signal?.throwIfAborted();
112697
- const openerFailed = () => {
112698
- if (!accepted)
112699
- throw new BrowserUnavailable("No browser is available; use device sign-in.");
112700
- };
112701
- const [code] = await Promise.all([
112702
- answer.promise,
112703
- options.open(url.href).then((opened) => {
112704
- if (!opened)
112705
- openerFailed();
112706
- }, openerFailed)
112707
- ]);
112708
- return { code, codeVerifier: verifier };
112709
- } finally {
113139
+ worker.once("exit", () => {
113140
+ exited = true;
113141
+ if (state2.observing.get(id)?.worker === worker)
113142
+ state2.observing.delete(id);
113143
+ for (const incarnation of incarnations)
113144
+ state2.exited.add(incarnation);
113145
+ });
113146
+ }
113147
+ function installLockWorkerObserver() {
113148
+ if (state2.installed)
113149
+ return;
113150
+ state2.installed = true;
113151
+ process.on("worker", attachWorker);
113152
+ state2.channel.postMessage({ kind: "hello", threadId });
113153
+ }
113154
+ installLockWorkerObserver();
113155
+ async function registerLockWorker() {
113156
+ if (state2.registered)
113157
+ return;
113158
+ state2.registration ??= new Promise((resolve) => {
113159
+ const finish = () => {
112710
113160
  clearTimeout(timer);
112711
- options.signal?.removeEventListener("abort", abort);
112712
- }
112713
- } finally {
112714
- server.closeAllConnections();
112715
- await new Promise((resolve) => server.close(() => resolve()));
112716
- }
113161
+ state2.onRegistered = undefined;
113162
+ resolve();
113163
+ };
113164
+ const timer = setTimeout(finish, 250);
113165
+ state2.onRegistered = finish;
113166
+ state2.channel.postMessage({ kind: "hello", threadId });
113167
+ });
113168
+ await state2.registration;
112717
113169
  }
112718
- async function loginLoopback(session, options) {
112719
- await session.ready();
112720
- const keys = generateDeviceKeys();
112721
- for (;; ) {
112722
- const authorization = await authorize({ accounts: options.accounts, open: options.open, signal: session.signal });
112723
- try {
112724
- const grant = parseReply(grantSchema, await session.request("/v1/session/exchange", jsonRequest({
112725
- ...authorization,
112726
- kind: "cli",
112727
- deviceName: options.name,
112728
- platform: options.platform,
112729
- ...keys.public
112730
- })));
112731
- await session.save({ ...grant, ...keys.private });
112732
- return;
112733
- } catch (error) {
112734
- if (await session.removeForLimit(error, options.chooseDevice))
112735
- continue;
112736
- throw new SignInError("Sign-in cancelled. No device was removed.");
112737
- }
112738
- }
113170
+ function markLockRecordHeld(record) {
113171
+ state2.records.set(record, "held");
113172
+ }
113173
+ function markLockRecordReleased(record) {
113174
+ if (state2.records.has(record))
113175
+ state2.records.set(record, "released");
113176
+ }
113177
+ function forgetLockRecord(record) {
113178
+ state2.records.delete(record);
113179
+ }
113180
+ async function isWorkerLockReleased(incarnation, record) {
113181
+ if (state2.exited.has(incarnation))
113182
+ return true;
113183
+ if (incarnation === state2.incarnation)
113184
+ return state2.records.get(record) === "released";
113185
+ const id = randomUUID5();
113186
+ return await new Promise((resolve) => {
113187
+ const finish = (released) => {
113188
+ clearTimeout(timer);
113189
+ state2.pending.delete(id);
113190
+ resolve(released);
113191
+ };
113192
+ const timer = setTimeout(() => finish(false), 250);
113193
+ state2.pending.set(id, finish);
113194
+ state2.channel.postMessage({ kind: "query", id, incarnation, record });
113195
+ });
112739
113196
  }
112740
-
112741
- // packages/omo-opencode/src/cli/service-auth/session.ts
112742
- import { mkdir as mkdir11 } from "node:fs/promises";
112743
- import { homedir as homedir31 } from "node:os";
112744
- import { join as join107 } from "node:path";
112745
-
112746
- // packages/team-core/src/team-state-store/lock-publish.ts
112747
- import { access as access3, open as open2, unlink as unlink2 } from "node:fs/promises";
112748
- import { dirname as dirname42 } from "node:path";
112749
113197
 
112750
113198
  // packages/team-core/src/team-state-store/lock-record.ts
112751
- import { randomUUID as randomUUID5 } from "node:crypto";
112752
- import { readFile as readFile33, stat as stat8 } from "node:fs/promises";
112753
- var lockOwnerInstanceId = randomUUID5();
112754
- var heldLockRecords = new Set;
112755
- function buildLockRecord(ownerTag) {
112756
- return `${ownerTag} ${randomUUID5()}
113199
+ async function buildLockRecord(ownerTag) {
113200
+ await registerLockWorker();
113201
+ const processStart = await getProcessStartIdentity(process.pid);
113202
+ return `${ownerTag} ${randomUUID6()}
112757
113203
  ${process.pid}
112758
113204
  ${Date.now()}
112759
113205
  ${lockOwnerInstanceId}
113206
+ ${processStart ?? "unavailable"}
112760
113207
  `;
112761
113208
  }
112762
- function markLockRecordHeld(content) {
112763
- heldLockRecords.add(content);
112764
- }
112765
- function markLockRecordReleased(content) {
112766
- heldLockRecords.delete(content);
112767
- }
112768
- function errorCode(error) {
113209
+ function errorCode2(error) {
112769
113210
  if (!(error instanceof Error) || !("code" in error))
112770
113211
  return null;
112771
113212
  return typeof error.code === "string" ? error.code : null;
112772
113213
  }
112773
113214
  function isPathAbsenceError(error) {
112774
- const code = errorCode(error);
113215
+ const code = errorCode2(error);
112775
113216
  return code === "ENOENT" || code === "ENOTDIR";
112776
113217
  }
112777
113218
  function parseLockOwner(content) {
112778
113219
  const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
112779
- if (lines.length !== 3 && lines.length !== 4)
113220
+ if (lines.length !== 3 && lines.length !== 4 && lines.length !== 5)
112780
113221
  return null;
112781
113222
  const ownerPid = Number.parseInt(lines[1] ?? "", 10);
112782
113223
  const acquiredAtEpochMs = Number.parseInt(lines[2] ?? "", 10);
@@ -112787,24 +113228,14 @@ function parseLockOwner(content) {
112787
113228
  return {
112788
113229
  ownerPid,
112789
113230
  acquiredAtEpochMs,
112790
- instanceId: lines.length === 4 ? lines[3] ?? null : null
113231
+ instanceId: lines[3] ?? null,
113232
+ processStart: lines[4] ?? null
112791
113233
  };
112792
113234
  }
112793
- function isPidAlive(pid) {
112794
- try {
112795
- process.kill(pid, 0);
112796
- return true;
112797
- } catch (error) {
112798
- if (!(error instanceof Error)) {
112799
- throw error;
112800
- }
112801
- return false;
112802
- }
112803
- }
112804
113235
  async function readLockRecord(lockPath) {
112805
113236
  try {
112806
- const content = await readFile33(lockPath, "utf8");
112807
- const { mtimeMs } = await stat8(lockPath);
113237
+ const content = await readFile34(lockPath, "utf8");
113238
+ const { mtimeMs } = await stat9(lockPath);
112808
113239
  return { content, modifiedAtEpochMs: mtimeMs };
112809
113240
  } catch (error) {
112810
113241
  if (!(error instanceof Error))
@@ -112812,23 +113243,30 @@ async function readLockRecord(lockPath) {
112812
113243
  return null;
112813
113244
  }
112814
113245
  }
112815
- function isLockRecordStale(record, staleAfterMs) {
113246
+ async function isLockRecordStale(record, staleAfterMs) {
112816
113247
  const owner = parseLockOwner(record.content);
112817
113248
  if (owner === null)
112818
113249
  return Date.now() - record.modifiedAtEpochMs > staleAfterMs;
112819
- if (owner.instanceId !== null && owner.ownerPid === process.pid) {
112820
- return owner.instanceId !== lockOwnerInstanceId || !heldLockRecords.has(record.content);
113250
+ const liveness = getPidLiveness(owner.ownerPid);
113251
+ if (liveness === "dead") {
113252
+ return owner.instanceId !== null || Date.now() - owner.acquiredAtEpochMs > staleAfterMs;
112821
113253
  }
112822
- if (isPidAlive(owner.ownerPid))
113254
+ if (liveness === "unknown")
112823
113255
  return false;
112824
- if (owner.instanceId !== null)
112825
- return true;
112826
- return Date.now() - owner.acquiredAtEpochMs > staleAfterMs;
113256
+ if (owner.processStart !== null) {
113257
+ const actual = await getProcessStartIdentity(owner.ownerPid);
113258
+ if (actual !== null && startIdentitiesConflict(owner.processStart, actual))
113259
+ return true;
113260
+ }
113261
+ if (owner.instanceId !== null && owner.ownerPid === process.pid) {
113262
+ return await isWorkerLockReleased(owner.instanceId, record.content);
113263
+ }
113264
+ return false;
112827
113265
  }
112828
113266
 
112829
113267
  // packages/team-core/src/team-state-store/lock-publish.ts
112830
113268
  async function pathMayExist(path, deps = {}) {
112831
- const accessPath = deps.access ?? access3;
113269
+ const accessPath = deps.access ?? access4;
112832
113270
  try {
112833
113271
  await accessPath(path);
112834
113272
  return true;
@@ -112839,7 +113277,7 @@ async function pathMayExist(path, deps = {}) {
112839
113277
  }
112840
113278
  }
112841
113279
  async function assertRetryableLockOpenError(lockPath, error, deps) {
112842
- const code = errorCode(error);
113280
+ const code = errorCode2(error);
112843
113281
  if (code === "EEXIST")
112844
113282
  return;
112845
113283
  if (code === "EPERM") {
@@ -112854,9 +113292,9 @@ async function publishLockRecord(lockPath, record) {
112854
113292
  markLockRecordHeld(record);
112855
113293
  let fileHandle;
112856
113294
  try {
112857
- fileHandle = await open2(lockPath, "wx");
113295
+ fileHandle = await open3(lockPath, "wx");
112858
113296
  } catch (error) {
112859
- markLockRecordReleased(record);
113297
+ forgetLockRecord(record);
112860
113298
  await assertRetryableLockOpenError(lockPath, error);
112861
113299
  return false;
112862
113300
  }
@@ -112865,7 +113303,7 @@ async function publishLockRecord(lockPath, record) {
112865
113303
  } catch (error) {
112866
113304
  markLockRecordReleased(record);
112867
113305
  await fileHandle.close();
112868
- await unlink2(lockPath).catch(() => {
113306
+ await unlink3(lockPath).catch(() => {
112869
113307
  return;
112870
113308
  });
112871
113309
  throw error;
@@ -112875,8 +113313,8 @@ async function publishLockRecord(lockPath, record) {
112875
113313
  }
112876
113314
 
112877
113315
  // packages/team-core/src/team-state-store/lock-reclaim.ts
112878
- import { createHash as createHash12 } from "node:crypto";
112879
- import { unlink as unlink3 } from "node:fs/promises";
113316
+ import { createHash as createHash10 } from "node:crypto";
113317
+ import { unlink as unlink4 } from "node:fs/promises";
112880
113318
  var RECLAIM_UNLINK_ATTEMPTS = 3;
112881
113319
  var RECLAIM_UNLINK_RETRY_MS = 25;
112882
113320
  function delay2(ms) {
@@ -112885,11 +113323,11 @@ function delay2(ms) {
112885
113323
  });
112886
113324
  }
112887
113325
  function reclaimGuardPath(lockPath, record) {
112888
- return `${lockPath}.reclaim-${createHash12("sha256").update(record).digest("hex").slice(0, 16)}`;
113326
+ return `${lockPath}.reclaim-${createHash10("sha256").update(record).digest("hex").slice(0, 16)}`;
112889
113327
  }
112890
113328
  async function unlinkWithRetry(path, deps) {
112891
113329
  const wait = deps.delay ?? delay2;
112892
- const unlinkFile = deps.unlink ?? unlink3;
113330
+ const unlinkFile = deps.unlink ?? unlink4;
112893
113331
  for (let attempt = 1;; attempt += 1) {
112894
113332
  try {
112895
113333
  await unlinkFile(path);
@@ -112899,7 +113337,7 @@ async function unlinkWithRetry(path, deps) {
112899
113337
  throw error;
112900
113338
  if (isPathAbsenceError(error))
112901
113339
  return "absent";
112902
- const code = errorCode(error);
113340
+ const code = errorCode2(error);
112903
113341
  if (code !== "EPERM" && code !== "EBUSY" || attempt === RECLAIM_UNLINK_ATTEMPTS)
112904
113342
  return "stuck";
112905
113343
  await wait(RECLAIM_UNLINK_RETRY_MS);
@@ -112908,10 +113346,10 @@ async function unlinkWithRetry(path, deps) {
112908
113346
  }
112909
113347
  async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterMs, deps = {}) {
112910
113348
  const guardPath = reclaimGuardPath(lockPath, expectedRecord);
112911
- const guardRecord = buildLockRecord("lock-reclaim");
113349
+ const guardRecord = await buildLockRecord("lock-reclaim");
112912
113350
  if (!await publishLockRecord(guardPath, guardRecord)) {
112913
113351
  const guard = await readLockRecord(guardPath);
112914
- if (guard !== null && isLockRecordStale(guard, staleAfterMs)) {
113352
+ if (guard !== null && await isLockRecordStale(guard, staleAfterMs)) {
112915
113353
  await removeLockRecordIfUnchanged(guardPath, guard.content, staleAfterMs, deps);
112916
113354
  }
112917
113355
  return "busy";
@@ -112920,13 +113358,16 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
112920
113358
  const current = await readLockRecord(lockPath);
112921
113359
  if (current === null)
112922
113360
  return "absent";
112923
- if (current.content !== expectedRecord || !isLockRecordStale(current, staleAfterMs))
113361
+ if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
112924
113362
  return "changed";
112925
113363
  const unlinked = await unlinkWithRetry(lockPath, deps);
113364
+ if (unlinked !== "stuck")
113365
+ forgetLockRecord(expectedRecord);
112926
113366
  return unlinked === "absent" ? "absent" : unlinked;
112927
113367
  } finally {
112928
113368
  markLockRecordReleased(guardRecord);
112929
- await unlinkWithRetry(guardPath, deps);
113369
+ if (await unlinkWithRetry(guardPath, deps) !== "stuck")
113370
+ forgetLockRecord(guardRecord);
112930
113371
  }
112931
113372
  }
112932
113373
 
@@ -112945,7 +113386,7 @@ async function acquireLock(lockPath, ownerTag, staleAfterMs) {
112945
113386
  if (Date.now() - startedAt > LOCK_WAIT_TIMEOUT_MS) {
112946
113387
  throw new Error(`Timed out acquiring lock: ${lockPath}`);
112947
113388
  }
112948
- const record = buildLockRecord(ownerTag);
113389
+ const record = await buildLockRecord(ownerTag);
112949
113390
  if (await publishLockRecord(lockPath, record))
112950
113391
  return record;
112951
113392
  const outcome = await reapStaleLock(lockPath, staleAfterMs);
@@ -112962,26 +113403,327 @@ async function withLock(lockPath, fn, opts) {
112962
113403
  return await fn();
112963
113404
  } finally {
112964
113405
  markLockRecordReleased(record);
112965
- await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
113406
+ const outcome = await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
113407
+ if (outcome === "removed" || outcome === "absent" || outcome === "changed")
113408
+ forgetLockRecord(record);
112966
113409
  }
112967
113410
  }
112968
113411
  async function reapStaleLock(lockPath, staleAfterMs = DEFAULT_STALE_AFTER_MS, deps = {}) {
112969
113412
  const observed = await readLockRecord(lockPath);
112970
113413
  if (observed === null)
112971
113414
  return "absent";
112972
- if (!isLockRecordStale(observed, staleAfterMs))
113415
+ if (!await isLockRecordStale(observed, staleAfterMs))
112973
113416
  return "changed";
112974
113417
  return await removeLockRecordIfUnchanged(lockPath, observed.content, staleAfterMs, deps);
112975
113418
  }
112976
113419
 
113420
+ // packages/omo-opencode/src/cli/service-auth/credential-lock.ts
113421
+ var held = new AsyncLocalStorage3;
113422
+ function credentialLockPaths(api, home = homedir31()) {
113423
+ const id = createHash11("sha256").update(serviceOrigin(api)).digest("hex");
113424
+ const directory = join106(home, ".omo", "session-locks");
113425
+ return { directory, lock: join106(directory, `${id}.lock`), desktopRecord: join106(directory, `${id}.desktop-generation.json`) };
113426
+ }
113427
+ async function withCredentialLock(api, action, home = homedir31(), ownerTag = "cli-session") {
113428
+ const { directory, lock } = credentialLockPaths(api, home);
113429
+ const owned = held.getStore();
113430
+ if (owned?.has(lock))
113431
+ return action();
113432
+ await mkdir11(directory, { recursive: true, mode: 448 });
113433
+ return withLock(lock, () => held.run(new Set([...owned ?? [], lock]), action), {
113434
+ ownerTag,
113435
+ staleAfterMs: Number.POSITIVE_INFINITY
113436
+ });
113437
+ }
113438
+
113439
+ // packages/omo-opencode/src/cli/service-auth/keystore.ts
113440
+ class CredentialStoreError extends SignInError {
113441
+ }
113442
+
113443
+ class KeychainLockedError extends CredentialStoreError {
113444
+ }
113445
+ class InvalidCredentialState extends SignInError {
113446
+ }
113447
+
113448
+ class CredentialIdentityChanged extends Error {
113449
+ constructor() {
113450
+ super("The stored sign-in changed; the captured account is no longer current.");
113451
+ }
113452
+ }
113453
+
113454
+ class KeychainApprovalPendingError extends CredentialStoreError {
113455
+ }
113456
+ var SESSION_READ_WAIT = { kind: "bounded", deadlineMs: 5000 };
113457
+ var INTERACTIVE_READ_WAIT = {
113458
+ kind: "interactive",
113459
+ noticeAfterMs: 2000,
113460
+ notice: (message) => process.stderr.write(`${message}
113461
+ `)
113462
+ };
113463
+ var processReads = new WeakMap;
113464
+ var LOCKED = /-25308|errSecInteractionNotAllowed|interaction is not allowed|locked collection/i;
113465
+ var UNLOCKED_REUSE_MS = 30000;
113466
+ var fallbackNoticed = false;
113467
+ var stderrNoticeOncePerProcess = (message) => {
113468
+ if (fallbackNoticed)
113469
+ return;
113470
+ fallbackNoticed = true;
113471
+ process.stderr.write(`${message}
113472
+ `);
113473
+ };
113474
+ var isLocked = (error) => error instanceof Error && (LOCKED.test(error.message) || LOCKED.test(String(error.code ?? "")));
113475
+ function credentialId(api) {
113476
+ return createHash12("sha256").update(serviceOrigin(api)).digest("hex");
113477
+ }
113478
+ function createCredentialStore(api, options = {}) {
113479
+ const store = createSealedStore(api, "omo-cli", credentialSchema, options.secrets, options.platform, options.lockProbe, options.notice, options.wait, (current, value) => {
113480
+ 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);
113481
+ const accountId = value.accountId ?? (sameIdentity ? current?.accountId : undefined);
113482
+ return {
113483
+ ...value,
113484
+ ...accountId === undefined ? {} : { accountId },
113485
+ credentialGeneration: sameIdentity ? current?.credentialGeneration ?? randomUUID7() : randomUUID7()
113486
+ };
113487
+ });
113488
+ return {
113489
+ read: store.read,
113490
+ readAuthoritative: store.readAuthoritative,
113491
+ write: (value) => withCredentialLock(api, () => store.write(value), options.home),
113492
+ clear: () => withCredentialLock(api, store.clear, options.home)
113493
+ };
113494
+ }
113495
+ function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT, amendWrite) {
113496
+ if (!secrets)
113497
+ throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
113498
+ const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
113499
+ if (platformName === null)
113500
+ throw new SignInError("This platform has no supported OS credential store.");
113501
+ const key = { service: namespace, name: credentialId(api) };
113502
+ const slot = `${key.service}
113503
+ ${key.name}`;
113504
+ const readsOf = (api) => {
113505
+ const known = processReads.get(api);
113506
+ if (known !== undefined)
113507
+ return known;
113508
+ const created = new Map;
113509
+ processReads.set(api, created);
113510
+ return created;
113511
+ };
113512
+ const forget = (api) => {
113513
+ readsOf(api).delete(slot);
113514
+ };
113515
+ const sharedRead = (api) => {
113516
+ const reads = readsOf(api);
113517
+ const pending = reads.get(slot);
113518
+ if (pending !== undefined)
113519
+ return pending;
113520
+ const read = Promise.resolve().then(() => api.get(key));
113521
+ const done = () => {
113522
+ if (reads.get(slot) === read)
113523
+ reads.delete(slot);
113524
+ };
113525
+ read.then(done, done);
113526
+ reads.set(slot, read);
113527
+ return read;
113528
+ };
113529
+ 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`;
113530
+ const answered = async (api, fresh = false) => {
113531
+ const read = fresh ? Promise.resolve().then(() => api.get(key)) : sharedRead(api);
113532
+ let timer;
113533
+ try {
113534
+ if (wait.kind === "interactive") {
113535
+ timer = setTimeout(() => wait.notice(`omo: ${waiting}.`), wait.noticeAfterMs);
113536
+ return await read;
113537
+ }
113538
+ const expired = new Promise((_, reject) => {
113539
+ timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waiting}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
113540
+ });
113541
+ return await Promise.race([read, expired]);
113542
+ } finally {
113543
+ clearTimeout(timer);
113544
+ }
113545
+ };
113546
+ 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.`);
113547
+ let unlockedUntil = 0;
113548
+ let noticed = false;
113549
+ const assertUsable = async () => {
113550
+ if (platform !== "linux" || Date.now() < unlockedUntil)
113551
+ return;
113552
+ const lock = await lockProbe();
113553
+ if (lock === "locked")
113554
+ throw new KeychainLockedError(`${platformName} is locked. Unlock it, then try again. Credentials are never saved to a file.`);
113555
+ if (lock === "unlocked") {
113556
+ unlockedUntil = Date.now() + UNLOCKED_REUSE_MS;
113557
+ return;
113558
+ }
113559
+ if (!noticed) {
113560
+ noticed = true;
113561
+ notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
113562
+ }
113563
+ };
113564
+ const parsedRead = async (fresh) => {
113565
+ await assertUsable();
113566
+ let value;
113567
+ try {
113568
+ value = await answered(secrets, fresh);
113569
+ } catch (error) {
113570
+ if (error instanceof KeychainApprovalPendingError)
113571
+ throw error;
113572
+ throw unavailable(error);
113573
+ }
113574
+ if (value === null)
113575
+ return null;
113576
+ try {
113577
+ return schema.parse(JSON.parse(value));
113578
+ } catch {
113579
+ 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.");
113580
+ }
113581
+ };
113582
+ return {
113583
+ read: () => parsedRead(false),
113584
+ readAuthoritative: () => parsedRead(true),
113585
+ async write(value) {
113586
+ await assertUsable();
113587
+ try {
113588
+ let next = value;
113589
+ if (amendWrite !== undefined) {
113590
+ const raw = await answered(secrets, true);
113591
+ let previous = null;
113592
+ if (raw !== null) {
113593
+ try {
113594
+ previous = schema.parse(JSON.parse(raw));
113595
+ } catch {}
113596
+ }
113597
+ next = amendWrite(previous, value);
113598
+ }
113599
+ await secrets.set({ ...key, value: JSON.stringify(schema.parse(next)) });
113600
+ } catch (error) {
113601
+ throw unavailable(error);
113602
+ }
113603
+ forget(secrets);
113604
+ },
113605
+ async clear() {
113606
+ await assertUsable();
113607
+ try {
113608
+ await secrets.delete(key);
113609
+ } catch (error) {
113610
+ throw unavailable(error);
113611
+ }
113612
+ forget(secrets);
113613
+ }
113614
+ };
113615
+ }
113616
+
113617
+ // packages/omo-opencode/src/cli/service-auth/loopback.ts
113618
+ import { createHash as createHash13, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
113619
+ import { createServer as createServer3 } from "node:http";
113620
+ class BrowserUnavailable extends SignInError {
113621
+ }
113622
+ async function authorize(options) {
113623
+ const verifier = randomBytes5(32).toString("base64url");
113624
+ const state = randomBytes5(32).toString("base64url");
113625
+ const answer = Promise.withResolvers();
113626
+ const abort = () => answer.reject(new SignInError("Browser sign-in cancelled or timed out."));
113627
+ let accepted = false;
113628
+ let origin = "";
113629
+ const server = createServer3((request, response) => {
113630
+ response.setHeader("cache-control", "no-store");
113631
+ response.setHeader("referrer-policy", "no-referrer");
113632
+ response.setHeader("content-type", "text/plain; charset=utf-8");
113633
+ const url = new URL(request.url ?? "/", origin);
113634
+ 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"]) {
113635
+ response.writeHead(404).end("Not found");
113636
+ return;
113637
+ }
113638
+ const code = url.searchParams.get("code");
113639
+ const suppliedState = Buffer.from(url.searchParams.get("state") ?? "");
113640
+ const expectedState = Buffer.from(state);
113641
+ if (accepted || url.searchParams.getAll("state").length !== 1 || suppliedState.length !== expectedState.length || !timingSafeEqual(suppliedState, expectedState) || url.searchParams.getAll("code").length !== 1 || !code) {
113642
+ response.writeHead(400).end("Invalid sign-in response");
113643
+ return;
113644
+ }
113645
+ accepted = true;
113646
+ response.writeHead(200).end("Return to the terminal to finish signing in.");
113647
+ answer.resolve(code);
113648
+ });
113649
+ try {
113650
+ await new Promise((resolve, reject) => {
113651
+ server.once("error", reject);
113652
+ server.listen(0, "127.0.0.1", () => {
113653
+ server.off("error", reject);
113654
+ resolve();
113655
+ });
113656
+ });
113657
+ const address = server.address();
113658
+ if (!address || typeof address === "string")
113659
+ throw new SignInError("Unable to start the sign-in callback.");
113660
+ origin = `http://127.0.0.1:${address.port}`;
113661
+ const url = new URL(serviceOrigin(options.accounts));
113662
+ url.search = new URLSearchParams({
113663
+ redirect_uri: `${origin}/callback`,
113664
+ code_challenge: createHash13("sha256").update(verifier).digest("base64url"),
113665
+ code_challenge_method: "S256",
113666
+ state
113667
+ }).toString();
113668
+ const timer = setTimeout(abort, 5 * 60000);
113669
+ options.signal?.addEventListener("abort", abort, { once: true });
113670
+ try {
113671
+ options.signal?.throwIfAborted();
113672
+ const openerFailed = () => {
113673
+ if (!accepted)
113674
+ throw new BrowserUnavailable("No browser is available; use device sign-in.");
113675
+ };
113676
+ const [code] = await Promise.all([
113677
+ answer.promise,
113678
+ options.open(url.href).then((opened) => {
113679
+ if (!opened)
113680
+ openerFailed();
113681
+ }, openerFailed)
113682
+ ]);
113683
+ return { code, codeVerifier: verifier };
113684
+ } finally {
113685
+ clearTimeout(timer);
113686
+ options.signal?.removeEventListener("abort", abort);
113687
+ }
113688
+ } finally {
113689
+ server.closeAllConnections();
113690
+ await new Promise((resolve) => server.close(() => resolve()));
113691
+ }
113692
+ }
113693
+ async function loginLoopback(session, options) {
113694
+ await session.ready();
113695
+ const keys = generateDeviceKeys();
113696
+ for (;; ) {
113697
+ const authorization = await authorize({ accounts: options.accounts, open: options.open, signal: session.signal });
113698
+ try {
113699
+ const grant = parseReply(grantSchema, await session.request("/v1/session/exchange", jsonRequest({
113700
+ ...authorization,
113701
+ kind: "cli",
113702
+ deviceName: options.name,
113703
+ platform: options.platform,
113704
+ ...keys.public
113705
+ })));
113706
+ await session.save({ ...grant, ...keys.private });
113707
+ return;
113708
+ } catch (error) {
113709
+ if (await session.removeForLimit(error, options.chooseDevice))
113710
+ continue;
113711
+ throw new SignInError("Sign-in cancelled. No device was removed.");
113712
+ }
113713
+ }
113714
+ }
113715
+
113716
+ // packages/omo-opencode/src/cli/service-auth/session.ts
113717
+ import { homedir as homedir32 } from "node:os";
113718
+
112977
113719
  // packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
112978
113720
  init_zod();
112979
- import { mkdir as mkdir10, readFile as readFile34, rename as rename7, rm as rm16, writeFile as writeFile16 } from "node:fs/promises";
112980
- import { dirname as dirname43, join as join106 } from "node:path";
113721
+ import { mkdir as mkdir12, readFile as readFile35, rename as rename8, rm as rm17, writeFile as writeFile17 } from "node:fs/promises";
113722
+ import { dirname as dirname43, join as join107 } from "node:path";
112981
113723
  var markerSchema = object({ device: string2().nullable(), at: string2() });
112982
- var signedOutMarkerPath = (home, credential) => join106(home, ".omo", "account-state", `${credential}.signed-out.json`);
113724
+ var signedOutMarkerPath = (home, credential) => join107(home, ".omo", "account-state", `${credential}.signed-out.json`);
112983
113725
  async function readSignedOutMarker(path) {
112984
- const text = await readFile34(path, "utf8").catch(() => null);
113726
+ const text = await readFile35(path, "utf8").catch(() => null);
112985
113727
  if (text === null)
112986
113728
  return null;
112987
113729
  let value;
@@ -112994,12 +113736,12 @@ async function readSignedOutMarker(path) {
112994
113736
  return parsed.success ? parsed.data : null;
112995
113737
  }
112996
113738
  async function writeSignedOutMarker(path, device) {
112997
- await mkdir10(dirname43(path), { recursive: true, mode: 448 });
113739
+ await mkdir12(dirname43(path), { recursive: true, mode: 448 });
112998
113740
  const staging = `${path}.${process.pid}.tmp`;
112999
- await writeFile16(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
113000
- await rename7(staging, path);
113741
+ await writeFile17(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
113742
+ await rename8(staging, path);
113001
113743
  }
113002
- var clearSignedOutMarker = (path) => rm16(path, { force: true });
113744
+ var clearSignedOutMarker = (path) => rm17(path, { force: true });
113003
113745
 
113004
113746
  // packages/omo-opencode/src/cli/service-auth/session.ts
113005
113747
  class SessionEnded extends SignInError {
@@ -113014,30 +113756,29 @@ class SessionEnded extends SignInError {
113014
113756
  var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
113015
113757
  function createSession(options) {
113016
113758
  const api = serviceOrigin(options.api);
113759
+ const now = options.now ?? Date.now;
113017
113760
  const { store, signal } = options;
113018
- const directory = join107(options.home ?? homedir31(), ".omo", "session-locks");
113019
- const lockPath = join107(directory, `${credentialId(api)}.lock`);
113020
- const markerPath = signedOutMarkerPath(options.home ?? homedir31(), credentialId(api));
113761
+ const markerPath = signedOutMarkerPath(options.home ?? homedir32(), credentialId(api));
113021
113762
  async function locked(action) {
113022
- await mkdir11(directory, { recursive: true, mode: 448 });
113023
113763
  signal?.throwIfAborted();
113024
- return withLock(lockPath, async () => {
113764
+ return withCredentialLock(api, async () => {
113025
113765
  signal?.throwIfAborted();
113026
113766
  return action();
113027
- }, { ownerTag: "cli-session", staleAfterMs: Number.POSITIVE_INFINITY });
113767
+ }, options.home);
113028
113768
  }
113029
113769
  const request = (path, init) => requestApi(api, path, init, signal);
113030
- 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);
113031
- async function refreshedAccess(current) {
113032
- if (current.refreshState === "uncertain")
113033
- throw uncertain();
113034
- if (Date.parse(current.accessTokenExpiresAt) > Date.now() + 30000)
113035
- return current.accessToken;
113770
+ async function refreshed(current) {
113771
+ if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
113772
+ throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
113773
+ }
113774
+ if (Date.parse(current.accessTokenExpiresAt) > now() + 30000)
113775
+ return current;
113036
113776
  await store.write({ ...current, refreshState: "uncertain" });
113037
113777
  try {
113038
113778
  const tokens = parseReply(tokenSchema, await request("/v1/session/refresh", jsonRequest({ refreshToken: current.refreshToken })));
113039
- await store.write({ ...current, ...tokens });
113040
- return tokens.accessToken;
113779
+ const successor = { ...current, ...tokens };
113780
+ await store.write(successor);
113781
+ return successor;
113041
113782
  } catch (error) {
113042
113783
  if (error instanceof CredentialStoreError)
113043
113784
  throw error;
@@ -113049,12 +113790,19 @@ function createSession(options) {
113049
113790
  await store.write(current);
113050
113791
  throw error;
113051
113792
  }
113052
- throw uncertain();
113793
+ throw new SessionEnded(`The refresh outcome is unknown. Saved credentials and keys were retained. ${signInHint("again")}`, false, "refresh_recovery_expired");
113053
113794
  }
113054
113795
  }
113796
+ async function snapshot() {
113797
+ return locked(async () => {
113798
+ const current = await store.read();
113799
+ return current === null ? null : refreshed(current);
113800
+ });
113801
+ }
113055
113802
  return {
113056
113803
  request,
113057
113804
  signal,
113805
+ transaction: locked,
113058
113806
  async ready() {
113059
113807
  await store.read();
113060
113808
  },
@@ -113066,18 +113814,32 @@ function createSession(options) {
113066
113814
  },
113067
113815
  signedOutMarker: () => readSignedOutMarker(markerPath),
113068
113816
  clearSignedOutMarker: () => clearSignedOutMarker(markerPath),
113069
- async update(action) {
113070
- return locked(async () => action(await store.read()));
113817
+ async update(action, options = {}) {
113818
+ return locked(async () => {
113819
+ let current;
113820
+ try {
113821
+ current = await store.readAuthoritative();
113822
+ } catch (error) {
113823
+ if (!options.replaceInvalid || !(error instanceof InvalidCredentialState))
113824
+ throw error;
113825
+ current = null;
113826
+ }
113827
+ return action(current);
113828
+ });
113071
113829
  },
113830
+ async forget() {
113831
+ await locked(() => store.clear());
113832
+ },
113833
+ accessSnapshot: snapshot,
113072
113834
  async logout() {
113073
113835
  return locked(async () => {
113074
113836
  let current = null;
113075
113837
  try {
113076
- current = await store.read();
113838
+ current = await store.readAuthoritative();
113077
113839
  if (current !== null) {
113078
113840
  if (current.refreshState === "uncertain")
113079
113841
  return false;
113080
- const access = Date.parse(current.accessTokenExpiresAt) <= Date.now() ? await refreshedAccess(current) : current.accessToken;
113842
+ const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
113081
113843
  await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
113082
113844
  method: "DELETE",
113083
113845
  headers: { authorization: `Bearer ${access}` }
@@ -113096,12 +113858,19 @@ function createSession(options) {
113096
113858
  }
113097
113859
  });
113098
113860
  },
113099
- async accessToken() {
113861
+ async accessToken(expect) {
113862
+ signal?.throwIfAborted();
113863
+ const snapshot = await store.read();
113864
+ signal?.throwIfAborted();
113865
+ if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)))
113866
+ return snapshot.accessToken;
113100
113867
  return locked(async () => {
113101
- const current = await store.read();
113868
+ const current = await store.readAuthoritative();
113102
113869
  if (current === null)
113103
113870
  throw new SignInError(`Not signed in. ${signInHint("first")}`);
113104
- return refreshedAccess(current);
113871
+ if (expect !== undefined && !expect(current))
113872
+ throw new CredentialIdentityChanged;
113873
+ return (await refreshed(current)).accessToken;
113105
113874
  });
113106
113875
  },
113107
113876
  async removeForLimit(error, choose) {
@@ -113430,12 +114199,12 @@ async function boulder(options) {
113430
114199
  }
113431
114200
  // packages/omo-opencode/src/cli/codex-ulw-loop.ts
113432
114201
  import { spawn as spawn6 } from "node:child_process";
113433
- import { existsSync as existsSync67, readFileSync as readFileSync44, realpathSync as realpathSync13 } from "node:fs";
113434
- import { homedir as homedir32 } from "node:os";
114202
+ import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "node:fs";
114203
+ import { homedir as homedir33 } from "node:os";
113435
114204
  var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
113436
114205
  function resolveCodexUlwLoopCommand(input = {}) {
113437
114206
  const env = input.env ?? process.env;
113438
- const homeDir = input.homeDir ?? homedir32();
114207
+ const homeDir = input.homeDir ?? homedir33();
113439
114208
  const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
113440
114209
  if (localComponentBin !== null)
113441
114210
  return { executable: localComponentBin, argsPrefix: [] };
@@ -113480,7 +114249,7 @@ function resolveLegacyLocalOmoBin(env, homeDir, currentExecutablePaths) {
113480
114249
  }
113481
114250
  function isGeneratedRuntimeWrapper(candidate) {
113482
114251
  try {
113483
- return readFileSync44(candidate, "utf8").includes(RUNTIME_WRAPPER_MARKER);
114252
+ return readFileSync45(candidate, "utf8").includes(RUNTIME_WRAPPER_MARKER);
113484
114253
  } catch (error) {
113485
114254
  if (error instanceof Error)
113486
114255
  return false;
@@ -113493,7 +114262,7 @@ function isCurrentExecutable(candidate, currentExecutablePaths) {
113493
114262
  }
113494
114263
  function realpathOrSelf2(path) {
113495
114264
  try {
113496
- return realpathSync13(path);
114265
+ return realpathSync14(path);
113497
114266
  } catch (error) {
113498
114267
  if (error instanceof Error)
113499
114268
  return path;
@@ -113678,7 +114447,7 @@ function linkedWorktrees(records) {
113678
114447
  }
113679
114448
  // packages/omo-opencode/src/cli/worktree-sweep/sweep.ts
113680
114449
  import { existsSync as existsSync68 } from "node:fs";
113681
- import { stat as stat9 } from "node:fs/promises";
114450
+ import { stat as stat10 } from "node:fs/promises";
113682
114451
  import os7 from "node:os";
113683
114452
  import { normalize as normalize2 } from "node:path";
113684
114453
 
@@ -113761,7 +114530,7 @@ async function isOlderThan(worktreePath, days, now) {
113761
114530
  if (days <= 0)
113762
114531
  return false;
113763
114532
  try {
113764
- const stats = await stat9(worktreePath);
114533
+ const stats = await stat10(worktreePath);
113765
114534
  return now - stats.mtimeMs > days * DAY_MS;
113766
114535
  } catch {
113767
114536
  return false;
@@ -114008,7 +114777,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Baili
114008
114777
  Copilot github-copilot/ models (fallback)
114009
114778
  OpenCode Zen opencode/ models (opencode/claude-opus-5, etc.)
114010
114779
  Z.ai zai-coding-plan/glm-5.2 (visual-engineering fallback)
114011
- Kimi kimi-for-coding/kimi-k3 (Sisyphus/Prometheus fallback)
114780
+ Kimi kimi-for-coding/kimi-k3.1-pro (Sisyphus/Prometheus fallback)
114012
114781
  Bailian bailian-coding-plan/ models (Qwen, GLM, Kimi fallback)
114013
114782
  MiniMax minimax-coding-plan/MiniMax-M3 (utility fallback)
114014
114783
  MiniMax CN minimax-cn-coding-plan/MiniMax-M3 (utility fallback)