elanous 0.2.22 → 0.2.24
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.
- package/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-c0ab229673a8b0eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b92caddb5c715f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +24 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +24 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/package.json +4 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +80 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +335 -33
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +40 -4
- package/scripts/release-loop/resume.ts +94 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +29 -7
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/tsc-baseline-cache.ts +147 -0
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +64 -8
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +20 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +19 -4
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +41 -7
- package/src/agent-substrate/acp-implementer.ts +139 -0
- package/src/agent-substrate/acp-reviewer.ts +17 -8
- package/src/agent-substrate/pr-reviewer.ts +191 -28
- package/src/agent-substrate/review-intent.ts +6 -4
- package/src/agent-substrate/self-review-cli.ts +155 -21
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +216 -12
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/pr-manager.ts +12 -3
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +21 -13
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/types.ts +8 -2
- package/src/budget/unified-usage.ts +88 -6
- package/src/chat/index.ts +12 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/brief-cli.ts +27 -21
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/log-event-names.ts +7 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +90 -5
- package/src/cli/pr-land-overlap-evidence.ts +279 -0
- package/src/cli/release-cli.ts +63 -12
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/self-update.ts +277 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -30
- package/src/cli/usage-cli.ts +91 -8
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +13 -2
- package/src/context-bus/long-term-memory.ts +3 -1
- package/src/context-bus/nightly-condense.ts +3 -2
- package/src/core-turn/run-goal-loop.ts +87 -2
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +45 -281
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
- package/src/dashboard/stale-install-check.ts +24 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +190 -0
- package/src/debug/log.ts +70 -17
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-tool.ts +27 -0
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/outbound-alert.ts +17 -6
- package/src/domains/release-tool.ts +158 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/error-report/report.ts +21 -4
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +2 -0
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +218 -8
- package/src/grok/usage.ts +23 -2
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +267 -0
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +229 -35
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-stop.ts +4 -2
- package/src/harness/harness-substrate-default.ts +214 -8
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +133 -21
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +250 -69
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +113 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +248 -0
- package/src/llm/bedrock.ts +491 -0
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +383 -41
- package/src/loops/budget.ts +150 -0
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/traffic.ts +5 -81
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -2
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +52 -4
- package/src/models/prompts.ts +23 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +262 -26
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/http-server.ts +8 -0
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +17 -75
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +55 -20
- package/src/oauth/codex-account-store.ts +451 -23
- package/src/oauth/fallback-chain.ts +75 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/onboarding.ts +2 -1
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/plugin-maker.ts +25 -20
- package/src/plugins/maker/wizard-generate.ts +16 -2
- package/src/policy/llm-policy.ts +14 -1
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +13 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +69 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist.ts +24 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +107 -23
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +26 -12
- package/src/seat-loop/seat-loop.ts +66 -11
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +109 -11
- package/src/self-dev/dev-pipeline.ts +11 -8
- package/src/self-dev/draft-residue.ts +475 -0
- package/src/self-dev/draft-sweep.ts +254 -10
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +82 -5
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +49 -141
- package/src/self-dev/review-provider-fallback.ts +115 -19
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +190 -36
- package/src/self-dev/run-types.ts +191 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +3 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +48 -13
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +32 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/host-regate.ts +120 -29
- package/src/self-implement/l8-merge-queue.ts +67 -5
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +271 -25
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/seams.ts +83 -4
- package/src/self-implement/self-implement-cli.ts +12 -5
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +22 -10
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +87 -24
- package/src/storage/file-lock.ts +8 -1
- package/src/task-agent/actions.ts +66 -5
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +101 -3
- package/src/task-agent/judge.ts +20 -3
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +219 -0
- package/src/task-agent/live-moves.ts +451 -34
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +352 -0
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +154 -14
- package/src/task-agent/task-hand.ts +186 -14
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +42 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +94 -7
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +110 -17
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +32 -3
- package/src/task-orchestrator/surfaces/pod-pool.ts +86 -18
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +463 -50
- package/src/task-orchestrator/surfaces/self-implement.ts +25 -3
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +180 -32
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
- /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
|
@@ -3,21 +3,33 @@
|
|
|
3
3
|
*
|
|
4
4
|
* - `review`: 수확 가능 런의 PR 에 elanous 리뷰를 «한 번» 요청한다 — PR 머리(sha)마다 한 번(카드 `reviewRequests` 이력).
|
|
5
5
|
* 요청만 한다: 결과로 착지·재발사로 잇지 않는다(실행부 `executeNextAction` 의 review→land 사슬을 타지 않는다).
|
|
6
|
+
* TA-REVIEW-RESULT-CAPTURE — 자식 stdout(`--json`)은 결과 파일로 받고, 회수(`review-result-capture.ts`)는 «다음» 판단 틱이 한다 —
|
|
7
|
+
* 회수한 pass 는 그 틱의 판단부·land 관문 입력(`selfReview`)이 될 뿐 land 판정 로직은 그대로다.
|
|
6
8
|
* - `propose-green`: 카드에 green «제안»(`greenProposal`)만 적는다 — 체크리스트는 손대지 않는다.
|
|
7
|
-
* - `propose-land`: 카드·현재 머리의 self review pass·non-draft 를 확인하고 기존 `pr land` 를 머리 고정으로 한 번 부른다.
|
|
9
|
+
* - `propose-land`: 카드·현재 머리의 self review 통과(pass «또는» warn ⊕ must-fix 0 · TA-LAND-WARN-MUSTFIX0)·non-draft 를 확인하고 기존 `pr land` 를 머리 고정으로 한 번 부른다.
|
|
10
|
+
* - 사다리 R4: `narrow-relaunch` · `wait-retry` · `salvage-relaunch` · `alternative` 도 허용 목록 어휘다 — 실제 발사는 실행부
|
|
11
|
+
* `executeNextAction`(`actions.ts`)이 «목록 ⊕ 같은 수 2회 상한 ⊕ 회당 1건 ⊕ 부하 관문»을 모두 넘을 때만 한다.
|
|
12
|
+
* - `decision-card`: 막힌 과제를 «근거(서명 · 화면 · must-fix)» 붙은 결정 카드로 올린다 — 근거가 하나도 없으면 카드를 올리지 않는다.
|
|
13
|
+
* 카드는 종전 실행부와 같은 `decisions raise` 모양이라 OP 거르기(`seat-loop/op-decide.ts`)가 그대로 본다 · 같은 근거는 카드 history 로 한 번만.
|
|
8
14
|
* - 설정 `taskAgent.liveMoves`(config > env `ELANOUS_TASK_AGENT_LIVE_MOVES` > 없음). 모르는 항목은 경고하고 버린다.
|
|
9
15
|
* - 관측: 실행한 수마다 `debug.log('task-agent', 'live-move', {kind, card, ok, detail, live:true})`.
|
|
10
16
|
*/
|
|
11
17
|
import { spawn, spawnSync } from 'node:child_process';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
import { closeSync, mkdirSync, openSync, readFileSync, statSync } from 'node:fs';
|
|
20
|
+
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
14
21
|
import { debug } from '../debug/log.js';
|
|
15
22
|
import { findGitDir } from '../git-fs/locate.js';
|
|
16
|
-
import { getUserConfig } from '../user-config.js';
|
|
23
|
+
import { getUserConfig, userConfigPath } from '../user-config.js';
|
|
17
24
|
import type { DetachedSpawn } from '../cli/tasks-cli.js';
|
|
18
|
-
import { taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
|
|
25
|
+
import { LIVE_MOVE_HISTORY_EVENT, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
|
|
26
|
+
import { LIVE_RETRY_MOVES } from './judge.js';
|
|
27
|
+
import { decisionCardGrounds, decisionRaiseArgs, type DecisionCardEvidence, type NextAction } from './actions.js';
|
|
28
|
+
import { reviewResultPath } from './review-result-capture.js';
|
|
29
|
+
import { buildPriorFixContext, PRIOR_FIX_SCOPE_LINE, priorFixBlock, priorFixObservation, type PriorDiffReader, type PriorFixContext } from './review-prior-fix.js';
|
|
30
|
+
import { createLandWorktree, localHead, observeLandWorktree, type LandWorktree, type LandWorktreeFailure, type LandWorktreeInput, type LandWorktreeRemoval } from './land-worktree.js';
|
|
19
31
|
|
|
20
|
-
export const TASK_AGENT_LIVE_MOVES = ['review', 'propose-green', 'propose-land'] as const;
|
|
32
|
+
export const TASK_AGENT_LIVE_MOVES = ['review', 'propose-green', 'propose-land', 'decision-card', ...LIVE_RETRY_MOVES] as const;
|
|
21
33
|
export type TaskAgentLiveMove = typeof TASK_AGENT_LIVE_MOVES[number];
|
|
22
34
|
export const TASK_AGENT_LIVE_MOVES_ENV = 'ELANOUS_TASK_AGENT_LIVE_MOVES';
|
|
23
35
|
|
|
@@ -61,13 +73,23 @@ export interface LiveMoveDeps {
|
|
|
61
73
|
prHead?: (pr: number, cwd?: string) => Promise<PrHeadView | null>;
|
|
62
74
|
/** TA-LIVE-REVIEW-POD — 작업 트리가 없는 런(Pod)의 리뷰 저장소 후보. 기본은 카드 project.target → harness.defaultRepo → 호스트 checkout. */
|
|
63
75
|
repoCandidates?: (card: TaskCard) => readonly ReviewRepoCandidate[];
|
|
64
|
-
/**
|
|
65
|
-
|
|
76
|
+
/**
|
|
77
|
+
* 리뷰 요청(떼어 띄운다) — 시험은 반드시 주입한다.
|
|
78
|
+
* TA-REVIEW-RESULT-CAPTURE — `capture.resultPath` 가 오면 자식 `--json` stdout 을 그 파일로 받는다(회수 = `review-result-capture.ts`).
|
|
79
|
+
*/
|
|
80
|
+
requestReview?: (pr: number, intent: string, cwd?: string, capture?: { resultPath: string }) => Promise<void>;
|
|
81
|
+
/** REVIEW-CONVERGE-PRIOR-FIX — 같은 PR 재리뷰의 직전 머리 → 지금 머리 diff(시험 주입 · 기본 = `git diff --numstat`). */
|
|
82
|
+
priorDiff?: PriorDiffReader;
|
|
66
83
|
/** Fresh PR head and draft flag for landing; separate from the unchanged review lookup. */
|
|
67
84
|
landPrHead?: (pr: number, cwd: string) => Promise<(PrHeadView & { isDraft: boolean }) | null>;
|
|
68
85
|
/** One existing pr land operation; inject in tests instead of invoking the CLI. */
|
|
69
|
-
|
|
86
|
+
/** TA-REJUDGE-ON-HEAD — `opts.overlapEvidence` 가 있으면 `pr land --overlap-evidence <file>` 로 넘긴다(없으면 종전 인자). */
|
|
87
|
+
land?: (pr: number, head: string, cwd: string, opts?: { overlapEvidence?: string }) => Promise<{ status: number; stdout: string; stderr?: string }>;
|
|
88
|
+
/** `decision-card` — `decisions raise` 한 번(시험 주입 · 기본 = 같은 우주의 CLI 자식). */
|
|
89
|
+
raiseDecision?: (args: string[]) => Promise<{ status: number; stdout: string; stderr?: string }>;
|
|
70
90
|
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
91
|
+
/** TA-LAND-WORKTREE — cwd HEAD 읽기 · PR 머리 임시 워크트리 만들기(시험 주입 · 기본 = git). */
|
|
92
|
+
landWorktree?: { localHead?: (cwd: string) => string | null; create?: (input: LandWorktreeInput) => Promise<LandWorktree | LandWorktreeFailure> };
|
|
71
93
|
}
|
|
72
94
|
|
|
73
95
|
/** `executed` = 부작용을 실제로 냈다(리뷰를 띄웠다 · 제안을 적었다). ok 이지만 이미 한 수(같은 머리·이미 제안)면 false. */
|
|
@@ -75,6 +97,10 @@ export interface LiveMoveResult {
|
|
|
75
97
|
kind: TaskAgentLiveMove | 'land'; card: string | null; ok: boolean; executed: boolean; detail: string;
|
|
76
98
|
/** TA-LIVE-REVIEW-POD — 작업 트리 없이 리뷰 저장소를 찾았을 때(또는 못 찾았을 때)의 근거 한 줄. */
|
|
77
99
|
reviewRepo?: { resolved: boolean; source?: ReviewRepoCandidate['source']; cwd?: string; proof?: 'head-sha' | 'branch'; reason: string };
|
|
100
|
+
/** TA-REVIEW-RESULT-CAPTURE — 띄운 review 의 결과 파일(자식 stdout) — 실행한 review 에만 실린다. */
|
|
101
|
+
resultPath?: string;
|
|
102
|
+
/** TA-LAND-RETRY-ON-INFRA — 실행한 land 의 그 머리 몇 번째 시도인가 · 실패면 갈래(infra|judgement|base-stale)·사유·재시도 가능 여부. */
|
|
103
|
+
landAttempt?: { attempt: number; class?: LandFailureClass; reason?: string; retryAllowed?: boolean };
|
|
78
104
|
}
|
|
79
105
|
|
|
80
106
|
export interface PrHeadView { head: string; state: string; branch?: string; url?: string }
|
|
@@ -178,26 +204,49 @@ export function liveReviewArgs(entry: string, configDir: string, pr: number, int
|
|
|
178
204
|
|
|
179
205
|
/**
|
|
180
206
|
* 지금 도는 진입점으로 같은 우주의 리뷰를 떼어 띄운다 — 기다리지 않는다(결과는 self review 자기 관측에 남는다).
|
|
207
|
+
* TA-REVIEW-RESULT-CAPTURE — `resultPath` 가 있으면 자식 stdout(`--json` 결과)만 그 파일로 받는다(stdin·stderr 는 종전대로 버린다 ·
|
|
208
|
+
* 파이프가 아니라 파일 — 부모가 먼저 끝나도 자식이 EPIPE 로 죽지 않는다). 없으면 종전과 같다(stdio ignore).
|
|
181
209
|
* `opts` 는 시험 몫(spawn·진입점·우주) — 기본은 실물.
|
|
182
210
|
*/
|
|
183
|
-
export async function defaultRequestReview(pr: number, intent: string, cwd?: string, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string } = {}): Promise<void> {
|
|
211
|
+
export async function defaultRequestReview(pr: number, intent: string, cwd?: string, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string; resultPath?: string } = {}): Promise<void> {
|
|
184
212
|
const { spawnDetachedConfirmed, ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
|
|
185
213
|
const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
|
|
186
214
|
const { effectiveInstanceRoot } = await import('../instance/resolve.js');
|
|
187
215
|
const configDir = opts.configDir ?? getElanousConfigDirOverride() ?? effectiveInstanceRoot();
|
|
188
|
-
|
|
216
|
+
const base = opts.spawn ?? (spawn as unknown as DetachedSpawn);
|
|
217
|
+
const args = liveReviewArgs(opts.entry ?? ELANOUS_CLI_ENTRY, configDir, pr, intent);
|
|
218
|
+
if (!opts.resultPath) { await spawnDetachedConfirmed(base, process.execPath, args, undefined, cwd); return; }
|
|
219
|
+
let fd: number;
|
|
220
|
+
try {
|
|
221
|
+
mkdirSync(dirname(opts.resultPath), { recursive: true });
|
|
222
|
+
fd = openSync(opts.resultPath, 'w');
|
|
223
|
+
} catch (error) {
|
|
224
|
+
// 결과 파일을 못 열어도 리뷰는 막지 않는다(종전처럼 stdio ignore) — 회수는 상한 뒤 «no result» 줄로 드러난다.
|
|
225
|
+
try { debug.log('task-agent', 'review-result-file-open-failed', { pr, resultPath: opts.resultPath, reason: (error instanceof Error ? error.message : String(error)).slice(-300) }, { level: 'warn' }); } catch { /* fail-soft */ }
|
|
226
|
+
await spawnDetachedConfirmed(base, process.execPath, args, undefined, cwd);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const toFile: DetachedSpawn = (command, spawnArgs, options) =>
|
|
230
|
+
(base as unknown as (c: string, a: string[], o: unknown) => ReturnType<DetachedSpawn>)(command, spawnArgs, { ...options, stdio: ['ignore', fd, 'ignore'] });
|
|
231
|
+
try {
|
|
232
|
+
await spawnDetachedConfirmed(toFile, process.execPath, args, undefined, cwd);
|
|
233
|
+
} finally {
|
|
234
|
+
try { closeSync(fd); } catch { /* the child keeps its own copy */ }
|
|
235
|
+
}
|
|
189
236
|
}
|
|
190
237
|
|
|
191
|
-
export function liveLandArgs(entry: string, configDir: string, pr: number, head: string, cwd: string): string[] {
|
|
192
|
-
return [resolve(entry), '--config-dir', configDir, 'pr', 'land', '--cwd', cwd, '--pr', String(pr), '--expected-head', head
|
|
238
|
+
export function liveLandArgs(entry: string, configDir: string, pr: number, head: string, cwd: string, overlapEvidence?: string): string[] {
|
|
239
|
+
return [resolve(entry), '--config-dir', configDir, 'pr', 'land', '--cwd', cwd, '--pr', String(pr), '--expected-head', head,
|
|
240
|
+
// TA-REJUDGE-ON-HEAD — 겹침 관문의 비대화형 증거(#26023) · 없으면 종전 인자 그대로.
|
|
241
|
+
...(overlapEvidence ? ['--overlap-evidence', overlapEvidence] : [])];
|
|
193
242
|
}
|
|
194
243
|
|
|
195
244
|
/** The CLI owns the freeze, gate and merge checks; no direct gh merge or bypass flags. */
|
|
196
|
-
export async function defaultLand(pr: number, head: string, cwd: string): Promise<{ status: number; stdout: string; stderr?: string }> {
|
|
245
|
+
export async function defaultLand(pr: number, head: string, cwd: string, opts: { overlapEvidence?: string } = {}): Promise<{ status: number; stdout: string; stderr?: string }> {
|
|
197
246
|
const { ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
|
|
198
247
|
const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
|
|
199
248
|
const { effectiveInstanceRoot } = await import('../instance/resolve.js');
|
|
200
|
-
const args = liveLandArgs(ELANOUS_CLI_ENTRY, getElanousConfigDirOverride() ?? effectiveInstanceRoot(), pr, head, cwd);
|
|
249
|
+
const args = liveLandArgs(ELANOUS_CLI_ENTRY, getElanousConfigDirOverride() ?? effectiveInstanceRoot(), pr, head, cwd, opts.overlapEvidence);
|
|
201
250
|
return new Promise((resolveResult, reject) => {
|
|
202
251
|
const child = spawn(process.execPath, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
203
252
|
let stdout = '';
|
|
@@ -207,11 +256,13 @@ export async function defaultLand(pr: number, head: string, cwd: string): Promis
|
|
|
207
256
|
child.once('error', reject);
|
|
208
257
|
child.once('close', (code) => {
|
|
209
258
|
if (code !== 0) { resolveResult({ status: code ?? 1, stdout, stderr }); return; }
|
|
259
|
+
// TA-LAND-RETRY-ON-INFRA — 왜 미확인인지 «마지막 줄»로 가른다(꼬리 300자에서도 남게): 못 읽음 = 인프라 · 읽었는데 MERGED 아님 = 판정.
|
|
260
|
+
const unconfirmed = (line: string, before = stderr || stdout || 'landing completed without confirmed merge') => ({ status: 1, stdout, stderr: `${before.slice(-(299 - line.length))}\n${line}` });
|
|
210
261
|
void defaultLandPrHead(pr, cwd).then((view) => {
|
|
211
262
|
resolveResult(view?.state === 'MERGED'
|
|
212
263
|
? { status: 0, stdout, stderr }
|
|
213
|
-
:
|
|
214
|
-
}).catch((error) => resolveResult(
|
|
264
|
+
: unconfirmed(view ? `✗ ta-land: pr land exited 0 but PR is ${view.state}` : '✗ ta-land: merge state unreadable after pr land exit 0'));
|
|
265
|
+
}).catch((error) => resolveResult(unconfirmed('✗ ta-land: merge state unreadable after pr land exit 0', String(error))));
|
|
215
266
|
});
|
|
216
267
|
});
|
|
217
268
|
}
|
|
@@ -234,13 +285,17 @@ export async function defaultLandPrHead(pr: number, cwd: string): Promise<(PrHea
|
|
|
234
285
|
} catch { return null; }
|
|
235
286
|
}
|
|
236
287
|
|
|
237
|
-
|
|
288
|
+
/**
|
|
289
|
+
* REVIEW-CONVERGE-PRIOR-FIX — `prior` 는 같은 PR 의 두 번째 이후 리뷰에만 온다: «직전 반영분»에 직전 머리 범위·diff·must-fix 를,
|
|
290
|
+
* 범위 경계에 «바뀌지 않은 줄의 새 must-fix 는 근거 줄» 한 줄을 붙인다. 없으면(첫 리뷰) 종전 문면 바이트 그대로.
|
|
291
|
+
*/
|
|
292
|
+
export function liveReviewIntent(card: TaskCard, runId: string | null, stopReason: string, prior?: PriorFixContext | null): string {
|
|
238
293
|
const goal = card.text.split('\n')[0]!.trim().slice(0, 300);
|
|
239
294
|
return [
|
|
240
295
|
`목표: ${goal}`,
|
|
241
296
|
`수용기준: 과제 카드 ${card.id} 원문 —\n${card.text.trim().slice(0, 4000)}`,
|
|
242
|
-
`직전 반영분: 런 ${runId ?? '-'} 이 ${stopReason} 로 멈춤 — 수확
|
|
243
|
-
|
|
297
|
+
`직전 반영분: 런 ${runId ?? '-'} 이 ${stopReason} 로 멈춤 — 수확 가능${prior ? `\n${priorFixBlock(prior)}` : ''}`,
|
|
298
|
+
`의도적 범위 경계: task-agent live review 요청(TA-JUDGE-LIVE-SAFE) — 리뷰만 한다 · 착지·재발사는 이 요청의 결정이 아니다${prior ? `\n${PRIOR_FIX_SCOPE_LINE}` : ''}`,
|
|
244
299
|
].join('\n');
|
|
245
300
|
}
|
|
246
301
|
|
|
@@ -284,18 +339,28 @@ export async function executeLiveReview(
|
|
|
284
339
|
if (head.state !== 'OPEN') return observe(deps, withRepo({ kind, executed: false, card: card.id, ok: false, detail: `PR #${pr} is ${head.state}` }));
|
|
285
340
|
const path = deps.statePath ?? taskAgentStatePath();
|
|
286
341
|
const at = (deps.now ?? (() => new Date()))().toISOString();
|
|
287
|
-
|
|
342
|
+
// TA-REVIEW-RESULT-CAPTURE — 머리마다 한 번이라 경로도 머리마다 하나다. 요청 칸에 먼저 적는다(회수가 이 칸을 본다).
|
|
343
|
+
const resultPath = reviewResultPath(path, card.id, pr, head.head);
|
|
344
|
+
const claim: { claimed: boolean; missing: boolean; before?: TaskCard } = { claimed: false, missing: false };
|
|
288
345
|
updateTaskCard(path, card.id, (current) => {
|
|
289
346
|
if (!current) { claim.missing = true; return undefined; }
|
|
290
347
|
// 머리 «이력»으로 본다 — A→B→A 로 돌아와도 A 는 다시 요청하지 않는다.
|
|
291
348
|
if ((current.reviewRequests ?? []).some((entry) => entry.pr === pr && entry.head === head!.head)) return undefined;
|
|
292
349
|
claim.claimed = true;
|
|
293
|
-
|
|
350
|
+
claim.before = current;
|
|
351
|
+
return { ...current, reviewRequests: [...(current.reviewRequests ?? []), { pr, head: head!.head, at, resultPath }] };
|
|
294
352
|
});
|
|
295
353
|
if (claim.missing) return observe(deps, withRepo({ kind, executed: false, card: card.id, ok: false, detail: 'task card not in state file' }));
|
|
296
354
|
if (!claim.claimed) return observe(deps, withRepo({ kind, executed: false, card: card.id, ok: true, detail: `already requested for #${pr} head ${head.head.slice(0, 12)}` }));
|
|
297
355
|
try {
|
|
298
|
-
|
|
356
|
+
// REVIEW-CONVERGE-PRIOR-FIX — 같은 PR 의 직전 요청(잠금 안에서 본 이력)이 있으면 그 라운드를 intent 에 싣는다 · 맥락을 못 만들면 종전 문면.
|
|
357
|
+
let prior: PriorFixContext | null = null;
|
|
358
|
+
try { prior = claim.before ? buildPriorFixContext(claim.before, pr, head.head, { ...(cwd ? { cwd } : {}), ...(deps.priorDiff ? { priorDiff: deps.priorDiff } : {}) }) : null; } catch { prior = null; }
|
|
359
|
+
if (prior) {
|
|
360
|
+
try { (deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'review-prior-fix-filled', priorFixObservation(card.id, pr, prior)); } catch { /* fail-soft */ }
|
|
361
|
+
}
|
|
362
|
+
const intent = liveReviewIntent(card, ctx.runId, ctx.stopReason, prior);
|
|
363
|
+
await (deps.requestReview ? deps.requestReview(pr, intent, cwd, { resultPath }) : defaultRequestReview(pr, intent, cwd, { resultPath }));
|
|
299
364
|
} catch (error) {
|
|
300
365
|
const reason = error instanceof Error ? error.message : String(error);
|
|
301
366
|
updateTaskCard(path, card.id, (current) => current?.reviewRequests?.some((entry) => entry.pr === pr && entry.head === head!.head && entry.at === at)
|
|
@@ -303,15 +368,158 @@ export async function executeLiveReview(
|
|
|
303
368
|
: undefined);
|
|
304
369
|
return observe(deps, withRepo({ kind, executed: false, card: card.id, ok: false, detail: `review request failed for #${pr} head ${head.head.slice(0, 12)}: ${reason}` }));
|
|
305
370
|
}
|
|
306
|
-
return observe(deps, withRepo({ kind, executed: true, card: card.id, ok: true, detail: `review requested for #${pr} head ${head.head.slice(0, 12)}
|
|
371
|
+
return observe(deps, withRepo({ kind, executed: true, card: card.id, ok: true, detail: `review requested for #${pr} head ${head.head.slice(0, 12)}`, resultPath }));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* TA-LAND-RETRY-ON-INFRA — land 실패를 둘로 가른다.
|
|
376
|
+
*
|
|
377
|
+
* - 왜: «같은 머리에 land 한 번»이 TA 쪽 인프라 결손(호스트에 PR 머리 트리가 없어 `✗ expected-head: … matching local HEAD and clean
|
|
378
|
+
* worktree required`)에 그 한 번을 써 버렸고, 결손을 고친(#26037) 뒤에도 같은 머리는 `already attempted` 로 막혀 사람이 머리를
|
|
379
|
+
* 흔들어야 했다(2026-10-11 #26030 · 카드 ta-20261010-c6b53b).
|
|
380
|
+
* - `infra` — 아래 «명시적 허용 목록»에 있는 사유만. 같은 머리에 한 번 더(머리당 총 `LAND_ATTEMPTS_PER_HEAD_ON_INFRA`).
|
|
381
|
+
* - `judgement` — 그 밖 전부(must-fix · 겹침 관문 · 머리 바뀜 · 동결 · 게이트 · 충돌 · 목록에 없는 ✗ 줄 · 기록 없는 옛 시도) — 종전대로 한 번 끝(fail-closed).
|
|
382
|
+
* - 판독 근거: `pr land` 의 실제 출력 줄(`src/cli/pr-cli.ts` 의 `✗ <관문>:` 문면 그대로)과 `executeLiveLand` 의 사유.
|
|
383
|
+
* - 임시 워크트리 «생성 실패»는 여기 오지 않는다 — #26037 이 land 를 부르지 않고 시도 기록을 «되돌린다»(시도를 안 쓴다).
|
|
384
|
+
* - `base-stale` — REJUDGE base-stale(OVERLAP-EVIDENCE-BASE-WINDOW 짝 · #26060): 겹침 증거의 게이트 base 뒤에 main 이 «PR 파일을 건드리며»
|
|
385
|
+
* 움직였다(`✗ overlap-evidence: base-stale-overlap: …` ⊕ 딸린 `✗ expected-head: overlap merge approval unavailable …` 줄 «만»).
|
|
386
|
+
* 같은 머리 «즉시» 재시도는 없다(`retryAllowed:false`) — 재판정 틱이 새 base 위 재게이트를 청하고, 그 재게이트가 «통과한 뒤»
|
|
387
|
+
* (`executeLiveLand` ctx `gateAt` = 그 재게이트 요청 시각)에만 이 시도는 «소비됨»으로 빠진다. judgement·infra 와 섞이지 않는다.
|
|
388
|
+
*/
|
|
389
|
+
export const LAND_ATTEMPTS_PER_HEAD_ON_INFRA = 2;
|
|
390
|
+
export type LandFailureClass = 'infra' | 'judgement' | 'base-stale';
|
|
391
|
+
|
|
392
|
+
/** `pr land` 출력 줄 → 인프라 사유. ⛔ 줄 «전체»가 맞아야 한다 — 비슷한 문면을 넓게 받지 않는다. */
|
|
393
|
+
export const LAND_INFRA_OUTPUT_REASONS: ReadonlyArray<{ reason: string; line: RegExp }> = [
|
|
394
|
+
// 머리 고정 사전 조건 — gh 로 본 PR(OPEN·non-draft·머리)은 executeLiveLand 가 «직전에» 확인했다 · 남는 원인은 로컬 HEAD·더러운 트리·gh 조회 실패.
|
|
395
|
+
{ reason: 'precondition-local-head-clean-tree', line: /^✗ expected-head: PR OPEN non-draft, matching local HEAD and clean worktree required$/ },
|
|
396
|
+
{ reason: 'precondition-branch', line: /^✗ branch: (?:PR head branch와 현재 브랜치가 다릅니다\.|현재 브랜치를 해석하지 못했습니다\.)$/ },
|
|
397
|
+
{ reason: 'base-unresolved', line: /^✗ base: 비교 base를 선택하지 못했습니다\.$/ },
|
|
398
|
+
{ reason: 'git-read-failed', line: /^✗ granularity: (?:비교 base를 해석하지 못했습니다\.|로컬 git log 를 읽지 못했습니다\.)$/ },
|
|
399
|
+
{ reason: 'gh-lookup-failed', line: /^✗ find: / },
|
|
400
|
+
{ reason: 'gh-merge-state-unknown', line: /^✗ merge: squash merge (?:결과를 모름 \(상태 미확정\)|상태 되읽기 실패)$/ },
|
|
401
|
+
// defaultLand — `pr land` 가 0 으로 끝났는데 병합 상태를 gh 로 다시 못 읽었다(병합됐으면 다음 시도는 MERGED 로 관문 앞에서 멈춘다).
|
|
402
|
+
{ reason: 'gh-merge-state-unreadable', line: /^✗ ta-land: merge state unreadable after pr land exit 0$/ },
|
|
403
|
+
];
|
|
404
|
+
/** 인프라 사유에 «딸려 나오는» 줄 — 그 사유가 같이 있을 때만 판정 거절로 세지 않는다. */
|
|
405
|
+
const LAND_INFRA_CONSEQUENCE_LINES: ReadonlyArray<{ of: string; line: RegExp }> = [
|
|
406
|
+
{ of: 'gh-lookup-failed', line: /^✗ upsert-ready: gh: pinned PR is not the branch open PR$/ },
|
|
407
|
+
];
|
|
408
|
+
/** REJUDGE base-stale — 겹침 증거의 게이트 base 가 낡았고 그 사이 착지가 PR 파일을 건드렸다(`pr land` · #26060 문면). */
|
|
409
|
+
const LAND_BASE_STALE_LINE = /^✗ overlap-evidence: (base-stale-overlap: .*)$/;
|
|
410
|
+
/** base-stale 에 «딸려 나오는» 줄 — 증거가 거절되면 `pr land` 가 이어서 낸다(그 줄만 있으면 판정 거절로 세지 않는다). */
|
|
411
|
+
const LAND_BASE_STALE_CONSEQUENCE_LINES: readonly RegExp[] = [/^✗ expected-head: overlap merge approval unavailable for the reviewed head$/];
|
|
412
|
+
/** 실패가 아닌 ✗ 줄 — `pr land` 가 «계속합니다»로 넘어간다(판정에 쓰지 않는다). */
|
|
413
|
+
const LAND_NON_FATAL_LINES: readonly RegExp[] = [/^✗ active-run-files: .*계속합니다\.?$/];
|
|
414
|
+
/** executeLiveLand 쪽 인프라 사유(출력 줄이 아니라 실행 사실). */
|
|
415
|
+
export const LAND_INFRA_EXECUTOR_REASONS = ['land-process-error', 'land-no-result-line'] as const;
|
|
416
|
+
const [LAND_PROCESS_ERROR, LAND_NO_RESULT_LINE] = LAND_INFRA_EXECUTOR_REASONS;
|
|
417
|
+
|
|
418
|
+
const RESULT_MARK = /^(?:\[dry-run\] )?[✓✗⚠⏳]/u;
|
|
419
|
+
|
|
420
|
+
export interface LandFailureClassification { class: LandFailureClass; reason: string }
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* 실패한 land 의 출력(또는 던진 오류)을 가른다 — 목록에 없는 ✗ 줄이 «하나라도» 있으면 판정 거절이다.
|
|
424
|
+
* `thrown` = land 를 띄우거나 기다리다 던졌다(프로세스 오류).
|
|
425
|
+
*/
|
|
426
|
+
export function classifyLandFailure(outcome: { status: number; stdout?: string; stderr?: string } | { thrown: string }): LandFailureClassification {
|
|
427
|
+
if ('thrown' in outcome) return { class: 'infra', reason: LAND_PROCESS_ERROR };
|
|
428
|
+
const lines = `${outcome.stdout ?? ''}\n${outcome.stderr ?? ''}`.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
429
|
+
const marked = lines.filter((line) => RESULT_MARK.test(line));
|
|
430
|
+
// 결과 줄이 «하나도» 없이 0 아닌 코드로 끝났다 — 관문까지 못 간 채 죽었다(크래시 · 신호).
|
|
431
|
+
if (!marked.length) return outcome.status !== 0 ? { class: 'infra', reason: LAND_NO_RESULT_LINE } : { class: 'judgement', reason: 'no-failure-line' };
|
|
432
|
+
const failures = marked.map((line) => line.replace(/^\[dry-run\] /, '')).filter((line) => line.startsWith('✗') && !LAND_NON_FATAL_LINES.some((re) => re.test(line)));
|
|
433
|
+
const infra = new Set<string>();
|
|
434
|
+
const unlisted: string[] = [];
|
|
435
|
+
for (const line of failures) {
|
|
436
|
+
const hit = LAND_INFRA_OUTPUT_REASONS.find((entry) => entry.line.test(line));
|
|
437
|
+
if (hit) infra.add(hit.reason); else unlisted.push(line);
|
|
438
|
+
}
|
|
439
|
+
const judged = unlisted.filter((line) => !LAND_INFRA_CONSEQUENCE_LINES.some((entry) => infra.has(entry.of) && entry.line.test(line)));
|
|
440
|
+
// REJUDGE base-stale — 거절 줄이 base-stale-overlap(⊕ 딸린 줄) «뿐»이고 인프라 사유가 없을 때만. 하나라도 다른 ✗ 줄이 섞이면 judgement(fail-closed).
|
|
441
|
+
const stale = judged.map((line) => LAND_BASE_STALE_LINE.exec(line)?.[1]).find((reason): reason is string => !!reason);
|
|
442
|
+
if (stale && !infra.size && judged.every((line) => LAND_BASE_STALE_LINE.test(line) || LAND_BASE_STALE_CONSEQUENCE_LINES.some((re) => re.test(line)))) {
|
|
443
|
+
return { class: 'base-stale', reason: stale.slice(0, 160) };
|
|
444
|
+
}
|
|
445
|
+
if (judged.length) return { class: 'judgement', reason: judged[0]!.slice(0, 120) };
|
|
446
|
+
if (infra.size) return { class: 'infra', reason: [...infra].join('+') };
|
|
447
|
+
return { class: 'judgement', reason: 'no-failure-line' };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
type LandAttempt = NonNullable<TaskCard['landAttempts']>[number];
|
|
451
|
+
type LandWorktreeCreateFailure = { pr: number; head: string; at: string; reason: string };
|
|
452
|
+
declare module './task-hand.js' {
|
|
453
|
+
interface TaskCard { landWorktreeCreateFailures?: LandWorktreeCreateFailure[] }
|
|
454
|
+
}
|
|
455
|
+
const sameHeadOf = (pr: number, head: string) => (entry: LandAttempt) => entry.pr === pr && entry.head.toLowerCase() === head.toLowerCase();
|
|
456
|
+
|
|
457
|
+
function landWorktreeCreateCap(): number {
|
|
458
|
+
try {
|
|
459
|
+
const config = JSON.parse(readFileSync(userConfigPath(), 'utf8')) as { tasks?: { landWorktreeCreateCap?: unknown } };
|
|
460
|
+
const configured = config.tasks?.landWorktreeCreateCap;
|
|
461
|
+
return typeof configured === 'number' && Number.isSafeInteger(configured) && configured > 0 ? configured : 3;
|
|
462
|
+
} catch { return 3; }
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function consecutiveLandWorktreeCreateFailures(card: TaskCard, pr: number, head: string): LandWorktreeCreateFailure[] {
|
|
466
|
+
const entries = (card.landWorktreeCreateFailures ?? []).filter((entry) => entry.pr === pr);
|
|
467
|
+
const last = entries.at(-1);
|
|
468
|
+
return last?.head.toLowerCase() === head.toLowerCase()
|
|
469
|
+
? entries.filter((entry) => entry.head.toLowerCase() === head.toLowerCase())
|
|
470
|
+
: [];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function recordLandWorktreeCreateFailure(card: TaskCard, failure: LandWorktreeCreateFailure): TaskCard {
|
|
474
|
+
const samePr = (card.landWorktreeCreateFailures ?? []).filter((entry) => entry.pr !== failure.pr);
|
|
475
|
+
const samePrHead = (card.landWorktreeCreateFailures ?? []).filter((entry) => entry.pr === failure.pr && entry.head.toLowerCase() === failure.head.toLowerCase());
|
|
476
|
+
return { ...card, landWorktreeCreateFailures: [...samePr, ...samePrHead, failure] };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function clearLandWorktreeCreateFailures(card: TaskCard, pr: number): TaskCard {
|
|
480
|
+
const remaining = (card.landWorktreeCreateFailures ?? []).filter((entry) => entry.pr !== pr);
|
|
481
|
+
const { landWorktreeCreateFailures: _removed, ...rest } = card;
|
|
482
|
+
return { ...rest, ...(remaining.length ? { landWorktreeCreateFailures: remaining } : {}) };
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function cappedLandWorktreeReason(failures: readonly LandWorktreeCreateFailure[], cap: number): string {
|
|
486
|
+
return `land worktree create capped (${failures.length}/${cap}): ${failures.at(-1)?.reason ?? 'unknown'}`;
|
|
307
487
|
}
|
|
308
488
|
|
|
489
|
+
function observeLandWorktreeCreateCapped(deps: LiveMoveDeps, data: { card: string; pr: number; head: string; failures: number; cap: number; reason: string }): void {
|
|
490
|
+
try { (deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'land-worktree-create-capped', data); } catch { /* fail-soft */ }
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** 같은 머리에 한 번 더 시도해도 되나 — 앞 시도가 «전부» 끝났고(ok:false) «전부» infra 이고 상한 밑일 때만. */
|
|
494
|
+
function landRetryAllowed(prior: readonly LandAttempt[]): boolean {
|
|
495
|
+
return prior.length > 0 && prior.length < LAND_ATTEMPTS_PER_HEAD_ON_INFRA && prior.every((entry) => entry.ok === false && entry.class === 'infra');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* REJUDGE base-stale — `gateAt`(새 base 위 재게이트를 «요청한» 시각) 앞의 base-stale 시도는 그 재게이트가 통과해 소비됐다 —
|
|
500
|
+
* 같은 머리 land 판단에서 뺀다. 나머지(infra·judgement·그 뒤의 시도)는 종전 규칙 그대로.
|
|
501
|
+
*/
|
|
502
|
+
export function openLandAttempts<T extends Pick<LandAttempt, 'at' | 'class'>>(prior: readonly T[], gateAt?: string): T[] {
|
|
503
|
+
if (!gateAt) return [...prior];
|
|
504
|
+
const since = Date.parse(gateAt);
|
|
505
|
+
return prior.filter((entry) => !(entry.class === 'base-stale' && Number.isFinite(since) && Date.parse(entry.at) < since));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/** 카드의 이 PR·머리에 인프라 재시도가 남았나(재판정 틱이 «머리 그대로»여도 land 단계까지 가게). */
|
|
509
|
+
export function landRetryPending(card: Pick<TaskCard, 'landAttempts'>, pr: number, head: string): boolean {
|
|
510
|
+
return landRetryAllowed((card.landAttempts ?? []).filter(sameHeadOf(pr, head)));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export const LAND_RETRY_ON_INFRA_EVENT = 'land-retry-on-infra';
|
|
514
|
+
|
|
309
515
|
const landedCycles = new Set<string>();
|
|
310
516
|
|
|
311
|
-
/** `propose-land` — only a passing self review of this exact OPEN, non-draft head may invoke pr land. */
|
|
517
|
+
/** `propose-land` — only a passing self review (pass or warn, with must-fix 0) of this exact OPEN, non-draft head may invoke pr land. */
|
|
312
518
|
export async function executeLiveLand(
|
|
313
519
|
card: TaskCard | undefined, pr: number | undefined,
|
|
314
|
-
ctx: { runId?: string | null; cycleId?: string; cwd?: string; produced?: { headCommit?: string; branch?: string; prUrl?: string }; review?: { verdict: 'pass' | 'fail'; head: string
|
|
520
|
+
ctx: { runId?: string | null; cycleId?: string; cwd?: string; produced?: { headCommit?: string; branch?: string; prUrl?: string }; review?: { verdict: 'pass' | 'warn' | 'fail'; head: string; /** TA-LAND-WARN-MUSTFIX0 — `false` 면 리뷰가 실제로 안 돌았다 → land 거부. 슈퍼바이저 입력은 reviewed 리뷰로만 만들어져 칸이 없다. */ reviewed?: boolean };
|
|
521
|
+
/** TA-REJUDGE-ON-HEAD — 겹침 증거 파일(있으면 land 에 넘길 뿐 · 판정은 그대로). */ overlapEvidence?: string;
|
|
522
|
+
/** REJUDGE base-stale — 증거의 재게이트를 요청한 시각 · 그 앞의 base-stale 시도는 소비됨(`openLandAttempts`). */ gateAt?: string },
|
|
315
523
|
deps: LiveMoveDeps = {},
|
|
316
524
|
): Promise<LiveMoveResult> {
|
|
317
525
|
const kind = 'land' as const;
|
|
@@ -336,20 +544,41 @@ export async function executeLiveLand(
|
|
|
336
544
|
if (ctx.produced?.prUrl && (!view.url || view.url.trim().replace(/\/+$/, '').toLowerCase() !== ctx.produced.prUrl.trim().replace(/\/+$/, '').toLowerCase())) {
|
|
337
545
|
return reject(card.id, `PR #${pr} URL mismatches run evidence`, reviewRepo);
|
|
338
546
|
}
|
|
339
|
-
|
|
547
|
+
// TA-LAND-WARN-MUSTFIX0 — 정본 규칙(#25941 canAuto · #25962): pass «또는» warn 이 통과 후보 · must-fix 0 은 바로 아래 검사가 본다.
|
|
548
|
+
if (ctx.review?.verdict !== 'pass' && ctx.review?.verdict !== 'warn') return reject(card.id, `PR #${pr} self review pass missing`, reviewRepo);
|
|
549
|
+
if (ctx.review.reviewed === false) return reject(card.id, `PR #${pr} self review not reviewed (reviewed:false)`, reviewRepo);
|
|
340
550
|
if (!/^[0-9a-f]{40}$/i.test(ctx.review.head) || ctx.review.head.toLowerCase() !== view.head.toLowerCase()) {
|
|
341
551
|
return reject(card.id, `PR #${pr} review head mismatch: ${ctx.review.head.slice(0, 12)} ≠ ${view.head.slice(0, 12)}`, reviewRepo);
|
|
342
552
|
}
|
|
553
|
+
// TA-LAND-MUSTFIX-ZERO — «pass ⊕ must-fix» 는 land 로 가지 않는다(#25941 `canAuto` 와 같은 축) · 수를 못 읽었으면 «0» 이 아니라 «모름»(fail-closed).
|
|
554
|
+
// (`mustFixCount` 는 `SupervisorJobResult.selfReview` 가 나른다 — 시그니처는 그대로 두고 여기서만 읽는다.)
|
|
555
|
+
const mustFixCount = (ctx.review as { mustFixCount?: unknown }).mustFixCount;
|
|
556
|
+
if (typeof mustFixCount !== 'number' || !Number.isSafeInteger(mustFixCount) || mustFixCount < 0) return reject(card.id, `PR #${pr} review-must-fix-unknown`, reviewRepo);
|
|
557
|
+
if (mustFixCount > 0) return reject(card.id, `PR #${pr} review-warn-with-must-fix: pass carries ${mustFixCount} must-fix`, reviewRepo);
|
|
343
558
|
const cycle = ctx.cycleId ?? ctx.runId;
|
|
344
559
|
if (cycle && landedCycles.has(cycle)) return reject(card.id, `cycle ${cycle} already landed — stays shadow`, reviewRepo);
|
|
345
560
|
const path = deps.statePath ?? taskAgentStatePath();
|
|
346
561
|
const at = (deps.now ?? (() => new Date()))().toISOString();
|
|
562
|
+
const local = (deps.landWorktree?.localHead ?? localHead)(cwd);
|
|
563
|
+
const needsLandWorktree = !!local && local.toLowerCase() !== view.head.toLowerCase();
|
|
564
|
+
const createCap = landWorktreeCreateCap();
|
|
347
565
|
let claimed = false;
|
|
348
566
|
let missing = false;
|
|
567
|
+
let cappedReason: string | undefined;
|
|
568
|
+
// TA-LAND-RETRY-ON-INFRA — 같은 머리의 앞 시도들(잠금 안에서 읽은 «지금» 카드) · 재시도면 그 근거.
|
|
569
|
+
let prior: LandAttempt[] = [];
|
|
349
570
|
try {
|
|
350
571
|
updateTaskCard(path, card.id, (current) => {
|
|
351
572
|
if (!current) { missing = true; return undefined; }
|
|
352
|
-
if (
|
|
573
|
+
if (needsLandWorktree) {
|
|
574
|
+
const failures = consecutiveLandWorktreeCreateFailures(current, pr, view!.head);
|
|
575
|
+
if (failures.length >= createCap) {
|
|
576
|
+
cappedReason = cappedLandWorktreeReason(failures, createCap);
|
|
577
|
+
return undefined;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
prior = openLandAttempts((current.landAttempts ?? []).filter(sameHeadOf(pr, view!.head)), ctx.gateAt);
|
|
581
|
+
if (prior.length && !landRetryAllowed(prior)) return undefined;
|
|
353
582
|
claimed = true;
|
|
354
583
|
return { ...current, landAttempts: [...(current.landAttempts ?? []), { pr, head: view!.head, at }] };
|
|
355
584
|
});
|
|
@@ -357,25 +586,128 @@ export async function executeLiveLand(
|
|
|
357
586
|
return reject(card.id, `land attempt could not be recorded: ${String(error).slice(-250)}`, reviewRepo);
|
|
358
587
|
}
|
|
359
588
|
if (missing) return reject(card.id, 'task card not in state file', reviewRepo);
|
|
360
|
-
if (
|
|
589
|
+
if (cappedReason) return reject(card.id, cappedReason, reviewRepo);
|
|
590
|
+
if (!claimed) {
|
|
591
|
+
const last = prior.at(-1);
|
|
592
|
+
const why = last ? ` (attempts ${prior.length} · last ${last.ok === false ? `class ${last.class ?? 'unclassified'}${last.reason ? ` ${last.reason}` : ''}` : last.ok === true ? 'ok' : 'unfinished'})` : '';
|
|
593
|
+
return observe(deps, withRepo({ kind, card: card.id, ok: true, executed: false, detail: `already attempted land for #${pr} head ${view.head.slice(0, 12)}${why}` }));
|
|
594
|
+
}
|
|
595
|
+
const attempt = prior.length + 1;
|
|
596
|
+
if (attempt > 1) {
|
|
597
|
+
const last = prior.at(-1)!;
|
|
598
|
+
try { (deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', LAND_RETRY_ON_INFRA_EVENT, { card: card.id, pr, head: view.head, attempt, reason: last.reason ?? 'unknown', class: 'infra', decision: 'retrying' }); } catch { /* fail-soft */ }
|
|
599
|
+
}
|
|
361
600
|
if (cycle) landedCycles.add(cycle);
|
|
601
|
+
// TA-LAND-WORKTREE — `pr land --expected-head` 는 «로컬 HEAD = 고정 머리»를 요구한다. cwd 가 다른 머리면(Pod 런 PR · 호스트 checkout)
|
|
602
|
+
// PR 머리의 임시 워크트리에서 부르고 끝나면 걷는다. 같은 머리(로컬 런 작업 트리)거나 HEAD 를 못 읽으면 종전 그대로 cwd 에서.
|
|
603
|
+
let landCwd = cwd;
|
|
604
|
+
let worktree: LandWorktree | undefined;
|
|
605
|
+
if (needsLandWorktree && local) {
|
|
606
|
+
let made: LandWorktree | LandWorktreeFailure;
|
|
607
|
+
try {
|
|
608
|
+
made = await (deps.landWorktree?.create ?? createLandWorktree)({ card: card.id, pr, head: view.head, branch: view.branch, repoCwd: cwd, statePath: path });
|
|
609
|
+
} catch (error) { made = { reason: (error instanceof Error ? error.message : String(error)).slice(-250), created: null, removed: null }; }
|
|
610
|
+
if ('reason' in made) {
|
|
611
|
+
const reason = made.reason;
|
|
612
|
+
observeLandWorktree({ card: card.id, pr, head: view.head, created: made.created, removed: made.removed, reason }, deps.log);
|
|
613
|
+
let failures: LandWorktreeCreateFailure[] = [];
|
|
614
|
+
let recordFailureError: unknown;
|
|
615
|
+
try {
|
|
616
|
+
updateTaskCard(path, card.id, (current) => {
|
|
617
|
+
if (!current) return undefined;
|
|
618
|
+
failures = [...consecutiveLandWorktreeCreateFailures(current, pr, view!.head), { pr, head: view!.head, at, reason }];
|
|
619
|
+
return recordLandWorktreeCreateFailure(current, { pr, head: view!.head, at, reason });
|
|
620
|
+
});
|
|
621
|
+
} catch (error) { recordFailureError = error; }
|
|
622
|
+
// land 를 부르지 않았다 — 이 머리의 시도 기록과 주기 표시를 되돌려 다음 틱이 다시 시도할 수 있게 한다.
|
|
623
|
+
if (cycle) landedCycles.delete(cycle);
|
|
624
|
+
try {
|
|
625
|
+
updateTaskCard(path, card.id, (current) => current?.landAttempts?.some(entry => entry.pr === pr && entry.head === view!.head && entry.at === at)
|
|
626
|
+
? { ...current, landAttempts: current.landAttempts.filter(entry => !(entry.pr === pr && entry.head === view!.head && entry.at === at)) }
|
|
627
|
+
: undefined);
|
|
628
|
+
} catch (error) {
|
|
629
|
+
// 되돌리기 실패 — 이 머리는 «시도함»으로 남아 다음 틱이 막힌다. 조용히 넘기지 않고 사유를 남긴다.
|
|
630
|
+
observeLandWorktree({ card: card.id, pr, head: view.head, created: made.created, removed: made.removed, reason: `land attempt release failed: ${String(error).slice(-200)}` }, deps.log);
|
|
631
|
+
return reject(card.id, `PR #${pr} land worktree unavailable: ${reason} · attempt release failed (head stays attempted)`, reviewRepo);
|
|
632
|
+
}
|
|
633
|
+
if (recordFailureError) return reject(card.id, `PR #${pr} land worktree unavailable: ${reason} · failure record failed: ${String(recordFailureError).slice(-200)}`, reviewRepo);
|
|
634
|
+
if (failures.length >= createCap) {
|
|
635
|
+
const capped = cappedLandWorktreeReason(failures, createCap);
|
|
636
|
+
if (failures.length === createCap) observeLandWorktreeCreateCapped(deps, { card: card.id, pr, head: view.head, failures: failures.length, cap: createCap, reason });
|
|
637
|
+
return reject(card.id, capped, reviewRepo);
|
|
638
|
+
}
|
|
639
|
+
return reject(card.id, `PR #${pr} land worktree unavailable: ${reason}`, reviewRepo);
|
|
640
|
+
}
|
|
641
|
+
worktree = made;
|
|
642
|
+
landCwd = made.cwd;
|
|
643
|
+
// 실패 장부 정리는 fail-soft — 정리 쓰기 실패로 정상 착지를 막지 않는다(막으면 잡아 둔 landAttempts 가 남아 그 head 가 영영 «already attempted»).
|
|
644
|
+
try {
|
|
645
|
+
updateTaskCard(path, card.id, (current) => current?.landWorktreeCreateFailures?.some((entry) => entry.pr === pr)
|
|
646
|
+
? clearLandWorktreeCreateFailures(current, pr) : undefined);
|
|
647
|
+
} catch (error) {
|
|
648
|
+
try { (deps.log ?? ((c, e, d) => debug.log(c, e, d, { level: 'warn' })))('task-agent', 'land-worktree-create-failures-clear-failed', { card: card.id, pr, head: view.head, error: String(error).slice(-200) }); } catch { /* fail-soft */ }
|
|
649
|
+
}
|
|
650
|
+
observeLandWorktree({ card: card.id, pr, head: view.head, created: true, removed: false, reason: `cwd HEAD ${local.slice(0, 12)} ≠ PR head ${view.head.slice(0, 12)}` }, deps.log);
|
|
651
|
+
}
|
|
652
|
+
// 증거 경로는 «원래» cwd 기준으로 고정한다 — 임시 트리로 cwd 를 바꿔도 상대경로가 다른 파일을 가리키지 않게(같은 cwd 면 그대로).
|
|
653
|
+
const overlapEvidence = ctx.overlapEvidence && worktree ? resolve(cwd, ctx.overlapEvidence) : ctx.overlapEvidence;
|
|
362
654
|
let ok = false;
|
|
363
655
|
let detail: string;
|
|
656
|
+
let failure: LandFailureClassification | undefined;
|
|
364
657
|
try {
|
|
365
658
|
// The CLI rechecks the pinned PR/head immediately before merge, after its own gates and freeze admission.
|
|
366
|
-
const outcome =
|
|
659
|
+
const outcome = overlapEvidence
|
|
660
|
+
? await (deps.land ?? defaultLand)(pr, view.head, landCwd, { overlapEvidence })
|
|
661
|
+
: await (deps.land ?? defaultLand)(pr, view.head, landCwd);
|
|
367
662
|
ok = outcome.status === 0;
|
|
368
663
|
detail = (ok ? outcome.stdout || `land merged #${pr} head ${view.head.slice(0, 12)}` : outcome.stderr || outcome.stdout || `exit ${outcome.status}`).slice(-300);
|
|
369
|
-
|
|
664
|
+
if (!ok) failure = classifyLandFailure(outcome);
|
|
665
|
+
} catch (error) {
|
|
666
|
+
detail = (error instanceof Error ? error.message : String(error)).slice(-300);
|
|
667
|
+
failure = classifyLandFailure({ thrown: detail });
|
|
668
|
+
}
|
|
669
|
+
const retryAllowed = failure?.class === 'infra' && attempt < LAND_ATTEMPTS_PER_HEAD_ON_INFRA;
|
|
670
|
+
// 인프라 실패로 재시도가 남으면 주기 표시도 푼다 — 같은 주기 id(재판정 틱의 `rejudge:<card>:<head>`)가 그 한 번을 막지 않게.
|
|
671
|
+
if (retryAllowed && cycle) landedCycles.delete(cycle);
|
|
672
|
+
if (worktree) {
|
|
673
|
+
// 성공이든 실패든 걷는다.
|
|
674
|
+
let removal: LandWorktreeRemoval;
|
|
675
|
+
try { removal = worktree.cleanup(); } catch (error) { removal = { removed: false, reason: String(error).slice(-200) }; }
|
|
676
|
+
observeLandWorktree({ card: card.id, pr, head: view.head, created: true, removed: removal.removed, ...(removal.branchRemoved !== undefined ? { branchRemoved: removal.branchRemoved } : {}),
|
|
677
|
+
reason: removal.reason ?? `land ${ok ? 'ok' : 'failed'} — removed` }, deps.log);
|
|
678
|
+
}
|
|
679
|
+
const landAttempt: LiveMoveResult['landAttempt'] = failure
|
|
680
|
+
? { attempt, class: failure.class, reason: failure.reason, retryAllowed }
|
|
681
|
+
: { attempt };
|
|
682
|
+
if (failure) {
|
|
683
|
+
try {
|
|
684
|
+
(deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', LAND_RETRY_ON_INFRA_EVENT, {
|
|
685
|
+
card: card.id, pr, head: view.head, attempt, reason: failure.reason, class: failure.class,
|
|
686
|
+
decision: retryAllowed ? 'retry-allowed' : failure.class === 'infra' ? 'retry-exhausted' : failure.class === 'base-stale' ? 'base-stale-awaiting-regate' : 'no-retry',
|
|
687
|
+
});
|
|
688
|
+
} catch { /* fail-soft */ }
|
|
689
|
+
}
|
|
370
690
|
try {
|
|
371
691
|
updateTaskCard(path, card.id, (current) => current?.landAttempts?.some(entry => entry.pr === pr && entry.head === view!.head && entry.at === at)
|
|
372
|
-
? {
|
|
692
|
+
? {
|
|
693
|
+
...current,
|
|
694
|
+
landAttempts: current.landAttempts.map(entry => entry.pr === pr && entry.head === view!.head && entry.at === at
|
|
695
|
+
? { ...entry, ok, detail, ...(failure ? { class: failure.class, reason: failure.reason } : {}) } : entry),
|
|
696
|
+
// TA-LAND-RETRY-ON-INFRA — 실패한 시도마다 카드 history 한 줄(logs 창이 지나도 «왜 다시 했나/안 했나»가 남게).
|
|
697
|
+
...(failure ? { history: [...(current.history ?? []), {
|
|
698
|
+
at, event: LAND_RETRY_ON_INFRA_EVENT, kind: failure.class, pr, head: view!.head,
|
|
699
|
+
effect: retryAllowed ? 'retry-allowed' : failure.class === 'infra' ? 'retry-exhausted' : failure.class === 'base-stale' ? 'awaiting-regate' : 'no-retry',
|
|
700
|
+
detail: failure.class === 'base-stale'
|
|
701
|
+
? `attempt ${attempt} · base-stale → 재게이트 대기 (land again only after a re-gate on a new base passes) · ${failure.reason}`
|
|
702
|
+
: `attempt ${attempt}/${failure.class === 'infra' ? LAND_ATTEMPTS_PER_HEAD_ON_INFRA : attempt} · ${failure.reason}`,
|
|
703
|
+
}] } : {}),
|
|
704
|
+
}
|
|
373
705
|
: undefined);
|
|
374
706
|
} catch (error) {
|
|
375
|
-
return observe(deps, withRepo({ kind, card: card.id, ok: false, executed: true,
|
|
707
|
+
return observe(deps, withRepo({ kind, card: card.id, ok: false, executed: true, landAttempt,
|
|
376
708
|
detail: `land ${ok ? 'succeeded' : 'failed'} but card update failed: ${String(error).slice(-230)}` }));
|
|
377
709
|
}
|
|
378
|
-
return observe(deps, withRepo({ kind, card: card.id, ok, executed: true, detail }));
|
|
710
|
+
return observe(deps, withRepo({ kind, card: card.id, ok, executed: true, detail, landAttempt }));
|
|
379
711
|
}
|
|
380
712
|
|
|
381
713
|
/** `propose-green` — 비지 않은 근거가 있을 때만 카드에 제안을 적는다(한 번). 체크리스트는 쓰지 않는다. */
|
|
@@ -397,3 +729,88 @@ export function executeLiveGreenProposal(card: TaskCard | undefined, evidence: R
|
|
|
397
729
|
if (!wrote.proposed) return observe(deps, { kind, executed: false, card: card.id, ok: true, detail: 'already proposed' });
|
|
398
730
|
return observe(deps, { kind, executed: true, card: card.id, ok: true, detail: `green proposed (${Object.values(refs).join(', ')}) · checklist untouched` });
|
|
399
731
|
}
|
|
732
|
+
|
|
733
|
+
export interface LiveDecisionCardContext {
|
|
734
|
+
runId: string | null; stopReason: string; reason: string; pr?: number;
|
|
735
|
+
risk?: NextAction['risk'];
|
|
736
|
+
/** 서명 · 화면 · must-fix — 하나도 비지 않아야 카드가 올라간다. */
|
|
737
|
+
evidence: DecisionCardEvidence;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
const DECISION_SIGNATURE_KEEP = 300;
|
|
741
|
+
const DECISION_SCREEN_KEEP = 1500;
|
|
742
|
+
|
|
743
|
+
/** 같은 런 · 사유 · 근거면 같은 지문 — 카드 history 의 «이미 올렸다» 판정 키. */
|
|
744
|
+
export function decisionCardFingerprint(runId: string | null, reason: string, evidence: { signature?: string; screen?: string; mustFix: readonly string[] }): string {
|
|
745
|
+
return createHash('sha1').update(JSON.stringify([runId, reason, evidence.signature ?? null, evidence.screen ?? null, evidence.mustFix])).digest('hex').slice(0, 12);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/** `decisions raise` 를 같은 우주의 CLI 자식으로 한 번 부른다 — 카드는 결정 원장에 들어가 OP 거르기가 읽는다. */
|
|
749
|
+
export async function defaultRaiseDecision(args: string[]): Promise<{ status: number; stdout: string; stderr?: string }> {
|
|
750
|
+
const { ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
|
|
751
|
+
const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
|
|
752
|
+
const { effectiveInstanceRoot } = await import('../instance/resolve.js');
|
|
753
|
+
const argv = [resolve(ELANOUS_CLI_ENTRY), '--config-dir', getElanousConfigDirOverride() ?? effectiveInstanceRoot(), ...args];
|
|
754
|
+
return new Promise((resolveResult, reject) => {
|
|
755
|
+
const child = spawn(process.execPath, argv, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
756
|
+
let stdout = '';
|
|
757
|
+
let stderr = '';
|
|
758
|
+
child.stdout.on('data', (chunk: Buffer) => { stdout = (stdout + chunk.toString()).slice(-300); });
|
|
759
|
+
child.stderr.on('data', (chunk: Buffer) => { stderr = (stderr + chunk.toString()).slice(-300); });
|
|
760
|
+
child.once('error', reject);
|
|
761
|
+
child.once('close', (code) => resolveResult({ status: code ?? 1, stdout, stderr }));
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* `decision-card` — 막힌 과제를 근거 붙은 결정 카드로 올린다. 근거(서명 · 화면 · must-fix)가 하나도 없으면 «올리지 않는다».
|
|
767
|
+
* 같은 지문의 카드는 한 번만(카드 history 의 `live-move` 줄 · 먼저 적고 올린다) · 올리기 실패는 줄을 걷어 다음 틱이 다시 시도한다.
|
|
768
|
+
*/
|
|
769
|
+
export async function executeLiveDecisionCard(card: TaskCard | undefined, ctx: LiveDecisionCardContext, deps: LiveMoveDeps = {}): Promise<LiveMoveResult> {
|
|
770
|
+
const kind = 'decision-card' as const;
|
|
771
|
+
if (!card) return observe(deps, { kind, executed: false, card: null, ok: false, detail: 'no task card — stays shadow' });
|
|
772
|
+
const grounds = decisionCardGrounds(ctx.evidence);
|
|
773
|
+
if (!grounds.length) return observe(deps, { kind, executed: false, card: card.id, ok: false, detail: 'no evidence (signature · screen · must-fix) — no card raised' });
|
|
774
|
+
const signature = ctx.evidence.signature?.trim().slice(0, DECISION_SIGNATURE_KEEP) || undefined;
|
|
775
|
+
const screen = ctx.evidence.screen?.trim().slice(-DECISION_SCREEN_KEEP) || undefined;
|
|
776
|
+
const mustFix = (ctx.evidence.mustFix ?? []).filter((fix) => typeof fix === 'string' && fix.trim()).map((fix) => fix.trim());
|
|
777
|
+
const mark = `fp:${decisionCardFingerprint(ctx.runId, ctx.reason, { ...(signature ? { signature } : {}), ...(screen ? { screen } : {}), mustFix })}`;
|
|
778
|
+
const path = deps.statePath ?? taskAgentStatePath();
|
|
779
|
+
const at = (deps.now ?? (() => new Date()))().toISOString();
|
|
780
|
+
const ours = (entry: TaskCard['history'][number]) => entry.event === LIVE_MOVE_HISTORY_EVENT && entry.kind === kind && !!entry.detail?.includes(mark);
|
|
781
|
+
const claim = { claimed: false, missing: false };
|
|
782
|
+
updateTaskCard(path, card.id, (current) => {
|
|
783
|
+
if (!current) { claim.missing = true; return undefined; }
|
|
784
|
+
if ((current.history ?? []).some(ours)) return undefined;
|
|
785
|
+
claim.claimed = true;
|
|
786
|
+
return { ...current, history: [...(current.history ?? []), {
|
|
787
|
+
at, event: LIVE_MOVE_HISTORY_EVENT, kind, executed: false, executorResult: 'live' as const,
|
|
788
|
+
detail: `decision card claimed · ${mark}`, ...(ctx.runId ? { runId: ctx.runId } : {}), ...(ctx.pr !== undefined ? { pr: ctx.pr } : {}),
|
|
789
|
+
effect: 'none — decision card claimed, not yet raised',
|
|
790
|
+
}] };
|
|
791
|
+
});
|
|
792
|
+
if (claim.missing) return observe(deps, { kind, executed: false, card: card.id, ok: false, detail: 'task card not in state file' });
|
|
793
|
+
if (!claim.claimed) return observe(deps, { kind, executed: false, card: card.id, ok: true, detail: `already raised for ${mark}` });
|
|
794
|
+
const evidence = JSON.stringify({
|
|
795
|
+
card: card.id, runId: ctx.runId, pr: ctx.pr ?? null, stopReason: ctx.stopReason, grounds,
|
|
796
|
+
...(signature ? { signature } : {}), ...(screen ? { screen } : {}), mustFix, selected: kind, reason: ctx.reason,
|
|
797
|
+
});
|
|
798
|
+
const args = decisionRaiseArgs({ taskId: card.id, reason: ctx.reason, ...(ctx.risk ? { risk: ctx.risk } : {}), evidence });
|
|
799
|
+
let failure: string | undefined;
|
|
800
|
+
try {
|
|
801
|
+
const outcome = await (deps.raiseDecision ?? defaultRaiseDecision)(args);
|
|
802
|
+
if (outcome.status !== 0) failure = (outcome.stderr || outcome.stdout || `exit ${outcome.status}`).slice(-250);
|
|
803
|
+
} catch (error) { failure = (error instanceof Error ? error.message : String(error)).slice(-250); }
|
|
804
|
+
const mine = (entry: TaskCard['history'][number]) => ours(entry) && entry.at === at;
|
|
805
|
+
const detail = failure ? `decisions raise failed: ${failure}` : `decision card raised (${grounds.join(' · ')}) · ${mark}`;
|
|
806
|
+
try {
|
|
807
|
+
updateTaskCard(path, card.id, (current) => current?.history?.some(mine)
|
|
808
|
+
? { ...current, history: failure
|
|
809
|
+
? current.history.filter((entry) => !mine(entry))
|
|
810
|
+
: current.history.map((entry) => mine(entry) ? { ...entry, executed: true, ok: true, detail, effect: `decision card raised · grounds ${grounds.join('+')} · decision ledger (OP filter reads it)` } : entry) }
|
|
811
|
+
: undefined);
|
|
812
|
+
} catch (error) {
|
|
813
|
+
return observe(deps, { kind, executed: !failure, card: card.id, ok: false, detail: `${detail} but card update failed: ${String(error).slice(-200)}` });
|
|
814
|
+
}
|
|
815
|
+
return observe(deps, { kind, executed: !failure, card: card.id, ok: !failure, detail });
|
|
816
|
+
}
|