elanous 0.2.32 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (753) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 0368f25d-ad84af92fefee68f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 1530.0e612369b6fd7ea0.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
  9. package/apps/pwa/out/_next/static/chunks/{7391.ebae168025c91b6a.js → 1674.2a65fd5668e1cc5f.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
  11. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
  12. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{7947-d0759430f8042240.js → 1993-c0007b7ad0c0ef41.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{60fb96c9.360b01d8d4927b7b.js → 1c735de4.f993a30bbd3c57c4.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 2018.a741297bce759490.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
  23. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{3902.e1e71aaac850a045.js → 2625.5d870aa999f33db1.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
  26. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
  31. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 3408.21d1570602f4b6c0.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 3677-4215f826f6aa68e5.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
  40. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
  42. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{7371.80c05c653b08e907.js → 4346.8601952e73bf5803.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
  46. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
  49. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 4718-17d2af636796a330.js} +3 -3
  51. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/{2001.6c7e0fd02190886c.js → 5154.a118f3957ed14e36.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
  61. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 5483-dd5d7697f6bdb106.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
  63. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3267c0e6.d34854e7b3984a6e.js → 56d372f2.681ab4ec4c998fae.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +287 -0
  67. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 6236.e18cced2d5ba6afb.js} +17 -17
  74. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
  78. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
  80. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6544cb48.a87fe20ddf137be2.js → 6b89c8bd.24df687a820500b3.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
  87. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
  88. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 7644.17e37ba6f1d4226e.js} +4 -4
  90. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{8018.a32663f04a6fc5f9.js → 8219.baa715d1deee80e2.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/{4111.2bfedbb233ad206b.js → 8256.e3ac8421a71f82f4.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 8444.4c26b379ca2b9596.js} +17 -17
  100. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
  101. package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
  104. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 8637.47f5b35afcae5e6b.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9214.63a510d39178e997.js} +2 -2
  111. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
  112. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 9512.5a76207a730e0491.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{69-0a2c8209c6d4a158.js → 967-2aa39b2d04b4c690.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 9952.5daf5f94063a2b3e.js} +1 -1
  120. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/{page-a27b1e5a0d1b308f.js → page-406b47745b53f269.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-32866485913d6a04.js → page-47c5d4db587266bd.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-dc0a532f5b9196ec.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → da5176c6.6773b6c5994e1d99.js} +7 -7
  178. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +10 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/README.md +5 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +76 -5
  285. package/graphs/document-loop.yaml +71 -4
  286. package/graphs/implement-loop.yaml +59 -4
  287. package/graphs/journey/SCENARIOS.md +33 -0
  288. package/graphs/journey/recipes.yaml +1 -0
  289. package/graphs/journey/ta-journey.yaml +94 -0
  290. package/graphs/journey/units/author/author.yaml +20 -0
  291. package/graphs/journey/units/author/recipes.yaml +2 -0
  292. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  293. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  294. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  295. package/graphs/journey/units/green/green.yaml +20 -0
  296. package/graphs/journey/units/green/recipes.yaml +2 -0
  297. package/graphs/journey/units/pr/pr.yaml +20 -0
  298. package/graphs/journey/units/pr/recipes.yaml +2 -0
  299. package/graphs/journey/units/remember/recipes.yaml +2 -0
  300. package/graphs/journey/units/remember/remember.yaml +20 -0
  301. package/graphs/operate-loop.yaml +71 -4
  302. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  303. package/graphs/release-rehearsal/recipes.yaml +1 -1
  304. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  305. package/graphs/research-loop.yaml +159 -4
  306. package/graphs/test-diet/test-diet.yaml +3 -0
  307. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  308. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  309. package/graphs/units/entry/entry.yaml +50 -0
  310. package/graphs/units/entry/recipes.yaml +14 -0
  311. package/graphs/units/harvest/harvest.yaml +25 -0
  312. package/graphs/units/harvest/recipes.yaml +4 -0
  313. package/graphs/units/land/land.yaml +45 -0
  314. package/graphs/units/land/recipes.yaml +3 -0
  315. package/graphs/units/recipes.yaml +7 -0
  316. package/graphs/units/recover.yaml +39 -0
  317. package/graphs/units/reflect/recipes.yaml +3 -0
  318. package/graphs/units/reflect/reflect.yaml +15 -0
  319. package/graphs/units/task-agent-recover-review.yaml +17 -0
  320. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  321. package/graphs/units/verbs/make-doc.yaml +34 -0
  322. package/graphs/units/verbs/recipes.yaml +33 -0
  323. package/graphs/units/verbs/verify.yaml +55 -0
  324. package/graphs/work/recipes.yaml +2 -0
  325. package/graphs/work/research-report.yaml +28 -0
  326. package/package.json +1 -1
  327. package/scripts/ci-typecheck-changed.ts +69 -16
  328. package/scripts/coord-role-pack.ts +19 -6
  329. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  330. package/scripts/graph-harvest-unit.ts +22 -0
  331. package/scripts/graph-units/journey-stub.ts +6 -0
  332. package/scripts/graph-units/land-enqueue.ts +78 -0
  333. package/scripts/graph-units/recover-plan.ts +15 -0
  334. package/scripts/graph-units/reflect-node.ts +88 -0
  335. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  336. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  337. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  338. package/scripts/graph-units/verbs-envelope.ts +139 -0
  339. package/scripts/hq/standby-snapshot.ts +30 -0
  340. package/scripts/public-export.ts +43 -1
  341. package/scripts/ratchets/train-side-invariants.sh +45 -0
  342. package/scripts/release-loop/auto-approve-node.ts +30 -16
  343. package/scripts/release-loop/docs-land-node.ts +21 -5
  344. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  345. package/scripts/release-loop/gate-closure.ts +5 -1
  346. package/scripts/release-loop/gate-diff.ts +1 -1
  347. package/scripts/release-loop/gate-node.ts +675 -49
  348. package/scripts/release-loop/gate-partial.ts +68 -14
  349. package/scripts/release-loop/gate-radius-live.ts +177 -0
  350. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  351. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  352. package/scripts/release-loop/gate-triage-node.ts +5 -2
  353. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  354. package/scripts/release-loop/known-issues-node.ts +77 -8
  355. package/scripts/release-loop/node-verdict.ts +12 -1
  356. package/scripts/release-loop/npm-publish-node.ts +66 -12
  357. package/scripts/release-loop/preflight.ts +93 -7
  358. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  359. package/scripts/release-loop/publish-node.ts +60 -9
  360. package/scripts/release-loop/pwa-remote.ts +166 -0
  361. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  362. package/scripts/release-loop/resume-cap.ts +56 -0
  363. package/scripts/release-loop/resume-release.ts +155 -19
  364. package/scripts/release-loop/resume.ts +24 -1
  365. package/scripts/release-loop/tui-sim-node.ts +8 -2
  366. package/scripts/release-loop/unattended-release.ts +10 -2
  367. package/scripts/test-diet/lib.ts +6 -1
  368. package/scripts/test-diet/node.ts +194 -13
  369. package/scripts/ux-sim.ts +39 -0
  370. package/src/acp/core-turn-bridge.ts +20 -5
  371. package/src/acp/reasoning-thought-buffer.ts +45 -0
  372. package/src/agent/self-ambient-cache.ts +8 -0
  373. package/src/agent-substrate/acp-reviewer.ts +90 -15
  374. package/src/agent-substrate/pr-reviewer.ts +17 -0
  375. package/src/agent-substrate/review-finding-key.ts +53 -0
  376. package/src/agent-substrate/self-review-cli.ts +188 -18
  377. package/src/ask-user-question/pending-questions.ts +1 -1
  378. package/src/autopilot/pr-manager.ts +393 -65
  379. package/src/budget/run-usage-rollup.ts +1 -0
  380. package/src/chat/index.ts +0 -2
  381. package/src/chat/pickers/modal-runtime.ts +10 -27
  382. package/src/chat/tool-render/dispatch.ts +62 -10
  383. package/src/cli/agent-cli.ts +13 -2
  384. package/src/cli/control-cli.ts +24 -7
  385. package/src/cli/doctor-cli.ts +4 -1
  386. package/src/cli/guardian-cli.ts +10 -0
  387. package/src/cli/light-entry-route.ts +75 -0
  388. package/src/cli/llm-detect-cli.ts +23 -1
  389. package/src/cli/pod-cli.ts +77 -3
  390. package/src/cli/pr-cli.ts +81 -14
  391. package/src/cli/pr-land-base-read.ts +2 -0
  392. package/src/cli/pr-land-overlap-evidence.ts +154 -16
  393. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  394. package/src/cli/pr-land-recovery.ts +64 -0
  395. package/src/cli/pty-takeover-cli.ts +6 -5
  396. package/src/cli/release-checklist-read-cli.ts +79 -0
  397. package/src/cli/release-cli.ts +189 -132
  398. package/src/cli/release-run-if-ready.ts +29 -28
  399. package/src/cli/release-single-flight.ts +178 -0
  400. package/src/cli/remote-resolve.ts +1 -1
  401. package/src/cli/root-tui-entry.ts +48 -0
  402. package/src/cli/seat-cli.ts +37 -0
  403. package/src/cli/setup-cli.ts +40 -1
  404. package/src/cli/sim-cli.ts +22 -0
  405. package/src/cli/tasks-cli.ts +667 -14
  406. package/src/cli/usage-cli.ts +13 -11
  407. package/src/clipboard/history.ts +179 -13
  408. package/src/config.ts +8 -1
  409. package/src/control/control-status.ts +8 -3
  410. package/src/control-plane/ledger.ts +5 -3
  411. package/src/control-plane/server.ts +5 -3
  412. package/src/core-turn/short-question.ts +5 -1
  413. package/src/dashboard/chat/acp-chat.ts +8 -0
  414. package/src/dashboard/index.ts +114 -77
  415. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  416. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  417. package/src/dashboard/input/seat-autowake.ts +56 -3
  418. package/src/dashboard/render/theme-resolver.ts +33 -4
  419. package/src/dashboard/seat-boot-preamble.ts +1 -1
  420. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  421. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  422. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  423. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  424. package/src/dashboard/turn-preamble.ts +47 -1
  425. package/src/dashboard/turn-stream-formatter.ts +34 -1
  426. package/src/dashboard/turn-stream-runtime.ts +2 -0
  427. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  428. package/src/domains/guardian-tick.ts +54 -2
  429. package/src/domains/outbound-alert.ts +3 -2
  430. package/src/domains/schedule-registry.ts +16 -2
  431. package/src/extractors.ts +3 -1
  432. package/src/git-fs/idle-refresh.ts +76 -0
  433. package/src/git-fs/index.ts +18 -7
  434. package/src/git-fs/retry.ts +4 -0
  435. package/src/git-fs/runner.ts +2 -0
  436. package/src/git-fs/worktree.ts +42 -4
  437. package/src/graph-kinds/registry.ts +2 -2
  438. package/src/graph-runner/runner.ts +267 -54
  439. package/src/grok/credential.ts +15 -3
  440. package/src/harness/harness-cli-command.ts +151 -38
  441. package/src/harness/harness-incidents.ts +37 -0
  442. package/src/harness/harness-pod-dispatch.ts +38 -1
  443. package/src/harness/harness-salvage-cli.ts +14 -2
  444. package/src/harness/launch-utterance-ledger.ts +208 -0
  445. package/src/impl-discipline/detector.ts +16 -4
  446. package/src/impl-discipline/system-prompt.ts +11 -0
  447. package/src/impl-discipline/types.ts +2 -2
  448. package/src/index.ts +683 -146
  449. package/src/intake-plane/already-built-hint.ts +91 -0
  450. package/src/intake-plane/requirement-funnel.ts +29 -1
  451. package/src/knowhow/pack.ts +199 -0
  452. package/src/light-cli.ts +111 -0
  453. package/src/llm/opengateway-models.ts +11 -0
  454. package/src/llm/provider-credentials.ts +14 -0
  455. package/src/llm/provider-detect.ts +8 -1
  456. package/src/llm/runtime-model-family.ts +2 -1
  457. package/src/llm.ts +268 -65
  458. package/src/loops/budget.ts +95 -0
  459. package/src/loops/msg-wake.ts +8 -2
  460. package/src/loops/orchestrator/traffic.ts +132 -1
  461. package/src/model-tier/llm-tier-map.ts +15 -1
  462. package/src/mss/logging/log-store.ts +4 -5
  463. package/src/native-tool-catalog.ts +15 -1
  464. package/src/nexus/api/graphs-api.ts +22 -3
  465. package/src/nexus/api/http-server.ts +1 -1
  466. package/src/nexus/api/loop-resources.ts +13 -1
  467. package/src/nexus/api/ops-api.ts +12 -0
  468. package/src/oauth/claude-pty-maturity.ts +66 -0
  469. package/src/oauth/codex-access-mirror.ts +55 -0
  470. package/src/oauth/codex.ts +7 -0
  471. package/src/oauth/fallback-chain.ts +1 -1
  472. package/src/onboarding/first-run.ts +5 -3
  473. package/src/onboarding/non-interactive.ts +64 -13
  474. package/src/onboarding.ts +10 -2
  475. package/src/ops/overview-collect.ts +54 -4
  476. package/src/ops/overview.ts +31 -7
  477. package/src/pr-tool/census.ts +282 -30
  478. package/src/pr-tool/inflight-registry.ts +160 -7
  479. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  480. package/src/pty-shell/herdr-agent-report.ts +442 -0
  481. package/src/pty-shell/pty-control-ipc.ts +5 -5
  482. package/src/pty-shell/pty-manifest.ts +7 -0
  483. package/src/pty-shell/pty-write-outcome.ts +24 -6
  484. package/src/pty-shell/tui-run-state.ts +117 -3
  485. package/src/release-loop/checklist.ts +103 -5
  486. package/src/release-loop/feature-store.ts +19 -2
  487. package/src/release-loop/landed-but-yellow.ts +129 -5
  488. package/src/release-loop/light-rc.ts +1 -0
  489. package/src/release-loop/placement.ts +10 -3
  490. package/src/release-loop/rehearsal.ts +205 -25
  491. package/src/release-loop/rubric.ts +16 -2
  492. package/src/repl/index.ts +174 -17
  493. package/src/repl/ops-msg-bridge.ts +32 -0
  494. package/src/self-dev/ask-launch-flow.ts +44 -5
  495. package/src/self-dev/cli-help-text.ts +17 -0
  496. package/src/self-dev/dev-cli.ts +11 -9
  497. package/src/self-dev/draft-residue.ts +37 -1
  498. package/src/self-dev/draft-sweep.ts +188 -13
  499. package/src/self-dev/draft-triage-rules.ts +107 -0
  500. package/src/self-dev/fleet-reduce.ts +3 -2
  501. package/src/self-dev/graph-front-nodes.ts +112 -0
  502. package/src/self-dev/graph-journey-nodes.ts +11 -6
  503. package/src/self-dev/graph-journey-route.ts +60 -6
  504. package/src/self-dev/harness-run-cli.ts +3 -15
  505. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  506. package/src/self-dev/orchestrate.ts +79 -3
  507. package/src/self-dev/review-provider-fallback.ts +35 -1
  508. package/src/self-dev/run-supervisor.ts +107 -12
  509. package/src/self-dev/run-types.ts +5 -1
  510. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  511. package/src/self-dev/shard-aggregate.ts +42 -5
  512. package/src/self-dev/shard-run.ts +8 -1
  513. package/src/self-implement/blocked-draft-policy.ts +20 -0
  514. package/src/self-implement/classify-shadow.ts +3 -7
  515. package/src/self-implement/doctor-visit.ts +18 -1
  516. package/src/self-implement/gate-baseline.ts +95 -12
  517. package/src/self-implement/gate-cli.ts +1 -0
  518. package/src/self-implement/gate-remote.ts +40 -25
  519. package/src/self-implement/goal-author-decompose.ts +275 -47
  520. package/src/self-implement/goal-author-identity.ts +66 -0
  521. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  522. package/src/self-implement/goal-author.ts +254 -120
  523. package/src/self-implement/goal-elaborate.ts +295 -0
  524. package/src/self-implement/goal-refine.ts +270 -0
  525. package/src/self-implement/graph-overlay-yaml.ts +28 -2
  526. package/src/self-implement/graph-unit-flatten.ts +103 -0
  527. package/src/self-implement/graph-unit-resolver.ts +107 -0
  528. package/src/self-implement/graph-yaml.ts +151 -1
  529. package/src/self-implement/headless-elanous-driver.ts +1 -0
  530. package/src/self-implement/knowhow-pack.ts +103 -0
  531. package/src/self-implement/orchestrator.ts +160 -45
  532. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  533. package/src/self-implement/review-mustfix-class.ts +203 -0
  534. package/src/self-implement/rework-budget-judgment.ts +5 -8
  535. package/src/self-implement/run-stop.ts +17 -2
  536. package/src/self-implement/running-runs.ts +29 -1
  537. package/src/self-implement/scope-adjacency.ts +113 -0
  538. package/src/self-implement/seams.ts +138 -4
  539. package/src/self-implement/stop-autoheal.ts +112 -2
  540. package/src/session/chat.ts +27 -0
  541. package/src/session-runtime/index.ts +1 -1
  542. package/src/session-runtime/retry-policy.ts +2 -1
  543. package/src/setup/llm-env-detect.ts +5 -0
  544. package/src/skills/tools/agent.ts +140 -14
  545. package/src/skills/tools/msg-ask.ts +100 -0
  546. package/src/skills/tools/ops-ledger.ts +2 -1
  547. package/src/skills/tools/schedule-wakeup.ts +66 -17
  548. package/src/steward/hold-hygiene.ts +24 -6
  549. package/src/steward/release-day.ts +7 -3
  550. package/src/steward/triage-budget.ts +194 -0
  551. package/src/steward/triage.ts +57 -7
  552. package/src/task-agent/actions.ts +69 -1
  553. package/src/task-agent/green-sweep.ts +4 -0
  554. package/src/task-agent/harvest-unit.ts +141 -0
  555. package/src/task-agent/live-moves.ts +257 -15
  556. package/src/task-agent/parent-host.ts +216 -6
  557. package/src/task-agent/postland-card.ts +80 -1
  558. package/src/task-agent/rejudge-on-head.ts +112 -26
  559. package/src/task-agent/repair-branch-cas.ts +4 -1
  560. package/src/task-agent/repair-cycle.ts +16 -3
  561. package/src/task-agent/run-identity.ts +4 -3
  562. package/src/task-agent/shadow.ts +19 -3
  563. package/src/task-agent/task-hand.ts +96 -36
  564. package/src/task-agent/tier-split.ts +127 -0
  565. package/src/task-agent/work-order-build.ts +24 -0
  566. package/src/task-agent/work-order.ts +3 -2
  567. package/src/task-orchestrator/generator-prompt.ts +60 -11
  568. package/src/task-orchestrator/surfaces/pod-account-broker.ts +72 -3
  569. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  570. package/src/task-orchestrator/surfaces/pod-command-job.ts +47 -8
  571. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  572. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  573. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  574. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  575. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
  576. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  577. package/src/task-orchestrator/surfaces/pod-source-receive.ts +72 -4
  578. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  579. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +32 -5
  580. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  581. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +421 -0
  582. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
  583. package/src/task-orchestrator/surfaces/self-implement-pod.ts +588 -71
  584. package/src/task-orchestrator/surfaces/self-implement.ts +106 -2
  585. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  586. package/src/tool-runtime/truncation-store.ts +4 -0
  587. package/src/tui/README.md +2 -0
  588. package/src/tui/chat/background-job-status.ts +54 -0
  589. package/src/tui/chat/log-view.ts +80 -0
  590. package/src/tui/entry.ts +406 -0
  591. package/src/tui/input/composer.ts +144 -0
  592. package/src/tui/seat-mail-boot.ts +59 -0
  593. package/src/tui/slash/compact.ts +100 -0
  594. package/src/tui/slash/new-session.ts +35 -0
  595. package/src/tui-client/dashboard-session.ts +10 -1
  596. package/src/tui-client/local-chat-turn.ts +239 -0
  597. package/src/tui-client/local-harness-command.ts +63 -0
  598. package/src/tui-client/local-provider-command.ts +184 -0
  599. package/src/user-config/coercion.ts +36 -0
  600. package/src/user-config.ts +22 -43
  601. package/src/ux-sim/event-monkey.ts +378 -0
  602. package/src/ux-sim/fake-bin.ts +42 -7
  603. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  604. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  605. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  606. package/src/ux-sim/scenario.ts +72 -13
  607. package/src/version/packed-revision.json +1 -1
  608. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  611. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  612. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  613. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  617. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  619. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  620. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  636. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  640. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +0 -226
  642. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  644. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/5543.a438b8ab5a13ea47.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  653. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  655. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  661. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  662. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  663. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  668. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  669. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  674. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +0 -24
  685. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9989.3694300e5f000b14.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  744. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  752. package/src/cli/g6a-registration-probe.ts +0 -16
  753. /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
@@ -17,9 +17,14 @@ import { dirname, join, resolve } from 'node:path';
17
17
  import { fileURLToPath } from 'node:url';
18
18
 
19
19
  import { debug } from '../debug/log.js';
20
+ import { createHerdrAgentReporter, type HerdrAgentReporterLike } from './herdr-agent-report.js';
20
21
  import { runGitCommand } from '../git-fs/runner.js';
21
22
  import { codeRevision, packageVersion, readInstallMetadataCommit } from '../version/code-revision.js';
22
- import { versionedDashboardInstallDir } from '../dashboard/stale-install-check.js';
23
+ import {
24
+ buildStaleInstallRelaunchCommand,
25
+ formatStaleInstallNotice,
26
+ versionedDashboardInstallDir,
27
+ } from '../dashboard/stale-install-check.js';
23
28
  import {
24
29
  updatePtyManifestBuild, updatePtyManifestTurn,
25
30
  type PtyBuildIdentity, type PtyManifestRow, type PtyTurnState,
@@ -138,6 +143,86 @@ export function judgeBuildStaleness(input: {
138
143
  return { stale: null, reason: 'unknown' };
139
144
  }
140
145
 
146
+ // ── 매 턴 자기 건강 한 줄(TUI-SELF-HEALTH-LINE · 0.2.34) ──
147
+ //
148
+ // 대시보드 턴 프리앰블에 매 턴 실리는 자기 관측 한 줄: «실행 판 vs 설치본» 낡음 판정
149
+ // (judgeBuildStaleness ⊕ readCurrentInstallRecord — 이미 있는 실물)에 «직전 30분 자기 오류»
150
+ // ·«크레딧 사용» 재료를 얹는다. 낡은 판이면 재기동 필요를 말하되 안내 문면·재기동 명령은
151
+ // stale-install-check 의 기존 재료(formatStaleInstallNotice · buildStaleInstallRelaunchCommand)를
152
+ // 그대로 쓴다 — 문면을 두벌로 만들지 않는다.
153
+ //
154
+ // ⚠️ 미결(이 모듈이 정하지 않는다): ① 직전 30분 창에서 «어떤 이벤트를 자기 오류로 세는지» —
155
+ // 호출자가 집계해 count·sample 로 넘긴다. ② 크레딧 사용 재료를 무엇으로 잴지 — 호출자가 만든
156
+ // 값을 넘긴다. 두 축은 계약이 정해지는 즉시 호출부에서 주입하면 된다.
157
+
158
+ export interface SelfHealthErrors {
159
+ /** 직전 30분 창의 자기 오류 건수. 0 = 오류 없음. */
160
+ readonly count: number;
161
+ /** 오류를 대표하는 한 줄(첫 오류 요약 등). 없으면 개수만 말한다. */
162
+ readonly sample?: string;
163
+ }
164
+
165
+ export interface SelfHealthLineDeps {
166
+ /** 기동 판 — 기본 runningBuild(기동 때 한 번 잡힌 값). */
167
+ readonly build?: () => PtyBuildIdentity;
168
+ /** 지금 current 설치본 기록 — 기본 readCurrentInstallRecord. */
169
+ readonly readInstalled?: () => InstalledRecord;
170
+ /** 체크아웃 HEAD 재독기 — 기동 판이 checkout 일 때만 불린다. 기본 readCheckoutHead. */
171
+ readonly readCheckoutHead?: (codeRoot: string) => string | undefined;
172
+ /** 재기동 명령에 얹을 대화 id — 없으면 안내 문면만. */
173
+ readonly sessionId?: string;
174
+ /** 새 판 안내 회차(formatStaleInstallNotice notifiedCount) — 기본 1. */
175
+ readonly notifiedCount?: number;
176
+ /** 크레딧 사용 재료(호출자가 만든 값) — 없으면 그 축은 생략된다. */
177
+ readonly creditUsage?: string;
178
+ }
179
+
180
+ /** 매 턴 자기 건강 한 줄. 판 축 재료가 깨져도 오류·크레딧 축은 살리고, 말할 것이 없으면 null —
181
+ * 줄이 턴을 막지 않는다(fail-soft). */
182
+ export function buildSelfHealthLine(
183
+ errors: SelfHealthErrors | null | undefined,
184
+ deps: SelfHealthLineDeps = {},
185
+ ): string | null {
186
+ const segments: string[] = [];
187
+ try {
188
+ const build = (deps.build ?? runningBuild)();
189
+ const installed = (deps.readInstalled ?? readCurrentInstallRecord)();
190
+ let checkoutHead: string | undefined;
191
+ if (build.source === 'checkout' && build.codeRoot) {
192
+ checkoutHead = (deps.readCheckoutHead ?? readCheckoutHead)(build.codeRoot);
193
+ }
194
+ const staleness = judgeBuildStaleness({ build, installed, ...(checkoutHead ? { checkoutHead } : {}) });
195
+ segments.push(`실행 판 ${build.version}@${shortSha(build.sha)}(${build.source})`);
196
+ if (staleness.stale === true) {
197
+ const relaunch = deps.sessionId
198
+ ? ` · 다시 띄우기: ${buildStaleInstallRelaunchCommand(deps.sessionId)}`
199
+ : '';
200
+ if (staleness.reason === 'installed-moved' && build.sha && installed.sha) {
201
+ segments.push(`낡은 판 — 재기동 필요: ${formatStaleInstallNotice(
202
+ { state: 'changed', bootCommit: build.sha, installedCommit: installed.sha },
203
+ deps.notifiedCount ?? 1,
204
+ )}${relaunch}`);
205
+ } else {
206
+ segments.push(`낡은 판(${staleness.reason}) — 재기동 필요${relaunch}`);
207
+ }
208
+ } else if (staleness.stale === false) {
209
+ segments.push(`판 최신(${staleness.reason})`);
210
+ } else {
211
+ // stale=null 은 «안 낡았다»가 아니다 — 못 잼을 못 잼으로 말한다.
212
+ segments.push(`판 낡음 모름(${staleness.reason})`);
213
+ }
214
+ } catch {
215
+ // 판 축 재료가 깨져도 오류·크레딧 축은 살린다 — 관측이 턴을 막지 않는다.
216
+ }
217
+ if (errors) {
218
+ segments.push(errors.count > 0
219
+ ? `직전 30분 자기 오류 ${errors.count}건${errors.sample ? ` — 대표: ${errors.sample}` : ''}`
220
+ : '직전 30분 자기 오류 0건');
221
+ }
222
+ if (deps.creditUsage) segments.push(`크레딧 사용 ${deps.creditUsage}`);
223
+ return segments.length > 0 ? `[자기 건강] ${segments.join(' · ')}` : null;
224
+ }
225
+
141
226
  // ── 판독(CLI) ──
142
227
 
143
228
  export type PtyTurnView = PtyTurnState | 'unknown';
@@ -230,6 +315,12 @@ export interface TuiRunStateRecorderDeps {
230
315
  readonly writeBuild?: (id: string, build: PtyBuildIdentity) => boolean;
231
316
  readonly writeTurn?: (id: string, turn: PtyTurnState, at: number) => boolean;
232
317
  readonly log?: (event: string, data: Record<string, unknown>) => void;
318
+ /**
319
+ * herdr pane 신고기. 생략 시: `writeTurn` 을 주입하지 않은 기본 녹음기만
320
+ * `createHerdrAgentReporter` 를 만든다(시험이 실 herdr 를 안 건드리게).
321
+ * `null` 이면 신고하지 않는다.
322
+ */
323
+ readonly herdr?: HerdrAgentReporterLike | null;
233
324
  }
234
325
 
235
326
  interface ActiveRecorder {
@@ -237,7 +328,11 @@ interface ActiveRecorder {
237
328
  readonly now: () => number;
238
329
  readonly writeTurn: (id: string, turn: PtyTurnState, at: number) => boolean;
239
330
  readonly log: (event: string, data: Record<string, unknown>) => void;
331
+ readonly herdr: HerdrAgentReporterLike | null;
332
+ /** manifest 에 실제로 적힌 마지막 턴. 실패면 안 바뀐다(재시도). */
240
333
  last?: PtyTurnState;
334
+ /** herdr 에 마지막으로 알린 턴. manifest 성패와 따로 둔다. */
335
+ herdrLast?: PtyTurnState;
241
336
  }
242
337
 
243
338
  let active: ActiveRecorder | null = null;
@@ -249,6 +344,10 @@ export function startTuiRunStateRecorder(surfaceId: string, deps: TuiRunStateRec
249
344
  const now = deps.now ?? Date.now;
250
345
  const log = deps.log ?? defaultLog;
251
346
  const writeTurn = deps.writeTurn ?? updatePtyManifestTurn;
347
+ // 기본 신고기는 기본 manifest 쓰기와 짝일 때만. writeTurn 주입(시험)은 herdr 를 안 만든다.
348
+ const herdr = deps.herdr !== undefined
349
+ ? deps.herdr
350
+ : (deps.writeTurn ? null : createHerdrAgentReporter({ sessionId: surfaceId }));
252
351
  let build: PtyBuildIdentity | undefined;
253
352
  try { build = (deps.build ?? runningBuild)(); } catch (error) {
254
353
  log('build-resolve-failed', { ptyId: surfaceId, error: error instanceof Error ? error.message : String(error) });
@@ -257,10 +356,15 @@ export function startTuiRunStateRecorder(surfaceId: string, deps: TuiRunStateRec
257
356
  const ok = (() => { try { return (deps.writeBuild ?? updatePtyManifestBuild)(surfaceId, build); } catch { return false; } })();
258
357
  log(ok ? 'build-recorded' : 'build-write-failed', { ptyId: surfaceId, sha: build.sha, version: build.version, source: build.source });
259
358
  }
260
- const recorder: ActiveRecorder = { surfaceId, now, writeTurn, log };
359
+ // 기동 순서: 판 → manifest 초기 idle → herdr 신고. herdr start 가 idle 을 신고하므로 초기 idle 을 turn 으로 다시 안 보낸다.
360
+ const recorder: ActiveRecorder = { surfaceId, now, writeTurn, log, herdr, herdrLast: herdr ? 'idle' : undefined };
261
361
  active = recorder;
262
362
  writeTurnState(recorder, 'idle');
263
- return () => { if (active === recorder) active = null; };
363
+ if (herdr) { try { herdr.start(); } catch { /* 신고 실패가 녹음기를 깨지 않는다 */ } }
364
+ return () => {
365
+ if (herdr) { try { herdr.release(); } catch { /* 종료 경로를 깨지 않는다 */ } }
366
+ if (active === recorder) active = null;
367
+ };
264
368
  }
265
369
 
266
370
  /** 대시보드가 턴 시작(busy)·끝(idle)에 부른다. 녹음기가 없으면(자기보고 꺼짐) 아무것도 안 한다. */
@@ -276,6 +380,16 @@ function writeTurnState(recorder: ActiveRecorder, turn: PtyTurnState): void {
276
380
  if (ok) recorder.last = turn;
277
381
  // 실패는 관측으로 남긴다 — 바깥 제어자는 그 사이 «unknown/낡은 값»을 본다. 성공은 남기지 않는다(턴마다 두 줄은 소음).
278
382
  else recorder.log('turn-write-failed', { ptyId: recorder.surfaceId, turn, at });
383
+ // herdr 는 manifest 쓰기 성패와 무관하게, 값이 바뀔 때 알린다(같은 값 재시도는 한 번만).
384
+ if (recorder.herdr && recorder.herdrLast !== turn) {
385
+ // 신고가 동기로 던지면 «보낸 상태» 로 적지 않는다 — herdr 가 아는 값(herdrLast)과 다음 전이를 비교해 다시 보낸다(r4 리뷰 sf).
386
+ try {
387
+ recorder.herdr.turn(turn);
388
+ recorder.herdrLast = turn;
389
+ } catch (error) {
390
+ recorder.log('herdr-turn-threw', { turn, error: error instanceof Error ? error.message : String(error) });
391
+ }
392
+ }
279
393
  }
280
394
 
281
395
  export function resetTuiRunStateForTesting(): void {
@@ -1,4 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
2
3
  import { readFileSync, statSync } from 'node:fs';
3
4
  import { isAbsolute, join } from 'node:path';
4
5
  import * as store from './feature-store.js';
@@ -131,20 +132,77 @@ function mentionedPaths(text: string): string[] {
131
132
  return [...text.matchAll(PATH_TOKEN)].map((match) => match[1]!).filter((path) => !path.split('/').includes('..'));
132
133
  }
133
134
 
135
+ /** `docs/goal-context/03-verification-menu.md` §선택 원칙: merge SHA·타입검사는 수용선이 아니다. */
136
+ export const MERGE_OR_TYPECHECK_ONLY_REAL_WARNING = '- 완료 경계 실물: merge sha·타입검사만으로는 실물이 아니다 — docs/goal-context/03-verification-menu.md 에서 동작을 재는 방법을 고른다';
137
+ /** 통합 이력·정적 타입 상태만 말하는 낱말(조사 뗀 꼴). 이 밖의 낱말이 하나라도 있으면 실물 주장으로 본다. */
138
+ const MERGE_OR_TYPECHECK_WORD = /^(?:pr|merge|merged|머지|병합|착지|landed|land|sha|merge-sha|commit|커밋|origin|main|tsc|typecheck|type-check|typecheck-changed|타입검사|타입|검사|type|check|changed|통과|pass|passed|green|clean|errors?|error|오류|에러|없음|후|뒤|완료|확인|and|및|만|됨|된다)$/i;
139
+ const MERGE_OR_TYPECHECK_SIGNAL = /^(?:merge|merged|머지|병합|착지|landed|land|sha|merge-sha|tsc|typecheck|type-check|타입검사)$/i;
140
+ const KOREAN_PARTICLE_TAIL = /(?:했다|했음|하였다|했고|함|으로|로|이|가|은|는|을|를|와|과|에|의|만|됨|된|된다)$/u;
141
+
142
+ /** 「완료 경계 실물」 값이 merge sha·PR 착지·타입검사 낱말로만 이뤄졌나(동작 관측이 하나도 없나). */
143
+ export function isMergeOrTypecheckOnlyEvidence(value: string): boolean {
144
+ const words = value.split(/[\s.!?。…~`'"·,⊕+()[\]:;/=|→-]+/u).map((word) => word.replace(/^#/, '')).filter(Boolean);
145
+ if (!words.length) return false;
146
+ let signal = false;
147
+ for (const raw of words) {
148
+ if (/^\d+$/.test(raw) || /^[0-9a-f]{7,40}$/i.test(raw)) continue;
149
+ let word = raw;
150
+ for (let strip = 0; strip < 3 && !MERGE_OR_TYPECHECK_WORD.test(word); strip++) word = word.replace(KOREAN_PARTICLE_TAIL, '');
151
+ if (!MERGE_OR_TYPECHECK_WORD.test(word)) return false;
152
+ if (MERGE_OR_TYPECHECK_SIGNAL.test(word)) signal = true;
153
+ }
154
+ return signal;
155
+ }
156
+
134
157
  /** Shadow check at checklist authorship. Callers supply the origin/main file probe and merged-PR file reader. */
135
158
  export function inspectChecklistTargetPaths(input: {
136
159
  title: string; evidence?: string; refs?: readonly string[]; dispatchKind?: ChecklistDispatchKind;
137
- }, deps: { existsAtMain: (path: string) => boolean; mergedPrFiles?: (number: number) => readonly string[] }): {
160
+ }, deps: { existsAtMain: (path: string) => boolean; objectTypeAtMain?: (path: string) => 'blob' | 'tree' | 'commit' | 'blocked-blob' | 'blocked-gitlink' | 'unavailable' | null; mergedPrFiles?: (number: number) => readonly string[] }): {
138
161
  targets: string[]; warnings: string[]; candidates: string[];
139
162
  } {
140
163
  const lines = input.title.split(/\r?\n/);
141
164
  const first = /^대상 경로:\s*(.*)$/.exec(lines[0] ?? '');
142
- const targets = first ? [...new Set(mentionedPaths(first[1]!))] : [];
143
- const newFileDeclared = /^신설:\s*/.test(lines[1] ?? '');
165
+ const rawTargets = first?.[1]?.split(' · ').map((path) => path.trim()) ?? [];
166
+ const validPath = (path: string): boolean => path.length > 0 && path.length < 4096
167
+ && !path.startsWith('/') && !path.includes('\\') && !/[\u0000-\u001f\u007f]/u.test(path)
168
+ && path.split('/').every((segment) => segment !== '' && segment !== '.' && segment !== '..');
169
+ const targets = [...new Set(rawTargets.filter(validPath))];
170
+ const misplacedNewFiles = lines.slice(2).filter((line) => /^신설:\s*/.test(line));
171
+ const rawNewFiles = lines.slice(1, 2).filter((line) => /^신설:\s*/.test(line))
172
+ .flatMap((line) => line.slice('신설:'.length).split(' · ').map((path) => path.trim()));
173
+ const newFiles = new Set(rawNewFiles.filter(validPath));
144
174
  const warnings: string[] = [];
145
175
  if ((input.dispatchKind ?? 'code') === 'code') {
146
- if (!first || !first[1]!.trim() || targets.length === 0) warnings.push('첫 줄 대상 경로가 없다');
147
- for (const path of targets) if (!deps.existsAtMain(path) && !newFileDeclared) warnings.push(`${path}: origin/main에 없는 파일 · 신설: 둘째 줄 선언 필요`);
176
+ if (!first || !first[1]!.trim()) warnings.push('첫 줄 대상 경로가 없다');
177
+ else if (targets.length !== rawTargets.length || targets.length === 0) warnings.push('첫 줄은 실제 파일 경로만 « · »로 구분한다');
178
+ if (misplacedNewFiles.length) warnings.push('신설: 선언은 제목 둘째 줄에만 둔다');
179
+ for (const path of rawNewFiles) if (!validPath(path)) warnings.push(`신설: ${path || '(빈 항목)'}: 정확한 새 파일 경로가 아니다`);
180
+ for (const path of targets) {
181
+ const objectType = deps.objectTypeAtMain?.(path);
182
+ const exists = objectType ? objectType === 'blob' : deps.existsAtMain(path);
183
+ if (objectType === 'unavailable') warnings.push(`${path}: origin/main Git 조회 실패 · 대상 검증 불가`);
184
+ if (objectType === 'tree' || objectType === 'commit') warnings.push(`${path}: origin/main의 ${objectType === 'tree' ? '디렉터리' : 'gitlink'}는 파일 대상이 아니다`);
185
+ if (objectType === 'blocked-blob' || objectType === 'blocked-gitlink')
186
+ warnings.push(`${path}: origin/main의 상위 ${objectType === 'blocked-blob' ? '파일' : 'gitlink'} 아래에는 신설할 수 없다`);
187
+ if (!exists && !newFiles.has(path)) warnings.push(`${path}: origin/main에 없는 파일 · 신설: 줄에 해당 경로 선언 필요`);
188
+ if (exists && newFiles.has(path)) warnings.push(`${path}: 이미 있는 파일은 신설:에서 뺀다`);
189
+ }
190
+ for (const path of newFiles) if (!targets.includes(path)) warnings.push(`${path}: 신설: 경로가 첫 줄 대상에 없다`);
191
+ for (const path of newFiles) {
192
+ const objectType = deps.objectTypeAtMain?.(path);
193
+ if (objectType === 'unavailable' && !targets.includes(path))
194
+ warnings.push(`${path}: origin/main Git 조회 실패 · 신설 검증 불가`);
195
+ if ((objectType === 'tree' || objectType === 'commit') && !targets.includes(path))
196
+ warnings.push(`${path}: origin/main의 ${objectType === 'tree' ? '디렉터리' : 'gitlink'}는 신설 파일이 아니다`);
197
+ if ((objectType === 'blocked-blob' || objectType === 'blocked-gitlink') && !targets.includes(path))
198
+ warnings.push(`${path}: origin/main의 상위 ${objectType === 'blocked-blob' ? '파일' : 'gitlink'} 아래에는 신설할 수 없다`);
199
+ }
200
+ for (const label of ['코드', '실물', '증거 명령']) {
201
+ if (!lines.some((line) => line.startsWith(`- 완료 경계 ${label}:`) && line.slice(`- 완료 경계 ${label}:`.length).trim()))
202
+ warnings.push(`- 완료 경계 ${label}: 줄이 없다`);
203
+ }
204
+ const real = lines.find((line) => line.startsWith('- 완료 경계 실물:'))?.slice('- 완료 경계 실물:'.length).trim();
205
+ if (real && isMergeOrTypecheckOnlyEvidence(real)) warnings.push(MERGE_OR_TYPECHECK_ONLY_REAL_WARNING);
148
206
  }
149
207
  if (!warnings.length) return { targets, warnings, candidates: [] };
150
208
  const sources = [input.title, input.evidence ?? '', ...(input.refs ?? [])].join('\n');
@@ -302,6 +360,46 @@ export function setItem(v: string, id: string, patch: { status?: ChecklistStatus
302
360
  return setItemGuarded(v, id, patch, by);
303
361
  }
304
362
 
363
+ /** Remove only the exact machine-authored line; preserve all other evidence bytes and blank lines. */
364
+ export function withoutDispatchSkipLine(evidence: string, line: string | null): string {
365
+ if (!line) return evidence;
366
+ if (evidence === line) return '';
367
+ if (evidence.endsWith(`\n${line}`)) return evidence.slice(0, -line.length - 1);
368
+ if (evidence.startsWith(`${line}\n`)) return evidence.slice(line.length + 1);
369
+ return evidence.replace(`\n${line}\n`, '\n');
370
+ }
371
+
372
+ /** Record one dispatcher refusal on the same title snapshot, without overwriting a person's evidence. */
373
+ export function noteDispatchSkip(v: string, id: string, reason: string, expectedTitle: string, by: string): Checklist {
374
+ if (!by.trim()) throw new CliUserError('건너뜀 기록 주체가 비었다');
375
+ const detail = reason.replace(/[\r\n\t]+/g, ' ').trim().slice(0, 300);
376
+ if (!detail) throw new CliUserError('건너뜀 사유가 비었다');
377
+ return mutate(v, (data) => {
378
+ const item = data.items.find((entry) => entry.id === id);
379
+ if (!item) throw new CliUserError(`없는 칸: ${id}`);
380
+ if (item.title !== expectedTitle) throw new CliUserError(`칸 제목이 바뀌어 건너뜀 근거를 기록하지 않았다: ${id}`);
381
+ const marker = createHash('sha256').update(`${v}\0${id}\0${expectedTitle}`).digest('hex').slice(0, 16);
382
+ const line = `디스패처 건너뜀 [${marker}]: ${detail}`;
383
+ const prior = item.evidence ?? '';
384
+ const previous = data.history.filter((entry) => entry.id === id && entry.field === 'dispatch-skip').at(-1)?.to;
385
+ const oldLine = typeof previous === 'string' ? previous : null;
386
+ if (oldLine === line && prior.split(/\r?\n/).includes(line)) return false;
387
+ const priorLines = prior.split('\n');
388
+ const oldIndex = oldLine ? priorLines.findIndex((entry) => entry.replace(/\r$/, '') === oldLine) : -1;
389
+ const next = oldIndex >= 0
390
+ ? priorLines.map((entry, index) => index === oldIndex ? entry.replace(oldLine!, line) : entry).join('\n')
391
+ : prior ? `${prior}\n${line}` : line;
392
+ if (next === prior) return false;
393
+ const at = new Date().toISOString();
394
+ item.evidence = next;
395
+ item.updatedAt = at;
396
+ item.updatedBy = by;
397
+ change(data, id, 'evidence', prior, next, by, at);
398
+ change(data, id, 'dispatch-skip', oldLine, line, by, at);
399
+ return true;
400
+ });
401
+ }
402
+
305
403
  /** Apply a measured verdict only while the release cell is still the snapshot that was judged. */
306
404
  export function setItemIfSnapshot(v: string, id: string, patch: Parameters<typeof setItem>[2], by: string, expected: Pick<ChecklistItem, 'title' | 'status' | 'evidence'>): Checklist {
307
405
  return setItemGuarded(v, id, patch, by, expected);
@@ -8,7 +8,7 @@ import { CliUserError } from '../cli/cli-user-error.js';
8
8
  import { debug } from '../debug/log.js';
9
9
  import { getUserConfig } from '../user-config.js';
10
10
  import { hqSeenGenerationPath, readHqLease, readSeenGeneration } from '../hq/hq.js';
11
- import { devVersion, type Checklist, type ChecklistHistory, type ChecklistItem } from './checklist.js';
11
+ import { devVersion, withoutDispatchSkipLine, type Checklist, type ChecklistHistory, type ChecklistItem } from './checklist.js';
12
12
 
13
13
  export function validateVersion(version: string): void {
14
14
  if (!/^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/.test(version)) throw new CliUserError(`체크리스트 판이 아니다: ${version}`);
@@ -487,7 +487,7 @@ export function move(id: string, from: string, to: string, by: string, released
487
487
  return result;
488
488
  } finally { db.close(); }
489
489
  }
490
- export function retitle(id: string, title: string, by: string, released = releasedVersion(), dev = devVersion()): void {
490
+ export function retitle(id: string, title: string, by: string, released = releasedVersion(), dev = devVersion(), validate?: (item: ChecklistItem, version: string) => void): void {
491
491
  if (!title.trim()) throw new CliUserError('칸 제목이 비었다');
492
492
  importLegacyAll();
493
493
  const db = open();
@@ -500,10 +500,27 @@ export function retitle(id: string, title: string, by: string, released = releas
500
500
  if (!versions.length) throw new CliUserError(`없는 칸: ${id}`);
501
501
  const changed = versions.filter((row) => row.title !== title);
502
502
  if (!changed.length && old.title === title) return false;
503
+ // Retitle changes every assignment for this id. Validate every affected
504
+ // version under the same transaction before the first title write.
505
+ for (const { version } of changed) {
506
+ const item = snapshot(db, version, released, dev).items.find((entry) => entry.id === id);
507
+ if (item) validate?.(item, version);
508
+ }
503
509
  const at = new Date().toISOString();
504
510
  db.query('UPDATE features SET title = ? WHERE id = ?').run(title, id);
505
511
  db.query('UPDATE assignments SET title_override = NULL WHERE feature_id = ?').run(id);
506
512
  for (const { version, title: previousTitle } of changed) {
513
+ const raw = db.query('SELECT evidence FROM assignments WHERE feature_id = ? AND version = ?').get(id, version) as { evidence: string | null };
514
+ const last = db.query('SELECT "to" AS value FROM events WHERE feature_id = ? AND version = ? AND field = ? ORDER BY seq DESC LIMIT 1')
515
+ .get(id, version, 'dispatch-skip') as { value: string | null } | null;
516
+ const managedLine = last?.value ? JSON.parse(last.value) as string | null : null;
517
+ const priorEvidence = raw.evidence ?? '';
518
+ const nextEvidence = withoutDispatchSkipLine(priorEvidence, managedLine);
519
+ if (nextEvidence !== priorEvidence) {
520
+ db.query('UPDATE assignments SET evidence = ? WHERE feature_id = ? AND version = ?').run(nextEvidence || null, id, version);
521
+ record(db, version, { at, by, id, field: 'evidence', from: priorEvidence, to: nextEvidence, released, dev });
522
+ record(db, version, { at, by, id, field: 'dispatch-skip', from: managedLine, to: null, released, dev });
523
+ }
507
524
  db.query('UPDATE assignments SET updated_at = ?, updated_by = ? WHERE feature_id = ? AND version = ?').run(at, by, id, version);
508
525
  record(db, version, { at, by, id, field: 'title', from: previousTitle, to: title, released, dev });
509
526
  }
@@ -23,9 +23,64 @@ export function evidencePlan(rows: readonly LandedButYellowRow[]): Array<{ id: s
23
23
  }));
24
24
  }
25
25
 
26
+ interface PrIndex {
27
+ /** Shape of the list when indexed — a mismatch means the caller changed the array in place. */
28
+ length: number;
29
+ firstNumber: number | undefined;
30
+ lastNumber: number | undefined;
31
+ /** PR positions per body `칸:` line id — the whole-line label the matcher accepts. */
32
+ cellIds: Map<string, number[]>;
33
+ /** PR positions per maximal ASCII-alphanumeric run in the title or body. */
34
+ runs: Map<string, number[]>;
35
+ }
36
+
37
+ const ALNUM_RUN = /[A-Za-z0-9]+/g;
38
+ const CELL_LINE = /^[ \t]*칸(?:[ \t]*:[ \t]*|[ \t]+)([A-Za-z0-9_-]+(?:[ \t]*,[ \t]*[A-Za-z0-9_-]+)*)[ \t]*$/;
39
+ const prIndexes = new WeakMap<readonly MergedChecklistPr[], PrIndex>();
40
+
41
+ function push(map: Map<string, number[]>, key: string, position: number): void {
42
+ const list = map.get(key);
43
+ if (!list) map.set(key, [position]);
44
+ else if (list[list.length - 1] !== position) list.push(position);
45
+ }
46
+
47
+ /**
48
+ * Built once per PR list (the open audit reuses one list across every version). Contract: callers treat the list as
49
+ * read-only after passing it. A cheap guard still re-indexes when the length or the first/last PR number changed;
50
+ * an in-place edit that keeps all three is not detected.
51
+ */
52
+ function prIndex(prs: readonly MergedChecklistPr[]): PrIndex {
53
+ const cached = prIndexes.get(prs);
54
+ if (cached && cached.length === prs.length && cached.firstNumber === prs[0]?.number && cached.lastNumber === prs[prs.length - 1]?.number) return cached;
55
+ const index: PrIndex = { length: prs.length, firstNumber: prs[0]?.number, lastNumber: prs[prs.length - 1]?.number, cellIds: new Map(), runs: new Map() };
56
+ prs.forEach((pr, position) => {
57
+ const body = pr.body ?? '';
58
+ for (const line of body.split('\n')) {
59
+ const match = CELL_LINE.exec(line.endsWith('\r') ? line.slice(0, -1) : line);
60
+ for (const candidate of match?.[1]?.split(',') ?? []) push(index.cellIds, candidate.trim(), position);
61
+ }
62
+ for (const text of [pr.title, body]) for (const [run] of text.matchAll(ALNUM_RUN)) push(index.runs, run, position);
63
+ });
64
+ prIndexes.set(prs, index);
65
+ return index;
66
+ }
67
+
68
+ /**
69
+ * PRs that can match `id` at all — a necessary condition, never a verdict. Every non-cell-line basis needs `id`
70
+ * in the title or body with no ASCII letter/digit on either side, so its leading alphanumeric run appears there
71
+ * as a maximal run. Ids that do not start with a letter or digit fall back to every PR.
72
+ */
73
+ function candidatePositions(index: PrIndex, id: string, total: number): number[] {
74
+ const lead = /^[A-Za-z0-9]+/.exec(id)?.[0];
75
+ if (!lead) return Array.from({ length: total }, (_, position) => position);
76
+ const merged = new Set([...(index.cellIds.get(id) ?? []), ...(index.runs.get(lead) ?? [])]);
77
+ return [...merged].sort((a, b) => a - b);
78
+ }
79
+
26
80
  /** Prefer a dedicated body cell line over title evidence; incidental mentions only qualify for long ids. */
27
81
  export function landedButYellow(items: readonly ChecklistItem[], prs: readonly MergedChecklistPr[], { owner }: { owner?: string } = {}): LandedButYellowRow[] {
28
82
  const rows: LandedButYellowRow[] = [];
83
+ const index = prIndex(prs);
29
84
  for (const item of items) {
30
85
  if (item.status !== 'yellow' && item.status !== 'red') continue;
31
86
  if (owner !== undefined && !ownerMatches(item.owner, owner)) continue;
@@ -37,11 +92,10 @@ export function landedButYellow(items: readonly ChecklistItem[], prs: readonly M
37
92
  : new RegExp(`^${id}(?:\\s|$)`);
38
93
  const explicitTitle = new RegExp(`(?<![A-Za-z0-9])${id}\\s+(?:수확|(?:첫|둘째|셋째)\\s*조각)(?![A-Za-z0-9가-힣])|\\(${id}\\)`);
39
94
  const rank: Record<PrMatchBasis, number> = { 'cell-line': 0, 'title-strong': 1, mention: 2 };
40
- const matched = prs.flatMap((pr) => {
41
- const cellLine = (pr.body ?? '').split('\n').some((line) => {
42
- const match = /^[ \t]*칸(?:[ \t]*:[ \t]*|[ \t]+)([A-Za-z0-9_-]+(?:[ \t]*,[ \t]*[A-Za-z0-9_-]+)*)[ \t]*$/.exec(line.endsWith('\r') ? line.slice(0, -1) : line);
43
- return match?.[1]?.split(',').some((candidate) => candidate.trim() === item.id) ?? false;
44
- });
95
+ const cellLines = new Set(index.cellIds.get(item.id) ?? []);
96
+ const matched = candidatePositions(index, item.id, prs.length).flatMap((position) => {
97
+ const pr = prs[position]!;
98
+ const cellLine = cellLines.has(position);
45
99
  const basis: PrMatchBasis | undefined = cellLine ? 'cell-line'
46
100
  : titleStart.test(pr.title) || explicitTitle.test(pr.title) ? 'title-strong'
47
101
  : !shortId && (word.test(pr.title) || word.test(pr.body ?? '')) ? 'mention' : undefined;
@@ -58,3 +112,73 @@ export function landedButYellow(items: readonly ChecklistItem[], prs: readonly M
58
112
  }
59
113
  return rows.sort((a, b) => Number(b.newer) - Number(a.newer));
60
114
  }
115
+
116
+ export interface MergedPrRunResult { status: number | null; stdout: string; stderr: string }
117
+ /** One `gh` invocation; resolves when the process exits. */
118
+ export type MergedPrRunner = (command: string, args: readonly string[], cwd: string) => Promise<MergedPrRunResult>;
119
+
120
+ export const MERGED_PR_LIMIT = 400;
121
+ /** Concurrent `gh pr list` calls once the first page is full (LANDED-YELLOW-FAST · 10-21 prod: 24 sequential calls ≈ 145s). */
122
+ export const MERGED_PR_CONCURRENCY = 6;
123
+ const DAY_MS = 86_400_000;
124
+
125
+ /**
126
+ * Merged PRs since `since` (UTC date). One call answers when it returns fewer than the cap. Otherwise the range
127
+ * splits into UTC-day windows fetched with a concurrency cap; a full window is halved down to one second as before,
128
+ * and a full one-second window probes one extra row to tell exactly 400 from truncation.
129
+ * The returned set and the truncation flag match the former sequential bisection; only call shape and time differ.
130
+ */
131
+ export async function fetchMergedChecklistPrs(since: string, now: Date, run: MergedPrRunner, cwd: string,
132
+ { concurrency = MERGED_PR_CONCURRENCY }: { concurrency?: number } = {}): Promise<{ prs: MergedChecklistPr[]; truncated: boolean; calls: number }> {
133
+ let calls = 0;
134
+ const fetch = async (lower: string, upper?: string, limit = MERGED_PR_LIMIT): Promise<MergedChecklistPr[]> => {
135
+ const search = `merged:>=${lower}${upper ? ` merged:<${upper}` : ''}`;
136
+ calls++;
137
+ const r = await run('gh', ['pr', 'list', '--state', 'merged', '--search', search, '--limit', String(limit), '--json', 'number,title,body,mergedAt'], cwd);
138
+ if (r.status !== 0) throw new Error(`병합 PR 조회(gh) 실패 rc=${r.status}: ${(r.stderr || r.stdout).trim().slice(0, 400)}`);
139
+ const page = JSON.parse(r.stdout.trim()) as MergedChecklistPr[];
140
+ if (!Array.isArray(page)) throw new Error('병합 PR 조회(gh): 배열이 아니다');
141
+ return page;
142
+ };
143
+ const first = await fetch(since);
144
+ if (first.length < MERGED_PR_LIMIT) return { prs: first, truncated: false, calls };
145
+ // Bounded pool: at most `concurrency` gh processes at once; a failure stops new calls and rejects.
146
+ let active = 0;
147
+ let failed: unknown;
148
+ const waiting: Array<() => void> = [];
149
+ const limited = async <T>(task: () => Promise<T>): Promise<T> => {
150
+ while (active >= Math.max(1, concurrency) && failed === undefined) await new Promise<void>((resolve) => waiting.push(resolve));
151
+ if (failed !== undefined) throw failed;
152
+ active++;
153
+ try { return await task(); }
154
+ catch (error) { failed ??= error; throw error; }
155
+ finally { active--; if (failed !== undefined) for (const wake of waiting.splice(0)) wake(); else waiting.shift()?.(); }
156
+ };
157
+ let truncated = false;
158
+ const visit = async (start: number, end: number): Promise<MergedChecklistPr[]> => {
159
+ const from = new Date(start).toISOString();
160
+ const to = new Date(end).toISOString();
161
+ const page = await limited(() => fetch(from, to));
162
+ if (page.length < MERGED_PR_LIMIT) return page;
163
+ if (end - start <= 1000) {
164
+ // The second-precision search cannot be subdivided; probe one extra row to distinguish exactly 400 from a real truncation.
165
+ const probe = await limited(() => fetch(from, to, MERGED_PR_LIMIT + 1));
166
+ if (probe.length > MERGED_PR_LIMIT) truncated = true;
167
+ return probe.slice(0, MERGED_PR_LIMIT);
168
+ }
169
+ const middle = start + Math.floor((end - start) / 2000) * 1000;
170
+ const [left, right] = await Promise.all([visit(start, middle), visit(middle, end)]);
171
+ return [...left, ...right];
172
+ };
173
+ const lower = Date.parse(`${since}T00:00:00Z`);
174
+ const upper = Math.max(lower + 1000, Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
175
+ const windows: Array<[number, number]> = [];
176
+ for (let start = lower; start < upper; start += DAY_MS) windows.push([start, Math.min(start + DAY_MS, upper)]);
177
+ const settled = await Promise.allSettled(windows.map(([start, end]) => visit(start, end)));
178
+ const rejected = settled.find((result): result is PromiseRejectedResult => result.status === 'rejected');
179
+ if (rejected) throw failed ?? rejected.reason;
180
+ // Chronological window order, first occurrence wins — the same de-duplication as before.
181
+ const unique = new Map<number, MergedChecklistPr>();
182
+ for (const result of settled) for (const pr of (result as PromiseFulfilledResult<MergedChecklistPr[]>).value) if (!unique.has(pr.number)) unique.set(pr.number, pr);
183
+ return { prs: [...unique.values()], truncated, calls };
184
+ }
@@ -209,6 +209,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
209
209
  };
210
210
  const captured: Buffer[] = [];
211
211
  const rc = await (deps.dispatch ?? dispatchHeavyCheck)({
212
+ // Keep the self-gate contract: an unavailable remote leaves this release check unmeasured; do not start a heavy gate locally.
212
213
  tool: 'self-gate', repo: cwd, installPwa: true, refs: [base], json: true, commit: measuredCommit,
213
214
  // The host re-runs this command with --local (and ELANOUS_GATE_REMOTE_CHILD=1), so it never recurses.
214
215
  remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), ...(opts.fixedShardDistribution ? ['--fixed-shard-distribution'] : []), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
@@ -6,7 +6,7 @@ import { resolveRepositoryName } from '../harness/repository-name.js';
6
6
  import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
7
7
  import { effectiveInstanceRoot } from '../instance/resolve.js';
8
8
  import { userConfigPath } from '../user-config.js';
9
- import { addItem, checklistHistory, inspectChecklistTargetPaths, listChecklist, ownerMatches, parseOwner, setItem, validateCeoLoad, type ChecklistItem } from './checklist.js';
9
+ import { addItem, checklistHistory, listChecklist, ownerMatches, parseOwner, setItem, validateCeoLoad, type ChecklistItem } from './checklist.js';
10
10
  import { assignedVersions, move, releasedVersion } from './feature-store.js';
11
11
  import { debug } from '../debug/log.js';
12
12
  import { kstDay, listSchedules, type ReleaseSchedule } from './release-schedule.js';
@@ -455,8 +455,15 @@ export function planPullForward(deps: PullForwardDeps): RebalanceResult {
455
455
  else incomplete.add(item.id);
456
456
  }
457
457
  const targetPathsReady = (title: string): boolean => {
458
- const check = inspectChecklistTargetPaths({ title }, { existsAtMain: deps.targetPathExists });
459
- return check.targets.length > 0 && check.warnings.length === 0;
458
+ const lines = title.split(/\r?\n/);
459
+ const first = /^대상 경로:\s*(.*)$/.exec(lines[0] ?? '');
460
+ if (!first) return false;
461
+ // Pull-forward reads existing cells. Preserve its original path token and
462
+ // second-line 신설: rules; strict authoring has a separate, richer contract.
463
+ const paths = [...first[1]!.matchAll(/(?:^|[^A-Za-z0-9_.\/-])((?:(?:[A-Za-z0-9_.-]+\/)+)?[A-Za-z0-9_.-]+\.(?:ts|tsx|js|jsx|mjs|cjs|json|md|yaml|yml|sh|py|css|html|toml|sql|rs|swift))(?![A-Za-z0-9_.\/-])/g)]
464
+ .map((match) => match[1]!).filter((path) => !path.split('/').includes('..'));
465
+ const legacyNewFile = /^신설:\s*/.test(lines[1] ?? '');
466
+ return paths.length > 0 && paths.every((path) => deps.targetPathExists(path) || legacyNewFile);
460
467
  };
461
468
  const candidates = snapshots.get(source.version)!.filter((item) =>
462
469
  (item.priority === 'P0' || item.priority === 'P1') && item.status !== 'green' && item.status !== 'done'