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
|
@@ -192,9 +192,9 @@ export function remoteParentAlive(parentHost: { host: string; pid?: number; runI
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/** 발사 전 점검 결과 — `gaps` 가 비어야 원격으로 띄운다. */
|
|
195
|
-
export interface ParentHostPreflight { ok: boolean; gaps: string[]; facts: Record<string, string> }
|
|
195
|
+
export interface ParentHostPreflight { ok: boolean; gaps: string[]; warnings: string[]; facts: Record<string, string> }
|
|
196
196
|
|
|
197
|
-
/** 원격 사실 한 번에 — key=value 줄. */
|
|
197
|
+
/** 원격 사실 한 번에 — key=value 줄. LLM 자격은 «존재·개수»만 센다(값을 읽지도 찍지도 않는다). */
|
|
198
198
|
export function preflightScript(target: ParentHostConfig): string {
|
|
199
199
|
const elanous = remotePath(target.elanous ?? DEFAULT_REMOTE_ELANOUS);
|
|
200
200
|
const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
|
|
@@ -204,6 +204,9 @@ export function preflightScript(target: ParentHostConfig): string {
|
|
|
204
204
|
`grep -Eq '"podPool"[[:space:]]*:[[:space:]]*"[^"[:space:]]+' ${configDir}/config.json 2>/dev/null && echo podPool=1`,
|
|
205
205
|
`(cd ${shellQuote(target.cwd)} 2>/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2>&1) && echo repo=1`,
|
|
206
206
|
`command -v kubectl >/dev/null 2>&1 && echo kubectl=1`,
|
|
207
|
+
`n=$(grep -Ec '^[[:space:]]*"openai-codex(:[^"]*)?"[[:space:]]*:[[:space:]]*\\{' ${configDir}/auth.json 2>/dev/null); echo "codexAccounts=\${n:-0}"`,
|
|
208
|
+
`{ grep -Eq '"key"[[:space:]]*:[[:space:]]*"[^"]+"' "$HOME/.grok/auth.json" 2>/dev/null || [ -n "\${XAI_API_KEY:-}\${GROK_API_KEY:-}\${GROK_CODE_XAI_API_KEY:-}" ]; } && echo grok=1`,
|
|
209
|
+
`{ [ -s "\${ELANOUS_KEY_CACHE_DIR:-$HOME/.cache}/openrouter_api_key" ] || [ -n "\${OPENROUTER_API_KEY:-}" ]; } && echo openrouter=1`,
|
|
207
210
|
`true`,
|
|
208
211
|
].join('; ');
|
|
209
212
|
}
|
|
@@ -242,6 +245,16 @@ export function judgeParentHostFacts(facts: Record<string, string>, input: Omit<
|
|
|
242
245
|
return gaps;
|
|
243
246
|
}
|
|
244
247
|
|
|
248
|
+
/** 순수 판정 — 원격 LLM 자격 사실 → 경고 목록(막지 않는다 · gaps 와 별개). 못 닿은 호스트는 사실이 없으므로 경고도 없다. */
|
|
249
|
+
export function judgeParentHostCredentials(facts: Record<string, string>): string[] {
|
|
250
|
+
if (facts.unreachable) return [];
|
|
251
|
+
const warnings: string[] = [];
|
|
252
|
+
if (!(Number(facts.codexAccounts) > 1)) warnings.push('codex-accounts-low');
|
|
253
|
+
if (facts.grok !== '1') warnings.push('grok-credential-missing');
|
|
254
|
+
if (facts.openrouter !== '1') warnings.push('openrouter-key-missing');
|
|
255
|
+
return warnings;
|
|
256
|
+
}
|
|
257
|
+
|
|
245
258
|
export function preflightParentHost(input: PreflightInput): ParentHostPreflight {
|
|
246
259
|
const ssh = input.ssh ?? defaultSshRunner;
|
|
247
260
|
const facts: Record<string, string> = {};
|
|
@@ -252,7 +265,18 @@ export function preflightParentHost(input: PreflightInput): ParentHostPreflight
|
|
|
252
265
|
if (at > 0) facts[line.slice(0, at).trim()] = line.slice(at + 1).trim();
|
|
253
266
|
}
|
|
254
267
|
const gaps = judgeParentHostFacts(facts, { localVersion: input.localVersion, launchHoldActive: input.launchHoldActive, podPoolOverride: Boolean(input.target.podPool) });
|
|
255
|
-
|
|
268
|
+
const warnings = judgeParentHostCredentials(facts);
|
|
269
|
+
if (warnings.length) {
|
|
270
|
+
try {
|
|
271
|
+
debug.log('task-agent.parent-host', 'credential-warning', {
|
|
272
|
+
host: input.target.host,
|
|
273
|
+
codexAccounts: Number(facts.codexAccounts) || 0,
|
|
274
|
+
grok: facts.grok === '1' ? 1 : 0,
|
|
275
|
+
openrouter: facts.openrouter === '1' ? 1 : 0,
|
|
276
|
+
});
|
|
277
|
+
} catch { /* fail-soft */ }
|
|
278
|
+
}
|
|
279
|
+
return { ok: gaps.length === 0, gaps, warnings, facts };
|
|
256
280
|
}
|
|
257
281
|
|
|
258
282
|
/** 원격이 «확실히 안 띄웠다»고 답했다 — 호출부가 로컬로 돌아가도 중복 발사가 아니다. */
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
* 거절되면 그 시도는 `base-stale` 갈래로 적히고(judgement 1회 규칙과 섞이지 않는다), 다음 틱이 «같은 머리»를 새 base 위에서 한 번 더
|
|
20
20
|
* 재게이트한다(`staleBase` = 낡은 base · 멱등 키 = 머리 ⊕ staleBase · 상한에 포함). 그 재게이트가 통과하고 base 가 실제로 바뀌었을 때만
|
|
21
21
|
* 새 baseCommit 으로 증거를 다시 써 land 한다(`gateAt` 으로 앞 base-stale 시도를 소비) — 관측 `rejudge-on-head {step:'regate', reason:'base-stale-overlap …'}`.
|
|
22
|
+
* - TA-REJUDGE-REBASE-LOOP: 그 1회가 «같은 base» 로 돌아오거나 stale 재게이트에 `baseCommit` 이 없으면 needs-owner 로 멈추지 않는다. origin/main 을
|
|
23
|
+
* fetch 한 뒤 PR 가지에 3-way merge(rerere 켬 · ⛔ rebase/force-push/reset/파일째 checkout) 하고 일반 push 로 새 머리를 만든 다음, 그 머리는 기존
|
|
24
|
+
* ①②③ 사슬을 탄다. 머리마다 1회 · 카드당 `CATCH_UP_CAP`(기본 2)회. 충돌이면 `merge --abort` ⊕ needs-owner(`main 따라잡기 충돌 · 파일 …`).
|
|
25
|
+
* 관측 `rejudge-on-head {step:'catch-up', decision: pushed|conflict|cap-reached, fromBase, toBase, newHead}`.
|
|
22
26
|
* - 대상: 카드에 묶인 PR(URL 로 저장소 확인) ⊕ 그 PR 로 TA 가 이미 리뷰를 요청한 카드(= 런이 멈춰 TA 판단이 시작됐다).
|
|
23
27
|
* - 사람의 hold(draft PR)는 뒤집지 않는다 — 재게이트(`noMerge`)와 land 관문이 draft 를 거부한다.
|
|
24
28
|
* - 허용: 설정 `taskAgent.liveMoves` 그대로 — 재게이트·land 는 `propose-land`, 리뷰 재요청은 `review` 가 있을 때만(없으면 «했을 수»).
|
|
@@ -26,7 +30,8 @@
|
|
|
26
30
|
* 한 줄(`event:'rejudge-on-head'` · 같은 머리·같은 단계·같은 판단은 한 번).
|
|
27
31
|
*/
|
|
28
32
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
29
|
-
import { spawn } from 'node:child_process';
|
|
33
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
34
|
+
import { tmpdir } from 'node:os';
|
|
30
35
|
import { dirname, join } from 'node:path';
|
|
31
36
|
import { debug } from '../debug/log.js';
|
|
32
37
|
import type { DetachedSpawn } from '../cli/tasks-cli.js';
|
|
@@ -39,18 +44,37 @@ import { cardPrNumber, readTaskCard, taskAgentStatePath, updateTaskCard, type Ta
|
|
|
39
44
|
export const REJUDGE_ON_HEAD_EVENT = 'rejudge-on-head';
|
|
40
45
|
/** 카드·PR 당 재게이트하는 머리 수 상한(머리가 바뀔 때마다 하나) — 넘으면 멈추고 사람에게 넘긴다. */
|
|
41
46
|
export const REJUDGE_HEAD_CAP = 3;
|
|
47
|
+
/** 카드당 origin/main 따라잡기(merge⊕push) 상한 — 넘으면 멈추고 사람에게 넘긴다. 머리마다 1회. */
|
|
48
|
+
export const CATCH_UP_CAP = 2;
|
|
42
49
|
/** 떼어 띄운 재게이트 결과를 기다리는 상한 — 지나도 파일이 없으면 «결과 없음»으로 적는다(같은 머리는 다시 안 돌린다). */
|
|
43
50
|
export const REGATE_RESULT_WAIT_MS = 90 * 60_000;
|
|
44
51
|
|
|
45
|
-
export type RejudgeStep = 'regate' | 'review' | 'land' | 'target';
|
|
46
|
-
export
|
|
52
|
+
export type RejudgeStep = 'regate' | 'review' | 'land' | 'target' | 'catch-up';
|
|
53
|
+
export type CatchUpDecision = 'pushed' | 'conflict' | 'cap-reached' | 'failed';
|
|
54
|
+
export interface RejudgeOutcome {
|
|
55
|
+
card: string; pr: number | null; fromHead: string | null; toHead: string | null; step: RejudgeStep; decision: string; reason: string;
|
|
56
|
+
fromBase?: string; toBase?: string; newHead?: string;
|
|
57
|
+
}
|
|
47
58
|
|
|
48
59
|
export interface RegateRequest { card: string; pr: number; head: string; repoRoot: string; resultPath: string }
|
|
60
|
+
export interface CatchUpRequest { cwd: string; pr: number; head: string; branch?: string; fromBase?: string; worktreePath?: string }
|
|
61
|
+
export interface CatchUpResult {
|
|
62
|
+
decision: Exclude<CatchUpDecision, 'cap-reached'>;
|
|
63
|
+
reason: string;
|
|
64
|
+
fromBase?: string;
|
|
65
|
+
toBase?: string;
|
|
66
|
+
newHead?: string;
|
|
67
|
+
files?: string[];
|
|
68
|
+
pushArgs?: string[];
|
|
69
|
+
}
|
|
70
|
+
export type CatchUpGit = (cwd: string, args: string[]) => { status: number | null; stdout: string; stderr: string };
|
|
49
71
|
export interface RejudgeDeps {
|
|
50
72
|
live?: LiveMoveDeps;
|
|
51
73
|
liveMoves: ReadonlySet<TaskAgentLiveMove>;
|
|
52
74
|
/** 재게이트를 떼어 띄운다 — 시험은 주입한다. 기본은 `tasks regate-run` 자식(stdio ignore · 결과는 파일). */
|
|
53
75
|
requestRegate?: (request: RegateRequest) => Promise<void>;
|
|
76
|
+
/** TA-REJUDGE-REBASE-LOOP — origin/main 을 PR 가지에 3-way merge 하고 일반 push. 시험은 주입한다. */
|
|
77
|
+
catchUpMain?: (request: CatchUpRequest) => Promise<CatchUpResult>;
|
|
54
78
|
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
55
79
|
/** 시험 seam — 결과 파일 읽기(없으면 ENOENT). */
|
|
56
80
|
readFile?: (path: string) => string;
|
|
@@ -104,6 +128,83 @@ export function parseRegateResult(text: string, pr: number, head: string): Regat
|
|
|
104
128
|
const sameUrl = (a: string, b: string) => a.trim().replace(/\/+$/, '').toLowerCase() === b.trim().replace(/\/+$/, '').toLowerCase();
|
|
105
129
|
const sameHead = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();
|
|
106
130
|
|
|
131
|
+
const defaultCatchUpGit: CatchUpGit = (cwd, args) => {
|
|
132
|
+
const r = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 120_000 });
|
|
133
|
+
return { status: r.status, stdout: String(r.stdout ?? ''), stderr: String(r.stderr ?? '') };
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export function catchUpWorktreePath(statePath: string, cardId: string, pr: number, head: string): string {
|
|
137
|
+
return join(dirname(statePath), 'catch-up-worktrees', `${safe(cardId)}-${pr}-${safe(head.slice(0, 12))}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const gitSha = (text: string): string | null => {
|
|
141
|
+
const value = text.trim();
|
|
142
|
+
return /^[0-9a-f]{40}$/i.test(value) ? value : null;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const catchUpFail = (reason: string, extra: Partial<CatchUpResult> = {}): CatchUpResult => ({ decision: 'failed', reason, ...extra });
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* origin/main 을 PR 머리에 3-way merge(rerere 켬) 하고 일반 push 한다.
|
|
149
|
+
* ⛔ rebase · force-push · reset · 남의 가지 파일째 checkout — 충돌이면 merge --abort.
|
|
150
|
+
*/
|
|
151
|
+
export async function defaultCatchUpMain(request: CatchUpRequest, git: CatchUpGit = defaultCatchUpGit): Promise<CatchUpResult> {
|
|
152
|
+
const repo = request.cwd;
|
|
153
|
+
const work = request.worktreePath ?? join(tmpdir(), `ta-catch-up-${request.pr}-${safe(request.head.slice(0, 12))}-${process.pid}`);
|
|
154
|
+
const gitRepo = (args: string[]) => git(repo, args);
|
|
155
|
+
const gitWork = (args: string[]) => git(work, args);
|
|
156
|
+
const fromBase = request.fromBase;
|
|
157
|
+
if (!request.branch) return catchUpFail('PR head branch name unknown', { fromBase });
|
|
158
|
+
|
|
159
|
+
const fetchMain = gitRepo(['fetch', 'origin', 'refs/heads/main']);
|
|
160
|
+
if (fetchMain.status !== 0) return catchUpFail(`origin/main fetch failed: ${(fetchMain.stderr || fetchMain.stdout).trim().slice(-200)}`, { fromBase });
|
|
161
|
+
const toBase = gitSha(gitRepo(['rev-parse', 'FETCH_HEAD']).stdout);
|
|
162
|
+
if (!toBase) return catchUpFail('origin/main sha unreadable', { fromBase });
|
|
163
|
+
|
|
164
|
+
const fetchPr = gitRepo(['fetch', 'origin', `pull/${request.pr}/head`]);
|
|
165
|
+
if (fetchPr.status !== 0) return catchUpFail(`fetch pull/${request.pr}/head failed: ${(fetchPr.stderr || fetchPr.stdout).trim().slice(-200)}`, { fromBase, toBase });
|
|
166
|
+
const fetchedHead = gitSha(gitRepo(['rev-parse', 'FETCH_HEAD']).stdout);
|
|
167
|
+
if (!fetchedHead || !sameHead(fetchedHead, request.head)) {
|
|
168
|
+
return catchUpFail(`fetched PR head ${(fetchedHead ?? '?').slice(0, 12)} ≠ ${request.head.slice(0, 12)}`, { fromBase, toBase });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const added = gitRepo(['worktree', 'add', '--detach', work, request.head]);
|
|
172
|
+
if (added.status !== 0) return catchUpFail(`worktree add failed: ${(added.stderr || added.stdout).trim().slice(-200)}`, { fromBase, toBase });
|
|
173
|
+
const cleanup = () => { gitRepo(['worktree', 'remove', '--force', work]); };
|
|
174
|
+
|
|
175
|
+
gitWork(['config', 'rerere.enabled', 'true']);
|
|
176
|
+
const merge = gitWork(['merge', '--no-ff', toBase, '-m', `catch-up: merge origin/main into PR #${request.pr}`]);
|
|
177
|
+
if (merge.status !== 0) {
|
|
178
|
+
const files = gitWork(['diff', '--name-only', '--diff-filter=U']).stdout.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
179
|
+
gitWork(['merge', '--abort']);
|
|
180
|
+
cleanup();
|
|
181
|
+
return {
|
|
182
|
+
decision: 'conflict',
|
|
183
|
+
reason: `main 따라잡기 충돌 · 파일 ${files.join(', ') || '(unknown)'}`,
|
|
184
|
+
fromBase, toBase, files,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const newHead = gitSha(gitWork(['rev-parse', 'HEAD']).stdout);
|
|
188
|
+
if (!newHead) { cleanup(); return catchUpFail('merge produced no head sha', { fromBase, toBase }); }
|
|
189
|
+
const pushArgs = ['push', 'origin', `HEAD:${request.branch}`];
|
|
190
|
+
const push = gitWork(pushArgs);
|
|
191
|
+
cleanup();
|
|
192
|
+
if (push.status !== 0) return catchUpFail(`push failed: ${(push.stderr || push.stdout).trim().slice(-200)}`, { fromBase, toBase, newHead, pushArgs });
|
|
193
|
+
return {
|
|
194
|
+
decision: 'pushed',
|
|
195
|
+
reason: `merged origin/main ${toBase.slice(0, 12)} → head ${newHead.slice(0, 12)}`,
|
|
196
|
+
fromBase, toBase, newHead, pushArgs,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** 실제로 «시도한» 따라잡기 기록(pushed·conflict·failed) — `cap-reached`·`would-catch-up` 표지는 시도가 아니다. */
|
|
201
|
+
const CATCH_UP_ATTEMPT_EFFECTS: ReadonlySet<string> = new Set(['pushed', 'conflict', 'failed']);
|
|
202
|
+
|
|
203
|
+
function catchUpHistory(card: Pick<TaskCard, 'history'>, pr: number) {
|
|
204
|
+
return (card.history ?? []).filter((item) => item.event === REJUDGE_ON_HEAD_EVENT && item.kind === 'catch-up' && item.pr === pr
|
|
205
|
+
&& typeof item.effect === 'string' && CATCH_UP_ATTEMPT_EFFECTS.has(item.effect));
|
|
206
|
+
}
|
|
207
|
+
|
|
107
208
|
/** 카드의 PR URL 과 같은 PR 을 돌려주는 후보 저장소 — 못 찾으면 이유. */
|
|
108
209
|
async function resolveCardPr(card: TaskCard, pr: number, url: string, deps: LiveMoveDeps): Promise<{ cwd: string; view: PrHeadView } | { reason: string }> {
|
|
109
210
|
let candidates: readonly ReviewRepoCandidate[];
|
|
@@ -195,7 +296,50 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
195
296
|
const { cwd, view } = found;
|
|
196
297
|
const toHead = view.head;
|
|
197
298
|
if (view.state !== 'OPEN') return target('pr-not-open', `PR #${pr} is ${view.state}`, pr, fromHead, toHead);
|
|
198
|
-
const step = (s: RejudgeStep, decision: string, reason: string, record: boolean
|
|
299
|
+
const step = (s: RejudgeStep, decision: string, reason: string, record: boolean, extra: Partial<RejudgeOutcome> = {}) =>
|
|
300
|
+
emit({ card: card!.id, pr, fromHead, toHead, step: s, decision, reason, ...extra }, record);
|
|
301
|
+
|
|
302
|
+
const tryCatchUp = async (fromBase: string | undefined, why: string): Promise<boolean> => {
|
|
303
|
+
const prior = catchUpHistory(card!, pr);
|
|
304
|
+
// 상한은 «실제 push» 만 센다 — 충돌·실패 뒤 사람이 새 머리를 올리면 다시 시도할 수 있어야 한다.
|
|
305
|
+
const pushed = prior.filter((item) => item.effect === 'pushed').length;
|
|
306
|
+
if (pushed >= CATCH_UP_CAP) {
|
|
307
|
+
step('catch-up', 'cap-reached', `${why} · catch-up pushed ${pushed} times already (cap ${CATCH_UP_CAP}) — needs owner`, true, { fromBase });
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
if (prior.some((item) => item.head && sameHead(item.head, toHead))) {
|
|
311
|
+
step('catch-up', 'cap-reached', `${why} · already catch-up on this head — needs owner`, true, { fromBase });
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
if (!deps.liveMoves.has('propose-land')) {
|
|
315
|
+
step('catch-up', 'would-catch-up', `${why} · propose-land not enabled in taskAgent.liveMoves — shadow`, false, { fromBase });
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
let result: CatchUpResult;
|
|
319
|
+
try {
|
|
320
|
+
result = await (deps.catchUpMain ?? defaultCatchUpMain)({
|
|
321
|
+
cwd, pr, head: toHead, branch: view.branch, fromBase,
|
|
322
|
+
worktreePath: catchUpWorktreePath(statePath, card!.id, pr, toHead),
|
|
323
|
+
});
|
|
324
|
+
} catch (error) {
|
|
325
|
+
result = { decision: 'failed', reason: `catch-up threw: ${(error instanceof Error ? error.message : String(error)).slice(-200)}`, fromBase };
|
|
326
|
+
}
|
|
327
|
+
const extra: Partial<RejudgeOutcome> = {
|
|
328
|
+
...(result.fromBase ? { fromBase: result.fromBase } : fromBase ? { fromBase } : {}),
|
|
329
|
+
...(result.toBase ? { toBase: result.toBase } : {}),
|
|
330
|
+
...(result.newHead ? { newHead: result.newHead } : {}),
|
|
331
|
+
};
|
|
332
|
+
if (result.decision === 'pushed') {
|
|
333
|
+
step('catch-up', 'pushed', result.reason, true, extra);
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
if (result.decision === 'conflict') {
|
|
337
|
+
step('catch-up', 'conflict', result.reason, true, extra);
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
step('catch-up', result.decision, `${why} · ${result.reason} — needs owner`, true, extra);
|
|
341
|
+
return true;
|
|
342
|
+
};
|
|
199
343
|
|
|
200
344
|
// 머리가 런 멈춤 때 그대로면 재판정하지 않는다 — 그 머리의 재게이트·리뷰·land 판단은 멈춤 때의 판단(슈퍼바이저 틱)이 이미 했다.
|
|
201
345
|
// TA-LAND-RETRY-ON-INFRA — 단, 그 머리의 land 가 TA 쪽 인프라 결손으로 실패해 재시도가 남았으면 아래 ①②③ 을 그대로 탄다
|
|
@@ -208,7 +352,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
208
352
|
const stale = regate?.passed === true ? baseStaleAttemptAfter(card, pr, toHead, regate.at) : undefined;
|
|
209
353
|
const staleBase = stale ? regate?.baseCommit : undefined;
|
|
210
354
|
if (stale && !staleBase) {
|
|
211
|
-
|
|
355
|
+
await tryCatchUp(undefined, `base-stale-overlap on head ${toHead.slice(0, 12)} but the stale regate has no baseCommit`);
|
|
212
356
|
return outcomes;
|
|
213
357
|
}
|
|
214
358
|
if (!regate || staleBase) {
|
|
@@ -282,9 +426,9 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
|
|
|
282
426
|
step('land', 'not-landing', regate ? (regate.passed === false ? `host regate not passed: ${regate.detail ?? regate.status ?? 'unknown'}` : 'host regate still running') : 'no host regate for this head', regate?.passed === false);
|
|
283
427
|
return outcomes;
|
|
284
428
|
}
|
|
285
|
-
// REJUDGE base-stale — 새 base 위 재게이트가 «같은» base 로 돌아왔다
|
|
429
|
+
// REJUDGE base-stale — 새 base 위 재게이트가 «같은» base 로 돌아왔다 → origin/main 따라잡기(merge⊕push) 후 새 머리 재게이트.
|
|
286
430
|
if (regate.staleBase && regate.baseCommit && sameHead(regate.baseCommit, regate.staleBase)) {
|
|
287
|
-
|
|
431
|
+
await tryCatchUp(regate.staleBase, `base-stale-overlap — re-gate on head ${toHead.slice(0, 12)} returned the same base ${regate.staleBase.slice(0, 12)} (did not advance)`);
|
|
288
432
|
return outcomes;
|
|
289
433
|
}
|
|
290
434
|
if (!deps.liveMoves.has('propose-land')) { step('land', 'would-land', 'propose-land not enabled in taskAgent.liveMoves — shadow', false); return outcomes; }
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { readFileSync } from 'node:fs';
|
|
14
14
|
import { dirname, join } from 'node:path';
|
|
15
|
+
import { isNoneSentinelFinding } from '../agent-substrate/pr-reviewer.js';
|
|
15
16
|
import { debug } from '../debug/log.js';
|
|
16
17
|
import { LIVE_MOVE_RESULT_EVENT, readTaskAgentState, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
|
|
17
18
|
|
|
@@ -63,7 +64,8 @@ export function parseReviewResultOutput(text: string): ParsedReviewResult | null
|
|
|
63
64
|
...(Number.isSafeInteger(prRaw) && prRaw > 0 ? { pr: prRaw } : {}),
|
|
64
65
|
verdict: typeof v.verdict === 'string' ? v.verdict : null,
|
|
65
66
|
reviewed: typeof v.reviewed === 'boolean' ? v.reviewed : null,
|
|
66
|
-
|
|
67
|
+
// PR-LAND-MUSTFIX-NONE — 저장된 결과(옛 판 리뷰 · 다른 경로)에 «(없음 — …)» 표지 줄이 남아 있어도 리뷰 출력과 «같은» 판정으로 0 으로 센다.
|
|
68
|
+
mustFix: Array.isArray(v.mustFix) && v.mustFix.every((fix) => typeof fix === 'string') ? v.mustFix.filter((fix) => !isNoneSentinelFinding(fix)).length : null,
|
|
67
69
|
reviewRoute: typeof v.reviewRoute === 'string' ? v.reviewRoute : null,
|
|
68
70
|
head: typeof v.headCommit === 'string' && SHA40.test(v.headCommit) ? v.headCommit : null,
|
|
69
71
|
error: typeof v.error === 'string' ? v.error : null,
|
package/src/task-agent/shadow.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type { SupervisorJobResult, SupervisorStopReason } from '../self-dev/run-
|
|
|
17
17
|
import { executeNextAction, type DeliveryKind, type NextAction } from './actions.js';
|
|
18
18
|
import { judgeNextMove, type TaskJudgeInput, type TaskJudgement } from './judge.js';
|
|
19
19
|
import { HARNESS_RUN_ID_ENV } from '../harness/harness-space.js';
|
|
20
|
+
import { collectWiringEvidence, type WiringEvidenceDeps } from './card-evidence.js';
|
|
20
21
|
import { recordLiveMoveHistory } from './live-move-history.js';
|
|
21
22
|
import { capturedSelfReview, captureReviewResults, hasCapturedPass } from './review-result-capture.js';
|
|
22
23
|
import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
|
|
@@ -60,6 +61,8 @@ export interface TaskAgentShadowDeps {
|
|
|
60
61
|
live?: LiveMoveDeps;
|
|
61
62
|
/** 카드 조회 상태 파일(시험 주입 · 운영 파일을 건드리지 않게). 기본 = `live.statePath` ⊕ `taskAgentStatePath()`. */
|
|
62
63
|
statePath?: string;
|
|
64
|
+
/** TA-WIRING-CHECK — 배선 근거 수집 의존(시험 주입 · 기본 = gh pr diff 한 번 ⊕ 카드 런 원장). */
|
|
65
|
+
wiring?: Omit<WiringEvidenceDeps, 'card'>;
|
|
63
66
|
/** Process env for the launched-run id (`ELANOUS_RUN_ID`) — test seam; default process.env. */
|
|
64
67
|
env?: NodeJS.ProcessEnv;
|
|
65
68
|
}
|
|
@@ -325,6 +328,15 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
325
328
|
...move, completion: shadowCompletion(card, cardLookupFailed), card: liveCard?.id ?? null, live, liveExecuted: liveMove?.executed ?? false, ...(liveMove ? { liveOk: liveMove.ok } : {}),
|
|
326
329
|
...(reviewFromCapture ? { reviewSource: 'captured-review-result' } : {}),
|
|
327
330
|
});
|
|
331
|
+
// TA-WIRING-CHECK — 병합 PR 은 판단한 «뒤» 배선 근거를 관측만 한다(move 불변 · 실패는 unknown 으로 남기고 던지지 않는다).
|
|
332
|
+
if (judgeInput.prState === 'MERGED' && typeof judgeInput.pr === 'number' && !delivery && liveCard) {
|
|
333
|
+
try {
|
|
334
|
+
const wiring = await collectWiringEvidence(judgeInput.pr, { ...deps.wiring, card: liveCard });
|
|
335
|
+
(deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'wiring-shadow', {
|
|
336
|
+
card: liveCard.id, pr: judgeInput.pr, required: wiring.required, liveRunRecorded: wiring.liveRunRecorded, unknown: wiring.unknown,
|
|
337
|
+
});
|
|
338
|
+
} catch { /* fail-soft — 관측일 뿐 판단을 막지 않는다 */ }
|
|
339
|
+
}
|
|
328
340
|
// TA-LIVE-MOVE-CARD-HISTORY — live-move 수(review·propose-green·propose-land)는 실행이든 그림자든 그 카드 history 에 한 줄.
|
|
329
341
|
// 결정·실행이 끝난 «뒤»에 덧붙이기만 한다(반환값·관측 무변경) · 실패는 관측만(live-move 를 막지 않는다).
|
|
330
342
|
if (liveKind !== null) recordLiveMoveOnCard({
|
|
@@ -487,7 +487,10 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
|
|
|
487
487
|
if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
|
|
488
488
|
const runId = mintRunId();
|
|
489
489
|
const launchId = `tl-${randomBytes(6).toString('hex')}`;
|
|
490
|
-
const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
|
|
490
|
+
const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
|
|
491
|
+
...(card.checklistId ? { ELANOUS_POD_SLOT_ID: card.checklistId } : {}),
|
|
492
|
+
...(card.seat ? { ELANOUS_POD_OWNER_KIND: 'seat', ELANOUS_POD_OWNER_ID: card.seat } : {}),
|
|
493
|
+
...(card.taLand ? { [TA_LAND_ENV]: '1' } : {}) }, cardLabelContext: taskCardLabelContext(card) };
|
|
491
494
|
let receipt: void | TaskLaunchReceipt;
|
|
492
495
|
try {
|
|
493
496
|
receipt = await opts.launcher(move.command!, project?.target, context);
|
|
@@ -371,6 +371,12 @@ export interface RunPodCommandOptions {
|
|
|
371
371
|
runId?: string;
|
|
372
372
|
name?: string;
|
|
373
373
|
pollMs?: number;
|
|
374
|
+
/**
|
|
375
|
+
* GATE-MULTI-HOST — throw once the Job's status has been unreadable (`kubectl get job` failing) this long, instead of
|
|
376
|
+
* polling forever: a pool member that died mid-Job (host off · tailnet drop) then frees its caller to place the work
|
|
377
|
+
* elsewhere. Omitted = poll without a bound (unchanged for every caller but the release gate).
|
|
378
|
+
*/
|
|
379
|
+
statusUnreadableMs?: number;
|
|
374
380
|
kubectl?: Kubectl;
|
|
375
381
|
/** A caller-owned scheduler is self-capped: acquires count only its own Jobs, never cluster occupancy (POOLGLOBAL-REG). */
|
|
376
382
|
poolScheduler?: PodPoolScheduler;
|
|
@@ -536,10 +542,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
536
542
|
throw new Error(applied.stderr.trim() || 'pod command: Job 적용 실패');
|
|
537
543
|
}
|
|
538
544
|
let state: 'complete' | 'failed' = 'failed';
|
|
545
|
+
let unreadableSince: number | null = null;
|
|
539
546
|
for (;;) {
|
|
540
547
|
const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
|
|
541
548
|
const finished = jobFinished(got.stdout);
|
|
542
549
|
if (finished) { state = finished; break; }
|
|
550
|
+
if (got.status !== 0 && options.statusUnreadableMs !== undefined) {
|
|
551
|
+
unreadableSince ??= Date.now();
|
|
552
|
+
if (Date.now() - unreadableSince >= options.statusUnreadableMs) {
|
|
553
|
+
log('pod.command', 'job-status-unreadable', { job: name, context, unreadableMs: Date.now() - unreadableSince, error: (got.stderr ?? '').trim().slice(0, 300) });
|
|
554
|
+
throw new Error(`pod command: Job 상태를 ${Math.round(options.statusUnreadableMs / 1000)}초 동안 못 읽었다(${context}) — ${(got.stderr ?? '').trim().split('\n').pop()?.slice(0, 200) ?? ''}`);
|
|
555
|
+
}
|
|
556
|
+
} else unreadableSince = null;
|
|
543
557
|
await sleep(options.pollMs ?? 15_000);
|
|
544
558
|
}
|
|
545
559
|
const logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// REVIEW-ACP-POD (0.2.25 · REVIEW-ACP-DEFAULT ② 조각) — Pod 런이 낸 merge-ready PR 을 «호스트»가 Claude ACP(구독)로 다시 본다.
|
|
2
|
+
//
|
|
3
|
+
// S Pod 안 하니스 리뷰는 api 리뷰어(codex 기본 gpt-6-sol · OR Pod 는 glm 고정)로 돈다 — Pod 엔 Claude 구독도 정책 파일도 없어
|
|
4
|
+
// `roleLlm.reviewer = claude-acp`(운영에 이미 켜져 있다)가 Pod 안에선 «안 닿는다». 호스트 레인 런만 ACP 로 리뷰받는다.
|
|
5
|
+
// C Pod 가 호스트로 돌려보내는 유일한 문은 merge-ready → 호스트 재게이트 → 병합이다. 여기에 리뷰가 없다.
|
|
6
|
+
// Q Pod 런의 리뷰를 구독(ACP)으로 옮기려면 어디서 하나?
|
|
7
|
+
// A 호스트 병합 직전 한 자리에서, 하니스 레인과 «같은» 정책 행(`resolveSubscriptionReviewer`)·같은 가용성 검사
|
|
8
|
+
// (`subscriptionReviewerAvailability` — 구독 확인 · 상한 · 프록시)·같은 ACP 리뷰어(`makeAcpReviewLLM`)로 PR 을 본다.
|
|
9
|
+
// ⛔ 못 쓰면(설정 없음·구독 확인 실패·상한·프록시 없음·리뷰 미완) «refused» 로 돌려주고 호출자는 종전 길(Pod 리뷰 결과로 재게이트)을 그대로 간다.
|
|
10
|
+
// 조용히 다른 공급자로 새지 않는다 — 이 함수 안엔 api 폴백이 «없다».
|
|
11
|
+
// ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
|
|
12
|
+
// 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { debug } from '../../debug/log.js';
|
|
15
|
+
import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
|
|
16
|
+
import type { SubscriptionReviewerSpec } from '../../user-config.js';
|
|
17
|
+
import type { SubscriptionReviewerDeps, subscriptionReviewerSpawn } from '../../self-dev/review-provider-fallback.js';
|
|
18
|
+
|
|
19
|
+
export const POD_HOST_ACP_REVIEW_ENV = 'ELANOUS_POD_HOST_ACP_REVIEW';
|
|
20
|
+
|
|
21
|
+
export type PodHostAcpReviewEnable = { enabled: boolean; source: 'option' | 'env' | 'config' | 'default' };
|
|
22
|
+
|
|
23
|
+
/** 켜는 순서: 옵션 → env(`1`/`true` 켬 · `0`/`false` 끔) → config `llm.podHostAcpReview === true` → 꺼짐. 읽기 실패는 꺼짐(종전). */
|
|
24
|
+
export function resolvePodHostAcpReview(
|
|
25
|
+
option: boolean | undefined,
|
|
26
|
+
env: NodeJS.ProcessEnv,
|
|
27
|
+
readConfig: () => unknown,
|
|
28
|
+
): PodHostAcpReviewEnable {
|
|
29
|
+
if (typeof option === 'boolean') return { enabled: option, source: 'option' };
|
|
30
|
+
const raw = env[POD_HOST_ACP_REVIEW_ENV]?.trim().toLowerCase();
|
|
31
|
+
if (raw === '1' || raw === 'true') return { enabled: true, source: 'env' };
|
|
32
|
+
if (raw === '0' || raw === 'false') return { enabled: false, source: 'env' };
|
|
33
|
+
try {
|
|
34
|
+
const cfg = readConfig() as { llm?: { podHostAcpReview?: unknown } } | undefined;
|
|
35
|
+
if (cfg?.llm?.podHostAcpReview === true) return { enabled: true, source: 'config' };
|
|
36
|
+
} catch { /* 읽기 실패 = 꺼짐(종전 길) */ }
|
|
37
|
+
return { enabled: false, source: 'default' };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type PodHostAcpReviewOutcome =
|
|
41
|
+
| { status: 'clean'; mustFix: 0; shouldFix: number }
|
|
42
|
+
| { status: 'must-fix'; mustFix: number; findings: string[]; verdict: ReviewResult['verdict'] }
|
|
43
|
+
| { status: 'refused'; reason: string };
|
|
44
|
+
|
|
45
|
+
export interface PodHostAcpReviewDeps {
|
|
46
|
+
/** `{ spec, cap }` — 기본은 하니스 레인과 같은 정책 행(`resolveSubscriptionReviewer`). */
|
|
47
|
+
resolveReviewer?: () => { spec: SubscriptionReviewerSpec; cap: number } | undefined;
|
|
48
|
+
/** 구독·상한·프록시 확인 — 기본은 `subscriptionReviewerAvailability`. */
|
|
49
|
+
availability?: (spec: SubscriptionReviewerSpec, cap: number) => { spawn?: ReturnType<typeof subscriptionReviewerSpawn>; reason?: string };
|
|
50
|
+
subscriptionReviewerDeps?: SubscriptionReviewerDeps;
|
|
51
|
+
/** PR 머리 sha·제목·본문·diff. 기본은 `gh`. */
|
|
52
|
+
readPr?: (prNumber: number, repoRoot: string) => { headRefOid: string; title: string; body: string; diff: string } | undefined;
|
|
53
|
+
/** ACP 리뷰어(prompt→text). 기본은 `makeAcpReviewLLM({ backend: 'claude', backendSpec, env })`. */
|
|
54
|
+
makeAcpReviewLLM?: (spawn: ReturnType<typeof subscriptionReviewerSpawn>, repoRoot: string) => (prompt: string) => Promise<string>;
|
|
55
|
+
reviewPullRequest?: (input: { prDiff: string; phaseIntent: string }, llm: (prompt: string) => Promise<string>) => Promise<ReviewResult>;
|
|
56
|
+
env?: NodeJS.ProcessEnv;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
|
|
60
|
+
const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
|
|
61
|
+
if (view.status !== 0) return undefined;
|
|
62
|
+
const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
|
|
63
|
+
if (diff.status !== 0) return undefined;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(view.stdout) as { headRefOid?: unknown; title?: unknown; body?: unknown };
|
|
66
|
+
if (typeof parsed.headRefOid !== 'string') return undefined;
|
|
67
|
+
return { headRefOid: parsed.headRefOid, title: typeof parsed.title === 'string' ? parsed.title : '', body: typeof parsed.body === 'string' ? parsed.body : '', diff: diff.stdout };
|
|
68
|
+
} catch { return undefined; }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function refused(reason: string, data: Record<string, unknown>): PodHostAcpReviewOutcome {
|
|
72
|
+
try { debug.log('self-implement.pod', 'acp-review-refused', { ...data, reason }, { level: 'warn' }); } catch { /* 관측은 결과를 안 바꾼다 */ }
|
|
73
|
+
return { status: 'refused', reason };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Pod merge-ready PR 을 호스트 Claude ACP 로 리뷰한다. ⛔ 던지지 않는다 — 모든 실패는 `refused`(호출자는 종전 길). */
|
|
77
|
+
export async function runPodHostAcpReview(
|
|
78
|
+
input: { prNumber: number; headCommit: string; repoRoot: string; job?: string },
|
|
79
|
+
deps: PodHostAcpReviewDeps = {},
|
|
80
|
+
): Promise<PodHostAcpReviewOutcome> {
|
|
81
|
+
const obs = { job: input.job ?? null, pr: input.prNumber, head: input.headCommit };
|
|
82
|
+
try {
|
|
83
|
+
const env = deps.env ?? process.env;
|
|
84
|
+
// 지연 import — 이 문이 꺼진 런은 정책·설정을 안 읽는다.
|
|
85
|
+
const picked = deps.resolveReviewer ? deps.resolveReviewer() : await (async () => {
|
|
86
|
+
const { loadLlmPolicy, resolveSubscriptionReviewer } = await import('../../policy/llm-policy.js');
|
|
87
|
+
const { getUserConfig } = await import('../../user-config.js');
|
|
88
|
+
return resolveSubscriptionReviewer(loadLlmPolicy(), getUserConfig().roleLlm);
|
|
89
|
+
})();
|
|
90
|
+
if (!picked) return refused('no-subscription-reviewer', obs);
|
|
91
|
+
const avail = deps.availability
|
|
92
|
+
? deps.availability(picked.spec, picked.cap)
|
|
93
|
+
: (await import('../../self-dev/review-provider-fallback.js')).subscriptionReviewerAvailability(picked.spec, picked.cap, env, deps.subscriptionReviewerDeps);
|
|
94
|
+
if (!avail.spawn) return refused(`unavailable: ${avail.reason ?? 'unknown'}`, { ...obs, cap: picked.cap });
|
|
95
|
+
const pr = (deps.readPr ?? defaultReadPr)(input.prNumber, input.repoRoot);
|
|
96
|
+
if (!pr) return refused('pr-unreadable', obs);
|
|
97
|
+
if (pr.headRefOid.toLowerCase() !== input.headCommit.toLowerCase()) return refused('head-moved', { ...obs, prHead: pr.headRefOid });
|
|
98
|
+
if (!pr.diff.trim()) return refused('empty-diff', obs);
|
|
99
|
+
const llm = deps.makeAcpReviewLLM
|
|
100
|
+
? deps.makeAcpReviewLLM(avail.spawn, input.repoRoot)
|
|
101
|
+
: await (async () => {
|
|
102
|
+
const { makeAcpReviewLLM } = await import('../../agent-substrate/acp-reviewer.js');
|
|
103
|
+
const spawn = avail.spawn!;
|
|
104
|
+
return makeAcpReviewLLM({ cwd: input.repoRoot, backend: 'claude', backendSpec: spawn.backendSpec, env: spawn.env });
|
|
105
|
+
})();
|
|
106
|
+
const review = deps.reviewPullRequest ?? (await import('../../agent-substrate/pr-reviewer.js')).reviewPullRequest;
|
|
107
|
+
const phaseIntent = [`Pod 런 PR #${input.prNumber} 의 호스트 Claude ACP 리뷰(병합 전 관문).`, pr.title, pr.body.slice(0, 4000)].filter((s) => s.trim()).join('\n\n');
|
|
108
|
+
const rr = await review({ prDiff: pr.diff, phaseIntent }, llm);
|
|
109
|
+
// ⛔ reviewed=false(파싱 실패·ACP 오류를 리뷰어가 흡수) 는 «리뷰 완료»가 아니다 — 통과로 읽지 않는다.
|
|
110
|
+
if (!rr.reviewed) return refused('acp-review-not-completed', obs);
|
|
111
|
+
const mustFix = rr.mustFix.length;
|
|
112
|
+
if (rr.verdict === 'fail' || mustFix > 0) {
|
|
113
|
+
debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'must-fix', verdict: rr.verdict, mustFix, shouldFix: rr.shouldFix.length });
|
|
114
|
+
return { status: 'must-fix', mustFix, findings: rr.mustFix.slice(0, 10), verdict: rr.verdict };
|
|
115
|
+
}
|
|
116
|
+
debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'clean', verdict: rr.verdict, mustFix: 0, shouldFix: rr.shouldFix.length });
|
|
117
|
+
return { status: 'clean', mustFix: 0, shouldFix: rr.shouldFix.length };
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// 원문은 싣지 않는다 — 계정·프록시 문면이 섞일 수 있다(하니스 레인과 같은 규율).
|
|
120
|
+
return refused(/handshake timeout/i.test(error instanceof Error ? error.message : String(error)) ? 'acp-handshake-timeout' : 'acp-error', obs);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BUDGET_SNAPSHOT_ENV } from '../../execution-loop/launch-gate.js';
|
|
2
|
+
|
|
3
|
+
// Preserve the manifest contract except for two values generated per launch.
|
|
4
|
+
export function stablePodManifestText(applied: Array<Record<string, any>>): string {
|
|
5
|
+
const manifests = structuredClone(applied.filter((entry) => entry.kind === 'Job' || entry.kind === 'Secret'));
|
|
6
|
+
let snapshots = 0;
|
|
7
|
+
for (const manifest of manifests) {
|
|
8
|
+
if (manifest.kind !== 'Job') continue;
|
|
9
|
+
for (const container of manifest.spec?.template?.spec?.containers ?? []) {
|
|
10
|
+
for (const entry of container.env ?? []) {
|
|
11
|
+
if (entry.name !== BUDGET_SNAPSHOT_ENV) continue;
|
|
12
|
+
snapshots++;
|
|
13
|
+
// Keep every original byte except this one volatile numeric value.
|
|
14
|
+
const measuredAt = /("measuredAt"\s*:\s*)\d+/g;
|
|
15
|
+
const matches = [...entry.value.matchAll(measuredAt)];
|
|
16
|
+
if (matches.length !== 1) throw new Error('budget snapshot must have exactly one numeric measuredAt');
|
|
17
|
+
entry.value = entry.value.replace(measuredAt, (_match: string, prefix: string) => `${prefix}0`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (snapshots === 0) throw new Error('manifest comparison requires a budget snapshot');
|
|
22
|
+
return JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>');
|
|
23
|
+
}
|
|
@@ -154,6 +154,59 @@ export function parsePodPool(spec: string): PodPoolMember[] {
|
|
|
154
154
|
*/
|
|
155
155
|
export type PodPlacementKind = 'lite' | 'standard';
|
|
156
156
|
|
|
157
|
+
/** Identity carried by a launched pool Job and its Pod; absent source fields stay absent. */
|
|
158
|
+
export interface PodWorkIdentity {
|
|
159
|
+
ownerKind?: 'seat' | 'steward' | 'orchestrator' | 'external';
|
|
160
|
+
ownerId?: string;
|
|
161
|
+
taskCard?: string;
|
|
162
|
+
slotId?: string;
|
|
163
|
+
work?: 'harness' | 'authoring' | 'lite';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Kubernetes label values cannot exceed 63 characters or contain arbitrary card/owner text. */
|
|
167
|
+
export function podWorkLabels(identity: PodWorkIdentity): Record<string, string> {
|
|
168
|
+
const value = (raw: string | undefined): string | undefined => {
|
|
169
|
+
const cleaned = (raw ?? '').replace(/[^A-Za-z0-9._-]+/g, '-').slice(0, 63).replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, '');
|
|
170
|
+
return cleaned || undefined;
|
|
171
|
+
};
|
|
172
|
+
const ownerId = identity.ownerId && value(identity.ownerId) === identity.ownerId ? identity.ownerId : undefined;
|
|
173
|
+
const taskCard = identity.taskCard && value(identity.taskCard) === identity.taskCard ? identity.taskCard : undefined;
|
|
174
|
+
const slotId = identity.slotId && value(identity.slotId) === identity.slotId ? identity.slotId : undefined;
|
|
175
|
+
return {
|
|
176
|
+
...(identity.ownerKind && ownerId ? { 'elanous.owner-kind': identity.ownerKind, 'elanous.owner-id': ownerId } : {}),
|
|
177
|
+
...(taskCard ? { 'elanous.task-card': taskCard } : {}),
|
|
178
|
+
...(slotId ? { 'elanous.checklist': slotId } : {}),
|
|
179
|
+
...(identity.work ? { 'elanous.work': identity.work } : {}),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Minih standard-Job policy, independent of the configured pool member capacity. Not wired into allocation. */
|
|
184
|
+
export type MinihLocation = 'home' | 'external';
|
|
185
|
+
|
|
186
|
+
export function minihStandardCapacity(location: MinihLocation): number {
|
|
187
|
+
return location === 'home' ? 1 : 2;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** A drain withholds new slots until occupancy falls to the target; it never evicts Running Pods. */
|
|
191
|
+
export function decideMinihDrain(location: MinihLocation, runningPods: number, pendingPods = 0): {
|
|
192
|
+
capacity: number;
|
|
193
|
+
runningPods: number;
|
|
194
|
+
drainNewAdmissions: boolean;
|
|
195
|
+
availableSlots: number;
|
|
196
|
+
} {
|
|
197
|
+
if (![runningPods, pendingPods].every((count) => Number.isSafeInteger(count) && count >= 0)) {
|
|
198
|
+
throw new RangeError('node-c occupancy must be non-negative whole Pods');
|
|
199
|
+
}
|
|
200
|
+
const capacity = minihStandardCapacity(location);
|
|
201
|
+
const occupied = runningPods + pendingPods;
|
|
202
|
+
return {
|
|
203
|
+
capacity,
|
|
204
|
+
runningPods,
|
|
205
|
+
drainNewAdmissions: occupied > capacity,
|
|
206
|
+
availableSlots: Math.max(0, capacity - occupied),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
157
210
|
export interface PodPlacement {
|
|
158
211
|
readonly member: string;
|
|
159
212
|
readonly kind: PodPlacementKind | null;
|