elanous 0.2.23 → 0.2.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +1 -0
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +36 -0
- package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +148 -0
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1454-37fd16f479f5554a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8532.a86e99acf9b761cb.js → 1516.83dd2c1b86b4e507.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{89849432.9eaa2f4c9c010965.js → 16e57f67.3ea19e893461e611.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1505.5826671109111e75.js → 1743.563d3168e95825ef.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +32 -0
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2846.d6a433b8663819a5.js +309 -0
- package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{5967-c0a80f8ffe5d4050.js → 3259-86f3be56e43eaf6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +287 -0
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5578.ac963634373b28c6.js → 4084.15ecaf4240bd9e77.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8438.ee7f0df3b3f6fcb4.js → 4204.a409ab6250c0f6a8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +8 -0
- package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7905.b230b9d06cb4ad5d.js → 4593.10f5b9bd702d4a6c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{8569.b853a8daa8f31d12.js → 5081.a240b63fad28663a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2528.0af5c0e1fad88df6.js → 5408.377c8c543635b81f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9502-32c5dc22e8f120f5.js → 5492-e05e26a033ba80d2.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5785-ea8d2c633b6688e3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +23 -0
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5974.360f8441eb0ac1ec.js → 6196.34d6b229079e9e28.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +77 -0
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +64 -0
- package/apps/pwa/out/_next/static/chunks/{ce383d63.d2ede338788ed18e.js → 65ebff95.081daeff622d238e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{83cfc5c8.349535543c1548b6.js → 6def8a8e.c81f9ca41028eccf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2721.bc9a8f36bd85c07a.js → 7483.ba01c6c209b81bba.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{6702.ebbd165d5e4a4a14.js → 7752.5cbdd0b433c54af9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8925-2abfb48af477fb7f.js → 8085-1e5fce59500a2cc2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{b4e12462-5fab4a813a63dadd.js → 83a80514-b897b64df43ce108.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +93 -0
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{8264.00e434fbd02e9311.js → 8578.dff22d988cc2b106.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +115 -0
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +41 -0
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +74 -0
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7518.49161e8f5814abdb.js → 9311.24c8f5ea793253dd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9976.8f28864317639fe6.js → 94.4cfed21c0b781a06.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +90 -0
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0e3acd34.d42b2ef87fdf4234.js → 973cbf1b.3bbcf2b41548eca7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6571-926ddf024a6ad5df.js → 9917-9e26abc5f7772735.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +79 -0
- package/apps/pwa/out/_next/static/chunks/{740.90b31555290236a9.js → 9974.e77b4ff4884557b3.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{4c5e95ce.83e9b16add6fcd8c.js → ab4d57c2.e90bc2cb31949045.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ad3bd8084048bee4.js → page-b12149c51f7d04b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-305cd294e754906e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-a648bc464c9dc754.js → page-dea4b795741126fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45889e7070d11126.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-16a2e893f83ae4d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-56888bc744e08dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-952c6ceec6d9de38.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-6d0202af568f4c63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4fb6fc34e20c07b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-e9502921f4f01b1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-b6169ea2f09cf287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6a14333d1b1b3967.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8c91a9a66c9ec90a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-48fb31810693c357.js → page-4e634c5b98fd4e93.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-cb154acadb025414.js → page-b9cc8a10bc6078b4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-3d3fc73dd187ed52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9c04dac0831c2bbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-04de9ca6d52a3893.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-62527677bbc2fdc4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9a2e09c4a311764c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-bfeb35d69e8b24bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-89cb33bced824e4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-6445ac4cbb8dd869.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-20162174b77f96cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-05a4b2c9b91034aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{53746282.1be36038d1abd949.js → e117f801.e92bf10242653497.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{0673cc54.8e2ef1c23e49e190.js → f4dfbfc0.a69fb12f854882aa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +1 -0
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/graphs/release/release-loop.yaml +5 -5
- package/graphs/steward/recipes.yaml +4 -0
- package/graphs/steward/steward.yaml +10 -1
- package/package.json +1 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/bench-report.ts +46 -1
- package/scripts/ci-typecheck-changed.ts +73 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/release-loop/auto-approve-node.ts +6 -0
- package/scripts/release-loop/gate-closure.ts +286 -0
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-node.ts +333 -37
- package/scripts/release-loop/gate-partial.ts +34 -6
- package/scripts/release-loop/ops-upgrade-node.ts +63 -42
- package/scripts/release-loop/publish-node.ts +6 -0
- package/scripts/release-loop/resume-release.ts +46 -13
- package/scripts/release-loop/resume.ts +110 -4
- package/scripts/release-loop/unattended-release.ts +22 -7
- package/scripts/tsc-baseline-cache.ts +172 -0
- package/scripts/usage-rollup.ts +72 -6
- package/scripts/ux-sim.ts +30 -1
- package/skills/youtube-master/scripts/main.ts +4 -1
- package/skills/youtube-master/src/obsidian.ts +9 -0
- package/src/agent/run-context.ts +10 -0
- package/src/agent-mission/driver.ts +18 -3
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +8 -2
- package/src/agent-substrate/acp-implementer.ts +146 -0
- package/src/agent-substrate/pr-reviewer.ts +60 -13
- package/src/agent-substrate/self-review-cli.ts +170 -15
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/budget/cost-tier-advisor.ts +91 -0
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/shadow-arms.ts +77 -0
- package/src/budget/types.ts +10 -2
- package/src/budget/unified-usage.ts +256 -10
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/doctor-cli.ts +21 -0
- package/src/cli/friendly-errors.ts +113 -0
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/intake-cli.ts +3 -1
- package/src/cli/log-event-names.ts +4 -0
- package/src/cli/memory-cli.ts +182 -0
- package/src/cli/model-watch-cli.ts +4 -1
- package/src/cli/pr-cli.ts +62 -5
- package/src/cli/pr-land-overlap-evidence.ts +160 -12
- package/src/cli/pr-land-pod-shadow.ts +54 -0
- package/src/cli/release-cli.ts +27 -16
- package/src/cli/release-run-if-ready.ts +11 -0
- package/src/cli/resource-cli.ts +48 -0
- package/src/cli/retro-cli.ts +12 -3
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/seat-requests-cli.ts +25 -0
- package/src/cli/self-update.ts +104 -0
- package/src/cli/tasks-cli.ts +139 -10
- package/src/cli/usage-cli.ts +93 -8
- package/src/compact/verify-probe.ts +23 -3
- package/src/context-card/index.ts +50 -0
- package/src/control/control-status.ts +30 -1
- package/src/core-turn/run-goal-loop.ts +5 -4
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/index.ts +18 -276
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
- package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
- package/src/dashboard/stale-install-check.ts +11 -0
- package/src/debug/log-diet.ts +53 -10
- package/src/debug/log.ts +19 -1
- package/src/domains/morning-essential.ts +18 -3
- package/src/domains/release-tool.ts +43 -0
- package/src/error-report/report.ts +21 -4
- package/src/execution-loop/launch-gate.ts +158 -2
- package/src/fleet/host-doctor.ts +375 -0
- package/src/github/pr-labels.ts +1 -0
- package/src/goals/judge.ts +20 -6
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +176 -11
- package/src/graph-wizard/archetypes.ts +14 -8
- package/src/graph-wizard/generate.ts +77 -1
- package/src/grok/usage.ts +23 -2
- package/src/grok.ts +13 -7
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +10 -2
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +176 -52
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-stop.ts +82 -10
- package/src/harness/harness-substrate-default.ts +142 -7
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/seats.ts +38 -22
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +110 -186
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/collect-github.ts +7 -2
- package/src/intake-plane/lens.ts +46 -4
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intake-plane/requirement-funnel.ts +53 -1
- package/src/intelligence-map/catalog-feed.ts +119 -0
- package/src/intelligence-map/model-catalog.ts +72 -0
- package/src/intelligence-map/model-watch-intake.ts +40 -0
- package/src/intelligence-map/model-watch-mission.ts +14 -1
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +114 -41
- package/src/llm/bedrock.ts +174 -28
- package/src/llm/open-weight-discipline.ts +21 -0
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +91 -24
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/maturity/feature-maturity.ts +3 -3
- package/src/model-tier/llm-tier-map.ts +9 -5
- package/src/models/prompts.ts +2 -1
- package/src/mss/logging/log-store.ts +58 -11
- package/src/nexus/api/http-server.ts +22 -0
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/index.ts +7 -75
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +43 -3
- package/src/oauth/codex-account-store.ts +339 -27
- package/src/oauth/codex-quota-policy.ts +33 -4
- package/src/oauth/fallback-chain.ts +53 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/preview/terminal.ts +15 -5
- package/src/project/project-store.ts +20 -0
- package/src/prompt-cache/openai.ts +3 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +23 -0
- package/src/release-loop/auto-start.ts +7 -5
- package/src/release-loop/checklist.ts +11 -1
- package/src/release-loop/gate-shards.ts +4 -0
- package/src/release-loop/light-rc.ts +84 -13
- package/src/release-loop/merged-pr-checklist.ts +35 -5
- package/src/release-loop/placement.ts +16 -1
- package/src/release-loop/rehearsal.ts +1 -1
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +5 -5
- package/src/seat-loop/duty-ledger.ts +64 -0
- package/src/seat-loop/seat-loop.ts +32 -10
- package/src/self-dev/decompose.ts +37 -3
- package/src/self-dev/dev-cli.ts +44 -10
- package/src/self-dev/dev-pipeline.ts +39 -9
- package/src/self-dev/draft-residue.ts +27 -5
- package/src/self-dev/draft-sweep.ts +151 -0
- package/src/self-dev/fabric-decompose-adapter.ts +9 -2
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/orchestrate-cli.ts +25 -3
- package/src/self-dev/orchestrate.ts +41 -6
- package/src/self-dev/run-supervisor.ts +218 -15
- package/src/self-dev/run-types.ts +13 -0
- package/src/self-dev/supervisor-verdict-edges.ts +1 -0
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/gate-cli.ts +29 -10
- package/src/self-implement/gate-remote.ts +4 -1
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +36 -11
- package/src/self-implement/goal-new-paths.ts +42 -0
- package/src/self-implement/graph-overlay-condition.ts +28 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/host-regate.ts +124 -30
- package/src/self-implement/importer-test-index.ts +3 -1
- package/src/self-implement/l8-merge-queue.ts +80 -2
- package/src/self-implement/merge-train.ts +19 -0
- package/src/self-implement/off-diff-evidence.ts +40 -1
- package/src/self-implement/orchestrator.ts +230 -32
- package/src/self-implement/premise-review.ts +159 -0
- package/src/self-implement/regate-detail.ts +79 -0
- package/src/self-implement/review-deferred-to-host.ts +21 -0
- package/src/self-implement/rework-budget-judgment.ts +23 -3
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/scope-adjacency.ts +23 -0
- package/src/self-implement/seams.ts +89 -8
- package/src/self-implement/self-implement-cli.ts +9 -4
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/tools/agent.ts +16 -1
- package/src/skills/tools/persistent-grounding.ts +11 -1
- package/src/skills/tools/shell.ts +33 -1
- package/src/steward/launch.ts +5 -4
- package/src/steward/rejudge-tick.ts +142 -0
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +83 -22
- package/src/task-agent/actions.ts +62 -5
- package/src/task-agent/board.ts +92 -3
- package/src/task-agent/card-evidence.ts +88 -1
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +166 -3
- package/src/task-agent/judge.ts +16 -0
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/live-move-history.ts +87 -1
- package/src/task-agent/live-moves.ts +350 -20
- package/src/task-agent/parent-host.ts +27 -3
- package/src/task-agent/rejudge-on-head.ts +223 -24
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/review-result-capture.ts +3 -1
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +65 -9
- package/src/task-agent/task-hand.ts +57 -7
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -4
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +432 -35
- package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +69 -15
- package/src/ux-sim/fault-cred-expiry.ts +100 -0
- package/src/ux-sim/fault-pod-death.ts +74 -0
- package/src/ux-sim/fault-pool-cap.ts +81 -0
- package/src/version/packed-revision.json +1 -1
- package/src/webclone/qa-table.ts +22 -0
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
- package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-6168a7c43e6ef8f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +0 -1
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
- /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
// changed — not the whole 24-shard sweep again (0.2.18: two timeout fixes on top of an 84-minute gate meant another full
|
|
3
3
|
// gate). The plan is opt-in (`release resume --from gate --partial`) and fail-closed: any non-test source change, a prior
|
|
4
4
|
// gate record for another commit, or a missing record means «full gate», never a guess.
|
|
5
|
+
// GATE-REUSE-BY-DIFF (0.2.25): a code change no longer forces the full sweep — with the tip's import closure
|
|
6
|
+
// (gate-closure.ts) the plan adds every test that can reach a changed file, and every test whose closure is opaque.
|
|
7
|
+
// `release resume --from gate` now plans this by default when the tip moved (`--no-partial` = full gate).
|
|
5
8
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
6
9
|
import { spawnSync } from 'node:child_process';
|
|
7
10
|
import { dirname, join } from 'node:path';
|
|
11
|
+
import { CODE_FILE, type ClosureVerdict } from './gate-closure';
|
|
8
12
|
|
|
9
13
|
export interface PartialPlan {
|
|
10
14
|
version: string;
|
|
@@ -12,7 +16,7 @@ export interface PartialPlan {
|
|
|
12
16
|
priorCommit: string;
|
|
13
17
|
/** The commit this plan is for — a gate on any other commit ignores it. */
|
|
14
18
|
forCommit: string;
|
|
15
|
-
/** Test files re-run: changed test files ⊕ files of the prior failures. */
|
|
19
|
+
/** Test files re-run: changed test files ⊕ files of the prior failures ⊕ tests reaching a changed code file. */
|
|
16
20
|
files: string[];
|
|
17
21
|
priorFailures: string[];
|
|
18
22
|
priorErrors: string[];
|
|
@@ -37,19 +41,43 @@ export function testFileOfId(id: string): string {
|
|
|
37
41
|
|
|
38
42
|
/** Decide whether a partial re-gate is safe for `changedFiles` (prior → for). Never guesses: any doubt is a full gate. */
|
|
39
43
|
export function planPartialRegate(input: { version: string; priorCommit: string; forCommit: string; changedFiles: readonly string[];
|
|
40
|
-
priorFailures: readonly string[]; priorErrors: readonly string[]
|
|
41
|
-
|
|
44
|
+
priorFailures: readonly string[]; priorErrors: readonly string[];
|
|
45
|
+
/** GATE-REUSE-BY-DIFF: the tests reaching these changed code files (seeds include changed tests). Without it any
|
|
46
|
+
* non-test change is a full gate. */
|
|
47
|
+
closure?: (changedCode: string[]) => ClosureVerdict;
|
|
48
|
+
/** Tracked at the tip — a deleted changed test is not re-run (nothing to run); a deleted prior-failure file is a full
|
|
49
|
+
* gate (its failure can be neither re-measured nor carried). Without it every changed test is planned. */
|
|
50
|
+
existsAtTip?: (file: string) => boolean }):
|
|
51
|
+
{ ok: true; plan: PartialPlan; closure?: { reached: number; opaque: number } } | { ok: false; reason: string } {
|
|
42
52
|
if (!/^[0-9a-f]{40}$/i.test(input.priorCommit) || !/^[0-9a-f]{40}$/i.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
|
|
43
53
|
if (input.priorCommit === input.forCommit) return { ok: false, reason: 'no new commit since the prior gate' };
|
|
44
54
|
const source = input.changedFiles.filter((file) => !TEST_FILE.test(file) && !isInert(file));
|
|
45
|
-
|
|
55
|
+
const list = (files: string[]) => `${files.slice(0, 5).join(', ')}${files.length > 5 ? ` (+${files.length - 5})` : ''}`;
|
|
56
|
+
// Only code is followed through the closure: a changed fixture, JSON, lockfile, config or script is a full gate.
|
|
57
|
+
const notCode = source.filter((file) => !CODE_FILE.test(file));
|
|
58
|
+
if (source.length && (!input.closure || notCode.length)) return { ok: false, reason: `non-test change → full gate: ${list(notCode.length ? notCode : source)}` };
|
|
59
|
+
let reaching: string[] = [];
|
|
60
|
+
let closure: { reached: number; opaque: number } | undefined;
|
|
61
|
+
if (source.length) {
|
|
62
|
+
let verdict: ClosureVerdict;
|
|
63
|
+
try { verdict = input.closure!(input.changedFiles.filter((file) => CODE_FILE.test(file))); }
|
|
64
|
+
catch (error) { return { ok: false, reason: `import closure unreadable → full gate: ${String(error instanceof Error ? error.message : error).slice(0, 200)}` }; }
|
|
65
|
+
if (!verdict.ok) return { ok: false, reason: verdict.reason };
|
|
66
|
+
const unsafe = verdict.tests.filter((file) => !TEST_FILE.test(file) || file.split('/').includes('..'));
|
|
67
|
+
if (unsafe.length) return { ok: false, reason: `closure selected a test path the plan cannot carry → full gate: ${list(unsafe)}` };
|
|
68
|
+
reaching = verdict.tests;
|
|
69
|
+
closure = { reached: verdict.reached, opaque: verdict.opaque };
|
|
70
|
+
}
|
|
46
71
|
let failureFiles: string[];
|
|
47
72
|
try { failureFiles = [...input.priorFailures, ...input.priorErrors].map(testFileOfId); }
|
|
48
73
|
catch (error) { return { ok: false, reason: String(error instanceof Error ? error.message : error) }; }
|
|
49
|
-
const
|
|
74
|
+
const exists = input.existsAtTip ?? (() => true);
|
|
75
|
+
const gone = failureFiles.filter((file) => !exists(file));
|
|
76
|
+
if (gone.length) return { ok: false, reason: `prior failure file deleted at the tip → full gate: ${list(gone)}` };
|
|
77
|
+
const files = [...new Set([...input.changedFiles.filter((file) => TEST_FILE.test(file) && exists(file)), ...failureFiles, ...reaching])].sort();
|
|
50
78
|
if (!files.length) return { ok: false, reason: 'nothing to re-run' };
|
|
51
79
|
return { ok: true, plan: { version: input.version, priorCommit: input.priorCommit, forCommit: input.forCommit, files,
|
|
52
|
-
priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors] } };
|
|
80
|
+
priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors] }, ...(closure ? { closure } : {}) };
|
|
53
81
|
}
|
|
54
82
|
|
|
55
83
|
export function writePartialPlan(root: string, plan: PartialPlan): string {
|
|
@@ -9,7 +9,7 @@ import { prereleaseKind } from './release-version.js';
|
|
|
9
9
|
interface HostResult { host: string; ok: boolean; before: string; after: string; error?: string; skipped?: string; hooks?: string; restart?: 'no-service' }
|
|
10
10
|
/** Where the internal feed is packed from: a checkout of the release tag, never the run's working tree. */
|
|
11
11
|
export interface FeedSource { checkout: string; commit: string; deps: 'linked' | 'installed'; cleanup: () => void }
|
|
12
|
-
interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null; feedSource?: (version: string) => FeedSource }
|
|
12
|
+
interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null; installCommit?: () => string | null; feedSource?: (version: string) => FeedSource }
|
|
13
13
|
|
|
14
14
|
/** Detached worktree at refs/tags/v<version> with the PWA built — the feed ships what was released (10-04 0.2.11:
|
|
15
15
|
* packing process.cwd() shipped main HEAD ee689ad2 as «0.2.11» to node-b·cloud-vm instead of the cut 31129c91). */
|
|
@@ -52,16 +52,24 @@ export function tagFeedSource(run: CommandRunner, repo: string = process.cwd()):
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function
|
|
55
|
+
function installMetadata(text: string): { source: string | null; commit: string | null } {
|
|
56
56
|
try {
|
|
57
|
-
const data: unknown = JSON.parse(
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
const data: unknown = JSON.parse(text);
|
|
58
|
+
if (!data || typeof data !== 'object') return { source: null, commit: null };
|
|
59
|
+
return {
|
|
60
|
+
source: 'source' in data && typeof data.source === 'string' ? data.source : null,
|
|
61
|
+
commit: 'commit' in data && typeof data.commit === 'string' ? data.commit : null,
|
|
62
|
+
};
|
|
63
|
+
} catch { return { source: null, commit: null }; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function localInstallMetadata(): { source: string | null; commit: string | null } {
|
|
67
|
+
try { return installMetadata(readFileSync(join(homedir(), '.local/share/elanous/install.json'), 'utf8')); }
|
|
68
|
+
catch { return { source: null, commit: null }; }
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
function installedMatches(installed: unknown, version: string
|
|
63
|
-
return installed === version
|
|
64
|
-
&& installed.startsWith(`${version}-`) && /^[0-9a-f]{12}$/.test(installed.slice(version.length + 1));
|
|
71
|
+
function installedMatches(installed: unknown, version: string): boolean {
|
|
72
|
+
return installed === version;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
function missingService(data: Record<string, unknown> | undefined): boolean {
|
|
@@ -116,17 +124,21 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
|
|
|
116
124
|
}
|
|
117
125
|
const results: HostResult[] = [];
|
|
118
126
|
for (const host of hosts as string[]) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
127
|
+
// Injected install metadata replaces the machine's install.json entirely — a test that injects only the source
|
|
128
|
+
// must not inherit this machine's real commit (that turned update cases into kept-ahead skips).
|
|
129
|
+
const injected = deps.installSource !== undefined || deps.installCommit !== undefined;
|
|
130
|
+
let metadata: { source: string | null; commit: string | null } = host !== 'local'
|
|
131
|
+
? { source: null, commit: null }
|
|
132
|
+
: injected
|
|
133
|
+
? { source: deps.installSource?.() ?? null, commit: deps.installCommit?.() ?? null }
|
|
134
|
+
: localInstallMetadata();
|
|
135
|
+
let source = metadata.source;
|
|
136
|
+
let railSource = false;
|
|
137
|
+
let path: 'checkout' | 'release' = 'release';
|
|
122
138
|
const record = (result: HostResult) => {
|
|
123
139
|
results.push(result);
|
|
124
140
|
debug.log('release-loop.ops-upgrade', 'host', { host, path, restart: result.restart ?? (context.input.opsRestart === true ? result.ok ? 'ok' : 'failed' : 'skipped'), ok: result.ok });
|
|
125
141
|
};
|
|
126
|
-
if (host !== 'local' && feedError) {
|
|
127
|
-
record({ host, ok: false, before: '', after: '', skipped: '내부 피드 발행 실패', error: feedError });
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
142
|
const command = (args: string[]): CommandResult => host === 'local'
|
|
131
143
|
? run('elanous', args)
|
|
132
144
|
// The installer's own bin dir comes first — a --no-modify-path install (the bot VM) has elanous only there.
|
|
@@ -134,35 +146,41 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
|
|
|
134
146
|
let before = '';
|
|
135
147
|
let after = '';
|
|
136
148
|
try {
|
|
149
|
+
if (host !== 'local') {
|
|
150
|
+
const installed = run('ssh', [host, `cat "$HOME/.local/share/elanous/install.json" 2>/dev/null || true`]);
|
|
151
|
+
if (installed.status === 0) metadata = installMetadata(installed.stdout);
|
|
152
|
+
}
|
|
153
|
+
source = metadata.source;
|
|
154
|
+
if (source !== null && isAbsolute(source)) {
|
|
155
|
+
const repository = host === 'local'
|
|
156
|
+
? run('git', ['rev-parse', '--is-inside-work-tree'], source)
|
|
157
|
+
: run('ssh', [host, `git -C ${quote(source)} rev-parse --is-inside-work-tree`]);
|
|
158
|
+
railSource = repository.status === 0 && firstLine(repository.stdout) === 'true';
|
|
159
|
+
}
|
|
160
|
+
path = railSource ? 'checkout' : 'release';
|
|
137
161
|
const previous = command(['--version']);
|
|
138
162
|
if (previous.status === 0) before = firstLine(previous.stdout);
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (
|
|
148
|
-
record({ host, ok:
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
const tag = git(['rev-parse', '--verify', `refs/tags/v${version}^{commit}`]);
|
|
152
|
-
if (tag.status !== 0 || !tag.stdout.trim()) {
|
|
153
|
-
record({ host, ok: false, before, after, error: `태그 없음: v${version}` });
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
const moved = git(['checkout', '--detach', `v${version}`]);
|
|
157
|
-
if (moved.status !== 0) {
|
|
158
|
-
record({ host, ok: false, before, after, error: `체크아웃 전환 실패: ${reason(moved)}` });
|
|
163
|
+
if (railSource) {
|
|
164
|
+
record({ host, ok: true, before, after: before, skipped: 'rail-source' });
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const installedCommit = metadata.commit;
|
|
168
|
+
if (installedCommit && /^[0-9a-f]{40,64}$/.test(installedCommit)) {
|
|
169
|
+
const ahead = run('git', ['merge-base', '--is-ancestor', `refs/tags/v${version}`, installedCommit]);
|
|
170
|
+
// Only exit 1 proves non-ancestry; missing local objects must not permit a potentially destructive downgrade.
|
|
171
|
+
if (ahead.status !== 1) {
|
|
172
|
+
record({ host, ok: true, before, after: before, skipped: 'kept-ahead' });
|
|
159
173
|
continue;
|
|
160
174
|
}
|
|
161
175
|
}
|
|
162
|
-
|
|
176
|
+
if (host !== 'local' && feedError) {
|
|
177
|
+
record({ host, ok: false, before, after: '', skipped: '내부 피드 발행 실패', error: feedError });
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const updated = command(['update', ...(host !== 'local' && feedPath !== undefined ? [] : ['--version', version]), '--json', ...(context.input.opsRestart === true ? ['--restart'] : [])]);
|
|
163
181
|
const updateResult = lastResult(updated);
|
|
164
182
|
const noService = host !== 'local' && context.input.opsRestart === true && updateResult?.exitCode === 1 && missingService(updateResult);
|
|
165
|
-
if ((!noService && (updated.status !== 0 || updateResult?.exitCode !== 0)) || !installedMatches(updateResult?.installedVersion, version
|
|
183
|
+
if ((!noService && (updated.status !== 0 || updateResult?.exitCode !== 0)) || !installedMatches(updateResult?.installedVersion, version)) {
|
|
166
184
|
const error = (updated.status === 0 && updateResult?.exitCode === 0 || noService)
|
|
167
185
|
? `설치판 불일치 (기대 ${version}, 실제 ${String(updateResult?.installedVersion)})` : reason(updated);
|
|
168
186
|
record({ host, ok: false, before, after, error });
|
|
@@ -174,7 +192,7 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
|
|
|
174
192
|
continue;
|
|
175
193
|
}
|
|
176
194
|
after = firstLine(current.stdout);
|
|
177
|
-
if (!installedMatches(after.split(/\s+/)[0], version
|
|
195
|
+
if (!installedMatches(after.split(/\s+/)[0], version)) {
|
|
178
196
|
record({ host, ok: false, before, after, error: `올렸는데 판이 그대로 (기대 ${version}, 실제 ${after || '없음'})` });
|
|
179
197
|
continue;
|
|
180
198
|
}
|
|
@@ -198,14 +216,17 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
|
|
|
198
216
|
feed: feedError ? 'failed' as const : feedPath === undefined ? 'skipped-no-path' as const : 'published' as const, hosts: results };
|
|
199
217
|
}
|
|
200
218
|
|
|
201
|
-
|
|
219
|
+
function main(): void {
|
|
202
220
|
let version = '';
|
|
203
221
|
try {
|
|
204
222
|
version = readGraphContext().input.version;
|
|
205
223
|
// RELEASE-REHEARSAL-RC: a prerelease never lands docs on main or upgrades the operating hosts.
|
|
206
|
-
|
|
207
|
-
? { outcome: 'ok', verdict: 'pass', summary: `ops-upgrade skipped — ${version} is a prerelease`, skipped: 'prerelease' }
|
|
208
|
-
: runOpsUpgrade()
|
|
224
|
+
const result = prereleaseKind(version) !== null
|
|
225
|
+
? { outcome: 'ok' as const, verdict: 'pass' as const, summary: `ops-upgrade skipped — ${version} is a prerelease`, skipped: 'prerelease' }
|
|
226
|
+
: runOpsUpgrade(runCommand);
|
|
227
|
+
process.exitCode = finishNode('ops-upgrade', version, result);
|
|
209
228
|
}
|
|
210
229
|
catch (error) { process.exitCode = finishNode('ops-upgrade', version, errorResult(error)); }
|
|
211
230
|
}
|
|
231
|
+
|
|
232
|
+
if (import.meta.main) main();
|
|
@@ -5,6 +5,7 @@ import { join } from 'node:path';
|
|
|
5
5
|
import { 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
|
+
import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
|
|
8
9
|
import { prereleaseKind } from './release-version.js';
|
|
9
10
|
import { publishAtError } from './publish-at.js';
|
|
10
11
|
import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
|
|
@@ -115,6 +116,11 @@ export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: str
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
if (import.meta.main) {
|
|
119
|
+
// GATE-OBS2-2 — the release graph spawns this node as its own process, which inherits no daemon sink. Without this the
|
|
120
|
+
// `release-loop.publish / result` event (the one that says whether the irreversible publication actually happened) stayed
|
|
121
|
+
// in the file trail and `elanous logs` read 0 rows. Same pattern as gate-node.ts and auto-approve-node.ts (GATE-OBS2-1).
|
|
122
|
+
// Observability must never stop the publication node — a failed sink registration is skipped (fail-soft).
|
|
123
|
+
try { await registerStandaloneLogSink('release-loop'); } catch { /* fail-soft: the verdict still goes to stdout */ }
|
|
118
124
|
let version = '';
|
|
119
125
|
try { version = readGraphContext().input.version; process.exitCode = finishNode('publish', version, runPublish()); }
|
|
120
126
|
catch (error) { process.exitCode = finishNode('publish', version, errorResult(error)); }
|
|
@@ -10,7 +10,8 @@ import { lastJsonObject, runGraph, type GraphRunState } from '../../src/graph-ru
|
|
|
10
10
|
import { releaseRunUniverse } from './release-universe.js';
|
|
11
11
|
import { isReleaseVersion } from './release-version.js';
|
|
12
12
|
import { changedFilesBetween, clearPartialPlan, planPartialRegate, writePartialPlan } from './gate-partial.js';
|
|
13
|
-
import {
|
|
13
|
+
import { gitClosureTree, testsReachingChanged, type ClosureTree } from './gate-closure.js';
|
|
14
|
+
import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
|
|
14
15
|
|
|
15
16
|
const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
|
|
16
17
|
|
|
@@ -29,8 +30,15 @@ export interface ResumeReleaseDeps {
|
|
|
29
30
|
now?: () => Date;
|
|
30
31
|
/** Machine release ledger (gate-failures.json of the prior gate) — default releaseLedgerRoot(). */
|
|
31
32
|
ledgerRoot?: string;
|
|
33
|
+
/** GATE-REUSE-BY-DIFF: the tip tree for the import closure — default read from git objects of the tip commit. */
|
|
34
|
+
closureTree?: (commit: string) => ClosureTree;
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
/** CLI entry files: a production file that only names one (help text, a goal's command line) does not run it. */
|
|
38
|
+
const CLI_ENTRIES = ['bin/elanous.mjs', 'src/index.ts'] as const;
|
|
39
|
+
/** The gate's own test-file set (gate-node sweep: `git ls-files '*.test.*'` filtered by this). */
|
|
40
|
+
const GATE_TEST = /\.test\.(?:tsx?|jsx?|mts|cts)$/;
|
|
41
|
+
|
|
34
42
|
export interface TipRefresh { version: string; branch: string; from: string; to: string; changed: boolean; statePath: string; backup?: string }
|
|
35
43
|
|
|
36
44
|
function gitRunner(repo: string) {
|
|
@@ -114,18 +122,25 @@ export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps =
|
|
|
114
122
|
return { version, branch, from: recorded, to, changed: true, statePath, backup };
|
|
115
123
|
}
|
|
116
124
|
|
|
117
|
-
/** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate.
|
|
118
|
-
|
|
125
|
+
/** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate. `auto` marks the
|
|
126
|
+
* default plan of `--from gate` (GATE-REUSE-BY-DIFF); `closure` is set when code changes were followed. */
|
|
127
|
+
export type PartialOutcome = { requested: false }
|
|
128
|
+
| { requested: true; applied: true; files: number; priorCommit: string; auto?: true; closure?: { reached: number; opaque: number } }
|
|
129
|
+
| { requested: true; applied: false; reason: string; auto?: true };
|
|
119
130
|
|
|
120
|
-
/** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate.
|
|
131
|
+
/** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate.
|
|
132
|
+
* GATE-REUSE-BY-DIFF: `--from gate` on a moved tip plans by default (`partial: undefined`); `partial: false` opts out. */
|
|
121
133
|
function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean }, deps: ResumeReleaseDeps): PartialOutcome {
|
|
122
134
|
const root = deps.root ?? effectiveInstanceRoot();
|
|
123
|
-
// Any resume starts from no plan: one without
|
|
135
|
+
// Any resume starts from no plan: one without a partial plan (from whatever node) never inherits an older plan.
|
|
124
136
|
clearPartialPlan(root, tip.version);
|
|
125
|
-
|
|
137
|
+
const auto = opts.partial === undefined;
|
|
138
|
+
// The default applies only where it can help: a gate re-run on a tip that moved. An unchanged tip re-uses its own
|
|
139
|
+
// shard results by commit already.
|
|
140
|
+
if (opts.partial === false || (auto && (opts.from !== 'gate' || !tip.changed))) return { requested: false };
|
|
126
141
|
const fallback = (reason: string): PartialOutcome => {
|
|
127
|
-
debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason });
|
|
128
|
-
return { requested: true, applied: false, reason };
|
|
142
|
+
debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason, auto });
|
|
143
|
+
return { requested: true, applied: false, reason, ...(auto ? { auto: true as const } : {}) };
|
|
129
144
|
};
|
|
130
145
|
if (opts.from !== 'gate') return fallback('--partial only applies to --from gate');
|
|
131
146
|
if (!tip.changed) return fallback('release branch tip unchanged — nothing new to re-check');
|
|
@@ -151,12 +166,23 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
|
|
|
151
166
|
// The tip is already refreshed — a failed diff must not strand the resume: run the full gate and say why.
|
|
152
167
|
return fallback(`changed files unreadable: ${String(error instanceof Error ? error.message : error).slice(0, 200)}`);
|
|
153
168
|
}
|
|
169
|
+
// The tip tree (git objects of tip.to, never the working tree): existence of planned tests ⊕ the import closure.
|
|
170
|
+
let tree: ClosureTree;
|
|
171
|
+
try { tree = (deps.closureTree ?? ((commit: string) => gitClosureTree(deps.repo ?? process.cwd(), commit)))(tip.to); }
|
|
172
|
+
catch (error) { return fallback(`tip tree unreadable: ${String(error instanceof Error ? error.message : error).slice(0, 200)}`); }
|
|
173
|
+
const tracked = new Set(tree.files);
|
|
174
|
+
const tests = tree.files.filter((file) => GATE_TEST.test(file));
|
|
154
175
|
const planned = planPartialRegate({ version: tip.version, priorCommit: tip.from, forCommit: tip.to, changedFiles: changed,
|
|
155
|
-
priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[]
|
|
176
|
+
priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[],
|
|
177
|
+
existsAtTip: (file) => tracked.has(file),
|
|
178
|
+
closure: (changedCode) => testsReachingChanged(tree, changedCode, tests, { cliEntries: CLI_ENTRIES }) });
|
|
156
179
|
if (!planned.ok) return fallback(planned.reason);
|
|
180
|
+
if (planned.plan.files.length >= tests.length) return fallback(`every test is re-run (${tests.length}) — full gate`);
|
|
157
181
|
const path = writePartialPlan(root, planned.plan);
|
|
158
|
-
debug.log('release-loop.resume', 'partial-planned', { version: tip.version, priorCommit: tip.from, commit: tip.to, files: planned.plan.files.length,
|
|
159
|
-
|
|
182
|
+
debug.log('release-loop.resume', 'partial-planned', { version: tip.version, priorCommit: tip.from, commit: tip.to, files: planned.plan.files.length,
|
|
183
|
+
tests: tests.length, auto, path, ...(planned.closure ? { reached: planned.closure.reached, opaque: planned.closure.opaque } : {}) });
|
|
184
|
+
return { requested: true, applied: true, files: planned.plan.files.length, priorCommit: tip.from,
|
|
185
|
+
...(auto ? { auto: true as const } : {}), ...(planned.closure ? { closure: planned.closure } : {}) };
|
|
160
186
|
}
|
|
161
187
|
|
|
162
188
|
/** The graph file the run started from — a snapshot run refuses any other path (the installed CLI's own copy differs). */
|
|
@@ -168,16 +194,22 @@ function savedGraphPath(statePath: string): string | undefined {
|
|
|
168
194
|
}
|
|
169
195
|
|
|
170
196
|
/** Refresh the branch tip, then restart the failed run at `from` with the saved graph snapshot. */
|
|
171
|
-
export async function resumeReleaseRun(opts: { runId: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[] }, deps: ResumeReleaseDeps = {}): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
|
|
197
|
+
export async function resumeReleaseRun(opts: { runId: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[]; gateExecutor?: string; gateHost?: string }, deps: ResumeReleaseDeps = {}): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
|
|
172
198
|
if (opts.from === 'version-release') throw new Error('--from version-release would cut again — resume at a later node');
|
|
173
199
|
// RELEASE-LEDGER-UNIVERSE: decide the universe once; the run lookup and every resumed node use it.
|
|
174
200
|
deps = { ...deps, root: releaseRunUniverse({ root: deps.root }) };
|
|
175
201
|
const statePath = join(deps.root!, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
|
|
176
202
|
let waiverCommit: string | undefined;
|
|
177
|
-
|
|
203
|
+
if (opts.gateHost !== undefined && opts.gateExecutor === undefined) throw new Error('--gate-host requires --gate-executor host');
|
|
204
|
+
const original = opts.waive !== undefined || opts.reason !== undefined || opts.acceptedRegressions !== undefined || opts.gateExecutor !== undefined
|
|
178
205
|
? JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState : undefined;
|
|
206
|
+
// GATE-HOST-EXECUTOR: checked before the tip refresh writes anything; the runner checks it again under the resume lock.
|
|
207
|
+
const gateExecutor = original && opts.gateExecutor !== undefined
|
|
208
|
+
? releaseResumeGateExecutor(original, { from: opts.from, executor: opts.gateExecutor, host: opts.gateHost }) : undefined;
|
|
209
|
+
if (gateExecutor) debug.log('release-loop.resume', 'gate-executor', { runId: opts.runId, from: opts.from, executor: gateExecutor.set.gateExecutor, host: gateExecutor.set.gateRemote ?? null, previous: gateExecutor.previous });
|
|
179
210
|
const waiver = original && (opts.waive !== undefined || opts.reason !== undefined)
|
|
180
211
|
? releaseResumeWaiver(original, opts) : undefined;
|
|
212
|
+
if (waiver) debug.log('release-loop.resume', 'waiver', { runId: opts.runId, node: waiver.nodeId, reason: waiver.reason, unmeasured: waiver.unmeasured ?? null });
|
|
181
213
|
const acceptedRegressions = original && opts.acceptedRegressions !== undefined && !waiver
|
|
182
214
|
? releaseResumeAcceptedRegressions(original, opts.acceptedRegressions, opts.from) : undefined;
|
|
183
215
|
// A waived verdict may reuse its original commit. A moved tip still requires a full re-gate.
|
|
@@ -202,6 +234,7 @@ export async function resumeReleaseRun(opts: { runId: string; from: string; part
|
|
|
202
234
|
const state = await (deps.graph ?? runGraph)(graphPath, { resumeRunId: opts.runId, fromNodeId: opts.from, pinChildUniverse: true,
|
|
203
235
|
...(waiver ? { releaseWaiver: { ...waiver, requestedRegressions: opts.acceptedRegressions ?? [] } } : {}),
|
|
204
236
|
...(acceptedRegressions ? { releaseAcceptedRegressions: { requested: opts.acceptedRegressions!, acceptedRegressions } } : {}),
|
|
237
|
+
...(gateExecutor ? { releaseGateExecutor: { executor: gateExecutor.set.gateExecutor, ...(opts.gateHost !== undefined ? { host: opts.gateHost } : {}) } } : {}),
|
|
205
238
|
deps: { root: deps.root, ...(deps.runBash ? { runBash: deps.runBash } : {}) } });
|
|
206
239
|
return { tip, partial, state };
|
|
207
240
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { lastJsonObject, STOPPED_NODE_ERROR, type GraphRunState } from '../../src/graph-runner/runner.js';
|
|
2
2
|
import { publicWaiverReason } from './known-issues-node.js';
|
|
3
|
+
import { checkGateExecutorChoice, type GateExecutor } from './gate-executor.js';
|
|
3
4
|
|
|
4
5
|
export interface AcceptedRegression { id: string; note: string }
|
|
5
6
|
|
|
@@ -27,11 +28,66 @@ export function releaseResumeAcceptedRegressions(state: GraphRunState, additions
|
|
|
27
28
|
return combined;
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
const SWEEP_INCOMPLETE = /^(?:pod sweep incomplete|sweep incomplete|[\w-]+ shard incomplete)\b/;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* RELEASE-WAIVE-UNMEASURED — why the saved gate record at `index` carries no verdict, or undefined when it does (or may).
|
|
35
|
+
* Fail-closed: only three shapes count, each read from what the runner and gate-node actually write:
|
|
36
|
+
* ① stopped — `graph runs stop` wrote {ok:false, executed:false, exit:null, error:STOPPED_NODE_ERROR} as the run's last record;
|
|
37
|
+
* ② no verdict — the gate process ended with exit null (signal, idle timeout, or a spawn that failed) and printed no result line at
|
|
38
|
+
* all (no output line is a JSON object with an `outcome`), so the run went gate → failed. A verdict followed by more
|
|
39
|
+
* log lines and then a kill is still a verdict: refused;
|
|
40
|
+
* ③ sweep incomplete — gate-node printed outcome `error` (no verdict: the baseline comparison never ran, so `introduced`
|
|
41
|
+
* is still the empty initial list) and the error is an incomplete sweep (stalled shards / no tests ran). The finished
|
|
42
|
+
* shards' counts go into the detail. Any other error (cleanup, baseline persistence, …) may follow a verdict: refused.
|
|
43
|
+
* An `outcome: fail` (introduced > 0), an introduced list that is not empty, or an already-waived record is never unmeasured.
|
|
44
|
+
*/
|
|
45
|
+
/** Any output line that is a JSON object naming an `outcome` — a verdict was printed, whatever came after it. */
|
|
46
|
+
function printedVerdict(output: unknown): boolean {
|
|
47
|
+
if (typeof output !== 'string') return false;
|
|
48
|
+
return output.split('\n').some((line) => {
|
|
49
|
+
const text = line.trim();
|
|
50
|
+
if (!text.startsWith('{')) return false;
|
|
51
|
+
try { const value = JSON.parse(text) as unknown; return !!value && typeof value === 'object' && 'outcome' in value; } catch { return false; }
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function gateUnmeasuredDetail(state: GraphRunState, index: number): string | undefined {
|
|
56
|
+
const record = state.nodes[index];
|
|
57
|
+
if (!record || record.nodeId !== 'gate' || state.path[index] !== 'gate' || record.ok !== false || record.waiver !== undefined) return undefined;
|
|
58
|
+
if (state.nodes.some((saved) => saved.nodeId === 'gate' && saved !== record)) return undefined;
|
|
59
|
+
const last = index === state.path.length - 1 && index === state.nodes.length - 1;
|
|
60
|
+
if (last && record.executed === false && record.exit === null && record.error === STOPPED_NODE_ERROR && record.output === undefined) {
|
|
61
|
+
return `stopped: ${STOPPED_NODE_ERROR}${typeof record.seconds === 'number' ? ` after ${record.seconds}s` : ''}`;
|
|
62
|
+
}
|
|
63
|
+
const failedAfter = index === state.path.length - 2 && state.path.at(-1) === 'failed' && state.nodes.at(-1)?.nodeId === 'failed'
|
|
64
|
+
&& state.nodes.length === state.path.length;
|
|
65
|
+
if (!failedAfter || record.executed !== true) return undefined;
|
|
66
|
+
const result = lastJsonObject(record.output);
|
|
67
|
+
if (result === undefined) {
|
|
68
|
+
if (record.exit !== null || printedVerdict(record.output)) return undefined;
|
|
69
|
+
return `no-verdict: gate process ended with exit null and no result line${record.error ? ` — ${record.error.split('\n')[0]!.slice(0, 120)}` : ''}`;
|
|
70
|
+
}
|
|
71
|
+
if (result.outcome !== 'error' || !Array.isArray(result.introduced) || result.introduced.length !== 0) return undefined;
|
|
72
|
+
const error = typeof result.error === 'string' ? result.error : '';
|
|
73
|
+
if (!SWEEP_INCOMPLETE.test(error)) return undefined;
|
|
74
|
+
// The detail keeps what WAS measured: each stalled shard's reason and the finished shards' counts (failures there are
|
|
75
|
+
// not yet split into introduced vs pre-existing — the baseline comparison never ran).
|
|
76
|
+
const stalled = Array.isArray(result.stalledShards) ? result.stalledShards as Array<{ reason?: unknown }> : [];
|
|
77
|
+
const reasons = new Map<string, number>();
|
|
78
|
+
for (const shard of stalled) reasons.set(String(shard?.reason ?? 'unknown'), (reasons.get(String(shard?.reason ?? 'unknown')) ?? 0) + 1);
|
|
79
|
+
const summary = result.partialSummary as { pass?: unknown; fail?: unknown; errors?: unknown; ran?: unknown } | undefined;
|
|
80
|
+
const measured = summary && typeof summary === 'object'
|
|
81
|
+
? ` · finished shards measured pass ${String(summary.pass)} fail ${String(summary.fail)} errors ${String(summary.errors)} ran ${String(summary.ran)}` : '';
|
|
82
|
+
return `sweep incomplete: ${error.split('\n')[0]!.slice(0, 200)}`
|
|
83
|
+
+ (stalled.length ? ` · stalled shards ${stalled.length} (${[...reasons].map(([reason, count]) => `${reason}×${count}`).join(', ')})` : '') + measured;
|
|
84
|
+
}
|
|
85
|
+
|
|
30
86
|
/** Only the recorded failure at the restart boundary may be waived. `--from` is never a waiver. */
|
|
31
87
|
export function releaseResumeWaiver(
|
|
32
88
|
state: GraphRunState,
|
|
33
89
|
opts: { from: string; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[] },
|
|
34
|
-
): { nodeId: string; reason: string; acceptedRegressions: AcceptedRegression[] } | undefined {
|
|
90
|
+
): { nodeId: string; reason: string; acceptedRegressions: AcceptedRegression[]; unmeasured?: string } | undefined {
|
|
35
91
|
if ((opts.waive === undefined) !== (opts.reason === undefined)) throw new Error('--waive <node> and --reason <text> must be supplied together');
|
|
36
92
|
if (opts.waive !== undefined && !opts.waive.trim()) throw new Error('--waive must not be empty');
|
|
37
93
|
if (opts.waive === undefined) return undefined;
|
|
@@ -40,14 +96,64 @@ export function releaseResumeWaiver(
|
|
|
40
96
|
publicWaiverReason(reason);
|
|
41
97
|
if (opts.from !== opts.waive) throw new Error('--from must name the waived node; --from alone does not waive a failure');
|
|
42
98
|
const index = state.path.indexOf(opts.waive);
|
|
43
|
-
|
|
99
|
+
const unique = index >= 0 && state.path.lastIndexOf(opts.waive) === index;
|
|
100
|
+
// RELEASE-WAIVE-UNMEASURED (OP 10-12): a gate cut before any verdict is the only gate that may be waived — a measured gate
|
|
101
|
+
// failure or an already-waived gate stays refused (fail-closed below), and the ledger records why it was unmeasured.
|
|
102
|
+
const unmeasured = opts.waive === 'gate' && unique ? gateUnmeasuredDetail(state, index) : undefined;
|
|
103
|
+
if (unmeasured !== undefined) {
|
|
104
|
+
return { nodeId: opts.waive, reason, unmeasured, acceptedRegressions: releaseResumeAcceptedRegressions(state,
|
|
105
|
+
[...(opts.acceptedRegressions ?? []), { id: `waive:${opts.waive}`, note: reason }]) };
|
|
106
|
+
}
|
|
107
|
+
if (!unique || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
|
|
44
108
|
state.nodes[index]?.executed !== true || state.path.at(-2) !== opts.waive || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') {
|
|
45
109
|
throw new Error(`--waive ${opts.waive} requires the failed executable node on the saved path`);
|
|
46
110
|
}
|
|
47
111
|
// Only user-visible, non-publication checks can become accepted regressions; build, safety and approval gates stay blocking.
|
|
112
|
+
// A measured gate failure (outcome fail / introduced > 0, or any error that is not an incomplete sweep) lands here too.
|
|
48
113
|
if (!['mac-smoke', 'tui'].includes(opts.waive)) {
|
|
49
|
-
throw new Error(`--waive ${opts.waive} cannot waive a safety, side-effect or approval node`
|
|
114
|
+
throw new Error(`--waive ${opts.waive} cannot waive a safety, side-effect or approval node`
|
|
115
|
+
+ (opts.waive === 'gate' ? ' (only an unmeasured gate — stopped, killed or sweep incomplete — may be waived)' : ''));
|
|
50
116
|
}
|
|
51
117
|
return { nodeId: opts.waive, reason, acceptedRegressions: releaseResumeAcceptedRegressions(state,
|
|
52
118
|
[...(opts.acceptedRegressions ?? []), { id: `waive:${opts.waive}`, note: reason }]) };
|
|
53
119
|
}
|
|
120
|
+
|
|
121
|
+
/** GATE-HOST-EXECUTOR — one explicit executor switch, recorded on the run (`GraphRunState.inputOverrides`). */
|
|
122
|
+
export interface GateExecutorOverride {
|
|
123
|
+
kind: 'gate-executor';
|
|
124
|
+
at: string;
|
|
125
|
+
from: string;
|
|
126
|
+
set: { gateExecutor: GateExecutor; gateRemote?: string };
|
|
127
|
+
/** Input keys removed — switching back to pod drops the host an earlier override added (the original had none). */
|
|
128
|
+
unset?: Array<'gateRemote'>;
|
|
129
|
+
previous: { gateExecutor: unknown; gateRemote: unknown };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Switch the gate executor of a resumed release run. Not a waiver: the gate node runs again (the restart must be at or
|
|
134
|
+
* before gate) and produces a normal verdict; only where its sweep runs changes.
|
|
135
|
+
*/
|
|
136
|
+
export function releaseResumeGateExecutor(state: GraphRunState, opts: { from: string; executor: unknown; host?: unknown; at?: string }): GateExecutorOverride {
|
|
137
|
+
const input = state.input;
|
|
138
|
+
if (!input || typeof input !== 'object' || Array.isArray(input) || typeof (input as { version?: unknown }).version !== 'string') throw new Error('release run has no input');
|
|
139
|
+
const saved = input as { gateExecutor?: unknown; gateRemote?: unknown; gatePodPool?: unknown };
|
|
140
|
+
// Host executor without --gate-host: the run's own gateRemote (release.loop.gateRemote when it started), like `release run`.
|
|
141
|
+
const choice = checkGateExecutorChoice(opts.executor, opts.executor === 'host' && opts.host === undefined ? saved.gateRemote : opts.host);
|
|
142
|
+
if (choice.executor === 'pod' && (typeof saved.gatePodPool !== 'string' || !saved.gatePodPool.trim())) {
|
|
143
|
+
throw new Error('--gate-executor pod requires the saved run input gatePodPool');
|
|
144
|
+
}
|
|
145
|
+
const start = state.path.indexOf(opts.from);
|
|
146
|
+
if (start < 0) throw new Error(`--from ${opts.from} is not a node on the saved path`);
|
|
147
|
+
const gate = state.path.indexOf('gate');
|
|
148
|
+
// A restart after gate keeps the recorded verdict — switching its executor there would record a choice nothing used.
|
|
149
|
+
if (gate >= 0 && start > gate) throw new Error('--gate-executor needs a resume that re-runs gate (--from gate or earlier)');
|
|
150
|
+
// Back to pod: restore the gateRemote the run started with (an earlier host override replaced it).
|
|
151
|
+
const firstHost = choice.executor === 'pod' ? state.inputOverrides?.find((item) => item.kind === 'gate-executor' && item.set.gateRemote !== undefined) : undefined;
|
|
152
|
+
const restored = firstHost ? firstHost.previous.gateRemote : undefined;
|
|
153
|
+
return {
|
|
154
|
+
kind: 'gate-executor', at: opts.at ?? new Date().toISOString(), from: opts.from,
|
|
155
|
+
set: { gateExecutor: choice.executor, ...(choice.host ? { gateRemote: choice.host } : typeof restored === 'string' ? { gateRemote: restored } : {}) },
|
|
156
|
+
...(firstHost && typeof restored !== 'string' ? { unset: ['gateRemote' as const] } : {}),
|
|
157
|
+
previous: { gateExecutor: saved.gateExecutor ?? null, gateRemote: saved.gateRemote ?? null },
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -12,6 +12,7 @@ import { runGraph, type GraphRunState } from '../../src/graph-runner/runner.js';
|
|
|
12
12
|
import { releaseRunUniverse } from './release-universe.js';
|
|
13
13
|
import { baseVersion, isStableVersion, nextPrereleaseVersion, type PrereleaseKind } from './release-version.js';
|
|
14
14
|
import { publishAtError } from './publish-at.js';
|
|
15
|
+
import { checkGateExecutorChoice, type GateExecutor } from './gate-executor.js';
|
|
15
16
|
|
|
16
17
|
const VERSION = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
17
18
|
const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
|
|
@@ -39,7 +40,10 @@ export interface ReleaseRunInput extends ReleaseLoopConfig {
|
|
|
39
40
|
version: string;
|
|
40
41
|
previousVersion: string;
|
|
41
42
|
cutCommit?: string;
|
|
42
|
-
|
|
43
|
+
/** Required for the pod executor (the default); a host-executor run may have none. */
|
|
44
|
+
gatePodPool?: string;
|
|
45
|
+
/** GATE-HOST-EXECUTOR — absent = pod (today's input, byte-identical); `host` sweeps on `gateRemote`. */
|
|
46
|
+
gateExecutor?: GateExecutor;
|
|
43
47
|
forceFreeze?: boolean;
|
|
44
48
|
publishAt?: string;
|
|
45
49
|
/** RELEASE-BRANCH: version-release cuts release/<v> from main HEAD and bumps only the branch. */
|
|
@@ -104,22 +108,32 @@ export function releaseLoopConfig(configPath = getElanousConfigDirOverride() ? j
|
|
|
104
108
|
return raw.release?.loop ?? {};
|
|
105
109
|
}
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
/** GATE-HOST-EXECUTOR — the operator's explicit executor choice (`--gate-executor` / `--gate-host`); absent = pod. */
|
|
112
|
+
export interface GateExecutorRequest { executor?: string; host?: string }
|
|
113
|
+
|
|
114
|
+
export function buildReleaseRunInput(version: string, deps: UnattendedReleaseDeps = {}, cutCommit?: string, gate: GateExecutorRequest = {}): ReleaseRunInput {
|
|
108
115
|
const config = deps.config ?? releaseLoopConfig(deps.configPath);
|
|
116
|
+
if (gate.executor === undefined && gate.host !== undefined) throw new Error('--gate-host requires --gate-executor host');
|
|
117
|
+
const choice = gate.executor === undefined ? undefined
|
|
118
|
+
: checkGateExecutorChoice(gate.executor, gate.executor === 'host' ? gate.host ?? config.gateRemote : gate.host);
|
|
109
119
|
const pool = config.gatePodPool;
|
|
110
|
-
|
|
120
|
+
const hasPool = typeof pool === 'string' && !!pool.trim();
|
|
121
|
+
// The pod executor (the default) stays fail-closed on a missing pool; an explicit host executor does not need one.
|
|
122
|
+
if (choice?.executor !== 'host' && !hasPool) throw new Error('release.loop.gatePodPool is required before graph execution');
|
|
111
123
|
const previousVersion = latestPublishedPreviousVersion(baseVersion(version), deps.ledgerRoot);
|
|
112
124
|
return {
|
|
113
125
|
...config,
|
|
114
126
|
version, previousVersion,
|
|
115
127
|
...(cutCommit !== undefined ? { cutCommit } : {}),
|
|
116
|
-
gatePodPool: pool.trim(),
|
|
128
|
+
...(hasPool ? { gatePodPool: pool.trim() } : {}),
|
|
129
|
+
...(choice ? { gateExecutor: choice.executor } : {}),
|
|
130
|
+
...(choice?.host ? { gateRemote: choice.host } : {}),
|
|
117
131
|
};
|
|
118
132
|
}
|
|
119
133
|
|
|
120
134
|
/** Fail closed at the entry boundary, before any graph node can change a release. */
|
|
121
135
|
export async function runUnattendedRelease(
|
|
122
|
-
opts: { version: string; dryRun?: boolean; cutCommit?: string; forceFreeze?: boolean; mainCut?: boolean; prerelease?: PrereleaseKind; publishAt?: string },
|
|
136
|
+
opts: { version: string; dryRun?: boolean; cutCommit?: string; forceFreeze?: boolean; mainCut?: boolean; prerelease?: PrereleaseKind; publishAt?: string; gateExecutor?: string; gateHost?: string },
|
|
123
137
|
deps: UnattendedReleaseDeps = {},
|
|
124
138
|
): Promise<{ input: ReleaseRunInput; dryRun: boolean; state?: GraphRunState }> {
|
|
125
139
|
// RELEASE-BRANCH (10-06): the default cut is a release branch, so main keeps landing and the run no longer needs a
|
|
@@ -135,7 +149,7 @@ export async function runUnattendedRelease(
|
|
|
135
149
|
}
|
|
136
150
|
}
|
|
137
151
|
const version = resolveRunVersion(opts.version, opts.prerelease, deps);
|
|
138
|
-
const input = buildReleaseRunInput(version, deps, opts.cutCommit);
|
|
152
|
+
const input = buildReleaseRunInput(version, deps, opts.cutCommit, { executor: opts.gateExecutor, host: opts.gateHost });
|
|
139
153
|
if (opts.publishAt !== undefined) {
|
|
140
154
|
const invalid = publishAtError(opts.publishAt);
|
|
141
155
|
if (invalid) throw new Error(invalid);
|
|
@@ -143,7 +157,8 @@ export async function runUnattendedRelease(
|
|
|
143
157
|
}
|
|
144
158
|
if (opts.forceFreeze) input.forceFreeze = true;
|
|
145
159
|
if (branchCut) input.branchCut = true;
|
|
146
|
-
debug.log('release.run', 'input', { version, requested: opts.version, branchCut, prerelease: opts.prerelease ?? null, dryRun: opts.dryRun === true
|
|
160
|
+
debug.log('release.run', 'input', { version, requested: opts.version, branchCut, prerelease: opts.prerelease ?? null, dryRun: opts.dryRun === true,
|
|
161
|
+
...(input.gateExecutor ? { gateExecutor: input.gateExecutor, gateHost: input.gateExecutor === 'host' ? input.gateRemote ?? null : null } : {}) });
|
|
147
162
|
if (opts.dryRun) return { input, dryRun: true };
|
|
148
163
|
if (opts.prerelease) {
|
|
149
164
|
// A rehearsal neither judges nor carries the stable version's checklist cells.
|