elanous 0.2.23 → 0.2.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +1 -0
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +36 -0
- package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +148 -0
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1454-37fd16f479f5554a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8532.a86e99acf9b761cb.js → 1516.83dd2c1b86b4e507.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{89849432.9eaa2f4c9c010965.js → 16e57f67.3ea19e893461e611.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1505.5826671109111e75.js → 1743.563d3168e95825ef.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +32 -0
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2846.d6a433b8663819a5.js +309 -0
- package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{5967-c0a80f8ffe5d4050.js → 3259-86f3be56e43eaf6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +287 -0
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5578.ac963634373b28c6.js → 4084.15ecaf4240bd9e77.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8438.ee7f0df3b3f6fcb4.js → 4204.a409ab6250c0f6a8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +8 -0
- package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7905.b230b9d06cb4ad5d.js → 4593.10f5b9bd702d4a6c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{8569.b853a8daa8f31d12.js → 5081.a240b63fad28663a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2528.0af5c0e1fad88df6.js → 5408.377c8c543635b81f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9502-32c5dc22e8f120f5.js → 5492-e05e26a033ba80d2.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5785-ea8d2c633b6688e3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +23 -0
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5974.360f8441eb0ac1ec.js → 6196.34d6b229079e9e28.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +77 -0
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +64 -0
- package/apps/pwa/out/_next/static/chunks/{ce383d63.d2ede338788ed18e.js → 65ebff95.081daeff622d238e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{83cfc5c8.349535543c1548b6.js → 6def8a8e.c81f9ca41028eccf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2721.bc9a8f36bd85c07a.js → 7483.ba01c6c209b81bba.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{6702.ebbd165d5e4a4a14.js → 7752.5cbdd0b433c54af9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8925-2abfb48af477fb7f.js → 8085-1e5fce59500a2cc2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{b4e12462-5fab4a813a63dadd.js → 83a80514-b897b64df43ce108.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +93 -0
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{8264.00e434fbd02e9311.js → 8578.dff22d988cc2b106.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +115 -0
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +41 -0
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +74 -0
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7518.49161e8f5814abdb.js → 9311.24c8f5ea793253dd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9976.8f28864317639fe6.js → 94.4cfed21c0b781a06.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +90 -0
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0e3acd34.d42b2ef87fdf4234.js → 973cbf1b.3bbcf2b41548eca7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6571-926ddf024a6ad5df.js → 9917-9e26abc5f7772735.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +79 -0
- package/apps/pwa/out/_next/static/chunks/{740.90b31555290236a9.js → 9974.e77b4ff4884557b3.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{4c5e95ce.83e9b16add6fcd8c.js → ab4d57c2.e90bc2cb31949045.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ad3bd8084048bee4.js → page-b12149c51f7d04b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-305cd294e754906e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-a648bc464c9dc754.js → page-dea4b795741126fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45889e7070d11126.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-16a2e893f83ae4d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-56888bc744e08dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-952c6ceec6d9de38.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-6d0202af568f4c63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4fb6fc34e20c07b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-e9502921f4f01b1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-b6169ea2f09cf287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6a14333d1b1b3967.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8c91a9a66c9ec90a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-48fb31810693c357.js → page-4e634c5b98fd4e93.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-cb154acadb025414.js → page-b9cc8a10bc6078b4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-3d3fc73dd187ed52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9c04dac0831c2bbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-04de9ca6d52a3893.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-62527677bbc2fdc4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9a2e09c4a311764c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-bfeb35d69e8b24bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-89cb33bced824e4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-6445ac4cbb8dd869.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-20162174b77f96cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-05a4b2c9b91034aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{53746282.1be36038d1abd949.js → e117f801.e92bf10242653497.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{0673cc54.8e2ef1c23e49e190.js → f4dfbfc0.a69fb12f854882aa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +1 -0
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/graphs/release/release-loop.yaml +5 -5
- package/graphs/steward/recipes.yaml +4 -0
- package/graphs/steward/steward.yaml +10 -1
- package/package.json +1 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/bench-report.ts +46 -1
- package/scripts/ci-typecheck-changed.ts +73 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/release-loop/auto-approve-node.ts +6 -0
- package/scripts/release-loop/gate-closure.ts +286 -0
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-node.ts +333 -37
- package/scripts/release-loop/gate-partial.ts +34 -6
- package/scripts/release-loop/ops-upgrade-node.ts +63 -42
- package/scripts/release-loop/publish-node.ts +6 -0
- package/scripts/release-loop/resume-release.ts +46 -13
- package/scripts/release-loop/resume.ts +110 -4
- package/scripts/release-loop/unattended-release.ts +22 -7
- package/scripts/tsc-baseline-cache.ts +172 -0
- package/scripts/usage-rollup.ts +72 -6
- package/scripts/ux-sim.ts +30 -1
- package/skills/youtube-master/scripts/main.ts +4 -1
- package/skills/youtube-master/src/obsidian.ts +9 -0
- package/src/agent/run-context.ts +10 -0
- package/src/agent-mission/driver.ts +18 -3
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +8 -2
- package/src/agent-substrate/acp-implementer.ts +146 -0
- package/src/agent-substrate/pr-reviewer.ts +60 -13
- package/src/agent-substrate/self-review-cli.ts +170 -15
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/budget/cost-tier-advisor.ts +91 -0
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/shadow-arms.ts +77 -0
- package/src/budget/types.ts +10 -2
- package/src/budget/unified-usage.ts +256 -10
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/doctor-cli.ts +21 -0
- package/src/cli/friendly-errors.ts +113 -0
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/intake-cli.ts +3 -1
- package/src/cli/log-event-names.ts +4 -0
- package/src/cli/memory-cli.ts +182 -0
- package/src/cli/model-watch-cli.ts +4 -1
- package/src/cli/pr-cli.ts +62 -5
- package/src/cli/pr-land-overlap-evidence.ts +160 -12
- package/src/cli/pr-land-pod-shadow.ts +54 -0
- package/src/cli/release-cli.ts +27 -16
- package/src/cli/release-run-if-ready.ts +11 -0
- package/src/cli/resource-cli.ts +48 -0
- package/src/cli/retro-cli.ts +12 -3
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/seat-requests-cli.ts +25 -0
- package/src/cli/self-update.ts +104 -0
- package/src/cli/tasks-cli.ts +139 -10
- package/src/cli/usage-cli.ts +93 -8
- package/src/compact/verify-probe.ts +23 -3
- package/src/context-card/index.ts +50 -0
- package/src/control/control-status.ts +30 -1
- package/src/core-turn/run-goal-loop.ts +5 -4
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/index.ts +18 -276
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
- package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
- package/src/dashboard/stale-install-check.ts +11 -0
- package/src/debug/log-diet.ts +53 -10
- package/src/debug/log.ts +19 -1
- package/src/domains/morning-essential.ts +18 -3
- package/src/domains/release-tool.ts +43 -0
- package/src/error-report/report.ts +21 -4
- package/src/execution-loop/launch-gate.ts +158 -2
- package/src/fleet/host-doctor.ts +375 -0
- package/src/github/pr-labels.ts +1 -0
- package/src/goals/judge.ts +20 -6
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +176 -11
- package/src/graph-wizard/archetypes.ts +14 -8
- package/src/graph-wizard/generate.ts +77 -1
- package/src/grok/usage.ts +23 -2
- package/src/grok.ts +13 -7
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +10 -2
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +176 -52
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-stop.ts +82 -10
- package/src/harness/harness-substrate-default.ts +142 -7
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/seats.ts +38 -22
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +110 -186
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/collect-github.ts +7 -2
- package/src/intake-plane/lens.ts +46 -4
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intake-plane/requirement-funnel.ts +53 -1
- package/src/intelligence-map/catalog-feed.ts +119 -0
- package/src/intelligence-map/model-catalog.ts +72 -0
- package/src/intelligence-map/model-watch-intake.ts +40 -0
- package/src/intelligence-map/model-watch-mission.ts +14 -1
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +114 -41
- package/src/llm/bedrock.ts +174 -28
- package/src/llm/open-weight-discipline.ts +21 -0
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +91 -24
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/maturity/feature-maturity.ts +3 -3
- package/src/model-tier/llm-tier-map.ts +9 -5
- package/src/models/prompts.ts +2 -1
- package/src/mss/logging/log-store.ts +58 -11
- package/src/nexus/api/http-server.ts +22 -0
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/index.ts +7 -75
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +43 -3
- package/src/oauth/codex-account-store.ts +339 -27
- package/src/oauth/codex-quota-policy.ts +33 -4
- package/src/oauth/fallback-chain.ts +53 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/preview/terminal.ts +15 -5
- package/src/project/project-store.ts +20 -0
- package/src/prompt-cache/openai.ts +3 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +23 -0
- package/src/release-loop/auto-start.ts +7 -5
- package/src/release-loop/checklist.ts +11 -1
- package/src/release-loop/gate-shards.ts +4 -0
- package/src/release-loop/light-rc.ts +84 -13
- package/src/release-loop/merged-pr-checklist.ts +35 -5
- package/src/release-loop/placement.ts +16 -1
- package/src/release-loop/rehearsal.ts +1 -1
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +5 -5
- package/src/seat-loop/duty-ledger.ts +64 -0
- package/src/seat-loop/seat-loop.ts +32 -10
- package/src/self-dev/decompose.ts +37 -3
- package/src/self-dev/dev-cli.ts +44 -10
- package/src/self-dev/dev-pipeline.ts +39 -9
- package/src/self-dev/draft-residue.ts +27 -5
- package/src/self-dev/draft-sweep.ts +151 -0
- package/src/self-dev/fabric-decompose-adapter.ts +9 -2
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/orchestrate-cli.ts +25 -3
- package/src/self-dev/orchestrate.ts +41 -6
- package/src/self-dev/run-supervisor.ts +218 -15
- package/src/self-dev/run-types.ts +13 -0
- package/src/self-dev/supervisor-verdict-edges.ts +1 -0
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/gate-cli.ts +29 -10
- package/src/self-implement/gate-remote.ts +4 -1
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +36 -11
- package/src/self-implement/goal-new-paths.ts +42 -0
- package/src/self-implement/graph-overlay-condition.ts +28 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/host-regate.ts +124 -30
- package/src/self-implement/importer-test-index.ts +3 -1
- package/src/self-implement/l8-merge-queue.ts +80 -2
- package/src/self-implement/merge-train.ts +19 -0
- package/src/self-implement/off-diff-evidence.ts +40 -1
- package/src/self-implement/orchestrator.ts +230 -32
- package/src/self-implement/premise-review.ts +159 -0
- package/src/self-implement/regate-detail.ts +79 -0
- package/src/self-implement/review-deferred-to-host.ts +21 -0
- package/src/self-implement/rework-budget-judgment.ts +23 -3
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/scope-adjacency.ts +23 -0
- package/src/self-implement/seams.ts +89 -8
- package/src/self-implement/self-implement-cli.ts +9 -4
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/tools/agent.ts +16 -1
- package/src/skills/tools/persistent-grounding.ts +11 -1
- package/src/skills/tools/shell.ts +33 -1
- package/src/steward/launch.ts +5 -4
- package/src/steward/rejudge-tick.ts +142 -0
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +83 -22
- package/src/task-agent/actions.ts +62 -5
- package/src/task-agent/board.ts +92 -3
- package/src/task-agent/card-evidence.ts +88 -1
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +166 -3
- package/src/task-agent/judge.ts +16 -0
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/live-move-history.ts +87 -1
- package/src/task-agent/live-moves.ts +350 -20
- package/src/task-agent/parent-host.ts +27 -3
- package/src/task-agent/rejudge-on-head.ts +223 -24
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/review-result-capture.ts +3 -1
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +65 -9
- package/src/task-agent/task-hand.ts +57 -7
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -4
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +432 -35
- package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +69 -15
- package/src/ux-sim/fault-cred-expiry.ts +100 -0
- package/src/ux-sim/fault-pod-death.ts +74 -0
- package/src/ux-sim/fault-pool-cap.ts +81 -0
- package/src/version/packed-revision.json +1 -1
- package/src/webclone/qa-table.ts +22 -0
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
- package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-6168a7c43e6ef8f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +0 -1
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
- /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
3
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
6
|
+
|
|
7
|
+
export interface DevProjectDeps {
|
|
8
|
+
git?: (dir: string, args: readonly string[]) => string | null;
|
|
9
|
+
stateDir?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface DevProjectRegistry {
|
|
13
|
+
projects: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface DevProjectCache {
|
|
17
|
+
identityKey: string;
|
|
18
|
+
devProject: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ULID_ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
22
|
+
|
|
23
|
+
export function resolveDevProject(dir: string, deps: DevProjectDeps = {}): string {
|
|
24
|
+
const suppliedDir = resolve(dir);
|
|
25
|
+
const git = deps.git ?? runGit;
|
|
26
|
+
const gitRoot = git(suppliedDir, ['rev-parse', '--show-toplevel'])?.trim();
|
|
27
|
+
const root = gitRoot ? resolve(gitRoot) : suppliedDir;
|
|
28
|
+
let identityKey: string;
|
|
29
|
+
// A repo with no commit yet (`git init` only) has no first commit to anchor on — it falls back to
|
|
30
|
+
// the path identity like a plain folder until its first commit exists.
|
|
31
|
+
const rootCommits = gitRoot
|
|
32
|
+
? git(root, ['rev-list', '--max-parents=0', 'HEAD'])?.trim().split(/\s+/).filter(Boolean) ?? []
|
|
33
|
+
: [];
|
|
34
|
+
|
|
35
|
+
if (rootCommits.length > 0) {
|
|
36
|
+
const firstCommit = rootCommits.length === 1 ? rootCommits[0]! : rootCommits
|
|
37
|
+
.map((commit) => ({
|
|
38
|
+
commit,
|
|
39
|
+
timestamp: Number(git(root, ['show', '-s', '--format=%ct', commit])?.trim()),
|
|
40
|
+
}))
|
|
41
|
+
.filter(({ timestamp }) => Number.isFinite(timestamp))
|
|
42
|
+
.sort((left, right) => left.timestamp - right.timestamp || left.commit.localeCompare(right.commit))[0]?.commit;
|
|
43
|
+
if (!firstCommit) throw new Error(`Unable to resolve oldest root commit for git project at ${root}`);
|
|
44
|
+
const remote = git(root, ['remote', 'get-url', 'origin']);
|
|
45
|
+
identityKey = `git:${firstCommit}:${normalizeRemoteUrl(remote ?? '')}`;
|
|
46
|
+
} else {
|
|
47
|
+
identityKey = `path:${createHash('sha256').update(root).digest('hex')}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const stateDir = resolve(deps.stateDir ?? elanousStateRoot());
|
|
51
|
+
const registryPath = join(stateDir, 'dev-projects.json');
|
|
52
|
+
const registry = readRegistry(registryPath);
|
|
53
|
+
const id = registry.projects[identityKey] ?? newDevProjectId();
|
|
54
|
+
if (!registry.projects[identityKey]) {
|
|
55
|
+
registry.projects[identityKey] = id;
|
|
56
|
+
writeJsonAtomically(registryPath, registry);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The cache is disposable (RFC §4f): a read-only root must not stop the id from resolving.
|
|
60
|
+
try {
|
|
61
|
+
writeJsonAtomically(join(root, '.elanous', 'project.json'), { identityKey, devProject: id } satisfies DevProjectCache);
|
|
62
|
+
} catch { /* cache only */ }
|
|
63
|
+
return id;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function runGit(dir: string, args: readonly string[]): string | null {
|
|
67
|
+
try {
|
|
68
|
+
return execFileSync('git', ['-C', dir, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizeRemoteUrl(remote: string): string {
|
|
75
|
+
const value = remote.trim();
|
|
76
|
+
if (!value) return '';
|
|
77
|
+
|
|
78
|
+
const scp = /^(?![a-z][a-z0-9+.-]*:\/\/)(?:[^@/]+@)?([^:/]+):(.+)$/.exec(value);
|
|
79
|
+
if (scp) return normalizeRemotePath(`${scp[1]!.toLowerCase()}/${scp[2]}`);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const url = new URL(value);
|
|
83
|
+
return normalizeRemotePath(`${url.hostname.toLowerCase()}${url.pathname}`);
|
|
84
|
+
} catch {
|
|
85
|
+
return normalizeRemotePath(resolve(value));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function normalizeRemotePath(value: string): string {
|
|
90
|
+
return value.replace(/\\/g, '/').replace(/\/+$/, '').replace(/\.git$/i, '');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The registry is the source of truth for prj- ids. A missing file starts a fresh registry; an
|
|
95
|
+
* existing but unreadable/corrupt one throws instead of silently re-issuing every project a new id.
|
|
96
|
+
*/
|
|
97
|
+
function readRegistry(path: string): DevProjectRegistry {
|
|
98
|
+
let raw: string;
|
|
99
|
+
try {
|
|
100
|
+
raw = readFileSync(path, 'utf8');
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projects: {} };
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
let parsed: Partial<DevProjectRegistry> | undefined;
|
|
106
|
+
try { parsed = JSON.parse(raw) as Partial<DevProjectRegistry>; } catch { parsed = undefined; }
|
|
107
|
+
if (parsed?.projects && typeof parsed.projects === 'object' && !Array.isArray(parsed.projects)) {
|
|
108
|
+
return { projects: parsed.projects as Record<string, string> };
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`dev-projects registry is corrupt: ${path}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function writeJsonAtomically(path: string, value: unknown): void {
|
|
114
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
115
|
+
const temporaryPath = join(dirname(path), `.${basename(path)}.${process.pid}.${newDevProjectId()}.tmp`);
|
|
116
|
+
writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx' });
|
|
117
|
+
renameSync(temporaryPath, path);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function newDevProjectId(): string {
|
|
121
|
+
const now = BigInt(Date.now());
|
|
122
|
+
let timestamp = '';
|
|
123
|
+
for (let index = 9; index >= 0; index -= 1) {
|
|
124
|
+
timestamp += ULID_ALPHABET[Number((now >> BigInt(index * 5)) & 31n)];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const entropy = BigInt(`0x${randomBytes(10).toString('hex')}`);
|
|
128
|
+
let random = '';
|
|
129
|
+
for (let index = 15; index >= 0; index -= 1) {
|
|
130
|
+
random += ULID_ALPHABET[Number((entropy >> BigInt(index * 5)) & 31n)];
|
|
131
|
+
}
|
|
132
|
+
return `prj-${timestamp}${random}`;
|
|
133
|
+
}
|
package/src/instance/resolve.ts
CHANGED
|
@@ -56,6 +56,30 @@ export function resolveInstance(deps: ResolveDeps = {}): InstanceResolution {
|
|
|
56
56
|
return { kind: 'test', root: normRoot(join(process.cwd(), '.elanous-test')), layer: 'default', why: '소스 트리 밖 실행(격리)' };
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** 부모가 도장으로 물려준 우주와 자식이 실제로 쓰는 우주가 다른가. 비어 있는 쪽은 비교하지 않는다. */
|
|
60
|
+
export function universeMismatch(parentRoot: string | undefined, childRoot: string | undefined): { parentRoot: string; childRoot: string } | null {
|
|
61
|
+
const parent = parentRoot?.trim();
|
|
62
|
+
const child = childRoot?.trim();
|
|
63
|
+
if (!parent || !child) return null;
|
|
64
|
+
const p = normRoot(parent);
|
|
65
|
+
const c = normRoot(child);
|
|
66
|
+
return p === c ? null : { parentRoot: p, childRoot: c };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type UniverseMeasure = { measurable: true } | { measurable: false; reason: '빈 우주' };
|
|
70
|
+
|
|
71
|
+
/** 읽을 우주가 비어 있으면 «0» 이 아니라 «측정 불가» 로 말해야 한다. 디렉터리가 없거나 항목이 하나도 없으면 빈 우주다. */
|
|
72
|
+
export function measureUniverse(root: string, entries: (dir: string) => string[] = defaultEntries): UniverseMeasure {
|
|
73
|
+
return entries(root).length > 0 ? { measurable: true } : { measurable: false, reason: '빈 우주' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function defaultEntries(dir: string): string[] {
|
|
77
|
+
try {
|
|
78
|
+
const { readdirSync } = require('node:fs') as typeof import('node:fs');
|
|
79
|
+
return readdirSync(dir);
|
|
80
|
+
} catch { return []; }
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
/** 명시 config-dir 이 없으면 state-dir 과 config-dir 을 같은 우주로 유지한다. */
|
|
60
84
|
export function configDirFollowingStateDir(
|
|
61
85
|
explicitConfigDir: string | undefined,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// 자식 elanous 기동의 단일 입구. 우주는 부모가 한 번 정해 ELANOUS_STATE_DIR 도장으로 물려준다.
|
|
2
|
+
import { spawn, spawnSync, type ChildProcess, type SpawnOptions, type SpawnSyncOptions, type SpawnSyncReturns } from 'node:child_process';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { stateDirSourceForChild } from '../agent/identity-env.js';
|
|
5
|
+
import { effectiveInstanceRoot } from './resolve.js';
|
|
6
|
+
|
|
7
|
+
const DEFAULT_BIN = resolve(import.meta.dir, '../../bin/elanous.mjs');
|
|
8
|
+
|
|
9
|
+
export interface SpawnElanousOptions {
|
|
10
|
+
/** 자식이 쓸 우주. 생략하면 부모의 effectiveInstanceRoot(). 명시한 값이 이긴다. */
|
|
11
|
+
stateDir?: string;
|
|
12
|
+
/** 실행할 elanous 진입 스크립트. 생략하면 이 트리의 bin/elanous.mjs. */
|
|
13
|
+
bin?: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ElanousInvocation {
|
|
19
|
+
command: string;
|
|
20
|
+
args: string[];
|
|
21
|
+
env: NodeJS.ProcessEnv;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 자식 기동 명세를 만든다. env 는 부모 env 위에 우주 도장(뿌리 ⊕ 출처)을 얹은 것이다. */
|
|
25
|
+
export function elanousInvocation(args: readonly string[], opts: SpawnElanousOptions = {}): ElanousInvocation {
|
|
26
|
+
const root = opts.stateDir?.trim() || effectiveInstanceRoot();
|
|
27
|
+
const base = opts.env ?? process.env;
|
|
28
|
+
return {
|
|
29
|
+
command: process.execPath,
|
|
30
|
+
args: [opts.bin ?? DEFAULT_BIN, ...args],
|
|
31
|
+
env: { ...base, ELANOUS_STATE_DIR: root, ELANOUS_STATE_DIR_SOURCE: stateDirSourceForChild(root, base) },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function spawnElanous(args: readonly string[], opts: SpawnElanousOptions & Omit<SpawnOptions, 'env' | 'cwd'> = {}): ChildProcess {
|
|
36
|
+
const { stateDir: _s, bin: _b, env: _e, ...rest } = opts;
|
|
37
|
+
const inv = elanousInvocation(args, opts);
|
|
38
|
+
return spawn(inv.command, inv.args, { ...rest, cwd: opts.cwd, env: inv.env });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function spawnElanousSync(args: readonly string[], opts: SpawnElanousOptions & Omit<SpawnSyncOptions, 'env' | 'cwd'> = {}): SpawnSyncReturns<string | Buffer> {
|
|
42
|
+
const { stateDir: _s, bin: _b, env: _e, ...rest } = opts;
|
|
43
|
+
const inv = elanousInvocation(args, opts);
|
|
44
|
+
return spawnSync(inv.command, inv.args, { ...rest, cwd: opts.cwd, env: inv.env });
|
|
45
|
+
}
|
|
@@ -29,6 +29,9 @@ export const DEFAULT_GITHUB_STAR_DAYS = 30;
|
|
|
29
29
|
*/
|
|
30
30
|
export const DEFAULT_GITHUB_STAR_PER_QUERY = 20;
|
|
31
31
|
|
|
32
|
+
/** 하루당 별 증가 상위 이 개수 행만 README 를 싣고 `surge.score` 를 받는다. */
|
|
33
|
+
const GITHUB_SURGE_TOP = 3;
|
|
34
|
+
|
|
32
35
|
export interface GithubStarRepo {
|
|
33
36
|
fullName: string;
|
|
34
37
|
url: string;
|
|
@@ -223,7 +226,7 @@ export async function collectGithubStars(
|
|
|
223
226
|
}).sort((a, b) => (b.starsPerDay ?? -Infinity) - (a.starsPerDay ?? -Infinity) || b.stars - a.stars);
|
|
224
227
|
const readmes = new Map<string, string>();
|
|
225
228
|
if (!opts.dryRun) {
|
|
226
|
-
for (const row of repos.slice(0,
|
|
229
|
+
for (const row of repos.slice(0, GITHUB_SURGE_TOP)) {
|
|
227
230
|
try {
|
|
228
231
|
readmes.set(row.repo, `README:\n${(await (opts.fetchReadme ?? ghApiFetchReadme)(row.repo)).slice(0, 1_500)}`);
|
|
229
232
|
} catch {
|
|
@@ -231,7 +234,7 @@ export async function collectGithubStars(
|
|
|
231
234
|
}
|
|
232
235
|
}
|
|
233
236
|
}
|
|
234
|
-
const raws: RawIntakeItem[] = repos.map((row) => ({
|
|
237
|
+
const raws: RawIntakeItem[] = repos.map((row, rank) => ({
|
|
235
238
|
url: row.url,
|
|
236
239
|
title: row.title,
|
|
237
240
|
// 모든 행 첫 줄에 라이선스: SPDX · 확인된 부재는 «없음» · 응답이 알려 주지 않으면 «미상»(없음으로 읽지 않는다).
|
|
@@ -240,6 +243,8 @@ export async function collectGithubStars(
|
|
|
240
243
|
stars: row.stars,
|
|
241
244
|
...(row.starsDelta !== undefined ? { starsDelta: row.starsDelta } : {}),
|
|
242
245
|
...(row.starsPerDay !== undefined ? { starsPerDay: row.starsPerDay } : {}),
|
|
246
|
+
// 급등 상위 3 행(README 를 싣는 그 셋)만 1위 3 · 2위 2 · 3위 1 — pickAbsorbQueue 가 `.score` 로 앞세운다.
|
|
247
|
+
...(rank < GITHUB_SURGE_TOP ? { 'surge.score': GITHUB_SURGE_TOP - rank } : {}),
|
|
243
248
|
},
|
|
244
249
|
}));
|
|
245
250
|
const result: CollectGithubResult = {
|
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));
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { RegisteredIntakeSource } from './intake-sources.js';
|
|
2
|
+
|
|
3
|
+
/** listChecklist(v).items 꼴 — 호출 쪽이 다음 두 판 칸을 모아 넘긴다. */
|
|
4
|
+
export interface PrefetchCell {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
status: string;
|
|
8
|
+
refs?: readonly string[];
|
|
9
|
+
/** 그 판 날짜(YYYY-MM-DD). 주제 until 로 실린다. */
|
|
10
|
+
until?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface PrefetchTopic {
|
|
14
|
+
topic: string;
|
|
15
|
+
cellIds: string[];
|
|
16
|
+
until?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PrefetchTopicsOpts {
|
|
20
|
+
max?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 의도적 경계: 이 파일은 제안만 만든다. intake CLI `prefetch --dry-run|--apply` 와
|
|
25
|
+
* REQ-LEDGER 테마 원천 교체는 다음 조각 — addSource · CLI 를 부르지 않는다.
|
|
26
|
+
*/
|
|
27
|
+
function backtickTokens(title: string): string[] {
|
|
28
|
+
const tokens: string[] = [];
|
|
29
|
+
const re = /`([^`]+)`/g;
|
|
30
|
+
for (let match = re.exec(title); match; match = re.exec(title)) {
|
|
31
|
+
const token = match[1]!.trim();
|
|
32
|
+
if (token) tokens.push(token);
|
|
33
|
+
}
|
|
34
|
+
return tokens;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function englishProperNouns(title: string): string[] {
|
|
38
|
+
const stripped = title.replace(/`[^`]*`/g, ' ');
|
|
39
|
+
const tokens: string[] = [];
|
|
40
|
+
// CamelCase · 내부 대문자 식별자, 또는 2글자 이상 대문자(하이픈 칸 id 포함).
|
|
41
|
+
const re = /\b(?:[A-Z][A-Za-z0-9]*[A-Z][A-Za-z0-9]*|[A-Z]{2,}(?:-[A-Z0-9]+)*)\b/g;
|
|
42
|
+
for (let match = re.exec(stripped); match; match = re.exec(stripped)) tokens.push(match[0]);
|
|
43
|
+
return tokens;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function rfcNames(refs: readonly string[] | undefined): string[] {
|
|
47
|
+
if (!refs) return [];
|
|
48
|
+
const names: string[] = [];
|
|
49
|
+
for (const ref of refs) {
|
|
50
|
+
const file = (ref.split('#')[0] ?? '').split('/').pop() ?? '';
|
|
51
|
+
const stem = file.replace(/\.[A-Za-z0-9]+$/, '').replace(/-\d{4}-\d{2}-\d{2}$/, '');
|
|
52
|
+
if (stem.startsWith('RFC-') && stem.length > 4) names.push(stem);
|
|
53
|
+
}
|
|
54
|
+
return names;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function laterDate(a: string | undefined, b: string | undefined): string | undefined {
|
|
58
|
+
if (!a) return b;
|
|
59
|
+
if (!b) return a;
|
|
60
|
+
return a >= b ? a : b;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function sourceId(topic: string): string {
|
|
64
|
+
const slug = topic.replace(/[^\w.-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48);
|
|
65
|
+
return `ref-prefetch-${slug || 'topic'}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function prefetchTopics(cells: readonly PrefetchCell[], opts: PrefetchTopicsOpts = {}): PrefetchTopic[] {
|
|
69
|
+
const max = opts.max ?? 5;
|
|
70
|
+
const byTopic = new Map<string, { topic: string; count: number; cellIds: string[]; until?: string }>();
|
|
71
|
+
const order: string[] = [];
|
|
72
|
+
for (const cell of cells) {
|
|
73
|
+
if (cell.status !== 'yellow') continue;
|
|
74
|
+
const tokens = new Set([
|
|
75
|
+
...englishProperNouns(cell.title),
|
|
76
|
+
...backtickTokens(cell.title),
|
|
77
|
+
...rfcNames(cell.refs),
|
|
78
|
+
]);
|
|
79
|
+
for (const topic of tokens) {
|
|
80
|
+
let acc = byTopic.get(topic);
|
|
81
|
+
if (!acc) {
|
|
82
|
+
acc = { topic, count: 0, cellIds: [], until: cell.until };
|
|
83
|
+
byTopic.set(topic, acc);
|
|
84
|
+
order.push(topic);
|
|
85
|
+
}
|
|
86
|
+
acc.count++;
|
|
87
|
+
if (!acc.cellIds.includes(cell.id)) acc.cellIds.push(cell.id);
|
|
88
|
+
acc.until = laterDate(acc.until, cell.until);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return order
|
|
92
|
+
.map((topic) => byTopic.get(topic)!)
|
|
93
|
+
.sort((a, b) => b.count - a.count || order.indexOf(a.topic) - order.indexOf(b.topic))
|
|
94
|
+
.slice(0, Math.max(0, max))
|
|
95
|
+
.map(({ topic, cellIds, until }) => until === undefined ? { topic, cellIds } : { topic, cellIds, until });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function prefetchSources(topics: readonly PrefetchTopic[], seat: string, now: Date): RegisteredIntakeSource[] {
|
|
99
|
+
// 판 날짜를 모르면 until 을 비운다 — now 로 채우면 untilMs(그날 00:00Z) 기준으로 이미 만료된 제안이 된다.
|
|
100
|
+
void now;
|
|
101
|
+
return topics.map((entry) => ({
|
|
102
|
+
id: sourceId(entry.topic),
|
|
103
|
+
seat,
|
|
104
|
+
kind: 'github-query',
|
|
105
|
+
spec: entry.topic,
|
|
106
|
+
every: '1d',
|
|
107
|
+
...(entry.until === undefined ? {} : { until: entry.until }),
|
|
108
|
+
why: `REF-PREFETCH ⊕ ${entry.cellIds.join(' ')}`,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
@@ -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
|
+
}
|