elanous 0.2.36 → 0.2.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) 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/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
  8. package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 1262.a89bb27a5b2f844e.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 1746.3563617ea64023a3.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 2002-a43a3f380df873ec.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +32 -0
  19. package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 2283.edd9627b7bdfb546.js} +2 -2
  20. package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 2375.bf364c85dbb6f085.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
  25. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
  29. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 3199.6a1a9b0e6cd01dc6.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{2986.45d7652e4f13557e.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
  35. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
  39. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
  40. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
  41. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{7481.39f7a4654907bf6e.js → 4313.76f232c304a15bde.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4337e36d.f42c3b391b3d8f20.js +122 -0
  45. package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 4383.18e5c54db3a22c88.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{3757-180308bc61021b05.js → 4725-34bed25720cc326b.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
  52. package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 4931.95cc6dbd230774ca.js} +3 -3
  53. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5046.7fd5cbd859299448.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
  57. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 58edce7d.f1b0c72acf13b123.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
  65. package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 5952.294fc574a8625184.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
  68. package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 6252.240578f10952e091.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 6680.6a693c28aae4cd19.js} +2 -2
  71. package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 6745-5a63492933959dd9.js} +3 -3
  72. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
  74. package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 6819.be5c9c4d67f22922.js} +3 -3
  75. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
  78. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
  80. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
  83. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 7424.c0fe2a595d4232b5.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 7867.e8725745ddd1d940.js} +4 -4
  93. package/apps/pwa/out/_next/static/chunks/{6466-92e65a48490b68a9.js → 7893-e444a1b0809cd1e4.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{ccae1c4b-0cf414f5eff1b10d.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
  98. package/apps/pwa/out/_next/static/chunks/{3840-5825d56d46976a92.js → 8080-40d781e7704d3671.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
  100. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
  103. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
  107. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → 8c58d09b.e8724a299658d86f.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 9151.a2c51e93f9156dae.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
  117. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{190.285c832bd9626f8c.js → 958.53a8dcf4729e6997.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/{page-e2de2e59111c9aad.js → page-3337c6a1328c2674.js} +1 -1
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-f2b2e4bf6e981450.js → page-89acd5d68c0bc560.js} +1 -1
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-2af16e62c12f22df.js → page-fe986fe79b107546.js} +1 -1
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-ac2c1e6169cfce57.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → d9815f84.4918f682a45a8502.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → de8446d3.31b73eb239fecd7b.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/graphs/drafts/recipes.yaml +27 -7
  279. package/graphs/work/draft-close.yaml +54 -0
  280. package/graphs/work/green-close.yaml +37 -0
  281. package/graphs/work/recipes.yaml +46 -1
  282. package/graphs/work/run-research.yaml +35 -0
  283. package/package.json +1 -1
  284. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  285. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  286. package/scripts/codex-fallback-live-probe.ts +17 -15
  287. package/scripts/fleet/node-setup.sh +32 -2
  288. package/scripts/fleet/run-light-worker.sh +9 -0
  289. package/scripts/gate-0226-failure-census.ts +507 -0
  290. package/scripts/goals/authoring-metrics.ts +258 -0
  291. package/scripts/graph-units/draft-close-node.ts +222 -0
  292. package/scripts/hook-order-sweep.ts +7 -4
  293. package/scripts/land-global-checks.ts +69 -1
  294. package/scripts/measure-nl-routing-corpus.ts +207 -2
  295. package/scripts/release-loop/docs-node.ts +140 -0
  296. package/scripts/release-loop/gate-closure.ts +48 -0
  297. package/scripts/release-loop/gate-diff.ts +2 -1
  298. package/scripts/release-loop/known-issues-node.ts +6 -4
  299. package/scripts/release-loop/notes-repair.ts +216 -0
  300. package/scripts/release-loop/prepare-node.ts +61 -5
  301. package/scripts/release-loop/resume-release.ts +114 -4
  302. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  303. package/scripts/release-loop/version-node.ts +81 -12
  304. package/scripts/train/green-leg.ts +176 -0
  305. package/scripts/tui-continue-real-evidence.ts +47 -0
  306. package/scripts/ux-sim.ts +1 -1
  307. package/src/acp/client.ts +31 -5
  308. package/src/acp/core-turn-bridge.ts +6 -0
  309. package/src/acp/stderr-summary.ts +49 -0
  310. package/src/agent/monad-agent-turn.ts +1 -0
  311. package/src/agent/terminal-surface.ts +217 -0
  312. package/src/agent-substrate/pr-reviewer.ts +11 -3
  313. package/src/agent-substrate/self-review-cli.ts +343 -31
  314. package/src/autopilot/lineage/sources.ts +1 -1
  315. package/src/autopilot/pr-manager.ts +64 -13
  316. package/src/boot/daemon-runtime.ts +35 -3
  317. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  318. package/src/budget/run-usage-rollup.ts +12 -7
  319. package/src/budget/unified-usage.ts +20 -0
  320. package/src/capture/tui-self-report.ts +32 -3
  321. package/src/cli/autopilot-cli.ts +24 -9
  322. package/src/cli/decisions-cli.ts +7 -4
  323. package/src/cli/doctor-cli.ts +116 -7
  324. package/src/cli/logs-cli.ts +357 -2
  325. package/src/cli/memory-cli.ts +30 -1
  326. package/src/cli/msg-cli.ts +15 -11
  327. package/src/cli/pr-granularity.ts +5 -3
  328. package/src/cli/release-checklist-read-cli.ts +109 -4
  329. package/src/cli/release-cli.ts +43 -10
  330. package/src/cli/self-update.ts +23 -5
  331. package/src/cli/self-utterances-cli.ts +13 -16
  332. package/src/cli/tasks-cli.ts +309 -11
  333. package/src/cli/usage-cli.ts +12 -10
  334. package/src/context-bus/claude-memory-import.ts +99 -0
  335. package/src/context-bus/long-term-memory.ts +125 -0
  336. package/src/core-turn/run-goal-loop.ts +5 -2
  337. package/src/core-turn/types.ts +2 -0
  338. package/src/dashboard/chat/acp-chat.ts +9 -0
  339. package/src/dashboard/index.ts +97 -13
  340. package/src/dashboard/input/agent-wake.ts +43 -0
  341. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  342. package/src/dashboard/replay-preview.ts +25 -0
  343. package/src/dashboard/slash-runtime/dashboard-handlers.ts +17 -8
  344. package/src/dashboard/synchronized-frame-output.ts +74 -0
  345. package/src/display/coordinator.ts +45 -12
  346. package/src/display/resize-listener.ts +41 -20
  347. package/src/display/synchronized-output-region.ts +60 -0
  348. package/src/domains/surface-events.ts +80 -1
  349. package/src/exec-requests/planner.ts +37 -2
  350. package/src/execution-loop/launch-gate.ts +4 -3
  351. package/src/git-fs/cli-stderr.ts +45 -0
  352. package/src/git-fs/gh-cli.ts +6 -3
  353. package/src/git-fs/git-cli.ts +11 -5
  354. package/src/graph-runner/graph-cli.ts +26 -2
  355. package/src/graph-runner/graph-run-api.ts +3 -2
  356. package/src/graph-runner/runner.ts +17 -5
  357. package/src/graph-wizard/generate.ts +29 -6
  358. package/src/harness/harness-cli-command.ts +179 -33
  359. package/src/harness/review-adapter.ts +26 -6
  360. package/src/index.ts +116 -13
  361. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  362. package/src/llm/route-decision.ts +13 -0
  363. package/src/llm-tool-name.ts +37 -0
  364. package/src/llm-tool-schema.ts +35 -0
  365. package/src/llm.ts +123 -11
  366. package/src/loops/checker.ts +100 -0
  367. package/src/loops/consensus.ts +26 -2
  368. package/src/loops/loop-cli.ts +9 -4
  369. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  370. package/src/loops/orchestrator/tick.ts +49 -4
  371. package/src/model-tier/llm-tier-map.ts +12 -17
  372. package/src/msg/msg-store.ts +17 -0
  373. package/src/native-tool-catalog.ts +1 -1
  374. package/src/nexus/api/graph-wizard-api.ts +27 -2
  375. package/src/nexus/api/grid.ts +24 -4
  376. package/src/nexus/api/http-server.ts +1 -1
  377. package/src/nexus/api/ops-api.ts +14 -6
  378. package/src/nexus/state/state.ts +7 -1
  379. package/src/oauth/codex-account-store.ts +34 -1
  380. package/src/ops/loops-map.ts +46 -0
  381. package/src/ops/overview-cache.ts +22 -4
  382. package/src/ops/overview.ts +41 -5
  383. package/src/policy/llm-policy.ts +3 -1
  384. package/src/prompt-enhance/enhance.ts +4 -4
  385. package/src/pty-shell/availability.ts +7 -0
  386. package/src/pty-shell/herdr-agent-report.ts +40 -31
  387. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  388. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  389. package/src/pty-shell/pty-control-ipc.ts +187 -18
  390. package/src/pty-shell/registry.ts +25 -15
  391. package/src/pty-shell/tui-run-state.ts +235 -1
  392. package/src/release-loop/checklist.ts +50 -5
  393. package/src/release-loop/feature-store.ts +9 -9
  394. package/src/release-loop/landed-but-yellow.ts +93 -12
  395. package/src/repl/index.ts +8 -0
  396. package/src/seat-loop/seat-report.ts +1 -0
  397. package/src/self-dev/ask-launch-flow.ts +86 -10
  398. package/src/self-dev/decompose-proposal.ts +29 -18
  399. package/src/self-dev/dev-pipeline.ts +29 -7
  400. package/src/self-dev/draft-sweep.ts +241 -16
  401. package/src/self-dev/draft-triage-rules.ts +19 -5
  402. package/src/self-dev/review-provider-fallback.ts +45 -7
  403. package/src/self-dev/shard-plan.ts +48 -0
  404. package/src/self-dev/shard-run.ts +50 -3
  405. package/src/self-implement/doctor-visit.ts +83 -0
  406. package/src/self-implement/gate-artifacts.ts +6 -2
  407. package/src/self-implement/gate-baseline.ts +64 -1
  408. package/src/self-implement/gate-cli.ts +93 -9
  409. package/src/self-implement/gate-remote.ts +28 -4
  410. package/src/self-implement/gate-scope.ts +13 -1
  411. package/src/self-implement/goal-author.ts +333 -18
  412. package/src/self-implement/goal-supervisor-fill.ts +75 -26
  413. package/src/self-implement/importer-test-index.ts +215 -2
  414. package/src/self-implement/knowhow-pack.ts +5 -5
  415. package/src/self-implement/orchestrator.ts +318 -25
  416. package/src/self-implement/review-round-brief.ts +300 -0
  417. package/src/self-implement/rework-policy.ts +14 -0
  418. package/src/self-implement/run-ledger.ts +170 -6
  419. package/src/self-implement/run-stop.ts +1 -1
  420. package/src/self-implement/running-runs.ts +17 -3
  421. package/src/self-implement/seams.ts +12 -6
  422. package/src/self-implement/stop-autoheal.ts +1 -0
  423. package/src/self-implement/test-seams.ts +13 -1
  424. package/src/self-implement/train-reach-grouping.ts +8 -2
  425. package/src/session/chat.ts +7 -1
  426. package/src/session/id-prefix.ts +60 -0
  427. package/src/session/index.ts +4 -0
  428. package/src/session-runtime/index.ts +9 -1
  429. package/src/skills/tools/pty.ts +5 -0
  430. package/src/status/metrics.ts +12 -1
  431. package/src/steward/rejudge-tick.ts +12 -5
  432. package/src/steward/resync-tick.ts +31 -4
  433. package/src/task-agent/actions.ts +199 -4
  434. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  435. package/src/task-agent/boundary-proof-producer.ts +147 -0
  436. package/src/task-agent/completion-evidence.ts +2 -1
  437. package/src/task-agent/green-close-recipe.ts +239 -0
  438. package/src/task-agent/green-sweep.ts +64 -10
  439. package/src/task-agent/live-moves.ts +48 -3
  440. package/src/task-agent/map-host-adapter.ts +134 -0
  441. package/src/task-agent/map-reduce.ts +158 -0
  442. package/src/task-agent/map-run-ledger.ts +226 -0
  443. package/src/task-agent/parent-host.ts +21 -11
  444. package/src/task-agent/rejudge-on-head.ts +72 -5
  445. package/src/task-agent/repair-cycle.ts +41 -0
  446. package/src/task-agent/repair-next-move.ts +12 -2
  447. package/src/task-agent/review-prior-fix.ts +12 -2
  448. package/src/task-agent/shadow.ts +188 -5
  449. package/src/task-agent/task-hand.ts +158 -13
  450. package/src/task-agent/task-parent-role-llm.ts +9 -0
  451. package/src/task-agent/tier-split.ts +4 -3
  452. package/src/task-agent/work-order.ts +53 -2
  453. package/src/task-orchestrator/dispatcher.ts +46 -1
  454. package/src/task-orchestrator/generator-prompt.ts +6 -0
  455. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  456. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  457. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  458. package/src/task-orchestrator/surfaces/pod-pool.ts +50 -4
  459. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
  460. package/src/task-orchestrator/surfaces/self-implement-pod.ts +217 -36
  461. package/src/task-orchestrator/surfaces/self-implement.ts +4 -0
  462. package/src/testing/linux-env.ts +177 -0
  463. package/src/tui/chat/goal-interim.ts +5 -1
  464. package/src/tui/entry.ts +258 -4
  465. package/src/tui/input/at-picker.ts +55 -0
  466. package/src/tui/slash/resume.ts +35 -12
  467. package/src/tui/slash/signals.ts +114 -0
  468. package/src/tui/slash/term-next.ts +71 -0
  469. package/src/tui-client/local-chat-turn.ts +4 -3
  470. package/src/user-config.ts +19 -1
  471. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  472. package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
  473. package/src/ux-sim/fake-gh.ts +174 -0
  474. package/src/ux-sim/fake-kubectl.ts +142 -0
  475. package/src/ux-sim/fake-llm.ts +6 -1
  476. package/src/ux-sim/next-tui-seat-scenarios.ts +124 -6
  477. package/src/ux-sim/resume-picker-device.ts +173 -0
  478. package/src/ux-sim/session-id-seed.ts +60 -0
  479. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  480. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  481. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  482. package/src/version/packed-revision.json +1 -1
  483. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
  484. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
  490. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
  493. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
  498. package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
  502. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/3148-98efd4869d660a87.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
  505. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
  509. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
  510. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
  512. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
  515. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
  519. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
  522. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
  524. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
  526. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +0 -41
  531. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
  532. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
  544. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
  557. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
  559. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
  560. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
  565. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
  630. /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
@@ -9,11 +9,10 @@
9
9
  // 마지막 턴 상태를 잠시 뒤 다시 신고하고(새 seq · 더 새 턴이 오면 그만) 이후 턴 신고도 그대로 보낸다.
10
10
  //
11
11
  // herdr 는 같은 pane·source 에서 «직전보다 큰 seq» 만 받는다(작으면 rc0 인데 무시).
12
- // 같은 pane 에서 TUI 를 다시 띄워도 신고가 살도록 seq 는 max(직전+1 · 시각 · pane 기록+1) 이다.
13
- // pane 기록 = 그 pane 에서 마지막으로 낸 seq(기본 tmpdir 파일) — 같은 ms 재기동·시계 역행에도 뒤 프로세스가 앞 프로세스보다 크다.
14
- // ⛔ 턴 경로는 파일을 안 만진다: 기록은 start 때 한 번 읽고, release(원래 동기인 종료 경로)에서만 쓴다.
12
+ // 같은 pane 에서 TUI 를 다시 띄워도 신고가 살도록 seq 는 max(직전+1 · 시각 · 예약 high-watermark+1) 이다.
13
+ // pane 기록 = 예약한 seq 범위의 high-watermark(기본 tmpdir 파일) — 정상·비정상 재기동에서 뒤 범위를 쓴다.
14
+ // ⛔ 턴 경로는 보통 파일을 안 만진다: 범위가 소진되면 next()가 새 범위를 파일에 예약한다.
15
15
  // 기록을 못 읽고 못 쓰면(관측 `seq-store-failed` 한 번) 시각·직전+1 로만 간다.
16
- // 한계: release 없이 죽은 프로세스의 마지막 seq 는 기록되지 않는다 — 그때 뒤 프로세스는 시각에 기댄다.
17
16
  //
18
17
  // 실패로 꺼지는 것은 «이후 turn» 뿐이다. release(권한 반납)는 start 실패가 «확인»됐을 때만 건너뛴다.
19
18
  // start 의 비동기 신고가 아직 안 끝났으면(결과 모름) 반납을 미루지 않고 바로 동기로 시도한다(관측 `release-start-pending`) —
@@ -27,6 +26,9 @@ import { tmpdir } from 'node:os';
27
26
  import { join } from 'node:path';
28
27
 
29
28
  import { debug } from '../debug/log.js';
29
+ import { pruneStaleHerdrAgent } from './herdr-prune-stale.js';
30
+ import { HerdrSequenceLease, type HerdrSeqStore } from './herdr-sequence-lease.js';
31
+ export type { HerdrSeqStore } from './herdr-sequence-lease.js';
30
32
 
31
33
  /** 턴 값 — tui-run-state 의 PtyTurnState 와 같은 낱말이지만 순환 import 를 피하려 여기 둔다. */
32
34
  export type HerdrTurn = 'busy' | 'idle';
@@ -55,10 +57,12 @@ export interface HerdrAgentReporterDeps {
55
57
  readonly sessionId?: string;
56
58
  /** seq 시작값의 시계(ms). 기본 Date.now. */
57
59
  readonly now?: () => number;
58
- /** pane 별 마지막 seq 기록. 기본 = tmpdir 파일(`createFileSeqStore`). */
60
+ /** pane 별 예약 범위 끝 기록. 기본 = tmpdir 파일(`createFileSeqStore`). */
59
61
  readonly seqStore?: HerdrSeqStore;
60
62
  /** 재신고 타이머 — 기본 setTimeout(unref). 시험이 가짜 시계를 준다. */
61
63
  readonly schedule?: (fn: () => void, ms: number) => void;
64
+ /** Injected runners skip production startup cleanup unless explicitly enabled. */
65
+ readonly pruneStaleOnStart?: boolean;
62
66
  }
63
67
 
64
68
  const defaultSchedule = (fn: () => void, ms: number): void => {
@@ -66,12 +70,6 @@ const defaultSchedule = (fn: () => void, ms: number): void => {
66
70
  (t as unknown as { unref?: () => void }).unref?.();
67
71
  };
68
72
 
69
- /** 같은 pane 에서 마지막으로 낸 seq — 프로세스 사이 단조를 잇는다. 실패는 던져도 된다(신고기가 삼킨다). */
70
- export interface HerdrSeqStore {
71
- read(): number | undefined;
72
- write(seq: number): void;
73
- }
74
-
75
73
  export function defaultHerdrSeqDir(): string {
76
74
  return join(tmpdir(), 'elanous-herdr-seq');
77
75
  }
@@ -277,13 +275,17 @@ export function createHerdrAgentReporter(deps: HerdrAgentReporterDeps = {}): Her
277
275
  }
278
276
  const run = deps.run ?? defaultHerdrRunner(env);
279
277
  const sessionId = deps.sessionId ?? '';
280
- return new Reporter(paneId, sessionId, run, log, deps.now ?? Date.now, deps.seqStore ?? createFileSeqStore(paneId), deps.schedule ?? defaultSchedule);
278
+ return new Reporter(
279
+ paneId, sessionId, run, log, deps.now ?? Date.now,
280
+ deps.seqStore ?? createFileSeqStore(paneId), deps.schedule ?? defaultSchedule,
281
+ deps.pruneStaleOnStart ?? deps.run === undefined,
282
+ );
281
283
  }
282
284
 
283
285
  type IssueResult = boolean | Promise<boolean>;
284
286
 
285
287
  class Reporter implements HerdrAgentReporterLike {
286
- private seq = 0;
288
+ private readonly sequence: HerdrSequenceLease;
287
289
  private disabled = false;
288
290
  /**
289
291
  * idle 신고(에이전트 등록)의 상태: none → (pending →) ok | failed.
@@ -291,8 +293,6 @@ class Reporter implements HerdrAgentReporterLike {
291
293
  */
292
294
  private startState: 'none' | 'pending' | 'ok' | 'failed' = 'none';
293
295
  private released = false;
294
- /** start 때 한 번 읽은 pane 기록(턴 경로는 파일을 안 만진다). */
295
- private storedSeq: number | undefined;
296
296
  /** idle 신고(비동기 포함)가 실패했다 — 등록된 적이 없으니 반납할 것이 없다. */
297
297
  private idleFailed = false;
298
298
  private seqStoreFailed = false;
@@ -313,9 +313,12 @@ class Reporter implements HerdrAgentReporterLike {
313
313
  private readonly run: HerdrRunner,
314
314
  private readonly log: (event: string, data: Record<string, unknown>) => void,
315
315
  private readonly now: () => number,
316
- private readonly seqStore: HerdrSeqStore,
316
+ seqStore: HerdrSeqStore,
317
317
  private readonly schedule: (fn: () => void, ms: number) => void,
318
- ) {}
318
+ private readonly pruneStaleOnStart: boolean,
319
+ ) {
320
+ this.sequence = new HerdrSequenceLease(seqStore, now, (error) => this.seqStoreFail(error));
321
+ }
319
322
 
320
323
  /** 마지막으로 요청된 턴 상태와 그 세대 — 재신고는 세대가 그대로일 때만(더 새 턴이 오면 그만). */
321
324
  private lastTurn: HerdrTurn | null = null;
@@ -324,7 +327,17 @@ class Reporter implements HerdrAgentReporterLike {
324
327
 
325
328
  start(): void {
326
329
  if (this.startState !== 'none') return;
327
- try { this.storedSeq = this.seqStore.read(); } catch (error) { this.seqStoreFail(error); }
330
+ if (this.pruneStaleOnStart) {
331
+ const pruneSeq = this.nextSeq();
332
+ try {
333
+ const pruned = pruneStaleHerdrAgent(this.paneId, pruneSeq, this.run);
334
+ this.log(pruned.ok ? 'startup-prune-complete' : 'startup-prune-failed', {
335
+ seq: pruneSeq, ...(pruned.stderr ? { stderrHead: stderrHead(pruned.stderr) } : {}),
336
+ });
337
+ } catch (error) {
338
+ this.log('startup-prune-failed', { seq: pruneSeq, stderrHead: stderrHead(error instanceof Error ? error.message : String(error)) });
339
+ }
340
+ }
328
341
  const idleOk = this.issue([
329
342
  'pane', 'report-agent',
330
343
  '--source', HERDR_SOURCE, '--agent', HERDR_AGENT,
@@ -365,8 +378,6 @@ class Reporter implements HerdrAgentReporterLike {
365
378
  this.releasedWhilePending = false;
366
379
  this.log('release-resend-after-late-start', {});
367
380
  const seq = this.nextSeq();
368
- // 재반납 seq 도 pane 기록에 남긴다 — 같은 ms 재기동의 첫 seq 가 이 값보다 커야 한다(r7 리뷰 mf).
369
- try { this.seqStore.write(this.seq); } catch (error) { this.seqStoreFail(error); }
370
381
  void this.runAndJudge([
371
382
  'pane', 'release-agent',
372
383
  this.paneId,
@@ -418,8 +429,6 @@ class Reporter implements HerdrAgentReporterLike {
418
429
  ], true, 'release');
419
430
  }
420
431
  const seq = this.nextSeq();
421
- // pane 기록 쓰기는 여기(동기 종료 경로)뿐이다.
422
- try { this.seqStore.write(this.seq); } catch (error) { this.seqStoreFail(error); }
423
432
  // ⛔ herdr 0.9.1 `release-agent` 는 PANE_ID 를 옵션 «앞»에 둬야 받는다 — 뒤에 두면
424
433
  // «unknown option: custom:elanous» rc2 로 반납이 영영 안 됐다(10-18 라이브 실측 · report-agent 는 뒤도 받음).
425
434
  this.issue([
@@ -457,20 +466,16 @@ class Reporter implements HerdrAgentReporterLike {
457
466
  this.log('seq-store-failed', { error: error instanceof Error ? error.message : String(error) });
458
467
  }
459
468
 
460
- /** max(직전+1 · 시각 ms · pane 기록+1) — 같은 ms 재기동에도 뒤 프로세스의 첫 seq 가 앞 프로세스의 마지막보다 크다. */
469
+ /** Reserved sequence lease advances monotonically across same-millisecond restarts. */
461
470
  private nextSeq(): string {
462
- const clock = Math.floor(this.now());
463
- let next = Number.isFinite(clock) ? Math.max(this.seq + 1, clock) : this.seq + 1;
464
- if (this.storedSeq !== undefined) next = Math.max(next, this.storedSeq + 1);
465
- this.seq = next;
466
- return String(this.seq);
471
+ return String(this.sequence.next());
467
472
  }
468
473
 
469
474
  /**
470
475
  * release 는 꺼진 뒤에도 보낸다(권한 반납 · start 성공 조건은 release() 가 본다).
471
476
  * @returns false = 동기 실패(신고기 꺼짐) · true = 동기 성공 · Promise = 비동기 결과(성공이면 true).
472
477
  */
473
- private issue(argv: string[], sync: boolean, phase: 'start' | 'session' | 'turn' | 'release'): IssueResult {
478
+ private issue(argv: string[], sync: boolean, phase: 'start' | 'session' | 'turn' | 'release' | 'stale-cleanup'): IssueResult {
474
479
  if (this.disabled && phase !== 'release') return false;
475
480
  const opts: HerdrRunOpts = { sync, timeoutMs: sync ? SYNC_TIMEOUT_MS : ASYNC_TIMEOUT_MS };
476
481
  if (!sync && this.pending) {
@@ -520,7 +525,7 @@ class Reporter implements HerdrAgentReporterLike {
520
525
  }
521
526
 
522
527
  /** 줄 선 비동기 한 건 — 러너 결과(동기·비동기 모두)를 성패로 접는다. */
523
- private async runAndJudge(argv: string[], opts: HerdrRunOpts, phase: 'start' | 'session' | 'turn' | 'release'): Promise<boolean> {
528
+ private async runAndJudge(argv: string[], opts: HerdrRunOpts, phase: 'start' | 'session' | 'turn' | 'release' | 'stale-cleanup'): Promise<boolean> {
524
529
  try {
525
530
  const r = await this.run(argv, opts);
526
531
  if (r.ok) return true;
@@ -532,7 +537,7 @@ class Reporter implements HerdrAgentReporterLike {
532
537
  }
533
538
  }
534
539
 
535
- private fail(argv: string[], phase: 'start' | 'session' | 'turn' | 'release', stderr: string | undefined, timedOut = false): void {
540
+ private fail(argv: string[], phase: 'start' | 'session' | 'turn' | 'release' | 'stale-cleanup', stderr: string | undefined, timedOut = false): void {
536
541
  if (phase === 'turn' && timedOut && !this.disabled) {
537
542
  this.retryTurnAfterTimeout(argv, stderr);
538
543
  return;
@@ -543,6 +548,10 @@ class Reporter implements HerdrAgentReporterLike {
543
548
  this.log('release-failed', { stderrHead: stderrHead(stderr) });
544
549
  return;
545
550
  }
551
+ if (phase === 'stale-cleanup') {
552
+ this.log('stale-agent-cleanup-failed', { stderrHead: stderrHead(stderr) });
553
+ return;
554
+ }
546
555
  if (this.disabled) return;
547
556
  this.disabled = true;
548
557
  const cmd = argv[1] ?? '';
@@ -0,0 +1,17 @@
1
+ import type { HerdrRunResult, HerdrRunner } from './herdr-agent-report.js';
2
+
3
+ const PRUNE_TIMEOUT_MS = 300;
4
+
5
+ /** Best-effort removal of a prior custom agent left behind in this pane. */
6
+ export function pruneStaleHerdrAgent(
7
+ paneId: string,
8
+ seq: string,
9
+ run: HerdrRunner,
10
+ ): HerdrRunResult {
11
+ const result = run([
12
+ 'pane', 'release-agent', paneId,
13
+ '--source', 'custom:elanous', '--agent', 'elanous', '--seq', seq,
14
+ ], { sync: true, timeoutMs: PRUNE_TIMEOUT_MS });
15
+ if (result instanceof Promise) throw new Error('startup prune requires a synchronous herdr runner');
16
+ return result;
17
+ }
@@ -0,0 +1,60 @@
1
+ export interface HerdrSeqStore {
2
+ read(): number | undefined;
3
+ write(seq: number): void;
4
+ }
5
+
6
+ const DEFAULT_SEQ_WINDOW = 65_536;
7
+
8
+ /** Reserve future sequence values before reporting so a SIGKILL restart can advance past the dead process. */
9
+ export class HerdrSequenceLease {
10
+ private seq = 0;
11
+ private end = 0;
12
+ private stored: number | undefined;
13
+ private ready = false;
14
+ private failed = false;
15
+
16
+ constructor(
17
+ private readonly store: HerdrSeqStore,
18
+ private readonly now: () => number,
19
+ private readonly onFailure: (error: unknown) => void,
20
+ private readonly seqWindow = DEFAULT_SEQ_WINDOW,
21
+ ) {}
22
+
23
+ next(): number {
24
+ this.initialize();
25
+ const clock = Math.floor(this.now());
26
+ let next = Number.isFinite(clock) ? Math.max(this.seq + 1, clock) : this.seq + 1;
27
+ if (this.stored !== undefined) next = Math.max(next, this.stored + 1);
28
+ if (next > this.end) this.reserve(next);
29
+ this.seq = next;
30
+ return next;
31
+ }
32
+
33
+ private initialize(): void {
34
+ if (this.ready) return;
35
+ try {
36
+ const stored = this.store.read();
37
+ this.stored = typeof stored === 'number' && Number.isSafeInteger(stored) && stored >= 0 ? stored : undefined;
38
+ } catch (error) { this.fail(error); }
39
+ const clock = Math.floor(this.now());
40
+ this.seq = Number.isFinite(clock) ? Math.max(clock + this.seqWindow, this.stored ?? 0) : (this.stored ?? 0);
41
+ this.reserve(this.seq);
42
+ this.ready = true;
43
+ }
44
+
45
+ private reserve(from: number): void {
46
+ const end = from + this.seqWindow;
47
+ try { this.store.write(end); } catch (error) { this.fail(error); }
48
+ this.end = end;
49
+ }
50
+
51
+ private fail(error: unknown): void {
52
+ if (this.failed) return;
53
+ this.failed = true;
54
+ this.onFailure(error);
55
+ }
56
+ }
57
+
58
+ export function staleHerdrReleaseArgs(paneId: string, source: string, agent: string, seq: number): string[] {
59
+ return ['pane', 'release-agent', paneId, '--source', source, '--agent', agent, '--seq', String(seq)];
60
+ }
@@ -1,13 +1,15 @@
1
1
  import { Database } from 'bun:sqlite';
2
2
  import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
- import { ptyManifestDbPath, getPtyManifest, markPtyControlled } from './pty-manifest.js';
4
+ import { ptyManifestDbPath, getPtyManifest, markPtyControlled, listPtyManifestRows, listPtyManifestRowsAt } from './pty-manifest.js';
5
5
  import { getHarnessRunId } from '../harness/harness-space.js';
6
6
  import { renamePty, type PtyControlTarget } from './registry.js';
7
7
  import { resizePtyWithOutcome, writePtyWithOutcome, writePtyWithOutcomeDetail } from './pty-write-outcome.js';
8
8
  import { resetExternalWriteProvenanceForTesting } from './pty-write-provenance.js';
9
9
  import { parsePtyWriteActor, resolveRemoteControlActor, type PtyWriteActor } from './pty-write-arbiter.js';
10
- import { isPtyAccessMode } from './pty-ref.js';
10
+ import { isPtyAccessMode, resolvePtyRef, type PtyRefReason } from './pty-ref.js';
11
+ import { RemotesStore } from '../cli/remotes.js';
12
+ import { bookmarkToElanousRemote } from '../cli/remote-resolve.js';
11
13
  import { debug } from '../debug/log.js';
12
14
  import { encodeSgrMouse, mouseModeOffReason, type PtyMouseInput } from './pty-mouse.js';
13
15
  import { startPtyRecording, stopPtyRecording } from './pty-recording.js';
@@ -53,6 +55,12 @@ export interface PtyControlRequestOptions {
53
55
  readonly now?: () => number;
54
56
  /** 요청자 poll 루프의 대기(기본 `Bun.sleep`) — 기본값에서 25ms cadence 계약은 그대로다. */
55
57
  readonly sleep?: (ms: number) => Promise<void>;
58
+ /** 사람 타이핑 세션 — 있으면 재해석·재캡처 없이 이 «고정값»만 쓴다(`beginPtyHumanTypingSession`). */
59
+ readonly typingSession?: PtyHumanTypingSession;
60
+ /** 아직 세션이 없을 때 캡처할 북마크 이름(없으면 remotes.json 의 default · 그것도 없으면 로컬). */
61
+ readonly bookmarkName?: string;
62
+ /** 호출자가 이미 캡처해 둔 북마크 핀 — 재조회하지 않는다. */
63
+ readonly typingBookmark?: PtyTypingBookmarkPin;
56
64
  }
57
65
 
58
66
  export interface PtyControlResult {
@@ -185,6 +193,27 @@ const PTY_CONTROL_DEEP_IDLE_AFTER_MS = 10 * 60_000;
185
193
  /** 깊은 유휴에서의 재읽기 간격. 요청 wake 는 이 간격을 «기다리지 않는다». */
186
194
  const PTY_CONTROL_DEEP_IDLE_POLL_MS = 1_500;
187
195
 
196
+ /** 감속 계단의 두 값과 «계측» 훅 — 생산 기본값은 위 상수 ⊕ env override 다. */
197
+ interface ControlCadenceLimits {
198
+ readonly deepIdleAfterMs: number;
199
+ readonly deepIdlePollMs: number;
200
+ /** 큐를 실제로 다시 읽을 때마다 1회 — 감속 계측용(생산 진입점은 넘기지 않는다). */
201
+ readonly onQueueRead?: () => void;
202
+ }
203
+
204
+ /** 생산 폴러는 옵션 없이 호출되므로 env override 뒤 상수 기본값만 사용한다. */
205
+ function resolveCadenceMs(envName: string, fallback: number): number {
206
+ return positiveInteger(Number(process.env[envName])) ?? fallback;
207
+ }
208
+
209
+ function cadenceLimits(options: PtyControlProcessOptions): ControlCadenceLimits {
210
+ return {
211
+ deepIdleAfterMs: resolveCadenceMs('ELANOUS_PTY_CONTROL_DEEP_IDLE_AFTER_MS', PTY_CONTROL_DEEP_IDLE_AFTER_MS),
212
+ deepIdlePollMs: resolveCadenceMs('ELANOUS_PTY_CONTROL_DEEP_IDLE_POLL_MS', PTY_CONTROL_DEEP_IDLE_POLL_MS),
213
+ ...(options.onQueueRead ? { onQueueRead: options.onQueueRead } : {}),
214
+ };
215
+ }
216
+
188
217
  /** 깨어움 표식은 큐와 같은 원장 디렉터리에 둔다 — 요청자와 owner 가 같은 원장(`ptyManifestDbPath`)을
189
218
  * 볼 때 owner 의 tick 이 곧바로 그 자리를 본다. 연합 큐(`manifestDbPath`)로 남의 원장에 요청하면
190
219
  * 표식은 그 원장 자리에 남고 그 owner 는 감속 간격만큼만 늦다(요청 timeout 안쪽 · fail-soft).
@@ -236,7 +265,7 @@ function observeControlCadence(state: ControlCadenceState, mode: 'active' | 'dee
236
265
  * ⛔ 첫 tick 은 언제나 읽는다(기동 직후 도착한 요청을 감속 뒤에 두지 않는다).
237
266
  * ⛔ 감속 시계는 `pollClock`(기본 `Date.now`) 뿐이다 — `now`(takeover TTL 시계)를 섞으면 시험이
238
267
  * 주입한 값이 실제 tick 을 감속시키는 회귀가 난다. */
239
- function shouldReadControlQueue(dbPath: string, nowMs: number): boolean {
268
+ function shouldReadControlQueue(dbPath: string, nowMs: number, limits: ControlCadenceLimits): boolean {
240
269
  const state = cadenceState(dbPath);
241
270
  // 시계가 뒤로 갔다 = 이전 관측과 다른 시계다. 그 앵커로는 유휴를 못 재므로 버리고 다시 센다.
242
271
  if (state.lastSeenAt !== null && nowMs < state.lastSeenAt) {
@@ -248,14 +277,15 @@ function shouldReadControlQueue(dbPath: string, nowMs: number): boolean {
248
277
  const woke = consumePtyControlWake(dbPath);
249
278
  if (state.lastControlAt === null || woke) state.lastControlAt = nowMs;
250
279
  const idleMs = nowMs - state.lastControlAt;
251
- const deepIdle = idleMs >= PTY_CONTROL_DEEP_IDLE_AFTER_MS;
280
+ const deepIdle = idleMs >= limits.deepIdleAfterMs;
252
281
  const sinceReadMs = state.lastDbReadAt === null ? Number.POSITIVE_INFINITY : nowMs - state.lastDbReadAt;
253
- if (!woke && deepIdle && sinceReadMs < PTY_CONTROL_DEEP_IDLE_POLL_MS) {
282
+ if (!woke && deepIdle && sinceReadMs < limits.deepIdlePollMs) {
254
283
  observeControlCadence(state, 'deep-idle', idleMs);
255
284
  return false;
256
285
  }
257
286
  state.lastDbReadAt = nowMs;
258
287
  observeControlCadence(state, deepIdle ? 'deep-idle' : 'active', idleMs);
288
+ limits.onQueueRead?.();
259
289
  return true;
260
290
  }
261
291
 
@@ -271,6 +301,124 @@ export async function requestRemotePtyControlCapabilities(id: string, options: P
271
301
  return { status: 'owner-result', result };
272
302
  }
273
303
 
304
+ // ── PTY-HUMAN-TYPING-REMOTE (0.2.36 · UX 칸) — 사람 타이핑의 ref 해석·bookmark 캡처는 «한 번» ──
305
+ //
306
+ // `--remote --human` 타이핑은 호출자가 준 ref(alias·nickname)를 그대로 원장에 흘리면 안 된다:
307
+ // 타이핑 도중 nickname 이 바뀌면 같은 입력이 다른 PTY 로 풀리고, 북마크(host·token·url)가 갈라지면
308
+ // «어느 원격에 쓰는가» 자체가 흔들린다. ⇒ 첫 글자를 넣기 前에 한 번 해석·캡처하고 그 값을 세션 전체에
309
+ // 고정한다. 해석이 확정되기 前에는 원장 행을 «쓰지 않는다»(fail-closed).
310
+ //
311
+ // ⛔ 여기서 해석기를 새로 만들지 않는다 — 목록은 `pty-manifest`(listPtyManifestRows/…At),
312
+ // 해석은 `pty-ref`(resolvePtyRef), 북마크는 `cli/remotes`(RemotesStore) 가 정본이다.
313
+
314
+ /** 사람 타이핑 세션이 고정하는 원격 북마크 신원 — 캡처는 세션 시작 때 한 번뿐이다. */
315
+ export interface PtyTypingBookmarkPin {
316
+ readonly name: string;
317
+ readonly host: string;
318
+ readonly url: string;
319
+ readonly token?: string;
320
+ }
321
+
322
+ /** 타이핑 세션의 고정값 — 이 객체가 사는 동안 재해석·재조회가 없다. */
323
+ export interface PtyHumanTypingSession {
324
+ /** 호출자가 준 ref(그대로 보존 — 원장·로그 대조용). */
325
+ readonly ref: string;
326
+ /** 해석된 canonical pty id — 이후 모든 요청이 쓰는 유일한 주소. */
327
+ readonly ptyId: string;
328
+ /** 어느 단계로 확정됐나(`exact-id`·`nickname-exact`·`kind`·`id-prefix`·`nickname-substr`). */
329
+ readonly resolvedBy: PtyRefReason;
330
+ /** 캡처된 원격 북마크(로컬이면 null). */
331
+ readonly bookmark: PtyTypingBookmarkPin | null;
332
+ /** 해석에 쓴 매니페스트 뿌리 — 연합 요청이면 그 원장이다. */
333
+ readonly manifestDbPath?: string;
334
+ }
335
+
336
+ export interface PtyHumanTypingOptions {
337
+ /** 해석에 쓸 매니페스트 뿌리 — 없으면 이 프로세스의 원장(`ptyManifestDbPath`). */
338
+ readonly manifestDbPath?: string;
339
+ /** 이미 읽어 둔 핀(호출자가 캡처를 마친 경우) — 재조회하지 않는다. */
340
+ readonly bookmark?: PtyTypingBookmarkPin;
341
+ /** 캡처할 북마크 이름. 없으면 default 북마크, 그것도 없으면 로컬(null). */
342
+ readonly bookmarkName?: string;
343
+ /** remotes.json 저장소 재정의(시험·연합). */
344
+ readonly remotes?: RemotesStore;
345
+ }
346
+
347
+ export type PtyHumanTypingResolution =
348
+ | { readonly ok: true; readonly session: PtyHumanTypingSession }
349
+ | {
350
+ readonly ok: false;
351
+ readonly status: 'ambiguous-ref' | 'unresolved-ref' | 'unknown-bookmark';
352
+ /** ambiguous 면 후보 canonical id 들(사람이 고를 수 있게). */
353
+ readonly candidates: readonly string[];
354
+ };
355
+
356
+ type BookmarkCapture = { readonly ok: true; readonly pin: PtyTypingBookmarkPin | null } | { readonly ok: false };
357
+
358
+ function captureTypingBookmark(options: PtyHumanTypingOptions): BookmarkCapture {
359
+ if (options.bookmark) return { ok: true, pin: options.bookmark };
360
+ const wanted = options.bookmarkName?.trim() ?? '';
361
+ try {
362
+ const store = options.remotes ?? new RemotesStore();
363
+ const listed = wanted ? undefined : store.listRemotes().find((item) => item.isDefault);
364
+ const entry = wanted ? store.getRemote(wanted) : listed?.entry;
365
+ if (!entry) return wanted ? { ok: false } : { ok: true, pin: null };
366
+ const token = store.readToken(entry);
367
+ return {
368
+ ok: true,
369
+ pin: {
370
+ name: wanted || listed?.name || entry.host,
371
+ host: entry.host,
372
+ url: bookmarkToElanousRemote(entry),
373
+ ...(token ? { token } : {}),
374
+ },
375
+ };
376
+ } catch {
377
+ return { ok: false };
378
+ }
379
+ }
380
+
381
+ /**
382
+ * ★ 사람 타이핑 세션 시작 — ref(alias·nickname·id)를 canonical id 로 **한 번** 해석하고
383
+ * bookmark host/token/URL 을 **한 번** 캡처한다. 해석이 확정되지 않으면 세션을 만들지 않는다.
384
+ *
385
+ * 목록은 «한 번의 스냅숏»이다(살아 있는 행만) — 해석 도중 목록이 바뀌어도 이 세션은 흔들리지 않는다.
386
+ */
387
+ export function beginPtyHumanTypingSession(ref: string, options: PtyHumanTypingOptions = {}): PtyHumanTypingResolution {
388
+ const items = (options.manifestDbPath ? listPtyManifestRowsAt(options.manifestDbPath) : listPtyManifestRows())
389
+ .filter((row) => row.alive)
390
+ .map((row) => ({ id: row.id, kind: row.kind, ...(row.nickname ? { nickname: row.nickname } : {}) }));
391
+ const resolution = resolvePtyRef(ref, items);
392
+ if (!resolution.match) {
393
+ const candidates = resolution.candidates.map((item) => item.id);
394
+ debug.log('pty.control', 'typing-ref-unresolved', { ref, reason: resolution.reason, candidates });
395
+ return { ok: false, status: resolution.reason === 'ambiguous' ? 'ambiguous-ref' : 'unresolved-ref', candidates };
396
+ }
397
+ const captured = captureTypingBookmark(options);
398
+ if (!captured.ok) {
399
+ // ⛔ 명시적으로 부른 북마크를 못 읽었으면 fail-closed. (부르지 않은 default 캡처 실패는 로컬로 떨어진다 — 아래)
400
+ if (options.bookmarkName?.trim()) {
401
+ debug.log('pty.control', 'typing-bookmark-unavailable', { ref, bookmark: options.bookmarkName.trim() });
402
+ return { ok: false, status: 'unknown-bookmark', candidates: [] };
403
+ }
404
+ debug.log('pty.control', 'typing-bookmark-skipped', { ref, reason: 'default-bookmark-unreadable' });
405
+ }
406
+ const session: PtyHumanTypingSession = {
407
+ ref,
408
+ ptyId: resolution.match.id,
409
+ resolvedBy: resolution.reason,
410
+ bookmark: captured.ok ? captured.pin : null,
411
+ ...(options.manifestDbPath ? { manifestDbPath: options.manifestDbPath } : {}),
412
+ };
413
+ debug.log('pty.control', 'typing-session-pinned', {
414
+ ref: session.ref,
415
+ ptyId: session.ptyId,
416
+ resolvedBy: session.resolvedBy,
417
+ bookmark: session.bookmark?.name ?? 'local',
418
+ });
419
+ return { ok: true, session };
420
+ }
421
+
274
422
  export async function requestRemotePtyControl(id: string, action: PtyControlAction, payloadOrTimeout?: PtyControlPayload | number, timeoutOrOptions: PtyControlRequestOptions | number = {}): Promise<PtyControlResult> {
275
423
  const payload = typeof payloadOrTimeout === 'number' ? undefined : payloadOrTimeout;
276
424
  const options = typeof timeoutOrOptions === 'number' ? { timeoutMs: timeoutOrOptions } : timeoutOrOptions;
@@ -280,23 +428,48 @@ export async function requestRemotePtyControl(id: string, action: PtyControlActi
280
428
  // 시험만 가상 시각으로 deadline·grace 경계와 cadence 를 결정론적으로 민다(벽시계 판별 없음).
281
429
  const pollNow = options.now ?? Date.now;
282
430
  const pollWait = options.sleep ?? ((ms: number): Promise<void> => Bun.sleep(ms));
283
- const opened = dbAt(options.manifestDbPath);
431
+ // ⭐ 사람 타이핑(input-text/input-key)은 원장에 «쓰기 前» ref 를 canonical id 로 확정한다.
432
+ // 확정 전에는 행을 안 쓴다(fail-closed) — 미해석·모호한 ref 가 남의 PTY 에 닿지 않게.
433
+ const typingAction = action === 'input-text' || action === 'input-key';
434
+ let session = options.typingSession;
435
+ let targetId = id;
436
+ if (typingAction) {
437
+ if (!session) {
438
+ const started = beginPtyHumanTypingSession(id, {
439
+ ...(options.manifestDbPath ? { manifestDbPath: options.manifestDbPath } : {}),
440
+ ...(options.bookmarkName ? { bookmarkName: options.bookmarkName } : {}),
441
+ ...(options.typingBookmark ? { bookmark: options.typingBookmark } : {}),
442
+ });
443
+ if (!started.ok) {
444
+ return started.status === 'ambiguous-ref'
445
+ ? { status: 'denied', reason: 'pty-ref-ambiguous' }
446
+ : started.status === 'unknown-bookmark'
447
+ ? { status: 'denied', reason: 'typing-bookmark-unavailable' }
448
+ : { status: 'unknown-pty' };
449
+ }
450
+ session = started.session;
451
+ }
452
+ targetId = session.ptyId;
453
+ }
454
+ // 세션 핀이 연합 원장을 정했으면 그 원장을 쓴다(재해석·재조회 없음).
455
+ const queuePath = options.manifestDbPath ?? session?.manifestDbPath;
456
+ const opened = dbAt(queuePath);
284
457
  const d = opened.database;
285
458
  try {
286
459
  cleanupStale(d);
287
- const target = options.manifestDbPath
288
- ? d.query('SELECT owner_pid, alive FROM pty_manifest WHERE id=?').get(id) as { owner_pid: number; alive: number } | null
289
- : getPtyManifest(id);
460
+ const target = queuePath
461
+ ? d.query('SELECT owner_pid, alive FROM pty_manifest WHERE id=?').get(targetId) as { owner_pid: number; alive: number } | null
462
+ : getPtyManifest(targetId);
290
463
  if (!target || !target.alive) return { status: 'unknown-pty' };
291
464
  const ownerPid = 'owner_pid' in target ? target.owner_pid : target.ownerPid;
292
465
  const requestId = crypto.randomUUID();
293
466
  const now = Date.now();
294
467
  // ⭐ 요청자의 run anchor 를 요청에 실어 보낸다 — 인가는 **owner 가** 자기 PTY 의 run 과 대조해 내린다
295
468
  // (요청자 자기 신고를 그대로 믿지 않는다는 뜻이 아니라, 판정 지점이 자원 소유자라는 뜻).
296
- d.run(`INSERT INTO pty_control_requests (request_id, pty_id, action, payload_json, actor, requester_run_id, owner_pid, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [requestId, id, action, payload ? JSON.stringify(payload) : null, actor, getHarnessRunId(process.env), ownerPid, 'pending', now, now]);
469
+ d.run(`INSERT INTO pty_control_requests (request_id, pty_id, action, payload_json, actor, requester_run_id, owner_pid, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [requestId, targetId, action, payload ? JSON.stringify(payload) : null, actor, getHarnessRunId(process.env), ownerPid, 'pending', now, now]);
297
470
  // ⭐ 깊은 유휴 감속 중인 owner 를 즉시 깨운다 — 행을 넣은 «뒤» 표식을 남기므로 그 재읽기가 이 행을 본다.
298
471
  // 표식은 그 행의 `ownerPid` «별» 파일이다 — 같은 원장을 공유하는 다른 owner 가 가져가지 못한다.
299
- signalPtyControlWake(requestQueuePath(options), ownerPid);
472
+ signalPtyControlWake(queuePath ?? ptyManifestDbPath(), ownerPid);
300
473
  const readback = (): ControlRow | null => d.query(SELECT_ROW).get(requestId) as ControlRow | null;
301
474
  const del = (): void => { d.run('DELETE FROM pty_control_requests WHERE request_id=?', [requestId]); };
302
475
  const deadline = pollNow() + timeoutMs;
@@ -369,6 +542,8 @@ export interface PtyControlProcessOptions {
369
542
  readonly takeoverTtlMs?: number;
370
543
  /** 깊은 유휴 감속 계단 **전용** 시계(기본 `Date.now`). `now` 는 takeover TTL 시계라 섞지 않는다. */
371
544
  readonly pollClock?: () => number;
545
+ /** 큐를 실제로 다시 읽을 때마다 1회 — 감속 계측용. 생산 진입점은 넘기지 않는다. */
546
+ readonly onQueueRead?: () => void;
372
547
  }
373
548
 
374
549
  function positiveInteger(value: unknown): number | undefined {
@@ -409,17 +584,11 @@ export function processPtyControlRequests(getHandle: (id: string) => PtyControlT
409
584
  // 감속 구간에서는 여기서 «큐를 다시 읽지 않는» 것으로 끝나고, 첫 원격 요청의 표식이 오면 즉시 통과한다.
410
585
  // ⛔ 감속 열쇠는 아래 `processPtyControlRequestsOnce` 가 실제로 여는 원장(`db()` = `ptyManifestDbPath()`)과
411
586
  // 같은 경로다 — 상태는 한 큐, 읽기는 다른 큐로 갈라지지 않는다.
412
- if (!shouldReadControlQueue(ptyManifestDbPath(), (options.pollClock ?? Date.now)())) return Promise.resolve();
587
+ if (!shouldReadControlQueue(ptyManifestDbPath(), (options.pollClock ?? Date.now)(), cadenceLimits(options))) return Promise.resolve();
413
588
  inFlight = processPtyControlRequestsOnce(getHandle, takeover, options).finally(() => { inFlight = null; });
414
589
  return inFlight;
415
590
  }
416
591
 
417
- /** 요청이 실제로 들어간 원장 — 깨어움 표식은 «그 원장의 owner» 가 보는 자리에 남겨야 한다.
418
- * 연합 요청(`manifestDbPath`)이면 그 원장 디렉터리, 내 요청이면 내 원장. */
419
- function requestQueuePath(options: { readonly manifestDbPath?: string }): string {
420
- return options.manifestDbPath ?? ptyManifestDbPath();
421
- }
422
-
423
592
  async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyControlTarget | undefined, takeover: (id: string, actor: 'human') => boolean, options: PtyControlProcessOptions): Promise<void> {
424
593
  const d = db();
425
594
  const now = options.now ?? Date.now;
@@ -23,6 +23,8 @@ import { getSessionCwd } from '../session/working-dir.js';
23
23
  import { buildPtyEnv } from '../agent/identity-env.js';
24
24
  import { getCurrentPtyId } from '../agent/pty-identity.js';
25
25
  import { bunNativePtyAvailable, bunSpawnPty } from './bun-native-pty.js';
26
+ import { ptyAvailable } from './availability.js';
27
+ export { ptyAvailable } from './availability.js';
26
28
  import { resolvePtyRef, canTransitionAccessMode, ptyIdSeparatorIndex, type PtyAccessMode, type PtyTransitionPolicy } from './pty-ref.js';
27
29
  import { resolveWriteDecision, resolveTakeover, type PtyWriteActor } from './pty-write-arbiter.js';
28
30
  import { addPtyManifestOutputBytes, upsertPtyManifest, updatePtyManifestSnapshot, updatePtyManifestNickname, markPtyManifestClosed, removePtyManifest, touchLivePtyManifest } from './pty-manifest.js';
@@ -513,7 +515,7 @@ export function startPty(opts: StartOpts): PtyHandle {
513
515
  set nickname(v: string | undefined) { nickname = v; },
514
516
  setNickname(name: string): void {
515
517
  nickname = name.trim() || undefined;
516
- if (PTY_MANIFEST_ENABLED) updatePtyManifestNickname(id, nickname, Date.now());
518
+ if (ptyManifestEnabled()) updatePtyManifestNickname(id, nickname, Date.now());
517
519
  },
518
520
  get accessMode() { return accessMode; },
519
521
  set accessMode(v: PtyAccessMode) { accessMode = v; },
@@ -718,7 +720,7 @@ export function startPty(opts: StartOpts): PtyHandle {
718
720
  catch (error) { debug.log('pty.record', 'tap-error', { ptyId: id, error: String(error) }); }
719
721
  emitPtyEvent({ type: 'output', id, chunk });
720
722
  // ★ 크로스-프로세스 관측(2026-07-23) — throttled 스냅샷을 공유 매니페스트에(데몬 PWA 유니온). getter 라 throttle 통과 시에만 snapshot().
721
- if (PTY_MANIFEST_ENABLED) {
723
+ if (ptyManifestEnabled()) {
722
724
  pendingManifestOutputBytes += Buffer.byteLength(chunk, 'utf8');
723
725
  const now = Date.now();
724
726
  // ⛔⭐ throttle 이 막은 출력도 «반드시» 실린다 — 안 그러면 마지막 버스트 뒤 조용해진 PTY 의
@@ -741,7 +743,7 @@ export function startPty(opts: StartOpts): PtyHandle {
741
743
  try { autoStopPtyRecording(id); }
742
744
  catch (error) { debug.log('pty.record', 'auto-stop-error', { ptyId: id, error: String(error) }); }
743
745
  emitPtyEvent({ type: 'exit', id, exitCode: code, signal });
744
- if (PTY_MANIFEST_ENABLED) {
746
+ if (ptyManifestEnabled()) {
745
747
  const now = Date.now();
746
748
  // Manifest closure and output durability are separate: a closed row keeps retrying trailing bytes until committed.
747
749
  manifestOutputFlush.close(now);
@@ -754,7 +756,7 @@ export function startPty(opts: StartOpts): PtyHandle {
754
756
  // ★ 크로스-프로세스 관측 — startPty 를 공유 매니페스트에 등록(다른 프로세스 데몬이 /v1/terminals 로 봄). fail-soft.
755
757
  // ⚠️ 테스트 런(NODE_ENV=test·bun test)은 skip — 테스트가 띄우는 임시 셸(self-implement gate·CI·수동 bun test)이
756
758
  // 운영 매니페스트(~/.elanous/pty)로 새어들어 관측소를 오염시키던 근본 차단(격리). 실 세션(NODE_ENV≠test)만 등록.
757
- if (PTY_MANIFEST_ENABLED) {
759
+ if (ptyManifestEnabled()) {
758
760
  const childSpaceId = opts.env?.ELANOUS_HARNESS_SPACE_ID;
759
761
  const childParentPtyId = opts.env?.ELANOUS_PARENT_PTY_ID ?? getCurrentPtyId();
760
762
  const childController = opts.env?.ELANOUS_CONTROLLER?.trim();
@@ -800,8 +802,24 @@ export function startPty(opts: StartOpts): PtyHandle {
800
802
  return handle;
801
803
  }
802
804
 
803
- /** 공유 PTY 매니페스트 등록 활성 여부 — 테스트 런(bun test=NODE_ENV=test)은 운영 매니페스트 오염 방지 위해 off. */
804
- const PTY_MANIFEST_ENABLED = process.env.NODE_ENV !== 'test';
805
+ /** 공유 PTY 매니페스트 등록 활성 여부 — 테스트 런(bun test=NODE_ENV=test)은 운영 매니페스트 오염 방지 위해 off.
806
+ *
807
+ * ⭐ 자리(seat) 수명주기는 이 기록자에서만 원장에 실린다 — spawned/exited 사건의 seat·
808
+ * 누적 outputBytesTotal·exitCode 를 남기는 곳이 `upsertPtyManifest`/`markPtyManifestClosed` 이기
809
+ * 때문이다. 그런데 NODE_ENV 판정만 있으면 **격리 test 우주에서는 이 경로를 한 번도 지날 수 없어**
810
+ * 자리 수명주기가 실행 증거를 가질 수 없다(합성 manifest 직접 호출만 남는다 — 완료 경계가 금지).
811
+ * ⇒ 판정을 호출 시점 함수로 두고, 격리 우주(전용 `ELANOUS_STATE_DIR`·전용 manifest db)가 **명시적으로**
812
+ * 켤 수 있는 seam 을 둔다. override 가 없으면 종전과 같은 NODE_ENV 판정이라 운영 동작은 불변이다. */
813
+ let _ptyManifestEnabledOverride: boolean | null = null;
814
+
815
+ /** 테스트 전용 seam — 격리 우주에서 생산 기록 경로를 그대로 지나기 위해 켠다. null = NODE_ENV 판정 복귀. */
816
+ export function setPtyManifestEnabledForTesting(enabled: boolean | null): void {
817
+ _ptyManifestEnabledOverride = enabled;
818
+ }
819
+
820
+ function ptyManifestEnabled(): boolean {
821
+ return _ptyManifestEnabledOverride ?? process.env.NODE_ENV !== 'test';
822
+ }
805
823
 
806
824
  // ★ 라이브 PTY 하트비트(2026-07-23) — 소유 프로세스가 자기 라이브 PTY 의 updated_at 을 주기 갱신해
807
825
  // "살아있음"을 증명한다. 데몬의 stale reap 이 하트비트 끊긴 유령만 제거하도록(pid 재활용 견고). unref 로 프로세스 종료 방해 X.
@@ -904,7 +922,7 @@ export function renamePty(id: string, nickname: string): boolean {
904
922
  // 별명은 manifest 행에만 산다. 여기서 받지 않으면 IPC rename 이 그 행에 `unknown-pty` 로 진다.
905
923
  const target = controlTargets.get(id);
906
924
  if (!target || !target.isAlive()) return false;
907
- if (PTY_MANIFEST_ENABLED) updatePtyManifestNickname(id, nickname.trim() || undefined, Date.now());
925
+ if (ptyManifestEnabled()) updatePtyManifestNickname(id, nickname.trim() || undefined, Date.now());
908
926
  debug.log('pty.rename', 'control-target-renamed', { ptyId: id, nickname: nickname.trim() });
909
927
  return true;
910
928
  }
@@ -1012,14 +1030,6 @@ export function killNonDetached(): number {
1012
1030
  return killed;
1013
1031
  }
1014
1032
 
1015
- /** Probe-compatible. Under Bun the native PTY (Bun.spawn terminal) is
1016
- * used instead of node-pty, so PTY is available even if node-pty can't
1017
- * resolve. Under node we still require node-pty. */
1018
- export function ptyAvailable(): boolean {
1019
- if (bunNativePtyAvailable()) return true;
1020
- try { require.resolve('node-pty'); return true; } catch { return false; }
1021
- }
1022
-
1023
1033
  // ─── Adapter wiring ──────────────────────────────────────────────
1024
1034
 
1025
1035
  let cachedSpawn: ((opts: StartOpts) => PtyAdapter) | null | undefined = undefined;