@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment-
|
|
1
|
+
{"version":3,"file":"environment-NJykOp33.js","names":[],"sources":["../src/utils/environment.ts"],"sourcesContent":["import readEnvModule from 'read-env';\n\nconst readEnv =\n typeof readEnvModule === 'function'\n ? readEnvModule\n : (readEnvModule as any).default;\nimport { tryGetPackageJson } from './setup-utils';\nimport type { WizardRunOptions } from './types';\nimport fg from 'fast-glob';\nimport { IS_DEV } from '@lib/constants';\n\nexport function isNonInteractiveEnvironment(): boolean {\n if (IS_DEV) {\n return false;\n }\n\n if (!process.stdout.isTTY || !process.stderr.isTTY) {\n return true;\n }\n\n return false;\n}\n\nexport function readEnvironment(): Record<string, unknown> {\n const result = readEnv('POSTHOG_WIZARD');\n\n return result;\n}\n\nexport async function detectEnvVarPrefix(\n options: WizardRunOptions,\n): Promise<string> {\n const packageJson = await tryGetPackageJson(options);\n if (!packageJson) return 'VITE_PUBLIC_';\n\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n const has = (name: string) => name in deps;\n const hasAnyFile = async (patterns: string[]) => {\n const matches = await fg(patterns, {\n cwd: options.installDir,\n absolute: false,\n onlyFiles: true,\n ignore: ['**/node_modules/**'],\n });\n return matches.length > 0;\n };\n\n // --- Next.js\n if (has('next') || (await hasAnyFile(['**/next.config.{js,ts,mjs,cjs}']))) {\n return 'NEXT_PUBLIC_';\n }\n\n // --- Create React App\n if (\n has('react-scripts') ||\n has('create-react-app') ||\n (await hasAnyFile(['**/config-overrides.js']))\n ) {\n return 'REACT_APP_';\n }\n\n // --- Vite (vanilla, TanStack, Solid, etc.)\n // Note: Vite does not need PUBLIC_ but we use it to follow the docs, to improve the chances of an LLM getting it right.\n if (has('vite') || (await hasAnyFile(['**/vite.config.{js,ts,mjs,cjs}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SvelteKit\n if (\n has('@sveltejs/kit') ||\n (await hasAnyFile(['**/svelte.config.{js,ts}']))\n ) {\n return 'PUBLIC_';\n }\n\n // --- TanStack Start (uses Vite)\n if (\n has('@tanstack/start') ||\n (await hasAnyFile(['**/tanstack.config.{js,ts}']))\n ) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SolidStart (uses Vite)\n if (has('solid-start') || (await hasAnyFile(['**/solid.config.{js,ts}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- Astro\n if (has('astro') || (await hasAnyFile(['**/astro.config.{js,ts,mjs}']))) {\n return 'PUBLIC_';\n }\n\n // We default to Vite if we can't detect a specific framework, since it's the most commonly used.\n return 'VITE_PUBLIC_';\n}\n"],"mappings":";;;;;;;;;;AAEA,MAAM,UACJ,OAAO,kBAAkB,aACrB,gBACC,cAAsB;AAM7B,SAAgB,8BAAuC;AAKrD,KAAI,CAAC,QAAQ,OAAO,SAAS,CAAC,QAAQ,OAAO,MAC3C,QAAO;AAGT,QAAO;;AAGT,SAAgB,kBAA2C;AAGzD,QAFe,QAAQ,iBAAiB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as analytics } from "./analytics-
|
|
1
|
+
import { n as analytics } from "./analytics-k76OWsl0.js";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
//#region src/utils/file-utils.ts
|
|
@@ -113,4 +113,4 @@ function safeReadFile(fullPath) {
|
|
|
113
113
|
//#endregion
|
|
114
114
|
export { safeReadFile as n, walkProjectFiles as r, IGNORED_DIRS as t };
|
|
115
115
|
|
|
116
|
-
//# sourceMappingURL=file-utils-
|
|
116
|
+
//# sourceMappingURL=file-utils-CLMcNIKi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-utils-
|
|
1
|
+
{"version":3,"file":"file-utils-CLMcNIKi.js","names":[],"sources":["../src/utils/file-utils.ts"],"sourcesContent":["import path from 'path';\nimport fs from 'fs';\nimport type { Dirent } from 'fs';\nimport { analytics } from './analytics';\nimport type { WizardRunOptions } from './types';\n\n/**\n * Report a swallowed filesystem error to error tracking. Traversal stays\n * best-effort — the caller still skips the failing entry — but the failure is\n * no longer silent. Preserves the original Error (and its `code`, e.g. EACCES\n * / ENOENT) when available.\n */\nfunction reportFsError(step: string, path: string, error: unknown): void {\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step, path },\n );\n}\n\nexport function getDotGitignore({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>) {\n const gitignorePath = path.join(installDir, '.gitignore');\n const gitignoreExists = fs.existsSync(gitignorePath);\n\n if (gitignoreExists) {\n return gitignorePath;\n }\n\n return undefined;\n}\n\n/**\n * Directory names to skip when recursively scanning a project tree.\n * Used by detection logic (e.g. finding all package.json files) to avoid\n * dependency directories, build output, virtual environments, etc.\n *\n * For fast-glob `ignore` patterns, map this to `**\\/<name>/**`.\n */\nexport const IGNORED_DIRS = new Set<string>([\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.turbo',\n '.cache',\n '.parcel-cache',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.coverage',\n 'venv',\n '.venv',\n '__pycache__',\n '.pytest_cache',\n 'vendor',\n 'target',\n '.gradle',\n '.idea',\n '.vscode',\n]);\n\n/**\n * Recursively walk a project tree, invoking `onFile(name, fullPath)` for every\n * regular file — including dotfiles like `.env` (the caller decides what it\n * cares about). Skips `IGNORED_DIRS` and hidden directories, follows symlinked\n * directories with realpath-based loop protection, and descends at most\n * `maxDepth` levels below `rootDir`. Filesystem errors are reported to error\n * tracking and then skipped: a missing/unreadable root simply yields no\n * callbacks (best-effort).\n *\n * Shared by the detection layers (warehouse sources, etc.) so traversal policy\n * — ignored dirs, depth, symlink handling — lives in one place.\n */\nexport function walkProjectFiles(\n rootDir: string,\n onFile: (name: string, fullPath: string) => void,\n maxDepth = 3,\n): void {\n const visited = new Set<string>();\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n // realpath both resolves symlinked dirs and gives us a stable key to\n // detect loops (symlink cycles, e.g. a -> ../a).\n let realDir: string;\n try {\n realDir = fs.realpathSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.realpath', dir, error);\n return;\n }\n if (visited.has(realDir)) return;\n visited.add(realDir);\n\n let entries: Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (error) {\n reportFsError('walkProjectFiles.readdir', dir, error);\n return;\n }\n\n for (const entry of entries) {\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n\n // Symlinks report isDirectory()/isFile() as false under withFileTypes,\n // so resolve the target before deciding how to handle the entry.\n let isDir = entry.isDirectory();\n let isFile = entry.isFile();\n if (entry.isSymbolicLink()) {\n try {\n const st = fs.statSync(fullPath);\n isDir = st.isDirectory();\n isFile = st.isFile();\n } catch (error) {\n reportFsError('walkProjectFiles.stat', fullPath, error);\n continue;\n }\n }\n\n if (isDir) {\n if (entry.name.startsWith('.')) continue; // skip hidden directories\n scan(fullPath, depth + 1);\n } else if (isFile) {\n onFile(entry.name, fullPath);\n }\n }\n }\n\n scan(rootDir, 0);\n}\n\n/**\n * Read a file as UTF-8, returning `null` on any error. Best-effort: errors are\n * reported to error tracking, then swallowed.\n */\nexport function safeReadFile(fullPath: string): string | null {\n try {\n return fs.readFileSync(fullPath, 'utf-8');\n } catch (error) {\n reportFsError('safeReadFile', fullPath, error);\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAS,cAAc,MAAc,MAAc,OAAsB;AACvE,WAAU,iBACR,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD;EAAE;EAAM;EAAM,CACf;;;;;;;;;AAuBH,MAAa,eAAe,IAAI,IAAY;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;;;;AAcF,SAAgB,iBACd,SACA,QACA,WAAW,GACL;CACN,MAAM,0BAAU,IAAI,KAAa;CAEjC,SAAS,KAAK,KAAa,OAAqB;AAC9C,MAAI,QAAQ,SAAU;EAItB,IAAI;AACJ,MAAI;AACF,aAAU,GAAG,aAAa,IAAI;WACvB,OAAO;AACd,iBAAc,6BAA6B,KAAK,MAAM;AACtD;;AAEF,MAAI,QAAQ,IAAI,QAAQ,CAAE;AAC1B,UAAQ,IAAI,QAAQ;EAEpB,IAAI;AACJ,MAAI;AACF,aAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;WAC/C,OAAO;AACd,iBAAc,4BAA4B,KAAK,MAAM;AACrD;;AAGF,OAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,aAAa,IAAI,MAAM,KAAK,CAAE;GAElC,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;GAI3C,IAAI,QAAQ,MAAM,aAAa;GAC/B,IAAI,SAAS,MAAM,QAAQ;AAC3B,OAAI,MAAM,gBAAgB,CACxB,KAAI;IACF,MAAM,KAAK,GAAG,SAAS,SAAS;AAChC,YAAQ,GAAG,aAAa;AACxB,aAAS,GAAG,QAAQ;YACb,OAAO;AACd,kBAAc,yBAAyB,UAAU,MAAM;AACvD;;AAIJ,OAAI,OAAO;AACT,QAAI,MAAM,KAAK,WAAW,IAAI,CAAE;AAChC,SAAK,UAAU,QAAQ,EAAE;cAChB,OACT,QAAO,MAAM,MAAM,SAAS;;;AAKlC,MAAK,SAAS,EAAE;;;;;;AAOlB,SAAgB,aAAa,UAAiC;AAC5D,KAAI;AACF,SAAO,GAAG,aAAa,UAAU,QAAQ;UAClC,OAAO;AACd,gBAAc,gBAAgB,UAAU,MAAM;AAC9C,SAAO"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { s as logToFile } from "./debug-C9HmIrwx.js";
|
|
2
|
+
import * as fs$1 from "fs";
|
|
3
|
+
import { basename, dirname } from "node:path";
|
|
4
|
+
//#region src/lib/file-watcher.ts
|
|
5
|
+
/**
|
|
6
|
+
* JSON file watcher shared by runner and UI machinery.
|
|
7
|
+
*
|
|
8
|
+
* `fs.watch` alone is unreliable for atomic-rename writes, so the watcher
|
|
9
|
+
* pairs it with a continuous mtime-polled re-read. The poll catches missed
|
|
10
|
+
* events; the watch keeps latency low when it does fire.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
13
|
+
const DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1e3;
|
|
14
|
+
const DEFAULT_WATCH_DEBOUNCE_MS = 25;
|
|
15
|
+
/** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the
|
|
16
|
+
* file's mtime changes and the contents are valid JSON. Caller must invoke
|
|
17
|
+
* `handle.stop()` to release the watcher. */
|
|
18
|
+
function startFileWatcher(path, onUpdate, options = {}) {
|
|
19
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
20
|
+
const attachRetryIntervalMs = options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;
|
|
21
|
+
const watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;
|
|
22
|
+
const watchers = [];
|
|
23
|
+
const intervals = [];
|
|
24
|
+
const targetDir = dirname(path);
|
|
25
|
+
const targetName = basename(path);
|
|
26
|
+
let lastMtimeMs = 0;
|
|
27
|
+
let ignoredInitialSignature = null;
|
|
28
|
+
let watchDebounceTimer = null;
|
|
29
|
+
let lastReadErrorSignature = null;
|
|
30
|
+
let stopped = false;
|
|
31
|
+
const signature = (stat) => `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;
|
|
32
|
+
if (options.ignoreInitialFile) try {
|
|
33
|
+
const stat = fs$1.lstatSync(path);
|
|
34
|
+
if (stat.isFile() && !stat.isSymbolicLink()) ignoredInitialSignature = signature(stat);
|
|
35
|
+
} catch {}
|
|
36
|
+
const logReadError = (errorSignature, message) => {
|
|
37
|
+
if (lastReadErrorSignature === errorSignature) return;
|
|
38
|
+
lastReadErrorSignature = errorSignature;
|
|
39
|
+
logToFile(`[file-watcher] ${message}: ${path}`);
|
|
40
|
+
};
|
|
41
|
+
const read = (force = false) => {
|
|
42
|
+
let stat;
|
|
43
|
+
try {
|
|
44
|
+
stat = fs$1.lstatSync(path);
|
|
45
|
+
} catch {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return;
|
|
49
|
+
const fileSignature = signature(stat);
|
|
50
|
+
try {
|
|
51
|
+
if (ignoredInitialSignature) {
|
|
52
|
+
if (fileSignature === ignoredInitialSignature) return;
|
|
53
|
+
ignoredInitialSignature = null;
|
|
54
|
+
}
|
|
55
|
+
if (options.maxFileSizeBytes !== void 0 && stat.size > options.maxFileSizeBytes) {
|
|
56
|
+
logReadError(`oversized:${fileSignature}`, `refusing oversized JSON file (${stat.size} bytes, limit ${options.maxFileSizeBytes} bytes)`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!force && stat.mtimeMs === lastMtimeMs) return;
|
|
60
|
+
lastMtimeMs = stat.mtimeMs;
|
|
61
|
+
const parsed = JSON.parse(fs$1.readFileSync(path, "utf-8"));
|
|
62
|
+
lastReadErrorSignature = null;
|
|
63
|
+
onUpdate(parsed);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
logReadError(`invalid:${fileSignature}:${String(error)}`, `could not read valid JSON (${String(error)})`);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const scheduleRead = () => {
|
|
69
|
+
if (stopped) return;
|
|
70
|
+
if (watchDebounceTimer) clearTimeout(watchDebounceTimer);
|
|
71
|
+
watchDebounceTimer = setTimeout(() => {
|
|
72
|
+
watchDebounceTimer = null;
|
|
73
|
+
read(true);
|
|
74
|
+
}, watchDebounceMs);
|
|
75
|
+
};
|
|
76
|
+
const attachWatch = () => {
|
|
77
|
+
watchers.push(fs$1.watch(targetDir, (_eventType, filename) => {
|
|
78
|
+
if (filename == null || filename.toString() === targetName) scheduleRead();
|
|
79
|
+
}));
|
|
80
|
+
};
|
|
81
|
+
intervals.push(setInterval(() => read(), pollIntervalMs));
|
|
82
|
+
try {
|
|
83
|
+
attachWatch();
|
|
84
|
+
queueMicrotask(() => {
|
|
85
|
+
if (!stopped) read(true);
|
|
86
|
+
});
|
|
87
|
+
} catch {
|
|
88
|
+
const attachInterval = setInterval(() => {
|
|
89
|
+
try {
|
|
90
|
+
fs$1.accessSync(targetDir);
|
|
91
|
+
clearInterval(attachInterval);
|
|
92
|
+
const idx = intervals.indexOf(attachInterval);
|
|
93
|
+
if (idx >= 0) intervals.splice(idx, 1);
|
|
94
|
+
attachWatch();
|
|
95
|
+
read(true);
|
|
96
|
+
} catch {}
|
|
97
|
+
}, attachRetryIntervalMs);
|
|
98
|
+
intervals.push(attachInterval);
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
refresh() {
|
|
102
|
+
if (stopped) return;
|
|
103
|
+
if (watchDebounceTimer) {
|
|
104
|
+
clearTimeout(watchDebounceTimer);
|
|
105
|
+
watchDebounceTimer = null;
|
|
106
|
+
}
|
|
107
|
+
read(true);
|
|
108
|
+
},
|
|
109
|
+
stop() {
|
|
110
|
+
stopped = true;
|
|
111
|
+
if (watchDebounceTimer) {
|
|
112
|
+
clearTimeout(watchDebounceTimer);
|
|
113
|
+
watchDebounceTimer = null;
|
|
114
|
+
}
|
|
115
|
+
for (const watcher of watchers) watcher.close();
|
|
116
|
+
for (const interval of intervals) clearInterval(interval);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
export { startFileWatcher as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=file-watcher-CBDCNQVV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher-CBDCNQVV.js","names":["fs"],"sources":["../src/lib/file-watcher.ts"],"sourcesContent":["/**\n * JSON file watcher shared by runner and UI machinery.\n *\n * `fs.watch` alone is unreliable for atomic-rename writes, so the watcher\n * pairs it with a continuous mtime-polled re-read. The poll catches missed\n * events; the watch keeps latency low when it does fire.\n */\n\nimport * as fs from 'fs';\nimport { basename, dirname } from 'node:path';\nimport { logToFile } from '@utils/debug';\n\nconst DEFAULT_POLL_INTERVAL_MS = 5000;\nconst DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1000;\nconst DEFAULT_WATCH_DEBOUNCE_MS = 25;\n\nexport interface FileWatcherHandle {\n refresh(): void;\n stop(): void;\n}\n\nexport interface FileWatcherOptions {\n /** ms between mtime checks once the file exists. */\n pollIntervalMs?: number;\n /** ms between attach attempts while waiting for the file to appear. */\n attachRetryIntervalMs?: number;\n /** ms to coalesce duplicate filesystem events. */\n watchDebounceMs?: number;\n /** Ignore the file that exists when the watcher starts until it changes. */\n ignoreInitialFile?: boolean;\n /** Refuse to read files larger than this many bytes. */\n maxFileSizeBytes?: number;\n}\n\n/** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the\n * file's mtime changes and the contents are valid JSON. Caller must invoke\n * `handle.stop()` to release the watcher. */\nexport function startFileWatcher(\n path: string,\n onUpdate: (parsed: unknown) => void,\n options: FileWatcherOptions = {},\n): FileWatcherHandle {\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const attachRetryIntervalMs =\n options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;\n const watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;\n\n const watchers: fs.FSWatcher[] = [];\n const intervals: Array<ReturnType<typeof setInterval>> = [];\n const targetDir = dirname(path);\n const targetName = basename(path);\n let lastMtimeMs = 0;\n let ignoredInitialSignature: string | null = null;\n let watchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let lastReadErrorSignature: string | null = null;\n let stopped = false;\n\n const signature = (stat: fs.Stats): string =>\n `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;\n\n if (options.ignoreInitialFile) {\n try {\n const stat = fs.lstatSync(path);\n if (stat.isFile() && !stat.isSymbolicLink()) {\n ignoredInitialSignature = signature(stat);\n }\n } catch {\n // No initial file to ignore.\n }\n }\n\n const logReadError = (errorSignature: string, message: string) => {\n if (lastReadErrorSignature === errorSignature) return;\n lastReadErrorSignature = errorSignature;\n logToFile(`[file-watcher] ${message}: ${path}`);\n };\n\n const read = (force = false) => {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(path);\n } catch {\n return;\n }\n\n if (!stat.isFile() || stat.isSymbolicLink()) return;\n const fileSignature = signature(stat);\n\n try {\n if (ignoredInitialSignature) {\n if (fileSignature === ignoredInitialSignature) return;\n ignoredInitialSignature = null;\n }\n if (\n options.maxFileSizeBytes !== undefined &&\n stat.size > options.maxFileSizeBytes\n ) {\n logReadError(\n `oversized:${fileSignature}`,\n `refusing oversized JSON file (${stat.size} bytes, limit ${options.maxFileSizeBytes} bytes)`,\n );\n return;\n }\n if (!force && stat.mtimeMs === lastMtimeMs) return;\n lastMtimeMs = stat.mtimeMs;\n const parsed: unknown = JSON.parse(fs.readFileSync(path, 'utf-8'));\n lastReadErrorSignature = null;\n onUpdate(parsed);\n } catch (error) {\n logReadError(\n `invalid:${fileSignature}:${String(error)}`,\n `could not read valid JSON (${String(error)})`,\n );\n }\n };\n\n const scheduleRead = () => {\n if (stopped) return;\n if (watchDebounceTimer) clearTimeout(watchDebounceTimer);\n watchDebounceTimer = setTimeout(() => {\n watchDebounceTimer = null;\n read(true);\n }, watchDebounceMs);\n };\n\n const attachWatch = () => {\n watchers.push(\n fs.watch(targetDir, (_eventType, filename) => {\n if (filename == null || filename.toString() === targetName) {\n scheduleRead();\n }\n }),\n );\n };\n\n intervals.push(setInterval(() => read(), pollIntervalMs));\n\n try {\n attachWatch();\n // Defer the initial callback until the caller has received the handle, so\n // callbacks that stop their watcher cannot race handle assignment.\n queueMicrotask(() => {\n if (!stopped) read(true);\n });\n } catch {\n // Parent directory does not exist yet. Polling still covers a later file;\n // retry attaching the low-latency directory watcher until it appears.\n const attachInterval = setInterval(() => {\n try {\n fs.accessSync(targetDir);\n clearInterval(attachInterval);\n const idx = intervals.indexOf(attachInterval);\n if (idx >= 0) intervals.splice(idx, 1);\n attachWatch();\n read(true);\n } catch {\n // Still waiting.\n }\n }, attachRetryIntervalMs);\n intervals.push(attachInterval);\n }\n\n return {\n refresh() {\n if (stopped) return;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n read(true);\n },\n stop() {\n stopped = true;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n for (const watcher of watchers) watcher.close();\n for (const interval of intervals) clearInterval(interval);\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { m as LoggingUI } from "./debug-
|
|
1
|
+
import { m as LoggingUI } from "./debug-C9HmIrwx.js";
|
|
2
2
|
//#region src/ui/headless-ui.ts
|
|
3
3
|
/**
|
|
4
4
|
* `LoggingUI` plus it feeds run state into a `WizardStore` so the background
|
|
5
5
|
* wizard-session sync (`TaskStreamPush`) can observe a headless run. We extend
|
|
6
6
|
* `LoggingUI` (not `InkUI`) because its blocking/gate methods would wait on a
|
|
7
7
|
* TUI that never renders; the runner drives phase transitions on the store
|
|
8
|
-
* directly, so only
|
|
9
|
-
*
|
|
8
|
+
* directly, so only UI-originated per-run updates tee through here. Runner
|
|
9
|
+
* machinery loads agent-authored artifacts such as the event plan directly
|
|
10
|
+
* into the store.
|
|
10
11
|
*/
|
|
11
12
|
var HeadlessUI = class extends LoggingUI {
|
|
12
13
|
constructor(store) {
|
|
@@ -21,4 +22,4 @@ var HeadlessUI = class extends LoggingUI {
|
|
|
21
22
|
//#endregion
|
|
22
23
|
export { HeadlessUI };
|
|
23
24
|
|
|
24
|
-
//# sourceMappingURL=headless-ui-
|
|
25
|
+
//# sourceMappingURL=headless-ui-B3QKxbz8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-ui-B3QKxbz8.js","names":[],"sources":["../src/ui/headless-ui.ts"],"sourcesContent":["import { LoggingUI } from './logging-ui';\nimport type { WizardStore } from './tui/store';\n\n/**\n * `LoggingUI` plus it feeds run state into a `WizardStore` so the background\n * wizard-session sync (`TaskStreamPush`) can observe a headless run. We extend\n * `LoggingUI` (not `InkUI`) because its blocking/gate methods would wait on a\n * TUI that never renders; the runner drives phase transitions on the store\n * directly, so only UI-originated per-run updates tee through here. Runner\n * machinery loads agent-authored artifacts such as the event plan directly\n * into the store.\n */\nexport class HeadlessUI extends LoggingUI {\n constructor(private readonly store: WizardStore) {\n super();\n }\n\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void {\n super.syncTodos(todos);\n this.store.syncTodos(todos);\n }\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAa,aAAb,cAAgC,UAAU;CACxC,YAAY,OAAqC;AAC/C,SAAO;AADoB,OAAA,QAAA;;CAI7B,UACE,OACM;AACN,QAAM,UAAU,MAAM;AACtB,OAAK,MAAM,UAAU,MAAM"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as posthogIntegrationConfig } from "./posthog-integration-
|
|
1
|
+
import { r as posthogIntegrationConfig } from "./posthog-integration-Do997QON.js";
|
|
2
2
|
import { l as runWizard } from "./bin.js";
|
|
3
3
|
//#region src/commands/basic-integration/interactive.ts
|
|
4
4
|
/** Default flow: run the posthog-integration program through the TUI. */
|
|
@@ -8,4 +8,4 @@ function runInteractive(argv) {
|
|
|
8
8
|
//#endregion
|
|
9
9
|
export { runInteractive };
|
|
10
10
|
|
|
11
|
-
//# sourceMappingURL=interactive-
|
|
11
|
+
//# sourceMappingURL=interactive-CIJRex02.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive-
|
|
1
|
+
{"version":3,"file":"interactive-CIJRex02.js","names":[],"sources":["../src/commands/basic-integration/interactive.ts"],"sourcesContent":["import type { Arguments } from 'yargs';\nimport { runWizard } from '@lib/runners';\nimport { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index';\n\n/** Default flow: run the posthog-integration program through the TUI. */\nexport function runInteractive(argv: Arguments): void {\n runWizard(posthogIntegrationConfig, argv);\n}\n"],"mappings":";;;;AAKA,SAAgB,eAAe,MAAuB;AACpD,WAAU,0BAA0B,KAAK"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as sanitizeAgentSubprocessEnv, t as buildAgentEnv } from "./agent-interface-
|
|
1
|
+
import { D as DEFAULT_AGENT_MODEL, gt as WIZARD_USER_AGENT, s as logToFile } from "./debug-C9HmIrwx.js";
|
|
2
|
+
import { d as sanitizeAgentSubprocessEnv, t as buildAgentEnv } from "./agent-interface-B8roB2UP.js";
|
|
3
3
|
//#region src/lib/agent/mcp-prompt-streaming.ts
|
|
4
4
|
let _sdkModule = null;
|
|
5
5
|
async function loadSdk() {
|
|
@@ -229,4 +229,4 @@ async function* runMcpPromptViaSdk(args) {
|
|
|
229
229
|
//#endregion
|
|
230
230
|
export { runMcpPromptViaSdk };
|
|
231
231
|
|
|
232
|
-
//# sourceMappingURL=mcp-prompt-streaming-
|
|
232
|
+
//# sourceMappingURL=mcp-prompt-streaming-D6OgW3lC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-prompt-streaming-AtntLsJ8.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 { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@lib/constants';\nimport { logToFile } from '@utils/debug';\nimport { buildAgentEnv } from '@lib/agent/agent-interface';\nimport { sanitizeAgentSubprocessEnv } from '@lib/agent/agent-env-isolation';\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 = DEFAULT_AGENT_MODEL;\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\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 // CLI mode's exec tool takes a `command` string; keep it verbatim so\n // the screen can recover the inner tool name for follow-ups.\n const command = (input as { command?: unknown })?.command;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n command: typeof command === 'string' ? command : undefined,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const sessionId = (message as { session_id?: string }).session_id;\n chunks.push({ kind: 'done', sessionId });\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\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 `Tables:`,\n `- Max 5 body rows. The prompts the user picks already constrain results to 5 or fewer — honor that and do not pad with extra rows.`,\n `- If a tool result returns more than 5 items, show the top 5 and mention the rest count inline (e.g. \"...and 12 more\").`,\n `- Prefer transposing wide-but-short data (items across columns, metrics down rows) when labels are short.`,\n `- A two-column table with many rows is the tall layout to AVOID.`,\n ``,\n `Other limits:`,\n `- Aim for 3-5 lines of prose. Maximum ${messageBudget} lines total.`,\n `- DO NOT announce what you are about to do. Skip preamble like \"I'll query…\", \"Let me check…\", \"Now I'll…\", \"I'm going to…\". Go straight to running tools and then the answer.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated), 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 ``,\n `Naming saved artifacts:`,\n `- Every dashboard, insight, notebook, or annotation you create MUST include \"(wizard MCP tutorial)\" at the end of its title or name field. Examples: \"Weekly signups (wizard MCP tutorial)\", \"Top errors this week (wizard MCP tutorial)\", \"Onboarding analysis (wizard MCP tutorial)\".`,\n `- This applies on both create AND rename calls. If the user asks you to rename a saved artifact, preserve the \"(wizard MCP tutorial)\" suffix unless they explicitly ask you to drop it.`,\n `- Reason: lets the user find / clean up everything this tutorial created from one search in PostHog. Don't skip it — it's the only signal they'll have that an artifact came from the wizard.`,\n ``,\n `Tone & framing:`,\n `- This is a tutorial demoing PostHog (the product the user just installed). You are showing it off, not auditing it. Stay constructive and neutral about PostHog throughout.`,\n `- Don't editorialize about PostHog's reliability, performance, or cost. Describe what the data shows; treat anomalies as the user's data, not a platform issue.`,\n `- If a tool call fails or returns nothing, say \"the query didn't return data — try a different angle\" or similar. Do NOT speculate about outages, gateway issues, MCP problems, or service health.`,\n `- Avoid value-laden phrases like \"worth investigating\", \"concerning\", \"red flag\", \"problematic\", \"suspicious\", \"alarming\" when describing the user's metrics. Stick to what the numbers show; the user draws conclusions.`,\n ].join('\\n');\n}\n\nexport async function* runMcpPromptViaSdk(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n /** When set, the SDK loads the named session's prior turns as\n * context so the follow-up prompt can reference what the agent\n * already showed. */\n resumeSessionId?: string;\n}): AsyncIterable<AgentChunk> {\n const { prompt, credentials, signal, resumeSessionId } = args;\n\n // Route the SDK's LLM calls through the PostHog LLM gateway, authed\n // with the user's OAuth access token. Set BEFORE loading the SDK in\n // case any in-process code reads env at module init (cached base\n // URLs, OAuth setup, etc.) — same reason `initializeAgent` does this\n // before its query() call. Without these the SDK tries to\n // authenticate directly against Anthropic and 401s with \"Invalid\n // authentication credentials\".\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // Route through the PostHog LLM gateway, authed with the user's OAuth token.\n const gatewayUrl = credentials.host.gatewayUrl;\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n process.env.ANTHROPIC_AUTH_TOKEN = credentials.accessToken;\n process.env.CLAUDE_CODE_OAUTH_TOKEN = credentials.accessToken;\n\n logToFile(\n `[runMcpPromptViaSdk] gatewayUrl=${gatewayUrl} tokenPrefix=${\n credentials.accessToken\n ? credentials.accessToken.slice(0, 4) + '***'\n : '(missing)'\n }`,\n );\n\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 = credentials.host.mcpUrl;\n logToFile(\n `[runMcpPromptViaSdk] mcpUrl=${mcpUrl} model=${MODEL} resume=${\n resumeSessionId ?? '(none)'\n }`,\n );\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 // Match agent-interface.ts — the 1M context beta is what keeps\n // resumed follow-up sessions from truncating after a few turns.\n betas: ['context-1m-2025-08-07'],\n // Only load project-level skills/settings. Without this the SDK\n // defaults to ['user', 'project'] and a user's\n // `~/.claude/settings.json` (apiKeyHelper / env block) can\n // override the OAuth routing we set above.\n settingSources: ['project'],\n // When set, the SDK replays the named session's turns into the\n // new query so the follow-up prompt has full conversation\n // context. Omit on the first prompt for a fresh session.\n ...(resumeSessionId ? { resume: resumeSessionId } : {}),\n // Without `canUseTool` the SDK falls back to \"ask the user\" on\n // every MCP tool call — `permissionMode: 'acceptEdits'` only\n // relaxes Edit/Write, not MCP. Our Ink TUI has no surface to\n // answer that prompt, so the agent would stall mid-stream\n // saying things like \"needs your approval to create dashboard\".\n // The tutorial's whole point is demoing the MCP tools against\n // the user's project, so we auto-allow everything that matches\n // the prefix and deny anything else (defense in depth — the\n // `allowedTools` filter above already enforces this).\n canUseTool: (toolName: string, input: unknown) => {\n if (toolName.startsWith('mcp__posthog-wizard__')) {\n return Promise.resolve({\n behavior: 'allow' as const,\n updatedInput: (input ?? {}) as Record<string, unknown>,\n });\n }\n logToFile(`[runMcpPromptViaSdk] denying non-MCP tool: ${toolName}`);\n return Promise.resolve({\n behavior: 'deny' as const,\n message: `${toolName} is not available in the MCP tutorial — only PostHog MCP tools are permitted.`,\n });\n },\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 // CLI mode's single `exec` tool carries the full command reference\n // on its schema — keep it in context, never deferred behind tool\n // search.\n alwaysLoad: true,\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 env: {\n // Drop the ENTIRE ANTHROPIC_*/CLAUDE_CODE_* namespace from the\n // inherited env so no shell/settings value can silently bypass the\n // PostHog gateway and defeat quota tracking / the OAuth flow; the\n // wizard's own gateway routing is injected fresh below. See\n // agent-env-isolation.ts.\n ...sanitizeAgentSubprocessEnv(process.env),\n // Gateway routing — injected explicitly (set on process.env above;\n // the strip removed them from the inherited copy, so re-add here).\n ANTHROPIC_BASE_URL: process.env.ANTHROPIC_BASE_URL,\n ANTHROPIC_AUTH_TOKEN: process.env.ANTHROPIC_AUTH_TOKEN,\n CLAUDE_CODE_OAUTH_TOKEN: process.env.CLAUDE_CODE_OAUTH_TOKEN,\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // SDK 0.3.142+ connects MCP servers in the background by\n // default; without this the agent may try to call tools\n // before posthog-wizard is connected on turn 1.\n MCP_CONNECTION_NONBLOCKING: '0',\n // Same Bedrock-fallback + telemetry-friendly headers as the\n // main runner. No wizard metadata or flags for the tutorial\n // — runs are distinguished downstream via posthog.capture\n // calls (program_id + event names), not SDK headers.\n ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv({}, {}),\n },\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
|
+
{"version":3,"file":"mcp-prompt-streaming-D6OgW3lC.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 { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@lib/constants';\nimport { logToFile } from '@utils/debug';\nimport { buildAgentEnv } from '@lib/agent/agent-interface';\nimport { sanitizeAgentSubprocessEnv } from '@lib/agent/agent-env-isolation';\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 = DEFAULT_AGENT_MODEL;\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\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 // CLI mode's exec tool takes a `command` string; keep it verbatim so\n // the screen can recover the inner tool name for follow-ups.\n const command = (input as { command?: unknown })?.command;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n command: typeof command === 'string' ? command : undefined,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const sessionId = (message as { session_id?: string }).session_id;\n chunks.push({ kind: 'done', sessionId });\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\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 `Tables:`,\n `- Max 5 body rows. The prompts the user picks already constrain results to 5 or fewer — honor that and do not pad with extra rows.`,\n `- If a tool result returns more than 5 items, show the top 5 and mention the rest count inline (e.g. \"...and 12 more\").`,\n `- Prefer transposing wide-but-short data (items across columns, metrics down rows) when labels are short.`,\n `- A two-column table with many rows is the tall layout to AVOID.`,\n ``,\n `Other limits:`,\n `- Aim for 3-5 lines of prose. Maximum ${messageBudget} lines total.`,\n `- DO NOT announce what you are about to do. Skip preamble like \"I'll query…\", \"Let me check…\", \"Now I'll…\", \"I'm going to…\". Go straight to running tools and then the answer.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated), 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 ``,\n `Naming saved artifacts:`,\n `- Every dashboard, insight, notebook, or annotation you create MUST include \"(wizard MCP tutorial)\" at the end of its title or name field. Examples: \"Weekly signups (wizard MCP tutorial)\", \"Top errors this week (wizard MCP tutorial)\", \"Onboarding analysis (wizard MCP tutorial)\".`,\n `- This applies on both create AND rename calls. If the user asks you to rename a saved artifact, preserve the \"(wizard MCP tutorial)\" suffix unless they explicitly ask you to drop it.`,\n `- Reason: lets the user find / clean up everything this tutorial created from one search in PostHog. Don't skip it — it's the only signal they'll have that an artifact came from the wizard.`,\n ``,\n `Tone & framing:`,\n `- This is a tutorial demoing PostHog (the product the user just installed). You are showing it off, not auditing it. Stay constructive and neutral about PostHog throughout.`,\n `- Don't editorialize about PostHog's reliability, performance, or cost. Describe what the data shows; treat anomalies as the user's data, not a platform issue.`,\n `- If a tool call fails or returns nothing, say \"the query didn't return data — try a different angle\" or similar. Do NOT speculate about outages, gateway issues, MCP problems, or service health.`,\n `- Avoid value-laden phrases like \"worth investigating\", \"concerning\", \"red flag\", \"problematic\", \"suspicious\", \"alarming\" when describing the user's metrics. Stick to what the numbers show; the user draws conclusions.`,\n ].join('\\n');\n}\n\nexport async function* runMcpPromptViaSdk(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n /** When set, the SDK loads the named session's prior turns as\n * context so the follow-up prompt can reference what the agent\n * already showed. */\n resumeSessionId?: string;\n}): AsyncIterable<AgentChunk> {\n const { prompt, credentials, signal, resumeSessionId } = args;\n\n // Route the SDK's LLM calls through the PostHog LLM gateway, authed\n // with the user's OAuth access token. Set BEFORE loading the SDK in\n // case any in-process code reads env at module init (cached base\n // URLs, OAuth setup, etc.) — same reason `initializeAgent` does this\n // before its query() call. Without these the SDK tries to\n // authenticate directly against Anthropic and 401s with \"Invalid\n // authentication credentials\".\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // Route through the PostHog LLM gateway, authed with the user's OAuth token.\n const gatewayUrl = credentials.host.gatewayUrl;\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n process.env.ANTHROPIC_AUTH_TOKEN = credentials.accessToken;\n process.env.CLAUDE_CODE_OAUTH_TOKEN = credentials.accessToken;\n\n logToFile(\n `[runMcpPromptViaSdk] gatewayUrl=${gatewayUrl} tokenPrefix=${\n credentials.accessToken\n ? credentials.accessToken.slice(0, 4) + '***'\n : '(missing)'\n }`,\n );\n\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 = credentials.host.mcpUrl;\n logToFile(\n `[runMcpPromptViaSdk] mcpUrl=${mcpUrl} model=${MODEL} resume=${\n resumeSessionId ?? '(none)'\n }`,\n );\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 // Match agent-interface.ts — the 1M context beta is what keeps\n // resumed follow-up sessions from truncating after a few turns.\n betas: ['context-1m-2025-08-07'],\n // Only load project-level skills/settings. Without this the SDK\n // defaults to ['user', 'project'] and a user's\n // `~/.claude/settings.json` (apiKeyHelper / env block) can\n // override the OAuth routing we set above.\n settingSources: ['project'],\n // When set, the SDK replays the named session's turns into the\n // new query so the follow-up prompt has full conversation\n // context. Omit on the first prompt for a fresh session.\n ...(resumeSessionId ? { resume: resumeSessionId } : {}),\n // Without `canUseTool` the SDK falls back to \"ask the user\" on\n // every MCP tool call — `permissionMode: 'acceptEdits'` only\n // relaxes Edit/Write, not MCP. Our Ink TUI has no surface to\n // answer that prompt, so the agent would stall mid-stream\n // saying things like \"needs your approval to create dashboard\".\n // The tutorial's whole point is demoing the MCP tools against\n // the user's project, so we auto-allow everything that matches\n // the prefix and deny anything else (defense in depth — the\n // `allowedTools` filter above already enforces this).\n canUseTool: (toolName: string, input: unknown) => {\n if (toolName.startsWith('mcp__posthog-wizard__')) {\n return Promise.resolve({\n behavior: 'allow' as const,\n updatedInput: (input ?? {}) as Record<string, unknown>,\n });\n }\n logToFile(`[runMcpPromptViaSdk] denying non-MCP tool: ${toolName}`);\n return Promise.resolve({\n behavior: 'deny' as const,\n message: `${toolName} is not available in the MCP tutorial — only PostHog MCP tools are permitted.`,\n });\n },\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 // CLI mode's single `exec` tool carries the full command reference\n // on its schema — keep it in context, never deferred behind tool\n // search.\n alwaysLoad: true,\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 env: {\n // Drop the ENTIRE ANTHROPIC_*/CLAUDE_CODE_* namespace from the\n // inherited env so no shell/settings value can silently bypass the\n // PostHog gateway and defeat quota tracking / the OAuth flow; the\n // wizard's own gateway routing is injected fresh below. See\n // agent-env-isolation.ts.\n ...sanitizeAgentSubprocessEnv(process.env),\n // Gateway routing — injected explicitly (set on process.env above;\n // the strip removed them from the inherited copy, so re-add here).\n ANTHROPIC_BASE_URL: process.env.ANTHROPIC_BASE_URL,\n ANTHROPIC_AUTH_TOKEN: process.env.ANTHROPIC_AUTH_TOKEN,\n CLAUDE_CODE_OAUTH_TOKEN: process.env.CLAUDE_CODE_OAUTH_TOKEN,\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // SDK 0.3.142+ connects MCP servers in the background by\n // default; without this the agent may try to call tools\n // before posthog-wizard is connected on turn 1.\n MCP_CONNECTION_NONBLOCKING: '0',\n // Same Bedrock-fallback + telemetry-friendly headers as the\n // main runner. No wizard metadata or flags for the tutorial\n // — runs are distinguished downstream via posthog.capture\n // calls (program_id + event names), not SDK headers.\n ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv({}, {}),\n },\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":";;;AAwBA,IAAI,aAAyB;AAG7B,eAAe,UAAwB;AACrC,KAAI,CAAC,WACH,cAAa,MAAM,OAAO;AAE5B,QAAO;;AAGT,MAAM,QAAQ;AAOd,MAAM,YAAY;;;;;;AAOlB,SAAS,UAAU,OAAgB,SAAS,KAAa;AACvD,KAAI,SAAS,KAAM,QAAO;CAC1B,IAAI;AACJ,KAAI,OAAO,UAAU,SAAU,QAAO;KAEpC,KAAI;AACF,SAAO,KAAK,UAAU,MAAM;SACtB;AACN,SAAO,OAAO,MAAM;;AAGxB,QAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC,MAAM;AACvC,KAAI,KAAK,SAAS,OAAQ,QAAO,KAAK,MAAM,GAAG,SAAS,EAAE,GAAG;AAC7D,QAAO;;;;;;;AAST,SAAS,gBAAgB,SAA4B;CACnD,MAAM,SAAuB,EAAE;AAE/B,KAAI,SAAS,SAAS,aAAa;EAEjC,MAAM,UAAU,QAAQ,SAAS;AACjC,MAAI,MAAM,QAAQ,QAAQ,CACxB,MAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,CAAC,SAAS,OAAO,UAAU,SAAU;GACzC,MAAM,OAAQ,MAA4B;AAC1C,OAAI,SAAS,QAAQ;IACnB,MAAM,OAAQ,MAA4B,QAAQ;AAClD,QAAI,KAAM,QAAO,KAAK;KAAE,MAAM;KAAQ;KAAM,CAAC;cACpC,SAAS,YAAY;IAC9B,MAAM,OAAQ,MAA4B,QAAQ;IAClD,MAAM,QAAS,MAA8B;IAG7C,MAAM,UAAW,OAAiC;AAClD,WAAO,KAAK;KACV,MAAM;KACN,UAAU;KACV,QAAQ,UAAU,MAAM;KACxB,SAAS,OAAO,YAAY,WAAW,UAAU,KAAA;KAClD,CAAC;;;;AAMV,KAAI,SAAS,SAAS,QAAQ;EAE5B,MAAM,UAAU,QAAQ,SAAS;AACjC,MAAI,MAAM,QAAQ,QAAQ,CACxB,MAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,CAAC,SAAS,OAAO,UAAU,SAAU;AAEzC,OADc,MAA4B,SAC7B,eAAe;IAC1B,MAAM,SAAS,UAAW,MAAgC,QAAQ;AAClE,WAAO,KAAK;KAAE,MAAM;KAAe,UAAU;KAAQ;KAAQ,CAAC;;;;AAMtE,KAAI,SAAS,SAAS,UAAU;EAE9B,MAAM,YAAa,QAAoC;AACvD,SAAO,KAAK;GAAE,MAAM;GAAQ;GAAW,CAAC;;AAG1C,QAAO;;;;;;;;;;;;;AAcT,SAAS,yBAAiC;CACxC,MAAM,OAAO,QAAQ,OAAO,WAAW;CACvC,MAAM,OAAO,QAAQ,OAAO,QAAQ;CAEpC,MAAM,gBAAgB,KAAK,IAAI,GAAG,OAAO,GAAG;AAE5C,QAAO;EACL,0DAA0D,KAAK,oBAAoB,KAAK;EACxF;EACA,sFAAsF,KAAK;EAC3F;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,yCAAyC,cAAc;EACvD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK;;AAGd,gBAAuB,mBAAmB,MAQZ;CAC5B,MAAM,EAAE,QAAQ,aAAa,QAAQ,oBAAoB;AASzD,SAAQ,IAAI,yCAAyC;CAGrD,MAAM,aAAa,YAAY,KAAK;AACpC,SAAQ,IAAI,qBAAqB;AACjC,SAAQ,IAAI,uBAAuB,YAAY;AAC/C,SAAQ,IAAI,0BAA0B,YAAY;AAElD,WACE,mCAAmC,WAAW,eAC5C,YAAY,cACR,YAAY,YAAY,MAAM,GAAG,EAAE,GAAG,QACtC,cAEP;CAGD,MAAM,EAAE,UAAU,MAAM,SAAS;CAGjC,MAAM,kBAAkB,IAAI,iBAAiB;AAC7C,KAAI,OAAO,QAAS,iBAAgB,OAAO;KAEzC,QAAO,iBAAiB,eAAe,gBAAgB,OAAO,EAAE,EAC9D,MAAM,MACP,CAAC;CAEJ,MAAM,SAAS,YAAY,KAAK;AAChC,WACE,+BAA+B,OAAO,SAAS,MAAM,UACnD,mBAAmB,WAEtB;CAMD,MAAM,qBAAqB,mBAAmB;AAC5C,QAAM;GACJ,MAAM;GACN,YAAY;GACZ,SAAS;IAAE,MAAM;IAAiB,SAAS;IAAQ;GACnD,oBAAoB;GACrB;AAID,QAAM,IAAI,SAAe,YAAY;AACnC,OAAI,gBAAgB,OAAO,SAAS;AAClC,aAAS;AACT;;AAEF,mBAAgB,OAAO,iBAAiB,eAAe,SAAS,EAAE,EAChE,MAAM,MACP,CAAC;IACF;;AAGJ,KAAI;EAEF,MAAM,WAAW,MAAM;GACrB,QAAQ,oBAAoB;GAC5B,SAAS;IACP;IACA,OAAO;IACP,KAAK,QAAQ,KAAK;IAClB,gBAAgB;IAChB,UAAU;IAGV,OAAO,CAAC,wBAAwB;IAKhC,gBAAgB,CAAC,UAAU;IAI3B,GAAI,kBAAkB,EAAE,QAAQ,iBAAiB,GAAG,EAAE;IAUtD,aAAa,UAAkB,UAAmB;AAChD,SAAI,SAAS,WAAW,wBAAwB,CAC9C,QAAO,QAAQ,QAAQ;MACrB,UAAU;MACV,cAAe,SAAS,EAAE;MAC3B,CAAC;AAEJ,eAAU,8CAA8C,WAAW;AACnE,YAAO,QAAQ,QAAQ;MACrB,UAAU;MACV,SAAS,GAAG,SAAS;MACtB,CAAC;;IAEJ,cAAc;KACZ,MAAM;KACN,QAAQ;KACR,QAAQ,wBAAwB;KACjC;IACD,YAAY,EACV,kBAAkB;KAChB,MAAM;KACN,KAAK;KACL,SAAS;MACP,eAAe,UAAU,YAAY;MACrC,cAAc;MACf;KAID,YAAY;KACb,EACF;IAID,cAAc,CAAC,yBAAyB;IACxC,KAAK;KAMH,GAAG,2BAA2B,QAAQ,IAAI;KAG1C,oBAAoB,QAAQ,IAAI;KAChC,sBAAsB,QAAQ,IAAI;KAClC,yBAAyB,QAAQ,IAAI;KACrC,wCAAwC;KAIxC,4BAA4B;KAK5B,0BAA0B,cAAc,EAAE,EAAE,EAAE,CAAC;KAChD;IACF;GACF,CAAC;AAEF,aAAW,MAAM,WAAW,UAAoC;AAC9D,OAAI,OAAO,QAAS;AACpB,QAAK,MAAM,SAAS,gBAAgB,QAAQ,EAAE;AAC5C,UAAM;AACN,QAAI,MAAM,SAAS,OAAQ;;;UAGxB,KAAK;EACZ,MAAM,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC7D,YAAU,+BAA+B,OAAO;AAChD,QAAM;GAAE,MAAM;GAAS;GAAM;WACrB;AAGR,kBAAgB,OAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as logToFile } from "./debug-
|
|
1
|
+
import { s as logToFile } from "./debug-C9HmIrwx.js";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { createJiti } from "jiti";
|
|
@@ -7,7 +7,7 @@ import { createJiti } from "jiti";
|
|
|
7
7
|
* Wire the real PostHog MCP into the pi backend (#10). pi has no built-in MCP,
|
|
8
8
|
* but `pi-mcp-adapter` is pi's own MCP extension — we load it the way pi itself
|
|
9
9
|
* does, with `jiti` (pi's runtime `.ts` loader, already a transitive dep). The
|
|
10
|
-
* adapter connects to the same hosted MCP the anthropic path uses (`boot.mcpUrl`).
|
|
10
|
+
* adapter connects to the same hosted MCP the anthropic path uses (`boot.credentials.host.mcpUrl`).
|
|
11
11
|
*
|
|
12
12
|
* In CLI mode the server exposes a single `exec` tool that carries the whole
|
|
13
13
|
* command protocol on its schema. We pre-warm the adapter's metadata cache by
|
|
@@ -101,4 +101,4 @@ async function setupPostHogMcp(opts) {
|
|
|
101
101
|
//#endregion
|
|
102
102
|
export { setupPostHogMcp };
|
|
103
103
|
|
|
104
|
-
//# sourceMappingURL=mcp-
|
|
104
|
+
//# sourceMappingURL=mcp-qTjKHqXN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-qTjKHqXN.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/mcp.ts"],"sourcesContent":["/**\n * Wire the real PostHog MCP into the pi backend (#10). pi has no built-in MCP,\n * but `pi-mcp-adapter` is pi's own MCP extension — we load it the way pi itself\n * does, with `jiti` (pi's runtime `.ts` loader, already a transitive dep). The\n * adapter connects to the same hosted MCP the anthropic path uses (`boot.credentials.host.mcpUrl`).\n *\n * In CLI mode the server exposes a single `exec` tool that carries the whole\n * command protocol on its schema. We pre-warm the adapter's metadata cache by\n * connecting once and register the roster as DIRECT tools — so the agent calls\n * `exec` in one step instead of through the fragile `mcp` proxy search.\n *\n * The bearer token is passed by env-var NAME (`bearerTokenEnv`), so it lives only\n * in the wizard process for the adapter's in-process client. It is never written\n * to disk and never reaches pi's (env-scrubbed) tool subprocesses.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { createJiti } from 'jiti';\nimport { logToFile } from '@utils/debug';\n\nconst MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN';\n\nexport interface PostHogMcpSetup {\n /** pi ExtensionFactory to add to the resource loader's `extensionFactories`. */\n extensionFactory: (pi: unknown) => void;\n /** Restore prior config + drop the token env var. Call after the run. */\n cleanup: () => void;\n /**\n * The MCP server's `instructions` payload, captured at warm-connect. The\n * adapter drops it, so the caller rides it into the system prompt — it carries\n * the \"prioritize skills over tools\" steer, the active project/environment, and\n * the tool domains the agent searches to discover tools. Undefined if the\n * warm-connect failed.\n */\n instructions?: string;\n}\n\nexport async function setupPostHogMcp(opts: {\n agentDir: string;\n mcpUrl: string;\n accessToken: string;\n userAgent: string;\n}): Promise<PostHogMcpSetup> {\n const { agentDir, mcpUrl, accessToken, userAgent } = opts;\n\n process.env[MCP_TOKEN_ENV] = accessToken;\n\n // The adapter discovers servers from <agentDir>/mcp.json. Merge our server in\n // and restore the prior file on cleanup so a user's own config is never lost.\n const configPath = path.join(agentDir, 'mcp.json');\n const previous = fs.existsSync(configPath)\n ? fs.readFileSync(configPath, 'utf8')\n : null;\n\n let config: { mcpServers: Record<string, Record<string, unknown>> } = {\n mcpServers: {},\n };\n if (previous) {\n try {\n config = JSON.parse(previous);\n config.mcpServers ??= {};\n } catch {\n config = { mcpServers: {} };\n }\n }\n const server: Record<string, unknown> = {\n url: mcpUrl,\n auth: 'bearer',\n bearerTokenEnv: MCP_TOKEN_ENV,\n headers: { 'User-Agent': userAgent },\n lifecycle: 'lazy',\n // Register only `exec`: `directTools: true` also mints a `posthog_get_<name>` tool per MCP resource, whose sentence-length names overflow Anthropic's 128-char tool-name limit and 400 the whole request.\n directTools: ['exec'],\n exposeResources: false,\n };\n config.mcpServers.posthog = server;\n // Disable the proxy `mcp` tool (its search indirection pollutes context); the adapter re-enables it only if no direct tools resolve.\n const settings = (config as { settings?: Record<string, unknown> }).settings;\n (config as { settings?: Record<string, unknown> }).settings = {\n ...settings,\n disableProxyTool: true,\n toolPrefix: 'posthog',\n };\n\n const writeConfig = (): void => {\n fs.mkdirSync(agentDir, { recursive: true });\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');\n };\n writeConfig();\n\n const jiti = createJiti(import.meta.url);\n\n // The server `instructions` (adapter drops them), captured below for the system prompt.\n let instructions: string | undefined;\n\n // Pre-warm: connect once to seed the adapter's metadata cache; best-effort (proxy fallback on failure).\n try {\n const sm = await jiti.import('pi-mcp-adapter/server-manager.ts');\n const mc = await jiti.import('pi-mcp-adapter/metadata-cache.ts');\n const manager = new sm.McpServerManager();\n try {\n const conn = await manager.connect('posthog', server);\n if (conn.status === 'connected' && conn.tools.length > 0) {\n mc.saveMetadataCache({\n version: 1,\n servers: {\n posthog: {\n configHash: mc.computeServerHash(server),\n tools: mc.serializeTools(conn.tools),\n resources: mc.serializeResources(conn.resources ?? []),\n cachedAt: Date.now(),\n },\n },\n });\n // The adapter drops the server `instructions` (skill steer + env + tool domains), so read them off the SDK client.\n const client = (conn as { client?: { getInstructions?: () => string } })\n .client;\n instructions = client?.getInstructions?.() || undefined;\n // Log the exec description length so adapter truncation of the protocol is detectable.\n const execTool = conn.tools.find((t: { name: string }) =>\n /(^|_)exec$/.test(t.name),\n ) as { description?: string } | undefined;\n const execDescLen = execTool?.description?.length ?? 0;\n logToFile(\n `[pi-mcp] warmed: ${conn.tools.length} tools, all direct; ` +\n `exec description ${execDescLen} chars; ` +\n `instructions ${instructions?.length ?? 0} chars`,\n );\n }\n } finally {\n await manager.closeAll().catch(() => undefined);\n }\n } catch (err) {\n logToFile(`[pi-mcp] cache warm skipped (proxy fallback): ${String(err)}`);\n }\n\n const mod = await jiti.import('pi-mcp-adapter/index.ts');\n const extensionFactory = ((mod as { default?: unknown }).default ?? mod) as (\n pi: unknown,\n ) => void;\n logToFile(`[pi-mcp] adapter loaded; posthog MCP at ${mcpUrl}`);\n\n const cleanup = (): void => {\n try {\n if (previous != null) fs.writeFileSync(configPath, previous, 'utf8');\n else fs.rmSync(configPath, { force: true });\n } catch (err) {\n logToFile(`[pi-mcp] config cleanup skipped: ${String(err)}`);\n }\n delete process.env[MCP_TOKEN_ENV];\n };\n\n return { extensionFactory, cleanup, instructions };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,gBAAgB;AAiBtB,eAAsB,gBAAgB,MAKT;CAC3B,MAAM,EAAE,UAAU,QAAQ,aAAa,cAAc;AAErD,SAAQ,IAAI,iBAAiB;CAI7B,MAAM,aAAa,KAAK,KAAK,UAAU,WAAW;CAClD,MAAM,WAAW,GAAG,WAAW,WAAW,GACtC,GAAG,aAAa,YAAY,OAAO,GACnC;CAEJ,IAAI,SAAkE,EACpE,YAAY,EAAE,EACf;AACD,KAAI,SACF,KAAI;AACF,WAAS,KAAK,MAAM,SAAS;AAC7B,SAAO,eAAe,EAAE;SAClB;AACN,WAAS,EAAE,YAAY,EAAE,EAAE;;CAG/B,MAAM,SAAkC;EACtC,KAAK;EACL,MAAM;EACN,gBAAgB;EAChB,SAAS,EAAE,cAAc,WAAW;EACpC,WAAW;EAEX,aAAa,CAAC,OAAO;EACrB,iBAAiB;EAClB;AACD,QAAO,WAAW,UAAU;CAE5B,MAAM,WAAY,OAAkD;AACnE,QAAkD,WAAW;EAC5D,GAAG;EACH,kBAAkB;EAClB,YAAY;EACb;CAED,MAAM,oBAA0B;AAC9B,KAAG,UAAU,UAAU,EAAE,WAAW,MAAM,CAAC;AAC3C,KAAG,cAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,EAAE,EAAE,OAAO;;AAEvE,cAAa;CAEb,MAAM,OAAO,WAAW,OAAO,KAAK,IAAI;CAGxC,IAAI;AAGJ,KAAI;EACF,MAAM,KAAK,MAAM,KAAK,OAAO,mCAAmC;EAChE,MAAM,KAAK,MAAM,KAAK,OAAO,mCAAmC;EAChE,MAAM,UAAU,IAAI,GAAG,kBAAkB;AACzC,MAAI;GACF,MAAM,OAAO,MAAM,QAAQ,QAAQ,WAAW,OAAO;AACrD,OAAI,KAAK,WAAW,eAAe,KAAK,MAAM,SAAS,GAAG;AACxD,OAAG,kBAAkB;KACnB,SAAS;KACT,SAAS,EACP,SAAS;MACP,YAAY,GAAG,kBAAkB,OAAO;MACxC,OAAO,GAAG,eAAe,KAAK,MAAM;MACpC,WAAW,GAAG,mBAAmB,KAAK,aAAa,EAAE,CAAC;MACtD,UAAU,KAAK,KAAK;MACrB,EACF;KACF,CAAC;AAIF,mBAFgB,KACb,QACoB,mBAAmB,IAAI,KAAA;IAK9C,MAAM,cAHW,KAAK,MAAM,MAAM,MAChC,aAAa,KAAK,EAAE,KAAK,CAC1B,EAC6B,aAAa,UAAU;AACrD,cACE,oBAAoB,KAAK,MAAM,OAAO,uCAChB,YAAY,uBAChB,cAAc,UAAU,EAAE,QAC7C;;YAEK;AACR,SAAM,QAAQ,UAAU,CAAC,YAAY,KAAA,EAAU;;UAE1C,KAAK;AACZ,YAAU,iDAAiD,OAAO,IAAI,GAAG;;CAG3E,MAAM,MAAM,MAAM,KAAK,OAAO,0BAA0B;CACxD,MAAM,mBAAqB,IAA8B,WAAW;AAGpE,WAAU,2CAA2C,SAAS;CAE9D,MAAM,gBAAsB;AAC1B,MAAI;AACF,OAAI,YAAY,KAAM,IAAG,cAAc,YAAY,UAAU,OAAO;OAC/D,IAAG,OAAO,YAAY,EAAE,OAAO,MAAM,CAAC;WACpC,KAAK;AACZ,aAAU,oCAAoC,OAAO,IAAI,GAAG;;AAE9D,SAAO,QAAQ,IAAI;;AAGrB,QAAO;EAAE;EAAkB;EAAS;EAAc"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as getUI } from "./debug-
|
|
1
|
+
import { f as getUI } from "./debug-C9HmIrwx.js";
|
|
2
2
|
//#region src/commands/basic-integration/non-interactive.ts
|
|
3
3
|
/** Print the "needs a TTY" error and exit. Used when no `--ci` flag and no TTY. */
|
|
4
4
|
function failNonInteractive() {
|
|
@@ -9,4 +9,4 @@ function failNonInteractive() {
|
|
|
9
9
|
//#endregion
|
|
10
10
|
export { failNonInteractive };
|
|
11
11
|
|
|
12
|
-
//# sourceMappingURL=non-interactive-
|
|
12
|
+
//# sourceMappingURL=non-interactive-8Eypq_h-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"non-interactive-
|
|
1
|
+
{"version":3,"file":"non-interactive-8Eypq_h-.js","names":[],"sources":["../src/commands/basic-integration/non-interactive.ts"],"sourcesContent":["import { getUI } from '@ui';\n\n/** Print the \"needs a TTY\" error and exit. Used when no `--ci` flag and no TTY. */\nexport function failNonInteractive(): void {\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'This installer requires an interactive terminal (TTY) to run.\\n' +\n 'It appears you are running in a non-interactive environment.\\n' +\n 'Please run the wizard in an interactive terminal.\\n\\n' +\n 'For CI/CD environments, use --ci mode:\\n' +\n ' npx @posthog/wizard --ci --region us --api-key phx_xxx',\n );\n process.exit(1);\n}\n"],"mappings":";;;AAGA,SAAgB,qBAA2B;AACzC,QAAO,CAAC,MAAM,iBAAiB;AAC/B,QAAO,CAAC,IAAI,MACV,qRAKD;AACD,SAAQ,KAAK,EAAE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { n as analytics } from "./analytics-k76OWsl0.js";
|
|
2
|
+
import { n as applyEnqueue, r as applyReadHandoffs, t as applyComplete } from "./queue-tools-CTUgbOU8.js";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
//#region src/lib/agent/runner/harness/pi/orchestrator-tools.ts
|
|
6
|
+
/**
|
|
7
|
+
* Orchestrator queue tools as pi custom tools. The queue lives in-process, and
|
|
8
|
+
* `applyEnqueue` / `applyComplete` / `applyReadHandoffs` are plain exported
|
|
9
|
+
* functions — so pi needs no MCP transport, just `defineTool` wrappers around
|
|
10
|
+
* the same guards and apply logic the anthropic path mounts through the
|
|
11
|
+
* wizard-tools MCP server. Tool names match the MCP short names so the shared
|
|
12
|
+
* agent prompts are unchanged.
|
|
13
|
+
*
|
|
14
|
+
* Lazily imported (typebox is ESM and must stay out of the static module graph
|
|
15
|
+
* so CommonJS unit tests can load the backend seam without parsing it).
|
|
16
|
+
*/
|
|
17
|
+
function text(s) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: s
|
|
22
|
+
}],
|
|
23
|
+
details: {}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const HANDOFF_PARAMS = Type.Object({
|
|
27
|
+
goals: Type.String({ description: "What this task was asked to achieve." }),
|
|
28
|
+
did: Type.String({ description: "What you actually did." }),
|
|
29
|
+
forNextAgent: Type.String({ description: "What the next agent should know." }),
|
|
30
|
+
filesTouched: Type.Optional(Type.Array(Type.String())),
|
|
31
|
+
conflict: Type.Optional(Type.String({ description: "A one-line summary of any conflict you could not cleanly resolve (e.g. a dependency or build conflict). Put full detail in your work; this line is surfaced to the user." }))
|
|
32
|
+
});
|
|
33
|
+
/** The three queue tools bound to one agent's orchestrator context. */
|
|
34
|
+
function createPiOrchestratorTools(ctx) {
|
|
35
|
+
return [
|
|
36
|
+
defineTool({
|
|
37
|
+
name: "enqueue_task",
|
|
38
|
+
label: "Enqueue task",
|
|
39
|
+
description: "Add a task to the orchestrator queue. Use it to seed work and to enqueue follow-up work you discover. Keep tasks small and discrete.",
|
|
40
|
+
promptSnippet: "enqueue_task(type, label, dependsOn, reason) — add a task to the queue; returns its id",
|
|
41
|
+
parameters: Type.Object({
|
|
42
|
+
type: Type.String({ description: `The task type. One of: ${ctx.validTypes.join(", ")}.` }),
|
|
43
|
+
label: Type.Optional(Type.String({ description: "A short label for the UI — the action in a few words (e.g. \"Add the PostHog SDK\", \"Initialize PostHog\"). Leave out file names, class names, and other specifics." })),
|
|
44
|
+
inputs: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
45
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Task ids that must be done before this task runs." })),
|
|
46
|
+
model: Type.Optional(Type.String()),
|
|
47
|
+
reason: Type.String({ description: "One line on why this task is needed." })
|
|
48
|
+
}),
|
|
49
|
+
execute(_id, args) {
|
|
50
|
+
const res = applyEnqueue(ctx, args);
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
analytics.wizardCapture("orchestrator guard tripped", {
|
|
53
|
+
guard: res.guard,
|
|
54
|
+
type: args.type
|
|
55
|
+
});
|
|
56
|
+
return Promise.resolve(text(`Error: ${res.message}`));
|
|
57
|
+
}
|
|
58
|
+
return Promise.resolve(text(JSON.stringify({ id: res.task.id })));
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
defineTool({
|
|
62
|
+
name: "complete_task",
|
|
63
|
+
label: "Complete task",
|
|
64
|
+
description: "Report the outcome of your task. Always call this exactly once when you finish, with a structured handoff for the next agent. Use status 'skipped' when the task does not apply to this project and you cannot do it (say why in the handoff) — not 'done'.",
|
|
65
|
+
promptSnippet: "complete_task(status, handoff) — report your outcome exactly once when done",
|
|
66
|
+
parameters: Type.Object({
|
|
67
|
+
status: Type.Union([
|
|
68
|
+
Type.Literal("done"),
|
|
69
|
+
Type.Literal("failed"),
|
|
70
|
+
Type.Literal("skipped")
|
|
71
|
+
]),
|
|
72
|
+
handoff: HANDOFF_PARAMS
|
|
73
|
+
}),
|
|
74
|
+
execute(_id, args) {
|
|
75
|
+
const res = applyComplete(ctx, args);
|
|
76
|
+
if (!res.ok) return Promise.resolve(text(`Error: ${res.message}`));
|
|
77
|
+
return Promise.resolve(text("ok"));
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
defineTool({
|
|
81
|
+
name: "read_handoffs",
|
|
82
|
+
label: "Read handoffs",
|
|
83
|
+
description: "Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.",
|
|
84
|
+
promptSnippet: "read_handoffs() — read what earlier tasks handed off (defaults to your dependencies)",
|
|
85
|
+
parameters: Type.Object({
|
|
86
|
+
type: Type.Optional(Type.String()),
|
|
87
|
+
taskId: Type.Optional(Type.String())
|
|
88
|
+
}),
|
|
89
|
+
execute(_id, args) {
|
|
90
|
+
const handoffs = applyReadHandoffs(ctx, args);
|
|
91
|
+
return Promise.resolve(text(JSON.stringify(handoffs, null, 2)));
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { createPiOrchestratorTools };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=orchestrator-tools-DVXOV-kz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-tools-DVXOV-kz.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/orchestrator-tools.ts"],"sourcesContent":["/**\n * Orchestrator queue tools as pi custom tools. The queue lives in-process, and\n * `applyEnqueue` / `applyComplete` / `applyReadHandoffs` are plain exported\n * functions — so pi needs no MCP transport, just `defineTool` wrappers around\n * the same guards and apply logic the anthropic path mounts through the\n * wizard-tools MCP server. Tool names match the MCP short names so the shared\n * agent prompts are unchanged.\n *\n * Lazily imported (typebox is ESM and must stay out of the static module graph\n * so CommonJS unit tests can load the backend seam without parsing it).\n */\n\nimport { Type } from 'typebox';\nimport { defineTool } from '@earendil-works/pi-coding-agent';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { analytics } from '@utils/analytics';\nimport {\n applyComplete,\n applyEnqueue,\n applyReadHandoffs,\n type EnqueueArgs,\n type OrchestratorToolsContext,\n} from '../../sequence/orchestrator/queue-tools';\nimport type { TaskHandoff } from '../../sequence/orchestrator/queue';\n\nfunction text(s: string): {\n content: [{ type: 'text'; text: string }];\n details: unknown;\n} {\n return { content: [{ type: 'text', text: s }], details: {} };\n}\n\nconst HANDOFF_PARAMS = Type.Object({\n goals: Type.String({ description: 'What this task was asked to achieve.' }),\n did: Type.String({ description: 'What you actually did.' }),\n forNextAgent: Type.String({\n description: 'What the next agent should know.',\n }),\n filesTouched: Type.Optional(Type.Array(Type.String())),\n conflict: Type.Optional(\n Type.String({\n description:\n 'A one-line summary of any conflict you could not cleanly resolve (e.g. a dependency or build conflict). Put full detail in your work; this line is surfaced to the user.',\n }),\n ),\n});\n\n/** The three queue tools bound to one agent's orchestrator context. */\nexport function createPiOrchestratorTools(\n ctx: OrchestratorToolsContext,\n): ToolDefinition[] {\n const enqueueTask = defineTool({\n name: 'enqueue_task',\n label: 'Enqueue task',\n description:\n 'Add a task to the orchestrator queue. Use it to seed work and to enqueue follow-up work you discover. Keep tasks small and discrete.',\n promptSnippet:\n 'enqueue_task(type, label, dependsOn, reason) — add a task to the queue; returns its id',\n parameters: Type.Object({\n type: Type.String({\n description: `The task type. One of: ${ctx.validTypes.join(', ')}.`,\n }),\n label: Type.Optional(\n Type.String({\n description:\n 'A short label for the UI — the action in a few words (e.g. \"Add the PostHog SDK\", \"Initialize PostHog\"). Leave out file names, class names, and other specifics.',\n }),\n ),\n inputs: Type.Optional(Type.Record(Type.String(), Type.Unknown())),\n dependsOn: Type.Optional(\n Type.Array(Type.String(), {\n description: 'Task ids that must be done before this task runs.',\n }),\n ),\n model: Type.Optional(Type.String()),\n reason: Type.String({\n description: 'One line on why this task is needed.',\n }),\n }),\n execute(_id, args) {\n const res = applyEnqueue(ctx, args as EnqueueArgs);\n if (!res.ok) {\n analytics.wizardCapture('orchestrator guard tripped', {\n guard: res.guard,\n type: (args as EnqueueArgs).type,\n });\n return Promise.resolve(text(`Error: ${res.message}`));\n }\n return Promise.resolve(text(JSON.stringify({ id: res.task.id })));\n },\n });\n\n const completeTask = defineTool({\n name: 'complete_task',\n label: 'Complete task',\n description:\n \"Report the outcome of your task. Always call this exactly once when you finish, with a structured handoff for the next agent. Use status 'skipped' when the task does not apply to this project and you cannot do it (say why in the handoff) — not 'done'.\",\n promptSnippet:\n 'complete_task(status, handoff) — report your outcome exactly once when done',\n parameters: Type.Object({\n status: Type.Union([\n Type.Literal('done'),\n Type.Literal('failed'),\n Type.Literal('skipped'),\n ]),\n handoff: HANDOFF_PARAMS,\n }),\n execute(_id, args) {\n const res = applyComplete(\n ctx,\n args as {\n status: 'done' | 'failed' | 'skipped';\n handoff: TaskHandoff;\n },\n );\n if (!res.ok) return Promise.resolve(text(`Error: ${res.message}`));\n return Promise.resolve(text('ok'));\n },\n });\n\n const readHandoffs = defineTool({\n name: 'read_handoffs',\n label: 'Read handoffs',\n description:\n 'Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.',\n promptSnippet:\n 'read_handoffs() — read what earlier tasks handed off (defaults to your dependencies)',\n parameters: Type.Object({\n type: Type.Optional(Type.String()),\n taskId: Type.Optional(Type.String()),\n }),\n execute(_id, args) {\n const handoffs = applyReadHandoffs(\n ctx,\n args as { type?: string; taskId?: string },\n );\n return Promise.resolve(text(JSON.stringify(handoffs, null, 2)));\n },\n });\n\n return [enqueueTask, completeTask, readHandoffs];\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,SAAS,KAAK,GAGZ;AACA,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAG,CAAC;EAAE,SAAS,EAAE;EAAE;;AAG9D,MAAM,iBAAiB,KAAK,OAAO;CACjC,OAAO,KAAK,OAAO,EAAE,aAAa,wCAAwC,CAAC;CAC3E,KAAK,KAAK,OAAO,EAAE,aAAa,0BAA0B,CAAC;CAC3D,cAAc,KAAK,OAAO,EACxB,aAAa,oCACd,CAAC;CACF,cAAc,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ,CAAC,CAAC;CACtD,UAAU,KAAK,SACb,KAAK,OAAO,EACV,aACE,4KACH,CAAC,CACH;CACF,CAAC;;AAGF,SAAgB,0BACd,KACkB;AA0FlB,QAAO;EAzFa,WAAW;GAC7B,MAAM;GACN,OAAO;GACP,aACE;GACF,eACE;GACF,YAAY,KAAK,OAAO;IACtB,MAAM,KAAK,OAAO,EAChB,aAAa,0BAA0B,IAAI,WAAW,KAAK,KAAK,CAAC,IAClE,CAAC;IACF,OAAO,KAAK,SACV,KAAK,OAAO,EACV,aACE,wKACH,CAAC,CACH;IACD,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,CAAC,CAAC;IACjE,WAAW,KAAK,SACd,KAAK,MAAM,KAAK,QAAQ,EAAE,EACxB,aAAa,qDACd,CAAC,CACH;IACD,OAAO,KAAK,SAAS,KAAK,QAAQ,CAAC;IACnC,QAAQ,KAAK,OAAO,EAClB,aAAa,wCACd,CAAC;IACH,CAAC;GACF,QAAQ,KAAK,MAAM;IACjB,MAAM,MAAM,aAAa,KAAK,KAAoB;AAClD,QAAI,CAAC,IAAI,IAAI;AACX,eAAU,cAAc,8BAA8B;MACpD,OAAO,IAAI;MACX,MAAO,KAAqB;MAC7B,CAAC;AACF,YAAO,QAAQ,QAAQ,KAAK,UAAU,IAAI,UAAU,CAAC;;AAEvD,WAAO,QAAQ,QAAQ,KAAK,KAAK,UAAU,EAAE,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;;GAEpE,CAAC;EAEmB,WAAW;GAC9B,MAAM;GACN,OAAO;GACP,aACE;GACF,eACE;GACF,YAAY,KAAK,OAAO;IACtB,QAAQ,KAAK,MAAM;KACjB,KAAK,QAAQ,OAAO;KACpB,KAAK,QAAQ,SAAS;KACtB,KAAK,QAAQ,UAAU;KACxB,CAAC;IACF,SAAS;IACV,CAAC;GACF,QAAQ,KAAK,MAAM;IACjB,MAAM,MAAM,cACV,KACA,KAID;AACD,QAAI,CAAC,IAAI,GAAI,QAAO,QAAQ,QAAQ,KAAK,UAAU,IAAI,UAAU,CAAC;AAClE,WAAO,QAAQ,QAAQ,KAAK,KAAK,CAAC;;GAErC,CAAC;EAEmB,WAAW;GAC9B,MAAM;GACN,OAAO;GACP,aACE;GACF,eACE;GACF,YAAY,KAAK,OAAO;IACtB,MAAM,KAAK,SAAS,KAAK,QAAQ,CAAC;IAClC,QAAQ,KAAK,SAAS,KAAK,QAAQ,CAAC;IACrC,CAAC;GACF,QAAQ,KAAK,MAAM;IACjB,MAAM,WAAW,kBACf,KACA,KACD;AACD,WAAO,QAAQ,QAAQ,KAAK,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC,CAAC;;GAElE,CAAC;EAE8C"}
|
|
@@ -38,4 +38,4 @@ function getInstalledPackageVersion(packageName, installDir) {
|
|
|
38
38
|
//#endregion
|
|
39
39
|
export { package_json_exports as i, getInstalledPackageVersion as n, hasDeclaredDependency as r, getDeclaredVersion as t };
|
|
40
40
|
|
|
41
|
-
//# sourceMappingURL=package-json-
|
|
41
|
+
//# sourceMappingURL=package-json-DCuoye-H.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-json-
|
|
1
|
+
{"version":3,"file":"package-json-DCuoye-H.js","names":[],"sources":["../src/utils/package-json.ts"],"sourcesContent":["import { readFileSync } from 'fs';\nimport path from 'path';\n\nexport type PackageJson = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string | undefined>;\n version?: string;\n overrides?: Record<string, string>;\n resolutions?: Record<string, string>;\n pnpm?: {\n overrides?: Record<string, string>;\n };\n};\n\ntype InstalledPackage = {\n name: string;\n version: string;\n};\n\n/**\n * Returns the raw version spec for `packageName` as written in\n * `package.json` (range, pinned version, workspace ref, URL, etc.).\n * `dependencies` wins over `devDependencies`. An empty-string value in\n * either slot falls through, matching the previous behaviour.\n */\nexport function getDeclaredVersion(\n packageName: string,\n packageJson: PackageJson,\n): string | undefined {\n const fromDeps = packageJson?.dependencies?.[packageName];\n if (fromDeps) return fromDeps;\n const fromDevDeps = packageJson?.devDependencies?.[packageName];\n if (fromDevDeps) return fromDevDeps;\n return undefined;\n}\n\nexport function hasDeclaredDependency(\n packageName: string,\n packageJson: PackageJson,\n): boolean {\n return getDeclaredVersion(packageName, packageJson) !== undefined;\n}\n\nexport function findDeclaredPackage(\n packageNamesList: string[],\n packageJson: PackageJson,\n): InstalledPackage | undefined {\n for (const name of packageNamesList) {\n const version = getDeclaredVersion(name, packageJson);\n if (version) {\n return { name, version };\n }\n }\n return undefined;\n}\n\n/**\n * Returns the resolved version from `node_modules/<pkg>/package.json`,\n * not the range declared in the project's `package.json`. Use this when\n * you need to know what npm actually installed.\n */\nexport function getInstalledPackageVersion(\n packageName: string,\n installDir: string,\n): string | undefined {\n try {\n const manifestPath = path.join(\n installDir,\n 'node_modules',\n packageName,\n 'package.json',\n );\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as {\n version?: string;\n };\n return manifest.version;\n } catch {\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,SAAgB,mBACd,aACA,aACoB;CACpB,MAAM,WAAW,aAAa,eAAe;AAC7C,KAAI,SAAU,QAAO;CACrB,MAAM,cAAc,aAAa,kBAAkB;AACnD,KAAI,YAAa,QAAO;;AAI1B,SAAgB,sBACd,aACA,aACS;AACT,QAAO,mBAAmB,aAAa,YAAY,KAAK,KAAA;;;;;;;AAqB1D,SAAgB,2BACd,aACA,YACoB;AACpB,KAAI;EACF,MAAM,eAAe,KAAK,KACxB,YACA,gBACA,aACA,eACD;AAID,SAHiB,KAAK,MAAM,aAAa,cAAc,QAAQ,CAAC,CAGhD;SACV;AACN"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as detectAllPackageManagers } from "./setup-utils-
|
|
1
|
+
import { c as detectAllPackageManagers } from "./setup-utils-Cb5uACEO.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-CAD9Uklp.js.map
|