@keystrokehq/cli 0.1.3 → 0.1.4
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/dist/alias-RTYYYW3D-CLFgrowj.mjs +98 -0
- package/dist/alias-RTYYYW3D-CLFgrowj.mjs.map +1 -0
- package/dist/awk2-LA3USKJP-BbsfXVlR.mjs +2737 -0
- package/dist/awk2-LA3USKJP-BbsfXVlR.mjs.map +1 -0
- package/dist/base64-C2AIWVNC-C0WIgu5V.mjs +123 -0
- package/dist/base64-C2AIWVNC-C0WIgu5V.mjs.map +1 -0
- package/dist/basename-UB3CIYNI-BgNN3bGm.mjs +53 -0
- package/dist/basename-UB3CIYNI-BgNN3bGm.mjs.map +1 -0
- package/dist/bash-YZ33HQZQ-N6YyKtUH.mjs +118 -0
- package/dist/bash-YZ33HQZQ-N6YyKtUH.mjs.map +1 -0
- package/dist/cat-TSFMZVYS-Dz3-oHsV.mjs +63 -0
- package/dist/cat-TSFMZVYS-Dz3-oHsV.mjs.map +1 -0
- package/dist/chmod-TFEPA42X-YF02QJUv.mjs +125 -0
- package/dist/chmod-TFEPA42X-YF02QJUv.mjs.map +1 -0
- package/dist/chunk-27JIFWUR-B6ZjjMMI.mjs +100 -0
- package/dist/chunk-27JIFWUR-B6ZjjMMI.mjs.map +1 -0
- package/dist/chunk-4I3HOE5Z-BixWWVkW.mjs +719 -0
- package/dist/chunk-4I3HOE5Z-BixWWVkW.mjs.map +1 -0
- package/dist/chunk-4RUAZWKT-D60fyWAB.mjs +22543 -0
- package/dist/chunk-4RUAZWKT-D60fyWAB.mjs.map +1 -0
- package/dist/chunk-4WKZNNJK-CiwxAWRf.mjs +69 -0
- package/dist/chunk-4WKZNNJK-CiwxAWRf.mjs.map +1 -0
- package/dist/chunk-5H5SCKJM-BvfXlL01.mjs +606 -0
- package/dist/chunk-5H5SCKJM-BvfXlL01.mjs.map +1 -0
- package/dist/chunk-AQ6FYS2X-CkVetjym.mjs +37 -0
- package/dist/chunk-AQ6FYS2X-CkVetjym.mjs.map +1 -0
- package/dist/chunk-BZUGFHVS-CPWRFwK8.mjs +34 -0
- package/dist/chunk-BZUGFHVS-CPWRFwK8.mjs.map +1 -0
- package/dist/chunk-CHFEPBH4-BUdgjFtD.mjs +594 -0
- package/dist/chunk-CHFEPBH4-BUdgjFtD.mjs.map +1 -0
- package/dist/chunk-DLL7UR66-BUYgzxnR.mjs +14 -0
- package/dist/chunk-DLL7UR66-BUYgzxnR.mjs.map +1 -0
- package/dist/chunk-DiodbrVj.mjs +27 -0
- package/dist/chunk-EBAPSGAO-Ctfslw2R.mjs +247 -0
- package/dist/chunk-EBAPSGAO-Ctfslw2R.mjs.map +1 -0
- package/dist/chunk-FOCWZZDE-BIntqBh2.mjs +19 -0
- package/dist/chunk-FOCWZZDE-BIntqBh2.mjs.map +1 -0
- package/dist/chunk-HBVMHTO5-CJyD-QZX.mjs +10 -0
- package/dist/chunk-HBVMHTO5-CJyD-QZX.mjs.map +1 -0
- package/dist/chunk-L2UW7DWF-B3tEHhPF.mjs +14 -0
- package/dist/chunk-L2UW7DWF-B3tEHhPF.mjs.map +1 -0
- package/dist/chunk-L64BMZUV-CyR7RKok.mjs +30 -0
- package/dist/chunk-L64BMZUV-CyR7RKok.mjs.map +1 -0
- package/dist/chunk-LEKBROJD-CJMrAyu9.mjs +3113 -0
- package/dist/chunk-LEKBROJD-CJMrAyu9.mjs.map +1 -0
- package/dist/chunk-NRSASXYY-CuWyREpD.mjs +41 -0
- package/dist/chunk-NRSASXYY-CuWyREpD.mjs.map +1 -0
- package/dist/chunk-QAYAQNCG-Bl0Kbd53.mjs +63 -0
- package/dist/chunk-QAYAQNCG-Bl0Kbd53.mjs.map +1 -0
- package/dist/chunk-QIQMJJZ4-BwKdslXs.mjs +93 -0
- package/dist/chunk-QIQMJJZ4-BwKdslXs.mjs.map +1 -0
- package/dist/chunk-SAI2SPQQ-CVRoDNs9.mjs +26 -0
- package/dist/chunk-SAI2SPQQ-CVRoDNs9.mjs.map +1 -0
- package/dist/chunk-SO6R3ZKN-tTw_RMDX.mjs +140 -0
- package/dist/chunk-SO6R3ZKN-tTw_RMDX.mjs.map +1 -0
- package/dist/chunk-STHBFACM-lyj-j2a-.mjs +8 -0
- package/dist/chunk-STHBFACM-lyj-j2a-.mjs.map +1 -0
- package/dist/chunk-SX2HC7SO-Cc4Hpis1.mjs +20 -0
- package/dist/chunk-SX2HC7SO-Cc4Hpis1.mjs.map +1 -0
- package/dist/chunk-TDD4NFYE-wsWW75MX.mjs +21 -0
- package/dist/chunk-TDD4NFYE-wsWW75MX.mjs.map +1 -0
- package/dist/chunk-TN7HHBQW-CSB_R-XD.mjs +1137 -0
- package/dist/chunk-TN7HHBQW-CSB_R-XD.mjs.map +1 -0
- package/dist/chunk-VPADYNBD-BKlA28GJ.mjs +122 -0
- package/dist/chunk-VPADYNBD-BKlA28GJ.mjs.map +1 -0
- package/dist/chunk-W5DWRFSU-lCyWk0ph.mjs +11 -0
- package/dist/chunk-W5DWRFSU-lCyWk0ph.mjs.map +1 -0
- package/dist/chunk-WNH3HOQA-BCZUOjCJ.mjs +34 -0
- package/dist/chunk-WNH3HOQA-BCZUOjCJ.mjs.map +1 -0
- package/dist/chunk-XRFHFXFP-BGxzVZgK.mjs +16 -0
- package/dist/chunk-XRFHFXFP-BGxzVZgK.mjs.map +1 -0
- package/dist/chunk-YCLFEX4T-COc1AThz.mjs +77 -0
- package/dist/chunk-YCLFEX4T-COc1AThz.mjs.map +1 -0
- package/dist/clear-HKGFEOF6-CekN2x-O.mjs +28 -0
- package/dist/clear-HKGFEOF6-CekN2x-O.mjs.map +1 -0
- package/dist/column-XT6UFXNQ-DHENV9D2.mjs +143 -0
- package/dist/column-XT6UFXNQ-DHENV9D2.mjs.map +1 -0
- package/dist/comm-VV2LDX2J-ppxDJFkY.mjs +87 -0
- package/dist/comm-VV2LDX2J-ppxDJFkY.mjs.map +1 -0
- package/dist/cp-BISAAS7A-CMWayU4n.mjs +106 -0
- package/dist/cp-BISAAS7A-CMWayU4n.mjs.map +1 -0
- package/dist/cut-OKARJCCV-Bt8b58eI.mjs +119 -0
- package/dist/cut-OKARJCCV-Bt8b58eI.mjs.map +1 -0
- package/dist/date-UUUPW43J-B7T5OTZZ.mjs +188 -0
- package/dist/date-UUUPW43J-B7T5OTZZ.mjs.map +1 -0
- package/dist/diff-MWJFIG7X-DhnPc_5r.mjs +755 -0
- package/dist/diff-MWJFIG7X-DhnPc_5r.mjs.map +1 -0
- package/dist/dirname-MPHRFUTI-Dkb3S4OX.mjs +43 -0
- package/dist/dirname-MPHRFUTI-Dkb3S4OX.mjs.map +1 -0
- package/dist/{dist-DjfxlOWX.mjs → dist-C47GdlWY.mjs} +18 -93
- package/dist/{dist-DjfxlOWX.mjs.map → dist-C47GdlWY.mjs.map} +1 -1
- package/dist/{dist-DWcRd4Se.mjs → dist-CJL2zYbP.mjs} +4 -71
- package/dist/dist-CJL2zYbP.mjs.map +1 -0
- package/dist/dist-Ch53z2P3.mjs +3 -0
- package/dist/dist-CwR72_PS.mjs +1887 -0
- package/dist/dist-CwR72_PS.mjs.map +1 -0
- package/dist/du-572XNP42-ClP4jXB1.mjs +176 -0
- package/dist/du-572XNP42-ClP4jXB1.mjs.map +1 -0
- package/dist/echo-NDWZZHPO-CCp_-MxA.mjs +137 -0
- package/dist/echo-NDWZZHPO-CCp_-MxA.mjs.map +1 -0
- package/dist/env-36M5BO7M-CsP_aiWr.mjs +119 -0
- package/dist/env-36M5BO7M-CsP_aiWr.mjs.map +1 -0
- package/dist/expand-JSPG6VOP-B-YUvYpu.mjs +145 -0
- package/dist/expand-JSPG6VOP-B-YUvYpu.mjs.map +1 -0
- package/dist/expr-5JAACS4X-1TBq84gG.mjs +153 -0
- package/dist/expr-5JAACS4X-1TBq84gG.mjs.map +1 -0
- package/dist/file-IPZJC3FQ-DcZNOWyY.mjs +4201 -0
- package/dist/file-IPZJC3FQ-DcZNOWyY.mjs.map +1 -0
- package/dist/find-INTH3OLC-6p47KeeT.mjs +1332 -0
- package/dist/find-INTH3OLC-6p47KeeT.mjs.map +1 -0
- package/dist/fold-4TQNYMSW-C54bHzLd.mjs +138 -0
- package/dist/fold-4TQNYMSW-C54bHzLd.mjs.map +1 -0
- package/dist/grep-V3LQVMRQ-D99Bq7Kj.mjs +335 -0
- package/dist/grep-V3LQVMRQ-D99Bq7Kj.mjs.map +1 -0
- package/dist/gzip-O5ASJAFY-CZDRROqP.mjs +592 -0
- package/dist/gzip-O5ASJAFY-CZDRROqP.mjs.map +1 -0
- package/dist/head-442HYESI-D96RMdki.mjs +36 -0
- package/dist/head-442HYESI-D96RMdki.mjs.map +1 -0
- package/dist/help-HZ6M2CKN--DK8mY2L.mjs +123 -0
- package/dist/help-HZ6M2CKN--DK8mY2L.mjs.map +1 -0
- package/dist/history-WYYKSLSZ-ACNQVupn.mjs +48 -0
- package/dist/history-WYYKSLSZ-ACNQVupn.mjs.map +1 -0
- package/dist/hostname-C4HQXXUP-CXVVFkUK.mjs +24 -0
- package/dist/hostname-C4HQXXUP-CXVVFkUK.mjs.map +1 -0
- package/dist/html-to-markdown-JW4MSQZO-DQOxFIvF.mjs +15890 -0
- package/dist/html-to-markdown-JW4MSQZO-DQOxFIvF.mjs.map +1 -0
- package/dist/index.mjs +9 -9
- package/dist/join-TBRGI3LQ-B8I9tkJ5.mjs +198 -0
- package/dist/join-TBRGI3LQ-B8I9tkJ5.mjs.map +1 -0
- package/dist/jq-4XLYLOS5-wFZYfsfJ.mjs +257 -0
- package/dist/jq-4XLYLOS5-wFZYfsfJ.mjs.map +1 -0
- package/dist/js-exec-N5KEZBH7-CgtG-I6s.mjs +333 -0
- package/dist/js-exec-N5KEZBH7-CgtG-I6s.mjs.map +1 -0
- package/dist/lib-D4GpdNNK.mjs +45 -0
- package/dist/lib-D4GpdNNK.mjs.map +1 -0
- package/dist/ln-4LGSXXGD-Dg0R9i5G.mjs +101 -0
- package/dist/ln-4LGSXXGD-Dg0R9i5G.mjs.map +1 -0
- package/dist/ls-ZJGQER7M-DLDSfI4x.mjs +1891 -0
- package/dist/ls-ZJGQER7M-DLDSfI4x.mjs.map +1 -0
- package/dist/lzma-CTMDi254.mjs +1135 -0
- package/dist/lzma-CTMDi254.mjs.map +1 -0
- package/dist/{maybe-auto-update-Ou7H6dXT.mjs → maybe-auto-update-B0kal2FM.mjs} +2 -2
- package/dist/{maybe-auto-update-Ou7H6dXT.mjs.map → maybe-auto-update-B0kal2FM.mjs.map} +1 -1
- package/dist/md5sum-SPU24VSG-DQc8sqXO.mjs +16 -0
- package/dist/md5sum-SPU24VSG-DQc8sqXO.mjs.map +1 -0
- package/dist/mkdir-MEPGZOB6-BjUKzhdL.mjs +58 -0
- package/dist/mkdir-MEPGZOB6-BjUKzhdL.mjs.map +1 -0
- package/dist/mv-W5BIQ646-CdSIyY-U.mjs +93 -0
- package/dist/mv-W5BIQ646-CdSIyY-U.mjs.map +1 -0
- package/dist/nl-WSDW7I4O-DmtCnyKU.mjs +208 -0
- package/dist/nl-WSDW7I4O-DmtCnyKU.mjs.map +1 -0
- package/dist/od-WOKFDJTP-DZ2nxQNJ.mjs +73 -0
- package/dist/od-WOKFDJTP-DZ2nxQNJ.mjs.map +1 -0
- package/dist/paste-7JC6S4DX-CtmM5Qy8.mjs +113 -0
- package/dist/paste-7JC6S4DX-CtmM5Qy8.mjs.map +1 -0
- package/dist/printf-TWGXF445-B7cTysaa.mjs +880 -0
- package/dist/printf-TWGXF445-B7cTysaa.mjs.map +1 -0
- package/dist/pwd-WE6EN5AV-CO8o2WQS.mjs +34 -0
- package/dist/pwd-WE6EN5AV-CO8o2WQS.mjs.map +1 -0
- package/dist/python3-POMOR4OA-CKy80mpF.mjs +299 -0
- package/dist/python3-POMOR4OA-CKy80mpF.mjs.map +1 -0
- package/dist/readlink-OPJF4DL5-Rc1Mz_Xx.mjs +76 -0
- package/dist/readlink-OPJF4DL5-Rc1Mz_Xx.mjs.map +1 -0
- package/dist/rev-5EHFX4EJ-3dd9vwHW.mjs +66 -0
- package/dist/rev-5EHFX4EJ-3dd9vwHW.mjs.map +1 -0
- package/dist/rg-S4FXYXWB-BbXVo6JX.mjs +1539 -0
- package/dist/rg-S4FXYXWB-BbXVo6JX.mjs.map +1 -0
- package/dist/rm-SSGETQVQ-Ch53Rmrr.mjs +81 -0
- package/dist/rm-SSGETQVQ-Ch53Rmrr.mjs.map +1 -0
- package/dist/rmdir-OC4ZLPYA-D3QCHlIB.mjs +132 -0
- package/dist/rmdir-OC4ZLPYA-D3QCHlIB.mjs.map +1 -0
- package/dist/sed-S5UIK574-DE1KeTk3.mjs +1722 -0
- package/dist/sed-S5UIK574-DE1KeTk3.mjs.map +1 -0
- package/dist/seq-M5EC7Q57-BHfGjQvK.mjs +85 -0
- package/dist/seq-M5EC7Q57-BHfGjQvK.mjs.map +1 -0
- package/dist/sha1sum-2PTOAFR6-DNjSNcYK.mjs +16 -0
- package/dist/sha1sum-2PTOAFR6-DNjSNcYK.mjs.map +1 -0
- package/dist/sha256sum-NS7D3IXX-BMaCKkT5.mjs +16 -0
- package/dist/sha256sum-NS7D3IXX-BMaCKkT5.mjs.map +1 -0
- package/dist/sleep-X22JJINO-Do5hEQQW.mjs +67 -0
- package/dist/sleep-X22JJINO-Do5hEQQW.mjs.map +1 -0
- package/dist/sort-SW2YEO5B-B7j1zw8k.mjs +320 -0
- package/dist/sort-SW2YEO5B-B7j1zw8k.mjs.map +1 -0
- package/dist/split-4KKZZXXE-h8GD4HP4.mjs +248 -0
- package/dist/split-4KKZZXXE-h8GD4HP4.mjs.map +1 -0
- package/dist/sqlite3-CGOEFJAO-DvzzghDg.mjs +2879 -0
- package/dist/sqlite3-CGOEFJAO-DvzzghDg.mjs.map +1 -0
- package/dist/stat-CD34IZ4P-B5ZOJh4J.mjs +65 -0
- package/dist/stat-CD34IZ4P-B5ZOJh4J.mjs.map +1 -0
- package/dist/strings-6WDHLGMX-DdiEdoL-.mjs +179 -0
- package/dist/strings-6WDHLGMX-DdiEdoL-.mjs.map +1 -0
- package/dist/tac-2STMMJYW-DPyeWM9R.mjs +53 -0
- package/dist/tac-2STMMJYW-DPyeWM9R.mjs.map +1 -0
- package/dist/tail-R4PCA2C4-CUfroNeu.mjs +37 -0
- package/dist/tail-R4PCA2C4-CUfroNeu.mjs.map +1 -0
- package/dist/tar-STHHZTZ6-DRf60e-G.mjs +2838 -0
- package/dist/tar-STHHZTZ6-DRf60e-G.mjs.map +1 -0
- package/dist/tee-YUZ2FKCJ-po_dfyc_.mjs +46 -0
- package/dist/tee-YUZ2FKCJ-po_dfyc_.mjs.map +1 -0
- package/dist/time-D4LNBSWX-DVWhAldK.mjs +112 -0
- package/dist/time-D4LNBSWX-DVWhAldK.mjs.map +1 -0
- package/dist/timeout-YDCRSLPQ-B_yntmXU.mjs +113 -0
- package/dist/timeout-YDCRSLPQ-B_yntmXU.mjs.map +1 -0
- package/dist/touch-UA33VN3N-oW1SBT1r.mjs +104 -0
- package/dist/touch-UA33VN3N-oW1SBT1r.mjs.map +1 -0
- package/dist/tr-36LHWFRQ-CTq3z6wq.mjs +167 -0
- package/dist/tr-36LHWFRQ-CTq3z6wq.mjs.map +1 -0
- package/dist/tree-YLD52CNT-CIozNsLQ.mjs +186 -0
- package/dist/tree-YLD52CNT-CIozNsLQ.mjs.map +1 -0
- package/dist/true-FHQXJXBE-DsJOznSp.mjs +31 -0
- package/dist/true-FHQXJXBE-DsJOznSp.mjs.map +1 -0
- package/dist/unexpand-CADSA4VO-Cq9DTcUg.mjs +155 -0
- package/dist/unexpand-CADSA4VO-Cq9DTcUg.mjs.map +1 -0
- package/dist/uniq-XSIZR6PB-D5lt-IXF.mjs +92 -0
- package/dist/uniq-XSIZR6PB-D5lt-IXF.mjs.map +1 -0
- package/dist/{version-n-JpPeUF.mjs → version-Dxl3y5p6.mjs} +2 -2
- package/dist/{version-n-JpPeUF.mjs.map → version-Dxl3y5p6.mjs.map} +1 -1
- package/dist/wc-LF7NU4LA-BFPabrwD.mjs +111 -0
- package/dist/wc-LF7NU4LA-BFPabrwD.mjs.map +1 -0
- package/dist/which-XEM24D5D-2LvlkpUo.mjs +62 -0
- package/dist/which-XEM24D5D-2LvlkpUo.mjs.map +1 -0
- package/dist/whoami-XMTX52VE-24Kwqrk6.mjs +24 -0
- package/dist/whoami-XMTX52VE-24Kwqrk6.mjs.map +1 -0
- package/dist/xan-Y6WF3IRG-DjKO96Pj.mjs +2832 -0
- package/dist/xan-Y6WF3IRG-DjKO96Pj.mjs.map +1 -0
- package/dist/xan-view-HDVKHFC2-DhDNVE_V.mjs +12 -0
- package/dist/xan-view-HDVKHFC2-DhDNVE_V.mjs.map +1 -0
- package/dist/xargs-MGZPH7AX-D2bIgrdg.mjs +112 -0
- package/dist/xargs-MGZPH7AX-D2bIgrdg.mjs.map +1 -0
- package/dist/yq-4QJW3EQG-XhB3aACo.mjs +8610 -0
- package/dist/yq-4QJW3EQG-XhB3aACo.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/dist-DWcRd4Se.mjs.map +0 -1
- package/dist/dist-DitNZUHA.mjs +0 -3
- package/dist/dist-vwoMCz6d.mjs +0 -775
- package/dist/dist-vwoMCz6d.mjs.map +0 -1
package/dist/dist-vwoMCz6d.mjs
DELETED
|
@@ -1,775 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { $t as normalizeCredentialList, an as custom, cn as object, dn as toJSONSchema, ht as PromptResponseSchema, in as array, ln as string, mt as PromptInputSchema, nn as ZodType, on as discriminatedUnion, rn as _function, sn as literal, un as union, vt as ROUTE_MANIFEST_REL_PATH } from "./dist-DjfxlOWX.mjs";
|
|
3
|
-
import { dirname, join, relative, sep } from "node:path";
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { readdir, stat } from "node:fs/promises";
|
|
7
|
-
//#region ../../packages/manifest/dist/discovery-CWjr_liZ.mjs
|
|
8
|
-
const SOURCE_EXT = /\.(ts|mts|mjs|js)$/;
|
|
9
|
-
const DECLARATION_FILE$1 = /\.d\.(ts|mts|cts)$/;
|
|
10
|
-
function entryIdFromFile(rootDir, filePath, options) {
|
|
11
|
-
if (DECLARATION_FILE$1.test(filePath)) return null;
|
|
12
|
-
const baseName = filePath.split(sep).at(-1) ?? "";
|
|
13
|
-
if (/\.(int\.)?test\.(ts|mts)$/.test(baseName)) return null;
|
|
14
|
-
const segments = relative(rootDir, filePath).replace(SOURCE_EXT, "").split(sep).filter((segment) => segment.length > 0);
|
|
15
|
-
if (segments.length === 1) return segments[0] ?? null;
|
|
16
|
-
const last = segments.at(-1);
|
|
17
|
-
const entryNames = new Set([options.nestedEntry]);
|
|
18
|
-
if (options.allowIndex !== false) entryNames.add("index");
|
|
19
|
-
if (!last || !entryNames.has(last)) return null;
|
|
20
|
-
const id = segments.slice(0, -1).join("/");
|
|
21
|
-
return id.length > 0 ? id : null;
|
|
22
|
-
}
|
|
23
|
-
const SOURCE_FILE = /\.(ts|mts|mjs|js)$/;
|
|
24
|
-
const TEST_FILE = /\.(int\.)?test\.(ts|mts)$/;
|
|
25
|
-
const DECLARATION_FILE = /\.d\.(ts|mts|cts)$/;
|
|
26
|
-
const JUNK_FILE = /^\._|\.DS_Store$/;
|
|
27
|
-
async function walkTypeScriptFiles(dir) {
|
|
28
|
-
let names;
|
|
29
|
-
try {
|
|
30
|
-
names = await readdir(dir);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (error.code === "ENOENT") return [];
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
const files = [];
|
|
36
|
-
for (const name of names) {
|
|
37
|
-
const path = join(dir, name);
|
|
38
|
-
if ((await stat(path)).isDirectory()) files.push(...await walkTypeScriptFiles(path));
|
|
39
|
-
else if (!JUNK_FILE.test(name) && SOURCE_FILE.test(name) && !DECLARATION_FILE.test(name) && !TEST_FILE.test(name)) files.push(path);
|
|
40
|
-
}
|
|
41
|
-
return files;
|
|
42
|
-
}
|
|
43
|
-
async function discoverEntries(rootDir, options) {
|
|
44
|
-
const files = await walkTypeScriptFiles(rootDir);
|
|
45
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
46
|
-
for (const filePath of files) {
|
|
47
|
-
const id = entryIdFromFile(rootDir, filePath, options);
|
|
48
|
-
if (!id) continue;
|
|
49
|
-
const key = options.formatKey(id);
|
|
50
|
-
const moduleFile = relative(rootDir, filePath);
|
|
51
|
-
const existing = byKey.get(key);
|
|
52
|
-
if (existing) throw new Error(`Duplicate ${options.duplicateLabel} ${key}: ${existing.filePath} and ${filePath}`);
|
|
53
|
-
byKey.set(key, {
|
|
54
|
-
key,
|
|
55
|
-
filePath,
|
|
56
|
-
moduleFile
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
return [...byKey.values()];
|
|
60
|
-
}
|
|
61
|
-
async function discoverModuleFileEntries(rootDir, options) {
|
|
62
|
-
return (await discoverEntries(rootDir, {
|
|
63
|
-
nestedEntry: options.nestedEntry,
|
|
64
|
-
formatKey: (id) => id,
|
|
65
|
-
duplicateLabel: options.duplicateLabel
|
|
66
|
-
})).filter((entry) => options.shouldDiscoverFile?.(entry.filePath) ?? true).map(({ filePath, moduleFile }) => ({
|
|
67
|
-
filePath,
|
|
68
|
-
moduleFile
|
|
69
|
-
}));
|
|
70
|
-
}
|
|
71
|
-
const HEADER_BYTES = 2048;
|
|
72
|
-
const DIRECTIVE_RE = /@keystroke\s+ignore(?::([a-z]+))?/;
|
|
73
|
-
/** Parse `@keystroke ignore` directives from a file header snippet. */
|
|
74
|
-
function parseKeystrokeIgnoreDirective(header) {
|
|
75
|
-
for (const line of header.slice(0, HEADER_BYTES).split("\n")) {
|
|
76
|
-
const trimmed = line.trim();
|
|
77
|
-
if (trimmed.length === 0) continue;
|
|
78
|
-
if (!isCommentLine(trimmed)) break;
|
|
79
|
-
const match = DIRECTIVE_RE.exec(trimmed);
|
|
80
|
-
if (!match) continue;
|
|
81
|
-
const scope = match[1];
|
|
82
|
-
if (!scope) return "ignore";
|
|
83
|
-
if (scope === "deploy") return "ignore:deploy";
|
|
84
|
-
throw new Error(`Unknown @keystroke ignore target "${scope}" in directive "@keystroke ignore:${scope}"`);
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
/** Read `@keystroke ignore` directives from the top of a module file. */
|
|
89
|
-
function readKeystrokeIgnoreDirective(filePath) {
|
|
90
|
-
return parseKeystrokeIgnoreDirective(readFileSync(filePath, "utf8").slice(0, HEADER_BYTES));
|
|
91
|
-
}
|
|
92
|
-
/** Whether a discovered module file should be skipped for the given build phase. */
|
|
93
|
-
function shouldSkipKeystrokeModuleFile(directive, phase) {
|
|
94
|
-
if (!directive) return false;
|
|
95
|
-
if (directive === "ignore") return true;
|
|
96
|
-
return phase === "deploy";
|
|
97
|
-
}
|
|
98
|
-
function isCommentLine(line) {
|
|
99
|
-
return line.startsWith("//") || line.startsWith("/*") || line.startsWith("*");
|
|
100
|
-
}
|
|
101
|
-
//#endregion
|
|
102
|
-
//#region ../../packages/manifest/dist/index.mjs
|
|
103
|
-
function isManifestAgent(value) {
|
|
104
|
-
if (typeof value !== "object" || value === null) return false;
|
|
105
|
-
const agent = value;
|
|
106
|
-
return typeof agent.slug === "string" && agent.slug.trim().length > 0 && typeof agent.buildRuntime === "function" && typeof agent.model === "string" && typeof agent.systemPrompt === "string";
|
|
107
|
-
}
|
|
108
|
-
function validateManifestAgent(value, filePath) {
|
|
109
|
-
if (!isManifestAgent(value)) throw new Error(`${filePath} must default-export defineAgent(...)`);
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
function normalizeWebhookEndpoint(endpoint) {
|
|
113
|
-
return endpoint.replace(/^\/+|\/+$/g, "").replace(/^triggers\/?/, "");
|
|
114
|
-
}
|
|
115
|
-
function agentRouteFromKey(key) {
|
|
116
|
-
return `/agents/${key}`;
|
|
117
|
-
}
|
|
118
|
-
function agentSessionsListPath(route) {
|
|
119
|
-
return `${route}/sessions`;
|
|
120
|
-
}
|
|
121
|
-
function agentSessionDetailPath(route) {
|
|
122
|
-
return `${route}/sessions/:sessionId`;
|
|
123
|
-
}
|
|
124
|
-
function workflowRouteFromKey(key) {
|
|
125
|
-
return `/workflows/${key}`;
|
|
126
|
-
}
|
|
127
|
-
function workflowRunsListPath(route) {
|
|
128
|
-
return `${route}/runs`;
|
|
129
|
-
}
|
|
130
|
-
function workflowRunDetailPath(route) {
|
|
131
|
-
return `${route}/runs/:runId`;
|
|
132
|
-
}
|
|
133
|
-
function triggerRunsListPath(attachmentKey) {
|
|
134
|
-
return `/triggers/${attachmentKey}/runs`;
|
|
135
|
-
}
|
|
136
|
-
function triggerRunDetailPath(attachmentKey) {
|
|
137
|
-
return `/triggers/${attachmentKey}/runs/:runId`;
|
|
138
|
-
}
|
|
139
|
-
function pollRouteFromKey(attachmentKey) {
|
|
140
|
-
return `/triggers/${attachmentKey}/poll`;
|
|
141
|
-
}
|
|
142
|
-
function pollGroupRouteFromId(pollId) {
|
|
143
|
-
return `/triggers/polls/${pollId}/run`;
|
|
144
|
-
}
|
|
145
|
-
function webhookRouteFromEndpoint(endpoint) {
|
|
146
|
-
const normalized = normalizeWebhookEndpoint(endpoint);
|
|
147
|
-
if (!normalized) throw new Error("Webhook endpoint must not be empty");
|
|
148
|
-
return `/triggers/${normalized}`;
|
|
149
|
-
}
|
|
150
|
-
async function discoverAgentEntries(agentsDir, options) {
|
|
151
|
-
const files = await discoverModuleFileEntries(agentsDir, {
|
|
152
|
-
nestedEntry: "agent",
|
|
153
|
-
duplicateLabel: "agent module file"
|
|
154
|
-
});
|
|
155
|
-
const entries = [];
|
|
156
|
-
for (const { filePath, moduleFile } of files) {
|
|
157
|
-
const agent = await importAgentDefinition(filePath, options);
|
|
158
|
-
entries.push({
|
|
159
|
-
key: agent.slug,
|
|
160
|
-
route: agentRouteFromKey(agent.slug),
|
|
161
|
-
filePath,
|
|
162
|
-
moduleFile
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
return entries;
|
|
166
|
-
}
|
|
167
|
-
async function importAgentDefinition(filePath, options) {
|
|
168
|
-
const href = pathToFileURL(filePath).href;
|
|
169
|
-
return validateManifestAgent((await (options?.reload ? import(`${href}?keystroke=${Date.now()}`) : import(href))).default, filePath);
|
|
170
|
-
}
|
|
171
|
-
const ACTION = Symbol.for("keystroke.action");
|
|
172
|
-
function isManifestAction(value) {
|
|
173
|
-
if (typeof value !== "object" || value === null) return false;
|
|
174
|
-
return ACTION in value && value[ACTION] === true;
|
|
175
|
-
}
|
|
176
|
-
function getManifestActionCredentialRequirements(action) {
|
|
177
|
-
return Array.isArray(action.credentials) ? action.credentials : void 0;
|
|
178
|
-
}
|
|
179
|
-
function countAgentCredentials(agent) {
|
|
180
|
-
const keys = /* @__PURE__ */ new Set();
|
|
181
|
-
for (const tool of agent.tools ?? []) {
|
|
182
|
-
const record = tool;
|
|
183
|
-
const requirements = isManifestAction(tool) ? getManifestActionCredentialRequirements(tool) : "credentials" in record && Array.isArray(record.credentials) ? record.credentials : void 0;
|
|
184
|
-
if (!requirements?.length) continue;
|
|
185
|
-
for (const requirement of normalizeCredentialList(requirements)) keys.add(requirement.key);
|
|
186
|
-
}
|
|
187
|
-
return keys.size;
|
|
188
|
-
}
|
|
189
|
-
const SKIP_DIRS = new Set([".git", "node_modules"]);
|
|
190
|
-
function toPosix$1(path) {
|
|
191
|
-
return path.split(sep).join("/");
|
|
192
|
-
}
|
|
193
|
-
function parseSkillFrontmatter(raw) {
|
|
194
|
-
const match = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
195
|
-
if (!match) return {};
|
|
196
|
-
const out = {};
|
|
197
|
-
for (const line of match[1]?.split("\n") ?? []) {
|
|
198
|
-
const trimmed = line.trim();
|
|
199
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
200
|
-
const colon = trimmed.indexOf(":");
|
|
201
|
-
if (colon < 0) continue;
|
|
202
|
-
const key = trimmed.slice(0, colon).trim();
|
|
203
|
-
let value = trimmed.slice(colon + 1).trim();
|
|
204
|
-
if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
|
|
205
|
-
if (key === "name") out.name = value;
|
|
206
|
-
else if (key === "description") out.description = value;
|
|
207
|
-
}
|
|
208
|
-
return out;
|
|
209
|
-
}
|
|
210
|
-
function walkSkillFiles(root, dir, out) {
|
|
211
|
-
for (const name of readdirSync(dir).sort()) {
|
|
212
|
-
const absolute = join(dir, name);
|
|
213
|
-
const stats = statSync(absolute);
|
|
214
|
-
if (stats.isDirectory()) {
|
|
215
|
-
if (SKIP_DIRS.has(name)) continue;
|
|
216
|
-
walkSkillFiles(root, absolute, out);
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (!stats.isFile() || name !== "SKILL.md") continue;
|
|
220
|
-
const moduleFile = toPosix$1(relative(root, absolute));
|
|
221
|
-
const slug = toPosix$1(relative(join(root, "src", "skills"), absolute)).replace(/\/?SKILL\.md$/, "");
|
|
222
|
-
if (!slug) continue;
|
|
223
|
-
const frontmatter = parseSkillFrontmatter(readFileSync(absolute, "utf8"));
|
|
224
|
-
out.push({
|
|
225
|
-
slug,
|
|
226
|
-
name: frontmatter.name,
|
|
227
|
-
description: frontmatter.description,
|
|
228
|
-
moduleFile
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
/** Discover skill metadata from src/skills SKILL.md files for the route manifest. */
|
|
233
|
-
function discoverSkillManifestEntries(projectRoot) {
|
|
234
|
-
const skillsDir = join(projectRoot, "src", "skills");
|
|
235
|
-
if (!statSync(skillsDir, { throwIfNoEntry: false })?.isDirectory()) return [];
|
|
236
|
-
const entries = [];
|
|
237
|
-
walkSkillFiles(projectRoot, skillsDir, entries);
|
|
238
|
-
return entries;
|
|
239
|
-
}
|
|
240
|
-
function schemaToJson(schema) {
|
|
241
|
-
return toJSONSchema(schema, { target: "openapi-3.0" });
|
|
242
|
-
}
|
|
243
|
-
function collectIntegrationKeys(integrations) {
|
|
244
|
-
return integrations.map((integration) => integration.key);
|
|
245
|
-
}
|
|
246
|
-
function serializeRouteManifest(manifest) {
|
|
247
|
-
return manifest.map((entry) => {
|
|
248
|
-
switch (entry.kind) {
|
|
249
|
-
case "health": return entry;
|
|
250
|
-
case "agent": return {
|
|
251
|
-
kind: entry.kind,
|
|
252
|
-
method: entry.method,
|
|
253
|
-
path: entry.path,
|
|
254
|
-
agentSlug: entry.agentSlug,
|
|
255
|
-
moduleFile: entry.moduleFile,
|
|
256
|
-
name: entry.name,
|
|
257
|
-
description: entry.description,
|
|
258
|
-
model: entry.model,
|
|
259
|
-
systemPrompt: entry.systemPrompt,
|
|
260
|
-
toolCount: entry.toolCount,
|
|
261
|
-
credentialCount: entry.credentialCount,
|
|
262
|
-
requestSchema: schemaToJson(entry.request),
|
|
263
|
-
responseSchema: schemaToJson(entry.response)
|
|
264
|
-
};
|
|
265
|
-
case "workflow": return {
|
|
266
|
-
kind: entry.kind,
|
|
267
|
-
method: entry.method,
|
|
268
|
-
path: entry.path,
|
|
269
|
-
workflowSlug: entry.workflowSlug,
|
|
270
|
-
workflowName: entry.workflowName,
|
|
271
|
-
description: entry.description,
|
|
272
|
-
subscribable: entry.subscribable,
|
|
273
|
-
moduleFile: entry.moduleFile,
|
|
274
|
-
requestSchema: schemaToJson(entry.request),
|
|
275
|
-
responseSchema: schemaToJson(entry.response)
|
|
276
|
-
};
|
|
277
|
-
case "trigger-webhook": return {
|
|
278
|
-
kind: entry.kind,
|
|
279
|
-
method: entry.method,
|
|
280
|
-
path: entry.path,
|
|
281
|
-
attachmentIds: entry.attachmentIds,
|
|
282
|
-
moduleFile: entry.moduleFile,
|
|
283
|
-
requestSchema: schemaToJson(entry.request),
|
|
284
|
-
attachmentSchemas: Object.fromEntries(Object.entries(entry.attachmentSchemas).map(([attachmentKey, schemas]) => [attachmentKey, {
|
|
285
|
-
requestSchema: schemaToJson(schemas.request),
|
|
286
|
-
...schemas.filter ? { filterSchema: schemaToJson(schemas.filter) } : {}
|
|
287
|
-
}])),
|
|
288
|
-
responseSchema: schemaToJson(entry.response)
|
|
289
|
-
};
|
|
290
|
-
case "trigger-poll": return {
|
|
291
|
-
kind: entry.kind,
|
|
292
|
-
method: entry.method,
|
|
293
|
-
path: entry.path,
|
|
294
|
-
attachmentId: entry.attachmentId,
|
|
295
|
-
moduleFile: entry.moduleFile,
|
|
296
|
-
schedule: entry.schedule,
|
|
297
|
-
responseSchema: schemaToJson(entry.response)
|
|
298
|
-
};
|
|
299
|
-
case "trigger-poll-group": return {
|
|
300
|
-
kind: entry.kind,
|
|
301
|
-
method: entry.method,
|
|
302
|
-
path: entry.path,
|
|
303
|
-
pollId: entry.pollId,
|
|
304
|
-
attachmentIds: entry.attachmentIds,
|
|
305
|
-
moduleFile: entry.moduleFile,
|
|
306
|
-
schedule: entry.schedule,
|
|
307
|
-
responseSchema: schemaToJson(entry.response)
|
|
308
|
-
};
|
|
309
|
-
case "plugin": return {
|
|
310
|
-
kind: entry.kind,
|
|
311
|
-
method: entry.method,
|
|
312
|
-
path: entry.path,
|
|
313
|
-
plugin: entry.plugin
|
|
314
|
-
};
|
|
315
|
-
default: return entry;
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
function toStoredRouteManifest(manifest, options) {
|
|
320
|
-
return {
|
|
321
|
-
version: 1,
|
|
322
|
-
entries: serializeRouteManifest(manifest),
|
|
323
|
-
skills: options?.skills ?? [],
|
|
324
|
-
integrations: options?.integrations
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
function buildStoredRouteManifestFromContext(ctx) {
|
|
328
|
-
const integrations = ctx.options?.integrations ?? ctx.options?.plugins?.map((plugin) => ({
|
|
329
|
-
key: plugin.name,
|
|
330
|
-
mount: plugin.register
|
|
331
|
-
})) ?? [];
|
|
332
|
-
return toStoredRouteManifest(ctx.manifest, {
|
|
333
|
-
integrations: collectIntegrationKeys(integrations),
|
|
334
|
-
skills: ctx.skills ?? (ctx.projectRoot ? discoverSkillManifestEntries(ctx.projectRoot) : void 0) ?? []
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function persistStoredRouteManifest(projectRoot, manifest) {
|
|
338
|
-
const path = join(projectRoot, ROUTE_MANIFEST_REL_PATH);
|
|
339
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
340
|
-
writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
341
|
-
}
|
|
342
|
-
const WORKFLOW = Symbol.for("keystroke.workflow");
|
|
343
|
-
function isManifestWorkflow(value) {
|
|
344
|
-
if (typeof value !== "object" || value === null) return false;
|
|
345
|
-
if (!(WORKFLOW in value) || value[WORKFLOW] !== true) return false;
|
|
346
|
-
const workflow = value;
|
|
347
|
-
return typeof workflow.slug === "string" && workflow.slug.trim().length > 0 && workflow.input instanceof Object && "safeParse" in workflow.input && workflow.output instanceof Object && "safeParse" in workflow.output;
|
|
348
|
-
}
|
|
349
|
-
function validateManifestWorkflow(value, filePath) {
|
|
350
|
-
if (!isManifestWorkflow(value)) throw new Error(`${filePath} must default-export defineWorkflow(...)`);
|
|
351
|
-
return value;
|
|
352
|
-
}
|
|
353
|
-
const TRIGGER_ATTACHMENT = Symbol.for("keystroke.triggerAttachment");
|
|
354
|
-
const zodSchema = custom((value) => value instanceof ZodType, "must be a Zod schema");
|
|
355
|
-
const cronScheduleSchema = string().trim().min(1, "cron schedule must be a non-empty string");
|
|
356
|
-
const workflowSchema = custom((value) => isManifestWorkflow(value), "must be defineWorkflow(...)");
|
|
357
|
-
const agentSchema = custom((value) => typeof value === "object" && value !== null && typeof value.slug === "string" && value.slug.trim().length > 0 && typeof value.prompt === "function", "must be defineAgent(...)");
|
|
358
|
-
const promptSchema = union([string(), _function()]);
|
|
359
|
-
const baseSourceShape = {
|
|
360
|
-
key: string().trim().min(1),
|
|
361
|
-
attach: _function()
|
|
362
|
-
};
|
|
363
|
-
const triggerSourceSchema = discriminatedUnion("kind", [
|
|
364
|
-
object({
|
|
365
|
-
kind: literal("webhook"),
|
|
366
|
-
...baseSourceShape,
|
|
367
|
-
endpoint: string().min(1),
|
|
368
|
-
request: zodSchema,
|
|
369
|
-
filter: zodSchema.optional(),
|
|
370
|
-
passes: _function()
|
|
371
|
-
}),
|
|
372
|
-
object({
|
|
373
|
-
kind: literal("cron"),
|
|
374
|
-
...baseSourceShape,
|
|
375
|
-
schedule: cronScheduleSchema
|
|
376
|
-
}),
|
|
377
|
-
object({
|
|
378
|
-
kind: literal("poll"),
|
|
379
|
-
...baseSourceShape,
|
|
380
|
-
id: string().optional(),
|
|
381
|
-
schedule: cronScheduleSchema,
|
|
382
|
-
run: _function(),
|
|
383
|
-
filters: array(_function()),
|
|
384
|
-
passes: _function()
|
|
385
|
-
})
|
|
386
|
-
]);
|
|
387
|
-
const triggerAttachmentCoreSchema = discriminatedUnion("target", [object({
|
|
388
|
-
key: string().trim().min(1),
|
|
389
|
-
source: triggerSourceSchema,
|
|
390
|
-
target: literal("workflow"),
|
|
391
|
-
workflow: workflowSchema,
|
|
392
|
-
transform: _function().optional()
|
|
393
|
-
}), object({
|
|
394
|
-
key: string().trim().min(1),
|
|
395
|
-
source: triggerSourceSchema,
|
|
396
|
-
target: literal("agent"),
|
|
397
|
-
agent: agentSchema,
|
|
398
|
-
prompt: promptSchema
|
|
399
|
-
})]);
|
|
400
|
-
function isManifestTriggerAttachment(value) {
|
|
401
|
-
if (typeof value !== "object" || value === null) return false;
|
|
402
|
-
if (!(TRIGGER_ATTACHMENT in value) || value[TRIGGER_ATTACHMENT] !== true) return false;
|
|
403
|
-
return triggerAttachmentCoreSchema.safeParse(value).success;
|
|
404
|
-
}
|
|
405
|
-
function validateManifestTriggerAttachment(value, filePath) {
|
|
406
|
-
if (!isManifestTriggerAttachment(value)) throw new Error(`${filePath} must default-export a trigger attachment from .attach({ workflow }) or .attach({ agent, prompt })`);
|
|
407
|
-
return value;
|
|
408
|
-
}
|
|
409
|
-
function shouldDiscoverTriggerFile(triggersDir, filePath) {
|
|
410
|
-
return !relative(triggersDir, filePath).split(sep).includes("sources");
|
|
411
|
-
}
|
|
412
|
-
async function discoverTriggerAttachments(triggersDir, options) {
|
|
413
|
-
const files = await discoverModuleFileEntries(triggersDir, {
|
|
414
|
-
nestedEntry: "trigger",
|
|
415
|
-
duplicateLabel: "trigger module file",
|
|
416
|
-
shouldDiscoverFile: (filePath) => shouldDiscoverTriggerFile(triggersDir, filePath)
|
|
417
|
-
});
|
|
418
|
-
const attachments = [];
|
|
419
|
-
for (const { filePath, moduleFile } of files) {
|
|
420
|
-
const attachment = await importTriggerAttachment(filePath, options);
|
|
421
|
-
attachments.push({
|
|
422
|
-
key: attachment.key,
|
|
423
|
-
filePath,
|
|
424
|
-
moduleFile,
|
|
425
|
-
attachment
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
return attachments;
|
|
429
|
-
}
|
|
430
|
-
function validateImportedTriggerAttachment(def, filePath) {
|
|
431
|
-
return validateManifestTriggerAttachment(def, filePath);
|
|
432
|
-
}
|
|
433
|
-
async function importTriggerAttachment(filePath, options) {
|
|
434
|
-
const href = pathToFileURL(filePath).href;
|
|
435
|
-
return validateImportedTriggerAttachment((await (options?.reload ? import(`${href}?keystroke=${Date.now()}`) : import(href))).default, filePath);
|
|
436
|
-
}
|
|
437
|
-
function pollGroupId(discovered) {
|
|
438
|
-
const source = discovered.attachment.source;
|
|
439
|
-
if (source.kind !== "poll") throw new Error(`Attachment "${discovered.key}" is not a poll trigger`);
|
|
440
|
-
return source.id ?? source.key;
|
|
441
|
-
}
|
|
442
|
-
function buildPollGroups(attachments) {
|
|
443
|
-
const byId = /* @__PURE__ */ new Map();
|
|
444
|
-
for (const discovered of attachments) {
|
|
445
|
-
if (discovered.attachment.source.kind !== "poll") continue;
|
|
446
|
-
const id = pollGroupId(discovered);
|
|
447
|
-
const group = byId.get(id) ?? [];
|
|
448
|
-
group.push(discovered);
|
|
449
|
-
byId.set(id, group);
|
|
450
|
-
}
|
|
451
|
-
return [...byId.entries()].map(([id, groupAttachments]) => ({
|
|
452
|
-
id,
|
|
453
|
-
attachments: groupAttachments
|
|
454
|
-
}));
|
|
455
|
-
}
|
|
456
|
-
function buildWebhookBindingsByRoute(attachments, handlerOptionsFor) {
|
|
457
|
-
const webhookBindingsByRoute = /* @__PURE__ */ new Map();
|
|
458
|
-
for (const discovered of attachments) {
|
|
459
|
-
const source = discovered.attachment.source;
|
|
460
|
-
if (source.kind !== "webhook") continue;
|
|
461
|
-
const route = webhookRouteFromEndpoint(source.endpoint);
|
|
462
|
-
const bindings = webhookBindingsByRoute.get(route) ?? [];
|
|
463
|
-
bindings.push({
|
|
464
|
-
discovered,
|
|
465
|
-
options: handlerOptionsFor(discovered.key)
|
|
466
|
-
});
|
|
467
|
-
webhookBindingsByRoute.set(route, bindings);
|
|
468
|
-
}
|
|
469
|
-
return webhookBindingsByRoute;
|
|
470
|
-
}
|
|
471
|
-
function webhookSchemaEntriesFromBindings(bindings) {
|
|
472
|
-
return bindings.flatMap((binding) => {
|
|
473
|
-
const source = binding.discovered.attachment.source;
|
|
474
|
-
if (source.kind !== "webhook") return [];
|
|
475
|
-
return [{
|
|
476
|
-
attachmentKey: binding.discovered.key,
|
|
477
|
-
request: source.request,
|
|
478
|
-
...source.filter ? { filter: source.filter } : {}
|
|
479
|
-
}];
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
function webhookMatchSchemaForBindings(bindings) {
|
|
483
|
-
const schemas = bindings.flatMap((binding) => {
|
|
484
|
-
const source = binding.discovered.attachment.source;
|
|
485
|
-
return source.kind === "webhook" ? [source.request] : [];
|
|
486
|
-
});
|
|
487
|
-
if (schemas.length === 0) throw new Error("Webhook bindings require at least one webhook source");
|
|
488
|
-
if (schemas.length === 1) return schemas[0];
|
|
489
|
-
return union(schemas);
|
|
490
|
-
}
|
|
491
|
-
function webhookManifestAttachmentSchemasFromBindings(bindings) {
|
|
492
|
-
return Object.fromEntries(webhookSchemaEntriesFromBindings(bindings).map((entry) => [entry.attachmentKey, {
|
|
493
|
-
request: entry.request,
|
|
494
|
-
...entry.filter ? { filter: entry.filter } : {}
|
|
495
|
-
}]));
|
|
496
|
-
}
|
|
497
|
-
async function discoverWorkflowEntries(workflowsDir, options) {
|
|
498
|
-
const files = await discoverModuleFileEntries(workflowsDir, {
|
|
499
|
-
nestedEntry: "workflow",
|
|
500
|
-
duplicateLabel: "workflow module file"
|
|
501
|
-
});
|
|
502
|
-
const entries = [];
|
|
503
|
-
for (const { filePath, moduleFile } of files) {
|
|
504
|
-
const definition = await importWorkflowDefinition(filePath, options);
|
|
505
|
-
entries.push({
|
|
506
|
-
key: definition.slug,
|
|
507
|
-
route: workflowRouteFromKey(definition.slug),
|
|
508
|
-
filePath,
|
|
509
|
-
moduleFile
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
return entries;
|
|
513
|
-
}
|
|
514
|
-
function validateImportedWorkflowDefinition(def, filePath) {
|
|
515
|
-
return validateManifestWorkflow(def, filePath);
|
|
516
|
-
}
|
|
517
|
-
async function importWorkflowDefinition(filePath, options) {
|
|
518
|
-
const href = pathToFileURL(filePath).href;
|
|
519
|
-
return validateImportedWorkflowDefinition((await (options?.reload ? import(`${href}?keystroke=${Date.now()}`) : import(href))).default, filePath);
|
|
520
|
-
}
|
|
521
|
-
async function discoverWorkflows(workflowsDir, options) {
|
|
522
|
-
const entries = await discoverWorkflowEntries(workflowsDir, options);
|
|
523
|
-
const workflows = [];
|
|
524
|
-
for (const entry of entries) {
|
|
525
|
-
const definition = await importWorkflowDefinition(entry.filePath, options);
|
|
526
|
-
workflows.push({
|
|
527
|
-
key: definition.slug,
|
|
528
|
-
route: workflowRouteFromKey(definition.slug),
|
|
529
|
-
filePath: entry.filePath,
|
|
530
|
-
definition
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
return workflows;
|
|
534
|
-
}
|
|
535
|
-
function resolveDistModuleDirs(projectRoot) {
|
|
536
|
-
const distBase = join(projectRoot, "dist");
|
|
537
|
-
if (!existsSync(distBase)) throw new Error(`Build output missing at ${distBase}. Run keystroke build before emitting the route manifest.`);
|
|
538
|
-
return {
|
|
539
|
-
agentsDir: join(distBase, "agents"),
|
|
540
|
-
workflowsDir: join(distBase, "workflows"),
|
|
541
|
-
triggersDir: join(distBase, "triggers")
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
function toPosix(path) {
|
|
545
|
-
return path.split(sep).join("/");
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Resolve manifest moduleFile values to project-root-relative source paths.
|
|
549
|
-
*
|
|
550
|
-
* Discovery runs over compiled `dist/` modules, so the raw moduleFile is a
|
|
551
|
-
* dist-relative `.mjs` path. Dist entries are named by their source entry id
|
|
552
|
-
* (`team/escalation.mjs` ← `src/agents/team/escalation/agent.ts`), so walking
|
|
553
|
-
* the matching source dir by the same id rules recovers the source path. Falls
|
|
554
|
-
* back to the dist-relative value when no source file matches (e.g. building
|
|
555
|
-
* a dist-only artifact with no `src/`).
|
|
556
|
-
*/
|
|
557
|
-
var SourceModuleFileResolver = class {
|
|
558
|
-
projectRoot;
|
|
559
|
-
mapsByKind = /* @__PURE__ */ new Map();
|
|
560
|
-
constructor(projectRoot) {
|
|
561
|
-
this.projectRoot = projectRoot;
|
|
562
|
-
}
|
|
563
|
-
async sourceMapFor(kindDir, nestedEntry) {
|
|
564
|
-
const existing = this.mapsByKind.get(kindDir);
|
|
565
|
-
if (existing) return existing;
|
|
566
|
-
const map = /* @__PURE__ */ new Map();
|
|
567
|
-
const sourceDir = join(this.projectRoot, "src", kindDir);
|
|
568
|
-
for (const filePath of await walkTypeScriptFiles(sourceDir)) {
|
|
569
|
-
const id = entryIdFromFile(sourceDir, filePath, { nestedEntry });
|
|
570
|
-
if (id) map.set(id, toPosix(relative(this.projectRoot, filePath)));
|
|
571
|
-
}
|
|
572
|
-
this.mapsByKind.set(kindDir, map);
|
|
573
|
-
return map;
|
|
574
|
-
}
|
|
575
|
-
async resolve(kindDir, nestedEntry, distDir, distFilePath) {
|
|
576
|
-
const fallback = toPosix(relative(distDir, distFilePath));
|
|
577
|
-
const id = entryIdFromFile(distDir, distFilePath, { nestedEntry });
|
|
578
|
-
if (!id) return fallback;
|
|
579
|
-
return (await this.sourceMapFor(kindDir, nestedEntry)).get(id) ?? fallback;
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
/** Build a stored route manifest from compiled dist/ modules without starting a server. */
|
|
583
|
-
async function buildStoredRouteManifestForProject(projectRoot, options) {
|
|
584
|
-
const previousRoot = process.env.KEYSTROKE_ROOT;
|
|
585
|
-
process.env.KEYSTROKE_ROOT = projectRoot;
|
|
586
|
-
const reload = options?.reloadModules ? { reload: true } : void 0;
|
|
587
|
-
try {
|
|
588
|
-
const dirs = resolveDistModuleDirs(projectRoot);
|
|
589
|
-
const sourcePaths = new SourceModuleFileResolver(projectRoot);
|
|
590
|
-
const manifest = [{
|
|
591
|
-
kind: "health",
|
|
592
|
-
method: "GET",
|
|
593
|
-
path: "/health"
|
|
594
|
-
}];
|
|
595
|
-
const agentEntries = await discoverAgentEntries(dirs.agentsDir, reload);
|
|
596
|
-
for (const entry of agentEntries) {
|
|
597
|
-
const agent = await importAgentDefinition(entry.filePath, reload);
|
|
598
|
-
const moduleFile = await sourcePaths.resolve("agents", "agent", dirs.agentsDir, entry.filePath);
|
|
599
|
-
manifest.push({
|
|
600
|
-
kind: "agent",
|
|
601
|
-
method: "POST",
|
|
602
|
-
path: entry.route,
|
|
603
|
-
agentSlug: agent.slug,
|
|
604
|
-
moduleFile,
|
|
605
|
-
name: agent.name,
|
|
606
|
-
description: agent.description,
|
|
607
|
-
model: agent.model,
|
|
608
|
-
systemPrompt: agent.systemPrompt,
|
|
609
|
-
toolCount: agent.tools?.length ?? 0,
|
|
610
|
-
credentialCount: countAgentCredentials(agent),
|
|
611
|
-
request: PromptInputSchema,
|
|
612
|
-
response: PromptResponseSchema
|
|
613
|
-
});
|
|
614
|
-
manifest.push({
|
|
615
|
-
kind: "agent-sessions-list",
|
|
616
|
-
method: "GET",
|
|
617
|
-
path: agentSessionsListPath(entry.route),
|
|
618
|
-
agentSlug: entry.key,
|
|
619
|
-
moduleFile
|
|
620
|
-
});
|
|
621
|
-
manifest.push({
|
|
622
|
-
kind: "agent-session-detail",
|
|
623
|
-
method: "GET",
|
|
624
|
-
path: agentSessionDetailPath(entry.route),
|
|
625
|
-
agentSlug: entry.key,
|
|
626
|
-
moduleFile
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
const workflows = await discoverWorkflows(dirs.workflowsDir, reload);
|
|
630
|
-
for (const workflow of workflows) {
|
|
631
|
-
const route = workflowRouteFromKey(workflow.key);
|
|
632
|
-
const moduleFile = await sourcePaths.resolve("workflows", "workflow", dirs.workflowsDir, workflow.filePath);
|
|
633
|
-
manifest.push({
|
|
634
|
-
kind: "workflow",
|
|
635
|
-
method: "POST",
|
|
636
|
-
path: route,
|
|
637
|
-
workflowSlug: workflow.definition.slug,
|
|
638
|
-
workflowName: workflow.definition.name,
|
|
639
|
-
description: workflow.definition.description,
|
|
640
|
-
subscribable: workflow.definition.subscription?.mode === "subscribable",
|
|
641
|
-
moduleFile,
|
|
642
|
-
request: workflow.definition.input,
|
|
643
|
-
response: workflow.definition.output
|
|
644
|
-
});
|
|
645
|
-
manifest.push({
|
|
646
|
-
kind: "workflow-runs-list",
|
|
647
|
-
method: "GET",
|
|
648
|
-
path: workflowRunsListPath(route),
|
|
649
|
-
workflowSlug: workflow.definition.slug,
|
|
650
|
-
workflowName: workflow.definition.name,
|
|
651
|
-
moduleFile
|
|
652
|
-
});
|
|
653
|
-
manifest.push({
|
|
654
|
-
kind: "workflow-run-detail",
|
|
655
|
-
method: "GET",
|
|
656
|
-
path: workflowRunDetailPath(route),
|
|
657
|
-
workflowSlug: workflow.definition.slug,
|
|
658
|
-
workflowName: workflow.definition.name,
|
|
659
|
-
moduleFile
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
const attachments = await discoverTriggerAttachments(dirs.triggersDir, reload);
|
|
663
|
-
const discoveredByKey = new Map(attachments.map((attachment) => [attachment.key, attachment]));
|
|
664
|
-
const pollGroups = buildPollGroups(attachments);
|
|
665
|
-
for (const discovered of discoveredByKey.values()) {
|
|
666
|
-
const source = discovered.attachment.source;
|
|
667
|
-
const moduleFile = await sourcePaths.resolve("triggers", "trigger", dirs.triggersDir, discovered.filePath);
|
|
668
|
-
if (source.kind === "cron") {
|
|
669
|
-
manifest.push({
|
|
670
|
-
kind: "cron-schedule",
|
|
671
|
-
attachmentId: discovered.key,
|
|
672
|
-
moduleFile,
|
|
673
|
-
schedule: source.schedule
|
|
674
|
-
});
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
if (source.kind === "poll") {
|
|
678
|
-
const route = pollRouteFromKey(source.key);
|
|
679
|
-
manifest.push({
|
|
680
|
-
kind: "trigger-poll",
|
|
681
|
-
method: "POST",
|
|
682
|
-
path: route,
|
|
683
|
-
attachmentId: discovered.key,
|
|
684
|
-
moduleFile,
|
|
685
|
-
schedule: source.schedule,
|
|
686
|
-
response: PromptResponseSchema
|
|
687
|
-
});
|
|
688
|
-
manifest.push({
|
|
689
|
-
kind: "trigger-runs-list",
|
|
690
|
-
method: "GET",
|
|
691
|
-
path: triggerRunsListPath(discovered.key),
|
|
692
|
-
attachmentId: discovered.key,
|
|
693
|
-
moduleFile
|
|
694
|
-
});
|
|
695
|
-
manifest.push({
|
|
696
|
-
kind: "trigger-run-detail",
|
|
697
|
-
method: "GET",
|
|
698
|
-
path: triggerRunDetailPath(discovered.key),
|
|
699
|
-
attachmentId: discovered.key,
|
|
700
|
-
moduleFile
|
|
701
|
-
});
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
if (source.kind === "webhook") {
|
|
705
|
-
const route = webhookRouteFromEndpoint(source.endpoint);
|
|
706
|
-
const bindings = buildWebhookBindingsByRoute(discoveredByKey.values(), () => ({
|
|
707
|
-
execution: { attachmentKey: discovered.key },
|
|
708
|
-
attachmentKey: discovered.key
|
|
709
|
-
})).get(route) ?? [{
|
|
710
|
-
discovered,
|
|
711
|
-
options: { attachmentKey: discovered.key }
|
|
712
|
-
}];
|
|
713
|
-
manifest.push({
|
|
714
|
-
kind: "trigger-webhook",
|
|
715
|
-
method: "POST",
|
|
716
|
-
path: route,
|
|
717
|
-
attachmentIds: bindings.map(({ discovered: row }) => row.key),
|
|
718
|
-
moduleFile,
|
|
719
|
-
request: webhookMatchSchemaForBindings(bindings),
|
|
720
|
-
attachmentSchemas: webhookManifestAttachmentSchemasFromBindings(bindings),
|
|
721
|
-
response: PromptResponseSchema
|
|
722
|
-
});
|
|
723
|
-
for (const { discovered: row } of bindings) {
|
|
724
|
-
const rowModuleFile = await sourcePaths.resolve("triggers", "trigger", dirs.triggersDir, row.filePath);
|
|
725
|
-
manifest.push({
|
|
726
|
-
kind: "trigger-runs-list",
|
|
727
|
-
method: "GET",
|
|
728
|
-
path: triggerRunsListPath(row.key),
|
|
729
|
-
attachmentId: row.key,
|
|
730
|
-
moduleFile: rowModuleFile
|
|
731
|
-
});
|
|
732
|
-
manifest.push({
|
|
733
|
-
kind: "trigger-run-detail",
|
|
734
|
-
method: "GET",
|
|
735
|
-
path: triggerRunDetailPath(row.key),
|
|
736
|
-
attachmentId: row.key,
|
|
737
|
-
moduleFile: rowModuleFile
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
for (const group of pollGroups) {
|
|
743
|
-
if (group.attachments.length <= 1) continue;
|
|
744
|
-
const first = group.attachments[0];
|
|
745
|
-
const source = first.attachment.source;
|
|
746
|
-
manifest.push({
|
|
747
|
-
kind: "trigger-poll-group",
|
|
748
|
-
method: "POST",
|
|
749
|
-
path: pollGroupRouteFromId(group.id),
|
|
750
|
-
pollId: group.id,
|
|
751
|
-
attachmentIds: group.attachments.map((attachment) => attachment.key),
|
|
752
|
-
moduleFile: await sourcePaths.resolve("triggers", "trigger", dirs.triggersDir, first.filePath),
|
|
753
|
-
schedule: source.kind === "poll" ? source.schedule : "",
|
|
754
|
-
response: PromptResponseSchema
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
return buildStoredRouteManifestFromContext({
|
|
758
|
-
manifest,
|
|
759
|
-
options: {},
|
|
760
|
-
projectRoot,
|
|
761
|
-
skills: discoverSkillManifestEntries(projectRoot)
|
|
762
|
-
});
|
|
763
|
-
} finally {
|
|
764
|
-
if (previousRoot === void 0) delete process.env.KEYSTROKE_ROOT;
|
|
765
|
-
else process.env.KEYSTROKE_ROOT = previousRoot;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
/** Write `dist/.keystroke/route-manifest.json` for the project. */
|
|
769
|
-
async function emitStoredRouteManifestForProject(projectRoot) {
|
|
770
|
-
persistStoredRouteManifest(projectRoot, await buildStoredRouteManifestForProject(projectRoot));
|
|
771
|
-
}
|
|
772
|
-
//#endregion
|
|
773
|
-
export { webhookMatchSchemaForBindings as A, walkTypeScriptFiles as B, serializeRouteManifest as C, validateImportedTriggerAttachment as D, triggerRunsListPath as E, discoverEntries as F, discoverModuleFileEntries as I, entryIdFromFile as L, workflowRouteFromKey as M, workflowRunDetailPath as N, validateImportedWorkflowDefinition as O, workflowRunsListPath as P, readKeystrokeIgnoreDirective as R, schemaToJson as S, triggerRunDetailPath as T, importWorkflowDefinition as _, buildStoredRouteManifestForProject as a, pollGroupRouteFromId as b, countAgentCredentials as c, discoverTriggerAttachments as d, discoverWorkflowEntries as f, importTriggerAttachment as g, importAgentDefinition as h, buildPollGroups as i, webhookRouteFromEndpoint as j, webhookManifestAttachmentSchemasFromBindings as k, discoverAgentEntries as l, emitStoredRouteManifestForProject as m, agentSessionDetailPath as n, buildStoredRouteManifestFromContext as o, discoverWorkflows as p, agentSessionsListPath as r, buildWebhookBindingsByRoute as s, agentRouteFromKey as t, discoverSkillManifestEntries as u, persistStoredRouteManifest as v, toStoredRouteManifest as w, pollRouteFromKey as x, pollGroupId as y, shouldSkipKeystrokeModuleFile as z };
|
|
774
|
-
|
|
775
|
-
//# sourceMappingURL=dist-vwoMCz6d.mjs.map
|