elanous 0.2.29 → 0.2.31

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 (709) 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/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
  5. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
  8. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
  9. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
  10. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
  12. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
  17. package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
  24. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
  31. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
  32. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
  33. package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
  35. package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
  39. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
  43. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
  45. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
  49. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
  50. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
  51. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
  53. package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
  67. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
  72. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
  75. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
  77. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
  78. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
  80. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
  85. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
  86. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  93. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  94. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  109. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  121. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +23 -23
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +23 -23
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +23 -23
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +22 -22
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +22 -22
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +23 -23
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +22 -22
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +23 -23
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +23 -23
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +22 -22
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +23 -23
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +23 -23
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +23 -23
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +23 -23
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +22 -22
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +22 -22
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +23 -23
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +23 -23
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +23 -23
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +22 -22
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +22 -22
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +23 -23
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +23 -23
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +22 -22
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +22 -22
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +22 -22
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +23 -23
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +23 -23
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +22 -22
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +23 -23
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +23 -23
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +23 -23
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +23 -23
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +23 -23
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +22 -22
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +23 -23
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +23 -23
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +23 -23
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +23 -23
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +23 -23
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +23 -23
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +23 -23
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +23 -23
  277. package/bin/elanous.mjs +7 -3
  278. package/graphs/context/nightly-condense.yaml +1 -0
  279. package/graphs/intake/intake-daily.yaml +8 -1
  280. package/graphs/intake/recipes.yaml +5 -0
  281. package/graphs/lecture/lecture-note.yaml +2 -2
  282. package/graphs/ops/harness-gc.yaml +1 -0
  283. package/graphs/release/recipes.yaml +3 -0
  284. package/graphs/release/release-loop.yaml +9 -5
  285. package/graphs/units/recipes.yaml +3 -0
  286. package/graphs/units/release-gate-recheck.yaml +15 -0
  287. package/package.json +2 -1
  288. package/scripts/check-native-tool-wiring.ts +3 -2
  289. package/scripts/ci-android-unit-tests.ts +16 -0
  290. package/scripts/ci-typecheck-changed.ts +37 -9
  291. package/scripts/coord-channel-watch.sh +22 -16
  292. package/scripts/coord-role-pack.ts +81 -2
  293. package/scripts/cron-run.ts +96 -3
  294. package/scripts/detect-test-interference.ts +38 -5
  295. package/scripts/gate-pr-cache.ts +65 -0
  296. package/scripts/gh-surface/capture.ts +126 -0
  297. package/scripts/gh-surface/gh +40 -0
  298. package/scripts/import-graph-scc.ts +38 -0
  299. package/scripts/install.ps1 +19 -0
  300. package/scripts/intake-social.ts +181 -0
  301. package/scripts/lecture-note/node.ts +71 -4
  302. package/scripts/lib/android-toolchain.ts +32 -0
  303. package/scripts/lib/deterministic-env.ts +62 -0
  304. package/scripts/lib/gate-test-env.ts +19 -0
  305. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  306. package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
  307. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  308. package/scripts/release-loop/cut-branch.ts +4 -3
  309. package/scripts/release-loop/export-check-node.ts +0 -1
  310. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  311. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  312. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  313. package/scripts/release-loop/gate-closure.ts +12 -8
  314. package/scripts/release-loop/gate-diff.ts +1 -1
  315. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  316. package/scripts/release-loop/gate-node.ts +523 -75
  317. package/scripts/release-loop/gate-partial.ts +106 -9
  318. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  319. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  320. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  321. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  322. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  323. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  324. package/scripts/release-loop/import-graph-scc.ts +215 -0
  325. package/scripts/release-loop/node-verdict.ts +2 -0
  326. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  327. package/scripts/release-loop/resume-release.ts +33 -4
  328. package/scripts/release-loop/resume.ts +13 -5
  329. package/scripts/release-loop/spawn-lane.ts +2 -19
  330. package/scripts/release-loop/tui-sim-node.ts +3 -2
  331. package/scripts/release-loop/unattended-release.ts +16 -0
  332. package/scripts/test-deterministic.ts +5 -61
  333. package/scripts/train-reach-grouping.ts +48 -0
  334. package/scripts/tsc-incremental-cache.ts +86 -0
  335. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  336. package/scripts/tsc-main-safety-net.ts +2 -2
  337. package/src/acp/client.ts +4 -1
  338. package/src/acp/core-turn-bridge.ts +50 -5
  339. package/src/ad-pipeline/run.ts +4 -2
  340. package/src/agent/runner.ts +169 -3
  341. package/src/agent/subagent-callable.ts +3 -2
  342. package/src/agent-mission/review-loop.ts +6 -3
  343. package/src/agent-substrate/acp-implementer.ts +14 -2
  344. package/src/agent-substrate/pr-reviewer.ts +12 -0
  345. package/src/agent-substrate/self-review-cli.ts +30 -4
  346. package/src/autopilot/pr-manager.ts +62 -7
  347. package/src/briefing/brief-items.ts +24 -22
  348. package/src/capture/tui-self-report.ts +15 -0
  349. package/src/chat/chat-cli.ts +10 -2
  350. package/src/chat/index.ts +77 -11
  351. package/src/chat/input-control-key.ts +5 -3
  352. package/src/chat/tool-interrupt-behavior.ts +38 -0
  353. package/src/chat/tool-render/dispatch.ts +5 -1
  354. package/src/chat/turn-typeahead.ts +75 -20
  355. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  356. package/src/cli/agent-cli.ts +41 -13
  357. package/src/cli/config-audit.ts +123 -0
  358. package/src/cli/decisions-cli.ts +80 -6
  359. package/src/cli/log-event-names.ts +7 -0
  360. package/src/cli/mcp-login.ts +21 -5
  361. package/src/cli/msg-cli.ts +88 -0
  362. package/src/cli/pr-cli.ts +214 -57
  363. package/src/cli/pr-land-heavy-remote.ts +2 -2
  364. package/src/cli/pr-land-overlap-evidence.ts +63 -9
  365. package/src/cli/pr-land-pod-shadow-job.ts +83 -0
  366. package/src/cli/pr-land-pod-shadow.ts +16 -3
  367. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  368. package/src/cli/release-cli.ts +80 -14
  369. package/src/cli/seat-cli.ts +138 -3
  370. package/src/cli/self-update.ts +5 -2
  371. package/src/cli/tasks-cli.ts +97 -19
  372. package/src/context-bus/context-first.ts +13 -0
  373. package/src/context-bus/context-now.ts +13 -2
  374. package/src/context-bus/ops-events.ts +75 -0
  375. package/src/control-plane/lease-holder.ts +12 -8
  376. package/src/control-plane/ledger.ts +163 -4
  377. package/src/control-plane/server.ts +91 -11
  378. package/src/core-turn/run-core-turn.ts +1 -0
  379. package/src/core-turn/run-goal-loop.ts +222 -3
  380. package/src/core-turn/seat-turn-cap.ts +79 -0
  381. package/src/core-turn/short-question.ts +38 -6
  382. package/src/core-turn/types.ts +3 -0
  383. package/src/dashboard/acp-boot.ts +3 -0
  384. package/src/dashboard/index.ts +224 -615
  385. package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
  386. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  387. package/src/dashboard/input/chat-main-session.ts +8 -1
  388. package/src/dashboard/input/chat-main-turn.ts +12 -3
  389. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  390. package/src/dashboard/input/external-input-host.ts +26 -0
  391. package/src/dashboard/input/internal-turn.ts +261 -0
  392. package/src/dashboard/input/seat-autowake.ts +318 -0
  393. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  394. package/src/dashboard/loop-scheduler.ts +72 -0
  395. package/src/dashboard/seat-boot-preamble.ts +18 -0
  396. package/src/dashboard/skill-runtime.ts +2 -0
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  398. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  399. package/src/dashboard/slash-runtime/index.ts +13 -0
  400. package/src/dashboard/turn-busy-teardown.ts +50 -0
  401. package/src/decisions/decision-ledger.ts +45 -4
  402. package/src/discord-self-message.ts +4 -4
  403. package/src/domains/release-tool.ts +18 -1
  404. package/src/field-note/transcribe.ts +17 -0
  405. package/src/github/remote-call.ts +81 -0
  406. package/src/goals/registry.ts +46 -6
  407. package/src/goals/types.ts +7 -1
  408. package/src/graph-runner/runner.ts +1 -0
  409. package/src/grok/credential.ts +26 -0
  410. package/src/harness/harness-clean.ts +2 -1
  411. package/src/harness/harness-cli-command.ts +52 -5
  412. package/src/harness/harness-gc.ts +2 -1
  413. package/src/harness/harness-incidents.ts +57 -20
  414. package/src/harness/harness-pod-dispatch.ts +87 -10
  415. package/src/harness/harness-queue.ts +53 -4
  416. package/src/harness/harness-stop.ts +4 -3
  417. package/src/harness/harness-substrate-default.ts +78 -7
  418. package/src/harness/harness-worktree-auto.ts +2 -1
  419. package/src/harness/harness-worktrees.ts +3 -2
  420. package/src/hooks/dispatch.ts +2 -1
  421. package/src/index.ts +152 -25
  422. package/src/input/external-input-queue.ts +33 -1
  423. package/src/intake-plane/slash.ts +14 -3
  424. package/src/keybindings.ts +4 -1
  425. package/src/llm/tool-loop-steered-rejection.ts +33 -0
  426. package/src/llm.ts +138 -19
  427. package/src/loops/consensus.ts +348 -0
  428. package/src/loops/msg-wake.ts +206 -4
  429. package/src/loops/observe.ts +19 -3
  430. package/src/loops/orchestrator/tick.ts +64 -10
  431. package/src/loops/orchestrator/traffic.ts +64 -1
  432. package/src/loops/registry.ts +30 -0
  433. package/src/market/signed-index.ts +14 -0
  434. package/src/mcp/mcp-oauth.ts +54 -5
  435. package/src/models/prompts.ts +28 -0
  436. package/src/msg/msg-sse-client.ts +223 -0
  437. package/src/msg/msg-store.ts +86 -2
  438. package/src/mss/logging/log-store.ts +225 -1
  439. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  440. package/src/nexus/api/http-server.ts +54 -15
  441. package/src/nexus/api/loop-resources.ts +19 -3
  442. package/src/nexus/api/ops-api.ts +11 -0
  443. package/src/nexus/daemon-thin-inventory.md +37 -0
  444. package/src/nexus/index.ts +70 -0
  445. package/src/nexus/state/state.ts +1 -0
  446. package/src/oauth/store.ts +32 -7
  447. package/src/onboarding/first-run.ts +28 -3
  448. package/src/ops/overview-cache.ts +16 -4
  449. package/src/ops/resources.ts +82 -0
  450. package/src/plugins/maker/connector-maker.ts +41 -0
  451. package/src/plugins/maker/skill-maker.ts +42 -0
  452. package/src/pr-tool/census.ts +288 -0
  453. package/src/prompt-library/chat-conciseness.ts +13 -0
  454. package/src/prompt-library/universal-preamble.ts +10 -5
  455. package/src/release-loop/gate-host-reservation.ts +97 -0
  456. package/src/release-loop/landing-freeze.ts +5 -0
  457. package/src/release-loop/light-rc.ts +5 -2
  458. package/src/release-loop/placement.ts +92 -1
  459. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  460. package/src/release-loop/rehearsal.ts +73 -17
  461. package/src/repl/index.ts +20 -2
  462. package/src/seat-loop/seat-knowhow.ts +282 -0
  463. package/src/seat-loop/seat-loop.ts +41 -2
  464. package/src/seat-loop/traffic-signal.ts +3 -0
  465. package/src/self-dev/ask-launch-flow.ts +24 -3
  466. package/src/self-dev/decompose-compose-graph.ts +28 -27
  467. package/src/self-dev/decompose-proposal.ts +53 -38
  468. package/src/self-dev/decompose.ts +17 -0
  469. package/src/self-dev/dev-pipeline.ts +31 -2
  470. package/src/self-dev/draft-residue.ts +24 -9
  471. package/src/self-dev/draft-sweep.ts +59 -4
  472. package/src/self-dev/external-call-zero.ts +77 -0
  473. package/src/self-dev/launch-preflight-text.ts +6 -0
  474. package/src/self-dev/launch-preflight.ts +25 -3
  475. package/src/self-dev/local-supervisor-judge.ts +185 -0
  476. package/src/self-dev/run-supervisor.ts +229 -19
  477. package/src/self-dev/run-types.ts +20 -0
  478. package/src/self-dev/shard-aggregate.ts +13 -2
  479. package/src/self-dev/shard-plan.ts +47 -0
  480. package/src/self-dev/shard-run.ts +112 -10
  481. package/src/self-dev/spawn-lane-files.ts +19 -0
  482. package/src/self-implement/app-api-budget.ts +51 -11
  483. package/src/self-implement/config-gate.ts +2 -1
  484. package/src/self-implement/expose-gate.ts +2 -1
  485. package/src/self-implement/gate-artifacts.ts +405 -0
  486. package/src/self-implement/gate-cli.ts +201 -16
  487. package/src/self-implement/gate-remote.ts +110 -25
  488. package/src/self-implement/gate-scenario.ts +85 -0
  489. package/src/self-implement/goal-author.ts +160 -8
  490. package/src/self-implement/graph-authority.ts +38 -6
  491. package/src/self-implement/graph-overlay-condition.ts +92 -1
  492. package/src/self-implement/heal-triage.ts +79 -0
  493. package/src/self-implement/host-regate.ts +61 -3
  494. package/src/self-implement/orchestrator.ts +14 -123
  495. package/src/self-implement/pr-title.ts +123 -0
  496. package/src/self-implement/run-checkpoint.ts +235 -0
  497. package/src/self-implement/run-ledger.ts +155 -10
  498. package/src/self-implement/run-stop.ts +4 -3
  499. package/src/self-implement/run-ttl.ts +28 -4
  500. package/src/self-implement/seams.ts +2 -0
  501. package/src/self-implement/shadow-stage.ts +7 -6
  502. package/src/self-implement/stop-autoheal.ts +2 -1
  503. package/src/self-implement/train-gate-remote.ts +37 -8
  504. package/src/self-implement/train-reach-grouping.ts +157 -0
  505. package/src/self-implement/train-scenario-layers.ts +133 -0
  506. package/src/self-implement/uncommitted-work.ts +2 -0
  507. package/src/session/pending-input.ts +19 -0
  508. package/src/session/session-start.ts +224 -0
  509. package/src/session-runtime/parallel-dispatch.ts +22 -5
  510. package/src/skills/tools/dev-harness.ts +6 -4
  511. package/src/skills/tools/shell.ts +1 -1
  512. package/src/steward/resync-tick.ts +114 -23
  513. package/src/steward/ta-repair-event-collect.ts +158 -0
  514. package/src/task-agent/card-evidence.ts +25 -1
  515. package/src/task-agent/green-sweep.ts +8 -3
  516. package/src/task-agent/judge.ts +76 -0
  517. package/src/task-agent/land-queue.ts +79 -0
  518. package/src/task-agent/live-moves.ts +30 -9
  519. package/src/task-agent/postland-card.ts +5 -0
  520. package/src/task-agent/prelaunch-already-done.ts +98 -0
  521. package/src/task-agent/real-launch-guard.ts +37 -0
  522. package/src/task-agent/rejudge-on-head.ts +89 -12
  523. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  524. package/src/task-agent/repair-cycle.ts +45 -7
  525. package/src/task-agent/repair-worker.ts +7 -0
  526. package/src/task-agent/run-identity.ts +200 -0
  527. package/src/task-agent/shadow.ts +50 -3
  528. package/src/task-agent/task-hand.ts +158 -5
  529. package/src/task-agent/train-landing.ts +77 -0
  530. package/src/task-agent/work-order.ts +104 -0
  531. package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
  532. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  533. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  534. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  535. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  536. package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
  537. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  538. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  539. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  540. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
  541. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  542. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  543. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  544. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  545. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
  546. package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
  547. package/src/telegram.ts +2 -4
  548. package/src/tui/input/pickers.ts +732 -0
  549. package/src/tui/slash/mission.ts +492 -0
  550. package/src/tui/slash/term.ts +877 -0
  551. package/src/tui-client/dashboard-session.ts +9 -0
  552. package/src/tui.ts +48 -0
  553. package/src/user-config/gemini-server-tools.ts +9 -0
  554. package/src/user-config.ts +53 -16
  555. package/src/util/spawn-sync-output.ts +7 -0
  556. package/src/ux-sim/fake-bin.ts +154 -0
  557. package/src/ux-sim/fake-clock.ts +36 -0
  558. package/src/ux-sim/headless-tui.ts +72 -0
  559. package/src/ux-sim/in-process-cli.ts +2 -1
  560. package/src/ux-sim/temp-git-remote.ts +82 -0
  561. package/src/version/packed-revision.json +1 -1
  562. package/src/video-pipeline/recipes/vlog.ts +25 -7
  563. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  567. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  569. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  572. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  573. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  576. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  578. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  584. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  588. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  599. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  605. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  608. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  609. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  610. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  613. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  615. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  616. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  617. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  619. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  625. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  632. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  635. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  640. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  642. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  703. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  709. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * RES-FLOOR-API — «자원 지도» 접기(순수 층). I/O 0 · kubectl/ssh 0 · 새 수집 0.
3
+ * 이미 도는 overview 캐시의 메모 스냅숏과 응답 때 얹는 Pod 점유를 PWA 자원 지도 꼴로 접는다.
4
+ * 설계: 칸 RES-FLOOR-API(0.2.28) — 호스트별 load·mem · Pod 슬롯 · 칸마다 observedAt · 빠진 칸은 missing 사유.
5
+ */
6
+ import type { Cell, MachineLoad, OverviewSnapshot, PodMemberRow } from './overview.js';
7
+
8
+ export interface ResourceCell<T> {
9
+ value: T | null;
10
+ observedAt: string | null;
11
+ /** value 가 없는 칸의 사유 — 측정됐으면 null */
12
+ missing: string | null;
13
+ }
14
+
15
+ export interface HostResourcesRow {
16
+ name: string;
17
+ load1: ResourceCell<number>;
18
+ load5: ResourceCell<number>;
19
+ load15: ResourceCell<number>;
20
+ cpuCount: ResourceCell<number>;
21
+ memFreeGb: ResourceCell<number>;
22
+ memTotalGb: ResourceCell<number>;
23
+ }
24
+
25
+ export interface PodSlotRow {
26
+ context: string;
27
+ capacity: number;
28
+ occupied: ResourceCell<number>;
29
+ }
30
+
31
+ export interface ResourcesMap {
32
+ /** 접은 스냅숏의 시각(overview generatedAt) */
33
+ generatedAt: string;
34
+ /** 이 읽기 시각 */
35
+ readAt: string;
36
+ hosts: HostResourcesRow[];
37
+ pods: PodSlotRow[];
38
+ /** 구조적으로 통째로 빈 칸의 사유(호스트 원장 비어 있음 · 풀 설정 없음) */
39
+ missing: string[];
40
+ }
41
+
42
+ const NO_REASON = '사유 없음';
43
+
44
+ function fold<T>(source: Cell<T>): ResourceCell<T> {
45
+ const measured = source.status !== 'unmeasured' && source.value !== null;
46
+ return { value: measured ? source.value : null, observedAt: source.observedAt, missing: measured ? null : source.reason ?? NO_REASON };
47
+ }
48
+
49
+ /** 호스트의 모든 숫자 칸은 같은 하트비트 cell 에서 나오니 observedAt·missing 도 함께 접힌다. */
50
+ function hostRow(host: OverviewSnapshot['machines']['hosts'][number]): HostResourcesRow {
51
+ const load = fold(host.load);
52
+ const num = (pick: (l: MachineLoad) => number): ResourceCell<number> => load.value !== null
53
+ ? { value: pick(load.value), observedAt: load.observedAt, missing: null }
54
+ : { value: null, observedAt: load.observedAt, missing: load.missing };
55
+ return {
56
+ name: host.name,
57
+ load1: num((l) => l.load1),
58
+ load5: num((l) => l.load5),
59
+ load15: num((l) => l.load15),
60
+ cpuCount: num((l) => l.cpuCount),
61
+ memFreeGb: num((l) => l.freeGb),
62
+ memTotalGb: num((l) => l.totalGb),
63
+ };
64
+ }
65
+
66
+ export function resourcesFromOverview(snapshot: OverviewSnapshot, pods: readonly PodMemberRow[], now: number): ResourcesMap {
67
+ const byContext = new Map(pods.map((pod) => [pod.context, pod]));
68
+ const missing: string[] = [];
69
+ if (snapshot.machines.hosts.length === 0) missing.push('hosts: 하트비트 원장 비어 있음');
70
+ if (snapshot.machines.pods.length === 0) missing.push('pods: 풀 설정 없음');
71
+ return {
72
+ generatedAt: snapshot.generatedAt,
73
+ readAt: new Date(now).toISOString(),
74
+ hosts: snapshot.machines.hosts.map(hostRow),
75
+ pods: snapshot.machines.pods.map((pod): PodSlotRow => ({
76
+ context: pod.context,
77
+ capacity: pod.capacity,
78
+ occupied: fold((byContext.get(pod.context) ?? pod).occupied),
79
+ })),
80
+ missing,
81
+ };
82
+ }
@@ -0,0 +1,41 @@
1
+ import { lstatSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
2
+ import { basename, dirname, join, resolve } from 'node:path';
3
+ import { loadPluginManifestFromDir } from '../core/manifest.js';
4
+ import type { PluginDraft } from './plugin-maker.js';
5
+
6
+ export interface MakeConnectorOptions {
7
+ dir: string;
8
+ gap: PluginDraft['connectors'][number];
9
+ id: string;
10
+ }
11
+
12
+ /** Add one connector's credential-name-only draft to the existing extension manifest. */
13
+ export function makeConnector({ dir: inputDir, gap, id }: MakeConnectorOptions): string {
14
+ if (!/^[a-z0-9][a-z0-9-]{1,31}$/.test(id) || !gap || !gap.name.trim() || gap.name === '미확인'
15
+ || !gap.use.trim() || !Array.isArray(gap.evidence) || !gap.evidence.every(source => typeof source === 'string')
16
+ || !Array.isArray(gap.missingCredentials)) throw new Error('invalid connector gap or id');
17
+ const dir = resolve(inputDir);
18
+ const path = join(dir, 'plugin.json');
19
+ const stat = lstatSync(path, { throwIfNoEntry: false });
20
+ if (!stat?.isFile() || stat.isSymbolicLink() || lstatSync(dir).isSymbolicLink()
21
+ || realpathSync(dir) !== join(realpathSync(dirname(dir)), basename(dir))) {
22
+ throw new Error('plugin.json missing or unsafe');
23
+ }
24
+ const raw: unknown = JSON.parse(readFileSync(path, 'utf8'));
25
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('invalid plugin.json');
26
+ const data = raw as Record<string, unknown>;
27
+ const extensions = data.extensions as Record<string, unknown> | undefined;
28
+ const extension = extensions?.['ai.elanous'];
29
+ if (!extension || typeof extension !== 'object' || Array.isArray(extension)) throw new Error('missing ai.elanous extension');
30
+ const entry = extension as Record<string, unknown>;
31
+ if (entry.connectors !== undefined && !Array.isArray(entry.connectors)) throw new Error('invalid connectors');
32
+ const manifest = loadPluginManifestFromDir(dir, { id: 'local-plugin' }).manifest;
33
+ if (manifest.contributes.connectors?.some(connector => connector.id === id)) throw new Error(`connector already exists: ${id}`);
34
+ const credentials = gap.missingCredentials.filter(name => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(name));
35
+ if (new Set(credentials).size !== credentials.length) throw new Error('duplicate connector credential name');
36
+ entry.connectors = [...(entry.connectors as unknown[] | undefined ?? []), {
37
+ id, fields: credentials.map(name => ({ name, secret: true })),
38
+ }];
39
+ writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
40
+ return path;
41
+ }
@@ -0,0 +1,42 @@
1
+ import { lstatSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
2
+ import { basename, dirname, join, resolve } from 'node:path';
3
+ import { stringify as stringifyYaml } from 'yaml';
4
+ import { loadPluginManifestFromDir } from '../core/manifest.js';
5
+ import type { PluginDraft } from './plugin-maker.js';
6
+
7
+ export interface MakeSkillOptions {
8
+ dir: string;
9
+ gap: PluginDraft['skills'][number];
10
+ id: string;
11
+ }
12
+
13
+ /** Write one researched skill as the wizard's SKILL.md draft, without altering the plugin manifest. */
14
+ export function makeSkill({ dir: inputDir, gap, id }: MakeSkillOptions): string {
15
+ if (!/^[a-z0-9][a-z0-9-]{1,31}$/.test(id) || !gap || !gap.name.trim() || gap.name === '미확인'
16
+ || !gap.use.trim() || !Array.isArray(gap.evidence) || !gap.evidence.every(source => typeof source === 'string')) {
17
+ throw new Error('invalid skill gap or id');
18
+ }
19
+ const dir = resolve(inputDir);
20
+ const manifestPath = join(dir, 'plugin.json');
21
+ const manifestEntry = lstatSync(manifestPath, { throwIfNoEntry: false });
22
+ if (!manifestEntry?.isFile() || manifestEntry.isSymbolicLink()) {
23
+ throw new Error('plugin.json missing or unsafe');
24
+ }
25
+ loadPluginManifestFromDir(dir, { id: 'local-plugin' });
26
+ const skillsDir = join(dir, 'skills');
27
+ const skillDir = join(skillsDir, id);
28
+ const path = join(skillDir, 'SKILL.md');
29
+ // An ancestor can be a platform alias (macOS /var -> /private/var); the plugin directory itself cannot be a link.
30
+ if (lstatSync(dir).isSymbolicLink()
31
+ || realpathSync(dir) !== join(realpathSync(dirname(dir)), basename(dir))) {
32
+ throw new Error('unsafe plugin directory');
33
+ }
34
+ const skillsEntry = lstatSync(skillsDir, { throwIfNoEntry: false });
35
+ if (skillsEntry && !skillsEntry.isDirectory()) throw new Error('unsafe skills directory');
36
+ if (lstatSync(skillDir, { throwIfNoEntry: false })) throw new Error(`skill already exists: ${id}`);
37
+ const instructions = gap.use + (gap.evidence.length ? `\n\nResearch sources:\n${gap.evidence.join(', ')}` : '');
38
+ const content = `---\n${stringifyYaml({ name: id, description: gap.use, requires: [] })}---\n\n${instructions}\n`;
39
+ mkdirSync(skillDir, { recursive: true });
40
+ writeFileSync(path, content, { flag: 'wx' });
41
+ return path;
42
+ }
@@ -0,0 +1,288 @@
1
+ /** Shared PR inventory and creation guard for the CLI and harness. All incomplete reads stay unknown. */
2
+ import { debug } from '../debug/log.js';
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
6
+ import { withFileLockSync } from '../storage/file-lock.js';
7
+ import { resolveHostId } from '../platform/host-id.js';
8
+
9
+ export interface PrToolCommandResult { ok: boolean; out: string; err?: string }
10
+ export type PrToolCommand = (command: string, args: readonly string[], opts?: { cwd?: string }) => PrToolCommandResult;
11
+ export type Seat = 'OP' | 'TC' | 'MK' | 'UX';
12
+ export interface OpenPr {
13
+ number: number;
14
+ title: string;
15
+ draft: boolean;
16
+ updatedAt: string;
17
+ headSha: string;
18
+ labels: readonly string[];
19
+ files: readonly string[];
20
+ seat: Seat | null;
21
+ lastCommitAt?: string;
22
+ cellId: string | null;
23
+ hunks?: readonly DiffHunk[];
24
+ }
25
+ export type Inventory = { status: 'checked'; prs: readonly OpenPr[] } | { status: 'unknown'; reason: string };
26
+ export interface CensusRow { seat: Seat | 'unknown'; open: number; goalOnly: number; staleDraft: number; supersededOpen: number }
27
+ export type Census = { status: 'checked'; total: number; rows: readonly CensusRow[]; closeCandidates: readonly { number: number; reason: 'goal-only' | 'stale-draft' | 'superseded-open' }[] }
28
+ | { status: 'unknown'; reason: string };
29
+ export interface DiffHunk { path: string; start: number; end: number }
30
+ export type GuardCode = 'inventory-unknown' | 'candidate-unknown' | 'goal-only' | 'file-overlap' | 'hunk-overlap' | 'same-cell' | 'seat-cap' | 'seat-unattributed';
31
+ export interface GuardReason { code: GuardCode; detail: string; prs?: readonly number[] }
32
+ export interface GuardVerdict { status: 'allow' | 'refuse' | 'unknown'; reasons: readonly GuardReason[]; warnings: readonly GuardReason[] }
33
+
34
+ const SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
35
+ const DEFAULT_SEAT_CAP = 30;
36
+ const DRAFT_STALE_MS = 2 * 24 * 60 * 60 * 1000;
37
+ const MAX_PAGES = 100;
38
+ const MAX_FILES = 3000; // GitHub does not expose more than 3000 PR files.
39
+ const UNMEASURED_WINDOW_MS = 60 * 60 * 1000;
40
+ const UNMEASURED_ALLOW_COUNT = 3;
41
+
42
+ function unknown(reason: string): Inventory { return { status: 'unknown', reason }; }
43
+ function seatValue(value: unknown): Seat | null { return SEATS.find(seat => seat === value) ?? null; }
44
+ function seatFromLabels(labels: readonly string[]): Seat | null {
45
+ return SEATS.find(seat => labels.includes(`seat:${seat}`)) ?? null;
46
+ }
47
+ export function cellIdFromBody(body: string): string | null {
48
+ return /^\s*(?:[-*]\s*)?칸\s*:\s*([A-Z][A-Z0-9-]{2,})\s*$/m.exec(body)?.[1] ?? null;
49
+ }
50
+
51
+ export function parseDiffHunks(patch: string): DiffHunk[] {
52
+ const hunks: DiffHunk[] = [];
53
+ let path: string | null = null;
54
+ let fileHeaderPending = false;
55
+ for (const line of patch.split('\n')) {
56
+ if (line.startsWith('diff --git ')) { path = null; fileHeaderPending = true; continue; }
57
+ if (fileHeaderPending && line.startsWith('--- ')) {
58
+ if (line.startsWith('--- a/')) path = line.slice('--- a/'.length);
59
+ continue;
60
+ }
61
+ if (fileHeaderPending && line.startsWith('+++ ')) {
62
+ if (line.startsWith('+++ b/')) path = line.slice('+++ b/'.length);
63
+ fileHeaderPending = false;
64
+ continue;
65
+ }
66
+ const match = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(line);
67
+ if (path && match) {
68
+ // This is an approximate comparison of old-side lines; PRs with different
69
+ // base trees can shift line numbers. The full merge gate remains authoritative.
70
+ // An insertion or new file has no old-side lines: use its insertion anchor.
71
+ const oldStart = Number(match[1]);
72
+ const oldCount = match[2] === undefined ? 1 : Number(match[2]);
73
+ const start = oldCount === 0 && oldStart === 0 ? Number(match[3]) : oldStart;
74
+ const count = oldCount === 0 ? 1 : oldCount;
75
+ hunks.push({ path, start, end: start + Math.max(1, count) - 1 });
76
+ }
77
+ }
78
+ return hunks;
79
+ }
80
+
81
+ /** `gh api --paginate --slurp` must return every REST page, including the last page. */
82
+ function pages(run: PrToolCommand, endpoint: string, cwd?: string): readonly unknown[] {
83
+ const result = run('gh', ['api', '--paginate', '--slurp', endpoint], cwd ? { cwd } : undefined);
84
+ if (!result.ok) throw new Error(`gh api ${endpoint}: ${result.err || result.out || '조회 실패'}`);
85
+ let parsed: unknown;
86
+ try { parsed = JSON.parse(result.out); } catch { throw new Error(`gh api ${endpoint}: JSON 오류`); }
87
+ if (!Array.isArray(parsed) || parsed.length >= MAX_PAGES || !parsed.every(page => Array.isArray(page) && page.length <= 100)) {
88
+ throw new Error(`gh api ${endpoint}: 페이지 형식·상한 판정 불가`);
89
+ }
90
+ return parsed.flat();
91
+ }
92
+
93
+ function object(value: unknown): Record<string, unknown> {
94
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('PR 응답 행 형식 오류');
95
+ return value as Record<string, unknown>;
96
+ }
97
+ function text(value: unknown, name: string): string {
98
+ if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} 누락`);
99
+ return value;
100
+ }
101
+ function date(value: unknown, name: string): string {
102
+ const raw = text(value, name);
103
+ if (!Number.isFinite(Date.parse(raw))) throw new Error(`${name} 날짜 오류`);
104
+ return raw;
105
+ }
106
+ function pathsForPr(run: PrToolCommand, number: number, cwd?: string): string[] {
107
+ const rows = pages(run, `repos/{owner}/{repo}/pulls/${number}/files?per_page=100`, cwd);
108
+ if (rows.length >= MAX_FILES) throw new Error(`PR #${number}: 파일 ${MAX_FILES}개 GitHub 상한에 닿음`);
109
+ return rows.map(row => text(object(row).filename, `PR #${number} 파일명`));
110
+ }
111
+
112
+ /** Fast file projection; the REST page census below remains the authority for which PRs exist. */
113
+ function projectedFiles(run: PrToolCommand, count: number, cwd?: string): Map<number, string[]> {
114
+ const result = run('gh', ['pr', 'list', '--state', 'open', '--limit', String(Math.max(count, 1)), '--json', 'number,changedFiles,files'], cwd ? { cwd } : undefined);
115
+ if (!result.ok) return new Map();
116
+ let rows: unknown;
117
+ try { rows = JSON.parse(result.out); } catch { return new Map(); }
118
+ if (!Array.isArray(rows)) return new Map();
119
+ const projection = new Map<number, string[]>();
120
+ for (const value of rows) {
121
+ try {
122
+ const row = object(value);
123
+ if (!Number.isSafeInteger(row.number) || (row.number as number) <= 0 || !Number.isSafeInteger(row.changedFiles) || (row.changedFiles as number) < 0 || !Array.isArray(row.files)) continue;
124
+ const paths = row.files.map(file => text(object(file).path, 'PR 파일명'));
125
+ if (paths.length === row.changedFiles && paths.length < MAX_FILES && !projection.has(row.number as number)) projection.set(row.number as number, paths);
126
+ } catch { /* malformed projection: REST file endpoint below decides this PR */ }
127
+ }
128
+ return projection;
129
+ }
130
+
131
+ export function readOpenPrs(run: PrToolCommand, options: {
132
+ cwd?: string;
133
+ seatOfPr?: (pr: { number: number; headRefName: string; body: string; labels: readonly string[] }) => Seat | null;
134
+ includeDraftCommitDates?: boolean;
135
+ candidateFiles?: readonly string[];
136
+ } = {}): Inventory {
137
+ try {
138
+ const rows = pages(run, 'repos/{owner}/{repo}/pulls?state=open&per_page=100', options.cwd);
139
+ const projected = projectedFiles(run, rows.length, options.cwd);
140
+ const prs: OpenPr[] = [];
141
+ const seen = new Set<number>();
142
+ for (const value of rows) {
143
+ const row = object(value);
144
+ const number = row.number;
145
+ if (!Number.isSafeInteger(number) || (number as number) <= 0 || seen.has(number as number)) throw new Error('PR 번호 누락·중복');
146
+ seen.add(number as number);
147
+ if (row.state !== 'open' || typeof row.draft !== 'boolean') throw new Error(`PR #${number}: OPEN 상태·draft 판정 불가`);
148
+ const head = object(row.head);
149
+ const labels = row.labels;
150
+ if (!Array.isArray(labels)) throw new Error(`PR #${number}: 라벨 판정 불가`);
151
+ const labelNames = labels.map(label => text(object(label).name, `PR #${number} 라벨`));
152
+ const headRefName = text(head.ref, `PR #${number} head ref`);
153
+ const headSha = text(head.sha, `PR #${number} head sha`);
154
+ const body = typeof row.body === 'string' ? row.body : '';
155
+ const seat = seatValue(options.seatOfPr?.({ number: number as number, headRefName, body, labels: labelNames })) ?? seatFromLabels(labelNames);
156
+ const pr: OpenPr = {
157
+ number: number as number, title: text(row.title, `PR #${number} title`), draft: row.draft,
158
+ updatedAt: date(row.updated_at, `PR #${number} updated_at`), headSha, labels: labelNames,
159
+ files: projected.get(number as number) ?? pathsForPr(run, number as number, options.cwd), seat,
160
+ cellId: cellIdFromBody(body),
161
+ };
162
+ if (options.candidateFiles?.some(file => pr.files.includes(file))) {
163
+ const patch = run('gh', ['pr', 'diff', String(number), '--patch'], options.cwd ? { cwd: options.cwd } : undefined);
164
+ if (!patch.ok) throw new Error(`PR #${number}: 수정 줄 조회 실패: ${patch.err || patch.out}`);
165
+ pr.hunks = parseDiffHunks(patch.out);
166
+ }
167
+ if (pr.draft && options.includeDraftCommitDates) {
168
+ const commit = run('gh', ['api', `repos/{owner}/{repo}/commits/${headSha}`, '--jq', '.commit.committer.date'], options.cwd ? { cwd: options.cwd } : undefined);
169
+ if (!commit.ok) throw new Error(`PR #${number}: 마지막 커밋 날짜 조회 실패: ${commit.err || commit.out}`);
170
+ pr.lastCommitAt = date(commit.out.trim(), `PR #${number} 마지막 커밋`);
171
+ }
172
+ prs.push(pr);
173
+ }
174
+ return { status: 'checked', prs };
175
+ } catch (error) {
176
+ return unknown(error instanceof Error ? error.message : String(error));
177
+ }
178
+ }
179
+
180
+ export function isGoalOnly(files: readonly string[]): boolean {
181
+ return files.length > 0 && files.every(path => path.startsWith('docs/goals/') && path.length > 'docs/goals/'.length);
182
+ }
183
+
184
+ export function censusOpenPrs(inventory: Inventory, now = Date.now()): Census {
185
+ if (inventory.status === 'unknown') {
186
+ debug.log('pr.tool', 'census', { status: 'unknown', reason: inventory.reason });
187
+ return inventory;
188
+ }
189
+ const rows = new Map<Seat | 'unknown', CensusRow>();
190
+ const closeCandidates: Array<{ number: number; reason: 'goal-only' | 'stale-draft' | 'superseded-open' }> = [];
191
+ for (const pr of inventory.prs) {
192
+ const key = pr.seat ?? 'unknown';
193
+ const row = rows.get(key) ?? { seat: key, open: 0, goalOnly: 0, staleDraft: 0, supersededOpen: 0 };
194
+ row.open += 1;
195
+ if (isGoalOnly(pr.files)) { row.goalOnly += 1; closeCandidates.push({ number: pr.number, reason: 'goal-only' }); }
196
+ if (pr.draft) {
197
+ if (!pr.lastCommitAt) {
198
+ const reason = `PR #${pr.number}: draft 마지막 커밋 날짜 없음`;
199
+ debug.log('pr.tool', 'census', { status: 'unknown', reason });
200
+ return { status: 'unknown', reason };
201
+ }
202
+ if (now - Date.parse(pr.lastCommitAt) >= DRAFT_STALE_MS) { row.staleDraft += 1; closeCandidates.push({ number: pr.number, reason: 'stale-draft' }); }
203
+ }
204
+ if (pr.labels.includes('elanous:superseded')) { row.supersededOpen += 1; closeCandidates.push({ number: pr.number, reason: 'superseded-open' }); }
205
+ rows.set(key, row);
206
+ }
207
+ const result: Census = { status: 'checked', total: inventory.prs.length, rows: [...rows.values()], closeCandidates };
208
+ debug.log('pr.tool', 'census', { status: 'checked', total: result.total, candidates: closeCandidates.length });
209
+ return result;
210
+ }
211
+
212
+ export function guardNewPr(input: { files: readonly string[] | null; seat?: Seat | null; seatCap?: number; cellId?: string | null; hunks?: readonly DiffHunk[] }, inventory: Inventory): GuardVerdict {
213
+ if (!input.files || input.files.length === 0 || input.files.some(file => !file || file.startsWith('/') || file.includes('..'))) {
214
+ const reasons: GuardReason[] = [{ code: 'candidate-unknown', detail: '새 PR 변경 파일을 확인할 수 없음' }];
215
+ debug.log('pr.tool', 'guard-refuse', { status: 'unknown', reasons });
216
+ return { status: 'unknown', reasons, warnings: [] };
217
+ }
218
+ if (inventory.status === 'unknown') {
219
+ const reasons: GuardReason[] = [{ code: 'inventory-unknown', detail: inventory.reason }];
220
+ return { status: 'unknown', reasons, warnings: [] };
221
+ }
222
+ const reasons: GuardReason[] = [];
223
+ const warnings: GuardReason[] = [];
224
+ if (isGoalOnly(input.files)) reasons.push({ code: 'goal-only', detail: '골 문서만 변경 · 구현 0' });
225
+ const candidate = new Set(input.files);
226
+ const sameCell = input.cellId ? inventory.prs.filter(pr => pr.cellId === input.cellId) : [];
227
+ if (sameCell.length) reasons.push({ code: 'same-cell', detail: `같은 칸 ${input.cellId} OPEN PR이 있음`, prs: sameCell.map(pr => pr.number) });
228
+ const overlaps = inventory.prs.filter(pr => pr.files.some(file => candidate.has(file)));
229
+ const sameHunk = overlaps.filter(pr => pr.hunks?.some(other => input.hunks?.some(own => own.path === other.path && own.start <= other.end && other.start <= own.end)));
230
+ if (sameHunk.length) reasons.push({ code: 'hunk-overlap', detail: '같은 파일의 수정 줄 범위가 겹침', prs: sameHunk.map(pr => pr.number) });
231
+ if (overlaps.length) warnings.push({ code: 'file-overlap', detail: '같은 파일의 OPEN PR이 있음 · 줄 겹침은 별도 판정', prs: overlaps.map(pr => pr.number) });
232
+ const seat = seatValue(input.seat);
233
+ if (input.seat !== undefined && input.seat !== null && !seat) reasons.push({ code: 'candidate-unknown', detail: '호출자 자리 값 오류' });
234
+ const cap = input.seatCap ?? DEFAULT_SEAT_CAP;
235
+ if (!Number.isSafeInteger(cap) || cap < 1) {
236
+ reasons.push({ code: 'candidate-unknown', detail: '자리별 PR 상한 설정 오류' });
237
+ } else if (!seat) {
238
+ warnings.push({ code: 'seat-unattributed', detail: `호출자 자리 미상 · 전체 OPEN PR ${inventory.prs.length}건` });
239
+ } else {
240
+ const count = inventory.prs.filter(pr => pr.seat === seat).length;
241
+ if (count >= cap) warnings.push({ code: 'seat-cap', detail: `${seat} OPEN PR ${count}건 · 상한 ${cap}` });
242
+ const unattributed = inventory.prs.filter(pr => pr.seat === null).length;
243
+ if (unattributed) warnings.push({ code: 'seat-unattributed', detail: `귀속 미상 ${unattributed}건 · 전체 OPEN PR ${inventory.prs.length}건` });
244
+ }
245
+ const status = reasons.some(reason => reason.code === 'candidate-unknown') ? 'unknown' : reasons.length ? 'refuse' : 'allow';
246
+ if (status !== 'allow') debug.log('pr.tool', 'guard-refuse', { status, reasons, warnings });
247
+ else if (warnings.length) debug.log('pr.tool', 'guard-warn', { warnings });
248
+ return { status, reasons, warnings };
249
+ }
250
+
251
+ /** Persist the unknown-read budget across harness processes sharing one instance state root. */
252
+ export function recordGuardUnmeasured(input: { seat: Seat | null; reason: string; stateRoot?: string; host?: string; now?: number }): { count: number; blocked: boolean; reason?: string } {
253
+ const now = input.now ?? Date.now();
254
+ const seat = input.seat ?? 'unknown';
255
+ const host = input.host ?? resolveHostId();
256
+ try {
257
+ const dir = join(input.stateRoot ?? effectiveInstanceRoot(), 'pr-tool');
258
+ mkdirSync(dir, { recursive: true });
259
+ const file = join(dir, 'guard-unmeasured.jsonl');
260
+ return withFileLockSync(`${file}.lock`, () => {
261
+ const rows = existsSync(file) ? readFileSync(file, 'utf8').split('\n').filter(Boolean) : [];
262
+ const retained: Array<{ at: number; seat: string; host: string }> = [];
263
+ let count = 0;
264
+ for (const line of rows) {
265
+ let value: unknown;
266
+ try { value = JSON.parse(line); } catch { return { count: 0, blocked: true, reason: '판정 불가 원장 JSON 오류' }; }
267
+ if (value && typeof value === 'object') {
268
+ const row = value as { at?: unknown; seat?: unknown; host?: unknown };
269
+ if (typeof row.at !== 'number' || typeof row.seat !== 'string' || typeof row.host !== 'string') return { count: 0, blocked: true, reason: '판정 불가 원장 행 형식 오류' };
270
+ if (row.at > now - UNMEASURED_WINDOW_MS && row.at <= now) {
271
+ retained.push({ at: row.at, seat: row.seat, host: row.host });
272
+ if (row.seat === seat && row.host === host) count += 1;
273
+ }
274
+ } else return { count: 0, blocked: true, reason: '판정 불가 원장 행 형식 오류' };
275
+ }
276
+ retained.push({ at: now, seat, host });
277
+ count += 1;
278
+ writeFileSync(file, `${retained.map(row => JSON.stringify(row)).join('\n')}\n`);
279
+ const blocked = count > UNMEASURED_ALLOW_COUNT;
280
+ debug.log('pr-tool.open-guard', 'guard-unmeasured', { seat, host, count, blocked, reason: input.reason });
281
+ return { count, blocked };
282
+ });
283
+ } catch (error) {
284
+ const reason = error instanceof Error ? error.message : String(error);
285
+ debug.log('pr-tool.open-guard', 'guard-unmeasured', { seat, host, blocked: true, reason: `원장 오류: ${reason}` });
286
+ return { count: 0, blocked: true, reason };
287
+ }
288
+ }
@@ -39,6 +39,19 @@ useful answers instead of narrated progress.
39
39
  - Group related actions into one short preamble instead of emitting
40
40
  a new status line before every command.
41
41
 
42
+ ## Initiative
43
+
44
+ - Act first: when looking (repo, logs, tools) can answer or advance the
45
+ request, do that before asking, and answer with what you found or did.
46
+ - Ambiguous request: take the most plausible reading, proceed, and state
47
+ the assumption in one line. Ask first only when a wrong guess would be
48
+ costly or hard to undo.
49
+ - Finish forward: end with up to 3 concrete next steps. When one is
50
+ obvious, cheap and inside the request, continue and do it instead of
51
+ offering it.
52
+ - A stop always comes with a path: when you decline or cannot finish, say
53
+ what you will do instead or what would unblock it.
54
+
42
55
  ## Terminal formatting
43
56
 
44
57
  - Use monospace CommonMark for commands, paths, env vars, and code ids.
@@ -104,10 +104,13 @@ execute the next stage; your tool calls are the audit trail.
104
104
 
105
105
  ## Analysis (분석) — find → read → organize
106
106
  When a user's analysis question identifies a concrete, user-fixable code or
107
- configuration defect, end the organized answer with a clear next-action CTA:
108
- ask whether they want the discovered fix implemented (for example,
109
- \`수정할까요?\`). Do not ask this when no actionable defect was found, and do
110
- not claim a change was made before it is implemented and verified.
107
+ configuration defect: if the fix is small, low-risk and inside what the user
108
+ asked about, make it — switch to the Implementation pipeline, verify it, then
109
+ report what changed. Otherwise end the organized answer with 1-3 concrete
110
+ next actions and ask only the one decision that is really the user's (for
111
+ example, \`이 세 곳을 고칠까요?\` / \`수정할까요?\`). Do not ask when no actionable
112
+ defect was found, and do not claim a change was made before it is implemented
113
+ and verified.
111
114
  1. **find**: ONE batch of search tools (Grep / Glob / ListDir / AstGrep
112
115
  in parallel) to locate candidate files. Do not run a second \`find\`
113
116
  batch unless the first returned ZERO useful candidates — if it
@@ -144,7 +147,9 @@ not claim a change was made before it is implemented and verified.
144
147
  produces candidate paths. Do not issue a second \`find\` batch
145
148
  searching the SAME paths/globs with different keywords — the
146
149
  candidates are already on the table; advance to \`read\`.
147
- - For Analysis: stop at \`organize\`. Don't drift into edit/exec.
150
+ - For Analysis: end at \`organize\` unless a small, low-risk fix inside the
151
+ request is ready — then switch to Implementation (edit → verify). Larger or
152
+ out-of-scope changes stay a proposal.
148
153
  - For Implementation/Debugging: \`verify\` is mandatory. "I made the
149
154
  change" without verification is incomplete output.
150
155
  - Pick a pipeline ONLY when you actually need to use it. Pure conversational
@@ -0,0 +1,97 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { psProcessStartMs } from '../harness/harness-stop.js';
5
+ import { debug } from '../debug/log.js';
6
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
7
+
8
+ interface GateHostClaim {
9
+ token: string;
10
+ runId: string;
11
+ hosts: string[];
12
+ pid: number;
13
+ pidStartedAt: number | null;
14
+ }
15
+
16
+ export type GateHostReservation =
17
+ | { status: 'free' }
18
+ | { status: 'reserved' | 'unknown'; reason: string; runId?: string };
19
+
20
+ const hostName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
21
+ const claimsDir = (root: string) => join(root, 'release', 'gate-host-reservations');
22
+
23
+ /** The release graph's pinned child state and the self gate CLI's selected universe resolve through this same entry. */
24
+ export function gateHostReservationRoot(): string { return effectiveInstanceRoot(); }
25
+
26
+ function claimAlive(claim: GateHostClaim): 'alive' | 'dead' | 'unknown' {
27
+ try { process.kill(claim.pid, 0); }
28
+ catch (error) {
29
+ return (error as NodeJS.ErrnoException).code === 'ESRCH' ? 'dead' : 'unknown';
30
+ }
31
+ if (claim.pidStartedAt === null) return 'unknown';
32
+ const current = psProcessStartMs(claim.pid);
33
+ if (current === null) return 'unknown';
34
+ return Math.abs(current - claim.pidStartedAt) <= 2_000 ? 'alive' : 'dead';
35
+ }
36
+
37
+ /** A gate owns its host until its node exits. A crashed owner's claim is removed on the next read. */
38
+ export function reserveReleaseGateHosts(root: string, runId: string, hosts: readonly string[]): () => void {
39
+ const unique = [...new Set(hosts)];
40
+ if (!runId || unique.some(host => host !== '*' && !hostName.test(host))) throw new Error('invalid release gate reservation');
41
+ if (!unique.length) return () => undefined;
42
+ const dir = claimsDir(root);
43
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
44
+ const token = randomUUID();
45
+ const pidStartedAt = psProcessStartMs(process.pid);
46
+ if (pidStartedAt === null) throw new Error('release gate owner start time unmeasured');
47
+ const claim: GateHostClaim = { token, runId, hosts: unique, pid: process.pid, pidStartedAt };
48
+ const path = join(dir, `${token}.json`);
49
+ const temp = join(dir, `.${token}.tmp`);
50
+ try {
51
+ writeFileSync(temp, JSON.stringify(claim) + '\n', { mode: 0o600, flag: 'wx' });
52
+ renameSync(temp, path);
53
+ } finally { if (existsSync(temp)) rmSync(temp); }
54
+ debug.log('release-loop.gate', 'host-reserved', { runId, hosts: unique, pid: process.pid, path });
55
+ return () => {
56
+ try {
57
+ const current = JSON.parse(readFileSync(path, 'utf8')) as Partial<GateHostClaim>;
58
+ if (current.token === token) rmSync(path);
59
+ debug.log('release-loop.gate', 'host-released', { runId, hosts: unique, path });
60
+ } catch (error) {
61
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT')
62
+ debug.log('release-loop.gate', 'host-release-unmeasured', { runId, path, error: String(error) });
63
+ }
64
+ };
65
+ }
66
+
67
+ /** An unreadable claim is a reservation, never permission to enter a gate host. */
68
+ export function inspectReleaseGateHost(root: string, host: string): GateHostReservation {
69
+ const dir = claimsDir(root);
70
+ let names: string[];
71
+ try { names = readdirSync(dir).filter(name => name.endsWith('.json')); }
72
+ catch (error) {
73
+ return { status: 'unknown', reason: `reservation directory unreadable: ${String(error)}` };
74
+ }
75
+ for (const name of names) {
76
+ const path = join(dir, name);
77
+ let claim: GateHostClaim;
78
+ try {
79
+ claim = JSON.parse(readFileSync(path, 'utf8')) as GateHostClaim;
80
+ if (!claim || !Array.isArray(claim.hosts) || claim.hosts.length === 0
81
+ || !claim.hosts.every(item => typeof item === 'string' && (item === '*' || hostName.test(item)))
82
+ || !Number.isSafeInteger(claim.pid) || claim.pid <= 0 || typeof claim.token !== 'string'
83
+ || typeof claim.runId !== 'string' || !claim.runId
84
+ || (claim.pidStartedAt !== null && (!Number.isSafeInteger(claim.pidStartedAt)
85
+ || claim.pidStartedAt <= 0 || claim.pidStartedAt > Date.now()))) throw new Error('invalid claim');
86
+ } catch (error) { return { status: 'unknown', reason: `reservation unreadable: ${name}: ${String(error)}` }; }
87
+ const live = claimAlive(claim);
88
+ if (live === 'dead') {
89
+ try { rmSync(path); } catch { /* a confirmed dead process cannot still own the host */ }
90
+ debug.log('release-loop.gate', 'host-claim-reclaimed', { runId: claim.runId, hosts: claim.hosts, path });
91
+ continue;
92
+ }
93
+ if (!claim.hosts.includes(host) && !claim.hosts.includes('*')) continue;
94
+ return { status: live === 'unknown' ? 'unknown' : 'reserved', reason: `release gate ${claim.runId} holds ${host}`, runId: claim.runId };
95
+ }
96
+ return { status: 'free' };
97
+ }
@@ -36,6 +36,11 @@ export function readLandingFreeze(root = effectiveInstanceRoot(), now = new Date
36
36
  return { ...freeze, holdLaunches: freeze.holdLaunches ?? false } as LandingFreeze;
37
37
  }
38
38
 
39
+ /** Interpret a validated, expiry-aware read without reading the freeze file twice. */
40
+ export function landingFreezeState(freeze: LandingFreeze | null): 'on' | 'off' {
41
+ return freeze === null ? 'off' : 'on';
42
+ }
43
+
39
44
  export function enableLandingFreeze(opts: { reason?: string; until?: string; by?: string; holdLaunches?: boolean }, root = effectiveInstanceRoot(), now = new Date()): LandingFreeze {
40
45
  const until = opts.until === undefined ? null : opts.until;
41
46
  if (until !== null && (!/^\d{4}-\d\d-\d\dT\d\d:\d\d(?::\d\d(?:\.\d+)?)?(?:Z|[+-]\d\d:\d\d)$/.test(until) || !Number.isFinite(Date.parse(until)) || Date.parse(until) <= now.getTime())) {
@@ -29,6 +29,9 @@ export interface LightRcOptions {
29
29
  /** Run on this machine (the remote child is re-invoked with it). */
30
30
  local?: boolean;
31
31
  shards?: number;
32
+ /** OP FU — pass `--fixed-shard-distribution` to self gate (sorted round-robin into `shards`, no RSS pre-measurement).
33
+ * Opt-in; absent = the measured planner, unchanged. Also carried to the remote child. */
34
+ fixedShardDistribution?: boolean;
32
35
  /** Release ledger root for the previous-version lookup (release run's deps.ledgerRoot). */
33
36
  ledgerRoot?: string;
34
37
  log?: (line: string) => void;
@@ -192,7 +195,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
192
195
  try {
193
196
  const dir = checkout?.dir ?? cwd;
194
197
  if (checkout) alwaysInclude = readList(dir);
195
- local = (deps.runGate ?? runSelfGateCli)(dir, { base, shards, alwaysInclude, includeImporterTests: true });
198
+ local = (deps.runGate ?? runSelfGateCli)(dir, { base, shards, ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), alwaysInclude, includeImporterTests: true });
196
199
  if (opts.rehearsalTui) {
197
200
  const command = async (cmd: string, args: string[], tree: string, limitMs?: number) => {
198
201
  const run = spawnSync(cmd, args, { cwd: tree, encoding: 'utf8', timeout: limitMs });
@@ -208,7 +211,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
208
211
  const rc = await (deps.dispatch ?? dispatchHeavyCheck)({
209
212
  tool: 'self-gate', repo: cwd, installPwa: true, refs: [base], json: true, commit: measuredCommit,
210
213
  // The host re-runs this command with --local (and ELANOUS_GATE_REMOTE_CHILD=1), so it never recurses.
211
- remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
214
+ remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), ...(opts.fixedShardDistribution ? ['--fixed-shard-distribution'] : []), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
212
215
  flags: { remote: opts.local ? undefined : opts.remote ?? true, local: !!opts.local },
213
216
  runLocal,
214
217
  }, {