elanous 0.2.35 → 0.2.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{d06f9160.a3d9062f95de8ad7.js → 053a429e.9a63436527cc751c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
- package/apps/pwa/out/_next/static/chunks/{4346.8601952e73bf5803.js → 1201.afbfc5b1c5e5cbe4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
- package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
- package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3103.0df8da390948bb84.js → 2500.cbc1257b774aae52.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 2683.c9773a0c589b031b.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 275-02ea4c2a33980422.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +1 -0
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8714.ff0b7ce3ec3e3ae2.js → 2941.3c3546f96bc6efa7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 2986.45d7652e4f13557e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3136.30aaaa5fa03662a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3677-4215f826f6aa68e5.js → 3148-98efd4869d660a87.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +226 -0
- package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324.a09703033abcbd2f.js +34 -0
- package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
- package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +32 -0
- package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
- package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 3727.7949ccaacaa71242.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 3757-180308bc61021b05.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 3840-5825d56d46976a92.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 4286.b70c4520306817e8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 4615.8525eb0add35eba6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
- package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 528.38ce20ef8aa251ff.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 552.b7d061ad91eeac51.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5711.957b095705c12560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 575.d929793a53f27c4b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +41 -0
- package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
- package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
- package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 6943.c6b24124853a47b2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{630.fe5a46428d63b013.js → 727.7deb87749b0a343a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 7481.39f7a4654907bf6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 771.c3cdb6c1f7f47c02.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3589.5444a06bcf6e775c.js → 7891.03f910124a737985.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
- package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 873d6c12.09bd499f57171543.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 8904.7d51af2dc033965c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{5637.281e5dec4ea6ecf1.js → 914.8abefd48d579547b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 9250-072df22eaadaa6b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
- package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8637.47f5b35afcae5e6b.js → 9514.131c52cc75fe6439.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1674.2a65fd5668e1cc5f.js → 9789.60f723d18097ec30.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → ceba0382.650712b56b85b582.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → da5ecc5c-b005ad8cac737d57.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{56d372f2.681ab4ec4c998fae.js → f9a61e4d.1fc2c1dbdd49fe46.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
- package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
- 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/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +3 -0
- package/graphs/default-loop.yaml +6 -1
- package/graphs/implement-loop.yaml +24 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/wizard/recipes.yaml +44 -0
- package/graphs/wizard/wizard-loop.yaml +44 -0
- package/graphs/work/research-report.yaml +2 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +139 -5
- package/scripts/coord-role-pack.ts +1 -1
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/release-loop/docs-node.ts +204 -8
- package/scripts/release-loop/gate-node.ts +249 -53
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +37 -11
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/ux-sim.ts +53 -0
- package/skills/README.md +1 -0
- package/src/acp/core-turn-bridge.ts +48 -6
- package/src/agent/delegate-hint.ts +16 -0
- package/src/agent/runner.ts +82 -2
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/pr-reviewer.ts +55 -3
- package/src/agent-substrate/review-intent.ts +29 -2
- package/src/agent-substrate/review-observation.ts +3 -0
- package/src/agent-substrate/self-review-cli.ts +168 -16
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +25 -5
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/usage-outcomes.ts +8 -4
- package/src/capture/tui-self-report.ts +102 -0
- package/src/chat/goal-continue-verdict.ts +41 -0
- package/src/chat/index.ts +30 -4
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/tool-render/block.ts +32 -0
- package/src/chat/tool-render/dispatch.ts +2 -20
- package/src/chat/tool-render/result-text.ts +98 -0
- package/src/chat/turn-typeahead.ts +70 -7
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/doctor-cli.ts +22 -0
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +6 -3
- package/src/cli/log-event-names.ts +2 -0
- package/src/cli/make-cli.ts +247 -11
- package/src/cli/msg-cli.ts +117 -3
- package/src/cli/pr-cli.ts +29 -16
- package/src/cli/pr-land-base-read.ts +11 -2
- package/src/cli/pr-land-heavy-remote.ts +6 -3
- package/src/cli/pr-land-overlap-evidence.ts +23 -4
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-cli.ts +21 -5
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +574 -356
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/core-turn/run-core-turn.ts +4 -2
- package/src/core-turn/run-goal-loop.ts +73 -16
- package/src/core-turn/types.ts +6 -1
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +202 -49
- package/src/dashboard/input/agent-wake.ts +7 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
- package/src/dashboard/input/chat-main-slash-command.ts +4 -2
- package/src/dashboard/input/goal-continue.ts +210 -0
- package/src/dashboard/input/goal-interim.ts +2 -0
- package/src/dashboard/input/internal-turn.ts +2 -8
- package/src/dashboard/input/seat-autowake.ts +9 -7
- package/src/dashboard/input/turn-autoheal.ts +52 -0
- package/src/dashboard/seat-boot-preamble.ts +132 -5
- package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
- package/src/dashboard/slash-runtime/model-choices.ts +15 -0
- package/src/dashboard/stale-install-check.ts +3 -99
- package/src/debug/batch-queue.ts +119 -0
- package/src/debug/tui-log-tag.ts +67 -0
- package/src/display/agent-surface.ts +7 -0
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/esc-abort-gate.ts +69 -0
- package/src/git-fs/worktree.ts +95 -1
- package/src/graph-runner/graph-cli.ts +18 -0
- package/src/graph-runner/runner.ts +20 -11
- package/src/graph-wizard/generate.ts +108 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +51 -7
- package/src/harness/harness-incidents.ts +52 -1
- package/src/harness/pod-control-send.ts +33 -5
- package/src/harness/self-send-remote.ts +69 -0
- package/src/harness/self-send-routing-guard.ts +6 -0
- package/src/harness/self-send-target.ts +4 -3
- package/src/index.ts +327 -12
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/light-cli.ts +6 -1
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +35 -4
- package/src/loops/msg-wake.ts +35 -39
- package/src/loops/orchestrator/inbox.ts +59 -11
- package/src/loops/orchestrator/knowhow-pack.ts +364 -0
- package/src/loops/orchestrator/tick.ts +5 -1
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/models/prompts.ts +17 -2
- package/src/msg/msg-post-office.ts +116 -0
- package/src/mss/logging/log-store.ts +79 -22
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +20 -2
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/overview-collect.ts +12 -6
- package/src/ops/overview.ts +3 -3
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/prompt-library/session-guidance.ts +14 -0
- package/src/provider-summary.ts +8 -0
- package/src/pty-shell/herdr-agent-report.ts +118 -9
- package/src/pty-shell/herdr-prompt.ts +266 -0
- package/src/pty-shell/pty-control-ipc.ts +151 -8
- package/src/pty-shell/pty-special-keys.ts +42 -2
- package/src/pty-shell/stale-install-check.ts +99 -0
- package/src/pty-shell/tui-run-state.ts +14 -2
- package/src/release-loop/auto-start.ts +20 -2
- package/src/release-loop/checklist.ts +76 -4
- package/src/release-loop/rehearsal.ts +36 -20
- package/src/repl/index.ts +19 -1
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/self-dev/decompose-proposal.ts +172 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +37 -3
- package/src/self-dev/dev-pipeline.ts +8 -2
- package/src/self-dev/draft-triage-rules.ts +31 -0
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-journey-nodes.ts +1 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +239 -1
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +265 -4
- package/src/self-implement/goal-author.ts +33 -8
- package/src/self-implement/goal-elaborate.ts +176 -22
- package/src/self-implement/goal-refine.ts +3 -0
- package/src/self-implement/graph-variant.ts +40 -6
- package/src/self-implement/headless-elanous-driver.ts +19 -3
- package/src/self-implement/off-diff-evidence.ts +58 -6
- package/src/self-implement/orchestrator.ts +222 -21
- package/src/self-implement/pod-warm-pool-profile.ts +1 -0
- package/src/self-implement/pwa-import-graph.ts +1 -1
- package/src/self-implement/rework-policy.ts +30 -0
- package/src/self-implement/run-ledger.ts +108 -0
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/scope-adjacency.ts +3 -1
- package/src/self-implement/seams.ts +60 -4
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +290 -48
- package/src/skills/tools/schedule-wakeup.ts +23 -4
- package/src/skills/tools/shell.ts +61 -6
- package/src/skills/tools/terminal-modal-inject.ts +1 -2
- package/src/skills/tools/terminal-modal.ts +10 -8
- package/src/skills/url-router.ts +41 -1
- package/src/smart-wizard/run.ts +66 -0
- package/src/status/bar.ts +34 -6
- package/src/status/status-provider-info.ts +37 -6
- package/src/steward/rejudge-tick.ts +10 -2
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/task-agent/actions.ts +3 -1
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +22 -6
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/rejudge-on-head.ts +15 -0
- package/src/task-agent/repair-cycle.ts +138 -32
- package/src/task-agent/repair-next-move.ts +31 -3
- package/src/task-agent/repair-outcomes.ts +29 -0
- package/src/task-agent/repair-worker.ts +14 -4
- package/src/task-agent/shadow.ts +41 -3
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +477 -22
- package/src/task-agent/task-parent-role-llm.ts +36 -0
- package/src/task-agent/tier-split.ts +78 -9
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
- package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +485 -36
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +396 -19
- package/src/task-orchestrator/surfaces/self-implement.ts +42 -2
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tty-foreground.ts +155 -0
- package/src/tui/chat/goal-interim.ts +173 -0
- package/src/tui/chat/log-view.ts +205 -18
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +370 -81
- package/src/tui/input/composer.ts +8 -1
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +1 -7
- package/src/tui/slash/resume.ts +75 -0
- package/src/tui-client/local-chat-turn.ts +45 -2
- package/src/tui-client/next-dashboard-runtime.ts +8 -0
- package/src/tui-client/next-loop-command.ts +70 -0
- package/src/tui-client/next-wakeup.ts +191 -0
- package/src/tui.ts +37 -0
- package/src/ui/modal-adapter.ts +2 -2
- package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
- package/src/ux-sim/cli-config-audit-device.ts +121 -0
- package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
- package/src/ux-sim/event-monkey.ts +3 -2
- package/src/ux-sim/fake-bin.ts +45 -0
- package/src/ux-sim/fake-herdr.ts +238 -0
- package/src/ux-sim/fake-llm.ts +111 -6
- package/src/ux-sim/fault-glm-no-credential.ts +116 -0
- package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
- package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
- package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
- package/src/ux-sim/goal-device.ts +619 -0
- package/src/ux-sim/in-process-cli.ts +22 -5
- package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
- package/src/ux-sim/mock-authoring-first-run.ts +97 -0
- package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
- package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
- package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
- package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
- package/src/ux-sim/onboarding-first-run-device.ts +269 -0
- package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
- package/src/ux-sim/subagent-tools-device.ts +81 -0
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
- package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +0 -1
- package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
- package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +0 -122
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5483-dd5d7697f6bdb106.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-dc0a532f5b9196ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
- /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Parent-only role selection for Task Agent launches. The child model is a separate axis. */
|
|
2
|
+
import { parseRoleLlmFlags } from '../llm/role-llm-cli.js';
|
|
3
|
+
import { isModelRole, parseRoleLlmEntry, roleLlmEnvName, type ModelRole, type RoleLlmSpec } from '../user-config.js';
|
|
4
|
+
|
|
5
|
+
const PARENT_ROLES = new Set<ModelRole>(['planning', 'classify', 'audit', 'review']);
|
|
6
|
+
|
|
7
|
+
export function taskParentRoleEnv(values: readonly string[]): Record<string, string> {
|
|
8
|
+
const env: Record<string, string> = {};
|
|
9
|
+
for (const value of values) {
|
|
10
|
+
const at = value.indexOf('=');
|
|
11
|
+
const role = value.slice(0, at);
|
|
12
|
+
if (at < 1 || !isModelRole(role) || !PARENT_ROLES.has(role)) {
|
|
13
|
+
throw new Error(`--role-llm 부모 역할이 아니다: ${JSON.stringify(value)}`);
|
|
14
|
+
}
|
|
15
|
+
let spec: RoleLlmSpec;
|
|
16
|
+
const raw = value.slice(at + 1);
|
|
17
|
+
if (raw.startsWith('{')) {
|
|
18
|
+
let parsed: unknown;
|
|
19
|
+
try { parsed = JSON.parse(raw); }
|
|
20
|
+
catch { throw new Error(`--role-llm JSON 을 읽을 수 없다: ${role}`); }
|
|
21
|
+
const entry = parseRoleLlmEntry(parsed);
|
|
22
|
+
if (!entry.ok) throw new Error(`--role-llm ${role}: ${entry.reason}`);
|
|
23
|
+
spec = entry.spec;
|
|
24
|
+
} else {
|
|
25
|
+
const parsed = parseRoleLlmFlags([value]);
|
|
26
|
+
if (!parsed.ok) throw new Error(`--role-llm ${parsed.message}`);
|
|
27
|
+
const selected = parsed.overrides[role];
|
|
28
|
+
if (!selected) throw new Error(`--role-llm 선택한 역할이 비었다: ${role}`);
|
|
29
|
+
spec = selected;
|
|
30
|
+
}
|
|
31
|
+
const name = roleLlmEnvName(role);
|
|
32
|
+
if (env[name] !== undefined) throw new Error(`--role-llm 같은 부모 역할을 두 번 고정했다: ${role}`);
|
|
33
|
+
env[name] = JSON.stringify(spec);
|
|
34
|
+
}
|
|
35
|
+
return env;
|
|
36
|
+
}
|
|
@@ -6,16 +6,19 @@
|
|
|
6
6
|
* - 분해 규칙은 TC 몫 — 여기는 그 함수를 «주입 seam» 으로 받는다. 기본 seam 은 이 파일 한 곳(`DEFAULT_TIER_SIZED_DECOMPOSE`)에서만 정한다.
|
|
7
7
|
* - 분해기 «미배선»(seam 에 undefined 명시) = `decomposer-unavailable` → 종전처럼 한 덩어리 발사 ⊕ 기록. 기본 seam 은 TC 함수다.
|
|
8
8
|
* - 분해 «실패»(ok:false · throw · 불가피 이유 없는 상 조각 · 빈/잘못된 조각) → 발사 0 · 카드 failed(history `tier-split-failed`).
|
|
9
|
-
* - 관측: `debug.log('task-agent.hand', 'tier-split', {cid, fromTier, outcome, reason?, slices, unavoidable
|
|
9
|
+
* - 관측: `debug.log('task-agent.hand', 'tier-split', {cid, fromTier, outcome, reason?, slices, unavoidable,
|
|
10
|
+
* countScope:'accepted-slices', totalSlices, highSlices, unavoidableCount, unavoidableReasons})`.
|
|
10
11
|
*/
|
|
11
12
|
import { randomBytes } from 'node:crypto';
|
|
13
|
+
import { resolve } from 'node:path';
|
|
12
14
|
import { debug } from '../debug/log.js';
|
|
13
|
-
import { handTask, TASK_CARD_PREFIX, type HandTaskOptions, type HandTaskResult } from './task-hand.js';
|
|
15
|
+
import { handTask, nextMoveFor, parseChildLlm, taskAgentStatePath, updateTaskCard, writeTaskCards, TASK_CARD_PREFIX, type HandTaskOptions, type HandTaskResult, type TaskCard } from './task-hand.js';
|
|
14
16
|
|
|
15
17
|
// 분해 규칙·타입 정본 = TC `src/self-implement/goal-author-decompose.ts`(TIER-SIZED-DECOMPOSE · #29987).
|
|
16
18
|
import { decomposeToTierSizedSlices, type SizedSlice, type TierSizedDecomposeResult } from '../self-implement/goal-author-decompose.js';
|
|
19
|
+
import { DEVICE_FIRST_STEP } from '../self-implement/device-first.js';
|
|
17
20
|
export type { SizedSlice, TierSizedDecomposeResult };
|
|
18
|
-
export type TierSizedDecompose = (goal: string, opts?: { signal?: AbortSignal }) => Promise<TierSizedDecomposeResult>;
|
|
21
|
+
export type TierSizedDecompose = (goal: string, opts?: { signal?: AbortSignal; repositoryRoot?: string }) => Promise<TierSizedDecomposeResult>;
|
|
19
22
|
|
|
20
23
|
/** 기본 분해기 — TC `decomposeToTierSizedSlices`. seam 에 undefined 를 명시하면 «미배선»(decomposer-unavailable). */
|
|
21
24
|
export const DEFAULT_TIER_SIZED_DECOMPOSE: TierSizedDecompose | undefined = decomposeToTierSizedSlices;
|
|
@@ -40,7 +43,9 @@ export function composeSliceHandText(sliceGoal: string, parentText: string, mark
|
|
|
40
43
|
const label = INHERITED_PARENT_LABELS.exec(line)?.[1];
|
|
41
44
|
return label !== undefined && !sliceHas.has(label);
|
|
42
45
|
});
|
|
43
|
-
|
|
46
|
+
// The slice marker also carries review scope. Device slices now own their
|
|
47
|
+
// completion boundary, so inherited can be empty while the marker is needed.
|
|
48
|
+
if (inherited.length === 0 && (marker.total < 2 || !sliceGoal.includes(`동작: ${DEVICE_FIRST_STEP}`))) return sliceGoal;
|
|
44
49
|
const tag = `조각 ${marker.index}/${marker.total} — 부모 ${marker.cid ?? '(칸 없음)'}(${marker.fromTier}) 를 중 이하로 나눈 몫. 아래 계약·완료 경계는 부모 칸에서 물려받았다 — 이 조각 범위만 채운다.`;
|
|
45
50
|
return [...sliceLines, tag, ...inherited].join('\n');
|
|
46
51
|
}
|
|
@@ -58,6 +63,12 @@ export function planTierSplit(result: TierSizedDecomposeResult): TierSplitPlan {
|
|
|
58
63
|
if (!slice.goal?.trim()) return { kind: 'blocked', reason: `empty-slice-goal: #${index + 1}` };
|
|
59
64
|
if (slice.tier === '상' && !slice.unavoidable?.trim()) return { kind: 'blocked', reason: `unjustified-상-slice: #${index + 1}` };
|
|
60
65
|
}
|
|
66
|
+
const deviceSlices = result.slices.filter((slice) => slice.deviceFirst === 'device-test');
|
|
67
|
+
if (deviceSlices.length === 0 && result.slices.some((slice) => slice.deviceFirst === 'feature'))
|
|
68
|
+
return { kind: 'blocked', reason: 'device-first-stage-missing' };
|
|
69
|
+
if (deviceSlices.length > 0 && (deviceSlices.length !== 1 || result.slices[0]?.deviceFirst !== 'device-test'
|
|
70
|
+
|| result.slices.slice(1).some((slice) => slice.deviceFirst !== 'feature')))
|
|
71
|
+
return { kind: 'blocked', reason: 'device-first-order-invalid' };
|
|
61
72
|
return { kind: 'split', slices: result.slices };
|
|
62
73
|
}
|
|
63
74
|
|
|
@@ -78,6 +89,14 @@ function record(data: Record<string, unknown>): void {
|
|
|
78
89
|
try { debug.log('task-agent.hand', 'tier-split', data); } catch { /* fail-soft */ }
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
function acceptedSliceCounts(slices: readonly SizedSlice[]) {
|
|
93
|
+
const unavoidableReasons = slices.filter((slice) => slice.tier === '상').map((slice) => slice.unavoidable!.trim());
|
|
94
|
+
// planTierSplit rejects every high slice without a reason, so the accepted
|
|
95
|
+
// high count and unavoidable count coincide. Keep both for the board axes.
|
|
96
|
+
return { countScope: 'accepted-slices' as const, totalSlices: slices.length, highSlices: unavoidableReasons.length,
|
|
97
|
+
unavoidableCount: unavoidableReasons.length, unavoidableReasons };
|
|
98
|
+
}
|
|
99
|
+
|
|
81
100
|
/**
|
|
82
101
|
* `tasks hand` 의 발사 앞단. 분해는 `--live` ⊕ tier 상|특 일 때만 — 중·하·tier 없음·shadow 는 `handTask` 그대로(분해 호출 0).
|
|
83
102
|
*/
|
|
@@ -88,7 +107,7 @@ export async function handTaskWithTierSplit(opts: TierSplitHandOptions): Promise
|
|
|
88
107
|
const decompose = 'decompose' in opts ? injected : DEFAULT_TIER_SIZED_DECOMPOSE;
|
|
89
108
|
const cid = hand.checklistId ?? null;
|
|
90
109
|
if (!decompose) {
|
|
91
|
-
record({ cid, fromTier, outcome: 'whole', reason: TIER_SPLIT_UNAVAILABLE, slices: [], unavoidable: [] });
|
|
110
|
+
record({ cid, fromTier, outcome: 'whole', reason: TIER_SPLIT_UNAVAILABLE, slices: [], unavoidable: [], ...acceptedSliceCounts([]) });
|
|
92
111
|
return { kind: 'whole', result: await handTask(hand), reason: TIER_SPLIT_UNAVAILABLE };
|
|
93
112
|
}
|
|
94
113
|
let plan: TierSplitPlan;
|
|
@@ -96,24 +115,74 @@ export async function handTaskWithTierSplit(opts: TierSplitHandOptions): Promise
|
|
|
96
115
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
97
116
|
const timedOut = new Promise<'timeout'>((resolve) => { timer = setTimeout(() => { controller.abort(); resolve('timeout'); }, decomposeTimeoutMs); });
|
|
98
117
|
try {
|
|
99
|
-
const raced = await Promise.race([decompose(hand.text.trim(), { signal: controller.signal
|
|
118
|
+
const raced = await Promise.race([decompose(hand.text.trim(), { signal: controller.signal,
|
|
119
|
+
...(hand.project ? { repositoryRoot: resolve(hand.project.target) } : {}) }), timedOut]);
|
|
100
120
|
plan = raced === 'timeout' ? { kind: 'blocked', reason: `decompose-timeout: ${decomposeTimeoutMs}ms` } : planTierSplit(raced);
|
|
101
121
|
} catch (error) {
|
|
102
122
|
plan = { kind: 'blocked', reason: `decompose-threw: ${String((error as Error)?.message ?? error).slice(0, 200)}` };
|
|
103
123
|
} finally { clearTimeout(timer); }
|
|
104
124
|
if (plan.kind === 'blocked') {
|
|
105
|
-
record({ cid, fromTier, outcome: 'blocked', reason: plan.reason, slices: [], unavoidable: [] });
|
|
125
|
+
record({ cid, fromTier, outcome: 'blocked', reason: plan.reason, slices: [], unavoidable: [], ...acceptedSliceCounts([]) });
|
|
106
126
|
return { kind: 'blocked', result: await handTask({ ...hand, tierSplitBlocked: plan.reason }), reason: plan.reason };
|
|
107
127
|
}
|
|
108
128
|
const group = `${TASK_CARD_PREFIX}split-${randomBytes(4).toString('hex')}`;
|
|
109
129
|
const total = plan.slices.length;
|
|
110
|
-
const
|
|
130
|
+
const counts = acceptedSliceCounts(plan.slices);
|
|
131
|
+
const unavoidable = counts.unavoidableReasons;
|
|
111
132
|
// 조각은 새 카드다 — 호출자 id·pr·goalId 를 조각마다 복제하면 «PR: #N» 조회·수확이 엇갈린다. 버린 것은 기록에 남긴다.
|
|
112
133
|
const dropped = { ...(hand.id ? { id: hand.id } : {}), ...(hand.cardFields?.pr !== undefined ? { pr: hand.cardFields.pr } : {}), ...(hand.cardFields?.goalId !== undefined ? { goalId: hand.cardFields.goalId } : {}) };
|
|
113
|
-
record({ cid, fromTier, outcome: 'split', group, ...(Object.keys(dropped).length ? { dropped } : {}), slices: plan.slices.map((s) => ({ tier: s.tier, files: s.files, behaviours: s.behaviours })), unavoidable
|
|
134
|
+
record({ cid, fromTier, outcome: 'split', group, ...(Object.keys(dropped).length ? { dropped } : {}), slices: plan.slices.map((s) => ({ tier: s.tier, files: s.files, behaviours: s.behaviours })), unavoidable: [...unavoidable],
|
|
135
|
+
...counts });
|
|
114
136
|
const { id: _wholeId, cardFields, ...rest } = hand;
|
|
115
137
|
const base = { ...rest, ...(cardFields?.handed !== undefined ? { cardFields: { handed: cardFields.handed } } : {}) };
|
|
116
138
|
const slices: TierSplitSliceOutcome[] = [];
|
|
139
|
+
// Device-first plans use the existing mission advance engine: only the test/device card starts.
|
|
140
|
+
// Feature cards carry an explicit `after` edge and `tasks advance` requires a merged PR before launch.
|
|
141
|
+
if (plan.slices[0]?.deviceFirst === 'device-test') {
|
|
142
|
+
const now = (hand.now ?? (() => new Date()))().toISOString();
|
|
143
|
+
const ids = plan.slices.map((_slice, index) => `${group}-${index + 1}`);
|
|
144
|
+
const mission: TaskCard = { id: group, text: hand.text, createdAt: now, status: 'handed', history: [],
|
|
145
|
+
pieces: ids, splitSource: 'device-first-tier-split', ...(hand.checklistId ? { checklistId: hand.checklistId } : {}),
|
|
146
|
+
...(hand.seat ? { seat: hand.seat } : {}) };
|
|
147
|
+
const drafts: TaskCard[] = plan.slices.map((slice, index) => ({
|
|
148
|
+
id: ids[index]!, text: composeSliceHandText(slice.goal, hand.text, { index: index + 1, total, fromTier, cid }),
|
|
149
|
+
createdAt: now, status: 'handed', history: [], mission: group,
|
|
150
|
+
after: index === 0 ? [] : [ids[0]!], tier: slice.tier,
|
|
151
|
+
tierSplit: { group, fromTier, index: index + 1, total, ...(slice.tier === '상' ? { unavoidable: slice.unavoidable!.trim() } : {}) },
|
|
152
|
+
...(hand.checklistId ? { checklistId: hand.checklistId } : {}),
|
|
153
|
+
...(hand.seat ? { seat: hand.seat } : {}),
|
|
154
|
+
...(hand.project ? { project: hand.project } : {}),
|
|
155
|
+
...(hand.completion ? { completion: hand.completion } : {}),
|
|
156
|
+
...(hand.taLand ? { taLand: true as const } : {}),
|
|
157
|
+
...(hand.childLlm ? { childLlm: parseChildLlm(hand.childLlm, hand.childLlmEffort) } : {}),
|
|
158
|
+
...(hand.parentRoleLlm?.length ? { parentRoleLlm: [...hand.parentRoleLlm] } : {}),
|
|
159
|
+
}));
|
|
160
|
+
writeTaskCards(hand.statePath ?? taskAgentStatePath(), [mission, ...drafts]);
|
|
161
|
+
const markFirstLaunchFailure = (reason: string) => {
|
|
162
|
+
updateTaskCard(hand.statePath ?? taskAgentStatePath(), group, (card) => card ? {
|
|
163
|
+
...card, status: 'failed', history: [...card.history, { at: new Date().toISOString(),
|
|
164
|
+
event: 'device-first-launch-failed', detail: reason }],
|
|
165
|
+
} : undefined);
|
|
166
|
+
};
|
|
167
|
+
for (const [index, slice] of plan.slices.entries()) {
|
|
168
|
+
if (index > 0) {
|
|
169
|
+
slices.push({ slice, result: { card: drafts[index]!, move: nextMoveFor(drafts[index]!), mode: hand.live ? 'live' : 'shadow', launched: false } });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const result = await handTask({ ...base, id: ids[0], text: drafts[0]!.text, tier: slice.tier,
|
|
174
|
+
mission: group, after: [], tierSplit: drafts[0]!.tierSplit });
|
|
175
|
+
slices.push({ slice, result });
|
|
176
|
+
if (hand.live && !result.launched) markFirstLaunchFailure(`first card not launched: ${result.card.status}`);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
179
|
+
slices.push({ slice, error: reason });
|
|
180
|
+
markFirstLaunchFailure(reason);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
record({ cid, fromTier, outcome: 'device-first-deferred', group, first: ids[0], blockedUntilLanded: ids.slice(1) });
|
|
184
|
+
return { kind: 'split', group, fromTier, slices };
|
|
185
|
+
}
|
|
117
186
|
for (const [index, slice] of plan.slices.entries()) {
|
|
118
187
|
try {
|
|
119
188
|
const result = await handTask({ ...base, text: composeSliceHandText(slice.goal, hand.text, { index: index + 1, total, fromTier, cid }), tier: slice.tier,
|
|
@@ -126,8 +126,17 @@ export function planPodAccounts(
|
|
|
126
126
|
export function planOwnerCodexMirrorCandidates(candidates: readonly RotationCandidate[], options: {
|
|
127
127
|
accountOrder: readonly string[];
|
|
128
128
|
thresholdPercentByAccount?: Readonly<Record<string, unknown>>;
|
|
129
|
+
creditsAllowed?: boolean;
|
|
130
|
+
creditReserve?: number;
|
|
129
131
|
}): RotationCandidate[] {
|
|
130
132
|
const usable = new Set(planPodAccounts(candidates, { thresholdPercentByAccount: options.thresholdPercentByAccount }).usable);
|
|
133
|
+
// The parent has to install an access mirror before the remote Pod can use its
|
|
134
|
+
// credit fallback. Only a measured balance above the reserve admits that mirror.
|
|
135
|
+
if (usable.size === 0 && options.creditsAllowed) {
|
|
136
|
+
const reserve = typeof options.creditReserve === 'number' && Number.isFinite(options.creditReserve) && options.creditReserve >= 0
|
|
137
|
+
? options.creditReserve : CODEX_CREDIT_RESERVE_DEFAULT;
|
|
138
|
+
return creditCandidatesByBalance(candidates, reserve);
|
|
139
|
+
}
|
|
131
140
|
const rank = (name: string): number => {
|
|
132
141
|
const index = options.accountOrder.indexOf(name);
|
|
133
142
|
return index < 0 ? options.accountOrder.length : index;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { decidePodReuseCleanup } from './pod-reuse-cleanup.js';
|
|
2
|
+
import type { WarmWorkerKey } from './pod-warm-worker-protocol.js';
|
|
3
|
+
|
|
4
|
+
/** An admitted si-v1 worker is identified by the pool, never by a Job name alone. */
|
|
5
|
+
export interface ChildPodLease {
|
|
6
|
+
workerId: string;
|
|
7
|
+
podUid: string;
|
|
8
|
+
leaseId: string;
|
|
9
|
+
generation: number;
|
|
10
|
+
key: WarmWorkerKey;
|
|
11
|
+
sourceSha: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ChildPodReuseCommandResult {
|
|
15
|
+
status: number | null;
|
|
16
|
+
stdout?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ChildPodCleanupReceipt {
|
|
20
|
+
clean: boolean;
|
|
21
|
+
reason: string;
|
|
22
|
+
/** Known residual lower bound; null means unmeasured surfaces and no observed residue. */
|
|
23
|
+
observedResidue: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Operations execute inside the admitted worker, after its child result and artifacts have been collected. */
|
|
27
|
+
export interface ChildPodReuseOperations {
|
|
28
|
+
stopChildProcesses: (lease: ChildPodLease) => Promise<{ remaining: number }>;
|
|
29
|
+
git: (lease: ChildPodLease, args: readonly string[]) => Promise<ChildPodReuseCommandResult>;
|
|
30
|
+
removeRunCredentials: (lease: ChildPodLease) => Promise<{ remaining: number }>;
|
|
31
|
+
returnLease: (lease: ChildPodLease, receipt: ChildPodCleanupReceipt) => Promise<void>;
|
|
32
|
+
quarantine: (lease: ChildPodLease, receipt: ChildPodCleanupReceipt) => Promise<void>;
|
|
33
|
+
observe: (event: 'return-decision' | 'clean-failed' | 'quarantine-failed', data: Record<string, unknown>) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ChildPodReturnResult {
|
|
37
|
+
outcome: 'returned' | 'quarantined';
|
|
38
|
+
reason: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A completed child may return to the pool only after all four independent
|
|
43
|
+
* checks succeed. A missing return-decision observation also blocks return;
|
|
44
|
+
* the worker stays out of the lease pool until quarantine succeeds.
|
|
45
|
+
*/
|
|
46
|
+
export async function cleanAndReturnChildPod(
|
|
47
|
+
lease: ChildPodLease,
|
|
48
|
+
ops: ChildPodReuseOperations,
|
|
49
|
+
): Promise<ChildPodReturnResult> {
|
|
50
|
+
const facts = { workerId: lease.workerId, podUid: lease.podUid,
|
|
51
|
+
leaseId: lease.leaseId, generation: lease.generation };
|
|
52
|
+
const log = (event: Parameters<ChildPodReuseOperations['observe']>[0], data: Record<string, unknown>) => {
|
|
53
|
+
try { ops.observe(event, { ...facts, ...data }); } catch { /* logging must not return an unsafe lease */ }
|
|
54
|
+
};
|
|
55
|
+
let reason = '';
|
|
56
|
+
let observedResidue = 0;
|
|
57
|
+
let processMeasured = false;
|
|
58
|
+
let gitMeasured = false;
|
|
59
|
+
let credentialsMeasured = false;
|
|
60
|
+
let credentialsRemoved = false;
|
|
61
|
+
try {
|
|
62
|
+
if (!lease.workerId || !lease.podUid || !lease.leaseId || !lease.key
|
|
63
|
+
|| !Number.isSafeInteger(lease.generation) || lease.generation < 1
|
|
64
|
+
|| !lease.key.context || !lease.key.architecture
|
|
65
|
+
|| !/^sha256:[0-9a-f]{64}$/.test(lease.key.imageDigest)
|
|
66
|
+
|| !/^[0-9a-f]{64}$/.test(lease.key.lockHash)
|
|
67
|
+
|| !/^[0-9a-f]{40}$/.test(lease.sourceSha)) {
|
|
68
|
+
reason = 'invalid-lease';
|
|
69
|
+
} else {
|
|
70
|
+
const stopped = await ops.stopChildProcesses(lease);
|
|
71
|
+
if (Number.isSafeInteger(stopped.remaining) && stopped.remaining >= 0) {
|
|
72
|
+
observedResidue += stopped.remaining;
|
|
73
|
+
processMeasured = true;
|
|
74
|
+
}
|
|
75
|
+
if (!Number.isSafeInteger(stopped.remaining) || stopped.remaining !== 0) {
|
|
76
|
+
reason = 'child-processes-remain';
|
|
77
|
+
} else {
|
|
78
|
+
const plan = decidePodReuseCleanup({ base: lease.sourceSha, resetExitCode: 0,
|
|
79
|
+
cleanExitCode: 0, statusExitCode: 0, statusPorcelain: '' });
|
|
80
|
+
const reset = await ops.git(lease, plan.resetArgs);
|
|
81
|
+
if (reset.status !== 0) reason = 'reset-failed';
|
|
82
|
+
else {
|
|
83
|
+
const clean = await ops.git(lease, plan.cleanArgs);
|
|
84
|
+
if (clean.status !== 0) reason = 'clean-failed';
|
|
85
|
+
else {
|
|
86
|
+
const status = await ops.git(lease, plan.statusArgs);
|
|
87
|
+
if (status.status === 0 && typeof status.stdout === 'string') {
|
|
88
|
+
observedResidue += status.stdout.split('\0').filter(Boolean).length;
|
|
89
|
+
gitMeasured = true;
|
|
90
|
+
}
|
|
91
|
+
const decision = decidePodReuseCleanup({ base: lease.sourceSha,
|
|
92
|
+
resetExitCode: reset.status, cleanExitCode: clean.status,
|
|
93
|
+
statusExitCode: status.status, statusPorcelain: status.stdout ?? '' });
|
|
94
|
+
if (status.status === 0 && typeof status.stdout !== 'string') reason = 'status-unavailable';
|
|
95
|
+
else if (decision.outcome !== 'reuse') reason = decision.reason ?? 'worktree-not-clean';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
reason = `cleanup-error:${error instanceof Error ? error.message : String(error)}`;
|
|
102
|
+
}
|
|
103
|
+
// A failed process or Git check never skips credential revocation.
|
|
104
|
+
try {
|
|
105
|
+
const credentials = await ops.removeRunCredentials(lease);
|
|
106
|
+
credentialsRemoved = credentials.remaining === 0;
|
|
107
|
+
if (Number.isSafeInteger(credentials.remaining) && credentials.remaining >= 0) {
|
|
108
|
+
observedResidue += credentials.remaining;
|
|
109
|
+
credentialsMeasured = true;
|
|
110
|
+
}
|
|
111
|
+
if (!credentialsRemoved && !reason) reason = 'credentials-remain';
|
|
112
|
+
} catch (error) {
|
|
113
|
+
const credentialReason = `credential-revoke-error:${error instanceof Error ? error.message : String(error)}`;
|
|
114
|
+
reason = reason ? `${reason};${credentialReason}` : credentialReason;
|
|
115
|
+
}
|
|
116
|
+
if (!reason && credentialsRemoved) {
|
|
117
|
+
try {
|
|
118
|
+
// Git clean and credential revocation can reveal child processes that appeared after the
|
|
119
|
+
// pre-cleanup survey. A lease returns clean only when the re-survey immediately before
|
|
120
|
+
// returnLease also reports zero remaining processes.
|
|
121
|
+
const resurvey = await ops.stopChildProcesses(lease);
|
|
122
|
+
if (!Number.isSafeInteger(resurvey.remaining) || resurvey.remaining !== 0) {
|
|
123
|
+
reason = 'child-processes-resurfaced';
|
|
124
|
+
if (Number.isSafeInteger(resurvey.remaining) && resurvey.remaining > 0) observedResidue += resurvey.remaining;
|
|
125
|
+
} else {
|
|
126
|
+
// Eligibility is observed only after the final process re-survey succeeds.
|
|
127
|
+
ops.observe('return-decision', { ...facts, outcome: 'eligible' });
|
|
128
|
+
await ops.returnLease(lease, { clean: true, reason: 'clean', observedResidue: 0 });
|
|
129
|
+
log('return-decision', { outcome: 'returned' });
|
|
130
|
+
return { outcome: 'returned', reason: 'clean' };
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
reason = `return-or-observation-error:${error instanceof Error ? error.message : String(error)}`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
log('clean-failed', { reason });
|
|
137
|
+
try { await ops.quarantine(lease, { clean: false, reason,
|
|
138
|
+
observedResidue: observedResidue > 0 || (processMeasured && gitMeasured && credentialsMeasured)
|
|
139
|
+
? observedResidue : null }); }
|
|
140
|
+
catch (error) {
|
|
141
|
+
log('quarantine-failed', { reason, error: error instanceof Error ? error.message : String(error) });
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
log('return-decision', { outcome: 'quarantined', reason });
|
|
145
|
+
return { outcome: 'quarantined', reason };
|
|
146
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// codex·elanous 자격 파일은 이 Job 에 없다. 격리 관문(호스트 넥서스에 닿으면 종료)은 기존 Job 과 같다.
|
|
6
6
|
// 명령 인자는 셸 문자열로 이어붙이지 않고 `"$@"` 로 따로 인용한다.
|
|
7
7
|
|
|
8
|
-
import { randomBytes } from 'node:crypto';
|
|
8
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
10
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { isAbsolute, resolve } from 'node:path';
|
|
@@ -229,12 +229,18 @@ export interface PodCommandJobInput {
|
|
|
229
229
|
/** W5 — emptyDir{medium: Memory} sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH} ⊕ `TMPDIR` (release gate shards only). Omitted = image `/tmp`. */
|
|
230
230
|
tmpfsSizeLimit?: string;
|
|
231
231
|
source?: PodSource;
|
|
232
|
+
/** Verified producer files, delivered into this Job's own source tree. */
|
|
233
|
+
warmFiles?: readonly string[];
|
|
232
234
|
deadlineSeconds: number;
|
|
233
235
|
runId?: string;
|
|
234
236
|
/** GATE-WARM-BOOT-NO-INIT fallback: the node-side hand-over did not run, so a root init container hands the hostPath dirs to uid 1000. */
|
|
235
237
|
hostDirsInit?: boolean;
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
function warmSourceName(name: string, launch: string): string {
|
|
241
|
+
return `${name.slice(0, 50).replace(/-+$/, '')}-${launch}`;
|
|
242
|
+
}
|
|
243
|
+
|
|
238
244
|
function bashSingleQuote(value: string): string {
|
|
239
245
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
240
246
|
}
|
|
@@ -282,6 +288,10 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
282
288
|
...(o.clone
|
|
283
289
|
? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl)]
|
|
284
290
|
: ['mkdir -p ~/work && cd ~/work']),
|
|
291
|
+
...(o.warmFiles?.length ? [
|
|
292
|
+
`if [ "$(git rev-parse HEAD)" != ${bashSingleQuote(o.source?.kind === 'commit' ? o.source.sha : '')} ]; then echo '[warm-source] commit mismatch'; exit 5; fi`,
|
|
293
|
+
...o.warmFiles.map((path, i) => `install -m 644 -D /warm-source/file-${i} ${bashSingleQuote(`./${path}`)} || exit 5\nprintf 'ELANOUS_WARM_SOURCE %s %s %s\\n' ${bashSingleQuote(path)} "$(sha256sum ${bashSingleQuote(`./${path}`)} | cut -d ' ' -f1)" "$(git rev-parse HEAD)"`),
|
|
294
|
+
] : []),
|
|
285
295
|
...(hostDirMounts.length ? [podHostDirsCheckScript(hostDirMounts)] : []),
|
|
286
296
|
...(bunCache ? [bunCache.shellPrefix] : []),
|
|
287
297
|
`set -- ${quotedArgs}`,
|
|
@@ -325,14 +335,16 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
325
335
|
...(provenance?.env ?? []),
|
|
326
336
|
...(tmpfs ? [{ name: 'TMPDIR', value: POD_TMPFS_MOUNT_PATH }] : []),
|
|
327
337
|
],
|
|
328
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumeMounts: [
|
|
338
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs || o.warmFiles?.length ? { volumeMounts: [
|
|
339
|
+
...(o.warmFiles?.length ? [{ name: 'warm-source', mountPath: '/warm-source', readOnly: true }] : []),
|
|
329
340
|
...(secretKeys ? [{ name: 'creds', mountPath: '/creds', readOnly: true }] : []),
|
|
330
341
|
...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : []),
|
|
331
342
|
...hostDirMounts,
|
|
332
343
|
...tmpfsMounts,
|
|
333
344
|
] } : {}),
|
|
334
345
|
}],
|
|
335
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumes: [
|
|
346
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs || o.warmFiles?.length ? { volumes: [
|
|
347
|
+
...(o.warmFiles?.length ? [{ name: 'warm-source', configMap: { name: warmSourceName(o.name, o.launch ?? 'source') } }] : []),
|
|
336
348
|
...(secretKeys ? [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] : []),
|
|
337
349
|
...(o.hostMirror ? [{ name: 'host-mirror', hostPath: { path: o.hostMirror, type: 'Directory' } }] : []),
|
|
338
350
|
...(bunCache ? [bunCache.volume] : []),
|
|
@@ -422,6 +434,8 @@ export interface RunPodCommandOptions {
|
|
|
422
434
|
/** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
|
|
423
435
|
lite?: boolean;
|
|
424
436
|
source?: PodSource;
|
|
437
|
+
/** Opt-in handoff from an existing producer Pod in the same namespace. */
|
|
438
|
+
warmProducer?: { pod: string; podUid: string; context: string; image: string; commit: string; files: readonly [string, string] };
|
|
425
439
|
ghToken?: () => string;
|
|
426
440
|
deadlineSeconds?: number;
|
|
427
441
|
namespace?: string;
|
|
@@ -553,6 +567,12 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
553
567
|
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
|
|
554
568
|
const namespace = options.namespace ?? 'elanous-test';
|
|
555
569
|
const image = options.image ?? podCommandImageFor(skills, options.clone === true, options.lite === true);
|
|
570
|
+
if (options.warmProducer && (!options.clone || options.source?.kind !== 'commit' || options.source.sha !== options.warmProducer.commit || options.image !== options.warmProducer.image || options.imageCommit !== options.warmProducer.commit)) {
|
|
571
|
+
throw new Error('pod warm source: consumer image and source commit must match producer');
|
|
572
|
+
}
|
|
573
|
+
if (options.warmProducer && (!/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(options.warmProducer.pod) || !options.warmProducer.podUid || typeof options.warmProducer.context !== 'string' || !/^[0-9a-f]{40}$/.test(options.warmProducer.commit) || options.warmProducer.files.length !== 2 || options.warmProducer.files.some((path) => !path || path.startsWith('/') || path.split('/').some((part) => !part || part === '.' || part === '..' || !/^[\w.-]+$/.test(part))))) {
|
|
574
|
+
throw new Error('pod warm source: invalid producer identity, commit or file path');
|
|
575
|
+
}
|
|
556
576
|
if (options.shelfImage && (options.image !== options.shelfImage || !options.imageCommit || !options.clone || options.source?.kind !== 'commit' || options.source.sha !== options.imageCommit)) {
|
|
557
577
|
throw new Error('pod shelf: image and source commit must match');
|
|
558
578
|
}
|
|
@@ -615,6 +635,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
615
635
|
const kubectlRaw: Kubectl = (args, stdin) => baseKubectl(context ? ['--context', context, ...args] : [...args], stdin);
|
|
616
636
|
const kubectl: Kubectl = (args, stdin) => { ensureLive(); const result = kubectlRaw(args, stdin); ensureLive(); return result; };
|
|
617
637
|
const cleanupSecret = () => { kubectlRaw(['-n', namespace, 'delete', 'secret', '-l', own, '--ignore-not-found']); };
|
|
638
|
+
const cleanupWarmSource = () => {
|
|
639
|
+
if (options.warmProducer) kubectlRaw(['-n', namespace, 'delete', 'configmap', '-l', own, '--ignore-not-found']);
|
|
640
|
+
};
|
|
618
641
|
const artifactRoot = options.artifactsRoot ?? `${effectiveInstanceRoot()}/pod-artifacts`;
|
|
619
642
|
const artifactsDir = `${artifactRoot}/${name}`;
|
|
620
643
|
let jobApplied = false;
|
|
@@ -648,7 +671,11 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
648
671
|
const localSkillsDigest = options.kubectl ? null : image === POD_LITE_IMAGE
|
|
649
672
|
? podSkillsDigest(POD_NETWORK_SKILLS, resolve(import.meta.dir, '../../../skills')).digest
|
|
650
673
|
: podSkillsDigest(resolvePodSkills(env).skills).digest;
|
|
651
|
-
if (options.
|
|
674
|
+
if (options.warmProducer) {
|
|
675
|
+
// The leased producer is already running this immutable image on the selected pool.
|
|
676
|
+
// Do not replace it with the host's independently synchronized commit tag.
|
|
677
|
+
member = { ...member, imageRef: options.warmProducer.image };
|
|
678
|
+
} else if (options.shelfImage) {
|
|
652
679
|
const found = (options.shelfLookup ?? registryImageRef)(member, imageCommit);
|
|
653
680
|
if (found !== options.shelfImage) throw new Error(`pod shelf: selected image unavailable on ${member.context}`);
|
|
654
681
|
member = { ...member, imageRef: found };
|
|
@@ -671,6 +698,33 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
671
698
|
.catch((error: unknown) => ({ host: member!.sshHost!, ok: false, ms: 0, detail: String(error).slice(0, 300) })), options.signal);
|
|
672
699
|
log('pod.command-job', 'mirror-seed', { host: member.sshHost, commit: options.source.sha, ok: seed?.ok ?? false, ms: seed?.ms ?? 0, ...(seed?.detail ? { detail: seed.detail } : {}) });
|
|
673
700
|
}
|
|
701
|
+
// Only a matching, live producer may hand its two source files to this Job; no other Pod's tree is trusted.
|
|
702
|
+
const warmHashes: Record<string, string> = {};
|
|
703
|
+
if (options.warmProducer) {
|
|
704
|
+
const producer = options.warmProducer;
|
|
705
|
+
if (context !== producer.context || (imageRef && imageRef !== producer.image)) throw new Error('pod warm source: selected pool or image differs from producer');
|
|
706
|
+
const got = kubectl(['-n', namespace, 'get', 'pod', producer.pod, '-o', 'json']);
|
|
707
|
+
if (got.status !== 0) throw new Error('pod warm source: producer Pod unavailable');
|
|
708
|
+
let pod: { metadata?: { name?: string; uid?: string }; spec?: { containers?: Array<{ name?: string; image?: string }> } };
|
|
709
|
+
try { pod = JSON.parse(got.stdout); } catch { throw new Error('pod warm source: invalid producer Pod'); }
|
|
710
|
+
if (pod.metadata?.name !== producer.pod || pod.metadata?.uid !== producer.podUid || pod.spec?.containers?.find((container) => container.name === 'child')?.image !== producer.image) {
|
|
711
|
+
throw new Error('pod warm source: producer Pod identity or image mismatch');
|
|
712
|
+
}
|
|
713
|
+
// kubectl exec starts in the image working directory; podSourceScript cloned
|
|
714
|
+
// `repo` there, then changed directory only in the original Job shell.
|
|
715
|
+
const head = kubectl(['-n', namespace, 'exec', producer.pod, '-c', 'child', '--', 'bash', '-c', 'git -C repo rev-parse HEAD']);
|
|
716
|
+
if (head.status !== 0 || head.stdout.trim() !== producer.commit) throw new Error('pod warm source: producer commit mismatch');
|
|
717
|
+
const binaryData: Record<string, string> = {};
|
|
718
|
+
for (const [i, path] of producer.files.entries()) {
|
|
719
|
+
const read = kubectl(['-n', namespace, 'exec', producer.pod, '-c', 'child', '--', 'bash', '-c', `base64 -w0 ${bashSingleQuote(`repo/${path}`)}`]);
|
|
720
|
+
if (read.status !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(read.stdout.trim())) throw new Error(`pod warm source: producer file unavailable: ${path}`);
|
|
721
|
+
binaryData[`file-${i}`] = read.stdout.trim();
|
|
722
|
+
warmHashes[path] = createHash('sha256').update(Buffer.from(binaryData[`file-${i}`]!, 'base64')).digest('hex');
|
|
723
|
+
}
|
|
724
|
+
const config = { apiVersion: 'v1', kind: 'ConfigMap', metadata: { name: warmSourceName(name, launch), namespace, labels: { 'elanous.job': name, 'elanous.launch': launch } }, binaryData };
|
|
725
|
+
const applied = kubectl(['apply', '-f', '-'], JSON.stringify(config));
|
|
726
|
+
if (applied.status !== 0) throw new Error(applied.stderr.trim() || 'pod warm source: ConfigMap apply failed');
|
|
727
|
+
}
|
|
674
728
|
// GATE-WARM-BOOT-NO-INIT (10-15): the hostPath dirs the uid-1000 child writes are handed over on the node itself, once per
|
|
675
729
|
// member·paths in this process (no init container). Best effort: a failure only logs; the child then falls back.
|
|
676
730
|
const hostDirPaths = [...(bunCache ? [bunCache] : []), ...(installSlots ? [installSlots] : [])];
|
|
@@ -701,7 +755,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
701
755
|
provenance: options.provenance, provenanceGate: options.provenanceGate,
|
|
702
756
|
...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
|
|
703
757
|
repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
|
|
704
|
-
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
|
|
758
|
+
...(options.source ? { source: options.source } : {}), ...(options.warmProducer ? { warmFiles: options.warmProducer.files } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
|
|
705
759
|
...(options.runId ? { runId: options.runId } : {}),
|
|
706
760
|
...(hostDirsInit ? { hostDirsInit: true } : {}),
|
|
707
761
|
});
|
|
@@ -718,6 +772,12 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
718
772
|
let markerRc: number | null = null;
|
|
719
773
|
const appliedAt = Date.now();
|
|
720
774
|
for (;;) {
|
|
775
|
+
// PRLAND-SHADOW-HOST-TIMEOUT: a Pending Pod poll never ends by itself — the host wall-clock deadline ends the
|
|
776
|
+
// loop here (before another status read) and leaves exactly one timeout record (deadline time ⊕ final state).
|
|
777
|
+
if (options.hostDeadlineAtMs !== undefined && nowMs() >= options.hostDeadlineAtMs) {
|
|
778
|
+
log('pod.command', 'host-timeout', { job: name, context, hostDeadlineAtMs: options.hostDeadlineAtMs, nowMs: nowMs(), finalState: 'timeout', waitedMs: nowMs() - appliedAt });
|
|
779
|
+
throw new Error('pod shadow: host timeout');
|
|
780
|
+
}
|
|
721
781
|
ensureLive();
|
|
722
782
|
const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
|
|
723
783
|
const finished = jobFinished(got.stdout);
|
|
@@ -744,6 +804,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
744
804
|
await awaitPodCommandAbort(sleep(options.pollMs ?? 15_000), options.signal);
|
|
745
805
|
}
|
|
746
806
|
ensureLive();
|
|
807
|
+
if (options.warmProducer) {
|
|
808
|
+
const found = kubectl(['-n', namespace, 'get', 'pods', '-l', `job-name=${name}`, '-o', 'json']);
|
|
809
|
+
let pods: { items?: Array<{ metadata?: { name?: string }; spec?: { containers?: Array<{ name?: string; image?: string }> } }> };
|
|
810
|
+
try { pods = JSON.parse(found.stdout); } catch { throw new Error('pod warm source: consumer Pod unavailable'); }
|
|
811
|
+
// A retried Job can leave an older Pod in the list. Never attribute the
|
|
812
|
+
// warm-source proof to an arbitrary Pod when the consumer is ambiguous.
|
|
813
|
+
const consumer = pods.items?.length === 1 ? pods.items[0] : undefined;
|
|
814
|
+
if (found.status !== 0 || !consumer?.metadata?.name || consumer.metadata.name === options.warmProducer.pod || consumer.spec?.containers?.find((container) => container.name === 'child')?.image !== (imageRef ?? image)) {
|
|
815
|
+
throw new Error('pod warm source: consumer Pod identity or image mismatch');
|
|
816
|
+
}
|
|
817
|
+
log('pod.command-job', 'warm-source-linked', { producerPod: options.warmProducer.pod, consumerPod: consumer.metadata.name, image: imageRef ?? image, commit: options.warmProducer.commit, files: [...options.warmProducer.files] });
|
|
818
|
+
}
|
|
747
819
|
let logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
748
820
|
// Marker path returns before the Job condition — a full-log read can hit the same transient window the tail read
|
|
749
821
|
// already survived (container log rotation · API hiccup). Retry it a little before calling the artifacts lost.
|
|
@@ -761,6 +833,13 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
761
833
|
}
|
|
762
834
|
const logsFailed = logsResult.status !== 0;
|
|
763
835
|
const logs = logsFailed ? '' : splitPodResultMarker(logsResult.stdout, launch).logs;
|
|
836
|
+
if (options.warmProducer) {
|
|
837
|
+
if (logsFailed) throw new Error(`pod warm source: consumer logs unavailable: ${logsResult.stderr.trim() || logsResult.status}`);
|
|
838
|
+
for (const path of options.warmProducer.files) {
|
|
839
|
+
const marker = `ELANOUS_WARM_SOURCE ${path} ${warmHashes[path]} ${options.warmProducer.commit}`;
|
|
840
|
+
if (logs.split(/\r?\n/).filter((line) => line === marker).length !== 1) throw new Error(`pod warm source: consumer file or commit mismatch: ${path}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
764
843
|
const artifactDir = artifactRoot;
|
|
765
844
|
let artifacts: PodArtifactCollection;
|
|
766
845
|
if (logsFailed) {
|
|
@@ -796,6 +875,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
796
875
|
// Marker path: the rc the child printed (the Pod's terminated state may lag like the condition). Condition path: unchanged.
|
|
797
876
|
const exitCode = markerRc ?? exitCodeFromPod(kubectl, namespace, name, state);
|
|
798
877
|
cleanupSecret();
|
|
878
|
+
cleanupWarmSource();
|
|
799
879
|
log('pod.command', 'job-finished', {
|
|
800
880
|
job: name,
|
|
801
881
|
exitCode,
|
|
@@ -815,6 +895,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
815
895
|
catch { /* preserve the cancellation reason */ }
|
|
816
896
|
}
|
|
817
897
|
cleanupSecret();
|
|
898
|
+
cleanupWarmSource();
|
|
818
899
|
throw err;
|
|
819
900
|
} finally {
|
|
820
901
|
if (member && pool) pool.release(member);
|