elanous 0.2.12 → 0.2.14

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 (534) 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/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1307-6e7e0377c1db0bdc.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
  31. package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/{9906-482c6619b3fdda20.js → 8060-cc008cc6fedfa818.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
  42. package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-7b2b4f378354869a.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/page-1abfe3aec3be6bdc.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-1512d91c7491ed62.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-a627db94ec6904a0.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/control/page-e6b84ab07d3567d5.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/editor/page-fed69f9759d248d0.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/exec/{page-a67e11ba962337b5.js → page-15374909d8f1aebd.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/app/field/page-012a742f81218b01.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/intake/page-99effd9d893a43dc.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/layout-938de57ae0315e46.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/loops/page-160089123a40dd91.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/market/page-629e1ede482ec6eb.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-793fa536b3a6ef37.js → page-2ce5471926761fdd.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/app/morning/page-27e99b4e54a849d4.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-32cde713be47cddb.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e7e10cd3386222e5.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/reflection/page-e64caff084f7ce21.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-db07eaffba0df7e3.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e1e47d8d940aba3d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/settings/page-86f91034bd5cabe5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/share/page-ce4d8a1215ce53a3.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/showroom/page-58043db78ba519ae.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/tasks/page-357750dfb91bf960.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/term/{page-e297866051595d81.js → page-274703bc41b71333.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/vault/page-3b7e821dc492bdfd.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/workflows/page-f8da5dc6f3752276.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2f810b18d89ecba6.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  98. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
  104. package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +1 -0
  105. package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +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 -1
  134. package/apps/pwa/out/inside/index.txt +22 -22
  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/loops/index.html +1 -0
  140. package/apps/pwa/out/loops/index.txt +30 -0
  141. package/apps/pwa/out/market/index.html +1 -1
  142. package/apps/pwa/out/market/index.txt +22 -22
  143. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  144. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  145. package/apps/pwa/out/morning/index.html +1 -1
  146. package/apps/pwa/out/morning/index.txt +23 -23
  147. package/apps/pwa/out/observatory/index.html +1 -1
  148. package/apps/pwa/out/observatory/index.txt +23 -23
  149. package/apps/pwa/out/ops/checklist/index.html +1 -1
  150. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  151. package/apps/pwa/out/ops/release/index.html +1 -1
  152. package/apps/pwa/out/ops/release/index.txt +22 -22
  153. package/apps/pwa/out/ops/seats/index.html +1 -1
  154. package/apps/pwa/out/ops/seats/index.txt +22 -22
  155. package/apps/pwa/out/outputs/index.html +1 -1
  156. package/apps/pwa/out/outputs/index.txt +22 -22
  157. package/apps/pwa/out/reflection/index.html +1 -1
  158. package/apps/pwa/out/reflection/index.txt +23 -23
  159. package/apps/pwa/out/scheduler/index.html +1 -1
  160. package/apps/pwa/out/scheduler/index.txt +23 -23
  161. package/apps/pwa/out/sessions/index.html +1 -1
  162. package/apps/pwa/out/sessions/index.txt +22 -22
  163. package/apps/pwa/out/settings/devices/index.html +1 -1
  164. package/apps/pwa/out/settings/devices/index.txt +23 -23
  165. package/apps/pwa/out/settings/index.html +1 -1
  166. package/apps/pwa/out/settings/index.txt +23 -23
  167. package/apps/pwa/out/setup/done/index.html +1 -1
  168. package/apps/pwa/out/setup/done/index.txt +23 -23
  169. package/apps/pwa/out/setup/index.html +1 -1
  170. package/apps/pwa/out/setup/index.txt +23 -23
  171. package/apps/pwa/out/share/index.html +1 -1
  172. package/apps/pwa/out/share/index.txt +23 -23
  173. package/apps/pwa/out/showroom/index.html +1 -1
  174. package/apps/pwa/out/showroom/index.txt +22 -22
  175. package/apps/pwa/out/tasks/index.html +1 -1
  176. package/apps/pwa/out/tasks/index.txt +23 -23
  177. package/apps/pwa/out/term/index.html +1 -1
  178. package/apps/pwa/out/term/index.txt +23 -23
  179. package/apps/pwa/out/today/index.html +1 -1
  180. package/apps/pwa/out/today/index.txt +23 -23
  181. package/apps/pwa/out/trace/index.html +1 -1
  182. package/apps/pwa/out/trace/index.txt +23 -23
  183. package/apps/pwa/out/vault/index.html +1 -1
  184. package/apps/pwa/out/vault/index.txt +23 -23
  185. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  186. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  187. package/apps/pwa/out/workflows/index.html +1 -1
  188. package/apps/pwa/out/workflows/index.txt +23 -23
  189. package/apps/pwa/out/workspace/index.html +1 -1
  190. package/apps/pwa/out/workspace/index.txt +23 -23
  191. package/apps/pwa/out/worktrees/index.html +1 -1
  192. package/apps/pwa/out/worktrees/index.txt +23 -23
  193. package/examples/teams/personas/backend.yaml +4 -0
  194. package/examples/teams/personas/pm.yaml +4 -0
  195. package/examples/teams/personas/qa.yaml +4 -0
  196. package/examples/teams/small-product.yaml +20 -0
  197. package/graphs/lecture/lecture-note.yaml +28 -0
  198. package/graphs/lecture/recipes.yaml +17 -0
  199. package/graphs/orchestrator/orchestrator.yaml +59 -0
  200. package/graphs/orchestrator/recipes.yaml +18 -0
  201. package/graphs/release/recipes.yaml +3 -0
  202. package/graphs/release/release-loop.yaml +4 -1
  203. package/graphs/rhythm/daily.yaml +38 -0
  204. package/graphs/rhythm/recipes.yaml +18 -0
  205. package/graphs/rhythm/weekly.yaml +39 -0
  206. package/graphs/video/recipes.yaml +3 -0
  207. package/graphs/video/youtube-summary.yaml +17 -0
  208. package/package.json +2 -1
  209. package/scripts/audit-test-state-writes.ts +72 -17
  210. package/scripts/brand/check.ts +186 -0
  211. package/scripts/context-hooks/emit.ts +36 -14
  212. package/scripts/coord-channel-watch.sh +1 -0
  213. package/scripts/coord-post.sh +11 -1
  214. package/scripts/discord-seat-probe.ts +144 -0
  215. package/scripts/docs-cli-check.ts +23 -6
  216. package/scripts/expose-rubric-check.ts +118 -0
  217. package/scripts/expose-rubric-suggest.ts +163 -0
  218. package/scripts/heal/run-role.ts +14 -0
  219. package/scripts/hq/hq-standby.sh +65 -0
  220. package/scripts/hq/standby-promote.ts +173 -0
  221. package/scripts/hq/standby-role.ts +59 -0
  222. package/scripts/hq/standby-snapshot.ts +226 -0
  223. package/scripts/hq/standby-verify.ts +223 -0
  224. package/scripts/lecture-note/node.ts +256 -0
  225. package/scripts/lessons/handbook-page.ts +85 -0
  226. package/scripts/release-loop/gate-node.ts +62 -15
  227. package/scripts/release-loop/ops-upgrade-node.ts +17 -5
  228. package/scripts/release-loop/publish-node.ts +14 -1
  229. package/scripts/release-loop/unattended-release.ts +23 -1
  230. package/scripts/release-loop/vault-note-node.ts +196 -0
  231. package/scripts/release-story/draft.ts +172 -0
  232. package/scripts/rhythm/daily.ts +383 -0
  233. package/scripts/rhythm/weekly.ts +294 -0
  234. package/scripts/skills/public-check.ts +169 -0
  235. package/scripts/test-deterministic.ts +57 -11
  236. package/scripts/test-diet/effectiveness.ts +195 -0
  237. package/scripts/test-diet/lib.ts +16 -8
  238. package/scripts/test-diet/node.ts +77 -9
  239. package/scripts/ux/demo-rehearsal.ts +2 -2
  240. package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
  241. package/scripts/video/youtube-summary.ts +133 -0
  242. package/skills/diagram-master/SKILL.md +42 -49
  243. package/skills/diagram-master/references/pyproject.toml +4 -1
  244. package/skills/diagram-master/references/routing-guide.md +4 -2
  245. package/skills/grill-me/SKILL.md +1 -0
  246. package/skills/omni-crawl/SKILL.md +16 -16
  247. package/skills/omni-crawl/package-lock.json +1 -544
  248. package/skills/omni-crawl/package.json +3 -4
  249. package/skills/omni-crawl/scripts/main.ts +13 -13
  250. package/skills/omni-crawl/scripts/monitor.ts +8 -8
  251. package/skills/omni-crawl/src/apify.ts +13 -2
  252. package/skills/omni-crawl/src/capture.ts +6 -0
  253. package/skills/omni-crawl/src/registry.ts +2 -2
  254. package/skills/omni-crawl/src/stdout-json.ts +4 -0
  255. package/skills/omni-digest/SKILL.md +10 -11
  256. package/skills/omni-digest/package-lock.json +0 -545
  257. package/skills/omni-digest/package.json +2 -5
  258. package/skills/omni-digest/scripts/main.ts +3 -3
  259. package/skills/omni-digest/src/delegate.ts +5 -5
  260. package/skills/omni-digest/src/fetch.ts +2 -2
  261. package/skills/omni-digest/src/media.ts +25 -11
  262. package/skills/omni-digest/src/visual.ts +3 -2
  263. package/skills/omni-market/scripts/main.ts +1 -1
  264. package/skills/omni-market/scripts/stdout-json.ts +4 -0
  265. package/skills/youtube-master/SKILL.md +13 -13
  266. package/skills/youtube-master/package-lock.json +0 -545
  267. package/skills/youtube-master/package.json +2 -5
  268. package/skills/youtube-master/scripts/main.ts +2 -2
  269. package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
  270. package/skills/youtube-master/src/util.ts +30 -7
  271. package/src/agent/identity-env.ts +11 -0
  272. package/src/agent-mission/driver.ts +15 -10
  273. package/src/agent-mission/duo.ts +94 -0
  274. package/src/agent-mission/pty-decision.ts +1 -1
  275. package/src/autopilot/build/llm-conflict-merge.ts +45 -8
  276. package/src/autopilot/build/merge-intent.ts +53 -0
  277. package/src/autopilot/track-agent-shadow.ts +2 -1
  278. package/src/autopilot/track-agent.ts +4 -1
  279. package/src/boot/daemon-prompt-request.ts +3 -0
  280. package/src/boot/daemon-prompt-turn.ts +6 -2
  281. package/src/boot/daemon-runtime.ts +48 -16
  282. package/src/chat/index.ts +2 -0
  283. package/src/claims/claims-ledger.ts +232 -0
  284. package/src/claims/claims-render.ts +157 -0
  285. package/src/cli/claims-cli.ts +94 -0
  286. package/src/cli/decisions-cli.ts +84 -20
  287. package/src/cli/docs-cli.ts +2 -0
  288. package/src/cli/flow-cli.ts +11 -0
  289. package/src/cli/freeze-cli.ts +45 -0
  290. package/src/cli/lesson-cli.ts +108 -0
  291. package/src/cli/logs-cli.ts +104 -2
  292. package/src/cli/logs-model-input.ts +131 -0
  293. package/src/cli/outputs-cli.ts +92 -0
  294. package/src/cli/persona-cli.ts +29 -0
  295. package/src/cli/pod-cli.ts +10 -3
  296. package/src/cli/pr-cli.ts +44 -2
  297. package/src/cli/private-ledger-commands.ts +54 -4
  298. package/src/cli/pty-drive-verdict.ts +11 -2
  299. package/src/cli/release-cli.ts +248 -45
  300. package/src/cli/rfc-status.ts +91 -0
  301. package/src/connectors/linear.ts +5 -3
  302. package/src/context-bus/condense.ts +189 -0
  303. package/src/context-bus/context-day.ts +82 -0
  304. package/src/context-bus/context-now-public.ts +86 -0
  305. package/src/context-bus/context-now-surfaces.ts +70 -4
  306. package/src/context-bus/context-now.ts +4 -3
  307. package/src/context-bus/long-term-memory.ts +201 -24
  308. package/src/context-bus/nightly-condense.ts +1 -1
  309. package/src/dashboard/index.ts +75 -22
  310. package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
  311. package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
  312. package/src/dashboard/slash-runtime/loops-table.ts +77 -0
  313. package/src/decisions/decision-cards.ts +13 -7
  314. package/src/decisions/decision-ledger.ts +83 -18
  315. package/src/discord/sprint21-runtime.ts +16 -0
  316. package/src/discord-self-message.ts +8 -0
  317. package/src/discord-slash-wire.ts +31 -2
  318. package/src/domains/outbound-alert.ts +1 -1
  319. package/src/elanous-config-dir.ts +29 -4
  320. package/src/execution-loop/launch-gate.ts +29 -14
  321. package/src/flow/cards.ts +239 -0
  322. package/src/graph-kinds/registry.ts +2 -2
  323. package/src/graph-runner/graph-approval-card.ts +2 -2
  324. package/src/graph-runner/graph-grow.ts +64 -11
  325. package/src/graph-runner/graph-tick.ts +13 -2
  326. package/src/graph-runner/runner.ts +111 -22
  327. package/src/harness/harness-cli-command.ts +178 -27
  328. package/src/harness/harness-incidents.ts +43 -12
  329. package/src/harness/harness-pod-dispatch.ts +2 -0
  330. package/src/harness/harness-queue-child.ts +37 -0
  331. package/src/harness/harness-queue.ts +494 -0
  332. package/src/harness/helper-scan.ts +139 -0
  333. package/src/harness/model-input-observation.ts +37 -0
  334. package/src/hooks/github-shadow.ts +72 -2
  335. package/src/hooks/receiver.ts +4 -2
  336. package/src/hq/hq.ts +318 -0
  337. package/src/hq/lease.ts +210 -0
  338. package/src/hq/ledger-write-target.ts +41 -0
  339. package/src/hq/promote.ts +301 -0
  340. package/src/index.ts +281 -27
  341. package/src/intake-plane/discord-seat-work.ts +13 -6
  342. package/src/intake-plane/linear-wish.ts +72 -0
  343. package/src/intake-plane/persona-answer.ts +5 -0
  344. package/src/intake-plane/telegram-seat-work.ts +13 -6
  345. package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
  346. package/src/intake-plane/wish-card.ts +53 -2
  347. package/src/intake-plane/wish-folder.ts +5 -2
  348. package/src/intake-plane/wish-reply.ts +72 -0
  349. package/src/lessons/lesson-import.ts +106 -0
  350. package/src/lessons/lesson-ledger.ts +206 -0
  351. package/src/loops/activity.ts +203 -0
  352. package/src/loops/budget.ts +32 -0
  353. package/src/loops/checker.ts +180 -0
  354. package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
  355. package/src/loops/loop-cli.ts +72 -6
  356. package/src/loops/neighbors.ts +40 -0
  357. package/src/loops/observe.ts +59 -0
  358. package/src/loops/orchestrator/author-depth.ts +164 -0
  359. package/src/loops/orchestrator/author-input-check.ts +77 -0
  360. package/src/loops/orchestrator/author-ledger.ts +230 -0
  361. package/src/loops/orchestrator/finish-rate.ts +175 -0
  362. package/src/loops/orchestrator/overlap.ts +180 -0
  363. package/src/loops/orchestrator/resync-shadow.ts +227 -0
  364. package/src/loops/orchestrator/tick.ts +302 -0
  365. package/src/loops/orchestrator/traffic.ts +165 -0
  366. package/src/loops/package/verify.ts +125 -0
  367. package/src/loops/registry.ts +454 -9
  368. package/src/loops/status-rows.ts +118 -0
  369. package/src/loops/verdict.ts +34 -0
  370. package/src/maturity/bot-slash-catalog.ts +66 -0
  371. package/src/maturity/feature-maturity.ts +8 -5
  372. package/src/memory.ts +37 -4
  373. package/src/nexus/api/card-followup-route.ts +118 -0
  374. package/src/nexus/api/dashboard.ts +6 -1
  375. package/src/nexus/api/decisions-route.ts +68 -0
  376. package/src/nexus/api/http-server.ts +65 -2
  377. package/src/nexus/api/merge-approvals-gate.ts +1 -1
  378. package/src/nexus/api/personas.ts +2 -1
  379. package/src/nexus/api/schedules-read.ts +5 -1
  380. package/src/nexus/api/skill-exec-route.ts +97 -0
  381. package/src/nexus/api/task-cards-api.ts +44 -5
  382. package/src/nexus/api/workflows.ts +2 -1
  383. package/src/persona/loader.ts +18 -0
  384. package/src/persona/persona-todo.ts +14 -9
  385. package/src/persona/presets.ts +2 -1
  386. package/src/persona/team.ts +105 -0
  387. package/src/persona/types.ts +4 -0
  388. package/src/pod-lease/host-lease.ts +130 -20
  389. package/src/release-loop/auto-start.ts +48 -0
  390. package/src/release-loop/checklist.ts +13 -4
  391. package/src/release-loop/feature-store.ts +28 -16
  392. package/src/release-loop/landed-but-yellow.ts +12 -0
  393. package/src/release-loop/landing-freeze.ts +121 -0
  394. package/src/release-loop/placement.ts +242 -0
  395. package/src/release-loop/release-schedule.ts +3 -1
  396. package/src/seat-dispatch/ceo-commands.ts +2 -2
  397. package/src/seat-dispatch/seat-ask.ts +73 -15
  398. package/src/seat-dispatch/seat-questions.ts +58 -0
  399. package/src/seat-loop/seat-loop.ts +495 -46
  400. package/src/seat-loop/seat-pack.ts +127 -0
  401. package/src/self-dev/ask-launch-flow.ts +3 -0
  402. package/src/self-dev/dev-pipeline.ts +6 -2
  403. package/src/self-dev/draft-sweep.ts +76 -0
  404. package/src/self-dev/run-store.ts +73 -1
  405. package/src/self-dev/run-supervisor.ts +8 -0
  406. package/src/self-dev/self-orchestrate-runtime.ts +5 -1
  407. package/src/self-implement/budget-gate.ts +29 -0
  408. package/src/self-implement/expose-gate.ts +47 -0
  409. package/src/self-implement/frozen-merges.ts +294 -0
  410. package/src/self-implement/gate-cli.ts +10 -4
  411. package/src/self-implement/gate-scope.ts +46 -9
  412. package/src/self-implement/goal-archive.ts +222 -0
  413. package/src/self-implement/goal-lookup.ts +147 -0
  414. package/src/self-implement/heal-intake.ts +79 -0
  415. package/src/self-implement/host-regate.ts +25 -2
  416. package/src/self-implement/l8-merge-queue.ts +157 -1
  417. package/src/self-implement/orchestrator.ts +114 -10
  418. package/src/self-implement/revert-guard.ts +62 -0
  419. package/src/self-implement/run-ledger.ts +1 -1
  420. package/src/self-implement/seams.ts +28 -8
  421. package/src/session/index.ts +2 -0
  422. package/src/steward/launch.ts +5 -1
  423. package/src/steward/readiness.ts +125 -0
  424. package/src/steward/rescue.ts +75 -0
  425. package/src/steward/triage.ts +48 -9
  426. package/src/task-cards/card-cli.ts +86 -0
  427. package/src/task-cards/card-store.ts +10 -6
  428. package/src/task-orchestrator/surfaces/pod-lease.ts +23 -8
  429. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
  430. package/src/task-orchestrator/surfaces/pod-pool.ts +27 -10
  431. package/src/task-orchestrator/surfaces/self-implement-pod.ts +112 -18
  432. package/src/telegram-commands.ts +27 -3
  433. package/src/telegram-dispatch-forward.ts +1 -1
  434. package/src/telegram-fabric-plan.ts +90 -0
  435. package/src/telegram-loops-command.ts +44 -0
  436. package/src/telegram-project-command.ts +10 -4
  437. package/src/telegram.ts +5 -0
  438. package/src/tool-runtime/elanous-control-runtimes.ts +2 -1
  439. package/src/user-config.ts +204 -16
  440. package/src/version/packed-revision.json +1 -1
  441. package/src/workflow-runtime/executor.ts +4 -0
  442. package/src/workflow-runtime/node-catalog.ts +13 -0
  443. package/src/workflow-runtime/nodes/knowledge.ts +38 -0
  444. package/src/workflow-runtime/schema.ts +17 -1
  445. package/src/workflow-runtime/storage.ts +31 -13
  446. package/src/workflow-runtime/types.ts +13 -1
  447. package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +0 -25
  459. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
  463. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5c05b0da4bc1392c.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
  533. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
  534. /package/apps/pwa/out/_next/static/{-6XrAoD3eU7NyMHAE4xPS → x6mjI6vqOkVVu0jFuDkz1}/_ssgManifest.js +0 -0
@@ -0,0 +1,131 @@
1
+ import { existsSync } from 'node:fs';
2
+ import type { LogStoreRow } from '../mss/logging/log-store.js';
3
+ import { LogStore } from '../mss/logging/log-store.js';
4
+ import type { ModelInputObservation } from '../harness/model-input-observation.js';
5
+ import { collectDegenerateRows } from './logs-degenerate.js';
6
+ import { parseSince, resolveLogTargets } from './logs-cli.js';
7
+
8
+ const DAY_MS = 86_400_000;
9
+ const CATEGORY = 'harness.model-input';
10
+ const EVENT = 'recorded';
11
+
12
+ type Baseline = { scope: ModelInputObservation['scope']; nodeKind: string; measured: number; unmeasured: number; median: number | null; p90: number | null };
13
+ export interface ModelInputReport {
14
+ since: string;
15
+ until: string;
16
+ stores: string[];
17
+ records: number;
18
+ baselines: Baseline[];
19
+ }
20
+ export interface LogsModelInputOpts {
21
+ since?: string;
22
+ json?: boolean;
23
+ test?: boolean;
24
+ instance?: string;
25
+ all?: boolean;
26
+ includeTest?: boolean;
27
+ }
28
+ export interface LogsModelInputDeps {
29
+ exists: typeof existsSync;
30
+ openReadOnly: typeof LogStore.openReadOnly;
31
+ resolveTargets: typeof resolveLogTargets;
32
+ now: () => number;
33
+ write: (line: string) => void;
34
+ writeError: (line: string) => void;
35
+ }
36
+ const DEFAULT_DEPS: LogsModelInputDeps = {
37
+ exists: existsSync, openReadOnly: LogStore.openReadOnly, resolveTargets: resolveLogTargets,
38
+ now: Date.now, write: console.log, writeError: console.error,
39
+ };
40
+
41
+ /** Only observations with a known state enter the baseline; unavailable usage is not zero. */
42
+ export function summarizeModelInput(rows: readonly LogStoreRow[], since: string, until: string, stores: string[]): ModelInputReport {
43
+ const groups = new Map<string, { scope: Baseline['scope']; nodeKind: string; values: number[]; unmeasured: number }>();
44
+ let records = 0;
45
+ for (const row of rows) {
46
+ if (row.category !== CATEGORY || row.event !== EVENT || !row.data) continue;
47
+ let data: unknown;
48
+ try { data = JSON.parse(row.data); } catch { continue; }
49
+ if (!data || typeof data !== 'object' || Array.isArray(data)) continue;
50
+ const observation = data as Partial<ModelInputObservation>;
51
+ if ((observation.scope !== 'harness-node' && observation.scope !== 'loop-tick')
52
+ || typeof observation.nodeKind !== 'string' || !observation.nodeKind.trim()) continue;
53
+ const measured = observation.status === 'measured'
54
+ && typeof observation.inputTokens === 'number'
55
+ && Number.isSafeInteger(observation.inputTokens) && observation.inputTokens >= 0;
56
+ const unmeasured = observation.status === 'unmeasured' && observation.inputTokens === null;
57
+ if (!measured && !unmeasured) continue;
58
+ const key = JSON.stringify([observation.scope, observation.nodeKind]);
59
+ const group = groups.get(key) ?? { scope: observation.scope, nodeKind: observation.nodeKind, values: [], unmeasured: 0 };
60
+ if (measured) group.values.push(observation.inputTokens as number);
61
+ else group.unmeasured += 1;
62
+ groups.set(key, group);
63
+ records += 1;
64
+ }
65
+ const baselines = [...groups.values()].map(({ scope, nodeKind, values, unmeasured }): Baseline => {
66
+ values.sort((a, b) => a - b);
67
+ const n = values.length;
68
+ return {
69
+ scope, nodeKind, measured: n, unmeasured,
70
+ median: n === 0 ? null : n % 2 === 1 ? values[Math.floor(n / 2)]! : (values[n / 2 - 1]! + values[n / 2]!) / 2,
71
+ p90: n === 0 ? null : values[Math.ceil(n * 0.9) - 1]!,
72
+ };
73
+ }).sort((a, b) => a.scope.localeCompare(b.scope) || a.nodeKind.localeCompare(b.nodeKind));
74
+ return { since, until, stores, records, baselines };
75
+ }
76
+
77
+ export function renderModelInput(report: ModelInputReport): string {
78
+ return [
79
+ `model input tokens · ${report.since} ~ ${report.until} · stores=${report.stores.join(', ') || '(없음)'} · records=${report.records}`,
80
+ 'scope\tnodeKind\tmeasured\tmedian\tp90\t못 잼',
81
+ ...(report.baselines.length === 0 ? ['(관측 표본 없음)'] : report.baselines.map((item) =>
82
+ `${item.scope}\t${item.nodeKind}\t${item.measured}\t${item.median ?? '—'}\t${item.p90 ?? '—'}\t${item.unmeasured}`)),
83
+ ].join('\n');
84
+ }
85
+
86
+ /** Read the entire bounded time window rather than just the newest default page. */
87
+ export function runLogsModelInput(opts: LogsModelInputOpts, deps: LogsModelInputDeps = DEFAULT_DEPS): number {
88
+ const untilMs = deps.now();
89
+ const relative = opts.since === undefined ? null : /^(\d+)(s|m|h|d)$/.exec(opts.since.trim());
90
+ const unitMs = { s: 1_000, m: 60_000, h: 3_600_000, d: DAY_MS };
91
+ const sinceMs = opts.since === undefined ? untilMs - 3 * DAY_MS
92
+ : relative ? untilMs - Number(relative[1]) * unitMs[relative[2] as keyof typeof unitMs]
93
+ : parseSince(opts.since);
94
+ if (sinceMs === null || !Number.isFinite(sinceMs) || sinceMs > untilMs) {
95
+ deps.writeError('elanous logs model-input: --since 파싱 불가 또는 미래 시각 (예: 3d, ISO)');
96
+ return 1;
97
+ }
98
+ const resolved = deps.resolveTargets({ test: opts.test, instance: opts.instance, all: opts.all, includeTest: opts.includeTest });
99
+ if (resolved.error) { deps.writeError(`elanous logs model-input: ${resolved.error}`); return 1; }
100
+ const rows: LogStoreRow[] = [];
101
+ const stores: string[] = [];
102
+ // Without a stable observation ID, equal timestamps and payloads in different
103
+ // stores may belong to distinct executions. Count every stored record.
104
+ for (const target of resolved.targets) {
105
+ if (!deps.exists(target.dbPath)) {
106
+ deps.writeError(`elanous logs model-input: 로그 스토어 없음: ${target.name} (${target.dbPath})`);
107
+ return 1;
108
+ }
109
+ let store: LogStore;
110
+ try { store = deps.openReadOnly(target.dbPath); }
111
+ catch (error) {
112
+ deps.writeError(`elanous logs model-input: ${target.name} 열기 실패: ${String(error)}`);
113
+ return 1;
114
+ }
115
+ try {
116
+ const scan = collectDegenerateRows(store, { exactCategories: [CATEGORY], events: [EVENT], sinceMs, untilMs });
117
+ if (scan.truncated) {
118
+ deps.writeError(`elanous logs model-input: ${target.name} 스캔 상한 도달 — --since 창을 좁혀라`);
119
+ return 1;
120
+ }
121
+ stores.push(target.name);
122
+ rows.push(...scan.rows);
123
+ } catch (error) {
124
+ deps.writeError(`elanous logs model-input: ${target.name} 조회 실패: ${String(error)}`);
125
+ return 1;
126
+ } finally { store.close(); }
127
+ }
128
+ const report = summarizeModelInput(rows, new Date(sinceMs).toISOString(), new Date(untilMs).toISOString(), stores);
129
+ deps.write(opts.json ? JSON.stringify(report) : renderModelInput(report));
130
+ return 0;
131
+ }
@@ -0,0 +1,92 @@
1
+ import { accessSync, constants, readdirSync, statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import type { Command } from 'commander';
4
+ import { debug } from '../debug/log.js';
5
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
6
+ import type { OutputEntry } from '../outputs/ledger.js';
7
+ import { writeStdoutJson } from './stdout-json.js';
8
+
9
+ type ListOptions = { since?: string; source?: string; limit?: string; json?: boolean };
10
+
11
+ function sinceIso(value: string): string {
12
+ if (value === '24h' || value === '7d') {
13
+ return new Date(Date.now() - (value === '24h' ? 24 : 7 * 24) * 60 * 60 * 1000).toISOString();
14
+ }
15
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/.test(value)
16
+ || !Number.isFinite(Date.parse(value))
17
+ || new Date(`${value.slice(0, 10)}T00:00:00Z`).toISOString().slice(0, 10) !== value.slice(0, 10)) {
18
+ throw new Error(`invalid --since: ${value} (ISO|24h|7d)`);
19
+ }
20
+ return new Date(value).toISOString();
21
+ }
22
+
23
+ // listOutputs intentionally tolerates unreadable months. Detect inaccessible ledger files here so the CLI
24
+ // does not report an incomplete read as a genuine zero (including when run as root under chmod 000).
25
+ function assertReadableLedger(root: string): void {
26
+ const dir = join(root, 'outputs');
27
+ let names: string[];
28
+ try {
29
+ const info = statSync(dir);
30
+ if (!info.isDirectory() || (info.mode & 0o444) === 0 || (info.mode & 0o111) === 0) {
31
+ throw new Error(`outputs ledger directory unreadable: ${dir}`);
32
+ }
33
+ accessSync(dir, constants.R_OK | constants.X_OK);
34
+ names = readdirSync(dir);
35
+ } catch (error) {
36
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;
37
+ throw error;
38
+ }
39
+ for (const name of names.filter(name => /^outputs-\d{4}-(0[1-9]|1[0-2])\.jsonl$/.test(name) || name === 'outputs.jsonl')) {
40
+ const file = join(dir, name);
41
+ const info = statSync(file);
42
+ if (!info.isFile() || (info.mode & 0o444) === 0) throw new Error(`outputs ledger file unreadable: ${file}`);
43
+ accessSync(file, constants.R_OK);
44
+ }
45
+ }
46
+
47
+ export function registerOutputsCommands(program: Command): void {
48
+ program.command('outputs').description('산출물 원장 조회 (읽기 전용)')
49
+ .command('list').description('산출물 최신순 목록과 종류별 수')
50
+ .option('--since <ISO|24h|7d>', '이 시각 이후')
51
+ .option('--source <source>', 'exec|field-reel|field-feed')
52
+ .option('--limit <N>', '최대 건수 (기본 50)', '50')
53
+ .option('--json', 'JSON 출력')
54
+ .action(async (options: ListOptions) => {
55
+ try {
56
+ if (options.source !== undefined && !['exec', 'field-reel', 'field-feed'].includes(options.source)) {
57
+ throw new Error(`invalid --source: ${options.source} (exec|field-reel|field-feed)`);
58
+ }
59
+ if (!options.limit || !/^[1-9]\d*$/.test(options.limit) || !Number.isSafeInteger(Number(options.limit))) {
60
+ throw new Error(`invalid --limit: ${options.limit}`);
61
+ }
62
+ const scope = {
63
+ since: options.since === undefined ? undefined : sinceIso(options.since),
64
+ source: options.source as OutputEntry['source'] | undefined,
65
+ limit: Number(options.limit),
66
+ };
67
+ const displayedScope = { since: scope.since ?? null, source: scope.source ?? null, limit: scope.limit };
68
+ const root = effectiveInstanceRoot();
69
+ assertReadableLedger(root);
70
+ const { listOutputs } = await import('../outputs/ledger.js');
71
+ const items = listOutputs(scope, root);
72
+ const byKind: Record<string, number> = {};
73
+ for (const item of items) byKind[item.kind] = (byKind[item.kind] ?? 0) + 1;
74
+ debug.log('outputs.cli', 'list', { count: items.length, source: scope.source, since: scope.since });
75
+ if (options.json) {
76
+ await writeStdoutJson(`${JSON.stringify({ items, count: items.length, byKind, scope: displayedScope })}\n`);
77
+ return;
78
+ }
79
+ for (const item of items) {
80
+ const at = Number.isFinite(Date.parse(item.at))
81
+ ? new Intl.DateTimeFormat('sv-SE', { timeZone: 'Asia/Seoul', dateStyle: 'short', timeStyle: 'medium', hourCycle: 'h23' }).format(new Date(item.at))
82
+ : item.at;
83
+ console.log(`${at} KST · ${item.kind} · ${item.title} · ${item.source}/${item.sourceId} · ${item.seat ?? '—'} · ${item.path ?? item.url ?? '—'}`);
84
+ }
85
+ if (!items.length) console.log(`scope: ${JSON.stringify(displayedScope)}`);
86
+ console.log(`${items.length}개 · 종류별 수 ${JSON.stringify(byKind)}`);
87
+ } catch (error) {
88
+ console.error(`outputs list: ${error instanceof Error ? error.message : String(error)}`);
89
+ process.exitCode = 1;
90
+ }
91
+ });
92
+ }
@@ -9,6 +9,8 @@ import { parsePersonaYaml } from '../persona/loader.js';
9
9
  import { resolveRepositoryPersonaDir, resolveStatePersonaDir } from '../persona/global-registry.js';
10
10
  import { UnknownPersonaSchemaKeyError, choosePersonaId, clonePreset, describePreset, editPersona, findPreset, loadPresetIndex, loadPresets, presetToProfileYaml } from '../persona/presets.js';
11
11
  import { addTeamSet, listTeamSets, removeTeamSet } from '../persona/team-set.js';
12
+ import { validateTeamFile } from '../persona/team.js';
13
+ import { runPersonaLoopOnce } from '../seat-loop/seat-loop.js';
12
14
 
13
15
  interface StoredPersona { personaId: string; displayName: string; description?: string; preset?: string; title?: string; path: string }
14
16
 
@@ -68,6 +70,18 @@ function editOptions(fromFile: string | undefined, assignments: readonly string[
68
70
  }
69
71
 
70
72
  export function registerPersonaCommands(program: Command): void {
73
+ program.command('team').description('Validate a YAML team definition')
74
+ .command('validate <file>').description('Check team schema, persona references and handoff order')
75
+ .action((file: string) => {
76
+ try {
77
+ const definition = validateTeamFile(file);
78
+ console.log(`Valid team ${definition.name}`);
79
+ } catch (error) {
80
+ console.error(error instanceof Error ? error.message.replace(/\s+/g, ' ').trim() : String(error));
81
+ process.exitCode = 2;
82
+ }
83
+ });
84
+
71
85
  const team = program.command('team-set').description('Install, remove and list persona team sets');
72
86
  team.command('add <file>').description('Install a YAML team set').action((file: string) => {
73
87
  try { const result = addTeamSet(file); console.log(`Installed team-set ${result['team-set']}`); }
@@ -178,6 +192,21 @@ export function registerPersonaCommands(program: Command): void {
178
192
  }
179
193
  });
180
194
 
195
+ persona.command('loop <name>')
196
+ .description('Shadow-pick one todo for a saved persona without executing it')
197
+ .requiredOption('--once', 'Pick exactly one todo')
198
+ .option('--json', 'JSON output')
199
+ .action(async (name: string, opts: { json?: boolean }) => {
200
+ try {
201
+ const entry = await runPersonaLoopOnce(name);
202
+ if (opts.json) console.log(JSON.stringify(entry));
203
+ else console.log(entry.todo ? `그림자 선택 — ${entry.todo.title} (${entry.todo.id})` : '할 일 없음');
204
+ } catch (error) {
205
+ console.error(error instanceof Error ? error.message : String(error));
206
+ process.exitCode = 1;
207
+ }
208
+ });
209
+
181
210
  persona.command('show <name>')
182
211
  .description('Show one of your personas (id or name), or a preset')
183
212
  .option('--json', 'JSON output')
@@ -6,9 +6,10 @@ import { debug } from '../debug/log.js';
6
6
  import { readPodMemoryAdvice } from './pod-memory-advice.js';
7
7
  import { getUserConfig } from '../user-config.js';
8
8
  import { listCodexAccountsInStore } from '../oauth/codex-account-store.js';
9
- import { parsePodPool, resolvePodPoolSpec, type PoolKubectl } from '../task-orchestrator/surfaces/pod-pool.js';
9
+ import { parsePodPool, resolvePodPoolSpec, podPoolHostLease, type PoolKubectl } from '../task-orchestrator/surfaces/pod-pool.js';
10
10
  import { leaseKubectl, measurePoolLease, probePoolDns, recommendConcurrency, type PoolLeaseMeasure, type PoolDnsProbe } from '../task-orchestrator/surfaces/pod-lease.js';
11
11
  import { POD_COMMAND_DEADLINE_SECONDS, runPodCommand, type PodCommandResult, type RunPodCommandOptions } from '../task-orchestrator/surfaces/pod-command-job.js';
12
+ import { hostLeaseCounts, leaseHasPendingPod } from '../pod-lease/host-lease.js';
12
13
 
13
14
  export interface PodCliIo {
14
15
  log: (line: string) => void;
@@ -78,8 +79,13 @@ export function registerPodCommands(program: Command, deps: PodCliDeps = {}): vo
78
79
  const perAccount = (deps.perAccount ?? (() => getUserConfig().pod?.lease?.perAccount ?? 4))();
79
80
  const decision = recommendConcurrency(measure, { capacity: members.reduce((sum, m) => sum + m.capacity, 0), accounts: accounts ?? -1, perAccount });
80
81
  if (!context) { decision.recommended = null; decision.limitedBy = null; decision.reason = '측정 불가: cluster (current context)'; }
81
- const result = { pool: spec, ...measure, accounts, perAccount, ...decision };
82
- debug.log('pod.lease', 'status', { pool: spec ? members.map((m) => ({ capacity: m.capacity })) : null, running: decision.running, pending: decision.pending, unleasedRunning: decision.unleasedRunning, recommended: decision.recommended, limitedBy: decision.limitedBy });
82
+ const records = members.length ? podPoolHostLease(members).live() : [];
83
+ const host = hostLeaseCounts(records);
84
+ // Pending Pods and Job-only reservations are disjoint; a lease for an already Pending Job is the same Job.
85
+ const waitingJobs = decision.pending === null ? null : decision.pending +
86
+ records.filter((r) => r.stage === 'job' && !leaseHasPendingPod(r, decision.pendingJobs ?? [])).length;
87
+ const result = { pool: spec, ...measure, accounts, perAccount, ...decision, reserved: host.reserved, waitingJobs };
88
+ debug.log('pod.lease', 'status', { pool: spec ? members.map((m) => ({ capacity: m.capacity })) : null, running: decision.running, pending: decision.pending, reserved: host.reserved, waitingJobs, unleasedRunning: decision.unleasedRunning, recommended: decision.recommended, limitedBy: decision.limitedBy });
83
89
  if (opts.json) io.log(JSON.stringify(result));
84
90
  else {
85
91
  io.log(`풀: ${(spec ?? context) || '?'}`);
@@ -89,6 +95,7 @@ export function registerPodCommands(program: Command, deps: PodCliDeps = {}): vo
89
95
  io.log(`${m.context} | ${m.capacity} | ${m.running ?? '?'} | ${m.pending ?? '?'} | ${mem(m.memoryLimitBytes)}/${mem(m.allocatableMemoryBytes)} | ${m.allocatableCpuMillicores === null ? '?' : m.allocatableCpuMillicores / 1000}${m.reason ? ` (${m.reason})` : ''}`);
90
96
  }
91
97
  io.log(`권장 지금 ${decision.recommended ?? '?'} 개 더 (limitedBy=${decision.limitedBy ?? 'unknown'})${decision.reason ? ` · ${decision.reason}` : ''}`);
98
+ io.log(`예약(저작 중) ${host.reserved} · 대기 Job ${waitingJobs ?? '?'} · 실행 ${decision.running ?? '?'}`);
92
99
  io.log(`임대 없는 실행 ${decision.unleasedRunning ?? '?'}`);
93
100
  io.log(`capacity: ${decision.capacitySlots ?? '?'} 칸 (상한 ${members.reduce((sum, m) => sum + m.capacity, 0)} − Running ${decision.running ?? '?'} − Pending ${decision.pending ?? '?'}; 권장 수에서 건강한 멤버의 임대 없는 실행 차감)`);
94
101
  io.log(`memory: ${decision.memorySlots ?? '?'} 칸 (할당 가능 − Running 하니스 상한 합; 골당 16Gi · 모든 네임스페이스의 노드별 기존 예약을 반영해 배치 가능 ${decision.placeableSlots ?? '?'} 칸)`);
package/src/cli/pr-cli.ts CHANGED
@@ -53,6 +53,9 @@ import {
53
53
  } from './pr-granularity.js';
54
54
  import { branchLineageSlug, findSiblingPrs } from './pr-lineage.js';
55
55
  import { parseReleaseNoteSection } from '../release-loop/release-note.js';
56
+ import { landingFreezeMessage } from '../release-loop/landing-freeze.js';
57
+ import { admitLandingMerge } from '../self-implement/frozen-merges.js';
58
+ import { enqueueL8ShadowQueue, runL8ShadowQueue, shadowPrNumber, statusL8ShadowQueue, type L8ShadowQueueDeps } from '../self-implement/l8-merge-queue.js';
56
59
 
57
60
  export { branchLineageSlug, findSiblingPrs };
58
61
 
@@ -1573,7 +1576,32 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1573
1576
  return 0;
1574
1577
  }
1575
1578
 
1576
- let merged = manager.mergePrOutcome(upsert.url);
1579
+ const prNumber = Number(/\/(\d+)$/.exec(upsert.url)?.[1]);
1580
+ const landedHead = run('git', ['rev-parse', 'HEAD'], { cwd });
1581
+ const headCommit = landedHead.ok && /^[a-f0-9]{40}$/i.test(landedHead.out.trim()) ? landedHead.out.trim() : undefined;
1582
+ const validPr = Number.isSafeInteger(prNumber) && prNumber > 0;
1583
+ const heldEntry = validPr && headCommit ? { prNumber, headCommit, repoRoot: cwd } : null;
1584
+ const admission = admitLandingMerge(heldEntry, undefined, {}, validPr ? { prNumber, repoRoot: cwd, ...(headCommit ? { headCommit } : {}) } : undefined);
1585
+ if (admission.kind === 'held' && !heldEntry) {
1586
+ out.error(`✗ freeze: ready PR의 검증 HEAD/번호를 보존하지 못했습니다: ${upsert.url}`);
1587
+ return 1;
1588
+ }
1589
+ if (admission.kind === 'held') {
1590
+ const frozen = admission.freeze;
1591
+ debug.log('harness.merge', 'frozen', { prUrl: upsert.url, reason: frozen.reason, until: frozen.until });
1592
+ record('freeze', true, { url: upsert.url, reason: frozen.reason, until: frozen.until });
1593
+ out.log(`✓ ready: ${upsert.url} — ${landingFreezeMessage(frozen)} · 병합 연기`);
1594
+ return 0;
1595
+ }
1596
+ if (admission.kind === 'taken') {
1597
+ record('freeze', true, { url: upsert.url, resumedElsewhere: true });
1598
+ out.log(`✓ ready: ${upsert.url} — 동결이 막 풀려 보류 병합 재개가 이 PR 을 맡았습니다`);
1599
+ return 0;
1600
+ }
1601
+ const landing = admission;
1602
+ let merged: ReturnType<typeof manager.mergePrOutcome>;
1603
+ try {
1604
+ merged = manager.mergePrOutcome(upsert.url);
1577
1605
  // `GIT-S14` — 병합이 «미완료(OPEN)»로 끝났고 GitHub 가 아직 `mergeable=UNKNOWN`(병합 가능 여부 계산 중)이면
1578
1606
  // 짧게 기다렸다 다시 병합한다. 표본 셋(08-25 · 09-24 🅢 #20233 등)이 모두 «같은 명령 재시도에 병합»이었다.
1579
1607
  // ⛔ UNKNOWN 일 때만 재시도한다 — CONFLICTING 등 다른 값은 기다려도 안 풀린다(그대로 실패를 낸다).
@@ -1587,6 +1615,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1587
1615
  await sleep(PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS);
1588
1616
  merged = manager.mergePrOutcome(upsert.url);
1589
1617
  }
1618
+ } finally { landing.end(merged!?.ok === true); }
1590
1619
  if (!merged.ok) {
1591
1620
  // `GIT-S76` — 「미완료(OPEN)」만으로는 «충돌»과 «아직 계산 중»이 안 갈린다. GitHub 의 병합 가능 상태를 같이 싣는다.
1592
1621
  // 되읽기에 실패하면 종전 문면 그대로다(못 읽은 것을 「충돌 아님」으로 적지 않는다).
@@ -1635,8 +1664,21 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1635
1664
  return 0;
1636
1665
  }
1637
1666
 
1638
- export function registerPrCommands(program: Command, deps: PrLandDeps = {}): void {
1667
+ export function registerPrCommands(program: Command, deps: PrLandDeps = {}, queueDeps: L8ShadowQueueDeps = {}): void {
1639
1668
  const pr = program.command('pr').description('PR landing commands');
1669
+ const queue = pr.command('queue').description('Shadow merge queue (never lands PRs)');
1670
+ const queueAction = async (action: () => Promise<unknown>) => {
1671
+ try {
1672
+ (deps.out ?? liveOut).log(JSON.stringify(await action()));
1673
+ } catch (error) {
1674
+ (deps.out ?? liveOut).error(`✗ merge-queue: ${String(error)}`);
1675
+ (deps.setExitCode ?? ((code: number) => { process.exitCode = code; }))(1);
1676
+ }
1677
+ };
1678
+ queue.command('status').description('Show pending PRs and shadow verdicts').action(() => queueAction(() => statusL8ShadowQueue(process.cwd(), queueDeps)));
1679
+ queue.command('enqueue <pr>').description('Pin a ready PR at the tail of the shadow queue').action((prNumber: string) => queueAction(() => enqueueL8ShadowQueue(process.cwd(), shadowPrNumber(prNumber), queueDeps)));
1680
+ queue.command('run').description('Evaluate the first PR without merging').requiredOption('--shadow', 'Only evaluate; never land').action(() => queueAction(() => runL8ShadowQueue(process.cwd(), queueDeps)));
1681
+
1640
1682
  pr.command('land')
1641
1683
  .description('현재 브랜치 PR을 생성 또는 갱신해 ready 상태로 만들고 squash merge')
1642
1684
  .option('--base <branch>', 'PR base branch')
@@ -1,11 +1,32 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { Command } from 'commander';
4
+ import { elanousStateRoot } from '../autopilot/state-paths.js';
5
+ import { debug } from '../debug/log.js';
6
+ import { hqCliWriteAllowed, type HqDeps } from '../hq/hq.js';
7
+ import { isIsolatedLedgerWriteRoot } from '../hq/ledger-write-target.js';
4
8
 
5
- // Private local ledgers (decisions · directives) are absent from the public export;
9
+ // Private local ledgers (decisions · directives · claims · lesson) are absent from the public export;
6
10
  // JS-only distributions still register them. Kept out of src/index.ts so the `self`
7
11
  // block stays free of direct sink registration (see self-cli-sink-surface.test.ts).
8
- export function registerPrivateLedgerCommands(program: Command): void {
12
+ const privateLedgerWrites: Record<string, readonly string[]> = {
13
+ claims: ['add', 'verify', 'publish', 'link', 'retract', 'list', 'show', 'render', 'recheck'], // list/show can mark expired evidence stale
14
+ lesson: ['add', 'recur', 'enforce', 'promote'],
15
+ directives: ['sync', 'search', 'list'], // search/list refresh the persistent index too
16
+ };
17
+
18
+ function mayWritePrivateLedger(name: string, args: readonly string[], hqDeps: HqDeps, ledgerRoot: string): boolean {
19
+ const action = args[0];
20
+ if (!action || !privateLedgerWrites[name]?.includes(action)) return true;
21
+ const command = `${name} ${action}`;
22
+ if (isIsolatedLedgerWriteRoot(ledgerRoot)) {
23
+ try { debug.log('hq.fence', 'skipped-isolated', { root: ledgerRoot, command }); } catch { /* observation is fail-soft */ }
24
+ return true;
25
+ }
26
+ return hqCliWriteAllowed(command, false, hqDeps);
27
+ }
28
+
29
+ export function registerPrivateLedgerCommands(program: Command, hqDeps: HqDeps = {}, ledgerRoot = elanousStateRoot()): void {
9
30
  if (existsSync(resolve(import.meta.dir, 'decisions-cli.ts')) || existsSync(resolve(import.meta.dir, 'decisions-cli.js'))) {
10
31
  program.command('decisions').description('대표 결정 로컬 원장').allowUnknownOption().allowExcessArguments(true)
11
32
  .action(async (_opts: unknown, command: Command) => {
@@ -18,13 +39,42 @@ export function registerPrivateLedgerCommands(program: Command): void {
18
39
  await privateProgram.parseAsync(['decisions', ...command.args], { from: 'user' });
19
40
  });
20
41
  }
42
+ if (existsSync(resolve(import.meta.dir, 'claims-cli.ts')) || existsSync(resolve(import.meta.dir, 'claims-cli.js'))) {
43
+ program.command('claims').description('소구점 실측 근거 로컬 원장').allowUnknownOption().allowExcessArguments(true)
44
+ .addHelpText('after', '\n add <id> 주장 등록\n verify <id> 실측 근거 기록\n publish <id> 유효 근거로 공개\n link <id> 체크리스트 연결\n retract <id> 소구점 철회\n list 소구점 목록\n show <id> 근거·연결·이력 보기\n render deck·site·notice 문면 생성\n recheck 낡은 근거 재측 요청\n\n각 명령의 옵션: elanous claims <명령> --help')
45
+ .action(async (_opts: unknown, command: Command) => {
46
+ if (!mayWritePrivateLedger('claims', command.args, hqDeps, ledgerRoot)) return;
47
+ try { await (await import('../domains/standalone-log-sink.js')).registerStandaloneLogSink('claims'); }
48
+ catch { /* Logging must not prevent recording a claim. */ }
49
+ const privateClaimsModule: string = './claims-cli.js';
50
+ const { registerClaimsCommands } = await import(privateClaimsModule) as { registerClaimsCommands: (program: Command, options: { stateDir: string; instanceRoot: string }) => void };
51
+ const privateProgram = new Command();
52
+ registerClaimsCommands(privateProgram, { stateDir: ledgerRoot, instanceRoot: ledgerRoot });
53
+ await privateProgram.parseAsync(['claims', ...command.args], { from: 'user' });
54
+ });
55
+ }
56
+ if (existsSync(resolve(import.meta.dir, 'lesson-cli.ts')) || existsSync(resolve(import.meta.dir, 'lesson-cli.js'))) {
57
+ program.command('lesson').description('교훈 · 재발 로컬 원장').allowUnknownOption().allowExcessArguments(true)
58
+ .addHelpText('after', '\n import 문서 교훈 미리 보기 (--apply 로 적재)\n add <id> 사고·원인·처방 등록\n recur <id> 재발 기록\n enforce <id> 강제 자리 기록\n promote <id> 규칙 경로 기록\n find <query> 교훈 검색\n show <id> 발생·이력 보기\n candidates 반복 교훈 목록\n\n각 명령의 옵션: elanous lesson <명령> --help')
59
+ .action(async (_opts: unknown, command: Command) => {
60
+ if (!mayWritePrivateLedger('lesson', command.args, hqDeps, ledgerRoot)) return;
61
+ try { await (await import('../domains/standalone-log-sink.js')).registerStandaloneLogSink('lesson'); }
62
+ catch { /* Logging must not prevent recording a lesson. */ }
63
+ const privateLessonModule: string = './lesson-cli.js';
64
+ const { registerLessonCommands } = await import(privateLessonModule) as { registerLessonCommands: (program: Command, options: { stateDir: string }) => void };
65
+ const privateProgram = new Command();
66
+ registerLessonCommands(privateProgram, { stateDir: ledgerRoot });
67
+ await privateProgram.parseAsync(['lesson', ...command.args], { from: 'user' });
68
+ });
69
+ }
21
70
  if (existsSync(resolve(import.meta.dir, 'directives-cli.ts')) || existsSync(resolve(import.meta.dir, 'directives-cli.js'))) {
22
71
  program.command('directives').description('대표 지시 로컬 색인·검색').allowUnknownOption().allowExcessArguments(true)
23
72
  .action(async (_opts: unknown, command: Command) => {
73
+ if (!mayWritePrivateLedger('directives', command.args, hqDeps, ledgerRoot)) return;
24
74
  const privateDirectivesModule: string = './directives-cli.js';
25
- const { registerDirectivesCommands } = await import(privateDirectivesModule) as { registerDirectivesCommands: (program: Command) => void };
75
+ const { registerDirectivesCommands } = await import(privateDirectivesModule) as { registerDirectivesCommands: (program: Command, options: { stateDir: string }) => void };
26
76
  const privateProgram = new Command();
27
- registerDirectivesCommands(privateProgram);
77
+ registerDirectivesCommands(privateProgram, { stateDir: ledgerRoot });
28
78
  await privateProgram.parseAsync(['directives', ...command.args], { from: 'user' });
29
79
  });
30
80
  }
@@ -8,6 +8,8 @@ export interface FinalPtyEvidence {
8
8
  readonly screen: string;
9
9
  readonly inputHistory: readonly string[];
10
10
  readonly exitCode: number | null;
11
+ /** A separately verified mission artifact; tool-history failures are not final-answer failures. */
12
+ readonly artifactEvidence?: boolean;
11
13
  }
12
14
 
13
15
  // eslint-disable-next-line no-control-regex
@@ -16,7 +18,7 @@ const FAILURE = /(?:\bcommand not found\b|\bnot recognized as (?:an internal or
16
18
  const SUCCESS = /(?:\b[1-9]\d*\s+(?:pass|passed)\b|\btests?:\s*[1-9]\d*\s+passed\b|\bbuild successful\b|\b(?:successfully|succeeded)\b|\bGOAL-COMPLETE\b)/i;
17
19
 
18
20
  /** Failure wins over success; an exit code of zero is not itself proof of the goal. */
19
- export function verdictForFinalPtyScreen({ screen, inputHistory, exitCode }: FinalPtyEvidence): PtyDriveVerdict {
21
+ export function verdictForFinalPtyScreen({ screen, inputHistory, exitCode, artifactEvidence = false }: FinalPtyEvidence): PtyDriveVerdict {
20
22
  if (exitCode !== null && exitCode !== 0) {
21
23
  return { kind: 'done-but-failed', reason: `child exit code ${exitCode}`, evidence: null };
22
24
  }
@@ -32,7 +34,14 @@ export function verdictForFinalPtyScreen({ screen, inputHistory, exitCode }: Fin
32
34
  }));
33
35
  const lines = screen.replace(ANSI, '').replace(/\r/g, '\n').split('\n')
34
36
  .map((line) => line.trim()).filter((line) => line && !inputs.has(line) && !echoedLiterals.has(line) && ![...inputs].some((input) => line.endsWith(`$ ${input}`) || line.endsWith(`> ${input}`)));
35
- const failure = lines.find((line) => FAILURE.test(line));
37
+ const toolNoMatch = (line: string) =>
38
+ /\b(?:rg|grep|diff)\b.*\bexit(?:ed)?\s*(?:with\s*)?(?:code\s*)?1\b|\bexit(?:ed)?\s*(?:with\s*)?(?:code\s*)?1\b.*\b(?:rg|grep|diff)\b/i.test(line)
39
+ && !/(?:\b(?:error|fatal|exception)\s*:|\b(?:build failed|tests? failed|failed to|permission denied|command not found)\b)/i.test(line);
40
+ // Codex renders tool status as «• Failed (exit 1) …». It is not the agent's final answer.
41
+ // For artifact-backed missions, consider only answer text following the last tool block.
42
+ const lastTool = artifactEvidence ? lines.reduce((index, line, i) => /^•\s+(?:Ran|Failed|Running|Worked)\b/i.test(line) ? i : index, -1) : -1;
43
+ const answer = lastTool < 0 ? lines : lines.slice(lastTool + 1).filter((line) => !/^[└│]/.test(line));
44
+ const failure = (artifactEvidence ? answer : lines).find((line) => FAILURE.test(line) && !toolNoMatch(line));
36
45
  if (failure) return { kind: 'done-but-failed', reason: failure, evidence: null };
37
46
  const evidence = lines.find((line) => SUCCESS.test(line) && !/\b0\s+(?:pass|passed)\b/i.test(line));
38
47
  if (evidence) return { kind: 'success', reason: 'final PTY screen has success evidence', evidence };