@posthog/wizard 2.15.0 → 2.16.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/dist/{TextBlock-B_8bXLLs.js → TextBlock-DJVhBkr3.js} +4 -4
- package/dist/TextBlock-DJVhBkr3.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-Dq0n2yzq.js → add-mcp-server-to-clients-9jQjc-CO.js} +5 -5
- package/dist/{add-mcp-server-to-clients-Dq0n2yzq.js.map → add-mcp-server-to-clients-9jQjc-CO.js.map} +1 -1
- package/dist/{agent-interface-yB_27jG8.js → agent-interface-pBnqJL8P.js} +6 -6
- package/dist/{agent-interface-yB_27jG8.js.map → agent-interface-pBnqJL8P.js.map} +1 -1
- package/dist/{agent-runner-C9sSudE0.js → agent-runner-H1FP6XTc.js} +12 -8
- package/dist/{agent-runner-C9sSudE0.js.map → agent-runner-H1FP6XTc.js.map} +1 -1
- package/dist/{analytics-Da4QHjMw.js → analytics-DZaUgJte.js} +2 -2
- package/dist/{analytics-Da4QHjMw.js.map → analytics-DZaUgJte.js.map} +1 -1
- package/dist/analytics-DqeW7XYt.js +2 -0
- package/dist/bin.js +106 -40
- package/dist/bin.js.map +1 -1
- package/dist/{debug-D5kt4fxB.js → debug-B6rX6xye.js} +1 -1
- package/dist/{debug-DRKLej5r.js → debug-C4jRuzny.js} +4 -2
- package/dist/{debug-DRKLej5r.js.map → debug-C4jRuzny.js.map} +1 -1
- package/dist/{defaults-CPH6eWhN.js → defaults-GbLPuHxj.js} +1 -1
- package/dist/{defaults-CPH6eWhN.js.map → defaults-GbLPuHxj.js.map} +1 -1
- package/dist/{detection-0Pz2NncX.js → detection-4eukp9HD.js} +3 -3
- package/dist/{detection-0Pz2NncX.js.map → detection-4eukp9HD.js.map} +1 -1
- package/dist/{env-api-key-HFqv1l-z.js → env-api-key-DU8uIEvo.js} +1 -1
- package/dist/{env-api-key-HFqv1l-z.js.map → env-api-key-DU8uIEvo.js.map} +1 -1
- package/dist/mcp-prompt-streaming-DKiaymMt.js +200 -0
- package/dist/mcp-prompt-streaming-DKiaymMt.js.map +1 -0
- package/dist/{package-manager-DlTISyej.js → package-manager-DLt75bit.js} +2 -2
- package/dist/{package-manager-DlTISyej.js.map → package-manager-DLt75bit.js.map} +1 -1
- package/dist/{posthog-B1G0raJU.js → posthog-7B92c2Ed.js} +1 -1
- package/dist/{posthog-B1G0raJU.js.map → posthog-7B92c2Ed.js.map} +1 -1
- package/dist/{posthog-integration-D-DyEJvz.js → posthog-integration-CukaeYil.js} +11 -11
- package/dist/{posthog-integration-D-DyEJvz.js.map → posthog-integration-CukaeYil.js.map} +1 -1
- package/dist/{provisioning-DmN8ZDbE.js → provisioning-C_ETLiZE.js} +3 -3
- package/dist/{provisioning-DmN8ZDbE.js.map → provisioning-C_ETLiZE.js.map} +1 -1
- package/dist/provisioning-Ch6i8dRV.js +2 -0
- package/dist/{registry-CofBzIdU.js → registry-DqbwO5EL.js} +4 -4
- package/dist/{registry-CofBzIdU.js.map → registry-DqbwO5EL.js.map} +1 -1
- package/dist/setup-utils-C5uZ9g60.js +2 -0
- package/dist/{setup-utils-_P-or31U.js → setup-utils-DdAdxUTV.js} +85 -15
- package/dist/setup-utils-DdAdxUTV.js.map +1 -0
- package/dist/{slides-D3I6JzlG.js → slides-Dpj4j0w_.js} +546 -26
- package/dist/slides-Dpj4j0w_.js.map +1 -0
- package/dist/{start-playground-Bxd2KG2L.js → start-playground-B40O4tye.js} +287 -4
- package/dist/start-playground-B40O4tye.js.map +1 -0
- package/dist/{start-tui-Bl8fCbp_.js → start-tui-CH_ZzQXx.js} +65 -16
- package/dist/start-tui-CH_ZzQXx.js.map +1 -0
- package/dist/{steps-B-vmvb2V.js → steps-0d9XqvI6.js} +6 -6
- package/dist/{steps-B-vmvb2V.js.map → steps-0d9XqvI6.js.map} +1 -1
- package/dist/{task-stream-z6QFZtpC.js → task-stream-CoEsidgG.js} +3 -3
- package/dist/{task-stream-z6QFZtpC.js.map → task-stream-CoEsidgG.js.map} +1 -1
- package/dist/{telemetry-XO0SlTFs.js → telemetry-jn2Daxl2.js} +2 -2
- package/dist/{telemetry-XO0SlTFs.js.map → telemetry-jn2Daxl2.js.map} +1 -1
- package/dist/{wizard-abort-uolun8Q3.js → wizard-abort-BjLIgu2s.js} +3 -3
- package/dist/{wizard-abort-uolun8Q3.js.map → wizard-abort-BjLIgu2s.js.map} +1 -1
- package/dist/{wizard-abort-CuaS1eXn.js → wizard-abort-BlYGA1Jk.js} +1 -1
- package/dist/{wizard-session-BlgiX-5d.js → wizard-session-Bi95IYca.js} +4 -1
- package/dist/wizard-session-Bi95IYca.js.map +1 -0
- package/dist/{wizard-session-DxU5ZMBN.js → wizard-session-DPGTaJ4W.js} +1 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/package.json +1 -1
- package/dist/TextBlock-B_8bXLLs.js.map +0 -1
- package/dist/analytics-BnR9904x.js +0 -2
- package/dist/provisioning-COeHnCVG.js +0 -2
- package/dist/setup-utils-C5iSJ3eg.js +0 -2
- package/dist/setup-utils-_P-or31U.js.map +0 -1
- package/dist/slides-D3I6JzlG.js.map +0 -1
- package/dist/start-playground-Bxd2KG2L.js.map +0 -1
- package/dist/start-tui-Bl8fCbp_.js.map +0 -1
- package/dist/wizard-session-BlgiX-5d.js.map +0 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { W as WIZARD_USER_AGENT, Y as runtimeEnv, s as logToFile } from "./debug-C4jRuzny.js";
|
|
2
|
+
//#region src/lib/agent/mcp-prompt-streaming.ts
|
|
3
|
+
let _sdkModule = null;
|
|
4
|
+
async function loadSdk() {
|
|
5
|
+
if (!_sdkModule) _sdkModule = await import("@anthropic-ai/claude-agent-sdk");
|
|
6
|
+
return _sdkModule;
|
|
7
|
+
}
|
|
8
|
+
const MODEL = "claude-sonnet-4-6";
|
|
9
|
+
const MAX_TURNS = 30;
|
|
10
|
+
function resolveMcpUrl(host) {
|
|
11
|
+
const override = runtimeEnv("MCP_URL");
|
|
12
|
+
if (override) return override;
|
|
13
|
+
const hostname = parseHostname(host);
|
|
14
|
+
return hostname === "eu.posthog.com" || hostname.endsWith(".eu.posthog.com") ? "https://mcp-eu.posthog.com/mcp" : "https://mcp.posthog.com/mcp";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalize a host string into a hostname suitable for trust checks.
|
|
18
|
+
* Accepts either a full URL (`https://us.posthog.com`) or a bare host
|
|
19
|
+
* (`us.posthog.com`). Returns the hostname lowercased, or the trimmed
|
|
20
|
+
* input lowercased if parsing fails (defensive fallback so a malformed
|
|
21
|
+
* value still resolves to the safer-default US endpoint).
|
|
22
|
+
*/
|
|
23
|
+
function parseHostname(raw) {
|
|
24
|
+
const trimmed = raw.trim().toLowerCase();
|
|
25
|
+
try {
|
|
26
|
+
const withScheme = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
|
|
27
|
+
return new URL(withScheme).hostname.toLowerCase();
|
|
28
|
+
} catch {
|
|
29
|
+
return trimmed;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract a short, single-line summary from an arbitrary value. Used
|
|
34
|
+
* for tool-call args and tool-result bodies so the screen has something
|
|
35
|
+
* compact to render.
|
|
36
|
+
*/
|
|
37
|
+
function summarize(value, maxLen = 120) {
|
|
38
|
+
if (value == null) return "";
|
|
39
|
+
let text;
|
|
40
|
+
if (typeof value === "string") text = value;
|
|
41
|
+
else try {
|
|
42
|
+
text = JSON.stringify(value);
|
|
43
|
+
} catch {
|
|
44
|
+
text = String(value);
|
|
45
|
+
}
|
|
46
|
+
text = text.replace(/\s+/g, " ").trim();
|
|
47
|
+
if (text.length > maxLen) text = text.slice(0, maxLen - 1) + "…";
|
|
48
|
+
return text;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert one SDK message into zero or more AgentChunks. Mirrors the
|
|
52
|
+
* subset of message shapes the wizard's main runAgent middleware
|
|
53
|
+
* handles, but narrowed to just the kinds the screen needs to render.
|
|
54
|
+
*/
|
|
55
|
+
function messageToChunks(message) {
|
|
56
|
+
const chunks = [];
|
|
57
|
+
if (message?.type === "assistant") {
|
|
58
|
+
const content = message.message?.content;
|
|
59
|
+
if (Array.isArray(content)) for (const block of content) {
|
|
60
|
+
if (!block || typeof block !== "object") continue;
|
|
61
|
+
const type = block.type;
|
|
62
|
+
if (type === "text") {
|
|
63
|
+
const text = block.text ?? "";
|
|
64
|
+
if (text) chunks.push({
|
|
65
|
+
kind: "text",
|
|
66
|
+
text
|
|
67
|
+
});
|
|
68
|
+
} else if (type === "tool_use") {
|
|
69
|
+
const name = block.name ?? "tool";
|
|
70
|
+
const input = block.input;
|
|
71
|
+
chunks.push({
|
|
72
|
+
kind: "tool-call",
|
|
73
|
+
toolName: name,
|
|
74
|
+
detail: summarize(input)
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (message?.type === "user") {
|
|
80
|
+
const content = message.message?.content;
|
|
81
|
+
if (Array.isArray(content)) for (const block of content) {
|
|
82
|
+
if (!block || typeof block !== "object") continue;
|
|
83
|
+
if (block.type === "tool_result") {
|
|
84
|
+
const detail = summarize(block.content);
|
|
85
|
+
chunks.push({
|
|
86
|
+
kind: "tool-result",
|
|
87
|
+
toolName: "tool",
|
|
88
|
+
detail
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (message?.type === "result") chunks.push({ kind: "done" });
|
|
94
|
+
return chunks;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build a system-prompt append that nudges the agent to fit its response
|
|
98
|
+
* inside the current terminal window. We can't actually constrain Claude
|
|
99
|
+
* — this is a soft cap that the model usually honors. The screen also
|
|
100
|
+
* applies a hard truncation cap as a fallback for non-compliant runs.
|
|
101
|
+
*
|
|
102
|
+
* Core principle nudged at the model: TALL CONTENT IS BAD, WIDE CONTENT
|
|
103
|
+
* IS GOOD. Default terminal is 120 columns × 24 rows — that's a lot of
|
|
104
|
+
* horizontal space, not much vertical. Spread data across columns, never
|
|
105
|
+
* stack it down rows when a horizontal layout would work.
|
|
106
|
+
*/
|
|
107
|
+
function buildTerminalFitPrompt() {
|
|
108
|
+
const cols = process.stdout.columns ?? 120;
|
|
109
|
+
const rows = process.stdout.rows ?? 24;
|
|
110
|
+
const messageBudget = Math.max(8, rows - 10);
|
|
111
|
+
const tableRowBudget = Math.min(8, Math.max(3, rows - 14));
|
|
112
|
+
return [
|
|
113
|
+
`You are responding inside a CLI window that is exactly ${cols} columns wide and ${rows} rows tall. The user CAN'T SCROLL — your entire reply must fit on screen.`,
|
|
114
|
+
``,
|
|
115
|
+
`LAYOUT PRINCIPLE: tall content is the enemy, wide content is your friend. You have ${cols} columns of horizontal space; use them. Spread data across columns instead of stacking it down rows.`,
|
|
116
|
+
``,
|
|
117
|
+
`Hard limits:`,
|
|
118
|
+
`- Aim for 3-6 lines of prose. Maximum ${messageBudget} lines total.`,
|
|
119
|
+
`- Tables: max ${tableRowBudget} rows. Prefer MULTI-COLUMN tables (5-8 columns) over narrow tables with many rows. A two-column table with a long list of rows is exactly what to AVOID — that's the tall layout. If you have many key/value pairs, transpose them: keys as column headers across the top, values as a single wide row underneath.`,
|
|
120
|
+
`- Lists: if there are 6+ short items, format them inline (comma-separated) or in 2-3 columns, not as a vertical bullet list.`,
|
|
121
|
+
`- For tool results, summarize the 1-3 numbers that matter. Do NOT echo raw JSON or the full payload.`,
|
|
122
|
+
`- Code blocks: no language tag, no leading blank lines.`,
|
|
123
|
+
`- No closing pleasantries ("let me know if…", "feel free to…"). Stop when the answer is delivered.`,
|
|
124
|
+
`- No section headers unless the response actually has multiple sections.`,
|
|
125
|
+
`- The last paragraph should always be one line that says "Now go use our MCP to build something!"`
|
|
126
|
+
].join("\n");
|
|
127
|
+
}
|
|
128
|
+
async function* runMcpPromptViaSdk(args) {
|
|
129
|
+
const { prompt, credentials, signal } = args;
|
|
130
|
+
const { query } = await loadSdk();
|
|
131
|
+
const abortController = new AbortController();
|
|
132
|
+
if (signal.aborted) abortController.abort();
|
|
133
|
+
else signal.addEventListener("abort", () => abortController.abort(), { once: true });
|
|
134
|
+
const mcpUrl = resolveMcpUrl(credentials.host);
|
|
135
|
+
logToFile(`[runMcpPromptViaSdk] mcpUrl=${mcpUrl} model=${MODEL}`);
|
|
136
|
+
const createPromptStream = async function* () {
|
|
137
|
+
yield {
|
|
138
|
+
type: "user",
|
|
139
|
+
session_id: "",
|
|
140
|
+
message: {
|
|
141
|
+
role: "user",
|
|
142
|
+
content: prompt
|
|
143
|
+
},
|
|
144
|
+
parent_tool_use_id: null
|
|
145
|
+
};
|
|
146
|
+
await new Promise((resolve) => {
|
|
147
|
+
if (abortController.signal.aborted) {
|
|
148
|
+
resolve();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
abortController.signal.addEventListener("abort", () => resolve(), { once: true });
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
try {
|
|
155
|
+
const response = query({
|
|
156
|
+
prompt: createPromptStream(),
|
|
157
|
+
options: {
|
|
158
|
+
abortController,
|
|
159
|
+
model: MODEL,
|
|
160
|
+
cwd: process.cwd(),
|
|
161
|
+
permissionMode: "acceptEdits",
|
|
162
|
+
maxTurns: MAX_TURNS,
|
|
163
|
+
systemPrompt: {
|
|
164
|
+
type: "preset",
|
|
165
|
+
preset: "claude_code",
|
|
166
|
+
append: buildTerminalFitPrompt()
|
|
167
|
+
},
|
|
168
|
+
mcpServers: { "posthog-wizard": {
|
|
169
|
+
type: "http",
|
|
170
|
+
url: mcpUrl,
|
|
171
|
+
headers: {
|
|
172
|
+
Authorization: `Bearer ${credentials.accessToken}`,
|
|
173
|
+
"User-Agent": WIZARD_USER_AGENT
|
|
174
|
+
}
|
|
175
|
+
} },
|
|
176
|
+
allowedTools: ["mcp__posthog-wizard__*"]
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
for await (const message of response) {
|
|
180
|
+
if (signal.aborted) return;
|
|
181
|
+
for (const chunk of messageToChunks(message)) {
|
|
182
|
+
yield chunk;
|
|
183
|
+
if (chunk.kind === "done") return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} catch (err) {
|
|
187
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
188
|
+
logToFile(`[runMcpPromptViaSdk] error: ${text}`);
|
|
189
|
+
yield {
|
|
190
|
+
kind: "error",
|
|
191
|
+
text
|
|
192
|
+
};
|
|
193
|
+
} finally {
|
|
194
|
+
abortController.abort();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
export { runMcpPromptViaSdk };
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=mcp-prompt-streaming-DKiaymMt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-prompt-streaming-DKiaymMt.js","names":[],"sources":["../src/lib/agent/mcp-prompt-streaming.ts"],"sourcesContent":["/**\n * Streaming prompt runner for the McpSuggestedPromptsScreen.\n *\n * Calls the Claude Agent SDK's `query()` directly with just the PostHog\n * MCP server configured — no skills, no sandbox, no settings sources,\n * no wizard-tools. This is the lightweight cousin of `runAgent` in\n * `agent-interface.ts`: same SDK, much narrower surface, suitable for\n * \"user asked a question, show the answer\" interactions.\n *\n * The function is an async generator that yields `AgentChunk`s extracted\n * from the SDK's message stream. Callers (the screen) consume them via\n * `for await (...)` and render as they arrive.\n */\n\nimport type { AgentChunk } from '@ui/tui/services/mcp-suggested-prompts-services';\nimport type { Credentials } from '@lib/wizard-session';\nimport { WIZARD_USER_AGENT } from '@lib/constants';\nimport { runtimeEnv } from '@env';\nimport { logToFile } from '@utils/debug';\n\n// Cached SDK module — first call pays the dynamic-import cost; later\n// calls reuse the same module.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _sdkModule: any | null = null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function loadSdk(): Promise<any> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nconst MODEL = 'claude-sonnet-4-6';\n\n// Bounded turn count so a single prompt can't loop forever on the\n// user's nickel. 20 gives the agent room for non-trivial multi-step\n// chains (multi-tool reads → reason → write → verify → summarize) while\n// still capping runaway loops. Worth tuning down once we see real\n// telemetry on average turn counts per prompt.\nconst MAX_TURNS = 30;\n\nfunction resolveMcpUrl(host: string): string {\n const override = runtimeEnv('MCP_URL');\n if (override) return override;\n // Parse the actual hostname rather than substring-matching the raw\n // input. `host.includes('eu.posthog.com')` would let arbitrary URLs\n // like `https://evil.eu.posthog.com.attacker.com` or\n // `https://useu.posthog.commerce` route to the EU MCP endpoint\n // (CodeQL: incomplete-url-substring-sanitization). Parsing into a\n // hostname and checking exact match / trusted subdomain blocks both.\n const hostname = parseHostname(host);\n const isEu =\n hostname === 'eu.posthog.com' || hostname.endsWith('.eu.posthog.com');\n return isEu\n ? 'https://mcp-eu.posthog.com/mcp'\n : 'https://mcp.posthog.com/mcp';\n}\n\n/**\n * Normalize a host string into a hostname suitable for trust checks.\n * Accepts either a full URL (`https://us.posthog.com`) or a bare host\n * (`us.posthog.com`). Returns the hostname lowercased, or the trimmed\n * input lowercased if parsing fails (defensive fallback so a malformed\n * value still resolves to the safer-default US endpoint).\n */\nfunction parseHostname(raw: string): string {\n const trimmed = raw.trim().toLowerCase();\n try {\n const withScheme = trimmed.includes('://') ? trimmed : `https://${trimmed}`;\n return new URL(withScheme).hostname.toLowerCase();\n } catch {\n return trimmed;\n }\n}\n\n/**\n * Extract a short, single-line summary from an arbitrary value. Used\n * for tool-call args and tool-result bodies so the screen has something\n * compact to render.\n */\nfunction summarize(value: unknown, maxLen = 120): string {\n if (value == null) return '';\n let text: string;\n if (typeof value === 'string') text = value;\n else {\n try {\n text = JSON.stringify(value);\n } catch {\n text = String(value);\n }\n }\n text = text.replace(/\\s+/g, ' ').trim();\n if (text.length > maxLen) text = text.slice(0, maxLen - 1) + '…';\n return text;\n}\n\n/**\n * Convert one SDK message into zero or more AgentChunks. Mirrors the\n * subset of message shapes the wizard's main runAgent middleware\n * handles, but narrowed to just the kinds the screen needs to render.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction messageToChunks(message: any): AgentChunk[] {\n const chunks: AgentChunk[] = [];\n\n if (message?.type === 'assistant') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (text) chunks.push({ kind: 'text', text });\n } else if (type === 'tool_use') {\n const name = (block as { name?: string }).name ?? 'tool';\n const input = (block as { input?: unknown }).input;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n });\n }\n }\n }\n }\n\n if (message?.type === 'user') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'tool_result') {\n const detail = summarize((block as { content?: unknown }).content);\n chunks.push({ kind: 'tool-result', toolName: 'tool', detail });\n }\n }\n }\n }\n\n if (message?.type === 'result') {\n chunks.push({ kind: 'done' });\n }\n\n return chunks;\n}\n\n/**\n * Build a system-prompt append that nudges the agent to fit its response\n * inside the current terminal window. We can't actually constrain Claude\n * — this is a soft cap that the model usually honors. The screen also\n * applies a hard truncation cap as a fallback for non-compliant runs.\n *\n * Core principle nudged at the model: TALL CONTENT IS BAD, WIDE CONTENT\n * IS GOOD. Default terminal is 120 columns × 24 rows — that's a lot of\n * horizontal space, not much vertical. Spread data across columns, never\n * stack it down rows when a horizontal layout would work.\n */\nfunction buildTerminalFitPrompt(): string {\n const cols = process.stdout.columns ?? 120;\n const rows = process.stdout.rows ?? 24;\n // Reserve rows for wizard chrome (title, status, hint, margins).\n const messageBudget = Math.max(8, rows - 10);\n const tableRowBudget = Math.min(8, Math.max(3, rows - 14));\n\n return [\n `You are responding inside a CLI window that is exactly ${cols} columns wide and ${rows} rows tall. The user CAN'T SCROLL — your entire reply must fit on screen.`,\n ``,\n `LAYOUT PRINCIPLE: tall content is the enemy, wide content is your friend. You have ${cols} columns of horizontal space; use them. Spread data across columns instead of stacking it down rows.`,\n ``,\n `Hard limits:`,\n `- Aim for 3-6 lines of prose. Maximum ${messageBudget} lines total.`,\n `- Tables: max ${tableRowBudget} rows. Prefer MULTI-COLUMN tables (5-8 columns) over narrow tables with many rows. A two-column table with a long list of rows is exactly what to AVOID — that's the tall layout. If you have many key/value pairs, transpose them: keys as column headers across the top, values as a single wide row underneath.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated) or in 2-3 columns, not as a vertical bullet list.`,\n `- For tool results, summarize the 1-3 numbers that matter. Do NOT echo raw JSON or the full payload.`,\n `- Code blocks: no language tag, no leading blank lines.`,\n `- No closing pleasantries (\"let me know if…\", \"feel free to…\"). Stop when the answer is delivered.`,\n `- No section headers unless the response actually has multiple sections.`,\n `- The last paragraph should always be one line that says \"Now go use our MCP to build something!\"`,\n ].join('\\n');\n}\n\nexport async function* runMcpPromptViaSdk(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n}): AsyncIterable<AgentChunk> {\n const { prompt, credentials, signal } = args;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { query } = await loadSdk();\n\n // Bridge external AbortSignal → SDK AbortController.\n const abortController = new AbortController();\n if (signal.aborted) abortController.abort();\n else\n signal.addEventListener('abort', () => abortController.abort(), {\n once: true,\n });\n\n const mcpUrl = resolveMcpUrl(credentials.host);\n logToFile(`[runMcpPromptViaSdk] mcpUrl=${mcpUrl} model=${MODEL}`);\n\n // The SDK expects an async generator for the prompt that stays open\n // until the result is received. For a single-turn prompt we yield one\n // user message and then await an abort (which fires when streaming\n // completes or the caller cancels).\n const createPromptStream = async function* () {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n // Hold the stream open until abort. The SDK closes its end when it\n // sees a `result` message; we close ours via the abortController in\n // the finally block below.\n await new Promise<void>((resolve) => {\n if (abortController.signal.aborted) {\n resolve();\n return;\n }\n abortController.signal.addEventListener('abort', () => resolve(), {\n once: true,\n });\n });\n };\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n const response = query({\n prompt: createPromptStream(),\n options: {\n abortController,\n model: MODEL,\n cwd: process.cwd(),\n permissionMode: 'acceptEdits',\n maxTurns: MAX_TURNS,\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: buildTerminalFitPrompt(),\n },\n mcpServers: {\n 'posthog-wizard': {\n type: 'http',\n url: mcpUrl,\n headers: {\n Authorization: `Bearer ${credentials.accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n },\n },\n // Only let the agent use MCP tools — no shell, no file I/O,\n // no Read/Edit/Write. This is a chat-with-MCP run, not a\n // wizard skill execution.\n allowedTools: ['mcp__posthog-wizard__*'],\n },\n });\n\n for await (const message of response as AsyncIterable<unknown>) {\n if (signal.aborted) return;\n for (const chunk of messageToChunks(message)) {\n yield chunk;\n if (chunk.kind === 'done') return;\n }\n }\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err);\n logToFile(`[runMcpPromptViaSdk] error: ${text}`);\n yield { kind: 'error', text };\n } finally {\n // Closes the prompt stream so `query()` shuts down cleanly even if\n // we never saw a 'result' message.\n abortController.abort();\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as detectAllPackageManagers } from "./setup-utils-
|
|
1
|
+
import { h as detectAllPackageManagers } from "./setup-utils-DdAdxUTV.js";
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
//#region src/frameworks/python/utils.ts
|
|
4
4
|
/**
|
|
@@ -219,4 +219,4 @@ function gradlePackageManager() {
|
|
|
219
219
|
//#endregion
|
|
220
220
|
export { gradlePackageManager as a, getPackageManagerName as c, detectPythonPackageManagers as i, getPythonVersion as l, composerPackageManager as n, swiftPackageManager as o, detectNodePackageManagers as r, detectPackageManager as s, bundlerPackageManager as t, getPythonVersionBucket as u };
|
|
221
221
|
|
|
222
|
-
//# sourceMappingURL=package-manager-
|
|
222
|
+
//# sourceMappingURL=package-manager-DLt75bit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-manager-DlTISyej.js","names":["detectPythonPM"],"sources":["../src/frameworks/python/utils.ts","../src/lib/detection/package-manager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport type { WizardRunOptions } from '@utils/types';\n\nexport enum PythonPackageManager {\n UV = 'uv',\n POETRY = 'poetry',\n PDM = 'pdm',\n HATCH = 'hatch',\n RYE = 'rye',\n PIPENV = 'pipenv',\n CONDA = 'conda',\n PIP = 'pip',\n UNKNOWN = 'unknown',\n}\n\n/**\n * Get the installed Python version\n */\nexport function getPythonVersion(\n options: WizardRunOptions,\n): string | undefined {\n try {\n const version = execSync('python --version || python3 --version', {\n cwd: options.installDir,\n encoding: 'utf-8',\n })\n .trim()\n .replace('Python ', '');\n return version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Bucket Python version for analytics (e.g., \"3.11.x\" -> \"3.11\")\n */\nexport function getPythonVersionBucket(version: string): string {\n const match = version.match(/^(\\d+\\.\\d+)/);\n return match ? match[1] : version;\n}\n\n/**\n * Detect which package manager the project uses\n */\nexport async function detectPackageManager(\n options: WizardRunOptions,\n): Promise<PythonPackageManager> {\n const { installDir } = options;\n const fs = await import('node:fs');\n const path = await import('node:path');\n\n // Check for uv (uv.lock)\n if (fs.existsSync(path.join(installDir, 'uv.lock'))) {\n return PythonPackageManager.UV;\n }\n\n // Check pyproject.toml for various tools\n if (fs.existsSync(path.join(installDir, 'pyproject.toml'))) {\n try {\n const content = fs.readFileSync(\n path.join(installDir, 'pyproject.toml'),\n 'utf-8',\n );\n\n // Check for Poetry\n if (content.includes('[tool.poetry]')) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM\n if (content.includes('[tool.pdm]')) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Hatch\n if (content.includes('[tool.hatch]')) {\n return PythonPackageManager.HATCH;\n }\n\n // Check for Rye\n if (content.includes('[tool.rye]')) {\n return PythonPackageManager.RYE;\n }\n } catch {\n // Continue checking\n }\n }\n\n // Check for Poetry lock file\n if (fs.existsSync(path.join(installDir, 'poetry.lock'))) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM lock file\n if (fs.existsSync(path.join(installDir, 'pdm.lock'))) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Pipenv (Pipfile or Pipfile.lock)\n if (\n fs.existsSync(path.join(installDir, 'Pipfile')) ||\n fs.existsSync(path.join(installDir, 'Pipfile.lock'))\n ) {\n return PythonPackageManager.PIPENV;\n }\n\n // Check for Conda (environment.yml or environment.yaml)\n if (\n fs.existsSync(path.join(installDir, 'environment.yml')) ||\n fs.existsSync(path.join(installDir, 'environment.yaml'))\n ) {\n return PythonPackageManager.CONDA;\n }\n\n // Check for pip (requirements.txt, setup.py, setup.cfg, or pyproject.toml)\n if (\n fs.existsSync(path.join(installDir, 'requirements.txt')) ||\n fs.existsSync(path.join(installDir, 'setup.py')) ||\n fs.existsSync(path.join(installDir, 'setup.cfg')) ||\n fs.existsSync(path.join(installDir, 'pyproject.toml'))\n ) {\n return PythonPackageManager.PIP;\n }\n\n // Check for requirements directory\n try {\n const requirementsDir = path.join(installDir, 'requirements');\n if (\n fs.existsSync(requirementsDir) &&\n fs.statSync(requirementsDir).isDirectory()\n ) {\n const files = fs.readdirSync(requirementsDir);\n if (files.some((f) => f.endsWith('.txt'))) {\n return PythonPackageManager.PIP;\n }\n }\n } catch {\n // Continue\n }\n\n return PythonPackageManager.UNKNOWN;\n}\n\n/**\n * Get package manager display name\n */\nexport function getPackageManagerName(\n packageManager: PythonPackageManager,\n): string {\n switch (packageManager) {\n case PythonPackageManager.UV:\n return 'uv';\n case PythonPackageManager.POETRY:\n return 'Poetry';\n case PythonPackageManager.PDM:\n return 'PDM';\n case PythonPackageManager.HATCH:\n return 'Hatch';\n case PythonPackageManager.RYE:\n return 'Rye';\n case PythonPackageManager.PIPENV:\n return 'Pipenv';\n case PythonPackageManager.CONDA:\n return 'Conda';\n case PythonPackageManager.PIP:\n return 'pip';\n case PythonPackageManager.UNKNOWN:\n return 'unknown';\n }\n}\n","/**\n * Cross-ecosystem package manager detection.\n *\n * Provides a common interface (PackageManagerDetector) that each FrameworkConfig\n * implements, plus shared helpers for Node.js, Python, PHP, and Swift ecosystems.\n * The MCP tool in wizard-tools.ts delegates to whatever detector the\n * current framework supplies.\n */\n\nimport {\n detectAllPackageManagers,\n type PackageManager,\n} from '@utils/package-manager';\nimport {\n detectPackageManager as detectPythonPM,\n PythonPackageManager,\n} from '@frameworks/python/utils';\n\n// ---------------------------------------------------------------------------\n// Common types\n// ---------------------------------------------------------------------------\n\n/** Structured package manager info the agent can act on */\nexport interface DetectedPackageManager {\n name: string;\n label: string;\n installCommand: string;\n runCommand?: string;\n}\n\n/** Result returned by every detector */\nexport interface PackageManagerInfo {\n detected: DetectedPackageManager[];\n primary: DetectedPackageManager | null;\n recommendation: string;\n}\n\n/** Signature each framework implements */\nexport type PackageManagerDetector = (\n installDir: string,\n) => Promise<PackageManagerInfo>;\n\n// ---------------------------------------------------------------------------\n// Node.js helper\n// ---------------------------------------------------------------------------\n\nfunction serializeNodePM(pm: PackageManager): DetectedPackageManager {\n return {\n name: pm.name,\n label: pm.label,\n installCommand: pm.installCommand,\n runCommand: pm.runScriptCommand,\n };\n}\n\n/**\n * Detect Node.js package managers via lockfiles.\n * Wraps the existing detectAllPackageManagers() from utils/package-manager.ts.\n */\nexport function detectNodePackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const detected = detectAllPackageManagers({ installDir }).map(\n serializeNodePM,\n );\n\n if (detected.length === 0) {\n return Promise.resolve({\n detected: [],\n primary: null,\n recommendation: 'No lockfile found. Default to npm (npm add, npm run).',\n });\n }\n\n const primary = detected[0];\n return Promise.resolve({\n detected,\n primary,\n recommendation:\n detected.length === 1\n ? `Use ${primary.label} (${primary.installCommand}).`\n : `Multiple package managers detected. Prefer ${primary.label} (${primary.installCommand}).`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Python helper\n// ---------------------------------------------------------------------------\n\nconst PYTHON_PM_INFO: Record<PythonPackageManager, DetectedPackageManager> = {\n [PythonPackageManager.UV]: {\n name: 'uv',\n label: 'uv',\n installCommand: 'uv add',\n runCommand: 'uv run',\n },\n [PythonPackageManager.POETRY]: {\n name: 'poetry',\n label: 'Poetry',\n installCommand: 'poetry add',\n runCommand: 'poetry run',\n },\n [PythonPackageManager.PDM]: {\n name: 'pdm',\n label: 'PDM',\n installCommand: 'pdm add',\n runCommand: 'pdm run',\n },\n [PythonPackageManager.HATCH]: {\n name: 'hatch',\n label: 'Hatch',\n installCommand: 'hatch add',\n runCommand: 'hatch run',\n },\n [PythonPackageManager.RYE]: {\n name: 'rye',\n label: 'Rye',\n installCommand: 'rye add',\n runCommand: 'rye run',\n },\n [PythonPackageManager.PIPENV]: {\n name: 'pipenv',\n label: 'Pipenv',\n installCommand: 'pipenv install',\n runCommand: 'pipenv run',\n },\n [PythonPackageManager.CONDA]: {\n name: 'conda',\n label: 'Conda',\n installCommand: 'conda install',\n runCommand: 'conda run',\n },\n [PythonPackageManager.PIP]: {\n name: 'pip',\n label: 'pip',\n installCommand: 'pip install',\n },\n [PythonPackageManager.UNKNOWN]: {\n name: 'pip',\n label: 'pip (default)',\n installCommand: 'pip install',\n },\n};\n\n/**\n * Detect Python package managers via lockfiles and config files.\n * Wraps the existing detectPackageManager() from python/utils.ts.\n */\nexport async function detectPythonPackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const pm = await detectPythonPM({ installDir } as any);\n const info = PYTHON_PM_INFO[pm];\n\n return {\n detected: [info],\n primary: info,\n recommendation: `Use ${info.label} (${info.installCommand}).`,\n };\n}\n\n// ---------------------------------------------------------------------------\n// PHP (Composer) helper\n// ---------------------------------------------------------------------------\n\nconst COMPOSER: DetectedPackageManager = {\n name: 'composer',\n label: 'Composer',\n installCommand: 'composer require',\n};\n\nexport function composerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [COMPOSER],\n primary: COMPOSER,\n recommendation: 'Use Composer (composer require).',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Swift (SPM) helper\n// ---------------------------------------------------------------------------\n\nconst SPM: DetectedPackageManager = {\n name: 'spm',\n label: 'Swift Package Manager',\n installCommand: 'swift package add-dependency',\n};\n\nexport function swiftPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [SPM],\n primary: SPM,\n recommendation:\n 'Use Swift Package Manager. Add the dependency to Package.swift or via Xcode.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Ruby (Bundler) helper\n// ---------------------------------------------------------------------------\n\nconst BUNDLER: DetectedPackageManager = {\n name: 'bundler',\n label: 'Bundler',\n installCommand: 'bundle add',\n runCommand: 'bundle exec',\n};\n\nexport function bundlerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [BUNDLER],\n primary: BUNDLER,\n recommendation: 'Use Bundler (bundle add). Run commands with bundle exec.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Android (Gradle) helper\n// ---------------------------------------------------------------------------\n\nconst GRADLE: DetectedPackageManager = {\n name: 'gradle',\n label: 'Gradle',\n installCommand: 'implementation',\n};\n\nexport function gradlePackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [GRADLE],\n primary: GRADLE,\n recommendation:\n 'Add dependencies to build.gradle(.kts) using implementation().',\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"package-manager-DLt75bit.js","names":["detectPythonPM"],"sources":["../src/frameworks/python/utils.ts","../src/lib/detection/package-manager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport type { WizardRunOptions } from '@utils/types';\n\nexport enum PythonPackageManager {\n UV = 'uv',\n POETRY = 'poetry',\n PDM = 'pdm',\n HATCH = 'hatch',\n RYE = 'rye',\n PIPENV = 'pipenv',\n CONDA = 'conda',\n PIP = 'pip',\n UNKNOWN = 'unknown',\n}\n\n/**\n * Get the installed Python version\n */\nexport function getPythonVersion(\n options: WizardRunOptions,\n): string | undefined {\n try {\n const version = execSync('python --version || python3 --version', {\n cwd: options.installDir,\n encoding: 'utf-8',\n })\n .trim()\n .replace('Python ', '');\n return version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Bucket Python version for analytics (e.g., \"3.11.x\" -> \"3.11\")\n */\nexport function getPythonVersionBucket(version: string): string {\n const match = version.match(/^(\\d+\\.\\d+)/);\n return match ? match[1] : version;\n}\n\n/**\n * Detect which package manager the project uses\n */\nexport async function detectPackageManager(\n options: WizardRunOptions,\n): Promise<PythonPackageManager> {\n const { installDir } = options;\n const fs = await import('node:fs');\n const path = await import('node:path');\n\n // Check for uv (uv.lock)\n if (fs.existsSync(path.join(installDir, 'uv.lock'))) {\n return PythonPackageManager.UV;\n }\n\n // Check pyproject.toml for various tools\n if (fs.existsSync(path.join(installDir, 'pyproject.toml'))) {\n try {\n const content = fs.readFileSync(\n path.join(installDir, 'pyproject.toml'),\n 'utf-8',\n );\n\n // Check for Poetry\n if (content.includes('[tool.poetry]')) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM\n if (content.includes('[tool.pdm]')) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Hatch\n if (content.includes('[tool.hatch]')) {\n return PythonPackageManager.HATCH;\n }\n\n // Check for Rye\n if (content.includes('[tool.rye]')) {\n return PythonPackageManager.RYE;\n }\n } catch {\n // Continue checking\n }\n }\n\n // Check for Poetry lock file\n if (fs.existsSync(path.join(installDir, 'poetry.lock'))) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM lock file\n if (fs.existsSync(path.join(installDir, 'pdm.lock'))) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Pipenv (Pipfile or Pipfile.lock)\n if (\n fs.existsSync(path.join(installDir, 'Pipfile')) ||\n fs.existsSync(path.join(installDir, 'Pipfile.lock'))\n ) {\n return PythonPackageManager.PIPENV;\n }\n\n // Check for Conda (environment.yml or environment.yaml)\n if (\n fs.existsSync(path.join(installDir, 'environment.yml')) ||\n fs.existsSync(path.join(installDir, 'environment.yaml'))\n ) {\n return PythonPackageManager.CONDA;\n }\n\n // Check for pip (requirements.txt, setup.py, setup.cfg, or pyproject.toml)\n if (\n fs.existsSync(path.join(installDir, 'requirements.txt')) ||\n fs.existsSync(path.join(installDir, 'setup.py')) ||\n fs.existsSync(path.join(installDir, 'setup.cfg')) ||\n fs.existsSync(path.join(installDir, 'pyproject.toml'))\n ) {\n return PythonPackageManager.PIP;\n }\n\n // Check for requirements directory\n try {\n const requirementsDir = path.join(installDir, 'requirements');\n if (\n fs.existsSync(requirementsDir) &&\n fs.statSync(requirementsDir).isDirectory()\n ) {\n const files = fs.readdirSync(requirementsDir);\n if (files.some((f) => f.endsWith('.txt'))) {\n return PythonPackageManager.PIP;\n }\n }\n } catch {\n // Continue\n }\n\n return PythonPackageManager.UNKNOWN;\n}\n\n/**\n * Get package manager display name\n */\nexport function getPackageManagerName(\n packageManager: PythonPackageManager,\n): string {\n switch (packageManager) {\n case PythonPackageManager.UV:\n return 'uv';\n case PythonPackageManager.POETRY:\n return 'Poetry';\n case PythonPackageManager.PDM:\n return 'PDM';\n case PythonPackageManager.HATCH:\n return 'Hatch';\n case PythonPackageManager.RYE:\n return 'Rye';\n case PythonPackageManager.PIPENV:\n return 'Pipenv';\n case PythonPackageManager.CONDA:\n return 'Conda';\n case PythonPackageManager.PIP:\n return 'pip';\n case PythonPackageManager.UNKNOWN:\n return 'unknown';\n }\n}\n","/**\n * Cross-ecosystem package manager detection.\n *\n * Provides a common interface (PackageManagerDetector) that each FrameworkConfig\n * implements, plus shared helpers for Node.js, Python, PHP, and Swift ecosystems.\n * The MCP tool in wizard-tools.ts delegates to whatever detector the\n * current framework supplies.\n */\n\nimport {\n detectAllPackageManagers,\n type PackageManager,\n} from '@utils/package-manager';\nimport {\n detectPackageManager as detectPythonPM,\n PythonPackageManager,\n} from '@frameworks/python/utils';\n\n// ---------------------------------------------------------------------------\n// Common types\n// ---------------------------------------------------------------------------\n\n/** Structured package manager info the agent can act on */\nexport interface DetectedPackageManager {\n name: string;\n label: string;\n installCommand: string;\n runCommand?: string;\n}\n\n/** Result returned by every detector */\nexport interface PackageManagerInfo {\n detected: DetectedPackageManager[];\n primary: DetectedPackageManager | null;\n recommendation: string;\n}\n\n/** Signature each framework implements */\nexport type PackageManagerDetector = (\n installDir: string,\n) => Promise<PackageManagerInfo>;\n\n// ---------------------------------------------------------------------------\n// Node.js helper\n// ---------------------------------------------------------------------------\n\nfunction serializeNodePM(pm: PackageManager): DetectedPackageManager {\n return {\n name: pm.name,\n label: pm.label,\n installCommand: pm.installCommand,\n runCommand: pm.runScriptCommand,\n };\n}\n\n/**\n * Detect Node.js package managers via lockfiles.\n * Wraps the existing detectAllPackageManagers() from utils/package-manager.ts.\n */\nexport function detectNodePackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const detected = detectAllPackageManagers({ installDir }).map(\n serializeNodePM,\n );\n\n if (detected.length === 0) {\n return Promise.resolve({\n detected: [],\n primary: null,\n recommendation: 'No lockfile found. Default to npm (npm add, npm run).',\n });\n }\n\n const primary = detected[0];\n return Promise.resolve({\n detected,\n primary,\n recommendation:\n detected.length === 1\n ? `Use ${primary.label} (${primary.installCommand}).`\n : `Multiple package managers detected. Prefer ${primary.label} (${primary.installCommand}).`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Python helper\n// ---------------------------------------------------------------------------\n\nconst PYTHON_PM_INFO: Record<PythonPackageManager, DetectedPackageManager> = {\n [PythonPackageManager.UV]: {\n name: 'uv',\n label: 'uv',\n installCommand: 'uv add',\n runCommand: 'uv run',\n },\n [PythonPackageManager.POETRY]: {\n name: 'poetry',\n label: 'Poetry',\n installCommand: 'poetry add',\n runCommand: 'poetry run',\n },\n [PythonPackageManager.PDM]: {\n name: 'pdm',\n label: 'PDM',\n installCommand: 'pdm add',\n runCommand: 'pdm run',\n },\n [PythonPackageManager.HATCH]: {\n name: 'hatch',\n label: 'Hatch',\n installCommand: 'hatch add',\n runCommand: 'hatch run',\n },\n [PythonPackageManager.RYE]: {\n name: 'rye',\n label: 'Rye',\n installCommand: 'rye add',\n runCommand: 'rye run',\n },\n [PythonPackageManager.PIPENV]: {\n name: 'pipenv',\n label: 'Pipenv',\n installCommand: 'pipenv install',\n runCommand: 'pipenv run',\n },\n [PythonPackageManager.CONDA]: {\n name: 'conda',\n label: 'Conda',\n installCommand: 'conda install',\n runCommand: 'conda run',\n },\n [PythonPackageManager.PIP]: {\n name: 'pip',\n label: 'pip',\n installCommand: 'pip install',\n },\n [PythonPackageManager.UNKNOWN]: {\n name: 'pip',\n label: 'pip (default)',\n installCommand: 'pip install',\n },\n};\n\n/**\n * Detect Python package managers via lockfiles and config files.\n * Wraps the existing detectPackageManager() from python/utils.ts.\n */\nexport async function detectPythonPackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const pm = await detectPythonPM({ installDir } as any);\n const info = PYTHON_PM_INFO[pm];\n\n return {\n detected: [info],\n primary: info,\n recommendation: `Use ${info.label} (${info.installCommand}).`,\n };\n}\n\n// ---------------------------------------------------------------------------\n// PHP (Composer) helper\n// ---------------------------------------------------------------------------\n\nconst COMPOSER: DetectedPackageManager = {\n name: 'composer',\n label: 'Composer',\n installCommand: 'composer require',\n};\n\nexport function composerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [COMPOSER],\n primary: COMPOSER,\n recommendation: 'Use Composer (composer require).',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Swift (SPM) helper\n// ---------------------------------------------------------------------------\n\nconst SPM: DetectedPackageManager = {\n name: 'spm',\n label: 'Swift Package Manager',\n installCommand: 'swift package add-dependency',\n};\n\nexport function swiftPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [SPM],\n primary: SPM,\n recommendation:\n 'Use Swift Package Manager. Add the dependency to Package.swift or via Xcode.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Ruby (Bundler) helper\n// ---------------------------------------------------------------------------\n\nconst BUNDLER: DetectedPackageManager = {\n name: 'bundler',\n label: 'Bundler',\n installCommand: 'bundle add',\n runCommand: 'bundle exec',\n};\n\nexport function bundlerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [BUNDLER],\n primary: BUNDLER,\n recommendation: 'Use Bundler (bundle add). Run commands with bundle exec.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Android (Gradle) helper\n// ---------------------------------------------------------------------------\n\nconst GRADLE: DetectedPackageManager = {\n name: 'gradle',\n label: 'Gradle',\n installCommand: 'implementation',\n};\n\nexport function gradlePackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [GRADLE],\n primary: GRADLE,\n recommendation:\n 'Add dependencies to build.gradle(.kts) using implementation().',\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-
|
|
1
|
+
{"version":3,"file":"posthog-7B92c2Ed.js","names":[],"sources":["../src/lib/task-stream/destinations/posthog.ts"],"sourcesContent":["/**\n * PostHog destination — pushes wizard run state to the PostHog backend\n * via `POST /api/projects/{project_id}/wizard/sessions/`.\n *\n * The endpoint is an upsert keyed by `(team, session_id)`: 201 means\n * the row was created, 200 means it was updated. Both are success.\n *\n * Failure handling is fail-silent: never throws to the caller, never\n * writes to stdout/stderr, never blocks the agent. Errors flow through\n * the optional `onError` callback for the wizard's debug log.\n *\n * Retry policy:\n * 5xx / network → exponential backoff base 500ms cap 8s, max 3 attempts\n * 429 → honour `Retry-After` (seconds), single retry\n * 401 / 403 → disable for the rest of the run, no further pushes\n * 400 → give up for this push, do not disable\n * other 4xx → give up for this push, do not disable\n */\n\nimport type {\n TaskStreamDestination,\n TaskStreamUpdate,\n StreamEvent,\n} from '@lib/task-stream/types';\nimport type { Credentials } from '@lib/wizard-session';\n\nexport interface PostHogDestinationOptions {\n /**\n * Lazy credential resolver — called on every send. Returns null\n * before authentication has completed; in that case the send is a\n * no-op (no HTTP request).\n */\n getCredentials: () => Credentials | null;\n /** Receives every error for the wizard's internal logfile. */\n onError?: (err: Error) => void;\n /** Override for tests. Defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Override for tests. Defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst MAX_ATTEMPTS = 3;\nconst BASE_BACKOFF_MS = 500;\nconst MAX_BACKOFF_MS = 8000;\nconst DEFAULT_RETRY_AFTER_MS = 1000;\n// setTimeout silently clamps anything above 2^31-1 ms to fire\n// immediately, so any Retry-After-derived sleep must be capped.\nconst MAX_RETRY_AFTER_MS = 60_000;\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfter(value: string | null): number {\n if (!value) return DEFAULT_RETRY_AFTER_MS;\n const seconds = Number(value);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(Math.ceil(seconds * 1000), MAX_RETRY_AFTER_MS);\n }\n // HTTP-date form — best-effort.\n const date = Date.parse(value);\n if (Number.isFinite(date)) {\n return Math.min(Math.max(0, date - Date.now()), MAX_RETRY_AFTER_MS);\n }\n return DEFAULT_RETRY_AFTER_MS;\n}\n\n/**\n * Strip the internal-only `timestamp` field before sending. The\n * backend schema in the RFC does not define it.\n */\nfunction toWirePayload(\n payload: TaskStreamUpdate,\n): Omit<TaskStreamUpdate, 'timestamp'> {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { timestamp: _unused, ...rest } = payload;\n return rest;\n}\n\nexport class PostHogDestination implements TaskStreamDestination {\n readonly name = 'posthog';\n\n private readonly getCredentials: () => Credentials | null;\n private readonly onError: (err: Error) => void;\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: (ms: number) => Promise<void>;\n\n private disabled = false;\n\n constructor(opts: PostHogDestinationOptions) {\n this.getCredentials = opts.getCredentials;\n this.onError = opts.onError ?? (() => undefined);\n this.fetchImpl = opts.fetchImpl ?? ((...args) => fetch(...args));\n this.sleep = opts.sleep ?? defaultSleep;\n }\n\n async send(_event: StreamEvent, payload: TaskStreamUpdate): Promise<void> {\n if (this.disabled) return;\n const creds = this.getCredentials();\n if (!creds) return;\n\n await this.postWithRetry(creds, toWirePayload(payload));\n }\n\n private buildRequest(\n creds: Credentials,\n body: object,\n ): { url: string; init: Parameters<typeof fetch>[1] } {\n const url = `${creds.host.replace(/\\/$/, '')}/api/projects/${\n creds.projectId\n }/wizard/sessions/`;\n return {\n url,\n init: {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${creds.accessToken}`,\n },\n body: JSON.stringify(body),\n },\n };\n }\n\n private async postWithRetry(creds: Credentials, body: object): Promise<void> {\n const { url, init } = this.buildRequest(creds, body);\n let attempt = 0;\n let backoff = BASE_BACKOFF_MS;\n let retriedAfter429 = false;\n\n while (attempt < MAX_ATTEMPTS) {\n attempt += 1;\n let response: Response;\n try {\n response = await this.fetchImpl(url, init);\n } catch (err) {\n if (attempt >= MAX_ATTEMPTS) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n return;\n }\n await this.sleep(backoff);\n backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);\n continue;\n }\n\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401 || status === 403) {\n this.disabled = true;\n this.onError(new Error(`wizard/sessions auth failed: ${status}`));\n return;\n }\n\n if (status === 429) {\n if (retriedAfter429) {\n this.onError(new Error('wizard/sessions rate limited'));\n return;\n }\n retriedAfter429 = true;\n const wait = parseRetryAfter(response.headers.get('Retry-After'));\n await this.sleep(wait);\n // Don't count this against the 5xx attempt budget.\n attempt -= 1;\n continue;\n }\n\n if (status >= 500) {\n if (attempt >= MAX_ATTEMPTS) {\n this.onError(new Error(`wizard/sessions server error: ${status}`));\n return;\n }\n await this.sleep(backoff);\n backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);\n continue;\n }\n\n if (status === 400) {\n let detail = '';\n try {\n detail = await response.text();\n } catch {\n // ignore\n }\n this.onError(new Error(`wizard/sessions bad request (400): ${detail}`));\n return;\n }\n\n this.onError(new Error(`wizard/sessions unexpected status: ${status}`));\n return;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { p as getUI, z as WIZARD_INTERACTION_EVENT_NAME } from "./debug-
|
|
3
|
-
import { n as analytics } from "./analytics-
|
|
4
|
-
import { a as isUsingTypeScript, f as getCloudUrlFromRegion, o as tryGetPackageJson } from "./setup-utils-
|
|
5
|
-
import { n as requestDeepLink } from "./provisioning-
|
|
6
|
-
import "./wizard-session-
|
|
7
|
-
import { t as AgentSignals, u as WIZARD_TOOL_NAMES } from "./agent-interface-
|
|
8
|
-
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-
|
|
9
|
-
import { c as HEALTH_CHECK_STEP, o as Colors } from "./TextBlock-
|
|
10
|
-
import { a as detectFramework, i as discoverFeatures, n as checkFrameworkVersion, r as gatherFrameworkContext } from "./detection-
|
|
2
|
+
import { p as getUI, z as WIZARD_INTERACTION_EVENT_NAME } from "./debug-C4jRuzny.js";
|
|
3
|
+
import { n as analytics } from "./analytics-DZaUgJte.js";
|
|
4
|
+
import { a as isUsingTypeScript, f as getCloudUrlFromRegion, o as tryGetPackageJson } from "./setup-utils-DdAdxUTV.js";
|
|
5
|
+
import { n as requestDeepLink } from "./provisioning-C_ETLiZE.js";
|
|
6
|
+
import "./wizard-session-Bi95IYca.js";
|
|
7
|
+
import { t as AgentSignals, u as WIZARD_TOOL_NAMES } from "./agent-interface-pBnqJL8P.js";
|
|
8
|
+
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-DqbwO5EL.js";
|
|
9
|
+
import { c as HEALTH_CHECK_STEP, o as Colors } from "./TextBlock-DJVhBkr3.js";
|
|
10
|
+
import { a as detectFramework, i as discoverFeatures, n as checkFrameworkVersion, r as gatherFrameworkContext } from "./detection-4eukp9HD.js";
|
|
11
11
|
import opn from "opn";
|
|
12
12
|
import { Text } from "ink";
|
|
13
13
|
import { useEffect } from "react";
|
|
@@ -944,7 +944,7 @@ Important: Use the detect_package_manager tool (from the wizard-tools MCP server
|
|
|
944
944
|
postRun: async (sess, credentials) => {
|
|
945
945
|
const envVars = config.environment.getEnvVars(credentials.projectApiKey, credentials.host);
|
|
946
946
|
if (config.environment.uploadToHosting) {
|
|
947
|
-
const { uploadEnvironmentVariablesStep } = await import("./steps-
|
|
947
|
+
const { uploadEnvironmentVariablesStep } = await import("./steps-0d9XqvI6.js");
|
|
948
948
|
const uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {
|
|
949
949
|
integration: config.metadata.integration,
|
|
950
950
|
session: sess
|
|
@@ -983,4 +983,4 @@ Important: Use the detect_package_manager tool (from the wizard-tools MCP server
|
|
|
983
983
|
//#endregion
|
|
984
984
|
export { LINE_CHART_BLOCK as a, FUNNEL_BLOCK as i, posthogIntegrationConfig as n, PRODUCT_SUITE_BLOCK as o, posthog_integration_exports as r, StatusPeekTrigger as s, EVENT_PLAN_FILE as t };
|
|
985
985
|
|
|
986
|
-
//# sourceMappingURL=posthog-integration-
|
|
986
|
+
//# sourceMappingURL=posthog-integration-CukaeYil.js.map
|