elanous 0.2.37 → 0.2.38

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 (588) 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/{8kITumG9GAZ1LwT9POrAR → RrjXTwz-urRAbChP1bX02}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{2002-a43a3f380df873ec.js → 1026-44010f405704050c.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +27 -0
  6. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.js → 1632.7d87f998e714bede.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/{4937-28d437999b77c9dd.js → 1923-5c1695332240246a.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +148 -0
  14. package/apps/pwa/out/_next/static/chunks/2104.70e086d5174a4736.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +93 -0
  18. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +104 -0
  19. package/apps/pwa/out/_next/static/chunks/{3199.6a1a9b0e6cd01dc6.js → 2415.738b777642a02233.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 3086.fb14b60ce98b53d3.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/3124-561f7f037943cde2.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +24 -0
  31. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{2283.edd9627b7bdfb546.js → 3291.f6c1005387d514bd.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +36 -0
  34. package/apps/pwa/out/_next/static/chunks/{6877-84d47b7e85d0c41e.js → 3341-f09b9efbd7a82f70.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +287 -0
  38. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.js → 3528.e4b8ab70d339f965.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4199-f7c6eb40cd0322f8.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +32 -0
  57. package/apps/pwa/out/_next/static/chunks/{4036.d54e55e1ebf5acdc.js → 4804.6012b5cd33c22792.js} +2 -2
  58. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +79 -0
  60. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6819.be5c9c4d67f22922.js → 5203.51e5d8b5f1dcfe53.js} +16 -16
  65. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{757-4fbaf50942b8c424.js → 5255-1b60d50eabe9f057.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +286 -0
  68. package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.js → 5307.d7328020227880c2.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +8 -0
  73. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{5046.7fd5cbd859299448.js → 5638.107314dc479e2f37.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6142.913b44e260a3f925.js +64 -0
  80. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6493.27ad77de7aac7966.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/{1224.2ceca6c180d5130b.js → 7000.28157393caaf5343.js} +1 -1
  88. package/apps/pwa/out/_next/static/chunks/{6745-5a63492933959dd9.js → 7161-8f22db3ec5ed005e.js} +3 -3
  89. package/apps/pwa/out/_next/static/chunks/{2479-fe7e188bd9402d14.js → 7311-60a7ea80d23c7521.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{5952.294fc574a8625184.js → 7488.966b116789f3d41a.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7524.ce973525d30b3d52.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +77 -0
  95. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 7628.6b16863ac3972333.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 7954.4f7a8832663ee979.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{4931.95cc6dbd230774ca.js → 8019.21ca554a821dad01.js} +16 -16
  102. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{2375.bf364c85dbb6f085.js → 8487.291666583bebe640.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{4383.18e5c54db3a22c88.js → 8879.ac06755bcf3e44a1.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +149 -0
  111. package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 8911.bf5e712acb25fb6c.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/{58edce7d.f1b0c72acf13b123.js → 8994d93e.33ba491f95345fc2.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → 89d6c04f-6b8ab341748e468a.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +226 -0
  116. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +24 -0
  117. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +2 -0
  121. package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.js → 9fe1b809.738da85c8b17e3fb.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-866aac5ff226a7f3.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/{page-5c112c6d7c33656e.js → page-c348a3959c5b5fc6.js} +1 -1
  140. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-88a1edbff62eaf1d.js → page-d1d1210f99f620ae.js} +1 -1
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/{page-b9af2ac1c4737ce8.js → page-7f569e533ddeecba.js} +1 -1
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/{page-fb9e639c107f5f72.js → page-a9d9a3e66459c1e0.js} +1 -1
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → b7459770.6539b11860eb8a9c.js} +7 -7
  174. package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b7478fef.5917716286213fcc.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/{4337e36d.f42c3b391b3d8f20.js → bb6987f9.3647e1a23b0e3217.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/de8b930d.d94c0f42acf807fc.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.js → eaad0cba.771200940c529df7.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/graphs/release/recipes.yaml +9 -0
  278. package/graphs/release/release-loop.yaml +26 -18
  279. package/package.json +1 -1
  280. package/scripts/ask-op-inbox-once.ts +17 -0
  281. package/scripts/brand/check.ts +13 -4
  282. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  283. package/scripts/gate-0226-failure-census.ts +39 -0
  284. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  285. package/scripts/provision-export-redactions.ts +15 -0
  286. package/scripts/public-copy-lint.ts +122 -0
  287. package/scripts/public-export.ts +69 -2
  288. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  289. package/scripts/ratchets/train-side-invariants.sh +7 -1
  290. package/scripts/release-loop/cut-branch.ts +61 -12
  291. package/scripts/release-loop/gate-node.ts +161 -25
  292. package/scripts/release-loop/gate-partial.ts +82 -3
  293. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  294. package/scripts/release-loop/gate-radius-live.ts +4 -2
  295. package/scripts/release-loop/resume-cap.ts +2 -1
  296. package/scripts/release-loop/resume-release.ts +297 -8
  297. package/scripts/release-loop/resume.ts +13 -5
  298. package/scripts/release-loop/traffic-node.ts +12 -4
  299. package/scripts/release-loop/traffic-transition.ts +53 -13
  300. package/scripts/release-loop/version-node.ts +29 -4
  301. package/scripts/ux-sim.ts +1 -1
  302. package/scripts/video-pipeline.ts +2 -2
  303. package/src/acp/core-turn-bridge.ts +6 -1
  304. package/src/agent/run-context.ts +1 -1
  305. package/src/agent/task-notification.ts +3 -1
  306. package/src/agent-substrate/review-observation.ts +10 -0
  307. package/src/agent-substrate/self-review-cli.ts +195 -27
  308. package/src/auto-research/question-ladder-contract.ts +137 -0
  309. package/src/auto-research/research-turn.ts +134 -0
  310. package/src/autopilot/discovery/doc-lint.ts +1 -1
  311. package/src/bots/screen-probe.ts +1 -1
  312. package/src/capture/tui-self-report.ts +10 -2
  313. package/src/chat/index.ts +1 -0
  314. package/src/chat/tool-render/dispatch.ts +8 -1
  315. package/src/cli/guardian-cli.ts +3 -1
  316. package/src/cli/intake-cli.ts +48 -12
  317. package/src/cli/lesson-cli.ts +69 -9
  318. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  319. package/src/cli/pr-land-refusal.ts +1 -1
  320. package/src/cli/pty-takeover-cli.ts +58 -5
  321. package/src/cli/release-checklist-read-cli.ts +5 -2
  322. package/src/cli/release-cli.ts +47 -9
  323. package/src/cli/review-carry.ts +77 -0
  324. package/src/cli/self-update.ts +1 -1
  325. package/src/cli/tasks-card-show.ts +31 -1
  326. package/src/cli/tasks-cli.ts +62 -23
  327. package/src/cli/tasks-read-cli.ts +13 -5
  328. package/src/context-bus/context-now.ts +86 -2
  329. package/src/core-turn/run-core-turn.ts +9 -2
  330. package/src/core-turn/types.ts +3 -0
  331. package/src/dashboard/index.ts +18 -17
  332. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  333. package/src/dashboard/side-basic-runtime.ts +61 -0
  334. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
  335. package/src/dashboard/term-slash-runtime.ts +2 -0
  336. package/src/dashboard/turn-preamble.ts +28 -4
  337. package/src/domains/guardian-tick.ts +9 -0
  338. package/src/git-fs/watcher.ts +27 -22
  339. package/src/git-fs/worktree.ts +19 -3
  340. package/src/graph-runner/graph-grow.ts +37 -9
  341. package/src/graph-runner/runner.ts +17 -2
  342. package/src/grok/credential.ts +107 -36
  343. package/src/hq/fence-wrapper.ts +1 -1
  344. package/src/hq/transfer.ts +1 -1
  345. package/src/index.ts +44 -14
  346. package/src/intake-plane/collect-telegram-saved.ts +54 -5
  347. package/src/interactive-terminal-modal.ts +3 -0
  348. package/src/keybindings.ts +17 -22
  349. package/src/llm/provider-credentials.ts +1 -1
  350. package/src/llm-tool-schema.ts +20 -0
  351. package/src/llm.ts +81 -11
  352. package/src/loops/orchestrator/inbox-once.ts +28 -0
  353. package/src/loops/orchestrator/inbox.ts +130 -1
  354. package/src/loops/orchestrator/tick.ts +6 -3
  355. package/src/maturity/feature-maturity.ts +1 -0
  356. package/src/nexus/api/channel-ask-op.ts +96 -0
  357. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  358. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  359. package/src/nexus/api/terminals.ts +28 -6
  360. package/src/patents/ledger.ts +18 -1
  361. package/src/preview/terminal.ts +4 -2
  362. package/src/prompt-cache/anthropic.ts +2 -0
  363. package/src/prompt-enhance/enhance.ts +5 -0
  364. package/src/pty-shell/pty-manifest.ts +16 -2
  365. package/src/release-loop/gate-shards.ts +61 -0
  366. package/src/release-loop/light-rc.ts +7 -4
  367. package/src/release-loop/rehearsal.ts +1 -1
  368. package/src/repl/index.ts +10 -0
  369. package/src/research/axis-fanout.ts +133 -0
  370. package/src/research/edge-decision.ts +88 -0
  371. package/src/research/output-router.ts +127 -0
  372. package/src/research-bridge/format.ts +16 -1
  373. package/src/research-bridge/index.ts +1 -0
  374. package/src/research-bridge/invoke.ts +41 -5
  375. package/src/self-dev/decompose.ts +45 -9
  376. package/src/self-dev/draft-residue.ts +221 -2
  377. package/src/self-dev/draft-sweep.ts +29 -16
  378. package/src/self-dev/orchestrate.ts +1 -0
  379. package/src/self-dev/run-supervisor.ts +22 -7
  380. package/src/self-dev/shard-run.ts +260 -3
  381. package/src/self-implement/comment-only-source.ts +54 -0
  382. package/src/self-implement/doctor-visit.ts +25 -0
  383. package/src/self-implement/gate-artifacts.ts +2 -2
  384. package/src/self-implement/gate-baseline.ts +44 -9
  385. package/src/self-implement/gate-cli.ts +151 -86
  386. package/src/self-implement/gate-failure-signature.ts +44 -0
  387. package/src/self-implement/gate-remote.ts +2 -0
  388. package/src/self-implement/goal-author.ts +74 -3
  389. package/src/self-implement/goal-doc/section.ts +22 -0
  390. package/src/self-implement/goal-supervisor-fill.ts +38 -4
  391. package/src/self-implement/knowhow-pack.ts +120 -7
  392. package/src/self-implement/l8-merge-queue.ts +198 -32
  393. package/src/self-implement/off-diff-evidence.ts +23 -0
  394. package/src/self-implement/orchestrator.ts +55 -12
  395. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  396. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  397. package/src/self-implement/premise-review.ts +7 -5
  398. package/src/self-implement/run-ledger.ts +258 -0
  399. package/src/self-implement/seams.ts +33 -10
  400. package/src/self-implement/self-implement-cli.ts +26 -2
  401. package/src/session/channel-ask-op-envelope.ts +36 -0
  402. package/src/session/channel-op-reply-route.ts +200 -0
  403. package/src/session/chat.ts +3 -0
  404. package/src/session/index.ts +2 -0
  405. package/src/session-runtime/index.ts +9 -22
  406. package/src/skills/runner.ts +7 -3
  407. package/src/skills/tools/dev-harness.ts +2 -2
  408. package/src/skills/tools/schedule-wakeup.ts +1 -6
  409. package/src/status/bar.ts +3 -3
  410. package/src/storage/file-lock.ts +17 -4
  411. package/src/task-agent/adopt-pr.ts +63 -2
  412. package/src/task-agent/evidence-command-normalize.ts +42 -0
  413. package/src/task-agent/export-redactions-provision.ts +43 -0
  414. package/src/task-agent/parent-host.ts +59 -12
  415. package/src/task-agent/repair-cycle.ts +67 -8
  416. package/src/task-agent/repair-worker.ts +37 -1
  417. package/src/task-agent/task-hand.ts +98 -10
  418. package/src/task-agent/tier-split.ts +37 -3
  419. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +31 -4
  420. package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
  421. package/src/task-orchestrator/surfaces/self-implement-pod.ts +126 -48
  422. package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
  423. package/src/terminal/session-registry.ts +1 -0
  424. package/src/terminal/terminal-modal-router.ts +156 -0
  425. package/src/tool-hints/gate.ts +6 -4
  426. package/src/tool-hints/signals.ts +33 -1
  427. package/src/tui/chat/background-job-status.ts +8 -2
  428. package/src/tui/entry.ts +469 -31
  429. package/src/tui/sidetab/attach.ts +304 -0
  430. package/src/tui/sidetab/list.ts +176 -0
  431. package/src/tui/sidetab/nl-tool.ts +136 -0
  432. package/src/tui/slash/resume-command.ts +23 -0
  433. package/src/tui/slash/resume.ts +3 -23
  434. package/src/tui/slash/term-next.ts +2 -1
  435. package/src/tui-client/local-chat-turn.ts +29 -8
  436. package/src/user-config.ts +11 -2
  437. package/src/ux-sim/fake-llm.ts +11 -5
  438. package/src/ux-sim/next-tui-seat-scenarios.ts +53 -1
  439. package/src/version/packed-revision.json +1 -1
  440. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
  451. package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
  454. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
  458. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/3578.4e9f9948a9a6f2f4.js +0 -2
  463. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
  465. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
  467. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
  468. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/4313.76f232c304a15bde.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/4725-34bed25720cc326b.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
  477. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
  479. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
  486. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
  487. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
  490. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
  493. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
  496. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
  508. package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
  510. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
  513. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
  517. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
  525. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
  527. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/live/page-3337c6a1328c2674.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/term/page-ac2c1e6169cfce57.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
  586. package/scripts/migrate-monad-to-elanous.ts +0 -195
  587. package/scripts/rebrand-elanous.ts +0 -242
  588. /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → RrjXTwz-urRAbChP1bX02}/_ssgManifest.js +0 -0
@@ -70,13 +70,26 @@ export function acquireLockSync(lockPath: string, opts: LockOpts = {}): ReleaseL
70
70
  for (let attempt = 0; attempt < maxTries; attempt += 1) {
71
71
  try {
72
72
  const fd = openSync(lockPath, 'wx');
73
- try { writeSync(fd, `${process.pid}\n`); }
74
- catch { /* metadata only · not fatal */ }
75
- const acquired = fstatSync(fd);
73
+ try {
74
+ writeSync(fd, `${process.pid}\n`);
75
+ } catch (writeErr) {
76
+ // 보유자 PID 를 못 쓰면 holderIsDead·onWait 독자 계약이 깨진다 — 방금 'wx' 로 만든 파일을 정리하고 올린다.
77
+ try { closeSync(fd); } catch { /* ignore */ }
78
+ try { unlinkSync(lockPath); } catch { /* ignore */ }
79
+ throw writeErr;
80
+ }
81
+ // ⭐ 소유 증명은 파일 «내용»이 아니라 «정체»다 — 내용은 보유자 PID 한 줄 계약(test/storage-file-lock ·
82
+ // goal-author supersession 잠금)이라 구분 토큰을 심을 수 없고, rm+즉시 재생성은 inode 번호를
83
+ // 재사용하므로 inode 만으로는 교체를 못 가린다(실측). dev·ino·mtimeNs 셋이 같을 때만 우리가 만든
84
+ // 그 파일로 본다 — 재사용된 inode 도 새 mtime 을 가지므로 교체 자물쇠는 mtimeNs 에서 갈린다.
85
+ const acquired = fstatSync(fd, { bigint: true });
76
86
  closeSync(fd);
77
87
  return () => {
78
88
  try {
79
- if (statSync(lockPath).ino === acquired.ino) unlinkSync(lockPath);
89
+ const current = statSync(lockPath, { bigint: true });
90
+ if (current.dev === acquired.dev && current.ino === acquired.ino && current.mtimeNs === acquired.mtimeNs) {
91
+ unlinkSync(lockPath);
92
+ }
80
93
  } catch { /* stale recovery or replacement won the path */ }
81
94
  };
82
95
  } catch (err) {
@@ -3,7 +3,7 @@ import { randomBytes } from 'node:crypto';
3
3
  import { loadRunLedger, runLedgerDir, type RunLedgerEntry } from '../self-implement/run-ledger.js';
4
4
  import { remoteLedgerMirrorDir } from './parent-host.js';
5
5
  import { prodInstanceRoot } from '../instance/resolve.js';
6
- import { cardPrNumber, updateTaskCard, type TaskCard } from './task-hand.js';
6
+ import { cardPrNumber, updateTaskCard, updateTaskCardsAtomically, type TaskCard } from './task-hand.js';
7
7
 
8
8
  export interface AdoptPrView {
9
9
  number: number; url: string; state: string; baseRefName: string; headRefOid: string;
@@ -20,6 +20,9 @@ export interface AdoptPrInput {
20
20
  unlinkedTerminal?: boolean;
21
21
  observedRun?: { runId?: string; runChildId?: string; parentHost?: string; launchId?: string };
22
22
  observedChecklist?: { id: string; version: string; status: string; cardVersion?: string };
23
+ /** --rebind: source snapshot and terminal proof (computed before taking the state lock). */
24
+ rebindSource?: { card: Pick<TaskCard, 'id' | 'status' | 'runId' | 'runChildId' | 'launchId' | 'parentHost' | 'checklistId' | 'checklistVersion' | 'pr'>;
25
+ terminalRunEvidence: boolean };
23
26
  checklistAtWrite?: () => { id: string; status: string } | undefined;
24
27
  }
25
28
 
@@ -60,7 +63,7 @@ export function adoptedRunTerminal(card: TaskCard, pr: AdoptPrView,
60
63
  }
61
64
 
62
65
  /** The PR is read from the selected repository before this call; rejudge checks it again before every live move. */
63
- export function adoptExistingPr(input: AdoptPrInput): { card: TaskCard; created: boolean; changed: boolean } {
66
+ export function adoptExistingPr(input: AdoptPrInput): { card: TaskCard; created: boolean; changed: boolean; previousCardId?: string } {
64
67
  const { pr } = input;
65
68
  const slug = pr.url.match(/^https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/\d+\/?$/)?.[1];
66
69
  if (!Number.isSafeInteger(pr.number) || pr.number < 1 || pr.state !== 'OPEN' || pr.baseRefName !== 'main'
@@ -68,6 +71,11 @@ export function adoptExistingPr(input: AdoptPrInput): { card: TaskCard; created:
68
71
  || Number(pr.url.match(/\/pull\/(\d+)/)?.[1]) !== pr.number
69
72
  || !/^[a-f0-9]{40}$/i.test(pr.headRefOid)) throw new Error('입양할 PR은 현재 저장소의 OPEN/main PR 번호·URL·head SHA40이어야 한다');
70
73
  if ((input.cardId === undefined) === (input.checklist === undefined)) throw new Error('--card 또는 --checklist/--version 중 하나만 준다');
74
+ if (input.rebindSource) {
75
+ if (input.cardId || !input.checklist || !input.version || input.checklist.version !== input.version)
76
+ throw new Error('--rebind는 --checklist와 같은 --version을 지정하고 --card는 생략한다');
77
+ return rebindExistingPr(input, input.rebindSource);
78
+ }
71
79
  if (input.cardId && !input.version) throw new Error('기존 카드는 체크리스트 판을 확정해야 한다');
72
80
  if (input.checklist && (!input.checklist.id || !input.checklist.title || !input.checklist.version
73
81
  || ['green', 'done'].includes(input.checklist.status))) throw new Error('입양할 체크리스트 칸은 미완 판·id·제목이어야 한다');
@@ -138,3 +146,56 @@ export function adoptExistingPr(input: AdoptPrInput): { card: TaskCard; created:
138
146
  if (!result) throw new Error(`카드 쓰기 실패: ${id}`);
139
147
  return { card: result, created, changed };
140
148
  }
149
+
150
+ function rebindExistingPr(input: AdoptPrInput, sourceSnapshot: NonNullable<AdoptPrInput['rebindSource']>)
151
+ : { card: TaskCard; created: true; changed: true; previousCardId: string } {
152
+ const { pr, checklist, version } = input;
153
+ if (!checklist || !version) throw new Error('--rebind 대상 체크리스트 판이 없다');
154
+ const at = (input.now ?? new Date()).toISOString();
155
+ const id = `ta-${at.slice(0, 10).replaceAll('-', '')}-${randomBytes(3).toString('hex')}`;
156
+ const replacements = updateTaskCardsAtomically(input.statePath, (tasks) => {
157
+ if (tasks[id]) throw new Error(`새 카드 id 충돌: ${id}`);
158
+ const matches = Object.values(tasks).filter((card) => cardPrNumber(card) === pr.number);
159
+ if (matches.length !== 1) throw new Error(matches.length
160
+ ? `PR #${pr.number}가 여러 카드에 묶였다 — 임의로 rebind하지 않는다`
161
+ : `PR #${pr.number}가 기존 카드에 묶이지 않았다 — --rebind 대상 없음`);
162
+ const current = matches[0]!;
163
+ const observed = sourceSnapshot.card;
164
+ if (current.id !== observed.id || current.status !== observed.status || current.runId !== observed.runId
165
+ || current.runChildId !== observed.runChildId || current.launchId !== observed.launchId
166
+ || current.checklistId !== observed.checklistId || current.checklistVersion !== observed.checklistVersion
167
+ || current.parentHost?.host !== observed.parentHost?.host || cardPrNumber(current) !== cardPrNumber(observed)
168
+ || (typeof current.pr === 'object' ? current.pr.url : undefined) !== (typeof observed.pr === 'object' ? observed.pr.url : undefined))
169
+ throw new Error(`rebind 중 원본 카드가 바뀌었다: ${observed.id}`);
170
+ if (typeof current.pr === 'object' && current.pr.url && current.pr.url !== pr.url)
171
+ throw new Error(`원본 카드의 PR URL이 조회 결과와 다르다: ${current.id}`);
172
+ if (current.status !== 'failed' && (current.checklistVersion === version && current.checklistId === checklist.id))
173
+ throw new Error(`같은 판·칸의 failed 카드만 rebind할 수 있다: ${current.id}`);
174
+ if (current.status !== 'failed' && (current.status !== 'launched' || sourceSnapshot.terminalRunEvidence !== true))
175
+ throw new Error(`원본 런 종결·정확한 PR 근거가 없다: ${current.id}`);
176
+ if (Object.values(tasks).some((card) => card.id !== current.id && card.status === 'launched' && card.taLand === true
177
+ && cardPrNumber(card) !== undefined && card.checklistId === checklist.id && card.checklistVersion === version))
178
+ throw new Error(`칸 ${checklist.id}에 이미 TA 착지 후보 카드가 있다`);
179
+ const liveCell = input.checklistAtWrite?.();
180
+ if (input.checklistAtWrite && (!liveCell || liveCell.id !== checklist.id || ['green', 'done'].includes(liveCell.status)))
181
+ throw new Error(`입양 중 체크리스트 칸이 바뀌거나 완료됐다: ${checklist.id}`);
182
+
183
+ const { pr: _pr, adoptedPr: _adoptedPr, prTerminal: _prTerminal, taLand: _taLand, ...oldCard } = current;
184
+ const released: TaskCard = { ...oldCard, history: [...current.history, {
185
+ at, event: 'pr-rebound-out', pr: pr.number, head: pr.headRefOid,
186
+ detail: `PR 결속을 ${version}/${checklist.id} 새 카드 ${id}로 이동 · ${pr.url}`,
187
+ }] };
188
+ const adopted: TaskCard = {
189
+ id, text: checklist.title, checklistId: checklist.id, checklistVersion: version,
190
+ createdAt: at, status: 'launched', taLand: true, pr: { number: pr.number, url: pr.url },
191
+ adoptedPr: { pr: pr.number, url: pr.url, head: pr.headRefOid, at },
192
+ history: [{ at, event: 'pr-adopted', pr: pr.number, head: pr.headRefOid,
193
+ detail: `기존 PR rebind · 원본 카드 ${current.id} · ${pr.url} · 새 구현 발사 0` }],
194
+ };
195
+ return [released, adopted];
196
+ });
197
+ const card = replacements?.find((replacement) => replacement.id === id);
198
+ const previous = replacements?.find((replacement) => replacement.id !== id);
199
+ if (!card || !previous) throw new Error('PR rebind 원자 갱신 결과가 없다');
200
+ return { card, created: true, changed: true, previousCardId: previous.id };
201
+ }
@@ -0,0 +1,42 @@
1
+ import { linesOutsideFencedCode, validateGoalDoneEvidenceCommand } from '../self-implement/goal-author.js';
2
+
3
+ const EVIDENCE_LINE = /^(\s*(?:[-*]\s*)?완료 경계 증거 명령\s*:\s*)(.*?)(\s*)$/;
4
+
5
+ /** Remove known result annotations from an evidence command, preserving every other line. */
6
+ export function normalizeEvidenceCommandLines(document: string): { text: string; warnings: string[]; unrecognized: string[] } {
7
+ const warnings: string[] = [];
8
+ const unrecognized: string[] = [];
9
+ const replacements: Array<{ start: number; old: string; next: string }> = [];
10
+ for (const line of linesOutsideFencedCode(document)) {
11
+ const match = EVIDENCE_LINE.exec(line.text);
12
+ if (!match) continue;
13
+ const original = match[2].trim();
14
+ if (!original) continue;
15
+ let candidate = original.replace(/\s*(?:→|->)\s*0\s+fail\s*$/i, '')
16
+ .replace(/\s*·\s*typecheck\s+PASS\s*$/i, '').trim();
17
+ // Some cards have both annotations; peel them in either order.
18
+ candidate = candidate.replace(/\s*(?:→|->)\s*0\s+fail\s*$/i, '')
19
+ .replace(/\s*·\s*typecheck\s+PASS\s*$/i, '').trim();
20
+ if (candidate.startsWith('`') && candidate.endsWith('`') && candidate.length > 2)
21
+ candidate = candidate.slice(1, -1).trim();
22
+ if (candidate === original) {
23
+ if (/[`→]|->|·\s*typecheck\b/i.test(original)) {
24
+ warnings.push(`완료 경계 증거 명령 정규화 불가: ${original}`);
25
+ unrecognized.push(original);
26
+ }
27
+ continue;
28
+ }
29
+ // An unrecognized decoration is never silently converted into a shell command.
30
+ if (!validateGoalDoneEvidenceCommand(candidate).command) {
31
+ warnings.push(`완료 경계 증거 명령 정규화 불가: ${original}`);
32
+ unrecognized.push(original);
33
+ continue;
34
+ }
35
+ replacements.push({ start: line.start, old: line.text, next: `${match[1]}${candidate}${match[3]}` });
36
+ warnings.push(`완료 경계 증거 명령 정규화: ${original} → ${candidate}`);
37
+ }
38
+ let text = document;
39
+ for (const replacement of replacements.reverse())
40
+ text = text.slice(0, replacement.start) + replacement.next + text.slice(replacement.start + replacement.old.length);
41
+ return { text, warnings, unrecognized };
42
+ }
@@ -0,0 +1,43 @@
1
+ import { lstatSync, readFileSync } from 'node:fs';
2
+ import { loadPrivateRedactions, privateRedactionsPath } from '../../scripts/public-export.js';
3
+ import { defaultSshRunner, type SshRunner } from './parent-host.js';
4
+ import { shellQuote } from './task-hand.js';
5
+
6
+ const ALLOWED_HOSTS = new Set(['node-b', 'elangram-wsl', 'host-e-wsl']);
7
+
8
+ /** Give a train host the same private list that release export-check reads on HQ.
9
+ * The list travels only over SSH stdin and is installed atomically at mode 0600.
10
+ * A missing or unreadable list is a failed preflight, never a weaker leak check. */
11
+ export function provisionExportRedactions(
12
+ host: string,
13
+ sourcePath = privateRedactionsPath(),
14
+ ssh: SshRunner = defaultSshRunner,
15
+ ): void {
16
+ if (!ALLOWED_HOSTS.has(host)) throw new Error('export redactions host not allowed');
17
+ let payload: string;
18
+ try {
19
+ const stat = lstatSync(sourcePath);
20
+ if (!stat.isFile() || (stat.mode & 0o077) !== 0 || stat.size === 0 || stat.size > 1_048_576) {
21
+ throw new Error('source is not a private regular file');
22
+ }
23
+ if (!loadPrivateRedactions(sourcePath)?.length) throw new Error('source has no redaction entries');
24
+ payload = readFileSync(sourcePath, 'utf8');
25
+ if (payload.includes('\0')) throw new Error('source contains NUL');
26
+ } catch {
27
+ throw new Error('export redactions source unavailable or invalid');
28
+ }
29
+
30
+ const code = [
31
+ 'const fs=require("node:fs"),path=require("node:path"),crypto=require("node:crypto");',
32
+ // Remote SSH execution has no repository resolver module. Match privateRedactionsPath():
33
+ // ELANOUS_EXPORT_REDACTIONS first, then the remote shell HOME default (OP #40040).
34
+ 'const home=process.env.HOME?.trim(),override=process.env.ELANOUS_EXPORT_REDACTIONS?.trim();',
35
+ 'const file=override||(home?path.join(home,".elanous","export-redactions.tsv"):"");if(!file||!path.isAbsolute(file))process.exit(2);const dir=path.dirname(file);',
36
+ 'const bytes=fs.readFileSync(0);if(!bytes.length||bytes.length>1048576||bytes.includes(0))process.exit(2);',
37
+ 'fs.mkdirSync(dir,{recursive:true,mode:0o700});fs.chmodSync(dir,0o700);',
38
+ 'const temp=file+"."+process.pid+"."+crypto.randomBytes(6).toString("hex")+".tmp";',
39
+ 'try{fs.writeFileSync(temp,bytes,{mode:0o600,flag:"wx"});fs.chmodSync(temp,0o600);fs.renameSync(temp,file)}catch{try{fs.rmSync(temp,{force:true})}catch{};process.exit(3)}',
40
+ ].join('');
41
+ const result = ssh(host, `umask 077; bun -e ${shellQuote(code)}`, 20_000, payload);
42
+ if (result.status !== 0) throw new Error(`export redactions provision failed (ssh rc=${result.status ?? 'unknown'})`);
43
+ }
@@ -44,6 +44,8 @@ export const PARENT_HOST_ENV = 'ELANOUS_TA_PARENT_HOST';
44
44
  const DEFAULT_REMOTE_ELANOUS = '$HOME/.local/share/elanous/bin/elanous';
45
45
  const DEFAULT_REMOTE_CONFIG_DIR = '$HOME/.elanous';
46
46
  const HOST_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]{0,127}$/;
47
+ /** A parent can wait for a child for tens of minutes; the two-minute HTTP refresh floor is too short here. */
48
+ export const PARENT_CHILD_CREDENTIAL_MIN_REMAINING_MS = 60 * 60_000;
47
49
 
48
50
  /** Missing child-provider metadata keeps the established Pod default: the HQ Codex mirror is needed. */
49
51
  export function shouldInstallRemoteCodexAccess(effectiveChildProvider: string | undefined): boolean {
@@ -81,7 +83,7 @@ export function resolveParentHosts(config: ParentHostSetting | undefined, env: N
81
83
  }
82
84
 
83
85
  /** Capacity sample is read on the host before launch. Unknown or saturated capacity is not a positive weight. */
84
- export interface ParentHostCapacity { active: number; waiting: number; approvalHeadroom: number; load: number }
86
+ export interface ParentHostCapacity { active: number; waiting: number; limit: number; headroom: number; approvalHeadroom: number; load: number }
85
87
 
86
88
  export interface ParentHostPodFit {
87
89
  state: 'fits' | 'never-fits' | 'unmeasured';
@@ -133,13 +135,13 @@ const LOAD_MARKER = '__ELANOUS_PARENT_LOAD__';
133
135
  /** Best-effort macOS `ps` fallback; Linux/WSL uses argv boundaries below. */
134
136
  export const PARENT_HOST_ACTIVE_FILTER = String.raw`/^(([^ ]+\/)?(bun|node|nodejs) )?([^ ]+\/)?elanous(\.mjs)?( --config-dir [^ ]+)? harness (say|ask)( |$)/ && / --no-auto-merge( |$)/ && !/ --substrate local( |$)/ && !/^([^ ]+\/)?[^ ]*sh -c/`;
135
137
  /** Count exact Linux argv entries so Pod-local commands and goal text cannot masquerade as host parents. */
136
- export const PARENT_HOST_PROC_COUNT_SCRIPT = "count=0; proc_root=${1:-/proc}; for file in \"$proc_root\"/[0-9]*/cmdline; do [ -r \"$file\" ] || continue; argv=(); while IFS= read -r -d '' arg; do argv+=(\"$arg\"); done < \"$file\" 2>/dev/null || true; [ ${#argv[@]} -ge 3 ] || continue; program=\"${argv[0]##*/}\"; case \"$program\" in elanous|elanous.mjs) ;; bun|node|nodejs) script_match=0; for ((i=1; i<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == */elanous.mjs ]]; then script_match=1; break; fi; [[ \"${argv[i]}\" == harness ]] && break; done; [ \"$script_match\" -eq 1 ] || continue ;; *) continue ;; esac; harness=0; for ((i=0; i+1<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == harness && ( \"${argv[i+1]}\" == say || \"${argv[i+1]}\" == ask ) ]]; then harness=1; break; fi; done; [ \"$harness\" -eq 1 ] || continue; has_no_auto_merge=0; for arg in \"${argv[@]}\"; do [[ \"$arg\" == --no-auto-merge ]] && has_no_auto_merge=1; done; [ \"$has_no_auto_merge\" -eq 1 ] || continue; local_substrate=0; for ((i=0; i+1<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == --substrate && \"${argv[i+1]}\" == local ]]; then local_substrate=1; break; fi; done; [ \"$local_substrate\" -eq 1 ] || count=$((count+1)); done; printf '__ELANOUS_PARENT_CAPACITY__%s\\n' \"$count\""
138
+ export const PARENT_HOST_PROC_COUNT_SCRIPT = "count=0; proc_root=${1:-/proc}; for file in \"$proc_root\"/[0-9]*/cmdline; do [ -r \"$file\" ] || continue; argv=(); while IFS= read -r -d '' arg; do argv+=(\"$arg\"); done < \"$file\" 2>/dev/null || true; [ ${#argv[@]} -ge 3 ] || continue; program=\"${argv[0]##*/}\"; case \"$program\" in elanous|elanous.mjs) ;; bun|node|nodejs) script_match=0; for ((i=1; i<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == */elanous.mjs ]]; then script_match=1; break; fi; [[ \"${argv[i]}\" == harness ]] && break; done; [ \"$script_match\" -eq 1 ] || continue ;; *) continue ;; esac; harness=0; for ((i=0; i+1<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == harness && ( \"${argv[i+1]}\" == say || \"${argv[i+1]}\" == ask ) ]]; then harness=1; break; fi; done; [ \"$harness\" -eq 1 ] || continue; has_no_auto_merge=0; for arg in \"${argv[@]}\"; do [[ \"$arg\" == --no-auto-merge ]] && has_no_auto_merge=1; done; [ \"$has_no_auto_merge\" -eq 1 ] || continue; local_substrate=0; for ((i=0; i+1<${#argv[@]}; i++)); do if [[ \"${argv[i]}\" == --substrate && \"${argv[i+1]}\" == local ]]; then local_substrate=1; break; fi; done; [ \"$local_substrate\" -eq 1 ] && continue; cgroup_file=${file%cmdline}cgroup; if [ ! -r $cgroup_file ]; then [ ! -d ${file%/cmdline} ] && continue; printf '__ELANOUS_PARENT_CAPACITY_ERROR__cgroup-unreadable\\n'; exit 1; fi; cgroup=$(cat $cgroup_file 2>/dev/null) || { [ ! -d ${file%/cmdline} ] && continue; printf '__ELANOUS_PARENT_CAPACITY_ERROR__cgroup-unreadable\\n'; exit 1; }; case $cgroup in *docker*|*kubepods*|*containerd*|*libpod*|*lxc*) continue;; esac; count=$((count+1)); done; printf '__ELANOUS_PARENT_CAPACITY__%s\\n' \"$count\""
137
139
  /** Recent admission decisions are the host's measured approval backlog, not an inferred process count. */
138
140
  export function readParentHostCapacity(target: ParentHostConfig, ssh: SshRunner = defaultSshRunner): ParentHostCapacity | null {
139
141
  const executable = remotePath(target.elanous ?? DEFAULT_REMOTE_ELANOUS);
140
142
  const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
141
143
  const unavailable = (reason: string): null => { try { debug.log('task-agent.parent-host', 'capacity-unavailable', { host: target.host, reason }); } catch { /* fail-soft */ } return null; };
142
- const processCount = `if [ -r /proc/self/cmdline ]; then if command -v bash >/dev/null 2>&1; then bash -c ${shellQuote(PARENT_HOST_PROC_COUNT_SCRIPT)} -- /proc; else printf "${CAPACITY_ERROR_MARKER}bash-unavailable\\n"; exit 1; fi; else parents=$(ps -Ao command) || exit 1; printf '%s\\n' "$parents" | awk '${PARENT_HOST_ACTIVE_FILTER} { n++ } END { print "${CAPACITY_MARKER}" n+0 }'; fi`;
144
+ const processCount = `if [ -r /proc/self/cmdline ]; then if command -v bash >/dev/null 2>&1; then bash -c ${shellQuote(PARENT_HOST_PROC_COUNT_SCRIPT)} -- /proc || exit 1; else printf "${CAPACITY_ERROR_MARKER}bash-unavailable\\n"; exit 1; fi; else parents=$(ps -Ao command) || exit 1; printf '%s\\n' "$parents" | awk '${PARENT_HOST_ACTIVE_FILTER} { n++ } END { print "${CAPACITY_MARKER}" n+0 }'; fi`;
143
145
  const script = `${processCount}; `
144
146
  + `${executable} --config-dir ${configDir} logs --event admit-by-usage --since 5m --json --limit 1000 || exit 1; `
145
147
  + `printf '\\n${APPROVAL_MARKER}\\n'; `
@@ -147,7 +149,8 @@ export function readParentHostCapacity(target: ParentHostConfig, ssh: SshRunner
147
149
  + `cores=$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null) || exit 1; printf '${LOAD_MARKER}cores=%s\\n' "$cores"`;
148
150
  try {
149
151
  const result = ssh(target.host, script, 15_000);
150
- if (result.status !== 0) return unavailable(result.stdout.includes(`${CAPACITY_ERROR_MARKER}bash-unavailable`) ? 'bash-unavailable' : 'remote-command-failed');
152
+ if (result.status !== 0) return unavailable(result.stdout.includes(`${CAPACITY_ERROR_MARKER}bash-unavailable`) ? 'bash-unavailable'
153
+ : result.stdout.includes(`${CAPACITY_ERROR_MARKER}cgroup-unreadable`) ? 'cgroup-unreadable' : 'remote-command-failed');
151
154
  const activeMatch = new RegExp(`^${CAPACITY_MARKER}(\\d+)$`, 'm').exec(result.stdout);
152
155
  const boundary = result.stdout.indexOf(`\n${APPROVAL_MARKER}\n`);
153
156
  const logsStart = result.stdout.indexOf('\n');
@@ -181,12 +184,13 @@ export function readParentHostCapacity(target: ParentHostConfig, ssh: SshRunner
181
184
  decisions.set(data.runId, data.recommended as number);
182
185
  }
183
186
  const waiting = [...decisions.values()].filter((n) => n === 0).length;
184
- return { active, waiting, approvalHeadroom: Math.max(0, capacity - active - waiting), load: Math.max(0, cpu / (cores * 100)) };
187
+ const headroom = Math.max(0, capacity - active - waiting);
188
+ return { active, waiting, limit: capacity, headroom, approvalHeadroom: headroom, load: Math.max(0, cpu / (cores * 100)) };
185
189
  } catch { return unavailable('capacity-parse-failed'); }
186
190
  }
187
191
 
188
192
  /** Weighted rendezvous rank with evidence fields for launch-time observation. */
189
- export function rankParentHosts(targets: readonly ParentHostConfig[], runId: string, capacities: Readonly<Record<string, ParentHostCapacity | null>>): Array<{ target: ParentHostConfig; weight: number; score: number }> {
193
+ export function rankParentHosts(targets: readonly ParentHostConfig[], runId: string, capacities: Readonly<Record<string, Pick<ParentHostCapacity, 'approvalHeadroom' | 'load'> | null>>): Array<{ target: ParentHostConfig; weight: number; score: number }> {
190
194
  return targets.map((target, index) => {
191
195
  const sample = capacities[target.host];
192
196
  const weight = sample && Number.isSafeInteger(sample.approvalHeadroom) && sample.approvalHeadroom > 0 && Number.isFinite(sample.load) && sample.load >= 0
@@ -264,14 +268,22 @@ export interface ParentHostPreflight { ok: boolean; gaps: string[]; warnings: st
264
268
  export function preflightScript(target: ParentHostConfig): string {
265
269
  const elanous = remotePath(target.elanous ?? DEFAULT_REMOTE_ELANOUS);
266
270
  const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
271
+ const grokCredentialFloorSeconds = Math.ceil(PARENT_CHILD_CREDENTIAL_MIN_REMAINING_MS / 1_000);
267
272
  return [
268
273
  `echo "version=$(${elanous} --version 2>/dev/null | tail -1 | cut -d' ' -f1)"`,
269
274
  `test -f ${configDir}/config.json && echo config=1`,
270
275
  `grep -Eq '"podPool"[[:space:]]*:[[:space:]]*"[^"[:space:]]+' ${configDir}/config.json 2>/dev/null && echo podPool=1`,
271
276
  `(cd ${shellQuote(target.cwd)} 2>/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2>&1) && echo repo=1`,
272
277
  `command -v kubectl >/dev/null 2>&1 && echo kubectl=1`,
278
+ `{ command -v grok >/dev/null 2>&1 || [ -x "$HOME/.grok/bin/grok" ]; } && echo grokCli=1`,
279
+ `{ command -v codex >/dev/null 2>&1 || [ -x "$HOME/.local/bin/codex" ]; } && echo codexCli=1`,
273
280
  `n=$(grep -Ec '^[[:space:]]*"openai-codex(:[^"]*)?"[[:space:]]*:[[:space:]]*\\{' ${configDir}/auth.json 2>/dev/null); echo "codexAccounts=\${n:-0}"`,
274
281
  `{ grep -Eq '"key"[[:space:]]*:[[:space:]]*"[^"]+"' "$HOME/.grok/auth.json" 2>/dev/null || [ -n "\${XAI_API_KEY:-}\${GROK_API_KEY:-}\${GROK_CODE_XAI_API_KEY:-}" ]; } && echo grok=1`,
282
+ // The remote host owns its device-auth session. Ignore the legacy HQ mirror entry; it can outlive and mask the host credential.
283
+ // Read only expiry metadata, never credential values, and compare against the shared minimum lifetime.
284
+ `grokProbe=$(if [ ! -f "$HOME/.grok/auth.json" ]; then printf '0|'; else bun -e 'const fs=require("node:fs");try{const auth=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const entries=Object.entries(auth).filter(([id])=>id!=="https://auth.x.ai::hq-mirror");const hasKey=entries.some(([,entry])=>typeof entry?.key==="string"&&entry.key.length>0);const expiries=entries.filter(([,entry])=>typeof entry?.expires_at==="string").map(([,entry])=>entry.expires_at).sort();process.stdout.write((hasKey?"1":"0")+"|"+(expiries.length?expiries[expiries.length-1]:""))}catch{}' "$HOME/.grok/auth.json" 2>/dev/null; fi); grokOtherKey=\${grokProbe%%|*}; grokExp=\${grokProbe#*|}`,
285
+ `grokFloor=$(date -u -d "@$(( $(date +%s) + ${grokCredentialFloorSeconds} ))" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -r "$(( $(date +%s) + ${grokCredentialFloorSeconds} ))" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || true); grokNow=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || true)`,
286
+ `grokHost=$(if [ -n "$XAI_API_KEY$GROK_API_KEY$GROK_CODE_XAI_API_KEY" ]; then echo valid; elif [ -z "$grokProbe" ]; then echo unknown; elif [ -z "$grokExp" ]; then [ "$grokOtherKey" = 1 ] && echo unknown || echo missing; elif [ -z "$grokFloor" ] || [ -z "$grokNow" ]; then echo unknown; else printf '%s\n%s\n%s\n' "$grokExp" "$grokFloor" "$grokNow" | awk 'NR==1{e=$0} NR==2{f=$0} NR==3{n=$0} END{if (e >= f) print "valid"; else if (e >= n) print "expiring"; else print "expired"}'; fi); echo "grokHost=$grokHost"`,
275
287
  `{ [ -s "\${ELANOUS_KEY_CACHE_DIR:-$HOME/.cache}/openrouter_api_key" ] || [ -n "\${OPENROUTER_API_KEY:-}" ]; } && echo openrouter=1`,
276
288
  `true`,
277
289
  ].join('; ');
@@ -283,6 +295,8 @@ export interface PreflightInput {
283
295
  localVersion: string;
284
296
  /** HQ 착지 동결이 «발사도 막는» 상태인가 — 원격 부모는 그 동결을 못 본다. */
285
297
  launchHoldActive: boolean;
298
+ /** Provider that the detached parent will use for its child. */
299
+ childProvider?: string;
286
300
  ssh?: SshRunner;
287
301
  }
288
302
 
@@ -306,11 +320,34 @@ export function judgeParentHostFacts(facts: Record<string, string>, input: Omit<
306
320
  if (facts.podPool !== '1' && !input.podPoolOverride) gaps.push('remote-pod-pool-unset');
307
321
  if (facts.repo !== '1') gaps.push('remote-repo-missing');
308
322
  if (facts.kubectl !== '1') gaps.push('remote-kubectl-missing');
323
+ if (input.childProvider === 'grok' && facts.grokCli !== '1') gaps.push('grok-cli-missing');
324
+ if ((input.childProvider === 'openai-codex' || input.childProvider === 'codex') && facts.codexCli !== '1') gaps.push('codex-cli-missing');
309
325
  }
310
326
  if (input.launchHoldActive) gaps.push('hq-launch-freeze-active');
311
327
  return gaps;
312
328
  }
313
329
 
330
+ /** Host-side Grok credential states the preflight probe reports; HQ never sees the token itself. */
331
+ export type ParentHostGrokCredentialState = 'valid' | 'expiring' | 'expired' | 'missing' | 'unknown';
332
+
333
+ /**
334
+ * 순수 판정 — 원격 호스트가 스스로 보고한 grok 자격 상태 → **막는** gap 목록(GROK-MIRROR-REAL-SCOPE · 10-20 방향 전환).
335
+ *
336
+ * 왜 경고가 아니라 gap 인가: access-only 미러(4필드)는 원격 grok CLI 1.0.41 에서 `session/new` -32000 으로
337
+ * 거부됐고, HQ refresh_token 복사는 단일 주인 원칙 위반이다. ⇒ 호스트가 각자 device-auth 세션을 스스로
338
+ * 갱신하고, HQ 는 「쓸 수 있나」만 재서 **무효면 Grok 자식 발사 전에** 막는다(발사 뒤 -32000 반복 금지).
339
+ *
340
+ * ⛔ 상태를 «안 보고한» 호스트(구 판)는 막지 않는다 — 모름을 「죽었다」로 읽으면 멀쩡한 호스트가 조용히 빠진다.
341
+ */
342
+ export function judgeParentHostGrokCredential(facts: Record<string, string>, opts: { childProvider?: string } = {}): string[] {
343
+ if (opts.childProvider !== 'grok' || facts.unreachable) return [];
344
+ const state = facts.grokHost as ParentHostGrokCredentialState | undefined;
345
+ if (state === 'missing') return ['grok-credential-missing'];
346
+ if (state === 'expiring') return ['grok-credential-expiring'];
347
+ if (state === 'expired') return ['grok-credential-expired'];
348
+ return [];
349
+ }
350
+
314
351
  /** 순수 판정 — 원격 LLM 자격 사실 → 경고 목록(막지 않는다 · gaps 와 별개). 못 닿은 호스트는 사실이 없으므로 경고도 없다. */
315
352
  export function judgeParentHostCredentials(facts: Record<string, string>): string[] {
316
353
  if (facts.unreachable) return [];
@@ -330,7 +367,16 @@ export function preflightParentHost(input: PreflightInput): ParentHostPreflight
330
367
  const at = line.indexOf('=');
331
368
  if (at > 0) facts[line.slice(0, at).trim()] = line.slice(at + 1).trim();
332
369
  }
333
- const gaps = judgeParentHostFacts(facts, { localVersion: input.localVersion, launchHoldActive: input.launchHoldActive, podPoolOverride: Boolean(input.target.podPool) });
370
+ const gaps = judgeParentHostFacts(facts, { localVersion: input.localVersion, launchHoldActive: input.launchHoldActive, podPoolOverride: Boolean(input.target.podPool), ...(input.childProvider ? { childProvider: input.childProvider } : {}) });
371
+ // 호스트 자체 grok 자격은 «경고»가 아니라 발사 전 «차단» 축이다 — 무효면 OP 재로그인 요청 신호를 남긴다.
372
+ const credentialGaps = judgeParentHostGrokCredential(facts, { ...(input.childProvider ? { childProvider: input.childProvider } : {}) });
373
+ if (credentialGaps.length) {
374
+ try {
375
+ debug.log('task-agent.parent-host', 'grok-relogin-required', {
376
+ host: input.target.host, state: facts.grokHost ?? 'unknown', gaps: credentialGaps,
377
+ });
378
+ } catch { /* fail-soft */ }
379
+ }
334
380
  const warnings = judgeParentHostCredentials(facts);
335
381
  if (warnings.length) {
336
382
  try {
@@ -342,7 +388,8 @@ export function preflightParentHost(input: PreflightInput): ParentHostPreflight
342
388
  });
343
389
  } catch { /* fail-soft */ }
344
390
  }
345
- return { ok: gaps.length === 0, gaps, warnings, facts };
391
+ const blocking = [...gaps, ...credentialGaps];
392
+ return { ok: blocking.length === 0, gaps: blocking, warnings, facts };
346
393
  }
347
394
 
348
395
  /** 원격이 «확실히 안 띄웠다»고 답했다 — 호출부가 로컬로 돌아가도 중복 발사가 아니다. */
@@ -360,9 +407,7 @@ export function launchRemoteParent(
360
407
  args: readonly string[],
361
408
  env: Record<string, string>,
362
409
  ssh: SshRunner = defaultSshRunner,
363
- grokMirrorResolver: () => OwnerGrokAccessMirror = resolveOwnerGrokAccessMirror,
364
410
  effectiveChildProvider?: string,
365
- now: () => number = Date.now,
366
411
  ): { pid: number; log: string } {
367
412
  const argvProvider = childProviderFromArgs(args);
368
413
  if (effectiveChildProvider && argvProvider && argvProvider !== effectiveChildProvider) {
@@ -371,9 +416,11 @@ export function launchRemoteParent(
371
416
  const launchArgs = effectiveChildProvider && !argvProvider
372
417
  ? [...args.slice(0, 2), '--child-llm-provider', effectiveChildProvider, ...args.slice(2)]
373
418
  : args;
419
+ // GROK-MIRROR-REAL-SCOPE: 원격 부모는 HQ access 미러를 «설치하지 않는다»(4필드 미러는 grok 1.0.41 에서
420
+ // `session/new` -32000 · HQ refresh_token 복사는 단일 주인 원칙 위반). 호스트가 각자 device-auth 로
421
+ // 자체 갱신 세션을 쓰고, HQ 는 preflight 에서 «유효성»만 재서 무효면 발사 전에 막는다.
374
422
  if ((effectiveChildProvider ?? argvProvider) === 'grok') {
375
- const mirror = grokMirrorResolver();
376
- installRemoteGrokAccess(target, mirror, ssh, now);
423
+ try { debug.log('task-agent.parent-host', 'grok-host-credential', { host: target.host, runId: env.ELANOUS_RUN_ID ?? 'unknown', source: 'host-device-auth' }); } catch { /* fail-soft */ }
377
424
  }
378
425
  const result = ssh(target.host, remoteLaunchScript(target, launchArgs, env), 30_000);
379
426
  const log = remoteParentLogPath(target, env.ELANOUS_RUN_ID ?? 'unknown');
@@ -1,5 +1,6 @@
1
1
  /** HQ same-PR repair launch and result collection; the reviewed head is the sole source of truth. */
2
2
  import { spawn } from 'node:child_process';
3
+ import { createHash } from 'node:crypto';
3
4
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
5
  import { dirname, join, resolve, sep } from 'node:path';
5
6
  import { debug } from '../debug/log.js';
@@ -13,13 +14,14 @@ import { applyRepairBundle, type RepairCasOutcome, type RepairCasRequest } from
13
14
  import { pairMoveId, repairNextMove } from './repair-next-move.js';
14
15
  import type { SupervisorGoalDeficit } from '../self-implement/goal-supervisor-fill.js';
15
16
  import { loadRunLedger, type RunLedgerEntry } from '../self-implement/run-ledger.js';
16
- import { parseRepairWorkerResult } from './repair-worker.js';
17
+ import { parseRepairWorkerResult, repairFailureSignature } from './repair-worker.js';
17
18
  import { TASK_SEATS, readTaskCard, updateTaskCard, type TaskCard, type TaskChildLlm, type TaskSeat } from './task-hand.js';
18
19
 
19
20
  const WAIT_MS = 90 * 60_000;
20
21
  const ESCALATE_MS = 6 * 60 * 60_000;
21
22
  const ALERT_CLAIM_STALE_MS = 10 * 60_000;
22
23
  const safe = (value: string) => value.replace(/[^A-Za-z0-9._-]/g, '_');
24
+ const reviewSignature = (mustFix: readonly string[]) => createHash('sha256').update(JSON.stringify(mustFix)).digest('hex');
23
25
 
24
26
  export interface RepairLaunchRequest {
25
27
  card: string; pr: number; head: string; repo: string; resultPath: string;
@@ -108,9 +110,9 @@ export async function repairModelAvailability(readInputs: () => Promise<Pick<Bud
108
110
  export function alternateRepairModel(card: TaskCard, availability: RepairModelAvailability = { codexSubscription: false, grokSubscription: false }): { from: string; to: TaskChildLlm } {
109
111
  const last = card.repairs?.at(-1);
110
112
  const from = last?.toModel ?? (card.childLlm ? `${card.childLlm.provider}/${card.childLlm.model}` : 'unknown');
111
- // The Pod's named ZAI subscription is the primary GLM route. A failed
112
- // glm-5.3 repair must never be retried with the smaller flash model.
113
- const glm: TaskChildLlm = { provider: 'glm', model: 'glm-5.3' };
113
+ // Pin the full model route; a bare glm-5.3 can be ambiguous in the Pod review path.
114
+ // A failed full GLM repair must never be retried with the smaller flash model.
115
+ const glm: TaskChildLlm = { provider: 'openrouter', model: 'openrouter/z-ai/glm-5.3' };
114
116
  const sol: TaskChildLlm = { provider: 'openai-codex', model: 'gpt-6-sol' };
115
117
  const grok: TaskChildLlm = { provider: 'grok', model: 'grok-4.6' };
116
118
  const tier = card.tier ?? '중';
@@ -275,6 +277,8 @@ export async function runRepairCycle(input: RepairCycleInput): Promise<RepairCyc
275
277
  }
276
278
  }
277
279
  const status = applied?.ok ? 'applied' : applied?.unconfirmed ? 'unconfirmed' : 'failed';
280
+ const failureSignature = status === 'failed' && !result.ok
281
+ ? result.failureSignature ?? repairFailureSignature(result.reason ?? '') : null;
278
282
  // NEXTMOVE-GENERAL-RELAUNCH-MOVEID — 결과 파일의 수 id 를 카드(발사 순간 적은 값)와 짝짓는다. 못 짝지으면 관측만(소비는 그대로).
279
283
  const pairing = pairMoveId(latest.moveId, result.moveId);
280
284
  if (pairing.kind === 'unpaired') try { debug.log('task-agent', 'move-id-unpaired', { card: card.id, pr, head: latest.head,
@@ -282,13 +286,16 @@ export async function runRepairCycle(input: RepairCycleInput): Promise<RepairCyc
282
286
  const pairedMoveId = pairing.kind === 'paired' ? { moveId: pairing.moveId } : {};
283
287
  try { debug.log('task-agent', 'repair-attempt-result', { card: card.id, pr, head: latest.head,
284
288
  runId: latest.runId, failureType: status === 'applied' || status === 'unconfirmed' ? null : result.ok ? 'artifact-or-cas' : 'worker',
285
- model: latest.toModel, resultPath: latest.resultPath, artifactDir: result.artifactDir ?? null, status, detail });
289
+ model: latest.toModel, resultPath: latest.resultPath, artifactDir: result.artifactDir ?? null, status, detail,
290
+ ...(result.gateFailureTests ? { gateFailureTests: result.gateFailureTests } : {}) });
286
291
  } catch { /* diagnostics cannot change the result */ }
287
292
  try {
288
293
  updateTaskCard(statePath, card.id, (current) => current?.repairs?.some((entry) => entry.runId === latest.runId
289
294
  && (entry.status === 'requested' || (claimedThisCycle && entry.status === 'unconfirmed' && entry.commit === result?.result?.commit)))
290
295
  ? { ...current, repairs: current.repairs.map((entry) => entry.runId === latest.runId
291
- ? { ...entry, status, detail, ...(result?.result && status === 'unconfirmed' ? { commit: result.result.commit,
296
+ ? { ...entry, status, detail, ...(failureSignature ? { failureSignature } : {}),
297
+ ...(failureSignature?.startsWith('gate:') && result.gateFailureTests ? { gateFailureTests: result.gateFailureTests } : {}),
298
+ ...(result?.result && status === 'unconfirmed' ? { commit: result.result.commit,
292
299
  bundleSha256: result.result.bundleSha256, bundlePath: join(resolve(result.artifactDir!), 'commit.bundle') } : {}),
293
300
  ...(applied?.ok ? { commit: applied.toHead } : {}) } : entry),
294
301
  history: [...(current.history ?? []), { at: now.toISOString(), event: 'repair-result', pr, head: latest.head,
@@ -428,10 +435,61 @@ export async function runRepairCycle(input: RepairCycleInput): Promise<RepairCyc
428
435
  return { decision: 'would-repair', reason };
429
436
  }
430
437
  const next = attempts.length + 1;
431
- const runId = mintRunId();
432
438
  // 결정 순간 만든 수 id — 아래 발사·카드·관측이 «이 값»만 쓴다(다시 만들지 않는다).
433
439
  const moveId = judged.moveId;
434
440
  const { from, to } = alternateRepairModel(card, availability);
441
+ const nextModel = `${to.provider}/${to.model}`;
442
+ const repeatSignature = latest?.status === 'failed' && latest.head.toLowerCase() === head.toLowerCase()
443
+ && latest.reviewSignature === reviewSignature(input.mustFix) && latest.failureSignature
444
+ && (latest.failureSignature.startsWith('gate:sha256:')
445
+ || latest.failureSignature.startsWith('provider:ambiguous-primary:') && latest.toModel === nextModel)
446
+ ? latest.failureSignature : null;
447
+ if (repeatSignature) {
448
+ const prior = latest!;
449
+ const tests = prior.gateFailureTests?.slice(0, 4).join(' | ');
450
+ const reason = `same PR/head/review deterministic repair failure ${repeatSignature}; owner repair required${tests ? ` · ${tests}` : ''}`;
451
+ let recorded = false;
452
+ updateTaskCard(statePath, card.id, (current) => {
453
+ if (!current || current.status !== 'launched' || !current.repairs?.some((entry) =>
454
+ entry.runId === prior.runId && entry.status === 'failed' && entry.failureSignature === repeatSignature
455
+ && entry.reviewSignature === prior.reviewSignature)
456
+ || current.history?.some((entry) => entry.event === 'repair-signature-repeat-stopped' && entry.pr === pr
457
+ && entry.head?.toLowerCase() === head.toLowerCase() && entry.runId === prior.runId)) return undefined;
458
+ recorded = true;
459
+ return { ...current, status: 'failed', history: [...(current.history ?? []),
460
+ { at: now.toISOString(), event: 'repair-signature-repeat-stopped', pr, head, runId: prior.runId, detail: reason }] };
461
+ });
462
+ if (recorded) try { debug.log('task-agent', 'repair-signature-repeat-stopped', { card: card.id, pr, head,
463
+ signature: repeatSignature, priorRunId: prior.runId, skippedRelaunch: true }); } catch { /* fail-soft */ }
464
+ let notifyClaimed = false;
465
+ updateTaskCard(statePath, card.id, (current) => {
466
+ const history = current?.history ?? [];
467
+ const lastAlert = history.filter((entry) => entry.runId === prior.runId && entry.event.startsWith('repair-repeat-owner-')).at(-1);
468
+ const staleClaim = lastAlert?.event === 'repair-repeat-owner-claimed'
469
+ && now.getTime() - Date.parse(lastAlert.at) >= ALERT_CLAIM_STALE_MS;
470
+ if (!current || !history.some((entry) => entry.event === 'repair-signature-repeat-stopped'
471
+ && entry.pr === pr && entry.head?.toLowerCase() === head.toLowerCase() && entry.runId === prior.runId)
472
+ || lastAlert && lastAlert.event !== 'repair-repeat-owner-failed' && !staleClaim) return undefined;
473
+ notifyClaimed = true;
474
+ return { ...current, history: [...history,
475
+ { at: now.toISOString(), event: 'repair-repeat-owner-claimed', pr, head, runId: prior.runId, detail: reason }] };
476
+ });
477
+ if (notifyClaimed) {
478
+ let event = 'repair-repeat-owner-sent';
479
+ let detail = reason;
480
+ try {
481
+ (input.notify ?? defaultNotify)(owner.seat, `${reason} · card ${card.id} · owner ${owner.seat} via ${owner.source}`);
482
+ } catch (error) {
483
+ event = 'repair-repeat-owner-failed';
484
+ detail = `${reason} · ${String(error).slice(0, 200)}`;
485
+ }
486
+ updateTaskCard(statePath, card.id, (current) => current?.history?.some((entry) =>
487
+ entry.event === 'repair-repeat-owner-claimed' && entry.runId === prior.runId)
488
+ ? { ...current, history: [...current.history, { at: now.toISOString(), event, pr, head, runId: prior.runId, detail }] } : undefined);
489
+ }
490
+ return { decision: 'repair-stopped', reason };
491
+ }
492
+ const runId = mintRunId();
435
493
  const resultPath = repairResultPath(statePath, card.id, pr, head, next, runId);
436
494
  const goalFile = resultPath.replace(/\.json$/, '.goal.txt');
437
495
  const goal = `기존 PR #${pr}의 리뷰 때 head ${head}를 같은 가지에서 수리한다. 새 PR을 열지 말고 아래 must-fix 원문만 고쳐 commit-only 결과를 반환한다.\n\n${input.mustFix.map((item, i) => `${i + 1}. ${item}`).join('\n')}`;
@@ -442,7 +500,8 @@ export async function runRepairCycle(input: RepairCycleInput): Promise<RepairCyc
442
500
  if (!current || current.status !== 'launched' || (current.repairs ?? []).length !== (card.repairs ?? []).length) return undefined;
443
501
  claimed = true;
444
502
  return { ...current, repairs: [...(current.repairs ?? []), { pr, head, branch, at: now.toISOString(),
445
- move: judged.judgement.move, moveId, runId, resultPath, fromModel: from, toModel: `${to.provider}/${to.model}`, status: 'requested' }],
503
+ move: judged.judgement.move, moveId, runId, resultPath, fromModel: from, toModel: `${to.provider}/${to.model}`,
504
+ reviewSignature: reviewSignature(input.mustFix), status: 'requested' }],
446
505
  history: [...(current.history ?? []), { at: now.toISOString(), event: 'repair-launched', pr, head, runId,
447
506
  effect: judged.judgement.move, moveId, detail: `source pr:${pr} · owner ${owner.seat} via ${owner.source} · must-fix ${input.mustFix.length} · childLlm ${from} → ${to.provider}/${to.model}` }] };
448
507
  });
@@ -22,9 +22,32 @@ export interface RepairWorkerRequest {
22
22
 
23
23
  export interface RepairWorkerResult {
24
24
  pr: number; head: string; runId: string; ok: boolean; reason?: string; moveId?: string;
25
+ /** A classified, stable failure only. Generic gate-failed is deliberately unsigned. */
26
+ failureSignature?: string;
27
+ /** Exact introduced test identities from the same signed gate receipt. */
28
+ gateFailureTests?: string[];
25
29
  job?: string; artifactDir?: string; result?: RepairCommitResult;
26
30
  }
27
31
 
32
+ export function repairFailureSignature(output: string): string | null {
33
+ const gate = output.match(/^GATE_FAILURE_SIGNATURE=sha256:([a-f0-9]{64})\s*$/m);
34
+ if (gate) return `gate:sha256:${gate[1]}`;
35
+ const model = output.match(/review fallback: ambiguous or unsupported primary model ["“]([^"”\n]+)["”]/i);
36
+ const name = model?.[1]?.trim().toLowerCase();
37
+ return name && /^[a-z0-9._/-]{1,120}$/.test(name) ? `provider:ambiguous-primary:${name}` : null;
38
+ }
39
+
40
+ export function repairGateFailureTests(output: string): string[] | null {
41
+ const line = /^GATE_FAILURE_TESTS=(\[[^\r\n]*\])\s*$/m.exec(output)?.[1];
42
+ if (!line) return null;
43
+ try {
44
+ const tests: unknown = JSON.parse(line);
45
+ return Array.isArray(tests) && tests.length > 0 && tests.length <= 32
46
+ && tests.every((test) => typeof test === 'string' && test.length > 0 && test.length <= 512)
47
+ ? tests as string[] : null;
48
+ } catch { return null; }
49
+ }
50
+
28
51
  export function repairHarnessArgs(request: RepairWorkerRequest): string[] {
29
52
  if (!Number.isSafeInteger(request.pr) || request.pr < 1 || !SHA40.test(request.head)
30
53
  || !request.goal.trim() || !request.runId) throw new Error('repair worker request invalid');
@@ -71,7 +94,15 @@ export async function runRepairWorker(request: RepairWorkerRequest): Promise<Rep
71
94
  child.once('close', resolve);
72
95
  });
73
96
  const marker = parseRepairMarker(output, request.pr, request.head, request.runId);
74
- if (code !== 0) result.reason = `harness exited ${code}: ${output.slice(-600)}`;
97
+ if (code !== 0) {
98
+ result.reason = `harness exited ${code}: ${output.slice(-600)}`;
99
+ const failureSignature = repairFailureSignature(output);
100
+ if (failureSignature) {
101
+ result.failureSignature = failureSignature;
102
+ const tests = failureSignature.startsWith('gate:') ? repairGateFailureTests(output) : null;
103
+ if (tests) result.gateFailureTests = tests;
104
+ }
105
+ }
75
106
  else if (!marker) result.reason = `repair artifact marker missing or invalid: ${output.slice(-600)}`;
76
107
  else Object.assign(result, { ok: true, ...marker });
77
108
  } catch (error) {
@@ -96,6 +127,11 @@ export function parseRepairWorkerResult(text: string, pr: number, head: string,
96
127
  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
97
128
  const v = value as RepairWorkerResult;
98
129
  if (v.pr !== pr || typeof v.head !== 'string' || v.head.toLowerCase() !== head.toLowerCase() || v.runId !== runId || typeof v.ok !== 'boolean') return null;
130
+ if (v.failureSignature !== undefined && (typeof v.failureSignature !== 'string'
131
+ || !/^(?:gate:sha256:[a-f0-9]{64}|provider:ambiguous-primary:[a-z0-9._/-]{1,120})$/.test(v.failureSignature))) delete v.failureSignature;
132
+ if (v.gateFailureTests !== undefined && (!v.failureSignature?.startsWith('gate:')
133
+ || !Array.isArray(v.gateFailureTests) || v.gateFailureTests.length < 1 || v.gateFailureTests.length > 32
134
+ || !v.gateFailureTests.every((test) => typeof test === 'string' && test.length > 0 && test.length <= 512))) delete v.gateFailureTests;
99
135
  if (v.ok && (typeof v.artifactDir !== 'string' || !v.artifactDir.startsWith('/') || typeof v.job !== 'string' || !v.job
100
136
  || !v.result || v.result.pr !== pr || typeof v.result.baseHead !== 'string'
101
137
  || v.result.baseHead.toLowerCase() !== head.toLowerCase() || v.result.runId !== runId || !SHA40.test(v.result.commit)