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
@@ -10,10 +10,13 @@
10
10
  */
11
11
  import type { DecomposeInput } from './generator.js';
12
12
  import type { ProposalValidationError } from './generator-schema.js';
13
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
14
+ import { resolve } from 'node:path';
13
15
 
14
16
  export type DecomposePromptProfile = 'goal-author-coarse';
15
17
 
16
- export const GOAL_AUTHOR_COARSE_MAX_SLICES = 6;
18
+ /** TaskGenerator's safety ceiling, not an authoring target; goal-author splits by slice size. */
19
+ export const GOAL_AUTHOR_SIZE_SAFETY_MAX_SLICES = 15;
17
20
 
18
21
  export interface BuildPromptOptions {
19
22
  maxTasks: number;
@@ -39,6 +42,35 @@ const CODING_GOAL_KINDS: ReadonlySet<string> = new Set([
39
42
  'agentic',
40
43
  ]);
41
44
 
45
+ /** Read the existing device sources at authoring time; the LLM has no file tools in this phase. */
46
+ let deviceInventoryCache: string[] | undefined;
47
+ function deviceInventory(): string[] {
48
+ if (deviceInventoryCache) return deviceInventoryCache;
49
+ const root = resolve(import.meta.dir, '../..');
50
+ const fallback = ['- Device inventory unavailable in this installation; verify a named device before claiming it exists.'];
51
+ if (!existsSync(resolve(root, 'src/ux-sim'))) return deviceInventoryCache = fallback;
52
+ try {
53
+ const files = readdirSync(resolve(root, 'src/ux-sim'))
54
+ .filter((name) => name.endsWith('.ts') && !name.endsWith('.test.ts')).sort();
55
+ const monkey = readFileSync(resolve(root, 'src/ux-sim/event-monkey.ts'), 'utf8');
56
+ const kinds = monkey.match(/export const EVENT_MONKEY_KINDS = \[([\s\S]*?)\] as const;/)?.[1]
57
+ ?.match(/'[^']+'/g)?.map((kind) => kind.slice(1, -1)) ?? [];
58
+ let rows: string[] = [];
59
+ try {
60
+ const manual = readFileSync(resolve(root, 'docs/manual/MANUAL-ux-simulation-devices-2026-08-23.md'), 'utf8');
61
+ rows = manual.split('\n').filter((line) => line.startsWith('|') && line.includes('`src/ux-sim/'));
62
+ } catch { /* Published packages omit docs/manual; source catalog still applies. */ }
63
+ return deviceInventoryCache = [
64
+ `- src/ux-sim files: ${files.join(', ')}`,
65
+ `- event-monkey kinds: ${kinds.join(', ')}`,
66
+ ...(rows.length ? [] : ['- manual §1 table unavailable in this installation; use the source files and event kinds above.']),
67
+ ...rows.map((row) => `- manual §1: ${row.replace(/\s*\|\s*/g, ' · ').slice(0, 500)}`),
68
+ ];
69
+ } catch {
70
+ return deviceInventoryCache = fallback;
71
+ }
72
+ }
73
+
42
74
  export function buildDecomposePrompt(
43
75
  input: DecomposeInput,
44
76
  opts: BuildPromptOptions
@@ -53,7 +85,7 @@ export function buildDecomposePrompt(
53
85
  lines.push(
54
86
  'You are the monad-agent Task Orchestrator decomposition planner.',
55
87
  isGoalAuthorCoarse
56
- ? `Break the objective into 1-${GOAL_AUTHOR_COARSE_MAX_SLICES} larger, concrete implementation slices.`
88
+ ? 'Break the objective into implementation slices that a low or medium tier model can finish. Split by slice size, not a target number of slices; the task count limit is only a safety ceiling.'
57
89
  : 'Break the objective into 3-7 concrete, single-responsibility tasks.',
58
90
  '',
59
91
  '## Output (STRICT JSON)',
@@ -119,9 +151,10 @@ export function buildDecomposePrompt(
119
151
  '- ★ Complete dependsOn contracts: if a phase CONSUMES another phase\'s output, that producing phase MUST be in this phase\'s `dependsOn` (by index). A consumer with no dependsOn on its producer looks like an ungrounded/orphan dependency to the critique. Trace every consumed symbol to either grounding (exists) or a dependsOn phase (produced this mission).',
120
152
  ...(isGoalAuthorCoarse
121
153
  ? [
122
- '- Coarse scope: permit a larger implementation slice when its related definition, tests, and runtime wiring are necessary for an executable end-to-end path; do not split those related concerns into sibling tasks.',
123
- '- One implementation run can complete a large multi-file slice, including its tests, so do not split work that fits in one run.',
124
- '- Keep a coarse slice focused on one executable outcome, but it may combine related implementation concerns and exceed the default small-scope LOC guidance.',
154
+ '- Goal-author size: each slice should touch at most 4 target files, change at most 2 behaviors, and create at most 2 files. Count tests and runtime wiring among target files.',
155
+ '- Prefer low tier (at most 2 files, 1 behavior, 1 new file), then medium tier (at most 4 files, 2 behaviors, 2 new files). Do not make a high tier slice merely to reduce the number of slices.',
156
+ '- Keep the executable dependency path through dependsOn; split oversized work into dependent slices rather than hiding multiple behaviors in one title.',
157
+ '- A high tier slice is allowed only when it cannot be split further without breaking an inseparable operation. State its unavoidable reason in the rationale.',
125
158
  ]
126
159
  : [
127
160
  '- Small scope: keep each task ≈≤250 LOC of change. If a step is bigger, split it into sibling tasks or defer to a recursive decompose (depth) rather than one giant task.',
@@ -155,13 +188,29 @@ export function buildDecomposePrompt(
155
188
  if (isGoalAuthorCoarse) {
156
189
  lines.push(
157
190
  '',
158
- '## Goal-author coarse slicing (follow strictly)',
159
- '- Prefer fewer, larger implementation slices over small single-concern tasks; use the task budget as a ceiling, not a target.',
160
- '- Keep related definition, tests, and runtime wiring together when they are required to make one implementation slice executable end-to-end.',
161
- '- A slice may cover multiple related concerns and a larger change scope when splitting them would leave a definition unwired or an execution path incomplete.',
162
- '- Every slice title MUST name at least one actual file path or function name because only the title is passed to the next stage; coarse slices must remain grounded and verifiable.',
191
+ '## Goal-author size-bounded slicing (follow strictly)',
192
+ '- Use the task budget as a safety ceiling, not a target. Add dependent slices whenever one slice would exceed medium size.',
193
+ '- Give each slice an executable outcome with tests or runtime wiring inside its size limit; place further wiring in a dependent slice.',
194
+ '- Every slice title MUST name at least one actual file path or function name because only the title is passed to the next stage; slices must remain grounded and verifiable.',
195
+ '- Every task JSON must include files, behaviours, newFiles and tier. Example: {"index":0,"title":"대상 경로: src/a.ts · 동작: 연결","files":1,"behaviours":1,"newFiles":0,"tier":"low","surface":{"kind":"llm-direct","prompt":"wire src/a.ts"}}.',
196
+ '- Only the title reaches the sizing fallback: start it with "대상 경로:" and name all touched paths; add one "동작:" clause per changed behavior and "신규 경로:" for each new file. Keep the title within 80 characters by splitting oversized work.',
163
197
  '- Fold non-code investigation or design into the implementation slice that needs it; do not emit it as a standalone slice.',
164
- '- Use dependsOn only for genuine ordering between independently completable slices; do not split related definition and runtime wiring merely to create sibling tasks.',
198
+ '- Use dependsOn for genuine ordering between independently completable slices, including definition before dependent runtime wiring.',
199
+ );
200
+ // ── 장치 우선 분해 (DEVICE-FIRST-AUTHORING · 대표 10-21 18:1x 골 저작 지침) ──
201
+ // 골 저작의 검증 계획(TDD) 절이 무대·층을 고를 때 그 시험에 필요한 mock 장치·주입 사건 정의의
202
+ // 존재를 먼저 확인하게 한다. 장치가 없으면 «실물 없음»으로 초록이 막히므로 첫 조각이 장치 조각이 된다.
203
+ lines.push(
204
+ '',
205
+ '## Device-first decomposition (DEVICE-FIRST-AUTHORING — follow strictly)',
206
+ '### Existing device inventory (read from this checkout; use these names before proposing a new device)',
207
+ ...deviceInventory(),
208
+ '- The objective\'s verification plan (검증 계획/TDD) section picks a stage and ladder tier (무대·층) — e.g. a `src/ux-sim/*` stage at L2 (fake-llm·fake-bin·fake-clock). BEFORE writing slices, CHECK whether the mock device or injected event definition that this verification plan needs ALREADY EXISTS: look in `src/ux-sim/*`, the §1 device table of `docs/manual/MANUAL-ux-simulation-devices-2026-08-23.md`, and the event-monkey event kinds.',
209
+ '- Two branches — exactly one applies per needed device:',
210
+ ' - Device EXISTS: its name MUST go into the verification plan wording — the slice that tests the feature carries the device\'s exact name (device file / §1 table row / event kind) in its acceptance criteria and reuses the device; never re-create it.',
211
+ ' - Device MISSING: the FIRST slice MUST be a device slice that develops that device feature first — the mock device or injected event definition under `src/ux-sim/*` — and every slice that tests the feature depends on it (구현할 때 해당 시험 mock 장치나 이벤트 정의가 있나 확인하고, 없으면 그 장치 피처를 먼저 개발).',
212
+ '- Do NOT create the device itself here beyond emitting that device slice (장치 자체는 만들지 않는다 — 조각으로 내보낼 뿐); consumer slices reference it only via dependsOn.',
213
+ '- Device slices obey the same size bounds and acceptance bar as every other slice — the size rules (TIER-SIZED-DECOMPOSE) and the green-judgment rules are UNCHANGED.',
165
214
  );
166
215
  }
167
216
 
@@ -17,6 +17,17 @@ export type PodProviderPlan =
17
17
  | { provider: 'grok'; excluded: PodAccountPlan['excluded']; grokSubscriptionEligible: boolean }
18
18
  | { provider: null; reasons: string[]; grokSubscriptionEligible: boolean };
19
19
 
20
+ /** Effective cap used by the Pod broker; callers carrying an owner-approved selection must carry this same value. */
21
+ export function podAccountThresholdPercent(name: string, options: {
22
+ excludeAt?: number;
23
+ thresholdPercentByAccount?: Readonly<Record<string, unknown>>;
24
+ } = {}): number {
25
+ return codexAccountThresholdPercent(name, {
26
+ thresholdPercent: options.excludeAt ?? POD_ACCOUNT_EXCLUDE_AT_PERCENT,
27
+ thresholdPercentByAccount: options.thresholdPercentByAccount,
28
+ });
29
+ }
30
+
20
31
  /** Pod 의 codex → grok 선택. 자격 종류는 과금 동의와 별도로 판단한다. */
21
32
  export function planPodProvider(input: {
22
33
  codexCandidates: readonly RotationCandidate[];
@@ -85,9 +96,7 @@ export function planPodAccounts(
85
96
  const known: RotationCandidate[] = [];
86
97
  const unknown: RotationCandidate[] = [];
87
98
  for (const c of candidates) {
88
- const threshold = typeof options === 'number'
89
- ? excludeAt
90
- : codexAccountThresholdPercent(c.name, { thresholdPercent: excludeAt, thresholdPercentByAccount });
99
+ const threshold = typeof options === 'number' ? excludeAt : podAccountThresholdPercent(c.name, { excludeAt, thresholdPercentByAccount });
91
100
  if (c.reached === true) { excluded.push({ name: c.name, why: 'quota reached' }); continue; }
92
101
  if (c.usedPercent !== undefined && c.usedPercent >= threshold) { excluded.push({ name: c.name, why: `used ${c.usedPercent}% ≥ ${threshold}%` }); continue; }
93
102
  (c.usedPercent === undefined ? unknown : known).push(c);
@@ -113,6 +122,66 @@ export function planPodAccounts(
113
122
  return { usable, excluded };
114
123
  }
115
124
 
125
+ /** HQ selects one owner account before remote-parent launch; keep the configured rotation order. */
126
+ export function planOwnerCodexMirrorCandidates(candidates: readonly RotationCandidate[], options: {
127
+ accountOrder: readonly string[];
128
+ thresholdPercentByAccount?: Readonly<Record<string, unknown>>;
129
+ }): RotationCandidate[] {
130
+ const usable = new Set(planPodAccounts(candidates, { thresholdPercentByAccount: options.thresholdPercentByAccount }).usable);
131
+ const rank = (name: string): number => {
132
+ const index = options.accountOrder.indexOf(name);
133
+ return index < 0 ? options.accountOrder.length : index;
134
+ };
135
+ return candidates.map((candidate, index) => ({ candidate, index })).filter(({ candidate }) => usable.has(candidate.name))
136
+ .sort((a, b) => rank(a.candidate.name) - rank(b.candidate.name) || a.index - b.index)
137
+ .map(({ candidate }) => candidate);
138
+ }
139
+
140
+ /** Remote owner-mirror runs may plan against exactly the account HQ selected and its measured usage. */
141
+ export function ownerCodexMirrorCandidate(candidates: readonly RotationCandidate[], account: string, usedPercent?: number): RotationCandidate[] {
142
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(account)) return [];
143
+ return candidates.filter((candidate) => candidate.name === account).map((candidate) => {
144
+ const ownerCandidate = { ...candidate };
145
+ delete ownerCandidate.usedPercent;
146
+ ownerCandidate.reached = false;
147
+ const measured = usedPercent !== undefined && Number.isFinite(usedPercent) ? usedPercent : undefined;
148
+ return { ...ownerCandidate, reached: false, ...(measured !== undefined ? { usedPercent: measured } : {}) };
149
+ });
150
+ }
151
+
152
+ export interface OwnerCodexMirrorAccount { account: string; usedPercent: number | null; thresholdPercent: number; expiresAt: number }
153
+
154
+ /** The remote may rotate only across the accounts HQ actually installed in this launch snapshot. */
155
+ export function parseOwnerCodexMirrorAccounts(raw: string): OwnerCodexMirrorAccount[] {
156
+ let parsed: unknown;
157
+ try { parsed = JSON.parse(raw); } catch { throw new Error('HQ Codex 미러 계정 목록이 잘못됐다'); }
158
+ if (!Array.isArray(parsed) || parsed.length === 0 || parsed.length > 16) throw new Error('HQ Codex 미러 계정 목록이 잘못됐다');
159
+ const seen = new Set<string>();
160
+ return parsed.map((item: unknown) => {
161
+ if (!item || typeof item !== 'object') throw new Error('HQ Codex 미러 계정 항목이 잘못됐다');
162
+ const value = item as Record<string, unknown>;
163
+ const { account, usedPercent, thresholdPercent, expiresAt } = value;
164
+ if (typeof account !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(account) || seen.has(account)
165
+ || (usedPercent !== null && (typeof usedPercent !== 'number' || !Number.isFinite(usedPercent) || usedPercent < 0 || usedPercent > 100))
166
+ || typeof thresholdPercent !== 'number' || !Number.isFinite(thresholdPercent) || thresholdPercent <= 0 || thresholdPercent > 100
167
+ || typeof expiresAt !== 'number' || !Number.isFinite(expiresAt) || expiresAt <= 0)
168
+ throw new Error('HQ Codex 미러 계정 항목이 잘못됐다');
169
+ seen.add(account);
170
+ return { account, usedPercent: usedPercent as number | null, thresholdPercent, expiresAt };
171
+ });
172
+ }
173
+
174
+ /** Do not plan a Pod against an access token that might expire while it starts and runs. */
175
+ export function freshOwnerCodexMirrorAccounts(accounts: readonly OwnerCodexMirrorAccount[], now = Date.now()): OwnerCodexMirrorAccount[] {
176
+ return accounts.filter(({ expiresAt }) => expiresAt > now + 3 * 60 * 60 * 1000);
177
+ }
178
+
179
+ export function selectOwnerCodexMirrorCandidates(candidates: readonly RotationCandidate[], accounts: readonly OwnerCodexMirrorAccount[]): RotationCandidate[] {
180
+ const selected = accounts.flatMap(({ account, usedPercent }) => ownerCodexMirrorCandidate(candidates, account, usedPercent ?? undefined));
181
+ if (selected.length !== accounts.length) throw new Error('HQ Codex 미러 계정 일부가 원격 auth-store 후보에 없다');
182
+ return selected;
183
+ }
184
+
116
185
  /** Job 마다 다음 계정 — 잔량 순으로 돌려 가며. 쓸 계정이 없으면 만들 때 이유를 대고 던진다. */
117
186
  export function makePodAccountBroker(plan: PodAccountPlan): () => string {
118
187
  if (plan.usable.length === 0) {
@@ -9,7 +9,7 @@
9
9
  */
10
10
  // BEDROCK-PROVIDER ② (0.2.24) — bedrock 은 «이름 있는 AWS Secret» 이 클러스터에 있을 때만 뜬다(pod-bedrock-child.ts · 발사 전 거부).
11
11
  // ZAI-POD-CHILD (0.2.24) — glm 은 Z.ai GLM Coding Plan(정액 구독) · «이름 있는 ZAI Secret» 이 클러스터에 있을 때만 뜬다(pod-zai-child.ts · 발사 전 거부 · 동시 상한 넘치면 정책대로).
12
- export const POD_CHILD_PROVIDERS = ['openai-codex', 'grok', 'openrouter', 'anthropic', 'bedrock', 'glm'] as const;
12
+ export const POD_CHILD_PROVIDERS = ['openai-codex', 'grok', 'openrouter', 'opengateway', 'anthropic', 'bedrock', 'glm'] as const;
13
13
  export type PodChildProvider = typeof POD_CHILD_PROVIDERS[number];
14
14
 
15
15
  /** 사람이 쓰는 별칭 → 정식 이름. */
@@ -17,9 +17,10 @@ import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.j
17
17
  import { podBunCacheVolume } from './pod-bun-cache.js';
18
18
  import { POD_JOB_TTL_AFTER_FINISHED_SECONDS } from './pod-lease.js';
19
19
  import { podHostDirsCheckScript, podInstallSlotsVolume, prepareHostDirsOnce, type HostDirsPrepResult, podHostDirsScript } from './pod-install-slots.js';
20
- import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
20
+ import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, registryImageRef, type PoolKubectl } from './pod-pool.js';
21
21
  import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
22
22
  import { podSourceScript, type PodSource } from './pod-source-receive.js';
23
+ import { podProvenanceMetadata, type PodProvenance } from './pod-provenance.js';
23
24
  import { seedMirrorOnce, type MirrorSeedResult } from './pod-mirror-seed.js';
24
25
  import {
25
26
  POD_CHILD_REQUESTS,
@@ -201,6 +202,8 @@ if [ -d "$HOME/outbox" ]; then
201
202
  fi`;
202
203
 
203
204
  export interface PodCommandJobInput {
205
+ provenance?: Partial<PodProvenance>;
206
+ provenanceGate?: boolean;
204
207
  /** POD1 — this launch's own label; cleanup selects by it, never by name alone. */
205
208
  launch?: string;
206
209
  name: string;
@@ -236,8 +239,21 @@ function bashSingleQuote(value: string): string {
236
239
  return `'${value.replace(/'/g, `'\\''`)}'`;
237
240
  }
238
241
 
242
+ function assertGateProvenanceException(gate: boolean | undefined, provenance: Partial<PodProvenance> | undefined,
243
+ clone: boolean | undefined, source: PodSource | undefined): void {
244
+ if (!gate) return;
245
+ const shardEntrance = process.env.ELANOUS_RELEASE_ENTRANCE?.trim() || 'release-run';
246
+ const shard = provenance?.kind === 'gate-shard' && provenance.entrance === shardEntrance;
247
+ const recheck = provenance?.kind === 'gate-recheck' && provenance.entrance === 'release-recheck';
248
+ if (!(shard || recheck) || clone !== true || source?.kind !== 'commit') {
249
+ throw new Error('pod provenance gate exception requires a release shard/recheck commit Job');
250
+ }
251
+ }
252
+
239
253
  /** 명령 Job 매니페스트. `skills`·`llm` 을 안 주면 Secret 키를 하나도 참조하지 않는다. */
240
254
  export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unknown> {
255
+ assertGateProvenanceException(o.provenanceGate, o.provenance, o.clone, o.source);
256
+ const provenance = podProvenanceMetadata(o.provenance, o.provenanceGate);
241
257
  const skillNames = [...new Set(o.skills.map((s) => s.trim()).filter(Boolean))];
242
258
  for (const name of skillNames) {
243
259
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(name)) throw new Error(`pod command skill name rejected: ${name}`);
@@ -284,13 +300,13 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
284
300
  return {
285
301
  apiVersion: 'batch/v1',
286
302
  kind: 'Job',
287
- metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, 'elanous.kind': 'command', ...(o.launch ? { 'elanous.launch': o.launch } : {}) } },
303
+ metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, 'elanous.kind': 'command', ...(o.launch ? { 'elanous.launch': o.launch } : {}), ...provenance?.labels }, ...(provenance ? { annotations: provenance.annotations } : {}) },
288
304
  spec: {
289
305
  backoffLimit: 0,
290
306
  ttlSecondsAfterFinished: POD_JOB_TTL_AFTER_FINISHED_SECONDS,
291
307
  activeDeadlineSeconds: o.deadlineSeconds,
292
308
  template: {
293
- metadata: { labels: { 'elanous.job': o.name, 'elanous.kind': 'command', ...(o.launch ? { 'elanous.launch': o.launch } : {}) } },
309
+ metadata: { labels: { 'elanous.job': o.name, 'elanous.kind': 'command', ...(o.launch ? { 'elanous.launch': o.launch } : {}), ...provenance?.labels }, ...(provenance ? { annotations: provenance.annotations } : {}) },
294
310
  spec: {
295
311
  restartPolicy: 'Never',
296
312
  securityContext: { runAsUser: 1000, fsGroup: 1000 },
@@ -306,6 +322,7 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
306
322
  ...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
307
323
  { name: 'ELANOUS_SUBSTRATE', value: 'pod' },
308
324
  { name: 'ELANOUS_POD_NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } },
325
+ ...(provenance?.env ?? []),
309
326
  ...(tmpfs ? [{ name: 'TMPDIR', value: POD_TMPFS_MOUNT_PATH }] : []),
310
327
  ],
311
328
  ...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumeMounts: [
@@ -382,6 +399,9 @@ export interface PodCommandResult {
382
399
  }
383
400
 
384
401
  export interface RunPodCommandOptions {
402
+ provenance?: Partial<PodProvenance>;
403
+ /** Release gate keeps availability: missing required identity becomes unknown and emits a warning. */
404
+ provenanceGate?: boolean;
385
405
  command: readonly string[];
386
406
  /** pod run opt-in; other runPodCommand callers keep their existing Job script. */
387
407
  returnLogs?: boolean;
@@ -434,6 +454,9 @@ export interface RunPodCommandOptions {
434
454
  checkPool?: typeof checkPodPool;
435
455
  syncImages?: typeof syncPoolImages;
436
456
  imageCommit?: string | null;
457
+ /** Shelf: require this exact registry tag; never fall back to a mutable local image. */
458
+ shelfImage?: string;
459
+ shelfLookup?: typeof registryImageRef;
437
460
  readSkillEnv?: (skills: readonly string[]) => Record<string, string>;
438
461
  grokCredentials?: () => { grokAuth?: string; grokApiKey?: string; ghToken: string };
439
462
  artifactsRoot?: string;
@@ -510,6 +533,9 @@ function awaitPodCommandAbort<T>(pending: Promise<T>, signal?: AbortSignal): Pro
510
533
 
511
534
  /** 풀 자리 · 이미지 판 · Job 적용 · 완료 대기 · 산출 회수 · Secret 정리. */
512
535
  export async function runPodCommand(options: RunPodCommandOptions): Promise<PodCommandResult> {
536
+ // A non-gate Job must have its owner before a pool lease, Secret, or Job is created.
537
+ assertGateProvenanceException(options.provenanceGate, options.provenance, options.clone, options.source);
538
+ const provenance = podProvenanceMetadata(options.provenance, options.provenanceGate);
513
539
  const nowMs = options.nowMs ?? Date.now;
514
540
  const ensureLive = () => {
515
541
  if (options.signal?.aborted) throw options.signal.reason ?? new Error('pod command aborted');
@@ -521,11 +547,15 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
521
547
  const skills = [...new Set((options.skills ?? []).map((s) => s.trim()).filter(Boolean))];
522
548
  const llm = options.llm;
523
549
  const log = options.log ?? ((c, e, d) => debug.log(c, e, d));
550
+ if (provenance.missing.length) log('pod.provenance', 'missing-gate-fields', { missing: provenance.missing });
524
551
  const baseKubectl = options.kubectl ?? ((args: readonly string[], input?: string) =>
525
552
  defaultKubectl(args, input, options.signal ? POD_COMMAND_CANCEL_KUBECTL_TIMEOUT_MS : undefined));
526
553
  const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
527
554
  const namespace = options.namespace ?? 'elanous-test';
528
555
  const image = options.image ?? podCommandImageFor(skills, options.clone === true, options.lite === true);
556
+ if (options.shelfImage && (options.image !== options.shelfImage || !options.imageCommit || !options.clone || options.source?.kind !== 'commit' || options.source.sha !== options.imageCommit)) {
557
+ throw new Error('pod shelf: image and source commit must match');
558
+ }
529
559
  const memoryLimit = options.memoryLimit ?? (image === POD_LITE_IMAGE ? POD_LITE_MEMORY_LIMIT : undefined);
530
560
  const repoUrl = options.repoUrl ?? 'https://github.com/ElanvitalAI/elanous';
531
561
  const deadlineSeconds = options.deadlineSeconds ?? POD_COMMAND_DEADLINE_SECONDS;
@@ -579,6 +609,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
579
609
  if (member && pool) pool.release(member);
580
610
  ensureLive();
581
611
  }
612
+ if (options.shelfImage && !member) throw new Error('pod shelf: remote pool member required');
582
613
  const currentContext = member || options.kubectl ? null : baseKubectl(['config', 'current-context']);
583
614
  const context = member?.context ?? (currentContext?.status === 0 ? currentContext.stdout.trim() : '');
584
615
  const kubectlRaw: Kubectl = (args, stdin) => baseKubectl(context ? ['--context', context, ...args] : [...args], stdin);
@@ -592,7 +623,8 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
592
623
  if (!context && !options.kubectl) throw new Error('pod command: kubectl context 를 확인할 수 없다');
593
624
  let grokAuth: string | undefined;
594
625
  if (llm === 'grok') {
595
- const creds = (options.grokCredentials ?? (() => hostGrokCredentials({ env, apiKeyOptIn: false })))();
626
+ // POD-GROK-VALIDITY-FIT — this Job's deadline is not fitted to the token, so the copy must outlive the whole Job.
627
+ const creds = (options.grokCredentials ?? (() => hostGrokCredentials({ env, apiKeyOptIn: false, minValidityMs: deadlineSeconds * 1000 })))();
596
628
  if (!creds.grokAuth) throw new Error('grok: 구독 자격 없음 · API 키 opt-in 꺼짐 또는 키 없음');
597
629
  let parsed: unknown;
598
630
  try { parsed = JSON.parse(creds.grokAuth); } catch { throw new Error('grok: Pod 구독 자격 JSON 이 아니다'); }
@@ -616,10 +648,16 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
616
648
  const localSkillsDigest = options.kubectl ? null : image === POD_LITE_IMAGE
617
649
  ? podSkillsDigest(POD_NETWORK_SKILLS, resolve(import.meta.dir, '../../../skills')).digest
618
650
  : podSkillsDigest(resolvePodSkills(env).skills).digest;
619
- const syncs = await awaitPodCommandAbort((options.syncImages ?? syncPoolImages)([member], image, imageCommit, { localSkillsDigest }), options.signal);
620
- const synced = syncs.get(member.context);
621
- if (synced && !synced.ok) throw new Error(`pod command: 이미지 판을 못 맞췄다: ${synced.detail}`);
622
- if (synced?.imageRef) member = { ...member, imageRef: synced.imageRef };
651
+ if (options.shelfImage) {
652
+ const found = (options.shelfLookup ?? registryImageRef)(member, imageCommit);
653
+ if (found !== options.shelfImage) throw new Error(`pod shelf: selected image unavailable on ${member.context}`);
654
+ member = { ...member, imageRef: found };
655
+ } else {
656
+ const syncs = await awaitPodCommandAbort((options.syncImages ?? syncPoolImages)([member], image, imageCommit, { localSkillsDigest }), options.signal);
657
+ const synced = syncs.get(member.context);
658
+ if (synced && !synced.ok) throw new Error(`pod command: 이미지 판을 못 맞췄다: ${synced.detail}`);
659
+ if (synced?.imageRef) member = { ...member, imageRef: synced.imageRef };
660
+ }
623
661
  }
624
662
  const imageRef = member?.imageRef;
625
663
  if (!imageRef) log('pod.command-job', 'image-fallback-local', { reason: !member ? 'no-pool-member' : !imageCommit ? 'image-commit-unavailable' : 'registry-tag-unavailable' });
@@ -660,6 +698,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
660
698
  }
661
699
  const manifest = podCommandJobManifest({
662
700
  name, namespace, launch, image: imageRef ?? image,
701
+ provenance: options.provenance, provenanceGate: options.provenanceGate,
663
702
  ...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
664
703
  repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
665
704
  ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
@@ -14,9 +14,12 @@
14
14
  * 이미지는 표준판(elanous-harness)만 — 이 발사 경로는 lite 를 쓰지 않는다.
15
15
  */
16
16
  import { spawnSync } from 'node:child_process';
17
+ import { mkdtempSync, rmSync } from 'node:fs';
18
+ import { tmpdir } from 'node:os';
19
+ import { join } from 'node:path';
17
20
  import { SPAWN_SYNC_MAX_BUFFER } from '../../util/spawn-sync-output.js';
18
21
  import { debug } from '../../debug/log.js';
19
- import { memberHasRegistry, registryImageRef, type RemoteRun } from './pod-pool.js';
22
+ import { memberHasRegistry, registryImageRef, syncPoolImages, parsePodPool, type PodPoolMember, type RemoteRun } from './pod-pool.js';
20
23
 
21
24
  const POD_IMAGE = 'elanous-harness';
22
25
 
@@ -59,6 +62,91 @@ export function resolvePodImageSource(
59
62
  return { kind: 'pinned', ref: podImageRef(registry, commit), commit, registry };
60
63
  }
61
64
 
65
+ export interface PodShelfImage { readonly commit: string; readonly image: string; readonly action: 'fresh' | 'built' }
66
+
67
+ export function resolvePodShelfRef(ref: string, cwd = process.cwd(), exec = spawnSync): string {
68
+ const requested = ref.trim();
69
+ if (!requested || requested.startsWith('-') || /[\s\x00-\x1f]/u.test(requested)) throw new Error('pod shelf: invalid ref');
70
+ const spec = /^#?(\d+)$/u.exec(requested);
71
+ if (spec) {
72
+ const pr = exec('gh', ['pr', 'view', spec[1]!, '--json', 'headRefOid', '--jq', '.headRefOid'], { cwd, encoding: 'utf8', timeout: 30_000 });
73
+ const sha = String(pr.stdout ?? '').trim().toLowerCase();
74
+ if (pr.status !== 0 || !/^[0-9a-f]{40}$/u.test(sha)) throw new Error(`pod shelf: PR head unavailable: ${requested}`);
75
+ return sha;
76
+ }
77
+ const git = exec('git', ['rev-parse', '--verify', `${requested}^{commit}`], { cwd, encoding: 'utf8', timeout: 30_000 });
78
+ const sha = String(git.stdout ?? '').trim().toLowerCase();
79
+ if (git.status !== 0 || !/^[0-9a-f]{40}$/u.test(sha)) throw new Error(`pod shelf: ref unavailable: ${requested}`);
80
+ return sha;
81
+ }
82
+
83
+ /** Checkout only the requested commit; syncPoolImages retains its per-host build lock and SHA12 registry check. */
84
+ export async function putPodShelfImage(ref: string, pool: string, deps: {
85
+ resolve?: (ref: string) => string;
86
+ sync?: typeof syncPoolImages;
87
+ checkout?: (commit: string, dir: string) => void;
88
+ tempDir?: () => string;
89
+ remove?: (dir: string) => void;
90
+ hasRegistry?: (member: PodPoolMember) => boolean;
91
+ } = {}): Promise<PodShelfImage> {
92
+ const members = parsePodPool(pool);
93
+ if (members.length !== 1 || !members[0]!.sshHost) throw new Error('pod shelf: one remote registry pool member is required');
94
+ const member: PodPoolMember = members[0]!;
95
+ if (!(deps.hasRegistry ?? memberHasRegistry)(member)) throw new Error('pod shelf: remote registry unavailable');
96
+ const commit = (deps.resolve ?? resolvePodShelfRef)(ref);
97
+ if (!/^[0-9a-f]{40}$/u.test(commit)) throw new Error('pod shelf: full commit required');
98
+ const registry = member.registry ?? podImageRegistry();
99
+ const image = podImageRef(registry, commit);
100
+ if (!deps.sync && registryImageRef(member, commit) === image) return { commit, image, action: 'fresh' };
101
+ const dir = (deps.tempDir ?? (() => mkdtempSync(join(tmpdir(), 'pod-shelf-'))))();
102
+ try {
103
+ if (deps.checkout) deps.checkout(commit, dir);
104
+ else {
105
+ const clone = spawnSync('git', ['clone', '-q', '--no-checkout', process.cwd(), dir], { encoding: 'utf8', timeout: 120_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
106
+ if (clone.status !== 0) throw new Error(`pod shelf: clone failed: ${clone.stderr}`);
107
+ const fetch = spawnSync('git', ['-C', dir, 'fetch', '-q', 'origin', commit], { encoding: 'utf8', timeout: 120_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
108
+ if (fetch.status !== 0) {
109
+ const remote = spawnSync('git', ['remote', 'get-url', 'origin'], { encoding: 'utf8', timeout: 10_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
110
+ if (remote.status !== 0) throw new Error(`pod shelf: fetch failed: ${fetch.stderr}`);
111
+ const fromOrigin = spawnSync('git', ['-C', dir, 'fetch', '-q', String(remote.stdout).trim(), commit], { encoding: 'utf8', timeout: 120_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
112
+ if (fromOrigin.status !== 0) throw new Error(`pod shelf: fetch failed: ${fromOrigin.stderr}`);
113
+ }
114
+ const checkout = spawnSync('git', ['-C', dir, 'checkout', '--detach', commit], { encoding: 'utf8', timeout: 120_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
115
+ if (checkout.status !== 0) throw new Error(`pod shelf: checkout failed: ${checkout.stderr}`);
116
+ }
117
+ const sync = deps.sync ?? syncPoolImages;
118
+ const results = await sync([member], 'elanous-harness:local', commit, {
119
+ buildScript: join(dir, 'docker/harness/build.sh'),
120
+ ...(deps.sync ? {} : { ship: () => ({ ok: false, action: 'failed' as const, detail: 'shelf build failed; local image fallback prohibited' }) }),
121
+ remoteBuild: deps.sync ? undefined : async (host, cluster, registry) => {
122
+ const { spawn } = await import('node:child_process');
123
+ return new Promise((done) => {
124
+ const child = spawn('bash', [join(dir, 'docker/harness/build.sh')], { env: { ...process.env, ELANOUS_BUILD_REMOTE: host, ELANOUS_L2_CLUSTER: cluster, ...(registry ? { ELANOUS_BUILD_REGISTRY: registry } : {}) }, stdio: ['ignore', 'pipe', 'pipe'] });
125
+ let output = '';
126
+ child.stdout.on('data', (chunk) => { output += chunk; });
127
+ child.stderr.on('data', (chunk) => { output += chunk; });
128
+ child.on('close', (code) => done({ ok: code === 0, detail: output.slice(-300) }));
129
+ child.on('error', (error) => done({ ok: false, detail: error.message }));
130
+ });
131
+ },
132
+ });
133
+ const result = results.get(member.context);
134
+ if (!result?.ok || result.imageRef !== image) throw new Error(`pod shelf: image unavailable: ${result?.detail ?? image}`);
135
+ return { commit, image, action: result.action === 'fresh' ? 'fresh' : 'built' };
136
+ } finally { (deps.remove ?? ((path) => rmSync(path, { recursive: true, force: true })))(dir); }
137
+ }
138
+
139
+ export function listPodShelfImages(pool: string, run: RemoteRun): string[] {
140
+ const member = parsePodPool(pool)[0];
141
+ if (!member?.sshHost) throw new Error('pod shelf: remote pool member required');
142
+ const registry = member.registry ?? podImageRegistry();
143
+ const port = registry.slice(registry.lastIndexOf(':') + 1);
144
+ const result = run(member.sshHost, `curl -fsS --max-time 5 http://localhost:${port}/v2/elanous-harness/tags/list 2>/dev/null`);
145
+ if (result.status !== 0) throw new Error(`pod shelf: registry unavailable: ${result.stderr}`);
146
+ const tags: unknown = JSON.parse(result.stdout).tags;
147
+ return Array.isArray(tags) ? tags.filter((tag): tag is string => typeof tag === 'string' && /^[0-9a-f]{12}$/u.test(tag)).map((tag) => `${registry}/elanous-harness:${tag}`) : [];
148
+ }
149
+
62
150
  export function podImageMissingMessage(ref: string): string {
63
151
  return `기준 이미지 ${ref} 가 레지스트리에 없다 — 레일이 굽기 전이다`;
64
152
  }
@@ -236,6 +236,10 @@ export interface ExternalGitHubProbe {
236
236
  githubHttps: boolean | null;
237
237
  measuredAt: string | null;
238
238
  reason: string | null;
239
+ /** Name of the disposable Pod for matching this reading with its Kubernetes logs. */
240
+ podName?: string;
241
+ /** Unmodified stdout from `kubectl logs` for this Pod (only present when readable). */
242
+ podLog?: string;
239
243
  }
240
244
  const DNS_CACHE_MS = 10 * 60_000;
241
245
  const DNS_STALE_OK_MS = 30 * 60_000;
@@ -261,9 +265,11 @@ export function probePoolGitHub(context: string, kubectl: PoolKubectl = leaseKub
261
265
  if (typeof record?.at !== 'number' || now() < record.at || now() - record.at >= 60_000) return null;
262
266
  if (typeof record.measuredAt !== 'string' || ![true, false].includes(record.externalDns as boolean) ||
263
267
  ![true, false, null].includes(record.githubHttps as boolean | null) ||
264
- !(record.reason === null || typeof record.reason === 'string')) return null;
268
+ !(record.reason === null || typeof record.reason === 'string') ||
269
+ typeof record.podName !== 'string' || typeof record.podLog !== 'string') return null;
265
270
  return { externalDns: record.externalDns as boolean, githubHttps: record.githubHttps as boolean | null,
266
- measuredAt: record.measuredAt, reason: record.reason as string | null };
271
+ measuredAt: record.measuredAt, reason: record.reason as string | null,
272
+ podName: record.podName, podLog: record.podLog };
267
273
  } catch { return null; }
268
274
  };
269
275
  const fresh = cached();
@@ -285,6 +291,7 @@ export function probePoolGitHub(context: string, kubectl: PoolKubectl = leaseKub
285
291
  const shared = cached();
286
292
  if (shared) return shared;
287
293
  const result = runPoolGitHubProbe(context, kubectl, new Date(now()).toISOString());
294
+ debug.log('pod.lease', 'github-egress-probe', { context, ...result });
288
295
  if (result.measuredAt !== null) {
289
296
  const temp = `${cache}.${randomUUID()}.tmp`;
290
297
  try { writeFileSync(temp, JSON.stringify({ ...result, at: now() }), { mode: 0o600 }); renameSync(temp, cache); }
@@ -300,16 +307,18 @@ export function probePoolGitHub(context: string, kubectl: PoolKubectl = leaseKub
300
307
  function runPoolGitHubProbe(context: string, kubectl: PoolKubectl, measuredAt: string): ExternalGitHubProbe {
301
308
  const name = `elanous-egress-${randomUUID().slice(0, 12)}`;
302
309
  const base = ['--context', context, '--request-timeout=15s'];
303
- const unknown = (reason: string): ExternalGitHubProbe => ({ externalDns: null, githubHttps: null, measuredAt: null, reason });
304
310
  let created = false;
311
+ const unknown = (reason: string): ExternalGitHubProbe => ({ externalDns: null, githubHttps: null, measuredAt: null, reason,
312
+ ...(created ? { podName: name } : {}) });
305
313
  try {
306
314
  const manifest = JSON.stringify({ apiVersion: 'v1', kind: 'Pod', metadata: { name, namespace: 'elanous-test', labels: { 'elanous.probe': 'github-egress' } }, spec: {
307
315
  restartPolicy: 'Never', activeDeadlineSeconds: 35, automountServiceAccountToken: false,
308
316
  containers: [{ name: 'probe', image: 'busybox:1.36', command: ['sh', '-c',
309
- 'if nslookup github.com >/dev/null 2>&1; then echo EXTERNAL_DNS_OK; if wget -q -T 8 -O /dev/null https://github.com/; then echo GITHUB_HTTPS_OK; else echo GITHUB_HTTPS_FAILED; fi; else echo EXTERNAL_DNS_FAILED; fi'],
317
+ 'if nslookup github.com 2>&1; then echo EXTERNAL_DNS_OK; if wget -T 8 -O /dev/null https://github.com/ 2>&1; then echo GITHUB_HTTPS_OK; else echo GITHUB_HTTPS_FAILED; fi; else echo EXTERNAL_DNS_FAILED; fi'],
310
318
  resources: { requests: { cpu: '0', memory: '16Mi' }, limits: { cpu: '100m', memory: '64Mi' } } }],
311
319
  } });
312
- if (kubectl([...base, 'create', '-f', '-'], manifest).status !== 0) return unknown('probe create failed');
320
+ const createdPod = kubectl([...base, 'create', '-f', '-'], manifest);
321
+ if (createdPod.status !== 0) return unknown(`probe create failed${createdPod.stderr.trim() ? `: ${createdPod.stderr.trim().split('\n').pop()!.slice(0, 160)}` : ''}`);
313
322
  created = true;
314
323
  const waited = kubectl([...base, '-n', 'elanous-test', 'wait', '--for=jsonpath={.status.phase}=Succeeded', `pod/${name}`, '--timeout=25s']);
315
324
  const podResult = kubectl([...base, '-n', 'elanous-test', 'get', `pod/${name}`, '-o', 'json']);
@@ -327,10 +336,10 @@ function runPoolGitHubProbe(context: string, kubectl: PoolKubectl, measuredAt: s
327
336
  const httpsOk = markers.includes('GITHUB_HTTPS_OK');
328
337
  const httpsFail = markers.includes('GITHUB_HTTPS_FAILED');
329
338
  if (dnsFail && !dnsOk && !httpsOk && !httpsFail)
330
- return { externalDns: false, githubHttps: null, measuredAt, reason: 'external DNS failed' };
339
+ return { externalDns: false, githubHttps: null, measuredAt, reason: 'external DNS failed', podName: name, podLog: logs.stdout };
331
340
  if (dnsOk && !dnsFail && httpsOk !== httpsFail)
332
- return { externalDns: true, githubHttps: httpsOk, measuredAt, reason: httpsFail ? 'GitHub HTTPS failed' : null };
333
- return unknown(waited.status === 0 ? 'probe output unavailable' : 'probe timeout');
341
+ return { externalDns: true, githubHttps: httpsOk, measuredAt, reason: httpsFail ? 'GitHub HTTPS failed' : null, podName: name, podLog: logs.stdout };
342
+ return { ...unknown(waited.status === 0 ? 'probe output unavailable' : 'probe timeout'), podLog: logs.stdout };
334
343
  } catch { return unknown('probe failed'); }
335
344
  finally {
336
345
  if (created) try { kubectl([...base, '-n', 'elanous-test', 'delete', `pod/${name}`, '--ignore-not-found=true', '--wait=false']); }