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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// ⛔ 토큰 «값»은 어디에도 출력하지 않는다 — accountId 앞 8자만(R-LLM2).
|
|
7
7
|
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import { mkdirSync, openSync, closeSync, unlinkSync, readFileSync, writeFileSync, statSync } from 'node:fs';
|
|
9
|
+
import { mkdirSync, openSync, closeSync, unlinkSync, readFileSync, writeFileSync, statSync, renameSync } from 'node:fs';
|
|
10
10
|
import { dirname, join, resolve } from 'node:path';
|
|
11
11
|
import { consumeCodexResetCredits, listCodexResetCredits } from '../budget/codex-reset-credits.js';
|
|
12
12
|
import { codexCredentialRoot, readAvailabilityState, writeAvailabilityState } from '../budget/codex-reset-credit-state.js';
|
|
@@ -20,16 +20,16 @@ import { creditPaceStatus } from '../budget/codex-credit-pace.js';
|
|
|
20
20
|
import { loadLlmPolicy } from '../policy/llm-policy.js';
|
|
21
21
|
import { getUserConfig } from '../user-config.js';
|
|
22
22
|
import {
|
|
23
|
-
decideCodexRotation, observeRotation, applyRotation, readCodexAccountRotationConfig, rotatedChildEnv,
|
|
23
|
+
decideCodexRotation, observeRotation, applyRotation, readCodexAccountRotationConfig, rotatedChildEnv, creditCandidatesByBalance, CODEX_CREDIT_RESERVE_DEFAULT,
|
|
24
24
|
codexAccountThresholdPercent,
|
|
25
25
|
type RotationCandidate,
|
|
26
26
|
} from './codex-account-rotation.js';
|
|
27
|
-
import { codexPolicyAllowsCredits, codexPolicyAllowsFallback, resolveCodexQuotaPolicy, type CodexQuotaPolicy, type ResolvedCodexQuotaPolicy } from './codex-quota-policy.js';
|
|
27
|
+
import { codexPolicyAllowsCredits, codexPolicyAllowsFallback, resolveCodexQuotaPolicy, type CodexQuotaPolicy, type CodexQuotaPolicyFileValue, type ResolvedCodexQuotaPolicy } from './codex-quota-policy.js';
|
|
28
28
|
import { emitDecision } from '../live/detail-switch.js';
|
|
29
29
|
import { debug } from '../debug/log.js';
|
|
30
30
|
import {
|
|
31
31
|
decideFallback, normalizeFallbackChain, grokQuotaFromUsageSnapshot,
|
|
32
|
-
type FallbackDecision, type FallbackInput, type RotationOutcome,
|
|
32
|
+
type FallbackDecision, type FallbackInput, type FallbackStep, type RotationOutcome,
|
|
33
33
|
} from './fallback-chain.js';
|
|
34
34
|
import { resolveGrokCredential } from '../grok/credential.js';
|
|
35
35
|
import { getOpenRouterApiKey } from '../config.js';
|
|
@@ -52,7 +52,7 @@ export function _setCodexAccountOutboundSenderForTesting(sender: CodexAccountOut
|
|
|
52
52
|
/** ⛔⭐ 정적 import 로 읽는다 — 종전 `require()` 는 ESM 에서 «정의되지 않을 수 있고», 그러면
|
|
53
53
|
* fail-soft 가 삼켜 ***config false 가 영영 무시된다***(리뷰 should-fix: 노브가 no-op 이 된다).
|
|
54
54
|
* ⚠️ 순환 없음을 확인했다 — user-config 는 oauth 를 안 끌어온다. */
|
|
55
|
-
type RotationConfig = { llm?: { codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexResetAutoConsumePerDay?: number; codexQuotaPolicy?: unknown; fallbackChain?: unknown; openrouter?: { fallbackModel?: unknown } } };
|
|
55
|
+
type RotationConfig = { llm?: { codexCreditReserve?: unknown; codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexResetAutoConsumePerDay?: number; codexQuotaPolicy?: unknown; fallbackChain?: unknown; openrouter?: { fallbackModel?: unknown } } };
|
|
56
56
|
|
|
57
57
|
function readUserConfig(): RotationConfig {
|
|
58
58
|
return getUserConfig();
|
|
@@ -238,11 +238,21 @@ function pinnedAccountExhausted(home: string, accountName: string): boolean {
|
|
|
238
238
|
|
|
239
239
|
/** codex 한도 정책(`llm.codexQuotaPolicy` · 옛 `codexCreditsAllowed`) — 못 읽으면 `fallback`(크레딧은 돈이라 fail-closed). */
|
|
240
240
|
export function codexQuotaPolicyFromConfig(): CodexQuotaPolicy {
|
|
241
|
-
try { return resolveCodexQuotaPolicy(configReader().llm).policy; } catch { return 'fallback'; }
|
|
241
|
+
try { return resolveCodexQuotaPolicy(configReader().llm, codexQuotaPolicyFileValue()).policy; } catch { return 'fallback'; }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** `policy/llm.yaml` 의 `credits.codex` — 파일 출처일 때만 값을 낸다(없거나 다른 출처면 undefined). 파일이 깨졌거나 못 읽으면 `unreadable`. */
|
|
245
|
+
function codexQuotaPolicyFileValue(): CodexQuotaPolicyFileValue | undefined {
|
|
246
|
+
try {
|
|
247
|
+
const loaded = loadLlmPolicy({ legacyConfig: {} });
|
|
248
|
+
if (!loaded.filePresent) return undefined;
|
|
249
|
+
if (!loaded.valid) return 'unreadable';
|
|
250
|
+
return loaded.sources['credits.codex'] === 'file' ? loaded.policy.credits.codex : undefined;
|
|
251
|
+
} catch { return 'unreadable'; }
|
|
242
252
|
}
|
|
243
253
|
|
|
244
254
|
function inspectedQuotaPolicy(): ResolvedCodexQuotaPolicy {
|
|
245
|
-
try { return resolveCodexQuotaPolicy(configReader().llm); } catch { return { policy: 'fallback', source: 'default' }; }
|
|
255
|
+
try { return resolveCodexQuotaPolicy(configReader().llm, codexQuotaPolicyFileValue()); } catch { return { policy: 'fallback', source: 'default' }; }
|
|
246
256
|
}
|
|
247
257
|
|
|
248
258
|
/** 지금 계정의 크레딧 신호 — 판정 입력 두 칸. 신호를 이 계정에 귀속할 수 없으면 비운다(모른다). */
|
|
@@ -259,6 +269,64 @@ function codexCreditsAllowedFromConfig(): boolean {
|
|
|
259
269
|
return codexPolicyAllowsCredits(codexQuotaPolicyFromConfig());
|
|
260
270
|
}
|
|
261
271
|
|
|
272
|
+
/** SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분 기본. 10-11 운영 실측: 잔액 29,401 · 하루 소모 25,132 → 2,000 ≈ 하루 소모의 8%
|
|
273
|
+
* (폴백이 서는 동안 계정을 0 으로 만들지 않는 몫). `llm.codexCreditReserve` 로 바꾼다(0 = 잔액 0 일 때만 넘김). */
|
|
274
|
+
export const DEFAULT_CODEX_CREDIT_RESERVE = CODEX_CREDIT_RESERVE_DEFAULT;
|
|
275
|
+
/** 예비분 넘김의 OpenRouter 모델(설정 `llm.openrouter.fallbackModel` 이 없을 때) — 대표 라우팅 «중» 시작 모델. */
|
|
276
|
+
export const CREDIT_RESERVE_OPENROUTER_MODEL = 'openrouter/z-ai/glm-5.3';
|
|
277
|
+
|
|
278
|
+
/** `llm.codexCreditReserve` — 유효하지 않거나 못 읽으면 기본(크레딧은 돈이라 예비분을 지킨다). */
|
|
279
|
+
export function codexCreditReserveFromConfig(): number {
|
|
280
|
+
try {
|
|
281
|
+
const raw = configReader().llm?.codexCreditReserve;
|
|
282
|
+
return typeof raw === 'number' && Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_CODEX_CREDIT_RESERVE;
|
|
283
|
+
} catch { return DEFAULT_CODEX_CREDIT_RESERVE; }
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** grok 자격 «존재» 판독 — 테스트 격리 심(실 자격을 안 읽게). */
|
|
287
|
+
let grokCredentialPresent: () => boolean = () => resolveGrokCredential() !== null;
|
|
288
|
+
export function _setGrokCredentialPresentForTesting(fn: (() => boolean) | null): void {
|
|
289
|
+
grokCredentialPresent = fn ?? (() => resolveGrokCredential() !== null);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** 회전 판정이 쓸 크레딧 허가와 그 출처.
|
|
293
|
+
* - `policy` 정책이 credits(옛 codexCreditsAllowed=true) — 종전 그대로.
|
|
294
|
+
* - `chain-step` CODEX-CREDITS-STEP: 정책은 fallback 이지만 체인이 `codex-credits` 칸에 «닿는다»
|
|
295
|
+
* (앞 칸 grok 등을 지금 못 쓰고 · 잔액 확인된 계정이 있다) ⇒ 이번 판정만 크레딧 계정을 고른다.
|
|
296
|
+
* - `none` 크레딧 ✗(`why` = 칸을 못 쓴 이유 · 칸이 없으면 생략).
|
|
297
|
+
* ⛔ 칸 판정은 `decideFallback` 를 그대로 부른다 — 체인 의미를 여기서 다시 짓지 않는다. 이 판독은 네트워크를 안 친다. */
|
|
298
|
+
type RotationCreditsGrant =
|
|
299
|
+
| { readonly allowed: true; readonly via: 'policy' }
|
|
300
|
+
| { readonly allowed: true; readonly via: 'chain-step'; readonly skipped: readonly { readonly step: FallbackStep; readonly why: string }[]; readonly creditAccountCount: number }
|
|
301
|
+
| { readonly allowed: false; readonly via: 'none'; readonly why?: string };
|
|
302
|
+
|
|
303
|
+
function rotationCreditsGrant(candidates: readonly RotationCandidate[]): RotationCreditsGrant {
|
|
304
|
+
const policy = codexQuotaPolicyFromConfig();
|
|
305
|
+
if (codexPolicyAllowsCredits(policy)) return { allowed: true, via: 'policy' };
|
|
306
|
+
if (!codexPolicyAllowsFallback(policy)) return { allowed: false, via: 'none' };
|
|
307
|
+
try {
|
|
308
|
+
const { chain } = normalizeFallbackChain(configReader().llm?.fallbackChain);
|
|
309
|
+
if (!chain.includes('codex-credits')) return { allowed: false, via: 'none' };
|
|
310
|
+
const creditAccountCount = codexCreditAccountNames(candidates, codexCreditReserveFromConfig()).length;
|
|
311
|
+
const fallbackModel = configReader().llm?.openrouter?.fallbackModel;
|
|
312
|
+
const decision = decideFallback({
|
|
313
|
+
rotation: { reason: 'no-candidate' },
|
|
314
|
+
chain,
|
|
315
|
+
grokAvailable: grokCredentialPresent(),
|
|
316
|
+
grokQuota: readCachedGrokQuota(),
|
|
317
|
+
...(chain.includes('openrouter') ? {
|
|
318
|
+
openrouterFallbackModel: typeof fallbackModel === 'string' ? fallbackModel : undefined,
|
|
319
|
+
openrouterAvailable: Boolean(getOpenRouterApiKey()?.trim()),
|
|
320
|
+
} : {}),
|
|
321
|
+
codexCreditsAvailable: creditAccountCount > 0,
|
|
322
|
+
});
|
|
323
|
+
if (decision.action === 'codex-credits') return { allowed: true, via: 'chain-step', skipped: decision.skipped, creditAccountCount };
|
|
324
|
+
return { allowed: false, via: 'none', why: decision.action === 'stay' ? decision.why : `earlier-step:${decision.action === 'switch-backend' ? decision.backend : decision.action}` };
|
|
325
|
+
} catch {
|
|
326
|
+
return { allowed: false, via: 'none', why: 'chain-unreadable' };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
262
330
|
function buildRotationCandidates(path: string, now: number, env: NodeJS.ProcessEnv = process.env): RotationCandidate[] {
|
|
263
331
|
return listCodexAccountsInStore(path)
|
|
264
332
|
.map((row) => {
|
|
@@ -277,12 +345,13 @@ function buildRotationCandidates(path: string, now: number, env: NodeJS.ProcessE
|
|
|
277
345
|
storeKey: row.storeKey,
|
|
278
346
|
home,
|
|
279
347
|
reached: readQuotaSignal(now, home),
|
|
348
|
+
resetCreditAvailability: resetCreditAvailability(home, now),
|
|
280
349
|
...(usedPercent === undefined ? {} : { usedPercent }),
|
|
281
350
|
...(credits.balance === undefined ? {} : { creditBalance: credits.balance }),
|
|
282
351
|
...(credits.hasCredits === undefined ? {} : { hasCredits: credits.hasCredits }),
|
|
283
|
-
};
|
|
352
|
+
} satisfies RotationCandidate;
|
|
284
353
|
})
|
|
285
|
-
.filter((c): c is
|
|
354
|
+
.filter((c): c is NonNullable<typeof c> => c !== null);
|
|
286
355
|
}
|
|
287
356
|
|
|
288
357
|
function rotationCreditPace(candidates: readonly RotationCandidate[], now: number) {
|
|
@@ -364,7 +433,7 @@ function codexAccountAlertsEnabled(): boolean {
|
|
|
364
433
|
}
|
|
365
434
|
}
|
|
366
435
|
|
|
367
|
-
function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed', details: Record<string, unknown>, text: string):
|
|
436
|
+
function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed' | 'credit-spend-start', details: Record<string, unknown>, text: string): boolean {
|
|
368
437
|
// ⛔ 끄더라도 «조용히» 사라지지 않는다 — 「왜 알림이 안 오나」를 나중에 로그로 답할 수 있어야 한다.
|
|
369
438
|
if (!codexAccountAlertsEnabled()) {
|
|
370
439
|
debug.log('oauth.codex-account', 'outbound-suppressed', {
|
|
@@ -373,20 +442,106 @@ function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed', de
|
|
|
373
442
|
knob: 'llm.codexAccountAlerts',
|
|
374
443
|
...details,
|
|
375
444
|
});
|
|
376
|
-
return;
|
|
445
|
+
return false;
|
|
377
446
|
}
|
|
378
|
-
|
|
447
|
+
try {
|
|
379
448
|
const delivered = codexAccountOutboundSender(text, 'alert');
|
|
380
449
|
debug.log('oauth.codex-account', 'outbound', { event, delivered, ...details });
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
attempt();
|
|
450
|
+
return delivered;
|
|
384
451
|
} catch (error) {
|
|
385
452
|
debug.log('oauth.codex-account', 'outbound-failed', {
|
|
386
453
|
event,
|
|
387
454
|
message: error instanceof Error ? error.message : String(error),
|
|
388
455
|
...details,
|
|
389
456
|
}, { level: 'warn' });
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** 크레딧 알림 잠금 — 이식 가능한 `wx` 잠금 파일(⛔ `flock(1)` 은 macOS 운영 호스트에 «없다» — mbp·node-b 실측 10-11).
|
|
462
|
+
* 기다림 상한을 넘기거나 오래된(죽은 소유자) 잠금이면 «알림을 잃지 않는 쪽»으로 간다:
|
|
463
|
+
* 오래된 잠금은 걷고, 상한을 넘기면 잠금 없이 보낸다(최악은 같은 날 중복 1통 — 누락보다 낫다). */
|
|
464
|
+
const CREDIT_SPEND_ALERT_LOCK_STALE_MS = 60_000;
|
|
465
|
+
let creditSpendAlertLockWaitMs = 5_000;
|
|
466
|
+
/** 시험 전용 — 기다림 상한을 줄인다(null = 기본 5초). */
|
|
467
|
+
export function _setCreditSpendAlertLockWaitMsForTesting(ms: number | null): void {
|
|
468
|
+
creditSpendAlertLockWaitMs = ms ?? 5_000;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function sleepSync(ms: number): void {
|
|
472
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** 잠갔으면 true(호출자가 풀어야 한다) · 상한을 넘겨 잠금 없이 가면 false. */
|
|
476
|
+
function acquireCreditSpendAlertLock(path: string, account: string): boolean {
|
|
477
|
+
const deadline = Date.now() + creditSpendAlertLockWaitMs;
|
|
478
|
+
for (;;) {
|
|
479
|
+
try {
|
|
480
|
+
const fd = openSync(path, 'wx');
|
|
481
|
+
try { writeFileSync(fd, String(process.pid)); } finally { closeSync(fd); }
|
|
482
|
+
return true;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
if (Date.now() - statSync(path).mtimeMs > CREDIT_SPEND_ALERT_LOCK_STALE_MS) {
|
|
488
|
+
debug.log('oauth.codex-account', 'credit-spend-alert-lock-stale', { account });
|
|
489
|
+
try { unlinkSync(path); } catch { /* 다른 소유자가 먼저 걷었다 */ }
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
} catch { continue; /* 그 사이 풀렸다 */ }
|
|
493
|
+
if (Date.now() >= deadline) {
|
|
494
|
+
debug.log('oauth.codex-account', 'credit-spend-alert-lock-timeout', { account, waitMs: creditSpendAlertLockWaitMs }, { level: 'warn' });
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
sleepSync(50);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** UTC 일자별 성공한 계정 알림만 기록한다. 잠근 채 발송하여 동시 런도 중복 발송하지 않는다. */
|
|
502
|
+
function notifyCreditSpendStart(
|
|
503
|
+
account: string,
|
|
504
|
+
reason: 'credits-allowed' | 'credit-pace' | 'credits-rotated',
|
|
505
|
+
usage: readonly RotationCandidate[],
|
|
506
|
+
now: number,
|
|
507
|
+
counterPath: string,
|
|
508
|
+
): void {
|
|
509
|
+
const day = new Date(now).toISOString().slice(0, 10);
|
|
510
|
+
const lockPath = `${counterPath}.lock`;
|
|
511
|
+
let locked = false;
|
|
512
|
+
try {
|
|
513
|
+
mkdirSync(dirname(counterPath), { recursive: true });
|
|
514
|
+
locked = acquireCreditSpendAlertLock(lockPath, account);
|
|
515
|
+
let accounts: string[] = [];
|
|
516
|
+
try {
|
|
517
|
+
const parsed = JSON.parse(readFileSync(counterPath, 'utf8')) as { day?: unknown; accounts?: unknown };
|
|
518
|
+
if (parsed.day === day && Array.isArray(parsed.accounts)) {
|
|
519
|
+
accounts = parsed.accounts.filter((value): value is string => typeof value === 'string');
|
|
520
|
+
}
|
|
521
|
+
} catch (error) {
|
|
522
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
523
|
+
}
|
|
524
|
+
if (accounts.includes(account)) {
|
|
525
|
+
debug.log('oauth.codex-account', 'credit-spend-alert-skipped', { account, reason: 'already-alerted-today' });
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const usageSummary = usage.map((candidate) => `${candidate.name}=${formatUsedPercent(candidate.usedPercent)}`).join(', ') || 'unknown';
|
|
529
|
+
if (!notifyCodexAccountEvent('credit-spend-start', { account, reason, day },
|
|
530
|
+
`💳 Codex credits in use\naccount: ${account}\nreason: ${reason}\nusage: ${usageSummary}`)) return;
|
|
531
|
+
const tempPath = `${counterPath}.${process.pid}.${Date.now()}.tmp`;
|
|
532
|
+
try {
|
|
533
|
+
writeFileSync(tempPath, `${JSON.stringify({ day, accounts: [...accounts, account] })}\n`, 'utf8');
|
|
534
|
+
renameSync(tempPath, counterPath);
|
|
535
|
+
} finally {
|
|
536
|
+
try { unlinkSync(tempPath); } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
|
|
537
|
+
}
|
|
538
|
+
debug.log('oauth.codex-account', 'credit-spend-start', { account, reason, day }, { level: 'warn' });
|
|
539
|
+
} catch (error) {
|
|
540
|
+
debug.log('oauth.codex-account', 'credit-spend-alert-failed', {
|
|
541
|
+
account, message: error instanceof Error ? error.message : String(error),
|
|
542
|
+
}, { level: 'warn' });
|
|
543
|
+
} finally {
|
|
544
|
+
if (locked) { try { unlinkSync(lockPath); } catch { /* 이미 없다 */ } }
|
|
390
545
|
}
|
|
391
546
|
}
|
|
392
547
|
|
|
@@ -511,6 +666,8 @@ export function inspectCodexRotation(
|
|
|
511
666
|
readonly candidateCount: number | undefined;
|
|
512
667
|
readonly accountThresholds: ReturnType<typeof decideCodexRotation>['accountThresholds'];
|
|
513
668
|
readonly to: string | undefined;
|
|
669
|
+
/** SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분에 닿아 `no-candidate` 가 됐을 때만 있다. */
|
|
670
|
+
readonly creditReserveHit?: { readonly balance: number; readonly reserve: number };
|
|
514
671
|
} {
|
|
515
672
|
const path = deps.storePath ?? authStorePath();
|
|
516
673
|
const now = deps.now ?? Date.now();
|
|
@@ -531,7 +688,7 @@ export function inspectCodexRotation(
|
|
|
531
688
|
const rawThreshold = rotationThresholdFromConfig();
|
|
532
689
|
const thresholdPercentByAccount = rotationThresholdsByAccountFromConfig();
|
|
533
690
|
const decision = decideCodexRotation({
|
|
534
|
-
current, explicit, enabled, disabledProvenance: rotationConfig.state, currentReached, currentUsedPercent, accountOrder: accountOrderFromConfig(), resetCreditAvailability: resetCreditAvailability(currentHome, now), thresholdPercent: rawThreshold, thresholdPercentByAccount, creditsAllowed:
|
|
691
|
+
current, explicit, enabled, disabledProvenance: rotationConfig.state, currentReached, currentUsedPercent, accountOrder: accountOrderFromConfig(), resetCreditAvailability: resetCreditAvailability(currentHome, now), thresholdPercent: rawThreshold, thresholdPercentByAccount, creditsAllowed: rotationCreditsGrant(candidates).allowed, creditReserve: codexCreditReserveFromConfig(), ...currentCredits, candidates, creditPace: rotationCreditPace(candidates, now),
|
|
535
692
|
});
|
|
536
693
|
// ⛔⭐ 나이는 «만료돼도» 낸다 — 「65분 전」과 「3일 전」은 다른 진단이다(리뷰 must-fix).
|
|
537
694
|
const observedAtByHome: Record<string, number> = {};
|
|
@@ -553,6 +710,7 @@ export function inspectCodexRotation(
|
|
|
553
710
|
candidates, observedAtByHome, freshByHome,
|
|
554
711
|
knownAccountCount: listCodexAccountsInStore(path).length,
|
|
555
712
|
reason: decision.reason, candidateCount: decision.candidateCount, accountThresholds: decision.accountThresholds, to: decision.to?.name,
|
|
713
|
+
...(decision.creditReserveHit ? { creditReserveHit: decision.creditReserveHit } : {}),
|
|
556
714
|
};
|
|
557
715
|
}
|
|
558
716
|
|
|
@@ -561,7 +719,7 @@ export function resolveCodexAccountForRun(
|
|
|
561
719
|
/** ⛔ 「설정을 우회하는 노브」를 두지 않는다(리뷰 must-fix) — 종전 `rotationEnabled` 는
|
|
562
720
|
* 아무도 안 주면서 «config 를 덮을 수 있는» 인자였다. 그런 인자는 수용 기준을 스스로 깬다.
|
|
563
721
|
* ⊕ `now` 도 아무도 안 주는 죽은 계약이라 지웠다. 남는 것은 «테스트 격리»뿐이다. */
|
|
564
|
-
deps: { readonly storePath?: string } = {},
|
|
722
|
+
deps: { readonly storePath?: string; readonly counterPath?: string } = {},
|
|
565
723
|
): CodexAccountResolution {
|
|
566
724
|
// ⛔ 「이름만 주고 홈을 안 준」 경우를 정본 기록으로 메운다 — 안 그러면 조용히 default 로 떨어지고
|
|
567
725
|
// 관측은 `explicit` 이라 말한다(2026-08-11 72차 실측).
|
|
@@ -618,6 +776,7 @@ export function resolveCodexAccountForRun(
|
|
|
618
776
|
const currentSignalAttributable = signalAttributableToAccount(currentHomeInfo);
|
|
619
777
|
|
|
620
778
|
const creditPace = rotationCreditPace(candidates, now);
|
|
779
|
+
const creditsGrant = rotationCreditsGrant(candidates);
|
|
621
780
|
const decision = decideCodexRotation({
|
|
622
781
|
current,
|
|
623
782
|
explicit,
|
|
@@ -629,11 +788,13 @@ export function resolveCodexAccountForRun(
|
|
|
629
788
|
resetCreditAvailability: resetCreditAvailability(currentHome, now),
|
|
630
789
|
thresholdPercent: rotationThresholdFromConfig(),
|
|
631
790
|
thresholdPercentByAccount: rotationThresholdsByAccountFromConfig(),
|
|
632
|
-
creditsAllowed:
|
|
791
|
+
creditsAllowed: creditsGrant.allowed,
|
|
792
|
+
creditReserve: codexCreditReserveFromConfig(),
|
|
633
793
|
...currentCreditsInput(currentSignalAttributable ? currentHome : undefined, now),
|
|
634
794
|
candidates,
|
|
635
795
|
creditPace,
|
|
636
796
|
});
|
|
797
|
+
observeCodexCreditsStep(creditsGrant, decision, current.name);
|
|
637
798
|
debug.log('codex.rotation', 'credit-pace', {
|
|
638
799
|
active: creditPace.active,
|
|
639
800
|
todaySpent: creditPace.todaySpent,
|
|
@@ -641,6 +802,17 @@ export function resolveCodexAccountForRun(
|
|
|
641
802
|
to: decision.reason === 'credit-pace' ? decision.to?.name ?? current.name : decision.to?.name,
|
|
642
803
|
});
|
|
643
804
|
observeRotation(decision, current.name);
|
|
805
|
+
// 발송 의무는 이 실행 경로에서 잠금 해제까지 기다린 뒤 하루 카운터에 기록한다.
|
|
806
|
+
// CREDIT-SPEND-ORDER(10-12) — «다른 계정의 선불 크레딧으로 옮김»(`rotated` ⊕ creditEntry)도 크레딧 진입이다.
|
|
807
|
+
const creditSpendReason = decision.reason === 'credits-allowed' || decision.reason === 'credit-pace' ? decision.reason
|
|
808
|
+
: decision.reason === 'rotated' && decision.creditEntry ? 'credits-rotated' as const : undefined;
|
|
809
|
+
if (creditSpendReason && !deps.counterPath && isUnderTestRunner(process.env)) {
|
|
810
|
+
// 시험 러너 가드(autoConsume 의 test-runtime-guard 와 같은 관용구) — 카운터를 주입 안 한 시험이 실제 카운터·송신기에 닿지 않는다.
|
|
811
|
+
debug.log('oauth.codex-account', 'credit-spend-alert-skipped', { account: decision.to?.name ?? current.name, reason: 'test-runtime-guard' });
|
|
812
|
+
} else if (creditSpendReason) {
|
|
813
|
+
notifyCreditSpendStart(decision.to?.name ?? current.name, creditSpendReason, candidates, now,
|
|
814
|
+
deps.counterPath ?? join(codexCredentialRoot(), 'budget', 'codex-credit-spend-alert.json'));
|
|
815
|
+
}
|
|
644
816
|
// 순서 ② — 구독 남은 계정이 없고 리셋권이 있으면 «스스로 1개» 쓴다(일일 상한 · 비동기 · 이번 호출은 종전대로 머문다).
|
|
645
817
|
// ⛔ 판정이 `reset-credit-available` 일 때만 닿는다 — 구독 남은 계정이 있으면(rotated) 여기 안 온다.
|
|
646
818
|
if (decision.reason === 'reset-credit-available') void autoConsumeCodexResetCredit({ storePath: path });
|
|
@@ -844,6 +1016,65 @@ export function listCodexAccountsInStore(storePath?: string): StoredCodexAccount
|
|
|
844
1016
|
* ⛔ 실패는 삼키되 «조용히»는 아니다 — 못 정했으면 그 사실을 관측에 남기고 `stay` 로 답한다.
|
|
845
1017
|
* (판정이 못 돌아서 백엔드가 안 뜨는 일은 없어야 한다.)
|
|
846
1018
|
*/
|
|
1019
|
+
/** CODEX-CREDITS-STEP 관측 — 회전이 «구독이 다 찬» 판정에 닿았을 때만(크레딧으로 갔든 · 칸을 못 써 건너뛰었든) 한 줄.
|
|
1020
|
+
* ⛔ 비밀·홈 경로를 넣지 않는다(계정 이름 · 이유 · 건너뛴 칸). */
|
|
1021
|
+
function observeCodexCreditsStep(
|
|
1022
|
+
grant: RotationCreditsGrant,
|
|
1023
|
+
decision: { readonly reason: string; readonly to?: RotationCandidate; readonly accountThresholds?: readonly { readonly name: string; readonly status: string }[] },
|
|
1024
|
+
currentName: string,
|
|
1025
|
+
): void {
|
|
1026
|
+
if (grant.via === 'policy') return;
|
|
1027
|
+
// 회전이 «크레딧 계정»으로 옮겼나 — 고른 계정의 구독 창이 이미 찼으면 크레딧 회전이다(구독 회전과 가른다).
|
|
1028
|
+
const toStatus = decision.to ? decision.accountThresholds?.find((row) => row.name === decision.to!.name)?.status : undefined;
|
|
1029
|
+
const creditRotation = decision.reason === 'rotated' && (toStatus === 'reached' || toStatus === 'threshold-reached');
|
|
1030
|
+
if (grant.via === 'chain-step' && (decision.reason === 'credits-allowed' || creditRotation)) {
|
|
1031
|
+
debug.log('oauth.fallback-chain', 'codex-credits-step', {
|
|
1032
|
+
site: 'rotation', outcome: 'credits', rotationReason: decision.reason, from: currentName, to: decision.to?.name ?? currentName,
|
|
1033
|
+
skipped: grant.skipped, creditAccountCount: grant.creditAccountCount,
|
|
1034
|
+
}, { level: 'warn' });
|
|
1035
|
+
} else if (grant.via === 'none' && decision.reason === 'no-candidate' && grant.why === 'codex-credits-unavailable') {
|
|
1036
|
+
debug.log('oauth.fallback-chain', 'codex-credits-step', {
|
|
1037
|
+
site: 'rotation', outcome: 'skipped', rotationReason: decision.reason, why: grant.why,
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/** 크레딧 잔액이 «확인된» codex 계정 이름(잔액 > 0 · 보유 ≠ false · 홈을 안다). 잔액을 모르면 넣지 않는다 — 돈이라 fail-closed.
|
|
1043
|
+
* (budget-gate `codexCreditCandidate` 와 같은 자.) */
|
|
1044
|
+
export function codexCreditAccountNames(candidates: readonly RotationCandidate[], reserve = 0): string[] {
|
|
1045
|
+
return creditCandidatesByBalance(candidates, reserve).map((c) => c.name);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/** 명시 계정 «자신»의 크레딧 잔액이 확인되나(잔액 > 0 · 보유 ≠ false) — 신호를 귀속 못 하면 후보 목록의 같은 이름 줄. */
|
|
1049
|
+
function explicitAccountHasCredits(snapshot: {
|
|
1050
|
+
readonly current: { readonly name: string };
|
|
1051
|
+
readonly candidates: readonly RotationCandidate[];
|
|
1052
|
+
readonly currentCreditBalance?: number;
|
|
1053
|
+
readonly currentHasCredits?: boolean;
|
|
1054
|
+
}, reserve = 0): boolean {
|
|
1055
|
+
const self = snapshot.candidates.find((c) => c.name === snapshot.current.name);
|
|
1056
|
+
const balance = snapshot.currentCreditBalance ?? self?.creditBalance;
|
|
1057
|
+
const has = snapshot.currentHasCredits ?? self?.hasCredits;
|
|
1058
|
+
return typeof balance === 'number' && Number.isFinite(balance) && balance > reserve && has !== false;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/** 명시 계정 자신을 후보 모양으로 — 홈을 모르면 없다(그때는 호스트 홈 그대로). */
|
|
1062
|
+
function explicitAccountCandidate(snapshot: {
|
|
1063
|
+
readonly current: { readonly name: string; readonly storeKey: string };
|
|
1064
|
+
readonly currentHome?: string;
|
|
1065
|
+
readonly candidates: readonly RotationCandidate[];
|
|
1066
|
+
}): RotationCandidate | undefined {
|
|
1067
|
+
const self = snapshot.candidates.find((c) => c.name === snapshot.current.name && c.home.length > 0);
|
|
1068
|
+
if (self) return self;
|
|
1069
|
+
const home = snapshot.currentHome?.trim();
|
|
1070
|
+
return home ? { name: snapshot.current.name, storeKey: snapshot.current.storeKey, home, reached: undefined } : undefined;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
/** 잔액이 가장 많은(확인된) 계정 — 크레딧 칸이 실제로 쓸 계정. */
|
|
1074
|
+
function richestCreditCandidate(candidates: readonly RotationCandidate[], reserve = 0): RotationCandidate | undefined {
|
|
1075
|
+
return creditCandidatesByBalance(candidates, reserve)[0];
|
|
1076
|
+
}
|
|
1077
|
+
|
|
847
1078
|
export function resolveRunFallback(
|
|
848
1079
|
env: NodeJS.ProcessEnv = process.env,
|
|
849
1080
|
deps: {
|
|
@@ -853,6 +1084,8 @@ export function resolveRunFallback(
|
|
|
853
1084
|
readonly grokQuota?: 'usable' | 'exhausted' | 'unknown';
|
|
854
1085
|
/** OpenRouter 키 «존재» seam(테스트 격리) — 안 주면 `getOpenRouterApiKey()` 로 잰다. 키 값은 기록하지 않는다. */
|
|
855
1086
|
readonly openrouterAvailable?: boolean;
|
|
1087
|
+
/** codex 크레딧 잔액 «확인» seam — 안 주면 회전 후보의 크레딧 신호(잔액 > 0 · 보유 ≠ false)로 잰다. */
|
|
1088
|
+
readonly codexCreditsAvailable?: boolean;
|
|
856
1089
|
} & Pick<FallbackInput, 'currentStep' | 'currentCredentialRateLimited'> = {},
|
|
857
1090
|
): FallbackDecision {
|
|
858
1091
|
try {
|
|
@@ -888,26 +1121,62 @@ export function resolveRunFallback(
|
|
|
888
1121
|
// ⛔ grok 가용성은 «호출자가 확정»해서 줄 수 있다(테스트 격리). 안 주면 여기서 잰다.
|
|
889
1122
|
// ⛔ «가용성 판정»이라 갱신을 유도하지 않는다 — 「자격이 있나」만 묻지 「지금 쓸 수 있나」를 묻지 않는다.
|
|
890
1123
|
// (쓸 수 있는지는 실제 요청 경로가 접힌 해석으로 확인한다.)
|
|
891
|
-
const grokAvailable = deps.grokAvailable ??
|
|
1124
|
+
const grokAvailable = deps.grokAvailable ?? grokCredentialPresent();
|
|
892
1125
|
// ⛔ 「지금 쓸 수 있나」는 «자격과 다른 축»이다. 안 주면 'unknown' — 그리고 unknown 은 «통과»다.
|
|
893
1126
|
// ⇒ 「모르고 갔다」와 「알고 갔다」가 관측에서 갈린다(아래 grokQuota).
|
|
894
1127
|
const grokQuota = deps.grokQuota ?? readCachedGrokQuota();
|
|
895
1128
|
const fallbackModel = configReader().llm?.openrouter?.fallbackModel;
|
|
896
|
-
|
|
897
|
-
|
|
1129
|
+
// SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분에 닿은 «넘김»은 OpenRouter 가 먼저다(대표 OP 10-11: grok 이 아니다).
|
|
1130
|
+
// 운영 체인 `['codex-rotate','grok']` 에는 openrouter 칸이 없다 ⇒ 이 경로에만 codex 바로 뒤에 openrouter 를 끼운다
|
|
1131
|
+
// (나머지 칸은 그 뒤 · 키가 없으면 종전 체인으로). 모델은 `llm.openrouter.fallbackModel`, 없으면 «중» 기본 glm-5.3.
|
|
1132
|
+
// ⛔ 정책이 within-quota 면 체인 밖으로 안 나간다(종전 규칙 그대로).
|
|
1133
|
+
const reserveHit = snapshot.creditReserveHit;
|
|
1134
|
+
const reserveReroute = reserveHit !== undefined && codexPolicyAllowsFallback(quotaPolicy);
|
|
1135
|
+
const effectiveChain: readonly FallbackStep[] = reserveReroute
|
|
1136
|
+
? ['codex-rotate', 'openrouter', ...chain.filter((step) => step !== 'codex-rotate' && step !== 'openrouter')]
|
|
1137
|
+
: chain;
|
|
1138
|
+
const openrouterFallbackModel = typeof fallbackModel === 'string' && fallbackModel.trim()
|
|
1139
|
+
? fallbackModel
|
|
1140
|
+
: reserveReroute ? CREDIT_RESERVE_OPENROUTER_MODEL : undefined;
|
|
1141
|
+
const openrouterAvailable = effectiveChain.includes('openrouter')
|
|
898
1142
|
&& (deps.openrouterAvailable ?? Boolean(getOpenRouterApiKey()?.trim()));
|
|
899
|
-
|
|
1143
|
+
// CODEX-CREDITS-STEP — 체인에 그 칸이 있을 때만 잰다(없으면 판정이 안 읽는다). 잔액을 «모르면» 없다고 본다(돈 · fail-closed).
|
|
1144
|
+
// ⛔ 사람이 계정을 «명시»했으면 그 계정의 잔액만 본다 — 다른 계정 잔액으로 칸을 열고 명시 계정으로 쏘면 fail-closed 가 깨진다.
|
|
1145
|
+
const explicitAccount = snapshot.reason === 'explicit';
|
|
1146
|
+
const creditReserve = codexCreditReserveFromConfig();
|
|
1147
|
+
const creditAccounts = !effectiveChain.includes('codex-credits') ? []
|
|
1148
|
+
: explicitAccount ? (explicitAccountHasCredits(snapshot, creditReserve) ? [snapshot.current.name] : [])
|
|
1149
|
+
: codexCreditAccountNames(snapshot.candidates, creditReserve);
|
|
1150
|
+
const codexCreditsAvailable = effectiveChain.includes('codex-credits') && (deps.codexCreditsAvailable ?? creditAccounts.length > 0);
|
|
1151
|
+
const fallbackBase = { rotation, chain: effectiveChain, grokAvailable, grokQuota, openrouterFallbackModel, openrouterAvailable, codexCreditsAvailable };
|
|
900
1152
|
const fallbackInput: FallbackInput = deps.currentCredentialRateLimited === true && deps.currentStep
|
|
901
1153
|
? { ...fallbackBase, currentStep: deps.currentStep, currentCredentialRateLimited: true }
|
|
902
1154
|
: { ...fallbackBase, ...(deps.currentStep ? { currentStep: deps.currentStep } : {}) };
|
|
903
|
-
const
|
|
1155
|
+
const judged = decideFallback(fallbackInput);
|
|
1156
|
+
// CODEX-CREDITS-STEP — 칸에 닿았으면 «어느 계정 크레딧으로» 갈지도 정한다(잔액 많은 순 · 홈을 안다).
|
|
1157
|
+
// 런타임 재시도(grok 429)는 회전을 다시 거치지 않으므로 여기서 계정을 실어 보내야 자식이 그 계정으로 뜬다.
|
|
1158
|
+
// ⛔ 사람이 계정을 «명시»했으면(explicit) 계정을 바꾸지 않는다 — 의도가 이긴다(그 계정 그대로 크레딧).
|
|
1159
|
+
// 명시 계정이면 «그 계정»의 홈을 싣는다 — 계정은 안 바꾸되, 잔액을 확인한 계정과 발사 홈이 갈리지 않게.
|
|
1160
|
+
const creditTo = judged.action !== 'codex-credits' ? undefined
|
|
1161
|
+
: explicitAccount ? explicitAccountCandidate(snapshot)
|
|
1162
|
+
: richestCreditCandidate(snapshot.candidates, creditReserve);
|
|
1163
|
+
const decision: FallbackDecision = judged.action === 'codex-credits' && creditTo ? { ...judged, to: creditTo } : judged;
|
|
1164
|
+
if (reserveHit) {
|
|
1165
|
+
debug.log('llm.codex', 'credit-reserve-hit', {
|
|
1166
|
+
balance: reserveHit.balance, reserve: reserveHit.reserve,
|
|
1167
|
+
next: decision.action === 'switch-backend' ? decision.backend : decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'codex-credits' ? 'codex-credits' : `stay:${decision.why}`,
|
|
1168
|
+
...(decision.action === 'switch-backend' && decision.backend === 'openrouter' ? { model: decision.model } : {}),
|
|
1169
|
+
openrouterAvailable, rerouted: reserveReroute,
|
|
1170
|
+
}, { level: 'warn' });
|
|
1171
|
+
}
|
|
904
1172
|
// tier-map 칸(가격·창 근거) — 유료 전환은 «무슨 값으로 가는지»를 관측에 남긴다. 미등록이면 'unregistered'.
|
|
905
1173
|
const openrouterSpec = decision.action === 'switch-backend' && decision.backend === 'openrouter'
|
|
906
1174
|
? lookupOpenRouterModelSpec(decision.model) : undefined;
|
|
907
1175
|
|
|
908
1176
|
debug.log('oauth.fallback-chain', 'decide', {
|
|
909
1177
|
rotationReason: rotation.reason,
|
|
910
|
-
chain, usedDefault, quotaPolicy,
|
|
1178
|
+
chain: effectiveChain, usedDefault, quotaPolicy,
|
|
1179
|
+
...(reserveHit ? { creditReserveHit: true } : {}),
|
|
911
1180
|
rotationResult: rotation.reason,
|
|
912
1181
|
// ⛔⭐ 「안 줬다」를 «false 로 접지 않는다»(무인 리뷰 must-fix · UNKNOWN-DEFAULT).
|
|
913
1182
|
// 호출자가 이 값을 생략하면 그것은 「한도가 아니었다」가 «아니라» ***「안 쟀다」***다.
|
|
@@ -915,11 +1184,11 @@ export function resolveRunFallback(
|
|
|
915
1184
|
credentialRateLimited: fallbackInput.currentCredentialRateLimited === undefined
|
|
916
1185
|
? 'unknown'
|
|
917
1186
|
: fallbackInput.currentCredentialRateLimited === true,
|
|
918
|
-
selectedChainStep: decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'switch-backend' ? decision.backend : null,
|
|
1187
|
+
selectedChainStep: decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'switch-backend' ? decision.backend : decision.action === 'codex-credits' ? 'codex-credits' : null,
|
|
919
1188
|
...(dropped.length > 0 ? { droppedSteps: dropped } : {}),
|
|
920
1189
|
grokAvailable,
|
|
921
1190
|
grokQuota,
|
|
922
|
-
...(
|
|
1191
|
+
...(effectiveChain.includes('openrouter') ? { openrouterAvailable, openrouterModelConfigured: Boolean(openrouterFallbackModel?.trim()) } : {}),
|
|
923
1192
|
action: decision.action,
|
|
924
1193
|
...(decision.action === 'switch-backend' ? { backend: decision.backend } : {}),
|
|
925
1194
|
...(decision.action === 'switch-backend' && decision.backend === 'openrouter'
|
|
@@ -928,7 +1197,50 @@ export function resolveRunFallback(
|
|
|
928
1197
|
...(decision.action === 'stay' ? { why: decision.why } : {}),
|
|
929
1198
|
...(decision.action === 'codex-rotate' ? { to: decision.to.name } : {}),
|
|
930
1199
|
});
|
|
931
|
-
|
|
1200
|
+
// 칸에 «닿았나» — 판정이 체인을 걸었고(한도 오류 재시도 · codex 축이 끝남) 그 걸음이 칸을 지났나.
|
|
1201
|
+
// 최종 결정과 무관하다: 칸을 건너뛰고 뒤 칸으로 갔든, 뒤 칸까지 못 써 머물렀든 도달은 도달이다.
|
|
1202
|
+
const selectedStep: FallbackStep | undefined = decision.action === 'switch-backend'
|
|
1203
|
+
? (decision.backend === 'claude' ? 'claude-pty' : decision.backend) : undefined;
|
|
1204
|
+
const walked = fallbackInput.currentCredentialRateLimited === true
|
|
1205
|
+
|| rotation.reason === 'no-candidate' || rotation.reason === 'disabled' || rotation.reason === 'reset-credit-available'
|
|
1206
|
+
|| ('to' in rotation && !chain.includes('codex-rotate'));
|
|
1207
|
+
const walkStart = fallbackInput.currentCredentialRateLimited === true ? fallbackInput.currentStep : 'codex-rotate';
|
|
1208
|
+
const walkIdx = walkStart === undefined ? -1 : chain.indexOf(walkStart);
|
|
1209
|
+
const walkRest = walkIdx === -1 ? chain : chain.slice(walkIdx + 1);
|
|
1210
|
+
const reachedCredits = walked && walkRest.includes('codex-credits')
|
|
1211
|
+
&& (selectedStep === undefined || walkRest.indexOf('codex-credits') < walkRest.indexOf(selectedStep));
|
|
1212
|
+
if (reachedCredits && decision.action !== 'codex-credits') {
|
|
1213
|
+
// 칸에 «닿았지만» 잔액 확인된 계정이 없어 못 썼다 — 실패한 도달도 이유와 함께 남긴다.
|
|
1214
|
+
debug.log('oauth.fallback-chain', 'codex-credits-step', {
|
|
1215
|
+
site: 'chain', outcome: 'skipped', why: 'codex-credits-unavailable', next: selectedStep ?? null, rotationReason: rotation.reason, quotaPolicy, chain,
|
|
1216
|
+
grokAvailable, grokQuota, currentStep: fallbackInput.currentStep ?? null,
|
|
1217
|
+
credentialRateLimited: fallbackInput.currentCredentialRateLimited === true,
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
if (decision.action === 'codex-credits') {
|
|
1221
|
+
// ⭐ 체인이 «마지막 칸»(유료)에 닿을 때마다 한 줄 — 왜 앞 칸들을 못 썼나를 값으로(비밀·홈 경로 없음).
|
|
1222
|
+
debug.log('oauth.fallback-chain', 'codex-credits-step', {
|
|
1223
|
+
site: 'chain', outcome: 'credits',
|
|
1224
|
+
to: decision.to?.name ?? null,
|
|
1225
|
+
rotationReason: rotation.reason,
|
|
1226
|
+
quotaPolicy,
|
|
1227
|
+
chain,
|
|
1228
|
+
skipped: decision.skipped,
|
|
1229
|
+
grokAvailable,
|
|
1230
|
+
grokQuota,
|
|
1231
|
+
currentStep: fallbackInput.currentStep ?? null,
|
|
1232
|
+
credentialRateLimited: fallbackInput.currentCredentialRateLimited === true,
|
|
1233
|
+
creditAccountCount: deps.codexCreditsAvailable === undefined ? creditAccounts.length : 'seam',
|
|
1234
|
+
}, { level: 'warn' });
|
|
1235
|
+
emitDecision({
|
|
1236
|
+
kind: 'ROUTE',
|
|
1237
|
+
what: '공급자 codex(크레딧) — 체인 마지막 칸',
|
|
1238
|
+
reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy} · 건너뜀 ${decision.skipped.map((x) => `${x.step}:${x.why}`).join(', ') || '없음'}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
|
|
1239
|
+
purpose: '구독·grok 이 모두 막혀 선불 크레딧으로 작업을 이어 간다',
|
|
1240
|
+
target: 'openai-codex(credits)',
|
|
1241
|
+
paths: chain.length,
|
|
1242
|
+
});
|
|
1243
|
+
} else if (decision.action === 'switch-backend') {
|
|
932
1244
|
const openrouterNote = decision.backend === 'openrouter'
|
|
933
1245
|
? ` · API 과금 ${decision.model} (${openrouterSpec ? `${openrouterSpec.label} · ${openrouterSpec.rationale}` : 'tier-map 미등록'})`
|
|
934
1246
|
: '';
|
|
@@ -9,15 +9,20 @@
|
|
|
9
9
|
// credits — 한도 안 ⊕ 크레딧(찬 계정을 선불 크레딧으로 계속). 크레딧도 떨어져 요청이 한도 오류를 내면 폴백 체인.
|
|
10
10
|
//
|
|
11
11
|
// ⛔ 옛 키 `llm.codexCreditsAllowed: true` 는 `credits` 로 읽는다(새 키가 있으면 새 키가 이긴다).
|
|
12
|
+
// ⭐ 새 자리 = `policy/llm.yaml` 의 `credits.codex`(use→credits · fallback→fallback · never→within-quota).
|
|
13
|
+
// 풀이 순서: env → 정책 파일(파일 출처일 때만) → 옛 `llm.codexQuotaPolicy` → 옛 `llm.codexCreditsAllowed` → fallback.
|
|
14
|
+
// 옛 키는 지우지 않고 읽기만 한다(적용·가려짐은 `codex.policy` 관측으로 남는다).
|
|
12
15
|
// ⛔ 못 읽거나 모르는 값이면 `fallback` — 크레딧은 돈이라 fail-closed(종전 기본과 같다).
|
|
13
16
|
|
|
17
|
+
import { debug } from '../debug/log.js';
|
|
18
|
+
|
|
14
19
|
export const CODEX_QUOTA_POLICIES = ['within-quota', 'fallback', 'credits'] as const;
|
|
15
20
|
export type CodexQuotaPolicy = (typeof CODEX_QUOTA_POLICIES)[number];
|
|
16
21
|
|
|
17
22
|
export interface ResolvedCodexQuotaPolicy {
|
|
18
23
|
readonly policy: CodexQuotaPolicy;
|
|
19
|
-
/** 어디서 정해졌나 — `config`(
|
|
20
|
-
readonly source: 'env' | 'config' | 'legacy-credits' | 'default' | 'invalid';
|
|
24
|
+
/** 어디서 정해졌나 — `policy-file`(policy/llm.yaml credits.codex) · `config`(옛 `codexQuotaPolicy`) · `legacy-credits`(옛 `codexCreditsAllowed`) · `default` · `invalid`(모르는 값 → 기본). */
|
|
25
|
+
readonly source: 'env' | 'policy-file' | 'config' | 'legacy-credits' | 'default' | 'invalid';
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
export const CODEX_QUOTA_POLICY_LABEL: Readonly<Record<CodexQuotaPolicy, string>> = {
|
|
@@ -30,16 +35,40 @@ export function isCodexQuotaPolicy(value: unknown): value is CodexQuotaPolicy {
|
|
|
30
35
|
return typeof value === 'string' && (CODEX_QUOTA_POLICIES as readonly string[]).includes(value);
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
/** `policy/llm.yaml` 의 `credits.codex` 값. `unreadable` = 파일이 있는데 깨졌거나 못 읽음(fail-closed 로 fallback). */
|
|
39
|
+
export type CodexQuotaPolicyFileValue = 'use' | 'fallback' | 'never' | 'unreadable';
|
|
40
|
+
|
|
41
|
+
const FILE_VALUE_TO_POLICY: Readonly<Record<Exclude<CodexQuotaPolicyFileValue, 'unreadable'>, CodexQuotaPolicy>> = {
|
|
42
|
+
use: 'credits',
|
|
43
|
+
fallback: 'fallback',
|
|
44
|
+
never: 'within-quota',
|
|
45
|
+
};
|
|
46
|
+
|
|
33
47
|
export function resolveCodexQuotaPolicy(
|
|
34
48
|
llm: { readonly codexQuotaPolicy?: unknown; readonly codexCreditsAllowed?: unknown } | undefined,
|
|
49
|
+
file?: CodexQuotaPolicyFileValue,
|
|
35
50
|
): ResolvedCodexQuotaPolicy {
|
|
36
51
|
// A Pod has no copy of the host config; the launcher hands the host's policy down in this variable
|
|
37
52
|
// (09-29: without it every Pod child fell back to grok while all three accounts still had credits).
|
|
38
53
|
const fromEnv = process.env.ELANOUS_CODEX_QUOTA_POLICY?.trim();
|
|
39
54
|
if (fromEnv && isCodexQuotaPolicy(fromEnv)) return { policy: fromEnv, source: 'env' };
|
|
55
|
+
// 정책 파일이 깨졌으면 옛 키가 credits 라 해도 따르지 않는다 — 크레딧은 돈이라 닫는다.
|
|
56
|
+
if (file === 'unreadable') return { policy: 'fallback', source: 'invalid' };
|
|
40
57
|
const raw = llm?.codexQuotaPolicy;
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
const legacy: { key: string; value: unknown; policy: CodexQuotaPolicy } | undefined = isCodexQuotaPolicy(raw)
|
|
59
|
+
? { key: 'llm.codexQuotaPolicy', value: raw, policy: raw }
|
|
60
|
+
: llm?.codexCreditsAllowed === true ? { key: 'llm.codexCreditsAllowed', value: true, policy: 'credits' } : undefined;
|
|
61
|
+
if (file !== undefined) {
|
|
62
|
+
const policy = FILE_VALUE_TO_POLICY[file];
|
|
63
|
+
if (legacy && legacy.policy !== policy) debug.log('codex.policy', 'legacy-key-shadowed', { key: legacy.key, legacy: legacy.value, file });
|
|
64
|
+
return { policy, source: 'policy-file' };
|
|
65
|
+
}
|
|
66
|
+
if (legacy) {
|
|
67
|
+
debug.log('codex.policy', 'legacy-key-applied', { key: legacy.key, value: legacy.value });
|
|
68
|
+
return legacy.key === 'llm.codexQuotaPolicy'
|
|
69
|
+
? { policy: legacy.policy, source: 'config' }
|
|
70
|
+
: { policy: 'credits', source: 'legacy-credits' };
|
|
71
|
+
}
|
|
43
72
|
if (raw !== undefined) return { policy: 'fallback', source: 'invalid' };
|
|
44
73
|
return { policy: 'fallback', source: 'default' };
|
|
45
74
|
}
|