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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** SUBSCRIPTION-EXHAUST-REROUTE (0.2.24 · P0) — Pod 구현 자식의 «기본» 모델을 codex 밖으로 뺀다.
|
|
2
|
+
*
|
|
3
|
+
* 🩸 10-11 실측(apiEq 24h): codex 소모의 ~95% 가 node-b Pod 구현 자식이었다($2,633 · 107런). 원인은
|
|
4
|
+
* 자식 모델을 안 준 Pod 발사가 `planPodProvider` 로 codex(gpt-6-sol)에 떨어진 것이다.
|
|
5
|
+
* ⭐ 결정 지점은 «호스트가 발사 인자를 만드는 곳»(`self orchestrate --substrate pod`) — 여기서 «자식 모델 없음 → 기본값»을
|
|
6
|
+
* `--child-llm-provider/--child-llm-model` 과 «같은 모양»으로 채운다. 그 뒤 경로(키 확인·passEnv·Job 인자)는 명시 발사와 같다.
|
|
7
|
+
* ⛔ 명시(`--child-llm-*`)가 있으면 손대지 않는다 · `--bench-arms`(팔마다 모델) · `--pod-account`(codex 계정 고정 = 사람의 선택)도 손대지 않는다.
|
|
8
|
+
* ⛔ 기본값이 «못 서면»(OpenRouter 키 없음) 종전 codex 경로로 간다 — 기본값 때문에 발사가 죽지 않는다(관측은 남긴다).
|
|
9
|
+
* config = `tools.selfImplement.podChildDefault`: `{ provider, model? }` · `'off'`(종전 codex 기본). 없으면 아래 상수. */
|
|
10
|
+
|
|
11
|
+
/** 대표 라우팅 «중» 시작 모델 — OpenRouter 키는 Pod 에 이미 있다(새 자격 0). */
|
|
12
|
+
export const POD_CHILD_DEFAULT = { provider: 'openrouter', model: 'openrouter/z-ai/glm-5.3' } as const;
|
|
13
|
+
|
|
14
|
+
export type PodChildDefaultDecision =
|
|
15
|
+
| { apply: true; provider: string; model?: string; source: 'config' | 'default' }
|
|
16
|
+
| { apply: false; reason: 'flag' | 'bench-arms' | 'pod-account' | 'config-off' | 'no-openrouter-key'; provider?: string; model?: string; source?: 'config' | 'default' };
|
|
17
|
+
|
|
18
|
+
function parseConfigValue(raw: unknown): { value: { provider: string; model?: string } | 'off'; source: 'config' } | { value: typeof POD_CHILD_DEFAULT; source: 'default'; invalid?: unknown } {
|
|
19
|
+
if (raw === undefined) return { value: POD_CHILD_DEFAULT, source: 'default' };
|
|
20
|
+
if (raw === 'off' || raw === false) return { value: 'off', source: 'config' };
|
|
21
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
22
|
+
const v = raw as Record<string, unknown>;
|
|
23
|
+
const provider = typeof v.provider === 'string' ? v.provider.trim() : '';
|
|
24
|
+
const model = typeof v.model === 'string' ? v.model.trim() : '';
|
|
25
|
+
if (provider) return { value: { provider, ...(model ? { model } : {}) }, source: 'config' };
|
|
26
|
+
}
|
|
27
|
+
return { value: POD_CHILD_DEFAULT, source: 'default', invalid: raw };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 순수 판정 — 「무엇을 보고 정했나」가 인자에 다 있다. */
|
|
31
|
+
export function resolvePodChildDefault(input: {
|
|
32
|
+
flags: { provider?: string; model?: string; effort?: string };
|
|
33
|
+
benchArms: boolean;
|
|
34
|
+
explicitPodAccount?: string;
|
|
35
|
+
config: unknown;
|
|
36
|
+
/** OpenRouter 키가 호스트에 «있나»(값은 안 본다) — openrouter 기본일 때만 묻는다. */
|
|
37
|
+
openrouterKeyPresent: () => boolean;
|
|
38
|
+
}): PodChildDefaultDecision & { invalidConfig?: unknown } {
|
|
39
|
+
if (input.flags.provider?.trim() || input.flags.model?.trim() || input.flags.effort?.trim()) return { apply: false, reason: 'flag' };
|
|
40
|
+
if (input.benchArms) return { apply: false, reason: 'bench-arms' };
|
|
41
|
+
if (input.explicitPodAccount?.trim()) return { apply: false, reason: 'pod-account' };
|
|
42
|
+
const parsed = parseConfigValue(input.config);
|
|
43
|
+
const invalid = 'invalid' in parsed ? { invalidConfig: parsed.invalid } : {};
|
|
44
|
+
if (parsed.value === 'off') return { apply: false, reason: 'config-off', source: 'config' };
|
|
45
|
+
const { provider, model } = parsed.value as { provider: string; model?: string };
|
|
46
|
+
if (provider === 'openrouter' && !input.openrouterKeyPresent()) {
|
|
47
|
+
return { apply: false, reason: 'no-openrouter-key', provider, ...(model ? { model } : {}), source: parsed.source, ...invalid };
|
|
48
|
+
}
|
|
49
|
+
return { apply: true, provider, ...(model ? { model } : {}), source: parsed.source, ...invalid };
|
|
50
|
+
}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* 목록 밖 provider 는 발사 «전»에 같은 문면으로 거부된다.
|
|
8
8
|
* ⛔ 이 모듈은 가볍게 둔다(무거운 import 0) — 하니스 CLI 가 Pod 표면 전체를 끌어오지 않게.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
// BEDROCK-PROVIDER ② (0.2.24) — bedrock 은 «이름 있는 AWS Secret» 이 클러스터에 있을 때만 뜬다(pod-bedrock-child.ts · 발사 전 거부).
|
|
11
|
+
// ZAI-POD-CHILD (0.2.24) — glm 은 Z.ai GLM Coding Plan(정액 구독) · «이름 있는 ZAI Secret» 이 클러스터에 있을 때만 뜬다(pod-zai-child.ts · 발사 전 거부 · 동시 상한 넘치면 정책대로).
|
|
12
|
+
export const POD_CHILD_PROVIDERS = ['openai-codex', 'grok', 'openrouter', 'anthropic', 'bedrock', 'glm'] as const;
|
|
11
13
|
export type PodChildProvider = typeof POD_CHILD_PROVIDERS[number];
|
|
12
14
|
|
|
13
15
|
/** 사람이 쓰는 별칭 → 정식 이름. */
|
|
@@ -27,3 +29,14 @@ export function podChildProviderRefusal(named: string | undefined): string | und
|
|
|
27
29
|
if (!id || podChildProviderOf(id)) return undefined;
|
|
28
30
|
return `pod: Pod 자식 provider 는 ${POD_CHILD_PROVIDERS.join('|')} 만 — 받음 ${id}`;
|
|
29
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* BEDROCK-POD-PROVIDER-DROP (0.2.24) — 발사(`index.ts`)가 고른 Pod provider 를 Pod 옵션(`provider` · `account`)으로 옮기는 «한 곳».
|
|
35
|
+
* 🩸 10-11: podBase 가 grok·openrouter·anthropic 만 손으로 나열해 `bedrock` 이 떨어졌다 — Pod 자식은 codex(team) 로 돌았다.
|
|
36
|
+
* ⭐ codex 가 아닌 provider 는 «그 이름»이 곧 account 다(Pod 표면 `plannedAccount` 와 같은 규칙) · codex 만 명시 계정 ?? team.
|
|
37
|
+
*/
|
|
38
|
+
export function podLaunchProviderOptions(podProvider: PodChildProvider, o: { explicitPodAccount?: string; grokApiKeyOptIn: boolean }): { account: string; provider: PodChildProvider; grokApiKeyOptIn?: boolean } {
|
|
39
|
+
// provider 는 여섯 전부 싣는다 — Pod 의 podChildLlmArgs 는 명시 발사에 provider 가 비면 거부한다(조용한 codex 금지).
|
|
40
|
+
if (podProvider === 'openai-codex') return { account: o.explicitPodAccount ?? 'team', provider: 'openai-codex' };
|
|
41
|
+
return { account: podProvider, provider: podProvider, ...(podProvider === 'grok' ? { grokApiKeyOptIn: o.grokApiKeyOptIn } : {}) };
|
|
42
|
+
}
|
|
@@ -371,6 +371,12 @@ export interface RunPodCommandOptions {
|
|
|
371
371
|
runId?: string;
|
|
372
372
|
name?: string;
|
|
373
373
|
pollMs?: number;
|
|
374
|
+
/**
|
|
375
|
+
* GATE-MULTI-HOST — throw once the Job's status has been unreadable (`kubectl get job` failing) this long, instead of
|
|
376
|
+
* polling forever: a pool member that died mid-Job (host off · tailnet drop) then frees its caller to place the work
|
|
377
|
+
* elsewhere. Omitted = poll without a bound (unchanged for every caller but the release gate).
|
|
378
|
+
*/
|
|
379
|
+
statusUnreadableMs?: number;
|
|
374
380
|
kubectl?: Kubectl;
|
|
375
381
|
/** A caller-owned scheduler is self-capped: acquires count only its own Jobs, never cluster occupancy (POOLGLOBAL-REG). */
|
|
376
382
|
poolScheduler?: PodPoolScheduler;
|
|
@@ -536,10 +542,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
536
542
|
throw new Error(applied.stderr.trim() || 'pod command: Job 적용 실패');
|
|
537
543
|
}
|
|
538
544
|
let state: 'complete' | 'failed' = 'failed';
|
|
545
|
+
let unreadableSince: number | null = null;
|
|
539
546
|
for (;;) {
|
|
540
547
|
const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
|
|
541
548
|
const finished = jobFinished(got.stdout);
|
|
542
549
|
if (finished) { state = finished; break; }
|
|
550
|
+
if (got.status !== 0 && options.statusUnreadableMs !== undefined) {
|
|
551
|
+
unreadableSince ??= Date.now();
|
|
552
|
+
if (Date.now() - unreadableSince >= options.statusUnreadableMs) {
|
|
553
|
+
log('pod.command', 'job-status-unreadable', { job: name, context, unreadableMs: Date.now() - unreadableSince, error: (got.stderr ?? '').trim().slice(0, 300) });
|
|
554
|
+
throw new Error(`pod command: Job 상태를 ${Math.round(options.statusUnreadableMs / 1000)}초 동안 못 읽었다(${context}) — ${(got.stderr ?? '').trim().split('\n').pop()?.slice(0, 200) ?? ''}`);
|
|
555
|
+
}
|
|
556
|
+
} else unreadableSince = null;
|
|
543
557
|
await sleep(options.pollMs ?? 15_000);
|
|
544
558
|
}
|
|
545
559
|
const logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
@@ -44,6 +44,81 @@ export function podTerminalRow(row: Record<string, unknown>): { stage: string; o
|
|
|
44
44
|
return nestedPodResult(row);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
|
|
48
|
+
|
|
49
|
+
export type PodExitClass = typeof POD_EXIT_CLASSES[number];
|
|
50
|
+
|
|
51
|
+
const isPodBookkeepingLine = (line: string): boolean =>
|
|
52
|
+
/^(?:ELANOUS_(?:MEM|RUN_LEDGER|USAGE_ROLLUP|POD_)|\[graph\] |\[ask\]\s+\d+\)\s)/u.test(line) || /^(?:at\s+\S|\.\.\.\s+\d+\s+more\b|cleanup\s+(?:complete|done|finished)\b)/iu.test(line);
|
|
53
|
+
|
|
54
|
+
const isPodErrorLine = (line: string): boolean =>
|
|
55
|
+
/\berror\b|\bfail(?:ed|ure)?\b|exception|fatal|denied|timed?\s*out|exceeded|overloaded|unavailable|exhausted|오류|실패/iu.test(line);
|
|
56
|
+
|
|
57
|
+
const normalizePodLogLine = (line: string): string => line.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240);
|
|
58
|
+
|
|
59
|
+
/** Classify a failed Pod using its terminal metadata and child output, without side effects. */
|
|
60
|
+
export function classifyPodExit(input: {
|
|
61
|
+
errorCode?: string | null;
|
|
62
|
+
containerReason?: string | null;
|
|
63
|
+
containerExitCode?: number | null;
|
|
64
|
+
jobReason?: string | null;
|
|
65
|
+
logs: string;
|
|
66
|
+
result?: Record<string, unknown> | null;
|
|
67
|
+
}): { class: PodExitClass; errorCode: string | null; containerReason: string | null; exitCode: number | null; jobReason: string | null; tail: string[] } {
|
|
68
|
+
const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
|
|
69
|
+
let terminalResult: { stage: string; ok: boolean; error?: string } | null = null;
|
|
70
|
+
for (const line of logLines) {
|
|
71
|
+
if (!line.startsWith('{')) continue;
|
|
72
|
+
let parsed: unknown;
|
|
73
|
+
try { parsed = JSON.parse(line); } catch { continue; }
|
|
74
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
75
|
+
terminalResult = podTerminalRow(parsed as Record<string, unknown>) ?? terminalResult;
|
|
76
|
+
}
|
|
77
|
+
if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
|
|
78
|
+
const hasResultLine = terminalResult !== null;
|
|
79
|
+
const askReprompt = logLines.some((line) =>
|
|
80
|
+
/^\[ask\](?!\s+\d+\)\s).*(?:implementation[_ -]?target|reprompt|re-prompt|되묻)/iu.test(line));
|
|
81
|
+
// 파싱되는 JSON 줄(진행·결과 행)은 오류 «줄»로 세지 않는다 — tail 과 같은 기준.
|
|
82
|
+
const isParsedJsonLine = (line: string): boolean => {
|
|
83
|
+
if (!line.startsWith('{')) return false;
|
|
84
|
+
try { const parsed = JSON.parse(line); return !!parsed && typeof parsed === 'object' && !Array.isArray(parsed); } catch { return false; }
|
|
85
|
+
};
|
|
86
|
+
const hasErrorLine = logLines.some((line) => !isPodBookkeepingLine(line) && !isParsedJsonLine(line) && isPodErrorLine(line));
|
|
87
|
+
let exitClass: PodExitClass;
|
|
88
|
+
if (input.errorCode === 'pod-secret') exitClass = 'pod-secret';
|
|
89
|
+
else if (input.jobReason === 'DeadlineExceeded') exitClass = 'deadline-exceeded';
|
|
90
|
+
else if (input.containerReason === 'OOMKilled') exitClass = 'oom-killed';
|
|
91
|
+
else if (input.containerExitCode === 7) exitClass = 'gh-login-failed';
|
|
92
|
+
else if (askReprompt) exitClass = 'ask-reprompt';
|
|
93
|
+
else if (terminalResult?.stage && terminalResult.ok === false) exitClass = 'child-unconverged';
|
|
94
|
+
else if (!hasResultLine && hasErrorLine) exitClass = 'child-error';
|
|
95
|
+
else if (!hasResultLine) exitClass = 'no-result-line';
|
|
96
|
+
else exitClass = 'unknown';
|
|
97
|
+
|
|
98
|
+
const tail = logLines.flatMap((line) => {
|
|
99
|
+
if (line.startsWith('{')) {
|
|
100
|
+
let parsed: unknown;
|
|
101
|
+
try { parsed = JSON.parse(line); } catch { parsed = undefined; }
|
|
102
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
103
|
+
const terminal = podTerminalRow(parsed as Record<string, unknown>);
|
|
104
|
+
if (terminal?.error) return terminal.error.split(/\r\n|\n|\r/u).map((part) => part.trim())
|
|
105
|
+
.filter((part) => part && !isPodBookkeepingLine(part)).map(normalizePodLogLine);
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return isPodBookkeepingLine(line) ? [] : [normalizePodLogLine(line)];
|
|
110
|
+
}).slice(-5);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
class: exitClass,
|
|
114
|
+
errorCode: input.errorCode ?? null,
|
|
115
|
+
containerReason: input.containerReason ?? null,
|
|
116
|
+
exitCode: input.containerExitCode ?? null,
|
|
117
|
+
jobReason: input.jobReason ?? null,
|
|
118
|
+
tail,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
47
122
|
/** Extract a human-readable reason from a failed child Pod without treating transfer markers as child errors. */
|
|
48
123
|
export function extractPodFailureReason(input: {
|
|
49
124
|
logs: string;
|
|
@@ -59,10 +134,8 @@ export function extractPodFailureReason(input: {
|
|
|
59
134
|
}
|
|
60
135
|
if (input.containerReason === 'OOMKilled') return 'OOMKilled: 컨테이너 메모리 한도 초과';
|
|
61
136
|
|
|
62
|
-
const isBookkeeping =
|
|
63
|
-
|
|
64
|
-
const isError = (line: string): boolean =>
|
|
65
|
-
/\berror\b|\bfail(?:ed|ure)?\b|exception|fatal|denied|timed?\s*out|exceeded|overloaded|unavailable|exhausted|오류|실패/iu.test(line);
|
|
137
|
+
const isBookkeeping = isPodBookkeepingLine;
|
|
138
|
+
const isError = isPodErrorLine;
|
|
66
139
|
const meaningful: Array<{ text: string; terminal: boolean }> = [];
|
|
67
140
|
for (const line of input.logs.split(/\r\n|\n|\r/u)) {
|
|
68
141
|
const trimmed = line.trim();
|
|
@@ -90,7 +163,7 @@ export function extractPodFailureReason(input: {
|
|
|
90
163
|
meaningful.push({ text: trimmed, terminal: false });
|
|
91
164
|
}
|
|
92
165
|
const errorLine = [...meaningful].reverse().find((line) => line.terminal || isError(line.text));
|
|
93
|
-
const reason = errorLine
|
|
166
|
+
const reason = errorLine ? normalizePodLogLine(errorLine.text) : undefined;
|
|
94
167
|
if (reason) return reason;
|
|
95
168
|
// POD-NORESULT: an unconverged child (exit 2 → BackoffLimitExceeded under backoffLimit 0) often leaves a result row
|
|
96
169
|
// with a stage and PR but no error text — report that instead of «unreadable».
|
|
@@ -101,5 +174,5 @@ export function extractPodFailureReason(input: {
|
|
|
101
174
|
return pr ? `수확 가능(${stage}) · ${pr}` : `수렴 못 함(단계 ${stage})`;
|
|
102
175
|
}
|
|
103
176
|
const why = input.logTailReason?.trim() || (input.logs.trim() ? '로그에 읽을 수 있는 오류 줄 없음' : '자식 로그 비어 있음');
|
|
104
|
-
return `사유 못 읽음: ${why
|
|
177
|
+
return `사유 못 읽음: ${normalizePodLogLine(why)}`;
|
|
105
178
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// REVIEW-ACP-POD (0.2.25 · REVIEW-ACP-DEFAULT ② 조각) — Pod 런이 낸 merge-ready PR 을 «호스트»가 Claude ACP(구독)로 다시 본다.
|
|
2
|
+
//
|
|
3
|
+
// S Pod 안 하니스 리뷰는 api 리뷰어(codex 기본 gpt-6-sol · OR Pod 는 glm 고정)로 돈다 — Pod 엔 Claude 구독도 정책 파일도 없어
|
|
4
|
+
// `roleLlm.reviewer = claude-acp`(운영에 이미 켜져 있다)가 Pod 안에선 «안 닿는다». 호스트 레인 런만 ACP 로 리뷰받는다.
|
|
5
|
+
// C Pod 가 호스트로 돌려보내는 유일한 문은 merge-ready → 호스트 재게이트 → 병합이다. 여기에 리뷰가 없다.
|
|
6
|
+
// Q Pod 런의 리뷰를 구독(ACP)으로 옮기려면 어디서 하나?
|
|
7
|
+
// A 호스트 병합 직전 한 자리에서, 하니스 레인과 «같은» 정책 행(`resolveSubscriptionReviewer`)·같은 가용성 검사
|
|
8
|
+
// (`subscriptionReviewerAvailability` — 구독 확인 · 상한 · 프록시)·같은 ACP 리뷰어(`makeAcpReviewLLM`)로 PR 을 본다.
|
|
9
|
+
// ⛔ 못 쓰면(설정 없음·구독 확인 실패·상한·프록시 없음·리뷰 미완) «refused» 로 돌려주고 호출자는 종전 길(Pod 리뷰 결과로 재게이트)을 그대로 간다.
|
|
10
|
+
// 조용히 다른 공급자로 새지 않는다 — 이 함수 안엔 api 폴백이 «없다».
|
|
11
|
+
// ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
|
|
12
|
+
// 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { debug } from '../../debug/log.js';
|
|
15
|
+
import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
|
|
16
|
+
import type { SubscriptionReviewerSpec } from '../../user-config.js';
|
|
17
|
+
import type { SubscriptionReviewerDeps, subscriptionReviewerSpawn } from '../../self-dev/review-provider-fallback.js';
|
|
18
|
+
|
|
19
|
+
export const POD_HOST_ACP_REVIEW_ENV = 'ELANOUS_POD_HOST_ACP_REVIEW';
|
|
20
|
+
|
|
21
|
+
export type PodHostAcpReviewEnable = { enabled: boolean; source: 'option' | 'env' | 'config' | 'default' };
|
|
22
|
+
|
|
23
|
+
/** 켜는 순서: 옵션 → env(`1`/`true` 켬 · `0`/`false` 끔) → config `llm.podHostAcpReview === true` → 꺼짐. 읽기 실패는 꺼짐(종전). */
|
|
24
|
+
export function resolvePodHostAcpReview(
|
|
25
|
+
option: boolean | undefined,
|
|
26
|
+
env: NodeJS.ProcessEnv,
|
|
27
|
+
readConfig: () => unknown,
|
|
28
|
+
): PodHostAcpReviewEnable {
|
|
29
|
+
if (typeof option === 'boolean') return { enabled: option, source: 'option' };
|
|
30
|
+
const raw = env[POD_HOST_ACP_REVIEW_ENV]?.trim().toLowerCase();
|
|
31
|
+
if (raw === '1' || raw === 'true') return { enabled: true, source: 'env' };
|
|
32
|
+
if (raw === '0' || raw === 'false') return { enabled: false, source: 'env' };
|
|
33
|
+
try {
|
|
34
|
+
const cfg = readConfig() as { llm?: { podHostAcpReview?: unknown } } | undefined;
|
|
35
|
+
if (cfg?.llm?.podHostAcpReview === true) return { enabled: true, source: 'config' };
|
|
36
|
+
} catch { /* 읽기 실패 = 꺼짐(종전 길) */ }
|
|
37
|
+
return { enabled: false, source: 'default' };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type PodHostAcpReviewOutcome =
|
|
41
|
+
| { status: 'clean'; mustFix: 0; shouldFix: number }
|
|
42
|
+
| { status: 'must-fix'; mustFix: number; findings: string[]; verdict: ReviewResult['verdict'] }
|
|
43
|
+
| { status: 'refused'; reason: string };
|
|
44
|
+
|
|
45
|
+
export interface PodHostAcpReviewDeps {
|
|
46
|
+
/** `{ spec, cap }` — 기본은 하니스 레인과 같은 정책 행(`resolveSubscriptionReviewer`). */
|
|
47
|
+
resolveReviewer?: () => { spec: SubscriptionReviewerSpec; cap: number } | undefined;
|
|
48
|
+
/** 구독·상한·프록시 확인 — 기본은 `subscriptionReviewerAvailability`. */
|
|
49
|
+
availability?: (spec: SubscriptionReviewerSpec, cap: number) => { spawn?: ReturnType<typeof subscriptionReviewerSpawn>; reason?: string };
|
|
50
|
+
subscriptionReviewerDeps?: SubscriptionReviewerDeps;
|
|
51
|
+
/** PR 머리 sha·제목·본문·diff. 기본은 `gh`. */
|
|
52
|
+
readPr?: (prNumber: number, repoRoot: string) => { headRefOid: string; title: string; body: string; diff: string } | undefined;
|
|
53
|
+
/** ACP 리뷰어(prompt→text). 기본은 `makeAcpReviewLLM({ backend: 'claude', backendSpec, env })`. */
|
|
54
|
+
makeAcpReviewLLM?: (spawn: ReturnType<typeof subscriptionReviewerSpawn>, repoRoot: string) => (prompt: string) => Promise<string>;
|
|
55
|
+
reviewPullRequest?: (input: { prDiff: string; phaseIntent: string }, llm: (prompt: string) => Promise<string>) => Promise<ReviewResult>;
|
|
56
|
+
env?: NodeJS.ProcessEnv;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
|
|
60
|
+
const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
|
|
61
|
+
if (view.status !== 0) return undefined;
|
|
62
|
+
const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
|
|
63
|
+
if (diff.status !== 0) return undefined;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(view.stdout) as { headRefOid?: unknown; title?: unknown; body?: unknown };
|
|
66
|
+
if (typeof parsed.headRefOid !== 'string') return undefined;
|
|
67
|
+
return { headRefOid: parsed.headRefOid, title: typeof parsed.title === 'string' ? parsed.title : '', body: typeof parsed.body === 'string' ? parsed.body : '', diff: diff.stdout };
|
|
68
|
+
} catch { return undefined; }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function refused(reason: string, data: Record<string, unknown>): PodHostAcpReviewOutcome {
|
|
72
|
+
try { debug.log('self-implement.pod', 'acp-review-refused', { ...data, reason }, { level: 'warn' }); } catch { /* 관측은 결과를 안 바꾼다 */ }
|
|
73
|
+
return { status: 'refused', reason };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Pod merge-ready PR 을 호스트 Claude ACP 로 리뷰한다. ⛔ 던지지 않는다 — 모든 실패는 `refused`(호출자는 종전 길). */
|
|
77
|
+
export async function runPodHostAcpReview(
|
|
78
|
+
input: { prNumber: number; headCommit: string; repoRoot: string; job?: string },
|
|
79
|
+
deps: PodHostAcpReviewDeps = {},
|
|
80
|
+
): Promise<PodHostAcpReviewOutcome> {
|
|
81
|
+
const obs = { job: input.job ?? null, pr: input.prNumber, head: input.headCommit };
|
|
82
|
+
try {
|
|
83
|
+
const env = deps.env ?? process.env;
|
|
84
|
+
// 지연 import — 이 문이 꺼진 런은 정책·설정을 안 읽는다.
|
|
85
|
+
const picked = deps.resolveReviewer ? deps.resolveReviewer() : await (async () => {
|
|
86
|
+
const { loadLlmPolicy, resolveSubscriptionReviewer } = await import('../../policy/llm-policy.js');
|
|
87
|
+
const { getUserConfig } = await import('../../user-config.js');
|
|
88
|
+
return resolveSubscriptionReviewer(loadLlmPolicy(), getUserConfig().roleLlm);
|
|
89
|
+
})();
|
|
90
|
+
if (!picked) return refused('no-subscription-reviewer', obs);
|
|
91
|
+
const avail = deps.availability
|
|
92
|
+
? deps.availability(picked.spec, picked.cap)
|
|
93
|
+
: (await import('../../self-dev/review-provider-fallback.js')).subscriptionReviewerAvailability(picked.spec, picked.cap, env, deps.subscriptionReviewerDeps);
|
|
94
|
+
if (!avail.spawn) return refused(`unavailable: ${avail.reason ?? 'unknown'}`, { ...obs, cap: picked.cap });
|
|
95
|
+
const pr = (deps.readPr ?? defaultReadPr)(input.prNumber, input.repoRoot);
|
|
96
|
+
if (!pr) return refused('pr-unreadable', obs);
|
|
97
|
+
if (pr.headRefOid.toLowerCase() !== input.headCommit.toLowerCase()) return refused('head-moved', { ...obs, prHead: pr.headRefOid });
|
|
98
|
+
if (!pr.diff.trim()) return refused('empty-diff', obs);
|
|
99
|
+
const llm = deps.makeAcpReviewLLM
|
|
100
|
+
? deps.makeAcpReviewLLM(avail.spawn, input.repoRoot)
|
|
101
|
+
: await (async () => {
|
|
102
|
+
const { makeAcpReviewLLM } = await import('../../agent-substrate/acp-reviewer.js');
|
|
103
|
+
const spawn = avail.spawn!;
|
|
104
|
+
return makeAcpReviewLLM({ cwd: input.repoRoot, backend: 'claude', backendSpec: spawn.backendSpec, env: spawn.env });
|
|
105
|
+
})();
|
|
106
|
+
const review = deps.reviewPullRequest ?? (await import('../../agent-substrate/pr-reviewer.js')).reviewPullRequest;
|
|
107
|
+
const phaseIntent = [`Pod 런 PR #${input.prNumber} 의 호스트 Claude ACP 리뷰(병합 전 관문).`, pr.title, pr.body.slice(0, 4000)].filter((s) => s.trim()).join('\n\n');
|
|
108
|
+
const rr = await review({ prDiff: pr.diff, phaseIntent }, llm);
|
|
109
|
+
// ⛔ reviewed=false(파싱 실패·ACP 오류를 리뷰어가 흡수) 는 «리뷰 완료»가 아니다 — 통과로 읽지 않는다.
|
|
110
|
+
if (!rr.reviewed) return refused('acp-review-not-completed', obs);
|
|
111
|
+
const mustFix = rr.mustFix.length;
|
|
112
|
+
if (rr.verdict === 'fail' || mustFix > 0) {
|
|
113
|
+
debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'must-fix', verdict: rr.verdict, mustFix, shouldFix: rr.shouldFix.length });
|
|
114
|
+
return { status: 'must-fix', mustFix, findings: rr.mustFix.slice(0, 10), verdict: rr.verdict };
|
|
115
|
+
}
|
|
116
|
+
debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'clean', verdict: rr.verdict, mustFix: 0, shouldFix: rr.shouldFix.length });
|
|
117
|
+
return { status: 'clean', mustFix: 0, shouldFix: rr.shouldFix.length };
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// 원문은 싣지 않는다 — 계정·프록시 문면이 섞일 수 있다(하니스 레인과 같은 규율).
|
|
120
|
+
return refused(/handshake timeout/i.test(error instanceof Error ? error.message : String(error)) ? 'acp-handshake-timeout' : 'acp-error', obs);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -40,6 +40,8 @@ export function leaseKubectl(args: readonly string[], input?: string): { status:
|
|
|
40
40
|
export interface PodLeaseMember {
|
|
41
41
|
context: string;
|
|
42
42
|
capacity: number;
|
|
43
|
+
/** POD-POOL-UNCAPPED-SPEC — `capacity` came from the spec default (`:N` absent), not from the operator. */
|
|
44
|
+
capacityDefaulted?: boolean;
|
|
43
45
|
running: number | null;
|
|
44
46
|
pending: number | null;
|
|
45
47
|
/** Job names of Pending harness Pods already included in pending (used to avoid counting the same Job's host lease twice). */
|
|
@@ -94,7 +96,12 @@ export interface PoolLeaseMeasure {
|
|
|
94
96
|
|
|
95
97
|
export interface PoolLeaseRecommendation {
|
|
96
98
|
recommended: number | null;
|
|
97
|
-
|
|
99
|
+
/**
|
|
100
|
+
* What stopped admission: `memory` = node memory headroom · `capacity` = the pool slot budget ·
|
|
101
|
+
* `pool-cap` = POD-POOL-UNCAPPED-SPEC — a member whose cap came from the spec default (`:N` absent → 2) is
|
|
102
|
+
* already at/over that cap, so the pool spec itself (not memory, not a configured budget) is the bound.
|
|
103
|
+
*/
|
|
104
|
+
limitedBy: 'capacity' | 'memory' | 'pool-cap' | null;
|
|
98
105
|
reason: string | null;
|
|
99
106
|
capacitySlots: number | null;
|
|
100
107
|
memorySlots: number | null;
|
|
@@ -392,7 +399,7 @@ export function measurePoolLease(members: readonly PodPoolMember[], deps: { kube
|
|
|
392
399
|
const kubectl = deps.kubectl ?? leaseKubectl;
|
|
393
400
|
return { members: members.map((member) => {
|
|
394
401
|
const base = ['--context', member.context, '--request-timeout=10s'];
|
|
395
|
-
const result: PodLeaseMember = { context: member.context, capacity: member.capacity, running: null, pending: null, unleasedRunning: null, memoryLimitBytes: null, allocatableMemoryBytes: null, allocatableCpuMillicores: null, availableMemoryByNodeBytes: null, reason: null };
|
|
402
|
+
const result: PodLeaseMember = { context: member.context, capacity: member.capacity, ...(member.capacityDefaulted ? { capacityDefaulted: true } : {}), running: null, pending: null, unleasedRunning: null, memoryLimitBytes: null, allocatableMemoryBytes: null, allocatableCpuMillicores: null, availableMemoryByNodeBytes: null, reason: null };
|
|
396
403
|
try {
|
|
397
404
|
const nodes = kubectl([...base, 'get', 'nodes', '-o', 'json']);
|
|
398
405
|
const jobs = kubectl([...base, '-n', 'elanous-test', 'get', 'jobs', '-l', 'elanous.substrate=pod', '-o', 'json']);
|
|
@@ -635,7 +642,7 @@ export function recommendConcurrency(measure: PoolLeaseMeasure, options: { capac
|
|
|
635
642
|
if (goalBytes === null || goalBytes <= 0) return { ...empty, reason: '측정 불가: perGoalMemory' };
|
|
636
643
|
const admission = admissionByUsage(measure, goalBytes, options.perGoalMemory !== undefined);
|
|
637
644
|
if (!measure.members.length || measure.members.some((m) => m.running === null || m.pending === null || m.unleasedRunning === null || m.allocatableMemoryBytes === null || m.memoryLimitBytes === null || m.allocatableCpuMillicores === null || m.availableMemoryByNodeBytes === null)) {
|
|
638
|
-
debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended: null, limitedBy: null });
|
|
645
|
+
debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended: null, limitedBy: null, capacity: options.capacity, capacitySlots: null, memorySlots: null, running: null, pending: null });
|
|
639
646
|
return { ...empty, reason: `측정 불가: cluster${measure.members.map((m) => m.reason ? ` ${m.context}: ${m.reason}` : '').join('')}` };
|
|
640
647
|
}
|
|
641
648
|
if (!Number.isSafeInteger(options.capacity) || options.capacity < 0) return { ...empty, reason: '측정 불가: capacity' };
|
|
@@ -680,9 +687,14 @@ export function recommendConcurrency(measure: PoolLeaseMeasure, options: { capac
|
|
|
680
687
|
Math.floor((m.allocatableMemoryBytes! - m.memoryLimitBytes!) / liteBytes))), 0);
|
|
681
688
|
const memoryBound = Math.min(memorySlots, placeableSlots);
|
|
682
689
|
const recommended = Math.max(0, Math.min(capacitySlots, memoryBound) - eligibleUnleasedRunning);
|
|
683
|
-
|
|
690
|
+
// POD-POOL-UNCAPPED-SPEC — `capacity ≤ occupied` on a member whose cap is the spec default (`:N` absent → 2) means
|
|
691
|
+
// the «uncapped» pool spec is what admits nothing. Name it `pool-cap`, not the generic `capacity`, so a launch that
|
|
692
|
+
// sits on `recommended=0` says in its first admit line that the pool spec never declared a cap of its own.
|
|
693
|
+
const defaultCapFull = capacitySlots <= 0 && measure.members.some((m) => m.capacityDefaulted === true
|
|
694
|
+
&& m.reason !== 'dns' && m.running !== null && m.pending !== null && m.running + m.pending >= m.capacity);
|
|
695
|
+
const limitedBy: PoolLeaseRecommendation['limitedBy'] = memoryBound < capacitySlots ? 'memory' : defaultCapFull ? 'pool-cap' : 'capacity';
|
|
684
696
|
if (unleasedRunning > 0) debug.log('pod-lease', 'unleased', { unleasedRunning, running, recommended });
|
|
685
|
-
debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended, limitedBy });
|
|
697
|
+
debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended, limitedBy, capacity: options.capacity, capacitySlots, memorySlots, running, pending });
|
|
686
698
|
return { recommended, limitedBy, reason: measure.members.some((m) => m.reason === 'dns') ? 'dns' : null, capacitySlots, memorySlots, liteMemorySlots, placeableSlots, accountSlots, running, pending, pendingJobs, unleasedRunning, admission };
|
|
687
699
|
}
|
|
688
700
|
|
|
@@ -14,6 +14,8 @@ type ParseResult = Ledger[] | { error: Incomplete[]; ledgers: Ledger[] };
|
|
|
14
14
|
const NON_PROGRESS_EVENTS = new Set(['progress-delivery-outcome']);
|
|
15
15
|
const REEMIT_EXCLUDED_PREFIX = 'progress-delivery';
|
|
16
16
|
type Emit = (category: string, event: string, data: Record<string, unknown>) => void;
|
|
17
|
+
/** Heal-loop starter seam — defaults to the real `startHealLoop` inside `recordFailureEvent`. */
|
|
18
|
+
type StartHealLoop = Parameters<typeof recordFailureEvent>[2];
|
|
17
19
|
|
|
18
20
|
/** Reemit only complete ledger records; offsets name the first byte of each line in the Pod ledger. */
|
|
19
21
|
function reemitLedgerLines(jsonl: string, runId: string, startOffset: number, emit: Emit): number {
|
|
@@ -93,7 +95,7 @@ export function parsePodLedgerChunks(logs: string): ParseResult {
|
|
|
93
95
|
return error.length ? { error, ledgers } : ledgers;
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
|
|
98
|
+
function intakeCollectedFailure(runId: string, dir: string, log: Emit, startHealLoop?: StartHealLoop): void {
|
|
97
99
|
let ledger: ReturnType<typeof loadRunLedger>;
|
|
98
100
|
try { ledger = loadRunLedger(runId, dir); }
|
|
99
101
|
catch { return; }
|
|
@@ -104,8 +106,10 @@ function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
|
|
|
104
106
|
if (terminal?.data.runStatus !== 'failed' || !terminal.timestamp || !Number.isFinite(Date.parse(terminal.timestamp))
|
|
105
107
|
|| ledger.slice(terminalIndex + 1).some(entry => !TRAILING_BOOKKEEPING_EVENTS.includes(entry.event as typeof TRAILING_BOOKKEEPING_EVENTS[number]))) return;
|
|
106
108
|
try {
|
|
109
|
+
// POD-HEAL-HOST — the recovered Pod failure is recorded into the HOST universe (`dirname(dir)`),
|
|
110
|
+
// so the host heal loop triages it (harvest + narrowed relaunch) instead of dying inside the Pod.
|
|
107
111
|
recordFailureEvent({ source: 'harness-run', kind: 'pod-run', ref: runId,
|
|
108
|
-
summary: `Pod run ${runId} failed`, at: terminal.timestamp }, dirname(dir));
|
|
112
|
+
summary: `Pod run ${runId} failed`, at: terminal.timestamp }, dirname(dir), startHealLoop);
|
|
109
113
|
} catch (error) {
|
|
110
114
|
log('self-implement.pod', 'heal-intake-failed', { runId, reason: error instanceof Error ? error.message : String(error) });
|
|
111
115
|
}
|
|
@@ -115,11 +119,13 @@ function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
|
|
|
115
119
|
* except a ledger that THIS run's live follower created (`replace`): that one is a partial copy and the final is complete. */
|
|
116
120
|
export function collectPodLedgers(
|
|
117
121
|
logs: string,
|
|
118
|
-
{ dir = runLedgerDir(), log = defaultPodReemit(), emit = defaultPodReemit(), replace = new Set<string>() }: {
|
|
122
|
+
{ dir = runLedgerDir(), log = defaultPodReemit(), emit = defaultPodReemit(), replace = new Set<string>(), startHealLoop }: {
|
|
119
123
|
dir?: string;
|
|
120
124
|
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
121
125
|
emit?: Emit;
|
|
122
126
|
replace?: ReadonlySet<string>;
|
|
127
|
+
/** Which starter receives a recovered Pod failure (POD-HEAL-HOST 판정선 measurement); default = real `startHealLoop`. */
|
|
128
|
+
startHealLoop?: StartHealLoop;
|
|
123
129
|
} = {},
|
|
124
130
|
): void {
|
|
125
131
|
const parsed = parsePodLedgerChunks(logs);
|
|
@@ -136,7 +142,7 @@ export function collectPodLedgers(
|
|
|
136
142
|
const newLines = Buffer.from(jsonl).subarray(previousBytes).toString('utf8');
|
|
137
143
|
reemitLedgerLines(newLines, runId, previousBytes, emit);
|
|
138
144
|
log('self-implement.pod', 'ledger-collected', { runId, lines: jsonl.split('\n').filter(Boolean).length, bytes: Buffer.byteLength(jsonl) });
|
|
139
|
-
intakeCollectedFailure(runId, dir, log);
|
|
145
|
+
intakeCollectedFailure(runId, dir, log, startHealLoop);
|
|
140
146
|
} catch (e) {
|
|
141
147
|
if ((e as NodeJS.ErrnoException).code === 'EEXIST') {
|
|
142
148
|
// A reattached Job may have already delivered this exact complete snapshot.
|
|
@@ -145,7 +151,7 @@ export function collectPodLedgers(
|
|
|
145
151
|
const existing = readFileSync(runLedgerPath(runId, dir));
|
|
146
152
|
const identical = existing.equals(Buffer.from(jsonl));
|
|
147
153
|
log('self-implement.pod', identical ? 'ledger-collect-already-complete' : 'ledger-collect-skipped', { runId, reason: 'exists' });
|
|
148
|
-
if (identical) intakeCollectedFailure(runId, dir, log);
|
|
154
|
+
if (identical) intakeCollectedFailure(runId, dir, log, startHealLoop);
|
|
149
155
|
} catch (readError) {
|
|
150
156
|
log('self-implement.pod', 'ledger-collect-incomplete', { runId, reason: readError instanceof Error ? readError.message : String(readError) });
|
|
151
157
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BUDGET_SNAPSHOT_ENV } from '../../execution-loop/launch-gate.js';
|
|
2
|
+
|
|
3
|
+
// Preserve the manifest contract except for two values generated per launch.
|
|
4
|
+
export function stablePodManifestText(applied: Array<Record<string, any>>): string {
|
|
5
|
+
const manifests = structuredClone(applied.filter((entry) => entry.kind === 'Job' || entry.kind === 'Secret'));
|
|
6
|
+
let snapshots = 0;
|
|
7
|
+
for (const manifest of manifests) {
|
|
8
|
+
if (manifest.kind !== 'Job') continue;
|
|
9
|
+
for (const container of manifest.spec?.template?.spec?.containers ?? []) {
|
|
10
|
+
for (const entry of container.env ?? []) {
|
|
11
|
+
if (entry.name !== BUDGET_SNAPSHOT_ENV) continue;
|
|
12
|
+
snapshots++;
|
|
13
|
+
// Keep every original byte except this one volatile numeric value.
|
|
14
|
+
const measuredAt = /("measuredAt"\s*:\s*)\d+/g;
|
|
15
|
+
const matches = [...entry.value.matchAll(measuredAt)];
|
|
16
|
+
if (matches.length !== 1) throw new Error('budget snapshot must have exactly one numeric measuredAt');
|
|
17
|
+
entry.value = entry.value.replace(measuredAt, (_match: string, prefix: string) => `${prefix}0`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (snapshots === 0) throw new Error('manifest comparison requires a budget snapshot');
|
|
22
|
+
return JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>');
|
|
23
|
+
}
|
|
@@ -31,6 +31,11 @@ export interface PodPoolMember {
|
|
|
31
31
|
/** 원격 클러스터가 도는 기계(ssh 호스트). 없으면 이 기계의 docker 에 있다. */
|
|
32
32
|
readonly sshHost?: string;
|
|
33
33
|
readonly capacity: number;
|
|
34
|
+
/**
|
|
35
|
+
* POD-POOL-UNCAPPED-SPEC — 스펙에 `:N` 이 없어서 `capacity` 가 운영자 숫자가 아니라 `POD_POOL_DEFAULT_CAPACITY` 다.
|
|
36
|
+
* 발사 허가는 이 표시로 «풀 기본 상한이 막았다»(`limitedBy=pool-cap`)를 일반 `capacity` 와 갈라 말한다.
|
|
37
|
+
*/
|
|
38
|
+
readonly capacityDefaulted?: boolean;
|
|
34
39
|
/** k3d 클러스터 이름(이미지 반입용). 기본: 컨텍스트가 `k3d-<이름>` 이면 그 이름, 원격이면 `elanous-pool`. */
|
|
35
40
|
readonly k3dCluster: string;
|
|
36
41
|
/** 노드 로컬 레지스트리의 이미지(커밋 태그) — 있으면 Pod 가 이것을 pull 한다(델타 · 대표 2026-09-26). 없으면 반입된 로컬 이미지. */
|
|
@@ -115,18 +120,23 @@ export function remoteImageSkillsDigest(member: PodPoolMember, image: string, ru
|
|
|
115
120
|
|
|
116
121
|
const MEMBER = /^([A-Za-z0-9][A-Za-z0-9._-]*)(?:@([A-Za-z0-9][A-Za-z0-9._-]*))?(?::(\d+))?(?:#(k3d-[A-Za-z0-9][A-Za-z0-9._-]*):([1-9]\d{0,4}))?$/u;
|
|
117
122
|
|
|
123
|
+
/** 상한 없는 풀 스펙(`:N` 없음)의 노드 상한 — 파일 머리 주석의 «기본 2» 정본(POD-POOL-UNCAPPED-SPEC). */
|
|
124
|
+
export const POD_POOL_DEFAULT_CAPACITY = 2;
|
|
125
|
+
|
|
118
126
|
export function parsePodPool(spec: string): PodPoolMember[] {
|
|
119
127
|
const members = spec.split(',').map((s) => s.trim()).filter(Boolean).map((part) => {
|
|
120
128
|
const m = MEMBER.exec(part);
|
|
121
129
|
if (!m) throw new Error(`--pod-pool: 못 읽는 노드 「${part}」 — 형식 컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]`);
|
|
122
|
-
|
|
130
|
+
// `:N` 이 없으면 «상한 없음»이 아니라 기본 상한 2 다 — 그 사실(`capacityDefaulted`)을 멤버에 남긴다.
|
|
131
|
+
const capacityDefaulted = m[3] === undefined;
|
|
132
|
+
const capacity = capacityDefaulted ? POD_POOL_DEFAULT_CAPACITY : Number(m[3]);
|
|
123
133
|
// POOL-LITE (10-07): `:0` means «this member is off» — a `node-c:0` entry once threw here and broke every launch.
|
|
124
134
|
// It is dropped below (never chosen); only a pool with no live member left is an error.
|
|
125
135
|
if (!Number.isInteger(capacity) || capacity < 0) throw new Error(`--pod-pool: 상한은 1 이상 — 「${part}」`);
|
|
126
136
|
if (m[5] && Number(m[5]) > 65535) throw new Error(`--pod-pool: 레지스트리 포트는 65535 이하 — 「${part}」`);
|
|
127
137
|
const context = m[1]!;
|
|
128
138
|
const k3dCluster = context.startsWith('k3d-') ? context.slice(4) : 'elanous-pool';
|
|
129
|
-
return { context, capacity, k3dCluster, ...(m[2] ? { sshHost: m[2] } : {}), ...(m[4] ? { registry: `${m[4]}:${m[5]}` } : {}) };
|
|
139
|
+
return { context, capacity, ...(capacityDefaulted ? { capacityDefaulted: true } : {}), k3dCluster, ...(m[2] ? { sshHost: m[2] } : {}), ...(m[4] ? { registry: `${m[4]}:${m[5]}` } : {}) };
|
|
130
140
|
});
|
|
131
141
|
if (members.length === 0) throw new Error('--pod-pool: 노드가 없다');
|
|
132
142
|
if (new Set(members.map((m) => m.context)).size !== members.length) throw new Error('--pod-pool: 컨텍스트가 겹친다');
|
|
@@ -144,6 +154,59 @@ export function parsePodPool(spec: string): PodPoolMember[] {
|
|
|
144
154
|
*/
|
|
145
155
|
export type PodPlacementKind = 'lite' | 'standard';
|
|
146
156
|
|
|
157
|
+
/** Identity carried by a launched pool Job and its Pod; absent source fields stay absent. */
|
|
158
|
+
export interface PodWorkIdentity {
|
|
159
|
+
ownerKind?: 'seat' | 'steward' | 'orchestrator' | 'external';
|
|
160
|
+
ownerId?: string;
|
|
161
|
+
taskCard?: string;
|
|
162
|
+
slotId?: string;
|
|
163
|
+
work?: 'harness' | 'authoring' | 'lite';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Kubernetes label values cannot exceed 63 characters or contain arbitrary card/owner text. */
|
|
167
|
+
export function podWorkLabels(identity: PodWorkIdentity): Record<string, string> {
|
|
168
|
+
const value = (raw: string | undefined): string | undefined => {
|
|
169
|
+
const cleaned = (raw ?? '').replace(/[^A-Za-z0-9._-]+/g, '-').slice(0, 63).replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, '');
|
|
170
|
+
return cleaned || undefined;
|
|
171
|
+
};
|
|
172
|
+
const ownerId = identity.ownerId && value(identity.ownerId) === identity.ownerId ? identity.ownerId : undefined;
|
|
173
|
+
const taskCard = identity.taskCard && value(identity.taskCard) === identity.taskCard ? identity.taskCard : undefined;
|
|
174
|
+
const slotId = identity.slotId && value(identity.slotId) === identity.slotId ? identity.slotId : undefined;
|
|
175
|
+
return {
|
|
176
|
+
...(identity.ownerKind && ownerId ? { 'elanous.owner-kind': identity.ownerKind, 'elanous.owner-id': ownerId } : {}),
|
|
177
|
+
...(taskCard ? { 'elanous.task-card': taskCard } : {}),
|
|
178
|
+
...(slotId ? { 'elanous.checklist': slotId } : {}),
|
|
179
|
+
...(identity.work ? { 'elanous.work': identity.work } : {}),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Minih standard-Job policy, independent of the configured pool member capacity. Not wired into allocation. */
|
|
184
|
+
export type MinihLocation = 'home' | 'external';
|
|
185
|
+
|
|
186
|
+
export function minihStandardCapacity(location: MinihLocation): number {
|
|
187
|
+
return location === 'home' ? 1 : 2;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** A drain withholds new slots until occupancy falls to the target; it never evicts Running Pods. */
|
|
191
|
+
export function decideMinihDrain(location: MinihLocation, runningPods: number, pendingPods = 0): {
|
|
192
|
+
capacity: number;
|
|
193
|
+
runningPods: number;
|
|
194
|
+
drainNewAdmissions: boolean;
|
|
195
|
+
availableSlots: number;
|
|
196
|
+
} {
|
|
197
|
+
if (![runningPods, pendingPods].every((count) => Number.isSafeInteger(count) && count >= 0)) {
|
|
198
|
+
throw new RangeError('node-c occupancy must be non-negative whole Pods');
|
|
199
|
+
}
|
|
200
|
+
const capacity = minihStandardCapacity(location);
|
|
201
|
+
const occupied = runningPods + pendingPods;
|
|
202
|
+
return {
|
|
203
|
+
capacity,
|
|
204
|
+
runningPods,
|
|
205
|
+
drainNewAdmissions: occupied > capacity,
|
|
206
|
+
availableSlots: Math.max(0, capacity - occupied),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
147
210
|
export interface PodPlacement {
|
|
148
211
|
readonly member: string;
|
|
149
212
|
readonly kind: PodPlacementKind | null;
|
|
@@ -642,7 +705,11 @@ export function syncPoolImage(member: PodPoolMember, image: string, localCommit:
|
|
|
642
705
|
// The import phase gets its own stale window (the lock file's age restarts here).
|
|
643
706
|
try { const now = new Date(); utimesSync(lockPath, now, now); } catch { /* lock gone · finish anyway */ }
|
|
644
707
|
const imp = remote(host, `k3d image import ${image} -c ${member.k3dCluster}`);
|
|
645
|
-
|
|
708
|
+
// As in build.sh, only tools-node cleanup errors may follow a nonzero import rc.
|
|
709
|
+
// Ignore informational lines, but reject any other failure line (including WARN and untagged output).
|
|
710
|
+
const failures = imp.stderr.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !/^(?:INFO|DEBU|DEBUG|TRAC|TRACE)(?:\[|\s|:|$)/.test(line));
|
|
711
|
+
const cleanup = /^(?:(?:ERROR|ERRO|FATAL|FATA|WARNING|WARN|INFO)(?:\[[^\]]*\])?:?\s*)?(?:failed to import images: )?failed to delete tools node '[^']*': (?:Error response from daemon: )?(?:No such container: [A-Za-z0-9_.-]+|removal of container [A-Za-z0-9_.-]+ is already in progress)$/i;
|
|
712
|
+
if (imp.status !== 0 && (failures.length === 0 || !failures.every((line) => cleanup.test(line)))) return { ok: false, action: 'failed', detail: `k3d import rc=${imp.status}: ${imp.stderr.slice(-300)}` };
|
|
646
713
|
const after = remoteImageCommit(member, image, remote);
|
|
647
714
|
return after && (!localCommit || after === localCommit)
|
|
648
715
|
? { ok: true, action: 'shipped', detail: `${labelNow?.slice(0, 12) ?? '없음'} → ${after.slice(0, 12)}` }
|
|
@@ -736,7 +803,9 @@ export async function syncPoolImages(members: readonly PodPoolMember[], image: s
|
|
|
736
803
|
const run = deps.run ?? defaultRemoteRun;
|
|
737
804
|
const script = deps.buildScript === undefined ? podImageBuildScript() : deps.buildScript;
|
|
738
805
|
const remoteBuild = deps.remoteBuild ?? (script ? defaultRemoteBuild(script, image) : null);
|
|
739
|
-
|
|
806
|
+
// The registry-less build fallback below calls this ship path, including its remote import result check.
|
|
807
|
+
const ship = deps.ship ?? ((m: PodPoolMember, img: string, commit: string | null, remote: RemoteRun) =>
|
|
808
|
+
syncPoolImage(m, img, commit, { run: remote, inspect: deps.inspect, transfer: deps.transfer }));
|
|
740
809
|
const results = new Map<string, PoolImageSync>();
|
|
741
810
|
// pack 한 번 ⊕ 나눠 쓰기 — 원격 멤버가 둘 이상일 때만(하나뿐이면 종전대로 build.sh 가 스스로 pack 한다).
|
|
742
811
|
// 주입된 remoteBuild(시험)에는 진짜 pack 을 붙이지 않는다 — pack 도 주입해야 쓴다.
|