elanous 0.2.21 → 0.2.23
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/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-111cabe4d1fd69ae.js → page-6168a7c43e6ef8f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
- 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 -23
- 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 +22 -22
- 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 -1
- package/apps/pwa/out/live-run/index.txt +24 -23
- 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/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/drafts/recipes.yaml +2 -2
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/graphs/test-diet/recipes.yaml +3 -0
- package/graphs/test-diet/test-diet.yaml +3 -1
- package/package.json +4 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +10 -1
- package/scripts/f-session-monitor.ts +69 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/hq/standby-snapshot.ts +7 -3
- package/scripts/knowledge-compress.ts +11 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/nightly-docops.ts +90 -3
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +73 -7
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +34 -4
- package/scripts/release-loop/resume.ts +53 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +8 -1
- package/scripts/research-coo-admin-dates.ts +39 -0
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/skills/public-check.ts +7 -2
- package/scripts/smart-merge/resync-shadow.ts +5 -3
- package/scripts/test-diet/lib.ts +81 -1
- package/scripts/test-diet/node.ts +48 -2
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +8 -4
- package/scripts/verify-coo-admin-evidence.ts +83 -0
- package/src/acp/client.ts +4 -2
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +14 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-env/profile.ts +25 -5
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +27 -13
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/review-loop.ts +33 -5
- package/src/agent-mission/supervisor-metrics.ts +17 -2
- package/src/agent-substrate/acp-reviewer.ts +25 -9
- package/src/agent-substrate/pr-reviewer.ts +175 -32
- package/src/agent-substrate/review-intent.ts +106 -5
- package/src/agent-substrate/self-review-cli.ts +111 -16
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +238 -20
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/pr-manager.ts +30 -11
- package/src/away/release-watch.ts +47 -8
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +123 -22
- package/src/chat/index.ts +13 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/brief-cli.ts +46 -22
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/config-classify.ts +83 -0
- package/src/cli/control-cli.ts +14 -0
- package/src/cli/decisions-cli.ts +26 -16
- package/src/cli/log-event-names.ts +3 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/logs-model-input.ts +1 -1
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +94 -9
- package/src/cli/pr-land-overlap-evidence.ts +131 -0
- package/src/cli/release-cli.ts +74 -15
- package/src/cli/self-update.ts +173 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -28
- package/src/connectors/types.ts +6 -6
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +29 -0
- package/src/context-bus/coord-events.ts +32 -4
- package/src/context-bus/long-term-memory.ts +26 -7
- package/src/context-bus/nightly-condense.ts +170 -21
- package/src/control/control-status.ts +87 -0
- package/src/control-plane/light-member.ts +5 -3
- package/src/control-plane/member.ts +172 -7
- package/src/core-turn/run-goal-loop.ts +108 -3
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +27 -5
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -3
- package/src/dashboard/stale-install-check.ts +13 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +159 -0
- package/src/debug/log.ts +52 -17
- package/src/decisions/decision-cards.ts +20 -1
- package/src/decisions/decision-ledger.ts +11 -8
- package/src/decisions/web-push-decision-cards.ts +19 -3
- package/src/discord-self-message.ts +2 -2
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-dates.evidence.json +876 -0
- package/src/domains/coo-admin-tool.ts +75 -14
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/ops-status.ts +53 -0
- package/src/domains/outbound-alert.ts +41 -7
- package/src/domains/release-tool.ts +119 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/exec-requests/planner.ts +6 -0
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +1 -0
- package/src/graph-kinds/registry.ts +6 -6
- package/src/graph-runner/graph-cli.ts +34 -2
- package/src/graph-runner/graph-run-api.ts +7 -0
- package/src/graph-runner/graph-tick.ts +73 -12
- package/src/graph-runner/runner.ts +94 -13
- package/src/graph-unify/wf-to-graph.ts +79 -0
- package/src/graph-wizard/generate.ts +34 -2
- package/src/graph-wizard/steps.ts +13 -0
- package/src/harness/dispatch-backpressure.ts +259 -0
- package/src/harness/harness-cli-command.ts +227 -50
- package/src/harness/harness-queue.ts +58 -14
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-substrate-default.ts +72 -1
- package/src/harness/launch-advice.ts +23 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +114 -18
- package/src/index.ts +199 -71
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +41 -0
- package/src/knowledge/conclusion-compress.ts +93 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/know-find.ts +9 -2
- package/src/knowledge/query.ts +20 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-provider.ts +175 -0
- package/src/llm/bedrock.ts +345 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm.ts +332 -51
- package/src/loops/budget.ts +150 -0
- package/src/loops/neighbor-runtime.ts +88 -0
- package/src/loops/orchestrator/author-depth.ts +29 -11
- package/src/loops/orchestrator/overlap.ts +7 -1
- package/src/loops/orchestrator/resync-shadow.ts +1 -1
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/tick.ts +35 -2
- package/src/loops/orchestrator/traffic.ts +6 -80
- package/src/loops/registry.ts +5 -0
- package/src/market/publish.ts +17 -1
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -1
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +48 -4
- package/src/models/prompts.ts +22 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +204 -15
- package/src/mss/logging/redaction.ts +17 -0
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/draft-metrics.ts +22 -8
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/graph-peer-edit.ts +77 -0
- package/src/nexus/api/graph-wizard-api.ts +9 -1
- package/src/nexus/api/graphs-api.ts +145 -7
- package/src/nexus/api/http-server.ts +101 -8
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/plugins-market.ts +24 -0
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +13 -2
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/oauth/claude-pty-maturity.ts +24 -0
- package/src/oauth/codex-account-rotation.ts +16 -18
- package/src/oauth/codex-account-store.ts +134 -5
- package/src/oauth/fallback-chain.ts +50 -15
- package/src/onboarding.ts +2 -1
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/market-bundle.ts +9 -0
- package/src/plugins/maker/plugin-maker.ts +32 -21
- package/src/plugins/maker/wizard-generate.ts +87 -9
- package/src/policy/llm-policy.ts +24 -6
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +10 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-enhance/enhance.ts +46 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist-board.ts +27 -0
- package/src/release-loop/checklist.ts +62 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +91 -22
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/retro/daily.ts +23 -9
- package/src/seat-address/seat-address.ts +1 -0
- package/src/seat-loop/seat-loop.ts +208 -21
- package/src/seat-loop/seat-report.ts +29 -1
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +157 -11
- package/src/self-dev/dev-pipeline.ts +18 -1
- package/src/self-dev/draft-residue.ts +463 -0
- package/src/self-dev/draft-sweep.ts +195 -17
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +57 -2
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +9 -133
- package/src/self-dev/review-provider-fallback.ts +179 -0
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +8 -23
- package/src/self-dev/run-types.ts +178 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +2 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author.ts +24 -4
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +4 -0
- package/src/self-implement/harness-policy-gates.ts +7 -5
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/host-regate.ts +148 -43
- package/src/self-implement/l8-merge-queue.ts +147 -13
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +201 -43
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/seams.ts +41 -6
- package/src/self-implement/self-implement-cli.ts +6 -0
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/shell-env-bootstrap.ts +19 -4
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +20 -9
- package/src/steward/triage.ts +29 -10
- package/src/storage/file-lock.ts +40 -4
- package/src/task-agent/actions.ts +4 -0
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +31 -3
- package/src/task-agent/cover.ts +61 -0
- package/src/task-agent/judge.ts +4 -3
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +133 -0
- package/src/task-agent/live-moves.ts +222 -12
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +297 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/shadow.ts +118 -7
- package/src/task-agent/task-hand.ts +138 -11
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +203 -28
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +11 -0
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-project-command.ts +6 -0
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/typecheck-ratchet.ts +2 -1
- package/src/user-config.ts +167 -28
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/executor.ts +24 -2
- package/src/workflow-runtime/triggers/registry.ts +27 -0
- package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +0 -1
- /package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
|
@@ -25,19 +25,21 @@ function storeDir(root: string): string { return join(root, 'error-reports'); }
|
|
|
25
25
|
/** Removes day folders older than the keep window. Returns how many days were removed. */
|
|
26
26
|
export function pruneErrorReports(root: string, now: number): number {
|
|
27
27
|
const base = storeDir(root);
|
|
28
|
-
if (!existsSync(base)) return 0;
|
|
29
28
|
let removed = 0;
|
|
30
|
-
|
|
31
|
-
for (const
|
|
32
|
-
for (const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
if (existsSync(base)) {
|
|
30
|
+
for (const year of readdirSync(base).filter((n) => /^\d{4}$/.test(n))) {
|
|
31
|
+
for (const month of readdirSync(join(base, year)).filter((n) => /^\d{2}$/.test(n))) {
|
|
32
|
+
for (const day of readdirSync(join(base, year, month)).filter((n) => /^\d{2}$/.test(n))) {
|
|
33
|
+
const at = Date.parse(`${year}-${month}-${day}T00:00:00Z`);
|
|
34
|
+
if (Number.isFinite(at) && now - at > ERROR_REPORT_KEEP_DAYS * DAY_MS + DAY_MS) {
|
|
35
|
+
rmSync(join(base, year, month, day), { recursive: true, force: true });
|
|
36
|
+
removed++;
|
|
37
|
+
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
debug.log('error-report.prune', 'done', { pruned: removed });
|
|
41
43
|
return removed;
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -77,6 +79,26 @@ function count24h(root: string, dedupe: string, now: number): number {
|
|
|
77
79
|
return n;
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
/** Retention without a receipt: prune once at daemon boot and then once a day (the ingest path still prunes too). */
|
|
83
|
+
export function startErrorReportPruneTick(deps: {
|
|
84
|
+
root?: () => string;
|
|
85
|
+
now?: () => number;
|
|
86
|
+
schedule?: (tick: () => void, ms: number) => { unref?: () => void };
|
|
87
|
+
} = {}): { stop(): void } {
|
|
88
|
+
const root = deps.root ?? effectiveInstanceRoot;
|
|
89
|
+
const now = deps.now ?? Date.now;
|
|
90
|
+
const run = (trigger: 'boot' | 'tick') => {
|
|
91
|
+
// pruneErrorReports emits error-report.prune/done { pruned }; only a failure is logged here.
|
|
92
|
+
try { pruneErrorReports(root(), now()); }
|
|
93
|
+
catch (error) { debug.log('error-report.prune', 'failed', { trigger, reason: error instanceof Error ? error.message : String(error) }); }
|
|
94
|
+
};
|
|
95
|
+
run('boot');
|
|
96
|
+
let stopped = false;
|
|
97
|
+
const handle = (deps.schedule ?? ((tick, ms) => setInterval(tick, ms)))(() => { if (!stopped) run('tick'); }, DAY_MS);
|
|
98
|
+
handle.unref?.();
|
|
99
|
+
return { stop: () => { stopped = true; if (!deps.schedule) clearInterval(handle as ReturnType<typeof setInterval>); } };
|
|
100
|
+
}
|
|
101
|
+
|
|
80
102
|
/** POST /v1/reports/ingest — the caller (router) has already checked the ingest token. */
|
|
81
103
|
export async function handleErrorReportIngest(req: Request, deps: ErrorReportIngestDeps = {}): Promise<Response> {
|
|
82
104
|
const root = (deps.root ?? effectiveInstanceRoot)();
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// W9c run guard (TC security review of #25123) — a peer «edit» grant lets another token rewrite a «mine» graph.
|
|
2
|
+
// Running that graph would run the peer's change with this machine's privileges, so a peer save leaves a
|
|
3
|
+
// marker next to the graph's access grants (`<mine>/.access/<id>.peer-edit.json`) and every run entry for a
|
|
4
|
+
// «mine» graph refuses it until the owner approves that exact version (or re-saves it themselves).
|
|
5
|
+
// Fail closed: a marker that exists but cannot be read or parsed refuses the run.
|
|
6
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
9
|
+
|
|
10
|
+
export const PEER_EDIT_REFUSAL = '상대가 바꾼 그래프 — 변경을 확인하고 승인해야 실행할 수 있다';
|
|
11
|
+
|
|
12
|
+
export interface PeerEditRecord {
|
|
13
|
+
/** `peer:<first 8 hex of the peer token's sha256>` — never the token itself. */
|
|
14
|
+
editedBy: string;
|
|
15
|
+
/** The version id the peer save produced (`pending` while the save is in flight). */
|
|
16
|
+
version: string;
|
|
17
|
+
at: string;
|
|
18
|
+
approved?: { version: string; at: string };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type PeerEditGate =
|
|
22
|
+
| { ok: true }
|
|
23
|
+
| { ok: false; error: 'peer-edit-unapproved'; record: PeerEditRecord }
|
|
24
|
+
| { ok: false; error: 'peer-edit-unreadable'; reason: string };
|
|
25
|
+
|
|
26
|
+
export function peerEditFile(mineDir: string, id: string): string {
|
|
27
|
+
return join(mineDir, '.access', `${id}.peer-edit.json`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** null = no peer ever saved this graph. Throws when the marker exists but is unreadable or malformed. */
|
|
31
|
+
export function readPeerEdit(mineDir: string, id: string): PeerEditRecord | null {
|
|
32
|
+
let text: string;
|
|
33
|
+
try { text = readFileSync(peerEditFile(mineDir, id), 'utf8'); }
|
|
34
|
+
catch (error) {
|
|
35
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
const parsed: unknown = JSON.parse(text);
|
|
39
|
+
const record = parsed as PeerEditRecord;
|
|
40
|
+
if (!parsed || typeof parsed !== 'object' || typeof record.editedBy !== 'string' || typeof record.version !== 'string'
|
|
41
|
+
|| typeof record.at !== 'string'
|
|
42
|
+
|| (record.approved !== undefined && (typeof record.approved !== 'object' || record.approved === null
|
|
43
|
+
|| typeof record.approved.version !== 'string' || typeof record.approved.at !== 'string'))) {
|
|
44
|
+
throw new Error('invalid peer-edit marker');
|
|
45
|
+
}
|
|
46
|
+
return record;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function writePeerEdit(mineDir: string, id: string, record: PeerEditRecord): void {
|
|
50
|
+
mkdirSync(join(mineDir, '.access'), { recursive: true, mode: 0o700 });
|
|
51
|
+
const target = peerEditFile(mineDir, id);
|
|
52
|
+
const temp = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
53
|
+
try {
|
|
54
|
+
writeFileSync(temp, JSON.stringify(record), { mode: 0o600 });
|
|
55
|
+
renameSync(temp, target);
|
|
56
|
+
} finally { rmSync(temp, { force: true }); }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** An owner-authorized save replaces the peer's bytes with bytes the owner chose. */
|
|
60
|
+
export function clearPeerEdit(mineDir: string, id: string): void {
|
|
61
|
+
rmSync(peerEditFile(mineDir, id), { force: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function peerEditRunGate(mineDir: string, id: string): PeerEditGate {
|
|
65
|
+
let record: PeerEditRecord | null;
|
|
66
|
+
try { record = readPeerEdit(mineDir, id); }
|
|
67
|
+
catch (error) { return { ok: false, error: 'peer-edit-unreadable', reason: String(error).slice(0, 200) }; }
|
|
68
|
+
if (!record || record.approved?.version === record.version) return { ok: true };
|
|
69
|
+
return { ok: false, error: 'peer-edit-unapproved', record };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** The 409 body every refusing run entry returns — `reason` is what the editor shows. */
|
|
73
|
+
export function peerEditRefusalBody(id: string, gate: Exclude<PeerEditGate, { ok: true }>): Record<string, unknown> {
|
|
74
|
+
return gate.error === 'peer-edit-unapproved'
|
|
75
|
+
? { error: gate.error, id, reason: PEER_EDIT_REFUSAL, editedBy: gate.record.editedBy, version: gate.record.version, editedAt: gate.record.at }
|
|
76
|
+
: { error: gate.error, id, reason: PEER_EDIT_REFUSAL, detail: gate.reason };
|
|
77
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { debug } from '../../debug/log.js';
|
|
2
|
-
import { GraphWizardInputError, generateGraphFromPrompt, type GraphWizardDeps, type GraphWizardTurn } from '../../graph-wizard/generate.js';
|
|
2
|
+
import { GraphWizardInputError, generateGraphFromPrompt, wizardInstalledPacks, type GraphWizardDeps, type GraphWizardTurn } from '../../graph-wizard/generate.js';
|
|
3
3
|
import { jsonResponse } from './json-response.js';
|
|
4
4
|
|
|
5
|
+
export function handleGraphWizardPacksGet(deps: GraphWizardDeps = {}): Response {
|
|
6
|
+
return jsonResponse({ packs: wizardInstalledPacks(deps) });
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
const MAX_PROMPT = 4000;
|
|
6
10
|
const MAX_YAML = 200_000;
|
|
7
11
|
|
|
@@ -28,6 +32,9 @@ export async function handleGraphWizardPost(req: Request, deps: GraphWizardDeps
|
|
|
28
32
|
if (body.currentYaml !== undefined && (typeof body.currentYaml !== 'string' || body.currentYaml.length > MAX_YAML)) {
|
|
29
33
|
return jsonResponse({ error: 'bad_request', reason: 'currentYaml must be a string' }, 400);
|
|
30
34
|
}
|
|
35
|
+
if (body.packId !== undefined && typeof body.packId !== 'string') {
|
|
36
|
+
return jsonResponse({ error: 'bad_request', reason: 'packId must be a string' }, 400);
|
|
37
|
+
}
|
|
31
38
|
let history: GraphWizardTurn[] | undefined;
|
|
32
39
|
if (body.history !== undefined) {
|
|
33
40
|
if (!Array.isArray(body.history) || !body.history.every((t) => t && typeof t === 'object' &&
|
|
@@ -42,6 +49,7 @@ export async function handleGraphWizardPost(req: Request, deps: GraphWizardDeps
|
|
|
42
49
|
...(body.kind ? { kind: body.kind as 'harness' | 'workflow' } : {}),
|
|
43
50
|
...(typeof body.currentYaml === 'string' && body.currentYaml.trim() ? { currentYaml: body.currentYaml } : {}),
|
|
44
51
|
...(history ? { history } : {}),
|
|
52
|
+
...(typeof body.packId === 'string' ? { packId: body.packId } : {}),
|
|
45
53
|
}, deps);
|
|
46
54
|
return jsonResponse({ ...result, base: result.base ?? null }, result.ok ? 200 : 422);
|
|
47
55
|
} catch (error) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { createHash, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
4
5
|
import { parse as parseYaml } from 'yaml';
|
|
5
6
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
6
7
|
import { debug } from '../../debug/log.js';
|
|
@@ -10,6 +11,7 @@ import { validateGraphYaml } from './graph-kinds.js';
|
|
|
10
11
|
import { parseWizardSteps, readWizardSteps, withWizardSteps } from '../../graph-wizard/saved-steps.js';
|
|
11
12
|
import type { WizardNodeStep } from '../../graph-wizard/steps.js';
|
|
12
13
|
import { jsonResponse } from './json-response.js';
|
|
14
|
+
import { clearPeerEdit, peerEditRefusalBody, peerEditRunGate, readPeerEdit, writePeerEdit } from './graph-peer-edit.js';
|
|
13
15
|
|
|
14
16
|
/** Declared graph ids only. A user string is never joined onto a filesystem path. */
|
|
15
17
|
const GRAPH_ID = /^[a-z0-9-]+$/;
|
|
@@ -44,6 +46,93 @@ function mineGraphsDir(): string {
|
|
|
44
46
|
return join(elanousStateRoot(), 'graphs');
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
export type GraphPermission = 'view' | 'edit';
|
|
50
|
+
type GraphGrant = { recipient: string; permission: GraphPermission };
|
|
51
|
+
const TOKEN_PATTERN = /^eg_[A-Za-z0-9_-]{32,}$/;
|
|
52
|
+
|
|
53
|
+
function accessFile(dir: string, id: string): string {
|
|
54
|
+
return join(dir, '.access', `${id}.json`);
|
|
55
|
+
}
|
|
56
|
+
function tokenHash(token: string): string {
|
|
57
|
+
return createHash('sha256').update(token).digest('hex');
|
|
58
|
+
}
|
|
59
|
+
function accessGrants(dir: string, id: string): GraphGrant[] {
|
|
60
|
+
let text: string;
|
|
61
|
+
try { text = readFileSync(accessFile(dir, id), 'utf8'); }
|
|
62
|
+
catch (error) {
|
|
63
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
const parsed: unknown = JSON.parse(text);
|
|
67
|
+
if (!Array.isArray(parsed) || !parsed.every((entry): entry is GraphGrant => entry !== null && typeof entry === 'object'
|
|
68
|
+
&& typeof entry.recipient === 'string' && /^[a-f0-9]{64}$/.test(entry.recipient)
|
|
69
|
+
&& (entry.permission === 'view' || entry.permission === 'edit'))) throw new Error('invalid graph access store');
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Only a hash is persisted; no owner bearer or raw recipient credential goes into a graph/YAML. */
|
|
74
|
+
export function handleGraphAccess(pathname: string, req: Request, deps: GraphsApiDeps = {}): Response {
|
|
75
|
+
const match = /^\/v1\/graphs\/([^/]+)\/access$/.exec(pathname);
|
|
76
|
+
const id = match ? resolveId(match[1]!) : null;
|
|
77
|
+
if (!id) return jsonResponse({ error: 'bad_request' }, 400);
|
|
78
|
+
const owned = mineOwnership(id, deps);
|
|
79
|
+
if (owned instanceof Response) return owned;
|
|
80
|
+
if (req.method !== 'GET') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
81
|
+
try { return jsonResponse({ grants: accessGrants(owned.mineDir, id) }); }
|
|
82
|
+
catch (error) { return saveFailed(id, error); }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function handleGraphAccessPut(pathname: string, req: Request, deps: GraphsApiDeps = {}): Promise<Response> {
|
|
86
|
+
const match = /^\/v1\/graphs\/([^/]+)\/access$/.exec(pathname);
|
|
87
|
+
const id = match ? resolveId(match[1]!) : null;
|
|
88
|
+
if (!id) return jsonResponse({ error: 'bad_request' }, 400);
|
|
89
|
+
const owned = mineOwnership(id, deps);
|
|
90
|
+
if (owned instanceof Response) return owned;
|
|
91
|
+
// Detail GET resolves a core id first; do not grant a token for a shadowed mine id.
|
|
92
|
+
if (indexByDeclaredId(deps.coreDir ?? defaultGraphsDir()).has(id)) return jsonResponse({ error: 'core-id-conflict', id }, 409);
|
|
93
|
+
let body: { recipient?: unknown; permission?: unknown };
|
|
94
|
+
try { body = await req.json() as typeof body; }
|
|
95
|
+
catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
96
|
+
if (!body || typeof body.recipient !== 'string' || !TOKEN_PATTERN.test(body.recipient)
|
|
97
|
+
|| (body.permission !== 'view' && body.permission !== 'edit')) {
|
|
98
|
+
return jsonResponse({ error: 'bad_request', reason: 'recipient access token and view/edit permission required' }, 400);
|
|
99
|
+
}
|
|
100
|
+
const recipient = tokenHash(body.recipient);
|
|
101
|
+
const dir = join(owned.mineDir, '.access');
|
|
102
|
+
try {
|
|
103
|
+
const grants = accessGrants(owned.mineDir, id).filter((grant) => grant.recipient !== recipient);
|
|
104
|
+
grants.push({ recipient, permission: body.permission });
|
|
105
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
106
|
+
const target = accessFile(owned.mineDir, id);
|
|
107
|
+
const temp = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
108
|
+
try {
|
|
109
|
+
writeFileSync(temp, JSON.stringify(grants), { mode: 0o600 });
|
|
110
|
+
renameSync(temp, target);
|
|
111
|
+
} finally { rmSync(temp, { force: true }); }
|
|
112
|
+
} catch (error) { return saveFailed(id, error); }
|
|
113
|
+
return jsonResponse({ recipient, permission: body.permission });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** The peer token works only on this graph and the requested read/edit operation. */
|
|
117
|
+
export function graphAccessForRequest(pathname: string, method: string, token: string | null, deps: GraphsApiDeps = {}): boolean {
|
|
118
|
+
const match = /^\/v1\/graphs\/([^/]+)(?:\/(yaml))?$/.exec(pathname);
|
|
119
|
+
const id = match ? resolveId(match[1]!) : null;
|
|
120
|
+
if (!id || !token || !TOKEN_PATTERN.test(token)) return false;
|
|
121
|
+
if (method !== 'GET' && !(method === 'PUT' && match?.[2] === 'yaml')) return false;
|
|
122
|
+
try {
|
|
123
|
+
if (!indexByDeclaredId(deps.mineDir ?? mineGraphsDir()).has(id)) return false;
|
|
124
|
+
if (indexByDeclaredId(deps.coreDir ?? defaultGraphsDir()).has(id)) return false;
|
|
125
|
+
const wanted = tokenHash(token);
|
|
126
|
+
return accessGrants(deps.mineDir ?? mineGraphsDir(), id).some((grant) => {
|
|
127
|
+
const stored = Buffer.from(grant.recipient, 'hex');
|
|
128
|
+
return timingSafeEqual(stored, Buffer.from(wanted, 'hex')) && (method === 'GET' || grant.permission === 'edit');
|
|
129
|
+
});
|
|
130
|
+
} catch (error) {
|
|
131
|
+
debug.log('nexus.graphs', 'access-read-failed', { id, reason: String(error) }, { level: 'warn' });
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
47
136
|
function resolveId(raw: string): string | null {
|
|
48
137
|
let id: string;
|
|
49
138
|
try { id = decodeURIComponent(raw); }
|
|
@@ -203,7 +292,10 @@ export function handleGraphsGet(pathname: string, dir = defaultGraphsDir(), deps
|
|
|
203
292
|
}
|
|
204
293
|
|
|
205
294
|
/** PUT writes only under the state-root graphs directory. Core YAML is never opened for write. */
|
|
206
|
-
|
|
295
|
+
/** Who authorized a save: the owner, or a peer token holding an «edit» grant (raw token; only a hash prefix is kept). */
|
|
296
|
+
export type GraphSaveActor = { peerToken: string } | null;
|
|
297
|
+
|
|
298
|
+
export async function handleGraphsPut(pathname: string, req: Request, deps: GraphsApiDeps = {}, actor: GraphSaveActor = null): Promise<Response> {
|
|
207
299
|
const match = /^\/v1\/graphs\/([^/]+)\/yaml$/.exec(pathname);
|
|
208
300
|
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
209
301
|
const id = resolveId(match[1]!);
|
|
@@ -229,11 +321,21 @@ export async function handleGraphsPut(pathname: string, req: Request, deps: Grap
|
|
|
229
321
|
// Writes go only to <mine>/<id>.yaml; a hand-placed file under another name is not edited over HTTP.
|
|
230
322
|
if (existing.file !== `${id}.yaml`) return jsonResponse({ error: 'file-name-mismatch', id, file: existing.file }, 409);
|
|
231
323
|
let written: { version: string; previous: string };
|
|
232
|
-
|
|
324
|
+
const editedBy = actor ? `peer:${tokenHash(actor.peerToken).slice(0, 8)}` : null;
|
|
325
|
+
try {
|
|
326
|
+
written = withWizardSteps(mineDir, id, steps, () => {
|
|
327
|
+
// Peer save: the marker goes down «before» the bytes, so a crash in between still refuses the run.
|
|
328
|
+
if (editedBy) writePeerEdit(mineDir, id, { editedBy, version: 'pending', at: new Date().toISOString() });
|
|
329
|
+
const result = writeWithVersion(mineDir, id, existing, body.yaml as string);
|
|
330
|
+
if (editedBy) writePeerEdit(mineDir, id, { editedBy, version: result.version, at: new Date().toISOString() });
|
|
331
|
+
else clearPeerEdit(mineDir, id);
|
|
332
|
+
return result;
|
|
333
|
+
});
|
|
334
|
+
}
|
|
233
335
|
catch (error) { return saveFailed(id, error); }
|
|
234
336
|
const { version, previous } = written;
|
|
235
|
-
debug.log('nexus.graphs', 'saved', { id, version, previous, steps: steps ? Object.keys(steps).length : 0 });
|
|
236
|
-
return jsonResponse({ id, source: 'mine', editable: true, saved: true, version, previous });
|
|
337
|
+
debug.log('nexus.graphs', 'saved', { id, version, previous, steps: steps ? Object.keys(steps).length : 0, ...(editedBy ? { editedBy } : {}) });
|
|
338
|
+
return jsonResponse({ id, source: 'mine', editable: true, saved: true, version, previous, ...(editedBy ? { editedBy } : {}) });
|
|
237
339
|
}
|
|
238
340
|
|
|
239
341
|
const VERSION_ID = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z(?:-\d{4})?$/;
|
|
@@ -408,8 +510,14 @@ export async function handleGraphsClone(pathname: string, req: Request, deps: Gr
|
|
|
408
510
|
if (reservedId) return reservedId;
|
|
409
511
|
const coreDir = deps.coreDir ?? defaultGraphsDir();
|
|
410
512
|
const mineDir = deps.mineDir ?? mineGraphsDir();
|
|
411
|
-
const
|
|
513
|
+
const fromCore = indexByDeclaredId(coreDir).get(id);
|
|
514
|
+
const source = fromCore ?? indexByDeclaredId(mineDir).get(id);
|
|
412
515
|
if (!source) return jsonResponse({ error: 'not-found', id }, 404);
|
|
516
|
+
// A clone would carry a peer's unapproved change into a graph with no marker — approve first.
|
|
517
|
+
if (!fromCore) {
|
|
518
|
+
const gate = peerEditRunGate(mineDir, id);
|
|
519
|
+
if (!gate.ok) return jsonResponse(peerEditRefusalBody(id, gate), 409);
|
|
520
|
+
}
|
|
413
521
|
if (indexByDeclaredId(mineDir).has(body.newId) || indexByDeclaredId(coreDir).has(body.newId)) {
|
|
414
522
|
return jsonResponse({ error: 'conflict', id: body.newId }, 409);
|
|
415
523
|
}
|
|
@@ -422,9 +530,39 @@ export async function handleGraphsClone(pathname: string, req: Request, deps: Gr
|
|
|
422
530
|
return jsonResponse({ id: body.newId, source: 'mine', editable: true, clonedFrom: id }, 201);
|
|
423
531
|
}
|
|
424
532
|
|
|
425
|
-
|
|
533
|
+
/** POST /v1/graphs/<id>/approve {version} — owner only (the route never accepts a peer token). Approves the
|
|
534
|
+
* exact peer version the run refusal named; a newer peer save is a new version and needs a new approval. */
|
|
535
|
+
export async function handleGraphsApprove(pathname: string, req: Request, deps: GraphsApiDeps = {}): Promise<Response> {
|
|
536
|
+
const match = /^\/v1\/graphs\/([^/]+)\/approve$/.exec(pathname);
|
|
537
|
+
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
538
|
+
const id = resolveId(match[1]!);
|
|
539
|
+
if (!id) return jsonResponse({ error: 'bad_request', reason: 'invalid graph id' }, 400);
|
|
540
|
+
const owned = mineOwnership(id, deps);
|
|
541
|
+
if (owned instanceof Response) return owned;
|
|
542
|
+
let body: { version?: unknown };
|
|
543
|
+
try { body = await req.json() as { version?: unknown }; }
|
|
544
|
+
catch { return jsonResponse({ error: 'bad_request', reason: 'json body required' }, 400); }
|
|
545
|
+
if (typeof body?.version !== 'string' || !body.version) return jsonResponse({ error: 'bad_request', reason: 'version string required' }, 400);
|
|
546
|
+
let record;
|
|
547
|
+
try { record = readPeerEdit(owned.mineDir, id); }
|
|
548
|
+
catch (error) { return saveFailed(id, error); }
|
|
549
|
+
if (!record) return jsonResponse({ id, approved: true, version: body.version, pending: false });
|
|
550
|
+
if (record.version !== body.version) {
|
|
551
|
+
return jsonResponse({ error: 'version-mismatch', id, version: record.version, reason: '승인하려는 판이 최신 상대 변경과 다르다 — 다시 확인하라' }, 409);
|
|
552
|
+
}
|
|
553
|
+
const approved = { version: record.version, at: new Date().toISOString() };
|
|
554
|
+
try { writePeerEdit(owned.mineDir, id, { ...record, approved }); }
|
|
555
|
+
catch (error) { return saveFailed(id, error); }
|
|
556
|
+
debug.log('nexus.graphs', 'peer-edit-approved', { id, version: record.version, editedBy: record.editedBy });
|
|
557
|
+
return jsonResponse({ id, approved: true, version: record.version, editedBy: record.editedBy });
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export async function handleGraphsMutation(pathname: string, req: Request, deps: GraphsApiDeps = {}, actor: GraphSaveActor = null): Promise<Response | null> {
|
|
561
|
+
// Only PUT …/yaml is open to a peer token; every other mutation is the owner's alone.
|
|
562
|
+
if (actor && !(req.method === 'PUT' && /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname))) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
426
563
|
if (req.method === 'POST' && pathname === '/v1/graphs') return handleGraphsCreate(req, deps);
|
|
427
|
-
if (req.method === 'PUT' && /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname)) return handleGraphsPut(pathname, req, deps);
|
|
564
|
+
if (req.method === 'PUT' && /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname)) return handleGraphsPut(pathname, req, deps, actor);
|
|
565
|
+
if (req.method === 'POST' && /^\/v1\/graphs\/[^/]+\/approve$/.test(pathname)) return handleGraphsApprove(pathname, req, deps);
|
|
428
566
|
if (req.method === 'POST' && /^\/v1\/graphs\/[^/]+\/clone$/.test(pathname)) return handleGraphsClone(pathname, req, deps);
|
|
429
567
|
if (req.method === 'POST' && /^\/v1\/graphs\/[^/]+\/revert$/.test(pathname)) return handleGraphsRevert(pathname, req, deps);
|
|
430
568
|
return null;
|
|
@@ -19,7 +19,9 @@ import { setInProcessOutbound } from '../../domains/outbound-alert.js';
|
|
|
19
19
|
import { getUserConfig } from '../../user-config.js';
|
|
20
20
|
import type { TelegramEvent } from '../../workflow-runtime/triggers/telegram-source.js';
|
|
21
21
|
import { spawnSync } from 'node:child_process';
|
|
22
|
-
import { isAbsolute } from 'node:path';
|
|
22
|
+
import { isAbsolute, join, dirname, relative } from 'node:path';
|
|
23
|
+
import { homedir } from 'node:os';
|
|
24
|
+
import { readdirSync, realpathSync, statSync } from 'node:fs';
|
|
23
25
|
import { createProject, listProjects } from '../../project/project-store.js';
|
|
24
26
|
import { handleOutputsGet, type OutputsDeps } from './outputs-route.js';
|
|
25
27
|
import { buildGridData, type GridDeps } from './grid.js';
|
|
@@ -168,6 +170,7 @@ import { handleBuildsGet, parseBuildsPath } from './builds-api.js';
|
|
|
168
170
|
import { handleHarnessAskPost, handleHarnessAskStatusGet, handleHarnessRunEventsGet, handleHarnessRunScreenGet, handleHarnessRunsGet, handleHarnessStopPost } from './harness-api.js';
|
|
169
171
|
import { handleHarnessRunTraversalGet } from './harness-traversal.js';
|
|
170
172
|
import { handleLoopEdgesGet } from './loop-edges.js';
|
|
173
|
+
import { handleLoopResourcesGet } from './loop-resources.js';
|
|
171
174
|
import { handleFabricPlans, type FabricPlansRouteOpts } from './fabric-plans.js';
|
|
172
175
|
import { dispatchPersonaRoute } from './personas.js';
|
|
173
176
|
import { handleMe, operatorSignal } from './operator.js';
|
|
@@ -368,12 +371,12 @@ import {
|
|
|
368
371
|
} from './workflows.js';
|
|
369
372
|
import { handleTriggersSnapshot } from './triggers.js';
|
|
370
373
|
import { handleWorkflowTemplatesList } from './workflow-templates.js';
|
|
371
|
-
import { handleGraphVersionsGet, handleGraphsGet, handleGraphsMutation } from './graphs-api.js';
|
|
374
|
+
import { graphAccessForRequest, handleGraphAccess, handleGraphAccessPut, handleGraphVersionsGet, handleGraphsGet, handleGraphsMutation } from './graphs-api.js';
|
|
372
375
|
import { handleGraphKindsGet, handleGraphsValidatePost } from './graph-kinds.js';
|
|
373
|
-
import { handleGraphWizardPost } from './graph-wizard-api.js';
|
|
376
|
+
import { handleGraphWizardPost, handleGraphWizardPacksGet } from './graph-wizard-api.js';
|
|
374
377
|
import { syncInstalledPluginNodes } from '../../graph-kinds/installed-plugin-nodes.js';
|
|
375
378
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
376
|
-
import { handlePluginsIndexGet, handlePluginsGet, handlePluginsMarketRefresh, handlePluginsInstall, handlePluginsRemove } from './plugins-market.js';
|
|
379
|
+
import { handlePluginsIndexGet, handlePluginsGet, handlePluginsMarketRefresh, handlePluginsInstall, handlePluginsRemove, handlePluginWizardList, handlePluginWizardSave } from './plugins-market.js';
|
|
377
380
|
import { handlePluginsCredentialsGet, handlePluginsCredentialsPut } from './plugins-credentials-api.js';
|
|
378
381
|
import {
|
|
379
382
|
handleWorkflowsList,
|
|
@@ -489,11 +492,15 @@ export interface NexusHttpServerOpts {
|
|
|
489
492
|
fabricPlans?: FabricPlansRouteOpts;
|
|
490
493
|
/** GRAPH-WIZARD 시험 주입(LLM·템플릿 뿌리). 운영은 비워 둔다. */
|
|
491
494
|
graphWizard?: import('../../graph-wizard/generate.js').GraphWizardDeps;
|
|
495
|
+
/** Roots the remote folder picker may browse (default: the daemon user's home). Tests inject a temp root. */
|
|
496
|
+
projectFolderRoots?: string[];
|
|
492
497
|
/** Optional installer state root for isolated API consumers and tests. */
|
|
493
498
|
pluginStateRoot?: string;
|
|
494
499
|
outputs?: OutputsDeps;
|
|
495
500
|
/** Read-only grid measurement seam; omitted in production for live HQ and Pod pool reads. */
|
|
496
501
|
grid?: GridDeps;
|
|
502
|
+
/** Resource observation seam; production reads the same ORCH traffic decision. */
|
|
503
|
+
loopResources?: Parameters<typeof handleLoopResourcesGet>[0];
|
|
497
504
|
/** DRAFT-METRIC cached source seam; omitted in production for the process-wide TTL cache. */
|
|
498
505
|
draftMetrics?: DraftMetricsSource;
|
|
499
506
|
decisions?: Pick<DecisionsRouteDeps, 'ledger'>;
|
|
@@ -846,6 +853,55 @@ export function handleProjectsGet(): Response {
|
|
|
846
853
|
return jsonResponse({ projects: listProjects() });
|
|
847
854
|
}
|
|
848
855
|
|
|
856
|
+
function isWithinRoot(path: string, root: string): boolean {
|
|
857
|
+
const rel = relative(root, path);
|
|
858
|
+
return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Remote folder picker: lists sub-folders under an allow-listed root only.
|
|
863
|
+
* Every path is resolved with realpath first, so `..` segments and symlinks cannot escape the roots;
|
|
864
|
+
* dot-folders are hidden and symlinked entries that point outside the roots are not listed.
|
|
865
|
+
*/
|
|
866
|
+
export function handleProjectFoldersGet(req: Request, roots: string[] = [homedir()]): Response {
|
|
867
|
+
const allowed: string[] = [];
|
|
868
|
+
for (const root of roots) {
|
|
869
|
+
try { allowed.push(realpathSync(root)); } catch { /* a missing root grants nothing */ }
|
|
870
|
+
}
|
|
871
|
+
if (allowed.length === 0) return jsonResponse({ error: 'folder_unavailable' }, 404);
|
|
872
|
+
const requested = new URL(req.url).searchParams.get('path') ?? allowed[0]!;
|
|
873
|
+
if (!isAbsolute(requested) || requested.includes('\0')) return jsonResponse({ error: 'invalid_folder' }, 400);
|
|
874
|
+
let path: string;
|
|
875
|
+
try { path = realpathSync(requested); }
|
|
876
|
+
catch {
|
|
877
|
+
debug.log('nexus.projects', 'folders-unavailable', { reason: 'missing' });
|
|
878
|
+
return jsonResponse({ error: 'folder_unavailable' }, 404);
|
|
879
|
+
}
|
|
880
|
+
if (!allowed.some(root => isWithinRoot(path, root))) {
|
|
881
|
+
debug.log('nexus.projects', 'folders-refused', { reason: 'outside-roots' });
|
|
882
|
+
return jsonResponse({ error: 'outside_allowed_roots' }, 403);
|
|
883
|
+
}
|
|
884
|
+
try {
|
|
885
|
+
if (!statSync(path).isDirectory()) return jsonResponse({ error: 'not_directory' }, 400);
|
|
886
|
+
const folders = readdirSync(path, { withFileTypes: true })
|
|
887
|
+
.filter(entry => {
|
|
888
|
+
if (entry.name.startsWith('.')) return false;
|
|
889
|
+
if (entry.isDirectory()) return true;
|
|
890
|
+
if (!entry.isSymbolicLink()) return false;
|
|
891
|
+
try {
|
|
892
|
+
const target = realpathSync(join(path, entry.name));
|
|
893
|
+
return statSync(target).isDirectory() && allowed.some(root => isWithinRoot(target, root));
|
|
894
|
+
} catch { return false; }
|
|
895
|
+
})
|
|
896
|
+
.map(entry => ({ name: entry.name, path: join(path, entry.name) }))
|
|
897
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
898
|
+
const atRoot = allowed.includes(path);
|
|
899
|
+
return jsonResponse({ path, parent: atRoot ? null : dirname(path), folders });
|
|
900
|
+
} catch {
|
|
901
|
+
return jsonResponse({ error: 'folder_unavailable' }, 404);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
849
905
|
export async function handleProjectsPost(req: Request): Promise<Response> {
|
|
850
906
|
let body: unknown;
|
|
851
907
|
try { body = await req.json(); }
|
|
@@ -996,7 +1052,9 @@ export async function routeRequest(
|
|
|
996
1052
|
const offered = req.headers.get('authorization');
|
|
997
1053
|
const fallbackAuthorized = fallbackToken !== undefined && offered?.startsWith('Bearer ') === true
|
|
998
1054
|
&& compareTokenConstTime(offered.slice('Bearer '.length).trim(), fallbackToken);
|
|
999
|
-
|
|
1055
|
+
const graphPeerAuthorized = (method === 'GET' || method === 'PUT')
|
|
1056
|
+
&& graphAccessForRequest(pathname, method, offered?.startsWith('Bearer ') ? offered.slice(7).trim() : null);
|
|
1057
|
+
if (!(opts.metaApi ? checkAuth(req, opts.metaApi) : fallbackAuthorized) && !graphPeerAuthorized) {
|
|
1000
1058
|
const name = method === 'POST' && (pathname === '/v1/tasks' || pathname === '/v1/reports/ingest') && opts.metaApi
|
|
1001
1059
|
? matchIngestAuthorization(req)?.name
|
|
1002
1060
|
: undefined;
|
|
@@ -1341,6 +1399,11 @@ export async function routeRequest(
|
|
|
1341
1399
|
|
|
1342
1400
|
// Same owner auth as the neighbouring GETs (short-lived owner tokens · same-origin PWA); #23932 compared the admin
|
|
1343
1401
|
// bearer only, so a PWA on a short-lived token got 401 and the loop map stayed empty.
|
|
1402
|
+
if (pathname === '/v1/loops/resources' && method === 'GET') {
|
|
1403
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-runtime-not-wired' }, 503);
|
|
1404
|
+
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1405
|
+
return handleLoopResourcesGet(opts.loopResources);
|
|
1406
|
+
}
|
|
1344
1407
|
if (pathname === '/v1/loops/edges' && method === 'GET') {
|
|
1345
1408
|
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-runtime-not-wired' }, 503);
|
|
1346
1409
|
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
@@ -1407,7 +1470,12 @@ export async function routeRequest(
|
|
|
1407
1470
|
return handleGraphsValidatePost(req, opts.metaApi);
|
|
1408
1471
|
}
|
|
1409
1472
|
|
|
1410
|
-
// GRAPH-WIZARD — 말 → 그래프 YAML(저장 안 함).
|
|
1473
|
+
// GRAPH-WIZARD — 설치된 팩 목록과 말 → 그래프 YAML(저장 안 함). 같은 소유자 인증.
|
|
1474
|
+
if (method === 'GET' && pathname === '/v1/graphs/wizard/packs') {
|
|
1475
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
1476
|
+
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1477
|
+
return handleGraphWizardPacksGet(opts.graphWizard);
|
|
1478
|
+
}
|
|
1411
1479
|
if (method === 'POST' && pathname === '/v1/graphs/wizard') {
|
|
1412
1480
|
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
1413
1481
|
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
@@ -1419,6 +1487,10 @@ export async function routeRequest(
|
|
|
1419
1487
|
return handleFabricPlans(req, opts.fabricPlans);
|
|
1420
1488
|
}
|
|
1421
1489
|
|
|
1490
|
+
if (pathname === '/v1/projects/folders' && method === 'GET') {
|
|
1491
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1492
|
+
return handleProjectFoldersGet(req, opts.projectFolderRoots);
|
|
1493
|
+
}
|
|
1422
1494
|
if (pathname === '/v1/projects' && (method === 'GET' || method === 'POST')) {
|
|
1423
1495
|
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1424
1496
|
return method === 'GET' ? handleProjectsGet() : handleProjectsPost(req);
|
|
@@ -1515,6 +1587,10 @@ export async function routeRequest(
|
|
|
1515
1587
|
...opts.decisions,
|
|
1516
1588
|
});
|
|
1517
1589
|
}
|
|
1590
|
+
if (method === 'POST' && pathname === '/v1/plugins/wizard') {
|
|
1591
|
+
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1592
|
+
return handlePluginWizardSave(req, opts.metaApi, opts.pluginStateRoot);
|
|
1593
|
+
}
|
|
1518
1594
|
if (method === 'POST' && pathname === '/v1/plugins/install') {
|
|
1519
1595
|
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1520
1596
|
return handlePluginsInstall(req, opts.metaApi, opts.pluginStateRoot);
|
|
@@ -1534,10 +1610,19 @@ export async function routeRequest(
|
|
|
1534
1610
|
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1535
1611
|
return handlePluginsRemove(req, pluginRemove[1]!, opts.metaApi, opts.pluginStateRoot);
|
|
1536
1612
|
}
|
|
1613
|
+
if (method === 'PUT' && /^\/v1\/graphs\/[^/]+\/access$/.test(pathname)) {
|
|
1614
|
+
if (!opts.metaApi || bearerCredential(req, opts.metaApi) === undefined) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1615
|
+
return handleGraphAccessPut(pathname, req);
|
|
1616
|
+
}
|
|
1537
1617
|
if ((method === 'PUT' || method === 'POST') && (pathname.startsWith('/v1/graphs/') || pathname === '/v1/graphs')) {
|
|
1538
1618
|
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
1539
|
-
|
|
1540
|
-
|
|
1619
|
+
const peerMayEdit = method === 'PUT' && graphAccessForRequest(pathname, method,
|
|
1620
|
+
req.headers.get('authorization')?.startsWith('Bearer ') ? req.headers.get('authorization')!.slice(7).trim() : null);
|
|
1621
|
+
const ownerAuthorized = checkAuth(req, opts.metaApi);
|
|
1622
|
+
if (!ownerAuthorized && !peerMayEdit) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1623
|
+
// A peer save is recorded on the graph so every run path refuses it until the owner approves (W9c run guard).
|
|
1624
|
+
const mutated = await handleGraphsMutation(pathname, req, {}, ownerAuthorized ? null
|
|
1625
|
+
: { peerToken: req.headers.get('authorization')!.slice(7).trim() });
|
|
1541
1626
|
if (mutated) return mutated;
|
|
1542
1627
|
}
|
|
1543
1628
|
const cardClose = /^\/v1\/task-cards\/([^/]+)\/close$/.exec(pathname);
|
|
@@ -2829,6 +2914,10 @@ export async function routeRequest(
|
|
|
2829
2914
|
// surface (`/v1/workflows` · `~/.elanous/workflows-runs/`) covers the same
|
|
2830
2915
|
// user need.
|
|
2831
2916
|
|
|
2917
|
+
if (method === 'GET' && pathname === '/v1/plugins/wizard') {
|
|
2918
|
+
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
2919
|
+
return handlePluginWizardList(req, opts.metaApi, opts.pluginStateRoot);
|
|
2920
|
+
}
|
|
2832
2921
|
const pluginCredentialsGet = /^\/v1\/plugins\/([^/]+)\/credentials$/.exec(pathname);
|
|
2833
2922
|
if (method === 'GET' && pluginCredentialsGet) {
|
|
2834
2923
|
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
@@ -2844,6 +2933,10 @@ export async function routeRequest(
|
|
|
2844
2933
|
catch (error) { debug.log('graph.kinds', 'installed-sync-failed', { reason: String(error) }); }
|
|
2845
2934
|
return handleGraphKindsGet(req, opts.metaApi);
|
|
2846
2935
|
}
|
|
2936
|
+
if (method === 'GET' && /^\/v1\/graphs\/[^/]+\/access$/.test(pathname)) {
|
|
2937
|
+
if (!opts.metaApi || bearerCredential(req, opts.metaApi) === undefined) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
2938
|
+
return handleGraphAccess(pathname, req);
|
|
2939
|
+
}
|
|
2847
2940
|
// F-M1 read + P-F1 raw YAML. Writes live in the mutation block and never touch core graphs/.
|
|
2848
2941
|
if (method === 'GET' && (pathname === '/v1/graphs' || /^\/v1\/graphs\/[^/]+$/.test(pathname) || /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname))) {
|
|
2849
2942
|
return handleGraphsGet(pathname);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defaultListHarnessProcesses } from '../../harness/harness-cli-command.js';
|
|
2
|
+
import { devVersion, listChecklist } from '../../release-loop/checklist.js';
|
|
3
|
+
import { listSchedules } from '../../release-loop/release-schedule.js';
|
|
4
|
+
import { releaseLedgerRoot } from '../../instance/resolve.js';
|
|
5
|
+
import { getUserConfig, ORCHESTRATOR_DEFAULTS } from '../../user-config.js';
|
|
6
|
+
import { seatOfTree, trafficTick, TRAFFIC_SEATS, type TrafficCell, type TrafficResult } from '../../loops/orchestrator/traffic.js';
|
|
7
|
+
import { finishAdvice, measureFinish } from '../../loops/orchestrator/finish-rate.js';
|
|
8
|
+
import { jsonResponse } from './json-response.js';
|
|
9
|
+
|
|
10
|
+
/** Read-only snapshot of the same ORCH traffic decision used by the scheduled tick. */
|
|
11
|
+
export function observeLoopResources(deps: {
|
|
12
|
+
now?: Date;
|
|
13
|
+
processes?: ReturnType<typeof defaultListHarnessProcesses>;
|
|
14
|
+
version?: string;
|
|
15
|
+
openCells?: readonly TrafficCell[];
|
|
16
|
+
nextRound?: readonly TrafficCell[];
|
|
17
|
+
totalSlots?: number;
|
|
18
|
+
} = {}): TrafficResult {
|
|
19
|
+
const now = deps.now ?? new Date();
|
|
20
|
+
const cfg = getUserConfig().loops?.orchestrator ?? ORCHESTRATOR_DEFAULTS;
|
|
21
|
+
const observation = deps.processes ?? defaultListHarnessProcesses();
|
|
22
|
+
if (observation.status !== 'ok') throw new Error(`process observation ${observation.status}`);
|
|
23
|
+
const version = deps.version ?? devVersion().replace(/-dev\.\d+$/, '');
|
|
24
|
+
const upcoming = deps.nextRound === undefined ? listSchedules(releaseLedgerRoot()).filter(row => Date.parse(row.cutAt) > now.getTime())
|
|
25
|
+
.sort((a, b) => Date.parse(a.cutAt) - Date.parse(b.cutAt)) : [];
|
|
26
|
+
const currentIndex = upcoming.findIndex(row => row.version === version);
|
|
27
|
+
const nextVersion = currentIndex < 0 ? upcoming[0]?.version : upcoming[currentIndex + 1]?.version;
|
|
28
|
+
const totalSlots = deps.totalSlots ?? finishAdvice(measureFinish({}, now),
|
|
29
|
+
TRAFFIC_SEATS.reduce((sum, seat) => sum + cfg.seatCaps[seat], 0)).launchSlots;
|
|
30
|
+
return trafficTick({
|
|
31
|
+
processes: observation.records.map(process => ({ ...process, seat: seatOfTree(process.cwdStatus === 'unknown' ? undefined : process.cwd, cfg) })),
|
|
32
|
+
now, caps: cfg.seatCaps, openCells: deps.openCells ?? listChecklist(version).items, totalSlots,
|
|
33
|
+
...(deps.nextRound !== undefined ? { nextRound: deps.nextRound }
|
|
34
|
+
: nextVersion ? { nextRound: listChecklist(nextVersion).items } : {}),
|
|
35
|
+
retainQueuedCells: true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function handleLoopResourcesGet(observe: () => TrafficResult = observeLoopResources): Response {
|
|
40
|
+
try { return jsonResponse({ resource: observe() }); }
|
|
41
|
+
catch { return jsonResponse({ error: 'resource-unavailable' }, 503); }
|
|
42
|
+
}
|