elanous 0.2.10 → 0.2.12

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 (615) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  8. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  18. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  19. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  24. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -1
  152. package/apps/pwa/out/ops/seats/index.txt +22 -22
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -1
  178. package/apps/pwa/out/today/index.txt +23 -23
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/context/nightly-condense.yaml +21 -0
  192. package/graphs/context/recipes.yaml +12 -0
  193. package/graphs/demo/inside-seed.yaml +20 -0
  194. package/graphs/demo/recipes.yaml +12 -0
  195. package/graphs/drafts/draft-cleanup.yaml +19 -0
  196. package/graphs/drafts/recipes.yaml +23 -0
  197. package/graphs/intake/intake-daily.yaml +2 -1
  198. package/graphs/ops/recipes.yaml +3 -0
  199. package/graphs/ops/secret-exposure.yaml +24 -0
  200. package/graphs/release/recipes.yaml +3 -0
  201. package/graphs/release/release-loop.yaml +4 -1
  202. package/graphs/video/explainer-line.yaml +2 -2
  203. package/package.json +2 -1
  204. package/plugins/card-followup/examples/sample-card.png +0 -0
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/context-hooks/claude-stop.sh +4 -0
  216. package/scripts/context-hooks/emit.ts +24 -0
  217. package/scripts/context-hooks/post-tool-use.sh +4 -0
  218. package/scripts/coord-channel-watch.sh +12 -0
  219. package/scripts/coord-requests-bridge.ts +143 -0
  220. package/scripts/field-feed/lib.ts +4 -0
  221. package/scripts/fleet/node-setup.sh +20 -3
  222. package/scripts/homebrew-formula-bump.ts +69 -0
  223. package/scripts/lib/telegram-inject-args.ts +31 -0
  224. package/scripts/marketing/measure-site-numbers.ts +169 -0
  225. package/scripts/measure-gate-shards.ts +309 -0
  226. package/scripts/measure-pod-memory-by-goal.ts +130 -0
  227. package/scripts/mission-request-judge.ts +31 -1
  228. package/scripts/morning-report.ts +2 -2
  229. package/scripts/opportunity-scan.ts +1 -1
  230. package/scripts/release-loop/auto-approve-node.ts +21 -4
  231. package/scripts/release-loop/checklist-gate-node.ts +2 -1
  232. package/scripts/release-loop/cut-branch.ts +84 -0
  233. package/scripts/release-loop/gate-node.ts +22 -15
  234. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  235. package/scripts/release-loop/node-verdict.ts +3 -3
  236. package/scripts/release-loop/ops-upgrade-node.ts +47 -6
  237. package/scripts/release-loop/publish-node.ts +4 -1
  238. package/scripts/release-loop/tui-node-checks.ts +42 -0
  239. package/scripts/release-loop/tui-sim-node.ts +32 -8
  240. package/scripts/release-loop/unattended-release.ts +5 -3
  241. package/scripts/release-loop/version-node.ts +74 -13
  242. package/scripts/signal-digest-cycle.ts +2 -7
  243. package/scripts/signal-digest-photo.ts +11 -0
  244. package/scripts/tech1-public-measure.ts +94 -0
  245. package/scripts/telegram-inject.ts +14 -6
  246. package/scripts/test-diet/node.ts +1 -1
  247. package/scripts/test-diet/remeasure-list.ts +112 -0
  248. package/scripts/tui-regress.ts +2 -2
  249. package/scripts/ux/demo-rehearsal.ts +247 -0
  250. package/scripts/ux/demo-seed.ts +108 -0
  251. package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
  252. package/skills/diagram-master/SKILL.md +366 -0
  253. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  254. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  255. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  256. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  257. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  258. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  259. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  260. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  261. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  262. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  263. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  264. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  265. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  266. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  267. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  268. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  269. package/skills/diagram-master/references/examples/README.md +69 -0
  270. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  271. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  272. package/skills/diagram-master/references/pyproject.toml +16 -0
  273. package/skills/diagram-master/references/quality-checklist.md +33 -0
  274. package/skills/diagram-master/references/routing-guide.md +164 -0
  275. package/skills/diagram-master/references/uv.lock +1356 -0
  276. package/skills/google-workspace/SKILL.md +33 -0
  277. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  278. package/skills/grill-me/SKILL.md +1 -1
  279. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  280. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  281. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  282. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  283. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  284. package/skills/omni-crawl/SKILL.md +21 -11
  285. package/skills/omni-crawl/scripts/main.ts +6 -6
  286. package/skills/omni-crawl/src/router.ts +3 -3
  287. package/skills/omni-digest/SKILL.md +17 -9
  288. package/skills/omni-digest/digest.md +2 -2
  289. package/skills/omni-digest/src/fetch.ts +30 -3
  290. package/skills/pitch-deck/SKILL.md +2 -2
  291. package/skills/pitch-deck/template.html +2 -2
  292. package/skills/youtube-master/SKILL.md +163 -0
  293. package/skills/youtube-master/package-lock.json +558 -0
  294. package/skills/youtube-master/package.json +13 -0
  295. package/skills/youtube-master/references/study-note-template.md +124 -0
  296. package/skills/youtube-master/scripts/main.ts +435 -0
  297. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  298. package/skills/youtube-master/src/audio.ts +63 -0
  299. package/skills/youtube-master/src/domain-staging.ts +50 -0
  300. package/skills/youtube-master/src/env.ts +36 -0
  301. package/skills/youtube-master/src/obsidian.ts +155 -0
  302. package/skills/youtube-master/src/router.ts +110 -0
  303. package/skills/youtube-master/src/stt.ts +199 -0
  304. package/skills/youtube-master/src/study-note.ts +175 -0
  305. package/skills/youtube-master/src/summarize.ts +358 -0
  306. package/skills/youtube-master/src/transcript.ts +76 -0
  307. package/skills/youtube-master/src/types.ts +91 -0
  308. package/skills/youtube-master/src/util.ts +93 -0
  309. package/skills/youtube-master/src/youtube.ts +70 -0
  310. package/skills/youtube-master/tsconfig.json +13 -0
  311. package/src/acp/server.ts +5 -2
  312. package/src/agent-mission/driver.ts +215 -23
  313. package/src/agent-mission/pty-decision.ts +71 -0
  314. package/src/agent-mission/review-loop.ts +30 -0
  315. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  316. package/src/autopilot/pty-control-loop.ts +4 -1
  317. package/src/autopilot/tool-registry.ts +2 -0
  318. package/src/boot/daemon-prompt-turn.ts +5 -0
  319. package/src/boot/daemon-runtime.ts +9 -3
  320. package/src/boot/daemon-tools/web-search.ts +3 -0
  321. package/src/card-followup/core.ts +109 -0
  322. package/src/chat/index.ts +2 -0
  323. package/src/cli/drive-input-jail.ts +101 -0
  324. package/src/cli/hooks-cli.ts +17 -3
  325. package/src/cli/make-cli.ts +43 -0
  326. package/src/cli/persona-cli.ts +98 -9
  327. package/src/cli/plugin-cli.ts +31 -22
  328. package/src/cli/pod-cli.ts +36 -9
  329. package/src/cli/pod-memory-advice.ts +35 -0
  330. package/src/cli/pr-cli.ts +51 -15
  331. package/src/cli/pty-drive-cli.ts +41 -7
  332. package/src/cli/pty-drive-verdict.ts +40 -0
  333. package/src/cli/release-cli.ts +63 -10
  334. package/src/cli/setup-cli.ts +43 -1
  335. package/src/cli/skills-cli.ts +17 -1
  336. package/src/context-bus/claude-hooks-install.ts +10 -0
  337. package/src/context-bus/context-now-surfaces.ts +65 -0
  338. package/src/context-bus/context-now.ts +104 -0
  339. package/src/context-bus/coord-events.ts +2 -2
  340. package/src/context-bus/external-events.ts +52 -0
  341. package/src/context-bus/long-term-memory.ts +108 -0
  342. package/src/context-bus/nightly-condense.ts +153 -0
  343. package/src/context-bus/session-events.ts +35 -0
  344. package/src/dashboard/dashboard-status-lines.ts +2 -0
  345. package/src/dashboard/index.ts +17 -4
  346. package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
  347. package/src/decisions/decision-cards.ts +10 -3
  348. package/src/decisions/decision-ledger.ts +13 -5
  349. package/src/discord/sprint21-runtime.ts +5 -1
  350. package/src/discord-self-message.ts +32 -0
  351. package/src/discord-slash-wire.ts +5 -1
  352. package/src/discord.ts +17 -1
  353. package/src/domains/core-tools.ts +3 -2
  354. package/src/domains/outbound-alert.ts +105 -32
  355. package/src/domains/outbound-log-probe.ts +8 -0
  356. package/src/domains/telegram-kind-route.ts +51 -13
  357. package/src/exec-requests/default-outputs.ts +25 -0
  358. package/src/exec-requests/planner.ts +10 -2
  359. package/src/exec-requests/runner.ts +20 -6
  360. package/src/exec-requests/store.ts +3 -0
  361. package/src/execution-loop/launch-gate.ts +109 -0
  362. package/src/field/field-reel.ts +5 -1
  363. package/src/field-note/index.ts +201 -0
  364. package/src/field-note/telegram.ts +142 -0
  365. package/src/field-note/transcribe.ts +248 -0
  366. package/src/graph-kinds/registry.ts +3 -3
  367. package/src/graph-runner/graph-cli.ts +61 -1
  368. package/src/graph-runner/graph-grow-llm.ts +47 -0
  369. package/src/graph-runner/graph-grow.ts +50 -0
  370. package/src/graph-runner/runner.ts +329 -33
  371. package/src/grok/agent-search.ts +8 -2
  372. package/src/guardian/secret-exposure-scan.ts +101 -0
  373. package/src/harness/harness-cli-command.ts +375 -13
  374. package/src/harness/harness-pod-dispatch.ts +43 -23
  375. package/src/harness/harness-seams.ts +38 -4
  376. package/src/harness/harness-stop.ts +23 -4
  377. package/src/harness/launch-registry.ts +91 -0
  378. package/src/harness/process-garbage.ts +5 -3
  379. package/src/hooks/consult-intake.ts +153 -0
  380. package/src/hooks/dispatch.ts +82 -0
  381. package/src/hooks/expose.ts +254 -0
  382. package/src/hooks/github-shadow.ts +108 -0
  383. package/src/hooks/providers.ts +71 -5
  384. package/src/hooks/queue.ts +1 -1
  385. package/src/hooks/receiver.ts +94 -16
  386. package/src/index.ts +76 -14
  387. package/src/intake-plane/categorize.ts +18 -46
  388. package/src/intake-plane/discord-seat-work.ts +38 -2
  389. package/src/intake-plane/front-route-classifier.ts +33 -39
  390. package/src/intake-plane/persona-answer.ts +30 -0
  391. package/src/intake-plane/runtime-callables.ts +8 -1
  392. package/src/intake-plane/telegram-seat-work.ts +36 -2
  393. package/src/intake-plane/wish-card.ts +33 -0
  394. package/src/intake-plane/wish-folder.ts +67 -0
  395. package/src/intent-gate/gate.ts +30 -10
  396. package/src/live/detail-switch.ts +5 -0
  397. package/src/llm/difficulty.ts +57 -0
  398. package/src/llm/judge-layer.ts +101 -0
  399. package/src/llm/mission-router.ts +33 -19
  400. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  401. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  402. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  403. package/src/loops/contract/loop-agent.schema.json +138 -0
  404. package/src/loops/contract/validate.ts +64 -0
  405. package/src/loops/registry.ts +20 -6
  406. package/src/market/signed-index.ts +4 -0
  407. package/src/maturity/bot-command-maturity.ts +45 -0
  408. package/src/maturity/feature-maturity.ts +27 -4
  409. package/src/model-tier/index.ts +2 -2
  410. package/src/model-tier/tier-resolver.ts +20 -20
  411. package/src/model-tier/types.ts +6 -6
  412. package/src/mss/logging/log-store.ts +15 -0
  413. package/src/nexus/api/config-model-tier.ts +5 -4
  414. package/src/nexus/api/fabric-plans.ts +53 -0
  415. package/src/nexus/api/harness-api.ts +5 -1
  416. package/src/nexus/api/health.ts +2 -0
  417. package/src/nexus/api/http-server.ts +67 -8
  418. package/src/nexus/api/inside-events.ts +226 -0
  419. package/src/nexus/api/meta-api.ts +21 -8
  420. package/src/nexus/api/missions.ts +6 -1
  421. package/src/nexus/api/ops-seats.ts +33 -0
  422. package/src/nexus/api/outbound-report.ts +40 -7
  423. package/src/nexus/api/outputs-route.ts +44 -0
  424. package/src/nexus/api/personas.ts +95 -53
  425. package/src/nexus/api/seat-requests.ts +44 -2
  426. package/src/nexus/api/sessions-store.ts +17 -38
  427. package/src/nexus/api/sub-seat-charters.ts +34 -0
  428. package/src/nexus/api/tabs-mutations.ts +3 -1
  429. package/src/nexus/api/task-cards-api.ts +19 -0
  430. package/src/nexus/api/trace.ts +18 -6
  431. package/src/nexus/api/workflow-history.ts +88 -0
  432. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  433. package/src/nexus/api/workflows.ts +132 -6
  434. package/src/nexus/index.ts +2 -0
  435. package/src/nexus/kinds/webterm.ts +2 -1
  436. package/src/nexus/outbound/delivery-ledger.ts +17 -8
  437. package/src/nexus/outbound/router.ts +8 -3
  438. package/src/nexus/webterm/pty.ts +6 -2
  439. package/src/onboarding/cli-auth-status.ts +80 -0
  440. package/src/onboarding/voice-ai.ts +3 -3
  441. package/src/org/seat-budget.ts +48 -0
  442. package/src/org/stall-escalation.ts +63 -0
  443. package/src/outputs/ledger.ts +120 -0
  444. package/src/persona/persona-todo.ts +79 -0
  445. package/src/persona/presets.ts +123 -2
  446. package/src/persona/team-set.ts +155 -0
  447. package/src/plugins/install/plugin-install.ts +14 -0
  448. package/src/plugins/maker/market-bundle.ts +110 -0
  449. package/src/plugins/maker/plugin-maker.ts +254 -11
  450. package/src/plugins/maker/wizard-generate.ts +103 -0
  451. package/src/pod-lease/admission.ts +150 -0
  452. package/src/pod-lease/dependency-state.ts +85 -0
  453. package/src/pod-lease/host-lease.ts +127 -0
  454. package/src/project/project-suggestion.ts +16 -0
  455. package/src/project/session-context.ts +24 -0
  456. package/src/release-loop/checklist.ts +17 -5
  457. package/src/release-loop/feature-store.ts +29 -13
  458. package/src/release-loop/landed-but-yellow.ts +48 -0
  459. package/src/release-loop/next-md-merge.ts +58 -0
  460. package/src/release-loop/release-note.ts +59 -4
  461. package/src/seat-dispatch/seat-ask.ts +130 -0
  462. package/src/seat-dispatch/seat-questions.ts +100 -0
  463. package/src/seat-loop/seat-loop.ts +709 -29
  464. package/src/seat-loop/seat-report.ts +37 -2
  465. package/src/self-dev/dev-cli.ts +4 -1
  466. package/src/self-dev/dev-pipeline.ts +37 -1
  467. package/src/self-dev/draft-sweep.ts +79 -40
  468. package/src/self-dev/draft-triage-rules.ts +62 -7
  469. package/src/self-dev/fabric-plan-core.ts +297 -0
  470. package/src/self-dev/orchestrate.ts +36 -4
  471. package/src/self-dev/release-path-guard.ts +62 -0
  472. package/src/self-dev/shard-aggregate.ts +230 -0
  473. package/src/self-dev/shard-placement.ts +60 -0
  474. package/src/self-dev/shard-plan.ts +48 -0
  475. package/src/self-dev/shard-pod-run.ts +77 -0
  476. package/src/self-dev/shard-run.ts +105 -0
  477. package/src/self-implement/budget-gate.ts +29 -12
  478. package/src/self-implement/gate-baseline.ts +1 -1
  479. package/src/self-implement/gate-candidate-ranking.ts +60 -0
  480. package/src/self-implement/gate-cli.ts +40 -1
  481. package/src/self-implement/gate-scope.ts +44 -13
  482. package/src/self-implement/graph-variant.ts +171 -0
  483. package/src/self-implement/harness-policy-gates.ts +1 -1
  484. package/src/self-implement/headless-elanous-driver.ts +27 -3
  485. package/src/self-implement/host-regate.ts +22 -1
  486. package/src/self-implement/importer-test-index.ts +2 -1
  487. package/src/self-implement/l8-merge-queue.ts +130 -0
  488. package/src/self-implement/orchestrator.ts +257 -9
  489. package/src/self-implement/route-consumer-test-index.ts +122 -0
  490. package/src/self-implement/seams.ts +72 -11
  491. package/src/self-implement/test-seams.ts +2 -0
  492. package/src/self-implement/uncommitted-work.ts +59 -0
  493. package/src/session/index.ts +36 -13
  494. package/src/skills/gift-install.ts +215 -0
  495. package/src/skills/tools/web-search.ts +4 -1
  496. package/src/steward/launch.ts +42 -26
  497. package/src/steward/steward-cards.ts +17 -9
  498. package/src/steward/triage.ts +46 -14
  499. package/src/task-cards/card-cli.ts +25 -1
  500. package/src/task-orchestrator/mission.ts +5 -0
  501. package/src/task-orchestrator/store.ts +12 -3
  502. package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
  503. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  504. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  505. package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
  506. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  507. package/src/task-orchestrator/types.ts +2 -0
  508. package/src/telegram-card-followup.ts +16 -96
  509. package/src/telegram-commands.ts +31 -1
  510. package/src/telegram-project-command.ts +145 -0
  511. package/src/telegram-report.ts +21 -17
  512. package/src/telegram.ts +61 -8
  513. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  514. package/src/user-config.ts +110 -24
  515. package/src/version/packed-revision.json +1 -1
  516. package/src/web-search/grok.ts +7 -1
  517. package/src/web-search/index.ts +28 -1
  518. package/src/web-search/provider.ts +4 -0
  519. package/src/web-search/x-intent.ts +5 -0
  520. package/src/workflow-runtime/executor.ts +277 -47
  521. package/src/workflow-runtime/index.ts +1 -0
  522. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  523. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  524. package/src/workflow-runtime/schema.ts +79 -4
  525. package/src/workflow-runtime/types.ts +35 -4
  526. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  536. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  537. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  556. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  614. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  615. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
@@ -0,0 +1,23 @@
1
+ classify:
2
+ command: >-
3
+ bun -e 'const ctx=await Bun.file(process.env.ELANOUS_GRAPH_CONTEXT).json();
4
+ const mode=ctx.input?.mode ?? "shadow";
5
+ if (mode !== "shadow" && mode !== "live") throw new Error("draft cleanup mode must be shadow or live");
6
+ const repo=process.env.ELANOUS_GRAPH_DIR+"/../..";
7
+ const run=Bun.spawnSync(["bun", repo+"/bin/elanous.mjs", "harness", "drafts", "sweep", "--json"], {cwd:repo,stdout:"pipe",stderr:"pipe"});
8
+ if (run.exitCode !== 0) throw new Error(new TextDecoder().decode(run.stderr));
9
+ const result=JSON.parse(new TextDecoder().decode(run.stdout));
10
+ if (!result.complete || result.apply !== false) throw new Error(result.error ?? "draft sweep classification must be shadow and complete");
11
+ console.log(JSON.stringify({outcome:mode,counts:result.counts,entries:result.entries}));'
12
+ timeout_ms: 120000
13
+ apply:
14
+ command: >-
15
+ bun -e 'const ctx=await Bun.file(process.env.ELANOUS_GRAPH_CONTEXT).json();
16
+ if (ctx.input?.mode !== "live" || ctx.outputs?.classify?.outcome !== "live") throw new Error("draft cleanup apply requires live mode and completed classification");
17
+ const repo=process.env.ELANOUS_GRAPH_DIR+"/../..";
18
+ const run=Bun.spawnSync(["bun", repo+"/bin/elanous.mjs", "harness", "drafts", "sweep", "--json", "--apply"], {cwd:repo,stdout:"pipe",stderr:"pipe"});
19
+ if (run.exitCode !== 0) throw new Error(new TextDecoder().decode(run.stderr));
20
+ const result=JSON.parse(new TextDecoder().decode(run.stdout));
21
+ if (!result.complete || result.apply !== true) throw new Error(result.error ?? "draft sweep application must be live and complete");
22
+ console.log(JSON.stringify({outcome:"ok",counts:result.counts,entries:result.entries}));'
23
+ timeout_ms: 120000
@@ -1,7 +1,8 @@
1
1
  # 정기 흡수 한 판 — RFC-regular-external-intake-and-normalization-pipeline §5.1 (1판: cmd 노드만).
2
2
  # 입력원 하나가 실패해도 판은 끝까지 간다(수집 노드의 fail 도 다음 노드로) — 각 단계가 «못 모음»을 로그에 남긴다.
3
- # 몸 = yt-vault 의 scripts/intake-daily.sh <step> · 크론이 `elanous graph run graphs/intake/intake-daily.yaml` 로 부른다.
3
+ # 몸 = yt-vault 의 scripts/intake-daily.sh <step> · 크론 입구 스크립트 intake-cron.sh 가 그래프를 부른다.
4
4
  graph_id: intake-daily
5
+ cron_entry: intake-cron.sh
5
6
  loop:
6
7
  title: 정기 흡수
7
8
  description: 외부 지식을 매일 수집·흡수한다
@@ -6,3 +6,6 @@ deploy-pages-dry:
6
6
  timeout_ms: 600000 # deploy-pages 도 안에서 build-public 을 돈다
7
7
  publish-approval:
8
8
  approval: "공개 발행을 승인하시겠습니까?"
9
+ secret-exposure-scan:
10
+ command: 'bun "$ELANOUS_GRAPH_DIR/../../src/guardian/secret-exposure-scan.ts"'
11
+ timeout_ms: 120000
@@ -0,0 +1,24 @@
1
+ graph_id: secret-exposure
2
+ loop:
3
+ title: Secret exposure scan
4
+ description: Daily read-only candidate scan; shadow by default
5
+ trigger:
6
+ cron: '0 4 * * *'
7
+ version: 1
8
+ entry_node: scan
9
+ terminal_nodes: [done, failed]
10
+ nodes:
11
+ - node_id: scan
12
+ kind: agent
13
+ recipe: cmd:secret-exposure-scan
14
+ max_visits: 1
15
+ - node_id: done
16
+ kind: gate
17
+ max_visits: 1
18
+ - node_id: failed
19
+ kind: gate
20
+ max_visits: 1
21
+ edges:
22
+ - from: scan
23
+ on: outcome
24
+ map: { ok: done, fail: failed }
@@ -11,6 +11,9 @@ gate:
11
11
  command: 'bun scripts/release-loop/gate-node.ts --json'
12
12
  # 4h — the Pod gate took 2h02m on 09-30 (G1f ②) and the 0.2.5 loop was cut at exactly 2h with no verdict; K9 (≤15 min) is the real fix.
13
13
  timeout_ms: 14400000
14
+ mac-smoke:
15
+ command: 'bun scripts/release-loop/mac-smoke-node.ts'
16
+ timeout_ms: 1800000
14
17
  export-check:
15
18
  command: 'bun scripts/release-loop/export-check-node.ts'
16
19
  timeout_ms: 1800000
@@ -15,6 +15,7 @@ nodes:
15
15
  - { node_id: cutoff, kind: judge, recipe: 'cmd:cutoff', max_visits: 1 }
16
16
  - { node_id: checklist-gate, kind: gate, recipe: 'cmd:checklist-gate', max_visits: 1 }
17
17
  - { node_id: gate, kind: gate, recipe: 'cmd:gate', max_visits: 1, notify: start }
18
+ - { node_id: mac-smoke, kind: gate, recipe: 'cmd:mac-smoke', max_visits: 1 }
18
19
  - { node_id: export-check, kind: gate, recipe: 'cmd:export-check', max_visits: 1 }
19
20
  - { node_id: pwa, kind: gate, recipe: 'cmd:pwa', max_visits: 1, notify: start }
20
21
  - { node_id: prepare, kind: agent, recipe: 'cmd:prepare', max_visits: 1, notify: start }
@@ -37,7 +38,9 @@ edges:
37
38
  - { from: version-release, on: outcome, map: { ok: cutoff, fail: failed, error: failed } }
38
39
  - { from: cutoff, on: outcome, map: { ok: checklist-gate, fail: failed, error: failed } }
39
40
  - { from: checklist-gate, on: outcome, map: { ok: gate, fail: failed, error: failed } }
40
- - { from: gate, on: outcome, map: { ok: export-check, fail: failed, error: failed } }
41
+ - { from: gate, on: outcome, map: { ok: mac-smoke, fail: failed, error: failed } }
42
+ # Warning-only: a macOS failure or unmeasured run never blocks publishing — auto-approve shows it as a warning row.
43
+ - { from: mac-smoke, on: outcome, map: { ok: export-check, fail: export-check, error: export-check } }
41
44
  - { from: export-check, on: outcome, map: { ok: pwa, fail: failed, error: failed } }
42
45
  - { from: pwa, on: outcome, map: { ok: prepare, fail: failed, error: failed } }
43
46
  - { from: prepare, on: outcome, map: { ok: upgrade, fail: failed, error: failed } }
@@ -1,7 +1,7 @@
1
1
  # «N가지 한 번에 정리» explainer: facts → script → timed VO → composition → checked render → measured QC.
2
2
  # Engine = skills/explainer-video (vo.ts · build.mjs). Render/snapshot/check = the existing hyperframes-render recipe.
3
- # ⚠️ Recipes explainer-script / explainer-vo / explainer-build / explainer-qc are declared here and not yet coded
4
- # (src/video-pipeline/recipes) — a walk stops at the first of them as «unknown recipe». Until then the skill runs these steps.
3
+ # Recipes explainer-script / explainer-vo / explainer-build / explainer-qc are implemented in
4
+ # src/video-pipeline/recipes/explainer.ts; the graph routes their outcomes through render and QC.
5
5
  graph_id: explainer-line
6
6
  version: 1
7
7
  entry_node: script
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "elanous",
3
- "version": "0.2.10",
3
+ "mcpName": "io.github.ElanvitalAI/elanous",
4
+ "version": "0.2.12",
4
5
  "description": "Self-healing coding harness where eyes, hands, and memory all turn on one sentence — it authors its own goals, implements them in isolated worktrees, and reviews its own work.",
5
6
  "license": "Apache-2.0",
6
7
  "author": "Elanvital AI",
@@ -0,0 +1,25 @@
1
+ # elanous-hwp
2
+
3
+ **S** — HWPX files carry Korean office documents in ZIP/XML form. **C** — Markdown-only tooling cannot read their paragraphs, headings or tables. **Q** — How can these documents be exchanged without external binaries? **A** — This official plugin provides a built-in ZIP/XML reader and a minimal writer.
4
+
5
+ ```sh
6
+ bun plugins/elanous-hwp/cli.ts to-md input.hwpx output.md
7
+ bun plugins/elanous-hwp/cli.ts from-md input.md output.hwpx
8
+ ```
9
+
10
+ The plugin also registers `HwpxToMarkdown` (HWPX path → Markdown text) and `MarkdownToHwpx` (Markdown path and new HWPX output path) as host LLM tools. `to-md` reads spine-ordered HWPX sections and emits paragraphs, headings (referenced paragraph properties with OUTLINE heading levels 0–5), and GFM tables. `from-md` writes paragraphs and headings into a minimal HWPX ZIP; it does not write tables. Existing output files are not overwritten. `.hwp` legacy binary files are **not supported**: save them as `.hwpx` first. No external executable, Python package, or third-party ZIP/XML library is required. This first piece does not validate page layout or promise round-trip preservation of unsupported styling, images, or merged cells.
11
+
12
+ ## Verification record
13
+
14
+ - Official manifest and both host conversion tools: `plugin.json` (`trust: official`, `main: ./plugin.ts`), `plugin.ts`, and `converter.test.ts` (host tool test and manifest loader assertions).
15
+ - Fixed compressed sample → OUTLINE level 0 heading with reference ID 4, ordinary paragraph with nonzero reference ID 2, joined paragraph, GFM table and escaped pipe, then mixed text/table/text within one run in original order: `fixtures/fixed.hwpx` and `converter.test.ts` (fixed sample test). `fixtures/fixed-controls.hwpx` checks text/lineBreak/tab interleaving inside one `<hp:t>`. `fixtures/fixed-table-controls.hwpx` checks that a cell's lineBreak and separate paragraphs become `<br>` within one GFM row (test at `converter.test.ts:64-70`; implementation at `converter.ts:153-162`).
16
+ - Minimal Markdown → HWPX → identical Markdown; unsupported Markdown tables fail explicitly: `converter.ts` and `converter.test.ts` (round-trip test). ATX headings end on their own line even without a blank separator: `converter.ts:198-220` and `converter.test.ts:55-62` assert three distinct generated XML content paragraphs (four including the section-properties paragraph), properties 1/0/2. Multiline ordinary paragraphs retain lineBreak controls (`converter.test.ts:47-53`). Legacy HWP guidance and no-overwrite behavior: `cli.ts`, `plugin.ts`, and `converter.test.ts` (CLI test).
17
+ - Zero external runtime binary dependencies: `converter.ts` uses `node:zlib`; `cli.ts` and `plugin.ts` use `node:fs`. The independent consumer below is a *verification-only* script from the existing pack, not invoked by the plugin.
18
+ - `bun test plugins/elanous-hwp/converter.test.ts 2>&1 | tail -6`: `8 pass`, `0 fail`, `Ran 8 tests across 1 file. [58.00ms]` (40 assertions). This includes a spawned `bun plugins/elanous-hwp/cli.ts to-md …` subprocess in the CLI test.
19
+ - `bun bin/elanous.mjs --test self typecheck 2>&1 | tail -4`: `✅ 변경 파일 타입 검사 통과 (4개 파일 검사…)`.
20
+ - `bun bin/elanous.mjs --test self gate --changed 2>&1 | tail -20`: `tests: pass (1 files)` and `[test-count] changed-test-files=1, test-cases=0→8, decrease=0`; the gate explicitly lists six files outside the bun test runner, including fixture archives (these archives are read by the focused tests).
21
+ - Earlier `bun .elanous-test/scratch/verify-generated-hwpx.ts`: `independent HWPX consumer: PASS — title, paragraph, OPF spine` (previous run, not a fresh verification; uses the repository's existing `packs/elanous-hwp/test/consumer.py` only for verification).
22
+ - Mutation (this review, table): changed `converter.ts:157` replacement of internal newlines from `<br>` to empty; `bun test plugins/elanous-hwp/converter.test.ts -t 'fixed HWPX table sample retains cell line breaks and multiple cell paragraphs within GFM rows' 2>&1 | tail -12` returned `0 pass`, `1 fail`, `Ran 1 test across 1 file. [29.00ms]`. Failing check verbatim: `(fail) fixed HWPX table sample retains cell line breaks and multiple cell paragraphs within GFM rows [2.78ms]`. Restored `<br>`.
23
+ - Mutation (this review, ATX): changed `converter.ts:209` heading regex from `{1,6}` to `{7,8}`; `bun test plugins/elanous-hwp/converter.test.ts -t 'adjacent ATX headings terminate at the end of their line even without blank separators' 2>&1 | tail -10` returned `0 pass`, `1 fail`, `Ran 1 test across 1 file. [37.00ms]`. Failing check verbatim: `(fail) adjacent ATX headings terminate at the end of their line even without blank separators [2.73ms]`. Restored `{1,6}`; full focused file passed `8 pass`, `0 fail` afterward.
24
+ - Preservation: `git status --short -- packs/elanous-hwp` returns no lines; the separate existing pack is unchanged. English release note: `release/next.md:30`. Review disposition: both must-fixes apply and are compatible with the requested Markdown and HWPX conversion; no refutation.
25
+ - Commit status: intentionally uncommitted. This self-implement child is explicitly prohibited from git commit/push/PR/branch changes; the parent harness owns the approval-gated commit.
@@ -0,0 +1,22 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { hwpxToMarkdown, markdownToHwpx } from './converter.js';
3
+
4
+ export function main(args: string[]): void {
5
+ const [command, input, output] = args;
6
+ if (!input || !output || !['to-md', 'from-md'].includes(command ?? '')) {
7
+ throw new Error('Usage: bun plugins/elanous-hwp/cli.ts to-md input.hwpx output.md | from-md input.md output.hwpx');
8
+ }
9
+ if (/\.hwp$/i.test(input) || /\.hwp$/i.test(output)) throw new Error('HWP(옛 바이너리)는 지원 안 함 · hwpx 로 저장해 달라');
10
+ if (command === 'to-md') {
11
+ if (!/\.hwpx$/i.test(input) || !/\.md$/i.test(output)) throw new Error('Expected .hwpx input and .md output');
12
+ writeFileSync(output, hwpxToMarkdown(readFileSync(input), input), { flag: 'wx' });
13
+ } else {
14
+ if (!/\.md$/i.test(input) || !/\.hwpx$/i.test(output)) throw new Error('Expected .md input and .hwpx output');
15
+ writeFileSync(output, markdownToHwpx(readFileSync(input, 'utf8')), { flag: 'wx' });
16
+ }
17
+ }
18
+
19
+ if (import.meta.main) {
20
+ try { main(process.argv.slice(2)); }
21
+ catch (error) { console.error(error instanceof Error ? error.message : error); process.exitCode = 1; }
22
+ }
@@ -0,0 +1,237 @@
1
+ import { deflateRawSync, inflateRawSync } from 'node:zlib';
2
+
3
+ const encoder = new TextEncoder();
4
+ const decoder = new TextDecoder('utf-8', { fatal: true });
5
+ const HP = 'http://www.hancom.co.kr/hwpml/2011/paragraph';
6
+ const HH = 'http://www.hancom.co.kr/hwpml/2011/head';
7
+ /** HWPX section root lives in the section namespace (OWPML `hs:sec`), not the paragraph one. */
8
+ const HS = 'http://www.hancom.co.kr/hwpml/2011/section';
9
+ const OPF = 'http://www.idpf.org/2007/opf/';
10
+ const HWP_NOTICE = 'HWP(옛 바이너리)는 지원 안 함 · hwpx 로 저장해 달라';
11
+
12
+ type XmlNode = { name: string; attrs: Record<string, string>; children: XmlNode[]; content: (XmlNode | string)[] };
13
+ const local = (name: string) => name.split(':').pop()!;
14
+ const xmlEscape = (value: string) => value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
15
+ function unescapeXml(value: string): string {
16
+ return value.replace(/&(#x[\da-f]+|#\d+|amp|lt|gt|quot|apos);/gi, (_, entity: string) => {
17
+ const named: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'" };
18
+ if (entity[0] !== '#') return named[entity] ?? `&${entity};`;
19
+ const cp = entity[1]?.toLowerCase() === 'x' ? parseInt(entity.slice(2), 16) : parseInt(entity.slice(1), 10);
20
+ if (cp > 0x10ffff || cp === 0 || (cp >= 0xd800 && cp <= 0xdfff)) throw new Error('Invalid XML character');
21
+ return String.fromCodePoint(cp);
22
+ });
23
+ }
24
+ function parseXml(xml: string): XmlNode {
25
+ if (/<!DOCTYPE|<!ENTITY/i.test(xml)) throw new Error('External XML entities are not supported');
26
+ const root: XmlNode = { name: '', attrs: {}, children: [], content: [] };
27
+ const stack = [root];
28
+ const tokens = xml.match(/<[^>]*>|[^<]+/g) ?? [];
29
+ for (const token of tokens) {
30
+ if (token.startsWith('<?') || token.startsWith('<!--')) continue;
31
+ if (token.startsWith('</')) {
32
+ if (local(stack.at(-1)!.name) !== local(token.slice(2, -1).trim()) || stack.length === 1) throw new Error('Invalid HWPX XML');
33
+ stack.pop();
34
+ } else if (token.startsWith('<')) {
35
+ if (token.startsWith('<!')) throw new Error('Unsupported HWPX XML declaration');
36
+ const match = /^<([\w:.-]+)(?:\s|\/?>)/.exec(token);
37
+ if (!match) throw new Error('Invalid HWPX XML');
38
+ const attrs: Record<string, string> = {};
39
+ for (const attr of token.slice(match[0].length).matchAll(/([\w:.-]+)\s*=\s*(["'])(.*?)\2/g)) attrs[local(attr[1]!)] = unescapeXml(attr[3]!);
40
+ const node: XmlNode = { name: local(match[1]!), attrs, children: [], content: [] };
41
+ stack.at(-1)!.children.push(node);
42
+ stack.at(-1)!.content.push(node);
43
+ if (!token.endsWith('/>')) stack.push(node);
44
+ } else {
45
+ stack.at(-1)!.content.push(unescapeXml(token));
46
+ }
47
+ }
48
+ if (stack.length !== 1 || root.children.length !== 1) throw new Error('Invalid HWPX XML');
49
+ return root.children[0]!;
50
+ }
51
+ const children = (node: XmlNode, name: string) => node.children.filter(child => child.name === name);
52
+ const descendants = (node: XmlNode, name: string): XmlNode[] => node.children.flatMap(child => [ ...(child.name === name ? [child] : []), ...descendants(child, name) ]);
53
+ const nodeText = (node: XmlNode): string => node.name === 'lineBreak' ? '\n' : node.name === 'tab' ? '\t' : node.content.map(part => typeof part === 'string' ? (node.name === 't' ? part : '') : nodeText(part)).join('');
54
+
55
+ function crc32(bytes: Uint8Array): number {
56
+ let crc = -1;
57
+ for (const byte of bytes) {
58
+ crc ^= byte;
59
+ for (let i = 0; i < 8; i++) crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0);
60
+ }
61
+ return (crc ^ -1) >>> 0;
62
+ }
63
+ function readZip(bytes: Uint8Array): Map<string, Uint8Array> {
64
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
65
+ let eocd = -1;
66
+ for (let i = bytes.length - 22; i >= Math.max(0, bytes.length - 65557); i--) {
67
+ if (view.getUint32(i, true) === 0x06054b50 && i + 22 + view.getUint16(i + 20, true) === bytes.length) { eocd = i; break; }
68
+ }
69
+ if (eocd < 0 || view.getUint16(eocd + 4, true) !== 0 || view.getUint16(eocd + 6, true) !== 0) throw new Error('Invalid HWPX ZIP');
70
+ if (view.getUint16(eocd + 8, true) !== view.getUint16(eocd + 10, true) || view.getUint32(eocd + 16, true) + view.getUint32(eocd + 12, true) > eocd) throw new Error('Invalid HWPX ZIP directory');
71
+ const count = view.getUint16(eocd + 10, true);
72
+ if (count > 1024) throw new Error('HWPX ZIP has too many entries');
73
+ let cursor = view.getUint32(eocd + 16, true);
74
+ const entries = new Map<string, Uint8Array>();
75
+ const directoryEnd = view.getUint32(eocd + 16, true) + view.getUint32(eocd + 12, true);
76
+ for (let i = 0; i < count; i++) {
77
+ if (cursor + 46 > directoryEnd || view.getUint32(cursor, true) !== 0x02014b50) throw new Error('Invalid HWPX ZIP directory');
78
+ const flags = view.getUint16(cursor + 8, true), method = view.getUint16(cursor + 10, true);
79
+ const crc = view.getUint32(cursor + 16, true), packed = view.getUint32(cursor + 20, true), size = view.getUint32(cursor + 24, true);
80
+ const nameLen = view.getUint16(cursor + 28, true), extraLen = view.getUint16(cursor + 30, true), commentLen = view.getUint16(cursor + 32, true);
81
+ if (flags & 1 || size > 32 * 1024 * 1024 || packed > 32 * 1024 * 1024 || cursor + 46 + nameLen + extraLen + commentLen > bytes.length) throw new Error('Unsupported HWPX ZIP entry');
82
+ const name = decoder.decode(bytes.subarray(cursor + 46, cursor + 46 + nameLen));
83
+ const offset = view.getUint32(cursor + 42, true);
84
+ if (offset + 30 > bytes.length || view.getUint32(offset, true) !== 0x04034b50) throw new Error('Invalid HWPX ZIP entry');
85
+ const start = offset + 30 + view.getUint16(offset + 26, true) + view.getUint16(offset + 28, true);
86
+ if (start + packed > bytes.length) throw new Error('Truncated HWPX ZIP entry');
87
+ const content = method === 0 ? bytes.slice(start, start + packed) : method === 8 ? inflateRawSync(bytes.subarray(start, start + packed), { maxOutputLength: 32 * 1024 * 1024 }) : null;
88
+ if (!content || content.length !== size || crc32(content) !== crc || entries.has(name)) throw new Error('Invalid HWPX ZIP entry: ' + name);
89
+ entries.set(name, content);
90
+ cursor += 46 + nameLen + extraLen + commentLen;
91
+ }
92
+ if (cursor !== directoryEnd) throw new Error('Invalid HWPX ZIP directory');
93
+ return entries;
94
+ }
95
+ function writeZip(files: [string, string][]): Uint8Array {
96
+ const parts: Uint8Array[] = [], directory: Uint8Array[] = [];
97
+ let offset = 0;
98
+ const uint16 = (view: DataView, at: number, n: number) => view.setUint16(at, n, true);
99
+ const uint32 = (view: DataView, at: number, n: number) => view.setUint32(at, n >>> 0, true);
100
+ for (const [name, value] of files) {
101
+ const filename = encoder.encode(name), body = encoder.encode(value);
102
+ const method = name === 'mimetype' ? 0 : 8;
103
+ const packed = method === 0 ? body : deflateRawSync(body);
104
+ const crc = crc32(body);
105
+ const header = new Uint8Array(30 + filename.length), h = new DataView(header.buffer);
106
+ uint32(h, 0, 0x04034b50); uint16(h, 4, 20); uint16(h, 6, 0x800); uint16(h, 8, method);
107
+ uint32(h, 14, crc); uint32(h, 18, packed.length); uint32(h, 22, body.length); uint16(h, 26, filename.length);
108
+ header.set(filename, 30);
109
+ parts.push(header, packed);
110
+ const central = new Uint8Array(46 + filename.length), c = new DataView(central.buffer);
111
+ uint32(c, 0, 0x02014b50); uint16(c, 4, 20); uint16(c, 6, 20); uint16(c, 8, 0x800); uint16(c, 10, method);
112
+ uint32(c, 16, crc); uint32(c, 20, packed.length); uint32(c, 24, body.length); uint16(c, 28, filename.length); uint32(c, 42, offset);
113
+ central.set(filename, 46); directory.push(central);
114
+ offset += header.length + packed.length;
115
+ }
116
+ const dirSize = directory.reduce((sum, part) => sum + part.length, 0);
117
+ const end = new Uint8Array(22), e = new DataView(end.buffer);
118
+ uint32(e, 0, 0x06054b50); uint16(e, 8, files.length); uint16(e, 10, files.length); uint32(e, 12, dirSize); uint32(e, 16, offset);
119
+ const result = new Uint8Array(offset + dirSize + end.length);
120
+ let pos = 0;
121
+ for (const part of [...parts, ...directory, end]) { result.set(part, pos); pos += part.length; }
122
+ return result;
123
+ }
124
+ function sections(zip: Map<string, Uint8Array>): { paths: string[]; paraProps: Map<string, XmlNode> } {
125
+ const container = zip.get('META-INF/container.xml');
126
+ if (!container) throw new Error('HWPX container.xml is missing');
127
+ const path = descendants(parseXml(decoder.decode(container)), 'rootfile')[0]?.attrs['full-path'];
128
+ const opf = path && zip.get(path);
129
+ if (!opf || !path) throw new Error('HWPX package is missing');
130
+ const pkg = parseXml(decoder.decode(opf));
131
+ const manifest = new Map(descendants(pkg, 'item').map(item => [item.attrs.id, item.attrs.href]));
132
+ const base = path.slice(0, path.lastIndexOf('/') + 1);
133
+ const ordered = descendants(pkg, 'itemref').map(ref => {
134
+ const href = manifest.get(ref.attrs.idref);
135
+ if (!href) return undefined;
136
+ const relative = [...base.split('/'), ...href.split('/')].reduce<string[]>((parts, part) => {
137
+ if (part === '..') parts.pop(); else if (part && part !== '.') parts.push(part);
138
+ return parts;
139
+ }, []).join('/');
140
+ return relative.endsWith('.xml') && zip.has(relative) && parseXml(decoder.decode(zip.get(relative)!)).name === 'sec' ? relative : undefined;
141
+ }).filter((name): name is string => !!name);
142
+ if (!ordered.length) throw new Error('HWPX section is missing');
143
+ const headerHref = [...manifest.values()].find(href => href?.endsWith('header.xml'));
144
+ const headerPath = headerHref && [...base.split('/'), ...headerHref.split('/')].reduce<string[]>((parts, part) => {
145
+ if (part === '..') parts.pop(); else if (part && part !== '.') parts.push(part);
146
+ return parts;
147
+ }, []).join('/');
148
+ const header = headerPath && zip.get(headerPath);
149
+ const paraProps = new Map<string, XmlNode>();
150
+ if (header) for (const prop of descendants(parseXml(decoder.decode(header)), 'paraPr')) {
151
+ if (prop.attrs.id !== undefined) paraProps.set(prop.attrs.id, prop);
152
+ }
153
+ return { paths: ordered, paraProps };
154
+ }
155
+ function tableMarkdown(table: XmlNode): string {
156
+ const cellText = (tc: XmlNode): string => {
157
+ const paragraphs = descendants(tc, 'p');
158
+ const text = paragraphs.length ? paragraphs.map(nodeText).join('\n') : nodeText(tc);
159
+ return text.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/\r\n|\r|\n/g, '<br>');
160
+ };
161
+ const rows = children(table, 'tr').map(tr => children(tr, 'tc').map(cellText));
162
+ if (!rows.length) return '';
163
+ return [rows[0], rows[0]!.map(() => '---'), ...rows.slice(1)].map(row => '| ' + row.join(' | ') + ' |').join('\n');
164
+ }
165
+ function paragraphMarkdown(p: XmlNode, paraProps: Map<string, XmlNode>): string[] {
166
+ const blocks: string[] = [];
167
+ let text = '';
168
+ const prop = paraProps.get(p.attrs.paraPrIDRef ?? '');
169
+ const heading = prop && children(prop, 'heading')[0];
170
+ const level = heading?.attrs.type === 'OUTLINE' ? Number(heading.attrs.level) : NaN;
171
+ const prefix = Number.isInteger(level) && level >= 0 && level <= 5 ? '#'.repeat(level + 1) + ' ' : '';
172
+ const flush = () => {
173
+ if (text.trim()) blocks.push(prefix + text.trim());
174
+ text = '';
175
+ };
176
+ const visit = (node: XmlNode): void => {
177
+ if (node.name === 'tbl') {
178
+ flush();
179
+ const md = tableMarkdown(node);
180
+ if (md) blocks.push(md);
181
+ } else if (node.name === 't' || node.name === 'lineBreak' || node.name === 'tab') {
182
+ text += nodeText(node);
183
+ } else {
184
+ for (const part of node.content) if (typeof part !== 'string') visit(part);
185
+ }
186
+ };
187
+ for (const run of children(p, 'run')) visit(run);
188
+ flush();
189
+ return blocks;
190
+ }
191
+ export function hwpxToMarkdown(bytes: Uint8Array, filename = 'document.hwpx'): string {
192
+ const oleSignature = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
193
+ if (/\.hwp$/i.test(filename) || (bytes.length >= oleSignature.length && oleSignature.every((byte, i) => bytes[i] === byte))) throw new Error(HWP_NOTICE);
194
+ const zip = readZip(bytes);
195
+ if (decoder.decode(zip.get('mimetype') ?? new Uint8Array()) !== 'application/hwp+zip') throw new Error('Not an HWPX document');
196
+ const { paths, paraProps } = sections(zip);
197
+ const blocks = paths.flatMap(path => children(parseXml(decoder.decode(zip.get(path)!)), 'p').flatMap(p => paragraphMarkdown(p, paraProps)));
198
+ return blocks.length ? blocks.join('\n\n') + '\n' : '';
199
+ }
200
+ export function markdownToHwpx(markdown: string): Uint8Array {
201
+ const paragraphs = markdown.replace(/\r\n/g, '\n').trim().split(/\n\s*\n/).filter(Boolean).flatMap(block => {
202
+ const lines = block.split('\n');
203
+ if (lines.some(line => /^\|.*\|$/.test(line))) throw new Error('Markdown tables are not supported by the minimal HWPX writer');
204
+ const result: { style: number; text: string }[] = [];
205
+ let body: string[] = [];
206
+ const flush = () => {
207
+ if (body.length) result.push({ style: 0, text: body.join('\n') });
208
+ body = [];
209
+ };
210
+ for (const line of lines) {
211
+ const heading = /^(#{1,6}) +(.+)$/.exec(line);
212
+ if (heading) {
213
+ flush();
214
+ result.push({ style: heading[1]!.length, text: heading[2]! });
215
+ } else body.push(line);
216
+ }
217
+ flush();
218
+ return result;
219
+ }).map(({ style, text }) => {
220
+ const content = text.split('\n').map(line => line.split('\t').map(xmlEscape).join('<hp:tab/>')).join('<hp:lineBreak/>');
221
+ return `<hp:p id="0" paraPrIDRef="${style}" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0"><hp:run charPrIDRef="0"><hp:t>${content}</hp:t></hp:run></hp:p>`;
222
+ }).join('');
223
+ const section = `<?xml version="1.0" encoding="UTF-8"?><hs:sec xmlns:hs="${HS}" xmlns:hp="${HP}"><hp:p id="0" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0"><hp:run charPrIDRef="0"><hp:secPr id="0" textDirection="HORIZONTAL" spaceColumns="0" tabStop="8000"><hp:pagePr landscape="WIDELY" width="59528" height="84188" gutterType="LEFT_ONLY"/><hp:pageMargin left="5660" right="5660" top="5660" bottom="5660"/></hp:secPr></hp:run></hp:p>${paragraphs}</hs:sec>`;
224
+ const langs = ['HANGUL', 'LATIN', 'HANJA', 'JAPANESE', 'OTHER', 'SYMBOL', 'USER'];
225
+ const fonts = langs.map(lang => `<hh:fontface lang="${lang}" fontCnt="1"><hh:font id="0" face="Malgun Gothic" type="TTF" isEmbedded="0"/></hh:fontface>`).join('');
226
+ const fontRefs = langs.map(lang => `${lang.toLowerCase()}="0"`).join(' ');
227
+ const charProps = `<hh:charPr id="0" height="1000" textColor="#000000" shadeColor="none" bold="0" italic="0"><hh:fontRef ${fontRefs}/></hh:charPr>`;
228
+ const paraProps = Array.from({ length: 7 }, (_, i) => `<hh:paraPr id="${i}" tabPrIDRef="0"><hh:heading type="${i ? 'OUTLINE' : 'NONE'}" level="${i ? i - 1 : 0}"/><hh:align horizontal="LEFT" vertical="BASELINE"/></hh:paraPr>`).join('');
229
+ const header = `<?xml version="1.0" encoding="UTF-8"?><hh:head xmlns:hh="${HH}" version="1.4" secCnt="1"><hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/><hh:refList><hh:fontfaces itemCnt="1">${fonts}</hh:fontfaces><hh:charProperties itemCnt="1">${charProps}</hh:charProperties><hh:paraProperties itemCnt="7">${paraProps}</hh:paraProperties><hh:styles itemCnt="1"><hh:style id="0" type="PARA" name="Normal" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langID="1042"/></hh:styles></hh:refList></hh:head>`;
230
+ const content = `<?xml version="1.0" encoding="UTF-8"?><opf:package xmlns:opf="${OPF}" version="1.0"><opf:metadata/><opf:manifest><opf:item id="header" href="header.xml" media-type="application/xml"/><opf:item id="section0" href="section0.xml" media-type="application/xml"/></opf:manifest><opf:spine><opf:itemref idref="header"/><opf:itemref idref="section0"/></opf:spine></opf:package>`;
231
+ return writeZip([
232
+ ['mimetype', 'application/hwp+zip'],
233
+ ['version.xml', '<?xml version="1.0" encoding="UTF-8"?><HWPVersion major="5" minor="0" micro="0" buildNumber="0"/>'],
234
+ ['META-INF/container.xml', '<?xml version="1.0" encoding="UTF-8"?><container xmlns="urn:oasis:names:tc:opendocument:xmlns:container"><rootfiles><rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/></rootfiles></container>'],
235
+ ['Contents/content.hpf', content], ['Contents/header.xml', header], ['Contents/section0.xml', section],
236
+ ]);
237
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
+ "name": "elanous-hwp",
4
+ "version": "0.1.0",
5
+ "main": "./plugin.ts",
6
+ "description": "Convert HWPX documents to Markdown and write minimal HWPX from Markdown; legacy HWP is not supported.",
7
+ "extensions": {
8
+ "ai.elanous": {
9
+ "capabilities": ["fs:workdir", "proc:bun"],
10
+ "connectors": [],
11
+ "pricing": { "model": "free" },
12
+ "trust": "official",
13
+ "category": "Productivity"
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,40 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import type { ElanousPlugin } from '../../src/plugins/core/types.js';
3
+ import { hwpxToMarkdown, markdownToHwpx } from './converter.js';
4
+
5
+ const plugin: ElanousPlugin = {
6
+ name: 'elanous-hwp',
7
+ version: '0.1.0',
8
+ description: 'Convert HWPX to Markdown and write minimal HWPX from Markdown.',
9
+ initialState: () => undefined,
10
+ panes: {},
11
+ llmTools: [
12
+ {
13
+ name: 'HwpxToMarkdown',
14
+ description: 'Read an HWPX ZIP document as Markdown (paragraphs, headings, tables). Legacy .hwp is unsupported.',
15
+ parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] },
16
+ async handler(args) {
17
+ const path = args.path;
18
+ if (typeof path !== 'string') throw new Error('path must be a string');
19
+ if (/\.hwp$/i.test(path)) throw new Error('HWP(옛 바이너리)는 지원 안 함 · hwpx 로 저장해 달라');
20
+ if (!/\.hwpx$/i.test(path)) throw new Error('Expected .hwpx input');
21
+ return { markdown: hwpxToMarkdown(readFileSync(path), path) };
22
+ },
23
+ },
24
+ {
25
+ name: 'MarkdownToHwpx',
26
+ description: 'Write paragraphs and headings from a Markdown file to a new HWPX ZIP document.',
27
+ parameters: { type: 'object', properties: { path: { type: 'string' }, output: { type: 'string' } }, required: ['path', 'output'] },
28
+ async handler(args) {
29
+ const { path, output } = args;
30
+ if (typeof path !== 'string' || typeof output !== 'string') throw new Error('path and output must be strings');
31
+ if (/\.hwp$/i.test(path) || /\.hwp$/i.test(output)) throw new Error('HWP(옛 바이너리)는 지원 안 함 · hwpx 로 저장해 달라');
32
+ if (!/\.md$/i.test(path) || !/\.hwpx$/i.test(output)) throw new Error('Expected .md input and .hwpx output');
33
+ writeFileSync(output, markdownToHwpx(readFileSync(path, 'utf8')), { flag: 'wx' });
34
+ return { output };
35
+ },
36
+ },
37
+ ],
38
+ };
39
+
40
+ export default plugin;
@@ -3,12 +3,15 @@
3
3
  * manifest transforms and private redactions applied, then the leak markers. A hit here fails the next prepare
4
4
  * (0.2.7: one test title), so `pr land` and the harness policy gates run it before landing.
5
5
  *
6
- * bun scripts/ci-public-export-leak-gate.ts --changed-files a b … # exit 1 on a hit · 0 when clean or not measurable
6
+ * bun scripts/ci-public-export-leak-gate.ts --changed-files a b … # exit 1 on a hit · 0 when clean
7
7
  */
8
8
  import { spawnSync } from 'node:child_process';
9
- import { existsSync } from 'node:fs';
10
- import { join, resolve } from 'node:path';
11
- import { privateRedactionsPath } from './public-export.js';
9
+ import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import { join, relative, resolve } from 'node:path';
12
+ import { stringify } from 'yaml';
13
+ import { computeSkillBoundaries, filterFilesBySkillVerdict } from './skill-boundary.js';
14
+ import { loadExportConfig, privateRedactionsPath, selectExportFiles } from './public-export.js';
12
15
 
13
16
  export interface ExportLeakCheck {
14
17
  readonly measured: boolean;
@@ -16,29 +19,87 @@ export interface ExportLeakCheck {
16
19
  readonly detail?: string;
17
20
  }
18
21
 
19
- export function exportLeakCheck(changedFiles: readonly string[], root: string): ExportLeakCheck {
22
+ /** Changed source paths that the public manifest would export; unknown skill boundaries remain in scope. */
23
+ export function publicExportChangedFiles(changedFiles: readonly string[], root: string): string[] {
24
+ const config = loadExportConfig(root);
25
+ const selected = [...new Set([
26
+ ...selectExportFiles(changedFiles, config),
27
+ ...changedFiles.filter((file) => Object.values(config.replace).includes(file)),
28
+ ])];
29
+ if (!config.skills || !selected.some((file) => file.startsWith('skills/'))) return selected;
30
+ try {
31
+ const boundary = computeSkillBoundaries(root);
32
+ if (boundary.errors.length) return selected;
33
+ return filterFilesBySkillVerdict(selected, boundary, config.skills);
34
+ } catch { return selected; }
35
+ }
36
+
37
+ export function exportLeakCheck(changedFiles: readonly string[], root: string, spawn: typeof spawnSync = spawnSync): ExportLeakCheck {
20
38
  const script = join(root, 'scripts', 'public-export.ts');
21
39
  if (!existsSync(script)) return { measured: false, hits: [], detail: 'scripts/public-export.ts 없음' };
22
40
  // Without the private table (a Pod, a fresh machine) the markers still run; private identifiers are not checked.
23
41
  const privateList = existsSync(privateRedactionsPath()) ? [] : ['--no-private-list'];
24
- const r = spawnSync('bun', [script, '--leak-check', '--json', '--all', ...privateList, '--files', ...changedFiles], { cwd: root, encoding: 'utf-8', timeout: 180_000, maxBuffer: 64 * 1024 * 1024 });
42
+ const args = ['--leak-check', '--json', '--all', ...privateList, '--files', ...changedFiles];
43
+ const run = (flags: string[]) => spawn('bun', [script, ...flags], { cwd: root, encoding: 'utf-8', timeout: 180_000, maxBuffer: 64 * 1024 * 1024 });
44
+ const initial = run(args);
45
+ if (initial.status !== 2) return measuredLeaks(initial);
46
+
47
+ const hits = [...String(initial.stderr).matchAll(/^⛔ skill boundary: ([^:\r\n]+):[^\r\n]*$/gm)]
48
+ .map((match) => ({ file: `skills/${match[1]}/SKILL.md`, line: 1, marker: 'skill-boundary' }));
49
+ if (!hits.length || !String(initial.stderr).trim().split(/\r?\n/).every((line) => /^⛔ skill boundary: [^:\r\n]+:[^\r\n]*$/.test(line))) {
50
+ return { measured: false, hits: [], detail: 'rc=2' };
51
+ }
52
+
53
+ // The exporter stops before scanning any changed file on a boundary error. Re-run its
54
+ // same transforms and leak check with only boundary selection disabled; retain the boundary hits.
55
+ let dir: string | undefined;
56
+ try {
57
+ const config = loadExportConfig(root);
58
+ dir = mkdtempSync(join(tmpdir(), 'public-export-leak-'));
59
+ const configPath = join(dir, 'export.yaml');
60
+ writeFileSync(configPath, stringify({ ...config, skills: undefined }));
61
+ const measured = measuredLeaks(run(['--config', relative(root, configPath), ...args]));
62
+ return { ...measured, hits: [...hits, ...measured.hits] };
63
+ } catch {
64
+ return { measured: false, hits, detail: 'skill boundary 뒤 재검사 실패' };
65
+ } finally {
66
+ if (dir) rmSync(dir, { recursive: true, force: true });
67
+ }
68
+ }
69
+
70
+ function measuredLeaks(r: ReturnType<typeof spawnSync>): ExportLeakCheck {
25
71
  if (r.status !== 0 && r.status !== 1) return { measured: false, hits: [], detail: `rc=${r.status ?? r.signal}` };
26
72
  try {
27
- const parsed = JSON.parse(String(r.stdout).trim().split('\n').at(-1) ?? '') as { hits?: Array<{ file: string; line: number; marker: string }> };
28
- return { measured: true, hits: (parsed.hits ?? []).map((h) => ({ file: h.file, line: h.line, marker: h.marker })) };
73
+ const parsed: unknown = JSON.parse(String(r.stdout).trim().split('\n').at(-1) ?? '');
74
+ if (!parsed || typeof parsed !== 'object' || !('hits' in parsed) || !Array.isArray(parsed.hits)
75
+ || parsed.hits.some((h: unknown) => !h || typeof h !== 'object'
76
+ || typeof (h as { file?: unknown }).file !== 'string'
77
+ || typeof (h as { line?: unknown }).line !== 'number'
78
+ || typeof (h as { marker?: unknown }).marker !== 'string')) throw new Error('invalid hits');
79
+ return { measured: true, hits: parsed.hits.map((h: { file: string; line: number; marker: string }) => ({ file: h.file, line: h.line, marker: h.marker })) };
29
80
  } catch { return { measured: false, hits: [], detail: 'JSON 을 못 읽었다' }; }
30
81
  }
31
82
 
32
- /** Gate form for the harness policy gates: 1 on a hit, 0 when clean or not measurable (said in a line). */
83
+ /** Gate form for the harness policy gates: 1 on a hit, 0 when clean (said in a line). */
33
84
  export function runPublicExportLeakGate(io: { args: readonly string[]; cwd: string; log: (line: string) => void; error: (line: string) => void }): number {
34
85
  const at = io.args.indexOf('--changed-files');
35
86
  const files = at >= 0 ? io.args.slice(at + 1).filter((a) => !a.startsWith('--')) : [];
36
87
  if (files.length === 0) return 0;
37
- const result = exportLeakCheck(files, io.cwd);
38
- if (!result.measured) { io.log(`⚠ public-export-leak: 못 쟀다(${result.detail ?? '?'})`); return 0; }
39
- if (result.hits.length === 0) return 0;
40
- io.error(`✗ public-export-leak: 바뀐 파일 ${result.hits.length}곳이 공개본에 사적 흔적을 싣는다 — 다음 release prepare 가 여기서 실패한다:`);
41
- for (const h of result.hits) io.error(` ${h.file}:${h.line} ${h.marker}`);
88
+ let result: ExportLeakCheck;
89
+ try { result = exportLeakCheck(files, io.cwd); }
90
+ catch { result = { measured: false, hits: [], detail: '검사 실행 실패' }; }
91
+ if (!result.measured) {
92
+ let publicFiles: string[];
93
+ try { publicFiles = publicExportChangedFiles(files, io.cwd); }
94
+ catch { publicFiles = files; }
95
+ if (publicFiles.length === 0) { io.log('⚠ public-export-leak: 못 쟀다 — 공개 대상 변경 없음'); return 0; }
96
+ io.error(`✗ public-export-leak: 못 쟀다 — 막는다(${result.detail ?? '?'})`);
97
+ return 1;
98
+ }
99
+ const hits = result.hits.filter((hit) => hit.marker !== 'skill-boundary' || files.includes(hit.file));
100
+ if (hits.length === 0) return 0;
101
+ io.error(`✗ public-export-leak: 바뀐 파일 ${hits.length}곳이 공개본에 사적 흔적을 싣는다 — 다음 release prepare 가 여기서 실패한다:`);
102
+ for (const h of hits) io.error(` ${h.file}:${h.line} · ${h.marker}`);
42
103
  io.error(' 그 줄에서 표식·홈 경로·내부 문서 이름을 빼라(주석이면 공개본 변환이 지우는지 bun scripts/public-export.ts --leak-check --files <파일> 로 확인).');
43
104
  return 1;
44
105
  }