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
|
@@ -96,7 +96,7 @@ export function podTerminalRow(row: Record<string, unknown>): {
|
|
|
96
96
|
return nestedPodResult(row);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
|
|
99
|
+
export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'provider-error', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
|
|
100
100
|
|
|
101
101
|
export type PodExitClass = typeof POD_EXIT_CLASSES[number];
|
|
102
102
|
|
|
@@ -108,6 +108,51 @@ const isPodErrorLine = (line: string): boolean =>
|
|
|
108
108
|
|
|
109
109
|
const normalizePodLogLine = (line: string): string => line.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240);
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* PROVIDER-ERROR-PRIORITY: 모델 호출 쪽이 죽은 줄(자격증명·쿼터·과부하·업스트림 5xx).
|
|
113
|
+
* 자식이 스스로 수렴 못 한 것과 사유가 다르므로 generic 실패(child-error/unknown)보다 먼저 분류한다.
|
|
114
|
+
*/
|
|
115
|
+
const POD_PROVIDER_ERROR_LINE =
|
|
116
|
+
/\bllm\.[a-z0-9_-]+ (?:credential|response|stream)\b.*\b(?:error|fail(?:ed|ure)?|denied|unavailable|overloaded|exhausted)\b|\b(?:rate[_ -]?limit|quota|credits?)\b.*\b(?:exceeded|exhausted|insufficient|hit)\b|\b(?:provider|upstream)\b.*\b(?:error|overloaded|unavailable|timed? out|5\d\d)\b|(?:프로바이더|제공자|모델)\s*(?:오류|호출 실패|한도 초과)/iu;
|
|
117
|
+
|
|
118
|
+
/** provider error 줄인가 — bookkeeping 줄과 «파싱되는 JSON 줄»은 세지 않는다(classifyPodExit 의 줄 기준과 같다). */
|
|
119
|
+
function isPodProviderErrorLine(line: string): boolean {
|
|
120
|
+
if (!line || isPodBookkeepingLine(line)) return false;
|
|
121
|
+
if (line.startsWith('{')) {
|
|
122
|
+
try {
|
|
123
|
+
const parsed: unknown = JSON.parse(line);
|
|
124
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return false;
|
|
125
|
+
} catch { /* 일반 줄이 중괄호로 시작할 수 있다. */ }
|
|
126
|
+
}
|
|
127
|
+
return POD_PROVIDER_ERROR_LINE.test(line);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* POD-FAIL-EVIDENCE-CAPTURE-FU — duplicate-cap 귀속: 마지막 «canonical» 자식 terminal 하나에만 실패를 붙인다.
|
|
132
|
+
* canonical 접두(`self`/`external`)가 아닌 lookalike kind 행은 건너뛰고, 마지막 canonical terminal 이 성공이거나
|
|
133
|
+
* 읽을 오류 줄이 bookkeeping 뿐이면 null — 더 오래된(다른 terminal 의) 실패를 재사용하지 않는다.
|
|
134
|
+
*/
|
|
135
|
+
export function podChildFailureAttribution(logs: string): { stage: string; error: string } | null {
|
|
136
|
+
for (const line of logs.split('\n').reverse()) {
|
|
137
|
+
if (!line.trimStart().startsWith('{')) continue;
|
|
138
|
+
let parsed: unknown;
|
|
139
|
+
try { parsed = JSON.parse(line); } catch { continue; }
|
|
140
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
141
|
+
const row = parsed as Record<string, unknown>;
|
|
142
|
+
const terminal = podTerminalRow(row);
|
|
143
|
+
if (!terminal) continue;
|
|
144
|
+
if (terminal.ok !== false || typeof terminal.error !== 'string') return null;
|
|
145
|
+
const errorLines = terminal.error.replace(/\/home\/[^/\s]+\//gu, '~/').split(/\r\n|\n|\r/u)
|
|
146
|
+
.map((part) => part.trim())
|
|
147
|
+
.filter((part) => part.length > 0 && !isPodBookkeepingLine(part));
|
|
148
|
+
if (!errorLines.length) return null;
|
|
149
|
+
const first = errorLines[0]!.slice(0, 240);
|
|
150
|
+
const last = errorLines.at(-1)!.slice(0, 240);
|
|
151
|
+
return { stage: terminal.stage, error: first === last ? first : `${first}\n${last}` };
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
111
156
|
/** Classify a failed Pod using its terminal metadata and child output, without side effects. */
|
|
112
157
|
export function classifyPodExit(input: {
|
|
113
158
|
errorCode?: string | null;
|
|
@@ -131,12 +176,19 @@ export function classifyPodExit(input: {
|
|
|
131
176
|
} {
|
|
132
177
|
const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
|
|
133
178
|
let terminalResult: ReturnType<typeof podTerminalRow> = null;
|
|
134
|
-
|
|
179
|
+
let lastTerminalIndex = -1;
|
|
180
|
+
let previousTerminalIndex = -1;
|
|
181
|
+
for (const [index, line] of logLines.entries()) {
|
|
135
182
|
if (!line.startsWith('{')) continue;
|
|
136
183
|
let parsed: unknown;
|
|
137
184
|
try { parsed = JSON.parse(line); } catch { continue; }
|
|
138
185
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
139
|
-
|
|
186
|
+
const terminal = podTerminalRow(parsed as Record<string, unknown>);
|
|
187
|
+
if (!terminal) continue;
|
|
188
|
+
// 마지막 canonical terminal 만 유지 — 앞선 terminal 의 실패를 재사용하지 않는다(duplicate-cap).
|
|
189
|
+
previousTerminalIndex = lastTerminalIndex;
|
|
190
|
+
terminalResult = terminal;
|
|
191
|
+
lastTerminalIndex = index;
|
|
140
192
|
}
|
|
141
193
|
const hasResultLine = terminalResult !== null;
|
|
142
194
|
if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
|
|
@@ -148,12 +200,19 @@ export function classifyPodExit(input: {
|
|
|
148
200
|
try { const parsed = JSON.parse(line); return !!parsed && typeof parsed === 'object' && !Array.isArray(parsed); } catch { return false; }
|
|
149
201
|
};
|
|
150
202
|
const hasErrorLine = logLines.some((line) => !isPodBookkeepingLine(line) && !isParsedJsonLine(line) && isPodErrorLine(line));
|
|
203
|
+
// 동일 terminal 직전만: 마지막 canonical terminal 에 딸린 구간(직전 terminal 다음 ~ 마지막 terminal)의 줄만
|
|
204
|
+
// provider error 근거로 쓴다 — 오래된 terminal 의 실패를 재사용하지 않는다(duplicate-cap).
|
|
205
|
+
const attributionLines = lastTerminalIndex === -1
|
|
206
|
+
? logLines
|
|
207
|
+
: logLines.slice(previousTerminalIndex + 1, lastTerminalIndex);
|
|
208
|
+
const providerError = attributionLines.some((line) => isPodProviderErrorLine(line));
|
|
151
209
|
let exitClass: PodExitClass;
|
|
152
210
|
if (input.errorCode === 'pod-secret') exitClass = 'pod-secret';
|
|
153
211
|
else if (input.jobReason === 'DeadlineExceeded') exitClass = 'deadline-exceeded';
|
|
154
212
|
else if (input.containerReason === 'OOMKilled') exitClass = 'oom-killed';
|
|
155
213
|
else if (input.containerExitCode === 7) exitClass = 'gh-login-failed';
|
|
156
214
|
else if (askReprompt) exitClass = 'ask-reprompt';
|
|
215
|
+
else if (providerError) exitClass = 'provider-error';
|
|
157
216
|
else if (terminalResult?.stage && terminalResult.ok === false) exitClass = 'child-unconverged';
|
|
158
217
|
else if (!hasResultLine && hasErrorLine) exitClass = 'child-error';
|
|
159
218
|
else if (!hasResultLine) exitClass = 'no-result-line';
|
|
@@ -245,3 +304,156 @@ export function extractPodFailureReason(input: {
|
|
|
245
304
|
const why = input.logTailReason?.trim() || (input.logs.trim() ? '로그에 읽을 수 있는 오류 줄 없음' : '자식 로그 비어 있음');
|
|
246
305
|
return `사유 못 읽음: ${normalizePodLogLine(why)}`;
|
|
247
306
|
}
|
|
307
|
+
|
|
308
|
+
// JOB-FAILURE-TERMINATION-CAPTURE — the Kubernetes facts of a failed Job, read once at the failure verdict
|
|
309
|
+
// (Job Failed condition · result marker early exit) before GC removes the Job and its Pod. Unobserved stays
|
|
310
|
+
// `unknown` — `no-result-line` is never promoted to OOM or deadline here. Only these scalar fields are kept:
|
|
311
|
+
// no Pod env, Secret, or describe output.
|
|
312
|
+
export type PodTerminationPath = 'job-failed-condition' | 'result-marker';
|
|
313
|
+
export type PodTerminationUnknown = 'unknown';
|
|
314
|
+
|
|
315
|
+
export interface PodTermination {
|
|
316
|
+
job: string;
|
|
317
|
+
path: PodTerminationPath;
|
|
318
|
+
observedAt: string;
|
|
319
|
+
/** `ok` only when the Job read names this launch's uid · `unavailable`: failed (NotFound after GC · API error),
|
|
320
|
+
* a different or missing uid, or no launch uid to attribute it to. */
|
|
321
|
+
jobLookup: 'ok' | 'unavailable';
|
|
322
|
+
/** This launch's Job uid (the attribution key) — `unknown` when the launcher had none, and then nothing is attributed. */
|
|
323
|
+
jobUid: string | PodTerminationUnknown;
|
|
324
|
+
jobConditionReason: string | PodTerminationUnknown;
|
|
325
|
+
/** The Job's configured `spec.activeDeadlineSeconds` — a setting, not evidence the deadline fired. */
|
|
326
|
+
activeDeadlineSeconds: number | PodTerminationUnknown;
|
|
327
|
+
/** From the Job Failed condition reason `DeadlineExceeded` only. */
|
|
328
|
+
deadlineExceeded: boolean | PodTerminationUnknown;
|
|
329
|
+
/** `terminated`: the latest child container of this uid has a terminated state · without one, the Pod phase
|
|
330
|
+
* (`running` · `pending`) or `unknown` (any other or unread phase) · `absent`: no Pod of this uid. */
|
|
331
|
+
podLookup: 'terminated' | 'running' | 'pending' | 'unknown' | 'absent' | 'unavailable';
|
|
332
|
+
containerReason: string | PodTerminationUnknown;
|
|
333
|
+
exitCode: number | PodTerminationUnknown;
|
|
334
|
+
finishedAt: string | PodTerminationUnknown;
|
|
335
|
+
/** From `state.terminated.reason === 'OOMKilled'` only (never from exit code 137). */
|
|
336
|
+
oomKilled: boolean | PodTerminationUnknown;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Job Failed condition reason first: the classification takes column one, the capture all three, from one read. */
|
|
340
|
+
export const POD_TERMINATION_JOB_JSONPATH = '{.status.conditions[?(@.type=="Failed")].reason}{"\\t"}{.spec.activeDeadlineSeconds}{"\\t"}{.metadata.uid}';
|
|
341
|
+
/**
|
|
342
|
+
* One row per Pod of this Job name. The first three columns keep the classification read's layout
|
|
343
|
+
* (`creation · terminated.reason · terminated.exitCode`, empty when the child has no status yet), so the
|
|
344
|
+
* Failed-condition path reads Pods once for both; `finishedAt` follows, then `|phase · owner Job uid`.
|
|
345
|
+
*/
|
|
346
|
+
export const POD_TERMINATION_PODS_JSONPATH = '{range .items[*]}{.metadata.creationTimestamp}{"\\t"}{range .status.containerStatuses[?(@.name=="child")]}{.state.terminated.reason}{"\\t"}{.state.terminated.exitCode}{"\\t"}{.state.terminated.finishedAt}{end}{"\\t"}{"\\t"}{"\\t"}{"|"}{.status.phase}{"\\t"}{.metadata.ownerReferences[?(@.kind=="Job")].uid}{"\\n"}{end}';
|
|
347
|
+
|
|
348
|
+
type PodTerminationKubectl = (args: readonly string[]) => { status: number | null; stdout: string; stderr: string };
|
|
349
|
+
|
|
350
|
+
const POD_TERMINATION_WORD = /^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;
|
|
351
|
+
const JOB_UID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
352
|
+
const terminationWord = (value: string | undefined): string => {
|
|
353
|
+
const text = value?.trim() ?? '';
|
|
354
|
+
return POD_TERMINATION_WORD.test(text) ? text : 'unknown';
|
|
355
|
+
};
|
|
356
|
+
const terminationCount = (value: string | undefined): number | PodTerminationUnknown => {
|
|
357
|
+
const text = value?.trim() ?? '';
|
|
358
|
+
return /^\d{1,10}$/.test(text) ? Number(text) : 'unknown';
|
|
359
|
+
};
|
|
360
|
+
const terminationInstant = (value: string | undefined): string => {
|
|
361
|
+
const text = value?.trim() ?? '';
|
|
362
|
+
return /^\d{4}-\d{2}-\d{2}T[\d:.]+Z$/.test(text) && Number.isFinite(Date.parse(text)) ? text : 'unknown';
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/** Two reads (the Job · its Pods), each fail-soft: a failed or thrown read is `unavailable`, never an inferred value. */
|
|
366
|
+
export function readPodTermination(input: { kubectl: PodTerminationKubectl; namespace: string; job: string; path: PodTerminationPath;
|
|
367
|
+
/** This launch's Job uid — the only attribution key. A same-name Job of another round (OOM retry · relaunch)
|
|
368
|
+
* is not this verdict's state; without it every Job/Pod fact stays unobserved. */
|
|
369
|
+
jobUid: string | undefined;
|
|
370
|
+
/** The Failed-condition path's own Job read of `POD_TERMINATION_JOB_JSONPATH` (null: it threw) — not read again,
|
|
371
|
+
* so a GC between the verdict and the capture cannot turn an observed reason into `unknown`. */
|
|
372
|
+
jobRead?: { status: number | null; stdout: string } | null;
|
|
373
|
+
/** The Failed-condition path's own Pods read of `POD_TERMINATION_PODS_JSONPATH` (null: it threw) — not read again. */
|
|
374
|
+
podsRead?: { status: number | null; stdout: string } | null;
|
|
375
|
+
now?: () => Date }): PodTermination {
|
|
376
|
+
const { kubectl, namespace, job, path } = input;
|
|
377
|
+
const read = (args: readonly string[]): { status: number | null; stdout: string } | null => {
|
|
378
|
+
try { return kubectl(args); } catch { return null; }
|
|
379
|
+
};
|
|
380
|
+
const jobRead = 'jobRead' in input ? input.jobRead ?? null
|
|
381
|
+
: read(['-n', namespace, 'get', 'job', job, '-o', `jsonpath=${POD_TERMINATION_JOB_JSONPATH}`]);
|
|
382
|
+
const [reasonText, deadlineText, uidText] = jobRead?.status === 0 ? jobRead.stdout.replace(/\r?\n$/, '').split('\t') : [];
|
|
383
|
+
const readUid = JOB_UID.test(uidText?.trim() ?? '') ? uidText!.trim() : undefined;
|
|
384
|
+
const jobUid = input.jobUid && JOB_UID.test(input.jobUid) ? input.jobUid : undefined;
|
|
385
|
+
// A read without a uid, or with another uid, is not this launch's Job.
|
|
386
|
+
const jobOk = jobRead?.status === 0 && jobUid !== undefined && readUid === jobUid;
|
|
387
|
+
const jobConditionReason = jobOk ? terminationWord(reasonText) : 'unknown';
|
|
388
|
+
const podsRead = 'podsRead' in input ? input.podsRead ?? null
|
|
389
|
+
: read(['-n', namespace, 'get', 'pods', '-l', `job-name=${job}`, '-o', `jsonpath=${POD_TERMINATION_PODS_JSONPATH}`]);
|
|
390
|
+
let podLookup: PodTermination['podLookup'] = 'unavailable';
|
|
391
|
+
let containerReason = 'unknown';
|
|
392
|
+
let exitCode: PodTermination['exitCode'] = 'unknown';
|
|
393
|
+
let finishedAt = 'unknown';
|
|
394
|
+
// Without a uid the rows cannot be attributed to this Job — they stay unread rather than borrowed from another round.
|
|
395
|
+
if (podsRead?.status === 0 && jobUid) {
|
|
396
|
+
// The latest Pod owned by this Job uid only.
|
|
397
|
+
const rows = podsRead.stdout.split('\n').map((line) => {
|
|
398
|
+
const cut = line.lastIndexOf('\t|');
|
|
399
|
+
const [created, reason, exit, finished] = (cut >= 0 ? line.slice(0, cut) : line).split('\t');
|
|
400
|
+
const [phase, owner] = cut >= 0 ? line.slice(cut + 2).split('\t') : [];
|
|
401
|
+
return { created: created ?? '', reason, exit, finished, phase: phase?.trim(), owner: owner?.trim() };
|
|
402
|
+
});
|
|
403
|
+
const owned = rows.filter((row) => row.created && Number.isFinite(Date.parse(row.created)) && row.owner === jobUid)
|
|
404
|
+
.sort((a, b) => Date.parse(b.created) - Date.parse(a.created));
|
|
405
|
+
const latest = owned[0];
|
|
406
|
+
// Two Pods of this uid created at the same instant (a Job retry): which one is «this» failure is not knowable.
|
|
407
|
+
const tied = latest !== undefined && owned.length > 1 && Date.parse(owned[1]!.created) === Date.parse(latest.created);
|
|
408
|
+
if (!latest) podLookup = 'absent';
|
|
409
|
+
else if (tied) podLookup = 'unknown';
|
|
410
|
+
else {
|
|
411
|
+
const { reason, exit, finished, phase } = latest;
|
|
412
|
+
containerReason = terminationWord(reason);
|
|
413
|
+
exitCode = terminationCount(exit);
|
|
414
|
+
finishedAt = terminationInstant(finished);
|
|
415
|
+
podLookup = containerReason !== 'unknown' || exitCode !== 'unknown' ? 'terminated'
|
|
416
|
+
: phase === 'Running' ? 'running' : phase === 'Pending' ? 'pending' : 'unknown';
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
job, path, observedAt: (input.now?.() ?? new Date()).toISOString(),
|
|
421
|
+
jobLookup: jobOk ? 'ok' : 'unavailable',
|
|
422
|
+
jobUid: jobUid ?? 'unknown',
|
|
423
|
+
jobConditionReason,
|
|
424
|
+
activeDeadlineSeconds: jobOk ? terminationCount(deadlineText) : 'unknown',
|
|
425
|
+
deadlineExceeded: jobConditionReason === 'unknown' ? 'unknown' : jobConditionReason === 'DeadlineExceeded',
|
|
426
|
+
podLookup, containerReason, exitCode, finishedAt,
|
|
427
|
+
oomKilled: podLookup === 'terminated' && containerReason !== 'unknown' ? containerReason === 'OOMKilled' : 'unknown',
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** Ledger → incident: only a well-formed record of `job` (the current attempt's Job) is carried; anything else is dropped. */
|
|
432
|
+
export function parsePodTermination(value: unknown, job: string): PodTermination | undefined {
|
|
433
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
434
|
+
const row = value as Record<string, unknown>;
|
|
435
|
+
const oneOf = (v: unknown, allowed: readonly unknown[]) => allowed.includes(v);
|
|
436
|
+
const wordOrUnknown = (v: unknown) => typeof v === 'string' && (v === 'unknown' || POD_TERMINATION_WORD.test(v));
|
|
437
|
+
const numberOrUnknown = (v: unknown) => v === 'unknown' || (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0);
|
|
438
|
+
const boolOrUnknown = (v: unknown) => v === 'unknown' || typeof v === 'boolean';
|
|
439
|
+
if (row.job !== job || !oneOf(row.path, ['job-failed-condition', 'result-marker'])
|
|
440
|
+
|| typeof row.observedAt !== 'string' || !Number.isFinite(Date.parse(row.observedAt))
|
|
441
|
+
|| !oneOf(row.jobLookup, ['ok', 'unavailable']) || !wordOrUnknown(row.jobConditionReason)
|
|
442
|
+
|| !(row.jobUid === 'unknown' || (typeof row.jobUid === 'string' && JOB_UID.test(row.jobUid)))
|
|
443
|
+
|| !numberOrUnknown(row.activeDeadlineSeconds) || !boolOrUnknown(row.deadlineExceeded)
|
|
444
|
+
|| !oneOf(row.podLookup, ['terminated', 'running', 'pending', 'unknown', 'absent', 'unavailable'])
|
|
445
|
+
|| !wordOrUnknown(row.containerReason) || !numberOrUnknown(row.exitCode)
|
|
446
|
+
|| !(row.finishedAt === 'unknown' || (typeof row.finishedAt === 'string' && terminationInstant(row.finishedAt) !== 'unknown'))
|
|
447
|
+
|| !boolOrUnknown(row.oomKilled)) return undefined;
|
|
448
|
+
// Facts are attributed through the uid only: a record claiming Job or Pod facts without one is contradictory.
|
|
449
|
+
if (row.jobUid === 'unknown' && (row.jobLookup !== 'unavailable' || row.podLookup !== 'unavailable')) return undefined;
|
|
450
|
+
return {
|
|
451
|
+
job, path: row.path as PodTerminationPath, observedAt: row.observedAt,
|
|
452
|
+
jobLookup: row.jobLookup as PodTermination['jobLookup'], jobUid: row.jobUid as string, jobConditionReason: row.jobConditionReason as string,
|
|
453
|
+
activeDeadlineSeconds: row.activeDeadlineSeconds as PodTermination['activeDeadlineSeconds'],
|
|
454
|
+
deadlineExceeded: row.deadlineExceeded as PodTermination['deadlineExceeded'],
|
|
455
|
+
podLookup: row.podLookup as PodTermination['podLookup'], containerReason: row.containerReason as string,
|
|
456
|
+
exitCode: row.exitCode as PodTermination['exitCode'], finishedAt: row.finishedAt as string,
|
|
457
|
+
oomKilled: row.oomKilled as PodTermination['oomKilled'],
|
|
458
|
+
};
|
|
459
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POD-LAUNCH-PROVENANCE slice 2 — TA/harness si-task Jobs.
|
|
3
|
+
*
|
|
4
|
+
* ① `siTaskPodProvenance` fills the shared provenance set (pod-provenance.ts · #29650) for a si-task Job from the
|
|
5
|
+
* launch env the parent already has (owner · seat · task card · checklist slot · entrance stamp). It never builds
|
|
6
|
+
* labels itself — `podProvenanceMetadata` stays the one builder.
|
|
7
|
+
* ② The history is append-only rows on the parent's existing run ledger (`pod-launch-started` when the Job is
|
|
8
|
+
* applied, `pod-launch-finished` at the terminal verdict) — no new store. `readPodLaunchHistory(runId)` answers
|
|
9
|
+
* «who launched which Pod, when and why, and how did it end» from that ledger alone.
|
|
10
|
+
*/
|
|
11
|
+
import { userInfo } from 'node:os';
|
|
12
|
+
import { LAUNCH_SEATS, resolveLaunchStamp } from '../../harness/launch-stamp.js';
|
|
13
|
+
import { loadRunLedger, runLedgerDir, type RunLedgerEntry } from '../../self-implement/run-ledger.js';
|
|
14
|
+
import type { PodProvenance } from './pod-provenance.js';
|
|
15
|
+
import type { PodWorkIdentity } from './pod-pool.js';
|
|
16
|
+
|
|
17
|
+
export const POD_LAUNCH_STARTED_EVENT = 'pod-launch-started';
|
|
18
|
+
export const POD_LAUNCH_FINISHED_EVENT = 'pod-launch-finished';
|
|
19
|
+
|
|
20
|
+
export interface SiTaskProvenanceInput {
|
|
21
|
+
env: NodeJS.ProcessEnv | Readonly<Record<string, string | undefined>>;
|
|
22
|
+
/** The child runId this Job runs as (`ELANOUS_RUN_ID` inside the Pod). */
|
|
23
|
+
runId: string;
|
|
24
|
+
parentRunId?: string;
|
|
25
|
+
workIdentity: PodWorkIdentity;
|
|
26
|
+
/** ISO-8601 UTC. */
|
|
27
|
+
requestedAt: string;
|
|
28
|
+
feature: string;
|
|
29
|
+
launchHost?: string;
|
|
30
|
+
commit?: string | null;
|
|
31
|
+
version?: string;
|
|
32
|
+
memReq?: string;
|
|
33
|
+
shard?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const text = (value: string | undefined | null): string | undefined => {
|
|
37
|
+
const trimmed = value?.trim();
|
|
38
|
+
return trimmed ? trimmed : undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function osUser(): string | undefined {
|
|
42
|
+
try { return text(userInfo().username); } catch { return undefined; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The si-task identity. Actor order: the Job owner the dispatcher named → the launch stamp actor (seat · session · loop)
|
|
47
|
+
* → the OS user. `pool` is deliberately absent: `ELANOUS_POD_POOL` is read as pool config by the child harness.
|
|
48
|
+
*/
|
|
49
|
+
export function siTaskPodProvenance(input: SiTaskProvenanceInput): Partial<PodProvenance> {
|
|
50
|
+
const env = input.env as NodeJS.ProcessEnv;
|
|
51
|
+
const identity = input.workIdentity;
|
|
52
|
+
const stamp = resolveLaunchStamp({}, env);
|
|
53
|
+
const ownerId = text(identity.ownerId);
|
|
54
|
+
const stampActor = text(stamp.actor);
|
|
55
|
+
const user = text(env.USER) ?? text(env.LOGNAME) ?? osUser();
|
|
56
|
+
const actor = ownerId ?? stampActor ?? user;
|
|
57
|
+
const actorKind = ownerId && identity.ownerKind
|
|
58
|
+
? (identity.ownerKind === 'steward' || identity.ownerKind === 'orchestrator' ? 'loop' : identity.ownerKind)
|
|
59
|
+
: stampActor && (LAUNCH_SEATS as readonly string[]).includes(stampActor) ? 'seat'
|
|
60
|
+
: stampActor && stampActor === text(env.ELANOUS_LOOP_NAME) ? 'loop'
|
|
61
|
+
: actor ? 'human' : undefined;
|
|
62
|
+
const authoring = identity.work === 'authoring';
|
|
63
|
+
const entrance = stamp.entrance !== 'unknown' ? stamp.entrance : identity.taskCard ? 'tasks-hand' : undefined;
|
|
64
|
+
const firstLine = input.feature.split('\n', 1)[0]?.trim().slice(0, 160) ?? '';
|
|
65
|
+
const reason = [identity.taskCard ? `TA ${identity.taskCard}` : undefined, firstLine || undefined].filter(Boolean).join(' · ');
|
|
66
|
+
return {
|
|
67
|
+
...(actorKind ? { actorKind } : {}),
|
|
68
|
+
...(actor ? { actor } : {}),
|
|
69
|
+
kind: 'si-task',
|
|
70
|
+
run: input.runId,
|
|
71
|
+
phase: authoring ? 'authoring' : 'impl',
|
|
72
|
+
requestedAt: input.requestedAt,
|
|
73
|
+
character: identity.taskCard ? 'ta-child' : authoring ? 'author-child' : 'harness-child',
|
|
74
|
+
...(entrance ? { entrance } : {}),
|
|
75
|
+
...(text(identity.slotId) ? { cell: identity.slotId } : {}),
|
|
76
|
+
...(text(input.version) ? { version: input.version } : {}),
|
|
77
|
+
...(text(input.commit) ? { commit: input.commit! } : {}),
|
|
78
|
+
...(text(input.launchHost) ? { launchHost: input.launchHost } : {}),
|
|
79
|
+
...(text(input.shard) ? { shard: input.shard } : {}),
|
|
80
|
+
...(text(input.memReq) ? { memReq: input.memReq } : {}),
|
|
81
|
+
...(text(input.parentRunId) ? { parent: input.parentRunId } : {}),
|
|
82
|
+
...(reason ? { reason } : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** `elanous.ai/<key>` annotations → `{ <key>: value }` for the started row (full values, not the 63-char labels). */
|
|
87
|
+
export function provenanceRowFromAnnotations(annotations: Readonly<Record<string, string>>): Record<string, string> {
|
|
88
|
+
const row: Record<string, string> = {};
|
|
89
|
+
for (const [key, value] of Object.entries(annotations)) if (key.startsWith('elanous.ai/')) row[key.slice('elanous.ai/'.length)] = value;
|
|
90
|
+
return row;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface PodLaunchRecord {
|
|
94
|
+
job: string;
|
|
95
|
+
run: string;
|
|
96
|
+
attempt: number | null;
|
|
97
|
+
startedAt: string | null;
|
|
98
|
+
provenance: Record<string, string>;
|
|
99
|
+
finished: { at: string | null; phase: string; exitCode: number | null; reason: string } | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const str = (value: unknown): string | undefined => (typeof value === 'string' && value ? value : undefined);
|
|
103
|
+
|
|
104
|
+
/** Rebuild launch records from one run ledger. Rows pair on job·run; an unpaired row stays visible (never dropped). */
|
|
105
|
+
export function readPodLaunchHistory(runId: string, dir: string = runLedgerDir()): PodLaunchRecord[] {
|
|
106
|
+
const entries: RunLedgerEntry[] = loadRunLedger(runId, dir) ?? [];
|
|
107
|
+
const records: PodLaunchRecord[] = [];
|
|
108
|
+
const open = new Map<string, PodLaunchRecord>();
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (entry.event !== POD_LAUNCH_STARTED_EVENT && entry.event !== POD_LAUNCH_FINISHED_EVENT) continue;
|
|
111
|
+
const job = str(entry.data.job) ?? 'unknown';
|
|
112
|
+
const run = str(entry.data.run) ?? 'unknown';
|
|
113
|
+
const key = `${job}\u0000${run}`;
|
|
114
|
+
if (entry.event === POD_LAUNCH_STARTED_EVENT) {
|
|
115
|
+
const provenance: Record<string, string> = {};
|
|
116
|
+
const raw = entry.data.provenance;
|
|
117
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
118
|
+
for (const [name, value] of Object.entries(raw as Record<string, unknown>)) if (typeof value === 'string') provenance[name] = value;
|
|
119
|
+
}
|
|
120
|
+
const record: PodLaunchRecord = { job, run, attempt: typeof entry.data.attempt === 'number' ? entry.data.attempt : null,
|
|
121
|
+
startedAt: entry.timestamp ?? null, provenance, finished: null };
|
|
122
|
+
records.push(record);
|
|
123
|
+
open.set(key, record);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const finished = { at: entry.timestamp ?? null, phase: str(entry.data.phase) ?? 'unknown',
|
|
127
|
+
exitCode: typeof entry.data.exitCode === 'number' ? entry.data.exitCode : null, reason: str(entry.data.reason) ?? 'unknown' };
|
|
128
|
+
const started = open.get(key);
|
|
129
|
+
if (started && !started.finished) { started.finished = finished; open.delete(key); continue; }
|
|
130
|
+
records.push({ job, run, attempt: typeof entry.data.attempt === 'number' ? entry.data.attempt : null, startedAt: null, provenance: {}, finished });
|
|
131
|
+
}
|
|
132
|
+
return records;
|
|
133
|
+
}
|
|
@@ -12,6 +12,17 @@ export function stablePodManifestText(applied: Array<Record<string, any>>): stri
|
|
|
12
12
|
let snapshots = 0;
|
|
13
13
|
for (const manifest of manifests) {
|
|
14
14
|
if (manifest.kind !== 'Job') continue;
|
|
15
|
+
// POD-LAUNCH-PROVENANCE — the request time and the 8-char run/parent labels are per launch like the run id.
|
|
16
|
+
for (const meta of [manifest.metadata, manifest.spec?.template?.metadata]) {
|
|
17
|
+
for (const bag of [meta?.labels, meta?.annotations]) {
|
|
18
|
+
if (!bag) continue;
|
|
19
|
+
if (bag['elanous.ai/requested-at'] !== undefined) bag['elanous.ai/requested-at'] = '<requested-at>';
|
|
20
|
+
if (meta?.labels === bag) for (const key of ['elanous.ai/run', 'elanous.ai/parent']) if (bag[key] !== undefined) bag[key] = '<run-label>';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const container of manifest.spec?.template?.spec?.containers ?? []) {
|
|
24
|
+
for (const entry of container.env ?? []) if (entry.name === 'ELANOUS_POD_REQUESTED_AT') entry.value = '<requested-at>';
|
|
25
|
+
}
|
|
15
26
|
for (const container of manifest.spec?.template?.spec?.containers ?? []) {
|
|
16
27
|
for (const entry of container.env ?? []) {
|
|
17
28
|
if (entry.name !== BUDGET_SNAPSHOT_ENV) continue;
|
|
@@ -89,14 +89,29 @@ function defaultLocalImageInspect(image: string): { status: number | null; stdou
|
|
|
89
89
|
return { status: r.status, stdout: r.stdout ?? '' };
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/** 레지스트리 안 이미지 이름 — `docker/harness/build.sh` 의 full/lite 규칙 그대로. */
|
|
93
|
+
function podRegistryImageName(image: string): string {
|
|
94
|
+
return image === 'elanous-harness-lite:local' ? 'elanous-harness-lite' : 'elanous-harness';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** 레지스트리 태그 = 커밋 앞 12자리 (build.sh:295 와 같은 규칙). */
|
|
98
|
+
function podRegistryTag(commit: string): string {
|
|
99
|
+
return commit.slice(0, 12);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** 노드 로컬 레지스트리의 HTTP 포트 — 호스트에서는 같은 포트의 localhost 로 조회한다. */
|
|
103
|
+
function memberRegistryPort(member: PodPoolMember): string {
|
|
104
|
+
const registry = memberRegistry(member);
|
|
105
|
+
return registry.slice(registry.lastIndexOf(':') + 1);
|
|
106
|
+
}
|
|
107
|
+
|
|
92
108
|
/** 이 커밋의 이미지가 노드 레지스트리에 있나 — 있으면 클러스터 안 이미지 주소. */
|
|
93
109
|
export function registryImageRef(member: PodPoolMember, commit: string | null, run: RemoteRun = defaultRemoteRun, image = 'elanous-harness:local'): string | null {
|
|
94
110
|
if (!member.sshHost || !commit) return null;
|
|
95
|
-
const imageName = image
|
|
96
|
-
const tag = commit
|
|
111
|
+
const imageName = podRegistryImageName(image);
|
|
112
|
+
const tag = podRegistryTag(commit);
|
|
97
113
|
const registry = memberRegistry(member);
|
|
98
|
-
const
|
|
99
|
-
const r = run(member.sshHost, `curl -fsS --max-time 5 http://localhost:${port}/v2/${imageName}/tags/list 2>/dev/null`);
|
|
114
|
+
const r = run(member.sshHost, `curl -fsS --max-time 5 http://localhost:${memberRegistryPort(member)}/v2/${imageName}/tags/list 2>/dev/null`);
|
|
100
115
|
if (r.status !== 0) return null;
|
|
101
116
|
try {
|
|
102
117
|
const tags = (JSON.parse(r.stdout) as { tags?: string[] }).tags ?? [];
|
|
@@ -104,6 +119,54 @@ export function registryImageRef(member: PodPoolMember, commit: string | null, r
|
|
|
104
119
|
} catch { return null; }
|
|
105
120
|
}
|
|
106
121
|
|
|
122
|
+
/** 레지스트리 HTTP 한 번 — 노드에서 `curl -fsS --max-time 5`(registryImageRef 와 같은 규칙). 실패면 null. */
|
|
123
|
+
function registryHttpGet(member: PodPoolMember, path: string, run: RemoteRun, accept?: string): string | null {
|
|
124
|
+
if (!member.sshHost) return null;
|
|
125
|
+
const header = accept ? `-H 'Accept: ${accept}' ` : '';
|
|
126
|
+
const r = run(member.sshHost, `curl -fsS --max-time 5 ${header}http://localhost:${memberRegistryPort(member)}/v2/${path} 2>/dev/null`);
|
|
127
|
+
return r.status === 0 && r.stdout.trim() ? r.stdout : null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function registryLabelValue(raw: unknown): string | null {
|
|
131
|
+
return typeof raw === 'string' && raw.trim() && raw !== '<no value>' ? raw.trim() : null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* GATE-REGISTRY-IMAGE-FASTPATH (0.2.36): 레지스트리 HTTP 만으로 이 커밋 태그 이미지의 config label 을 읽는다 —
|
|
136
|
+
* 노드 Docker 데몬(`docker image inspect`)을 부르지 않는다. 태그 결손 · HTTP 오류 · manifest list(단일 config 없음) ·
|
|
137
|
+
* 비JSON 은 null 이다(판정하지 않고 종전 경로로 떨어진다).
|
|
138
|
+
* GET /v2/<이미지>/manifests/<커밋12> → config.digest → GET /v2/<이미지>/blobs/<digest> → config.Labels
|
|
139
|
+
*/
|
|
140
|
+
export function registryImageLabels(member: PodPoolMember, image: string, commit: string | null, run: RemoteRun = defaultRemoteRun): { commit: string | null; skills: string | null } | null {
|
|
141
|
+
if (!member.sshHost || !commit) return null;
|
|
142
|
+
const imageName = podRegistryImageName(image);
|
|
143
|
+
const manifest = registryHttpGet(member, `${imageName}/manifests/${podRegistryTag(commit)}`, run, 'application/vnd.docker.distribution.manifest.v2+json');
|
|
144
|
+
if (!manifest) return null;
|
|
145
|
+
let digest: string | undefined;
|
|
146
|
+
try { digest = (JSON.parse(manifest) as { config?: { digest?: string } }).config?.digest; } catch { return null; }
|
|
147
|
+
if (!digest) return null;
|
|
148
|
+
// config digest 는 `sha256:<64 hex>` — 이 형태가 아니면 경로에 넣지 않는다.
|
|
149
|
+
if (!/^sha256:[0-9a-f]{64}$/u.test(digest)) return null;
|
|
150
|
+
const blob = registryHttpGet(member, `${imageName}/blobs/${digest}`, run);
|
|
151
|
+
if (!blob) return null;
|
|
152
|
+
let labels: Record<string, unknown> | undefined;
|
|
153
|
+
try { labels = (JSON.parse(blob) as { config?: { Labels?: Record<string, unknown> } }).config?.Labels; } catch { return null; }
|
|
154
|
+
if (!labels || typeof labels !== 'object') return null;
|
|
155
|
+
return { commit: registryLabelValue(labels['elanous.commit']), skills: registryLabelValue(labels['elanous.pod-skills']) };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 이 커밋 태그의 이미지 label 이 이번 발사 값과 모두 맞나 — 맞으면 Docker 조회 없이 그 판을 쓸 수 있다.
|
|
160
|
+
* 커밋 label 은 발사 커밋과 «정확히» 같아야 한다(태그가 다른 판을 가리키는 경우를 거른다).
|
|
161
|
+
* `localSkillsDigest` 가 없으면(모르는 값) 커밋 label 만 본다 — syncPoolImages 의 종전 skillsSame 과 같은 뜻.
|
|
162
|
+
*/
|
|
163
|
+
export function registryImageLabelsMatch(member: PodPoolMember, image: string, commit: string | null, opts: { localSkillsDigest?: string | null; run?: RemoteRun } = {}): boolean {
|
|
164
|
+
if (!commit) return false;
|
|
165
|
+
const labels = registryImageLabels(member, image, commit, opts.run ?? defaultRemoteRun);
|
|
166
|
+
if (!labels || labels.commit !== commit) return false;
|
|
167
|
+
return opts.localSkillsDigest == null || labels.skills === opts.localSkillsDigest;
|
|
168
|
+
}
|
|
169
|
+
|
|
107
170
|
/** IMAGE-ONE-SOURCE: 이 멤버의 노드에 레지스트리 컨테이너가 있나(syncPoolImages 의 판정과 같은 명령). 로컬 멤버는 false. */
|
|
108
171
|
export function memberHasRegistry(member: PodPoolMember, run: RemoteRun = defaultRemoteRun): boolean {
|
|
109
172
|
if (!member.sshHost) return false;
|
|
@@ -873,6 +936,15 @@ export async function syncPoolImages(members: readonly PodPoolMember[], image: s
|
|
|
873
936
|
await Promise.all(members.map(async (m) => {
|
|
874
937
|
const t0 = Date.now();
|
|
875
938
|
if (!m.sshHost) { results.set(m.context, { ok: true, action: 'local', detail: 'this machine', ms: 0 }); return; }
|
|
939
|
+
// ⭐ GATE-REGISTRY-IMAGE-FASTPATH (0.2.36 · OP): 레지스트리 커밋 태그의 config label(commit ⊕ pod-skills)이 이번 발사
|
|
940
|
+
// 값과 같으면 노드 Docker 데몬을 «한 번도» 부르지 않고 그 커밋 ref 로 끝난다 — 데몬 조회가 느려도 gate 첫 Pod 이 뜬다.
|
|
941
|
+
// 태그 결손 · label 불일치 · HTTP 오류면 아래 종전 경로(원격 inspect → 노드 빌드 → 통째 전송)가 그대로 판정한다.
|
|
942
|
+
if (localCommit && registryImageLabelsMatch(m, image, localCommit, { ...(deps.localSkillsDigest !== undefined ? { localSkillsDigest: deps.localSkillsDigest } : {}), run })) {
|
|
943
|
+
const imageRef = `${memberRegistry(m)}/${podRegistryImageName(image)}:${podRegistryTag(localCommit)}`;
|
|
944
|
+
debug.log('pod.pool', 'image-fresh-registry-label', { context: m.context, host: m.sshHost, commit: localCommit, imageRef, skills: deps.localSkillsDigest ?? null, waitedMs: 0 });
|
|
945
|
+
results.set(m.context, { ok: true, action: 'fresh', detail: localCommit.slice(0, 12), ms: Date.now() - t0, imageRef });
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
876
948
|
const before = remoteImageCommit(m, image, run);
|
|
877
949
|
const skillsNow = deps.localSkillsDigest;
|
|
878
950
|
const refBefore = registryImageRef(m, localCommit, run, image);
|
|
@@ -17,6 +17,8 @@ export interface PodProvenance {
|
|
|
17
17
|
commit?: string;
|
|
18
18
|
shard?: string;
|
|
19
19
|
reason?: string;
|
|
20
|
+
/** Parent runId / lease id — whose child this Pod is. Label keeps the first 8 characters like run/commit. */
|
|
21
|
+
parent?: string;
|
|
20
22
|
pool?: string;
|
|
21
23
|
cpuReq?: string;
|
|
22
24
|
memReq?: string;
|
|
@@ -28,11 +30,15 @@ const required = ['actorKind', 'actor', 'kind', 'run', 'phase', 'requestedAt'] a
|
|
|
28
30
|
const names: Record<keyof PodProvenance, string> = {
|
|
29
31
|
actorKind: 'actor-kind', actor: 'actor', kind: 'kind', run: 'run', phase: 'phase', requestedAt: 'requested-at',
|
|
30
32
|
character: 'character', launchHost: 'launch-host', entrance: 'entrance', graphNode: 'graph-node', cell: 'cell',
|
|
31
|
-
version: 'version', commit: 'commit', shard: 'shard', reason: 'reason',
|
|
33
|
+
version: 'version', commit: 'commit', shard: 'shard', reason: 'reason', parent: 'parent',
|
|
32
34
|
pool: 'pool', cpuReq: 'cpu-req', memReq: 'mem-req',
|
|
33
35
|
warmReused: 'warm-reused', argv: 'argv',
|
|
34
36
|
};
|
|
35
37
|
|
|
38
|
+
/** Every child env name the set can carry (`ELANOUS_POD_<KEY>`). */
|
|
39
|
+
export const POD_PROVENANCE_ENV_NAMES: readonly string[] = Object.values(names)
|
|
40
|
+
.map((name) => `ELANOUS_POD_${name.toUpperCase().replaceAll('-', '_')}`);
|
|
41
|
+
|
|
36
42
|
const labelValue = (value: string): string => {
|
|
37
43
|
const cleaned = value.toLowerCase().replace(/[^a-z0-9._-]/g, '-').replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '');
|
|
38
44
|
return cleaned.slice(0, 63).replace(/[^a-z0-9]+$/g, '') || 'unknown';
|
|
@@ -67,7 +73,7 @@ export function podProvenanceMetadata(input: Partial<PodProvenance> | undefined,
|
|
|
67
73
|
const annotations: Record<string, string> = {};
|
|
68
74
|
const env: Array<{ name: string; value: string }> = [];
|
|
69
75
|
for (const [name, value] of Object.entries(values)) {
|
|
70
|
-
const label = name === 'run' || name === 'commit' ? value.slice(0, 8) : value;
|
|
76
|
+
const label = name === 'run' || name === 'commit' || name === 'parent' ? value.slice(0, 8) : value;
|
|
71
77
|
if (name !== 'reason' && name !== 'argv') labels[`elanous.ai/${name}`] = labelValue(label);
|
|
72
78
|
annotations[`elanous.ai/${name}`] = value;
|
|
73
79
|
env.push({ name: `ELANOUS_POD_${name.toUpperCase().replaceAll('-', '_')}`, value });
|
|
@@ -3,6 +3,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
6
|
+
import { classifyGateEnvDeficit, GATE_ENV_DEFICIT_HARVESTABLE_MARK } from '../../self-implement/gate-env-retry.js';
|
|
6
7
|
|
|
7
8
|
export const REPAIR_REF = 'refs/elanous/repair/result';
|
|
8
9
|
export const REPAIR_BUNDLE_MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -39,15 +40,29 @@ function completedWorktree(output: string): { path: string; runId: string } {
|
|
|
39
40
|
let value: Record<string, unknown>;
|
|
40
41
|
try { value = JSON.parse(line) as Record<string, unknown>; } catch { continue; }
|
|
41
42
|
if (value.kind === 'self' && value.result && typeof value.result === 'object') value = value.result as Record<string, unknown>;
|
|
42
|
-
|
|
43
|
+
const completed = value.stage === 'worktree-completed' && value.ok === true;
|
|
44
|
+
// The gate could not measure an environmental failure. Keep the implementation as a
|
|
45
|
+
// bundle for the pinned PR; the parent still has to review and rejudge that head.
|
|
46
|
+
const gate = value.gate && typeof value.gate === 'object' && !Array.isArray(value.gate)
|
|
47
|
+
? value.gate as { passed?: unknown; log?: unknown; reflectGateFacts?: { introduced?: number; unknownReason?: string; childResponsibility?: string } }
|
|
48
|
+
: null;
|
|
49
|
+
const environmentHarvest = value.stage === 'gate-failed' && value.ok === false
|
|
50
|
+
&& value.harvestable === true && typeof value.detail === 'string'
|
|
51
|
+
&& value.detail.includes(GATE_ENV_DEFICIT_HARVESTABLE_MARK)
|
|
52
|
+
&& gate?.passed === false
|
|
53
|
+
&& gate.reflectGateFacts?.introduced === 0
|
|
54
|
+
&& gate.reflectGateFacts?.childResponsibility === 'none'
|
|
55
|
+
&& classifyGateEnvDeficit({ passed: false, ...(typeof gate.log === 'string' ? { log: gate.log } : {}),
|
|
56
|
+
...(gate.reflectGateFacts ? { reflectGateFacts: gate.reflectGateFacts } : {}) }).envDeficit;
|
|
57
|
+
if ((!completed && !environmentHarvest) || typeof value.worktreePath !== 'string'
|
|
43
58
|
|| typeof value.runId !== 'string' || !value.runId)
|
|
44
|
-
throw new Error('repair child final result is
|
|
59
|
+
throw new Error('repair child final result is neither successful worktree-only nor environment-deficit harvestable');
|
|
45
60
|
return { path: value.worktreePath, runId: value.runId };
|
|
46
61
|
}
|
|
47
62
|
throw new Error('repair child did not return a successful worktree-only result');
|
|
48
63
|
}
|
|
49
64
|
|
|
50
|
-
/** Called in the Pod after
|
|
65
|
+
/** Called in the Pod after a successful child or a verified environment-deficit harvest. */
|
|
51
66
|
export function writePodRepairCommit(input: { pr: number; baseHead: string; runId: string; output: string; repo: string; outbox: string }): PodRepairResult {
|
|
52
67
|
if (!Number.isSafeInteger(input.pr) || input.pr < 1 || !SHA40.test(input.baseHead)) throw new Error('invalid repair PR or base head');
|
|
53
68
|
if (!input.runId.trim()) throw new Error('repair parent run id missing');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Opt-in SI warm entry; the ordinary Pod spawn remains the default. */
|
|
2
|
+
import { podSelfImplementSpawn, type PodSpawnOptions } from './self-implement-pod.js';
|
|
3
|
+
|
|
4
|
+
export async function podSpawnWithSiWarm(base: PodSpawnOptions,
|
|
5
|
+
env: NodeJS.ProcessEnv = process.env) {
|
|
6
|
+
if (env.ELANOUS_SI_WARM_REUSE !== '1') return podSelfImplementSpawn(base);
|
|
7
|
+
const { acquireSiWarmChild, postprocessSiWarmChild } = await import('./pod-si-warm-host.js');
|
|
8
|
+
return podSelfImplementSpawn({ ...base,
|
|
9
|
+
siWarmAttempt: async input => {
|
|
10
|
+
const result = await acquireSiWarmChild(input, base);
|
|
11
|
+
return result.status === 'acquired' ? result.attempt : null;
|
|
12
|
+
},
|
|
13
|
+
siWarmHostPostprocess: (result, attempt, input) =>
|
|
14
|
+
postprocessSiWarmChild(input, result, attempt, base),
|
|
15
|
+
});
|
|
16
|
+
}
|