elanous 0.2.19 → 0.2.21
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/MObU8ujkMciAKr6ljAV05/_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/{4323.c5dfb6f503304775.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.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/1826-5d279da64bbbc2de.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/195-fb1d7690bf30bab4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2977-e38442e86289f1d3.js → 211-9c9090c59e2c5907.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.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 +1 -0
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
- 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/2699-325cc923ba7b8631.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/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.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/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.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/4144-fad095b48a1862ee.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/4565-3d7e3fdeb43686a8.js +1 -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/4795-f372490b178583fc.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/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-59fedea50d13c762.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/{4847.56f5bc454fbcc827.js → 6110.1297d4093fdfbb0d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6158.566c890adc06a459.js +2 -0
- 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/6877-74399f69c7da1433.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/{1470.98a6ab61ccb4131c.js → 726.83532d69452ee24b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 7327-2d69fb321ba73389.js} +1 -1
- 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/7797-df5aa0381fdc078f.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/8060-cc008cc6fedfa818.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.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/8401-35e94e9091f5eb8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
- package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.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/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7647.2fcd30d894d5ee30.js → 935.4ddaa99fc1d1126c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +1 -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/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-111cabe4d1fd69ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-b70cd005d9169e25.js → page-be8b4615c919e36c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2ea96958.e8c7e112de50b067.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.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/e81df11490b4413b.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +24 -24
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +23 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- 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 +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/demo/editor-recipes.yaml +22 -0
- package/graphs/drafts/recipes.yaml +4 -4
- package/graphs/implement-loop.yaml +277 -5
- package/graphs/retro/daily.yaml +25 -0
- package/graphs/retro/recipes.yaml +24 -0
- package/package.json +1 -1
- package/scripts/ask-marker-check.ts +3 -1
- package/scripts/coord-channel-watch.sh +31 -4
- package/scripts/docs-lint.ts +4 -1
- package/scripts/land-global-checks.ts +89 -0
- package/scripts/lib/pch-regress-map.ts +2 -1
- package/scripts/marketing/generate-ax-brief.ts +18 -1
- package/scripts/measure-nl-routing-corpus.ts +11 -3
- package/scripts/release-loop/gate-node.ts +296 -25
- package/scripts/release-loop/gate-timing.ts +116 -7
- package/scripts/release-loop/preflight.ts +6 -4
- package/scripts/release-loop/publish-window.ts +141 -0
- package/scripts/release-loop/release-docs.ts +1 -4
- package/scripts/release-loop/release-universe.ts +38 -0
- package/scripts/release-loop/resume-release.ts +4 -1
- package/scripts/release-loop/shard-plan.ts +50 -5
- package/scripts/release-loop/unattended-release.ts +10 -2
- package/scripts/release-story/draft.ts +5 -1
- package/scripts/retro/shadow-compare.ts +71 -0
- package/scripts/rhythm/daily.ts +8 -2
- package/src/agent-mission/driver.ts +34 -6
- package/src/autopilot/build/llm-conflict-merge.ts +132 -7
- package/src/autopilot/build/merge-intent.ts +135 -7
- package/src/away/release-watch.ts +20 -3
- package/src/browser-cdp/client.ts +10 -5
- package/src/cli/config-drift.ts +513 -0
- package/src/cli/log-event-names.ts +4 -0
- 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 +20 -0
- package/src/cli/release-cli.ts +20 -5
- package/src/cli/retro-cli.ts +78 -0
- package/src/cli/tasks-cli.ts +200 -8
- package/src/dashboard/index.ts +40 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -4
- package/src/dashboard/slash-runtime/help-from-registry.ts +57 -31
- package/src/domains/outbound-log-probe.ts +6 -1
- package/src/esc-abort-gate.ts +3 -1
- package/src/graph-runner/graph-cli.ts +57 -0
- package/src/graph-runner/graph-run-api.ts +218 -0
- package/src/graph-runner/runner.ts +11 -1
- package/src/graph-wizard/archetypes.ts +88 -0
- package/src/graph-wizard/generate.ts +545 -0
- package/src/graph-wizard/saved-steps.ts +120 -0
- package/src/graph-wizard/steps.ts +193 -0
- package/src/harness/harness-cli-command.ts +482 -59
- package/src/harness/harness-queue.ts +315 -25
- package/src/harness/harness-salvage-cli.ts +62 -0
- package/src/hq/fence-outcomes.ts +63 -0
- package/src/hq/fence-wrapper.ts +33 -0
- package/src/hq/hq.ts +11 -1
- package/src/index.ts +76 -10
- package/src/intake-plane/digest.ts +18 -11
- package/src/maturity/feature-maturity.ts +4 -3
- package/src/nexus/api/draft-metrics.ts +114 -0
- package/src/nexus/api/graph-kinds.ts +10 -4
- package/src/nexus/api/graph-wizard-api.ts +53 -0
- package/src/nexus/api/graphs-api.ts +220 -10
- package/src/nexus/api/harness-traversal.ts +205 -0
- package/src/nexus/api/http-server.ts +69 -3
- package/src/nexus/api/loop-edges.ts +4 -2
- package/src/nexus/api/ops-api.ts +22 -7
- package/src/nexus/api/ops-board-route.ts +48 -0
- package/src/nexus/outbound/router.ts +28 -8
- package/src/onboarding/entry-hints.ts +5 -0
- package/src/onboarding/first-run.ts +3 -0
- package/src/onboarding.ts +24 -6
- 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/release-loop/feature-store.ts +14 -11
- package/src/release-loop/gate-shards.ts +163 -0
- package/src/release-loop/release-schedule.ts +6 -2
- package/src/retro/daily.ts +372 -0
- package/src/seat-loop/op-decide.ts +173 -0
- package/src/seat-loop/seat-loop.ts +60 -3
- package/src/seat-loop/seat-report.ts +58 -3
- package/src/self-dev/ask-launch-flow.ts +9 -6
- package/src/self-dev/ask-launch-io.ts +52 -2
- package/src/self-dev/ask-path-candidates.ts +40 -2
- package/src/self-dev/draft-sweep.ts +371 -16
- package/src/self-dev/draft-triage-rules.ts +19 -4
- 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/pr-preview.ts +84 -16
- package/src/self-dev/release-path-guard.ts +7 -4
- package/src/self-implement/blocked-draft-policy.ts +101 -0
- package/src/self-implement/execution-clarification.ts +11 -0
- package/src/self-implement/frozen-merges.ts +23 -0
- package/src/self-implement/gate-env-retry.ts +83 -0
- package/src/self-implement/goal-author.ts +14 -0
- package/src/self-implement/heal-intake.ts +3 -0
- package/src/self-implement/orchestrator.ts +234 -6
- package/src/self-implement/run-stop.ts +123 -0
- package/src/self-implement/run-ttl.ts +258 -0
- package/src/self-implement/salvage-retention.ts +123 -0
- package/src/self-implement/seams.ts +7 -0
- package/src/self-implement/self-implement-cli.ts +2 -0
- package/src/self-implement/self-implement-runtime.ts +12 -0
- package/src/self-implement/sibling-resync.ts +223 -0
- package/src/self-implement/stop-autoheal.ts +204 -0
- package/src/session-runtime/index.ts +5 -3
- package/src/shell-env-bootstrap.ts +17 -3
- package/src/task-agent/board.ts +1 -1
- package/src/task-agent/card-evidence.ts +105 -10
- package/src/task-agent/judge.ts +7 -0
- package/src/task-agent/live-moves.ts +120 -20
- package/src/task-agent/mission.ts +1 -1
- package/src/task-agent/parent-host.ts +315 -0
- package/src/task-agent/shadow.ts +10 -1
- package/src/task-agent/task-hand.ts +16 -4
- package/src/task-orchestrator/surfaces/pod-command-job.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -10
- package/src/task-orchestrator/surfaces/pod-pool.ts +147 -34
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +58 -9
- package/src/telegram-commands.ts +41 -0
- package/src/testing/real-cli-spawn.ts +106 -0
- package/src/tool-runtime/browser-runtime.ts +87 -3
- package/src/tool-runtime/index.ts +1 -0
- package/src/user-config.ts +76 -7
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +0 -1
- package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-e061bb24cd2b5cde.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +0 -2
- package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +0 -25
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +0 -1
- package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +0 -1
- /package/apps/pwa/out/_next/static/{J5H7BvqgSI8DUjtRRcA_S → MObU8ujkMciAKr6ljAV05}/_ssgManifest.js +0 -0
- /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// LOOPCHECK-FENCE (0.2.20): an hq-fence cron execution is one process, not a loop.
|
|
2
|
+
// Each wrapped run leaves its rc in a per-role streak file; the wrapper's owner alert
|
|
3
|
+
// raises a seat request only when the same role failed in consecutive runs, keyed per
|
|
4
|
+
// role so the seat request journal holds at most one `loopcheck:hq-fence:<role>` per day.
|
|
5
|
+
// No loops/ import here: hq.ts records through this module and loops/registry imports hq.ts.
|
|
6
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { Database } from 'bun:sqlite';
|
|
9
|
+
import { debug } from '../debug/log.js';
|
|
10
|
+
|
|
11
|
+
/** The role is the file name; `lastAt` is shown in the owner alert so TC sees when the streak last grew. */
|
|
12
|
+
export interface FenceOutcome { consecutiveFailures: number; lastRc: number; lastAt: string }
|
|
13
|
+
|
|
14
|
+
/** Two failures in a row: one rc=1 from a job that recovers on the next fire is not a fence fault. */
|
|
15
|
+
export const FENCE_FAILURE_STREAK = 2;
|
|
16
|
+
|
|
17
|
+
const safeRole = (role: string): string => role.replace(/[^\w.-]/g, '_') || 'unknown';
|
|
18
|
+
|
|
19
|
+
export function fenceOutcomePath(dir: string, role: string): string {
|
|
20
|
+
return join(dir, `${safeRole(role)}.json`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Default directory next to the host-local lease view (`<config>/hq/fence-outcomes`). */
|
|
24
|
+
export function fenceOutcomeDir(localPath: string): string {
|
|
25
|
+
return join(dirname(localPath), 'fence-outcomes');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function readFenceOutcome(dir: string, role: string): FenceOutcome | null {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(readFileSync(fenceOutcomePath(dir, role), 'utf8')) as Partial<FenceOutcome>;
|
|
31
|
+
return typeof parsed.consecutiveFailures === 'number' ? parsed as FenceOutcome : null;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
|
|
34
|
+
debug.log('hq.fence-outcome', 'read-failed', { role, error: String(error) });
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** rc 0 resets the streak; any other rc extends it. A skipped (not-holder) run is not recorded.
|
|
40
|
+
* Overlapping runs of one role serialize the read-modify-write on an SQLite lock (released even on SIGKILL). */
|
|
41
|
+
export function recordFenceOutcome(dir: string, role: string, rc: number, now: Date = new Date()): FenceOutcome {
|
|
42
|
+
const path = fenceOutcomePath(dir, role);
|
|
43
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
44
|
+
const lock = new Database(`${path}.lock.sqlite`);
|
|
45
|
+
try {
|
|
46
|
+
lock.exec('PRAGMA busy_timeout = 10000');
|
|
47
|
+
lock.exec('BEGIN EXCLUSIVE');
|
|
48
|
+
try {
|
|
49
|
+
const previous = readFenceOutcome(dir, role);
|
|
50
|
+
const outcome: FenceOutcome = { consecutiveFailures: rc === 0 ? 0 : (previous?.consecutiveFailures ?? 0) + 1, lastRc: rc, lastAt: now.toISOString() };
|
|
51
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
52
|
+
writeFileSync(tmp, JSON.stringify(outcome));
|
|
53
|
+
renameSync(tmp, path);
|
|
54
|
+
lock.exec('COMMIT');
|
|
55
|
+
return outcome;
|
|
56
|
+
} catch (error) { lock.exec('ROLLBACK'); throw error; }
|
|
57
|
+
} finally { lock.close(); }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** `hq-fence: fence failed (rc=1, role=seat-loop)` → `seat-loop`; other wrapper reasons have no role. */
|
|
61
|
+
export function fenceAlertRole(reason: string): string | null {
|
|
62
|
+
return /\brole=([\w.-]+)/.exec(reason)?.[1] ?? null;
|
|
63
|
+
}
|
package/src/hq/fence-wrapper.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { chmodSync, constants, copyFileSync, lstatSync, mkdirSync, mkdtempSync,
|
|
|
3
3
|
import { dirname, isAbsolute, join } from 'node:path';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { createPatch } from 'diff';
|
|
6
|
+
import { debug } from '../debug/log.js';
|
|
7
|
+
import { notifyOwners } from '../loops/checker.js';
|
|
8
|
+
import { FENCE_FAILURE_STREAK, fenceAlertRole, readFenceOutcome } from './fence-outcomes.js';
|
|
6
9
|
|
|
7
10
|
const quote = (value: string): string => `'${value.replaceAll("'", "'\"'\"'")}'`;
|
|
8
11
|
|
|
@@ -121,3 +124,33 @@ export function installHqFenceWrapper(configDir: string, body: string, yes: bool
|
|
|
121
124
|
} finally { rmSync(tempDir, { recursive: true, force: true }); }
|
|
122
125
|
return { path, preview, ...(backup ? { backup } : {}) };
|
|
123
126
|
}
|
|
127
|
+
|
|
128
|
+
export interface FenceAlertDeps { root: string; outcomeDir: string; now?: Date }
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The wrapper's owner alert. Returns the number of seat requests queued (0 or 1).
|
|
132
|
+
* - `fence failed (rc, role)`: queued only when that role's streak reached FENCE_FAILURE_STREAK
|
|
133
|
+
* (an unknown streak is not read as «first failure» — it is queued, still capped per role/day).
|
|
134
|
+
* - Any other wrapper failure (entry missing, bun missing, role missing): queued under `hq-fence:wrapper`.
|
|
135
|
+
*/
|
|
136
|
+
export function hqFenceAlert(reason: string, deps: FenceAlertDeps): number {
|
|
137
|
+
const now = deps.now ?? new Date();
|
|
138
|
+
const fenceFailure = /fence failed \(rc=/.test(reason);
|
|
139
|
+
const role = fenceAlertRole(reason);
|
|
140
|
+
let streak: number | null = null;
|
|
141
|
+
let lastAt: string | undefined;
|
|
142
|
+
if (fenceFailure && role) {
|
|
143
|
+
const outcome = readFenceOutcome(deps.outcomeDir, role);
|
|
144
|
+
streak = outcome?.consecutiveFailures ?? null;
|
|
145
|
+
lastAt = outcome?.lastAt;
|
|
146
|
+
if (streak !== null && streak < FENCE_FAILURE_STREAK) {
|
|
147
|
+
debug.log('hq.fence-wrapper', 'alert-suppressed', { role, streak, threshold: FENCE_FAILURE_STREAK, reason });
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const id = `hq-fence:${fenceFailure && role ? role : 'wrapper'}`;
|
|
152
|
+
const text = streak !== null ? `${reason} · ${streak} consecutive runs (last ${lastAt ?? 'unknown'})` : reason;
|
|
153
|
+
const added = notifyOwners([{ id, owner: 'TC', enabled: true, registered: true, state: 'failing', reason: text }], { root: deps.root, now });
|
|
154
|
+
debug.log('hq.fence-wrapper', added ? 'alert-queued' : 'alert-deduplicated', { id, role, streak, reason });
|
|
155
|
+
return added;
|
|
156
|
+
}
|
package/src/hq/hq.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { debug } from '../debug/log.js';
|
|
|
10
10
|
import { DEFAULT_NEXUS_HTTP_PORT } from '../nexus/default-port.js';
|
|
11
11
|
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
12
12
|
import { getUserConfig, type HqConfig, type HqFenceRole } from '../user-config.js';
|
|
13
|
+
import { fenceOutcomeDir, recordFenceOutcome } from './fence-outcomes.js';
|
|
13
14
|
import { promoteHq, proposeHqPromotion, writeOpSeatRequest } from './promote.js';
|
|
14
15
|
import type { HqOpRequestWriter, PromoteResult } from './promote.js';
|
|
15
16
|
import {
|
|
@@ -42,6 +43,8 @@ export interface HqDeps {
|
|
|
42
43
|
/** Holder/standby views and the arbiter's check use this tailnet probe — never ssh (OP 10-04 09:04). */
|
|
43
44
|
probe?: HostProbe;
|
|
44
45
|
localPath?: string;
|
|
46
|
+
/** Per-role streak files of wrapped-run rc (LOOPCHECK-FENCE · default next to localPath). */
|
|
47
|
+
outcomeDir?: string;
|
|
45
48
|
/** Host-local identity, deliberately outside the replicated config/state directory. */
|
|
46
49
|
hostPath?: string;
|
|
47
50
|
/** Seen-generation marker (default hq.seenGenerationFile · ~/.elanous-hq/seen-generation). */
|
|
@@ -391,5 +394,12 @@ export function hqFenceRun(role: HqFenceRole, command: string[], deps: HqDeps =
|
|
|
391
394
|
const [cmd, ...args] = command;
|
|
392
395
|
if (!cmd) throw new Error('hq fence: command required after --');
|
|
393
396
|
const r = spawnSync(cmd, args, { stdio: 'inherit', env: { ...process.env, ELANOUS_HQ_GENERATION: String(decided.generation ?? '') } });
|
|
394
|
-
|
|
397
|
+
const rc = r.status ?? 1;
|
|
398
|
+
// LOOPCHECK-FENCE: the wrapper's alert reads this streak, so a lone failure is not a seat request.
|
|
399
|
+
try {
|
|
400
|
+
const dir = deps.outcomeDir ?? fenceOutcomeDir(deps.localPath ?? join(getElanousConfigDir(), 'hq', 'local.json'));
|
|
401
|
+
const outcome = recordFenceOutcome(dir, role, rc, new Date(deps.now?.() ?? Date.now()));
|
|
402
|
+
if (rc !== 0) debug.log('hq.fence', 'run-failed', { role, rc, consecutiveFailures: outcome.consecutiveFailures });
|
|
403
|
+
} catch (error) { try { debug.log('hq.fence', 'outcome-record-failed', { role, rc, error: String(error) }); } catch { /* fail-soft */ } }
|
|
404
|
+
return rc;
|
|
395
405
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { SelfDevRunParticipant, SelfDevRunState } from './self-dev/run-stor
|
|
|
7
7
|
import { applyConfigDirFlagFromArgv } from './cli/config-dir-flag.js';
|
|
8
8
|
import { LOGS_SINCE_OPTION, registerLogsCommands } from './cli/logs-cli.js';
|
|
9
9
|
import { registerDocsCommands } from './cli/docs-cli.js';
|
|
10
|
+
import { registerRetroCommands } from './cli/retro-cli.js';
|
|
10
11
|
import { registerA2ACommands } from './cli/a2a-cli.js';
|
|
11
12
|
import { registerPluginCommands } from './cli/plugin-cli.js';
|
|
12
13
|
import { registerMakeCommand } from './cli/make-cli.js';
|
|
@@ -219,13 +220,14 @@ program.enablePositionalOptions();
|
|
|
219
220
|
|
|
220
221
|
program.command('preview <target>')
|
|
221
222
|
.description('Isolated PR/branch-head TUI + PWA preview; publish the TUI-COMFORT friction table to a PR')
|
|
222
|
-
.option('--scenario <id>', 'TUI-COMFORT scenario (default S2)', 'S2')
|
|
223
|
+
.option('--scenario <id>', 'TUI-COMFORT scenario IDs (comma-separated; default S2)', 'S2')
|
|
223
224
|
.option('--flag <path>', 'Enable an existing config feature flag in main-based preview (repeatable)', (value: string, all: string[]) => [...all, value], [] as string[])
|
|
225
|
+
.option('--bundle-pr <number>', 'Merge PR head into isolated main preview (repeatable; no flags)', (value: string, all: number[]) => [...all, Number(value)], [] as number[])
|
|
224
226
|
.option('--comment-pr <number>', 'PR to receive a branch/main preview report', (value: string) => Number(value))
|
|
225
|
-
.action(async (target: string, opts: { scenario: string; flag: string[]; commentPr?: number }) => {
|
|
227
|
+
.action(async (target: string, opts: { scenario: string; flag: string[]; bundlePr: number[]; commentPr?: number }) => {
|
|
226
228
|
try {
|
|
227
229
|
const { runPrPreview } = await import('./self-dev/pr-preview.js');
|
|
228
|
-
const result = await runPrPreview({ target, repoRoot: process.cwd(), scenario: opts.scenario, flags: opts.flag, ...(opts.commentPr === undefined ? {} : { commentPr: opts.commentPr }) });
|
|
230
|
+
const result = await runPrPreview({ target, repoRoot: process.cwd(), scenario: opts.scenario, flags: opts.flag, bundlePrs: opts.bundlePr, ...(opts.commentPr === undefined ? {} : { commentPr: opts.commentPr }) });
|
|
229
231
|
console.log(`preview ${result.status} · ${result.head} · PR #${result.prNumber} · comment posted`);
|
|
230
232
|
if (result.status !== 'passed') process.exitCode = 1;
|
|
231
233
|
} catch (error) {
|
|
@@ -1059,10 +1061,12 @@ fenceWrapperCmd.command('install').description('래퍼 제안 또는 백업 후
|
|
|
1059
1061
|
fenceWrapperCmd.command('alert <reason>').description('HQ 울타리 실패를 기존 루프 소유자 요청 원장에 적재')
|
|
1060
1062
|
.action(async (reason: string) => {
|
|
1061
1063
|
try {
|
|
1062
|
-
|
|
1064
|
+
// LOOPCHECK-FENCE: keyed per role (not per pid) and only after consecutive failures of that role.
|
|
1065
|
+
const { fenceOutcomeDir } = await import('./hq/fence-outcomes.js');
|
|
1066
|
+
const { hqFenceAlert } = await import('./hq/fence-wrapper.js');
|
|
1063
1067
|
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
1064
|
-
|
|
1065
|
-
|
|
1068
|
+
const root = getElanousConfigDir();
|
|
1069
|
+
hqFenceAlert(reason, { root, outcomeDir: fenceOutcomeDir(_joinPath(root, 'hq', 'local.json')) });
|
|
1066
1070
|
} catch (error) { console.error(`hq fence-wrapper alert: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1067
1071
|
});
|
|
1068
1072
|
hqCmd.command('fence-audit').description('운영 crontab 의 HQ 울타리 밖 쓰기 잡 목록과 감싼 줄 제안(읽기 전용)')
|
|
@@ -1905,6 +1909,7 @@ program
|
|
|
1905
1909
|
});
|
|
1906
1910
|
|
|
1907
1911
|
registerAutopilotCommands(program);
|
|
1912
|
+
registerRetroCommands(program);
|
|
1908
1913
|
|
|
1909
1914
|
// ── memory ──
|
|
1910
1915
|
const memCmd = program.command('memory').description('Persistent memories injected into every chat turn (user / feedback / project / reference)');
|
|
@@ -4460,8 +4465,10 @@ selfCmd
|
|
|
4460
4465
|
};
|
|
4461
4466
|
try {
|
|
4462
4467
|
const { dispatchHeavyCheck } = await import('./self-implement/gate-remote.js');
|
|
4463
|
-
const {
|
|
4464
|
-
const
|
|
4468
|
+
const { runGitCommand } = await import('./git-fs/runner.js');
|
|
4469
|
+
const topLevel = runGitCommand(process.cwd(), ['rev-parse', '--show-toplevel'], { encoding: 'utf8' });
|
|
4470
|
+
if (topLevel.status !== 0) throw new Error(`git rev-parse --show-toplevel failed: ${topLevel.stderr.trim() || `rc=${topLevel.status}`}`);
|
|
4471
|
+
const repo = topLevel.stdout.trim();
|
|
4465
4472
|
// Only a committed --base range is reproducible on another host: the default mode measures uncommitted files, --pr
|
|
4466
4473
|
// reads files through gh on this host, and the remote checkout runs from the repository root — those stay local.
|
|
4467
4474
|
const { realpathSync } = await import('node:fs');
|
|
@@ -4886,7 +4893,7 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4886
4893
|
// ☸️ 풀이 «원격 노드뿐»이면 이 기계의 이미지는 아무도 안 쓴다 — 로컬 판정·굽기를 건너뛰고 기준 판 = HEAD 로 노드 동기화만 한다.
|
|
4887
4894
|
// 🩸 2026-09-26 실측: 원격 전용 풀인데 로컬 이미지가 없다고 로컬에서 굽다가 로컬 클러스터(elanous-h1)가 없어 런이 시작도 전에 죽었다.
|
|
4888
4895
|
const remoteOnlyPool = poolMembers.length > 0 && poolMembers.every((m) => Boolean(m.sshHost));
|
|
4889
|
-
const headCommit = remoteOnlyPool ? ((await import('
|
|
4896
|
+
const headCommit = remoteOnlyPool ? ((await import('./git-fs/runner.js')).runGitCommand(process.cwd(), ['rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim() || null) : null;
|
|
4890
4897
|
let image = remoteOnlyPool
|
|
4891
4898
|
? { imageCommit: headCommit, headCommit, fresh: true, reason: 'remote-only pool — 노드 쪽에서 맞춘다' }
|
|
4892
4899
|
: podImageFreshness();
|
|
@@ -4896,7 +4903,8 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4896
4903
|
} else {
|
|
4897
4904
|
if (!opts.json) ui.info(`[pod] 이미지 다시 굽기 — ${image.reason} (~1분)`);
|
|
4898
4905
|
const { spawnSync } = await import('node:child_process');
|
|
4899
|
-
const
|
|
4906
|
+
const { runGitCommand } = await import('./git-fs/runner.js');
|
|
4907
|
+
const top = runGitCommand(process.cwd(), ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).stdout.trim() || process.cwd();
|
|
4900
4908
|
// bun 1.4 applies the 1 MiB default maxBuffer: a docker build log past it kills the child (ENOBUFS · status null).
|
|
4901
4909
|
const b = spawnSync('bash', [`${top}/docker/harness/build.sh`], { encoding: 'utf8', timeout: 900_000, maxBuffer: 64 * 1024 * 1024 });
|
|
4902
4910
|
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); }
|
|
@@ -7679,6 +7687,11 @@ configCmd
|
|
|
7679
7687
|
.description('Print all config or one dotted path, e.g. llm.provider (secrets redacted by default)')
|
|
7680
7688
|
.option('--reveal', 'Print unredacted output and record the reveal')
|
|
7681
7689
|
.action(async (path: string | undefined, opts: { reveal?: boolean }) => {
|
|
7690
|
+
const { resolveCurrentInstance } = await import('./instance/current.js');
|
|
7691
|
+
const instance = resolveCurrentInstance();
|
|
7692
|
+
if (instance.kind === 'test' && instance.layer === 'tree-derived') {
|
|
7693
|
+
console.error('⚠️ test 우주의 config를 읽습니다 — 운영 값은 --config-dir ~/.elanous');
|
|
7694
|
+
}
|
|
7682
7695
|
const cfg = getUserConfig() as unknown as Record<string, unknown>;
|
|
7683
7696
|
const value = path ? getConfigPath(cfg, path) : cfg;
|
|
7684
7697
|
if (value === undefined) {
|
|
@@ -7773,6 +7786,59 @@ configCmd
|
|
|
7773
7786
|
ui.info(`unset ${path}`);
|
|
7774
7787
|
});
|
|
7775
7788
|
|
|
7789
|
+
// ── config drift / explain (CFG-STORE1 · 0.2.20 · 2026-10-08) — 읽기 전용 «유효 config ⊕ 출처» ──
|
|
7790
|
+
// 집(~/.elanous)과 파생 시험 우주(<트리>/.elanous-test) config 사본의 드리프트를 한 명령으로.
|
|
7791
|
+
// ⛔ 쓰기 0 · 못 읽음 ≠ 같음 · 비밀 값 가림. 계산 = src/cli/config-drift.ts.
|
|
7792
|
+
async function configDriftDiscover(o: { registry?: string | boolean; scanRoot?: string[]; treeScan?: boolean }) {
|
|
7793
|
+
const { discoverUniverses } = await import('./cli/config-drift.js');
|
|
7794
|
+
return discoverUniverses({
|
|
7795
|
+
...(o.registry === false ? { registryPath: null } : typeof o.registry === 'string' ? { registryPath: o.registry } : {}),
|
|
7796
|
+
...(o.treeScan === false ? { treeScanRoots: [] } : o.scanRoot?.length ? { treeScanRoots: o.scanRoot } : {}),
|
|
7797
|
+
});
|
|
7798
|
+
}
|
|
7799
|
+
|
|
7800
|
+
configCmd
|
|
7801
|
+
.command('drift')
|
|
7802
|
+
.description('읽기 전용 — 운영 config 와 파생 시험 우주(.elanous-test) config 사본이 다른 키 표 (CFG-STORE1)')
|
|
7803
|
+
.option('--key <key>', '이 키(또는 그 아래)만')
|
|
7804
|
+
.option('--json', 'JSON 출력')
|
|
7805
|
+
.option('--limit <n>', '표시할 키 수 (0=전부 · 기본 50)', '50')
|
|
7806
|
+
.option('--registry <path>', '인스턴스 레지스트리 경로 (기본 ~/.elanous/logs/instances.json)')
|
|
7807
|
+
.option('--scan-root <dir...>', '명시 트리 뿌리 (기본 = config-drift.ts defaultTreeScanRoots)')
|
|
7808
|
+
.option('--no-tree-scan', '트리 뿌리 훑기 끔 — 레지스트리만')
|
|
7809
|
+
.option('--no-registry', '레지스트리 끔 — 명시 트리 뿌리(자리·작업 트리)만')
|
|
7810
|
+
.option('--include-expected', 'sync-test 의 test-safe 변환(비밀 제거·발송 끔)과 _test 메타 키 차이도 드리프트로 센다')
|
|
7811
|
+
.action(async (o: { key?: string; json?: boolean; limit: string; includeExpected?: boolean; registry?: string | boolean; scanRoot?: string[]; treeScan?: boolean }) => {
|
|
7812
|
+
const { computeDrift, renderDrift } = await import('./cli/config-drift.js');
|
|
7813
|
+
const report = computeDrift(await configDriftDiscover(o), { key: o.key, includeExpected: o.includeExpected });
|
|
7814
|
+
debug.log('config.drift', 'computed', {
|
|
7815
|
+
key: o.key ?? null, rows: report.rows.length, prodStatus: report.prodStatus, ...report.universes,
|
|
7816
|
+
});
|
|
7817
|
+
debug.flush();
|
|
7818
|
+
console.log(o.json ? JSON.stringify(report, null, 2) : renderDrift(report, { limit: Number(o.limit) || 0 }));
|
|
7819
|
+
if (report.prodStatus !== 'ok') process.exit(1);
|
|
7820
|
+
});
|
|
7821
|
+
|
|
7822
|
+
configCmd
|
|
7823
|
+
.command('explain <key>')
|
|
7824
|
+
.description('읽기 전용 — 운영 값 ⊕ 출처 층 ⊕ 파생 시험 우주별 값 (CFG-STORE1)')
|
|
7825
|
+
.option('--json', 'JSON 출력')
|
|
7826
|
+
.option('--registry <path>', '인스턴스 레지스트리 경로')
|
|
7827
|
+
.option('--scan-root <dir...>', '명시 트리 뿌리')
|
|
7828
|
+
.option('--no-tree-scan', '트리 뿌리 훑기 끔 — 레지스트리만')
|
|
7829
|
+
.option('--no-registry', '레지스트리 끔 — 명시 트리 뿌리만')
|
|
7830
|
+
.action(async (key: string, o: { json?: boolean; registry?: string | boolean; scanRoot?: string[]; treeScan?: boolean }) => {
|
|
7831
|
+
const { computeExplain, renderExplain } = await import('./cli/config-drift.js');
|
|
7832
|
+
const { buildUserConfig } = await import('./user-config.js');
|
|
7833
|
+
const report = computeExplain(await configDriftDiscover(o), key, {
|
|
7834
|
+
codeDefaults: () => buildUserConfig('/nonexistent/elanous-config-drift/config.json'),
|
|
7835
|
+
});
|
|
7836
|
+
debug.log('config.explain', 'computed', { key, layer: report.prod.layer, ...report.universes });
|
|
7837
|
+
debug.flush();
|
|
7838
|
+
console.log(o.json ? JSON.stringify(report, null, 2) : renderExplain(report));
|
|
7839
|
+
if (report.prod.layer === 'prod-unreadable') process.exit(1);
|
|
7840
|
+
});
|
|
7841
|
+
|
|
7776
7842
|
// ── config 격리 sync (ISO-1 · 2026-07-13) — 운영→테스트 물질화 동기화 ──
|
|
7777
7843
|
// 격리 테스트 인스턴스는 운영 config 를 공유하지 않는다(overlay 은퇴 방향).
|
|
7778
7844
|
configCmd
|
|
@@ -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
|
}
|
|
@@ -16,10 +16,11 @@ export const FEATURE_MATURITY = {
|
|
|
16
16
|
'/today': { pwa: 'stable' },
|
|
17
17
|
'/term': { pwa: 'stable' },
|
|
18
18
|
'/live': { pwa: 'stable' },
|
|
19
|
+
'/live-run': { pwa: 'beta' }, // HARNESS-RUN-LIVE-GRAPH (0.2.21) — 하니스 런 하나가 도는 장면
|
|
19
20
|
'/market': { pwa: 'stable' },
|
|
20
21
|
'/sessions': { pwa: 'stable' },
|
|
21
22
|
'/settings': { pwa: 'beta' },
|
|
22
|
-
'/editor': { pwa: '
|
|
23
|
+
'/editor': { pwa: 'stable' }, // EDITOR-NAV-PUBLIC (0.2.21) — 데모·0순위 피처: 역할을 안 고른 기기에도 «만들기 › 편집기»
|
|
23
24
|
'/intake': { pwa: 'beta' },
|
|
24
25
|
'/trace': { pwa: 'beta' },
|
|
25
26
|
'/inside': { pwa: 'beta' },
|
|
@@ -74,7 +75,7 @@ export const FEATURE_MATURITY = {
|
|
|
74
75
|
loops: 'beta', buzz: 'beta', harness: 'stable', self: 'beta', factcheck: 'beta',
|
|
75
76
|
provider: 'stable', 'provider:set': 'beta', 'provider:restore': 'beta',
|
|
76
77
|
'provider:rotate': 'beta', 'provider:use': 'beta', 'status-bar': 'beta',
|
|
77
|
-
schedule: 'beta', guardian: 'beta', intake: 'beta', logs: 'stable', ad: 'beta', docs: 'beta',
|
|
78
|
+
schedule: 'beta', guardian: 'beta', intake: 'beta', logs: 'stable', retro: 'beta', ad: 'beta', docs: 'beta',
|
|
78
79
|
decisions: 'beta', directives: 'beta', claims: 'beta', lesson: 'beta', fleet: 'beta', ops: 'stable', outputs: 'beta', publish: 'beta',
|
|
79
80
|
env: 'beta', 'agent-mission': 'beta', dev: 'beta', keys: 'beta', finance: 'beta',
|
|
80
81
|
config: 'stable', tasks: 'stable', brief: 'beta', notify: 'beta', away: 'beta', labels: 'beta', msg: 'beta', ask: 'stable',
|
|
@@ -160,7 +161,7 @@ export const FEATURE_MATURITY = {
|
|
|
160
161
|
ping: 'stable', provider: 'stable', sessions: 'stable', fork: 'stable', resume: 'stable',
|
|
161
162
|
decisions: 'stable', work: 'stable', cancel: 'stable',
|
|
162
163
|
skills: 'beta', skill: 'beta', digest: 'beta', intake: 'beta', ad: 'beta',
|
|
163
|
-
taste: 'beta', missions: 'beta', attach: 'beta', detach: 'beta', now: 'beta', loops: 'beta', release: 'beta', away: 'beta', project: 'beta', wish: 'beta',
|
|
164
|
+
taste: 'beta', missions: 'beta', attach: 'beta', detach: 'beta', now: 'beta', loops: 'beta', runs: 'beta', release: 'beta', away: 'beta', project: 'beta', wish: 'beta',
|
|
164
165
|
brain: 'tool', cc: 'tool', cdx: 'tool', gem: 'tool', local: 'tool',
|
|
165
166
|
harness: 'ops',
|
|
166
167
|
// Existing commands outside the CXO four-grade menu list are owner-only.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { debug } from '../../debug/log.js';
|
|
3
|
+
import type { DraftMetrics } from '../../self-dev/draft-sweep.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* DRAFT-METRIC — CEO view source. Opening the page must never trigger a GitHub read:
|
|
7
|
+
* `read()` answers from memory and at most one background collection runs at a time,
|
|
8
|
+
* no more often than the TTL (or the failure back-off). The collection itself is
|
|
9
|
+
* `elanous harness drafts metrics --json` in a child process, which reads PR evidence
|
|
10
|
+
* through the batched GraphQL path (#24918) — one call per 40 drafts, no per-draft comments call.
|
|
11
|
+
*/
|
|
12
|
+
export type DraftMetricsState = 'measuring' | 'ready' | 'unavailable';
|
|
13
|
+
|
|
14
|
+
export interface DraftMetricsSnapshot {
|
|
15
|
+
/** measuring = no value yet and a collection is running · unavailable = no value and the last collection failed. */
|
|
16
|
+
readonly state: DraftMetricsState;
|
|
17
|
+
readonly metrics: DraftMetrics | null;
|
|
18
|
+
/** When the served value was collected (ISO). null without a value. */
|
|
19
|
+
readonly measuredAt: string | null;
|
|
20
|
+
/** A background collection is in flight. */
|
|
21
|
+
readonly refreshing: boolean;
|
|
22
|
+
/** Last collection failure; with a value it means the value is older than intended. */
|
|
23
|
+
readonly reason: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DraftMetricsSourceOptions {
|
|
27
|
+
readonly collect?: () => Promise<DraftMetrics>;
|
|
28
|
+
readonly ttlMs?: number;
|
|
29
|
+
readonly failureRetryMs?: number;
|
|
30
|
+
readonly now?: () => number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const DRAFT_METRICS_TTL_MS = 10 * 60_000;
|
|
34
|
+
export const DRAFT_METRICS_FAILURE_RETRY_MS = 2 * 60_000;
|
|
35
|
+
const COLLECT_TIMEOUT_MS = 5 * 60_000;
|
|
36
|
+
|
|
37
|
+
function isMetrics(value: unknown): value is DraftMetrics {
|
|
38
|
+
if (!value || typeof value !== 'object') return false;
|
|
39
|
+
const row = value as Record<string, unknown>;
|
|
40
|
+
const count = (key: string) => Number.isInteger(row[key]) && (row[key] as number) >= 0;
|
|
41
|
+
const nullableNumber = (key: string) => row[key] === null || (typeof row[key] === 'number' && Number.isFinite(row[key]));
|
|
42
|
+
return count('inventory') && count('needsOwner') && count('converted48h') && count('cohort48h')
|
|
43
|
+
&& nullableNumber('oldestAgeHours') && nullableNumber('conversion48h');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Parses the CLI's single JSON line; anything else is a failed collection, never a zero. */
|
|
47
|
+
export function parseDraftMetricsOutput(stdout: string): DraftMetrics {
|
|
48
|
+
const line = stdout.trim().split('\n').reverse().find((text) => text.trim().startsWith('{'));
|
|
49
|
+
if (!line) throw new Error('draft metrics: no JSON output');
|
|
50
|
+
const parsed: unknown = JSON.parse(line);
|
|
51
|
+
if (!isMetrics(parsed)) throw new Error('draft metrics: malformed output');
|
|
52
|
+
const { inventory, oldestAgeHours, needsOwner, converted48h, cohort48h, conversion48h } = parsed;
|
|
53
|
+
return { inventory, oldestAgeHours, needsOwner, converted48h, cohort48h, conversion48h };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function collectViaCli(): Promise<DraftMetrics> {
|
|
57
|
+
const root = join(import.meta.dir, '../../..');
|
|
58
|
+
const proc = Bun.spawn(['bun', join(root, 'bin/elanous.mjs'), 'harness', 'drafts', 'metrics', '--json'], {
|
|
59
|
+
cwd: root, stdout: 'pipe', stderr: 'pipe',
|
|
60
|
+
});
|
|
61
|
+
const timer = setTimeout(() => proc.kill(), COLLECT_TIMEOUT_MS);
|
|
62
|
+
try {
|
|
63
|
+
const [stdout, stderr, exitCode] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
|
|
64
|
+
if (exitCode !== 0) throw new Error(stderr.trim().split('\n').at(-1) || `draft metrics exited ${exitCode}`);
|
|
65
|
+
return parseDraftMetricsOutput(stdout);
|
|
66
|
+
} finally { clearTimeout(timer); }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface DraftMetricsSource {
|
|
70
|
+
read(): DraftMetricsSnapshot;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createDraftMetricsSource(options: DraftMetricsSourceOptions = {}): DraftMetricsSource {
|
|
74
|
+
const collect = options.collect ?? collectViaCli;
|
|
75
|
+
const ttl = options.ttlMs ?? DRAFT_METRICS_TTL_MS;
|
|
76
|
+
const retry = options.failureRetryMs ?? DRAFT_METRICS_FAILURE_RETRY_MS;
|
|
77
|
+
const now = options.now ?? Date.now;
|
|
78
|
+
let value: { metrics: DraftMetrics; at: number } | null = null;
|
|
79
|
+
let failure: { reason: string; at: number } | null = null;
|
|
80
|
+
let inFlight: Promise<void> | null = null;
|
|
81
|
+
|
|
82
|
+
const refresh = (): void => {
|
|
83
|
+
if (inFlight) return;
|
|
84
|
+
const started = now();
|
|
85
|
+
inFlight = (async () => {
|
|
86
|
+
try {
|
|
87
|
+
const metrics = await collect();
|
|
88
|
+
value = { metrics, at: now() };
|
|
89
|
+
failure = null;
|
|
90
|
+
try { debug.log('nexus.draft-metrics', 'collected', { ms: now() - started, inventory: metrics.inventory }); } catch { /* fail-soft */ }
|
|
91
|
+
} catch (error) {
|
|
92
|
+
failure = { reason: error instanceof Error ? error.message : String(error), at: now() };
|
|
93
|
+
try { debug.log('nexus.draft-metrics', 'failed', { ms: now() - started, reason: failure.reason }); } catch { /* fail-soft */ }
|
|
94
|
+
} finally { inFlight = null; }
|
|
95
|
+
})();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
read() {
|
|
100
|
+
const clock = now();
|
|
101
|
+
const due = failure && (!value || failure.at >= value.at)
|
|
102
|
+
? clock - failure.at >= retry
|
|
103
|
+
: !value || clock - value.at >= ttl;
|
|
104
|
+
if (due) refresh();
|
|
105
|
+
return {
|
|
106
|
+
state: value ? 'ready' : failure && !inFlight ? 'unavailable' : 'measuring',
|
|
107
|
+
metrics: value?.metrics ?? null,
|
|
108
|
+
measuredAt: value ? new Date(value.at).toISOString() : null,
|
|
109
|
+
refreshing: inFlight !== null,
|
|
110
|
+
reason: failure?.reason ?? null,
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -58,12 +58,18 @@ export async function handleGraphsValidatePost(req: Request, opts: MetaApiOpts):
|
|
|
58
58
|
return jsonResponse({ error: 'bad_request', reason: 'graph (harness|workflow) and yaml (string) required' }, 400);
|
|
59
59
|
}
|
|
60
60
|
const { graph, yaml } = body as { graph: GraphKind; yaml: string };
|
|
61
|
+
const { ok, errors, ignoredKeys } = validateGraphYaml(graph, yaml);
|
|
62
|
+
debug.log('graph.kinds', 'validate', { graph, ok, errors, ignored: ignoredKeys });
|
|
63
|
+
return jsonResponse({ ok, errors, ignoredKeys }, ok ? 200 : 422);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The one validator behind `POST /v1/graphs/validate` and the graph save path. */
|
|
67
|
+
export function validateGraphYaml(graph: GraphKind, yaml: string): { ok: boolean; errors: readonly unknown[]; ignoredKeys: string[]; graphId?: string } {
|
|
61
68
|
const result = graph === 'harness' ? parseGraphTemplateYaml(yaml) : parseWorkflowYaml(yaml);
|
|
62
|
-
const errors = graph === 'harness' ? (result as ReturnType<typeof parseGraphTemplateYaml>).errors : (result as ReturnType<typeof parseWorkflowYaml>).issues;
|
|
69
|
+
const errors: readonly unknown[] = graph === 'harness' ? (result as ReturnType<typeof parseGraphTemplateYaml>).errors : (result as ReturnType<typeof parseWorkflowYaml>).issues;
|
|
63
70
|
let input: unknown;
|
|
64
71
|
try { input = parseYaml(yaml); } catch { /* The parser already reports the YAML error. */ }
|
|
65
72
|
const ignoredKeys = ignoredPaths(input, graph === 'harness' ? harnessShape : workflowShape);
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
return jsonResponse({ ok, errors, ignoredKeys }, ok ? 200 : 422);
|
|
73
|
+
const graphId = graph === 'harness' ? (result as ReturnType<typeof parseGraphTemplateYaml>).template?.graphId : undefined;
|
|
74
|
+
return { ok: errors.length === 0, errors, ignoredKeys, ...(graphId === undefined ? {} : { graphId }) };
|
|
69
75
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { debug } from '../../debug/log.js';
|
|
2
|
+
import { GraphWizardInputError, generateGraphFromPrompt, type GraphWizardDeps, type GraphWizardTurn } from '../../graph-wizard/generate.js';
|
|
3
|
+
import { jsonResponse } from './json-response.js';
|
|
4
|
+
|
|
5
|
+
const MAX_PROMPT = 4000;
|
|
6
|
+
const MAX_YAML = 200_000;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* POST /v1/graphs/wizard {prompt, kind?, currentYaml?, history?}
|
|
10
|
+
* → 200 {ok:true, id, yaml, base, baseReason, issues:[], attempts, summary, labels, steps, recipes, dryRun} · 422 {ok:false, …} · 400 빈 prompt.
|
|
11
|
+
* (labels·steps·recipes·dryRun·baseReason 는 v2 추가 필드 — 기존 필드는 그대로.)
|
|
12
|
+
* currentYaml 이 빈 문자열이면 «빈 캔버스»로 보고 새 그래프를 짓는다(의도) · 내용이 있는데 id 가 없거나 형식 밖이면 400.
|
|
13
|
+
* 저장하지 않는다 — 저장은 POST /v1/graphs(새 그래프) 또는 PUT /v1/graphs/<id>/yaml(내 그래프).
|
|
14
|
+
*/
|
|
15
|
+
export async function handleGraphWizardPost(req: Request, deps: GraphWizardDeps = {}): Promise<Response> {
|
|
16
|
+
let body: Record<string, unknown>;
|
|
17
|
+
try {
|
|
18
|
+
const parsed: unknown = await req.json();
|
|
19
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('object');
|
|
20
|
+
body = parsed as Record<string, unknown>;
|
|
21
|
+
} catch { return jsonResponse({ error: 'bad_request', reason: 'json body required' }, 400); }
|
|
22
|
+
const prompt = typeof body.prompt === 'string' ? body.prompt.trim() : '';
|
|
23
|
+
if (!prompt) return jsonResponse({ error: 'bad_request', reason: 'prompt required' }, 400);
|
|
24
|
+
if (prompt.length > MAX_PROMPT) return jsonResponse({ error: 'bad_request', reason: `prompt longer than ${MAX_PROMPT}` }, 400);
|
|
25
|
+
if (body.kind !== undefined && body.kind !== 'harness' && body.kind !== 'workflow') {
|
|
26
|
+
return jsonResponse({ error: 'bad_request', reason: 'kind must be harness or workflow' }, 400);
|
|
27
|
+
}
|
|
28
|
+
if (body.currentYaml !== undefined && (typeof body.currentYaml !== 'string' || body.currentYaml.length > MAX_YAML)) {
|
|
29
|
+
return jsonResponse({ error: 'bad_request', reason: 'currentYaml must be a string' }, 400);
|
|
30
|
+
}
|
|
31
|
+
let history: GraphWizardTurn[] | undefined;
|
|
32
|
+
if (body.history !== undefined) {
|
|
33
|
+
if (!Array.isArray(body.history) || !body.history.every((t) => t && typeof t === 'object' &&
|
|
34
|
+
((t as GraphWizardTurn).role === 'user' || (t as GraphWizardTurn).role === 'assistant') && typeof (t as GraphWizardTurn).text === 'string')) {
|
|
35
|
+
return jsonResponse({ error: 'bad_request', reason: 'history must be [{role, text}]' }, 400);
|
|
36
|
+
}
|
|
37
|
+
history = body.history as GraphWizardTurn[];
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const result = await generateGraphFromPrompt({
|
|
41
|
+
prompt,
|
|
42
|
+
...(body.kind ? { kind: body.kind as 'harness' | 'workflow' } : {}),
|
|
43
|
+
...(typeof body.currentYaml === 'string' && body.currentYaml.trim() ? { currentYaml: body.currentYaml } : {}),
|
|
44
|
+
...(history ? { history } : {}),
|
|
45
|
+
}, deps);
|
|
46
|
+
return jsonResponse({ ...result, base: result.base ?? null }, result.ok ? 200 : 422);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
+
if (error instanceof GraphWizardInputError) return jsonResponse({ error: 'bad_request', reason: message }, 400);
|
|
50
|
+
debug.log('graph.wizard', 'error', { message });
|
|
51
|
+
return jsonResponse({ error: 'wizard-failed', reason: message }, 502);
|
|
52
|
+
}
|
|
53
|
+
}
|