elanous 0.2.20 → 0.2.22
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/aBi6EyMtLsrl7J8eH4kF7/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/088d8e8a.8069543d082bec12.js +160 -0
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +148 -0
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +32 -0
- package/apps/pwa/out/_next/static/chunks/119fc678.6f591cdb84ca5791.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +309 -0
- package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +122 -0
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +79 -0
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1948.5f35b39eef222a94.js +5 -0
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{2489-ff55a35b202c0f94.js → 2489-d238d3e2eb5b2bf5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +1 -0
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{6158.af2e93b7adff709b.js → 6158.566c890adc06a459.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
- package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-c855c24de7db74fe.js → page-88459e0903da2803.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-85b316bb4235980b.js → page-d85c43f46f58716b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-9b2b26a33cb2cd42.js → page-4e645600579ae952.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-c9955fde67b1bcb5.js → page-87edbfd19117823b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-4ba4abe096b6c2a8.js → page-cbaf66b1e1804adf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-575d4a8b4f7becb2.js → page-80ed511e02c81412.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/{page-f5d56ff5f45ad164.js → page-9f5610caaa06178c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/{page-2260e9eef0357421.js → page-ec8f3575e339de74.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-466bf0ee16ad1432.js → page-2a19c5cd3b562580.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-a23bc71713bcc08f.js → page-b6a09cde2e07521a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/{page-35bfec2e631d3eae.js → page-abd86cd832aaa011.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-f9ccb1b1adbea14d.js → page-8c3f168fc3f91939.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-ec102c9b8b691e37.js → page-786fb4504d0f2fa9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-db03ae3589a81c9e.js → page-7ec8e289b4c14df6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-4a6463b97f0ad94f.js → page-8c8ac17d52be2a79.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-75bffecc9aa1004e.js → page-d359ab048d63a9d9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-31d5b875760bb62d.js → page-f151cc10ad026940.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/{page-46d5201d2207a511.js → page-bf495a1e284f4e00.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-cf0a4b4abead71ea.js → page-9abcfac07e02a542.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-0acc8e198f7b0dfb.js → page-69cb93d1a2e57e0e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-34882c84f84021c5.js → page-72ec543928d67c3e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
- package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
- package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
- package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +14 -14
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +15 -15
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +15 -15
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/live-run/index.html +1 -0
- package/apps/pwa/out/live-run/index.txt +35 -0
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +14 -14
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/drafts/recipes.yaml +6 -6
- package/graphs/implement-loop.yaml +277 -5
- package/graphs/test-diet/recipes.yaml +3 -0
- package/graphs/test-diet/test-diet.yaml +3 -1
- package/package.json +1 -1
- package/scripts/coord-channel-watch.sh +31 -4
- package/scripts/docs-lint.ts +4 -1
- package/scripts/f-session-monitor.ts +69 -0
- package/scripts/hq/standby-snapshot.ts +7 -3
- package/scripts/knowledge-compress.ts +11 -0
- package/scripts/marketing/generate-ax-brief.ts +18 -1
- package/scripts/measure-nl-routing-corpus.ts +11 -3
- package/scripts/nightly-docops.ts +90 -3
- package/scripts/release-loop/gate-node.ts +5 -5
- package/scripts/release-loop/shard-plan.ts +50 -5
- package/scripts/research-coo-admin-dates.ts +39 -0
- package/scripts/rhythm/daily.ts +2 -1
- package/scripts/skills/public-check.ts +7 -2
- package/scripts/smart-merge/resync-shadow.ts +5 -3
- package/scripts/test-diet/lib.ts +81 -1
- package/scripts/test-diet/node.ts +48 -2
- package/scripts/verify-coo-admin-evidence.ts +83 -0
- package/src/acp/client.ts +4 -2
- package/src/agent/run-context.ts +4 -0
- package/src/agent-env/profile.ts +25 -5
- package/src/agent-mission/driver.ts +26 -12
- package/src/agent-mission/supervisor-metrics.ts +17 -2
- package/src/agent-substrate/acp-reviewer.ts +12 -5
- package/src/agent-substrate/pr-reviewer.ts +11 -4
- package/src/agent-substrate/review-intent.ts +102 -3
- package/src/autopilot/build/llm-conflict-merge.ts +22 -8
- package/src/autopilot/pr-manager.ts +18 -8
- package/src/away/release-watch.ts +47 -8
- package/src/briefing/brief-items.ts +104 -11
- package/src/browser-cdp/client.ts +10 -5
- package/src/chat/index.ts +1 -0
- package/src/cli/brief-cli.ts +20 -2
- package/src/cli/config-classify.ts +83 -0
- package/src/cli/control-cli.ts +14 -0
- package/src/cli/decisions-cli.ts +26 -16
- package/src/cli/logs-model-input.ts +1 -1
- package/src/cli/ops-cli.ts +11 -0
- package/src/cli/ops-overview-cli.ts +50 -0
- package/src/cli/pod-cli.ts +1 -0
- package/src/cli/pr-cli.ts +65 -8
- package/src/cli/release-cli.ts +21 -4
- package/src/cli/tasks-cli.ts +214 -1
- package/src/connectors/types.ts +6 -6
- package/src/context-bus/context-now-surfaces.ts +18 -0
- package/src/context-bus/coord-events.ts +32 -4
- package/src/context-bus/long-term-memory.ts +23 -6
- package/src/context-bus/nightly-condense.ts +169 -21
- package/src/control/control-status.ts +87 -0
- package/src/control-plane/light-member.ts +5 -3
- package/src/control-plane/member.ts +172 -7
- package/src/core-turn/run-goal-loop.ts +22 -1
- package/src/dashboard/index.ts +40 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +9 -0
- package/src/decisions/decision-cards.ts +20 -1
- package/src/decisions/decision-ledger.ts +11 -8
- package/src/decisions/web-push-decision-cards.ts +19 -3
- package/src/discord-self-message.ts +2 -2
- package/src/domains/coo-admin-dates.evidence.json +876 -0
- package/src/domains/coo-admin-tool.ts +48 -14
- package/src/domains/ops-status.ts +53 -0
- package/src/domains/outbound-alert.ts +24 -1
- package/src/esc-abort-gate.ts +3 -1
- package/src/exec-requests/planner.ts +6 -0
- package/src/graph-kinds/registry.ts +6 -6
- package/src/graph-runner/graph-cli.ts +91 -2
- package/src/graph-runner/graph-run-api.ts +20 -0
- package/src/graph-runner/graph-tick.ts +73 -12
- package/src/graph-runner/runner.ts +43 -11
- package/src/graph-unify/wf-to-graph.ts +79 -0
- package/src/graph-wizard/archetypes.ts +88 -0
- package/src/graph-wizard/generate.ts +577 -0
- package/src/graph-wizard/saved-steps.ts +120 -0
- package/src/graph-wizard/steps.ts +206 -0
- package/src/harness/harness-cli-command.ts +186 -32
- package/src/harness/harness-queue.ts +58 -14
- package/src/harness/launch-advice.ts +23 -0
- package/src/index.ts +43 -11
- package/src/intake-plane/digest.ts +18 -11
- package/src/knowledge/conclusion-compress.ts +93 -0
- package/src/knowledge/know-find.ts +9 -2
- package/src/knowledge/query.ts +20 -0
- package/src/llm.ts +26 -16
- package/src/loops/neighbor-runtime.ts +88 -0
- package/src/loops/orchestrator/author-depth.ts +29 -11
- package/src/loops/orchestrator/overlap.ts +7 -1
- package/src/loops/orchestrator/resync-shadow.ts +1 -1
- package/src/loops/orchestrator/tick.ts +35 -2
- package/src/loops/orchestrator/traffic.ts +2 -0
- package/src/loops/registry.ts +5 -0
- package/src/market/publish.ts +17 -1
- package/src/maturity/feature-maturity.ts +4 -2
- package/src/mss/logging/redaction.ts +17 -0
- package/src/nexus/api/draft-metrics.ts +128 -0
- package/src/nexus/api/graph-peer-edit.ts +77 -0
- package/src/nexus/api/graph-wizard-api.ts +61 -0
- package/src/nexus/api/graphs-api.ts +193 -17
- package/src/nexus/api/harness-traversal.ts +205 -0
- package/src/nexus/api/http-server.ts +122 -6
- package/src/nexus/api/plugins-market.ts +24 -0
- package/src/nexus/index.ts +3 -2
- package/src/nexus/outbound/router.ts +28 -8
- package/src/oauth/claude-pty-maturity.ts +24 -0
- package/src/oauth/fallback-chain.ts +27 -14
- package/src/onboarding/first-run.ts +3 -0
- package/src/ops/overview-collect.ts +345 -0
- package/src/ops/overview-seat-era.ts +90 -0
- package/src/ops/overview.ts +223 -0
- package/src/plugins/maker/market-bundle.ts +9 -0
- package/src/plugins/maker/plugin-maker.ts +9 -3
- package/src/plugins/maker/wizard-generate.ts +73 -9
- package/src/policy/llm-policy.ts +11 -6
- package/src/release-loop/checklist-board.ts +27 -0
- package/src/release-loop/checklist.ts +38 -0
- package/src/release-loop/gate-shards.ts +7 -2
- package/src/seat-address/seat-address.ts +1 -0
- package/src/seat-loop/seat-loop.ts +174 -20
- package/src/seat-loop/seat-report.ts +29 -1
- package/src/self-dev/ask-launch-flow.ts +4 -2
- package/src/self-dev/ask-launch-io.ts +3 -1
- package/src/self-dev/dev-cli.ts +90 -8
- package/src/self-dev/dev-pipeline.ts +20 -1
- package/src/self-dev/draft-sweep.ts +45 -8
- package/src/self-dev/graph-journey-nodes.ts +157 -0
- package/src/self-dev/graph-journey-route.ts +105 -0
- package/src/self-dev/launch-preflight.ts +43 -3
- package/src/self-dev/orchestrate.ts +3 -0
- package/src/self-dev/release-path-guard.ts +7 -4
- package/src/self-dev/review-provider-fallback.ts +83 -0
- package/src/self-dev/run-supervisor.ts +5 -1
- package/src/self-implement/frozen-merges.ts +23 -0
- package/src/self-implement/goal-author.ts +14 -0
- package/src/self-implement/harness-policy-gates.ts +7 -5
- package/src/self-implement/heal-intake.ts +3 -0
- package/src/self-implement/host-regate.ts +28 -14
- package/src/self-implement/l8-merge-queue.ts +80 -8
- package/src/self-implement/orchestrator.ts +84 -28
- package/src/self-implement/seams.ts +8 -3
- package/src/self-implement/self-implement-cli.ts +4 -0
- package/src/self-implement/self-implement-runtime.ts +12 -0
- package/src/session-runtime/index.ts +5 -3
- package/src/shell-env-bootstrap.ts +35 -6
- package/src/steward/triage.ts +25 -8
- package/src/storage/file-lock.ts +33 -4
- package/src/task-agent/card-evidence.ts +6 -0
- package/src/task-agent/completion-evidence.ts +31 -3
- package/src/task-agent/cover.ts +61 -0
- package/src/task-agent/live-moves.ts +126 -3
- package/src/task-agent/parent-host.ts +315 -0
- package/src/task-agent/shadow.ts +19 -4
- package/src/task-agent/task-hand.ts +11 -2
- package/src/task-orchestrator/surfaces/pod-command-job.ts +41 -6
- package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +138 -15
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +39 -6
- package/src/task-orchestrator/surfaces/self-implement.ts +7 -0
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-project-command.ts +6 -0
- package/src/telegram.ts +2 -2
- package/src/tool-runtime/browser-runtime.ts +87 -3
- package/src/tool-runtime/index.ts +1 -0
- package/src/typecheck-ratchet.ts +2 -1
- package/src/user-config.ts +55 -8
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/executor.ts +24 -2
- package/src/workflow-runtime/triggers/registry.ts +27 -0
- package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
- package/apps/pwa/out/_next/static/Bam1YziK2iH9bN4K0utGk/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1307-77fad80cf54477c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
- package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +0 -25
- package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7a852956c74015a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-7c058069c5e7fa63.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-9cd565005b93aca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-474cb5888ea0e8f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ca21f9ad3208a61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-a9c2cfa8dda922a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-f6055495e9ed7ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c26fa10aac6c21c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-68793c6e10331d66.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-d81c07a7b4f618ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-be1c4e8697f22360.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0fd895fab9b62c1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c6e4364d9de8f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-c260571513bf43c2.js +0 -1
- package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +0 -1
- /package/apps/pwa/out/_next/static/{Bam1YziK2iH9bN4K0utGk → aBi6EyMtLsrl7J8eH4kF7}/_ssgManifest.js +0 -0
- /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
package/src/agent-env/profile.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
1
2
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
|
|
5
|
-
type Agent = 'claude' | 'codex' | 'grok';
|
|
6
|
+
type Agent = 'claude' | 'codex' | 'grok' | 'gemini';
|
|
7
|
+
|
|
8
|
+
function versionOf(binary: string): string | null {
|
|
9
|
+
const result = spawnSync(binary, ['--version'], { encoding: 'utf8', timeout: 3000 });
|
|
10
|
+
const line = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim().split(/\r?\n/, 1)[0];
|
|
11
|
+
return result.status === 0 && line && /^[\w .+()-]{1,100}$/.test(line) ? line : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Plugin and marketplace keys are `name@marketplace`; check each part instead of redacting every scoped name.
|
|
15
|
+
function safePluginName(name: string): string {
|
|
16
|
+
const parts = name.split('@');
|
|
17
|
+
return parts.length <= 2 && parts.every(part => part !== '' && safeIdentifier(part) === part) ? name : '<redacted>';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function safeNames(path: string): string[] | '«없음»' {
|
|
21
|
+
return !existsSync(path) ? '«없음»' : readdirSync(path, { withFileTypes: true })
|
|
22
|
+
.filter(entry => entry.isDirectory()).map(entry => safeIdentifier(entry.name) ?? '<redacted>').sort();
|
|
23
|
+
}
|
|
6
24
|
type Presence = 'present' | '«없음»';
|
|
7
25
|
|
|
8
26
|
function present(path: string): Presence {
|
|
@@ -54,7 +72,7 @@ function collectMcp(
|
|
|
54
72
|
servers: unknown,
|
|
55
73
|
source: McpSource,
|
|
56
74
|
): void {
|
|
57
|
-
for (const [name, server] of Object.entries(record(servers))) into[name] = mcpEntry(server, source);
|
|
75
|
+
for (const [name, server] of Object.entries(record(servers))) into[safeIdentifier(name) ?? '<redacted>'] = mcpEntry(server, source);
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
function hookGroups(hooks: Record<string, unknown>): Record<string, unknown[]> {
|
|
@@ -86,6 +104,7 @@ function claude(home: string): Record<string, unknown> {
|
|
|
86
104
|
const skillsDir = join(dir, 'skills');
|
|
87
105
|
const team = join(home, '.teamclaude');
|
|
88
106
|
const teamManifest = json(join(team, 'package.json'));
|
|
107
|
+
const marketplaces = record(data.extraKnownMarketplaces);
|
|
89
108
|
const teamVersion = typeof teamManifest?.version === 'string' && /^\d+\.\d+\.\d+(?:[-+.][a-zA-Z0-9.-]+)?$/.test(teamManifest.version)
|
|
90
109
|
? teamManifest.version : undefined;
|
|
91
110
|
const mcp: Record<string, unknown> = {};
|
|
@@ -98,6 +117,7 @@ function claude(home: string): Record<string, unknown> {
|
|
|
98
117
|
}
|
|
99
118
|
const mcpFilesMissing = settings === null && user === null;
|
|
100
119
|
return {
|
|
120
|
+
version: versionOf('claude'),
|
|
101
121
|
settings: settings === null ? '«없음»' : 'present',
|
|
102
122
|
userConfig: user === null ? '«없음»' : 'present',
|
|
103
123
|
permissionMode: safeIdentifier(record(data.permissions).defaultMode),
|
|
@@ -106,10 +126,10 @@ function claude(home: string): Record<string, unknown> {
|
|
|
106
126
|
command: safeCommand(statusLine.command) ?? null,
|
|
107
127
|
},
|
|
108
128
|
hooks: settings === null ? '«없음»' : hookGroups(hooks),
|
|
109
|
-
enabledPlugins: settings === null ? '«없음»' : Object.fromEntries(Object.entries(plugins).map(([name, enabled]) => [name, enabled === true])),
|
|
129
|
+
enabledPlugins: settings === null ? '«없음»' : Object.fromEntries(Object.entries(plugins).map(([name, enabled]) => [safePluginName(name), enabled === true])),
|
|
130
|
+
marketplaces: settings === null ? '«없음»' : Object.keys(marketplaces).map(name => safeIdentifier(name) ?? '<redacted>').sort(),
|
|
110
131
|
mcpServers: mcpFilesMissing ? '«없음»' : mcp,
|
|
111
|
-
skills:
|
|
112
|
-
.filter(entry => entry.isDirectory()).map(entry => entry.name).sort(),
|
|
132
|
+
skills: safeNames(skillsDir),
|
|
113
133
|
teamclaude: { installed: present(team), version: teamVersion ?? null },
|
|
114
134
|
auth: present(join(dir, 'auth.json')),
|
|
115
135
|
credentials: present(join(dir, '.credentials.json')),
|
|
@@ -30,7 +30,7 @@ import { resolvePtyWebAddress } from '../cli/pty-web-address.js';
|
|
|
30
30
|
import { verdictForFinalPtyScreen } from '../cli/pty-drive-verdict.js';
|
|
31
31
|
import { reemitPtyUsage } from '../budget/pty-usage-reemit.js';
|
|
32
32
|
import { classifyAuthError } from '../oauth/codex.js';
|
|
33
|
-
import type
|
|
33
|
+
import { normalizeFallbackChain, type FallbackStep } from '../oauth/fallback-chain.js';
|
|
34
34
|
import { runPtyControlLoop, controlDepsForHandle, type ControlDecision, type ControlObservation, type RunSupervisor } from '../autopilot/pty-control-loop.js';
|
|
35
35
|
import { probeControlStance, stanceBlocksWrite } from '../pty-shell/pty-control-stance.js';
|
|
36
36
|
import { mapControlStance, supervisionObservationFields } from '../self-implement/supervision-vocabulary.js';
|
|
@@ -441,7 +441,7 @@ export function agentBackendNames(): string[] {
|
|
|
441
441
|
*
|
|
442
442
|
* ⛔ 불변식 셋(윗 모듈에서 그대로 이어받는다):
|
|
443
443
|
* ① **사람이 이름을 «명시»했으면 이 함수는 «안» 불린다** — 의도가 이긴다(호출자가 위에서 갈린다).
|
|
444
|
-
* ② **기본 체인은 `['codex-rotate']`**
|
|
444
|
+
* ② **기본 체인은 `['codex-rotate', 'grok']`** 이며 claude-pty 는 명시 구성에서만 선택된다.
|
|
445
445
|
* ③ **조용히 바꾸지 않는다** — 바꿨으면 관측에 남긴다. 조용한 폴백은 이 파일이 이미
|
|
446
446
|
* 거부한 형태다(위 `resolveBackend` 주석: *"조용한 codex 폴백은 애그노스틱 위반"*).
|
|
447
447
|
*
|
|
@@ -460,9 +460,9 @@ export function resolveDefaultBackend(
|
|
|
460
460
|
return resolveRunFallback();
|
|
461
461
|
});
|
|
462
462
|
const decision = decide();
|
|
463
|
-
if (decision.action === 'switch-backend' && decision.backend === 'grok') {
|
|
464
|
-
debug.log('agent-mission.backend', 'fallback-switch', { from: 'codex', to:
|
|
465
|
-
return grokBackend;
|
|
463
|
+
if (decision.action === 'switch-backend' && (decision.backend === 'grok' || decision.backend === 'claude')) {
|
|
464
|
+
debug.log('agent-mission.backend', 'fallback-switch', { from: 'codex', to: decision.backend, reason: 'codex-exhausted' });
|
|
465
|
+
return decision.backend === 'claude' ? claudeBackend : grokBackend;
|
|
466
466
|
}
|
|
467
467
|
} catch (err) {
|
|
468
468
|
debug.log('agent-mission.backend', 'fallback-failed', { message: (err as Error)?.message }, { level: 'warn' });
|
|
@@ -503,6 +503,20 @@ interface RuntimeFallbackContext extends RuntimeFallbackState {
|
|
|
503
503
|
readonly fallbackEligible: boolean;
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
+
/** 초기 백엔드의 체인 위치부터 남은 칸만 재시도한다. 실제 전환은 각 칸의 판정이 허용해야 한다. */
|
|
507
|
+
export function initialRuntimeFallback(backend: AgentBackend, chain: readonly FallbackStep[]): RuntimeFallbackContext {
|
|
508
|
+
const step: FallbackStep = backend.name === 'grok' ? 'grok' : backend.name === 'claude' ? 'claude-pty' : 'codex-rotate';
|
|
509
|
+
const position = chain.indexOf(step);
|
|
510
|
+
return {
|
|
511
|
+
fallbackEligible: true,
|
|
512
|
+
attemptedSteps: new Set<FallbackStep>([step]),
|
|
513
|
+
descents: 0,
|
|
514
|
+
// 초기 칸이 체인에 «없으면»(예: chain=['grok'] 인데 기본 codex 로 떴다) 체인 전체가 남은 칸이다 —
|
|
515
|
+
// 종전(codex 면 1칸)보다 줄이지 않는다.
|
|
516
|
+
maxDescents: position < 0 ? chain.filter((s) => s !== step).length : chain.length - position - 1,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
506
520
|
/** 한도 실패에만 재판정한다. 새·미시도 체인 칸과 최초 남은 칸 상한을 모두 만족해야 이동한다. */
|
|
507
521
|
export function decideRuntimeFallback(
|
|
508
522
|
failure: unknown,
|
|
@@ -512,8 +526,10 @@ export function decideRuntimeFallback(
|
|
|
512
526
|
): AgentBackend | null {
|
|
513
527
|
if (classifyAuthError(failure).errorKind !== 'rate-limited' || state.descents >= state.maxDescents) return null;
|
|
514
528
|
const decision = decide({ currentStep, currentCredentialRateLimited: true });
|
|
515
|
-
if (decision.action !== 'switch-backend'
|
|
516
|
-
|
|
529
|
+
if (decision.action !== 'switch-backend') return null;
|
|
530
|
+
const nextStep = decision.backend === 'grok' ? 'grok' : decision.backend === 'claude' ? 'claude-pty' : null;
|
|
531
|
+
if (!nextStep || state.attemptedSteps.has(nextStep)) return null;
|
|
532
|
+
return nextStep === 'claude-pty' ? claudeBackend : grokBackend;
|
|
517
533
|
}
|
|
518
534
|
|
|
519
535
|
export interface AgentMissionSpec {
|
|
@@ -1586,10 +1602,8 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
|
|
|
1586
1602
|
if (spec.plugin && (spec.headless || (backend.name !== 'codex' && backend.name !== 'claude'))) throw new Error('--plugin 은 codex/claude PTY 전용입니다');
|
|
1587
1603
|
if (spec.workdir && spec.chain) throw new Error('workdir 모드는 넘기기 사슬을 쓰지 않는다');
|
|
1588
1604
|
const runtimeFallback = deps.runtimeFallback ?? {
|
|
1605
|
+
...initialRuntimeFallback(backend, normalizeFallbackChain(getUserConfig().llm?.fallbackChain).chain),
|
|
1589
1606
|
fallbackEligible: spec.agent === undefined && !spec.chain,
|
|
1590
|
-
attemptedSteps: new Set<FallbackStep>([backend.name === 'grok' ? 'grok' : 'codex-rotate']),
|
|
1591
|
-
descents: 0,
|
|
1592
|
-
maxDescents: backend.name === 'codex' ? 1 : 0,
|
|
1593
1607
|
};
|
|
1594
1608
|
const spawnPty = deps.startPty ?? startPty;
|
|
1595
1609
|
const createMissionWorktree = deps.createWorktree ?? createWorktree;
|
|
@@ -2279,7 +2293,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
|
|
|
2279
2293
|
const { resolveRunFallback: resolve } = require('../oauth/codex-account-store.js') as typeof import('../oauth/codex-account-store.js');
|
|
2280
2294
|
return resolve(process.env, input);
|
|
2281
2295
|
});
|
|
2282
|
-
const currentStep: FallbackStep = backend.name === 'grok' ? 'grok' : 'codex-rotate';
|
|
2296
|
+
const currentStep: FallbackStep = backend.name === 'grok' ? 'grok' : backend.name === 'claude' ? 'claude-pty' : 'codex-rotate';
|
|
2283
2297
|
const nextBackend = runtimeFallback.fallbackEligible ? decideRuntimeFallback(
|
|
2284
2298
|
failure,
|
|
2285
2299
|
currentStep,
|
|
@@ -2296,7 +2310,7 @@ async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDep
|
|
|
2296
2310
|
});
|
|
2297
2311
|
if (nextBackend && !deps.isMissionAborted?.()) {
|
|
2298
2312
|
decisionEvent({ step: 'recover', text: `Switching ${backend.name} to ${nextBackend.name}`, detail: { blocked: control.termination.message, action: `Retry with ${nextBackend.name}` } });
|
|
2299
|
-
const nextStep: FallbackStep = nextBackend.name === 'grok' ? 'grok' : 'codex-rotate';
|
|
2313
|
+
const nextStep: FallbackStep = nextBackend.name === 'grok' ? 'grok' : nextBackend.name === 'claude' ? 'claude-pty' : 'codex-rotate';
|
|
2300
2314
|
stopLive();
|
|
2301
2315
|
if (h.pid) await (deps.terminateProcessTree ?? terminateMissionProcessTree)(h.pid);
|
|
2302
2316
|
try { h.kill(); } catch { /* noop */ }
|
|
@@ -69,8 +69,17 @@ function linkedRows(rows: readonly SupervisorLogRow[], missionIds: ReadonlySet<s
|
|
|
69
69
|
const linked: SupervisorLogRow[] = [];
|
|
70
70
|
let unlinked = false;
|
|
71
71
|
for (const row of rows) {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// The driver writes its runId into the ambient log payload and the PTY decision's
|
|
73
|
+
// sessionId; the decision emitter may replace missionId with a display alias.
|
|
74
|
+
// Without a runId, either retained identifier can identify an existing result.
|
|
75
|
+
const runId = row.data?.runId;
|
|
76
|
+
const sessionId = row.category === DECISION_CATEGORY ? row.data?.sessionId : undefined;
|
|
77
|
+
const key = typeof runId === 'string' && runId.trim() ? runId.trim() : null;
|
|
78
|
+
const sessionKey = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : null;
|
|
79
|
+
const missionId = typeof row.data?.missionId === 'string' && row.data.missionId.trim() ? row.data.missionId.trim() : null;
|
|
80
|
+
const matches = key ? missionIds.has(key)
|
|
81
|
+
: (missionId !== null && missionIds.has(missionId)) || (sessionKey !== null && missionIds.has(sessionKey));
|
|
82
|
+
if (matches) linked.push(row);
|
|
74
83
|
else unlinked = true;
|
|
75
84
|
}
|
|
76
85
|
return { linked, unlinked };
|
|
@@ -123,6 +132,12 @@ export function aggregateSupervisorMetrics(
|
|
|
123
132
|
? unmeasured('questionsAnswered', '대화형 질문에 답해 넘긴 수', UNLINKED_REASON)
|
|
124
133
|
: answers.linked.length === 0
|
|
125
134
|
? unmeasured('questionsAnswered', '대화형 질문에 답해 넘긴 수', '못 잼 · pty.decision answer 기록 없음')
|
|
135
|
+
: answers.linked.some((row) => {
|
|
136
|
+
const detail = row.data?.detail;
|
|
137
|
+
return !detail || typeof detail !== 'object' || !('answer' in detail)
|
|
138
|
+
|| typeof detail.answer !== 'string' || !detail.answer.trim();
|
|
139
|
+
})
|
|
140
|
+
? unmeasured('questionsAnswered', '대화형 질문에 답해 넘긴 수', '못 잼 · 답변 본문 기록 없음')
|
|
126
141
|
: {
|
|
127
142
|
id: 'questionsAnswered',
|
|
128
143
|
label: '대화형 질문에 답해 넘긴 수',
|
|
@@ -25,6 +25,10 @@ export interface AcpReviewerOpts {
|
|
|
25
25
|
cwd: string;
|
|
26
26
|
/** ACP 백엔드 id (기본 claude = Claude Code via claude-code-acp). */
|
|
27
27
|
backend?: string;
|
|
28
|
+
/** Per-review ACP spawn specification (subscription executor). */
|
|
29
|
+
backendSpec?: import('../acp/backend-registry.js').AcpBackendSpec;
|
|
30
|
+
/** Subscription child environment after billing credentials are removed. */
|
|
31
|
+
env?: Record<string, string>;
|
|
28
32
|
/** 모델 tier 별칭 (opus|sonnet|haiku 등). 지정 시 session/set_model 로 고정(백엔드 CLI 기본 위임 아님). */
|
|
29
33
|
model?: string;
|
|
30
34
|
/** 리뷰 1턴 최대 대기(ms). 초과 시 cancel→throw(부분 리뷰로 오판 pass 방지). 기본 300000. */
|
|
@@ -96,7 +100,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
|
|
|
96
100
|
// ⇒ 이 한 줄만 자기 catch 로 감싼다(전체 try 를 앞당기면 `start` 관측이 그 안으로 들어간다).
|
|
97
101
|
let transport: string | null;
|
|
98
102
|
try {
|
|
99
|
-
transport = injected ? null : getAcpBackend(backend).transport ?? 'acp';
|
|
103
|
+
transport = injected ? null : opts.backendSpec?.transport ?? getAcpBackend(backend).transport ?? 'acp';
|
|
100
104
|
} catch (e) {
|
|
101
105
|
debug.log('acp-review', 'error', {
|
|
102
106
|
requestedBackend, backend, stage: 'resolve-backend', message: (e as Error).message,
|
|
@@ -116,6 +120,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
|
|
|
116
120
|
let capabilitiesObserved = false;
|
|
117
121
|
const agentOpts: Omit<AcpAgentOpts, 'backendId'> = {
|
|
118
122
|
cwd: opts.cwd,
|
|
123
|
+
...(opts.backendSpec ? { backendSpec: opts.backendSpec, env: opts.env } : {}),
|
|
119
124
|
log: (message) => debug.log('acp-review', 'agent-log', { backend, message }),
|
|
120
125
|
onCapabilities: (capabilities) => {
|
|
121
126
|
capabilitiesObserved = true;
|
|
@@ -142,7 +147,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
|
|
|
142
147
|
};
|
|
143
148
|
// A review owns its manager and subprocess: the global manager caches
|
|
144
149
|
// chat agents, whose callbacks and lifecycle must not be mutated here.
|
|
145
|
-
const reviewManager = injected ? undefined : new AcpAgentManager();
|
|
150
|
+
const reviewManager = injected || opts.backendSpec ? undefined : new AcpAgentManager();
|
|
146
151
|
let agent: AcpAgent | undefined;
|
|
147
152
|
let text = '';
|
|
148
153
|
let timedOut = false;
|
|
@@ -150,8 +155,10 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
|
|
|
150
155
|
try {
|
|
151
156
|
agent = opts.createAgent
|
|
152
157
|
? opts.createAgent({ backendId: requestedBackend, ...agentOpts })
|
|
153
|
-
:
|
|
154
|
-
|
|
158
|
+
: opts.backendSpec
|
|
159
|
+
? new AcpAgent({ backendId: requestedBackend, ...agentOpts })
|
|
160
|
+
: await reviewManager!.getAgent(requestedBackend, agentOpts);
|
|
161
|
+
if (injected || opts.backendSpec) await agent.start();
|
|
155
162
|
if (!capabilitiesObserved) {
|
|
156
163
|
try {
|
|
157
164
|
debug.log('acp-review', 'capabilities', {
|
|
@@ -211,7 +218,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
|
|
|
211
218
|
// cleanup seam, while the per-review manager releases its agents and
|
|
212
219
|
// process hooks. An injected agent is external to the manager.
|
|
213
220
|
try {
|
|
214
|
-
if (injected) await agent?.stop();
|
|
221
|
+
if (injected || opts.backendSpec) await agent?.stop();
|
|
215
222
|
else await reviewManager!.dispose();
|
|
216
223
|
} catch (e) {
|
|
217
224
|
debug.log('acp-review', 'stop-fail', { backend, message: (e as Error).message }, { level: 'error' });
|
|
@@ -59,6 +59,8 @@ export interface ReviewResult {
|
|
|
59
59
|
* ⚠️ 미주입(`llmReview` 없음)은 «실패가 아니라 미검토»라 이 칸을 안 채운다 — 둘을 구분한다.
|
|
60
60
|
*/
|
|
61
61
|
failureReason?: string;
|
|
62
|
+
/** Subscription reviewer unavailable: the default reviewer produced this verdict. */
|
|
63
|
+
reviewerFallback?: string;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
/** 모든 리뷰 관측 생산자가 공유하는 diff 예산 필드 계약. 예산 부재는 빈 객체로 보존한다.
|
|
@@ -300,7 +302,7 @@ export function planReviewChunks(
|
|
|
300
302
|
*/
|
|
301
303
|
export function foldReviewResults(
|
|
302
304
|
results: readonly ReviewResult[],
|
|
303
|
-
): Pick<ReviewResult, 'verdict' | 'mustFix' | 'shouldFix' | 'requirements' | 'reviewed' | 'failureReason'> {
|
|
305
|
+
): Pick<ReviewResult, 'verdict' | 'mustFix' | 'shouldFix' | 'requirements' | 'reviewed' | 'failureReason' | 'reviewerFallback'> {
|
|
304
306
|
const dedupe = (values: readonly string[]): string[] => [...new Set(values)];
|
|
305
307
|
const collect = (pick: (r: ReviewResult) => readonly string[] | undefined): string[] =>
|
|
306
308
|
dedupe(results.flatMap((r) => [...(pick(r) ?? [])]));
|
|
@@ -311,6 +313,7 @@ export function foldReviewResults(
|
|
|
311
313
|
const shouldFix = collect((r) => r.shouldFix).slice(0, 6);
|
|
312
314
|
const requirements = collect((r) => r.requirements);
|
|
313
315
|
const failed = results.find((r) => r.reviewed !== true);
|
|
316
|
+
const reviewerFallback = results.find((r) => r.reviewerFallback)?.reviewerFallback;
|
|
314
317
|
return {
|
|
315
318
|
verdict,
|
|
316
319
|
mustFix,
|
|
@@ -318,6 +321,7 @@ export function foldReviewResults(
|
|
|
318
321
|
...(requirements.length ? { requirements } : {}),
|
|
319
322
|
reviewed: results.length > 0 && failed === undefined,
|
|
320
323
|
...(failed?.failureReason ? { failureReason: failed.failureReason } : {}),
|
|
324
|
+
...(reviewerFallback ? { reviewerFallback } : {}),
|
|
321
325
|
};
|
|
322
326
|
}
|
|
323
327
|
|
|
@@ -560,6 +564,9 @@ export function buildReviewPrompt(
|
|
|
560
564
|
|
|
561
565
|
return [
|
|
562
566
|
'You are a strict staff-engineer reviewing an ALREADY-OPENED pull request from an autonomous coding agent.',
|
|
567
|
+
// ⚠️ 무표식 절단 금지(리뷰 must-fix) — 잘렸으면 **어느 절부터**인지 리뷰어가 알아야 한다.
|
|
568
|
+
phaseIntentHeading, phaseIntent,
|
|
569
|
+
...(input.acceptance ? ['## Acceptance criteria', input.acceptance.slice(0, 1000)] : []),
|
|
563
570
|
'This is a POST-PR review of the produced artifact. Judge whether the PR actually',
|
|
564
571
|
'delivers the phase intent CORRECTLY and soundly: (1) correctness/latent bugs, (2) does it meet the stated',
|
|
565
572
|
'acceptance criteria, (3) design/regression risk, (4) missing wiring (new code never called), (5) tests present',
|
|
@@ -584,9 +591,6 @@ export function buildReviewPrompt(
|
|
|
584
591
|
' and check that the error names that site; use values the real caller produces instead of synthetic input.',
|
|
585
592
|
'Do NOT rubber-stamp; an empty review is a failed review — always surface at least a watch item.',
|
|
586
593
|
'',
|
|
587
|
-
// ⚠️ 무표식 절단 금지(리뷰 must-fix) — 잘렸으면 **어느 절부터**인지 리뷰어가 알아야 한다.
|
|
588
|
-
phaseIntentHeading, phaseIntent,
|
|
589
|
-
...(input.acceptance ? ['## Acceptance criteria', input.acceptance.slice(0, 1000)] : []),
|
|
590
594
|
...(input.workingMemory ? ['## Prior decisions / reuse boundaries (working memory)', input.workingMemory.slice(0, 1200)] : []),
|
|
591
595
|
// ⭐ 증거가 무엇인지 먼저 말한다 — 규칙 (7) 이 "의도를 넘어선 변경" 을 판정하려면
|
|
592
596
|
// diff 에 담긴 것이 **이 PR 이 저작한 것인지**를 알아야 한다.
|
|
@@ -634,10 +638,12 @@ export function parseReviewResult(text: string): ReviewResult {
|
|
|
634
638
|
const first = shouldFix.shift() ?? fallbackFinding;
|
|
635
639
|
mustFix.push(first ?? 'PR 리뷰 FAIL — 재작업 필요(구체 지적 미파싱).');
|
|
636
640
|
}
|
|
641
|
+
const fallback = text.match(/\n\[reviewer fallback: ([^\r\n]+)\]$/);
|
|
637
642
|
return {
|
|
638
643
|
verdict,
|
|
639
644
|
mustFix: mustFix.slice(0, 6),
|
|
640
645
|
shouldFix: shouldFix.slice(0, 6),
|
|
646
|
+
...(fallback ? { reviewerFallback: fallback[1] } : {}),
|
|
641
647
|
...(requirements.length ? { requirements } : {}),
|
|
642
648
|
};
|
|
643
649
|
}
|
|
@@ -830,6 +836,7 @@ export function renderReview(r: ReviewResult): string {
|
|
|
830
836
|
const icon = r.verdict === 'pass' ? '✅' : r.verdict === 'warn' ? '⚠️' : '⛔';
|
|
831
837
|
const head = `${icon} 자율 PR 리뷰: ${r.verdict.toUpperCase()}`;
|
|
832
838
|
const parts = [head];
|
|
839
|
+
if (r.reviewerFallback) parts.push(`[reviewer fallback: ${r.reviewerFallback}]`);
|
|
833
840
|
if (r.mustFix.length) parts.push('**Must-fix (blockers)**', ...r.mustFix.map((f) => `- ${f}`));
|
|
834
841
|
if (r.shouldFix.length) parts.push('**Should-fix**', ...r.shouldFix.map((f) => `- ${f}`));
|
|
835
842
|
if (r.mustFix.length === 0 && r.shouldFix.length === 0) parts.push('— 리뷰 통과(블로커·비블로커 지적 없음).');
|
|
@@ -525,6 +525,73 @@ function goalFileBlock(goalFile: string | undefined): Block | undefined {
|
|
|
525
525
|
: undefined;
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
+
function isLightweightGoal(goal: string): boolean {
|
|
529
|
+
try {
|
|
530
|
+
const tree = unified().use(remarkParse).use(remarkGfm).parse(goal) as MarkdownNode;
|
|
531
|
+
const nodes = tree.children ?? [];
|
|
532
|
+
const headings = new Set<string>();
|
|
533
|
+
const declarations = new Set<string>();
|
|
534
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
535
|
+
const node = nodes[index]!;
|
|
536
|
+
if (node.type !== 'heading' || node.depth !== 2) continue;
|
|
537
|
+
const start = node.position?.start.offset;
|
|
538
|
+
const end = node.position?.end.offset;
|
|
539
|
+
if (start === undefined || end === undefined) return false;
|
|
540
|
+
const heading = goal.slice(start, end).trim();
|
|
541
|
+
headings.add(heading);
|
|
542
|
+
if (heading !== '## 답하지 못하는 것' && heading !== '## 불변식') continue;
|
|
543
|
+
const next = nodes[index + 1];
|
|
544
|
+
if (next?.type !== 'list' || next.children?.length !== 1) continue;
|
|
545
|
+
const item = next.children[0];
|
|
546
|
+
const itemStart = item?.position?.start.offset;
|
|
547
|
+
const itemEnd = item?.position?.end.offset;
|
|
548
|
+
if (itemStart === undefined || itemEnd === undefined) continue;
|
|
549
|
+
if (goal.slice(itemStart, itemEnd).trim() === '- No persistent grounding was performed in lite authoring.') {
|
|
550
|
+
declarations.add(heading);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return headings.has('## WHAT TO BUILD') && headings.has('## ACCEPTANCE CRITERIA')
|
|
554
|
+
&& declarations.has('## 답하지 못하는 것') && declarations.has('## 불변식');
|
|
555
|
+
} catch {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function lightweightGoalContext(goal: string, goalFile: string): Block {
|
|
561
|
+
const nodes = (unified().use(remarkParse).use(remarkGfm).parse(goal) as MarkdownNode).children ?? [];
|
|
562
|
+
const firstLine = (title: string): string | undefined => {
|
|
563
|
+
const headingIndex = nodes.findIndex((node) => {
|
|
564
|
+
if (node.type !== 'heading' || node.depth !== 2) return false;
|
|
565
|
+
const start = node.position?.start.offset;
|
|
566
|
+
const end = node.position?.end.offset;
|
|
567
|
+
return start !== undefined && end !== undefined && goal.slice(start, end).trim() === `## ${title}`;
|
|
568
|
+
});
|
|
569
|
+
if (headingIndex < 0) return undefined;
|
|
570
|
+
for (const node of nodes.slice(headingIndex + 1)) {
|
|
571
|
+
if (node.type === 'heading' && (node.depth ?? 0) <= 2) break;
|
|
572
|
+
if (node.type === 'code') continue;
|
|
573
|
+
const start = node.position?.start.offset;
|
|
574
|
+
const end = node.position?.end.offset;
|
|
575
|
+
if (start === undefined || end === undefined) continue;
|
|
576
|
+
const line = goal.slice(start, end).split('\n').find((item) => item.trim());
|
|
577
|
+
if (line) return line.replace(/^[-*]\s*/, '').replace(/^(?:무엇|왜):\s*/, '').trim();
|
|
578
|
+
}
|
|
579
|
+
return undefined;
|
|
580
|
+
};
|
|
581
|
+
const brief = (text: string): string => text.length > 350 ? `${text.slice(0, 350)}…[골 원문 참조]` : text;
|
|
582
|
+
const what = firstLine('WHAT TO BUILD');
|
|
583
|
+
const why = firstLine('PROBLEM');
|
|
584
|
+
return {
|
|
585
|
+
title: '무엇을 왜',
|
|
586
|
+
text: [
|
|
587
|
+
'무엇을 왜',
|
|
588
|
+
...(what ? [`무엇: ${brief(what)}`] : []),
|
|
589
|
+
...(why ? [`왜: ${brief(why)}`] : []),
|
|
590
|
+
`골 원문·긴 참조: ${goalFile}`,
|
|
591
|
+
].join('\n'),
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
|
|
528
595
|
export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
529
596
|
// ① 조망 — 명시값이 없으면 **골 텍스트에서 추출**한다(생산자는 골 자체다·LLM 없음).
|
|
530
597
|
const mined = extractIntentBlocks(i.goal);
|
|
@@ -537,7 +604,9 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
|
537
604
|
// 후순위 블록(스코프 경계)이 불필요하게 잘린다.
|
|
538
605
|
const identity = parseShardIdentity(i.goal);
|
|
539
606
|
const shardBoundary = identity ? { title: '조각 경계', text: `조각 경계\n${shardBoundaryBlock(identity)}` } : undefined;
|
|
540
|
-
const
|
|
607
|
+
const authoredLiteGoal = isLightweightGoal(i.goal);
|
|
608
|
+
const liteGoal = authoredLiteGoal && Boolean(i.goalFile?.trim());
|
|
609
|
+
const goalBody = liteGoal ? '' : stripExtractedSections(identity ? withoutShardIdentity(i.goal) : i.goal).trim();
|
|
541
610
|
const goal = goalBody ? { title: '목표', text: `목표\n${goalBody}` } : undefined;
|
|
542
611
|
// ⭐ **자식이 낸 증거**(diff 밖 이행 · base 적색 · 직전 반영분)를 한 묶음으로 잡아 둔다 — 아래 예산
|
|
543
612
|
// 배분에서 **목표 본문보다 먼저** 채우기 위해서다. 제목 문자열이 아니라 **동일성**으로 가른다.
|
|
@@ -553,6 +622,20 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
|
553
622
|
const coverage = evidenceCoverageBlock(i.evidenceCoverage);
|
|
554
623
|
const goalFile = goalFileBlock(i.goalFile);
|
|
555
624
|
const runFacts = runFactsBlock(i);
|
|
625
|
+
// Lite authoring keeps its original ask in a fenced block under WHAT TO BUILD.
|
|
626
|
+
// Review the authored criteria and short context; the goal document is the pointer to the long source.
|
|
627
|
+
if (liteGoal) {
|
|
628
|
+
const acceptanceBlock = listBlock('수용기준', acceptance);
|
|
629
|
+
const context = lightweightGoalContext(i.goal, i.goalFile!.trim());
|
|
630
|
+
const boundaryBlock = listBlock('의도적 스코프 경계', boundaries);
|
|
631
|
+
const liteBlocks = [
|
|
632
|
+
acceptanceBlock, context, boundaryBlock, priorFindings, applied,
|
|
633
|
+
runFacts, goalType, shardBoundary, preexisting, importerTestsNotRun,
|
|
634
|
+
gateEvidence, designCheck, designGate, shardSiblings, coverage, claims,
|
|
635
|
+
listBlock('검증 못 한 경계 후보 (결정 아님 — 이것만으로 must-fix 를 면제하지도, 만들지도 말 것)', unverifiedBoundaryCandidates),
|
|
636
|
+
].filter((block): block is Block => Boolean(block));
|
|
637
|
+
return fitReviewIntentBlocks(liteBlocks, liteBlocks, liteBlocks);
|
|
638
|
+
}
|
|
556
639
|
// ⛔⭐⭐⭐ **런 사실이 «맨 앞»이다 — 라이브 실측으로 옮겼다**(2026-08-07).
|
|
557
640
|
// 📏 `#7556`(실물 하니스 PR · 본문 37,354자)을 프로덕션 `intentFromPr` 에 태우니
|
|
558
641
|
// ***`runId` 도 커밋도 변경 파일도 «하나도» 안 남았다***(4,000자 상한 · 살아남은 것은 `목표`·`수용기준`).
|
|
@@ -645,7 +728,7 @@ function sectionPriority(title: string): 0 | 1 | 2 {
|
|
|
645
728
|
const PREAMBLE_TITLE = '(머리말)';
|
|
646
729
|
|
|
647
730
|
type MarkdownPosition = { readonly start: { readonly offset?: number }; readonly end: { readonly offset?: number } };
|
|
648
|
-
type MarkdownNode = { readonly type: string; readonly position?: MarkdownPosition; readonly children?: readonly MarkdownNode[] };
|
|
731
|
+
type MarkdownNode = { readonly type: string; readonly depth?: number; readonly position?: MarkdownPosition; readonly children?: readonly MarkdownNode[] };
|
|
649
732
|
type MarkdownUnit = { readonly text: string; readonly start: number; readonly end: number };
|
|
650
733
|
|
|
651
734
|
/** 비교 가능한 CommonMark 단위와 그 원문 범위. 코드 펜스는 원문에 남기되 비교 후보에서는 제외한다. */
|
|
@@ -829,6 +912,18 @@ function isTableHeader(line: string, next: string | undefined): boolean {
|
|
|
829
912
|
return /^\s*\|(\s*:?-{2,}:?\s*\|)+\s*$/.test(next ?? '');
|
|
830
913
|
}
|
|
831
914
|
|
|
915
|
+
function topLevelCodeLines(goal: string): ReadonlySet<number> {
|
|
916
|
+
const lines = new Set<number>();
|
|
917
|
+
try {
|
|
918
|
+
const tree = unified().use(remarkParse).use(remarkGfm).parse(goal);
|
|
919
|
+
for (const node of tree.children) {
|
|
920
|
+
if (node.type !== 'code' || !node.position) continue;
|
|
921
|
+
for (let index = node.position.start.line - 1; index < node.position.end.line; index += 1) lines.add(index);
|
|
922
|
+
}
|
|
923
|
+
} catch { /* unknown syntax: keep existing extraction behavior */ }
|
|
924
|
+
return lines;
|
|
925
|
+
}
|
|
926
|
+
|
|
832
927
|
/** 골에서 **추출된 것만** 걷어낸 나머지(목표 서술). 추출 내용이 목표 블록에 중복되지 않게 한다.
|
|
833
928
|
*
|
|
834
929
|
* ⚠️ **산문은 남긴다**(리뷰 must-fix) — 초판은 인식된 절을 만나면 다음 헤더까지 **통째로** 버려,
|
|
@@ -839,7 +934,9 @@ export function stripExtractedSections(goal: string): string {
|
|
|
839
934
|
const mined = extractIntentBlocks(goal);
|
|
840
935
|
const out: string[] = [];
|
|
841
936
|
let extractedSection: 'acceptance' | 'boundary' | null = null;
|
|
842
|
-
|
|
937
|
+
const fencedLines = topLevelCodeLines(goal);
|
|
938
|
+
for (const [index, line] of goal.split('\n').entries()) {
|
|
939
|
+
if (fencedLines.has(index)) { out.push(line); continue; }
|
|
843
940
|
const kind = headKind(line);
|
|
844
941
|
if (kind === 'acceptance' || kind === 'boundary') { extractedSection = kind; continue; } // 헤더만 제거
|
|
845
942
|
if (kind === 'other') extractedSection = null;
|
|
@@ -921,6 +1018,7 @@ function isUnverifiedBoundaryCandidate(item: string): boolean {
|
|
|
921
1018
|
}
|
|
922
1019
|
|
|
923
1020
|
export function extractIntentBlocks(goal: string, includeSections = false): ExtractedIntentBlocks {
|
|
1021
|
+
const fencedLines = topLevelCodeLines(goal);
|
|
924
1022
|
const acceptanceItems: string[] = [];
|
|
925
1023
|
const scopeBoundaryItems: string[] = [];
|
|
926
1024
|
const unverifiedBoundaryCandidateItems: string[] = [];
|
|
@@ -945,6 +1043,7 @@ export function extractIntentBlocks(goal: string, includeSections = false): Extr
|
|
|
945
1043
|
push();
|
|
946
1044
|
}
|
|
947
1045
|
for (const [idx, line] of lines.entries()) {
|
|
1046
|
+
if (fencedLines.has(idx)) continue;
|
|
948
1047
|
const kind = headKind(line);
|
|
949
1048
|
if (kind === 'acceptance') { cur = 'acceptance'; continue; }
|
|
950
1049
|
if (kind === 'boundary') { cur = 'boundary'; continue; }
|
|
@@ -16,8 +16,9 @@ import { collectMergeIntent, collectSiblingPrIntents, defaultIntentGit, type Int
|
|
|
16
16
|
|
|
17
17
|
function deterministicNextMd(git: MergeGitSeam, worktreePath: string, file: string): string | null {
|
|
18
18
|
try {
|
|
19
|
+
// stage 1 = base, stage 2 = ours (the checked-out run), stage 3 = theirs (the merged-in main) —
|
|
20
|
+
// the resolver's contract is (base, ours appends only, theirs may drop released lines on dev-bump).
|
|
19
21
|
const resolved = resolveNextMdConflict(git.readIndexStage(worktreePath, 1, file), git.readIndexStage(worktreePath, 2, file), git.readIndexStage(worktreePath, 3, file));
|
|
20
|
-
void import('../../debug/log.js').then(({ debug }) => debug.log('self-dev.merge', 'next-md-deterministic', { resolved: resolved !== null })).catch(() => {});
|
|
21
22
|
return resolved;
|
|
22
23
|
} catch {
|
|
23
24
|
return null; // a stage is missing (added/deleted on one side) — the usual resolver decides
|
|
@@ -58,9 +59,9 @@ export type LlmMergeErrorStep = 'fetch' | 'merge' | 'conflicted-files' | 'commit
|
|
|
58
59
|
/** git stderr 첫 줄을 관측에 실을 때 쓰는 길이 상한. 구현이 정한다. */
|
|
59
60
|
export const GIT_ERROR_DETAIL_MAX_CHARS = 240;
|
|
60
61
|
|
|
61
|
-
/** merge 결과. llm-resolved=충돌을 LLM 이 종합 해결·커밋. conflict-unresolved=LLM 도 못 풀어 abort(base 유지). */
|
|
62
|
+
/** merge 결과. llm-resolved=충돌을 LLM 이 종합 해결·커밋. deterministic-resolved=release/next.md 만 결정적 해결기로 커밋(LLM 0). conflict-unresolved=LLM 도 못 풀어 abort(base 유지). */
|
|
62
63
|
export interface LlmMergeOutcome {
|
|
63
|
-
status: 'merged' | 'up-to-date' | 'llm-resolved' | 'conflict-unresolved' | 'error';
|
|
64
|
+
status: 'merged' | 'up-to-date' | 'llm-resolved' | 'deterministic-resolved' | 'conflict-unresolved' | 'error';
|
|
64
65
|
resolvedFiles?: string[];
|
|
65
66
|
sizeChange?: LlmMergeSizeChange;
|
|
66
67
|
testDeclarationLoss?: Array<{ file: string; ours: number; theirs: number; merged: number }>;
|
|
@@ -118,7 +119,9 @@ function addSizeChange(size: LlmMergeSizeChange, file: string, before: string, a
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
export function formatLlmMergeOutcome(outcome: LlmMergeOutcome): string {
|
|
121
|
-
const files = outcome.resolvedFiles?.length
|
|
122
|
+
const files = outcome.resolvedFiles?.length
|
|
123
|
+
? ` (${outcome.status === 'deterministic-resolved' ? '결정적 해결' : 'LLM 종합'} ${outcome.resolvedFiles.length}파일: ${outcome.resolvedFiles.join(', ')})`
|
|
124
|
+
: '';
|
|
122
125
|
if (outcome.status === 'conflict-unresolved') {
|
|
123
126
|
// ⛔ reason·failedFile 은 «선택» 칸이다 — 공급자 오류·시험 선언 유실·크기 붕괴 출구는 계약상 reason 이 없다.
|
|
124
127
|
// 있는 칸만 싣고, 그 출구들은 자기 실제 결과(어느 판정이 멈췄나)를 싣는다 — 「사유 undefined」 금지.
|
|
@@ -133,7 +136,7 @@ export function formatLlmMergeOutcome(outcome: LlmMergeOutcome): string {
|
|
|
133
136
|
];
|
|
134
137
|
return `${outcome.status}${files}${parts.length ? `; ${parts.join(' · ')}` : ''}`;
|
|
135
138
|
}
|
|
136
|
-
if (outcome.status !== 'llm-resolved') return `${outcome.status}${files}`;
|
|
139
|
+
if (outcome.status !== 'llm-resolved' && outcome.status !== 'deterministic-resolved') return `${outcome.status}${files}`;
|
|
137
140
|
const size = outcome.sizeChange;
|
|
138
141
|
if (size === undefined) return `${outcome.status}${files}; 규모 변화: 못 쟀다`;
|
|
139
142
|
const delta = size.totalDeltaLines >= 0 ? `+${size.totalDeltaLines}` : `${size.totalDeltaLines}`;
|
|
@@ -233,6 +236,8 @@ export async function mergeMainWithLlmResolve(
|
|
|
233
236
|
const resolvedFiles: string[] = [];
|
|
234
237
|
const sizeChange: LlmMergeSizeChange = { files: [], totalBeforeLines: 0, totalAfterLines: 0, totalDeltaLines: 0 };
|
|
235
238
|
const testDeclarationUnmeasured: string[] = [];
|
|
239
|
+
let deterministicResolved = 0;
|
|
240
|
+
let llmResolved = 0;
|
|
236
241
|
const measuredOutcome = <T extends object>(outcome: T): T & Pick<LlmMergeOutcome, 'testDeclarationUnmeasured'> => ({
|
|
237
242
|
...outcome,
|
|
238
243
|
...(testDeclarationUnmeasured.length ? { testDeclarationUnmeasured } : {}),
|
|
@@ -245,6 +250,7 @@ export async function mergeMainWithLlmResolve(
|
|
|
245
250
|
const abs = join(worktreePath, f);
|
|
246
251
|
let conflicted: string;
|
|
247
252
|
let merged: string;
|
|
253
|
+
let resolvedDeterministically = false;
|
|
248
254
|
try {
|
|
249
255
|
conflicted = git.readFile(abs);
|
|
250
256
|
} catch {
|
|
@@ -252,9 +258,15 @@ export async function mergeMainWithLlmResolve(
|
|
|
252
258
|
return unresolved({ status: 'conflict-unresolved', reason: 'conflict-file-unreadable', failedFile: f, resolvedFiles });
|
|
253
259
|
}
|
|
254
260
|
try {
|
|
255
|
-
// release/next.md: concurrent landings each append a line — keep both
|
|
261
|
+
// release/next.md: concurrent landings each append a line — keep both before the LLM sees the file.
|
|
256
262
|
const deterministic = f === NEXT_MD_PATH ? deterministicNextMd(git, worktreePath, f) : null;
|
|
257
|
-
|
|
263
|
+
if (deterministic !== null) {
|
|
264
|
+
merged = deterministic;
|
|
265
|
+
resolvedDeterministically = true;
|
|
266
|
+
debug.log('self-implement.main-sync', 'next-md-resolved', { deterministic: true });
|
|
267
|
+
} else {
|
|
268
|
+
merged = await resolve(f, conflicted);
|
|
269
|
+
}
|
|
258
270
|
} catch (error) {
|
|
259
271
|
git.abort(worktreePath); // LLM 예외 → base 유지
|
|
260
272
|
return unresolved({ status: 'conflict-unresolved', resolvedFiles, failedFile: f,
|
|
@@ -299,11 +311,13 @@ export async function mergeMainWithLlmResolve(
|
|
|
299
311
|
git.writeFile(abs, merged);
|
|
300
312
|
git.add(worktreePath, f);
|
|
301
313
|
resolvedFiles.push(f);
|
|
314
|
+
if (resolvedDeterministically) deterministicResolved += 1;
|
|
315
|
+
else llmResolved += 1;
|
|
302
316
|
}
|
|
303
317
|
const committed = seamOk(git.commit(worktreePath));
|
|
304
318
|
if (!committed.ok) { git.abort(worktreePath); return measuredOutcome(errorOutcome('commit', committed.errorDetail, resolvedFiles)); }
|
|
305
319
|
return measuredOutcome({
|
|
306
|
-
status: 'llm-resolved',
|
|
320
|
+
status: llmResolved === 0 && deterministicResolved > 0 ? 'deterministic-resolved' : 'llm-resolved',
|
|
307
321
|
resolvedFiles,
|
|
308
322
|
sizeChange,
|
|
309
323
|
});
|