elanous 0.2.40 → 0.2.41
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/README.md +7 -7
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{HjeK7zONHfR7op1hKXp4k → GiOLWmt4MqDZePubBjA4Q}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +36 -0
- package/apps/pwa/out/_next/static/chunks/{9184.45afbf44fec87574.js → 1178.1aa9cad0e7695427.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2829-734fe8bf2eee7347.js → 1197-54da59d250a6e476.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6749.0744ce6eb08d40e9.js → 1219.7e17964e0e7cd8e5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +90 -0
- package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{2226.2cf61ec781827219.js → 1800.f7ff51dc4978a958.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9175.2de5209a5ce6f68a.js → 2073.689dcb2680113d76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +1 -0
- package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5383.bdfa5d886e39a826.js → 2263.e09b6edea33bad2d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9069.657590a84afb8fac.js → 2743.5d3f76948be32b34.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{6624.981ef7caeb680560.js → 2773.0e80b9d325fb5635.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4864a2ca.1c1c280a7772c5e5.js → 2fdf2931.b431eee4fb468bc3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9189505a.980427ac048c8c60.js → 2fe2c302.41b517f88d6fe502.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9992.07ce73c10bd5e6a1.js → 3097.864e92bdaa2f4d15.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +1 -0
- package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +74 -0
- package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b84cad00.594027ebe0531fe2.js → 385e4574.e9886ab32759eda3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8086.1ab9103c41be884f.js → 4156.ba4de4a3664f04b4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +148 -0
- package/apps/pwa/out/_next/static/chunks/{1281.d81877e35b9068f4.js → 4527.a69f2894d1bc9f4a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{8357.1aaa713b052a78b1.js → 4667.97e31aa38c95c475.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/{5436.fdf6fa8ae3e9588d.js → 4702.4a4adc1f16d7c93b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +94 -0
- package/apps/pwa/out/_next/static/chunks/{4769.9fd582071301f382.js → 5159.115f1c2ca471386c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/530.d26346e18089640a.js +115 -0
- package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{d8de0de2-dd0f4ac8e5ab1832.js → 53aeb4ee-51c92f8d683f5220.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6257.c0037b8949239f5e.js → 5471.1e611302ed3a7c53.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2566.beaffc3a5e1fcd2e.js → 5574.f35accf4f132b29d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2066.a77257c8c350770a.js → 5744.b9415e18ad623100.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4351.0f37a6db2b34d50b.js → 5937.c2df9e3447e1f667.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{6051-0ae955eedb10adb9.js → 5947-135e26537d80a6b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{3746-f80a78f220bf37b5.js → 5964-7e21164a8f2cf0ce.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +62 -0
- package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2047.8f23e210995d4548.js → 6874.d5cf7eb8edb2cabe.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +122 -0
- package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7191.fdc955f7d96064a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8272-025653884f9645d2.js → 8050-9b364bdef8f71927.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{2281-b8cede695c6c650e.js → 8464-e24f10451b658aac.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5622.94893f5aea7185d0.js → 8880.64c445592f04acaf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1452.162bb2d9d699e82a.js → 8981.c706964c8ba27aff.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{470.51a72a2348306455.js → 9048.212083de42d25be3.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2177.df8547f9d7215c4e.js → 9507.7026657a2f47eb64.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7515.1ad6efe157fa4448.js → 9579.4a8169600fff2058.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{2499.02fbfd18126c10c0.js → 9834.63ab2bbc3153172e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{409c787b.e48c5bec8ec10456.js → a0a01613.6d1cca322238d7fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6cc1d1d6.9a98dd4622f1afc6.js → addc2b32.8c4ff8f0aefe987d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ba957ff875a026a0.js → page-14949db884bfa672.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{c696986b.5dc8bb1143af16d1.js → b2271e54.c1de3347976e90b0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{ca3702f8.2913182e73889fa2.js → c0c1a699.0ba79f97005965d4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.mjs +6 -1
- package/catalog/models/openai/gpt-6.1-sol.yaml +16 -0
- package/catalog/models/openai/gpt-6.1-terra.yaml +16 -0
- package/graphs/demo/persona-teacher/lesson-pack.yaml +16 -0
- package/graphs/demo/persona-teacher/recipes.yaml +17 -0
- package/graphs/demo/persona-teacher/weekly-lesson.yaml +36 -0
- package/graphs/overlays/stop-heal-ladder.yaml +23 -2
- package/graphs/release/release-loop.yaml +3 -1
- package/graphs/units/gate/gate.yaml +20 -0
- package/graphs/units/git/git.yaml +26 -0
- package/graphs/units/implement/implement.yaml +19 -0
- package/graphs/units/landing/landing.yaml +18 -0
- package/graphs/units/review/review.yaml +20 -0
- package/graphs/units/verbs/recipes.yaml +3 -0
- package/graphs/units/verbs/research.yaml +20 -0
- package/graphs/work/research-report.yaml +11 -1
- package/package.json +1 -1
- package/scripts/disk-steward.ts +46 -0
- package/scripts/fleet/node-setup.sh +50 -0
- package/scripts/graph-units/verbs/research.ts +55 -0
- package/scripts/llm-cost-ledger.ts +179 -8
- package/scripts/measure-nl-routing-corpus.ts +10 -2
- package/scripts/persona-teacher/weekly-lesson-node.ts +172 -0
- package/scripts/public-copy-lint.ts +163 -19
- package/scripts/ratchets/train-side-invariants.sh +0 -1
- package/scripts/release-loop/gate-autoheal.ts +117 -0
- package/scripts/release-loop/gate-baseline-receipt.ts +8 -1
- package/scripts/release-loop/gate-diff.ts +22 -3
- package/scripts/release-loop/gate-node.ts +205 -17
- package/scripts/release-loop/gate-shard-load-flaky.ts +256 -0
- package/scripts/release-loop/gate-triage-node.ts +70 -10
- package/scripts/release-loop/resume-release.ts +247 -15
- package/scripts/release-loop/traffic-node.ts +6 -3
- package/scripts/release-loop/unattended-release.ts +4 -2
- package/scripts/shadow-authoring-probe.ts +20 -0
- package/scripts/ux-sim.ts +19 -2
- package/src/acp/core-turn-bridge.ts +86 -4
- package/src/agent-substrate/self-review-cli.ts +91 -29
- package/src/auto-research/research-turn.ts +10 -1
- package/src/autopilot/discovery/wiki-claim-proposer.ts +22 -1
- package/src/boot/daemon-tools/self-implement.ts +46 -9
- package/src/budget/shadow-arms.ts +52 -0
- package/src/chat/pickers/state.ts +7 -1
- package/src/cli/log-event-names.ts +5 -0
- package/src/cli/mcp-login.ts +8 -18
- package/src/cli/msg-cli.ts +57 -1
- package/src/cli/pr-land-heavy-remote.ts +15 -9
- package/src/cli/release-cli.ts +27 -1
- package/src/cli/sim-cli.ts +7 -1
- package/src/cli/tasks-cli.ts +5 -4
- package/src/codex/models.ts +30 -15
- package/src/core-turn/run-core-turn.ts +3 -0
- package/src/core-turn/run-goal-loop.ts +88 -2
- package/src/dashboard/acp-boot.ts +72 -3
- package/src/dashboard/index.ts +6 -0
- package/src/dashboard/turn-preamble.ts +12 -1
- package/src/disk-steward/judge.ts +73 -0
- package/src/disk-steward/ledger.ts +122 -0
- package/src/disk-steward/steward.ts +373 -0
- package/src/domains/guardian-tick.ts +191 -2
- package/src/graph-runner/graph-cli.ts +21 -0
- package/src/graph-runner/in-process-registry.ts +37 -0
- package/src/graph-runner/runner.ts +33 -3
- package/src/grounding/ref-index.ts +19 -0
- package/src/grounding/sources-cli.ts +9 -1
- package/src/harness/harness-cli-command.ts +267 -14
- package/src/harness/harness-incidents.ts +312 -7
- package/src/harness/harness-space.ts +15 -1
- package/src/harness/progress-worker-entry.ts +59 -0
- package/src/harness/progress-worker-runtime.ts +11 -0
- package/src/index.ts +18 -2
- package/src/instance/dev-project.ts +25 -0
- package/src/intelligence-map/model-alias.ts +6 -5
- package/src/intelligence-map/model-catalog.ts +59 -2
- package/src/llm/model-defaults.ts +4 -4
- package/src/llm.ts +42 -11
- package/src/loops/orchestrator/tick.ts +48 -0
- package/src/mcp/mcp-oauth.ts +3 -1
- package/src/model-tier/llm-tier-map.ts +9 -9
- package/src/model-tier/turn-tier.ts +1 -1
- package/src/msg/msg-mirror-github.ts +80 -0
- package/src/msg/msg-mirror-policy.ts +61 -0
- package/src/msg/msg-mirror-runner.ts +219 -0
- package/src/msg/msg-mirror-state.ts +33 -0
- package/src/msg/msg-store.ts +11 -0
- package/src/output-truncation.ts +41 -12
- package/src/project/project-store.ts +48 -1
- package/src/release-loop/gate-host-reservation.ts +144 -0
- package/src/release-loop/release-schedule.ts +90 -1
- package/src/research/bloom-exemplars.ts +135 -0
- package/src/self-dev/ask-launch-flow.ts +39 -25
- package/src/self-dev/dev-cli.ts +17 -17
- package/src/self-dev/graph-front-nodes.ts +23 -0
- package/src/self-dev/launch-preflight.ts +9 -4
- package/src/self-dev/orchestrate.ts +15 -0
- package/src/self-dev/run-supervisor.ts +185 -3
- package/src/self-dev/run-types.ts +3 -0
- package/src/self-implement/gate-artifacts.ts +13 -0
- package/src/self-implement/gate-cli.ts +54 -24
- package/src/self-implement/gate-remote.ts +23 -5
- package/src/self-implement/goal-author-clarification.ts +31 -12
- package/src/self-implement/goal-author.ts +77 -5
- package/src/self-implement/graph-stage-units.ts +172 -0
- package/src/self-implement/graph-templates.ts +162 -1
- package/src/self-implement/graph-variant.ts +37 -4
- package/src/self-implement/host-regate.ts +4 -4
- package/src/self-implement/knowhow-pack.ts +38 -0
- package/src/self-implement/orchestrator.ts +235 -21
- package/src/self-implement/run-ledger.ts +64 -6
- package/src/self-implement/run-stop.ts +21 -2
- package/src/self-implement/running-runs.ts +35 -12
- package/src/self-implement/self-implement-cli.ts +36 -4
- package/src/self-implement/stop-autoheal-operational.ts +43 -0
- package/src/self-implement/stop-autoheal.ts +15 -6
- package/src/session/chat.ts +31 -54
- package/src/session/request-size-guard.ts +123 -0
- package/src/sidetab-core/model.ts +136 -0
- package/src/task-agent/parent-host.ts +14 -1
- package/src/task-agent/task-hand.ts +4 -1
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +43 -0
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +29 -4
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +116 -16
- package/src/task-orchestrator/surfaces/self-implement.ts +18 -0
- package/src/tui/entry.ts +10 -3
- package/src/tui/sidetab/list.ts +45 -0
- package/src/tui/sidetab/nl-tool.ts +2 -136
- package/src/tui/sidetab/peek.ts +52 -0
- package/src/tui-client/dashboard-session.ts +3 -0
- package/src/user-config.ts +11 -5
- package/src/ux-sim/fault-needs-human-reason-repair.ts +107 -0
- package/src/ux-sim/fault-pod-child-result.ts +42 -0
- package/src/ux-sim/release-sim-rig.ts +262 -0
- package/src/ux-sim/seminar-rehearsal.ts +109 -0
- package/src/ux-sim/subagent-tools-device.ts +2 -2
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1060.014f1f01a17aec26.js +0 -115
- package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +0 -286
- package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +0 -104
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2522.f2766b76d22c8bdf.js +0 -34
- package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +0 -226
- package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +0 -27
- package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2774-719820e3f5b2a3eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3330.7443183b7e6fdbdf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +0 -24
- package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +0 -77
- package/apps/pwa/out/_next/static/chunks/3b355b3d.6f73c98bf6f9c749.js +0 -122
- package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +0 -36
- package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +0 -287
- package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +0 -1
- package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6908.06008c67f6380ea9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +0 -93
- package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8639-92c11d069792429e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-4edb8df90f4537ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-fca2e59a81744d9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-139d722de1dcd6c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-ccde99f07aaf71f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +0 -1
- package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +0 -1
- package/scripts/ratchets/next-tui-entry-budget.ts +0 -124
- /package/apps/pwa/out/_next/static/{HjeK7zONHfR7op1hKXp4k → GiOLWmt4MqDZePubBjA4Q}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { Message } from './msg-store.js';
|
|
2
|
+
import { buildMirrorSummary, isMirrorEvent, MIRROR_SUMMARY_INTERVAL_MS, selectMirrorEvents, shouldRotateMirrorChannel } from './msg-mirror-policy.js';
|
|
3
|
+
|
|
4
|
+
export interface MirrorTarget {
|
|
5
|
+
repo: string;
|
|
6
|
+
issueNumber: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface MsgMirrorState {
|
|
10
|
+
version: 1;
|
|
11
|
+
target: MirrorTarget;
|
|
12
|
+
messageCursor: number;
|
|
13
|
+
summaryWindowEnd: string;
|
|
14
|
+
rotationPending?: { from: MirrorTarget; to: MirrorTarget };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface MsgMirrorSource {
|
|
18
|
+
listAfter(afterId: number, limit: number): Message[];
|
|
19
|
+
listWindow(start: string, end: string): Message[];
|
|
20
|
+
latestId(): number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface MsgMirrorStateStore {
|
|
24
|
+
read(): MsgMirrorState | null;
|
|
25
|
+
write(state: MsgMirrorState): void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MsgMirrorTransport {
|
|
29
|
+
beginTick?(): Promise<void> | void;
|
|
30
|
+
countComments(target: MirrorTarget): Promise<number> | number;
|
|
31
|
+
hasMarker(target: MirrorTarget, marker: string): Promise<boolean> | boolean;
|
|
32
|
+
postComment(target: MirrorTarget, body: string): Promise<void> | void;
|
|
33
|
+
createNextChannel(target: MirrorTarget, idempotencyKey: string): Promise<MirrorTarget> | MirrorTarget;
|
|
34
|
+
linkAndCloseChannel(from: MirrorTarget, to: MirrorTarget): Promise<void> | void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MsgMirrorTickOptions {
|
|
38
|
+
configuredTarget?: MirrorTarget;
|
|
39
|
+
nowMs?: number;
|
|
40
|
+
dryRun?: boolean;
|
|
41
|
+
source: MsgMirrorSource;
|
|
42
|
+
state: MsgMirrorStateStore;
|
|
43
|
+
transport: MsgMirrorTransport;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface MsgMirrorTickResult {
|
|
47
|
+
status: 'disabled' | 'dry-run' | 'synced';
|
|
48
|
+
target: MirrorTarget | null;
|
|
49
|
+
scanned: number;
|
|
50
|
+
posted: number;
|
|
51
|
+
rotated: number;
|
|
52
|
+
summaries: number;
|
|
53
|
+
sourceCursor: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const VALID_REPO = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
57
|
+
|
|
58
|
+
export function validateMirrorTarget(value: unknown): MirrorTarget {
|
|
59
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('mirror target must be an object');
|
|
60
|
+
const target = value as Record<string, unknown>;
|
|
61
|
+
if (typeof target.repo !== 'string' || !VALID_REPO.test(target.repo)
|
|
62
|
+
|| typeof target.issueNumber !== 'number' || !Number.isSafeInteger(target.issueNumber) || target.issueNumber < 1) {
|
|
63
|
+
throw new Error('mirror target requires repo=owner/name and a positive issueNumber');
|
|
64
|
+
}
|
|
65
|
+
return { repo: target.repo, issueNumber: target.issueNumber as number };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Sparse settings are disabled by default; malformed nonempty settings are rejected. */
|
|
69
|
+
export function configuredMirrorTarget(raw: unknown): MirrorTarget | undefined {
|
|
70
|
+
if (raw === undefined) return undefined;
|
|
71
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('msgMirror config must be an object');
|
|
72
|
+
const target = (raw as Record<string, unknown>).target;
|
|
73
|
+
return target === undefined ? undefined : validateMirrorTarget(target);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function validateMsgMirrorState(value: unknown): MsgMirrorState {
|
|
77
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('invalid message mirror state');
|
|
78
|
+
const state = value as Record<string, unknown>;
|
|
79
|
+
if (state.version !== 1 || typeof state.messageCursor !== 'number' || !Number.isSafeInteger(state.messageCursor) || state.messageCursor < 0
|
|
80
|
+
|| typeof state.summaryWindowEnd !== 'string' || !Number.isFinite(Date.parse(state.summaryWindowEnd))) throw new Error('invalid message mirror state');
|
|
81
|
+
const target = validateMirrorTarget(state.target);
|
|
82
|
+
const pending = state.rotationPending;
|
|
83
|
+
const rotationPending = pending && typeof pending === 'object' && !Array.isArray(pending)
|
|
84
|
+
? { from: validateMirrorTarget((pending as Record<string, unknown>).from), to: validateMirrorTarget((pending as Record<string, unknown>).to) }
|
|
85
|
+
: undefined;
|
|
86
|
+
if (pending !== undefined && !rotationPending) throw new Error('invalid pending mirror rotation');
|
|
87
|
+
return { version: 1, target, messageCursor: state.messageCursor as number, summaryWindowEnd: new Date(state.summaryWindowEnd as string).toISOString(),
|
|
88
|
+
...(rotationPending ? { rotationPending } : {}) };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function initialState(target: MirrorTarget, nowMs: number, latestMessageId: number): MsgMirrorState {
|
|
92
|
+
if (!Number.isSafeInteger(latestMessageId) || latestMessageId < 0) throw new Error('source latest message ID is invalid');
|
|
93
|
+
const end = Math.floor(nowMs / MIRROR_SUMMARY_INTERVAL_MS) * MIRROR_SUMMARY_INTERVAL_MS;
|
|
94
|
+
return { version: 1, target, messageCursor: latestMessageId, summaryWindowEnd: new Date(end).toISOString() };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function eventMarker(id: number): string { return `<!-- elanous-msg-mirror:event:${id} -->`; }
|
|
98
|
+
function summaryMarker(start: string): string { return `<!-- elanous-msg-mirror:summary:${start} -->`; }
|
|
99
|
+
|
|
100
|
+
function renderEvent(message: Message): string {
|
|
101
|
+
return `## ${message.kind} · #${message.id}\n\n**${message.from} → ${message.to}** · ${message.createdAt}\n\n${message.body.trim()}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function prepareTarget(state: MsgMirrorState, transport: MsgMirrorTransport, dryRun: boolean): Promise<{
|
|
105
|
+
state: MsgMirrorState; rotated: number;
|
|
106
|
+
}> {
|
|
107
|
+
let current = state;
|
|
108
|
+
let rotated = 0;
|
|
109
|
+
if (current.rotationPending) {
|
|
110
|
+
if (dryRun) return { state: current, rotated };
|
|
111
|
+
await transport.linkAndCloseChannel(current.rotationPending.from, current.rotationPending.to);
|
|
112
|
+
current = { ...current, rotationPending: undefined };
|
|
113
|
+
}
|
|
114
|
+
const count = await transport.countComments(current.target);
|
|
115
|
+
if (!shouldRotateMirrorChannel(count)) return { state: current, rotated };
|
|
116
|
+
if (dryRun) return { state: current, rotated };
|
|
117
|
+
const oldTarget = current.target;
|
|
118
|
+
const nextTarget = validateMirrorTarget(await transport.createNextChannel(oldTarget,
|
|
119
|
+
`msg-mirror-rotate:${oldTarget.repo}#${oldTarget.issueNumber}`));
|
|
120
|
+
current = { ...current, target: nextTarget, rotationPending: { from: oldTarget, to: nextTarget } };
|
|
121
|
+
// Persist the pointer before closing the old issue. On restart the pending link/close is retried.
|
|
122
|
+
// If this write fails, the adapter's idempotency key prevents creating another channel.
|
|
123
|
+
return { state: current, rotated: 1 };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** One idempotent mirror pass. All GitHub effects are behind the injected transport. */
|
|
127
|
+
export async function runMsgMirrorTick(options: MsgMirrorTickOptions): Promise<MsgMirrorTickResult> {
|
|
128
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
129
|
+
if (!Number.isFinite(nowMs)) throw new Error('nowMs must be finite');
|
|
130
|
+
const stored = options.state.read();
|
|
131
|
+
const configured = options.configuredTarget ? validateMirrorTarget(options.configuredTarget) : undefined;
|
|
132
|
+
if (!stored && !configured) return { status: 'disabled', target: null, scanned: 0, posted: 0, rotated: 0, summaries: 0, sourceCursor: 0 };
|
|
133
|
+
await options.transport.beginTick?.();
|
|
134
|
+
let state = stored ? validateMsgMirrorState(stored) : initialState(configured!, nowMs, options.source.latestId());
|
|
135
|
+
let scanned = 0, posted = 0, rotated = 0, summaries = 0;
|
|
136
|
+
if (!options.dryRun) options.state.write(state);
|
|
137
|
+
|
|
138
|
+
const startTarget = state.target;
|
|
139
|
+
const prepared = await prepareTarget(state, options.transport, options.dryRun === true);
|
|
140
|
+
state = prepared.state;
|
|
141
|
+
rotated += prepared.rotated;
|
|
142
|
+
if (!options.dryRun && state !== stored) options.state.write(state);
|
|
143
|
+
|
|
144
|
+
// A rotation is recorded before side effects that close the previous issue.
|
|
145
|
+
if (state.rotationPending && !options.dryRun) {
|
|
146
|
+
await options.transport.linkAndCloseChannel(state.rotationPending.from, state.rotationPending.to);
|
|
147
|
+
state = { ...state, rotationPending: undefined };
|
|
148
|
+
options.state.write(state);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let page = options.source.listAfter(state.messageCursor, 1000);
|
|
152
|
+
while (page.length > 0) {
|
|
153
|
+
const eligible = new Map(selectMirrorEvents(page, state.messageCursor).map(message => [message.id, message]));
|
|
154
|
+
for (const message of page) {
|
|
155
|
+
scanned++;
|
|
156
|
+
const event = eligible.get(message.id);
|
|
157
|
+
if (event) {
|
|
158
|
+
const preparedNext = await prepareTarget(state, options.transport, options.dryRun === true);
|
|
159
|
+
if (preparedNext.rotated) {
|
|
160
|
+
state = preparedNext.state;
|
|
161
|
+
rotated += preparedNext.rotated;
|
|
162
|
+
if (!options.dryRun) {
|
|
163
|
+
options.state.write(state);
|
|
164
|
+
if (state.rotationPending) {
|
|
165
|
+
await options.transport.linkAndCloseChannel(state.rotationPending.from, state.rotationPending.to);
|
|
166
|
+
state = { ...state, rotationPending: undefined };
|
|
167
|
+
options.state.write(state);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const marker = eventMarker(event.id);
|
|
172
|
+
if (!options.dryRun && !(await options.transport.hasMarker(state.target, marker))) {
|
|
173
|
+
await options.transport.postComment(state.target, `${marker}\n${renderEvent(event)}`);
|
|
174
|
+
posted++;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
state = { ...state, messageCursor: message.id };
|
|
178
|
+
if (!options.dryRun) options.state.write(state);
|
|
179
|
+
}
|
|
180
|
+
if (page.length < 1000) break;
|
|
181
|
+
page = options.source.listAfter(state.messageCursor, 1000);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let windowStart = Date.parse(state.summaryWindowEnd);
|
|
185
|
+
const nowWindowEnd = Math.floor(nowMs / MIRROR_SUMMARY_INTERVAL_MS) * MIRROR_SUMMARY_INTERVAL_MS;
|
|
186
|
+
while (windowStart + MIRROR_SUMMARY_INTERVAL_MS <= nowWindowEnd) {
|
|
187
|
+
const windowEnd = windowStart + MIRROR_SUMMARY_INTERVAL_MS;
|
|
188
|
+
const from = new Date(windowStart).toISOString();
|
|
189
|
+
const to = new Date(windowEnd).toISOString();
|
|
190
|
+
const summary = buildMirrorSummary(options.source.listWindow(from, to), from, to);
|
|
191
|
+
if (summary) {
|
|
192
|
+
const preparedNext = await prepareTarget(state, options.transport, options.dryRun === true);
|
|
193
|
+
if (preparedNext.rotated) {
|
|
194
|
+
state = preparedNext.state;
|
|
195
|
+
rotated += preparedNext.rotated;
|
|
196
|
+
if (!options.dryRun) {
|
|
197
|
+
options.state.write(state);
|
|
198
|
+
if (state.rotationPending) {
|
|
199
|
+
await options.transport.linkAndCloseChannel(state.rotationPending.from, state.rotationPending.to);
|
|
200
|
+
state = { ...state, rotationPending: undefined };
|
|
201
|
+
options.state.write(state);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const marker = summaryMarker(from);
|
|
206
|
+
if (!options.dryRun && !(await options.transport.hasMarker(state.target, marker))) {
|
|
207
|
+
await options.transport.postComment(state.target, `${marker}\n${summary}`);
|
|
208
|
+
posted++;
|
|
209
|
+
}
|
|
210
|
+
summaries++;
|
|
211
|
+
}
|
|
212
|
+
state = { ...state, summaryWindowEnd: to };
|
|
213
|
+
if (!options.dryRun) options.state.write(state);
|
|
214
|
+
windowStart = windowEnd;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { status: options.dryRun ? 'dry-run' : 'synced', target: options.dryRun ? startTarget : state.target,
|
|
218
|
+
scanned, posted, rotated, summaries, sourceCursor: state.messageCursor };
|
|
219
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
5
|
+
import { validateMsgMirrorState, type MsgMirrorState, type MsgMirrorStateStore } from './msg-mirror-runner.js';
|
|
6
|
+
|
|
7
|
+
export function defaultMsgMirrorStatePath(): string {
|
|
8
|
+
return join(elanousStateRoot(), 'msg', 'github-mirror-state.json');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** One durable rotation pointer and progress cursor, stored atomically in the active state universe. */
|
|
12
|
+
export class JsonMsgMirrorStateStore implements MsgMirrorStateStore {
|
|
13
|
+
constructor(readonly path: string = defaultMsgMirrorStatePath()) {}
|
|
14
|
+
|
|
15
|
+
read(): MsgMirrorState | null {
|
|
16
|
+
if (!existsSync(this.path)) return null;
|
|
17
|
+
const parsed: unknown = JSON.parse(readFileSync(this.path, 'utf8'));
|
|
18
|
+
return validateMsgMirrorState(parsed);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
write(state: MsgMirrorState): void {
|
|
22
|
+
const normalized = validateMsgMirrorState(state);
|
|
23
|
+
mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 });
|
|
24
|
+
const temp = `${this.path}.${process.pid}.${randomUUID()}.tmp`;
|
|
25
|
+
try {
|
|
26
|
+
writeFileSync(temp, `${JSON.stringify(normalized, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
27
|
+
renameSync(temp, this.path);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
try { rmSync(temp, { force: true }); } catch { /* preserve the original write error */ }
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/msg/msg-store.ts
CHANGED
|
@@ -129,6 +129,7 @@ export class MsgStore {
|
|
|
129
129
|
created_at TEXT NOT NULL
|
|
130
130
|
);
|
|
131
131
|
CREATE INDEX IF NOT EXISTS idx_msg_messages_recipient_id ON msg_messages(recipient, id);
|
|
132
|
+
CREATE INDEX IF NOT EXISTS idx_msg_messages_created_at_id ON msg_messages(created_at, id);
|
|
132
133
|
CREATE TABLE IF NOT EXISTS msg_cursors (
|
|
133
134
|
recipient TEXT PRIMARY KEY,
|
|
134
135
|
last_id INTEGER NOT NULL DEFAULT 0 CHECK(last_id >= 0)
|
|
@@ -307,6 +308,16 @@ export class MsgStore {
|
|
|
307
308
|
WHERE id > ? ORDER BY id ASC LIMIT ?`).all(after, limit) as MessageRow[]).map(fromRow));
|
|
308
309
|
}
|
|
309
310
|
|
|
311
|
+
/** Read a half-open UTC timestamp window for periodic message-mirror summaries. */
|
|
312
|
+
listCreatedBetween(start: string, end: string): Message[] {
|
|
313
|
+
const startMs = Date.parse(start);
|
|
314
|
+
const endMs = Date.parse(end);
|
|
315
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) throw new Error('invalid message time window');
|
|
316
|
+
return this.readWithSchema(hasReplyTo => (this.db.query(`SELECT id, sender, recipient, body, kind,
|
|
317
|
+
${hasReplyTo ? 'reply_to' : 'NULL AS reply_to'}, created_at FROM msg_messages
|
|
318
|
+
WHERE created_at >= ? AND created_at < ? ORDER BY id ASC`).all(new Date(startMs).toISOString(), new Date(endMs).toISOString()) as MessageRow[]).map(fromRow));
|
|
319
|
+
}
|
|
320
|
+
|
|
310
321
|
latestId(): number {
|
|
311
322
|
return (this.db.query('SELECT COALESCE(MAX(id), 0) AS id FROM msg_messages').get() as { id: number }).id;
|
|
312
323
|
}
|
package/src/output-truncation.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface TruncateOptions {
|
|
|
35
35
|
toolName: string;
|
|
36
36
|
/** File extension for the spilled file (no leading dot). Default 'txt'. */
|
|
37
37
|
ext?: string;
|
|
38
|
-
/** Bytes above which we spill. Default 8192. */
|
|
38
|
+
/** Bytes above which we spill. Default 8192. The inline spill marker must fit this limit. */
|
|
39
39
|
inlineLimit?: number;
|
|
40
40
|
/** Head bytes preserved when spilled. Default 4096. */
|
|
41
41
|
headBytes?: number;
|
|
@@ -59,8 +59,8 @@ export interface TruncateResult {
|
|
|
59
59
|
/** Apply head/tail truncation + optional disk spill. */
|
|
60
60
|
export function truncateOutput(body: string, opts: TruncateOptions): TruncateResult {
|
|
61
61
|
const inlineLimit = opts.inlineLimit ?? DEFAULT_INLINE_LIMIT;
|
|
62
|
-
const
|
|
63
|
-
const
|
|
62
|
+
const requestedHead = opts.headBytes ?? DEFAULT_HEAD_BYTES;
|
|
63
|
+
const requestedTail = opts.tailBytes ?? DEFAULT_TAIL_BYTES;
|
|
64
64
|
const ext = (opts.ext ?? 'txt').replace(/^\./, '');
|
|
65
65
|
const outputDir = opts.outputDir ?? DEFAULT_OUTPUT_DIR;
|
|
66
66
|
|
|
@@ -74,22 +74,51 @@ export function truncateOutput(body: string, opts: TruncateOptions): TruncateRes
|
|
|
74
74
|
const filename = `${opts.toolName}-${hash}.${ext}`;
|
|
75
75
|
const savedPath = joinPath(outputDir, filename);
|
|
76
76
|
|
|
77
|
+
// Reserve enough space for the full path/footer first, then scale the
|
|
78
|
+
// requested head/tail budgets to fit the inline byte limit. A tiny limit
|
|
79
|
+
// that cannot hold the recovery marker is invalid instead of silently
|
|
80
|
+
// exceeding the configured maximum.
|
|
81
|
+
const marker = (elided: number) =>
|
|
82
|
+
`\n\n[... ${elided} bytes elided — saved to ${savedPath} (${bytes} bytes total). ` +
|
|
83
|
+
`Use Read tool with file_path="${savedPath}" to inspect more. ...]\n\n`;
|
|
84
|
+
const markerBudget = Buffer.byteLength(marker(bytes), 'utf8');
|
|
85
|
+
if (markerBudget >= inlineLimit) {
|
|
86
|
+
throw new RangeError(`inlineLimit must leave room for the saved-output marker (minimum ${markerBudget + 1} bytes)`);
|
|
87
|
+
}
|
|
77
88
|
if (!existsSync(savedPath)) {
|
|
78
89
|
mkdirSync(outputDir, { recursive: true });
|
|
79
90
|
writeFileSync(savedPath, body, 'utf-8');
|
|
80
91
|
}
|
|
92
|
+
const availableContentBytes = inlineLimit - markerBudget;
|
|
93
|
+
const requestedContentBytes = requestedHead + requestedTail;
|
|
94
|
+
const scale = requestedContentBytes > availableContentBytes
|
|
95
|
+
? availableContentBytes / requestedContentBytes
|
|
96
|
+
: 1;
|
|
97
|
+
const head = Math.floor(requestedHead * scale);
|
|
98
|
+
const tail = Math.floor(requestedTail * scale);
|
|
81
99
|
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
// Preserve byte budgets and never split a UTF-8 code point. The LLM
|
|
101
|
+
// inline limit is a byte limit too, so character slicing would allow
|
|
102
|
+
// multibyte output to exceed it by up to 4x.
|
|
103
|
+
const bodyBuffer = Buffer.from(body, 'utf8');
|
|
104
|
+
const alignStart = (offset: number): number => {
|
|
105
|
+
let index = Math.max(0, Math.min(bodyBuffer.length, offset));
|
|
106
|
+
while (index < bodyBuffer.length && (bodyBuffer[index]! & 0b1100_0000) === 0b1000_0000) index++;
|
|
107
|
+
return index;
|
|
108
|
+
};
|
|
109
|
+
const alignEnd = (offset: number): number => {
|
|
110
|
+
let index = Math.max(0, Math.min(bodyBuffer.length, offset));
|
|
111
|
+
while (index > 0 && index < bodyBuffer.length && (bodyBuffer[index]! & 0b1100_0000) === 0b1000_0000) index--;
|
|
112
|
+
return index;
|
|
113
|
+
};
|
|
114
|
+
const headEnd = alignEnd(head);
|
|
115
|
+
const tailStart = alignStart(bodyBuffer.length - tail);
|
|
116
|
+
const headStr = bodyBuffer.toString('utf8', 0, headEnd);
|
|
117
|
+
const tailStr = bodyBuffer.toString('utf8', tailStart);
|
|
118
|
+
const elided = bytes - Buffer.byteLength(headStr, 'utf8') - Buffer.byteLength(tailStr, 'utf8');
|
|
89
119
|
const out = [
|
|
90
120
|
headStr,
|
|
91
|
-
|
|
92
|
-
`Use Read tool with file_path="${savedPath}" to inspect more. ...]\n\n`,
|
|
121
|
+
marker(elided),
|
|
93
122
|
tailStr,
|
|
94
123
|
].join('');
|
|
95
124
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
1
|
+
import { createHash, createHmac, randomBytes, randomUUID } from 'node:crypto';
|
|
2
2
|
import { linkSync, mkdirSync, readFileSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
4
|
import { parse, stringify } from 'yaml';
|
|
@@ -133,3 +133,50 @@ export function getProject(id: string): Project | null {
|
|
|
133
133
|
export function suggestProjectForFolder(folder: string): Project | null {
|
|
134
134
|
return new ProjectStore().suggestForFolder(folder);
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
// TENANT-BOUNDARY (0.2.41 · nfr:security): 고객 프로젝트 원장이 설치 밖으로 나가는
|
|
138
|
+
// 출구는 이 익명 내보내기 하나다 — 식별 필드(이름·경로)는 익명 토큰으로 치환되고
|
|
139
|
+
// id(이미 불투명한 uuid)·createdAt·relations 만 남는다.
|
|
140
|
+
export interface AnonymousProject {
|
|
141
|
+
id: string;
|
|
142
|
+
name: string;
|
|
143
|
+
createdAt: string;
|
|
144
|
+
primaryFolder?: string;
|
|
145
|
+
relations?: Project['relations'];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const ANONYMOUS_EXPORT_DOMAIN = 'elanous-tenant-boundary';
|
|
149
|
+
|
|
150
|
+
function anonymousExportSecret(): Buffer {
|
|
151
|
+
const configDir = getElanousConfigDir();
|
|
152
|
+
const path = join(configDir, 'tenant-boundary-secret');
|
|
153
|
+
try {
|
|
154
|
+
const existing = readFileSync(path);
|
|
155
|
+
if (existing.length === 32) return existing;
|
|
156
|
+
} catch { /* first use */ }
|
|
157
|
+
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
158
|
+
const secret = randomBytes(32);
|
|
159
|
+
try { writeFileSync(path, secret, { flag: 'wx', mode: 0o600 }); }
|
|
160
|
+
catch (error) {
|
|
161
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
162
|
+
const existing = readFileSync(path);
|
|
163
|
+
if (existing.length === 32) return existing;
|
|
164
|
+
throw new Error('invalid tenant boundary secret');
|
|
165
|
+
}
|
|
166
|
+
return secret;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function anonymousToken(prefix: 'project' | 'folder', value: string): string {
|
|
170
|
+
return `${prefix}-${createHmac('sha256', anonymousExportSecret()).update(`${ANONYMOUS_EXPORT_DOMAIN}\u0000${prefix}\u0000${value}`).digest('hex').slice(0, 16)}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function anonymousExport(project: Project): AnonymousProject {
|
|
174
|
+
const exported: AnonymousProject = {
|
|
175
|
+
id: project.id,
|
|
176
|
+
name: anonymousToken('project', project.name),
|
|
177
|
+
createdAt: project.createdAt,
|
|
178
|
+
};
|
|
179
|
+
if (project.primaryFolder !== undefined) exported.primaryFolder = anonymousToken('folder', project.primaryFolder);
|
|
180
|
+
if (project.relations !== undefined) exported.relations = project.relations;
|
|
181
|
+
return exported;
|
|
182
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
import { psProcessStartMs } from '../harness/harness-stop.js';
|
|
5
6
|
import { debug } from '../debug/log.js';
|
|
6
7
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
8
|
+
import { psProcessStart, type HostLeaseRecord, type PendingJobIdentity } from '../pod-lease/host-lease.js';
|
|
9
|
+
import { parsePodPool, podPoolHostLease, resolvePodPoolSpec, type PodPoolMember } from '../task-orchestrator/surfaces/pod-pool.js';
|
|
7
10
|
|
|
8
11
|
interface GateHostClaim {
|
|
9
12
|
token: string;
|
|
@@ -19,6 +22,147 @@ export type GateHostReservation =
|
|
|
19
22
|
| { status: 'free' }
|
|
20
23
|
| { status: 'reserved' | 'unknown'; reason: string; runId?: string; reservedAt?: number };
|
|
21
24
|
|
|
25
|
+
/** Read-only snapshots used to decide whether the resource pool behind a gate host is occupied. */
|
|
26
|
+
export interface GateHostResourceSnapshot {
|
|
27
|
+
/** null means the lease ledger was unreadable; [] is a measured empty ledger. */
|
|
28
|
+
leases: readonly HostLeaseRecord[] | null;
|
|
29
|
+
/** Active Pending/Running Jobs from the configured Pod pool; null means not measurable. */
|
|
30
|
+
activeJobs: readonly PendingJobIdentity[] | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type GateHostResourceReading =
|
|
34
|
+
| { status: 'measured'; empty: boolean; reservations: number; authoringLeases: number; waitingJobs: number; activeJobs: number }
|
|
35
|
+
| { status: 'unmeasurable'; empty: null; reason: 'lease-ledger-unavailable' | 'lease-ledger-invalid' | 'pod-list-unavailable' | 'pod-list-invalid' | 'pod-pool-invalid' };
|
|
36
|
+
|
|
37
|
+
const unavailable = (reason: Extract<GateHostResourceReading, { status: 'unmeasurable' }>['reason']): GateHostResourceReading => ({ status: 'unmeasurable', empty: null, reason });
|
|
38
|
+
|
|
39
|
+
/** Read leases and active harness Pods from the configured pool without creating, pruning, or updating any ledger. */
|
|
40
|
+
export function readGateHostResourcesForHost(host: string, env: NodeJS.ProcessEnv = process.env,
|
|
41
|
+
deps: { members?: readonly PodPoolMember[]; kubectl?: (args: readonly string[]) => { status: number | null; stdout: string };
|
|
42
|
+
processStart?: (pid: number) => string | null } = {}): GateHostResourceReading {
|
|
43
|
+
let members: readonly PodPoolMember[];
|
|
44
|
+
try {
|
|
45
|
+
const spec = resolvePodPoolSpec(undefined, env, () => {
|
|
46
|
+
try {
|
|
47
|
+
// The gate path resolves its pool from harness.podPool, unlike generic Pod launches.
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
49
|
+
return (require('../user-config.js') as typeof import('../user-config.js')).getUserConfig().harness?.podPool;
|
|
50
|
+
} catch { return undefined; }
|
|
51
|
+
});
|
|
52
|
+
members = deps.members ?? (spec ? parsePodPool(spec) : []);
|
|
53
|
+
} catch { return unavailable('pod-pool-invalid'); }
|
|
54
|
+
if (!members.length) return unavailable('pod-list-unavailable');
|
|
55
|
+
const selectedHost = host.split('@').at(-1)!;
|
|
56
|
+
const selectedMembers = members.filter(member => member.sshHost === selectedHost);
|
|
57
|
+
if (!selectedMembers.length) return unavailable('pod-list-unavailable');
|
|
58
|
+
const selectedContexts = new Set(selectedMembers.map(member => member.context));
|
|
59
|
+
|
|
60
|
+
const leasePool = podPoolHostLease(members);
|
|
61
|
+
let leases: HostLeaseRecord[];
|
|
62
|
+
try {
|
|
63
|
+
let names: string[];
|
|
64
|
+
try { names = readdirSync(leasePool.dir).filter(name => name.endsWith('.json')); }
|
|
65
|
+
catch (error) {
|
|
66
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') names = [];
|
|
67
|
+
else return unavailable('lease-ledger-unavailable');
|
|
68
|
+
}
|
|
69
|
+
leases = [];
|
|
70
|
+
const processStart = deps.processStart ?? psProcessStart;
|
|
71
|
+
for (const name of names) {
|
|
72
|
+
if (!/^[A-Za-z0-9._-]+\.json$/.test(name)) return unavailable('lease-ledger-invalid');
|
|
73
|
+
let lease: HostLeaseRecord;
|
|
74
|
+
try { lease = JSON.parse(readFileSync(join(leasePool.dir, name), 'utf8')) as HostLeaseRecord; }
|
|
75
|
+
catch { return unavailable('lease-ledger-invalid'); }
|
|
76
|
+
if (!lease || !Number.isSafeInteger(lease.pid) || lease.pid <= 0 || typeof lease.startedAt !== 'string' || !lease.startedAt ||
|
|
77
|
+
typeof lease.at !== 'string' || (lease.stage !== undefined && lease.stage !== 'authoring' && lease.stage !== 'job') ||
|
|
78
|
+
(lease.stage === 'job' && (!lease.job || !lease.context || !lease.namespace))) return unavailable('lease-ledger-invalid');
|
|
79
|
+
try { process.kill(lease.pid, 0); }
|
|
80
|
+
catch (error) {
|
|
81
|
+
if ((error as NodeJS.ErrnoException).code === 'ESRCH') continue;
|
|
82
|
+
// EPERM means the PID may still be alive; the start-time comparison below is still read-only.
|
|
83
|
+
}
|
|
84
|
+
const startedAt = processStart(lease.pid);
|
|
85
|
+
if (startedAt === null) return unavailable('lease-ledger-unavailable');
|
|
86
|
+
if (startedAt !== lease.startedAt) continue;
|
|
87
|
+
if (lease.stage !== 'job' || selectedContexts.has(lease.context!)) leases.push(lease);
|
|
88
|
+
}
|
|
89
|
+
} catch { return unavailable('lease-ledger-unavailable'); }
|
|
90
|
+
|
|
91
|
+
const kubectl = deps.kubectl ?? ((args: readonly string[]) => {
|
|
92
|
+
const result = spawnSync('kubectl', [...args], { encoding: 'utf8', timeout: 15_000, maxBuffer: 64 * 1024 * 1024 });
|
|
93
|
+
return { status: result.status, stdout: result.stdout ?? '' };
|
|
94
|
+
});
|
|
95
|
+
const activeJobs = new Map<string, PendingJobIdentity>();
|
|
96
|
+
for (const member of selectedMembers) {
|
|
97
|
+
let result: { status: number | null; stdout: string };
|
|
98
|
+
try { result = kubectl(['--context', member.context, '--request-timeout=10s', 'get', 'pods', '--all-namespaces', '-l', 'elanous.substrate=pod', '-o', 'json']); }
|
|
99
|
+
catch { return unavailable('pod-list-unavailable'); }
|
|
100
|
+
if (result.status !== 0) return unavailable('pod-list-unavailable');
|
|
101
|
+
let items: unknown;
|
|
102
|
+
try { items = (JSON.parse(result.stdout) as { items?: unknown }).items; }
|
|
103
|
+
catch { return unavailable('pod-list-invalid'); }
|
|
104
|
+
if (!Array.isArray(items)) return unavailable('pod-list-invalid');
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
if (!item || typeof item !== 'object') return unavailable('pod-list-invalid');
|
|
107
|
+
const pod = item as { metadata?: { name?: unknown; namespace?: unknown; deletionTimestamp?: unknown; labels?: Record<string, unknown>; ownerReferences?: Array<{ kind?: unknown; name?: unknown }> }; status?: { phase?: unknown } };
|
|
108
|
+
const phase = pod.status?.phase;
|
|
109
|
+
if (phase === 'Succeeded' || phase === 'Failed') continue;
|
|
110
|
+
if (phase !== 'Pending' && phase !== 'Running') return unavailable('pod-list-invalid');
|
|
111
|
+
// Deleting Pods are already leaving the pool and must not keep the selected host occupied.
|
|
112
|
+
if (pod.metadata?.deletionTimestamp != null) continue;
|
|
113
|
+
const context = member.context;
|
|
114
|
+
const namespace = pod.metadata?.namespace;
|
|
115
|
+
const owner = pod.metadata?.ownerReferences?.find(ref => ref.kind === 'Job')?.name;
|
|
116
|
+
const job = owner ?? pod.metadata?.labels?.['job-name'];
|
|
117
|
+
if (typeof namespace !== 'string' || !namespace || typeof job !== 'string' || !job) return unavailable('pod-list-invalid');
|
|
118
|
+
const identity = { context, namespace, job };
|
|
119
|
+
activeJobs.set(`${context}\0${namespace}\0${job}`, identity);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const reading = readGateHostResources({ leases, activeJobs: [...activeJobs.values()] });
|
|
123
|
+
debug.log('release-loop.gate', 'host-resource-probe', { host: selectedHost, poolContexts: selectedMembers.map(member => member.context), ...reading });
|
|
124
|
+
return reading;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function activeJobKey(job: PendingJobIdentity): string | null {
|
|
128
|
+
return typeof job?.context === 'string' && job.context.length > 0 &&
|
|
129
|
+
typeof job.namespace === 'string' && job.namespace.length > 0 &&
|
|
130
|
+
typeof job.job === 'string' && job.job.length > 0
|
|
131
|
+
? `${job.context}\0${job.namespace}\0${job.job}` : null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Read the resource ledgers as the authority for host occupancy. Process argv is deliberately not an input:
|
|
136
|
+
* unrelated commands that happen to contain `bun test` do not reserve a gate host.
|
|
137
|
+
* A Job-backed lease and its active Job are one reservation; a lease without an observed Job remains reserved.
|
|
138
|
+
*/
|
|
139
|
+
export function readGateHostResources(snapshot: GateHostResourceSnapshot): GateHostResourceReading {
|
|
140
|
+
if (snapshot.leases === null) return { status: 'unmeasurable', empty: null, reason: 'lease-ledger-unavailable' };
|
|
141
|
+
if (snapshot.activeJobs === null) return { status: 'unmeasurable', empty: null, reason: 'pod-list-unavailable' };
|
|
142
|
+
if (!Array.isArray(snapshot.leases) || snapshot.leases.some((lease) => !lease ||
|
|
143
|
+
!Number.isSafeInteger(lease.pid) || lease.pid <= 0 || typeof lease.startedAt !== 'string' || !lease.startedAt || typeof lease.at !== 'string' ||
|
|
144
|
+
(lease.stage !== undefined && lease.stage !== 'authoring' && lease.stage !== 'job') ||
|
|
145
|
+
(lease.stage === 'job' && (!lease.job || !lease.context || !lease.namespace)))) {
|
|
146
|
+
return { status: 'unmeasurable', empty: null, reason: 'lease-ledger-invalid' };
|
|
147
|
+
}
|
|
148
|
+
if (!Array.isArray(snapshot.activeJobs) || snapshot.activeJobs.some((job) => !job || activeJobKey(job) === null)) {
|
|
149
|
+
return { status: 'unmeasurable', empty: null, reason: 'pod-list-invalid' };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const jobs = new Set(snapshot.activeJobs.map(activeJobKey) as string[]);
|
|
153
|
+
// Authoring leases have no host/context yet, so they conservatively occupy each selected host in the shared pool.
|
|
154
|
+
let authoringLeases = 0;
|
|
155
|
+
let waitingJobs = 0;
|
|
156
|
+
for (const lease of snapshot.leases) {
|
|
157
|
+
if (lease.stage !== 'job') { authoringLeases++; continue; }
|
|
158
|
+
const key = lease.job && lease.context && lease.namespace
|
|
159
|
+
? activeJobKey({ job: lease.job, context: lease.context, namespace: lease.namespace }) : null;
|
|
160
|
+
if (!key || !jobs.has(key)) waitingJobs++;
|
|
161
|
+
}
|
|
162
|
+
const reservations = authoringLeases + waitingJobs + jobs.size;
|
|
163
|
+
return { status: 'measured', empty: reservations === 0, reservations, authoringLeases, waitingJobs, activeJobs: jobs.size };
|
|
164
|
+
}
|
|
165
|
+
|
|
22
166
|
const hostName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
23
167
|
const claimsDir = (root: string) => join(root, 'release', 'gate-host-reservations');
|
|
24
168
|
|