elanous 0.2.34 → 0.2.36
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/{abb4b98b.163e0f56e84ae35d.js → 053a429e.9a63436527cc751c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
- package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
- package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 2683.c9773a0c589b031b.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 275-02ea4c2a33980422.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{ffdc3a04.b9c23c1b28dd4a96.js → 2812ca6a.3b9f4a7a08885744.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 2986.45d7652e4f13557e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8817.61bb7ffbba502ecb.js → 3136.30aaaa5fa03662a3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3148-98efd4869d660a87.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3498.cf2a15a8a9e5b926.js → 3155.2587a55196ecb394.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3103.84470c8445962f04.js → 3324.a09703033abcbd2f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
- package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/{3819.163d4777f0a597f6.js → 3538.a445e50bb359d068.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
- package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 3727.7949ccaacaa71242.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
- package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 4286.b70c4520306817e8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 4615.8525eb0add35eba6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
- package/apps/pwa/out/_next/static/chunks/{3411-f87314c6c66ebc73.js → 5085-bce4904931767ca6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 528.38ce20ef8aa251ff.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 552.b7d061ad91eeac51.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3837.722e053fb9f321ad.js → 5711.957b095705c12560.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 575.d929793a53f27c4b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7562.948255cbc3e79d33.js → 599.c39c571b6733f2a2.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
- package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
- package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5446.edf141cff9ef647d.js → 6925.562d532110879886.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 6943.c6b24124853a47b2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 7481.39f7a4654907bf6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 771.c3cdb6c1f7f47c02.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 7891.03f910124a737985.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
- package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → 873d6c12.09bd499f57171543.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 8904.7d51af2dc033965c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
- package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 9250-072df22eaadaa6b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
- package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 9514.131c52cc75fe6439.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/{page-4fb31eb476dcbad3.js → page-083747f1d4518f61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → ceba0382.650712b56b85b582.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/da5ecc5c-b005ad8cac737d57.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
- package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_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/bin/elanous.mjs +3 -2
- package/catalog/providers/opengateway.yaml +25 -0
- package/docs/goal-context/01-goal-authoring-checks.md +8 -0
- package/docs/goal-context/03-verification-menu.md +24 -0
- package/docs/goal-context/04-mock-scenarios.md +100 -0
- package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +7 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/default-loop.yaml +63 -4
- package/graphs/document-loop.yaml +51 -3
- package/graphs/implement-loop.yaml +77 -4
- package/graphs/journey/ta-journey.yaml +11 -1
- package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
- package/graphs/journey/units/author-dialogue/observe.ts +96 -0
- package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
- package/graphs/operate-loop.yaml +51 -3
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/research-loop.yaml +137 -3
- package/graphs/test-diet/test-diet.yaml +3 -0
- package/graphs/wizard/recipes.yaml +44 -0
- package/graphs/wizard/wizard-loop.yaml +44 -0
- package/graphs/work/research-report.yaml +2 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +139 -5
- package/scripts/coord-role-pack.ts +19 -6
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/hq/standby-snapshot.ts +17 -12
- package/scripts/release-loop/docs-land-node.ts +21 -5
- package/scripts/release-loop/docs-node.ts +204 -8
- package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
- package/scripts/release-loop/gate-node.ts +427 -72
- package/scripts/release-loop/gate-partial.ts +65 -11
- package/scripts/release-loop/gate-radius-live.ts +177 -0
- package/scripts/release-loop/gate-radius-shadow.ts +1 -1
- package/scripts/release-loop/node-verdict.ts +14 -1
- package/scripts/release-loop/npm-publish-node.ts +66 -12
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
- package/scripts/release-loop/pwa-remote.ts +166 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +78 -15
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/release-loop/unattended-release.ts +2 -0
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/test-diet/lib.ts +6 -1
- package/scripts/test-diet/node.ts +194 -13
- package/scripts/ux-sim.ts +92 -0
- package/skills/README.md +1 -0
- package/src/acp/core-turn-bridge.ts +48 -6
- package/src/agent/delegate-hint.ts +16 -0
- package/src/agent/runner.ts +82 -2
- package/src/agent/self-ambient-cache.ts +8 -0
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/acp-reviewer.ts +39 -4
- package/src/agent-substrate/pr-reviewer.ts +72 -3
- package/src/agent-substrate/review-intent.ts +29 -2
- package/src/agent-substrate/review-observation.ts +3 -0
- package/src/agent-substrate/self-review-cli.ts +229 -28
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +240 -41
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/run-usage-rollup.ts +1 -0
- package/src/budget/usage-outcomes.ts +8 -4
- package/src/capture/tui-self-report.ts +102 -0
- package/src/chat/goal-continue-verdict.ts +41 -0
- package/src/chat/index.ts +30 -6
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/pickers/modal-runtime.ts +10 -27
- package/src/chat/tool-render/block.ts +32 -0
- package/src/chat/tool-render/dispatch.ts +2 -20
- package/src/chat/tool-render/result-text.ts +98 -0
- package/src/chat/turn-typeahead.ts +70 -7
- package/src/cli/agent-cli.ts +13 -2
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/doctor-cli.ts +26 -1
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +50 -7
- package/src/cli/log-event-names.ts +2 -0
- package/src/cli/make-cli.ts +247 -11
- package/src/cli/msg-cli.ts +117 -3
- package/src/cli/pod-cli.ts +77 -3
- package/src/cli/pr-cli.ts +34 -18
- package/src/cli/pr-land-base-read.ts +11 -2
- package/src/cli/pr-land-heavy-remote.ts +6 -3
- package/src/cli/pr-land-overlap-evidence.ts +23 -4
- package/src/cli/pr-land-pod-shadow-job.ts +3 -0
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-checklist-read-cli.ts +79 -0
- package/src/cli/release-cli.ts +92 -106
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/remote-resolve.ts +1 -1
- package/src/cli/root-tui-entry.ts +48 -0
- package/src/cli/sim-cli.ts +22 -0
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +1065 -338
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/cli/usage-cli.ts +13 -11
- package/src/clipboard/history.ts +179 -13
- package/src/config.ts +8 -1
- package/src/core-turn/run-core-turn.ts +4 -2
- package/src/core-turn/run-goal-loop.ts +73 -16
- package/src/core-turn/types.ts +6 -1
- package/src/dashboard/chat/acp-chat.ts +8 -0
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +280 -59
- package/src/dashboard/input/agent-wake.ts +7 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
- package/src/dashboard/input/chat-main-slash-command.ts +4 -2
- package/src/dashboard/input/goal-continue.ts +210 -0
- package/src/dashboard/input/goal-interim.ts +2 -0
- package/src/dashboard/input/internal-turn.ts +2 -8
- package/src/dashboard/input/seat-autowake.ts +9 -7
- package/src/dashboard/input/turn-autoheal.ts +52 -0
- package/src/dashboard/render/theme-resolver.ts +33 -4
- package/src/dashboard/seat-boot-preamble.ts +132 -5
- package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
- package/src/dashboard/slash-runtime/model-choices.ts +15 -0
- package/src/dashboard/stale-install-check.ts +3 -99
- package/src/debug/batch-queue.ts +119 -0
- package/src/debug/tui-log-tag.ts +67 -0
- package/src/display/agent-surface.ts +7 -0
- package/src/domains/schedule-registry.ts +16 -2
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/esc-abort-gate.ts +69 -0
- package/src/git-fs/idle-refresh.ts +76 -0
- package/src/git-fs/index.ts +18 -7
- package/src/git-fs/worktree.ts +137 -5
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/graph-cli.ts +18 -0
- package/src/graph-runner/runner.ts +173 -21
- package/src/graph-wizard/generate.ts +108 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grok/credential.ts +10 -3
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +163 -35
- package/src/harness/harness-incidents.ts +85 -1
- package/src/harness/launch-utterance-ledger.ts +208 -0
- package/src/harness/pod-control-send.ts +33 -5
- package/src/harness/self-send-remote.ts +69 -0
- package/src/harness/self-send-routing-guard.ts +6 -0
- package/src/harness/self-send-target.ts +4 -3
- package/src/impl-discipline/detector.ts +16 -4
- package/src/impl-discipline/system-prompt.ts +11 -0
- package/src/impl-discipline/types.ts +2 -2
- package/src/index.ts +822 -154
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/intake-plane/already-built-hint.ts +4 -2
- package/src/intake-plane/requirement-funnel.ts +29 -1
- package/src/light-cli.ts +32 -11
- package/src/llm/opengateway-models.ts +11 -0
- package/src/llm/provider-credentials.ts +14 -0
- package/src/llm/provider-detect.ts +8 -1
- package/src/llm/runtime-model-family.ts +2 -1
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +247 -59
- package/src/loops/msg-wake.ts +35 -39
- package/src/loops/orchestrator/inbox.ts +59 -11
- package/src/loops/orchestrator/knowhow-pack.ts +364 -0
- package/src/loops/orchestrator/tick.ts +5 -1
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/model-tier/llm-tier-map.ts +15 -1
- package/src/models/prompts.ts +17 -2
- package/src/msg/msg-post-office.ts +116 -0
- package/src/mss/logging/log-store.ts +79 -22
- package/src/native-tool-catalog.ts +15 -1
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +20 -2
- package/src/nexus/api/loop-resources.ts +13 -1
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/oauth/codex.ts +7 -0
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/overview-collect.ts +30 -9
- package/src/ops/overview.ts +22 -9
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/pr-tool/census.ts +261 -27
- package/src/prompt-library/session-guidance.ts +14 -0
- package/src/provider-summary.ts +8 -0
- package/src/pty-shell/herdr-agent-report.ts +118 -9
- package/src/pty-shell/herdr-prompt.ts +266 -0
- package/src/pty-shell/pty-control-ipc.ts +151 -8
- package/src/pty-shell/pty-manifest.ts +7 -0
- package/src/pty-shell/pty-special-keys.ts +42 -2
- package/src/pty-shell/stale-install-check.ts +99 -0
- package/src/pty-shell/tui-run-state.ts +14 -2
- package/src/release-loop/auto-start.ts +20 -2
- package/src/release-loop/checklist.ts +100 -4
- package/src/release-loop/landed-but-yellow.ts +129 -5
- package/src/release-loop/light-rc.ts +1 -0
- package/src/release-loop/rehearsal.ts +37 -21
- package/src/repl/index.ts +192 -17
- package/src/repl/ops-msg-bridge.ts +32 -0
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/self-dev/ask-launch-flow.ts +44 -5
- package/src/self-dev/cli-help-text.ts +17 -0
- package/src/self-dev/decompose-proposal.ts +172 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +48 -12
- package/src/self-dev/dev-pipeline.ts +8 -2
- package/src/self-dev/draft-residue.ts +37 -1
- package/src/self-dev/draft-sweep.ts +137 -11
- package/src/self-dev/draft-triage-rules.ts +138 -0
- package/src/self-dev/fleet-reduce.ts +3 -2
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-front-nodes.ts +112 -0
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/harness-run-cli.ts +3 -15
- package/src/self-dev/orchestrate-cli-text.ts +10 -0
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/review-provider-fallback.ts +35 -1
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-dev/self-orchestrate-runtime.ts +1 -11
- package/src/self-dev/shard-aggregate.ts +42 -5
- package/src/self-dev/shard-run.ts +8 -1
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/blocked-draft-policy.ts +20 -0
- package/src/self-implement/classify-shadow.ts +3 -7
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +257 -2
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/gate-baseline.ts +56 -17
- package/src/self-implement/gate-cli.ts +1 -0
- package/src/self-implement/gate-remote.ts +31 -20
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +534 -45
- package/src/self-implement/goal-author.ts +282 -7
- package/src/self-implement/goal-elaborate.ts +449 -0
- package/src/self-implement/goal-refine.ts +273 -0
- package/src/self-implement/graph-overlay-yaml.ts +14 -3
- package/src/self-implement/graph-variant.ts +40 -6
- package/src/self-implement/headless-elanous-driver.ts +19 -3
- package/src/self-implement/off-diff-evidence.ts +58 -6
- package/src/self-implement/orchestrator.ts +370 -62
- package/src/self-implement/pod-warm-pool-profile.ts +1 -0
- package/src/self-implement/pwa-import-graph.ts +1 -1
- package/src/self-implement/rework-budget-judgment.ts +5 -8
- package/src/self-implement/rework-policy.ts +30 -0
- package/src/self-implement/run-ledger.ts +108 -0
- package/src/self-implement/run-stop.ts +10 -1
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/running-runs.ts +29 -1
- package/src/self-implement/scope-adjacency.ts +115 -0
- package/src/self-implement/seams.ts +187 -28
- package/src/self-implement/stop-autoheal.ts +87 -1
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/session-runtime/index.ts +1 -1
- package/src/setup/llm-env-detect.ts +5 -0
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +408 -40
- package/src/skills/tools/msg-ask.ts +100 -0
- package/src/skills/tools/ops-ledger.ts +2 -1
- package/src/skills/tools/schedule-wakeup.ts +23 -4
- package/src/skills/tools/shell.ts +61 -6
- package/src/skills/tools/terminal-modal-inject.ts +1 -2
- package/src/skills/tools/terminal-modal.ts +10 -8
- package/src/skills/url-router.ts +41 -1
- package/src/smart-wizard/run.ts +66 -0
- package/src/status/bar.ts +34 -6
- package/src/status/status-provider-info.ts +37 -6
- package/src/steward/hold-hygiene.ts +24 -6
- package/src/steward/rejudge-tick.ts +10 -2
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/steward/triage-budget.ts +194 -0
- package/src/steward/triage.ts +20 -3
- package/src/task-agent/actions.ts +72 -2
- package/src/task-agent/green-sweep.ts +4 -0
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +182 -10
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/parent-host.ts +123 -3
- package/src/task-agent/rejudge-on-head.ts +15 -0
- package/src/task-agent/repair-cycle.ts +138 -32
- package/src/task-agent/repair-next-move.ts +31 -3
- package/src/task-agent/repair-outcomes.ts +29 -0
- package/src/task-agent/repair-worker.ts +14 -4
- package/src/task-agent/shadow.ts +48 -4
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +525 -57
- package/src/task-agent/task-parent-role-llm.ts +36 -0
- package/src/task-agent/tier-split.ts +196 -0
- package/src/task-agent/work-order-build.ts +2 -0
- package/src/task-agent/work-order.ts +3 -2
- package/src/task-orchestrator/generator-prompt.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +42 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +130 -11
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +19 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
- package/src/task-orchestrator/surfaces/pod-provenance.ts +82 -0
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
- package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +7 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +521 -40
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +759 -50
- package/src/task-orchestrator/surfaces/self-implement.ts +65 -2
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
- package/src/tty-foreground.ts +155 -0
- package/src/tui/README.md +2 -0
- package/src/tui/chat/background-job-status.ts +54 -0
- package/src/tui/chat/goal-interim.ts +173 -0
- package/src/tui/chat/log-view.ts +267 -0
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +695 -0
- package/src/tui/input/composer.ts +151 -0
- package/src/tui/seat-mail-boot.ts +59 -0
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +94 -0
- package/src/tui/slash/new-session.ts +35 -0
- package/src/tui/slash/resume.ts +75 -0
- package/src/tui-client/local-chat-turn.ts +282 -0
- package/src/tui-client/local-harness-command.ts +63 -0
- package/src/tui-client/local-provider-command.ts +184 -0
- package/src/tui-client/next-dashboard-runtime.ts +8 -0
- package/src/tui-client/next-loop-command.ts +70 -0
- package/src/tui-client/next-wakeup.ts +191 -0
- package/src/tui.ts +37 -0
- package/src/ui/modal-adapter.ts +2 -2
- package/src/user-config.ts +4 -2
- package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
- package/src/ux-sim/cli-config-audit-device.ts +121 -0
- package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
- package/src/ux-sim/event-monkey.ts +379 -0
- package/src/ux-sim/fake-bin.ts +87 -7
- package/src/ux-sim/fake-herdr.ts +238 -0
- package/src/ux-sim/fake-llm.ts +111 -6
- package/src/ux-sim/fault-glm-no-credential.ts +116 -0
- package/src/ux-sim/fault-nextmove-dispatch.ts +367 -0
- package/src/ux-sim/fault-pod-codex-503.ts +211 -0
- package/src/ux-sim/fault-scope-escape-lift.ts +216 -0
- package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
- package/src/ux-sim/goal-device.ts +619 -0
- package/src/ux-sim/in-process-cli.ts +22 -5
- package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
- package/src/ux-sim/mock-authoring-first-run.ts +97 -0
- package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
- package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
- package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
- package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
- package/src/ux-sim/onboarding-first-run-device.ts +269 -0
- package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
- package/src/ux-sim/subagent-tools-device.ts +81 -0
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
- package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
- package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
- package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
- package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
- package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2987-30cf9c2eb7b8bdd5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
- package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
- package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
- package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
- package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
- package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +0 -287
- package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
- package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
- package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
- package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
- package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
- /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
|
@@ -14,26 +14,38 @@
|
|
|
14
14
|
//
|
|
15
15
|
// index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
|
|
16
16
|
|
|
17
|
-
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
18
18
|
import { homedir, tmpdir } from 'node:os';
|
|
19
19
|
import { dirname, join } from 'node:path';
|
|
20
20
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
21
21
|
import { tierModel } from '../llm/model-defaults.js';
|
|
22
22
|
import { buildReviewObservation, safeLogText } from './review-observation.js';
|
|
23
|
-
import { DEFAULT_REVIEW_BACKEND } from './acp-reviewer.js';
|
|
23
|
+
import { DEFAULT_REVIEW_BACKEND, defaultAcpReviewTimeoutSec } from './acp-reviewer.js';
|
|
24
|
+
import { ZAI_OPENROUTER_FALLBACK_MODEL } from '../llm/zai-coding-plan.js';
|
|
25
|
+
import { debug } from '../debug/log.js';
|
|
24
26
|
import { ACP_BACKENDS, canonicalizeBackendId } from '../acp/backend-registry.js';
|
|
25
27
|
import { buildManualReviewIntent, intentFromPr, prIntentSectionCoverage, reviewIntentTruncationFromPr, reviewIntentTruncationObservation } from './review-intent.js';
|
|
26
28
|
import { budgetReviewerContext, reviewDiffBudgetObservation, splitDiffByFile, type ReviewImage, type ReviewInput, type ReviewerContextItem, type ReviewResult } from './pr-reviewer.js';
|
|
27
29
|
import type { ReferencedFileReader } from '../self-implement/goal-file-reader.js';
|
|
28
|
-
import { getUserConfig, type SubscriptionReviewerSpec } from '../user-config.js';
|
|
30
|
+
import { getUserConfig, type LLMProviderName, type RoleLlmSpec, type SubscriptionReviewerSpec } from '../user-config.js';
|
|
29
31
|
import { listRunLedgers, lookupPrGoalAcceptance, lookupRunLedger, type PrGoalAcceptanceLookup, type RunLedgerEntry, type RunLedgerLookup } from '../self-implement/run-ledger.js';
|
|
30
32
|
|
|
31
33
|
/** SUBSCRIPTION-EXHAUST-REROUTE — API reviewer when the configured `roleLlm.reviewer` lane is unavailable (off codex). */
|
|
32
34
|
export const ROLE_REVIEWER_FALLBACK_MODEL = 'openrouter/z-ai/glm-5.3';
|
|
33
35
|
|
|
36
|
+
/** Only an explicit provider+model role setting selects the API review model. */
|
|
37
|
+
export function apiReviewModelFromRoleSpec(spec: RoleLlmSpec | undefined): string | undefined {
|
|
38
|
+
const model = spec?.model?.trim();
|
|
39
|
+
if (!spec?.provider || !model) return undefined;
|
|
40
|
+
return spec.provider === 'openrouter' && !model.startsWith('openrouter/') ? `openrouter/${model}` : model;
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
export interface SelfReviewCliOpts {
|
|
35
44
|
intent?: string | undefined;
|
|
36
45
|
model?: string | undefined;
|
|
46
|
+
/** Explicit `roleLlm.review` provider+model, normalized by the CLI entry. */
|
|
47
|
+
configuredReviewModel?: string | undefined;
|
|
48
|
+
configuredReviewProvider?: LLMProviderName | undefined;
|
|
37
49
|
acp?: boolean | undefined;
|
|
38
50
|
acpModel?: string | undefined;
|
|
39
51
|
acpBackend?: string | undefined;
|
|
@@ -73,7 +85,7 @@ export interface SelfReviewCliDeps {
|
|
|
73
85
|
* 라우터 폴백(grok 등)으로 조용히 넘어가지 않고 실패를 오류로 낸다.
|
|
74
86
|
* `o.onResolved` — streamLLM 이 «실제로 응답한» provider·model 을 알린다.
|
|
75
87
|
*/
|
|
76
|
-
makeApiLlm(model: string, o?: { pinProvider?: boolean; onResolved?: (provider: string, model: string) => void }): (prompt: string) => Promise<string>;
|
|
88
|
+
makeApiLlm(model: string, o?: { pinProvider?: boolean; providerName?: LLMProviderName; onResolved?: (provider: string, model: string) => void }): (prompt: string) => Promise<string>;
|
|
77
89
|
/** `--acp` 경로 리뷰어 LLM(독립 프로세스). */
|
|
78
90
|
/**
|
|
79
91
|
* ⭐ `P4b` — 두 번째 인자가 **멀티미디어 통로**다.
|
|
@@ -127,27 +139,36 @@ export interface SelfReviewCliOutcome {
|
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
/** Saved results are round evidence only when their PR, exact head and reviewed status agree. */
|
|
130
|
-
|
|
142
|
+
function savedReviewRecords(pr: string, root = effectiveInstanceRoot()): Array<{ head: string; reviewedAt: number }> {
|
|
131
143
|
const dir = join(root, 'review-results');
|
|
132
144
|
let names: string[];
|
|
133
145
|
try { names = readdirSync(dir); } catch { return []; }
|
|
134
146
|
// Manual review saves in the operating house also use head10; the JSON's full head is authoritative.
|
|
135
147
|
const matching = new RegExp(`^.+-${pr}-([a-f0-9]{7,40})\\.json$`, 'i');
|
|
136
|
-
const
|
|
148
|
+
const records = new Map<string, { head: string; reviewedAt: number }>();
|
|
137
149
|
for (const name of names) {
|
|
138
150
|
const match = matching.exec(name);
|
|
139
151
|
if (!match) continue;
|
|
140
152
|
try {
|
|
141
|
-
const
|
|
153
|
+
const recordPath = join(dir, name);
|
|
154
|
+
const raw: unknown = JSON.parse(readFileSync(recordPath, 'utf8'));
|
|
142
155
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
|
|
143
156
|
const result = raw as Record<string, unknown>;
|
|
144
157
|
const head = result.headCommit;
|
|
145
158
|
if (String(result.pr) !== pr || result.reviewed !== true || typeof head !== 'string'
|
|
146
159
|
|| !COMMIT_OID.test(head) || !head.toLowerCase().startsWith(match[1]!.toLowerCase())) continue;
|
|
147
|
-
|
|
160
|
+
const normalized = head.toLowerCase();
|
|
161
|
+
const existing = records.get(normalized);
|
|
162
|
+
const reviewedAt = typeof result.reviewedAt === 'number' && Number.isFinite(result.reviewedAt)
|
|
163
|
+
? result.reviewedAt : statSync(recordPath).mtimeMs;
|
|
164
|
+
if (!existing || reviewedAt > existing.reviewedAt) records.set(normalized, { head: normalized, reviewedAt });
|
|
148
165
|
} catch { /* corrupt or partial result is not a completed round */ }
|
|
149
166
|
}
|
|
150
|
-
return [...
|
|
167
|
+
return [...records.values()];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
|
|
171
|
+
return savedReviewRecords(pr, root).map(({ head }) => head);
|
|
151
172
|
}
|
|
152
173
|
|
|
153
174
|
function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string | null {
|
|
@@ -166,14 +187,42 @@ function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string |
|
|
|
166
187
|
} catch { return null; }
|
|
167
188
|
}
|
|
168
189
|
|
|
190
|
+
function readCapOverride(pr: string): { head: string; reason: string } | undefined {
|
|
191
|
+
try {
|
|
192
|
+
const value = JSON.parse(readFileSync(join(effectiveInstanceRoot(), 'review-results', `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
|
|
193
|
+
if (String(value.pr) !== pr || typeof value.head !== 'string' || !COMMIT_OID.test(value.head)
|
|
194
|
+
|| typeof value.reason !== 'string' || !value.reason.trim()) return undefined;
|
|
195
|
+
return { head: value.head.toLowerCase(), reason: value.reason };
|
|
196
|
+
} catch { return undefined; }
|
|
197
|
+
}
|
|
198
|
+
|
|
169
199
|
function claimCapOverride(pr: string, head: string, reason: string, now: number): boolean {
|
|
170
200
|
const dir = join(effectiveInstanceRoot(), 'review-results');
|
|
171
201
|
try {
|
|
172
202
|
mkdirSync(dir, { recursive: true });
|
|
173
|
-
|
|
174
|
-
|
|
203
|
+
const normalizedHead = head.toLowerCase();
|
|
204
|
+
const authorizationPath = join(dir, `cap-override-${pr}.json`);
|
|
205
|
+
// The first over-cap review creates the durable, PR-scoped authorization record atomically.
|
|
206
|
+
writeFileSync(authorizationPath, JSON.stringify({ pr, head: normalizedHead, reason, claimedAt: now, use: 'initial-authorization' }) + '\n', { flag: 'wx' });
|
|
175
207
|
return true;
|
|
176
|
-
} catch {
|
|
208
|
+
} catch {
|
|
209
|
+
// An OP authorization applies to later heads of this PR while the allowlist remains active.
|
|
210
|
+
// Keep the initial claim immutable, and atomically record each additional head separately so
|
|
211
|
+
// retries of the same head cannot spend the grant twice.
|
|
212
|
+
try {
|
|
213
|
+
const authorization = JSON.parse(readFileSync(join(dir, `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
|
|
214
|
+
const authorizedHead = authorization.head;
|
|
215
|
+
if (String(authorization.pr) !== pr || typeof authorization.reason !== 'string' || !authorization.reason.trim()
|
|
216
|
+
|| authorization.reason !== reason
|
|
217
|
+
|| typeof authorizedHead !== 'string' || !COMMIT_OID.test(authorizedHead)
|
|
218
|
+
|| authorizedHead.toLowerCase() === head.toLowerCase()) return false;
|
|
219
|
+
const normalizedHead = head.toLowerCase();
|
|
220
|
+
writeFileSync(join(dir, `cap-override-${pr}-head-${normalizedHead}.json`), JSON.stringify({
|
|
221
|
+
pr, head: normalizedHead, reason, claimedAt: now, use: 'subsequent-head', authorizationHead: authorizedHead.toLowerCase(),
|
|
222
|
+
}) + '\n', { flag: 'wx' });
|
|
223
|
+
return true;
|
|
224
|
+
} catch { return false; }
|
|
225
|
+
}
|
|
177
226
|
}
|
|
178
227
|
|
|
179
228
|
/** OP owns this list. Missing, unreadable, or malformed traffic never grants a review exception. */
|
|
@@ -1331,6 +1380,34 @@ export function selfReviewJsonLine(results: readonly unknown[]): string {
|
|
|
1331
1380
|
return JSON.stringify(results.length === 1 ? results[0] : results) + '\n';
|
|
1332
1381
|
}
|
|
1333
1382
|
|
|
1383
|
+
// Normalize only whole-item forms whose complete text is an explicit no-finding
|
|
1384
|
+
// sentinel. Any extra clause stays in mustFix (fail-closed).
|
|
1385
|
+
const NO_FINDING_REVIEW_NOTE_ALLOWLIST: readonly RegExp[] = [
|
|
1386
|
+
/^(?:없음|해당\s*없음|none|nothing|n\/a)[.!。]?$/i,
|
|
1387
|
+
/^\((?:없음|해당\s*없음|none|nothing|n\/a)\)[.!。]?$/i,
|
|
1388
|
+
/^\(이 조각에서 확인된 코어 결함 없음\s*[—–-]\s*명시 intent 기준 mustFix 는 비움\)$/i,
|
|
1389
|
+
/^\(이 조각에서 검증된 (?:차단 )?결함은 발견되지 않음(?:\s*\(mustFix \[\]\))?\)$/i,
|
|
1390
|
+
];
|
|
1391
|
+
|
|
1392
|
+
function isNoFindingReviewNote(finding: string): boolean {
|
|
1393
|
+
const wholeItem = finding.trim();
|
|
1394
|
+
return NO_FINDING_REVIEW_NOTE_ALLOWLIST.some((form) => form.test(wholeItem));
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
function normalizeSavedReviewMustFix(result: Record<string, unknown>): { result: Record<string, unknown>; count: number } {
|
|
1398
|
+
if (!Array.isArray(result.mustFix)) return { result, count: 0 };
|
|
1399
|
+
const noFindingNotes = result.mustFix.filter((finding): finding is string =>
|
|
1400
|
+
typeof finding === 'string' && isNoFindingReviewNote(finding));
|
|
1401
|
+
if (noFindingNotes.length === 0) return { result, count: 0 };
|
|
1402
|
+
const retained = result.mustFix.filter((finding) =>
|
|
1403
|
+
typeof finding !== 'string' || !isNoFindingReviewNote(finding));
|
|
1404
|
+
const existingNotes = Array.isArray(result.noFindingNotes) ? result.noFindingNotes : [];
|
|
1405
|
+
return {
|
|
1406
|
+
result: { ...result, mustFix: retained, noFindingNotes: [...existingNotes, ...noFindingNotes] },
|
|
1407
|
+
count: noFindingNotes.length,
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1334
1411
|
export async function runSelfReviewCliCommand(
|
|
1335
1412
|
prArgs: string[],
|
|
1336
1413
|
opts: SelfReviewCliOpts,
|
|
@@ -1371,7 +1448,9 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1371
1448
|
return { results: [], failed: 1 };
|
|
1372
1449
|
}
|
|
1373
1450
|
|
|
1374
|
-
|
|
1451
|
+
// An explicit API model is the caller's reviewer choice even when a default ACP lane supplied both flags.
|
|
1452
|
+
const requestedModel = opts.model?.trim() || undefined;
|
|
1453
|
+
const useAcp = opts.acp === true && !requestedModel;
|
|
1375
1454
|
const acpModel = opts.acpModel?.trim() || undefined;
|
|
1376
1455
|
const acpBackendResolution = opts.acpBackend
|
|
1377
1456
|
? { backend: opts.acpBackend, source: 'cli' as const }
|
|
@@ -1379,7 +1458,6 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1379
1458
|
? { backend: opts.configuredAcpBackend, source: 'config' as const }
|
|
1380
1459
|
: { backend: DEFAULT_REVIEW_BACKEND, source: 'default' as const };
|
|
1381
1460
|
const acpBackend = acpBackendResolution.backend;
|
|
1382
|
-
const requestedModel = opts.model?.trim() || undefined;
|
|
1383
1461
|
const rawReviewDenyBackends = (getUserConfig().raw?.acp as { reviewDenyBackends?: unknown } | undefined)?.reviewDenyBackends;
|
|
1384
1462
|
const denyCheckedAt = Date.now();
|
|
1385
1463
|
const configuredReviewDenyBackends = validateReviewDenyBackends(rawReviewDenyBackends, denyCheckedAt);
|
|
@@ -1396,11 +1474,15 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1396
1474
|
? [canonicalizeBackendId(opts.acpBackend)]
|
|
1397
1475
|
: automaticFallbacks.backends;
|
|
1398
1476
|
const skippedAcpFallbackBackends = opts.acpBackend ? [] : automaticFallbacks.skipped;
|
|
1399
|
-
|
|
1400
|
-
|
|
1477
|
+
// ACP-REVIEW-VIA-TEAMCLAUDE: no `--acp-timeout` = the backend's default (claude 600s · others 300s).
|
|
1478
|
+
const explicitAcpTimeoutSec = Number.isFinite(Number(opts.acpTimeout)) && Number(opts.acpTimeout) > 0
|
|
1479
|
+
? Number(opts.acpTimeout) : undefined;
|
|
1480
|
+
const acpTimeoutSecFor = (backend: string): number => explicitAcpTimeoutSec ?? defaultAcpReviewTimeoutSec(backend);
|
|
1481
|
+
const acpTimeoutSec = explicitAcpTimeoutSec ?? 300;
|
|
1482
|
+
const primaryAcpTimeoutSec = acpTimeoutSecFor(acpBackend);
|
|
1401
1483
|
let acpReviewLLM: ((prompt: string, images?: readonly ReviewImage[]) => Promise<string>) | null = null;
|
|
1402
1484
|
if (useAcp) {
|
|
1403
|
-
acpReviewLLM = deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs:
|
|
1485
|
+
acpReviewLLM = deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: primaryAcpTimeoutSec * 1000 });
|
|
1404
1486
|
}
|
|
1405
1487
|
// ⭐ Reviewer selection source. An explicit flag always wins byte-for-byte; only without one does
|
|
1406
1488
|
// `roleLlm.reviewer` (the harness's reviewer row) pick the ACP lane. Worst case = today's API review.
|
|
@@ -1422,7 +1504,11 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1422
1504
|
deps.error(message);
|
|
1423
1505
|
return { results: opts.json ? [{ error: message, requestedModel }] : [], failed: 1 };
|
|
1424
1506
|
}
|
|
1425
|
-
const
|
|
1507
|
+
const configuredReviewModel = opts.configuredReviewModel?.trim() || undefined;
|
|
1508
|
+
// REVIEW-MODEL-ALIAS-PROVIDER: provider pinning needs GLM's OpenRouter model id, not the bare alias.
|
|
1509
|
+
const explicitApiModel = requestedModel?.toLowerCase() === 'glm' ? ROLE_REVIEWER_FALLBACK_MODEL : opts.model;
|
|
1510
|
+
const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (explicitApiModel || envModel || configuredReviewModel || roleFallbackModel || tierModel('better'));
|
|
1511
|
+
const configuredReviewSelected = !opts.model?.trim() && !envModel && Boolean(configuredReviewModel);
|
|
1426
1512
|
let roleReviewer: { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; model: string } | undefined;
|
|
1427
1513
|
let roleReviewerUnavailableReason: string | undefined;
|
|
1428
1514
|
let roleReviewerAvailabilityMs: number | undefined;
|
|
@@ -1444,7 +1530,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1444
1530
|
deps.log('role-reviewer-fallback', {
|
|
1445
1531
|
reviewerSource, roleReviewerProvider: opts.roleReviewer.provider, roleReviewerAvailabilityMs,
|
|
1446
1532
|
stage: 'availability', reason: roleReviewerUnavailableReason, fallbackModel: safeLogText(model),
|
|
1447
|
-
fallbackModelSource: roleFallbackModel ? 'role-fallback' : 'default',
|
|
1533
|
+
fallbackModelSource: configuredReviewSelected ? 'role-review-config' : roleFallbackModel ? 'role-fallback' : 'default',
|
|
1448
1534
|
}, { level: 'warn' });
|
|
1449
1535
|
}
|
|
1450
1536
|
}
|
|
@@ -1463,16 +1549,17 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1463
1549
|
const previousHeads = savedReviewHeads(pr);
|
|
1464
1550
|
const previousRoundCount = previousHeads.length;
|
|
1465
1551
|
const reason = opts.overCapReason?.trim();
|
|
1552
|
+
const authorization = previousRoundCount >= 5 ? readCapOverride(pr) : undefined;
|
|
1466
1553
|
deps.observeDoctorReview?.('round-counted', { pr, previousRoundCount, round: previousRoundCount + 1 });
|
|
1467
1554
|
const opAllowed = previousRoundCount >= 5 && opAllowsReviewOverCap(pr);
|
|
1468
1555
|
if (previousRoundCount >= 5) {
|
|
1469
1556
|
deps.observeDoctorReview?.('cap-attempt', { pr, previousRoundCount, round: previousRoundCount + 1, reasonProvided: Boolean(reason), opAllowed }, { level: 'warn' });
|
|
1470
1557
|
}
|
|
1471
|
-
if (previousRoundCount >= 5 && (!
|
|
1558
|
+
if (previousRoundCount >= 5 && (!opAllowed || (!authorization && !reason))) {
|
|
1472
1559
|
const refusalHead = prHeadCommit(pr, deps).value;
|
|
1473
1560
|
const message = !opAllowed
|
|
1474
1561
|
? `PR ${pr}: r5 상한 초과 리뷰는 OP traffic.json reviewOverCapAllow 허용 목록에 있어야 합니다.`
|
|
1475
|
-
: `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다.
|
|
1562
|
+
: `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. OP 허용 상태와 --over-cap-reason <사유>가 필요합니다.`;
|
|
1476
1563
|
deps.observeDoctorReview?.('cap-refused', { pr, head: refusalHead, previousRoundCount, round: previousRoundCount + 1, reason: opAllowed ? 'missing-reason' : 'not-op-allowlisted' }, { level: 'warn' });
|
|
1477
1564
|
deps.error(message);
|
|
1478
1565
|
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: refusalHead });
|
|
@@ -1480,9 +1567,69 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1480
1567
|
continue;
|
|
1481
1568
|
}
|
|
1482
1569
|
const diffRead = readDiffAtHead(pr, deps);
|
|
1483
|
-
if (previousRoundCount >= 5 &&
|
|
1484
|
-
|
|
1485
|
-
|
|
1570
|
+
if (previousRoundCount >= 5 && authorization && diffRead.headCommit.toLowerCase() === authorization.head) {
|
|
1571
|
+
const message = `PR ${pr}: 동일 head는 이미 승인 소모 기록이 있습니다.`;
|
|
1572
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'same-head-already-used' }, { level: 'warn' });
|
|
1573
|
+
deps.error(message);
|
|
1574
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1575
|
+
failed += 1;
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
if (previousRoundCount >= 5 && authorization && reason && reason !== authorization.reason) {
|
|
1579
|
+
const message = `PR ${pr}: 기존 PR 승인의 사유와 일치하지 않습니다.`;
|
|
1580
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'authorization-reason-mismatch' }, { level: 'warn' });
|
|
1581
|
+
deps.error(message);
|
|
1582
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1583
|
+
failed += 1;
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
let mergeOnlyDeltaRange: { base: string; head: string } | undefined;
|
|
1587
|
+
if (previousRoundCount >= 5 && authorization) {
|
|
1588
|
+
const git = deps.git;
|
|
1589
|
+
if (!git || diffRead.source !== 'sha-pinned' || diffRead.headCommitState !== 'known'
|
|
1590
|
+
|| diffRead.currentHeadCommitState !== 'known' || diffRead.stale || diffRead.diff.status !== 0) {
|
|
1591
|
+
const message = `PR ${pr}: 후속 head의 merge-only 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1592
|
+
deps.error(message);
|
|
1593
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1594
|
+
failed += 1;
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
const savedRecords = savedReviewRecords(pr);
|
|
1598
|
+
const latestReviewed = savedRecords.reduce<(typeof savedRecords)[number] | undefined>(
|
|
1599
|
+
(latest, record) => !latest || record.reviewedAt > latest.reviewedAt ? record : latest, undefined,
|
|
1600
|
+
);
|
|
1601
|
+
const classificationBase = latestReviewed?.head ?? authorization.head;
|
|
1602
|
+
const ancestry = git(['merge-base', '--is-ancestor', classificationBase, diffRead.headCommit], 10_000);
|
|
1603
|
+
const parents = git(['rev-list', '--parents', '-n', '1', diffRead.headCommit], 10_000);
|
|
1604
|
+
const parentFields = parents.stdout.trim().split(/\s+/);
|
|
1605
|
+
const headIsMerge = parentFields.length > 2;
|
|
1606
|
+
const deltaHead = headIsMerge ? parentFields[1] : diffRead.headCommit;
|
|
1607
|
+
if ((ancestry.status !== 0 && ancestry.status !== 1) || parents.status !== 0 || parentFields[0]?.toLowerCase() !== diffRead.headCommit.toLowerCase()
|
|
1608
|
+
|| !COMMIT_OID.test(deltaHead) || classificationBase === diffRead.headCommit.toLowerCase()) {
|
|
1609
|
+
const message = `PR ${pr}: 후속 head ancestry 또는 parent 정보를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1610
|
+
deps.error(message);
|
|
1611
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1612
|
+
failed += 1;
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
// A non-ancestor head can be a force-push rewind or rebase. It is still
|
|
1616
|
+
// reviewed from the pinned full PR diff; only a proven descendant can
|
|
1617
|
+
// qualify for the merge-only delta path.
|
|
1618
|
+
if (ancestry.status === 0) {
|
|
1619
|
+
// Non-merge commits brought in from main are reachable but are not on
|
|
1620
|
+
// this first-parent line. A merge-only head ends at its first parent;
|
|
1621
|
+
// a later PR commit remains in the candidate range.
|
|
1622
|
+
const commits = git(['rev-list', '--first-parent', '--no-merges', `${classificationBase}..${deltaHead}`], 10_000);
|
|
1623
|
+
if (commits.status !== 0) {
|
|
1624
|
+
const message = `PR ${pr}: 후속 head의 PR 변경 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1625
|
+
deps.error(message);
|
|
1626
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1627
|
+
failed += 1;
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1630
|
+
if (commits.stdout.trim() === '') mergeOnlyDeltaRange = { base: classificationBase, head: diffRead.headCommit.toLowerCase() };
|
|
1631
|
+
}
|
|
1632
|
+
} else if (previousRoundCount >= 5 && reason) {
|
|
1486
1633
|
const claimable = diffRead.source === 'sha-pinned' && diffRead.headCommitState === 'known'
|
|
1487
1634
|
&& diffRead.currentHeadCommitState === 'known' && !diffRead.stale && diffRead.diff.status === 0;
|
|
1488
1635
|
if (!claimable || !claimCapOverride(pr, diffRead.headCommit, reason, deps.now())) {
|
|
@@ -1495,6 +1642,25 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1495
1642
|
}
|
|
1496
1643
|
deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason }, { level: 'warn' });
|
|
1497
1644
|
}
|
|
1645
|
+
if (mergeOnlyDeltaRange) {
|
|
1646
|
+
const delta = deps.git?.(['diff', '--no-ext-diff', `${mergeOnlyDeltaRange.base}...${mergeOnlyDeltaRange.head}`], 25_000);
|
|
1647
|
+
if (!delta || delta.status !== 0) {
|
|
1648
|
+
const message = `PR ${pr}: merge-only 후속 head의 delta diff를 고정할 수 없습니다.`;
|
|
1649
|
+
deps.error(message);
|
|
1650
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1651
|
+
failed += 1;
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
diffRead.diff = delta;
|
|
1655
|
+
diffRead.baseCommit = mergeOnlyDeltaRange.base;
|
|
1656
|
+
}
|
|
1657
|
+
if (previousRoundCount >= 5 && authorization && !claimCapOverride(pr, diffRead.headCommit, authorization.reason, deps.now())) {
|
|
1658
|
+
const message = `PR ${pr}: 후속 head 승인 사용 기록을 남기지 못했습니다.`;
|
|
1659
|
+
deps.error(message);
|
|
1660
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1661
|
+
failed += 1;
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1498
1664
|
const localHeadComparison = compareLocalHead(pr, { value: diffRead.headCommit, state: diffRead.headCommitState }, deps);
|
|
1499
1665
|
const { diff } = diffRead;
|
|
1500
1666
|
const baseReviewerContext = hasProvidedReviewerContext
|
|
@@ -1668,7 +1834,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1668
1834
|
} else if (mergeState.kind === 'unpinnable') reviewCwdPinFallbackReason = mergeState.reason;
|
|
1669
1835
|
const reviewCwd = reviewPin?.cwd;
|
|
1670
1836
|
const prAcpReviewLLM = reviewCwd && useAcp
|
|
1671
|
-
? deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs:
|
|
1837
|
+
? deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: primaryAcpTimeoutSec * 1000, cwd: reviewCwd })
|
|
1672
1838
|
: acpReviewLLM;
|
|
1673
1839
|
let prRoleReviewer = roleReviewer;
|
|
1674
1840
|
if (reviewCwd && roleReviewer && opts.roleReviewer && deps.makeRoleReviewerLlm) {
|
|
@@ -1684,7 +1850,8 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1684
1850
|
// Role-config lane builds the API reviewer only when it falls back (`made().api` stays 0 on ACP success).
|
|
1685
1851
|
const responded: { provider?: string; model?: string } = {};
|
|
1686
1852
|
const makeApi = () => deps.makeApiLlm(model, {
|
|
1687
|
-
pinProvider: Boolean(opts.model?.trim()),
|
|
1853
|
+
pinProvider: Boolean(opts.model?.trim() || configuredReviewSelected),
|
|
1854
|
+
...(configuredReviewSelected && opts.configuredReviewProvider ? { providerName: opts.configuredReviewProvider } : {}),
|
|
1688
1855
|
onResolved: (provider, respondedModel) => { responded.provider = provider; responded.model = respondedModel; },
|
|
1689
1856
|
});
|
|
1690
1857
|
const llmReview = prRoleReviewer ? undefined : (prAcpReviewLLM ?? makeApi());
|
|
@@ -1748,7 +1915,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1748
1915
|
try {
|
|
1749
1916
|
const fallbackReview = await deps.reviewPullRequest(
|
|
1750
1917
|
reviewInput,
|
|
1751
|
-
deps.makeAcpLlm({ backend, timeoutMs:
|
|
1918
|
+
deps.makeAcpLlm({ backend, timeoutMs: acpTimeoutSecFor(backend) * 1000, ...(reviewCwd ? { cwd: reviewCwd } : {}) }),
|
|
1752
1919
|
);
|
|
1753
1920
|
if (fallbackReview.reviewed === true) {
|
|
1754
1921
|
review = fallbackReview;
|
|
@@ -1764,6 +1931,34 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1764
1931
|
}
|
|
1765
1932
|
}
|
|
1766
1933
|
}
|
|
1934
|
+
// OP #25981: an explicit ACP claude review that ends without a verdict («Autocompact is thrashing …» ·
|
|
1935
|
+
// reviewed:false · no JSON) goes once to GLM on the same head — never a claude retry (subscription quota).
|
|
1936
|
+
// An explicit `--acp-model` is the operator's model choice: it is not silently swapped for GLM.
|
|
1937
|
+
// GLM that throws or also ends without a verdict keeps the claude result, and says so (`glmReviewed`).
|
|
1938
|
+
let claudeFallbackGlm: { reason: string; model: string; glmReviewed: boolean; glmFailureReason?: string } | undefined;
|
|
1939
|
+
if (useAcp && !roleReview && !acpModel && canonicalizeBackendId(acpBackend) === 'claude' && review.reviewed !== true) {
|
|
1940
|
+
const reason = safeLogText(review.failureReason || 'reviewed=false', 400);
|
|
1941
|
+
debug.log('review.acp', 'claude-fallback-glm', { reason }, { level: 'warn' });
|
|
1942
|
+
fallbackAttempted = true;
|
|
1943
|
+
fallbackTriggerReason = reason;
|
|
1944
|
+
let glmFailureReason: string | undefined;
|
|
1945
|
+
try {
|
|
1946
|
+
const glmReview = await deps.reviewPullRequest(reviewInput, deps.makeApiLlm(ZAI_OPENROUTER_FALLBACK_MODEL, {
|
|
1947
|
+
pinProvider: true,
|
|
1948
|
+
onResolved: (provider, respondedModel) => { responded.provider = provider; responded.model = respondedModel; },
|
|
1949
|
+
}));
|
|
1950
|
+
if (glmReview.reviewed === true) {
|
|
1951
|
+
review = glmReview;
|
|
1952
|
+
selectedModel = ZAI_OPENROUTER_FALLBACK_MODEL;
|
|
1953
|
+
reviewRoute = 'api';
|
|
1954
|
+
} else glmFailureReason = safeLogText(glmReview.failureReason || 'reviewed=false', 400);
|
|
1955
|
+
} catch (error) {
|
|
1956
|
+
glmFailureReason = safeLogText(error instanceof Error ? error.message : String(error), 400);
|
|
1957
|
+
}
|
|
1958
|
+
if (glmFailureReason !== undefined) fallbackFailures.push({ backend: ZAI_OPENROUTER_FALLBACK_MODEL, reason: glmFailureReason });
|
|
1959
|
+
claudeFallbackGlm = { reason, model: ZAI_OPENROUTER_FALLBACK_MODEL, glmReviewed: glmFailureReason === undefined,
|
|
1960
|
+
...(glmFailureReason !== undefined ? { glmFailureReason } : {}) };
|
|
1961
|
+
}
|
|
1767
1962
|
reviewPin?.remove();
|
|
1768
1963
|
// reviewCwdCommit 은 «최종 판정을 낸 LLM 이 실제로 그 cwd 를 받았을 때만» 싣는다(role 실패 → API 폴백이면 안 싣는다).
|
|
1769
1964
|
const reviewedOnPin = Boolean(reviewPin) && (roleReview ? rolePinned : reviewRoute === 'acp-fallback' ? true : reviewRoute === 'acp' && useAcp);
|
|
@@ -1783,6 +1978,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1783
1978
|
...(fallbackBackend ? { requestedModel: primaryModel, actualBackend: `acp:${fallbackBackend}` } : {}),
|
|
1784
1979
|
...(fallbackNotAttemptedReason ? { fallbackNotAttemptedReason } : {}),
|
|
1785
1980
|
...(fallbackTriggerReason ? { fallbackTriggerReason } : {}),
|
|
1981
|
+
...(claudeFallbackGlm ? { claudeFallbackGlm } : {}),
|
|
1786
1982
|
...(fallbackFailures.length ? { fallbackFailures } : {}),
|
|
1787
1983
|
...(skippedAcpFallbackBackends.length ? { skippedAcpFallbackBackends } : {}),
|
|
1788
1984
|
};
|
|
@@ -1838,10 +2034,15 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1838
2034
|
if (review.reviewed === true) failed += 1;
|
|
1839
2035
|
} else {
|
|
1840
2036
|
const path = join(effectiveInstanceRoot(), 'review-results', `${opts.save}-${pr}-${diffRead.headCommit.slice(0, 12)}.json`);
|
|
1841
|
-
const
|
|
2037
|
+
const rawResult = results.at(-1);
|
|
2038
|
+
const normalized = rawResult && typeof rawResult === 'object'
|
|
2039
|
+
? normalizeSavedReviewMustFix(rawResult)
|
|
2040
|
+
: { result: rawResult, count: 0 };
|
|
2041
|
+
const result = normalized.result;
|
|
1842
2042
|
try {
|
|
1843
2043
|
mkdirSync(dirname(path), { recursive: true });
|
|
1844
2044
|
writeFileSync(path, selfReviewJsonLine([result]));
|
|
2045
|
+
if (normalized.count > 0) deps.log('mustfix-normalized', { pr, head: diffRead.headCommit, count: normalized.count });
|
|
1845
2046
|
} catch (error) {
|
|
1846
2047
|
failed += 1;
|
|
1847
2048
|
deps.error(`PR ${pr}: --save 실패: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -28,6 +28,116 @@ import { llmUsageCostFields } from '../budget/llm-cost.js';
|
|
|
28
28
|
|
|
29
29
|
const execFileAsync = promisify(execFile);
|
|
30
30
|
|
|
31
|
+
/** git 서브프로세스 대역 — term grep 동시성 계약을 실제 git 없이 재기 위한 교체점. */
|
|
32
|
+
export type ExecFileLike = (
|
|
33
|
+
file: string,
|
|
34
|
+
args: readonly string[],
|
|
35
|
+
options: { cwd?: string; encoding: 'utf-8'; maxBuffer: number },
|
|
36
|
+
) => Promise<{ stdout: string; stderr?: string }>;
|
|
37
|
+
|
|
38
|
+
const defaultExecFile: ExecFileLike = execFileAsync as unknown as ExecFileLike;
|
|
39
|
+
let execFileImpl: ExecFileLike = defaultExecFile;
|
|
40
|
+
|
|
41
|
+
/** 테스트 seam — null/미지정이면 실제 git 서브프로세스로 되돌린다. */
|
|
42
|
+
export function setExecFileForTest(fn?: ExecFileLike | null): void {
|
|
43
|
+
execFileImpl = fn ?? defaultExecFile;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** term 별 git grep 동시 실행 상한(기본 3 · OP 06:3x 실측 13개 동시 부하 101 을 막는다). */
|
|
47
|
+
export const TERM_GREP_CONCURRENCY = 3;
|
|
48
|
+
let termGrepConcurrency: number = TERM_GREP_CONCURRENCY;
|
|
49
|
+
|
|
50
|
+
/** 테스트 seam — 상한 없음(Infinity)과 결과 불변을 비교하기 위해 올린다. */
|
|
51
|
+
export function setTermGrepConcurrencyForTest(value?: number | null): void {
|
|
52
|
+
termGrepConcurrency = value ?? TERM_GREP_CONCURRENCY;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 상한 클램프 — 풀 크기와 관측값이 같은 규칙을 쓰게 한 곳에 둔다. */
|
|
56
|
+
function effectiveConcurrency(concurrency: number, width: number): number {
|
|
57
|
+
const limit = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : width;
|
|
58
|
+
return Math.max(1, Math.min(limit, width));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 동시 실행 상한 풀 — 결과 순서는 입력 순서 그대로(순위 계산이 순서에 의존하지 않게). */
|
|
62
|
+
async function mapWithConcurrency<T, R>(
|
|
63
|
+
items: readonly T[],
|
|
64
|
+
concurrency: number,
|
|
65
|
+
worker: (item: T) => Promise<R>,
|
|
66
|
+
): Promise<R[]> {
|
|
67
|
+
const results = new Array<R>(items.length);
|
|
68
|
+
const size = effectiveConcurrency(concurrency, items.length);
|
|
69
|
+
let cursor = 0;
|
|
70
|
+
await Promise.all(
|
|
71
|
+
Array.from({ length: size }, async () => {
|
|
72
|
+
for (let index = cursor++; index < items.length; index = cursor++) {
|
|
73
|
+
results[index] = await worker(items[index]!);
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** cwd seam 복원의 **단일 소유** — `process.chdir` 로 되돌리는 곳은 이 묶음(acquire/release) 하나뿐이다.
|
|
81
|
+
*
|
|
82
|
+
* ⛔ 왜 «생산» 이 소유하나: 한 번의 grounding 런은 persistent 코드 채널·skill 도구처럼 **임의 코드**를
|
|
83
|
+
* 지나고(`dispatchTool` → shell·pty), 그 코드가 cwd 를 옮긴 채 끝날 수 있다. 되돌리기를 «각 의존성» 에
|
|
84
|
+
* 맡기면 런이 마감(타임아웃)·예외로 끝나는 순간 그 되돌리기가 통째로 빠지고, 다음 런의 seam
|
|
85
|
+
* (`deps.cwd ?? process.cwd()`)이 **엉뚱한 트리를 저장소 루트로 읽어** 조용히 0건 grounding 을 낸다
|
|
86
|
+
* (#29343 r3 지적: 타임아웃 뒤 cwd seam 오염).
|
|
87
|
+
*
|
|
88
|
+
* ⛔ 소유는 «런마다» 가 아니라 «겹친 런 묶음» 하나다 — cwd 는 프로세스 전역이므로 런별 스냅샷은 겹침에서
|
|
89
|
+
* 깨진다(A 가 임시 트리로 옮긴 사이 B 가 시작하면 B 가 그 임시 트리를 «시작 자리» 로 저장하고, A 가 되돌린
|
|
90
|
+
* 뒤 B 가 다시 임시 트리로 되돌린다). ⇒ 첫 런이 시작 자리를 한 번 스냅샷하고, 겹쳐 들어온 런은 그 값을
|
|
91
|
+
* seam 으로 «물려받으며», 마지막으로 나가는 런만 되돌린다. 마감으로 «버려진» 런도 본문이 끝날 때까지
|
|
92
|
+
* holder 로 남으므로, 마감 뒤에 재개된 본문이 cwd 를 옮겨도 그 뒤의 런은 오염된 자리를 seam 으로 읽지 않고
|
|
93
|
+
* 본문이 끝나는 순간 되돌려진다.
|
|
94
|
+
* ⛔ 복원 보장의 «경계»: 복원은 런의 수명 안에서만 소유한다. 호출자가 마감으로 버렸는데 본문이 «끝나지
|
|
95
|
+
* 않으면» 전역 cwd 는 그 본문이 끝날 때까지 옮겨진 채 남는다 — 이 함수에는 호출자의 마감 신호가 들어오지
|
|
96
|
+
* 않고, 진행 중인 본문 밑의 cwd 를 남이 바꾸면 그 본문을 깨뜨린다. 그 사이 보장되는 것은 «겹쳐 들어온
|
|
97
|
+
* grounding 런의 seam 이 오염된 자리를 읽지 않는다» 이고, 본문이 끝나는 순간 마지막 holder 가 되돌린다
|
|
98
|
+
* (mission-codebase-gate.test.ts «마감 뒤 재개» 시험이 이 경계를 그대로 잰다).
|
|
99
|
+
* ⛔ 되돌리기 실패는 grounding 결과를 바꾸지 않되 «조용히 삼키지» 않는다 — `mission.grounding`
|
|
100
|
+
* `cwd-restore-failed` 로 남긴다(기존 이벤트 형식은 그대로). */
|
|
101
|
+
interface CwdSeamOwner { root: string; holders: number }
|
|
102
|
+
let cwdSeamOwner: CwdSeamOwner | null = null;
|
|
103
|
+
|
|
104
|
+
/** 소유 토큰 — `owned=false` 면 이 런은 묶음에 들지 않았다(시작 자리를 못 읽었다) ⇒ 되돌릴 것도 없다.
|
|
105
|
+
* ⛔ 절대 throw 하지 않는다: 지워진 cwd 에서도 `deps.cwd` 를 받은 호출은 예전처럼 진행해야 한다. */
|
|
106
|
+
interface CwdSeamLease { root: string | null; owned: boolean }
|
|
107
|
+
|
|
108
|
+
function acquireCwdSeam(): CwdSeamLease {
|
|
109
|
+
if (!cwdSeamOwner) {
|
|
110
|
+
let root: string;
|
|
111
|
+
try { root = process.cwd(); } catch { return { root: null, owned: false }; }
|
|
112
|
+
cwdSeamOwner = { root, holders: 0 };
|
|
113
|
+
}
|
|
114
|
+
cwdSeamOwner.holders += 1;
|
|
115
|
+
return { root: cwdSeamOwner.root, owned: true };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function releaseCwdSeam(lease: CwdSeamLease): void {
|
|
119
|
+
if (!lease.owned) return;
|
|
120
|
+
const owner = cwdSeamOwner;
|
|
121
|
+
if (!owner) return;
|
|
122
|
+
owner.holders -= 1;
|
|
123
|
+
if (owner.holders > 0) return;
|
|
124
|
+
cwdSeamOwner = null;
|
|
125
|
+
let current: string | null = null;
|
|
126
|
+
try { current = process.cwd(); } catch { /* 지워진 자리 — 아래에서 되돌린다 */ }
|
|
127
|
+
if (current === owner.root) return;
|
|
128
|
+
try {
|
|
129
|
+
process.chdir(owner.root);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
try {
|
|
132
|
+
debug.log('mission.grounding', 'cwd-restore-failed', {
|
|
133
|
+
root: owner.root,
|
|
134
|
+
current,
|
|
135
|
+
error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200),
|
|
136
|
+
}, { level: 'warn' });
|
|
137
|
+
} catch { /* 관측 실패가 grounding 을 바꾸지 않는다 */ }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
31
141
|
function logLlmUsage(site: 'codebase-gate-injected' | 'codebase-gate-dynamic', model: string, usage: LLMUsage): void {
|
|
32
142
|
try {
|
|
33
143
|
debug.log('llm.usage', 'llm-usage', {
|
|
@@ -215,28 +325,37 @@ export function commonTermCoverageWeight(matchLines: number): number {
|
|
|
215
325
|
}
|
|
216
326
|
|
|
217
327
|
async function searchRepository(terms: string[], limit: number, cwd: string | undefined, paths: string[], commonPaths = paths): Promise<string[]> {
|
|
218
|
-
|
|
328
|
+
// 같은 키워드는 한 번만 실행한다 — 실행·랭킹이 같은 목록을 쓰므로 결과는 결정적이다.
|
|
329
|
+
const uniqueTerms = [...new Set(terms)];
|
|
330
|
+
if (!uniqueTerms.length) return [];
|
|
219
331
|
const fileTerms = new Map<string, Set<string>>(); // file → 매칭된 서로 다른 term
|
|
220
332
|
const fileLines = new Map<string, number>(); // file → 총 매칭 라인 수
|
|
221
333
|
const fileTermLines = new Map<string, Map<string, number>>(); // file → term별 매칭 라인 수
|
|
222
334
|
const tooCommon = new Set<string>(); // 200+ 파일 매칭 = 밀도 감쇠 대상
|
|
223
|
-
const trackedPaths = await
|
|
335
|
+
const trackedPaths = await execFileImpl('git', ['ls-files', '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
|
|
224
336
|
.then(({ stdout }) => stdout.split('\n').filter(Boolean))
|
|
225
337
|
.catch(() => [] as string[]);
|
|
226
|
-
const pathMatches = new Map(
|
|
227
|
-
// term별 git grep 을
|
|
228
|
-
//
|
|
229
|
-
|
|
338
|
+
const pathMatches = new Map(uniqueTerms.map((term) => [term, trackedPaths.filter((file) => file.toLowerCase().includes(term)).length]));
|
|
339
|
+
// term별 git grep 을 동시 실행 상한 풀(기본 3)로 돌린다 — 무제한 병렬은 mbp 1분 부하 101·git grep
|
|
340
|
+
// 13개 동시(OP 06:3x 실측)를 만들었다. git grep=현재 워킹트리 파일 검색(history 아님)·
|
|
341
|
+
// gitignore/바이너리 자동 제외. 호출자가 코드와 문서를 분리한다.
|
|
342
|
+
const termGrepStartedAt = Date.now();
|
|
343
|
+
const perTerm = await mapWithConcurrency(uniqueTerms, termGrepConcurrency, async (t) => {
|
|
230
344
|
try {
|
|
231
345
|
// -c: file:count. -i 무시·-I 바이너리제외. term 하나씩(어느 term 이 걸렸는지 추적).
|
|
232
|
-
const { stdout } = await
|
|
346
|
+
const { stdout } = await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 });
|
|
233
347
|
const rows = stdout.split('\n').filter(Boolean);
|
|
234
|
-
const commonRows = commonPaths === paths ? rows : await
|
|
348
|
+
const commonRows = commonPaths === paths ? rows : await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...commonPaths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
|
|
235
349
|
.then(({ stdout }) => stdout.split('\n').filter(Boolean))
|
|
236
350
|
.catch(() => [] as string[]);
|
|
237
351
|
return { t, rows, commonCount: commonRows.length };
|
|
238
352
|
} catch { return { t, rows: [] as string[], commonCount: 0 }; } // git grep no-match = exit 1(throw) → 빈 결과
|
|
239
|
-
})
|
|
353
|
+
});
|
|
354
|
+
debug.log('grounding.search', 'term-grep-batch', {
|
|
355
|
+
terms: uniqueTerms.length,
|
|
356
|
+
concurrency: effectiveConcurrency(termGrepConcurrency, uniqueTerms.length),
|
|
357
|
+
ms: Date.now() - termGrepStartedAt,
|
|
358
|
+
});
|
|
240
359
|
for (const { t, rows, commonCount } of perTerm) {
|
|
241
360
|
if (commonCount > 200) {
|
|
242
361
|
tooCommon.add(t);
|
|
@@ -260,7 +379,7 @@ async function searchRepository(terms: string[], limit: number, cwd: string | un
|
|
|
260
379
|
const cover = [...ts].reduce((total, term) => total + (tooCommon.has(term)
|
|
261
380
|
? commonTermCoverageWeight(termLines?.get(term) ?? 0)
|
|
262
381
|
: 1), 0);
|
|
263
|
-
const nameTerms =
|
|
382
|
+
const nameTerms = uniqueTerms.filter((t) => f.toLowerCase().includes(t));
|
|
264
383
|
const nameWeight = nameTerms.reduce((total, term) => {
|
|
265
384
|
const matches = pathMatches.get(term) ?? 0;
|
|
266
385
|
// 경로상 유일한 식별자는 강한 +25를 유지하고, 공유 조각은 매칭 경로 수에 반비례해 감쇠한다.
|
|
@@ -531,8 +650,12 @@ export async function groundMissionInCodebase(
|
|
|
531
650
|
goal: string, deps: { cwd?: string; seedPaths?: readonly string[]; searchTerms?: SearchTermFn; skillIndex?: SkillIndexFn; pickSkills?: SkillPickFn; recallMemory?: RecallMemoryFn; recallSelf?: RecallSelfFn; refDigest?: RefDigestFn; persistent?: PersistentGroundingDeps | false } & CapsuleGroundingDeps = {},
|
|
532
651
|
): Promise<CodebaseGrounding> {
|
|
533
652
|
// 호출자가 준 root를 모든 저장소 채널과 corpus 관측에 공유한다. 미지정 호출은 기존처럼 프로세스 cwd를 쓴다.
|
|
653
|
+
// ⛔ seam 은 «읽기» 만 하지 않는다 — 시작 자리를 소유자(acquireCwdSeam)에게서 받고 finally 에서 돌려준다.
|
|
654
|
+
// 겹친 런은 첫 런의 스냅샷을 물려받으므로, 다른 런이 옮겨 놓은 cwd 를 시작 자리로 읽지 않는다.
|
|
655
|
+
const cwdLease = acquireCwdSeam();
|
|
534
656
|
const cwdSource = deps.cwd === undefined ? 'process' : 'caller';
|
|
535
|
-
|
|
657
|
+
// 시작 자리를 못 읽었으면(지워진 cwd) 소유하지 않는다 — caller root 는 그대로 쓰고, 미지정이면 예전처럼 process.cwd() 가 판정한다.
|
|
658
|
+
const searchRoot = deps.cwd ?? cwdLease.root ?? process.cwd();
|
|
536
659
|
const startedAt = performance.now();
|
|
537
660
|
let searchTermsElapsedMs = 0;
|
|
538
661
|
let persistentElapsedMs = 0;
|
|
@@ -695,7 +818,13 @@ export async function groundMissionInCodebase(
|
|
|
695
818
|
debug.log('mission.grounding', 'corpus', { grounded: false, reason: 'error', cwd: searchRoot, cwdSource, error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200), persistentEvidence: null, persistentStopReason: null, codeChannel: 'failed' }, { level: 'warn' });
|
|
696
819
|
return { grounded: false, context: '', files: [], persistentEvidence: [], skillFacts: [], codeFacts: [], memoryFacts: [], documentFacts: [], refFacts: [], ptyFacts: [] };
|
|
697
820
|
} finally {
|
|
698
|
-
|
|
821
|
+
// 정상·예외·타임아웃 어느 경로로 끝났든 소유를 돌려준다 — 마지막 holder 가 시작 자리로 되돌린다.
|
|
822
|
+
// 되돌리기를 관측보다 «먼저» 둔다: 관측이 무엇을 하든 복원이 빠지지 않는다.
|
|
823
|
+
try {
|
|
824
|
+
releaseCwdSeam(cwdLease);
|
|
825
|
+
} finally {
|
|
826
|
+
observeTiming();
|
|
827
|
+
}
|
|
699
828
|
}
|
|
700
829
|
}
|
|
701
830
|
|