elanous 0.2.34 → 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 (611) 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/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.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/{2124.ed5bf480cea7f85b.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/1674.2a65fd5668e1cc5f.js +1 -0
  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/1993-c0007b7ad0c0ef41.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.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/2625.5d870aa999f33db1.js +34 -0
  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/{1644.35dd25240ae24e4b.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/{3121.779fafe3e44612c5.js → 3589.5444a06bcf6e775c.js} +1 -1
  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/{9131-fce7256c4180c4a5.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/4346.8601952e73bf5803.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/{6053-d893974de92e6198.js → 4441-875b97f5821ed58a.js} +1 -1
  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/{1895-60ed0e341c658bd4.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.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/{7431.3051e9b8a4372d2d.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +1 -0
  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/{2987-30cf9c2eb7b8bdd5.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/56d372f2.681ab4ec4c998fae.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{7386.5d8e7e42e818dfb6.js → 5852.db1f7449f4f74612.js} +2 -2
  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/{3110.0a7065f25c841818.js → 6236.e18cced2d5ba6afb.js} +3 -3
  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/6b89c8bd.24df687a820500b3.js +1 -0
  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/{7005.1623d2aea78eb85f.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.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/8219.baa715d1deee80e2.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +1 -0
  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/{7193-cf355cca5ba6c5d5.js → 8437-8d5492094b166cfa.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 8444.4c26b379ca2b9596.js} +4 -4
  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/{2547.dd27303624cb4da8.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/{9550.d5f76828f972058c.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/{8548.036c344973968847.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.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/967-2aa39b2d04b4c690.js +1 -0
  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/{6740.43de73fc427c9fe2.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-406b47745b53f269.js +1 -0
  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-d7bff0f0905a662c.js → page-26e6c18a1a750cf6.js} +1 -1
  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-47c5d4db587266bd.js +1 -0
  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-df3445b207ceceab.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/{9a8cb466.cc9fc9e6e46038aa.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/{4fa33ebd.21c1bd5b294496e6.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{abb4b98b.163e0f56e84ae35d.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → da5176c6.6773b6c5994e1d99.js} +1 -1
  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 +3 -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 +4 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +57 -3
  285. package/graphs/document-loop.yaml +51 -3
  286. package/graphs/implement-loop.yaml +53 -4
  287. package/graphs/journey/ta-journey.yaml +11 -1
  288. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  289. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  290. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  291. package/graphs/operate-loop.yaml +51 -3
  292. package/graphs/research-loop.yaml +137 -3
  293. package/graphs/test-diet/test-diet.yaml +3 -0
  294. package/package.json +1 -1
  295. package/scripts/coord-role-pack.ts +19 -6
  296. package/scripts/hq/standby-snapshot.ts +17 -12
  297. package/scripts/release-loop/docs-land-node.ts +21 -5
  298. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  299. package/scripts/release-loop/gate-node.ts +181 -22
  300. package/scripts/release-loop/gate-partial.ts +65 -11
  301. package/scripts/release-loop/gate-radius-live.ts +177 -0
  302. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  303. package/scripts/release-loop/node-verdict.ts +12 -1
  304. package/scripts/release-loop/npm-publish-node.ts +66 -12
  305. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  306. package/scripts/release-loop/pwa-remote.ts +166 -0
  307. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  308. package/scripts/release-loop/resume-release.ts +41 -4
  309. package/scripts/release-loop/unattended-release.ts +2 -0
  310. package/scripts/test-diet/lib.ts +6 -1
  311. package/scripts/test-diet/node.ts +194 -13
  312. package/scripts/ux-sim.ts +39 -0
  313. package/src/agent/self-ambient-cache.ts +8 -0
  314. package/src/agent-substrate/acp-reviewer.ts +39 -4
  315. package/src/agent-substrate/pr-reviewer.ts +17 -0
  316. package/src/agent-substrate/self-review-cli.ts +62 -13
  317. package/src/autopilot/pr-manager.ts +215 -36
  318. package/src/budget/run-usage-rollup.ts +1 -0
  319. package/src/chat/index.ts +0 -2
  320. package/src/chat/pickers/modal-runtime.ts +10 -27
  321. package/src/cli/agent-cli.ts +13 -2
  322. package/src/cli/doctor-cli.ts +4 -1
  323. package/src/cli/light-entry-route.ts +46 -6
  324. package/src/cli/pod-cli.ts +77 -3
  325. package/src/cli/pr-cli.ts +5 -2
  326. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  327. package/src/cli/release-checklist-read-cli.ts +79 -0
  328. package/src/cli/release-cli.ts +72 -102
  329. package/src/cli/remote-resolve.ts +1 -1
  330. package/src/cli/root-tui-entry.ts +48 -0
  331. package/src/cli/sim-cli.ts +22 -0
  332. package/src/cli/tasks-cli.ts +540 -31
  333. package/src/cli/usage-cli.ts +13 -11
  334. package/src/clipboard/history.ts +179 -13
  335. package/src/config.ts +8 -1
  336. package/src/dashboard/chat/acp-chat.ts +8 -0
  337. package/src/dashboard/index.ts +78 -10
  338. package/src/dashboard/render/theme-resolver.ts +33 -4
  339. package/src/domains/schedule-registry.ts +16 -2
  340. package/src/git-fs/idle-refresh.ts +76 -0
  341. package/src/git-fs/index.ts +18 -7
  342. package/src/git-fs/worktree.ts +42 -4
  343. package/src/graph-kinds/registry.ts +2 -2
  344. package/src/graph-runner/runner.ts +153 -10
  345. package/src/grok/credential.ts +10 -3
  346. package/src/harness/harness-cli-command.ts +112 -28
  347. package/src/harness/harness-incidents.ts +33 -0
  348. package/src/harness/launch-utterance-ledger.ts +208 -0
  349. package/src/impl-discipline/detector.ts +16 -4
  350. package/src/impl-discipline/system-prompt.ts +11 -0
  351. package/src/impl-discipline/types.ts +2 -2
  352. package/src/index.ts +496 -143
  353. package/src/intake-plane/already-built-hint.ts +4 -2
  354. package/src/intake-plane/requirement-funnel.ts +29 -1
  355. package/src/light-cli.ts +27 -11
  356. package/src/llm/opengateway-models.ts +11 -0
  357. package/src/llm/provider-credentials.ts +14 -0
  358. package/src/llm/provider-detect.ts +8 -1
  359. package/src/llm/runtime-model-family.ts +2 -1
  360. package/src/llm.ts +213 -56
  361. package/src/model-tier/llm-tier-map.ts +15 -1
  362. package/src/native-tool-catalog.ts +15 -1
  363. package/src/nexus/api/loop-resources.ts +13 -1
  364. package/src/oauth/codex.ts +7 -0
  365. package/src/ops/overview-collect.ts +18 -3
  366. package/src/ops/overview.ts +20 -7
  367. package/src/pr-tool/census.ts +261 -27
  368. package/src/pty-shell/pty-manifest.ts +7 -0
  369. package/src/release-loop/checklist.ts +24 -0
  370. package/src/release-loop/landed-but-yellow.ts +129 -5
  371. package/src/release-loop/light-rc.ts +1 -0
  372. package/src/release-loop/rehearsal.ts +2 -2
  373. package/src/repl/index.ts +174 -17
  374. package/src/repl/ops-msg-bridge.ts +32 -0
  375. package/src/self-dev/ask-launch-flow.ts +44 -5
  376. package/src/self-dev/cli-help-text.ts +17 -0
  377. package/src/self-dev/dev-cli.ts +11 -9
  378. package/src/self-dev/draft-residue.ts +37 -1
  379. package/src/self-dev/draft-sweep.ts +137 -11
  380. package/src/self-dev/draft-triage-rules.ts +107 -0
  381. package/src/self-dev/fleet-reduce.ts +3 -2
  382. package/src/self-dev/graph-front-nodes.ts +112 -0
  383. package/src/self-dev/graph-journey-nodes.ts +1 -0
  384. package/src/self-dev/harness-run-cli.ts +3 -15
  385. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  386. package/src/self-dev/review-provider-fallback.ts +35 -1
  387. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  388. package/src/self-dev/shard-aggregate.ts +42 -5
  389. package/src/self-dev/shard-run.ts +8 -1
  390. package/src/self-implement/blocked-draft-policy.ts +20 -0
  391. package/src/self-implement/classify-shadow.ts +3 -7
  392. package/src/self-implement/doctor-visit.ts +18 -1
  393. package/src/self-implement/gate-baseline.ts +56 -17
  394. package/src/self-implement/gate-cli.ts +1 -0
  395. package/src/self-implement/gate-remote.ts +31 -20
  396. package/src/self-implement/goal-author-decompose.ts +275 -47
  397. package/src/self-implement/goal-author.ts +250 -0
  398. package/src/self-implement/goal-elaborate.ts +295 -0
  399. package/src/self-implement/goal-refine.ts +270 -0
  400. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  401. package/src/self-implement/orchestrator.ts +152 -45
  402. package/src/self-implement/rework-budget-judgment.ts +5 -8
  403. package/src/self-implement/run-stop.ts +10 -1
  404. package/src/self-implement/running-runs.ts +29 -1
  405. package/src/self-implement/scope-adjacency.ts +113 -0
  406. package/src/self-implement/seams.ts +127 -24
  407. package/src/self-implement/stop-autoheal.ts +87 -1
  408. package/src/session-runtime/index.ts +1 -1
  409. package/src/setup/llm-env-detect.ts +5 -0
  410. package/src/skills/tools/agent.ts +140 -14
  411. package/src/skills/tools/msg-ask.ts +100 -0
  412. package/src/skills/tools/ops-ledger.ts +2 -1
  413. package/src/steward/hold-hygiene.ts +24 -6
  414. package/src/steward/triage-budget.ts +194 -0
  415. package/src/steward/triage.ts +20 -3
  416. package/src/task-agent/actions.ts +69 -1
  417. package/src/task-agent/green-sweep.ts +4 -0
  418. package/src/task-agent/live-moves.ts +160 -4
  419. package/src/task-agent/parent-host.ts +123 -3
  420. package/src/task-agent/shadow.ts +7 -1
  421. package/src/task-agent/task-hand.ts +54 -41
  422. package/src/task-agent/tier-split.ts +127 -0
  423. package/src/task-agent/work-order-build.ts +2 -0
  424. package/src/task-agent/work-order.ts +3 -2
  425. package/src/task-orchestrator/generator-prompt.ts +60 -11
  426. package/src/task-orchestrator/surfaces/pod-account-broker.ts +33 -0
  427. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  428. package/src/task-orchestrator/surfaces/pod-command-job.ts +45 -7
  429. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  430. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  431. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  432. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  433. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  434. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  435. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  436. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  437. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +37 -5
  438. package/src/task-orchestrator/surfaces/self-implement-pod.ts +368 -36
  439. package/src/task-orchestrator/surfaces/self-implement.ts +23 -0
  440. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  441. package/src/tui/README.md +2 -0
  442. package/src/tui/chat/background-job-status.ts +54 -0
  443. package/src/tui/chat/log-view.ts +80 -0
  444. package/src/tui/entry.ts +406 -0
  445. package/src/tui/input/composer.ts +144 -0
  446. package/src/tui/seat-mail-boot.ts +59 -0
  447. package/src/tui/slash/compact.ts +100 -0
  448. package/src/tui/slash/new-session.ts +35 -0
  449. package/src/tui-client/local-chat-turn.ts +239 -0
  450. package/src/tui-client/local-harness-command.ts +63 -0
  451. package/src/tui-client/local-provider-command.ts +184 -0
  452. package/src/user-config.ts +4 -2
  453. package/src/ux-sim/event-monkey.ts +378 -0
  454. package/src/ux-sim/fake-bin.ts +42 -7
  455. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  456. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  457. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  458. package/src/version/packed-revision.json +1 -1
  459. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  460. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  463. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  465. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  467. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  468. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +0 -34
  479. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/3498.cf2a15a8a9e5b926.js +0 -226
  485. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +0 -32
  487. package/apps/pwa/out/_next/static/chunks/3837.722e053fb9f321ad.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  490. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  491. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  492. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  493. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  494. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  497. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  504. package/apps/pwa/out/_next/static/chunks/5446.edf141cff9ef647d.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  506. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  517. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  520. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +0 -41
  527. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  530. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  533. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  547. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  549. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  603. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/ffdc3a04.b9c23c1b28dd4a96.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  611. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → 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`). */
@@ -163,10 +174,16 @@ export interface DefaultTaskLauncherDeps {
163
174
  /** HQ 판(시험 주입). */
164
175
  localVersion?: string;
165
176
  /** HQ-owned, refresh-less Codex access mirror to install before a remote parent launch. */
166
- codexAccessMirror?: () => Promise<{ elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number } | null>;
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;
167
182
  /** Isolated integration seam; production still reads the HQ rotation snapshot and config directly. */
168
183
  ownerCodexRotation?: () => ReturnType<typeof import('../oauth/codex-account-store.js').inspectCodexRotation>;
169
184
  ownerCodexRotationConfig?: { accountOrder?: readonly string[]; thresholdPercentByAccount?: Readonly<Record<string, unknown>> };
185
+ /** The HQ owner fence is checked before any token refresh. */
186
+ ownerCodexLeaseHolder?: () => boolean;
170
187
  /** 원격 → 로컬 되돌림 알림(시험 주입). 기본 = stderr 한 줄. */
171
188
  notice?: (line: string) => void;
172
189
  }
@@ -187,13 +204,17 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
187
204
  const multi = Array.isArray(configured);
188
205
  const targets = configured === null ? [] : parentHostModule.resolveParentHosts(configured, deps.parentHost === undefined ? process.env : { ...process.env, ELANOUS_TA_PARENT_HOST: undefined });
189
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;
190
210
  const notice = deps.notice ?? ((line: string) => { try { process.stderr.write(`${line}\n`); } catch { /* ignore */ } });
191
211
  const failed = (target: typeof targets[number], gaps: string[], facts: Record<string, string> = {}): void => {
192
212
  try { debug.log('task-agent', 'parent-host-fallback', { host: target.host, runId: context.runId, gaps, facts }); } catch { /* fail-soft */ }
193
213
  notice(`[parent-host] ${target.host} 로 못 띄움 — ${multi ? '다음 호스트 또는 로컬 발사로 간다' : '로컬 발사로 간다'}: ${gaps.join(' · ')}`);
194
214
  };
195
- let accessMirror: { elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number } | null | undefined;
196
- const getAccessMirror = async (): Promise<{ elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number } | null> => {
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> => {
197
218
  if (accessMirror !== undefined) return accessMirror;
198
219
  if (deps.codexAccessMirror) {
199
220
  accessMirror = await deps.codexAccessMirror();
@@ -212,6 +233,10 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
212
233
  const config = getUserConfig();
213
234
  const ownerConfig = deps.ownerCodexRotationConfig;
214
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 토큰 주인 임대가 없어 원격 미러 발사를 거부한다');
215
240
  const eligible = planOwnerCodexMirrorCandidates(candidates, {
216
241
  accountOrder: ownerConfig?.accountOrder ?? config.llm?.codexAccountOrder ?? [],
217
242
  thresholdPercentByAccount: ownerConfig?.thresholdPercentByAccount ?? config.llm?.codexAccountRotationThresholdPercentByAccount,
@@ -220,22 +245,44 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
220
245
  const prerefreshDeps = {
221
246
  credentials: (account: string) => pod.hostCredentials(account, authStore.authStorePath(), () => '', { requireExplicitChatgptAuthMode: true }),
222
247
  refresh: (account: string) => codex.refreshCodexAccountHome(account),
223
- isLeaseHolder: () => hq.hqFenceDecision('ledger-cli').run,
248
+ isLeaseHolder: () => deps.ownerCodexLeaseHolder?.() ?? hq.hqFenceDecision('ledger-cli').run,
224
249
  };
225
- for (const candidate of eligible) {
226
- // The account's refresh token stays on HQ. Only the selected account's access-only mirror crosses SSH.
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.
227
258
  let credential: Awaited<ReturnType<typeof pod.podCodexCredentialWithPrerefresh>> = null;
228
259
  try { credential = await pod.podCodexCredentialWithPrerefresh(candidate.name, prerefreshDeps); }
229
- catch { continue; }
230
- if (!credential) continue;
231
- accessMirror = { elanousAuth: credential.elanousAuth, codexAuth: credential.codexAuth, account: candidate.name,
232
- ...(candidate.usedPercent !== undefined ? { usedPercent: candidate.usedPercent } : {}),
233
- thresholdPercent: podAccountThresholdPercent(candidate.name, {
234
- thresholdPercentByAccount: ownerConfig?.thresholdPercentByAccount ?? config.llm?.codexAccountRotationThresholdPercentByAccount,
235
- }) };
236
- return accessMirror;
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
+ }
237
284
  }
238
- accessMirror = null;
285
+ accessMirror = mirrors.length ? { ...mirrors[0]!, mirrors } : null;
239
286
  return accessMirror;
240
287
  };
241
288
  if (cwd) {
@@ -248,6 +295,11 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
248
295
  // 그 앞의 readParentHostCapacity 도 ssh). 가드를 아래로 내리면 hold 경로에서 시험이 실 ssh 를 쏜다(R7 사고 모양).
249
296
  // hold 경로를 재는 시험은 deps.ssh 가짜 또는 parentHost:null 을 주입한다(real-launch-guard.test 가 이 순서를 문다).
250
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;
251
303
  let launchHoldActive = false;
252
304
  try {
253
305
  if (deps.launchHoldActive) launchHoldActive = deps.launchHoldActive();
@@ -264,6 +316,8 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
264
316
  delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNT;
265
317
  delete remoteEnv.ELANOUS_REMOTE_CODEX_USED_PERCENT;
266
318
  delete remoteEnv.ELANOUS_REMOTE_CODEX_THRESHOLD_PERCENT;
319
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNTS;
320
+ delete remoteEnv.ELANOUS_REMOTE_CODEX_ACCESS_ONLY;
267
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) {
268
322
  const value = context.env[key] ?? process.env[key];
269
323
  if (value !== undefined) remoteEnv[key] = value;
@@ -300,30 +354,63 @@ async function tryRemoteParent(args: string[], cwd: string | undefined, context:
300
354
  if (preflight.warnings.length) notice(`⚠ ${target.host} 자격: ${preflight.warnings.join(' · ')}`);
301
355
  try {
302
356
  if (parentHostModule.shouldInstallRemoteCodexAccess(context.effectiveChildProvider)) {
303
- let mirror: { elanousAuth: string; codexAuth: string; account?: string; usedPercent?: number; thresholdPercent?: number } | null = null;
357
+ let mirror: OwnerMirror | null = null;
304
358
  let mirrorReason = 'credential-source-empty';
305
359
  try { mirror = await getAccessMirror(); }
306
360
  catch (error) {
307
361
  if (error instanceof NoEligibleOwnerCodexAccountError) throw error;
308
362
  mirrorReason = 'credential-source-error';
309
363
  }
310
- if (mirror) parentHostModule.installRemoteCodexAccess(target, mirror, deps.ssh);
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
+ }
311
394
  else {
312
395
  try { debug.log('task-agent.parent-host', 'codex-access-mirror-unavailable', { host: target.host, runId: context.runId, reason: mirrorReason }); } catch { /* fail-soft */ }
313
396
  failed(target, ['codex-access-mirror-unavailable']);
314
397
  return null;
315
398
  }
316
- if (mirror.account) {
317
- remoteEnv.ELANOUS_REMOTE_CODEX_ACCOUNT = mirror.account;
318
- remoteEnv.ELANOUS_REMOTE_CODEX_USED_PERCENT = mirror.usedPercent === undefined ? 'unknown' : String(mirror.usedPercent);
319
- if (mirror.thresholdPercent !== undefined) remoteEnv.ELANOUS_REMOTE_CODEX_THRESHOLD_PERCENT = String(mirror.thresholdPercent);
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);
320
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';
321
406
  }
322
- const launched = parentHostModule.launchRemoteParent(target, args, remoteEnv, deps.ssh);
407
+ const launched = parentHostModule.launchRemoteParent(target, args, remoteEnv, deps.ssh,
408
+ grokAccessMirror ? () => grokAccessMirror : undefined, effectiveChildProvider, deps.now);
323
409
  try { debug.log('task-agent', 'parent-host-launched', { host: target.host, runId: context.runId, pid: launched.pid, log: launched.log }); } catch { /* fail-soft */ }
324
410
  return { runId: context.runId, parentHost: { host: target.host, ...(target.configDir ? { configDir: target.configDir } : {}), pid: launched.pid, log: launched.log } };
325
411
  } catch (error) {
326
412
  if (error instanceof parentHostModule.RemoteParentNotLaunchedError) { failed(target, [error.message]); continue; }
413
+ if (error instanceof NoEligibleOwnerCodexAccountError) throw error;
327
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 */ }
328
415
  throw error;
329
416
  }
@@ -344,6 +431,7 @@ function firstStderrLine(path: string): string {
344
431
  }
345
432
 
346
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
347
435
  if (context) {
348
436
  const remote = await tryRemoteParent(args, cwd, context, deps);
349
437
  if (remote) return remote;
@@ -897,6 +985,332 @@ export function readTaskAgentCover(
897
985
  limitReached: truncated.taskAgentActions || truncated.allLands || moveRead?.limitReached === true || orderRead?.limitReached === true || goalAsksTruncated || goalRunsTruncated, unreadableStores };
898
986
  }
899
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
+
900
1314
  export function registerTasksCommands(program: Command, deps: TasksCliDeps = {}): void {
901
1315
  let activeToken: string | undefined;
902
1316
  const output = deps.output ?? console.log;
@@ -909,6 +1323,38 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
909
1323
  };
910
1324
  const tasks = program.command('tasks').alias('task').description('TOX 태스크 조회 및 승인 · TASK-AGENT 과제 넘기기(hand)');
911
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
+
912
1358
  tasks.command('green-sweep')
913
1359
  .description('병합된 과제 PR 과 칸 근거를 대조해 green/기록만/건너뜀을 미리 본다 (항상 dry-run)')
914
1360
  .requiredOption('--version <version>', '조회할 체크리스트 판')
@@ -923,6 +1369,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
923
1369
  { cwd: process.cwd(), encoding: 'utf8', timeout: 20_000 }));
924
1370
  const cards = Object.values(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(deps.taskStatePath ?? taskStatePathDefault()).tasks ?? {});
925
1371
  let holds: Set<string> | null = null;
1372
+ let holdDiagnostic: string | undefined;
926
1373
  if (opts.traffic) {
927
1374
  try {
928
1375
  const traffic: unknown = JSON.parse(readFileSync(opts.traffic, 'utf8'));
@@ -930,8 +1377,13 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
930
1377
  && Array.isArray((traffic as { hold?: unknown }).hold)
931
1378
  && (traffic as { hold: unknown[] }).hold.every((id) => typeof id === 'string'))
932
1379
  holds = new Set((traffic as { hold: string[] }).hold);
933
- } catch { /* unknown is not an empty hold set */ }
934
- }
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';
935
1387
  const prCache = new Map<number, GreenSweepPr | null>();
936
1388
  const ambiguousPrs = ambiguousGreenSweepPrs(snapshot.items, opts.version, cards);
937
1389
  const origin = run('git', ['remote', 'get-url', 'origin']);
@@ -981,7 +1433,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
981
1433
  return check.status === 0 ? true : check.status === 1 ? false : null;
982
1434
  })();
983
1435
  const decision = decideGreenSweep({ item, candidate, candidateCount: candidates.length,
984
- 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,
985
1437
  ambiguousAcrossCells: ambiguousPrs.has(candidate.pr) });
986
1438
  observeGreenSweep(decision);
987
1439
  return decision;
@@ -993,8 +1445,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
993
1445
  if (opts.json) out(JSON.stringify({ dryRun: true, version: opts.version, counts, decisions }));
994
1446
  else {
995
1447
  out(`dry-run · ${opts.version} · 후보 ${counts.candidate} · green ${counts.green} · 기록만 ${counts.recordOnly} · 건너뜀 ${counts.skipped}`);
996
- 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)}`);
997
- 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 ?? ''}`);
998
1449
  }
999
1450
  } catch (error) { out(`green-sweep 조회 실패: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
1000
1451
  });
@@ -1051,6 +1502,41 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1051
1502
  } catch (error) { out(error instanceof Error ? error.message : '커버 조회 실패'); process.exitCode = 1; }
1052
1503
  });
1053
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
+
1054
1540
  tasks.command('list')
1055
1541
  .description('우선순위와 생성 시각 순으로 태스크 보기')
1056
1542
  .option('--status <s>', '상태로 필터')
@@ -1227,7 +1713,8 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1227
1713
  if (resolved.kind === 'inlined') {
1228
1714
  try { debug.log('task-agent.hand', 'goal-file-inlined', { path: resolved.path, chars: resolved.chars, sha256: resolved.sha256 }); } catch { /* fail-soft */ }
1229
1715
  }
1230
- const result = await handTask({
1716
+ const handed = await handTaskWithTierSplit({
1717
+ ...('tierSizedDecompose' in deps ? { decompose: deps.tierSizedDecompose } : {}),
1231
1718
  text: resolved.text,
1232
1719
  ...(opts.project !== undefined && opts.target !== undefined ? { project: { id: opts.project, target: opts.target } } : {}),
1233
1720
  ...(opts.goal !== undefined ? { goal: opts.goal } : {}),
@@ -1236,6 +1723,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1236
1723
  ...(opts.checklist ? { checklistId: opts.checklist } : {}),
1237
1724
  ...(opts.completion ? { completion: opts.completion } : {}),
1238
1725
  live: opts.live === true,
1726
+ preflightGoalDoneBoundary: opts.live === true && deps.taskLauncher === undefined,
1239
1727
  ...(opts.taLand === true ? { taLand: true } : {}),
1240
1728
  ...(opts.childLlm !== undefined ? { childLlm: opts.childLlm } : {}),
1241
1729
  ...(opts.childLlmEffort !== undefined ? { childLlmEffort: opts.childLlmEffort } : {}),
@@ -1246,8 +1734,29 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
1246
1734
  ...(deps.taskCompositionRoot ? { compositionRoot: deps.taskCompositionRoot } : {}),
1247
1735
  launcher: deps.taskLauncher ?? defaultTaskLauncher,
1248
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;
1249
1754
  if (opts.json) out(JSON.stringify(result));
1250
- 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 {
1251
1760
  out(`${result.card.id}\t${result.mode}\t${result.launched ? 'launched' : 'not launched'}`);
1252
1761
  if (result.move.command) out(`elanous ${result.move.command.map(shellQuote).join(' ')}`);
1253
1762
  else out(result.move.reason);