elanous 0.2.34 → 0.2.36

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 (802) 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/chunks/{abb4b98b.163e0f56e84ae35d.js → 053a429e.9a63436527cc751c.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
  5. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
  11. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
  12. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
  15. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 2683.c9773a0c589b031b.js} +4 -4
  20. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
  21. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 275-02ea4c2a33980422.js} +3 -3
  22. package/apps/pwa/out/_next/static/chunks/{ffdc3a04.b9c23c1b28dd4a96.js → 2812ca6a.3b9f4a7a08885744.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
  26. package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 2986.45d7652e4f13557e.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/{8817.61bb7ffbba502ecb.js → 3136.30aaaa5fa03662a3.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3148-98efd4869d660a87.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{3498.cf2a15a8a9e5b926.js → 3155.2587a55196ecb394.js} +3 -3
  31. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{3103.84470c8445962f04.js → 3324.a09703033abcbd2f.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
  36. package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
  37. package/apps/pwa/out/_next/static/chunks/{3819.163d4777f0a597f6.js → 3538.a445e50bb359d068.js} +2 -2
  38. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
  40. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 3727.7949ccaacaa71242.js} +2 -2
  42. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
  45. package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 4286.b70c4520306817e8.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
  54. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 4615.8525eb0add35eba6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/{3411-f87314c6c66ebc73.js → 5085-bce4904931767ca6.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
  59. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 528.38ce20ef8aa251ff.js} +16 -16
  61. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
  62. package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 552.b7d061ad91eeac51.js} +2 -2
  63. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3837.722e053fb9f321ad.js → 5711.957b095705c12560.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 575.d929793a53f27c4b.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{7562.948255cbc3e79d33.js → 599.c39c571b6733f2a2.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
  71. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/{5446.edf141cff9ef647d.js → 6925.562d532110879886.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 6943.c6b24124853a47b2.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 7481.39f7a4654907bf6e.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 771.c3cdb6c1f7f47c02.js} +16 -16
  92. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 7891.03f910124a737985.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
  100. package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → 873d6c12.09bd499f57171543.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 8904.7d51af2dc033965c.js} +2 -2
  102. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
  104. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +94 -0
  105. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 9250-072df22eaadaa6b5.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
  111. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 9514.131c52cc75fe6439.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/{page-4fb31eb476dcbad3.js → page-083747f1d4518f61.js} +1 -1
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → ceba0382.650712b56b85b582.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/da5ecc5c-b005ad8cac737d57.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
  183. package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
  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/05-authoring-lessons.jsonl +47 -0
  283. package/docs/goal-context/README.md +7 -0
  284. package/graphs/catalog/catalog.yaml +1 -1
  285. package/graphs/default-loop.yaml +63 -4
  286. package/graphs/document-loop.yaml +51 -3
  287. package/graphs/implement-loop.yaml +77 -4
  288. package/graphs/journey/ta-journey.yaml +11 -1
  289. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  290. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  291. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  292. package/graphs/operate-loop.yaml +51 -3
  293. package/graphs/release/recipes.yaml +6 -0
  294. package/graphs/release/release-loop.yaml +17 -4
  295. package/graphs/research-loop.yaml +137 -3
  296. package/graphs/test-diet/test-diet.yaml +3 -0
  297. package/graphs/wizard/recipes.yaml +44 -0
  298. package/graphs/wizard/wizard-loop.yaml +44 -0
  299. package/graphs/work/research-report.yaml +2 -0
  300. package/package.json +1 -1
  301. package/scripts/ci-typecheck-changed.ts +139 -5
  302. package/scripts/coord-role-pack.ts +19 -6
  303. package/scripts/first10-gate.ts +416 -0
  304. package/scripts/fleet/wsl-node-setup.sh +432 -0
  305. package/scripts/hq/standby-snapshot.ts +17 -12
  306. package/scripts/release-loop/docs-land-node.ts +21 -5
  307. package/scripts/release-loop/docs-node.ts +204 -8
  308. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  309. package/scripts/release-loop/gate-node.ts +427 -72
  310. package/scripts/release-loop/gate-partial.ts +65 -11
  311. package/scripts/release-loop/gate-radius-live.ts +177 -0
  312. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  313. package/scripts/release-loop/node-verdict.ts +14 -1
  314. package/scripts/release-loop/npm-publish-node.ts +66 -12
  315. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  316. package/scripts/release-loop/pwa-remote.ts +166 -0
  317. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  318. package/scripts/release-loop/resume-cap.ts +14 -34
  319. package/scripts/release-loop/resume-release.ts +78 -15
  320. package/scripts/release-loop/traffic-node.ts +59 -0
  321. package/scripts/release-loop/traffic-transition.ts +159 -0
  322. package/scripts/release-loop/unattended-release.ts +2 -0
  323. package/scripts/rhythm/daily.ts +137 -3
  324. package/scripts/test-diet/lib.ts +6 -1
  325. package/scripts/test-diet/node.ts +194 -13
  326. package/scripts/ux-sim.ts +92 -0
  327. package/skills/README.md +1 -0
  328. package/src/acp/core-turn-bridge.ts +48 -6
  329. package/src/agent/delegate-hint.ts +16 -0
  330. package/src/agent/runner.ts +82 -2
  331. package/src/agent/self-ambient-cache.ts +8 -0
  332. package/src/agent/task-notification.ts +56 -10
  333. package/src/agent/types.ts +4 -0
  334. package/src/agent-substrate/acp-reviewer.ts +39 -4
  335. package/src/agent-substrate/pr-reviewer.ts +72 -3
  336. package/src/agent-substrate/review-intent.ts +29 -2
  337. package/src/agent-substrate/review-observation.ts +3 -0
  338. package/src/agent-substrate/self-review-cli.ts +229 -28
  339. package/src/autopilot/mission-codebase-gate.ts +141 -12
  340. package/src/autopilot/pr-manager.ts +240 -41
  341. package/src/boot/daemon-tools/self-implement.ts +1 -0
  342. package/src/budget/run-usage-rollup.ts +1 -0
  343. package/src/budget/usage-outcomes.ts +8 -4
  344. package/src/capture/tui-self-report.ts +102 -0
  345. package/src/chat/goal-continue-verdict.ts +41 -0
  346. package/src/chat/index.ts +30 -6
  347. package/src/chat/internal-turn-origin.ts +1 -0
  348. package/src/chat/paste-fold.ts +86 -0
  349. package/src/chat/pickers/modal-runtime.ts +10 -27
  350. package/src/chat/tool-render/block.ts +32 -0
  351. package/src/chat/tool-render/dispatch.ts +2 -20
  352. package/src/chat/tool-render/result-text.ts +98 -0
  353. package/src/chat/turn-typeahead.ts +70 -7
  354. package/src/cli/agent-cli.ts +13 -2
  355. package/src/cli/config-audit.ts +119 -0
  356. package/src/cli/doctor-cli.ts +26 -1
  357. package/src/cli/guardian-cli.ts +10 -0
  358. package/src/cli/herdr-cli.ts +34 -0
  359. package/src/cli/light-entry-route.ts +50 -7
  360. package/src/cli/log-event-names.ts +2 -0
  361. package/src/cli/make-cli.ts +247 -11
  362. package/src/cli/msg-cli.ts +117 -3
  363. package/src/cli/pod-cli.ts +77 -3
  364. package/src/cli/pr-cli.ts +34 -18
  365. package/src/cli/pr-land-base-read.ts +11 -2
  366. package/src/cli/pr-land-heavy-remote.ts +6 -3
  367. package/src/cli/pr-land-overlap-evidence.ts +23 -4
  368. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  369. package/src/cli/pr-land-recovery.ts +117 -1
  370. package/src/cli/pty-takeover-cli.ts +8 -7
  371. package/src/cli/release-checklist-read-cli.ts +79 -0
  372. package/src/cli/release-cli.ts +92 -106
  373. package/src/cli/release-single-flight.ts +1 -1
  374. package/src/cli/remote-resolve.ts +1 -1
  375. package/src/cli/root-tui-entry.ts +48 -0
  376. package/src/cli/sim-cli.ts +22 -0
  377. package/src/cli/tasks-card-show.ts +162 -0
  378. package/src/cli/tasks-cli.ts +1065 -338
  379. package/src/cli/tasks-read-cli.ts +197 -0
  380. package/src/cli/usage-cli.ts +13 -11
  381. package/src/clipboard/history.ts +179 -13
  382. package/src/config.ts +8 -1
  383. package/src/core-turn/run-core-turn.ts +4 -2
  384. package/src/core-turn/run-goal-loop.ts +73 -16
  385. package/src/core-turn/types.ts +6 -1
  386. package/src/dashboard/chat/acp-chat.ts +8 -0
  387. package/src/dashboard/context/keys.ts +8 -31
  388. package/src/dashboard/index.ts +280 -59
  389. package/src/dashboard/input/agent-wake.ts +7 -1
  390. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
  391. package/src/dashboard/input/chat-main-slash-command.ts +4 -2
  392. package/src/dashboard/input/goal-continue.ts +210 -0
  393. package/src/dashboard/input/goal-interim.ts +2 -0
  394. package/src/dashboard/input/internal-turn.ts +2 -8
  395. package/src/dashboard/input/seat-autowake.ts +9 -7
  396. package/src/dashboard/input/turn-autoheal.ts +52 -0
  397. package/src/dashboard/render/theme-resolver.ts +33 -4
  398. package/src/dashboard/seat-boot-preamble.ts +132 -5
  399. package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
  400. package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
  401. package/src/dashboard/slash-runtime/model-choices.ts +15 -0
  402. package/src/dashboard/stale-install-check.ts +3 -99
  403. package/src/debug/batch-queue.ts +119 -0
  404. package/src/debug/tui-log-tag.ts +67 -0
  405. package/src/display/agent-surface.ts +7 -0
  406. package/src/domains/schedule-registry.ts +16 -2
  407. package/src/domains/standalone-log-sink.ts +15 -2
  408. package/src/esc-abort-gate.ts +69 -0
  409. package/src/git-fs/idle-refresh.ts +76 -0
  410. package/src/git-fs/index.ts +18 -7
  411. package/src/git-fs/worktree.ts +137 -5
  412. package/src/graph-kinds/registry.ts +2 -2
  413. package/src/graph-runner/graph-cli.ts +18 -0
  414. package/src/graph-runner/runner.ts +173 -21
  415. package/src/graph-wizard/generate.ts +108 -4
  416. package/src/graph-wizard/steps.ts +15 -0
  417. package/src/grok/credential.ts +10 -3
  418. package/src/grounding/proactive-ground.ts +86 -0
  419. package/src/harness/control-inbox.ts +49 -1
  420. package/src/harness/harness-cli-command.ts +163 -35
  421. package/src/harness/harness-incidents.ts +85 -1
  422. package/src/harness/launch-utterance-ledger.ts +208 -0
  423. package/src/harness/pod-control-send.ts +33 -5
  424. package/src/harness/self-send-remote.ts +69 -0
  425. package/src/harness/self-send-routing-guard.ts +6 -0
  426. package/src/harness/self-send-target.ts +4 -3
  427. package/src/impl-discipline/detector.ts +16 -4
  428. package/src/impl-discipline/system-prompt.ts +11 -0
  429. package/src/impl-discipline/types.ts +2 -2
  430. package/src/index.ts +822 -154
  431. package/src/input-core/context-key-runtime.ts +21 -0
  432. package/src/intake-plane/already-built-hint.ts +4 -2
  433. package/src/intake-plane/requirement-funnel.ts +29 -1
  434. package/src/light-cli.ts +32 -11
  435. package/src/llm/opengateway-models.ts +11 -0
  436. package/src/llm/provider-credentials.ts +14 -0
  437. package/src/llm/provider-detect.ts +8 -1
  438. package/src/llm/runtime-model-family.ts +2 -1
  439. package/src/llm-wellformed.ts +70 -0
  440. package/src/llm.ts +247 -59
  441. package/src/loops/msg-wake.ts +35 -39
  442. package/src/loops/orchestrator/inbox.ts +59 -11
  443. package/src/loops/orchestrator/knowhow-pack.ts +364 -0
  444. package/src/loops/orchestrator/tick.ts +5 -1
  445. package/src/maturity/feature-maturity.ts +1 -1
  446. package/src/model-tier/llm-tier-map.ts +15 -1
  447. package/src/models/prompts.ts +17 -2
  448. package/src/msg/msg-post-office.ts +116 -0
  449. package/src/mss/logging/log-store.ts +79 -22
  450. package/src/native-tool-catalog.ts +15 -1
  451. package/src/nexus/api/decisions-route.ts +38 -18
  452. package/src/nexus/api/graph-wizard-api.ts +20 -2
  453. package/src/nexus/api/loop-resources.ts +13 -1
  454. package/src/nexus/boot/register-mcp-clients.ts +263 -38
  455. package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
  456. package/src/oauth/codex.ts +7 -0
  457. package/src/onboarding/first-run.ts +37 -6
  458. package/src/onboarding/web-first.ts +43 -11
  459. package/src/ops/overview-collect.ts +30 -9
  460. package/src/ops/overview.ts +22 -9
  461. package/src/persona/loader.ts +11 -0
  462. package/src/persona/types.ts +8 -0
  463. package/src/pr-tool/census.ts +261 -27
  464. package/src/prompt-library/session-guidance.ts +14 -0
  465. package/src/provider-summary.ts +8 -0
  466. package/src/pty-shell/herdr-agent-report.ts +118 -9
  467. package/src/pty-shell/herdr-prompt.ts +266 -0
  468. package/src/pty-shell/pty-control-ipc.ts +151 -8
  469. package/src/pty-shell/pty-manifest.ts +7 -0
  470. package/src/pty-shell/pty-special-keys.ts +42 -2
  471. package/src/pty-shell/stale-install-check.ts +99 -0
  472. package/src/pty-shell/tui-run-state.ts +14 -2
  473. package/src/release-loop/auto-start.ts +20 -2
  474. package/src/release-loop/checklist.ts +100 -4
  475. package/src/release-loop/landed-but-yellow.ts +129 -5
  476. package/src/release-loop/light-rc.ts +1 -0
  477. package/src/release-loop/rehearsal.ts +37 -21
  478. package/src/repl/index.ts +192 -17
  479. package/src/repl/ops-msg-bridge.ts +32 -0
  480. package/src/seat-loop/knowhow-lint.ts +1 -1
  481. package/src/self-dev/ask-launch-flow.ts +44 -5
  482. package/src/self-dev/cli-help-text.ts +17 -0
  483. package/src/self-dev/decompose-proposal.ts +172 -20
  484. package/src/self-dev/decompose.ts +61 -0
  485. package/src/self-dev/dev-cli.ts +48 -12
  486. package/src/self-dev/dev-pipeline.ts +8 -2
  487. package/src/self-dev/draft-residue.ts +37 -1
  488. package/src/self-dev/draft-sweep.ts +137 -11
  489. package/src/self-dev/draft-triage-rules.ts +138 -0
  490. package/src/self-dev/fleet-reduce.ts +3 -2
  491. package/src/self-dev/glm-credential-guard.ts +77 -0
  492. package/src/self-dev/graph-front-nodes.ts +112 -0
  493. package/src/self-dev/graph-journey-nodes.ts +2 -0
  494. package/src/self-dev/graph-journey-route.ts +12 -2
  495. package/src/self-dev/harness-run-cli.ts +3 -15
  496. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  497. package/src/self-dev/orchestrate-cli.ts +68 -3
  498. package/src/self-dev/orchestrate.ts +116 -17
  499. package/src/self-dev/review-provider-fallback.ts +35 -1
  500. package/src/self-dev/run-supervisor.ts +55 -2
  501. package/src/self-dev/run-types.ts +1 -1
  502. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  503. package/src/self-dev/shard-aggregate.ts +42 -5
  504. package/src/self-dev/shard-run.ts +8 -1
  505. package/src/self-health/autoheal.ts +153 -0
  506. package/src/self-health/signatures.ts +6 -0
  507. package/src/self-implement/blocked-draft-policy.ts +20 -0
  508. package/src/self-implement/classify-shadow.ts +3 -7
  509. package/src/self-implement/device-first.ts +116 -0
  510. package/src/self-implement/doctor-visit.ts +257 -2
  511. package/src/self-implement/evidence-command-budget.ts +80 -0
  512. package/src/self-implement/gate-baseline.ts +56 -17
  513. package/src/self-implement/gate-cli.ts +1 -0
  514. package/src/self-implement/gate-remote.ts +31 -20
  515. package/src/self-implement/goal-author-cli.ts +1 -0
  516. package/src/self-implement/goal-author-decompose.ts +534 -45
  517. package/src/self-implement/goal-author.ts +282 -7
  518. package/src/self-implement/goal-elaborate.ts +449 -0
  519. package/src/self-implement/goal-refine.ts +273 -0
  520. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  521. package/src/self-implement/graph-variant.ts +40 -6
  522. package/src/self-implement/headless-elanous-driver.ts +19 -3
  523. package/src/self-implement/off-diff-evidence.ts +58 -6
  524. package/src/self-implement/orchestrator.ts +370 -62
  525. package/src/self-implement/pod-warm-pool-profile.ts +1 -0
  526. package/src/self-implement/pwa-import-graph.ts +1 -1
  527. package/src/self-implement/rework-budget-judgment.ts +5 -8
  528. package/src/self-implement/rework-policy.ts +30 -0
  529. package/src/self-implement/run-ledger.ts +108 -0
  530. package/src/self-implement/run-stop.ts +10 -1
  531. package/src/self-implement/run-ttl.ts +38 -24
  532. package/src/self-implement/running-runs.ts +29 -1
  533. package/src/self-implement/scope-adjacency.ts +115 -0
  534. package/src/self-implement/seams.ts +187 -28
  535. package/src/self-implement/stop-autoheal.ts +87 -1
  536. package/src/self-implement/wiring-check.ts +358 -0
  537. package/src/session-runtime/index.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +5 -0
  539. package/src/shell-env-bootstrap.ts +11 -4
  540. package/src/skills/runner.ts +4 -2
  541. package/src/skills/tools/agent.ts +408 -40
  542. package/src/skills/tools/msg-ask.ts +100 -0
  543. package/src/skills/tools/ops-ledger.ts +2 -1
  544. package/src/skills/tools/schedule-wakeup.ts +23 -4
  545. package/src/skills/tools/shell.ts +61 -6
  546. package/src/skills/tools/terminal-modal-inject.ts +1 -2
  547. package/src/skills/tools/terminal-modal.ts +10 -8
  548. package/src/skills/url-router.ts +41 -1
  549. package/src/smart-wizard/run.ts +66 -0
  550. package/src/status/bar.ts +34 -6
  551. package/src/status/status-provider-info.ts +37 -6
  552. package/src/steward/hold-hygiene.ts +24 -6
  553. package/src/steward/rejudge-tick.ts +10 -2
  554. package/src/steward/ta-repair-event-collect.ts +17 -6
  555. package/src/steward/triage-budget.ts +194 -0
  556. package/src/steward/triage.ts +20 -3
  557. package/src/task-agent/actions.ts +72 -2
  558. package/src/task-agent/green-sweep.ts +4 -0
  559. package/src/task-agent/land-queue.ts +21 -8
  560. package/src/task-agent/live-moves.ts +182 -10
  561. package/src/task-agent/mission.ts +30 -0
  562. package/src/task-agent/parent-host.ts +123 -3
  563. package/src/task-agent/rejudge-on-head.ts +15 -0
  564. package/src/task-agent/repair-cycle.ts +138 -32
  565. package/src/task-agent/repair-next-move.ts +31 -3
  566. package/src/task-agent/repair-outcomes.ts +29 -0
  567. package/src/task-agent/repair-worker.ts +14 -4
  568. package/src/task-agent/shadow.ts +48 -4
  569. package/src/task-agent/task-card-prefix.ts +2 -0
  570. package/src/task-agent/task-hand.ts +525 -57
  571. package/src/task-agent/task-parent-role-llm.ts +36 -0
  572. package/src/task-agent/tier-split.ts +196 -0
  573. package/src/task-agent/work-order-build.ts +2 -0
  574. package/src/task-agent/work-order.ts +3 -2
  575. package/src/task-orchestrator/generator-prompt.ts +60 -11
  576. package/src/task-orchestrator/surfaces/pod-account-broker.ts +42 -0
  577. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  578. package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
  579. package/src/task-orchestrator/surfaces/pod-command-job.ts +130 -11
  580. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
  581. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  582. package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
  583. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  584. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +19 -2
  585. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
  586. package/src/task-orchestrator/surfaces/pod-provenance.ts +82 -0
  587. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
  588. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
  589. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
  590. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
  591. package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
  592. package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
  593. package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
  594. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  595. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  596. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  597. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +7 -0
  598. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +521 -40
  599. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
  600. package/src/task-orchestrator/surfaces/self-implement-pod.ts +759 -50
  601. package/src/task-orchestrator/surfaces/self-implement.ts +65 -2
  602. package/src/tool-runtime/index.ts +15 -2
  603. package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
  604. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  605. package/src/tty-foreground.ts +155 -0
  606. package/src/tui/README.md +2 -0
  607. package/src/tui/chat/background-job-status.ts +54 -0
  608. package/src/tui/chat/goal-interim.ts +173 -0
  609. package/src/tui/chat/log-view.ts +267 -0
  610. package/src/tui/chat/self-health-status.ts +232 -0
  611. package/src/tui/entry.ts +695 -0
  612. package/src/tui/input/composer.ts +151 -0
  613. package/src/tui/seat-mail-boot.ts +59 -0
  614. package/src/tui/slash/compact-command.ts +7 -0
  615. package/src/tui/slash/compact.ts +94 -0
  616. package/src/tui/slash/new-session.ts +35 -0
  617. package/src/tui/slash/resume.ts +75 -0
  618. package/src/tui-client/local-chat-turn.ts +282 -0
  619. package/src/tui-client/local-harness-command.ts +63 -0
  620. package/src/tui-client/local-provider-command.ts +184 -0
  621. package/src/tui-client/next-dashboard-runtime.ts +8 -0
  622. package/src/tui-client/next-loop-command.ts +70 -0
  623. package/src/tui-client/next-wakeup.ts +191 -0
  624. package/src/tui.ts +37 -0
  625. package/src/ui/modal-adapter.ts +2 -2
  626. package/src/user-config.ts +4 -2
  627. package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
  628. package/src/ux-sim/cli-config-audit-device.ts +121 -0
  629. package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
  630. package/src/ux-sim/event-monkey.ts +379 -0
  631. package/src/ux-sim/fake-bin.ts +87 -7
  632. package/src/ux-sim/fake-herdr.ts +238 -0
  633. package/src/ux-sim/fake-llm.ts +111 -6
  634. package/src/ux-sim/fault-glm-no-credential.ts +116 -0
  635. package/src/ux-sim/fault-nextmove-dispatch.ts +367 -0
  636. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  637. package/src/ux-sim/fault-scope-escape-lift.ts +216 -0
  638. package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
  639. package/src/ux-sim/goal-device.ts +619 -0
  640. package/src/ux-sim/in-process-cli.ts +22 -5
  641. package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
  642. package/src/ux-sim/mock-authoring-first-run.ts +97 -0
  643. package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
  644. package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
  645. package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
  646. package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
  647. package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
  648. package/src/ux-sim/onboarding-first-run-device.ts +269 -0
  649. package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
  650. package/src/ux-sim/subagent-tools-device.ts +81 -0
  651. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
  652. package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
  653. package/src/version/packed-revision.json +1 -1
  654. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  655. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  658. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  660. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  662. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  663. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/2987-30cf9c2eb7b8bdd5.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  681. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  682. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  683. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  684. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  685. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  688. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  695. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  696. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  708. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  711. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +0 -287
  717. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  722. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  725. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  738. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  740. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  795. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  802. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
@@ -7,16 +7,17 @@
7
7
  * - 기본은 SHADOW: 카드와 명령만 남기고 아무것도 띄우지 않는다. `--live` 일 때만 주입된 launcher 로 띄운다.
8
8
  * - 관측: `debug.log('task-agent', 'handed', {taskId, seat, checklistId, mode, runPriority})`.
9
9
  */
10
- import { execFileSync } from 'node:child_process';
10
+ import { execFile, execFileSync } from 'node:child_process';
11
11
  import { createHash, randomBytes } from 'node:crypto';
12
12
  import { mkdirSync, readFileSync, statSync, writeFileSync, type Stats } from 'node:fs';
13
13
  import { dirname, join, posix, resolve } from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { parse as parseYaml } from 'yaml';
16
- import { validateUnitCalls } from '../graph-runner/runner.js';
16
+ import { runGraph, validateUnitCalls, type GraphRunOptions, type GraphRunState } from '../graph-runner/runner.js';
17
17
  import { parseGraphTemplateYaml } from '../self-implement/graph-yaml.js';
18
18
  import { resolveDaemonHarnessTarget } from '../intake-plane/harness-target.js';
19
19
  import { HARNESS_RUN_ID_ENV, mintRunId, normalizeRunId } from '../harness/harness-space.js';
20
+ import { newLaunchUtteranceId, recordLaunchUtterance } from '../harness/launch-utterance-ledger.js';
20
21
  import { debug } from '../debug/log.js';
21
22
  import { effectiveInstanceRoot } from '../instance/resolve.js';
22
23
  import { withFileLockSync } from '../storage/file-lock.js';
@@ -24,14 +25,19 @@ import { checkCompletionEvidence, deliverableReceiptEvidence } from './completio
24
25
  import { judgeNextMove } from './judge.js';
25
26
  import { checklistDevVersion, listChecklist } from '../release-loop/checklist.js';
26
27
  import { loadRunLedger, runLedgerDir } from '../self-implement/run-ledger.js';
28
+ // Keep doctor-visit recording synchronous: updateTaskCard callers observe it before the transition returns.
29
+ import { recordTaskAgentNeedsOwnerVisit } from '../self-implement/doctor-visit.js';
27
30
  import { applyRunIdentityTag, applyRunIdentityTags, deriveBirthIdentity, parseRunIdentityTag, runIdentityFieldText, runIdentityQueuePriority, runPriorityClass, validateRunIdentity, type RunIdentity, type RunIdentityCell, type RunIdentityOrigin } from './run-identity.js';
28
31
  import { parseWorkOrder, renderWorkOrderGoal, WORK_ORDER_FILE_PATTERN, type WorkOrder } from './work-order.js';
29
32
  import { inspectPrelaunchAlreadyDone, type AlreadyDoneDecision, type AlreadyDoneCandidate,
30
33
  type PrelaunchGitRunnerForTest } from './prelaunch-already-done.js';
31
- import { draftReleaseComment } from '../self-dev/draft-triage-rules.js';
34
+ import { draftClaimComment, draftClaimRecordLive, draftClaimState, draftReleaseComment } from '../self-dev/draft-triage-rules.js';
32
35
  import { parseAskTargetPathHints, parseAskTargetPathHintsResult } from '../self-dev/launch-preflight-text.js';
33
- import { inspectGoalDoneBoundary } from '../self-implement/goal-author.js';
36
+ import { inspectGoalDoneBoundary, linesOutsideFencedCode } from '../self-implement/goal-author.js';
34
37
  import { INFLIGHT_REGISTRY_FILE, registerInflight } from '../pr-tool/inflight-registry.js';
38
+ import { taskParentRoleEnv } from './task-parent-role-llm.js';
39
+ import { runHarvestUnit, type ReviewInvocation } from './harvest-unit.js';
40
+ import { TASK_CARD_PREFIX } from './task-card-prefix.js';
35
41
 
36
42
  export interface ResolveHandTextDeps {
37
43
  cwd: string;
@@ -51,38 +57,35 @@ function missingOrReadFailure(error: unknown): '없다' | '읽기 실패' {
51
57
  return code === 'ENOENT' || code === 'ENOTDIR' ? '없다' : '읽기 실패';
52
58
  }
53
59
 
54
- /**
55
- * TA-WORK-ORDER — `.work-order.json` 골 파일의 내용을 지시서로 검증한다.
56
- * 통과하면 골 문면으로 펼쳐 `work-order` 로, 깨진 JSON·칸 id 없음은 `rejected`(사유) 로 돌린다.
57
- * 관측: `debug.log('task-agent.work-order', 'parsed' | 'rejected', { cellId, unknownFields })`.
58
- */
59
- function resolveWorkOrderFile(content: string, path: string): ResolvedHandText {
60
- const parsed = parseWorkOrder(content);
61
- if (!parsed.ok) {
62
- try { debug.log('task-agent.work-order', 'rejected', { cellId: null, unknownFields: [] }); } catch { /* fail-soft */ }
63
- return { kind: 'rejected', path, reason: parsed.reason };
64
- }
65
- try { debug.log('task-agent.work-order', 'parsed', { cellId: parsed.order.cellId, unknownFields: parsed.order.unknownFields }); } catch { /* fail-soft */ }
66
- return { kind: 'work-order', text: renderWorkOrderGoal(parsed.order), path, order: parsed.order };
67
- }
68
-
69
- /** 파일 판정만 한다. 관측과 카드 작성은 호출자가 결과에 따라 수행한다. */
60
+ /** 파일 판정만 한다. 카드 작성은 호출자가 결과에 따라 수행한다. */
70
61
  export function resolveHandText(text: string, deps: ResolveHandTextDeps = { cwd: process.cwd(), stat: statSync, readFile: readFileSync }): ResolvedHandText {
71
- if (!text || /\s/.test(text)) return { kind: 'unchanged', text };
62
+ const workOrder = WORK_ORDER_FILE_PATTERN.test(text);
63
+ if (!text || (/\s/.test(text) && !workOrder)) return { kind: 'unchanged', text };
72
64
  const path = resolve(deps.cwd, text);
73
65
  const extension = /\.(?:md|markdown|txt)$/i.test(text);
66
+ const reject = (reason: string): ResolvedHandText => {
67
+ if (workOrder) {
68
+ try { debug.log('task-agent.work-order', 'rejected', { cellId: null, unknownFields: [] }); } catch { /* fail-soft */ }
69
+ }
70
+ return { kind: 'rejected', path, reason };
71
+ };
74
72
  let file: Pick<Stats, 'isFile' | 'isDirectory'>;
75
73
  try { file = deps.stat(path); } catch (error) {
76
- if (!extension) return { kind: 'unchanged', text };
77
- return { kind: 'rejected', path, reason: missingOrReadFailure(error) };
74
+ if (!extension && !workOrder) return { kind: 'unchanged', text };
75
+ return reject(missingOrReadFailure(error));
78
76
  }
79
- if (!file.isFile() && !extension && !file.isDirectory()) return { kind: 'unchanged', text };
80
- if (!file.isFile()) return { kind: 'rejected', path, reason: file.isDirectory() ? '디렉터리' : '읽기 실패' };
77
+ if (!file.isFile() && !extension && !workOrder && !file.isDirectory()) return { kind: 'unchanged', text };
78
+ if (!file.isFile()) return reject(file.isDirectory() ? '디렉터리' : '읽기 실패');
81
79
  let content: string;
82
80
  // stat 과 read 사이에 지워지거나 경로가 바뀌어도 사유는 같은 규칙(없다/읽기 실패)으로 가른다.
83
- try { content = deps.readFile(path, 'utf8'); } catch (error) { return { kind: 'rejected', path, reason: missingOrReadFailure(error) }; }
81
+ try { content = deps.readFile(path, 'utf8'); } catch (error) { return reject(missingOrReadFailure(error)); }
84
82
  // TA-WORK-ORDER — 지시서 골 파일은 인라인하지 않고 지시서로 검증해 골 문면으로 펼친다.
85
- if (WORK_ORDER_FILE_PATTERN.test(text)) return resolveWorkOrderFile(content, path);
83
+ if (workOrder) {
84
+ const parsed = parseWorkOrder(content);
85
+ if (!parsed.ok) return reject(parsed.reason);
86
+ try { debug.log('task-agent.work-order', 'parsed', { cellId: parsed.order.cellId, unknownFields: parsed.order.unknownFields }); } catch { /* fail-soft */ }
87
+ return { kind: 'work-order', text: renderWorkOrderGoal(parsed.order), path, order: parsed.order };
88
+ }
86
89
  const carried = content.trim();
87
90
  if (!carried) return { kind: 'rejected', path, reason: '비었다' };
88
91
  return { kind: 'inlined', text: content, path, chars: carried.length, sha256: createHash('sha256').update(carried).digest('hex') };
@@ -90,8 +93,8 @@ export function resolveHandText(text: string, deps: ResolveHandTextDeps = { cwd:
90
93
 
91
94
  export const TASK_SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
92
95
  export type TaskSeat = typeof TASK_SEATS[number];
93
- /** 과제 카드 id 접두 — `task show <id>` 가 이 접두로 TOX 태스크와 갈린다. */
94
- export const TASK_CARD_PREFIX = 'ta-';
96
+ /** 과제 카드 id 접두 — `task show <id>` 가 이 접두로 TOX 태스크와 갈린다(정본 = task-card-prefix.ts). */
97
+ export { TASK_CARD_PREFIX };
95
98
  /** Pod Job 의 metadata.labels 에 붙일 카드 식별자 — 원장의 카드 id 와 정확히 같아야 한다. */
96
99
  export const TASK_CARD_LABEL = 'elanous.task-card';
97
100
  /**
@@ -135,8 +138,11 @@ export interface CompositionSelection {
135
138
  error?: string;
136
139
  }
137
140
 
141
+ /** 조합 저장소 루트(기본) — `graphs/work/<completion>.yaml` 는 이 루트에서 읽는다. */
142
+ export const COMPOSITION_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
143
+
138
144
  /** 1판은 조합을 고르고 단위 해석 결과를 기록한다. 단위 실행은 2판의 몫이다. */
139
- export function selectTaskComposition(completion: CompletionKind, root = join(dirname(fileURLToPath(import.meta.url)), '..', '..')): CompositionSelection {
145
+ export function selectTaskComposition(completion: CompletionKind, root = COMPOSITION_ROOT): CompositionSelection {
140
146
  const file = `graphs/work/${completion}.yaml`;
141
147
  const path = join(root, file);
142
148
  let source: string;
@@ -200,6 +206,9 @@ export interface TaskCardEvent {
200
206
  verdict?: string | null; reviewed?: boolean | null; mustFix?: number | null; reviewRoute?: string | null;
201
207
  /** Exact bytes of the captured review stdout; repair must read the same resultPath and digest. */
202
208
  reviewSha256?: string;
209
+ /** HARNESS-FULL-GRAPH-NEXTMOVE — next-move 결정 순간 만든 수 id(간선·발사와 같은 값). `repair-launched` · `relaunch-launched`(일반 재발사) ·
210
+ * `repair-result`(결과 파일의 값이 카드와 짝지어졌을 때만 · NEXTMOVE-GENERAL-RELAUNCH-MOVEID) 줄에 싣는다. */
211
+ moveId?: string;
203
212
  }
204
213
  /** 카드 history 의 live-move 줄 이벤트 이름 — 상태 사유(«마지막 칸») 판정에서 뺀다. */
205
214
  export const LIVE_MOVE_HISTORY_EVENT = 'live-move';
@@ -264,6 +273,11 @@ export interface TaskCard {
264
273
  goalId?: string;
265
274
  /** `manual` = pr/goalId 를 사람이 적었다(`recordPieceRef`) — 런 묶기가 건드리지 않는다. */
266
275
  refSource?: 'manual';
276
+ /**
277
+ * DRAFT-CLAIM-AUTO-2-FU — 이 손이 그 draft 로 남긴 claim 기록. `body` 는 PR 에 달 «🔧 처리 중» 문면이고
278
+ * claim 이 성립한 손만 갖는다(수확이 머리를 확정하지 못하면 `body` 없이 `harvest` 사유만 남는다).
279
+ */
280
+ draftClaim?: TaskCardDraftClaimRecord;
267
281
  /** 조각 카드만 — ② 가 선행 착지 뒤 넘겼다(한 번만 · 같은 잠금 안에서 먼저 적는다). */
268
282
  handed?: { at: string; mode: 'shadow' | 'live'; claim?: string; error?: string };
269
283
  /**
@@ -303,14 +317,23 @@ export interface TaskCard {
303
317
  taLand?: true;
304
318
  /** TASKS-HAND-CHILD-LLM — `tasks hand --child-llm <provider>/<model> [--child-llm-effort <level>]` → 발사 인자 `--child-llm-provider/-model/-effort`. */
305
319
  childLlm?: TaskChildLlm;
320
+ /** Explicit parent role pins; the implementation child remains controlled by childLlm. */
321
+ parentRoleLlm?: string[];
306
322
  /** Dispatch difficulty, fixed at handoff so repair uses the same judgement. */
307
323
  tier?: '하' | '중' | '상' | '특';
324
+ /**
325
+ * TIER-SPLIT-BEFORE-LAUNCH — 상·특 hand 를 분해해 나온 조각 카드(`tier-split.ts`). group = 같은 hand 에서 나온 조각들의 묶음 id
326
+ * (칸 연결은 `checklistId` 가 그대로 잇는다) · fromTier = 원래 난이도 · unavoidable = 상으로 남은 조각의 불가피 이유.
327
+ */
328
+ tierSplit?: { group: string; fromTier: '상' | '특'; index: number; total: number; unavoidable?: string };
308
329
  /** RUN-IDENTITY-TAGS — 출생 신분 묶음(`run-identity.js` 정본): 칸 우선순위·대표 표시에서 태어나고 `--tag k=v` 가 덮는다. 카드 상태 파일이 원장 정본이다. */
309
330
  identity?: RunIdentity;
310
331
  /** Same-PR repair launches; exact source head and worker result are retained for CAS and retry limits. */
311
332
  repairs?: Array<{ pr: number; head: string; branch: string; at: string; move: string; runId: string;
312
333
  resultPath: string; fromModel: string; toModel: string; status: 'requested' | 'unconfirmed' | 'failed' | 'applied';
313
- detail?: string; commit?: string; bundleSha256?: string; bundlePath?: string }>;
334
+ detail?: string; commit?: string; bundleSha256?: string; bundlePath?: string;
335
+ /** HARNESS-FULL-GRAPH-NEXTMOVE — next-move 결정 순간 만든 수 id. 이 칸 전 원장 줄엔 없다. */
336
+ moveId?: string }>;
314
337
  }
315
338
 
316
339
  /** 구현 자식 LLM 선택 — 하니스 `--child-llm-provider/--child-llm-model/--child-llm-effort` 로 그대로 넘긴다(검증 권위는 하니스). */
@@ -359,14 +382,295 @@ export function abandonedDraftReleaseNote(card: Pick<TaskCard, 'id' | 'status' |
359
382
 
360
383
  /** A uniquely launched code-PR card may own a draft through its PR or its opening run. */
361
384
  export function draftTaskOwner(cards: readonly TaskCard[], draft: { number: number; runId?: string | null }): TaskCard | undefined {
362
- const owners = cards.filter((card) => card.status === 'launched' && (card.completion ?? 'code-pr') === 'code-pr'
385
+ const owners = draftTaskOwners(cards, draft);
386
+ return owners.length === 1 ? owners[0] : undefined;
387
+ }
388
+
389
+ /**
390
+ * DRAFT-CLAIM-AUTO-2-FU — 그 draft 를 쥐고 있다고 말하는 카드 «전부». `draftTaskOwner` 는 이 목록이 한 장일 때만
391
+ * 주인을 돌려주므로, 두 장 이상이면 어느 쪽이 진짜인지 모른다 = 중복 claim.
392
+ */
393
+ export function draftTaskOwners(cards: readonly TaskCard[], draft: { number: number; runId?: string | null }): TaskCard[] {
394
+ return cards.filter((card) => card.status === 'launched' && (card.completion ?? 'code-pr') === 'code-pr'
363
395
  && card.seat && (card.runId || card.runChildId) && (cardPrNumber(card) === draft.number
364
396
  || (draft.runId && (card.runId === draft.runId || card.runChildId === draft.runId))));
365
- return owners.length === 1 ? owners[0] : undefined;
397
+ }
398
+
399
+ /** DRAFT-CLAIM-AUTO-2-FU — 손이 draft 하나를 잡을 때의 «지금» 관측값(라벨·갱신 시각은 호출자가 관측해 넘긴다). */
400
+ export interface HandTaskDraftClaim {
401
+ /** 관측한 draft PR 번호 — 손이 잡으려는 PR. 카드에 묶인 PR 과 같은 번호다. */
402
+ pr: number;
403
+ /** 그 PR 의 지금 라벨(claim·harvestable 판정 입력 · `draftClaimState`). */
404
+ labels: readonly string[];
405
+ /** 그 PR 의 마지막 갱신 시각 — 없으면 만료인지 아닌지 모르므로 claim 하지 않는다. */
406
+ updatedAt?: string;
407
+ /** 그 PR 을 연 런 id(카드 묶기 키 — `draftTaskOwner`). */
408
+ runId?: string | null;
409
+ /** 손 수확 — 리뷰 결과로 머리를 확정한 «뒤에만» claim 한다. */
410
+ harvest?: HandTaskDraftHarvest;
411
+ /** DRAFT-CLAIM-AUTO-2-FU — claim 문면을 «실제 PR 댓글»로 게시하는 포트. 생산 배선(`tasks hand --draft-claim <pr>`)이 gh 게시자를 준다. 없으면 `body` 를 카드에만 남긴다. */
412
+ postComment?: (pr: number, body: string) => Promise<string | undefined>;
413
+ }
414
+
415
+ /**
416
+ * DRAFT-CLAIM-AUTO-2-FU — 손 수확: 그 머리에서 리뷰를 다시 받아 수확이 성립할 때만 claim 한다.
417
+ * 생산 배선(`handDraftClaim`)이 관측한 PR 머리(`expectedHead`) ⊕ 포트의 리뷰 러너(`invokeReview`)로 조립한다.
418
+ */
419
+ export interface HandTaskDraftHarvest {
420
+ /** 리뷰를 요청한 머리(40-hex) — 없거나 지금 머리와 다르면 수확은 성립하지 않는다(claim 0). */
421
+ expectedHead?: string;
422
+ /** 리뷰 의도 문면(없으면 손 문면을 쓴다). */
423
+ reviewIntent?: string;
424
+ /** `elanous self review <pr> --json` 를 부르는 자리 — 호출자(관측 포트)가 준다. */
425
+ invokeReview: (args: { pr: string; intent: string }) => Promise<ReviewInvocation>;
426
+ }
427
+
428
+ /** DRAFT-CLAIM-AUTO-2-FU — 카드에 남는 claim 기록. */
429
+ export interface TaskCardDraftClaimRecord {
430
+ pr: number;
431
+ at: string;
432
+ /** 만료된 claim 을 다시 잡았나(= 재claim). */
433
+ reclaim: boolean;
434
+ /** PR 에 달 «🔧 처리 중» 문면 — claim 이 성립한 손만. */
435
+ body?: string;
436
+ /** shadow 는 게시 예약이 아니므로 live claim 을 막지 않는다. 옛 기록은 live 로 취급한다. */
437
+ mode?: 'shadow' | 'live';
438
+ /** DRAFT-CLAIM-AUTO-2-FU — 게시한 PR 댓글 위치(댓글 url·id · `postComment` 포트가 있는 생산 경로만). */
439
+ postedTo?: string;
440
+ /** 쥐고 있던 카드 id(관측됐을 때). */
441
+ ownerId?: string;
442
+ /** 손 수확 증거 — 머리를 확정하지 못했으면 `outcome`·`reason` 만 있고 `body` 는 없다. */
443
+ harvest?: { outcome: 'done' | 'rework' | 'needs-human' | 'failed'; headCommit?: string; reason?: string };
444
+ }
445
+
446
+ /** DRAFT-CLAIM-AUTO-2-FU — 이 손이 draft 를 잡아도 되나(중복 claim 거부 · 만료된 claim 만 재claim). */
447
+ export type DraftClaimJudgement =
448
+ | { ok: true; body: string; reclaim: boolean; ownerId?: string }
449
+ | { ok: false; reason: string; ownerId?: string };
450
+
451
+ /**
452
+ * DRAFT-CLAIM-AUTO-2-FU — 판정선: ⑴ 두 장 이상의 카드가 같은 draft 를 쥐고 있으면 거부(어느 쪽이 진짜인지 모른다),
453
+ * ⑵ 갱신 시각을 못 읽으면(`unobserved`) 만료인지 알 수 없으니 거부, ⑶ 살아 있는 claim 을 다른 카드가 쥐고 있으면 거부
454
+ * (중복 claim), ⑷ 다른 카드에 남은 «살아 있는» claim 기록(카드 `draftClaim`)이 같은 PR 을 쥐고 있으면 거부 —
455
+ * 연속된 손 호출이 «같은» draft 를 다시 claim 하지 못하게(launched 카드의 PR·런 소유권 가드만으는 부족하다),
456
+ * ⑸ «만료»로 관측된 claim 만 다시 잡는다(재claim 문면).
457
+ */
458
+ export function judgeDraftClaim(input: {
459
+ draft: { number: number; labels: readonly string[]; updatedAt?: string; runId?: string | null };
460
+ cards: readonly TaskCard[];
461
+ cardId: string;
462
+ seat?: TaskSeat;
463
+ now: Date;
464
+ }): DraftClaimJudgement {
465
+ const owners = draftTaskOwners(input.cards, input.draft);
466
+ if (owners.length > 1) {
467
+ return { ok: false, reason: `duplicate-claim: ${owners.map((card) => card.id).join(', ')} 가 같은 PR #${input.draft.number} 를 쥐고 있다` };
468
+ }
469
+ const owner = owners[0];
470
+ const state = draftClaimState(input.draft, input.now);
471
+ if (state === 'unobserved') {
472
+ return { ok: false, ...(owner ? { ownerId: owner.id } : {}), reason: `claim-unobserved: PR #${input.draft.number} 의 claim 시각을 못 읽었다` };
473
+ }
474
+ if (state === 'claimed' && owner?.id !== input.cardId) {
475
+ return {
476
+ ok: false,
477
+ ...(owner ? { ownerId: owner.id } : {}),
478
+ reason: `duplicate-claim: ${owner ? owner.id : '카드 원장 밖 주인'} 가 PR #${input.draft.number} 를 처리 중이다`,
479
+ };
480
+ }
481
+ const recordOwner = input.cards.find((card) => {
482
+ const record = card.draftClaim;
483
+ return card.id !== input.cardId && record !== undefined && record.pr === input.draft.number
484
+ && record.body !== undefined && record.mode !== 'shadow' && draftClaimRecordLive(record.at, input.now);
485
+ });
486
+ if (recordOwner) {
487
+ return { ok: false, ownerId: recordOwner.id, reason: `duplicate-claim: 카드 ${recordOwner.id} 가 PR #${input.draft.number} 의 claim 기록을 쥐고 있다` };
488
+ }
489
+ const reclaim = state === 'expired';
490
+ return {
491
+ ok: true,
492
+ reclaim,
493
+ ...(owner ? { ownerId: owner.id } : {}),
494
+ body: draftClaimComment(input.seat ?? input.cardId, input.now, reclaim ? '만료 claim 재claim — 자동' : undefined),
495
+ };
496
+ }
497
+
498
+ /** DRAFT-CLAIM-AUTO-2-FU — 그 draft 를 이미 다른 카드가 쥐고 있다(또는 만료인지 못 정한다). 이때 카드는 «쓰지 않는다». */
499
+ export class TaskDraftClaimRejectedError extends Error {
500
+ readonly cardId: string;
501
+ readonly reason: string;
502
+ constructor(cardId: string, reason: string) {
503
+ super(`draft claim 거부 (${cardId}): ${reason}`);
504
+ this.name = 'TaskDraftClaimRejectedError';
505
+ this.cardId = cardId;
506
+ this.reason = reason;
507
+ }
508
+ }
509
+
510
+ /**
511
+ * DRAFT-CLAIM-AUTO-2-FU — 손 수확(있으면) → claim 판정을 생산 진입점 안에서 닫는다.
512
+ *
513
+ * ⑴ 수확이 머리를 확정하지 못하면(`needs-human`·`failed`) claim 문면(`body`)을 만들지 않고 사유만 남긴다 —
514
+ * 다른 PR/낡은 머리 리뷰를 이 claim 에 붙이지 않는다. ⑵ 머리를 확정했으면 카드 원장(디스크)의 다른 카드와
515
+ * 견줘 중복·만료를 판정하고, 거부면 던진다(호출자가 카드를 쓰기 «전»에 멈춘다).
516
+ */
517
+ async function resolveHandDraftClaim(input: {
518
+ claim: HandTaskDraftClaim;
519
+ cards: readonly TaskCard[];
520
+ cardId: string;
521
+ seat?: TaskSeat;
522
+ now: Date;
523
+ ask: string;
524
+ }): Promise<TaskCardDraftClaimRecord> {
525
+ const { claim } = input;
526
+ const harvest = claim.harvest ? await runHarvestUnit({
527
+ ask: input.ask,
528
+ context: {
529
+ pr: claim.pr,
530
+ ...(claim.harvest.expectedHead !== undefined ? { expectedHead: claim.harvest.expectedHead } : {}),
531
+ reviewIntent: claim.harvest.reviewIntent ?? input.ask,
532
+ },
533
+ }, claim.harvest.invokeReview) : undefined;
534
+ const reason = harvest
535
+ ? typeof harvest.result.reason === 'string' ? harvest.result.reason
536
+ : typeof harvest.result.error === 'string' ? harvest.result.error : undefined
537
+ : undefined;
538
+ const harvestRecord: TaskCardDraftClaimRecord['harvest'] | undefined = harvest ? {
539
+ outcome: harvest.outcome,
540
+ ...(typeof harvest.result.headCommit === 'string' ? { headCommit: harvest.result.headCommit } : {}),
541
+ ...(reason !== undefined ? { reason } : {}),
542
+ } : undefined;
543
+ const at = input.now.toISOString();
544
+ if (harvest && harvest.outcome !== 'done' && harvest.outcome !== 'rework') {
545
+ try { debug.log('task-agent.draft-claim', 'harvest-unconfirmed', { card: input.cardId, pr: claim.pr, outcome: harvest.outcome, reason: reason ?? null }); } catch { /* fail-soft */ }
546
+ return { pr: claim.pr, at, reclaim: false, ...(harvestRecord ? { harvest: harvestRecord } : {}) };
547
+ }
548
+ const judgement = judgeDraftClaim({
549
+ draft: { number: claim.pr, labels: claim.labels,
550
+ ...(claim.updatedAt !== undefined ? { updatedAt: claim.updatedAt } : {}),
551
+ ...(claim.runId !== undefined ? { runId: claim.runId } : {}) },
552
+ cards: input.cards,
553
+ cardId: input.cardId,
554
+ ...(input.seat !== undefined ? { seat: input.seat } : {}),
555
+ now: input.now,
556
+ });
557
+ if (!judgement.ok) {
558
+ try { debug.log('task-agent.draft-claim', 'rejected', { card: input.cardId, pr: claim.pr, reason: judgement.reason }); } catch { /* fail-soft */ }
559
+ throw new TaskDraftClaimRejectedError(input.cardId, judgement.reason);
560
+ }
561
+ try { debug.log('task-agent.draft-claim', judgement.reclaim ? 'reclaimed' : 'claimed', { card: input.cardId, pr: claim.pr, ownerId: judgement.ownerId ?? null }); } catch { /* fail-soft */ }
562
+ return {
563
+ pr: claim.pr, at, reclaim: judgement.reclaim, body: judgement.body,
564
+ ...(judgement.ownerId !== undefined ? { ownerId: judgement.ownerId } : {}),
565
+ ...(harvestRecord ? { harvest: harvestRecord } : {}),
566
+ };
366
567
  }
367
568
 
368
569
  interface TaskAgentStateFile { tasks?: Record<string, TaskCard>; [key: string]: unknown }
369
570
 
571
+ /**
572
+ * DRAFT-CLAIM-AUTO-2-FU — 손이 draft 를 잡을 때 필요한 관측·게시·수확 리뷰 포트(생산 기본값은 gh CLI ⊕ `elanous self
573
+ * review` 러너 · 시험은 가짜 포트로 몽크). `handDraftClaim` 이 이 포트들로 `draftClaim`(⊕ 손 수확)을 조립한다.
574
+ */
575
+ export interface DraftClaimGhPorts {
576
+ /** PR 을 관측해 라벨·갱신 시각(·런 id)·머리(headRefOid · 손 수확 `expectedHead` 근거)을 읽는다. */
577
+ observePr: (pr: number) => Promise<{ labels: readonly string[]; updatedAt?: string; runId?: string | null; head?: string }>;
578
+ /** PR 댓글을 게시한다 — 게시 위치(댓글 url·id)를 돌려준다. */
579
+ postComment: (pr: number, body: string) => Promise<string | undefined>;
580
+ /**
581
+ * DRAFT-CLAIM-AUTO-2-FU — 손 수확 리뷰 러너: `elanous self review <pr> --json` 관측 원문(stdout·stderr·exitCode)을
582
+ * 돌려준다(판정은 `runHarvestUnit` 몫). 주면 생산 배선이 관측한 PR 머리와 함께 손 수확을 조립한다 — 없으면 수확 없이 claim 한다.
583
+ */
584
+ runReview?: (args: { pr: string; intent: string }) => Promise<ReviewInvocation>;
585
+ }
586
+
587
+ function ghExec(args: readonly string[]): Promise<string> {
588
+ return new Promise((done, fail) => {
589
+ execFile('gh', [...args], { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 }, (error, stdout) => {
590
+ if (error) fail(new Error(`gh ${args.join(' ')} 실패: ${error.message}`));
591
+ else done(String(stdout));
592
+ });
593
+ });
594
+ }
595
+
596
+ /**
597
+ * DRAFT-CLAIM-AUTO-2-FU — 손 수확 리뷰 러너(생산 기본값): 지금 도는 진입점으로 같은 우주의
598
+ * `elanous self review <pr> --json --intent <intent>` 를 «기다려» 관측 원문(stdout·stderr·exitCode)을 돌려준다
599
+ * (argv 는 `liveReviewArgs` 정본 — `defaultRequestReview` 가 떼어 띄우는 것과 같다). 판정·파싱은 `runHarvestUnit` 몫이다.
600
+ */
601
+ export async function defaultDraftClaimReviewRunner(args: { pr: string; intent: string }): Promise<ReviewInvocation> {
602
+ const { ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
603
+ const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
604
+ const { liveReviewArgs } = await import('./live-moves.js');
605
+ const configDir = getElanousConfigDirOverride() ?? effectiveInstanceRoot();
606
+ const argv = liveReviewArgs(ELANOUS_CLI_ENTRY, configDir, Number(args.pr), args.intent);
607
+ return await new Promise<ReviewInvocation>((done) => {
608
+ execFile(process.execPath, argv, { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
609
+ const exitCode = error ? (typeof (error as { code?: unknown }).code === 'number' ? (error as { code: number }).code : 1) : 0;
610
+ done({ stdout: String(stdout), stderr: String(stderr), exitCode });
611
+ });
612
+ });
613
+ }
614
+
615
+ /** 생산 기본 포트 — gh CLI 로 PR 을 관측(라벨·갱신 시각·머리)하고 댓글을 게시하며, 손 수확 리뷰는 같은 우주의 `elanous self review` 러너로 돌린다(자격·원격 저장소는 각 설정을 따른다). */
616
+ export function defaultDraftClaimGhPorts(): DraftClaimGhPorts {
617
+ return {
618
+ async observePr(pr: number) {
619
+ let parsed: Record<string, unknown>;
620
+ try {
621
+ parsed = JSON.parse(await ghExec(['pr', 'view', String(pr), '--json', 'labels,updatedAt,headRefOid'])) as Record<string, unknown>;
622
+ } catch (error) {
623
+ throw new Error(`PR #${pr} 관측 실패(gh pr view): ${error instanceof Error ? error.message : String(error)}`);
624
+ }
625
+ const labels = Array.isArray(parsed.labels) ? parsed.labels
626
+ .map((label) => typeof label === 'string' ? label : (label as { name?: unknown } | null)?.name)
627
+ .filter((name): name is string => typeof name === 'string') : [];
628
+ const updatedAt = typeof parsed.updatedAt === 'string' ? parsed.updatedAt : undefined;
629
+ const head = typeof parsed.headRefOid === 'string' && /^[0-9a-f]{40}$/i.test(parsed.headRefOid) ? parsed.headRefOid : undefined;
630
+ return { labels, ...(updatedAt !== undefined ? { updatedAt } : {}), ...(head !== undefined ? { head } : {}) };
631
+ },
632
+ async postComment(pr: number, body: string) {
633
+ await ghExec(['pr', 'comment', String(pr), '--body', body]);
634
+ return `PR #${pr} 댓글`;
635
+ },
636
+ // DRAFT-CLAIM-AUTO-2-FU — 손 수확 리뷰 러너(생산): handDraftClaim 이 관측한 머리와 함께 조립한다.
637
+ runReview: defaultDraftClaimReviewRunner,
638
+ };
639
+ }
640
+
641
+ /**
642
+ * DRAFT-CLAIM-AUTO-2-FU — 생산 진입점 배선: 관측 포트로 PR 을 읽어 `draftClaim` 을 «조립해» `handTask` 에 넘긴다
643
+ * (`tasks hand --draft-claim <pr>` 가 부른다). 손 수확도 여기서 조립한다 — 관측한 PR 머리(`expectedHead`) ⊕ 포트의
644
+ * 리뷰 러너(`invokeReview` · 생산 기본값 `elanous self review <pr> --json`)로 `runHarvestUnit` 을 거치게 한다.
645
+ * 시험도 이 경로로 돌며 gh·리뷰 포트만 몽크한다 — `draftClaim` 을 직접 주입하지 않는다. 호출자가 직접 준 `harvest`
646
+ * 가 우선(시험 주입)이고 리뷰 러너가 없는 포트는 종전대로 수확 없이 claim 한다(기본 동작 보존).
647
+ */
648
+ export async function handDraftClaim(input: {
649
+ pr: number;
650
+ gh: DraftClaimGhPorts;
651
+ /** DRAFT-CLAIM-AUTO-2-FU — 직접 주는 수확(시험 주입). 안 주면 배선이 관측한 머리 ⊕ 포트의 리뷰 러너로 조립한다. */
652
+ harvest?: HandTaskDraftHarvest;
653
+ } & Omit<Parameters<typeof handTask>[0], 'draftClaim'>): Promise<Awaited<ReturnType<typeof handTask>>> {
654
+ const { pr, gh, harvest, ...handOpts } = input;
655
+ const observed = await gh.observePr(pr);
656
+ // DRAFT-CLAIM-AUTO-2-FU — 손 수확 조립(생산): 관측한 PR 머리(expectedHead) + 포트의 리뷰 러너(invokeReview).
657
+ const handHarvest: HandTaskDraftHarvest | undefined = harvest ?? (gh.runReview === undefined ? undefined : {
658
+ ...(observed.head !== undefined ? { expectedHead: observed.head } : {}),
659
+ invokeReview: gh.runReview,
660
+ });
661
+ return handTask({
662
+ ...handOpts,
663
+ draftClaim: {
664
+ pr,
665
+ labels: observed.labels,
666
+ ...(observed.updatedAt !== undefined ? { updatedAt: observed.updatedAt } : {}),
667
+ ...(observed.runId !== undefined ? { runId: observed.runId } : {}),
668
+ ...(handHarvest !== undefined ? { harvest: handHarvest } : {}),
669
+ postComment: gh.postComment,
670
+ },
671
+ });
672
+ }
673
+
370
674
  function isGitWorkTree(path: string): boolean {
371
675
  try {
372
676
  return execFileSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: path, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() === 'true';
@@ -424,16 +728,35 @@ export function writeTaskCards(path: string, cards: readonly TaskCard[]): void {
424
728
  }
425
729
 
426
730
  /** 카드 하나를 잠금 안에서 읽고 고쳐 쓴다 — `update` 가 undefined 를 돌려주면 쓰지 않는다. 쓴(또는 그대로인) 카드를 돌려준다. */
427
- export function updateTaskCard(path: string, id: string, update: (card: TaskCard | undefined, tasks: Readonly<Record<string, TaskCard>>) => TaskCard | undefined): TaskCard | undefined {
428
- return withFileLockSync(`${path}.lock`, () => {
731
+ export function updateTaskCard(path: string, id: string, update: (card: TaskCard | undefined, tasks: Readonly<Record<string, TaskCard>>) => TaskCard | undefined,
732
+ options: { doctorLedgerDir?: string } = {}): TaskCard | undefined {
733
+ let needsOwner: { runId: string; at: string; reason: string; transitionIndex: number } | undefined;
734
+ const result = withFileLockSync(`${path}.lock`, () => {
429
735
  const disk = readState(path);
430
736
  const current = disk.tasks?.[id];
431
737
  const next = update(current, disk.tasks ?? {});
432
738
  if (!next) return current;
739
+ const transitionIndex = next.history.length - 1;
740
+ const last = next.history[transitionIndex];
741
+ if (current?.status === 'launched' && next.status === 'failed' && next.runId
742
+ && next.history.length > (current?.history.length ?? 0) && last?.event === 'failed'
743
+ && last.detail?.startsWith('failed/needs-owner')) {
744
+ needsOwner = { runId: next.runId, at: last.at, reason: last.detail, transitionIndex };
745
+ }
433
746
  mkdirSync(dirname(path), { recursive: true });
434
747
  writeFileSync(path, JSON.stringify({ ...disk, tasks: { ...(disk.tasks ?? {}), [id]: next } }));
435
748
  return next;
436
749
  });
750
+ if (needsOwner) {
751
+ try {
752
+ const visit = recordTaskAgentNeedsOwnerVisit({ ...needsOwner, cardId: id, dir: options.doctorLedgerDir });
753
+ debug.log('task-agent', 'doctor-visit', { card: id, runId: needsOwner.runId, status: visit.status });
754
+ } catch (error) {
755
+ debug.log('task-agent', 'doctor-visit-failed', { card: id, runId: needsOwner.runId,
756
+ reason: error instanceof Error ? error.message : String(error) });
757
+ }
758
+ }
759
+ return result;
437
760
  }
438
761
 
439
762
  export function readTaskCard(id: string, path = taskAgentStatePath()): TaskCard | undefined {
@@ -577,7 +900,7 @@ export function shellQuote(arg: string): string {
577
900
  }
578
901
 
579
902
  /** 발사기에 넘기는 연결 — env(`ELANOUS_RUN_ID`)를 자식 환경에 얹으면 하니스 런이 `runId` 로 돈다(`resolveRunIdentity` 상속). launchId 는 카드에만 남는 발사 토큰이다. */
580
- export interface TaskLaunchContext { runId: string; launchId: string; env: Record<string, string>; cardLabelContext?: TaskCardLabelContext; substrate?: 'pod'; podGoal?: string; effectiveChildProvider?: string }
903
+ export interface TaskLaunchContext { runId: string; launchId: string; env: Record<string, string>; /** exact untrimmed hand text (launch-utterance ledger pair) */ launchUtterance?: string; cardLabelContext?: TaskCardLabelContext; substrate?: 'pod'; podGoal?: string; effectiveChildProvider?: string }
581
904
  /** 발사기가 «이 런 id 로 띄웠다»고 돌려주는 영수증 — 없으면 카드에 런 id 를 적지 않는다(추측하지 않는다). */
582
905
  export interface TaskLaunchReceipt {
583
906
  runId?: string;
@@ -597,12 +920,19 @@ export interface HandTaskOptions {
597
920
  goal?: string;
598
921
  milestone?: string;
599
922
  live?: boolean;
923
+ /** Production `tasks hand --live` guard; test launchers opt in explicitly. */
924
+ preflightGoalDoneBoundary?: boolean;
600
925
  /** TA-LIVE-LAND-2 — `--ta-land`: card field `taLand` ⊕ launch env `ELANOUS_TA_LAND=1`. */
601
926
  taLand?: boolean;
602
927
  /** TASKS-HAND-CHILD-LLM — `<provider>/<model>`(`parseChildLlm`) ⊕ 선택 추론 노력. effort 만 주면 거부. */
603
928
  childLlm?: string;
604
929
  childLlmEffort?: string;
930
+ parentRoleLlm?: string[];
605
931
  tier?: TaskCard['tier'];
932
+ /** TIER-SPLIT-BEFORE-LAUNCH — 조각 카드에 싣는 분해 연결(`tier-split.ts` 만 준다). */
933
+ tierSplit?: TaskCard['tierSplit'];
934
+ /** TIER-SPLIT-BEFORE-LAUNCH — 분해 실패 사유. 주면 카드를 발사 없이 failed(history `tier-split-failed`)로 남기고 launched:false 로 돌아온다. */
935
+ tierSplitBlocked?: string;
606
936
  /** RUN-IDENTITY-TAGS — `tasks hand --tag k=v`(반복): 출생 신분을 덮는다. 목록 밖 값은 거부한다(`run-identity.js`). */
607
937
  tags?: string[];
608
938
  /** RUN-IDENTITY-TAGS — 칸 읽기 seam(우선순위·대표 표시). 주면 그 답이 최종이다(«칸 없음» 포함). */
@@ -618,6 +948,11 @@ export interface HandTaskOptions {
618
948
  compositionRoot?: string;
619
949
  /** `--live` 일 때만 불린다. */
620
950
  launcher?: TaskLauncher;
951
+ /**
952
+ * 2판 — launcher 'graph-run' 조합을 실제 graph run 으로 발사한다(기본 = src/graph-runner/runner.ts runGraph).
953
+ * 시험은 이 seam 을 주입해 발사 인자(선택된 조합 경로 ⊕ GraphRunOptions)를 'calls' capture 로 검증한다.
954
+ */
955
+ graphRunner?: (path: string, options: GraphRunOptions) => Promise<GraphRunState>;
621
956
  /** Deterministic contract seam; production uses the pinned-main verifier. */
622
957
  prelaunchInspector?: (text: string, projectTarget?: string) => AlreadyDoneDecision;
623
958
  /** Test-only: inject Git calls into the production verifier; no CLI/config surface. */
@@ -631,6 +966,12 @@ export interface HandTaskOptions {
631
966
  landed?: ReadonlySet<string>;
632
967
  /** 카드에 그대로 싣는 칸(② 의 넘김 표지·착지 근거) — handTask 가 카드를 새로 적을 때 지워지지 않게. */
633
968
  cardFields?: Pick<TaskCard, 'pr' | 'goalId' | 'handed'>;
969
+ /**
970
+ * DRAFT-CLAIM-AUTO-2-FU — 손이 잡으려는 draft(PR)의 «지금» 관측값(라벨·갱신 시각·리뷰 러너).
971
+ * 주면 `handTask` 가 손 수확(있으면) → `judgeDraftClaim` 을 거쳐 카드 `draftClaim` 에 기록한다. 거부면
972
+ * 카드를 쓰기 전에 `TaskDraftClaimRejectedError`. 안 주면 종전과 똑같이 claim 을 하지 않는다(기본 동작 보존).
973
+ */
974
+ draftClaim?: HandTaskDraftClaim;
634
975
  /**
635
976
  * 있으면 카드 쓰기마다 잠금 안에서 디스크 카드를 보고 참일 때만 쓴다(② 의 claim 소유 확인).
636
977
  * 거짓이면 쓰지 않고 `TaskCardSupersededError` — 다른 넘김이 그 카드를 가져갔다(발사 전이면 발사하지 않는다).
@@ -679,9 +1020,30 @@ export function dispatchDeliverableCompletion(id: string, input: { ref: string;
679
1020
  return closed;
680
1021
  }
681
1022
 
1023
+ /**
1024
+ * ENTRANCE-EVIDENCE-COMMAND-ONLY — 증거 명령 줄의 «형태» 판정. 기존 TA-HAND-PREFLIGHT 의 계약 줄 «존재» 검사
1025
+ * (`inspectGoalDoneBoundary`)와 구분된다: 세 경계 줄이 이미 갖춰진 골에서 증거 명령 줄의 값이 명령 원문인지만 본다.
1026
+ * 설명 접미(예: `→ 0 fail`)와 백틱 장식은 줄마다 이유를 붙여 거부한다. 빈 값·누락은 존재 검사 몫이다.
1027
+ */
1028
+ const GOAL_EVIDENCE_COMMAND_LINE = /^\s*(?:[-*]\s*)?완료 경계 증거 명령\s*:\s*(.*?)\s*$/;
1029
+ const GOAL_EVIDENCE_COMMAND_DESCRIPTION_SUFFIX = /->|→/;
1030
+ const GOAL_EVIDENCE_COMMAND_BACKTICK_DECORATION = /`/;
1031
+
1032
+ function goalEvidenceCommandFormViolations(document: string): string[] {
1033
+ const violations: string[] = [];
1034
+ for (const line of linesOutsideFencedCode(document)) {
1035
+ const value = GOAL_EVIDENCE_COMMAND_LINE.exec(line.text)?.[1];
1036
+ if (value === undefined || !value.trim()) continue;
1037
+ if (GOAL_EVIDENCE_COMMAND_BACKTICK_DECORATION.test(value)) violations.push(`백틱 장식: ${value}`);
1038
+ else if (GOAL_EVIDENCE_COMMAND_DESCRIPTION_SUFFIX.test(value)) violations.push(`설명 접미: ${value}`);
1039
+ }
1040
+ return violations;
1041
+ }
1042
+
682
1043
  export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
683
1044
  const text = opts.text.trim();
684
1045
  if (!text) throw new Error('과제 한 줄이 비어 있다');
1046
+ const path = opts.statePath ?? taskAgentStatePath();
685
1047
  const targetPathHints = parseAskTargetPathHintsResult(text);
686
1048
  const targetPaths = canonicalTargetPaths(targetPathHints.paths);
687
1049
  if (opts.seat !== undefined && !TASK_SEATS.includes(opts.seat)) throw new Error(`자리는 ${TASK_SEATS.join('|')} 중 하나다: ${opts.seat}`);
@@ -691,6 +1053,7 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
691
1053
  }
692
1054
  if (opts.childLlmEffort !== undefined && opts.childLlm === undefined) throw new Error('--child-llm-effort 는 --child-llm <provider>/<model> 과 함께 준다');
693
1055
  if (opts.tier !== undefined && !['하', '중', '상', '특'].includes(opts.tier)) throw new Error(`--tier 는 하|중|상|특 중 하나다: ${opts.tier}`);
1056
+ const tierSplitBlocked = opts.tierSplitBlocked;
694
1057
  // RUN-IDENTITY-TAGS — 출생 신분: 칸 우선순위(P0 = critical·special·protect · P1 = normal · 그 외 normal)·대표 표시에서 단다.
695
1058
  // `--tag k=v`(반복) 이 덮는다 — 칸·태그 없는 손은 오늘 모양 그대로다(신분 없음). 목록 밖 값은 카드를 적기 전에 거부한다(`run-identity.js` 정본).
696
1059
  const birthCell = opts.checklistId === undefined ? undefined
@@ -709,11 +1072,19 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
709
1072
  launcher: 'hand',
710
1073
  }, birthTags);
711
1074
  const childLlm = opts.childLlm !== undefined ? parseChildLlm(opts.childLlm, opts.childLlmEffort) : undefined;
1075
+ const parentRoleEnv = taskParentRoleEnv(opts.parentRoleLlm ?? []); // validate before writing the card
712
1076
  const completion = opts.completion ?? 'code-pr';
713
1077
  const selected = selectTaskComposition(completion, opts.compositionRoot);
714
- const selectionFailure = !selected.composition ? `조합 없음: graphs/work/${completion}.yaml`
715
- : selected.error ?? (completion !== 'code-pr' || selected.launcher !== 'harness-say'
716
- ? `조합 실행기 없음: ${selected.composition.file} (1판은 code-pr harness-say만 발사)` : undefined);
1078
+ // 2판 — launcher 'graph-run' 조합(단위 해석까지 완료)은 실제 graph run 으로 발사한다. 더 이상 거부하지 않는다.
1079
+ const graphRun = selected.composition && selected.launcher === 'graph-run' && !selected.error && selected.unitsResolved
1080
+ ? selected.composition : undefined;
1081
+ const graphRunPath = graphRun ? join(opts.compositionRoot ?? COMPOSITION_ROOT, graphRun.file) : undefined;
1082
+ const selectionFailure = graphRun ? undefined
1083
+ : !selected.composition ? `조합 없음: graphs/work/${completion}.yaml`
1084
+ : selected.error ?? (selected.launcher === 'graph-run' && !selected.unitsResolved
1085
+ ? `조합 단위 미해석: ${selected.composition.file} — 대상 unit: ${selected.missingUnits.length ? selected.missingUnits.join(', ') : '해석 실패'} (graph-run 발사는 단위 해석이 필요하다)`
1086
+ : completion !== 'code-pr' || selected.launcher !== 'harness-say'
1087
+ ? `조합 실행기 없음: ${selected.composition.file} (발사 가능한 launcher: code-pr harness-say · graph-run)` : undefined);
717
1088
  let project: TaskCard['project'];
718
1089
  let targetIsGit: boolean | null = null;
719
1090
  if (opts.project) {
@@ -732,8 +1103,15 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
732
1103
  const now = (opts.now ?? (() => new Date()))();
733
1104
  const id = opts.id ?? `${TASK_CARD_PREFIX}${now.toISOString().slice(0, 10).replaceAll('-', '')}-${randomBytes(3).toString('hex')}`;
734
1105
  const mode = opts.live ? 'live' : 'shadow';
735
- const path = opts.statePath ?? taskAgentStatePath();
736
- const card: TaskCard = {
1106
+ // DRAFT-CLAIM-AUTO-2-FU — claim 은 카드를 쓰기 «전»에 판정한다(거부면 원장에 아무것도 남기지 않는다).
1107
+ // 견줄 상대는 카드 원장(디스크)의 다른 카드다 — 손이 들고 있는 사본이 아니라 정본을 본다.
1108
+ const draftClaim = opts.draftClaim
1109
+ ? await resolveHandDraftClaim({
1110
+ claim: opts.draftClaim, cards: Object.values(readState(path).tasks ?? {}), cardId: id,
1111
+ ...(opts.seat !== undefined ? { seat: opts.seat } : {}), now, ask: text,
1112
+ })
1113
+ : undefined;
1114
+ let card: TaskCard = {
737
1115
  id, text,
738
1116
  ...(!targetPathHints.labelMissing ? { targetPaths } : {}),
739
1117
  ...(opts.seat ? { seat: opts.seat } : {}),
@@ -748,21 +1126,57 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
748
1126
  ...(opts.milestone ? { milestone: opts.milestone } : {}),
749
1127
  ...(opts.taLand === true ? { taLand: true as const } : {}),
750
1128
  ...(childLlm ? { childLlm } : {}),
1129
+ ...(opts.parentRoleLlm?.length ? { parentRoleLlm: [...opts.parentRoleLlm] } : {}),
751
1130
  ...(opts.tier ? { tier: opts.tier } : {}),
1131
+ ...(opts.tierSplit ? { tierSplit: opts.tierSplit } : {}),
752
1132
  ...(identity ? { identity } : {}),
753
1133
  createdAt: now.toISOString(),
754
- status: selectionFailure ? 'failed' : 'handed',
755
- history: selectionFailure ? [{ at: now.toISOString(), event: !selected.composition ? 'composition-missing'
756
- : selected.error ? 'composition-invalid' : 'composition-launcher-unavailable', detail: selectionFailure }] : [],
1134
+ status: selectionFailure || tierSplitBlocked !== undefined ? 'failed' : 'handed',
1135
+ history: [
1136
+ ...(selectionFailure ? [{ at: now.toISOString(), event: !selected.composition ? 'composition-missing'
1137
+ : selected.error ? 'composition-invalid' : 'composition-launcher-unavailable', detail: selectionFailure }] : []),
1138
+ ...(tierSplitBlocked !== undefined ? [{ at: now.toISOString(), event: 'tier-split-failed', detail: `tier-split-failed: ${tierSplitBlocked}` }] : []),
1139
+ ],
757
1140
  ...(opts.mission ? { mission: opts.mission, after: [...(opts.after ?? [])] } : {}),
758
1141
  ...(opts.cardFields?.pr !== undefined ? { pr: opts.cardFields.pr } : {}),
759
1142
  ...(opts.cardFields?.goalId !== undefined ? { goalId: opts.cardFields.goalId } : {}),
760
1143
  ...(opts.cardFields?.handed !== undefined ? { handed: opts.cardFields.handed } : {}),
1144
+ ...(draftClaim ? { draftClaim } : {}),
761
1145
  };
762
- const move = selectionFailure ? undefined : nextMoveFor(card, opts.landed);
763
- if (move && move.kind !== 'launch') throw new Error(`발사할 수 없는 과제다 — ${move.reason}`);
1146
+ // 2판 graph-run 조합의 다음 수는 실제 graph run — harness say 인자를 조립하지 않는다.
1147
+ const move = graphRun && graphRunPath ? { kind: 'launch' as const, command: ['graph', 'run', graphRunPath], reason: `조합 launcher graph-run — ${graphRun.file}` } satisfies TaskCardMove
1148
+ : selectionFailure ? undefined : nextMoveFor(card, opts.landed);
1149
+ // 분해 실패로 막은 카드는 wait(failed 사유)가 정답이다 — 던지지 않고 카드를 적은 뒤 발사 0 으로 돌아간다.
1150
+ if (move && move.kind !== 'launch' && tierSplitBlocked === undefined) throw new Error(`발사할 수 없는 과제다 — ${move.reason}`);
764
1151
  const guard = opts.writeGuard;
765
1152
  const writeCard = (target: string, next: TaskCard): void => {
1153
+ if (next.draftClaim?.body !== undefined && opts.draftClaim) {
1154
+ let written = false;
1155
+ const saved = updateTaskCard(target, next.id, (current, tasks) => {
1156
+ if (guard && !guard(current)) return undefined;
1157
+ // 같은 파일 잠금 안에서 판정과 기록을 마친다. 댓글은 잠금 밖에서 기록 성공 후 게시한다.
1158
+ const judgement = judgeDraftClaim({
1159
+ draft: { number: opts.draftClaim!.pr, labels: opts.draftClaim!.labels,
1160
+ ...(opts.draftClaim!.updatedAt !== undefined ? { updatedAt: opts.draftClaim!.updatedAt } : {}),
1161
+ ...(opts.draftClaim!.runId !== undefined ? { runId: opts.draftClaim!.runId } : {}) },
1162
+ cards: Object.values(tasks), cardId: next.id,
1163
+ ...(opts.seat !== undefined ? { seat: opts.seat } : {}), now,
1164
+ });
1165
+ if (!judgement.ok) throw new TaskDraftClaimRejectedError(next.id, judgement.reason);
1166
+ written = true;
1167
+ const claim: TaskCardDraftClaimRecord = { ...next.draftClaim!, body: judgement.body, reclaim: judgement.reclaim, mode,
1168
+ ...(judgement.ownerId !== undefined ? { ownerId: judgement.ownerId } : {}) };
1169
+ const { pr: _stalePr, goalId: _staleGoal, refSource: _staleSource, ...base } = next;
1170
+ const evidence = current ?? next;
1171
+ return { ...base, draftClaim: claim,
1172
+ ...(evidence.pr !== undefined ? { pr: evidence.pr } : {}),
1173
+ ...(evidence.goalId !== undefined ? { goalId: evidence.goalId } : {}),
1174
+ ...(evidence.refSource ? { refSource: evidence.refSource } : {}) };
1175
+ });
1176
+ if (!written) throw new TaskCardSupersededError(next.id);
1177
+ if (saved) card = saved;
1178
+ return;
1179
+ }
766
1180
  if (!guard) { writeTaskCards(target, [next]); return; }
767
1181
  const owned = { ok: false };
768
1182
  // 착지 근거(pr·goalId)는 `recordPieceRef` 소유 — claim 뒤에 적힌 최신 근거를 디스크에서 이어 받는다.
@@ -775,6 +1189,20 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
775
1189
  });
776
1190
  if (!owned.ok) throw new TaskCardSupersededError(next.id);
777
1191
  };
1192
+ // Production Pod launches use the remote-parent lint's shared boundary judge.
1193
+ // Injected launchers are test seams and opt in explicitly at the contract test.
1194
+ if (opts.live && opts.preflightGoalDoneBoundary && !selectionFailure && tierSplitBlocked === undefined && move?.kind === 'launch') {
1195
+ readTaskAgentState(path);
1196
+ const { missing } = inspectGoalDoneBoundary(text);
1197
+ if (missing.length > 0) {
1198
+ throw new Error(`goal-revision-required: 완료 경계 누락 ${missing.join(' · ')} — 골 문면에 완료 경계 코드·완료 경계 실물·완료 경계 증거 명령을 적은 뒤 다시 넘기세요`);
1199
+ }
1200
+ // ENTRANCE-EVIDENCE-COMMAND-ONLY — 존재 검사와 구분된 형태 판정: 증거 명령 줄은 명령 원문만 받는다.
1201
+ const formViolations = goalEvidenceCommandFormViolations(text);
1202
+ if (formViolations.length > 0) {
1203
+ throw new Error(`goal-revision-required: 완료 경계 증거 명령은 명령 원문이어야 한다 ${formViolations.join(' · ')} — 증거 명령 줄에 설명 접미(예: → 0 fail)나 백틱 장식을 붙이지 말고 명령만 적은 뒤 다시 넘기세요`);
1204
+ }
1205
+ }
778
1206
  writeCard(path, card);
779
1207
  try { debug.log('task-agent.hand', 'target-paths', { card: id, count: targetPaths.length, labelMissing: targetPathHints.labelMissing }); } catch { /* fail-soft */ }
780
1208
  try { debug.log('task-agent.graph-select', !selected.composition ? 'composition-missing' : selected.error ? 'composition-invalid' : 'composition-selected', {
@@ -782,25 +1210,63 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
782
1210
  unitsResolved: selected.unitsResolved, missingUnits: selected.missingUnits,
783
1211
  ...(selected.error ? { error: selected.error } : {}),
784
1212
  }); } catch { /* fail-soft */ }
1213
+ if (tierSplitBlocked !== undefined) return { card, move: move ?? nextMoveFor(card), mode, launched: false, ...(project ? { cwd: project.target } : {}) };
785
1214
  if (selectionFailure) throw new Error(`${selectionFailure} (카드 ${id})`);
786
1215
  if (!move || move.kind !== 'launch') throw new Error('조합 선택 뒤 발사 수가 없다');
1216
+ if (opts.live && opts.draftClaim?.postComment && card.draftClaim?.body !== undefined) {
1217
+ let postedTo: string | undefined;
1218
+ try {
1219
+ postedTo = await opts.draftClaim.postComment(opts.draftClaim.pr, card.draftClaim.body);
1220
+ } catch (error) {
1221
+ // 댓글이 없으면 «살아 있는» 예약도 남기지 않는다. 다음 손이 다시 claim 할 수 있다.
1222
+ card = updateTaskCard(path, card.id, (current) => current?.draftClaim
1223
+ ? { ...current, draftClaim: { ...current.draftClaim, body: undefined } } : undefined) ?? card;
1224
+ throw error;
1225
+ }
1226
+ if (postedTo !== undefined) {
1227
+ card = updateTaskCard(path, card.id, (current) => current?.draftClaim
1228
+ ? { ...current, draftClaim: { ...current.draftClaim, postedTo } } : undefined) ?? card;
1229
+ }
1230
+ try { debug.log('task-agent.draft-claim', 'comment-posted', { card: id, pr: opts.draftClaim.pr,
1231
+ ...(postedTo !== undefined ? { postedTo } : {}) }); } catch { /* fail-soft */ }
1232
+ }
787
1233
  try { debug.log('task-agent', 'handed', { taskId: id, seat: card.seat ?? null, checklistId: card.checklistId ?? null, mode, projectId: project?.id ?? null, targetIsGit, taLand: card.taLand === true, runPriority: card.identity ? runPriorityClass(card.identity) : null }); } catch { /* fail-soft */ }
788
1234
  if (childLlm) {
789
1235
  try { debug.log('task-agent', 'child-llm', { taskId: id, input: opts.childLlm, provider: childLlm.provider, model: childLlm.model, effort: childLlm.effort ?? null, mode }); } catch { /* fail-soft */ }
790
1236
  }
791
1237
  if (mode === 'shadow') return { card, move, mode, launched: false, ...(project ? { cwd: project.target } : {}) };
792
- if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
793
- if (completion === 'code-pr' && card.checklistId) {
794
- const { missing } = inspectGoalDoneBoundary(text);
795
- if (missing.length > 0) {
796
- const reason = `goal-revision-required: 완료 경계 누락 ${missing.join(' · ')} — 골 문면을 고친 뒤 다시 넘기세요`;
797
- const failed: TaskCard = { ...card, status: 'failed', history: [...card.history,
798
- { at: (opts.now ?? (() => new Date()))().toISOString(), event: 'goal-revision-required', detail: reason }] };
1238
+ // 2판 — launcher 'graph-run' 조합은 launcher(harness say 발사기) 대신 실제 graph run 진입점(runGraph)으로 발사한다.
1239
+ if (graphRun && graphRunPath) {
1240
+ const runId = mintRunId();
1241
+ const launchId = newLaunchUtteranceId();
1242
+ recordLaunchUtterance({ source: 'hand', utterance: opts.text, launchId });
1243
+ let state: GraphRunState;
1244
+ try {
1245
+ state = await (opts.graphRunner ?? runGraph)(graphRunPath, { runId, input: { ask: text }, quiet: true });
1246
+ } catch (error) {
1247
+ // 조합 파일·대상 node가 없으면 runGraph 가 구체 사유로 던진다 — 임의 성공 처리하지 않는다.
1248
+ const reason = `graph run 실패: ${error instanceof Error ? error.message : String(error)}`;
1249
+ const failed: TaskCard = { ...card, status: 'launch-failed', runId, launchId,
1250
+ history: [...card.history, { at: (opts.now ?? (() => new Date()))().toISOString(), event: 'launch-failed', detail: reason, runId }] };
799
1251
  writeCard(path, failed);
800
- try { debug.log('task-agent.hand', 'done-boundary-missing', { taskId: id, checklistId: card.checklistId ?? null, missing, reason }); } catch { /* fail-soft */ }
801
- throw new Error(`${reason} (카드 ${id})`);
1252
+ try { debug.log('task-agent', 'launch-failed', { taskId: id, seat: card.seat ?? null, reason }); } catch { /* fail-soft */ }
1253
+ throw new TaskLaunchError(failed, reason);
802
1254
  }
1255
+ const at = (opts.now ?? (() => new Date()))().toISOString();
1256
+ const ok = state.status === 'done';
1257
+ // 실패 종료도 구체 blocker(종료 상태·이유·마지막 node)를 기록한다 — 임의 성공 처리하지 않는다.
1258
+ const blocker = ok ? undefined : `graph run 종료 상태 ${state.status}${state.reason ? ` — ${state.reason}` : ''}`
1259
+ + `${state.nodes.length ? ` — 마지막 node ${state.nodes.at(-1)?.nodeId} (ok=${state.nodes.at(-1)?.ok})` : ' — node 없음'}`;
1260
+ const launchedGraph: TaskCard = { ...card, status: ok ? 'launched' : 'failed', runId: state.runId, launchId,
1261
+ history: [...card.history,
1262
+ { at, event: 'launch', detail: `graph run ${graphRunPath} (run ${state.runId})` },
1263
+ { at, event: 'run-bound', detail: state.runId, runId: state.runId },
1264
+ ...(blocker ? [{ at, event: 'graph-run-failed', detail: blocker, runId: state.runId }] : [])] };
1265
+ writeCard(path, launchedGraph);
1266
+ try { debug.log('task-agent', 'launched', { taskId: id, seat: card.seat ?? null, runId: state.runId }); } catch { /* fail-soft */ }
1267
+ return { card: launchedGraph, move, mode, launched: true, ...(project ? { cwd: project.target } : {}) };
803
1268
  }
1269
+ if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
804
1270
  let prelaunch: AlreadyDoneDecision;
805
1271
  try { prelaunch = completion === 'code-pr'
806
1272
  ? (opts.prelaunchInspector ?? ((input, target) => inspectPrelaunchAlreadyDone(input, target,
@@ -817,8 +1283,10 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
817
1283
  return { card: candidate, move: nextMoveFor(candidate), mode, launched: false, ...(project ? { cwd: project.target } : {}) };
818
1284
  }
819
1285
  const runId = mintRunId();
820
- const launchId = `tl-${randomBytes(6).toString('hex')}`;
821
- const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
1286
+ const launchId = newLaunchUtteranceId();
1287
+ recordLaunchUtterance({ source: 'hand', utterance: opts.text, launchId });
1288
+ const context: TaskLaunchContext = { runId, launchId, launchUtterance: opts.text, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
1289
+ ...parentRoleEnv,
822
1290
  ...(cardPrNumber(card) ? { ELANOUS_TASK_BOUND_PR: String(cardPrNumber(card)) } : {}),
823
1291
  ...(card.checklistId ? { ELANOUS_POD_SLOT_ID: card.checklistId } : {}),
824
1292
  ...(card.seat ? { ELANOUS_POD_OWNER_KIND: 'seat', ELANOUS_POD_OWNER_ID: card.seat } : {}),