@posthog/wizard 2.80.0 → 2.80.1

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.
Files changed (227) hide show
  1. package/README.md +187 -57
  2. package/dist/{PickerMenu-m4CCPX4f.js → PickerMenu-BGGeYqd-.js} +104 -4
  3. package/dist/PickerMenu-BGGeYqd-.js.map +1 -0
  4. package/dist/README.md +9 -6
  5. package/dist/{agent-interface-CzyCmp7q.js → agent-interface-CemBvTAA.js} +115 -346
  6. package/dist/agent-interface-CemBvTAA.js.map +1 -0
  7. package/dist/{agent-prompt-loader-4wMxlYSX.js → agent-prompt-loader-DPnj6SwU.js} +6 -5
  8. package/dist/agent-prompt-loader-DPnj6SwU.js.map +1 -0
  9. package/dist/analytics-B3ROGuIr.js +2 -0
  10. package/dist/analytics-D21z3E5l.js +732 -0
  11. package/dist/analytics-D21z3E5l.js.map +1 -0
  12. package/dist/{api-C3Dc4LFl.js → api-DtGIqQ2U.js} +2 -3
  13. package/dist/api-DtGIqQ2U.js.map +1 -0
  14. package/dist/api-IhROOQNv.js +2 -0
  15. package/dist/api-key-login-OEntFvu5.js +2 -0
  16. package/dist/api-key-login-h3E2G3zu.js +55 -0
  17. package/dist/api-key-login-h3E2G3zu.js.map +1 -0
  18. package/dist/bin.js +2 -2
  19. package/dist/bin.js.map +1 -1
  20. package/dist/{bounded-fs-CC_NDtoP.js → bounded-fs-CAsuF6al.js} +3 -3
  21. package/dist/{bounded-fs-CC_NDtoP.js.map → bounded-fs-CAsuF6al.js.map} +1 -1
  22. package/dist/{ci-install-DfcAMhlu.js → ci-install-CEYE02t-.js} +21 -25
  23. package/dist/ci-install-CEYE02t-.js.map +1 -0
  24. package/dist/console-log-O828zyiq.js +32 -0
  25. package/dist/console-log-O828zyiq.js.map +1 -0
  26. package/dist/{debug-DyARf5TF.js → debug-BfQPD2Hg.js} +18 -52
  27. package/dist/debug-BfQPD2Hg.js.map +1 -0
  28. package/dist/{defaults-DpfMnH2q.js → defaults-DDVl3tKN.js} +2 -51
  29. package/dist/defaults-DDVl3tKN.js.map +1 -0
  30. package/dist/{emit-BSetXzDV.js → emit-RfAewcWv.js} +1 -1
  31. package/dist/{emit-BSetXzDV.js.map → emit-RfAewcWv.js.map} +1 -1
  32. package/dist/{errors-C2domSkK.js → errors-CHrJzAZb.js} +4 -4
  33. package/dist/{errors-C2domSkK.js.map → errors-CHrJzAZb.js.map} +1 -1
  34. package/dist/family-picker-BKs-tTyu.js +46 -0
  35. package/dist/family-picker-BKs-tTyu.js.map +1 -0
  36. package/dist/{gateway-BmjYUSua.js → gateway-D3gIlR6b.js} +122 -11
  37. package/dist/gateway-D3gIlR6b.js.map +1 -0
  38. package/dist/headless-BJjhP0SI.js +10 -0
  39. package/dist/headless-BJjhP0SI.js.map +1 -0
  40. package/dist/headless-DIX68UUA.js +3 -0
  41. package/dist/{host-resolution-DVSb7kXb.js → host-resolution-D8GhEVoX.js} +4 -4
  42. package/dist/{host-resolution-DVSb7kXb.js.map → host-resolution-D8GhEVoX.js.map} +1 -1
  43. package/dist/install-Bw8tvDvS.js +2 -0
  44. package/dist/{install-Bk5TNk27.js → install-paPCzPHI.js} +26 -93
  45. package/dist/install-paPCzPHI.js.map +1 -0
  46. package/dist/interactive-tdxZKWax.js +11 -0
  47. package/dist/interactive-tdxZKWax.js.map +1 -0
  48. package/dist/{links-9LWZPSCq.js → links-Cyj6v8kg.js} +3 -3
  49. package/dist/{links-9LWZPSCq.js.map → links-Cyj6v8kg.js.map} +1 -1
  50. package/dist/{main-DKPjFHEV.js → main-0p-YxUNa.js} +204 -469
  51. package/dist/main-0p-YxUNa.js.map +1 -0
  52. package/dist/{mcp-Co8VRF62.js → mcp-D3Z5MXhA.js} +3 -4
  53. package/dist/{mcp-Co8VRF62.js.map → mcp-D3Z5MXhA.js.map} +1 -1
  54. package/dist/mcp-install-smoke-test.ts +2 -2
  55. package/dist/{mcp-prompt-streaming-ljCVoQ9I.js → mcp-prompt-streaming-COVbWnHt.js} +12 -12
  56. package/dist/mcp-prompt-streaming-COVbWnHt.js.map +1 -0
  57. package/dist/mode-label-DB3ol_sj.js +9 -0
  58. package/dist/mode-label-DB3ol_sj.js.map +1 -0
  59. package/dist/{models-Dba8ITeo.js → models-D1SnCzvl.js} +2 -2
  60. package/dist/{models-Dba8ITeo.js.map → models-D1SnCzvl.js.map} +1 -1
  61. package/dist/non-interactive-DxRBc73O.js +18 -0
  62. package/dist/non-interactive-DxRBc73O.js.map +1 -0
  63. package/dist/{oauth-session-D-RfcVmr.js → oauth-session-Dde79Ycm.js} +3 -3
  64. package/dist/{oauth-session-D-RfcVmr.js.map → oauth-session-Dde79Ycm.js.map} +1 -1
  65. package/dist/{orchestrator-tools-CVJ1F9Ub.js → orchestrator-tools-BSNhzzkT.js} +3 -3
  66. package/dist/{orchestrator-tools-CVJ1F9Ub.js.map → orchestrator-tools-BSNhzzkT.js.map} +1 -1
  67. package/dist/{package-json-Cowya9-3.js → package-json-2UrhE6kP.js} +1 -1
  68. package/dist/{package-json-Cowya9-3.js.map → package-json-2UrhE6kP.js.map} +1 -1
  69. package/dist/package-json-Dblip2_X.js +2 -0
  70. package/dist/package-manager-BRXlXo0p.js +105 -0
  71. package/dist/package-manager-BRXlXo0p.js.map +1 -0
  72. package/dist/{pi-B5YTBRDv.js → pi-cM_4Gd_9.js} +16 -18
  73. package/dist/pi-cM_4Gd_9.js.map +1 -0
  74. package/dist/playground-DTKy0XHT.js +12 -0
  75. package/dist/playground-DTKy0XHT.js.map +1 -0
  76. package/dist/posthog-integration-bwHwE87a.js +10291 -0
  77. package/dist/posthog-integration-bwHwE87a.js.map +1 -0
  78. package/dist/programs-BhtyA3lE.js +3 -0
  79. package/dist/programs-SeT1qNik.js +5348 -0
  80. package/dist/programs-SeT1qNik.js.map +1 -0
  81. package/dist/provisioning-BcXfeCMc.js +2 -0
  82. package/dist/{provisioning-CLhuKqXH.js → provisioning-JbJtq7hq.js} +4 -5
  83. package/dist/{provisioning-CLhuKqXH.js.map → provisioning-JbJtq7hq.js.map} +1 -1
  84. package/dist/{queue-tools-knnPQP0e.js → queue-tools-BIZSJyt6.js} +6 -8
  85. package/dist/queue-tools-BIZSJyt6.js.map +1 -0
  86. package/dist/results-DtKICAdz.js +55 -0
  87. package/dist/results-DtKICAdz.js.map +1 -0
  88. package/dist/run-CDurA5tO.js +248 -0
  89. package/dist/run-CDurA5tO.js.map +1 -0
  90. package/dist/run-DDCvLILJ.js +246 -0
  91. package/dist/run-DDCvLILJ.js.map +1 -0
  92. package/dist/run-tool-CTq9OOdT.js +2 -0
  93. package/dist/run-tool-DML8JJvt.js +2420 -0
  94. package/dist/run-tool-DML8JJvt.js.map +1 -0
  95. package/dist/runners-Dhu4pZTN.js +253 -0
  96. package/dist/runners-Dhu4pZTN.js.map +1 -0
  97. package/dist/{security-BvdSFDuM.js → security-DEH8Rn0_.js} +5 -5
  98. package/dist/security-DEH8Rn0_.js.map +1 -0
  99. package/dist/setup-utils-C5-WM-hS.js +118 -0
  100. package/dist/setup-utils-C5-WM-hS.js.map +1 -0
  101. package/dist/smoke-test.sh +1 -1
  102. package/dist/{playground-BLsCfHmQ.js → start-playground-DL4mVEUx.js} +43 -34
  103. package/dist/start-playground-DL4mVEUx.js.map +1 -0
  104. package/dist/{subagent-D_Sqak94.js → subagent-CnFvAq6E.js} +3 -3
  105. package/dist/{subagent-D_Sqak94.js.map → subagent-CnFvAq6E.js.map} +1 -1
  106. package/dist/{task-DiTI6Sak.js → task-BOScSm4W.js} +16 -17
  107. package/dist/task-BOScSm4W.js.map +1 -0
  108. package/dist/{tasks-ChZ_F1YP.js → tasks-BfJhVky2.js} +1 -1
  109. package/dist/tasks-BfJhVky2.js.map +1 -0
  110. package/dist/{telemetry-BNKsDxNS.js → telemetry-CP4rGicd.js} +2 -2
  111. package/dist/{telemetry-BNKsDxNS.js.map → telemetry-CP4rGicd.js.map} +1 -1
  112. package/dist/terminal-J3OD3dN0.js +16162 -0
  113. package/dist/terminal-J3OD3dN0.js.map +1 -0
  114. package/dist/tools-CCMV3DmB.js +544 -0
  115. package/dist/tools-CCMV3DmB.js.map +1 -0
  116. package/dist/{tools-C8LQ8QFz.js → tools-Cz8tDptL.js} +9 -9
  117. package/dist/tools-Cz8tDptL.js.map +1 -0
  118. package/dist/tui-BUZ2PWqN.js +2 -0
  119. package/dist/tui-Csf7VJxt.js +25 -0
  120. package/dist/tui-Csf7VJxt.js.map +1 -0
  121. package/dist/{steps-Hc28zVc_.js → upload-step-CEacB2RV.js} +14 -16
  122. package/dist/upload-step-CEacB2RV.js.map +1 -0
  123. package/dist/{urls-BI4kJ4qQ.js → urls-BDELGZHq.js} +2 -2
  124. package/dist/{urls-BI4kJ4qQ.js.map → urls-BDELGZHq.js.map} +1 -1
  125. package/dist/warlock-smoke-test.ts +1 -2
  126. package/dist/{wizard-abort-DBKtfnBR.js → wizard-abort-D3-75KyV.js} +40 -33
  127. package/dist/wizard-abort-D3-75KyV.js.map +1 -0
  128. package/dist/yara-hooks-CZ1tKxy_.js +2 -0
  129. package/dist/{yara-hooks-C3L6lBij.js → yara-hooks-D8YDyX7o.js} +283 -21
  130. package/dist/yara-hooks-D8YDyX7o.js.map +1 -0
  131. package/package.json +6 -6
  132. package/dist/PickerMenu-m4CCPX4f.js.map +0 -1
  133. package/dist/agent-BkBbVuNq.js +0 -3189
  134. package/dist/agent-BkBbVuNq.js.map +0 -1
  135. package/dist/agent-QGK2YzlX.js +0 -6
  136. package/dist/agent-interface-CzyCmp7q.js.map +0 -1
  137. package/dist/agent-prompt-loader-4wMxlYSX.js.map +0 -1
  138. package/dist/analytics-B6q5PN7a.js +0 -301
  139. package/dist/analytics-B6q5PN7a.js.map +0 -1
  140. package/dist/analytics-BXtfK9o7.js +0 -2
  141. package/dist/api-C3Dc4LFl.js.map +0 -1
  142. package/dist/api-yNjrfZs2.js +0 -2
  143. package/dist/check-screens.tsx +0 -190
  144. package/dist/ci-install-DfcAMhlu.js.map +0 -1
  145. package/dist/constants-DO4X70po.js +0 -260
  146. package/dist/constants-DO4X70po.js.map +0 -1
  147. package/dist/debug-BueK5mRR.js +0 -2
  148. package/dist/debug-DyARf5TF.js.map +0 -1
  149. package/dist/defaults-DpfMnH2q.js.map +0 -1
  150. package/dist/endpoints-D-4KxZiB.js +0 -108
  151. package/dist/endpoints-D-4KxZiB.js.map +0 -1
  152. package/dist/env-api-key-CHGLe0iz.js +0 -2
  153. package/dist/env-api-key-COf0U-Au.js +0 -17
  154. package/dist/env-api-key-COf0U-Au.js.map +0 -1
  155. package/dist/environment-DrLaSsA8.js +0 -39
  156. package/dist/environment-DrLaSsA8.js.map +0 -1
  157. package/dist/environment-hBj7ngmO.js +0 -2
  158. package/dist/file-CVA9ocIC.js +0 -60
  159. package/dist/file-CVA9ocIC.js.map +0 -1
  160. package/dist/file-CmoKK_Pp.js +0 -2
  161. package/dist/file-watcher-C3Su8vXm.js +0 -123
  162. package/dist/file-watcher-C3Su8vXm.js.map +0 -1
  163. package/dist/gateway-BmjYUSua.js.map +0 -1
  164. package/dist/headless-ui-CUbv12Yx.js +0 -44
  165. package/dist/headless-ui-CUbv12Yx.js.map +0 -1
  166. package/dist/install-Bk5TNk27.js.map +0 -1
  167. package/dist/install-F4wm3RSl.js +0 -2
  168. package/dist/interactive-C5LNvDj6.js +0 -11
  169. package/dist/interactive-C5LNvDj6.js.map +0 -1
  170. package/dist/local-dev-McsurOC-.js +0 -135
  171. package/dist/local-dev-McsurOC-.js.map +0 -1
  172. package/dist/logging-ui-p6XKVmTx.js +0 -226
  173. package/dist/logging-ui-p6XKVmTx.js.map +0 -1
  174. package/dist/main-DKPjFHEV.js.map +0 -1
  175. package/dist/mcp-prompt-streaming-ljCVoQ9I.js.map +0 -1
  176. package/dist/mint-failure-C0HyvEwO.js +0 -6403
  177. package/dist/mint-failure-C0HyvEwO.js.map +0 -1
  178. package/dist/non-interactive-CLMJrj_7.js +0 -18
  179. package/dist/non-interactive-CLMJrj_7.js.map +0 -1
  180. package/dist/package-json--ppioh2F.js +0 -2
  181. package/dist/pi-B5YTBRDv.js.map +0 -1
  182. package/dist/playground-BLsCfHmQ.js.map +0 -1
  183. package/dist/posthog-B2E0hpZt.js +0 -2
  184. package/dist/posthog-B42rt_1S.js +0 -124
  185. package/dist/posthog-B42rt_1S.js.map +0 -1
  186. package/dist/project-data--L-WZyvj.js +0 -2
  187. package/dist/project-data-BO9IXn9y.js +0 -1131
  188. package/dist/project-data-BO9IXn9y.js.map +0 -1
  189. package/dist/provisioning-C01REIU2.js +0 -2
  190. package/dist/queue-tools-knnPQP0e.js.map +0 -1
  191. package/dist/registry-B3rC5U4b.js +0 -3464
  192. package/dist/registry-B3rC5U4b.js.map +0 -1
  193. package/dist/registry-BamsM7J9.js +0 -2
  194. package/dist/run-agent-legacy-CwUmPfQF.js +0 -2
  195. package/dist/run-agent-legacy-DWBajsMh.js +0 -3467
  196. package/dist/run-agent-legacy-DWBajsMh.js.map +0 -1
  197. package/dist/runners-D1PqqpjA.js +0 -834
  198. package/dist/runners-D1PqqpjA.js.map +0 -1
  199. package/dist/security-BvdSFDuM.js.map +0 -1
  200. package/dist/setup-utils-ChXXTi1m.js +0 -301
  201. package/dist/setup-utils-ChXXTi1m.js.map +0 -1
  202. package/dist/start-tui-DicLfgsj.js +0 -6964
  203. package/dist/start-tui-DicLfgsj.js.map +0 -1
  204. package/dist/steps-Hc28zVc_.js.map +0 -1
  205. package/dist/store-COCO6U0P.js +0 -5
  206. package/dist/store-D3509G87.js +0 -1030
  207. package/dist/store-D3509G87.js.map +0 -1
  208. package/dist/task-DiTI6Sak.js.map +0 -1
  209. package/dist/task-status-CmrrR7zo.js +0 -16
  210. package/dist/task-status-CmrrR7zo.js.map +0 -1
  211. package/dist/task-stream-BckhG_cB.js +0 -363
  212. package/dist/task-stream-BckhG_cB.js.map +0 -1
  213. package/dist/tasks-ChZ_F1YP.js.map +0 -1
  214. package/dist/terminal-PK9bCLRi.js +0 -7222
  215. package/dist/terminal-PK9bCLRi.js.map +0 -1
  216. package/dist/tools-C8LQ8QFz.js.map +0 -1
  217. package/dist/ui-tPNpM6vj.js +0 -15
  218. package/dist/ui-tPNpM6vj.js.map +0 -1
  219. package/dist/version-5_ydHkM6.js +0 -6
  220. package/dist/version-5_ydHkM6.js.map +0 -1
  221. package/dist/wizard-abort-BVjqLyeA.js +0 -3
  222. package/dist/wizard-abort-DBKtfnBR.js.map +0 -1
  223. package/dist/wizard-session-B7BHnay0.js +0 -2
  224. package/dist/wizard-session-BYw6LzpS.js +0 -133
  225. package/dist/wizard-session-BYw6LzpS.js.map +0 -1
  226. package/dist/yara-hooks-C3L6lBij.js.map +0 -1
  227. package/dist/yara-hooks-CF_IsoaA.js +0 -2
@@ -1,3467 +0,0 @@
1
- import { at as isEnvFileName, c as checkAllSettingsConflicts, d as restoreClaudeSettings, h as markGrantRevoked, it as MAX_ENV_KEY_SET, l as classifySettingsConflicts, n as buildRunTags, ot as parseEnvKeyNames, s as backupAndFixClaudeSettings, st as toPromptSafeRelativePath } from "./agent-interface-CzyCmp7q.js";
2
- import { n as ErrorCodes } from "./emit-BSetXzDV.js";
3
- import { i as enableDebugLogs, o as initLogFile, s as logToFile } from "./debug-DyARf5TF.js";
4
- import { $ as getSkillsBaseUrl, W as WIZARD_OAUTH_SCOPES } from "./constants-DO4X70po.js";
5
- import { r as mayReportScanResults } from "./wizard-session-BYw6LzpS.js";
6
- import { n as analytics, r as groupsFromUser } from "./analytics-B6q5PN7a.js";
7
- import "./errors-C2domSkK.js";
8
- import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-CC_NDtoP.js";
9
- import { a as getBlockingServiceKeys, i as evaluateWizardReadiness, n as SERVICE_LABELS, r as SIGNUP_WIZARD_READINESS_CONFIG } from "./logging-ui-p6XKVmTx.js";
10
- import { t as getUI } from "./ui-tPNpM6vj.js";
11
- import { r as wizardAbort, t as registerCleanup } from "./wizard-abort-DBKtfnBR.js";
12
- import { t as isNonInteractiveEnvironment } from "./environment-DrLaSsA8.js";
13
- import { i as oauthCredentials, t as configureOAuthSession } from "./oauth-session-D-RfcVmr.js";
14
- import { i as resolveBinding, n as captureSwitchboardDecision, r as runAgent } from "./agent-BkBbVuNq.js";
15
- import { _ as coerceAuditChecks, a as flushScanReport } from "./yara-hooks-C3L6lBij.js";
16
- import { g as TASK_OUTCOMES_KEY } from "./queue-tools-knnPQP0e.js";
17
- import { a as OAuthError, i as refreshAccessToken, r as missingOAuthScopes, t as getOrAskForProjectData } from "./project-data-BO9IXn9y.js";
18
- import { t as FRAMEWORK_REGISTRY } from "./registry-B3rC5U4b.js";
19
- import { t as startFileWatcher } from "./file-watcher-C3Su8vXm.js";
20
- import fs, { existsSync, statSync } from "fs";
21
- import path, { join } from "path";
22
- import { randomUUID } from "crypto";
23
- //#region src/programs/credentials.ts
24
- /**
25
- * Grants the token endpoint refuses permanently. A dead grant means the login
26
- * is gone, not that the network blipped, so only these mark the session.
27
- */
28
- const DEAD_GRANT_CODES = new Set(["invalid_grant", "invalid_client"]);
29
- async function rotateCredentials(credentials, baseUrl) {
30
- if (!credentials.refreshToken) return credentials;
31
- try {
32
- const token = await refreshAccessToken(credentials.refreshToken, baseUrl, credentials.oauthClientId);
33
- return {
34
- ...credentials,
35
- accessToken: token.access_token,
36
- missingScopes: missingOAuthScopes([...WIZARD_OAUTH_SCOPES, ...credentials.missingScopes ?? []], token.scope),
37
- refreshToken: token.refresh_token ?? credentials.refreshToken,
38
- expiresAt: Date.now() + token.expires_in * 1e3
39
- };
40
- } catch (error) {
41
- if (error instanceof OAuthError && DEAD_GRANT_CODES.has(error.code)) {
42
- markGrantRevoked();
43
- analytics.wizardCapture("auth session expired", { reason: error.code });
44
- }
45
- logToFile("[oauth] token refresh failed, continuing with the existing token:", error instanceof Error ? error.message : error);
46
- return credentials;
47
- }
48
- }
49
- //#endregion
50
- //#region src/programs/warehouse-sources/registry.ts
51
- const CORE_SOURCE_DETECTORS = [
52
- {
53
- kind: "Postgres",
54
- label: "PostgreSQL",
55
- mode: "in-cli",
56
- signals: {
57
- npm: [
58
- "pg",
59
- "postgres",
60
- "postgres.js",
61
- "knex",
62
- "sequelize"
63
- ],
64
- python: [
65
- "psycopg",
66
- "psycopg2",
67
- "psycopg2-binary",
68
- "asyncpg"
69
- ],
70
- ruby: ["pg"],
71
- envKeys: [
72
- /^DATABASE_URL$/,
73
- /^POSTGRES_/,
74
- /^PG(HOST|DATABASE|USER|PORT)$/
75
- ]
76
- },
77
- supersededBy: ["Neon", "Supabase"]
78
- },
79
- {
80
- kind: "MySQL",
81
- label: "MySQL",
82
- mode: "in-cli",
83
- signals: {
84
- npm: ["mysql", "mysql2"],
85
- python: [
86
- "pymysql",
87
- "mysqlclient",
88
- "mysql-connector-python"
89
- ],
90
- ruby: ["mysql2"],
91
- envKeys: [/^MYSQL_/]
92
- }
93
- },
94
- {
95
- kind: "MongoDB",
96
- label: "MongoDB",
97
- mode: "in-cli",
98
- signals: {
99
- npm: ["mongodb", "mongoose"],
100
- python: ["pymongo", "motor"],
101
- ruby: ["mongo", "mongoid"],
102
- envKeys: [/^MONGO(DB)?_/]
103
- }
104
- },
105
- {
106
- kind: "Snowflake",
107
- label: "Snowflake",
108
- mode: "in-cli",
109
- signals: {
110
- npm: ["snowflake-sdk"],
111
- python: ["snowflake-connector-python", "snowflake-sqlalchemy"],
112
- envKeys: [/^SNOWFLAKE_/]
113
- }
114
- },
115
- {
116
- kind: "BigQuery",
117
- label: "BigQuery",
118
- mode: "deep-link",
119
- signals: {
120
- npm: ["@google-cloud/bigquery"],
121
- python: ["google-cloud-bigquery"],
122
- envKeys: [/^BIGQUERY_/]
123
- }
124
- },
125
- {
126
- kind: "Redshift",
127
- label: "Redshift",
128
- mode: "in-cli",
129
- signals: {
130
- npm: ["node-redshift"],
131
- python: ["redshift-connector"],
132
- envKeys: [/^REDSHIFT_/]
133
- }
134
- },
135
- {
136
- kind: "MSSQL",
137
- label: "SQL Server",
138
- mode: "in-cli",
139
- signals: {
140
- npm: ["mssql", "tedious"],
141
- python: ["pyodbc", "pymssql"],
142
- envKeys: [/^MSSQL_/]
143
- }
144
- },
145
- {
146
- kind: "Supabase",
147
- label: "Supabase",
148
- mode: "in-cli",
149
- signals: {
150
- npm: ["@supabase/supabase-js"],
151
- python: ["supabase"],
152
- envKeys: [/^SUPABASE_/]
153
- }
154
- },
155
- {
156
- kind: "ClickHouse",
157
- label: "ClickHouse",
158
- mode: "in-cli",
159
- signals: {
160
- npm: ["@clickhouse/client"],
161
- python: ["clickhouse-connect", "clickhouse-driver"],
162
- envKeys: [/^CLICKHOUSE_/]
163
- }
164
- },
165
- {
166
- kind: "Convex",
167
- label: "Convex",
168
- mode: "in-cli",
169
- signals: {
170
- npm: ["convex"],
171
- python: ["convex"],
172
- envKeys: [/^CONVEX_/, /^NEXT_PUBLIC_CONVEX_URL$/]
173
- }
174
- },
175
- {
176
- kind: "Firebase",
177
- label: "Firebase",
178
- mode: "deep-link",
179
- signals: {
180
- npm: ["firebase-admin", "firebase"],
181
- python: ["firebase-admin"],
182
- envKeys: [/^FIREBASE_/, /^NEXT_PUBLIC_FIREBASE_/]
183
- }
184
- },
185
- {
186
- kind: "Neon",
187
- label: "Neon",
188
- mode: "in-cli",
189
- signals: {
190
- npm: ["@neondatabase/serverless"],
191
- envKeys: [/^NEON_/]
192
- }
193
- },
194
- {
195
- kind: "PlanetScaleMySQL",
196
- label: "PlanetScale MySQL",
197
- mode: "in-cli",
198
- signals: {
199
- npm: ["@planetscale/database"],
200
- envKeys: [/^PLANETSCALE_/]
201
- }
202
- },
203
- {
204
- kind: "DynamoDB",
205
- label: "DynamoDB",
206
- mode: "in-cli",
207
- signals: {
208
- npm: ["@aws-sdk/client-dynamodb", "@aws-sdk/lib-dynamodb"],
209
- python: ["pynamodb"]
210
- }
211
- },
212
- {
213
- kind: "Motherduck",
214
- label: "MotherDuck",
215
- mode: "in-cli",
216
- signals: {
217
- npm: ["@motherduck/wasm-client"],
218
- envKeys: [/^MOTHERDUCK_/]
219
- }
220
- },
221
- {
222
- kind: "Databricks",
223
- label: "Databricks",
224
- mode: "in-cli",
225
- signals: {
226
- npm: ["@databricks/sql"],
227
- python: ["databricks-sql-connector", "databricks-sdk"],
228
- envKeys: [/^DATABRICKS_/]
229
- }
230
- },
231
- {
232
- kind: "Singlestore",
233
- label: "SingleStore",
234
- mode: "in-cli",
235
- signals: {
236
- python: ["singlestoredb"],
237
- envKeys: [/^SINGLESTORE_/]
238
- }
239
- },
240
- {
241
- kind: "Stripe",
242
- label: "Stripe",
243
- mode: "in-cli",
244
- signals: {
245
- npm: [
246
- "stripe",
247
- "@stripe/stripe-js",
248
- "@stripe/react-stripe-js"
249
- ],
250
- python: ["stripe"],
251
- ruby: ["stripe"],
252
- envKeys: [/^STRIPE_(SECRET|API)_KEY$/]
253
- }
254
- },
255
- {
256
- kind: "Clerk",
257
- label: "Clerk",
258
- mode: "in-cli",
259
- signals: {
260
- npm: [
261
- "@clerk/nextjs",
262
- "@clerk/clerk-react",
263
- "@clerk/backend",
264
- "@clerk/express",
265
- "@clerk/fastify",
266
- "@clerk/remix"
267
- ],
268
- envKeys: [/^CLERK_SECRET_KEY$/, /^NEXT_PUBLIC_CLERK_/]
269
- }
270
- },
271
- {
272
- kind: "Resend",
273
- label: "Resend",
274
- mode: "in-cli",
275
- signals: {
276
- npm: ["resend"],
277
- python: ["resend"],
278
- envKeys: [/^RESEND_API_KEY$/]
279
- }
280
- },
281
- {
282
- kind: "Shopify",
283
- label: "Shopify",
284
- mode: "in-cli",
285
- signals: {
286
- npm: ["@shopify/shopify-api", "shopify-api-node"],
287
- python: ["shopifyapi"],
288
- envKeys: [/^SHOPIFY_/]
289
- }
290
- },
291
- {
292
- kind: "Klaviyo",
293
- label: "Klaviyo",
294
- mode: "in-cli",
295
- signals: {
296
- npm: ["klaviyo-api"],
297
- python: ["klaviyo-api"],
298
- envKeys: [/^KLAVIYO_/]
299
- }
300
- },
301
- {
302
- kind: "Chargebee",
303
- label: "Chargebee",
304
- mode: "in-cli",
305
- signals: {
306
- npm: ["chargebee"],
307
- python: ["chargebee"],
308
- envKeys: [/^CHARGEBEE_/]
309
- }
310
- },
311
- {
312
- kind: "Paddle",
313
- label: "Paddle",
314
- mode: "in-cli",
315
- signals: {
316
- npm: ["@paddle/paddle-node-sdk", "@paddle/paddle-js"],
317
- envKeys: [/^PADDLE_/]
318
- }
319
- },
320
- {
321
- kind: "Polar",
322
- label: "Polar",
323
- mode: "in-cli",
324
- signals: {
325
- npm: ["@polar-sh/sdk", "@polar-sh/nextjs"],
326
- envKeys: [/^POLAR_/]
327
- }
328
- },
329
- {
330
- kind: "Mailchimp",
331
- label: "Mailchimp",
332
- mode: "in-cli",
333
- signals: {
334
- npm: ["@mailchimp/mailchimp_marketing"],
335
- python: ["mailchimp-marketing"],
336
- envKeys: [/^MAILCHIMP_/]
337
- }
338
- },
339
- {
340
- kind: "CustomerIO",
341
- label: "Customer.io",
342
- mode: "in-cli",
343
- signals: {
344
- npm: ["customerio-node"],
345
- python: ["customerio"],
346
- envKeys: [/^CUSTOMER_?IO_/]
347
- }
348
- },
349
- {
350
- kind: "Typeform",
351
- label: "Typeform",
352
- mode: "in-cli",
353
- signals: {
354
- npm: ["@typeform/api-client"],
355
- envKeys: [/^TYPEFORM_/]
356
- }
357
- },
358
- {
359
- kind: "Sentry",
360
- label: "Sentry",
361
- mode: "in-cli",
362
- signals: {
363
- npm: [
364
- "@sentry/node",
365
- "@sentry/browser",
366
- "@sentry/react",
367
- "@sentry/nextjs"
368
- ],
369
- python: ["sentry-sdk"],
370
- ruby: ["sentry-ruby"]
371
- }
372
- },
373
- {
374
- kind: "Plaid",
375
- label: "Plaid",
376
- mode: "in-cli",
377
- signals: {
378
- npm: ["plaid"],
379
- python: ["plaid-python", "plaid"],
380
- ruby: ["plaid"],
381
- envKeys: [/^PLAID_/]
382
- }
383
- },
384
- {
385
- kind: "Braintree",
386
- label: "Braintree",
387
- mode: "in-cli",
388
- signals: {
389
- npm: ["braintree"],
390
- python: ["braintree"],
391
- ruby: ["braintree"],
392
- envKeys: [/^BRAINTREE_/]
393
- }
394
- },
395
- {
396
- kind: "Square",
397
- label: "Square",
398
- mode: "in-cli",
399
- signals: {
400
- npm: ["square"],
401
- python: ["squareup"],
402
- ruby: ["square"],
403
- envKeys: [/^SQUARE_/]
404
- }
405
- },
406
- {
407
- kind: "GoCardless",
408
- label: "GoCardless",
409
- mode: "in-cli",
410
- signals: {
411
- npm: ["gocardless-nodejs"],
412
- python: ["gocardless-pro"],
413
- ruby: ["gocardless_pro"],
414
- envKeys: [/^GOCARDLESS_/]
415
- }
416
- },
417
- {
418
- kind: "Mollie",
419
- label: "Mollie",
420
- mode: "in-cli",
421
- signals: {
422
- npm: ["@mollie/api-client"],
423
- python: ["mollie-api-python"],
424
- envKeys: [/^MOLLIE_/]
425
- }
426
- },
427
- {
428
- kind: "CheckoutCom",
429
- label: "Checkout.com",
430
- mode: "in-cli",
431
- signals: {
432
- npm: ["checkout-sdk-node"],
433
- python: ["checkout-sdk"],
434
- envKeys: [/^CKO_/, /^CHECKOUT_COM_/]
435
- }
436
- },
437
- {
438
- kind: "Recurly",
439
- label: "Recurly",
440
- mode: "in-cli",
441
- signals: {
442
- npm: ["recurly"],
443
- python: ["recurly"],
444
- ruby: ["recurly"],
445
- envKeys: [/^RECURLY_/]
446
- }
447
- },
448
- {
449
- kind: "RevenueCat",
450
- label: "RevenueCat",
451
- mode: "in-cli",
452
- signals: {
453
- npm: [
454
- "@revenuecat/purchases-js",
455
- "react-native-purchases",
456
- "@revenuecat/purchases-capacitor"
457
- ],
458
- envKeys: [/^REVENUE_?CAT_/]
459
- }
460
- },
461
- {
462
- kind: "Twilio",
463
- label: "Twilio",
464
- mode: "in-cli",
465
- signals: {
466
- npm: ["twilio"],
467
- python: ["twilio"],
468
- ruby: ["twilio-ruby"],
469
- envKeys: [/^TWILIO_/]
470
- }
471
- },
472
- {
473
- kind: "SendGrid",
474
- label: "SendGrid",
475
- mode: "in-cli",
476
- signals: {
477
- npm: ["@sendgrid/mail", "@sendgrid/client"],
478
- python: ["sendgrid"],
479
- ruby: ["sendgrid-ruby"],
480
- envKeys: [/^SENDGRID_/]
481
- }
482
- },
483
- {
484
- kind: "Mailgun",
485
- label: "Mailgun",
486
- mode: "in-cli",
487
- signals: {
488
- npm: ["mailgun.js", "mailgun-js"],
489
- python: ["mailgun"],
490
- ruby: ["mailgun-ruby"],
491
- envKeys: [/^MAILGUN_/]
492
- }
493
- },
494
- {
495
- kind: "Postmark",
496
- label: "Postmark",
497
- mode: "in-cli",
498
- signals: {
499
- npm: ["postmark"],
500
- python: ["postmarker"],
501
- ruby: ["postmark"],
502
- envKeys: [/^POSTMARK_/]
503
- }
504
- },
505
- {
506
- kind: "Brevo",
507
- label: "Brevo",
508
- mode: "in-cli",
509
- signals: {
510
- npm: ["@getbrevo/brevo", "sib-api-v3-sdk"],
511
- python: ["sib-api-v3-sdk"],
512
- envKeys: [/^BREVO_/]
513
- }
514
- },
515
- {
516
- kind: "MailerLite",
517
- label: "MailerLite",
518
- mode: "in-cli",
519
- signals: {
520
- npm: ["@mailerlite/mailerlite-nodejs"],
521
- python: ["mailerlite"],
522
- envKeys: [/^MAILERLITE_/]
523
- }
524
- },
525
- {
526
- kind: "Mailjet",
527
- label: "Mailjet",
528
- mode: "in-cli",
529
- signals: {
530
- npm: ["node-mailjet"],
531
- python: ["mailjet-rest"],
532
- envKeys: [/^MAILJET_/, /^MJ_APIKEY_/]
533
- }
534
- },
535
- {
536
- kind: "LaunchDarkly",
537
- label: "LaunchDarkly",
538
- mode: "in-cli",
539
- signals: {
540
- npm: [
541
- "launchdarkly-node-server-sdk",
542
- "@launchdarkly/node-server-sdk",
543
- "launchdarkly-js-client-sdk",
544
- "launchdarkly-react-client-sdk"
545
- ],
546
- python: ["launchdarkly-server-sdk"],
547
- ruby: ["launchdarkly-server-sdk"],
548
- envKeys: [/^LAUNCHDARKLY_/, /^LD_SDK_KEY$/]
549
- }
550
- },
551
- {
552
- kind: "Optimizely",
553
- label: "Optimizely",
554
- mode: "in-cli",
555
- signals: {
556
- npm: ["@optimizely/optimizely-sdk"],
557
- python: ["optimizely-sdk"],
558
- envKeys: [/^OPTIMIZELY_/]
559
- }
560
- },
561
- {
562
- kind: "Braze",
563
- label: "Braze",
564
- mode: "in-cli",
565
- signals: {
566
- npm: ["@braze/web-sdk", "@braze/react-native-sdk"],
567
- python: ["braze-client"],
568
- envKeys: [/^BRAZE_/]
569
- }
570
- },
571
- {
572
- kind: "Rollbar",
573
- label: "Rollbar",
574
- mode: "in-cli",
575
- signals: {
576
- npm: ["rollbar"],
577
- python: ["rollbar", "pyrollbar"],
578
- ruby: ["rollbar"],
579
- envKeys: [/^ROLLBAR_/]
580
- }
581
- },
582
- {
583
- kind: "Okta",
584
- label: "Okta",
585
- mode: "in-cli",
586
- signals: {
587
- npm: [
588
- "@okta/okta-sdk-nodejs",
589
- "@okta/okta-auth-js",
590
- "@okta/okta-react"
591
- ],
592
- python: ["okta"],
593
- envKeys: [/^OKTA_/]
594
- }
595
- },
596
- {
597
- kind: "WorkOS",
598
- label: "WorkOS",
599
- mode: "in-cli",
600
- signals: {
601
- npm: ["@workos-inc/node"],
602
- python: ["workos"],
603
- envKeys: [/^WORKOS_/]
604
- }
605
- },
606
- {
607
- kind: "Notion",
608
- label: "Notion",
609
- mode: "in-cli",
610
- signals: {
611
- npm: ["@notionhq/client"],
612
- python: ["notion-client"],
613
- envKeys: [/^NOTION_/]
614
- }
615
- },
616
- {
617
- kind: "FullStory",
618
- label: "FullStory",
619
- mode: "in-cli",
620
- signals: {
621
- npm: ["@fullstory/browser", "@fullstory/react-native"],
622
- envKeys: [/^FULLSTORY_/]
623
- }
624
- },
625
- {
626
- kind: "Amplitude",
627
- label: "Amplitude",
628
- mode: "in-cli",
629
- signals: {
630
- npm: [
631
- "@amplitude/analytics-browser",
632
- "@amplitude/analytics-node",
633
- "@amplitude/analytics-react-native",
634
- "amplitude-js"
635
- ],
636
- python: ["amplitude-analytics"],
637
- envKeys: [/^AMPLITUDE_/]
638
- }
639
- },
640
- {
641
- kind: "Mixpanel",
642
- label: "Mixpanel",
643
- mode: "in-cli",
644
- signals: {
645
- npm: ["mixpanel", "mixpanel-browser"],
646
- python: ["mixpanel"],
647
- ruby: ["mixpanel-ruby"],
648
- envKeys: [/^MIXPANEL_/]
649
- }
650
- },
651
- {
652
- kind: "Pendo",
653
- label: "Pendo",
654
- mode: "in-cli",
655
- signals: {
656
- npm: ["@pendo/agent"],
657
- envKeys: [/^PENDO_/]
658
- }
659
- },
660
- {
661
- kind: "Salesforce",
662
- label: "Salesforce",
663
- mode: "deep-link",
664
- signals: {
665
- npm: ["jsforce"],
666
- python: ["simple-salesforce"],
667
- envKeys: [/^SALESFORCE_/]
668
- }
669
- },
670
- {
671
- kind: "Hubspot",
672
- label: "HubSpot",
673
- mode: "deep-link",
674
- signals: {
675
- npm: ["@hubspot/api-client"],
676
- python: ["hubspot-api-client"],
677
- envKeys: [/^HUBSPOT_/]
678
- }
679
- },
680
- {
681
- kind: "Zendesk",
682
- label: "Zendesk",
683
- mode: "deep-link",
684
- signals: {
685
- npm: ["node-zendesk"],
686
- python: ["zenpy"],
687
- envKeys: [/^ZENDESK_/]
688
- }
689
- },
690
- {
691
- kind: "Intercom",
692
- label: "Intercom",
693
- mode: "deep-link",
694
- signals: {
695
- npm: ["intercom-client", "@intercom/messenger-js-sdk"],
696
- python: ["python-intercom"],
697
- envKeys: [/^INTERCOM_/]
698
- }
699
- },
700
- {
701
- kind: "Linear",
702
- label: "Linear",
703
- mode: "deep-link",
704
- signals: {
705
- npm: ["@linear/sdk"],
706
- envKeys: [/^LINEAR_API_KEY$/]
707
- }
708
- },
709
- {
710
- kind: "Slack",
711
- label: "Slack",
712
- mode: "deep-link",
713
- signals: {
714
- npm: ["@slack/web-api", "@slack/bolt"],
715
- python: ["slack-sdk", "slack-bolt"],
716
- envKeys: [/^SLACK_(BOT|APP|SIGNING|CLIENT)_/]
717
- }
718
- },
719
- {
720
- kind: "Github",
721
- label: "GitHub",
722
- mode: "deep-link",
723
- signals: {
724
- npm: [
725
- "@octokit/rest",
726
- "@octokit/core",
727
- "@octokit/graphql",
728
- "octokit"
729
- ],
730
- python: ["pygithub"],
731
- ruby: ["octokit"]
732
- }
733
- }
734
- ];
735
- const LLM_SOURCE_DETECTORS = [
736
- {
737
- kind: "OpenAI",
738
- label: "OpenAI",
739
- mode: "in-cli",
740
- signals: {
741
- npm: ["openai"],
742
- python: ["openai"],
743
- envKeys: [/^OPENAI_/]
744
- }
745
- },
746
- {
747
- kind: "Anthropic",
748
- label: "Anthropic",
749
- mode: "in-cli",
750
- signals: {
751
- npm: ["@anthropic-ai/sdk"],
752
- python: ["anthropic"],
753
- envKeys: [/^ANTHROPIC_/]
754
- }
755
- },
756
- {
757
- kind: "Cohere",
758
- label: "Cohere",
759
- mode: "in-cli",
760
- signals: {
761
- npm: ["cohere-ai"],
762
- python: ["cohere"],
763
- envKeys: [/^COHERE_/]
764
- }
765
- },
766
- {
767
- kind: "MistralAI",
768
- label: "Mistral AI",
769
- mode: "in-cli",
770
- signals: {
771
- npm: ["@mistralai/mistralai"],
772
- python: ["mistralai"],
773
- envKeys: [/^MISTRAL_/]
774
- }
775
- },
776
- {
777
- kind: "Groq",
778
- label: "Groq",
779
- mode: "in-cli",
780
- signals: {
781
- npm: ["groq-sdk"],
782
- python: ["groq"],
783
- envKeys: [/^GROQ_/]
784
- }
785
- },
786
- {
787
- kind: "TogetherAI",
788
- label: "Together AI",
789
- mode: "in-cli",
790
- signals: {
791
- npm: ["together-ai"],
792
- python: ["together"],
793
- envKeys: [/^TOGETHER_/]
794
- }
795
- },
796
- {
797
- kind: "FireworksAI",
798
- label: "Fireworks AI",
799
- mode: "in-cli",
800
- signals: {
801
- python: ["fireworks-ai"],
802
- envKeys: [/^FIREWORKS_/]
803
- }
804
- },
805
- {
806
- kind: "Replicate",
807
- label: "Replicate",
808
- mode: "in-cli",
809
- signals: {
810
- npm: ["replicate"],
811
- python: ["replicate"],
812
- envKeys: [/^REPLICATE_/]
813
- }
814
- },
815
- {
816
- kind: "HuggingFace",
817
- label: "Hugging Face",
818
- mode: "in-cli",
819
- signals: {
820
- npm: ["@huggingface/inference"],
821
- python: ["huggingface-hub"],
822
- envKeys: [/^HUGGINGFACE_/, /^HF_TOKEN$/]
823
- }
824
- },
825
- {
826
- kind: "ElevenLabs",
827
- label: "ElevenLabs",
828
- mode: "in-cli",
829
- signals: {
830
- npm: ["@elevenlabs/elevenlabs-js", "elevenlabs"],
831
- python: ["elevenlabs"],
832
- envKeys: [/^ELEVENLABS_/, /^ELEVEN_LABS_/]
833
- }
834
- },
835
- {
836
- kind: "Deepgram",
837
- label: "Deepgram",
838
- mode: "in-cli",
839
- signals: {
840
- npm: ["@deepgram/sdk"],
841
- python: ["deepgram-sdk"],
842
- envKeys: [/^DEEPGRAM_/]
843
- }
844
- },
845
- {
846
- kind: "AssemblyAI",
847
- label: "AssemblyAI",
848
- mode: "in-cli",
849
- signals: {
850
- npm: ["assemblyai"],
851
- python: ["assemblyai"],
852
- envKeys: [/^ASSEMBLYAI_/]
853
- }
854
- },
855
- {
856
- kind: "Langfuse",
857
- label: "Langfuse",
858
- mode: "in-cli",
859
- signals: {
860
- npm: ["langfuse"],
861
- python: ["langfuse"],
862
- envKeys: [/^LANGFUSE_/]
863
- }
864
- },
865
- {
866
- kind: "LangSmith",
867
- label: "LangSmith",
868
- mode: "in-cli",
869
- signals: {
870
- npm: ["langsmith"],
871
- python: ["langsmith"],
872
- envKeys: [/^LANGSMITH_/, /^LANGCHAIN_API_KEY$/]
873
- }
874
- },
875
- {
876
- kind: "Firecrawl",
877
- label: "Firecrawl",
878
- mode: "in-cli",
879
- signals: {
880
- npm: ["@mendable/firecrawl-js"],
881
- python: ["firecrawl-py"],
882
- envKeys: [/^FIRECRAWL_/]
883
- }
884
- },
885
- {
886
- kind: "Mem0",
887
- label: "Mem0",
888
- mode: "in-cli",
889
- signals: {
890
- npm: ["mem0ai"],
891
- python: ["mem0ai"],
892
- envKeys: [/^MEM0_/]
893
- }
894
- },
895
- {
896
- kind: "Vellum",
897
- label: "Vellum",
898
- mode: "in-cli",
899
- signals: {
900
- npm: ["vellum-ai"],
901
- python: ["vellum-ai"],
902
- envKeys: [/^VELLUM_/]
903
- }
904
- },
905
- {
906
- kind: "Helicone",
907
- label: "Helicone",
908
- mode: "in-cli",
909
- signals: {
910
- npm: ["@helicone/helpers"],
911
- envKeys: [/^HELICONE_/]
912
- }
913
- },
914
- {
915
- kind: "OpenRouter",
916
- label: "OpenRouter",
917
- mode: "in-cli",
918
- signals: {
919
- npm: ["@openrouter/ai-sdk-provider"],
920
- envKeys: [/^OPENROUTER_/]
921
- }
922
- },
923
- {
924
- kind: "Browserbase",
925
- label: "Browserbase",
926
- mode: "in-cli",
927
- signals: {
928
- npm: ["@browserbasehq/sdk", "@browserbasehq/stagehand"],
929
- python: ["browserbase"],
930
- envKeys: [/^BROWSERBASE_/]
931
- }
932
- },
933
- {
934
- kind: "E2B",
935
- label: "E2B",
936
- mode: "in-cli",
937
- signals: {
938
- npm: ["e2b", "@e2b/code-interpreter"],
939
- python: ["e2b", "e2b-code-interpreter"],
940
- envKeys: [/^E2B_/]
941
- }
942
- },
943
- {
944
- kind: "WeightsAndBiases",
945
- label: "Weights & Biases",
946
- mode: "in-cli",
947
- signals: {
948
- python: ["wandb"],
949
- envKeys: [/^WANDB_/]
950
- }
951
- },
952
- {
953
- kind: "LlamaCloud",
954
- label: "LlamaCloud",
955
- mode: "in-cli",
956
- signals: {
957
- npm: ["llama-cloud-services"],
958
- python: ["llama-cloud-services"],
959
- envKeys: [/^LLAMA_CLOUD_/]
960
- }
961
- },
962
- {
963
- kind: "Zep",
964
- label: "Zep",
965
- mode: "in-cli",
966
- signals: {
967
- npm: ["@getzep/zep-cloud"],
968
- python: ["zep-cloud"],
969
- envKeys: [/^ZEP_API_KEY$/]
970
- }
971
- }
972
- ];
973
- const OTHER_SOURCE_DETECTORS = [
974
- {
975
- kind: "Paystack",
976
- label: "Paystack",
977
- mode: "in-cli",
978
- signals: {
979
- python: ["paystackapi"],
980
- envKeys: [/^PAYSTACK_/]
981
- }
982
- },
983
- {
984
- kind: "Orb",
985
- label: "Orb",
986
- mode: "in-cli",
987
- signals: {
988
- npm: ["orb-billing"],
989
- python: ["orb-billing"],
990
- envKeys: [/^ORB_/]
991
- }
992
- },
993
- {
994
- kind: "Lago",
995
- label: "Lago",
996
- mode: "in-cli",
997
- signals: {
998
- npm: ["lago-javascript-client"],
999
- python: ["lago-python-client"],
1000
- envKeys: [/^LAGO_/]
1001
- }
1002
- },
1003
- {
1004
- kind: "Zuora",
1005
- label: "Zuora",
1006
- mode: "in-cli",
1007
- signals: { envKeys: [/^ZUORA_/] }
1008
- },
1009
- {
1010
- kind: "Stigg",
1011
- label: "Stigg",
1012
- mode: "in-cli",
1013
- signals: {
1014
- npm: ["@stigg/node-server-sdk"],
1015
- envKeys: [/^STIGG_/]
1016
- }
1017
- },
1018
- {
1019
- kind: "Ramp",
1020
- label: "Ramp",
1021
- mode: "in-cli",
1022
- signals: { envKeys: [/^RAMP_/] }
1023
- },
1024
- {
1025
- kind: "Brex",
1026
- label: "Brex",
1027
- mode: "in-cli",
1028
- signals: { envKeys: [/^BREX_/] }
1029
- },
1030
- {
1031
- kind: "Tremendous",
1032
- label: "Tremendous",
1033
- mode: "in-cli",
1034
- signals: { envKeys: [/^TREMENDOUS_/] }
1035
- },
1036
- {
1037
- kind: "Maxio",
1038
- label: "Maxio",
1039
- mode: "in-cli",
1040
- signals: { envKeys: [/^MAXIO_/] }
1041
- },
1042
- {
1043
- kind: "Chargify",
1044
- label: "Chargify",
1045
- mode: "in-cli",
1046
- signals: { envKeys: [/^CHARGIFY_/] }
1047
- },
1048
- {
1049
- kind: "Invoiced",
1050
- label: "Invoiced",
1051
- mode: "in-cli",
1052
- signals: {
1053
- npm: ["invoiced"],
1054
- python: ["invoiced"],
1055
- envKeys: [/^INVOICED_/]
1056
- }
1057
- },
1058
- {
1059
- kind: "LemonSqueezy",
1060
- label: "Lemon Squeezy",
1061
- mode: "in-cli",
1062
- signals: {
1063
- npm: ["@lemonsqueezy/lemonsqueezy.js"],
1064
- envKeys: [/^LEMONSQUEEZY_/, /^LEMON_SQUEEZY_/]
1065
- }
1066
- },
1067
- {
1068
- kind: "Razorpay",
1069
- label: "Razorpay",
1070
- mode: "in-cli",
1071
- signals: {
1072
- npm: ["razorpay"],
1073
- python: ["razorpay"],
1074
- ruby: ["razorpay"],
1075
- envKeys: [/^RAZORPAY_/]
1076
- }
1077
- },
1078
- {
1079
- kind: "Adyen",
1080
- label: "Adyen",
1081
- mode: "in-cli",
1082
- signals: {
1083
- npm: ["@adyen/api-library"],
1084
- python: ["adyen"],
1085
- envKeys: [/^ADYEN_/]
1086
- }
1087
- },
1088
- {
1089
- kind: "ChartMogul",
1090
- label: "ChartMogul",
1091
- mode: "in-cli",
1092
- signals: {
1093
- npm: ["chartmogul-node"],
1094
- python: ["chartmogul"],
1095
- envKeys: [/^CHARTMOGUL_/]
1096
- }
1097
- },
1098
- {
1099
- kind: "Airwallex",
1100
- label: "Airwallex",
1101
- mode: "in-cli",
1102
- signals: {
1103
- npm: ["airwallex-payment-elements"],
1104
- envKeys: [/^AIRWALLEX_/]
1105
- }
1106
- },
1107
- {
1108
- kind: "Flutterwave",
1109
- label: "Flutterwave",
1110
- mode: "in-cli",
1111
- signals: {
1112
- npm: ["flutterwave-node-v3"],
1113
- python: ["flutterwave"],
1114
- envKeys: [/^FLUTTERWAVE_/, /^FLW_(PUBLIC|SECRET)_KEY$/]
1115
- }
1116
- },
1117
- {
1118
- kind: "DodoPayments",
1119
- label: "Dodo Payments",
1120
- mode: "in-cli",
1121
- signals: {
1122
- npm: ["dodopayments"],
1123
- python: ["dodopayments"],
1124
- envKeys: [/^DODO_PAYMENTS_/]
1125
- }
1126
- },
1127
- {
1128
- kind: "Whop",
1129
- label: "Whop",
1130
- mode: "in-cli",
1131
- signals: {
1132
- npm: ["@whop/api", "@whop-apps/sdk"],
1133
- envKeys: [/^WHOP_/]
1134
- }
1135
- },
1136
- {
1137
- kind: "SparkPost",
1138
- label: "SparkPost",
1139
- mode: "in-cli",
1140
- signals: {
1141
- npm: ["sparkpost"],
1142
- python: ["sparkpost"],
1143
- envKeys: [/^SPARKPOST_/]
1144
- }
1145
- },
1146
- {
1147
- kind: "MailerSend",
1148
- label: "MailerSend",
1149
- mode: "in-cli",
1150
- signals: {
1151
- npm: ["mailersend"],
1152
- python: ["mailersend"],
1153
- envKeys: [/^MAILERSEND_/]
1154
- }
1155
- },
1156
- {
1157
- kind: "Iterable",
1158
- label: "Iterable",
1159
- mode: "in-cli",
1160
- signals: { envKeys: [/^ITERABLE_/] }
1161
- },
1162
- {
1163
- kind: "ConvertKit",
1164
- label: "ConvertKit",
1165
- mode: "in-cli",
1166
- signals: { envKeys: [/^CONVERTKIT_/] }
1167
- },
1168
- {
1169
- kind: "Drip",
1170
- label: "Drip",
1171
- mode: "in-cli",
1172
- signals: {
1173
- npm: ["drip-nodejs"],
1174
- envKeys: [/^DRIP_/]
1175
- }
1176
- },
1177
- {
1178
- kind: "Omnisend",
1179
- label: "Omnisend",
1180
- mode: "in-cli",
1181
- signals: { envKeys: [/^OMNISEND_/] }
1182
- },
1183
- {
1184
- kind: "EmailOctopus",
1185
- label: "EmailOctopus",
1186
- mode: "in-cli",
1187
- signals: { envKeys: [/^EMAILOCTOPUS_/, /^EMAIL_OCTOPUS_/] }
1188
- },
1189
- {
1190
- kind: "Elasticemail",
1191
- label: "Elastic Email",
1192
- mode: "in-cli",
1193
- signals: { envKeys: [/^ELASTICEMAIL_/, /^ELASTIC_EMAIL_/] }
1194
- },
1195
- {
1196
- kind: "CampaignMonitor",
1197
- label: "Campaign Monitor",
1198
- mode: "in-cli",
1199
- signals: {
1200
- npm: ["createsend-node"],
1201
- envKeys: [/^CAMPAIGN_MONITOR_/, /^CREATESEND_/]
1202
- }
1203
- },
1204
- {
1205
- kind: "Lemlist",
1206
- label: "Lemlist",
1207
- mode: "in-cli",
1208
- signals: { envKeys: [/^LEMLIST_/] }
1209
- },
1210
- {
1211
- kind: "Loops",
1212
- label: "Loops",
1213
- mode: "in-cli",
1214
- signals: {
1215
- npm: ["loops"],
1216
- envKeys: [/^LOOPS_/]
1217
- }
1218
- },
1219
- {
1220
- kind: "Knock",
1221
- label: "Knock",
1222
- mode: "in-cli",
1223
- signals: {
1224
- npm: ["@knocklabs/node", "@knocklabs/client"],
1225
- python: ["knockapi"],
1226
- envKeys: [/^KNOCK_/]
1227
- }
1228
- },
1229
- {
1230
- kind: "AwsSes",
1231
- label: "Amazon SES",
1232
- mode: "in-cli",
1233
- signals: {
1234
- npm: ["@aws-sdk/client-ses", "@aws-sdk/client-sesv2"],
1235
- envKeys: [/^AWS_SES_/]
1236
- }
1237
- },
1238
- {
1239
- kind: "Beehiiv",
1240
- label: "beehiiv",
1241
- mode: "in-cli",
1242
- signals: { envKeys: [/^BEEHIIV_/] }
1243
- },
1244
- {
1245
- kind: "Mailtrap",
1246
- label: "Mailtrap",
1247
- mode: "in-cli",
1248
- signals: {
1249
- npm: ["mailtrap"],
1250
- python: ["mailtrap"],
1251
- envKeys: [/^MAILTRAP_/]
1252
- }
1253
- },
1254
- {
1255
- kind: "Plunk",
1256
- label: "Plunk",
1257
- mode: "in-cli",
1258
- signals: {
1259
- npm: ["@plunk/node"],
1260
- envKeys: [/^PLUNK_/]
1261
- }
1262
- },
1263
- {
1264
- kind: "Ortto",
1265
- label: "Ortto",
1266
- mode: "in-cli",
1267
- signals: { envKeys: [/^ORTTO_/] }
1268
- },
1269
- {
1270
- kind: "Postscript",
1271
- label: "Postscript",
1272
- mode: "in-cli",
1273
- signals: { envKeys: [/^POSTSCRIPT_/] }
1274
- },
1275
- {
1276
- kind: "Marketo",
1277
- label: "Marketo",
1278
- mode: "in-cli",
1279
- signals: {
1280
- python: ["marketorestpython"],
1281
- envKeys: [/^MARKETO_/]
1282
- }
1283
- },
1284
- {
1285
- kind: "Lob",
1286
- label: "Lob",
1287
- mode: "in-cli",
1288
- signals: {
1289
- npm: ["lob"],
1290
- python: ["lob"],
1291
- envKeys: [/^LOB_API_KEY$/]
1292
- }
1293
- },
1294
- {
1295
- kind: "Segment",
1296
- label: "Segment",
1297
- mode: "in-cli",
1298
- signals: {
1299
- npm: ["@segment/analytics-node", "analytics-node"],
1300
- python: ["segment-analytics-python", "analytics-python"],
1301
- envKeys: [/^SEGMENT_/]
1302
- }
1303
- },
1304
- {
1305
- kind: "Snowplow",
1306
- label: "Snowplow Analytics",
1307
- mode: "in-cli",
1308
- signals: {
1309
- npm: ["@snowplow/node-tracker"],
1310
- python: ["snowplow-tracker"],
1311
- envKeys: [/^SNOWPLOW_/]
1312
- }
1313
- },
1314
- {
1315
- kind: "Matomo",
1316
- label: "Matomo",
1317
- mode: "in-cli",
1318
- signals: {
1319
- npm: ["matomo-tracker"],
1320
- envKeys: [/^MATOMO_/]
1321
- }
1322
- },
1323
- {
1324
- kind: "Plausible",
1325
- label: "Plausible",
1326
- mode: "in-cli",
1327
- signals: {
1328
- npm: ["plausible-tracker"],
1329
- envKeys: [/^PLAUSIBLE_/]
1330
- }
1331
- },
1332
- {
1333
- kind: "ConfigCat",
1334
- label: "ConfigCat",
1335
- mode: "in-cli",
1336
- signals: {
1337
- npm: ["configcat-node", "configcat-js"],
1338
- python: ["configcat-client"],
1339
- envKeys: [/^CONFIGCAT_/]
1340
- }
1341
- },
1342
- {
1343
- kind: "Flagsmith",
1344
- label: "Flagsmith",
1345
- mode: "in-cli",
1346
- signals: {
1347
- npm: ["flagsmith-nodejs", "flagsmith"],
1348
- python: ["flagsmith"],
1349
- envKeys: [/^FLAGSMITH_/]
1350
- }
1351
- },
1352
- {
1353
- kind: "Unleash",
1354
- label: "Unleash",
1355
- mode: "in-cli",
1356
- signals: {
1357
- npm: ["unleash-client"],
1358
- python: ["unleashclient"],
1359
- envKeys: [/^UNLEASH_/]
1360
- }
1361
- },
1362
- {
1363
- kind: "SplitIo",
1364
- label: "Split.io",
1365
- mode: "in-cli",
1366
- signals: {
1367
- npm: ["@splitsoftware/splitio"],
1368
- python: ["splitio-client"],
1369
- envKeys: [/^SPLITIO_/, /^SPLIT_IO_/]
1370
- }
1371
- },
1372
- {
1373
- kind: "Stytch",
1374
- label: "Stytch",
1375
- mode: "in-cli",
1376
- signals: {
1377
- npm: ["stytch"],
1378
- python: ["stytch"],
1379
- envKeys: [/^STYTCH_/]
1380
- }
1381
- },
1382
- {
1383
- kind: "Doppler",
1384
- label: "Doppler",
1385
- mode: "in-cli",
1386
- signals: {
1387
- npm: ["@dopplerhq/node-sdk"],
1388
- envKeys: [/^DOPPLER_/]
1389
- }
1390
- },
1391
- {
1392
- kind: "Infisical",
1393
- label: "Infisical",
1394
- mode: "in-cli",
1395
- signals: {
1396
- npm: ["@infisical/sdk"],
1397
- python: ["infisicalsdk"],
1398
- envKeys: [/^INFISICAL_/]
1399
- }
1400
- },
1401
- {
1402
- kind: "OnePassword",
1403
- label: "1Password",
1404
- mode: "in-cli",
1405
- signals: {
1406
- npm: ["@1password/sdk"],
1407
- python: ["onepassword-sdk"],
1408
- envKeys: [/^ONEPASSWORD_/, /^OP_SERVICE_ACCOUNT_TOKEN$/]
1409
- }
1410
- },
1411
- {
1412
- kind: "Persona",
1413
- label: "Persona",
1414
- mode: "in-cli",
1415
- signals: { envKeys: [/^PERSONA_/] }
1416
- },
1417
- {
1418
- kind: "Svix",
1419
- label: "Svix",
1420
- mode: "in-cli",
1421
- signals: {
1422
- npm: ["svix"],
1423
- python: ["svix"],
1424
- envKeys: [/^SVIX_/]
1425
- }
1426
- },
1427
- {
1428
- kind: "Mux",
1429
- label: "Mux",
1430
- mode: "in-cli",
1431
- signals: {
1432
- npm: ["@mux/mux-node"],
1433
- python: ["mux-python"],
1434
- envKeys: [/^MUX_/]
1435
- }
1436
- },
1437
- {
1438
- kind: "Vapi",
1439
- label: "Vapi",
1440
- mode: "in-cli",
1441
- signals: {
1442
- npm: ["@vapi-ai/server-sdk"],
1443
- python: ["vapi-server-sdk"],
1444
- envKeys: [/^VAPI_/]
1445
- }
1446
- },
1447
- {
1448
- kind: "Aircall",
1449
- label: "Aircall",
1450
- mode: "in-cli",
1451
- signals: { envKeys: [/^AIRCALL_/] }
1452
- },
1453
- {
1454
- kind: "JustCall",
1455
- label: "JustCall",
1456
- mode: "in-cli",
1457
- signals: { envKeys: [/^JUSTCALL_/] }
1458
- },
1459
- {
1460
- kind: "Telnyx",
1461
- label: "Telnyx",
1462
- mode: "in-cli",
1463
- signals: {
1464
- npm: ["telnyx"],
1465
- python: ["telnyx"],
1466
- envKeys: [/^TELNYX_/]
1467
- }
1468
- },
1469
- {
1470
- kind: "Plivo",
1471
- label: "Plivo",
1472
- mode: "in-cli",
1473
- signals: {
1474
- npm: ["plivo"],
1475
- python: ["plivo"],
1476
- envKeys: [/^PLIVO_/]
1477
- }
1478
- },
1479
- {
1480
- kind: "Courier",
1481
- label: "Courier",
1482
- mode: "in-cli",
1483
- signals: {
1484
- npm: ["@trycourier/courier"],
1485
- python: ["trycourier"],
1486
- envKeys: [/^COURIER_AUTH_TOKEN$/]
1487
- }
1488
- },
1489
- {
1490
- kind: "WooCommerce",
1491
- label: "WooCommerce",
1492
- mode: "in-cli",
1493
- signals: {
1494
- npm: ["@woocommerce/woocommerce-rest-api"],
1495
- python: ["woocommerce"],
1496
- envKeys: [/^WOOCOMMERCE_/]
1497
- }
1498
- },
1499
- {
1500
- kind: "Recharge",
1501
- label: "Recharge",
1502
- mode: "in-cli",
1503
- signals: { envKeys: [/^RECHARGE_/] }
1504
- },
1505
- {
1506
- kind: "Commercetools",
1507
- label: "commercetools",
1508
- mode: "in-cli",
1509
- signals: {
1510
- npm: ["@commercetools/platform-sdk"],
1511
- python: ["commercetools"],
1512
- envKeys: [/^CTP_/, /^COMMERCETOOLS_/]
1513
- }
1514
- },
1515
- {
1516
- kind: "Webflow",
1517
- label: "Webflow",
1518
- mode: "in-cli",
1519
- signals: {
1520
- npm: ["webflow-api"],
1521
- envKeys: [/^WEBFLOW_/]
1522
- }
1523
- },
1524
- {
1525
- kind: "Easypost",
1526
- label: "EasyPost",
1527
- mode: "in-cli",
1528
- signals: {
1529
- npm: ["@easypost/api"],
1530
- python: ["easypost"],
1531
- envKeys: [/^EASYPOST_/]
1532
- }
1533
- },
1534
- {
1535
- kind: "Shippo",
1536
- label: "Shippo",
1537
- mode: "in-cli",
1538
- signals: {
1539
- npm: ["shippo"],
1540
- python: ["shippo"],
1541
- envKeys: [/^SHIPPO_/]
1542
- }
1543
- },
1544
- {
1545
- kind: "ShipStation",
1546
- label: "ShipStation",
1547
- mode: "in-cli",
1548
- signals: { envKeys: [/^SHIPSTATION_/] }
1549
- },
1550
- {
1551
- kind: "Squarespace",
1552
- label: "Squarespace",
1553
- mode: "in-cli",
1554
- signals: { envKeys: [/^SQUARESPACE_/] }
1555
- },
1556
- {
1557
- kind: "Printify",
1558
- label: "Printify",
1559
- mode: "in-cli",
1560
- signals: { envKeys: [/^PRINTIFY_/] }
1561
- },
1562
- {
1563
- kind: "BigCommerce",
1564
- label: "BigCommerce",
1565
- mode: "in-cli",
1566
- signals: {
1567
- npm: ["node-bigcommerce"],
1568
- envKeys: [/^BIGCOMMERCE_/]
1569
- }
1570
- },
1571
- {
1572
- kind: "Freshdesk",
1573
- label: "Freshdesk",
1574
- mode: "in-cli",
1575
- signals: {
1576
- python: ["python-freshdesk"],
1577
- envKeys: [/^FRESHDESK_/]
1578
- }
1579
- },
1580
- {
1581
- kind: "Front",
1582
- label: "Front",
1583
- mode: "in-cli",
1584
- signals: { envKeys: [/^FRONTAPP_/, /^FRONT_API_/] }
1585
- },
1586
- {
1587
- kind: "Gorgias",
1588
- label: "Gorgias",
1589
- mode: "in-cli",
1590
- signals: { envKeys: [/^GORGIAS_/] }
1591
- },
1592
- {
1593
- kind: "Chatwoot",
1594
- label: "Chatwoot",
1595
- mode: "in-cli",
1596
- signals: { envKeys: [/^CHATWOOT_/] }
1597
- },
1598
- {
1599
- kind: "Kustomer",
1600
- label: "Kustomer",
1601
- mode: "in-cli",
1602
- signals: { envKeys: [/^KUSTOMER_/] }
1603
- },
1604
- {
1605
- kind: "Plain",
1606
- label: "Plain",
1607
- mode: "in-cli",
1608
- signals: {
1609
- npm: ["@team-plain/typescript-sdk"],
1610
- envKeys: [/^PLAIN_/]
1611
- }
1612
- },
1613
- {
1614
- kind: "Canny",
1615
- label: "Canny",
1616
- mode: "in-cli",
1617
- signals: { envKeys: [/^CANNY_/] }
1618
- },
1619
- {
1620
- kind: "Pylon",
1621
- label: "Pylon",
1622
- mode: "in-cli",
1623
- signals: { envKeys: [/^PYLON_/] }
1624
- },
1625
- {
1626
- kind: "GitLab",
1627
- label: "GitLab",
1628
- mode: "in-cli",
1629
- signals: {
1630
- npm: ["@gitbeaker/rest"],
1631
- python: ["python-gitlab"],
1632
- ruby: ["gitlab"],
1633
- envKeys: [/^GITLAB_/]
1634
- }
1635
- },
1636
- {
1637
- kind: "Bitbucket",
1638
- label: "Atlassian Bitbucket Cloud",
1639
- mode: "in-cli",
1640
- signals: {
1641
- npm: ["bitbucket"],
1642
- envKeys: [/^BITBUCKET_/]
1643
- }
1644
- },
1645
- {
1646
- kind: "Gitea",
1647
- label: "Gitea",
1648
- mode: "in-cli",
1649
- signals: {
1650
- npm: ["gitea-js"],
1651
- envKeys: [/^GITEA_/]
1652
- }
1653
- },
1654
- {
1655
- kind: "Datadog",
1656
- label: "Datadog",
1657
- mode: "in-cli",
1658
- signals: {
1659
- npm: ["@datadog/datadog-api-client", "dd-trace"],
1660
- python: ["datadog", "datadog-api-client"],
1661
- ruby: ["dogapi"],
1662
- envKeys: [
1663
- /^DATADOG_/,
1664
- /^DD_API_KEY$/,
1665
- /^DD_APP_KEY$/
1666
- ]
1667
- }
1668
- },
1669
- {
1670
- kind: "NewRelic",
1671
- label: "New Relic",
1672
- mode: "in-cli",
1673
- signals: {
1674
- npm: ["newrelic"],
1675
- python: ["newrelic"],
1676
- ruby: ["newrelic_rpm"],
1677
- envKeys: [/^NEW_RELIC_/, /^NEWRELIC_/]
1678
- }
1679
- },
1680
- {
1681
- kind: "Cloudflare",
1682
- label: "Cloudflare",
1683
- mode: "in-cli",
1684
- signals: {
1685
- npm: ["cloudflare"],
1686
- python: ["cloudflare"],
1687
- envKeys: [/^CLOUDFLARE_/, /^CF_API_TOKEN$/]
1688
- }
1689
- },
1690
- {
1691
- kind: "Elasticsearch",
1692
- label: "Elasticsearch",
1693
- mode: "in-cli",
1694
- signals: {
1695
- npm: ["@elastic/elasticsearch"],
1696
- python: ["elasticsearch"],
1697
- ruby: ["elasticsearch"],
1698
- envKeys: [/^ELASTICSEARCH_/]
1699
- }
1700
- },
1701
- {
1702
- kind: "Snyk",
1703
- label: "Snyk",
1704
- mode: "in-cli",
1705
- signals: {
1706
- npm: ["snyk"],
1707
- python: ["pysnyk"],
1708
- envKeys: [/^SNYK_/]
1709
- }
1710
- },
1711
- {
1712
- kind: "PagerDuty",
1713
- label: "PagerDuty",
1714
- mode: "in-cli",
1715
- signals: {
1716
- npm: ["@pagerduty/pdjs"],
1717
- python: ["pdpyras"],
1718
- envKeys: [/^PAGERDUTY_/, /^PD_API_KEY$/]
1719
- }
1720
- },
1721
- {
1722
- kind: "Opsgenie",
1723
- label: "Opsgenie",
1724
- mode: "in-cli",
1725
- signals: { envKeys: [/^OPSGENIE_/] }
1726
- },
1727
- {
1728
- kind: "IncidentIo",
1729
- label: "incident.io",
1730
- mode: "in-cli",
1731
- signals: { envKeys: [/^INCIDENT_IO_/, /^INCIDENTIO_/] }
1732
- },
1733
- {
1734
- kind: "Bugsnag",
1735
- label: "Bugsnag",
1736
- mode: "in-cli",
1737
- signals: {
1738
- npm: ["@bugsnag/js"],
1739
- python: ["bugsnag"],
1740
- ruby: ["bugsnag"],
1741
- envKeys: [/^BUGSNAG_/]
1742
- }
1743
- },
1744
- {
1745
- kind: "Honeybadger",
1746
- label: "Honeybadger",
1747
- mode: "in-cli",
1748
- signals: {
1749
- npm: ["@honeybadger-io/js"],
1750
- python: ["honeybadger"],
1751
- ruby: ["honeybadger"],
1752
- envKeys: [/^HONEYBADGER_/]
1753
- }
1754
- },
1755
- {
1756
- kind: "Raygun",
1757
- label: "Raygun",
1758
- mode: "in-cli",
1759
- signals: {
1760
- npm: ["raygun"],
1761
- python: ["raygun4py"],
1762
- ruby: ["raygun4ruby"],
1763
- envKeys: [/^RAYGUN_/]
1764
- }
1765
- },
1766
- {
1767
- kind: "CircleCI",
1768
- label: "CircleCI",
1769
- mode: "in-cli",
1770
- signals: { envKeys: [/^CIRCLECI_/, /^CIRCLE_TOKEN$/] }
1771
- },
1772
- {
1773
- kind: "Upstash",
1774
- label: "Upstash",
1775
- mode: "in-cli",
1776
- signals: {
1777
- npm: ["@upstash/redis"],
1778
- python: ["upstash-redis"],
1779
- envKeys: [/^UPSTASH_/]
1780
- }
1781
- },
1782
- {
1783
- kind: "Vercel",
1784
- label: "Vercel",
1785
- mode: "in-cli",
1786
- signals: {
1787
- npm: ["@vercel/sdk"],
1788
- envKeys: [/^VERCEL_API_TOKEN$/]
1789
- }
1790
- },
1791
- {
1792
- kind: "Algolia",
1793
- label: "Algolia",
1794
- mode: "in-cli",
1795
- signals: {
1796
- npm: ["algoliasearch"],
1797
- python: ["algoliasearch"],
1798
- ruby: ["algolia"],
1799
- envKeys: [/^ALGOLIA_/]
1800
- }
1801
- },
1802
- {
1803
- kind: "Inngest",
1804
- label: "Inngest",
1805
- mode: "in-cli",
1806
- signals: {
1807
- npm: ["inngest"],
1808
- python: ["inngest"],
1809
- envKeys: [/^INNGEST_/]
1810
- }
1811
- },
1812
- {
1813
- kind: "TriggerDev",
1814
- label: "Trigger.dev",
1815
- mode: "in-cli",
1816
- signals: {
1817
- npm: ["@trigger.dev/sdk"],
1818
- envKeys: [/^TRIGGER_(SECRET_KEY|API_KEY|PROJECT_ID)$/]
1819
- }
1820
- },
1821
- {
1822
- kind: "Ably",
1823
- label: "Ably",
1824
- mode: "in-cli",
1825
- signals: {
1826
- npm: ["ably"],
1827
- python: ["ably"],
1828
- envKeys: [/^ABLY_/]
1829
- }
1830
- },
1831
- {
1832
- kind: "Netlify",
1833
- label: "Netlify",
1834
- mode: "in-cli",
1835
- signals: {
1836
- npm: ["@netlify/functions"],
1837
- envKeys: [/^NETLIFY_/]
1838
- }
1839
- },
1840
- {
1841
- kind: "Railway",
1842
- label: "Railway",
1843
- mode: "in-cli",
1844
- signals: { envKeys: [/^RAILWAY_/] }
1845
- },
1846
- {
1847
- kind: "Render",
1848
- label: "Render",
1849
- mode: "in-cli",
1850
- signals: { envKeys: [/^RENDER_API_KEY$/] }
1851
- },
1852
- {
1853
- kind: "FlyIo",
1854
- label: "Fly.io",
1855
- mode: "in-cli",
1856
- signals: { envKeys: [/^FLY_API_TOKEN$/, /^FLY_APP_NAME$/] }
1857
- },
1858
- {
1859
- kind: "Heroku",
1860
- label: "Heroku",
1861
- mode: "in-cli",
1862
- signals: { envKeys: [/^HEROKU_/] }
1863
- },
1864
- {
1865
- kind: "DigitalOcean",
1866
- label: "DigitalOcean",
1867
- mode: "in-cli",
1868
- signals: { envKeys: [/^DIGITALOCEAN_/] }
1869
- },
1870
- {
1871
- kind: "Grafana",
1872
- label: "Grafana",
1873
- mode: "in-cli",
1874
- signals: {
1875
- python: ["grafana-client"],
1876
- envKeys: [/^GRAFANA_/]
1877
- }
1878
- },
1879
- {
1880
- kind: "BetterStack",
1881
- label: "Better Stack",
1882
- mode: "in-cli",
1883
- signals: {
1884
- npm: ["@logtail/node", "@logtail/js"],
1885
- envKeys: [
1886
- /^BETTERSTACK_/,
1887
- /^BETTER_STACK_/,
1888
- /^LOGTAIL_/
1889
- ]
1890
- }
1891
- },
1892
- {
1893
- kind: "Honeycomb",
1894
- label: "Honeycomb",
1895
- mode: "in-cli",
1896
- signals: {
1897
- npm: ["@honeycombio/opentelemetry-node", "honeycomb-beeline"],
1898
- python: ["honeycomb-beeline", "libhoney"],
1899
- envKeys: [/^HONEYCOMB_/]
1900
- }
1901
- },
1902
- {
1903
- kind: "Descope",
1904
- label: "Descope",
1905
- mode: "in-cli",
1906
- signals: {
1907
- npm: [
1908
- "@descope/node-sdk",
1909
- "@descope/nextjs-sdk",
1910
- "@descope/react-sdk"
1911
- ],
1912
- python: ["descope"],
1913
- envKeys: [/^DESCOPE_/]
1914
- }
1915
- },
1916
- {
1917
- kind: "FusionAuth",
1918
- label: "FusionAuth",
1919
- mode: "in-cli",
1920
- signals: {
1921
- npm: ["@fusionauth/typescript-client"],
1922
- python: ["fusionauth-client"],
1923
- envKeys: [/^FUSIONAUTH_/, /^FUSION_AUTH_/]
1924
- }
1925
- },
1926
- {
1927
- kind: "Hookdeck",
1928
- label: "Hookdeck",
1929
- mode: "in-cli",
1930
- signals: {
1931
- npm: ["@hookdeck/sdk"],
1932
- envKeys: [/^HOOKDECK_/]
1933
- }
1934
- },
1935
- {
1936
- kind: "N8n",
1937
- label: "n8n",
1938
- mode: "in-cli",
1939
- signals: {
1940
- npm: ["n8n"],
1941
- envKeys: [/^N8N_/]
1942
- }
1943
- },
1944
- {
1945
- kind: "Dbt",
1946
- label: "dbt",
1947
- mode: "in-cli",
1948
- signals: {
1949
- python: [
1950
- "dbt-core",
1951
- "dbt-snowflake",
1952
- "dbt-postgres",
1953
- "dbt-bigquery",
1954
- "dbt-redshift",
1955
- "dbt-databricks"
1956
- ],
1957
- envKeys: [/^DBT_/]
1958
- }
1959
- },
1960
- {
1961
- kind: "Fastly",
1962
- label: "Fastly",
1963
- mode: "in-cli",
1964
- signals: {
1965
- npm: ["fastly"],
1966
- python: ["fastly"],
1967
- envKeys: [/^FASTLY_/]
1968
- }
1969
- },
1970
- {
1971
- kind: "Bunny",
1972
- label: "Bunny.net",
1973
- mode: "in-cli",
1974
- signals: { envKeys: [/^BUNNY_/] }
1975
- },
1976
- {
1977
- kind: "Codecov",
1978
- label: "Codecov",
1979
- mode: "in-cli",
1980
- signals: {
1981
- npm: ["codecov"],
1982
- envKeys: [/^CODECOV_/]
1983
- }
1984
- },
1985
- {
1986
- kind: "Sourcegraph",
1987
- label: "Sourcegraph",
1988
- mode: "in-cli",
1989
- signals: { envKeys: [/^SOURCEGRAPH_/, /^SRC_ACCESS_TOKEN$/] }
1990
- },
1991
- {
1992
- kind: "TemporalIO",
1993
- label: "Temporal.io",
1994
- mode: "in-cli",
1995
- signals: {
1996
- npm: ["@temporalio/client", "@temporalio/worker"],
1997
- python: ["temporalio"],
1998
- envKeys: [/^TEMPORAL_/]
1999
- }
2000
- },
2001
- {
2002
- kind: "Hatchet",
2003
- label: "Hatchet",
2004
- mode: "in-cli",
2005
- signals: {
2006
- npm: ["@hatchet-dev/typescript-sdk"],
2007
- python: ["hatchet-sdk"],
2008
- envKeys: [/^HATCHET_/]
2009
- }
2010
- },
2011
- {
2012
- kind: "Pipedrive",
2013
- label: "Pipedrive",
2014
- mode: "in-cli",
2015
- signals: {
2016
- npm: ["pipedrive"],
2017
- envKeys: [/^PIPEDRIVE_/]
2018
- }
2019
- },
2020
- {
2021
- kind: "Close",
2022
- label: "Close",
2023
- mode: "in-cli",
2024
- signals: {
2025
- python: ["closeio"],
2026
- envKeys: [/^CLOSE_API_KEY$/]
2027
- }
2028
- },
2029
- {
2030
- kind: "Copper",
2031
- label: "Copper",
2032
- mode: "in-cli",
2033
- signals: { envKeys: [/^COPPER_/] }
2034
- },
2035
- {
2036
- kind: "Insightly",
2037
- label: "Insightly",
2038
- mode: "in-cli",
2039
- signals: { envKeys: [/^INSIGHTLY_/] }
2040
- },
2041
- {
2042
- kind: "Salesflare",
2043
- label: "Salesflare",
2044
- mode: "in-cli",
2045
- signals: { envKeys: [/^SALESFLARE_/] }
2046
- },
2047
- {
2048
- kind: "SalesLoft",
2049
- label: "Salesloft",
2050
- mode: "in-cli",
2051
- signals: { envKeys: [/^SALESLOFT_/] }
2052
- },
2053
- {
2054
- kind: "Attio",
2055
- label: "Attio",
2056
- mode: "in-cli",
2057
- signals: {
2058
- npm: ["attio"],
2059
- envKeys: [/^ATTIO_/]
2060
- }
2061
- },
2062
- {
2063
- kind: "ActiveCampaign",
2064
- label: "ActiveCampaign",
2065
- mode: "in-cli",
2066
- signals: { envKeys: [/^ACTIVECAMPAIGN_/, /^ACTIVE_CAMPAIGN_/] }
2067
- },
2068
- {
2069
- kind: "Vitally",
2070
- label: "Vitally",
2071
- mode: "in-cli",
2072
- signals: { envKeys: [/^VITALLY_/] }
2073
- },
2074
- {
2075
- kind: "Docusign",
2076
- label: "DocuSign",
2077
- mode: "in-cli",
2078
- signals: {
2079
- npm: ["docusign-esign"],
2080
- python: ["docusign-esign"],
2081
- envKeys: [/^DOCUSIGN_/]
2082
- }
2083
- },
2084
- {
2085
- kind: "PandaDoc",
2086
- label: "PandaDoc",
2087
- mode: "in-cli",
2088
- signals: { envKeys: [/^PANDADOC_/] }
2089
- },
2090
- {
2091
- kind: "Gong",
2092
- label: "Gong",
2093
- mode: "in-cli",
2094
- signals: { envKeys: [/^GONG_/] }
2095
- },
2096
- {
2097
- kind: "Asana",
2098
- label: "Asana",
2099
- mode: "in-cli",
2100
- signals: {
2101
- npm: ["asana"],
2102
- python: ["asana"],
2103
- envKeys: [/^ASANA_/]
2104
- }
2105
- },
2106
- {
2107
- kind: "Trello",
2108
- label: "Trello",
2109
- mode: "in-cli",
2110
- signals: {
2111
- npm: ["trello"],
2112
- envKeys: [/^TRELLO_/]
2113
- }
2114
- },
2115
- {
2116
- kind: "Todoist",
2117
- label: "Todoist",
2118
- mode: "in-cli",
2119
- signals: {
2120
- npm: ["@doist/todoist-api-typescript"],
2121
- python: ["todoist-api-python"],
2122
- envKeys: [/^TODOIST_/]
2123
- }
2124
- },
2125
- {
2126
- kind: "Monday",
2127
- label: "monday.com",
2128
- mode: "in-cli",
2129
- signals: {
2130
- npm: ["@mondaydotcomorg/api"],
2131
- envKeys: [/^MONDAY_/]
2132
- }
2133
- },
2134
- {
2135
- kind: "ClickUp",
2136
- label: "ClickUp",
2137
- mode: "in-cli",
2138
- signals: { envKeys: [/^CLICKUP_/] }
2139
- },
2140
- {
2141
- kind: "Height",
2142
- label: "Height",
2143
- mode: "in-cli",
2144
- signals: { envKeys: [/^HEIGHT_API_KEY$/] }
2145
- },
2146
- {
2147
- kind: "Shortcut",
2148
- label: "Shortcut",
2149
- mode: "in-cli",
2150
- signals: {
2151
- npm: ["@shortcut/client"],
2152
- envKeys: [/^SHORTCUT_/]
2153
- }
2154
- },
2155
- {
2156
- kind: "Jira",
2157
- label: "Jira",
2158
- mode: "in-cli",
2159
- signals: {
2160
- npm: ["jira-client"],
2161
- python: ["jira", "atlassian-python-api"],
2162
- envKeys: [/^JIRA_/]
2163
- }
2164
- },
2165
- {
2166
- kind: "Confluence",
2167
- label: "Confluence",
2168
- mode: "in-cli",
2169
- signals: { envKeys: [/^CONFLUENCE_/] }
2170
- },
2171
- {
2172
- kind: "Airtable",
2173
- label: "Airtable",
2174
- mode: "in-cli",
2175
- signals: {
2176
- npm: ["airtable"],
2177
- python: ["pyairtable"],
2178
- envKeys: [/^AIRTABLE_/]
2179
- }
2180
- },
2181
- {
2182
- kind: "Smartsheet",
2183
- label: "Smartsheet",
2184
- mode: "in-cli",
2185
- signals: {
2186
- npm: ["smartsheet"],
2187
- python: ["smartsheet-python-sdk"],
2188
- envKeys: [/^SMARTSHEET_/]
2189
- }
2190
- },
2191
- {
2192
- kind: "Coda",
2193
- label: "Coda",
2194
- mode: "in-cli",
2195
- signals: { envKeys: [/^CODA_API_/] }
2196
- },
2197
- {
2198
- kind: "Productboard",
2199
- label: "Productboard",
2200
- mode: "in-cli",
2201
- signals: { envKeys: [/^PRODUCTBOARD_/] }
2202
- },
2203
- {
2204
- kind: "GoogleSheets",
2205
- label: "Google Sheets",
2206
- mode: "in-cli",
2207
- signals: {
2208
- npm: ["google-spreadsheet"],
2209
- python: ["gspread"],
2210
- envKeys: [/^GOOGLE_SHEETS_/]
2211
- }
2212
- },
2213
- {
2214
- kind: "Formbricks",
2215
- label: "Formbricks",
2216
- mode: "in-cli",
2217
- signals: {
2218
- npm: ["@formbricks/js"],
2219
- envKeys: [/^FORMBRICKS_/]
2220
- }
2221
- },
2222
- {
2223
- kind: "Tally",
2224
- label: "Tally",
2225
- mode: "in-cli",
2226
- signals: { envKeys: [/^TALLY_API_KEY$/] }
2227
- },
2228
- {
2229
- kind: "Jotform",
2230
- label: "Jotform",
2231
- mode: "in-cli",
2232
- signals: {
2233
- python: ["jotform"],
2234
- envKeys: [/^JOTFORM_/]
2235
- }
2236
- },
2237
- {
2238
- kind: "GitBook",
2239
- label: "GitBook",
2240
- mode: "in-cli",
2241
- signals: {
2242
- npm: ["@gitbook/api"],
2243
- envKeys: [/^GITBOOK_/]
2244
- }
2245
- },
2246
- {
2247
- kind: "Wordpress",
2248
- label: "WordPress",
2249
- mode: "in-cli",
2250
- signals: {
2251
- npm: ["wpapi"],
2252
- envKeys: [/^WORDPRESS_/]
2253
- }
2254
- },
2255
- {
2256
- kind: "Clockify",
2257
- label: "Clockify",
2258
- mode: "in-cli",
2259
- signals: { envKeys: [/^CLOCKIFY_/] }
2260
- },
2261
- {
2262
- kind: "Calendly",
2263
- label: "Calendly",
2264
- mode: "in-cli",
2265
- signals: { envKeys: [/^CALENDLY_/] }
2266
- },
2267
- {
2268
- kind: "CalCom",
2269
- label: "Cal.com",
2270
- mode: "in-cli",
2271
- signals: { envKeys: [/^CALCOM_/, /^CAL_API_KEY$/] }
2272
- },
2273
- {
2274
- kind: "Eventbrite",
2275
- label: "Eventbrite",
2276
- mode: "in-cli",
2277
- signals: {
2278
- python: ["eventbrite"],
2279
- envKeys: [/^EVENTBRITE_/]
2280
- }
2281
- },
2282
- {
2283
- kind: "BambooHR",
2284
- label: "BambooHR",
2285
- mode: "in-cli",
2286
- signals: {
2287
- python: ["pybamboohr"],
2288
- envKeys: [/^BAMBOOHR_/, /^BAMBOO_HR_/]
2289
- }
2290
- },
2291
- {
2292
- kind: "Personio",
2293
- label: "Personio",
2294
- mode: "in-cli",
2295
- signals: { envKeys: [/^PERSONIO_/] }
2296
- },
2297
- {
2298
- kind: "Rippling",
2299
- label: "Rippling",
2300
- mode: "in-cli",
2301
- signals: { envKeys: [/^RIPPLING_/] }
2302
- },
2303
- {
2304
- kind: "Greenhouse",
2305
- label: "Greenhouse",
2306
- mode: "in-cli",
2307
- signals: { envKeys: [/^GREENHOUSE_/] }
2308
- },
2309
- {
2310
- kind: "Ashby",
2311
- label: "Ashby",
2312
- mode: "in-cli",
2313
- signals: { envKeys: [/^ASHBY_/] }
2314
- },
2315
- {
2316
- kind: "Workable",
2317
- label: "Workable",
2318
- mode: "in-cli",
2319
- signals: { envKeys: [/^WORKABLE_/] }
2320
- },
2321
- {
2322
- kind: "GoogleAds",
2323
- label: "Google Ads",
2324
- mode: "deep-link",
2325
- signals: {
2326
- npm: ["google-ads-api"],
2327
- python: ["google-ads"],
2328
- envKeys: [/^GOOGLE_ADS_/]
2329
- }
2330
- },
2331
- {
2332
- kind: "MetaAds",
2333
- label: "Meta Ads",
2334
- mode: "deep-link",
2335
- signals: {
2336
- npm: ["facebook-nodejs-business-sdk"],
2337
- python: ["facebook-business"],
2338
- envKeys: [/^META_ADS_/, /^FACEBOOK_ADS_/]
2339
- }
2340
- },
2341
- {
2342
- kind: "LinkedinAds",
2343
- label: "LinkedIn Ads",
2344
- mode: "deep-link",
2345
- signals: { envKeys: [/^LINKEDIN_ADS_/] }
2346
- },
2347
- {
2348
- kind: "TikTokAds",
2349
- label: "TikTok Ads",
2350
- mode: "deep-link",
2351
- signals: { envKeys: [/^TIKTOK_ADS_/] }
2352
- },
2353
- {
2354
- kind: "RedditAds",
2355
- label: "Reddit Ads",
2356
- mode: "deep-link",
2357
- signals: { envKeys: [/^REDDIT_ADS_/] }
2358
- },
2359
- {
2360
- kind: "PinterestAds",
2361
- label: "Pinterest Ads",
2362
- mode: "deep-link",
2363
- signals: { envKeys: [/^PINTEREST_ADS_/] }
2364
- },
2365
- {
2366
- kind: "BingAds",
2367
- label: "Bing Ads",
2368
- mode: "deep-link",
2369
- signals: {
2370
- python: ["bingads"],
2371
- envKeys: [/^BING_ADS_/, /^MICROSOFT_ADS_/]
2372
- }
2373
- },
2374
- {
2375
- kind: "AmazonAds",
2376
- label: "Amazon Ads",
2377
- mode: "deep-link",
2378
- signals: { envKeys: [/^AMAZON_ADS_/] }
2379
- },
2380
- {
2381
- kind: "GoogleAnalytics",
2382
- label: "Google Analytics",
2383
- mode: "deep-link",
2384
- signals: {
2385
- npm: ["react-ga4"],
2386
- python: ["google-analytics-data"],
2387
- envKeys: [/^GOOGLE_ANALYTICS_/, /^GA4_/]
2388
- }
2389
- },
2390
- {
2391
- kind: "GoogleSearchConsole",
2392
- label: "Google Search Console",
2393
- mode: "deep-link",
2394
- signals: { envKeys: [/^SEARCH_CONSOLE_/, /^GSC_/] }
2395
- },
2396
- {
2397
- kind: "AppsFlyer",
2398
- label: "AppsFlyer",
2399
- mode: "in-cli",
2400
- signals: {
2401
- npm: ["react-native-appsflyer"],
2402
- envKeys: [/^APPSFLYER_/]
2403
- }
2404
- },
2405
- {
2406
- kind: "Dub",
2407
- label: "Dub",
2408
- mode: "in-cli",
2409
- signals: {
2410
- npm: ["dub"],
2411
- python: ["dub"],
2412
- envKeys: [/^DUB_API_KEY$/]
2413
- }
2414
- }
2415
- ];
2416
- const SOURCE_DETECTORS = [
2417
- ...CORE_SOURCE_DETECTORS,
2418
- ...LLM_SOURCE_DETECTORS,
2419
- ...OTHER_SOURCE_DETECTORS
2420
- ];
2421
- /** Kinds from the LLM / AI section above — the only ones that may set `wizard_ai_sdk_detected`. */
2422
- const AI_SOURCE_KINDS = new Set(LLM_SOURCE_DETECTORS.map((detector) => detector.kind));
2423
- //#endregion
2424
- //#region src/programs/detection/ai-sdk-stamp.ts
2425
- function hasAiSdkEvidence(evidence) {
2426
- return evidence.warehouseSources.some((s) => AI_SOURCE_KINDS.has(s.kind)) || evidence.discoveredFeatures.includes("llm");
2427
- }
2428
- /**
2429
- * Boolean only, on the org, never the list of kinds or any non-AI tool: a
2430
- * decline must not leak even the shape of what local detection saw.
2431
- */
2432
- function stampAiSdkDetected(evidence) {
2433
- if (!evidence.mayReportScanResults) return;
2434
- const organizationId = evidence.apiUser?.organization?.id;
2435
- if (!organizationId) return;
2436
- if (!hasAiSdkEvidence(evidence)) return;
2437
- analytics.groupIdentify("organization", organizationId, { wizard_ai_sdk_detected: true });
2438
- }
2439
- //#endregion
2440
- //#region src/programs/program-store.ts
2441
- const MAX_DIAGNOSTICS = 10;
2442
- var ProgramStore = class {
2443
- runs = [];
2444
- diagnostics = [];
2445
- data;
2446
- onData;
2447
- constructor(options = {}) {
2448
- this.onData = options.onData;
2449
- this.data = {
2450
- credentials: null,
2451
- apiProject: null,
2452
- apiUser: null,
2453
- detection: { frameworkContext: {} },
2454
- binding: null,
2455
- aiSdkStampReported: options.aiSdkStampReported ?? false
2456
- };
2457
- }
2458
- readData() {
2459
- return structuredClone(this.data);
2460
- }
2461
- setAuthenticated(auth) {
2462
- Object.assign(this.data, structuredClone(auth));
2463
- this.emitData();
2464
- }
2465
- setFrameworkContext(key, value) {
2466
- this.data.detection.frameworkContext[key] = structuredClone(value);
2467
- this.emitData();
2468
- }
2469
- setBinding(binding) {
2470
- this.data.binding = structuredClone(binding);
2471
- this.emitData();
2472
- }
2473
- setAiSdkStampReported() {
2474
- if (this.data.aiSdkStampReported) return;
2475
- this.data.aiSdkStampReported = true;
2476
- this.emitData();
2477
- }
2478
- beginRun(runId, observer) {
2479
- const run = { runId };
2480
- this.runs.push(run);
2481
- return {
2482
- onProgress: (event) => {
2483
- const source = {
2484
- runId: run.runId,
2485
- eventKind: event.kind
2486
- };
2487
- if (run.result) {
2488
- this.recordDiagnostic(source, "progress after finish");
2489
- return;
2490
- }
2491
- if (!observer) return;
2492
- this.deliver(source, () => observer({
2493
- kind: "run",
2494
- runId,
2495
- event: structuredClone(event)
2496
- }));
2497
- },
2498
- finish: (result) => {
2499
- run.result = result;
2500
- }
2501
- };
2502
- }
2503
- settledRuns() {
2504
- return this.runs.flatMap(({ runId, result }) => result ? [{
2505
- runId,
2506
- result
2507
- }] : []);
2508
- }
2509
- readDiagnostics() {
2510
- return this.diagnostics.map((diagnostic) => ({ ...diagnostic }));
2511
- }
2512
- emitData() {
2513
- const onData = this.onData;
2514
- if (!onData) return;
2515
- this.deliver({ eventKind: "data" }, () => onData({
2516
- kind: "program",
2517
- data: this.readData()
2518
- }));
2519
- }
2520
- /** Never waits for an observer; a throw or a rejection becomes a diagnostic. */
2521
- deliver(source, send) {
2522
- try {
2523
- const delivery = send();
2524
- if (delivery && typeof delivery.then === "function") Promise.resolve(delivery).catch((error) => {
2525
- this.recordDiagnostic(source, error);
2526
- });
2527
- } catch (error) {
2528
- this.recordDiagnostic(source, error);
2529
- }
2530
- }
2531
- recordDiagnostic(source, error) {
2532
- this.diagnostics.push({
2533
- ...source,
2534
- message: error instanceof Error ? error.message : String(error)
2535
- });
2536
- if (this.diagnostics.length > MAX_DIAGNOSTICS) this.diagnostics.shift();
2537
- }
2538
- };
2539
- //#endregion
2540
- //#region src/programs/run-program.ts
2541
- /** A caller-owned program invocation. No TUI store or session is required. */
2542
- /** Handed to the caller's capabilities when it supplied no signal. */
2543
- const NEVER_ABORTED = new AbortController().signal;
2544
- const DEFAULT_FLAGS = {
2545
- ci: false,
2546
- signup: false,
2547
- debug: false,
2548
- e2eAsk: false,
2549
- localMcp: false,
2550
- captureAio: false,
2551
- benchmark: false,
2552
- yaraReport: false
2553
- };
2554
- /** Fields that carry functions or class instances; everything else is data. */
2555
- const KEPT_BY_REFERENCE = [
2556
- "credentials",
2557
- "run",
2558
- "program",
2559
- "hooks",
2560
- "seedTasks"
2561
- ];
2562
- /** Copy the caller's input, so a later caller write cannot reach the run or its hooks. */
2563
- function snapshotProgramInput(input) {
2564
- const data = { ...input };
2565
- for (const key of KEPT_BY_REFERENCE) delete data[key];
2566
- return {
2567
- ...input,
2568
- ...structuredClone(data)
2569
- };
2570
- }
2571
- /** Run an existing program from explicit inputs, with invocation-owned state. */
2572
- async function runProgram(programId, callerInput, options = {}) {
2573
- const input = snapshotProgramInput(callerInput);
2574
- const store = new ProgramStore({
2575
- aiSdkStampReported: input.aiSdkStampReported,
2576
- onData: options.onProgress
2577
- });
2578
- const { installDir, run } = input;
2579
- const program = input.program ?? {};
2580
- const artifacts = {};
2581
- const runId = input.runId ?? randomUUID();
2582
- const signal = options.signal ?? NEVER_ABORTED;
2583
- const settle = (outcome, failure) => ({
2584
- programId,
2585
- outcome,
2586
- data: store.readData(),
2587
- settledRuns: store.settledRuns(),
2588
- diagnostics: store.readDiagnostics(),
2589
- artifacts,
2590
- ...failure && { failure }
2591
- });
2592
- const fail = (message) => settle("failed", {
2593
- code: ErrorCodes.InternalUnhandled,
2594
- message
2595
- });
2596
- const abort = (message) => settle("aborted", {
2597
- code: ErrorCodes.AgentAbort,
2598
- message
2599
- });
2600
- const cancelled = () => abort("Run cancelled by the caller.");
2601
- if (signal.aborted) return cancelled();
2602
- analytics.wizardCapture("agent started", {
2603
- integration: run.integrationLabel,
2604
- program_id: programId,
2605
- skill_id: run.skillId ?? null
2606
- });
2607
- /** Await a caller capability; a caller abort during the wait wins over its answer. */
2608
- const park = async (work) => {
2609
- const value = await work;
2610
- signal.throwIfAborted();
2611
- return value;
2612
- };
2613
- let credentials = input.credentials;
2614
- const flags = {
2615
- ...DEFAULT_FLAGS,
2616
- ...input.flags
2617
- };
2618
- let flagSnapshot = {
2619
- flags: { ...input.wizardFlags },
2620
- payloads: { ...input.wizardFlagPayloads }
2621
- };
2622
- try {
2623
- if (!credentials && options.credentials) credentials = await park(options.credentials.resolve(programId, { signal }));
2624
- if (!credentials) return fail(`Credentials are required to run ${programId}.`);
2625
- store.setAuthenticated({
2626
- credentials: credentials.posthog,
2627
- apiProject: credentials.project,
2628
- apiUser: credentials.apiUser
2629
- });
2630
- if (credentials.apiUser) analytics.identifyUser(credentials.apiUser);
2631
- analytics.setGroups(groupsFromUser(credentials.apiUser, credentials.posthog.host.apiHost));
2632
- if (!store.readData().aiSdkStampReported) {
2633
- store.setAiSdkStampReported();
2634
- stampAiSdkDetected({
2635
- apiUser: credentials.apiUser,
2636
- discoveredFeatures: input.discoveredFeatures ?? [],
2637
- warehouseSources: input.warehouseSources ?? [],
2638
- mayReportScanResults: input.mayReportScanResults ?? false
2639
- });
2640
- }
2641
- if (program.requiresAi !== false && !flags.ci && !flags.signup && credentials.apiUser?.organization?.is_ai_data_processing_approved !== true) {
2642
- if (!options.awaitAiApproval) return fail("AI processing approval is required before this program can run.");
2643
- if (!await park(options.awaitAiApproval({
2644
- programId,
2645
- signal
2646
- }))) return abort("AI processing approval declined.");
2647
- }
2648
- const gates = program.postAuthGates ?? [];
2649
- if (gates.length > 0 && options.awaitPostAuthGates) await park(options.awaitPostAuthGates({
2650
- programId,
2651
- gates,
2652
- signal
2653
- }));
2654
- if (!input.wizardFlags && options.featureFlags) flagSnapshot = await park(options.featureFlags());
2655
- const login = credentials;
2656
- configureOAuthSession(login.posthog, {
2657
- rotate: (held) => rotateCredentials(held, input.host?.baseUrl),
2658
- onRefreshed: (refreshed) => store.setAuthenticated({
2659
- credentials: refreshed,
2660
- apiProject: login.project,
2661
- apiUser: login.apiUser
2662
- })
2663
- });
2664
- const posthog = await oauthCredentials() ?? login.posthog;
2665
- credentials = {
2666
- ...login,
2667
- posthog
2668
- };
2669
- signal.throwIfAborted();
2670
- } catch (error) {
2671
- if (signal.aborted) return cancelled();
2672
- return fail(error instanceof Error ? error.message : String(error));
2673
- }
2674
- const wizardFlags = { ...flagSnapshot.flags };
2675
- const wizardFlagPayloads = { ...flagSnapshot.payloads };
2676
- const switchboard = {
2677
- program: programId,
2678
- composed: input.composed ?? false,
2679
- flags: wizardFlags,
2680
- flagPayloads: wizardFlagPayloads,
2681
- cliHarness: input.overrides?.harness,
2682
- cliSequence: input.overrides?.sequence,
2683
- cliModel: input.overrides?.model
2684
- };
2685
- const binding = resolveBinding(switchboard);
2686
- analytics.setTag("sequence", binding.sequence);
2687
- analytics.setTag("harness", binding.harness);
2688
- captureSwitchboardDecision(switchboard, binding);
2689
- store.setBinding(binding);
2690
- const wizardMetadata = {
2691
- ...buildRunTags({
2692
- programId,
2693
- integration: run.integrationLabel,
2694
- runId: analytics.runId,
2695
- build: analytics.build,
2696
- skillId: run.skillId
2697
- }),
2698
- SEQUENCE: binding.sequence,
2699
- HARNESS: binding.harness
2700
- };
2701
- artifacts.reportFile = path.resolve(installDir, run.reportFile);
2702
- const adapter = store.beginRun(runId, options.onProgress);
2703
- const result = await runAgent({
2704
- programId,
2705
- run,
2706
- composed: input.composed ?? false,
2707
- binding,
2708
- switchboard,
2709
- skillsBaseUrl: getSkillsBaseUrl(),
2710
- wizardFlags,
2711
- wizardFlagPayloads,
2712
- wizardMetadata,
2713
- allowedTools: program.allowedTools,
2714
- disallowedTools: program.disallowedTools,
2715
- agentFlow: program.agentFlow,
2716
- excludedTaskTypes: program.excludedTaskTypes,
2717
- seedTasks: input.seedTasks,
2718
- hooks: input.hooks
2719
- }, {
2720
- installDir,
2721
- credentials: credentials.posthog,
2722
- project: credentials.project,
2723
- apiUser: credentials.apiUser,
2724
- skillId: input.skillId ?? run.skillId ?? run.integrationLabel,
2725
- integration: input.integration,
2726
- frameworkDocsUrl: input.frameworkDocsUrl,
2727
- flags,
2728
- host: { ...input.host }
2729
- }, {
2730
- interaction: options.interaction,
2731
- onProgress: (event) => adapter.onProgress(event),
2732
- signal: options.signal
2733
- });
2734
- adapter.finish(result);
2735
- return settle(result.outcome, result.outcome === "success" ? void 0 : result.failure);
2736
- }
2737
- //#endregion
2738
- //#region src/programs/session/interaction.ts
2739
- /**
2740
- * Dismiss one open request on abort; a settled one leaves the UI alone. A
2741
- * throw inside an abort listener reaches no caller: Node rethrows it as an
2742
- * uncaught exception, so a broken overlay is logged here instead.
2743
- */
2744
- function dismissOnAbort(open, signal, dismiss) {
2745
- const onAbort = () => {
2746
- try {
2747
- dismiss();
2748
- } catch (error) {
2749
- logToFile("[agent-progress] dismissing an aborted request failed", error);
2750
- }
2751
- };
2752
- if (signal.aborted) onAbort();
2753
- else signal.addEventListener("abort", onAbort, { once: true });
2754
- return open.finally(() => signal.removeEventListener("abort", onAbort));
2755
- }
2756
- //#endregion
2757
- //#region src/ui/agent-progress.ts
2758
- /**
2759
- * The inverse of the agent's former `getUI()` calls: one event, one
2760
- * `WizardUI` method, synchronous, in emission order. Because each case maps
2761
- * back to exactly the call the agent used to make, the frame and flow goldens
2762
- * hold without regeneration.
2763
- */
2764
- function createUiReducer(ui) {
2765
- let spinner;
2766
- return (event) => {
2767
- switch (event.kind) {
2768
- case "lifecycle":
2769
- if (event.phase === "started") ui.startRun();
2770
- else ui.outro(event.message);
2771
- break;
2772
- case "spinner":
2773
- (spinner ??= ui.spinner())[event.action](event.message);
2774
- break;
2775
- case "log":
2776
- ui.log[event.level](event.message);
2777
- break;
2778
- case "status":
2779
- ui.pushStatus(event.message);
2780
- break;
2781
- case "tasks":
2782
- ui.syncTodos(event.tasks);
2783
- break;
2784
- case "stage":
2785
- ui.setStage(event.stage);
2786
- break;
2787
- case "url":
2788
- if (event.which === "dashboard") ui.setDashboardUrl(event.url);
2789
- else ui.setNotebookUrl(event.url);
2790
- break;
2791
- case "usage":
2792
- ui.addTokenUsage(event.delta);
2793
- break;
2794
- case "finalCost":
2795
- ui.setFinalTokenCostUsd(event.usd);
2796
- break;
2797
- case "authError":
2798
- ui.showAuthError(event.detail);
2799
- break;
2800
- case "handoff":
2801
- ui.setHandoffText(event.text);
2802
- break;
2803
- case "completion":
2804
- ui.setOutroData(event.outro);
2805
- break;
2806
- case "activity": break;
2807
- default: throw new Error(`Unhandled agent progress: ${JSON.stringify(event)}`);
2808
- }
2809
- };
2810
- }
2811
- /** The agent's questions, answered wherever `getUI()` answers them today. */
2812
- function uiInteraction(ui) {
2813
- return {
2814
- ask: (question, { signal, onAnswer }) => dismissOnAbort(ui.requestQuestion(question, onAnswer), signal, () => ui.cancelPendingQuestion()),
2815
- taskNotice: (notice, { signal }) => dismissOnAbort(ui.showTaskNotice(notice), signal, () => ui.cancelTaskNotice())
2816
- };
2817
- }
2818
- //#endregion
2819
- //#region src/programs/program-step.ts
2820
- /**
2821
- * The gated steps the agent runner awaits after `auth` and before `run`, in
2822
- * step order. Empty when a program has no auth step or runs before it.
2823
- */
2824
- function postAuthGateSteps(steps) {
2825
- const authIndex = steps.findIndex((s) => s.screenId === "auth");
2826
- const runIndex = steps.findIndex((s) => s.screenId === "run");
2827
- if (authIndex === -1 || runIndex <= authIndex) return [];
2828
- return steps.slice(authIndex + 1, runIndex).filter((s) => s.gate);
2829
- }
2830
- //#endregion
2831
- //#region src/programs/authenticate.ts
2832
- async function authenticate(session, programId) {
2833
- if (session.credentials) return;
2834
- logToFile("[agent-runner] starting OAuth");
2835
- const { projectApiKey, host, accessToken, refreshToken, expiresAt, oauthClientId, projectId, roleAtOrganization, user, project, missingScopes } = await getOrAskForProjectData({
2836
- signup: session.signup,
2837
- ci: session.ci,
2838
- apiKey: session.apiKey,
2839
- projectId: session.projectId,
2840
- email: session.email,
2841
- region: session.region,
2842
- baseUrl: session.baseUrl,
2843
- localMcp: session.localMcp,
2844
- programId
2845
- });
2846
- session.credentials = {
2847
- accessToken,
2848
- refreshToken,
2849
- expiresAt,
2850
- oauthClientId,
2851
- projectApiKey,
2852
- host,
2853
- projectId,
2854
- missingScopes
2855
- };
2856
- session.apiProject = project;
2857
- session.roleAtOrganization = roleAtOrganization;
2858
- session.apiUser = user;
2859
- getUI().setCredentials(session.credentials);
2860
- getUI().setRoleAtOrganization(roleAtOrganization);
2861
- getUI().setApiUser(user);
2862
- if (user) analytics.identifyUser(user);
2863
- analytics.setGroups(groupsFromUser(user, host.apiHost));
2864
- }
2865
- //#endregion
2866
- //#region src/programs/session/audit-checks.ts
2867
- const AUDIT_CHECKS_KEY = "auditChecks";
2868
- function getAuditChecks(session) {
2869
- const raw = session.frameworkContext[AUDIT_CHECKS_KEY];
2870
- return Array.isArray(raw) ? raw : [];
2871
- }
2872
- //#endregion
2873
- //#region src/programs/audit/ledger-watcher.ts
2874
- /**
2875
- * Mirrors the agent's `.posthog-audit-checks.json` into the session, so the TUI
2876
- * screens and the task stream read one value. `runProgramAgent` owns the
2877
- * lifecycle and removes the file at run end, so every path gets it — including
2878
- * the e2e host, which builds no task stream.
2879
- */
2880
- const MAX_LEDGER_FILE_BYTES = 256 * 1024;
2881
- function startAuditLedgerWatcher(installDir, file, options = {}) {
2882
- const target = path.join(installDir, file);
2883
- logToFile(`[audit-ledger] watching ${target}`);
2884
- return startFileWatcher(target, (parsed) => getUI().setFrameworkContext(AUDIT_CHECKS_KEY, coerceAuditChecks(parsed)), {
2885
- ignoreInitialFile: true,
2886
- maxFileSizeBytes: MAX_LEDGER_FILE_BYTES,
2887
- ...options
2888
- });
2889
- }
2890
- /** The program declared the ledger, so it removes it, agent `rm` step or not. */
2891
- function removeAuditLedger(installDir, file) {
2892
- const target = path.join(installDir, file);
2893
- try {
2894
- fs.rmSync(target, { force: true });
2895
- } catch (error) {
2896
- logToFile(`[audit-ledger] could not remove ${target}: ${String(error)}`);
2897
- }
2898
- }
2899
- //#endregion
2900
- //#region src/programs/detection/features.ts
2901
- /**
2902
- * Feature discovery — scan project dependencies for known SDK patterns
2903
- * that indicate additional PostHog programs are relevant.
2904
- *
2905
- * Pure function: takes an install dir, returns a set of discovered features.
2906
- * No store mutations, no UI calls.
2907
- */
2908
- const STRIPE_PACKAGES = new Set(["stripe", "@stripe/stripe-js"]);
2909
- const LLM_PACKAGES = new Set([
2910
- "openai",
2911
- "@anthropic-ai/sdk",
2912
- "ai",
2913
- "@ai-sdk/openai",
2914
- "langchain",
2915
- "@langchain/openai",
2916
- "@langchain/langgraph",
2917
- "@google/generative-ai",
2918
- "@google/genai",
2919
- "@instructor-ai/instructor",
2920
- "@mastra/core",
2921
- "portkey-ai"
2922
- ]);
2923
- const PYTHON_LLM_PACKAGES = new Set([
2924
- "openai",
2925
- "anthropic",
2926
- "langchain",
2927
- "langchain-openai",
2928
- "langchain-anthropic",
2929
- "langchain-google-genai",
2930
- "langgraph",
2931
- "litellm",
2932
- "llama-index",
2933
- "pydantic-ai",
2934
- "crewai",
2935
- "instructor",
2936
- "dspy-ai",
2937
- "mistralai",
2938
- "cohere",
2939
- "google-generativeai",
2940
- "google-genai",
2941
- "portkey-ai"
2942
- ]);
2943
- function discoverFeatures(installDir) {
2944
- const features = [];
2945
- discoverNodeFeatures(installDir, features);
2946
- discoverPythonFeatures(installDir, features);
2947
- return features;
2948
- }
2949
- function discoverNodeFeatures(installDir, features) {
2950
- const packageJsonText = safeRead(installDir, "package.json");
2951
- if (!packageJsonText) return;
2952
- let packageJson;
2953
- try {
2954
- packageJson = JSON.parse(packageJsonText);
2955
- } catch {
2956
- return;
2957
- }
2958
- const depNames = Object.keys({
2959
- ...packageJson.dependencies,
2960
- ...packageJson.devDependencies
2961
- });
2962
- if (depNames.some((depName) => STRIPE_PACKAGES.has(depName))) features.push("stripe");
2963
- if (depNames.some((depName) => LLM_PACKAGES.has(depName))) features.push("llm");
2964
- }
2965
- function discoverPythonFeatures(installDir, features) {
2966
- if (features.includes("llm")) return;
2967
- const depNames = [];
2968
- const requirementsTxt = safeRead(installDir, "requirements.txt");
2969
- if (requirementsTxt) depNames.push(...parseRequirementsTxt(requirementsTxt));
2970
- const pyprojectToml = safeRead(installDir, "pyproject.toml");
2971
- if (pyprojectToml) depNames.push(...parsePyprojectToml(pyprojectToml));
2972
- const pipfile = safeRead(installDir, "Pipfile");
2973
- if (pipfile) depNames.push(...parsePipfile(pipfile));
2974
- if (depNames.some((depName) => PYTHON_LLM_PACKAGES.has(depName))) features.push("llm");
2975
- }
2976
- function safeRead(installDir, file) {
2977
- return readProjectFile(join(installDir, file));
2978
- }
2979
- function normalizePyName(name) {
2980
- return name.toLowerCase().replace(/_/g, "-");
2981
- }
2982
- function parseRequirementsTxt(content) {
2983
- return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("-")).map((line) => line.replace(/\[[^\]]*\]/, "")).map((line) => line.split(/[<>=!~;\s]/)[0]).filter(Boolean).map(normalizePyName);
2984
- }
2985
- function parsePyprojectToml(content) {
2986
- const depNames = [];
2987
- for (const arrayMatch of content.matchAll(/dependencies\s*=\s*\[([^\]]*)\]/g)) {
2988
- const arrayBody = arrayMatch[1];
2989
- for (const quotedMatch of arrayBody.matchAll(/["']([^"']+)["']/g)) {
2990
- const name = quotedMatch[1].replace(/\[[^\]]*\]/, "").split(/[<>=!~;\s]/)[0];
2991
- if (name) depNames.push(normalizePyName(name));
2992
- }
2993
- }
2994
- for (const sectionMatch of content.matchAll(/\[tool\.poetry\.(?:dev-dependencies|dependencies|group\.[^.\]]+\.dependencies)\]([\s\S]*?)(?=\n\[|$)/g)) {
2995
- const sectionBody = sectionMatch[1];
2996
- depNames.push(...extractTomlSectionKeys(sectionBody, { skip: ["python"] }));
2997
- }
2998
- return depNames;
2999
- }
3000
- function parsePipfile(content) {
3001
- const depNames = [];
3002
- for (const sectionMatch of content.matchAll(/\[(packages|dev-packages)\]([\s\S]*?)(?=\n\[|$)/g)) {
3003
- const sectionBody = sectionMatch[2];
3004
- depNames.push(...extractTomlSectionKeys(sectionBody));
3005
- }
3006
- return depNames;
3007
- }
3008
- function extractTomlSectionKeys(sectionBody, opts = {}) {
3009
- const skipNames = new Set(opts.skip ?? []);
3010
- const depNames = [];
3011
- for (const line of sectionBody.split("\n")) {
3012
- const trimmed = line.trim();
3013
- if (!trimmed || trimmed.startsWith("#")) continue;
3014
- const equalsIndex = trimmed.indexOf("=");
3015
- if (equalsIndex <= 0) continue;
3016
- const name = trimmed.slice(0, equalsIndex).trim();
3017
- if (!/^[a-zA-Z0-9._-]+$/.test(name)) continue;
3018
- if (skipNames.has(name.toLowerCase())) continue;
3019
- depNames.push(normalizePyName(name));
3020
- }
3021
- return depNames;
3022
- }
3023
- //#endregion
3024
- //#region src/programs/warehouse-sources/detect.ts
3025
- /**
3026
- * Data warehouse source detection.
3027
- *
3028
- * Scans a project for codebase signals (npm/python/ruby deps, `.env` key
3029
- * names) and matches them against the `SOURCE_DETECTORS` registry. Pure
3030
- * function: no store mutations, no UI calls. Reads files locally — only the
3031
- * wizard process does this; the agent never sees secret values.
3032
- *
3033
- * Note we only read `.env` KEY NAMES, never values.
3034
- */
3035
- const MAX_DEPTH = 3;
3036
- const MAX_SIGNAL_SET = MAX_ENV_KEY_SET;
3037
- function addCapped(set, value) {
3038
- if (set.size < MAX_SIGNAL_SET) set.add(value);
3039
- }
3040
- /**
3041
- * Detect which warehouse sources the project at `installDir` appears to use.
3042
- * Returns one `DetectedSource` per matched registry entry (kinds are unique,
3043
- * so the result is naturally deduped), minus the entries a more specific
3044
- * match supersedes.
3045
- */
3046
- function detectWarehouseSources(installDir) {
3047
- const signals = collectSignals(installDir);
3048
- const matched = [];
3049
- for (const detector of SOURCE_DETECTORS) {
3050
- const signal = matchDetector(detector, signals);
3051
- if (signal) matched.push({
3052
- detector,
3053
- signal
3054
- });
3055
- }
3056
- const kinds = new Set(matched.map((m) => m.detector.kind));
3057
- return matched.filter(({ detector }) => !isSuperseded(detector, kinds)).map(({ detector, signal }) => ({
3058
- kind: detector.kind,
3059
- label: detector.label,
3060
- mode: detector.mode,
3061
- matchedSignal: signal
3062
- }));
3063
- }
3064
- /**
3065
- * Whether a more specific match covers this detector's data. Every consumer
3066
- * treats a detected kind as a source to create, so a project whose Postgres
3067
- * lives on Neon or Supabase would otherwise be offered both and end up with
3068
- * the same tables imported twice.
3069
- */
3070
- function isSuperseded(detector, detectedKinds) {
3071
- return (detector.supersededBy ?? []).some((kind) => detectedKinds.has(kind));
3072
- }
3073
- /** Returns a human-readable description of the first matching signal, or null. */
3074
- function matchDetector(detector, signals) {
3075
- const { npm, python, ruby, envKeys } = detector.signals;
3076
- const npmHit = npm?.find((dep) => signals.npm.has(dep));
3077
- if (npmHit) return `found \`${npmHit}\` in package.json`;
3078
- const pyHit = python?.find((dep) => signals.python.has(dep));
3079
- if (pyHit) return `found \`${pyHit}\` in Python dependencies`;
3080
- const rubyHit = ruby?.find((gem) => signals.ruby.has(gem));
3081
- if (rubyHit) return `found \`${rubyHit}\` in Gemfile`;
3082
- if (envKeys) {
3083
- for (const [key, file] of signals.envKeys) if (envKeys.some((re) => re.test(key))) return `found \`${key}\` in \`${file}\``;
3084
- }
3085
- return null;
3086
- }
3087
- function collectSignals(installDir) {
3088
- const signals = {
3089
- npm: /* @__PURE__ */ new Set(),
3090
- python: /* @__PURE__ */ new Set(),
3091
- ruby: /* @__PURE__ */ new Set(),
3092
- envKeys: /* @__PURE__ */ new Map()
3093
- };
3094
- walkProjectFiles(installDir, (name, fullPath) => ingestFile(installDir, name, fullPath, signals), MAX_DEPTH);
3095
- return signals;
3096
- }
3097
- /**
3098
- * Route a file to the right parser BY NAME, reading its contents only when the
3099
- * name matches one of the ~6 manifests we care about. Checking the name first
3100
- * avoids slurping every file in the tree (lockfiles, binaries, assets) into
3101
- * memory just to discard it.
3102
- */
3103
- function ingestFile(installDir, name, fullPath, signals) {
3104
- const ingest = ingestorFor(name);
3105
- if (!ingest) return;
3106
- const content = safeReadFile(fullPath);
3107
- if (content === null) return;
3108
- ingest(content, signals, toPromptSafeRelativePath(installDir, fullPath));
3109
- }
3110
- /** Pick the parser for a manifest filename, or null if it's not one we read. */
3111
- function ingestorFor(name) {
3112
- if (name === "package.json") return addNpmDeps;
3113
- if (name === "requirements.txt") return (c, s) => parseRequirementsTxt(c).forEach((d) => addCapped(s.python, d));
3114
- if (name === "pyproject.toml") return (c, s) => parsePyprojectToml(c).forEach((d) => addCapped(s.python, d));
3115
- if (name === "Pipfile") return (c, s) => parsePipfile(c).forEach((d) => addCapped(s.python, d));
3116
- if (name === "Gemfile") return (c, s) => parseGemfile(c).forEach((g) => addCapped(s.ruby, g));
3117
- if (isEnvFileName(name)) return (c, s, relativePath) => addEnvKeys(c, s, relativePath);
3118
- return null;
3119
- }
3120
- /**
3121
- * Record each key NAME against the file that defined it. The first file wins,
3122
- * so the reported signal stays stable when several `.env*` files repeat a key.
3123
- * Values are never read.
3124
- */
3125
- function addEnvKeys(content, signals, relativePath) {
3126
- for (const key of parseEnvKeyNames(content)) {
3127
- if (signals.envKeys.has(key)) continue;
3128
- if (signals.envKeys.size >= MAX_SIGNAL_SET) return;
3129
- signals.envKeys.set(key, relativePath);
3130
- }
3131
- }
3132
- function addNpmDeps(content, signals) {
3133
- try {
3134
- const pkg = JSON.parse(content);
3135
- for (const dep of Object.keys({
3136
- ...pkg.dependencies,
3137
- ...pkg.devDependencies
3138
- })) addCapped(signals.npm, dep);
3139
- } catch (error) {
3140
- analytics.captureException(error instanceof Error ? error : new Error(String(error)), { step: "detectWarehouseSources.parsePackageJson" });
3141
- }
3142
- }
3143
- /** Extract gem names from `gem 'name'` declarations. */
3144
- function parseGemfile(content) {
3145
- const gems = [];
3146
- for (const match of content.matchAll(/^\s*gem\s+['"]([^'"]+)['"]/gm)) gems.push(match[1]);
3147
- return gems;
3148
- }
3149
- //#endregion
3150
- //#region src/programs/warehouse-source/detect.ts
3151
- /**
3152
- * Warehouse-source program detection step.
3153
- *
3154
- * Thin adapter over `detectWarehouseSources` that writes results into
3155
- * frameworkContext for the intro screen, plus the `[ABORT]` cases the
3156
- * data-warehouse-source-setup skill can emit.
3157
- */
3158
- /** frameworkContext key holding the detected sources (set on success). */
3159
- const DETECTED_WAREHOUSE_SOURCES_KEY = "detectedWarehouseSources";
3160
- /**
3161
- * Read the detected sources out of frameworkContext. Single accessor shared by
3162
- * the intro screen and the prompt builder so the key + cast live in one place.
3163
- */
3164
- function getDetectedWarehouseSources(session) {
3165
- return session.frameworkContext["detectedWarehouseSources"] ?? [];
3166
- }
3167
- /** `[ABORT] <reason>` cases the skill can emit. */
3168
- const WAREHOUSE_ABORT_CASES = [{
3169
- match: /^no data sources? detected\.?$/i,
3170
- message: "No data source detected",
3171
- body: "The agent could not confirm a data warehouse source to connect. Run this command from a project that uses a supported source (a database, Stripe, etc.).",
3172
- docsUrl: "https://posthog.com/docs/data-warehouse"
3173
- }, {
3174
- match: /^source creation failed\.?$/i,
3175
- message: "Source creation failed",
3176
- body: "PostHog could not create the data warehouse source with the credentials provided. Double-check the connection details and try again, or set the source up directly in the PostHog app.",
3177
- docsUrl: "https://posthog.com/docs/data-warehouse"
3178
- }];
3179
- /**
3180
- * Scan `session.installDir` for warehouse-source signals. Writes the detected
3181
- * sources (or a `detectError`) into frameworkContext for the intro screen.
3182
- */
3183
- function detectWarehousePrerequisites(session, setFrameworkContext) {
3184
- const fail = (error) => setFrameworkContext("detectError", error);
3185
- const installDir = session.installDir;
3186
- if (!existsSync(installDir)) {
3187
- fail({
3188
- kind: "bad-directory",
3189
- path: installDir,
3190
- reason: "missing"
3191
- });
3192
- return;
3193
- }
3194
- try {
3195
- if (!statSync(installDir).isDirectory()) {
3196
- fail({
3197
- kind: "bad-directory",
3198
- path: installDir,
3199
- reason: "not-dir"
3200
- });
3201
- return;
3202
- }
3203
- } catch (error) {
3204
- analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
3205
- step: "detectWarehousePrerequisites.stat",
3206
- path: installDir
3207
- });
3208
- fail({
3209
- kind: "bad-directory",
3210
- path: installDir,
3211
- reason: "unreadable"
3212
- });
3213
- return;
3214
- }
3215
- const sources = detectWarehouseSources(installDir);
3216
- if (sources.length === 0) {
3217
- fail({ kind: "no-sources" });
3218
- return;
3219
- }
3220
- analytics.setTag("warehouse_source_kinds", sources.map((s) => s.kind).join(","));
3221
- analytics.setTag("warehouse_source_modes", sources.map((s) => `${s.kind}:${s.mode}`).join(","));
3222
- analytics.setTag("warehouse_source_count", sources.length);
3223
- setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);
3224
- }
3225
- //#endregion
3226
- //#region src/programs/run-agent-legacy.ts
3227
- /**
3228
- * The session-driven agent runner every existing caller uses.
3229
- *
3230
- * `runProgramAgent(programConfig, session)` runs the gates the TUI owns
3231
- * (health, settings), then calls `runProgram` as its caller, backed by the
3232
- * session and `getUI()`: credentials come from `authenticate`, the AI
3233
- * opt-in and post-auth gates park on the UI, every progress event maps back
3234
- * onto `getUI()`, and the invocation's data projects back onto the session.
3235
- * It applies the result — `wizardAbort` with the outcome's terminal status for
3236
- * a decided failure, the terminal analytics event for a finished top-level run.
3237
- *
3238
- * This is the only file that knows about `getUI()`, the session and
3239
- * `wizardAbort` on the agent's behalf.
3240
- *
3241
- * ⚠️ Temporary adapter. It is removed later in the refactor.
3242
- */
3243
- /**
3244
- * Resolve a ProgramConfig's agent run definition and execute the pipeline.
3245
- * Entry point for the runners and for composed run steps.
3246
- */
3247
- async function runProgramAgent(programConfig, session, options = {}) {
3248
- if (!programConfig.run) throw new Error(`Program "${programConfig.id}" has no run configuration.`);
3249
- const ledgerFile = programConfig.auditLedgerFile;
3250
- const ledger = ledgerFile ? startAuditLedgerWatcher(session.installDir, ledgerFile) : null;
3251
- const releaseLedger = () => {
3252
- ledger?.refresh();
3253
- ledger?.stop();
3254
- if (ledgerFile) removeAuditLedger(session.installDir, ledgerFile);
3255
- };
3256
- if (ledger) registerCleanup(releaseLedger);
3257
- try {
3258
- await runSessionProgram(session, typeof programConfig.run === "function" ? await programConfig.run(session, uiRunnerContext()) : programConfig.run, programConfig, options.composed ?? false);
3259
- } finally {
3260
- releaseLedger();
3261
- }
3262
- }
3263
- /** The runner context each program effect reaches `getUI()` through, read at call time. */
3264
- function uiRunnerContext() {
3265
- return {
3266
- getFrameworkContext: (key) => getUI().getFrameworkContext(key),
3267
- setFrameworkContext: (key, value) => getUI().setFrameworkContext(key, value),
3268
- log: { warn: (message) => getUI().log.warn(message) }
3269
- };
3270
- }
3271
- /** Gates → runProgram on the session's behalf → apply result. */
3272
- async function runSessionProgram(session, run, programConfig, composed) {
3273
- initLogFile();
3274
- session.skillId = run.skillId ?? run.integrationLabel;
3275
- logToFile(`[agent-runner] START ${run.integrationLabel} build=${analytics.build}${session.ci ? " (non-interactive)" : ""}`);
3276
- if (session.debug) enableDebugLogs();
3277
- await runHealthGate(session, programConfig);
3278
- await runSettingsGate(session);
3279
- const ui = getUI();
3280
- const reduceUi = createUiReducer(ui);
3281
- const projectData = projectProgramData(ui, session);
3282
- let capabilityFailure;
3283
- const keepFailure = (work) => work.catch((error) => {
3284
- capabilityFailure ??= { error };
3285
- throw error;
3286
- });
3287
- const framework = session.integration ?? session.skillId ?? void 0;
3288
- const result = await runProgram(programConfig.id, {
3289
- installDir: session.installDir,
3290
- run,
3291
- composed,
3292
- overrides: {
3293
- harness: session.harness,
3294
- sequence: session.sequence,
3295
- model: session.model
3296
- },
3297
- skillId: session.skillId ?? void 0,
3298
- integration: session.integration,
3299
- frameworkDocsUrl: framework ? FRAMEWORK_REGISTRY[framework]?.metadata.docsUrl : void 0,
3300
- flags: {
3301
- ci: session.ci,
3302
- signup: session.signup,
3303
- debug: session.debug,
3304
- e2eAsk: session.e2eAsk,
3305
- localMcp: session.localMcp,
3306
- captureAio: session.captureAio,
3307
- benchmark: session.benchmark,
3308
- yaraReport: session.yaraReport
3309
- },
3310
- host: {
3311
- baseUrl: session.baseUrl,
3312
- region: session.region,
3313
- email: session.email,
3314
- projectId: session.projectId,
3315
- apiKey: session.apiKey
3316
- },
3317
- seedTasks: programConfig.seedTasks ? () => programConfig.seedTasks(session) : void 0,
3318
- hooks: {
3319
- postRun: run.postRun ? (creds) => run.postRun(session, creds) : void 0,
3320
- buildOutroData: run.buildOutroData ? (creds) => run.buildOutroData(session, creds) ?? void 0 : void 0,
3321
- buildOutroNextSteps: run.buildOutroNextSteps ? (creds, completed) => run.buildOutroNextSteps(session, creds, completed) : void 0,
3322
- recordTaskOutcomes: (outcomes) => {
3323
- session.frameworkContext[TASK_OUTCOMES_KEY] = outcomes;
3324
- }
3325
- },
3326
- program: {
3327
- requiresAi: programConfig.requiresAi,
3328
- agentFlow: programConfig.agentFlow,
3329
- allowedTools: programConfig.allowedTools,
3330
- disallowedTools: programConfig.disallowedTools,
3331
- excludedTaskTypes: programConfig.excludedTaskTypes,
3332
- postAuthGates: postAuthGateSteps(programConfig.steps).map((step) => step.id)
3333
- },
3334
- aiSdkStampReported: session.aiSdkStampReported,
3335
- discoveredFeatures: session.discoveredFeatures,
3336
- warehouseSources: getDetectedWarehouseSources(session),
3337
- mayReportScanResults: mayReportScanResults(session)
3338
- }, {
3339
- credentials: { resolve: () => keepFailure(authenticate(session, programConfig.id).then(() => ({
3340
- posthog: session.credentials,
3341
- project: session.apiProject,
3342
- apiUser: session.apiUser
3343
- }))) },
3344
- awaitAiApproval: async () => {
3345
- logToFile("[agent-runner] checking AI opt-in gate");
3346
- await ui.waitForAiOptIn();
3347
- logToFile("[agent-runner] AI opt-in gate cleared");
3348
- return true;
3349
- },
3350
- awaitPostAuthGates: async ({ gates }) => {
3351
- for (const gate of gates) {
3352
- logToFile(`[agent-runner] awaiting post-auth gate: ${gate}`);
3353
- await ui.waitForGate(gate);
3354
- logToFile(`[agent-runner] post-auth gate cleared: ${gate}`);
3355
- }
3356
- },
3357
- featureFlags: () => keepFailure(loadWizardFlags()),
3358
- onProgress: (progress) => {
3359
- if (progress.kind === "run") reduceUi(progress.event);
3360
- else projectData(progress.data);
3361
- },
3362
- interaction: uiInteraction(ui)
3363
- });
3364
- for (const diagnostic of result.diagnostics) {
3365
- const runLabel = "runId" in diagnostic ? ` run=${diagnostic.runId}` : "";
3366
- logToFile(`[agent-runner] progress diagnostic (${diagnostic.eventKind}${runLabel}): ${diagnostic.message}`);
3367
- }
3368
- if (capabilityFailure) throw capabilityFailure.error;
3369
- if (result.outcome === "crashed") throw result.failure?.error;
3370
- if (result.outcome !== "success") {
3371
- if (result.failure?.authErrorDetail) ui.showAuthError(result.failure.authErrorDetail);
3372
- await wizardAbort({
3373
- ...result.failure,
3374
- status: result.outcome === "aborted" ? "cancelled" : "error"
3375
- });
3376
- } else if (!composed) try {
3377
- await analytics.shutdown("success");
3378
- } catch (error) {
3379
- logToFile("[agent-runner] analytics shutdown failed:", error);
3380
- }
3381
- }
3382
- /** Mirror the invocation's data onto the session and the UI the TUI reads. */
3383
- function projectProgramData(ui, session) {
3384
- let bindingSeen = false;
3385
- return (data) => {
3386
- const current = session.credentials;
3387
- if (current && data.credentials && data.credentials.accessToken !== current.accessToken) {
3388
- session.credentials = {
3389
- ...current,
3390
- accessToken: data.credentials.accessToken,
3391
- refreshToken: data.credentials.refreshToken,
3392
- expiresAt: data.credentials.expiresAt
3393
- };
3394
- ui.setAccessToken(session.credentials);
3395
- }
3396
- if (data.aiSdkStampReported) session.aiSdkStampReported = true;
3397
- if (!data.binding || bindingSeen) return;
3398
- bindingSeen = true;
3399
- registerCleanup(() => {
3400
- const report = flushScanReport({ yaraReport: session.yaraReport });
3401
- if (report) ui.log.info(report);
3402
- });
3403
- if (data.binding.sequence === "linear") ui.onEnterScreen("outro", () => restoreClaudeSettings(session.installDir));
3404
- };
3405
- }
3406
- const loadWizardFlags = async () => ({
3407
- flags: await analytics.getAllFlagsForWizard(),
3408
- payloads: analytics.getWizardFlagPayloads()
3409
- });
3410
- async function runHealthGate(session, programConfig) {
3411
- const hasHealthCheckScreen = programConfig.steps.some((s) => s.screenId === "health-check");
3412
- if (session.readinessResult) logToFile(`[agent-runner] readiness pre-computed by TUI: decision=${session.readinessResult.decision}${session.outageDismissed ? " (outage dismissed by user)" : ""} — skipping re-check`);
3413
- if (!hasHealthCheckScreen || session.readinessResult) return;
3414
- logToFile("[agent-runner] evaluating wizard readiness");
3415
- const readinessConfig = session.signup ? SIGNUP_WIZARD_READINESS_CONFIG : void 0;
3416
- const readiness = await evaluateWizardReadiness(readinessConfig);
3417
- logToFile(`[agent-runner] readiness=${readiness.decision}`);
3418
- if (readiness.decision === "no") {
3419
- const blockingLabels = getBlockingServiceKeys(readiness.health, readinessConfig).map((k) => `${SERVICE_LABELS[k]} (${readiness.health[k].status})`);
3420
- logToFile(`[agent-runner] blocked by: ${blockingLabels.join(", ")}`);
3421
- await getUI().showBlockingOutage(readiness);
3422
- if (!isNonInteractiveEnvironment()) await wizardAbort({
3423
- code: ErrorCodes.EnvServiceOutage,
3424
- message: "Cannot start — external services are down:\n" + blockingLabels.map((l) => ` - ${l}`).join("\n") + "\n\nPlease try again later."
3425
- });
3426
- } else if (readiness.decision === "yes_with_warnings") getUI().setReadinessWarnings(readiness);
3427
- }
3428
- async function runSettingsGate(session) {
3429
- const settingsConflicts = checkAllSettingsConflicts(session.installDir);
3430
- logToFile(`[agent-runner] settings conflicts: ${settingsConflicts.length > 0 ? settingsConflicts.map((c) => `${c.source}(${c.keys.join(",")})`).join("; ") : "none"}`);
3431
- if (settingsConflicts.length === 0) return;
3432
- for (const conflict of settingsConflicts) {
3433
- const level = conflict.source === "managed" ? "org" : conflict.source;
3434
- analytics.wizardCapture("settings conflict detected", {
3435
- level,
3436
- keys: conflict.keys
3437
- });
3438
- }
3439
- const { autoFix, failClosed, warnOnly } = classifySettingsConflicts(settingsConflicts);
3440
- for (const conflict of warnOnly) {
3441
- logToFile(`[agent-runner] settings conflict in ${conflict.source} (${conflict.path}) neutralized by settingSources:['project'] — not blocking`);
3442
- analytics.wizardCapture("settings conflict neutralized", {
3443
- level: conflict.source,
3444
- keys: conflict.keys
3445
- });
3446
- }
3447
- let unfixable = failClosed;
3448
- if (autoFix.length > 0) if (backupAndFixClaudeSettings(session.installDir)) {
3449
- logToFile("[agent-runner] auto-neutralized writable settings conflict");
3450
- analytics.wizardCapture("settings conflict auto-neutralized", { keys: autoFix.flatMap((c) => c.keys) });
3451
- } else {
3452
- logToFile("[agent-runner] could not back up writable settings conflict — failing closed");
3453
- unfixable = [...failClosed, ...autoFix];
3454
- }
3455
- if (unfixable.length > 0) {
3456
- if (isNonInteractiveEnvironment()) await wizardAbort({
3457
- code: ErrorCodes.SettingsUnfixableConflict,
3458
- message: "Cannot start — a Claude settings file redirects the agent away from the PostHog gateway and cannot be neutralized automatically:\n" + unfixable.map((c) => ` - ${c.source} (${c.path}): ${c.keys.join(", ")}`).join("\n") + "\n\nRemove the conflicting keys and re-run the wizard."
3459
- });
3460
- await getUI().showSettingsOverride(unfixable, () => backupAndFixClaudeSettings(session.installDir));
3461
- logToFile("[agent-runner] settings override resolved");
3462
- }
3463
- }
3464
- //#endregion
3465
- export { getDetectedWarehouseSources as a, AUDIT_CHECKS_KEY as c, createUiReducer as d, stampAiSdkDetected as f, detectWarehousePrerequisites as i, getAuditChecks as l, DETECTED_WAREHOUSE_SOURCES_KEY as n, detectWarehouseSources as o, WAREHOUSE_ABORT_CASES as r, discoverFeatures as s, runProgramAgent as t, authenticate as u };
3466
-
3467
- //# sourceMappingURL=run-agent-legacy-DWBajsMh.js.map