elanous 0.2.28 → 0.2.29

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 (609) 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/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.js → 058a98ba.7eb28d5e6dc03565.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{4565-67e4c620597965c8.js → 1015-9cba22a5a4554797.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +8 -0
  9. package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.js → 1142.65d002789ab3af7d.js} +2 -2
  10. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +34 -0
  12. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1516.dfaceff3fd2d0e0d.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +286 -0
  16. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +24 -0
  17. package/apps/pwa/out/_next/static/chunks/1782-59db1b5aa06df38a.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{1743.563d3168e95825ef.js → 1852.7f7b53991fcb99ef.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +36 -0
  22. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +64 -0
  24. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{65ebff95.081daeff622d238e.js → 285adb1a.5654e605dddf86d2.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +115 -0
  31. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3160-95c96f4d2a21dd26.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +90 -0
  36. package/apps/pwa/out/_next/static/chunks/328bb3ab-6628a1114fe3fb3b.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 3396-97b97928c49190c9.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 3403.7199205e65124486.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/419.736c0d6f426249a7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{6def8a8e.c81f9ca41028eccf.js → 425cfc4d.fb91158e3971c39f.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 46bd8bea.2f4b4099172fcdb7.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{5081.a240b63fad28663a.js → 4759.1f76713aefb87db5.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +94 -0
  54. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +27 -0
  63. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +104 -0
  64. package/apps/pwa/out/_next/static/chunks/{9974.e77b4ff4884557b3.js → 5591.a35e7a217734a8b9.js} +2 -2
  65. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +93 -0
  66. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/{5492-e05e26a033ba80d2.js → 6013-2f769370d8b4c2c6.js} +3 -3
  69. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +24 -0
  70. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +2 -0
  72. package/apps/pwa/out/_next/static/chunks/{5408.377c8c543635b81f.js → 6534.1ab00f370db7b105.js} +1 -1
  73. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +148 -0
  74. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +149 -0
  75. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +79 -0
  77. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/{8578.dff22d988cc2b106.js → 6767.1fcfc9b8be83975f.js} +16 -16
  79. package/apps/pwa/out/_next/static/chunks/6776.06ff1e3b464cc607.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.js → 6853.cc5174a9dee59593.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +287 -0
  86. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 7375.050ea0d72968e49f.js} +16 -16
  92. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +77 -0
  94. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +74 -0
  97. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7725-4f83d5541fbdb81b.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8332.6f0f49df772e163b.js +23 -0
  102. package/apps/pwa/out/_next/static/chunks/{7483.ba01c6c209b81bba.js → 8398.73a19b39715eda04.js} +1 -1
  103. package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.js → 8471.8d2a8c74f09c36ff.js} +3 -3
  104. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +226 -0
  106. package/apps/pwa/out/_next/static/chunks/{5785-ea8d2c633b6688e3.js → 8767-2f6a634f5abeaa01.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +32 -0
  109. package/apps/pwa/out/_next/static/chunks/8795.32573a185af18c7b.js +41 -0
  110. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.js → 9143.ff14585db1d275ff.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.js → 9907.49be0fcadaf214b5.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{973cbf1b.3bbcf2b41548eca7.js → a435ad95.577add051b4facb2.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-fa46d4588e8442c2.js → page-a5635eba0d73b84e.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/{page-66ad46ed0279feb9.js → page-86feb08080261a2f.js} +1 -1
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/{page-646b50f63b6fe732.js → page-8aaa6dedc4c10dfb.js} +1 -1
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-6f131b51193a36f9.js → page-33bf667a5fb297bf.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-29900ed0011b2c83.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{f4dfbfc0.a69fb12f854882aa.js → bc324b7c.02a09dd93f6a399b.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +122 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +1 -0
  183. package/apps/pwa/out/approvals/index.html +1 -1
  184. package/apps/pwa/out/approvals/index.txt +22 -22
  185. package/apps/pwa/out/autopilot/index.html +1 -1
  186. package/apps/pwa/out/autopilot/index.txt +22 -22
  187. package/apps/pwa/out/board/index.html +1 -1
  188. package/apps/pwa/out/board/index.txt +22 -22
  189. package/apps/pwa/out/botlab/index.html +1 -1
  190. package/apps/pwa/out/botlab/index.txt +21 -21
  191. package/apps/pwa/out/bots/index.html +1 -1
  192. package/apps/pwa/out/bots/index.txt +21 -21
  193. package/apps/pwa/out/ceo/index.html +1 -1
  194. package/apps/pwa/out/ceo/index.txt +22 -22
  195. package/apps/pwa/out/chat/index.html +1 -1
  196. package/apps/pwa/out/chat/index.txt +21 -21
  197. package/apps/pwa/out/consult/index.html +1 -1
  198. package/apps/pwa/out/consult/index.txt +22 -22
  199. package/apps/pwa/out/control/index.html +1 -1
  200. package/apps/pwa/out/control/index.txt +22 -22
  201. package/apps/pwa/out/decisions/index.html +1 -1
  202. package/apps/pwa/out/decisions/index.txt +21 -21
  203. package/apps/pwa/out/design-check/index.html +1 -1
  204. package/apps/pwa/out/design-check/index.txt +22 -22
  205. package/apps/pwa/out/editor/index.html +1 -1
  206. package/apps/pwa/out/editor/index.txt +22 -22
  207. package/apps/pwa/out/exec/index.html +1 -1
  208. package/apps/pwa/out/exec/index.txt +22 -22
  209. package/apps/pwa/out/field/index.html +1 -1
  210. package/apps/pwa/out/field/index.txt +22 -22
  211. package/apps/pwa/out/healthz +1 -1
  212. package/apps/pwa/out/index.html +1 -1
  213. package/apps/pwa/out/index.txt +21 -21
  214. package/apps/pwa/out/inside/index.html +1 -1
  215. package/apps/pwa/out/inside/index.txt +21 -21
  216. package/apps/pwa/out/intake/index.html +1 -1
  217. package/apps/pwa/out/intake/index.txt +22 -22
  218. package/apps/pwa/out/live/index.html +1 -1
  219. package/apps/pwa/out/live/index.txt +22 -22
  220. package/apps/pwa/out/live-run/index.html +1 -1
  221. package/apps/pwa/out/live-run/index.txt +22 -22
  222. package/apps/pwa/out/loops/index.html +1 -1
  223. package/apps/pwa/out/loops/index.txt +21 -21
  224. package/apps/pwa/out/market/index.html +1 -1
  225. package/apps/pwa/out/market/index.txt +21 -21
  226. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  227. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  228. package/apps/pwa/out/morning/index.html +1 -1
  229. package/apps/pwa/out/morning/index.txt +22 -22
  230. package/apps/pwa/out/observatory/index.html +1 -1
  231. package/apps/pwa/out/observatory/index.txt +22 -22
  232. package/apps/pwa/out/ops/checklist/index.html +1 -1
  233. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  234. package/apps/pwa/out/ops/release/index.html +1 -1
  235. package/apps/pwa/out/ops/release/index.txt +21 -21
  236. package/apps/pwa/out/ops/seats/index.html +1 -1
  237. package/apps/pwa/out/ops/seats/index.txt +21 -21
  238. package/apps/pwa/out/outputs/index.html +1 -1
  239. package/apps/pwa/out/outputs/index.txt +21 -21
  240. package/apps/pwa/out/reflection/index.html +1 -1
  241. package/apps/pwa/out/reflection/index.txt +22 -22
  242. package/apps/pwa/out/scheduler/index.html +1 -1
  243. package/apps/pwa/out/scheduler/index.txt +22 -22
  244. package/apps/pwa/out/sessions/index.html +1 -1
  245. package/apps/pwa/out/sessions/index.txt +21 -21
  246. package/apps/pwa/out/settings/devices/index.html +1 -1
  247. package/apps/pwa/out/settings/devices/index.txt +22 -22
  248. package/apps/pwa/out/settings/index.html +1 -1
  249. package/apps/pwa/out/settings/index.txt +22 -22
  250. package/apps/pwa/out/setup/done/index.html +1 -1
  251. package/apps/pwa/out/setup/done/index.txt +22 -22
  252. package/apps/pwa/out/setup/index.html +1 -1
  253. package/apps/pwa/out/setup/index.txt +22 -22
  254. package/apps/pwa/out/share/index.html +1 -1
  255. package/apps/pwa/out/share/index.txt +22 -22
  256. package/apps/pwa/out/showroom/index.html +1 -1
  257. package/apps/pwa/out/showroom/index.txt +21 -21
  258. package/apps/pwa/out/tasks/index.html +1 -1
  259. package/apps/pwa/out/tasks/index.txt +22 -22
  260. package/apps/pwa/out/term/index.html +1 -1
  261. package/apps/pwa/out/term/index.txt +22 -22
  262. package/apps/pwa/out/today/index.html +1 -1
  263. package/apps/pwa/out/today/index.txt +22 -22
  264. package/apps/pwa/out/trace/index.html +1 -1
  265. package/apps/pwa/out/trace/index.txt +22 -22
  266. package/apps/pwa/out/vault/index.html +1 -1
  267. package/apps/pwa/out/vault/index.txt +22 -22
  268. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  269. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  270. package/apps/pwa/out/workflows/index.html +1 -1
  271. package/apps/pwa/out/workflows/index.txt +22 -22
  272. package/apps/pwa/out/workspace/index.html +1 -1
  273. package/apps/pwa/out/workspace/index.txt +22 -22
  274. package/apps/pwa/out/worktrees/index.html +1 -1
  275. package/apps/pwa/out/worktrees/index.txt +22 -22
  276. package/graphs/release/release-loop.yaml +6 -2
  277. package/package.json +1 -1
  278. package/plugins/agent-team/agents/research.md +1 -0
  279. package/scripts/ci-typecheck-changed.ts +3 -2
  280. package/scripts/coord-channel-watch.sh +26 -6
  281. package/scripts/coord-role-pack.ts +143 -0
  282. package/scripts/lib/morning-report-options.ts +41 -0
  283. package/scripts/pr-land-extra-remote-gates.ts +49 -0
  284. package/scripts/release-loop/gate-batch-safe.ts +23 -0
  285. package/scripts/release-loop/gate-history.ts +422 -0
  286. package/scripts/release-loop/gate-node.ts +310 -46
  287. package/scripts/release-loop/gate-triage-node.ts +190 -0
  288. package/scripts/release-loop/spawn-lane.ts +68 -0
  289. package/scripts/release-loop/tui-node-checks.ts +23 -0
  290. package/scripts/release-loop/version-node.ts +62 -4
  291. package/scripts/test-deterministic.ts +41 -12
  292. package/scripts/usage-rollup.ts +11 -3
  293. package/src/acp/core-turn-bridge.ts +98 -22
  294. package/src/acp/elanous-extensions.ts +2 -0
  295. package/src/acp/server.ts +2 -0
  296. package/src/agent/ref-grounding.ts +18 -0
  297. package/src/agent-substrate/pr-reviewer.ts +29 -21
  298. package/src/budget/pty-usage-reemit.ts +7 -0
  299. package/src/budget/run-usage-rollup.ts +9 -0
  300. package/src/budget/usage-daily-store.ts +98 -0
  301. package/src/capture/tui-self-report.ts +22 -4
  302. package/src/chat/index.ts +31 -10
  303. package/src/chat/pickers/modal-runtime.ts +1 -0
  304. package/src/chat/pickers/modals.ts +3 -1
  305. package/src/chat/turn-typeahead.ts +123 -16
  306. package/src/cli/dashboard-name-flag.ts +48 -0
  307. package/src/cli/doctor-cli.ts +80 -0
  308. package/src/cli/log-event-names.ts +12 -0
  309. package/src/cli/msg-cli.ts +45 -2
  310. package/src/cli/pr-cli.ts +382 -105
  311. package/src/cli/pr-land-heavy-remote.ts +233 -0
  312. package/src/cli/pr-land-overlap-evidence.ts +104 -5
  313. package/src/cli/pty-takeover-cli.ts +125 -16
  314. package/src/cli/release-cli.ts +44 -2
  315. package/src/cli/remote-resolve.ts +2 -1
  316. package/src/cli/seat-cli.ts +26 -16
  317. package/src/cli/tasks-cli.ts +8 -2
  318. package/src/cli/usage-cli.ts +146 -12
  319. package/src/cli/usage-daily-cli.ts +84 -0
  320. package/src/context-bus/context-now.ts +82 -5
  321. package/src/core-turn/auth-rejected-notice.ts +41 -0
  322. package/src/core-turn/run-core-turn.ts +13 -2
  323. package/src/core-turn/run-goal-loop.ts +17 -1
  324. package/src/core-turn/short-question.ts +45 -12
  325. package/src/core-turn/types.ts +7 -0
  326. package/src/dashboard/acp-active-model.ts +40 -0
  327. package/src/dashboard/auto-compact-runtime.ts +2 -0
  328. package/src/dashboard/boot-banner.ts +80 -0
  329. package/src/dashboard/dashboard-status-lines.ts +11 -0
  330. package/src/dashboard/detail-viewer-runtime.ts +15 -2
  331. package/src/dashboard/event-loop-stall-monitor.ts +4 -0
  332. package/src/dashboard/goal-loop-thinking.ts +16 -0
  333. package/src/dashboard/hitl-boot.ts +9 -4
  334. package/src/dashboard/index.ts +228 -387
  335. package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
  336. package/src/dashboard/input/chat-main-log-actions.ts +4 -0
  337. package/src/dashboard/input/chat-main-log-command.ts +12 -1
  338. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +172 -3
  339. package/src/dashboard/input/chat-main-session.ts +6 -2
  340. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  341. package/src/dashboard/input/chat-main-turn.ts +2 -1
  342. package/src/dashboard/input/compact-prepass-recovery.ts +97 -0
  343. package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
  344. package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
  345. package/src/dashboard/input/external-input-host.ts +45 -0
  346. package/src/dashboard/input/log-fold-binding.ts +18 -0
  347. package/src/dashboard/input/mouse-wiring.ts +17 -4
  348. package/src/dashboard/input/turn-steer-bridge.ts +94 -0
  349. package/src/dashboard/log-click-runtime.ts +5 -3
  350. package/src/dashboard/running-build-status.ts +74 -0
  351. package/src/dashboard/seat-boot-preamble.ts +113 -0
  352. package/src/dashboard/seat-local-instructions.ts +305 -0
  353. package/src/dashboard/slash-runtime/dashboard-handlers.ts +100 -28
  354. package/src/dashboard/slash-runtime/model-choices.ts +35 -0
  355. package/src/dashboard/term-slash-runtime.ts +15 -0
  356. package/src/dashboard/turn-preamble.ts +30 -2
  357. package/src/dashboard/turn-session-layers.ts +176 -0
  358. package/src/dashboard/turn-stream-formatter.ts +14 -6
  359. package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
  360. package/src/domains/release-tool.ts +8 -9
  361. package/src/domains/surface-events.ts +4 -1
  362. package/src/domains/watch-default-scheduler.ts +8 -9
  363. package/src/fold-stack.ts +24 -1
  364. package/src/git-fs/dirty.ts +32 -4
  365. package/src/git-fs/index.ts +43 -1
  366. package/src/graph-runner/runner.ts +1 -0
  367. package/src/harness/harness-gc.ts +32 -5
  368. package/src/index.ts +14 -1
  369. package/src/input/external-input-queue.ts +219 -0
  370. package/src/interactive-terminal-modal.ts +13 -0
  371. package/src/llm/route-decision.ts +25 -0
  372. package/src/llm-stream-retry-display.ts +59 -0
  373. package/src/llm.ts +253 -55
  374. package/src/log-entry.ts +3 -3
  375. package/src/log-pane/search.ts +29 -4
  376. package/src/loops/agent-reply.ts +256 -0
  377. package/src/loops/budget.ts +37 -7
  378. package/src/loops/loop-cli.ts +3 -2
  379. package/src/loops/msg-address.ts +57 -0
  380. package/src/loops/msg-wake.ts +282 -0
  381. package/src/loops/orchestrator/inbox.ts +60 -3
  382. package/src/loops/orchestrator/tick.ts +24 -4
  383. package/src/loops/registry.ts +42 -4
  384. package/src/memory.ts +20 -5
  385. package/src/native-tool-catalog.ts +125 -0
  386. package/src/nexus/api/http-server.ts +5 -0
  387. package/src/nexus/api/ops-api.ts +2 -0
  388. package/src/nexus/api/project-autopsy.ts +127 -0
  389. package/src/nexus/api/terminals.ts +3 -0
  390. package/src/nexus/api/workflow-approvals.ts +2 -0
  391. package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
  392. package/src/oauth/codex-account-store.ts +15 -3
  393. package/src/oauth/codex-billing-route.ts +31 -0
  394. package/src/ops/overview-collect.ts +19 -2
  395. package/src/panes/log-pane.ts +67 -8
  396. package/src/persona/presets.ts +44 -0
  397. package/src/plugins/maker/wizard-generate.ts +6 -4
  398. package/src/preview/terminal.ts +14 -1
  399. package/src/prompt-cache/types.ts +2 -0
  400. package/src/prompt-enhance/enhance.ts +24 -8
  401. package/src/prompt-library/universal-preamble.ts +273 -56
  402. package/src/pty-shell/pty-control-ipc.ts +4 -1
  403. package/src/pty-shell/pty-manifest.ts +77 -5
  404. package/src/pty-shell/registry.ts +19 -2
  405. package/src/pty-shell/tui-run-state.ts +253 -0
  406. package/src/release-loop/light-rc.ts +28 -3
  407. package/src/release-loop/rehearsal.ts +1 -1
  408. package/src/render.ts +5 -1
  409. package/src/seat-loop/seat-report.ts +42 -2
  410. package/src/self-dev/run-supervisor.ts +71 -5
  411. package/src/self-dev/shard-aggregate.ts +2 -0
  412. package/src/self-dev/shard-run.ts +23 -2
  413. package/src/self-health/signatures.ts +132 -0
  414. package/src/self-implement/doctor-visit.ts +118 -0
  415. package/src/self-implement/gate-cli.ts +11 -2
  416. package/src/self-implement/goal-author-decompose.ts +80 -16
  417. package/src/self-implement/goal-author.ts +114 -72
  418. package/src/self-implement/goal-authoring-grounding.ts +1 -1
  419. package/src/self-implement/goal-file-name.ts +65 -0
  420. package/src/self-implement/ground-goal.ts +2 -1
  421. package/src/self-implement/host-regate.ts +14 -0
  422. package/src/self-implement/review-mustfix-class.ts +115 -0
  423. package/src/self-implement/run-ledger.ts +111 -7
  424. package/src/self-implement/running-runs.ts +10 -6
  425. package/src/self-implement/self-implement-runtime.ts +32 -0
  426. package/src/session/pending-input.ts +62 -11
  427. package/src/session-runtime/index.ts +7 -1
  428. package/src/skills/tools/ops-ledger.ts +707 -0
  429. package/src/skills/tools/persistent-grounding.ts +47 -7
  430. package/src/skills/tools/shell.ts +117 -1
  431. package/src/status/bar.ts +32 -2
  432. package/src/status/status-provider-info.ts +58 -0
  433. package/src/task-agent/rejudge-on-head.ts +4 -1
  434. package/src/task-agent/remote-rejudge-bind.ts +34 -5
  435. package/src/task-agent/repair-cycle.ts +13 -0
  436. package/src/task-orchestrator/surfaces/kubectl-transient-retry.ts +51 -0
  437. package/src/task-orchestrator/surfaces/pod-command-job.ts +63 -7
  438. package/src/task-orchestrator/surfaces/pod-install-slots.ts +6 -11
  439. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +76 -0
  440. package/src/task-orchestrator/surfaces/self-implement-pod.ts +107 -33
  441. package/src/terminal/session-registry.ts +6 -0
  442. package/src/thinking-line.ts +12 -3
  443. package/src/tool-runtime/index.ts +4 -0
  444. package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
  445. package/src/tool-runtime/ref-consult-runtime.ts +17 -2
  446. package/src/tool-runtime/run-shell-runtime.ts +4 -1
  447. package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
  448. package/src/tui.ts +5 -0
  449. package/src/user-config.ts +54 -6
  450. package/src/ux-sim/fake-llm.ts +29 -0
  451. package/src/ux-sim/in-process-cli.ts +175 -0
  452. package/src/version/packed-revision.json +1 -1
  453. package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
  458. package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +0 -148
  460. package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
  467. package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +0 -24
  472. package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
  475. package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +0 -34
  477. package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
  482. package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
  487. package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
  492. package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
  494. package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
  496. package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
  506. package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
  510. package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
  512. package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
  514. package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
  522. package/apps/pwa/out/_next/static/chunks/7752.5cbdd0b433c54af9.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
  531. package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
  533. package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
  534. package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
  537. package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
  539. package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
  540. package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
  541. package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +0 -90
  545. package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +0 -79
  549. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/live/page-ced0bcfc6542b3fc.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-cb249e81ed339318.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/e117f801.e92bf10242653497.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +0 -122
  599. package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
  605. package/src/dashboard/bench-slash-runtime.ts +0 -40
  606. package/src/dashboard/input/search-modal-router.ts +0 -9
  607. package/src/dashboard/modals/pane-key-router.ts +0 -27
  608. package/src/dashboard/view-slash-runtime.ts +0 -48
  609. /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_ssgManifest.js +0 -0
@@ -0,0 +1,282 @@
1
+ // ── 우편 깨움 — 글을 저장한 «뒤» 받는 몸을 한 번 두드린다 ──
2
+ //
3
+ // 주소에 «답할 몸»(replyBody)이 있어도 «깨울 길»이 없으면 죽은 주소다(10-14 grok OP 16분 정지).
4
+ // 종류(`MessageWake`)마다 하는 일:
5
+ // sse — 아무것도 안 한다(구독자가 이미 듣는다)
6
+ // cron — 다음 틱에 읽는다 · `wake-deferred` 로그만
7
+ // pty-inject — elanous TUI(pty 별명 = 자리 소문자)가 턴 idle 일 때만 한 줄 주입
8
+ // herdr — 자리 폴더 `herdr.pane` 의 pane 이 agent_status=idle 일 때만 한 줄 주입
9
+ // none — stderr 경고 한 줄 · 해석 실패는 «모름»으로 남긴다(«없다»로 위장 금지)
10
+ // ⛔ 우편은 입력칸에 넣지 않는다(대표 10-15 01:20) — 기본은 입력칸 주입 0. 10-15 01:10 사고: 대표 가 치던 문장에
11
+ // 깨움 한 줄 ⊕ Enter 가 섞여 제출됐다(«에이전트 idle ≠ 사람이 안 친다»). 자리 폴더에서 푼 대상(pty 별명·
12
+ // pty.ref·herdr.pane)은 `<seat-state>/<자리>/wake-inject` 일반 파일이 있을 때만 주입하고, 없으면
13
+ // `msg.wake skipped{reason}` 만 남긴다.
14
+ // ⚠️ wake-inject 는 «사람이 치지 않는 pane»(무인 에이전트 전용)에만 둔다 — 사람이 치는 pane 에는 켜지 말 것.
15
+ // ⛔ 깨움은 post 의 성패를 바꾸지 않는다 — 실패·시간 초과는 결과 값으로만 돌아온다.
16
+ // ⛔ 시험 우주에서는 실제 pty/herdr 호출 0 — `ELANOUS_MSG_WAKE_LIVE=1` 로만 연다(격리 실물 시험용).
17
+
18
+ import { spawn } from 'node:child_process';
19
+ import { Database } from 'bun:sqlite';
20
+ import { randomUUID } from 'node:crypto';
21
+ import { existsSync, lstatSync, mkdirSync, readFileSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { dirname, join } from 'node:path';
24
+
25
+ import { debug } from '../debug/log.js';
26
+ import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
27
+ import { listPtyManifestRows } from '../pty-shell/pty-manifest.js';
28
+ import { messageRouteFor, type MessageWake } from './msg-address.js';
29
+
30
+ export const WAKE_DEBOUNCE_MS = 5 * 60_000;
31
+ export const WAKE_TIMEOUT_MS = 3_000;
32
+ /** Seat-folder file that opts a human pane in to wake injection (presence is the switch). */
33
+ const WAKE_OPT_IN_FILE = 'wake-inject';
34
+
35
+ export interface WakeResolution {
36
+ wake: MessageWake;
37
+ /** pty id (pty-inject) or herdr pane id (herdr). */
38
+ target?: string;
39
+ /** Where the answer came from — `unresolved` means «모름», not a measured absence. */
40
+ source: 'loop-table' | 'pty-name' | 'pty.ref' | 'herdr.pane' | 'unresolved';
41
+ reason?: string;
42
+ /** For a seat-folder target: the seat opted in to injection (`<seat>/wake-inject` exists). Absent = not a seat target. */
43
+ optIn?: boolean;
44
+ }
45
+
46
+ export type WakeResult = 'none-sse' | 'wake-deferred' | 'injected' | 'busy' | 'debounced' | 'skipped' | 'skipped-reply'
47
+ | 'skipped-self' | 'skipped-test-universe' | 'no-wake' | 'failed' | 'timeout';
48
+
49
+ export interface WakeOutcome extends WakeResolution { address: string; msgId: number; result: WakeResult }
50
+
51
+ export interface WakeDeps {
52
+ /** Seat folders (`<root>/<SEAT>/pty.ref` · `herdr.pane`). Prod: ~/elanous-hq/seat-state · test universe: <root>/seat-state. */
53
+ seatStateRoot?: string;
54
+ /** Debounce claims live here (`<stateRoot>/msg/wake-claims.db`). */
55
+ stateRoot?: string;
56
+ now?: () => number;
57
+ /** Real pty/herdr calls are allowed (default: prod universe or ELANOUS_MSG_WAKE_LIVE=1). */
58
+ live?: boolean;
59
+ timeoutMs?: number;
60
+ listPtys?: () => Array<{ id: string; nickname?: string; alive: boolean; turnState?: 'busy' | 'idle' }>;
61
+ /** Reads one seat-folder file (`pty.ref` · `herdr.pane`); null when absent. */
62
+ readPane?: (path: string) => string | null;
63
+ /** Does this seat-folder opt-in file exist (`<seat>/wake-inject`)? */
64
+ hasOptIn?: (path: string) => boolean;
65
+ /** Loads the pty writer (the CLI module is heavy, so it is imported only when a pty wake is due). */
66
+ ptyInjector?: () => Promise<(ptyId: string, line: string) => Promise<void>>;
67
+ herdrStatus?: (paneId: string, signal: AbortSignal) => Promise<string>;
68
+ herdrInject?: (paneId: string, line: string, signal: AbortSignal) => Promise<void>;
69
+ warn?: (line: string) => void;
70
+ }
71
+
72
+ function isLive(deps: WakeDeps): boolean {
73
+ if (deps.live !== undefined) return deps.live;
74
+ return effectiveInstanceRoot() === prodInstanceRoot() || process.env.ELANOUS_MSG_WAKE_LIVE === '1';
75
+ }
76
+
77
+ function seatStateRoot(deps: WakeDeps): string {
78
+ if (deps.seatStateRoot) return deps.seatStateRoot;
79
+ const root = effectiveInstanceRoot();
80
+ return root === prodInstanceRoot() ? join(homedir(), 'elanous-hq', 'seat-state') : join(root, 'seat-state');
81
+ }
82
+
83
+ /** The opt-in must be a regular file — a directory, a symlink or anything else at that name does not open injection. */
84
+ function isRegularFile(path: string): boolean {
85
+ // lstat — 링크는 따라가지 않는다(자리 자체의 일반 파일만 opt-in).
86
+ try { return lstatSync(path).isFile(); } catch { return false; }
87
+ }
88
+
89
+ /** The seat's own opt-in, read independently of whatever target the seat folder points at now. */
90
+ function seatOptedIn(address: string, deps: WakeDeps): boolean {
91
+ return (deps.hasOptIn ?? isRegularFile)(join(seatStateRoot(deps), address.trim().toUpperCase(), WAKE_OPT_IN_FILE));
92
+ }
93
+
94
+ function readPaneFile(path: string): string | null {
95
+ try { return existsSync(path) ? readFileSync(path, 'utf8').trim() || null : null; }
96
+ catch { return null; }
97
+ }
98
+
99
+ /** How a post to `address` would wake its reader — table first, then a live pty named after the seat, then herdr. */
100
+ export function resolveWake(address: string, deps: WakeDeps = {}): WakeResolution {
101
+ const name = address.trim().toUpperCase();
102
+ if (name === 'ALL') return { wake: 'none', source: 'unresolved', reason: 'topic' };
103
+ const route = messageRouteFor(name);
104
+ if (route?.wake) return { wake: route.wake, source: 'loop-table' };
105
+ // 호스트 해석은 표에 선언된 자리 줄(wakeFrom: 'host')만 — 모르는 주소는 같은 이름의 pty 가 있어도 깨우지 않는다.
106
+ if (route?.wakeFrom !== 'host') return { wake: 'none', source: 'unresolved', reason: 'undeclared-address' };
107
+ // ⭐ 별명은 «정확히» 같은 것만 — pty ref 해석의 부분 일치(op ⊂ opt)로 남의 TUI 에 넣지 않는다.
108
+ const lower = name.toLowerCase();
109
+ let ptys: ReturnType<NonNullable<WakeDeps['listPtys']>> = [];
110
+ try { ptys = (deps.listPtys ?? listPtyManifestRows)(); } catch { ptys = []; }
111
+ const named = ptys.filter(row => row.alive && (row.nickname ?? '').toLowerCase() === lower);
112
+ const optIn = seatOptedIn(name, deps);
113
+ if (named.length === 1) return { wake: 'pty-inject', target: named[0]!.id, source: 'pty-name', optIn };
114
+ // seat-inbox.sh 와 같은 자리 폴더 파일: pty.ref(살아 있는 행의 id·별명과 정확히 같을 때만) → herdr.pane.
115
+ const readSeatFile = deps.readPane ?? readPaneFile;
116
+ const ref = readSeatFile(join(seatStateRoot(deps), name, 'pty.ref'))?.toLowerCase();
117
+ const byRef = ref ? ptys.filter(row => row.alive && (row.id.toLowerCase() === ref || (row.nickname ?? '').toLowerCase() === ref)) : [];
118
+ if (byRef.length === 1) return { wake: 'pty-inject', target: byRef[0]!.id, source: 'pty.ref', optIn };
119
+ const pane = readSeatFile(join(seatStateRoot(deps), name, 'herdr.pane'));
120
+ if (pane) return { wake: 'herdr', target: pane, source: 'herdr.pane', optIn };
121
+ return { wake: 'none', source: 'unresolved', reason: named.length > 1 ? `pty-name-ambiguous:${named.length}` : 'no-pty-name-no-herdr-pane' };
122
+ }
123
+
124
+ function claimDbPath(deps: WakeDeps): string {
125
+ return join(deps.stateRoot ?? effectiveInstanceRoot(), 'msg', 'wake-claims.db');
126
+ }
127
+
128
+ interface WakeClaim { db: string; address: string; token: string }
129
+
130
+ /**
131
+ * Atomically claim the 5-minute wake window for one address. One SQLite upsert decides it under the
132
+ * write lock — the row is replaced only when the held claim is older than the window — so two
133
+ * concurrent `msg post` processes cannot both win, including when both saw an expired claim.
134
+ */
135
+ export function claimWake(db: string, address: string, now: number): WakeClaim | null {
136
+ mkdirSync(dirname(db), { recursive: true });
137
+ const token = `${now} ${process.pid} ${randomUUID()}`;
138
+ const conn = new Database(db);
139
+ try {
140
+ conn.exec('PRAGMA busy_timeout = 2000');
141
+ conn.exec('CREATE TABLE IF NOT EXISTS wake_claims (address TEXT PRIMARY KEY, at INTEGER NOT NULL, token TEXT NOT NULL)');
142
+ const changed = conn.query(`INSERT INTO wake_claims (address, at, token) VALUES (?1, ?2, ?3)
143
+ ON CONFLICT(address) DO UPDATE SET at = excluded.at, token = excluded.token WHERE wake_claims.at <= ?2 - ?4`)
144
+ .run(address, now, token, WAKE_DEBOUNCE_MS).changes;
145
+ return changed === 1 ? { db, address, token } : null;
146
+ } finally { conn.close(); }
147
+ }
148
+
149
+ /** Give the window back when nothing was injected (busy · timeout · failure) — only our own claim. */
150
+ function releaseClaim(claim: WakeClaim): void {
151
+ try {
152
+ const conn = new Database(claim.db);
153
+ try { conn.exec('PRAGMA busy_timeout = 2000'); conn.query('DELETE FROM wake_claims WHERE address = ?1 AND token = ?2').run(claim.address, claim.token); }
154
+ finally { conn.close(); }
155
+ } catch { /* a stale claim only delays the next wake by one window */ }
156
+ }
157
+
158
+ function run(cmd: string, args: string[], timeoutMs: number, signal: AbortSignal): Promise<string> {
159
+ return new Promise((resolve, reject) => {
160
+ if (signal.aborted) { reject(new Error(`${cmd} aborted`)); return; }
161
+ const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], signal });
162
+ let out = '';
163
+ const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error(`${cmd} timeout`)); }, timeoutMs);
164
+ child.stdout.on('data', chunk => { out += String(chunk); });
165
+ child.on('error', error => { clearTimeout(timer); reject(error); });
166
+ child.on('close', code => { clearTimeout(timer); code === 0 ? resolve(out) : reject(new Error(`${cmd} exit ${code}`)); });
167
+ });
168
+ }
169
+
170
+ async function defaultHerdrStatus(paneId: string, signal: AbortSignal): Promise<string> {
171
+ const parsed = JSON.parse(await run('herdr', ['pane', 'get', paneId], WAKE_TIMEOUT_MS, signal)) as { result?: { pane?: { agent_status?: unknown } } };
172
+ const status = parsed.result?.pane?.agent_status;
173
+ return typeof status === 'string' ? status : 'unknown';
174
+ }
175
+
176
+ async function defaultHerdrInject(paneId: string, line: string, signal: AbortSignal): Promise<void> {
177
+ // `pane run` = send-text ⊕ Enter 한 번에.
178
+ await run('herdr', ['pane', 'run', paneId, line], WAKE_TIMEOUT_MS, signal);
179
+ }
180
+
181
+ async function defaultPtyInjector(): Promise<(ptyId: string, line: string) => Promise<void>> {
182
+ const { runPtyText } = await import('../cli/pty-takeover-cli.js');
183
+ return async (ptyId, line) => {
184
+ const result = await runPtyText(ptyId, line, true);
185
+ if (result.exitCode !== 0) throw new Error(result.message);
186
+ };
187
+ }
188
+
189
+ export function wakeLine(from: string, address: string, msgId: number): string {
190
+ return `[우편 깨움] ${from} → ${address} #${msgId} — eln msg list --to ${address} 로 읽고 처리`;
191
+ }
192
+
193
+ export const NO_WAKE_NOTICE = '이 주소는 깨울 길이 없다 — 받는 몸이 스스로 읽을 때까지 쌓인다';
194
+
195
+ /**
196
+ * Wake the reader of a just-saved message. Never throws; the caller's post outcome is already final.
197
+ * `message.from`/`kind` decide the skips (a reply or a self-addressed note never wakes anyone).
198
+ */
199
+ export async function wakeRecipient(address: string, msgId: number, message: { from: string; kind?: string }, deps: WakeDeps = {}): Promise<WakeOutcome> {
200
+ const timeoutMs = deps.timeoutMs ?? WAKE_TIMEOUT_MS;
201
+ let timer: ReturnType<typeof setTimeout> | undefined;
202
+ let resolution: WakeResolution = { wake: 'none', source: 'unresolved', reason: 'not-resolved' };
203
+ const controller = new AbortController();
204
+ // 마감은 «진입» 시각 기준 — 동기 작업(claim 잠금 대기 등)이 늦어 타이머가 못 울려도 넘기면 주입하지 않는다.
205
+ const deadline = Date.now() + timeoutMs;
206
+ const expired = () => controller.signal.aborted || Date.now() >= deadline;
207
+ let claim: WakeClaim | null = null;
208
+ let injecting = false;
209
+ const attempt = (async (): Promise<WakeOutcome> => {
210
+ const done = (result: WakeResult, reason?: string): WakeOutcome =>
211
+ ({ ...resolution, ...(reason ? { reason } : {}), address, msgId, result });
212
+ if (message.kind === 'reply') return done('skipped-reply', 'kind=reply');
213
+ if (message.from.toUpperCase() === address.toUpperCase()) return done('skipped-self', 'from=to');
214
+ resolution = resolveWake(address, deps);
215
+ if (resolution.wake === 'sse') return done('none-sse');
216
+ if (resolution.wake === 'cron') return done('wake-deferred');
217
+ if (resolution.wake === 'none') return done('no-wake');
218
+ // 사람이 앉는 pane 은 명시 opt-in 이 없으면 주입 0 — 에이전트가 idle 이어도 사람이 치는 중일 수 있다.
219
+ if (resolution.optIn === false) return done('skipped', 'human-pane-no-opt-in');
220
+ if (!isLive(deps)) return done('skipped-test-universe');
221
+ claim = claimWake(claimDbPath(deps), address, (deps.now ?? Date.now)());
222
+ if (!claim) return done('debounced');
223
+ try {
224
+ const line = wakeLine(message.from, address, msgId);
225
+ if (resolution.wake === 'pty-inject') {
226
+ // 모듈을 «먼저» 불러오고, 그 뒤에 턴을 읽는다 — 로드 사이 busy 로 바뀐 TUI 에 넣지 않는다.
227
+ const inject = await (deps.ptyInjector ?? defaultPtyInjector)();
228
+ // turnState 는 TUI 가 스스로 적은 값(#27485) — 살아 있고 idle 이 «기록»돼 있을 때만 넣는다(모름 = 넣지 않음).
229
+ // 로드 사이 별명·pty.ref 가 다른 행으로 옮겨 갔으면 넣지 않는다 — 주소→대상을 다시 푼다.
230
+ const again = resolveWake(address, deps);
231
+ // opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
232
+ if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
233
+ if (again.wake !== 'pty-inject' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
234
+ const row = (deps.listPtys ?? listPtyManifestRows)().find(item => item.id === resolution.target);
235
+ if (!row?.alive || row.turnState !== 'idle') return done('busy', `turn=${row?.alive === false ? 'dead' : row?.turnState ?? 'unknown'}`);
236
+ // ⛔ 마감이 지났으면 새 주입을 시작하지 않는다.
237
+ if (expired()) return done('timeout');
238
+ injecting = true;
239
+ await inject(resolution.target!, line);
240
+ } else {
241
+ const status = await (deps.herdrStatus ?? defaultHerdrStatus)(resolution.target!, controller.signal);
242
+ if (status !== 'idle') return done('busy', `agent_status=${status}`);
243
+ // 조회 사이 자리의 pane 이 바뀌었으면 옛 pane 에 넣지 않는다 — 주소→대상을 다시 푼다.
244
+ const again = resolveWake(address, deps);
245
+ // opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
246
+ if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
247
+ if (again.wake !== 'herdr' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
248
+ // ⛔ 마감은 «주입 바로 앞»에서 — 재해석이 늦어 넘겼어도 새 주입 0.
249
+ if (expired()) return done('timeout');
250
+ injecting = true;
251
+ await (deps.herdrInject ?? defaultHerdrInject)(resolution.target!, line, controller.signal);
252
+ }
253
+ return done('injected');
254
+ } catch (error) {
255
+ // 주입이 «시작»됐다 실패하면 들어갔는지 모른다 — 창을 돌려줘 다음 글이 다시 깨우게 한다.
256
+ injecting = false;
257
+ throw error;
258
+ } finally { if (!injecting && claim) releaseClaim(claim); }
259
+ })();
260
+ let outcome: WakeOutcome;
261
+ try {
262
+ outcome = await Promise.race([attempt, new Promise<WakeOutcome>(resolve => {
263
+ timer = setTimeout(() => {
264
+ controller.abort();
265
+ // 시간 초과면 창을 돌려준다 — 주입 전이면 들어간 것이 없고, 주입 중 멈췄으면 들어갔는지 «모른다».
266
+ // 모를 때는 다음 글이 다시 두드리게 둔다(내용 없는 한 줄의 중복은 무해, 깨움 누락은 16분 정지).
267
+ if (claim) releaseClaim(claim);
268
+ resolve({ ...resolution, address, msgId, result: 'timeout' });
269
+ }, timeoutMs);
270
+ })]);
271
+ } catch (error) {
272
+ outcome = { ...resolution, address, msgId, result: 'failed', reason: error instanceof Error ? error.message : String(error) };
273
+ } finally { clearTimeout(timer); }
274
+ attempt.catch(() => { /* a late failure after timeout is already reported as timeout */ });
275
+ try {
276
+ if (outcome.result === 'no-wake') (deps.warn ?? (line => console.error(line)))(
277
+ outcome.source === 'unresolved' ? `${NO_WAKE_NOTICE} (wake=none · 모름: ${outcome.reason})` : `${NO_WAKE_NOTICE} (wake=none)`);
278
+ debug.log('msg.wake', outcome.result === 'skipped' ? 'skipped' : outcome.wake, { address, msgId, wake: outcome.wake, result: outcome.result, reason: outcome.reason ?? outcome.source,
279
+ ...(outcome.target ? { target: outcome.target } : {}) });
280
+ } catch { /* reporting never turns a wake outcome into a throw */ }
281
+ return outcome;
282
+ }
@@ -1,10 +1,26 @@
1
1
  import { openMsgStore, type Message, type MsgStore } from '../../msg/msg-store.js';
2
2
  import { classifySeatTrafficProposal } from '../../seat-loop/traffic-signal.js';
3
3
  import { debug } from '../../debug/log.js';
4
+ import { LOOP_MESSAGE_ROUTES } from '../msg-address.js';
5
+ import { replyWithAgent, type AgentReplyInput } from '../agent-reply.js';
6
+ import type { RoleLlmSpec } from '../../user-config.js';
7
+ import type { LLMProvider } from '../../llm.js';
4
8
 
5
- const RECIPIENT = 'COORDINATOR';
9
+ const RECIPIENT = LOOP_MESSAGE_ROUTES.orchestrator.msgAddress;
6
10
 
7
11
  export interface CoordinatorInboxResult { replied: number; acknowledged: number }
12
+ export interface CoordinatorAgentInboxOptions {
13
+ role: RoleLlmSpec;
14
+ pack: string;
15
+ store?: MsgStore;
16
+ path?: string;
17
+ root?: string;
18
+ limit?: number;
19
+ runAgent?: AgentReplyInput['runAgent'];
20
+ provider?: LLMProvider;
21
+ /** Only the ordered tick scan may advance the durable inbox cursor. */
22
+ acknowledge?: boolean;
23
+ }
8
24
 
9
25
  function trafficProposal(request: Message): 'hold' | 'UNHOLD' | null {
10
26
  // A question mentioning a signal is not evidence that the signal occurred.
@@ -26,10 +42,10 @@ export function coordinatorReply(request: Message): string {
26
42
  function writeCoordinatorReply(store: MsgStore, request: Message): { id: number; posted: boolean } {
27
43
  const marker = `re #${request.id}`;
28
44
  const linked = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
29
- AND reply_to = ? ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
45
+ AND reply_to = ? AND kind = 'reply' ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
30
46
  if (linked) return { id: linked.id, posted: false };
31
47
  const legacy = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
32
- AND reply_to IS NULL AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
48
+ AND reply_to IS NULL AND kind = 'reply' AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
33
49
  .get(RECIPIENT, request.from, marker, marker.length + 1, `${marker}\n`) as { id: number } | null;
34
50
  if (legacy) return { id: legacy.id, posted: false };
35
51
  const reply = store.post({ from: RECIPIENT, to: request.from,
@@ -71,3 +87,44 @@ export function runCoordinatorInbox(inputStore?: MsgStore, limit = 100, path?: s
71
87
  return { replied, acknowledged };
72
88
  } finally { if (ownStore) store.close(); }
73
89
  }
90
+
91
+ /** One SSE delivery or tick scan uses the same durable handler. At-least-once wake is safe. */
92
+ export async function handleCoordinatorAgentMessage(
93
+ request: Message, input: CoordinatorAgentInboxOptions,
94
+ ): Promise<CoordinatorInboxResult> {
95
+ const store = input.store ?? openMsgStore(input.path);
96
+ const ownStore = input.store === undefined;
97
+ const acknowledge = input.acknowledge === true;
98
+ try {
99
+ if (request.to !== RECIPIENT || request.from === RECIPIENT ||
100
+ (request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
101
+ if (acknowledge) store.ack(RECIPIENT, request.id);
102
+ return { replied: 0, acknowledged: acknowledge ? 1 : 0 };
103
+ }
104
+ // With explicit role selection, every request goes through the agent body.
105
+ const result = await replyWithAgent({ address: RECIPIENT, request, role: input.role,
106
+ pack: input.pack, store, observationRoot: input.root,
107
+ ...(input.provider ? { provider: input.provider } : {}),
108
+ ...(input.runAgent ? { runAgent: input.runAgent } : {}) });
109
+ if (result.replyId === null) throw new Error(`coordinator agent returned no reply for #${request.id}`);
110
+ if (acknowledge) store.ack(RECIPIENT, request.id);
111
+ return { replied: result.posted ? 1 : 0, acknowledged: acknowledge ? 1 : 0 };
112
+ } finally { if (ownStore) store.close(); }
113
+ }
114
+
115
+ /** Configured body path; callers must check the explicit roleLlm opt-in before invoking it. */
116
+ export async function runCoordinatorAgentInbox(input: CoordinatorAgentInboxOptions): Promise<CoordinatorInboxResult> {
117
+ const store = input.store ?? openMsgStore(input.path);
118
+ const ownStore = input.store === undefined;
119
+ const result = { replied: 0, acknowledged: 0 };
120
+ try {
121
+ const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), input.limit ?? 100);
122
+ for (const request of requests) {
123
+ const one = await handleCoordinatorAgentMessage(request, { ...input, store, acknowledge: true });
124
+ result.replied += one.replied;
125
+ result.acknowledged += one.acknowledged;
126
+ }
127
+ debug.log('loop.coordinator-inbox', 'agent-tick', result);
128
+ return result;
129
+ } finally { if (ownStore) store.close(); }
130
+ }
@@ -5,7 +5,7 @@ import { CardStore, taskCardsDir, type TaskCard } from '../../task-cards/card-st
5
5
  import { Database } from 'bun:sqlite';
6
6
  import { type ChecklistItem } from '../../release-loop/checklist.js';
7
7
  import { effectiveInstanceRoot } from '../../instance/resolve.js';
8
- import { getUserConfig, type OrchestratorLoopConfig } from '../../user-config.js';
8
+ import { getUserConfig, resolveConfiguredAgentRoleLlm, type OrchestratorLoopConfig } from '../../user-config.js';
9
9
  import { rubricPriority } from '../../release-loop/rubric.js';
10
10
  import { debug } from '../../debug/log.js';
11
11
  import { emitLoopHeartbeat } from '../neighbor-runtime.js';
@@ -15,14 +15,23 @@ import { addHarnessQueue, harnessQueueOutcome, setQueuedPoolHint } from '../../h
15
15
  import { placeOnGrid, type GridHost } from './grid-place.js';
16
16
  import { checkPodPool, parsePodPool, resolvePodPoolSpec } from '../../task-orchestrator/surfaces/pod-pool.js';
17
17
  import { leaseKubectl } from '../../task-orchestrator/surfaces/pod-lease.js';
18
+ import type { TrafficSeatRow } from './traffic.js';
18
19
  import { readTaskAgentState, TASK_SEATS, type HandTaskOptions, type TaskCard as TaskAgentCard, type HandTaskResult, type TaskLauncher, type TaskSeat } from '../../task-agent/task-hand.js';
19
- import { runCoordinatorInbox } from './inbox.js';
20
+ import { runCoordinatorAgentInbox, runCoordinatorInbox, type CoordinatorInboxResult } from './inbox.js';
21
+ import { loadAgentRolePack, type AgentReplyInput } from '../agent-reply.js';
22
+ import type { LLMProvider } from '../../llm.js';
20
23
 
21
24
  export type Window = '08' | '12' | '18';
22
25
  export type Node = 'intake' | 'split' | 'place' | 'delegate' | 'launch' | 'reconcile' | 'report';
23
26
  export type Mode = 'off' | 'shadow' | 'live';
24
27
  const SEAT_LOOP_IDS: Readonly<Record<string, string>> = { OP: 'op-seat', MK: 'cmo-seat', TC: 'tc-seat', UX: 'ux-seat' };
25
28
  export interface Cell { id: string; title: string; kind?: string; seat?: string; host?: string; gridHost?: boolean; version?: string; cardId: string; origin: 'candidate' | 'flow1a'; priority?: 'P0' | 'P1' | 'P2' | 'P3' | 'P4'; predecessors?: string[] }
29
+ /** Pure launch decision over observed traffic; dispatch-c will wire it into the periodic launch path. */
30
+ export function isLaunchEligible(row: Pick<TrafficSeatRow, 'nextCell' | 'running' | 'launchCap'>,
31
+ skipReason?: string): boolean {
32
+ return row.nextCell !== null && row.running < row.launchCap &&
33
+ skipReason !== 'degraded-skip' && skipReason !== 'cap-deferred';
34
+ }
26
35
  export interface TickState {
27
36
  runId: string; window: Window; mode: Mode; day: string;
28
37
  cards: TaskCard[]; skippedCards: Array<{ id: string; reason: string }>; cells: Cell[]; placed: number; unplaced?: number; delegated: number; wouldDelegate: number; rebalanced?: number; rebalanceBlocked?: Array<{ id: string; reason: string }>;
@@ -73,7 +82,10 @@ export interface TickDeps {
73
82
  handTask?: (opts: HandTaskOptions) => Promise<HandTaskResult>;
74
83
  taskLauncher?: TaskLauncher;
75
84
  /** Coordinator inbox seam; the real intake reads and replies on the durable message bus. */
76
- coordinatorInbox?: () => { replied: number; acknowledged: number };
85
+ coordinatorInbox?: () => CoordinatorInboxResult | Promise<CoordinatorInboxResult>;
86
+ /** Production still uses the restricted turn; tests can supply a deterministic turn. */
87
+ coordinatorAgentRun?: AgentReplyInput['runAgent'];
88
+ coordinatorAgentProvider?: LLMProvider;
77
89
  }
78
90
 
79
91
  /** ORCH-TA-HAND ledger — one row per handed `orch:<card>:<cell>` key so a cell is handed once across ticks and processes. */
@@ -475,7 +487,15 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
475
487
  // A graph node may be replayed with the same runId, and 12/18 skip intake.
476
488
  // Drain the bus on every tick command; the message transaction prevents duplicate answers.
477
489
  if (mode !== 'off') {
478
- const inbox = (deps.coordinatorInbox ?? (() => runCoordinatorInbox(undefined, 100, join(root, 'msg', 'messages.db'))))();
490
+ const inboxPath = join(root, 'msg', 'messages.db');
491
+ const inbox = await (deps.coordinatorInbox ?? (() => {
492
+ const role = resolveConfiguredAgentRoleLlm('coordinator');
493
+ return role
494
+ ? runCoordinatorAgentInbox({ role, pack: loadAgentRolePack('coordinator'), path: inboxPath, root,
495
+ ...(deps.coordinatorAgentRun ? { runAgent: deps.coordinatorAgentRun } : {}),
496
+ ...(deps.coordinatorAgentProvider ? { provider: deps.coordinatorAgentProvider } : {}) })
497
+ : runCoordinatorInbox(undefined, 100, inboxPath);
498
+ }))();
479
499
  if (inbox.replied || inbox.acknowledged) {
480
500
  observe('exchange', 'coordinator-inbox-replied', inbox.replied);
481
501
  observe('exchange', 'coordinator-inbox-acknowledged', inbox.acknowledged);
@@ -14,6 +14,9 @@ import { getUserConfig, type UserConfig } from '../user-config.js';
14
14
  import { runGraph, type GraphRunState } from '../graph-runner/runner.js';
15
15
  import { FENCE_ROLES } from '../hq/hq.js';
16
16
  import { dueBefore, type CheckEntry } from './checker.js';
17
+ import { readUnreadCount } from '../msg/msg-store.js';
18
+ import { loopMessageRoute, SEAT_MESSAGE_ROUTES, type LoopReplyBody, type MessageWake } from './msg-address.js';
19
+ import { resolveWake, type WakeDeps, type WakeResolution } from './msg-wake.js';
17
20
 
18
21
  export interface LoopRun {
19
22
  at: string;
@@ -25,6 +28,12 @@ export interface LoopRun {
25
28
  }
26
29
  export interface LoopEntry {
27
30
  id: string;
31
+ msgAddress?: string | null;
32
+ replyBody?: LoopReplyBody;
33
+ wake?: MessageWake;
34
+ /** Where `wake` came from — `unresolved` is «모름», not a measured absence. */
35
+ wakeSource?: WakeResolution['source'];
36
+ unreadCount?: number | null;
28
37
  title: string;
29
38
  description: string | null;
30
39
  owner?: string | null;
@@ -48,6 +57,20 @@ export interface LoopRegistryOptions {
48
57
  scheduleAction?: (action: 'create' | 'enable' | 'disable', args: Record<string, unknown>) => Promise<unknown>;
49
58
  /** Home used to expand `~`/`$HOME` in cron redirects; tests inject a temp dir instead of writing the real HOME. */
50
59
  home?: string;
60
+ /** Seat wake resolution (pty manifest ⊕ seat folders); tests inject fixed rows. */
61
+ wakeDeps?: WakeDeps;
62
+ }
63
+
64
+ function messageFields(id: string, stateRoot: string): { msgAddress: string | null; replyBody: LoopReplyBody; wake: MessageWake; wakeSource?: WakeResolution['source']; unreadCount: number | null } {
65
+ const route = loopMessageRoute(id);
66
+ return { ...route, ...(route.msgAddress ? { wakeSource: 'loop-table' as const } : {}), unreadCount: route.msgAddress ? readUnreadCount(route.msgAddress, join(stateRoot, 'msg', 'messages.db')) : null };
67
+ }
68
+
69
+ /** A seat row is addressed by its seat; its wake path is resolved on this host (pty name → herdr pane → 모름). */
70
+ function seatMessageFields(seat: string, stateRoot: string, wakeDeps?: WakeDeps): { msgAddress: string; replyBody: LoopReplyBody; wake: MessageWake; wakeSource: WakeResolution['source']; unreadCount: number | null } {
71
+ const wake = resolveWake(seat, wakeDeps);
72
+ return { msgAddress: seat, replyBody: 'agent', wake: wake.wake, wakeSource: wake.source,
73
+ unreadCount: readUnreadCount(seat, join(stateRoot, 'msg', 'messages.db')) };
51
74
  }
52
75
 
53
76
  function graphFiles(dir: string): string[] {
@@ -216,7 +239,7 @@ export function listLoops(opts: LoopRegistryOptions = {}): LoopEntry[] {
216
239
  const active = matched.filter(row => !!row.enabled && !!row.cron);
217
240
  const next = active.map(row => nextLoopFire(row.cron!, opts.now ?? new Date())).filter((v): v is string => v !== null).sort()[0] ?? null;
218
241
  const title = typeof header?.title === 'string' ? header.title : doc.graph_id;
219
- const entry: LoopEntry = { id: doc.graph_id, title,
242
+ const entry: LoopEntry = { id: doc.graph_id, title, ...messageFields(doc.graph_id, stateRoot),
220
243
  description: typeof header?.description === 'string' ? header.description : null,
221
244
  ...resolveOwner(doc.graph_id, title, config, header?.owner),
222
245
  mode: typeof header?.mode === 'string' ? header.mode : null, file: relative(root, file),
@@ -229,6 +252,12 @@ export function listLoops(opts: LoopRegistryOptions = {}): LoopEntry[] {
229
252
  }
230
253
 
231
254
  export interface AllLoopEntry extends CheckEntry {
255
+ msgAddress?: string | null;
256
+ replyBody?: LoopReplyBody;
257
+ wake?: MessageWake;
258
+ /** Where `wake` came from — `unresolved` is «모름», not a measured absence. */
259
+ wakeSource?: WakeResolution['source'];
260
+ unreadCount?: number | null;
232
261
  kind: 'graph' | 'seat' | 'cron-shell' | 'orchestrator' | 'unregistered';
233
262
  title: string;
234
263
  cron?: string;
@@ -589,6 +618,7 @@ export function listAllLoops(opts: LoopRegistryOptions = {}): AllLoopEntry[] {
589
618
  const declaredHost = typeof header.host === 'string' && header.host ? header.host : undefined;
590
619
  const declaredCategory = typeof header.observationCategory === 'string' && header.observationCategory ? header.observationCategory : undefined;
591
620
  return { kind: 'graph', id: loop.id, title: loop.title, owner: loop.owner ?? undefined, ownerSource: loop.ownerSource,
621
+ msgAddress: loop.msgAddress, replyBody: loop.replyBody, wake: loop.wake, ...(loop.wakeSource ? { wakeSource: loop.wakeSource } : {}), unreadCount: loop.unreadCount,
592
622
  ...(declaredHost || installed.length ? { host: declaredHost ?? hostname() } : {}),
593
623
  observationCategory: declaredCategory ?? 'graph.runner',
594
624
  ...(fenceRole ? { fenceRole } : {}),
@@ -599,6 +629,7 @@ export function listAllLoops(opts: LoopRegistryOptions = {}): AllLoopEntry[] {
599
629
  recentStatuses: runs.map(run => run.status) };
600
630
  });
601
631
  const namedIds = namedCronIds(rows, claimed);
632
+ const seatOf = new Map<AllLoopEntry, string>();
602
633
  for (const row of rows) {
603
634
  if (claimed.has(row.id)) continue;
604
635
  const command = row.command ?? '';
@@ -622,7 +653,7 @@ export function listAllLoops(opts: LoopRegistryOptions = {}): AllLoopEntry[] {
622
653
  const picked = logMtime && (!recorded || Date.parse(logMtime) >= Date.parse(recorded)) ? 'log-mtime'
623
654
  : recorded ? 'registry' : 'none';
624
655
  debug.log('loops.registry', 'cron-last-run', { id, targets, picked });
625
- all.push({ kind, id, title,
656
+ const pushed: AllLoopEntry = { kind, id, title,
626
657
  ...resolveOwner(id, title, config, undefined, seatArg ?? seat, seatArg ? 'seat-arg' : 'seat'), ...(fenceRole ? { fenceRole } : {}),
627
658
  host: hostname(), observationCategory: row.category,
628
659
  enabled: !!row.enabled, registered: true,
@@ -632,7 +663,11 @@ export function listAllLoops(opts: LoopRegistryOptions = {}): AllLoopEntry[] {
632
663
  ...(picked === 'log-mtime' ? { lastRunAt: logMtime, evidence: picked }
633
664
  : picked === 'registry' ? { lastRunAt: recorded, evidence: picked } : {}),
634
665
  ...(row.last_status ? { lastStatus: row.last_status } : {}),
635
- recentStatuses: row.last_status ? [row.last_status] : [] });
666
+ recentStatuses: row.last_status ? [row.last_status] : [] };
667
+ all.push(pushed);
668
+ const seatName = (seatArg ?? seat)?.toUpperCase();
669
+ // 선언된 자리 줄만 자리 주소로 공개한다 — 모르는 `--seat FOO` 는 종전처럼 주소 없음.
670
+ if (kind === 'seat' && seatName && Object.hasOwn(SEAT_MESSAGE_ROUTES, seatName)) seatOf.set(pushed, seatName);
636
671
  }
637
672
  const warnings = unregisteredCronLoops(all, graphOpts);
638
673
  for (const row of warnings) {
@@ -647,7 +682,10 @@ export function listAllLoops(opts: LoopRegistryOptions = {}): AllLoopEntry[] {
647
682
  for (const loop of all) bySource[loop.ownerSource!]++;
648
683
  debug.log('loop.check', 'ownership', { total: all.length, bySource });
649
684
  debug.log('loops.registry', 'list-all', { count: all.length });
650
- return all;
685
+ const stateRoot = opts.stateRoot ?? effectiveInstanceRoot();
686
+ return all.map(entry => entry.kind === 'graph' ? entry
687
+ : seatOf.has(entry) ? { ...entry, ...seatMessageFields(seatOf.get(entry)!, stateRoot, opts.wakeDeps) }
688
+ : { ...entry, ...messageFields(entry.id, stateRoot) });
651
689
  }
652
690
 
653
691
  /** An unclaimed cron line with any elanous marker must surface as an unregistered warning. */
package/src/memory.ts CHANGED
@@ -444,7 +444,12 @@ const INDEX_MAX_LINES = 200;
444
444
  */
445
445
  export function rebuildIndex(root: string = memoryRoot()): void {
446
446
  ensureRoot(root);
447
- const entries = listMemories({}, root);
447
+ writeFileDurable(memoryIndexPath(root), renderMemoryIndex(listMemories({}, root)));
448
+ }
449
+
450
+ /** The MEMORY.md text for a set of entries — rebuildIndex writes it for the whole store,
451
+ * a scoped injection renders it for the entries its filter keeps. */
452
+ export function renderMemoryIndex(entries: readonly MemoryEntry[]): string {
448
453
  const byType: Record<MemoryType, MemoryEntry[]> = {
449
454
  user: [], feedback: [], project: [], reference: [],
450
455
  };
@@ -468,7 +473,7 @@ export function rebuildIndex(root: string = memoryRoot()): void {
468
473
  }
469
474
  lines.push('');
470
475
  }
471
- writeFileDurable(memoryIndexPath(root), lines.join('\n'));
476
+ return lines.join('\n');
472
477
  }
473
478
 
474
479
  /** Read the MEMORY.md index verbatim. Returns '' when missing (e.g.
@@ -512,6 +517,11 @@ export interface InjectOpts {
512
517
  minScore?: number;
513
518
  /** Always include the MEMORY.md index even if no keyword hits. */
514
519
  alwaysIncludeIndex?: boolean;
520
+ /** Scope filter. When set, only kept entries are injected and the index is rendered from
521
+ * them instead of read from MEMORY.md (which lists every entry, other seats' cards included). */
522
+ filter?: (entry: MemoryEntry) => boolean;
523
+ /** Inject these bodies like pinned ones (e.g. the current seat's context cards). */
524
+ alwaysInject?: (entry: MemoryEntry) => boolean;
515
525
  }
516
526
 
517
527
  /** Build the memory-injection block for a user turn. Always prepends
@@ -531,7 +541,9 @@ export function buildMemoryInjection(
531
541
  const minScore = opts.minScore ?? 2;
532
542
  const alwaysIdx = opts.alwaysIncludeIndex !== false;
533
543
 
534
- const index = readIndex(root);
544
+ const filter = opts.filter;
545
+ const scoped = filter ? listMemories({}, root).filter(m => m.contextCard?.status !== 'retired' && filter(m)) : null;
546
+ const index = scoped ? (scoped.length > 0 ? renderMemoryIndex(scoped) : '') : readIndex(root);
535
547
  if (!index) return { block: '', tokens: 0, injectedIds: [] };
536
548
 
537
549
  const parts: string[] = [];
@@ -548,7 +560,10 @@ export function buildMemoryInjection(
548
560
 
549
561
  // 📌 pinned 기억 — 키워드 무관 항상 주입(relevance gate bypass · Letta pinned block /
550
562
  // claude-code MEMORY.md tier 동형). priority 높은 순. core/safety/ref-location 사실용.
551
- const pinnedMems = listMemories({}, root).filter(m => m.pinned && m.contextCard?.status !== 'retired').sort((a, b) => b.priority - a.priority);
563
+ const alwaysInject = opts.alwaysInject;
564
+ const pinnedMems = (scoped ?? listMemories({}, root))
565
+ .filter(m => (m.pinned || alwaysInject?.(m) === true) && m.contextCard?.status !== 'retired')
566
+ .sort((a, b) => b.priority - a.priority);
552
567
  const pinnedParts: string[] = [];
553
568
  for (const e of pinnedMems) {
554
569
  const chunk = pinnedChunk(e);
@@ -566,7 +581,7 @@ export function buildMemoryInjection(
566
581
  const hits = lowContext
567
582
  ? []
568
583
  : searchMemories(userText, { limit: maxHits + pinnedParts.length }, root)
569
- .filter(h => h.score >= minScore && !injected.includes(h.entry.id))
584
+ .filter(h => h.score >= minScore && !injected.includes(h.entry.id) && (!filter || filter(h.entry)))
570
585
  .slice(0, maxHits);
571
586
  const bodyParts: string[] = [];
572
587
  for (const hit of hits) {