elanous 0.2.32 → 0.2.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 0368f25d-ad84af92fefee68f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
- package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 1530.0e612369b6fd7ea0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
- package/apps/pwa/out/_next/static/chunks/{7391.ebae168025c91b6a.js → 1674.2a65fd5668e1cc5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7947-d0759430f8042240.js → 1993-c0007b7ad0c0ef41.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{60fb96c9.360b01d8d4927b7b.js → 1c735de4.f993a30bbd3c57c4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 2018.a741297bce759490.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3902.e1e71aaac850a045.js → 2625.5d870aa999f33db1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
- package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
- package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 3408.21d1570602f4b6c0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 3677-4215f826f6aa68e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7371.80c05c653b08e907.js → 4346.8601952e73bf5803.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 4705-194e64e47ca0fbdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 4718-17d2af636796a330.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 5101.e32282718f99ed6f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{2001.6c7e0fd02190886c.js → 5154.a118f3957ed14e36.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 5483-dd5d7697f6bdb106.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3267c0e6.d34854e7b3984a6e.js → 56d372f2.681ab4ec4c998fae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +287 -0
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 6236.e18cced2d5ba6afb.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
- package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6544cb48.a87fe20ddf137be2.js → 6b89c8bd.24df687a820500b3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7385.50a308a477bdfc21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 7644.17e37ba6f1d4226e.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8018.a32663f04a6fc5f9.js → 8219.baa715d1deee80e2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4111.2bfedbb233ad206b.js → 8256.e3ac8421a71f82f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 8444.4c26b379ca2b9596.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
- package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 8637.47f5b35afcae5e6b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9214.63a510d39178e997.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 938.66ad1ef0e5abae1c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 9512.5a76207a730e0491.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{69-0a2c8209c6d4a158.js → 967-2aa39b2d04b4c690.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 9952.5daf5f94063a2b3e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-a27b1e5a0d1b308f.js → page-406b47745b53f269.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-32866485913d6a04.js → page-47c5d4db587266bd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-dc0a532f5b9196ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → cbe38a15.5a032598e39970c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → da5176c6.6773b6c5994e1d99.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.mjs +10 -2
- package/catalog/providers/opengateway.yaml +25 -0
- package/docs/goal-context/01-goal-authoring-checks.md +8 -0
- package/docs/goal-context/03-verification-menu.md +24 -0
- package/docs/goal-context/04-mock-scenarios.md +100 -0
- package/docs/goal-context/README.md +5 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/default-loop.yaml +76 -5
- package/graphs/document-loop.yaml +71 -4
- package/graphs/implement-loop.yaml +59 -4
- package/graphs/journey/SCENARIOS.md +33 -0
- package/graphs/journey/recipes.yaml +1 -0
- package/graphs/journey/ta-journey.yaml +94 -0
- package/graphs/journey/units/author/author.yaml +20 -0
- package/graphs/journey/units/author/recipes.yaml +2 -0
- package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
- package/graphs/journey/units/author-dialogue/observe.ts +96 -0
- package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
- package/graphs/journey/units/green/green.yaml +20 -0
- package/graphs/journey/units/green/recipes.yaml +2 -0
- package/graphs/journey/units/pr/pr.yaml +20 -0
- package/graphs/journey/units/pr/recipes.yaml +2 -0
- package/graphs/journey/units/remember/recipes.yaml +2 -0
- package/graphs/journey/units/remember/remember.yaml +20 -0
- package/graphs/operate-loop.yaml +71 -4
- package/graphs/overlays/stop-heal-ladder.yaml +1 -1
- package/graphs/release-rehearsal/recipes.yaml +1 -1
- package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
- package/graphs/research-loop.yaml +159 -4
- package/graphs/test-diet/test-diet.yaml +3 -0
- package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
- package/graphs/units/dispatch-pod/recipes.yaml +14 -0
- package/graphs/units/entry/entry.yaml +50 -0
- package/graphs/units/entry/recipes.yaml +14 -0
- package/graphs/units/harvest/harvest.yaml +25 -0
- package/graphs/units/harvest/recipes.yaml +4 -0
- package/graphs/units/land/land.yaml +45 -0
- package/graphs/units/land/recipes.yaml +3 -0
- package/graphs/units/recipes.yaml +7 -0
- package/graphs/units/recover.yaml +39 -0
- package/graphs/units/reflect/recipes.yaml +3 -0
- package/graphs/units/reflect/reflect.yaml +15 -0
- package/graphs/units/task-agent-recover-review.yaml +17 -0
- package/graphs/units/task-agent-recover-wait.yaml +17 -0
- package/graphs/units/verbs/make-doc.yaml +34 -0
- package/graphs/units/verbs/recipes.yaml +33 -0
- package/graphs/units/verbs/verify.yaml +55 -0
- package/graphs/work/recipes.yaml +2 -0
- package/graphs/work/research-report.yaml +28 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +69 -16
- package/scripts/coord-role-pack.ts +19 -6
- package/scripts/docs/generate-graph-anatomy.ts +19 -2
- package/scripts/graph-harvest-unit.ts +22 -0
- package/scripts/graph-units/journey-stub.ts +6 -0
- package/scripts/graph-units/land-enqueue.ts +78 -0
- package/scripts/graph-units/recover-plan.ts +15 -0
- package/scripts/graph-units/reflect-node.ts +88 -0
- package/scripts/graph-units/ta-journey-observe.ts +109 -0
- package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
- package/scripts/graph-units/verbs/verify-stage.ts +75 -0
- package/scripts/graph-units/verbs-envelope.ts +139 -0
- package/scripts/hq/standby-snapshot.ts +30 -0
- package/scripts/public-export.ts +43 -1
- package/scripts/ratchets/train-side-invariants.sh +45 -0
- package/scripts/release-loop/auto-approve-node.ts +30 -16
- package/scripts/release-loop/docs-land-node.ts +21 -5
- package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
- package/scripts/release-loop/gate-closure.ts +5 -1
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-node.ts +675 -49
- package/scripts/release-loop/gate-partial.ts +68 -14
- package/scripts/release-loop/gate-radius-live.ts +177 -0
- package/scripts/release-loop/gate-radius-shadow.ts +138 -0
- package/scripts/release-loop/gate-traffic-mode.ts +128 -0
- package/scripts/release-loop/gate-triage-node.ts +5 -2
- package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
- package/scripts/release-loop/known-issues-node.ts +77 -8
- package/scripts/release-loop/node-verdict.ts +12 -1
- package/scripts/release-loop/npm-publish-node.ts +66 -12
- package/scripts/release-loop/preflight.ts +93 -7
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
- package/scripts/release-loop/publish-node.ts +60 -9
- package/scripts/release-loop/pwa-remote.ts +166 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
- package/scripts/release-loop/resume-cap.ts +56 -0
- package/scripts/release-loop/resume-release.ts +155 -19
- package/scripts/release-loop/resume.ts +24 -1
- package/scripts/release-loop/tui-sim-node.ts +8 -2
- package/scripts/release-loop/unattended-release.ts +10 -2
- package/scripts/test-diet/lib.ts +6 -1
- package/scripts/test-diet/node.ts +194 -13
- package/scripts/ux-sim.ts +39 -0
- package/src/acp/core-turn-bridge.ts +20 -5
- package/src/acp/reasoning-thought-buffer.ts +45 -0
- package/src/agent/self-ambient-cache.ts +8 -0
- package/src/agent-substrate/acp-reviewer.ts +90 -15
- package/src/agent-substrate/pr-reviewer.ts +17 -0
- package/src/agent-substrate/review-finding-key.ts +53 -0
- package/src/agent-substrate/self-review-cli.ts +188 -18
- package/src/ask-user-question/pending-questions.ts +1 -1
- package/src/autopilot/pr-manager.ts +393 -65
- package/src/budget/run-usage-rollup.ts +1 -0
- package/src/chat/index.ts +0 -2
- package/src/chat/pickers/modal-runtime.ts +10 -27
- package/src/chat/tool-render/dispatch.ts +62 -10
- package/src/cli/agent-cli.ts +13 -2
- package/src/cli/control-cli.ts +24 -7
- package/src/cli/doctor-cli.ts +4 -1
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/light-entry-route.ts +75 -0
- package/src/cli/llm-detect-cli.ts +23 -1
- package/src/cli/pod-cli.ts +77 -3
- package/src/cli/pr-cli.ts +81 -14
- package/src/cli/pr-land-base-read.ts +2 -0
- package/src/cli/pr-land-overlap-evidence.ts +154 -16
- package/src/cli/pr-land-pod-shadow-job.ts +3 -0
- package/src/cli/pr-land-recovery.ts +64 -0
- package/src/cli/pty-takeover-cli.ts +6 -5
- package/src/cli/release-checklist-read-cli.ts +79 -0
- package/src/cli/release-cli.ts +189 -132
- package/src/cli/release-run-if-ready.ts +29 -28
- package/src/cli/release-single-flight.ts +178 -0
- package/src/cli/remote-resolve.ts +1 -1
- package/src/cli/root-tui-entry.ts +48 -0
- package/src/cli/seat-cli.ts +37 -0
- package/src/cli/setup-cli.ts +40 -1
- package/src/cli/sim-cli.ts +22 -0
- package/src/cli/tasks-cli.ts +667 -14
- package/src/cli/usage-cli.ts +13 -11
- package/src/clipboard/history.ts +179 -13
- package/src/config.ts +8 -1
- package/src/control/control-status.ts +8 -3
- package/src/control-plane/ledger.ts +5 -3
- package/src/control-plane/server.ts +5 -3
- package/src/core-turn/short-question.ts +5 -1
- package/src/dashboard/chat/acp-chat.ts +8 -0
- package/src/dashboard/index.ts +114 -77
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/seat-autowake.ts +56 -3
- package/src/dashboard/render/theme-resolver.ts +33 -4
- package/src/dashboard/seat-boot-preamble.ts +1 -1
- package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
- package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
- package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
- package/src/dashboard/turn-preamble.ts +47 -1
- package/src/dashboard/turn-stream-formatter.ts +34 -1
- package/src/dashboard/turn-stream-runtime.ts +2 -0
- package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
- package/src/domains/guardian-tick.ts +54 -2
- package/src/domains/outbound-alert.ts +3 -2
- package/src/domains/schedule-registry.ts +16 -2
- package/src/extractors.ts +3 -1
- package/src/git-fs/idle-refresh.ts +76 -0
- package/src/git-fs/index.ts +18 -7
- package/src/git-fs/retry.ts +4 -0
- package/src/git-fs/runner.ts +2 -0
- package/src/git-fs/worktree.ts +42 -4
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/runner.ts +267 -54
- package/src/grok/credential.ts +15 -3
- package/src/harness/harness-cli-command.ts +151 -38
- package/src/harness/harness-incidents.ts +37 -0
- package/src/harness/harness-pod-dispatch.ts +38 -1
- package/src/harness/harness-salvage-cli.ts +14 -2
- package/src/harness/launch-utterance-ledger.ts +208 -0
- package/src/impl-discipline/detector.ts +16 -4
- package/src/impl-discipline/system-prompt.ts +11 -0
- package/src/impl-discipline/types.ts +2 -2
- package/src/index.ts +683 -146
- package/src/intake-plane/already-built-hint.ts +91 -0
- package/src/intake-plane/requirement-funnel.ts +29 -1
- package/src/knowhow/pack.ts +199 -0
- package/src/light-cli.ts +111 -0
- package/src/llm/opengateway-models.ts +11 -0
- package/src/llm/provider-credentials.ts +14 -0
- package/src/llm/provider-detect.ts +8 -1
- package/src/llm/runtime-model-family.ts +2 -1
- package/src/llm.ts +268 -65
- package/src/loops/budget.ts +95 -0
- package/src/loops/msg-wake.ts +8 -2
- package/src/loops/orchestrator/traffic.ts +132 -1
- package/src/model-tier/llm-tier-map.ts +15 -1
- package/src/mss/logging/log-store.ts +4 -5
- package/src/native-tool-catalog.ts +15 -1
- package/src/nexus/api/graphs-api.ts +22 -3
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/loop-resources.ts +13 -1
- package/src/nexus/api/ops-api.ts +12 -0
- package/src/oauth/claude-pty-maturity.ts +66 -0
- package/src/oauth/codex-access-mirror.ts +55 -0
- package/src/oauth/codex.ts +7 -0
- package/src/oauth/fallback-chain.ts +1 -1
- package/src/onboarding/first-run.ts +5 -3
- package/src/onboarding/non-interactive.ts +64 -13
- package/src/onboarding.ts +10 -2
- package/src/ops/overview-collect.ts +54 -4
- package/src/ops/overview.ts +31 -7
- package/src/pr-tool/census.ts +282 -30
- package/src/pr-tool/inflight-registry.ts +160 -7
- package/src/prompt-library/gpt6-family-addendum.ts +14 -1
- package/src/pty-shell/herdr-agent-report.ts +442 -0
- package/src/pty-shell/pty-control-ipc.ts +5 -5
- package/src/pty-shell/pty-manifest.ts +7 -0
- package/src/pty-shell/pty-write-outcome.ts +24 -6
- package/src/pty-shell/tui-run-state.ts +117 -3
- package/src/release-loop/checklist.ts +103 -5
- package/src/release-loop/feature-store.ts +19 -2
- package/src/release-loop/landed-but-yellow.ts +129 -5
- package/src/release-loop/light-rc.ts +1 -0
- package/src/release-loop/placement.ts +10 -3
- package/src/release-loop/rehearsal.ts +205 -25
- package/src/release-loop/rubric.ts +16 -2
- package/src/repl/index.ts +174 -17
- package/src/repl/ops-msg-bridge.ts +32 -0
- package/src/self-dev/ask-launch-flow.ts +44 -5
- package/src/self-dev/cli-help-text.ts +17 -0
- package/src/self-dev/dev-cli.ts +11 -9
- package/src/self-dev/draft-residue.ts +37 -1
- package/src/self-dev/draft-sweep.ts +188 -13
- package/src/self-dev/draft-triage-rules.ts +107 -0
- package/src/self-dev/fleet-reduce.ts +3 -2
- package/src/self-dev/graph-front-nodes.ts +112 -0
- package/src/self-dev/graph-journey-nodes.ts +11 -6
- package/src/self-dev/graph-journey-route.ts +60 -6
- package/src/self-dev/harness-run-cli.ts +3 -15
- package/src/self-dev/orchestrate-cli-text.ts +10 -0
- package/src/self-dev/orchestrate.ts +79 -3
- package/src/self-dev/review-provider-fallback.ts +35 -1
- package/src/self-dev/run-supervisor.ts +107 -12
- package/src/self-dev/run-types.ts +5 -1
- package/src/self-dev/self-orchestrate-runtime.ts +1 -11
- package/src/self-dev/shard-aggregate.ts +42 -5
- package/src/self-dev/shard-run.ts +8 -1
- package/src/self-implement/blocked-draft-policy.ts +20 -0
- package/src/self-implement/classify-shadow.ts +3 -7
- package/src/self-implement/doctor-visit.ts +18 -1
- package/src/self-implement/gate-baseline.ts +95 -12
- package/src/self-implement/gate-cli.ts +1 -0
- package/src/self-implement/gate-remote.ts +40 -25
- package/src/self-implement/goal-author-decompose.ts +275 -47
- package/src/self-implement/goal-author-identity.ts +66 -0
- package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
- package/src/self-implement/goal-author.ts +254 -120
- package/src/self-implement/goal-elaborate.ts +295 -0
- package/src/self-implement/goal-refine.ts +270 -0
- package/src/self-implement/graph-overlay-yaml.ts +28 -2
- package/src/self-implement/graph-unit-flatten.ts +103 -0
- package/src/self-implement/graph-unit-resolver.ts +107 -0
- package/src/self-implement/graph-yaml.ts +151 -1
- package/src/self-implement/headless-elanous-driver.ts +1 -0
- package/src/self-implement/knowhow-pack.ts +103 -0
- package/src/self-implement/orchestrator.ts +160 -45
- package/src/self-implement/pod-warm-pool-profile.ts +45 -0
- package/src/self-implement/review-mustfix-class.ts +203 -0
- package/src/self-implement/rework-budget-judgment.ts +5 -8
- package/src/self-implement/run-stop.ts +17 -2
- package/src/self-implement/running-runs.ts +29 -1
- package/src/self-implement/scope-adjacency.ts +113 -0
- package/src/self-implement/seams.ts +138 -4
- package/src/self-implement/stop-autoheal.ts +112 -2
- package/src/session/chat.ts +27 -0
- package/src/session-runtime/index.ts +1 -1
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/setup/llm-env-detect.ts +5 -0
- package/src/skills/tools/agent.ts +140 -14
- package/src/skills/tools/msg-ask.ts +100 -0
- package/src/skills/tools/ops-ledger.ts +2 -1
- package/src/skills/tools/schedule-wakeup.ts +66 -17
- package/src/steward/hold-hygiene.ts +24 -6
- package/src/steward/release-day.ts +7 -3
- package/src/steward/triage-budget.ts +194 -0
- package/src/steward/triage.ts +57 -7
- package/src/task-agent/actions.ts +69 -1
- package/src/task-agent/green-sweep.ts +4 -0
- package/src/task-agent/harvest-unit.ts +141 -0
- package/src/task-agent/live-moves.ts +257 -15
- package/src/task-agent/parent-host.ts +216 -6
- package/src/task-agent/postland-card.ts +80 -1
- package/src/task-agent/rejudge-on-head.ts +112 -26
- package/src/task-agent/repair-branch-cas.ts +4 -1
- package/src/task-agent/repair-cycle.ts +16 -3
- package/src/task-agent/run-identity.ts +4 -3
- package/src/task-agent/shadow.ts +19 -3
- package/src/task-agent/task-hand.ts +96 -36
- package/src/task-agent/tier-split.ts +127 -0
- package/src/task-agent/work-order-build.ts +24 -0
- package/src/task-agent/work-order.ts +3 -2
- package/src/task-orchestrator/generator-prompt.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +72 -3
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +47 -8
- package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
- package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +72 -4
- package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +32 -5
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +421 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +588 -71
- package/src/task-orchestrator/surfaces/self-implement.ts +106 -2
- package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
- package/src/tool-runtime/truncation-store.ts +4 -0
- package/src/tui/README.md +2 -0
- package/src/tui/chat/background-job-status.ts +54 -0
- package/src/tui/chat/log-view.ts +80 -0
- package/src/tui/entry.ts +406 -0
- package/src/tui/input/composer.ts +144 -0
- package/src/tui/seat-mail-boot.ts +59 -0
- package/src/tui/slash/compact.ts +100 -0
- package/src/tui/slash/new-session.ts +35 -0
- package/src/tui-client/dashboard-session.ts +10 -1
- package/src/tui-client/local-chat-turn.ts +239 -0
- package/src/tui-client/local-harness-command.ts +63 -0
- package/src/tui-client/local-provider-command.ts +184 -0
- package/src/user-config/coercion.ts +36 -0
- package/src/user-config.ts +22 -43
- package/src/ux-sim/event-monkey.ts +378 -0
- package/src/ux-sim/fake-bin.ts +42 -7
- package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
- package/src/ux-sim/fault-pod-codex-503.ts +211 -0
- package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
- package/src/ux-sim/scenario.ts +72 -13
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
- package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
- package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
- package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5543.a438b8ab5a13ea47.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989.3694300e5f000b14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
- package/src/cli/g6a-registration-probe.ts +0 -16
- /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
|
@@ -16,6 +16,9 @@ import { createHash } from 'node:crypto';
|
|
|
16
16
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
17
17
|
import { join, resolve } from 'node:path';
|
|
18
18
|
import { debug } from '../debug/log.js';
|
|
19
|
+
import { resolveFreshGrokCredential } from '../grok/credential.js';
|
|
20
|
+
import { memoryQuantityBytes } from '../task-orchestrator/surfaces/pod-lease.js';
|
|
21
|
+
import { parsePodPool } from '../task-orchestrator/surfaces/pod-pool.js';
|
|
19
22
|
import { shellQuote } from './task-hand.js';
|
|
20
23
|
|
|
21
24
|
/** `taskAgent.parentHost` 설정 칸. */
|
|
@@ -42,6 +45,11 @@ const DEFAULT_REMOTE_ELANOUS = '$HOME/.local/share/elanous/bin/elanous';
|
|
|
42
45
|
const DEFAULT_REMOTE_CONFIG_DIR = '$HOME/.elanous';
|
|
43
46
|
const HOST_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]{0,127}$/;
|
|
44
47
|
|
|
48
|
+
/** Missing child-provider metadata keeps the established Pod default: the HQ Codex mirror is needed. */
|
|
49
|
+
export function shouldInstallRemoteCodexAccess(effectiveChildProvider: string | undefined): boolean {
|
|
50
|
+
return effectiveChildProvider === undefined || effectiveChildProvider === 'openai-codex';
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
/**
|
|
46
54
|
* 켜졌나 — env 가 이긴다(`off`·`0`·빈 값이면 끔). env 가 호스트를 주면 나머지 칸(cwd 등)은 설정에서 받는다.
|
|
47
55
|
* cwd 가 없으면 켜지지 않는다(어디서 띄울지 모르는 원격 발사는 하지 않는다).
|
|
@@ -74,6 +82,50 @@ export function resolveParentHosts(config: ParentHostSetting | undefined, env: N
|
|
|
74
82
|
|
|
75
83
|
/** Capacity sample is read on the host before launch. Unknown or saturated capacity is not a positive weight. */
|
|
76
84
|
export interface ParentHostCapacity { approvalHeadroom: number; load: number }
|
|
85
|
+
|
|
86
|
+
export interface ParentHostPodFit {
|
|
87
|
+
state: 'fits' | 'never-fits' | 'unmeasured';
|
|
88
|
+
memoryLimit: string;
|
|
89
|
+
requiredBytes: number | null;
|
|
90
|
+
allocatableBytes: number | null;
|
|
91
|
+
reason: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Read node allocatable memory only. This preflight never creates a probe Pod. */
|
|
95
|
+
export function readParentHostPodFit(target: ParentHostConfig, memoryLimit: string, ssh: SshRunner = defaultSshRunner): ParentHostPodFit {
|
|
96
|
+
const requiredBytes = memoryQuantityBytes(memoryLimit);
|
|
97
|
+
const unknown = (reason: string, allocatableBytes: number | null = null): ParentHostPodFit =>
|
|
98
|
+
({ state: 'unmeasured', memoryLimit, requiredBytes, allocatableBytes, reason });
|
|
99
|
+
if (requiredBytes === null || requiredBytes <= 0) return unknown('memory-limit-unreadable');
|
|
100
|
+
// Without an explicit pool, the remote current kubectl context may be unrelated to the launched Job.
|
|
101
|
+
if (!target.podPool) return unknown('pod-pool-unset');
|
|
102
|
+
let members: ReturnType<typeof parsePodPool>;
|
|
103
|
+
try { members = parsePodPool(target.podPool); }
|
|
104
|
+
catch { return unknown('pod-pool-unreadable'); }
|
|
105
|
+
if (!members.length) return unknown('pod-pool-empty');
|
|
106
|
+
let maximum = 0;
|
|
107
|
+
let unreadable = false;
|
|
108
|
+
for (const member of members) {
|
|
109
|
+
let result: ReturnType<SshRunner>;
|
|
110
|
+
try { result = ssh(target.host, `kubectl --context ${shellQuote(member.context)} get nodes -o json`, 15_000); }
|
|
111
|
+
catch { unreadable = true; continue; }
|
|
112
|
+
if (result.status !== 0) { unreadable = true; continue; }
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(result.stdout) as { items?: Array<{ status?: { allocatable?: { memory?: unknown } } }> };
|
|
115
|
+
if (!Array.isArray(parsed.items) || parsed.items.length === 0) { unreadable = true; continue; }
|
|
116
|
+
for (const node of parsed.items) {
|
|
117
|
+
const raw = node?.status?.allocatable?.memory;
|
|
118
|
+
const bytes = typeof raw === 'string' ? memoryQuantityBytes(raw) : null;
|
|
119
|
+
if (bytes === null || bytes <= 0) { unreadable = true; continue; }
|
|
120
|
+
maximum = Math.max(maximum, bytes);
|
|
121
|
+
}
|
|
122
|
+
} catch { unreadable = true; }
|
|
123
|
+
}
|
|
124
|
+
if (maximum >= requiredBytes) return { state: 'fits', memoryLimit, requiredBytes, allocatableBytes: maximum, reason: 'node-allocatable-fits' };
|
|
125
|
+
if (unreadable || maximum === 0) return unknown('node-allocatable-unmeasured', maximum || null);
|
|
126
|
+
return { state: 'never-fits', memoryLimit, requiredBytes, allocatableBytes: maximum, reason: 'memory-never-fits' };
|
|
127
|
+
}
|
|
128
|
+
|
|
77
129
|
const CAPACITY_MARKER = '__ELANOUS_PARENT_CAPACITY__';
|
|
78
130
|
const APPROVAL_MARKER = '__ELANOUS_PARENT_APPROVALS__';
|
|
79
131
|
const LOAD_MARKER = '__ELANOUS_PARENT_LOAD__';
|
|
@@ -159,7 +211,9 @@ export function remoteLaunchScript(target: ParentHostConfig, args: readonly stri
|
|
|
159
211
|
const elanous = target.elanous ?? DEFAULT_REMOTE_ELANOUS;
|
|
160
212
|
const configDir = target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR;
|
|
161
213
|
const log = remoteParentLogPath(target, env.ELANOUS_RUN_ID ?? 'unknown');
|
|
162
|
-
|
|
214
|
+
// --config-dir keeps the parent's operational config/state; authStorePath()
|
|
215
|
+
// reads XDG_CONFIG_HOME/elanous/auth.json first, as the entrypoint test proves.
|
|
216
|
+
const envPart = [...Object.entries(env).filter(([key]) => key !== 'ELANOUS_STATE_DIR' && /^[A-Z_][A-Z0-9_]*$/.test(key)).map(([key, value]) => `${key}=${key === 'XDG_CONFIG_HOME' || key === 'CODEX_HOME' || key === 'GH_CONFIG_DIR' ? remotePath(value) : shellQuote(value)}`), `ELANOUS_STATE_DIR=${remotePath(configDir)}`].join(' ');
|
|
163
217
|
const argv = [remotePath(elanous), '--config-dir', remotePath(configDir), ...remoteParentArgs(args, target.podPool).map(shellQuote)].join(' ');
|
|
164
218
|
// 준비가 실패하면 «확실히 안 띄웠다»(not-launched=…)를 찍고 끝낸다 — 그때만 호출부가 로컬로 돌아간다.
|
|
165
219
|
// 띄운 뒤에는 짧게 살아 있는지 보고 pid 를 찍는다(조기 종료면 early-exit — 역시 «안 돈다»가 확실).
|
|
@@ -170,10 +224,12 @@ export function remoteLaunchScript(target: ParentHostConfig, args: readonly stri
|
|
|
170
224
|
}
|
|
171
225
|
|
|
172
226
|
/** ssh 실행기(시험 주입). */
|
|
173
|
-
export type SshRunner = (host: string, script: string, timeoutMs: number) => { status: number | null; stdout: string; stderr: string };
|
|
227
|
+
export type SshRunner = (host: string, script: string, timeoutMs: number, stdin?: string) => { status: number | null; stdout: string; stderr: string };
|
|
174
228
|
|
|
175
|
-
export const defaultSshRunner: SshRunner = (host, script, timeoutMs) => {
|
|
176
|
-
const result = spawnSync('ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', '-o', 'ControlPath=none', host, script], {
|
|
229
|
+
export const defaultSshRunner: SshRunner = (host, script, timeoutMs, stdin) => {
|
|
230
|
+
const result = spawnSync('ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', '-o', 'ControlPath=none', host, script], {
|
|
231
|
+
encoding: 'utf8', timeout: timeoutMs, maxBuffer: 32 * 1024 * 1024, ...(stdin !== undefined ? { input: stdin } : {}),
|
|
232
|
+
});
|
|
177
233
|
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? (result.error ? String(result.error) : '') };
|
|
178
234
|
};
|
|
179
235
|
|
|
@@ -289,8 +345,27 @@ export class RemoteParentNotLaunchedError extends Error {
|
|
|
289
345
|
* 그 밖(ssh 끊김·시간 초과·알 수 없는 답)은 «떴는지 모른다» — 일반 Error 로 던져 카드가 launch-failed 로 남게 한다
|
|
290
346
|
* (⛔ 로컬로 또 띄우면 원격에 이미 뜬 부모와 중복이 될 수 있다).
|
|
291
347
|
*/
|
|
292
|
-
export function launchRemoteParent(
|
|
293
|
-
|
|
348
|
+
export function launchRemoteParent(
|
|
349
|
+
target: ParentHostConfig,
|
|
350
|
+
args: readonly string[],
|
|
351
|
+
env: Record<string, string>,
|
|
352
|
+
ssh: SshRunner = defaultSshRunner,
|
|
353
|
+
grokMirrorResolver: () => OwnerGrokAccessMirror = resolveOwnerGrokAccessMirror,
|
|
354
|
+
effectiveChildProvider?: string,
|
|
355
|
+
now: () => number = Date.now,
|
|
356
|
+
): { pid: number; log: string } {
|
|
357
|
+
const argvProvider = childProviderFromArgs(args);
|
|
358
|
+
if (effectiveChildProvider && argvProvider && argvProvider !== effectiveChildProvider) {
|
|
359
|
+
throw new Error(`effective child provider mismatch (context=${effectiveChildProvider}, argv=${argvProvider})`);
|
|
360
|
+
}
|
|
361
|
+
const launchArgs = effectiveChildProvider && !argvProvider
|
|
362
|
+
? [...args.slice(0, 2), '--child-llm-provider', effectiveChildProvider, ...args.slice(2)]
|
|
363
|
+
: args;
|
|
364
|
+
if ((effectiveChildProvider ?? argvProvider) === 'grok') {
|
|
365
|
+
const mirror = grokMirrorResolver();
|
|
366
|
+
installRemoteGrokAccess(target, mirror, ssh, now);
|
|
367
|
+
}
|
|
368
|
+
const result = ssh(target.host, remoteLaunchScript(target, launchArgs, env), 30_000);
|
|
294
369
|
const log = remoteParentLogPath(target, env.ELANOUS_RUN_ID ?? 'unknown');
|
|
295
370
|
const pid = Number(/^pid=(\d+)$/m.exec(result.stdout)?.[1]);
|
|
296
371
|
if (result.status === 0 && Number.isSafeInteger(pid) && pid > 0) return { pid, log };
|
|
@@ -302,6 +377,141 @@ export function launchRemoteParent(target: ParentHostConfig, args: readonly stri
|
|
|
302
377
|
throw new Error(`원격 부모 발사 결과 불확실(${target.host} · rc=${result.status}) — 중복을 피해 로컬로 다시 띄우지 않는다 · 원격에서 ELANOUS_RUN_ID=${env.ELANOUS_RUN_ID ?? '?'} 를 확인: ${(result.stderr.trim().split('\n').pop() || '').slice(0, 160)}`);
|
|
303
378
|
}
|
|
304
379
|
|
|
380
|
+
/** The provider selection travels as an argv pair or assignment; absent remains the existing Codex default. */
|
|
381
|
+
function childProviderFromArgs(args: readonly string[]): string | undefined {
|
|
382
|
+
for (let i = 0; i < args.length; i++) {
|
|
383
|
+
const arg = args[i]!;
|
|
384
|
+
if (arg === '--child-llm-provider') return args[i + 1];
|
|
385
|
+
if (arg.startsWith('--child-llm-provider=')) return arg.slice('--child-llm-provider='.length);
|
|
386
|
+
}
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface OwnerGrokAccessMirror { key: string; expiresAt: string }
|
|
391
|
+
|
|
392
|
+
/** Resolve/refresh on HQ and return only a still-usable subscription access token. */
|
|
393
|
+
export function resolveOwnerGrokAccessMirror(opts: {
|
|
394
|
+
home?: string;
|
|
395
|
+
env?: NodeJS.ProcessEnv;
|
|
396
|
+
now?: () => number;
|
|
397
|
+
execImpl?: (cmd: string, args: string[], timeoutMs: number) => void;
|
|
398
|
+
} = {}): OwnerGrokAccessMirror {
|
|
399
|
+
const credential = resolveFreshGrokCredential({
|
|
400
|
+
...(opts.home ? { home: opts.home } : {}),
|
|
401
|
+
...(opts.env ? { env: opts.env } : {}),
|
|
402
|
+
...(opts.now ? { now: opts.now } : {}),
|
|
403
|
+
...(opts.execImpl ? { execImpl: opts.execImpl } : {}),
|
|
404
|
+
});
|
|
405
|
+
if (!credential || credential.kind !== 'subscription') throw new Error('Grok subscription mirror unavailable: no-usable-subscription');
|
|
406
|
+
// Expiry travels with the selected credential so a second auth-file read cannot pair another scope's
|
|
407
|
+
// expiry with this access token if the file changes between reads.
|
|
408
|
+
if (!credential.expiresAt) throw new Error('Grok subscription mirror unavailable: access-state-incomplete');
|
|
409
|
+
const expiresAt = Date.parse(credential.expiresAt);
|
|
410
|
+
// Keep the same two-minute safety margin that triggers HQ refresh before remote installation.
|
|
411
|
+
if (!Number.isFinite(expiresAt) || expiresAt <= (opts.now ?? Date.now)() + 120_000) {
|
|
412
|
+
throw new Error('Grok subscription mirror unavailable: expired-or-refresh-did-not-produce-fresh-access');
|
|
413
|
+
}
|
|
414
|
+
return { key: credential.token, expiresAt: credential.expiresAt };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Install one HQ-selected Grok access token over SSH stdin; never copy refresh or other scopes. */
|
|
418
|
+
export function installRemoteGrokAccess(
|
|
419
|
+
target: ParentHostConfig,
|
|
420
|
+
mirror: OwnerGrokAccessMirror,
|
|
421
|
+
ssh: SshRunner = defaultSshRunner,
|
|
422
|
+
now: () => number = Date.now,
|
|
423
|
+
): void {
|
|
424
|
+
if (!mirror || typeof mirror.key !== 'string' || !mirror.key || typeof mirror.expiresAt !== 'string'
|
|
425
|
+
|| !Number.isFinite(Date.parse(mirror.expiresAt)) || Date.parse(mirror.expiresAt) <= now() + 120_000) {
|
|
426
|
+
throw new Error('invalid Grok access mirror');
|
|
427
|
+
}
|
|
428
|
+
const payload = JSON.stringify({ key: mirror.key, expires_at: mirror.expiresAt });
|
|
429
|
+
const code = [
|
|
430
|
+
'const fs=require("node:fs"),path=require("node:path"),os=require("node:os");',
|
|
431
|
+
'const p=JSON.parse(fs.readFileSync(0,"utf8"));if(!p||typeof p.key!=="string"||!p.key||typeof p.expires_at!=="string"||!Number.isFinite(Date.parse(p.expires_at))||Date.parse(p.expires_at)<=Date.now()+120000||Object.keys(p).some(k=>!new Set(["key","expires_at"]).has(k)))process.exit(2);',
|
|
432
|
+
'const dir=path.join(os.homedir(),".grok"),file=path.join(dir,"auth.json"),temp=file+"."+process.pid+".tmp";fs.mkdirSync(dir,{recursive:true,mode:0o700});fs.chmodSync(dir,0o700);',
|
|
433
|
+
'try{let auth={};try{const prior=JSON.parse(fs.readFileSync(file,"utf8"));if(!prior||typeof prior!=="object"||Array.isArray(prior))process.exit(3);auth=prior}catch(e){if(e.code!=="ENOENT")throw e}auth["https://auth.x.ai::hq-mirror"]={key:p.key,expires_at:p.expires_at};fs.writeFileSync(temp,JSON.stringify(auth),{mode:0o600});fs.chmodSync(temp,0o600);fs.renameSync(temp,file)}catch(e){try{fs.unlinkSync(temp)}catch{};throw e}',
|
|
434
|
+
].join('');
|
|
435
|
+
const result = ssh(target.host, `umask 077; bun -e ${shellQuote(code)}`, 20_000, payload);
|
|
436
|
+
if (result.status !== 0) throw new Error(`remote Grok access mirror failed (ssh rc=${result.status ?? 'unknown'})`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Install access-only Codex copies over SSH stdin; credentials never enter argv, shell text, or logs. */
|
|
440
|
+
export function installRemoteCodexAccess(target: ParentHostConfig, mirror: { elanousAuth: string; codexAuth: string; account?: string }, ssh: SshRunner = defaultSshRunner): void {
|
|
441
|
+
let elanous: { version?: number; providers?: Record<string, Record<string, unknown>> };
|
|
442
|
+
let codex: { auth_mode?: string; tokens?: Record<string, unknown> };
|
|
443
|
+
try {
|
|
444
|
+
elanous = JSON.parse(mirror.elanousAuth) as typeof elanous;
|
|
445
|
+
codex = JSON.parse(mirror.codexAuth) as typeof codex;
|
|
446
|
+
} catch { throw new Error('invalid local Codex access mirror'); }
|
|
447
|
+
const provider = elanous.providers?.['openai-codex'];
|
|
448
|
+
const elanousTokens = provider?.tokens as Record<string, unknown> | undefined;
|
|
449
|
+
const codexTokens = codex.tokens;
|
|
450
|
+
if (!Number.isSafeInteger(elanous.version) || Number(elanous.version) < 1
|
|
451
|
+
|| typeof elanousTokens?.accessToken !== 'string' || !elanousTokens.accessToken || elanousTokens.refreshToken !== '' || elanousTokens.refresh_token !== ''
|
|
452
|
+
|| codex.auth_mode !== 'chatgpt'
|
|
453
|
+
|| typeof codexTokens?.access_token !== 'string' || !codexTokens.access_token || codexTokens.refresh_token !== '' || codexTokens.refreshToken !== '')
|
|
454
|
+
throw new Error('Codex access mirror must contain a versioned store, auth mode, access tokens, and empty refresh tokens');
|
|
455
|
+
|
|
456
|
+
const account = mirror.account ?? 'default';
|
|
457
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(account)) throw new Error('invalid Codex mirror account name');
|
|
458
|
+
|
|
459
|
+
const payload = JSON.stringify({ elanousVersion: elanous.version, provider, codexAuth: codex, account, storeKey: account === 'default' ? 'openai-codex' : `openai-codex:${account}` });
|
|
460
|
+
const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
|
|
461
|
+
// HQ owns token metadata; the remote keeps only the selected named Codex credential in managed account homes.
|
|
462
|
+
const code = [
|
|
463
|
+
'const fs=require("node:fs"),path=require("node:path"),os=require("node:os");',
|
|
464
|
+
'const payload=JSON.parse(fs.readFileSync(0,"utf8"));',
|
|
465
|
+
'const read=(file)=>{try{return JSON.parse(fs.readFileSync(file,"utf8"))}catch{return {}}};',
|
|
466
|
+
'const write=(file,value)=>{const temp=file+"."+process.pid+".tmp";try{fs.writeFileSync(temp,JSON.stringify(value),{mode:0o600});fs.chmodSync(temp,0o600);fs.renameSync(temp,file)}catch(error){try{fs.unlinkSync(temp)}catch{};throw error}};',
|
|
467
|
+
'const elanousFile=path.join(process.argv[1],"auth.json"),configDir=path.dirname(elanousFile);fs.mkdirSync(configDir,{recursive:true,mode:0o700});',
|
|
468
|
+
'const elanous=read(elanousFile);if(typeof elanous.version!=="number")elanous.version=payload.elanousVersion;elanous.providers={...(elanous.providers||{})};const defaultHome=path.join(os.homedir(),".codex"),managedAccounts=path.join(configDir,"codex-accounts");for(const key of Object.keys(elanous.providers)){if(key.startsWith("openai-codex:"))delete elanous.providers[key]}fs.rmSync(managedAccounts,{recursive:true,force:true});fs.rmSync(path.join(configDir,"remote-codex-mirror.json"),{force:true});',
|
|
469
|
+
'const accountHome=payload.account==="default"?defaultHome:path.join(configDir,"codex-accounts",payload.account),tokens={...(payload.provider.tokens||{}),refreshToken:"",refresh_token:""};const upsert=(key,codexHome)=>{const current=elanous.providers[key]||{};elanous.providers[key]={...current,...payload.provider,codexHome,chatGPT:{...(current.chatGPT||{}),...(payload.provider.chatGPT||{})},tokens}};upsert("openai-codex",defaultHome);if(payload.storeKey!=="openai-codex")upsert(payload.storeKey,accountHome);write(elanousFile,elanous);',
|
|
470
|
+
'const incoming=payload.codexAuth;const installCodex=(home)=>{const file=path.join(home,"auth.json");fs.mkdirSync(home,{recursive:true,mode:0o700});const current=read(file),merged={...current,...incoming};merged.auth_mode=incoming.auth_mode;if(Object.prototype.hasOwnProperty.call(incoming,"last_refresh"))merged.last_refresh=incoming.last_refresh;else delete merged.last_refresh;merged.tokens={...(incoming.tokens||{}),refresh_token:"",refreshToken:""};write(file,merged)};installCodex(defaultHome);if(accountHome!==defaultHome)installCodex(accountHome);',
|
|
471
|
+
].join('');
|
|
472
|
+
const result = ssh(target.host, `umask 077; mkdir -p ${configDir} "$HOME/.codex" && bun -e ${shellQuote(code)} ${configDir}`, 20_000, payload);
|
|
473
|
+
if (result.status !== 0) throw new Error(`remote Codex access mirror failed (ssh rc=${result.status ?? 'unknown'})`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** Replace the remote Codex account set with one HQ-owned, refresh-free snapshot. */
|
|
477
|
+
export function installRemoteCodexAccessBatch(target: ParentHostConfig, mirrors: readonly { elanousAuth: string; codexAuth: string; account: string }[], ssh: SshRunner = defaultSshRunner): void {
|
|
478
|
+
if (!mirrors.length) throw new Error('Codex access mirror batch is empty');
|
|
479
|
+
const seen = new Set<string>();
|
|
480
|
+
const accounts = mirrors.map((mirror) => {
|
|
481
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(mirror.account) || seen.has(mirror.account)) throw new Error('invalid or duplicate Codex mirror account name');
|
|
482
|
+
seen.add(mirror.account);
|
|
483
|
+
let elanous: { version?: number; providers?: Record<string, Record<string, unknown>> };
|
|
484
|
+
let codex: { auth_mode?: string; tokens?: Record<string, unknown> };
|
|
485
|
+
try { elanous = JSON.parse(mirror.elanousAuth); codex = JSON.parse(mirror.codexAuth); }
|
|
486
|
+
catch { throw new Error('invalid local Codex access mirror'); }
|
|
487
|
+
const provider = elanous.providers?.['openai-codex'];
|
|
488
|
+
const token = provider?.tokens as Record<string, unknown> | undefined;
|
|
489
|
+
if (!Number.isSafeInteger(elanous.version) || Number(elanous.version) < 1
|
|
490
|
+
|| typeof token?.accessToken !== 'string' || !token.accessToken || token.refreshToken !== '' || token.refresh_token !== ''
|
|
491
|
+
|| codex.auth_mode !== 'chatgpt' || typeof codex.tokens?.access_token !== 'string' || !codex.tokens.access_token
|
|
492
|
+
|| codex.tokens.refresh_token !== '' || codex.tokens.refreshToken !== '')
|
|
493
|
+
throw new Error('Codex access mirror batch requires access tokens and empty refresh tokens');
|
|
494
|
+
return { account: mirror.account, provider, codexAuth: codex, version: elanous.version };
|
|
495
|
+
});
|
|
496
|
+
const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
|
|
497
|
+
const code = [
|
|
498
|
+
'const fs=require("node:fs"),path=require("node:path"),os=require("node:os");',
|
|
499
|
+
'const items=JSON.parse(fs.readFileSync(0,"utf8"));const dir=process.argv[1],file=path.join(dir,"auth.json"),defaultHome=path.join(dir,"codex-default"),managed=path.join(dir,"codex-accounts");',
|
|
500
|
+
'const read=(p)=>{try{return JSON.parse(fs.readFileSync(p,"utf8"))}catch{return {}}};',
|
|
501
|
+
'const write=(p,v)=>{fs.mkdirSync(path.dirname(p),{recursive:true,mode:0o700});const tmp=p+"."+process.pid+".tmp";try{fs.writeFileSync(tmp,JSON.stringify(v),{mode:0o600});fs.chmodSync(tmp,0o600);fs.renameSync(tmp,p)}catch(e){try{fs.unlinkSync(tmp)}catch{};throw e}};',
|
|
502
|
+
// A remote parent can launch concurrently with another parent. Serialize the
|
|
503
|
+
// entire auth-store + named-home transition, including stale-home pruning.
|
|
504
|
+
'const lock=path.join(dir,"remote-codex-mirror.lock"),deadline=Date.now()+15000,sleep=new Int32Array(new SharedArrayBuffer(4));fs.mkdirSync(dir,{recursive:true,mode:0o700});while(true){try{fs.writeFileSync(lock,String(process.pid),{flag:"wx",mode:0o600});break}catch(e){if(e.code!=="EEXIST")throw e;try{if(Date.now()-fs.statSync(lock).mtimeMs>60000)fs.rmSync(lock,{force:true})}catch{}if(Date.now()>=deadline)throw new Error("remote Codex mirror lock timeout");Atomics.wait(sleep,0,0,25)}}try{',
|
|
505
|
+
'const store=read(file);store.version=typeof store.version==="number"?store.version:items[0].version;store.providers={...(store.providers||{})};for(const key of Object.keys(store.providers)){if(key==="openai-codex"||key.startsWith("openai-codex:"))delete store.providers[key]}',
|
|
506
|
+
'for(const item of items){const home=item.account==="default"?defaultHome:path.join(managed,item.account),key=item.account==="default"?"openai-codex":"openai-codex:"+item.account;const current=read(path.join(home,"auth.json")),auth={...current,...item.codexAuth,auth_mode:"chatgpt",tokens:{...(item.codexAuth.tokens||{}),refresh_token:"",refreshToken:""}};write(path.join(home,"auth.json"),auth);store.providers[key]={...item.provider,codexHome:home,tokens:{...(item.provider.tokens||{}),refreshToken:"",refresh_token:""}}}',
|
|
507
|
+
'if(!store.providers["openai-codex"]){const first=items[0],home=path.join(managed,first.account);write(path.join(defaultHome,"auth.json"),{...first.codexAuth,auth_mode:"chatgpt",tokens:{...(first.codexAuth.tokens||{}),refresh_token:"",refreshToken:""}});store.providers["openai-codex"]={...store.providers["openai-codex:"+first.account],codexHome:defaultHome}}',
|
|
508
|
+
'write(file,store);const keep=new Set(items.filter(x=>x.account!=="default").map(x=>x.account));try{for(const name of fs.readdirSync(managed)){if(!keep.has(name))fs.rmSync(path.join(managed,name),{recursive:true,force:true})}}catch(e){if(e.code!=="ENOENT")throw e}fs.rmSync(path.join(dir,"remote-codex-mirror.json"),{force:true});',
|
|
509
|
+
'}finally{fs.rmSync(lock,{force:true})}',
|
|
510
|
+
].join('');
|
|
511
|
+
const result = ssh(target.host, `umask 077; mkdir -p ${configDir} "$HOME/.codex" && bun -e ${shellQuote(code)} ${configDir}`, 20_000, JSON.stringify(accounts));
|
|
512
|
+
if (result.status !== 0) throw new Error(`remote Codex access mirror batch failed (ssh rc=${result.status ?? 'unknown'})`);
|
|
513
|
+
}
|
|
514
|
+
|
|
305
515
|
// ── 관측: 원격 런 원장 거울 ─────────────────────────────────────────────────────────────
|
|
306
516
|
|
|
307
517
|
const RUN_ID_RE = /^run-[A-Za-z0-9_-]{4,64}$/;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
1
2
|
import { debug } from '../debug/log.js';
|
|
2
3
|
import { listChecklist, setItemIfSnapshot, type Checklist } from '../release-loop/checklist.js';
|
|
3
4
|
import { judgeLandedCell, parseJudgeSignals, type GreenVerdict } from '../release-loop/landed-to-green.js';
|
|
4
|
-
import { cardPrNumber, readTaskAgentState, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
|
|
5
|
+
import { HAND_MOVE_HISTORY_EVENT, LIVE_MOVE_HISTORY_EVENT, LIVE_MOVE_RESULT_EVENT, cardPrNumber, readTaskAgentState, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
|
|
5
6
|
import { isGoalOnlyPr } from './judge.js';
|
|
6
7
|
|
|
7
8
|
export interface LandedTaskPr { number: number; url: string; headRefOid: string; state: string; baseRefName: string; mergedAt: string; files?: Array<{ path: string }> }
|
|
@@ -142,3 +143,81 @@ export function closeMergedTaskCard(pr: LandedTaskPr, cwd: string, deps: Postlan
|
|
|
142
143
|
log('task-agent', 'postland-card-closed', { pr: pr.number, card: card.id, version, id: item.id, outcome: complete ? 'complete' : 'partial', verdict });
|
|
143
144
|
return item.id;
|
|
144
145
|
}
|
|
146
|
+
|
|
147
|
+
const defaultGit = (cwd: string, args: string[]): { status: number; stdout: string; stderr: string } => {
|
|
148
|
+
const run = spawnSync('git', args, { cwd, encoding: 'utf8' });
|
|
149
|
+
return { status: run.status ?? 1, stdout: run.stdout ?? '', stderr: run.stderr ?? '' };
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export type HandMergeReconcileOutcome =
|
|
153
|
+
| { outcome: 'reconciled'; card: string; status: 'landed-by-hand' | 'landed'; pr: number; head: string; mergeSha: string; mergedAt: string }
|
|
154
|
+
| { outcome: 'not-reconciled'; reason: 'pr-not-merged' | 'no-merge-sha' | 'no-bound-card' | 'ambiguous-card' | 'card-not-failed' | 'not-ancestor-of-main' | 'card-binding-changed-before-write' };
|
|
155
|
+
|
|
156
|
+
export interface HandMergeReconcileDeps {
|
|
157
|
+
statePath?: string;
|
|
158
|
+
mainRef?: string;
|
|
159
|
+
updateCard?: typeof updateTaskCard;
|
|
160
|
+
git?: (cwd: string, args: string[]) => { status: number; stdout: string; stderr: string };
|
|
161
|
+
log?: typeof debug.log;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* TA-CARD-MERGE-RECONCILE — 실패 카드에 묶인 PR을 사람이 손수 병합했을 때만 카드를 정산한다.
|
|
166
|
+
* MERGED + merge SHA가 `${mainRef}`(기본 `origin/main`) 조상일 때 status=landed-by-hand(또는 merge 커밋이
|
|
167
|
+
* land attempt head와 일치하면 landed)로 `updateTaskCard` 파일-락 트랜잭션 하나로 갱신하고,
|
|
168
|
+
* 이전 status·사유는 history `hand-move` 줄에 보존한다. OPEN·비조상·묶임 없음은 카드를 그대로 둔다.
|
|
169
|
+
*/
|
|
170
|
+
export function reconcileHandMergedCard(pr: LandedTaskPr & { mergeCommit?: string }, cwd: string, deps: HandMergeReconcileDeps = {}): HandMergeReconcileOutcome {
|
|
171
|
+
const log = deps.log ?? debug.log.bind(debug);
|
|
172
|
+
if (pr.state !== 'MERGED' || !pr.url) return { outcome: 'not-reconciled', reason: 'pr-not-merged' };
|
|
173
|
+
const mergeSha = pr.mergeCommit ?? '';
|
|
174
|
+
if (!/^[a-f0-9]{40}$/i.test(mergeSha)) return { outcome: 'not-reconciled', reason: 'no-merge-sha' };
|
|
175
|
+
const path = deps.statePath ?? taskAgentStatePath();
|
|
176
|
+
const tasks = readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(path).tasks ?? {};
|
|
177
|
+
const cards = Object.values(tasks).filter((card) => card.taLand && cardPrNumber(card) === pr.number
|
|
178
|
+
&& typeof card.pr === 'object' && card.pr.url?.replace(/\/+$/, '') === pr.url.replace(/\/+$/, ''));
|
|
179
|
+
if (cards.length !== 1) {
|
|
180
|
+
log('task-agent', 'postland-card-hand-skipped', { pr: pr.number, reason: cards.length ? 'ambiguous-card' : 'no-bound-card' });
|
|
181
|
+
return { outcome: 'not-reconciled', reason: cards.length ? 'ambiguous-card' : 'no-bound-card' };
|
|
182
|
+
}
|
|
183
|
+
const card = cards[0]!;
|
|
184
|
+
if (card.status !== 'failed') {
|
|
185
|
+
log('task-agent', 'postland-card-hand-skipped', { pr: pr.number, card: card.id, reason: 'card-not-failed', status: card.status });
|
|
186
|
+
return { outcome: 'not-reconciled', reason: 'card-not-failed' };
|
|
187
|
+
}
|
|
188
|
+
const mainRef = deps.mainRef ?? 'origin/main';
|
|
189
|
+
if ((deps.git ?? defaultGit)(cwd, ['merge-base', '--is-ancestor', mergeSha, mainRef]).status !== 0) {
|
|
190
|
+
log('task-agent', 'postland-card-hand-skipped', { pr: pr.number, card: card.id, reason: 'not-ancestor-of-main', mainRef });
|
|
191
|
+
return { outcome: 'not-reconciled', reason: 'not-ancestor-of-main' };
|
|
192
|
+
}
|
|
193
|
+
const at = new Date().toISOString();
|
|
194
|
+
let reconciled: { status: 'landed-by-hand' | 'landed' } | undefined;
|
|
195
|
+
// The card lock keeps the settlement atomic with its binding checks: a card that flipped off
|
|
196
|
+
// `failed` mid-flight is left untouched for its owning path to finish.
|
|
197
|
+
(deps.updateCard ?? updateTaskCard)(path, card.id, (current, currentTasks) => {
|
|
198
|
+
const matching = Object.values(currentTasks).filter((candidate) => candidate.taLand && cardPrNumber(candidate) === pr.number
|
|
199
|
+
&& typeof candidate.pr === 'object' && candidate.pr.url?.replace(/\/+$/, '') === pr.url.replace(/\/+$/, ''));
|
|
200
|
+
if (matching.length !== 1 || matching[0]?.id !== card.id) return undefined;
|
|
201
|
+
if (!current || current.status !== 'failed' || cardPrNumber(current) !== pr.number || typeof current.pr !== 'object'
|
|
202
|
+
|| current.pr.url?.replace(/\/+$/, '') !== pr.url.replace(/\/+$/, '')) return undefined;
|
|
203
|
+
const status = (current.landAttempts ?? []).some((attempt) => attempt.pr === pr.number
|
|
204
|
+
&& attempt.head.toLowerCase() === mergeSha.toLowerCase()) ? 'landed' : 'landed-by-hand';
|
|
205
|
+
const priorReason = [...current.history].reverse().find((event) => event.event !== LIVE_MOVE_HISTORY_EVENT
|
|
206
|
+
&& event.event !== LIVE_MOVE_RESULT_EVENT && event.event !== HAND_MOVE_HISTORY_EVENT)?.detail ?? '사유 기록 없음';
|
|
207
|
+
const detail = status === 'landed'
|
|
208
|
+
? `PR #${pr.number} 병합 정산: merge ${mergeSha}가 land attempt head와 일치 — status landed; 이전 status: failed; 이전 사유: ${priorReason}`
|
|
209
|
+
: `PR #${pr.number} 손 병합 정산: merge ${mergeSha}가 ${mainRef} 조상 — status landed-by-hand; 이전 status: failed; 이전 사유: ${priorReason}`;
|
|
210
|
+
reconciled = { status };
|
|
211
|
+
return { ...current,
|
|
212
|
+
status,
|
|
213
|
+
prTerminal: { pr: pr.number, url: pr.url, head: mergeSha, state: 'MERGED' as const, at },
|
|
214
|
+
history: [...current.history, { at, event: HAND_MOVE_HISTORY_EVENT, pr: pr.number, head: mergeSha, detail }],
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
if (!reconciled) {
|
|
218
|
+
log('task-agent', 'postland-card-hand-pending', { pr: pr.number, card: card.id, reason: 'card-binding-changed-before-write' });
|
|
219
|
+
return { outcome: 'not-reconciled', reason: 'card-binding-changed-before-write' };
|
|
220
|
+
}
|
|
221
|
+
log('task-agent', 'postland-card-hand-reconciled', { pr: pr.number, card: card.id, status: reconciled.status, mergeSha, mainRef });
|
|
222
|
+
return { outcome: 'reconciled', card: card.id, status: reconciled.status, pr: pr.number, head: pr.headRefOid, mergeSha, mergedAt: pr.mergedAt };
|
|
223
|
+
}
|
|
@@ -29,10 +29,13 @@
|
|
|
29
29
|
* - 관측: `task-agent` · `rejudge-on-head {card, pr, fromHead, toHead, step, decision, reason}` — 수가 난 판단은 카드 history 에도
|
|
30
30
|
* 한 줄(`event:'rejudge-on-head'` · 같은 머리·같은 단계·같은 판단은 한 번).
|
|
31
31
|
*/
|
|
32
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
32
|
+
import { closeSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
33
|
+
import { randomUUID } from 'node:crypto';
|
|
33
34
|
import { spawn, spawnSync } from 'node:child_process';
|
|
34
35
|
import { tmpdir } from 'node:os';
|
|
35
36
|
import { dirname, join } from 'node:path';
|
|
37
|
+
import { planPrLandRecovery, type PrLandRecoveryPlan } from '../cli/pr-land-recovery.js';
|
|
38
|
+
import { lastJsonObject, runGraph } from '../graph-runner/runner.js';
|
|
36
39
|
import { debug } from '../debug/log.js';
|
|
37
40
|
import { prodInstanceRoot } from '../instance/resolve.js';
|
|
38
41
|
import { getUserConfig } from '../user-config.js';
|
|
@@ -44,7 +47,7 @@ import { recordLiveMoveHistory } from './live-move-history.js';
|
|
|
44
47
|
import { runRepairCycle, type RepairLaunchRequest } from './repair-cycle.js';
|
|
45
48
|
import { repairMustFixFromReview, repairReviewDigest } from './repair-review.js';
|
|
46
49
|
import type { RepairCasOutcome, RepairCasRequest } from './repair-branch-cas.js';
|
|
47
|
-
import { defaultLandPrHead, defaultPrHead, defaultReviewRepoCandidates, executeLiveLand, executeLiveReview, landRetryPending, type LiveMoveDeps, type LiveMoveResult, type PrHeadView, type ReviewRepoCandidate, type TaskAgentLiveMove } from './live-moves.js';
|
|
50
|
+
import { configuredMsb1Worker, defaultLandPrHead, defaultPrHead, defaultReviewRepoCandidates, executeLiveLand, executeLiveReview, landRetryPending, remoteTaWorkerCommand, type LiveMoveDeps, type LiveMoveResult, type PrHeadView, type ReviewRepoCandidate, type TaskAgentLiveMove } from './live-moves.js';
|
|
48
51
|
import { capturedLandReview, captureReviewResults, parseReviewResultOutput, pendingReviewResults, reviewResultPath, type ParsedReviewResult } from './review-result-capture.js';
|
|
49
52
|
import { boundPrTerminal, cardPrNumber, LIVE_MOVE_RESULT_EVENT, readTaskCard, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
|
|
50
53
|
import { verifiedTrainLanding, type TrainLanding } from './train-landing.js';
|
|
@@ -98,6 +101,10 @@ export interface RejudgeDeps {
|
|
|
98
101
|
notifyRepair?: (seat: string, body: string) => void;
|
|
99
102
|
/** Shared new-launch budget for this `tasks rejudge --all` call. */
|
|
100
103
|
repairBudget?: import('./repair-cycle.js').RepairTickBudget;
|
|
104
|
+
/** One review request across all candidates in one --all tick; standalone card rejudge is uncapped. */
|
|
105
|
+
reviewBudget?: { max: number; requested: number };
|
|
106
|
+
/** One land or queue attempt across all candidates in one --all tick. */
|
|
107
|
+
landBudget?: { max: number; requested: number };
|
|
101
108
|
/** TA-REJUDGE-REBASE-LOOP — origin/main 을 PR 가지에 3-way merge 하고 일반 push. 시험은 주입한다. */
|
|
102
109
|
catchUpMain?: (request: CatchUpRequest) => Promise<CatchUpResult>;
|
|
103
110
|
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
@@ -265,12 +272,28 @@ export function regateRunArgs(entry: string, configDir: string, request: RegateR
|
|
|
265
272
|
return [entry, '--config-dir', configDir, 'tasks', 'regate-run', '--card', request.card, '--pr', String(request.pr), '--head', request.head, '--repo', request.repoRoot, '--out', request.resultPath];
|
|
266
273
|
}
|
|
267
274
|
|
|
268
|
-
export async function defaultRequestRegate(request: RegateRequest, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string } = {}): Promise<void> {
|
|
275
|
+
export async function defaultRequestRegate(request: RegateRequest, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string; remote?: import('./parent-host.js').ParentHostConfig | null } = {}): Promise<void> {
|
|
269
276
|
const { spawnDetachedConfirmed, ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
|
|
270
277
|
const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
|
|
271
278
|
const { effectiveInstanceRoot } = await import('../instance/resolve.js');
|
|
272
279
|
const configDir = opts.configDir ?? getElanousConfigDirOverride() ?? effectiveInstanceRoot();
|
|
273
|
-
|
|
280
|
+
const base = opts.spawn ?? (spawn as unknown as DetachedSpawn);
|
|
281
|
+
const remote = opts.remote === undefined ? (opts.spawn ? null : configuredMsb1Worker()) : opts.remote;
|
|
282
|
+
if (!remote) {
|
|
283
|
+
await spawnDetachedConfirmed(base, process.execPath, regateRunArgs(opts.entry ?? ELANOUS_CLI_ENTRY, configDir, request), undefined, request.repoRoot);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// The remote worker writes its own result, then SSH carries only that JSON into the HQ result path.
|
|
287
|
+
const remoteResult = `/tmp/elanous-ta-regate-${randomUUID()}.json`;
|
|
288
|
+
const script = `${remoteTaWorkerCommand(remote, ['tasks', 'regate-run', '--card', request.card, '--pr', String(request.pr),
|
|
289
|
+
'--head', request.head, '--repo', remote.cwd, '--out', remoteResult])} >/dev/null; rc=$?; cat '${remoteResult}'; rm -f '${remoteResult}'; exit $rc`;
|
|
290
|
+
mkdirSync(dirname(request.resultPath), { recursive: true });
|
|
291
|
+
const fd = openSync(request.resultPath, 'w');
|
|
292
|
+
const toFile: DetachedSpawn = (command, args, options) =>
|
|
293
|
+
(base as unknown as (c: string, a: string[], o: unknown) => ReturnType<DetachedSpawn>)(command, args, { ...options, stdio: ['ignore', fd, 'ignore'] });
|
|
294
|
+
try {
|
|
295
|
+
await spawnDetachedConfirmed(toFile, 'ssh', ['-T', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=5', remote.host, script]);
|
|
296
|
+
} finally { closeSync(fd); }
|
|
274
297
|
}
|
|
275
298
|
|
|
276
299
|
/** 재게이트 결과 파일 — `tasks regate-run` 이 쓴다. */
|
|
@@ -513,6 +536,19 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
513
536
|
}
|
|
514
537
|
const step = (s: RejudgeStep, decision: string, reason: string, record: boolean, extra: Partial<RejudgeOutcome> = {}) =>
|
|
515
538
|
emit({ card: card!.id, pr, fromHead, toHead, step: s, decision, reason, ...extra }, record);
|
|
539
|
+
const requestReview = async (candidate: TaskCard, reason: string, forceNewReview = false): Promise<void> => {
|
|
540
|
+
const budget = deps.reviewBudget;
|
|
541
|
+
if (budget && budget.requested >= budget.max) {
|
|
542
|
+
step('review', 'tick-cap', `review request cap ${budget.max} reached — next tick`, false);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
// Reserve before awaiting the worker so another candidate cannot launch a second request.
|
|
546
|
+
if (budget) budget.requested++;
|
|
547
|
+
const before = { reviewRequests: candidate.reviewRequests, landAttempts: candidate.landAttempts };
|
|
548
|
+
const result = await executeLiveReview(candidate, pr, { runId: candidate.runId ?? null, stopReason: reason, cwd, forceNewReview }, { ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
549
|
+
recordMove(statePath, candidate.id, candidate.runId, 'review', result, pr, before, now, deps.log);
|
|
550
|
+
step('review', result.executed ? 'review-requested' : 'review-request-failed', result.detail, true);
|
|
551
|
+
};
|
|
516
552
|
|
|
517
553
|
// Adoption is a first judgement for the current head, even when the implementation run
|
|
518
554
|
// already asked for a review. A captured failure needs repair; an accepted result must
|
|
@@ -526,10 +562,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
526
562
|
} else if (!deps.liveMoves.has('review')) {
|
|
527
563
|
step('review', 'would-review', 'adopted PR first judgement · review not enabled in HQ taskAgent.liveMoves — shadow', false);
|
|
528
564
|
} else {
|
|
529
|
-
|
|
530
|
-
const result = await executeLiveReview(card, pr, { runId: card.runId ?? null, stopReason: 'adopted-pr-first-judgement', cwd }, { ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
531
|
-
recordMove(statePath, card.id, card.runId, 'review', result, pr, before, now, deps.log);
|
|
532
|
-
step('review', result.executed ? 'review-requested' : 'review-request-failed', result.detail, true);
|
|
565
|
+
await requestReview(card, 'adopted-pr-first-judgement');
|
|
533
566
|
}
|
|
534
567
|
return outcomes;
|
|
535
568
|
}
|
|
@@ -618,12 +651,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
618
651
|
|
|
619
652
|
if (!reviews.length) {
|
|
620
653
|
if (!deps.liveMoves.has('review')) step('review', 'would-review', 'remote run terminal proven · review not enabled in HQ taskAgent.liveMoves — shadow', false);
|
|
621
|
-
else
|
|
622
|
-
const before = { reviewRequests: card.reviewRequests, landAttempts: card.landAttempts };
|
|
623
|
-
const result = await executeLiveReview(card, pr, { runId: card.runId ?? null, stopReason: 'remote-run-terminal', cwd }, { ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
624
|
-
recordMove(statePath, card.id, card.runId, 'review', result, pr, before, now, deps.log);
|
|
625
|
-
step('review', result.executed ? 'review-requested' : 'review-request-failed', result.detail, true);
|
|
626
|
-
}
|
|
654
|
+
else await requestReview(card, 'remote-run-terminal');
|
|
627
655
|
return outcomes;
|
|
628
656
|
}
|
|
629
657
|
|
|
@@ -642,10 +670,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
642
670
|
if (pendingReviewResults(latest).some((entry) => entry.pr === pr && sameHead(entry.head, toHead))) {
|
|
643
671
|
step('review', 'awaiting-review-result', 'exact-head review result pending', false);
|
|
644
672
|
} else if (!latest.reviewRequests?.some((entry) => entry.pr === pr && sameHead(entry.head, toHead)) && deps.liveMoves.has('review')) {
|
|
645
|
-
|
|
646
|
-
const result = await executeLiveReview(latest, pr, { runId: latest.runId ?? null, stopReason: 'queue-exact-head', cwd }, { ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
647
|
-
recordMove(statePath, latest.id, latest.runId, 'review', result, pr, before, now, deps.log);
|
|
648
|
-
step('review', result.executed ? 'review-requested' : 'review-request-failed', result.detail, true);
|
|
673
|
+
await requestReview(latest, 'queue-exact-head');
|
|
649
674
|
} else step('review', 'not-landing', 'exact-head PASS/WARN mf0 review not captured', true);
|
|
650
675
|
return outcomes;
|
|
651
676
|
}
|
|
@@ -654,8 +679,13 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
654
679
|
const reviewResult = latest.reviewRequests?.find((entry) => entry.pr === pr && sameHead(entry.head, toHead) && entry.resultPath)?.resultPath;
|
|
655
680
|
if (!reviewResult) { step('land', 'not-landing', 'exact-head review JSON path missing', true); return outcomes; }
|
|
656
681
|
const before = { reviewRequests: latest.reviewRequests, landAttempts: latest.landAttempts };
|
|
682
|
+
if (deps.landBudget && deps.landBudget.requested >= deps.landBudget.max) {
|
|
683
|
+
step('land', 'tick-cap', `land attempt cap ${deps.landBudget.max} reached — next tick`, false);
|
|
684
|
+
return outcomes;
|
|
685
|
+
}
|
|
657
686
|
const queued = await executeLiveLand(latest, pr, { runId: latest.runId ?? null, cycleId: `queue:${latest.id}:${toHead}`, cwd,
|
|
658
687
|
review, reviewResultPath: reviewResult }, { ...live, landQueueConfig: queueMode, ...(deps.log ? { log: deps.log } : {}) });
|
|
688
|
+
if (deps.landBudget && queued.executed) deps.landBudget.requested++;
|
|
659
689
|
recordMove(statePath, latest.id, latest.runId, 'propose-land', queued, pr, before, now, deps.log);
|
|
660
690
|
step('land', queued.queued ? 'queued' : queued.ok && !queued.executed ? 'queue-skipped' : 'queue-refused', queued.detail, true);
|
|
661
691
|
return outcomes;
|
|
@@ -778,12 +808,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
778
808
|
// ② 리뷰 — 지금 머리로 요청한 적이 없으면 다시(같은 머리는 한 번 · 상한은 ① 의 머리 수가 이미 막았다).
|
|
779
809
|
if (!reviews.some((entry) => sameHead(entry.head, toHead))) {
|
|
780
810
|
if (!deps.liveMoves.has('review')) step('review', 'would-review', 'review not enabled in taskAgent.liveMoves — shadow', false);
|
|
781
|
-
else
|
|
782
|
-
const before = { reviewRequests: card.reviewRequests, landAttempts: card.landAttempts };
|
|
783
|
-
const result = await executeLiveReview(card, pr, { runId: card.runId ?? null, stopReason: 'rejudge-on-head', cwd }, { ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
784
|
-
recordMove(statePath, card.id, card.runId, 'review', result, pr, before, now, deps.log);
|
|
785
|
-
step('review', result.executed ? 'review-requested' : 'review-request-failed', result.detail, true);
|
|
786
|
-
}
|
|
811
|
+
else await requestReview(card, 'rejudge-on-head');
|
|
787
812
|
return outcomes;
|
|
788
813
|
}
|
|
789
814
|
const latest = readTaskCard(card.id, statePath) ?? card;
|
|
@@ -828,10 +853,15 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
828
853
|
return outcomes;
|
|
829
854
|
}
|
|
830
855
|
const before = { reviewRequests: latest.reviewRequests, landAttempts: latest.landAttempts };
|
|
856
|
+
if (deps.landBudget && deps.landBudget.requested >= deps.landBudget.max) {
|
|
857
|
+
step('land', 'tick-cap', `land attempt cap ${deps.landBudget.max} reached — next tick`, false);
|
|
858
|
+
return outcomes;
|
|
859
|
+
}
|
|
831
860
|
// 주기 id — base-stale 재게이트 뒤의 land 는 새 base 를 붙여 앞 land 의 주기 표시(모듈 전역)와 갈린다 · gateAt 이 앞 base-stale 시도를 소비한다.
|
|
832
861
|
const cycleId = `rejudge:${card.id}:${toHead}${regate.staleBase ? `:${regate.baseCommit.slice(0, 12)}` : ''}`;
|
|
833
862
|
const landed = await executeLiveLand(latest, pr, { runId: card.runId ?? null, cycleId, cwd, review, reviewResultPath: reviewResult, overlapEvidence, gateAt: regate.at },
|
|
834
863
|
{ ...live, ...(deps.log ? { log: deps.log } : {}) });
|
|
864
|
+
if (deps.landBudget && landed.executed) deps.landBudget.requested++;
|
|
835
865
|
// LAND-ORDER-LEDGER — executeLiveLand 직후 원장 한 줄(같은 pr+head 는 한 줄만). 쓰기가 실패해도 land 결과는 그대로(삼킨다).
|
|
836
866
|
const landOrderLog = (event: 'appended' | 'append-failed') => { try { log('task-agent.land-order', event, { pr, head: toHead }); } catch { /* fail-soft */ } };
|
|
837
867
|
try {
|
|
@@ -844,6 +874,38 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
844
874
|
landOrderLog('append-failed');
|
|
845
875
|
}
|
|
846
876
|
recordMove(statePath, card.id, card.runId, 'propose-land', landed, pr, before, now, deps.log);
|
|
877
|
+
if (landed.executed && !landed.ok && /^✗/.test(landed.detail)) {
|
|
878
|
+
const context = { refusal: landed.detail, pr, head: toHead };
|
|
879
|
+
const preliminary = planPrLandRecovery(context);
|
|
880
|
+
if (preliminary.result.action === 'request-review' || preliminary.result.action === 'wait-retry') {
|
|
881
|
+
const entry = preliminary.result.action;
|
|
882
|
+
try {
|
|
883
|
+
const graphPath = entry === 'request-review' ? '../../graphs/units/task-agent-recover-review.yaml' : '../../graphs/units/task-agent-recover-wait.yaml';
|
|
884
|
+
const graph = await runGraph(join(import.meta.dir, graphPath), {
|
|
885
|
+
input: { ask: `TA land refusal for PR #${pr}`, context, prior: {} },
|
|
886
|
+
pinChildUniverse: true,
|
|
887
|
+
deps: { root: dirname(statePath) },
|
|
888
|
+
});
|
|
889
|
+
const output = lastJsonObject(graph.nodes.find((node) => node.nodeId === 'recover')?.output);
|
|
890
|
+
const plan = graph.status === 'done' && graph.unitCalls?.[0]?.entry === entry
|
|
891
|
+
&& graph.unitCalls[0].exit === 'rework' ? output as unknown as PrLandRecoveryPlan | undefined : undefined;
|
|
892
|
+
const action = plan?.result?.action;
|
|
893
|
+
const matched = plan?.outcome === 'rework' && plan.result.pr === pr && plan.result.head === toHead
|
|
894
|
+
&& action === preliminary.result.action && plan.evidence?.refusal === context.refusal.slice(0, 500)
|
|
895
|
+
&& (action !== 'wait-retry' || plan.result.delayMs === 30_000);
|
|
896
|
+
if (!matched) step('land', 'recover-untrusted', `recover@1 ${entry} produced no pinned matching action`, true);
|
|
897
|
+
else if (action === 'request-review' && deps.liveMoves.has('review')) {
|
|
898
|
+
await requestReview(readTaskCard(card.id, statePath) ?? card, 'land-refusal-review-missing', true);
|
|
899
|
+
} else if (action === 'request-review') {
|
|
900
|
+
step('review', 'recover-review-disabled', 'recover@1 selected review but taskAgent.liveMoves excludes review', true);
|
|
901
|
+
} else if (action === 'wait-retry') {
|
|
902
|
+
step('land', 'recover-wait-retry', `recover@1 ${entry} selected existing retry admission after ${plan.result.delayMs}ms`, true);
|
|
903
|
+
} else step('land', 'recover-needs-human', `recover@1 ${entry}: ${plan.result.reason}`, true);
|
|
904
|
+
} catch (error) {
|
|
905
|
+
step('land', 'recover-failed', `recover@1 ${entry}: ${String(error).slice(0, 200)}`, true);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
847
909
|
// TA-LAND-RETRY-ON-INFRA — 실패한 시도는 갈래·사유·재시도 여부를 사유 줄에 싣는다(다음 틱이 왜 다시 하는지/안 하는지).
|
|
848
910
|
const attempt = landed.landAttempt?.class
|
|
849
911
|
? ` · land-class ${landed.landAttempt.class} (${landed.landAttempt.reason}) · attempt ${landed.landAttempt.attempt} · ${landed.landAttempt.class === 'base-stale' ? 'base-stale → re-gate on a new base next tick (cap counts)' : landed.landAttempt.retryAllowed ? 'retry allowed on this head' : 'no retry on this head'}`
|
|
@@ -862,11 +924,35 @@ function recordMove(statePath: string, cardId: string, runId: string | undefined
|
|
|
862
924
|
}
|
|
863
925
|
|
|
864
926
|
/** 재판정 대상 카드 — 기존 리뷰 또는 HQ 가 종결 원장을 검증할 원격 부모 카드. */
|
|
865
|
-
export function rejudgeCandidates(tasks: Readonly<Record<string, TaskCard
|
|
927
|
+
export function rejudgeCandidates(tasks: Readonly<Record<string, TaskCard>>, opts: {
|
|
928
|
+
now?: Date; maxAgeHours?: number; onAgeSkip?: (card: TaskCard, ageHours: number | null) => void;
|
|
929
|
+
/** Fresh remote PR heads; mf0 only gets priority when it matches this head. */
|
|
930
|
+
currentHeads?: ReadonlyMap<string, string>;
|
|
931
|
+
} = {}): string[] {
|
|
932
|
+
const now = opts.now?.getTime() ?? Date.now();
|
|
933
|
+
const maxAgeHours = opts.maxAgeHours;
|
|
866
934
|
return Object.values(tasks).filter((card) => {
|
|
867
935
|
const pr = cardPrNumber(card);
|
|
868
|
-
|
|
936
|
+
const eligible = pr !== undefined && !boundPrTerminal(card) && ((card.reviewRequests ?? []).some((entry) => entry.pr === pr)
|
|
869
937
|
|| (card.status === 'launched' && card.taLand === true && ((!!card.parentHost && !!card.runId && !!card.runChildId)
|
|
870
938
|
|| (card.adoptedPr?.pr === pr && typeof card.pr === 'object' && !!card.pr.url && sameUrl(card.adoptedPr.url, card.pr.url)))));
|
|
939
|
+
if (!eligible) return false;
|
|
940
|
+
if (maxAgeHours !== undefined) {
|
|
941
|
+
const created = Date.parse(card.createdAt);
|
|
942
|
+
const ageHours = Number.isFinite(created) ? Math.max(0, (now - created) / 3_600_000) : null;
|
|
943
|
+
if (ageHours === null || ageHours > maxAgeHours) { opts.onAgeSkip?.(card, ageHours); return false; }
|
|
944
|
+
}
|
|
945
|
+
return true;
|
|
946
|
+
}).sort((a, b) => {
|
|
947
|
+
const hasMf0 = (card: TaskCard): number => {
|
|
948
|
+
const pr = cardPrNumber(card);
|
|
949
|
+
const head = card.reviewRequests?.filter((entry) => entry.pr === pr).at(-1)?.head;
|
|
950
|
+
const currentHead = opts.currentHeads?.get(card.id);
|
|
951
|
+
return pr !== undefined && head && currentHead?.toLowerCase() === head.toLowerCase()
|
|
952
|
+
&& capturedLandReview(card, pr, head)?.mustFixCount === 0 ? 1 : 0;
|
|
953
|
+
};
|
|
954
|
+
const ageOrder = (Number.isFinite(Date.parse(b.createdAt)) ? Date.parse(b.createdAt) : 0)
|
|
955
|
+
- (Number.isFinite(Date.parse(a.createdAt)) ? Date.parse(a.createdAt) : 0);
|
|
956
|
+
return hasMf0(b) - hasMf0(a) || ageOrder || a.id.localeCompare(b.id);
|
|
871
957
|
}).map((card) => card.id);
|
|
872
958
|
}
|