@hasna/connectors 1.3.2 → 1.3.3
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/bin/index.js +2116 -248
- package/bin/mcp.js +1620 -172
- package/bin/serve.js +1230 -128
- package/connectors/connect-aiagenttool/src/api/client.ts +18 -205
- package/connectors/connect-aiagenttool/src/api/index.ts +32 -43
- package/connectors/connect-aiagenttool/src/types/index.ts +7 -233
- package/connectors/connect-airbrake/src/api/client.ts +25 -208
- package/connectors/connect-airbrake/src/api/index.ts +31 -44
- package/connectors/connect-airbrake/src/types/index.ts +10 -233
- package/connectors/connect-airnow/src/api/client.ts +16 -204
- package/connectors/connect-airnow/src/api/index.ts +32 -43
- package/connectors/connect-airnow/src/types/index.ts +5 -233
- package/connectors/connect-airtop/src/api/client.ts +18 -205
- package/connectors/connect-airtop/src/api/index.ts +35 -41
- package/connectors/connect-airtop/src/types/index.ts +9 -233
- package/connectors/connect-aitableai/src/api/client.ts +18 -205
- package/connectors/connect-aitableai/src/api/index.ts +35 -43
- package/connectors/connect-aitableai/src/types/index.ts +10 -233
- package/connectors/connect-alchemy/src/api/client.ts +33 -207
- package/connectors/connect-alchemy/src/api/index.ts +38 -44
- package/connectors/connect-alchemy/src/types/index.ts +13 -235
- package/connectors/connect-alerty/src/api/client.ts +18 -205
- package/connectors/connect-alerty/src/api/index.ts +29 -44
- package/connectors/connect-alerty/src/types/index.ts +9 -233
- package/connectors/connect-alienvault/src/api/client.ts +18 -205
- package/connectors/connect-alienvault/src/api/index.ts +34 -44
- package/connectors/connect-alienvault/src/types/index.ts +9 -233
- package/connectors/connect-alphamoon/src/api/client.ts +19 -206
- package/connectors/connect-alphamoon/src/api/index.ts +30 -42
- package/connectors/connect-alphamoon/src/types/index.ts +10 -233
- package/connectors/connect-alttextai/src/api/client.ts +18 -205
- package/connectors/connect-alttextai/src/api/index.ts +20 -43
- package/connectors/connect-alttextai/src/types/index.ts +7 -233
- package/connectors/connect-amadeus/src/api/client.ts +2 -2
- package/connectors/connect-amilia/src/api/client.ts +26 -211
- package/connectors/connect-amilia/src/api/index.ts +27 -44
- package/connectors/connect-amilia/src/types/index.ts +9 -233
- package/connectors/connect-amqpsender/src/api/client.ts +35 -212
- package/connectors/connect-amqpsender/src/api/index.ts +35 -42
- package/connectors/connect-amqpsender/src/types/index.ts +8 -233
- package/connectors/connect-announcekit/src/api/client.ts +19 -206
- package/connectors/connect-announcekit/src/api/index.ts +30 -43
- package/connectors/connect-announcekit/src/types/index.ts +8 -233
- package/connectors/connect-anthropic/src/api/messages.ts +2 -2
- package/connectors/connect-apiary/src/api/client.ts +19 -206
- package/connectors/connect-apiary/src/api/index.ts +23 -44
- package/connectors/connect-apiary/src/types/index.ts +9 -233
- package/connectors/connect-apiflash/src/api/client.ts +19 -204
- package/connectors/connect-apiflash/src/api/index.ts +48 -43
- package/connectors/connect-apiflash/src/types/index.ts +29 -235
- package/connectors/connect-apitemplateio/src/api/client.ts +18 -205
- package/connectors/connect-apitemplateio/src/api/index.ts +27 -43
- package/connectors/connect-apitemplateio/src/types/index.ts +8 -233
- package/connectors/connect-apptivegrid/src/api/client.ts +19 -205
- package/connectors/connect-apptivegrid/src/api/index.ts +32 -43
- package/connectors/connect-apptivegrid/src/types/index.ts +9 -233
- package/connectors/connect-auth0/src/api/client.ts +20 -206
- package/connectors/connect-auth0/src/api/index.ts +47 -45
- package/connectors/connect-auth0/src/types/index.ts +9 -233
- package/connectors/connect-autom/src/api/client.ts +18 -205
- package/connectors/connect-autom/src/api/index.ts +33 -43
- package/connectors/connect-autom/src/types/index.ts +8 -233
- package/connectors/connect-automizy/src/api/client.ts +19 -206
- package/connectors/connect-automizy/src/api/index.ts +37 -45
- package/connectors/connect-automizy/src/types/index.ts +10 -233
- package/connectors/connect-autopilot/src/api/client.ts +18 -205
- package/connectors/connect-autopilot/src/api/index.ts +34 -42
- package/connectors/connect-autopilot/src/types/index.ts +8 -233
- package/connectors/connect-azureaisearchvectorstore/src/api/client.ts +21 -204
- package/connectors/connect-azureaisearchvectorstore/src/api/index.ts +31 -41
- package/connectors/connect-azureaisearchvectorstore/src/types/index.ts +9 -233
- package/connectors/connect-azurecosmosdb/src/api/client.ts +32 -204
- package/connectors/connect-azurecosmosdb/src/api/index.ts +42 -43
- package/connectors/connect-azurecosmosdb/src/types/index.ts +9 -233
- package/connectors/connect-botstar/src/api/client.ts +19 -206
- package/connectors/connect-botstar/src/api/index.ts +36 -43
- package/connectors/connect-botstar/src/types/index.ts +9 -233
- package/connectors/connect-breezyhr/src/api/client.ts +19 -206
- package/connectors/connect-breezyhr/src/api/index.ts +40 -41
- package/connectors/connect-breezyhr/src/types/index.ts +9 -233
- package/connectors/connect-browseai/src/api/client.ts +18 -205
- package/connectors/connect-browseai/src/api/index.ts +22 -43
- package/connectors/connect-browseai/src/types/index.ts +6 -233
- package/connectors/connect-browserless/src/api/client.ts +20 -203
- package/connectors/connect-browserless/src/api/index.ts +32 -43
- package/connectors/connect-browserless/src/types/index.ts +8 -233
- package/connectors/connect-browserstack/src/api/client.ts +19 -206
- package/connectors/connect-browserstack/src/api/index.ts +28 -43
- package/connectors/connect-browserstack/src/types/index.ts +8 -233
- package/connectors/connect-bugbug/src/api/client.ts +18 -205
- package/connectors/connect-bugbug/src/api/index.ts +27 -42
- package/connectors/connect-bugbug/src/types/index.ts +9 -233
- package/connectors/connect-bugherd/src/api/client.ts +24 -211
- package/connectors/connect-bugherd/src/api/index.ts +33 -43
- package/connectors/connect-bugherd/src/types/index.ts +8 -233
- package/connectors/connect-bugreplay/src/api/client.ts +18 -205
- package/connectors/connect-bugreplay/src/api/index.ts +24 -43
- package/connectors/connect-bugreplay/src/types/index.ts +7 -233
- package/connectors/connect-buildkite/src/api/client.ts +19 -206
- package/connectors/connect-buildkite/src/api/index.ts +37 -43
- package/connectors/connect-buildkite/src/types/index.ts +8 -233
- package/connectors/connect-bunnycdn/src/api/client.ts +18 -207
- package/connectors/connect-bunnycdn/src/api/index.ts +29 -44
- package/connectors/connect-bunnycdn/src/types/index.ts +7 -233
- package/connectors/connect-carbonblack/src/api/client.ts +19 -205
- package/connectors/connect-carbonblack/src/api/index.ts +34 -43
- package/connectors/connect-carbonblack/src/types/index.ts +9 -233
- package/connectors/connect-chargify/src/api/client.ts +21 -204
- package/connectors/connect-chargify/src/api/index.ts +49 -42
- package/connectors/connect-chargify/src/types/index.ts +8 -233
- package/connectors/connect-chatling/src/api/client.ts +18 -205
- package/connectors/connect-chatling/src/api/index.ts +35 -42
- package/connectors/connect-chatling/src/types/index.ts +8 -233
- package/connectors/connect-chekhub/src/api/client.ts +19 -206
- package/connectors/connect-chekhub/src/api/index.ts +33 -44
- package/connectors/connect-chekhub/src/types/index.ts +9 -233
- package/connectors/connect-chromavectorstore/src/api/client.ts +28 -206
- package/connectors/connect-chromavectorstore/src/api/index.ts +41 -44
- package/connectors/connect-chromavectorstore/src/types/index.ts +7 -233
- package/connectors/connect-ciscoumbrella/src/api/client.ts +24 -207
- package/connectors/connect-ciscoumbrella/src/api/index.ts +33 -43
- package/connectors/connect-ciscoumbrella/src/types/index.ts +8 -233
- package/connectors/connect-clicksendsms/src/api/client.ts +19 -206
- package/connectors/connect-clicksendsms/src/api/index.ts +32 -43
- package/connectors/connect-clicksendsms/src/types/index.ts +9 -233
- package/connectors/connect-cloudboost/src/api/client.ts +23 -208
- package/connectors/connect-cloudboost/src/api/index.ts +36 -43
- package/connectors/connect-cloudboost/src/types/index.ts +9 -233
- package/connectors/connect-cloudlayer/src/api/client.ts +20 -209
- package/connectors/connect-cloudlayer/src/api/index.ts +25 -42
- package/connectors/connect-cloudlayer/src/types/index.ts +8 -233
- package/connectors/connect-cody/src/api/client.ts +19 -205
- package/connectors/connect-cody/src/api/index.ts +23 -42
- package/connectors/connect-cody/src/types/index.ts +6 -233
- package/connectors/connect-confluent/src/api/client.ts +21 -205
- package/connectors/connect-confluent/src/api/index.ts +36 -43
- package/connectors/connect-confluent/src/types/index.ts +9 -233
- package/connectors/connect-convertapi/src/api/client.ts +17 -205
- package/connectors/connect-convertapi/src/api/index.ts +20 -44
- package/connectors/connect-convertapi/src/types/index.ts +7 -233
- package/connectors/connect-copper/src/api/client.ts +20 -205
- package/connectors/connect-copper/src/api/index.ts +38 -42
- package/connectors/connect-copper/src/types/index.ts +8 -233
- package/connectors/connect-cortex/src/api/client.ts +19 -206
- package/connectors/connect-cortex/src/api/index.ts +33 -43
- package/connectors/connect-cortex/src/types/index.ts +10 -233
- package/connectors/connect-craftdraft/src/api/client.ts +18 -205
- package/connectors/connect-craftdraft/src/api/index.ts +27 -43
- package/connectors/connect-craftdraft/src/types/index.ts +7 -233
- package/connectors/connect-crisp/src/api/client.ts +24 -207
- package/connectors/connect-crisp/src/api/index.ts +34 -42
- package/connectors/connect-crisp/src/types/index.ts +7 -233
- package/connectors/connect-crossmint/src/api/client.ts +20 -208
- package/connectors/connect-crossmint/src/api/index.ts +29 -43
- package/connectors/connect-crossmint/src/types/index.ts +7 -233
- package/connectors/connect-crowddev/src/api/client.ts +18 -204
- package/connectors/connect-crowddev/src/api/index.ts +23 -43
- package/connectors/connect-crowddev/src/types/index.ts +8 -233
- package/connectors/connect-crowdpower/src/api/client.ts +18 -205
- package/connectors/connect-crowdpower/src/api/index.ts +28 -44
- package/connectors/connect-crowdpower/src/types/index.ts +9 -233
- package/connectors/connect-cryptolens/src/api/client.ts +20 -211
- package/connectors/connect-cryptolens/src/api/index.ts +34 -44
- package/connectors/connect-cryptolens/src/types/index.ts +7 -233
- package/connectors/connect-customerio/src/api/client.ts +37 -211
- package/connectors/connect-customerio/src/api/index.ts +34 -44
- package/connectors/connect-customerio/src/types/index.ts +9 -233
- package/connectors/connect-daffy/src/api/client.ts +18 -205
- package/connectors/connect-daffy/src/api/index.ts +25 -42
- package/connectors/connect-daffy/src/types/index.ts +8 -233
- package/connectors/connect-datasoap/src/api/client.ts +18 -205
- package/connectors/connect-datasoap/src/api/index.ts +28 -42
- package/connectors/connect-datasoap/src/types/index.ts +8 -233
- package/connectors/connect-dayschedule/src/api/client.ts +18 -205
- package/connectors/connect-dayschedule/src/api/index.ts +25 -43
- package/connectors/connect-dayschedule/src/types/index.ts +8 -233
- package/connectors/connect-deepl/src/api/client.ts +46 -185
- package/connectors/connect-deepl/src/api/index.ts +18 -40
- package/connectors/connect-deepl/src/api/translate.ts +98 -0
- package/connectors/connect-deepl/src/types/index.ts +33 -217
- package/connectors/connect-demio/src/api/client.ts +19 -204
- package/connectors/connect-demio/src/api/index.ts +29 -42
- package/connectors/connect-demio/src/types/index.ts +7 -233
- package/connectors/connect-dhl/src/api/client.ts +22 -201
- package/connectors/connect-dhl/src/api/index.ts +23 -42
- package/connectors/connect-dhl/src/types/index.ts +10 -233
- package/connectors/connect-docsbotai/src/api/client.ts +21 -206
- package/connectors/connect-docsbotai/src/api/index.ts +55 -39
- package/connectors/connect-docsbotai/src/types/index.ts +7 -233
- package/connectors/connect-drift/src/api/client.ts +19 -203
- package/connectors/connect-drift/src/api/index.ts +41 -42
- package/connectors/connect-drift/src/types/index.ts +7 -233
- package/connectors/connect-dropcontact/src/api/client.ts +21 -209
- package/connectors/connect-dropcontact/src/api/index.ts +23 -42
- package/connectors/connect-dropcontact/src/types/index.ts +8 -233
- package/connectors/connect-eartho/src/api/client.ts +21 -206
- package/connectors/connect-eartho/src/api/index.ts +24 -44
- package/connectors/connect-eartho/src/types/index.ts +6 -233
- package/connectors/connect-echowin/src/api/client.ts +18 -205
- package/connectors/connect-echowin/src/api/index.ts +29 -43
- package/connectors/connect-echowin/src/types/index.ts +8 -233
- package/connectors/connect-ecwid/src/api/client.ts +20 -205
- package/connectors/connect-ecwid/src/api/index.ts +36 -42
- package/connectors/connect-ecwid/src/types/index.ts +9 -233
- package/connectors/connect-elasticsearch/src/api/client.ts +29 -204
- package/connectors/connect-elasticsearch/src/api/index.ts +40 -41
- package/connectors/connect-elasticsearch/src/types/index.ts +9 -233
- package/connectors/connect-emelia/src/api/client.ts +23 -199
- package/connectors/connect-emelia/src/api/index.ts +60 -41
- package/connectors/connect-emelia/src/types/index.ts +24 -220
- package/connectors/connect-engati/src/api/client.ts +20 -205
- package/connectors/connect-engati/src/api/index.ts +31 -42
- package/connectors/connect-engati/src/types/index.ts +9 -233
- package/connectors/connect-erpnext/src/api/client.ts +21 -204
- package/connectors/connect-erpnext/src/api/index.ts +34 -43
- package/connectors/connect-erpnext/src/types/index.ts +6 -233
- package/connectors/connect-evervault/src/api/client.ts +22 -211
- package/connectors/connect-evervault/src/api/index.ts +28 -42
- package/connectors/connect-evervault/src/types/index.ts +9 -233
- package/connectors/connect-faros/src/api/client.ts +18 -204
- package/connectors/connect-faros/src/api/index.ts +31 -43
- package/connectors/connect-faros/src/types/index.ts +9 -233
- package/connectors/connect-fastbots/src/api/client.ts +18 -205
- package/connectors/connect-fastbots/src/api/index.ts +31 -42
- package/connectors/connect-fastbots/src/types/index.ts +8 -233
- package/connectors/connect-flagship/src/api/client.ts +24 -209
- package/connectors/connect-flagship/src/api/index.ts +24 -42
- package/connectors/connect-flagship/src/types/index.ts +7 -233
- package/connectors/connect-float/src/api/client.ts +19 -206
- package/connectors/connect-float/src/api/index.ts +38 -42
- package/connectors/connect-float/src/types/index.ts +9 -233
- package/connectors/connect-flotiq/src/api/client.ts +18 -205
- package/connectors/connect-flotiq/src/api/index.ts +38 -42
- package/connectors/connect-flotiq/src/types/index.ts +9 -233
- package/connectors/connect-formcarry/src/api/client.ts +20 -210
- package/connectors/connect-formcarry/src/api/index.ts +25 -46
- package/connectors/connect-formcarry/src/types/index.ts +5 -235
- package/connectors/connect-formdesk/src/api/client.ts +19 -204
- package/connectors/connect-formdesk/src/api/index.ts +23 -44
- package/connectors/connect-formdesk/src/types/index.ts +7 -233
- package/connectors/connect-formsonfire/src/api/client.ts +18 -205
- package/connectors/connect-formsonfire/src/api/index.ts +21 -44
- package/connectors/connect-formsonfire/src/types/index.ts +8 -233
- package/connectors/connect-fortinetfortigate/src/api/client.ts +19 -205
- package/connectors/connect-fortinetfortigate/src/api/index.ts +33 -43
- package/connectors/connect-fortinetfortigate/src/types/index.ts +8 -233
- package/connectors/connect-freedictionary/src/api/client.ts +11 -205
- package/connectors/connect-freedictionary/src/api/index.ts +29 -42
- package/connectors/connect-freedictionary/src/types/index.ts +5 -233
- package/connectors/connect-freshworkscrm/src/api/client.ts +18 -204
- package/connectors/connect-freshworkscrm/src/api/index.ts +41 -41
- package/connectors/connect-freshworkscrm/src/types/index.ts +8 -233
- package/connectors/connect-fusioo/src/api/client.ts +19 -206
- package/connectors/connect-fusioo/src/api/index.ts +29 -43
- package/connectors/connect-fusioo/src/types/index.ts +8 -233
- package/connectors/connect-genderapi/src/api/client.ts +14 -205
- package/connectors/connect-genderapi/src/api/index.ts +23 -42
- package/connectors/connect-genderapi/src/types/index.ts +5 -233
- package/connectors/connect-ghost/src/api/client.ts +45 -211
- package/connectors/connect-ghost/src/api/index.ts +38 -43
- package/connectors/connect-ghost/src/types/index.ts +9 -233
- package/connectors/connect-gitea/src/api/client.ts +19 -205
- package/connectors/connect-gitea/src/api/index.ts +39 -43
- package/connectors/connect-gitea/src/types/index.ts +9 -233
- package/connectors/connect-github/src/api/client.ts +11 -0
- package/connectors/connect-github/src/api/commits.ts +169 -0
- package/connectors/connect-github/src/api/index.ts +12 -0
- package/connectors/connect-github/src/api/releases.ts +158 -0
- package/connectors/connect-github/src/api/workflows.ts +169 -0
- package/connectors/connect-github/src/types/index.ts +190 -0
- package/connectors/connect-gmail/src/cli/index.ts +3 -32
- package/connectors/connect-googleads/src/api/adGroups.ts +3 -3
- package/connectors/connect-googleads/src/api/ads.ts +3 -3
- package/connectors/connect-googleads/src/api/campaigns.ts +4 -4
- package/connectors/connect-googleads/src/api/client.ts +1 -1
- package/connectors/connect-googleads/src/api/keywords.ts +6 -6
- package/connectors/connect-googlebigquery/src/api/client.ts +24 -204
- package/connectors/connect-googlebigquery/src/api/index.ts +39 -42
- package/connectors/connect-googlebigquery/src/types/index.ts +8 -233
- package/connectors/connect-googletranslate/src/api/client.ts +20 -204
- package/connectors/connect-googletranslate/src/api/index.ts +22 -43
- package/connectors/connect-googletranslate/src/types/index.ts +9 -233
- package/connectors/connect-gotowebinar/src/api/client.ts +24 -207
- package/connectors/connect-gotowebinar/src/api/index.ts +36 -43
- package/connectors/connect-gotowebinar/src/types/index.ts +7 -233
- package/connectors/connect-gptea/src/api/client.ts +20 -209
- package/connectors/connect-gptea/src/api/index.ts +23 -42
- package/connectors/connect-gptea/src/types/index.ts +6 -233
- package/connectors/connect-grain/src/api/client.ts +19 -206
- package/connectors/connect-grain/src/api/index.ts +29 -43
- package/connectors/connect-grain/src/types/index.ts +8 -233
- package/connectors/connect-grist/src/api/client.ts +18 -204
- package/connectors/connect-grist/src/api/index.ts +27 -43
- package/connectors/connect-grist/src/types/index.ts +10 -233
- package/connectors/connect-handwrytten/src/api/client.ts +18 -205
- package/connectors/connect-handwrytten/src/api/index.ts +23 -43
- package/connectors/connect-handwrytten/src/types/index.ts +8 -233
- package/connectors/connect-harrypotterapi/src/api/client.ts +9 -206
- package/connectors/connect-harrypotterapi/src/api/index.ts +15 -45
- package/connectors/connect-harrypotterapi/src/types/index.ts +5 -233
- package/connectors/connect-helcim/src/api/client.ts +20 -210
- package/connectors/connect-helcim/src/api/index.ts +38 -43
- package/connectors/connect-helcim/src/types/index.ts +15 -228
- package/connectors/connect-heysummit/src/api/client.ts +22 -209
- package/connectors/connect-heysummit/src/api/index.ts +23 -44
- package/connectors/connect-heysummit/src/types/index.ts +8 -233
- package/connectors/connect-hubplanner/src/api/client.ts +18 -205
- package/connectors/connect-hubplanner/src/api/index.ts +33 -42
- package/connectors/connect-hubplanner/src/types/index.ts +8 -233
- package/connectors/connect-huggingface/src/api/client.ts +5 -0
- package/connectors/connect-huggingface/src/api/datasets.ts +73 -0
- package/connectors/connect-huggingface/src/api/index.ts +17 -19
- package/connectors/connect-huggingface/src/api/inference.ts +199 -0
- package/connectors/connect-huggingface/src/api/models.ts +66 -0
- package/connectors/connect-huggingface/src/api/spaces.ts +42 -0
- package/connectors/connect-huggingface/src/cli/index.ts +148 -36
- package/connectors/connect-hunter/src/api/client.ts +14 -205
- package/connectors/connect-hunter/src/api/index.ts +25 -42
- package/connectors/connect-hunter/src/types/index.ts +8 -233
- package/connectors/connect-hybridanalysis/src/api/client.ts +24 -204
- package/connectors/connect-hybridanalysis/src/api/index.ts +24 -43
- package/connectors/connect-hybridanalysis/src/types/index.ts +7 -233
- package/connectors/connect-ideta/src/api/client.ts +18 -205
- package/connectors/connect-ideta/src/api/index.ts +25 -42
- package/connectors/connect-ideta/src/types/index.ts +8 -233
- package/connectors/connect-invoiced/src/api/client.ts +19 -208
- package/connectors/connect-invoiced/src/api/index.ts +22 -49
- package/connectors/connect-invoiced/src/types/index.ts +5 -237
- package/connectors/connect-ip2location/src/api/client.ts +14 -205
- package/connectors/connect-ip2location/src/api/index.ts +20 -43
- package/connectors/connect-ip2location/src/types/index.ts +5 -233
- package/connectors/connect-ipinfo/src/api/client.ts +16 -206
- package/connectors/connect-ipinfo/src/api/index.ts +21 -47
- package/connectors/connect-ipinfo/src/types/index.ts +6 -233
- package/connectors/connect-jasper/src/api/client.ts +18 -202
- package/connectors/connect-jasper/src/api/index.ts +41 -43
- package/connectors/connect-jasper/src/types/index.ts +7 -233
- package/connectors/connect-jenkins/src/api/client.ts +25 -205
- package/connectors/connect-jenkins/src/api/index.ts +38 -43
- package/connectors/connect-jenkins/src/types/index.ts +8 -233
- package/connectors/connect-jinaai/src/api/client.ts +21 -204
- package/connectors/connect-jinaai/src/api/index.ts +23 -42
- package/connectors/connect-jinaai/src/types/index.ts +9 -233
- package/connectors/connect-jira/src/api/client.ts +57 -0
- package/connectors/connect-jira/src/api/index.ts +22 -63
- package/connectors/connect-kafka/src/api/client.ts +27 -206
- package/connectors/connect-kafka/src/api/index.ts +29 -42
- package/connectors/connect-kafka/src/types/index.ts +9 -233
- package/connectors/connect-kaggle/src/api/client.ts +15 -205
- package/connectors/connect-kaggle/src/api/index.ts +27 -43
- package/connectors/connect-kaggle/src/types/index.ts +7 -233
- package/connectors/connect-kanbantool/src/api/client.ts +19 -205
- package/connectors/connect-kanbantool/src/api/index.ts +34 -43
- package/connectors/connect-kanbantool/src/types/index.ts +8 -233
- package/connectors/connect-keygen/src/api/client.ts +19 -205
- package/connectors/connect-keygen/src/api/index.ts +33 -43
- package/connectors/connect-keygen/src/types/index.ts +8 -233
- package/connectors/connect-kibana/src/api/client.ts +24 -204
- package/connectors/connect-kibana/src/api/index.ts +36 -42
- package/connectors/connect-kibana/src/types/index.ts +9 -233
- package/connectors/connect-lambdatest/src/api/client.ts +19 -206
- package/connectors/connect-lambdatest/src/api/index.ts +29 -44
- package/connectors/connect-lambdatest/src/types/index.ts +8 -233
- package/connectors/connect-laposta/src/api/client.ts +19 -206
- package/connectors/connect-laposta/src/api/index.ts +39 -42
- package/connectors/connect-laposta/src/types/index.ts +8 -233
- package/connectors/connect-launch27/src/api/client.ts +18 -207
- package/connectors/connect-launch27/src/api/index.ts +31 -42
- package/connectors/connect-launch27/src/types/index.ts +7 -233
- package/connectors/connect-leadboxer/src/api/client.ts +18 -205
- package/connectors/connect-leadboxer/src/api/index.ts +20 -44
- package/connectors/connect-leadboxer/src/types/index.ts +7 -233
- package/connectors/connect-leadpops/src/api/client.ts +18 -205
- package/connectors/connect-leadpops/src/api/index.ts +25 -45
- package/connectors/connect-leadpops/src/types/index.ts +7 -233
- package/connectors/connect-lighthouse/src/api/client.ts +18 -205
- package/connectors/connect-lighthouse/src/api/index.ts +33 -41
- package/connectors/connect-lighthouse/src/types/index.ts +9 -233
- package/connectors/connect-limego/src/api/client.ts +18 -205
- package/connectors/connect-limego/src/api/index.ts +25 -44
- package/connectors/connect-limego/src/types/index.ts +8 -233
- package/connectors/connect-line/src/api/client.ts +23 -205
- package/connectors/connect-line/src/api/index.ts +34 -44
- package/connectors/connect-line/src/types/index.ts +9 -233
- package/connectors/connect-linear/src/api/comments.ts +148 -0
- package/connectors/connect-linear/src/api/index.ts +8 -0
- package/connectors/connect-linear/src/api/states.ts +88 -0
- package/connectors/connect-linear/src/types/index.ts +68 -0
- package/connectors/connect-lingvanex/src/api/client.ts +19 -209
- package/connectors/connect-lingvanex/src/api/index.ts +24 -42
- package/connectors/connect-lingvanex/src/types/index.ts +7 -233
- package/connectors/connect-liveagent/src/api/client.ts +18 -204
- package/connectors/connect-liveagent/src/api/index.ts +34 -42
- package/connectors/connect-liveagent/src/types/index.ts +9 -233
- package/connectors/connect-loginradius/src/api/client.ts +23 -202
- package/connectors/connect-loginradius/src/api/index.ts +35 -43
- package/connectors/connect-loginradius/src/types/index.ts +9 -233
- package/connectors/connect-mailerlite/src/api/client.ts +18 -205
- package/connectors/connect-mailerlite/src/api/index.ts +35 -42
- package/connectors/connect-mailerlite/src/types/index.ts +9 -233
- package/connectors/connect-mailgun/src/api/client.ts +29 -201
- package/connectors/connect-mailgun/src/api/index.ts +37 -43
- package/connectors/connect-mailgun/src/types/index.ts +10 -233
- package/connectors/connect-malcore/src/api/client.ts +18 -205
- package/connectors/connect-malcore/src/api/index.ts +30 -43
- package/connectors/connect-malcore/src/types/index.ts +7 -233
- package/connectors/connect-marketplacer/src/api/client.ts +18 -204
- package/connectors/connect-marketplacer/src/api/index.ts +30 -44
- package/connectors/connect-marketplacer/src/types/index.ts +9 -233
- package/connectors/connect-matrix/src/api/client.ts +21 -204
- package/connectors/connect-matrix/src/api/index.ts +34 -41
- package/connectors/connect-matrix/src/types/index.ts +10 -233
- package/connectors/connect-mattermost/src/api/client.ts +19 -205
- package/connectors/connect-mattermost/src/api/index.ts +34 -42
- package/connectors/connect-mattermost/src/types/index.ts +8 -233
- package/connectors/connect-mem/src/api/client.ts +18 -205
- package/connectors/connect-mem/src/api/index.ts +20 -43
- package/connectors/connect-mem/src/types/index.ts +6 -233
- package/connectors/connect-mercury/CLAUDE.md +0 -1
- package/connectors/connect-microsoftentraid/src/api/client.ts +21 -205
- package/connectors/connect-microsoftentraid/src/api/index.ts +29 -44
- package/connectors/connect-microsoftentraid/src/types/index.ts +8 -233
- package/connectors/connect-microsoftentraidazureactivedirectory/src/api/client.ts +21 -205
- package/connectors/connect-microsoftentraidazureactivedirectory/src/api/index.ts +37 -44
- package/connectors/connect-microsoftentraidazureactivedirectory/src/types/index.ts +10 -233
- package/connectors/connect-microsoftgraphsecurity/src/api/client.ts +21 -205
- package/connectors/connect-microsoftgraphsecurity/src/api/index.ts +28 -43
- package/connectors/connect-microsoftgraphsecurity/src/types/index.ts +8 -233
- package/connectors/connect-microsoftonedrive/src/api/client.ts +21 -205
- package/connectors/connect-microsoftonedrive/src/api/index.ts +41 -41
- package/connectors/connect-microsoftonedrive/src/types/index.ts +8 -233
- package/connectors/connect-microsofttodo/src/api/client.ts +21 -205
- package/connectors/connect-microsofttodo/src/api/index.ts +35 -43
- package/connectors/connect-microsofttodo/src/types/index.ts +6 -233
- package/connectors/connect-miestro/src/api/client.ts +18 -205
- package/connectors/connect-miestro/src/api/index.ts +30 -43
- package/connectors/connect-miestro/src/types/index.ts +8 -233
- package/connectors/connect-miro/src/api/client.ts +19 -206
- package/connectors/connect-miro/src/api/index.ts +32 -41
- package/connectors/connect-miro/src/types/index.ts +10 -233
- package/connectors/connect-missive/src/api/client.ts +19 -206
- package/connectors/connect-missive/src/api/index.ts +35 -42
- package/connectors/connect-missive/src/types/index.ts +13 -235
- package/connectors/connect-mist/src/api/client.ts +19 -205
- package/connectors/connect-mist/src/api/index.ts +24 -43
- package/connectors/connect-mist/src/types/index.ts +8 -233
- package/connectors/connect-mistral/src/api/chat.ts +2 -1
- package/connectors/connect-mistral/src/api/embeddings.ts +2 -1
- package/connectors/connect-monday/src/api/index.ts +120 -1
- package/connectors/connect-moonmail/src/api/client.ts +18 -205
- package/connectors/connect-moonmail/src/api/index.ts +31 -43
- package/connectors/connect-moonmail/src/types/index.ts +7 -233
- package/connectors/connect-mxtoolbox/src/api/client.ts +15 -204
- package/connectors/connect-mxtoolbox/src/api/index.ts +25 -45
- package/connectors/connect-mxtoolbox/src/types/index.ts +10 -233
- package/connectors/connect-myaskai/src/api/client.ts +18 -205
- package/connectors/connect-myaskai/src/api/index.ts +28 -42
- package/connectors/connect-myaskai/src/types/index.ts +7 -233
- package/connectors/connect-myphoner/src/api/client.ts +18 -205
- package/connectors/connect-myphoner/src/api/index.ts +30 -43
- package/connectors/connect-myphoner/src/types/index.ts +8 -233
- package/connectors/connect-nanonetsocr/src/api/client.ts +19 -206
- package/connectors/connect-nanonetsocr/src/api/index.ts +22 -42
- package/connectors/connect-nanonetsocr/src/types/index.ts +8 -233
- package/connectors/connect-nocodb/src/api/client.ts +22 -208
- package/connectors/connect-nocodb/src/api/index.ts +40 -42
- package/connectors/connect-nocodb/src/types/index.ts +10 -233
- package/connectors/connect-npm/src/api/client.ts +22 -203
- package/connectors/connect-npm/src/api/index.ts +24 -43
- package/connectors/connect-npm/src/types/index.ts +8 -233
- package/connectors/connect-nuclia/src/api/client.ts +19 -205
- package/connectors/connect-nuclia/src/api/index.ts +32 -43
- package/connectors/connect-nuclia/src/types/index.ts +8 -233
- package/connectors/connect-nyota/src/api/client.ts +18 -205
- package/connectors/connect-nyota/src/api/index.ts +24 -43
- package/connectors/connect-nyota/src/types/index.ts +8 -233
- package/connectors/connect-offalerts/src/api/client.ts +18 -205
- package/connectors/connect-offalerts/src/api/index.ts +25 -44
- package/connectors/connect-offalerts/src/types/index.ts +7 -233
- package/connectors/connect-okta/src/api/client.ts +21 -204
- package/connectors/connect-okta/src/api/index.ts +40 -42
- package/connectors/connect-okta/src/types/index.ts +10 -233
- package/connectors/connect-omnimind/src/api/client.ts +18 -205
- package/connectors/connect-omnimind/src/api/index.ts +31 -43
- package/connectors/connect-omnimind/src/types/index.ts +7 -233
- package/connectors/connect-on2air/src/api/client.ts +18 -205
- package/connectors/connect-on2air/src/api/index.ts +26 -44
- package/connectors/connect-on2air/src/types/index.ts +7 -233
- package/connectors/connect-oneai/src/api/client.ts +19 -209
- package/connectors/connect-oneai/src/api/index.ts +36 -39
- package/connectors/connect-oneai/src/types/index.ts +7 -233
- package/connectors/connect-onesimpleapi/src/api/client.ts +17 -204
- package/connectors/connect-onesimpleapi/src/api/index.ts +30 -43
- package/connectors/connect-onesimpleapi/src/types/index.ts +8 -233
- package/connectors/connect-openai/src/api/chat.ts +2 -2
- package/connectors/connect-openai/src/api/images.ts +52 -8
- package/connectors/connect-openai/src/types/index.ts +0 -10
- package/connectors/connect-ortto/src/api/client.ts +19 -204
- package/connectors/connect-ortto/src/api/index.ts +28 -44
- package/connectors/connect-ortto/src/types/index.ts +9 -233
- package/connectors/connect-oura/src/api/client.ts +16 -205
- package/connectors/connect-oura/src/api/index.ts +25 -42
- package/connectors/connect-oura/src/types/index.ts +9 -233
- package/connectors/connect-papyrs/src/api/client.ts +18 -204
- package/connectors/connect-papyrs/src/api/index.ts +30 -43
- package/connectors/connect-papyrs/src/types/index.ts +8 -233
- package/connectors/connect-paymo/src/api/client.ts +19 -206
- package/connectors/connect-paymo/src/api/index.ts +34 -43
- package/connectors/connect-paymo/src/types/index.ts +9 -233
- package/connectors/connect-personalai/src/api/client.ts +18 -205
- package/connectors/connect-personalai/src/api/index.ts +26 -43
- package/connectors/connect-personalai/src/types/index.ts +8 -233
- package/connectors/connect-phantombuster/src/api/client.ts +18 -205
- package/connectors/connect-phantombuster/src/api/index.ts +28 -43
- package/connectors/connect-phantombuster/src/types/index.ts +6 -233
- package/connectors/connect-planyoonlinebooking/src/api/client.ts +19 -209
- package/connectors/connect-planyoonlinebooking/src/api/index.ts +34 -43
- package/connectors/connect-planyoonlinebooking/src/types/index.ts +8 -233
- package/connectors/connect-plivo/src/api/client.ts +22 -208
- package/connectors/connect-plivo/src/api/index.ts +32 -44
- package/connectors/connect-plivo/src/types/index.ts +9 -233
- package/connectors/connect-posthog/src/api/client.ts +22 -205
- package/connectors/connect-posthog/src/api/index.ts +65 -39
- package/connectors/connect-posthog/src/types/index.ts +8 -233
- package/connectors/connect-practitest/src/api/client.ts +19 -206
- package/connectors/connect-practitest/src/api/index.ts +36 -40
- package/connectors/connect-practitest/src/types/index.ts +9 -233
- package/connectors/connect-predisai/src/api/client.ts +18 -205
- package/connectors/connect-predisai/src/api/index.ts +25 -43
- package/connectors/connect-predisai/src/types/index.ts +7 -233
- package/connectors/connect-prodia/src/api/client.ts +18 -205
- package/connectors/connect-prodia/src/api/index.ts +26 -43
- package/connectors/connect-prodia/src/types/index.ts +7 -233
- package/connectors/connect-profitwell/src/api/client.ts +18 -205
- package/connectors/connect-profitwell/src/api/index.ts +28 -44
- package/connectors/connect-profitwell/src/types/index.ts +7 -233
- package/connectors/connect-projectbubbleproprofsproject/src/api/client.ts +18 -205
- package/connectors/connect-projectbubbleproprofsproject/src/api/index.ts +32 -43
- package/connectors/connect-projectbubbleproprofsproject/src/types/index.ts +8 -233
- package/connectors/connect-pulsetic/src/api/client.ts +18 -205
- package/connectors/connect-pulsetic/src/api/index.ts +25 -43
- package/connectors/connect-pulsetic/src/types/index.ts +8 -233
- package/connectors/connect-pusher/src/api/client.ts +36 -205
- package/connectors/connect-pusher/src/api/index.ts +29 -41
- package/connectors/connect-pusher/src/types/index.ts +8 -233
- package/connectors/connect-pushover/src/api/client.ts +24 -207
- package/connectors/connect-pushover/src/api/index.ts +27 -46
- package/connectors/connect-pushover/src/types/index.ts +5 -237
- package/connectors/connect-qualys/src/api/client.ts +21 -205
- package/connectors/connect-qualys/src/api/index.ts +35 -42
- package/connectors/connect-qualys/src/types/index.ts +8 -233
- package/connectors/connect-quentn/src/api/client.ts +18 -204
- package/connectors/connect-quentn/src/api/index.ts +35 -44
- package/connectors/connect-quentn/src/types/index.ts +9 -233
- package/connectors/connect-questdb/src/api/client.ts +22 -204
- package/connectors/connect-questdb/src/api/index.ts +35 -43
- package/connectors/connect-questdb/src/types/index.ts +7 -233
- package/connectors/connect-quintadb/src/api/client.ts +21 -207
- package/connectors/connect-quintadb/src/api/index.ts +32 -43
- package/connectors/connect-quintadb/src/types/index.ts +6 -233
- package/connectors/connect-rapid7insightvm/src/api/client.ts +19 -205
- package/connectors/connect-rapid7insightvm/src/api/index.ts +34 -42
- package/connectors/connect-rapid7insightvm/src/types/index.ts +9 -233
- package/connectors/connect-raventools/src/api/client.ts +20 -209
- package/connectors/connect-raventools/src/api/index.ts +24 -44
- package/connectors/connect-raventools/src/types/index.ts +8 -233
- package/connectors/connect-rdstationcrm/src/api/client.ts +20 -206
- package/connectors/connect-rdstationcrm/src/api/index.ts +34 -43
- package/connectors/connect-rdstationcrm/src/types/index.ts +9 -233
- package/connectors/connect-realphonevalidation/src/api/client.ts +15 -205
- package/connectors/connect-realphonevalidation/src/api/index.ts +21 -43
- package/connectors/connect-realphonevalidation/src/types/index.ts +5 -233
- package/connectors/connect-recharge/src/api/client.ts +19 -206
- package/connectors/connect-recharge/src/api/index.ts +35 -42
- package/connectors/connect-recharge/src/types/index.ts +10 -233
- package/connectors/connect-relevanceai/src/api/client.ts +21 -204
- package/connectors/connect-relevanceai/src/api/index.ts +28 -41
- package/connectors/connect-relevanceai/src/types/index.ts +8 -233
- package/connectors/connect-relinkurlshortener/src/api/client.ts +18 -205
- package/connectors/connect-relinkurlshortener/src/api/index.ts +25 -44
- package/connectors/connect-relinkurlshortener/src/types/index.ts +6 -233
- package/connectors/connect-reply/src/api/client.ts +18 -205
- package/connectors/connect-reply/src/api/index.ts +31 -44
- package/connectors/connect-reply/src/types/index.ts +9 -233
- package/connectors/connect-ritekit/src/api/client.ts +15 -206
- package/connectors/connect-ritekit/src/api/index.ts +32 -43
- package/connectors/connect-ritekit/src/types/index.ts +7 -233
- package/connectors/connect-rocketchat/src/api/client.ts +20 -205
- package/connectors/connect-rocketchat/src/api/index.ts +39 -41
- package/connectors/connect-rocketchat/src/types/index.ts +8 -233
- package/connectors/connect-rundeck/src/api/client.ts +20 -205
- package/connectors/connect-rundeck/src/api/index.ts +30 -43
- package/connectors/connect-rundeck/src/types/index.ts +8 -233
- package/connectors/connect-salesforce/src/api/client.ts +49 -0
- package/connectors/connect-salesforce/src/api/index.ts +18 -15
- package/connectors/connect-samsungsmartthings/src/api/client.ts +19 -206
- package/connectors/connect-samsungsmartthings/src/api/index.ts +26 -44
- package/connectors/connect-samsungsmartthings/src/types/index.ts +10 -233
- package/connectors/connect-scrapeitcloud/src/api/client.ts +18 -205
- package/connectors/connect-scrapeitcloud/src/api/index.ts +22 -43
- package/connectors/connect-scrapeitcloud/src/types/index.ts +7 -233
- package/connectors/connect-seamlessai/src/api/client.ts +18 -205
- package/connectors/connect-seamlessai/src/api/index.ts +28 -43
- package/connectors/connect-seamlessai/src/types/index.ts +8 -233
- package/connectors/connect-sekoia/src/api/client.ts +18 -205
- package/connectors/connect-sekoia/src/api/index.ts +31 -41
- package/connectors/connect-sekoia/src/types/index.ts +9 -233
- package/connectors/connect-sellix/src/api/client.ts +18 -205
- package/connectors/connect-sellix/src/api/index.ts +32 -42
- package/connectors/connect-sellix/src/types/index.ts +10 -233
- package/connectors/connect-servicenow/src/api/client.ts +21 -204
- package/connectors/connect-servicenow/src/api/index.ts +45 -41
- package/connectors/connect-servicenow/src/types/index.ts +9 -233
- package/connectors/connect-shopify/src/api/products.ts +79 -2
- package/connectors/connect-shuffler/src/api/client.ts +18 -204
- package/connectors/connect-shuffler/src/api/index.ts +29 -44
- package/connectors/connect-shuffler/src/types/index.ts +8 -233
- package/connectors/connect-signaturit/src/api/client.ts +19 -205
- package/connectors/connect-signaturit/src/api/index.ts +30 -42
- package/connectors/connect-signaturit/src/types/index.ts +10 -233
- package/connectors/connect-simplehash/src/api/client.ts +14 -204
- package/connectors/connect-simplehash/src/api/index.ts +29 -43
- package/connectors/connect-simplehash/src/types/index.ts +7 -233
- package/connectors/connect-simplelocalize/src/api/client.ts +18 -205
- package/connectors/connect-simplelocalize/src/api/index.ts +33 -42
- package/connectors/connect-simplelocalize/src/types/index.ts +13 -235
- package/connectors/connect-sitespeakai/src/api/client.ts +18 -205
- package/connectors/connect-sitespeakai/src/api/index.ts +29 -41
- package/connectors/connect-sitespeakai/src/types/index.ts +8 -233
- package/connectors/connect-smaily/src/api/client.ts +19 -205
- package/connectors/connect-smaily/src/api/index.ts +29 -44
- package/connectors/connect-smaily/src/types/index.ts +8 -233
- package/connectors/connect-snatchbot/src/api/client.ts +19 -206
- package/connectors/connect-snatchbot/src/api/index.ts +25 -42
- package/connectors/connect-snatchbot/src/types/index.ts +8 -233
- package/connectors/connect-solvedata/src/api/client.ts +18 -205
- package/connectors/connect-solvedata/src/api/index.ts +26 -43
- package/connectors/connect-solvedata/src/types/index.ts +7 -233
- package/connectors/connect-specter/src/api/client.ts +24 -209
- package/connectors/connect-specter/src/api/index.ts +27 -43
- package/connectors/connect-specter/src/types/index.ts +10 -233
- package/connectors/connect-spike/src/api/client.ts +18 -205
- package/connectors/connect-spike/src/api/index.ts +28 -45
- package/connectors/connect-spike/src/types/index.ts +8 -233
- package/connectors/connect-sportsdata/src/api/client.ts +14 -206
- package/connectors/connect-sportsdata/src/api/index.ts +32 -46
- package/connectors/connect-sportsdata/src/types/index.ts +8 -233
- package/connectors/connect-sslmatecertspotterapi/src/api/client.ts +15 -204
- package/connectors/connect-sslmatecertspotterapi/src/api/index.ts +23 -43
- package/connectors/connect-sslmatecertspotterapi/src/types/index.ts +5 -233
- package/connectors/connect-starton/src/api/client.ts +18 -205
- package/connectors/connect-starton/src/api/index.ts +34 -42
- package/connectors/connect-starton/src/types/index.ts +8 -233
- package/connectors/connect-statuscake/src/api/client.ts +18 -205
- package/connectors/connect-statuscake/src/api/index.ts +30 -44
- package/connectors/connect-statuscake/src/types/index.ts +9 -233
- package/connectors/connect-strapi/src/api/client.ts +21 -204
- package/connectors/connect-strapi/src/api/index.ts +38 -42
- package/connectors/connect-strapi/src/types/index.ts +9 -233
- package/connectors/connect-supernormal/src/api/client.ts +18 -205
- package/connectors/connect-supernormal/src/api/index.ts +28 -43
- package/connectors/connect-supernormal/src/types/index.ts +8 -233
- package/connectors/connect-supportivekoala/src/api/client.ts +18 -205
- package/connectors/connect-supportivekoala/src/api/index.ts +21 -43
- package/connectors/connect-supportivekoala/src/types/index.ts +7 -233
- package/connectors/connect-surveysparrow/src/api/client.ts +20 -210
- package/connectors/connect-surveysparrow/src/api/index.ts +39 -42
- package/connectors/connect-surveysparrow/src/types/index.ts +7 -233
- package/connectors/connect-swagup/src/api/client.ts +18 -205
- package/connectors/connect-swagup/src/api/index.ts +30 -42
- package/connectors/connect-swagup/src/types/index.ts +8 -233
- package/connectors/connect-switchboard/src/api/client.ts +18 -205
- package/connectors/connect-switchboard/src/api/index.ts +27 -43
- package/connectors/connect-switchboard/src/types/index.ts +7 -233
- package/connectors/connect-syncly/src/api/client.ts +18 -205
- package/connectors/connect-syncly/src/api/index.ts +21 -44
- package/connectors/connect-syncly/src/types/index.ts +8 -233
- package/connectors/connect-syncromsp/src/api/client.ts +19 -204
- package/connectors/connect-syncromsp/src/api/index.ts +35 -42
- package/connectors/connect-syncromsp/src/types/index.ts +8 -233
- package/connectors/connect-talentlms/src/api/client.ts +19 -205
- package/connectors/connect-talentlms/src/api/index.ts +30 -42
- package/connectors/connect-talentlms/src/types/index.ts +8 -233
- package/connectors/connect-tdameritrade/src/api/client.ts +22 -205
- package/connectors/connect-tdameritrade/src/api/index.ts +32 -41
- package/connectors/connect-tdameritrade/src/types/index.ts +9 -233
- package/connectors/connect-teamdeck/src/api/client.ts +20 -210
- package/connectors/connect-teamdeck/src/api/index.ts +39 -41
- package/connectors/connect-teamdeck/src/types/index.ts +8 -233
- package/connectors/connect-teamgate/src/api/client.ts +21 -206
- package/connectors/connect-teamgate/src/api/index.ts +37 -43
- package/connectors/connect-teamgate/src/types/index.ts +9 -233
- package/connectors/connect-teamup/src/api/client.ts +24 -209
- package/connectors/connect-teamup/src/api/index.ts +25 -45
- package/connectors/connect-teamup/src/types/index.ts +6 -233
- package/connectors/connect-testmonitor/src/api/client.ts +19 -205
- package/connectors/connect-testmonitor/src/api/index.ts +38 -42
- package/connectors/connect-testmonitor/src/types/index.ts +8 -233
- package/connectors/connect-textcortexai/src/api/client.ts +18 -205
- package/connectors/connect-textcortexai/src/api/index.ts +33 -43
- package/connectors/connect-textcortexai/src/types/index.ts +7 -233
- package/connectors/connect-textmagic/src/api/client.ts +20 -205
- package/connectors/connect-textmagic/src/api/index.ts +34 -43
- package/connectors/connect-textmagic/src/types/index.ts +9 -233
- package/connectors/connect-thankster/src/api/client.ts +18 -205
- package/connectors/connect-thankster/src/api/index.ts +27 -43
- package/connectors/connect-thankster/src/types/index.ts +8 -233
- package/connectors/connect-thecustomerfactor/src/api/client.ts +18 -205
- package/connectors/connect-thecustomerfactor/src/api/index.ts +34 -42
- package/connectors/connect-thecustomerfactor/src/types/index.ts +7 -233
- package/connectors/connect-theleap/src/api/client.ts +18 -205
- package/connectors/connect-theleap/src/api/index.ts +23 -43
- package/connectors/connect-theleap/src/types/index.ts +6 -233
- package/connectors/connect-thoughtfulgpt/src/api/client.ts +18 -205
- package/connectors/connect-thoughtfulgpt/src/api/index.ts +22 -44
- package/connectors/connect-thoughtfulgpt/src/types/index.ts +7 -233
- package/connectors/connect-tilda/src/api/client.ts +18 -206
- package/connectors/connect-tilda/src/api/index.ts +22 -46
- package/connectors/connect-tilda/src/types/index.ts +7 -233
- package/connectors/connect-tisanelabs/src/api/client.ts +13 -206
- package/connectors/connect-tisanelabs/src/api/index.ts +26 -41
- package/connectors/connect-tisanelabs/src/types/index.ts +8 -233
- package/connectors/connect-trackvia/src/api/client.ts +22 -206
- package/connectors/connect-trackvia/src/api/index.ts +35 -43
- package/connectors/connect-trackvia/src/types/index.ts +9 -233
- package/connectors/connect-travisci/src/api/client.ts +19 -205
- package/connectors/connect-travisci/src/api/index.ts +28 -43
- package/connectors/connect-travisci/src/types/index.ts +7 -233
- package/connectors/connect-turbohire/src/api/client.ts +18 -205
- package/connectors/connect-turbohire/src/api/index.ts +34 -42
- package/connectors/connect-turbohire/src/types/index.ts +8 -233
- package/connectors/connect-tuskr/src/api/client.ts +19 -206
- package/connectors/connect-tuskr/src/api/index.ts +37 -42
- package/connectors/connect-tuskr/src/types/index.ts +8 -233
- package/connectors/connect-unisender/src/api/client.ts +19 -209
- package/connectors/connect-unisender/src/api/index.ts +37 -42
- package/connectors/connect-unisender/src/types/index.ts +10 -233
- package/connectors/connect-uproc/src/api/client.ts +18 -205
- package/connectors/connect-uproc/src/api/index.ts +25 -43
- package/connectors/connect-uproc/src/types/index.ts +7 -233
- package/connectors/connect-uptimerobot/src/api/client.ts +22 -208
- package/connectors/connect-uptimerobot/src/api/index.ts +43 -39
- package/connectors/connect-uptimerobot/src/types/index.ts +8 -233
- package/connectors/connect-uservoice/src/api/client.ts +19 -205
- package/connectors/connect-uservoice/src/api/index.ts +31 -43
- package/connectors/connect-uservoice/src/types/index.ts +13 -235
- package/connectors/connect-verifalia/src/api/client.ts +20 -206
- package/connectors/connect-verifalia/src/api/index.ts +31 -41
- package/connectors/connect-verifalia/src/types/index.ts +6 -233
- package/connectors/connect-virustotal/src/api/client.ts +21 -204
- package/connectors/connect-virustotal/src/api/index.ts +27 -42
- package/connectors/connect-virustotal/src/types/index.ts +8 -233
- package/connectors/connect-vivifyscrum/src/api/client.ts +19 -206
- package/connectors/connect-vivifyscrum/src/api/index.ts +28 -44
- package/connectors/connect-vivifyscrum/src/types/index.ts +9 -233
- package/connectors/connect-voicit/src/api/client.ts +18 -205
- package/connectors/connect-voicit/src/api/index.ts +19 -45
- package/connectors/connect-voicit/src/types/index.ts +7 -233
- package/connectors/connect-vowel/src/api/client.ts +18 -205
- package/connectors/connect-vowel/src/api/index.ts +22 -44
- package/connectors/connect-vowel/src/types/index.ts +8 -233
- package/connectors/connect-watchsignals/src/api/client.ts +15 -205
- package/connectors/connect-watchsignals/src/api/index.ts +24 -42
- package/connectors/connect-watchsignals/src/types/index.ts +8 -233
- package/connectors/connect-wavelineextract/src/api/client.ts +18 -205
- package/connectors/connect-wavelineextract/src/api/index.ts +21 -45
- package/connectors/connect-wavelineextract/src/types/index.ts +6 -233
- package/connectors/connect-webinarjam/src/api/client.ts +15 -206
- package/connectors/connect-webinarjam/src/api/index.ts +18 -44
- package/connectors/connect-webinarjam/src/types/index.ts +6 -233
- package/connectors/connect-wikipedia/src/api/client.ts +22 -202
- package/connectors/connect-wikipedia/src/api/index.ts +49 -43
- package/connectors/connect-wikipedia/src/types/index.ts +22 -228
- package/connectors/connect-wubookratechecker/src/api/client.ts +14 -204
- package/connectors/connect-wubookratechecker/src/api/index.ts +18 -46
- package/connectors/connect-wubookratechecker/src/types/index.ts +6 -233
- package/connectors/connect-xai/src/api/chat.ts +2 -1
- package/connectors/connect-yodiz/src/api/client.ts +20 -205
- package/connectors/connect-yodiz/src/api/index.ts +36 -41
- package/connectors/connect-yodiz/src/types/index.ts +8 -233
- package/connectors/connect-yourls/src/api/client.ts +25 -211
- package/connectors/connect-yourls/src/api/index.ts +33 -41
- package/connectors/connect-yourls/src/types/index.ts +7 -233
- package/connectors/connect-zammad/src/api/client.ts +19 -208
- package/connectors/connect-zammad/src/api/index.ts +32 -44
- package/connectors/connect-zammad/src/types/index.ts +8 -233
- package/connectors/connect-zohobooks/src/api/client.ts +21 -205
- package/connectors/connect-zohobooks/src/api/index.ts +36 -42
- package/connectors/connect-zohobooks/src/types/index.ts +10 -233
- package/connectors/connect-zohocrm/src/api/client.ts +21 -204
- package/connectors/connect-zohocrm/src/api/index.ts +36 -41
- package/connectors/connect-zohocrm/src/types/index.ts +10 -233
- package/connectors/connect-zohoworkdrive/src/api/client.ts +24 -206
- package/connectors/connect-zohoworkdrive/src/api/index.ts +31 -42
- package/connectors/connect-zohoworkdrive/src/types/index.ts +7 -233
- package/connectors/connect-zoom/src/api/users.ts +95 -1
- package/connectors/connect-zulip/src/api/client.ts +22 -206
- package/connectors/connect-zulip/src/api/index.ts +35 -44
- package/connectors/connect-zulip/src/types/index.ts +7 -233
- package/dist/db/agents.d.ts +38 -0
- package/dist/db/agents.test.d.ts +1 -0
- package/dist/db/database.d.ts +7 -0
- package/dist/db/jobs.d.ts +53 -0
- package/dist/db/jobs.test.d.ts +1 -0
- package/dist/db/locks.d.ts +59 -0
- package/dist/db/locks.test.d.ts +1 -0
- package/dist/db/promotions.d.ts +5 -0
- package/dist/db/promotions.test.d.ts +1 -0
- package/dist/db/rate.d.ts +57 -0
- package/dist/db/rate.test.d.ts +1 -0
- package/dist/db/usage.d.ts +17 -0
- package/dist/db/usage.test.d.ts +1 -0
- package/dist/db/workflows.d.ts +26 -0
- package/dist/db/workflows.test.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +312 -22
- package/dist/lib/fuzzy.d.ts +16 -0
- package/dist/lib/fuzzy.test.d.ts +1 -0
- package/dist/lib/installer.d.ts +6 -7
- package/dist/lib/llm.d.ts +38 -0
- package/dist/lib/llm.test.d.ts +1 -0
- package/dist/lib/lock.d.ts +22 -0
- package/dist/lib/lock.test.d.ts +1 -0
- package/dist/lib/registry.d.ts +22 -1
- package/dist/lib/scheduler.d.ts +20 -0
- package/dist/lib/scheduler.test.d.ts +1 -0
- package/dist/lib/strip.d.ts +20 -0
- package/dist/lib/strip.test.d.ts +1 -0
- package/dist/lib/synonyms.d.ts +12 -0
- package/dist/lib/synonyms.test.d.ts +1 -0
- package/dist/lib/workflow-runner.d.ts +22 -0
- package/dist/server/auth.d.ts +4 -2
- package/package.json +2 -1
- package/connectors/connect-huggingface/src/api/example.ts +0 -48
- package/connectors/connect-yousign/CLAUDE.md +0 -48
- package/connectors/connect-yousign/package.json +0 -52
- package/connectors/connect-yousign/src/api/client.ts +0 -119
- package/connectors/connect-yousign/src/api/index.ts +0 -221
- package/connectors/connect-yousign/src/cli/index.ts +0 -555
- package/connectors/connect-yousign/src/index.ts +0 -21
- package/connectors/connect-yousign/src/types/index.ts +0 -275
- package/connectors/connect-yousign/src/utils/config.ts +0 -121
- package/connectors/connect-yousign/tsconfig.json +0 -16
package/bin/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __create = Object.create;
|
|
|
4
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __toESM = (mod, isNodeMode, target) => {
|
|
9
10
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
@@ -16,6 +17,20 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
16
17
|
});
|
|
17
18
|
return to;
|
|
18
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
19
34
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
35
|
var __export = (target, all) => {
|
|
21
36
|
for (var name in all)
|
|
@@ -1868,16 +1883,820 @@ var require_commander = __commonJS((exports) => {
|
|
|
1868
1883
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
1869
1884
|
});
|
|
1870
1885
|
|
|
1886
|
+
// src/lib/llm.ts
|
|
1887
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
1888
|
+
import { join } from "path";
|
|
1889
|
+
import { homedir } from "os";
|
|
1890
|
+
function getLlmConfigPath() {
|
|
1891
|
+
return join(homedir(), ".connectors", "llm.json");
|
|
1892
|
+
}
|
|
1893
|
+
function getLlmConfig() {
|
|
1894
|
+
const path = getLlmConfigPath();
|
|
1895
|
+
if (!existsSync(path))
|
|
1896
|
+
return null;
|
|
1897
|
+
try {
|
|
1898
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
1899
|
+
} catch {
|
|
1900
|
+
return null;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
function saveLlmConfig(config) {
|
|
1904
|
+
const dir = join(homedir(), ".connectors");
|
|
1905
|
+
mkdirSync(dir, { recursive: true });
|
|
1906
|
+
writeFileSync(getLlmConfigPath(), JSON.stringify(config, null, 2));
|
|
1907
|
+
}
|
|
1908
|
+
function setLlmStrip(enabled) {
|
|
1909
|
+
const config = getLlmConfig();
|
|
1910
|
+
if (!config)
|
|
1911
|
+
throw new Error("No LLM config found. Run: connectors llm set --provider <provider> --key <key>");
|
|
1912
|
+
saveLlmConfig({ ...config, strip: enabled });
|
|
1913
|
+
}
|
|
1914
|
+
function maskKey(key) {
|
|
1915
|
+
if (key.length <= 8)
|
|
1916
|
+
return "***";
|
|
1917
|
+
return key.slice(0, 8) + "***";
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
class LLMClient {
|
|
1921
|
+
config;
|
|
1922
|
+
constructor(config) {
|
|
1923
|
+
this.config = config;
|
|
1924
|
+
}
|
|
1925
|
+
static fromConfig() {
|
|
1926
|
+
const config = getLlmConfig();
|
|
1927
|
+
if (!config)
|
|
1928
|
+
return null;
|
|
1929
|
+
return new LLMClient(config);
|
|
1930
|
+
}
|
|
1931
|
+
async complete(prompt, content) {
|
|
1932
|
+
const start = Date.now();
|
|
1933
|
+
const { provider, model, api_key } = this.config;
|
|
1934
|
+
if (provider === "anthropic") {
|
|
1935
|
+
return this._anthropicComplete(prompt, content, start);
|
|
1936
|
+
}
|
|
1937
|
+
const baseUrl = PROVIDER_BASE_URLS[provider];
|
|
1938
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
1939
|
+
method: "POST",
|
|
1940
|
+
headers: {
|
|
1941
|
+
"Content-Type": "application/json",
|
|
1942
|
+
Authorization: `Bearer ${api_key}`
|
|
1943
|
+
},
|
|
1944
|
+
body: JSON.stringify({
|
|
1945
|
+
model,
|
|
1946
|
+
messages: [
|
|
1947
|
+
{ role: "system", content: prompt },
|
|
1948
|
+
{ role: "user", content }
|
|
1949
|
+
],
|
|
1950
|
+
temperature: 0,
|
|
1951
|
+
max_tokens: 4096
|
|
1952
|
+
})
|
|
1953
|
+
});
|
|
1954
|
+
if (!response.ok) {
|
|
1955
|
+
const error = await response.text();
|
|
1956
|
+
throw new Error(`LLM request failed (${provider} ${response.status}): ${error}`);
|
|
1957
|
+
}
|
|
1958
|
+
const data = await response.json();
|
|
1959
|
+
return {
|
|
1960
|
+
content: data.choices[0].message.content,
|
|
1961
|
+
provider,
|
|
1962
|
+
model,
|
|
1963
|
+
latency_ms: Date.now() - start
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
async _anthropicComplete(prompt, content, start) {
|
|
1967
|
+
const { model, api_key } = this.config;
|
|
1968
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1969
|
+
method: "POST",
|
|
1970
|
+
headers: {
|
|
1971
|
+
"Content-Type": "application/json",
|
|
1972
|
+
"x-api-key": api_key,
|
|
1973
|
+
"anthropic-version": "2023-06-01"
|
|
1974
|
+
},
|
|
1975
|
+
body: JSON.stringify({
|
|
1976
|
+
model,
|
|
1977
|
+
system: prompt,
|
|
1978
|
+
messages: [{ role: "user", content }],
|
|
1979
|
+
max_tokens: 4096
|
|
1980
|
+
})
|
|
1981
|
+
});
|
|
1982
|
+
if (!response.ok) {
|
|
1983
|
+
const error = await response.text();
|
|
1984
|
+
throw new Error(`LLM request failed (anthropic ${response.status}): ${error}`);
|
|
1985
|
+
}
|
|
1986
|
+
const data = await response.json();
|
|
1987
|
+
return {
|
|
1988
|
+
content: data.content[0].text,
|
|
1989
|
+
provider: "anthropic",
|
|
1990
|
+
model,
|
|
1991
|
+
latency_ms: Date.now() - start
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
var PROVIDER_BASE_URLS, PROVIDER_DEFAULTS;
|
|
1996
|
+
var init_llm = __esm(() => {
|
|
1997
|
+
PROVIDER_BASE_URLS = {
|
|
1998
|
+
cerebras: "https://api.cerebras.ai/v1",
|
|
1999
|
+
groq: "https://api.groq.com/openai/v1",
|
|
2000
|
+
openai: "https://api.openai.com/v1"
|
|
2001
|
+
};
|
|
2002
|
+
PROVIDER_DEFAULTS = {
|
|
2003
|
+
cerebras: { model: "qwen-3-32b" },
|
|
2004
|
+
groq: { model: "llama-3.3-70b-versatile" },
|
|
2005
|
+
openai: { model: "gpt-4o-mini" },
|
|
2006
|
+
anthropic: { model: "claude-haiku-4-5-20251001" }
|
|
2007
|
+
};
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
// src/db/database.ts
|
|
2011
|
+
var exports_database = {};
|
|
2012
|
+
__export(exports_database, {
|
|
2013
|
+
shortUuid: () => shortUuid,
|
|
2014
|
+
now: () => now,
|
|
2015
|
+
getDatabase: () => getDatabase,
|
|
2016
|
+
closeDatabase: () => closeDatabase
|
|
2017
|
+
});
|
|
2018
|
+
import { Database } from "bun:sqlite";
|
|
2019
|
+
import { join as join2 } from "path";
|
|
2020
|
+
import { homedir as homedir2 } from "os";
|
|
2021
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
2022
|
+
function getDatabase(path) {
|
|
2023
|
+
if (_db)
|
|
2024
|
+
return _db;
|
|
2025
|
+
const dbPath = path ?? DB_PATH;
|
|
2026
|
+
mkdirSync2(join2(dbPath, ".."), { recursive: true });
|
|
2027
|
+
_db = new Database(dbPath);
|
|
2028
|
+
_db.run("PRAGMA journal_mode = WAL");
|
|
2029
|
+
migrate(_db);
|
|
2030
|
+
return _db;
|
|
2031
|
+
}
|
|
2032
|
+
function closeDatabase() {
|
|
2033
|
+
_db?.close();
|
|
2034
|
+
_db = null;
|
|
2035
|
+
}
|
|
2036
|
+
function now() {
|
|
2037
|
+
return new Date().toISOString();
|
|
2038
|
+
}
|
|
2039
|
+
function shortUuid() {
|
|
2040
|
+
return crypto.randomUUID().slice(0, 8);
|
|
2041
|
+
}
|
|
2042
|
+
function migrate(db) {
|
|
2043
|
+
db.run(`
|
|
2044
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
2045
|
+
id TEXT PRIMARY KEY,
|
|
2046
|
+
name TEXT UNIQUE NOT NULL,
|
|
2047
|
+
session_id TEXT,
|
|
2048
|
+
role TEXT NOT NULL DEFAULT 'agent',
|
|
2049
|
+
last_seen_at TEXT NOT NULL,
|
|
2050
|
+
created_at TEXT NOT NULL
|
|
2051
|
+
)
|
|
2052
|
+
`);
|
|
2053
|
+
db.run(`
|
|
2054
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
2055
|
+
id TEXT PRIMARY KEY,
|
|
2056
|
+
resource_type TEXT NOT NULL CHECK(resource_type IN ('connector', 'agent', 'profile', 'token')),
|
|
2057
|
+
resource_id TEXT NOT NULL,
|
|
2058
|
+
agent_id TEXT NOT NULL,
|
|
2059
|
+
lock_type TEXT NOT NULL DEFAULT 'exclusive' CHECK(lock_type IN ('advisory', 'exclusive')),
|
|
2060
|
+
locked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2061
|
+
expires_at TEXT NOT NULL
|
|
2062
|
+
)
|
|
2063
|
+
`);
|
|
2064
|
+
db.run(`
|
|
2065
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_resource_locks_exclusive
|
|
2066
|
+
ON resource_locks(resource_type, resource_id)
|
|
2067
|
+
WHERE lock_type = 'exclusive'
|
|
2068
|
+
`);
|
|
2069
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id)`);
|
|
2070
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_expires ON resource_locks(expires_at)`);
|
|
2071
|
+
db.run(`
|
|
2072
|
+
CREATE TABLE IF NOT EXISTS connector_rate_usage (
|
|
2073
|
+
agent_id TEXT NOT NULL,
|
|
2074
|
+
connector TEXT NOT NULL,
|
|
2075
|
+
window_start TEXT NOT NULL,
|
|
2076
|
+
call_count INTEGER NOT NULL DEFAULT 0,
|
|
2077
|
+
PRIMARY KEY (agent_id, connector, window_start)
|
|
2078
|
+
)
|
|
2079
|
+
`);
|
|
2080
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_rate_usage_window ON connector_rate_usage(connector, window_start)`);
|
|
2081
|
+
db.run(`
|
|
2082
|
+
CREATE TABLE IF NOT EXISTS connector_jobs (
|
|
2083
|
+
id TEXT PRIMARY KEY,
|
|
2084
|
+
name TEXT UNIQUE NOT NULL,
|
|
2085
|
+
connector TEXT NOT NULL,
|
|
2086
|
+
command TEXT NOT NULL,
|
|
2087
|
+
args TEXT NOT NULL DEFAULT '[]',
|
|
2088
|
+
cron TEXT NOT NULL,
|
|
2089
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
2090
|
+
strip INTEGER NOT NULL DEFAULT 0,
|
|
2091
|
+
created_at TEXT NOT NULL,
|
|
2092
|
+
last_run_at TEXT
|
|
2093
|
+
)
|
|
2094
|
+
`);
|
|
2095
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_jobs_enabled ON connector_jobs(enabled)`);
|
|
2096
|
+
db.run(`
|
|
2097
|
+
CREATE TABLE IF NOT EXISTS connector_job_runs (
|
|
2098
|
+
id TEXT PRIMARY KEY,
|
|
2099
|
+
job_id TEXT NOT NULL REFERENCES connector_jobs(id) ON DELETE CASCADE,
|
|
2100
|
+
started_at TEXT NOT NULL,
|
|
2101
|
+
finished_at TEXT,
|
|
2102
|
+
exit_code INTEGER,
|
|
2103
|
+
raw_output TEXT,
|
|
2104
|
+
stripped_output TEXT
|
|
2105
|
+
)
|
|
2106
|
+
`);
|
|
2107
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_job_runs_job ON connector_job_runs(job_id, started_at DESC)`);
|
|
2108
|
+
db.run(`
|
|
2109
|
+
CREATE TABLE IF NOT EXISTS connector_workflows (
|
|
2110
|
+
id TEXT PRIMARY KEY,
|
|
2111
|
+
name TEXT UNIQUE NOT NULL,
|
|
2112
|
+
steps TEXT NOT NULL DEFAULT '[]',
|
|
2113
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
2114
|
+
created_at TEXT NOT NULL
|
|
2115
|
+
)
|
|
2116
|
+
`);
|
|
2117
|
+
db.run(`
|
|
2118
|
+
CREATE TABLE IF NOT EXISTS connector_usage (
|
|
2119
|
+
id TEXT PRIMARY KEY,
|
|
2120
|
+
connector TEXT NOT NULL,
|
|
2121
|
+
action TEXT NOT NULL,
|
|
2122
|
+
agent_id TEXT,
|
|
2123
|
+
timestamp TEXT NOT NULL
|
|
2124
|
+
)
|
|
2125
|
+
`);
|
|
2126
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_usage_connector ON connector_usage(connector, timestamp DESC)`);
|
|
2127
|
+
db.run(`
|
|
2128
|
+
CREATE TABLE IF NOT EXISTS connector_promotions (
|
|
2129
|
+
connector TEXT UNIQUE NOT NULL,
|
|
2130
|
+
promoted_at TEXT NOT NULL
|
|
2131
|
+
)
|
|
2132
|
+
`);
|
|
2133
|
+
}
|
|
2134
|
+
var DB_DIR, DB_PATH, _db = null;
|
|
2135
|
+
var init_database = __esm(() => {
|
|
2136
|
+
DB_DIR = join2(homedir2(), ".connectors");
|
|
2137
|
+
DB_PATH = join2(DB_DIR, "connectors.db");
|
|
2138
|
+
});
|
|
2139
|
+
|
|
2140
|
+
// src/db/jobs.ts
|
|
2141
|
+
function rowToJob(row) {
|
|
2142
|
+
return {
|
|
2143
|
+
...row,
|
|
2144
|
+
args: JSON.parse(row.args || "[]"),
|
|
2145
|
+
enabled: row.enabled === 1,
|
|
2146
|
+
strip: row.strip === 1
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function createJob(input, db) {
|
|
2150
|
+
const d = db ?? getDatabase();
|
|
2151
|
+
const id = shortUuid();
|
|
2152
|
+
const ts = now();
|
|
2153
|
+
d.run("INSERT INTO connector_jobs (id, name, connector, command, args, cron, enabled, strip, created_at) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)", [id, input.name, input.connector, input.command, JSON.stringify(input.args ?? []), input.cron, input.strip ? 1 : 0, ts]);
|
|
2154
|
+
return getJob(id, d);
|
|
2155
|
+
}
|
|
2156
|
+
function getJob(id, db) {
|
|
2157
|
+
const d = db ?? getDatabase();
|
|
2158
|
+
const row = d.query("SELECT * FROM connector_jobs WHERE id = ?").get(id);
|
|
2159
|
+
return row ? rowToJob(row) : null;
|
|
2160
|
+
}
|
|
2161
|
+
function getJobByName(name, db) {
|
|
2162
|
+
const d = db ?? getDatabase();
|
|
2163
|
+
const row = d.query("SELECT * FROM connector_jobs WHERE name = ?").get(name);
|
|
2164
|
+
return row ? rowToJob(row) : null;
|
|
2165
|
+
}
|
|
2166
|
+
function listJobs(db) {
|
|
2167
|
+
const d = db ?? getDatabase();
|
|
2168
|
+
return d.query("SELECT * FROM connector_jobs ORDER BY name").all().map(rowToJob);
|
|
2169
|
+
}
|
|
2170
|
+
function listEnabledJobs(db) {
|
|
2171
|
+
const d = db ?? getDatabase();
|
|
2172
|
+
return d.query("SELECT * FROM connector_jobs WHERE enabled = 1").all().map(rowToJob);
|
|
2173
|
+
}
|
|
2174
|
+
function updateJob(id, input, db) {
|
|
2175
|
+
const d = db ?? getDatabase();
|
|
2176
|
+
const sets = [];
|
|
2177
|
+
const params = [];
|
|
2178
|
+
if (input.name !== undefined) {
|
|
2179
|
+
sets.push("name = ?");
|
|
2180
|
+
params.push(input.name);
|
|
2181
|
+
}
|
|
2182
|
+
if (input.connector !== undefined) {
|
|
2183
|
+
sets.push("connector = ?");
|
|
2184
|
+
params.push(input.connector);
|
|
2185
|
+
}
|
|
2186
|
+
if (input.command !== undefined) {
|
|
2187
|
+
sets.push("command = ?");
|
|
2188
|
+
params.push(input.command);
|
|
2189
|
+
}
|
|
2190
|
+
if (input.args !== undefined) {
|
|
2191
|
+
sets.push("args = ?");
|
|
2192
|
+
params.push(JSON.stringify(input.args));
|
|
2193
|
+
}
|
|
2194
|
+
if (input.cron !== undefined) {
|
|
2195
|
+
sets.push("cron = ?");
|
|
2196
|
+
params.push(input.cron);
|
|
2197
|
+
}
|
|
2198
|
+
if (input.enabled !== undefined) {
|
|
2199
|
+
sets.push("enabled = ?");
|
|
2200
|
+
params.push(input.enabled ? 1 : 0);
|
|
2201
|
+
}
|
|
2202
|
+
if (input.strip !== undefined) {
|
|
2203
|
+
sets.push("strip = ?");
|
|
2204
|
+
params.push(input.strip ? 1 : 0);
|
|
2205
|
+
}
|
|
2206
|
+
if (sets.length === 0)
|
|
2207
|
+
return getJob(id, d);
|
|
2208
|
+
params.push(id);
|
|
2209
|
+
d.run(`UPDATE connector_jobs SET ${sets.join(", ")} WHERE id = ?`, params);
|
|
2210
|
+
return getJob(id, d);
|
|
2211
|
+
}
|
|
2212
|
+
function deleteJob(id, db) {
|
|
2213
|
+
const d = db ?? getDatabase();
|
|
2214
|
+
return d.run("DELETE FROM connector_jobs WHERE id = ?", [id]).changes > 0;
|
|
2215
|
+
}
|
|
2216
|
+
function touchJobLastRun(id, db) {
|
|
2217
|
+
const d = db ?? getDatabase();
|
|
2218
|
+
d.run("UPDATE connector_jobs SET last_run_at = ? WHERE id = ?", [now(), id]);
|
|
2219
|
+
}
|
|
2220
|
+
function createJobRun(jobId, db) {
|
|
2221
|
+
const d = db ?? getDatabase();
|
|
2222
|
+
const id = shortUuid();
|
|
2223
|
+
const ts = now();
|
|
2224
|
+
d.run("INSERT INTO connector_job_runs (id, job_id, started_at) VALUES (?, ?, ?)", [id, jobId, ts]);
|
|
2225
|
+
return { id, job_id: jobId, started_at: ts, finished_at: null, exit_code: null, raw_output: null, stripped_output: null };
|
|
2226
|
+
}
|
|
2227
|
+
function finishJobRun(id, result, db) {
|
|
2228
|
+
const d = db ?? getDatabase();
|
|
2229
|
+
d.run("UPDATE connector_job_runs SET finished_at = ?, exit_code = ?, raw_output = ?, stripped_output = ? WHERE id = ?", [now(), result.exit_code, result.raw_output, result.stripped_output ?? null, id]);
|
|
2230
|
+
}
|
|
2231
|
+
function listJobRuns(jobId, limit = 20, db) {
|
|
2232
|
+
const d = db ?? getDatabase();
|
|
2233
|
+
return d.query("SELECT * FROM connector_job_runs WHERE job_id = ? ORDER BY started_at DESC LIMIT ?").all(jobId, limit);
|
|
2234
|
+
}
|
|
2235
|
+
var init_jobs = __esm(() => {
|
|
2236
|
+
init_database();
|
|
2237
|
+
});
|
|
2238
|
+
|
|
2239
|
+
// src/db/workflows.ts
|
|
2240
|
+
function rowToWorkflow(row) {
|
|
2241
|
+
return {
|
|
2242
|
+
...row,
|
|
2243
|
+
steps: JSON.parse(row.steps || "[]"),
|
|
2244
|
+
enabled: row.enabled === 1
|
|
2245
|
+
};
|
|
2246
|
+
}
|
|
2247
|
+
function createWorkflow(input, db) {
|
|
2248
|
+
const d = db ?? getDatabase();
|
|
2249
|
+
const id = shortUuid();
|
|
2250
|
+
d.run("INSERT INTO connector_workflows (id, name, steps, enabled, created_at) VALUES (?, ?, ?, 1, ?)", [id, input.name, JSON.stringify(input.steps), now()]);
|
|
2251
|
+
return getWorkflow(id, d);
|
|
2252
|
+
}
|
|
2253
|
+
function getWorkflow(id, db) {
|
|
2254
|
+
const d = db ?? getDatabase();
|
|
2255
|
+
const row = d.query("SELECT * FROM connector_workflows WHERE id = ?").get(id);
|
|
2256
|
+
return row ? rowToWorkflow(row) : null;
|
|
2257
|
+
}
|
|
2258
|
+
function getWorkflowByName(name, db) {
|
|
2259
|
+
const d = db ?? getDatabase();
|
|
2260
|
+
const row = d.query("SELECT * FROM connector_workflows WHERE name = ?").get(name);
|
|
2261
|
+
return row ? rowToWorkflow(row) : null;
|
|
2262
|
+
}
|
|
2263
|
+
function listWorkflows(db) {
|
|
2264
|
+
const d = db ?? getDatabase();
|
|
2265
|
+
return d.query("SELECT * FROM connector_workflows ORDER BY name").all().map(rowToWorkflow);
|
|
2266
|
+
}
|
|
2267
|
+
function deleteWorkflow(id, db) {
|
|
2268
|
+
const d = db ?? getDatabase();
|
|
2269
|
+
return d.run("DELETE FROM connector_workflows WHERE id = ?", [id]).changes > 0;
|
|
2270
|
+
}
|
|
2271
|
+
var init_workflows = __esm(() => {
|
|
2272
|
+
init_database();
|
|
2273
|
+
});
|
|
2274
|
+
|
|
2275
|
+
// src/lib/strip.ts
|
|
2276
|
+
async function maybeStrip(output, _type = "json") {
|
|
2277
|
+
const config = getLlmConfig();
|
|
2278
|
+
if (!config?.strip)
|
|
2279
|
+
return output;
|
|
2280
|
+
if (!output || output.trim().length === 0)
|
|
2281
|
+
return output;
|
|
2282
|
+
const client = LLMClient.fromConfig();
|
|
2283
|
+
if (!client)
|
|
2284
|
+
return output;
|
|
2285
|
+
try {
|
|
2286
|
+
const result = await client.complete(STRIP_PROMPT, output);
|
|
2287
|
+
return result.content.trim();
|
|
2288
|
+
} catch {
|
|
2289
|
+
return output;
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
var STRIP_PROMPT = `You are a data extraction assistant. Your job is to take raw API output and return ONLY the essential, structured data.
|
|
2293
|
+
|
|
2294
|
+
Rules:
|
|
2295
|
+
- Return valid JSON only (no markdown, no explanation)
|
|
2296
|
+
- Remove pagination metadata, rate limit headers, empty fields, null values
|
|
2297
|
+
- Keep all meaningful data fields
|
|
2298
|
+
- If the input is already minimal, return it unchanged
|
|
2299
|
+
- If input is not JSON, extract key facts as a JSON object
|
|
2300
|
+
- Never truncate actual data values`;
|
|
2301
|
+
var init_strip = __esm(() => {
|
|
2302
|
+
init_llm();
|
|
2303
|
+
});
|
|
2304
|
+
|
|
2305
|
+
// src/lib/scheduler.ts
|
|
2306
|
+
var exports_scheduler = {};
|
|
2307
|
+
__export(exports_scheduler, {
|
|
2308
|
+
triggerJob: () => triggerJob,
|
|
2309
|
+
stopScheduler: () => stopScheduler,
|
|
2310
|
+
startScheduler: () => startScheduler
|
|
2311
|
+
});
|
|
2312
|
+
import { spawn } from "child_process";
|
|
2313
|
+
function cronMatches(cron, d) {
|
|
2314
|
+
const parts = cron.trim().split(/\s+/);
|
|
2315
|
+
if (parts.length !== 5)
|
|
2316
|
+
return false;
|
|
2317
|
+
const [min, hour, dom, mon, dow] = parts;
|
|
2318
|
+
function matches(field, value, min_v, max_v) {
|
|
2319
|
+
if (field === "*")
|
|
2320
|
+
return true;
|
|
2321
|
+
if (field.startsWith("*/")) {
|
|
2322
|
+
const step = parseInt(field.slice(2));
|
|
2323
|
+
return value % step === 0;
|
|
2324
|
+
}
|
|
2325
|
+
if (field.includes("-")) {
|
|
2326
|
+
const [a, b] = field.split("-").map(Number);
|
|
2327
|
+
return value >= a && value <= b;
|
|
2328
|
+
}
|
|
2329
|
+
if (field.includes(",")) {
|
|
2330
|
+
return field.split(",").map(Number).includes(value);
|
|
2331
|
+
}
|
|
2332
|
+
return parseInt(field) === value;
|
|
2333
|
+
}
|
|
2334
|
+
return matches(min, d.getMinutes(), 0, 59) && matches(hour, d.getHours(), 0, 23) && matches(dom, d.getDate(), 1, 31) && matches(mon, d.getMonth() + 1, 1, 12) && matches(dow, d.getDay(), 0, 6);
|
|
2335
|
+
}
|
|
2336
|
+
async function runConnectorCommand(connector, command, args) {
|
|
2337
|
+
return new Promise((resolve) => {
|
|
2338
|
+
const cmdArgs = [connector, command, ...args, "--format", "json"];
|
|
2339
|
+
const proc = spawn("connectors", ["run", ...cmdArgs], { shell: false });
|
|
2340
|
+
let output = "";
|
|
2341
|
+
proc.stdout.on("data", (d) => {
|
|
2342
|
+
output += d.toString();
|
|
2343
|
+
});
|
|
2344
|
+
proc.stderr.on("data", (d) => {
|
|
2345
|
+
output += d.toString();
|
|
2346
|
+
});
|
|
2347
|
+
proc.on("close", (code) => resolve({ exitCode: code ?? 1, output }));
|
|
2348
|
+
proc.on("error", () => resolve({ exitCode: 1, output: `Failed to spawn connectors run` }));
|
|
2349
|
+
setTimeout(() => {
|
|
2350
|
+
proc.kill();
|
|
2351
|
+
resolve({ exitCode: 124, output: output + `
|
|
2352
|
+
[timeout]` });
|
|
2353
|
+
}, 60000);
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
async function executeJob(job, db) {
|
|
2357
|
+
const run = createJobRun(job.id, db);
|
|
2358
|
+
try {
|
|
2359
|
+
const { exitCode, output } = await runConnectorCommand(job.connector, job.command, job.args);
|
|
2360
|
+
const stripped = job.strip ? await maybeStrip(output) : undefined;
|
|
2361
|
+
finishJobRun(run.id, { exit_code: exitCode, raw_output: output, stripped_output: stripped }, db);
|
|
2362
|
+
touchJobLastRun(job.id, db);
|
|
2363
|
+
} catch (e) {
|
|
2364
|
+
finishJobRun(run.id, { exit_code: 1, raw_output: String(e) }, db);
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
function startScheduler(db) {
|
|
2368
|
+
if (_interval)
|
|
2369
|
+
return;
|
|
2370
|
+
_interval = setInterval(async () => {
|
|
2371
|
+
const now2 = new Date;
|
|
2372
|
+
const currentMinute = now2.getMinutes() + now2.getHours() * 60;
|
|
2373
|
+
if (currentMinute === _lastCheckedMinute)
|
|
2374
|
+
return;
|
|
2375
|
+
_lastCheckedMinute = currentMinute;
|
|
2376
|
+
const jobs = listEnabledJobs(db);
|
|
2377
|
+
for (const job of jobs) {
|
|
2378
|
+
if (cronMatches(job.cron, now2)) {
|
|
2379
|
+
executeJob(job, db).catch(() => {});
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
}, 30000);
|
|
2383
|
+
}
|
|
2384
|
+
function stopScheduler() {
|
|
2385
|
+
if (_interval) {
|
|
2386
|
+
clearInterval(_interval);
|
|
2387
|
+
_interval = null;
|
|
2388
|
+
_lastCheckedMinute = -1;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
async function triggerJob(job, db) {
|
|
2392
|
+
const run = createJobRun(job.id, db);
|
|
2393
|
+
const { exitCode, output } = await runConnectorCommand(job.connector, job.command, job.args);
|
|
2394
|
+
const stripped = job.strip ? await maybeStrip(output) : undefined;
|
|
2395
|
+
finishJobRun(run.id, { exit_code: exitCode, raw_output: output, stripped_output: stripped }, db);
|
|
2396
|
+
touchJobLastRun(job.id, db);
|
|
2397
|
+
return { run_id: run.id, exit_code: exitCode, output: stripped ?? output };
|
|
2398
|
+
}
|
|
2399
|
+
var _interval = null, _lastCheckedMinute = -1;
|
|
2400
|
+
var init_scheduler = __esm(() => {
|
|
2401
|
+
init_jobs();
|
|
2402
|
+
init_strip();
|
|
2403
|
+
});
|
|
2404
|
+
|
|
2405
|
+
// src/lib/workflow-runner.ts
|
|
2406
|
+
import { spawn as spawn2 } from "child_process";
|
|
2407
|
+
async function runStep(step, previousOutput) {
|
|
2408
|
+
return new Promise((resolve) => {
|
|
2409
|
+
const args = [...step.args ?? []];
|
|
2410
|
+
if (previousOutput && previousOutput.trim()) {
|
|
2411
|
+
args.push("--input", previousOutput.trim().slice(0, 4096));
|
|
2412
|
+
}
|
|
2413
|
+
const cmdArgs = ["run", step.connector, step.command, ...args, "--format", "json"];
|
|
2414
|
+
const proc = spawn2("connectors", cmdArgs, { shell: false });
|
|
2415
|
+
let output = "";
|
|
2416
|
+
proc.stdout.on("data", (d) => {
|
|
2417
|
+
output += d.toString();
|
|
2418
|
+
});
|
|
2419
|
+
proc.stderr.on("data", (d) => {
|
|
2420
|
+
output += d.toString();
|
|
2421
|
+
});
|
|
2422
|
+
proc.on("close", (code) => resolve({ exitCode: code ?? 1, output }));
|
|
2423
|
+
proc.on("error", () => resolve({ exitCode: 1, output: "Failed to spawn connectors" }));
|
|
2424
|
+
setTimeout(() => {
|
|
2425
|
+
proc.kill();
|
|
2426
|
+
resolve({ exitCode: 124, output: output + `
|
|
2427
|
+
[timeout]` });
|
|
2428
|
+
}, 60000);
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
async function runWorkflow(workflow) {
|
|
2432
|
+
const results = [];
|
|
2433
|
+
let previousOutput;
|
|
2434
|
+
let success = true;
|
|
2435
|
+
for (let i = 0;i < workflow.steps.length; i++) {
|
|
2436
|
+
const step = workflow.steps[i];
|
|
2437
|
+
const { exitCode, output } = await runStep(step, previousOutput);
|
|
2438
|
+
const stripped = await maybeStrip(output);
|
|
2439
|
+
results.push({ step: i + 1, connector: step.connector, command: step.command, exit_code: exitCode, output: stripped });
|
|
2440
|
+
if (exitCode !== 0) {
|
|
2441
|
+
success = false;
|
|
2442
|
+
break;
|
|
2443
|
+
}
|
|
2444
|
+
previousOutput = stripped;
|
|
2445
|
+
}
|
|
2446
|
+
return {
|
|
2447
|
+
workflow_id: workflow.id,
|
|
2448
|
+
workflow_name: workflow.name,
|
|
2449
|
+
steps: results,
|
|
2450
|
+
success,
|
|
2451
|
+
final_output: results[results.length - 1]?.output ?? ""
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
var init_workflow_runner = __esm(() => {
|
|
2455
|
+
init_strip();
|
|
2456
|
+
});
|
|
2457
|
+
|
|
2458
|
+
// src/lib/fuzzy.ts
|
|
2459
|
+
function levenshtein(a, b) {
|
|
2460
|
+
const m = a.length;
|
|
2461
|
+
const n = b.length;
|
|
2462
|
+
if (m === 0)
|
|
2463
|
+
return n;
|
|
2464
|
+
if (n === 0)
|
|
2465
|
+
return m;
|
|
2466
|
+
let prev = new Array(n + 1);
|
|
2467
|
+
let curr = new Array(n + 1);
|
|
2468
|
+
for (let j = 0;j <= n; j++)
|
|
2469
|
+
prev[j] = j;
|
|
2470
|
+
for (let i = 1;i <= m; i++) {
|
|
2471
|
+
curr[0] = i;
|
|
2472
|
+
for (let j = 1;j <= n; j++) {
|
|
2473
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
2474
|
+
curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
|
|
2475
|
+
}
|
|
2476
|
+
[prev, curr] = [curr, prev];
|
|
2477
|
+
}
|
|
2478
|
+
return prev[n];
|
|
2479
|
+
}
|
|
2480
|
+
function bestFuzzyScore(token, candidates, maxDistance = 2) {
|
|
2481
|
+
if (token.length < 3)
|
|
2482
|
+
return 0;
|
|
2483
|
+
let bestDist = maxDistance + 1;
|
|
2484
|
+
for (const c of candidates) {
|
|
2485
|
+
if (Math.abs(token.length - c.length) > maxDistance)
|
|
2486
|
+
continue;
|
|
2487
|
+
const d = levenshtein(token, c);
|
|
2488
|
+
if (d < bestDist)
|
|
2489
|
+
bestDist = d;
|
|
2490
|
+
if (d === 0)
|
|
2491
|
+
return maxDistance + 1;
|
|
2492
|
+
}
|
|
2493
|
+
if (bestDist > maxDistance)
|
|
2494
|
+
return 0;
|
|
2495
|
+
return maxDistance - bestDist + 1;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// src/lib/synonyms.ts
|
|
2499
|
+
function expandQuery(tokens) {
|
|
2500
|
+
const synonyms = new Set;
|
|
2501
|
+
for (const token of tokens) {
|
|
2502
|
+
const matches = SYNONYM_MAP[token];
|
|
2503
|
+
if (matches) {
|
|
2504
|
+
for (const syn of matches) {
|
|
2505
|
+
if (!tokens.includes(syn))
|
|
2506
|
+
synonyms.add(syn);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
for (const [key, values] of Object.entries(SYNONYM_MAP)) {
|
|
2510
|
+
if (values.includes(token) && !tokens.includes(key)) {
|
|
2511
|
+
synonyms.add(key);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
return { original: tokens, expanded: [...synonyms] };
|
|
2516
|
+
}
|
|
2517
|
+
var SYNONYM_MAP;
|
|
2518
|
+
var init_synonyms = __esm(() => {
|
|
2519
|
+
SYNONYM_MAP = {
|
|
2520
|
+
email: ["smtp", "mail", "inbox", "resend", "ses"],
|
|
2521
|
+
chat: ["messaging", "im", "slack", "discord", "teams"],
|
|
2522
|
+
sms: ["text", "twilio", "messaging"],
|
|
2523
|
+
payment: ["billing", "invoicing", "commerce", "checkout", "stripe"],
|
|
2524
|
+
payments: ["billing", "invoicing", "commerce", "checkout", "stripe"],
|
|
2525
|
+
ecommerce: ["shop", "store", "commerce", "shopify"],
|
|
2526
|
+
finance: ["banking", "accounting", "invoicing"],
|
|
2527
|
+
crypto: ["blockchain", "web3", "wallet"],
|
|
2528
|
+
ai: ["llm", "ml", "model", "gpt", "claude", "anthropic", "openai"],
|
|
2529
|
+
llm: ["ai", "model", "gpt", "claude"],
|
|
2530
|
+
auth: ["oauth", "sso", "login", "identity", "authentication"],
|
|
2531
|
+
database: ["db", "sql", "nosql", "postgres", "mongo", "supabase"],
|
|
2532
|
+
deploy: ["hosting", "infrastructure", "ci", "cd", "vercel"],
|
|
2533
|
+
storage: ["files", "drive", "s3", "bucket", "upload"],
|
|
2534
|
+
cloud: ["aws", "gcp", "azure", "infrastructure"],
|
|
2535
|
+
api: ["rest", "graphql", "endpoint", "webhook"],
|
|
2536
|
+
monitoring: ["logs", "observability", "alerting", "datadog", "sentry"],
|
|
2537
|
+
ci: ["cd", "deploy", "pipeline", "github", "actions"],
|
|
2538
|
+
crm: ["sales", "leads", "contacts", "hubspot", "salesforce"],
|
|
2539
|
+
analytics: ["data", "metrics", "tracking", "mixpanel", "amplitude"],
|
|
2540
|
+
project: ["task", "issue", "board", "jira", "linear", "asana"],
|
|
2541
|
+
docs: ["documentation", "wiki", "notion", "confluence"],
|
|
2542
|
+
design: ["figma", "sketch", "ui", "ux"],
|
|
2543
|
+
security: ["auth", "encryption", "compliance", "vault"]
|
|
2544
|
+
};
|
|
2545
|
+
});
|
|
2546
|
+
|
|
1871
2547
|
// src/lib/registry.ts
|
|
1872
|
-
import { existsSync, readFileSync } from "fs";
|
|
1873
|
-
import { join, dirname } from "path";
|
|
2548
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
2549
|
+
import { join as join3, dirname } from "path";
|
|
1874
2550
|
import { fileURLToPath } from "url";
|
|
1875
2551
|
function getConnectorsByCategory(category) {
|
|
1876
2552
|
return CONNECTORS.filter((c) => c.category === category);
|
|
1877
2553
|
}
|
|
1878
|
-
function searchConnectors(query) {
|
|
1879
|
-
const
|
|
1880
|
-
|
|
2554
|
+
function searchConnectors(query, context) {
|
|
2555
|
+
const tokens = query.toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
2556
|
+
if (tokens.length === 0)
|
|
2557
|
+
return [];
|
|
2558
|
+
const limit = context?.limit ?? 20;
|
|
2559
|
+
const installed = new Set(context?.installed ?? []);
|
|
2560
|
+
const promoted = new Set(context?.promoted ?? []);
|
|
2561
|
+
const usage = context?.usage ?? new Map;
|
|
2562
|
+
const results = [];
|
|
2563
|
+
for (const c of CONNECTORS) {
|
|
2564
|
+
const nameLow = c.name.toLowerCase();
|
|
2565
|
+
const displayLow = c.displayName.toLowerCase();
|
|
2566
|
+
const descLow = c.description.toLowerCase();
|
|
2567
|
+
const tagsLow = c.tags.map((t) => t.toLowerCase());
|
|
2568
|
+
let score = 0;
|
|
2569
|
+
const matchReasons = [];
|
|
2570
|
+
let allTokensMatch = true;
|
|
2571
|
+
for (const token of tokens) {
|
|
2572
|
+
let tokenMatched = false;
|
|
2573
|
+
if (nameLow === token) {
|
|
2574
|
+
score += 100;
|
|
2575
|
+
matchReasons.push(`name="${token}"`);
|
|
2576
|
+
tokenMatched = true;
|
|
2577
|
+
} else if (nameLow.includes(token)) {
|
|
2578
|
+
score += 10;
|
|
2579
|
+
matchReasons.push(`name~${token}`);
|
|
2580
|
+
tokenMatched = true;
|
|
2581
|
+
}
|
|
2582
|
+
if (tagsLow.includes(token)) {
|
|
2583
|
+
score += 8;
|
|
2584
|
+
if (!tokenMatched)
|
|
2585
|
+
matchReasons.push(`tag="${token}"`);
|
|
2586
|
+
tokenMatched = true;
|
|
2587
|
+
} else if (tagsLow.some((t) => t.includes(token))) {
|
|
2588
|
+
score += 5;
|
|
2589
|
+
if (!tokenMatched)
|
|
2590
|
+
matchReasons.push(`tag~${token}`);
|
|
2591
|
+
tokenMatched = true;
|
|
2592
|
+
}
|
|
2593
|
+
if (displayLow.includes(token)) {
|
|
2594
|
+
score += 3;
|
|
2595
|
+
if (!tokenMatched)
|
|
2596
|
+
matchReasons.push(`display~${token}`);
|
|
2597
|
+
tokenMatched = true;
|
|
2598
|
+
}
|
|
2599
|
+
if (descLow.includes(token)) {
|
|
2600
|
+
score += 1;
|
|
2601
|
+
if (!tokenMatched)
|
|
2602
|
+
matchReasons.push(`desc~${token}`);
|
|
2603
|
+
tokenMatched = true;
|
|
2604
|
+
}
|
|
2605
|
+
if (!tokenMatched && token.length >= 3) {
|
|
2606
|
+
const nameFuzzy = bestFuzzyScore(token, [nameLow], 1);
|
|
2607
|
+
if (nameFuzzy > 0) {
|
|
2608
|
+
score += nameFuzzy * 6;
|
|
2609
|
+
matchReasons.push(`fuzzy:name\u2248${token}`);
|
|
2610
|
+
tokenMatched = true;
|
|
2611
|
+
}
|
|
2612
|
+
if (!tokenMatched) {
|
|
2613
|
+
const tagFuzzy = bestFuzzyScore(token, tagsLow, 2);
|
|
2614
|
+
if (tagFuzzy > 0) {
|
|
2615
|
+
score += tagFuzzy * 3;
|
|
2616
|
+
matchReasons.push(`fuzzy:tag\u2248${token}`);
|
|
2617
|
+
tokenMatched = true;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (!tokenMatched) {
|
|
2621
|
+
const displayFuzzy = bestFuzzyScore(token, [displayLow], 2);
|
|
2622
|
+
if (displayFuzzy > 0) {
|
|
2623
|
+
score += displayFuzzy * 2;
|
|
2624
|
+
matchReasons.push(`fuzzy:display\u2248${token}`);
|
|
2625
|
+
tokenMatched = true;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
if (!tokenMatched) {
|
|
2630
|
+
allTokensMatch = false;
|
|
2631
|
+
break;
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
if (!allTokensMatch)
|
|
2635
|
+
continue;
|
|
2636
|
+
const badges = [];
|
|
2637
|
+
if (installed.has(c.name)) {
|
|
2638
|
+
score += 50;
|
|
2639
|
+
badges.push("installed");
|
|
2640
|
+
}
|
|
2641
|
+
if (promoted.has(c.name)) {
|
|
2642
|
+
score += 30;
|
|
2643
|
+
badges.push("promoted");
|
|
2644
|
+
}
|
|
2645
|
+
const usageCount = usage.get(c.name) ?? 0;
|
|
2646
|
+
if (usageCount > 0) {
|
|
2647
|
+
score += Math.min(usageCount * 2, 40);
|
|
2648
|
+
if (usageCount >= 5)
|
|
2649
|
+
badges.push("hot");
|
|
2650
|
+
}
|
|
2651
|
+
results.push({ ...c, score, matchReasons, badges });
|
|
2652
|
+
}
|
|
2653
|
+
const matchedNames = new Set(results.map((r) => r.name));
|
|
2654
|
+
if (results.length < limit) {
|
|
2655
|
+
const { expanded } = expandQuery(tokens);
|
|
2656
|
+
if (expanded.length > 0) {
|
|
2657
|
+
for (const c of CONNECTORS) {
|
|
2658
|
+
if (matchedNames.has(c.name))
|
|
2659
|
+
continue;
|
|
2660
|
+
const nameLow2 = c.name.toLowerCase();
|
|
2661
|
+
const tagsLow2 = c.tags.map((t) => t.toLowerCase());
|
|
2662
|
+
const descLow2 = c.description.toLowerCase();
|
|
2663
|
+
let synScore = 0;
|
|
2664
|
+
const synReasons = [];
|
|
2665
|
+
for (const syn of expanded) {
|
|
2666
|
+
if (nameLow2.includes(syn)) {
|
|
2667
|
+
synScore += 2;
|
|
2668
|
+
synReasons.push(`syn:name~${syn}`);
|
|
2669
|
+
} else if (tagsLow2.some((t) => t.includes(syn))) {
|
|
2670
|
+
synScore += 1;
|
|
2671
|
+
synReasons.push(`syn:tag~${syn}`);
|
|
2672
|
+
} else if (descLow2.includes(syn)) {
|
|
2673
|
+
synScore += 1;
|
|
2674
|
+
synReasons.push(`syn:desc~${syn}`);
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
if (synScore > 0) {
|
|
2678
|
+
const badges = [];
|
|
2679
|
+
if (installed.has(c.name)) {
|
|
2680
|
+
synScore += 50;
|
|
2681
|
+
badges.push("installed");
|
|
2682
|
+
}
|
|
2683
|
+
if (promoted.has(c.name)) {
|
|
2684
|
+
synScore += 30;
|
|
2685
|
+
badges.push("promoted");
|
|
2686
|
+
}
|
|
2687
|
+
const usageCount = usage.get(c.name) ?? 0;
|
|
2688
|
+
if (usageCount > 0) {
|
|
2689
|
+
synScore += Math.min(usageCount * 2, 40);
|
|
2690
|
+
if (usageCount >= 5)
|
|
2691
|
+
badges.push("hot");
|
|
2692
|
+
}
|
|
2693
|
+
results.push({ ...c, score: synScore, matchReasons: synReasons, badges });
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
results.sort((a, b) => b.score - a.score);
|
|
2699
|
+
return results.slice(0, limit);
|
|
1881
2700
|
}
|
|
1882
2701
|
function getConnector(name) {
|
|
1883
2702
|
return CONNECTORS.find((c) => c.name === name);
|
|
@@ -1888,17 +2707,17 @@ function loadConnectorVersions() {
|
|
|
1888
2707
|
versionsLoaded = true;
|
|
1889
2708
|
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
1890
2709
|
const candidates = [
|
|
1891
|
-
|
|
1892
|
-
|
|
2710
|
+
join3(thisDir, "..", "connectors"),
|
|
2711
|
+
join3(thisDir, "..", "..", "connectors")
|
|
1893
2712
|
];
|
|
1894
|
-
const connectorsDir = candidates.find((d) =>
|
|
2713
|
+
const connectorsDir = candidates.find((d) => existsSync2(d));
|
|
1895
2714
|
if (!connectorsDir)
|
|
1896
2715
|
return;
|
|
1897
2716
|
for (const connector of CONNECTORS) {
|
|
1898
2717
|
try {
|
|
1899
|
-
const pkgPath =
|
|
1900
|
-
if (
|
|
1901
|
-
const pkg = JSON.parse(
|
|
2718
|
+
const pkgPath = join3(connectorsDir, `connect-${connector.name}`, "package.json");
|
|
2719
|
+
if (existsSync2(pkgPath)) {
|
|
2720
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1902
2721
|
connector.version = pkg.version || "0.0.0";
|
|
1903
2722
|
}
|
|
1904
2723
|
} catch {}
|
|
@@ -1906,6 +2725,7 @@ function loadConnectorVersions() {
|
|
|
1906
2725
|
}
|
|
1907
2726
|
var CATEGORIES, CONNECTORS, versionsLoaded = false;
|
|
1908
2727
|
var init_registry = __esm(() => {
|
|
2728
|
+
init_synonyms();
|
|
1909
2729
|
CATEGORIES = [
|
|
1910
2730
|
"AI & ML",
|
|
1911
2731
|
"Developer Tools",
|
|
@@ -6791,13 +7611,6 @@ var init_registry = __esm(() => {
|
|
|
6791
7611
|
category: "Business Tools",
|
|
6792
7612
|
tags: ["e-signature", "contracts", "digital", "documents", "legal"]
|
|
6793
7613
|
},
|
|
6794
|
-
{
|
|
6795
|
-
name: "yousign",
|
|
6796
|
-
displayName: "Yousign",
|
|
6797
|
-
description: "eIDAS-compliant electronic signature API for EU workflows",
|
|
6798
|
-
category: "Business Tools",
|
|
6799
|
-
tags: ["e-signature", "eidas", "contracts", "documents", "legal", "eu"]
|
|
6800
|
-
},
|
|
6801
7614
|
{
|
|
6802
7615
|
name: "signl4",
|
|
6803
7616
|
displayName: "SIGNL4",
|
|
@@ -9471,23 +10284,28 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
9471
10284
|
});
|
|
9472
10285
|
|
|
9473
10286
|
// src/lib/installer.ts
|
|
9474
|
-
import { existsSync as
|
|
9475
|
-
import {
|
|
10287
|
+
import { existsSync as existsSync3, cpSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, readdirSync, statSync, rmSync } from "fs";
|
|
10288
|
+
import { homedir as homedir3 } from "os";
|
|
10289
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
9476
10290
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9477
10291
|
function resolveConnectorsDir() {
|
|
9478
|
-
const fromBin =
|
|
9479
|
-
if (
|
|
10292
|
+
const fromBin = join4(__dirname2, "..", "connectors");
|
|
10293
|
+
if (existsSync3(fromBin))
|
|
9480
10294
|
return fromBin;
|
|
9481
|
-
const fromSrc =
|
|
9482
|
-
if (
|
|
10295
|
+
const fromSrc = join4(__dirname2, "..", "..", "connectors");
|
|
10296
|
+
if (existsSync3(fromSrc))
|
|
9483
10297
|
return fromSrc;
|
|
9484
10298
|
return fromBin;
|
|
9485
10299
|
}
|
|
9486
10300
|
function getConnectorPath(name) {
|
|
9487
10301
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
9488
|
-
return
|
|
10302
|
+
return join4(CONNECTORS_DIR, connectorName);
|
|
10303
|
+
}
|
|
10304
|
+
function connectorExists(name) {
|
|
10305
|
+
return existsSync3(getConnectorPath(name));
|
|
9489
10306
|
}
|
|
9490
10307
|
function installConnector(name, options = {}) {
|
|
10308
|
+
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
9491
10309
|
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
9492
10310
|
return {
|
|
9493
10311
|
connector: name,
|
|
@@ -9495,35 +10313,91 @@ function installConnector(name, options = {}) {
|
|
|
9495
10313
|
error: `Invalid connector name '${name}'`
|
|
9496
10314
|
};
|
|
9497
10315
|
}
|
|
10316
|
+
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
9498
10317
|
const sourcePath = getConnectorPath(name);
|
|
9499
|
-
|
|
10318
|
+
const destDir = join4(targetDir, ".connectors");
|
|
10319
|
+
const destPath = join4(destDir, connectorName);
|
|
10320
|
+
if (!existsSync3(sourcePath)) {
|
|
9500
10321
|
return {
|
|
9501
10322
|
connector: name,
|
|
9502
10323
|
success: false,
|
|
9503
10324
|
error: `Connector '${name}' not found`
|
|
9504
10325
|
};
|
|
9505
10326
|
}
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
10327
|
+
if (existsSync3(destPath) && !overwrite) {
|
|
10328
|
+
return {
|
|
10329
|
+
connector: name,
|
|
10330
|
+
success: false,
|
|
10331
|
+
error: `Already installed. Use --overwrite to replace.`,
|
|
10332
|
+
path: destPath
|
|
10333
|
+
};
|
|
10334
|
+
}
|
|
10335
|
+
try {
|
|
10336
|
+
if (!existsSync3(destDir)) {
|
|
10337
|
+
mkdirSync3(destDir, { recursive: true });
|
|
10338
|
+
}
|
|
10339
|
+
cpSync(sourcePath, destPath, { recursive: true });
|
|
10340
|
+
const homeCredDir = join4(homedir3(), ".connectors", connectorName);
|
|
10341
|
+
if (existsSync3(homeCredDir)) {
|
|
10342
|
+
const filesToCopy = ["credentials.json", "current_profile"];
|
|
10343
|
+
for (const file of filesToCopy) {
|
|
10344
|
+
const src = join4(homeCredDir, file);
|
|
10345
|
+
if (existsSync3(src)) {
|
|
10346
|
+
cpSync(src, join4(destPath, file));
|
|
10347
|
+
}
|
|
10348
|
+
}
|
|
10349
|
+
const profilesDir = join4(homeCredDir, "profiles");
|
|
10350
|
+
if (existsSync3(profilesDir)) {
|
|
10351
|
+
cpSync(profilesDir, join4(destPath, "profiles"), { recursive: true });
|
|
10352
|
+
}
|
|
10353
|
+
}
|
|
10354
|
+
updateConnectorsIndex(destDir);
|
|
10355
|
+
return {
|
|
10356
|
+
connector: name,
|
|
10357
|
+
success: true,
|
|
10358
|
+
path: destPath
|
|
10359
|
+
};
|
|
10360
|
+
} catch (error) {
|
|
10361
|
+
return {
|
|
10362
|
+
connector: name,
|
|
10363
|
+
success: false,
|
|
10364
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
10365
|
+
};
|
|
10366
|
+
}
|
|
10367
|
+
}
|
|
10368
|
+
function updateConnectorsIndex(connectorsDir) {
|
|
10369
|
+
const indexPath = join4(connectorsDir, "index.ts");
|
|
10370
|
+
const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
|
|
10371
|
+
const exports = connectors.map((c) => {
|
|
10372
|
+
const name = c.replace("connect-", "");
|
|
10373
|
+
return `export * as ${name} from './${c}/src/index.js';`;
|
|
10374
|
+
}).join(`
|
|
10375
|
+
`);
|
|
10376
|
+
const content = `/**
|
|
10377
|
+
* Auto-generated index of installed connectors
|
|
10378
|
+
* Do not edit manually - run 'connectors install' to update
|
|
10379
|
+
*/
|
|
10380
|
+
|
|
10381
|
+
${exports}
|
|
10382
|
+
`;
|
|
10383
|
+
writeFileSync2(indexPath, content);
|
|
9511
10384
|
}
|
|
9512
|
-
function getInstalledConnectors() {
|
|
9513
|
-
|
|
10385
|
+
function getInstalledConnectors(targetDir = process.cwd()) {
|
|
10386
|
+
const connectorsDir = join4(targetDir, ".connectors");
|
|
10387
|
+
if (!existsSync3(connectorsDir)) {
|
|
9514
10388
|
return [];
|
|
9515
10389
|
}
|
|
9516
|
-
return readdirSync(
|
|
9517
|
-
const fullPath =
|
|
10390
|
+
return readdirSync(connectorsDir).filter((f) => {
|
|
10391
|
+
const fullPath = join4(connectorsDir, f);
|
|
9518
10392
|
return f.startsWith("connect-") && statSync(fullPath).isDirectory();
|
|
9519
10393
|
}).map((f) => f.replace("connect-", ""));
|
|
9520
10394
|
}
|
|
9521
10395
|
function getConnectorDocs(name) {
|
|
9522
10396
|
const connectorPath = getConnectorPath(name);
|
|
9523
|
-
const claudeMdPath =
|
|
9524
|
-
if (!
|
|
10397
|
+
const claudeMdPath = join4(connectorPath, "CLAUDE.md");
|
|
10398
|
+
if (!existsSync3(claudeMdPath))
|
|
9525
10399
|
return null;
|
|
9526
|
-
const raw =
|
|
10400
|
+
const raw = readFileSync3(claudeMdPath, "utf-8");
|
|
9527
10401
|
return {
|
|
9528
10402
|
overview: extractSection(raw, "Project Overview"),
|
|
9529
10403
|
auth: extractSection(raw, "Authentication"),
|
|
@@ -9560,8 +10434,16 @@ function parseEnvVarsTable(section) {
|
|
|
9560
10434
|
}
|
|
9561
10435
|
return vars;
|
|
9562
10436
|
}
|
|
9563
|
-
function removeConnector(name) {
|
|
9564
|
-
|
|
10437
|
+
function removeConnector(name, targetDir = process.cwd()) {
|
|
10438
|
+
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
10439
|
+
const connectorsDir = join4(targetDir, ".connectors");
|
|
10440
|
+
const connectorPath = join4(connectorsDir, connectorName);
|
|
10441
|
+
if (!existsSync3(connectorPath)) {
|
|
10442
|
+
return false;
|
|
10443
|
+
}
|
|
10444
|
+
rmSync(connectorPath, { recursive: true });
|
|
10445
|
+
updateConnectorsIndex(connectorsDir);
|
|
10446
|
+
return true;
|
|
9565
10447
|
}
|
|
9566
10448
|
var __dirname2, CONNECTORS_DIR;
|
|
9567
10449
|
var init_installer = __esm(() => {
|
|
@@ -9569,11 +10451,77 @@ var init_installer = __esm(() => {
|
|
|
9569
10451
|
CONNECTORS_DIR = resolveConnectorsDir();
|
|
9570
10452
|
});
|
|
9571
10453
|
|
|
10454
|
+
// src/lib/lock.ts
|
|
10455
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10456
|
+
import { join as join5 } from "path";
|
|
10457
|
+
import { homedir as homedir4 } from "os";
|
|
10458
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
10459
|
+
function lockPath(connector) {
|
|
10460
|
+
const dir = join5(homedir4(), ".connectors", `connect-${connector}`);
|
|
10461
|
+
mkdirSync4(dir, { recursive: true });
|
|
10462
|
+
return join5(dir, ".write.lock");
|
|
10463
|
+
}
|
|
10464
|
+
function isStale(path) {
|
|
10465
|
+
try {
|
|
10466
|
+
const stat = statSync2(path);
|
|
10467
|
+
return Date.now() - stat.mtimeMs > STALE_LOCK_MS;
|
|
10468
|
+
} catch {
|
|
10469
|
+
return false;
|
|
10470
|
+
}
|
|
10471
|
+
}
|
|
10472
|
+
function tryAcquire(path) {
|
|
10473
|
+
if (existsSync4(path) && isStale(path)) {
|
|
10474
|
+
try {
|
|
10475
|
+
unlinkSync(path);
|
|
10476
|
+
} catch {}
|
|
10477
|
+
}
|
|
10478
|
+
try {
|
|
10479
|
+
const fd = openSync(path, "wx");
|
|
10480
|
+
closeSync(fd);
|
|
10481
|
+
return true;
|
|
10482
|
+
} catch (e) {
|
|
10483
|
+
if (e.code === "EEXIST")
|
|
10484
|
+
return false;
|
|
10485
|
+
throw e;
|
|
10486
|
+
}
|
|
10487
|
+
}
|
|
10488
|
+
function release(path) {
|
|
10489
|
+
try {
|
|
10490
|
+
unlinkSync(path);
|
|
10491
|
+
} catch {}
|
|
10492
|
+
}
|
|
10493
|
+
async function withWriteLock(connector, fn) {
|
|
10494
|
+
const path = lockPath(connector);
|
|
10495
|
+
const deadline = Date.now() + LOCK_TIMEOUT_MS;
|
|
10496
|
+
while (Date.now() < deadline) {
|
|
10497
|
+
if (tryAcquire(path)) {
|
|
10498
|
+
try {
|
|
10499
|
+
return await fn();
|
|
10500
|
+
} finally {
|
|
10501
|
+
release(path);
|
|
10502
|
+
}
|
|
10503
|
+
}
|
|
10504
|
+
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
|
|
10505
|
+
}
|
|
10506
|
+
throw new LockTimeoutError(connector);
|
|
10507
|
+
}
|
|
10508
|
+
var LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 100, STALE_LOCK_MS = 30000, LockTimeoutError;
|
|
10509
|
+
var init_lock = __esm(() => {
|
|
10510
|
+
LockTimeoutError = class LockTimeoutError extends Error {
|
|
10511
|
+
connector;
|
|
10512
|
+
constructor(connector) {
|
|
10513
|
+
super(`Could not acquire write lock for connector "${connector}" within ${LOCK_TIMEOUT_MS}ms. Another agent may be writing. Try again shortly.`);
|
|
10514
|
+
this.connector = connector;
|
|
10515
|
+
this.name = "LockTimeoutError";
|
|
10516
|
+
}
|
|
10517
|
+
};
|
|
10518
|
+
});
|
|
10519
|
+
|
|
9572
10520
|
// src/server/auth.ts
|
|
9573
|
-
import { existsSync as
|
|
10521
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5, readdirSync as readdirSync2, rmSync as rmSync2, statSync as statSync3 } from "fs";
|
|
9574
10522
|
import { randomBytes } from "crypto";
|
|
9575
|
-
import { homedir } from "os";
|
|
9576
|
-
import { join as
|
|
10523
|
+
import { homedir as homedir5 } from "os";
|
|
10524
|
+
import { join as join6 } from "path";
|
|
9577
10525
|
function getAuthType(name) {
|
|
9578
10526
|
const docs = getConnectorDocs(name);
|
|
9579
10527
|
if (!docs?.auth)
|
|
@@ -9587,14 +10535,14 @@ function getAuthType(name) {
|
|
|
9587
10535
|
}
|
|
9588
10536
|
function getConnectorConfigDir(name) {
|
|
9589
10537
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
9590
|
-
return
|
|
10538
|
+
return join6(homedir5(), ".connectors", connectorName);
|
|
9591
10539
|
}
|
|
9592
10540
|
function getCurrentProfile(name) {
|
|
9593
10541
|
const configDir = getConnectorConfigDir(name);
|
|
9594
|
-
const currentProfileFile =
|
|
9595
|
-
if (
|
|
10542
|
+
const currentProfileFile = join6(configDir, "current_profile");
|
|
10543
|
+
if (existsSync5(currentProfileFile)) {
|
|
9596
10544
|
try {
|
|
9597
|
-
return
|
|
10545
|
+
return readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
9598
10546
|
} catch {
|
|
9599
10547
|
return "default";
|
|
9600
10548
|
}
|
|
@@ -9606,16 +10554,16 @@ function loadProfileConfig(name) {
|
|
|
9606
10554
|
const profile = getCurrentProfile(name);
|
|
9607
10555
|
let flatConfig = {};
|
|
9608
10556
|
let dirConfig = {};
|
|
9609
|
-
const profileFile =
|
|
9610
|
-
if (
|
|
10557
|
+
const profileFile = join6(configDir, "profiles", `${profile}.json`);
|
|
10558
|
+
if (existsSync5(profileFile)) {
|
|
9611
10559
|
try {
|
|
9612
|
-
flatConfig = JSON.parse(
|
|
10560
|
+
flatConfig = JSON.parse(readFileSync4(profileFile, "utf-8"));
|
|
9613
10561
|
} catch {}
|
|
9614
10562
|
}
|
|
9615
|
-
const profileDirConfig =
|
|
9616
|
-
if (
|
|
10563
|
+
const profileDirConfig = join6(configDir, "profiles", profile, "config.json");
|
|
10564
|
+
if (existsSync5(profileDirConfig)) {
|
|
9617
10565
|
try {
|
|
9618
|
-
dirConfig = JSON.parse(
|
|
10566
|
+
dirConfig = JSON.parse(readFileSync4(profileDirConfig, "utf-8"));
|
|
9619
10567
|
} catch {}
|
|
9620
10568
|
}
|
|
9621
10569
|
if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
|
|
@@ -9626,14 +10574,24 @@ function loadProfileConfig(name) {
|
|
|
9626
10574
|
function loadTokens(name) {
|
|
9627
10575
|
const configDir = getConnectorConfigDir(name);
|
|
9628
10576
|
const profile = getCurrentProfile(name);
|
|
9629
|
-
const tokensFile =
|
|
9630
|
-
if (
|
|
10577
|
+
const tokensFile = join6(configDir, "profiles", profile, "tokens.json");
|
|
10578
|
+
if (existsSync5(tokensFile)) {
|
|
9631
10579
|
try {
|
|
9632
|
-
return JSON.parse(
|
|
10580
|
+
return JSON.parse(readFileSync4(tokensFile, "utf-8"));
|
|
9633
10581
|
} catch {
|
|
9634
10582
|
return null;
|
|
9635
10583
|
}
|
|
9636
10584
|
}
|
|
10585
|
+
const profileConfig = loadProfileConfig(name);
|
|
10586
|
+
if (profileConfig.refreshToken || profileConfig.accessToken) {
|
|
10587
|
+
return {
|
|
10588
|
+
accessToken: profileConfig.accessToken ?? "",
|
|
10589
|
+
refreshToken: profileConfig.refreshToken,
|
|
10590
|
+
expiresAt: profileConfig.expiresAt ?? 0,
|
|
10591
|
+
tokenType: profileConfig.tokenType,
|
|
10592
|
+
scope: profileConfig.scope
|
|
10593
|
+
};
|
|
10594
|
+
}
|
|
9637
10595
|
return null;
|
|
9638
10596
|
}
|
|
9639
10597
|
function getAuthStatus(name) {
|
|
@@ -9678,48 +10636,51 @@ function getEnvVars(name) {
|
|
|
9678
10636
|
const docs = getConnectorDocs(name);
|
|
9679
10637
|
return docs?.envVars || [];
|
|
9680
10638
|
}
|
|
9681
|
-
function saveApiKey(name, key, field) {
|
|
10639
|
+
async function saveApiKey(name, key, field) {
|
|
10640
|
+
return withWriteLock(name, () => _saveApiKey(name, key, field));
|
|
10641
|
+
}
|
|
10642
|
+
function _saveApiKey(name, key, field) {
|
|
9682
10643
|
const configDir = getConnectorConfigDir(name);
|
|
9683
10644
|
const profile = getCurrentProfile(name);
|
|
9684
10645
|
const keyField = field || guessKeyField(name);
|
|
9685
10646
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
9686
|
-
const credentialsFile =
|
|
9687
|
-
|
|
10647
|
+
const credentialsFile = join6(configDir, "credentials.json");
|
|
10648
|
+
mkdirSync5(configDir, { recursive: true });
|
|
9688
10649
|
let creds = {};
|
|
9689
|
-
if (
|
|
10650
|
+
if (existsSync5(credentialsFile)) {
|
|
9690
10651
|
try {
|
|
9691
|
-
creds = JSON.parse(
|
|
10652
|
+
creds = JSON.parse(readFileSync4(credentialsFile, "utf-8"));
|
|
9692
10653
|
} catch {}
|
|
9693
10654
|
}
|
|
9694
10655
|
creds[keyField] = key;
|
|
9695
|
-
|
|
10656
|
+
writeFileSync3(credentialsFile, JSON.stringify(creds, null, 2));
|
|
9696
10657
|
return;
|
|
9697
10658
|
}
|
|
9698
|
-
const profileFile =
|
|
9699
|
-
const profileDir =
|
|
9700
|
-
if (
|
|
10659
|
+
const profileFile = join6(configDir, "profiles", `${profile}.json`);
|
|
10660
|
+
const profileDir = join6(configDir, "profiles", profile);
|
|
10661
|
+
if (existsSync5(profileFile)) {
|
|
9701
10662
|
let config = {};
|
|
9702
10663
|
try {
|
|
9703
|
-
config = JSON.parse(
|
|
10664
|
+
config = JSON.parse(readFileSync4(profileFile, "utf-8"));
|
|
9704
10665
|
} catch {}
|
|
9705
10666
|
config[keyField] = key;
|
|
9706
|
-
|
|
10667
|
+
writeFileSync3(profileFile, JSON.stringify(config, null, 2));
|
|
9707
10668
|
return;
|
|
9708
10669
|
}
|
|
9709
|
-
if (
|
|
9710
|
-
const configFile =
|
|
10670
|
+
if (existsSync5(profileDir)) {
|
|
10671
|
+
const configFile = join6(profileDir, "config.json");
|
|
9711
10672
|
let config = {};
|
|
9712
|
-
if (
|
|
10673
|
+
if (existsSync5(configFile)) {
|
|
9713
10674
|
try {
|
|
9714
|
-
config = JSON.parse(
|
|
10675
|
+
config = JSON.parse(readFileSync4(configFile, "utf-8"));
|
|
9715
10676
|
} catch {}
|
|
9716
10677
|
}
|
|
9717
10678
|
config[keyField] = key;
|
|
9718
|
-
|
|
10679
|
+
writeFileSync3(configFile, JSON.stringify(config, null, 2));
|
|
9719
10680
|
return;
|
|
9720
10681
|
}
|
|
9721
|
-
|
|
9722
|
-
|
|
10682
|
+
mkdirSync5(profileDir, { recursive: true });
|
|
10683
|
+
writeFileSync3(join6(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
|
|
9723
10684
|
}
|
|
9724
10685
|
function guessKeyField(name) {
|
|
9725
10686
|
const docs = getConnectorDocs(name);
|
|
@@ -9737,10 +10698,10 @@ function guessKeyField(name) {
|
|
|
9737
10698
|
}
|
|
9738
10699
|
function getOAuthConfig(name) {
|
|
9739
10700
|
const configDir = getConnectorConfigDir(name);
|
|
9740
|
-
const credentialsFile =
|
|
9741
|
-
if (
|
|
10701
|
+
const credentialsFile = join6(configDir, "credentials.json");
|
|
10702
|
+
if (existsSync5(credentialsFile)) {
|
|
9742
10703
|
try {
|
|
9743
|
-
const creds = JSON.parse(
|
|
10704
|
+
const creds = JSON.parse(readFileSync4(credentialsFile, "utf-8"));
|
|
9744
10705
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
9745
10706
|
} catch {}
|
|
9746
10707
|
}
|
|
@@ -9819,12 +10780,15 @@ async function exchangeOAuthCode(name, code, redirectUri) {
|
|
|
9819
10780
|
function saveOAuthTokens(name, tokens) {
|
|
9820
10781
|
const configDir = getConnectorConfigDir(name);
|
|
9821
10782
|
const profile = getCurrentProfile(name);
|
|
9822
|
-
const profileDir =
|
|
9823
|
-
|
|
9824
|
-
const tokensFile =
|
|
9825
|
-
|
|
10783
|
+
const profileDir = join6(configDir, "profiles", profile);
|
|
10784
|
+
mkdirSync5(profileDir, { recursive: true });
|
|
10785
|
+
const tokensFile = join6(profileDir, "tokens.json");
|
|
10786
|
+
writeFileSync3(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
9826
10787
|
}
|
|
9827
10788
|
async function refreshOAuthToken(name) {
|
|
10789
|
+
return withWriteLock(name, () => _refreshOAuthToken(name));
|
|
10790
|
+
}
|
|
10791
|
+
async function _refreshOAuthToken(name) {
|
|
9828
10792
|
const oauthConfig = getOAuthConfig(name);
|
|
9829
10793
|
const currentTokens = loadTokens(name);
|
|
9830
10794
|
if (!oauthConfig.clientId || !oauthConfig.clientSecret) {
|
|
@@ -9861,15 +10825,15 @@ async function refreshOAuthToken(name) {
|
|
|
9861
10825
|
}
|
|
9862
10826
|
function listProfiles(name) {
|
|
9863
10827
|
const configDir = getConnectorConfigDir(name);
|
|
9864
|
-
const profilesDir =
|
|
9865
|
-
if (!
|
|
10828
|
+
const profilesDir = join6(configDir, "profiles");
|
|
10829
|
+
if (!existsSync5(profilesDir))
|
|
9866
10830
|
return ["default"];
|
|
9867
10831
|
const seen = new Set;
|
|
9868
10832
|
try {
|
|
9869
10833
|
const entries = readdirSync2(profilesDir);
|
|
9870
10834
|
for (const entry of entries) {
|
|
9871
|
-
const fullPath =
|
|
9872
|
-
const stat =
|
|
10835
|
+
const fullPath = join6(profilesDir, entry);
|
|
10836
|
+
const stat = statSync3(fullPath);
|
|
9873
10837
|
if (stat.isDirectory()) {
|
|
9874
10838
|
seen.add(entry);
|
|
9875
10839
|
} else if (entry.endsWith(".json")) {
|
|
@@ -9882,25 +10846,25 @@ function listProfiles(name) {
|
|
|
9882
10846
|
}
|
|
9883
10847
|
function switchProfile(name, profile) {
|
|
9884
10848
|
const configDir = getConnectorConfigDir(name);
|
|
9885
|
-
|
|
9886
|
-
|
|
10849
|
+
mkdirSync5(configDir, { recursive: true });
|
|
10850
|
+
writeFileSync3(join6(configDir, "current_profile"), profile);
|
|
9887
10851
|
}
|
|
9888
10852
|
function deleteProfile(name, profile) {
|
|
9889
10853
|
if (profile === "default")
|
|
9890
10854
|
return false;
|
|
9891
10855
|
const configDir = getConnectorConfigDir(name);
|
|
9892
|
-
const profilesDir =
|
|
9893
|
-
const profileFile =
|
|
9894
|
-
if (
|
|
9895
|
-
|
|
10856
|
+
const profilesDir = join6(configDir, "profiles");
|
|
10857
|
+
const profileFile = join6(profilesDir, `${profile}.json`);
|
|
10858
|
+
if (existsSync5(profileFile)) {
|
|
10859
|
+
rmSync2(profileFile);
|
|
9896
10860
|
if (getCurrentProfile(name) === profile) {
|
|
9897
10861
|
switchProfile(name, "default");
|
|
9898
10862
|
}
|
|
9899
10863
|
return true;
|
|
9900
10864
|
}
|
|
9901
|
-
const profileDir =
|
|
9902
|
-
if (
|
|
9903
|
-
|
|
10865
|
+
const profileDir = join6(profilesDir, profile);
|
|
10866
|
+
if (existsSync5(profileDir)) {
|
|
10867
|
+
rmSync2(profileDir, { recursive: true });
|
|
9904
10868
|
if (getCurrentProfile(name) === profile) {
|
|
9905
10869
|
switchProfile(name, "default");
|
|
9906
10870
|
}
|
|
@@ -9911,6 +10875,7 @@ function deleteProfile(name, profile) {
|
|
|
9911
10875
|
var FETCH_TIMEOUT = 1e4, oauthStateStore, GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth", GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token", GOOGLE_SCOPES;
|
|
9912
10876
|
var init_auth = __esm(() => {
|
|
9913
10877
|
init_installer();
|
|
10878
|
+
init_lock();
|
|
9914
10879
|
oauthStateStore = new Map;
|
|
9915
10880
|
GOOGLE_SCOPES = {
|
|
9916
10881
|
gmail: [
|
|
@@ -9952,15 +10917,222 @@ var init_auth = __esm(() => {
|
|
|
9952
10917
|
};
|
|
9953
10918
|
});
|
|
9954
10919
|
|
|
10920
|
+
// src/db/promotions.ts
|
|
10921
|
+
var exports_promotions = {};
|
|
10922
|
+
__export(exports_promotions, {
|
|
10923
|
+
promoteConnector: () => promoteConnector,
|
|
10924
|
+
isPromoted: () => isPromoted,
|
|
10925
|
+
getPromotedConnectors: () => getPromotedConnectors,
|
|
10926
|
+
demoteConnector: () => demoteConnector
|
|
10927
|
+
});
|
|
10928
|
+
function promoteConnector(name, db) {
|
|
10929
|
+
const d = db ?? getDatabase();
|
|
10930
|
+
d.run("INSERT OR REPLACE INTO connector_promotions (connector, promoted_at) VALUES (?, ?)", [name, now()]);
|
|
10931
|
+
}
|
|
10932
|
+
function demoteConnector(name, db) {
|
|
10933
|
+
const d = db ?? getDatabase();
|
|
10934
|
+
return d.run("DELETE FROM connector_promotions WHERE connector = ?", [name]).changes > 0;
|
|
10935
|
+
}
|
|
10936
|
+
function getPromotedConnectors(db) {
|
|
10937
|
+
const d = db ?? getDatabase();
|
|
10938
|
+
return d.query("SELECT connector FROM connector_promotions ORDER BY promoted_at DESC").all().map((r) => r.connector);
|
|
10939
|
+
}
|
|
10940
|
+
function isPromoted(name, db) {
|
|
10941
|
+
const d = db ?? getDatabase();
|
|
10942
|
+
const row = d.query("SELECT 1 FROM connector_promotions WHERE connector = ?").get(name);
|
|
10943
|
+
return !!row;
|
|
10944
|
+
}
|
|
10945
|
+
var init_promotions = __esm(() => {
|
|
10946
|
+
init_database();
|
|
10947
|
+
});
|
|
10948
|
+
|
|
10949
|
+
// src/db/usage.ts
|
|
10950
|
+
var exports_usage = {};
|
|
10951
|
+
__export(exports_usage, {
|
|
10952
|
+
logUsage: () => logUsage,
|
|
10953
|
+
getUsageStats: () => getUsageStats,
|
|
10954
|
+
getUsageMap: () => getUsageMap,
|
|
10955
|
+
getTopConnectors: () => getTopConnectors,
|
|
10956
|
+
cleanOldUsage: () => cleanOldUsage
|
|
10957
|
+
});
|
|
10958
|
+
function logUsage(connector, action, agentId, db) {
|
|
10959
|
+
const d = db ?? getDatabase();
|
|
10960
|
+
d.run("INSERT INTO connector_usage (id, connector, action, agent_id, timestamp) VALUES (?, ?, ?, ?, ?)", [shortUuid(), connector, action, agentId ?? null, now()]);
|
|
10961
|
+
}
|
|
10962
|
+
function getUsageStats(connector, db) {
|
|
10963
|
+
const d = db ?? getDatabase();
|
|
10964
|
+
const total = d.query("SELECT COUNT(*) as c FROM connector_usage WHERE connector = ?").get(connector).c;
|
|
10965
|
+
const d7 = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
10966
|
+
const last7d = d.query("SELECT COUNT(*) as c FROM connector_usage WHERE connector = ? AND timestamp > ?").get(connector, d7).c;
|
|
10967
|
+
const d1 = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
10968
|
+
const last24h = d.query("SELECT COUNT(*) as c FROM connector_usage WHERE connector = ? AND timestamp > ?").get(connector, d1).c;
|
|
10969
|
+
return { connector, total, last7d, last24h };
|
|
10970
|
+
}
|
|
10971
|
+
function getTopConnectors(limit = 10, days = 7, db) {
|
|
10972
|
+
const d = db ?? getDatabase();
|
|
10973
|
+
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
10974
|
+
return d.query("SELECT connector, COUNT(*) as count FROM connector_usage WHERE timestamp > ? GROUP BY connector ORDER BY count DESC LIMIT ?").all(since, limit);
|
|
10975
|
+
}
|
|
10976
|
+
function getUsageMap(days = 7, db) {
|
|
10977
|
+
const top = getTopConnectors(100, days, db);
|
|
10978
|
+
return new Map(top.map((t) => [t.connector, t.count]));
|
|
10979
|
+
}
|
|
10980
|
+
function cleanOldUsage(days = 30, db) {
|
|
10981
|
+
const d = db ?? getDatabase();
|
|
10982
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
10983
|
+
return d.run("DELETE FROM connector_usage WHERE timestamp < ?", [cutoff]).changes;
|
|
10984
|
+
}
|
|
10985
|
+
var init_usage = __esm(() => {
|
|
10986
|
+
init_database();
|
|
10987
|
+
});
|
|
10988
|
+
|
|
10989
|
+
// src/db/agents.ts
|
|
10990
|
+
function shortUuid2() {
|
|
10991
|
+
return crypto.randomUUID().slice(0, 8);
|
|
10992
|
+
}
|
|
10993
|
+
function isAgentConflict(result) {
|
|
10994
|
+
return result.conflict === true;
|
|
10995
|
+
}
|
|
10996
|
+
function registerAgent(input, db) {
|
|
10997
|
+
const d = db ?? getDatabase();
|
|
10998
|
+
const normalizedName = input.name.trim().toLowerCase();
|
|
10999
|
+
const existing = getAgentByName(normalizedName, d);
|
|
11000
|
+
if (existing) {
|
|
11001
|
+
const lastSeenMs = new Date(existing.last_seen_at).getTime();
|
|
11002
|
+
const isActive = Date.now() - lastSeenMs < AGENT_ACTIVE_WINDOW_MS;
|
|
11003
|
+
const sameSession = input.session_id && existing.session_id && input.session_id === existing.session_id;
|
|
11004
|
+
const differentSession = input.session_id && existing.session_id && input.session_id !== existing.session_id;
|
|
11005
|
+
if (isActive && differentSession) {
|
|
11006
|
+
const minutesAgo = Math.round((Date.now() - lastSeenMs) / 60000);
|
|
11007
|
+
return {
|
|
11008
|
+
conflict: true,
|
|
11009
|
+
existing_id: existing.id,
|
|
11010
|
+
existing_name: existing.name,
|
|
11011
|
+
last_seen_at: existing.last_seen_at,
|
|
11012
|
+
session_hint: existing.session_id ? existing.session_id.slice(0, 8) : null,
|
|
11013
|
+
working_dir: null,
|
|
11014
|
+
message: `Agent "${normalizedName}" is already active (last seen ${minutesAgo}m ago). Pass session_id="${existing.session_id}" to reclaim it, or choose a different name.`
|
|
11015
|
+
};
|
|
11016
|
+
}
|
|
11017
|
+
const updates = ["last_seen_at = ?"];
|
|
11018
|
+
const params = [now()];
|
|
11019
|
+
if (input.session_id && !sameSession) {
|
|
11020
|
+
updates.push("session_id = ?");
|
|
11021
|
+
params.push(input.session_id);
|
|
11022
|
+
}
|
|
11023
|
+
params.push(existing.id);
|
|
11024
|
+
d.run(`UPDATE agents SET ${updates.join(", ")} WHERE id = ?`, params);
|
|
11025
|
+
return getAgent(existing.id, d);
|
|
11026
|
+
}
|
|
11027
|
+
const id = shortUuid2();
|
|
11028
|
+
const ts = now();
|
|
11029
|
+
d.run(`INSERT INTO agents (id, name, session_id, role, last_seen_at, created_at)
|
|
11030
|
+
VALUES (?, ?, ?, ?, ?, ?)`, [id, normalizedName, input.session_id ?? null, input.role ?? "agent", ts, ts]);
|
|
11031
|
+
return getAgent(id, d);
|
|
11032
|
+
}
|
|
11033
|
+
function getAgent(id, db) {
|
|
11034
|
+
const d = db ?? getDatabase();
|
|
11035
|
+
return d.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
11036
|
+
}
|
|
11037
|
+
function getAgentByName(name, db) {
|
|
11038
|
+
const d = db ?? getDatabase();
|
|
11039
|
+
return d.query("SELECT * FROM agents WHERE LOWER(name) = ?").get(name.trim().toLowerCase());
|
|
11040
|
+
}
|
|
11041
|
+
function listAgents(db) {
|
|
11042
|
+
const d = db ?? getDatabase();
|
|
11043
|
+
return d.query("SELECT * FROM agents ORDER BY name").all();
|
|
11044
|
+
}
|
|
11045
|
+
function deleteAgent(id, db) {
|
|
11046
|
+
const d = db ?? getDatabase();
|
|
11047
|
+
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
11048
|
+
}
|
|
11049
|
+
var AGENT_ACTIVE_WINDOW_MS;
|
|
11050
|
+
var init_agents = __esm(() => {
|
|
11051
|
+
init_database();
|
|
11052
|
+
AGENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
|
|
11053
|
+
});
|
|
11054
|
+
|
|
11055
|
+
// src/db/rate.ts
|
|
11056
|
+
function ensureRateTable(db) {
|
|
11057
|
+
db.run(`
|
|
11058
|
+
CREATE TABLE IF NOT EXISTS connector_rate_usage (
|
|
11059
|
+
agent_id TEXT NOT NULL,
|
|
11060
|
+
connector TEXT NOT NULL,
|
|
11061
|
+
window_start TEXT NOT NULL,
|
|
11062
|
+
call_count INTEGER NOT NULL DEFAULT 0,
|
|
11063
|
+
PRIMARY KEY (agent_id, connector, window_start)
|
|
11064
|
+
)
|
|
11065
|
+
`);
|
|
11066
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_rate_usage_window ON connector_rate_usage(connector, window_start)`);
|
|
11067
|
+
}
|
|
11068
|
+
function countActiveAgents(db) {
|
|
11069
|
+
const cutoff = new Date(Date.now() - AGENT_ACTIVE_WINDOW_MS2).toISOString();
|
|
11070
|
+
const row = db.query("SELECT COUNT(*) as count FROM agents WHERE last_seen_at > ?").get(cutoff);
|
|
11071
|
+
return Math.max(1, row?.count ?? 1);
|
|
11072
|
+
}
|
|
11073
|
+
function currentWindowStart() {
|
|
11074
|
+
const now3 = Date.now();
|
|
11075
|
+
const windowMs = WINDOW_SECONDS * 1000;
|
|
11076
|
+
return new Date(Math.floor(now3 / windowMs) * windowMs).toISOString();
|
|
11077
|
+
}
|
|
11078
|
+
function checkRateBudget(agentId, connector, connectorLimit, consume = true, db) {
|
|
11079
|
+
const d = db ?? getDatabase();
|
|
11080
|
+
ensureRateTable(d);
|
|
11081
|
+
const activeAgents = countActiveAgents(d);
|
|
11082
|
+
const budget = Math.max(1, Math.floor(connectorLimit / activeAgents));
|
|
11083
|
+
const windowStart = currentWindowStart();
|
|
11084
|
+
const windowMs = WINDOW_SECONDS * 1000;
|
|
11085
|
+
const windowEnd = new Date(Math.floor(Date.now() / windowMs) * windowMs + windowMs);
|
|
11086
|
+
const windowResetsIn = windowEnd.getTime() - Date.now();
|
|
11087
|
+
const row = d.query("SELECT call_count FROM connector_rate_usage WHERE agent_id = ? AND connector = ? AND window_start = ?").get(agentId, connector, windowStart);
|
|
11088
|
+
const used = row?.call_count ?? 0;
|
|
11089
|
+
if (used >= budget) {
|
|
11090
|
+
return {
|
|
11091
|
+
exceeded: true,
|
|
11092
|
+
connector,
|
|
11093
|
+
agent_id: agentId,
|
|
11094
|
+
budget,
|
|
11095
|
+
used,
|
|
11096
|
+
active_agents: activeAgents,
|
|
11097
|
+
window_resets_in_ms: windowResetsIn,
|
|
11098
|
+
message: `Rate budget exceeded for "${connector}" (${used}/${budget} calls used, ${activeAgents} active agent${activeAgents === 1 ? "" : "s"} sharing limit of ${connectorLimit}/min). Resets in ${Math.ceil(windowResetsIn / 1000)}s.`
|
|
11099
|
+
};
|
|
11100
|
+
}
|
|
11101
|
+
if (consume) {
|
|
11102
|
+
d.run(`INSERT INTO connector_rate_usage (agent_id, connector, window_start, call_count)
|
|
11103
|
+
VALUES (?, ?, ?, 1)
|
|
11104
|
+
ON CONFLICT(agent_id, connector, window_start) DO UPDATE SET call_count = call_count + 1`, [agentId, connector, windowStart]);
|
|
11105
|
+
}
|
|
11106
|
+
return {
|
|
11107
|
+
connector,
|
|
11108
|
+
agent_id: agentId,
|
|
11109
|
+
limit: connectorLimit,
|
|
11110
|
+
active_agents: activeAgents,
|
|
11111
|
+
budget,
|
|
11112
|
+
used: consume ? used + 1 : used,
|
|
11113
|
+
remaining: consume ? budget - used - 1 : budget - used,
|
|
11114
|
+
window_start: windowStart,
|
|
11115
|
+
window_resets_in_ms: windowResetsIn
|
|
11116
|
+
};
|
|
11117
|
+
}
|
|
11118
|
+
function getRateBudget(agentId, connector, connectorLimit, db) {
|
|
11119
|
+
return checkRateBudget(agentId, connector, connectorLimit, false, db);
|
|
11120
|
+
}
|
|
11121
|
+
var AGENT_ACTIVE_WINDOW_MS2, WINDOW_SECONDS = 60;
|
|
11122
|
+
var init_rate = __esm(() => {
|
|
11123
|
+
init_database();
|
|
11124
|
+
AGENT_ACTIVE_WINDOW_MS2 = 30 * 60 * 1000;
|
|
11125
|
+
});
|
|
11126
|
+
|
|
9955
11127
|
// src/server/serve.ts
|
|
9956
11128
|
var exports_serve = {};
|
|
9957
11129
|
__export(exports_serve, {
|
|
9958
11130
|
startServer: () => startServer
|
|
9959
11131
|
});
|
|
9960
|
-
import { existsSync as
|
|
9961
|
-
import { join as
|
|
11132
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
11133
|
+
import { join as join8, dirname as dirname4, extname, basename } from "path";
|
|
9962
11134
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
9963
|
-
import { homedir as
|
|
11135
|
+
import { homedir as homedir6 } from "os";
|
|
9964
11136
|
function logActivity(action, connector, detail) {
|
|
9965
11137
|
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
9966
11138
|
if (activityLog.length > MAX_ACTIVITY_LOG) {
|
|
@@ -9971,20 +11143,20 @@ function resolveDashboardDir() {
|
|
|
9971
11143
|
const candidates = [];
|
|
9972
11144
|
try {
|
|
9973
11145
|
const scriptDir = dirname4(fileURLToPath4(import.meta.url));
|
|
9974
|
-
candidates.push(
|
|
9975
|
-
candidates.push(
|
|
11146
|
+
candidates.push(join8(scriptDir, "..", "dashboard", "dist"));
|
|
11147
|
+
candidates.push(join8(scriptDir, "..", "..", "dashboard", "dist"));
|
|
9976
11148
|
} catch {}
|
|
9977
11149
|
if (process.argv[1]) {
|
|
9978
11150
|
const mainDir = dirname4(process.argv[1]);
|
|
9979
|
-
candidates.push(
|
|
9980
|
-
candidates.push(
|
|
11151
|
+
candidates.push(join8(mainDir, "..", "dashboard", "dist"));
|
|
11152
|
+
candidates.push(join8(mainDir, "..", "..", "dashboard", "dist"));
|
|
9981
11153
|
}
|
|
9982
|
-
candidates.push(
|
|
11154
|
+
candidates.push(join8(process.cwd(), "dashboard", "dist"));
|
|
9983
11155
|
for (const candidate of candidates) {
|
|
9984
|
-
if (
|
|
11156
|
+
if (existsSync7(candidate))
|
|
9985
11157
|
return candidate;
|
|
9986
11158
|
}
|
|
9987
|
-
return
|
|
11159
|
+
return join8(process.cwd(), "dashboard", "dist");
|
|
9988
11160
|
}
|
|
9989
11161
|
function json(data, status = 200, port) {
|
|
9990
11162
|
return new Response(JSON.stringify(data), {
|
|
@@ -9996,6 +11168,18 @@ function json(data, status = 200, port) {
|
|
|
9996
11168
|
}
|
|
9997
11169
|
});
|
|
9998
11170
|
}
|
|
11171
|
+
async function jsonStripped(data, status = 200, port) {
|
|
11172
|
+
const raw = JSON.stringify(data);
|
|
11173
|
+
const body = await maybeStrip(raw);
|
|
11174
|
+
return new Response(body, {
|
|
11175
|
+
status,
|
|
11176
|
+
headers: {
|
|
11177
|
+
"Content-Type": "application/json",
|
|
11178
|
+
"Access-Control-Allow-Origin": port ? `http://localhost:${port}` : "*",
|
|
11179
|
+
...SECURITY_HEADERS
|
|
11180
|
+
}
|
|
11181
|
+
});
|
|
11182
|
+
}
|
|
9999
11183
|
function htmlResponse(content, status = 200) {
|
|
10000
11184
|
return new Response(content, {
|
|
10001
11185
|
status,
|
|
@@ -10057,7 +11241,7 @@ function oauthPage(type, title, message, hint, extra) {
|
|
|
10057
11241
|
</body></html>`;
|
|
10058
11242
|
}
|
|
10059
11243
|
function serveStaticFile(filePath) {
|
|
10060
|
-
if (!
|
|
11244
|
+
if (!existsSync7(filePath))
|
|
10061
11245
|
return null;
|
|
10062
11246
|
const ext = extname(filePath);
|
|
10063
11247
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -10081,7 +11265,7 @@ async function startServer(requestedPort, options) {
|
|
|
10081
11265
|
const shouldOpen = options?.open ?? true;
|
|
10082
11266
|
loadConnectorVersions();
|
|
10083
11267
|
const dashboardDir = resolveDashboardDir();
|
|
10084
|
-
const dashboardExists =
|
|
11268
|
+
const dashboardExists = existsSync7(dashboardDir);
|
|
10085
11269
|
if (!dashboardExists) {
|
|
10086
11270
|
console.error(`
|
|
10087
11271
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -10110,10 +11294,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10110
11294
|
const fields = fieldsParam ? new Set(fieldsParam.split(",").map((f) => f.trim())) : null;
|
|
10111
11295
|
const data = getAllConnectorsWithAuth();
|
|
10112
11296
|
if (compact) {
|
|
10113
|
-
return
|
|
11297
|
+
return jsonStripped(data.map((c) => ({ name: c.name, category: c.category, installed: c.installed })), 200, port);
|
|
10114
11298
|
}
|
|
10115
11299
|
if (fields) {
|
|
10116
|
-
return
|
|
11300
|
+
return jsonStripped(data.map((c) => {
|
|
10117
11301
|
const out = {};
|
|
10118
11302
|
for (const f of fields) {
|
|
10119
11303
|
if (f in c)
|
|
@@ -10122,7 +11306,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10122
11306
|
return out;
|
|
10123
11307
|
}), 200, port);
|
|
10124
11308
|
}
|
|
10125
|
-
return
|
|
11309
|
+
return jsonStripped(data, 200, port);
|
|
10126
11310
|
}
|
|
10127
11311
|
const singleMatch = path.match(/^\/api\/connectors\/([^/]+)$/);
|
|
10128
11312
|
if (singleMatch && method === "GET") {
|
|
@@ -10156,7 +11340,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10156
11340
|
const body = await req.json();
|
|
10157
11341
|
if (!body.key)
|
|
10158
11342
|
return json({ error: "Missing 'key' in request body" }, 400, port);
|
|
10159
|
-
saveApiKey(name, body.key, body.field);
|
|
11343
|
+
await saveApiKey(name, body.key, body.field);
|
|
10160
11344
|
logActivity("key_saved", name, body.field ? `Field: ${body.field}` : undefined);
|
|
10161
11345
|
return json({ success: true }, 200, port);
|
|
10162
11346
|
} catch (e) {
|
|
@@ -10201,7 +11385,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10201
11385
|
if (!isValidConnectorName(name))
|
|
10202
11386
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
10203
11387
|
try {
|
|
10204
|
-
removeConnector(name);
|
|
11388
|
+
const removed = removeConnector(name);
|
|
11389
|
+
if (!removed) {
|
|
11390
|
+
return json({ error: `Connector '${name}' is not installed` }, 404, port);
|
|
11391
|
+
}
|
|
10205
11392
|
logActivity("uninstalled", name);
|
|
10206
11393
|
return json({ success: true, name }, 200, port);
|
|
10207
11394
|
} catch (e) {
|
|
@@ -10227,6 +11414,167 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10227
11414
|
if (path === "/api/activity" && method === "GET") {
|
|
10228
11415
|
return json(activityLog, 200, port);
|
|
10229
11416
|
}
|
|
11417
|
+
if (path === "/api/hot" && method === "GET") {
|
|
11418
|
+
const { getTopConnectors: getTopConnectors2 } = await Promise.resolve().then(() => (init_usage(), exports_usage));
|
|
11419
|
+
const { getPromotedConnectors: getPromotedConnectors2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11420
|
+
const limit = parseInt(url2.searchParams.get("limit") || "10", 10);
|
|
11421
|
+
const days = parseInt(url2.searchParams.get("days") || "7", 10);
|
|
11422
|
+
const db = getDatabase2();
|
|
11423
|
+
const top = getTopConnectors2(limit, days, db);
|
|
11424
|
+
const promoted = new Set(getPromotedConnectors2(db));
|
|
11425
|
+
return json(top.map((t) => ({ ...t, promoted: promoted.has(t.connector) })), 200, port);
|
|
11426
|
+
}
|
|
11427
|
+
const promoteMatch = path.match(/^\/api\/connectors\/([^/]+)\/promote$/);
|
|
11428
|
+
if (promoteMatch && method === "POST") {
|
|
11429
|
+
const name = promoteMatch[1];
|
|
11430
|
+
if (!getConnector(name))
|
|
11431
|
+
return json({ error: "Connector not found" }, 404, port);
|
|
11432
|
+
const { promoteConnector: promoteConnector2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11433
|
+
promoteConnector2(name, getDatabase2());
|
|
11434
|
+
return json({ success: true, connector: name }, 200, port);
|
|
11435
|
+
}
|
|
11436
|
+
if (promoteMatch && method === "DELETE") {
|
|
11437
|
+
const { demoteConnector: demoteConnector2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11438
|
+
const removed = demoteConnector2(promoteMatch[1], getDatabase2());
|
|
11439
|
+
return json({ success: removed, connector: promoteMatch[1] }, 200, port);
|
|
11440
|
+
}
|
|
11441
|
+
if (path === "/api/llm" && method === "GET") {
|
|
11442
|
+
const config = getLlmConfig();
|
|
11443
|
+
if (!config)
|
|
11444
|
+
return json({ configured: false }, 200, port);
|
|
11445
|
+
return json({ configured: true, provider: config.provider, model: config.model, key: maskKey(config.api_key), strip: config.strip }, 200, port);
|
|
11446
|
+
}
|
|
11447
|
+
if (path === "/api/llm" && method === "POST") {
|
|
11448
|
+
const body = await req.json().catch(() => ({}));
|
|
11449
|
+
const validProviders = ["cerebras", "groq", "openai", "anthropic"];
|
|
11450
|
+
const provider = body.provider;
|
|
11451
|
+
if (!provider || !validProviders.includes(provider))
|
|
11452
|
+
return json({ error: "provider must be one of: " + validProviders.join(", ") }, 400, port);
|
|
11453
|
+
const api_key = body.api_key;
|
|
11454
|
+
if (!api_key)
|
|
11455
|
+
return json({ error: "api_key is required" }, 400, port);
|
|
11456
|
+
const model = body.model || getLlmConfig()?.model || "qwen-3-32b";
|
|
11457
|
+
const strip = typeof body.strip === "boolean" ? body.strip : getLlmConfig()?.strip ?? false;
|
|
11458
|
+
saveLlmConfig({ provider, model, api_key, strip });
|
|
11459
|
+
return json({ success: true, provider, model, strip }, 200, port);
|
|
11460
|
+
}
|
|
11461
|
+
if (path === "/api/llm/test" && method === "POST") {
|
|
11462
|
+
const config = getLlmConfig();
|
|
11463
|
+
if (!config)
|
|
11464
|
+
return json({ error: "No LLM configured" }, 400, port);
|
|
11465
|
+
try {
|
|
11466
|
+
const client = new LLMClient(config);
|
|
11467
|
+
const result = await client.complete('Respond with exactly: {"status":"ok"}', "ping");
|
|
11468
|
+
return json({ success: true, provider: result.provider, model: result.model, latency_ms: result.latency_ms, response: result.content }, 200, port);
|
|
11469
|
+
} catch (e) {
|
|
11470
|
+
return json({ success: false, error: e instanceof Error ? e.message : String(e) }, 500, port);
|
|
11471
|
+
}
|
|
11472
|
+
}
|
|
11473
|
+
if (path === "/api/jobs" && method === "GET") {
|
|
11474
|
+
return json(listJobs(getDatabase2()), 200, port);
|
|
11475
|
+
}
|
|
11476
|
+
if (path === "/api/jobs" && method === "POST") {
|
|
11477
|
+
const body = await req.json().catch(() => ({}));
|
|
11478
|
+
if (!body.name || !body.connector || !body.command || !body.cron)
|
|
11479
|
+
return json({ error: "name, connector, command, cron required" }, 400, port);
|
|
11480
|
+
const job = createJob({ name: body.name, connector: body.connector, command: body.command, args: body.args ?? [], cron: body.cron, strip: !!body.strip }, getDatabase2());
|
|
11481
|
+
return json(job, 201, port);
|
|
11482
|
+
}
|
|
11483
|
+
const jobMatch = path.match(/^\/api\/jobs\/([^/]+)$/);
|
|
11484
|
+
if (jobMatch) {
|
|
11485
|
+
const db = getDatabase2();
|
|
11486
|
+
const job = getJobByName(jobMatch[1]) ?? getDatabase2().query("SELECT * FROM connector_jobs WHERE id = ?").get(jobMatch[1]);
|
|
11487
|
+
if (!job && method !== "DELETE")
|
|
11488
|
+
return json({ error: "Job not found" }, 404, port);
|
|
11489
|
+
if (method === "GET")
|
|
11490
|
+
return json(listJobRuns(job.id, 20, db), 200, port);
|
|
11491
|
+
if (method === "DELETE") {
|
|
11492
|
+
const j = getJobByName(jobMatch[1], db);
|
|
11493
|
+
if (!j)
|
|
11494
|
+
return json({ error: "Job not found" }, 404, port);
|
|
11495
|
+
deleteJob(j.id, db);
|
|
11496
|
+
return json({ success: true }, 200, port);
|
|
11497
|
+
}
|
|
11498
|
+
if (method === "PATCH") {
|
|
11499
|
+
const body = await req.json().catch(() => ({}));
|
|
11500
|
+
const j = getJobByName(jobMatch[1], db);
|
|
11501
|
+
const updated = updateJob(j.id, { enabled: typeof body.enabled === "boolean" ? body.enabled : undefined, strip: typeof body.strip === "boolean" ? body.strip : undefined }, db);
|
|
11502
|
+
return json(updated, 200, port);
|
|
11503
|
+
}
|
|
11504
|
+
}
|
|
11505
|
+
const jobRunMatch = path.match(/^\/api\/jobs\/([^/]+)\/run$/);
|
|
11506
|
+
if (jobRunMatch && method === "POST") {
|
|
11507
|
+
const db = getDatabase2();
|
|
11508
|
+
const job = getJobByName(jobRunMatch[1], db);
|
|
11509
|
+
if (!job)
|
|
11510
|
+
return json({ error: "Job not found" }, 404, port);
|
|
11511
|
+
const result = await triggerJob(job, db);
|
|
11512
|
+
return json(result, 200, port);
|
|
11513
|
+
}
|
|
11514
|
+
if (path === "/api/workflows" && method === "GET") {
|
|
11515
|
+
return json(listWorkflows(getDatabase2()), 200, port);
|
|
11516
|
+
}
|
|
11517
|
+
if (path === "/api/workflows" && method === "POST") {
|
|
11518
|
+
const body = await req.json().catch(() => ({}));
|
|
11519
|
+
if (!body.name || !body.steps)
|
|
11520
|
+
return json({ error: "name and steps required" }, 400, port);
|
|
11521
|
+
const wf = createWorkflow({ name: body.name, steps: body.steps }, getDatabase2());
|
|
11522
|
+
return json(wf, 201, port);
|
|
11523
|
+
}
|
|
11524
|
+
const wfMatch = path.match(/^\/api\/workflows\/([^/]+)$/);
|
|
11525
|
+
if (wfMatch) {
|
|
11526
|
+
const db = getDatabase2();
|
|
11527
|
+
const wf = getWorkflowByName(wfMatch[1], db);
|
|
11528
|
+
if (!wf)
|
|
11529
|
+
return json({ error: "Workflow not found" }, 404, port);
|
|
11530
|
+
if (method === "GET")
|
|
11531
|
+
return json(wf, 200, port);
|
|
11532
|
+
if (method === "DELETE") {
|
|
11533
|
+
deleteWorkflow(wf.id, db);
|
|
11534
|
+
return json({ success: true }, 200, port);
|
|
11535
|
+
}
|
|
11536
|
+
}
|
|
11537
|
+
const wfRunMatch = path.match(/^\/api\/workflows\/([^/]+)\/run$/);
|
|
11538
|
+
if (wfRunMatch && method === "POST") {
|
|
11539
|
+
const wf = getWorkflowByName(wfRunMatch[1], getDatabase2());
|
|
11540
|
+
if (!wf)
|
|
11541
|
+
return json({ error: "Workflow not found" }, 404, port);
|
|
11542
|
+
const result = await runWorkflow(wf);
|
|
11543
|
+
return json(result, 200, port);
|
|
11544
|
+
}
|
|
11545
|
+
if (path === "/api/agents" && method === "GET") {
|
|
11546
|
+
return json(listAgents(), 200, port);
|
|
11547
|
+
}
|
|
11548
|
+
if (path === "/api/agents/register" && method === "POST") {
|
|
11549
|
+
const body = await req.json().catch(() => ({}));
|
|
11550
|
+
const name = typeof body.name === "string" ? body.name : null;
|
|
11551
|
+
if (!name)
|
|
11552
|
+
return json({ error: "name is required" }, 400, port);
|
|
11553
|
+
const result = registerAgent({
|
|
11554
|
+
name,
|
|
11555
|
+
session_id: typeof body.session_id === "string" ? body.session_id : undefined,
|
|
11556
|
+
role: typeof body.role === "string" ? body.role : undefined
|
|
11557
|
+
});
|
|
11558
|
+
if (isAgentConflict(result))
|
|
11559
|
+
return json(result, 409, port);
|
|
11560
|
+
return json(result, 200, port);
|
|
11561
|
+
}
|
|
11562
|
+
if (path.startsWith("/api/agents/") && method === "DELETE") {
|
|
11563
|
+
const agentName = path.slice("/api/agents/".length);
|
|
11564
|
+
const agent = getAgentByName(agentName);
|
|
11565
|
+
if (!agent)
|
|
11566
|
+
return json({ error: "Agent not found" }, 404, port);
|
|
11567
|
+
deleteAgent(agent.id);
|
|
11568
|
+
return json({ success: true }, 200, port);
|
|
11569
|
+
}
|
|
11570
|
+
const rateMatch = path.match(/^\/api\/rate\/([^/]+)\/([^/]+)$/);
|
|
11571
|
+
if (rateMatch && method === "GET") {
|
|
11572
|
+
const [, agentId, connector] = rateMatch;
|
|
11573
|
+
const limit = parseInt(url2.searchParams.get("limit") || "60", 10);
|
|
11574
|
+
const consume = url2.searchParams.get("consume") === "true";
|
|
11575
|
+
const result = consume ? checkRateBudget(agentId, connector, limit) : getRateBudget(agentId, connector, limit);
|
|
11576
|
+
return json(result, 200, port);
|
|
11577
|
+
}
|
|
10230
11578
|
const profilesMatch = path.match(/^\/api\/connectors\/([^/]+)\/profiles$/);
|
|
10231
11579
|
if (profilesMatch && method === "GET") {
|
|
10232
11580
|
const name = profilesMatch[1];
|
|
@@ -10234,12 +11582,12 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10234
11582
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
10235
11583
|
try {
|
|
10236
11584
|
const profiles = listProfiles(name);
|
|
10237
|
-
const configDir =
|
|
10238
|
-
const currentProfileFile =
|
|
11585
|
+
const configDir = join8(homedir6(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
11586
|
+
const currentProfileFile = join8(configDir, "current_profile");
|
|
10239
11587
|
let current = "default";
|
|
10240
|
-
if (
|
|
11588
|
+
if (existsSync7(currentProfileFile)) {
|
|
10241
11589
|
try {
|
|
10242
|
-
current =
|
|
11590
|
+
current = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
10243
11591
|
} catch {}
|
|
10244
11592
|
}
|
|
10245
11593
|
return json({ current, profiles }, 200, port);
|
|
@@ -10286,16 +11634,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10286
11634
|
}
|
|
10287
11635
|
if (path === "/api/export" && method === "GET") {
|
|
10288
11636
|
try {
|
|
10289
|
-
const connectDir =
|
|
11637
|
+
const connectDir = join8(homedir6(), ".connectors");
|
|
10290
11638
|
const result = {};
|
|
10291
|
-
if (
|
|
11639
|
+
if (existsSync7(connectDir)) {
|
|
10292
11640
|
const entries = readdirSync3(connectDir, { withFileTypes: true });
|
|
10293
11641
|
for (const entry of entries) {
|
|
10294
11642
|
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
10295
11643
|
continue;
|
|
10296
11644
|
const connectorName = entry.name.replace(/^connect-/, "");
|
|
10297
|
-
const profilesDir =
|
|
10298
|
-
if (!
|
|
11645
|
+
const profilesDir = join8(connectDir, entry.name, "profiles");
|
|
11646
|
+
if (!existsSync7(profilesDir))
|
|
10299
11647
|
continue;
|
|
10300
11648
|
const profiles = {};
|
|
10301
11649
|
const profileEntries = readdirSync3(profilesDir, { withFileTypes: true });
|
|
@@ -10303,15 +11651,15 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10303
11651
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
10304
11652
|
const profileName = basename(pEntry.name, ".json");
|
|
10305
11653
|
try {
|
|
10306
|
-
const config = JSON.parse(
|
|
11654
|
+
const config = JSON.parse(readFileSync5(join8(profilesDir, pEntry.name), "utf-8"));
|
|
10307
11655
|
profiles[profileName] = config;
|
|
10308
11656
|
} catch {}
|
|
10309
11657
|
}
|
|
10310
11658
|
if (pEntry.isDirectory()) {
|
|
10311
|
-
const configPath =
|
|
10312
|
-
if (
|
|
11659
|
+
const configPath = join8(profilesDir, pEntry.name, "config.json");
|
|
11660
|
+
if (existsSync7(configPath)) {
|
|
10313
11661
|
try {
|
|
10314
|
-
const config = JSON.parse(
|
|
11662
|
+
const config = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
10315
11663
|
profiles[pEntry.name] = config;
|
|
10316
11664
|
} catch {}
|
|
10317
11665
|
}
|
|
@@ -10346,20 +11694,20 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10346
11694
|
return json({ error: "Invalid import format: missing 'connectors' object" }, 400, port);
|
|
10347
11695
|
}
|
|
10348
11696
|
let imported = 0;
|
|
10349
|
-
const connectDir =
|
|
11697
|
+
const connectDir = join8(homedir6(), ".connectors");
|
|
10350
11698
|
for (const [connectorName, data] of Object.entries(body.connectors)) {
|
|
10351
11699
|
if (!isValidConnectorName(connectorName))
|
|
10352
11700
|
continue;
|
|
10353
11701
|
if (!data.profiles || typeof data.profiles !== "object")
|
|
10354
11702
|
continue;
|
|
10355
|
-
const connectorDir =
|
|
10356
|
-
const profilesDir =
|
|
11703
|
+
const connectorDir = join8(connectDir, `connect-${connectorName}`);
|
|
11704
|
+
const profilesDir = join8(connectorDir, "profiles");
|
|
10357
11705
|
for (const [profileName, config] of Object.entries(data.profiles)) {
|
|
10358
11706
|
if (!config || typeof config !== "object")
|
|
10359
11707
|
continue;
|
|
10360
|
-
|
|
10361
|
-
const profileFile =
|
|
10362
|
-
|
|
11708
|
+
mkdirSync6(profilesDir, { recursive: true });
|
|
11709
|
+
const profileFile = join8(profilesDir, `${profileName}.json`);
|
|
11710
|
+
writeFileSync4(profileFile, JSON.stringify(config, null, 2));
|
|
10363
11711
|
imported++;
|
|
10364
11712
|
}
|
|
10365
11713
|
}
|
|
@@ -10414,12 +11762,12 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10414
11762
|
}
|
|
10415
11763
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
10416
11764
|
if (path !== "/") {
|
|
10417
|
-
const filePath =
|
|
11765
|
+
const filePath = join8(dashboardDir, path);
|
|
10418
11766
|
const res2 = serveStaticFile(filePath);
|
|
10419
11767
|
if (res2)
|
|
10420
11768
|
return res2;
|
|
10421
11769
|
}
|
|
10422
|
-
const indexPath =
|
|
11770
|
+
const indexPath = join8(dashboardDir, "index.html");
|
|
10423
11771
|
const res = serveStaticFile(indexPath);
|
|
10424
11772
|
if (res)
|
|
10425
11773
|
return res;
|
|
@@ -10433,6 +11781,9 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10433
11781
|
};
|
|
10434
11782
|
process.on("SIGINT", shutdown);
|
|
10435
11783
|
process.on("SIGTERM", shutdown);
|
|
11784
|
+
const { startScheduler: startScheduler2 } = await Promise.resolve().then(() => (init_scheduler(), exports_scheduler));
|
|
11785
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
11786
|
+
startScheduler2(getDatabase2());
|
|
10436
11787
|
const url = `http://localhost:${port}`;
|
|
10437
11788
|
console.log(`Connectors Dashboard running at ${url}`);
|
|
10438
11789
|
if (shouldOpen) {
|
|
@@ -10445,6 +11796,14 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10445
11796
|
}
|
|
10446
11797
|
var activityLog, MAX_ACTIVITY_LOG = 100, MIME_TYPES, SECURITY_HEADERS, MAX_BODY_SIZE;
|
|
10447
11798
|
var init_serve = __esm(() => {
|
|
11799
|
+
init_agents();
|
|
11800
|
+
init_rate();
|
|
11801
|
+
init_strip();
|
|
11802
|
+
init_llm();
|
|
11803
|
+
init_jobs();
|
|
11804
|
+
init_workflows();
|
|
11805
|
+
init_scheduler();
|
|
11806
|
+
init_workflow_runner();
|
|
10448
11807
|
init_registry();
|
|
10449
11808
|
init_installer();
|
|
10450
11809
|
init_auth();
|
|
@@ -10489,6 +11848,101 @@ var {
|
|
|
10489
11848
|
|
|
10490
11849
|
// src/cli/index.tsx
|
|
10491
11850
|
import chalk2 from "chalk";
|
|
11851
|
+
// package.json
|
|
11852
|
+
var package_default = {
|
|
11853
|
+
name: "@hasna/connectors",
|
|
11854
|
+
version: "1.3.3",
|
|
11855
|
+
description: "Open source connector library - Install API connectors with a single command",
|
|
11856
|
+
type: "module",
|
|
11857
|
+
bin: {
|
|
11858
|
+
connectors: "./bin/index.js",
|
|
11859
|
+
"connectors-mcp": "./bin/mcp.js",
|
|
11860
|
+
"connectors-serve": "./bin/serve.js"
|
|
11861
|
+
},
|
|
11862
|
+
files: [
|
|
11863
|
+
"bin/",
|
|
11864
|
+
"dist/",
|
|
11865
|
+
"dashboard/dist/",
|
|
11866
|
+
"connectors/",
|
|
11867
|
+
"README.md"
|
|
11868
|
+
],
|
|
11869
|
+
exports: {
|
|
11870
|
+
".": {
|
|
11871
|
+
import: "./dist/index.js",
|
|
11872
|
+
types: "./dist/index.d.ts"
|
|
11873
|
+
}
|
|
11874
|
+
},
|
|
11875
|
+
main: "./dist/index.js",
|
|
11876
|
+
types: "./dist/index.d.ts",
|
|
11877
|
+
scripts: {
|
|
11878
|
+
build: "cd dashboard && bun run build && cd .. && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk --external conf && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/serve.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --outDir ./dist",
|
|
11879
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
11880
|
+
postinstall: '[ "$SKIP_DASHBOARD" = "1" ] || [ ! -f dashboard/package.json ] || [ -d dashboard/node_modules ] || (cd dashboard && bun install)',
|
|
11881
|
+
dev: "bun run ./src/cli/index.tsx",
|
|
11882
|
+
typecheck: "tsc --noEmit",
|
|
11883
|
+
test: "bun test",
|
|
11884
|
+
"sdk:build": "cd sdk && bun run build",
|
|
11885
|
+
prepublishOnly: "bun test && bun run build"
|
|
11886
|
+
},
|
|
11887
|
+
keywords: [
|
|
11888
|
+
"connectors",
|
|
11889
|
+
"api",
|
|
11890
|
+
"cli",
|
|
11891
|
+
"typescript",
|
|
11892
|
+
"bun",
|
|
11893
|
+
"figma",
|
|
11894
|
+
"stripe",
|
|
11895
|
+
"github",
|
|
11896
|
+
"openai",
|
|
11897
|
+
"mcp",
|
|
11898
|
+
"model-context-protocol"
|
|
11899
|
+
],
|
|
11900
|
+
author: "Hasna",
|
|
11901
|
+
license: "Apache-2.0",
|
|
11902
|
+
devDependencies: {
|
|
11903
|
+
"@types/bun": "latest",
|
|
11904
|
+
"@types/react": "^18.2.0",
|
|
11905
|
+
"ink-testing-library": "^4.0.0",
|
|
11906
|
+
typescript: "^5"
|
|
11907
|
+
},
|
|
11908
|
+
dependencies: {
|
|
11909
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
11910
|
+
chalk: "^5.3.0",
|
|
11911
|
+
commander: "^12.1.0",
|
|
11912
|
+
conf: "^13.0.1",
|
|
11913
|
+
"fast-xml-parser": "^5.5.3",
|
|
11914
|
+
ink: "^5.0.1",
|
|
11915
|
+
"ink-select-input": "^6.0.0",
|
|
11916
|
+
"ink-spinner": "^5.0.0",
|
|
11917
|
+
"ink-text-input": "^6.0.0",
|
|
11918
|
+
open: "^11.0.0",
|
|
11919
|
+
react: "^18.2.0",
|
|
11920
|
+
zod: "3"
|
|
11921
|
+
},
|
|
11922
|
+
engines: {
|
|
11923
|
+
bun: ">=1.0.0"
|
|
11924
|
+
},
|
|
11925
|
+
publishConfig: {
|
|
11926
|
+
registry: "https://registry.npmjs.org",
|
|
11927
|
+
access: "public"
|
|
11928
|
+
},
|
|
11929
|
+
repository: {
|
|
11930
|
+
type: "git",
|
|
11931
|
+
url: "git+https://github.com/hasna/connectors.git"
|
|
11932
|
+
},
|
|
11933
|
+
homepage: "https://github.com/hasna/connectors#readme",
|
|
11934
|
+
bugs: {
|
|
11935
|
+
url: "https://github.com/hasna/connectors/issues"
|
|
11936
|
+
}
|
|
11937
|
+
};
|
|
11938
|
+
|
|
11939
|
+
// src/cli/index.tsx
|
|
11940
|
+
init_llm();
|
|
11941
|
+
init_jobs();
|
|
11942
|
+
init_workflows();
|
|
11943
|
+
init_scheduler();
|
|
11944
|
+
init_workflow_runner();
|
|
11945
|
+
init_database();
|
|
10492
11946
|
|
|
10493
11947
|
// src/cli/components/App.tsx
|
|
10494
11948
|
import { useState as useState7 } from "react";
|
|
@@ -11962,9 +13416,9 @@ function App({ initialConnectors, overwrite = false }) {
|
|
|
11962
13416
|
init_registry();
|
|
11963
13417
|
init_installer();
|
|
11964
13418
|
init_auth();
|
|
11965
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
11966
|
-
import { homedir as
|
|
11967
|
-
import { join as
|
|
13419
|
+
import { readdirSync as readdirSync4, existsSync as existsSync8, statSync as statSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
13420
|
+
import { homedir as homedir7 } from "os";
|
|
13421
|
+
import { join as join9, relative } from "path";
|
|
11968
13422
|
|
|
11969
13423
|
// src/lib/test-endpoints.ts
|
|
11970
13424
|
var TEST_ENDPOINTS = {
|
|
@@ -12165,17 +13619,17 @@ var TEST_ENDPOINTS = {
|
|
|
12165
13619
|
import { createInterface } from "readline";
|
|
12166
13620
|
|
|
12167
13621
|
// src/lib/runner.ts
|
|
12168
|
-
import { existsSync as
|
|
12169
|
-
import { join as
|
|
13622
|
+
import { existsSync as existsSync6 } from "fs";
|
|
13623
|
+
import { join as join7, dirname as dirname3 } from "path";
|
|
12170
13624
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12171
|
-
import { spawn } from "child_process";
|
|
13625
|
+
import { spawn as spawn3 } from "child_process";
|
|
12172
13626
|
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
12173
13627
|
function resolveConnectorsDir2() {
|
|
12174
|
-
const fromBin =
|
|
12175
|
-
if (
|
|
13628
|
+
const fromBin = join7(__dirname3, "..", "connectors");
|
|
13629
|
+
if (existsSync6(fromBin))
|
|
12176
13630
|
return fromBin;
|
|
12177
|
-
const fromSrc =
|
|
12178
|
-
if (
|
|
13631
|
+
const fromSrc = join7(__dirname3, "..", "..", "connectors");
|
|
13632
|
+
if (existsSync6(fromSrc))
|
|
12179
13633
|
return fromSrc;
|
|
12180
13634
|
return fromBin;
|
|
12181
13635
|
}
|
|
@@ -12215,13 +13669,13 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
12215
13669
|
}
|
|
12216
13670
|
function getConnectorCliPath(name) {
|
|
12217
13671
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
12218
|
-
const connectorDir =
|
|
12219
|
-
const cliPath =
|
|
12220
|
-
if (
|
|
13672
|
+
const connectorDir = join7(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
13673
|
+
const cliPath = join7(connectorDir, "src", "cli", "index.ts");
|
|
13674
|
+
if (existsSync6(cliPath))
|
|
12221
13675
|
return cliPath;
|
|
12222
13676
|
return null;
|
|
12223
13677
|
}
|
|
12224
|
-
function
|
|
13678
|
+
function runConnectorCommand2(name, args, timeoutMs = 30000) {
|
|
12225
13679
|
const cliPath = getConnectorCliPath(name);
|
|
12226
13680
|
if (!cliPath) {
|
|
12227
13681
|
return Promise.resolve({
|
|
@@ -12232,7 +13686,7 @@ function runConnectorCommand(name, args, timeoutMs = 30000) {
|
|
|
12232
13686
|
});
|
|
12233
13687
|
}
|
|
12234
13688
|
return new Promise((resolve) => {
|
|
12235
|
-
const proc =
|
|
13689
|
+
const proc = spawn3("bun", ["run", cliPath, ...args], {
|
|
12236
13690
|
timeout: timeoutMs,
|
|
12237
13691
|
env: buildEnvWithCredentials(name, process.env),
|
|
12238
13692
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12268,7 +13722,7 @@ async function getConnectorOperations(name) {
|
|
|
12268
13722
|
if (!cliPath) {
|
|
12269
13723
|
return { commands: [], helpText: "", hasCli: false };
|
|
12270
13724
|
}
|
|
12271
|
-
const result = await
|
|
13725
|
+
const result = await runConnectorCommand2(name, ["--help"]);
|
|
12272
13726
|
const helpText = result.stdout || result.stderr;
|
|
12273
13727
|
const commands = [];
|
|
12274
13728
|
const lines = helpText.split(`
|
|
@@ -12292,7 +13746,7 @@ async function getConnectorOperations(name) {
|
|
|
12292
13746
|
return { commands, helpText, hasCli: true };
|
|
12293
13747
|
}
|
|
12294
13748
|
async function getConnectorCommandHelp(name, command) {
|
|
12295
|
-
const result = await
|
|
13749
|
+
const result = await runConnectorCommand2(name, [command, "--help"]);
|
|
12296
13750
|
return result.stdout || result.stderr;
|
|
12297
13751
|
}
|
|
12298
13752
|
|
|
@@ -12309,7 +13763,7 @@ var PRESETS = {
|
|
|
12309
13763
|
commerce: { description: "Commerce and finance", connectors: ["stripe", "shopify", "revolut", "mercury", "pandadoc"] }
|
|
12310
13764
|
};
|
|
12311
13765
|
var program2 = new Command;
|
|
12312
|
-
program2.name("connectors").description("Install API connectors for your project").version(
|
|
13766
|
+
program2.name("connectors").description("Install API connectors for your project").version(package_default.version).enablePositionalOptions();
|
|
12313
13767
|
program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
|
|
12314
13768
|
if (!isTTY) {
|
|
12315
13769
|
console.log(`Non-interactive environment detected. Use a subcommand:
|
|
@@ -12330,8 +13784,8 @@ Run 'connectors --help' for full usage.`);
|
|
|
12330
13784
|
function listFilesRecursive(dir, base = dir) {
|
|
12331
13785
|
const files = [];
|
|
12332
13786
|
for (const entry of readdirSync4(dir)) {
|
|
12333
|
-
const fullPath =
|
|
12334
|
-
if (
|
|
13787
|
+
const fullPath = join9(dir, entry);
|
|
13788
|
+
if (statSync4(fullPath).isDirectory()) {
|
|
12335
13789
|
files.push(...listFilesRecursive(fullPath, base));
|
|
12336
13790
|
} else {
|
|
12337
13791
|
files.push(relative(base, fullPath));
|
|
@@ -12339,7 +13793,7 @@ function listFilesRecursive(dir, base = dir) {
|
|
|
12339
13793
|
}
|
|
12340
13794
|
return files;
|
|
12341
13795
|
}
|
|
12342
|
-
program2.command("install").alias("add").argument("[connectors...]", "Connectors to
|
|
13796
|
+
program2.command("install").alias("add").argument("[connectors...]", "Connectors to install").option("-o, --overwrite", "Overwrite existing connectors", false).option("-d, --dry-run", "Preview what would be installed without making changes", false).option("-c, --category <category>", "Install all connectors in a category").option("--preset <preset>", "Install a preset bundle (e.g. ai, fullstack, google)").option("--json", "Output results as JSON", false).description("Install one or more connectors").action((connectors, options) => {
|
|
12343
13797
|
if (options.category) {
|
|
12344
13798
|
const category = CATEGORIES.find((c) => c.toLowerCase() === options.category.toLowerCase());
|
|
12345
13799
|
if (!category) {
|
|
@@ -12352,7 +13806,8 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
12352
13806
|
process.exit(1);
|
|
12353
13807
|
return;
|
|
12354
13808
|
}
|
|
12355
|
-
|
|
13809
|
+
const categoryConnectors = getConnectorsByCategory(category).map((c) => c.name);
|
|
13810
|
+
connectors.push(...categoryConnectors);
|
|
12356
13811
|
}
|
|
12357
13812
|
if (options.preset) {
|
|
12358
13813
|
const preset = PRESETS[options.preset.toLowerCase()];
|
|
@@ -12370,25 +13825,133 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
12370
13825
|
}
|
|
12371
13826
|
if (connectors.length === 0) {
|
|
12372
13827
|
if (!isTTY) {
|
|
12373
|
-
console.error("Error: specify connectors to
|
|
13828
|
+
console.error("Error: specify connectors to install. Example: connectors install figma stripe");
|
|
12374
13829
|
process.exit(1);
|
|
12375
13830
|
}
|
|
12376
13831
|
render(/* @__PURE__ */ jsxDEV7(App, {}, undefined, false, undefined, this));
|
|
12377
13832
|
return;
|
|
12378
13833
|
}
|
|
12379
|
-
|
|
13834
|
+
if (options.dryRun) {
|
|
13835
|
+
const installed = getInstalledConnectors();
|
|
13836
|
+
const destDir = join9(process.cwd(), ".connectors");
|
|
13837
|
+
const actions = [];
|
|
13838
|
+
for (const name of connectors) {
|
|
13839
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
13840
|
+
actions.push({ connector: name, action: "error", reason: `Invalid connector name '${name}'` });
|
|
13841
|
+
continue;
|
|
13842
|
+
}
|
|
13843
|
+
const meta = getConnector(name);
|
|
13844
|
+
if (!meta) {
|
|
13845
|
+
actions.push({ connector: name, action: "error", reason: `Connector '${name}' not found in registry` });
|
|
13846
|
+
continue;
|
|
13847
|
+
}
|
|
13848
|
+
if (!connectorExists(name)) {
|
|
13849
|
+
actions.push({ connector: name, action: "error", reason: `Connector '${name}' source files not found` });
|
|
13850
|
+
continue;
|
|
13851
|
+
}
|
|
13852
|
+
const connectorDirName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
13853
|
+
const sourcePath = getConnectorPath(name);
|
|
13854
|
+
const destPath = join9(destDir, connectorDirName);
|
|
13855
|
+
const alreadyInstalled = installed.includes(name);
|
|
13856
|
+
const files = listFilesRecursive(sourcePath);
|
|
13857
|
+
const importLine = `export * as ${name} from './${connectorDirName}/src/index.js';`;
|
|
13858
|
+
if (alreadyInstalled && !options.overwrite) {
|
|
13859
|
+
actions.push({
|
|
13860
|
+
connector: name,
|
|
13861
|
+
action: "skip",
|
|
13862
|
+
reason: "Already installed. Use --overwrite to replace.",
|
|
13863
|
+
sourcePath,
|
|
13864
|
+
destPath
|
|
13865
|
+
});
|
|
13866
|
+
} else {
|
|
13867
|
+
actions.push({
|
|
13868
|
+
connector: name,
|
|
13869
|
+
action: alreadyInstalled ? "overwrite" : "install",
|
|
13870
|
+
sourcePath,
|
|
13871
|
+
destPath,
|
|
13872
|
+
files,
|
|
13873
|
+
importLine
|
|
13874
|
+
});
|
|
13875
|
+
}
|
|
13876
|
+
}
|
|
13877
|
+
if (options.json) {
|
|
13878
|
+
console.log(JSON.stringify({ dryRun: true, actions }, null, 2));
|
|
13879
|
+
process.exit(actions.every((a) => a.action !== "error") ? 0 : 1);
|
|
13880
|
+
return;
|
|
13881
|
+
}
|
|
13882
|
+
console.log(chalk2.bold(`
|
|
13883
|
+
Dry run \u2014 no changes will be made
|
|
13884
|
+
`));
|
|
13885
|
+
for (const a of actions) {
|
|
13886
|
+
if (a.action === "error") {
|
|
13887
|
+
console.log(chalk2.red(` \u2717 ${a.connector}: ${a.reason}`));
|
|
13888
|
+
continue;
|
|
13889
|
+
}
|
|
13890
|
+
if (a.action === "skip") {
|
|
13891
|
+
console.log(chalk2.yellow(` \u2298 ${a.connector}: ${a.reason}`));
|
|
13892
|
+
continue;
|
|
13893
|
+
}
|
|
13894
|
+
const actionLabel = a.action === "overwrite" ? chalk2.yellow("overwrite") : chalk2.green("install");
|
|
13895
|
+
console.log(` ${actionLabel} ${chalk2.cyan(a.connector)}`);
|
|
13896
|
+
console.log(chalk2.dim(` source: ${a.sourcePath}`));
|
|
13897
|
+
console.log(chalk2.dim(` dest: ${a.destPath}`));
|
|
13898
|
+
if (a.files && a.files.length > 0) {
|
|
13899
|
+
console.log(chalk2.dim(` files (${a.files.length}):`));
|
|
13900
|
+
for (const f of a.files) {
|
|
13901
|
+
console.log(chalk2.dim(` ${f}`));
|
|
13902
|
+
}
|
|
13903
|
+
}
|
|
13904
|
+
if (a.importLine) {
|
|
13905
|
+
console.log(` ${chalk2.dim("index.ts:")} ${a.importLine}`);
|
|
13906
|
+
}
|
|
13907
|
+
console.log();
|
|
13908
|
+
}
|
|
13909
|
+
const installCount = actions.filter((a) => a.action === "install").length;
|
|
13910
|
+
const overwriteCount = actions.filter((a) => a.action === "overwrite").length;
|
|
13911
|
+
const skipCount = actions.filter((a) => a.action === "skip").length;
|
|
13912
|
+
const errorCount = actions.filter((a) => a.action === "error").length;
|
|
13913
|
+
const parts = [];
|
|
13914
|
+
if (installCount)
|
|
13915
|
+
parts.push(chalk2.green(`${installCount} to install`));
|
|
13916
|
+
if (overwriteCount)
|
|
13917
|
+
parts.push(chalk2.yellow(`${overwriteCount} to overwrite`));
|
|
13918
|
+
if (skipCount)
|
|
13919
|
+
parts.push(chalk2.yellow(`${skipCount} skipped`));
|
|
13920
|
+
if (errorCount)
|
|
13921
|
+
parts.push(chalk2.red(`${errorCount} failed`));
|
|
13922
|
+
console.log(` ${chalk2.bold("Summary:")} ${parts.join(", ")}`);
|
|
13923
|
+
console.log(chalk2.dim(`
|
|
13924
|
+
Run without --dry-run to apply.
|
|
13925
|
+
`));
|
|
13926
|
+
process.exit(errorCount > 0 ? 1 : 0);
|
|
13927
|
+
return;
|
|
13928
|
+
}
|
|
13929
|
+
const results = connectors.map((name) => installConnector(name, { overwrite: options.overwrite }));
|
|
12380
13930
|
if (options.json) {
|
|
12381
13931
|
console.log(JSON.stringify(results, null, 2));
|
|
12382
13932
|
process.exit(results.every((r) => r.success) ? 0 : 1);
|
|
12383
13933
|
return;
|
|
12384
13934
|
}
|
|
13935
|
+
console.log(chalk2.bold(`
|
|
13936
|
+
Installing connectors...
|
|
13937
|
+
`));
|
|
13938
|
+
const succeeded = [];
|
|
12385
13939
|
for (const result of results) {
|
|
12386
13940
|
if (result.success) {
|
|
12387
|
-
console.log(chalk2.green(`\u2713 ${result.connector}`)
|
|
13941
|
+
console.log(chalk2.green(`\u2713 ${result.connector}`));
|
|
13942
|
+
succeeded.push(result.connector);
|
|
12388
13943
|
} else {
|
|
12389
13944
|
console.log(chalk2.red(`\u2717 ${result.connector}: ${result.error}`));
|
|
12390
13945
|
}
|
|
12391
13946
|
}
|
|
13947
|
+
if (succeeded.length > 0) {
|
|
13948
|
+
console.log(chalk2.bold(`
|
|
13949
|
+
Next steps:`));
|
|
13950
|
+
const importNames = succeeded.join(", ");
|
|
13951
|
+
console.log(chalk2.dim(` 1. Import: `) + `import { ${importNames} } from './.connectors'`);
|
|
13952
|
+
console.log(chalk2.dim(` 2. Set key: `) + `connectors docs ${succeeded[0]}` + chalk2.dim(` (see env vars)`));
|
|
13953
|
+
console.log(chalk2.dim(` 3. Explore: `) + `connectors serve` + chalk2.dim(` (dashboard for auth management)`));
|
|
13954
|
+
}
|
|
12392
13955
|
process.exit(results.every((r) => r.success) ? 0 : 1);
|
|
12393
13956
|
});
|
|
12394
13957
|
program2.command("list").alias("ls").option("-c, --category <category>", "Filter by category").option("-a, --all", "Show all available connectors", false).option("-i, --installed", "Show only installed connectors", false).option("-b, --brief", "Output only connector names", false).option("--json", "Output as JSON", false).description("List available or installed connectors").action((options) => {
|
|
@@ -12542,10 +14105,18 @@ Available connectors (${CONNECTORS.length}):
|
|
|
12542
14105
|
console.log();
|
|
12543
14106
|
}
|
|
12544
14107
|
});
|
|
12545
|
-
program2.command("search").argument("<query>", "Search term").option("--json", "Output as JSON", false).description("Search for connectors").action((query, options) => {
|
|
12546
|
-
const
|
|
14108
|
+
program2.command("search").argument("<query>", "Search term").option("--json", "Output as JSON", false).option("--limit <n>", "Max results", "20").description("Search for connectors (ranked with fuzzy matching)").action((query, options) => {
|
|
14109
|
+
const installed = getInstalledConnectors();
|
|
14110
|
+
const { getPromotedConnectors: getPromotedConnectors2 } = (init_promotions(), __toCommonJS(exports_promotions));
|
|
14111
|
+
const { getUsageMap: getUsageMap2 } = (init_usage(), __toCommonJS(exports_usage));
|
|
14112
|
+
const results = searchConnectors(query, {
|
|
14113
|
+
installed,
|
|
14114
|
+
promoted: getPromotedConnectors2(),
|
|
14115
|
+
usage: getUsageMap2(),
|
|
14116
|
+
limit: parseInt(options.limit)
|
|
14117
|
+
});
|
|
12547
14118
|
if (options.json) {
|
|
12548
|
-
console.log(JSON.stringify(results));
|
|
14119
|
+
console.log(JSON.stringify(results.map((c) => ({ name: c.name, displayName: c.displayName, version: c.version, category: c.category, description: c.description, score: c.score, badges: c.badges, matchReasons: c.matchReasons }))));
|
|
12549
14120
|
return;
|
|
12550
14121
|
}
|
|
12551
14122
|
if (results.length === 0) {
|
|
@@ -12555,10 +14126,12 @@ program2.command("search").argument("<query>", "Search term").option("--json", "
|
|
|
12555
14126
|
console.log(chalk2.bold(`
|
|
12556
14127
|
Found ${results.length} connector(s):
|
|
12557
14128
|
`));
|
|
12558
|
-
console.log(` ${chalk2.dim("Name".padEnd(
|
|
12559
|
-
console.log(chalk2.dim(` ${"\u2500".repeat(
|
|
14129
|
+
console.log(` ${chalk2.dim("Name".padEnd(22))}${chalk2.dim("Score".padEnd(7))}${chalk2.dim("Category".padEnd(20))}${chalk2.dim("Description")}`);
|
|
14130
|
+
console.log(chalk2.dim(` ${"\u2500".repeat(75)}`));
|
|
12560
14131
|
for (const c of results) {
|
|
12561
|
-
|
|
14132
|
+
const badges = c.badges.map((b) => b === "installed" ? chalk2.green("[INS]") : b === "hot" ? chalk2.red("[HOT]") : b === "promoted" ? chalk2.yellow("[PRO]") : "").join(" ");
|
|
14133
|
+
const badgeStr = badges ? " " + badges : "";
|
|
14134
|
+
console.log(` ${chalk2.cyan(c.name.padEnd(22))}${String(c.score).padEnd(7)}${chalk2.dim(c.category.padEnd(20))}${c.description}${badgeStr}`);
|
|
12562
14135
|
}
|
|
12563
14136
|
});
|
|
12564
14137
|
program2.command("info").argument("<connector>", "Connector name").option("--json", "Output as JSON", false).description("Show detailed info about a connector").action((connector, options) => {
|
|
@@ -12792,17 +14365,17 @@ Updating ${toUpdate.length} connector(s)...
|
|
|
12792
14365
|
});
|
|
12793
14366
|
program2.command("status").option("--json", "Output as JSON", false).description("Show auth status of all configured connectors (project + global)").action((options) => {
|
|
12794
14367
|
const installed = getInstalledConnectors();
|
|
12795
|
-
const configDir =
|
|
14368
|
+
const configDir = join9(homedir7(), ".connectors");
|
|
12796
14369
|
const seen = new Set;
|
|
12797
14370
|
const allStatuses = [];
|
|
12798
14371
|
function buildStatusEntry(name, source) {
|
|
12799
14372
|
const auth = getAuthStatus(name);
|
|
12800
14373
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
12801
|
-
const currentProfileFile =
|
|
14374
|
+
const currentProfileFile = join9(configDir, connectorName, "current_profile");
|
|
12802
14375
|
let profile = "default";
|
|
12803
|
-
if (
|
|
14376
|
+
if (existsSync8(currentProfileFile)) {
|
|
12804
14377
|
try {
|
|
12805
|
-
profile =
|
|
14378
|
+
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
12806
14379
|
} catch {}
|
|
12807
14380
|
}
|
|
12808
14381
|
let expiryLabel = null;
|
|
@@ -12838,13 +14411,13 @@ program2.command("status").option("--json", "Output as JSON", false).description
|
|
|
12838
14411
|
seen.add(name);
|
|
12839
14412
|
allStatuses.push(buildStatusEntry(name, "project"));
|
|
12840
14413
|
}
|
|
12841
|
-
if (
|
|
14414
|
+
if (existsSync8(configDir)) {
|
|
12842
14415
|
try {
|
|
12843
14416
|
const globalDirs = readdirSync4(configDir).filter((f) => {
|
|
12844
14417
|
if (!f.startsWith("connect-"))
|
|
12845
14418
|
return false;
|
|
12846
14419
|
try {
|
|
12847
|
-
return
|
|
14420
|
+
return statSync4(join9(configDir, f)).isDirectory();
|
|
12848
14421
|
} catch {
|
|
12849
14422
|
return false;
|
|
12850
14423
|
}
|
|
@@ -13118,7 +14691,7 @@ Open this URL to authenticate:
|
|
|
13118
14691
|
return;
|
|
13119
14692
|
}
|
|
13120
14693
|
if (options.key) {
|
|
13121
|
-
saveApiKey(connector, options.key, options.field || undefined);
|
|
14694
|
+
await saveApiKey(connector, options.key, options.field || undefined);
|
|
13122
14695
|
const statusAfter2 = getAuthStatus(connector);
|
|
13123
14696
|
if (options.json) {
|
|
13124
14697
|
console.log(JSON.stringify({
|
|
@@ -13192,7 +14765,7 @@ Open this URL to authenticate:
|
|
|
13192
14765
|
process.exit(1);
|
|
13193
14766
|
return;
|
|
13194
14767
|
}
|
|
13195
|
-
saveApiKey(connector, key.trim(), options.field || undefined);
|
|
14768
|
+
await saveApiKey(connector, key.trim(), options.field || undefined);
|
|
13196
14769
|
const statusAfter = getAuthStatus(connector);
|
|
13197
14770
|
console.log(chalk2.green(`
|
|
13198
14771
|
\u2713 API key saved for ${meta.displayName}`));
|
|
@@ -13209,15 +14782,15 @@ program2.command("init").option("--json", "Output presets and suggestions as JSO
|
|
|
13209
14782
|
{ key: "commerce", emoji: "\uD83D\uDCB3", label: "Commerce", connectors: ["stripe", "shopify", "paypal", "revolut", "mercury"], description: "Commerce and finance" },
|
|
13210
14783
|
{ key: "google", emoji: "\uD83D\uDCC1", label: "Google Workspace", connectors: ["gmail", "googledrive", "googlecalendar", "googledocs", "googlesheets"], description: "Google Workspace suite" }
|
|
13211
14784
|
];
|
|
13212
|
-
const connectorsHome =
|
|
14785
|
+
const connectorsHome = join9(homedir7(), ".connectors");
|
|
13213
14786
|
let configuredCount = 0;
|
|
13214
14787
|
const configuredNames = [];
|
|
13215
14788
|
try {
|
|
13216
|
-
if (
|
|
13217
|
-
const entries = readdirSync4(connectorsHome).filter((e) => e.startsWith("connect-") &&
|
|
14789
|
+
if (existsSync8(connectorsHome)) {
|
|
14790
|
+
const entries = readdirSync4(connectorsHome).filter((e) => e.startsWith("connect-") && statSync4(join9(connectorsHome, e)).isDirectory());
|
|
13218
14791
|
for (const entry of entries) {
|
|
13219
|
-
const profilesDir =
|
|
13220
|
-
if (
|
|
14792
|
+
const profilesDir = join9(connectorsHome, entry, "profiles");
|
|
14793
|
+
if (existsSync8(profilesDir)) {
|
|
13221
14794
|
configuredCount++;
|
|
13222
14795
|
configuredNames.push(entry.replace(/^connect-/, ""));
|
|
13223
14796
|
}
|
|
@@ -13315,44 +14888,44 @@ function redactSecrets(obj) {
|
|
|
13315
14888
|
return obj;
|
|
13316
14889
|
}
|
|
13317
14890
|
program2.command("export").option("-o, --output <file>", "Write to file instead of stdout").option("--include-secrets", "Include secrets in plaintext (dangerous \u2014 use only for backup/restore)").description("Export all connector credentials as JSON backup").action((options) => {
|
|
13318
|
-
const connectDir =
|
|
14891
|
+
const connectDir = join9(homedir7(), ".connectors");
|
|
13319
14892
|
const result = {};
|
|
13320
|
-
if (
|
|
14893
|
+
if (existsSync8(connectDir)) {
|
|
13321
14894
|
for (const entry of readdirSync4(connectDir)) {
|
|
13322
|
-
const entryPath =
|
|
13323
|
-
if (!
|
|
14895
|
+
const entryPath = join9(connectDir, entry);
|
|
14896
|
+
if (!statSync4(entryPath).isDirectory() || !entry.startsWith("connect-"))
|
|
13324
14897
|
continue;
|
|
13325
14898
|
const connectorName = entry.replace(/^connect-/, "");
|
|
13326
14899
|
let credentials = undefined;
|
|
13327
|
-
const credentialsPath =
|
|
13328
|
-
if (
|
|
14900
|
+
const credentialsPath = join9(entryPath, "credentials.json");
|
|
14901
|
+
if (existsSync8(credentialsPath)) {
|
|
13329
14902
|
try {
|
|
13330
|
-
credentials = JSON.parse(
|
|
14903
|
+
credentials = JSON.parse(readFileSync6(credentialsPath, "utf-8"));
|
|
13331
14904
|
} catch {}
|
|
13332
14905
|
}
|
|
13333
|
-
const profilesDir =
|
|
13334
|
-
if (!
|
|
14906
|
+
const profilesDir = join9(entryPath, "profiles");
|
|
14907
|
+
if (!existsSync8(profilesDir) && !credentials)
|
|
13335
14908
|
continue;
|
|
13336
14909
|
const profiles = {};
|
|
13337
|
-
if (
|
|
14910
|
+
if (existsSync8(profilesDir)) {
|
|
13338
14911
|
for (const pEntry of readdirSync4(profilesDir)) {
|
|
13339
|
-
const pPath =
|
|
13340
|
-
if (
|
|
14912
|
+
const pPath = join9(profilesDir, pEntry);
|
|
14913
|
+
if (statSync4(pPath).isFile() && pEntry.endsWith(".json")) {
|
|
13341
14914
|
try {
|
|
13342
|
-
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(
|
|
14915
|
+
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync6(pPath, "utf-8"));
|
|
13343
14916
|
} catch {}
|
|
13344
|
-
} else if (
|
|
13345
|
-
const configPath =
|
|
13346
|
-
const tokensPath =
|
|
14917
|
+
} else if (statSync4(pPath).isDirectory()) {
|
|
14918
|
+
const configPath = join9(pPath, "config.json");
|
|
14919
|
+
const tokensPath = join9(pPath, "tokens.json");
|
|
13347
14920
|
let merged = {};
|
|
13348
|
-
if (
|
|
14921
|
+
if (existsSync8(configPath)) {
|
|
13349
14922
|
try {
|
|
13350
|
-
merged = { ...merged, ...JSON.parse(
|
|
14923
|
+
merged = { ...merged, ...JSON.parse(readFileSync6(configPath, "utf-8")) };
|
|
13351
14924
|
} catch {}
|
|
13352
14925
|
}
|
|
13353
|
-
if (
|
|
14926
|
+
if (existsSync8(tokensPath)) {
|
|
13354
14927
|
try {
|
|
13355
|
-
merged = { ...merged, ...JSON.parse(
|
|
14928
|
+
merged = { ...merged, ...JSON.parse(readFileSync6(tokensPath, "utf-8")) };
|
|
13356
14929
|
} catch {}
|
|
13357
14930
|
}
|
|
13358
14931
|
if (Object.keys(merged).length > 0)
|
|
@@ -13373,7 +14946,7 @@ program2.command("export").option("-o, --output <file>", "Write to file instead
|
|
|
13373
14946
|
}
|
|
13374
14947
|
const exportData = JSON.stringify(exportPayload, null, 2);
|
|
13375
14948
|
if (options.output) {
|
|
13376
|
-
|
|
14949
|
+
writeFileSync5(options.output, exportData);
|
|
13377
14950
|
console.log(chalk2.green(`\u2713 Exported to ${options.output}`));
|
|
13378
14951
|
} else {
|
|
13379
14952
|
console.log(exportData);
|
|
@@ -13387,7 +14960,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13387
14960
|
chunks.push(chunk.toString());
|
|
13388
14961
|
raw = chunks.join("");
|
|
13389
14962
|
} else {
|
|
13390
|
-
if (!
|
|
14963
|
+
if (!existsSync8(file)) {
|
|
13391
14964
|
if (options.json) {
|
|
13392
14965
|
console.log(JSON.stringify({ error: `File not found: ${file}` }));
|
|
13393
14966
|
} else {
|
|
@@ -13396,7 +14969,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13396
14969
|
process.exit(1);
|
|
13397
14970
|
return;
|
|
13398
14971
|
}
|
|
13399
|
-
raw =
|
|
14972
|
+
raw = readFileSync6(file, "utf-8");
|
|
13400
14973
|
}
|
|
13401
14974
|
let data;
|
|
13402
14975
|
try {
|
|
@@ -13419,25 +14992,25 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13419
14992
|
process.exit(1);
|
|
13420
14993
|
return;
|
|
13421
14994
|
}
|
|
13422
|
-
const connectDir =
|
|
14995
|
+
const connectDir = join9(homedir7(), ".connectors");
|
|
13423
14996
|
let imported = 0;
|
|
13424
14997
|
for (const [connectorName, connData] of Object.entries(data.connectors)) {
|
|
13425
14998
|
if (!/^[a-z0-9-]+$/.test(connectorName))
|
|
13426
14999
|
continue;
|
|
13427
|
-
const connectorDir =
|
|
15000
|
+
const connectorDir = join9(connectDir, `connect-${connectorName}`);
|
|
13428
15001
|
if (connData.credentials && typeof connData.credentials === "object") {
|
|
13429
|
-
|
|
13430
|
-
|
|
15002
|
+
mkdirSync7(connectorDir, { recursive: true });
|
|
15003
|
+
writeFileSync5(join9(connectorDir, "credentials.json"), JSON.stringify(connData.credentials, null, 2));
|
|
13431
15004
|
imported++;
|
|
13432
15005
|
}
|
|
13433
15006
|
if (!connData.profiles || typeof connData.profiles !== "object")
|
|
13434
15007
|
continue;
|
|
13435
|
-
const profilesDir =
|
|
15008
|
+
const profilesDir = join9(connectorDir, "profiles");
|
|
13436
15009
|
for (const [profileName, config] of Object.entries(connData.profiles)) {
|
|
13437
15010
|
if (!config || typeof config !== "object")
|
|
13438
15011
|
continue;
|
|
13439
|
-
|
|
13440
|
-
|
|
15012
|
+
mkdirSync7(profilesDir, { recursive: true });
|
|
15013
|
+
writeFileSync5(join9(profilesDir, `${profileName}.json`), JSON.stringify(config, null, 2));
|
|
13441
15014
|
imported++;
|
|
13442
15015
|
}
|
|
13443
15016
|
}
|
|
@@ -13448,9 +15021,9 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13448
15021
|
}
|
|
13449
15022
|
});
|
|
13450
15023
|
program2.command("auth-import").option("--json", "Output as JSON", false).option("-d, --dry-run", "Preview what would be imported without copying", false).option("--force", "Overwrite existing files in ~/.connectors/", false).description("Migrate auth tokens from ~/.connect/ to ~/.connectors/").action((options) => {
|
|
13451
|
-
const oldBase =
|
|
13452
|
-
const newBase =
|
|
13453
|
-
if (!
|
|
15024
|
+
const oldBase = join9(homedir7(), ".connect");
|
|
15025
|
+
const newBase = join9(homedir7(), ".connectors");
|
|
15026
|
+
if (!existsSync8(oldBase)) {
|
|
13454
15027
|
if (options.json) {
|
|
13455
15028
|
console.log(JSON.stringify({ imported: [], skipped: [], error: null, message: "No ~/.connect/ directory found" }));
|
|
13456
15029
|
} else {
|
|
@@ -13462,7 +15035,7 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13462
15035
|
if (!name.startsWith("connect-"))
|
|
13463
15036
|
return false;
|
|
13464
15037
|
try {
|
|
13465
|
-
return
|
|
15038
|
+
return statSync4(join9(oldBase, name)).isDirectory();
|
|
13466
15039
|
} catch {
|
|
13467
15040
|
return false;
|
|
13468
15041
|
}
|
|
@@ -13478,8 +15051,8 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13478
15051
|
const imported = [];
|
|
13479
15052
|
const skipped = [];
|
|
13480
15053
|
for (const dirName of entries) {
|
|
13481
|
-
const oldDir =
|
|
13482
|
-
const newDir =
|
|
15054
|
+
const oldDir = join9(oldBase, dirName);
|
|
15055
|
+
const newDir = join9(newBase, dirName);
|
|
13483
15056
|
const connectorName = dirName.replace(/^connect-/, "");
|
|
13484
15057
|
const allFiles = listFilesRecursive(oldDir);
|
|
13485
15058
|
const authFiles = allFiles.filter((f) => {
|
|
@@ -13490,17 +15063,17 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13490
15063
|
const copiedFiles = [];
|
|
13491
15064
|
const skippedFiles = [];
|
|
13492
15065
|
for (const relFile of authFiles) {
|
|
13493
|
-
const srcPath =
|
|
13494
|
-
const destPath =
|
|
13495
|
-
if (
|
|
15066
|
+
const srcPath = join9(oldDir, relFile);
|
|
15067
|
+
const destPath = join9(newDir, relFile);
|
|
15068
|
+
if (existsSync8(destPath) && !options.force) {
|
|
13496
15069
|
skippedFiles.push(relFile);
|
|
13497
15070
|
continue;
|
|
13498
15071
|
}
|
|
13499
15072
|
if (!options.dryRun) {
|
|
13500
|
-
const parentDir =
|
|
13501
|
-
|
|
13502
|
-
const content =
|
|
13503
|
-
|
|
15073
|
+
const parentDir = join9(destPath, "..");
|
|
15074
|
+
mkdirSync7(parentDir, { recursive: true });
|
|
15075
|
+
const content = readFileSync6(srcPath);
|
|
15076
|
+
writeFileSync5(destPath, content);
|
|
13504
15077
|
}
|
|
13505
15078
|
copiedFiles.push(relFile);
|
|
13506
15079
|
}
|
|
@@ -13745,7 +15318,7 @@ program2.command("env").option("-o, --output <file>", "Write to file instead of
|
|
|
13745
15318
|
`) + `
|
|
13746
15319
|
`;
|
|
13747
15320
|
if (options.output) {
|
|
13748
|
-
|
|
15321
|
+
writeFileSync5(options.output, output);
|
|
13749
15322
|
console.log(chalk2.green(`\u2713 Written to ${options.output} (${vars.length} variables)`));
|
|
13750
15323
|
} else {
|
|
13751
15324
|
console.log(output);
|
|
@@ -13773,7 +15346,7 @@ Available presets:
|
|
|
13773
15346
|
`));
|
|
13774
15347
|
});
|
|
13775
15348
|
program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
|
|
13776
|
-
const configDir =
|
|
15349
|
+
const configDir = join9(homedir7(), ".connectors");
|
|
13777
15350
|
const installed = getInstalledConnectors();
|
|
13778
15351
|
const version = "0.3.1";
|
|
13779
15352
|
let configured = 0;
|
|
@@ -13787,23 +15360,23 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
13787
15360
|
configured++;
|
|
13788
15361
|
else
|
|
13789
15362
|
unconfigured++;
|
|
13790
|
-
const connectorConfigDir =
|
|
13791
|
-
const currentProfileFile =
|
|
15363
|
+
const connectorConfigDir = join9(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
|
|
15364
|
+
const currentProfileFile = join9(connectorConfigDir, "current_profile");
|
|
13792
15365
|
let profile = "default";
|
|
13793
|
-
if (
|
|
15366
|
+
if (existsSync8(currentProfileFile)) {
|
|
13794
15367
|
try {
|
|
13795
|
-
profile =
|
|
15368
|
+
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
13796
15369
|
} catch {}
|
|
13797
15370
|
}
|
|
13798
15371
|
connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile, source: "project" });
|
|
13799
15372
|
}
|
|
13800
|
-
if (
|
|
15373
|
+
if (existsSync8(configDir)) {
|
|
13801
15374
|
try {
|
|
13802
15375
|
const globalDirs = readdirSync4(configDir).filter((f) => {
|
|
13803
15376
|
if (!f.startsWith("connect-"))
|
|
13804
15377
|
return false;
|
|
13805
15378
|
try {
|
|
13806
|
-
return
|
|
15379
|
+
return statSync4(join9(configDir, f)).isDirectory();
|
|
13807
15380
|
} catch {
|
|
13808
15381
|
return false;
|
|
13809
15382
|
}
|
|
@@ -13817,11 +15390,11 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
13817
15390
|
continue;
|
|
13818
15391
|
seen.add(name);
|
|
13819
15392
|
configured++;
|
|
13820
|
-
const currentProfileFile =
|
|
15393
|
+
const currentProfileFile = join9(configDir, dir, "current_profile");
|
|
13821
15394
|
let profile = "default";
|
|
13822
|
-
if (
|
|
15395
|
+
if (existsSync8(currentProfileFile)) {
|
|
13823
15396
|
try {
|
|
13824
|
-
profile =
|
|
15397
|
+
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
13825
15398
|
} catch {}
|
|
13826
15399
|
}
|
|
13827
15400
|
connectorDetails.push({ name, configured: true, authType: auth.type, profile, source: "global" });
|
|
@@ -13832,7 +15405,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
13832
15405
|
console.log(JSON.stringify({
|
|
13833
15406
|
version,
|
|
13834
15407
|
configDir,
|
|
13835
|
-
configDirExists:
|
|
15408
|
+
configDirExists: existsSync8(configDir),
|
|
13836
15409
|
installed: installed.length,
|
|
13837
15410
|
configured,
|
|
13838
15411
|
unconfigured,
|
|
@@ -13844,7 +15417,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
13844
15417
|
Connectors Setup
|
|
13845
15418
|
`));
|
|
13846
15419
|
console.log(` Version: ${chalk2.cyan(version)}`);
|
|
13847
|
-
console.log(` Config: ${configDir}${
|
|
15420
|
+
console.log(` Config: ${configDir}${existsSync8(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
|
|
13848
15421
|
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
13849
15422
|
console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
|
|
13850
15423
|
const projectConnectors = connectorDetails.filter((c) => c.source === "project");
|
|
@@ -13934,18 +15507,18 @@ Testing connector credentials...
|
|
|
13934
15507
|
}
|
|
13935
15508
|
}
|
|
13936
15509
|
if (!apiKey) {
|
|
13937
|
-
const connectorConfigDir =
|
|
15510
|
+
const connectorConfigDir = join9(homedir7(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
13938
15511
|
let currentProfile = "default";
|
|
13939
|
-
const currentProfileFile =
|
|
13940
|
-
if (
|
|
15512
|
+
const currentProfileFile = join9(connectorConfigDir, "current_profile");
|
|
15513
|
+
if (existsSync8(currentProfileFile)) {
|
|
13941
15514
|
try {
|
|
13942
|
-
currentProfile =
|
|
15515
|
+
currentProfile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
13943
15516
|
} catch {}
|
|
13944
15517
|
}
|
|
13945
|
-
const tokensFile =
|
|
13946
|
-
if (
|
|
15518
|
+
const tokensFile = join9(connectorConfigDir, "profiles", currentProfile, "tokens.json");
|
|
15519
|
+
if (existsSync8(tokensFile)) {
|
|
13947
15520
|
try {
|
|
13948
|
-
const tokens = JSON.parse(
|
|
15521
|
+
const tokens = JSON.parse(readFileSync6(tokensFile, "utf-8"));
|
|
13949
15522
|
const isExpired = tokens.expiresAt && Date.now() >= tokens.expiresAt - 60000;
|
|
13950
15523
|
if (isExpired && tokens.refreshToken) {
|
|
13951
15524
|
try {
|
|
@@ -13963,19 +15536,19 @@ Testing connector credentials...
|
|
|
13963
15536
|
} catch {}
|
|
13964
15537
|
}
|
|
13965
15538
|
if (!apiKey) {
|
|
13966
|
-
const profileFile =
|
|
13967
|
-
if (
|
|
15539
|
+
const profileFile = join9(connectorConfigDir, "profiles", `${currentProfile}.json`);
|
|
15540
|
+
if (existsSync8(profileFile)) {
|
|
13968
15541
|
try {
|
|
13969
|
-
const config = JSON.parse(
|
|
15542
|
+
const config = JSON.parse(readFileSync6(profileFile, "utf-8"));
|
|
13970
15543
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
13971
15544
|
} catch {}
|
|
13972
15545
|
}
|
|
13973
15546
|
}
|
|
13974
15547
|
if (!apiKey) {
|
|
13975
|
-
const profileDirConfig =
|
|
13976
|
-
if (
|
|
15548
|
+
const profileDirConfig = join9(connectorConfigDir, "profiles", currentProfile, "config.json");
|
|
15549
|
+
if (existsSync8(profileDirConfig)) {
|
|
13977
15550
|
try {
|
|
13978
|
-
const config = JSON.parse(
|
|
15551
|
+
const config = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
|
|
13979
15552
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
13980
15553
|
} catch {}
|
|
13981
15554
|
}
|
|
@@ -14112,7 +15685,7 @@ program2.command("run").description("Execute an API operation on a connector").a
|
|
|
14112
15685
|
console.error(chalk2.yellow(`No command specified. Run ${chalk2.white(`connectors ops ${name}`)} to see available operations.`));
|
|
14113
15686
|
process.exit(1);
|
|
14114
15687
|
}
|
|
14115
|
-
const result = await
|
|
15688
|
+
const result = await runConnectorCommand2(name, args, parseInt(options.timeout));
|
|
14116
15689
|
if (result.stdout) {
|
|
14117
15690
|
console.log(result.stdout);
|
|
14118
15691
|
}
|
|
@@ -14142,7 +15715,7 @@ Setting up ${meta.displayName}...
|
|
|
14142
15715
|
const alreadyInstalled = installed.includes(meta.name);
|
|
14143
15716
|
let installResult;
|
|
14144
15717
|
if (alreadyInstalled && !options.overwrite) {
|
|
14145
|
-
installResult = { success: true, path:
|
|
15718
|
+
installResult = { success: true, path: join9(process.cwd(), ".connectors", `connect-${meta.name}`) };
|
|
14146
15719
|
if (!options.json) {
|
|
14147
15720
|
console.log(` ${chalk2.green("\u2713")} Already installed`);
|
|
14148
15721
|
}
|
|
@@ -14167,7 +15740,7 @@ Setting up ${meta.displayName}...
|
|
|
14167
15740
|
let authConfigured = false;
|
|
14168
15741
|
if (authType === "oauth") {
|
|
14169
15742
|
if (options.key) {
|
|
14170
|
-
saveApiKey(name, options.key, options.field || undefined);
|
|
15743
|
+
await saveApiKey(name, options.key, options.field || undefined);
|
|
14171
15744
|
authConfigured = true;
|
|
14172
15745
|
if (!options.json) {
|
|
14173
15746
|
console.log(` ${chalk2.green("\u2713")} Token saved`);
|
|
@@ -14225,7 +15798,7 @@ Setting up ${meta.displayName}...
|
|
|
14225
15798
|
}
|
|
14226
15799
|
} else {
|
|
14227
15800
|
if (options.key) {
|
|
14228
|
-
saveApiKey(name, options.key, options.field || undefined);
|
|
15801
|
+
await saveApiKey(name, options.key, options.field || undefined);
|
|
14229
15802
|
authConfigured = true;
|
|
14230
15803
|
if (!options.json) {
|
|
14231
15804
|
console.log(` ${chalk2.green("\u2713")} ${authType === "bearer" ? "Bearer token" : "API key"} saved`);
|
|
@@ -14268,4 +15841,299 @@ Setting up ${meta.displayName}...
|
|
|
14268
15841
|
}
|
|
14269
15842
|
process.exit(0);
|
|
14270
15843
|
});
|
|
15844
|
+
program2.command("hot").description("Show top connectors by usage").option("--limit <n>", "Max results", "10").option("--days <n>", "Time window in days", "7").option("--json", "Output as JSON").action((options) => {
|
|
15845
|
+
const { getTopConnectors: getTopConnectors2 } = (init_usage(), __toCommonJS(exports_usage));
|
|
15846
|
+
const { getPromotedConnectors: getPromotedConnectors2 } = (init_promotions(), __toCommonJS(exports_promotions));
|
|
15847
|
+
const top = getTopConnectors2(parseInt(options.limit), parseInt(options.days), getDatabase());
|
|
15848
|
+
const promoted = new Set(getPromotedConnectors2(getDatabase()));
|
|
15849
|
+
if (options.json) {
|
|
15850
|
+
console.log(JSON.stringify(top.map((t) => ({ ...t, promoted: promoted.has(t.connector) }))));
|
|
15851
|
+
return;
|
|
15852
|
+
}
|
|
15853
|
+
if (top.length === 0) {
|
|
15854
|
+
console.log(chalk2.dim("No usage data yet. Use connectors to build up stats."));
|
|
15855
|
+
return;
|
|
15856
|
+
}
|
|
15857
|
+
console.log(chalk2.bold(`
|
|
15858
|
+
Top connectors (last ${options.days} days):
|
|
15859
|
+
`));
|
|
15860
|
+
console.log(` ${chalk2.dim("#".padEnd(4))}${chalk2.dim("Connector".padEnd(22))}${chalk2.dim("Usage".padEnd(8))}${chalk2.dim("Badges")}`);
|
|
15861
|
+
console.log(chalk2.dim(` ${"\u2500".repeat(45)}`));
|
|
15862
|
+
for (let i = 0;i < top.length; i++) {
|
|
15863
|
+
const t = top[i];
|
|
15864
|
+
const badges = [
|
|
15865
|
+
t.count >= 5 ? chalk2.red("[HOT]") : "",
|
|
15866
|
+
promoted.has(t.connector) ? chalk2.yellow("[PRO]") : ""
|
|
15867
|
+
].filter(Boolean).join(" ");
|
|
15868
|
+
console.log(` ${String(i + 1).padEnd(4)}${chalk2.cyan(t.connector.padEnd(22))}${String(t.count).padEnd(8)}${badges}`);
|
|
15869
|
+
}
|
|
15870
|
+
});
|
|
15871
|
+
program2.command("promote").argument("<connector>", "Connector to promote").description("Mark a connector as promoted (boosted in search)").action((connector) => {
|
|
15872
|
+
const meta = getConnector(connector);
|
|
15873
|
+
if (!meta) {
|
|
15874
|
+
console.error(chalk2.red(`Connector '${connector}' not found`));
|
|
15875
|
+
process.exit(1);
|
|
15876
|
+
}
|
|
15877
|
+
const { promoteConnector: promoteConnector2 } = (init_promotions(), __toCommonJS(exports_promotions));
|
|
15878
|
+
promoteConnector2(connector, getDatabase());
|
|
15879
|
+
console.log(chalk2.green("\u2713") + ` ${meta.displayName} promoted \u2014 will rank higher in search`);
|
|
15880
|
+
});
|
|
15881
|
+
program2.command("demote").argument("<connector>", "Connector to demote").description("Remove promotion from a connector").action((connector) => {
|
|
15882
|
+
const { demoteConnector: demoteConnector2 } = (init_promotions(), __toCommonJS(exports_promotions));
|
|
15883
|
+
const removed = demoteConnector2(connector, getDatabase());
|
|
15884
|
+
if (removed)
|
|
15885
|
+
console.log(chalk2.green("\u2713") + ` ${connector} demoted`);
|
|
15886
|
+
else
|
|
15887
|
+
console.log(chalk2.dim(`${connector} was not promoted`));
|
|
15888
|
+
});
|
|
15889
|
+
var jobsCmd = program2.command("jobs").description("Manage scheduled connector jobs");
|
|
15890
|
+
jobsCmd.command("add").description("Add a scheduled job").requiredOption("--name <name>", "Job name").requiredOption("--connector <connector>", "Connector name").requiredOption("--command <command>", "Command to run").requiredOption("--cron <cron>", "Cron expression (5-field)").option("--args <args>", "Command args (space-separated)").option("--strip", "Apply LLM stripping to output").option("--json", "Output as JSON").action((options) => {
|
|
15891
|
+
const db = getDatabase();
|
|
15892
|
+
const args = options.args ? options.args.split(" ") : [];
|
|
15893
|
+
const job = createJob({ name: options.name, connector: options.connector, command: options.command, args, cron: options.cron, strip: !!options.strip }, db);
|
|
15894
|
+
if (options.json) {
|
|
15895
|
+
console.log(JSON.stringify(job));
|
|
15896
|
+
return;
|
|
15897
|
+
}
|
|
15898
|
+
console.log(chalk2.green("\u2713") + ` Job created: ${job.name} (${job.cron})`);
|
|
15899
|
+
});
|
|
15900
|
+
jobsCmd.command("list").description("List all jobs").option("--json", "Output as JSON").action((options) => {
|
|
15901
|
+
const jobs = listJobs(getDatabase());
|
|
15902
|
+
if (options.json) {
|
|
15903
|
+
console.log(JSON.stringify(jobs));
|
|
15904
|
+
return;
|
|
15905
|
+
}
|
|
15906
|
+
if (jobs.length === 0) {
|
|
15907
|
+
console.log(chalk2.dim("No jobs configured."));
|
|
15908
|
+
return;
|
|
15909
|
+
}
|
|
15910
|
+
for (const j of jobs) {
|
|
15911
|
+
const status = j.enabled ? chalk2.green("enabled") : chalk2.dim("disabled");
|
|
15912
|
+
const strip = j.strip ? chalk2.cyan(" [strip]") : "";
|
|
15913
|
+
console.log(` ${j.name.padEnd(20)} ${j.connector}.${j.command.padEnd(16)} ${j.cron.padEnd(15)} ${status}${strip}`);
|
|
15914
|
+
}
|
|
15915
|
+
});
|
|
15916
|
+
jobsCmd.command("run").description("Manually trigger a job").argument("<name>", "Job name").option("--json", "Output as JSON").action(async (name, options) => {
|
|
15917
|
+
const db = getDatabase();
|
|
15918
|
+
const job = getJobByName(name, db);
|
|
15919
|
+
if (!job) {
|
|
15920
|
+
console.error(chalk2.red(`Job "${name}" not found`));
|
|
15921
|
+
process.exit(1);
|
|
15922
|
+
}
|
|
15923
|
+
if (!options.json)
|
|
15924
|
+
console.log(chalk2.dim(`Running ${job.connector} ${job.command}...`));
|
|
15925
|
+
const result = await triggerJob(job, db);
|
|
15926
|
+
if (options.json) {
|
|
15927
|
+
console.log(JSON.stringify(result));
|
|
15928
|
+
return;
|
|
15929
|
+
}
|
|
15930
|
+
const icon = result.exit_code === 0 ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
15931
|
+
console.log(`${icon} Run ${result.run_id} \u2014 exit ${result.exit_code}`);
|
|
15932
|
+
if (result.output)
|
|
15933
|
+
console.log(result.output.slice(0, 2000));
|
|
15934
|
+
});
|
|
15935
|
+
jobsCmd.command("logs").description("Show recent runs for a job").argument("<name>", "Job name").option("--limit <n>", "Max results", "10").option("--json", "Output as JSON").action((name, options) => {
|
|
15936
|
+
const db = getDatabase();
|
|
15937
|
+
const job = getJobByName(name, db);
|
|
15938
|
+
if (!job) {
|
|
15939
|
+
console.error(chalk2.red(`Job "${name}" not found`));
|
|
15940
|
+
process.exit(1);
|
|
15941
|
+
}
|
|
15942
|
+
const runs = listJobRuns(job.id, parseInt(options.limit), db);
|
|
15943
|
+
if (options.json) {
|
|
15944
|
+
console.log(JSON.stringify(runs));
|
|
15945
|
+
return;
|
|
15946
|
+
}
|
|
15947
|
+
if (runs.length === 0) {
|
|
15948
|
+
console.log(chalk2.dim("No runs yet."));
|
|
15949
|
+
return;
|
|
15950
|
+
}
|
|
15951
|
+
for (const r of runs) {
|
|
15952
|
+
const icon = r.exit_code === 0 ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
15953
|
+
console.log(` ${icon} ${r.started_at.slice(0, 19)} \u2014 exit ${r.exit_code ?? "?"}`);
|
|
15954
|
+
}
|
|
15955
|
+
});
|
|
15956
|
+
jobsCmd.command("enable").description("Enable a job").argument("<name>").action((name) => {
|
|
15957
|
+
const db = getDatabase();
|
|
15958
|
+
const job = getJobByName(name, db);
|
|
15959
|
+
if (!job) {
|
|
15960
|
+
console.error(chalk2.red(`Job "${name}" not found`));
|
|
15961
|
+
process.exit(1);
|
|
15962
|
+
}
|
|
15963
|
+
updateJob(job.id, { enabled: true }, db);
|
|
15964
|
+
console.log(chalk2.green("\u2713") + ` Job "${name}" enabled`);
|
|
15965
|
+
});
|
|
15966
|
+
jobsCmd.command("disable").description("Disable a job").argument("<name>").action((name) => {
|
|
15967
|
+
const db = getDatabase();
|
|
15968
|
+
const job = getJobByName(name, db);
|
|
15969
|
+
if (!job) {
|
|
15970
|
+
console.error(chalk2.red(`Job "${name}" not found`));
|
|
15971
|
+
process.exit(1);
|
|
15972
|
+
}
|
|
15973
|
+
updateJob(job.id, { enabled: false }, db);
|
|
15974
|
+
console.log(chalk2.green("\u2713") + ` Job "${name}" disabled`);
|
|
15975
|
+
});
|
|
15976
|
+
jobsCmd.command("delete").description("Delete a job").argument("<name>").action((name) => {
|
|
15977
|
+
const db = getDatabase();
|
|
15978
|
+
const job = getJobByName(name, db);
|
|
15979
|
+
if (!job) {
|
|
15980
|
+
console.error(chalk2.red(`Job "${name}" not found`));
|
|
15981
|
+
process.exit(1);
|
|
15982
|
+
}
|
|
15983
|
+
deleteJob(job.id, db);
|
|
15984
|
+
console.log(chalk2.green("\u2713") + ` Job "${name}" deleted`);
|
|
15985
|
+
});
|
|
15986
|
+
var workflowsCmd = program2.command("workflows").description("Manage connector workflows (sequential pipelines)");
|
|
15987
|
+
workflowsCmd.command("add").description("Create a workflow from a JSON steps array").requiredOption("--name <name>", "Workflow name").requiredOption("--steps <json>", `Steps JSON array, e.g. '[{"connector":"stripe","command":"products list"}]'`).option("--json", "Output as JSON").action((options) => {
|
|
15988
|
+
let steps;
|
|
15989
|
+
try {
|
|
15990
|
+
steps = JSON.parse(options.steps);
|
|
15991
|
+
} catch {
|
|
15992
|
+
console.error(chalk2.red("Invalid JSON for --steps"));
|
|
15993
|
+
process.exit(1);
|
|
15994
|
+
}
|
|
15995
|
+
const wf = createWorkflow({ name: options.name, steps }, getDatabase());
|
|
15996
|
+
if (options.json) {
|
|
15997
|
+
console.log(JSON.stringify(wf));
|
|
15998
|
+
return;
|
|
15999
|
+
}
|
|
16000
|
+
console.log(chalk2.green("\u2713") + ` Workflow "${wf.name}" created (${wf.steps.length} steps)`);
|
|
16001
|
+
});
|
|
16002
|
+
workflowsCmd.command("list").description("List all workflows").option("--json", "Output as JSON").action((options) => {
|
|
16003
|
+
const wfs = listWorkflows(getDatabase());
|
|
16004
|
+
if (options.json) {
|
|
16005
|
+
console.log(JSON.stringify(wfs));
|
|
16006
|
+
return;
|
|
16007
|
+
}
|
|
16008
|
+
if (wfs.length === 0) {
|
|
16009
|
+
console.log(chalk2.dim("No workflows configured."));
|
|
16010
|
+
return;
|
|
16011
|
+
}
|
|
16012
|
+
for (const wf of wfs) {
|
|
16013
|
+
const status = wf.enabled ? chalk2.green("enabled") : chalk2.dim("disabled");
|
|
16014
|
+
console.log(` ${wf.name.padEnd(20)} ${String(wf.steps.length).padStart(2)} steps ${status}`);
|
|
16015
|
+
}
|
|
16016
|
+
});
|
|
16017
|
+
workflowsCmd.command("run").description("Run a workflow").argument("<name>", "Workflow name").option("--json", "Output as JSON").action(async (name, options) => {
|
|
16018
|
+
const wf = getWorkflowByName(name, getDatabase());
|
|
16019
|
+
if (!wf) {
|
|
16020
|
+
console.error(chalk2.red(`Workflow "${name}" not found`));
|
|
16021
|
+
process.exit(1);
|
|
16022
|
+
}
|
|
16023
|
+
if (!options.json)
|
|
16024
|
+
console.log(chalk2.dim(`Running workflow "${wf.name}" (${wf.steps.length} steps)...`));
|
|
16025
|
+
const result = await runWorkflow(wf);
|
|
16026
|
+
if (options.json) {
|
|
16027
|
+
console.log(JSON.stringify(result));
|
|
16028
|
+
return;
|
|
16029
|
+
}
|
|
16030
|
+
for (const step of result.steps) {
|
|
16031
|
+
const icon = step.exit_code === 0 ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
16032
|
+
console.log(` ${icon} Step ${step.step}: ${step.connector} ${step.command}`);
|
|
16033
|
+
}
|
|
16034
|
+
console.log(result.success ? chalk2.green(`
|
|
16035
|
+
Workflow completed`) : chalk2.red(`
|
|
16036
|
+
Workflow failed`));
|
|
16037
|
+
});
|
|
16038
|
+
workflowsCmd.command("delete").description("Delete a workflow").argument("<name>").action((name) => {
|
|
16039
|
+
const wf = getWorkflowByName(name, getDatabase());
|
|
16040
|
+
if (!wf) {
|
|
16041
|
+
console.error(chalk2.red(`Workflow "${name}" not found`));
|
|
16042
|
+
process.exit(1);
|
|
16043
|
+
}
|
|
16044
|
+
deleteWorkflow(wf.id, getDatabase());
|
|
16045
|
+
console.log(chalk2.green("\u2713") + ` Workflow "${name}" deleted`);
|
|
16046
|
+
});
|
|
16047
|
+
var llmCmd = program2.command("llm").description("Manage LLM provider for output stripping");
|
|
16048
|
+
llmCmd.command("set").description("Configure LLM provider and API key").requiredOption("--provider <provider>", "Provider: cerebras, groq, openai, anthropic").requiredOption("--key <key>", "API key").option("--model <model>", "Model name (defaults to provider default)").option("--json", "Output as JSON").action((options) => {
|
|
16049
|
+
const provider = options.provider;
|
|
16050
|
+
const validProviders = ["cerebras", "groq", "openai", "anthropic"];
|
|
16051
|
+
if (!validProviders.includes(provider)) {
|
|
16052
|
+
console.error(chalk2.red(`Unknown provider "${provider}". Valid: ${validProviders.join(", ")}`));
|
|
16053
|
+
process.exit(1);
|
|
16054
|
+
}
|
|
16055
|
+
const model = options.model || PROVIDER_DEFAULTS[provider].model;
|
|
16056
|
+
const existing = getLlmConfig();
|
|
16057
|
+
saveLlmConfig({ provider, model, api_key: options.key, strip: existing?.strip ?? false });
|
|
16058
|
+
if (options.json) {
|
|
16059
|
+
console.log(JSON.stringify({ provider, model, key: maskKey(options.key), strip: existing?.strip ?? false }));
|
|
16060
|
+
} else {
|
|
16061
|
+
console.log(chalk2.green("\u2713") + ` LLM configured: ${provider} / ${model}`);
|
|
16062
|
+
console.log(` Key: ${maskKey(options.key)}`);
|
|
16063
|
+
console.log(` Strip: ${existing?.strip ? chalk2.green("enabled") : chalk2.dim("disabled")} (run 'connectors llm strip enable' to turn on)`);
|
|
16064
|
+
}
|
|
16065
|
+
});
|
|
16066
|
+
llmCmd.command("status").description("Show current LLM configuration").option("--json", "Output as JSON").action((options) => {
|
|
16067
|
+
const config = getLlmConfig();
|
|
16068
|
+
if (!config) {
|
|
16069
|
+
if (options.json)
|
|
16070
|
+
console.log(JSON.stringify({ configured: false }));
|
|
16071
|
+
else
|
|
16072
|
+
console.log(chalk2.dim("No LLM configured. Run: connectors llm set --provider <provider> --key <key>"));
|
|
16073
|
+
return;
|
|
16074
|
+
}
|
|
16075
|
+
if (options.json) {
|
|
16076
|
+
console.log(JSON.stringify({ configured: true, provider: config.provider, model: config.model, key: maskKey(config.api_key), strip: config.strip }));
|
|
16077
|
+
} else {
|
|
16078
|
+
console.log(chalk2.bold("LLM Configuration"));
|
|
16079
|
+
console.log(` Provider : ${config.provider}`);
|
|
16080
|
+
console.log(` Model : ${config.model}`);
|
|
16081
|
+
console.log(` Key : ${maskKey(config.api_key)}`);
|
|
16082
|
+
console.log(` Strip : ${config.strip ? chalk2.green("enabled") : chalk2.red("disabled")}`);
|
|
16083
|
+
}
|
|
16084
|
+
});
|
|
16085
|
+
llmCmd.command("strip").description("Enable or disable global output stripping").argument("<action>", "enable or disable").action((action) => {
|
|
16086
|
+
if (action !== "enable" && action !== "disable") {
|
|
16087
|
+
console.error(chalk2.red('Action must be "enable" or "disable"'));
|
|
16088
|
+
process.exit(1);
|
|
16089
|
+
}
|
|
16090
|
+
try {
|
|
16091
|
+
setLlmStrip(action === "enable");
|
|
16092
|
+
console.log(chalk2.green("\u2713") + ` Output stripping ${action}d`);
|
|
16093
|
+
} catch (e) {
|
|
16094
|
+
console.error(chalk2.red(String(e instanceof Error ? e.message : e)));
|
|
16095
|
+
process.exit(1);
|
|
16096
|
+
}
|
|
16097
|
+
});
|
|
16098
|
+
llmCmd.command("test").description("Test current LLM configuration with a sample prompt").option("--json", "Output as JSON").action(async (options) => {
|
|
16099
|
+
const config = getLlmConfig();
|
|
16100
|
+
if (!config) {
|
|
16101
|
+
console.error(chalk2.red("No LLM configured. Run: connectors llm set --provider <provider> --key <key>"));
|
|
16102
|
+
process.exit(1);
|
|
16103
|
+
}
|
|
16104
|
+
if (!options.json)
|
|
16105
|
+
console.log(chalk2.dim(`Testing ${config.provider} / ${config.model}...`));
|
|
16106
|
+
try {
|
|
16107
|
+
const client = new LLMClient(config);
|
|
16108
|
+
const result = await client.complete('You are a helpful assistant. Respond with exactly: {"status":"ok"}', "ping");
|
|
16109
|
+
if (options.json) {
|
|
16110
|
+
console.log(JSON.stringify({ success: true, provider: result.provider, model: result.model, latency_ms: result.latency_ms, response: result.content }));
|
|
16111
|
+
} else {
|
|
16112
|
+
console.log(chalk2.green("\u2713") + ` Response received in ${result.latency_ms}ms`);
|
|
16113
|
+
console.log(` ${result.content.trim()}`);
|
|
16114
|
+
}
|
|
16115
|
+
} catch (e) {
|
|
16116
|
+
if (options.json)
|
|
16117
|
+
console.log(JSON.stringify({ success: false, error: String(e instanceof Error ? e.message : e) }));
|
|
16118
|
+
else
|
|
16119
|
+
console.error(chalk2.red("\u2717 " + String(e instanceof Error ? e.message : e)));
|
|
16120
|
+
process.exit(1);
|
|
16121
|
+
}
|
|
16122
|
+
});
|
|
16123
|
+
llmCmd.command("providers").description("List supported LLM providers").option("--json", "Output as JSON").action((options) => {
|
|
16124
|
+
const providers = [
|
|
16125
|
+
{ name: "cerebras", baseUrl: "https://api.cerebras.ai/v1", defaultModel: PROVIDER_DEFAULTS.cerebras.model, compatible: "OpenAI" },
|
|
16126
|
+
{ name: "groq", baseUrl: "https://api.groq.com/openai/v1", defaultModel: PROVIDER_DEFAULTS.groq.model, compatible: "OpenAI" },
|
|
16127
|
+
{ name: "openai", baseUrl: "https://api.openai.com/v1", defaultModel: PROVIDER_DEFAULTS.openai.model, compatible: "OpenAI" },
|
|
16128
|
+
{ name: "anthropic", baseUrl: "https://api.anthropic.com/v1", defaultModel: PROVIDER_DEFAULTS.anthropic.model, compatible: "Anthropic" }
|
|
16129
|
+
];
|
|
16130
|
+
if (options.json) {
|
|
16131
|
+
console.log(JSON.stringify(providers));
|
|
16132
|
+
return;
|
|
16133
|
+
}
|
|
16134
|
+
console.log(chalk2.bold("Supported LLM Providers"));
|
|
16135
|
+
for (const p of providers) {
|
|
16136
|
+
console.log(` ${chalk2.cyan(p.name.padEnd(12))} ${p.defaultModel.padEnd(30)} ${chalk2.dim(p.baseUrl)}`);
|
|
16137
|
+
}
|
|
16138
|
+
});
|
|
14271
16139
|
program2.parse();
|