@litfamily/lithermes 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/README_Ko-KR.md +188 -0
  4. package/assets/lithermes-plugin/NOTICE.md +46 -0
  5. package/assets/lithermes-plugin/README.md +390 -0
  6. package/assets/lithermes-plugin/__init__.py +589 -0
  7. package/assets/lithermes-plugin/auto_update.py +338 -0
  8. package/assets/lithermes-plugin/bounded_work.py +1120 -0
  9. package/assets/lithermes-plugin/bounded_work_tools.py +115 -0
  10. package/assets/lithermes-plugin/core.py +1813 -0
  11. package/assets/lithermes-plugin/core_commands.py +243 -0
  12. package/assets/lithermes-plugin/core_contexts.py +458 -0
  13. package/assets/lithermes-plugin/core_contract.py +456 -0
  14. package/assets/lithermes-plugin/core_plans.py +418 -0
  15. package/assets/lithermes-plugin/core_reader_args.py +34 -0
  16. package/assets/lithermes-plugin/core_recap_command.py +141 -0
  17. package/assets/lithermes-plugin/core_recap_state.py +175 -0
  18. package/assets/lithermes-plugin/core_review.py +198 -0
  19. package/assets/lithermes-plugin/core_routing.py +641 -0
  20. package/assets/lithermes-plugin/core_runs.py +283 -0
  21. package/assets/lithermes-plugin/core_runtime.py +251 -0
  22. package/assets/lithermes-plugin/core_workflow_commands.py +207 -0
  23. package/assets/lithermes-plugin/deliverable_hedge_guard.py +562 -0
  24. package/assets/lithermes-plugin/diagnostics.py +468 -0
  25. package/assets/lithermes-plugin/handoff.py +97 -0
  26. package/assets/lithermes-plugin/knowledge.py +920 -0
  27. package/assets/lithermes-plugin/knowledge_tools.py +130 -0
  28. package/assets/lithermes-plugin/lit_mark.py +140 -0
  29. package/assets/lithermes-plugin/lit_mark_rows.json +1363 -0
  30. package/assets/lithermes-plugin/litgoal/__init__.py +10 -0
  31. package/assets/lithermes-plugin/litgoal/cli.py +207 -0
  32. package/assets/lithermes-plugin/litgoal/hook.py +81 -0
  33. package/assets/lithermes-plugin/litgoal/model.py +203 -0
  34. package/assets/lithermes-plugin/litgoal/runtime.py +522 -0
  35. package/assets/lithermes-plugin/litgoal/store.py +367 -0
  36. package/assets/lithermes-plugin/litgoal/tools.py +300 -0
  37. package/assets/lithermes-plugin/output-styles/asd-ste100-ko.md +41 -0
  38. package/assets/lithermes-plugin/output-styles/asd-ste100.md +40 -0
  39. package/assets/lithermes-plugin/output-styles/eli5-ko.md +13 -0
  40. package/assets/lithermes-plugin/output-styles/eli5.md +11 -0
  41. package/assets/lithermes-plugin/output_styles.py +62 -0
  42. package/assets/lithermes-plugin/payload-version.json +2107 -0
  43. package/assets/lithermes-plugin/plugin.yaml +16 -0
  44. package/assets/lithermes-plugin/provider_metrics.py +161 -0
  45. package/assets/lithermes-plugin/redaction.py +148 -0
  46. package/assets/lithermes-plugin/rules/__init__.py +55 -0
  47. package/assets/lithermes-plugin/rules/bundled-rules/baseline-discipline.md +20 -0
  48. package/assets/lithermes-plugin/rules/bundled-rules/build-decision-gate.md +19 -0
  49. package/assets/lithermes-plugin/rules/bundled-rules/windows-git-bash.md +17 -0
  50. package/assets/lithermes-plugin/rules/constants.py +122 -0
  51. package/assets/lithermes-plugin/rules/discovery.py +276 -0
  52. package/assets/lithermes-plugin/rules/engine.py +447 -0
  53. package/assets/lithermes-plugin/rules/frontmatter.py +149 -0
  54. package/assets/lithermes-plugin/rules/globmatch.py +333 -0
  55. package/assets/lithermes-plugin/scientific_visualization.py +158 -0
  56. package/assets/lithermes-plugin/session_context.py +8 -0
  57. package/assets/lithermes-plugin/skill_loop.py +2044 -0
  58. package/assets/lithermes-plugin/skill_observer.py +1778 -0
  59. package/assets/lithermes-plugin/skills/autoconference/LICENSE +21 -0
  60. package/assets/lithermes-plugin/skills/autoconference/ORIGIN.json +11 -0
  61. package/assets/lithermes-plugin/skills/autoconference/SKILL.md +163 -0
  62. package/assets/lithermes-plugin/skills/autoconference/assets/conference_template.md +76 -0
  63. package/assets/lithermes-plugin/skills/autoconference/assets/report_template.md +53 -0
  64. package/assets/lithermes-plugin/skills/autoconference/assets/synthesis_template.md +39 -0
  65. package/assets/lithermes-plugin/skills/autoconference/dependencies/autoresearch.md +14 -0
  66. package/assets/lithermes-plugin/skills/autoconference/modes/analyze/SKILL.md +269 -0
  67. package/assets/lithermes-plugin/skills/autoconference/modes/core/SKILL.md +134 -0
  68. package/assets/lithermes-plugin/skills/autoconference/modes/core/convergence-guide.md +162 -0
  69. package/assets/lithermes-plugin/skills/autoconference/modes/core/crash-recovery.md +63 -0
  70. package/assets/lithermes-plugin/skills/autoconference/modes/debate/SKILL.md +383 -0
  71. package/assets/lithermes-plugin/skills/autoconference/modes/plan/SKILL.md +304 -0
  72. package/assets/lithermes-plugin/skills/autoconference/modes/resume/SKILL.md +82 -0
  73. package/assets/lithermes-plugin/skills/autoconference/modes/ship/SKILL.md +78 -0
  74. package/assets/lithermes-plugin/skills/autoconference/modes/survey/SKILL.md +376 -0
  75. package/assets/lithermes-plugin/skills/autoconference/references/agent-prompts.md +110 -0
  76. package/assets/lithermes-plugin/skills/autoconference/references/conference-protocol.md +90 -0
  77. package/assets/lithermes-plugin/skills/autoconference/references/core-principles.md +78 -0
  78. package/assets/lithermes-plugin/skills/autoconference/references/results-logging.md +165 -0
  79. package/assets/lithermes-plugin/skills/autoconference/references/visualization-guide.md +99 -0
  80. package/assets/lithermes-plugin/skills/autoconference/scripts/check_conference.sh +197 -0
  81. package/assets/lithermes-plugin/skills/autoconference/scripts/init_conference.py +489 -0
  82. package/assets/lithermes-plugin/skills/autoconference/scripts/style_presets.py +104 -0
  83. package/assets/lithermes-plugin/skills/autoconference/templates/code-performance.md +59 -0
  84. package/assets/lithermes-plugin/skills/autoconference/templates/debate-mode.md +50 -0
  85. package/assets/lithermes-plugin/skills/autoconference/templates/prompt-optimization.md +58 -0
  86. package/assets/lithermes-plugin/skills/autoconference/templates/quick-conference.md +48 -0
  87. package/assets/lithermes-plugin/skills/autoconference/templates/research-synthesis.md +56 -0
  88. package/assets/lithermes-plugin/skills/autoconference/templates/survey-mode.md +63 -0
  89. package/assets/lithermes-plugin/skills/autoresearch/LICENSE +21 -0
  90. package/assets/lithermes-plugin/skills/autoresearch/ORIGIN.json +11 -0
  91. package/assets/lithermes-plugin/skills/autoresearch/SKILL.md +175 -0
  92. package/assets/lithermes-plugin/skills/autoresearch/assets/report_template.md +50 -0
  93. package/assets/lithermes-plugin/skills/autoresearch/assets/research_template.md +38 -0
  94. package/assets/lithermes-plugin/skills/autoresearch/assets/results_template.tsv +2 -0
  95. package/assets/lithermes-plugin/skills/autoresearch/modes/core/SKILL.md +204 -0
  96. package/assets/lithermes-plugin/skills/autoresearch/modes/core/evaluator-contract.md +108 -0
  97. package/assets/lithermes-plugin/skills/autoresearch/modes/core/stuck-detection.md +102 -0
  98. package/assets/lithermes-plugin/skills/autoresearch/modes/debug/SKILL.md +240 -0
  99. package/assets/lithermes-plugin/skills/autoresearch/modes/debug/investigation-techniques.md +254 -0
  100. package/assets/lithermes-plugin/skills/autoresearch/modes/fix/SKILL.md +176 -0
  101. package/assets/lithermes-plugin/skills/autoresearch/modes/learn/SKILL.md +96 -0
  102. package/assets/lithermes-plugin/skills/autoresearch/modes/plan/SKILL.md +291 -0
  103. package/assets/lithermes-plugin/skills/autoresearch/modes/predict/SKILL.md +271 -0
  104. package/assets/lithermes-plugin/skills/autoresearch/modes/predict/persona-templates.md +227 -0
  105. package/assets/lithermes-plugin/skills/autoresearch/modes/reason/SKILL.md +174 -0
  106. package/assets/lithermes-plugin/skills/autoresearch/modes/scenario/SKILL.md +168 -0
  107. package/assets/lithermes-plugin/skills/autoresearch/modes/scenario/dimensions.md +173 -0
  108. package/assets/lithermes-plugin/skills/autoresearch/modes/security/SKILL.md +287 -0
  109. package/assets/lithermes-plugin/skills/autoresearch/modes/security/owasp-checklist.md +156 -0
  110. package/assets/lithermes-plugin/skills/autoresearch/modes/security/stride-model.md +191 -0
  111. package/assets/lithermes-plugin/skills/autoresearch/modes/ship/SKILL.md +99 -0
  112. package/assets/lithermes-plugin/skills/autoresearch/modes/ship/type-checklists.md +158 -0
  113. package/assets/lithermes-plugin/skills/autoresearch/references/core-principles.md +75 -0
  114. package/assets/lithermes-plugin/skills/autoresearch/references/results-logging.md +55 -0
  115. package/assets/lithermes-plugin/skills/autoresearch/references/visualization-guide.md +90 -0
  116. package/assets/lithermes-plugin/skills/autoresearch/scripts/check_progress.sh +139 -0
  117. package/assets/lithermes-plugin/skills/autoresearch/scripts/init_research.py +219 -0
  118. package/assets/lithermes-plugin/skills/autoresearch/scripts/style_presets.py +104 -0
  119. package/assets/lithermes-plugin/skills/browser-drive/SKILL.md +147 -0
  120. package/assets/lithermes-plugin/skills/browser-drive/scripts/capability_probe.py +528 -0
  121. package/assets/lithermes-plugin/skills/comment-checker/SKILL.md +162 -0
  122. package/assets/lithermes-plugin/skills/debugging/SKILL.md +271 -0
  123. package/assets/lithermes-plugin/skills/debugging/references/methodology/00-setup.md +108 -0
  124. package/assets/lithermes-plugin/skills/debugging/references/methodology/02-investigate.md +122 -0
  125. package/assets/lithermes-plugin/skills/debugging/references/methodology/04-oracle-triple.md +136 -0
  126. package/assets/lithermes-plugin/skills/debugging/references/methodology/05-escalate.md +69 -0
  127. package/assets/lithermes-plugin/skills/debugging/references/methodology/06-fix.md +116 -0
  128. package/assets/lithermes-plugin/skills/debugging/references/methodology/08-qa.md +94 -0
  129. package/assets/lithermes-plugin/skills/debugging/references/methodology/09-cleanup.md +164 -0
  130. package/assets/lithermes-plugin/skills/debugging/references/methodology/partial-runtime-evidence.md +229 -0
  131. package/assets/lithermes-plugin/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  132. package/assets/lithermes-plugin/skills/debugging/references/runtimes/go.md +252 -0
  133. package/assets/lithermes-plugin/skills/debugging/references/runtimes/native-binary.md +484 -0
  134. package/assets/lithermes-plugin/skills/debugging/references/runtimes/node.md +260 -0
  135. package/assets/lithermes-plugin/skills/debugging/references/runtimes/python.md +248 -0
  136. package/assets/lithermes-plugin/skills/debugging/references/runtimes/rust.md +234 -0
  137. package/assets/lithermes-plugin/skills/debugging/references/tools/ghidra.md +212 -0
  138. package/assets/lithermes-plugin/skills/debugging/references/tools/playwright-cli.md +194 -0
  139. package/assets/lithermes-plugin/skills/debugging/references/tools/pwndbg.md +263 -0
  140. package/assets/lithermes-plugin/skills/debugging/references/tools/pwntools.md +265 -0
  141. package/assets/lithermes-plugin/skills/deep-interview/SKILL.md +419 -0
  142. package/assets/lithermes-plugin/skills/frontend-ui-ux/SKILL.md +49 -0
  143. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/.gitattributes +2 -0
  144. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/README.md +248 -0
  145. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/_INDEX.md +191 -0
  146. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/airbnb.md +393 -0
  147. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/airtable.md +92 -0
  148. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/apple.md +250 -0
  149. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/aside.md +209 -0
  150. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/binance.md +348 -0
  151. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/bmw.md +183 -0
  152. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/brutalist-skill.md +92 -0
  153. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/bugatti.md +271 -0
  154. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/cal.md +262 -0
  155. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/claude.md +315 -0
  156. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/clay.md +307 -0
  157. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/clickhouse.md +284 -0
  158. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/clone-from-url.md +65 -0
  159. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/cohere.md +269 -0
  160. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/coinbase.md +132 -0
  161. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/composio.md +310 -0
  162. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/cursor.md +312 -0
  163. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/design-system-architecture.md +244 -0
  164. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/elevenlabs.md +268 -0
  165. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/expo.md +284 -0
  166. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/ferrari.md +317 -0
  167. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/figma.md +223 -0
  168. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/framer.md +249 -0
  169. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/gpt-tasteskill.md +74 -0
  170. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/hashicorp.md +281 -0
  171. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/ibm.md +335 -0
  172. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/image-to-code-skill.md +1228 -0
  173. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/imagegen-brandkit.md +798 -0
  174. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/imagegen-frontend-mobile.md +1465 -0
  175. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/imagegen-frontend-web.md +987 -0
  176. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/intercom.md +149 -0
  177. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/kraken.md +128 -0
  178. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/lamborghini.md +291 -0
  179. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/layout-skill.md +107 -0
  180. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/lazyweb.md +77 -0
  181. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/linear.app.md +370 -0
  182. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/lovable.md +301 -0
  183. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/mastercard.md +368 -0
  184. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/meta.md +369 -0
  185. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/minimalist-skill.md +85 -0
  186. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/minimax.md +260 -0
  187. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/mintlify.md +329 -0
  188. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/miro.md +111 -0
  189. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/mistral.ai.md +264 -0
  190. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/mongodb.md +269 -0
  191. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/nike.md +366 -0
  192. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/notion.md +312 -0
  193. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/nvidia.md +296 -0
  194. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/ollama.md +270 -0
  195. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/opencode.ai.md +284 -0
  196. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/output-skill.md +49 -0
  197. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/pinterest.md +233 -0
  198. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/playstation.md +367 -0
  199. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/posthog.md +259 -0
  200. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/raycast.md +271 -0
  201. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/react-dev-tooling-skill.md +230 -0
  202. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/redesign-skill.md +178 -0
  203. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/renault.md +314 -0
  204. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/replicate.md +264 -0
  205. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/resend.md +306 -0
  206. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/revolut.md +188 -0
  207. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/runwayml.md +247 -0
  208. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/sanity.md +360 -0
  209. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/sentry.md +265 -0
  210. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/shopify.md +353 -0
  211. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/soft-skill.md +98 -0
  212. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/spacex.md +197 -0
  213. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/spotify.md +249 -0
  214. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/starbucks.md +583 -0
  215. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/stitch-design-example.md +121 -0
  216. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/stitch-skill.md +184 -0
  217. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/stripe.md +325 -0
  218. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/supabase.md +258 -0
  219. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/superhuman.md +255 -0
  220. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/taste-skill.md +1206 -0
  221. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/tesla.md +289 -0
  222. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/theverge.md +342 -0
  223. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/together.ai.md +266 -0
  224. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/uber.md +298 -0
  225. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/vercel.md +313 -0
  226. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/vodafone.md +426 -0
  227. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/voltagent.md +326 -0
  228. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/warp.md +256 -0
  229. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/webflow.md +95 -0
  230. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/wired.md +281 -0
  231. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/wise.md +176 -0
  232. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/x.ai.md +260 -0
  233. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/design/zapier.md +331 -0
  234. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/EVIDENCE.md +97 -0
  235. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/README.md +48 -0
  236. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/UPSTREAM.md +80 -0
  237. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/lane-a-direction.md +64 -0
  238. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/lane-b-execution.md +65 -0
  239. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/lane-c-review.md +65 -0
  240. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/lane-d-memory.md +83 -0
  241. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/orchestration.md +80 -0
  242. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/routing.md +79 -0
  243. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/LICENSE +21 -0
  244. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  245. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/content-writer.md +132 -0
  246. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/design-builder.md +109 -0
  247. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/design-critic.md +89 -0
  248. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/design-lead.md +113 -0
  249. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/design-scout.md +78 -0
  250. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/design-strategist.md +121 -0
  251. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  252. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/inspiration-scout.md +107 -0
  253. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/agents/motion-designer.md +120 -0
  254. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/accessible-content/reference.md +101 -0
  255. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/adaptive-interfaces/reference.md +109 -0
  256. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/cognitive-accessibility/reference.md +107 -0
  257. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-debate/reference.md +199 -0
  258. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-debt-tracker/reference.md +174 -0
  259. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-handoff/reference.md +125 -0
  260. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-md/reference.md +106 -0
  261. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-retrospective/reference.md +266 -0
  262. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-review/reference.md +123 -0
  263. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-system-alignment/reference.md +120 -0
  264. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/designpowers-critique/reference.md +164 -0
  265. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/heuristic-evaluation/reference.md +85 -0
  266. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/inclusive-personas/reference.md +98 -0
  267. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/inspiration-scouting/reference.md +165 -0
  268. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/interaction-design/reference.md +122 -0
  269. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/motion-choreography/reference.md +81 -0
  270. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/research-planning/reference.md +96 -0
  271. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/responsive-patterns/reference.md +77 -0
  272. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/synthetic-user-testing/reference.md +192 -0
  273. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/taste-feedback/reference.md +165 -0
  274. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/taste-report/reference.md +78 -0
  275. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/token-architecture/reference.md +75 -0
  276. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/ui-composition/reference.md +117 -0
  277. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/usability-testing/reference.md +78 -0
  278. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/verification-before-shipping/reference.md +125 -0
  279. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/voice-and-tone/reference.md +79 -0
  280. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/writing-design-plans/reference.md +119 -0
  281. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/perfection/README.md +160 -0
  282. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/perfection/react-perf-tooling.md +127 -0
  283. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/README.md +659 -0
  284. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/charts.csv +26 -0
  285. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/colors.csv +162 -0
  286. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/icons.csv +106 -0
  287. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/landing.csv +35 -0
  288. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/products.csv +162 -0
  289. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/react-performance.csv +45 -0
  290. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/astro.csv +54 -0
  291. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/flutter.csv +53 -0
  292. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/html-tailwind.csv +56 -0
  293. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/jetpack-compose.csv +53 -0
  294. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/nextjs.csv +53 -0
  295. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/nuxt-ui.csv +51 -0
  296. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/nuxtjs.csv +59 -0
  297. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/react-native.csv +52 -0
  298. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/react.csv +54 -0
  299. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/shadcn.csv +61 -0
  300. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/svelte.csv +54 -0
  301. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/swiftui.csv +51 -0
  302. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/stacks/vue.csv +50 -0
  303. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/styles.csv +85 -0
  304. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/typography.csv +74 -0
  305. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/ui-reasoning.csv +162 -0
  306. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/ux-guidelines.csv +100 -0
  307. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/data/web-interface.csv +31 -0
  308. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/scripts/core.py +262 -0
  309. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/scripts/design_system.py +1148 -0
  310. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/ui-ux-db/scripts/search.py +114 -0
  311. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/legal/ATTRIBUTION.md +217 -0
  312. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/legal/LICENSE +21 -0
  313. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/legal/LICENSE-Apache-2.0.txt +201 -0
  314. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/manifest.json +876 -0
  315. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/adaptive-layout.md +81 -0
  316. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/brand-and-imagery.md +84 -0
  317. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/complete-contract.md +457 -0
  318. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/composition.md +89 -0
  319. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/creative-directions.md +81 -0
  320. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/evidence-review.md +113 -0
  321. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/implementation-platforms.md +92 -0
  322. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/inclusive-interface.md +85 -0
  323. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/interaction-motion.md +87 -0
  324. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/operating-lanes.md +85 -0
  325. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/performance-delivery.md +85 -0
  326. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/product-direction.md +86 -0
  327. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/redesign-playbook.md +91 -0
  328. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/system-foundations.md +82 -0
  329. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/taste-direction.md +86 -0
  330. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/visual-language.md +85 -0
  331. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/visual-reconstruction.md +94 -0
  332. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/LICENSE +21 -0
  333. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/PROVENANCE.json +38 -0
  334. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/THIRD-PARTY-NOTICE.txt +14 -0
  335. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/design-intelligence.json +1 -0
  336. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/import-manifest.json +1060 -0
  337. package/assets/lithermes-plugin/skills/frontend-ui-ux/schemas/design-contract-v1alpha1.schema.json +264 -0
  338. package/assets/lithermes-plugin/skills/frontend-ui-ux/schemas/design-contract-v1beta1.schema.json +268 -0
  339. package/assets/lithermes-plugin/skills/frontend-ui-ux/schemas/design-contract-v1beta2.schema.json +280 -0
  340. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/design_contract_validation.py +996 -0
  341. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/design_intelligence.py +128 -0
  342. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/design_runtime.py +98 -0
  343. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/import_design_intelligence.py +56 -0
  344. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/source_import.py +144 -0
  345. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/source_manifest.py +65 -0
  346. package/assets/lithermes-plugin/skills/lit-burnoff/SKILL.md +448 -0
  347. package/assets/lithermes-plugin/skills/lit-burnoff-file/SKILL.md +254 -0
  348. package/assets/lithermes-plugin/skills/lit-code/SKILL.md +609 -0
  349. package/assets/lithermes-plugin/skills/lit-code/references/go/README.md +90 -0
  350. package/assets/lithermes-plugin/skills/lit-code/references/go/backend-stack.md +641 -0
  351. package/assets/lithermes-plugin/skills/lit-code/references/go/bootstrap.md +328 -0
  352. package/assets/lithermes-plugin/skills/lit-code/references/go/bubbletea-v2.md +359 -0
  353. package/assets/lithermes-plugin/skills/lit-code/references/go/cobra-stack.md +468 -0
  354. package/assets/lithermes-plugin/skills/lit-code/references/go/concurrency.md +362 -0
  355. package/assets/lithermes-plugin/skills/lit-code/references/go/data-modeling.md +329 -0
  356. package/assets/lithermes-plugin/skills/lit-code/references/go/error-handling.md +359 -0
  357. package/assets/lithermes-plugin/skills/lit-code/references/go/golangci-strict.md +236 -0
  358. package/assets/lithermes-plugin/skills/lit-code/references/go/grpc-connect.md +375 -0
  359. package/assets/lithermes-plugin/skills/lit-code/references/go/libraries.md +337 -0
  360. package/assets/lithermes-plugin/skills/lit-code/references/go/one-liners.md +202 -0
  361. package/assets/lithermes-plugin/skills/lit-code/references/go/sqlc-pgx.md +471 -0
  362. package/assets/lithermes-plugin/skills/lit-code/references/go/testing.md +467 -0
  363. package/assets/lithermes-plugin/skills/lit-code/references/go/type-patterns.md +298 -0
  364. package/assets/lithermes-plugin/skills/lit-code/references/python/README.md +314 -0
  365. package/assets/lithermes-plugin/skills/lit-code/references/python/async-anyio.md +442 -0
  366. package/assets/lithermes-plugin/skills/lit-code/references/python/data-modeling.md +233 -0
  367. package/assets/lithermes-plugin/skills/lit-code/references/python/data-processing.md +133 -0
  368. package/assets/lithermes-plugin/skills/lit-code/references/python/error-handling.md +218 -0
  369. package/assets/lithermes-plugin/skills/lit-code/references/python/fastapi-stack.md +316 -0
  370. package/assets/lithermes-plugin/skills/lit-code/references/python/httpx2-optimization.md +360 -0
  371. package/assets/lithermes-plugin/skills/lit-code/references/python/libraries.md +307 -0
  372. package/assets/lithermes-plugin/skills/lit-code/references/python/one-liners.md +268 -0
  373. package/assets/lithermes-plugin/skills/lit-code/references/python/orjson-stack.md +378 -0
  374. package/assets/lithermes-plugin/skills/lit-code/references/python/pydantic-ai.md +285 -0
  375. package/assets/lithermes-plugin/skills/lit-code/references/python/pyproject-strict.md +232 -0
  376. package/assets/lithermes-plugin/skills/lit-code/references/python/textual-tui.md +201 -0
  377. package/assets/lithermes-plugin/skills/lit-code/references/python/type-patterns.md +176 -0
  378. package/assets/lithermes-plugin/skills/lit-code/references/rust/README.md +317 -0
  379. package/assets/lithermes-plugin/skills/lit-code/references/rust/async-tokio.md +299 -0
  380. package/assets/lithermes-plugin/skills/lit-code/references/rust/axum-stack.md +467 -0
  381. package/assets/lithermes-plugin/skills/lit-code/references/rust/cargo-strict.md +317 -0
  382. package/assets/lithermes-plugin/skills/lit-code/references/rust/clap-stack.md +409 -0
  383. package/assets/lithermes-plugin/skills/lit-code/references/rust/concurrency.md +375 -0
  384. package/assets/lithermes-plugin/skills/lit-code/references/rust/libraries.md +439 -0
  385. package/assets/lithermes-plugin/skills/lit-code/references/rust/one-liners.md +291 -0
  386. package/assets/lithermes-plugin/skills/lit-code/references/rust/proptest-insta.md +429 -0
  387. package/assets/lithermes-plugin/skills/lit-code/references/rust/type-state.md +354 -0
  388. package/assets/lithermes-plugin/skills/lit-code/references/rust/unsafe-discipline.md +250 -0
  389. package/assets/lithermes-plugin/skills/lit-code/references/rust/zero-cost-safety.md +527 -0
  390. package/assets/lithermes-plugin/skills/lit-code/references/rust-ub/README.md +289 -0
  391. package/assets/lithermes-plugin/skills/lit-code/references/rust-ub/miri-sanitizers-loom.md +411 -0
  392. package/assets/lithermes-plugin/skills/lit-code/references/rust-ub/ub-taxonomy.md +269 -0
  393. package/assets/lithermes-plugin/skills/lit-code/references/typescript/README.md +195 -0
  394. package/assets/lithermes-plugin/skills/lit-code/references/typescript/backend-hono.md +672 -0
  395. package/assets/lithermes-plugin/skills/lit-code/references/typescript/bootstrap.md +199 -0
  396. package/assets/lithermes-plugin/skills/lit-code/references/typescript/data-modeling.md +202 -0
  397. package/assets/lithermes-plugin/skills/lit-code/references/typescript/error-handling.md +169 -0
  398. package/assets/lithermes-plugin/skills/lit-code/references/typescript/tsconfig-strict.md +152 -0
  399. package/assets/lithermes-plugin/skills/lit-code/references/typescript/type-patterns.md +196 -0
  400. package/assets/lithermes-plugin/skills/lit-code/scripts/go/check-no-excuse-rules.sh +173 -0
  401. package/assets/lithermes-plugin/skills/lit-code/scripts/go/new-project.py +138 -0
  402. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/.editorconfig +13 -0
  403. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/.golangci.yml +95 -0
  404. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/AGENTS.md.tmpl +24 -0
  405. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/README.md.tmpl +12 -0
  406. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/Taskfile.yml +40 -0
  407. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/ci.yml +37 -0
  408. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/config.go +24 -0
  409. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/gitignore +15 -0
  410. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/main.go.tmpl +22 -0
  411. package/assets/lithermes-plugin/skills/lit-code/scripts/go/templates/run.go +15 -0
  412. package/assets/lithermes-plugin/skills/lit-code/scripts/python/check-no-excuse-rules.py +687 -0
  413. package/assets/lithermes-plugin/skills/lit-code/scripts/python/new-project.py +172 -0
  414. package/assets/lithermes-plugin/skills/lit-code/scripts/python/new-script.py +116 -0
  415. package/assets/lithermes-plugin/skills/lit-code/scripts/rust/check-no-excuse-rules.py +296 -0
  416. package/assets/lithermes-plugin/skills/lit-code/scripts/rust/check-no-excuse-rules.sh +158 -0
  417. package/assets/lithermes-plugin/skills/lit-code/scripts/rust/new-project.py +175 -0
  418. package/assets/lithermes-plugin/skills/lit-code/scripts/typescript/check-no-excuse-rules.ts +282 -0
  419. package/assets/lithermes-plugin/skills/lit-code/scripts/typescript/new-project.ts +177 -0
  420. package/assets/lithermes-plugin/skills/lit-commit/SKILL.md +242 -0
  421. package/assets/lithermes-plugin/skills/lit-comprehend/SKILL.md +259 -0
  422. package/assets/lithermes-plugin/skills/lit-comprehend/assets/explainer-scaffold.html +123 -0
  423. package/assets/lithermes-plugin/skills/lit-comprehend/references/artifact-template.md +205 -0
  424. package/assets/lithermes-plugin/skills/lit-comprehend/references/micro-worlds.md +139 -0
  425. package/assets/lithermes-plugin/skills/lit-comprehend/scripts/verify-explainer.py +324 -0
  426. package/assets/lithermes-plugin/skills/lit-crucible/SKILL.md +315 -0
  427. package/assets/lithermes-plugin/skills/lit-handoff/ORIGIN.json +23 -0
  428. package/assets/lithermes-plugin/skills/lit-handoff/SKILL.md +145 -0
  429. package/assets/lithermes-plugin/skills/lit-init/SKILL.md +329 -0
  430. package/assets/lithermes-plugin/skills/lit-korean/SKILL.md +237 -0
  431. package/assets/lithermes-plugin/skills/lit-korean/references/quick-rules.md +24 -0
  432. package/assets/lithermes-plugin/skills/lit-korean/references/safety-checklist.md +23 -0
  433. package/assets/lithermes-plugin/skills/lit-plan/SKILL.md +596 -0
  434. package/assets/lithermes-plugin/skills/lit-recap/SKILL.md +183 -0
  435. package/assets/lithermes-plugin/skills/lit-scientific-visualization/ORIGIN.json +32 -0
  436. package/assets/lithermes-plugin/skills/lit-scientific-visualization/SKILL.md +170 -0
  437. package/assets/lithermes-plugin/skills/litgoal/.gitkeep +0 -0
  438. package/assets/lithermes-plugin/skills/litgoal/SKILL.md +372 -0
  439. package/assets/lithermes-plugin/skills/litresearch/ATTRIBUTION.md +50 -0
  440. package/assets/lithermes-plugin/skills/litresearch/SKILL.md +593 -0
  441. package/assets/lithermes-plugin/skills/litwork/SKILL.md +419 -0
  442. package/assets/lithermes-plugin/skills/lsp/SKILL.md +165 -0
  443. package/assets/lithermes-plugin/skills/lsp-setup/SKILL.md +265 -0
  444. package/assets/lithermes-plugin/skills/lsp-setup/references/bash/README.md +68 -0
  445. package/assets/lithermes-plugin/skills/lsp-setup/references/c-cpp/README.md +78 -0
  446. package/assets/lithermes-plugin/skills/lsp-setup/references/csharp/README.md +90 -0
  447. package/assets/lithermes-plugin/skills/lsp-setup/references/dart/README.md +59 -0
  448. package/assets/lithermes-plugin/skills/lsp-setup/references/elixir/README.md +61 -0
  449. package/assets/lithermes-plugin/skills/lsp-setup/references/go/README.md +63 -0
  450. package/assets/lithermes-plugin/skills/lsp-setup/references/haskell/README.md +69 -0
  451. package/assets/lithermes-plugin/skills/lsp-setup/references/java/README.md +70 -0
  452. package/assets/lithermes-plugin/skills/lsp-setup/references/julia/README.md +70 -0
  453. package/assets/lithermes-plugin/skills/lsp-setup/references/kotlin/README.md +72 -0
  454. package/assets/lithermes-plugin/skills/lsp-setup/references/lua/README.md +68 -0
  455. package/assets/lithermes-plugin/skills/lsp-setup/references/php/README.md +61 -0
  456. package/assets/lithermes-plugin/skills/lsp-setup/references/python/README.md +73 -0
  457. package/assets/lithermes-plugin/skills/lsp-setup/references/ruby/README.md +67 -0
  458. package/assets/lithermes-plugin/skills/lsp-setup/references/rust/README.md +65 -0
  459. package/assets/lithermes-plugin/skills/lsp-setup/references/swift/README.md +64 -0
  460. package/assets/lithermes-plugin/skills/lsp-setup/references/terraform/README.md +66 -0
  461. package/assets/lithermes-plugin/skills/lsp-setup/references/typescript/README.md +82 -0
  462. package/assets/lithermes-plugin/skills/lsp-setup/references/yaml/README.md +65 -0
  463. package/assets/lithermes-plugin/skills/lsp-setup/references/zig/README.md +59 -0
  464. package/assets/lithermes-plugin/skills/lsp-setup/scripts/detect-lsp.ts +221 -0
  465. package/assets/lithermes-plugin/skills/lsp-setup/scripts/lsp-server-table.ts +146 -0
  466. package/assets/lithermes-plugin/skills/lsp-setup/scripts/tsconfig.json +18 -0
  467. package/assets/lithermes-plugin/skills/lsp-setup/scripts/verify-lsp.ts +252 -0
  468. package/assets/lithermes-plugin/skills/refactor/SKILL.md +896 -0
  469. package/assets/lithermes-plugin/skills/review-work/SKILL.md +450 -0
  470. package/assets/lithermes-plugin/skills/rules/SKILL.md +194 -0
  471. package/assets/lithermes-plugin/skills/skill-observer/SKILL.md +190 -0
  472. package/assets/lithermes-plugin/skills/skill-observer/references/review-contract.md +77 -0
  473. package/assets/lithermes-plugin/skills/start-work/SKILL.md +550 -0
  474. package/assets/lithermes-plugin/skills/structural-search/SKILL.md +274 -0
  475. package/assets/lithermes-plugin/skills/visual-qa/SKILL.md +48 -0
  476. package/assets/lithermes-plugin/skills/visual-qa/references/capture-playbook.md +133 -0
  477. package/assets/lithermes-plugin/skills/visual-qa/references/complete-contract.md +522 -0
  478. package/assets/lithermes-plugin/skills/visual-qa/schemas/evidence-manifest-v1alpha1.schema.json +135 -0
  479. package/assets/lithermes-plugin/skills/visual-qa/schemas/evidence-manifest-v1beta1.schema.json +110 -0
  480. package/assets/lithermes-plugin/skills/visual-qa/schemas/review-receipt-v1alpha1.schema.json +49 -0
  481. package/assets/lithermes-plugin/skills/visual-qa/scripts/contract_checks.py +71 -0
  482. package/assets/lithermes-plugin/skills/visual-qa/scripts/evidence_contract.py +288 -0
  483. package/assets/lithermes-plugin/skills/visual-qa/scripts/png_runtime.py +379 -0
  484. package/assets/lithermes-plugin/skills/visual-qa/scripts/review_contract.py +151 -0
  485. package/assets/lithermes-plugin/skills/visual-qa/scripts/tier_checks.py +190 -0
  486. package/assets/lithermes-plugin/skills/visual-qa/scripts/tier_contract.py +103 -0
  487. package/assets/lithermes-plugin/skills/visual-qa/scripts/tui_runtime.py +170 -0
  488. package/assets/lithermes-plugin/skills/visual-qa/scripts/visual_contracts.py +31 -0
  489. package/assets/lithermes-plugin/skills/visual-qa/scripts/visual_qa.py +79 -0
  490. package/assets/lithermes-plugin/skills/wikify/LICENSE +21 -0
  491. package/assets/lithermes-plugin/skills/wikify/ORIGIN.json +12 -0
  492. package/assets/lithermes-plugin/skills/wikify/SKILL.md +192 -0
  493. package/assets/lithermes-plugin/skills/wikify/assets/home-template.md +44 -0
  494. package/assets/lithermes-plugin/skills/wikify/assets/maintenance-report-template.md +46 -0
  495. package/assets/lithermes-plugin/skills/wikify/assets/paper-source-note-template.md +138 -0
  496. package/assets/lithermes-plugin/skills/wikify/assets/source-note-template.md +45 -0
  497. package/assets/lithermes-plugin/skills/wikify/assets/wiki-rules-template.md +117 -0
  498. package/assets/lithermes-plugin/skills/wikify/modes/ingest/SKILL.md +24 -0
  499. package/assets/lithermes-plugin/skills/wikify/modes/init/SKILL.md +26 -0
  500. package/assets/lithermes-plugin/skills/wikify/modes/lint/SKILL.md +30 -0
  501. package/assets/lithermes-plugin/skills/wikify/modes/query/SKILL.md +22 -0
  502. package/assets/lithermes-plugin/skills/wikify/modes/save/SKILL.md +32 -0
  503. package/assets/lithermes-plugin/skills/wikify/references/full-contract.md +761 -0
  504. package/assets/lithermes-plugin/uiux_runtime_common.py +117 -0
  505. package/assets/lithermes-plugin/vendor/NOTICE.md +21 -0
  506. package/assets/lithermes-plugin/vendor/handoff/SKILL.md +199 -0
  507. package/assets/lithermes-plugin/vendor/handoff/evals/evals.json +154 -0
  508. package/assets/lithermes-plugin/vendor/handoff/examples/HANDOFF-example-generic-auth-refactor.md +97 -0
  509. package/assets/lithermes-plugin/vendor/handoff/templates/HANDOFF.md +121 -0
  510. package/assets/lithermes-plugin/vendor/licenses/022_handoff-MIT.txt +21 -0
  511. package/assets/lithermes-plugin/vendor/licenses/045_scientific-visualization-MIT.txt +21 -0
  512. package/assets/lithermes-plugin/vendor/provenance/022_handoff.md +16 -0
  513. package/assets/lithermes-plugin/vendor/provenance/045_scientific-visualization.md +18 -0
  514. package/assets/lithermes-plugin/vendor/scientific-visualization/SKILL.md +283 -0
  515. package/assets/lithermes-plugin/vendor/scientific-visualization/assets/color_palettes.py +197 -0
  516. package/assets/lithermes-plugin/vendor/scientific-visualization/assets/nature.mplstyle +75 -0
  517. package/assets/lithermes-plugin/vendor/scientific-visualization/assets/presentation.mplstyle +74 -0
  518. package/assets/lithermes-plugin/vendor/scientific-visualization/assets/publication.mplstyle +78 -0
  519. package/assets/lithermes-plugin/vendor/scientific-visualization/evals/evals.json +158 -0
  520. package/assets/lithermes-plugin/vendor/scientific-visualization/references/color_palettes.md +380 -0
  521. package/assets/lithermes-plugin/vendor/scientific-visualization/references/journal_requirements.md +359 -0
  522. package/assets/lithermes-plugin/vendor/scientific-visualization/references/matplotlib_examples.md +608 -0
  523. package/assets/lithermes-plugin/vendor/scientific-visualization/references/mdanalysis_martini_visualization.md +85 -0
  524. package/assets/lithermes-plugin/vendor/scientific-visualization/references/publication_guidelines.md +217 -0
  525. package/assets/lithermes-plugin/vendor/scientific-visualization/references/seaborn_for_publications.md +293 -0
  526. package/assets/lithermes-plugin/vendor/scientific-visualization/scripts/figure_export.py +238 -0
  527. package/assets/lithermes-plugin/vendor/scientific-visualization/scripts/style_presets.py +467 -0
  528. package/assets/lithermes-plugin/vendor/scientific-visualization/tests/test_figure_export.py +51 -0
  529. package/assets/lithermes-plugin/vendor/scientific-visualization/tests/test_style_presets.py +114 -0
  530. package/bin/lithermes.js +8 -0
  531. package/package.json +58 -0
  532. package/readme-assets/badge-license.svg +1 -0
  533. package/readme-assets/badge-version.svg +1 -0
  534. package/readme-assets/cover.webp +0 -0
  535. package/readme-assets/lithermes-clay-icon.png +0 -0
  536. package/readme-assets/lithermes-wordmark.svg +5 -0
  537. package/src/cli.js +396 -0
  538. package/src/lib/autoUpdate.js +4 -0
  539. package/src/lib/canonicalCorpus.js +436 -0
  540. package/src/lib/check.js +200 -0
  541. package/src/lib/config.js +229 -0
  542. package/src/lib/files.js +126 -0
  543. package/src/lib/hermesDiscovery.js +122 -0
  544. package/src/lib/hud.js +135 -0
  545. package/src/lib/install.js +559 -0
  546. package/src/lib/litMark.js +68 -0
  547. package/src/lib/modelConfig.js +431 -0
  548. package/src/lib/modelConfigBoundary.js +206 -0
  549. package/src/lib/modelPrompt.js +201 -0
  550. package/src/lib/modelRoutePolicy.js +379 -0
  551. package/src/lib/patch.js +153 -0
  552. package/src/lib/skillLoop.js +62 -0
  553. package/src/lib/skillPayload.js +306 -0
  554. package/src/lib/skins.js +274 -0
  555. package/src/lib/spinner.js +193 -0
  556. package/src/lib/updateNotifier.js +1133 -0
  557. package/src/lib/updateNotifierWorker.js +9 -0
@@ -0,0 +1,1133 @@
1
+ const { assertPluginParent, assertStateParent, assertManagedDirectory } = require("./hermesDiscovery");
2
+ const fs = require("node:fs");
3
+ const https = require("node:https");
4
+ const path = require("node:path");
5
+ const crypto = require("node:crypto");
6
+ const { spawn, spawnSync } = require("node:child_process");
7
+ const { writeFileAtomic } = require("./files");
8
+ const { defaultHermesHome } = require("./hermesDiscovery");
9
+
10
+ const PACKAGE_NAME = "@litfamily/lithermes";
11
+ const REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
12
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
13
+ const MAX_RESPONSE_BYTES = 64 * 1024;
14
+ const REQUEST_TIMEOUT_MS = 3000;
15
+ const UPDATE_LOCK_STALE_MS = 30 * 1000;
16
+ const OWNER_PATTERN = /^[a-f0-9]{32}$/;
17
+ const AUTO_UPDATE_TIMEOUT_MS = 30 * 1000;
18
+ const AUTO_UPDATE_LOCK_STALE_MS = 2 * AUTO_UPDATE_TIMEOUT_MS;
19
+ const AUTO_UPDATE_LOCK_NAME = "auto-update.lock";
20
+ const AUTO_UPDATE_JOURNAL_NAME = "auto-update-journal.json";
21
+ const AUTO_UPDATE_RECEIPT_NAME = "auto-update-receipt.json";
22
+ const AUTO_UPDATE_GUARD_ENV = "LITHERMES_AUTO_UPDATE_RUNNING";
23
+ const AUTO_UPDATE_TRIGGER_COMMANDS = new Set(["install", "check", "doctor"]);
24
+ const AUTO_UPDATE_INERT_COMMANDS = new Set(["help", "--help", "-h", "version", "--version", "-v", "uninstall", "hud"]);
25
+
26
+ function parseStableSemver(value) {
27
+ if (typeof value !== "string") return null;
28
+ const match = value.match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/);
29
+ if (!match) return null;
30
+ const parts = match.slice(1).map(Number);
31
+ return parts.every(Number.isSafeInteger) ? parts : null;
32
+ }
33
+
34
+ function compareStableSemver(left, right) {
35
+ const a = parseStableSemver(left);
36
+ const b = parseStableSemver(right);
37
+ if (!a || !b) return null;
38
+ for (let index = 0; index < a.length; index += 1) {
39
+ if (a[index] !== b[index]) return a[index] > b[index] ? 1 : -1;
40
+ }
41
+ return 0;
42
+ }
43
+
44
+ function validTimestamp(value, now = Date.now()) {
45
+ if (typeof value !== "string") return false;
46
+ const timestamp = Date.parse(value);
47
+ if (!Number.isFinite(timestamp) || timestamp > now) return false;
48
+ return new Date(timestamp).toISOString() === value;
49
+ }
50
+
51
+ function parseUpdateCache(text, { now = Date.now() } = {}) {
52
+ try {
53
+ const value = JSON.parse(String(text));
54
+ if (!value || Array.isArray(value) || typeof value !== "object") return null;
55
+ if (value.schemaVersion !== 1 || value.packageName !== PACKAGE_NAME || !validTimestamp(value.attemptedAt, now)) return null;
56
+ const parsed = {
57
+ schemaVersion: 1,
58
+ packageName: PACKAGE_NAME,
59
+ attemptedAt: value.attemptedAt,
60
+ };
61
+ if (value.attemptOwner !== undefined) {
62
+ if (typeof value.attemptOwner !== "string" || !OWNER_PATTERN.test(value.attemptOwner)) return null;
63
+ parsed.attemptOwner = value.attemptOwner;
64
+ }
65
+ const hasResult = value.checkedAt !== undefined || value.latestVersion !== undefined;
66
+ if (hasResult) {
67
+ if (!validTimestamp(value.checkedAt, now) || !parseStableSemver(value.latestVersion)) return null;
68
+ parsed.checkedAt = value.checkedAt;
69
+ parsed.latestVersion = value.latestVersion;
70
+ }
71
+ return parsed;
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+
77
+ function readUpdateCache(cachePath, { readFileSync = fs.readFileSync, now = Date.now() } = {}) {
78
+ let fd;
79
+ try {
80
+ const home = path.dirname(path.dirname(cachePath));
81
+ const state = assertStateParent(home);
82
+ const before = fs.lstatSync(cachePath, { throwIfNoEntry: false });
83
+ if (!before?.isFile()) return null;
84
+ fd = fs.openSync(cachePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0) | (fs.constants.O_NONBLOCK || 0));
85
+ const opened = fs.fstatSync(fd);
86
+ if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino) return null;
87
+ assertStateParent(home, state);
88
+ const text = readFileSync(fd, "utf8");
89
+ assertStateParent(home, state);
90
+ const after = fs.lstatSync(cachePath, { throwIfNoEntry: false });
91
+ if (!after?.isFile() || after.dev !== before.dev || after.ino !== before.ino) return null;
92
+ if (Buffer.byteLength(String(text), "utf8") > MAX_RESPONSE_BYTES) return null;
93
+ return parseUpdateCache(text, { now });
94
+ } catch {
95
+ return null;
96
+ } finally {
97
+ if (fd !== undefined) fs.closeSync(fd);
98
+ }
99
+ }
100
+
101
+ function shouldRefreshCache(cache, now = Date.now()) {
102
+ if (!cache || !validTimestamp(cache.attemptedAt, now)) return true;
103
+ const attemptedAt = Date.parse(cache.attemptedAt);
104
+ return attemptedAt > now || now - attemptedAt >= CACHE_TTL_MS;
105
+ }
106
+
107
+ function shouldCheckForUpdates({
108
+ command,
109
+ flags = {},
110
+ env = {},
111
+ streams = {},
112
+ hermesHome,
113
+ existsSync = fs.existsSync,
114
+ isNodeRuntime = process.release?.name === "node" && !process.versions.bun,
115
+ }) {
116
+ if (!isNodeRuntime) return false;
117
+ if (!new Set(["install", "check", "doctor"]).has(command)) return false;
118
+ if (["offline", "json", "dry-run"].some((flag) => Object.prototype.hasOwnProperty.call(flags, flag))) return false;
119
+ if (["CI", "NO_UPDATE_NOTIFIER", "LITHERMES_NO_UPDATE_CHECK"].some((key) => Object.prototype.hasOwnProperty.call(env, key))) return false;
120
+ if (!streams.stdin?.isTTY || !streams.stdout?.isTTY || !streams.stderr?.isTTY) return false;
121
+ return typeof hermesHome === "string" && hermesHome.length > 0 && existsSync(hermesHome);
122
+ }
123
+
124
+ function acceptedJsonContentType(value) {
125
+ const contentType = Array.isArray(value) ? value[0] : value;
126
+ if (typeof contentType !== "string") return false;
127
+ const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();
128
+ return mediaType === "application/json" || /^application\/[a-z0-9!#$&^_.+-]+\+json$/.test(mediaType);
129
+ }
130
+
131
+ function parseRegistryResponse({ statusCode, headers = {}, body }) {
132
+ if (statusCode !== 200) throw new Error(`Unexpected npm registry status ${statusCode}`);
133
+ if (!acceptedJsonContentType(headers["content-type"])) throw new Error("Unexpected npm registry content type");
134
+ if (!Buffer.isBuffer(body)) throw new Error("Invalid npm registry response body");
135
+ if (body.length > MAX_RESPONSE_BYTES) throw new Error("npm registry response exceeds 64 KiB");
136
+ let value;
137
+ try {
138
+ value = JSON.parse(body.toString("utf8"));
139
+ } catch {
140
+ throw new Error("Invalid npm registry JSON body");
141
+ }
142
+ if (!value || Array.isArray(value) || value.name !== PACKAGE_NAME) throw new Error("Unexpected npm registry package name");
143
+ if (!parseStableSemver(value.version)) throw new Error("npm registry version is not a strict stable semver");
144
+ return value.version;
145
+ }
146
+
147
+ function fetchLatestVersion({
148
+ httpsGet = https.get,
149
+ setTimeoutFn = setTimeout,
150
+ clearTimeoutFn = clearTimeout,
151
+ } = {}) {
152
+ return new Promise((resolve, reject) => {
153
+ let request;
154
+ let timer;
155
+ let settled = false;
156
+ const finish = (error, value) => {
157
+ if (settled) return;
158
+ settled = true;
159
+ if (timer !== undefined) clearTimeoutFn(timer);
160
+ if (error) reject(error);
161
+ else resolve(value);
162
+ };
163
+
164
+ try {
165
+ request = httpsGet(REGISTRY_URL, {
166
+ headers: {
167
+ accept: "application/json",
168
+ "user-agent": `${PACKAGE_NAME}-update-check`,
169
+ },
170
+ }, (response) => {
171
+ const chunks = [];
172
+ let size = 0;
173
+ const contentLength = Number(response.headers?.["content-length"]);
174
+ if (Number.isFinite(contentLength) && contentLength > MAX_RESPONSE_BYTES) {
175
+ if (typeof response.resume === "function") response.resume();
176
+ finish(new Error("npm registry response exceeds 64 KiB"));
177
+ return;
178
+ }
179
+ response.on("data", (chunk) => {
180
+ if (settled) return;
181
+ const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
182
+ size += data.length;
183
+ if (size > MAX_RESPONSE_BYTES) {
184
+ finish(new Error("npm registry response exceeds 64 KiB"));
185
+ if (typeof response.destroy === "function") response.destroy();
186
+ return;
187
+ }
188
+ chunks.push(data);
189
+ });
190
+ response.once("error", (error) => finish(error));
191
+ response.once("end", () => {
192
+ if (settled) return;
193
+ try {
194
+ finish(null, parseRegistryResponse({
195
+ statusCode: response.statusCode,
196
+ headers: response.headers,
197
+ body: Buffer.concat(chunks, size),
198
+ }));
199
+ } catch (error) {
200
+ finish(error);
201
+ }
202
+ });
203
+ });
204
+ request.once("error", (error) => finish(error));
205
+ timer = setTimeoutFn(() => {
206
+ finish(new Error("npm update check timed out after 3 seconds"));
207
+ if (typeof request.destroy === "function") request.destroy();
208
+ }, REQUEST_TIMEOUT_MS);
209
+ } catch (error) {
210
+ finish(error);
211
+ }
212
+ });
213
+ }
214
+
215
+ function ensureCacheDirectory(cachePath, {
216
+ existsSync = fs.existsSync,
217
+ mkdirSync = fs.mkdirSync,
218
+ } = {}) {
219
+ const cacheDir = path.dirname(cachePath);
220
+ const hermesHome = path.dirname(cacheDir);
221
+ if (!existsSync(hermesHome)) throw new Error("Hermes home no longer exists");
222
+ const state = assertStateParent(hermesHome);
223
+ try {
224
+ mkdirSync(cacheDir, { recursive: false });
225
+ } catch (error) {
226
+ if (error.code !== "EEXIST") throw error;
227
+ }
228
+ assertStateParent(hermesHome, state || undefined);
229
+ return cacheDir;
230
+ }
231
+
232
+ function writeUpdateCache(cachePath, record, {
233
+ existsSync = fs.existsSync,
234
+ mkdirSync = fs.mkdirSync,
235
+ writeFileAtomicFn = writeFileAtomic,
236
+ } = {}) {
237
+ ensureCacheDirectory(cachePath, { existsSync, mkdirSync });
238
+ writeFileAtomicFn(cachePath, `${JSON.stringify(record, null, 2)}\n`, "utf8");
239
+ }
240
+
241
+ function generateOwner(randomBytes = crypto.randomBytes) {
242
+ return randomBytes(16).toString("hex");
243
+ }
244
+
245
+ function createOwnedLock(lockPath, owner, now, {
246
+ openSync = fs.openSync,
247
+ closeSync = fs.closeSync,
248
+ writeSync = fs.writeSync,
249
+ fsyncSync = fs.fsyncSync,
250
+ unlinkSync = fs.unlinkSync,
251
+ } = {}) {
252
+ const state = assertStateParent(path.dirname(path.dirname(lockPath)));
253
+ const checkState = () => assertStateParent(path.dirname(path.dirname(lockPath)), state);
254
+ let fd;
255
+ let opened;
256
+ try {
257
+ checkState();
258
+ fd = openSync(lockPath, "wx", 0o600);
259
+ opened = fs.fstatSync(fd);
260
+ } catch (error) {
261
+ if (error.code === "EEXIST") return false;
262
+ throw error;
263
+ }
264
+ try {
265
+ writeSync(fd, `${JSON.stringify({ owner, acquiredAt: new Date(now).toISOString() })}\n`, null, "utf8");
266
+ try {
267
+ fsyncSync(fd);
268
+ } catch {
269
+ // Exclusive creation is still effective where fsync is unavailable.
270
+ }
271
+ closeSync(fd);
272
+ fd = undefined;
273
+ checkState();
274
+ return true;
275
+ } catch (error) {
276
+ try {
277
+ closeSync(fd);
278
+ } catch {
279
+ // Preserve the original lock-write error.
280
+ }
281
+ try {
282
+ checkState();
283
+ const current = fs.lstatSync(lockPath, { throwIfNoEntry: false });
284
+ if (current?.isFile() && opened && current.dev === opened.dev && current.ino === opened.ino) unlinkSync(lockPath);
285
+ } catch {
286
+ // Callers fail closed if the incomplete lock cannot be removed.
287
+ }
288
+ throw error;
289
+ }
290
+ }
291
+
292
+ function readOwnedLock(lockPath, {
293
+ openSync = fs.openSync,
294
+ closeSync = fs.closeSync,
295
+ readFileSync = fs.readFileSync,
296
+ fstatSync = fs.fstatSync,
297
+ } = {}) {
298
+ let fd;
299
+ try {
300
+ const before = fs.lstatSync(lockPath, { throwIfNoEntry: false });
301
+ if (before && !before.isFile()) return null;
302
+ fd = openSync(lockPath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
303
+ const stat = fstatSync(fd);
304
+ if (!stat.isFile() || (before && (before.dev !== stat.dev || before.ino !== stat.ino))) throw new Error("Replaced update lock");
305
+ const text = String(readFileSync(fd, "utf8"));
306
+ let value = null;
307
+ try {
308
+ value = JSON.parse(text);
309
+ } catch {
310
+ value = null;
311
+ }
312
+ const owner = typeof value?.owner === "string" && OWNER_PATTERN.test(value.owner)
313
+ ? value.owner
314
+ : null;
315
+ const pid = Number.isInteger(value?.pid) && value.pid > 0 ? value.pid : null;
316
+ const acquiredAtMs = typeof value?.acquiredAt === "string" ? Date.parse(value.acquiredAt) : NaN;
317
+ const generation = owner || crypto.createHash("sha256")
318
+ .update(`${stat.dev}:${stat.ino}:${text}`)
319
+ .digest("hex")
320
+ .slice(0, 32);
321
+ closeSync(fd);
322
+ return { owner, pid, generation, mtimeMs: stat.mtimeMs, acquiredAtMs };
323
+ } catch {
324
+ if (fd !== undefined) {
325
+ try {
326
+ closeSync(fd);
327
+ } catch {
328
+ // Preserve the read failure.
329
+ }
330
+ }
331
+ return null;
332
+ }
333
+ }
334
+
335
+ function lockIsStale(lock, now) {
336
+ return Boolean(lock)
337
+ && Number.isFinite(lock.mtimeMs)
338
+ && lock.mtimeMs <= now
339
+ && now - lock.mtimeMs >= UPDATE_LOCK_STALE_MS;
340
+ }
341
+
342
+ function transitionPath(cacheDir) {
343
+ return path.join(cacheDir, "update-check.transition.lock");
344
+ }
345
+
346
+ function acquireTransitionMutex(cacheDir, now) {
347
+ try { assertStateParent(path.dirname(cacheDir)); } catch { return null; }
348
+ const mutexPath = transitionPath(cacheDir);
349
+ const owner = generateOwner();
350
+ try { return createOwnedLock(mutexPath, owner, now) ? owner : null; } catch { return null; }
351
+ }
352
+
353
+ function ownsTransitionMutex(cacheDir, owner, state) {
354
+ try { assertStateParent(path.dirname(cacheDir), state); } catch { return false; }
355
+ return readOwnedLock(transitionPath(cacheDir))?.owner === owner;
356
+ }
357
+
358
+ function releaseTransitionMutex(cacheDir, owner, state) {
359
+ if (!ownsTransitionMutex(cacheDir, owner, state)) return false;
360
+ const mutexPath = transitionPath(cacheDir);
361
+ const current = readOwnedLock(mutexPath);
362
+ if (!current || current.owner !== owner) return false;
363
+ try {
364
+ fs.unlinkSync(mutexPath);
365
+ return true;
366
+ } catch {
367
+ return false;
368
+ }
369
+ }
370
+
371
+ function removeAttemptLock(lockPath, owner, state) {
372
+ try { assertStateParent(path.dirname(path.dirname(lockPath)), state); } catch { return false; }
373
+ const current = readOwnedLock(lockPath);
374
+ if (!current || current.owner !== owner) return false;
375
+ try {
376
+ fs.unlinkSync(lockPath);
377
+ return true;
378
+ } catch {
379
+ return false;
380
+ }
381
+ }
382
+
383
+ function reserveUpdateAttempt(cachePath, {
384
+ now = Date.now,
385
+ readFileSync = fs.readFileSync,
386
+ existsSync = fs.existsSync,
387
+ mkdirSync = fs.mkdirSync,
388
+ writeUpdateCacheFn = writeUpdateCache,
389
+ } = {}) {
390
+ const nowMs = now();
391
+ let cacheDir;
392
+ try {
393
+ cacheDir = ensureCacheDirectory(cachePath, { existsSync, mkdirSync });
394
+ } catch {
395
+ return { reserved: false };
396
+ }
397
+ let state;
398
+ try { state = assertStateParent(path.dirname(cacheDir)); } catch { return { reserved: false }; }
399
+ const mutexOwner = acquireTransitionMutex(cacheDir, nowMs);
400
+ if (!mutexOwner) return { reserved: false };
401
+
402
+ try {
403
+ const cache = readUpdateCache(cachePath, { readFileSync, now: nowMs });
404
+ if (!shouldRefreshCache(cache, nowMs)) return { reserved: false, cache };
405
+ assertStateParent(path.dirname(cacheDir), state);
406
+ const lockPath = path.join(cacheDir, "update-check.lock");
407
+ const existingLock = readOwnedLock(lockPath);
408
+ if (existingLock) {
409
+ if (!lockIsStale(existingLock, nowMs)) return { reserved: false, cache };
410
+ const current = readOwnedLock(lockPath);
411
+ if (!current || current.generation !== existingLock.generation) return { reserved: false, cache };
412
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return { reserved: false, cache };
413
+ try {
414
+ fs.unlinkSync(lockPath);
415
+ } catch {
416
+ return { reserved: false, cache };
417
+ }
418
+ }
419
+ const owner = generateOwner();
420
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return { reserved: false, cache };
421
+ if (!createOwnedLock(lockPath, owner, nowMs)) return { reserved: false, cache };
422
+ const reservation = {
423
+ schemaVersion: 1,
424
+ packageName: PACKAGE_NAME,
425
+ attemptedAt: new Date(nowMs).toISOString(),
426
+ attemptOwner: owner,
427
+ };
428
+ if (cache?.latestVersion) {
429
+ reservation.checkedAt = cache.checkedAt;
430
+ reservation.latestVersion = cache.latestVersion;
431
+ }
432
+ try {
433
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return { reserved: false, cache };
434
+ writeUpdateCacheFn(cachePath, reservation);
435
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return { reserved: false, cache };
436
+ } catch {
437
+ if (ownsTransitionMutex(cacheDir, mutexOwner, state)) removeAttemptLock(lockPath, owner, state);
438
+ return { reserved: false, cache };
439
+ }
440
+ return { reserved: true, owner, cache: reservation };
441
+ } catch {
442
+ return { reserved: false };
443
+ } finally {
444
+ releaseTransitionMutex(cacheDir, mutexOwner, state);
445
+ }
446
+ }
447
+
448
+ function completeUpdateAttempt(cachePath, owner, {
449
+ latestVersion = null,
450
+ now = Date.now,
451
+ readFileSync = fs.readFileSync,
452
+ writeUpdateCacheFn = writeUpdateCache,
453
+ } = {}) {
454
+ if (typeof owner !== "string" || !OWNER_PATTERN.test(owner)) return false;
455
+ const nowMs = now();
456
+ const cacheDir = path.dirname(cachePath);
457
+ let state;
458
+ try { state = assertStateParent(path.dirname(cacheDir)); } catch { return false; }
459
+ const mutexOwner = acquireTransitionMutex(cacheDir, nowMs);
460
+ if (!mutexOwner) return false;
461
+ try {
462
+ const cache = readUpdateCache(cachePath, { readFileSync, now: nowMs });
463
+ assertStateParent(path.dirname(cacheDir), state);
464
+ const lockPath = path.join(cacheDir, "update-check.lock");
465
+ const lock = readOwnedLock(lockPath);
466
+ if (!cache || cache.attemptOwner !== owner || lock?.owner !== owner) return false;
467
+ if (latestVersion !== null) {
468
+ if (!parseStableSemver(latestVersion)) return false;
469
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return false;
470
+ writeUpdateCacheFn(cachePath, {
471
+ schemaVersion: 1,
472
+ packageName: PACKAGE_NAME,
473
+ attemptedAt: cache.attemptedAt,
474
+ attemptOwner: owner,
475
+ checkedAt: new Date(nowMs).toISOString(),
476
+ latestVersion,
477
+ });
478
+ }
479
+ if (!ownsTransitionMutex(cacheDir, mutexOwner, state)) return false;
480
+ return removeAttemptLock(lockPath, owner, state);
481
+ } catch {
482
+ return false;
483
+ } finally {
484
+ releaseTransitionMutex(cacheDir, mutexOwner, state);
485
+ }
486
+ }
487
+
488
+ async function refreshUpdateCache(cachePath, {
489
+ attemptOwner = null,
490
+ now = Date.now,
491
+ readFileSync = fs.readFileSync,
492
+ writeUpdateCacheFn = writeUpdateCache,
493
+ fetchLatestVersionFn = fetchLatestVersion,
494
+ } = {}) {
495
+ const startedAt = now();
496
+ let state;
497
+ try { state = assertStateParent(path.dirname(path.dirname(cachePath))); } catch { return false; }
498
+ const reservation = readUpdateCache(cachePath, { readFileSync, now: startedAt });
499
+ const owner = attemptOwner || reservation?.attemptOwner;
500
+ if (!reservation || !owner || reservation.attemptOwner !== owner) return false;
501
+ try {
502
+ const latestVersion = await fetchLatestVersionFn();
503
+ assertStateParent(path.dirname(path.dirname(cachePath)), state);
504
+ return completeUpdateAttempt(cachePath, owner, {
505
+ latestVersion,
506
+ now,
507
+ readFileSync,
508
+ writeUpdateCacheFn,
509
+ });
510
+ } catch {
511
+ try { assertStateParent(path.dirname(path.dirname(cachePath)), state); } catch { return false; }
512
+ completeUpdateAttempt(cachePath, owner, { now, readFileSync, writeUpdateCacheFn });
513
+ return false;
514
+ }
515
+ }
516
+
517
+ function formatUpdateNotice(currentVersion, latestVersion) {
518
+ return [
519
+ `LitHermes update available: ${currentVersion} → ${latestVersion}`,
520
+ `Run exactly: npx --yes --package ${PACKAGE_NAME}@${latestVersion} -- lithermes install --yes --no-hud`,
521
+ "Then restart the Hermes CLI and any Hermes gateways.",
522
+ ].join("\n");
523
+ }
524
+
525
+ function workerEnvironment(env) {
526
+ const workerEnv = {};
527
+ if (typeof env?.NODE_EXTRA_CA_CERTS === "string" && env.NODE_EXTRA_CA_CERTS.length > 0) {
528
+ workerEnv.NODE_EXTRA_CA_CERTS = env.NODE_EXTRA_CA_CERTS;
529
+ }
530
+ return workerEnv;
531
+ }
532
+
533
+ function scheduleUpdateCheck({ command, flags = {}, currentVersion }, {
534
+ env = process.env,
535
+ streams = { stdin: process.stdin, stdout: process.stdout, stderr: process.stderr },
536
+ resolveHermesHome = (inputFlags) => defaultHermesHome(inputFlags),
537
+ existsSync = fs.existsSync,
538
+ readFileSync = fs.readFileSync,
539
+ now = Date.now,
540
+ spawn: spawnFn = spawn,
541
+ reserveUpdateAttemptFn = reserveUpdateAttempt,
542
+ } = {}) {
543
+ const idle = { notified: false, refreshScheduled: false };
544
+ try {
545
+ const hermesHome = resolveHermesHome(flags);
546
+ if (!shouldCheckForUpdates({ command, flags, env, streams, hermesHome, existsSync })) return idle;
547
+ const state = assertStateParent(hermesHome);
548
+ const cachePath = path.join(hermesHome, "lithermes", "update-check.json");
549
+ const nowMs = now();
550
+ const cache = readUpdateCache(cachePath, { readFileSync, now: nowMs });
551
+ let notified = false;
552
+ if (cache?.latestVersion && compareStableSemver(cache.latestVersion, currentVersion) === 1) {
553
+ streams.stderr.write(`${formatUpdateNotice(currentVersion, cache.latestVersion)}\n`);
554
+ notified = true;
555
+ }
556
+ if (!shouldRefreshCache(cache, nowMs)) return { notified, refreshScheduled: false };
557
+ const reservation = reserveUpdateAttemptFn(cachePath, { now: () => nowMs });
558
+ if (!reservation?.reserved || !OWNER_PATTERN.test(reservation.owner || "")) {
559
+ return { notified, refreshScheduled: false };
560
+ }
561
+ assertStateParent(hermesHome, state || undefined);
562
+ const worker = path.join(__dirname, "updateNotifierWorker.js");
563
+ try {
564
+ const child = spawnFn(process.execPath, [worker, cachePath, reservation.owner], {
565
+ detached: true,
566
+ env: workerEnvironment(env),
567
+ stdio: "ignore",
568
+ windowsHide: true,
569
+ });
570
+ if (!child || typeof child.once !== "function" || typeof child.unref !== "function") {
571
+ return { notified, refreshScheduled: false };
572
+ }
573
+ child.once("error", () => {});
574
+ child.unref();
575
+ return { notified, refreshScheduled: true };
576
+ } catch {
577
+ return { notified, refreshScheduled: false };
578
+ }
579
+ } catch {
580
+ return idle;
581
+ }
582
+ }
583
+
584
+ // Automatic updates intentionally live beside the advisory notifier, but use a
585
+ // different lock, journal, and transaction root. The advisory path above is
586
+ // cache-only and detached; this path is a bounded foreground lifecycle barrier
587
+ // that may replace an installed payload only after a truthful doctor pass.
588
+ function hasOwn(value, key) {
589
+ return Boolean(value) && Object.prototype.hasOwnProperty.call(value, key);
590
+ }
591
+
592
+ function isInteractiveStreams(streams = {}) {
593
+ return Boolean(streams.stdin?.isTTY && streams.stdout?.isTTY && streams.stderr?.isTTY);
594
+ }
595
+
596
+ function shouldAutoUpdate({
597
+ trigger = "cli",
598
+ command,
599
+ flags = {},
600
+ env = {},
601
+ streams = {},
602
+ hermesHome,
603
+ existsSync = fs.existsSync,
604
+ isNodeRuntime = process.release?.name === "node" && !process.versions.bun,
605
+ platform = "cli",
606
+ isFirstTurn,
607
+ isInteractive,
608
+ } = {}) {
609
+ if (!isNodeRuntime) return false;
610
+ if (typeof command === "string" && AUTO_UPDATE_INERT_COMMANDS.has(command.trim().toLowerCase())) return false;
611
+ if (hasOwn(env, "CI") || hasOwn(env, "NO_UPDATE_NOTIFIER") || hasOwn(env, "LITHERMES_NO_UPDATE_CHECK")) return false;
612
+ if (hasOwn(env, "LITHERMES_NO_AUTO_UPDATE") || hasOwn(env, AUTO_UPDATE_GUARD_ENV)) return false;
613
+ if (hasOwn(flags, "no-auto-update") || hasOwn(flags, "offline") || hasOwn(flags, "json") || hasOwn(flags, "dry-run")) return false;
614
+ if (trigger === "pre_llm_call") {
615
+ if (platform === "subagent" || platform === "delegate" || platform === "worker") return false;
616
+ if (isFirstTurn !== true) return false;
617
+ } else if (!AUTO_UPDATE_TRIGGER_COMMANDS.has(command)) {
618
+ return false;
619
+ }
620
+ if (isInteractive === false || (isInteractive !== true && !isInteractiveStreams(streams))) return false;
621
+ return typeof hermesHome === "string" && path.isAbsolute(hermesHome) && hermesHome.length > 1 && existsSync(hermesHome);
622
+ }
623
+
624
+ function buildAutoUpdateArgv({ latestVersion, hermesHome, packageName = PACKAGE_NAME } = {}) {
625
+ if (!parseStableSemver(latestVersion)) throw new Error("automatic update requires an exact stable semver");
626
+ if (typeof packageName !== "string" || packageName.length > 214 || packageName.trim() !== packageName || !/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u.test(packageName)) {
627
+ throw new Error("automatic update package name is invalid");
628
+ }
629
+ if (typeof hermesHome !== "string" || !path.isAbsolute(hermesHome)) {
630
+ throw new Error("automatic update requires a resolved absolute Hermes home");
631
+ }
632
+ return [
633
+ "--yes",
634
+ "--package",
635
+ `${packageName}@${latestVersion}`,
636
+ "--",
637
+ "lithermes",
638
+ "install",
639
+ "--yes",
640
+ "--no-hud",
641
+ "--no-style",
642
+ "--no-patch-installed-hermes",
643
+ "--hermes-home",
644
+ hermesHome,
645
+ ];
646
+ }
647
+
648
+ function sanitizeNpmEnvironment(source = process.env, { hermesHome } = {}) {
649
+ const safe = {};
650
+ // Keep only process plumbing needed to resolve npx and write temporary
651
+ // files. In particular, do not inherit npm config, proxies, NODE_OPTIONS,
652
+ // or any token-bearing environment key into the child installer.
653
+ for (const key of ["PATH", "HOME", "USERPROFILE", "TMPDIR", "TEMP", "TMP", "LANG", "LC_ALL", "LC_CTYPE", "TERM"]) {
654
+ if (typeof source?.[key] === "string" && source[key].length > 0) safe[key] = source[key];
655
+ }
656
+ if (typeof source?.NODE_EXTRA_CA_CERTS === "string" && source.NODE_EXTRA_CA_CERTS.length > 0) {
657
+ safe.NODE_EXTRA_CA_CERTS = source.NODE_EXTRA_CA_CERTS;
658
+ }
659
+ if (typeof hermesHome !== "string" || !path.isAbsolute(hermesHome)) {
660
+ throw new Error("automatic update requires a resolved absolute Hermes home");
661
+ }
662
+ safe.HERMES_HOME = hermesHome;
663
+ safe[AUTO_UPDATE_GUARD_ENV] = "1";
664
+ return safe;
665
+ }
666
+
667
+ function autoUpdatePaths(hermesHome) {
668
+ if (typeof hermesHome !== "string" || !path.isAbsolute(hermesHome)) {
669
+ throw new Error("automatic update requires a resolved absolute Hermes home");
670
+ }
671
+ const stateDir = path.join(hermesHome, "lithermes");
672
+ return {
673
+ stateDir,
674
+ lockPath: path.join(stateDir, AUTO_UPDATE_LOCK_NAME),
675
+ journalPath: path.join(stateDir, AUTO_UPDATE_JOURNAL_NAME),
676
+ receiptPath: path.join(stateDir, AUTO_UPDATE_RECEIPT_NAME),
677
+ transactionRoot: path.join(stateDir, "auto-update"),
678
+ pluginPath: path.join(hermesHome, "plugins", "lithermes"),
679
+ configPath: path.join(hermesHome, "config.yaml"),
680
+ manifestPath: path.join(stateDir, "install-manifest.json"),
681
+ skinsPath: path.join(hermesHome, "skins"),
682
+ };
683
+ }
684
+
685
+ function autoUpdateTimestamp(now = Date.now) {
686
+ return new Date(now()).toISOString();
687
+ }
688
+
689
+ function writeJsonAtomic(filePath, value) {
690
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
691
+ writeFileAtomic(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
692
+ }
693
+
694
+ function removePath(target) {
695
+ try {
696
+ const stat = fs.lstatSync(target);
697
+ if (stat.isDirectory() && !stat.isSymbolicLink()) fs.rmSync(target, { recursive: true, force: true });
698
+ else fs.unlinkSync(target);
699
+ } catch (error) {
700
+ if (error.code !== "ENOENT") throw error;
701
+ }
702
+ }
703
+
704
+ function copyPathPreservingLinks(source, target) {
705
+ const stat = fs.lstatSync(source);
706
+ if (stat.isSymbolicLink()) {
707
+ fs.mkdirSync(path.dirname(target), { recursive: true });
708
+ fs.symlinkSync(fs.readlinkSync(source), target);
709
+ return;
710
+ }
711
+ if (stat.isDirectory()) {
712
+ fs.mkdirSync(target, { recursive: true });
713
+ for (const entry of fs.readdirSync(source)) {
714
+ copyPathPreservingLinks(path.join(source, entry), path.join(target, entry));
715
+ }
716
+ return;
717
+ }
718
+ fs.mkdirSync(path.dirname(target), { recursive: true });
719
+ fs.copyFileSync(source, target);
720
+ }
721
+
722
+ function snapshotTargets(paths, transactionRoot, checkState) {
723
+ checkState();
724
+ const backupRoot = path.join(transactionRoot, "backup");
725
+ fs.mkdirSync(backupRoot, { mode: 0o700 });
726
+ const backupIdentity = assertManagedDirectory(backupRoot);
727
+ const entries = [];
728
+ for (const [name, target] of Object.entries(paths)) {
729
+ if (["stateDir", "lockPath", "journalPath", "receiptPath", "transactionRoot"].includes(name)) continue;
730
+ const exists = fs.existsSync(target) || (() => {
731
+ try { fs.lstatSync(target); return true; } catch { return false; }
732
+ })();
733
+ const backup = path.join(backupRoot, name);
734
+ checkState();
735
+ assertManagedDirectory(backupRoot, backupIdentity);
736
+ if (exists) copyPathPreservingLinks(target, backup);
737
+ entries.push({ name, target, backup, existed: exists });
738
+ }
739
+ checkState();
740
+ assertManagedDirectory(backupRoot, backupIdentity);
741
+ return { backupRoot, backupIdentity, entries };
742
+ }
743
+
744
+ function restoreSnapshot(snapshot, hermesHome, checkState) {
745
+ const failures = [];
746
+ for (const entry of [...snapshot.entries].reverse()) {
747
+ try {
748
+ checkState();
749
+ assertManagedDirectory(snapshot.backupRoot, snapshot.backupIdentity);
750
+ if (entry.name === "pluginPath") assertPluginParent(hermesHome);
751
+ removePath(entry.target);
752
+ checkState();
753
+ assertManagedDirectory(snapshot.backupRoot, snapshot.backupIdentity);
754
+ if (entry.existed) copyPathPreservingLinks(entry.backup, entry.target);
755
+ } catch (error) {
756
+ failures.push(`${entry.name}: ${error.message}`);
757
+ }
758
+ }
759
+ return failures.length ? { status: "failed", failures } : { status: "restored" };
760
+ }
761
+
762
+ function acquireAutoUpdateLock(lockPath, now = Date.now, checkState) {
763
+ checkState();
764
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true });
765
+ for (let attempt = 0; attempt < 2; attempt += 1) {
766
+ const owner = generateOwner();
767
+ let fd;
768
+ let identity;
769
+ try {
770
+ checkState();
771
+ fd = fs.openSync(lockPath, "wx", 0o600);
772
+ identity = fs.fstatSync(fd);
773
+ fs.writeFileSync(fd, `${JSON.stringify({ owner, pid: process.pid, acquiredAt: autoUpdateTimestamp(now) })}\n`);
774
+ try { fs.fsyncSync(fd); } catch {}
775
+ return { fd, owner, identity };
776
+ } catch (error) {
777
+ if (fd !== undefined) {
778
+ try {
779
+ checkState();
780
+ const current = fs.lstatSync(lockPath, { throwIfNoEntry: false });
781
+ if (current?.isFile() && identity && current.dev === identity.dev && current.ino === identity.ino) fs.unlinkSync(lockPath);
782
+ } catch {}
783
+ try { fs.closeSync(fd); } catch {}
784
+ }
785
+ if (error.code !== "EEXIST") throw error;
786
+ const existing = readOwnedLock(lockPath);
787
+ const acquiredAt = Number.isFinite(existing?.acquiredAtMs) ? existing.acquiredAtMs : existing?.mtimeMs;
788
+ const currentNow = now();
789
+ const stale = Boolean(existing && Number.isFinite(acquiredAt)
790
+ && acquiredAt <= currentNow
791
+ && currentNow - acquiredAt >= AUTO_UPDATE_LOCK_STALE_MS);
792
+ if (!stale) return null;
793
+ if (existing.pid !== null) {
794
+ try {
795
+ process.kill(existing.pid, 0);
796
+ return null;
797
+ } catch (probeError) {
798
+ if (probeError?.code !== "ESRCH") return null;
799
+ }
800
+ }
801
+ // Rename is the atomic stale-owner takeover. Never unlink the path
802
+ // directly: a concurrent process may have replaced it with a fresh lock.
803
+ const tombstone = `${lockPath}.stale-${generateOwner()}`;
804
+ try {
805
+ checkState();
806
+ fs.renameSync(lockPath, tombstone);
807
+ } catch {
808
+ return null;
809
+ }
810
+ try { checkState(); fs.unlinkSync(tombstone); } catch {}
811
+ }
812
+ }
813
+ return null;
814
+ }
815
+
816
+ function releaseAutoUpdateLock(lockPath, lock, checkState) {
817
+ if (!lock) return;
818
+ try {
819
+ checkState();
820
+ const current = readOwnedLock(lockPath);
821
+ const identity = fs.lstatSync(lockPath, { throwIfNoEntry: false });
822
+ if (current?.owner === lock.owner && identity?.isFile()
823
+ && identity.dev === lock.identity.dev && identity.ino === lock.identity.ino) fs.unlinkSync(lockPath);
824
+ } catch {} finally {
825
+ try { if (lock.fd !== undefined) fs.closeSync(lock.fd); } catch {}
826
+ }
827
+ }
828
+
829
+ function doctorPassed(result) {
830
+ // Do not infer health from a human-readable string: an untrusted or stale
831
+ // output containing "PASS" is not proof that the installed payload loaded.
832
+ return Boolean(result && typeof result === "object" && result.ok === true);
833
+ }
834
+
835
+ function rollbackFailure(reason, rollback) {
836
+ if (rollback?.status !== "failed") return { reason, extra: {} };
837
+ return {
838
+ reason: "automatic update rollback failed; installed profile state is unknown",
839
+ extra: { state: "unknown", rollbackFailure: true },
840
+ };
841
+ }
842
+
843
+ function safeNpmFailure(result) {
844
+ if (!result || result.signal) return result?.signal ? `npm installer interrupted (${result.signal})` : "npm installer returned no status";
845
+ if (result.error?.code === "ETIMEDOUT") return "npm installer timed out";
846
+ return `npm installer exited with status ${result.status}`;
847
+ }
848
+
849
+ function runAutomaticUpdate({
850
+ currentVersion,
851
+ latestVersion = null,
852
+ hermesHome,
853
+ env = process.env,
854
+ now = Date.now,
855
+ fetchLatestVersionFn = fetchLatestVersion,
856
+ spawnSync: spawnSyncFn = spawnSync,
857
+ doctor,
858
+ packageName = PACKAGE_NAME,
859
+ timeoutMs = AUTO_UPDATE_TIMEOUT_MS,
860
+ cwd = process.cwd(),
861
+ } = {}) {
862
+ let paths;
863
+ let stateIdentity;
864
+ let transactionParentIdentity;
865
+ try {
866
+ paths = autoUpdatePaths(hermesHome);
867
+ if (!fs.existsSync(hermesHome)) return { status: "skipped", reason: "missing-hermes-home" };
868
+ stateIdentity = assertStateParent(hermesHome);
869
+ transactionParentIdentity = assertManagedDirectory(paths.transactionRoot);
870
+ if (!parseStableSemver(currentVersion)) return { status: "failed", reason: "invalid-current-version" };
871
+ } catch (error) {
872
+ return { status: "failed", reason: error.message, rollback: { status: "not-started" } };
873
+ }
874
+
875
+ // The fetch is intentionally foreground and bounded by fetchLatestVersion's
876
+ // three-second request deadline. The npm installer itself is bounded below.
877
+ const finishWithoutInstall = (status, reason, extra = {}) => ({
878
+ status,
879
+ reason,
880
+ hermesHome,
881
+ ...extra,
882
+ });
883
+ let targetVersion = latestVersion;
884
+ if (targetVersion === null || targetVersion === undefined) {
885
+ try {
886
+ // fetchLatestVersion is asynchronous by design. Keep this API thenable
887
+ // by returning a promise from the small async adapter below; callers that
888
+ // provide latestVersion (all transaction tests and deterministic callers)
889
+ // remain synchronous.
890
+ return runAutomaticUpdateAsync({
891
+ currentVersion,
892
+ hermesHome,
893
+ env,
894
+ now,
895
+ fetchLatestVersionFn,
896
+ spawnSyncFn,
897
+ doctor,
898
+ packageName,
899
+ timeoutMs,
900
+ cwd,
901
+ paths,
902
+ stateIdentity,
903
+ transactionParentIdentity,
904
+ });
905
+ } catch (error) {
906
+ return finishWithoutInstall("failed", "update-check-failed");
907
+ }
908
+ }
909
+ if (!parseStableSemver(targetVersion)) return finishWithoutInstall("failed", "invalid-latest-version");
910
+ const comparison = compareStableSemver(targetVersion, currentVersion);
911
+ if (comparison === null) return finishWithoutInstall("failed", "invalid-version-comparison");
912
+ if (comparison <= 0) return finishWithoutInstall("current", "already-current", { currentVersion, latestVersion: targetVersion });
913
+ return performAutomaticUpdateTransaction({
914
+ currentVersion,
915
+ latestVersion: targetVersion,
916
+ hermesHome,
917
+ env,
918
+ now,
919
+ spawnSyncFn,
920
+ doctor,
921
+ packageName,
922
+ timeoutMs,
923
+ cwd,
924
+ paths,
925
+ stateIdentity,
926
+ transactionParentIdentity,
927
+ });
928
+ }
929
+
930
+ async function runAutomaticUpdateAsync(options) {
931
+ let latestVersion;
932
+ try {
933
+ latestVersion = await options.fetchLatestVersionFn();
934
+ assertStateParent(options.hermesHome, options.stateIdentity);
935
+ } catch {
936
+ return { status: "failed", reason: "update-check-failed", hermesHome: options.hermesHome };
937
+ }
938
+ if (!parseStableSemver(latestVersion)) return { status: "failed", reason: "invalid-latest-version", hermesHome: options.hermesHome };
939
+ const comparison = compareStableSemver(latestVersion, options.currentVersion);
940
+ if (comparison === null) return { status: "failed", reason: "invalid-version-comparison", hermesHome: options.hermesHome };
941
+ if (comparison <= 0) return { status: "current", reason: "already-current", currentVersion: options.currentVersion, latestVersion, hermesHome: options.hermesHome };
942
+ return performAutomaticUpdateTransaction({ ...options, latestVersion });
943
+ }
944
+
945
+ function performAutomaticUpdateTransaction({
946
+ currentVersion,
947
+ latestVersion,
948
+ hermesHome,
949
+ env = process.env,
950
+ now = Date.now,
951
+ spawnSyncFn = spawnSync,
952
+ doctor,
953
+ packageName = PACKAGE_NAME,
954
+ timeoutMs = AUTO_UPDATE_TIMEOUT_MS,
955
+ cwd = process.cwd(),
956
+ paths = autoUpdatePaths(hermesHome),
957
+ stateIdentity,
958
+ transactionParentIdentity,
959
+ } = {}) {
960
+ const startedAt = autoUpdateTimestamp(now);
961
+ let state;
962
+ try {
963
+ assertStateParent(hermesHome, stateIdentity);
964
+ assertManagedDirectory(paths.transactionRoot, transactionParentIdentity);
965
+ fs.mkdirSync(paths.stateDir, { recursive: true });
966
+ state = assertStateParent(hermesHome, stateIdentity || undefined);
967
+ } catch (error) {
968
+ return { status: "failed", reason: error.message, rollback: { status: "not-started" } };
969
+ }
970
+ let transactionParent = transactionParentIdentity;
971
+ let transactionIdentity;
972
+ const checkState = () => {
973
+ assertStateParent(hermesHome, state);
974
+ assertManagedDirectory(paths.transactionRoot, transactionParent);
975
+ if (transactionIdentity) assertManagedDirectory(transactionRoot, transactionIdentity);
976
+ };
977
+ let lock;
978
+ try { lock = acquireAutoUpdateLock(paths.lockPath, now, checkState); } catch (error) {
979
+ return { status: "failed", reason: error.message, rollback: { status: "not-started" } };
980
+ }
981
+ if (!lock) return { status: "skipped", reason: "auto-update-lock-held", hermesHome };
982
+ const transactionId = `${Date.now().toString(36)}-${crypto.randomBytes(6).toString("hex")}`;
983
+ const transactionRoot = path.join(paths.transactionRoot, transactionId);
984
+ const journalPath = paths.journalPath;
985
+ const receiptPath = paths.receiptPath;
986
+ let snapshot;
987
+ const journal = {
988
+ schemaVersion: 1,
989
+ packageName,
990
+ transactionId,
991
+ currentVersion,
992
+ targetVersion: latestVersion,
993
+ hermesHome,
994
+ transactionRoot,
995
+ startedAt,
996
+ stage: "created",
997
+ };
998
+ const writeJournal = (stage, extra = {}) => {
999
+ journal.stage = stage;
1000
+ Object.assign(journal, extra);
1001
+ checkState();
1002
+ writeJsonAtomic(journalPath, journal);
1003
+ checkState();
1004
+ writeJsonAtomic(path.join(transactionRoot, "journal.json"), journal);
1005
+ };
1006
+ const finish = (status, reason, rollback, extra = {}) => {
1007
+ const receipt = {
1008
+ schemaVersion: 1,
1009
+ packageName,
1010
+ transactionId,
1011
+ currentVersion,
1012
+ targetVersion: latestVersion,
1013
+ hermesHome,
1014
+ status,
1015
+ reason,
1016
+ startedAt,
1017
+ completedAt: autoUpdateTimestamp(now),
1018
+ rollback,
1019
+ ...extra,
1020
+ };
1021
+ let receiptWritten = false;
1022
+ try {
1023
+ checkState();
1024
+ writeJsonAtomic(receiptPath, receipt);
1025
+ checkState();
1026
+ receiptWritten = true;
1027
+ } catch (error) {
1028
+ if (status === "updated") {
1029
+ receipt.status = "failed";
1030
+ receipt.reason = `Automatic update receipt could not be confirmed: ${error.message}`;
1031
+ receipt.state = "unknown";
1032
+ }
1033
+ }
1034
+ return { ...receipt, receiptPath, journalPath, receiptWritten, transactionRoot,
1035
+ stateDirectoryIdentity: { dev: state.dev, ino: state.ino } };
1036
+ };
1037
+
1038
+ try {
1039
+ checkState();
1040
+ fs.mkdirSync(paths.transactionRoot, { recursive: true, mode: 0o700 });
1041
+ assertStateParent(hermesHome, state);
1042
+ transactionParent = assertManagedDirectory(paths.transactionRoot, transactionParent || undefined);
1043
+ fs.mkdirSync(transactionRoot, { mode: 0o700 });
1044
+ transactionIdentity = assertManagedDirectory(transactionRoot);
1045
+ writeJournal("prepared");
1046
+ assertPluginParent(hermesHome);
1047
+ checkState();
1048
+ snapshot = snapshotTargets(paths, transactionRoot, checkState);
1049
+ writeJournal("backup-created", { backupRoot: snapshot.backupRoot });
1050
+ writeJournal("installing");
1051
+ const argv = buildAutoUpdateArgv({ latestVersion, hermesHome, packageName });
1052
+ checkState();
1053
+ const result = spawnSyncFn("npx", argv, {
1054
+ cwd,
1055
+ env: sanitizeNpmEnvironment(env, { hermesHome }),
1056
+ encoding: "utf8",
1057
+ timeout: timeoutMs,
1058
+ maxBuffer: MAX_RESPONSE_BYTES,
1059
+ stdio: ["ignore", "pipe", "pipe"],
1060
+ windowsHide: true,
1061
+ });
1062
+ if (!result || result.status !== 0 || result.signal || result.error) {
1063
+ const reason = safeNpmFailure(result);
1064
+ const rollback = restoreSnapshot(snapshot, hermesHome, checkState);
1065
+ const outcome = rollbackFailure(reason, rollback);
1066
+ writeJournal("rolled-back", { reason: outcome.reason, rollback, ...(outcome.extra.state ? { state: outcome.extra.state } : {}) });
1067
+ return finish("failed", outcome.reason, rollback, outcome.extra);
1068
+ }
1069
+ writeJournal("installed");
1070
+ writeJournal("doctor");
1071
+ let doctorResult;
1072
+ try {
1073
+ const doctorFn = doctor || ((flags) => require("./check").doctorLitHermes(flags));
1074
+ doctorResult = doctorFn({ offline: true, "hermes-home": hermesHome });
1075
+ } catch (error) {
1076
+ doctorResult = { ok: false, reason: "doctor-threw" };
1077
+ }
1078
+ if (!doctorPassed(doctorResult)) {
1079
+ const rollback = restoreSnapshot(snapshot, hermesHome, checkState);
1080
+ const reason = "post-install doctor did not prove a healthy payload";
1081
+ const outcome = rollbackFailure(reason, rollback);
1082
+ writeJournal("rolled-back", { reason: outcome.reason, rollback, ...(outcome.extra.state ? { state: outcome.extra.state } : {}) });
1083
+ return finish("failed", outcome.reason, rollback, { doctor: "failed", ...outcome.extra });
1084
+ }
1085
+ writeJournal("committed", { doctor: "ok" });
1086
+ return finish("updated", "automatic update committed", { status: "not-needed" }, { doctor: "ok" });
1087
+ } catch (error) {
1088
+ const reason = error instanceof Error ? error.message : "automatic update failed";
1089
+ const rollback = snapshot ? restoreSnapshot(snapshot, hermesHome, checkState) : { status: "not-started" };
1090
+ const outcome = rollbackFailure(reason, rollback);
1091
+ try { writeJournal("rolled-back", { reason: outcome.reason, rollback, ...(outcome.extra.state ? { state: outcome.extra.state } : {}) }); } catch {}
1092
+ return finish("failed", outcome.reason, rollback, outcome.extra);
1093
+ } finally {
1094
+ releaseAutoUpdateLock(paths.lockPath, lock, checkState);
1095
+ }
1096
+ }
1097
+
1098
+ module.exports = {
1099
+ CACHE_TTL_MS,
1100
+ AUTO_UPDATE_GUARD_ENV,
1101
+ AUTO_UPDATE_JOURNAL_NAME,
1102
+ AUTO_UPDATE_LOCK_NAME,
1103
+ AUTO_UPDATE_RECEIPT_NAME,
1104
+ AUTO_UPDATE_TIMEOUT_MS,
1105
+ AUTO_UPDATE_LOCK_STALE_MS,
1106
+ MAX_RESPONSE_BYTES,
1107
+ PACKAGE_NAME,
1108
+ REGISTRY_URL,
1109
+ UPDATE_LOCK_STALE_MS,
1110
+ completeUpdateAttempt,
1111
+ autoUpdatePaths,
1112
+ automaticUpdateArgv: buildAutoUpdateArgv,
1113
+ performAutomaticUpdate: runAutomaticUpdate,
1114
+ autoUpdate: runAutomaticUpdate,
1115
+ buildAutoUpdateArgv,
1116
+ compareStableSemver,
1117
+ fetchLatestVersion,
1118
+ formatUpdateNotice,
1119
+ parseRegistryResponse,
1120
+ parseStableSemver,
1121
+ parseUpdateCache,
1122
+ readUpdateCache,
1123
+ runAutomaticUpdate,
1124
+ sanitizeNpmEnvironment,
1125
+ refreshUpdateCache,
1126
+ reserveUpdateAttempt,
1127
+ scheduleUpdateCheck,
1128
+ shouldCheckForUpdates,
1129
+ shouldRunAutomaticUpdate: shouldAutoUpdate,
1130
+ shouldAutoUpdate,
1131
+ shouldRefreshCache,
1132
+ writeUpdateCache,
1133
+ };