elanous 0.2.38 → 0.2.41

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 (712) hide show
  1. package/README.md +7 -7
  2. package/apps/pwa/out/404/index.html +1 -1
  3. package/apps/pwa/out/404.html +1 -1
  4. package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_buildManifest.js +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +149 -0
  6. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +36 -0
  7. package/apps/pwa/out/_next/static/chunks/1178.1aa9cad0e7695427.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 1219.7e17964e0e7cd8e5.js} +3 -3
  10. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +287 -0
  11. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +90 -0
  16. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{7573.2376e13c9c21f1f8.js → 1765.679b29625c8e88d4.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 1800.f7ff51dc4978a958.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 2263.e09b6edea33bad2d.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +41 -0
  31. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +32 -0
  32. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 2fdf2931.b431eee4fb468bc3.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 2fe2c302.41b517f88d6fe502.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +79 -0
  36. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +74 -0
  41. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → 385e4574.e9886ab32759eda3.js} +3 -3
  46. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +148 -0
  53. package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 4527.a69f2894d1bc9f4a.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +226 -0
  55. package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 4667.97e31aa38c95c475.js} +4 -4
  56. package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 4702.4a4adc1f16d7c93b.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +94 -0
  64. package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 5159.115f1c2ca471386c.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/530.d26346e18089640a.js +115 -0
  67. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +8 -0
  68. package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → 53aeb4ee-51c92f8d683f5220.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 5471.1e611302ed3a7c53.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 5574.f35accf4f132b29d.js} +1 -1
  73. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 5744.b9415e18ad623100.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/{5300.677c97e0393742e6.js → 5892.2526d962339662d8.js} +1 -1
  76. package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +286 -0
  78. package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 5947-135e26537d80a6b9.js} +3 -3
  79. package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 5964-7e21164a8f2cf0ce.js} +1 -1
  80. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +62 -0
  86. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +24 -0
  87. package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +2 -0
  88. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +122 -0
  90. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2415.738b777642a02233.js → 7191.fdc955f7d96064a4.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8050-9b364bdef8f71927.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +104 -0
  103. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 9048.212083de42d25be3.js} +2 -2
  110. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 9507.7026657a2f47eb64.js} +16 -16
  117. package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +93 -0
  118. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +34 -0
  123. package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 9834.63ab2bbc3153172e.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/{3389.012c70767a872f9b.js → 9869.81a1e24ca682d5a0.js} +1 -1
  125. package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → a0a01613.6d1cca322238d7fe.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → addc2b32.8c4ff8f0aefe987d.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-14949db884bfa672.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/b2271e54.c1de3347976e90b0.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → c0c1a699.0ba79f97005965d4.js} +7 -7
  180. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +1 -0
  185. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +1 -0
  186. package/apps/pwa/out/approvals/index.html +1 -1
  187. package/apps/pwa/out/approvals/index.txt +22 -22
  188. package/apps/pwa/out/autopilot/index.html +1 -1
  189. package/apps/pwa/out/autopilot/index.txt +22 -22
  190. package/apps/pwa/out/board/index.html +1 -1
  191. package/apps/pwa/out/board/index.txt +22 -22
  192. package/apps/pwa/out/botlab/index.html +1 -1
  193. package/apps/pwa/out/botlab/index.txt +21 -21
  194. package/apps/pwa/out/bots/index.html +1 -1
  195. package/apps/pwa/out/bots/index.txt +21 -21
  196. package/apps/pwa/out/ceo/index.html +1 -1
  197. package/apps/pwa/out/ceo/index.txt +22 -22
  198. package/apps/pwa/out/chat/index.html +1 -1
  199. package/apps/pwa/out/chat/index.txt +21 -21
  200. package/apps/pwa/out/consult/index.html +1 -1
  201. package/apps/pwa/out/consult/index.txt +22 -22
  202. package/apps/pwa/out/control/index.html +1 -1
  203. package/apps/pwa/out/control/index.txt +22 -22
  204. package/apps/pwa/out/decisions/index.html +1 -1
  205. package/apps/pwa/out/decisions/index.txt +21 -21
  206. package/apps/pwa/out/design-check/index.html +1 -1
  207. package/apps/pwa/out/design-check/index.txt +22 -22
  208. package/apps/pwa/out/editor/index.html +1 -1
  209. package/apps/pwa/out/editor/index.txt +22 -22
  210. package/apps/pwa/out/exec/index.html +1 -1
  211. package/apps/pwa/out/exec/index.txt +22 -22
  212. package/apps/pwa/out/field/index.html +1 -1
  213. package/apps/pwa/out/field/index.txt +22 -22
  214. package/apps/pwa/out/healthz +1 -1
  215. package/apps/pwa/out/index.html +1 -1
  216. package/apps/pwa/out/index.txt +21 -21
  217. package/apps/pwa/out/inside/index.html +1 -1
  218. package/apps/pwa/out/inside/index.txt +21 -21
  219. package/apps/pwa/out/intake/index.html +1 -1
  220. package/apps/pwa/out/intake/index.txt +22 -22
  221. package/apps/pwa/out/live/index.html +1 -1
  222. package/apps/pwa/out/live/index.txt +22 -22
  223. package/apps/pwa/out/live-run/index.html +1 -1
  224. package/apps/pwa/out/live-run/index.txt +22 -22
  225. package/apps/pwa/out/loops/index.html +1 -1
  226. package/apps/pwa/out/loops/index.txt +21 -21
  227. package/apps/pwa/out/market/index.html +1 -1
  228. package/apps/pwa/out/market/index.txt +21 -21
  229. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  230. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  231. package/apps/pwa/out/morning/index.html +1 -1
  232. package/apps/pwa/out/morning/index.txt +22 -22
  233. package/apps/pwa/out/observatory/index.html +1 -1
  234. package/apps/pwa/out/observatory/index.txt +22 -22
  235. package/apps/pwa/out/ops/checklist/index.html +1 -1
  236. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  237. package/apps/pwa/out/ops/release/index.html +1 -1
  238. package/apps/pwa/out/ops/release/index.txt +21 -21
  239. package/apps/pwa/out/ops/seats/index.html +1 -1
  240. package/apps/pwa/out/ops/seats/index.txt +21 -21
  241. package/apps/pwa/out/outputs/index.html +1 -1
  242. package/apps/pwa/out/outputs/index.txt +21 -21
  243. package/apps/pwa/out/reflection/index.html +1 -1
  244. package/apps/pwa/out/reflection/index.txt +22 -22
  245. package/apps/pwa/out/scheduler/index.html +1 -1
  246. package/apps/pwa/out/scheduler/index.txt +22 -22
  247. package/apps/pwa/out/sessions/index.html +1 -1
  248. package/apps/pwa/out/sessions/index.txt +21 -21
  249. package/apps/pwa/out/settings/devices/index.html +1 -1
  250. package/apps/pwa/out/settings/devices/index.txt +22 -22
  251. package/apps/pwa/out/settings/index.html +1 -1
  252. package/apps/pwa/out/settings/index.txt +22 -22
  253. package/apps/pwa/out/setup/done/index.html +1 -1
  254. package/apps/pwa/out/setup/done/index.txt +22 -22
  255. package/apps/pwa/out/setup/index.html +1 -1
  256. package/apps/pwa/out/setup/index.txt +22 -22
  257. package/apps/pwa/out/share/index.html +1 -1
  258. package/apps/pwa/out/share/index.txt +22 -22
  259. package/apps/pwa/out/showroom/index.html +1 -1
  260. package/apps/pwa/out/showroom/index.txt +21 -21
  261. package/apps/pwa/out/tasks/index.html +1 -1
  262. package/apps/pwa/out/tasks/index.txt +22 -22
  263. package/apps/pwa/out/term/index.html +1 -1
  264. package/apps/pwa/out/term/index.txt +22 -22
  265. package/apps/pwa/out/today/index.html +1 -1
  266. package/apps/pwa/out/today/index.txt +22 -22
  267. package/apps/pwa/out/trace/index.html +1 -1
  268. package/apps/pwa/out/trace/index.txt +22 -22
  269. package/apps/pwa/out/vault/index.html +1 -1
  270. package/apps/pwa/out/vault/index.txt +22 -22
  271. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  272. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  273. package/apps/pwa/out/workflows/index.html +1 -1
  274. package/apps/pwa/out/workflows/index.txt +22 -22
  275. package/apps/pwa/out/workspace/index.html +1 -1
  276. package/apps/pwa/out/workspace/index.txt +22 -22
  277. package/apps/pwa/out/worktrees/index.html +1 -1
  278. package/apps/pwa/out/worktrees/index.txt +22 -22
  279. package/bin/elanous.mjs +6 -1
  280. package/catalog/models/openai/gpt-6.1-sol.yaml +16 -0
  281. package/catalog/models/openai/gpt-6.1-terra.yaml +16 -0
  282. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  283. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  284. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  285. package/graphs/demo/persona-teacher/lesson-pack.yaml +16 -0
  286. package/graphs/demo/persona-teacher/recipes.yaml +17 -0
  287. package/graphs/demo/persona-teacher/weekly-lesson.yaml +36 -0
  288. package/graphs/overlays/stop-heal-ladder.yaml +23 -2
  289. package/graphs/release/release-loop.yaml +3 -1
  290. package/graphs/units/gate/gate.yaml +20 -0
  291. package/graphs/units/git/git.yaml +26 -0
  292. package/graphs/units/implement/implement.yaml +19 -0
  293. package/graphs/units/landing/landing.yaml +18 -0
  294. package/graphs/units/review/review.yaml +20 -0
  295. package/graphs/units/verbs/recipes.yaml +3 -0
  296. package/graphs/units/verbs/research.yaml +20 -0
  297. package/graphs/video/explainer-line.yaml +4 -1
  298. package/graphs/work/research-report.yaml +11 -1
  299. package/package.json +1 -1
  300. package/scripts/dead-code/report.ts +169 -0
  301. package/scripts/disk-steward.ts +46 -0
  302. package/scripts/fleet/node-setup.sh +50 -0
  303. package/scripts/graph-units/verbs/research.ts +55 -0
  304. package/scripts/lib/morning-report-options.ts +3 -4
  305. package/scripts/lib/tui-regress-evidence.ts +56 -0
  306. package/scripts/llm-cost-ledger.ts +179 -8
  307. package/scripts/measure-nl-routing-corpus.ts +10 -2
  308. package/scripts/morning-report.ts +5 -1
  309. package/scripts/persona-teacher/weekly-lesson-node.ts +172 -0
  310. package/scripts/public-copy-lint.ts +163 -19
  311. package/scripts/public-export.ts +15 -7
  312. package/scripts/ratchets/train-side-invariants.sh +0 -1
  313. package/scripts/release-loop/export-check-node.ts +21 -3
  314. package/scripts/release-loop/gate-autoheal.ts +117 -0
  315. package/scripts/release-loop/gate-baseline-receipt.ts +8 -1
  316. package/scripts/release-loop/gate-diff.ts +22 -3
  317. package/scripts/release-loop/gate-node.ts +583 -64
  318. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  319. package/scripts/release-loop/gate-shard-load-flaky.ts +256 -0
  320. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  321. package/scripts/release-loop/gate-triage-node.ts +70 -10
  322. package/scripts/release-loop/gate-wall.ts +5 -5
  323. package/scripts/release-loop/preflight.ts +6 -2
  324. package/scripts/release-loop/resume-release.ts +267 -20
  325. package/scripts/release-loop/resume.ts +48 -0
  326. package/scripts/release-loop/traffic-node.ts +6 -3
  327. package/scripts/release-loop/unattended-release.ts +4 -2
  328. package/scripts/release-loop/version-node.ts +7 -2
  329. package/scripts/release-story/draft.ts +1 -1
  330. package/scripts/research-bench/README.md +53 -0
  331. package/scripts/research-bench/questions.json +66 -0
  332. package/scripts/research-bench/rubric.md +33 -0
  333. package/scripts/research-bench/run.ts +523 -0
  334. package/scripts/shadow-authoring-probe.ts +20 -0
  335. package/scripts/tui-regress.ts +85 -10
  336. package/scripts/ux-sim.ts +19 -2
  337. package/src/acp/core-turn-bridge.ts +94 -4
  338. package/src/agent/autonomous-tools.ts +10 -3
  339. package/src/agent/monad-agent-turn.ts +4 -1
  340. package/src/agent/registry.ts +26 -2
  341. package/src/agent/shared-app-tools.ts +1 -1
  342. package/src/agent/surface-ux/build.ts +12 -3
  343. package/src/agent/surface-ux/types.ts +1 -1
  344. package/src/agent/task-notification.ts +75 -6
  345. package/src/agent/types.ts +3 -0
  346. package/src/agent-mission/driver.ts +29 -3
  347. package/src/agent-mission/mission-cli.ts +2 -1
  348. package/src/agent-substrate/review-context-pack.ts +365 -0
  349. package/src/agent-substrate/self-review-cli.ts +291 -20
  350. package/src/ask-user-question/index.ts +6 -0
  351. package/src/ask-user-question/inline-resolver.ts +49 -0
  352. package/src/auto-research/question-ladder-contract.ts +22 -3
  353. package/src/auto-research/research-turn.ts +359 -17
  354. package/src/autopilot/agent-loop.ts +1 -1
  355. package/src/autopilot/discovery/wiki-claim-proposer.ts +22 -1
  356. package/src/autopilot/pty-control-loop.ts +8 -1
  357. package/src/boot/daemon-tools/index.ts +4 -3
  358. package/src/boot/daemon-tools/self-implement.ts +312 -7
  359. package/src/boot/daemon-tools/types.ts +2 -0
  360. package/src/budget/llm-cost.ts +44 -5
  361. package/src/budget/shadow-arms.ts +52 -0
  362. package/src/budget/unified-usage.ts +17 -1
  363. package/src/capture/tui-self-report.ts +14 -0
  364. package/src/chat/index.ts +33 -7
  365. package/src/chat/pickers/state.ts +7 -1
  366. package/src/cli/agent-cli.ts +43 -8
  367. package/src/cli/intake-cli.ts +22 -1
  368. package/src/cli/lesson-cli.ts +19 -3
  369. package/src/cli/log-event-names.ts +6 -0
  370. package/src/cli/mcp-login.ts +8 -18
  371. package/src/cli/msg-cli.ts +57 -1
  372. package/src/cli/pod-cli.ts +17 -2
  373. package/src/cli/pr-land-heavy-remote.ts +15 -9
  374. package/src/cli/pty-takeover-cli.ts +67 -7
  375. package/src/cli/release-cli.ts +79 -7
  376. package/src/cli/repo-cli.ts +2 -1
  377. package/src/cli/sim-cli.ts +7 -1
  378. package/src/cli/tasks-cli.ts +41 -13
  379. package/src/codex/models.ts +30 -15
  380. package/src/control-plane/ledger.ts +21 -4
  381. package/src/core-turn/run-core-turn.ts +47 -3
  382. package/src/core-turn/run-goal-loop.ts +240 -10
  383. package/src/core-turn/types.ts +9 -0
  384. package/src/dashboard/acp-boot.ts +72 -3
  385. package/src/dashboard/chat/acp-chat.ts +2 -2
  386. package/src/dashboard/classic-sigquit.ts +16 -0
  387. package/src/dashboard/index.ts +327 -27
  388. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  389. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  390. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  391. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  392. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  393. package/src/dashboard/input/external-input-host.ts +2 -0
  394. package/src/dashboard/sidetab-runtime.ts +228 -0
  395. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  396. package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
  397. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  398. package/src/dashboard/term-slash-runtime.ts +16 -18
  399. package/src/dashboard/turn-preamble.ts +14 -1
  400. package/src/disk-steward/judge.ts +73 -0
  401. package/src/disk-steward/ledger.ts +122 -0
  402. package/src/disk-steward/steward.ts +373 -0
  403. package/src/domains/guardian-tick.ts +191 -2
  404. package/src/domains/knowledge.ts +1 -1
  405. package/src/esc-abort-gate.ts +33 -1
  406. package/src/execution-loop/launch-gate.ts +206 -1
  407. package/src/graph-runner/graph-cli.ts +27 -4
  408. package/src/graph-runner/in-process-registry.ts +37 -0
  409. package/src/graph-runner/runner.ts +63 -11
  410. package/src/graph-wizard/generate.ts +16 -7
  411. package/src/graph-wizard/mission-compose.ts +201 -0
  412. package/src/grok/agent-search.ts +8 -2
  413. package/src/grok/credential.ts +5 -0
  414. package/src/grounding/ref-index.ts +30 -0
  415. package/src/grounding/ref-vector.ts +61 -0
  416. package/src/grounding/sources-cli.ts +11 -3
  417. package/src/grounding/sources.ts +15 -1
  418. package/src/harness/harness-cli-command.ts +305 -23
  419. package/src/harness/harness-incidents.ts +312 -7
  420. package/src/harness/harness-pod-dispatch.ts +7 -1
  421. package/src/harness/harness-space.ts +15 -1
  422. package/src/harness/progress-worker-entry.ts +59 -0
  423. package/src/harness/progress-worker-runtime.ts +11 -0
  424. package/src/index.ts +35 -5
  425. package/src/input/external-input-queue.ts +10 -0
  426. package/src/instance/dev-project.ts +25 -0
  427. package/src/intake-plane/collect-telegram-saved.ts +36 -1
  428. package/src/intake-plane/intake-to-tasks.ts +246 -3
  429. package/src/intelligence-map/model-alias.ts +6 -5
  430. package/src/intelligence-map/model-catalog.ts +59 -2
  431. package/src/lessons/friction-ledger.ts +154 -0
  432. package/src/live-supply/collector.ts +149 -0
  433. package/src/live-supply/probes.ts +52 -0
  434. package/src/live-supply/snapshot.ts +40 -0
  435. package/src/llm/model-defaults.ts +4 -4
  436. package/src/llm.ts +473 -87
  437. package/src/loops/orchestrator/tick.ts +56 -0
  438. package/src/mcp/mcp-oauth.ts +3 -1
  439. package/src/model-tier/llm-tier-map.ts +9 -9
  440. package/src/model-tier/turn-tier.ts +1 -1
  441. package/src/msg/msg-mirror-github.ts +80 -0
  442. package/src/msg/msg-mirror-policy.ts +61 -0
  443. package/src/msg/msg-mirror-runner.ts +219 -0
  444. package/src/msg/msg-mirror-state.ts +33 -0
  445. package/src/msg/msg-store.ts +11 -0
  446. package/src/nexus/api/harness-api.ts +2 -1
  447. package/src/output-truncation.ts +41 -12
  448. package/src/project/project-store.ts +48 -1
  449. package/src/pty/snapshot.py +132 -0
  450. package/src/pty-shell/pty-control-ipc.ts +29 -2
  451. package/src/pty-shell/pty-manifest.ts +59 -3
  452. package/src/pty-shell/registry.ts +2 -0
  453. package/src/pty-shell/tui-run-state.ts +80 -3
  454. package/src/release-loop/gate-host-reservation.ts +157 -4
  455. package/src/release-loop/gate-shard-ledger.ts +68 -0
  456. package/src/release-loop/merged-pr-checklist.ts +25 -2
  457. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  458. package/src/release-loop/rehearsal.ts +27 -0
  459. package/src/release-loop/release-schedule.ts +90 -1
  460. package/src/research/bloom-exemplars.ts +135 -0
  461. package/src/research/edge-decision.ts +124 -15
  462. package/src/research/gap-followup.ts +249 -0
  463. package/src/research/lenses/counter-evidence.ts +100 -0
  464. package/src/research/lenses/working-backwards.ts +89 -0
  465. package/src/research/plugin-discovery.ts +242 -0
  466. package/src/research-bridge/invoke.ts +4 -2
  467. package/src/research-bridge/types.ts +2 -0
  468. package/src/self-dev/ask-launch-flow.ts +73 -131
  469. package/src/self-dev/dev-cli.ts +19 -17
  470. package/src/self-dev/dev-pipeline.ts +8 -4
  471. package/src/self-dev/graph-front-nodes.ts +23 -0
  472. package/src/self-dev/graph-journey-route.ts +10 -2
  473. package/src/self-dev/launch-preflight-text.ts +2 -2
  474. package/src/self-dev/launch-preflight.ts +47 -11
  475. package/src/self-dev/orchestrate-cli.ts +1 -0
  476. package/src/self-dev/orchestrate.ts +15 -0
  477. package/src/self-dev/run-supervisor.ts +204 -3
  478. package/src/self-dev/run-types.ts +3 -0
  479. package/src/self-implement/device-first.ts +8 -2
  480. package/src/self-implement/doctor-visit.ts +76 -58
  481. package/src/self-implement/gate-artifacts.ts +16 -0
  482. package/src/self-implement/gate-baseline.ts +75 -4
  483. package/src/self-implement/gate-cli.ts +368 -30
  484. package/src/self-implement/gate-receipt-registry.ts +180 -0
  485. package/src/self-implement/gate-remote.ts +165 -24
  486. package/src/self-implement/goal-author-clarification.ts +205 -32
  487. package/src/self-implement/goal-author-decompose.ts +24 -15
  488. package/src/self-implement/goal-author.ts +86 -10
  489. package/src/self-implement/graph-stage-units.ts +172 -0
  490. package/src/self-implement/graph-templates.ts +162 -1
  491. package/src/self-implement/graph-variant.ts +37 -4
  492. package/src/self-implement/host-regate.ts +124 -49
  493. package/src/self-implement/impl-findings-feedback.ts +188 -0
  494. package/src/self-implement/knowhow-pack.ts +227 -10
  495. package/src/self-implement/off-diff-evidence.ts +124 -0
  496. package/src/self-implement/orchestrator.ts +320 -28
  497. package/src/self-implement/run-ledger.ts +110 -14
  498. package/src/self-implement/run-stop.ts +33 -2
  499. package/src/self-implement/running-runs.ts +35 -12
  500. package/src/self-implement/seams.ts +6 -3
  501. package/src/self-implement/self-implement-cli.ts +40 -6
  502. package/src/self-implement/stop-autoheal-operational.ts +43 -0
  503. package/src/self-implement/stop-autoheal.ts +15 -6
  504. package/src/session/chat.ts +66 -15
  505. package/src/session/request-size-guard.ts +123 -0
  506. package/src/session-runtime/provider-circuit.ts +140 -0
  507. package/src/shell-runner/file-engine.ts +1 -0
  508. package/src/shell-runner/types.ts +4 -0
  509. package/src/sidetab-core/model.ts +312 -0
  510. package/src/skills/tools/schedule-wakeup.ts +23 -1
  511. package/src/skills/tools/shell.ts +51 -5
  512. package/src/steward/directive-audit.ts +354 -0
  513. package/src/surface/child-process.ts +31 -0
  514. package/src/surface/tui-stderr-owner.ts +48 -0
  515. package/src/task-agent/cover.ts +30 -12
  516. package/src/task-agent/judge.ts +56 -0
  517. package/src/task-agent/parent-host.ts +14 -1
  518. package/src/task-agent/postland-card.ts +35 -2
  519. package/src/task-agent/rejudge-on-head.ts +46 -2
  520. package/src/task-agent/repair-cycle.ts +1 -1
  521. package/src/task-agent/task-hand.ts +133 -25
  522. package/src/task-agent/tier-split.ts +105 -21
  523. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  524. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  525. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +70 -2
  526. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +29 -4
  527. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  528. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  529. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  530. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  531. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  532. package/src/task-orchestrator/surfaces/self-implement-pod.ts +298 -45
  533. package/src/task-orchestrator/surfaces/self-implement.ts +18 -0
  534. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  535. package/src/tui/entry.ts +25 -5
  536. package/src/tui/inline-choice.ts +188 -0
  537. package/src/tui/sidetab/list.ts +36 -165
  538. package/src/tui/sidetab/nl-tool.ts +2 -136
  539. package/src/tui/sidetab/peek.ts +52 -0
  540. package/src/tui/slash/term.ts +12 -1
  541. package/src/tui-client/dashboard-session.ts +10 -1
  542. package/src/user-config.ts +45 -9
  543. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  544. package/src/ux-sim/fake-land-queue.ts +88 -0
  545. package/src/ux-sim/fault-needs-human-reason-repair.ts +107 -0
  546. package/src/ux-sim/fault-pod-child-result.ts +42 -0
  547. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  548. package/src/ux-sim/goal-interim-trace.ts +24 -0
  549. package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
  550. package/src/ux-sim/release-sim-rig.ts +262 -0
  551. package/src/ux-sim/seminar-rehearsal.ts +109 -0
  552. package/src/ux-sim/subagent-tools-device.ts +2 -2
  553. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  554. package/src/version/packed-revision.json +1 -1
  555. package/src/video-pipeline/recipes/explainer.ts +54 -2
  556. package/src/web-search/grok.ts +32 -6
  557. package/src/web-search/index.ts +8 -7
  558. package/src/workflow-runtime/node-catalog.ts +53 -4
  559. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
  560. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +0 -148
  567. package/apps/pwa/out/_next/static/chunks/2104.70e086d5174a4736.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
  571. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
  572. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
  581. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
  583. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
  586. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
  592. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4199-f7c6eb40cd0322f8.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
  604. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
  605. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
  607. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
  614. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
  617. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
  629. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7524.ce973525d30b3d52.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/7628.6b16863ac3972333.js +0 -34
  636. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/7954.4f7a8832663ee979.js +0 -115
  639. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
  647. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
  648. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +0 -226
  649. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
  650. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
  654. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +0 -122
  705. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
  711. package/scripts/ratchets/next-tui-entry-budget.ts +0 -124
  712. /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_ssgManifest.js +0 -0
@@ -1,12 +1,18 @@
1
1
  import type { Database } from 'bun:sqlite';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
2
4
  import { hostname } from 'node:os';
5
+ import { dirname, join } from 'node:path';
3
6
  import { fileURLToPath } from 'node:url';
7
+ import { elanousStateRoot } from '../autopilot/state-paths.js';
4
8
  import { debug } from '../debug/log.js';
9
+ import { withFileLockSync } from '../storage/file-lock.js';
5
10
  import { calendarFields, resolveTimeZone } from '../time/format.js';
6
11
  import { cronMatches } from './cron-match.js';
7
12
  import { listScheduleRuns } from './schedule-runs.js';
8
13
  import { listSchedules, openSchedulesDb, type ScheduleRow } from './schedule-registry.js';
9
14
  import type { SpawnOutcome } from './schedule-runner.js';
15
+ import { classifyTcellHealthCards, type TcellHealthCard, type TcellHealthClassification } from '../harness/harness-incidents.js';
10
16
 
11
17
  export interface GuardianPlan {
12
18
  jobs: readonly (Pick<ScheduleRow, 'id' | 'cron' | 'enabled' | 'source' | 'run_via'> & Partial<Pick<ScheduleRow, 'command'>>)[];
@@ -21,9 +27,147 @@ export interface GuardianDeps {
21
27
  grokExpiry?: () => string | null;
22
28
  /** Injected in tests; production reevaluates recorded doctor visits without dispatching a prescription. */
23
29
  doctorShadow?: () => void | Promise<void>;
30
+ /** Read-only health-card source. T-cell classification remains shadow-only and never dispatches an action. */
31
+ readTcellHealthCards?: (now: Date) => readonly TcellHealthCard[] | Promise<readonly TcellHealthCard[]>;
32
+ /** Test-only path override; production uses the resolved state root. */
33
+ tcellDedupeStatePath?: string;
24
34
  hostName?: string;
25
35
  }
26
36
 
37
+ type TcellPatrolSummary = Pick<TcellHealthClassification, 'total' | 'measured' | 'counts'> & { unmeasured: number };
38
+
39
+ type TcellShadowMailTarget = 'doctor' | 'macrophage';
40
+ interface TcellShadowMailProposal {
41
+ causeGroupId: string;
42
+ target: TcellShadowMailTarget;
43
+ reason: 'no-progress-30m' | 'risk-signal' | 'cause-quorum';
44
+ runIds: string[];
45
+ runIdsTruncated: boolean;
46
+ causeGroupSize: number;
47
+ }
48
+
49
+ const TCELL_SHADOW_DEDUPE_WINDOW_MS = 60 * 60_000;
50
+ interface TcellShadowDedupeState {
51
+ version: 1;
52
+ lastProposedAt: Record<string, number>;
53
+ }
54
+ interface TcellShadowMailSuppression {
55
+ proposal: TcellShadowMailProposal;
56
+ lastProposedAt?: number;
57
+ eligibleAt?: number;
58
+ suppressionReason: 'hourly-dedupe' | 'dedupe-state-unavailable';
59
+ }
60
+
61
+ function tcellShadowDedupePath(): string {
62
+ return join(elanousStateRoot(), 'guardian', 'tcell-dedupe.json');
63
+ }
64
+
65
+ function loadTcellShadowDedupeState(path: string): TcellShadowDedupeState {
66
+ let raw: string;
67
+ try { raw = readFileSync(path, 'utf8'); }
68
+ catch (error) {
69
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { version: 1, lastProposedAt: {} };
70
+ throw error;
71
+ }
72
+ const parsed: unknown = JSON.parse(raw);
73
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid T-cell dedupe state');
74
+ const record = parsed as Record<string, unknown>;
75
+ if (record.version !== 1 || !record.lastProposedAt || typeof record.lastProposedAt !== 'object' || Array.isArray(record.lastProposedAt)) {
76
+ throw new Error('invalid T-cell dedupe state shape');
77
+ }
78
+ const lastProposedAt: Record<string, number> = Object.create(null) as Record<string, number>;
79
+ for (const [causeGroupId, at] of Object.entries(record.lastProposedAt)) {
80
+ if (!causeGroupId || !Number.isSafeInteger(at) || (at as number) < 0) throw new Error('invalid T-cell dedupe timestamp');
81
+ lastProposedAt[causeGroupId] = at as number;
82
+ }
83
+ return { version: 1, lastProposedAt };
84
+ }
85
+
86
+ /** Reserve the per-cause hourly shadow proposal before logging it, so concurrent guardian ticks share the limit. */
87
+ function reserveTcellShadowMail(proposals: readonly TcellShadowMailProposal[], nowMs: number, statePath?: string): {
88
+ proposed: TcellShadowMailProposal[];
89
+ suppressed: TcellShadowMailSuppression[];
90
+ stateError?: unknown;
91
+ } {
92
+ if (proposals.length === 0) return { proposed: [], suppressed: [] };
93
+ const path = statePath ?? tcellShadowDedupePath();
94
+ try {
95
+ mkdirSync(dirname(path), { recursive: true });
96
+ return withFileLockSync(`${path}.lock`, () => {
97
+ const state = loadTcellShadowDedupeState(path);
98
+ const lastProposedAt = Object.assign(Object.create(null) as Record<string, number>, state.lastProposedAt);
99
+ let changed = false;
100
+ for (const [causeGroupId, at] of Object.entries(lastProposedAt)) {
101
+ if (nowMs - at >= TCELL_SHADOW_DEDUPE_WINDOW_MS) {
102
+ delete lastProposedAt[causeGroupId];
103
+ changed = true;
104
+ }
105
+ }
106
+
107
+ const proposed: TcellShadowMailProposal[] = [];
108
+ const suppressed: TcellShadowMailSuppression[] = [];
109
+ for (const proposal of proposals) {
110
+ const last = lastProposedAt[proposal.causeGroupId];
111
+ if (last !== undefined && nowMs - last < TCELL_SHADOW_DEDUPE_WINDOW_MS) {
112
+ suppressed.push({ proposal, lastProposedAt: last, eligibleAt: last + TCELL_SHADOW_DEDUPE_WINDOW_MS,
113
+ suppressionReason: 'hourly-dedupe' });
114
+ continue;
115
+ }
116
+ lastProposedAt[proposal.causeGroupId] = nowMs;
117
+ changed = true;
118
+ proposed.push(proposal);
119
+ }
120
+
121
+ if (changed) {
122
+ const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
123
+ try {
124
+ writeFileSync(tmp, `${JSON.stringify({ version: 1, lastProposedAt }, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
125
+ renameSync(tmp, path);
126
+ } finally {
127
+ try { unlinkSync(tmp); } catch { /* rename succeeded or temp was never created */ }
128
+ }
129
+ }
130
+ return { proposed, suppressed };
131
+ });
132
+ } catch (stateError) {
133
+ return { proposed: [], suppressed: proposals.map(proposal => ({ proposal, suppressionReason: 'dedupe-state-unavailable' })), stateError };
134
+ }
135
+ }
136
+
137
+ function proposeTcellShadowMail(classification: TcellHealthClassification): {
138
+ proposals: TcellShadowMailProposal[]; proposalsTruncated: number; missingCause: number;
139
+ } {
140
+ const byCause = new Map<string, typeof classification.decisions>();
141
+ let missingCause = 0;
142
+ for (const decision of classification.decisions) {
143
+ if (decision.classification !== 'stalled' && decision.classification !== 'infected') continue;
144
+ if (!decision.causeGroupId || !decision.causeGroupSize) { missingCause++; continue; }
145
+ const group = byCause.get(decision.causeGroupId) ?? [];
146
+ group.push(decision);
147
+ byCause.set(decision.causeGroupId, group);
148
+ }
149
+
150
+ const proposals: TcellShadowMailProposal[] = [];
151
+ for (const [causeGroupId, decisions] of byCause) {
152
+ const infected = decisions.filter(decision => decision.classification === 'infected');
153
+ const selected = infected.length ? infected : decisions;
154
+ const first = selected[0]!;
155
+ const reason = infected.length
156
+ ? (infected.some(decision => decision.reason === 'cause-quorum') ? 'cause-quorum' : 'risk-signal')
157
+ : 'no-progress-30m';
158
+ const runIds = [...new Set(selected.map(decision => decision.runId))];
159
+ proposals.push({
160
+ causeGroupId,
161
+ target: infected.length ? 'macrophage' : 'doctor',
162
+ reason,
163
+ runIds: runIds.slice(0, 25),
164
+ runIdsTruncated: runIds.length > 25,
165
+ causeGroupSize: first.causeGroupSize!,
166
+ });
167
+ }
168
+ return { proposals: proposals.slice(0, 100), proposalsTruncated: Math.max(0, proposals.length - 100), missingCause };
169
+ }
170
+
27
171
  export const GROK_EXPIRY_ALERT_WINDOW_MS = 4 * 60 * 60 * 1000;
28
172
 
29
173
  function durationLabel(ms: number): string {
@@ -85,7 +229,7 @@ function liveCommand(jobId: string, raw: string): string {
85
229
  }
86
230
 
87
231
  /** One five-minute guardian observation. No schedule state or crontab is mutated in shadow mode. */
88
- export async function guardianTick(now: Date, plan: GuardianPlan, deps: GuardianDeps = {}): Promise<{ mode: 'shadow' | 'live'; wouldRun: string[]; executed: number; credentialAlert?: string }> {
232
+ export async function guardianTick(now: Date, plan: GuardianPlan, deps: GuardianDeps = {}): Promise<{ mode: 'shadow' | 'live'; wouldRun: string[]; executed: number; credentialAlert?: string; tcellPatrol?: TcellPatrolSummary }> {
89
233
  if (!Number.isFinite(now.getTime())) throw new RangeError('invalid tick time');
90
234
  const mode = deps.config?.guardian?.mode === 'live' ? 'live' : 'shadow';
91
235
  let expiryLine: string | null = null;
@@ -109,6 +253,51 @@ export async function guardianTick(now: Date, plan: GuardianPlan, deps: Guardian
109
253
  errorName: error instanceof Error ? error.name : 'unknown',
110
254
  });
111
255
  }
256
+ let tcellPatrol: TcellPatrolSummary | undefined;
257
+ if (deps.readTcellHealthCards) {
258
+ try {
259
+ const cards = await deps.readTcellHealthCards(now);
260
+ const classification = classifyTcellHealthCards(cards, now.getTime());
261
+ const shadowMail = proposeTcellShadowMail(classification);
262
+ const reservedMail = reserveTcellShadowMail(shadowMail.proposals, now.getTime(), deps.tcellDedupeStatePath);
263
+ tcellPatrol = { total: classification.total, measured: classification.measured,
264
+ unmeasured: classification.unmeasuredRunIds.length, counts: classification.counts };
265
+ // One bounded shadow observation per guardian tick. Cause signatures are represented only by a digest.
266
+ debug.log('guardian.tcell', 'shadow-classification', {
267
+ mode: 'shadow', ...tcellPatrol,
268
+ shadowMailProposed: reservedMail.proposed.length,
269
+ shadowMailSuppressed: reservedMail.suppressed.length,
270
+ shadowMailProposalsTruncated: shadowMail.proposalsTruncated,
271
+ shadowMailMissingCause: shadowMail.missingCause,
272
+ decisions: classification.decisions.slice(0, 100).map(({ runId, stage, classification: verdict, reason, causeGroupId, causeGroupSize }) => ({
273
+ runId, stage, classification: verdict, reason, ...(causeGroupId ? { causeGroupId, causeGroupSize } : {}),
274
+ })),
275
+ decisionsTruncated: classification.decisions.length > 100,
276
+ });
277
+ if (reservedMail.stateError) {
278
+ debug.log('guardian.tcell', 'shadow-mail-dedupe-unavailable', {
279
+ mode: 'shadow', errorName: reservedMail.stateError instanceof Error ? reservedMail.stateError.name : 'unknown',
280
+ suppressed: reservedMail.suppressed.length,
281
+ });
282
+ }
283
+ for (const suppressed of reservedMail.suppressed) {
284
+ debug.log('guardian.tcell', 'shadow-mail-suppressed', {
285
+ mode: 'shadow', ...suppressed.proposal, suppressionReason: suppressed.suppressionReason,
286
+ ...(suppressed.lastProposedAt !== undefined ? { lastProposedAt: suppressed.lastProposedAt } : {}),
287
+ ...(suppressed.eligibleAt !== undefined ? { eligibleAt: suppressed.eligibleAt } : {}),
288
+ });
289
+ }
290
+ for (const proposal of reservedMail.proposed) {
291
+ debug.log('guardian.tcell', 'shadow-mail-proposed', {
292
+ mode: 'shadow', recipientCandidate: 'OP', ownerRule: 'first-recipient-ack', ...proposal,
293
+ });
294
+ }
295
+ } catch (error) {
296
+ debug.log('guardian.tcell', 'observation-failed', {
297
+ mode: 'shadow', errorName: error instanceof Error ? error.name : 'unknown',
298
+ });
299
+ }
300
+ }
112
301
  const timeZone = plan.timeZone ?? resolveTimeZone().timeZone;
113
302
  const wouldRun: string[] = [];
114
303
  let executed = 0;
@@ -125,7 +314,7 @@ export async function guardianTick(now: Date, plan: GuardianPlan, deps: Guardian
125
314
  if (outcome.code !== 0) throw new Error(`guardian job ${job.id} exited ${outcome.code}`);
126
315
  }
127
316
  }
128
- return { mode, wouldRun, executed, ...(expiryLine ? { credentialAlert: expiryLine } : {}) };
317
+ return { mode, wouldRun, executed, ...(expiryLine ? { credentialAlert: expiryLine } : {}), ...(tcellPatrol ? { tcellPatrol } : {}) };
129
318
  }
130
319
 
131
320
  export interface GuardianDayDeps {
@@ -52,7 +52,7 @@ export interface KnowledgeDoc {
52
52
  // 의미검색으로 회상(domain='elanous'). [[self-awareness]].
53
53
  // memory = M3 consolidation(2026-07-08): 흐린 에피소드 다수를 의미 umbrella 1건으로
54
54
  // 압축·영속(에피소드→의미·수면 공고화). 원본은 consolidated 마킹.
55
- kind: 'signal' | 'dig' | 'alpha' | 'xreport' | 'morning' | 'outbound' | 'docs' | 'memory' | 'taste';
55
+ kind: 'signal' | 'dig' | 'alpha' | 'xreport' | 'morning' | 'outbound' | 'docs' | 'memory' | 'taste' | 'reference';
56
56
  sector_tags: string | null;
57
57
  text: string;
58
58
  source_ref: string | null;
@@ -33,7 +33,7 @@ import type { ModalBounds, ModalSurface } from './display/modal-stack.js';
33
33
  import type { KeyEvent } from './display/types.js';
34
34
  import type { ThemeTokens } from './theme/tokens.js';
35
35
  import { debug } from './debug/log.js';
36
- import { abortTurnOnly } from './turn-abort-scope.js';
36
+ import { abortAndKillChildren, abortTurnOnly } from './turn-abort-scope.js';
37
37
  import { SELF_IMPLEMENT_TOOL_NAMES } from './boot/daemon-tools/self-implement-names.js';
38
38
 
39
39
  export const DASHBOARD_CLARIFICATION_REQUEST = Symbol.for('elanous.dashboard.clarification-request');
@@ -57,6 +57,10 @@ export interface EscAbortGateDeps {
57
57
  getWaitingTargetNames?: () => readonly string[];
58
58
  /** Only an identified foreground harness run may bypass the sub-agent confirmation. */
59
59
  shouldAbortImmediately?: () => boolean;
60
+ /** Seat mode can have no operator to answer a confirmation: Esc stops this turn and its children without opening a modal. */
61
+ forceStopWithoutModal?: () => boolean;
62
+ /** Non-modal replacement for the approval surface in unattended TUI mode. Timeout/cancel resolves false. */
63
+ confirmStopInline?: () => Promise<boolean>;
60
64
  /** Called before abortTurnOnly so the UI can paint a visible pending state immediately. */
61
65
  onAbortPending?: (event: { running: number; repeat: number; targets: readonly string[] }) => void;
62
66
  /** Called when another Escape arrives after the first abort request. */
@@ -218,7 +222,9 @@ export function createEscAbortGate(deps: EscAbortGateDeps): EscAbortGate {
218
222
  let current: ApprovalModalHandle | null = null;
219
223
  let currentDispose: (() => void) | null = null;
220
224
  let abortPending = false;
225
+ let inlineConfirmationPending = false;
221
226
  let escapePresses = 0;
227
+ let disposed = false;
222
228
 
223
229
  const redraw = (): void => {
224
230
  try { deps.requestRedraw?.(); } catch { /* ignore */ }
@@ -282,6 +288,31 @@ export function createEscAbortGate(deps: EscAbortGateDeps): EscAbortGate {
282
288
  return;
283
289
  }
284
290
  const running = deps.getRunningCount();
291
+ if (running > 0 && deps.forceStopWithoutModal?.()) {
292
+ if (inlineConfirmationPending) return;
293
+ if (!deps.confirmStopInline) {
294
+ debug.log('esc.abort', 'unattended-force-stop', { running, repeat: Math.max(0, escapePresses - 1) });
295
+ abortAndKillChildren(deps.abortCtrl);
296
+ redraw();
297
+ return;
298
+ }
299
+ inlineConfirmationPending = true;
300
+ debug.log('esc.abort', 'unattended-inline-confirmation', { running, repeat: Math.max(0, escapePresses - 1) });
301
+ void deps.confirmStopInline().then((confirmed) => {
302
+ if (confirmed && !disposed && !deps.abortCtrl.signal.aborted) {
303
+ debug.log('esc.abort', 'unattended-inline-confirmed', { running });
304
+ abortAndKillChildren(deps.abortCtrl);
305
+ } else {
306
+ debug.log('esc.abort', 'unattended-inline-cancelled', { running, reason: 'declined-or-timeout' });
307
+ resetAbortRequestState();
308
+ }
309
+ }).catch((error) => {
310
+ debug.log('esc.abort', 'unattended-inline-failed', { reason: error instanceof Error ? error.message : String(error) }, { level: 'warn' });
311
+ resetAbortRequestState();
312
+ }).finally(() => { inlineConfirmationPending = false; redraw(); });
313
+ redraw();
314
+ return;
315
+ }
285
316
  if (running <= 0 || deps.shouldAbortImmediately?.()) {
286
317
  debug.log('esc.abort', 'abort-immediately', { running, repeat: Math.max(0, escapePresses - 1) });
287
318
  abortPendingTurn(running);
@@ -347,6 +378,7 @@ export function createEscAbortGate(deps: EscAbortGateDeps): EscAbortGate {
347
378
  resetAbortRequestState();
348
379
  },
349
380
  dispose(): void {
381
+ disposed = true;
350
382
  if (current) current.dispose(false);
351
383
  resetAbortRequestState();
352
384
  close();
@@ -1,6 +1,9 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { readFileSync } from 'node:fs';
2
+ import { closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync, writeSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
3
4
  import { debug } from '../debug/log.js';
5
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
6
+ import { assertLedgerPathPolicy } from '../harness/launch-utterance-ledger.js';
4
7
  import { extractVerbatimOriginalAsk } from '../self-implement/goal-author.js';
5
8
  import { loadRunLedger } from '../self-implement/run-ledger.js';
6
9
  import { queryRunningRuns, type QueriedRunningRunsResult } from '../self-implement/running-runs.js';
@@ -252,6 +255,8 @@ export interface PreLaunchGateInput {
252
255
 
253
256
  export interface PreLaunchGateDeps extends ActiveRunsForGoalDeps {
254
257
  activeRuns?: (goalId: string) => ActiveRunsForGoal;
258
+ /** LAUNCH-SINGLE-DOOR-1C — 주입 우선 단일문: 시험 우주가 격리 루트의 문을 끼워 생산 배선을 그대로 검증한다. */
259
+ launchDoor?: LaunchRequestDoor;
255
260
  }
256
261
 
257
262
  export interface PreLaunchGateDecision {
@@ -279,3 +284,203 @@ function decidePreLaunch(input: PreLaunchGateInput, deps: PreLaunchGateDeps): Pr
279
284
  }
280
285
  return { action: 'proceed', sameGoalActiveRuns, budget, reason: sameGoalActiveRuns === 'unknown' ? 'active runs unknown' : input.forceLaunch && sameGoalActiveRuns.length > 0 ? 'duplicate overridden by force-launch' : 'no confirmed duplicate' };
281
286
  }
287
+
288
+ // ─────────────────────────────────────────────────────────────────────────────────────
289
+ // LAUNCH-SINGLE-DOOR-1C — 발사 요청의 단일 문.
290
+ // ─────────────────────────────────────────────────────────────────────────────────────
291
+
292
+ /** Env contract: hand 가 소비한 requestId 를 자식 say 가 물려받아 같은 문을 다시 두드리지 않게 한다(한 번만 상속). */
293
+ export const LAUNCH_DOOR_RECEIPT_ENV = 'ELANOUS_LAUNCH_DOOR_RECEIPT';
294
+
295
+ /** append 전용 요청 원장의 행 종류 — 요청(중복 포함)·소비·거절·강제·실패·단일문 사용 불가 관측. */
296
+ export type LaunchRequestLedgerEvent = 'requested' | 'consumed' | 'refused-duplicate' | 'forced-duplicate' | 'launch-failed' | 'door-unavailable';
297
+
298
+ /** append 전용 요청 원장의 한 행 — 행은 지우거나 고치지 않는다(관측 전용). */
299
+ export interface LaunchRequestLedgerRow {
300
+ readonly event: LaunchRequestLedgerEvent;
301
+ readonly requestId: string;
302
+ readonly at: string;
303
+ readonly source?: string;
304
+ readonly receiptId?: string;
305
+ readonly reason?: string;
306
+ }
307
+
308
+ /** requestId 단위 소비 영수증 — 최초 1회만 발급된다(O_EXCL 파일이 곧 영수증이다). */
309
+ export interface LaunchRequestReceipt {
310
+ readonly requestId: string;
311
+ readonly receiptId: string;
312
+ readonly at: string;
313
+ readonly source?: string;
314
+ }
315
+
316
+ /** `consume` 의 답 — `refused` 는 기존 영수증을 읽어 사유와 함께 거절한 것이다. */
317
+ export type LaunchRequestConsumption =
318
+ | { readonly status: 'consumed'; readonly requestId: string; readonly receiptId: string; readonly receiptAt: string; readonly inherited?: true }
319
+ | { readonly status: 'forced'; readonly requestId: string; readonly receiptId: string | null; readonly receiptAt: string | null; readonly reason: string }
320
+ | { readonly status: 'refused'; readonly requestId: string; readonly receiptId: string | null; readonly receiptAt: string | null; readonly reason: string }
321
+ | { readonly status: 'unavailable'; readonly requestId: string; readonly reason: string };
322
+
323
+ /** 발사 요청의 단일 문 — 원장 append · 단일 소비 · 실패 기록 · 원장 조회. */
324
+ export interface LaunchRequestDoor {
325
+ /** 요청 한 건을 원장에 append 하고 그 requestId 를 돌려준다(중복 재요청도 매번 append 된다). */
326
+ requestId(ask: string): string;
327
+ /** requestId 단위 단일 소비 — 영수증은 최초 1회만 발급된다(두 번째는 기존 영수증과 사유로 거절). */
328
+ consume(requestId: string, opts?: { readonly force?: boolean; readonly inheritedReceipt?: string }): LaunchRequestConsumption;
329
+ /** 발사 실패 사유를 원장에 append 한다(관측 — 발사를 막지 않는다). */
330
+ fail(requestId: string, reason: string): void;
331
+ /** 원장 조회 — 중복 거절·실패·재시도 사유를 읽는다(인자를 주면 그 requestId 의 행만). */
332
+ rows(requestId?: string): readonly LaunchRequestLedgerRow[];
333
+ }
334
+
335
+ /** 단일문 deps — 원장 뿌리(기본 = 이 우주의 실효 인스턴스 루트)·시계·요청 출처 표지. */
336
+ export interface LaunchRequestDoorDeps {
337
+ readonly root?: string;
338
+ readonly now?: () => Date;
339
+ readonly source?: string;
340
+ }
341
+
342
+ const LAUNCH_REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
343
+ const LAUNCH_REQUEST_DATE_FILE = /^\d{4}-\d{2}-\d{2}\.jsonl$/;
344
+
345
+ function launchRequestLedgerDir(root: string): string {
346
+ return join(resolve(root), 'launch-requests');
347
+ }
348
+
349
+ /** 단일문을 연다 — 문 자체는 상태를 갖지 않고, 원장·영수증은 이 우주의 인스턴스 루트 아래 파일로 남는다. */
350
+ export function openLaunchRequestDoor(deps: LaunchRequestDoorDeps = {}): LaunchRequestDoor {
351
+ const dir = launchRequestLedgerDir(deps.root ?? effectiveInstanceRoot());
352
+ const receiptsDir = join(dir, 'receipts');
353
+ const now = deps.now ?? (() => new Date());
354
+ const source = deps.source;
355
+
356
+ const observe = (event: string, data: Record<string, unknown>): void => {
357
+ try { debug.log('execution-loop.launch-gate', event, data, { level: 'warn' }); } catch { /* 관측은 fail-soft */ }
358
+ };
359
+
360
+ const appendRow = (row: LaunchRequestLedgerRow): boolean => {
361
+ try {
362
+ assertLedgerPathPolicy(dir);
363
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
364
+ assertLedgerPathPolicy(dir);
365
+ if (!lstatSync(dir).isDirectory()) throw new Error(`launch request ledger dir is not a directory: ${dir}`);
366
+ const file = join(dir, `${row.at.slice(0, 10)}.jsonl`);
367
+ const fd = openSync(file, constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
368
+ try {
369
+ if (!fstatSync(fd).isFile()) throw new Error(`launch request ledger file is not a regular file: ${file}`);
370
+ writeSync(fd, `${JSON.stringify(row)}\n`);
371
+ } finally { closeSync(fd); }
372
+ return true;
373
+ } catch (error) {
374
+ observe('request-ledger-unwritten', { event: row.event, requestId: row.requestId, reason: error instanceof Error ? error.message : String(error) });
375
+ return false;
376
+ }
377
+ };
378
+
379
+ const readReceipt = (requestId: string): LaunchRequestReceipt | null => {
380
+ try {
381
+ const fd = openSync(join(receiptsDir, `${requestId}.json`), constants.O_RDONLY | constants.O_NOFOLLOW);
382
+ try {
383
+ if (!fstatSync(fd).isFile()) return null;
384
+ const parsed = JSON.parse(readFileSync(fd, 'utf8')) as LaunchRequestReceipt;
385
+ return parsed && typeof parsed === 'object' && parsed.requestId === requestId
386
+ && typeof parsed.receiptId === 'string' && typeof parsed.at === 'string' ? parsed : null;
387
+ } finally { closeSync(fd); }
388
+ } catch { return null; }
389
+ };
390
+
391
+ const requestId = (ask: string): string => {
392
+ const id = launchRequestId(ask);
393
+ appendRow({ event: 'requested', requestId: id, at: now().toISOString(), ...(source ? { source } : {}) });
394
+ return id;
395
+ };
396
+
397
+ const consume = (id: string, opts: { readonly force?: boolean; readonly inheritedReceipt?: string } = {}): LaunchRequestConsumption => {
398
+ if (!LAUNCH_REQUEST_ID_PATTERN.test(id)) {
399
+ return { status: 'unavailable', requestId: id, reason: `requestId 가 원장 키로 쓸 수 없다: ${JSON.stringify(id)}` };
400
+ }
401
+ const at = now().toISOString();
402
+ // 부모(hand)가 같은 requestId 를 이미 소비했다면 상속 영수증으로 지나간다 — 새 영수증을 만들지 않는다.
403
+ if (opts.inheritedReceipt !== undefined && opts.inheritedReceipt === id) {
404
+ const inherited = readReceipt(id);
405
+ if (inherited !== null) {
406
+ try { debug.log('execution-loop.launch-gate', 'request-consumption-inherited', { requestId: id, receiptId: inherited.receiptId }); } catch { /* 관측은 fail-soft */ }
407
+ return { status: 'consumed', requestId: id, receiptId: inherited.receiptId, receiptAt: inherited.at, inherited: true };
408
+ }
409
+ }
410
+ const receipt: LaunchRequestReceipt = { requestId: id,
411
+ receiptId: `receipt-${createHash('sha256').update(`${id}:${at}`).digest('hex').slice(0, 12)}`, at,
412
+ ...(source ? { source } : {}) };
413
+ let created = true;
414
+ try {
415
+ assertLedgerPathPolicy(receiptsDir);
416
+ mkdirSync(receiptsDir, { recursive: true, mode: 0o700 });
417
+ assertLedgerPathPolicy(receiptsDir);
418
+ const fd = openSync(join(receiptsDir, `${id}.json`), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
419
+ try {
420
+ if (!fstatSync(fd).isFile()) throw new Error(`소비 영수증이 일반 파일이 아니다: ${id}`);
421
+ writeSync(fd, JSON.stringify(receipt));
422
+ } finally { closeSync(fd); }
423
+ } catch (error) {
424
+ if ((error as NodeJS.ErrnoException)?.code !== 'EEXIST') {
425
+ const reason = error instanceof Error ? error.message : String(error);
426
+ observe('request-receipt-unavailable', { requestId: id, reason });
427
+ appendRow({ event: 'door-unavailable', requestId: id, at, ...(source ? { source } : {}), reason });
428
+ return { status: 'unavailable', requestId: id, reason: `소비 영수증을 만들지 못했다 — 발사를 막지 않는다: ${reason}` };
429
+ }
430
+ created = false;
431
+ }
432
+ if (created) {
433
+ appendRow({ event: 'consumed', requestId: id, at, ...(source ? { source } : {}), receiptId: receipt.receiptId });
434
+ return { status: 'consumed', requestId: id, receiptId: receipt.receiptId, receiptAt: receipt.at };
435
+ }
436
+ const existing = readReceipt(id);
437
+ if (existing === null) {
438
+ const reason = `requestId ${id} 의 소비 영수증이 이미 있지만 읽지 못했다 — 중복 발사 거절`;
439
+ appendRow({ event: 'refused-duplicate', requestId: id, at, ...(source ? { source } : {}), reason });
440
+ return { status: 'refused', requestId: id, receiptId: null, receiptAt: null, reason };
441
+ }
442
+ if (opts.force === true) {
443
+ const reason = `requestId ${id} 는 영수증 ${existing.receiptId} (${existing.at}) 로 이미 소비됐다 — force 로 다시 띄운다`;
444
+ appendRow({ event: 'forced-duplicate', requestId: id, at, ...(source ? { source } : {}), receiptId: existing.receiptId, reason });
445
+ return { status: 'forced', requestId: id, receiptId: existing.receiptId, receiptAt: existing.at, reason };
446
+ }
447
+ const reason = `requestId ${id} 는 영수증 ${existing.receiptId} (${existing.at}) 로 이미 소비됐다 — 중복 발사 거절`;
448
+ appendRow({ event: 'refused-duplicate', requestId: id, at, ...(source ? { source } : {}), receiptId: existing.receiptId, reason });
449
+ return { status: 'refused', requestId: id, receiptId: existing.receiptId, receiptAt: existing.at, reason };
450
+ };
451
+
452
+ const fail = (id: string, reason: string): void => {
453
+ appendRow({ event: 'launch-failed', requestId: id, at: now().toISOString(),
454
+ ...(source ? { source } : {}), reason: reason.trim() || '사유 없음' });
455
+ };
456
+
457
+ const rows = (requestId?: string): readonly LaunchRequestLedgerRow[] => {
458
+ const result: LaunchRequestLedgerRow[] = [];
459
+ let names: string[];
460
+ try {
461
+ assertLedgerPathPolicy(dir);
462
+ names = readdirSync(dir);
463
+ } catch { return result; }
464
+ for (const name of names.filter((candidate) => LAUNCH_REQUEST_DATE_FILE.test(candidate)).sort()) {
465
+ let text: string;
466
+ try {
467
+ const fd = openSync(join(dir, name), constants.O_RDONLY | constants.O_NOFOLLOW);
468
+ try {
469
+ if (!fstatSync(fd).isFile()) continue;
470
+ text = readFileSync(fd, 'utf8');
471
+ } finally { closeSync(fd); }
472
+ } catch { continue; }
473
+ for (const line of text.split('\n')) {
474
+ if (!line) continue;
475
+ try {
476
+ const row = JSON.parse(line) as LaunchRequestLedgerRow;
477
+ if (row && typeof row === 'object' && typeof row.event === 'string' && typeof row.requestId === 'string'
478
+ && typeof row.at === 'string' && (requestId === undefined || row.requestId === requestId)) result.push(row);
479
+ } catch { /* 찢어진 줄은 건너뛴다 */ }
480
+ }
481
+ }
482
+ return result;
483
+ };
484
+
485
+ return { requestId, consume, fail, rows };
486
+ }
@@ -31,19 +31,21 @@ export function registerGraphCommands(program: Command, runsDeps: { root?: strin
31
31
  graph.command('adapt-report')
32
32
  .description('Measure recorded graph path diversity, unit calls, adaptations and landings for one goal')
33
33
  .requiredOption('--goal <id>', 'Goal ID to measure')
34
+ .option('--from <timestamp>', 'Include runs started at or after this ISO timestamp')
35
+ .option('--to <timestamp>', 'Exclude runs started at or after this ISO timestamp')
34
36
  .option('--json', 'Print measurement as JSON')
35
- .action(async (opts: { goal: string; json?: boolean }) => {
37
+ .action(async (opts: { goal: string; from?: string; to?: string; json?: boolean }) => {
36
38
  try {
37
39
  const { queryGraphAdaptReport } = await import('../self-implement/run-ledger.js');
38
- const report = queryGraphAdaptReport(opts.goal);
40
+ const report = queryGraphAdaptReport(opts.goal, undefined, { since: opts.from, until: opts.to });
39
41
  if (opts.json) await writeStdoutJson(JSON.stringify(report) + '\n');
40
- else if (report.runCount === 0) console.log(`graph adapt-report: ${opts.goal} · 표본 0 · 제외 ${report.excludedCount} ${JSON.stringify(report.exclusionReasons)}`);
42
+ else if (report.runCount === 0) console.log(`graph adapt-report: ${opts.goal} · 표본 0 · 제외 ${report.excludedCount} ${JSON.stringify(report.exclusionReasons)} · 미측정 ${report.unmeasuredCount} ${JSON.stringify(report.unmeasuredReasons)}`);
41
43
  else {
42
44
  const landing = (group: typeof report.adapted) => group.denominator
43
45
  ? `${group.landed}/${group.denominator} (${(group.rate! * 100).toFixed(1)}%)` : '표본 0';
44
46
  console.log(`graph adapt-report: ${opts.goal} · 경로 ${report.uniquePathSignatures} · 유닛 호출 ${report.unitCallCount} · 적응 ${report.adaptationCount}`);
45
47
  console.log(`적응 착지율 ${landing(report.adapted)} · 비적응 착지율 ${landing(report.nonAdapted)}`);
46
- console.log(`제외 ${report.excludedCount} ${JSON.stringify(report.exclusionReasons)}`);
48
+ console.log(`제외 ${report.excludedCount} ${JSON.stringify(report.exclusionReasons)} · 미측정 ${report.unmeasuredCount} ${JSON.stringify(report.unmeasuredReasons)}`);
47
49
  }
48
50
  } catch (error) {
49
51
  console.error(`graph adapt-report: ${error instanceof Error ? error.message : String(error)}`);
@@ -256,10 +258,31 @@ export function registerGraphCommands(program: Command, runsDeps: { root?: strin
256
258
  const { createScheduleSource } = await import('../workflow-runtime/triggers/schedule-source.js');
257
259
  const graphFile = resolve(file);
258
260
  const source = createScheduleSource();
261
+ const graphDocument = parseYaml(readFileSync(graphFile, 'utf8')) as { graph_id?: string; loop?: { trigger?: { events?: string[] } } };
262
+ const cutEventSubscribed = graphDocument.graph_id === 'release-loop'
263
+ && graphDocument.loop?.trigger?.events?.includes('release.cut.due') === true;
259
264
  // The CLI tick callback is the graph counterpart of the workflow scheduler's onEmit.
260
265
  const onScheduledTick = async () => {
261
266
  try {
262
267
  const { notifyGraphEvents } = await import('./graph-notify.js');
268
+ if (cutEventSubscribed) {
269
+ const { emitDueReleaseCutEvents } = await import('../release-loop/release-schedule.js');
270
+ const { runUnattendedRelease } = await import('../../scripts/release-loop/unattended-release.js');
271
+ try {
272
+ await emitDueReleaseCutEvents(new Date().toISOString(), async event => {
273
+ const fired = await runUnattendedRelease({ version: event.version, triggerEvent: event });
274
+ await notifyGraphEvents();
275
+ if (fired.state?.status === 'failed') console.error(`graph tick: ${fired.state.runId}: failed`);
276
+ });
277
+ } catch (error) {
278
+ debug.log('graph.runner', 'cut-event-failed', { file: graphFile, error: error instanceof Error ? error.message : String(error) });
279
+ console.error(`graph cut event: ${error instanceof Error ? error.message : String(error)}`);
280
+ }
281
+ const resumed = await graphTick(graphFile, { deps: { notify: async () => { await notifyGraphEvents(); } } });
282
+ if (resumed.status === 'refused') console.error(`graph tick: refused: ${resumed.reason}`);
283
+ else if (resumed.status === 'failed') console.error(`graph tick: ${resumed.runId}: failed`);
284
+ return;
285
+ }
263
286
  const result = await graphTick(graphFile, { startIfIdle: true, deps: { notify: async () => { await notifyGraphEvents(); } } });
264
287
  if (result.status === 'refused') console.error(`graph tick: refused: ${result.reason}`);
265
288
  else if (result.status === 'failed') console.error(`graph tick: ${result.runId}: failed`);
@@ -0,0 +1,37 @@
1
+ /** A run-scoped registry keeps in-process graph effects out of YAML and shell recipes. */
2
+ export interface InProcessHandlerContext {
3
+ readonly graphId: string;
4
+ readonly runId: string;
5
+ readonly nodeId: string;
6
+ readonly input: unknown;
7
+ readonly outputs: Readonly<Record<string, unknown>>;
8
+ }
9
+
10
+ export interface InProcessHandlerResult {
11
+ readonly ok: boolean;
12
+ /** Named edge outcome from the graph's declared map. */
13
+ readonly outcome: string;
14
+ readonly evidence?: Readonly<Record<string, unknown>>;
15
+ readonly error?: string;
16
+ }
17
+
18
+ export type InProcessHandler = (context: InProcessHandlerContext) =>
19
+ InProcessHandlerResult | Promise<InProcessHandlerResult>;
20
+
21
+ export type InProcessHandlerRegistry = Readonly<Record<string, InProcessHandler>>;
22
+
23
+ function inProcessHandlerName(recipe: string): string | undefined {
24
+ if (!recipe.startsWith('handler:')) return undefined;
25
+ const name = recipe.slice('handler:'.length);
26
+ if (!/^[a-z][a-z0-9-]*$/.test(name)) throw new Error(`invalid in-process handler recipe: ${recipe}`);
27
+ return name;
28
+ }
29
+
30
+ export function requireInProcessHandler(recipe: string, nodeId: string,
31
+ registry: InProcessHandlerRegistry | undefined): InProcessHandler | undefined {
32
+ const name = inProcessHandlerName(recipe);
33
+ if (name === undefined) return undefined;
34
+ const handler = registry && Object.hasOwn(registry, name) ? registry[name] : undefined;
35
+ if (typeof handler !== 'function') throw new Error(`unknown in-process handler for ${nodeId}: ${name}`);
36
+ return handler;
37
+ }