elanous 0.2.24 → 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-24282bf9f90031a5.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-dea4b795741126fd.js +1 -0
- 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-1d809a87139dd024.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-b92caddb5c715f30.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/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/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/bench-report.ts +46 -1
- package/scripts/ci-typecheck-changed.ts +7 -5
- package/scripts/release-loop/auto-approve-node.ts +6 -0
- package/scripts/release-loop/gate-closure.ts +286 -0
- package/scripts/release-loop/gate-node.ts +73 -13
- 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 +37 -10
- package/scripts/release-loop/resume.ts +69 -4
- package/scripts/tsc-baseline-cache.ts +28 -3
- package/scripts/usage-rollup.ts +27 -13
- 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-substrate/acp-implementer.ts +14 -7
- package/src/agent-substrate/pr-reviewer.ts +30 -10
- package/src/agent-substrate/self-review-cli.ts +126 -10
- package/src/budget/cost-tier-advisor.ts +91 -0
- package/src/budget/shadow-arms.ts +77 -0
- package/src/budget/types.ts +5 -3
- package/src/budget/unified-usage.ts +172 -8
- package/src/cli/doctor-cli.ts +21 -0
- package/src/cli/friendly-errors.ts +113 -0
- package/src/cli/intake-cli.ts +3 -1
- package/src/cli/memory-cli.ts +182 -0
- package/src/cli/model-watch-cli.ts +4 -1
- package/src/cli/pr-land-pod-shadow.ts +54 -0
- package/src/cli/release-cli.ts +9 -7
- 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/seat-requests-cli.ts +25 -0
- package/src/cli/tasks-cli.ts +31 -7
- package/src/cli/usage-cli.ts +3 -1
- 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/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
- package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
- package/src/debug/log-diet.ts +16 -4
- package/src/domains/morning-essential.ts +18 -3
- package/src/domains/release-tool.ts +4 -0
- package/src/execution-loop/launch-gate.ts +158 -2
- package/src/fleet/host-doctor.ts +375 -0
- package/src/goals/judge.ts +20 -6
- package/src/graph-runner/runner.ts +9 -5
- package/src/graph-wizard/archetypes.ts +14 -8
- package/src/graph-wizard/generate.ts +77 -1
- package/src/grok.ts +13 -7
- package/src/harness/harness-cli-command.ts +56 -47
- package/src/harness/harness-stop.ts +82 -12
- package/src/index.ts +17 -175
- package/src/intake-plane/collect-github.ts +7 -2
- package/src/intake-plane/lens.ts +46 -4
- package/src/intake-plane/requirement-funnel.ts +53 -1
- package/src/intelligence-map/catalog-feed.ts +119 -0
- package/src/intelligence-map/model-watch-intake.ts +40 -0
- package/src/intelligence-map/model-watch-mission.ts +14 -1
- package/src/llm/open-weight-discipline.ts +21 -0
- package/src/llm.ts +4 -8
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/nexus/api/http-server.ts +22 -0
- package/src/oauth/codex-account-rotation.ts +4 -1
- package/src/oauth/codex-account-store.ts +20 -7
- package/src/oauth/codex-quota-policy.ts +33 -4
- package/src/preview/terminal.ts +15 -5
- package/src/project/project-store.ts +20 -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/rehearsal.ts +1 -1
- package/src/seat-loop/duty-ledger.ts +64 -0
- package/src/self-dev/decompose.ts +37 -3
- package/src/self-dev/dev-pipeline.ts +32 -7
- package/src/self-dev/draft-residue.ts +16 -6
- package/src/self-dev/draft-sweep.ts +52 -4
- package/src/self-dev/fabric-decompose-adapter.ts +9 -2
- package/src/self-dev/run-supervisor.ts +37 -7
- package/src/self-implement/gate-cli.ts +29 -10
- package/src/self-implement/gate-remote.ts +4 -1
- package/src/self-implement/goal-author.ts +12 -2
- package/src/self-implement/goal-new-paths.ts +42 -0
- 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 +88 -19
- 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 +2 -2
- package/src/self-implement/scope-adjacency.ts +23 -0
- package/src/self-implement/seams.ts +42 -7
- 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/rejudge-tick.ts +142 -0
- package/src/task-agent/board.ts +92 -3
- package/src/task-agent/card-evidence.ts +88 -1
- package/src/task-agent/cover.ts +65 -0
- package/src/task-agent/parent-host.ts +27 -3
- package/src/task-agent/rejudge-on-head.ts +151 -7
- package/src/task-agent/review-result-capture.ts +3 -1
- package/src/task-agent/shadow.ts +12 -0
- package/src/task-agent/task-hand.ts +4 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +53 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +235 -28
- package/src/user-config.ts +18 -4
- 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/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-0eed0fb0aab716b6.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-aaae04ed1d32622f.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-3b9fc39362473ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c0ab229673a8b0eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.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-22725e2570f1126b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.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-901a1391b81053bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.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/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
package/src/intake-plane/lens.ts
CHANGED
|
@@ -43,8 +43,13 @@ export interface AnnotateIntakeLensResult {
|
|
|
43
43
|
capped: boolean;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/** 렌즈가 판정하는 갈래 — 하루 상한을 갈래별로 번갈아 나눈다(한 갈래가 많아도 다른 갈래가 0 이 되지 않게). */
|
|
47
|
+
export type LensLane = 'outbox' | 'github' | 'x';
|
|
48
|
+
export const LENS_LANES: readonly LensLane[] = ['outbox', 'github', 'x'];
|
|
49
|
+
|
|
46
50
|
interface GroupedItem {
|
|
47
51
|
id: string;
|
|
52
|
+
lane?: LensLane;
|
|
48
53
|
facts: { fact: string; current: string }[];
|
|
49
54
|
url?: string;
|
|
50
55
|
}
|
|
@@ -88,7 +93,7 @@ function groupOutbox(root: string, day: string): GroupedItem[] {
|
|
|
88
93
|
if (!id || !fact) continue;
|
|
89
94
|
let group = groups.get(id);
|
|
90
95
|
if (!group) {
|
|
91
|
-
group = { id, facts: [] };
|
|
96
|
+
group = { id, lane: 'outbox', facts: [] };
|
|
92
97
|
groups.set(id, group);
|
|
93
98
|
order.push(id);
|
|
94
99
|
}
|
|
@@ -113,12 +118,39 @@ function ledgerLensItems(root: string, day: string, existing: ReadonlySet<string
|
|
|
113
118
|
.map((fact) => ({ fact, current: '' }));
|
|
114
119
|
if (!facts.length) continue;
|
|
115
120
|
seen.add(item.id);
|
|
116
|
-
items.push({ id: item.id, facts, url: item.url });
|
|
121
|
+
items.push({ id: item.id, lane: source, facts, url: item.url });
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
return items;
|
|
120
125
|
}
|
|
121
126
|
|
|
127
|
+
/**
|
|
128
|
+
* 남은 몫(remaining)을 갈래별로 번갈아 채운다 — 매 칸마다 «이미 판정된 수 ⊕ 이번에 고른 수»가 가장 적은 갈래에서
|
|
129
|
+
* 하나를 꺼낸다(동점이면 LENS_LANES 순서). 비거나 다 쓴 갈래의 몫은 남은 갈래로 넘어간다. 총량은 remaining 을 넘지 않는다.
|
|
130
|
+
*/
|
|
131
|
+
export function fairLensBatch<T extends { id: string; lane?: LensLane }>(
|
|
132
|
+
pending: readonly T[],
|
|
133
|
+
doneByLane: Readonly<Partial<Record<LensLane, number>>>,
|
|
134
|
+
remaining: number,
|
|
135
|
+
): T[] {
|
|
136
|
+
const queues = new Map<LensLane, T[]>(LENS_LANES.map((lane) => [lane, []]));
|
|
137
|
+
for (const item of pending) queues.get(item.lane ?? 'outbox')!.push(item);
|
|
138
|
+
const used = new Map<LensLane, number>(LENS_LANES.map((lane) => [lane, doneByLane[lane] ?? 0]));
|
|
139
|
+
const picked = new Set<string>();
|
|
140
|
+
for (let n = 0; n < remaining; n++) {
|
|
141
|
+
let best: LensLane | undefined;
|
|
142
|
+
for (const lane of LENS_LANES) {
|
|
143
|
+
if (!queues.get(lane)!.length) continue;
|
|
144
|
+
if (best === undefined || used.get(lane)! < used.get(best)!) best = lane;
|
|
145
|
+
}
|
|
146
|
+
if (best === undefined) break;
|
|
147
|
+
picked.add(queues.get(best)!.shift()!.id);
|
|
148
|
+
used.set(best, used.get(best)! + 1);
|
|
149
|
+
}
|
|
150
|
+
// 원래 순서를 지킨다(흡수 → GitHub → X).
|
|
151
|
+
return pending.filter((item) => picked.has(item.id));
|
|
152
|
+
}
|
|
153
|
+
|
|
122
154
|
function judgedIds(file: string): Set<string> {
|
|
123
155
|
return new Set(readJsonl(file).flatMap((row) => typeof row.id === 'string' && row.id ? [row.id] : []));
|
|
124
156
|
}
|
|
@@ -171,10 +203,20 @@ export async function annotateIntakeLens(
|
|
|
171
203
|
const pending = items.filter((item) => !done.has(item.id));
|
|
172
204
|
const remaining = Math.max(0, LENS_DAILY_CAP - done.size);
|
|
173
205
|
const capped = pending.length > remaining;
|
|
174
|
-
const
|
|
206
|
+
const doneByLane: Partial<Record<LensLane, number>> = {};
|
|
207
|
+
for (const item of items) {
|
|
208
|
+
if (!done.has(item.id)) continue;
|
|
209
|
+
const lane = item.lane ?? 'outbox';
|
|
210
|
+
doneByLane[lane] = (doneByLane[lane] ?? 0) + 1;
|
|
211
|
+
}
|
|
212
|
+
const batch = capped ? fairLensBatch(pending, doneByLane, remaining) : pending;
|
|
175
213
|
if (capped) {
|
|
176
|
-
const
|
|
214
|
+
const chosen = new Set(batch.map((item) => item.id));
|
|
215
|
+
const skippedIds = pending.filter((item) => !chosen.has(item.id)).map((item) => item.id);
|
|
216
|
+
const byLane = (list: readonly GroupedItem[]) => Object.fromEntries(LENS_LANES.map((lane) =>
|
|
217
|
+
[lane, list.filter((item) => (item.lane ?? 'outbox') === lane).length]));
|
|
177
218
|
log('capped', { day, total: pending.length, judged: batch.length, skippedIds,
|
|
219
|
+
pendingByLane: byLane(pending), judgedByLane: byLane(batch), doneByLane,
|
|
178
220
|
...(skippedIds.length ? { marker: `외 ${skippedIds.length}건 · 원장 \`elanous intake items\`` } : {}) });
|
|
179
221
|
}
|
|
180
222
|
const judgeOne = deps.judge ?? ((input: LensJudgeInput) => defaultJudge(input));
|
|
@@ -12,6 +12,7 @@ import { getUserConfig } from '../user-config.js';
|
|
|
12
12
|
import { dateKey } from '../time/format.js';
|
|
13
13
|
import { cardIndexPath, CardStore, type TaskCard } from '../task-cards/card-store.js';
|
|
14
14
|
import { loadIntakeLedger, type IntakeItem } from './items.js';
|
|
15
|
+
import { RequirementLedger } from '../requirements/requirement-ledger.js';
|
|
15
16
|
import { parseRubric, rubricGrade, rubricScore } from '../release-loop/rubric.js';
|
|
16
17
|
|
|
17
18
|
export type RequirementSource = 'directive' | 'intake' | 'grounding' | 'coordination' | 'linear';
|
|
@@ -67,6 +68,8 @@ export interface FunnelOptions {
|
|
|
67
68
|
allowedLicenses?: readonly string[];
|
|
68
69
|
placement?: PlacementDeps;
|
|
69
70
|
adopt?: (candidate: RequirementCandidate, version: string, cellId: string, evidence: string) => void;
|
|
71
|
+
/** REQ-INTAKE-ALL (0.2.25) piece 1: REQ-LEDGER side-record — every candidate captured once (idempotent on candidate id); adopted decisions fold to `placed`. */
|
|
72
|
+
ledger?: RequirementLedger;
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
/** How many of the last 24 hours' unlinked directives the single P0 brief line names (the full backlog is one count). */
|
|
@@ -170,6 +173,15 @@ export function runRequirementFunnel(options: FunnelOptions): RequirementFunnelR
|
|
|
170
173
|
cellId, version: placement.version, rubric });
|
|
171
174
|
if (!isDirective) used++;
|
|
172
175
|
}
|
|
176
|
+
// REQ-INTAKE-ALL (0.2.25) piece 1: record every funnel candidate into the REQ-LEDGER side-ledger
|
|
177
|
+
// (idempotent on candidate id). The ledger is a side-record — a capture failure must not change the
|
|
178
|
+
// funnel result or any other command's default behavior (preservation contract).
|
|
179
|
+
if (options.ledger) {
|
|
180
|
+
try { captureFunnelCandidates(decisions, options.ledger); }
|
|
181
|
+
catch (error) {
|
|
182
|
+
debug.log('intake.requirement-funnel', 'ledger-capture-failed', { error: error instanceof Error ? error.message : String(error) });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
173
185
|
const unlinkedDirectives = [...directiveCandidates(options.historicalDirectives ?? []).filter(candidate =>
|
|
174
186
|
candidate.text && Number.isFinite(Date.parse(candidate.receivedAt)) && Date.parse(candidate.receivedAt) <= now.getTime()
|
|
175
187
|
&& !linkFor(candidate, cells) && !arrivals.some(arrival => arrival.id === candidate.id)),
|
|
@@ -202,7 +214,46 @@ export function runRequirementFunnel(options: FunnelOptions): RequirementFunnelR
|
|
|
202
214
|
return { counts, candidates: groups.size, decisions, unlinkedDirectives, briefItems };
|
|
203
215
|
}
|
|
204
216
|
|
|
205
|
-
/**
|
|
217
|
+
/**
|
|
218
|
+
* REQ-INTAKE-ALL (0.2.25) piece 1 — record the funnel's five entrances (directive · intake · grounding ·
|
|
219
|
+
* coordination · linear) into the REQ-LEDGER. Each decision captures one row per candidate (its `sources`
|
|
220
|
+
* members) with status `captured`, kind fixed to `fr`, source {kind, at: receivedAt}, statement = one-line
|
|
221
|
+
* text and tags = [priority] (the funnel's own P1 default when the candidate carries none). Idempotent on
|
|
222
|
+
* candidate id — re-running adds no rows. Adopted decisions fold their rows to `placed`. Per source with
|
|
223
|
+
* fresh rows it emits debug.log('requirements.intake', 'captured', {source, count}). Ledger validation
|
|
224
|
+
* (secret-shape rejection, allowlist) stays REQ-LEDGER's share; kind classification (REQ-KINDS) is a later
|
|
225
|
+
* piece — kind is fixed to `fr` here.
|
|
226
|
+
*/
|
|
227
|
+
export function captureFunnelCandidates(candidates: readonly RequirementDecision[], ledger: RequirementLedger): void {
|
|
228
|
+
const statuses = new Map(ledger.list().map(row => [row.id, row.status] as const));
|
|
229
|
+
const fresh = new Map<RequirementSource, number>();
|
|
230
|
+
for (const decision of candidates) {
|
|
231
|
+
for (const candidate of decision.sources) {
|
|
232
|
+
if (statuses.has(candidate.id)) continue;
|
|
233
|
+
// One bad candidate (secret-shaped text · unparseable time) must not stop the rest of the capture.
|
|
234
|
+
try {
|
|
235
|
+
const at = new Date(candidate.receivedAt).toISOString(); // ledger takes UTC `…Z` only; sources may carry offsets
|
|
236
|
+
ledger.capture({ id: candidate.id, statement: oneLine(candidate.text), kind: 'fr',
|
|
237
|
+
source: { kind: candidate.source, at }, tags: [candidate.priority ?? 'P1'] });
|
|
238
|
+
} catch (error) {
|
|
239
|
+
debug.log('intake.requirement-funnel', 'ledger-capture-failed', { id: candidate.id, source: candidate.source,
|
|
240
|
+
error: error instanceof Error ? error.message : String(error) });
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
statuses.set(candidate.id, 'captured');
|
|
244
|
+
fresh.set(candidate.source, (fresh.get(candidate.source) ?? 0) + 1);
|
|
245
|
+
}
|
|
246
|
+
if (decision.status !== 'adopted') continue;
|
|
247
|
+
for (const candidate of decision.sources) {
|
|
248
|
+
if (statuses.get(candidate.id) !== 'captured') continue;
|
|
249
|
+
ledger.place(candidate.id);
|
|
250
|
+
statuses.set(candidate.id, 'placed');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
for (const [source, count] of fresh) debug.log('requirements.intake', 'captured', { source, count });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Existing ledgers only; no source collector or sender is started here. Side effect: captures every candidate into this universe's REQ-LEDGER (REQ-INTAKE-ALL). */
|
|
206
257
|
export function readRequirementFunnel(options: { stateDir?: string; now?: Date; mode?: 'shadow' | 'live'; dailyCap?: number;
|
|
207
258
|
allowedLicenses?: readonly string[]; grounding?: readonly IncomingRequirement[]; coordination?: readonly IncomingRequirement[];
|
|
208
259
|
linear?: readonly IncomingRequirement[]; placement?: PlacementDeps } = {}): RequirementFunnelResult {
|
|
@@ -276,6 +327,7 @@ export function readRequirementFunnel(options: { stateDir?: string; now?: Date;
|
|
|
276
327
|
grounding: today(options.grounding ?? fromQueue('outbox/grounding.jsonl')),
|
|
277
328
|
coordination: today(options.coordination ?? cardRequests.coordination), linear: today(options.linear ?? cardRequests.linear) }, historicalDirectives, cells, now, mode,
|
|
278
329
|
dailyCap, adoptedToday: todayCount, allowedLicenses, placement: { ...options.placement, schedules },
|
|
330
|
+
ledger: new RequirementLedger({ stateDir }),
|
|
279
331
|
adopt: (candidate, version, cellId, evidence) => {
|
|
280
332
|
placeCell({ id: cellId, title: candidate.text, owner: candidate.owner ?? 'OP', priority: candidate.priority ?? 'P1',
|
|
281
333
|
predecessors: [], ...(candidate.deadlineVersion ? { deadlineVersion: candidate.deadlineVersion } : {}) }, { ...options.placement, now, schedules });
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// ── MK · 0.2.26 칸 CATALOG-FEED — signed catalog feed ──────────────────
|
|
2
|
+
//
|
|
3
|
+
// Folds a ModelCatalog into a verifiable feed document and verifies it on
|
|
4
|
+
// the receiving side:
|
|
5
|
+
// buildCatalogFeed — canonicalize (models sorted by id, stable-key JSON)
|
|
6
|
+
// + sha256 content digest.
|
|
7
|
+
// signCatalogFeed — ed25519 signature over the feed document (base64).
|
|
8
|
+
// verifyCatalogFeed — reject tampered / forged feeds with a reason.
|
|
9
|
+
//
|
|
10
|
+
// Design = 내부 문서 `RFC-smart-model-routing-and-catalog-2026-10-10` §판올림=카탈로그 동봉.
|
|
11
|
+
// This piece is the judgment only — key generation/holding, the daily
|
|
12
|
+
// publish cron, and fetching are the next slice.
|
|
13
|
+
//
|
|
14
|
+
// 🔎 세 얼굴 — 관측: verify 거부는 debug.log('intelligence-map.catalog-feed',
|
|
15
|
+
// 'verify-rejected', { reason }) 로 남는다. 판단 근거: digest 는 «정렬·키 고정
|
|
16
|
+
// JSON» 의 sha256 hex 라 서명과 무관하게 내용 변조를 가른다. 수복·인계: 거부
|
|
17
|
+
// 사유가 'digest-mismatch' 면 서명 키는 맞고 «내용»이 바뀌었다 — 발행 측 카탈로그를
|
|
18
|
+
// 다시 잰다; 'bad-signature' 면 키가 다르다.
|
|
19
|
+
|
|
20
|
+
import { createHash, sign as cryptoSign, verify as cryptoVerify } from 'node:crypto';
|
|
21
|
+
import { debug } from '../debug/log.js';
|
|
22
|
+
import type { ModelCatalog, ModelEntry } from './types.js';
|
|
23
|
+
|
|
24
|
+
export interface CatalogFeed {
|
|
25
|
+
schema: 'elanous.catalog-feed/1';
|
|
26
|
+
issuedAt: string;
|
|
27
|
+
models: ModelEntry[];
|
|
28
|
+
digest: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SignedCatalogFeed {
|
|
32
|
+
feed: CatalogFeed;
|
|
33
|
+
signature: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type CatalogFeedVerifyResult =
|
|
37
|
+
| { ok: true; feed: CatalogFeed }
|
|
38
|
+
| { ok: false; reason: 'bad-signature' | 'digest-mismatch' | 'schema' };
|
|
39
|
+
|
|
40
|
+
/** Canonical JSON — sorted object keys, deterministic spacing. Arrays keep
|
|
41
|
+
* order; `models` is sorted by `id` before this is applied. */
|
|
42
|
+
function canonicalJson(value: unknown): string {
|
|
43
|
+
// undefined follows JSON.stringify: dropped as an object key, null in an
|
|
44
|
+
// array — so a feed survives a JSON round trip with the same digest.
|
|
45
|
+
if (value === undefined) return 'null';
|
|
46
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value);
|
|
47
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
|
|
48
|
+
const obj = value as Record<string, unknown>;
|
|
49
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== undefined).sort();
|
|
50
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`).join(',')}}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** sha256 hex of the canonical (sorted, key-stable) JSON of the feed. */
|
|
54
|
+
function feedDigest(feed: Omit<CatalogFeed, 'digest'>): string {
|
|
55
|
+
return createHash('sha256').update(canonicalJson(feed)).digest('hex');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Fold a catalog into a signed-feed-ready document. `models` is sorted by
|
|
59
|
+
* id so byte-identical catalogs always produce the same digest. */
|
|
60
|
+
export function buildCatalogFeed(catalog: ModelCatalog, issuedAt: Date): CatalogFeed {
|
|
61
|
+
const models = [...catalog.models].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
62
|
+
const base = {
|
|
63
|
+
schema: 'elanous.catalog-feed/1' as const,
|
|
64
|
+
issuedAt: issuedAt.toISOString(),
|
|
65
|
+
models,
|
|
66
|
+
};
|
|
67
|
+
return { ...base, digest: feedDigest(base) };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Sign the feed document (whole feed, digest included) with an ed25519
|
|
71
|
+
* private key (PEM). Signature is base64 over the canonical JSON of the
|
|
72
|
+
* feed. */
|
|
73
|
+
export function signCatalogFeed(
|
|
74
|
+
feed: CatalogFeed,
|
|
75
|
+
privateKeyPem: string,
|
|
76
|
+
): { feed: CatalogFeed; signature: string } {
|
|
77
|
+
const signature = cryptoSign(null, Buffer.from(canonicalJson(feed)), privateKeyPem).toString('base64');
|
|
78
|
+
return { feed, signature };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Verify a signed feed: schema → content digest (recomputed, catches
|
|
82
|
+
* tampering that keeps the original digest) → signature. Rejected feeds
|
|
83
|
+
* are logged (제1원칙 관측) so the receiver's self-cognition can see why a
|
|
84
|
+
* feed was refused. */
|
|
85
|
+
export function verifyCatalogFeed(signed: SignedCatalogFeed, publicKeyPem: string): CatalogFeedVerifyResult {
|
|
86
|
+
if (signed === null || typeof signed !== 'object') return reject('schema');
|
|
87
|
+
const { feed, signature } = signed;
|
|
88
|
+
if (feed === null || typeof feed !== 'object' || feed.schema !== 'elanous.catalog-feed/1' || typeof feed.issuedAt !== 'string' || !Array.isArray(feed.models)
|
|
89
|
+
|| typeof feed.digest !== 'string' || typeof signature !== 'string' || !feed.models.every(isModelEntryShape)) {
|
|
90
|
+
return reject('schema');
|
|
91
|
+
}
|
|
92
|
+
const { digest: _digest, ...body } = feed;
|
|
93
|
+
if (feedDigest(body) !== feed.digest) return reject('digest-mismatch');
|
|
94
|
+
let sigOk = false;
|
|
95
|
+
try {
|
|
96
|
+
sigOk = cryptoVerify(null, Buffer.from(canonicalJson(feed)), publicKeyPem, Buffer.from(signature, 'base64'));
|
|
97
|
+
} catch {
|
|
98
|
+
sigOk = false;
|
|
99
|
+
}
|
|
100
|
+
if (!sigOk) return reject('bad-signature');
|
|
101
|
+
return { ok: true, feed };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Required ModelEntry fields at the receiving boundary — a signed feed with
|
|
105
|
+
* a model missing any of these is a schema failure, not a usable catalog. */
|
|
106
|
+
function isModelEntryShape(m: unknown): boolean {
|
|
107
|
+
if (m === null || typeof m !== 'object') return false;
|
|
108
|
+
const e = m as Record<string, unknown>;
|
|
109
|
+
const finite = (v: unknown) => typeof v === 'number' && Number.isFinite(v);
|
|
110
|
+
const strings = (v: unknown) => Array.isArray(v) && v.every((x) => typeof x === 'string');
|
|
111
|
+
return typeof e.id === 'string' && e.id.length > 0 && typeof e.provider === 'string' && typeof e.family === 'string'
|
|
112
|
+
&& finite(e.contextWindow) && finite(e.inputPerMtok) && finite(e.outputPerMtok)
|
|
113
|
+
&& typeof e.local === 'boolean' && strings(e.tags) && strings(e.bestFor);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function reject(reason: 'bad-signature' | 'digest-mismatch' | 'schema'): { ok: false; reason: typeof reason } {
|
|
117
|
+
debug.log('intelligence-map.catalog-feed', 'verify-rejected', { reason });
|
|
118
|
+
return { ok: false, reason };
|
|
119
|
+
}
|
|
@@ -103,6 +103,46 @@ export async function runModelWatchIntake(
|
|
|
103
103
|
return { candidates, proposal, perSource };
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
export type PriceField = 'inputPerMtok' | 'outputPerMtok';
|
|
107
|
+
|
|
108
|
+
export interface PriceChange {
|
|
109
|
+
id: string;
|
|
110
|
+
field: PriceField;
|
|
111
|
+
/** Price currently in the catalog (USD per 1M tokens). */
|
|
112
|
+
before: number;
|
|
113
|
+
/** Price the watched page reports. */
|
|
114
|
+
after: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const PRICE_FIELDS: readonly PriceField[] = ['inputPerMtok', 'outputPerMtok'];
|
|
118
|
+
|
|
119
|
+
/** Price differences between the catalog and the watched pages. The merge
|
|
120
|
+
* only fills undefined fields, so a repriced model shows up in
|
|
121
|
+
* `proposal.updated` with no trace of the new price — this reports it.
|
|
122
|
+
* A catalog price of 0 means "not priced yet" and is not a change. */
|
|
123
|
+
export function detectPriceChanges(result: Pick<WatchIntakeResult, 'candidates' | 'proposal'>): PriceChange[] {
|
|
124
|
+
const current = new Map(result.proposal.catalog.models.map((model) => [model.id, model]));
|
|
125
|
+
const updated = new Set(result.proposal.updated);
|
|
126
|
+
const changes: PriceChange[] = [];
|
|
127
|
+
for (const candidate of result.candidates) {
|
|
128
|
+
const entry = current.get(candidate.id);
|
|
129
|
+
if (!entry || !updated.has(candidate.id)) continue;
|
|
130
|
+
for (const field of PRICE_FIELDS) {
|
|
131
|
+
const before = entry[field];
|
|
132
|
+
const after = candidate[field];
|
|
133
|
+
if (typeof after !== 'number' || !Number.isFinite(after) || after < 0) continue;
|
|
134
|
+
if (typeof before !== 'number' || before <= 0 || before === after) continue;
|
|
135
|
+
changes.push({ id: candidate.id, field, before, after });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return changes;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function formatPriceChange(change: PriceChange): string {
|
|
142
|
+
const label = change.field === 'inputPerMtok' ? 'input' : 'output';
|
|
143
|
+
return `${change.id} ${label} $${change.before}→$${change.after} /Mtok`;
|
|
144
|
+
}
|
|
145
|
+
|
|
106
146
|
function errorMessage(error: unknown): string {
|
|
107
147
|
try {
|
|
108
148
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -21,7 +21,13 @@ import { lookupLlmTierSpec } from '../model-tier/index.js';
|
|
|
21
21
|
import type { LlmRunner } from '../model-tier/preset-suggest-llm.js';
|
|
22
22
|
import type { LLMProviderName } from '../user-config.js';
|
|
23
23
|
import { getUserConfig } from '../user-config.js';
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
detectPriceChanges,
|
|
26
|
+
formatPriceChange,
|
|
27
|
+
runModelWatchIntake,
|
|
28
|
+
type WatchIntakeResult,
|
|
29
|
+
type WatchPage,
|
|
30
|
+
} from './model-watch-intake.js';
|
|
25
31
|
|
|
26
32
|
export function getModelWatchProposalPath(home: string = homedir()): string {
|
|
27
33
|
return join(home, '.elanous', 'model-watch-proposals.jsonl');
|
|
@@ -93,6 +99,13 @@ export async function runModelIntelligenceWatch(
|
|
|
93
99
|
line: `Classification incomplete for zero-candidate sources: ${abnormalEmptySources.join(', ')}`,
|
|
94
100
|
});
|
|
95
101
|
}
|
|
102
|
+
const priceChanges = detectPriceChanges(result);
|
|
103
|
+
if (priceChanges.length > 0) {
|
|
104
|
+
await safeLog(log, 'intelligence-map.model-watch', 'price-changes', {
|
|
105
|
+
changes: priceChanges,
|
|
106
|
+
line: `Price changes vs catalog: ${priceChanges.map(formatPriceChange).join('; ')}`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
96
109
|
await safeLog(log, 'intelligence-map.model-watch', 'pass', {
|
|
97
110
|
pages: pages.length,
|
|
98
111
|
candidates: result.candidates.length,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** OpenRouter(`openrouter/…`) GLM·Kimi·Qwen 전용 도구 호출 규율 — 다른 군 상수와 합성하지 않는 독립 상수.
|
|
2
|
+
*
|
|
3
|
+
* 2026-10-11 GLM-PROMPT-TUNE 첫 조각: `llm.ts` 동결(RFC #25983)을 위해 상수를 이 파일로 옮겼다.
|
|
4
|
+
* 줄 둘을 추가했다 — 실측 약점 둘을 겨냥한다:
|
|
5
|
+
* ⑴ 그라운딩 비교 8회 중 GLM 3회 전부 «Grep 으로만 확인하고 Read 는 안 했다»고 스스로 적고
|
|
6
|
+
* 그 경로를 증거로 써 grounding-evidence 기각
|
|
7
|
+
* ⑵ 상 칸에서 PR 없이 라운드만 도는 no-progress(부검반 ×26)
|
|
8
|
+
* 다른 군(codex·grok·local·claude·gemini·gpt·other)의 요청 바이트는 불변 — 이 상수는
|
|
9
|
+
* open-weight 계열에만 주입된다(`TOOL_DISCIPLINE_BY_FAMILY`).
|
|
10
|
+
*
|
|
11
|
+
* ⛔ `llm.ts` 의 `selectIntentClassificationMessages` 가 이 상수와 «정확 일치»로 분류기를
|
|
12
|
+
* 걸러 내므로, 주입부는 상수를 그대로 싣는다(합성 금지). */
|
|
13
|
+
export const OPEN_WEIGHT_TOOL_DISCIPLINE = [
|
|
14
|
+
'[open-weight tool-use discipline]',
|
|
15
|
+
'- 도구로 할 수 있는 일은 이번 응답에서 바로 도구를 호출하라. "먼저 읽겠다" 또는 "확인하겠다" 같은 계획만 말하고 응답을 끝내지 마라.',
|
|
16
|
+
'- 작업을 시작하는 첫 응답에는 도구 호출이 하나 이상 있어야 한다.',
|
|
17
|
+
'- 도구 호출 인자는 해당 도구의 스키마에 맞는 JSON 으로 내라.',
|
|
18
|
+
'- 충분한 근거가 모이면 도구 호출 없이 최종 답을 평문으로 써서 끝내라.',
|
|
19
|
+
'- 증거·근거로 적는 파일은 이번 작업에서 Read 로 연 파일만 — Grep·Glob 결과만으로 내용을 단정하지 마라.',
|
|
20
|
+
'- 구현을 끝냈다고 말하기 전에 바꾼 파일과 돌린 시험 명령·결과를 적어라.',
|
|
21
|
+
].join('\n');
|
package/src/llm.ts
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from './session-runtime/retry-policy.js';
|
|
43
43
|
import { fetchApiWithRetry, OverloadFailoverError, type FetchApiWithRetryOpts } from './session-runtime/retry-api.js';
|
|
44
44
|
import { BedrockProvider, isBedrockCompatibleModel, makeBedrockProvider } from './llm/bedrock-provider.js';
|
|
45
|
+
import { OPEN_WEIGHT_TOOL_DISCIPLINE } from './llm/open-weight-discipline.js';
|
|
45
46
|
import { makeZaiCodingPlanProvider, zaiCodingPlanAvailable } from './llm/zai-coding-plan.js';
|
|
46
47
|
import { isOpenRouterDeepSeekWireModel, nonEmptyReasoningDetails, openRouterDeepSeekCatalogEffort, openRouterDeepSeekEffort, openRouterDeepSeekRequestExtras, openRouterNeedsKimiToolSchema } from './llm/openrouter-deepseek.js';
|
|
47
48
|
import { resolveModelAlias } from './intelligence-map/model-alias.js';
|
|
@@ -5165,14 +5166,9 @@ const LOCAL_TOOL_DISCIPLINE = [
|
|
|
5165
5166
|
'- 범위 읽기만으로 판단할 수 없을 때에만 전체 읽기를 선택하고, 읽은 뒤에는 다음 행동을 계속 결정하라.',
|
|
5166
5167
|
].join('\n');
|
|
5167
5168
|
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
'- 도구로 할 수 있는 일은 이번 응답에서 바로 도구를 호출하라. "먼저 읽겠다" 또는 "확인하겠다" 같은 계획만 말하고 응답을 끝내지 마라.',
|
|
5172
|
-
'- 작업을 시작하는 첫 응답에는 도구 호출이 하나 이상 있어야 한다.',
|
|
5173
|
-
'- 도구 호출 인자는 해당 도구의 스키마에 맞는 JSON 으로 내라.',
|
|
5174
|
-
'- 충분한 근거가 모이면 도구 호출 없이 최종 답을 평문으로 써서 끝내라.',
|
|
5175
|
-
].join('\n');
|
|
5169
|
+
// ⭐ 2026-10-11 GLM-PROMPT-TUNE: 상수 정의는 `src/llm/open-weight-discipline.ts` 로 옮겼다(llm.ts 동결 RFC #25983).
|
|
5170
|
+
// llm.ts 는 이 재수출만 남긴다 — 기존 임포트 경로(`./llm.js`)를 그대로 지킨다.
|
|
5171
|
+
export { OPEN_WEIGHT_TOOL_DISCIPLINE };
|
|
5176
5172
|
|
|
5177
5173
|
/** 모델군 → 그 군에 주입할 툴 규율(없으면 `null`). **능력 술어 판** — 2026-08-14.
|
|
5178
5174
|
*
|
|
@@ -64,7 +64,7 @@ export const FEATURE_MATURITY = {
|
|
|
64
64
|
pod: 'beta', browser: 'beta', questions: 'beta', usage: 'stable', live: 'beta',
|
|
65
65
|
research: 'beta', release: 'beta', know: 'beta', freeze: 'beta', flow: 'beta', seat: 'beta', hq: 'beta', steward: 'beta', coord: 'beta', context: 'beta', 'model-watch': 'beta', doctor: 'stable',
|
|
66
66
|
control: 'beta', resources: 'beta', hooks: 'beta', setup: 'stable', start: 'stable',
|
|
67
|
-
grounding: 'beta', graph: 'beta', loop: 'stable', card: 'stable', 'launch-head': 'beta',
|
|
67
|
+
grounding: 'beta', graph: 'beta', loop: 'stable', resource: 'beta', card: 'stable', 'launch-head': 'beta',
|
|
68
68
|
a2a: 'beta', plugin: 'stable', make: 'beta', skills: 'beta', connect: 'beta', import: 'beta',
|
|
69
69
|
persona: 'beta', team: 'beta', 'team-set': 'beta', market: 'beta', directive: 'stable', connector: 'beta', storyboard: 'beta',
|
|
70
70
|
python: 'beta', 'self-update': 'stable', 'measure-fabric-arc-ab': 'beta', mcp: 'beta',
|
|
@@ -505,6 +505,8 @@ export interface NexusHttpServerOpts {
|
|
|
505
505
|
draftMetrics?: DraftMetricsSource;
|
|
506
506
|
decisions?: Pick<DecisionsRouteDeps, 'ledger'>;
|
|
507
507
|
opsBoard?: Pick<OpsBoardDeps, 'openStore'>;
|
|
508
|
+
/** `GET /api/task-agent/board` 의 원장 경로 — 생략하면 인스턴스의 task-agent-actions.json. */
|
|
509
|
+
taskAgentStatePath?: string;
|
|
508
510
|
cardFollowup?: CardFollowupJobs;
|
|
509
511
|
skillExec?: SkillExecJobs;
|
|
510
512
|
execRequests?: ExecRequestRunner;
|
|
@@ -943,6 +945,8 @@ function defaultCardFollowupJobs(): CardFollowupJobs {
|
|
|
943
945
|
return cardFollowupJobs ??= createCardFollowupJobs();
|
|
944
946
|
}
|
|
945
947
|
|
|
948
|
+
const TASK_AGENT_BOARD_PATH = '/api/task-agent/board';
|
|
949
|
+
|
|
946
950
|
let skillExecJobs: SkillExecJobs | undefined;
|
|
947
951
|
function defaultSkillExecJobs(): SkillExecJobs {
|
|
948
952
|
return skillExecJobs ??= createSkillExecJobs();
|
|
@@ -1521,6 +1525,24 @@ export async function routeRequest(
|
|
|
1521
1525
|
...opts.opsBoard,
|
|
1522
1526
|
});
|
|
1523
1527
|
}
|
|
1528
|
+
// TASKS-ON-TA-LEDGER — 읽기 전용 · 이 경로는 `/v1/` 밖이라 default-deny 관문이 못 덮는다 → 여기서 owner 인증을 직접 건다.
|
|
1529
|
+
if (pathname === TASK_AGENT_BOARD_PATH) {
|
|
1530
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-runtime-not-wired' }, 503);
|
|
1531
|
+
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1532
|
+
if (method !== 'GET') return jsonResponse({ error: 'method-not-allowed', method }, 405);
|
|
1533
|
+
// 동적 import — 다른 무거운 라우트(skill-exec · card-followup)와 같은 꼴: task-agent 모듈 트리를 데몬 기동 경로에 싣지 않는다.
|
|
1534
|
+
const [{ taskAgentBoard }, { taskAgentStatePath }] = await Promise.all([import('../../task-agent/board.js'), import('../../task-agent/task-hand.js')]);
|
|
1535
|
+
try {
|
|
1536
|
+
// progress 관측은 동기 수 초라 요청이 명시할 때만(`?progress=1`) — 기본 응답은 progress=null(UX 수확 리뷰 should-fix).
|
|
1537
|
+
const withProgress = new URL(req.url, 'http://local').searchParams.get('progress') === '1';
|
|
1538
|
+
const response = taskAgentBoard(opts.taskAgentStatePath ?? taskAgentStatePath(), { withProgress });
|
|
1539
|
+
debug.log('task-agent', 'board-served', { projects: response.board.length });
|
|
1540
|
+
return jsonResponse(response);
|
|
1541
|
+
} catch (error) {
|
|
1542
|
+
debug.log('task-agent', 'board-read-failed', { error: error instanceof Error ? error.message : String(error) });
|
|
1543
|
+
return jsonResponse({ error: 'task-agent-ledger-unreadable' }, 503);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1524
1546
|
if (method === 'GET' && pathname === DECISIONS_PATH) {
|
|
1525
1547
|
return handleDecisions(req, {
|
|
1526
1548
|
authorize: request => !!opts.metaApi && checkAuth(request, opts.metaApi),
|
|
@@ -74,6 +74,9 @@ interface RotationDecision {
|
|
|
74
74
|
readonly resetCreditAccount?: string;
|
|
75
75
|
/** SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분에 닿아 `no-candidate` 로 넘겼을 때만 있다(잔액은 «알려진» 값). */
|
|
76
76
|
readonly creditReserveHit?: { readonly balance: number; readonly reserve: number };
|
|
77
|
+
/** CREDIT-SPEND-ORDER — 구독·리셋권이 다 없어 «다른 계정의 선불 크레딧»으로 옮긴 `rotated` 일 때만 true.
|
|
78
|
+
* 이 이동도 크레딧 진입이다 — 호출부가 💳 알림 ⊕ `credit-spend-start` 를 낸다(10-12 S2: 이 갈래만 알림 0). */
|
|
79
|
+
readonly creditEntry?: true;
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
/** ⛔ 비공개 — 호출자는 객체 리터럴로 준다(구조적 타이핑). */
|
|
@@ -261,7 +264,7 @@ export function decideCodexRotation(input: RotationInput): RotationDecision {
|
|
|
261
264
|
const curHas = input.currentHasCredits ?? self?.hasCredits;
|
|
262
265
|
const currentDry = curHas === false || (typeof cur === 'number' && cur <= floor);
|
|
263
266
|
if (richest && (currentDry || (typeof cur === 'number' && richest.creditBalance! > cur * 1.2))) {
|
|
264
|
-
return { reason: 'rotated', candidateCount, accountThresholds, to: richest };
|
|
267
|
+
return { reason: 'rotated', candidateCount, accountThresholds, to: richest, creditEntry: true };
|
|
265
268
|
}
|
|
266
269
|
// 🩸 10-11: 크레딧이 0 이 돼도 여기 머물러 codex 로 계속 쐈다. 잔액이 «알려져 있고» 예비분 이하이며
|
|
267
270
|
// 예비분을 넘는 다른 계정도 없으면 «갈 곳 없음» — 폴백 체인이 다음 칸을 정한다. 모르면 종전대로 머문다.
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
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 {
|
|
@@ -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
|
/** 지금 계정의 크레딧 신호 — 판정 입력 두 칸. 신호를 이 계정에 귀속할 수 없으면 비운다(모른다). */
|
|
@@ -491,7 +501,7 @@ function acquireCreditSpendAlertLock(path: string, account: string): boolean {
|
|
|
491
501
|
/** UTC 일자별 성공한 계정 알림만 기록한다. 잠근 채 발송하여 동시 런도 중복 발송하지 않는다. */
|
|
492
502
|
function notifyCreditSpendStart(
|
|
493
503
|
account: string,
|
|
494
|
-
reason: 'credits-allowed' | 'credit-pace',
|
|
504
|
+
reason: 'credits-allowed' | 'credit-pace' | 'credits-rotated',
|
|
495
505
|
usage: readonly RotationCandidate[],
|
|
496
506
|
now: number,
|
|
497
507
|
counterPath: string,
|
|
@@ -793,11 +803,14 @@ export function resolveCodexAccountForRun(
|
|
|
793
803
|
});
|
|
794
804
|
observeRotation(decision, current.name);
|
|
795
805
|
// 발송 의무는 이 실행 경로에서 잠금 해제까지 기다린 뒤 하루 카운터에 기록한다.
|
|
796
|
-
|
|
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)) {
|
|
797
810
|
// 시험 러너 가드(autoConsume 의 test-runtime-guard 와 같은 관용구) — 카운터를 주입 안 한 시험이 실제 카운터·송신기에 닿지 않는다.
|
|
798
811
|
debug.log('oauth.codex-account', 'credit-spend-alert-skipped', { account: decision.to?.name ?? current.name, reason: 'test-runtime-guard' });
|
|
799
|
-
} else if (
|
|
800
|
-
notifyCreditSpendStart(decision.to?.name ?? current.name,
|
|
812
|
+
} else if (creditSpendReason) {
|
|
813
|
+
notifyCreditSpendStart(decision.to?.name ?? current.name, creditSpendReason, candidates, now,
|
|
801
814
|
deps.counterPath ?? join(codexCredentialRoot(), 'budget', 'codex-credit-spend-alert.json'));
|
|
802
815
|
}
|
|
803
816
|
// 순서 ② — 구독 남은 계정이 없고 리셋권이 있으면 «스스로 1개» 쓴다(일일 상한 · 비동기 · 이번 호출은 종전대로 머문다).
|
|
@@ -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
|
}
|