elanous 0.2.42 → 0.2.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/08334415.f0e80896acbef722.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1032-78ba4f6391258cab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1082-53f86a26e03d309d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1109-7d0e264f6f2edbc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1124-7c26330402481143.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2160.a097e7b138ae1c55.js → 118.2a89982fe4276880.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1244.6c435dbf1bf21d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1252.9e665904d3aa3b1a.js +32 -0
- package/apps/pwa/out/_next/static/chunks/1266.a46cc33cb6a72d75.js +104 -0
- package/apps/pwa/out/_next/static/chunks/1306.967240ede9a0f757.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1344.3b95f3bd1b77a3fe.js +94 -0
- package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 1401.22dfe92640a2b1ac.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/1431-f7c78bd5be21e011.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1451-cdd35a8a0b31834b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 1694.18debfd77562e56d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1708-f03d587b7a7545c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1775-fa7152bdeff6c95f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/178-4da509cd7266672a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1850-522de4ee34957210.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1876-c6f6e0ddcc76c6a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1976.097066b072432242.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1978.eeb60a606dc5deac.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2043.e233e3b5a3e790f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2150.71b94e3348107c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2158.ebc6fc5a10280ab7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2216.802962c04f40a26e.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2294.7890edcfa046c97d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/235.c89aaae4bcd6233a.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{5885.0a3e52c8faccec98.js → 239.de075467b5523469.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/249.ba7051590d603c8f.js +226 -0
- package/apps/pwa/out/_next/static/chunks/2571.a6ac4e26c8618403.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2610.e149cd564a08913e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2705.9816f3c244f8b85f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2801.afeb8a4dae22f85f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2954.bbefc95d6b20e0d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2e0f720a.a0697c08e3806a60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3042.96ec235fe41c8d4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3097-8e358f158acef46b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3205-93b1abe28b4fb16a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3273.b4434f0dcae7eb29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3311.9cbc43ea0c90d60c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 3349.b5f09ee474d9533e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3503.a47a9755fb4d97b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3506-5f429b3b7e1392b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3843.bad404d008893291.js +77 -0
- package/apps/pwa/out/_next/static/chunks/3877-4b40e530b47e3bf9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/435-ce2958253cf7de61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4393.28fa5228d0eec217.js +149 -0
- package/apps/pwa/out/_next/static/chunks/4404.7281c847c6e10dfc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 4415-b9d6a90960920a4a.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/447-5b304de1fe098f43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4484-8ebea83d431e6fae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 4502.bdcc877abd437a05.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4599-f95790fc5c65b8df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 46.57c783fa4884714f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/463-b9114e411f33728e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4659.a57d1f0c5d754cd2.js +36 -0
- package/apps/pwa/out/_next/static/chunks/4722-a847e7a28115035f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 4757.67c6d7473a038e78.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4874-c86f878ec4502ad3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6377.bc7df239edbff244.js → 4891.3f80ba517a3b2373.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4998.810ca8833084caa9.js +62 -0
- package/apps/pwa/out/_next/static/chunks/4f98febc.ea5841d4d616bfb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5052.7dbb12a55d4f18f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5166-ca73b3e361085a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5180-039f4a18b07ad387.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5232.5a2ce4daf7a9e11d.js +115 -0
- package/apps/pwa/out/_next/static/chunks/5439.3fec6dbce29ecb36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5612-074d9a5e00dfac6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5675-01989d524a84c505.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5751.af641a1adf5ec697.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5758-c6cb98714d18ab0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/578eded8.b582637306e16964.js +122 -0
- package/apps/pwa/out/_next/static/chunks/5790.5eb06a653ebd8571.js +34 -0
- package/apps/pwa/out/_next/static/chunks/5853-4033e5bd5afbe06b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5904.97d70bb7f46b2db7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 5989.7ecd362c5c44b747.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 5a34fb2f.52f1b4e1baebb48a.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 5a5078f8.2099200e5ea95e16.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6036-c302c34ff0b3d410.js +1 -0
- package/apps/pwa/out/_next/static/chunks/606.ef81c313381f4264.js +1 -0
- package/apps/pwa/out/_next/static/chunks/616.1af54a928b1ba704.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6201.bc936f71f613a8e9.js +41 -0
- package/apps/pwa/out/_next/static/chunks/6204-fdc86e0e64c4f92d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 6245.1182e007e9d230d9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 63699a35.17262e162bc514b2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6420.494801a80030160c.js +27 -0
- package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → 6549dad0.2740b25e51bf8f05.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 6881.9e7955847640c7fe.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/6931.fcdfb94141e67b3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6991-8e081c6ce38c0ba1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7010.1bbd17a7f2b3e376.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7029.d1466acf55fae2ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7152-a123aa8e129c131f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7455.196168fffac3b9c4.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7638.6ca4770dd1129138.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7649-f37d76260e5e2a5a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7679.32c40cdd14f20b4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7751.04bfbd16b4c6cd0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7864.b1ff31d4030b8994.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7869-c47bd2c075c1fefa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 8442.2f09ca969d631615.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8445.2738dbd59a78c78c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8447.5510c439f9938c6d.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{9415.69e4a21c60c7d2db.js → 8551.f762945c2cda2e95.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8635-57a9d8d9db70f4f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/86961958-4b0689a5048f756b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8709.3c6019bb18f8554f.js +8 -0
- package/apps/pwa/out/_next/static/chunks/8759.c999528a0a907bf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9a852a62-6192a6ea9346ced3.js → 87f498e5-0881de09f2e44707.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8843.c3197f904c952b81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → 892fd990.456232f326cc39c2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8965-135a2c9eaa2464cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8971-8d3b9c96f8a6c958.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9059.c8598d96f8e5e9cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9115.90447ae198b84eae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9147.d9b0a02e0babc9b4.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9204-83075f4b70c61cdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9244-c32ef14b5dc72bdf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/930.2a9a30f964350c66.js +90 -0
- package/apps/pwa/out/_next/static/chunks/9398.1f56e3f17795f43f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9527.3e5ad31c891c5fcb.js +79 -0
- package/apps/pwa/out/_next/static/chunks/9571-4ac933e774d1225c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-9fc644de2d8edae3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-0c9dace2db62bee8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f5e65c3dc9d89f2a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-2a9c19b9a140b7b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-61533ad92141adfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-112004ced6fd0329.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-f733318c237a49d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-51ea677d2d33bbc0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-428b41f2f9566e3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-1b29396ea90a61e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-cf83ec613ac904bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-3f4c0ecbc284bb5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b63c322f54f70cc6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-fe328c4ee9aac6b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-bfb855c584f0fb98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-9fc644de2d8edae3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-47b1710c110eabd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-42895214458bc6d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d03de0ebd8366e23.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-3ed6c47e4b1c61c2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-ae653e9bf261c738.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-23f3f0a0209c0ac4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-88c691273aae66f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e187ac52a95538b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6e45828daed1295e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-edb5d7287bb46186.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4a7eaacd93c3f6a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ca073d43d74cc84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1e9fee67b1199436.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-df1283ea963c6816.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-19fcf8d8301ccd18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-5ab699e0303bbb40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7cde0d29756984c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9d4c598e8ee22f7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-cc1609a71f44ec62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7659a9a1345bfaa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0afef60ecc0c4af5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a3553949f8f34f5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-9fc644de2d8edae3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-057a69702f3c67c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-c0f0e570f3f74c73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-1825071ae34e3b89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-6244e3e135d8ccfc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-da787e8a10b8a82e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-1316d32498e2be42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-4df94572e343de2e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-708969f7475e88c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c58add08c919a1dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a24847f45e5d5bf9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-acfec65a3a60e22e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-3dfc598e6fbde245.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-c658a626118411b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-4c73685fd891445b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-6310f7e5de7dd01d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-51c326bf48610be1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-d0beadf754da59b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-acd243bfbf3f6732.js +1 -0
- package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -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 +23 -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/external-commands.yaml +5 -3
- package/catalog/meta/catalogVersion.yaml +2 -1
- package/catalog/signing/catalog-signing-public.pem +3 -0
- package/graphs/intake/intake-daily.yaml +16 -0
- package/graphs/intake/news-sources.yaml +1 -0
- package/graphs/intake/recipes.yaml +7 -0
- package/graphs/overlays/README.md +6 -0
- package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
- package/graphs/profiles/local.yaml +5 -0
- package/graphs/profiles/pod.yaml +4 -0
- package/graphs/release/release-loop.yaml +33 -17
- package/graphs/units/verbs/make-doc.yaml +1 -0
- package/package.json +6 -2
- package/plugins/demo-absorption-briefing/plugin.json +18 -0
- package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
- package/plugins/demo-browser-hand/plugin.json +13 -0
- package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
- package/plugins/demo-linear-secretary/plugin.json +15 -0
- package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
- package/plugins/demo-plugin-wizard/plugin.json +11 -0
- package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
- package/plugins/demo-research/plugin.json +16 -0
- package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
- package/plugins/demo-video-briefing/plugin.json +15 -0
- package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
- package/scripts/bench-metering-plan.ts +229 -0
- package/scripts/build-signed-catalog.ts +48 -0
- package/scripts/ci-typecheck-main-delta.sh +88 -0
- package/scripts/codex-fallback-live-probe.ts +1 -1
- package/scripts/demo/demo1104-parallel-host.ts +56 -0
- package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
- package/scripts/demo/demo1104-parallel.ts +72 -0
- package/scripts/demo/demo1104-stage.config.ts +21 -0
- package/scripts/demo/demo1104-stage.ts +316 -0
- package/scripts/goal-method-audit.ts +17 -1
- package/scripts/graph-units/land-enqueue.ts +90 -0
- package/scripts/hooks/codex-notify.sh +32 -0
- package/scripts/install.sh +10 -38
- package/scripts/landing-heal/land-plan.ts +57 -0
- package/scripts/public-leak-baseline.txt +0 -1
- package/scripts/release-loop/auto-approve-node.ts +1 -1
- package/scripts/release-loop/docs-node.ts +4 -2
- package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
- package/scripts/release-loop/gate-image-pin.ts +116 -2
- package/scripts/release-loop/gate-method.ts +139 -0
- package/scripts/release-loop/gate-node.ts +395 -43
- package/scripts/release-loop/gate-progress-sim.ts +73 -0
- package/scripts/release-loop/gate-traffic-mode.ts +151 -3
- package/scripts/release-loop/node-verdict.ts +38 -25
- package/scripts/release-loop/notes-repair.ts +18 -1
- package/scripts/release-loop/preflight.ts +544 -10
- package/scripts/release-loop/render-warm-control-manifest.ts +22 -0
- package/scripts/release-loop/resume-release.ts +9 -7
- package/scripts/release-loop/resume.ts +13 -4
- package/scripts/release-loop/unattended-release.ts +20 -9
- package/scripts/release-loop/warm-control-forward.ts +178 -0
- package/scripts/retro-cycle.ts +30 -8
- package/scripts/rhythm/daily.ts +39 -4
- package/scripts/rhythm/linear-progress-sync.ts +311 -0
- package/scripts/ux-sim.ts +7 -1
- package/scripts/video-pipeline.ts +9 -1
- package/scripts/warm-pool-provider-config.ts +35 -7
- package/src/acp/agent-manager.ts +1 -0
- package/src/acp/codex-app-server-agent.ts +33 -0
- package/src/acp/codex-app-server-client.ts +153 -16
- package/src/acp/core-turn-bridge.ts +17 -12
- package/src/acp/event-router.ts +20 -1
- package/src/acp/server.ts +6 -0
- package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
- package/src/agent-mission/claude-headless.ts +4 -1
- package/src/agent-mission/codex-exec.ts +105 -0
- package/src/agent-mission/driver.ts +192 -11
- package/src/agent-mission/grok-auth-status.ts +107 -0
- package/src/agent-mission/hand-hooks.ts +101 -0
- package/src/agent-mission/mission-cli.ts +56 -21
- package/src/agent-mission/mission-hand-reply.ts +118 -0
- package/src/agent-mission/mission-line.ts +180 -0
- package/src/agent-mission/mission-out.ts +256 -18
- package/src/agent-mission/tool-install.ts +122 -11
- package/src/agent-substrate/pr-reviewer.ts +147 -11
- package/src/agent-substrate/self-review-cli.ts +10 -2
- package/src/agents/general-purpose.md +1 -1
- package/src/auto-research/research-fanout.ts +221 -0
- package/src/auto-research/research-turn.ts +362 -31
- package/src/autopilot/mission-codebase-gate.ts +7 -3
- package/src/autopilot/pr-manager.ts +31 -3
- package/src/boot/daemon-tools/self-implement.ts +3 -1
- package/src/boot/daemon-tools/web-search.ts +1 -2
- package/src/briefing/brief-items.ts +55 -11
- package/src/cli/agent-cli.ts +2 -1
- package/src/cli/catalog-cli.ts +31 -0
- package/src/cli/connector-cli.ts +16 -0
- package/src/cli/control-cli.ts +15 -6
- package/src/cli/doctor-fix.ts +2 -2
- package/src/cli/intake-source-cli.ts +44 -8
- package/src/cli/log-event-names.ts +8 -0
- package/src/cli/msg-cli.ts +32 -3
- package/src/cli/pr-cli.ts +21 -1
- package/src/cli/pr-land-heavy-remote.ts +44 -6
- package/src/cli/pr-land-overlap-evidence.ts +13 -1
- package/src/cli/pr-land-pod-shadow-job.ts +143 -5
- package/src/cli/pr-land-pod-shadow.ts +9 -2
- package/src/cli/release-checklist-read-cli.ts +44 -16
- package/src/cli/release-cli.ts +23 -3
- package/src/cli/research-cli.ts +9 -0
- package/src/cli/setup-cli.ts +166 -6
- package/src/cli/setup-keys.ts +199 -0
- package/src/cli/task-plugin-wizard-host.ts +114 -0
- package/src/cli/tasks-cli.ts +54 -9
- package/src/cli/tui-test-cli.ts +190 -0
- package/src/config.ts +4 -2
- package/src/connectors/linear-daily-progress.ts +228 -0
- package/src/connectors/linear-projector.ts +34 -12
- package/src/connectors/linear.ts +151 -7
- package/src/control-plane/ledger.ts +42 -4
- package/src/control-plane/member-tokens.ts +25 -2
- package/src/control-plane/ports.ts +8 -3
- package/src/control-plane/server.ts +26 -5
- package/src/core-turn/deep-turn-bloom.ts +67 -0
- package/src/core-turn/research-policy.ts +43 -0
- package/src/core-turn/run-core-turn.ts +488 -51
- package/src/core-turn/types.ts +4 -0
- package/src/dashboard/chat/acp-chat.ts +10 -0
- package/src/dashboard/classic-sidetab-mission-job.ts +192 -0
- package/src/dashboard/classic-sidetab-mission-pair.ts +82 -0
- package/src/dashboard/classic-sidetab-mission-trio.ts +242 -0
- package/src/dashboard/classic-sidetab-mission.ts +169 -5
- package/src/dashboard/index.ts +387 -14
- package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
- package/src/dashboard/mission-cli-consumer.ts +20 -8
- package/src/dashboard/plugin-wizard-runtime.ts +50 -0
- package/src/dashboard/plugin-wizard-tool.ts +55 -0
- package/src/dashboard/sidetab-runtime.ts +3 -1
- package/src/dashboard/terminal-popup-runtime.ts +6 -3
- package/src/dashboard/visible-mission-diagnostics.ts +16 -0
- package/src/decisions/linear-progress-summary.ts +78 -0
- package/src/decisions/linear-progress-sync.ts +152 -0
- package/src/domains/outbound-alert.ts +49 -11
- package/src/domains/retro-cycle-observation.ts +43 -0
- package/src/domains/retro-cycle.ts +13 -2
- package/src/domains/retro-proposals.ts +92 -0
- package/src/domains/retro-report.ts +6 -1
- package/src/domains/telegram-kind-route.ts +16 -9
- package/src/graph-runner/arg-allowance.ts +13 -0
- package/src/graph-runner/graph-cli.ts +24 -1
- package/src/graph-runner/graph-grow-llm.ts +3 -1
- package/src/graph-runner/graph-run-api.ts +3 -1
- package/src/graph-runner/runner.ts +310 -46
- package/src/graph-wizard/mission-compose.ts +407 -12
- package/src/harness/dispatch-backpressure.ts +54 -1
- package/src/harness/dispatch-shadow-compare.ts +74 -0
- package/src/harness/harness-cli-command.ts +15 -3
- package/src/harness/harness-pod-dispatch.ts +3 -0
- package/src/harness/skill-exec.ts +21 -9
- package/src/harness/skill-select.ts +1 -1
- package/src/hooks/error-report-cloud.ts +101 -0
- package/src/hooks/receiver.ts +29 -2
- package/src/index.ts +129 -12
- package/src/intake-plane/actions.ts +354 -0
- package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
- package/src/intake-plane/intake-sources.ts +78 -8
- package/src/intake-plane/items.ts +14 -4
- package/src/intake-plane/linear-mission-sync.ts +80 -0
- package/src/intake-plane/linear-secretary-runtime.ts +178 -0
- package/src/intake-plane/linear-wish.ts +227 -1
- package/src/life/life-cli.ts +168 -0
- package/src/life/life-kinds.ts +160 -0
- package/src/live-supply/budget-consumer.ts +78 -0
- package/src/live-supply/read.ts +3 -0
- package/src/live-supply/snapshot.ts +45 -0
- package/src/llm/child-first-llm-observation.ts +112 -0
- package/src/llm/provider-credentials.ts +68 -6
- package/src/llm/provider-failure-evidence.ts +44 -0
- package/src/llm.ts +172 -12
- package/src/maturity/feature-maturity.ts +3 -3
- package/src/mcp/client.ts +7 -0
- package/src/mcp/proxy-runtime.ts +6 -1
- package/src/mcp/server.ts +54 -0
- package/src/msg/msg-sse-server.ts +3 -3
- package/src/msg/msg-store.ts +177 -19
- package/src/native-tool-catalog.ts +36 -2
- package/src/nexus/api/consult-requests.ts +18 -6
- package/src/nexus/api/discord-trigger-bot.ts +6 -6
- package/src/nexus/api/graphs-api.ts +4 -2
- package/src/nexus/api/grokbot-trigger-bot.ts +206 -0
- package/src/nexus/api/http-server.ts +37 -1
- package/src/nexus/api/mcp-public-allowlist.ts +2 -0
- package/src/nexus/api/telegram-trigger-bot.ts +6 -6
- package/src/nexus/boot/register-mcp-clients.ts +114 -8
- package/src/nexus/index.ts +22 -2
- package/src/nexus/outbound/format.ts +9 -0
- package/src/nexus/outbound/grokbot-adapter.ts +71 -0
- package/src/nexus/outbound/router.ts +121 -16
- package/src/nexus/setup-status.ts +9 -0
- package/src/nexus/state/state.ts +3 -0
- package/src/oauth/codex-account-store.ts +20 -7
- package/src/oauth/codex-owner-mirror.ts +81 -0
- package/src/oauth/codex.ts +17 -2
- package/src/oauth/fallback-chain.ts +47 -17
- package/src/onboarding/first-run-doctor.ts +8 -1
- package/src/onboarding/first-run.ts +126 -29
- package/src/onboarding/key-setup.ts +103 -0
- package/src/onboarding/menu-answer.ts +13 -0
- package/src/onboarding/secret-prompt.ts +37 -0
- package/src/plugins/install/plugin-install.ts +59 -0
- package/src/pr-tool/census.ts +130 -0
- package/src/preview/terminal.ts +22 -7
- package/src/prompt-enhance/enhance.ts +10 -0
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-write-provenance.ts +21 -3
- package/src/pty-shell/registry.ts +9 -2
- package/src/registry/catalog-server.ts +232 -0
- package/src/registry/loader.ts +45 -1
- package/src/registry/types.ts +1 -2
- package/src/release-loop/proposal-auto-place.ts +83 -0
- package/src/research/axis-fanout.ts +79 -29
- package/src/research/lenses/second-order.ts +312 -0
- package/src/self-dev/ask-launch-flow.ts +72 -1
- package/src/self-dev/dev-cli.ts +7 -2
- package/src/self-dev/dev-pipeline.ts +5 -0
- package/src/self-dev/draft-residue.ts +64 -5
- package/src/self-dev/draft-sweep.ts +31 -10
- package/src/self-dev/draft-triage-rules.ts +60 -3
- package/src/self-dev/graph-front-nodes.ts +2 -1
- package/src/self-dev/graph-journey-route.ts +76 -21
- package/src/self-dev/launch-preflight.ts +58 -0
- package/src/self-dev/orchestrate.ts +1 -1
- package/src/self-dev/run-supervisor.ts +152 -2
- package/src/self-dev/shard-aggregate.ts +4 -0
- package/src/self-dev/shard-run.ts +36 -15
- package/src/self-implement/abandoned-classification.ts +12 -3
- package/src/self-implement/budget-gate.ts +7 -0
- package/src/self-implement/child-llm-preference.ts +10 -1
- package/src/self-implement/doctor-visit.ts +30 -8
- package/src/self-implement/elanous-tui-spawn.ts +3 -0
- package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
- package/src/self-implement/gate-artifacts.ts +2 -1
- package/src/self-implement/goal-author-cli.ts +4 -2
- package/src/self-implement/goal-author.ts +549 -10
- package/src/self-implement/graph-overlay-yaml.ts +181 -4
- package/src/self-implement/graph-overlay.ts +3 -1
- package/src/self-implement/graph-profile-yaml.ts +107 -0
- package/src/self-implement/graph-yaml.ts +94 -5
- package/src/self-implement/off-diff-evidence.ts +249 -5
- package/src/self-implement/orchestrator.ts +298 -26
- package/src/self-implement/run-chart.ts +6 -3
- package/src/self-implement/run-ledger.ts +51 -1
- package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
- package/src/self-implement/tdd-evidence-tags.ts +9 -0
- package/src/self-implement/test-scenario-request.ts +37 -6
- package/src/self-implement/train-gate-receipt.ts +166 -0
- package/src/self-implement/train-gate-remote.ts +62 -18
- package/src/session/chat.ts +6 -4
- package/src/session/session-fanout.ts +2 -0
- package/src/session/streaming/acp-stream-sink.ts +2 -1
- package/src/session/streaming/chunk-producer.ts +6 -0
- package/src/session/streaming/stream-compositor.ts +3 -2
- package/src/session-runtime/index.ts +74 -6
- package/src/session-runtime/retry-policy.ts +1 -1
- package/src/setup/llm-env-detect.ts +3 -0
- package/src/setup/service-key-catalog.ts +46 -0
- package/src/setup/service-keys.ts +241 -0
- package/src/sidetab-core/model.ts +205 -10
- package/src/sidetab-core/visible-agent-mission-pair.ts +51 -0
- package/src/sidetab-core/visible-agent-mission.ts +182 -48
- package/src/skills/tools/agent.ts +23 -4
- package/src/skills/tools/omni-search.ts +127 -27
- package/src/task-agent/parent-host.ts +29 -1
- package/src/task-agent/recall-inject.ts +98 -0
- package/src/task-agent/repair-outcomes.ts +65 -0
- package/src/task-agent/task-hand.ts +46 -14
- package/src/task-orchestrator/dispatcher.ts +14 -1
- package/src/task-orchestrator/linear-capture-events.ts +55 -0
- package/src/task-orchestrator/store.ts +16 -5
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +23 -1
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +107 -1
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +21 -9
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
- package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +467 -77
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +45 -3
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +210 -14
- package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
- package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
- package/src/task-orchestrator/types.ts +14 -0
- package/src/telegram.ts +14 -16
- package/src/terminal/coding-agent.ts +14 -5
- package/src/terminal/session-registry.ts +1 -1
- package/src/tool-hints/gate.ts +46 -14
- package/src/tool-hints/signals.ts +1 -1
- package/src/tool-hints/types.ts +2 -0
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/browser-hand-runtime.ts +391 -0
- package/src/tool-runtime/browser-runtime.ts +33 -19
- package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
- package/src/tool-runtime/elanous-linear-secretary-runtime.ts +173 -0
- package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
- package/src/tool-runtime/index.ts +6 -0
- package/src/tool-runtime/types.ts +5 -0
- package/src/tui/entry.ts +51 -8
- package/src/tui/sidetab/attach.ts +252 -11
- package/src/tui/sidetab/herdr-portal.ts +225 -0
- package/src/tui/sidetab/list.ts +3 -2
- package/src/tui-client/next-dashboard-runtime.ts +52 -0
- package/src/user-config.ts +34 -9
- package/src/user-intent/types.ts +4 -3
- package/src/ux-sim/browser-hand.ts +165 -0
- package/src/ux-sim/draft-inventory-builder.ts +199 -0
- package/src/ux-sim/fake-browser-page.ts +81 -0
- package/src/ux-sim/fake-linear-device.ts +31 -0
- package/src/ux-sim/graph-engine-sim.ts +47 -0
- package/src/ux-sim/linear-secretary.ts +208 -0
- package/src/ux-sim/mock-scenario-catalog.json +81 -26
- package/src/ux-sim/mock-scenario-catalog.ts +175 -5
- package/src/ux-sim/onboarding-first-run-device.ts +31 -21
- package/src/ux-sim/release-sim-rig.ts +62 -18
- package/src/ux-sim/scenario.ts +70 -26
- package/src/ux-sim/service-key-setup.ts +113 -0
- package/src/ux-sim/term-slash-device.ts +74 -0
- package/src/ux-sim/turn-throw-sim.ts +31 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/exa.ts +77 -0
- package/src/web-search/index.ts +30 -9
- package/src/web-search/provider.ts +4 -1
- package/src/web-search/x-intent.ts +5 -0
- package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
- package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
- package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
- package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2690.0521c738b7749931.js +0 -115
- package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
- package/apps/pwa/out/_next/static/chunks/3207.a756c95e9ec8c3c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
- package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
- package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
- package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
- package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
- package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +0 -122
- package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
- package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
- package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
- package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
- package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
- package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +0 -79
- package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9656-374232558fd528d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
- package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
- /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import type { Task, TaskExecution, TaskStatus } from '../task-orchestrator/types.js';
|
|
3
3
|
import { EventLedger } from './event-ledger.js';
|
|
4
|
+
import { parseLinearSecretaryManifest, readApprovedLinearCapture, updateLinearSecretaryProgress } from '../intake-plane/linear-wish.js';
|
|
4
5
|
|
|
5
6
|
const LINEAR_GRAPHQL_URL = 'https://api.linear.app/graphql';
|
|
6
7
|
const STATE_NAMES: Partial<Record<TaskStatus, string>> = {
|
|
@@ -10,7 +11,7 @@ const STATE_NAMES: Partial<Record<TaskStatus, string>> = {
|
|
|
10
11
|
failed: 'Todo',
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
type ProjectableTask = Pick<Task, 'id' | 'status' | 'generatedBy' | 'lastExecutionId' | 'notes'>;
|
|
14
|
+
type ProjectableTask = Pick<Task, 'id' | 'status' | 'generatedBy' | 'lastExecutionId' | 'notes'> & Pick<Partial<Task>, 'description' | 'title'>;
|
|
14
15
|
|
|
15
16
|
export interface LinearProjectionOptions {
|
|
16
17
|
task: ProjectableTask;
|
|
@@ -19,7 +20,7 @@ export interface LinearProjectionOptions {
|
|
|
19
20
|
ledger?: EventLedger;
|
|
20
21
|
/** Linear user ID for the elanous agent, when configured. */
|
|
21
22
|
assigneeId?: string;
|
|
22
|
-
execution?: Pick<TaskExecution, 'output' | 'error'>;
|
|
23
|
+
execution?: Pick<TaskExecution, 'output' | 'error' | 'runId' | 'captureArtifacts'>;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
async function graphql<T>(apiKey: string, fetchFn: typeof fetch, query: string, variables: Record<string, unknown>): Promise<T> {
|
|
@@ -34,25 +35,46 @@ async function graphql<T>(apiKey: string, fetchFn: typeof fetch, query: string,
|
|
|
34
35
|
return result.data;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
function projectionComment(task: ProjectableTask
|
|
38
|
+
function projectionComment(task: ProjectableTask): string | null {
|
|
38
39
|
switch (task.status) {
|
|
39
40
|
case 'running': return `elanous 실행 시작 (task: ${task.id}${task.lastExecutionId ? `, execution: ${task.lastExecutionId}` : ''}).`;
|
|
40
|
-
case 'review': return `elanous 실행 결과가 사람 확인을 기다립니다 (task: ${task.id})
|
|
41
|
-
case 'done': return `elanous 실행 완료 (task: ${task.id})
|
|
42
|
-
case 'failed': {
|
|
43
|
-
const reason = execution?.error?.message ?? task.notes.at(-1);
|
|
44
|
-
return `elanous 실행 실패 (task: ${task.id}).${reason ? `\n\n${reason.slice(0, 2000)}` : ''}`;
|
|
45
|
-
}
|
|
41
|
+
case 'review': return `elanous 실행 결과가 사람 확인을 기다립니다 (task: ${task.id}).`;
|
|
42
|
+
case 'done': return `elanous 실행 완료 (task: ${task.id}).`;
|
|
43
|
+
case 'failed': return `elanous 실행 실패 (task: ${task.id}).`;
|
|
46
44
|
default: return null;
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
/** Project only Linear-origin task transitions. Every successful write is recorded for inbound echo filtering. */
|
|
51
49
|
export async function projectLinearTask({ task, apiKey, fetch: fetchFn = fetch, ledger, assigneeId, execution }: LinearProjectionOptions): Promise<boolean> {
|
|
52
|
-
if (task.generatedBy?.kind !== 'external' || task.generatedBy.provider !== 'linear' || !task.generatedBy.ref
|
|
53
|
-
if (!apiKey) throw new Error('Linear API key is required for projection');
|
|
50
|
+
if (task.generatedBy?.kind !== 'external' || task.generatedBy.provider !== 'linear' || !task.generatedBy.ref) return false;
|
|
54
51
|
const issueId = task.generatedBy.ref;
|
|
55
52
|
const events = ledger ?? new EventLedger();
|
|
53
|
+
const secretary = parseLinearSecretaryManifest(task.description ?? '', issueId);
|
|
54
|
+
if (secretary) {
|
|
55
|
+
if (task.status !== 'running' && task.status !== 'review' && task.status !== 'done' && task.status !== 'failed') return false;
|
|
56
|
+
if (!apiKey) throw new Error('Linear API key is required for projection');
|
|
57
|
+
const state = task.status === 'running' ? 'started' : task.status === 'done' ? 'completed' : 'comment';
|
|
58
|
+
const captureCandidate = execution?.captureArtifacts?.find(capture =>
|
|
59
|
+
capture.runId === execution.runId && capture.runId.trim().length > 0 &&
|
|
60
|
+
capture.linearIssueId === secretary.parentIssueId && capture.externalShare === true && capture.sensitivity === 'public');
|
|
61
|
+
let captureArtifact: typeof captureCandidate;
|
|
62
|
+
if (captureCandidate) {
|
|
63
|
+
try { readApprovedLinearCapture(captureCandidate); captureArtifact = captureCandidate; }
|
|
64
|
+
catch { /* Invalid, stale, or unavailable captures fail closed; progress still syncs without a URL. */ }
|
|
65
|
+
}
|
|
66
|
+
await updateLinearSecretaryProgress({ apiKey, parentIssueId: secretary.parentIssueId, taskIssueId: issueId,
|
|
67
|
+
taskTitle: secretary.tasks.find(item => item.issueId === issueId)!.title, tasks: secretary.tasks, state,
|
|
68
|
+
summary: task.status === 'running' ? '하위 작업을 시작했습니다.'
|
|
69
|
+
: task.status === 'done' ? '하위 작업을 완료했습니다.'
|
|
70
|
+
: task.status === 'failed' ? '하위 작업이 실패했습니다.' : '하위 작업 진행 상태를 갱신했습니다.',
|
|
71
|
+
workaround: task.status === 'failed' ? 'Linear 상태는 In Progress로 유지하고 실패 내용을 기록했습니다.' : undefined,
|
|
72
|
+
captureArtifact,
|
|
73
|
+
ledger: events, fetch: fetchFn });
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (!STATE_NAMES[task.status]) return false;
|
|
77
|
+
if (!apiKey) throw new Error('Linear API key is required for projection');
|
|
56
78
|
const { issue, viewer } = await graphql<{
|
|
57
79
|
issue?: { team?: { states?: { nodes?: Array<{ id: string; name: string }> } } };
|
|
58
80
|
viewer?: { id?: string };
|
|
@@ -72,7 +94,7 @@ export async function projectLinearTask({ task, apiKey, fetch: fetchFn = fetch,
|
|
|
72
94
|
events.record('linear', `outgoing:state:${issueId}:${update.issueUpdate.issue.updatedAt}:${stateHash}`,
|
|
73
95
|
{ ref: issueId, occurredAt: update.issueUpdate.issue.updatedAt });
|
|
74
96
|
|
|
75
|
-
const comment = projectionComment(task
|
|
97
|
+
const comment = projectionComment(task);
|
|
76
98
|
if (comment) {
|
|
77
99
|
const created = await graphql<{ commentCreate?: { success?: boolean; comment?: { id?: string; updatedAt?: string; issue?: { updatedAt?: string } } } }>(apiKey, fetchFn,
|
|
78
100
|
'mutation ProjectorComment($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { id updatedAt issue { updatedAt } } } }',
|
package/src/connectors/linear.ts
CHANGED
|
@@ -180,6 +180,12 @@ export async function resolveLinearProjectId({ apiKey, project, fetch: fetchFn =
|
|
|
180
180
|
return projectId;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
export async function resolveLinearViewerId({ apiKey, fetch: fetchFn = fetch }: LinearRequestOptions): Promise<string> {
|
|
184
|
+
const data = await linearRequest<{ viewer?: { id?: string } }>({ apiKey, fetch: fetchFn }, 'query LinearSecretaryViewer { viewer { id } }', {});
|
|
185
|
+
if (!data.viewer?.id) throw new Error('Linear viewer id could not be resolved');
|
|
186
|
+
return data.viewer.id;
|
|
187
|
+
}
|
|
188
|
+
|
|
183
189
|
/** Read-only project lookup. A name is resolved uniquely before querying its issues. */
|
|
184
190
|
export async function fetchLinearProjectIssues({ apiKey, project, includeDone = false, fetch: fetchFn = fetch }: {
|
|
185
191
|
apiKey: string; project: string; includeDone?: boolean; fetch?: typeof fetch;
|
|
@@ -234,17 +240,47 @@ export async function findLinearDecisionIssue({ apiKey, projectId, decisionId, f
|
|
|
234
240
|
return match;
|
|
235
241
|
}
|
|
236
242
|
|
|
237
|
-
/** Create in
|
|
238
|
-
export async function createLinearIssue({ apiKey, projectId, title, description, dueDate, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
239
|
-
projectId
|
|
243
|
+
/** Create in a project or directly in an explicitly selected team. */
|
|
244
|
+
export async function createLinearIssue({ apiKey, projectId, teamKey, title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
245
|
+
projectId?: string; teamKey?: string; title: string; description: string; dueDate?: string; parentId?: string; assigneeId?: string;
|
|
246
|
+
stateType?: 'started' | 'unstarted' | 'completed' | 'canceled';
|
|
240
247
|
}): Promise<string> {
|
|
241
|
-
|
|
242
|
-
|
|
248
|
+
if (!apiKey.trim() || (!projectId?.trim() && !teamKey?.trim())) throw new Error('Linear project or team and API key are required');
|
|
249
|
+
if (!projectId?.trim()) return createLinearTeamIssue({ apiKey, teamKey: teamKey!.trim(), title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn });
|
|
250
|
+
type Team = { id: string; states?: { nodes?: Array<{ id: string; type: string }> } };
|
|
251
|
+
const data = await linearRequest<{ project?: { teams?: { nodes?: Team[] } } }>({ apiKey, fetch: fetchFn },
|
|
252
|
+
'query DecisionProjectTeam($id: String!) { project(id: $id) { teams { nodes { id states { nodes { id type } } } } } }', { id: projectId });
|
|
243
253
|
const teams = data.project?.teams?.nodes;
|
|
244
254
|
if (!teams?.[0]?.id) throw new Error('Linear project has no team');
|
|
255
|
+
const stateId = stateType ? teams[0].states?.nodes?.find(state => state.type === stateType)?.id : undefined;
|
|
256
|
+
if (stateType && !stateId) throw new Error(`Linear team workflow state not found: ${stateType}`);
|
|
245
257
|
const created = await linearRequest<{ issueCreate?: { success?: boolean; issue?: { id?: string } } }>({ apiKey, fetch: fetchFn },
|
|
246
258
|
'mutation DecisionIssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id } } }',
|
|
247
|
-
{ input: {
|
|
259
|
+
{ input: {
|
|
260
|
+
teamId: teams[0].id, projectId, title, description,
|
|
261
|
+
...(dueDate ? { dueDate } : {}), ...(parentId ? { parentId } : {}), ...(assigneeId ? { assigneeId } : {}), ...(stateId ? { stateId } : {}),
|
|
262
|
+
} });
|
|
263
|
+
const id = created.issueCreate?.issue?.id;
|
|
264
|
+
if (!created.issueCreate?.success || !id) throw new Error('Linear issueCreate did not return an issue id');
|
|
265
|
+
return id;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Create an issue directly in a team, without requiring a project. */
|
|
269
|
+
export async function createLinearTeamIssue({ apiKey, teamKey, title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
270
|
+
teamKey: string; title: string; description?: string; dueDate?: string; parentId?: string; assigneeId?: string;
|
|
271
|
+
stateType?: 'started' | 'unstarted' | 'completed' | 'canceled';
|
|
272
|
+
}): Promise<string> {
|
|
273
|
+
if (!apiKey.trim() || !teamKey.trim() || !title.trim()) throw new Error('Linear team, title and API key are required');
|
|
274
|
+
const data = await linearRequest<{ teams?: { nodes?: Array<{ id?: string; states?: { nodes?: Array<{ id: string; type: string }> } }> } }>({ apiKey, fetch: fetchFn },
|
|
275
|
+
'query LinearTeamByKey($key: String!) { teams(filter: { key: { eq: $key } }) { nodes { id states { nodes { id type } } } } }', { key: teamKey.trim() });
|
|
276
|
+
const teams = data.teams?.nodes ?? [];
|
|
277
|
+
if (teams.length !== 1 || !teams[0]?.id) throw new Error(teams.length ? 'Linear team key is ambiguous' : 'Linear team key was not found');
|
|
278
|
+
const stateId = stateType ? teams[0].states?.nodes?.find(state => state.type === stateType)?.id : undefined;
|
|
279
|
+
if (stateType && !stateId) throw new Error(`Linear team workflow state not found: ${stateType}`);
|
|
280
|
+
const created = await linearRequest<{ issueCreate?: { success?: boolean; issue?: { id?: string } } }>({ apiKey, fetch: fetchFn },
|
|
281
|
+
'mutation LinearTeamIssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id } } }',
|
|
282
|
+
{ input: { teamId: teams[0].id, title: title.trim(), ...(description?.trim() ? { description: description.trim() } : {}),
|
|
283
|
+
...(dueDate ? { dueDate } : {}), ...(parentId ? { parentId } : {}), ...(assigneeId ? { assigneeId } : {}), ...(stateId ? { stateId } : {}) } });
|
|
248
284
|
const id = created.issueCreate?.issue?.id;
|
|
249
285
|
if (!created.issueCreate?.success || !id) throw new Error('Linear issueCreate did not return an issue id');
|
|
250
286
|
return id;
|
|
@@ -257,8 +293,74 @@ export async function commentLinearIssue({ apiKey, issueId, body, fetch: fetchFn
|
|
|
257
293
|
if (!data.commentCreate?.success || !data.commentCreate.comment?.id) throw new Error('Linear commentCreate failed');
|
|
258
294
|
}
|
|
259
295
|
|
|
296
|
+
export async function createLinearAttachment({ apiKey, issueId, title, url, subtitle, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
297
|
+
issueId: string; title: string; url: string; subtitle?: string;
|
|
298
|
+
}): Promise<string> {
|
|
299
|
+
const parsed = new URL(url);
|
|
300
|
+
if (parsed.protocol !== 'https:') throw new Error('Linear attachment URL must use HTTPS');
|
|
301
|
+
const data = await linearRequest<{ attachmentCreate?: { success?: boolean; attachment?: { id?: string } } }>({ apiKey, fetch: fetchFn },
|
|
302
|
+
'mutation LinearAttachmentCreate($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }',
|
|
303
|
+
{ input: { issueId, title, url: parsed.toString(), ...(subtitle ? { subtitle } : {}) } });
|
|
304
|
+
const id = data.attachmentCreate?.attachment?.id;
|
|
305
|
+
if (!data.attachmentCreate?.success || !id) throw new Error('Linear attachmentCreate did not return an attachment id');
|
|
306
|
+
return id;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Request a signed Linear upload URL and stream a generated artifact from the server. */
|
|
310
|
+
export async function uploadLinearFile({ apiKey, filename, contentType, body, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
311
|
+
filename: string; contentType: string; body: Buffer;
|
|
312
|
+
}): Promise<string> {
|
|
313
|
+
const data = await linearRequest<{ fileUpload?: { success?: boolean; uploadFile?: {
|
|
314
|
+
uploadUrl?: string; assetUrl?: string; headers?: Array<{ key: string; value: string }>;
|
|
315
|
+
} } }>({ apiKey, fetch: fetchFn },
|
|
316
|
+
`mutation LinearFileUpload($contentType: String!, $filename: String!, $size: Int!) {
|
|
317
|
+
fileUpload(contentType: $contentType, filename: $filename, size: $size) {
|
|
318
|
+
success uploadFile { uploadUrl assetUrl headers { key value } }
|
|
319
|
+
}
|
|
320
|
+
}`,
|
|
321
|
+
{ contentType, filename, size: body.byteLength });
|
|
322
|
+
const upload = data.fileUpload?.uploadFile;
|
|
323
|
+
if (!data.fileUpload?.success || !upload?.uploadUrl || !upload.assetUrl || !Array.isArray(upload.headers)) {
|
|
324
|
+
throw new Error('Linear fileUpload did not return an upload URL');
|
|
325
|
+
}
|
|
326
|
+
const uploadUrl = new URL(upload.uploadUrl);
|
|
327
|
+
const assetUrl = new URL(upload.assetUrl);
|
|
328
|
+
if (uploadUrl.protocol !== 'https:' || assetUrl.protocol !== 'https:') throw new Error('Linear file upload URLs must use HTTPS');
|
|
329
|
+
const headers = new Headers({ 'Content-Type': contentType, 'Cache-Control': 'public, max-age=31536000' });
|
|
330
|
+
for (const header of upload.headers) {
|
|
331
|
+
if (!header || typeof header.key !== 'string' || typeof header.value !== 'string') throw new Error('Linear fileUpload returned invalid headers');
|
|
332
|
+
headers.set(header.key, header.value);
|
|
333
|
+
}
|
|
334
|
+
let response: Response;
|
|
335
|
+
try {
|
|
336
|
+
const uploadBody = new Uint8Array(body.byteLength);
|
|
337
|
+
uploadBody.set(body);
|
|
338
|
+
response = await fetchFn(uploadUrl, { method: 'PUT', headers, body: uploadBody, redirect: 'error' });
|
|
339
|
+
} catch {
|
|
340
|
+
throw new Error('Linear file upload PUT failed');
|
|
341
|
+
}
|
|
342
|
+
if (!response.ok) throw new Error(`Linear file upload PUT HTTP ${response.status}`);
|
|
343
|
+
return assetUrl.toString();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export async function updateLinearIssueDescription({ apiKey, issueId, description, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
347
|
+
issueId: string; description: string;
|
|
348
|
+
}): Promise<void> {
|
|
349
|
+
const data = await linearRequest<{ issueUpdate?: { success?: boolean } }>({ apiKey, fetch: fetchFn },
|
|
350
|
+
'mutation LinearIssueDescriptionUpdate($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }',
|
|
351
|
+
{ id: issueId, input: { description } });
|
|
352
|
+
if (!data.issueUpdate?.success) throw new Error('Linear issue description update failed');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export async function fetchLinearIssueDescription({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
|
|
356
|
+
const data = await linearRequest<{ issue?: { description?: string | null } }>({ apiKey, fetch: fetchFn },
|
|
357
|
+
'query LinearIssueDescription($id: String!) { issue(id: $id) { description } }', { id: issueId });
|
|
358
|
+
if (typeof data.issue?.description !== 'string') throw new Error('Linear issue description is missing');
|
|
359
|
+
return data.issue.description;
|
|
360
|
+
}
|
|
361
|
+
|
|
260
362
|
export async function moveLinearIssueToStateType({ apiKey, issueId, type, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
261
|
-
issueId: string; type: 'completed' | 'canceled';
|
|
363
|
+
issueId: string; type: 'unstarted' | 'started' | 'completed' | 'canceled';
|
|
262
364
|
}): Promise<void> {
|
|
263
365
|
const data = await linearRequest<{ issue?: { team?: { states?: { nodes?: Array<{ id: string; type: string }> } } } }>({ apiKey, fetch: fetchFn },
|
|
264
366
|
'query DecisionIssueStates($id: String!) { issue(id: $id) { team { states { nodes { id type } } } } }', { id: issueId });
|
|
@@ -270,6 +372,48 @@ export async function moveLinearIssueToStateType({ apiKey, issueId, type, fetch:
|
|
|
270
372
|
if (!updated.issueUpdate?.success) throw new Error('Linear issueUpdate failed');
|
|
271
373
|
}
|
|
272
374
|
|
|
375
|
+
/** Check the issue's current workflow state and transition in one fresh read/write operation. */
|
|
376
|
+
export async function transitionLinearIssueStateType({ apiKey, issueId, type, fromTypes, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
377
|
+
issueId: string; type: 'unstarted' | 'started' | 'completed' | 'canceled'; fromTypes?: readonly string[];
|
|
378
|
+
}): Promise<boolean> {
|
|
379
|
+
const data = await linearRequest<{ issue?: { state?: { type?: string } | null; team?: { states?: { nodes?: Array<{ id: string; type: string }> } } } }>({ apiKey, fetch: fetchFn },
|
|
380
|
+
'query LinearIssueTransitionGuard($id: String!) { issue(id: $id) { state { type } team { states { nodes { id type } } } } }', { id: issueId });
|
|
381
|
+
const currentType = data.issue?.state?.type;
|
|
382
|
+
if (!currentType || currentType === 'completed' || currentType === 'canceled' || (fromTypes && !fromTypes.includes(currentType))) return false;
|
|
383
|
+
const state = data.issue?.team?.states?.nodes?.find(node => node.type === type);
|
|
384
|
+
if (!state?.id) throw new Error(`Linear team workflow state not found: ${type}`);
|
|
385
|
+
const updated = await linearRequest<{ issueUpdate?: { success?: boolean } }>({ apiKey, fetch: fetchFn },
|
|
386
|
+
'mutation LinearIssueTransition($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }',
|
|
387
|
+
{ id: issueId, input: { stateId: state.id } });
|
|
388
|
+
if (!updated.issueUpdate?.success) throw new Error('Linear issueUpdate failed');
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export async function fetchLinearIssueStateType({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
|
|
393
|
+
const data = await linearRequest<{ issue?: { state?: { type?: string } | null } }>({ apiKey, fetch: fetchFn },
|
|
394
|
+
'query LinearIssueStatus($id: String!) { issue(id: $id) { state { type } } }', { id: issueId });
|
|
395
|
+
const type = data.issue?.state?.type;
|
|
396
|
+
if (!type) throw new Error('Linear issue state type is missing');
|
|
397
|
+
return type;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Read the immutable identity needed to bind a demo mission to a real child issue. */
|
|
401
|
+
export async function fetchLinearMissionIssueIdentity({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<{ id: string; teamKey: string; parentId: string | null }> {
|
|
402
|
+
const data = await linearRequest<{ issue?: { id?: string; team?: { key?: string } | null; parent?: { id?: string } | null } }>({ apiKey, fetch: fetchFn },
|
|
403
|
+
'query LinearMissionIssueIdentity($id: String!) { issue(id: $id) { id team { key } parent { id } } }', { id: issueId });
|
|
404
|
+
const issue = data.issue;
|
|
405
|
+
if (!issue?.id || !issue.team?.key) throw new Error('Linear issue identity is incomplete');
|
|
406
|
+
return { id: issue.id, teamKey: issue.team.key, parentId: issue.parent?.id ?? null };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export async function fetchLinearIssueUpdatedAt({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
|
|
410
|
+
const data = await linearRequest<{ issue?: { updatedAt?: string } }>({ apiKey, fetch: fetchFn },
|
|
411
|
+
'query LinearIssueUpdatedAt($id: String!) { issue(id: $id) { updatedAt } }', { id: issueId });
|
|
412
|
+
const updatedAt = data.issue?.updatedAt;
|
|
413
|
+
if (!updatedAt || !Number.isFinite(Date.parse(updatedAt))) throw new Error('Linear issue updatedAt is missing');
|
|
414
|
+
return updatedAt;
|
|
415
|
+
}
|
|
416
|
+
|
|
273
417
|
export function toTaskRequest(event: ExternalTaskEvent): {
|
|
274
418
|
title: string; description: string; priority: 'high' | 'medium' | 'low';
|
|
275
419
|
external: { provider: 'linear'; ref: string; url?: string; team?: string };
|
|
@@ -20,7 +20,7 @@ export interface ResourceRecord {
|
|
|
20
20
|
export type ResourceView = ResourceRecord & { ageMs: number; expired: boolean };
|
|
21
21
|
|
|
22
22
|
export interface PodWorkerKey { context: string; imageDigest: string; lockHash: string; architecture: string }
|
|
23
|
-
type PodWorkerState = 'idle' | 'leased' | 'sanitizing' | 'timeout-fenced' | 'quarantined';
|
|
23
|
+
type PodWorkerState = 'idle' | 'leased' | 'sanitizing' | 'timeout-fenced' | 'quarantined' | 'reaping';
|
|
24
24
|
interface PodWorkerLeaseAttrs {
|
|
25
25
|
key: PodWorkerKey;
|
|
26
26
|
podUid: string;
|
|
@@ -35,6 +35,8 @@ interface PodWorkerLeaseAttrs {
|
|
|
35
35
|
timeoutFenceUntil?: number;
|
|
36
36
|
timeoutRunId?: string;
|
|
37
37
|
timeoutAttemptId?: string;
|
|
38
|
+
timeoutPreviousObservedAt?: number;
|
|
39
|
+
timeoutPreviousTtlMs?: number;
|
|
38
40
|
runId?: string;
|
|
39
41
|
attemptId?: string;
|
|
40
42
|
reason?: string;
|
|
@@ -216,6 +218,13 @@ export class ResourceLedger {
|
|
|
216
218
|
now ??= Date.now();
|
|
217
219
|
const rows = this.read();
|
|
218
220
|
const id = `pod-worker-lease:${request.workerId}`;
|
|
221
|
+
if (rows.some(row => {
|
|
222
|
+
if (row.kind !== 'pod-worker-lease' || row.name === request.workerId) return false;
|
|
223
|
+
const attrs = workerAttrs(row);
|
|
224
|
+
return attrs.podUid === request.podUid
|
|
225
|
+
&& (attrs.state === 'quarantined' || attrs.state === 'timeout-fenced' || attrs.state === 'reaping');
|
|
226
|
+
}))
|
|
227
|
+
throw new ResourceLedgerError(409, 'pod-uid-already-registered');
|
|
219
228
|
const index = rows.findIndex(row => row.id === id);
|
|
220
229
|
const previous = index < 0 ? undefined : rows[index]!;
|
|
221
230
|
if (previous && previous.kind !== 'pod-worker-lease') throw new ResourceLedgerError(409, 'worker-id-conflict');
|
|
@@ -244,8 +253,10 @@ export class ResourceLedger {
|
|
|
244
253
|
const idleAttrs: PodWorkerLeaseAttrs = { ...candidateAttrs, state: 'idle' };
|
|
245
254
|
delete idleAttrs.leaseId; delete idleAttrs.leaseOwner; delete idleAttrs.runId; delete idleAttrs.attemptId;
|
|
246
255
|
delete idleAttrs.timeoutFenceUntil; delete idleAttrs.timeoutRunId; delete idleAttrs.timeoutAttemptId;
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
const observedAt = candidateAttrs.timeoutPreviousObservedAt ?? at;
|
|
257
|
+
const ttlMs = candidateAttrs.timeoutPreviousTtlMs ?? candidateAttrs.idleTtlMs;
|
|
258
|
+
delete idleAttrs.timeoutPreviousObservedAt; delete idleAttrs.timeoutPreviousTtlMs;
|
|
259
|
+
rows[rowIndex] = { ...candidate, attrs: idleAttrs as unknown as Record<string, unknown>, observedAt, ttlMs };
|
|
249
260
|
expiredFenceChanged = true;
|
|
250
261
|
}
|
|
251
262
|
const index = rows.findIndex(row => row.kind === 'pod-worker-lease' && (!request.machine || row.machine === request.machine)
|
|
@@ -283,12 +294,16 @@ export class ResourceLedger {
|
|
|
283
294
|
&& attrs.timeoutAttemptId === request.attemptId;
|
|
284
295
|
const sameLease = attrs.state === 'leased' && attrs.leaseOwner === request.owner
|
|
285
296
|
&& attrs.runId === request.runId && attrs.attemptId === request.attemptId;
|
|
286
|
-
const available = attrs.state === 'idle';
|
|
297
|
+
const available = attrs.state === 'idle' && Math.max(0, at - row.observedAt) < row.ttlMs;
|
|
287
298
|
if (!request.owner || !request.runId || !request.attemptId || !Number.isSafeInteger(request.fenceMs)
|
|
288
299
|
|| request.fenceMs < 1 || !(sameFence || sameLease || available))
|
|
289
300
|
throw new ResourceLedgerError(409, 'stale-timeout-fence');
|
|
290
301
|
const nextAttrs: PodWorkerLeaseAttrs = { ...attrs, state: 'timeout-fenced',
|
|
291
302
|
timeoutFenceUntil: at + request.fenceMs, timeoutRunId: request.runId, timeoutAttemptId: request.attemptId };
|
|
303
|
+
if (available) {
|
|
304
|
+
nextAttrs.timeoutPreviousObservedAt = row.observedAt;
|
|
305
|
+
nextAttrs.timeoutPreviousTtlMs = row.ttlMs;
|
|
306
|
+
}
|
|
292
307
|
const next: ResourceRecord = { ...row, attrs: nextAttrs as unknown as Record<string, unknown>, observedAt: at };
|
|
293
308
|
rows[index] = next;
|
|
294
309
|
this.write(rows);
|
|
@@ -296,6 +311,29 @@ export class ResourceLedger {
|
|
|
296
311
|
});
|
|
297
312
|
}
|
|
298
313
|
|
|
314
|
+
/** Atomically reserves a fenced Pod UID so a timeout-fence expiry cannot make it leasable during deletion. */
|
|
315
|
+
reservePodWorkerReap(id: string, request: { machine: string; podUid: string }, now?: number): ResourceRecord {
|
|
316
|
+
return this.mutate(() => {
|
|
317
|
+
now ??= Date.now();
|
|
318
|
+
const rows = this.read();
|
|
319
|
+
const index = rows.findIndex(row => row.id === id && row.kind === 'pod-worker-lease');
|
|
320
|
+
if (index < 0) throw new ResourceLedgerError(404, 'not-found');
|
|
321
|
+
const row = rows[index]!;
|
|
322
|
+
const attrs = workerAttrs(row);
|
|
323
|
+
if (row.machine !== request.machine || attrs.podUid !== request.podUid || attrs.leaseId
|
|
324
|
+
|| !['quarantined', 'timeout-fenced', 'reaping'].includes(attrs.state))
|
|
325
|
+
throw new ResourceLedgerError(409, 'pod-worker-reap-not-eligible');
|
|
326
|
+
if (rows.some((other, otherIndex) => otherIndex !== index && other.kind === 'pod-worker-lease'
|
|
327
|
+
&& workerAttrs(other).podUid === request.podUid))
|
|
328
|
+
throw new ResourceLedgerError(409, 'pod-worker-uid-has-other-lease');
|
|
329
|
+
const next: ResourceRecord = { ...row,
|
|
330
|
+
attrs: { ...attrs, state: 'reaping' } as unknown as Record<string, unknown>, observedAt: now };
|
|
331
|
+
rows[index] = next;
|
|
332
|
+
this.write(rows);
|
|
333
|
+
return next;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
299
337
|
transitionPodWorker(id: string, request: { owner: string; leaseId: string; generation: number; action: 'renew' | 'release' | 'sanitize' | 'quarantine'; ttlMs?: number; reason?: string }, now?: number): ResourceRecord {
|
|
300
338
|
return this.mutate(() => {
|
|
301
339
|
now ??= Date.now();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
2
|
-
import { chmodSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
2
|
+
import { chmodSync, closeSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, fsyncSync } from 'node:fs';
|
|
3
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
4
4
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
5
5
|
|
|
6
6
|
interface MemberTokenEntry { sha256: string; issuedAt: string }
|
|
@@ -65,6 +65,29 @@ export function issueMemberToken(machine: string, root: string = effectiveInstan
|
|
|
65
65
|
return token;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/** Issue a member credential into a new private file without sending the value to stdout. */
|
|
69
|
+
export function issueMemberTokenToFile(machine: string, tokenFile: string, root: string = effectiveInstanceRoot()): void {
|
|
70
|
+
checkMachine(machine);
|
|
71
|
+
if (!isAbsolute(tokenFile)) throw new Error('token file path must be absolute');
|
|
72
|
+
const token = randomBytes(32).toString('hex');
|
|
73
|
+
mkdirSync(dirname(tokenFile), { recursive: true, mode: 0o700 });
|
|
74
|
+
let outputCreated = false;
|
|
75
|
+
try {
|
|
76
|
+
const fd = openSync(tokenFile, 'wx', 0o600);
|
|
77
|
+
outputCreated = true;
|
|
78
|
+
try {
|
|
79
|
+
writeFileSync(fd, `${token}\n`, 'utf8');
|
|
80
|
+
fsyncSync(fd);
|
|
81
|
+
} finally { closeSync(fd); }
|
|
82
|
+
const entries = readStore(root);
|
|
83
|
+
entries[machine] = { sha256: createHash('sha256').update(token).digest('hex'), issuedAt: new Date().toISOString() };
|
|
84
|
+
writeStore(root, entries);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (outputCreated) try { unlinkSync(tokenFile); } catch { /* retain the original failure */ }
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
68
91
|
export function revokeMemberToken(machine: string, root: string = effectiveInstanceRoot()): void {
|
|
69
92
|
checkMachine(machine);
|
|
70
93
|
const entries = readStore(root);
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ResourceLedger, ResourceLedgerError, type ResourceRecord } from './ledger.js';
|
|
2
2
|
import { DEFAULT_NEXUS_HTTP_PORT } from '../nexus/default-port.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/** Release PWA bind configured by OP; isolated test leases must never claim it. */
|
|
5
|
+
export const RELEASE_PWA_FIXED_HTTP_PORT = 31453;
|
|
6
|
+
|
|
7
|
+
/** Inclusive port bands. Fixed release PWA ports are reserved from every isolated test allocator. */
|
|
5
8
|
export const PORT_BANDS = {
|
|
6
|
-
reserved: [31413, DEFAULT_NEXUS_HTTP_PORT, 31420],
|
|
9
|
+
reserved: [31413, DEFAULT_NEXUS_HTTP_PORT, 31420, RELEASE_PWA_FIXED_HTTP_PORT],
|
|
7
10
|
test: { start: 31450, end: 31499 },
|
|
8
11
|
offline: { start: 31500, end: 31509 },
|
|
9
12
|
} as const;
|
|
@@ -36,5 +39,7 @@ export function leasePort(request: PortLeaseRequest, ledger: ResourceLedger, now
|
|
|
36
39
|
throw new ResourceLedgerError(400, 'invalid-port-lease');
|
|
37
40
|
}
|
|
38
41
|
const owner = request.owner ?? machine;
|
|
39
|
-
|
|
42
|
+
const reservedTestPorts = PORT_BANDS.reserved.filter(port => port >= PORT_BANDS.test.start && port <= PORT_BANDS.test.end);
|
|
43
|
+
const excluded = [...new Set([...(request.excluded ?? []), ...reservedTestPorts])];
|
|
44
|
+
return ledger.leaseTestPort({ machine, purpose, ttlMs: Math.min(ttlMs, MAX_PORT_LEASE_TTL_MS), owner }, PORT_BANDS.test, now, excluded);
|
|
40
45
|
}
|
|
@@ -12,12 +12,17 @@ export const CONTROL_HOSTNAME = '127.0.0.1';
|
|
|
12
12
|
const MAX_POD_WORKER_TTL_MS = 24 * 60 * 60 * 1000;
|
|
13
13
|
const POD_WORKER_TIMEOUT_FENCE_MS = 150_000;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
function controlHostnameAllowed(hostname: string, allowClusterBind: boolean): boolean {
|
|
16
|
+
// Cluster-facing binds require an explicit opt-in; wildcard exposure is never inferred from the address.
|
|
17
|
+
if (hostname === '0.0.0.0') return allowClusterBind;
|
|
16
18
|
if (hostname === '127.0.0.1' || hostname === '::1') return true;
|
|
17
19
|
const parts = hostname.split('.');
|
|
18
20
|
if (parts.length !== 4 || !parts.every(part => /^(0|[1-9]\d{0,2})$/.test(part) && Number(part) <= 255)) return false;
|
|
19
21
|
return parts[0] === '100' && Number(parts[1]) >= 64 && Number(parts[1]) <= 127;
|
|
20
22
|
}
|
|
23
|
+
export function allowedControlHostname(hostname: string): boolean {
|
|
24
|
+
return controlHostnameAllowed(hostname, false);
|
|
25
|
+
}
|
|
21
26
|
export type ControlScope = 'admin' | 'member' | 'query';
|
|
22
27
|
export type ControlTokens = Record<ControlScope, string>;
|
|
23
28
|
|
|
@@ -89,6 +94,7 @@ export interface ControlServerOptions {
|
|
|
89
94
|
root?: string;
|
|
90
95
|
port?: number;
|
|
91
96
|
hostname?: string;
|
|
97
|
+
allowClusterBind?: boolean;
|
|
92
98
|
leaseView?: LeaseHolderView;
|
|
93
99
|
requireKnownLeaseForWrites?: boolean;
|
|
94
100
|
}
|
|
@@ -99,7 +105,7 @@ export function startControlServer(opts: ControlServerOptions = {}): {
|
|
|
99
105
|
stop(): void;
|
|
100
106
|
} {
|
|
101
107
|
const hostname = opts.hostname ?? CONTROL_HOSTNAME;
|
|
102
|
-
if (!
|
|
108
|
+
if (!controlHostnameAllowed(hostname, opts.allowClusterBind ?? false)) throw new Error('invalid control hostname');
|
|
103
109
|
const root = opts.root ?? effectiveInstanceRoot();
|
|
104
110
|
const tokens = ensureControlTokens(root);
|
|
105
111
|
const ledger = new ResourceLedger(root);
|
|
@@ -127,7 +133,7 @@ export function startControlServer(opts: ControlServerOptions = {}): {
|
|
|
127
133
|
const leaseRenewal = /^\/v1\/leases\/port\/([^/]+)\/heartbeat$/.exec(path);
|
|
128
134
|
const workerRegister = path === '/v1/workers/pod' && method === 'POST';
|
|
129
135
|
const workerAcquire = path === '/v1/leases/pod-worker' && method === 'POST';
|
|
130
|
-
const workerTransition = /^\/v1\/leases\/pod-worker\/([^/]+)\/(renew|release|sanitize|quarantine|timeout)$/.exec(path);
|
|
136
|
+
const workerTransition = /^\/v1\/leases\/pod-worker\/([^/]+)\/(renew|release|sanitize|quarantine|timeout|reap)$/.exec(path);
|
|
131
137
|
if (!resourcePath && !registerPath && !leaseRequest && !workerRegister && !workerAcquire && !(workerTransition && method === 'POST') && !(leaseDeletion && method === 'DELETE') && !(leaseRenewal && method === 'POST') && !(heartbeat && method === 'POST') && !(deletion && method === 'DELETE')) {
|
|
132
138
|
return json({ error: 'not-found' }, 404);
|
|
133
139
|
}
|
|
@@ -177,10 +183,13 @@ export function startControlServer(opts: ControlServerOptions = {}): {
|
|
|
177
183
|
() => ledger.registerPodWorker({ workerId, machine: workerMachine, podUid, key: podWorkerKey(key), ttlMs, owner })));
|
|
178
184
|
}
|
|
179
185
|
if (workerAcquire) {
|
|
180
|
-
|
|
186
|
+
// A host-scoped provider may acquire only its own worker lease. Global consumers
|
|
187
|
+
// retain the member scope; a machine credential can never select another host.
|
|
188
|
+
if (scope !== 'member' && !machine) throw new ResourceLedgerError(403, 'worker-consumer-required');
|
|
181
189
|
const body = podWorkerBody(await req.json());
|
|
182
190
|
const { machine: workerMachine, key, runId, attemptId, ttlMs } = body;
|
|
183
191
|
if (workerMachine !== undefined && (typeof workerMachine !== 'string' || !workerMachine.trim())) throw new ResourceLedgerError(400, 'invalid-pod-worker-lease');
|
|
192
|
+
if (machine && workerMachine !== machine) throw new ResourceLedgerError(403, 'machine-scope');
|
|
184
193
|
if (typeof runId !== 'string' || !runId.trim() || typeof attemptId !== 'string' || !attemptId.trim()
|
|
185
194
|
|| typeof ttlMs !== 'number' || !Number.isSafeInteger(ttlMs) || ttlMs <= 0 || ttlMs > MAX_POD_WORKER_TTL_MS) throw new ResourceLedgerError(400, 'invalid-pod-worker-lease');
|
|
186
195
|
const stale = await currentWorkerPrimary();
|
|
@@ -192,7 +201,19 @@ export function startControlServer(opts: ControlServerOptions = {}): {
|
|
|
192
201
|
if (workerTransition) {
|
|
193
202
|
const workerId = decodeURIComponent(workerTransition[1]!);
|
|
194
203
|
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,95}$/.test(workerId)) throw new ResourceLedgerError(400, 'invalid-worker-id');
|
|
195
|
-
const action = workerTransition[2] as 'renew' | 'release' | 'sanitize' | 'quarantine' | 'timeout';
|
|
204
|
+
const action = workerTransition[2] as 'renew' | 'release' | 'sanitize' | 'quarantine' | 'timeout' | 'reap';
|
|
205
|
+
if (action === 'reap') {
|
|
206
|
+
if (!machine) throw new ResourceLedgerError(403, 'worker-reap-host-required');
|
|
207
|
+
const body = podWorkerBody(await req.json());
|
|
208
|
+
const podUid = body.podUid;
|
|
209
|
+
if (typeof podUid !== 'string' || !podUid.trim()) throw new ResourceLedgerError(400, 'invalid-pod-worker-reap');
|
|
210
|
+
const id = `pod-worker-lease:${workerId}`;
|
|
211
|
+
requireTarget(id);
|
|
212
|
+
const stale = await currentWorkerPrimary();
|
|
213
|
+
if (stale) return stale;
|
|
214
|
+
return json(await ledger.withGuardedWorkerMutation(async () => !(await currentWorkerPrimary()),
|
|
215
|
+
() => ledger.reservePodWorkerReap(id, { machine, podUid })));
|
|
216
|
+
}
|
|
196
217
|
if (action === 'timeout') {
|
|
197
218
|
if (scope !== 'member') throw new ResourceLedgerError(403, 'worker-timeout-scope');
|
|
198
219
|
const body = podWorkerBody(await req.json());
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type DeepBloomTrigger = 'research-intent' | 'deep-question' | 'high-reasoning-effort';
|
|
2
|
+
|
|
3
|
+
export type DeepBloomDecision =
|
|
4
|
+
| { apply: true; reason: DeepBloomTrigger }
|
|
5
|
+
| { apply: false; reason: 'lightweight' | 'no-deep-signal' };
|
|
6
|
+
|
|
7
|
+
export type DeepBloomInstruction = Extract<DeepBloomDecision, { apply: true }> & {
|
|
8
|
+
levels: readonly [4, 5];
|
|
9
|
+
questionCount: 3 | 4 | 5;
|
|
10
|
+
prompt?: string;
|
|
11
|
+
exemplarDomain?: string;
|
|
12
|
+
exemplarLevels?: number[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const LIGHTWEIGHT_TEXT = /^(?:hi|hello|hey|thanks|thank you|good morning|good night|안녕(?:하세요)?|고마워(?:요)?|감사합니다|잘 자(?:요)?)[.!?\s]*$/iu;
|
|
16
|
+
const LIGHTWEIGHT_FACT = /^(?:what(?:'s| is)\s+(?:the\s+)?(?:capital|time|date|meaning|definition)\b.*|who is\b.*|where is\b.*|몇 시(?:야|인가요)?|오늘 날짜(?:는|가)?|\S+의 뜻(?:은|이)?)[??.!\s]*$/iu;
|
|
17
|
+
const LIGHTWEIGHT_COMMAND = /^(?:please\s+)?(?:open|show|list|translate|convert|print|set|turn on|turn off)\b|^(?:열어(?:줘|주세요)|보여(?:줘|주세요)|나열해(?:줘|주세요)|번역해(?:줘|주세요)|계산해(?:줘|주세요)|켜(?:줘|주세요)|꺼(?:줘|주세요))\s*$/iu;
|
|
18
|
+
const DEEP_QUESTION = /\b(?:analy[sz]e|analysis|evaluate|evaluation|compare|comparison|outlook|forecast|cause|causes|why|impact|trade-?offs?|pros and cons|design|strategy|scenario|counterargument|assess|judge)\b|분석|평가|비교|전망|예측|원인|영향|장단점|설계|전략|시나리오|반박|판단|어떻게 봐야|왜\b/iu;
|
|
19
|
+
|
|
20
|
+
/** Lightweight turns have precedence so effort settings never inflate greetings, simple facts, or direct commands. */
|
|
21
|
+
export function selectDeepBloom(
|
|
22
|
+
request: string | undefined,
|
|
23
|
+
options: { researchIntent?: boolean; reasoningEffort?: string } = {},
|
|
24
|
+
): DeepBloomDecision {
|
|
25
|
+
const text = request?.trim() ?? '';
|
|
26
|
+
if (!text || LIGHTWEIGHT_TEXT.test(text) || LIGHTWEIGHT_FACT.test(text) || LIGHTWEIGHT_COMMAND.test(text))
|
|
27
|
+
return { apply: false, reason: 'lightweight' };
|
|
28
|
+
if (options.researchIntent) return { apply: true, reason: 'research-intent' };
|
|
29
|
+
if (options.reasoningEffort && ['high', 'xhigh', 'max'].includes(options.reasoningEffort))
|
|
30
|
+
return { apply: true, reason: 'high-reasoning-effort' };
|
|
31
|
+
if (DEEP_QUESTION.test(text)) return { apply: true, reason: 'deep-question' };
|
|
32
|
+
return { apply: false, reason: 'no-deep-signal' };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Build a hidden same-call analysis/evaluation instruction with the existing KGS Bloom cells and exemplar bank. */
|
|
36
|
+
export async function buildDeepBloomInstruction(
|
|
37
|
+
request: string,
|
|
38
|
+
trigger: DeepBloomTrigger,
|
|
39
|
+
): Promise<DeepBloomInstruction> {
|
|
40
|
+
const [{ BLOOM_2D_SCOPED }, { getBloomExemplarContext }] = await Promise.all([
|
|
41
|
+
import('../knowledge/kgs/types.js'), import('../research/bloom-exemplars.js'),
|
|
42
|
+
]);
|
|
43
|
+
const analyze = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'analyze')!;
|
|
44
|
+
const evaluate = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'evaluate')!;
|
|
45
|
+
const exemplar = getBloomExemplarContext(request);
|
|
46
|
+
const prompt = [
|
|
47
|
+
'Before answering, silently ask yourself 3–5 short questions and answer them from the available context.',
|
|
48
|
+
`Analysis focus (${analyze.cognitive}/${analyze.knowledge}): break the subject into components, relationships, and causal mechanisms.`,
|
|
49
|
+
`Evaluation focus (${evaluate.cognitive}/${evaluate.knowledge}): set explicit criteria, compare alternatives or claims, and test at least one counterargument.`,
|
|
50
|
+
'Use those answers to produce a clear conclusion. Do not expose these internal labels or a checklist unless the user asks for the reasoning process.',
|
|
51
|
+
exemplar.context,
|
|
52
|
+
].filter(Boolean).join('\n\n');
|
|
53
|
+
return { apply: true, reason: trigger, levels: [4, 5], questionCount: 4,
|
|
54
|
+
prompt, exemplarDomain: exemplar.domain, exemplarLevels: exemplar.levels };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Ensure the existing research ladder gives levels 4 and 5 distinct analysis/evaluation work. */
|
|
58
|
+
export async function buildResearchBloom45Directive(): Promise<string> {
|
|
59
|
+
const { BLOOM_2D_SCOPED } = await import('../knowledge/kgs/types.js');
|
|
60
|
+
const analyze = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'analyze')!;
|
|
61
|
+
const evaluate = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'evaluate')!;
|
|
62
|
+
return [
|
|
63
|
+
`For Bloom level 4 (${analyze.cognitive}/${analyze.knowledge}), ask about components, relationships, and causal mechanisms.`,
|
|
64
|
+
`For Bloom level 5 (${evaluate.cognitive}/${evaluate.knowledge}), ask for criteria-based judgment across alternatives and a counterargument.`,
|
|
65
|
+
'Keep both questions request-specific and ensure each has search terms; do not duplicate level 3 or level 6 work.',
|
|
66
|
+
].join('\n');
|
|
67
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Shared guardrails for every core-turn research surface. */
|
|
2
|
+
export const RESEARCH_TURN_MAX_TOOL_TURNS = 20;
|
|
3
|
+
export const RESEARCH_TURN_FIRST_REPLY_BUDGET_MS = 15_000;
|
|
4
|
+
/** Research returns its best partial evidence before the parent has to abort the turn. */
|
|
5
|
+
export const RESEARCH_TURN_FINAL_ANSWER_DEADLINE_MS = 8 * 60_000;
|
|
6
|
+
export const RESEARCH_TURN_DEEP_BUDGET_MS = 9 * 60_000;
|
|
7
|
+
export const RESEARCH_TURN_SHALLOW_BUDGET_MS = 3 * 60_000;
|
|
8
|
+
/** Leave time for shallow partial-answer synthesis before the unchanged parent timeout. */
|
|
9
|
+
export const RESEARCH_TURN_SHALLOW_FINAL_ANSWER_DEADLINE_MS = RESEARCH_TURN_SHALLOW_BUDGET_MS - 10_000;
|
|
10
|
+
export const RESEARCH_TURN_DEADLINE_STOP_ERROR = 'research stopped by its deadline';
|
|
11
|
+
|
|
12
|
+
/** Research turns only receive these tools; unrelated writers are never implicit. */
|
|
13
|
+
export const RESEARCH_TOOL_ALLOWLIST = [
|
|
14
|
+
'OmniSearch',
|
|
15
|
+
'WebSearch',
|
|
16
|
+
'WebFetch',
|
|
17
|
+
'Agent',
|
|
18
|
+
'Read',
|
|
19
|
+
// TUI quick-route contracts: every quick turn can recall memory, and the
|
|
20
|
+
// investigation route may list (but never mutate) the seat mailbox.
|
|
21
|
+
'memory_recall',
|
|
22
|
+
'MsgList',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
const RESEARCH_TOOL_NAMES: ReadonlySet<string> = new Set(RESEARCH_TOOL_ALLOWLIST);
|
|
26
|
+
export const RESEARCH_DOCUMENT_WRITE_TOOLS = ['Edit', 'Write'] as const;
|
|
27
|
+
|
|
28
|
+
/** A research turn may write only when the user explicitly asks for a document at a concrete path. */
|
|
29
|
+
const DOCUMENT_OUTPUT_PATH = /(?:^|[\s"'\x60])(?:\.{1,2}\/)?(?:[\w.-]+\/)*[\w.-]+\.(?:md|mdx|txt|rst|adoc|html|json|ya?ml|csv)\b/i;
|
|
30
|
+
const DOCUMENT_OUTPUT_PATH_GLOBAL = /(?:^|[\s"'\x60])(?:\.{1,2}\/)?(?:[\w.-]+\/)*[\w.-]+\.(?:md|mdx|txt|rst|adoc|html|json|ya?ml|csv)\b/gi;
|
|
31
|
+
const POSITIVE_DOCUMENT_WRITE_INTENT = /\b(?:write|writes|writing|written|draft|drafts|drafting|create|creates|creating|author|authors|authoring|produce|produces|producing|save|saves|saving)\b|작성|초안|생성|기록/i;
|
|
32
|
+
const NEGATED_DOCUMENT_WRITE_INTENT = /\b(?:do\s+not|don['’]?t|never|must\s+not|should\s+not|avoid)\s+(?:(?:be|to)\s+)*(?:write|writes|writing|written|draft|drafts|drafting|create|creates|creating|author|authors|authoring|produce|produces|producing|save|saves|saving)\b|(?:작성|초안|생성|기록)(?:\s*(?:을|를))?\s*(?:하지\s*마|하지\s*말|하지\s*않|금지)/i;
|
|
33
|
+
|
|
34
|
+
/** A research turn may write only when the user explicitly asks for a document at a concrete path. */
|
|
35
|
+
export function requestsResearchDocumentWrite(text: string | undefined): boolean {
|
|
36
|
+
if (!text || !DOCUMENT_OUTPUT_PATH.test(text)) return false;
|
|
37
|
+
const intentText = text.replace(DOCUMENT_OUTPUT_PATH_GLOBAL, ' ');
|
|
38
|
+
return POSITIVE_DOCUMENT_WRITE_INTENT.test(intentText)
|
|
39
|
+
&& !NEGATED_DOCUMENT_WRITE_INTENT.test(intentText);
|
|
40
|
+
}
|
|
41
|
+
export function isResearchToolAllowed(name: string): boolean {
|
|
42
|
+
return RESEARCH_TOOL_NAMES.has(name);
|
|
43
|
+
}
|