elanous 0.2.42 → 0.2.43
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 → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 0ad6802e.ae7afb63fdcb4491.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/114.2b90424d1a3ce84c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1151-5c2bb8f002ca2dd6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1200.6a37c202f9f17e9a.js +226 -0
- package/apps/pwa/out/_next/static/chunks/1261-a616d5728e02e624.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1313-19f737e0222c4444.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1357.3bbef3976c37f94a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1362-20adddfaf662b0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1406.a1dc2ab6f8449374.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1737-9491fc6ab29b9ec6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1803-4f91a8e7dcaf042c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1961.a81b12872c3e93a9.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{53c73f84.373b6160adfa89a4.js → 1970cf59.2d4d8ce5d6c81853.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9211-330b6736a63d4cb3.js → 2073-ba274e00e4f9efb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 2144.25b292396712196d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2268-53861f339e0b65a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2312.0c8b61e22d3136d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 2573.387a707f6f9d720c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/273.f156eee28f11af77.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2873.d2140e5a82546401.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 3072.01338851ca21a6f7.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3091.a5a4143dea33d197.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{2456.b6de0e1c05f28843.js → 3095.dc44586a5f83b86d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3207.a756c95e9ec8c3c8.js → 3113.d7472bbc27d580c7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3228-9650b6447b6fa288.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3402.44b565b314f2263c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3557ac4a.c8931684475018ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8505.fd803c6c33b54cc3.js → 360.ae9f9f4c33c395e8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 363bfab3.9623b9f89363541f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3694.e0099884345f0198.js +64 -0
- package/apps/pwa/out/_next/static/chunks/3744.54f87db52acfd1ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3903.3ef4656c67572764.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3935.16701e33f8982dc9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3955.6922286237f2ac2b.js +24 -0
- package/apps/pwa/out/_next/static/chunks/3969.272ee7f9fd6c62e5.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 4199.ce86b281fd0a60b7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4311-6dd3144002cc0c2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4426-2b230fad00c88930.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2690.0521c738b7749931.js → 4445.7990c76b3751a918.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4447-14c5161fa59166c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4856-b0b8075bba8c53f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4870-de370d65e73c0bb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4885-2c989165c4b29fad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1945.7b54990d578c119b.js → 4894.fec2ca9e99caefa2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5093.8f04b7f8cb899a95.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5122-2bb177cebf89e19a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5154.5f56dc3902e3d275.js +36 -0
- package/apps/pwa/out/_next/static/chunks/529.64ff7257180b2ac9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5394.5dabeb0c62293a28.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5461.08bf2404ff38ec85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5474-22e08a85583209b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 5564.9e72532188f57586.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/5567-265df39ed8fe9dcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5570-a94ae19811cb2046.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5574-b47c9ef2dceff1fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 5628.6ddb2d5ffba4ff4c.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/{1319.b9b815ae0f181e06.js → 5730.43d7ccc09988e646.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5789.2da35c258292e1e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5824.da9527b15a3221e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 5930.8b4df3b46c32b05a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5963-c4d8469c52a0828b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6001.ec4049ceb3c43418.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6120-471f03db1e299c0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6175-41479e643aca1878.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6291.a2de4f9787637075.js +104 -0
- package/apps/pwa/out/_next/static/chunks/6400-6699907c3537436a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6428.1f4327d6ae5fdf9a.js +287 -0
- package/apps/pwa/out/_next/static/chunks/644.02cb026fa44bcd0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6466-6c87d60d3dd174fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 6540.c7bef57ad8f90a87.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6773.d4264665ab31bec0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6822.3c789f1a8443e774.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 6944.309f4e3ea54d1537.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7261-8ff69d3b2ee671fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7266.084c6bbc70035140.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7271.5c0100e7320aa856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7429-bf5731358c8f2f68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7464.01f7a0ae1215fbe7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7479.0fcad5f37eb64f0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4770.769c9cd9c7034eba.js → 7483.427a2fe2049e388d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{1147-5196d19c222051b3.js → 7502-be74718178e13e56.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7530.0889722b19572065.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7645.5b2ee3ad45c55ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7788.7d1c79f1a8e18946.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7900.096f455c7c1efc53.js +77 -0
- package/apps/pwa/out/_next/static/chunks/7910-6f139bcafd238b9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7966.f71c8958d1637548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 8062-7cd0bcc7f01455ba.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8073.f6cf2f2c71aafbd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8201.190b94088980f430.js +74 -0
- package/apps/pwa/out/_next/static/chunks/8205.282ca4bb62d54a0a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/8313-dfa1021bb58a46d6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/837-81336ebaca8198a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8447.7963352ef5f71b76.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8574-868e8129525ef6d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8588.d1c6a2903727ce87.js +149 -0
- package/apps/pwa/out/_next/static/chunks/8637.90f92d5c8db4732c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/868.6e953be05bcf6dca.js +41 -0
- package/apps/pwa/out/_next/static/chunks/8706-e1fe0309343a2273.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8749-06384cdfc4520add.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-374232558fd528d0.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5440-4236de26c5ea5856.js → 8967-7dfebf710c9dec9d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 8986.8e2e4efbfa655c59.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8997-3c564dbb3b58b055.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4320.583cbab64db6be02.js → 923.2034d10ae91e9c20.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1574.878c18ecc97b1bd4.js → 943.39ae5e82f4f1893f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9469.0500480de55fb205.js +32 -0
- package/apps/pwa/out/_next/static/chunks/9770.5f75bc6088b16109.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9810-2543267050e58b82.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9870.8419702475254745.js +8 -0
- package/apps/pwa/out/_next/static/chunks/9941-376d1b74d51b01a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9958.385434ab04241758.js +1 -0
- package/apps/pwa/out/_next/static/chunks/aa57532f.510551854ff239b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-70985b904f8650ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a2e15e33e56a4353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-fc72ce2db12d6ca9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-be03e41f9436ebd9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-35a35999382da3f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-3ff5b1e6ca88b848.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-a65101300a0ee5c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3aca5b6d67dba511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-45b8ab0a71e61314.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-53046e282d4cda8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-17809e60e8354c17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-fd2442d347bf5898.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-e9d720d6fc082e21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-6b8b4267bab0a677.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8bcf6233ac7c17af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-7cc25591cfc2126f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-053e871f35c9beba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-eff819f0c2d5e084.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-4d7e9d8db5274a87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2b2d8f5aa5f69ad4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-0b8f92c5062e68b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1bd9d0fdac2ced3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-0f291d3c8fd55a3a.js → page-9ee28f7df07428ea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-44b7a1ff468c6648.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-cbc6523711dc1b65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-fdad47899c2695be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-79a8b5fee4c20871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-03e8ac9606aeaffb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-4cd55c55ec287e2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-db17b4305404161e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-30041d848350fd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c540da022dbf86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9399efc538da057f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ca2d09128c585ca4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0e2635aecd343038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ef7f4399b6b7726e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-caf530535b875468.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-eaa20c1543a5fd8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c541eb1b75120f61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-ab5e213eda9479f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-0a815f34367b6db6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-e858ba0ed9393b68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-1638ee9dd6e0582f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4cf5a399109391f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b4396321238798ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-cb72bfd21006781a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6135d0242afbc434.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a1dccf907eddb856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/c7945435-b44d4dbe90ba0dcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → d96660fb.cbc21a2a88539dbb.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{50061469.0326382241ef3b2d.js → ea514caa.05a24f78d9dffe5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/fb7d20d5-6892502b6ee39ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-e8a911e19b1be41f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-7022f418fabba021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-e5f15df755756a1e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-4525f91e36940c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-140f0e519c085b0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8f22ef63dcb865b1.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/examples/research-runtime-empty-terminal.yaml +28 -0
- package/graphs/profiles/local.yaml +5 -0
- package/graphs/profiles/pod.yaml +4 -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/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-scenes.ts +301 -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/release-loop/auto-approve-node.ts +1 -1
- package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
- package/scripts/release-loop/gate-method.ts +139 -0
- package/scripts/release-loop/gate-node.ts +180 -20
- package/scripts/release-loop/gate-traffic-mode.ts +151 -3
- package/scripts/release-loop/node-verdict.ts +38 -25
- package/scripts/release-loop/preflight.ts +362 -8
- package/scripts/release-loop/unattended-release.ts +20 -9
- package/scripts/rhythm/daily.ts +36 -4
- package/scripts/rhythm/linear-progress-sync.ts +298 -0
- package/scripts/video-pipeline.ts +9 -1
- package/scripts/warm-pool-provider-config.ts +29 -6
- 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 +47 -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/agents/general-purpose.md +1 -1
- package/src/auto-research/research-turn.ts +95 -10
- 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/doctor-fix.ts +2 -2
- package/src/cli/intake-source-cli.ts +44 -8
- 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 +187 -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 +186 -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/core-turn/deep-turn-bloom.ts +67 -0
- package/src/core-turn/research-policy.ts +37 -0
- package/src/core-turn/run-core-turn.ts +320 -30
- package/src/core-turn/types.ts +2 -0
- package/src/dashboard/chat/acp-chat.ts +10 -0
- package/src/dashboard/classic-sidetab-mission-job.ts +103 -0
- package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
- package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
- package/src/dashboard/classic-sidetab-mission.ts +167 -5
- package/src/dashboard/index.ts +378 -13
- 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 +1 -1
- package/src/dashboard/terminal-popup-runtime.ts +6 -3
- 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/telegram-kind-route.ts +16 -9
- package/src/graph-runner/arg-allowance.ts +13 -0
- package/src/graph-runner/graph-run-api.ts +3 -1
- package/src/graph-runner/runner.ts +85 -17
- 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 +11 -1
- 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 +127 -10
- 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/provider-credentials.ts +8 -2
- package/src/llm.ts +2 -1
- package/src/maturity/feature-maturity.ts +3 -3
- 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/http-server.ts +37 -1
- package/src/nexus/api/mcp-public-allowlist.ts +2 -0
- package/src/nexus/index.ts +7 -2
- package/src/nexus/outbound/format.ts +9 -0
- package/src/nexus/outbound/router.ts +98 -13
- 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 +44 -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 +85 -26
- 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/pty-shell/pty-control-ipc.ts +4 -1
- package/src/registry/catalog-server.ts +232 -0
- package/src/registry/loader.ts +45 -1
- package/src/registry/types.ts +1 -2
- package/src/research/axis-fanout.ts +43 -28
- package/src/self-dev/ask-launch-flow.ts +72 -1
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +5 -0
- package/src/self-dev/draft-residue.ts +64 -5
- 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/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 +358 -4
- package/src/self-implement/graph-overlay-yaml.ts +30 -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 +26 -3
- package/src/self-implement/off-diff-evidence.ts +249 -5
- package/src/self-implement/orchestrator.ts +240 -15
- 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/train-gate-receipt.ts +166 -0
- package/src/self-implement/train-gate-remote.ts +62 -18
- package/src/session/chat.ts +4 -2
- 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 +37 -1
- 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/visible-agent-mission.ts +98 -22
- package/src/skills/tools/agent.ts +23 -4
- package/src/skills/tools/omni-search.ts +123 -25
- package/src/task-agent/parent-host.ts +10 -0
- package/src/task-agent/repair-outcomes.ts +65 -0
- package/src/task-agent/task-hand.ts +20 -7
- 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 +4 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
- 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-provider.ts +35 -9
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -6
- 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 +1 -0
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/browser-hand-runtime.ts +381 -0
- package/src/tool-runtime/browser-runtime.ts +2 -1
- package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
- package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -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 +3 -0
- package/src/tui/entry.ts +24 -1
- package/src/tui/sidetab/attach.ts +140 -11
- package/src/tui/sidetab/herdr-portal.ts +225 -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 +198 -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 +216 -0
- package/src/ux-sim/mock-scenario-catalog.json +75 -23
- package/src/ux-sim/mock-scenario-catalog.ts +120 -2
- package/src/ux-sim/onboarding-first-run-device.ts +31 -21
- package/src/ux-sim/scenario.ts +70 -26
- package/src/ux-sim/service-key-setup.ts +50 -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/1345-31427b833438f521.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.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/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/2160.a097e7b138ae1c55.js +0 -23
- 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/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/2974.595d1e29d040cb6a.js +0 -64
- 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/4768-8eac183fd291ca53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
- 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/5431-72a1dbde59400691.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/5885.0a3e52c8faccec98.js +0 -287
- 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/6377.bc7df239edbff244.js +0 -1
- 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/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/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/9415.69e4a21c60c7d2db.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/9832.f4a98c878ecf2c0a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.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/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 → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import { BriefItemsLedger } from '../briefing/brief-items.js';
|
|
2
|
+
import { EventLedger } from '../connectors/event-ledger.js';
|
|
3
|
+
import { commentLinearIssue, moveLinearIssueToStateType } from '../connectors/linear.js';
|
|
4
|
+
import { getSecretAsync } from '../nexus/config/secrets/index.js';
|
|
1
5
|
import { captureAndDraftIntakeRecord } from './capture.js';
|
|
6
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
7
|
+
import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
10
|
+
import { addSource, canonicalSeat, listSources, removeSource, runDue, type RunDueDeps, type RegisteredIntakeSource } from './intake-sources.js';
|
|
2
11
|
import {
|
|
3
12
|
applyClarifyAnswerToDraft,
|
|
4
13
|
buildDecisionFromIntent,
|
|
@@ -10,6 +19,351 @@ import {
|
|
|
10
19
|
proposeIntakeSessionToTox,
|
|
11
20
|
} from './tox-adapter.js';
|
|
12
21
|
import type { IntakeSession, RawIntakeRecord } from './types.js';
|
|
22
|
+
import type { BriefItem } from '../briefing/brief-items.js';
|
|
23
|
+
|
|
24
|
+
export interface TopicBriefingDeliveryDeps {
|
|
25
|
+
sendIssueCard: (input: { linearIssueId: string; text: string }) => Promise<void>;
|
|
26
|
+
commentIssue: (linearIssueId: string, text: string) => Promise<void>;
|
|
27
|
+
issueIsDone: (linearIssueId: string) => Promise<boolean>;
|
|
28
|
+
isDecisionImpacting: (items: readonly BriefItem[]) => Promise<boolean>;
|
|
29
|
+
reopenIssue: (linearIssueId: string) => Promise<void>;
|
|
30
|
+
sendMemoUpdateCard: (input: { linearIssueId: string; text: string }) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface TopicBriefingDeliveryReceipt {
|
|
34
|
+
telegramSent: boolean;
|
|
35
|
+
linearCommented: boolean;
|
|
36
|
+
reopened: boolean;
|
|
37
|
+
memoSent: boolean;
|
|
38
|
+
updatedAt: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function topicBriefingReceiptsFile(stateDir: string): string { return join(stateDir, 'intake', 'topic-briefing-deliveries.json'); }
|
|
42
|
+
|
|
43
|
+
function readTopicBriefingReceipts(stateDir: string): Record<string, TopicBriefingDeliveryReceipt> {
|
|
44
|
+
const file = topicBriefingReceiptsFile(stateDir);
|
|
45
|
+
if (!existsSync(file)) return {};
|
|
46
|
+
const parsed: unknown = JSON.parse(readFileSync(file, 'utf8'));
|
|
47
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error(`topic briefing receipt ledger shape invalid: ${file}`);
|
|
48
|
+
return parsed as Record<string, TopicBriefingDeliveryReceipt>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function saveTopicBriefingReceipts(stateDir: string, receipts: Record<string, TopicBriefingDeliveryReceipt>): void {
|
|
52
|
+
const file = topicBriefingReceiptsFile(stateDir);
|
|
53
|
+
mkdirSync(join(stateDir, 'intake'), { recursive: true });
|
|
54
|
+
const temp = `${file}.${randomUUID()}.tmp`;
|
|
55
|
+
try {
|
|
56
|
+
const fd = openSync(temp, 'wx', 0o600);
|
|
57
|
+
try { writeFileSync(fd, JSON.stringify(receipts, null, 2) + '\n'); } finally { closeSync(fd); }
|
|
58
|
+
chmodSync(temp, 0o600);
|
|
59
|
+
renameSync(temp, file);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (existsSync(temp)) unlinkSync(temp);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Persist each external delivery stage so a later channel failure cannot resend a successful Telegram card/comment. */
|
|
67
|
+
export async function deliverTopicBriefingWithReceipts(input: {
|
|
68
|
+
linearIssueId: string;
|
|
69
|
+
issueLabel?: string;
|
|
70
|
+
summary: string;
|
|
71
|
+
items: readonly BriefItem[];
|
|
72
|
+
}, stateDir: string, deps: TopicBriefingDeliveryDeps, mode: 'live' | 'telegram-dry-run' = 'live'): Promise<{ related: number; reopened: boolean }> {
|
|
73
|
+
const receiptKey = createHash('sha256').update(`${mode}\n${input.linearIssueId.toLowerCase()}\n${input.items.map(item => item.id).sort((a, b) => a - b).join(',')}`).digest('hex');
|
|
74
|
+
const receipts = readTopicBriefingReceipts(stateDir);
|
|
75
|
+
const receipt = receipts[receiptKey] ?? { telegramSent: false, linearCommented: false, reopened: false, memoSent: false, updatedAt: '' };
|
|
76
|
+
const saveReceipt = (): void => {
|
|
77
|
+
receipt.updatedAt = new Date().toISOString();
|
|
78
|
+
receipts[receiptKey] = receipt;
|
|
79
|
+
const expiry = Date.now() - 90 * 86_400_000;
|
|
80
|
+
for (const [key, value] of Object.entries(receipts)) if (Date.parse(value.updatedAt) < expiry) delete receipts[key];
|
|
81
|
+
saveTopicBriefingReceipts(stateDir, receipts);
|
|
82
|
+
};
|
|
83
|
+
return deliverTopicBriefing(input, {
|
|
84
|
+
...deps,
|
|
85
|
+
sendIssueCard: async card => { if (!receipt.telegramSent) { await deps.sendIssueCard(card); receipt.telegramSent = true; saveReceipt(); } },
|
|
86
|
+
commentIssue: async (issueId, text) => { if (!receipt.linearCommented) { await deps.commentIssue(issueId, text); receipt.linearCommented = true; saveReceipt(); } },
|
|
87
|
+
issueIsDone: async issueId => receipt.reopened || await deps.issueIsDone(issueId),
|
|
88
|
+
isDecisionImpacting: async items => receipt.reopened || await deps.isDecisionImpacting(items),
|
|
89
|
+
reopenIssue: async issueId => { if (!receipt.reopened) { await deps.reopenIssue(issueId); receipt.reopened = true; saveReceipt(); } },
|
|
90
|
+
sendMemoUpdateCard: async card => { if (!receipt.memoSent) { await deps.sendMemoUpdateCard(card); receipt.memoSent = true; saveReceipt(); } },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function isDecisionImpactingTopicEvidence(items: readonly BriefItem[]): boolean {
|
|
95
|
+
const decisionTerms = /(?:파산|부도|법정관리|사업 철수|공장 폐쇄|생산 중단|공급 중단|제재|소송|(?:계약|주문|공급|생산|투자|가이던스|실적|매출|수익|전망)(?:이|가|을|를|은|는)?\s*(?:취소|파기|철회|중단|감산|급감|감소|축소|하향|하락|적자 전환|대폭 삭감)|\b(?:bankruptcy|default|plant closure|business exit|production halt|supply halt|sanction|lawsuit|withdrawn|terminated)\b|\b(?:contract|order|supply|production|investment|guidance|earnings|revenue|profit|outlook)\s+(?:cancelled?|terminated|withdrawn|suspended|cut|reduced|downgraded|loss|miss)\b)/iu;
|
|
96
|
+
return items.some(item => decisionTerms.test(item.text));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Project only issue-linked findings; scheduled callers may invoke this after every run, including after Done. */
|
|
100
|
+
export async function deliverTopicBriefing(input: {
|
|
101
|
+
linearIssueId: string;
|
|
102
|
+
issueLabel?: string;
|
|
103
|
+
summary: string;
|
|
104
|
+
items: readonly BriefItem[];
|
|
105
|
+
}, deps: TopicBriefingDeliveryDeps): Promise<{ related: number; reopened: boolean }> {
|
|
106
|
+
const related = input.items.filter(item => item.linearIssueId?.toLowerCase() === input.linearIssueId.toLowerCase());
|
|
107
|
+
if (related.length === 0) return { related: 0, reopened: false };
|
|
108
|
+
const sources = related.map(item => item.evidence).filter((url): url is string => !!url);
|
|
109
|
+
const text = `관련 이슈 · ${input.issueLabel?.trim() || input.linearIssueId}\n\n${input.summary.trim()}${sources.length ? `\n\n출처\n${sources.map(url => `- ${url}`).join('\n')}` : ''}`;
|
|
110
|
+
await deps.sendIssueCard({ linearIssueId: input.linearIssueId, text });
|
|
111
|
+
await deps.commentIssue(input.linearIssueId, text);
|
|
112
|
+
const reopened = await deps.issueIsDone(input.linearIssueId) && await deps.isDecisionImpacting(related);
|
|
113
|
+
if (reopened) {
|
|
114
|
+
await deps.reopenIssue(input.linearIssueId);
|
|
115
|
+
await deps.sendMemoUpdateCard({ linearIssueId: input.linearIssueId,
|
|
116
|
+
text: `관련 이슈 · ${input.issueLabel?.trim() || input.linearIssueId}\n메모 갱신?\n\n${input.summary.trim()}` });
|
|
117
|
+
}
|
|
118
|
+
return { related: related.length, reopened };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Production adapter used by both the immediate subscription run and each existing daemon schedule fire. */
|
|
122
|
+
export function appendTopicBriefingTelegramDryRun(file: string, input: { linearIssueId: string; text: string; kind: 'issue' | 'memo' }): void {
|
|
123
|
+
appendFileSync(file, `${JSON.stringify({ recordedAt: new Date().toISOString(), ...input })}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
124
|
+
chmodSync(file, 0o600);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function projectTopicBriefing(source: RegisteredIntakeSource, items: BriefItem[], stateDir = effectiveInstanceRoot(),
|
|
128
|
+
options: { telegramDryRunFile?: string } = {}): Promise<void> {
|
|
129
|
+
if (!source.linearIssueId || items.length === 0) return;
|
|
130
|
+
const [{ getSecretAsync }, { commentLinearIssue, fetchLinearIssueStateType, moveLinearIssueToStateType },
|
|
131
|
+
{ kindRouteTarget }, { getUserConfig }, { sendTelegramTo }] = await Promise.all([
|
|
132
|
+
import('../nexus/config/secrets/index.js'), import('../connectors/linear.js'), import('../domains/telegram-kind-route.js'),
|
|
133
|
+
import('../user-config.js'), import('../autopilot/mission-notify.js'),
|
|
134
|
+
]);
|
|
135
|
+
const target = options.telegramDryRunFile ? undefined : kindRouteTarget(getUserConfig(), 'ops-report');
|
|
136
|
+
if (!options.telegramDryRunFile && !target) throw new Error('관련 이슈 브리핑 Telegram ops-report 대상이 없습니다');
|
|
137
|
+
const send = async (text: string, kind: 'issue' | 'memo'): Promise<void> => {
|
|
138
|
+
if (options.telegramDryRunFile) {
|
|
139
|
+
appendTopicBriefingTelegramDryRun(options.telegramDryRunFile, { linearIssueId: source.linearIssueId!, text, kind });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!target || !sendTelegramTo(target.botToken, target.chatId, text)) throw new Error('관련 이슈 브리핑 Telegram 발송 실패');
|
|
143
|
+
};
|
|
144
|
+
const apiKey = await getSecretAsync('connector.linear.apiKey');
|
|
145
|
+
if (!apiKey) throw new Error('Linear 키가 없습니다');
|
|
146
|
+
await deliverTopicBriefingWithReceipts({ linearIssueId: source.linearIssueId, issueLabel: source.spec,
|
|
147
|
+
summary: items.map(item => item.text).join('\n'), items }, stateDir, {
|
|
148
|
+
sendIssueCard: async ({ text }) => send(text, 'issue'),
|
|
149
|
+
commentIssue: async (issueId, body) => commentLinearIssue({ apiKey, issueId, body }),
|
|
150
|
+
issueIsDone: async issueId => await fetchLinearIssueStateType({ apiKey, issueId }) === 'completed',
|
|
151
|
+
isDecisionImpacting: async related => isDecisionImpactingTopicEvidence(related),
|
|
152
|
+
reopenIssue: async issueId => moveLinearIssueToStateType({ apiKey, issueId, type: 'started' }),
|
|
153
|
+
sendMemoUpdateCard: async ({ text }) => send(text, 'memo'),
|
|
154
|
+
}, options.telegramDryRunFile ? 'telegram-dry-run' : 'live');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface SubscribeTopicSearchInput {
|
|
158
|
+
seat: string;
|
|
159
|
+
topic: string;
|
|
160
|
+
/** Parent Linear issue.id UUID (`ExternalTaskEvent.ref` / task generatedBy.ref). */
|
|
161
|
+
linearIssueId: string;
|
|
162
|
+
every: string;
|
|
163
|
+
/** Per-subscription five-field cron, e.g. `0 8 * * 1` for Mondays at 08:00. */
|
|
164
|
+
scheduleCron: string;
|
|
165
|
+
/** Absolute path receiving Telegram message bodies instead of live sends. */
|
|
166
|
+
telegramDryRunFile?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface SubscribeTopicSearchDeps {
|
|
170
|
+
stateDir?: string;
|
|
171
|
+
now?: Date;
|
|
172
|
+
runDue?: typeof runDue;
|
|
173
|
+
sourceAdd?: typeof addSource;
|
|
174
|
+
sourceList?: typeof listSources;
|
|
175
|
+
sourceRemove?: typeof removeSource;
|
|
176
|
+
scheduleDispatch?: (args: Record<string, unknown>) => Promise<unknown>;
|
|
177
|
+
runDeps?: RunDueDeps;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function scheduleError(result: unknown): string | null {
|
|
181
|
+
return result && typeof result === 'object' && 'error' in result ? String((result as { error: unknown }).error) : null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Linear secretary handoff: register one issue-linked topic source, create and
|
|
186
|
+
* migrate exactly one existing schedule-registry job to the workflow daemon,
|
|
187
|
+
* then run that same source immediately through runDue.
|
|
188
|
+
*/
|
|
189
|
+
export async function subscribeTopicSearch(input: SubscribeTopicSearchInput, deps: SubscribeTopicSearchDeps = {}): Promise<{
|
|
190
|
+
source: RegisteredIntakeSource;
|
|
191
|
+
scheduleId: string;
|
|
192
|
+
immediate: Awaited<ReturnType<typeof runDue>>;
|
|
193
|
+
}> {
|
|
194
|
+
const stateDir = deps.stateDir ?? effectiveInstanceRoot();
|
|
195
|
+
const normalizedTopic = input.topic.trim();
|
|
196
|
+
if (!normalizedTopic) throw new Error('topic-search topic이 비었다');
|
|
197
|
+
const seat = canonicalSeat(input.seat);
|
|
198
|
+
const sourceId = `topic-${createHash('sha256').update(`${seat}\n${input.linearIssueId.toLowerCase()}\n${normalizedTopic.toLowerCase()}`)
|
|
199
|
+
.digest('hex').slice(0, 20)}`;
|
|
200
|
+
const sources = deps.sourceList ?? listSources;
|
|
201
|
+
const add = deps.sourceAdd ?? addSource;
|
|
202
|
+
const remove = deps.sourceRemove ?? removeSource;
|
|
203
|
+
const existing = sources({}, stateDir).find((source) => source.id === sourceId);
|
|
204
|
+
let source: RegisteredIntakeSource;
|
|
205
|
+
let created = false;
|
|
206
|
+
let scheduleCreatedNow = false;
|
|
207
|
+
if (existing) {
|
|
208
|
+
if (existing.kind !== 'topic-search' || existing.linearIssueId?.toLowerCase() !== input.linearIssueId.toLowerCase()
|
|
209
|
+
|| existing.spec.toLowerCase() !== normalizedTopic.toLowerCase() || existing.scheduleCron !== input.scheduleCron) {
|
|
210
|
+
throw new Error(`topic-search source identity collision: ${sourceId}`);
|
|
211
|
+
}
|
|
212
|
+
source = existing;
|
|
213
|
+
} else {
|
|
214
|
+
source = add({ id: sourceId, seat, kind: 'topic-search', spec: normalizedTopic,
|
|
215
|
+
every: input.every, scheduleCron: input.scheduleCron, linearIssueId: input.linearIssueId }, stateDir);
|
|
216
|
+
created = true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const dispatch = deps.scheduleDispatch ?? (async (args: Record<string, unknown>) => {
|
|
220
|
+
const { dispatchScheduleManage } = await import('../domains/schedule-manage-tool.js');
|
|
221
|
+
return dispatchScheduleManage(args);
|
|
222
|
+
});
|
|
223
|
+
const dryRunArg = input.telegramDryRunFile
|
|
224
|
+
? ` --telegram-dry-run-file '${input.telegramDryRunFile.replaceAll("'", "'\\''")}'` : '';
|
|
225
|
+
const command = `eln intake source run-due --source-id ${sourceId} --project-issue-briefing${dryRunArg}`;
|
|
226
|
+
let scheduleId: string | undefined;
|
|
227
|
+
const createSchedule = async (): Promise<void> => {
|
|
228
|
+
const creation = await dispatch({ action: 'create', cron: input.scheduleCron, command, category: 'ingest' });
|
|
229
|
+
const createError = scheduleError(creation);
|
|
230
|
+
if (createError) throw new Error(`topic-search 일정 등록 실패: ${createError}`);
|
|
231
|
+
scheduleCreatedNow = true;
|
|
232
|
+
// Crontab inventory derives category from the command, so the created
|
|
233
|
+
// job may appear under maintenance instead of the requested ingest
|
|
234
|
+
// category. Match by exact command + cron across the registry.
|
|
235
|
+
const listing = await dispatch({ action: 'list' }) as { schedules?: Array<{ id?: string; command?: string; cron?: string }> };
|
|
236
|
+
const listError = scheduleError(listing);
|
|
237
|
+
if (listError) throw new Error(`topic-search 일정 목록 확인 실패: ${listError}`);
|
|
238
|
+
const match = listing.schedules?.find((row) => row.command === command && row.cron === input.scheduleCron);
|
|
239
|
+
if (!match?.id) throw new Error('topic-search 일정이 schedule registry에 나타나지 않았다');
|
|
240
|
+
scheduleId = match.id;
|
|
241
|
+
const migrated = await dispatch({ action: 'migrate', id: scheduleId, yes: true });
|
|
242
|
+
const migrateError = scheduleError(migrated);
|
|
243
|
+
if (migrateError) throw new Error(`topic-search 일정을 데몬으로 이관하지 못했다: ${migrateError}`);
|
|
244
|
+
const noted = await dispatch({ action: 'note', id: scheduleId,
|
|
245
|
+
note: `topic-search · ${sourceId} · parent Linear UUID ${input.linearIssueId}` });
|
|
246
|
+
const noteError = scheduleError(noted);
|
|
247
|
+
if (noteError) throw new Error(`topic-search 일정 설명 저장 실패: ${noteError}`);
|
|
248
|
+
};
|
|
249
|
+
try {
|
|
250
|
+
if (!existing) await createSchedule();
|
|
251
|
+
else {
|
|
252
|
+
const listing = await dispatch({ action: 'list' }) as { schedules?: Array<{ id?: string; command?: string; cron?: string }> };
|
|
253
|
+
const listError = scheduleError(listing);
|
|
254
|
+
if (listError) throw new Error(`기존 topic-search 일정 목록 확인 실패: ${listError}`);
|
|
255
|
+
const sourceCommandPrefix = `eln intake source run-due --source-id ${sourceId} --project-issue-briefing`;
|
|
256
|
+
const conflicting = listing.schedules?.find((row) => row.cron === input.scheduleCron
|
|
257
|
+
&& row.command?.startsWith(sourceCommandPrefix) && row.command !== command);
|
|
258
|
+
if (conflicting) throw new Error(`기존 topic-search 일정의 Telegram 실행 모드가 다르다; 중복 예약을 피하려면 기존 일정부터 제거해야 한다: ${conflicting.id ?? sourceId}`);
|
|
259
|
+
const match = listing.schedules?.find((row) => row.command === command && row.cron === input.scheduleCron);
|
|
260
|
+
if (match?.id) scheduleId = match.id;
|
|
261
|
+
else await createSchedule();
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
if (scheduleCreatedNow) {
|
|
265
|
+
let orphan = scheduleId;
|
|
266
|
+
if (!orphan) {
|
|
267
|
+
try {
|
|
268
|
+
const listing = await dispatch({ action: 'list' }) as { schedules?: Array<{ id?: string; command?: string; cron?: string }> };
|
|
269
|
+
orphan = listing.schedules?.find((row) => row.command === command && row.cron === input.scheduleCron)?.id;
|
|
270
|
+
} catch { /* source cleanup below remains primary */ }
|
|
271
|
+
}
|
|
272
|
+
if (orphan) try { await dispatch({ action: 'delete', id: orphan, yes: true }); } catch { /* preserve primary error */ }
|
|
273
|
+
}
|
|
274
|
+
if (created) {
|
|
275
|
+
remove(sourceId, stateDir);
|
|
276
|
+
}
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const immediate = await (deps.runDue ?? runDue)({ now: deps.now ?? new Date(), seat, sourceId,
|
|
281
|
+
deps: { ...deps.runDeps, stateDir, projectTopicBriefing: deps.runDeps?.projectTopicBriefing ?? (input.telegramDryRunFile
|
|
282
|
+
? (registered, items, dir) => projectTopicBriefing(registered, items, dir, { telegramDryRunFile: input.telegramDryRunFile })
|
|
283
|
+
: projectTopicBriefing) } });
|
|
284
|
+
return { source, scheduleId: scheduleId!, immediate };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface IntakeIssueBriefingEvidence {
|
|
288
|
+
title: string;
|
|
289
|
+
url: string;
|
|
290
|
+
summary: string;
|
|
291
|
+
reopensIssue?: boolean;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface IntakeIssueBriefingInput {
|
|
295
|
+
issueRef: string;
|
|
296
|
+
topic: string;
|
|
297
|
+
state: 'open' | 'done';
|
|
298
|
+
evidence: readonly IntakeIssueBriefingEvidence[];
|
|
299
|
+
collected?: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface IntakeIssueBriefingDeps {
|
|
303
|
+
stateDir: string;
|
|
304
|
+
ledger?: BriefItemsLedger;
|
|
305
|
+
registerSource?: (source: RegisteredIntakeSource) => void;
|
|
306
|
+
runSources?: () => Promise<{ ran: Array<{ id: string; items: number; error?: string }> }>;
|
|
307
|
+
commentIssue?: (issueRef: string, body: string) => Promise<void>;
|
|
308
|
+
reopenIssue?: (issueRef: string) => Promise<void>;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function issueWatchId(issueRef: string): string {
|
|
312
|
+
return `watch-${issueRef.replace(/[^\w.-]+/g, '-')}`;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function issueBriefingComment(input: IntakeIssueBriefingInput, evidence: readonly IntakeIssueBriefingEvidence[]): string {
|
|
316
|
+
return [`## 흡수 브리핑 · ${input.issueRef}`, ...evidence.map(item => `- ${item.title}: ${item.summary} (${item.url})`)].join('\n');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function defaultCommentIssue(stateDir: string, issueRef: string, body: string): Promise<void> {
|
|
320
|
+
const apiKey = await getSecretAsync('connector.linear.apiKey');
|
|
321
|
+
if (!apiKey?.trim()) return;
|
|
322
|
+
await commentLinearIssue({ apiKey, issueId: issueRef, body });
|
|
323
|
+
const hash = createHash('sha256').update(body).digest('hex');
|
|
324
|
+
new EventLedger(join(stateDir, 'connectors', 'events.jsonl')).record('linear', `outgoing:comment:brief:${issueRef}:${hash}`, {
|
|
325
|
+
ref: issueRef, occurredAt: new Date().toISOString(),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function defaultReopenIssue(stateDir: string, issueRef: string): Promise<void> {
|
|
330
|
+
const apiKey = await getSecretAsync('connector.linear.apiKey');
|
|
331
|
+
if (!apiKey?.trim()) return;
|
|
332
|
+
await moveLinearIssueToStateType({ apiKey, issueId: issueRef, type: 'started' });
|
|
333
|
+
new EventLedger(join(stateDir, 'connectors', 'events.jsonl')).record('linear', `outgoing:reopen:brief:${issueRef}:${Date.now()}`, {
|
|
334
|
+
ref: issueRef, occurredAt: new Date().toISOString(),
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* The intake-daily bridge preserves the Linear secretary identifier from subscription through the briefing ledger.
|
|
340
|
+
* Open issues receive evidence cards and Linear comments; a material event on a done issue records a memo-update card and reopens it.
|
|
341
|
+
*/
|
|
342
|
+
export async function runIntakeIssueBriefing(input: IntakeIssueBriefingInput, deps: IntakeIssueBriefingDeps): Promise<void> {
|
|
343
|
+
if (!input.issueRef.trim() || !input.topic.trim()) throw new Error('issueRef and topic are required');
|
|
344
|
+
const source: RegisteredIntakeSource = {
|
|
345
|
+
id: issueWatchId(input.issueRef), seat: 'user', kind: 'github-query', spec: input.topic, every: '1d',
|
|
346
|
+
why: `linear-secretary:${input.issueRef}`, issueRef: input.issueRef,
|
|
347
|
+
};
|
|
348
|
+
if (deps.registerSource) deps.registerSource(source);
|
|
349
|
+
else if (!listSources({}, deps.stateDir).some(entry => entry.id === source.id)) addSource(source, deps.stateDir);
|
|
350
|
+
if (!input.collected) await (deps.runSources ?? (() => runDue({ deps: { stateDir: deps.stateDir } })))();
|
|
351
|
+
|
|
352
|
+
const relevant = input.state === 'open' ? input.evidence : input.evidence.filter(item => item.reopensIssue === true);
|
|
353
|
+
if (relevant.length === 0) return;
|
|
354
|
+
const ledger = deps.ledger ?? new BriefItemsLedger({ stateDir: deps.stateDir });
|
|
355
|
+
for (const item of relevant) {
|
|
356
|
+
ledger.add({
|
|
357
|
+
text: input.state === 'done' ? `메모 갱신? ${item.title}: ${item.summary}` : `${item.title}: ${item.summary}`,
|
|
358
|
+
domain: '흡수', priority: item.reopensIssue ? 'P0' : 'P1', source: 'intake-daily', evidence: item.url, issueRef: input.issueRef,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
const body = issueBriefingComment(input, relevant);
|
|
362
|
+
await (deps.commentIssue ?? ((issueRef, comment) => defaultCommentIssue(deps.stateDir, issueRef, comment)))(input.issueRef, body);
|
|
363
|
+
if (input.state === 'done' && relevant.some(item => item.reopensIssue)) {
|
|
364
|
+
await (deps.reopenIssue ?? (issueRef => defaultReopenIssue(deps.stateDir, issueRef)))(input.issueRef);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
13
367
|
|
|
14
368
|
export interface ReplayIntakeResult {
|
|
15
369
|
sourceId: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { maybeHandleAmbientTextIntake } from '../ambient.js';
|
|
2
2
|
import type { IntakeAmbientCaptureMode } from '../../user-config.js';
|
|
3
3
|
|
|
4
|
+
const LINEAR_SECRETARY_INTENT = /(?:리니어|linear)(?:로|에|에다)?\s*(?:등록해(?:줘요?|주세요)?|정리해(?:줘요?|주세요)|쪼개(?:줘요?|주세요)|맡겨(?:줘요?|주세요)|만들어(?:줘요?|주세요))(?!\s*(?:라고|하던데|했는데|하라던데|해달라고|하라며))/i;
|
|
5
|
+
|
|
4
6
|
export interface TelegramAmbientMessageContext {
|
|
5
7
|
text: string;
|
|
6
8
|
chatId: number | string;
|
|
@@ -10,22 +12,36 @@ export interface TelegramAmbientMessageContext {
|
|
|
10
12
|
ambientCapture?: IntakeAmbientCaptureMode;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
export function createTelegramAmbientMessageHandler(deps: {
|
|
16
|
+
runSecretary?: (request: string) => Promise<{ replyCard: string }>;
|
|
17
|
+
} = {}) {
|
|
18
|
+
return async function maybeHandleTelegramAmbientMessage(ctx: TelegramAmbientMessageContext): Promise<string | null> {
|
|
19
|
+
if (!ctx.text || ctx.text.startsWith('/')) return null;
|
|
20
|
+
if (LINEAR_SECRETARY_INTENT.test(ctx.text)) {
|
|
21
|
+
const runSecretary = deps.runSecretary ?? (async (request: string) =>
|
|
22
|
+
(await import('../linear-secretary-runtime.js')).runLinearSecretaryRequest(request));
|
|
23
|
+
try {
|
|
24
|
+
const result = await runSecretary(ctx.text);
|
|
25
|
+
return result.replyCard;
|
|
26
|
+
} catch {
|
|
27
|
+
return 'Linear 등록을 보류했습니다. 요청 날짜와 근거를 확인한 뒤 다시 시도해 주세요.';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return maybeHandleAmbientTextIntake({
|
|
31
|
+
surface: 'telegram',
|
|
32
|
+
source: 'telegram',
|
|
33
|
+
text: ctx.text,
|
|
34
|
+
actor: {
|
|
35
|
+
id: String(ctx.userId),
|
|
36
|
+
...(ctx.userName ? { display: ctx.userName } : {}),
|
|
37
|
+
},
|
|
38
|
+
channelContext: {
|
|
39
|
+
chatId: String(ctx.chatId),
|
|
40
|
+
...(ctx.threadId != null ? { threadId: String(ctx.threadId) } : {}),
|
|
41
|
+
},
|
|
42
|
+
mode: ctx.ambientCapture ?? 'off',
|
|
43
|
+
});
|
|
44
|
+
};
|
|
31
45
|
}
|
|
46
|
+
|
|
47
|
+
export const maybeHandleTelegramAmbientMessage = createTelegramAmbientMessageHandler();
|
|
@@ -2,20 +2,27 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
3
|
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
import cron from 'node-cron';
|
|
5
6
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
7
|
import { findTrack } from '../autopilot/mission-phase-track.js';
|
|
7
8
|
import { appendGithubStarSnapshots, collectGithubStars, ghApiSearchRepos, type SearchGithubRepos } from './collect-github.js';
|
|
8
9
|
import { ingestIntakeItems, parseRawIntakeJsonl, type IntakeSource, type RegisteredIntakeSourceKind, type RawIntakeItem } from './items.js';
|
|
9
10
|
|
|
10
|
-
export type SourceKind = 'github-query' | 'rss' | 'command';
|
|
11
|
+
export type SourceKind = 'github-query' | 'rss' | 'command' | 'topic-search';
|
|
11
12
|
export interface RegisteredIntakeSource {
|
|
12
13
|
id: string;
|
|
13
14
|
seat: string;
|
|
14
15
|
kind: SourceKind;
|
|
15
16
|
spec: string;
|
|
16
17
|
every: string;
|
|
18
|
+
/** Per-topic recurring fire time, interpreted by the existing schedule registry/daemon path. */
|
|
19
|
+
scheduleCron?: string;
|
|
17
20
|
until?: string;
|
|
18
21
|
why?: string;
|
|
22
|
+
/** Existing Linear secretary issue identifier; absent for ordinary sources. */
|
|
23
|
+
issueRef?: string;
|
|
24
|
+
/** Parent Linear issue UUID; never replace with the display identifier. */
|
|
25
|
+
linearIssueId?: string;
|
|
19
26
|
lastRunAt?: string;
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -88,11 +95,19 @@ function commandArgv(spec: string): string[] {
|
|
|
88
95
|
|
|
89
96
|
export function addSource(input: RegisteredIntakeSource, stateDir = effectiveInstanceRoot()): RegisteredIntakeSource {
|
|
90
97
|
const seat = canonicalSeat(input.seat);
|
|
91
|
-
if (!['github-query', 'rss', 'command'].includes(input.kind)) throw new Error(`알 수 없는 원천 종류: ${input.kind}`);
|
|
98
|
+
if (!['github-query', 'rss', 'command', 'topic-search'].includes(input.kind)) throw new Error(`알 수 없는 원천 종류: ${input.kind}`);
|
|
92
99
|
cadenceMs(input.every);
|
|
93
100
|
if (input.until !== undefined) untilMs(input.until);
|
|
94
101
|
if (!input.id?.trim() || !/^[\w.-]+$/.test(input.id)) throw new Error('원천 id 는 영문·숫자·_·-·. 만 허용한다');
|
|
95
102
|
if (!input.spec?.trim()) throw new Error('원천 spec 이 비었다');
|
|
103
|
+
if (input.linearIssueId !== undefined && (input.kind !== 'topic-search'
|
|
104
|
+
|| !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(input.linearIssueId))) {
|
|
105
|
+
throw new Error('topic-search linearIssueId 는 부모 Linear issue UUID여야 한다');
|
|
106
|
+
}
|
|
107
|
+
if (input.kind === 'topic-search' && (!input.linearIssueId || !input.scheduleCron || !cron.validate(input.scheduleCron))) {
|
|
108
|
+
throw new Error('topic-search 는 부모 Linear UUID와 유효한 개별 schedule cron 이 필요하다');
|
|
109
|
+
}
|
|
110
|
+
if (input.kind !== 'topic-search' && input.scheduleCron !== undefined) throw new Error('scheduleCron 은 topic-search 원천만 가질 수 있다');
|
|
96
111
|
if (input.kind === 'rss') {
|
|
97
112
|
let protocol = '';
|
|
98
113
|
try { protocol = new URL(input.spec).protocol; } catch { /* validation below */ }
|
|
@@ -118,8 +133,11 @@ export function removeSource(id: string, stateDir = effectiveInstanceRoot()): bo
|
|
|
118
133
|
return true;
|
|
119
134
|
}
|
|
120
135
|
|
|
121
|
-
export function dueSources(now: Date = new Date(), stateDir = effectiveInstanceRoot()): RegisteredIntakeSource[] {
|
|
122
|
-
return listSources({}, stateDir).filter((source) =>
|
|
136
|
+
export function dueSources(now: Date = new Date(), stateDir = effectiveInstanceRoot(), sourceId?: string): RegisteredIntakeSource[] {
|
|
137
|
+
return listSources({}, stateDir).filter((source) => (sourceId === undefined || source.id === sourceId)
|
|
138
|
+
&& (sourceId !== undefined && source.kind === 'topic-search'
|
|
139
|
+
? !expiredSource(source, now)
|
|
140
|
+
: sourceIsDue(source, now)));
|
|
123
141
|
}
|
|
124
142
|
|
|
125
143
|
export interface RunDueDeps {
|
|
@@ -127,7 +145,39 @@ export interface RunDueDeps {
|
|
|
127
145
|
searchGithub?: SearchGithubRepos;
|
|
128
146
|
fetchFeed?: (url: string) => Promise<string>;
|
|
129
147
|
runCommand?: (command: string) => Promise<string>;
|
|
148
|
+
searchTopic?: (topic: string) => Promise<RawIntakeItem[]>;
|
|
149
|
+
addBriefItem?: (input: import('../briefing/brief-items.js').AddBriefItem) => unknown;
|
|
150
|
+
projectTopicBriefing?: (source: RegisteredIntakeSource, items: import('../briefing/brief-items.js').BriefItem[], stateDir?: string) => Promise<void>;
|
|
130
151
|
ingest?: typeof ingestIntakeItems;
|
|
152
|
+
onCollected?: (source: RegisteredIntakeSource, raws: RawIntakeItem[], now: Date) => Promise<void> | void;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function searchTopicWithResearchBridge(topic: string): Promise<RawIntakeItem[]> {
|
|
156
|
+
const { invokeResearchAxes } = await import('../research-bridge/index.js');
|
|
157
|
+
const fanout = await invokeResearchAxes([{ id: 'intake-topic', prompt: topic, level: 3, searchTerms: [topic] }]);
|
|
158
|
+
const evidence = fanout.axes.find((axis) => axis.questionId === 'intake-topic')?.evidence ?? [];
|
|
159
|
+
return evidence.filter((entry) => entry.outcome !== 'failed' && /^https?:\/\//i.test(entry.source))
|
|
160
|
+
.map((entry) => {
|
|
161
|
+
const [title, ...summary] = entry.content.split(' — ');
|
|
162
|
+
return { url: entry.source, title, text: summary.join(' — ') || entry.content, kind: 'article' };
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function addTopicBriefItems(stateDir: string, source: RegisteredIntakeSource, items: readonly RawIntakeItem[], createdAt: string,
|
|
167
|
+
addBriefItem?: RunDueDeps['addBriefItem']): Promise<void> {
|
|
168
|
+
const ledger = addBriefItem ? null : new (await import('../briefing/brief-items.js')).BriefItemsLedger({ stateDir });
|
|
169
|
+
for (const item of items) {
|
|
170
|
+
if (!item.url) continue;
|
|
171
|
+
const text = `새 토픽 자료: ${(item.title ?? item.text ?? item.url).replace(/[\r\n]+/g, ' ').trim()}`;
|
|
172
|
+
const input = {
|
|
173
|
+
text, domain: '흡수' as const, priority: 'P1' as const, source: `intake.topic-search:${source.id}`,
|
|
174
|
+
evidence: item.url, createdAt,
|
|
175
|
+
...(source.linearIssueId ? { linearIssueId: source.linearIssueId } : {}),
|
|
176
|
+
dedupeKey: `${source.linearIssueId ?? source.id}:${item.url}`, dedupeWithinMs: Math.max(86_400_000, cadenceMs(source.every)),
|
|
177
|
+
};
|
|
178
|
+
if (addBriefItem) addBriefItem(input);
|
|
179
|
+
else ledger!.add(input);
|
|
180
|
+
}
|
|
131
181
|
}
|
|
132
182
|
|
|
133
183
|
function xmlText(value: string): string {
|
|
@@ -150,11 +200,13 @@ export function parseFeed(xml: string): RawIntakeItem[] {
|
|
|
150
200
|
}).filter((entry) => !!entry.url);
|
|
151
201
|
}
|
|
152
202
|
|
|
153
|
-
export async function runDue({ now = new Date(), seat, deps = {} }: { now?: Date; seat?: string; deps?: RunDueDeps } = {}): Promise<{ ran: Array<{ id: string; items: number; error?: string }> }> {
|
|
203
|
+
export async function runDue({ now = new Date(), seat, sourceId, deps = {} }: { now?: Date; seat?: string; sourceId?: string; deps?: RunDueDeps } = {}): Promise<{ ran: Array<{ id: string; items: number; error?: string }> }> {
|
|
154
204
|
const stateDir = deps.stateDir ?? effectiveInstanceRoot();
|
|
155
205
|
const selectedSeat = seat === undefined ? undefined : canonicalSeat(seat);
|
|
156
206
|
const ran: Array<{ id: string; items: number; error?: string }> = [];
|
|
157
|
-
for (const source of dueSources(now, stateDir).filter((source) =>
|
|
207
|
+
for (const source of dueSources(now, stateDir, sourceId).filter((source) =>
|
|
208
|
+
(selectedSeat === undefined || source.seat === selectedSeat)
|
|
209
|
+
&& (source.kind !== 'topic-search' || !!deps.projectTopicBriefing))) {
|
|
158
210
|
try {
|
|
159
211
|
let raws: RawIntakeItem[];
|
|
160
212
|
let githubSnapshots: { day: string; repo: string; stars: number }[] | undefined;
|
|
@@ -176,6 +228,9 @@ export async function runDue({ now = new Date(), seat, deps = {} }: { now?: Date
|
|
|
176
228
|
}))(source.spec);
|
|
177
229
|
raws = parseFeed(feed);
|
|
178
230
|
intakeSource = 'rss';
|
|
231
|
+
} else if (source.kind === 'topic-search') {
|
|
232
|
+
raws = await (deps.searchTopic ?? searchTopicWithResearchBridge)(source.spec);
|
|
233
|
+
intakeSource = 'topic-search';
|
|
179
234
|
} else {
|
|
180
235
|
const argv = commandArgv(source.spec);
|
|
181
236
|
const stdout = await (deps.runCommand ?? (async () => execFileSync(argv[0]!, argv.slice(1), { encoding: 'utf8', timeout: 600_000, maxBuffer: 16 * 1024 * 1024 })))(source.spec);
|
|
@@ -188,9 +243,24 @@ export async function runDue({ now = new Date(), seat, deps = {} }: { now?: Date
|
|
|
188
243
|
raws = parsed.raws;
|
|
189
244
|
intakeSource = 'command';
|
|
190
245
|
}
|
|
191
|
-
|
|
246
|
+
raws = raws.map((raw) => ({ ...raw, seat: source.seat,
|
|
247
|
+
...(source.kind === 'topic-search' && source.linearIssueId ? { linearIssueId: source.linearIssueId } : {}) }));
|
|
248
|
+
const items = (deps.ingest ?? ingestIntakeItems)(stateDir, intakeSource, raws, now.toISOString()).shaped;
|
|
249
|
+
if (source.kind === 'topic-search') await addTopicBriefItems(stateDir, source, raws, now.toISOString(), deps.addBriefItem);
|
|
250
|
+
await deps.onCollected?.(source, raws, now);
|
|
192
251
|
if (githubSnapshots) appendGithubStarSnapshots(stateDir, githubSnapshots);
|
|
193
|
-
|
|
252
|
+
if (source.kind === 'topic-search' && source.linearIssueId && deps.projectTopicBriefing) {
|
|
253
|
+
const { BriefItemsLedger } = await import('../briefing/brief-items.js');
|
|
254
|
+
const ledger = new BriefItemsLedger({ stateDir });
|
|
255
|
+
const pending = ledger.list().filter(item => item.source === `intake.topic-search:${source.id}`
|
|
256
|
+
&& item.linearIssueId?.toLowerCase() === source.linearIssueId!.toLowerCase() && item.sent_at === null);
|
|
257
|
+
if (pending.length) {
|
|
258
|
+
await deps.projectTopicBriefing(source, pending, stateDir);
|
|
259
|
+
// This dedicated issue card/comment is the delivery for these brief items.
|
|
260
|
+
ledger.markSent(pending.map(item => item.id), 'realtime');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// A projection failure must remain retryable; advance cadence only after delivery succeeds.
|
|
194
264
|
const current = readSources(stateDir);
|
|
195
265
|
const found = current.find((entry) => entry.id === source.id);
|
|
196
266
|
if (found) saveSources(stateDir, current.map((entry) => entry.id === source.id ? { ...entry, lastRunAt: now.toISOString() } : entry));
|
|
@@ -8,7 +8,7 @@ import { findTrack } from '../autopilot/mission-phase-track.js';
|
|
|
8
8
|
import { wasIntakeEventScheduled } from './route.js';
|
|
9
9
|
|
|
10
10
|
export const INTAKE_SOURCES = ['x', 'youtube', 'github', 'telegram-saved', 'telegram-bot', 'memo', 'pwa'] as const;
|
|
11
|
-
export type RegisteredIntakeSourceKind = 'rss' | 'command';
|
|
11
|
+
export type RegisteredIntakeSourceKind = 'rss' | 'command' | 'topic-search';
|
|
12
12
|
export type IntakeSource = typeof INTAKE_SOURCES[number];
|
|
13
13
|
export type IntakeKind = 'video' | 'repo' | 'post' | 'article' | 'note' | 'rss';
|
|
14
14
|
export type IntakePrivacy = 'public' | 'user-private';
|
|
@@ -21,6 +21,8 @@ export interface IntakeItem {
|
|
|
21
21
|
/** 같은 항목이 다른 입력원에서도 왔으면 여기 모인다 — «두 입력원에서 동시에 뜬 것»이 신호다. */
|
|
22
22
|
sources: (IntakeSource | RegisteredIntakeSourceKind)[];
|
|
23
23
|
seat?: string;
|
|
24
|
+
/** Parent Linear issue UUID, kept separate from its human-readable identifier. */
|
|
25
|
+
linearIssueId?: string;
|
|
24
26
|
url?: string;
|
|
25
27
|
kind: IntakeKind;
|
|
26
28
|
title?: string;
|
|
@@ -39,6 +41,7 @@ export interface IntakeItem {
|
|
|
39
41
|
/** 수집기가 내는 한 줄 — 모양 맞추기 전. */
|
|
40
42
|
export interface RawIntakeItem {
|
|
41
43
|
seat?: string;
|
|
44
|
+
linearIssueId?: string;
|
|
42
45
|
url?: string;
|
|
43
46
|
title?: string;
|
|
44
47
|
text?: string;
|
|
@@ -90,10 +93,12 @@ function normalizedSeat(seat: unknown): string | undefined {
|
|
|
90
93
|
return track.id;
|
|
91
94
|
}
|
|
92
95
|
|
|
93
|
-
export function intakeItemId(source: IntakeSource | RegisteredIntakeSourceKind,
|
|
96
|
+
export function intakeItemId(source: IntakeSource | RegisteredIntakeSourceKind,
|
|
97
|
+
raw: Pick<RawIntakeItem, 'url' | 'text' | 'linearIssueId'> & { seat?: string }): string {
|
|
94
98
|
const seat = normalizedSeat(raw.seat);
|
|
95
99
|
const url = raw.url ? canonicalUrl(raw.url) : undefined;
|
|
96
|
-
const
|
|
100
|
+
const itemKey = url ?? `${source}:${(raw.text ?? '').trim().slice(0, 200)}`;
|
|
101
|
+
const basis = raw.linearIssueId ? JSON.stringify(['linear-issue', raw.linearIssueId.toLowerCase(), itemKey]) : itemKey;
|
|
97
102
|
// Unassigned items retain their original IDs; assigned items have an independent lifecycle per seat.
|
|
98
103
|
return createHash('sha256').update(seat ? JSON.stringify([seat, basis]) : basis).digest('hex').slice(0, 16);
|
|
99
104
|
}
|
|
@@ -114,6 +119,9 @@ export function privacyFor(source: IntakeSource | RegisteredIntakeSourceKind): I
|
|
|
114
119
|
/** ① 모양 맞추기 — 수집기 한 줄 → IntakeItem. 비어 있으면(URL·본문 둘 다 없음) null. */
|
|
115
120
|
export function shapeIntakeItem(source: IntakeSource | RegisteredIntakeSourceKind, raw: RawIntakeItem, now: string): IntakeItem | null {
|
|
116
121
|
const seat = normalizedSeat(raw.seat);
|
|
122
|
+
if (raw.linearIssueId !== undefined && !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(raw.linearIssueId)) {
|
|
123
|
+
throw new Error('invalid Linear issue UUID');
|
|
124
|
+
}
|
|
117
125
|
const url = raw.url ? canonicalUrl(raw.url) : undefined;
|
|
118
126
|
const text = raw.text?.trim() || undefined;
|
|
119
127
|
if (!url && !text) return null;
|
|
@@ -121,10 +129,11 @@ export function shapeIntakeItem(source: IntakeSource | RegisteredIntakeSourceKin
|
|
|
121
129
|
const signals: Record<string, number> = {};
|
|
122
130
|
for (const [k, v] of Object.entries(raw.signals ?? {})) if (Number.isFinite(v)) signals[`${source}.${k}`] = v;
|
|
123
131
|
return {
|
|
124
|
-
id: intakeItemId(source, { url, text, seat }),
|
|
132
|
+
id: intakeItemId(source, { url, text, seat, linearIssueId: raw.linearIssueId }),
|
|
125
133
|
source,
|
|
126
134
|
sources: [source],
|
|
127
135
|
...(seat ? { seat } : {}),
|
|
136
|
+
...(raw.linearIssueId ? { linearIssueId: raw.linearIssueId } : {}),
|
|
128
137
|
...(url ? { url } : {}),
|
|
129
138
|
kind: raw.kind ?? kindFor(source, url),
|
|
130
139
|
...(raw.title?.trim() ? { title: raw.title.trim().slice(0, 300) } : {}),
|
|
@@ -191,6 +200,7 @@ export function ingestIntakeItems(instanceRoot: string, source: IntakeSource | R
|
|
|
191
200
|
signals: { ...prev.signals, ...shaped.signals },
|
|
192
201
|
title: prev.title ?? shaped.title,
|
|
193
202
|
text: prev.text ?? shaped.text,
|
|
203
|
+
linearIssueId: prev.linearIssueId ?? shaped.linearIssueId,
|
|
194
204
|
axis: shaped.axis ?? prev.axis,
|
|
195
205
|
judgement: shaped.judgement ?? prev.judgement,
|
|
196
206
|
// 한 번이라도 개인 입력원에서 왔으면 개인으로 남긴다(공개로 풀지 않는다).
|