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
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
// `elanous release preflight` — 컷 30분
|
|
1
|
+
// `elanous release preflight` — 컷 −30분 운영 점검 + 컷 −60분 main export 사전 점검.
|
|
2
2
|
//
|
|
3
3
|
// 🩸 계기(10-06 실측): 0.2.17 릴리스 런이 첫 노드(checklist-gate)에서 멎었다 — «발행 뒤» 칸(POSTPUB-VERIFY)이 그 판에
|
|
4
|
-
// 남아 있었고 게이트가 그것을 미완으로 셌다.
|
|
4
|
+
// 남아 있었고 게이트가 그것을 미완으로 셌다. 컷 전 체크리스트 점검은 착지 마감 컷 −30분, F9 export 는 main HEAD 에서 컷 −60분 수동 실행.
|
|
5
5
|
// ⛔ 읽기 전용 — 칸을 옮기지도, 동결을 바꾸지도, push 하지도 않는다. 옮길 것은 «명령»으로 제안만 한다.
|
|
6
6
|
// ⛔ 게이트 규칙을 다시 쓰지 않는다 — checklist-gate 노드 · release run 진입 검사 · 예약 시작 준비 검사(releaseReadiness, #24557)가
|
|
7
7
|
// 함께 쓰는 단 하나의 판정 cutChecklistGate 를 그대로 부르고, 예약 시작 경로는 releaseReadiness 를 CLI 와 같은 인자로 부른다.
|
|
8
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
8
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, mkdtempSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { spawnSync } from 'node:child_process';
|
|
10
12
|
import { cutChecklistGate, listChecklist, type ChecklistItem } from '../../src/release-loop/checklist.js';
|
|
11
13
|
import { getSchedule, formatKst, type ReleaseSchedule } from '../../src/release-loop/release-schedule.js';
|
|
12
14
|
import { readLandingFreeze, landingFreezeMessage, type LandingFreeze } from '../../src/release-loop/landing-freeze.js';
|
|
@@ -14,9 +16,10 @@ import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
|
14
16
|
import { debug } from '../../src/debug/log.js';
|
|
15
17
|
import { releaseReadiness } from './release-readiness.js';
|
|
16
18
|
import { latestPublishedPreviousVersion, runUnattendedRelease, type UnattendedReleaseDeps } from './unattended-release.js';
|
|
19
|
+
import { loadExportConfig, run as runPublicExport, selectExportFiles } from '../public-export.js';
|
|
17
20
|
|
|
18
21
|
export type PreflightLevel = 'ok' | 'warn' | 'block';
|
|
19
|
-
export type PreflightCheck = 'checklist' | 'postpub' | 'run-input' | 'freeze' | 'schedule';
|
|
22
|
+
export type PreflightCheck = 'checklist' | 'postpub' | 'run-input' | 'freeze' | 'schedule' | 'export';
|
|
20
23
|
export interface PreflightFinding { level: PreflightLevel; check: PreflightCheck; id?: string; message: string; suggestion?: string }
|
|
21
24
|
export interface GateMeasure { version: string; runId: string; gateSeconds: number; toPublishSeconds?: number }
|
|
22
25
|
const compareStable = (a: string, b: string) => { const x = a.split('.').map(Number), y = b.split('.').map(Number); return x[0]! - y[0]! || x[1]! - y[1]! || x[2]! - y[2]!; };
|
|
@@ -27,7 +30,8 @@ export interface PreflightResult {
|
|
|
27
30
|
blockers: number;
|
|
28
31
|
warnings: number;
|
|
29
32
|
findings: PreflightFinding[];
|
|
30
|
-
schedule: { cutAt: string; landBy: string | null; publishAt: string | null; publishAtSource: 'option' | 'schedule' | 'cadence' | null } | null;
|
|
33
|
+
schedule: { cutAt: string; landBy: string | null; publishAt: string | null; publishAtSource: 'option' | 'schedule' | 'cadence' | null; exportCheckAt: string } | null;
|
|
34
|
+
exportCheck: { mainSha: string; files: number; leaks: number; codeLiterals: number } | null;
|
|
31
35
|
/** The immediately previous release (by version order) whose gate is compared. */
|
|
32
36
|
previousVersion: string | null;
|
|
33
37
|
gateMeasure: GateMeasure | null;
|
|
@@ -46,6 +50,72 @@ export interface PreflightDeps {
|
|
|
46
50
|
releaseRunDeps?: UnattendedReleaseDeps;
|
|
47
51
|
/** The immediately previous release; default = the run input's previousVersion (release ledger). */
|
|
48
52
|
previousVersion?: string;
|
|
53
|
+
/** Injectable for deterministic preflight tests. Production pins origin/main and scans a disposable checkout. */
|
|
54
|
+
exportCheck?: () => Promise<{ mainSha: string; files: number; leaks: number; codeLiterals: number }>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function runGit(cwd: string, args: string[]): string {
|
|
58
|
+
const result = spawnSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 16 << 20 });
|
|
59
|
+
if (result.status !== 0) throw new Error(`git ${args.join(' ')} 실패 rc=${result.status}: ${(result.stderr ?? '').trim().slice(0, 300)}`);
|
|
60
|
+
return (result.stdout ?? '').trim();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Read-only main snapshot: all checkout and cleanup writes are contained in a disposable temp directory. */
|
|
64
|
+
export async function scanOriginMainExport(): Promise<{ mainSha: string; files: number; leaks: number; codeLiterals: number }> {
|
|
65
|
+
const repoRoot = runGit(process.cwd(), ['rev-parse', '--show-toplevel']);
|
|
66
|
+
const mainSha = runGit(repoRoot, ['rev-parse', '--verify', 'origin/main^{commit}']);
|
|
67
|
+
const temp = mkdtempSync(join(tmpdir(), 'release-preflight-main-'));
|
|
68
|
+
const snapshot = join(temp, 'checkout');
|
|
69
|
+
try {
|
|
70
|
+
runGit(temp, ['clone', '--shared', '--no-checkout', '--quiet', repoRoot, snapshot]);
|
|
71
|
+
runGit(snapshot, ['read-tree', mainSha]);
|
|
72
|
+
const tracked = runGit(snapshot, ['ls-files', '-z']).split('\0').filter(Boolean);
|
|
73
|
+
const trackedSet = new Set(tracked);
|
|
74
|
+
// `git check-ignore --no-index` applies every nested ignore file, including ones below selected paths.
|
|
75
|
+
const needed = new Set(tracked.filter((file) => file === '.gitignore' || file.endsWith('/.gitignore')));
|
|
76
|
+
needed.add('release/public-export.yaml');
|
|
77
|
+
// Read only the paths the pinned manifest can inspect; the full tracked-path index stays at mainSha.
|
|
78
|
+
const manifestPath = join(snapshot, 'release/public-export.yaml');
|
|
79
|
+
const manifest = spawnSync('git', ['-C', snapshot, 'show', `${mainSha}:release/public-export.yaml`], { encoding: 'utf8', maxBuffer: 4 << 20 });
|
|
80
|
+
if (manifest.status !== 0) throw new Error(`origin/main public export manifest 읽기 실패: ${(manifest.stderr ?? '').trim()}`);
|
|
81
|
+
mkdirSync(join(snapshot, 'release'), { recursive: true });
|
|
82
|
+
writeFileSync(manifestPath, manifest.stdout ?? '');
|
|
83
|
+
const config = loadExportConfig(snapshot);
|
|
84
|
+
const selected = selectExportFiles(tracked, config);
|
|
85
|
+
for (const file of selected) needed.add(file);
|
|
86
|
+
for (const source of Object.values(config.replace)) needed.add(source);
|
|
87
|
+
if (config.skills) {
|
|
88
|
+
needed.add('catalog/resources.yaml');
|
|
89
|
+
needed.add('src/video-pipeline/capabilities.ts');
|
|
90
|
+
for (const file of tracked) if (/^skills\/[^/]+\/SKILL\.md$/u.test(file)) needed.add(file);
|
|
91
|
+
for (const file of tracked) {
|
|
92
|
+
const skill = /^skills\/([^/]+)\//u.exec(file)?.[1];
|
|
93
|
+
if (skill) mkdirSync(join(snapshot, 'skills', skill), { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const checkout = spawnSync('git', ['-C', snapshot, 'checkout-index', '--stdin', '-z', '-f'], {
|
|
97
|
+
input: `${[...needed].filter((file) => trackedSet.has(file)).join('\0')}\0`, encoding: 'utf8', maxBuffer: 16 << 20,
|
|
98
|
+
});
|
|
99
|
+
if (checkout.status !== 0) throw new Error(`origin/main export 입력 파일 준비 실패 rc=${checkout.status}: ${(checkout.stderr ?? '').trim().slice(0, 300)}`);
|
|
100
|
+
let output = '';
|
|
101
|
+
const originalLog = console.log;
|
|
102
|
+
const originalError = console.error;
|
|
103
|
+
console.log = (...args: unknown[]) => { output += `${args.map(String).join(' ')}\n`; };
|
|
104
|
+
console.error = () => {};
|
|
105
|
+
let code: number;
|
|
106
|
+
try { code = runPublicExport(['--leak-check', '--json'], snapshot); }
|
|
107
|
+
finally { console.log = originalLog; console.error = originalError; }
|
|
108
|
+
const report = JSON.parse(output.trim()) as {
|
|
109
|
+
files?: number; leaks?: number; hits?: Array<{ marker: string }>; codeLiterals?: { hits?: number };
|
|
110
|
+
privateRedactions?: { loaded?: boolean };
|
|
111
|
+
};
|
|
112
|
+
if (report.privateRedactions?.loaded !== true) throw new Error('개인 치환표를 읽지 못해 export 누수 검사를 완결할 수 없다');
|
|
113
|
+
if (typeof report.files !== 'number' || typeof report.leaks !== 'number') throw new Error('public-export 검사 결과가 완전하지 않다');
|
|
114
|
+
if (code !== (report.leaks > 0 ? 1 : 0)) throw new Error(`public-export 종료 코드와 누수 결과 불일치: rc=${code} leaks=${report.leaks}`);
|
|
115
|
+
return { mainSha, files: report.files, leaks: report.leaks, codeLiterals: report.codeLiterals?.hits ?? 0 };
|
|
116
|
+
} finally {
|
|
117
|
+
rmSync(temp, { recursive: true, force: true });
|
|
118
|
+
}
|
|
49
119
|
}
|
|
50
120
|
|
|
51
121
|
const POSTPUB_ID = /^POSTPUB-/i;
|
|
@@ -127,6 +197,7 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
|
|
|
127
197
|
const now = deps.now ?? new Date();
|
|
128
198
|
const next = nextPatch(version);
|
|
129
199
|
const findings: PreflightFinding[] = [];
|
|
200
|
+
let exportCheck: PreflightResult['exportCheck'] = null;
|
|
130
201
|
const moveHint = (id: string) => `elanous release checklist move ${id} --from ${version} --to ${next} --reason "발행 뒤 칸 — 다음 판에서 확인"`;
|
|
131
202
|
|
|
132
203
|
// 1·2. Checklist gate simulation «at the cut» (the node and the run entry both judge after land-by) ⊕ post-publish cells.
|
|
@@ -176,6 +247,17 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
|
|
|
176
247
|
for (const p of gate.parity ?? []) findings.push({ level: 'warn', check: 'checklist', id: p.id, message: `${p.id} — 화면 짝 경고: ${p.why}` });
|
|
177
248
|
if (!blockReason.size) findings.push({ level: 'ok', check: 'checklist', message: `체크리스트 게이트 모의 통과 — ${data.items.length}칸 · 이월 ${gate.moved.length} · 알려진 문제 ${gate.knownIssues.length}` });
|
|
178
249
|
|
|
250
|
+
// 3a. Public export leakage is measured against one pinned origin/main commit, never this possibly dirty branch.
|
|
251
|
+
try {
|
|
252
|
+
exportCheck = await (deps.exportCheck ?? scanOriginMainExport)();
|
|
253
|
+
findings.push(exportCheck.leaks
|
|
254
|
+
? { level: 'block', check: 'export', message: `origin/main ${exportCheck.mainSha.slice(0, 12)} 공개 export 누수 ${exportCheck.leaks}건 · ${exportCheck.files} 파일 검사` }
|
|
255
|
+
: { level: 'ok', check: 'export', message: `origin/main ${exportCheck.mainSha.slice(0, 12)} 공개 export 누수 0건 · ${exportCheck.files} 파일 검사` });
|
|
256
|
+
if (exportCheck.codeLiterals) findings.push({ level: 'warn', check: 'export', message: `코드 리터럴 표지 ${exportCheck.codeLiterals}건은 문서/주석 누수에서 분리해 기록` });
|
|
257
|
+
} catch (error) {
|
|
258
|
+
findings.push({ level: 'block', check: 'export', message: `origin/main 공개 export 검사를 완료하지 못했다 — ${error instanceof Error ? error.message : String(error)}` });
|
|
259
|
+
}
|
|
260
|
+
|
|
179
261
|
// 3. The same input check `release run --dry-run` makes.
|
|
180
262
|
let runPrevious: string | undefined;
|
|
181
263
|
try {
|
|
@@ -209,7 +291,11 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
|
|
|
209
291
|
// --publish-at > the stored schedule publish time (`release schedule set --publish-at`) > the October cadence.
|
|
210
292
|
const publishAtSource = deps.publishAt ? 'option' : schedule.publishAt ? 'schedule' : 'cadence';
|
|
211
293
|
const publishAt = deps.publishAt ? new Date(deps.publishAt).toISOString() : schedule.publishAt ?? cadencePublishAt(schedule.cutAt);
|
|
212
|
-
|
|
294
|
+
const exportCheckAt = new Date(cut - 60 * 60_000).toISOString();
|
|
295
|
+
scheduleOut = { cutAt: schedule.cutAt, landBy: schedule.landBy, publishAt, publishAtSource, exportCheckAt };
|
|
296
|
+
findings.push(Date.parse(now.toISOString()) < Date.parse(exportCheckAt)
|
|
297
|
+
? { level: 'warn', check: 'schedule', message: `main export 검사 시각 ${formatKst(exportCheckAt)}(컷 − 60분)보다 이르다 · OP가 그 시각에 수동 실행` }
|
|
298
|
+
: { level: 'ok', check: 'schedule', message: `main export 검사 시각 ${formatKst(exportCheckAt)}(컷 − 60분) · 자동 예약 없음` });
|
|
213
299
|
if (!schedule.landBy) findings.push({ level: 'warn', check: 'schedule', message: `착지 마감 없음 — 컷 ${formatKst(schedule.cutAt)} · 규칙은 컷 − 30분` });
|
|
214
300
|
else if (cut - Date.parse(schedule.landBy) < 30 * 60_000) findings.push({ level: 'warn', check: 'schedule', message: `착지 마감 ${formatKst(schedule.landBy)} 이 컷 − 30분보다 늦다(컷 ${formatKst(schedule.cutAt)})` });
|
|
215
301
|
else findings.push({ level: 'ok', check: 'schedule', message: `일정 — 착지 마감 ${formatKst(schedule.landBy)} · 컷 ${formatKst(schedule.cutAt)}` });
|
|
@@ -233,7 +319,7 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
|
|
|
233
319
|
const blockers = findings.filter((f) => f.level === 'block').length;
|
|
234
320
|
const warnings = findings.filter((f) => f.level === 'warn').length;
|
|
235
321
|
debug.log('release.preflight', 'checked', { version, blockers, warnings });
|
|
236
|
-
return { version, next, verdict: blockers ? 'block' : warnings ? 'warn' : 'ok', blockers, warnings, findings, schedule: scheduleOut, previousVersion, gateMeasure, fallbackGateMeasure };
|
|
322
|
+
return { version, next, verdict: blockers ? 'block' : warnings ? 'warn' : 'ok', blockers, warnings, findings, schedule: scheduleOut, exportCheck, previousVersion, gateMeasure, fallbackGateMeasure };
|
|
237
323
|
}
|
|
238
324
|
|
|
239
325
|
const ICON: Record<PreflightLevel, string> = { ok: '✅', warn: '⚠️', block: '⛔' };
|
|
@@ -20,6 +20,8 @@ function option(name: string, fallback?: string): string {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async function main(): Promise<void> {
|
|
23
|
+
const actor = process.env.ELANOUS_SEAT?.trim() || process.env.USER?.trim() || process.env.LOGNAME?.trim();
|
|
24
|
+
if (!actor) throw new Error('pod provenance actor missing: ELANOUS_SEAT or USER/LOGNAME required');
|
|
23
25
|
const context = option('context');
|
|
24
26
|
const host = option('host');
|
|
25
27
|
const cluster = option('cluster', 'elanous-pool');
|
|
@@ -51,6 +53,9 @@ async function main(): Promise<void> {
|
|
|
51
53
|
let completed = false;
|
|
52
54
|
try {
|
|
53
55
|
const result = await runPodCommand({
|
|
56
|
+
provenance: { actorKind: process.env.ELANOUS_SEAT?.trim() ? 'seat' : 'human', actor, character: 'host-dirs-probe',
|
|
57
|
+
entrance: 'probe', kind: 'probe', run: name, phase: 'exec', requestedAt: new Date().toISOString(),
|
|
58
|
+
reason: `host directory probe ${arm}` },
|
|
54
59
|
command: ['sh', '-c', 'printf cache-ok > /bun-cache/.host-dir-probe && printf slots-ok > /gate-install-slots/.host-dir-probe && test "$(cat /bun-cache/.host-dir-probe)" = cache-ok && test "$(cat /gate-install-slots/.host-dir-probe)" = slots-ok && rm /bun-cache/.host-dir-probe /gate-install-slots/.host-dir-probe && echo HOST_DIRS_WRITTEN'],
|
|
55
60
|
name,
|
|
56
61
|
namespace, image, imageCommit: null, deadlineSeconds: 120, pollMs: 1_000, statusUnreadableMs: 30_000,
|
|
@@ -1,14 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { WARNING_ONLY } from './auto-approve-node.js';
|
|
5
|
+
import { BLOCKING_METRIC_NAMES, WARNING_ONLY } from './auto-approve-node.js';
|
|
6
6
|
import { beginLandingMerge, landingFreezeMessage } from '../../src/release-loop/landing-freeze.js';
|
|
7
7
|
import { debug } from '../../src/debug/log.js';
|
|
8
8
|
import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
|
|
9
|
+
import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
9
10
|
import { prereleaseKind } from './release-version.js';
|
|
10
11
|
import { publishAtError } from './publish-at.js';
|
|
11
|
-
import {
|
|
12
|
+
import { validatedTuiRegress } from './tui-node-checks.js';
|
|
13
|
+
import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner, type GraphContext } from './node-verdict.js';
|
|
14
|
+
|
|
15
|
+
/** The approval output alone is not authority: the runner also stores a one-winner decision claim for this visit. */
|
|
16
|
+
export function hasRecordedPublishApproval(context: GraphContext, root: string): boolean {
|
|
17
|
+
const runId = context.runId;
|
|
18
|
+
const approval = context.outputs['approve-publish'];
|
|
19
|
+
if (!runId || !/^[A-Za-z0-9_-]+$/.test(runId) || approval?.outcome !== 'approved'
|
|
20
|
+
|| approval.graphId !== 'release-loop' || approval.runId !== runId || approval.nodeId !== 'approve-publish'
|
|
21
|
+
|| typeof approval.decidedAt !== 'string' || Number.isNaN(Date.parse(approval.decidedAt))) return false;
|
|
22
|
+
try {
|
|
23
|
+
const statePath = join(root, 'graph-runs', 'release-loop', `${runId}.json`);
|
|
24
|
+
const state = JSON.parse(readFileSync(statePath, 'utf8')) as {
|
|
25
|
+
graphId?: string; runId?: string; path?: string[];
|
|
26
|
+
nodes?: Array<{ nodeId?: string; ok?: boolean; output?: unknown; decidedAt?: string }>;
|
|
27
|
+
};
|
|
28
|
+
const visit = state.path?.lastIndexOf('approve-publish') ?? -1;
|
|
29
|
+
if (state.graphId !== 'release-loop' || state.runId !== runId || state.path?.at(-1) !== 'publish'
|
|
30
|
+
|| visit < 0 || !Array.isArray(state.nodes)) return false;
|
|
31
|
+
const node = state.nodes.filter((item) => item.nodeId === 'approve-publish').at(-1);
|
|
32
|
+
const output = typeof node?.output === 'string' ? JSON.parse(node.output) as Record<string, unknown> : null;
|
|
33
|
+
if (!node?.ok || node.decidedAt !== approval.decidedAt || output?.runId !== runId
|
|
34
|
+
|| output?.decidedAt !== approval.decidedAt || output?.outcome !== 'approved') return false;
|
|
35
|
+
const claim = JSON.parse(readFileSync(`${statePath}.${visit + 1}.decision.json`, 'utf8')) as Record<string, unknown>;
|
|
36
|
+
return claim.nodeId === 'approve-publish' && claim.decision === 'approved'
|
|
37
|
+
&& claim.decidedAt === approval.decidedAt;
|
|
38
|
+
} catch { return false; }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Warning rows may be repeated, but each of the eight fixed gates must occur exactly once in its declared order. */
|
|
42
|
+
export function hasMeasuredApprovalMetrics(metrics: unknown): boolean {
|
|
43
|
+
if (!Array.isArray(metrics) || !metrics.every((row: unknown) => row && typeof row === 'object'
|
|
44
|
+
&& typeof (row as Record<string, unknown>).name === 'string'
|
|
45
|
+
&& (row as Record<string, unknown>).verdict === 'pass')) return false;
|
|
46
|
+
const rows = metrics as Array<{ name: string; verdict: string }>;
|
|
47
|
+
const fixed = rows.filter((row) => !WARNING_ONLY.has(row.name));
|
|
48
|
+
return fixed.length === BLOCKING_METRIC_NAMES.length
|
|
49
|
+
&& BLOCKING_METRIC_NAMES.every((name, index) => fixed[index]?.name === name)
|
|
50
|
+
&& rows.some((row) => row.name === 'tui-regress')
|
|
51
|
+
&& rows.some((row) => row.name === 'mac-smoke');
|
|
52
|
+
}
|
|
12
53
|
|
|
13
54
|
export function publicNotes(markdown: string, pages: { pages: Array<{ id: string; slug?: string; source?: string }> }): string {
|
|
14
55
|
if (!Array.isArray(pages.pages)) throw new Error('invalid public pages registry');
|
|
@@ -46,7 +87,8 @@ export function waitForAssets(run: CommandRunner, repo: string, tag: string, nam
|
|
|
46
87
|
}
|
|
47
88
|
|
|
48
89
|
export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: string,
|
|
49
|
-
clock: { now: () => number; sleep: (ms: number) => void } = { now: Date.now, sleep: Bun.sleepSync }
|
|
90
|
+
clock: { now: () => number; sleep: (ms: number) => void } = { now: Date.now, sleep: Bun.sleepSync },
|
|
91
|
+
approvalRoot = effectiveInstanceRoot()) {
|
|
50
92
|
const context = readGraphContext();
|
|
51
93
|
// A resumed graph once invoked this irreversible node at npm-publish, docs-land, and failed.
|
|
52
94
|
// The runner's context is the authority: only the publish visit may publish.
|
|
@@ -54,12 +96,21 @@ export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: str
|
|
|
54
96
|
const version = context.input.version;
|
|
55
97
|
// A measured automatic decision or the existing human approval must authorize publication.
|
|
56
98
|
const auto = context.outputs['auto-approve'];
|
|
57
|
-
|
|
99
|
+
const regress = validatedTuiRegress(context.outputs.tui?.regress);
|
|
100
|
+
const approvedForRun = hasRecordedPublishApproval(context, approvalRoot);
|
|
101
|
+
if (!approvedForRun &&
|
|
58
102
|
!(auto?.outcome === 'ok' && auto.decidedBy === 'release-loop metrics'
|
|
59
|
-
|
|
60
|
-
&&
|
|
61
|
-
&& auto.
|
|
62
|
-
&& auto.
|
|
103
|
+
&& !('unmeasured' in regress) && regress.pass === 7 && regress.fail === 0
|
|
104
|
+
&& typeof context.runId === 'string' && context.runId.length > 0 && auto.runId === context.runId
|
|
105
|
+
&& auto.tuiSubcheck && typeof auto.tuiSubcheck === 'object'
|
|
106
|
+
&& (auto.tuiSubcheck as Record<string, unknown>).runId === context.runId
|
|
107
|
+
&& (auto.tuiSubcheck as Record<string, unknown>).level === 'ok'
|
|
108
|
+
&& (auto.tuiSubcheck as Record<string, unknown>).fail === 0
|
|
109
|
+
&& Array.isArray((auto.tuiSubcheck as Record<string, unknown>).failedCheckIds)
|
|
110
|
+
&& ((auto.tuiSubcheck as Record<string, unknown>).failedCheckIds as unknown[]).length === 0
|
|
111
|
+
&& (auto.tuiSubcheck as Record<string, unknown>).approvalRequired === false
|
|
112
|
+
// Eight fixed metrics; the TUI subcheck is outside that count but its fail/unmeasured verdict still blocks auto-publish.
|
|
113
|
+
&& hasMeasuredApprovalMetrics(auto.metrics))) {
|
|
63
114
|
return { outcome: 'fail' as const, verdict: 'fail' as const, summary: 'publish blocked: neither auto-approve nor approve-publish approved' };
|
|
64
115
|
}
|
|
65
116
|
for (const node of ['gate', 'pwa', 'upgrade', 'tui', 'prepare', 'docs']) {
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// RELEASE-PWA-NODE-RESILIENCE ① (0.2.36 · 대표 10-20 «PWA 단계도 원격에서»): the release `pwa` node can run its
|
|
2
|
+
// scenario suite on an SSH host (`release.loop.pwaRemote`, e.g. node-b) instead of the busy release machine.
|
|
3
|
+
// 0.2.34 (10-20 18:50~19:13): at 1-min load 100+ on mbp the CDP attach went past 5s and T1b failed twice on reruns,
|
|
4
|
+
// while the same commit alone passed — the release machine's load, not the PWA, decided the verdict.
|
|
5
|
+
//
|
|
6
|
+
// Same shape as the gate's host executor (`--gate-executor host` · `gateRemote` · `gateRemoteMirror`):
|
|
7
|
+
// ① ensure the bare mirror on the host ② push the commit to `refs/elanous/pwa/<sha>`
|
|
8
|
+
// ③ one ssh call: clone the mirror at <sha> into a temp dir, install, run THAT commit's
|
|
9
|
+
// `pwa-scenarios-node.ts` locally there, print its JSON verdict, remove the temp dir.
|
|
10
|
+
// ⛔ No silent fallback: when any step fails the node reports `error` with the stage and the host's own words
|
|
11
|
+
// and exits 2. It never reruns the suite on the release machine.
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
import { debug } from '../../src/debug/log.js';
|
|
14
|
+
|
|
15
|
+
/** `[user@]host`. A leading `-` is refused separately (ssh/git would read it as an option — `-oProxyCommand=…`). */
|
|
16
|
+
export const PWA_REMOTE_HOST_PATTERN = /^(?:[\w.-]+@)?[\w.-]+$/;
|
|
17
|
+
export const DEFAULT_PWA_REMOTE_MIRROR = '~/mirror/elanous-agent.git';
|
|
18
|
+
/** Build (≤15m) + boot + warm-up + suite + reruns on the host; the local ssh deadline is only a backstop. */
|
|
19
|
+
export const PWA_REMOTE_TIMEOUT_MS = 75 * 60_000;
|
|
20
|
+
/** The host kills its own work first (shorter than the local backstop) so the temp clone and the ref are cleaned there. */
|
|
21
|
+
export const PWA_REMOTE_LIMIT_SECONDS = 70 * 60;
|
|
22
|
+
/** rc of a run the Perl supervisor stopped after its deadline. */
|
|
23
|
+
const LIMIT_RCS = new Set([124]);
|
|
24
|
+
|
|
25
|
+
export type PwaRemoteStage = 'input' | 'mirror' | 'push' | 'run' | 'timeout' | 'parse';
|
|
26
|
+
|
|
27
|
+
export interface PwaRemoteOptions {
|
|
28
|
+
host: string;
|
|
29
|
+
commit: string;
|
|
30
|
+
withCostly: boolean;
|
|
31
|
+
reruns: number;
|
|
32
|
+
/** Bare mirror on the host (absolute or `~/…`). Default = the gate's mirror. */
|
|
33
|
+
mirror?: string;
|
|
34
|
+
/** Local repository that holds `commit` (pushed from here). */
|
|
35
|
+
repo: string;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PwaRemoteResult {
|
|
40
|
+
/** Exit code for the graph node: 0 pass/flaky · 1 fail · 2 could not run. */
|
|
41
|
+
exitCode: 0 | 1 | 2;
|
|
42
|
+
output: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface Spawned { rc: number; stdout: string; stderr: string; error?: string }
|
|
46
|
+
export type PwaRemoteSpawn = (cmd: string, args: string[], opts: { cwd: string; timeoutMs: number }) => Spawned;
|
|
47
|
+
|
|
48
|
+
const defaultSpawn: PwaRemoteSpawn = (cmd, args, opts) => {
|
|
49
|
+
const env = Object.fromEntries(Object.entries(process.env).filter(([k]) => !/^(https?|all)_proxy$/i.test(k)));
|
|
50
|
+
const r = spawnSync(cmd, args, { cwd: opts.cwd, env, encoding: 'utf8', timeout: opts.timeoutMs, killSignal: 'SIGKILL', maxBuffer: 64 * 1024 * 1024 });
|
|
51
|
+
return { rc: r.status ?? 255, stdout: r.stdout ?? '', stderr: r.stderr ?? '', ...(r.error ? { error: String(r.error) } : {}) };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const shQuote = (value: string): string => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
55
|
+
|
|
56
|
+
/** Validate the host and mirror before anything is spawned. */
|
|
57
|
+
export function checkPwaRemote(host: unknown, mirror: unknown): { host: string; mirror: string } {
|
|
58
|
+
if (typeof host === 'string' && host.trim().startsWith('-')) throw new Error(`invalid pwa remote host: ${host.trim()} — a leading «-» would be read as an ssh/git option`);
|
|
59
|
+
if (typeof host !== 'string' || !PWA_REMOTE_HOST_PATTERN.test(host.trim())) throw new Error(`invalid pwa remote host: ${String(host)}`);
|
|
60
|
+
const m = mirror === undefined ? DEFAULT_PWA_REMOTE_MIRROR : mirror;
|
|
61
|
+
if (typeof m !== 'string' || !/^(?:\/|~\/)[\w./-]+$/.test(m) || m.split('/').includes('..')) throw new Error(`invalid pwa remote mirror path: ${String(m)}`);
|
|
62
|
+
return { host: host.trim(), mirror: m };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** `~/x` stays unquoted at the front so the remote shell expands it; the rest is quoted. */
|
|
66
|
+
function remotePath(path: string): string {
|
|
67
|
+
return path.startsWith('~/') ? `"$HOME"/${shQuote(path.slice(2))}` : shQuote(path);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The single remote script for step ③ — `sh -c` so the remote login shell (zsh on node-b) does not change its meaning.
|
|
72
|
+
* - Limit: Perl supervises a separate process group at PWA_REMOTE_LIMIT_SECONDS.
|
|
73
|
+
* On timeout it kills the group, including the shell's children, then exits 124.
|
|
74
|
+
* - Cleanup: traps on EXIT · HUP · INT · TERM remove the temp clone and this run's mirror ref `refs/elanous/pwa/<sha>`
|
|
75
|
+
* on success and failure alike — the ref only had to live until the clone fetched it, and deleting «our own» ref
|
|
76
|
+
* (not a sweep of `refs/elanous/pwa/*`) cannot race another run on a different commit.
|
|
77
|
+
*/
|
|
78
|
+
export function remoteRunScript(opts: { commit: string; mirror: string; withCostly: boolean; reruns: number; limitSeconds?: number }): string {
|
|
79
|
+
const sha = shQuote(opts.commit);
|
|
80
|
+
const ref = shQuote(`refs/elanous/pwa/${opts.commit}`);
|
|
81
|
+
const limit = String(opts.limitSeconds ?? PWA_REMOTE_LIMIT_SECONDS);
|
|
82
|
+
const nodeArgs = ['--commit', opts.commit, '--json', '--reruns', String(opts.reruns), ...(opts.withCostly ? ['--with-costly'] : [])].map(shQuote).join(' ');
|
|
83
|
+
const body = [
|
|
84
|
+
`git clone --quiet --shared --no-checkout ${remotePath(opts.mirror)} "$1/repo" >&2 || exit 2`,
|
|
85
|
+
`cd "$1/repo" && git fetch --quiet origin ${ref} >&2 && git checkout --quiet --detach ${sha} >&2 || exit 2`,
|
|
86
|
+
'bun install --frozen-lockfile >&2 || exit 2',
|
|
87
|
+
'(cd apps/pwa && bun install --frozen-lockfile) >&2 || exit 2',
|
|
88
|
+
`exec bun scripts/release-loop/pwa-scenarios-node.ts ${nodeArgs}`,
|
|
89
|
+
].join('\n');
|
|
90
|
+
// Arm the deadline only after the child confirms its new group exists. Otherwise a busy host
|
|
91
|
+
// can deliver SIGALRM between fork and setpgrp, making kill(-pid) miss every descendant.
|
|
92
|
+
const supervisor = [
|
|
93
|
+
'my $seconds = shift;',
|
|
94
|
+
'pipe(my $ready_r, my $ready_w) or exit 127;',
|
|
95
|
+
'my $pid = fork(); defined($pid) or exit 127;',
|
|
96
|
+
'if ($pid == 0) { close $ready_r; defined(setpgrp(0, 0)) or exit 127; syswrite($ready_w, "1") == 1 or exit 127; close $ready_w; exec @ARGV or exit 127; }',
|
|
97
|
+
'close $ready_w; my $ready = ""; unless (read($ready_r, $ready, 1) == 1) { kill 9, -$pid; kill 9, $pid; waitpid($pid, 0); exit 127; } close $ready_r;',
|
|
98
|
+
'local $SIG{ALRM} = sub { kill 9, -$pid; waitpid($pid, 0); exit 124; };',
|
|
99
|
+
'alarm $seconds; waitpid($pid, 0); alarm 0;',
|
|
100
|
+
'exit(($? & 127) ? 128 + ($? & 127) : ($? >> 8));',
|
|
101
|
+
].join(' ');
|
|
102
|
+
return [
|
|
103
|
+
'PATH=$HOME/.bun/bin:/opt/homebrew/bin:/usr/local/bin:$PATH; export PATH',
|
|
104
|
+
'command -v perl >/dev/null 2>&1 || { echo "pwa remote requires perl" >&2; exit 127; }',
|
|
105
|
+
'D=$(mktemp -d /tmp/pwa-node-remote-XXXXXX) || exit 2',
|
|
106
|
+
`cleanup() { cd /tmp; rm -rf "$D"; git --git-dir=${remotePath(opts.mirror)} update-ref -d ${ref} 2>/dev/null; }`,
|
|
107
|
+
`trap 'cleanup' EXIT`,
|
|
108
|
+
`trap 'cleanup; trap - EXIT; exit 129' HUP`,
|
|
109
|
+
`trap 'cleanup; trap - EXIT; exit 130' INT`,
|
|
110
|
+
`trap 'cleanup; trap - EXIT; exit 143' TERM`,
|
|
111
|
+
`lim() { perl -e ${shQuote(supervisor)} ${limit} "$@"; }`,
|
|
112
|
+
`lim sh -c ${shQuote(body)} pwa-node "$D"`,
|
|
113
|
+
].join('\n');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const COMMIT_40 = /^[0-9a-f]{40}$/;
|
|
117
|
+
|
|
118
|
+
const tail = (text: string, n = 600): string => text.trim().slice(-n);
|
|
119
|
+
|
|
120
|
+
function lastJson(stdout: string): Record<string, unknown> | undefined {
|
|
121
|
+
const line = stdout.split('\n').reverse().find((l) => l.trim().startsWith('{'));
|
|
122
|
+
if (!line) return undefined;
|
|
123
|
+
try {
|
|
124
|
+
const value: unknown = JSON.parse(line);
|
|
125
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
|
|
126
|
+
} catch { return undefined; }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Run the PWA scenario node on `host`. Never falls back to the local machine. */
|
|
130
|
+
export function runPwaRemote(opts: PwaRemoteOptions, spawn: PwaRemoteSpawn = defaultSpawn): PwaRemoteResult {
|
|
131
|
+
const { host, mirror } = checkPwaRemote(opts.host, opts.mirror);
|
|
132
|
+
if (!COMMIT_40.test(opts.commit)) {
|
|
133
|
+
const error = `remote ${host} input refused: commit must be a full 40-hex sha (got ${JSON.stringify(opts.commit)}) — a short sha can name a different commit on the host mirror`;
|
|
134
|
+
debug.log('release-loop.pwa', 'remote-failed', { host, stage: 'input', rc: null, detail: error }, { level: 'warn' });
|
|
135
|
+
return { exitCode: 2, output: { verdict: 'error', commit: opts.commit, withCostly: opts.withCostly, executor: 'host', host, cells: [], error, remote: { stage: 'input', rc: null } } };
|
|
136
|
+
}
|
|
137
|
+
const timeoutMs = opts.timeoutMs ?? PWA_REMOTE_TIMEOUT_MS;
|
|
138
|
+
const base = { commit: opts.commit, withCostly: opts.withCostly, executor: 'host', host };
|
|
139
|
+
const started = Date.now();
|
|
140
|
+
debug.log('release-loop.pwa', 'remote-start', { host, mirror, commit: opts.commit, withCostly: opts.withCostly, reruns: opts.reruns });
|
|
141
|
+
const fail = (stage: PwaRemoteStage, run: Spawned | undefined, detail: string): PwaRemoteResult => {
|
|
142
|
+
const error = `remote ${host} ${stage} failed${run ? ` (rc=${run.rc})` : ''}: ${detail || 'no output'} — 원격 실패는 mbp 로 폴백하지 않는다`;
|
|
143
|
+
debug.log('release-loop.pwa', 'remote-failed', { host, stage, rc: run?.rc ?? null, detail: detail.slice(0, 600), elapsedMs: Date.now() - started }, { level: 'warn' });
|
|
144
|
+
return { exitCode: 2, output: { verdict: 'error', ...base, cells: [], error, remote: { stage, rc: run?.rc ?? null } } };
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// ① mirror — a bare repo the commit can be pushed to (the gate uses the same one).
|
|
148
|
+
const ensure = `test -d ${remotePath(mirror)} || { mkdir -p "$(dirname ${remotePath(mirror)})" && git init --quiet --bare ${remotePath(mirror)}; }`;
|
|
149
|
+
const m = spawn('ssh', ['--', host, `sh -c ${shQuote(ensure)}`], { cwd: '/tmp', timeoutMs: 120_000 });
|
|
150
|
+
if (m.rc !== 0) return fail('mirror', m, tail(`${m.stderr}\n${m.error ?? ''}`));
|
|
151
|
+
|
|
152
|
+
// ② push the commit from the release machine.
|
|
153
|
+
const pushTarget = mirror.startsWith('~/') ? mirror.slice(2) : mirror;
|
|
154
|
+
const p = spawn('git', ['push', '--quiet', '--force', '--', `${host}:${pushTarget}`, `${opts.commit}:refs/elanous/pwa/${opts.commit}`], { cwd: opts.repo, timeoutMs: 600_000 });
|
|
155
|
+
if (p.rc !== 0) return fail('push', p, tail(`${p.stderr}\n${p.error ?? ''}`));
|
|
156
|
+
|
|
157
|
+
// ③ one call: clone · install · run the commit's own node there.
|
|
158
|
+
const script = remoteRunScript({ commit: opts.commit, mirror, withCostly: opts.withCostly, reruns: opts.reruns });
|
|
159
|
+
const r = spawn('ssh', ['--', host, `sh -c ${shQuote(script)}`], { cwd: '/tmp', timeoutMs });
|
|
160
|
+
const data = lastJson(r.stdout);
|
|
161
|
+
if (!data) return fail(r.rc === 0 ? 'parse' : LIMIT_RCS.has(r.rc) ? 'timeout' : 'run', r, tail(`${r.stderr}\n${r.error ?? ''}`));
|
|
162
|
+
const verdict = data.verdict;
|
|
163
|
+
const exitCode: 0 | 1 | 2 = verdict === 'pass' || verdict === 'flaky' ? (r.rc === 0 ? 0 : 2) : verdict === 'fail' ? 1 : 2;
|
|
164
|
+
debug.log('release-loop.pwa', 'remote-result', { host, verdict: typeof verdict === 'string' ? verdict : null, rc: r.rc, exitCode, elapsedMs: Date.now() - started });
|
|
165
|
+
return { exitCode, output: { ...data, ...base, ...(exitCode === 2 && typeof data.error !== 'string' ? { error: `remote ${host} run rc=${r.rc} verdict=${String(verdict)}: ${tail(r.stderr, 300)}` } : {}) } };
|
|
166
|
+
}
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Release-loop ④ — run the PWA scenario suite on one commit, in isolation, and print one verdict.
|
|
4
4
|
*
|
|
5
5
|
* bun scripts/release-loop/pwa-scenarios-node.ts --commit <sha> [--with-costly] [--reruns 2] [--json]
|
|
6
|
+
* [--remote <ssh-host> [--remote-mirror <path>]]
|
|
7
|
+
*
|
|
8
|
+
* `--remote` (release.loop.pwaRemote) runs the same steps on that host — see pwa-remote.ts.
|
|
9
|
+
* A remote failure is reported as `error` (exit 2); it never falls back to this machine.
|
|
6
10
|
*
|
|
7
11
|
* Steps: temp worktree at <sha> → `nexus build` → isolated nexus (`--test`, leased test port)
|
|
8
12
|
* → warm-up pass (discarded — the first page load after boot is slow and made T4a/N5a fail on the
|
|
@@ -18,14 +22,17 @@ import { tmpdir } from 'node:os';
|
|
|
18
22
|
import { join, resolve } from 'node:path';
|
|
19
23
|
import { decideVerdict, exitCodeFor, idsToRerun, type CellRun, type NodeVerdict } from './pwa-node-verdict';
|
|
20
24
|
import { envLiteral } from '../../src/platform/env-literal.js';
|
|
25
|
+
import { checkPwaRemote, runPwaRemote } from './pwa-remote';
|
|
21
26
|
|
|
22
|
-
interface Options { commit: string; withCostly: boolean; reruns: number; json: boolean }
|
|
27
|
+
interface Options { commit: string; withCostly: boolean; reruns: number; json: boolean; remote?: string; remoteMirror?: string }
|
|
23
28
|
|
|
24
|
-
function parseArgs(argv: readonly string[]): Options {
|
|
29
|
+
export function parseArgs(argv: readonly string[]): Options {
|
|
25
30
|
const opts: Options = { commit: '', withCostly: false, reruns: 2, json: false };
|
|
26
31
|
for (let i = 0; i < argv.length; i++) {
|
|
27
32
|
const arg = argv[i];
|
|
28
33
|
if (arg === '--commit') opts.commit = argv[++i] ?? '';
|
|
34
|
+
else if (arg === '--remote') opts.remote = argv[++i] ?? '';
|
|
35
|
+
else if (arg === '--remote-mirror') opts.remoteMirror = argv[++i] ?? '';
|
|
29
36
|
else if (arg === '--with-costly') opts.withCostly = true;
|
|
30
37
|
else if (arg === '--json') opts.json = true;
|
|
31
38
|
else if (arg === '--reruns') opts.reruns = Number(argv[++i] ?? '2');
|
|
@@ -33,6 +40,8 @@ function parseArgs(argv: readonly string[]): Options {
|
|
|
33
40
|
}
|
|
34
41
|
if (!/^[0-9a-f]{7,40}$/i.test(opts.commit)) throw new Error('--commit <sha> is required');
|
|
35
42
|
if (!Number.isInteger(opts.reruns) || opts.reruns < 0 || opts.reruns > 5) throw new Error('--reruns must be 0..5');
|
|
43
|
+
if (opts.remoteMirror !== undefined && opts.remote === undefined) throw new Error('--remote-mirror requires --remote');
|
|
44
|
+
if (opts.remote !== undefined) checkPwaRemote(opts.remote, opts.remoteMirror);
|
|
36
45
|
return opts;
|
|
37
46
|
}
|
|
38
47
|
|
|
@@ -65,6 +74,13 @@ async function main(): Promise<number> {
|
|
|
65
74
|
let opts: Options;
|
|
66
75
|
try { opts = parseArgs(process.argv.slice(2)); } catch (e) { log(String(e)); return 2; }
|
|
67
76
|
const repo = resolve('.');
|
|
77
|
+
if (opts.remote !== undefined) {
|
|
78
|
+
log(`remote ${opts.remote} · ${opts.commit.slice(0, 10)}`);
|
|
79
|
+
const remote = runPwaRemote({ host: opts.remote, ...(opts.remoteMirror ? { mirror: opts.remoteMirror } : {}), commit: opts.commit, withCostly: opts.withCostly, reruns: opts.reruns, repo });
|
|
80
|
+
if (opts.json) console.log(JSON.stringify(remote.output));
|
|
81
|
+
else console.log(`pwa-node: ${String(remote.output.verdict)} · ${opts.commit.slice(0, 10)} · host ${opts.remote}${typeof remote.output.error === 'string' ? `\n error: ${remote.output.error}` : ''}`);
|
|
82
|
+
return remote.exitCode;
|
|
83
|
+
}
|
|
68
84
|
const work = mkdtempSync(join(tmpdir(), 'pwa-node-'));
|
|
69
85
|
const worktree = join(work, 'tree');
|
|
70
86
|
let nexusPid: number | undefined;
|
|
@@ -137,4 +153,4 @@ async function main(): Promise<number> {
|
|
|
137
153
|
return verdict ? exitCodeFor(verdict.verdict) : 2;
|
|
138
154
|
}
|
|
139
155
|
|
|
140
|
-
process.exit(await main());
|
|
156
|
+
if (import.meta.main) process.exit(await main());
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { DecisionLedger } from '../../src/decisions/decision-ledger.js';
|
|
5
|
+
import type { GraphRunState } from '../../src/graph-runner/runner.js';
|
|
6
|
+
import { isReleaseVersion } from './release-version.js';
|
|
7
|
+
|
|
8
|
+
export const RELEASE_RESUME_LIMIT = 2;
|
|
9
|
+
|
|
10
|
+
/** Called under the OP seat flock, before any branch-tip or graph-run mutation. */
|
|
11
|
+
export function reserveReleaseResumeAttempt(state: GraphRunState, root: string, options: {
|
|
12
|
+
now?: () => Date;
|
|
13
|
+
openCard?: (version: string, runId: string, reason: string) => string;
|
|
14
|
+
/** Under the OP flock, check capacity before tip preflight without consuming an attempt. */
|
|
15
|
+
checkOnly?: boolean;
|
|
16
|
+
/** A dry-run reports the cap without creating an OP decision card. */
|
|
17
|
+
noDecision?: boolean;
|
|
18
|
+
} = {}): { attempt: number; path: string } {
|
|
19
|
+
const version = (state.input as { version?: unknown } | undefined)?.version;
|
|
20
|
+
if (typeof version !== 'string' || !isReleaseVersion(version) || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(state.runId))
|
|
21
|
+
throw new Error('release resume cap requires a valid saved version and run id');
|
|
22
|
+
const path = join(root, 'release', version, 'resume-attempts', `${state.runId}.json`);
|
|
23
|
+
const card = options.openCard ?? ((v: string, id: string, reason: string) => {
|
|
24
|
+
const ref = `release-resume-cap:${v}:${id}`;
|
|
25
|
+
return new DecisionLedger({ stateDir: root, now: options.now }).raiseOnce({
|
|
26
|
+
title: `${v} release resume limit: ${id}`, category: 'scope',
|
|
27
|
+
scqa: { s: `Release ${v} run ${id} has reached its two-resume limit.`, c: reason,
|
|
28
|
+
q: 'Should this release be deferred or moved to the next version?' },
|
|
29
|
+
options: [{ key: 'a', label: 'Defer this release', consequence: 'Stop this run and reschedule the release.' },
|
|
30
|
+
{ key: 'b', label: 'Move to next version', consequence: 'Stop this run and carry the work to a new release.' }],
|
|
31
|
+
recommendation: { skipped: true, reason: 'OP must choose the release disposition.' },
|
|
32
|
+
raisedBy: { agent: 'release-resume-cap', track: 'TC' }, refs: [ref],
|
|
33
|
+
}, ref).id;
|
|
34
|
+
});
|
|
35
|
+
const blocked = (reason: string): never => {
|
|
36
|
+
if (options.noDecision) throw new Error(`release resume limit reached: ${reason}`);
|
|
37
|
+
throw new Error(`release resume limit reached — decision ${card(version, state.runId, reason)}: ${reason}`);
|
|
38
|
+
};
|
|
39
|
+
if (options.noDecision && !options.checkOnly) throw new Error('noDecision requires checkOnly');
|
|
40
|
+
if (!existsSync(path) && state.resume) blocked('saved run was resumed before attempt counting; prior count is unknown');
|
|
41
|
+
const prior = existsSync(path) ? JSON.parse(readFileSync(path, 'utf8')) as unknown : { version, runId: state.runId, attempts: [] };
|
|
42
|
+
if (!prior || typeof prior !== 'object' || Array.isArray(prior)) throw new Error('release resume attempts ledger invalid');
|
|
43
|
+
const saved = prior as { version?: unknown; runId?: unknown; attempts?: unknown };
|
|
44
|
+
if (saved.version !== version || saved.runId !== state.runId || !Array.isArray(saved.attempts)
|
|
45
|
+
|| saved.attempts.some(value => typeof value !== 'string' || !Number.isFinite(Date.parse(value))))
|
|
46
|
+
throw new Error('release resume attempts ledger invalid');
|
|
47
|
+
if (saved.attempts.length >= RELEASE_RESUME_LIMIT) blocked(`${saved.attempts.length} resumes already recorded`);
|
|
48
|
+
if (options.checkOnly) return { attempt: saved.attempts.length + 1, path };
|
|
49
|
+
const at = (options.now ?? (() => new Date()))().toISOString();
|
|
50
|
+
const next = { version, runId: state.runId, attempts: [...saved.attempts, at] };
|
|
51
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
52
|
+
const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
53
|
+
try { writeFileSync(temp, `${JSON.stringify(next)}\n`, { mode: 0o600 }); renameSync(temp, path); }
|
|
54
|
+
finally { try { unlinkSync(temp); } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; } }
|
|
55
|
+
return { attempt: next.attempts.length, path };
|
|
56
|
+
}
|