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/index.ts
CHANGED
|
@@ -613,9 +613,10 @@ function buildHarnessAskSayDevCliSpec(
|
|
|
613
613
|
input: { file: string },
|
|
614
614
|
cliOpts: ReturnType<typeof harnessAskSayOptionsToDevCliOpts>,
|
|
615
615
|
entranceId: EntranceId,
|
|
616
|
+
runId: string,
|
|
616
617
|
) {
|
|
617
618
|
return {
|
|
618
|
-
...buildDevCliSpec(input, { kind: 'self' }, cliOpts, Object.keys(cliOpts), entranceId),
|
|
619
|
+
...buildDevCliSpec(input, { kind: 'self' }, cliOpts, Object.keys(cliOpts), entranceId, undefined, undefined, runId),
|
|
619
620
|
...(cliOpts.json ? { humanReadableOutput: false } : {}),
|
|
620
621
|
};
|
|
621
622
|
}
|
|
@@ -661,6 +662,7 @@ async function runDevAskFromAskFile(askPath: string, opts: HarnessAskSayChildLlm
|
|
|
661
662
|
{ file: flowResult.goalFile },
|
|
662
663
|
cliOpts,
|
|
663
664
|
CLI_HARNESS_ASK_ENTRANCE.id,
|
|
665
|
+
identity.runId,
|
|
664
666
|
),
|
|
665
667
|
...(pieceFeature === undefined ? {} : { input: { text: pieceFeature } }),
|
|
666
668
|
...(base === undefined ? {} : { base }),
|
|
@@ -765,6 +767,7 @@ async function runDevAskFromGoalFile(goalPath: string, opts: HarnessAskSayChildL
|
|
|
765
767
|
{ file: goalPath },
|
|
766
768
|
cliOpts,
|
|
767
769
|
CLI_HARNESS_ASK_ENTRANCE.id,
|
|
770
|
+
identity.runId,
|
|
768
771
|
),
|
|
769
772
|
runId: identity.runId,
|
|
770
773
|
runIdSource: identity.source,
|
|
@@ -868,6 +871,7 @@ async function runDevSayFromWords(
|
|
|
868
871
|
{ file: flowResult.goalFile },
|
|
869
872
|
cliOpts,
|
|
870
873
|
entrance,
|
|
874
|
+
identity.runId,
|
|
871
875
|
),
|
|
872
876
|
runId: identity.runId,
|
|
873
877
|
runIdSource: identity.source,
|
|
@@ -1271,9 +1275,10 @@ marketCmd.command('publish').description('Publish a local signed marketplace ind
|
|
|
1271
1275
|
.option('--source-sha <sha>', 'Git source commit')
|
|
1272
1276
|
.option('--source-base <path>', 'Git source plugin base directory')
|
|
1273
1277
|
.option('--bundle-root <dir>', 'Root that extensions["ai.elanous"].bundle paths resolve against (usually the repository root)')
|
|
1278
|
+
.option('--keep-existing', 'Carry over previous index entries whose name has no folder under --dir (unchanged entry and archive)')
|
|
1274
1279
|
.option('--json', 'JSON result')
|
|
1275
1280
|
.action(async (opts: { dir: string; out: string; key: string; keyId: string; marketName: string; displayName: string;
|
|
1276
|
-
sourceRepo?: string; sourceSha?: string; sourceBase?: string; bundleRoot?: string; json?: boolean }) => {
|
|
1281
|
+
sourceRepo?: string; sourceSha?: string; sourceBase?: string; bundleRoot?: string; keepExisting?: boolean; json?: boolean }) => {
|
|
1277
1282
|
try {
|
|
1278
1283
|
const sourceOptions = [opts.sourceRepo, opts.sourceSha, opts.sourceBase];
|
|
1279
1284
|
if (sourceOptions.some(Boolean) && !sourceOptions.every(Boolean)) throw new Error('source-repo, source-sha and source-base must be provided together');
|
|
@@ -1282,12 +1287,14 @@ marketCmd.command('publish').description('Publish a local signed marketplace ind
|
|
|
1282
1287
|
market: { name: opts.marketName, displayName: opts.displayName },
|
|
1283
1288
|
key: { keyId: opts.keyId, privateKeyPem: readFileSync(opts.key, 'utf8') },
|
|
1284
1289
|
...(opts.bundleRoot ? { bundleRoot: opts.bundleRoot } : {}),
|
|
1290
|
+
...(opts.keepExisting ? { keepExisting: true } : {}),
|
|
1285
1291
|
...(opts.sourceRepo && opts.sourceSha && opts.sourceBase
|
|
1286
1292
|
? { source: { repoUrl: opts.sourceRepo, sha: opts.sourceSha, basePath: opts.sourceBase } } : {}),
|
|
1287
1293
|
});
|
|
1288
1294
|
if (opts.json) await writeStdoutJson(JSON.stringify(result) + '\n');
|
|
1289
1295
|
else {
|
|
1290
|
-
console.log(`Published ${result.published.length} plugins (sequence ${result.sequence}); skipped ${result.skipped.length}`
|
|
1296
|
+
console.log(`Published ${result.published.length} plugins (sequence ${result.sequence}); skipped ${result.skipped.length}` +
|
|
1297
|
+
(opts.keepExisting ? `; kept ${result.kept.length}` : ''));
|
|
1291
1298
|
for (const warning of result.warnings) console.warn(`⚠ ${warning.dir}: ${warning.graph} uses recipes it does not ship (${warning.recipes.join(', ')}) — third-party graphs should use their own recipes.yaml or custom nodes`);
|
|
1292
1299
|
}
|
|
1293
1300
|
for (const item of result.skipped) {
|
|
@@ -3477,8 +3484,10 @@ coordCmd.command('event').command('record')
|
|
|
3477
3484
|
.requiredOption('--header <line>', '채널 글 첫 줄')
|
|
3478
3485
|
.option('--url <url>', '채널 코멘트 URL')
|
|
3479
3486
|
.action(async (opts: { seat: string; header: string; url?: string }) => {
|
|
3480
|
-
const { parseCoordHeader, recordCoordEvent } = await import('./context-bus/coord-events.js');
|
|
3481
|
-
|
|
3487
|
+
const { parseCoordHeader, recordCoordEvent, mirrorCoordDecision } = await import('./context-bus/coord-events.js');
|
|
3488
|
+
const input = { ...parseCoordHeader(opts.seat, opts.header), url: opts.url || null, at: new Date().toISOString() };
|
|
3489
|
+
try { recordCoordEvent(input); }
|
|
3490
|
+
finally { mirrorCoordDecision(input); }
|
|
3482
3491
|
});
|
|
3483
3492
|
coordCmd.command('events')
|
|
3484
3493
|
.option('--since <ISO|2h>', '조회 시작', '2h')
|
|
@@ -4465,8 +4474,10 @@ selfCmd
|
|
|
4465
4474
|
};
|
|
4466
4475
|
try {
|
|
4467
4476
|
const { dispatchHeavyCheck } = await import('./self-implement/gate-remote.js');
|
|
4468
|
-
const {
|
|
4469
|
-
const
|
|
4477
|
+
const { runGitCommand } = await import('./git-fs/runner.js');
|
|
4478
|
+
const topLevel = runGitCommand(process.cwd(), ['rev-parse', '--show-toplevel'], { encoding: 'utf8' });
|
|
4479
|
+
if (topLevel.status !== 0) throw new Error(`git rev-parse --show-toplevel failed: ${topLevel.stderr.trim() || `rc=${topLevel.status}`}`);
|
|
4480
|
+
const repo = topLevel.stdout.trim();
|
|
4470
4481
|
// Only a committed --base range is reproducible on another host: the default mode measures uncommitted files, --pr
|
|
4471
4482
|
// reads files through gh on this host, and the remote checkout runs from the repository root — those stay local.
|
|
4472
4483
|
const { realpathSync } = await import('node:fs');
|
|
@@ -4891,7 +4902,7 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4891
4902
|
// ☸️ 풀이 «원격 노드뿐»이면 이 기계의 이미지는 아무도 안 쓴다 — 로컬 판정·굽기를 건너뛰고 기준 판 = HEAD 로 노드 동기화만 한다.
|
|
4892
4903
|
// 🩸 2026-09-26 실측: 원격 전용 풀인데 로컬 이미지가 없다고 로컬에서 굽다가 로컬 클러스터(elanous-h1)가 없어 런이 시작도 전에 죽었다.
|
|
4893
4904
|
const remoteOnlyPool = poolMembers.length > 0 && poolMembers.every((m) => Boolean(m.sshHost));
|
|
4894
|
-
const headCommit = remoteOnlyPool ? ((await import('
|
|
4905
|
+
const headCommit = remoteOnlyPool ? ((await import('./git-fs/runner.js')).runGitCommand(process.cwd(), ['rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim() || null) : null;
|
|
4895
4906
|
let image = remoteOnlyPool
|
|
4896
4907
|
? { imageCommit: headCommit, headCommit, fresh: true, reason: 'remote-only pool — 노드 쪽에서 맞춘다' }
|
|
4897
4908
|
: podImageFreshness();
|
|
@@ -4901,7 +4912,8 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4901
4912
|
} else {
|
|
4902
4913
|
if (!opts.json) ui.info(`[pod] 이미지 다시 굽기 — ${image.reason} (~1분)`);
|
|
4903
4914
|
const { spawnSync } = await import('node:child_process');
|
|
4904
|
-
const
|
|
4915
|
+
const { runGitCommand } = await import('./git-fs/runner.js');
|
|
4916
|
+
const top = runGitCommand(process.cwd(), ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).stdout.trim() || process.cwd();
|
|
4905
4917
|
// bun 1.4 applies the 1 MiB default maxBuffer: a docker build log past it kills the child (ENOBUFS · status null).
|
|
4906
4918
|
const b = spawnSync('bash', [`${top}/docker/harness/build.sh`], { encoding: 'utf8', timeout: 900_000, maxBuffer: 64 * 1024 * 1024 });
|
|
4907
4919
|
if (b.status !== 0) { ui.error(`--substrate pod: 이미지 굽기 실패 rc=${b.status}${b.error ? ` (${(b.error as NodeJS.ErrnoException).code ?? b.error.message})` : ''}: ${(b.stdout + b.stderr).slice(-400)}`); process.exit(2); }
|
|
@@ -7314,8 +7326,8 @@ const selfDevCmd = program
|
|
|
7314
7326
|
console.error(`[dev] 외부 backend 미션의 자기 명령은 \`elanous agent-mission mission\` 입니다; 대응 명령: elanous agent-mission mission --backend ${executor.backend}`);
|
|
7315
7327
|
}
|
|
7316
7328
|
let spec = invokedAsDrive
|
|
7317
|
-
? devCli.buildDriveAliasDevSpec(hasText ? textParts.join(' ') : undefined, devOpts, devCli.explicitDevOptionNames(command))
|
|
7318
|
-
: buildDevCliSpec(input, executor, devOpts, devCli.explicitDevOptionNames(command));
|
|
7329
|
+
? devCli.buildDriveAliasDevSpec(hasText ? textParts.join(' ') : undefined, devOpts, devCli.explicitDevOptionNames(command), devRunId)
|
|
7330
|
+
: buildDevCliSpec(input, executor, devOpts, devCli.explicitDevOptionNames(command), 'cli-dev-ask', undefined, undefined, devRunId);
|
|
7319
7331
|
if (!opts.json && spec.notice) console.error(spec.notice);
|
|
7320
7332
|
// 역할별 LLM은 현재 프로세스 설정이다. self-mission 구현 자식에 전달되지 않는 조합은 위 검증이 먼저 거부한다.
|
|
7321
7333
|
if (Array.isArray(opts.roleLlm) && opts.roleLlm.length > 0) {
|
|
@@ -7816,6 +7828,26 @@ configCmd
|
|
|
7816
7828
|
if (report.prodStatus !== 'ok') process.exit(1);
|
|
7817
7829
|
});
|
|
7818
7830
|
|
|
7831
|
+
configCmd
|
|
7832
|
+
.command('classify')
|
|
7833
|
+
.description('읽기 전용 — 운영 config 잎의 자리(기본값·기계 사실·비밀·운영 정책)와 덮어쓰기 수 (CFG-CLASSIFY)')
|
|
7834
|
+
.option('--json', '잎 전체를 JSON 으로 출력 (비밀 값 제외)')
|
|
7835
|
+
.action(async (o: { json?: boolean }) => {
|
|
7836
|
+
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
7837
|
+
const { readUniverseConfig } = await import('./cli/config-drift.js');
|
|
7838
|
+
const { classifyConfig, renderClassify } = await import('./cli/config-classify.js');
|
|
7839
|
+
const { buildUserConfig } = await import('./user-config.js');
|
|
7840
|
+
const prod = readUniverseConfig(getElanousConfigDir(), []);
|
|
7841
|
+
if (prod.status !== 'ok' || !prod.raw) {
|
|
7842
|
+
console.error(`config classify — config 못 읽음(${prod.status}${prod.error ? `: ${prod.error}` : ''})`);
|
|
7843
|
+
process.exitCode = 1;
|
|
7844
|
+
return;
|
|
7845
|
+
}
|
|
7846
|
+
const report = classifyConfig(prod.raw, buildUserConfig('/nonexistent/elanous-config-drift/config.json') as unknown as Record<string, unknown>);
|
|
7847
|
+
if (o.json) await (await import('./cli/stdout-flush.js')).writeStdoutFully(JSON.stringify(report, null, 2));
|
|
7848
|
+
else console.log(renderClassify(report));
|
|
7849
|
+
});
|
|
7850
|
+
|
|
7819
7851
|
configCmd
|
|
7820
7852
|
.command('explain <key>')
|
|
7821
7853
|
.description('읽기 전용 — 운영 값 ⊕ 출처 층 ⊕ 파생 시험 우주별 값 (CFG-STORE1)')
|
|
@@ -125,6 +125,19 @@ export function buildIntakeDigest(root: string, day: string, readFile: (p: strin
|
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
function digestNoteRef(e: DigestEntry): string {
|
|
129
|
+
return e.noteName ? `[[${e.noteName}]]` : e.note?.trim() || e.url?.trim() || e.id;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** 참고 줄에 이름을 다는 상한 — 많은 날에도 화면 한 장을 지킨다(M 은 그대로 센다). */
|
|
133
|
+
const DIGEST_REFERENCE_NAMED = 10;
|
|
134
|
+
|
|
135
|
+
function digestReferenceLine(entries: DigestEntry[]): string {
|
|
136
|
+
const named = entries.slice(0, DIGEST_REFERENCE_NAMED).map(digestNoteRef).join(', ');
|
|
137
|
+
const rest = entries.length - DIGEST_REFERENCE_NAMED;
|
|
138
|
+
return `참고 ${entries.length}편 — 노트: ${named}${rest > 0 ? ` 외 ${rest}편 · 원장 \`elanous intake items\`` : ''}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
/** 노트 절 — 축별 묶음 · 노트 링크 · 한 줄 요약 · 골 후보. */
|
|
129
142
|
export function renderDigestMarkdown(d: IntakeDigest): string {
|
|
130
143
|
const L: string[] = [`## 📰 오늘의 흡수 요약 (${d.absorbed.length})`, ''];
|
|
@@ -165,14 +178,9 @@ export function renderDigestMarkdown(d: IntakeDigest): string {
|
|
|
165
178
|
|
|
166
179
|
/** 텔레그램 — 흡수 렌즈가 대조한 항목만 SCQA 짧은 판으로 낸다. */
|
|
167
180
|
export function renderDigestTelegram(d: IntakeDigest, _opts: { vaultRoot?: string; notePath?: string } = {}): string {
|
|
168
|
-
if (d.seat && !d.absorbed.length) return '오늘 새 소식 없음';
|
|
169
|
-
if (d.seat) return [
|
|
170
|
-
`흡수 ${d.absorbed.length}`,
|
|
171
|
-
...d.absorbed.map((item) => `- ${item.oneLiner ?? item.noteName ?? item.id}${item.url ? ` · ${item.url}` : ''}`),
|
|
172
|
-
].join('\n');
|
|
173
181
|
// «Touching» is decided by the lens verdict alone; a missing note summary only changes how S reads (ACP must-fix).
|
|
174
182
|
const touching = d.absorbed.filter((e) => e.impact);
|
|
175
|
-
const L = [`흡수 ${d.absorbed.length} → 우리에게 닿는 것 ${touching.length}`];
|
|
183
|
+
const L = [`흡수 ${d.absorbed.length}편 → 우리에게 닿는 것 ${touching.length}`];
|
|
176
184
|
// 관심 뉴스는 최대 셋 — 기사마다 S(요약 첫 줄) · A(엘라누스 함의 첫 줄) · 링크를 한 덩어리로(NEWS-INTAKE).
|
|
177
185
|
for (const article of (d.news ?? []).slice(0, 3)) {
|
|
178
186
|
L.push(`📰 ${article.title}`);
|
|
@@ -181,9 +189,7 @@ export function renderDigestTelegram(d: IntakeDigest, _opts: { vaultRoot?: strin
|
|
|
181
189
|
L.push(article.url);
|
|
182
190
|
}
|
|
183
191
|
if (d.shadowSuggestions?.length) L.push(`뉴스 칸 제안 ${d.shadowSuggestions.length}건 (그림자·판 미등록): ${d.shadowSuggestions.slice(0, 3).map((s) => `[${s.verdict}] ${s.fact}${s.url ? ` ${s.url}` : ''}`).join(' · ')}`);
|
|
184
|
-
|
|
185
|
-
// At most three items are shown, each as its own S·C·A·link block so context and source stay paired;
|
|
186
|
-
// a later item sharing (verdict, target) says «위와 같은 행동» instead of repeating the A sentence (ACP must-fix).
|
|
192
|
+
// At most three items are shown, each as its own S·C·A·note block so context and source stay paired.
|
|
187
193
|
// S must be the note's own summary: items without one still count as touching but are not shown (ACP must-fix).
|
|
188
194
|
const shownItems = touching.filter((e) => e.oneLiner?.trim()).slice(0, 3);
|
|
189
195
|
const actionSeen = new Set<string>();
|
|
@@ -205,10 +211,11 @@ export function renderDigestTelegram(d: IntakeDigest, _opts: { vaultRoot?: strin
|
|
|
205
211
|
`S 무엇: ${e.oneLiner?.trim() || '노트 한 줄 요약 없음'}`,
|
|
206
212
|
`C 우리에게 왜: ${impact.why}`,
|
|
207
213
|
`A 그래서 무엇을 하나: ${action}`,
|
|
208
|
-
`🔗
|
|
214
|
+
`🔗 노트: ${digestNoteRef(e)}`,
|
|
209
215
|
);
|
|
210
216
|
}
|
|
211
217
|
if (touching.length > shownItems.length) L.push('', `닿는 것 ${touching.length - shownItems.length}건 더(요약 없는 것 포함) · 원장 \`elanous intake items\``);
|
|
212
|
-
|
|
218
|
+
const reference = d.absorbed.filter((e) => !e.impact);
|
|
219
|
+
if (reference.length) L.push('', digestReferenceLine(reference));
|
|
213
220
|
return L.join('\n');
|
|
214
221
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { releaseLedgerRoot } from '../instance/resolve.js';
|
|
5
|
+
import { listChecklist, setItem } from '../release-loop/checklist.js';
|
|
6
|
+
import { withFileLockSync } from '../storage/file-lock.js';
|
|
7
|
+
|
|
8
|
+
export type ConclusionKind = 'evidence' | 'decision' | 'lesson';
|
|
9
|
+
export type ConclusionSource = 'goal' | 'handoff' | 'run-log' | 'channel' | 'pr-discussion';
|
|
10
|
+
export interface ConclusionRecord {
|
|
11
|
+
source: ConclusionSource;
|
|
12
|
+
cell: string;
|
|
13
|
+
kind: ConclusionKind;
|
|
14
|
+
conclusion: string;
|
|
15
|
+
/** Original URL, or a relative path to the original for non-channel sources. */
|
|
16
|
+
ref: string;
|
|
17
|
+
body: string;
|
|
18
|
+
/** The original post's UTC timestamp; required when compressing a channel day. */
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
/** Terminal status is required before a run can be archived. */
|
|
21
|
+
status?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ConclusionBatch {
|
|
24
|
+
version: string;
|
|
25
|
+
day: string;
|
|
26
|
+
records: ConclusionRecord[];
|
|
27
|
+
}
|
|
28
|
+
export interface ConclusionReceipt {
|
|
29
|
+
archive: string;
|
|
30
|
+
lines: string[];
|
|
31
|
+
originalBytes: number;
|
|
32
|
+
conclusionBytes: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const kinds = new Set<ConclusionKind>(['evidence', 'decision', 'lesson']);
|
|
36
|
+
const sources = new Set<ConclusionSource>(['goal', 'handoff', 'run-log', 'channel', 'pr-discussion']);
|
|
37
|
+
const closed = new Set(['done', 'failed', 'cancelled', 'superseded', 'completed', 'abandoned']);
|
|
38
|
+
const validDay = (day: string) => /^\d{4}-\d{2}-\d{2}$/.test(day) && new Date(`${day}T00:00:00Z`).toISOString().slice(0, 10) === day;
|
|
39
|
+
|
|
40
|
+
/** Archive a complete input batch; publish only source-linked, explicitly supplied conclusions to the checklist ledger. */
|
|
41
|
+
export function compressConclusions(batch: ConclusionBatch, root = releaseLedgerRoot()): ConclusionReceipt {
|
|
42
|
+
if (!batch || !Array.isArray(batch.records) || !batch.records.length || !validDay(batch.day)) throw new Error('invalid day or empty records');
|
|
43
|
+
if (!/^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/.test(batch.version)) throw new Error('invalid checklist version');
|
|
44
|
+
if (resolve(root) !== resolve(releaseLedgerRoot())) throw new Error('archive and checklist must share a ledger root');
|
|
45
|
+
const checklist = listChecklist(batch.version);
|
|
46
|
+
const digest = createHash('sha256').update(JSON.stringify(batch)).digest('hex');
|
|
47
|
+
const archiveRef = `knowledge-compress/archive/${digest}.json`;
|
|
48
|
+
const byCell = new Map<string, string[]>();
|
|
49
|
+
for (const [index, record] of batch.records.entries()) {
|
|
50
|
+
if (!record || !sources.has(record.source) || !kinds.has(record.kind) ||
|
|
51
|
+
!checklist.items.some(item => item.id === record.cell) || !record.body?.trim() ||
|
|
52
|
+
!record.conclusion?.trim() || /[\r\n]/.test(record.conclusion) || !record.ref?.trim()) {
|
|
53
|
+
throw new Error('unverified source, conclusion or checklist cell');
|
|
54
|
+
}
|
|
55
|
+
if (record.source === 'channel') {
|
|
56
|
+
if (!/^https:\/\/github\.com\/[^\s]+#issuecomment-\d+$/.test(record.ref) ||
|
|
57
|
+
!record.createdAt || !Number.isFinite(Date.parse(record.createdAt)) ||
|
|
58
|
+
new Date(record.createdAt).toISOString().slice(0, 10) !== batch.day) throw new Error('channel comment must link to the selected UTC day');
|
|
59
|
+
}
|
|
60
|
+
if (record.source === 'run-log' && !closed.has(record.status ?? '')) throw new Error('run is not finished');
|
|
61
|
+
const conclusion = record.conclusion.trim().replace(/\s+/g, ' ');
|
|
62
|
+
if (conclusion.length > 160 || !conclusion) throw new Error('conclusion exceeds one line');
|
|
63
|
+
const ref = record.ref.trim();
|
|
64
|
+
if (/\s|[\r\n]/.test(ref) || (record.source !== 'channel' && !/^(https:\/\/|[^/][^\s]*$)/.test(ref))) throw new Error('invalid source pointer');
|
|
65
|
+
const line = `${record.kind}: ${conclusion} (${record.source === 'channel' ? ref : `${archiveRef}#record-${index + 1}`})`;
|
|
66
|
+
byCell.set(record.cell, [...(byCell.get(record.cell) ?? []), line]);
|
|
67
|
+
}
|
|
68
|
+
const lines = [...byCell].flatMap(([cell, entries]) => [...new Set(entries)].map(line => `${cell} · ${line}`));
|
|
69
|
+
const originalBytes = Buffer.byteLength(JSON.stringify(batch.records));
|
|
70
|
+
const conclusionBytes = Buffer.byteLength(lines.join('\n'));
|
|
71
|
+
if (conclusionBytes * 10 > originalBytes) throw new Error(`conclusions exceed 1/10 of original (${conclusionBytes}/${originalBytes} bytes)`);
|
|
72
|
+
|
|
73
|
+
const dir = join(root, 'knowledge-compress');
|
|
74
|
+
const archive = join(root, archiveRef);
|
|
75
|
+
const lock = join(dir, 'conclusions.lock');
|
|
76
|
+
mkdirSync(dirname(archive), { recursive: true });
|
|
77
|
+
return withFileLockSync(lock, () => {
|
|
78
|
+
if (existsSync(archive)) {
|
|
79
|
+
if (readFileSync(archive, 'utf8') !== JSON.stringify(batch)) throw new Error('archive digest collision');
|
|
80
|
+
} else {
|
|
81
|
+
const temp = `${archive}.${randomUUID()}.tmp`;
|
|
82
|
+
writeFileSync(temp, JSON.stringify(batch), { flag: 'wx', mode: 0o600 });
|
|
83
|
+
renameSync(temp, archive);
|
|
84
|
+
}
|
|
85
|
+
for (const [cell, entries] of byCell) {
|
|
86
|
+
const existing = listChecklist(batch.version).items.find(item => item.id === cell);
|
|
87
|
+
if (!existing) throw new Error(`checklist cell disappeared: ${cell}`);
|
|
88
|
+
const additions = [...new Set(entries)].filter(line => !existing.evidence?.split('\n').includes(line));
|
|
89
|
+
if (additions.length) setItem(batch.version, cell, { evidence: [existing.evidence, ...additions].filter(Boolean).join('\n') }, 'knowledge-compress');
|
|
90
|
+
}
|
|
91
|
+
return { archive: resolve(archive), lines, originalBytes, conclusionBytes };
|
|
92
|
+
});
|
|
93
|
+
}
|
|
@@ -3,6 +3,7 @@ import { LessonLedger, type LessonRow } from '../lessons/lesson-ledger.js';
|
|
|
3
3
|
import { DecisionLedger, type DecisionEntry, type SeatDecisionRecord } from '../decisions/decision-ledger.js';
|
|
4
4
|
import { devVersion, listChecklist, type Checklist } from '../release-loop/checklist.js';
|
|
5
5
|
import { debug } from '../debug/log.js';
|
|
6
|
+
import { queryInstalledPack } from './query.js';
|
|
6
7
|
|
|
7
8
|
/** Directive row fields this search reads — kept local because `src/directives/directive-index` is excluded from the public export. */
|
|
8
9
|
export interface DirectiveRow { ts: string; text: string; source_file: string; line_no: number }
|
|
@@ -14,7 +15,7 @@ function openDirectiveIndex(): { search(q: string): DirectiveRow[]; close(): voi
|
|
|
14
15
|
return new mod.DirectiveIndex();
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export type KnowSource = 'directive' | 'decision' | 'checklist' | 'lesson';
|
|
18
|
+
export type KnowSource = 'directive' | 'decision' | 'checklist' | 'lesson' | 'pack';
|
|
18
19
|
export interface KnowHit {
|
|
19
20
|
source: KnowSource;
|
|
20
21
|
id: string;
|
|
@@ -36,6 +37,7 @@ export interface KnowFindDeps {
|
|
|
36
37
|
lessons: (query: string) => LessonRow[];
|
|
37
38
|
versions: () => string[];
|
|
38
39
|
now: () => Date;
|
|
40
|
+
pack?: typeof queryInstalledPack;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
function versions(): string[] {
|
|
@@ -55,6 +57,7 @@ const defaults: KnowFindDeps = {
|
|
|
55
57
|
lessons: (query) => new LessonLedger().find(query),
|
|
56
58
|
versions,
|
|
57
59
|
now: () => new Date(),
|
|
60
|
+
pack: queryInstalledPack,
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
function matches(text: string, words: string[]): boolean {
|
|
@@ -62,7 +65,7 @@ function matches(text: string, words: string[]): boolean {
|
|
|
62
65
|
return words.every((word) => normalized.includes(word));
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
export function knowFind(query: string, deps: Partial<KnowFindDeps> = {}): KnowResult {
|
|
68
|
+
export function knowFind(query: string, deps: Partial<KnowFindDeps> = {}, packId?: string): KnowResult {
|
|
66
69
|
const read = { ...defaults, ...deps };
|
|
67
70
|
const words = query.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
|
|
68
71
|
if (!words.length) throw new Error('know: 질문이 필요합니다');
|
|
@@ -106,6 +109,10 @@ export function knowFind(query: string, deps: Partial<KnowFindDeps> = {}): KnowR
|
|
|
106
109
|
for (const row of read.lessons(query)) rows.push({ source: 'lesson', id: row.id, title: row.incident,
|
|
107
110
|
status: row.status, at: row.updated_at, current: row.occurrence_count > 1, ref: `lesson show ${row.id}` });
|
|
108
111
|
});
|
|
112
|
+
if (packId) attempt('pack', () => {
|
|
113
|
+
for (const card of (read.pack ?? queryInstalledPack)(packId, query)) rows.push({ source: 'pack', id: card.id, title: card.title,
|
|
114
|
+
status: 'installed', at: card.updatedAt, current: true, ref: card.ref });
|
|
115
|
+
});
|
|
109
116
|
rows.sort((a, b) => Number(b.current) - Number(a.current) || (Date.parse(b.at) || 0) - (Date.parse(a.at) || 0)
|
|
110
117
|
|| a.source.localeCompare(b.source) || a.id.localeCompare(b.id));
|
|
111
118
|
debug.log('knowledge.know', 'query', { query, counts: Object.fromEntries((['directive', 'decision', 'checklist', 'lesson'] as const)
|
package/src/knowledge/query.ts
CHANGED
|
@@ -10,6 +10,26 @@ import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
|
10
10
|
import { join, relative, sep } from 'node:path';
|
|
11
11
|
import { parseFrontmatter, type ObsidianVault } from '../auto-research/obsidian-bridge.js';
|
|
12
12
|
import type { KnowledgeKind, KnowledgeNote, KnowledgeQueryInput, KnowledgeQueryResult } from './types.js';
|
|
13
|
+
import { PACK_KINDS, parsePackIdString, packIdString } from './kgs/pack.js';
|
|
14
|
+
import { kgsStoreSingleton, type KgsSqliteStore } from './kgs/sqlite-store.js';
|
|
15
|
+
|
|
16
|
+
/** Search only cards belonging to a pack present in the local KGS index. No vault fallback. */
|
|
17
|
+
export function listInstalledPacks(store: Pick<KgsSqliteStore, 'listPacksByKind'> = kgsStoreSingleton()): Array<{ id: string; title: string }> {
|
|
18
|
+
return PACK_KINDS.flatMap(kind => store.listPacksByKind(kind).map(pack => ({ id: packIdString(pack.metadata.id), title: pack.metadata.title })));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function queryInstalledPack(packId: string, question: string, store: Pick<KgsSqliteStore, 'readPack'> = kgsStoreSingleton()): Array<{ id: string; title: string; body: string; ref: string; updatedAt: string }> {
|
|
22
|
+
const id = parsePackIdString(packId);
|
|
23
|
+
if (!id) throw new Error(`invalid pack id: ${packId}`);
|
|
24
|
+
const pack = store.readPack(id.slug, id.version);
|
|
25
|
+
if (!pack) throw new Error(`pack not installed: ${packId}`);
|
|
26
|
+
const words = question.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
|
|
27
|
+
return pack.cards.map(card => ({ card, score: words.filter(word => `${card.title} ${card.body}`.toLocaleLowerCase().includes(word)).length }))
|
|
28
|
+
.filter(hit => hit.score > 0 || words.length === 0)
|
|
29
|
+
.sort((a, b) => b.score - a.score || a.card.id.localeCompare(b.card.id))
|
|
30
|
+
.map(({ card }) => ({ id: card.id, title: card.title, body: card.body,
|
|
31
|
+
ref: `${packIdString(pack.metadata.id)}#${card.id}`, updatedAt: card.updatedAt }));
|
|
32
|
+
}
|
|
13
33
|
|
|
14
34
|
const DEFAULT_LIMIT = 20;
|
|
15
35
|
const MAX_LIMIT = 100;
|
package/src/llm.ts
CHANGED
|
@@ -1746,7 +1746,7 @@ export const REASONING_CYCLE: readonly import('./user-config.js').ReasoningLevel
|
|
|
1746
1746
|
|
|
1747
1747
|
/** Does the (provider, model) pair support a "think before answering"
|
|
1748
1748
|
* reasoning surface? Capability-based: gpt-5 family on Codex /
|
|
1749
|
-
* Responses API + Anthropic
|
|
1749
|
+
* Responses API + Anthropic Claude 3.7+ (extended thinking)
|
|
1750
1750
|
* + OpenAI o-series. Other providers / older models return false so
|
|
1751
1751
|
* the HUD pill auto-hides and the wire body skips the reasoning
|
|
1752
1752
|
* field — no user toggle required. */
|
|
@@ -1768,9 +1768,7 @@ export function modelSupportsReasoning(
|
|
|
1768
1768
|
return m.startsWith('o1') || m.startsWith('o3') || m.startsWith('o4');
|
|
1769
1769
|
}
|
|
1770
1770
|
if (provider === 'anthropic') {
|
|
1771
|
-
|
|
1772
|
-
// (opus-4, sonnet-4, haiku-4) plus the 3.7 line.
|
|
1773
|
-
return m.includes('-4-') || m.includes('-3-7') || m.includes('3.7') || m.includes('claude-4');
|
|
1771
|
+
return claudeSupportsThinking(model);
|
|
1774
1772
|
}
|
|
1775
1773
|
if (provider === 'gemini') {
|
|
1776
1774
|
// Gemini 2.5+ family supports thinking budget (thinkingConfig).
|
|
@@ -1926,16 +1924,32 @@ function mapReasoningLevelToAnthropicEffort(
|
|
|
1926
1924
|
* 🩹 그래서 규칙을 이름 목록이 아니라 «수»로 둔다 — 목록은 새 모델마다 늙지만 세대 비교는 안 늙는다.
|
|
1927
1925
|
* ⚠️ 알 수 없는 형태는 legacy 로 둔다(무회귀). 판정 못 하면 종전 동작이 정답이다. */
|
|
1928
1926
|
function usesAdaptiveThinking(model: string | undefined): boolean {
|
|
1927
|
+
const version = claudeVersion(model, true);
|
|
1928
|
+
if (!version) return false;
|
|
1929
|
+
if (version.generation >= 5) return true;
|
|
1930
|
+
return version.generation === 4 && version.minor >= 7;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/** Shared numeric version parser for adaptive API shape and extended-thinking support. */
|
|
1934
|
+
function claudeVersion(model: string | undefined, requireTerminal = false): { generation: number; minor: number } | undefined {
|
|
1929
1935
|
// 끝에 붙는 릴리스 날짜(`-20251101`)는 버전이 아니다 — 떼고 본다.
|
|
1930
1936
|
const m = (model ?? '').toLowerCase().replace(/-\d{8}$/, '');
|
|
1931
|
-
const v
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
return generation === 4 && minor >= 7;
|
|
1937
|
+
for (const v of m.matchAll(/-(\d+)(?:[-.](\d+))?(?=-|$)/g)) {
|
|
1938
|
+
if (requireTerminal && v.index + v[0].length !== m.length) continue;
|
|
1939
|
+
return { generation: Number(v[1]), minor: v[2] === undefined ? 0 : Number(v[2]) };
|
|
1940
|
+
}
|
|
1941
|
+
return undefined;
|
|
1937
1942
|
}
|
|
1938
1943
|
|
|
1944
|
+
function claudeSupportsThinking(model: string | undefined): boolean {
|
|
1945
|
+
// includes, not startsWith: prefixed ids (`us.anthropic.claude-…`, `anthropic/claude-…`) passed the old substring check.
|
|
1946
|
+
if (!model?.toLowerCase().includes('claude-')) return false;
|
|
1947
|
+
const version = claudeVersion(model);
|
|
1948
|
+
return version !== undefined && (version.generation > 3 || version.generation === 3 && version.minor >= 7);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
export const _claudeSupportsThinkingForContractTest = claudeSupportsThinking;
|
|
1952
|
+
|
|
1939
1953
|
/** ⛔ 테스트 전용 노출이 아니다 — 모델 계열 계약은 «이름을 가진 판정»이라 회귀를 테스트로 물어야 한다.
|
|
1940
1954
|
* 이 파일 안 두 조립부(:3102·:9591)가 그 값을 쓰고, 그 계약이 틀리면 provider 가 통째로 막힌다. */
|
|
1941
1955
|
export const _usesAdaptiveThinkingForContractTest = usesAdaptiveThinking;
|
|
@@ -3134,13 +3148,9 @@ async function* streamAnthropicEvents(
|
|
|
3134
3148
|
// forcing a single thinking block before all tools). Improves
|
|
3135
3149
|
// multi-tool turn quality — the model can decide what to call
|
|
3136
3150
|
// next based on the prior tool's output thinking. Only supported
|
|
3137
|
-
// on extended-thinking-capable models (
|
|
3138
|
-
const model: string = (body?.model ?? '') as string;
|
|
3139
|
-
const m = model.toLowerCase();
|
|
3140
|
-
const supportsThinking =
|
|
3141
|
-
m.includes('-4-') || m.includes('-3-7') || m.includes('3.7') || m.includes('claude-4');
|
|
3151
|
+
// on extended-thinking-capable models (Claude 3.7+).
|
|
3142
3152
|
const betas: string[] = ['fine-grained-tool-streaming-2025-05-14'];
|
|
3143
|
-
if (
|
|
3153
|
+
if (claudeSupportsThinking(body?.model)) betas.push('interleaved-thinking-2025-05-14');
|
|
3144
3154
|
|
|
3145
3155
|
const response = await fetchApiWithRetry(
|
|
3146
3156
|
ANTHROPIC_API_URL,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
import { openMsgStore } from '../msg/msg-store.js';
|
|
3
|
+
import { judgeNeighbor, type Neighbor } from './neighbors.js';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
export type LoopHealth = 'healthy' | 'degraded';
|
|
7
|
+
export type NeighborIncident = { observer: string; neighbor: string; state: 'absent'; reason: string; action: Neighbor['onAbsent']['action']; to: string; at: string; lastSeenAt: string | null };
|
|
8
|
+
|
|
9
|
+
export const SEAT_NEIGHBORS: Record<string, Neighbor[]> = Object.fromEntries(['OP', 'TC', 'MK', 'UX'].map(seat => [seat,
|
|
10
|
+
[
|
|
11
|
+
...['OP', 'TC', 'MK', 'UX'].filter(peer => peer !== seat).map(peer => ({
|
|
12
|
+
id: peer === 'MK' ? 'cmo-seat' : `${peer.toLowerCase()}-seat`, exchange: ['status'] as Neighbor['exchange'],
|
|
13
|
+
heartbeat: { everyMinutes: 15, missedTicks: 2 },
|
|
14
|
+
onAbsent: peer === 'OP' ? { action: 'delegate' as const, delegateTo: 'steward' }
|
|
15
|
+
: peer === 'TC' ? { action: 'escalate' as const, delegateTo: 'orchestrator' }
|
|
16
|
+
: { action: 'defer' as const, delegateTo: 'orchestrator' },
|
|
17
|
+
})),
|
|
18
|
+
{ id: 'orchestrator', exchange: ['status'], heartbeat: { everyMinutes: 120, missedTicks: 2 },
|
|
19
|
+
onAbsent: { action: 'escalate', delegateTo: 'human' } },
|
|
20
|
+
],
|
|
21
|
+
]));
|
|
22
|
+
|
|
23
|
+
type Signal = { at: string; health: LoopHealth; ends_at: string | null };
|
|
24
|
+
|
|
25
|
+
function withStore<T>(root: string, fn: (store: ReturnType<typeof openMsgStore>) => T): T {
|
|
26
|
+
const store = openMsgStore(join(root, 'msg', 'messages.db'));
|
|
27
|
+
try {
|
|
28
|
+
store.db.exec(`CREATE TABLE IF NOT EXISTS loop_signals (loop_id TEXT PRIMARY KEY, at TEXT NOT NULL, health TEXT NOT NULL, ends_at TEXT);
|
|
29
|
+
CREATE TABLE IF NOT EXISTS loop_watches (observer TEXT NOT NULL, neighbor TEXT NOT NULL, first_at TEXT NOT NULL, PRIMARY KEY(observer, neighbor));
|
|
30
|
+
CREATE TABLE IF NOT EXISTS loop_incidents (observer TEXT NOT NULL, neighbor TEXT NOT NULL, signal_at TEXT NOT NULL,
|
|
31
|
+
reason TEXT NOT NULL, action TEXT NOT NULL, recipient TEXT NOT NULL, at TEXT NOT NULL,
|
|
32
|
+
PRIMARY KEY(observer, neighbor, signal_at, reason));`);
|
|
33
|
+
return fn(store);
|
|
34
|
+
} finally { store.close(); }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Durable signal, independent of chat sessions or the seat work-item ledger. */
|
|
38
|
+
export function emitLoopHeartbeat(root: string, loopId: string, health: LoopHealth, now: Date, endsAt?: string): void {
|
|
39
|
+
if (!/^[a-z][a-z0-9-]*$/.test(loopId) || !Number.isFinite(now.getTime())) throw new Error('invalid loop heartbeat');
|
|
40
|
+
if (endsAt && !Number.isFinite(Date.parse(endsAt))) throw new Error('invalid heartbeat end');
|
|
41
|
+
withStore(root, store => {
|
|
42
|
+
store.db.query(`INSERT INTO loop_signals(loop_id, at, health, ends_at) VALUES(?, ?, ?, ?)
|
|
43
|
+
ON CONFLICT(loop_id) DO UPDATE SET at=excluded.at, health=excluded.health, ends_at=excluded.ends_at
|
|
44
|
+
WHERE loop_signals.at <= excluded.at`).run(loopId, now.toISOString(), health, endsAt ?? null);
|
|
45
|
+
});
|
|
46
|
+
debug.log(`loop.${loopId}`, 'heartbeat', { loopId, at: now.toISOString(), health, endsAt: endsAt ?? null });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** First watch starts the missing-signal clock. Action receipt and message commit atomically. */
|
|
50
|
+
export function checkLoopNeighbors(root: string, observer: string, neighbors: readonly Neighbor[], now: Date): NeighborIncident[] {
|
|
51
|
+
return withStore(root, store => {
|
|
52
|
+
const incidents: NeighborIncident[] = [];
|
|
53
|
+
for (const neighbor of neighbors) {
|
|
54
|
+
if (neighbor.id === observer) continue;
|
|
55
|
+
try {
|
|
56
|
+
store.db.exec('BEGIN IMMEDIATE');
|
|
57
|
+
store.db.query('INSERT OR IGNORE INTO loop_watches(observer, neighbor, first_at) VALUES(?, ?, ?)').run(observer, neighbor.id, now.toISOString());
|
|
58
|
+
const signal = store.db.query('SELECT at, health, ends_at FROM loop_signals WHERE loop_id=?').get(neighbor.id) as Signal | null;
|
|
59
|
+
const watch = store.db.query('SELECT first_at FROM loop_watches WHERE observer=? AND neighbor=?').get(observer, neighbor.id) as { first_at: string };
|
|
60
|
+
const judgment = judgeNeighbor({ neighbor, lastSeenAt: signal?.at ?? watch.first_at, now });
|
|
61
|
+
const expired = !!signal?.ends_at && Date.parse(signal.ends_at) <= now.getTime();
|
|
62
|
+
// A declared lease (ends_at in the future) outranks the heartbeat interval: a scheduled loop idle between
|
|
63
|
+
// windows is not absent until its own declared end passes.
|
|
64
|
+
const leased = !!signal?.ends_at && !expired;
|
|
65
|
+
const absent = expired || signal?.health === 'degraded' || (!leased && judgment.state === 'absent');
|
|
66
|
+
if (!absent) { store.db.exec('COMMIT'); continue; }
|
|
67
|
+
const reason = expired ? 'end-expired' : signal?.health === 'degraded' ? 'degraded' : judgment.reason;
|
|
68
|
+
const signalAt = signal?.at ?? watch.first_at;
|
|
69
|
+
const { action, delegateTo: to } = neighbor.onAbsent;
|
|
70
|
+
const inserted = store.db.query(`INSERT OR IGNORE INTO loop_incidents(observer, neighbor, signal_at, reason, action, recipient, at)
|
|
71
|
+
VALUES(?, ?, ?, ?, ?, ?, ?)`).run(observer, neighbor.id, signalAt, reason, action, to, now.toISOString());
|
|
72
|
+
if (inserted.changes) {
|
|
73
|
+
const incident: NeighborIncident = { observer, neighbor: neighbor.id, state: 'absent', reason, action, to,
|
|
74
|
+
at: now.toISOString(), lastSeenAt: signal?.at ?? null };
|
|
75
|
+
store.append({ from: observer, to, kind: `neighbor-${action}`,
|
|
76
|
+
body: `[${observer} → ${to}] ${neighbor.id} ${reason}: ${action}` });
|
|
77
|
+
incidents.push(incident);
|
|
78
|
+
}
|
|
79
|
+
store.db.exec('COMMIT');
|
|
80
|
+
} catch (error) {
|
|
81
|
+
try { store.db.exec('ROLLBACK'); } catch { /* no open transaction */ }
|
|
82
|
+
debug.log('loop.neighbors', 'check-failed', { observer, neighbor: neighbor.id, error: String(error) }, { level: 'warn' });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const incident of incidents) debug.log('loop.neighbors', 'absent', incident, { level: 'warn' });
|
|
86
|
+
return incidents;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
@@ -12,7 +12,7 @@ import { getUserConfig, ORCHESTRATOR_DEFAULTS, type OrchestratorSeat } from '../
|
|
|
12
12
|
import { checkAuthorInput } from './author-input-check.js';
|
|
13
13
|
import { AuthorLedger } from './author-ledger.js';
|
|
14
14
|
import { collectWork, findOverlaps, type WorkItem } from './overlap.js';
|
|
15
|
-
import { seatOfTree, trafficTick, TRAFFIC_SEATS } from './traffic.js';
|
|
15
|
+
import { isTrafficLaunch, seatOfTree, trafficTick, TRAFFIC_SEATS } from './traffic.js';
|
|
16
16
|
|
|
17
17
|
export type AuthorCell = Pick<ChecklistItem, 'id' | 'title' | 'owner' | 'status' | 'evidence'> & { version: string };
|
|
18
18
|
export type AuthorQueueRow = Pick<QueueItem, 'seat' | 'status'> & Partial<Pick<QueueItem, 'input' | 'kind'>>;
|
|
@@ -101,8 +101,12 @@ export interface CollectAuthorDepthDeps {
|
|
|
101
101
|
versions?: () => readonly [string, string];
|
|
102
102
|
ledger?: Pick<AuthorLedger, 'request'>;
|
|
103
103
|
log?: (category: string, event: string, data: Record<string, unknown>) => void;
|
|
104
|
+
listProcesses?: typeof defaultListHarnessProcesses;
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
/** Budget for the shadow's process read (it runs inside the queue lock, whose waiters give up after 30 s). */
|
|
108
|
+
export const AUTHOR_DEPTH_PROCESS_DEADLINE_MS = 10_000;
|
|
109
|
+
|
|
106
110
|
function defaultVersions(now: Date, root = releaseLedgerRoot()): readonly [string, string] {
|
|
107
111
|
if (!existsSync(join(root, 'release', 'features.sqlite'))) throw new Error('release schedule ledger unavailable');
|
|
108
112
|
const upcoming = listSchedules(root).filter(row => row.cutAt && Date.parse(row.cutAt) > now.getTime())
|
|
@@ -122,15 +126,6 @@ export function collectAuthorDepth(deps: CollectAuthorDepthDeps = {}): AuthorDep
|
|
|
122
126
|
};
|
|
123
127
|
const cfg = deps.caps && deps.running ? null : observe('config', () => getUserConfig().loops?.orchestrator ?? ORCHESTRATOR_DEFAULTS);
|
|
124
128
|
const caps = deps.caps ? observe('caps', deps.caps) : cfg === null ? null : observe('caps', () => cfg.seatCaps);
|
|
125
|
-
const running = deps.running ? observe('running', deps.running) : cfg === null ? null : observe('running', () => {
|
|
126
|
-
const observation = defaultListHarnessProcesses();
|
|
127
|
-
if (observation.status !== 'ok') throw new Error(`process observation ${observation.status}`);
|
|
128
|
-
const processes = observation.records.map(process => ({ ...process,
|
|
129
|
-
seat: seatOfTree(process.cwdStatus === 'unknown' ? undefined : process.cwd, cfg) }));
|
|
130
|
-
const measured = trafficTick({ processes, now, caps: cfg.seatCaps, openCells: [] });
|
|
131
|
-
if (measured.unassigned) throw new Error(`${measured.unassigned} unassigned harness launch process(es)`);
|
|
132
|
-
return Object.fromEntries(measured.seats.map(row => [row.seat, row.running]));
|
|
133
|
-
});
|
|
134
129
|
const queued = observe('queue', deps.queued ?? (() => listHarnessQueue({ root: deps.root })));
|
|
135
130
|
const releaseRoot = deps.root ?? releaseLedgerRoot();
|
|
136
131
|
const versions = observe('versions', deps.versions ?? (() => defaultVersions(now, releaseRoot)));
|
|
@@ -139,7 +134,30 @@ export function collectAuthorDepth(deps: CollectAuthorDepthDeps = {}): AuthorDep
|
|
|
139
134
|
throw new Error('checklist ledger unavailable');
|
|
140
135
|
return deps.cells?.(version) ?? listChecklist(version, deps.root).items.map(item => ({ ...item, version }));
|
|
141
136
|
}));
|
|
142
|
-
|
|
137
|
+
// Without release cells there is no candidate to compare, and the host reads below are the expensive ones (every launch's
|
|
138
|
+
// cwd · open PRs over the network) — a fresh --test universe has no release ledger, so it skips them (10-08 tick hang).
|
|
139
|
+
const noCells = cells === null && !deps.cells;
|
|
140
|
+
if (noCells && !deps.running && cfg !== null) unreadable.push({ source: 'running', reason: 'skipped: no release cells to compare' });
|
|
141
|
+
const running = deps.running ? observe('running', deps.running) : cfg === null || noCells ? null : observe('running', () => {
|
|
142
|
+
// Only launch processes are counted, so only they need a cwd; the whole read is bounded because the queue tick runs
|
|
143
|
+
// this shadow inside its lock (10-08: ~490 host processes × lsof kept a --test tick for minutes).
|
|
144
|
+
const started = Date.now();
|
|
145
|
+
const observation = (deps.listProcesses ?? defaultListHarnessProcesses)({ include: record => isTrafficLaunch(record.command),
|
|
146
|
+
cwdOnly: true, deadlineMs: AUTHOR_DEPTH_PROCESS_DEADLINE_MS });
|
|
147
|
+
if (observation.status !== 'ok') throw new Error(`process observation ${observation.status}`);
|
|
148
|
+
const late = observation.records.filter(process => process.cwdFailureReason?.startsWith('observation deadline')).length;
|
|
149
|
+
(deps.log ?? ((category: string, event: string, data: Record<string, unknown>) => debug.log(category, event, data)))(
|
|
150
|
+
'loop.orchestrator', 'author-depth-processes', { launches: observation.records.length, late, ms: Date.now() - started,
|
|
151
|
+
deadlineMs: AUTHOR_DEPTH_PROCESS_DEADLINE_MS });
|
|
152
|
+
if (late) throw new Error(`process observation deadline ${AUTHOR_DEPTH_PROCESS_DEADLINE_MS}ms: ${late} launch cwd(s) unread`);
|
|
153
|
+
const processes = observation.records.map(process => ({ ...process,
|
|
154
|
+
seat: seatOfTree(process.cwdStatus === 'unknown' ? undefined : process.cwd, cfg) }));
|
|
155
|
+
const measured = trafficTick({ processes, now, caps: cfg.seatCaps, openCells: [] });
|
|
156
|
+
if (measured.unassigned) throw new Error(`${measured.unassigned} unassigned harness launch process(es)`);
|
|
157
|
+
return Object.fromEntries(measured.seats.map(row => [row.seat, row.running]));
|
|
158
|
+
});
|
|
159
|
+
if (noCells && !deps.overlaps) unreadable.push({ source: 'overlap', reason: 'skipped: no release cells to compare' });
|
|
160
|
+
const overlaps = noCells && !deps.overlaps ? null : observe('overlap', deps.overlaps ?? (() => {
|
|
143
161
|
const observed = collectWork();
|
|
144
162
|
if (observed.unreadableTrees || observed.unreadableGoals || observed.work.some(item => item.unreadable))
|
|
145
163
|
throw new Error(`incomplete work observation: trees=${observed.unreadableTrees} goals=${observed.unreadableGoals}`);
|