elanous 0.2.24 → 0.2.27
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/{Q-7iofoxOEv1WX18S35of → Ev2jivDMTSoEc-5rIXdcy}/_buildManifest.js +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-a9c338f5bb556f42.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-a1ce306364f08da9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-07110da72c45e68f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2d76d4a7eae91bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-30007380f2e2a3c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e5a9302c105725a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-b93c04b5311c97ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-718a49e86bf25f9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-20662900d6b4b455.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-f707a509515ac50c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6a16a48d1aa6e91f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-26345242e4049f55.js → page-fcb06e305f515527.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-6acf5ec4e6c6d1af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-39f82acf619cca23.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-7c2c8f81b185f9c0.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-ae7aff07e32676bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-482c60c1bc540d0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-7cb996c1aa08b6f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-623e08fe4477d606.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-db460cd8aecb8490.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-ff27902d0b11ef4f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-8397a5c6ca569bf4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1917ea87ea71ab6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-25a302273b054fd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-670510eda8b9443f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d73c3f1e00d93986.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-65caacf54389081e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4bb7556e2e97a750.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-77e04b4f8762c666.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-b92caddb5c715f30.js → page-15c0a4095baddfba.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4eb96fc7241c2456.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-63e272a4cd3b6634.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d64ff212dc55d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-7f096248993fc2d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e47fc72049149a38.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f7d808e31e005895.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-5c2b24b5496dad73.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-76cdb531668b5191.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-e2b63345bba1a11f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-d376e0c83edc041a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d6db55fe2c04d128.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-87b88f551f421d8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-dab163b338e3b966.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-08019efef111ed2e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-0260ffc7eda50db1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-980ce6fe36ad95eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-99c4e6c7345a9156.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-0ab42e0f05823013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ad9220422d20ba33.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/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 +88 -7
- package/scripts/coord-msg-bridge.ts +209 -0
- package/scripts/coord-post.sh +40 -7
- package/scripts/coord-requests-bridge.ts +10 -5
- package/scripts/expose-rubric-suggest.ts +1 -1
- package/scripts/measure-tsc-affected-roots.ts +10 -1
- package/scripts/release-loop/auto-approve-node.ts +6 -0
- package/scripts/release-loop/export-check-node.ts +8 -5
- 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/node-verdict.ts +7 -2
- 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/task-notification.ts +30 -1
- package/src/agent-substrate/acp-implementer.ts +14 -7
- package/src/agent-substrate/pr-reviewer.ts +30 -10
- package/src/agent-substrate/review-observation.ts +9 -2
- package/src/agent-substrate/self-review-cli.ts +154 -16
- package/src/boot/daemon-tools/self-implement.ts +72 -4
- package/src/budget/cost-tier-advisor.ts +91 -0
- package/src/budget/llm-cost.ts +5 -1
- 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/control-cli.ts +29 -0
- package/src/cli/doctor-cli.ts +106 -3
- 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/msg-cli.ts +15 -5
- package/src/cli/pr-cli.ts +53 -0
- package/src/cli/pr-land-overlap-evidence.ts +18 -10
- package/src/cli/pr-land-pod-shadow.ts +54 -0
- package/src/cli/release-cli.ts +41 -12
- 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-cli.ts +121 -0
- package/src/cli/seat-requests-cli.ts +25 -0
- package/src/cli/self-utterances-cli.ts +140 -0
- package/src/cli/tasks-cli.ts +168 -14
- package/src/cli/usage-cli.ts +3 -1
- package/src/compact/verify-probe.ts +23 -3
- package/src/context-card/cell.ts +40 -0
- package/src/context-card/index.ts +50 -0
- package/src/control/control-status.ts +30 -1
- package/src/dashboard/boot-timing.ts +35 -0
- package/src/dashboard/index.ts +86 -24
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +26 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +10 -138
- package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
- package/src/debug/log-diet.ts +16 -4
- package/src/debug/log.ts +1 -1
- package/src/domains/morning-essential.ts +18 -3
- package/src/domains/release-tool.ts +29 -8
- package/src/domains/surface-events.ts +16 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/execution-loop/launch-gate.ts +158 -2
- package/src/fleet/host-doctor.ts +446 -0
- package/src/goals/judge.ts +20 -6
- package/src/graph-runner/runner.ts +12 -6
- 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 +102 -51
- package/src/harness/harness-stop.ts +93 -19
- package/src/index.ts +52 -179
- package/src/instance/current.ts +2 -6
- package/src/instance/resolve.ts +5 -6
- 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/openai-sampling-fields.ts +89 -0
- package/src/llm/runtime-model-family.ts +61 -0
- package/src/llm/zai-coding-plan.ts +27 -1
- package/src/llm.ts +17 -97
- package/src/machines/machine-ledger.ts +31 -3
- package/src/maturity/cli-maturity.ts +13 -3
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/msg/msg-store.ts +69 -7
- 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/ops/overview-collect.ts +3 -2
- package/src/ops/overview-owner.ts +29 -0
- package/src/plugin-hooks/shell-hook.ts +17 -2
- package/src/plugin-missions/evaluator-runner.ts +18 -2
- package/src/plugins/install/plugin-install.ts +11 -1
- package/src/preview/terminal.ts +15 -5
- package/src/project/project-store.ts +20 -0
- package/src/prompt-enhance/enhance.ts +11 -0
- package/src/release-loop/auto-start.ts +7 -5
- package/src/release-loop/checklist.ts +52 -5
- package/src/release-loop/feature-store.ts +10 -9
- 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/seat-loop/seat-loop.ts +5 -1
- 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 +75 -18
- package/src/self-dev/fabric-decompose-adapter.ts +9 -2
- package/src/self-dev/orchestrate.ts +6 -2
- package/src/self-dev/run-supervisor.ts +72 -8
- 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 +15 -29
- package/src/self-implement/goal-command-execution.ts +26 -0
- 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 +90 -20
- package/src/self-implement/premise-review.ts +159 -0
- package/src/self-implement/pwa-import-graph.ts +194 -7
- 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/self-implement/self-implement-runtime.ts +126 -21
- package/src/session/index.ts +14 -4
- package/src/session-runtime/index.ts +55 -11
- 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 +85 -1
- package/src/task-agent/live-moves.ts +14 -6
- package/src/task-agent/parent-host.ts +27 -3
- package/src/task-agent/rejudge-on-head.ts +370 -29
- package/src/task-agent/review-result-capture.ts +67 -2
- package/src/task-agent/shadow.ts +148 -21
- package/src/task-agent/task-hand.ts +22 -3
- 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 +236 -28
- package/src/tool-runtime/tool-search-runtime.ts +25 -0
- package/src/tui.ts +20 -1
- package/src/user-config.ts +21 -63
- 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/botlab/page-24282bf9f90031a5.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/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/release/page-1d809a87139dd024.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 → Ev2jivDMTSoEc-5rIXdcy}/_ssgManifest.js +0 -0
|
@@ -12,15 +12,23 @@
|
|
|
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
|
-
import { LIVE_MOVE_RESULT_EVENT, readTaskAgentState, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
|
|
17
|
+
import { LIVE_MOVE_RESULT_EVENT, cardPrNumber, readTaskAgentState, readTaskCard, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
|
|
18
|
+
import type { RejudgeDeps } from './rejudge-on-head.js';
|
|
17
19
|
|
|
18
20
|
export const REVIEW_RESULT_MISSING_EFFECT = 'review process produced no result';
|
|
19
21
|
/** 결과 파일은 있는데 읽지 못했다(EACCES 등) — «결과 없음»과 가른다(결과가 있었을 수 있다). */
|
|
20
22
|
export const REVIEW_RESULT_UNREADABLE_EFFECT = 'review result file unreadable';
|
|
23
|
+
/** Detached self review child: only this card and exact result file may trigger a completion tick. */
|
|
24
|
+
export const TA_REVIEW_COMPLETION_CARD_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_CARD';
|
|
25
|
+
export const TA_REVIEW_COMPLETION_STATE_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_STATE';
|
|
26
|
+
export const TA_REVIEW_COMPLETION_RESULT_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_RESULT';
|
|
21
27
|
/** 리뷰 한 판(1차 ⊕ 폴백 · ACP 300s 상한 여러 번)을 넉넉히 덮는 대기 상한 — 이 안에는 «아직»으로 본다. */
|
|
22
28
|
export const REVIEW_RESULT_WAIT_MS = 90 * 60_000;
|
|
23
29
|
|
|
30
|
+
const reviewRejudgeInFlight = new Set<string>();
|
|
31
|
+
|
|
24
32
|
const SHA40 = /^[0-9a-f]{40}$/i;
|
|
25
33
|
|
|
26
34
|
/** 결과 파일 경로 — 카드 상태 파일 옆 `review-results/` · 카드 id 는 파일 이름에 안전한 글자만. */
|
|
@@ -63,7 +71,8 @@ export function parseReviewResultOutput(text: string): ParsedReviewResult | null
|
|
|
63
71
|
...(Number.isSafeInteger(prRaw) && prRaw > 0 ? { pr: prRaw } : {}),
|
|
64
72
|
verdict: typeof v.verdict === 'string' ? v.verdict : null,
|
|
65
73
|
reviewed: typeof v.reviewed === 'boolean' ? v.reviewed : null,
|
|
66
|
-
|
|
74
|
+
// PR-LAND-MUSTFIX-NONE — 저장된 결과(옛 판 리뷰 · 다른 경로)에 «(없음 — …)» 표지 줄이 남아 있어도 리뷰 출력과 «같은» 판정으로 0 으로 센다.
|
|
75
|
+
mustFix: Array.isArray(v.mustFix) && v.mustFix.every((fix) => typeof fix === 'string') ? v.mustFix.filter((fix) => !isNoneSentinelFinding(fix)).length : null,
|
|
67
76
|
reviewRoute: typeof v.reviewRoute === 'string' ? v.reviewRoute : null,
|
|
68
77
|
head: typeof v.headCommit === 'string' && SHA40.test(v.headCommit) ? v.headCommit : null,
|
|
69
78
|
error: typeof v.error === 'string' ? v.error : null,
|
|
@@ -86,6 +95,8 @@ export function pendingReviewResults(card: TaskCard): ReviewRequest[] {
|
|
|
86
95
|
export interface CaptureReviewResultsOptions {
|
|
87
96
|
/** 이 카드들만 본다 — 없으면 상태 파일의 모든 카드. */
|
|
88
97
|
cardIds?: readonly string[];
|
|
98
|
+
/** A detached completion callback may only harvest its own result file. */
|
|
99
|
+
resultPaths?: readonly string[];
|
|
89
100
|
now?: () => Date;
|
|
90
101
|
/** 시험 seam — 결과 파일 읽기(없으면 ENOENT 를 던진다). */
|
|
91
102
|
readFile?: (path: string) => string;
|
|
@@ -121,6 +132,7 @@ export function captureReviewResults(statePath: string, opts: CaptureReviewResul
|
|
|
121
132
|
if (!card) continue;
|
|
122
133
|
for (const request of pendingReviewResults(card)) {
|
|
123
134
|
const resultPath = request.resultPath!;
|
|
135
|
+
if (opts.resultPaths && !opts.resultPaths.includes(resultPath)) continue;
|
|
124
136
|
let text: string | null = null;
|
|
125
137
|
let readError: string | null = null;
|
|
126
138
|
let unreadable = false;
|
|
@@ -182,6 +194,59 @@ export function captureReviewResults(statePath: string, opts: CaptureReviewResul
|
|
|
182
194
|
return out;
|
|
183
195
|
}
|
|
184
196
|
|
|
197
|
+
/** Run after the detached review child has fully written its JSON stdout. Never infer a card from PR alone. */
|
|
198
|
+
export async function rejudgeCompletedTaskReview(
|
|
199
|
+
env: Record<string, string | undefined> = process.env,
|
|
200
|
+
rejudge?: (cardId: string, statePath: string) => Promise<unknown>,
|
|
201
|
+
rejudgeDeps?: RejudgeDeps,
|
|
202
|
+
): Promise<boolean> {
|
|
203
|
+
const cardId = env[TA_REVIEW_COMPLETION_CARD_ENV];
|
|
204
|
+
const statePath = env[TA_REVIEW_COMPLETION_STATE_ENV];
|
|
205
|
+
const resultPath = env[TA_REVIEW_COMPLETION_RESULT_ENV];
|
|
206
|
+
if (!cardId || !statePath || !resultPath) return false;
|
|
207
|
+
const before = readTaskCard(cardId, statePath);
|
|
208
|
+
const bound = before?.reviewRequests?.find((item) => item.resultPath === resultPath);
|
|
209
|
+
if (before?.status !== 'launched' || before.taLand !== true || !bound || cardPrNumber(before) !== bound.pr
|
|
210
|
+
|| !SHA40.test(bound.head) || (before.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)) return false;
|
|
211
|
+
captureReviewResults(statePath, { cardIds: [cardId], resultPaths: [resultPath] });
|
|
212
|
+
const key = `${statePath}\0${cardId}\0${resultPath}`;
|
|
213
|
+
if (reviewRejudgeInFlight.has(key)) return false;
|
|
214
|
+
const card = readTaskCard(cardId, statePath);
|
|
215
|
+
const request = card?.reviewRequests?.find((item) => item.resultPath === resultPath);
|
|
216
|
+
if (card?.status !== 'launched' || card.taLand !== true || !request || cardPrNumber(card) !== request.pr
|
|
217
|
+
|| !(card.history ?? []).some((item) => item.event === LIVE_MOVE_RESULT_EVENT && item.resultPath === resultPath && item.kind === 'review'
|
|
218
|
+
&& item.pr === request.pr && SHA40.test(request.head) && SHA40.test(item.head ?? '')
|
|
219
|
+
&& item.effect?.startsWith('review result captured') && item.reviewed === true && item.head?.toLowerCase() === request.head.toLowerCase())
|
|
220
|
+
|| (card.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)) return false;
|
|
221
|
+
reviewRejudgeInFlight.add(key);
|
|
222
|
+
try {
|
|
223
|
+
const run = async (): Promise<unknown> => {
|
|
224
|
+
if (rejudgeDeps) {
|
|
225
|
+
const { rejudgeShadowCard } = await import('./rejudge-on-head.js');
|
|
226
|
+
return rejudgeShadowCard(cardId, statePath, rejudgeDeps, { pr: request.pr, head: request.head, kind: 'review', resultPath });
|
|
227
|
+
} else if (rejudge) return rejudge(cardId, statePath);
|
|
228
|
+
else {
|
|
229
|
+
const { rejudgeAsyncResultCard } = await import('./rejudge-on-head.js');
|
|
230
|
+
return rejudgeAsyncResultCard(cardId, statePath, {}, { pr: request.pr, head: request.head, kind: 'review', resultPath });
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const { requireCompletedHeadRejudge } = await import('./rejudge-on-head.js');
|
|
234
|
+
try { requireCompletedHeadRejudge(await run(), request.pr, request.head); }
|
|
235
|
+
catch { requireCompletedHeadRejudge(await run(), request.pr, request.head); } // Bounded retry; no marker on failed outcomes.
|
|
236
|
+
updateTaskCard(statePath, cardId, (current) => current?.status === 'launched' && current.taLand === true && cardPrNumber(current) === request.pr
|
|
237
|
+
&& (current.reviewRequests ?? []).some((item) => item.pr === request.pr && SHA40.test(item.head) && item.head.toLowerCase() === request.head.toLowerCase() && item.resultPath === resultPath)
|
|
238
|
+
&& (current.history ?? []).some((item) => item.event === LIVE_MOVE_RESULT_EVENT && item.resultPath === resultPath && item.kind === 'review'
|
|
239
|
+
&& item.pr === request.pr && SHA40.test(item.head ?? '') && item.head?.toLowerCase() === request.head.toLowerCase()
|
|
240
|
+
&& item.reviewed === true && item.effect?.startsWith('review result captured'))
|
|
241
|
+
&& !(current.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)
|
|
242
|
+
? { ...current, history: [...(current.history ?? []), { at: new Date().toISOString(), event: 'async-result-rejudge', kind: 'review', pr: request.pr, head: request.head, resultPath, effect: 'completion callback succeeded' }] }
|
|
243
|
+
: undefined);
|
|
244
|
+
} finally {
|
|
245
|
+
reviewRejudgeInFlight.delete(key);
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
185
250
|
/**
|
|
186
251
|
* 다음 수 판단의 입력 — 카드에 회수된 리뷰 결과 중 «그 머리(`head`)»의 «가장 최근» 결과가 실제로 돈(reviewed) pass 이고
|
|
187
252
|
* 리뷰한 머리가 40자 sha 일 때만 `selfReview` 모양으로 돌려준다(슈퍼바이저가 나르는 `self-implement-cli` 의 규칙과 같다 ·
|
package/src/task-agent/shadow.ts
CHANGED
|
@@ -10,16 +10,22 @@
|
|
|
10
10
|
* - 관측: `debug.log('task-agent', 'shadow-move', …)` → `elanous logs --category task-agent`.
|
|
11
11
|
*/
|
|
12
12
|
import { lstatSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
13
14
|
import { extname, join, relative, resolve } from 'node:path';
|
|
14
15
|
import { debug } from '../debug/log.js';
|
|
15
|
-
import { readTaskAgentState, readTaskCard, taskAgentStatePath, type CompletionKind, type TaskCard } from './task-hand.js';
|
|
16
|
+
import { readTaskAgentState, readTaskCard, taskAgentStatePath, TASK_CARD_PREFIX, type CompletionKind, type TaskCard } from './task-hand.js';
|
|
16
17
|
import type { SupervisorJobResult, SupervisorStopReason } from '../self-dev/run-supervisor.js';
|
|
17
18
|
import { executeNextAction, type DeliveryKind, type NextAction } from './actions.js';
|
|
18
19
|
import { judgeNextMove, type TaskJudgeInput, type TaskJudgement } from './judge.js';
|
|
19
20
|
import { HARNESS_RUN_ID_ENV } from '../harness/harness-space.js';
|
|
20
|
-
import {
|
|
21
|
+
import { appendRunLedgerEntry, loadRunLedger } from '../self-implement/run-ledger.js';
|
|
22
|
+
import { collectWiringEvidence, readCardRunSnapshot, type WiringEvidenceDeps, type CardRunEvidenceDeps } from './card-evidence.js';
|
|
23
|
+
import { remoteLedgerMirrorDir } from './parent-host.js';
|
|
24
|
+
import { prodInstanceRoot } from '../instance/resolve.js';
|
|
25
|
+
import { liveMoveHistoryEntry, recordLiveMoveHistory } from './live-move-history.js';
|
|
26
|
+
import { updateTaskCard } from './task-hand.js';
|
|
21
27
|
import { capturedSelfReview, captureReviewResults, hasCapturedPass } from './review-result-capture.js';
|
|
22
|
-
import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
|
|
28
|
+
import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveDecisionCard, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
|
|
23
29
|
|
|
24
30
|
export interface TaskAgentShadowInput {
|
|
25
31
|
runId: string | null;
|
|
@@ -45,6 +51,8 @@ export interface TaskAgentShadowMove {
|
|
|
45
51
|
pr: number | null;
|
|
46
52
|
/** TA-JUDGE-LIVE-SAFE — `taskAgent.liveMoves` 가 이 수를 실제로 했을 때만 실린다(없으면 종전 그대로 그림자). */
|
|
47
53
|
liveMove?: LiveMoveResult;
|
|
54
|
+
/** 원격 카드 결선이 미결일 때 런 원장 대기열 보존 결과. */
|
|
55
|
+
cardBinding?: 'pending' | 'queue-failed';
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
export interface TaskAgentShadowDeps {
|
|
@@ -60,10 +68,16 @@ export interface TaskAgentShadowDeps {
|
|
|
60
68
|
live?: LiveMoveDeps;
|
|
61
69
|
/** 카드 조회 상태 파일(시험 주입 · 운영 파일을 건드리지 않게). 기본 = `live.statePath` ⊕ `taskAgentStatePath()`. */
|
|
62
70
|
statePath?: string;
|
|
71
|
+
/** TA-WIRING-CHECK — 배선 근거 수집 의존(시험 주입 · 기본 = gh pr diff 한 번 ⊕ 카드 런 원장). */
|
|
72
|
+
wiring?: Omit<WiringEvidenceDeps, 'card'>;
|
|
63
73
|
/** Process env for the launched-run id (`ELANOUS_RUN_ID`) — test seam; default process.env. */
|
|
64
74
|
env?: NodeJS.ProcessEnv;
|
|
75
|
+
/** Remote pending-move ledger seam; defaults to the run ledger. */
|
|
76
|
+
queueMove?: typeof appendRunLedgerEntry;
|
|
65
77
|
}
|
|
66
78
|
|
|
79
|
+
export const REMOTE_CARD_MOVE_PENDING = 'task-agent-card-move-pending';
|
|
80
|
+
|
|
67
81
|
/** 카드 조회 상태 파일 — 조회 경로 전부가 같은 파일을 본다. */
|
|
68
82
|
function cardStatePath(deps: TaskAgentShadowDeps): string {
|
|
69
83
|
return deps.statePath ?? deps.live?.statePath ?? taskAgentStatePath();
|
|
@@ -172,6 +186,13 @@ function shadowCompletion(card: TaskCard | undefined, lookupFailed: boolean): Co
|
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, deps: TaskAgentShadowDeps = {}): Promise<TaskAgentShadowMove> {
|
|
189
|
+
const env = deps.env ?? process.env;
|
|
190
|
+
const remoteChild = !!env.ELANOUS_POD_NAME;
|
|
191
|
+
const hintedCard = env.ELANOUS_TASK_CARD_ID?.trim();
|
|
192
|
+
const pendingCardId = hintedCard?.startsWith(TASK_CARD_PREFIX) && hintedCard.length <= 63 && /^[A-Za-z0-9._-]+$/.test(hintedCard) ? hintedCard : null;
|
|
193
|
+
const parentRunId = env.ELANOUS_PARENT_RUN_ID?.trim() || null;
|
|
194
|
+
const matchesLaunchCard = (candidate: TaskCard | undefined): boolean => !!candidate && !!parentRunId
|
|
195
|
+
&& candidate.id === pendingCardId && candidate.runId === parentRunId;
|
|
175
196
|
// TA-REVIEW-RESULT-CAPTURE — 판단 «전»에 지난 live review 의 결과 파일을 회수한다(카드 원장을 아는 때만 · 던지지 않는다).
|
|
176
197
|
// 대기 중인 요청이 없으면 아무것도 쓰지 않는다(결과 파일 없는 카드의 동작은 종전과 같다).
|
|
177
198
|
const reviewLedger = cardLedgerPath(deps);
|
|
@@ -185,14 +206,22 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
185
206
|
let card: TaskCard | undefined;
|
|
186
207
|
let cardLookupFailed = false;
|
|
187
208
|
try {
|
|
188
|
-
|
|
189
|
-
if (
|
|
209
|
+
// Pod 에 발사 카드 id 가 있으면 그 id 만 믿는다. 같은 문장을 가진 다른 카드가 있어도 묶지 않는다.
|
|
210
|
+
if (remoteChild) {
|
|
211
|
+
if (pendingCardId) {
|
|
212
|
+
const found = deps.readCard ? deps.readCard(pendingCardId) : readTaskCard(pendingCardId, cardStatePath(deps));
|
|
213
|
+
if (matchesLaunchCard(found)) card = found;
|
|
214
|
+
}
|
|
215
|
+
} else if (successful) {
|
|
216
|
+
card = deps.readCard ? deps.readCard(successful.taskId) : readTaskCard(successful.taskId, cardStatePath(deps));
|
|
217
|
+
}
|
|
218
|
+
if (!card && successful && !deps.readCard && !remoteChild) {
|
|
190
219
|
const tasks = readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(cardStatePath(deps)).tasks ?? {};
|
|
191
220
|
const matches = Object.values(tasks).filter(candidate => candidate.status === 'launched' && candidate.text === successful.feature);
|
|
192
221
|
if (matches.length === 1) card = matches[0];
|
|
193
222
|
}
|
|
194
223
|
// TA-OWN-ALL-RUNS — 런 소유 카드: 입력 runId ⊕ 상속 ELANOUS_RUN_ID(Pod 자식의 부모 런) 중 카드 runId 와 «정확히» 같은 것만.
|
|
195
|
-
if (!card && !deps.readCard) card = runCardFor(input.runId, deps);
|
|
224
|
+
if (!card && !deps.readCard && !remoteChild) card = runCardFor(input.runId, deps);
|
|
196
225
|
} catch {
|
|
197
226
|
// Card lookup is optional; preserve the original PR judgement when unavailable — but mark the completion kind as unmeasured.
|
|
198
227
|
cardLookupFailed = true;
|
|
@@ -206,7 +235,7 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
206
235
|
try {
|
|
207
236
|
const reviewedPr = judgeInput.pr;
|
|
208
237
|
const prRun = input.results.find((result) => result.prNumber === reviewedPr);
|
|
209
|
-
const prCard = prRun ? (card && successful?.taskId === prRun.taskId ? card : liveCardFor([prRun], deps, input.runId)) : undefined;
|
|
238
|
+
const prCard = prRun ? (remoteChild ? card : card && successful?.taskId === prRun.taskId ? card : liveCardFor([prRun], deps, input.runId)) : undefined;
|
|
210
239
|
// 회수한 판정은 «리뷰한 머리»의 것이다 — 지금 PR 머리의 결과만 입력으로 쓴다(A 의 pass 로 B 를 land 쪽으로 보내지 않게 ·
|
|
211
240
|
// 여러 머리 결과가 역순으로 회수돼도 지금 머리 것을 고른다). 지금 머리 = 그 런 작업 트리에서 PR 머리 조회 ·
|
|
212
241
|
// 작업 트리가 없으면(Pod) 런이 낸 머리. 못 정하면 쓰지 않는다(종전처럼 review 수 → 새 머리면 새 리뷰).
|
|
@@ -275,20 +304,23 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
275
304
|
move.reason = wouldDo ?? judgement.reason;
|
|
276
305
|
move.wouldDo = null;
|
|
277
306
|
}
|
|
278
|
-
const liveKind: TaskAgentLiveMove | null = move.move === 'review' || move.move === 'propose-green' || move.move === 'propose-land' ? move.move : null;
|
|
307
|
+
const liveKind: TaskAgentLiveMove | null = move.move === 'review' || move.move === 'propose-green' || move.move === 'propose-land' || move.move === 'decision-card' ? move.move : null;
|
|
279
308
|
// 판단마다 해석한다 — 허용되지 않은 수를 판단할 때도 모르는 항목 경고가 남게.
|
|
280
309
|
const liveMoves = deps.liveMoves ?? await configuredTaskAgentLiveMoves();
|
|
281
|
-
const live = liveKind !== null && liveMoves.has(liveKind);
|
|
282
310
|
// 카드 id 는 모든 판단 관측에 싣는다(그림자 일치율을 카드로 잇는다) — 읽기 전용 조회.
|
|
283
311
|
// live 수는 «근거 결과»에 묶는다 — PR 수는 그 PR 을 낸 결과의 카드·작업 트리, 전달은 전달한 카드(다중 결과에서 남의 카드에 쓰지 않게).
|
|
284
312
|
const prResult = typeof judgeInput.pr === 'number' ? input.results.find((result) => result.prNumber === judgeInput.pr) : undefined;
|
|
285
|
-
const
|
|
313
|
+
const candidateBoundCard = delivery
|
|
286
314
|
? card
|
|
287
315
|
: prResult
|
|
288
|
-
? (card && successful?.taskId === prResult.taskId ? card : liveCardFor([prResult], deps, input.runId))
|
|
289
|
-
: undefined;
|
|
316
|
+
? (card && (successful?.taskId === prResult.taskId || (remoteChild && pendingCardId === card.id)) ? card : liveCardFor([prResult], deps, input.runId))
|
|
317
|
+
: liveKind === 'decision-card' ? card ?? liveCardFor(input.results, deps, input.runId) : undefined;
|
|
318
|
+
const boundCard = remoteChild && !matchesLaunchCard(candidateBoundCard) ? undefined : candidateBoundCard;
|
|
290
319
|
// PR 에 묶인 수는 그 PR 의 카드만 관측에 싣는다(못 찾으면 null — 다른 결과의 카드로 대체하지 않는다).
|
|
291
|
-
const
|
|
320
|
+
const candidateLiveCard = prResult || delivery ? boundCard : card ?? (cardLookupFailed ? undefined : liveCardFor(input.results, deps, input.runId));
|
|
321
|
+
const liveCard = remoteChild && !matchesLaunchCard(candidateLiveCard) ? undefined : candidateLiveCard;
|
|
322
|
+
// 원격 Pod 는 HQ 카드 파일을 갖지 않는다. id 를 전달받아도 현지 원장이 없으면 실행 수는 보류한다.
|
|
323
|
+
const live = liveKind !== null && liveMoves.has(liveKind) && (!remoteChild || boundCard !== undefined);
|
|
292
324
|
let liveMove: LiveMoveResult | undefined;
|
|
293
325
|
if (live) {
|
|
294
326
|
if (liveKind === 'review') {
|
|
@@ -313,6 +345,17 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
313
345
|
...(prResult.prUrl ? { prUrl: prResult.prUrl } : {}),
|
|
314
346
|
} } : {}),
|
|
315
347
|
}, liveMoveDeps(deps));
|
|
348
|
+
} else if (liveKind === 'decision-card') {
|
|
349
|
+
// Supervisor results carry failure text and reviewer must-fix items, but no screen tail.
|
|
350
|
+
// A stop reason alone is not evidence: the executor correctly raises no card when both are absent.
|
|
351
|
+
const evidenceResults = prResult ? [prResult] : input.results;
|
|
352
|
+
const signature = evidenceResults.find((result) => result.error?.message?.trim())?.error?.message;
|
|
353
|
+
const mustFix = evidenceResults.flatMap((result) => result.reviewMustFix ?? []);
|
|
354
|
+
liveMove = await executeLiveDecisionCard(boundCard, {
|
|
355
|
+
runId: input.runId, stopReason: input.stopReason, reason: move.reason,
|
|
356
|
+
...(prResult ? { pr: prResult.prNumber } : {}),
|
|
357
|
+
evidence: { ...(signature ? { signature } : {}), mustFix },
|
|
358
|
+
}, liveMoveDeps(deps));
|
|
316
359
|
} else {
|
|
317
360
|
const evidence: Record<string, string> = {};
|
|
318
361
|
if (boundCard && !delivery && judgeInput.prState === 'MERGED' && prResult) evidence[boundCard.id] = `#${prResult.prNumber}`;
|
|
@@ -320,26 +363,62 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
|
|
|
320
363
|
liveMove = executeLiveGreenProposal(boundCard, evidence, liveMoveDeps(deps));
|
|
321
364
|
}
|
|
322
365
|
}
|
|
323
|
-
// 판단한
|
|
324
|
-
(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
366
|
+
// TA-WIRING-CHECK — 병합 PR 은 판단한 «뒤» 배선 근거를 관측만 한다(move 불변 · 실패는 unknown 으로 남기고 던지지 않는다).
|
|
367
|
+
if (judgeInput.prState === 'MERGED' && typeof judgeInput.pr === 'number' && !delivery && liveCard) {
|
|
368
|
+
try {
|
|
369
|
+
const wiring = await collectWiringEvidence(judgeInput.pr, { ...deps.wiring, card: liveCard });
|
|
370
|
+
(deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'wiring-shadow', {
|
|
371
|
+
card: liveCard.id, pr: judgeInput.pr, required: wiring.required, liveRunRecorded: wiring.liveRunRecorded, unknown: wiring.unknown,
|
|
372
|
+
});
|
|
373
|
+
} catch { /* fail-soft — 관측일 뿐 판단을 막지 않는다 */ }
|
|
374
|
+
}
|
|
328
375
|
// TA-LIVE-MOVE-CARD-HISTORY — live-move 수(review·propose-green·propose-land)는 실행이든 그림자든 그 카드 history 에 한 줄.
|
|
329
376
|
// 결정·실행이 끝난 «뒤»에 덧붙이기만 한다(반환값·관측 무변경) · 실패는 관측만(live-move 를 막지 않는다).
|
|
330
|
-
if (liveKind !== null) recordLiveMoveOnCard({
|
|
377
|
+
if (liveKind !== null && (liveKind !== 'decision-card' || live) && (!remoteChild || liveCard)) recordLiveMoveOnCard({
|
|
331
378
|
liveKind, live, liveMove, card: live ? boundCard : liveCard, runId: input.runId,
|
|
332
379
|
pr: prResult?.prNumber ?? (typeof judgeInput.pr === 'number' ? judgeInput.pr : undefined),
|
|
333
380
|
shadowDetail: move.wouldDo ?? move.reason,
|
|
334
381
|
}, deps);
|
|
335
|
-
|
|
382
|
+
let cardBinding: TaskAgentShadowMove['cardBinding'];
|
|
383
|
+
if (liveKind !== null && !liveCard && remoteChild) {
|
|
384
|
+
const inheritedRunId = parentRunId || env[HARNESS_RUN_ID_ENV]?.trim() || null;
|
|
385
|
+
const reason = !parentRunId ? 'parent run id absent; HQ binding required'
|
|
386
|
+
: pendingCardId ? 'card id carried but ledger unavailable' : 'card id absent; parent run lookup required';
|
|
387
|
+
try {
|
|
388
|
+
if (!input.runId) throw new Error('runId absent');
|
|
389
|
+
(deps.queueMove ?? appendRunLedgerEntry)({
|
|
390
|
+
timestamp: new Date().toISOString(), runId: input.runId, event: REMOTE_CARD_MOVE_PENDING,
|
|
391
|
+
data: { id: randomUUID(), card: pendingCardId, parentRunId: inheritedRunId, kind: liveKind, pr: move.pr,
|
|
392
|
+
detail: move.wouldDo ?? move.reason, reason, executorResult: 'shadow' },
|
|
393
|
+
});
|
|
394
|
+
cardBinding = 'pending';
|
|
395
|
+
} catch (error) {
|
|
396
|
+
cardBinding = 'queue-failed';
|
|
397
|
+
try {
|
|
398
|
+
(deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'card-binding-queue-failed',
|
|
399
|
+
{ card: pendingCardId, runId: input.runId, parentRunId: inheritedRunId, kind: liveKind, reason: error instanceof Error ? error.message : String(error) });
|
|
400
|
+
} catch { /* queue failure remains visible in the return value */ }
|
|
401
|
+
}
|
|
402
|
+
if (cardBinding === 'pending') try {
|
|
403
|
+
(deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'card-binding-pending',
|
|
404
|
+
{ card: pendingCardId, runId: input.runId, parentRunId: inheritedRunId, kind: liveKind, reason });
|
|
405
|
+
} catch { /* queued evidence remains authoritative */ }
|
|
406
|
+
}
|
|
407
|
+
// 판단 관측은 원격 미결 수를 실제 원장에 기록한 결과까지 확정한 뒤 남긴다.
|
|
408
|
+
(deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'shadow-move', {
|
|
409
|
+
...move, completion: shadowCompletion(card, cardLookupFailed), card: liveCard?.id ?? pendingCardId,
|
|
410
|
+
live, liveExecuted: liveMove?.executed ?? false, ...(liveMove ? { liveOk: liveMove.ok } : {}),
|
|
411
|
+
...(cardBinding ? { cardBinding } : {}),
|
|
412
|
+
...(reviewFromCapture ? { reviewSource: 'captured-review-result' } : {}),
|
|
413
|
+
});
|
|
414
|
+
return { ...move, ...(liveMove ? { liveMove } : {}), ...(cardBinding ? { cardBinding } : {}) };
|
|
336
415
|
}
|
|
337
416
|
|
|
338
417
|
/**
|
|
339
418
|
* 런 id 폴백 — 입력 runId(슈퍼바이저 · Pod 면 자식 런) → 상속 `ELANOUS_RUN_ID`(발사기가 넘긴 부모 런) 순으로,
|
|
340
419
|
* 카드 runId 와 정확히 같고 그 카드가 하나뿐일 때만 쓴다. 못 찾으면 추측하지 않고 이유 한 줄을 남긴다(조용한 미스 0).
|
|
341
420
|
*/
|
|
342
|
-
function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps): TaskCard | undefined {
|
|
421
|
+
export function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps): TaskCard | undefined {
|
|
343
422
|
const own = runId?.trim() || undefined;
|
|
344
423
|
const inherited = (deps.env ?? process.env)[HARNESS_RUN_ID_ENV]?.trim() || undefined;
|
|
345
424
|
if (!own && !inherited) return undefined;
|
|
@@ -358,6 +437,54 @@ function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps)
|
|
|
358
437
|
return undefined;
|
|
359
438
|
}
|
|
360
439
|
|
|
440
|
+
/** HQ `tasks show` 가 원격 원장 거울의 미결 수를 카드에 회수한다. 부모→자식 원장 간선과 카드 id 를 함께 확인한다. */
|
|
441
|
+
export async function replayRemoteCardMoves(cardId: string, statePath: string, evidenceDeps: CardRunEvidenceDeps = {},
|
|
442
|
+
log: (category: string, event: string, data: Record<string, unknown>) => void = (c, e, d) => debug.log(c, e, d)): Promise<number> {
|
|
443
|
+
const card = readTaskCard(cardId, statePath);
|
|
444
|
+
if (!card?.runId || !card.parentHost) return 0;
|
|
445
|
+
// 원격 부모와 동일 runId 의 HQ 국소 원장은 발사 영수증만 있을 수 있다. 이 회수는 원격 거울을 우선한다.
|
|
446
|
+
const loadLedger = evidenceDeps.loadLedger ?? ((runId: string) =>
|
|
447
|
+
loadRunLedger(runId, remoteLedgerMirrorDir(prodInstanceRoot(), card.parentHost!.host)));
|
|
448
|
+
const snapshot = await readCardRunSnapshot(card, { ...evidenceDeps, loadLedger });
|
|
449
|
+
if (snapshot.readErrors?.length) {
|
|
450
|
+
log('task-agent', 'card-binding-replay-failed', { card: cardId, runId: card.runId, reason: snapshot.readErrors.join(' · ') });
|
|
451
|
+
return 0;
|
|
452
|
+
}
|
|
453
|
+
// 카드 id 가 빠진 옛 원격 줄은 부모 runId 의 유일 카드일 때만 역조회한다.
|
|
454
|
+
const matches = Object.values(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(statePath).tasks ?? {})
|
|
455
|
+
.filter((candidate) => candidate.runId === card.runId);
|
|
456
|
+
let written = 0;
|
|
457
|
+
for (const [childRunId, entries] of Object.entries(snapshot.children)) {
|
|
458
|
+
for (const entry of entries ?? []) {
|
|
459
|
+
if (entry.event !== REMOTE_CARD_MOVE_PENDING) continue;
|
|
460
|
+
const data = entry.data;
|
|
461
|
+
const id = data.id;
|
|
462
|
+
const kind = data.kind;
|
|
463
|
+
const linked = data.card === cardId || (data.card == null && matches.length === 1 && matches[0]?.id === cardId);
|
|
464
|
+
const parentMatches = data.parentRunId == null || data.parentRunId === card.runId;
|
|
465
|
+
if (!linked || !parentMatches || typeof id !== 'string' || !/^[a-f0-9-]{36}$/i.test(id)
|
|
466
|
+
|| !['review', 'propose-green', 'propose-land', 'decision-card'].includes(String(kind))) {
|
|
467
|
+
log('task-agent', 'card-binding-replay-skipped', { card: cardId, childRunId, pendingId: typeof id === 'string' ? id : null,
|
|
468
|
+
reason: !linked ? 'card mismatch or ambiguous runId' : !parentMatches ? 'parent run mismatch' : 'invalid pending move' });
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
const at = entry.timestamp ?? '';
|
|
472
|
+
if (!Number.isFinite(Date.parse(at))) continue;
|
|
473
|
+
const pr = Number.isSafeInteger(data.pr) && (data.pr as number) > 0 ? data.pr as number : undefined;
|
|
474
|
+
updateTaskCard(statePath, cardId, (current) => {
|
|
475
|
+
if (!current || current.runId !== card.runId || current.history.some((item) => item.sourceId === id)) return undefined;
|
|
476
|
+
const item = liveMoveHistoryEntry(current, { at, kind: kind as TaskAgentLiveMove, executorResult: 'shadow',
|
|
477
|
+
shadowDetail: typeof data.detail === 'string' ? data.detail : 'remote card binding pending', runId: childRunId,
|
|
478
|
+
...(pr ? { pr } : {}) });
|
|
479
|
+
written++;
|
|
480
|
+
return { ...current, history: [...current.history, { ...item, sourceId: id }] };
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (written) log('task-agent', 'card-binding-replayed', { card: cardId, parentRunId: card.runId, written });
|
|
485
|
+
return written;
|
|
486
|
+
}
|
|
487
|
+
|
|
361
488
|
/**
|
|
362
489
|
* 카드 history 에 live-move 한 줄 — 상태 파일은 카드를 읽은 곳과 같아야 한다: 주입한 경로(`live.statePath`) 또는
|
|
363
490
|
* 기본 리더를 썼을 때의 기본 경로. 주입한 카드 리더(`readCard`)만 있고 경로가 없으면 그 카드의 원장을 모른다 — 적지 않는다.
|
|
@@ -18,6 +18,7 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
|
18
18
|
import { withFileLockSync } from '../storage/file-lock.js';
|
|
19
19
|
import { checkCompletionEvidence, deliverableReceiptEvidence } from './completion-evidence.js';
|
|
20
20
|
import { judgeNextMove } from './judge.js';
|
|
21
|
+
import { loadRunLedger, runLedgerDir } from '../self-implement/run-ledger.js';
|
|
21
22
|
|
|
22
23
|
export interface ResolveHandTextDeps {
|
|
23
24
|
cwd: string;
|
|
@@ -94,6 +95,8 @@ export type CompletionKind = typeof COMPLETION_KINDS[number];
|
|
|
94
95
|
*/
|
|
95
96
|
export interface TaskCardEvent {
|
|
96
97
|
at: string; event: string; detail?: string; runId?: string; pr?: number;
|
|
98
|
+
/** 원격 미결 수를 HQ 에 한 번만 회수하기 위한 원장 사건 id. */
|
|
99
|
+
sourceId?: string;
|
|
97
100
|
/** `closed-by-hand` 줄만 — 닫은 사유 · 닫은 자리(`closeTaskCard`). */
|
|
98
101
|
reason?: string; by?: string;
|
|
99
102
|
kind?: string; executed?: boolean; ok?: boolean; executorResult?: 'shadow' | 'live'; head?: string; effect?: string;
|
|
@@ -167,7 +170,9 @@ export interface TaskCard {
|
|
|
167
170
|
*/
|
|
168
171
|
regates?: Array<{ pr: number; head: string; at: string; resultPath?: string; passed?: boolean; status?: string; baseCommit?: string; detail?: string;
|
|
169
172
|
/** REJUDGE base-stale — 같은 머리를 새 base 위에서 다시 잰 재게이트면, land 가 낡았다고 거절한 앞 재게이트의 base(멱등 키 = 머리 ⊕ 이 base). */
|
|
170
|
-
staleBase?: string
|
|
173
|
+
staleBase?: string;
|
|
174
|
+
/** TA-READY-BEFORE-REGATE — draft 때문에 실패한 같은 머리를 ready 뒤 딱 한 번 다시 잰다. */
|
|
175
|
+
readyRetry?: true }>;
|
|
171
176
|
/**
|
|
172
177
|
* Live land attempts, claimed before invocation, once per PR head even if the command fails.
|
|
173
178
|
* TA-LAND-RETRY-ON-INFRA — a failed attempt carries `class`/`reason`: `infra` (TA-side, allow-listed) leaves one more attempt on
|
|
@@ -316,7 +321,8 @@ export function launchArgs(card: Pick<TaskCard, 'text' | 'seat' | 'childLlm'>):
|
|
|
316
321
|
* 이유에 «착지 미확인»을 단다(착지했다/안 했다를 단정하지 않는다).
|
|
317
322
|
* 미션 카드는 스스로 발사하지 않는다 · 아직 안 뜬 조각의 선행이 덜 착지했으면 `wait after <id>`.
|
|
318
323
|
*/
|
|
319
|
-
export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string
|
|
324
|
+
export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string>, deps: { ledgerDir?: string } = {}): TaskCardMove {
|
|
325
|
+
// Completion callbacks record a shadow decision; do not suggest the live CLI here.
|
|
320
326
|
if (card.pieces) return { kind: 'wait', reason: `미션 — 조각 ${card.pieces.length}장이 선후대로 발사된다` };
|
|
321
327
|
const unmet = (card.after ?? []).filter((id) => !landed?.has(id));
|
|
322
328
|
if (card.status !== 'launched' && unmet.length > 0) return { kind: 'wait', reason: `after ${unmet.join(', ')}${landed ? '' : ' · 착지 미확인'}` };
|
|
@@ -324,6 +330,16 @@ export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string>): TaskC
|
|
|
324
330
|
if (card.status === 'launch-failed') return { kind: 'launch', command: launchArgs(card), reason: '직전 발사 실패 — 다시 발사' };
|
|
325
331
|
// live-move·hand-move 줄(관측 기록)은 실패 사유가 아니다 — 그 줄을 뺀 마지막 칸이 사유다(live-move 줄 없는 카드는 종전과 같다).
|
|
326
332
|
if (card.status === 'failed') return { kind: 'wait', reason: card.history.filter((item) => item.event !== LIVE_MOVE_HISTORY_EVENT && item.event !== LIVE_MOVE_RESULT_EVENT && item.event !== HAND_MOVE_HISTORY_EVENT).at(-1)?.detail ?? '런 실패 — PR·수확 가지 없음' };
|
|
333
|
+
if (card.status === 'launched' && card.runId) {
|
|
334
|
+
try {
|
|
335
|
+
const ledger = loadRunLedger(card.runId, deps.ledgerDir ?? runLedgerDir());
|
|
336
|
+
const terminal = ledger?.filter((entry) => entry.event === 'run-status').at(-1);
|
|
337
|
+
if (terminal && ['succeeded', 'failed', 'cancelled', 'abandoned'].includes(String(terminal.data.runStatus))) {
|
|
338
|
+
if (cardPrNumber(card) === undefined) return { kind: 'wait', reason: `런 원장 종료 — ${terminal.data.runStatus} · PR 없음` };
|
|
339
|
+
return { kind: 'wait', reason: `런 원장 종료 — ${terminal.data.runStatus} · 그림자 재판정은 완료 훅이 기록` };
|
|
340
|
+
}
|
|
341
|
+
} catch { /* 원장 결손·손상은 종료로 단정하지 않는다. */ }
|
|
342
|
+
}
|
|
327
343
|
return { kind: 'wait', reason: '발사됨 — 런 멈춤을 슈퍼바이저 그림자 판단(task-agent.shadow-move)이 받는다' };
|
|
328
344
|
}
|
|
329
345
|
|
|
@@ -487,7 +503,10 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
|
|
|
487
503
|
if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
|
|
488
504
|
const runId = mintRunId();
|
|
489
505
|
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,
|
|
506
|
+
const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
|
|
507
|
+
...(card.checklistId ? { ELANOUS_POD_SLOT_ID: card.checklistId } : {}),
|
|
508
|
+
...(card.seat ? { ELANOUS_POD_OWNER_KIND: 'seat', ELANOUS_POD_OWNER_ID: card.seat } : {}),
|
|
509
|
+
...(card.taLand ? { [TA_LAND_ENV]: '1' } : {}) }, cardLabelContext: taskCardLabelContext(card) };
|
|
491
510
|
let receipt: void | TaskLaunchReceipt;
|
|
492
511
|
try {
|
|
493
512
|
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
|
+
}
|