elanous 0.2.13 → 0.2.15

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 (524) 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/LZcstaO9_NXypPFmujolv/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1307-33ffcc49ab45123b.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
  10. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.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-c952712c87a1f757.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/8060-cc008cc6fedfa818.js +1 -0
  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/899-46946fe8363e1262.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0e2c57fe6add4b2a.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e05a77df7e005b04.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/bots/page-b8c49f6b4fa2df91.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/chat/page-976813c91d7394ea.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/control/page-1d4901eb7c2d8822.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/design-check/page-72d3e7ff35a8c954.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/editor/page-60c7a8e1a4fe62ce.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a52b316cb143d9c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/field/page-c3ce483c8d5db370.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/intake/page-96f074f6538e8a2c.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/layout-e97be5334d83a9f5.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-c1343f9499d86f3f.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-8739a2e0ae793130.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-d23b12bb92242558.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c7fea475488201a8.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-5efbf81124c474ae.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-06ee266953d9c879.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-153c2b3bcc89e8de.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-0d6d23b40263a7ea.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-f5597e894c02cd33.js} +1 -1
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-73735b64bfe1ae67.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f7e631e9b4daf66e.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9817c7f9007466cc.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
  106. package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +1 -0
  107. package/apps/pwa/out/approvals/index.html +1 -1
  108. package/apps/pwa/out/approvals/index.txt +23 -23
  109. package/apps/pwa/out/autopilot/index.html +1 -1
  110. package/apps/pwa/out/autopilot/index.txt +23 -23
  111. package/apps/pwa/out/board/index.html +1 -1
  112. package/apps/pwa/out/board/index.txt +23 -23
  113. package/apps/pwa/out/botlab/index.html +1 -1
  114. package/apps/pwa/out/botlab/index.txt +22 -22
  115. package/apps/pwa/out/bots/index.html +1 -1
  116. package/apps/pwa/out/bots/index.txt +22 -22
  117. package/apps/pwa/out/ceo/index.html +1 -0
  118. package/apps/pwa/out/ceo/index.txt +33 -0
  119. package/apps/pwa/out/chat/index.html +1 -1
  120. package/apps/pwa/out/chat/index.txt +22 -22
  121. package/apps/pwa/out/consult/index.html +1 -1
  122. package/apps/pwa/out/consult/index.txt +23 -23
  123. package/apps/pwa/out/control/index.html +1 -1
  124. package/apps/pwa/out/control/index.txt +23 -23
  125. package/apps/pwa/out/design-check/index.html +1 -1
  126. package/apps/pwa/out/design-check/index.txt +23 -23
  127. package/apps/pwa/out/editor/index.html +1 -1
  128. package/apps/pwa/out/editor/index.txt +23 -23
  129. package/apps/pwa/out/exec/index.html +1 -1
  130. package/apps/pwa/out/exec/index.txt +23 -23
  131. package/apps/pwa/out/field/index.html +1 -1
  132. package/apps/pwa/out/field/index.txt +23 -23
  133. package/apps/pwa/out/healthz +1 -1
  134. package/apps/pwa/out/index.html +1 -1
  135. package/apps/pwa/out/index.txt +22 -22
  136. package/apps/pwa/out/inside/index.html +1 -1
  137. package/apps/pwa/out/inside/index.txt +22 -22
  138. package/apps/pwa/out/intake/index.html +1 -1
  139. package/apps/pwa/out/intake/index.txt +23 -23
  140. package/apps/pwa/out/live/index.html +1 -1
  141. package/apps/pwa/out/live/index.txt +23 -23
  142. package/apps/pwa/out/loops/index.html +1 -0
  143. package/apps/pwa/out/loops/index.txt +30 -0
  144. package/apps/pwa/out/market/index.html +1 -1
  145. package/apps/pwa/out/market/index.txt +22 -22
  146. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  147. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  148. package/apps/pwa/out/morning/index.html +1 -1
  149. package/apps/pwa/out/morning/index.txt +23 -23
  150. package/apps/pwa/out/observatory/index.html +1 -1
  151. package/apps/pwa/out/observatory/index.txt +23 -23
  152. package/apps/pwa/out/ops/checklist/index.html +1 -1
  153. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  154. package/apps/pwa/out/ops/release/index.html +1 -1
  155. package/apps/pwa/out/ops/release/index.txt +22 -22
  156. package/apps/pwa/out/ops/seats/index.html +1 -1
  157. package/apps/pwa/out/ops/seats/index.txt +22 -22
  158. package/apps/pwa/out/outputs/index.html +1 -1
  159. package/apps/pwa/out/outputs/index.txt +22 -22
  160. package/apps/pwa/out/reflection/index.html +1 -1
  161. package/apps/pwa/out/reflection/index.txt +23 -23
  162. package/apps/pwa/out/scheduler/index.html +1 -1
  163. package/apps/pwa/out/scheduler/index.txt +23 -23
  164. package/apps/pwa/out/sessions/index.html +1 -1
  165. package/apps/pwa/out/sessions/index.txt +22 -22
  166. package/apps/pwa/out/settings/devices/index.html +1 -1
  167. package/apps/pwa/out/settings/devices/index.txt +23 -23
  168. package/apps/pwa/out/settings/index.html +1 -1
  169. package/apps/pwa/out/settings/index.txt +23 -23
  170. package/apps/pwa/out/setup/done/index.html +1 -1
  171. package/apps/pwa/out/setup/done/index.txt +23 -23
  172. package/apps/pwa/out/setup/index.html +1 -1
  173. package/apps/pwa/out/setup/index.txt +23 -23
  174. package/apps/pwa/out/share/index.html +1 -1
  175. package/apps/pwa/out/share/index.txt +23 -23
  176. package/apps/pwa/out/showroom/index.html +1 -1
  177. package/apps/pwa/out/showroom/index.txt +22 -22
  178. package/apps/pwa/out/tasks/index.html +1 -1
  179. package/apps/pwa/out/tasks/index.txt +23 -23
  180. package/apps/pwa/out/term/index.html +1 -1
  181. package/apps/pwa/out/term/index.txt +23 -23
  182. package/apps/pwa/out/today/index.html +1 -1
  183. package/apps/pwa/out/today/index.txt +23 -23
  184. package/apps/pwa/out/trace/index.html +1 -1
  185. package/apps/pwa/out/trace/index.txt +23 -23
  186. package/apps/pwa/out/vault/index.html +1 -1
  187. package/apps/pwa/out/vault/index.txt +23 -23
  188. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  189. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  190. package/apps/pwa/out/workflows/index.html +1 -1
  191. package/apps/pwa/out/workflows/index.txt +23 -23
  192. package/apps/pwa/out/workspace/index.html +1 -1
  193. package/apps/pwa/out/workspace/index.txt +23 -23
  194. package/apps/pwa/out/worktrees/index.html +1 -1
  195. package/apps/pwa/out/worktrees/index.txt +23 -23
  196. package/graphs/heal/heal-loop.yaml +1 -1
  197. package/graphs/implement-loop.yaml +1 -1
  198. package/graphs/orchestrator/orchestrator.yaml +59 -0
  199. package/graphs/orchestrator/recipes.yaml +18 -0
  200. package/graphs/release/recipes.yaml +6 -0
  201. package/graphs/release/release-loop.yaml +6 -1
  202. package/graphs/rhythm/daily.yaml +38 -0
  203. package/graphs/rhythm/recipes.yaml +18 -0
  204. package/graphs/rhythm/weekly.yaml +39 -0
  205. package/graphs/video/recipes.yaml +3 -0
  206. package/graphs/video/youtube-summary.yaml +17 -0
  207. package/package.json +1 -1
  208. package/scripts/audit-test-state-writes.ts +72 -17
  209. package/scripts/brand/check.ts +188 -0
  210. package/scripts/ci-typecheck-changed.ts +50 -18
  211. package/scripts/coord-post.sh +11 -1
  212. package/scripts/docs/generate-graph-anatomy.ts +315 -0
  213. package/scripts/docs-cli-check.ts +23 -6
  214. package/scripts/expose-rubric-check.ts +118 -0
  215. package/scripts/expose-rubric-suggest.ts +169 -0
  216. package/scripts/heal/run-role.ts +14 -0
  217. package/scripts/hq/standby-verify.ts +11 -7
  218. package/scripts/lecture-note/node.ts +31 -11
  219. package/scripts/lessons/handbook-page.ts +112 -0
  220. package/scripts/marketing/generate-ax-brief.ts +140 -0
  221. package/scripts/marketing/generate-feature-map.ts +118 -0
  222. package/scripts/release-loop/checklist-gate-node.ts +53 -14
  223. package/scripts/release-loop/gate-node.ts +89 -14
  224. package/scripts/release-loop/publish-node.ts +14 -1
  225. package/scripts/release-loop/unattended-release.ts +23 -1
  226. package/scripts/release-loop/vault-note-node.ts +428 -0
  227. package/scripts/release-story/draft.ts +220 -0
  228. package/scripts/rhythm/daily.ts +570 -0
  229. package/scripts/rhythm/weekly.ts +315 -0
  230. package/scripts/skills/public-check.ts +169 -0
  231. package/scripts/smart-merge/resync-shadow.ts +147 -0
  232. package/scripts/test-deterministic.ts +4 -8
  233. package/scripts/test-diet/effectiveness.ts +195 -0
  234. package/scripts/test-diet/lib.ts +16 -8
  235. package/scripts/test-diet/node.ts +77 -9
  236. package/scripts/ux/demo-rehearsal.ts +2 -2
  237. package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
  238. package/scripts/video/youtube-summary.ts +133 -0
  239. package/skills/diagram-master/SKILL.md +42 -49
  240. package/skills/diagram-master/references/pyproject.toml +4 -1
  241. package/skills/diagram-master/references/routing-guide.md +4 -2
  242. package/skills/grill-me/SKILL.md +1 -0
  243. package/skills/youtube-master/SKILL.md +13 -13
  244. package/skills/youtube-master/package-lock.json +0 -545
  245. package/skills/youtube-master/package.json +2 -5
  246. package/skills/youtube-master/scripts/main.ts +2 -2
  247. package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
  248. package/skills/youtube-master/src/util.ts +30 -7
  249. package/src/agent-env/profile.ts +161 -0
  250. package/src/agent-mission/driver.ts +3 -3
  251. package/src/agent-substrate/pr-reviewer.ts +2 -0
  252. package/src/ask-user-question/pending-questions.ts +5 -0
  253. package/src/auth/github-app-token.ts +112 -13
  254. package/src/autopilot/build/llm-conflict-merge.ts +73 -10
  255. package/src/autopilot/build/merge-intent.ts +53 -0
  256. package/src/briefing/brief-items.ts +121 -0
  257. package/src/chat/index.ts +2 -0
  258. package/src/claims/claims-ledger.ts +232 -0
  259. package/src/claims/claims-render.ts +166 -0
  260. package/src/cli/agent-env-cli.ts +21 -0
  261. package/src/cli/claims-cli.ts +94 -0
  262. package/src/cli/decisions-cli.ts +44 -3
  263. package/src/cli/docs-cli.ts +2 -0
  264. package/src/cli/doctor-cli.ts +23 -1
  265. package/src/cli/doctor-node-modules.ts +147 -0
  266. package/src/cli/flow-cli.ts +11 -0
  267. package/src/cli/freeze-cli.ts +45 -0
  268. package/src/cli/intake-cli.ts +46 -17
  269. package/src/cli/lesson-cli.ts +108 -0
  270. package/src/cli/logs-cli.ts +104 -2
  271. package/src/cli/logs-model-input.ts +131 -0
  272. package/src/cli/pod-cli.ts +2 -0
  273. package/src/cli/pr-cli.ts +29 -1
  274. package/src/cli/private-ledger-commands.ts +54 -4
  275. package/src/cli/pty-drive-verdict.ts +11 -2
  276. package/src/cli/release-cli.ts +190 -33
  277. package/src/cli/rfc-status.ts +91 -0
  278. package/src/cli/seat-requests-cli.ts +52 -0
  279. package/src/connectors/linear.ts +5 -3
  280. package/src/context-bus/condense.ts +15 -20
  281. package/src/context-bus/context-now-public.ts +96 -0
  282. package/src/context-bus/context-now-surfaces.ts +55 -2
  283. package/src/context-bus/context-now.ts +6 -3
  284. package/src/context-bus/coord-events.ts +6 -4
  285. package/src/context-bus/long-term-memory.ts +92 -11
  286. package/src/dashboard/index.ts +75 -22
  287. package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
  288. package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
  289. package/src/dashboard/slash-runtime/loops-table.ts +77 -0
  290. package/src/decisions/decision-cards.ts +33 -7
  291. package/src/decisions/decision-ledger.ts +40 -1
  292. package/src/decisions/proact-meter.ts +286 -0
  293. package/src/decisions/proact1-lite.ts +86 -0
  294. package/src/decisions/web-push-decision-cards.ts +1 -1
  295. package/src/discord/sprint21-runtime.ts +16 -0
  296. package/src/discord-self-message.ts +8 -0
  297. package/src/discord-slash-wire.ts +31 -2
  298. package/src/domains/alert-audit.ts +271 -0
  299. package/src/domains/core-tools.ts +4 -3
  300. package/src/domains/ops-facts-tool.ts +31 -1
  301. package/src/domains/outbound-alert.ts +1 -1
  302. package/src/elanous-config-dir.ts +29 -4
  303. package/src/execution-loop/launch-gate.ts +29 -14
  304. package/src/flow/cards.ts +239 -0
  305. package/src/graph-runner/graph-tick.ts +4 -0
  306. package/src/graph-runner/runner.ts +30 -5
  307. package/src/harness/harness-cli-command.ts +259 -38
  308. package/src/harness/harness-incidents.ts +45 -12
  309. package/src/harness/harness-pod-dispatch.ts +102 -11
  310. package/src/harness/harness-queue-child.ts +3 -3
  311. package/src/harness/harness-queue.ts +583 -65
  312. package/src/harness/helper-repair.ts +87 -0
  313. package/src/harness/helper-scan.ts +151 -0
  314. package/src/harness/launch-stamp.ts +236 -0
  315. package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
  316. package/src/harness/ledger-write-guard.ts +35 -0
  317. package/src/harness/model-input-observation.ts +37 -0
  318. package/src/harness/pod-memory-policy.ts +15 -0
  319. package/src/harness/repository-name.ts +55 -0
  320. package/src/hq/fence-audit.ts +90 -0
  321. package/src/hq/hq.ts +63 -5
  322. package/src/hq/lease.ts +4 -4
  323. package/src/hq/move-plan.ts +126 -0
  324. package/src/hq/promote.ts +332 -0
  325. package/src/index.ts +159 -27
  326. package/src/intake-plane/check.ts +63 -0
  327. package/src/intake-plane/digest.ts +37 -15
  328. package/src/intake-plane/front-classifier.ts +6 -0
  329. package/src/intake-plane/items.ts +3 -2
  330. package/src/intake-plane/lens.ts +177 -0
  331. package/src/intake-plane/linear-wish.ts +39 -11
  332. package/src/intake-plane/route.ts +145 -1
  333. package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
  334. package/src/intake-plane/wish-card.ts +53 -2
  335. package/src/intake-plane/wish-folder.ts +5 -2
  336. package/src/intake-plane/wish-reply.ts +72 -0
  337. package/src/launch-head/seat-goal-queue-lock.fixture.ts +15 -0
  338. package/src/launch-head/seat-goal-queue.ts +198 -0
  339. package/src/lessons/lesson-import.ts +106 -0
  340. package/src/lessons/lesson-ledger.ts +206 -0
  341. package/src/loops/activity.ts +203 -0
  342. package/src/loops/budget.ts +63 -0
  343. package/src/loops/checker.ts +5 -3
  344. package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
  345. package/src/loops/loop-cli.ts +36 -4
  346. package/src/loops/neighbors.ts +40 -0
  347. package/src/loops/observe.ts +10 -0
  348. package/src/loops/orchestrator/author-depth.ts +220 -0
  349. package/src/loops/orchestrator/author-input-check.ts +82 -0
  350. package/src/loops/orchestrator/author-ledger.ts +232 -0
  351. package/src/loops/orchestrator/finish-rate.ts +175 -0
  352. package/src/loops/orchestrator/overlap.ts +51 -12
  353. package/src/loops/orchestrator/resync-shadow.ts +227 -0
  354. package/src/loops/orchestrator/seat-share.ts +56 -0
  355. package/src/loops/orchestrator/tick.ts +309 -0
  356. package/src/loops/orchestrator/traffic.ts +134 -13
  357. package/src/loops/registry.ts +535 -9
  358. package/src/loops/status-rows.ts +118 -0
  359. package/src/loops/verdict.ts +17 -5
  360. package/src/maturity/bot-slash-catalog.ts +66 -0
  361. package/src/maturity/feature-maturity.ts +9 -5
  362. package/src/maturity/tui-slash-availability.ts +31 -0
  363. package/src/mss/logging/log-store.ts +35 -4
  364. package/src/nexus/api/dashboard.ts +6 -1
  365. package/src/nexus/api/http-server.ts +33 -3
  366. package/src/nexus/api/loop-edges.ts +173 -0
  367. package/src/nexus/api/merge-approvals-gate.ts +1 -1
  368. package/src/nexus/api/schedules-read.ts +18 -1
  369. package/src/nexus/api/seat-requests.ts +79 -56
  370. package/src/nexus/api/task-cards-api.ts +44 -5
  371. package/src/nexus/api/workflows.ts +2 -1
  372. package/src/prompt-enhance/enhance.ts +6 -1
  373. package/src/release-loop/auto-start.ts +51 -0
  374. package/src/release-loop/checklist.ts +22 -4
  375. package/src/release-loop/feature-store.ts +71 -32
  376. package/src/release-loop/landing-freeze.ts +121 -0
  377. package/src/release-loop/merged-pr-checklist.ts +125 -0
  378. package/src/release-loop/placement.ts +302 -0
  379. package/src/release-loop/release-schedule.ts +3 -1
  380. package/src/seat-dispatch/ceo-commands.ts +2 -2
  381. package/src/seat-dispatch/seat-ask.ts +16 -3
  382. package/src/seat-dispatch/seat-questions.ts +58 -0
  383. package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
  384. package/src/seat-dispatch/seat-request-ledger.ts +133 -0
  385. package/src/seat-loop/seat-loop.ts +531 -40
  386. package/src/self-dev/dev-pipeline.ts +14 -6
  387. package/src/self-dev/draft-sweep.ts +162 -6
  388. package/src/self-dev/draft-triage-rules.ts +25 -8
  389. package/src/self-dev/orchestrate.ts +15 -1
  390. package/src/self-dev/review-provider-fallback.ts +6 -1
  391. package/src/self-dev/run-store.ts +73 -1
  392. package/src/self-dev/run-supervisor.ts +57 -2
  393. package/src/self-dev/self-orchestrate-runtime.ts +5 -1
  394. package/src/self-implement/budget-gate.ts +29 -0
  395. package/src/self-implement/expose-gate.ts +47 -0
  396. package/src/self-implement/frozen-merges.ts +295 -0
  397. package/src/self-implement/gate-cli.ts +10 -4
  398. package/src/self-implement/gate-scope.ts +46 -9
  399. package/src/self-implement/goal-archive.ts +222 -0
  400. package/src/self-implement/goal-author.ts +43 -5
  401. package/src/self-implement/goal-clarification-escalation.ts +5 -0
  402. package/src/self-implement/goal-lookup.ts +147 -0
  403. package/src/self-implement/heal-intake.ts +197 -0
  404. package/src/self-implement/host-regate.ts +32 -2
  405. package/src/self-implement/l8-merge-queue.ts +132 -0
  406. package/src/self-implement/orchestrator.ts +299 -48
  407. package/src/self-implement/pipeline-shape.ts +1 -1
  408. package/src/self-implement/revert-guard.ts +97 -0
  409. package/src/self-implement/run-ledger.ts +3 -1
  410. package/src/self-implement/run-status-mapping.ts +2 -0
  411. package/src/self-implement/seams.ts +29 -9
  412. package/src/self-implement/self-implement-cli.ts +1 -0
  413. package/src/self-implement/speed-claims.ts +338 -0
  414. package/src/session/index.ts +2 -0
  415. package/src/steward/triage.ts +74 -3
  416. package/src/steward/working-backwards.ts +4 -1
  417. package/src/task-cards/card-cli.ts +10 -2
  418. package/src/task-cards/card-store.ts +10 -6
  419. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
  420. package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
  421. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
  422. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  423. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
  424. package/src/task-orchestrator/surfaces/pod-pool.ts +60 -8
  425. package/src/task-orchestrator/surfaces/self-implement-pod.ts +224 -49
  426. package/src/task-orchestrator/surfaces/self-implement.ts +5 -1
  427. package/src/telegram-commands.ts +27 -3
  428. package/src/telegram-loops-command.ts +44 -0
  429. package/src/telegram.ts +25 -4
  430. package/src/user-config.ts +146 -18
  431. package/src/version/packed-revision.json +1 -1
  432. package/src/workflow-runtime/nodes/bash.ts +9 -1
  433. package/src/workflow-runtime/storage.ts +31 -13
  434. package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
  445. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
  449. package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f14987d5850a31e0.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66c27608f651b866.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-78b40a344ed22f24.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
  523. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
  524. /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → LZcstaO9_NXypPFmujolv}/_ssgManifest.js +0 -0
@@ -14,7 +14,7 @@
14
14
  // 같은 케이던스). 레벨 제어만 데몬 REST(/v1/logs/level — 런타임 상태라 프로세스
15
15
  // 경유 필수). 설계: 내부 문서 `PLAN-unified-log-fabric-2026-07-13` §LF3.
16
16
 
17
- import { existsSync, readFileSync } from 'node:fs';
17
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
18
18
  import type { Command } from 'commander';
19
19
  import { homedir } from 'node:os';
20
20
  import { basename, dirname, join } from 'node:path';
@@ -37,7 +37,7 @@ import { isRenderCategory, RENDER_ORIENTED_PREFIXES } from '../mss/logging/rende
37
37
  import { readScopedRenderLogs } from '../mss/logging/scoped-level.js';
38
38
  import { formatClock } from '../time/format.js';
39
39
  import { HARNESS_SPACE_KINDS } from '../harness/harness-space.js';
40
- import { LogCursorNotFoundError, STORE_SAFETY_MAX } from '../mss/logging/log-store.js';
40
+ import { LOG_RETENTION_DEFAULTS, LogCursorNotFoundError, STORE_SAFETY_MAX } from '../mss/logging/log-store.js';
41
41
  import { resolveDaemonEndpoint } from '../nexus/daemon-endpoint.js';
42
42
  import { getElanousConfigDir } from '../elanous-config-dir.js';
43
43
  import { debug } from '../debug/log.js';
@@ -705,6 +705,74 @@ export function categoryCandidateWarning(
705
705
  return `안내: 지정한 카테고리 이름은 이 로그 스토어에서 관측된 적 없습니다: ${shown}${rest > 0 ? ` 외 ${rest}개` : ''}.`;
706
706
  }
707
707
 
708
+ /** A child-observation query can miss Pod-only logs even when the local store was read successfully. */
709
+ export function podObservationGapNotice(
710
+ query: Pick<LogQuery, 'categories' | 'exactCategories' | 'events'>,
711
+ podRuns: number,
712
+ ): string | null {
713
+ if (podRuns <= 0) return null;
714
+ const childCategory = (category: string): boolean => ['self-implement', 'self-dev', 'harness']
715
+ .some((prefix) => category.startsWith(prefix));
716
+ const categories = [...(query.categories ?? []), ...(query.exactCategories ?? [])];
717
+ if (!categories.some(childCategory) && !(categories.length === 0 && (query.events?.length ?? 0) > 0)) return null;
718
+ return `안내: 이 창에 Pod 에서 돈 런 ${podRuns}개 — Pod 자식의 관측은 이 logs.db 에 수집되지 않는다(POD-OBS). 원장으로 본다: elanous self run-ledger <runId>`;
719
+ }
720
+
721
+ /** Select ledger roots independently of DB existence; --all includes registered roots with no logs.db. */
722
+ function podLedgerDirectories(opts: LogsCliOpts, targets: readonly LogTarget[], instances: readonly LogInstanceView[]): string[] {
723
+ const roots = targets.map(({ dbPath }) => dirname(dirname(dbPath)));
724
+ if (opts.all && !opts.instance) {
725
+ roots.push(dirname(dirname(prodTarget().dbPath)));
726
+ for (const instance of instances) {
727
+ if (instance.kind !== 'test' || opts.includeTest) roots.push(instance.stateDir);
728
+ }
729
+ }
730
+ return [...new Set(roots.map((root) => join(root, 'run-ledger')))];
731
+ }
732
+
733
+ /** Read-only run-ledger scan over the independently selected instance roots. */
734
+ async function countPodRunLedgers(
735
+ directories: readonly string[],
736
+ query: Pick<LogQuery, 'sinceMs' | 'untilMs'>,
737
+ ): Promise<{ podRuns: number; unreadableLedgers: number }> {
738
+ const { loadRunLedger } = await import('../self-implement/run-ledger.js');
739
+ const untilMs = query.untilMs ?? Date.now();
740
+ const sinceMs = query.sinceMs ?? untilMs - LOG_RETENTION_DEFAULTS.maxAgeDays * 86_400_000;
741
+ let podRuns = 0;
742
+ let unreadableLedgers = 0;
743
+ for (const directory of directories) {
744
+ let files: string[];
745
+ try { files = readdirSync(directory); }
746
+ catch (error) {
747
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') unreadableLedgers += 1;
748
+ continue;
749
+ }
750
+ for (const file of files) {
751
+ if (!/^run-[a-zA-Z0-9-]+\.jsonl$/.test(file)) continue;
752
+ try {
753
+ const stamp = statSync(join(directory, file));
754
+ if (!stamp.isFile() || stamp.mtimeMs < sinceMs) continue;
755
+ const ledger = loadRunLedger(file.slice(0, -'.jsonl'.length), directory);
756
+ if (!ledger) { unreadableLedgers += 1; continue; }
757
+ const origin = ledger.find((entry) => entry.event === 'run-origin');
758
+ if (!origin || typeof origin.data.hostname !== 'string' || !origin.data.hostname.startsWith('si-task-')) continue;
759
+ let start = Number.POSITIVE_INFINITY;
760
+ let end = Number.NEGATIVE_INFINITY;
761
+ for (const entry of ledger) {
762
+ const time = entry.timestamp === undefined ? NaN : Date.parse(entry.timestamp);
763
+ if (!Number.isFinite(time)) continue;
764
+ start = Math.min(start, time);
765
+ end = Math.max(end, time);
766
+ }
767
+ // Older ledgers may have no timestamp at all; their mtime is the only available window evidence.
768
+ if (start === Number.POSITIVE_INFINITY) { start = stamp.mtimeMs; end = stamp.mtimeMs; }
769
+ if (start <= untilMs && end >= sinceMs) podRuns += 1;
770
+ } catch { unreadableLedgers += 1; }
771
+ }
772
+ }
773
+ return { podRuns, unreadableLedgers };
774
+ }
775
+
708
776
  // ── 0건 --event 안내: 이미 찍힌 기록에서만 답한다 ────────────────────────
709
777
  //
710
778
  // 갈림 ① 어느 범위에서 모으나 — **고정 24시간 관측 창**.
@@ -1480,9 +1548,25 @@ export async function runLogsCli(opts: LogsCliOpts, deps: RunLogsCliDeps = {}):
1480
1548
  : {};
1481
1549
  const queryStatus = registryScope.queryStatus;
1482
1550
  const unopenedStoreBanner = unopenedStores === undefined ? '안 본 스토어 수 미측정' : `안 본 스토어 ${unopenedStores}개`;
1551
+ const podGap = !opts.topFailures && podObservationGapNotice(query, 1) !== null
1552
+ ? await countPodRunLedgers(podLedgerDirectories(opts, resolved.targets, registryScope.instances), query)
1553
+ : null;
1554
+ const podNotice = podGap ? podObservationGapNotice(query, podGap.podRuns) : null;
1555
+ const podGapMeta = podGap && (podNotice || podGap.unreadableLedgers > 0)
1556
+ ? { _meta: { type: 'log-query-pod-observation-gap', ...podGap } }
1557
+ : null;
1558
+ const emitPodGap = (): void => {
1559
+ if (!opts.json && podGap) {
1560
+ if (podNotice) console.error(`${podNotice}${podGap.unreadableLedgers > 0 ? ` (못 읽은 원장 ${podGap.unreadableLedgers})` : ''}`);
1561
+ else if (podGap.unreadableLedgers > 0) console.error(`안내: Pod 원장 조회 중 못 읽은 원장 ${podGap.unreadableLedgers}개 — Pod 런 수를 확정할 수 없다(POD-OBS).`);
1562
+ }
1563
+ if (podGapMeta && podGap) debug.log('logs.query', 'pod-observation-gap', podGap);
1564
+ };
1483
1565
  if (opened.length === 0) {
1484
1566
  console.error(`elanous logs: 열 수 있는 로그 스토어 없음 — ${missing.join(' · ') || '타겟 0'} · scope=${JSON.stringify(scope)} · queryStatus=${JSON.stringify(queryStatus)}`);
1485
1567
  console.error(' 스토어는 해당 인스턴스 데몬(LF0 이후)이 한 번은 떠야 생성됩니다.');
1568
+ if (opts.json && podGapMeta) console.log(JSON.stringify(podGapMeta));
1569
+ emitPodGap();
1486
1570
  return 1;
1487
1571
  }
1488
1572
  if (missing.length > 0) console.error(`elanous logs: 스킵 — ${missing.join(' · ')}`);
@@ -1666,6 +1750,7 @@ export async function runLogsCli(opts: LogsCliOpts, deps: RunLogsCliDeps = {}):
1666
1750
  // JSONL 소비자는 stdout만 읽는다. 결손·중복 성격·상한 메타도 별도 행으로 내어 행별 JSON 파싱을 보존한다.
1667
1751
  if (opts.json && multiSurfaceDuplicateMeta) outputLines.unshift(JSON.stringify(multiSurfaceDuplicateMeta));
1668
1752
  if (opts.json && unreadableMeta) outputLines.unshift(JSON.stringify(unreadableMeta));
1753
+ if (opts.json && podGapMeta) outputLines.unshift(JSON.stringify(podGapMeta));
1669
1754
  if (unreadableInstances.length > 0 && !opts.json) {
1670
1755
  outputLines.unshift(`⚠️ 못 읽은 인스턴스 ${unreadableInstances.length}개: ${unreadableInstances.join(', ')}`);
1671
1756
  }
@@ -1676,6 +1761,7 @@ export async function runLogsCli(opts: LogsCliOpts, deps: RunLogsCliDeps = {}):
1676
1761
  const output = `${outputLines.join('\n')}\n`;
1677
1762
  await new Promise<void>((resolve, reject) => process.stdout.write(output, (error) => error ? reject(error) : resolve()));
1678
1763
  }
1764
+ emitPodGap();
1679
1765
  const eventWarning = eventCategoryWarning(opts.event);
1680
1766
  if (eventWarning) {
1681
1767
  console.error(eventWarning);
@@ -1744,6 +1830,8 @@ export async function runLogsCli(opts: LogsCliOpts, deps: RunLogsCliDeps = {}):
1744
1830
  }
1745
1831
  seed.sort((a, b) => a.row.ts_ms - b.row.ts_ms || a.row.id - b.row.id);
1746
1832
  for (const m of seed.slice(-20)) emit(m.row, m.name, m.path);
1833
+ if (opts.json && podGapMeta) console.log(JSON.stringify(podGapMeta));
1834
+ emitPodGap();
1747
1835
  const cursors = new Map<string, number>();
1748
1836
  for (const { name, store } of opened) {
1749
1837
  try { cursors.set(name, store.maxId()); } catch { cursors.set(name, 0); }
@@ -1993,6 +2081,20 @@ logsCmd.command('durations')
1993
2081
  process.exit(runLogsToolDurations(merged));
1994
2082
  });
1995
2083
 
2084
+ logsCmd.command('model-input')
2085
+ .description('최근 노드 종류별 모델 입력 토큰 기준선 (중앙값·p90·못 잼 별도 집계, 기본 3일)')
2086
+ .option('--since <t>', '조회 시작 (기본 3d · 30s|15m|2h|7d 또는 ISO)')
2087
+ .option('--json', '구조화 JSON 출력')
2088
+ .option('--test', 'cwd 레포의 격리 테스트 인스턴스(.elanous-test/)')
2089
+ .option('--instance <name>', '레지스트리 등록 인스턴스')
2090
+ .option('--all', '등록된 모든 로그 인스턴스 연합 조회')
2091
+ .option('--include-test', '--all 연합에 격리 test 인스턴스 포함')
2092
+ .action(async (o: import('./logs-model-input.js').LogsModelInputOpts, cmd: { optsWithGlobals(): Record<string, unknown> }) => {
2093
+ const merged = { ...cmd.optsWithGlobals(), ...o } as import('./logs-model-input.js').LogsModelInputOpts;
2094
+ const { runLogsModelInput } = await import('./logs-model-input.js');
2095
+ process.exitCode = runLogsModelInput(merged);
2096
+ });
2097
+
1996
2098
  logsCmd.command('degenerate')
1997
2099
  .description('수치 로그 필드의 always-same/all-zero/표본 부족 퇴화를 NDJSON으로 판정 (기본 표본 50)')
1998
2100
  .option('--category <prefix>', '카테고리 접두 필터 (복수는 쉼표)')
@@ -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
+ }
@@ -94,6 +94,7 @@ export function registerPodCommands(program: Command, deps: PodCliDeps = {}): vo
94
94
  const mem = (v: number | null) => v === null ? '?' : `${(v / 1024 ** 3).toFixed(1)}Gi`;
95
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})` : ''}`);
96
96
  }
97
+ io.log(`실측 점유: ${measure.members.map((m) => `${m.context} ${m.running === null || m.pending === null ? '못 쟀다' : m.running + m.pending}/${m.capacity}`).join(' · ') || '?'}`);
97
98
  io.log(`권장 지금 ${decision.recommended ?? '?'} 개 더 (limitedBy=${decision.limitedBy ?? 'unknown'})${decision.reason ? ` · ${decision.reason}` : ''}`);
98
99
  io.log(`예약(저작 중) ${host.reserved} · 대기 Job ${waitingJobs ?? '?'} · 실행 ${decision.running ?? '?'}`);
99
100
  io.log(`임대 없는 실행 ${decision.unleasedRunning ?? '?'}`);
@@ -155,6 +156,7 @@ export function registerPodCommands(program: Command, deps: PodCliDeps = {}): vo
155
156
  });
156
157
  if (result.image) io.error(`[pod] image ${result.image} · job ${result.job}`);
157
158
  io.log(result.artifactsDir);
159
+ if (result.artifacts?.error) io.error(`산출 회수 못 함: ${result.artifacts.error}`);
158
160
  io.exit(result.exitCode);
159
161
  } catch (err) {
160
162
  io.error(err instanceof Error ? err.message : String(err));
package/src/cli/pr-cli.ts CHANGED
@@ -53,6 +53,8 @@ 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';
56
58
  import { enqueueL8ShadowQueue, runL8ShadowQueue, shadowPrNumber, statusL8ShadowQueue, type L8ShadowQueueDeps } from '../self-implement/l8-merge-queue.js';
57
59
 
58
60
  export { branchLineageSlug, findSiblingPrs };
@@ -1574,7 +1576,32 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1574
1576
  return 0;
1575
1577
  }
1576
1578
 
1577
- 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);
1578
1605
  // `GIT-S14` — 병합이 «미완료(OPEN)»로 끝났고 GitHub 가 아직 `mergeable=UNKNOWN`(병합 가능 여부 계산 중)이면
1579
1606
  // 짧게 기다렸다 다시 병합한다. 표본 셋(08-25 · 09-24 🅢 #20233 등)이 모두 «같은 명령 재시도에 병합»이었다.
1580
1607
  // ⛔ UNKNOWN 일 때만 재시도한다 — CONFLICTING 등 다른 값은 기다려도 안 풀린다(그대로 실패를 낸다).
@@ -1588,6 +1615,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1588
1615
  await sleep(PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS);
1589
1616
  merged = manager.mergePrOutcome(upsert.url);
1590
1617
  }
1618
+ } finally { landing.end(merged!?.ok === true); }
1591
1619
  if (!merged.ok) {
1592
1620
  // `GIT-S76` — 「미완료(OPEN)」만으로는 «충돌»과 «아직 계산 중»이 안 갈린다. GitHub 의 병합 가능 상태를 같이 싣는다.
1593
1621
  // 되읽기에 실패하면 종전 문면 그대로다(못 읽은 것을 「충돌 아님」으로 적지 않는다).
@@ -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 };