elanous 0.2.32 → 0.2.35

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 (753) 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/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 0368f25d-ad84af92fefee68f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 1530.0e612369b6fd7ea0.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
  9. package/apps/pwa/out/_next/static/chunks/{7391.ebae168025c91b6a.js → 1674.2a65fd5668e1cc5f.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
  11. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
  12. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{7947-d0759430f8042240.js → 1993-c0007b7ad0c0ef41.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{60fb96c9.360b01d8d4927b7b.js → 1c735de4.f993a30bbd3c57c4.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 2018.a741297bce759490.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
  23. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{3902.e1e71aaac850a045.js → 2625.5d870aa999f33db1.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
  26. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
  31. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 3408.21d1570602f4b6c0.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 3677-4215f826f6aa68e5.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
  40. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
  42. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{7371.80c05c653b08e907.js → 4346.8601952e73bf5803.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
  46. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
  49. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 4718-17d2af636796a330.js} +3 -3
  51. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/{2001.6c7e0fd02190886c.js → 5154.a118f3957ed14e36.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
  61. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 5483-dd5d7697f6bdb106.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
  63. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3267c0e6.d34854e7b3984a6e.js → 56d372f2.681ab4ec4c998fae.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +287 -0
  67. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 6236.e18cced2d5ba6afb.js} +17 -17
  74. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
  78. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
  80. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6544cb48.a87fe20ddf137be2.js → 6b89c8bd.24df687a820500b3.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
  87. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
  88. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 7644.17e37ba6f1d4226e.js} +4 -4
  90. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{8018.a32663f04a6fc5f9.js → 8219.baa715d1deee80e2.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/{4111.2bfedbb233ad206b.js → 8256.e3ac8421a71f82f4.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 8444.4c26b379ca2b9596.js} +17 -17
  100. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
  101. package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
  104. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 8637.47f5b35afcae5e6b.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9214.63a510d39178e997.js} +2 -2
  111. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
  112. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 9512.5a76207a730e0491.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{69-0a2c8209c6d4a158.js → 967-2aa39b2d04b4c690.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 9952.5daf5f94063a2b3e.js} +1 -1
  120. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/{page-a27b1e5a0d1b308f.js → page-406b47745b53f269.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-32866485913d6a04.js → page-47c5d4db587266bd.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-dc0a532f5b9196ec.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → da5176c6.6773b6c5994e1d99.js} +7 -7
  178. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.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/bin/elanous.mjs +10 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/README.md +5 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +76 -5
  285. package/graphs/document-loop.yaml +71 -4
  286. package/graphs/implement-loop.yaml +59 -4
  287. package/graphs/journey/SCENARIOS.md +33 -0
  288. package/graphs/journey/recipes.yaml +1 -0
  289. package/graphs/journey/ta-journey.yaml +94 -0
  290. package/graphs/journey/units/author/author.yaml +20 -0
  291. package/graphs/journey/units/author/recipes.yaml +2 -0
  292. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  293. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  294. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  295. package/graphs/journey/units/green/green.yaml +20 -0
  296. package/graphs/journey/units/green/recipes.yaml +2 -0
  297. package/graphs/journey/units/pr/pr.yaml +20 -0
  298. package/graphs/journey/units/pr/recipes.yaml +2 -0
  299. package/graphs/journey/units/remember/recipes.yaml +2 -0
  300. package/graphs/journey/units/remember/remember.yaml +20 -0
  301. package/graphs/operate-loop.yaml +71 -4
  302. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  303. package/graphs/release-rehearsal/recipes.yaml +1 -1
  304. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  305. package/graphs/research-loop.yaml +159 -4
  306. package/graphs/test-diet/test-diet.yaml +3 -0
  307. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  308. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  309. package/graphs/units/entry/entry.yaml +50 -0
  310. package/graphs/units/entry/recipes.yaml +14 -0
  311. package/graphs/units/harvest/harvest.yaml +25 -0
  312. package/graphs/units/harvest/recipes.yaml +4 -0
  313. package/graphs/units/land/land.yaml +45 -0
  314. package/graphs/units/land/recipes.yaml +3 -0
  315. package/graphs/units/recipes.yaml +7 -0
  316. package/graphs/units/recover.yaml +39 -0
  317. package/graphs/units/reflect/recipes.yaml +3 -0
  318. package/graphs/units/reflect/reflect.yaml +15 -0
  319. package/graphs/units/task-agent-recover-review.yaml +17 -0
  320. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  321. package/graphs/units/verbs/make-doc.yaml +34 -0
  322. package/graphs/units/verbs/recipes.yaml +33 -0
  323. package/graphs/units/verbs/verify.yaml +55 -0
  324. package/graphs/work/recipes.yaml +2 -0
  325. package/graphs/work/research-report.yaml +28 -0
  326. package/package.json +1 -1
  327. package/scripts/ci-typecheck-changed.ts +69 -16
  328. package/scripts/coord-role-pack.ts +19 -6
  329. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  330. package/scripts/graph-harvest-unit.ts +22 -0
  331. package/scripts/graph-units/journey-stub.ts +6 -0
  332. package/scripts/graph-units/land-enqueue.ts +78 -0
  333. package/scripts/graph-units/recover-plan.ts +15 -0
  334. package/scripts/graph-units/reflect-node.ts +88 -0
  335. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  336. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  337. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  338. package/scripts/graph-units/verbs-envelope.ts +139 -0
  339. package/scripts/hq/standby-snapshot.ts +30 -0
  340. package/scripts/public-export.ts +43 -1
  341. package/scripts/ratchets/train-side-invariants.sh +45 -0
  342. package/scripts/release-loop/auto-approve-node.ts +30 -16
  343. package/scripts/release-loop/docs-land-node.ts +21 -5
  344. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  345. package/scripts/release-loop/gate-closure.ts +5 -1
  346. package/scripts/release-loop/gate-diff.ts +1 -1
  347. package/scripts/release-loop/gate-node.ts +675 -49
  348. package/scripts/release-loop/gate-partial.ts +68 -14
  349. package/scripts/release-loop/gate-radius-live.ts +177 -0
  350. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  351. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  352. package/scripts/release-loop/gate-triage-node.ts +5 -2
  353. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  354. package/scripts/release-loop/known-issues-node.ts +77 -8
  355. package/scripts/release-loop/node-verdict.ts +12 -1
  356. package/scripts/release-loop/npm-publish-node.ts +66 -12
  357. package/scripts/release-loop/preflight.ts +93 -7
  358. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  359. package/scripts/release-loop/publish-node.ts +60 -9
  360. package/scripts/release-loop/pwa-remote.ts +166 -0
  361. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  362. package/scripts/release-loop/resume-cap.ts +56 -0
  363. package/scripts/release-loop/resume-release.ts +155 -19
  364. package/scripts/release-loop/resume.ts +24 -1
  365. package/scripts/release-loop/tui-sim-node.ts +8 -2
  366. package/scripts/release-loop/unattended-release.ts +10 -2
  367. package/scripts/test-diet/lib.ts +6 -1
  368. package/scripts/test-diet/node.ts +194 -13
  369. package/scripts/ux-sim.ts +39 -0
  370. package/src/acp/core-turn-bridge.ts +20 -5
  371. package/src/acp/reasoning-thought-buffer.ts +45 -0
  372. package/src/agent/self-ambient-cache.ts +8 -0
  373. package/src/agent-substrate/acp-reviewer.ts +90 -15
  374. package/src/agent-substrate/pr-reviewer.ts +17 -0
  375. package/src/agent-substrate/review-finding-key.ts +53 -0
  376. package/src/agent-substrate/self-review-cli.ts +188 -18
  377. package/src/ask-user-question/pending-questions.ts +1 -1
  378. package/src/autopilot/pr-manager.ts +393 -65
  379. package/src/budget/run-usage-rollup.ts +1 -0
  380. package/src/chat/index.ts +0 -2
  381. package/src/chat/pickers/modal-runtime.ts +10 -27
  382. package/src/chat/tool-render/dispatch.ts +62 -10
  383. package/src/cli/agent-cli.ts +13 -2
  384. package/src/cli/control-cli.ts +24 -7
  385. package/src/cli/doctor-cli.ts +4 -1
  386. package/src/cli/guardian-cli.ts +10 -0
  387. package/src/cli/light-entry-route.ts +75 -0
  388. package/src/cli/llm-detect-cli.ts +23 -1
  389. package/src/cli/pod-cli.ts +77 -3
  390. package/src/cli/pr-cli.ts +81 -14
  391. package/src/cli/pr-land-base-read.ts +2 -0
  392. package/src/cli/pr-land-overlap-evidence.ts +154 -16
  393. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  394. package/src/cli/pr-land-recovery.ts +64 -0
  395. package/src/cli/pty-takeover-cli.ts +6 -5
  396. package/src/cli/release-checklist-read-cli.ts +79 -0
  397. package/src/cli/release-cli.ts +189 -132
  398. package/src/cli/release-run-if-ready.ts +29 -28
  399. package/src/cli/release-single-flight.ts +178 -0
  400. package/src/cli/remote-resolve.ts +1 -1
  401. package/src/cli/root-tui-entry.ts +48 -0
  402. package/src/cli/seat-cli.ts +37 -0
  403. package/src/cli/setup-cli.ts +40 -1
  404. package/src/cli/sim-cli.ts +22 -0
  405. package/src/cli/tasks-cli.ts +667 -14
  406. package/src/cli/usage-cli.ts +13 -11
  407. package/src/clipboard/history.ts +179 -13
  408. package/src/config.ts +8 -1
  409. package/src/control/control-status.ts +8 -3
  410. package/src/control-plane/ledger.ts +5 -3
  411. package/src/control-plane/server.ts +5 -3
  412. package/src/core-turn/short-question.ts +5 -1
  413. package/src/dashboard/chat/acp-chat.ts +8 -0
  414. package/src/dashboard/index.ts +114 -77
  415. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  416. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  417. package/src/dashboard/input/seat-autowake.ts +56 -3
  418. package/src/dashboard/render/theme-resolver.ts +33 -4
  419. package/src/dashboard/seat-boot-preamble.ts +1 -1
  420. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  421. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  422. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  423. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  424. package/src/dashboard/turn-preamble.ts +47 -1
  425. package/src/dashboard/turn-stream-formatter.ts +34 -1
  426. package/src/dashboard/turn-stream-runtime.ts +2 -0
  427. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  428. package/src/domains/guardian-tick.ts +54 -2
  429. package/src/domains/outbound-alert.ts +3 -2
  430. package/src/domains/schedule-registry.ts +16 -2
  431. package/src/extractors.ts +3 -1
  432. package/src/git-fs/idle-refresh.ts +76 -0
  433. package/src/git-fs/index.ts +18 -7
  434. package/src/git-fs/retry.ts +4 -0
  435. package/src/git-fs/runner.ts +2 -0
  436. package/src/git-fs/worktree.ts +42 -4
  437. package/src/graph-kinds/registry.ts +2 -2
  438. package/src/graph-runner/runner.ts +267 -54
  439. package/src/grok/credential.ts +15 -3
  440. package/src/harness/harness-cli-command.ts +151 -38
  441. package/src/harness/harness-incidents.ts +37 -0
  442. package/src/harness/harness-pod-dispatch.ts +38 -1
  443. package/src/harness/harness-salvage-cli.ts +14 -2
  444. package/src/harness/launch-utterance-ledger.ts +208 -0
  445. package/src/impl-discipline/detector.ts +16 -4
  446. package/src/impl-discipline/system-prompt.ts +11 -0
  447. package/src/impl-discipline/types.ts +2 -2
  448. package/src/index.ts +683 -146
  449. package/src/intake-plane/already-built-hint.ts +91 -0
  450. package/src/intake-plane/requirement-funnel.ts +29 -1
  451. package/src/knowhow/pack.ts +199 -0
  452. package/src/light-cli.ts +111 -0
  453. package/src/llm/opengateway-models.ts +11 -0
  454. package/src/llm/provider-credentials.ts +14 -0
  455. package/src/llm/provider-detect.ts +8 -1
  456. package/src/llm/runtime-model-family.ts +2 -1
  457. package/src/llm.ts +268 -65
  458. package/src/loops/budget.ts +95 -0
  459. package/src/loops/msg-wake.ts +8 -2
  460. package/src/loops/orchestrator/traffic.ts +132 -1
  461. package/src/model-tier/llm-tier-map.ts +15 -1
  462. package/src/mss/logging/log-store.ts +4 -5
  463. package/src/native-tool-catalog.ts +15 -1
  464. package/src/nexus/api/graphs-api.ts +22 -3
  465. package/src/nexus/api/http-server.ts +1 -1
  466. package/src/nexus/api/loop-resources.ts +13 -1
  467. package/src/nexus/api/ops-api.ts +12 -0
  468. package/src/oauth/claude-pty-maturity.ts +66 -0
  469. package/src/oauth/codex-access-mirror.ts +55 -0
  470. package/src/oauth/codex.ts +7 -0
  471. package/src/oauth/fallback-chain.ts +1 -1
  472. package/src/onboarding/first-run.ts +5 -3
  473. package/src/onboarding/non-interactive.ts +64 -13
  474. package/src/onboarding.ts +10 -2
  475. package/src/ops/overview-collect.ts +54 -4
  476. package/src/ops/overview.ts +31 -7
  477. package/src/pr-tool/census.ts +282 -30
  478. package/src/pr-tool/inflight-registry.ts +160 -7
  479. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  480. package/src/pty-shell/herdr-agent-report.ts +442 -0
  481. package/src/pty-shell/pty-control-ipc.ts +5 -5
  482. package/src/pty-shell/pty-manifest.ts +7 -0
  483. package/src/pty-shell/pty-write-outcome.ts +24 -6
  484. package/src/pty-shell/tui-run-state.ts +117 -3
  485. package/src/release-loop/checklist.ts +103 -5
  486. package/src/release-loop/feature-store.ts +19 -2
  487. package/src/release-loop/landed-but-yellow.ts +129 -5
  488. package/src/release-loop/light-rc.ts +1 -0
  489. package/src/release-loop/placement.ts +10 -3
  490. package/src/release-loop/rehearsal.ts +205 -25
  491. package/src/release-loop/rubric.ts +16 -2
  492. package/src/repl/index.ts +174 -17
  493. package/src/repl/ops-msg-bridge.ts +32 -0
  494. package/src/self-dev/ask-launch-flow.ts +44 -5
  495. package/src/self-dev/cli-help-text.ts +17 -0
  496. package/src/self-dev/dev-cli.ts +11 -9
  497. package/src/self-dev/draft-residue.ts +37 -1
  498. package/src/self-dev/draft-sweep.ts +188 -13
  499. package/src/self-dev/draft-triage-rules.ts +107 -0
  500. package/src/self-dev/fleet-reduce.ts +3 -2
  501. package/src/self-dev/graph-front-nodes.ts +112 -0
  502. package/src/self-dev/graph-journey-nodes.ts +11 -6
  503. package/src/self-dev/graph-journey-route.ts +60 -6
  504. package/src/self-dev/harness-run-cli.ts +3 -15
  505. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  506. package/src/self-dev/orchestrate.ts +79 -3
  507. package/src/self-dev/review-provider-fallback.ts +35 -1
  508. package/src/self-dev/run-supervisor.ts +107 -12
  509. package/src/self-dev/run-types.ts +5 -1
  510. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  511. package/src/self-dev/shard-aggregate.ts +42 -5
  512. package/src/self-dev/shard-run.ts +8 -1
  513. package/src/self-implement/blocked-draft-policy.ts +20 -0
  514. package/src/self-implement/classify-shadow.ts +3 -7
  515. package/src/self-implement/doctor-visit.ts +18 -1
  516. package/src/self-implement/gate-baseline.ts +95 -12
  517. package/src/self-implement/gate-cli.ts +1 -0
  518. package/src/self-implement/gate-remote.ts +40 -25
  519. package/src/self-implement/goal-author-decompose.ts +275 -47
  520. package/src/self-implement/goal-author-identity.ts +66 -0
  521. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  522. package/src/self-implement/goal-author.ts +254 -120
  523. package/src/self-implement/goal-elaborate.ts +295 -0
  524. package/src/self-implement/goal-refine.ts +270 -0
  525. package/src/self-implement/graph-overlay-yaml.ts +28 -2
  526. package/src/self-implement/graph-unit-flatten.ts +103 -0
  527. package/src/self-implement/graph-unit-resolver.ts +107 -0
  528. package/src/self-implement/graph-yaml.ts +151 -1
  529. package/src/self-implement/headless-elanous-driver.ts +1 -0
  530. package/src/self-implement/knowhow-pack.ts +103 -0
  531. package/src/self-implement/orchestrator.ts +160 -45
  532. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  533. package/src/self-implement/review-mustfix-class.ts +203 -0
  534. package/src/self-implement/rework-budget-judgment.ts +5 -8
  535. package/src/self-implement/run-stop.ts +17 -2
  536. package/src/self-implement/running-runs.ts +29 -1
  537. package/src/self-implement/scope-adjacency.ts +113 -0
  538. package/src/self-implement/seams.ts +138 -4
  539. package/src/self-implement/stop-autoheal.ts +112 -2
  540. package/src/session/chat.ts +27 -0
  541. package/src/session-runtime/index.ts +1 -1
  542. package/src/session-runtime/retry-policy.ts +2 -1
  543. package/src/setup/llm-env-detect.ts +5 -0
  544. package/src/skills/tools/agent.ts +140 -14
  545. package/src/skills/tools/msg-ask.ts +100 -0
  546. package/src/skills/tools/ops-ledger.ts +2 -1
  547. package/src/skills/tools/schedule-wakeup.ts +66 -17
  548. package/src/steward/hold-hygiene.ts +24 -6
  549. package/src/steward/release-day.ts +7 -3
  550. package/src/steward/triage-budget.ts +194 -0
  551. package/src/steward/triage.ts +57 -7
  552. package/src/task-agent/actions.ts +69 -1
  553. package/src/task-agent/green-sweep.ts +4 -0
  554. package/src/task-agent/harvest-unit.ts +141 -0
  555. package/src/task-agent/live-moves.ts +257 -15
  556. package/src/task-agent/parent-host.ts +216 -6
  557. package/src/task-agent/postland-card.ts +80 -1
  558. package/src/task-agent/rejudge-on-head.ts +112 -26
  559. package/src/task-agent/repair-branch-cas.ts +4 -1
  560. package/src/task-agent/repair-cycle.ts +16 -3
  561. package/src/task-agent/run-identity.ts +4 -3
  562. package/src/task-agent/shadow.ts +19 -3
  563. package/src/task-agent/task-hand.ts +96 -36
  564. package/src/task-agent/tier-split.ts +127 -0
  565. package/src/task-agent/work-order-build.ts +24 -0
  566. package/src/task-agent/work-order.ts +3 -2
  567. package/src/task-orchestrator/generator-prompt.ts +60 -11
  568. package/src/task-orchestrator/surfaces/pod-account-broker.ts +72 -3
  569. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  570. package/src/task-orchestrator/surfaces/pod-command-job.ts +47 -8
  571. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  572. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  573. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  574. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  575. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
  576. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  577. package/src/task-orchestrator/surfaces/pod-source-receive.ts +72 -4
  578. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  579. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +32 -5
  580. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  581. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +421 -0
  582. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
  583. package/src/task-orchestrator/surfaces/self-implement-pod.ts +588 -71
  584. package/src/task-orchestrator/surfaces/self-implement.ts +106 -2
  585. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  586. package/src/tool-runtime/truncation-store.ts +4 -0
  587. package/src/tui/README.md +2 -0
  588. package/src/tui/chat/background-job-status.ts +54 -0
  589. package/src/tui/chat/log-view.ts +80 -0
  590. package/src/tui/entry.ts +406 -0
  591. package/src/tui/input/composer.ts +144 -0
  592. package/src/tui/seat-mail-boot.ts +59 -0
  593. package/src/tui/slash/compact.ts +100 -0
  594. package/src/tui/slash/new-session.ts +35 -0
  595. package/src/tui-client/dashboard-session.ts +10 -1
  596. package/src/tui-client/local-chat-turn.ts +239 -0
  597. package/src/tui-client/local-harness-command.ts +63 -0
  598. package/src/tui-client/local-provider-command.ts +184 -0
  599. package/src/user-config/coercion.ts +36 -0
  600. package/src/user-config.ts +22 -43
  601. package/src/ux-sim/event-monkey.ts +378 -0
  602. package/src/ux-sim/fake-bin.ts +42 -7
  603. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  604. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  605. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  606. package/src/ux-sim/scenario.ts +72 -13
  607. package/src/version/packed-revision.json +1 -1
  608. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  611. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  612. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  613. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  617. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  619. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  620. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  636. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  640. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +0 -226
  642. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  644. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/5543.a438b8ab5a13ea47.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  653. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  655. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  661. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  662. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  663. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  668. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  669. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  674. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +0 -24
  685. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9989.3694300e5f000b14.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  744. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  752. package/src/cli/g6a-registration-probe.ts +0 -16
  753. /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
@@ -8,8 +8,10 @@ import { isAbsolute, join, normalize, resolve } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
  import type { Kubectl } from './self-implement-pod.js';
10
10
  import { elanousStateRoot } from '../../autopilot/state-paths.js';
11
+ import { debug } from '../../debug/log.js';
11
12
  import { parseWarmWorkerReply, type WarmWorkerCommand, type WarmWorkerKey, type WarmWorkerReply } from './pod-warm-worker-protocol.js';
12
13
  import type { WarmWorkerOutcome } from './pod-warm-worker-runtime.js';
14
+ import { warmExecEnv } from './pod-warm-provenance.js';
13
15
 
14
16
  const SHA = /^[a-f0-9]{40}$/;
15
17
  const DIGEST = /^sha256:[a-f0-9]{64}$/;
@@ -43,6 +45,8 @@ export interface WarmPodSpec {
43
45
  nodeName?: string;
44
46
  cutSha: string;
45
47
  key: WarmWorkerKey;
48
+ /** Resident worker tier. A lite Pod is capped at 2 GiB, including each request exec. */
49
+ memoryLimit?: '2Gi' | '16Gi';
46
50
  /** Caller resolves the live host daemon endpoint; no guessed port. */
47
51
  hostProbeUrl: string;
48
52
  /** Cluster service endpoint to prove production network isolation. */
@@ -187,6 +191,7 @@ function validateSpec(spec: WarmPodSpec): void {
187
191
  || normalize(spec.sourceMirrorHostPath) !== spec.sourceMirrorHostPath || !spec.nodeName))
188
192
  || !probeValid(spec.hostProbeUrl, 'host.orb.internal')
189
193
  || !probeValid(spec.prodProbeUrl, 'core.elanous-prod')
194
+ || (spec.memoryLimit !== undefined && spec.memoryLimit !== '2Gi' && spec.memoryLimit !== '16Gi')
190
195
  || (spec.nodeName !== undefined && !DNS.test(spec.nodeName.replace(/\./g, '-')))) throw new Error('invalid warm Pod spec');
191
196
  }
192
197
 
@@ -223,9 +228,11 @@ export function warmWorkerPodManifest(spec: WarmPodSpec): Record<string, unknown
223
228
  ...(mirror ? [{ name: 'source-mirror', mountPath: '/source-mirror', readOnly: true }] : [])] },
224
229
  { name: 'install', image: spec.image, imagePullPolicy: 'IfNotPresent',
225
230
  securityContext: { runAsUser: 0, allowPrivilegeEscalation: false },
231
+ resources: { limits: { memory: spec.memoryLimit ?? '16Gi' }, requests: { memory: '512Mi' } },
226
232
  command: ['bun', '-e', WARM_POD_INSTALL],
227
233
  volumeMounts: [{ name: 'workspace', mountPath: '/workspace' }] }],
228
234
  containers: [{ name: 'worker', image: spec.image, imagePullPolicy: 'IfNotPresent',
235
+ resources: { limits: { memory: spec.memoryLimit ?? '16Gi' }, requests: { memory: '512Mi' } },
229
236
  securityContext: { runAsUser: 0, allowPrivilegeEscalation: false,
230
237
  capabilities: { drop: ['ALL'], add: ['CHOWN', 'SETUID', 'SETGID', 'KILL'] } },
231
238
  command: ['sleep', 'infinity'], env: [
@@ -240,7 +247,7 @@ export function warmWorkerPodManifest(spec: WarmPodSpec): Record<string, unknown
240
247
  { name: 'WARM_HOST_PROBE_URL', value: spec.hostProbeUrl },
241
248
  { name: 'WARM_PROD_PROBE_URL', value: spec.prodProbeUrl },
242
249
  ],
243
- volumeMounts: [{ name: 'workspace', mountPath: '/workspace/repo', subPath: 'repo', readOnly: true },
250
+ volumeMounts: [{ name: 'workspace', mountPath: '/workspace/repo', subPath: 'repo' },
244
251
  { name: 'runtime-data', mountPath: '/workspace/data' }] }],
245
252
  volumes: [{ name: 'workspace', emptyDir: {} },
246
253
  { name: 'runtime-data', emptyDir: {} },
@@ -252,14 +259,26 @@ export function warmWorkerPodManifest(spec: WarmPodSpec): Record<string, unknown
252
259
  export interface WarmPodTransportResult {
253
260
  /** Every non-complete response leaves the existing one-shot Job authoritative. */
254
261
  status: 'observed' | 'fallback';
255
- reason: 'complete' | 'key-drift' | 'pod-unready' | 'pod-replaced' | 'exec-failed' | 'invalid-result' | 'worker-quarantined';
262
+ reason: 'complete' | 'key-drift' | 'pod-unready' | 'pod-replaced' | 'exec-failed' | 'invalid-result' | 'worker-quarantined'
263
+ | 'no-candidate' | 'lease-unavailable' | 'context-unavailable';
256
264
  reply: WarmWorkerReply | null;
265
+ /** Original local kubectl error when a remote pool context is absent; no Pod was contacted. */
266
+ kubectlStderr?: string;
257
267
  artifactsDir?: string;
258
268
  /** Base64 preserves the exact bytes copied from the same Pod. Keys are artifact suffixes. */
259
269
  artifacts?: readonly { file: string; data: Readonly<Record<string, string>> }[];
260
270
  }
261
271
  const fallback = (reason: WarmPodTransportResult['reason']): WarmPodTransportResult => ({ status: 'fallback', reason, reply: null });
262
272
 
273
+ /** A remote pool's internal k3d context must be available locally before acquiring its worker lease. */
274
+ export function probeWarmPodContext(context: string, kubectl: Kubectl = warmKubectl): WarmPodTransportResult | null {
275
+ if (!/^k3d-[a-z0-9-]+$/.test(context)) return null;
276
+ const observed = kubectl(['config', 'get-contexts', context, '-o', 'name']);
277
+ if (observed.status === 0 && observed.stdout.split(/\r?\n/).includes(context)) return null;
278
+ debug.log('pod.warm', 'context-unavailable', { context, kubectlStderr: observed.stderr }, { level: 'warn' });
279
+ return { status: 'fallback', reason: 'context-unavailable', reply: null, kubectlStderr: observed.stderr };
280
+ }
281
+
263
282
  function canonicalJson(value: unknown): unknown {
264
283
  if (Array.isArray(value)) return value.map(canonicalJson);
265
284
  if (value !== null && typeof value === 'object') return Object.fromEntries(
@@ -330,7 +349,12 @@ function matchesPodManifest(pod: any, spec: WarmPodSpec): boolean {
330
349
  // API-server defaults may add resources/termination fields; execution-bearing fields stay exact.
331
350
  for (const field of ['name', 'image', 'imagePullPolicy', 'command', 'args', 'workingDir', 'env', 'envFrom',
332
351
  'volumeMounts', 'volumeDevices', 'ports', 'securityContext', 'stdin', 'stdinOnce', 'tty', 'lifecycle',
333
- 'startupProbe', 'livenessProbe', 'readinessProbe', 'resizePolicy', 'restartPolicy']) {
352
+ 'startupProbe', 'livenessProbe', 'readinessProbe', 'resizePolicy', 'restartPolicy', 'resources']) {
353
+ // Kubernetes materializes an omitted resource stanza as {} on init containers.
354
+ // Only that empty default is equivalent; limits and requests still must match exactly.
355
+ if (field === 'resources' && want?.resources === undefined && got?.resources
356
+ && typeof got.resources === 'object' && !Array.isArray(got.resources)
357
+ && Object.keys(got.resources).length === 0) continue;
334
358
  if (!sameJson(got?.[field], want?.[field])) return false;
335
359
  }
336
360
  }
@@ -401,7 +425,9 @@ export class WarmPodTransport {
401
425
  try { nodeArch = node.status === 0 ? JSON.parse(node.stdout)?.metadata?.labels?.['kubernetes.io/arch'] : null; }
402
426
  catch { nodeArch = null; }
403
427
  if (nodeArch !== this.spec.key.architecture) return fallback('pod-unready');
404
- if (this.podUid && uid !== this.podUid) { this.quarantined = true; return fallback('pod-replaced'); }
428
+ if ((command.podUid && uid !== command.podUid) || (this.podUid && uid !== this.podUid)) {
429
+ this.quarantined = true; return fallback('pod-replaced');
430
+ }
405
431
  this.podUid = uid;
406
432
  const ledgerKey = sha256([this.spec.kubectlContext, this.spec.namespace, this.spec.name, uid].join('\0'));
407
433
  const ledgerPath = this.ledgerDir ? join(this.ledgerDir, ledgerKey) : null;
@@ -411,7 +437,8 @@ export class WarmPodTransport {
411
437
  this.quarantined = true;
412
438
  return fallback('worker-quarantined');
413
439
  }
414
- const exec = this.kubectl([...prefix, 'exec', '-i', this.spec.name, '-c', 'worker', '--', 'bun', '-e', WARM_POD_EXEC], JSON.stringify(command));
440
+ const exec = this.kubectl([...prefix, 'exec', '-i', this.spec.name, '-c', 'worker', '--',
441
+ 'env', ...warmExecEnv(command), 'bun', '-e', WARM_POD_EXEC], JSON.stringify(command));
415
442
  if (exec.status !== 0) { this.quarantined = true; return fallback('exec-failed'); }
416
443
  // UID alone is insufficient: ephemeral containers can be added to a live Pod under the same UID.
417
444
  const after = this.kubectl([...prefix, 'get', 'pod', this.spec.name, '-o', 'json']);
@@ -20,6 +20,9 @@ export interface WarmWorkerCommand {
20
20
  leaseId: string;
21
21
  generation: number;
22
22
  workerId: string;
23
+ /** Acquired Pod identity and lease timestamp, carried only by the host control path. */
24
+ podUid?: string;
25
+ requestedAt?: string;
23
26
  key: WarmWorkerKey;
24
27
  deadlineAt: number;
25
28
  files: readonly string[];
@@ -0,0 +1,421 @@
1
+ /** Fenced warm-Pod lease bridge with one-worker-per-host preparation. The Job remains authoritative. */
2
+ import { spawn, spawnSync } from 'node:child_process';
3
+ import { isAbsolute, join } from 'node:path';
4
+ import { mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { debug } from '../../debug/log.js';
8
+ import { getUserConfig } from '../../user-config.js';
9
+ import { resolveWarmPoolProfile, resolveWarmPoolQuota, type WarmPoolTier } from '../../self-implement/pod-warm-pool-profile.js';
10
+ import { WarmPodTransport, probeWarmPodContext, warmWorkerPodManifest, type WarmPodSpec, type WarmPodTransportResult } from './pod-warm-worker-pod.js';
11
+ import type { WarmWorkerCommand } from './pod-warm-worker-protocol.js';
12
+ import { patchWarmLeaseMetadata, warmLeaseMetadata } from './pod-warm-provenance.js';
13
+
14
+ // Cold source install on node-b exceeded the old five-minute Ready wait (2026-10-20).
15
+ const POD_READY_WAIT_SECONDS = 900;
16
+
17
+ export type WarmReplayInput = Omit<WarmWorkerCommand, 'leaseId' | 'generation' | 'workerId' | 'key'>;
18
+ export interface WarmReplayResult { command: WarmWorkerCommand | null; transport: WarmPodTransportResult }
19
+ export interface WarmWorkerCandidate { host: string; tier: WarmPoolTier; spec: WarmPodSpec }
20
+ export interface WarmPodProviderOptions {
21
+ candidates: readonly WarmWorkerCandidate[];
22
+ /** This address is resolved by the control-plane join/primary mechanism, never guessed from a Pod context. */
23
+ controlUrl: string;
24
+ memberToken: string;
25
+ /** Only the trusted producer host has these credentials; consumers may omit them. */
26
+ machineTokens?: Readonly<Record<string, string>>;
27
+ profileConfig?: unknown;
28
+ leaseTtlMs?: number;
29
+ fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
30
+ transport?: (spec: WarmPodSpec) => Pick<WarmPodTransport, 'request'>;
31
+ maxShadowMs?: number;
32
+ now?: () => number;
33
+ kubectl?: (args: readonly string[], input?: string) => { status: number | null; stdout: string; stderr: string };
34
+ }
35
+
36
+ const fallback = (reason: 'no-candidate' | 'lease-unavailable'): WarmReplayResult =>
37
+ ({ command: null, transport: { status: 'fallback', reason, reply: null } });
38
+ const keyEquals = (left: WarmPodSpec['key'], right: WarmPodSpec['key']) =>
39
+ left.context === right.context && left.imageDigest === right.imageDigest
40
+ && left.lockHash === right.lockHash && left.architecture === right.architecture;
41
+ const token = (value: string | undefined): value is string => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
42
+ const workerId = (value: unknown): value is string => typeof value === 'string'
43
+ && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,95}$/.test(value);
44
+
45
+ export class WarmPodProvider {
46
+ private readonly fetcher: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
47
+ private readonly now: () => number;
48
+ constructor(private readonly options: WarmPodProviderOptions) {
49
+ const url = new URL(options.controlUrl);
50
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash
51
+ || url.pathname !== '/' || !token(options.memberToken)) throw new Error('invalid warm control address');
52
+ if (options.candidates.some(candidate => !workerId(candidate.spec.workerId)
53
+ || !candidate.host.trim() || resolveWarmPoolQuota(resolveWarmPoolProfile(options.profileConfig ?? getUserConfig()), candidate.host, candidate.tier) < 1
54
+ || candidate.spec.memoryLimit !== (candidate.tier === 'lite' ? '2Gi' : '16Gi')
55
+ || !warmWorkerPodManifest(candidate.spec))) throw new Error('invalid warm candidate');
56
+ if (new Set(options.candidates.map(candidate => candidate.spec.workerId)).size !== options.candidates.length)
57
+ throw new Error('duplicate warm worker ID');
58
+ this.fetcher = options.fetch ?? fetch;
59
+ this.now = options.now ?? Date.now;
60
+ }
61
+
62
+ private async control(path: string, credential: string, body?: Record<string, unknown>): Promise<{ status: number; value: any }> {
63
+ const response = await this.fetcher(new URL(path, this.options.controlUrl), {
64
+ method: body ? 'POST' : 'GET', headers: { authorization: `Bearer ${credential}`,
65
+ ...(body ? { 'content-type': 'application/json' } : {}) },
66
+ ...(body ? { body: JSON.stringify(body) } : {}), signal: AbortSignal.timeout(15_000),
67
+ });
68
+ let value: any = null;
69
+ try { value = await response.json(); } catch { /* A missing body is a failed admission. */ }
70
+ return { status: response.status, value };
71
+ }
72
+
73
+ /** The child owns kubectl. Timeout terminates only this child process group and fences its lease. */
74
+ private async runTransport(spec: WarmPodSpec, command: WarmWorkerCommand): Promise<WarmPodTransportResult> {
75
+ if (this.options.transport) return this.options.transport(spec).request(command);
76
+ const budget = Math.min(command.deadlineAt - this.now(), this.options.maxShadowMs ?? 120_000);
77
+ if (!Number.isFinite(budget) || budget < 1) return { status: 'fallback', reason: 'exec-failed', reply: null };
78
+ const directory = mkdtempSync(join(tmpdir(), 'elanous-warm-provider-'));
79
+ const path = join(directory, 'request.json');
80
+ try {
81
+ writeFileSync(path, JSON.stringify({ spec, command }), { mode: 0o600, flag: 'wx' });
82
+ return await new Promise<WarmPodTransportResult>((resolve) => {
83
+ const child = spawn(process.execPath,
84
+ [fileURLToPath(new URL('./pod-warm-worker-pod.ts', import.meta.url)), '--shadow-request', path],
85
+ { detached: true, stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env } });
86
+ let stdout = '';
87
+ let settled = false;
88
+ let stopped = false;
89
+ const finish = (result: WarmPodTransportResult) => {
90
+ if (settled) return;
91
+ settled = true;
92
+ clearTimeout(timer);
93
+ resolve(result);
94
+ };
95
+ const stop = () => {
96
+ if (stopped) return;
97
+ stopped = true;
98
+ // Kill the whole group, including a kubectl child that ignores SIGTERM.
99
+ if (child.pid) { try { process.kill(-child.pid, 'SIGKILL'); } catch { child.kill('SIGKILL'); } }
100
+ };
101
+ const timer = setTimeout(stop, budget);
102
+ child.stdout?.on('data', (chunk: Buffer) => {
103
+ stdout += chunk.toString('utf8');
104
+ if (stdout.length > 64 * 1024 * 1024) stop();
105
+ });
106
+ child.stderr?.on('data', () => { /* Drain without revealing Pod output or credentials. */ });
107
+ child.on('error', () => { stop(); finish({ status: 'fallback', reason: 'exec-failed', reply: null }); });
108
+ child.on('close', (code) => {
109
+ if (stopped) { finish({ status: 'fallback', reason: 'exec-failed', reply: null }); return; }
110
+ try {
111
+ const parsed = JSON.parse(stdout) as WarmPodTransportResult;
112
+ if ((code === 0 || code === 2) && parsed
113
+ && (parsed.status === 'observed' || parsed.status === 'fallback')) finish(parsed);
114
+ else { stop(); finish({ status: 'fallback', reason: 'exec-failed', reply: null }); }
115
+ } catch { stop(); finish({ status: 'fallback', reason: 'exec-failed', reply: null }); }
116
+ });
117
+ });
118
+ } finally { rmSync(directory, { recursive: true, force: true }); }
119
+ }
120
+
121
+ /** Prepare at most one standing worker per host. A foreign or replaced Pod is never deleted. */
122
+ async ensureStandingWorker(candidate: WarmWorkerCandidate): Promise<boolean> {
123
+ const configured = this.options.candidates.find(row => row.host === candidate.host
124
+ && row.spec.workerId === candidate.spec.workerId && row.spec.cutSha === candidate.spec.cutSha
125
+ && keyEquals(row.spec.key, candidate.spec.key));
126
+ // A single API name per host makes concurrent creates contend on Kubernetes object identity.
127
+ if (!configured || !configured.spec.nodeName || configured.spec.name !== `warm-${configured.host}`
128
+ || candidate.spec.name !== configured.spec.name || candidate.spec.nodeName !== configured.spec.nodeName) return false;
129
+ const { spec, host } = configured;
130
+ const nodeName = spec.nodeName;
131
+ if (!nodeName) return false;
132
+ const credential = this.options.machineTokens?.[host];
133
+ if (!token(credential)) return false;
134
+ const manifest = warmWorkerPodManifest(spec);
135
+ const metadata = manifest.metadata as { labels: Record<string, string>; annotations: Record<string, string> };
136
+ const template = manifest.spec as Record<string, unknown>;
137
+ const kubectl = (args: readonly string[], input?: string) => {
138
+ const argv = ['--context', spec.kubectlContext, '-n', spec.namespace, ...args];
139
+ if (this.options.kubectl) return this.options.kubectl(argv, input);
140
+ const env = { ...process.env };
141
+ for (const name of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']) delete env[name];
142
+ // A new standing worker can spend more than five minutes in its cold init
143
+ // containers. argv[0..3] is context/namespace; argv[4] is the verb.
144
+ // Keep the process deadline beyond kubectl's Ready deadline.
145
+ const result = spawnSync('kubectl', argv, { encoding: 'utf8', input, env,
146
+ timeout: argv[4] === 'wait' ? (POD_READY_WAIT_SECONDS + 30) * 1000 : 360_000,
147
+ maxBuffer: 2 * 1024 * 1024 });
148
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
149
+ };
150
+ const parse = (result: { status: number | null; stdout: string }) => {
151
+ if (result.status !== 0) return null;
152
+ try { return JSON.parse(result.stdout) as any; } catch { return null; }
153
+ };
154
+ const sameSpec = (actual: unknown, expected: unknown): boolean => {
155
+ if (Array.isArray(expected)) return Array.isArray(actual) && actual.length === expected.length
156
+ && expected.every((item, index) => sameSpec(actual[index], item));
157
+ if (expected && typeof expected === 'object') return !!actual && typeof actual === 'object'
158
+ && !Array.isArray(actual)
159
+ && Object.keys(actual).length === Object.keys(expected).length
160
+ && Object.entries(expected).every(([key, value]) =>
161
+ sameSpec((actual as Record<string, unknown>)[key], value));
162
+ return actual === expected;
163
+ };
164
+ const normalizedSpec = (actual: any): Record<string, unknown> | null => {
165
+ if (!actual || typeof actual !== 'object' || Array.isArray(actual)) return null;
166
+ const podSpec = { ...actual };
167
+ const defaults: Record<string, unknown> = { dnsPolicy: 'ClusterFirst', serviceAccountName: 'default',
168
+ serviceAccount: 'default', schedulerName: 'default-scheduler', terminationGracePeriodSeconds: 30,
169
+ enableServiceLinks: true, priority: 0, preemptionPolicy: 'PreemptLowerPriority' };
170
+ for (const [key, value] of Object.entries(defaults)) if (podSpec[key] === value) delete podSpec[key];
171
+ const defaultTolerations = [
172
+ { effect: 'NoExecute', key: 'node.kubernetes.io/not-ready', operator: 'Exists', tolerationSeconds: 300 },
173
+ { effect: 'NoExecute', key: 'node.kubernetes.io/unreachable', operator: 'Exists', tolerationSeconds: 300 },
174
+ ];
175
+ if (sameSpec(podSpec.tolerations, defaultTolerations)) delete podSpec.tolerations;
176
+ for (const kind of ['containers', 'initContainers']) {
177
+ if (!Array.isArray(podSpec[kind])) return null;
178
+ podSpec[kind] = podSpec[kind].map((container: any, index: number) => {
179
+ if (!container || typeof container !== 'object' || Array.isArray(container)) return container;
180
+ const copy = { ...container };
181
+ if (copy.terminationMessagePath === '/dev/termination-log') delete copy.terminationMessagePath;
182
+ if (copy.terminationMessagePolicy === 'File') delete copy.terminationMessagePolicy;
183
+ const expected = (template[kind] as Record<string, unknown>[])[index];
184
+ if (expected && !('resources' in expected) && copy.resources
185
+ && typeof copy.resources === 'object' && Object.keys(copy.resources).length === 0) delete copy.resources;
186
+ return copy;
187
+ });
188
+ }
189
+ return podSpec;
190
+ };
191
+ const matches = (pod: any): boolean => typeof pod?.metadata?.uid === 'string' && !!pod.metadata.uid
192
+ && pod.metadata.name === spec.name && pod.metadata.namespace === spec.namespace
193
+ && !pod.metadata.deletionTimestamp
194
+ && (pod.metadata.ownerReferences === undefined || (Array.isArray(pod.metadata.ownerReferences)
195
+ && pod.metadata.ownerReferences.length === 0))
196
+ && Object.entries(metadata.labels).every(([key, value]) => pod.metadata.labels?.[key] === value)
197
+ && Object.entries(metadata.annotations).every(([key, value]) => pod.metadata.annotations?.[key] === value)
198
+ && pod.spec?.nodeName === nodeName
199
+ && sameSpec(normalizedSpec(pod.spec), template);
200
+ // Read the whole namespace: a Pod for this host on another node must block
201
+ // creation, and another host's standing worker must not consume this slot.
202
+ const listed = parse(kubectl(['get', 'pods', '-o', 'json']));
203
+ if (!Array.isArray(listed?.items)) return false;
204
+ const hostPods = listed.items.filter((row: any) => row?.metadata?.name === spec.name
205
+ || row?.metadata?.annotations?.['elanous.dev/warm-worker-id'] === spec.workerId);
206
+ if (hostPods.length > 1) return false;
207
+ let pod = hostPods[0];
208
+ const preexisting = !!pod;
209
+ if (pod && !matches(pod)) return false;
210
+ const readLedger = async (): Promise<any[] | null> => {
211
+ try {
212
+ const query = new URLSearchParams({ kind: 'pod-worker-lease', machine: host, name: spec.workerId });
213
+ const ledger = await this.control(`/v1/resources?${query}`, credential);
214
+ return ledger.status === 200 && Array.isArray(ledger.value?.resources)
215
+ && ledger.value.resources.length <= 1 ? ledger.value.resources : null;
216
+ } catch { return null; }
217
+ };
218
+ if (!pod) {
219
+ // A worker ID already bound to another UID must not leave a newly created, unregistered Pod.
220
+ const before = await readLedger();
221
+ if (!before || before.length !== 0) return false;
222
+ pod = parse(kubectl(['create', '-f', '-', '-o', 'json'], JSON.stringify(manifest)));
223
+ if (!matches(pod)) return false;
224
+ }
225
+ const uid = pod.metadata.uid as string;
226
+ if (kubectl(['wait', `pod/${spec.name}`, '--for=condition=Ready', `--timeout=${POD_READY_WAIT_SECONDS}s`]).status !== 0) return false;
227
+ const ready = parse(kubectl(['get', `pod/${spec.name}`, '-o', 'json']));
228
+ if (!matches(ready) || ready.metadata.uid !== uid || ready.status?.phase !== 'Running'
229
+ || !ready.status?.conditions?.some((row: any) => row.type === 'Ready' && row.status === 'True')) return false;
230
+ // Re-read after create: a registration racing the preflight must fail before our POST.
231
+ const rows = await readLedger();
232
+ if (!rows) return false;
233
+ const existing = rows[0];
234
+ const leaseTtlMs = this.options.leaseTtlMs ?? 30 * 60_000;
235
+ if (existing) return preexisting && existing.kind === 'pod-worker-lease'
236
+ && existing.machine === host && existing.name === spec.workerId
237
+ && (existing.attrs?.state === 'idle' || existing.attrs?.state === 'leased')
238
+ && existing.attrs?.podUid === uid
239
+ && Number.isSafeInteger(existing.observedAt) && Number.isSafeInteger(existing.ttlMs)
240
+ && existing.ttlMs === leaseTtlMs && existing.attrs?.idleTtlMs === leaseTtlMs
241
+ && existing.observedAt <= Date.now()
242
+ && Date.now() - existing.observedAt < existing.ttlMs
243
+ && existing.attrs?.key && keyEquals(existing.attrs.key, spec.key);
244
+ // An unregistered Pod could have been created by anyone with namespace access.
245
+ // Only this invocation's successful create response may become a new ledger row.
246
+ if (preexisting) return false;
247
+ let registered: { status: number; value: any };
248
+ try {
249
+ registered = await this.control('/v1/workers/pod', credential, {
250
+ workerId: spec.workerId, machine: host, podUid: uid, key: spec.key,
251
+ ttlMs: leaseTtlMs,
252
+ });
253
+ } catch { return false; }
254
+ return registered.status === 200 && registered.value?.name === spec.workerId
255
+ && registered.value?.attrs?.state === 'idle'
256
+ && registered.value?.attrs?.podUid === uid
257
+ && !!registered.value.attrs.key && keyEquals(registered.value.attrs.key, spec.key);
258
+ }
259
+
260
+ async prepareWorker(workerId: string): Promise<boolean> {
261
+ const candidate = this.options.candidates.find(row => row.spec.workerId === workerId);
262
+ if (!candidate) return false;
263
+ return this.ensureStandingWorker(candidate);
264
+ }
265
+
266
+ /** Acquire a matching idle worker before exec. Every uncertain result is fenced out of reuse. */
267
+ async request(input: WarmReplayInput): Promise<WarmReplayResult> {
268
+ if (input.protocol !== 1 || input.envProfile !== 'gate-v1' || !Array.isArray(input.files)
269
+ || !input.files.length || !Number.isFinite(input.deadlineAt) || input.deadlineAt <= this.now()) return fallback('no-candidate');
270
+ const candidate = this.options.candidates.find(row => row.spec.cutSha === input.cutSha);
271
+ if (!candidate) return fallback('no-candidate');
272
+ const { spec, host } = candidate;
273
+ const contextFailure = probeWarmPodContext(spec.kubectlContext, this.options.kubectl);
274
+ if (contextFailure) return { command: null, transport: contextFailure };
275
+ let acquired: { status: number; value: any };
276
+ try {
277
+ acquired = await this.control('/v1/leases/pod-worker', this.options.memberToken, {
278
+ machine: host, key: spec.key, runId: input.runId, attemptId: input.attemptId,
279
+ ttlMs: this.options.leaseTtlMs ?? 30 * 60_000,
280
+ });
281
+ } catch { return fallback('lease-unavailable'); }
282
+ if (acquired.status !== 200) return fallback('lease-unavailable');
283
+ const row = acquired.value;
284
+ const leasedId = row?.attrs?.leaseId;
285
+ const generation = row?.attrs?.generation;
286
+ const podUid = row?.attrs?.podUid;
287
+ if (!workerId(row?.name) || typeof leasedId !== 'string' || !leasedId
288
+ || typeof podUid !== 'string' || !podUid
289
+ || !Number.isSafeInteger(generation) || generation < 1) return fallback('lease-unavailable');
290
+ // Acquisition selects by host/key, not by worker ID. Resolve the returned worker
291
+ // before choosing its transport; an unknown worker must not be executed or fenced.
292
+ const leasedCandidate = this.options.candidates.find(entry => entry.host === host
293
+ && entry.spec.workerId === row.name && entry.spec.cutSha === input.cutSha
294
+ && keyEquals(entry.spec.key, spec.key));
295
+ if (!leasedCandidate) {
296
+ debug.log('pod.warm', 'lease-candidate-unmatched', { host, workerId: row.name,
297
+ runId: input.runId, attemptId: input.attemptId }, { level: 'warn' });
298
+ return fallback('lease-unavailable');
299
+ }
300
+ if (!row.attrs?.key || !keyEquals(row.attrs.key, leasedCandidate.spec.key)) {
301
+ const command: WarmWorkerCommand = { ...input, leaseId: leasedId, generation, podUid,
302
+ requestedAt: new Date(this.now()).toISOString(),
303
+ workerId: row.name, key: leasedCandidate.spec.key };
304
+ await this.quarantine(command, 'candidate-identity-mismatch', false);
305
+ return fallback('lease-unavailable');
306
+ }
307
+ const command: WarmWorkerCommand = { ...input, leaseId: leasedId, generation, podUid,
308
+ requestedAt: new Date(this.now()).toISOString(),
309
+ workerId: row.name, key: leasedCandidate.spec.key };
310
+ const admitted = patchWarmLeaseMetadata(leasedCandidate.spec, command, 'leased', this.options.kubectl);
311
+ if (!admitted.ok) {
312
+ debug.log('pod.provenance', 'lease-patch-refused', { pod: leasedCandidate.spec.name,
313
+ podUid, leaseId: leasedId, reason: admitted.reason }, { level: 'warn' });
314
+ await this.quarantine(command, 'provenance-unavailable', false);
315
+ return fallback('lease-unavailable');
316
+ }
317
+ debug.log('pod.provenance', 'lease-start', { pod: leasedCandidate.spec.name, podUid,
318
+ leaseId: leasedId, runId: command.runId, attemptId: command.attemptId,
319
+ requestedAt: command.requestedAt, metadata: warmLeaseMetadata(command).annotations });
320
+ let transport: WarmPodTransportResult;
321
+ try { transport = await this.runTransport(leasedCandidate.spec, command); }
322
+ catch { transport = { status: 'fallback', reason: 'exec-failed', reply: null }; }
323
+ if (transport.status !== 'observed' || transport.reason !== 'complete') {
324
+ await this.quarantine(command, transport.reason);
325
+ return { command, transport };
326
+ }
327
+ // Keep the lease fenced until the gate has compared these bytes with its Job baseline.
328
+ // A missing finalization leaves the worker leased and therefore unavailable.
329
+ return { command, transport };
330
+ }
331
+
332
+ private async transition(command: WarmWorkerCommand, action: 'release' | 'sanitize' | 'quarantine',
333
+ credential = this.options.memberToken, reason?: string): Promise<boolean> {
334
+ try {
335
+ const response = await this.control(`/v1/leases/pod-worker/${encodeURIComponent(command.workerId)}/${action}`,
336
+ credential, { leaseId: command.leaseId, generation: command.generation,
337
+ ...(reason ? { reason } : {}) });
338
+ return response.status === 200;
339
+ } catch { return false; }
340
+ }
341
+
342
+ async finalize(command: WarmWorkerCommand): Promise<void> {
343
+ const candidate = this.options.candidates.find(row => row.spec.workerId === command.workerId);
344
+ if (!candidate) throw new Error('warm finalize candidate missing');
345
+ const released = await this.transition(command, 'release');
346
+ const machineToken = this.options.machineTokens?.[candidate.host];
347
+ // Sanitizing is the producer's machine-scoped acknowledgement, after transport's cleanup and ACK.
348
+ const cleared = released ? patchWarmLeaseMetadata(candidate.spec, command, 'idle', this.options.kubectl)
349
+ : { ok: false, reason: 'release-failed' };
350
+ if (!cleared.ok) debug.log('pod.provenance', 'lease-patch-refused', { pod: candidate.spec.name,
351
+ podUid: command.podUid, leaseId: command.leaseId, reason: cleared.reason }, { level: 'warn' });
352
+ if (!cleared.ok || !token(machineToken) || !await this.transition(command, 'sanitize', machineToken)) {
353
+ await this.quarantine(command, 'sanitize-unavailable');
354
+ throw new Error('warm sanitize unavailable');
355
+ }
356
+ debug.log('pod.provenance', 'lease-end', { pod: candidate.spec.name, podUid: command.podUid,
357
+ leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
358
+ releasedAt: new Date(this.now()).toISOString(), result: 'sanitized' });
359
+ }
360
+
361
+ /** `leaseStarted=false` marks a refusal before `lease-start`, so start/end history stays paired. */
362
+ async quarantine(command: WarmWorkerCommand, reason: string, leaseStarted = true): Promise<void> {
363
+ if (!await this.transition(command, 'quarantine', this.options.memberToken, reason.slice(0, 120) || 'mismatch')) {
364
+ throw new Error('warm quarantine unavailable');
365
+ }
366
+ const candidate = this.options.candidates.find(row => row.spec.workerId === command.workerId);
367
+ if (candidate) {
368
+ const cleared = patchWarmLeaseMetadata(candidate.spec, command, 'quarantined', this.options.kubectl);
369
+ if (!cleared.ok && reason !== 'provenance-unavailable') debug.log('pod.provenance', 'lease-patch-refused', { pod: candidate.spec.name,
370
+ podUid: command.podUid, leaseId: command.leaseId, reason: cleared.reason }, { level: 'warn' });
371
+ }
372
+ debug.log('pod.provenance', leaseStarted ? 'lease-end' : 'lease-refused', { podUid: command.podUid,
373
+ leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId, leaseStarted,
374
+ releasedAt: new Date(this.now()).toISOString(), result: 'quarantined', reason });
375
+ }
376
+
377
+
378
+ }
379
+
380
+ let configuredProvider: WarmPodProvider | null = null;
381
+ /** The trusted producer configures this once; an absent provider fails closed without creating a Pod. */
382
+ export function configureWarmPodProvider(provider: WarmPodProvider | null): void { configuredProvider = provider; }
383
+ /** Optional private producer config; a missing/unsafe file leaves the Job path untouched. */
384
+ export function loadWarmPodProvider(path: string): WarmPodProvider {
385
+ if (!isAbsolute(path) || (statSync(path).mode & 0o077) !== 0) throw new Error('warm provider config must be private');
386
+ const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
387
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid warm provider config');
388
+ return new WarmPodProvider(parsed as WarmPodProviderOptions);
389
+ }
390
+ function currentProvider(): WarmPodProvider | null {
391
+ if (configuredProvider) return configuredProvider;
392
+ const file = process.env.ELANOUS_WARM_POD_PROVIDER_CONFIG;
393
+ if (!file) return null;
394
+ try { configuredProvider = loadWarmPodProvider(file); }
395
+ catch { return null; }
396
+ return configuredProvider;
397
+ }
398
+ export async function requestWarmPodReplay(input: WarmReplayInput): Promise<WarmReplayResult> {
399
+ return currentProvider() ? currentProvider()!.request(input) : fallback('no-candidate');
400
+ }
401
+ export async function quarantineWarmPodReplay(command: WarmWorkerCommand, reason: string): Promise<void> {
402
+ const provider = currentProvider();
403
+ if (!provider) throw new Error('warm provider unavailable');
404
+ await provider.quarantine(command, reason);
405
+ }
406
+ export async function finalizeWarmPodReplay(command: WarmWorkerCommand): Promise<void> {
407
+ const provider = currentProvider();
408
+ if (!provider) throw new Error('warm provider unavailable');
409
+ await provider.finalize(command);
410
+ }
411
+
412
+ if (import.meta.main) {
413
+ const [action, workerId] = process.argv.slice(2);
414
+ const file = process.env.ELANOUS_WARM_POD_PROVIDER_CONFIG;
415
+ if (action !== '--prepare' || !workerId) throw new Error('usage: --prepare <workerId> with private provider config');
416
+ let prepared = false;
417
+ try { if (file) prepared = await loadWarmPodProvider(file).prepareWorker(workerId); }
418
+ catch { /* An invalid private config is a failed preparation, never a Pod mutation. */ }
419
+ process.stdout.write(JSON.stringify({ workerId, prepared }) + '\n');
420
+ if (!prepared) process.exitCode = 2;
421
+ }
@@ -166,7 +166,7 @@ export class WarmWorkerRuntime {
166
166
  || !token(command.workerId) || command.workerId !== this.options.workerId
167
167
  || !Number.isSafeInteger(command.generation) || command.generation < 1
168
168
  || !Number.isFinite(command.deadlineAt)
169
- || !token(command.envProfile) || (command.baselineSha !== undefined && !sha(command.baselineSha))
169
+ || command.envProfile !== 'gate-v1' || (command.baselineSha !== undefined && !sha(command.baselineSha))
170
170
  || !keyValid(command.key)
171
171
  || !Array.isArray(command.files) || command.files.length === 0
172
172
  || command.files.some(file => !testPath(file)) || new Set(command.files).size !== command.files.length) {
@@ -234,6 +234,7 @@ export class WarmWorkerRuntime {
234
234
  ELANOUS_STATE_DIR_SOURCE: stateDirSourceForChild(dirs.state), TMPDIR: dirs.tmp,
235
235
  XDG_CONFIG_HOME: dirs.config, XDG_CACHE_HOME: dirs.cache,
236
236
  XDG_DATA_HOME: dirs.data, XDG_STATE_HOME: dirs['xdg-state'], XDG_RUNTIME_DIR: dirs['xdg-runtime'],
237
+ TZ: 'UTC', LANG: 'C.UTF-8', LC_ALL: 'C.UTF-8', ELANOUS_TEST_FAKE_LLM: '1',
237
238
  };
238
239
  let rc = 1;
239
240
  try {