elanous 0.2.32 → 0.2.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 0368f25d-ad84af92fefee68f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
- package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 1530.0e612369b6fd7ea0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
- package/apps/pwa/out/_next/static/chunks/{7391.ebae168025c91b6a.js → 1674.2a65fd5668e1cc5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7947-d0759430f8042240.js → 1993-c0007b7ad0c0ef41.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{60fb96c9.360b01d8d4927b7b.js → 1c735de4.f993a30bbd3c57c4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 2018.a741297bce759490.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3902.e1e71aaac850a045.js → 2625.5d870aa999f33db1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
- package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
- package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 3408.21d1570602f4b6c0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 3677-4215f826f6aa68e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7371.80c05c653b08e907.js → 4346.8601952e73bf5803.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 4705-194e64e47ca0fbdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 4718-17d2af636796a330.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 5101.e32282718f99ed6f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{2001.6c7e0fd02190886c.js → 5154.a118f3957ed14e36.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 5483-dd5d7697f6bdb106.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3267c0e6.d34854e7b3984a6e.js → 56d372f2.681ab4ec4c998fae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +287 -0
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 6236.e18cced2d5ba6afb.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
- package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6544cb48.a87fe20ddf137be2.js → 6b89c8bd.24df687a820500b3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7385.50a308a477bdfc21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 7644.17e37ba6f1d4226e.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8018.a32663f04a6fc5f9.js → 8219.baa715d1deee80e2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4111.2bfedbb233ad206b.js → 8256.e3ac8421a71f82f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 8444.4c26b379ca2b9596.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
- package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 8637.47f5b35afcae5e6b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9214.63a510d39178e997.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 938.66ad1ef0e5abae1c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 9512.5a76207a730e0491.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{69-0a2c8209c6d4a158.js → 967-2aa39b2d04b4c690.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 9952.5daf5f94063a2b3e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-a27b1e5a0d1b308f.js → page-406b47745b53f269.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-32866485913d6a04.js → page-47c5d4db587266bd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-dc0a532f5b9196ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → cbe38a15.5a032598e39970c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → da5176c6.6773b6c5994e1d99.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.mjs +10 -2
- package/catalog/providers/opengateway.yaml +25 -0
- package/docs/goal-context/01-goal-authoring-checks.md +8 -0
- package/docs/goal-context/03-verification-menu.md +24 -0
- package/docs/goal-context/04-mock-scenarios.md +100 -0
- package/docs/goal-context/README.md +5 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/default-loop.yaml +76 -5
- package/graphs/document-loop.yaml +71 -4
- package/graphs/implement-loop.yaml +59 -4
- package/graphs/journey/SCENARIOS.md +33 -0
- package/graphs/journey/recipes.yaml +1 -0
- package/graphs/journey/ta-journey.yaml +94 -0
- package/graphs/journey/units/author/author.yaml +20 -0
- package/graphs/journey/units/author/recipes.yaml +2 -0
- package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
- package/graphs/journey/units/author-dialogue/observe.ts +96 -0
- package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
- package/graphs/journey/units/green/green.yaml +20 -0
- package/graphs/journey/units/green/recipes.yaml +2 -0
- package/graphs/journey/units/pr/pr.yaml +20 -0
- package/graphs/journey/units/pr/recipes.yaml +2 -0
- package/graphs/journey/units/remember/recipes.yaml +2 -0
- package/graphs/journey/units/remember/remember.yaml +20 -0
- package/graphs/operate-loop.yaml +71 -4
- package/graphs/overlays/stop-heal-ladder.yaml +1 -1
- package/graphs/release-rehearsal/recipes.yaml +1 -1
- package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
- package/graphs/research-loop.yaml +159 -4
- package/graphs/test-diet/test-diet.yaml +3 -0
- package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
- package/graphs/units/dispatch-pod/recipes.yaml +14 -0
- package/graphs/units/entry/entry.yaml +50 -0
- package/graphs/units/entry/recipes.yaml +14 -0
- package/graphs/units/harvest/harvest.yaml +25 -0
- package/graphs/units/harvest/recipes.yaml +4 -0
- package/graphs/units/land/land.yaml +45 -0
- package/graphs/units/land/recipes.yaml +3 -0
- package/graphs/units/recipes.yaml +7 -0
- package/graphs/units/recover.yaml +39 -0
- package/graphs/units/reflect/recipes.yaml +3 -0
- package/graphs/units/reflect/reflect.yaml +15 -0
- package/graphs/units/task-agent-recover-review.yaml +17 -0
- package/graphs/units/task-agent-recover-wait.yaml +17 -0
- package/graphs/units/verbs/make-doc.yaml +34 -0
- package/graphs/units/verbs/recipes.yaml +33 -0
- package/graphs/units/verbs/verify.yaml +55 -0
- package/graphs/work/recipes.yaml +2 -0
- package/graphs/work/research-report.yaml +28 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +69 -16
- package/scripts/coord-role-pack.ts +19 -6
- package/scripts/docs/generate-graph-anatomy.ts +19 -2
- package/scripts/graph-harvest-unit.ts +22 -0
- package/scripts/graph-units/journey-stub.ts +6 -0
- package/scripts/graph-units/land-enqueue.ts +78 -0
- package/scripts/graph-units/recover-plan.ts +15 -0
- package/scripts/graph-units/reflect-node.ts +88 -0
- package/scripts/graph-units/ta-journey-observe.ts +109 -0
- package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
- package/scripts/graph-units/verbs/verify-stage.ts +75 -0
- package/scripts/graph-units/verbs-envelope.ts +139 -0
- package/scripts/hq/standby-snapshot.ts +30 -0
- package/scripts/public-export.ts +43 -1
- package/scripts/ratchets/train-side-invariants.sh +45 -0
- package/scripts/release-loop/auto-approve-node.ts +30 -16
- package/scripts/release-loop/docs-land-node.ts +21 -5
- package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
- package/scripts/release-loop/gate-closure.ts +5 -1
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-node.ts +675 -49
- package/scripts/release-loop/gate-partial.ts +68 -14
- package/scripts/release-loop/gate-radius-live.ts +177 -0
- package/scripts/release-loop/gate-radius-shadow.ts +138 -0
- package/scripts/release-loop/gate-traffic-mode.ts +128 -0
- package/scripts/release-loop/gate-triage-node.ts +5 -2
- package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
- package/scripts/release-loop/known-issues-node.ts +77 -8
- package/scripts/release-loop/node-verdict.ts +12 -1
- package/scripts/release-loop/npm-publish-node.ts +66 -12
- package/scripts/release-loop/preflight.ts +93 -7
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
- package/scripts/release-loop/publish-node.ts +60 -9
- package/scripts/release-loop/pwa-remote.ts +166 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
- package/scripts/release-loop/resume-cap.ts +56 -0
- package/scripts/release-loop/resume-release.ts +155 -19
- package/scripts/release-loop/resume.ts +24 -1
- package/scripts/release-loop/tui-sim-node.ts +8 -2
- package/scripts/release-loop/unattended-release.ts +10 -2
- package/scripts/test-diet/lib.ts +6 -1
- package/scripts/test-diet/node.ts +194 -13
- package/scripts/ux-sim.ts +39 -0
- package/src/acp/core-turn-bridge.ts +20 -5
- package/src/acp/reasoning-thought-buffer.ts +45 -0
- package/src/agent/self-ambient-cache.ts +8 -0
- package/src/agent-substrate/acp-reviewer.ts +90 -15
- package/src/agent-substrate/pr-reviewer.ts +17 -0
- package/src/agent-substrate/review-finding-key.ts +53 -0
- package/src/agent-substrate/self-review-cli.ts +188 -18
- package/src/ask-user-question/pending-questions.ts +1 -1
- package/src/autopilot/pr-manager.ts +393 -65
- package/src/budget/run-usage-rollup.ts +1 -0
- package/src/chat/index.ts +0 -2
- package/src/chat/pickers/modal-runtime.ts +10 -27
- package/src/chat/tool-render/dispatch.ts +62 -10
- package/src/cli/agent-cli.ts +13 -2
- package/src/cli/control-cli.ts +24 -7
- package/src/cli/doctor-cli.ts +4 -1
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/light-entry-route.ts +75 -0
- package/src/cli/llm-detect-cli.ts +23 -1
- package/src/cli/pod-cli.ts +77 -3
- package/src/cli/pr-cli.ts +81 -14
- package/src/cli/pr-land-base-read.ts +2 -0
- package/src/cli/pr-land-overlap-evidence.ts +154 -16
- package/src/cli/pr-land-pod-shadow-job.ts +3 -0
- package/src/cli/pr-land-recovery.ts +64 -0
- package/src/cli/pty-takeover-cli.ts +6 -5
- package/src/cli/release-checklist-read-cli.ts +79 -0
- package/src/cli/release-cli.ts +189 -132
- package/src/cli/release-run-if-ready.ts +29 -28
- package/src/cli/release-single-flight.ts +178 -0
- package/src/cli/remote-resolve.ts +1 -1
- package/src/cli/root-tui-entry.ts +48 -0
- package/src/cli/seat-cli.ts +37 -0
- package/src/cli/setup-cli.ts +40 -1
- package/src/cli/sim-cli.ts +22 -0
- package/src/cli/tasks-cli.ts +667 -14
- package/src/cli/usage-cli.ts +13 -11
- package/src/clipboard/history.ts +179 -13
- package/src/config.ts +8 -1
- package/src/control/control-status.ts +8 -3
- package/src/control-plane/ledger.ts +5 -3
- package/src/control-plane/server.ts +5 -3
- package/src/core-turn/short-question.ts +5 -1
- package/src/dashboard/chat/acp-chat.ts +8 -0
- package/src/dashboard/index.ts +114 -77
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/seat-autowake.ts +56 -3
- package/src/dashboard/render/theme-resolver.ts +33 -4
- package/src/dashboard/seat-boot-preamble.ts +1 -1
- package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
- package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
- package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
- package/src/dashboard/turn-preamble.ts +47 -1
- package/src/dashboard/turn-stream-formatter.ts +34 -1
- package/src/dashboard/turn-stream-runtime.ts +2 -0
- package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
- package/src/domains/guardian-tick.ts +54 -2
- package/src/domains/outbound-alert.ts +3 -2
- package/src/domains/schedule-registry.ts +16 -2
- package/src/extractors.ts +3 -1
- package/src/git-fs/idle-refresh.ts +76 -0
- package/src/git-fs/index.ts +18 -7
- package/src/git-fs/retry.ts +4 -0
- package/src/git-fs/runner.ts +2 -0
- package/src/git-fs/worktree.ts +42 -4
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/runner.ts +267 -54
- package/src/grok/credential.ts +15 -3
- package/src/harness/harness-cli-command.ts +151 -38
- package/src/harness/harness-incidents.ts +37 -0
- package/src/harness/harness-pod-dispatch.ts +38 -1
- package/src/harness/harness-salvage-cli.ts +14 -2
- package/src/harness/launch-utterance-ledger.ts +208 -0
- package/src/impl-discipline/detector.ts +16 -4
- package/src/impl-discipline/system-prompt.ts +11 -0
- package/src/impl-discipline/types.ts +2 -2
- package/src/index.ts +683 -146
- package/src/intake-plane/already-built-hint.ts +91 -0
- package/src/intake-plane/requirement-funnel.ts +29 -1
- package/src/knowhow/pack.ts +199 -0
- package/src/light-cli.ts +111 -0
- package/src/llm/opengateway-models.ts +11 -0
- package/src/llm/provider-credentials.ts +14 -0
- package/src/llm/provider-detect.ts +8 -1
- package/src/llm/runtime-model-family.ts +2 -1
- package/src/llm.ts +268 -65
- package/src/loops/budget.ts +95 -0
- package/src/loops/msg-wake.ts +8 -2
- package/src/loops/orchestrator/traffic.ts +132 -1
- package/src/model-tier/llm-tier-map.ts +15 -1
- package/src/mss/logging/log-store.ts +4 -5
- package/src/native-tool-catalog.ts +15 -1
- package/src/nexus/api/graphs-api.ts +22 -3
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/loop-resources.ts +13 -1
- package/src/nexus/api/ops-api.ts +12 -0
- package/src/oauth/claude-pty-maturity.ts +66 -0
- package/src/oauth/codex-access-mirror.ts +55 -0
- package/src/oauth/codex.ts +7 -0
- package/src/oauth/fallback-chain.ts +1 -1
- package/src/onboarding/first-run.ts +5 -3
- package/src/onboarding/non-interactive.ts +64 -13
- package/src/onboarding.ts +10 -2
- package/src/ops/overview-collect.ts +54 -4
- package/src/ops/overview.ts +31 -7
- package/src/pr-tool/census.ts +282 -30
- package/src/pr-tool/inflight-registry.ts +160 -7
- package/src/prompt-library/gpt6-family-addendum.ts +14 -1
- package/src/pty-shell/herdr-agent-report.ts +442 -0
- package/src/pty-shell/pty-control-ipc.ts +5 -5
- package/src/pty-shell/pty-manifest.ts +7 -0
- package/src/pty-shell/pty-write-outcome.ts +24 -6
- package/src/pty-shell/tui-run-state.ts +117 -3
- package/src/release-loop/checklist.ts +103 -5
- package/src/release-loop/feature-store.ts +19 -2
- package/src/release-loop/landed-but-yellow.ts +129 -5
- package/src/release-loop/light-rc.ts +1 -0
- package/src/release-loop/placement.ts +10 -3
- package/src/release-loop/rehearsal.ts +205 -25
- package/src/release-loop/rubric.ts +16 -2
- package/src/repl/index.ts +174 -17
- package/src/repl/ops-msg-bridge.ts +32 -0
- package/src/self-dev/ask-launch-flow.ts +44 -5
- package/src/self-dev/cli-help-text.ts +17 -0
- package/src/self-dev/dev-cli.ts +11 -9
- package/src/self-dev/draft-residue.ts +37 -1
- package/src/self-dev/draft-sweep.ts +188 -13
- package/src/self-dev/draft-triage-rules.ts +107 -0
- package/src/self-dev/fleet-reduce.ts +3 -2
- package/src/self-dev/graph-front-nodes.ts +112 -0
- package/src/self-dev/graph-journey-nodes.ts +11 -6
- package/src/self-dev/graph-journey-route.ts +60 -6
- package/src/self-dev/harness-run-cli.ts +3 -15
- package/src/self-dev/orchestrate-cli-text.ts +10 -0
- package/src/self-dev/orchestrate.ts +79 -3
- package/src/self-dev/review-provider-fallback.ts +35 -1
- package/src/self-dev/run-supervisor.ts +107 -12
- package/src/self-dev/run-types.ts +5 -1
- package/src/self-dev/self-orchestrate-runtime.ts +1 -11
- package/src/self-dev/shard-aggregate.ts +42 -5
- package/src/self-dev/shard-run.ts +8 -1
- package/src/self-implement/blocked-draft-policy.ts +20 -0
- package/src/self-implement/classify-shadow.ts +3 -7
- package/src/self-implement/doctor-visit.ts +18 -1
- package/src/self-implement/gate-baseline.ts +95 -12
- package/src/self-implement/gate-cli.ts +1 -0
- package/src/self-implement/gate-remote.ts +40 -25
- package/src/self-implement/goal-author-decompose.ts +275 -47
- package/src/self-implement/goal-author-identity.ts +66 -0
- package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
- package/src/self-implement/goal-author.ts +254 -120
- package/src/self-implement/goal-elaborate.ts +295 -0
- package/src/self-implement/goal-refine.ts +270 -0
- package/src/self-implement/graph-overlay-yaml.ts +28 -2
- package/src/self-implement/graph-unit-flatten.ts +103 -0
- package/src/self-implement/graph-unit-resolver.ts +107 -0
- package/src/self-implement/graph-yaml.ts +151 -1
- package/src/self-implement/headless-elanous-driver.ts +1 -0
- package/src/self-implement/knowhow-pack.ts +103 -0
- package/src/self-implement/orchestrator.ts +160 -45
- package/src/self-implement/pod-warm-pool-profile.ts +45 -0
- package/src/self-implement/review-mustfix-class.ts +203 -0
- package/src/self-implement/rework-budget-judgment.ts +5 -8
- package/src/self-implement/run-stop.ts +17 -2
- package/src/self-implement/running-runs.ts +29 -1
- package/src/self-implement/scope-adjacency.ts +113 -0
- package/src/self-implement/seams.ts +138 -4
- package/src/self-implement/stop-autoheal.ts +112 -2
- package/src/session/chat.ts +27 -0
- package/src/session-runtime/index.ts +1 -1
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/setup/llm-env-detect.ts +5 -0
- package/src/skills/tools/agent.ts +140 -14
- package/src/skills/tools/msg-ask.ts +100 -0
- package/src/skills/tools/ops-ledger.ts +2 -1
- package/src/skills/tools/schedule-wakeup.ts +66 -17
- package/src/steward/hold-hygiene.ts +24 -6
- package/src/steward/release-day.ts +7 -3
- package/src/steward/triage-budget.ts +194 -0
- package/src/steward/triage.ts +57 -7
- package/src/task-agent/actions.ts +69 -1
- package/src/task-agent/green-sweep.ts +4 -0
- package/src/task-agent/harvest-unit.ts +141 -0
- package/src/task-agent/live-moves.ts +257 -15
- package/src/task-agent/parent-host.ts +216 -6
- package/src/task-agent/postland-card.ts +80 -1
- package/src/task-agent/rejudge-on-head.ts +112 -26
- package/src/task-agent/repair-branch-cas.ts +4 -1
- package/src/task-agent/repair-cycle.ts +16 -3
- package/src/task-agent/run-identity.ts +4 -3
- package/src/task-agent/shadow.ts +19 -3
- package/src/task-agent/task-hand.ts +96 -36
- package/src/task-agent/tier-split.ts +127 -0
- package/src/task-agent/work-order-build.ts +24 -0
- package/src/task-agent/work-order.ts +3 -2
- package/src/task-orchestrator/generator-prompt.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +72 -3
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +47 -8
- package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
- package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +72 -4
- package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +32 -5
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +421 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +588 -71
- package/src/task-orchestrator/surfaces/self-implement.ts +106 -2
- package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
- package/src/tool-runtime/truncation-store.ts +4 -0
- package/src/tui/README.md +2 -0
- package/src/tui/chat/background-job-status.ts +54 -0
- package/src/tui/chat/log-view.ts +80 -0
- package/src/tui/entry.ts +406 -0
- package/src/tui/input/composer.ts +144 -0
- package/src/tui/seat-mail-boot.ts +59 -0
- package/src/tui/slash/compact.ts +100 -0
- package/src/tui/slash/new-session.ts +35 -0
- package/src/tui-client/dashboard-session.ts +10 -1
- package/src/tui-client/local-chat-turn.ts +239 -0
- package/src/tui-client/local-harness-command.ts +63 -0
- package/src/tui-client/local-provider-command.ts +184 -0
- package/src/user-config/coercion.ts +36 -0
- package/src/user-config.ts +22 -43
- package/src/ux-sim/event-monkey.ts +378 -0
- package/src/ux-sim/fake-bin.ts +42 -7
- package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
- package/src/ux-sim/fault-pod-codex-503.ts +211 -0
- package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
- package/src/ux-sim/scenario.ts +72 -13
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
- package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
- package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
- package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5543.a438b8ab5a13ea47.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989.3694300e5f000b14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
- package/src/cli/g6a-registration-probe.ts +0 -16
- /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
|
@@ -14,7 +14,7 @@ import { debug } from '../../debug/log.js';
|
|
|
14
14
|
|
|
15
15
|
export const POD_LIFECYCLE_STAGES = ['create', 'schedule', 'clone', 'mirror', 'deps', 'test', 'delete'] as const;
|
|
16
16
|
/** si-task Pod 은 시험이 아니라 `self implement`(또는 harness ask/say) 본체를 돈다 — 그 칸은 `test` 가 아니라 `run` 이다. */
|
|
17
|
-
export const SI_TASK_POD_LIFECYCLE_STAGES = ['create', 'schedule', 'clone', 'mirror', 'deps', 'run', 'delete'] as const;
|
|
17
|
+
export const SI_TASK_POD_LIFECYCLE_STAGES = ['create', 'schedule', 'start', 'clone', 'mirror', 'deps', 'run', 'delete'] as const;
|
|
18
18
|
export type PodLifecycleStageName = typeof POD_LIFECYCLE_STAGES[number] | typeof SI_TASK_POD_LIFECYCLE_STAGES[number];
|
|
19
19
|
export type PodLifecycleClock = 'host' | 'k8s' | 'pod' | 'mixed';
|
|
20
20
|
export type PodLifecycleKind = 'gate' | 'si-task';
|
|
@@ -29,6 +29,16 @@ export interface PodLifecycleEvent {
|
|
|
29
29
|
stages: PodLifecycleStage[];
|
|
30
30
|
outcome: string;
|
|
31
31
|
missing: PodLifecycleStageName[];
|
|
32
|
+
/** si-task: the Pod whose named logs supplied the stage markers. */
|
|
33
|
+
podUid?: string | null;
|
|
34
|
+
podName?: string | null;
|
|
35
|
+
/** Original Kubernetes timestamps; null means the API did not provide one. */
|
|
36
|
+
k8s?: { created: string | null; scheduled: string | null; started: string | null; clock: 'k8s' };
|
|
37
|
+
/** A skipped install is a state with a Pod-clock time, never a fabricated duration. */
|
|
38
|
+
deps?: { status: 'skipped'; at: number; clock: 'pod'; reason: string } | { status: 'missing'; reason: string };
|
|
39
|
+
missingReasons?: Partial<Record<PodLifecycleStageName, string>>;
|
|
40
|
+
podSelectionReason?: string | null;
|
|
41
|
+
watch?: { start: number; end: number; clock: 'host' };
|
|
32
42
|
[extra: string]: unknown;
|
|
33
43
|
}
|
|
34
44
|
|
|
@@ -118,9 +128,40 @@ export function siTaskPodStageShell(stage: SiTaskMarkedStage, edge: 'start' | 'e
|
|
|
118
128
|
return `printf 'ELANOUS_POD_STAGE ${stage} ${edge} %s\\n' "$(date +%s)" || true`;
|
|
119
129
|
}
|
|
120
130
|
const SI_TASK_STAGE_LINE = /^ELANOUS_POD_STAGE (clone|mirror|run) (start|end) (\d{1,12})\r?$/gm;
|
|
131
|
+
const SI_TASK_DEPS_SKIPPED_LINE = /^ELANOUS_POD_DEPS skipped (\d{1,12}) (image-prepared-no-install)\r?$/m;
|
|
132
|
+
|
|
133
|
+
export function parseSiTaskDepsSkipped(logs: string | undefined): { at: number; reason: string } | undefined {
|
|
134
|
+
const match = logs?.match(SI_TASK_DEPS_SKIPPED_LINE);
|
|
135
|
+
return match ? { at: Number(match[1]), reason: match[2]! } : undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** The API timestamps belong to one Pod UID; retries must never combine two Pods' clocks. */
|
|
139
|
+
export function siTaskPodK8sTiming(json: string | undefined, childRunLabel: string, podJob: string, jobUid: string | undefined): { podName?: string; podUid?: string; podCreated?: string; podScheduled?: string; containerStarted?: string; podSelectionReason?: string } {
|
|
140
|
+
try {
|
|
141
|
+
const items = (JSON.parse(json ?? '') as { items?: unknown[] }).items;
|
|
142
|
+
if (!Array.isArray(items)) return {};
|
|
143
|
+
const matching = items.filter((item): item is Record<string, any> => !!item && typeof item === 'object')
|
|
144
|
+
.filter((item) => item.metadata?.labels?.['elanous.child-run'] === childRunLabel);
|
|
145
|
+
// `logs job/<name>` may choose either Pod. No identity can safely be joined when
|
|
146
|
+
// more than one Pod belongs to this child run, even if one was created later.
|
|
147
|
+
if (matching.length > 1) return { podSelectionReason: 'ambiguous-pod-attempts' };
|
|
148
|
+
const pod = matching[0];
|
|
149
|
+
if (!pod || typeof pod.metadata?.name !== 'string' || typeof pod.metadata?.uid !== 'string') return {};
|
|
150
|
+
const jobLabels = [pod.metadata.labels?.['batch.kubernetes.io/job-name'], pod.metadata.labels?.['job-name']].filter((value): value is string => typeof value === 'string');
|
|
151
|
+
const owned = pod.metadata.ownerReferences?.some((owner: any) => owner?.kind === 'Job' && owner?.name === podJob && owner?.uid === jobUid);
|
|
152
|
+
if (!jobUid || jobLabels.length === 0 || jobLabels.some((value) => value !== podJob) || !owned) return { podSelectionReason: 'pod-job-unverified' };
|
|
153
|
+
const scheduled = pod.status?.conditions?.find((condition: any) => condition?.type === 'PodScheduled' && condition.status === 'True')?.lastTransitionTime;
|
|
154
|
+
const child = pod.status?.containerStatuses?.find((status: any) => status?.name === 'child');
|
|
155
|
+
const started = child?.state?.running?.startedAt ?? child?.state?.terminated?.startedAt;
|
|
156
|
+
return { podName: pod.metadata.name, podUid: pod.metadata.uid,
|
|
157
|
+
...(isoMs(pod.metadata.creationTimestamp) !== undefined ? { podCreated: pod.metadata.creationTimestamp } : {}),
|
|
158
|
+
...(isoMs(scheduled) !== undefined ? { podScheduled: scheduled } : {}),
|
|
159
|
+
...(isoMs(started) !== undefined ? { containerStarted: started } : {}) };
|
|
160
|
+
} catch { return {}; }
|
|
161
|
+
}
|
|
121
162
|
|
|
122
163
|
/**
|
|
123
|
-
*
|
|
164
|
+
* 선택된 Pod 로그에서 단계 표지를 읽는다 → `{ 'clone-start': 초, 'clone-end': 초, … }` (gate 의 podStages 와 같은 꼴).
|
|
124
165
|
* 같은 표지가 두 번 나오면 «첫» 값 — 셸 표지는 모두 자식 출력(`cat /tmp/si.out`)보다 앞에 찍히므로, 자식이 같은 모양의 줄을
|
|
125
166
|
* 내도 셸 값을 덮지 못한다(리뷰 should-fix). 모르는 단계·꼴은 버린다(지어내지 않는다).
|
|
126
167
|
*/
|
|
@@ -135,12 +176,12 @@ export function parseSiTaskPodStages(logs: string | undefined): Record<string, n
|
|
|
135
176
|
}
|
|
136
177
|
|
|
137
178
|
/**
|
|
138
|
-
* si-task Pod —
|
|
179
|
+
* si-task Pod — Kubernetes 원시 시각으로 create · schedule · start, Pod 셸 표지로 clone · mirror · run 을 채운다.
|
|
139
180
|
* - clone = 소스 받기(`podSourceScript`) 시작 → 그 스크립트 전체가 끝난 뒤(`cd repo` 포함 · 어느 줄에서든 exit 하면 끝이 없다 → missing)
|
|
140
181
|
* - mirror = 호스트 미러 `clone --shared` 시도 → 성공(미러를 건너뛰면 끝이 없다 → missing)
|
|
141
|
-
* - deps =
|
|
182
|
+
* - deps = 현재 이미지는 의존성을 미리 포함한다. 자식이 install 생략 시각과 이유를 별도 상태로 기록한다.
|
|
142
183
|
* - run = 본체(`self implement` · `harness ask`/`say`) 띄움 → `wait` 가 돌아옴(SIGTERM 이면 끝이 없다 → missing)
|
|
143
|
-
* -
|
|
184
|
+
* - delete = 이 경로에서 관측하지 않는다 → missing.
|
|
144
185
|
* 호스트가 지켜본 구간은 단계가 아닌 `watch`(host 시계)로 따로 싣는다 — 단계로 지어내지 않는다.
|
|
145
186
|
*/
|
|
146
187
|
export function siTaskPodLifecycleEvent(input: {
|
|
@@ -149,16 +190,53 @@ export function siTaskPodLifecycleEvent(input: {
|
|
|
149
190
|
host?: string | null;
|
|
150
191
|
watchStart?: number;
|
|
151
192
|
watchEnd?: number;
|
|
193
|
+
createStart?: number;
|
|
152
194
|
podStages?: Readonly<Record<string, number>>;
|
|
195
|
+
podUid?: string;
|
|
196
|
+
podName?: string;
|
|
197
|
+
podSelectionReason?: string;
|
|
198
|
+
podCreated?: string;
|
|
199
|
+
podScheduled?: string;
|
|
200
|
+
containerStarted?: string;
|
|
201
|
+
depsSkipped?: { at: number; reason: string };
|
|
153
202
|
outcome: string;
|
|
154
203
|
}): PodLifecycleEvent {
|
|
155
204
|
const pod = input.podStages ?? {};
|
|
156
|
-
const
|
|
205
|
+
const created = isoMs(input.podCreated);
|
|
206
|
+
const scheduled = isoMs(input.podScheduled);
|
|
207
|
+
const started = isoMs(input.containerStarted);
|
|
208
|
+
const measured: Measured = {
|
|
209
|
+
create: { start: input.createStart, end: created, clock: 'mixed' },
|
|
210
|
+
schedule: { start: created, end: scheduled, clock: 'k8s' },
|
|
211
|
+
start: { start: scheduled, end: started, clock: 'k8s' },
|
|
212
|
+
};
|
|
157
213
|
for (const name of SI_TASK_MARKED_STAGES) measured[name] = { start: podSecondsMs(pod[`${name}-start`]), end: podSecondsMs(pod[`${name}-end`]), clock: 'pod' };
|
|
158
214
|
const { stages, missing } = splitPodLifecycleStages(measured, SI_TASK_POD_LIFECYCLE_STAGES);
|
|
159
|
-
const
|
|
215
|
+
const watchStart = input.watchStart;
|
|
216
|
+
const watchEnd = input.watchEnd;
|
|
217
|
+
let watch: PodLifecycleEvent['watch'];
|
|
218
|
+
if (watchStart !== undefined && watchEnd !== undefined && Number.isFinite(watchStart) && Number.isFinite(watchEnd) && watchEnd >= watchStart) {
|
|
219
|
+
watch = { start: watchStart, end: watchEnd, clock: 'host' };
|
|
220
|
+
}
|
|
221
|
+
const missingReason = (stage: PodLifecycleStageName): string => {
|
|
222
|
+
if (input.podSelectionReason && stage !== 'delete') return input.podSelectionReason;
|
|
223
|
+
if (stage === 'deps') return input.depsSkipped ? `skipped:${input.depsSkipped.reason}` : 'child-deps-marker-unavailable';
|
|
224
|
+
if (stage === 'delete') return 'not-observed';
|
|
225
|
+
if (stage === 'create' && input.createStart === undefined) return 'host-apply-start-unavailable';
|
|
226
|
+
if (stage === 'create' || stage === 'schedule' || stage === 'start') {
|
|
227
|
+
const timestamps = stage === 'create' ? [created] : stage === 'schedule' ? [created, scheduled] : [scheduled, started];
|
|
228
|
+
return timestamps.some((time) => time === undefined) ? 'k8s-timestamp-unavailable' : 'clock-order-invalid';
|
|
229
|
+
}
|
|
230
|
+
return 'stage-marker-unavailable';
|
|
231
|
+
};
|
|
160
232
|
return { runId: input.runId ?? null, podJob: input.podJob, host: input.host ?? null, kind: 'si-task', stages, outcome: input.outcome, missing,
|
|
161
|
-
|
|
233
|
+
podUid: input.podUid ?? null, podName: input.podName ?? null,
|
|
234
|
+
k8s: { created: input.podCreated ?? null, scheduled: input.podScheduled ?? null, started: input.containerStarted ?? null, clock: 'k8s' },
|
|
235
|
+
deps: input.depsSkipped ? { status: 'skipped', at: input.depsSkipped.at * 1000, clock: 'pod', reason: input.depsSkipped.reason }
|
|
236
|
+
: { status: 'missing', reason: input.podSelectionReason ?? 'child-deps-marker-unavailable' },
|
|
237
|
+
podSelectionReason: input.podSelectionReason ?? null,
|
|
238
|
+
missingReasons: Object.fromEntries(missing.map((stage) => [stage, missingReason(stage)])),
|
|
239
|
+
...(watch ? { watch } : {}) };
|
|
162
240
|
}
|
|
163
241
|
|
|
164
242
|
export type PodLifecycleLog = (category: string, event: string, data: Record<string, unknown>) => void;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BUDGET_SNAPSHOT_ENV } from '../../execution-loop/launch-gate.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/** The Pod push fence embeds a different six-hex run key in each independent launch. */
|
|
4
|
+
export function stablePodRunGuard(text: string): string {
|
|
5
|
+
return text.replace(/pr-create-r[0-9a-f]{6}-/g, 'pr-create-r<run>-')
|
|
6
|
+
.replace(/-r[0-9a-f]{6}(?=[-|*])/g, '-r<run>');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Preserve the manifest contract except for the budget timestamp and run identities generated per launch.
|
|
4
10
|
export function stablePodManifestText(applied: Array<Record<string, any>>): string {
|
|
5
11
|
const manifests = structuredClone(applied.filter((entry) => entry.kind === 'Job' || entry.kind === 'Secret'));
|
|
6
12
|
let snapshots = 0;
|
|
@@ -19,5 +25,5 @@ export function stablePodManifestText(applied: Array<Record<string, any>>): stri
|
|
|
19
25
|
}
|
|
20
26
|
}
|
|
21
27
|
if (snapshots === 0) throw new Error('manifest comparison requires a budget snapshot');
|
|
22
|
-
return JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>');
|
|
28
|
+
return stablePodRunGuard(JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>'));
|
|
23
29
|
}
|
|
@@ -294,6 +294,8 @@ export class PodPoolScheduler {
|
|
|
294
294
|
* GATE-RESERVE-AUTO CPU bound, which exists to protect the gate from harness Pods, not from itself.
|
|
295
295
|
*/
|
|
296
296
|
private readonly gateAdmission: PodLeaseAdmission;
|
|
297
|
+
/** A launch with an explicit memory limit must be measured with that limit, not the pool's 16Gi default. */
|
|
298
|
+
private readonly memoryAdmissions = new Map<string, { admission: PodLeaseAdmission; reading: () => PoolLeaseRecommendation | null; measure: () => Promise<PoolLeaseRecommendation>; take: () => void; release: () => void }>();
|
|
297
299
|
private readonly outstanding = new Set<PodLeaseRelease>();
|
|
298
300
|
private lastFree = 0;
|
|
299
301
|
private budget = 0;
|
|
@@ -301,6 +303,8 @@ export class PodPoolScheduler {
|
|
|
301
303
|
private seenActive = 0;
|
|
302
304
|
private initialized = false;
|
|
303
305
|
private readonly measure: () => Promise<PoolLeaseRecommendation>;
|
|
306
|
+
private readonly measureForMemory: (memoryLimit: string) => Promise<PoolLeaseRecommendation>;
|
|
307
|
+
private readonly dependencyMerged: (after: PodLeasePredecessor, signal?: AbortSignal) => PredecessorState | boolean | Promise<PredecessorState | boolean>;
|
|
304
308
|
private lastRaw: PoolLeaseRecommendation | null = null;
|
|
305
309
|
/** GATE-ADMIT-EXEMPT — the same reading before the gate CPU cap (memory/limitedBy unchanged); gate callers read it. */
|
|
306
310
|
private lastUncapped: PoolLeaseRecommendation | null = null;
|
|
@@ -308,18 +312,18 @@ export class PodPoolScheduler {
|
|
|
308
312
|
private readonly pollMs: number;
|
|
309
313
|
private readonly occupancy: () => Record<string, MemberOccupancy> | Promise<Record<string, MemberOccupancy>>;
|
|
310
314
|
private readonly memberMemory: () => Array<{ context: string; allocatableMemoryBytes: number | null }> | Promise<Array<{ context: string; allocatableMemoryBytes: number | null }>>;
|
|
311
|
-
constructor(readonly members: readonly PodPoolMember[], options: { status?: () => PoolLeaseRecommendation | Promise<PoolLeaseRecommendation>; kubectl?: PoolKubectl; dns?: (context: string) => PoolDnsProbe; pollMs?: number; hostLease?: HostPoolLease; memberMemory?: () => Array<{ context: string; allocatableMemoryBytes: number | null }> | Promise<Array<{ context: string; allocatableMemoryBytes: number | null }>>; occupancy?: () => Record<string, MemberOccupancy> | Promise<Record<string, MemberOccupancy>>; dependencyMerged?: (after: PodLeasePredecessor, signal?: AbortSignal) => PredecessorState | boolean | Promise<PredecessorState | boolean> } = {}) {
|
|
315
|
+
constructor(readonly members: readonly PodPoolMember[], options: { status?: (memoryLimit?: string) => PoolLeaseRecommendation | Promise<PoolLeaseRecommendation>; kubectl?: PoolKubectl; dns?: (context: string) => PoolDnsProbe; pollMs?: number; hostLease?: HostPoolLease; memberMemory?: () => Array<{ context: string; allocatableMemoryBytes: number | null }> | Promise<Array<{ context: string; allocatableMemoryBytes: number | null }>>; occupancy?: () => Record<string, MemberOccupancy> | Promise<Record<string, MemberOccupancy>>; dependencyMerged?: (after: PodLeasePredecessor, signal?: AbortSignal) => PredecessorState | boolean | Promise<PredecessorState | boolean> } = {}) {
|
|
312
316
|
this.pollMs = options.pollMs ?? 15_000;
|
|
313
317
|
// One lease directory per pool (contexts, not caps) — every CLI process launching into the same clusters shares it.
|
|
314
318
|
this.hostLease = options.hostLease ?? podPoolHostLease(members);
|
|
315
319
|
// GATE-RESERVE-AUTO: the gate reservation is returned beside the recommendation, never folded into it — the
|
|
316
320
|
// delta budget below must not see a gate start/end as a free-slot change (that made the result order-dependent).
|
|
317
|
-
const measureStatus: () => Promise<{ status: PoolLeaseRecommendation; gateSlots: number | null | undefined }> = options.status
|
|
318
|
-
? async () => ({ status: await options.status!(), gateSlots: undefined })
|
|
319
|
-
: async () => {
|
|
321
|
+
const measureStatus: (memoryLimit?: string) => Promise<{ status: PoolLeaseRecommendation; gateSlots: number | null | undefined }> = options.status
|
|
322
|
+
? async (memoryLimit) => ({ status: await options.status!(memoryLimit), gateSlots: undefined })
|
|
323
|
+
: async (memoryLimit) => {
|
|
320
324
|
// POD-ADMIT-BY-USAGE: admission reads observed Pod usage (`kubectl top`); tryAcquire's occupancy read does not.
|
|
321
325
|
const measure = measurePoolLease(members, { ...(options.kubectl ? { kubectl: options.kubectl } : {}), ...(options.dns ? { dns: options.dns } : {}), measureUsage: true });
|
|
322
|
-
return { status: recommendConcurrency(measure, { capacity: members.reduce((n, m) => n + m.capacity, 0), accounts: 0, perAccount: 0 }), gateSlots: harnessCpuSlotsBesideGate(measure) };
|
|
326
|
+
return { status: recommendConcurrency(measure, { capacity: members.reduce((n, m) => n + m.capacity, 0), ...(memoryLimit ? { perGoalMemory: memoryLimit } : {}), accounts: 0, perAccount: 0 }), gateSlots: harnessCpuSlotsBesideGate(measure) };
|
|
323
327
|
};
|
|
324
328
|
/** Cluster-level additional slots for the cross-process host lease: the measured free slots, capped by the gate's CPU. */
|
|
325
329
|
const capped = ({ status, gateSlots }: { status: PoolLeaseRecommendation; gateSlots: number | null | undefined }): PoolLeaseRecommendation =>
|
|
@@ -327,6 +331,7 @@ export class PodPoolScheduler {
|
|
|
327
331
|
: gateSlots === null ? { ...status, recommended: null, reason: '측정 불가: gate CPU' }
|
|
328
332
|
: { ...status, recommended: Math.min(status.recommended, gateSlots) };
|
|
329
333
|
this.measure = async () => { const reading = await measureStatus(); this.lastUncapped = reading.status; return capped(reading); };
|
|
334
|
+
this.measureForMemory = async (memoryLimit) => capped(await measureStatus(memoryLimit));
|
|
330
335
|
// An injected status (tests, callers with their own measurement) without memberMemory never shells out to kubectl here.
|
|
331
336
|
this.memberMemory = options.memberMemory ?? (options.status ? (() => []) : () => measurePoolLease(members, { ...(options.kubectl ? { kubectl: options.kubectl } : {}), ...(options.dns ? { dns: options.dns } : {}) }).members
|
|
332
337
|
.map((m: PodLeaseMember) => ({ context: m.context, allocatableMemoryBytes: m.allocatableMemoryBytes })));
|
|
@@ -379,28 +384,74 @@ export class PodPoolScheduler {
|
|
|
379
384
|
? { ...decision, recommended, reason: '측정 불가: gate CPU' }
|
|
380
385
|
: { ...decision, recommended };
|
|
381
386
|
};
|
|
382
|
-
|
|
383
|
-
this.admission = new PodLeaseAdmission({ status: () => decide(false), ...(options.pollMs ? { pollMs: options.pollMs } : {}), dependencyMerged });
|
|
384
|
-
this.gateAdmission = new PodLeaseAdmission({ status: () => decide(true), ...(options.pollMs ? { pollMs: options.pollMs } : {}), dependencyMerged });
|
|
387
|
+
this.dependencyMerged = options.dependencyMerged ?? ((after: PodLeasePredecessor, signal?: AbortSignal) => predecessorState(after, {}, signal));
|
|
388
|
+
this.admission = new PodLeaseAdmission({ status: () => decide(false), ...(options.pollMs ? { pollMs: options.pollMs } : {}), dependencyMerged: this.dependencyMerged });
|
|
389
|
+
this.gateAdmission = new PodLeaseAdmission({ status: () => decide(true), ...(options.pollMs ? { pollMs: options.pollMs } : {}), dependencyMerged: this.dependencyMerged });
|
|
390
|
+
}
|
|
391
|
+
private memoryAdmission(memoryLimit: string): { admission: PodLeaseAdmission; reading: () => PoolLeaseRecommendation | null; measure: () => Promise<PoolLeaseRecommendation>; take: () => void; release: () => void } {
|
|
392
|
+
const existing = this.memoryAdmissions.get(memoryLimit);
|
|
393
|
+
if (existing) return existing;
|
|
394
|
+
let last: PoolLeaseRecommendation | null = null;
|
|
395
|
+
let admission: PodLeaseAdmission;
|
|
396
|
+
let lastFree = 0;
|
|
397
|
+
let budget = 0;
|
|
398
|
+
let initialized = false;
|
|
399
|
+
const measure = async () => { last = await this.measureForMemory(memoryLimit); return last; };
|
|
400
|
+
admission = new PodLeaseAdmission({
|
|
401
|
+
status: async () => {
|
|
402
|
+
const raw = await measure();
|
|
403
|
+
if (raw.recommended === null) return raw;
|
|
404
|
+
const ownStart = this.hostLease.selfStart();
|
|
405
|
+
const pendingJobs = raw.pendingJobs ?? [];
|
|
406
|
+
const transferId = process.env.ELANOUS_POD_RESERVED_LEASE;
|
|
407
|
+
const transferIsOther = !!transferId && this.hostLease.reservationIsOther(transferId);
|
|
408
|
+
const others = this.hostLease.live().filter((r) =>
|
|
409
|
+
(r.pid !== process.pid || r.startedAt !== ownStart) && !leaseHasPendingPod(r, pendingJobs)).length;
|
|
410
|
+
const available = Math.max(0, raw.recommended - others + (transferIsOther ? 1 : 0));
|
|
411
|
+
// A repeated stale reading does not mint another permit before an admitted Job is observed.
|
|
412
|
+
// Other tiers and processes share the host lease, which enforces the pool cap before Job apply.
|
|
413
|
+
budget = Math.max(0, budget + available - (initialized ? lastFree : 0));
|
|
414
|
+
initialized = true;
|
|
415
|
+
lastFree = available;
|
|
416
|
+
return { ...raw, recommended: admission.snapshot().active + budget };
|
|
417
|
+
},
|
|
418
|
+
pollMs: this.pollMs,
|
|
419
|
+
dependencyMerged: this.dependencyMerged,
|
|
420
|
+
});
|
|
421
|
+
const entry = { admission, reading: () => last, measure,
|
|
422
|
+
take: () => { budget = Math.max(0, budget - 1); },
|
|
423
|
+
release: () => { if (lastFree > 0) budget = Math.min(lastFree, budget + 1); },
|
|
424
|
+
};
|
|
425
|
+
this.memoryAdmissions.set(memoryLimit, entry);
|
|
426
|
+
return entry;
|
|
385
427
|
}
|
|
386
428
|
/** FIFO gate within this process, then a host lease so independent CLI processes cannot over-admit the same pool. */
|
|
387
|
-
async acquireAdmission(signal?: AbortSignal, after?: PodLeasePredecessor, opts: { gate?: boolean } = {}): Promise<PodLeaseRelease & { applied: (job: string, context: string, namespace: string) => void; observed: () => void }> {
|
|
429
|
+
async acquireAdmission(signal?: AbortSignal, after?: PodLeasePredecessor, opts: { gate?: boolean; memoryLimit?: string } = {}): Promise<PodLeaseRelease & { applied: (job: string, context: string, namespace: string) => void; observed: () => void }> {
|
|
388
430
|
const gate = opts.gate === true;
|
|
389
|
-
const
|
|
431
|
+
const lane = !gate && opts.memoryLimit && opts.memoryLimit !== '16Gi' ? this.memoryAdmission(opts.memoryLimit) : null;
|
|
432
|
+
const local = lane ? await lane.admission.acquire(signal, after).then((release) => {
|
|
433
|
+
lane.take();
|
|
434
|
+
let done = false;
|
|
435
|
+
return () => { if (done) return; done = true; lane.release(); release(); };
|
|
436
|
+
}) : await this.acquireLocalAdmission(signal, after, gate);
|
|
390
437
|
try {
|
|
391
438
|
for (;;) {
|
|
392
439
|
if (signal?.aborted) throw new Error('pod lease admission aborted');
|
|
393
440
|
// GATE-ADMIT-EXEMPT: a gate caller is not bounded by its own gate's CPU reservation (memory still bounds it).
|
|
394
|
-
const
|
|
441
|
+
const reading = lane?.reading() ?? (gate ? this.lastUncapped : this.lastRaw);
|
|
442
|
+
const free = reading?.recommended ?? null;
|
|
395
443
|
// Same check as the local gate, but atomic across processes: other authoring and pre-Running leases hold slots.
|
|
396
444
|
const reservedId = process.env.ELANOUS_POD_RESERVED_LEASE;
|
|
397
445
|
const transferred = reservedId ? this.hostLease.claim(reservedId) : null;
|
|
398
446
|
if (reservedId && !transferred) throw new Error('pod lease: authoring reservation could not be transferred');
|
|
399
447
|
if (transferred) delete process.env.ELANOUS_POD_RESERVED_LEASE;
|
|
400
|
-
const pendingJobs =
|
|
448
|
+
const pendingJobs = reading?.pendingJobs ?? [];
|
|
401
449
|
const lease = transferred ?? (free !== null && free > 0 ? this.hostLease.tryReserve((others) =>
|
|
402
450
|
others - this.hostLease.live().filter((r) => leaseHasPendingPod(r, pendingJobs) &&
|
|
403
|
-
(r.pid !== process.pid || r.startedAt !== this.hostLease.selfStart())).length < free
|
|
451
|
+
((lane || this.memoryAdmissions.size > 0) || r.pid !== process.pid || r.startedAt !== this.hostLease.selfStart())).length < free,
|
|
452
|
+
// The legacy queue accounts for its own permits locally. Mixed memory tiers have separate queues,
|
|
453
|
+
// so their host leases must count together under the same pool cap.
|
|
454
|
+
!!lane || this.memoryAdmissions.size > 0) : (gate && free === null ? this.hostLease.tryReserve(() => true) : null));
|
|
404
455
|
if (lease) {
|
|
405
456
|
let hostReleased = false;
|
|
406
457
|
const releaseHost = () => { if (!hostReleased) { hostReleased = true; lease(); } };
|
|
@@ -421,7 +472,8 @@ export class PodPoolScheduler {
|
|
|
421
472
|
const onAbort = () => { clearTimeout(timer); reject(new Error('pod lease admission aborted')); };
|
|
422
473
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
423
474
|
});
|
|
424
|
-
try {
|
|
475
|
+
try { if (lane) await lane.measure(); else this.lastRaw = await this.measure(); }
|
|
476
|
+
catch { if (!lane) { this.lastRaw = null; this.lastUncapped = null; } }
|
|
425
477
|
}
|
|
426
478
|
} catch (error) {
|
|
427
479
|
local();
|
|
@@ -454,14 +506,18 @@ export class PodPoolScheduler {
|
|
|
454
506
|
? [{ context: r.context, allocatableMemoryBytes: r.allocatableMemoryBytes }] : []);
|
|
455
507
|
}
|
|
456
508
|
/** Why admission is still waiting: the pool-wide lease measurement (null before any reading). Slot waits get their reason from tryAcquire's onEmpty. */
|
|
457
|
-
waitReason(): string | null {
|
|
458
|
-
const r = this.lastRaw;
|
|
509
|
+
waitReason(memoryLimit?: string): string | null {
|
|
510
|
+
const r = memoryLimit && memoryLimit !== '16Gi' ? this.memoryAdmissions.get(memoryLimit)?.reading() : this.lastRaw;
|
|
459
511
|
if (!r) return null;
|
|
460
512
|
return `recommended=${r.recommended ?? 'unknown'} limitedBy=${r.limitedBy ?? '-'} memorySlots=${r.memorySlots ?? '?'}${r.reason ? ` reason=${r.reason}` : ''}`;
|
|
461
513
|
}
|
|
462
514
|
/** The harness queue by default; `{ gate: true }` reads the gate-caller queue (GATE-ADMIT-EXEMPT). */
|
|
463
515
|
admissionSnapshot(opts: { gate?: boolean } = {}): ReturnType<PodLeaseAdmission['snapshot']> {
|
|
464
|
-
|
|
516
|
+
if (opts.gate) return this.gateAdmission.snapshot();
|
|
517
|
+
const snapshots = [this.admission.snapshot(), ...[...this.memoryAdmissions.values()].map((lane) => lane.admission.snapshot())];
|
|
518
|
+
return { active: snapshots.reduce((n, item) => n + item.active, 0), queued: snapshots.reduce((n, item) => n + item.queued, 0),
|
|
519
|
+
recommended: Math.min(this.members.reduce((n, item) => n + item.capacity, 0), snapshots.reduce((n, item) => n + item.recommended, 0)),
|
|
520
|
+
waiting: snapshots.flatMap((item) => item.waiting) };
|
|
465
521
|
}
|
|
466
522
|
/**
|
|
467
523
|
* Pick the member with the largest free share: (capacity − measured cluster occupancy − this process's inflight) / capacity.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { redactSecretText } from '../../debug/log.js';
|
|
2
|
+
|
|
3
|
+
/** The work that owns a Pod. Job metadata is the current view; pod.provenance events retain history. */
|
|
4
|
+
export interface PodProvenance {
|
|
5
|
+
actorKind: string;
|
|
6
|
+
actor: string;
|
|
7
|
+
kind: string;
|
|
8
|
+
run: string;
|
|
9
|
+
phase: string;
|
|
10
|
+
requestedAt: string;
|
|
11
|
+
character?: string;
|
|
12
|
+
launchHost?: string;
|
|
13
|
+
entrance?: string;
|
|
14
|
+
graphNode?: string;
|
|
15
|
+
cell?: string;
|
|
16
|
+
version?: string;
|
|
17
|
+
commit?: string;
|
|
18
|
+
shard?: string;
|
|
19
|
+
reason?: string;
|
|
20
|
+
pool?: string;
|
|
21
|
+
cpuReq?: string;
|
|
22
|
+
memReq?: string;
|
|
23
|
+
warmReused?: boolean;
|
|
24
|
+
argv?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const required = ['actorKind', 'actor', 'kind', 'run', 'phase', 'requestedAt'] as const;
|
|
28
|
+
const names: Record<keyof PodProvenance, string> = {
|
|
29
|
+
actorKind: 'actor-kind', actor: 'actor', kind: 'kind', run: 'run', phase: 'phase', requestedAt: 'requested-at',
|
|
30
|
+
character: 'character', launchHost: 'launch-host', entrance: 'entrance', graphNode: 'graph-node', cell: 'cell',
|
|
31
|
+
version: 'version', commit: 'commit', shard: 'shard', reason: 'reason',
|
|
32
|
+
pool: 'pool', cpuReq: 'cpu-req', memReq: 'mem-req',
|
|
33
|
+
warmReused: 'warm-reused', argv: 'argv',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const labelValue = (value: string): string => {
|
|
37
|
+
const cleaned = value.toLowerCase().replace(/[^a-z0-9._-]/g, '-').replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '');
|
|
38
|
+
return cleaned.slice(0, 63).replace(/[^a-z0-9]+$/g, '') || 'unknown';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface PodProvenanceMetadata {
|
|
42
|
+
labels: Record<string, string>;
|
|
43
|
+
annotations: Record<string, string>;
|
|
44
|
+
env: Array<{ name: string; value: string }>;
|
|
45
|
+
missing: string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A gate reports missing identity as `unknown`; every other launch refuses it before kubectl apply. */
|
|
49
|
+
export function podProvenanceMetadata(input: Partial<PodProvenance> | undefined, gate = false): PodProvenanceMetadata {
|
|
50
|
+
const missing = required.filter((key) => typeof input?.[key] !== 'string' || !input?.[key]?.trim());
|
|
51
|
+
if (missing.length && !gate) throw new Error(`pod provenance missing: ${missing.map((key) => names[key]).join(', ')}`);
|
|
52
|
+
const values: Record<string, string> = {};
|
|
53
|
+
for (const [key, name] of Object.entries(names) as Array<[keyof PodProvenance, string]>) {
|
|
54
|
+
const raw = input?.[key];
|
|
55
|
+
if (raw === undefined || raw === null || raw === '') continue;
|
|
56
|
+
const value = String(raw).trim();
|
|
57
|
+
if (!value) continue;
|
|
58
|
+
// Metadata and env are observable by many users. Never carry a raw secret through an identity field.
|
|
59
|
+
const redacted = redactSecretText(value);
|
|
60
|
+
if (redacted !== value && key !== 'reason' && key !== 'argv') throw new Error(`pod provenance secret in ${name}`);
|
|
61
|
+
values[name] = redacted;
|
|
62
|
+
}
|
|
63
|
+
for (const key of missing) values[names[key]] = 'unknown';
|
|
64
|
+
// The launch reason is observable even when the caller cannot supply one.
|
|
65
|
+
values.reason ??= 'unknown';
|
|
66
|
+
const labels: Record<string, string> = {};
|
|
67
|
+
const annotations: Record<string, string> = {};
|
|
68
|
+
const env: Array<{ name: string; value: string }> = [];
|
|
69
|
+
for (const [name, value] of Object.entries(values)) {
|
|
70
|
+
const label = name === 'run' || name === 'commit' ? value.slice(0, 8) : value;
|
|
71
|
+
if (name !== 'reason' && name !== 'argv') labels[`elanous.ai/${name}`] = labelValue(label);
|
|
72
|
+
annotations[`elanous.ai/${name}`] = value;
|
|
73
|
+
env.push({ name: `ELANOUS_POD_${name.toUpperCase().replaceAll('-', '_')}`, value });
|
|
74
|
+
}
|
|
75
|
+
return { labels, annotations, env, missing: missing.map((key) => names[key]) };
|
|
76
|
+
}
|
|
@@ -56,13 +56,48 @@ function assertRemoteBase(repoUrl: string, base: string): void {
|
|
|
56
56
|
/** Job 스크립트의 원천 단계. 성공 갈래는 `ELANOUS_POD_SOURCE <kind> <HEAD>` 로 끝난다.
|
|
57
57
|
* `stageMarkers` — si-task Job 만: 호스트 미러 `clone --shared` 시도의 시작·성공을 `ELANOUS_POD_STAGE mirror start|end` 로 찍는다
|
|
58
58
|
* (건너뛰거나 실패하면 끝 표지가 없다 → 호스트가 missing 으로 읽는다). 기본은 꺼짐 — gate·pod-command Job 의 바이트는 그대로다. */
|
|
59
|
-
export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath = '/host-mirror', options: { stageMarkers?: boolean } = {}): string {
|
|
59
|
+
export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath = '/host-mirror', options: { stageMarkers?: boolean; imageSourceDir?: string; imageCommitFile?: string; imageGitDir?: string } = {}): string {
|
|
60
60
|
const mark = (edge: 'start' | 'end'): string[] => options.stageMarkers ? [siTaskPodStageShell('mirror', edge)] : [];
|
|
61
61
|
const quotedUrl = `'${repoUrl.replace(/'/g, `'\\''`)}'`;
|
|
62
62
|
const quotedMirror = `'${mirrorPath.replace(/'/g, `'\\''`)}'`;
|
|
63
|
+
const quotedImageDir = `'${(options.imageSourceDir ?? '/opt/elanous-source').replace(/'/g, `'\\''`)}'`;
|
|
64
|
+
const quotedCommitFile = `'${(options.imageCommitFile ?? '/opt/elanous-source-commit').replace(/'/g, `'\\''`)}'`;
|
|
65
|
+
const quotedImageGitDir = `'${(options.imageGitDir ?? '/opt/elanous-pin.git').replace(/'/g, `'\\''`)}'`;
|
|
63
66
|
const clone = `git clone -q --depth 50 ${quotedUrl} repo`;
|
|
64
67
|
const start = [
|
|
65
68
|
'if [ -e repo ]; then exit 5; fi',
|
|
69
|
+
// POD-MIRROR-IO: the image's pinned tree is a shared read-only lower layer.
|
|
70
|
+
// Git metadata is tiny and private to this Pod; alternates point first at
|
|
71
|
+
// the image's shallow pin objects, then optionally at the host mirror.
|
|
72
|
+
'source_via=',
|
|
73
|
+
`if [ -f ${quotedCommitFile} ] && [ -d ${quotedImageDir} ] && [ -d ${quotedImageGitDir} ]; then`,
|
|
74
|
+
// Older pinned images can contain macOS AppleDouble pack sidecars. Git may
|
|
75
|
+
// interpret `._pack-*.idx` as an index and fail even when the real pack is valid.
|
|
76
|
+
` if [ -d ${quotedImageGitDir}/objects/pack ]; then find ${quotedImageGitDir}/objects/pack -maxdepth 1 -type f -name '._*' -delete || { printf 'ELANOUS_POD_SOURCE_IMAGE_FAIL appledouble-cleanup\n'; exit 5; }; fi`,
|
|
77
|
+
` image_commit=$(cat ${quotedCommitFile})`,
|
|
78
|
+
` if [[ "$image_commit" =~ ^[0-9a-f]{40}$ ]] && git -C ${quotedImageGitDir} cat-file -e "$image_commit^{commit}" 2>/dev/null && [ -f ${quotedImageGitDir}/shallow ] && grep -Fxq "$image_commit" ${quotedImageGitDir}/shallow; then`,
|
|
79
|
+
` ln -s ${quotedImageDir} repo || exit 5`,
|
|
80
|
+
` image_objects=$(git -C ${quotedImageGitDir} rev-parse --path-format=absolute --git-path objects)`,
|
|
81
|
+
` if git -C repo init -q -b main && mkdir -p repo/.git/objects/info && printf '%s\\n' "$image_objects" > repo/.git/objects/info/alternates; then`,
|
|
82
|
+
` if [ -d ${quotedMirror} ]; then mirror_objects=$(git -C ${quotedMirror} rev-parse --path-format=absolute --git-path objects 2>/dev/null || :); [ -z "$mirror_objects" ] || printf '%s\\n' "$mirror_objects" >> repo/.git/objects/info/alternates; fi`,
|
|
83
|
+
` if [ -f ${quotedImageGitDir}/shallow ]; then cp ${quotedImageGitDir}/shallow repo/.git/shallow || exit 5; fi`,
|
|
84
|
+
` if git -C repo update-ref refs/heads/main "$image_commit" && git -C repo read-tree "$image_commit" && git -C repo update-index --refresh && git -C repo diff-files --quiet && extra=$(git -C repo ls-files --others) && [ -z "$extra" ]; then`,
|
|
85
|
+
` git -C repo remote add origin ${quotedUrl} || exit 5`,
|
|
86
|
+
' source_via=image',
|
|
87
|
+
' printf \'ELANOUS_POD_SOURCE_IMAGE %s\\n\' "$image_commit"',
|
|
88
|
+
' else',
|
|
89
|
+
' printf \'ELANOUS_POD_SOURCE_IMAGE_SKIP source-tree-mismatch\\n\'',
|
|
90
|
+
' rm -- repo || exit 5',
|
|
91
|
+
' fi',
|
|
92
|
+
' else',
|
|
93
|
+
' printf \'ELANOUS_POD_SOURCE_IMAGE_FAIL bootstrap-failed\\n\'',
|
|
94
|
+
' exit 5',
|
|
95
|
+
' fi',
|
|
96
|
+
' else',
|
|
97
|
+
' printf \'ELANOUS_POD_SOURCE_IMAGE_SKIP pin-objects-mismatch\\n\'',
|
|
98
|
+
' fi',
|
|
99
|
+
'fi',
|
|
100
|
+
'if [ "$source_via" != image ]; then',
|
|
66
101
|
// TA-POD-WARMBOOT-PARITY (10-16): the mirror fallback used to be silent — 157 HARD gate Pods all said
|
|
67
102
|
// `VIA github` and nothing said why (the Job had no /host-mirror mount). Each failed step now names itself.
|
|
68
103
|
'mirror_skip=',
|
|
@@ -81,6 +116,7 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
81
116
|
` ${clone} || exit 5`,
|
|
82
117
|
' source_via=github',
|
|
83
118
|
'fi',
|
|
119
|
+
'fi',
|
|
84
120
|
"printf 'ELANOUS_POD_SOURCE_VIA %s\\n' \"$source_via\"",
|
|
85
121
|
'cd repo || exit 5',
|
|
86
122
|
];
|
|
@@ -100,13 +136,27 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
100
136
|
}
|
|
101
137
|
return [
|
|
102
138
|
...start,
|
|
103
|
-
'if [ "$source_via"
|
|
104
|
-
'
|
|
139
|
+
'if [ "$source_via" != github ]; then',
|
|
140
|
+
' remote_info=$(git ls-remote --symref origin HEAD) || exit 5',
|
|
141
|
+
` remote_head=$(printf '%s\\n' "$remote_info" | awk '$2=="HEAD" && $1!="ref:" {print $1}')`,
|
|
142
|
+
` remote_branch=$(printf '%s\\n' "$remote_info" | awk '$1=="ref:" && $3=="HEAD" && $2 ~ /^refs\\/heads\\// {sub(/^refs\\/heads\\//, "", $2); print $2}')`,
|
|
105
143
|
' if ! [[ "$remote_head" =~ ^[0-9a-f]{40}$ ]]; then exit 5; fi',
|
|
106
144
|
' if [ "$remote_head" != "$(git rev-parse HEAD)" ]; then',
|
|
107
|
-
|
|
145
|
+
` if [ "$source_via" = image ] && git -C ${quotedMirror} cat-file -e "$remote_head^{commit}" 2>/dev/null; then`,
|
|
146
|
+
' git reset --hard "$remote_head" || exit 5',
|
|
147
|
+
" printf 'ELANOUS_POD_SOURCE_DELTA mirror\\n'",
|
|
148
|
+
' else',
|
|
149
|
+
' git fetch --depth 50 origin HEAD && git reset --hard FETCH_HEAD || exit 5',
|
|
150
|
+
" printf 'ELANOUS_POD_SOURCE_DELTA origin\\n'",
|
|
151
|
+
' fi',
|
|
108
152
|
' fi',
|
|
109
153
|
'fi',
|
|
154
|
+
'if [ "$source_via" = image ] && [ -n "$remote_branch" ] && git check-ref-format --branch "$remote_branch" >/dev/null 2>&1; then',
|
|
155
|
+
' if [ "$remote_branch" != main ]; then git branch -m "$remote_branch" || exit 5; fi',
|
|
156
|
+
' git update-ref "refs/remotes/origin/$remote_branch" "$(git rev-parse HEAD)" || exit 5',
|
|
157
|
+
' git symbolic-ref refs/remotes/origin/HEAD "refs/remotes/origin/$remote_branch" || exit 5',
|
|
158
|
+
' git branch --set-upstream-to="origin/$remote_branch" "$remote_branch" >/dev/null || exit 5',
|
|
159
|
+
'fi',
|
|
110
160
|
'head=$(git rev-parse HEAD)',
|
|
111
161
|
"printf 'ELANOUS_POD_SOURCE default %s\\n' \"$head\"",
|
|
112
162
|
].join('\n');
|
|
@@ -129,6 +179,24 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
129
179
|
'if ! [[ "$pr_sha" =~ ^[0-9a-f]{40}$ ]]; then exit 5; fi',
|
|
130
180
|
`if ! git cat-file -e "$pr_sha^{commit}" 2>/dev/null; then git fetch --depth 50 origin pull/${n}/head || exit 5; fi`,
|
|
131
181
|
`git checkout -B pr-${n} "$pr_sha" || exit 5`,
|
|
182
|
+
// A pinned image starts at one shallow main commit. Fetching a PR tip at
|
|
183
|
+
// depth 50 can leave that pin and the PR in disconnected shallow spans.
|
|
184
|
+
// Deepen only after merge-base fails; the gate still reports unavailable
|
|
185
|
+
// if ancestry cannot be obtained.
|
|
186
|
+
'remote_info=$(git ls-remote --symref origin HEAD 2>/dev/null) || { printf \'ELANOUS_POD_COMPARISON_BASE unavailable\\n\'; exit 5; }',
|
|
187
|
+
`base_branch=$(printf '%s\\n' "$remote_info" | awk '$1=="ref:" && $3=="HEAD" && $2 ~ /^refs\\/heads\\// {sub(/^refs\\/heads\\//, "", $2); print $2}')`,
|
|
188
|
+
'if [ -n "$base_branch" ] && git check-ref-format --branch "$base_branch" >/dev/null 2>&1; then',
|
|
189
|
+
' base_ref="refs/remotes/origin/$base_branch"',
|
|
190
|
+
' git fetch --depth 50 origin "+refs/heads/$base_branch:$base_ref" || { printf \'ELANOUS_POD_COMPARISON_BASE unavailable\\n\'; exit 5; }',
|
|
191
|
+
' git symbolic-ref refs/remotes/origin/HEAD "$base_ref" || exit 5',
|
|
192
|
+
' if ! git merge-base HEAD "$base_ref" >/dev/null 2>&1 && [ "$(git rev-parse --is-shallow-repository)" = true ]; then',
|
|
193
|
+
` git fetch --deepen=100 origin "+refs/heads/$base_branch:$base_ref" +refs/pull/${n}/head:refs/remotes/origin/pr-${n}-head || printf 'ELANOUS_POD_COMPARISON_BASE deepen-failed\\n'`,
|
|
194
|
+
' fi',
|
|
195
|
+
' if ! git merge-base HEAD "$base_ref" >/dev/null 2>&1 && [ "$(git rev-parse --is-shallow-repository)" = true ]; then',
|
|
196
|
+
` git fetch --unshallow origin "+refs/heads/$base_branch:$base_ref" +refs/pull/${n}/head:refs/remotes/origin/pr-${n}-head || { printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; exit 5; }`,
|
|
197
|
+
' fi',
|
|
198
|
+
" if ! git merge-base HEAD \"$base_ref\" >/dev/null 2>&1; then printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; fi",
|
|
199
|
+
"else printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; exit 5; fi",
|
|
132
200
|
'head=$(git rev-parse HEAD)',
|
|
133
201
|
"printf 'ELANOUS_POD_SOURCE pr %s\\n' \"$head\"",
|
|
134
202
|
].join('\n');
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import type { Kubectl } from './self-implement-pod.js';
|
|
3
|
+
import { podProvenanceMetadata } from './pod-provenance.js';
|
|
4
|
+
import type { WarmWorkerCommand } from './pod-warm-worker-protocol.js';
|
|
5
|
+
import type { WarmPodSpec } from './pod-warm-worker-pod.js';
|
|
6
|
+
|
|
7
|
+
const PREFIX = 'elanous.ai/';
|
|
8
|
+
const STATIC = new Set(['pool', 'image-digest', 'launch-host']);
|
|
9
|
+
const workKey = (key: string) => key.startsWith(PREFIX) && !STATIC.has(key.slice(PREFIX.length));
|
|
10
|
+
|
|
11
|
+
export function warmLeaseMetadata(command: WarmWorkerCommand) {
|
|
12
|
+
return podProvenanceMetadata({ actorKind: 'loop', actor: 'release-gate', character: 'gate-warm-worker',
|
|
13
|
+
entrance: 'release-gate-warm', kind: 'warm', run: command.runId, phase: 'release-gate',
|
|
14
|
+
requestedAt: command.requestedAt || 'unknown', reason: 'gate shadow replay', commit: command.cutSha,
|
|
15
|
+
shard: command.attemptId, warmReused: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function warmExecEnv(command: WarmWorkerCommand): string[] {
|
|
19
|
+
return [...warmLeaseMetadata(command).env,
|
|
20
|
+
{ name: 'ELANOUS_POD_LEASE', value: command.leaseId },
|
|
21
|
+
{ name: 'ELANOUS_POD_WORKER', value: command.workerId },
|
|
22
|
+
].map(({ name, value }) => `${name}=${value}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** One UID/resourceVersion-guarded metadata mutation. A failed patch never admits a lease. */
|
|
26
|
+
export function patchWarmLeaseMetadata(spec: WarmPodSpec, command: WarmWorkerCommand,
|
|
27
|
+
next: 'leased' | 'idle' | 'quarantined', injected?: Kubectl): { ok: boolean; reason: string } {
|
|
28
|
+
const fail = (reason: string) => ({ ok: false, reason });
|
|
29
|
+
if (!command.podUid || !command.requestedAt) return fail('lease-identity-missing');
|
|
30
|
+
const kubectl: Kubectl = injected ?? ((args, input) => {
|
|
31
|
+
const env = { ...process.env };
|
|
32
|
+
for (const name of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']) delete env[name];
|
|
33
|
+
const result = spawnSync('kubectl', [...args], { encoding: 'utf8', input, env,
|
|
34
|
+
timeout: 120_000, maxBuffer: 2 * 1024 * 1024 });
|
|
35
|
+
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
|
|
36
|
+
});
|
|
37
|
+
const prefix = ['--context', spec.kubectlContext, '-n', spec.namespace];
|
|
38
|
+
const observed = kubectl([...prefix, 'get', 'pod', spec.name, '-o', 'json']);
|
|
39
|
+
if (observed.status !== 0) return fail('pod-read-failed');
|
|
40
|
+
let pod: any;
|
|
41
|
+
try { pod = JSON.parse(observed.stdout); } catch { return fail('pod-read-invalid'); }
|
|
42
|
+
const metadata = pod?.metadata;
|
|
43
|
+
if (metadata?.name !== spec.name || metadata?.namespace !== spec.namespace
|
|
44
|
+
|| metadata?.uid !== command.podUid || typeof metadata?.resourceVersion !== 'string'
|
|
45
|
+
|| !metadata.resourceVersion
|
|
46
|
+
|| metadata.annotations?.['elanous.dev/warm-worker-id'] !== spec.workerId
|
|
47
|
+
|| metadata.annotations?.['elanous.dev/warm-cut-sha'] !== spec.cutSha) return fail('pod-identity-drift');
|
|
48
|
+
const labels = { ...(metadata.labels ?? {}) } as Record<string, string>;
|
|
49
|
+
const annotations = { ...(metadata.annotations ?? {}) } as Record<string, string>;
|
|
50
|
+
if (next === 'leased' && labels[`${PREFIX}state`] !== undefined
|
|
51
|
+
&& labels[`${PREFIX}state`] !== 'idle') return fail('lease-state-not-idle');
|
|
52
|
+
if (next === 'leased' && labels[`${PREFIX}state`] === undefined
|
|
53
|
+
&& [...Object.keys(labels), ...Object.keys(annotations)].some(workKey)) return fail('stale-work-metadata');
|
|
54
|
+
if (next === 'idle' && (labels[`${PREFIX}state`] !== 'leased'
|
|
55
|
+
|| labels[`${PREFIX}lease`] !== command.leaseId)) return fail('lease-state-mismatch');
|
|
56
|
+
if (next === 'quarantined' && labels[`${PREFIX}state`] === 'leased'
|
|
57
|
+
&& labels[`${PREFIX}lease`] !== command.leaseId) return fail('lease-state-mismatch');
|
|
58
|
+
for (const key of Object.keys(labels)) if (workKey(key)) delete labels[key];
|
|
59
|
+
for (const key of Object.keys(annotations)) if (workKey(key)) delete annotations[key];
|
|
60
|
+
if (next === 'leased') {
|
|
61
|
+
const work = warmLeaseMetadata(command);
|
|
62
|
+
Object.assign(labels, work.labels, { [`${PREFIX}state`]: 'leased', [`${PREFIX}lease`]: command.leaseId });
|
|
63
|
+
Object.assign(annotations, work.annotations, { [`${PREFIX}lease`]: command.leaseId });
|
|
64
|
+
} else labels[`${PREFIX}state`] = next;
|
|
65
|
+
const patch = [
|
|
66
|
+
{ op: 'test', path: '/metadata/uid', value: command.podUid },
|
|
67
|
+
{ op: 'test', path: '/metadata/resourceVersion', value: metadata.resourceVersion },
|
|
68
|
+
{ op: 'add', path: '/metadata/labels', value: labels },
|
|
69
|
+
{ op: 'add', path: '/metadata/annotations', value: annotations },
|
|
70
|
+
];
|
|
71
|
+
const updated = kubectl([...prefix, 'patch', 'pod', spec.name, '--type=json', '-p', JSON.stringify(patch), '-o', 'json']);
|
|
72
|
+
if (updated.status !== 0) return fail('conditional-patch-failed');
|
|
73
|
+
try {
|
|
74
|
+
const after = JSON.parse(updated.stdout);
|
|
75
|
+
const matched = after?.metadata?.uid === command.podUid
|
|
76
|
+
&& after?.metadata?.labels?.[`${PREFIX}state`] === next
|
|
77
|
+
&& (next !== 'leased' ? after.metadata.labels[`${PREFIX}lease`] === undefined
|
|
78
|
+
: after.metadata.labels[`${PREFIX}lease`] === command.leaseId);
|
|
79
|
+
return matched ? { ok: true, reason: 'applied' } : fail('patch-result-mismatch');
|
|
80
|
+
} catch { return fail('patch-result-invalid'); }
|
|
81
|
+
}
|