@posthog/wizard 2.44.0 → 2.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/{add-mcp-server-to-clients-D5qsqCkj.js → add-mcp-server-to-clients-Bv2CBSil.js} +53 -6
- package/dist/add-mcp-server-to-clients-Bv2CBSil.js.map +1 -0
- package/dist/{agent-interface-BvTxWiol.js → agent-interface-B8roB2UP.js} +1122 -157
- package/dist/agent-interface-B8roB2UP.js.map +1 -0
- package/dist/{agent-runner-BF6_f8Qh.js → agent-runner-CV3qh_2p.js} +298 -610
- package/dist/agent-runner-CV3qh_2p.js.map +1 -0
- package/dist/analytics-D7vUZgzf.js +2 -0
- package/dist/{analytics-DSlQuwOT.js → analytics-k76OWsl0.js} +20 -6
- package/dist/analytics-k76OWsl0.js.map +1 -0
- package/dist/{api-BXduJZrw.js → api-CmIWcW-U.js} +3 -3
- package/dist/{api-BXduJZrw.js.map → api-CmIWcW-U.js.map} +1 -1
- package/dist/bin.js +242 -1043
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-GirEJqu2.js → ci-install-CNEJxdHf.js} +4 -4
- package/dist/{ci-install-GirEJqu2.js.map → ci-install-CNEJxdHf.js.map} +1 -1
- package/dist/commandments-DSNrOeOC.js +42 -0
- package/dist/commandments-DSNrOeOC.js.map +1 -0
- package/dist/commandments-qTW7pwaT.js +2 -0
- package/dist/{debug-BOFxiVVs.js → debug-BwIo7nwn.js} +1 -1
- package/dist/{debug-DXfQFmcM.js → debug-C9HmIrwx.js} +36 -6
- package/dist/debug-C9HmIrwx.js.map +1 -0
- package/dist/{defaults-BWLIffh5.js → defaults-CtWMmC8s.js} +1 -1
- package/dist/{defaults-BWLIffh5.js.map → defaults-CtWMmC8s.js.map} +1 -1
- package/dist/{env-api-key-cjD4yfGT.js → env-api-key-C3LzH8Lr.js} +1 -1
- package/dist/{env-api-key-cjD4yfGT.js.map → env-api-key-C3LzH8Lr.js.map} +1 -1
- package/dist/{environment-F1yw21dG.js → environment-NJykOp33.js} +3 -3
- package/dist/{environment-F1yw21dG.js.map → environment-NJykOp33.js.map} +1 -1
- package/dist/{file-utils-D-7YfJ7A.js → file-utils-CLMcNIKi.js} +2 -2
- package/dist/{file-utils-D-7YfJ7A.js.map → file-utils-CLMcNIKi.js.map} +1 -1
- package/dist/file-watcher-CBDCNQVV.js +123 -0
- package/dist/file-watcher-CBDCNQVV.js.map +1 -0
- package/dist/{headless-ui-Dni0gPND.js → headless-ui-B3QKxbz8.js} +5 -4
- package/dist/headless-ui-B3QKxbz8.js.map +1 -0
- package/dist/{interactive-Bmi82rsO.js → interactive-CIJRex02.js} +2 -2
- package/dist/{interactive-Bmi82rsO.js.map → interactive-CIJRex02.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-AtntLsJ8.js → mcp-prompt-streaming-D6OgW3lC.js} +3 -3
- package/dist/{mcp-prompt-streaming-AtntLsJ8.js.map → mcp-prompt-streaming-D6OgW3lC.js.map} +1 -1
- package/dist/{mcp-xKRDnrcq.js → mcp-qTjKHqXN.js} +3 -3
- package/dist/mcp-qTjKHqXN.js.map +1 -0
- package/dist/{non-interactive-BIHqcW8g.js → non-interactive-8Eypq_h-.js} +2 -2
- package/dist/{non-interactive-BIHqcW8g.js.map → non-interactive-8Eypq_h-.js.map} +1 -1
- package/dist/orchestrator-tools-DVXOV-kz.js +99 -0
- package/dist/orchestrator-tools-DVXOV-kz.js.map +1 -0
- package/dist/{package-json-CDs1ZVKu.js → package-json-DCuoye-H.js} +1 -1
- package/dist/{package-json-CDs1ZVKu.js.map → package-json-DCuoye-H.js.map} +1 -1
- package/dist/{package-manager-C6R_zpML.js → package-manager-CAD9Uklp.js} +2 -2
- package/dist/{package-manager-C6R_zpML.js.map → package-manager-CAD9Uklp.js.map} +1 -1
- package/dist/pi-C9iHv5uG.js +619 -0
- package/dist/pi-C9iHv5uG.js.map +1 -0
- package/dist/{playground-DwL36I2u.js → playground-C-9Q3ETa.js} +8 -9
- package/dist/{playground-DwL36I2u.js.map → playground-C-9Q3ETa.js.map} +1 -1
- package/dist/{posthog-DwKlq0HM.js → posthog-DZZbziJ1.js} +1 -1
- package/dist/{posthog-DwKlq0HM.js.map → posthog-DZZbziJ1.js.map} +1 -1
- package/dist/{posthog-integration-BhLKCFsI.js → posthog-integration-Do997QON.js} +2206 -112
- package/dist/posthog-integration-Do997QON.js.map +1 -0
- package/dist/{provisioning-jVZm2E-A.js → provisioning-DpqnGk3z.js} +3 -3
- package/dist/{provisioning-jVZm2E-A.js.map → provisioning-DpqnGk3z.js.map} +1 -1
- package/dist/queue-tools-CTUgbOU8.js +366 -0
- package/dist/queue-tools-CTUgbOU8.js.map +1 -0
- package/dist/{registry-DcoBCMQR.js → registry-DT58jEYr.js} +96 -18
- package/dist/registry-DT58jEYr.js.map +1 -0
- package/dist/{security-jxjVsOpd.js → security-CTigdAWm.js} +10 -8
- package/dist/security-CTigdAWm.js.map +1 -0
- package/dist/{setup-utils-BQCl28D8.js → setup-utils-Cb5uACEO.js} +31 -9
- package/dist/setup-utils-Cb5uACEO.js.map +1 -0
- package/dist/{start-tui-DgSKFMVh.js → start-tui-Cwc-PFma.js} +37 -92
- package/dist/start-tui-Cwc-PFma.js.map +1 -0
- package/dist/{steps-erepgD0V.js → steps-DyEKYM4I.js} +7 -7
- package/dist/{steps-erepgD0V.js.map → steps-DyEKYM4I.js.map} +1 -1
- package/dist/{store-C79GoHCQ.js → store-4sj-vWr5.js} +5 -6
- package/dist/store-4sj-vWr5.js.map +1 -0
- package/dist/{subagent-aDlD_Ltz.js → subagent-D8_yDgCB.js} +2 -2
- package/dist/{subagent-aDlD_Ltz.js.map → subagent-D8_yDgCB.js.map} +1 -1
- package/dist/task-D8Y8pkzd.js +304 -0
- package/dist/task-D8Y8pkzd.js.map +1 -0
- package/dist/{task-stream-0Pk0tPBN.js → task-stream-DQT3vjwS.js} +72 -7
- package/dist/task-stream-DQT3vjwS.js.map +1 -0
- package/dist/{tasks-ZkrluXCa.js → tasks-D2WKssA5.js} +2 -2
- package/dist/{tasks-ZkrluXCa.js.map → tasks-D2WKssA5.js.map} +1 -1
- package/dist/{telemetry-DZShaH-y.js → telemetry-CYr4HgS2.js} +3 -3
- package/dist/{telemetry-DZShaH-y.js.map → telemetry-CYr4HgS2.js.map} +1 -1
- package/dist/{terminal-CEhufbJ4.js → terminal-1RfyHQC2.js} +13 -13
- package/dist/{terminal-CEhufbJ4.js.map → terminal-1RfyHQC2.js.map} +1 -1
- package/dist/tools-DQCUOQZX.js +199 -0
- package/dist/tools-DQCUOQZX.js.map +1 -0
- package/dist/{wizard-abort-UCm4Pd5m.js → wizard-abort-D_-v1zvS.js} +1 -1
- package/dist/{wizard-abort-C14PzXZ8.js → wizard-abort-FuyIaI_0.js} +4 -4
- package/dist/{wizard-abort-C14PzXZ8.js.map → wizard-abort-FuyIaI_0.js.map} +1 -1
- package/dist/{wizard-session-C5lZPPEc.js → wizard-session-DWHe83uk.js} +1 -1
- package/dist/{wizard-session-BAZql11N.js → wizard-session-tp4Zdbwl.js} +1 -1
- package/dist/{wizard-session-BAZql11N.js.map → wizard-session-tp4Zdbwl.js.map} +1 -1
- package/dist/yara-hooks-6gNnPFPo.js +2 -0
- package/dist/{yara-hooks-CPH8N4yz.js → yara-hooks-DdYRRxfH.js} +82 -21
- package/dist/yara-hooks-DdYRRxfH.js.map +1 -0
- package/package.json +1 -1
- package/dist/add-mcp-server-to-clients-D5qsqCkj.js.map +0 -1
- package/dist/agent-interface-BvTxWiol.js.map +0 -1
- package/dist/agent-runner-BF6_f8Qh.js.map +0 -1
- package/dist/analytics-C7Xx6csw.js +0 -2
- package/dist/analytics-DSlQuwOT.js.map +0 -1
- package/dist/debug-DXfQFmcM.js.map +0 -1
- package/dist/headless-ui-Dni0gPND.js.map +0 -1
- package/dist/mcp-xKRDnrcq.js.map +0 -1
- package/dist/posthog-integration-BhLKCFsI.js.map +0 -1
- package/dist/registry-DcoBCMQR.js.map +0 -1
- package/dist/security-jxjVsOpd.js.map +0 -1
- package/dist/setup-utils-BQCl28D8.js.map +0 -1
- package/dist/start-tui-DgSKFMVh.js.map +0 -1
- package/dist/store-C79GoHCQ.js.map +0 -1
- package/dist/task-stream-0Pk0tPBN.js.map +0 -1
- package/dist/tools-BIPMan6l.js +0 -122
- package/dist/tools-BIPMan6l.js.map +0 -1
- package/dist/types-y3HkjtSq.js +0 -46
- package/dist/types-y3HkjtSq.js.map +0 -1
- package/dist/wizard-tools-B7SLjCic.js +0 -1106
- package/dist/wizard-tools-B7SLjCic.js.map +0 -1
- package/dist/wizard-ui-WZ48rUgr.js +0 -15
- package/dist/wizard-ui-WZ48rUgr.js.map +0 -1
- package/dist/yara-hooks-CPH8N4yz.js.map +0 -1
- package/dist/yara-hooks-VZlj4Lib.js +0 -2
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import { i as withUtm, n as openTrackedLink } from "./telemetry-
|
|
4
|
-
import { i as tryGetPackageJson, n as isUsingTypeScript } from "./setup-utils-
|
|
5
|
-
import { r as requestDeepLink } from "./provisioning-
|
|
6
|
-
import "./wizard-session-
|
|
7
|
-
import { i as wizardAbort } from "./wizard-abort-
|
|
8
|
-
import { n as runAgent } from "./agent-runner-
|
|
9
|
-
import { i as runAgent$1, p as AgentSignals, r as initializeAgent } from "./agent-interface-
|
|
10
|
-
import {
|
|
11
|
-
import { r as detectNodePackageManagers } from "./package-manager-
|
|
12
|
-
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-
|
|
1
|
+
import { B as Integration, L as HAIKU_MODEL, O as DETECTION_TIMEOUT_MS, _ as evaluateWizardReadiness, f as getUI, g as SIGNUP_WIZARD_READINESS_CONFIG, s as logToFile, st as WIZARD_INTERACTION_EVENT_NAME, v as getBlockingServiceKeys, vt as getSkillsBaseUrl, x as AGENTIC_DETECTION_TIMEOUT_MS } from "./debug-C9HmIrwx.js";
|
|
2
|
+
import { n as analytics } from "./analytics-k76OWsl0.js";
|
|
3
|
+
import { i as withUtm, n as openTrackedLink } from "./telemetry-CYr4HgS2.js";
|
|
4
|
+
import { i as tryGetPackageJson, n as isUsingTypeScript } from "./setup-utils-Cb5uACEO.js";
|
|
5
|
+
import { r as requestDeepLink } from "./provisioning-DpqnGk3z.js";
|
|
6
|
+
import "./wizard-session-tp4Zdbwl.js";
|
|
7
|
+
import { i as wizardAbort } from "./wizard-abort-FuyIaI_0.js";
|
|
8
|
+
import { n as runAgent, o as authenticate } from "./agent-runner-CV3qh_2p.js";
|
|
9
|
+
import { i as runAgent$1, p as AgentSignals, r as initializeAgent, v as WIZARD_TOOL_NAMES } from "./agent-interface-B8roB2UP.js";
|
|
10
|
+
import { m as EVENT_PLAN_FILE } from "./yara-hooks-DdYRRxfH.js";
|
|
11
|
+
import { r as detectNodePackageManagers } from "./package-manager-CAD9Uklp.js";
|
|
12
|
+
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-DT58jEYr.js";
|
|
13
|
+
import { n as safeReadFile, r as walkProjectFiles } from "./file-utils-CLMcNIKi.js";
|
|
13
14
|
import * as semver from "semver";
|
|
14
|
-
import { readFileSync } from "fs";
|
|
15
|
-
import { isAbsolute, join } from "path";
|
|
15
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
16
|
+
import { isAbsolute, join, resolve, sep } from "path";
|
|
16
17
|
import { Text } from "ink";
|
|
17
18
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
18
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -263,8 +264,9 @@ const PROJECT_MANIFESTS = [
|
|
|
263
264
|
function manifestGlob() {
|
|
264
265
|
return `**/{${PROJECT_MANIFESTS.join(",")}}`;
|
|
265
266
|
}
|
|
266
|
-
function buildPrompt(cwd, targets, purpose) {
|
|
267
|
+
function buildPrompt(cwd, targets, purpose, recommend) {
|
|
267
268
|
const targetList = targets.map((t) => `- ${t.id} → ${t.name}`).join("\n");
|
|
269
|
+
const projectShape = `{"path":string,"framework":string,"targetId":string|null,"hasPostHog":boolean${recommend ? ",\"recommended\":boolean" : ""}}`;
|
|
268
270
|
return [
|
|
269
271
|
`You are scanning a code repository to ${purpose}. Be fast and mechanical — do not over-explore. Keep any reasoning to one short sentence, then run the tool calls and output the JSON.`,
|
|
270
272
|
"",
|
|
@@ -280,16 +282,18 @@ function buildPrompt(cwd, targets, purpose) {
|
|
|
280
282
|
" - the matching target id from the list below. That list is ordered by priority — most specific first — so when a project could match more than one target (e.g. it uses several of the listed technologies), pick the one listed EARLIEST. Use null only if none matches,",
|
|
281
283
|
` - hasPostHog: true if any dependency is a PostHog SDK. This includes: a name containing "posthog" in any ecosystem (e.g. posthog-js, posthog-node, @posthog/*, posthog for pip/gem/hex, a com.posthog:* gradle/maven coordinate, a PostHog NuGet PackageReference); an SPM package named "PostHog" or a repositoryURL of github.com/PostHog/posthog-ios (in Package.swift or a .pbxproj); or a "pod 'PostHog'" line in a Podfile. Else false.`,
|
|
282
284
|
" Do NOT read any file other than these manifests.",
|
|
285
|
+
...recommend ? ["4. Pick exactly ONE project as recommended — the main user-facing client application. Prefer a frontend web app or a mobile app over backend servers/APIs, libraries, CLIs, tooling, and example/demo/docs apps. If several client apps exist, pick the primary production app; if no client app exists, pick the primary application project."] : [],
|
|
283
286
|
"",
|
|
284
287
|
"Target ids (id → name), in priority order — most specific first; if several match a project, keep the one listed earliest:",
|
|
285
288
|
targetList,
|
|
286
289
|
"",
|
|
287
290
|
"Output requirements:",
|
|
288
291
|
"- Respond with ONLY a single JSON object. No prose, no markdown code fences.",
|
|
289
|
-
|
|
292
|
+
`- Shape: {"repoType":"monorepo"|"single","projects":[${projectShape}]}`,
|
|
290
293
|
"- \"path\" is the project directory relative to the working directory; use \".\" for the repo root.",
|
|
291
294
|
"- \"targetId\" MUST be exactly one of the target ids above when it matches; if several match, use the one listed earliest; otherwise null.",
|
|
292
295
|
"- Include projects whose stack matches no target too (targetId: null).",
|
|
296
|
+
...recommend ? ["- Exactly one project has \"recommended\": true; every other project has \"recommended\": false."] : [],
|
|
293
297
|
`- If there are no manifests at all, respond with exactly: ${AgentSignals.ABORT} detection failed`
|
|
294
298
|
].join("\n");
|
|
295
299
|
}
|
|
@@ -311,107 +315,2125 @@ function coercePath(raw) {
|
|
|
311
315
|
if (isAbsolute(raw) || raw.split(/[\\/]/).includes("..")) return ".";
|
|
312
316
|
return raw;
|
|
313
317
|
}
|
|
318
|
+
/** Resolve an agent-reported path to an absolute dir clamped to the root — the caller-side counterpart of coercePath. */
|
|
319
|
+
function resolveProjectDir(installDir, rel) {
|
|
320
|
+
if (typeof rel !== "string" || rel === ".") return installDir;
|
|
321
|
+
const root = resolve(installDir);
|
|
322
|
+
const dir = resolve(root, rel);
|
|
323
|
+
return dir === root || dir.startsWith(root + sep) ? dir : root;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Validate the agent's raw JSON into a report, clamping each targetId to the
|
|
327
|
+
* supplied set and each path to a repo-relative dir. Exported for testing.
|
|
328
|
+
* `recommended` is stripped unless requested; at most one (the first) survives.
|
|
329
|
+
*/
|
|
330
|
+
function coerceAgenticReport(parsed, validTargetIds, options) {
|
|
331
|
+
const recommend = options?.recommend === true;
|
|
332
|
+
const obj = parsed ?? {};
|
|
333
|
+
const repoType = obj.repoType === "monorepo" ? "monorepo" : "single";
|
|
334
|
+
const rawProjects = Array.isArray(obj.projects) ? obj.projects : [];
|
|
335
|
+
let recommendedSeen = false;
|
|
336
|
+
return {
|
|
337
|
+
repoType,
|
|
338
|
+
projects: rawProjects.map((raw) => {
|
|
339
|
+
const p = raw ?? {};
|
|
340
|
+
const targetId = typeof p.targetId === "string" && validTargetIds.includes(p.targetId) ? p.targetId : null;
|
|
341
|
+
const recommended = recommend && !recommendedSeen && p.recommended === true;
|
|
342
|
+
recommendedSeen ||= recommended;
|
|
343
|
+
return {
|
|
344
|
+
path: coercePath(p.path),
|
|
345
|
+
framework: typeof p.framework === "string" ? p.framework : "Unknown",
|
|
346
|
+
targetId,
|
|
347
|
+
hasPostHog: p.hasPostHog === true,
|
|
348
|
+
...recommend ? { recommended } : {}
|
|
349
|
+
};
|
|
350
|
+
})
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function formatToolUse(block) {
|
|
354
|
+
const name = typeof block?.name === "string" ? block.name : "tool";
|
|
355
|
+
const input = block?.input ?? {};
|
|
356
|
+
const detail = input.file_path || input.pattern || input.path || "";
|
|
357
|
+
return detail ? `${name} ${detail}` : name;
|
|
358
|
+
}
|
|
359
|
+
function sessionToWizardOptions(session) {
|
|
360
|
+
return {
|
|
361
|
+
installDir: session.installDir,
|
|
362
|
+
ci: session.ci,
|
|
363
|
+
debug: session.debug,
|
|
364
|
+
default: false,
|
|
365
|
+
benchmark: session.benchmark,
|
|
366
|
+
yaraReport: session.yaraReport,
|
|
367
|
+
signup: session.signup,
|
|
368
|
+
apiKey: session.apiKey,
|
|
369
|
+
projectId: session.projectId,
|
|
370
|
+
localMcp: session.localMcp
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const NOOP_SPINNER = {
|
|
374
|
+
start: () => void 0,
|
|
375
|
+
stop: () => void 0,
|
|
376
|
+
message: () => void 0
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Drive the wizard's agent loop on HAIKU_MODEL to scan the repo and return a
|
|
380
|
+
* structured detection report. Reuses the same setup every program uses, so
|
|
381
|
+
* MCP, tools, and credentials are wired identically.
|
|
382
|
+
*/
|
|
383
|
+
async function detectProjectsWithAgent(session, options) {
|
|
384
|
+
if (!session.credentials) throw new Error("Detection requires authenticated credentials.");
|
|
385
|
+
const { targets, purpose = "set up a PostHog integration", recommend = false, onEvent } = options;
|
|
386
|
+
const { accessToken, host } = session.credentials;
|
|
387
|
+
const cwd = session.installDir;
|
|
388
|
+
const runOptions = sessionToWizardOptions(session);
|
|
389
|
+
const agent = await initializeAgent({
|
|
390
|
+
workingDirectory: cwd,
|
|
391
|
+
posthogMcpUrl: host.mcpUrl,
|
|
392
|
+
posthogApiKey: accessToken,
|
|
393
|
+
host,
|
|
394
|
+
detectPackageManager: detectNodePackageManagers,
|
|
395
|
+
skillsBaseUrl: getSkillsBaseUrl(session.localMcp),
|
|
396
|
+
integrationLabel: "agentic-detect",
|
|
397
|
+
allowedTools: [
|
|
398
|
+
"Read",
|
|
399
|
+
"Grep",
|
|
400
|
+
"Glob"
|
|
401
|
+
],
|
|
402
|
+
modelOverride: HAIKU_MODEL
|
|
403
|
+
}, runOptions);
|
|
404
|
+
const collected = [];
|
|
405
|
+
let resultText = "";
|
|
406
|
+
const result = await runAgent$1(agent, buildPrompt(cwd, targets, purpose, recommend), runOptions, NOOP_SPINNER, {
|
|
407
|
+
spinnerMessage: "Scanning the repo...",
|
|
408
|
+
successMessage: "Detection complete",
|
|
409
|
+
errorMessage: "Detection failed",
|
|
410
|
+
requestRemark: false
|
|
411
|
+
}, {
|
|
412
|
+
onMessage: (message) => {
|
|
413
|
+
if (message?.type === "assistant") {
|
|
414
|
+
for (const block of message.message?.content ?? []) if (block?.type === "text" && typeof block.text === "string") {
|
|
415
|
+
collected.push(block.text);
|
|
416
|
+
const line = block.text.trim();
|
|
417
|
+
if (line && onEvent) onEvent(line.length > 100 ? `${line.slice(0, 100)}…` : line);
|
|
418
|
+
} else if (block?.type === "tool_use") onEvent?.(formatToolUse(block));
|
|
419
|
+
} else if (message?.type === "result" && typeof message.result === "string") resultText = message.result;
|
|
420
|
+
},
|
|
421
|
+
finalize: (_resultMessage, _durationMs) => void 0
|
|
422
|
+
});
|
|
423
|
+
if (result.error) throw new Error(result.message || `Agent error: ${result.error}`);
|
|
424
|
+
const output = resultText || collected.join("\n");
|
|
425
|
+
try {
|
|
426
|
+
return coerceAgenticReport(extractJson(output), targets.map((t) => t.id), { recommend });
|
|
427
|
+
} catch (err) {
|
|
428
|
+
if (output.includes(AgentSignals.ABORT)) return {
|
|
429
|
+
repoType: "single",
|
|
430
|
+
projects: []
|
|
431
|
+
};
|
|
432
|
+
throw err;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/lib/detection/project-scope.ts
|
|
437
|
+
/** Non-interactive project scoping — scan the repo agentically and pick which project the run integrates. */
|
|
438
|
+
/** Integration framework targets for the agentic detector (id → display name). */
|
|
439
|
+
const INTEGRATION_TARGETS = Object.entries(FRAMEWORK_REGISTRY).map(([id, config]) => ({
|
|
440
|
+
id,
|
|
441
|
+
name: config.metadata.name
|
|
442
|
+
}));
|
|
443
|
+
/** Run the agentic detector for the wizard's integration frameworks — the single home of targets + purpose. */
|
|
444
|
+
async function detectIntegrationProjects(session, options = {}) {
|
|
445
|
+
return detectProjectsWithAgent(session, {
|
|
446
|
+
...options,
|
|
447
|
+
targets: INTEGRATION_TARGETS,
|
|
448
|
+
purpose: "set up a PostHog SDK integration"
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
/** Pick the recommended-if-supported project (even with PostHog — the main app wins), else the first supported PostHog-free one. */
|
|
452
|
+
function chooseIntegrationProject(projects) {
|
|
453
|
+
return projects.find((p) => p.recommended === true && p.targetId != null) ?? projects.find((p) => p.targetId != null && !p.hasPostHog);
|
|
454
|
+
}
|
|
455
|
+
/** Sentinel for a scan that outran AGENTIC_DETECTION_TIMEOUT_MS. */
|
|
456
|
+
const TIMED_OUT = Symbol("timed-out");
|
|
457
|
+
function captureOutcome(outcome, properties = {}) {
|
|
458
|
+
analytics.wizardCapture("agentic detection", {
|
|
459
|
+
outcome,
|
|
460
|
+
...properties
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
/** Flag-gated non-interactive monorepo phase: scan, auto-choose the recommended project, re-point session.installDir; every failure leaves the session untouched. */
|
|
464
|
+
async function scopeInstallDirToProject(session) {
|
|
465
|
+
await authenticate(session, "posthog-integration");
|
|
466
|
+
if ((await analytics.getAllFlagsForWizard())["wizard-basic-integration-agentic-detection"] !== "true") {
|
|
467
|
+
captureOutcome("flag-off");
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
getUI().log.info("Scanning the repo for projects...");
|
|
471
|
+
const startedAt = Date.now();
|
|
472
|
+
let report;
|
|
473
|
+
try {
|
|
474
|
+
report = await Promise.race([detectIntegrationProjects(session, {
|
|
475
|
+
recommend: true,
|
|
476
|
+
onEvent: (line) => logToFile("[agentic detect]", line)
|
|
477
|
+
}), new Promise((resolve) => setTimeout(() => resolve(TIMED_OUT), AGENTIC_DETECTION_TIMEOUT_MS))]);
|
|
478
|
+
} catch (err) {
|
|
479
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
480
|
+
analytics.captureException(error, { step: "agentic_detection" });
|
|
481
|
+
captureOutcome("error", {
|
|
482
|
+
duration_ms: Date.now() - startedAt,
|
|
483
|
+
error_message: error.message
|
|
484
|
+
});
|
|
485
|
+
getUI().log.warn(`Project scan failed (${error.message}); continuing with the install dir as-is.`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (report === TIMED_OUT) {
|
|
489
|
+
captureOutcome("timeout", { duration_ms: Date.now() - startedAt });
|
|
490
|
+
getUI().log.warn(`Project scan timed out after ${AGENTIC_DETECTION_TIMEOUT_MS / 1e3}s; continuing with the install dir as-is.`);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const { projects } = report;
|
|
494
|
+
const recommended = projects.find((p) => p.recommended === true);
|
|
495
|
+
const scanProperties = {
|
|
496
|
+
duration_ms: Date.now() - startedAt,
|
|
497
|
+
repo_type: report.repoType,
|
|
498
|
+
project_count: projects.length,
|
|
499
|
+
supported_count: projects.filter((p) => p.targetId != null).length,
|
|
500
|
+
has_recommendation: recommended !== void 0,
|
|
501
|
+
recommended_path: recommended?.path ?? null,
|
|
502
|
+
projects
|
|
503
|
+
};
|
|
504
|
+
const project = chooseIntegrationProject(projects);
|
|
505
|
+
if (!project) {
|
|
506
|
+
captureOutcome("no-project", scanProperties);
|
|
507
|
+
getUI().log.info("The scan found no supported project; continuing with the install dir as-is.");
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
session.installDir = resolveProjectDir(session.installDir, project.path);
|
|
511
|
+
captureOutcome(project.recommended ? "recommended" : "first-instrumentable", {
|
|
512
|
+
...scanProperties,
|
|
513
|
+
chosen_framework: project.targetId,
|
|
514
|
+
chosen_path: project.path
|
|
515
|
+
});
|
|
516
|
+
getUI().log.info(`Continuing with ${project.path} (${project.framework}).`);
|
|
517
|
+
}
|
|
518
|
+
//#endregion
|
|
519
|
+
//#region src/lib/warehouse-sources/registry.ts
|
|
520
|
+
const SOURCE_DETECTORS = [
|
|
521
|
+
{
|
|
522
|
+
kind: "Postgres",
|
|
523
|
+
label: "PostgreSQL",
|
|
524
|
+
mode: "in-cli",
|
|
525
|
+
signals: {
|
|
526
|
+
npm: [
|
|
527
|
+
"pg",
|
|
528
|
+
"postgres",
|
|
529
|
+
"postgres.js",
|
|
530
|
+
"knex",
|
|
531
|
+
"sequelize"
|
|
532
|
+
],
|
|
533
|
+
python: [
|
|
534
|
+
"psycopg",
|
|
535
|
+
"psycopg2",
|
|
536
|
+
"psycopg2-binary",
|
|
537
|
+
"asyncpg"
|
|
538
|
+
],
|
|
539
|
+
ruby: ["pg"],
|
|
540
|
+
envKeys: [
|
|
541
|
+
/^DATABASE_URL$/,
|
|
542
|
+
/^POSTGRES_/,
|
|
543
|
+
/^PG(HOST|DATABASE|USER|PORT)$/
|
|
544
|
+
]
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
kind: "MySQL",
|
|
549
|
+
label: "MySQL",
|
|
550
|
+
mode: "in-cli",
|
|
551
|
+
signals: {
|
|
552
|
+
npm: ["mysql", "mysql2"],
|
|
553
|
+
python: [
|
|
554
|
+
"pymysql",
|
|
555
|
+
"mysqlclient",
|
|
556
|
+
"mysql-connector-python"
|
|
557
|
+
],
|
|
558
|
+
ruby: ["mysql2"],
|
|
559
|
+
envKeys: [/^MYSQL_/]
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
kind: "MongoDB",
|
|
564
|
+
label: "MongoDB",
|
|
565
|
+
mode: "in-cli",
|
|
566
|
+
signals: {
|
|
567
|
+
npm: ["mongodb", "mongoose"],
|
|
568
|
+
python: ["pymongo", "motor"],
|
|
569
|
+
ruby: ["mongo", "mongoid"],
|
|
570
|
+
envKeys: [/^MONGO(DB)?_/]
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
kind: "Snowflake",
|
|
575
|
+
label: "Snowflake",
|
|
576
|
+
mode: "in-cli",
|
|
577
|
+
signals: {
|
|
578
|
+
npm: ["snowflake-sdk"],
|
|
579
|
+
python: ["snowflake-connector-python", "snowflake-sqlalchemy"],
|
|
580
|
+
envKeys: [/^SNOWFLAKE_/]
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
kind: "BigQuery",
|
|
585
|
+
label: "BigQuery",
|
|
586
|
+
mode: "in-cli",
|
|
587
|
+
signals: {
|
|
588
|
+
npm: ["@google-cloud/bigquery"],
|
|
589
|
+
python: ["google-cloud-bigquery"],
|
|
590
|
+
envKeys: [/^BIGQUERY_/]
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
kind: "Redshift",
|
|
595
|
+
label: "Redshift",
|
|
596
|
+
mode: "in-cli",
|
|
597
|
+
signals: {
|
|
598
|
+
npm: ["node-redshift"],
|
|
599
|
+
python: ["redshift-connector"],
|
|
600
|
+
envKeys: [/^REDSHIFT_/]
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
kind: "MSSQL",
|
|
605
|
+
label: "SQL Server",
|
|
606
|
+
mode: "in-cli",
|
|
607
|
+
signals: {
|
|
608
|
+
npm: ["mssql", "tedious"],
|
|
609
|
+
python: ["pyodbc", "pymssql"],
|
|
610
|
+
envKeys: [/^MSSQL_/]
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
kind: "Supabase",
|
|
615
|
+
label: "Supabase",
|
|
616
|
+
mode: "in-cli",
|
|
617
|
+
signals: {
|
|
618
|
+
npm: ["@supabase/supabase-js"],
|
|
619
|
+
python: ["supabase"],
|
|
620
|
+
envKeys: [/^SUPABASE_/]
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
kind: "ClickHouse",
|
|
625
|
+
label: "ClickHouse",
|
|
626
|
+
mode: "in-cli",
|
|
627
|
+
signals: {
|
|
628
|
+
npm: ["@clickhouse/client"],
|
|
629
|
+
python: ["clickhouse-connect", "clickhouse-driver"],
|
|
630
|
+
envKeys: [/^CLICKHOUSE_/]
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
kind: "Convex",
|
|
635
|
+
label: "Convex",
|
|
636
|
+
mode: "in-cli",
|
|
637
|
+
signals: {
|
|
638
|
+
npm: ["convex"],
|
|
639
|
+
python: ["convex"],
|
|
640
|
+
envKeys: [/^CONVEX_/, /^NEXT_PUBLIC_CONVEX_URL$/]
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
kind: "Stripe",
|
|
645
|
+
label: "Stripe",
|
|
646
|
+
mode: "in-cli",
|
|
647
|
+
signals: {
|
|
648
|
+
npm: [
|
|
649
|
+
"stripe",
|
|
650
|
+
"@stripe/stripe-js",
|
|
651
|
+
"@stripe/react-stripe-js"
|
|
652
|
+
],
|
|
653
|
+
python: ["stripe"],
|
|
654
|
+
ruby: ["stripe"],
|
|
655
|
+
envKeys: [/^STRIPE_(SECRET|API)_KEY$/]
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
kind: "Clerk",
|
|
660
|
+
label: "Clerk",
|
|
661
|
+
mode: "in-cli",
|
|
662
|
+
signals: {
|
|
663
|
+
npm: [
|
|
664
|
+
"@clerk/nextjs",
|
|
665
|
+
"@clerk/clerk-react",
|
|
666
|
+
"@clerk/backend",
|
|
667
|
+
"@clerk/express",
|
|
668
|
+
"@clerk/fastify",
|
|
669
|
+
"@clerk/remix"
|
|
670
|
+
],
|
|
671
|
+
envKeys: [/^CLERK_SECRET_KEY$/, /^NEXT_PUBLIC_CLERK_/]
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
kind: "Resend",
|
|
676
|
+
label: "Resend",
|
|
677
|
+
mode: "in-cli",
|
|
678
|
+
signals: {
|
|
679
|
+
npm: ["resend"],
|
|
680
|
+
python: ["resend"],
|
|
681
|
+
envKeys: [/^RESEND_API_KEY$/]
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
kind: "Shopify",
|
|
686
|
+
label: "Shopify",
|
|
687
|
+
mode: "in-cli",
|
|
688
|
+
signals: {
|
|
689
|
+
npm: ["@shopify/shopify-api", "shopify-api-node"],
|
|
690
|
+
python: ["shopifyapi"],
|
|
691
|
+
envKeys: [/^SHOPIFY_/]
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
kind: "Klaviyo",
|
|
696
|
+
label: "Klaviyo",
|
|
697
|
+
mode: "in-cli",
|
|
698
|
+
signals: {
|
|
699
|
+
npm: ["klaviyo-api"],
|
|
700
|
+
python: ["klaviyo-api"],
|
|
701
|
+
envKeys: [/^KLAVIYO_/]
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
kind: "Chargebee",
|
|
706
|
+
label: "Chargebee",
|
|
707
|
+
mode: "in-cli",
|
|
708
|
+
signals: {
|
|
709
|
+
npm: ["chargebee"],
|
|
710
|
+
python: ["chargebee"],
|
|
711
|
+
envKeys: [/^CHARGEBEE_/]
|
|
712
|
+
}
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
kind: "Paddle",
|
|
716
|
+
label: "Paddle",
|
|
717
|
+
mode: "in-cli",
|
|
718
|
+
signals: {
|
|
719
|
+
npm: ["@paddle/paddle-node-sdk", "@paddle/paddle-js"],
|
|
720
|
+
envKeys: [/^PADDLE_/]
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
kind: "Polar",
|
|
725
|
+
label: "Polar",
|
|
726
|
+
mode: "in-cli",
|
|
727
|
+
signals: {
|
|
728
|
+
npm: ["@polar-sh/sdk", "@polar-sh/nextjs"],
|
|
729
|
+
envKeys: [/^POLAR_/]
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
kind: "Mailchimp",
|
|
734
|
+
label: "Mailchimp",
|
|
735
|
+
mode: "in-cli",
|
|
736
|
+
signals: {
|
|
737
|
+
npm: ["@mailchimp/mailchimp_marketing"],
|
|
738
|
+
python: ["mailchimp-marketing"],
|
|
739
|
+
envKeys: [/^MAILCHIMP_/]
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
kind: "CustomerIO",
|
|
744
|
+
label: "Customer.io",
|
|
745
|
+
mode: "in-cli",
|
|
746
|
+
signals: {
|
|
747
|
+
npm: ["customerio-node"],
|
|
748
|
+
python: ["customerio"],
|
|
749
|
+
envKeys: [/^CUSTOMER_?IO_/]
|
|
750
|
+
}
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
kind: "Typeform",
|
|
754
|
+
label: "Typeform",
|
|
755
|
+
mode: "in-cli",
|
|
756
|
+
signals: {
|
|
757
|
+
npm: ["@typeform/api-client"],
|
|
758
|
+
envKeys: [/^TYPEFORM_/]
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
kind: "Sentry",
|
|
763
|
+
label: "Sentry",
|
|
764
|
+
mode: "in-cli",
|
|
765
|
+
signals: {
|
|
766
|
+
npm: [
|
|
767
|
+
"@sentry/node",
|
|
768
|
+
"@sentry/browser",
|
|
769
|
+
"@sentry/react",
|
|
770
|
+
"@sentry/nextjs"
|
|
771
|
+
],
|
|
772
|
+
python: ["sentry-sdk"],
|
|
773
|
+
ruby: ["sentry-ruby"]
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
kind: "Plaid",
|
|
778
|
+
label: "Plaid",
|
|
779
|
+
mode: "in-cli",
|
|
780
|
+
signals: {
|
|
781
|
+
npm: ["plaid"],
|
|
782
|
+
python: ["plaid-python", "plaid"],
|
|
783
|
+
ruby: ["plaid"],
|
|
784
|
+
envKeys: [/^PLAID_/]
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
kind: "Braintree",
|
|
789
|
+
label: "Braintree",
|
|
790
|
+
mode: "in-cli",
|
|
791
|
+
signals: {
|
|
792
|
+
npm: ["braintree"],
|
|
793
|
+
python: ["braintree"],
|
|
794
|
+
ruby: ["braintree"],
|
|
795
|
+
envKeys: [/^BRAINTREE_/]
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
kind: "Square",
|
|
800
|
+
label: "Square",
|
|
801
|
+
mode: "in-cli",
|
|
802
|
+
signals: {
|
|
803
|
+
npm: ["square"],
|
|
804
|
+
python: ["squareup"],
|
|
805
|
+
ruby: ["square"],
|
|
806
|
+
envKeys: [/^SQUARE_/]
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
kind: "GoCardless",
|
|
811
|
+
label: "GoCardless",
|
|
812
|
+
mode: "in-cli",
|
|
813
|
+
signals: {
|
|
814
|
+
npm: ["gocardless-nodejs"],
|
|
815
|
+
python: ["gocardless-pro"],
|
|
816
|
+
ruby: ["gocardless_pro"],
|
|
817
|
+
envKeys: [/^GOCARDLESS_/]
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
kind: "Mollie",
|
|
822
|
+
label: "Mollie",
|
|
823
|
+
mode: "in-cli",
|
|
824
|
+
signals: {
|
|
825
|
+
npm: ["@mollie/api-client"],
|
|
826
|
+
python: ["mollie-api-python"],
|
|
827
|
+
envKeys: [/^MOLLIE_/]
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
kind: "CheckoutCom",
|
|
832
|
+
label: "Checkout.com",
|
|
833
|
+
mode: "in-cli",
|
|
834
|
+
signals: {
|
|
835
|
+
npm: ["checkout-sdk-node"],
|
|
836
|
+
python: ["checkout-sdk"],
|
|
837
|
+
envKeys: [/^CKO_/, /^CHECKOUT_COM_/]
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
kind: "Recurly",
|
|
842
|
+
label: "Recurly",
|
|
843
|
+
mode: "in-cli",
|
|
844
|
+
signals: {
|
|
845
|
+
npm: ["recurly"],
|
|
846
|
+
python: ["recurly"],
|
|
847
|
+
ruby: ["recurly"],
|
|
848
|
+
envKeys: [/^RECURLY_/]
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
kind: "RevenueCat",
|
|
853
|
+
label: "RevenueCat",
|
|
854
|
+
mode: "in-cli",
|
|
855
|
+
signals: {
|
|
856
|
+
npm: [
|
|
857
|
+
"@revenuecat/purchases-js",
|
|
858
|
+
"react-native-purchases",
|
|
859
|
+
"@revenuecat/purchases-capacitor"
|
|
860
|
+
],
|
|
861
|
+
envKeys: [/^REVENUE_?CAT_/]
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
kind: "Twilio",
|
|
866
|
+
label: "Twilio",
|
|
867
|
+
mode: "in-cli",
|
|
868
|
+
signals: {
|
|
869
|
+
npm: ["twilio"],
|
|
870
|
+
python: ["twilio"],
|
|
871
|
+
ruby: ["twilio-ruby"],
|
|
872
|
+
envKeys: [/^TWILIO_/]
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
kind: "SendGrid",
|
|
877
|
+
label: "SendGrid",
|
|
878
|
+
mode: "in-cli",
|
|
879
|
+
signals: {
|
|
880
|
+
npm: ["@sendgrid/mail", "@sendgrid/client"],
|
|
881
|
+
python: ["sendgrid"],
|
|
882
|
+
ruby: ["sendgrid-ruby"],
|
|
883
|
+
envKeys: [/^SENDGRID_/]
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
kind: "Mailgun",
|
|
888
|
+
label: "Mailgun",
|
|
889
|
+
mode: "in-cli",
|
|
890
|
+
signals: {
|
|
891
|
+
npm: ["mailgun.js", "mailgun-js"],
|
|
892
|
+
python: ["mailgun"],
|
|
893
|
+
ruby: ["mailgun-ruby"],
|
|
894
|
+
envKeys: [/^MAILGUN_/]
|
|
895
|
+
}
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
kind: "Postmark",
|
|
899
|
+
label: "Postmark",
|
|
900
|
+
mode: "in-cli",
|
|
901
|
+
signals: {
|
|
902
|
+
npm: ["postmark"],
|
|
903
|
+
python: ["postmarker"],
|
|
904
|
+
ruby: ["postmark"],
|
|
905
|
+
envKeys: [/^POSTMARK_/]
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
kind: "Brevo",
|
|
910
|
+
label: "Brevo",
|
|
911
|
+
mode: "in-cli",
|
|
912
|
+
signals: {
|
|
913
|
+
npm: ["@getbrevo/brevo", "sib-api-v3-sdk"],
|
|
914
|
+
python: ["sib-api-v3-sdk"],
|
|
915
|
+
envKeys: [/^BREVO_/]
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
kind: "MailerLite",
|
|
920
|
+
label: "MailerLite",
|
|
921
|
+
mode: "in-cli",
|
|
922
|
+
signals: {
|
|
923
|
+
npm: ["@mailerlite/mailerlite-nodejs"],
|
|
924
|
+
python: ["mailerlite"],
|
|
925
|
+
envKeys: [/^MAILERLITE_/]
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
kind: "Mailjet",
|
|
930
|
+
label: "Mailjet",
|
|
931
|
+
mode: "in-cli",
|
|
932
|
+
signals: {
|
|
933
|
+
npm: ["node-mailjet"],
|
|
934
|
+
python: ["mailjet-rest"],
|
|
935
|
+
envKeys: [/^MAILJET_/, /^MJ_APIKEY_/]
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
kind: "LaunchDarkly",
|
|
940
|
+
label: "LaunchDarkly",
|
|
941
|
+
mode: "in-cli",
|
|
942
|
+
signals: {
|
|
943
|
+
npm: [
|
|
944
|
+
"launchdarkly-node-server-sdk",
|
|
945
|
+
"@launchdarkly/node-server-sdk",
|
|
946
|
+
"launchdarkly-js-client-sdk",
|
|
947
|
+
"launchdarkly-react-client-sdk"
|
|
948
|
+
],
|
|
949
|
+
python: ["launchdarkly-server-sdk"],
|
|
950
|
+
ruby: ["launchdarkly-server-sdk"],
|
|
951
|
+
envKeys: [/^LAUNCHDARKLY_/, /^LD_SDK_KEY$/]
|
|
952
|
+
}
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
kind: "Optimizely",
|
|
956
|
+
label: "Optimizely",
|
|
957
|
+
mode: "in-cli",
|
|
958
|
+
signals: {
|
|
959
|
+
npm: ["@optimizely/optimizely-sdk"],
|
|
960
|
+
python: ["optimizely-sdk"],
|
|
961
|
+
envKeys: [/^OPTIMIZELY_/]
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
kind: "Braze",
|
|
966
|
+
label: "Braze",
|
|
967
|
+
mode: "in-cli",
|
|
968
|
+
signals: {
|
|
969
|
+
npm: ["@braze/web-sdk", "@braze/react-native-sdk"],
|
|
970
|
+
python: ["braze-client"],
|
|
971
|
+
envKeys: [/^BRAZE_/]
|
|
972
|
+
}
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
kind: "Rollbar",
|
|
976
|
+
label: "Rollbar",
|
|
977
|
+
mode: "in-cli",
|
|
978
|
+
signals: {
|
|
979
|
+
npm: ["rollbar"],
|
|
980
|
+
python: ["rollbar", "pyrollbar"],
|
|
981
|
+
ruby: ["rollbar"],
|
|
982
|
+
envKeys: [/^ROLLBAR_/]
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
kind: "Okta",
|
|
987
|
+
label: "Okta",
|
|
988
|
+
mode: "in-cli",
|
|
989
|
+
signals: {
|
|
990
|
+
npm: [
|
|
991
|
+
"@okta/okta-sdk-nodejs",
|
|
992
|
+
"@okta/okta-auth-js",
|
|
993
|
+
"@okta/okta-react"
|
|
994
|
+
],
|
|
995
|
+
python: ["okta"],
|
|
996
|
+
envKeys: [/^OKTA_/]
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
kind: "WorkOS",
|
|
1001
|
+
label: "WorkOS",
|
|
1002
|
+
mode: "in-cli",
|
|
1003
|
+
signals: {
|
|
1004
|
+
npm: ["@workos-inc/node"],
|
|
1005
|
+
python: ["workos"],
|
|
1006
|
+
envKeys: [/^WORKOS_/]
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
kind: "Notion",
|
|
1011
|
+
label: "Notion",
|
|
1012
|
+
mode: "in-cli",
|
|
1013
|
+
signals: {
|
|
1014
|
+
npm: ["@notionhq/client"],
|
|
1015
|
+
python: ["notion-client"],
|
|
1016
|
+
envKeys: [/^NOTION_/]
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
kind: "FullStory",
|
|
1021
|
+
label: "FullStory",
|
|
1022
|
+
mode: "in-cli",
|
|
1023
|
+
signals: {
|
|
1024
|
+
npm: ["@fullstory/browser", "@fullstory/react-native"],
|
|
1025
|
+
envKeys: [/^FULLSTORY_/]
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
kind: "Amplitude",
|
|
1030
|
+
label: "Amplitude",
|
|
1031
|
+
mode: "in-cli",
|
|
1032
|
+
signals: {
|
|
1033
|
+
npm: [
|
|
1034
|
+
"@amplitude/analytics-browser",
|
|
1035
|
+
"@amplitude/analytics-node",
|
|
1036
|
+
"@amplitude/analytics-react-native",
|
|
1037
|
+
"amplitude-js"
|
|
1038
|
+
],
|
|
1039
|
+
python: ["amplitude-analytics"],
|
|
1040
|
+
envKeys: [/^AMPLITUDE_/]
|
|
1041
|
+
}
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
kind: "Mixpanel",
|
|
1045
|
+
label: "Mixpanel",
|
|
1046
|
+
mode: "in-cli",
|
|
1047
|
+
signals: {
|
|
1048
|
+
npm: ["mixpanel", "mixpanel-browser"],
|
|
1049
|
+
python: ["mixpanel"],
|
|
1050
|
+
ruby: ["mixpanel-ruby"],
|
|
1051
|
+
envKeys: [/^MIXPANEL_/]
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
kind: "Pendo",
|
|
1056
|
+
label: "Pendo",
|
|
1057
|
+
mode: "in-cli",
|
|
1058
|
+
signals: {
|
|
1059
|
+
npm: ["@pendo/agent"],
|
|
1060
|
+
envKeys: [/^PENDO_/]
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
kind: "Salesforce",
|
|
1065
|
+
label: "Salesforce",
|
|
1066
|
+
mode: "deep-link",
|
|
1067
|
+
signals: {
|
|
1068
|
+
npm: ["jsforce"],
|
|
1069
|
+
python: ["simple-salesforce"],
|
|
1070
|
+
envKeys: [/^SALESFORCE_/]
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
kind: "Hubspot",
|
|
1075
|
+
label: "HubSpot",
|
|
1076
|
+
mode: "deep-link",
|
|
1077
|
+
signals: {
|
|
1078
|
+
npm: ["@hubspot/api-client"],
|
|
1079
|
+
python: ["hubspot-api-client"],
|
|
1080
|
+
envKeys: [/^HUBSPOT_/]
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
kind: "Zendesk",
|
|
1085
|
+
label: "Zendesk",
|
|
1086
|
+
mode: "deep-link",
|
|
1087
|
+
signals: {
|
|
1088
|
+
npm: ["node-zendesk"],
|
|
1089
|
+
python: ["zenpy"],
|
|
1090
|
+
envKeys: [/^ZENDESK_/]
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
kind: "Intercom",
|
|
1095
|
+
label: "Intercom",
|
|
1096
|
+
mode: "deep-link",
|
|
1097
|
+
signals: {
|
|
1098
|
+
npm: ["intercom-client", "@intercom/messenger-js-sdk"],
|
|
1099
|
+
python: ["python-intercom"],
|
|
1100
|
+
envKeys: [/^INTERCOM_/]
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
kind: "Linear",
|
|
1105
|
+
label: "Linear",
|
|
1106
|
+
mode: "deep-link",
|
|
1107
|
+
signals: {
|
|
1108
|
+
npm: ["@linear/sdk"],
|
|
1109
|
+
envKeys: [/^LINEAR_API_KEY$/]
|
|
1110
|
+
}
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
kind: "Slack",
|
|
1114
|
+
label: "Slack",
|
|
1115
|
+
mode: "deep-link",
|
|
1116
|
+
signals: {
|
|
1117
|
+
npm: ["@slack/web-api", "@slack/bolt"],
|
|
1118
|
+
python: ["slack-sdk", "slack-bolt"],
|
|
1119
|
+
envKeys: [/^SLACK_(BOT|APP|SIGNING|CLIENT)_/]
|
|
1120
|
+
}
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
kind: "Github",
|
|
1124
|
+
label: "GitHub",
|
|
1125
|
+
mode: "deep-link",
|
|
1126
|
+
signals: {
|
|
1127
|
+
npm: [
|
|
1128
|
+
"@octokit/rest",
|
|
1129
|
+
"@octokit/core",
|
|
1130
|
+
"@octokit/graphql",
|
|
1131
|
+
"octokit"
|
|
1132
|
+
],
|
|
1133
|
+
python: ["pygithub"],
|
|
1134
|
+
ruby: ["octokit"]
|
|
1135
|
+
}
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
kind: "OpenAI",
|
|
1139
|
+
label: "OpenAI",
|
|
1140
|
+
mode: "in-cli",
|
|
1141
|
+
signals: {
|
|
1142
|
+
npm: ["openai"],
|
|
1143
|
+
python: ["openai"],
|
|
1144
|
+
envKeys: [/^OPENAI_/]
|
|
1145
|
+
}
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
kind: "Anthropic",
|
|
1149
|
+
label: "Anthropic",
|
|
1150
|
+
mode: "in-cli",
|
|
1151
|
+
signals: {
|
|
1152
|
+
npm: ["@anthropic-ai/sdk"],
|
|
1153
|
+
python: ["anthropic"],
|
|
1154
|
+
envKeys: [/^ANTHROPIC_/]
|
|
1155
|
+
}
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
kind: "Cohere",
|
|
1159
|
+
label: "Cohere",
|
|
1160
|
+
mode: "in-cli",
|
|
1161
|
+
signals: {
|
|
1162
|
+
npm: ["cohere-ai"],
|
|
1163
|
+
python: ["cohere"],
|
|
1164
|
+
envKeys: [/^COHERE_/]
|
|
1165
|
+
}
|
|
1166
|
+
},
|
|
1167
|
+
{
|
|
1168
|
+
kind: "MistralAI",
|
|
1169
|
+
label: "Mistral AI",
|
|
1170
|
+
mode: "in-cli",
|
|
1171
|
+
signals: {
|
|
1172
|
+
npm: ["@mistralai/mistralai"],
|
|
1173
|
+
python: ["mistralai"],
|
|
1174
|
+
envKeys: [/^MISTRAL_/]
|
|
1175
|
+
}
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
kind: "Groq",
|
|
1179
|
+
label: "Groq",
|
|
1180
|
+
mode: "in-cli",
|
|
1181
|
+
signals: {
|
|
1182
|
+
npm: ["groq-sdk"],
|
|
1183
|
+
python: ["groq"],
|
|
1184
|
+
envKeys: [/^GROQ_/]
|
|
1185
|
+
}
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
kind: "TogetherAI",
|
|
1189
|
+
label: "Together AI",
|
|
1190
|
+
mode: "in-cli",
|
|
1191
|
+
signals: {
|
|
1192
|
+
npm: ["together-ai"],
|
|
1193
|
+
python: ["together"],
|
|
1194
|
+
envKeys: [/^TOGETHER_/]
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
kind: "FireworksAI",
|
|
1199
|
+
label: "Fireworks AI",
|
|
1200
|
+
mode: "in-cli",
|
|
1201
|
+
signals: {
|
|
1202
|
+
python: ["fireworks-ai"],
|
|
1203
|
+
envKeys: [/^FIREWORKS_/]
|
|
1204
|
+
}
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
kind: "Replicate",
|
|
1208
|
+
label: "Replicate",
|
|
1209
|
+
mode: "in-cli",
|
|
1210
|
+
signals: {
|
|
1211
|
+
npm: ["replicate"],
|
|
1212
|
+
python: ["replicate"],
|
|
1213
|
+
envKeys: [/^REPLICATE_/]
|
|
1214
|
+
}
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
kind: "HuggingFace",
|
|
1218
|
+
label: "Hugging Face",
|
|
1219
|
+
mode: "in-cli",
|
|
1220
|
+
signals: {
|
|
1221
|
+
npm: ["@huggingface/inference"],
|
|
1222
|
+
python: ["huggingface-hub"],
|
|
1223
|
+
envKeys: [/^HUGGINGFACE_/, /^HF_TOKEN$/]
|
|
1224
|
+
}
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
kind: "ElevenLabs",
|
|
1228
|
+
label: "ElevenLabs",
|
|
1229
|
+
mode: "in-cli",
|
|
1230
|
+
signals: {
|
|
1231
|
+
npm: ["@elevenlabs/elevenlabs-js", "elevenlabs"],
|
|
1232
|
+
python: ["elevenlabs"],
|
|
1233
|
+
envKeys: [/^ELEVENLABS_/, /^ELEVEN_LABS_/]
|
|
1234
|
+
}
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
kind: "Deepgram",
|
|
1238
|
+
label: "Deepgram",
|
|
1239
|
+
mode: "in-cli",
|
|
1240
|
+
signals: {
|
|
1241
|
+
npm: ["@deepgram/sdk"],
|
|
1242
|
+
python: ["deepgram-sdk"],
|
|
1243
|
+
envKeys: [/^DEEPGRAM_/]
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1246
|
+
{
|
|
1247
|
+
kind: "AssemblyAI",
|
|
1248
|
+
label: "AssemblyAI",
|
|
1249
|
+
mode: "in-cli",
|
|
1250
|
+
signals: {
|
|
1251
|
+
npm: ["assemblyai"],
|
|
1252
|
+
python: ["assemblyai"],
|
|
1253
|
+
envKeys: [/^ASSEMBLYAI_/]
|
|
1254
|
+
}
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
kind: "Langfuse",
|
|
1258
|
+
label: "Langfuse",
|
|
1259
|
+
mode: "in-cli",
|
|
1260
|
+
signals: {
|
|
1261
|
+
npm: ["langfuse"],
|
|
1262
|
+
python: ["langfuse"],
|
|
1263
|
+
envKeys: [/^LANGFUSE_/]
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
kind: "LangSmith",
|
|
1268
|
+
label: "LangSmith",
|
|
1269
|
+
mode: "in-cli",
|
|
1270
|
+
signals: {
|
|
1271
|
+
npm: ["langsmith"],
|
|
1272
|
+
python: ["langsmith"],
|
|
1273
|
+
envKeys: [/^LANGSMITH_/, /^LANGCHAIN_API_KEY$/]
|
|
1274
|
+
}
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
kind: "Firecrawl",
|
|
1278
|
+
label: "Firecrawl",
|
|
1279
|
+
mode: "in-cli",
|
|
1280
|
+
signals: {
|
|
1281
|
+
npm: ["@mendable/firecrawl-js"],
|
|
1282
|
+
python: ["firecrawl-py"],
|
|
1283
|
+
envKeys: [/^FIRECRAWL_/]
|
|
1284
|
+
}
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
kind: "Mem0",
|
|
1288
|
+
label: "Mem0",
|
|
1289
|
+
mode: "in-cli",
|
|
1290
|
+
signals: {
|
|
1291
|
+
npm: ["mem0ai"],
|
|
1292
|
+
python: ["mem0ai"],
|
|
1293
|
+
envKeys: [/^MEM0_/]
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
kind: "Vellum",
|
|
1298
|
+
label: "Vellum",
|
|
1299
|
+
mode: "in-cli",
|
|
1300
|
+
signals: {
|
|
1301
|
+
npm: ["vellum-ai"],
|
|
1302
|
+
python: ["vellum-ai"],
|
|
1303
|
+
envKeys: [/^VELLUM_/]
|
|
1304
|
+
}
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
kind: "Helicone",
|
|
1308
|
+
label: "Helicone",
|
|
1309
|
+
mode: "in-cli",
|
|
1310
|
+
signals: {
|
|
1311
|
+
npm: ["@helicone/helpers"],
|
|
1312
|
+
envKeys: [/^HELICONE_/]
|
|
1313
|
+
}
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
kind: "OpenRouter",
|
|
1317
|
+
label: "OpenRouter",
|
|
1318
|
+
mode: "in-cli",
|
|
1319
|
+
signals: {
|
|
1320
|
+
npm: ["@openrouter/ai-sdk-provider"],
|
|
1321
|
+
envKeys: [/^OPENROUTER_/]
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
kind: "Paystack",
|
|
1326
|
+
label: "Paystack",
|
|
1327
|
+
mode: "in-cli",
|
|
1328
|
+
signals: {
|
|
1329
|
+
python: ["paystackapi"],
|
|
1330
|
+
envKeys: [/^PAYSTACK_/]
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
{
|
|
1334
|
+
kind: "Orb",
|
|
1335
|
+
label: "Orb",
|
|
1336
|
+
mode: "in-cli",
|
|
1337
|
+
signals: {
|
|
1338
|
+
npm: ["orb-billing"],
|
|
1339
|
+
python: ["orb-billing"],
|
|
1340
|
+
envKeys: [/^ORB_/]
|
|
1341
|
+
}
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
kind: "Lago",
|
|
1345
|
+
label: "Lago",
|
|
1346
|
+
mode: "in-cli",
|
|
1347
|
+
signals: {
|
|
1348
|
+
npm: ["lago-javascript-client"],
|
|
1349
|
+
python: ["lago-python-client"],
|
|
1350
|
+
envKeys: [/^LAGO_/]
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
kind: "Zuora",
|
|
1355
|
+
label: "Zuora",
|
|
1356
|
+
mode: "in-cli",
|
|
1357
|
+
signals: { envKeys: [/^ZUORA_/] }
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
kind: "Stigg",
|
|
1361
|
+
label: "Stigg",
|
|
1362
|
+
mode: "in-cli",
|
|
1363
|
+
signals: {
|
|
1364
|
+
npm: ["@stigg/node-server-sdk"],
|
|
1365
|
+
envKeys: [/^STIGG_/]
|
|
1366
|
+
}
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
kind: "Ramp",
|
|
1370
|
+
label: "Ramp",
|
|
1371
|
+
mode: "in-cli",
|
|
1372
|
+
signals: { envKeys: [/^RAMP_/] }
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
kind: "Brex",
|
|
1376
|
+
label: "Brex",
|
|
1377
|
+
mode: "in-cli",
|
|
1378
|
+
signals: { envKeys: [/^BREX_/] }
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
kind: "Tremendous",
|
|
1382
|
+
label: "Tremendous",
|
|
1383
|
+
mode: "in-cli",
|
|
1384
|
+
signals: { envKeys: [/^TREMENDOUS_/] }
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
kind: "Maxio",
|
|
1388
|
+
label: "Maxio",
|
|
1389
|
+
mode: "in-cli",
|
|
1390
|
+
signals: { envKeys: [/^MAXIO_/] }
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
kind: "Chargify",
|
|
1394
|
+
label: "Chargify",
|
|
1395
|
+
mode: "in-cli",
|
|
1396
|
+
signals: { envKeys: [/^CHARGIFY_/] }
|
|
1397
|
+
},
|
|
1398
|
+
{
|
|
1399
|
+
kind: "Invoiced",
|
|
1400
|
+
label: "Invoiced",
|
|
1401
|
+
mode: "in-cli",
|
|
1402
|
+
signals: {
|
|
1403
|
+
npm: ["invoiced"],
|
|
1404
|
+
python: ["invoiced"],
|
|
1405
|
+
envKeys: [/^INVOICED_/]
|
|
1406
|
+
}
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
kind: "SparkPost",
|
|
1410
|
+
label: "SparkPost",
|
|
1411
|
+
mode: "in-cli",
|
|
1412
|
+
signals: {
|
|
1413
|
+
npm: ["sparkpost"],
|
|
1414
|
+
python: ["sparkpost"],
|
|
1415
|
+
envKeys: [/^SPARKPOST_/]
|
|
1416
|
+
}
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
kind: "MailerSend",
|
|
1420
|
+
label: "MailerSend",
|
|
1421
|
+
mode: "in-cli",
|
|
1422
|
+
signals: {
|
|
1423
|
+
npm: ["mailersend"],
|
|
1424
|
+
python: ["mailersend"],
|
|
1425
|
+
envKeys: [/^MAILERSEND_/]
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
kind: "Iterable",
|
|
1430
|
+
label: "Iterable",
|
|
1431
|
+
mode: "in-cli",
|
|
1432
|
+
signals: { envKeys: [/^ITERABLE_/] }
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
kind: "ConvertKit",
|
|
1436
|
+
label: "ConvertKit",
|
|
1437
|
+
mode: "in-cli",
|
|
1438
|
+
signals: { envKeys: [/^CONVERTKIT_/] }
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
kind: "Drip",
|
|
1442
|
+
label: "Drip",
|
|
1443
|
+
mode: "in-cli",
|
|
1444
|
+
signals: {
|
|
1445
|
+
npm: ["drip-nodejs"],
|
|
1446
|
+
envKeys: [/^DRIP_/]
|
|
1447
|
+
}
|
|
1448
|
+
},
|
|
1449
|
+
{
|
|
1450
|
+
kind: "Omnisend",
|
|
1451
|
+
label: "Omnisend",
|
|
1452
|
+
mode: "in-cli",
|
|
1453
|
+
signals: { envKeys: [/^OMNISEND_/] }
|
|
1454
|
+
},
|
|
1455
|
+
{
|
|
1456
|
+
kind: "EmailOctopus",
|
|
1457
|
+
label: "EmailOctopus",
|
|
1458
|
+
mode: "in-cli",
|
|
1459
|
+
signals: { envKeys: [/^EMAILOCTOPUS_/, /^EMAIL_OCTOPUS_/] }
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
kind: "Elasticemail",
|
|
1463
|
+
label: "Elastic Email",
|
|
1464
|
+
mode: "in-cli",
|
|
1465
|
+
signals: { envKeys: [/^ELASTICEMAIL_/, /^ELASTIC_EMAIL_/] }
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
kind: "CampaignMonitor",
|
|
1469
|
+
label: "Campaign Monitor",
|
|
1470
|
+
mode: "in-cli",
|
|
1471
|
+
signals: {
|
|
1472
|
+
npm: ["createsend-node"],
|
|
1473
|
+
envKeys: [/^CAMPAIGN_MONITOR_/, /^CREATESEND_/]
|
|
1474
|
+
}
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
kind: "Lemlist",
|
|
1478
|
+
label: "Lemlist",
|
|
1479
|
+
mode: "in-cli",
|
|
1480
|
+
signals: { envKeys: [/^LEMLIST_/] }
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
kind: "Segment",
|
|
1484
|
+
label: "Segment",
|
|
1485
|
+
mode: "in-cli",
|
|
1486
|
+
signals: {
|
|
1487
|
+
npm: ["@segment/analytics-node", "analytics-node"],
|
|
1488
|
+
python: ["segment-analytics-python", "analytics-python"],
|
|
1489
|
+
envKeys: [/^SEGMENT_/]
|
|
1490
|
+
}
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
kind: "Snowplow",
|
|
1494
|
+
label: "Snowplow Analytics",
|
|
1495
|
+
mode: "in-cli",
|
|
1496
|
+
signals: {
|
|
1497
|
+
npm: ["@snowplow/node-tracker"],
|
|
1498
|
+
python: ["snowplow-tracker"],
|
|
1499
|
+
envKeys: [/^SNOWPLOW_/]
|
|
1500
|
+
}
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
kind: "Matomo",
|
|
1504
|
+
label: "Matomo",
|
|
1505
|
+
mode: "in-cli",
|
|
1506
|
+
signals: {
|
|
1507
|
+
npm: ["matomo-tracker"],
|
|
1508
|
+
envKeys: [/^MATOMO_/]
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
kind: "Plausible",
|
|
1513
|
+
label: "Plausible",
|
|
1514
|
+
mode: "in-cli",
|
|
1515
|
+
signals: {
|
|
1516
|
+
npm: ["plausible-tracker"],
|
|
1517
|
+
envKeys: [/^PLAUSIBLE_/]
|
|
1518
|
+
}
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
kind: "ConfigCat",
|
|
1522
|
+
label: "ConfigCat",
|
|
1523
|
+
mode: "in-cli",
|
|
1524
|
+
signals: {
|
|
1525
|
+
npm: ["configcat-node", "configcat-js"],
|
|
1526
|
+
python: ["configcat-client"],
|
|
1527
|
+
envKeys: [/^CONFIGCAT_/]
|
|
1528
|
+
}
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
kind: "Flagsmith",
|
|
1532
|
+
label: "Flagsmith",
|
|
1533
|
+
mode: "in-cli",
|
|
1534
|
+
signals: {
|
|
1535
|
+
npm: ["flagsmith-nodejs", "flagsmith"],
|
|
1536
|
+
python: ["flagsmith"],
|
|
1537
|
+
envKeys: [/^FLAGSMITH_/]
|
|
1538
|
+
}
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
kind: "Unleash",
|
|
1542
|
+
label: "Unleash",
|
|
1543
|
+
mode: "in-cli",
|
|
1544
|
+
signals: {
|
|
1545
|
+
npm: ["unleash-client"],
|
|
1546
|
+
python: ["unleashclient"],
|
|
1547
|
+
envKeys: [/^UNLEASH_/]
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
kind: "SplitIo",
|
|
1552
|
+
label: "Split.io",
|
|
1553
|
+
mode: "in-cli",
|
|
1554
|
+
signals: {
|
|
1555
|
+
npm: ["@splitsoftware/splitio"],
|
|
1556
|
+
python: ["splitio-client"],
|
|
1557
|
+
envKeys: [/^SPLITIO_/, /^SPLIT_IO_/]
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
kind: "Stytch",
|
|
1562
|
+
label: "Stytch",
|
|
1563
|
+
mode: "in-cli",
|
|
1564
|
+
signals: {
|
|
1565
|
+
npm: ["stytch"],
|
|
1566
|
+
python: ["stytch"],
|
|
1567
|
+
envKeys: [/^STYTCH_/]
|
|
1568
|
+
}
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
kind: "Doppler",
|
|
1572
|
+
label: "Doppler",
|
|
1573
|
+
mode: "in-cli",
|
|
1574
|
+
signals: {
|
|
1575
|
+
npm: ["@dopplerhq/node-sdk"],
|
|
1576
|
+
envKeys: [/^DOPPLER_/]
|
|
1577
|
+
}
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
kind: "Infisical",
|
|
1581
|
+
label: "Infisical",
|
|
1582
|
+
mode: "in-cli",
|
|
1583
|
+
signals: {
|
|
1584
|
+
npm: ["@infisical/sdk"],
|
|
1585
|
+
python: ["infisicalsdk"],
|
|
1586
|
+
envKeys: [/^INFISICAL_/]
|
|
1587
|
+
}
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
kind: "OnePassword",
|
|
1591
|
+
label: "1Password",
|
|
1592
|
+
mode: "in-cli",
|
|
1593
|
+
signals: {
|
|
1594
|
+
npm: ["@1password/sdk"],
|
|
1595
|
+
python: ["onepassword-sdk"],
|
|
1596
|
+
envKeys: [/^ONEPASSWORD_/, /^OP_SERVICE_ACCOUNT_TOKEN$/]
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
kind: "Persona",
|
|
1601
|
+
label: "Persona",
|
|
1602
|
+
mode: "in-cli",
|
|
1603
|
+
signals: { envKeys: [/^PERSONA_/] }
|
|
1604
|
+
},
|
|
1605
|
+
{
|
|
1606
|
+
kind: "Svix",
|
|
1607
|
+
label: "Svix",
|
|
1608
|
+
mode: "in-cli",
|
|
1609
|
+
signals: {
|
|
1610
|
+
npm: ["svix"],
|
|
1611
|
+
python: ["svix"],
|
|
1612
|
+
envKeys: [/^SVIX_/]
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
kind: "Mux",
|
|
1617
|
+
label: "Mux",
|
|
1618
|
+
mode: "in-cli",
|
|
1619
|
+
signals: {
|
|
1620
|
+
npm: ["@mux/mux-node"],
|
|
1621
|
+
python: ["mux-python"],
|
|
1622
|
+
envKeys: [/^MUX_/]
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
kind: "Vapi",
|
|
1627
|
+
label: "Vapi",
|
|
1628
|
+
mode: "in-cli",
|
|
1629
|
+
signals: {
|
|
1630
|
+
npm: ["@vapi-ai/server-sdk"],
|
|
1631
|
+
python: ["vapi-server-sdk"],
|
|
1632
|
+
envKeys: [/^VAPI_/]
|
|
1633
|
+
}
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
kind: "Aircall",
|
|
1637
|
+
label: "Aircall",
|
|
1638
|
+
mode: "in-cli",
|
|
1639
|
+
signals: { envKeys: [/^AIRCALL_/] }
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
kind: "JustCall",
|
|
1643
|
+
label: "JustCall",
|
|
1644
|
+
mode: "in-cli",
|
|
1645
|
+
signals: { envKeys: [/^JUSTCALL_/] }
|
|
1646
|
+
},
|
|
1647
|
+
{
|
|
1648
|
+
kind: "WooCommerce",
|
|
1649
|
+
label: "WooCommerce",
|
|
1650
|
+
mode: "in-cli",
|
|
1651
|
+
signals: {
|
|
1652
|
+
npm: ["@woocommerce/woocommerce-rest-api"],
|
|
1653
|
+
python: ["woocommerce"],
|
|
1654
|
+
envKeys: [/^WOOCOMMERCE_/]
|
|
1655
|
+
}
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
kind: "Recharge",
|
|
1659
|
+
label: "Recharge",
|
|
1660
|
+
mode: "in-cli",
|
|
1661
|
+
signals: { envKeys: [/^RECHARGE_/] }
|
|
1662
|
+
},
|
|
1663
|
+
{
|
|
1664
|
+
kind: "Commercetools",
|
|
1665
|
+
label: "commercetools",
|
|
1666
|
+
mode: "in-cli",
|
|
1667
|
+
signals: {
|
|
1668
|
+
npm: ["@commercetools/platform-sdk"],
|
|
1669
|
+
python: ["commercetools"],
|
|
1670
|
+
envKeys: [/^CTP_/, /^COMMERCETOOLS_/]
|
|
1671
|
+
}
|
|
1672
|
+
},
|
|
1673
|
+
{
|
|
1674
|
+
kind: "Webflow",
|
|
1675
|
+
label: "Webflow",
|
|
1676
|
+
mode: "in-cli",
|
|
1677
|
+
signals: {
|
|
1678
|
+
npm: ["webflow-api"],
|
|
1679
|
+
envKeys: [/^WEBFLOW_/]
|
|
1680
|
+
}
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
kind: "Easypost",
|
|
1684
|
+
label: "EasyPost",
|
|
1685
|
+
mode: "in-cli",
|
|
1686
|
+
signals: {
|
|
1687
|
+
npm: ["@easypost/api"],
|
|
1688
|
+
python: ["easypost"],
|
|
1689
|
+
envKeys: [/^EASYPOST_/]
|
|
1690
|
+
}
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
kind: "Shippo",
|
|
1694
|
+
label: "Shippo",
|
|
1695
|
+
mode: "in-cli",
|
|
1696
|
+
signals: {
|
|
1697
|
+
npm: ["shippo"],
|
|
1698
|
+
python: ["shippo"],
|
|
1699
|
+
envKeys: [/^SHIPPO_/]
|
|
1700
|
+
}
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
kind: "ShipStation",
|
|
1704
|
+
label: "ShipStation",
|
|
1705
|
+
mode: "in-cli",
|
|
1706
|
+
signals: { envKeys: [/^SHIPSTATION_/] }
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
kind: "Squarespace",
|
|
1710
|
+
label: "Squarespace",
|
|
1711
|
+
mode: "in-cli",
|
|
1712
|
+
signals: { envKeys: [/^SQUARESPACE_/] }
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
kind: "Printify",
|
|
1716
|
+
label: "Printify",
|
|
1717
|
+
mode: "in-cli",
|
|
1718
|
+
signals: { envKeys: [/^PRINTIFY_/] }
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
kind: "Freshdesk",
|
|
1722
|
+
label: "Freshdesk",
|
|
1723
|
+
mode: "in-cli",
|
|
1724
|
+
signals: {
|
|
1725
|
+
python: ["python-freshdesk"],
|
|
1726
|
+
envKeys: [/^FRESHDESK_/]
|
|
1727
|
+
}
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
kind: "Front",
|
|
1731
|
+
label: "Front",
|
|
1732
|
+
mode: "in-cli",
|
|
1733
|
+
signals: { envKeys: [/^FRONTAPP_/, /^FRONT_API_/] }
|
|
1734
|
+
},
|
|
1735
|
+
{
|
|
1736
|
+
kind: "Gorgias",
|
|
1737
|
+
label: "Gorgias",
|
|
1738
|
+
mode: "in-cli",
|
|
1739
|
+
signals: { envKeys: [/^GORGIAS_/] }
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
kind: "Chatwoot",
|
|
1743
|
+
label: "Chatwoot",
|
|
1744
|
+
mode: "in-cli",
|
|
1745
|
+
signals: { envKeys: [/^CHATWOOT_/] }
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
kind: "Kustomer",
|
|
1749
|
+
label: "Kustomer",
|
|
1750
|
+
mode: "in-cli",
|
|
1751
|
+
signals: { envKeys: [/^KUSTOMER_/] }
|
|
1752
|
+
},
|
|
1753
|
+
{
|
|
1754
|
+
kind: "Plain",
|
|
1755
|
+
label: "Plain",
|
|
1756
|
+
mode: "in-cli",
|
|
1757
|
+
signals: {
|
|
1758
|
+
npm: ["@team-plain/typescript-sdk"],
|
|
1759
|
+
envKeys: [/^PLAIN_/]
|
|
1760
|
+
}
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
kind: "Canny",
|
|
1764
|
+
label: "Canny",
|
|
1765
|
+
mode: "in-cli",
|
|
1766
|
+
signals: { envKeys: [/^CANNY_/] }
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
kind: "Pylon",
|
|
1770
|
+
label: "Pylon",
|
|
1771
|
+
mode: "in-cli",
|
|
1772
|
+
signals: { envKeys: [/^PYLON_/] }
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
kind: "GitLab",
|
|
1776
|
+
label: "GitLab",
|
|
1777
|
+
mode: "in-cli",
|
|
1778
|
+
signals: {
|
|
1779
|
+
npm: ["@gitbeaker/rest"],
|
|
1780
|
+
python: ["python-gitlab"],
|
|
1781
|
+
ruby: ["gitlab"],
|
|
1782
|
+
envKeys: [/^GITLAB_/]
|
|
1783
|
+
}
|
|
1784
|
+
},
|
|
1785
|
+
{
|
|
1786
|
+
kind: "Bitbucket",
|
|
1787
|
+
label: "Atlassian Bitbucket Cloud",
|
|
1788
|
+
mode: "in-cli",
|
|
1789
|
+
signals: {
|
|
1790
|
+
npm: ["bitbucket"],
|
|
1791
|
+
envKeys: [/^BITBUCKET_/]
|
|
1792
|
+
}
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
kind: "Gitea",
|
|
1796
|
+
label: "Gitea",
|
|
1797
|
+
mode: "in-cli",
|
|
1798
|
+
signals: {
|
|
1799
|
+
npm: ["gitea-js"],
|
|
1800
|
+
envKeys: [/^GITEA_/]
|
|
1801
|
+
}
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
kind: "Datadog",
|
|
1805
|
+
label: "Datadog",
|
|
1806
|
+
mode: "in-cli",
|
|
1807
|
+
signals: {
|
|
1808
|
+
npm: ["@datadog/datadog-api-client", "dd-trace"],
|
|
1809
|
+
python: ["datadog", "datadog-api-client"],
|
|
1810
|
+
ruby: ["dogapi"],
|
|
1811
|
+
envKeys: [
|
|
1812
|
+
/^DATADOG_/,
|
|
1813
|
+
/^DD_API_KEY$/,
|
|
1814
|
+
/^DD_APP_KEY$/
|
|
1815
|
+
]
|
|
1816
|
+
}
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
kind: "NewRelic",
|
|
1820
|
+
label: "New Relic",
|
|
1821
|
+
mode: "in-cli",
|
|
1822
|
+
signals: {
|
|
1823
|
+
npm: ["newrelic"],
|
|
1824
|
+
python: ["newrelic"],
|
|
1825
|
+
ruby: ["newrelic_rpm"],
|
|
1826
|
+
envKeys: [/^NEW_RELIC_/, /^NEWRELIC_/]
|
|
1827
|
+
}
|
|
1828
|
+
},
|
|
1829
|
+
{
|
|
1830
|
+
kind: "Cloudflare",
|
|
1831
|
+
label: "Cloudflare",
|
|
1832
|
+
mode: "in-cli",
|
|
1833
|
+
signals: {
|
|
1834
|
+
npm: ["cloudflare"],
|
|
1835
|
+
python: ["cloudflare"],
|
|
1836
|
+
envKeys: [/^CLOUDFLARE_/, /^CF_API_TOKEN$/]
|
|
1837
|
+
}
|
|
1838
|
+
},
|
|
1839
|
+
{
|
|
1840
|
+
kind: "Elasticsearch",
|
|
1841
|
+
label: "Elasticsearch",
|
|
1842
|
+
mode: "in-cli",
|
|
1843
|
+
signals: {
|
|
1844
|
+
npm: ["@elastic/elasticsearch"],
|
|
1845
|
+
python: ["elasticsearch"],
|
|
1846
|
+
ruby: ["elasticsearch"],
|
|
1847
|
+
envKeys: [/^ELASTICSEARCH_/]
|
|
1848
|
+
}
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
kind: "Snyk",
|
|
1852
|
+
label: "Snyk",
|
|
1853
|
+
mode: "in-cli",
|
|
1854
|
+
signals: {
|
|
1855
|
+
npm: ["snyk"],
|
|
1856
|
+
python: ["pysnyk"],
|
|
1857
|
+
envKeys: [/^SNYK_/]
|
|
1858
|
+
}
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
kind: "PagerDuty",
|
|
1862
|
+
label: "PagerDuty",
|
|
1863
|
+
mode: "in-cli",
|
|
1864
|
+
signals: {
|
|
1865
|
+
npm: ["@pagerduty/pdjs"],
|
|
1866
|
+
python: ["pdpyras"],
|
|
1867
|
+
envKeys: [/^PAGERDUTY_/, /^PD_API_KEY$/]
|
|
1868
|
+
}
|
|
1869
|
+
},
|
|
1870
|
+
{
|
|
1871
|
+
kind: "Opsgenie",
|
|
1872
|
+
label: "Opsgenie",
|
|
1873
|
+
mode: "in-cli",
|
|
1874
|
+
signals: { envKeys: [/^OPSGENIE_/] }
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
kind: "IncidentIo",
|
|
1878
|
+
label: "incident.io",
|
|
1879
|
+
mode: "in-cli",
|
|
1880
|
+
signals: { envKeys: [/^INCIDENT_IO_/, /^INCIDENTIO_/] }
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
kind: "Bugsnag",
|
|
1884
|
+
label: "Bugsnag",
|
|
1885
|
+
mode: "in-cli",
|
|
1886
|
+
signals: {
|
|
1887
|
+
npm: ["@bugsnag/js"],
|
|
1888
|
+
python: ["bugsnag"],
|
|
1889
|
+
ruby: ["bugsnag"],
|
|
1890
|
+
envKeys: [/^BUGSNAG_/]
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
kind: "Honeybadger",
|
|
1895
|
+
label: "Honeybadger",
|
|
1896
|
+
mode: "in-cli",
|
|
1897
|
+
signals: {
|
|
1898
|
+
npm: ["@honeybadger-io/js"],
|
|
1899
|
+
python: ["honeybadger"],
|
|
1900
|
+
ruby: ["honeybadger"],
|
|
1901
|
+
envKeys: [/^HONEYBADGER_/]
|
|
1902
|
+
}
|
|
1903
|
+
},
|
|
1904
|
+
{
|
|
1905
|
+
kind: "Raygun",
|
|
1906
|
+
label: "Raygun",
|
|
1907
|
+
mode: "in-cli",
|
|
1908
|
+
signals: {
|
|
1909
|
+
npm: ["raygun"],
|
|
1910
|
+
python: ["raygun4py"],
|
|
1911
|
+
ruby: ["raygun4ruby"],
|
|
1912
|
+
envKeys: [/^RAYGUN_/]
|
|
1913
|
+
}
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
kind: "CircleCI",
|
|
1917
|
+
label: "CircleCI",
|
|
1918
|
+
mode: "in-cli",
|
|
1919
|
+
signals: { envKeys: [/^CIRCLECI_/, /^CIRCLE_TOKEN$/] }
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
kind: "Upstash",
|
|
1923
|
+
label: "Upstash",
|
|
1924
|
+
mode: "in-cli",
|
|
1925
|
+
signals: {
|
|
1926
|
+
npm: ["@upstash/redis"],
|
|
1927
|
+
python: ["upstash-redis"],
|
|
1928
|
+
envKeys: [/^UPSTASH_/]
|
|
1929
|
+
}
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
kind: "Vercel",
|
|
1933
|
+
label: "Vercel",
|
|
1934
|
+
mode: "in-cli",
|
|
1935
|
+
signals: {
|
|
1936
|
+
npm: ["@vercel/sdk"],
|
|
1937
|
+
envKeys: [/^VERCEL_API_TOKEN$/]
|
|
1938
|
+
}
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
kind: "Pipedrive",
|
|
1942
|
+
label: "Pipedrive",
|
|
1943
|
+
mode: "in-cli",
|
|
1944
|
+
signals: {
|
|
1945
|
+
npm: ["pipedrive"],
|
|
1946
|
+
envKeys: [/^PIPEDRIVE_/]
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
kind: "Close",
|
|
1951
|
+
label: "Close",
|
|
1952
|
+
mode: "in-cli",
|
|
1953
|
+
signals: {
|
|
1954
|
+
python: ["closeio"],
|
|
1955
|
+
envKeys: [/^CLOSE_API_KEY$/]
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
kind: "Copper",
|
|
1960
|
+
label: "Copper",
|
|
1961
|
+
mode: "in-cli",
|
|
1962
|
+
signals: { envKeys: [/^COPPER_/] }
|
|
1963
|
+
},
|
|
1964
|
+
{
|
|
1965
|
+
kind: "Insightly",
|
|
1966
|
+
label: "Insightly",
|
|
1967
|
+
mode: "in-cli",
|
|
1968
|
+
signals: { envKeys: [/^INSIGHTLY_/] }
|
|
1969
|
+
},
|
|
1970
|
+
{
|
|
1971
|
+
kind: "Salesflare",
|
|
1972
|
+
label: "Salesflare",
|
|
1973
|
+
mode: "in-cli",
|
|
1974
|
+
signals: { envKeys: [/^SALESFLARE_/] }
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
kind: "SalesLoft",
|
|
1978
|
+
label: "Salesloft",
|
|
1979
|
+
mode: "in-cli",
|
|
1980
|
+
signals: { envKeys: [/^SALESLOFT_/] }
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
kind: "Attio",
|
|
1984
|
+
label: "Attio",
|
|
1985
|
+
mode: "in-cli",
|
|
1986
|
+
signals: {
|
|
1987
|
+
npm: ["attio"],
|
|
1988
|
+
envKeys: [/^ATTIO_/]
|
|
1989
|
+
}
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
kind: "ActiveCampaign",
|
|
1993
|
+
label: "ActiveCampaign",
|
|
1994
|
+
mode: "in-cli",
|
|
1995
|
+
signals: { envKeys: [/^ACTIVECAMPAIGN_/, /^ACTIVE_CAMPAIGN_/] }
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
kind: "Vitally",
|
|
1999
|
+
label: "Vitally",
|
|
2000
|
+
mode: "in-cli",
|
|
2001
|
+
signals: { envKeys: [/^VITALLY_/] }
|
|
2002
|
+
},
|
|
2003
|
+
{
|
|
2004
|
+
kind: "Asana",
|
|
2005
|
+
label: "Asana",
|
|
2006
|
+
mode: "in-cli",
|
|
2007
|
+
signals: {
|
|
2008
|
+
npm: ["asana"],
|
|
2009
|
+
python: ["asana"],
|
|
2010
|
+
envKeys: [/^ASANA_/]
|
|
2011
|
+
}
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
kind: "Trello",
|
|
2015
|
+
label: "Trello",
|
|
2016
|
+
mode: "in-cli",
|
|
2017
|
+
signals: {
|
|
2018
|
+
npm: ["trello"],
|
|
2019
|
+
envKeys: [/^TRELLO_/]
|
|
2020
|
+
}
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
kind: "Todoist",
|
|
2024
|
+
label: "Todoist",
|
|
2025
|
+
mode: "in-cli",
|
|
2026
|
+
signals: {
|
|
2027
|
+
npm: ["@doist/todoist-api-typescript"],
|
|
2028
|
+
python: ["todoist-api-python"],
|
|
2029
|
+
envKeys: [/^TODOIST_/]
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
{
|
|
2033
|
+
kind: "Monday",
|
|
2034
|
+
label: "monday.com",
|
|
2035
|
+
mode: "in-cli",
|
|
2036
|
+
signals: {
|
|
2037
|
+
npm: ["@mondaydotcomorg/api"],
|
|
2038
|
+
envKeys: [/^MONDAY_/]
|
|
2039
|
+
}
|
|
2040
|
+
},
|
|
2041
|
+
{
|
|
2042
|
+
kind: "ClickUp",
|
|
2043
|
+
label: "ClickUp",
|
|
2044
|
+
mode: "in-cli",
|
|
2045
|
+
signals: { envKeys: [/^CLICKUP_/] }
|
|
2046
|
+
},
|
|
2047
|
+
{
|
|
2048
|
+
kind: "Height",
|
|
2049
|
+
label: "Height",
|
|
2050
|
+
mode: "in-cli",
|
|
2051
|
+
signals: { envKeys: [/^HEIGHT_API_KEY$/] }
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
kind: "Shortcut",
|
|
2055
|
+
label: "Shortcut",
|
|
2056
|
+
mode: "in-cli",
|
|
2057
|
+
signals: {
|
|
2058
|
+
npm: ["@shortcut/client"],
|
|
2059
|
+
envKeys: [/^SHORTCUT_/]
|
|
2060
|
+
}
|
|
2061
|
+
},
|
|
2062
|
+
{
|
|
2063
|
+
kind: "Jira",
|
|
2064
|
+
label: "Jira",
|
|
2065
|
+
mode: "in-cli",
|
|
2066
|
+
signals: {
|
|
2067
|
+
npm: ["jira-client"],
|
|
2068
|
+
python: ["jira", "atlassian-python-api"],
|
|
2069
|
+
envKeys: [/^JIRA_/]
|
|
2070
|
+
}
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
kind: "Confluence",
|
|
2074
|
+
label: "Confluence",
|
|
2075
|
+
mode: "in-cli",
|
|
2076
|
+
signals: { envKeys: [/^CONFLUENCE_/] }
|
|
2077
|
+
},
|
|
2078
|
+
{
|
|
2079
|
+
kind: "Airtable",
|
|
2080
|
+
label: "Airtable",
|
|
2081
|
+
mode: "in-cli",
|
|
2082
|
+
signals: {
|
|
2083
|
+
npm: ["airtable"],
|
|
2084
|
+
python: ["pyairtable"],
|
|
2085
|
+
envKeys: [/^AIRTABLE_/]
|
|
2086
|
+
}
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
kind: "Smartsheet",
|
|
2090
|
+
label: "Smartsheet",
|
|
2091
|
+
mode: "in-cli",
|
|
2092
|
+
signals: {
|
|
2093
|
+
npm: ["smartsheet"],
|
|
2094
|
+
python: ["smartsheet-python-sdk"],
|
|
2095
|
+
envKeys: [/^SMARTSHEET_/]
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
kind: "Coda",
|
|
2100
|
+
label: "Coda",
|
|
2101
|
+
mode: "in-cli",
|
|
2102
|
+
signals: { envKeys: [/^CODA_API_/] }
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
kind: "Productboard",
|
|
2106
|
+
label: "Productboard",
|
|
2107
|
+
mode: "in-cli",
|
|
2108
|
+
signals: { envKeys: [/^PRODUCTBOARD_/] }
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
kind: "Calendly",
|
|
2112
|
+
label: "Calendly",
|
|
2113
|
+
mode: "in-cli",
|
|
2114
|
+
signals: { envKeys: [/^CALENDLY_/] }
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
kind: "CalCom",
|
|
2118
|
+
label: "Cal.com",
|
|
2119
|
+
mode: "in-cli",
|
|
2120
|
+
signals: { envKeys: [/^CALCOM_/, /^CAL_API_KEY$/] }
|
|
2121
|
+
},
|
|
2122
|
+
{
|
|
2123
|
+
kind: "Eventbrite",
|
|
2124
|
+
label: "Eventbrite",
|
|
2125
|
+
mode: "in-cli",
|
|
2126
|
+
signals: {
|
|
2127
|
+
python: ["eventbrite"],
|
|
2128
|
+
envKeys: [/^EVENTBRITE_/]
|
|
2129
|
+
}
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
kind: "BambooHR",
|
|
2133
|
+
label: "BambooHR",
|
|
2134
|
+
mode: "in-cli",
|
|
2135
|
+
signals: {
|
|
2136
|
+
python: ["pybamboohr"],
|
|
2137
|
+
envKeys: [/^BAMBOOHR_/, /^BAMBOO_HR_/]
|
|
2138
|
+
}
|
|
2139
|
+
},
|
|
2140
|
+
{
|
|
2141
|
+
kind: "Personio",
|
|
2142
|
+
label: "Personio",
|
|
2143
|
+
mode: "in-cli",
|
|
2144
|
+
signals: { envKeys: [/^PERSONIO_/] }
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
kind: "Rippling",
|
|
2148
|
+
label: "Rippling",
|
|
2149
|
+
mode: "in-cli",
|
|
2150
|
+
signals: { envKeys: [/^RIPPLING_/] }
|
|
2151
|
+
},
|
|
2152
|
+
{
|
|
2153
|
+
kind: "Greenhouse",
|
|
2154
|
+
label: "Greenhouse",
|
|
2155
|
+
mode: "in-cli",
|
|
2156
|
+
signals: { envKeys: [/^GREENHOUSE_/] }
|
|
2157
|
+
},
|
|
2158
|
+
{
|
|
2159
|
+
kind: "Ashby",
|
|
2160
|
+
label: "Ashby",
|
|
2161
|
+
mode: "in-cli",
|
|
2162
|
+
signals: { envKeys: [/^ASHBY_/] }
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
kind: "Workable",
|
|
2166
|
+
label: "Workable",
|
|
2167
|
+
mode: "in-cli",
|
|
2168
|
+
signals: { envKeys: [/^WORKABLE_/] }
|
|
2169
|
+
},
|
|
2170
|
+
{
|
|
2171
|
+
kind: "GoogleAds",
|
|
2172
|
+
label: "Google Ads",
|
|
2173
|
+
mode: "deep-link",
|
|
2174
|
+
signals: {
|
|
2175
|
+
npm: ["google-ads-api"],
|
|
2176
|
+
python: ["google-ads"],
|
|
2177
|
+
envKeys: [/^GOOGLE_ADS_/]
|
|
2178
|
+
}
|
|
2179
|
+
},
|
|
2180
|
+
{
|
|
2181
|
+
kind: "MetaAds",
|
|
2182
|
+
label: "Meta Ads",
|
|
2183
|
+
mode: "deep-link",
|
|
2184
|
+
signals: {
|
|
2185
|
+
npm: ["facebook-nodejs-business-sdk"],
|
|
2186
|
+
python: ["facebook-business"],
|
|
2187
|
+
envKeys: [/^META_ADS_/, /^FACEBOOK_ADS_/]
|
|
2188
|
+
}
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
kind: "LinkedinAds",
|
|
2192
|
+
label: "LinkedIn Ads",
|
|
2193
|
+
mode: "deep-link",
|
|
2194
|
+
signals: { envKeys: [/^LINKEDIN_ADS_/] }
|
|
2195
|
+
},
|
|
2196
|
+
{
|
|
2197
|
+
kind: "TikTokAds",
|
|
2198
|
+
label: "TikTok Ads",
|
|
2199
|
+
mode: "deep-link",
|
|
2200
|
+
signals: { envKeys: [/^TIKTOK_ADS_/] }
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
kind: "RedditAds",
|
|
2204
|
+
label: "Reddit Ads",
|
|
2205
|
+
mode: "deep-link",
|
|
2206
|
+
signals: { envKeys: [/^REDDIT_ADS_/] }
|
|
2207
|
+
},
|
|
2208
|
+
{
|
|
2209
|
+
kind: "PinterestAds",
|
|
2210
|
+
label: "Pinterest Ads",
|
|
2211
|
+
mode: "deep-link",
|
|
2212
|
+
signals: { envKeys: [/^PINTEREST_ADS_/] }
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
kind: "BingAds",
|
|
2216
|
+
label: "Bing Ads",
|
|
2217
|
+
mode: "deep-link",
|
|
2218
|
+
signals: {
|
|
2219
|
+
python: ["bingads"],
|
|
2220
|
+
envKeys: [/^BING_ADS_/, /^MICROSOFT_ADS_/]
|
|
2221
|
+
}
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
kind: "AmazonAds",
|
|
2225
|
+
label: "Amazon Ads",
|
|
2226
|
+
mode: "deep-link",
|
|
2227
|
+
signals: { envKeys: [/^AMAZON_ADS_/] }
|
|
2228
|
+
},
|
|
2229
|
+
{
|
|
2230
|
+
kind: "GoogleAnalytics",
|
|
2231
|
+
label: "Google Analytics",
|
|
2232
|
+
mode: "deep-link",
|
|
2233
|
+
signals: {
|
|
2234
|
+
npm: ["react-ga4"],
|
|
2235
|
+
python: ["google-analytics-data"],
|
|
2236
|
+
envKeys: [/^GOOGLE_ANALYTICS_/, /^GA4_/]
|
|
2237
|
+
}
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
kind: "GoogleSearchConsole",
|
|
2241
|
+
label: "Google Search Console",
|
|
2242
|
+
mode: "deep-link",
|
|
2243
|
+
signals: { envKeys: [/^SEARCH_CONSOLE_/, /^GSC_/] }
|
|
2244
|
+
},
|
|
2245
|
+
{
|
|
2246
|
+
kind: "AppsFlyer",
|
|
2247
|
+
label: "AppsFlyer",
|
|
2248
|
+
mode: "in-cli",
|
|
2249
|
+
signals: {
|
|
2250
|
+
npm: ["react-native-appsflyer"],
|
|
2251
|
+
envKeys: [/^APPSFLYER_/]
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
];
|
|
2255
|
+
//#endregion
|
|
2256
|
+
//#region src/lib/warehouse-sources/detect.ts
|
|
314
2257
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
2258
|
+
* Data warehouse source detection.
|
|
2259
|
+
*
|
|
2260
|
+
* Scans a project for codebase signals (npm/python/ruby deps, `.env` key
|
|
2261
|
+
* names) and matches them against the `SOURCE_DETECTORS` registry. Pure
|
|
2262
|
+
* function: no store mutations, no UI calls. Reads files locally — only the
|
|
2263
|
+
* wizard process does this; the agent never sees secret values.
|
|
2264
|
+
*
|
|
2265
|
+
* Note we only read `.env` KEY NAMES, never values.
|
|
317
2266
|
*/
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
2267
|
+
const MAX_DEPTH = 3;
|
|
2268
|
+
/**
|
|
2269
|
+
* Detect which warehouse sources the project at `installDir` appears to use.
|
|
2270
|
+
* Returns one `DetectedSource` per matched registry entry (kinds are unique,
|
|
2271
|
+
* so the result is naturally deduped).
|
|
2272
|
+
*/
|
|
2273
|
+
function detectWarehouseSources(installDir) {
|
|
2274
|
+
const signals = collectSignals(installDir);
|
|
2275
|
+
const detected = [];
|
|
2276
|
+
for (const detector of SOURCE_DETECTORS) {
|
|
2277
|
+
const match = matchDetector(detector, signals);
|
|
2278
|
+
if (match) detected.push({
|
|
2279
|
+
kind: detector.kind,
|
|
2280
|
+
label: detector.label,
|
|
2281
|
+
mode: detector.mode,
|
|
2282
|
+
matchedSignal: match
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
return detected;
|
|
333
2286
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
const
|
|
338
|
-
|
|
2287
|
+
/** Returns a human-readable description of the first matching signal, or null. */
|
|
2288
|
+
function matchDetector(detector, signals) {
|
|
2289
|
+
const { npm, python, ruby, envKeys } = detector.signals;
|
|
2290
|
+
const npmHit = npm?.find((dep) => signals.npm.has(dep));
|
|
2291
|
+
if (npmHit) return `found \`${npmHit}\` in package.json`;
|
|
2292
|
+
const pyHit = python?.find((dep) => signals.python.has(dep));
|
|
2293
|
+
if (pyHit) return `found \`${pyHit}\` in Python dependencies`;
|
|
2294
|
+
const rubyHit = ruby?.find((gem) => signals.ruby.has(gem));
|
|
2295
|
+
if (rubyHit) return `found \`${rubyHit}\` in Gemfile`;
|
|
2296
|
+
if (envKeys) {
|
|
2297
|
+
for (const key of signals.envKeys) if (envKeys.some((re) => re.test(key))) return `found \`${key}\` in .env`;
|
|
2298
|
+
}
|
|
2299
|
+
return null;
|
|
339
2300
|
}
|
|
340
|
-
function
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
benchmark: session.benchmark,
|
|
347
|
-
yaraReport: session.yaraReport,
|
|
348
|
-
signup: session.signup,
|
|
349
|
-
apiKey: session.apiKey,
|
|
350
|
-
projectId: session.projectId,
|
|
351
|
-
localMcp: session.localMcp
|
|
2301
|
+
function collectSignals(installDir) {
|
|
2302
|
+
const signals = {
|
|
2303
|
+
npm: /* @__PURE__ */ new Set(),
|
|
2304
|
+
python: /* @__PURE__ */ new Set(),
|
|
2305
|
+
ruby: /* @__PURE__ */ new Set(),
|
|
2306
|
+
envKeys: /* @__PURE__ */ new Set()
|
|
352
2307
|
};
|
|
2308
|
+
walkProjectFiles(installDir, (name, fullPath) => ingestFile(name, fullPath, signals), MAX_DEPTH);
|
|
2309
|
+
return signals;
|
|
353
2310
|
}
|
|
354
|
-
const NOOP_SPINNER = {
|
|
355
|
-
start: () => void 0,
|
|
356
|
-
stop: () => void 0,
|
|
357
|
-
message: () => void 0
|
|
358
|
-
};
|
|
359
2311
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
2312
|
+
* Route a file to the right parser BY NAME, reading its contents only when the
|
|
2313
|
+
* name matches one of the ~6 manifests we care about. Checking the name first
|
|
2314
|
+
* avoids slurping every file in the tree (lockfiles, binaries, assets) into
|
|
2315
|
+
* memory just to discard it.
|
|
363
2316
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
],
|
|
383
|
-
modelOverride: HAIKU_MODEL
|
|
384
|
-
}, runOptions);
|
|
385
|
-
const collected = [];
|
|
386
|
-
let resultText = "";
|
|
387
|
-
const result = await runAgent$1(agent, buildPrompt(cwd, targets, purpose), runOptions, NOOP_SPINNER, {
|
|
388
|
-
spinnerMessage: "Scanning the repo...",
|
|
389
|
-
successMessage: "Detection complete",
|
|
390
|
-
errorMessage: "Detection failed",
|
|
391
|
-
requestRemark: false
|
|
392
|
-
}, {
|
|
393
|
-
onMessage: (message) => {
|
|
394
|
-
if (message?.type === "assistant") {
|
|
395
|
-
for (const block of message.message?.content ?? []) if (block?.type === "text" && typeof block.text === "string") {
|
|
396
|
-
collected.push(block.text);
|
|
397
|
-
const line = block.text.trim();
|
|
398
|
-
if (line && onEvent) onEvent(line.length > 100 ? `${line.slice(0, 100)}…` : line);
|
|
399
|
-
} else if (block?.type === "tool_use") onEvent?.(formatToolUse(block));
|
|
400
|
-
} else if (message?.type === "result" && typeof message.result === "string") resultText = message.result;
|
|
401
|
-
},
|
|
402
|
-
finalize: (_resultMessage, _durationMs) => void 0
|
|
403
|
-
});
|
|
404
|
-
if (result.error) throw new Error(result.message || `Agent error: ${result.error}`);
|
|
405
|
-
const output = resultText || collected.join("\n");
|
|
2317
|
+
function ingestFile(name, fullPath, signals) {
|
|
2318
|
+
const ingest = ingestorFor(name);
|
|
2319
|
+
if (!ingest) return;
|
|
2320
|
+
const content = safeReadFile(fullPath);
|
|
2321
|
+
if (content === null) return;
|
|
2322
|
+
ingest(content, signals);
|
|
2323
|
+
}
|
|
2324
|
+
/** Pick the parser for a manifest filename, or null if it's not one we read. */
|
|
2325
|
+
function ingestorFor(name) {
|
|
2326
|
+
if (name === "package.json") return addNpmDeps;
|
|
2327
|
+
if (name === "requirements.txt") return (c, s) => parseRequirementsTxt(c).forEach((d) => s.python.add(d));
|
|
2328
|
+
if (name === "pyproject.toml") return (c, s) => parsePyprojectToml(c).forEach((d) => s.python.add(d));
|
|
2329
|
+
if (name === "Pipfile") return (c, s) => parsePipfile(c).forEach((d) => s.python.add(d));
|
|
2330
|
+
if (name === "Gemfile") return (c, s) => parseGemfile(c).forEach((g) => s.ruby.add(g));
|
|
2331
|
+
if (name.startsWith(".env")) return (c, s) => parseEnvKeys(c).forEach((k) => s.envKeys.add(k));
|
|
2332
|
+
return null;
|
|
2333
|
+
}
|
|
2334
|
+
function addNpmDeps(content, signals) {
|
|
406
2335
|
try {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
2336
|
+
const pkg = JSON.parse(content);
|
|
2337
|
+
for (const dep of Object.keys({
|
|
2338
|
+
...pkg.dependencies,
|
|
2339
|
+
...pkg.devDependencies
|
|
2340
|
+
})) signals.npm.add(dep);
|
|
2341
|
+
} catch (error) {
|
|
2342
|
+
analytics.captureException(error instanceof Error ? error : new Error(String(error)), { step: "detectWarehouseSources.parsePackageJson" });
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
/** Extract gem names from `gem 'name'` declarations. */
|
|
2346
|
+
function parseGemfile(content) {
|
|
2347
|
+
const gems = [];
|
|
2348
|
+
for (const match of content.matchAll(/^\s*gem\s+['"]([^'"]+)['"]/gm)) gems.push(match[1]);
|
|
2349
|
+
return gems;
|
|
2350
|
+
}
|
|
2351
|
+
/** Extract KEY NAMES from a dotenv file. Values are intentionally discarded. */
|
|
2352
|
+
function parseEnvKeys(content) {
|
|
2353
|
+
const keys = [];
|
|
2354
|
+
for (const line of content.split("\n")) {
|
|
2355
|
+
const trimmed = line.trim();
|
|
2356
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
2357
|
+
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);
|
|
2358
|
+
if (match) keys.push(match[1]);
|
|
2359
|
+
}
|
|
2360
|
+
return keys;
|
|
2361
|
+
}
|
|
2362
|
+
//#endregion
|
|
2363
|
+
//#region src/lib/programs/warehouse-source/detect.ts
|
|
2364
|
+
/**
|
|
2365
|
+
* Warehouse-source program detection step.
|
|
2366
|
+
*
|
|
2367
|
+
* Thin adapter over `detectWarehouseSources` that writes results into
|
|
2368
|
+
* frameworkContext for the intro screen, plus the `[ABORT]` cases the
|
|
2369
|
+
* data-warehouse-source-setup skill can emit.
|
|
2370
|
+
*/
|
|
2371
|
+
/** frameworkContext key holding the detected sources (set on success). */
|
|
2372
|
+
const DETECTED_WAREHOUSE_SOURCES_KEY = "detectedWarehouseSources";
|
|
2373
|
+
/**
|
|
2374
|
+
* Read the detected sources out of frameworkContext. Single accessor shared by
|
|
2375
|
+
* the intro screen and the prompt builder so the key + cast live in one place.
|
|
2376
|
+
*/
|
|
2377
|
+
function getDetectedWarehouseSources(session) {
|
|
2378
|
+
return session.frameworkContext["detectedWarehouseSources"] ?? [];
|
|
2379
|
+
}
|
|
2380
|
+
/** `[ABORT] <reason>` cases the skill can emit. */
|
|
2381
|
+
const WAREHOUSE_ABORT_CASES = [{
|
|
2382
|
+
match: /^no data sources? detected\.?$/i,
|
|
2383
|
+
message: "No data source detected",
|
|
2384
|
+
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.).",
|
|
2385
|
+
docsUrl: "https://posthog.com/docs/data-warehouse"
|
|
2386
|
+
}, {
|
|
2387
|
+
match: /^source creation failed\.?$/i,
|
|
2388
|
+
message: "Source creation failed",
|
|
2389
|
+
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.",
|
|
2390
|
+
docsUrl: "https://posthog.com/docs/data-warehouse"
|
|
2391
|
+
}];
|
|
2392
|
+
/**
|
|
2393
|
+
* Scan `session.installDir` for warehouse-source signals. Writes the detected
|
|
2394
|
+
* sources (or a `detectError`) into frameworkContext for the intro screen.
|
|
2395
|
+
*/
|
|
2396
|
+
function detectWarehousePrerequisites(session, setFrameworkContext) {
|
|
2397
|
+
const fail = (error) => setFrameworkContext("detectError", error);
|
|
2398
|
+
const installDir = session.installDir;
|
|
2399
|
+
if (!existsSync(installDir)) {
|
|
2400
|
+
fail({
|
|
2401
|
+
kind: "bad-directory",
|
|
2402
|
+
path: installDir,
|
|
2403
|
+
reason: "missing"
|
|
2404
|
+
});
|
|
2405
|
+
return;
|
|
2406
|
+
}
|
|
2407
|
+
try {
|
|
2408
|
+
if (!statSync(installDir).isDirectory()) {
|
|
2409
|
+
fail({
|
|
2410
|
+
kind: "bad-directory",
|
|
2411
|
+
path: installDir,
|
|
2412
|
+
reason: "not-dir"
|
|
2413
|
+
});
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
} catch (error) {
|
|
2417
|
+
analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
|
|
2418
|
+
step: "detectWarehousePrerequisites.stat",
|
|
2419
|
+
path: installDir
|
|
2420
|
+
});
|
|
2421
|
+
fail({
|
|
2422
|
+
kind: "bad-directory",
|
|
2423
|
+
path: installDir,
|
|
2424
|
+
reason: "unreadable"
|
|
2425
|
+
});
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
const sources = detectWarehouseSources(installDir);
|
|
2429
|
+
if (sources.length === 0) {
|
|
2430
|
+
fail({ kind: "no-sources" });
|
|
2431
|
+
return;
|
|
414
2432
|
}
|
|
2433
|
+
analytics.setTag("warehouse_source_kinds", sources.map((s) => s.kind).join(","));
|
|
2434
|
+
analytics.setTag("warehouse_source_modes", sources.map((s) => `${s.kind}:${s.mode}`).join(","));
|
|
2435
|
+
analytics.setTag("warehouse_source_count", sources.length);
|
|
2436
|
+
setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);
|
|
415
2437
|
}
|
|
416
2438
|
//#endregion
|
|
417
2439
|
//#region src/lib/programs/shared/health-check-step.ts
|
|
@@ -472,8 +2494,41 @@ async function detectPostHogIntegration(ctx) {
|
|
|
472
2494
|
if (versionResult.supported !== true) ctx.setUnsupportedVersion(versionResult.supported);
|
|
473
2495
|
}
|
|
474
2496
|
for (const feature of discoverFeatures(installDir)) ctx.addDiscoveredFeature(feature);
|
|
2497
|
+
detectWarehouseSourcesForSuggestion(ctx, installDir);
|
|
475
2498
|
ctx.setDetectionComplete();
|
|
476
2499
|
}
|
|
2500
|
+
/**
|
|
2501
|
+
* Scan for data warehouse source signals (Postgres, Stripe, Hubspot, …) and,
|
|
2502
|
+
* when found, stash them for a `wizard warehouse` suggestion on the outro.
|
|
2503
|
+
*
|
|
2504
|
+
* Deliberately a suggestion, not an inline agent run: a second credential-
|
|
2505
|
+
* collecting agent run before the outro could `process.exit()` on any of its
|
|
2506
|
+
* failure paths and cost the user the success outro on a run where PostHog
|
|
2507
|
+
* installed fine.
|
|
2508
|
+
*
|
|
2509
|
+
* Calls `detectWarehouseSources` (a pure scan) rather than the warehouse
|
|
2510
|
+
* program's `detectWarehousePrerequisites`, which writes a `detectError` when
|
|
2511
|
+
* it finds nothing — that's right for `wizard warehouse` but here would show a
|
|
2512
|
+
* spurious error and trip the CI prerequisites abort. No sources is a no-op.
|
|
2513
|
+
*
|
|
2514
|
+
* Best-effort: never let a scan failure break the surrounding detect step.
|
|
2515
|
+
*/
|
|
2516
|
+
function detectWarehouseSourcesForSuggestion(ctx, installDir) {
|
|
2517
|
+
try {
|
|
2518
|
+
const sources = detectWarehouseSources(installDir);
|
|
2519
|
+
analytics.wizardCapture("warehouse sources detected", {
|
|
2520
|
+
warehouse_source_count: sources.length,
|
|
2521
|
+
warehouse_source_kinds: sources.map((s) => s.kind),
|
|
2522
|
+
warehouse_source_modes: sources.map((s) => s.mode)
|
|
2523
|
+
});
|
|
2524
|
+
if (sources.length === 0) return;
|
|
2525
|
+
analytics.setTag("warehouse_source_kinds", sources.map((s) => s.kind).join(","));
|
|
2526
|
+
analytics.setTag("warehouse_source_count", sources.length);
|
|
2527
|
+
ctx.setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);
|
|
2528
|
+
} catch (error) {
|
|
2529
|
+
analytics.captureException(error instanceof Error ? error : new Error(String(error)), { step: "detectWarehouseSourcesForSuggestion" });
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
477
2532
|
//#endregion
|
|
478
2533
|
//#region src/lib/programs/posthog-integration/steps.ts
|
|
479
2534
|
function needsSetup(session) {
|
|
@@ -1560,15 +3615,53 @@ function resolveContinueUrl(sess, host, deepLink) {
|
|
|
1560
3615
|
if (typeof deepLink === "string" && deepLink) return deepLink;
|
|
1561
3616
|
return withUtm(`${host.appHost}/products?source=wizard`, "outro-continue");
|
|
1562
3617
|
}
|
|
3618
|
+
/**
|
|
3619
|
+
* Outro suggestion for data sources found in the project but not connected.
|
|
3620
|
+
*
|
|
3621
|
+
* A pointer at `wizard warehouse`, not an inline flow. Connecting a source
|
|
3622
|
+
* needs interactive credential collection, and chaining that as a second agent
|
|
3623
|
+
* run before the outro would let any of its terminal failure paths
|
|
3624
|
+
* `process.exit()` — costing the user the success outro and the post-outro
|
|
3625
|
+
* MCP / Slack steps on a run where PostHog installed fine.
|
|
3626
|
+
*
|
|
3627
|
+
* Returns undefined when nothing was detected, so the outro is unchanged for
|
|
3628
|
+
* projects with no connectable source.
|
|
3629
|
+
*/
|
|
3630
|
+
function buildWarehouseNextSteps(sess) {
|
|
3631
|
+
const sources = getDetectedWarehouseSources(sess);
|
|
3632
|
+
if (sources.length === 0) return void 0;
|
|
3633
|
+
return {
|
|
3634
|
+
heading: "Query your other data in PostHog:",
|
|
3635
|
+
items: [`Found in this project: ${sources.map((s) => s.label).join(", ")}`, "Import it into the data warehouse with: npx @posthog/wizard warehouse"]
|
|
3636
|
+
};
|
|
3637
|
+
}
|
|
3638
|
+
/**
|
|
3639
|
+
* Prompt fragment asking the agent to note the detected data sources in the
|
|
3640
|
+
* setup report's checklist.
|
|
3641
|
+
*
|
|
3642
|
+
* Empty string when nothing was detected, so the prompt is byte-identical to
|
|
3643
|
+
* today for projects with no connectable source. Best-effort by nature — the
|
|
3644
|
+
* agent may word it differently or skip it. That is acceptable here precisely
|
|
3645
|
+
* because it is a note in a report: the outro `nextSteps` bullet carries the
|
|
3646
|
+
* same information deterministically, so nothing is lost if the agent drops it.
|
|
3647
|
+
*/
|
|
3648
|
+
function warehouseReportInstruction(sess) {
|
|
3649
|
+
const sources = getDetectedWarehouseSources(sess);
|
|
3650
|
+
if (sources.length === 0) return "";
|
|
3651
|
+
return `Finally: this project also contains data sources PostHog can import (${sources.map((s) => s.label).join(", ")}). In the setup report's "Verify before merging" checklist, add one item noting these were found and that \`npx @posthog/wizard warehouse\` will connect them to PostHog's data warehouse. Do not attempt to set them up yourself in this run.`;
|
|
3652
|
+
}
|
|
1563
3653
|
const SETUP_REPORT_FILE = "posthog-setup-report.md";
|
|
1564
3654
|
const posthogIntegrationConfig = {
|
|
1565
3655
|
command: "integrate",
|
|
1566
3656
|
description: "Set up PostHog SDK integration",
|
|
1567
3657
|
id: "posthog-integration",
|
|
3658
|
+
agentFlow: "integration-v2",
|
|
3659
|
+
eventPlanFile: EVENT_PLAN_FILE,
|
|
1568
3660
|
steps: POSTHOG_INTEGRATION_PROGRAM,
|
|
1569
3661
|
getContentBlocks,
|
|
1570
3662
|
disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],
|
|
1571
3663
|
ciPreRun: async (session) => {
|
|
3664
|
+
await scopeInstallDirToProject(session);
|
|
1572
3665
|
const integration = await detectFramework(session.installDir);
|
|
1573
3666
|
if (!integration) {
|
|
1574
3667
|
await wizardAbort({ message: "Could not auto-detect your framework for this project." });
|
|
@@ -1599,7 +3692,7 @@ const posthogIntegrationConfig = {
|
|
|
1599
3692
|
if (usesPackageJson) {
|
|
1600
3693
|
const packageJson = await tryGetPackageJson({ installDir: session.installDir });
|
|
1601
3694
|
if (packageJson) {
|
|
1602
|
-
const { hasDeclaredDependency } = await import("./package-json-
|
|
3695
|
+
const { hasDeclaredDependency } = await import("./package-json-DCuoye-H.js").then((n) => n.i);
|
|
1603
3696
|
if (!hasDeclaredDependency(config.detection.packageName, packageJson)) getUI().log.warn(`${config.detection.packageDisplayName} does not seem to be installed. Continuing anyway — the agent will handle it.`);
|
|
1604
3697
|
frameworkVersion = config.detection.getVersion(packageJson);
|
|
1605
3698
|
} else getUI().log.warn("Could not find package.json. Continuing anyway — the agent will handle it.");
|
|
@@ -1661,13 +3754,13 @@ STEP 5: Set up environment variables for PostHog using the wizard-tools MCP serv
|
|
|
1661
3754
|
|
|
1662
3755
|
Important: Use the detect_package_manager tool (from the wizard-tools MCP server) to determine which package manager the project uses, then run its install command to add the SDK. Do not manually search for lockfiles or config files. If a file already EXISTS, read it immediately before you edit or overwrite it — writing from a stale read causes a tool failure. Creating a brand-new file needs no prior read: never read a path that does not exist yet; just write it.
|
|
1663
3756
|
|
|
1664
|
-
|
|
3757
|
+
${warehouseReportInstruction(session)}
|
|
1665
3758
|
`;
|
|
1666
3759
|
},
|
|
1667
3760
|
postRun: async (sess, credentials) => {
|
|
1668
3761
|
const envVars = config.environment.getEnvVars(credentials.projectApiKey, credentials.host.apiHost);
|
|
1669
3762
|
if (config.environment.uploadToHosting) {
|
|
1670
|
-
const { uploadEnvironmentVariablesStep } = await import("./steps-
|
|
3763
|
+
const { uploadEnvironmentVariablesStep } = await import("./steps-DyEKYM4I.js");
|
|
1671
3764
|
const uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {
|
|
1672
3765
|
integration: config.metadata.integration,
|
|
1673
3766
|
session: sess
|
|
@@ -1699,6 +3792,7 @@ Important: Use the detect_package_manager tool (from the wizard-tools MCP server
|
|
|
1699
3792
|
changes: [...config.ui.getOutroChanges(frameworkContext), Object.keys(envVars).length > 0 ? "Added environment variables to .env file" : ""].filter(Boolean),
|
|
1700
3793
|
docsUrl: config.metadata.docsUrl,
|
|
1701
3794
|
continueUrl,
|
|
3795
|
+
nextSteps: buildWarehouseNextSteps(sess),
|
|
1702
3796
|
notebookUrl: sess.notebookUrl ?? void 0,
|
|
1703
3797
|
handoffPrompt: buildCodingAgentPrompt(SETUP_REPORT_FILE)
|
|
1704
3798
|
};
|
|
@@ -1721,6 +3815,6 @@ const integrationRunStep = {
|
|
|
1721
3815
|
isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
|
|
1722
3816
|
};
|
|
1723
3817
|
//#endregion
|
|
1724
|
-
export { gatherFrameworkContext as _, LINE_CHART_BLOCK as a,
|
|
3818
|
+
export { gatherFrameworkContext as S, detectWarehousePrerequisites as _, LINE_CHART_BLOCK as a, detectProjectsWithAgent as b, TextBlock as c, isLinesBlock as d, isObjectBlock as f, WAREHOUSE_ABORT_CASES as g, HEALTH_CHECK_STEP as h, FUNNEL_BLOCK as i, computeVisibleRange as l, Icons as m, integrationRunStep as n, PRODUCT_SUITE_BLOCK as o, Colors as p, posthogIntegrationConfig as r, StatusPeekTrigger as s, SETUP_REPORT_FILE as t, isClearBlock as u, getDetectedWarehouseSources as v, resolveProjectDir as x, detectIntegrationProjects as y };
|
|
1725
3819
|
|
|
1726
|
-
//# sourceMappingURL=posthog-integration-
|
|
3820
|
+
//# sourceMappingURL=posthog-integration-Do997QON.js.map
|