elanous 0.2.32 → 0.2.34
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/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
- package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
- package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
- package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
- package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
- package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
- package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
- package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
- package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
- package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
- package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
- package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
- package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
- package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
- package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
- package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
- package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-8c66a3b24a745630.js → page-398c0faa173203f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-df3445b207ceceab.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
- package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.mjs +9 -2
- package/docs/goal-context/README.md +1 -0
- package/graphs/default-loop.yaml +20 -3
- package/graphs/document-loop.yaml +21 -2
- package/graphs/implement-loop.yaml +6 -0
- package/graphs/journey/SCENARIOS.md +33 -0
- package/graphs/journey/recipes.yaml +1 -0
- package/graphs/journey/ta-journey.yaml +84 -0
- package/graphs/journey/units/author/author.yaml +20 -0
- package/graphs/journey/units/author/recipes.yaml +2 -0
- package/graphs/journey/units/green/green.yaml +20 -0
- package/graphs/journey/units/green/recipes.yaml +2 -0
- package/graphs/journey/units/pr/pr.yaml +20 -0
- package/graphs/journey/units/pr/recipes.yaml +2 -0
- package/graphs/journey/units/remember/recipes.yaml +2 -0
- package/graphs/journey/units/remember/remember.yaml +20 -0
- package/graphs/operate-loop.yaml +21 -2
- package/graphs/overlays/stop-heal-ladder.yaml +1 -1
- package/graphs/release-rehearsal/recipes.yaml +1 -1
- package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
- package/graphs/research-loop.yaml +23 -2
- package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
- package/graphs/units/dispatch-pod/recipes.yaml +14 -0
- package/graphs/units/entry/entry.yaml +50 -0
- package/graphs/units/entry/recipes.yaml +14 -0
- package/graphs/units/harvest/harvest.yaml +25 -0
- package/graphs/units/harvest/recipes.yaml +4 -0
- package/graphs/units/land/land.yaml +45 -0
- package/graphs/units/land/recipes.yaml +3 -0
- package/graphs/units/recipes.yaml +7 -0
- package/graphs/units/recover.yaml +39 -0
- package/graphs/units/reflect/recipes.yaml +3 -0
- package/graphs/units/reflect/reflect.yaml +15 -0
- package/graphs/units/task-agent-recover-review.yaml +17 -0
- package/graphs/units/task-agent-recover-wait.yaml +17 -0
- package/graphs/units/verbs/make-doc.yaml +34 -0
- package/graphs/units/verbs/recipes.yaml +33 -0
- package/graphs/units/verbs/verify.yaml +55 -0
- package/graphs/work/recipes.yaml +2 -0
- package/graphs/work/research-report.yaml +28 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +69 -16
- package/scripts/docs/generate-graph-anatomy.ts +19 -2
- package/scripts/graph-harvest-unit.ts +22 -0
- package/scripts/graph-units/journey-stub.ts +6 -0
- package/scripts/graph-units/land-enqueue.ts +78 -0
- package/scripts/graph-units/recover-plan.ts +15 -0
- package/scripts/graph-units/reflect-node.ts +88 -0
- package/scripts/graph-units/ta-journey-observe.ts +109 -0
- package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
- package/scripts/graph-units/verbs/verify-stage.ts +75 -0
- package/scripts/graph-units/verbs-envelope.ts +139 -0
- package/scripts/hq/standby-snapshot.ts +25 -0
- package/scripts/public-export.ts +43 -1
- package/scripts/ratchets/train-side-invariants.sh +45 -0
- package/scripts/release-loop/auto-approve-node.ts +30 -16
- package/scripts/release-loop/gate-closure.ts +5 -1
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-node.ts +498 -31
- package/scripts/release-loop/gate-partial.ts +3 -3
- package/scripts/release-loop/gate-radius-shadow.ts +138 -0
- package/scripts/release-loop/gate-traffic-mode.ts +128 -0
- package/scripts/release-loop/gate-triage-node.ts +5 -2
- package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
- package/scripts/release-loop/known-issues-node.ts +77 -8
- package/scripts/release-loop/preflight.ts +93 -7
- package/scripts/release-loop/publish-node.ts +60 -9
- package/scripts/release-loop/resume-cap.ts +56 -0
- package/scripts/release-loop/resume-release.ts +114 -15
- package/scripts/release-loop/resume.ts +24 -1
- package/scripts/release-loop/tui-sim-node.ts +8 -2
- package/scripts/release-loop/unattended-release.ts +8 -2
- package/src/acp/core-turn-bridge.ts +20 -5
- package/src/acp/reasoning-thought-buffer.ts +45 -0
- package/src/agent-substrate/acp-reviewer.ts +52 -12
- package/src/agent-substrate/review-finding-key.ts +53 -0
- package/src/agent-substrate/self-review-cli.ts +126 -5
- package/src/ask-user-question/pending-questions.ts +1 -1
- package/src/autopilot/pr-manager.ts +192 -43
- package/src/chat/tool-render/dispatch.ts +62 -10
- package/src/cli/control-cli.ts +24 -7
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/light-entry-route.ts +35 -0
- package/src/cli/llm-detect-cli.ts +23 -1
- package/src/cli/pr-cli.ts +76 -12
- package/src/cli/pr-land-base-read.ts +2 -0
- package/src/cli/pr-land-overlap-evidence.ts +154 -16
- package/src/cli/pr-land-recovery.ts +64 -0
- package/src/cli/pty-takeover-cli.ts +6 -5
- package/src/cli/release-cli.ts +120 -33
- package/src/cli/release-run-if-ready.ts +29 -28
- package/src/cli/release-single-flight.ts +178 -0
- package/src/cli/seat-cli.ts +37 -0
- package/src/cli/setup-cli.ts +40 -1
- package/src/cli/tasks-cli.ts +149 -5
- package/src/control/control-status.ts +8 -3
- package/src/control-plane/ledger.ts +5 -3
- package/src/control-plane/server.ts +5 -3
- package/src/core-turn/short-question.ts +5 -1
- package/src/dashboard/index.ts +36 -67
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/seat-autowake.ts +56 -3
- package/src/dashboard/seat-boot-preamble.ts +1 -1
- package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
- package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
- package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
- package/src/dashboard/turn-preamble.ts +47 -1
- package/src/dashboard/turn-stream-formatter.ts +34 -1
- package/src/dashboard/turn-stream-runtime.ts +2 -0
- package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
- package/src/domains/guardian-tick.ts +54 -2
- package/src/domains/outbound-alert.ts +3 -2
- package/src/extractors.ts +3 -1
- package/src/git-fs/retry.ts +4 -0
- package/src/git-fs/runner.ts +2 -0
- package/src/graph-runner/runner.ts +114 -44
- package/src/grok/credential.ts +5 -0
- package/src/harness/harness-cli-command.ts +39 -10
- package/src/harness/harness-incidents.ts +4 -0
- package/src/harness/harness-pod-dispatch.ts +38 -1
- package/src/harness/harness-salvage-cli.ts +14 -2
- package/src/index.ts +192 -8
- package/src/intake-plane/already-built-hint.ts +89 -0
- package/src/knowhow/pack.ts +199 -0
- package/src/light-cli.ts +95 -0
- package/src/llm.ts +55 -9
- package/src/loops/budget.ts +95 -0
- package/src/loops/msg-wake.ts +8 -2
- package/src/loops/orchestrator/traffic.ts +132 -1
- package/src/mss/logging/log-store.ts +4 -5
- package/src/nexus/api/graphs-api.ts +22 -3
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/ops-api.ts +12 -0
- package/src/oauth/claude-pty-maturity.ts +66 -0
- package/src/oauth/codex-access-mirror.ts +55 -0
- package/src/oauth/fallback-chain.ts +1 -1
- package/src/onboarding/first-run.ts +5 -3
- package/src/onboarding/non-interactive.ts +64 -13
- package/src/onboarding.ts +10 -2
- package/src/ops/overview-collect.ts +36 -1
- package/src/ops/overview.ts +11 -0
- package/src/pr-tool/census.ts +23 -5
- package/src/pr-tool/inflight-registry.ts +160 -7
- package/src/prompt-library/gpt6-family-addendum.ts +14 -1
- package/src/pty-shell/herdr-agent-report.ts +442 -0
- package/src/pty-shell/pty-control-ipc.ts +5 -5
- package/src/pty-shell/pty-write-outcome.ts +24 -6
- package/src/pty-shell/tui-run-state.ts +117 -3
- package/src/release-loop/checklist.ts +79 -5
- package/src/release-loop/feature-store.ts +19 -2
- package/src/release-loop/placement.ts +10 -3
- package/src/release-loop/rehearsal.ts +205 -25
- package/src/release-loop/rubric.ts +16 -2
- package/src/self-dev/draft-sweep.ts +52 -3
- package/src/self-dev/graph-journey-nodes.ts +10 -6
- package/src/self-dev/graph-journey-route.ts +60 -6
- package/src/self-dev/orchestrate.ts +79 -3
- package/src/self-dev/run-supervisor.ts +107 -12
- package/src/self-dev/run-types.ts +5 -1
- package/src/self-implement/gate-baseline.ts +49 -5
- package/src/self-implement/gate-remote.ts +9 -5
- package/src/self-implement/goal-author-identity.ts +66 -0
- package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
- package/src/self-implement/goal-author.ts +4 -120
- package/src/self-implement/graph-overlay-yaml.ts +17 -2
- package/src/self-implement/graph-unit-flatten.ts +103 -0
- package/src/self-implement/graph-unit-resolver.ts +107 -0
- package/src/self-implement/graph-yaml.ts +151 -1
- package/src/self-implement/headless-elanous-driver.ts +1 -0
- package/src/self-implement/knowhow-pack.ts +103 -0
- package/src/self-implement/orchestrator.ts +8 -0
- package/src/self-implement/pod-warm-pool-profile.ts +45 -0
- package/src/self-implement/review-mustfix-class.ts +203 -0
- package/src/self-implement/run-stop.ts +8 -2
- package/src/self-implement/seams.ts +32 -1
- package/src/self-implement/stop-autoheal.ts +25 -1
- package/src/session/chat.ts +27 -0
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/tools/schedule-wakeup.ts +66 -17
- package/src/steward/release-day.ts +7 -3
- package/src/steward/triage.ts +37 -4
- package/src/task-agent/harvest-unit.ts +141 -0
- package/src/task-agent/live-moves.ts +98 -12
- package/src/task-agent/parent-host.ts +93 -3
- package/src/task-agent/postland-card.ts +80 -1
- package/src/task-agent/rejudge-on-head.ts +112 -26
- package/src/task-agent/repair-branch-cas.ts +4 -1
- package/src/task-agent/repair-cycle.ts +16 -3
- package/src/task-agent/run-identity.ts +4 -3
- package/src/task-agent/shadow.ts +12 -2
- package/src/task-agent/task-hand.ts +54 -7
- package/src/task-agent/work-order-build.ts +22 -0
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +26 -3
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +223 -38
- package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
- package/src/tool-runtime/truncation-store.ts +4 -0
- package/src/tui-client/dashboard-session.ts +10 -1
- package/src/user-config/coercion.ts +36 -0
- package/src/user-config.ts +18 -41
- package/src/ux-sim/scenario.ts +72 -13
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
- package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
- package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
- package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
- package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
- package/src/cli/g6a-registration-probe.ts +0 -16
- /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
2
3
|
|
|
3
4
|
export const REVIEW_FINDING_KEY_VERSION = 'reviewFindingKey-v1';
|
|
4
5
|
export const MAX_CITED_REVIEW_SYMBOL_CHARS = 256;
|
|
5
6
|
const CITED_REVIEW_SYMBOL_HASH_CHARS = 16;
|
|
7
|
+
const CITED_PATH_EXTENSION = /\.(?:ts|tsx|js|jsx|mjs|cjs|json|md|yaml|yml|sh|py|toml|css|go|sql|rs|rb|java|kt|swift|c|h|cpp|hpp|graphql|proto)$/;
|
|
6
8
|
|
|
7
9
|
export interface CitedReviewSymbol {
|
|
8
10
|
hash: string;
|
|
@@ -18,6 +20,57 @@ export interface ReviewFindingKeyOverlap {
|
|
|
18
20
|
overlapRatio: number | undefined;
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
export type CitedReviewPathStatus = 'present' | 'missing' | 'unreadable';
|
|
24
|
+
|
|
25
|
+
export interface ReviewFindingPathHeadCheck {
|
|
26
|
+
head: string;
|
|
27
|
+
status: 'verified' | 'path-missing' | 'unreadable' | 'no-cited-path';
|
|
28
|
+
paths: Array<{ path: string; status: CitedReviewPathStatus }>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Only file-shaped citations are checked; symbols such as `terminal.id` are not paths. */
|
|
32
|
+
export function citedReviewPaths(finding: string): string[] {
|
|
33
|
+
return [...new Set(fullCitedReviewSymbols(finding)
|
|
34
|
+
.map((symbol) => symbol.replace(/^\.\//, '').replace(/:\d+(?::\d+)?$/, ''))
|
|
35
|
+
.filter((symbol) => !symbol.startsWith('/')
|
|
36
|
+
&& !symbol.includes('\\')
|
|
37
|
+
&& !symbol.includes('://')
|
|
38
|
+
&& /^[A-Za-z0-9_.@+/-]+$/.test(symbol)
|
|
39
|
+
&& !symbol.split('/').some((part) => part === '..' || part === '')
|
|
40
|
+
&& (symbol.includes('/') || CITED_PATH_EXTENSION.test(symbol))))];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Check cited paths against the supplied exact commit, never the worktree's current HEAD. */
|
|
44
|
+
export function checkCitedReviewPathsAtHead(finding: string, repo: string, head: string): ReviewFindingPathHeadCheck {
|
|
45
|
+
const paths = citedReviewPaths(finding);
|
|
46
|
+
if (paths.length === 0) return { head, status: 'no-cited-path', paths: [] };
|
|
47
|
+
if (!/^[0-9a-f]{40}$/i.test(head)) {
|
|
48
|
+
return { head, status: 'unreadable', paths: paths.map((path) => ({ path, status: 'unreadable' })) };
|
|
49
|
+
}
|
|
50
|
+
const commitType = spawnSync('git', ['-C', repo, 'cat-file', '-t', head], { encoding: 'utf8' });
|
|
51
|
+
if (commitType.error || commitType.status !== 0 || commitType.stdout?.trim() !== 'commit') {
|
|
52
|
+
return { head, status: 'unreadable', paths: paths.map((path) => ({ path, status: 'unreadable' })) };
|
|
53
|
+
}
|
|
54
|
+
const checked = paths.map((path): { path: string; status: CitedReviewPathStatus } => {
|
|
55
|
+
const result = spawnSync('git', ['--literal-pathspecs', '-C', repo, 'ls-tree', '-r', '-z', '--full-tree', head, '--', path], {
|
|
56
|
+
encoding: 'utf8', maxBuffer: 1024 * 1024,
|
|
57
|
+
});
|
|
58
|
+
if (result.error || result.status !== 0) return { path, status: 'unreadable' };
|
|
59
|
+
const output = typeof result.stdout === 'string' ? result.stdout : '';
|
|
60
|
+
const present = output.split('\0').some((entry) => {
|
|
61
|
+
const separator = entry.indexOf('\t');
|
|
62
|
+
return separator >= 0 && entry.slice(separator + 1) === path;
|
|
63
|
+
});
|
|
64
|
+
return { path, status: present ? 'present' : 'missing' };
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
head,
|
|
68
|
+
status: checked.some(({ status }) => status === 'unreadable') ? 'unreadable'
|
|
69
|
+
: checked.some(({ status }) => status === 'missing') ? 'path-missing' : 'verified',
|
|
70
|
+
paths: checked,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
21
74
|
interface ReviewFindingKey {
|
|
22
75
|
key: string;
|
|
23
76
|
source: 'symbol' | 'prose';
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
//
|
|
15
15
|
// index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
|
|
16
16
|
|
|
17
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
18
|
-
import { tmpdir } from 'node:os';
|
|
17
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
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';
|
|
@@ -49,6 +49,8 @@ export interface SelfReviewCliOpts {
|
|
|
49
49
|
json?: boolean | undefined;
|
|
50
50
|
/** Save completed reviews under the task-agent state's review-results directory. */
|
|
51
51
|
save?: string | undefined;
|
|
52
|
+
/** One invocation past r5, only for a PR in OP's traffic.json allowlist; the reason is recorded before review starts. */
|
|
53
|
+
overCapReason?: string | undefined;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/** 셸/네트워크/로그 경계 — 테스트는 전부 대역으로 채운다. */
|
|
@@ -101,6 +103,10 @@ export interface SelfReviewCliDeps {
|
|
|
101
103
|
registerSink(surface: string): Promise<void>;
|
|
102
104
|
/** `data` 는 payload 객체 — 순수 헬퍼가 만든 관측 타입도 그대로 받는다(인덱스 시그니처 강요 금지). */
|
|
103
105
|
log(event: string, data: object, opts?: { level?: 'info' | 'warn' | 'error' }): void;
|
|
106
|
+
/** Doctor observation lane, kept separate from the existing self-review event contract. */
|
|
107
|
+
observeDoctorReview?(event: string, data: object, opts?: { level?: 'info' | 'warn' | 'error' }): void;
|
|
108
|
+
/** Optional MK doctor module; absence or failure leaves the original intent intact. */
|
|
109
|
+
loadDoctorReviewBrief?(input: { pr: number; head: string; title: string; body: string; changedFiles: string[] }): Promise<string | null>;
|
|
104
110
|
info(text: string): void;
|
|
105
111
|
error(text: string): void;
|
|
106
112
|
print(text: string): void;
|
|
@@ -120,6 +126,68 @@ export interface SelfReviewCliOutcome {
|
|
|
120
126
|
failed: number;
|
|
121
127
|
}
|
|
122
128
|
|
|
129
|
+
/** Saved results are round evidence only when their PR, exact head and reviewed status agree. */
|
|
130
|
+
export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
|
|
131
|
+
const dir = join(root, 'review-results');
|
|
132
|
+
let names: string[];
|
|
133
|
+
try { names = readdirSync(dir); } catch { return []; }
|
|
134
|
+
// Manual review saves in the operating house also use head10; the JSON's full head is authoritative.
|
|
135
|
+
const matching = new RegExp(`^.+-${pr}-([a-f0-9]{7,40})\\.json$`, 'i');
|
|
136
|
+
const heads = new Set<string>();
|
|
137
|
+
for (const name of names) {
|
|
138
|
+
const match = matching.exec(name);
|
|
139
|
+
if (!match) continue;
|
|
140
|
+
try {
|
|
141
|
+
const raw: unknown = JSON.parse(readFileSync(join(dir, name), 'utf8'));
|
|
142
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
|
|
143
|
+
const result = raw as Record<string, unknown>;
|
|
144
|
+
const head = result.headCommit;
|
|
145
|
+
if (String(result.pr) !== pr || result.reviewed !== true || typeof head !== 'string'
|
|
146
|
+
|| !COMMIT_OID.test(head) || !head.toLowerCase().startsWith(match[1]!.toLowerCase())) continue;
|
|
147
|
+
heads.add(head.toLowerCase());
|
|
148
|
+
} catch { /* corrupt or partial result is not a completed round */ }
|
|
149
|
+
}
|
|
150
|
+
return [...heads];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string | null {
|
|
154
|
+
if (/^#?[1-9]\d*$/.test(input)) return input.replace(/^#/, '');
|
|
155
|
+
try {
|
|
156
|
+
const url = new URL(input);
|
|
157
|
+
if (url.protocol !== 'https:') return null;
|
|
158
|
+
const pr = /^\/[^/]+\/[^/]+\/pull\/([1-9]\d*)\/?$/.exec(url.pathname)?.[1];
|
|
159
|
+
if (!pr) return null;
|
|
160
|
+
// A URL from another repository must not inherit this repository's saved review history.
|
|
161
|
+
const view = deps.gh(['pr', 'view', pr, '--json', 'url'], 15_000);
|
|
162
|
+
if (view.status !== 0) return null;
|
|
163
|
+
const actual = new URL((JSON.parse(view.stdout) as { url?: string }).url ?? '');
|
|
164
|
+
const identity = (value: URL): string => `${value.host.toLowerCase()}${value.pathname.replace(/\/$/, '').toLowerCase()}`;
|
|
165
|
+
return actual.protocol === 'https:' && identity(actual) === identity(url) ? pr : null;
|
|
166
|
+
} catch { return null; }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function claimCapOverride(pr: string, head: string, reason: string, now: number): boolean {
|
|
170
|
+
const dir = join(effectiveInstanceRoot(), 'review-results');
|
|
171
|
+
try {
|
|
172
|
+
mkdirSync(dir, { recursive: true });
|
|
173
|
+
// wx is atomic across concurrent CLI processes; a PR receives one recorded exception.
|
|
174
|
+
writeFileSync(join(dir, `cap-override-${pr}.json`), JSON.stringify({ pr, head, reason, claimedAt: now }) + '\n', { flag: 'wx' });
|
|
175
|
+
return true;
|
|
176
|
+
} catch { return false; }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** OP owns this list. Missing, unreadable, or malformed traffic never grants a review exception. */
|
|
180
|
+
function opAllowsReviewOverCap(pr: string): boolean {
|
|
181
|
+
const path = process.env.ELANOUS_TRAFFIC_SIGNAL ?? join(homedir(), 'elanous-hq', 'seat-state', 'OP', 'traffic.json');
|
|
182
|
+
try {
|
|
183
|
+
const value: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
184
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
185
|
+
const allow = (value as Record<string, unknown>).reviewOverCapAllow;
|
|
186
|
+
return Array.isArray(allow) && allow.every((number) => Number.isSafeInteger(number) && number > 0)
|
|
187
|
+
&& allow.includes(Number(pr));
|
|
188
|
+
} catch { return false; }
|
|
189
|
+
}
|
|
190
|
+
|
|
123
191
|
interface GhResult {
|
|
124
192
|
status: number | null;
|
|
125
193
|
stdout: string;
|
|
@@ -1285,7 +1353,8 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1285
1353
|
// 관측 sink는 모든 종료 경로보다 먼저 등록해 거부도 운영 로그에 남긴다.
|
|
1286
1354
|
await deps.registerSink('self-review');
|
|
1287
1355
|
|
|
1288
|
-
const
|
|
1356
|
+
const normalizedPrArgs = prArgs.map((pr) => normalizeReviewPrArg(pr, deps));
|
|
1357
|
+
const invalidPrArgs = prArgs.filter((_, index) => normalizedPrArgs[index] === null);
|
|
1289
1358
|
if (invalidPrArgs.length > 0) {
|
|
1290
1359
|
const safeInvalidPrArgs = invalidPrArgs.map((pr) => JSON.stringify(safeLogText(pr)));
|
|
1291
1360
|
deps.log('invalid-pr-args', {
|
|
@@ -1293,7 +1362,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1293
1362
|
invalidPrArgsCount: invalidPrArgs.length,
|
|
1294
1363
|
invalidPrArgs: safeInvalidPrArgs,
|
|
1295
1364
|
}, { level: 'warn' });
|
|
1296
|
-
deps.error(`PR 인자가 올바르지 않습니다: ${safeInvalidPrArgs.join(', ')}. PR
|
|
1365
|
+
deps.error(`PR 인자가 올바르지 않습니다: ${safeInvalidPrArgs.join(', ')}. PR 번호·#번호·URL을 입력하세요 (예: elanous self review 5502).`);
|
|
1297
1366
|
return { results: [], failed: 0 };
|
|
1298
1367
|
}
|
|
1299
1368
|
|
|
@@ -1390,8 +1459,42 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1390
1459
|
let failed = 0;
|
|
1391
1460
|
const providedReviewerContext = loadReviewerContext(opts, deps.readReferencedFile);
|
|
1392
1461
|
const hasProvidedReviewerContext = (opts.contextOrder?.length ?? 0) > 0 || (opts.context?.length ?? 0) > 0 || (opts.contextText?.length ?? 0) > 0;
|
|
1393
|
-
for (const pr of
|
|
1462
|
+
for (const pr of normalizedPrArgs as string[]) {
|
|
1463
|
+
const previousHeads = savedReviewHeads(pr);
|
|
1464
|
+
const previousRoundCount = previousHeads.length;
|
|
1465
|
+
const reason = opts.overCapReason?.trim();
|
|
1466
|
+
deps.observeDoctorReview?.('round-counted', { pr, previousRoundCount, round: previousRoundCount + 1 });
|
|
1467
|
+
const opAllowed = previousRoundCount >= 5 && opAllowsReviewOverCap(pr);
|
|
1468
|
+
if (previousRoundCount >= 5) {
|
|
1469
|
+
deps.observeDoctorReview?.('cap-attempt', { pr, previousRoundCount, round: previousRoundCount + 1, reasonProvided: Boolean(reason), opAllowed }, { level: 'warn' });
|
|
1470
|
+
}
|
|
1471
|
+
if (previousRoundCount >= 5 && (!reason || !opAllowed)) {
|
|
1472
|
+
const refusalHead = prHeadCommit(pr, deps).value;
|
|
1473
|
+
const message = !opAllowed
|
|
1474
|
+
? `PR ${pr}: r5 상한 초과 리뷰는 OP traffic.json reviewOverCapAllow 허용 목록에 있어야 합니다.`
|
|
1475
|
+
: `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. 새 리뷰는 --over-cap-reason <사유>로 PR당 한 번만 허용됩니다.`;
|
|
1476
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: refusalHead, previousRoundCount, round: previousRoundCount + 1, reason: opAllowed ? 'missing-reason' : 'not-op-allowlisted' }, { level: 'warn' });
|
|
1477
|
+
deps.error(message);
|
|
1478
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: refusalHead });
|
|
1479
|
+
failed += 1;
|
|
1480
|
+
continue;
|
|
1481
|
+
}
|
|
1394
1482
|
const diffRead = readDiffAtHead(pr, deps);
|
|
1483
|
+
if (previousRoundCount >= 5 && reason) {
|
|
1484
|
+
// Claim only the exact SHA-pinned diff that the reviewer will see; never spend the sole
|
|
1485
|
+
// exception on a separately read head that may move before readDiffAtHead.
|
|
1486
|
+
const claimable = diffRead.source === 'sha-pinned' && diffRead.headCommitState === 'known'
|
|
1487
|
+
&& diffRead.currentHeadCommitState === 'known' && !diffRead.stale && diffRead.diff.status === 0;
|
|
1488
|
+
if (!claimable || !claimCapOverride(pr, diffRead.headCommit, reason, deps.now())) {
|
|
1489
|
+
const message = `PR ${pr}: r5 상한 예외를 청구하지 못했습니다(정확 head 고정 실패 또는 이미 사용).`;
|
|
1490
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: claimable ? 'already-claimed' : 'head-unpinnable' }, { level: 'warn' });
|
|
1491
|
+
deps.error(message);
|
|
1492
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1493
|
+
failed += 1;
|
|
1494
|
+
continue;
|
|
1495
|
+
}
|
|
1496
|
+
deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason }, { level: 'warn' });
|
|
1497
|
+
}
|
|
1395
1498
|
const localHeadComparison = compareLocalHead(pr, { value: diffRead.headCommit, state: diffRead.headCommitState }, deps);
|
|
1396
1499
|
const { diff } = diffRead;
|
|
1397
1500
|
const baseReviewerContext = hasProvidedReviewerContext
|
|
@@ -1434,6 +1537,24 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1434
1537
|
intentSource = body?.trim() ? 'pr-body' : title.trim() ? 'pr-title' : 'fallback';
|
|
1435
1538
|
if (!intent) intent = `PR ${pr}`;
|
|
1436
1539
|
}
|
|
1540
|
+
if (previousRoundCount >= 2 && diff.status === 0 && !diffRead.stale && diffRead.headCommitState === 'known') {
|
|
1541
|
+
if (!deps.loadDoctorReviewBrief) {
|
|
1542
|
+
deps.observeDoctorReview?.('brief-unavailable', { pr, head: diffRead.headCommit, previousRoundCount, reason: 'module-not-wired' });
|
|
1543
|
+
} else {
|
|
1544
|
+
try {
|
|
1545
|
+
const block = await deps.loadDoctorReviewBrief({ pr: Number(pr), head: diffRead.headCommit, title, body: body ?? '', changedFiles: diffFilePaths(diff.stdout) });
|
|
1546
|
+
if (block?.trim()) {
|
|
1547
|
+
intent += `\n\n${block.trim()}`;
|
|
1548
|
+
intentTruncation = { ...intentTruncation, ...reviewIntentTruncationObservation(intent) };
|
|
1549
|
+
deps.observeDoctorReview?.('brief-injected', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, briefChars: block.length });
|
|
1550
|
+
} else {
|
|
1551
|
+
deps.observeDoctorReview?.('brief-unavailable', { pr, head: diffRead.headCommit, previousRoundCount, reason: 'no-ready-brief' });
|
|
1552
|
+
}
|
|
1553
|
+
} catch (error) {
|
|
1554
|
+
deps.observeDoctorReview?.('brief-unavailable', { pr, head: diffRead.headCommit, previousRoundCount, reason: safeLogText(String(error), 200) }, { level: 'warn' });
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1437
1558
|
const startObservation = (extra: Record<string, unknown> = {}) => deps.log('start', {
|
|
1438
1559
|
pr: safeLogText(pr), model: safeLogText(primaryModel),
|
|
1439
1560
|
...reviewerSourceObservation(),
|
|
@@ -161,8 +161,8 @@ function pendingQuestionAnswerPath(id: string, root?: string): string {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function writeAtomicRecord(id: string, value: unknown, dir: string, target: string, deps: PendingQuestionStoreDeps): void {
|
|
164
|
-
const temp = join(dir, `.${encodeURIComponent(id)}.${process.pid}.${(deps.now ?? (() => new Date()))().getTime()}.${Math.random().toString(36).slice(2)}.tmp`);
|
|
165
164
|
assertNotTestWritingOps(target, 'write a pending question record');
|
|
165
|
+
const temp = join(dir, `.${encodeURIComponent(id)}.${process.pid}.${(deps.now ?? (() => new Date()))().getTime()}.${Math.random().toString(36).slice(2)}.tmp`);
|
|
166
166
|
const remove = deps.removeFile ?? rmSync;
|
|
167
167
|
try {
|
|
168
168
|
(deps.makeDir ?? mkdirSync)(dir, { recursive: true });
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// 구현을 교체(누적 아님). 기존 PR 없으면 새로 생성.
|
|
10
10
|
|
|
11
11
|
import { spawnSync } from 'node:child_process';
|
|
12
|
+
import { randomUUID } from 'node:crypto';
|
|
12
13
|
import { githubAutomationToken } from '../auth/github-app-token.js';
|
|
13
14
|
import { debug } from '../debug/log.js';
|
|
14
15
|
import { POD_GITHUB_CREDENTIAL_TOKEN_ENV, POD_GITHUB_CREDENTIAL_URL_ENV } from '../nexus/api/pod-credential-api.js';
|
|
@@ -17,7 +18,8 @@ import { DEFAULT_BRANCH_WORKTREE_BASE } from '../git-fs/worktree.js';
|
|
|
17
18
|
import { isElanousRuntimeArtifactPath } from '../self-implement/gate-scope.js';
|
|
18
19
|
import { isTransientExecutionFailure } from '../self-dev/execution-transient.js';
|
|
19
20
|
import { withGhRestFallback } from './gh-rest-fallback.js';
|
|
20
|
-
import { cellIdFromBody, guardNewPr, parseDiffHunks, readOpenPrs, recordGuardUnmeasured, type GuardVerdict, type HunkOverlapMode, type Seat } from '../pr-tool/census.js';
|
|
21
|
+
import { cardIdFromBody, cellIdFromBody, guardNewPr, hasCardMarker, parseDiffHunks, readOpenPrs, recordGuardUnmeasured, type GuardVerdict, type HunkOverlapMode, type Seat } from '../pr-tool/census.js';
|
|
22
|
+
import { labelsForAxis, PR_LABEL_NAMES } from '../github/pr-labels.js';
|
|
21
23
|
import { getUserConfig } from '../user-config.js';
|
|
22
24
|
|
|
23
25
|
/** ★ stderr 캡처(대표 2026-07-21·관측 갭) — 종전엔 stdout 만 담아 git/gh 실패 사유가 소실됐다
|
|
@@ -118,7 +120,8 @@ export interface UpsertPrResult { url: string; reused: boolean }
|
|
|
118
120
|
* 특히 `noop`(nothing to commit)은 **실패가 아니라 이미 반영된 no-op** — 호출부가 정직 PASS 처리.
|
|
119
121
|
* 나머지 reason(add/commit/push/gh)은 진짜 실패로 detail(stderr)과 함께 관측·pr-failed. */
|
|
120
122
|
export type UpsertPrOutcome =
|
|
121
|
-
| { ok: true; url: string; reused: boolean; labelsApplied?: boolean; labelsOmitted?: boolean
|
|
123
|
+
| { ok: true; url: string; reused: boolean; labelsApplied?: boolean; labelsOmitted?: boolean;
|
|
124
|
+
supersededPr?: number }
|
|
122
125
|
| { ok: false; reason: 'add' | 'commit' | 'base' | 'noop' | 'push' | 'gh' | 'guard'; detail: string };
|
|
123
126
|
|
|
124
127
|
/** 관측된 문면 두 가지:
|
|
@@ -334,7 +337,151 @@ function defaultPrCreateGuard(input: { cwd: string; base: string | undefined; se
|
|
|
334
337
|
const files = diff.ok ? diff.out.split('\0').filter(Boolean) : null;
|
|
335
338
|
const patch = run('git', ['-C', input.cwd, 'diff', '--unified=0', `${input.base}...HEAD`]);
|
|
336
339
|
if (!patch.ok) return guardNewPr({ files: null, seat: input.seat }, { status: 'unknown', reason: `후보 수정 줄 조회 실패: ${patch.err || patch.out}` });
|
|
337
|
-
|
|
340
|
+
const boundRaw = process.env.ELANOUS_TASK_BOUND_PR;
|
|
341
|
+
const boundPrNumber = boundRaw && /^[1-9]\d*$/.test(boundRaw) ? Number(boundRaw) : undefined;
|
|
342
|
+
return guardNewPr({ files, seat: input.seat, cellId: cellIdFromBody(input.body), cardId: cardIdFromBody(input.body),
|
|
343
|
+
...(boundPrNumber && Number.isSafeInteger(boundPrNumber) ? { boundPrNumber } : {}),
|
|
344
|
+
hunks: parseDiffHunks(patch.out), hunkOverlap: configuredHunkOverlapMode() }, readOpenPrs(run, { cwd: input.cwd, ...(files ? { candidateFiles: files } : {}) }));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function editExistingPr(run: CmdRunner, input: UpsertPrInput, url: string): UpsertPrOutcome {
|
|
348
|
+
const opts = { cwd: input.worktreePath };
|
|
349
|
+
const detailOf = (r: CmdResult) => (r.err || r.out || '').slice(0, 300);
|
|
350
|
+
const editArgs = ['pr', 'edit', url, '--title', input.title, '--body', input.body];
|
|
351
|
+
const explicitBase = input.base?.trim();
|
|
352
|
+
if (explicitBase && !isBranchSelfRef(explicitBase, input.branch)) editArgs.push('--base', prBaseFromComparison(explicitBase));
|
|
353
|
+
for (const label of new Set((input.labels ?? []).map(label => label.trim()).filter(Boolean))) editArgs.push('--add-label', label);
|
|
354
|
+
const edited = run('gh', editArgs, opts);
|
|
355
|
+
if (!edited.ok) return { ok: false, reason: 'gh', detail: detailOf(edited) || 'gh pr edit 실패' };
|
|
356
|
+
if (input.draft !== undefined) {
|
|
357
|
+
const stateR = run('gh', ['pr', 'view', url, '--json', 'isDraft', '-q', '.isDraft'], opts);
|
|
358
|
+
const raw = stateR.out.trim();
|
|
359
|
+
if (!stateR.ok || (raw !== 'true' && raw !== 'false'))
|
|
360
|
+
return { ok: false, reason: 'gh', detail: detailOf(stateR) || `draft 상태 조회 실패(isDraft=${raw || 'empty'})` };
|
|
361
|
+
if (input.draft === false && raw === 'true') {
|
|
362
|
+
const ready = run('gh', ['pr', 'ready', url], opts);
|
|
363
|
+
if (!ready.ok) return { ok: false, reason: 'gh', detail: detailOf(ready) || 'gh pr ready 실패' };
|
|
364
|
+
} else if (input.draft === true && raw === 'false') {
|
|
365
|
+
const undo = run('gh', ['pr', 'ready', url, '--undo'], opts);
|
|
366
|
+
if (!undo.ok) return { ok: false, reason: 'gh', detail: detailOf(undo) || 'gh pr ready --undo 실패' };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (input.reuseComment) run('gh', ['pr', 'comment', url, '--body', input.reuseComment], opts);
|
|
370
|
+
return { ok: true, url, reused: true };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** Same-card rework may have a new run branch. Merge the bound PR head into that work,
|
|
374
|
+
* then update the bound branch with a plain fast-forward push. Every identity read is
|
|
375
|
+
* checked again after the inventory snapshot; an ambiguous or moved PR stays refused. */
|
|
376
|
+
function reuseSameCellPr(run: CmdRunner, input: UpsertPrInput, target: NonNullable<GuardVerdict['sameCellReuse']>, recheck: () => GuardVerdict): UpsertPrOutcome {
|
|
377
|
+
const cwd = input.worktreePath;
|
|
378
|
+
const fail = (detail: string): UpsertPrOutcome => ({ ok: false, reason: 'guard', detail: `same-cell reuse: ${detail}` });
|
|
379
|
+
if (!/^[0-9a-f]{40}$/i.test(target.headSha) || !Number.isSafeInteger(target.number) || target.number < 1
|
|
380
|
+
|| cellIdFromBody(input.body) !== target.cellId || cardIdFromBody(input.body) !== target.cardId)
|
|
381
|
+
return fail('candidate identity mismatch');
|
|
382
|
+
const validBranch = run('git', ['-C', cwd, 'check-ref-format', '--branch', target.branch]);
|
|
383
|
+
if (!validBranch.ok) return fail('PR branch name invalid');
|
|
384
|
+
const viewFields = 'state,headRefOid,headRefName,body,isCrossRepository,url,isDraft,labels';
|
|
385
|
+
const view = run('gh', ['pr', 'view', String(target.number), '--json', viewFields], { cwd });
|
|
386
|
+
if (!view.ok) return fail('PR identity read failed');
|
|
387
|
+
let pr: Record<string, unknown>;
|
|
388
|
+
try { pr = JSON.parse(view.out) as Record<string, unknown>; } catch { return fail('PR identity malformed'); }
|
|
389
|
+
if (pr.state !== 'OPEN' || pr.isCrossRepository !== false || pr.headRefOid !== target.headSha
|
|
390
|
+
|| pr.headRefName !== target.branch || typeof pr.body !== 'string'
|
|
391
|
+
|| cellIdFromBody(pr.body) !== target.cellId
|
|
392
|
+
|| (target.legacyBound ? hasCardMarker(pr.body) || process.env.ELANOUS_TASK_BOUND_PR !== String(target.number)
|
|
393
|
+
: cardIdFromBody(pr.body) !== target.cardId)
|
|
394
|
+
|| typeof pr.url !== 'string' || extractPrNumber(pr.url) !== target.number)
|
|
395
|
+
return fail('PR state, head, repository, or card lineage changed');
|
|
396
|
+
const remoteRef = `refs/heads/${target.branch}`;
|
|
397
|
+
const remote = run('git', ['-C', cwd, 'ls-remote', '--exit-code', 'origin', remoteRef]);
|
|
398
|
+
if (!remote.ok || remote.out.trim() !== `${target.headSha}\t${remoteRef}`) return fail('remote head changed');
|
|
399
|
+
const localRef = `refs/elanous/pr-reuse/${target.number}-${target.headSha.slice(0, 12)}`;
|
|
400
|
+
const fetched = run('git', ['-C', cwd, 'fetch', 'origin', `${remoteRef}:${localRef}`]);
|
|
401
|
+
const fetchedHead = fetched.ok ? run('git', ['-C', cwd, 'rev-parse', localRef]) : undefined;
|
|
402
|
+
if (!fetched.ok || !fetchedHead?.ok || fetchedHead.out.trim() !== target.headSha) return fail('PR head fetch mismatch');
|
|
403
|
+
const merged = run('git', ['-C', cwd, 'merge', '--no-edit', target.headSha]);
|
|
404
|
+
if (!merged.ok) {
|
|
405
|
+
const aborted = run('git', ['-C', cwd, 'merge', '--abort']);
|
|
406
|
+
if (!aborted.ok) return fail(`PR head merge abort failed: ${(aborted.err || aborted.out).slice(0, 220)}`);
|
|
407
|
+
// A conflicting same-card draft cannot be fast-forwarded. Preserve this run's
|
|
408
|
+
// head on its own branch, and let the returned new PR URL bind the card.
|
|
409
|
+
if (pr.isDraft !== true) return fail('conflicting PR is not a draft');
|
|
410
|
+
const clean = run('git', ['-C', cwd, 'status', '--porcelain', '--untracked-files=no']);
|
|
411
|
+
if (!clean.ok || clean.out.trim()) return fail('worktree changed after merge abort');
|
|
412
|
+
const before = run('gh', ['pr', 'view', String(target.number), '--json', viewFields], { cwd });
|
|
413
|
+
let old: Record<string, unknown>;
|
|
414
|
+
try { old = JSON.parse(before.out) as Record<string, unknown>; } catch { return fail('PR pre-create identity malformed'); }
|
|
415
|
+
const remoteNow = run('git', ['-C', cwd, 'ls-remote', '--exit-code', 'origin', remoteRef]);
|
|
416
|
+
const latest = recheck().sameCellReuse;
|
|
417
|
+
if (!before.ok || old.state !== 'OPEN' || old.isDraft !== true || old.headRefOid !== target.headSha
|
|
418
|
+
|| old.headRefName !== target.branch || old.body !== pr.body || old.url !== pr.url
|
|
419
|
+
|| !remoteNow.ok || remoteNow.out.trim() !== `${target.headSha}\t${remoteRef}`
|
|
420
|
+
|| !latest || latest.number !== target.number || latest.branch !== target.branch
|
|
421
|
+
|| latest.headSha !== target.headSha || latest.cellId !== target.cellId
|
|
422
|
+
|| latest.cardId !== target.cardId || Boolean(latest.legacyBound) !== Boolean(target.legacyBound))
|
|
423
|
+
return fail('PR changed before superseding draft');
|
|
424
|
+
const newRef = `refs/heads/${input.branch}`;
|
|
425
|
+
if (!run('git', ['-C', cwd, 'check-ref-format', '--branch', input.branch]).ok) return fail('new run branch name invalid');
|
|
426
|
+
const newRemote = run('git', ['-C', cwd, 'ls-remote', '--heads', 'origin', newRef]);
|
|
427
|
+
if (!newRemote.ok || newRemote.out.trim()) return fail('new run branch already exists or remote unreadable');
|
|
428
|
+
const localHead = run('git', ['-C', cwd, 'rev-parse', 'HEAD']);
|
|
429
|
+
if (!localHead.ok || !/^[0-9a-f]{40}$/i.test(localHead.out.trim())) return fail('new run head unreadable');
|
|
430
|
+
// Upload the commit through a unique scratch ref. GitHub's create-ref API then
|
|
431
|
+
// atomically refuses a concurrent writer of the intended branch name.
|
|
432
|
+
const scratch = `elanous-pr-create/${randomUUID()}`;
|
|
433
|
+
const scratchRef = `refs/heads/${scratch}`;
|
|
434
|
+
const uploaded = run('git', ['-C', cwd, 'push', 'origin', `HEAD:${scratchRef}`]);
|
|
435
|
+
if (!uploaded.ok) return fail(`new run object upload failed: ${(uploaded.err || uploaded.out).slice(0, 220)}`);
|
|
436
|
+
const repository = run('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], { cwd });
|
|
437
|
+
const repoName = repository.out.trim();
|
|
438
|
+
const createdRef = repository.ok && /^[^/\s]+\/[^/\s]+$/.test(repoName)
|
|
439
|
+
? run('gh', ['api', '--method', 'POST', `repos/${repoName}/git/refs`, '-f', `ref=${newRef}`, '-f', `sha=${localHead.out.trim()}`], { cwd })
|
|
440
|
+
: { ok: false, out: '', err: 'repository identity unavailable' };
|
|
441
|
+
const removedScratch = run('git', ['-C', cwd, 'push', 'origin', `:${scratchRef}`]);
|
|
442
|
+
if (!removedScratch.ok) debug.log('autopilot.pr-manager', 'same-cell-scratch-cleanup-failed',
|
|
443
|
+
{ scratchRef, detail: removedScratch.err || removedScratch.out,
|
|
444
|
+
stderr: removedScratch.err ?? '', stdout: removedScratch.out, truncated: false }, { level: 'warn' });
|
|
445
|
+
if (!createdRef.ok) return fail(`new run branch create refused: ${(createdRef.err || createdRef.out).slice(0, 220)}`);
|
|
446
|
+
const stateLabels = new Set(labelsForAxis('state').map(label => label.name));
|
|
447
|
+
const labels = [...new Set([...(input.labels ?? []).filter(label => !stateLabels.has(label as typeof PR_LABEL_NAMES.running)),
|
|
448
|
+
PR_LABEL_NAMES.running, ...(input.seat ? [`seat:${input.seat}`] : [])])];
|
|
449
|
+
const body = `${input.body.trimEnd()}\n\nSupersedes: #${target.number}`;
|
|
450
|
+
const create = ['pr', 'create', '--draft', '--head', input.branch, '--title', input.title, '--body', body];
|
|
451
|
+
const base = input.base?.trim();
|
|
452
|
+
if (base && !isBranchSelfRef(base, input.branch)) create.push('--base', prBaseFromComparison(base));
|
|
453
|
+
for (const label of labels) create.push('--label', label);
|
|
454
|
+
const created = run('gh', create, { cwd });
|
|
455
|
+
const newUrl = created.out.trim();
|
|
456
|
+
const newNumber = extractPrNumber(newUrl);
|
|
457
|
+
if (!created.ok || !newNumber) return { ok: false, reason: 'gh', detail: `superseding draft create failed: ${(created.err || created.out).slice(0, 220)}` };
|
|
458
|
+
debug.log('autopilot.pr-manager', 'same-cell-conflict-new-draft',
|
|
459
|
+
{ oldPr: target.number, newPr: newNumber, cardId: target.cardId, oldDraftCleanup: 'deferred' });
|
|
460
|
+
return { ok: true, url: newUrl, reused: false, supersededPr: target.number };
|
|
461
|
+
}
|
|
462
|
+
if (!run('git', ['-C', cwd, 'merge-base', '--is-ancestor', target.headSha, 'HEAD']).ok) return fail('PR head is not ancestor of result');
|
|
463
|
+
const finalView = run('gh', ['pr', 'view', String(target.number), '--json', viewFields], { cwd });
|
|
464
|
+
let finalPr: Record<string, unknown>;
|
|
465
|
+
try { finalPr = JSON.parse(finalView.out) as Record<string, unknown>; } catch { return fail('PR pre-push identity read failed'); }
|
|
466
|
+
if (!finalView.ok || finalPr.state !== 'OPEN' || finalPr.isCrossRepository !== false
|
|
467
|
+
|| finalPr.headRefOid !== target.headSha || finalPr.headRefName !== target.branch
|
|
468
|
+
|| typeof finalPr.body !== 'string' || cellIdFromBody(finalPr.body) !== target.cellId
|
|
469
|
+
|| (target.legacyBound ? hasCardMarker(finalPr.body) || process.env.ELANOUS_TASK_BOUND_PR !== String(target.number)
|
|
470
|
+
: cardIdFromBody(finalPr.body) !== target.cardId)
|
|
471
|
+
|| finalPr.url !== pr.url) return fail('PR changed before push');
|
|
472
|
+
const finalRemote = run('git', ['-C', cwd, 'ls-remote', '--exit-code', 'origin', remoteRef]);
|
|
473
|
+
if (!finalRemote.ok || finalRemote.out.trim() !== `${target.headSha}\t${remoteRef}`) return fail('remote head changed before push');
|
|
474
|
+
const latest = recheck().sameCellReuse;
|
|
475
|
+
if (!latest || latest.number !== target.number || latest.branch !== target.branch
|
|
476
|
+
|| latest.headSha !== target.headSha || latest.cellId !== target.cellId
|
|
477
|
+
|| latest.cardId !== target.cardId || Boolean(latest.legacyBound) !== Boolean(target.legacyBound))
|
|
478
|
+
return fail('OPEN PR inventory changed before push');
|
|
479
|
+
// The result descends from the exact fetched head. The explicit lease binds the
|
|
480
|
+
// remote update to that head, so a delete or move between reads cannot be revived.
|
|
481
|
+
const pushed = run('git', ['-C', cwd, 'push', `--force-with-lease=${remoteRef}:${target.headSha}`, 'origin', `HEAD:${remoteRef}`]);
|
|
482
|
+
if (!pushed.ok) return fail(`fast-forward push refused: ${(pushed.err || pushed.out).slice(0, 220)}`);
|
|
483
|
+
debug.log('autopilot.pr-manager', 'same-cell-reused', { pr: target.number, cellId: target.cellId, cardId: target.cardId, branch: target.branch });
|
|
484
|
+
return editExistingPr(run, input, pr.url);
|
|
338
485
|
}
|
|
339
486
|
|
|
340
487
|
/** ★ PR 매니저 팩토리(대표 2026-07-12) — CmdRunner 주입(테스트 스텁). 실 배선은 기본 러너. */
|
|
@@ -496,11 +643,37 @@ export function makePrManager(
|
|
|
496
643
|
}
|
|
497
644
|
// ahead > 0 + 내용차 존재 → 이미 커밋된 산출. commit 스킵하고 아래 push + PR 로 fall-through.
|
|
498
645
|
}
|
|
646
|
+
// 카드 계보를 아는 재작업은 새 run 가지를 발사하기 전에 같은 칸 PR 을 찾는다.
|
|
647
|
+
// 같은 카드로 증명된 단일 PR 만 기존 가지를 빠른 전진시킨다. 다른 계보·모호한 목록은 종전 가드다.
|
|
648
|
+
const candidateCardId = cardIdFromBody(input.body);
|
|
649
|
+
if (hasCardMarker(input.body) && !candidateCardId)
|
|
650
|
+
return { ok: false, reason: 'guard', detail: 'candidate card lineage is ambiguous' };
|
|
651
|
+
const earlyGuard = candidateCardId && checkCreate
|
|
652
|
+
? checkCreate({ cwd, base: comparisonBase, seat: input.seat ?? seatFromEnvironment(), body: input.body }, run)
|
|
653
|
+
: undefined;
|
|
654
|
+
const freshGuard = () => checkCreate!({ cwd, base: comparisonBase, seat: input.seat ?? seatFromEnvironment(), body: input.body }, run);
|
|
655
|
+
if (earlyGuard?.sameCellReuse) return reuseSameCellPr(run, input, earlyGuard.sameCellReuse, freshGuard);
|
|
656
|
+
if (earlyGuard?.status === 'refuse') return { ok: false, reason: 'guard', detail: earlyGuard.reasons.map(reason => `${reason.code}: ${reason.detail}`).join('; ') };
|
|
657
|
+
const earlyInventoryUnknown = !!candidateCardId && (!checkCreate || (earlyGuard?.status === 'unknown'
|
|
658
|
+
&& earlyGuard.reasons.length === 1 && earlyGuard.reasons[0]?.code === 'inventory-unknown'));
|
|
659
|
+
if (candidateCardId && earlyGuard?.status !== 'allow' && !earlyInventoryUnknown)
|
|
660
|
+
return { ok: false, reason: 'guard', detail: 'candidate card inventory unmeasured before push' };
|
|
661
|
+
if (earlyInventoryUnknown) debug.log('pr-tool.open-guard', 'candidate-inventory-unmeasured', {
|
|
662
|
+
branch: input.branch, cardId: candidateCardId, stage: 'before-push',
|
|
663
|
+
reason: earlyGuard?.reasons[0]?.detail ?? 'create guard unavailable',
|
|
664
|
+
});
|
|
665
|
+
if (candidateCardId) {
|
|
666
|
+
const branchPr = findPrForBranchOutcome(input.branch, cwd);
|
|
667
|
+
if (branchPr.status === 'FAILED' || branchPr.url)
|
|
668
|
+
return { ok: false, reason: 'guard', detail: 'candidate run branch PR already exists or is unmeasured before push' };
|
|
669
|
+
}
|
|
499
670
|
// force-push — 재구현이 이전 구현을 교체(기존 브랜치 갱신 or 신규). 안정 브랜치명이라 기존 PR 이
|
|
500
671
|
// 있으면 GitHub 이 그 PR 을 자동 업데이트(닫고 새로 안 만듦). elanous 자체 SE 브랜치라 force 안전.
|
|
501
672
|
// 일시 원격 실패(5xx·연결 끊김 등)만 최대 3회. 영구 거부는 한 번에 끝낸다.
|
|
502
673
|
const waitForPushRetry = input.waitForPushRetry ?? defaultWaitForPushRetry;
|
|
503
|
-
const pushArgs =
|
|
674
|
+
const pushArgs = candidateCardId
|
|
675
|
+
? ['-C', cwd, 'push', '-u', 'origin', input.branch]
|
|
676
|
+
: ['-C', cwd, 'push', '--force', '-u', 'origin', input.branch];
|
|
504
677
|
let pushR = runGitWrite(pushArgs);
|
|
505
678
|
let pushAttempts = 1;
|
|
506
679
|
while (!pushR.ok && pushAttempts < MAX_PUSH_ATTEMPTS && isTransientPushFailure(detailOf(pushR))) {
|
|
@@ -516,47 +689,20 @@ export function makePrManager(
|
|
|
516
689
|
}
|
|
517
690
|
const existing = findPrForBranchOutcome(input.branch, cwd);
|
|
518
691
|
if (existing.url) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
// - draft: 현재 상태를 조회해 실제 전이가 필요할 때만 수행(멱등) — 이미 요청 상태면 no-op.
|
|
523
|
-
// draft=false && 현재 draft → gh pr ready · draft=true && 현재 ready → gh pr ready --undo.
|
|
524
|
-
const editArgs = ['pr', 'edit', existing.url, '--title', input.title, '--body', input.body];
|
|
525
|
-
// ⚠️ 재사용 경로는 **명시 base 만** 넘긴다(리뷰 must-fix 2026-07-26). 추론한 base 를 넘기면
|
|
526
|
-
// `release/*` 등 비기본 브랜치를 대상으로 열려 있던 기존 PR 을 **main 으로 재타기팅**하는
|
|
527
|
-
// 회귀가 된다(요청자는 base 를 지정하지도 않았는데). 미지정 = "base 는 건드리지 마라".
|
|
528
|
-
// 신규 생성은 base 가 반드시 필요하므로 그쪽만 추론값을 쓴다.
|
|
529
|
-
// 트림은 신규 경로(resolveDeliverableBase)와 동일하게 — 공백 전용 base 는 미지정으로 본다(리뷰 should-fix).
|
|
530
|
-
const explicitBase = input.base?.trim();
|
|
531
|
-
if (explicitBase && !isBranchSelfRef(explicitBase, input.branch)) editArgs.push('--base', prBaseFromComparison(explicitBase));
|
|
532
|
-
for (const label of new Set((input.labels ?? []).map(label => label.trim()).filter(Boolean))) editArgs.push('--add-label', label);
|
|
533
|
-
let edited = run('gh', editArgs, opts);
|
|
534
|
-
if (!edited.ok) return { ok: false, reason: 'gh', detail: detailOf(edited) || 'gh pr edit 실패' };
|
|
535
|
-
if (input.draft !== undefined) {
|
|
536
|
-
// 현재 draft 상태 조회 — 조회 실패/비정상 출력은 fail-closed(요청 draft 를 적용 못했는데
|
|
537
|
-
// 성공 반환하면 openPr 계약 위반). 정상 조회 시에만 실제 전이가 필요할 때 수행(멱등).
|
|
538
|
-
const stateR = run('gh', ['pr', 'view', existing.url, '--json', 'isDraft', '-q', '.isDraft'], opts);
|
|
539
|
-
const raw = stateR.out.trim();
|
|
540
|
-
if (!stateR.ok || (raw !== 'true' && raw !== 'false')) {
|
|
541
|
-
return { ok: false, reason: 'gh', detail: detailOf(stateR) || `draft 상태 조회 실패(isDraft=${raw || 'empty'})` };
|
|
542
|
-
}
|
|
543
|
-
const isDraft = raw === 'true';
|
|
544
|
-
if (input.draft === false && isDraft) {
|
|
545
|
-
const ready = run('gh', ['pr', 'ready', existing.url], opts);
|
|
546
|
-
if (!ready.ok) return { ok: false, reason: 'gh', detail: detailOf(ready) || 'gh pr ready 실패' };
|
|
547
|
-
} else if (input.draft === true && !isDraft) {
|
|
548
|
-
const undo = run('gh', ['pr', 'ready', existing.url, '--undo'], opts);
|
|
549
|
-
if (!undo.ok) return { ok: false, reason: 'gh', detail: detailOf(undo) || 'gh pr ready --undo 실패' };
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
if (input.reuseComment) run('gh', ['pr', 'comment', existing.url, '--body', input.reuseComment], opts);
|
|
553
|
-
return { ok: true, url: existing.url, reused: true };
|
|
692
|
+
if (candidateCardId)
|
|
693
|
+
return { ok: false, reason: 'guard', detail: 'candidate run branch PR appeared after push; refuse edit' };
|
|
694
|
+
return editExistingPr(run, input, existing.url);
|
|
554
695
|
}
|
|
555
|
-
|
|
696
|
+
if (existing.status === 'FAILED') return { ok: false, reason: 'gh', detail: 'existing PR branch lookup failed' };
|
|
697
|
+
let guardUnmeasured = earlyInventoryUnknown;
|
|
556
698
|
let hunkOverlapWarning: { prs: readonly number[]; files: readonly string[] } | null = null;
|
|
557
699
|
if (checkCreate) {
|
|
558
700
|
const seat = input.seat ?? seatFromEnvironment();
|
|
701
|
+
// Another run may open a PR after the early inventory and before this create.
|
|
702
|
+
// Read the complete OPEN inventory again after push, immediately before create.
|
|
559
703
|
const verdict = checkCreate({ cwd, base: comparisonBase, seat, body: input.body }, run);
|
|
704
|
+
if (verdict.sameCellReuse)
|
|
705
|
+
return { ok: false, reason: 'guard', detail: 'same-cell PR appeared after run branch push; retry from fresh inventory' };
|
|
560
706
|
const hunkWarn = verdict.status === 'allow' ? verdict.warnings.find(warning => warning.code === 'hunk-overlap') : undefined;
|
|
561
707
|
if (hunkWarn) hunkOverlapWarning = { prs: hunkWarn.prs ?? [], files: hunkWarn.files ?? [] };
|
|
562
708
|
if (verdict.status === 'unknown' && verdict.reasons.length === 1 && verdict.reasons[0]?.code === 'inventory-unknown') {
|
|
@@ -569,9 +715,9 @@ export function makePrManager(
|
|
|
569
715
|
} else {
|
|
570
716
|
const count = recordUnmeasured({ seat, reason: verdict.reasons[0].detail });
|
|
571
717
|
if (count.blocked) {
|
|
572
|
-
const alert = run('eln', ['msg', 'post', '--from', seat ?? 'HARNESS', '--to', 'OP', '--kind', 'alert', '--body', `PR open-guard 판정 불가 1시간 ${count.count}회 · 새 PR 차단 · ${count.reason ?? verdict.reasons[0].detail}`]);
|
|
718
|
+
const alert = run('eln', ['msg', 'post', '--from', seat ?? 'HARNESS', '--to', 'OP', '--kind', 'alert', '--body', `PR open-guard 판정 불가 1시간 ${count.count}회 · ${candidateCardId ? '카드 후보는 draft 관측' : '새 PR 차단'} · ${count.reason ?? verdict.reasons[0].detail}`]);
|
|
573
719
|
if (!alert.ok) debug.log('pr-tool.open-guard', 'op-alert-failed', { seat, reason: alert.err || alert.out || 'eln msg post 실패' });
|
|
574
|
-
return { ok: false, reason: 'guard', detail: `inventory-unknown: 1시간 ${count.count}회 · 새 PR 차단${count.reason ? ` (${count.reason})` : ''}` };
|
|
720
|
+
if (!candidateCardId) return { ok: false, reason: 'guard', detail: `inventory-unknown: 1시간 ${count.count}회 · 새 PR 차단${count.reason ? ` (${count.reason})` : ''}` };
|
|
575
721
|
}
|
|
576
722
|
}
|
|
577
723
|
guardUnmeasured = true;
|
|
@@ -581,7 +727,7 @@ export function makePrManager(
|
|
|
581
727
|
}
|
|
582
728
|
const createArgs = ['pr', 'create', '--head', input.branch, '--title', input.title, '--body', input.body];
|
|
583
729
|
if (prBase) createArgs.push('--base', prBase);
|
|
584
|
-
if (input.draft) createArgs.push('--draft');
|
|
730
|
+
if (input.draft || guardUnmeasured) createArgs.push('--draft');
|
|
585
731
|
const seat = input.seat ?? seatFromEnvironment();
|
|
586
732
|
const requiredLabels = [...(seat ? [`seat:${seat}`] : []), ...(guardUnmeasured ? ['pr-guard:unmeasured'] : [])];
|
|
587
733
|
// PR-GUARD-HUNK-WARN: 줄 겹침 경고 라벨은 «최선» — 만들기 실패해도 아래 재시도가 빼고 PR 을 연다.
|
|
@@ -599,6 +745,9 @@ export function makePrManager(
|
|
|
599
745
|
if (hunkOverlapWarning) debug.log('pr-tool.guard', 'hunk-overlap-warn', { pr: extractPrNumber(url), files: hunkOverlapWarning.files, against: hunkOverlapWarning.prs });
|
|
600
746
|
};
|
|
601
747
|
if (created.ok && created.out) {
|
|
748
|
+
if (guardUnmeasured) debug.log('pr-tool.open-guard', 'candidate-draft-unmeasured', {
|
|
749
|
+
branch: input.branch, cardId: candidateCardId ?? null, url: created.out,
|
|
750
|
+
});
|
|
602
751
|
logHunkOverlapWarn(created.out);
|
|
603
752
|
return {
|
|
604
753
|
ok: true,
|