elanous 0.2.35 → 0.2.37

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 (827) 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/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
  8. package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 1262.a89bb27a5b2f844e.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1746.3563617ea64023a3.js +115 -0
  12. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/{1dc5a567.9b092bfae3d7099b.js → 1ed5e8af.cf424815c7c0efad.js} +1 -1
  16. package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 2002-a43a3f380df873ec.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{13.02a07436dec15f89.js → 210.90b2cbd64926cf34.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 2283.edd9627b7bdfb546.js} +2 -2
  20. package/apps/pwa/out/_next/static/chunks/{6866-79aa5b4e47cac6aa.js → 2318-450e75d07605b8fe.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 2375.bf364c85dbb6f085.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
  25. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
  29. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
  35. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
  39. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
  40. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
  41. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 4313.76f232c304a15bde.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/{1165.bad13fc9151a7288.js → 4324.c99ba3e83eb1b691.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/{3f7c4ee5.3dde54f01a816613.js → 4337e36d.f42c3b391b3d8f20.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 4383.18e5c54db3a22c88.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 4725-34bed25720cc326b.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/{5483-dd5d7697f6bdb106.js → 4833-7934c592c5569f00.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
  52. package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 4931.95cc6dbd230774ca.js} +17 -17
  53. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 5046.7fd5cbd859299448.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
  57. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/58edce7d.f1b0c72acf13b123.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
  65. package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
  68. package/apps/pwa/out/_next/static/chunks/6252.240578f10952e091.js +34 -0
  69. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 6680.6a693c28aae4cd19.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 6745-5a63492933959dd9.js} +3 -3
  72. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
  74. package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 6819.be5c9c4d67f22922.js} +16 -16
  75. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/{2833-0fe47af99ed13c29.js → 6971-fb5f9dc0a2cb5d2d.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
  78. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
  80. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
  83. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7424.c0fe2a595d4232b5.js +23 -0
  87. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 7867.e8725745ddd1d940.js} +4 -4
  93. package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
  98. package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 8080-40d781e7704d3671.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
  100. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
  103. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
  107. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 8c58d09b.e8724a299658d86f.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 9151.a2c51e93f9156dae.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/{4441-875b97f5821ed58a.js → 9175-7d383df15a82e2be.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
  117. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +64 -0
  119. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-3337c6a1328c2674.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/{page-47c5d4db587266bd.js → page-1e5da297557d2354.js} +1 -1
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-1f5a60f70cb4dd0c.js → page-88a1edbff62eaf1d.js} +1 -1
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-bac7dee94e5eae4a.js → page-443364c9e4a23b31.js} +1 -1
  155. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/{page-dc0a532f5b9196ec.js → page-ac2c1e6169cfce57.js} +1 -1
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{d06f9160.a3d9062f95de8ad7.js → d9815f84.4918f682a45a8502.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → de8446d3.31b73eb239fecd7b.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
  279. package/docs/goal-context/README.md +3 -0
  280. package/graphs/default-loop.yaml +6 -1
  281. package/graphs/drafts/recipes.yaml +27 -7
  282. package/graphs/implement-loop.yaml +24 -0
  283. package/graphs/release/recipes.yaml +6 -0
  284. package/graphs/release/release-loop.yaml +17 -4
  285. package/graphs/wizard/recipes.yaml +44 -0
  286. package/graphs/wizard/wizard-loop.yaml +44 -0
  287. package/graphs/work/draft-close.yaml +54 -0
  288. package/graphs/work/green-close.yaml +37 -0
  289. package/graphs/work/recipes.yaml +46 -1
  290. package/graphs/work/research-report.yaml +2 -0
  291. package/graphs/work/run-research.yaml +35 -0
  292. package/package.json +1 -1
  293. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  294. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  295. package/scripts/ci-typecheck-changed.ts +139 -5
  296. package/scripts/codex-fallback-live-probe.ts +17 -15
  297. package/scripts/coord-role-pack.ts +1 -1
  298. package/scripts/first10-gate.ts +416 -0
  299. package/scripts/fleet/node-setup.sh +32 -2
  300. package/scripts/fleet/run-light-worker.sh +9 -0
  301. package/scripts/fleet/wsl-node-setup.sh +432 -0
  302. package/scripts/gate-0226-failure-census.ts +507 -0
  303. package/scripts/goals/authoring-metrics.ts +258 -0
  304. package/scripts/graph-units/draft-close-node.ts +222 -0
  305. package/scripts/hook-order-sweep.ts +7 -4
  306. package/scripts/land-global-checks.ts +69 -1
  307. package/scripts/measure-nl-routing-corpus.ts +207 -2
  308. package/scripts/release-loop/docs-node.ts +344 -8
  309. package/scripts/release-loop/gate-closure.ts +48 -0
  310. package/scripts/release-loop/gate-diff.ts +2 -1
  311. package/scripts/release-loop/gate-node.ts +249 -53
  312. package/scripts/release-loop/known-issues-node.ts +6 -4
  313. package/scripts/release-loop/node-verdict.ts +2 -0
  314. package/scripts/release-loop/notes-repair.ts +216 -0
  315. package/scripts/release-loop/prepare-node.ts +61 -5
  316. package/scripts/release-loop/resume-cap.ts +14 -34
  317. package/scripts/release-loop/resume-release.ts +151 -15
  318. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  319. package/scripts/release-loop/traffic-node.ts +59 -0
  320. package/scripts/release-loop/traffic-transition.ts +159 -0
  321. package/scripts/release-loop/version-node.ts +81 -12
  322. package/scripts/rhythm/daily.ts +137 -3
  323. package/scripts/train/green-leg.ts +176 -0
  324. package/scripts/tui-continue-real-evidence.ts +47 -0
  325. package/scripts/ux-sim.ts +53 -0
  326. package/skills/README.md +1 -0
  327. package/src/acp/client.ts +31 -5
  328. package/src/acp/core-turn-bridge.ts +54 -6
  329. package/src/acp/stderr-summary.ts +49 -0
  330. package/src/agent/delegate-hint.ts +16 -0
  331. package/src/agent/monad-agent-turn.ts +1 -0
  332. package/src/agent/runner.ts +82 -2
  333. package/src/agent/task-notification.ts +56 -10
  334. package/src/agent/terminal-surface.ts +217 -0
  335. package/src/agent/types.ts +4 -0
  336. package/src/agent-substrate/pr-reviewer.ts +64 -4
  337. package/src/agent-substrate/review-intent.ts +29 -2
  338. package/src/agent-substrate/review-observation.ts +3 -0
  339. package/src/agent-substrate/self-review-cli.ts +490 -26
  340. package/src/autopilot/lineage/sources.ts +1 -1
  341. package/src/autopilot/mission-codebase-gate.ts +141 -12
  342. package/src/autopilot/pr-manager.ts +89 -18
  343. package/src/boot/daemon-runtime.ts +35 -3
  344. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  345. package/src/boot/daemon-tools/self-implement.ts +1 -0
  346. package/src/budget/run-usage-rollup.ts +12 -7
  347. package/src/budget/unified-usage.ts +20 -0
  348. package/src/budget/usage-outcomes.ts +8 -4
  349. package/src/capture/tui-self-report.ts +132 -1
  350. package/src/chat/goal-continue-verdict.ts +41 -0
  351. package/src/chat/index.ts +30 -4
  352. package/src/chat/internal-turn-origin.ts +1 -0
  353. package/src/chat/paste-fold.ts +86 -0
  354. package/src/chat/tool-render/block.ts +32 -0
  355. package/src/chat/tool-render/dispatch.ts +2 -20
  356. package/src/chat/tool-render/result-text.ts +98 -0
  357. package/src/chat/turn-typeahead.ts +70 -7
  358. package/src/cli/autopilot-cli.ts +24 -9
  359. package/src/cli/config-audit.ts +119 -0
  360. package/src/cli/decisions-cli.ts +7 -4
  361. package/src/cli/doctor-cli.ts +137 -6
  362. package/src/cli/guardian-cli.ts +10 -0
  363. package/src/cli/herdr-cli.ts +34 -0
  364. package/src/cli/light-entry-route.ts +6 -3
  365. package/src/cli/log-event-names.ts +2 -0
  366. package/src/cli/logs-cli.ts +357 -2
  367. package/src/cli/make-cli.ts +247 -11
  368. package/src/cli/memory-cli.ts +30 -1
  369. package/src/cli/msg-cli.ts +132 -14
  370. package/src/cli/pr-cli.ts +29 -16
  371. package/src/cli/pr-granularity.ts +5 -3
  372. package/src/cli/pr-land-base-read.ts +11 -2
  373. package/src/cli/pr-land-heavy-remote.ts +6 -3
  374. package/src/cli/pr-land-overlap-evidence.ts +23 -4
  375. package/src/cli/pr-land-recovery.ts +117 -1
  376. package/src/cli/pty-takeover-cli.ts +8 -7
  377. package/src/cli/release-checklist-read-cli.ts +109 -4
  378. package/src/cli/release-cli.ts +64 -15
  379. package/src/cli/release-single-flight.ts +1 -1
  380. package/src/cli/self-update.ts +23 -5
  381. package/src/cli/self-utterances-cli.ts +13 -16
  382. package/src/cli/tasks-card-show.ts +162 -0
  383. package/src/cli/tasks-cli.ts +868 -352
  384. package/src/cli/tasks-read-cli.ts +197 -0
  385. package/src/cli/usage-cli.ts +12 -10
  386. package/src/context-bus/claude-memory-import.ts +99 -0
  387. package/src/context-bus/long-term-memory.ts +125 -0
  388. package/src/core-turn/run-core-turn.ts +4 -2
  389. package/src/core-turn/run-goal-loop.ts +76 -16
  390. package/src/core-turn/types.ts +8 -1
  391. package/src/dashboard/chat/acp-chat.ts +9 -0
  392. package/src/dashboard/context/keys.ts +8 -31
  393. package/src/dashboard/index.ts +299 -62
  394. package/src/dashboard/input/agent-wake.ts +50 -1
  395. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  396. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
  397. package/src/dashboard/input/chat-main-slash-command.ts +4 -2
  398. package/src/dashboard/input/goal-continue.ts +210 -0
  399. package/src/dashboard/input/goal-interim.ts +2 -0
  400. package/src/dashboard/input/internal-turn.ts +2 -8
  401. package/src/dashboard/input/seat-autowake.ts +9 -7
  402. package/src/dashboard/input/turn-autoheal.ts +52 -0
  403. package/src/dashboard/replay-preview.ts +25 -0
  404. package/src/dashboard/seat-boot-preamble.ts +132 -5
  405. package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
  406. package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -10
  407. package/src/dashboard/slash-runtime/model-choices.ts +15 -0
  408. package/src/dashboard/stale-install-check.ts +3 -99
  409. package/src/dashboard/synchronized-frame-output.ts +74 -0
  410. package/src/debug/batch-queue.ts +119 -0
  411. package/src/debug/tui-log-tag.ts +67 -0
  412. package/src/display/agent-surface.ts +7 -0
  413. package/src/display/coordinator.ts +45 -12
  414. package/src/display/resize-listener.ts +41 -20
  415. package/src/display/synchronized-output-region.ts +60 -0
  416. package/src/domains/standalone-log-sink.ts +15 -2
  417. package/src/domains/surface-events.ts +80 -1
  418. package/src/esc-abort-gate.ts +69 -0
  419. package/src/exec-requests/planner.ts +37 -2
  420. package/src/execution-loop/launch-gate.ts +4 -3
  421. package/src/git-fs/cli-stderr.ts +45 -0
  422. package/src/git-fs/gh-cli.ts +6 -3
  423. package/src/git-fs/git-cli.ts +11 -5
  424. package/src/git-fs/worktree.ts +95 -1
  425. package/src/graph-runner/graph-cli.ts +44 -2
  426. package/src/graph-runner/graph-run-api.ts +3 -2
  427. package/src/graph-runner/runner.ts +37 -16
  428. package/src/graph-wizard/generate.ts +131 -4
  429. package/src/graph-wizard/steps.ts +15 -0
  430. package/src/grounding/proactive-ground.ts +86 -0
  431. package/src/harness/control-inbox.ts +49 -1
  432. package/src/harness/harness-cli-command.ts +230 -40
  433. package/src/harness/harness-incidents.ts +52 -1
  434. package/src/harness/pod-control-send.ts +33 -5
  435. package/src/harness/review-adapter.ts +26 -6
  436. package/src/harness/self-send-remote.ts +69 -0
  437. package/src/harness/self-send-routing-guard.ts +6 -0
  438. package/src/harness/self-send-target.ts +4 -3
  439. package/src/index.ts +443 -25
  440. package/src/input-core/context-key-runtime.ts +21 -0
  441. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  442. package/src/light-cli.ts +6 -1
  443. package/src/llm/route-decision.ts +13 -0
  444. package/src/llm-tool-name.ts +37 -0
  445. package/src/llm-tool-schema.ts +35 -0
  446. package/src/llm-wellformed.ts +70 -0
  447. package/src/llm.ts +158 -15
  448. package/src/loops/checker.ts +100 -0
  449. package/src/loops/consensus.ts +26 -2
  450. package/src/loops/loop-cli.ts +9 -4
  451. package/src/loops/msg-wake.ts +35 -39
  452. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  453. package/src/loops/orchestrator/inbox.ts +59 -11
  454. package/src/loops/orchestrator/knowhow-pack.ts +364 -0
  455. package/src/loops/orchestrator/tick.ts +54 -5
  456. package/src/maturity/feature-maturity.ts +1 -1
  457. package/src/model-tier/llm-tier-map.ts +12 -17
  458. package/src/models/prompts.ts +17 -2
  459. package/src/msg/msg-post-office.ts +116 -0
  460. package/src/msg/msg-store.ts +17 -0
  461. package/src/mss/logging/log-store.ts +79 -22
  462. package/src/native-tool-catalog.ts +1 -1
  463. package/src/nexus/api/decisions-route.ts +38 -18
  464. package/src/nexus/api/graph-wizard-api.ts +46 -3
  465. package/src/nexus/api/grid.ts +24 -4
  466. package/src/nexus/api/http-server.ts +1 -1
  467. package/src/nexus/api/ops-api.ts +14 -6
  468. package/src/nexus/boot/register-mcp-clients.ts +263 -38
  469. package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
  470. package/src/nexus/state/state.ts +7 -1
  471. package/src/oauth/codex-account-store.ts +34 -1
  472. package/src/onboarding/first-run.ts +37 -6
  473. package/src/onboarding/web-first.ts +43 -11
  474. package/src/ops/loops-map.ts +46 -0
  475. package/src/ops/overview-cache.ts +22 -4
  476. package/src/ops/overview-collect.ts +12 -6
  477. package/src/ops/overview.ts +44 -8
  478. package/src/persona/loader.ts +11 -0
  479. package/src/persona/types.ts +8 -0
  480. package/src/policy/llm-policy.ts +3 -1
  481. package/src/prompt-enhance/enhance.ts +4 -4
  482. package/src/prompt-library/session-guidance.ts +14 -0
  483. package/src/provider-summary.ts +8 -0
  484. package/src/pty-shell/availability.ts +7 -0
  485. package/src/pty-shell/herdr-agent-report.ts +155 -37
  486. package/src/pty-shell/herdr-prompt.ts +266 -0
  487. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  488. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  489. package/src/pty-shell/pty-control-ipc.ts +327 -15
  490. package/src/pty-shell/pty-special-keys.ts +42 -2
  491. package/src/pty-shell/registry.ts +25 -15
  492. package/src/pty-shell/stale-install-check.ts +99 -0
  493. package/src/pty-shell/tui-run-state.ts +249 -3
  494. package/src/release-loop/auto-start.ts +20 -2
  495. package/src/release-loop/checklist.ts +126 -9
  496. package/src/release-loop/feature-store.ts +9 -9
  497. package/src/release-loop/landed-but-yellow.ts +93 -12
  498. package/src/release-loop/rehearsal.ts +36 -20
  499. package/src/repl/index.ts +27 -1
  500. package/src/seat-loop/knowhow-lint.ts +1 -1
  501. package/src/seat-loop/seat-report.ts +1 -0
  502. package/src/self-dev/ask-launch-flow.ts +86 -10
  503. package/src/self-dev/decompose-proposal.ts +183 -20
  504. package/src/self-dev/decompose.ts +61 -0
  505. package/src/self-dev/dev-cli.ts +37 -3
  506. package/src/self-dev/dev-pipeline.ts +37 -9
  507. package/src/self-dev/draft-sweep.ts +241 -16
  508. package/src/self-dev/draft-triage-rules.ts +50 -5
  509. package/src/self-dev/glm-credential-guard.ts +77 -0
  510. package/src/self-dev/graph-journey-nodes.ts +1 -0
  511. package/src/self-dev/graph-journey-route.ts +12 -2
  512. package/src/self-dev/orchestrate-cli.ts +68 -3
  513. package/src/self-dev/orchestrate.ts +116 -17
  514. package/src/self-dev/review-provider-fallback.ts +45 -7
  515. package/src/self-dev/run-supervisor.ts +55 -2
  516. package/src/self-dev/run-types.ts +1 -1
  517. package/src/self-dev/shard-plan.ts +48 -0
  518. package/src/self-dev/shard-run.ts +50 -3
  519. package/src/self-health/autoheal.ts +153 -0
  520. package/src/self-health/signatures.ts +6 -0
  521. package/src/self-implement/device-first.ts +116 -0
  522. package/src/self-implement/doctor-visit.ts +322 -1
  523. package/src/self-implement/evidence-command-budget.ts +80 -0
  524. package/src/self-implement/gate-artifacts.ts +6 -2
  525. package/src/self-implement/gate-baseline.ts +64 -1
  526. package/src/self-implement/gate-cli.ts +93 -9
  527. package/src/self-implement/gate-remote.ts +28 -4
  528. package/src/self-implement/gate-scope.ts +13 -1
  529. package/src/self-implement/goal-author-cli.ts +1 -0
  530. package/src/self-implement/goal-author-decompose.ts +265 -4
  531. package/src/self-implement/goal-author.ts +366 -26
  532. package/src/self-implement/goal-elaborate.ts +176 -22
  533. package/src/self-implement/goal-refine.ts +3 -0
  534. package/src/self-implement/goal-supervisor-fill.ts +75 -26
  535. package/src/self-implement/graph-variant.ts +40 -6
  536. package/src/self-implement/headless-elanous-driver.ts +19 -3
  537. package/src/self-implement/importer-test-index.ts +215 -2
  538. package/src/self-implement/knowhow-pack.ts +5 -5
  539. package/src/self-implement/off-diff-evidence.ts +58 -6
  540. package/src/self-implement/orchestrator.ts +536 -42
  541. package/src/self-implement/pod-warm-pool-profile.ts +1 -0
  542. package/src/self-implement/pwa-import-graph.ts +1 -1
  543. package/src/self-implement/review-round-brief.ts +300 -0
  544. package/src/self-implement/rework-policy.ts +44 -0
  545. package/src/self-implement/run-ledger.ts +278 -6
  546. package/src/self-implement/run-stop.ts +1 -1
  547. package/src/self-implement/run-ttl.ts +38 -24
  548. package/src/self-implement/running-runs.ts +17 -3
  549. package/src/self-implement/scope-adjacency.ts +3 -1
  550. package/src/self-implement/seams.ts +72 -10
  551. package/src/self-implement/stop-autoheal.ts +1 -0
  552. package/src/self-implement/test-seams.ts +13 -1
  553. package/src/self-implement/train-reach-grouping.ts +8 -2
  554. package/src/self-implement/wiring-check.ts +358 -0
  555. package/src/session/chat.ts +7 -1
  556. package/src/session/id-prefix.ts +60 -0
  557. package/src/session/index.ts +4 -0
  558. package/src/session-runtime/index.ts +9 -1
  559. package/src/shell-env-bootstrap.ts +11 -4
  560. package/src/skills/runner.ts +4 -2
  561. package/src/skills/tools/agent.ts +290 -48
  562. package/src/skills/tools/pty.ts +5 -0
  563. package/src/skills/tools/schedule-wakeup.ts +23 -4
  564. package/src/skills/tools/shell.ts +61 -6
  565. package/src/skills/tools/terminal-modal-inject.ts +1 -2
  566. package/src/skills/tools/terminal-modal.ts +10 -8
  567. package/src/skills/url-router.ts +41 -1
  568. package/src/smart-wizard/run.ts +66 -0
  569. package/src/status/bar.ts +34 -6
  570. package/src/status/metrics.ts +12 -1
  571. package/src/status/status-provider-info.ts +37 -6
  572. package/src/steward/rejudge-tick.ts +22 -7
  573. package/src/steward/resync-tick.ts +31 -4
  574. package/src/steward/ta-repair-event-collect.ts +17 -6
  575. package/src/task-agent/actions.ts +202 -5
  576. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  577. package/src/task-agent/boundary-proof-producer.ts +147 -0
  578. package/src/task-agent/completion-evidence.ts +2 -1
  579. package/src/task-agent/green-close-recipe.ts +239 -0
  580. package/src/task-agent/green-sweep.ts +64 -10
  581. package/src/task-agent/land-queue.ts +21 -8
  582. package/src/task-agent/live-moves.ts +70 -9
  583. package/src/task-agent/map-host-adapter.ts +134 -0
  584. package/src/task-agent/map-reduce.ts +158 -0
  585. package/src/task-agent/map-run-ledger.ts +226 -0
  586. package/src/task-agent/mission.ts +30 -0
  587. package/src/task-agent/parent-host.ts +21 -11
  588. package/src/task-agent/rejudge-on-head.ts +87 -5
  589. package/src/task-agent/repair-cycle.ts +179 -32
  590. package/src/task-agent/repair-next-move.ts +42 -4
  591. package/src/task-agent/repair-outcomes.ts +29 -0
  592. package/src/task-agent/repair-worker.ts +14 -4
  593. package/src/task-agent/review-prior-fix.ts +12 -2
  594. package/src/task-agent/shadow.ts +229 -8
  595. package/src/task-agent/task-card-prefix.ts +2 -0
  596. package/src/task-agent/task-hand.ts +630 -30
  597. package/src/task-agent/task-parent-role-llm.ts +45 -0
  598. package/src/task-agent/tier-split.ts +80 -10
  599. package/src/task-agent/work-order.ts +53 -2
  600. package/src/task-orchestrator/dispatcher.ts +46 -1
  601. package/src/task-orchestrator/generator-prompt.ts +6 -0
  602. package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
  603. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  604. package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
  605. package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
  606. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
  607. package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
  608. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  609. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  610. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
  611. package/src/task-orchestrator/surfaces/pod-pool.ts +126 -8
  612. package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
  613. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
  614. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
  615. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
  616. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
  617. package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
  618. package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
  619. package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
  620. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
  621. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +491 -36
  622. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
  623. package/src/task-orchestrator/surfaces/self-implement-pod.ts +612 -54
  624. package/src/task-orchestrator/surfaces/self-implement.ts +46 -2
  625. package/src/testing/linux-env.ts +177 -0
  626. package/src/tool-runtime/index.ts +15 -2
  627. package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
  628. package/src/tty-foreground.ts +155 -0
  629. package/src/tui/chat/goal-interim.ts +177 -0
  630. package/src/tui/chat/log-view.ts +205 -18
  631. package/src/tui/chat/self-health-status.ts +232 -0
  632. package/src/tui/entry.ts +623 -80
  633. package/src/tui/input/at-picker.ts +55 -0
  634. package/src/tui/input/composer.ts +8 -1
  635. package/src/tui/slash/compact-command.ts +7 -0
  636. package/src/tui/slash/compact.ts +1 -7
  637. package/src/tui/slash/resume.ts +98 -0
  638. package/src/tui/slash/signals.ts +114 -0
  639. package/src/tui/slash/term-next.ts +71 -0
  640. package/src/tui-client/local-chat-turn.ts +49 -5
  641. package/src/tui-client/next-dashboard-runtime.ts +8 -0
  642. package/src/tui-client/next-loop-command.ts +70 -0
  643. package/src/tui-client/next-wakeup.ts +191 -0
  644. package/src/tui.ts +37 -0
  645. package/src/ui/modal-adapter.ts +2 -2
  646. package/src/user-config.ts +19 -1
  647. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  648. package/src/ux-sim/classic-tui-seat-scenarios.ts +670 -0
  649. package/src/ux-sim/cli-config-audit-device.ts +121 -0
  650. package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
  651. package/src/ux-sim/event-monkey.ts +3 -2
  652. package/src/ux-sim/fake-bin.ts +45 -0
  653. package/src/ux-sim/fake-gh.ts +174 -0
  654. package/src/ux-sim/fake-herdr.ts +238 -0
  655. package/src/ux-sim/fake-kubectl.ts +142 -0
  656. package/src/ux-sim/fake-llm.ts +116 -6
  657. package/src/ux-sim/fault-glm-no-credential.ts +116 -0
  658. package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
  659. package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
  660. package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
  661. package/src/ux-sim/goal-device.ts +619 -0
  662. package/src/ux-sim/in-process-cli.ts +22 -5
  663. package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
  664. package/src/ux-sim/mock-authoring-first-run.ts +97 -0
  665. package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
  666. package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
  667. package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
  668. package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
  669. package/src/ux-sim/next-tui-seat-scenarios.ts +749 -0
  670. package/src/ux-sim/onboarding-first-run-device.ts +269 -0
  671. package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
  672. package/src/ux-sim/resume-picker-device.ts +173 -0
  673. package/src/ux-sim/session-id-seed.ts +60 -0
  674. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  675. package/src/ux-sim/subagent-tools-device.ts +81 -0
  676. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  677. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  678. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
  679. package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
  680. package/src/version/packed-revision.json +1 -1
  681. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
  682. package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
  684. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
  685. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
  694. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
  696. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
  697. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
  699. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
  701. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
  705. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/3677-4215f826f6aa68e5.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
  708. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
  712. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
  715. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
  724. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +0 -94
  725. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
  729. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
  736. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
  739. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
  741. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
  747. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
  748. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
  758. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
  760. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/8637.47f5b35afcae5e6b.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
  767. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
  795. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
  802. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
  803. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
  804. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
  805. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
  806. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
  807. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
  808. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
  809. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
  810. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
  811. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
  812. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
  813. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
  814. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
  815. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
  816. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
  817. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
  818. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
  819. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
  820. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
  821. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
  822. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
  823. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
  824. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
  825. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
  826. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
  827. /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
@@ -33,6 +33,9 @@ export interface CheckEntry {
33
33
  expectedVersion?: string;
34
34
  /** Registry graph path, supplied only by graph inventory. */
35
35
  file?: string;
36
+ /** LOOP-PRUNE-1021-FU 판정 재료 — cron-shell·미등록 행이 실은 crontab 명세(그래프 루프에는 없다). */
37
+ cron?: string;
38
+ command?: string;
36
39
  enabled: boolean;
37
40
  registered: boolean;
38
41
  }
@@ -317,3 +320,100 @@ export function observeLoopCheck(results: CheckResult[], scope: LoopScope, deps:
317
320
  catch (error) { if (existsSync(tmp)) unlinkSync(tmp); throw error; }
318
321
  return counts;
319
322
  }
323
+
324
+ // ── LOOP-PRUNE-1021-FU 정리 판정 (내부 문서 `loop-lineage-1021` · 0.2.36) ─────
325
+ /** 무실행 은퇴 한계 — off 상태가 원장으로 최근 14일 실행이 증명될 때만 은퇴 후보가 된다. */
326
+ export const PRUNE_IDLE_DAYS = 14;
327
+ /** 활성 루프 상한 — alive 가 25 를 넘으면 접기·은퇴 판정을 먼저 치른다. */
328
+ export const PRUNE_ALIVE_LIMIT = 25;
329
+
330
+ export interface PruneFoldGroup { family: string; ids: string[]; }
331
+ export interface PruneUnregisteredRow { id: string; cron?: string; command?: string; }
332
+ export interface PruneJudgment {
333
+ /** 14일 무실행이 원장으로 증명된 은퇴 후보(off). */
334
+ idleRetire: string[];
335
+ /** 실행 기록이 없어 무실행을 증명할 수 없는 항목 — 은퇴 후보에서 제외한다. */
336
+ idleUnproven: string[];
337
+ /** 등록되지 않은 elanous 크론 행 — 등록/제거 판정에 넘긴다. */
338
+ unregistered: PruneUnregisteredRow[];
339
+ /** 같은 일을 하는 elanous:* 형제 슬롯 가족 — 그래프 루프·원장 해시는 접지 않는다. */
340
+ foldGroups: PruneFoldGroup[];
341
+ /** 활성 루프 수와 25 한도 판정. */
342
+ alive: { count: number; limit: number; within: boolean };
343
+ /** 운영 이름이 없는 원장 해시 id — 명명 대상. */
344
+ unnamed: string[];
345
+ }
346
+
347
+ /** elanous:* 슬롯의 가족 이름 — namedCronIds 의 -N 접미와 자리 슬롯(:SEAT)을 원래 가족으로 되돌린다. */
348
+ function pruneFoldFamily(id: string): string | undefined {
349
+ if (!id.startsWith('elanous:')) return undefined;
350
+ const seat = /^elanous:([^:]+):[^:]+$/.exec(id);
351
+ if (seat) return `elanous:${seat[1]}`;
352
+ const sibling = /^elanous:(.+)-\d+$/.exec(id);
353
+ return `elanous:${sibling ? sibling[1] : id.slice('elanous:'.length)}`;
354
+ }
355
+
356
+ /** LOOP-PRUNE-1021-FU — CheckResult 원장 위에서 무실행 은퇴·미등록 정리·형제 접기·alive ≤ 25·이름 없는 해시를 판정한다. */
357
+ export function pruneJudgment(results: readonly CheckResult[], opts: { now?: Date } = {}): PruneJudgment {
358
+ const now = opts.now ?? new Date();
359
+ const idleMs = PRUNE_IDLE_DAYS * 24 * 60 * 60_000;
360
+ const idleRetire: string[] = [];
361
+ const idleUnproven: string[] = [];
362
+ const unregistered: PruneUnregisteredRow[] = [];
363
+ const unnamed: string[] = [];
364
+ const families = new Map<string, string[]>();
365
+ let aliveCount = 0;
366
+ for (const result of results) {
367
+ if (result.state === 'alive') aliveCount++;
368
+ if (result.state === 'unregistered') {
369
+ unregistered.push({
370
+ id: result.id,
371
+ ...(result.cron ? { cron: result.cron } : {}),
372
+ ...(result.command ? { command: result.command } : {}),
373
+ });
374
+ }
375
+ if (result.state === 'off') {
376
+ const ran = result.lastRunAt && Number.isFinite(Date.parse(result.lastRunAt)) ? Date.parse(result.lastRunAt) : undefined;
377
+ if (ran === undefined) idleUnproven.push(result.id);
378
+ else if (now.getTime() - ran > idleMs) idleRetire.push(result.id);
379
+ }
380
+ if (/^[0-9a-f]{8,}$/.test(result.id)) unnamed.push(result.id);
381
+ const family = pruneFoldFamily(result.id);
382
+ if (family) {
383
+ const group = families.get(family) ?? [];
384
+ group.push(result.id);
385
+ families.set(family, group);
386
+ }
387
+ }
388
+ const foldGroups: PruneFoldGroup[] = [];
389
+ for (const [family, ids] of families) {
390
+ if (ids.length < 2) continue;
391
+ foldGroups.push({ family, ids: [...ids].sort() });
392
+ }
393
+ const judgment: PruneJudgment = {
394
+ idleRetire,
395
+ idleUnproven,
396
+ unregistered,
397
+ foldGroups,
398
+ alive: { count: aliveCount, limit: PRUNE_ALIVE_LIMIT, within: aliveCount <= PRUNE_ALIVE_LIMIT },
399
+ unnamed,
400
+ };
401
+ debug.log('loop.checker', 'prune', {
402
+ idleRetire: idleRetire.length, idleUnproven: idleUnproven.length, unregistered: unregistered.length,
403
+ folds: foldGroups.length, alive: aliveCount, unnamed: unnamed.length,
404
+ });
405
+ return judgment;
406
+ }
407
+
408
+ /** LOOP-PRUNE-1021-FU — PruneJudgment 을 사람용 정리 판정 줄로 렌더한다(loop status --all 인간 출력 꼬리). */
409
+ export function pruneText(judgment: PruneJudgment): string {
410
+ const lines = [
411
+ `무실행 은퇴 ${judgment.idleRetire.length}: ${judgment.idleRetire.join(', ') || '없음'}`,
412
+ `무실행 미증명 ${judgment.idleUnproven.length}: ${judgment.idleUnproven.join(', ') || '없음'}`,
413
+ `미등록 ${judgment.unregistered.length}: ${judgment.unregistered.map(row => row.command ? `${row.id} (${row.command})` : row.id).join(', ') || '없음'}`,
414
+ `형제 접기 ${judgment.foldGroups.length}: ${judgment.foldGroups.map(group => `${group.family}[${group.ids.join('+')}]`).join(', ') || '없음'}`,
415
+ `alive ${judgment.alive.count}/${judgment.alive.limit} ${judgment.alive.within ? '한도 이내' : '한도 초과'}`,
416
+ `이름 없는 해시 ${judgment.unnamed.length}: ${judgment.unnamed.join(', ') || '없음'}`,
417
+ ];
418
+ return lines.join('\n');
419
+ }
@@ -45,6 +45,8 @@ export const CROWN_MARK = String.fromCodePoint(0x1F451);
45
45
  export interface ProposalCard {
46
46
  id: string;
47
47
  category: ConsensusCategory;
48
+ /** Stable orchestrator work key (orch:<card>:<cell>) for a cross-branch split cell. */
49
+ workKey?: string;
48
50
  title: string;
49
51
  /** 사실 id — 제안의 근거 관측. */
50
52
  factId: string;
@@ -152,8 +154,14 @@ export class ConsensusEngine {
152
154
 
153
155
  propose(input: {
154
156
  by: ConsensusRepresentative; category: ConsensusCategory; title: string; factId: string; cost: string; undo: string;
155
- thresholds?: DecisionCategory[]; provider?: string;
157
+ thresholds?: DecisionCategory[]; provider?: string; workKey?: string;
156
158
  }): ProposalCard {
159
+ if (input.workKey !== undefined) {
160
+ if (input.category !== 'cross-branch-change' || !/^orch:[a-zA-Z0-9_-]+:[a-zA-Z0-9_-]+$/.test(input.workKey))
161
+ throw new Error('invalid cross-branch work key');
162
+ const existing = this.list().find(proposal => proposal.workKey === input.workKey);
163
+ if (existing) throw new Error(`cross-branch work already proposed: ${existing.id}`);
164
+ }
157
165
  if (!CONSENSUS_REPRESENTATIVES.includes(input.by)) throw new Error(`invalid representative: ${input.by} (coordinator|guardian)`);
158
166
  if (!CONSENSUS_CATEGORIES.includes(input.category)) throw new Error(`invalid consensus category: ${input.category} (${CONSENSUS_CATEGORIES.join('|')})`);
159
167
  const thresholds = [...new Set(input.thresholds ?? [])];
@@ -164,6 +172,7 @@ export class ConsensusEngine {
164
172
  const proposal: ProposalCard = {
165
173
  id: this.nextId('C', at),
166
174
  category: input.category,
175
+ ...(input.workKey ? { workKey: input.workKey } : {}),
167
176
  title: oneLine(input.title, 'title'),
168
177
  factId: oneLine(input.factId, 'fact id'),
169
178
  cost: oneLine(input.cost, 'cost'),
@@ -210,11 +219,24 @@ export class ConsensusEngine {
210
219
  return proposal;
211
220
  }
212
221
 
222
+ proposalForWork(workKey: string): ProposalCard | undefined {
223
+ return this.list().find(entry => entry.workKey === workKey);
224
+ }
225
+
213
226
  crownCards(): CrownCard[] {
214
227
  return [...this.state().cards]
215
228
  .sort((a, b) => b.raisedAt.localeCompare(a.raisedAt) || a.id.localeCompare(b.id));
216
229
  }
217
230
 
231
+ /** The same durable execution gate is used by CLI replies, hooks and loop consumers. */
232
+ canExecute(id: string): boolean {
233
+ const proposal = this.show(id);
234
+ return proposal.status === 'agreed' && proposal.thresholds.length === 0
235
+ && proposal.roundTrips >= 1 && proposal.roundTrips <= MAX_REVIEW_ROUND_TRIPS
236
+ && proposal.reviews.at(-1)?.verdict === 'agree'
237
+ && proposal.reviews.at(-1)?.by !== proposal.proposedBy;
238
+ }
239
+
218
240
  /** 판정선 — 합의 원장의 agreed 이벤트를 ISO 주 단위로 센다 (한 주 N건의 기전). */
219
241
  weeklyAgreementCounts(): Array<{ week: string; count: number }> {
220
242
  const counts = new Map<string, number>();
@@ -230,7 +252,9 @@ export class ConsensusEngine {
230
252
  private conclude(id: string, verdict: ReviewRecord['verdict'], input: { by: ConsensusRepresentative; claim?: string; provider?: string }): { proposal: ProposalCard; crownCard?: CrownCard } {
231
253
  const proposal = this.show(id);
232
254
  if (proposal.status !== 'open') throw new Error(`합의가 이미 결론났다: ${id} (${proposal.status === 'agreed' ? '합의' : '불합의'})`);
255
+ if (!CONSENSUS_REPRESENTATIVES.includes(input.by)) throw new Error(`invalid representative: ${input.by}`);
233
256
  if (input.by === proposal.proposedBy) throw new Error('메아리 방지 — 제안한 대표는 자기 제안을 검토하지 않는다');
257
+ if (proposal.roundTrips >= MAX_REVIEW_ROUND_TRIPS) throw new Error(`상대 검토는 최대 ${MAX_REVIEW_ROUND_TRIPS}왕복이다`);
234
258
  if (verdict === 'revise' && proposal.roundTrips + 1 >= MAX_REVIEW_ROUND_TRIPS)
235
259
  throw new Error(`상대 검토는 최대 ${MAX_REVIEW_ROUND_TRIPS}왕복이다 — 마지막 왕복에는 합의 또는 불합의로 끝낸다`);
236
260
  const claim = oneLine(input.claim ?? (verdict === 'agree' ? '동의 — 제안대로 실행한다' : ''), 'claim');
@@ -249,7 +273,7 @@ export class ConsensusEngine {
249
273
  this.appendLens(input.by, { action: 'reviewed', proposalId: proposal.id, at, verdict, ...(provider ? { provider } : {}) });
250
274
  debug.log('loops.consensus', 'reviewed', { proposalId: proposal.id, verdict, roundTrip: review.roundTrip, by: input.by });
251
275
  const updated = this.show(proposal.id);
252
- if (verdict === 'agree') this.executeHook(updated);
276
+ if (this.canExecute(updated.id)) this.executeHook(updated);
253
277
  return { proposal: updated, ...(crownCard ? { crownCard } : {}) };
254
278
  }
255
279
 
@@ -1,7 +1,7 @@
1
1
  import type { Command } from 'commander';
2
2
  import { writeStdoutJson } from '../cli/stdout-json.js';
3
3
  import { listAllLoops, listLoops, loopStatus, runLoop, setLoopEnabled, unregisteredCronLoops, type AllLoopEntry, type LoopRegistryOptions } from './registry.js';
4
- import { checkLoops, countLoopStates, entriesFromRegistry, LOOP_STATES, notifyOwners, observeLoopCheck, type RegistryAdapterDeps } from './checker.js';
4
+ import { checkLoops, countLoopStates, entriesFromRegistry, LOOP_STATES, notifyOwners, observeLoopCheck, pruneJudgment, pruneText, type RegistryAdapterDeps } from './checker.js';
5
5
  import { effectiveInstanceRoot } from '../instance/resolve.js';
6
6
  import { verifyLoopPackage } from './package/verify.js';
7
7
  import { loopActivity } from './activity.js';
@@ -56,7 +56,8 @@ export function registerLoopCommands(program: Command, checkerDeps: RegistryAdap
56
56
  }));
57
57
  loop.command('status [id]').option('--all', 'Check all registered loops')
58
58
  .option('--json', 'Print JSON').option('--notify', 'Queue late/failing loops for their owners')
59
- .action((id: string | undefined, opts: { all?: boolean; json?: boolean; notify?: boolean }) => handle(async () => {
59
+ .option('--prune', 'Judge idle retire · unregistered cleanup · sibling folding · alive ≤ 25')
60
+ .action((id: string | undefined, opts: { all?: boolean; json?: boolean; notify?: boolean; prune?: boolean }) => handle(async () => {
60
61
  if (!opts.all) {
61
62
  if (!id) throw new Error('loop status requires an id or --all');
62
63
  await output(loopStatus(id), !!opts.json);
@@ -65,15 +66,19 @@ export function registerLoopCommands(program: Command, checkerDeps: RegistryAdap
65
66
  if (id) throw new Error('loop status --all does not take an id');
66
67
  const now = checkerDeps.now ?? new Date();
67
68
  const root = checkerDeps.root ?? effectiveInstanceRoot();
68
- const { entries, scope } = entriesFromRegistry({ ...checkerDeps, now });
69
+ const registryOpts = checkerDeps.registryOptions;
70
+ const { entries, scope } = entriesFromRegistry({ ...checkerDeps, now,
71
+ listAllLoops: checkerDeps.listAllLoops ?? (registryOpts ? () => listAllLoops(registryOpts) : undefined) });
69
72
  const results = checkLoops(entries, now);
70
73
  const counts = countLoopStates(results);
74
+ const prune = pruneJudgment(results, { now });
71
75
  observeLoopCheck(results, scope, { root, now });
72
76
  if (opts.notify) notifyOwners(results, { root, now });
73
- if (opts.json) { await output({ results, counts, scope }, true); return; }
77
+ if (opts.json) { await output({ results, counts, scope, prune }, true); return; }
74
78
  console.log('id\tstate\tlast run\texpected interval\towner\treason');
75
79
  for (const result of results) console.log(`${result.id}\t${result.state}\t${result.lastRunAt ?? '—'}\t${result.expectEveryMinutes === undefined ? '—' : `${result.expectEveryMinutes}m`}\t${result.owner ?? '—'}\t${result.reason}`);
76
80
  console.log(`${LOOP_STATES.map(state => `${state} ${counts[state]}`).join(' · ')} · scope ${scope}`);
81
+ if (opts.prune) console.log(pruneText(prune));
77
82
  }));
78
83
  for (const [name, enabled] of [['start', true], ['stop', false]] as const) {
79
84
  loop.command(`${name} <id>`).option('--yes', 'Apply the crontab change (otherwise preview only)')
@@ -5,7 +5,8 @@
5
5
  // sse — 아무것도 안 한다(구독자가 이미 듣는다)
6
6
  // cron — 다음 틱에 읽는다 · `wake-deferred` 로그만
7
7
  // pty-inject — elanous TUI(pty 별명 = 자리 소문자)가 턴 idle 일 때만 한 줄 주입
8
- // herdr — 자리 폴더 `herdr.pane` 의 pane 이 agent_status=idle 일 때만 한 줄 주입
8
+ // herdr — 자리 폴더 `herdr.pane` 의 pane 이 idle(·done) 일 때만 한 줄 주입 — `eln herdr prompt` 와 같은 생산 함수
9
+ // (`herdrPrompt` · `agent get` 상태 확인 → bracketed `pane run` 한 번). working/blocked 는 넣지 않고 busy.
9
10
  // none — stderr 경고 한 줄 · 해석 실패는 «모름»으로 남긴다(«없다»로 위장 금지)
10
11
  // ⛔ 우편은 입력칸에 넣지 않는다(대표 10-15 01:20) — 기본은 입력칸 주입 0. 10-15 01:10 사고: 대표 가 치던 문장에
11
12
  // 깨움 한 줄 ⊕ Enter 가 섞여 제출됐다(«에이전트 idle ≠ 사람이 안 친다»). 자리 폴더에서 푼 대상(pty 별명·
@@ -20,7 +21,6 @@
20
21
  // 상한(시도 3 · 2시간) → `gave-up`. 관측 = `loops.msg-wake` deferred | redelivered | gave-up.
21
22
  // 재두드림 «전»에 그 주소 미읽음을 잰다 — 0 이면 두드리지 않고 줄을 지운다(`dropped-read` · H4-FOLLOW ③).
22
23
 
23
- import { spawn } from 'node:child_process';
24
24
  import { Database } from 'bun:sqlite';
25
25
  import { randomUUID } from 'node:crypto';
26
26
  import { existsSync, lstatSync, mkdirSync, readFileSync } from 'node:fs';
@@ -30,6 +30,7 @@ import { dirname, join } from 'node:path';
30
30
  import { debug } from '../debug/log.js';
31
31
  import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
32
32
  import { readUnreadCount } from '../msg/msg-store.js';
33
+ import { herdrPrompt, type HerdrCliRunner } from '../pty-shell/herdr-prompt.js';
33
34
  import { listPtyManifestRows } from '../pty-shell/pty-manifest.js';
34
35
  import { messageRouteFor, type MessageWake } from './msg-address.js';
35
36
 
@@ -75,8 +76,8 @@ export interface WakeDeps {
75
76
  hasOptIn?: (path: string) => boolean;
76
77
  /** Loads the pty writer (the CLI module is heavy, so it is imported only when a pty wake is due). */
77
78
  ptyInjector?: () => Promise<(ptyId: string, line: string) => Promise<void>>;
78
- herdrStatus?: (paneId: string, signal: AbortSignal) => Promise<string>;
79
- herdrInject?: (paneId: string, line: string, signal: AbortSignal) => Promise<void>;
79
+ /** The herdr CLI runner `herdrPrompt` drives (`agent get` · `pane run`). Default: the real `herdr` (HERDR_BIN_PATH · PATH). */
80
+ herdrRun?: HerdrCliRunner;
80
81
  warn?: (line: string) => void;
81
82
  /** Unread count for an address before a deferred re-knock (H4-FOLLOW ③). null = «모름» (never drops). Default: the msg ledger. */
82
83
  readUnread?: (address: string) => number | null;
@@ -178,29 +179,6 @@ function releaseClaim(claim: WakeClaim): void {
178
179
  } catch { /* a stale claim only delays the next wake by one window */ }
179
180
  }
180
181
 
181
- function run(cmd: string, args: string[], timeoutMs: number, signal: AbortSignal): Promise<string> {
182
- return new Promise((resolve, reject) => {
183
- if (signal.aborted) { reject(new Error(`${cmd} aborted`)); return; }
184
- const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], signal });
185
- let out = '';
186
- const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error(`${cmd} timeout`)); }, timeoutMs);
187
- child.stdout.on('data', chunk => { out += String(chunk); });
188
- child.on('error', error => { clearTimeout(timer); reject(error); });
189
- child.on('close', code => { clearTimeout(timer); code === 0 ? resolve(out) : reject(new Error(`${cmd} exit ${code}`)); });
190
- });
191
- }
192
-
193
- async function defaultHerdrStatus(paneId: string, signal: AbortSignal): Promise<string> {
194
- const parsed = JSON.parse(await run('herdr', ['pane', 'get', paneId], WAKE_TIMEOUT_MS, signal)) as { result?: { pane?: { agent_status?: unknown } } };
195
- const status = parsed.result?.pane?.agent_status;
196
- return typeof status === 'string' ? status : 'unknown';
197
- }
198
-
199
- async function defaultHerdrInject(paneId: string, line: string, signal: AbortSignal): Promise<void> {
200
- // `pane run` = send-text ⊕ Enter 한 번에.
201
- await run('herdr', ['pane', 'run', paneId, line], WAKE_TIMEOUT_MS, signal);
202
- }
203
-
204
182
  async function defaultPtyInjector(): Promise<(ptyId: string, line: string) => Promise<void>> {
205
183
  const { runPtyText } = await import('../cli/pty-takeover-cli.js');
206
184
  return async (ptyId, line) => {
@@ -261,17 +239,35 @@ export async function wakeRecipient(address: string, msgId: number, message: { f
261
239
  injecting = true;
262
240
  await inject(resolution.target!, line);
263
241
  } else {
264
- const status = await (deps.herdrStatus ?? defaultHerdrStatus)(resolution.target!, controller.signal);
265
- if (status !== 'idle') return done('busy', `agent_status=${status}`);
266
- // 조회 사이 자리의 pane 이 바뀌었으면 옛 pane 에 넣지 않는다 — 주소→대상을 다시 푼다.
267
- const again = resolveWake(address, deps);
268
- // opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
269
- if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
270
- if (again.wake !== 'herdr' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
271
- // ⛔ 마감은 «주입 바로 앞»에서 — 재해석이 늦어 넘겼어도 새 주입 0.
272
- if (expired()) return done('timeout');
273
- injecting = true;
274
- await (deps.herdrInject ?? defaultHerdrInject)(resolution.target!, line, controller.signal);
242
+ // `eln herdr prompt` 와 같은 생산 함수 — 상태 확인(idle·done 만) → 제출 앞 관문 → bracketed `pane run` 한 번.
243
+ // 라벨은 묻지 않는다(anyAgent): 자리 폴더가 이미 대상을 정했고, claude/codex pane 도 예전처럼 깨운다.
244
+ const target = resolution.target!;
245
+ const prompted = await herdrPrompt({ target, text: line, anyAgent: true, paneFallback: true, timeoutMs: Math.max(1, deadline - Date.now()) }, {
246
+ ...(deps.herdrRun ? { run: deps.herdrRun } : {}),
247
+ beforeSubmit: () => {
248
+ // opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
249
+ if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return 'human-pane-no-opt-in'; }
250
+ // 조회 사이 자리의 pane 이 바뀌었으면 옛 pane 에 넣지 않는다 — 주소→대상을 다시 푼다.
251
+ const again = resolveWake(address, deps);
252
+ if (again.wake !== 'herdr' || again.target !== target) return `target-moved:${again.target ?? again.wake}`;
253
+ // ⛔ 마감은 «주입 바로 앞»에서 — 재해석이 늦어 넘겼어도 새 주입 0.
254
+ if (expired()) return 'timeout';
255
+ injecting = true;
256
+ return undefined;
257
+ },
258
+ });
259
+ if (!prompted.accepted) injecting = false;
260
+ const reason = prompted.reason;
261
+ const result: WakeResult = reason === 'submitted' ? 'injected'
262
+ : reason === 'human-pane-no-opt-in' ? 'skipped'
263
+ : reason === 'timeout' ? 'timeout'
264
+ : reason.startsWith('target-moved:') || reason === 'agent_working' || reason === 'agent_blocked' || reason === 'agent_unknown' ? 'busy'
265
+ : 'failed';
266
+ const outReason = result === 'busy' && !reason.startsWith('target-moved:') ? `agent_status=${prompted.status ?? 'unknown'}`
267
+ : result === 'injected' || result === 'timeout' ? undefined : reason;
268
+ logPending('herdr-prompt', { seat: address.trim().toUpperCase(), msgId, target, result, accepted: prompted.accepted, reason,
269
+ ...(prompted.status ? { status: prompted.status } : {}), ...(prompted.agent ? { agent: prompted.agent } : {}), ms: prompted.ms });
270
+ if (result !== 'injected') return done(result, outReason);
275
271
  }
276
272
  return done('injected');
277
273
  } catch (error) {
@@ -309,7 +305,7 @@ export async function wakeRecipient(address: string, msgId: number, message: { f
309
305
 
310
306
  interface PendingWakeRow { address: string; first_msg_id: number; last_msg_id: number; last_from: string; count: number; since: number; attempts: number; reason: string }
311
307
 
312
- export type PendingWakeEvent = 'deferred' | 'redelivered' | 'gave-up' | 'dropped-read' | 'skip';
308
+ export type PendingWakeEvent = 'deferred' | 'redelivered' | 'gave-up' | 'dropped-read' | 'skip' | 'herdr-prompt';
313
309
 
314
310
  function logPending(event: PendingWakeEvent, data: Record<string, unknown>): void {
315
311
  try { debug.log('loops.msg-wake', event, data); } catch { /* observability is fail-open */ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * ANOMALY-CLUSTER-PRODUCT — repeated failure signatures hold relaunches.
3
+ *
4
+ * Reference contract (read-only, unchanged): `seat-state/OP/tools/anomaly-cluster.{sh,py}` groups the same
5
+ * failures for an OP seat by eye and never holds anything automatically. This module is the product
6
+ * transfer of that reading contract: it computes a signature and turns it into a hold/release decision.
7
+ *
8
+ * Boundary: when the SAME signature shows up in 3+ DIFFERENT runs, relaunches of that goal·host are held
9
+ * automatically until a cause verdict (`release`) clears them. The host is a hold key, never part of the
10
+ * signature. When there is nothing measured for a goal·host, the hold reason says so ("원천 미측정").
11
+ *
12
+ * Pure module: no fs, no network, no clock reads unless a `now` seam is injected.
13
+ */
14
+
15
+ /** Runs of the same signature required before relaunches are held. */
16
+ export const ANOMALY_HOLD_THRESHOLD = 3;
17
+
18
+ /** Signature components: failure kind · container exit · stage · tail of `lastLines` reason. */
19
+ export interface FailureObservation {
20
+ /** Goal identifier — a hold key, not part of the signature. */
21
+ goal: string;
22
+ /** Host (seat / surface / launch host) — a hold key, not part of the signature. */
23
+ host: string;
24
+ /** Run identifier — the unit counted as "a different run". */
25
+ runId: string;
26
+ /** Failure kind (`preflight` · `exit` · `timeout` · adapter name …). */
27
+ kind: string;
28
+ /** Container exit code when observed; `null`/absent when the failure never reached a container. */
29
+ containerExit?: number | null;
30
+ /** Stage the failure was observed at (`launch` · `delegate` · `monitor` …). */
31
+ stage: string;
32
+ /** Tail lines of the failure; the last non-empty line is the "reason tail" that splits signatures. */
33
+ lastLines?: readonly string[];
34
+ at?: string;
35
+ }
36
+
37
+ export interface HoldDecision {
38
+ /** `true` when relaunches of this goal·host are held. */
39
+ hold: boolean;
40
+ /** Korean explanation — includes "원천 미측정" when nothing was measured. */
41
+ reason: string;
42
+ signature?: string;
43
+ /** Distinct runs counted for the holding signature. */
44
+ runs?: number;
45
+ }
46
+
47
+ export interface ReleaseDecision {
48
+ released: boolean;
49
+ reason: string;
50
+ }
51
+
52
+ const REASON_TAIL_LIMIT = 160;
53
+
54
+ /** Collapse whitespace and cap length — the reason tail is a signature component, not a payload. */
55
+ function reasonTail(lines: readonly string[] | undefined): string {
56
+ if (!lines || lines.length === 0) return 'none';
57
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
58
+ const line = (lines[i] ?? '').replace(/\s+/g, ' ').trim().replace(/^reason\s*[:=]\s*/i, '');
59
+ if (line) return line.slice(0, REASON_TAIL_LIMIT);
60
+ }
61
+ return 'none';
62
+ }
63
+
64
+ /** Pull a container exit code out of free text (`exited with code 137`, `exit status 1`, `exit=137`). */
65
+ export function extractContainerExit(text: string): number | null {
66
+ const match = /(?:exit(?:ed)?(?: with)?(?: code| status)?|exit=)\s*[:=]?\s*(\d+)/i.exec(text ?? '');
67
+ if (!match) return null;
68
+ const value = Number.parseInt(match[1]!, 10);
69
+ return Number.isFinite(value) ? value : null;
70
+ }
71
+
72
+ /**
73
+ * Signature = kind · exit · stage · reason tail. Host and run are deliberately excluded: the host is a
74
+ * hold key and the run is the counter.
75
+ */
76
+ export function failureSignature(obs: FailureObservation): string {
77
+ const exit = obs.containerExit === undefined || obs.containerExit === null ? 'none' : String(obs.containerExit);
78
+ return `kind=${obs.kind}|exit=${exit}|stage=${obs.stage}|reason=${reasonTail(obs.lastLines)}`;
79
+ }
80
+
81
+ interface ClusterState {
82
+ goal: string;
83
+ host: string;
84
+ signature: string;
85
+ runs: Set<string>;
86
+ held: boolean;
87
+ /** First `FailureObservation.at` read into this cluster — the observation window shown in the reason. */
88
+ firstAt?: string;
89
+ /** Latest `FailureObservation.at` read into this cluster. */
90
+ lastAt?: string;
91
+ }
92
+
93
+ function keyOf(goal: string, host: string): string {
94
+ return `${goal}\u0000${host}`;
95
+ }
96
+
97
+ /** In-memory grouping state — written by the failure observation point, read by the relaunch point. */
98
+ export class AnomalyCluster {
99
+ private readonly threshold: number;
100
+ private readonly now: () => Date;
101
+ private readonly clusters = new Map<string, ClusterState>();
102
+ /**
103
+ * Observations of a DIFFERENT signature that arrived while its goal·host was held. They are kept
104
+ * counting in a side bucket so a late-arriving observation can never drop a hold before a cause
105
+ * verdict — the hold is only ever cleared by `release`.
106
+ */
107
+ private readonly parked = new Map<string, ClusterState>();
108
+
109
+ constructor(opts: { threshold?: number; now?: () => Date } = {}) {
110
+ this.threshold = Math.max(1, Math.trunc(opts.threshold ?? ANOMALY_HOLD_THRESHOLD));
111
+ this.now = opts.now ?? (() => new Date());
112
+ }
113
+
114
+ /** Record one failure observation and return the resulting hold decision for its goal·host. */
115
+ record(obs: FailureObservation): { signature: string; runs: number; hold: HoldDecision } {
116
+ const signature = failureSignature(obs);
117
+ const key = keyOf(obs.goal, obs.host);
118
+ const at = typeof obs.at === 'string' && obs.at.trim() ? obs.at.trim() : undefined;
119
+ let cluster = this.clusters.get(key);
120
+ if (cluster && cluster.signature !== signature && cluster.held) {
121
+ // Held: the signature is frozen until a cause verdict. A late observation of another signature is
122
+ // counted in the parked bucket — replacing the cluster here would silently drop the hold.
123
+ const parkedKey = keyOf(key, signature);
124
+ let parked = this.parked.get(parkedKey);
125
+ if (!parked) {
126
+ parked = { goal: obs.goal, host: obs.host, signature, runs: new Set(), held: false };
127
+ this.parked.set(parkedKey, parked);
128
+ }
129
+ this.touch(parked, obs.runId, at);
130
+ const held = this.describe(cluster);
131
+ return {
132
+ signature: cluster.signature,
133
+ runs: cluster.runs.size,
134
+ hold: {
135
+ ...held,
136
+ reason: `${held.reason} · 보류 중 도착한 다른 서명 ${parked.runs.size}건은 해제 없이 별도 보관(판정 뒤 재판정)`,
137
+ },
138
+ };
139
+ }
140
+ if (!cluster || cluster.signature !== signature) {
141
+ // Not held: a different signature takes over. A parked bucket of that same signature keeps its runs.
142
+ const parkedKey = keyOf(key, signature);
143
+ const resumed = this.parked.get(parkedKey);
144
+ for (const stale of [...this.parked.keys()]) {
145
+ if (stale !== parkedKey && stale.startsWith(`${key}\u0000`)) this.parked.delete(stale);
146
+ }
147
+ if (resumed) this.parked.delete(parkedKey);
148
+ cluster = resumed ?? { goal: obs.goal, host: obs.host, signature, runs: new Set(), held: false };
149
+ this.clusters.set(key, cluster);
150
+ }
151
+ this.touch(cluster, obs.runId, at);
152
+ return { signature, runs: cluster.runs.size, hold: this.describe(cluster) };
153
+ }
154
+
155
+ /** Relaunch gate. A hold is decided before any cause verdict; the reason names an unmeasured source. */
156
+ hold(goal: string, host: string): HoldDecision {
157
+ const cluster = this.clusters.get(keyOf(goal, host));
158
+ if (!cluster) {
159
+ return { hold: false, reason: `원천 미측정: ${goal}·${host} 의 실패 관측이 없다 — 보류 판정 근거 없음` };
160
+ }
161
+ return this.describe(cluster);
162
+ }
163
+
164
+ isHeld(goal: string, host: string): boolean {
165
+ return this.clusters.get(keyOf(goal, host))?.held ?? false;
166
+ }
167
+
168
+ /** Cause verdict — clears the hold. Returns `released: false` when nothing was held. */
169
+ release(goal: string, host: string, cause: string): ReleaseDecision {
170
+ const key = keyOf(goal, host);
171
+ const cluster = this.clusters.get(key);
172
+ if (!cluster || !cluster.held) {
173
+ return { released: false, reason: `${goal}·${host} 는 보류 상태가 아니다` };
174
+ }
175
+ const judged = cluster.signature;
176
+ const judgedRuns = cluster.runs.size;
177
+ cluster.held = false;
178
+ cluster.runs.clear();
179
+ cluster.firstAt = undefined;
180
+ cluster.lastAt = undefined;
181
+ const promoted = this.takeStrongestParked(key);
182
+ if (promoted) this.clusters.set(key, promoted);
183
+ const head = `보류 해제: ${cause} (${this.now().toISOString()}) — 판정한 서명 ${judged} ${judgedRuns}건`;
184
+ return {
185
+ released: true,
186
+ reason: promoted
187
+ ? `${head} · 보류 중 보관한 다른 서명 ${promoted.signature} ${promoted.runs.size}건을 재판정 대상으로 승격${promoted.held ? ' (임계 도달 — 새 서명 기준 재보류)' : ''}`
188
+ : head,
189
+ };
190
+ }
191
+
192
+ private touch(cluster: ClusterState, runId: string, at: string | undefined): void {
193
+ cluster.runs.add(runId);
194
+ if (at) {
195
+ cluster.firstAt ??= at;
196
+ cluster.lastAt = at;
197
+ }
198
+ if (cluster.runs.size >= this.threshold) cluster.held = true;
199
+ }
200
+
201
+ /** The parked bucket of this goal·host with the most runs — the next signature to judge. */
202
+ private takeStrongestParked(key: string): ClusterState | undefined {
203
+ let best: ClusterState | undefined;
204
+ let bestKey: string | undefined;
205
+ for (const [parkedKey, state] of this.parked) {
206
+ if (!parkedKey.startsWith(`${key}\u0000`)) continue;
207
+ if (!best || state.runs.size > best.runs.size) {
208
+ best = state;
209
+ bestKey = parkedKey;
210
+ }
211
+ }
212
+ if (best && bestKey) this.parked.delete(bestKey);
213
+ return best;
214
+ }
215
+
216
+ private describe(cluster: ClusterState): HoldDecision {
217
+ const runs = cluster.runs.size;
218
+ const window = cluster.firstAt ? ` · 관측 ${cluster.firstAt}${cluster.lastAt && cluster.lastAt !== cluster.firstAt ? `..${cluster.lastAt}` : ''}` : '';
219
+ if (cluster.held) {
220
+ return {
221
+ hold: true,
222
+ reason: `같은 서명 ${runs}건(임계 ${this.threshold}) — 원인 판정 전 ${cluster.goal}·${cluster.host} 재발사 보류${window}`,
223
+ signature: cluster.signature,
224
+ runs,
225
+ };
226
+ }
227
+ return {
228
+ hold: false,
229
+ reason: `같은 서명 ${runs}건 < 임계 ${this.threshold} — 보류하지 않는다${window}`,
230
+ signature: cluster.signature,
231
+ runs,
232
+ };
233
+ }
234
+ }
235
+
236
+ /** Process-wide cluster shared by the tick failure record point and the dispatcher relaunch gate. */
237
+ let shared: AnomalyCluster | undefined;
238
+
239
+ /** Lazily created shared instance — no fs side effects, process-wide by design. */
240
+ export function defaultAnomalyCluster(): AnomalyCluster {
241
+ shared ??= new AnomalyCluster();
242
+ return shared;
243
+ }