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
@@ -1,6 +1,7 @@
1
- import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync } from 'node:fs';
1
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, writeFileSync } from 'node:fs';
2
2
  import { tmpdir } from 'node:os';
3
3
  import { execFileSync, spawnSync } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
4
5
  import { loadRunLedger as loadRunLedgerSync, loadRunLedgerWithMetadata, runLedgerDir, resolveFederatedRunLedgerDirectories } from '../self-implement/run-ledger.js';
5
6
  import { goalRunDbPath, loadGoalRunQuery } from '../self-implement/goal-run-store.js';
6
7
  import { loadGoalAskRecords } from '../self-implement/goal-ask-store.js';
@@ -14,14 +15,16 @@ import { assignedVersions, releasedVersion, validateVersion } from '../release-l
14
15
  import { compareVersions } from '../directives/version-at.js';
15
16
  import { cardsBoard, countBoardTasks, INTERNAL_PACK_PROJECT, mergeBoards, releasePackBoard, type BoardNode } from '../task-agent/board.js';
16
17
  import type { Task } from '../task-orchestrator/types.js';
17
- import { cardPrNumber, CLOSED_BY_HAND_EVENT, closeTaskCard, COMPLETION_KINDS, handTask, updateTaskCard, LIVE_MOVE_HISTORY_EVENT, LIVE_MOVE_RESULT_EVENT, nextMoveFor, resolveHandText, readTaskAgentState, readTaskCard, runTagChange, taskAgentStatePath as taskStatePathDefault, taskCardLabelContext, shellQuote, TASK_CARD_PREFIX, TASK_SEATS, type CompletionKind, type TaskCard, type TaskLaunchContext, type TaskLaunchReceipt, type TaskLauncher, type TaskSeat } from '../task-agent/task-hand.js';
18
+ import { boundPrTerminal, cardPrNumber, CLOSED_BY_HAND_EVENT, closeTaskCard, COMPLETION_KINDS, HAND_MOVE_HISTORY_EVENT, updateTaskCard, LIVE_MOVE_HISTORY_EVENT, LIVE_MOVE_RESULT_EVENT, nextMoveFor, resolveHandText, readTaskAgentState, readTaskCard, runTagChange, taskAgentStatePath as taskStatePathDefault, taskCardLabelContext, shellQuote, TASK_CARD_PREFIX, TASK_SEATS, type CompletionKind, type TaskCard, type TaskCardEvent, type TaskLaunchContext, type TaskLaunchReceipt, type TaskLauncher, type TaskSeat } from '../task-agent/task-hand.js';
18
19
  import { RUN_TAG_KEYS, runIdentityFieldText, runPriorityClass } from '../task-agent/run-identity.js';
19
20
  import { readCardSalvageBranch, recordWiringLiveVerified, refreshCardRunBinding, type CardRunEvidenceDeps } from '../task-agent/card-evidence.js';
20
21
  import { captureReviewResults } from '../task-agent/review-result-capture.js';
21
22
  import { replayRemoteCardMoves } from '../task-agent/shadow.js';
22
23
  import { remoteLedgerMirrorDirs } from '../task-agent/parent-host.js';
24
+ import { buildWorkOrder } from '../task-agent/work-order-build.js';
23
25
  import { ambiguousGreenSweepPrs, decideGreenSweep, greenSweepCandidates, observeGreenSweep, type GreenSweepPr } from '../task-agent/green-sweep.js';
24
26
  import { HAND_MOVE_KINDS, recordHandMove } from '../task-agent/live-move-history.js';
27
+ import { handTaskWithTierSplit, type TierSizedDecompose } from '../task-agent/tier-split.js';
25
28
  import { advanceMission, handMission, MissionAdvanceError, openMissionIds, recordPieceRef, type AdvanceMissionResult, type MissionDecompose, type PieceEvidenceReader } from '../task-agent/mission.js';
26
29
  import { formatSevenVerbLive, formatTaskAgentCover, measureSevenVerbLive, measureTaskAgentCover, type CoverRow, type ImplementCardRunBinding, type ImplementRunMergeEvent, type SevenVerbLive, type TaskAgentCoverInput } from '../task-agent/cover.js';
27
30
  import { LogStore, STORE_SAFETY_MAX, type LogQuery, type LogStoreRow } from '../mss/logging/log-store.js';
@@ -49,6 +52,8 @@ export interface TasksCliDeps {
49
52
  registerSink?: (surface: string) => Promise<unknown>;
50
53
  /** `task hand --mission` 의 분해기(시험 주입). 기본 = 나열형은 결정론 · 아니면 `decomposeSelfDevGoal`. */
51
54
  missionDecompose?: MissionDecompose;
55
+ /** TIER-SPLIT-BEFORE-LAUNCH — `tasks hand --tier 상|특 --live` 의 분해기(시험 주입). 키가 없으면 `DEFAULT_TIER_SIZED_DECOMPOSE`. */
56
+ tierSizedDecompose?: TierSizedDecompose;
52
57
  /** `task advance` 의 착지 근거 읽기(시험 주입). 기본 = `predecessorState`(gh · 런 원장). */
53
58
  pieceEvidence?: PieceEvidenceReader;
54
59
  /** `task board` 의 내부 팩 어댑터(시험 주입). 기본 = 현재 판(`checklistDevVersion()`)의 `releasePackBoard` — 읽기만. */
@@ -57,6 +62,8 @@ export interface TasksCliDeps {
57
62
  releaseVersions?: () => string[];
58
63
  /** Isolated checklist read for PR adoption. */
59
64
  adoptChecklist?: typeof listChecklist;
65
+ /** Isolated checklist read for work-order build. */
66
+ workOrderChecklist?: typeof listChecklist;
60
67
  /** `tasks adopt-pr` live PR read seam; default is gh in this repository. */
61
68
  adoptPrView?: (number: number, cwd: string) => import('../task-agent/adopt-pr.js').AdoptPrView;
62
69
  /** Isolated ledger proof for a launched card being adopted. */
@@ -85,6 +92,10 @@ export interface TasksCliDeps {
85
92
  coverImplementRunMerges?: () => ReadonlyMap<string, ImplementRunMergeEvent> | null;
86
93
  /** Read test-universe ledgers only when --include-test was requested. */
87
94
  coverIncludeTest?: boolean;
95
+ /** `tasks outcomes` 의 «지금» — 상대 기간(`--since 24h`)을 푸는 기준(시험 주입). 기본 = `Date.now()`. */
96
+ outcomesNow?: () => number;
97
+ /** `tasks outcomes` 페이지 상한(시험 주입). 기본 = `OUTCOMES_QUERY_LIMIT`. */
98
+ outcomesLimit?: number;
88
99
  /** TA-REJUDGE-ON-HEAD — `tasks rejudge` 의 판단 의존(시험 주입 · 기본 = 설정 liveMoves ⊕ 실물 gh·리뷰·재게이트·land). */
89
100
  rejudge?: Partial<import('../task-agent/rejudge-on-head.js').RejudgeDeps>;
90
101
  /** TA-REJUDGE-ON-HEAD — `tasks regate-run` 의 재게이트(시험 주입 · 기본 `runHostRegate`). */
@@ -162,10 +173,23 @@ export interface DefaultTaskLauncherDeps {
162
173
  launchHoldActive?: () => boolean;
163
174
  /** HQ 판(시험 주입). */
164
175
  localVersion?: string;
176
+ /** HQ-owned, refresh-less Codex access mirror to install before a remote parent launch. */
177
+ codexAccessMirror?: () => Promise<{ elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number; mirrors?: Array<{ elanousAuth: string; codexAuth: string; account: string; usedPercent?: number; thresholdPercent: number; expiresAt: number }> } | null>;
178
+ /** HQ-owned Grok subscription access mirror; resolved before the first remote SSH call. */
179
+ grokAccessMirror?: () => import('../task-agent/parent-host.js').OwnerGrokAccessMirror;
180
+ /** Clock used to recheck mirror freshness immediately before installation. */
181
+ now?: () => number;
182
+ /** Isolated integration seam; production still reads the HQ rotation snapshot and config directly. */
183
+ ownerCodexRotation?: () => ReturnType<typeof import('../oauth/codex-account-store.js').inspectCodexRotation>;
184
+ ownerCodexRotationConfig?: { accountOrder?: readonly string[]; thresholdPercentByAccount?: Readonly<Record<string, unknown>> };
185
+ /** The HQ owner fence is checked before any token refresh. */
186
+ ownerCodexLeaseHolder?: () => boolean;
165
187
  /** 원격 → 로컬 되돌림 알림(시험 주입). 기본 = stderr 한 줄. */
166
188
  notice?: (line: string) => void;
167
189
  }
168
190
 
191
+ class NoEligibleOwnerCodexAccountError extends Error {}
192
+
169
193
  /**
170
194
  * HARNESS-PARENT-ON-MSB1 — 켜져 있고 발사 전 점검이 통과하면 원격(ssh)에서 부모를 띄운다(PR 까지만 · 병합은 HQ).
171
195
  * 막히면 null — 호출부가 종전 로컬 발사로 간다(관측: task-agent parent-host-fallback).
@@ -180,11 +204,87 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
180
204
  const multi = Array.isArray(configured);
181
205
  const targets = configured === null ? [] : parentHostModule.resolveParentHosts(configured, deps.parentHost === undefined ? process.env : { ...process.env, ELANOUS_TA_PARENT_HOST: undefined });
182
206
  if (!targets.length) return null;
207
+ const providerFromArgs = args.find((arg) => arg.startsWith('--child-llm-provider='))?.slice('--child-llm-provider='.length)
208
+ ?? (args.includes('--child-llm-provider') ? args[args.indexOf('--child-llm-provider') + 1] : undefined);
209
+ const effectiveChildProvider = context.effectiveChildProvider ?? providerFromArgs;
183
210
  const notice = deps.notice ?? ((line: string) => { try { process.stderr.write(`${line}\n`); } catch { /* ignore */ } });
184
211
  const failed = (target: typeof targets[number], gaps: string[], facts: Record<string, string> = {}): void => {
185
212
  try { debug.log('task-agent', 'parent-host-fallback', { host: target.host, runId: context.runId, gaps, facts }); } catch { /* fail-soft */ }
186
213
  notice(`[parent-host] ${target.host} 로 못 띄움 — ${multi ? '다음 호스트 또는 로컬 발사로 간다' : '로컬 발사로 간다'}: ${gaps.join(' · ')}`);
187
214
  };
215
+ type OwnerMirror = { elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number; mirrors?: Array<{ elanousAuth: string; codexAuth: string; account: string; usedPercent?: number; thresholdPercent: number; expiresAt: number }> };
216
+ let accessMirror: OwnerMirror | null | undefined;
217
+ const getAccessMirror = async (): Promise<OwnerMirror | null> => {
218
+ if (accessMirror !== undefined) return accessMirror;
219
+ if (deps.codexAccessMirror) {
220
+ accessMirror = await deps.codexAccessMirror();
221
+ return accessMirror;
222
+ }
223
+ const [pod, authStore, codex, hq] = await Promise.all([
224
+ import('../task-orchestrator/surfaces/self-implement-pod.js'),
225
+ import('../oauth/store.js'),
226
+ import('../oauth/codex.js'),
227
+ import('../hq/hq.js'),
228
+ ]);
229
+ const { inspectCodexRotation } = await import('../oauth/codex-account-store.js');
230
+ const { planOwnerCodexMirrorCandidates, podAccountThresholdPercent } = await import('../task-orchestrator/surfaces/pod-account-broker.js');
231
+ const { getUserConfig } = await import('../user-config.js');
232
+ const rotation = deps.ownerCodexRotation?.() ?? inspectCodexRotation();
233
+ const config = getUserConfig();
234
+ const ownerConfig = deps.ownerCodexRotationConfig;
235
+ const candidates = [...rotation.candidates];
236
+ // No local credential preserves the established local-launch fallback.
237
+ if (candidates.length === 0) { accessMirror = null; return null; }
238
+ const ownerLeaseHeld = deps.ownerCodexLeaseHolder?.() ?? hq.hqFenceDecision('ledger-cli').run;
239
+ if (!ownerLeaseHeld) throw new NoEligibleOwnerCodexAccountError('HQ Codex 토큰 주인 임대가 없어 원격 미러 발사를 거부한다');
240
+ const eligible = planOwnerCodexMirrorCandidates(candidates, {
241
+ accountOrder: ownerConfig?.accountOrder ?? config.llm?.codexAccountOrder ?? [],
242
+ thresholdPercentByAccount: ownerConfig?.thresholdPercentByAccount ?? config.llm?.codexAccountRotationThresholdPercentByAccount,
243
+ });
244
+ if (candidates.length > 0 && eligible.length === 0) throw new NoEligibleOwnerCodexAccountError('HQ 소유 Codex 계정이 모두 사용 임계에 도달해 원격 부모 발사를 거부한다');
245
+ const prerefreshDeps = {
246
+ credentials: (account: string) => pod.hostCredentials(account, authStore.authStorePath(), () => '', { requireExplicitChatgptAuthMode: true }),
247
+ refresh: (account: string) => codex.refreshCodexAccountHome(account),
248
+ isLeaseHolder: () => deps.ownerCodexLeaseHolder?.() ?? hq.hqFenceDecision('ledger-cli').run,
249
+ };
250
+ const mirrors: NonNullable<OwnerMirror['mirrors']> = [];
251
+ for (const [index, candidate] of eligible.entries()) {
252
+ const usedPercent = candidate.usedPercent;
253
+ const thresholdPercent = podAccountThresholdPercent(candidate.name, {
254
+ thresholdPercentByAccount: ownerConfig?.thresholdPercentByAccount ?? config.llm?.codexAccountRotationThresholdPercentByAccount,
255
+ });
256
+ // HQ is the sole refresh owner. Send every usable account as an access-only snapshot
257
+ // so the remote Pod broker can rotate instead of pinning all jobs to one account.
258
+ let credential: Awaited<ReturnType<typeof pod.podCodexCredentialWithPrerefresh>> = null;
259
+ try { credential = await pod.podCodexCredentialWithPrerefresh(candidate.name, prerefreshDeps); }
260
+ catch {
261
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-account-skipped', { account: candidate.name, reason: 'credential-error' }); } catch { /* fail-soft */ }
262
+ continue;
263
+ }
264
+ if (!credential) {
265
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-account-skipped', { account: candidate.name, reason: 'expiring-or-refresh-failed' }); } catch { /* fail-soft */ }
266
+ continue;
267
+ }
268
+ const expiresAt = (JSON.parse(credential.elanousAuth) as { providers?: { 'openai-codex'?: { tokens?: { expiresAt?: unknown } } } }).providers?.['openai-codex']?.tokens?.expiresAt;
269
+ if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt) || expiresAt <= (deps.now?.() ?? Date.now()) + 3 * 60 * 60 * 1000) {
270
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-account-skipped', { account: candidate.name, reason: 'access-expiring' }); } catch { /* fail-soft */ }
271
+ continue;
272
+ }
273
+ mirrors.push({ elanousAuth: credential.elanousAuth, codexAuth: credential.codexAuth, account: candidate.name,
274
+ expiresAt,
275
+ ...(usedPercent !== undefined ? { usedPercent } : {}), thresholdPercent });
276
+ // The receiving marker parser accepts at most 16 distinct accounts.
277
+ // Apply the same bound before writing credentials on the remote parent.
278
+ if (mirrors.length === 16) {
279
+ for (const skipped of eligible.slice(index + 1)) {
280
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-account-skipped', { account: skipped.name, reason: 'snapshot-limit-16' }); } catch { /* fail-soft */ }
281
+ }
282
+ break;
283
+ }
284
+ }
285
+ accessMirror = mirrors.length ? { ...mirrors[0]!, mirrors } : null;
286
+ return accessMirror;
287
+ };
188
288
  if (cwd) {
189
289
  failed(targets[0]!, ['project-target-is-local']);
190
290
  return null;
@@ -195,6 +295,11 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
195
295
  // 그 앞의 readParentHostCapacity 도 ssh). 가드를 아래로 내리면 hold 경로에서 시험이 실 ssh 를 쏜다(R7 사고 모양).
196
296
  // hold 경로를 재는 시험은 deps.ssh 가짜 또는 parentHost:null 을 주입한다(real-launch-guard.test 가 이 순서를 문다).
197
297
  if (!deps.ssh) (await import('../task-agent/real-launch-guard.js')).refuseRealLaunchUnderTest('remote-parent-ssh', targets.map((target) => target.host).join(','));
298
+ // Grok access is selected/refreshed on HQ before preflight performs any SSH call. A missing or stale
299
+ // subscription must fail closed without touching the remote host or falling back to a local launch.
300
+ const grokAccessMirror = effectiveChildProvider === 'grok'
301
+ ? (deps.grokAccessMirror?.() ?? parentHostModule.resolveOwnerGrokAccessMirror())
302
+ : undefined;
198
303
  let launchHoldActive = false;
199
304
  try {
200
305
  if (deps.launchHoldActive) launchHoldActive = deps.launchHoldActive();
@@ -204,8 +309,39 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
204
309
  launchHoldActive = readLandingFreeze(prodInstanceRoot())?.holdLaunches === true;
205
310
  }
206
311
  } catch { launchHoldActive = true; /* 못 읽으면 막힌 것으로(fail-closed) */ }
207
- const capacities = Object.fromEntries(multi ? targets.map((target) => [target.host, parentHostModule.readParentHostCapacity(target, deps.ssh)]) : []);
208
- const ordered = multi ? parentHostModule.orderParentHosts(targets, context.runId, capacities) : targets;
312
+ const podGoal = context.substrate === 'pod' ? context.podGoal : undefined;
313
+ // 부모에서 잰 메모리 선택자만 원격 자식에도 넘긴다. 로컬의 나머지 환경·자격은 SSH 로 복사하지 않는다.
314
+ const remoteEnv = { ...context.env };
315
+ // These labels describe an HQ-selected Codex access mirror; never forward an inherited label by itself.
316
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNT;
317
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_USED_PERCENT;
318
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_THRESHOLD_PERCENT;
319
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNTS;
320
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCESS_ONLY;
321
+ if (podGoal) for (const key of ['ELANOUS_POD_MEMORY_TIER', 'ELANOUS_POD_MEMORY', 'ELANOUS_POD_MEMORY_HIGH', 'ELANOUS_POD_MEMORY_LITE', 'ELANOUS_POD_GOAL_TYPE'] as const) {
322
+ const value = context.env[key] ?? process.env[key];
323
+ if (value !== undefined) remoteEnv[key] = value;
324
+ }
325
+ const memoryLimit = podGoal ? (await import('../task-orchestrator/surfaces/self-implement-pod.js')).podMemoryLimitFor(podGoal, remoteEnv).limit : undefined;
326
+ const fits = Object.fromEntries(targets.map((target) => {
327
+ const fit = memoryLimit
328
+ ? parentHostModule.readParentHostPodFit(target, memoryLimit, deps.ssh)
329
+ : { state: 'unmeasured' as const, memoryLimit: '', requiredBytes: null, allocatableBytes: null, reason: 'pod-context-unmeasured' };
330
+ try { debug.log('task-agent.parent-host', 'pod-fit', { host: target.host, runId: context.runId, ...fit }); } catch { /* fail-soft */ }
331
+ if (fit.state === 'never-fits') notice(`[parent-host] ${target.host} 제외 — ${fit.reason}: Pod ${fit.memoryLimit} (${fit.requiredBytes} bytes) > node allocatable ${fit.allocatableBytes} bytes`);
332
+ return [target.host, fit];
333
+ }));
334
+ const eligible = targets.filter((target) => fits[target.host]?.state !== 'never-fits');
335
+ if (!eligible.length) {
336
+ const details = targets.map((target) => `${target.host}: Pod ${fits[target.host]!.memoryLimit} (${fits[target.host]!.requiredBytes} bytes) > node allocatable ${fits[target.host]!.allocatableBytes} bytes`).join(' · ');
337
+ throw new Error(`parent-host memory-never-fits — ${details}; local fallback refused`);
338
+ }
339
+ const capacities = Object.fromEntries(multi ? eligible.map((target) => [target.host, parentHostModule.readParentHostCapacity(target, deps.ssh)]) : []);
340
+ const measured = eligible.filter((target) => fits[target.host]?.state === 'fits');
341
+ const unknown = eligible.filter((target) => fits[target.host]?.state !== 'fits');
342
+ const ordered = multi
343
+ ? [...parentHostModule.orderParentHosts(measured, context.runId, capacities), ...parentHostModule.orderParentHosts(unknown, context.runId, capacities)]
344
+ : eligible;
209
345
  for (const target of ordered) {
210
346
  if (multi && (!capacities[target.host] || capacities[target.host]!.approvalHeadroom <= 0)) {
211
347
  failed(target, ['capacity-unavailable']);
@@ -217,11 +353,64 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
217
353
  if (!preflight.ok) { failed(target, preflight.gaps, preflight.facts); continue; }
218
354
  if (preflight.warnings.length) notice(`⚠ ${target.host} 자격: ${preflight.warnings.join(' · ')}`);
219
355
  try {
220
- const launched = parentHostModule.launchRemoteParent(target, args, context.env, deps.ssh);
356
+ if (parentHostModule.shouldInstallRemoteCodexAccess(context.effectiveChildProvider)) {
357
+ let mirror: OwnerMirror | null = null;
358
+ let mirrorReason = 'credential-source-empty';
359
+ try { mirror = await getAccessMirror(); }
360
+ catch (error) {
361
+ if (error instanceof NoEligibleOwnerCodexAccountError) throw error;
362
+ mirrorReason = 'credential-source-error';
363
+ }
364
+ // The receiver accepts at most 16 accounts. Use this same bounded
365
+ // snapshot for installation, the launch marker, and the selected account,
366
+ // including mirrors supplied by the injected credential source.
367
+ const mirrors = mirror?.mirrors?.slice(0, 16);
368
+ const selected = mirrors?.[0] ?? mirror;
369
+ if (mirror) {
370
+ // Snapshot construction can outlive the HQ owner lease. Fresh tokens
371
+ // bypass prerefresh's lock, so recheck before any credential leaves HQ.
372
+ if (!(deps.ownerCodexLeaseHolder?.() ?? (await import('../hq/hq.js')).hqFenceDecision('ledger-cli').run)) {
373
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-owner-lease-lost', { host: target.host, runId: context.runId, reason: 'owner-lease-lost-before-install' }); } catch { /* fail-soft */ }
374
+ throw new NoEligibleOwnerCodexAccountError('HQ Codex 토큰 주인 임대가 설치 직전에 사라져 원격 미러 발사를 거부한다');
375
+ }
376
+ if (mirror.mirrors && mirror.mirrors.length > 16) {
377
+ for (const skipped of mirror.mirrors.slice(16)) {
378
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-account-skipped', { account: skipped.account, reason: 'snapshot-limit-16' }); } catch { /* fail-soft */ }
379
+ }
380
+ }
381
+ // Each detached parent keeps its own auth store and Codex homes for
382
+ // its full lifetime, including the legacy single-account source.
383
+ const identity = createHash('sha256').update(`${context.runId}\0${context.launchId}`).digest('hex').slice(0, 20);
384
+ const xdgRoot = `${target.configDir ?? '$HOME/.elanous'}/remote-parent-credentials/${identity}`;
385
+ const mirrorDir = `${xdgRoot}/elanous`;
386
+ const installed = mirrors ?? [{ ...mirror, account: mirror.account ?? 'default' }];
387
+ parentHostModule.installRemoteCodexAccessBatch({ ...target, configDir: mirrorDir }, installed, deps.ssh);
388
+ remoteEnv.XDG_CONFIG_HOME = xdgRoot;
389
+ remoteEnv.CODEX_HOME = `${mirrorDir}/codex-default`;
390
+ // XDG isolation is for Codex credentials only. gh otherwise loses
391
+ // the remote host's existing login before a Pod can be created.
392
+ remoteEnv.GH_CONFIG_DIR = '$HOME/.config/gh';
393
+ }
394
+ else {
395
+ try { debug.log('task-agent.parent-host', 'codex-access-mirror-unavailable', { host: target.host, runId: context.runId, reason: mirrorReason }); } catch { /* fail-soft */ }
396
+ failed(target, ['codex-access-mirror-unavailable']);
397
+ return null;
398
+ }
399
+ if (selected?.account) {
400
+ remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNT = selected.account;
401
+ remoteEnv.ELANOUS_REMOTE_CODEX_USED_PERCENT = selected.usedPercent === undefined ? 'unknown' : String(selected.usedPercent);
402
+ if (selected.thresholdPercent !== undefined) remoteEnv.ELANOUS_REMOTE_CODEX_THRESHOLD_PERCENT = String(selected.thresholdPercent);
403
+ }
404
+ if (mirrors) remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNTS = JSON.stringify(mirrors.map(({ account, usedPercent, thresholdPercent, expiresAt }) => ({ account, usedPercent: usedPercent ?? null, thresholdPercent, expiresAt })));
405
+ remoteEnv.ELANOUS_REMOTE_CODEX_ACCESS_ONLY = '1';
406
+ }
407
+ const launched = parentHostModule.launchRemoteParent(target, args, remoteEnv, deps.ssh,
408
+ grokAccessMirror ? () => grokAccessMirror : undefined, effectiveChildProvider, deps.now);
221
409
  try { debug.log('task-agent', 'parent-host-launched', { host: target.host, runId: context.runId, pid: launched.pid, log: launched.log }); } catch { /* fail-soft */ }
222
410
  return { runId: context.runId, parentHost: { host: target.host, ...(target.configDir ? { configDir: target.configDir } : {}), pid: launched.pid, log: launched.log } };
223
411
  } catch (error) {
224
412
  if (error instanceof parentHostModule.RemoteParentNotLaunchedError) { failed(target, [error.message]); continue; }
413
+ if (error instanceof NoEligibleOwnerCodexAccountError) throw error;
225
414
  try { debug.log('task-agent', 'parent-host-launch-uncertain', { host: target.host, runId: context.runId, error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
226
415
  throw error;
227
416
  }
@@ -242,6 +431,7 @@ function firstStderrLine(path: string): string {
242
431
  }
243
432
 
244
433
  export async function defaultTaskLauncher(args: string[], cwd?: string, context?: TaskLaunchContext, deps: DefaultTaskLauncherDeps = {}): Promise<void | TaskLaunchReceipt> {
434
+ if (context) context = (await import('../harness/launch-utterance-ledger.js')).withHandLaunchPairContext(args, context); // LAUNCH-UTTERANCE-LEDGER hand→say pair env
245
435
  if (context) {
246
436
  const remote = await tryRemoteParent(args, cwd, context, deps);
247
437
  if (remote) return remote;
@@ -398,6 +588,7 @@ function taskCardLines(card: TaskCard): string[] {
398
588
  return [
399
589
  [card.id, card.status, card.seat ?? '-', card.checklistId ?? '-', card.createdAt, card.text].join('\t'),
400
590
  ...cardIdentityLines(card),
591
+ ...(card.targetPaths !== undefined ? [`대상 경로: ${card.targetPaths.length ? card.targetPaths.join(' · ') : '(유효한 경로 없음)'}`] : []),
401
592
  ...(card.mission ? [`미션: ${card.mission} · after: ${card.after?.length ? card.after.join(', ') : '-'}`] : []),
402
593
  ...runLinkLine(card),
403
594
  ...liveMoveLines(card),
@@ -794,6 +985,332 @@ export function readTaskAgentCover(
794
985
  limitReached: truncated.taskAgentActions || truncated.allLands || moveRead?.limitReached === true || orderRead?.limitReached === true || goalAsksTruncated || goalRunsTruncated, unreadableStores };
795
986
  }
796
987
 
988
+ const OUTCOMES_QUERY_LIMIT = STORE_SAFETY_MAX;
989
+
990
+ /** «끝났다»로 읽는 카드 상태 — 이 밖(handed·launched)은 PR 종결 관측이 있어야 끝난 것으로 센다. */
991
+ const OUTCOME_TERMINAL_STATUSES: ReadonlySet<TaskCard['status']> = new Set(['failed', 'launch-failed', 'landed', 'landed-by-hand', 'done']);
992
+
993
+ /** 카드 원장에서 «종결»로 읽는 사건 — 이 줄의 시각만 종료 시각으로 쓴다(run-bound · launch 같은 끝나기 전 사건은 종료 시각이 아니다). */
994
+ const OUTCOME_TERMINAL_HISTORY_EVENTS: ReadonlySet<string> = new Set([
995
+ 'failed', 'launch-failed', 'closed-by-hand', 'landed-via-train', 'postland-card', 'postland',
996
+ ]);
997
+ const OUTCOME_SUCCESS_HISTORY_EVENTS: ReadonlySet<string> = new Set(['landed-via-train', 'postland-card', 'postland']);
998
+
999
+ /** `--since`/`--until` 의 상대 기간 — `24h` · `90m` · `3d`. */
1000
+ const OUTCOMES_RELATIVE_WINDOW = /^\d+(?:\.\d+)?(?:m|h|d)$/;
1001
+
1002
+ /** `--since`/`--until` — ISO 시각 또는 상대 기간. 그 밖의 모양은 창을 지어내지 않고 거부한다. */
1003
+ function parseOutcomeTime(value: string | undefined, flag: string, now: number): number | undefined {
1004
+ if (value === undefined) return undefined;
1005
+ const text = value.trim();
1006
+ if (OUTCOMES_RELATIVE_WINDOW.test(text)) {
1007
+ const amount = Number(text.slice(0, -1));
1008
+ const unit = text.slice(-1);
1009
+ const hours = unit === 'd' ? amount * 24 : unit === 'm' ? amount / 60 : amount;
1010
+ return now - hours * 3_600_000;
1011
+ }
1012
+ const time = Date.parse(text);
1013
+ if (!/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d\d:\d\d)$/.test(text) || !Number.isFinite(time)) {
1014
+ throw new Error(`${flag} 는 ISO 시각 또는 상대 기간(24h·3d)이어야 한다`);
1015
+ }
1016
+ return time;
1017
+ }
1018
+
1019
+ /** `tasks outcomes` 한 줄 — 카드 하나의 결과. 모르는 칸은 null(지어내지 않는다). */
1020
+ export interface TaskOutcomeRow {
1021
+ /** 칸(체크리스트 id) — 칸 없이 넘긴 카드는 null. */
1022
+ cell: string | null;
1023
+ card: string;
1024
+ runId: string | null;
1025
+ /** 자식(구현) 런 — 카드가 직접 적은 결속만 사용한다. */
1026
+ childRunId: string | null;
1027
+ /** 부모 호스트 원격 이름 — HQ 로컬 발사면 null. */
1028
+ host: string | null;
1029
+ /** 종료 시각 = 카드 원장의 마지막 종결 사건 시각 ⊕ PR 종결 시각 중 늦은 것(ISO). */
1030
+ endedAt: string;
1031
+ /** 원시 카드 상태. board가 PR 종결로 투영한 상태와 구별한다. */
1032
+ cardStatus: TaskCard['status'];
1033
+ /** PR 결속 — 번호 ⊕ 종결 상태(종결을 못 봤으면 state null). */
1034
+ pr: { number: number; state: 'MERGED' | 'CLOSED' | null } | null;
1035
+ /** 종결 사유는 후속 조각까지 미측정. */
1036
+ reason: null;
1037
+ reasonFrom: null;
1038
+ }
1039
+
1040
+ export interface TaskOutcomeReport {
1041
+ since: string | null;
1042
+ until: string | null;
1043
+ rows: TaskOutcomeRow[];
1044
+ /** 사유별 집계 — 이 부분 조각에서는 reasons=[], missingReason=cards. */
1045
+ aggregate: { cards: number; reasons: Array<{ reason: string; count: number }>; missingReason: number };
1046
+ /** 조회 상한에 닿아 절단됐나 — 그때 집계는 «이 창 안에서 센 행»만 센다. */
1047
+ limitReached: boolean;
1048
+ /** 절단 사유 — 카드 조회 상한. */
1049
+ stopReason: 'page-limit' | null;
1050
+ /** 자식 원장 관측은 후속 조각에서 연결한다. */
1051
+ childLedgerObserved: false;
1052
+ /** 재결속 검증 전까지 카드 사유도 후속 조각에서 연결한다. */
1053
+ reasonObserved: false;
1054
+ /** 끝났는데 종료 시각을 몰라 창에 넣지 못한 카드 수. */
1055
+ undatedCards: number;
1056
+ /** 아직 끝나지 않은 카드 수(창 대상 아님). */
1057
+ openCards: number;
1058
+ warning?: string;
1059
+ }
1060
+
1061
+ /** 마지막 실제 종결 사건. 후보·발사·run-bound·관측 줄은 종료 증거가 아니다. */
1062
+ function outcomeTerminalHistoryLine(card: TaskCard): TaskCardEvent | undefined {
1063
+ return (card.history ?? []).filter((item) => OUTCOME_TERMINAL_HISTORY_EVENTS.has(item.event)).at(-1);
1064
+ }
1065
+
1066
+ /**
1067
+ * TA 카드·PR 종결 사실을 기간으로 센다(읽기 전용). 창은 «종료 시각»에 걸린다.
1068
+ * 사유는 재결속 증거를 확인할 때까지 미측정으로 드러낸다.
1069
+ */
1070
+ export function readTaskOutcomes(
1071
+ window: { sinceMs?: number; untilMs?: number } = {},
1072
+ deps: Pick<TasksCliDeps, 'taskStatePath' | 'outcomesLimit'> = {},
1073
+ snapshot?: Record<string, TaskCard>,
1074
+ ): Omit<TaskOutcomeReport, 'since' | 'until'> {
1075
+ const statePath = deps.taskStatePath ?? taskStatePathDefault();
1076
+ const cards = snapshot ?? readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(statePath).tasks ?? {};
1077
+ const limit = deps.outcomesLimit ?? OUTCOMES_QUERY_LIMIT;
1078
+ const candidates: Array<{ card: TaskCard; terminal: TaskCard['prTerminal']; endedAt: string }> = [];
1079
+ let undatedCards = 0;
1080
+ let openCards = 0;
1081
+ for (const card of Object.values(cards)) {
1082
+ if (!card || typeof card.id !== 'string') continue;
1083
+ const terminal = boundPrTerminal(card);
1084
+ // 결과란 «끝난 카드»다 — 종결 상태이거나 PR 이 종결로 관측된 카드. 아직 도는 카드는 창 대상이 아니다(따로 센다).
1085
+ if (!OUTCOME_TERMINAL_STATUSES.has(card.status) && terminal === undefined) { openCards++; continue; }
1086
+ const terminalHistory = outcomeTerminalHistoryLine(card);
1087
+ const successfulStatus = card.status === 'done' || card.status === 'landed' || card.status === 'landed-by-hand';
1088
+ const manualClosure = (card.status === 'done' || card.status === 'landed-by-hand')
1089
+ && terminalHistory?.event === CLOSED_BY_HAND_EVENT;
1090
+ const failedStatus = card.status === 'failed' || card.status === 'launch-failed';
1091
+ const history = successfulStatus
1092
+ ? (OUTCOME_SUCCESS_HISTORY_EVENTS.has(terminalHistory?.event ?? '') || manualClosure ? terminalHistory : undefined)
1093
+ : failedStatus && (terminalHistory?.event === 'failed' || terminalHistory?.event === 'launch-failed')
1094
+ ? terminalHistory : undefined;
1095
+ // 종료 시각은 «종결 관측»에서만 온다 — 마지막 종결 사건 줄 ⊕ PR 종결 관측 중 늦은 것.
1096
+ // run-bound 같은 끝나기 전 사건을 종료 시각으로 단정하지 않는다(모르면 undatedCards 로 세고 창에 넣지 않는다).
1097
+ const endedAt = [history?.at, terminal?.at]
1098
+ .filter((at): at is string => typeof at === 'string' && Number.isFinite(Date.parse(at)))
1099
+ .sort((a, b) => Date.parse(b) - Date.parse(a))[0];
1100
+ if (endedAt === undefined) { undatedCards++; continue; }
1101
+ const time = Date.parse(endedAt);
1102
+ if ((window.sinceMs !== undefined && time < window.sinceMs) || (window.untilMs !== undefined && time > window.untilMs)) continue;
1103
+ candidates.push({ card, terminal, endedAt });
1104
+ }
1105
+ candidates.sort((a, b) => Date.parse(b.endedAt) - Date.parse(a.endedAt) || a.card.id.localeCompare(b.card.id));
1106
+ const limitReached = candidates.length > limit;
1107
+ const selected = limitReached ? candidates.slice(0, limit) : candidates;
1108
+ const rows = selected.map(({ card, terminal, endedAt }): TaskOutcomeRow => {
1109
+ // 이 조각은 카드·PR 종결 사실만 관측한다. 재결속 검증 전까지 사유는 확정하지 않는다.
1110
+ const number = cardPrNumber(card);
1111
+ return {
1112
+ cell: card.checklistId ?? null,
1113
+ card: card.id,
1114
+ runId: card.runId ?? null,
1115
+ childRunId: card.runChildId ?? null,
1116
+ host: card.parentHost?.host ?? null,
1117
+ endedAt,
1118
+ cardStatus: card.status,
1119
+ pr: number === undefined ? null : { number, state: terminal?.state ?? null },
1120
+ reason: null,
1121
+ reasonFrom: null,
1122
+ };
1123
+ });
1124
+ const missingReason = rows.length;
1125
+ const warnings = [
1126
+ limitReached ? `카드 조회 상한 ${limit} 도달 — 창 안 ${candidates.length}장 중 ${rows.length}장만 셌다(집계도 이 행들만 센다)` : null,
1127
+ missingReason > 0 ? `종결 사유 미측정 — ${missingReason}장은 재결속 검증 전까지 사유를 모른다` : null,
1128
+ ].filter((line): line is string => line !== null);
1129
+ return {
1130
+ rows,
1131
+ aggregate: { cards: rows.length, reasons: [], missingReason },
1132
+ limitReached,
1133
+ stopReason: limitReached ? 'page-limit' : null,
1134
+ childLedgerObserved: false,
1135
+ reasonObserved: false,
1136
+ undatedCards,
1137
+ openCards,
1138
+ ...(warnings.length ? { warning: warnings.join(' · ') } : {}),
1139
+ };
1140
+ }
1141
+
1142
+ /** MODEL-SIZE-OUTCOME-MEASURE — `tasks outcomes --by` 가 아는 집계 축. */
1143
+ export const TASK_OUTCOME_BY_DIMENSIONS = ['model', 'size'] as const;
1144
+
1145
+ /** 못 읽은 값의 이름 — 0 이나 빈 문자열로 지어내지 않는다. */
1146
+ export const TASK_OUTCOME_UNKNOWN = 'unknown';
1147
+
1148
+ /** 카드 하나의 결과 — PR 착지 · 범위 이탈 · 수렴 실패 · 결과 줄 없음. */
1149
+ export type TaskOutcomeModelSizeResult = 'landed' | 'scope-escape' | 'convergence-failure' | 'no-result-line';
1150
+
1151
+ /** 카드 하나의 측정 줄 — 자식 모델 · 등급 · 조각 크기(대상 경로 수 · 바꿀 동작 수) · 결과. */
1152
+ export interface TaskOutcomeModelSizeCard {
1153
+ card: string;
1154
+ /** `provider/model`(카드 childLlm) · 못 읽으면 `unknown`. */
1155
+ model: string;
1156
+ /** 디스패처 난이도(하|중|상|특) · 못 읽으면 `unknown`. */
1157
+ tier: string;
1158
+ size: { targetPaths: number | typeof TASK_OUTCOME_UNKNOWN; behaviors: number | typeof TASK_OUTCOME_UNKNOWN };
1159
+ result: TaskOutcomeModelSizeResult;
1160
+ }
1161
+
1162
+ /** 모델×크기 칸 하나 — 성공률 · 표본 수 · unknown 수. */
1163
+ export interface TaskOutcomeModelSizeCell {
1164
+ model: string;
1165
+ /** 크기 칸 이름(`paths=<n>·behaviors=<n>`) · 못 읽은 칸은 `unknown`. */
1166
+ size: string;
1167
+ samples: number;
1168
+ landed: number;
1169
+ /** landed / samples. */
1170
+ successRate: number | null;
1171
+ /** 이 칸에서 한 축이라도 못 읽은 카드 수. */
1172
+ unknown: number;
1173
+ results: Record<TaskOutcomeModelSizeResult, number>;
1174
+ }
1175
+
1176
+ export interface TaskOutcomeModelSizeReport {
1177
+ dimensions: readonly ['model', 'size'];
1178
+ cells: TaskOutcomeModelSizeCell[];
1179
+ cards: TaskOutcomeModelSizeCard[];
1180
+ /** 축별 «못 읽음» 수 — 카드 합계가 아니라 축마다 센다(한 카드가 둘을 못 읽을 수 있다). */
1181
+ unknown: { model: number; tier: number; size: number };
1182
+ samples: number;
1183
+ limitReached: boolean;
1184
+ }
1185
+
1186
+ const OUTCOME_MODEL_SIZE_RESULTS: readonly TaskOutcomeModelSizeResult[] = ['landed', 'scope-escape', 'convergence-failure', 'no-result-line'];
1187
+
1188
+ /** `--by` 인자 — 지금은 `model,size` 하나뿐이다(순서 무관 · 그 밖은 거부). */
1189
+ function parseOutcomeDimensions(value: string | undefined): readonly ['model', 'size'] | undefined {
1190
+ if (value === undefined) return undefined;
1191
+ const parts = [...new Set(value.split(',').map((part) => part.trim().toLowerCase()).filter(Boolean))];
1192
+ if (parts.length !== TASK_OUTCOME_BY_DIMENSIONS.length || !TASK_OUTCOME_BY_DIMENSIONS.every((dimension) => parts.includes(dimension))) {
1193
+ throw new Error(`--by 는 ${TASK_OUTCOME_BY_DIMENSIONS.join(',')} 다(모델×조각 크기): ${value}`);
1194
+ }
1195
+ return ['model', 'size'];
1196
+ }
1197
+
1198
+ /** 카드 문면의 «바꿀 동작 수» — `바꿀` 선언 줄 ⊕ 그 아래 항목. 선언이 없으면 null(0 으로 지어내지 않는다). */
1199
+ function declaredChangeCount(text: string): number | null {
1200
+ let declared = 0;
1201
+ let explicitlyNone = false;
1202
+ let insideChangeList = false;
1203
+ for (const line of text.split(/\r?\n/)) {
1204
+ const trimmed = line.trim();
1205
+ if (/^바꿀(?:\s|:|것|동작)/.test(trimmed)) {
1206
+ const at = trimmed.indexOf(':');
1207
+ const inline = at < 0 ? '' : trimmed.slice(at + 1).trim();
1208
+ if (/^바꿀\s*(?:것|동작)?\s*:?[\s]*(?:없음|없다)$/u.test(trimmed)) {
1209
+ explicitlyNone = true;
1210
+ insideChangeList = false;
1211
+ continue;
1212
+ }
1213
+ // «바꿀 것: 하나» 처럼 한 줄에 적었으면 그 줄이 한 동작이고, 목록이 뒤따르지 않는다.
1214
+ // «바꿀 것: 다음» 처럼 목록을 가리키는 선언은 그 줄이 동작이 아니고, 뒤따르는 목록을 센다.
1215
+ insideChangeList = inline.length === 0 || /^다음[.!?]?$/.test(inline);
1216
+ if (!insideChangeList) declared++;
1217
+ continue;
1218
+ }
1219
+ if (!insideChangeList) continue;
1220
+ if (/^[-*·]\s+\S/.test(trimmed)) { declared++; continue; }
1221
+ if (trimmed.length > 0) insideChangeList = false;
1222
+ }
1223
+ return declared > 0 ? declared : explicitlyNone ? 0 : null;
1224
+ }
1225
+
1226
+ /** 조각 크기 — 대상 경로 수(카드가 적은 목록) ⊕ 바꿀 동작 수(문면의 바꿀 선언). */
1227
+ function outcomeCardSize(card: TaskCard | undefined): TaskOutcomeModelSizeCard['size'] {
1228
+ const targetPaths = Array.isArray(card?.targetPaths) ? card.targetPaths.length : TASK_OUTCOME_UNKNOWN;
1229
+ const behaviors = card && typeof card.text === 'string' ? declaredChangeCount(card.text) ?? TASK_OUTCOME_UNKNOWN : TASK_OUTCOME_UNKNOWN;
1230
+ return { targetPaths, behaviors };
1231
+ }
1232
+
1233
+ function outcomeCardModel(card: TaskCard | undefined): string {
1234
+ const llm = card?.childLlm;
1235
+ if (!llm || typeof llm.provider !== 'string' || !llm.provider || typeof llm.model !== 'string' || !llm.model) return TASK_OUTCOME_UNKNOWN;
1236
+ return `${llm.provider}/${llm.model}`;
1237
+ }
1238
+
1239
+ function outcomeCardTier(card: TaskCard | undefined): string {
1240
+ const tier = card?.tier;
1241
+ return tier === '하' || tier === '중' || tier === '상' || tier === '특' ? tier : TASK_OUTCOME_UNKNOWN;
1242
+ }
1243
+
1244
+ /**
1245
+ * 결과 판정 — 카드 원장에 있는 사실만 쓴다(문면 추측 없음).
1246
+ * ① 실제 실행·성공한 손 범위 자르기 hand-move(trim-scope)가 있으면 «범위 이탈» — 실행·성공 값이
1247
+ * 없거나 false인 조정 · post-land partial(남은 작업)만으로는 범위 이탈이 아니다.
1248
+ * ② PR MERGED 종결 증거(row.pr ⊕ 원장 prTerminal) 또는 손 착지 종결 기록(closed-by-hand)이 있으면 «PR 착지» —
1249
+ * 카드 상태(landed·done)만으로는 착지로 단정하지 않는다.
1250
+ * ③ 실패 종결 줄이 있으면 «수렴 실패» ④ 그 밖은 «결과 줄 없음».
1251
+ */
1252
+ function classifyOutcomeResult(card: TaskCard | undefined, row: TaskOutcomeRow): TaskOutcomeModelSizeResult {
1253
+ if ((card?.history ?? []).some((item) => item.event === HAND_MOVE_HISTORY_EVENT && item.kind === 'trim-scope'
1254
+ && item.executed === true && item.ok === true)) return 'scope-escape';
1255
+ const terminal = card ? boundPrTerminal(card) : undefined;
1256
+ const landedByHand = row.cardStatus === 'landed-by-hand'
1257
+ && (card?.history ?? []).some((item) => item.event === CLOSED_BY_HAND_EVENT);
1258
+ if (row.pr?.state === 'MERGED' || terminal?.state === 'MERGED' || landedByHand) return 'landed';
1259
+ const terminalLine = card ? outcomeTerminalHistoryLine(card) : undefined;
1260
+ if (terminalLine?.event === 'failed' || terminalLine?.event === 'launch-failed') return 'convergence-failure';
1261
+ if (row.cardStatus === 'failed' || row.cardStatus === 'launch-failed') return 'convergence-failure';
1262
+ return 'no-result-line';
1263
+ }
1264
+
1265
+ /**
1266
+ * MODEL-SIZE-OUTCOME-MEASURE — `tasks outcomes --by model,size`(읽기 전용).
1267
+ * 창 안에서 «끝난» 카드(readTaskOutcomes 와 같은 판정)를 모델×조각 크기 칸으로 묶어 성공률·표본 수·unknown 수를 낸다.
1268
+ * `report` 와 `snapshot` 을 함께 주면 같은 원장 시점으로 창·크기·결과를 센다.
1269
+ */
1270
+ export function readTaskOutcomeModelSize(
1271
+ window: { sinceMs?: number; untilMs?: number } = {},
1272
+ deps: Pick<TasksCliDeps, 'taskStatePath' | 'outcomesLimit'> = {},
1273
+ report?: Omit<TaskOutcomeReport, 'since' | 'until'>,
1274
+ snapshot?: Record<string, TaskCard>,
1275
+ ): TaskOutcomeModelSizeReport {
1276
+ const cards = snapshot ?? readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(deps.taskStatePath ?? taskStatePathDefault()).tasks ?? {};
1277
+ const observed = report ?? readTaskOutcomes(window, deps, cards);
1278
+ const unknown = { model: 0, tier: 0, size: 0 };
1279
+ const cells = new Map<string, TaskOutcomeModelSizeCell>();
1280
+ const rows = observed.rows.map((row): TaskOutcomeModelSizeCard => {
1281
+ const card = cards[row.card];
1282
+ const model = outcomeCardModel(card);
1283
+ const tier = outcomeCardTier(card);
1284
+ const size = outcomeCardSize(card);
1285
+ const result = classifyOutcomeResult(card, row);
1286
+ if (model === TASK_OUTCOME_UNKNOWN) unknown.model++;
1287
+ if (tier === TASK_OUTCOME_UNKNOWN) unknown.tier++;
1288
+ const sizeKey = size.targetPaths === TASK_OUTCOME_UNKNOWN || size.behaviors === TASK_OUTCOME_UNKNOWN
1289
+ ? TASK_OUTCOME_UNKNOWN : `paths=${size.targetPaths}·behaviors=${size.behaviors}`;
1290
+ if (sizeKey === TASK_OUTCOME_UNKNOWN) unknown.size++;
1291
+ // Cell unknown belongs to its two grouping axes; tier is reported separately per card and in unknown.tier.
1292
+ const unresolved = model === TASK_OUTCOME_UNKNOWN || sizeKey === TASK_OUTCOME_UNKNOWN;
1293
+ const key = `${model}\u0000${sizeKey}`;
1294
+ const cell = cells.get(key) ?? { model, size: sizeKey, samples: 0, landed: 0, successRate: null, unknown: 0,
1295
+ results: Object.fromEntries(OUTCOME_MODEL_SIZE_RESULTS.map((name) => [name, 0])) as Record<TaskOutcomeModelSizeResult, number> };
1296
+ cell.samples++;
1297
+ if (result === 'landed') cell.landed++;
1298
+ if (unresolved) cell.unknown++;
1299
+ cell.results[result]++;
1300
+ cell.successRate = cell.landed / cell.samples;
1301
+ cells.set(key, cell);
1302
+ return { card: row.card, model, tier, size, result };
1303
+ });
1304
+ return {
1305
+ dimensions: ['model', 'size'],
1306
+ cells: [...cells.values()].sort((a, b) => a.model.localeCompare(b.model) || a.size.localeCompare(b.size)),
1307
+ cards: rows,
1308
+ unknown,
1309
+ samples: rows.length,
1310
+ limitReached: observed.limitReached,
1311
+ };
1312
+ }
1313
+
797
1314
  export function registerTasksCommands(program: Command, deps: TasksCliDeps = {}): void {
798
1315
  let activeToken: string | undefined;
799
1316
  const output = deps.output ?? console.log;
@@ -806,6 +1323,38 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
806
1323
  };
807
1324
  const tasks = program.command('tasks').alias('task').description('TOX 태스크 조회 및 승인 · TASK-AGENT 과제 넘기기(hand)');
808
1325
 
1326
+ tasks.command('work-order').description('TASK-AGENT 작업 지시서')
1327
+ .command('build')
1328
+ .description('체크리스트 칸으로 작업 지시서를 만들어 파일에 쓴다')
1329
+ .requiredOption('--checklist <cellId>', '체크리스트 칸 id')
1330
+ .requiredOption('--version <version>', '체크리스트 판')
1331
+ .requiredOption('--out <path>', '작업 지시서 출력 파일')
1332
+ .action((opts: { checklist: string; version: string; out: string }) => {
1333
+ try {
1334
+ validateVersion(opts.version);
1335
+ const item = (deps.workOrderChecklist ?? listChecklist)(opts.version).items.find((cell) => cell.id === opts.checklist);
1336
+ if (!item) throw new Error(`체크리스트 칸 없음: ${opts.checklist}`);
1337
+ const targets = /^대상 경로:[ \t]*(.*)$/.exec(item.title.split(/\r?\n/, 1)[0]!)?.[1]?.split(' · ').map((path) => path.trim()).filter(Boolean) ?? [];
1338
+ const missing = targets.filter((path) => !existsSync(resolve(process.cwd(), path)));
1339
+ const boundary = [
1340
+ ...(targets.length ? [`대상 경로: ${targets.join(' · ')}`] : []),
1341
+ ...(missing.length ? [`boundary.missing: ${missing.join(' · ')}`] : []),
1342
+ ].join('\n');
1343
+ const order = buildWorkOrder({
1344
+ cellId: item.id,
1345
+ version: opts.version,
1346
+ priority: item.priority,
1347
+ boundary: boundary || undefined,
1348
+ });
1349
+ mkdirSync(dirname(opts.out), { recursive: true });
1350
+ writeFileSync(opts.out, `${JSON.stringify(order, null, 2)}\n`);
1351
+ out(opts.out);
1352
+ } catch (error) {
1353
+ out(error instanceof Error ? error.message : '작업 지시서 작성 실패');
1354
+ process.exitCode = 1;
1355
+ }
1356
+ });
1357
+
809
1358
  tasks.command('green-sweep')
810
1359
  .description('병합된 과제 PR 과 칸 근거를 대조해 green/기록만/건너뜀을 미리 본다 (항상 dry-run)')
811
1360
  .requiredOption('--version <version>', '조회할 체크리스트 판')
@@ -820,6 +1369,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
820
1369
  { cwd: process.cwd(), encoding: 'utf8', timeout: 20_000 }));
821
1370
  const cards = Object.values(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(deps.taskStatePath ?? taskStatePathDefault()).tasks ?? {});
822
1371
  let holds: Set<string> | null = null;
1372
+ let holdDiagnostic: string | undefined;
823
1373
  if (opts.traffic) {
824
1374
  try {
825
1375
  const traffic: unknown = JSON.parse(readFileSync(opts.traffic, 'utf8'));
@@ -827,8 +1377,13 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
827
1377
  && Array.isArray((traffic as { hold?: unknown }).hold)
828
1378
  && (traffic as { hold: unknown[] }).hold.every((id) => typeof id === 'string'))
829
1379
  holds = new Set((traffic as { hold: string[] }).hold);
830
- } catch { /* unknown is not an empty hold set */ }
831
- }
1380
+ else holdDiagnostic = `invalid-traffic-shape: ${opts.traffic} must contain hold: string[]`;
1381
+ } catch (error) {
1382
+ const code = error && typeof error === 'object' && 'code' in error && typeof error.code === 'string'
1383
+ ? error.code : error instanceof SyntaxError ? 'invalid-json' : 'read-error';
1384
+ holdDiagnostic = `${code}: ${opts.traffic}`;
1385
+ }
1386
+ } else holdDiagnostic = 'traffic-path-not-provided: pass --traffic ~/elanous-hq/seat-state/OP/traffic.json';
832
1387
  const prCache = new Map<number, GreenSweepPr | null>();
833
1388
  const ambiguousPrs = ambiguousGreenSweepPrs(snapshot.items, opts.version, cards);
834
1389
  const origin = run('git', ['remote', 'get-url', 'origin']);
@@ -878,7 +1433,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
878
1433
  return check.status === 0 ? true : check.status === 1 ? false : null;
879
1434
  })();
880
1435
  const decision = decideGreenSweep({ item, candidate, candidateCount: candidates.length,
881
- pr: landingPr ?? null, ancestor, hold: holds === null ? null : holds.has(item.id), repositoryMatches,
1436
+ pr: landingPr ?? null, ancestor, hold: holds === null ? null : holds.has(item.id), holdDiagnostic, repositoryMatches,
882
1437
  ambiguousAcrossCells: ambiguousPrs.has(candidate.pr) });
883
1438
  observeGreenSweep(decision);
884
1439
  return decision;
@@ -890,8 +1445,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
890
1445
  if (opts.json) out(JSON.stringify({ dryRun: true, version: opts.version, counts, decisions }));
891
1446
  else {
892
1447
  out(`dry-run · ${opts.version} · 후보 ${counts.candidate} · green ${counts.green} · 기록만 ${counts.recordOnly} · 건너뜀 ${counts.skipped}`);
893
- for (const d of decisions) out(`${d.verdict}\t${d.cell}\t#${d.pr}\t${d.mergeSha ?? '-'}\t${d.reason}\t${d.evidence}\tbefore=${JSON.stringify(d.existingEvidence)}\tafter=${JSON.stringify(d.plannedEvidence)}`);
894
- if (holds === null) out('⚠ hold 원장을 읽지 못해 green 없이 기록만 판정');
1448
+ for (const d of decisions) out(`${d.verdict}\t${d.cell}\t#${d.pr}\t${d.mergeSha ?? '-'}\t${d.reason}\t${d.evidence}\tbefore=${JSON.stringify(d.existingEvidence)}\tafter=${JSON.stringify(d.plannedEvidence)}\tholdDiagnostic=${d.holdDiagnostic ?? ''}`);
895
1449
  }
896
1450
  } catch (error) { out(`green-sweep 조회 실패: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
897
1451
  });
@@ -948,6 +1502,41 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
948
1502
  } catch (error) { out(error instanceof Error ? error.message : '커버 조회 실패'); process.exitCode = 1; }
949
1503
  });
950
1504
 
1505
+ tasks.command('outcomes')
1506
+ .description('TA 카드·PR 종결 결과를 기간으로 센다 — JSON 한 건, 자식 원장 미측정(읽기 전용 · 카드 페이지 상한)')
1507
+ .option('--since <기간>', '시작 시각 — ISO 또는 상대 기간(24h · 3d)')
1508
+ .option('--until <기간>', '끝 시각 — ISO 또는 지금에서 뺀 상대 기간(24h · 3d)')
1509
+ .option('--by <축>', '집계 축 — model,size = 카드마다 자식 모델 · 등급 · 조각 크기(대상 경로 수·바꿀 동작 수) · 결과(PR 착지 · 범위 이탈 · 수렴 실패 · 결과 줄 없음)를 묶어 모델×크기 칸별 성공률 · 표본 수 · unknown 수를 낸다(읽기 전용)')
1510
+ .option('--json', 'JSON 출력(기본값)')
1511
+ .action((opts: { since?: string; until?: string; by?: string; json?: boolean }) => {
1512
+ try {
1513
+ const now = deps.outcomesNow?.() ?? Date.now();
1514
+ const sinceMs = parseOutcomeTime(opts.since, '--since', now);
1515
+ const untilMs = parseOutcomeTime(opts.until, '--until', now) ?? now;
1516
+ // 창이 뒤집혔으면 아무것도 읽지 않는다(«빈 결과»로 속이지 않는다).
1517
+ if (sinceMs !== undefined && untilMs !== undefined && sinceMs > untilMs) throw new Error('--since 가 --until 보다 늦다');
1518
+ // 축 이름이 틀렸으면 원장도 읽지 않는다(지어낸 집계를 내지 않게).
1519
+ const dimensions = parseOutcomeDimensions(opts.by);
1520
+ const snapshot = dimensions
1521
+ ? readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(deps.taskStatePath ?? taskStatePathDefault()).tasks ?? {}
1522
+ : undefined;
1523
+ const observed = readTaskOutcomes({ sinceMs, untilMs }, deps, snapshot);
1524
+ const report: TaskOutcomeReport = {
1525
+ since: sinceMs === undefined ? null : new Date(sinceMs).toISOString(),
1526
+ until: untilMs === undefined ? null : new Date(untilMs).toISOString(),
1527
+ ...observed,
1528
+ };
1529
+ try { debug.log('task-agent', 'card-outcomes', { since: report.since, until: report.until, rows: report.rows.length,
1530
+ missingReason: report.aggregate.missingReason, stopReason: report.stopReason,
1531
+ childLedgerObserved: false, reasonObserved: false }); } catch { /* fail-soft */ }
1532
+ // `--by model,size` 는 지금 JSON 에 «한 칸»을 더할 뿐 — 없으면 종전 JSON 그대로다.
1533
+ out(JSON.stringify(dimensions ? { ...report, byModelSize: readTaskOutcomeModelSize({ sinceMs, untilMs }, deps, observed, snapshot) } : report));
1534
+ } catch (error) {
1535
+ out(JSON.stringify({ error: error instanceof Error ? error.message : '결과 조회 실패' }));
1536
+ process.exitCode = 1;
1537
+ }
1538
+ });
1539
+
951
1540
  tasks.command('list')
952
1541
  .description('우선순위와 생성 시각 순으로 태스크 보기')
953
1542
  .option('--status <s>', '상태로 필터')
@@ -1124,7 +1713,8 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1124
1713
  if (resolved.kind === 'inlined') {
1125
1714
  try { debug.log('task-agent.hand', 'goal-file-inlined', { path: resolved.path, chars: resolved.chars, sha256: resolved.sha256 }); } catch { /* fail-soft */ }
1126
1715
  }
1127
- const result = await handTask({
1716
+ const handed = await handTaskWithTierSplit({
1717
+ ...('tierSizedDecompose' in deps ? { decompose: deps.tierSizedDecompose } : {}),
1128
1718
  text: resolved.text,
1129
1719
  ...(opts.project !== undefined && opts.target !== undefined ? { project: { id: opts.project, target: opts.target } } : {}),
1130
1720
  ...(opts.goal !== undefined ? { goal: opts.goal } : {}),
@@ -1133,6 +1723,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1133
1723
  ...(opts.checklist ? { checklistId: opts.checklist } : {}),
1134
1724
  ...(opts.completion ? { completion: opts.completion } : {}),
1135
1725
  live: opts.live === true,
1726
+ preflightGoalDoneBoundary: opts.live === true && deps.taskLauncher === undefined,
1136
1727
  ...(opts.taLand === true ? { taLand: true } : {}),
1137
1728
  ...(opts.childLlm !== undefined ? { childLlm: opts.childLlm } : {}),
1138
1729
  ...(opts.childLlmEffort !== undefined ? { childLlmEffort: opts.childLlmEffort } : {}),
@@ -1143,8 +1734,29 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1143
1734
  ...(deps.taskCompositionRoot ? { compositionRoot: deps.taskCompositionRoot } : {}),
1144
1735
  launcher: deps.taskLauncher ?? defaultTaskLauncher,
1145
1736
  });
1737
+ if (handed.kind === 'split') {
1738
+ // TIER-SPLIT-BEFORE-LAUNCH — 상·특 hand 를 조각으로 나눠 쐈다: 첫 줄 = 묶음 · 조각마다 한 줄(미션 출력과 같은 꼴).
1739
+ if (opts.json) out(JSON.stringify(handed));
1740
+ else {
1741
+ // 디스패처 계약(ta-dispatcher.sh · `grep -E '^ta-' | head -1`): 줄 머리 `ta-` 는 «카드 id» 만 — 조각 카드 줄이 먼저, 묶음 줄은 끝에 `tier-split` 머리로.
1742
+ for (const piece of handed.slices) {
1743
+ out([piece.result?.card.id ?? '-', piece.result?.launched ? 'launched' : piece.error ? 'failed' : 'not launched', `tier ${piece.slice.tier} · 파일 ${piece.slice.files} · 행동 ${piece.slice.behaviours}`, headLine(piece.slice.goal)].join('\t'));
1744
+ if (piece.slice.unavoidable) out(` 불가피: ${piece.slice.unavoidable}`);
1745
+ if (piece.error) out(` ${piece.error}`);
1746
+ }
1747
+ out(`tier-split\t${handed.group}\t${handed.fromTier} → 조각 ${handed.slices.length}`);
1748
+ }
1749
+ if (handed.slices.some((piece) => piece.error)) process.exitCode = 1;
1750
+ return;
1751
+ }
1752
+ const result = handed.result;
1753
+ if (handed.kind === 'blocked') process.exitCode = 1;
1146
1754
  if (opts.json) out(JSON.stringify(result));
1147
- else {
1755
+ else if (handed.kind === 'blocked') {
1756
+ // 발사 0 — 디스패처가 «넘김 실패» 로 읽도록 어느 줄도 `ta-` 로 시작하지 않는다.
1757
+ out(`tier-split-failed\t${result.card.id}\tnot launched`);
1758
+ out(`(tier-split-failed — 발사 0 · 카드 failed · ${handed.reason})`);
1759
+ } else {
1148
1760
  out(`${result.card.id}\t${result.mode}\t${result.launched ? 'launched' : 'not launched'}`);
1149
1761
  if (result.move.command) out(`elanous ${result.move.command.map(shellQuote).join(' ')}`);
1150
1762
  else out(result.move.reason);
@@ -1578,7 +2190,45 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1578
2190
  : {});
1579
2191
  try { debug.log('task-agent', 'remote-rejudge-bind', binding); } catch { /* fail-soft */ }
1580
2192
  }
1581
- ids = id ? [id] : rejudgeCandidates(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(statePath).tasks ?? {});
2193
+ if (id) ids = [id];
2194
+ else {
2195
+ const maxAgeHours = (await import('../user-config.js')).getUserConfig().taskAgent?.rejudgeMaxAgeHours ?? 72;
2196
+ const cards = readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(statePath).tasks ?? {};
2197
+ const candidates = rejudgeCandidates(cards, { maxAgeHours, onAgeSkip: (card, ageHours) => {
2198
+ try { debug.log('task-agent', 'rejudge-age-skip', { card: card.id, ageHours, maxAgeHours }); } catch { /* fail-soft */ }
2199
+ } });
2200
+ const { capturedLandReview } = await import('../task-agent/review-result-capture.js');
2201
+ const { defaultPrHead, defaultReviewRepoCandidates } = await import('../task-agent/live-moves.js');
2202
+ const currentHeads = new Map<string, string>();
2203
+ // Priority is a hint, not a gate. Consider only the three newest candidates;
2204
+ // a non-mf0 card still consumes one of those three places. Everyone else runs in age order.
2205
+ const priorityCandidates = candidates.slice(0, 3);
2206
+ let headProbes = 0;
2207
+ for (const cardId of priorityCandidates) {
2208
+ const card = cards[cardId];
2209
+ if (!card || typeof card.pr !== 'object' || !card.pr?.url) continue;
2210
+ const pr = card.pr.number;
2211
+ const lastHead = card.reviewRequests?.filter((entry) => entry.pr === pr).at(-1)?.head;
2212
+ if (!lastHead || capturedLandReview(card, pr, lastHead)?.mustFixCount !== 0) continue;
2213
+ let repos: readonly import('../task-agent/live-moves.js').ReviewRepoCandidate[] = [];
2214
+ try { repos = (deps.rejudge?.live?.repoCandidates ?? defaultReviewRepoCandidates)(card); } catch { /* no trusted repo */ }
2215
+ const repo = repos[0];
2216
+ if (!repo) continue;
2217
+ headProbes++;
2218
+ let view: Awaited<ReturnType<typeof defaultPrHead>>;
2219
+ try { view = await (deps.rejudge?.live?.prHead
2220
+ ? deps.rejudge.live.prHead(pr, repo.cwd)
2221
+ : defaultPrHead(pr, repo.cwd, (args, options) => spawnSync('gh', args, {
2222
+ encoding: 'utf8', timeout: 3_000, env: options.env, ...(options.cwd ? { cwd: options.cwd } : {}),
2223
+ }))); } catch { view = null; }
2224
+ if (view?.state === 'OPEN' && view.url === card.pr.url) currentHeads.set(cardId, view.head);
2225
+ }
2226
+ if (candidates.length > priorityCandidates.length) {
2227
+ try { debug.log('task-agent', 'rejudge-head-priority-probe-cap', { considered: priorityCandidates.length,
2228
+ probed: headProbes, totalCandidates: candidates.length, max: 3 }); } catch { /* fail-soft */ }
2229
+ }
2230
+ ids = rejudgeCandidates(cards, { maxAgeHours, currentHeads });
2231
+ }
1582
2232
  } catch (error) {
1583
2233
  out(error instanceof Error ? error.message : '과제 카드 읽기 실패'); process.exitCode = 1; return;
1584
2234
  }
@@ -1586,6 +2236,8 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1586
2236
  const liveMoves = deps.rejudge?.liveMoves ?? await configuredTaskAgentLiveMoves();
1587
2237
  const repairBudget = opts.all ? { max: (await import('../user-config.js')).getUserConfig().taskAgent?.repairMaxPerTick ?? 3,
1588
2238
  requested: 0, capped: 0 } : undefined;
2239
+ const reviewBudget = opts.all ? { max: 1, requested: 0 } : undefined;
2240
+ const landBudget = opts.all ? { max: 1, requested: 0 } : undefined;
1589
2241
  const all = [];
1590
2242
  for (const cardId of ids) {
1591
2243
  await mirrorRemoteCardLedger(cardId, deps);
@@ -1594,7 +2246,8 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1594
2246
  }
1595
2247
  let outcomes: Awaited<ReturnType<typeof rejudgeCardOnHead>>;
1596
2248
  try { outcomes = await rejudgeCardOnHead(cardId, { ...deps.rejudge, liveMoves,
1597
- ...(repairBudget ? { repairBudget } : {}), live: { ...deps.rejudge?.live, statePath } }); } catch (error) {
2249
+ ...(repairBudget ? { repairBudget } : {}), ...(reviewBudget ? { reviewBudget } : {}), ...(landBudget ? { landBudget } : {}),
2250
+ live: { ...deps.rejudge?.live, statePath } }); } catch (error) {
1598
2251
  // 카드 하나의 예외가 --all 의 나머지 카드 판단을 멈추지 않게 — 사유를 남기고 다음 카드로.
1599
2252
  const reason = (error instanceof Error ? error.message : String(error)).slice(-300);
1600
2253
  try { debug.log('task-agent', 'rejudge-on-head', { card: cardId, pr: null, fromHead: null, toHead: null, step: 'target', decision: 'rejudge-threw', reason }, { level: 'warn' }); } catch { /* fail-soft */ }