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
|
@@ -16,6 +16,7 @@ import { createGitHubIssueCommentFetchStatus, lintDocLinks, lintGitHubIssueComme
|
|
|
16
16
|
import { proposeWikiClaimsFromHandoff, type Claim } from '../src/autopilot/discovery/wiki-claim-proposer.js';
|
|
17
17
|
import { runNightlyDocOpsCycle, assertLoopbackModelUrl } from '../src/autopilot/discovery/nightly-docops-runner.js';
|
|
18
18
|
import { assessDocsStaleness, defaultStalenessRevisions } from '../src/autopilot/discovery/doc-staleness.js';
|
|
19
|
+
import { defaultManualFiles, scanDocRot } from './docs/doc-rot.js';
|
|
19
20
|
import { debug } from '../src/debug/log.js';
|
|
20
21
|
import { registerStandaloneLogSink } from '../src/domains/standalone-log-sink.js';
|
|
21
22
|
import {
|
|
@@ -51,13 +52,27 @@ const githubHeaders: Record<string, string> = { Accept: 'application/vnd.github+
|
|
|
51
52
|
if (process.env.GITHUB_TOKEN) githubHeaders.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
52
53
|
const issueCommentFetchStatus = createGitHubIssueCommentFetchStatus(fetch, githubHeaders);
|
|
53
54
|
|
|
54
|
-
export
|
|
55
|
+
export type DocRotStageResult =
|
|
56
|
+
| { status: 'measured'; totals: ReturnType<typeof scanDocRot>['totals']; staleFiles: Array<{
|
|
57
|
+
file: string;
|
|
58
|
+
missingPaths: ReturnType<typeof scanDocRot>['files'][number]['missingPaths'];
|
|
59
|
+
badCommands: ReturnType<typeof scanDocRot>['files'][number]['commands'];
|
|
60
|
+
}> }
|
|
61
|
+
| { status: 'failed'; error: string };
|
|
62
|
+
|
|
63
|
+
export function formatNightlyDocOpsCompletion(
|
|
64
|
+
metrics: Awaited<ReturnType<typeof runNightlyDocOpsCycle>>,
|
|
65
|
+
docRot?: DocRotStageResult,
|
|
66
|
+
): string {
|
|
55
67
|
const stalenessLine = metrics.staleness?.status === 'measured'
|
|
56
68
|
? `늙음 검사 ${metrics.staleness.checked}·사라진 식별자 ${metrics.staleness.byAxis.removedIdentifiers}·깨진 링크 ${metrics.staleness.byAxis.brokenLinks}·superseded ${metrics.staleness.byAxis.supersededMarked}·staleScore ${metrics.staleness.byAxis.staleScoreOverThreshold}·문서목록 ${metrics.staleness.removedIdentifierDocuments.length}${metrics.staleness.removedIdentifierDocumentsTruncated ? '+' : ''}`
|
|
57
69
|
: metrics.staleness?.status === 'failed'
|
|
58
70
|
? `늙음 측정 실패(${metrics.staleness.error})`
|
|
59
71
|
: '늙음 측정 미지정';
|
|
60
|
-
|
|
72
|
+
const docRotLine = docRot?.status === 'measured'
|
|
73
|
+
? `·doc-rot 낡은 파일 ${docRot.totals.staleFiles}·없는 경로 ${docRot.totals.missingPaths}·깨진 명령 ${docRot.totals.badCommands}·못 잰 명령 ${docRot.totals.unmeasured}`
|
|
74
|
+
: docRot?.status === 'failed' ? `·doc-rot 측정 실패(${docRot.error})` : '';
|
|
75
|
+
return `[nightly-docops] 완료 — 처리 ${metrics.processed}·후보 ${metrics.candidates}·제안 ${metrics.proposals}·억제 ${metrics.suppressed}·에러 ${metrics.errors}·${stalenessLine}${docRotLine}·${metrics.durationMs}ms → ${outDir} (HITL 승인 대기)`;
|
|
61
76
|
}
|
|
62
77
|
|
|
63
78
|
/**
|
|
@@ -102,6 +117,76 @@ export function stalenessEventName(staleness: { status: string } | undefined): s
|
|
|
102
117
|
return staleness.status === 'failed' ? 'staleness-failed' : 'staleness-measured';
|
|
103
118
|
}
|
|
104
119
|
|
|
120
|
+
export function buildDocRotStage(
|
|
121
|
+
repoRoot: string,
|
|
122
|
+
deps: { scan?: typeof scanDocRot; files?: () => string[] } = {},
|
|
123
|
+
): () => DocRotStageResult {
|
|
124
|
+
const scan = deps.scan ?? scanDocRot;
|
|
125
|
+
const files = deps.files ?? (() => defaultManualFiles(repoRoot));
|
|
126
|
+
return () => {
|
|
127
|
+
try {
|
|
128
|
+
const report = scan({ repoRoot, files: files() });
|
|
129
|
+
return {
|
|
130
|
+
status: 'measured',
|
|
131
|
+
totals: report.totals,
|
|
132
|
+
staleFiles: report.files.flatMap((entry) => {
|
|
133
|
+
const badCommands = entry.commands.filter((finding) =>
|
|
134
|
+
finding.kind === 'unknown-command' || finding.kind === 'unknown-subcommand' || finding.kind === 'unknown-flag');
|
|
135
|
+
return entry.missingPaths.length || badCommands.length
|
|
136
|
+
? [{ file: entry.file, missingPaths: entry.missingPaths, badCommands }]
|
|
137
|
+
: [];
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
} catch (error) {
|
|
141
|
+
return { status: 'failed', error: error instanceof Error ? error.message : String(error) };
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface DocRotRecordDeps {
|
|
147
|
+
outDir: string;
|
|
148
|
+
nowDate: string;
|
|
149
|
+
mkdir?: (dir: string) => void;
|
|
150
|
+
write?: (path: string, body: string) => void;
|
|
151
|
+
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* doc-rot 단계 결과를 ⑴ `doc-rot-<날짜>.json` 보고서 ⑵ `docs.rot` 관측 이벤트로 남긴다.
|
|
156
|
+
* 보고서·관측 어느 쪽이 실패해도 던지지 않는다 — 야간 사이클의 종료 코드를 바꾸지 않는다.
|
|
157
|
+
*/
|
|
158
|
+
export function recordDocRotStage(
|
|
159
|
+
docRot: DocRotStageResult,
|
|
160
|
+
deps: DocRotRecordDeps,
|
|
161
|
+
): { reportPath: string | null; writeError: string | null } {
|
|
162
|
+
const mkdir = deps.mkdir ?? ((dir: string) => { mkdirSync(dir, { recursive: true }); });
|
|
163
|
+
const write = deps.write ?? ((path: string, body: string) => { writeFileSync(path, body); });
|
|
164
|
+
const log = deps.log ?? ((category: string, event: string, data: Record<string, unknown>) => { debug.log(category, event, data); });
|
|
165
|
+
const reportPath = join(deps.outDir, `doc-rot-${deps.nowDate}.json`);
|
|
166
|
+
let writeError: string | null = null;
|
|
167
|
+
try {
|
|
168
|
+
mkdir(deps.outDir);
|
|
169
|
+
write(reportPath, JSON.stringify(docRot, null, 2));
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// 보고서 파일을 못 써도 측정 결과는 버리지 않는다 — 원인은 관측 이벤트에 따로 싣는다.
|
|
172
|
+
writeError = error instanceof Error ? error.message : String(error);
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const totals = docRot.status === 'measured' ? docRot.totals : null;
|
|
176
|
+
log('docs.rot', docRot.status === 'measured' ? 'nightly-scanned' : 'nightly-failed', {
|
|
177
|
+
files: totals?.files ?? null,
|
|
178
|
+
staleFiles: totals?.staleFiles ?? null,
|
|
179
|
+
missingPaths: totals?.missingPaths ?? null,
|
|
180
|
+
badCommands: totals?.badCommands ?? null,
|
|
181
|
+
unmeasured: totals?.unmeasured ?? null,
|
|
182
|
+
error: docRot.status === 'failed' ? docRot.error : null,
|
|
183
|
+
reportPath: writeError ? null : reportPath,
|
|
184
|
+
writeError,
|
|
185
|
+
});
|
|
186
|
+
} catch { /* 관측 실패가 야간 사이클의 종료 코드를 바꾸지 않는다 */ }
|
|
187
|
+
return { reportPath: writeError ? null : reportPath, writeError };
|
|
188
|
+
}
|
|
189
|
+
|
|
105
190
|
if (import.meta.main) {
|
|
106
191
|
await registerStandaloneLogSink('scheduler');
|
|
107
192
|
mkdirSync(ckDir, { recursive: true });
|
|
@@ -156,7 +241,9 @@ const metrics = await runNightlyDocOpsCycle({
|
|
|
156
241
|
},
|
|
157
242
|
}, { batchLimit: 15, maxRetryPerItem: 1 });
|
|
158
243
|
|
|
159
|
-
|
|
244
|
+
const docRot = buildDocRotStage(repoRoot)();
|
|
245
|
+
recordDocRotStage(docRot, { outDir, nowDate });
|
|
246
|
+
console.log(formatNightlyDocOpsCompletion(metrics, docRot));
|
|
160
247
|
}
|
|
161
248
|
|
|
162
249
|
// ── arc2 되살리기 · 의미 supersede 계층 (gemma-4 · 제목/토픽 클러스터 bounded · 미션 668871) ──
|
|
@@ -20,6 +20,7 @@ import { runPodCommand, parsePodCpu, resolvePodCpu, type RunPodCommandOptions, t
|
|
|
20
20
|
import { POD_BUN_CACHE_HOST_PATH, parseInstallSeconds, podBunCacheVolume } from '../../src/task-orchestrator/surfaces/pod-bun-cache.js';
|
|
21
21
|
import { PodPoolScheduler, parsePodPool, checkPodPool } from '../../src/task-orchestrator/surfaces/pod-pool.js';
|
|
22
22
|
import { POD_INSTALL_SLOTS_DEFAULT, POD_INSTALL_SLOTS_HOST_PATH, installSlotScript } from '../../src/task-orchestrator/surfaces/pod-install-slots.js';
|
|
23
|
+
import { gateDepsInstallScript, parseGateDeps } from '../../src/task-orchestrator/surfaces/pod-gate-deps.js';
|
|
23
24
|
import { gateShardsPath, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
24
25
|
import { defaultKubectl } from '../../src/task-orchestrator/surfaces/self-implement-pod.js';
|
|
25
26
|
|
|
@@ -253,7 +254,7 @@ export function shardParts(paths: readonly string[], seconds: (file: string) =>
|
|
|
253
254
|
* leaving `install.log`/`install.rc`, `part-<i>.log`/`.rc`/`.junit.xml`, and `shard.timeout` (the part index) when the
|
|
254
255
|
* deadline cut the shard. A part without `.rc` did not finish. The shell itself always exits 0 (as before).
|
|
255
256
|
*/
|
|
256
|
-
export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number }): string {
|
|
257
|
+
export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number; depsDir?: string }): string {
|
|
257
258
|
const run = o.parts.map((part, index) => {
|
|
258
259
|
const ignores = o.cdpPatterns.filter((pattern) => part.includes(pattern)).flatMap((pattern) => ['--path-ignore-patterns', pattern]);
|
|
259
260
|
return `run_part ${index} ${['bun', 'run', 'test:deterministic', ...ignores, ...part.map(asPath)].map(quote).join(' ')}`;
|
|
@@ -276,9 +277,8 @@ export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPa
|
|
|
276
277
|
' echo "$prc" > "$O/part-$i.rc"',
|
|
277
278
|
'}',
|
|
278
279
|
'if cd .. && cd repo; then',
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
...(o.installSlots > 0 ? [' install_slot_release'] : []),
|
|
280
|
+
// GATE-IMAGE-DEPS: link the image's baked node_modules when the lockfiles match; only a miss installs (behind a slot).
|
|
281
|
+
...gateDepsInstallScript({ log: '"$O/install.log"', installSlots: o.installSlots, ...(o.depsDir ? { depsDir: o.depsDir } : {}) }).split('\n').map((line) => ` ${line}`),
|
|
282
282
|
' echo "$irc" > "$O/install.rc"',
|
|
283
283
|
` if [ "$irc" -eq 0 ]; then ${run || 'true'}; fi`,
|
|
284
284
|
'else echo 5 > "$O/install.rc"; fi',
|
|
@@ -800,7 +800,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
800
800
|
}
|
|
801
801
|
const installSeconds = parseInstallSeconds(output ?? '');
|
|
802
802
|
// GATE-TIMEOUT-HEAL ③: a cut shard is «reason: timeout» (with the files that still finished), not a bare rc=null.
|
|
803
|
-
if (!reused && !descent) debug.log('release-loop.gate', 'pod-shard', { shard, files: paths, durationMs, rc: rc ?? null, attempt: depth + 1, installSeconds, deadlineSeconds: shardDeadline, parts: parts.length,
|
|
803
|
+
if (!reused && !descent) debug.log('release-loop.gate', 'pod-shard', { shard, files: paths, durationMs, rc: rc ?? null, attempt: depth + 1, installSeconds, gateDeps: parseGateDeps(output ?? ''), deadlineSeconds: shardDeadline, parts: parts.length,
|
|
804
804
|
...(timedOut ? { reason: 'timeout', finishedFiles: finished.length } : {}) });
|
|
805
805
|
if (!reused && !descent) markShard(shard, { ...(installSeconds !== null ? { installSec: installSeconds } : {}), ...(rc !== undefined ? { rc } : {}), ...(timedOut ? { state: 'timeout' as const } : {}) });
|
|
806
806
|
let clean = output?.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
|
|
@@ -1,15 +1,60 @@
|
|
|
1
|
-
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { debug } from '../../src/debug/log.js';
|
|
4
4
|
|
|
5
5
|
/** Plan weights for a Pod sweep: wall-scaled when the previous cut recorded shard wall times, junit seconds otherwise. */
|
|
6
|
-
export function planDurations(durationSource: string | undefined): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number } } {
|
|
6
|
+
export function planDurations(durationSource: string | undefined): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number }; fallback?: string } {
|
|
7
7
|
if (!durationSource) return { durations: new Map() };
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const primary = planDurationsFrom(durationSource);
|
|
9
|
+
if (primary.durations.size) return primary;
|
|
10
|
+
// GATE-PLAN-TIMINGS: the baseline cut left no reports (0.2.20: baseline 0.2.19 was gated from another universe, so
|
|
11
|
+
// all 5,585 files were «unknown», planned 3.9 min, measured 13–20 min). Use the most recent sibling cut instead.
|
|
12
|
+
const fallback = latestSiblingCutDir(durationSource);
|
|
13
|
+
if (!fallback) {
|
|
14
|
+
debug.log('release-loop.gate', 'plan-duration-fallback', { source: durationSource, fallback: null });
|
|
15
|
+
return primary;
|
|
16
|
+
}
|
|
17
|
+
const result = planDurationsFrom(fallback);
|
|
18
|
+
debug.log('release-loop.gate', 'plan-duration-fallback', { source: durationSource, fallback, files: result.durations.size, wall: !!result.wall });
|
|
19
|
+
return result.durations.size ? { ...result, fallback } : primary;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function planDurationsFrom(dir: string): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number } } {
|
|
23
|
+
const junit = readFileDurations(dir);
|
|
24
|
+
const wall = readFileWallWeights(dir, junit);
|
|
10
25
|
return wall ? { durations: wall.weights, wall: { shards: wall.shards, scaledFiles: wall.scaledFiles } } : { durations: junit };
|
|
11
26
|
}
|
|
12
27
|
|
|
28
|
+
/**
|
|
29
|
+
* For a `<root>/<version>/<a>/<b>` duration source (the gate passes `<ledger>/release/<baseline>/gate-logs/cut`), the
|
|
30
|
+
* sibling `<root>/<other>/<a>/<b>` directory whose newest `*.junit.xml` is the most recent — «the latest gate». The
|
|
31
|
+
* source itself is skipped. Undefined when the path is too shallow or no sibling holds a junit report.
|
|
32
|
+
*/
|
|
33
|
+
export function latestSiblingCutDir(durationSource: string): string | undefined {
|
|
34
|
+
const source = resolve(durationSource);
|
|
35
|
+
const b = basename(source);
|
|
36
|
+
const a = basename(dirname(source));
|
|
37
|
+
const root = dirname(dirname(dirname(source)));
|
|
38
|
+
if (!a || !b || root === dirname(dirname(source))) return undefined;
|
|
39
|
+
let versions: string[];
|
|
40
|
+
try { versions = readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name); }
|
|
41
|
+
catch { return undefined; }
|
|
42
|
+
let best: { dir: string; mtimeMs: number } | undefined;
|
|
43
|
+
for (const version of versions.sort()) {
|
|
44
|
+
const dir = join(root, version, a, b);
|
|
45
|
+
if (dir === source) continue;
|
|
46
|
+
let newest = -1;
|
|
47
|
+
try {
|
|
48
|
+
for (const name of readdirSync(dir)) {
|
|
49
|
+
if (!name.endsWith('.junit.xml')) continue;
|
|
50
|
+
try { newest = Math.max(newest, statSync(join(dir, name)).mtimeMs); } catch { /* vanished mid-scan */ }
|
|
51
|
+
}
|
|
52
|
+
} catch { continue; }
|
|
53
|
+
if (newest >= 0 && (!best || newest > best.mtimeMs)) best = { dir, mtimeMs: newest };
|
|
54
|
+
}
|
|
55
|
+
return best?.dir;
|
|
56
|
+
}
|
|
57
|
+
|
|
13
58
|
/** Observation for GATE-PLAN-WALLTIME, emitted once the shards are planned so `maxPlannedMin` is the heaviest shard. */
|
|
14
59
|
export function logPlanWalltime(wall: { shards: number; scaledFiles: number } | undefined, shards: ReadonlyArray<{ plannedSeconds: number }>): void {
|
|
15
60
|
if (!wall) return;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { searchFirecrawl } from '../skills/omni-crawl/src/firecrawl.js';
|
|
3
|
+
|
|
4
|
+
type Check = { identifier: string; query: string; inspectedLead: { url: string } | null };
|
|
5
|
+
type Search = (query: string, options: { limit: number }) => Promise<{ items: Array<{ url?: string }> }>;
|
|
6
|
+
|
|
7
|
+
export async function recheckCooAdminLeads(checks: Check[], search: Search): Promise<string[]> {
|
|
8
|
+
let verified = 0;
|
|
9
|
+
let withUrl = 0;
|
|
10
|
+
let withoutUrl = 0;
|
|
11
|
+
const lines: string[] = [];
|
|
12
|
+
for (const check of checks) {
|
|
13
|
+
const result = await search(check.query, { limit: 3 });
|
|
14
|
+
const recordedUrl = check.inspectedLead?.url?.trim();
|
|
15
|
+
if (!recordedUrl) {
|
|
16
|
+
withoutUrl++;
|
|
17
|
+
lines.push(`${check.identifier} hits=${result.items.length} recordedUrl=none (not verified) query=${check.query}`);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
withUrl++;
|
|
21
|
+
const found = result.items.some(item => item.url === recordedUrl);
|
|
22
|
+
if (found) verified++;
|
|
23
|
+
lines.push(`${check.identifier} hits=${result.items.length} recordedUrlVerified=${found} query=${check.query}`);
|
|
24
|
+
}
|
|
25
|
+
lines.push(`SEARCH checked=${checks.length} recordedUrlVerified=${verified}/${withUrl} noRecordedUrl=${withoutUrl} recordedUrlNotInCurrentTop3=${withUrl - verified} (search rankings change; no official date inferred)`);
|
|
26
|
+
return lines;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (import.meta.main) {
|
|
30
|
+
const evidence = JSON.parse(await readFile(new URL('../src/domains/coo-admin-dates.evidence.json', import.meta.url), 'utf8')) as {
|
|
31
|
+
verifiedIssues: Array<{ identifier: string }>;
|
|
32
|
+
research: { issueChecks: Check[] };
|
|
33
|
+
};
|
|
34
|
+
const checks = evidence.research.issueChecks;
|
|
35
|
+
if (checks.length !== 29 || checks.some((check, index) => check.identifier !== evidence.verifiedIssues[index]?.identifier || !check.query)) {
|
|
36
|
+
throw new Error('29 issue search queries do not match recorded issue identifiers');
|
|
37
|
+
}
|
|
38
|
+
for (const line of await recheckCooAdminLeads(checks, searchFirecrawl)) console.log(line);
|
|
39
|
+
}
|
package/scripts/rhythm/daily.ts
CHANGED
|
@@ -587,8 +587,9 @@ export async function main(args: string[] = process.argv.slice(2), deps: DailyDe
|
|
|
587
587
|
for (const arg of args) if (!['--dry-run', '--no-news', '--json'].includes(arg)) throw new Error(`알 수 없는 옵션: ${arg}`);
|
|
588
588
|
const result = await runDaily({ dryRun: args.includes('--dry-run'), noNews: args.includes('--no-news'), stage }, deps);
|
|
589
589
|
(deps.print ?? console.log)(args.includes('--json') ? JSON.stringify(result) : `${result.markdown}\n파일: ${result.file} · ${result.deliveryLine}`);
|
|
590
|
-
//
|
|
590
|
+
// 그래프 deliver 는 미발송도 출력·tick 에 기록한 뒤 실패로 종결한다.
|
|
591
591
|
if ((stage === 'compose' || !stage) && result.vaultFatal) throw new Error(`볼트 사본 실패 · ${result.vaultError}`);
|
|
592
|
+
if (stage === 'deliver' && result.deliveryState === 'send-disabled') throw new Error('발송 실패 · 발송 비활성');
|
|
592
593
|
if (stage === 'deliver' && result.sendError) throw new Error(`발송 실패 · ${result.sendError}`);
|
|
593
594
|
return result;
|
|
594
595
|
}
|
|
@@ -140,10 +140,15 @@ export function checkPublicSkills(root: string, boundary: SkillBoundaryReport =
|
|
|
140
140
|
const errors = [...boundary.errors];
|
|
141
141
|
const skills: PublicSkillRow[] = [];
|
|
142
142
|
const skillsDir = join(root, 'skills');
|
|
143
|
-
|
|
143
|
+
// Scope discrepancy: the stated 15 public deployments have no named fifteenth
|
|
144
|
+
// skill in this tree's boundary inventory (14 core, 5 addons). No verified
|
|
145
|
+
// deployment-name list is available here to justify adding a row. Never use
|
|
146
|
+
// an addon to fill the gap; keep the existing report shape and exit semantics.
|
|
147
|
+
// Unclassified folders retain their check rows and boundary errors.
|
|
148
|
+
const verdicts = new Map(boundary.skills.map((row) => [row.skill, row.verdict]));
|
|
144
149
|
const names = existsSync(skillsDir) ? readdirSync(skillsDir).filter((name) => {
|
|
145
150
|
const dir = join(skillsDir, name);
|
|
146
|
-
return lstatSync(dir).isDirectory() &&
|
|
151
|
+
return lstatSync(dir).isDirectory() && verdicts.get(name) !== 'addon';
|
|
147
152
|
}).sort() : [];
|
|
148
153
|
if (!existsSync(skillsDir)) errors.push('skills/ 디렉터리가 없다');
|
|
149
154
|
for (const row of boundary.skills) {
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
defaultGitMergeSeam, defaultLlmResolve, mergeMainWithLlmResolve,
|
|
9
9
|
type MergeGitSeam,
|
|
10
10
|
} from '../../src/autopilot/build/llm-conflict-merge.js';
|
|
11
|
-
import { NEXT_MD_PATH } from '../../src/release-loop/next-md-merge.js';
|
|
12
11
|
|
|
13
12
|
type Command = (cwd: string, program: 'git' | 'gh', args: readonly string[]) => { status: number; stdout: string; stderr: string };
|
|
14
13
|
export type ShadowOutcome = 'clean' | 'resolved-deterministic' | 'resolved-llm' | 'unresolved' | 'unmeasured';
|
|
@@ -108,9 +107,12 @@ export async function runResyncShadow(options: ShadowOptions): Promise<ShadowRow
|
|
|
108
107
|
const result = await mergeMainWithLlmResolve(temp, 'origin/main',
|
|
109
108
|
options.resolve ?? ((file, conflicted) => defaultLlmResolve(file, conflicted, 'origin/main', { worktreePath: temp })), observedGit);
|
|
110
109
|
if (result.status === 'merged' || result.status === 'up-to-date') outcome = 'clean';
|
|
111
|
-
else if (result.status === '
|
|
110
|
+
else if (result.status === 'deterministic-resolved') {
|
|
112
111
|
files = result.resolvedFiles ?? files;
|
|
113
|
-
outcome =
|
|
112
|
+
outcome = 'resolved-deterministic';
|
|
113
|
+
} else if (result.status === 'llm-resolved') {
|
|
114
|
+
files = result.resolvedFiles ?? files;
|
|
115
|
+
outcome = 'resolved-llm';
|
|
114
116
|
} else if (result.status === 'conflict-unresolved') outcome = 'unresolved';
|
|
115
117
|
// A git error is a measurement failure, not evidence of an unresolvable conflict.
|
|
116
118
|
} catch {
|
package/scripts/test-diet/lib.ts
CHANGED
|
@@ -1,8 +1,88 @@
|
|
|
1
1
|
// TD2 — a daily look at the test suite, one cost-weighted slice at a time (shadow: it measures and drafts, it
|
|
2
2
|
// never deletes or moves a test). Design: 내부 문서 `TD1-v2-gate-content-review-2026-10-01`.
|
|
3
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
|
|
6
|
+
/** These were reported as preexisting in the recent gate/harvest; remeasurement, not this list, decides today's count. */
|
|
7
|
+
export const DEFAULT_MAIN_FAILURE_FILES = [
|
|
8
|
+
'src/task-orchestrator/surfaces/pod-pool-cli.test.ts',
|
|
9
|
+
'src/self-dev/dev-cli.test.ts',
|
|
10
|
+
'src/self-dev/dev-pipeline.test.ts',
|
|
11
|
+
'src/agent-mission/agent-backend-flag-smoke.test.ts',
|
|
12
|
+
'scripts/release-story/draft.test.ts',
|
|
13
|
+
'scripts/release-loop/freeze-off-parity.test.ts',
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
export type MainFailureClass = '시험이 낡음' | '코드 결함' | '환경·부하 의존' | '외부 의존';
|
|
17
|
+
export interface MainFailureResult { file: string; rc: number | null; stdout: string; stderr: string; timedOut?: boolean }
|
|
18
|
+
export interface MainFailureRow { file: string; failures: number; firstError: string; classification: MainFailureClass; draft: '고침' | '격리' }
|
|
19
|
+
export interface MainFailureDay { date: string; at: string; owner: 'TC'; mode: 'shadow'; commit: string; selected: string[]; rows: MainFailureRow[]; unmeasured: { file: string; reason: string }[]; failingFiles: number; previousFailingFiles: number | null; delta: number | null }
|
|
20
|
+
|
|
21
|
+
export function mainFailureLedgerPath(root: string, date: string): string { return join(root, 'test-diet', 'main-failures', `${date}.json`); }
|
|
22
|
+
export function kstDay(at: Date): string { return new Date(at.getTime() + 9 * 3600_000).toISOString().slice(0, 10); }
|
|
23
|
+
|
|
24
|
+
export function mainFailureFiles(value: unknown): string[] {
|
|
25
|
+
const files = value === undefined ? [...DEFAULT_MAIN_FAILURE_FILES] : value;
|
|
26
|
+
if (!Array.isArray(files) || files.length === 0 || !files.every((file) => typeof file === 'string' && /^(?:src|scripts|test)\/[A-Za-z0-9_./-]+\.test\.tsx?$/.test(file) && !file.split('/').includes('..'))) {
|
|
27
|
+
throw new Error('main failure files must be nonempty repository-relative test paths');
|
|
28
|
+
}
|
|
29
|
+
return [...new Set(files as string[])];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A heuristic draft, never a finding about the root cause or permission to skip a test. */
|
|
33
|
+
export function mainFailureRow(result: MainFailureResult): MainFailureRow | null {
|
|
34
|
+
const text = `${result.stdout}\n${result.stderr}`.replace(/\x1b\[[0-9;]*m/g, '');
|
|
35
|
+
const count = [...text.matchAll(/^\s*(\d+) fail\b/gm)].at(-1);
|
|
36
|
+
const failures = count ? Number(count[1]) : 0;
|
|
37
|
+
const ran = /Ran [1-9]\d* tests? across [1-9]\d* files?/m.test(text);
|
|
38
|
+
if (result.timedOut || !ran || !Number.isSafeInteger(failures) || (result.rc !== 0 && failures === 0)
|
|
39
|
+
|| (result.rc === 0 && failures > 0) || /^(?:\s*[1-9]\d* errors?\b|# Unhandled error between tests)/m.test(text)) {
|
|
40
|
+
throw new Error(`test not measured: ${result.file}: ${text.split('\n').map((line) => line.trim()).find((line) => /error:|Error:|timed out|timeout|Cannot find|not found|errors?\b/i.test(line)) ?? 'no completed test result'}`);
|
|
41
|
+
}
|
|
42
|
+
if (failures === 0 && result.rc === 0) return null;
|
|
43
|
+
const firstError = text.split('\n').map((line) => line.trim()).find((line) => /^(?:\(fail\)|error:|\w*Error:|Expected:|Received:|Cannot find|Unable to)/i.test(line))
|
|
44
|
+
?? `test exited ${result.rc} without a diagnostic`;
|
|
45
|
+
const classification: MainFailureClass = /timed out|timeout|load average|resource temporarily unavailable/i.test(firstError) ? '환경·부하 의존'
|
|
46
|
+
: /codex|--yolo|network|ECONN|API key|Unable to|Cannot find module|ENOENT/i.test(firstError) ? '외부 의존'
|
|
47
|
+
: /snapshot|next\.md|expected|Received|toEqual|toContain/i.test(firstError) ? '시험이 낡음' : '코드 결함';
|
|
48
|
+
return { file: result.file, failures, firstError: firstError.slice(0, 240), classification,
|
|
49
|
+
draft: classification === '환경·부하 의존' || classification === '외부 의존' ? '격리' : '고침' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One KST-day snapshot, replaced on remeasurement. Incomplete runs cannot masquerade as zero failures. */
|
|
53
|
+
export function writeMainFailureDay(root: string, selected: string[], results: MainFailureResult[], commit: string, at = new Date()): MainFailureDay {
|
|
54
|
+
if (results.length !== selected.length || results.some((r, i) => r.file !== selected[i])) throw new Error('incomplete main failure measurement');
|
|
55
|
+
const date = kstDay(at);
|
|
56
|
+
const dir = join(root, 'test-diet', 'main-failures');
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
const dates = earlierMainFailureDays(dir, date);
|
|
59
|
+
const previous = dates.at(-1);
|
|
60
|
+
const previousDay = previous ? JSON.parse(readFileSync(join(dir, previous), 'utf8')) as MainFailureDay : null;
|
|
61
|
+
const rows: MainFailureRow[] = [];
|
|
62
|
+
const unmeasured: MainFailureDay['unmeasured'] = [];
|
|
63
|
+
for (const result of results) {
|
|
64
|
+
try {
|
|
65
|
+
const row = mainFailureRow(result);
|
|
66
|
+
if (row) rows.push(row);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// 못 잰 파일은 «실패»가 아니다 — 행으로 접으면 측정 실패가 main 결함 1건으로 둔갑한다.
|
|
69
|
+
unmeasured.push({ file: result.file, reason: (error instanceof Error ? error.message : String(error)).slice(0, 240) });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const previousFailingFiles = unmeasured.length === 0 && previousDay?.unmeasured?.length === 0
|
|
73
|
+
&& previousDay.selected.join('\0') === selected.join('\0') ? previousDay.failingFiles : null;
|
|
74
|
+
const line: MainFailureDay = { date, at: at.toISOString(), owner: 'TC', mode: 'shadow', commit, selected, rows, unmeasured, failingFiles: rows.length,
|
|
75
|
+
previousFailingFiles, delta: previousFailingFiles === null ? null : rows.length - previousFailingFiles };
|
|
76
|
+
const path = mainFailureLedgerPath(root, date);
|
|
77
|
+
writeFileSync(`${path}.${process.pid}.tmp`, JSON.stringify(line, null, 2) + '\n');
|
|
78
|
+
renameSync(`${path}.${process.pid}.tmp`, path);
|
|
79
|
+
return line;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function earlierMainFailureDays(dir: string, date: string): string[] {
|
|
83
|
+
return readdirSync(dir).filter((name) => /^\d{4}-\d{2}-\d{2}\.json$/.test(name) && name < `${date}.json`).sort();
|
|
84
|
+
}
|
|
85
|
+
|
|
6
86
|
export const DEFAULT_COST_SECS = 10;
|
|
7
87
|
export const SLOW_SECS = 60;
|
|
8
88
|
export const HEAVY_MB = 2048;
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
// bun scripts/test-diet/node.ts pick|measure|audit|record (test-diet or nightly-audit graph)
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { appendFileSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
7
8
|
import { join } from 'node:path';
|
|
8
9
|
import { debug } from '../../src/debug/log.js';
|
|
9
10
|
import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
10
11
|
import { CardStore } from '../../src/task-cards/card-store.js';
|
|
11
12
|
import { GATE_NIGHTLY_AUDITS } from '../release-loop/gate-node.js';
|
|
12
|
-
import {
|
|
13
|
+
import { isCredentialKey } from '../lib/deterministic-env.js';
|
|
14
|
+
import { appendLedger, costTable, judge, lastLedgerLine, ledgerPath, mainFailureFiles, nightlyAuditLedgerPath, pickRange, propose, td1Dispositions, writeCardDraft, writeMainFailureDay, type LedgerLine, type MainFailureResult, type Measurement, type Td1Disposition } from './lib.js';
|
|
13
15
|
import { fixedCountAssertions, flakeVerdict, sweepSlice, unreachableImports, type Mutation, type TestRun } from './effectiveness.js';
|
|
14
16
|
|
|
15
17
|
type Context = { graphId?: string; input: Record<string, unknown>; outputs: Record<string, Record<string, unknown> | null> };
|
|
@@ -235,6 +237,49 @@ export function record(ctx: Context, deps: { createStore?: (root: string) => Pic
|
|
|
235
237
|
return emit({ outcome: 'ok', summary: `test-diet ${line.range} · keep ${counts.keep} · review ${counts.review} · failing ${counts.failing}${card ? ' · card draft' : ''}`, range: line.range, ...counts, ...(card ? { card } : {}) });
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
export function mainFailures(ctx: Context, deps: { root?: string; checkout?: string; runFile?: (file: string, cwd: string) => MainFailureResult; now?: Date } = {}): number {
|
|
241
|
+
const selected = mainFailureFiles(ctx.input.files);
|
|
242
|
+
const root = deps.root ?? effectiveInstanceRoot();
|
|
243
|
+
const guarded = process.env.NODE_ENV === 'test' || !!process.env.ELANOUS_TEST_HOME;
|
|
244
|
+
const directory = deps.checkout || guarded ? undefined : mkdtempSync(join(tmpdir(), 'test-diet-main-'));
|
|
245
|
+
try {
|
|
246
|
+
let checkout = deps.checkout ?? directory ?? '';
|
|
247
|
+
let commit: string;
|
|
248
|
+
if (guarded) {
|
|
249
|
+
// No clone, install, test subprocess or harness dispatch in the test universe.
|
|
250
|
+
const at = deps.now ?? new Date();
|
|
251
|
+
const ledger = join(root, 'test-diet', 'main-failures', `${at.toISOString().slice(0, 10)}-guard.json`);
|
|
252
|
+
mkdirSync(join(root, 'test-diet', 'main-failures'), { recursive: true });
|
|
253
|
+
writeFileSync(ledger, JSON.stringify({ at: at.toISOString(), selected, measured: false, reason: 'test environment', owner: 'TC', mode: 'shadow' }) + '\n');
|
|
254
|
+
return emit({ outcome: 'ok', summary: 'main failures record only: test environment (not measured)', ledger, selected, measured: false });
|
|
255
|
+
} else if (deps.checkout) {
|
|
256
|
+
const head = spawnSync('git', ['rev-parse', 'HEAD'], { cwd: checkout, encoding: 'utf8' });
|
|
257
|
+
if (head.status !== 0) throw new Error(`main checkout unreadable: ${checkout}`);
|
|
258
|
+
commit = head.stdout.trim();
|
|
259
|
+
} else {
|
|
260
|
+
const source = process.cwd();
|
|
261
|
+
const clone = spawnSync('git', ['clone', '--quiet', '--shared', '--single-branch', '--branch', 'main', source, checkout], { encoding: 'utf8', timeout: 120_000 });
|
|
262
|
+
if (clone.status !== 0) return emit({ outcome: 'error', summary: `main checkout failed: ${clone.stderr || clone.error}` });
|
|
263
|
+
commit = spawnSync('git', ['rev-parse', 'HEAD'], { cwd: checkout, encoding: 'utf8' }).stdout.trim();
|
|
264
|
+
const install = spawnSync('bun', ['install', '--frozen-lockfile'], { cwd: checkout, encoding: 'utf8', timeout: 300_000, maxBuffer: 1024 * 1024 });
|
|
265
|
+
if (install.status !== 0) return emit({ outcome: 'error', summary: `main install failed: ${install.stderr || install.error}` });
|
|
266
|
+
}
|
|
267
|
+
const runFile = deps.runFile ?? ((file: string, cwd: string): MainFailureResult => {
|
|
268
|
+
if (!existsSync(join(cwd, file))) return { file, rc: null, stdout: '', stderr: 'test file not present on main' };
|
|
269
|
+
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !isCredentialKey(key)));
|
|
270
|
+
const child = spawnSync('bun', ['run', 'test:deterministic', file], {
|
|
271
|
+
cwd, encoding: 'utf8', timeout: 300_000, maxBuffer: 4 * 1024 * 1024,
|
|
272
|
+
env: { ...env, NODE_ENV: 'test', ELANOUS_STATE_DIR: join(root, 'test-diet', 'isolated-test-state') },
|
|
273
|
+
});
|
|
274
|
+
return { file, rc: child.status, stdout: child.stdout ?? '', stderr: child.stderr ?? String(child.error ?? ''), timedOut: (child.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT' };
|
|
275
|
+
});
|
|
276
|
+
const results = selected.map((file) => runFile(file, checkout));
|
|
277
|
+
const day = writeMainFailureDay(root, selected, results, commit, deps.now);
|
|
278
|
+
debug.log('test-diet.main-failures', 'recorded', { selected: selected.length, failingFiles: day.failingFiles, delta: day.delta, guarded });
|
|
279
|
+
return emit({ outcome: 'ok', summary: `main failures ${day.failingFiles}/${selected.length} · delta ${day.delta ?? 'n/a'} · shadow TC`, ledger: join(root, 'test-diet', 'main-failures', `${day.date}.json`), ...day });
|
|
280
|
+
} finally { if (directory) rmSync(directory, { recursive: true, force: true }); }
|
|
281
|
+
}
|
|
282
|
+
|
|
238
283
|
function status(root: string, options: { json?: boolean; days?: number } = {}): number {
|
|
239
284
|
const path = ledgerPath(root);
|
|
240
285
|
const ledger = existsSync(path) ? readFileSync(path, 'utf8') : '';
|
|
@@ -286,6 +331,7 @@ if (import.meta.main) {
|
|
|
286
331
|
const ctx = context();
|
|
287
332
|
const flags = process.argv.slice(3);
|
|
288
333
|
process.exitCode = step === 'pick' ? pick(ctx, flags.includes('--sweep')) : step === 'measure' ? measure(ctx, false, flags.includes('--effectiveness')) : step === 'audit' ? measure(ctx, true)
|
|
334
|
+
: step === 'main-failures' ? mainFailures(ctx)
|
|
289
335
|
: step === 'record' ? (ctx.graphId === 'nightly-audit' || Object.hasOwn(ctx.outputs, 'audit') ? recordNightlyAudit(ctx) : record(ctx)) : emit({ outcome: 'error', summary: `unknown step: ${step}` });
|
|
290
336
|
}
|
|
291
337
|
} catch (error) {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { fetchLinearProjectIssues, type LinearProjectIssue } from '../src/connectors/linear.js';
|
|
3
|
+
|
|
4
|
+
type RecordedIssue = {
|
|
5
|
+
identifier: string; title: string; url: string; createdAt: string; updatedAt: string;
|
|
6
|
+
existingDueDate: string | null; priority: number;
|
|
7
|
+
};
|
|
8
|
+
type Evidence = {
|
|
9
|
+
project: string;
|
|
10
|
+
verifiedIssues: RecordedIssue[];
|
|
11
|
+
cohort: { excludedCurrentIssues: Array<{identifier: string; url: string; dueDate: string | null; priority: number; createdAt: string}> };
|
|
12
|
+
};
|
|
13
|
+
type LiveIssue = LinearProjectIssue & { createdAt: string };
|
|
14
|
+
|
|
15
|
+
export function compareCooEvidence(record: Evidence, live: LiveIssue[], truncated: boolean): string[] {
|
|
16
|
+
const errors: string[] = [];
|
|
17
|
+
if (truncated) errors.push('Linear result truncated');
|
|
18
|
+
if (live.length !== 33) errors.push(`current open count: ${live.length} != 33`);
|
|
19
|
+
if (record.verifiedIssues.length !== 29) errors.push(`recorded count: ${record.verifiedIssues.length} != 29`);
|
|
20
|
+
const sorted = [...live].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
21
|
+
const selected = sorted.slice(0, 29);
|
|
22
|
+
const excluded = sorted.slice(29);
|
|
23
|
+
const actual = new Map(live.map(issue => [issue.identifier, issue]));
|
|
24
|
+
if (actual.size !== live.length) errors.push('duplicate Linear identifier');
|
|
25
|
+
const seen = new Set<string>();
|
|
26
|
+
for (const row of record.verifiedIssues) {
|
|
27
|
+
if (seen.has(row.identifier)) errors.push(`duplicate recorded identifier: ${row.identifier}`);
|
|
28
|
+
seen.add(row.identifier);
|
|
29
|
+
const issue = actual.get(row.identifier);
|
|
30
|
+
if (!issue) { errors.push(`not in Linear: ${row.identifier}`); continue; }
|
|
31
|
+
for (const [field, expected, value] of [
|
|
32
|
+
['title', row.title, issue.title], ['url', row.url, issue.url],
|
|
33
|
+
['createdAt', row.createdAt, issue.createdAt], ['updatedAt', row.updatedAt, issue.updatedAt],
|
|
34
|
+
['dueDate', row.existingDueDate, issue.dueDate], ['priority', row.priority, issue.priority],
|
|
35
|
+
] as const) if (expected !== value) errors.push(`${row.identifier} ${field}: recorded=${String(expected)} Linear=${String(value)}`);
|
|
36
|
+
}
|
|
37
|
+
const selectedIds = selected.map(issue => issue.identifier).sort().join(',');
|
|
38
|
+
if ([...seen].sort().join(',') !== selectedIds) errors.push('recorded identifiers differ from oldest 29 currently open by createdAt');
|
|
39
|
+
if (selected.filter(issue => issue.dueDate !== null).length !== 4) errors.push('Linear selected dueDate count != 4');
|
|
40
|
+
if (selected.filter(issue => issue.priority !== 0).length !== 7) errors.push('Linear selected priority count != 7');
|
|
41
|
+
const excludedRecorded = record.cohort.excludedCurrentIssues;
|
|
42
|
+
if (excludedRecorded.map(issue => issue.identifier).sort().join(',') !== excluded.map(issue => issue.identifier).sort().join(',')) errors.push('excluded identifiers differ from Linear');
|
|
43
|
+
for (const row of excludedRecorded) {
|
|
44
|
+
const issue = actual.get(row.identifier);
|
|
45
|
+
if (!issue) continue;
|
|
46
|
+
if (row.url !== issue.url || row.createdAt !== issue.createdAt || row.dueDate !== issue.dueDate || row.priority !== issue.priority) errors.push(`excluded ${row.identifier} differs from Linear`);
|
|
47
|
+
}
|
|
48
|
+
return errors;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Linear GraphQL read-only fetchLinearProjectIssues resolves the project and paginates the open issues.
|
|
52
|
+
// createdAt is queried separately because the shared COO tool's projection does not include it.
|
|
53
|
+
export async function readLiveCooIssues(apiKey: string, project: string): Promise<{ issues: LiveIssue[]; truncated: boolean }> {
|
|
54
|
+
const issues = await fetchLinearProjectIssues({apiKey, project});
|
|
55
|
+
const identifiers = issues.map(issue => issue.identifier);
|
|
56
|
+
if (new Set(identifiers).size !== identifiers.length) throw new Error('duplicate Linear identifier');
|
|
57
|
+
const query = 'query CooIssueCreation($id: String!) { issue(id: $id) { identifier createdAt } }';
|
|
58
|
+
const creations = await Promise.all(identifiers.map(async identifier => {
|
|
59
|
+
const response = await fetch('https://api.linear.app/graphql', {
|
|
60
|
+
method: 'POST', headers: {Authorization: apiKey, 'Content-Type': 'application/json'},
|
|
61
|
+
body: JSON.stringify({query, variables: {id: identifier}}),
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) throw new Error(`Linear creation read HTTP ${response.status}`);
|
|
64
|
+
const body = await response.json() as { errors?: unknown[]; data?: {issue?: {identifier: string; createdAt: string}} };
|
|
65
|
+
if (body.errors?.length || body.data?.issue?.identifier !== identifier || !body.data.issue.createdAt) throw new Error(`Linear creation read failed: ${identifier}`);
|
|
66
|
+
return body.data.issue.createdAt;
|
|
67
|
+
}));
|
|
68
|
+
return {issues: issues.map((issue, index) => ({...issue, createdAt: creations[index]!})), truncated: issues.truncated};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (import.meta.main) {
|
|
72
|
+
const apiKey = process.env.LINEAR_API_KEY?.trim();
|
|
73
|
+
if (!apiKey) throw new Error('LINEAR_API_KEY absent; cannot compare recorded evidence to live Linear');
|
|
74
|
+
const record = JSON.parse(await readFile(new URL('../src/domains/coo-admin-dates.evidence.json', import.meta.url), 'utf8')) as Evidence;
|
|
75
|
+
const {issues, truncated} = await readLiveCooIssues(apiKey, record.project);
|
|
76
|
+
const errors = compareCooEvidence(record, issues, truncated);
|
|
77
|
+
if (errors.length) {
|
|
78
|
+
for (const error of errors) console.error(error);
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
} else {
|
|
81
|
+
console.log(`PASS Linear live comparison: open=${issues.length} selected=${record.verifiedIssues.length} dueDates=${record.verifiedIssues.filter(issue => issue.existingDueDate !== null).length} priorities=${record.verifiedIssues.filter(issue => issue.priority !== 0).length} excluded=${record.cohort.excludedCurrentIssues.length}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/acp/client.ts
CHANGED
|
@@ -371,6 +371,8 @@ export function readClientInfo(
|
|
|
371
371
|
export interface AcpAgentOpts {
|
|
372
372
|
/** Backend id from ACP_BACKENDS. */
|
|
373
373
|
backendId: string;
|
|
374
|
+
/** Review-owned ACP executable override; never changes the shared backend registry. */
|
|
375
|
+
backendSpec?: AcpBackendSpec;
|
|
374
376
|
/** Working directory the agent runs in (cwd argument to spawn).
|
|
375
377
|
* Affects file-tool resolution. Default: getSessionCwd() so a
|
|
376
378
|
* Ctrl+W / /wd in the dashboard retargets new ACP agents. */
|
|
@@ -443,7 +445,7 @@ export class AcpAgent {
|
|
|
443
445
|
private authMethods: string[] = [];
|
|
444
446
|
|
|
445
447
|
constructor(opts: AcpAgentOpts) {
|
|
446
|
-
this.spec = getAcpBackend(opts.backendId);
|
|
448
|
+
this.spec = opts.backendSpec ?? getAcpBackend(opts.backendId);
|
|
447
449
|
// WD7 — default to the session working directory; ACP agents
|
|
448
450
|
// inherit the "active project" concept.
|
|
449
451
|
this.cwd = opts.cwd ?? getSessionCwd();
|
|
@@ -456,7 +458,7 @@ export class AcpAgent {
|
|
|
456
458
|
// proactively. Mirrors zed's env-strip pattern for provider
|
|
457
459
|
// tokens (acp.rs:232-243), generalized here for any env that
|
|
458
460
|
// breaks nested agents.
|
|
459
|
-
const cleanEnv: NodeJS.ProcessEnv = { ...process.env, ...opts.env };
|
|
461
|
+
const cleanEnv: NodeJS.ProcessEnv = opts.backendSpec && opts.env ? { ...opts.env, NODE_ENV: process.env.NODE_ENV } : { ...process.env, ...opts.env };
|
|
460
462
|
for (const key of Object.keys(cleanEnv)) {
|
|
461
463
|
if (NESTED_AGENT_ENV_BLOCKLIST.has(key) || /^CLAUDE_CODE_/.test(key)) {
|
|
462
464
|
delete cleanEnv[key];
|
package/src/agent/run-context.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface ChildLlmSelection {
|
|
|
54
54
|
effort?: ChildLlmEffort;
|
|
55
55
|
/** 선택이 CLI 플래그에서 왔나, self-dev 설정에서 왔나. 같은 모델이라도 다른 사실이다. */
|
|
56
56
|
source: 'flag' | 'config';
|
|
57
|
+
/** Grok weekly cap rerouted this run to Codex: allow prepaid credits even when subscription quota is exhausted. */
|
|
58
|
+
codexQuotaPolicy?: 'credits';
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
/** ⭐⭐ **가르는 축은 「키냐 주소냐」가 «아니라» 「그 자격이 «파일»에 사나 «env»에 사나」다**
|
|
@@ -91,6 +93,8 @@ export function childLlmSelectionEnv(selection?: ChildLlmSelection): Record<stri
|
|
|
91
93
|
return {
|
|
92
94
|
ELANOUS_LLM_PROVIDER: provider,
|
|
93
95
|
ELANOUS_LLM_MODEL: childRelayModel(provider, selection.model),
|
|
96
|
+
...(selection.codexQuotaPolicy === 'credits' && provider === 'openai-codex'
|
|
97
|
+
? { ELANOUS_CODEX_QUOTA_POLICY: 'credits' } : {}),
|
|
94
98
|
// ⛔⭐ 새 env 이름을 «짓지 않는다» — `ELANOUS_ESCALATE_EFFORT` 가 «이미» 있고
|
|
95
99
|
// `user-config.ts` 가 그것으로 `reasoningLevel`(anthropic)과
|
|
96
100
|
// `codexReasoning.effort`(openai-codex/sol) 를 ***둘 다*** 덮는다.
|