@posthog/wizard 2.74.1 → 2.76.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 +31 -17
- package/dist/README.md +10 -0
- package/dist/{add-mcp-server-to-clients-CBtInAoH.js → add-mcp-server-to-clients-Exddicp2.js} +5 -5
- package/dist/{add-mcp-server-to-clients-CBtInAoH.js.map → add-mcp-server-to-clients-Exddicp2.js.map} +1 -1
- package/dist/{agent-interface-lCIi_alS.js → agent-interface-CZWRgZMc.js} +204 -376
- package/dist/agent-interface-CZWRgZMc.js.map +1 -0
- package/dist/{agent-prompt-loader-CSxm81TM.js → agent-prompt-loader-BobuLDIg.js} +5 -5
- package/dist/{agent-prompt-loader-CSxm81TM.js.map → agent-prompt-loader-BobuLDIg.js.map} +1 -1
- package/dist/{agent-runner-DVrkOFDA.js → agent-runner-C_R1X_UT.js} +158 -45
- package/dist/agent-runner-C_R1X_UT.js.map +1 -0
- package/dist/{analytics-CeVMOExk.js → analytics-C_RyE8fz.js} +7 -4
- package/dist/analytics-C_RyE8fz.js.map +1 -0
- package/dist/analytics-DXvdQqyp.js +2 -0
- package/dist/{api-2nAofyKY.js → api-k5aGQpIZ.js} +3 -3
- package/dist/{api-2nAofyKY.js.map → api-k5aGQpIZ.js.map} +1 -1
- package/dist/bin.js +164 -4087
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-DmcmFPRq.js → bounded-fs-BHLy83N9.js} +3 -3
- package/dist/{bounded-fs-DmcmFPRq.js.map → bounded-fs-BHLy83N9.js.map} +1 -1
- package/dist/{ci-install-lwYLQ4Yw.js → ci-install-CXt4c41q.js} +4 -4
- package/dist/{ci-install-lwYLQ4Yw.js.map → ci-install-CXt4c41q.js.map} +1 -1
- package/dist/{debug-BvheXnxB.js → debug-BxMMpepn.js} +1 -1
- package/dist/{debug-GxjVplPx.js → debug-C5Zz8hmm.js} +6 -4
- package/dist/debug-C5Zz8hmm.js.map +1 -0
- package/dist/{defaults-DI642M3n.js → defaults-DulzMJpN.js} +1 -1
- package/dist/{defaults-DI642M3n.js.map → defaults-DulzMJpN.js.map} +1 -1
- package/dist/{env-api-key-BMXH7_4u.js → env-api-key-Ca-CrkgV.js} +2 -2
- package/dist/{env-api-key-BMXH7_4u.js.map → env-api-key-Ca-CrkgV.js.map} +1 -1
- package/dist/{environment-C3nfPBu-.js → environment-B0uTamFf.js} +4 -4
- package/dist/{environment-C3nfPBu-.js.map → environment-B0uTamFf.js.map} +1 -1
- package/dist/file-CNstcW8F.js +60 -0
- package/dist/file-CNstcW8F.js.map +1 -0
- package/dist/{file-watcher-BGElIpJi.js → file-watcher-CiT-oZpu.js} +2 -2
- package/dist/{file-watcher-BGElIpJi.js.map → file-watcher-CiT-oZpu.js.map} +1 -1
- package/dist/gateway-session-BIVN_Xfr.js +2 -0
- package/dist/gateway-session-C3Uqwc4R.js +271 -0
- package/dist/gateway-session-C3Uqwc4R.js.map +1 -0
- package/dist/{headless-ui-jkS2Dm_G.js → headless-ui-TpSp-F43.js} +10 -5
- package/dist/headless-ui-TpSp-F43.js.map +1 -0
- package/dist/{interactive-CrQWwMr2.js → interactive-B72L-sO5.js} +2 -2
- package/dist/{interactive-CrQWwMr2.js.map → interactive-B72L-sO5.js.map} +1 -1
- package/dist/{mcp-S3yX8Uz1.js → mcp-CNc6CLK0.js} +2 -2
- package/dist/{mcp-S3yX8Uz1.js.map → mcp-CNc6CLK0.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-BvvCZBYa.js → mcp-prompt-streaming-BvBNkzjv.js} +6 -5
- package/dist/{mcp-prompt-streaming-BvvCZBYa.js.map → mcp-prompt-streaming-BvBNkzjv.js.map} +1 -1
- package/dist/mint-failure-CZ5FZ0Jd.js +5739 -0
- package/dist/mint-failure-CZ5FZ0Jd.js.map +1 -0
- package/dist/{non-interactive-B-MIn3vt.js → non-interactive-UeQlnU0U.js} +2 -2
- package/dist/{non-interactive-B-MIn3vt.js.map → non-interactive-UeQlnU0U.js.map} +1 -1
- package/dist/{orchestrator-tools-CefodRf2.js → orchestrator-tools-CLADku26.js} +5 -5
- package/dist/orchestrator-tools-CLADku26.js.map +1 -0
- package/dist/{package-manager-pB6S0gyu.js → package-manager-CppzeIgu.js} +2 -2
- package/dist/{package-manager-pB6S0gyu.js.map → package-manager-CppzeIgu.js.map} +1 -1
- package/dist/{pi-Dbw8VakI.js → pi-Bs1Tbt0C.js} +35 -24
- package/dist/pi-Bs1Tbt0C.js.map +1 -0
- package/dist/{playground-C7DwGktN.js → playground-CZgZX4j0.js} +8 -8
- package/dist/{playground-C7DwGktN.js.map → playground-CZgZX4j0.js.map} +1 -1
- package/dist/{posthog-B3RuLfxH.js → posthog-BZ3NNCyh.js} +2 -2
- package/dist/{posthog-B3RuLfxH.js.map → posthog-BZ3NNCyh.js.map} +1 -1
- package/dist/{provisioning-B4Lr3-aS.js → provisioning-Ba7GWKzK.js} +3 -3
- package/dist/{provisioning-B4Lr3-aS.js.map → provisioning-Ba7GWKzK.js.map} +1 -1
- package/dist/{queue-tools-BveMVXQm.js → queue-tools-D09PNS0X.js} +17 -5
- package/dist/queue-tools-D09PNS0X.js.map +1 -0
- package/dist/{registry-D8MIZ9kJ.js → registry-COcpEsMD.js} +5 -5
- package/dist/{registry-D8MIZ9kJ.js.map → registry-COcpEsMD.js.map} +1 -1
- package/dist/{security-B_Eo15wD.js → security-CpAT0fZa.js} +5 -5
- package/dist/{security-B_Eo15wD.js.map → security-CpAT0fZa.js.map} +1 -1
- package/dist/{setup-utils-D3OK2RE_.js → setup-utils-BUAoRjw3.js} +48 -9
- package/dist/setup-utils-BUAoRjw3.js.map +1 -0
- package/dist/smoke-test-ci.sh +9 -14
- package/dist/{start-tui-B7u962uh.js → start-tui-Bz23_yym.js} +848 -127
- package/dist/start-tui-Bz23_yym.js.map +1 -0
- package/dist/{steps-D4mHkYX4.js → steps-DbsDish5.js} +7 -7
- package/dist/{steps-D4mHkYX4.js.map → steps-DbsDish5.js.map} +1 -1
- package/dist/{store-Cn1VK6U0.js → store-D5ROpUje.js} +63 -10
- package/dist/store-D5ROpUje.js.map +1 -0
- package/dist/{subagent-1UEmD7bE.js → subagent-CSBZnhgK.js} +2 -2
- package/dist/{subagent-1UEmD7bE.js.map → subagent-CSBZnhgK.js.map} +1 -1
- package/dist/{task-DNHNZMO0.js → task-D8sTR7jZ.js} +23 -23
- package/dist/task-D8sTR7jZ.js.map +1 -0
- package/dist/{task-stream-BJrRzR9K.js → task-stream-Dl0XEsZ9.js} +49 -7
- package/dist/task-stream-Dl0XEsZ9.js.map +1 -0
- package/dist/{tasks-DSEJ8GZC.js → tasks-BDt427kT.js} +2 -2
- package/dist/{tasks-DSEJ8GZC.js.map → tasks-BDt427kT.js.map} +1 -1
- package/dist/{telemetry-DWkTy6TJ.js → telemetry-Dp6zjZBj.js} +3 -3
- package/dist/{telemetry-DWkTy6TJ.js.map → telemetry-Dp6zjZBj.js.map} +1 -1
- package/dist/{terminal-DNnNkvFu.js → terminal-pInlleVD.js} +20 -18
- package/dist/{terminal-DNnNkvFu.js.map → terminal-pInlleVD.js.map} +1 -1
- package/dist/{tools-HHK4XbnC.js → tools-MkyMOjQI.js} +98 -28
- package/dist/tools-MkyMOjQI.js.map +1 -0
- package/dist/{wizard-abort-BVmjqUAQ.js → wizard-abort-BCnUgT9z.js} +4 -4
- package/dist/{wizard-abort-BVmjqUAQ.js.map → wizard-abort-BCnUgT9z.js.map} +1 -1
- package/dist/{wizard-abort-CG_xzEFN.js → wizard-abort-BHLKVKLN.js} +1 -1
- package/dist/{wizard-session-BWAQoi9q.js → wizard-session-CYvyYnti.js} +1 -1
- package/dist/{wizard-session-GdDN_aMS.js → wizard-session-FSJCkTcP.js} +9 -2
- package/dist/wizard-session-FSJCkTcP.js.map +1 -0
- package/dist/{yara-hooks-qRkdjYiV.js → yara-hooks-BJWVgTpU.js} +4 -4
- package/dist/{yara-hooks-qRkdjYiV.js.map → yara-hooks-BJWVgTpU.js.map} +1 -1
- package/dist/yara-hooks-Dp82xJGd.js +2 -0
- package/package.json +1 -1
- package/dist/agent-interface-lCIi_alS.js.map +0 -1
- package/dist/agent-runner-DVrkOFDA.js.map +0 -1
- package/dist/analytics-3H_AlflZ.js +0 -2
- package/dist/analytics-CeVMOExk.js.map +0 -1
- package/dist/debug-GxjVplPx.js.map +0 -1
- package/dist/headless-ui-jkS2Dm_G.js.map +0 -1
- package/dist/orchestrator-tools-CefodRf2.js.map +0 -1
- package/dist/pi-Dbw8VakI.js.map +0 -1
- package/dist/posthog-integration-su2LXi3-.js +0 -1475
- package/dist/posthog-integration-su2LXi3-.js.map +0 -1
- package/dist/queue-tools-BveMVXQm.js.map +0 -1
- package/dist/setup-utils-D3OK2RE_.js.map +0 -1
- package/dist/start-tui-B7u962uh.js.map +0 -1
- package/dist/store-Cn1VK6U0.js.map +0 -1
- package/dist/task-DNHNZMO0.js.map +0 -1
- package/dist/task-stream-BJrRzR9K.js.map +0 -1
- package/dist/tools-HHK4XbnC.js.map +0 -1
- package/dist/wizard-session-GdDN_aMS.js.map +0 -1
- package/dist/yara-hooks-BOMbtTOr.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { s as logToFile } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { s as logToFile } from "./debug-C5Zz8hmm.js";
|
|
2
|
+
import { n as analytics } from "./analytics-C_RyE8fz.js";
|
|
3
|
+
import { R as WIZARD_TOOL_NAMES, rt as fetchWithRetry } from "./agent-interface-CZWRgZMc.js";
|
|
4
|
+
import { _ as isThinkingLevel } from "./queue-tools-D09PNS0X.js";
|
|
5
5
|
//#region src/lib/agent/agent-prompt-loader.ts
|
|
6
6
|
function projectContext(ctx) {
|
|
7
7
|
return `You have access to the PostHog MCP server and the wizard tools.
|
|
@@ -311,4 +311,4 @@ const EMPTY_PROMPT = {};
|
|
|
311
311
|
//#endregion
|
|
312
312
|
export { assembleTaskPrompt as a, queueTools as c, taskModelSpec as d, assembleSeedPrompt as i, renderToolInventory as l, agentRunTools as n, loadAgentRegistry as o, allowsPostHogMcp as r, promptModelFor as s, ASK_TOOL as t, resolveTask as u };
|
|
313
313
|
|
|
314
|
-
//# sourceMappingURL=agent-prompt-loader-
|
|
314
|
+
//# sourceMappingURL=agent-prompt-loader-BobuLDIg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-prompt-loader-CSxm81TM.js","names":[],"sources":["../src/lib/agent/agent-prompt-loader.ts"],"sourcesContent":["/**\n * Agent-prompt loader + registry.\n *\n * Agent prompts are the WHAT of a task: a markdown file per type, served from\n * context-mill as the `agents` content type (parallel to skills). The frontmatter\n * carries the artifacts the executor needs — model, the mini-skills to load (the\n * HOW), the tools the task may use, and its dependencies — and the body is the\n * instruction the agent reads.\n *\n * The registry is fetched once at startup and scoped to one flow — agents\n * declare `flow` and (for the planner) `seed: true` in frontmatter, so each\n * program (integration, audit, migration, ...) ships its own agent set and the\n * loader stays generic. Every prompt is downloaded and parsed up front, so\n * resolving a task to its run config is synchronous and adds no mid-drain\n * network latency. The registry's type list also drives `enqueue_task`\n * validation.\n */\nimport type {\n QueueStore,\n QueuedTask,\n} from './runner/sequence/orchestrator/queue';\nimport type { ResolvedTask } from './runner/sequence/orchestrator/executor';\nimport type { HostResolution } from '@lib/host-resolution';\nimport {\n isThinkingLevel,\n type ThinkingLevel,\n} from './runner/switchboard/models';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport { fetchWithRetry } from '@lib/fetch-retry';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools/tools';\n\n/**\n * The basics the client injects around every agent-prompt body. The `/agents/`\n * files carry intent only (goal, success criteria); the wizard owns the I/O\n * contract — who the agent is, how it reports, how it surfaces progress — so the\n * authored prompts never restate it.\n */\nexport interface OrchestratorPromptContext {\n projectId: number;\n projectApiKey: string;\n host: HostResolution;\n /** Path to the framework's reference implementation (EXAMPLE.md), if available. */\n examplePath?: string;\n /** Path to the framework's rules (COMMANDMENTS.md), if available. */\n commandmentsPath?: string;\n}\n\nfunction projectContext(ctx: OrchestratorPromptContext): string {\n // Both hosts, distinctly labelled: `apiHost` is the ingestion/API origin the\n // SDK talks to, `appHost` the user-facing web app. A task that hands the user\n // a link (e.g. the data-warehouse new-source fallback) must build it from the\n // app host — the ingestion host does not serve those pages.\n return `You have access to the PostHog MCP server and the wizard tools.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host.apiHost}\n- PostHog app URL (base for any link you show the user in a browser): ${ctx.host.appHost}`;\n}\n\n/** Points the agent at the framework's reference integration to learn patterns from. */\nfunction exampleReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.examplePath) return null;\n return `A reference PostHog integration for this framework is at \\`${ctx.examplePath}\\`. It shows the target implementation pattern. Reference its patterns and conventions, adapting them to this codebase.`;\n}\n\n/** The framework's rules ship with the reference skill; every task follows them. */\nfunction commandmentsReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.commandmentsPath) return null;\n return `Framework rules for this integration are at \\`${ctx.commandmentsPath}\\`. Read them before you edit and follow them.`;\n}\n\n/**\n * The task's own tool list, injected so an agent never has to discover a tool's\n * absence by trying it — and never reports that absence as a finding. Later\n * tasks hold tools this one does not, so work it cannot do is handed on rather\n * than attempted.\n */\n/** Renders the inventory from the tool names a harness actually registered for\n * the run — the one complete list, in the vocabulary the agent will call. */\nexport function renderToolInventory(toolNames: readonly string[]): string {\n if (toolNames.length === 0) return '';\n return `Your tools for this task: ${toolNames.join(\n ', ',\n )}. Do not look for a tool that is not listed or treat its absence as a problem to report. Later tasks in this run hold tools you do not: when your task needs one, hand that work off in your handoff for the task that can do it, or note it for the final report.`;\n}\n\nconst TASK_BASICS = `You are one step in a larger PostHog workflow made of several tasks, run as a fresh agent with no memory of the other tasks beyond the context you are given. Other tasks — before and after you — own the rest of the work, so stay strictly on your own task: do not do a neighbouring step's job, redo what an upstream handoff already did, or reach beyond what you were asked. Do only your task, then report exactly once by calling complete_task with a structured handoff: what your goal was, what you did, and what the next agent should know. When you are given context from previous steps, trust it — those agents already did their work, so do not re-verify or re-read what their handoffs tell you. Build on it and move fast. Read a file before you edit it, so your own changes do not duplicate what is already there. Work only inside this project's own directory: never read, list, or search (find, ls, grep, glob) outside it — not the OS, not other projects, not global package caches. If your task seems to need something outside this directory, it does not — skip that part and say so in your handoff rather than hunting across the filesystem. If your task does not apply to this project — there is genuinely nothing for it to do — report it with status \\`not needed\\` and say why, rather than marking it done.`;\n\nconst SEED_BASICS = `You are the orchestrator. Plan the work and seed the queue with enqueue_task — each call returns an id you can pass as a dependency to a later task. Give each task a short label for the UI — the action in a few words, not file names, class names, or other specifics. The last task you queue, the one that reports on the run, must depend on every other task in the queue — directly, or through a task it already depends on. You are not a task yourself: do not call complete_task and do not edit the project.`;\n\n/**\n * Tasks the wizard queued before the planner ran. It has to see them: they are\n * part of the run it is planning around, and the task that reports last has to\n * depend on them. Their ids are real, so it can wire the edge directly.\n *\n * The one-way rule matters as much as the sink edge. These tasks are deferred to\n * the end of the drain after planning (`seeded-deps.ts`) and may block on a\n * person, so a task the planner hangs off one would wait on the user too — which\n * is the interruption deferring them removed. The resolver drops such a task\n * from the seeded task's own dependencies to stay acyclic, so the damage is\n * silent; saying so here is what prevents it.\n */\nfunction preQueuedTasks(\n tasks: readonly { id: string; type: string }[],\n): string | null {\n if (tasks.length === 0) return null;\n const lines = tasks.map((t) => `- ${t.type} (id: ${t.id})`);\n return `The queue already holds these tasks, placed by the wizard from what it found in this project. Do not queue them again. They run late — after every task you queue — and one may stop to ask the user for input, so make the reporting task depend on each one and hang nothing else off them: any other task you made depend on one would end up waiting on a person.\\n${lines.join(\n '\\n',\n )}`;\n}\n\n/**\n * Points the agent at its installed task instructions (the HOW). They live under\n * the wizard's run dir, not `.claude/skills/`, so the SDK does not auto-load\n * them — the prompt has to name them.\n */\nfunction skillReference(paths: readonly string[]): string | null {\n if (paths.length === 0) return null;\n const list = paths.map((p) => `\\`${p}\\``).join(', ');\n return `Your task instructions are at ${list}. Read them before you start and follow them. They are wizard scaffolding, not part of the project.`;\n}\n\n/** A task agent's full prompt: injected basics, then the authored intent. */\nexport function assembleTaskPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n skillPaths: readonly string[] = [],\n): string {\n return [\n projectContext(ctx),\n exampleReference(ctx),\n commandmentsReference(ctx),\n skillReference(skillPaths),\n TASK_BASICS,\n body,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** The seed agent's full prompt: injected basics, then the authored intent. */\nexport function assembleSeedPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n preQueued: readonly { id: string; type: string }[] = [],\n): string {\n return [projectContext(ctx), SEED_BASICS, preQueuedTasks(preQueued), body]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** Orchestrator tools are MCP tools under the `posthog-wizard` server. Frontmatter\n * names them short (e.g. `enqueue_task`); the SDK gates on the full name. */\nconst ORCHESTRATOR_TOOL_PREFIX = 'mcp__posthog-wizard__';\nconst ORCHESTRATOR_TOOLS = new Set([\n 'enqueue_task',\n 'complete_task',\n 'read_handoffs',\n]);\n\n/** The one tool that stops a task until a person answers. Named short in frontmatter. */\nexport const ASK_TOOL = 'wizard_ask';\n\n/** The skill-menu tools, as agents ask for them in frontmatter. */\nconst SKILL_MENU_TOOL = 'load_skill_menu';\nconst INSTALL_SKILL_TOOL = 'install_skill';\n\n/**\n * The PostHog MCP, as an agent asks for it in frontmatter. Every tool a task\n * gets is granted by its own prompt, this one included: a task that never names\n * it never has the server wired in, and one that does gets it under this name\n * on both harnesses.\n */\nexport const POSTHOG_MCP_TOOL = 'posthog_exec';\n/** The same tool as the anthropic SDK names it, on the hosted PostHog server. */\nconst POSTHOG_MCP_SDK_TOOL = 'mcp__posthog-wizard__exec';\n\n/** Whether a task asked for the PostHog MCP — accepts either spelling. */\nexport function allowsPostHogMcp(\n allowedTools: readonly string[] | undefined,\n): boolean {\n return (allowedTools ?? []).some(\n (name) => name === POSTHOG_MCP_TOOL || name === POSTHOG_MCP_SDK_TOOL,\n );\n}\n\n/** The queue tools a task holds — all of them minus its disallows. Short names.\n * Single source for both the injected inventory and the harness's tool grant. */\nexport function queueTools(disallowedTools: readonly string[]): string[] {\n const disallowed = new Set(\n disallowedTools.map((n) => n.replace(ORCHESTRATOR_TOOL_PREFIX, '')),\n );\n return [...ORCHESTRATOR_TOOLS].filter((t) => !disallowed.has(t));\n}\n\n/** A parsed agent prompt. The frontmatter fields plus the markdown body. */\nexport interface AgentPrompt {\n type: string;\n /** Human-readable title for the TUI; falls back to `type` when absent. */\n label?: string;\n /** The flow this agent belongs to (the program id, e.g. \\`posthog-integration\\`). */\n flow?: string;\n /** Marks the flow's planner: it seeds the queue and is not an enqueueable task. */\n seed: boolean;\n /** Marks a task that runs last: it must depend on every other task in the queue. */\n sink: boolean;\n /**\n * Marks a task only the wizard may queue. The planner never sees the type, so\n * whether it runs is a decision the client makes from what it detected, not\n * one an agent can reach — it can neither invent the task nor forget it.\n */\n runnerSeeded: boolean;\n /** Per-harness model/effort; both profiles also require gateway admission and prompt compatibility. */\n modelPi?: string;\n effortPi?: ThinkingLevel;\n modelSdk?: string;\n effortSdk?: ThinkingLevel;\n skills: string[];\n allowedTools: string[];\n disallowedTools: string[];\n /**\n * Task types this one runs after. Read differently by the two kinds of task:\n *\n * - **Enqueueable types**: advisory. The planner authors the real graph with\n * `enqueue_task`, passing ids, and its seed prompt describes the shape it\n * should build. Nothing resolves this field for them.\n * - **`runnerSeeded` types**: authoritative. Such a task is queued before the\n * planner runs, so it cannot name ids; the runner resolves these types to\n * the ids the planner produced and applies them (see `seeded-deps.ts`).\n * Empty means \"after everything that is not the sink\".\n */\n dependsOn: string[];\n body: string;\n}\n\n/** Pi selects the pi profile; the legacy Anthropic SDK selects the sdk profile. */\nexport function promptModelFor(\n prompt: AgentPrompt,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const pi = harness === 'pi';\n return {\n model: pi ? prompt.modelPi : prompt.modelSdk,\n effort: pi ? prompt.effortPi : prompt.effortSdk,\n };\n}\n\nexport interface AgentRegistry {\n /** The flow's task types — every prompt except the seed. */\n readonly types: string[];\n /** The types an agent may enqueue: `types` minus the runner-seeded ones. */\n readonly enqueueableTypes: string[];\n /** The types that run last and must depend on the whole queue. */\n readonly sinkTypes: string[];\n /** The types only the wizard queues, from what it detected before the run. */\n readonly runnerSeededTypes: string[];\n /** The flow's planner, the one prompt marked `seed: true` in its frontmatter. */\n readonly seed?: AgentPrompt;\n get(type: string): AgentPrompt | undefined;\n}\n\n/** The registry for one flow's prompts. Pure; the loader feeds it the fetched set. */\nexport function buildRegistry(\n prompts: readonly AgentPrompt[],\n flow: string,\n opts?: {\n exclude?: readonly string[];\n /** Per-stage pi model/effort overlays, keyed by task type ('seed' for the planner). Applied here — the one place prompts enter the wizard — so every downstream read sees the effective spec. */\n overrides?: Record<\n string,\n { model?: string; effort?: ThinkingLevel } | undefined\n >;\n },\n): AgentRegistry {\n // The harness can exclude task types (CI excludes dashboards). An excluded\n // type does not exist for the run: the seed cannot enqueue it and no agent\n // is ever spun up for it.\n const excluded = new Set(opts?.exclude ?? []);\n const inFlow = prompts\n .filter((p) => p.flow === flow && !excluded.has(p.type))\n .map((p) => {\n const o = opts?.overrides?.[p.seed ? 'seed' : p.type];\n if (!o) return p;\n return {\n ...p,\n modelPi: o.model ?? p.modelPi,\n effortPi: o.effort ?? p.effortPi,\n };\n });\n const byType = new Map(inFlow.map((p) => [p.type, p]));\n const tasks = inFlow.filter((p) => !p.seed);\n return {\n types: tasks.map((p) => p.type),\n enqueueableTypes: tasks.filter((p) => !p.runnerSeeded).map((p) => p.type),\n sinkTypes: tasks.filter((p) => p.sink).map((p) => p.type),\n runnerSeededTypes: tasks.filter((p) => p.runnerSeeded).map((p) => p.type),\n seed: inFlow.find((p) => p.seed),\n get: (type) => byType.get(type),\n };\n}\n\ninterface AgentMenu {\n /** `flow` arrived with context-mill's flow-scoped agents folder; older menus omit it. */\n agents: { id: string; flow?: string; downloadUrl: string }[];\n}\n\n/** A native tool passes through; an MCP tool gets its fully-qualified name. */\nfunction expandToolName(name: string): string {\n if (name === ASK_TOOL) return WIZARD_TOOL_NAMES.wizardAsk;\n if (name === SKILL_MENU_TOOL) return WIZARD_TOOL_NAMES.loadSkillMenu;\n if (name === INSTALL_SKILL_TOOL) return WIZARD_TOOL_NAMES.installSkill;\n if (name === POSTHOG_MCP_TOOL) return POSTHOG_MCP_SDK_TOOL;\n return ORCHESTRATOR_TOOLS.has(name)\n ? `${ORCHESTRATOR_TOOL_PREFIX}${name}`\n : name;\n}\n\n/** A prompt's allow/disallow lists with orchestrator tool names MCP-qualified. */\nexport function agentRunTools(prompt: AgentPrompt): {\n allowedTools: string[];\n disallowedTools: string[];\n} {\n return {\n allowedTools: prompt.allowedTools.map(expandToolName),\n disallowedTools: prompt.disallowedTools.map(expandToolName),\n };\n}\n\nfunction toStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((v): v is string => typeof v === 'string');\n}\n\n/**\n * Parse the leading `---` frontmatter block and the markdown body. The\n * frontmatter is a small, known schema (scalars and inline `[a, b]` arrays), so\n * a tiny parser covers it without a YAML dependency. Inline `# comments` after a\n * value are stripped. `fallbackType` (the menu id) and `fallbackFlow` (the\n * menu entry's flow) apply when the frontmatter omits `type:`/`flow:`.\n */\nexport function parseAgentPrompt(\n text: string,\n fallbackType: string,\n fallbackFlow?: string,\n): AgentPrompt {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n const frontmatter = match ? match[1] : '';\n const body = (match ? match[2] : text).trim();\n\n const fields: Record<string, unknown> = {};\n for (const rawLine of frontmatter.split(/\\r?\\n/)) {\n const line = rawLine.replace(/\\s+#.*$/, '').trim();\n if (!line || line.startsWith('#')) continue;\n const kv = line.match(/^([\\w-]+):\\s*(.*)$/);\n if (!kv) continue;\n const [, key, raw] = kv;\n if (raw.startsWith('[') && raw.endsWith(']')) {\n fields[key] = raw\n .slice(1, -1)\n .split(',')\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''))\n .filter(Boolean);\n } else {\n fields[key] = raw.replace(/^['\"]|['\"]$/g, '');\n }\n }\n\n const str = (v: unknown) => (typeof v === 'string' ? v : undefined);\n // Effort is remote data — reject typos here so downstream carries ThinkingLevel.\n const effort = (v: unknown, key: string): ThinkingLevel | undefined => {\n if (v === undefined) return undefined;\n if (isThinkingLevel(v)) return v;\n logToFile(\n `[agent-prompt] ${fallbackType}: ignoring invalid ${key} \"${String(v)}\"`,\n );\n analytics.wizardCapture('agent prompt invalid effort', {\n task_type: fallbackType,\n key,\n value: String(v),\n });\n return undefined;\n };\n return {\n type: typeof fields.type === 'string' ? fields.type : fallbackType,\n label: typeof fields.label === 'string' ? fields.label : undefined,\n flow: typeof fields.flow === 'string' ? fields.flow : fallbackFlow,\n seed: fields.seed === 'true',\n sink: fields.sink === 'true',\n runnerSeeded: fields.runnerSeeded === 'true',\n modelPi: str(fields.model_pi),\n effortPi: effort(fields.effort_pi, 'effort_pi'),\n modelSdk: str(fields.model_sdk),\n effortSdk: effort(fields.effort_sdk, 'effort_sdk'),\n skills: toStringArray(fields.skills),\n allowedTools: toStringArray(fields.allowedTools),\n disallowedTools: toStringArray(fields.disallowedTools),\n dependsOn: toStringArray(fields.dependsOn),\n body,\n };\n}\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetchWithRetry(url);\n return res.text();\n}\n\n/**\n * Fetch the agent menu and every agent prompt it lists, parse them, and build\n * the registry for one flow. Throws if the menu cannot be fetched — the\n * orchestrator cannot run without its prompts.\n */\nexport async function loadAgentRegistry(\n skillsBaseUrl: string,\n flow: string,\n opts?: Parameters<typeof buildRegistry>[2],\n): Promise<AgentRegistry> {\n const menuRaw = await fetchText(`${skillsBaseUrl}/agent-menu.json`);\n const menu = JSON.parse(menuRaw) as AgentMenu;\n\n // Menus that carry a flow per entry let us skip other flows' prompts before\n // fetching them; entries without one are fetched and filtered by their\n // frontmatter in buildRegistry, as before.\n const entries = (menu.agents ?? []).filter(\n (entry) => !entry.flow || entry.flow === flow,\n );\n const prompts = await Promise.all(\n entries.map(async (entry) => {\n const text = await fetchText(entry.downloadUrl);\n return parseAgentPrompt(text, entry.id, entry.flow);\n }),\n );\n\n return buildRegistry(prompts, flow, opts);\n}\n\n/**\n * Render a task's own inputs into a section, so a fanned-out task (e.g. one\n * `capture` per event) sees the specific thing it owns. Empty when there are none.\n */\nfunction renderInputs(task: QueuedTask): string {\n const entries = Object.entries(task.inputs ?? {});\n if (entries.length === 0) return '';\n const lines = entries.map(([k, v]) => `- ${k}: ${formatInputValue(v)}`);\n return `## Your task input\\n\\n${lines.join('\\n')}`;\n}\n\nfunction formatInputValue(value: unknown): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\n/**\n * The ids of every task `task` transitively depends on — the full upstream\n * chain, not just direct dependencies — ordered roots-first, each once. A `seen`\n * set dedupes diamonds and guards against cycles.\n */\nfunction ancestorIds(task: QueuedTask, store: QueueStore): string[] {\n const seen = new Set<string>();\n const ordered: string[] = [];\n const visit = (id: string): void => {\n if (seen.has(id)) return;\n seen.add(id);\n const t = store.get(id);\n if (!t) return;\n for (const dep of t.dependsOn) visit(dep); // ancestors before dependents\n ordered.push(id);\n };\n for (const dep of task.dependsOn) visit(dep);\n return ordered;\n}\n\n/**\n * Render the handoffs of every step `task` transitively depends on into a context\n * section, so a fresh agent sees the whole upstream chain — not just its direct\n * dependencies. Reliability over token economy: a step must never have to\n * re-discover what any ancestor already established just because an intermediate\n * handoff happened to omit it. Empty when there are no completed ancestors.\n */\nfunction renderHandoffContext(task: QueuedTask, store: QueueStore): string {\n const lines: string[] = [];\n for (const id of ancestorIds(task, store)) {\n const dep = store.get(id);\n const handoff = store.readHandoff(id);\n if (!dep || !handoff) continue;\n lines.push(`### ${dep.type}`);\n lines.push(`- did: ${handoff.did}`);\n lines.push(`- for you: ${handoff.forNextAgent}`);\n if (handoff.filesTouched?.length) {\n lines.push(`- files: ${handoff.filesTouched.join(', ')}`);\n }\n if (handoff.evidence) {\n lines.push(`- evidence: ${handoff.evidence}`);\n }\n if (handoff.assumptions) {\n lines.push(`- assumed: ${handoff.assumptions}`);\n }\n if (handoff.reportSection) {\n lines.push(`- report section:\\n${handoff.reportSection}`);\n }\n lines.push('');\n }\n if (lines.length === 0) return '';\n return `## Context from previous steps\\n\\n${lines.join('\\n')}`.trim();\n}\n\n/**\n * Resolve a queued task to its run config: the prompt body (with upstream\n * handoffs appended), the model, and the tool lists with orchestrator tool names\n * MCP-qualified. The model precedence is enqueue override, then prompt, then\n * default. Throws if no prompt is registered for the task's type.\n */\nexport function resolveTask(\n registry: AgentRegistry,\n task: QueuedTask,\n store: QueueStore,\n): ResolvedTask {\n const prompt = registry.get(task.type);\n if (!prompt) {\n throw new Error(`No agent prompt registered for task type \"${task.type}\"`);\n }\n\n const body = [\n renderInputs(task),\n prompt.body,\n renderHandoffContext(task, store),\n ]\n .filter(Boolean)\n .join('\\n\\n');\n\n return {\n ...agentRunTools(prompt),\n prompt: body,\n skills: prompt.skills,\n };\n}\n\n/** The model + effort a task runs on for a harness: enqueue override, then the\n * prompt's per-profile frontmatter; the caller's switchboard pick is the fallback. */\nexport function taskModelSpec(\n registry: AgentRegistry,\n task: QueuedTask,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const picked = promptModelFor(\n registry.get(task.type) ?? EMPTY_PROMPT,\n harness,\n );\n return {\n model: task.model ?? picked.model,\n effort: picked.effort,\n };\n}\n\nconst EMPTY_PROMPT = {} as AgentPrompt;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-prompt-loader-BobuLDIg.js","names":[],"sources":["../src/lib/agent/agent-prompt-loader.ts"],"sourcesContent":["/**\n * Agent-prompt loader + registry.\n *\n * Agent prompts are the WHAT of a task: a markdown file per type, served from\n * context-mill as the `agents` content type (parallel to skills). The frontmatter\n * carries the artifacts the executor needs — model, the mini-skills to load (the\n * HOW), the tools the task may use, and its dependencies — and the body is the\n * instruction the agent reads.\n *\n * The registry is fetched once at startup and scoped to one flow — agents\n * declare `flow` and (for the planner) `seed: true` in frontmatter, so each\n * program (integration, audit, migration, ...) ships its own agent set and the\n * loader stays generic. Every prompt is downloaded and parsed up front, so\n * resolving a task to its run config is synchronous and adds no mid-drain\n * network latency. The registry's type list also drives `enqueue_task`\n * validation.\n */\nimport type {\n QueueStore,\n QueuedTask,\n} from './runner/sequence/orchestrator/queue';\nimport type { ResolvedTask } from './runner/sequence/orchestrator/executor';\nimport type { HostResolution } from '@lib/host-resolution';\nimport {\n isThinkingLevel,\n type ThinkingLevel,\n} from './runner/switchboard/models';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport { fetchWithRetry } from '@lib/fetch-retry';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools/tools';\n\n/**\n * The basics the client injects around every agent-prompt body. The `/agents/`\n * files carry intent only (goal, success criteria); the wizard owns the I/O\n * contract — who the agent is, how it reports, how it surfaces progress — so the\n * authored prompts never restate it.\n */\nexport interface OrchestratorPromptContext {\n projectId: number;\n projectApiKey: string;\n host: HostResolution;\n /** Path to the framework's reference implementation (EXAMPLE.md), if available. */\n examplePath?: string;\n /** Path to the framework's rules (COMMANDMENTS.md), if available. */\n commandmentsPath?: string;\n}\n\nfunction projectContext(ctx: OrchestratorPromptContext): string {\n // Both hosts, distinctly labelled: `apiHost` is the ingestion/API origin the\n // SDK talks to, `appHost` the user-facing web app. A task that hands the user\n // a link (e.g. the data-warehouse new-source fallback) must build it from the\n // app host — the ingestion host does not serve those pages.\n return `You have access to the PostHog MCP server and the wizard tools.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host.apiHost}\n- PostHog app URL (base for any link you show the user in a browser): ${ctx.host.appHost}`;\n}\n\n/** Points the agent at the framework's reference integration to learn patterns from. */\nfunction exampleReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.examplePath) return null;\n return `A reference PostHog integration for this framework is at \\`${ctx.examplePath}\\`. It shows the target implementation pattern. Reference its patterns and conventions, adapting them to this codebase.`;\n}\n\n/** The framework's rules ship with the reference skill; every task follows them. */\nfunction commandmentsReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.commandmentsPath) return null;\n return `Framework rules for this integration are at \\`${ctx.commandmentsPath}\\`. Read them before you edit and follow them.`;\n}\n\n/**\n * The task's own tool list, injected so an agent never has to discover a tool's\n * absence by trying it — and never reports that absence as a finding. Later\n * tasks hold tools this one does not, so work it cannot do is handed on rather\n * than attempted.\n */\n/** Renders the inventory from the tool names a harness actually registered for\n * the run — the one complete list, in the vocabulary the agent will call. */\nexport function renderToolInventory(toolNames: readonly string[]): string {\n if (toolNames.length === 0) return '';\n return `Your tools for this task: ${toolNames.join(\n ', ',\n )}. Do not look for a tool that is not listed or treat its absence as a problem to report. Later tasks in this run hold tools you do not: when your task needs one, hand that work off in your handoff for the task that can do it, or note it for the final report.`;\n}\n\nconst TASK_BASICS = `You are one step in a larger PostHog workflow made of several tasks, run as a fresh agent with no memory of the other tasks beyond the context you are given. Other tasks — before and after you — own the rest of the work, so stay strictly on your own task: do not do a neighbouring step's job, redo what an upstream handoff already did, or reach beyond what you were asked. Do only your task, then report exactly once by calling complete_task with a structured handoff: what your goal was, what you did, and what the next agent should know. When you are given context from previous steps, trust it — those agents already did their work, so do not re-verify or re-read what their handoffs tell you. Build on it and move fast. Read a file before you edit it, so your own changes do not duplicate what is already there. Work only inside this project's own directory: never read, list, or search (find, ls, grep, glob) outside it — not the OS, not other projects, not global package caches. If your task seems to need something outside this directory, it does not — skip that part and say so in your handoff rather than hunting across the filesystem. If your task does not apply to this project — there is genuinely nothing for it to do — report it with status \\`not needed\\` and say why, rather than marking it done.`;\n\nconst SEED_BASICS = `You are the orchestrator. Plan the work and seed the queue with enqueue_task — each call returns an id you can pass as a dependency to a later task. Give each task a short label for the UI — the action in a few words, not file names, class names, or other specifics. The last task you queue, the one that reports on the run, must depend on every other task in the queue — directly, or through a task it already depends on. You are not a task yourself: do not call complete_task and do not edit the project.`;\n\n/**\n * Tasks the wizard queued before the planner ran. It has to see them: they are\n * part of the run it is planning around, and the task that reports last has to\n * depend on them. Their ids are real, so it can wire the edge directly.\n *\n * The one-way rule matters as much as the sink edge. These tasks are deferred to\n * the end of the drain after planning (`seeded-deps.ts`) and may block on a\n * person, so a task the planner hangs off one would wait on the user too — which\n * is the interruption deferring them removed. The resolver drops such a task\n * from the seeded task's own dependencies to stay acyclic, so the damage is\n * silent; saying so here is what prevents it.\n */\nfunction preQueuedTasks(\n tasks: readonly { id: string; type: string }[],\n): string | null {\n if (tasks.length === 0) return null;\n const lines = tasks.map((t) => `- ${t.type} (id: ${t.id})`);\n return `The queue already holds these tasks, placed by the wizard from what it found in this project. Do not queue them again. They run late — after every task you queue — and one may stop to ask the user for input, so make the reporting task depend on each one and hang nothing else off them: any other task you made depend on one would end up waiting on a person.\\n${lines.join(\n '\\n',\n )}`;\n}\n\n/**\n * Points the agent at its installed task instructions (the HOW). They live under\n * the wizard's run dir, not `.claude/skills/`, so the SDK does not auto-load\n * them — the prompt has to name them.\n */\nfunction skillReference(paths: readonly string[]): string | null {\n if (paths.length === 0) return null;\n const list = paths.map((p) => `\\`${p}\\``).join(', ');\n return `Your task instructions are at ${list}. Read them before you start and follow them. They are wizard scaffolding, not part of the project.`;\n}\n\n/** A task agent's full prompt: injected basics, then the authored intent. */\nexport function assembleTaskPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n skillPaths: readonly string[] = [],\n): string {\n return [\n projectContext(ctx),\n exampleReference(ctx),\n commandmentsReference(ctx),\n skillReference(skillPaths),\n TASK_BASICS,\n body,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** The seed agent's full prompt: injected basics, then the authored intent. */\nexport function assembleSeedPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n preQueued: readonly { id: string; type: string }[] = [],\n): string {\n return [projectContext(ctx), SEED_BASICS, preQueuedTasks(preQueued), body]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** Orchestrator tools are MCP tools under the `posthog-wizard` server. Frontmatter\n * names them short (e.g. `enqueue_task`); the SDK gates on the full name. */\nconst ORCHESTRATOR_TOOL_PREFIX = 'mcp__posthog-wizard__';\nconst ORCHESTRATOR_TOOLS = new Set([\n 'enqueue_task',\n 'complete_task',\n 'read_handoffs',\n]);\n\n/** The one tool that stops a task until a person answers. Named short in frontmatter. */\nexport const ASK_TOOL = 'wizard_ask';\n\n/** The skill-menu tools, as agents ask for them in frontmatter. */\nconst SKILL_MENU_TOOL = 'load_skill_menu';\nconst INSTALL_SKILL_TOOL = 'install_skill';\n\n/**\n * The PostHog MCP, as an agent asks for it in frontmatter. Every tool a task\n * gets is granted by its own prompt, this one included: a task that never names\n * it never has the server wired in, and one that does gets it under this name\n * on both harnesses.\n */\nexport const POSTHOG_MCP_TOOL = 'posthog_exec';\n/** The same tool as the anthropic SDK names it, on the hosted PostHog server. */\nconst POSTHOG_MCP_SDK_TOOL = 'mcp__posthog-wizard__exec';\n\n/** Whether a task asked for the PostHog MCP — accepts either spelling. */\nexport function allowsPostHogMcp(\n allowedTools: readonly string[] | undefined,\n): boolean {\n return (allowedTools ?? []).some(\n (name) => name === POSTHOG_MCP_TOOL || name === POSTHOG_MCP_SDK_TOOL,\n );\n}\n\n/** The queue tools a task holds — all of them minus its disallows. Short names.\n * Single source for both the injected inventory and the harness's tool grant. */\nexport function queueTools(disallowedTools: readonly string[]): string[] {\n const disallowed = new Set(\n disallowedTools.map((n) => n.replace(ORCHESTRATOR_TOOL_PREFIX, '')),\n );\n return [...ORCHESTRATOR_TOOLS].filter((t) => !disallowed.has(t));\n}\n\n/** A parsed agent prompt. The frontmatter fields plus the markdown body. */\nexport interface AgentPrompt {\n type: string;\n /** Human-readable title for the TUI; falls back to `type` when absent. */\n label?: string;\n /** The flow this agent belongs to (the program id, e.g. \\`posthog-integration\\`). */\n flow?: string;\n /** Marks the flow's planner: it seeds the queue and is not an enqueueable task. */\n seed: boolean;\n /** Marks a task that runs last: it must depend on every other task in the queue. */\n sink: boolean;\n /**\n * Marks a task only the wizard may queue. The planner never sees the type, so\n * whether it runs is a decision the client makes from what it detected, not\n * one an agent can reach — it can neither invent the task nor forget it.\n */\n runnerSeeded: boolean;\n /** Per-harness model/effort; both profiles also require gateway admission and prompt compatibility. */\n modelPi?: string;\n effortPi?: ThinkingLevel;\n modelSdk?: string;\n effortSdk?: ThinkingLevel;\n skills: string[];\n allowedTools: string[];\n disallowedTools: string[];\n /**\n * Task types this one runs after. Read differently by the two kinds of task:\n *\n * - **Enqueueable types**: advisory. The planner authors the real graph with\n * `enqueue_task`, passing ids, and its seed prompt describes the shape it\n * should build. Nothing resolves this field for them.\n * - **`runnerSeeded` types**: authoritative. Such a task is queued before the\n * planner runs, so it cannot name ids; the runner resolves these types to\n * the ids the planner produced and applies them (see `seeded-deps.ts`).\n * Empty means \"after everything that is not the sink\".\n */\n dependsOn: string[];\n body: string;\n}\n\n/** Pi selects the pi profile; the legacy Anthropic SDK selects the sdk profile. */\nexport function promptModelFor(\n prompt: AgentPrompt,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const pi = harness === 'pi';\n return {\n model: pi ? prompt.modelPi : prompt.modelSdk,\n effort: pi ? prompt.effortPi : prompt.effortSdk,\n };\n}\n\nexport interface AgentRegistry {\n /** The flow's task types — every prompt except the seed. */\n readonly types: string[];\n /** The types an agent may enqueue: `types` minus the runner-seeded ones. */\n readonly enqueueableTypes: string[];\n /** The types that run last and must depend on the whole queue. */\n readonly sinkTypes: string[];\n /** The types only the wizard queues, from what it detected before the run. */\n readonly runnerSeededTypes: string[];\n /** The flow's planner, the one prompt marked `seed: true` in its frontmatter. */\n readonly seed?: AgentPrompt;\n get(type: string): AgentPrompt | undefined;\n}\n\n/** The registry for one flow's prompts. Pure; the loader feeds it the fetched set. */\nexport function buildRegistry(\n prompts: readonly AgentPrompt[],\n flow: string,\n opts?: {\n exclude?: readonly string[];\n /** Per-stage pi model/effort overlays, keyed by task type ('seed' for the planner). Applied here — the one place prompts enter the wizard — so every downstream read sees the effective spec. */\n overrides?: Record<\n string,\n { model?: string; effort?: ThinkingLevel } | undefined\n >;\n },\n): AgentRegistry {\n // The harness can exclude task types (CI excludes dashboards). An excluded\n // type does not exist for the run: the seed cannot enqueue it and no agent\n // is ever spun up for it.\n const excluded = new Set(opts?.exclude ?? []);\n const inFlow = prompts\n .filter((p) => p.flow === flow && !excluded.has(p.type))\n .map((p) => {\n const o = opts?.overrides?.[p.seed ? 'seed' : p.type];\n if (!o) return p;\n return {\n ...p,\n modelPi: o.model ?? p.modelPi,\n effortPi: o.effort ?? p.effortPi,\n };\n });\n const byType = new Map(inFlow.map((p) => [p.type, p]));\n const tasks = inFlow.filter((p) => !p.seed);\n return {\n types: tasks.map((p) => p.type),\n enqueueableTypes: tasks.filter((p) => !p.runnerSeeded).map((p) => p.type),\n sinkTypes: tasks.filter((p) => p.sink).map((p) => p.type),\n runnerSeededTypes: tasks.filter((p) => p.runnerSeeded).map((p) => p.type),\n seed: inFlow.find((p) => p.seed),\n get: (type) => byType.get(type),\n };\n}\n\ninterface AgentMenu {\n /** `flow` arrived with context-mill's flow-scoped agents folder; older menus omit it. */\n agents: { id: string; flow?: string; downloadUrl: string }[];\n}\n\n/** A native tool passes through; an MCP tool gets its fully-qualified name. */\nfunction expandToolName(name: string): string {\n if (name === ASK_TOOL) return WIZARD_TOOL_NAMES.wizardAsk;\n if (name === SKILL_MENU_TOOL) return WIZARD_TOOL_NAMES.loadSkillMenu;\n if (name === INSTALL_SKILL_TOOL) return WIZARD_TOOL_NAMES.installSkill;\n if (name === POSTHOG_MCP_TOOL) return POSTHOG_MCP_SDK_TOOL;\n return ORCHESTRATOR_TOOLS.has(name)\n ? `${ORCHESTRATOR_TOOL_PREFIX}${name}`\n : name;\n}\n\n/** A prompt's allow/disallow lists with orchestrator tool names MCP-qualified. */\nexport function agentRunTools(prompt: AgentPrompt): {\n allowedTools: string[];\n disallowedTools: string[];\n} {\n return {\n allowedTools: prompt.allowedTools.map(expandToolName),\n disallowedTools: prompt.disallowedTools.map(expandToolName),\n };\n}\n\nfunction toStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((v): v is string => typeof v === 'string');\n}\n\n/**\n * Parse the leading `---` frontmatter block and the markdown body. The\n * frontmatter is a small, known schema (scalars and inline `[a, b]` arrays), so\n * a tiny parser covers it without a YAML dependency. Inline `# comments` after a\n * value are stripped. `fallbackType` (the menu id) and `fallbackFlow` (the\n * menu entry's flow) apply when the frontmatter omits `type:`/`flow:`.\n */\nexport function parseAgentPrompt(\n text: string,\n fallbackType: string,\n fallbackFlow?: string,\n): AgentPrompt {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n const frontmatter = match ? match[1] : '';\n const body = (match ? match[2] : text).trim();\n\n const fields: Record<string, unknown> = {};\n for (const rawLine of frontmatter.split(/\\r?\\n/)) {\n const line = rawLine.replace(/\\s+#.*$/, '').trim();\n if (!line || line.startsWith('#')) continue;\n const kv = line.match(/^([\\w-]+):\\s*(.*)$/);\n if (!kv) continue;\n const [, key, raw] = kv;\n if (raw.startsWith('[') && raw.endsWith(']')) {\n fields[key] = raw\n .slice(1, -1)\n .split(',')\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''))\n .filter(Boolean);\n } else {\n fields[key] = raw.replace(/^['\"]|['\"]$/g, '');\n }\n }\n\n const str = (v: unknown) => (typeof v === 'string' ? v : undefined);\n // Effort is remote data — reject typos here so downstream carries ThinkingLevel.\n const effort = (v: unknown, key: string): ThinkingLevel | undefined => {\n if (v === undefined) return undefined;\n if (isThinkingLevel(v)) return v;\n logToFile(\n `[agent-prompt] ${fallbackType}: ignoring invalid ${key} \"${String(v)}\"`,\n );\n analytics.wizardCapture('agent prompt invalid effort', {\n task_type: fallbackType,\n key,\n value: String(v),\n });\n return undefined;\n };\n return {\n type: typeof fields.type === 'string' ? fields.type : fallbackType,\n label: typeof fields.label === 'string' ? fields.label : undefined,\n flow: typeof fields.flow === 'string' ? fields.flow : fallbackFlow,\n seed: fields.seed === 'true',\n sink: fields.sink === 'true',\n runnerSeeded: fields.runnerSeeded === 'true',\n modelPi: str(fields.model_pi),\n effortPi: effort(fields.effort_pi, 'effort_pi'),\n modelSdk: str(fields.model_sdk),\n effortSdk: effort(fields.effort_sdk, 'effort_sdk'),\n skills: toStringArray(fields.skills),\n allowedTools: toStringArray(fields.allowedTools),\n disallowedTools: toStringArray(fields.disallowedTools),\n dependsOn: toStringArray(fields.dependsOn),\n body,\n };\n}\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetchWithRetry(url);\n return res.text();\n}\n\n/**\n * Fetch the agent menu and every agent prompt it lists, parse them, and build\n * the registry for one flow. Throws if the menu cannot be fetched — the\n * orchestrator cannot run without its prompts.\n */\nexport async function loadAgentRegistry(\n skillsBaseUrl: string,\n flow: string,\n opts?: Parameters<typeof buildRegistry>[2],\n): Promise<AgentRegistry> {\n const menuRaw = await fetchText(`${skillsBaseUrl}/agent-menu.json`);\n const menu = JSON.parse(menuRaw) as AgentMenu;\n\n // Menus that carry a flow per entry let us skip other flows' prompts before\n // fetching them; entries without one are fetched and filtered by their\n // frontmatter in buildRegistry, as before.\n const entries = (menu.agents ?? []).filter(\n (entry) => !entry.flow || entry.flow === flow,\n );\n const prompts = await Promise.all(\n entries.map(async (entry) => {\n const text = await fetchText(entry.downloadUrl);\n return parseAgentPrompt(text, entry.id, entry.flow);\n }),\n );\n\n return buildRegistry(prompts, flow, opts);\n}\n\n/**\n * Render a task's own inputs into a section, so a fanned-out task (e.g. one\n * `capture` per event) sees the specific thing it owns. Empty when there are none.\n */\nfunction renderInputs(task: QueuedTask): string {\n const entries = Object.entries(task.inputs ?? {});\n if (entries.length === 0) return '';\n const lines = entries.map(([k, v]) => `- ${k}: ${formatInputValue(v)}`);\n return `## Your task input\\n\\n${lines.join('\\n')}`;\n}\n\nfunction formatInputValue(value: unknown): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\n/**\n * The ids of every task `task` transitively depends on — the full upstream\n * chain, not just direct dependencies — ordered roots-first, each once. A `seen`\n * set dedupes diamonds and guards against cycles.\n */\nfunction ancestorIds(task: QueuedTask, store: QueueStore): string[] {\n const seen = new Set<string>();\n const ordered: string[] = [];\n const visit = (id: string): void => {\n if (seen.has(id)) return;\n seen.add(id);\n const t = store.get(id);\n if (!t) return;\n for (const dep of t.dependsOn) visit(dep); // ancestors before dependents\n ordered.push(id);\n };\n for (const dep of task.dependsOn) visit(dep);\n return ordered;\n}\n\n/**\n * Render the handoffs of every step `task` transitively depends on into a context\n * section, so a fresh agent sees the whole upstream chain — not just its direct\n * dependencies. Reliability over token economy: a step must never have to\n * re-discover what any ancestor already established just because an intermediate\n * handoff happened to omit it. Empty when there are no completed ancestors.\n */\nfunction renderHandoffContext(task: QueuedTask, store: QueueStore): string {\n const lines: string[] = [];\n for (const id of ancestorIds(task, store)) {\n const dep = store.get(id);\n const handoff = store.readHandoff(id);\n if (!dep || !handoff) continue;\n lines.push(`### ${dep.type}`);\n lines.push(`- did: ${handoff.did}`);\n lines.push(`- for you: ${handoff.forNextAgent}`);\n if (handoff.filesTouched?.length) {\n lines.push(`- files: ${handoff.filesTouched.join(', ')}`);\n }\n if (handoff.evidence) {\n lines.push(`- evidence: ${handoff.evidence}`);\n }\n if (handoff.assumptions) {\n lines.push(`- assumed: ${handoff.assumptions}`);\n }\n if (handoff.reportSection) {\n lines.push(`- report section:\\n${handoff.reportSection}`);\n }\n lines.push('');\n }\n if (lines.length === 0) return '';\n return `## Context from previous steps\\n\\n${lines.join('\\n')}`.trim();\n}\n\n/**\n * Resolve a queued task to its run config: the prompt body (with upstream\n * handoffs appended), the model, and the tool lists with orchestrator tool names\n * MCP-qualified. The model precedence is enqueue override, then prompt, then\n * default. Throws if no prompt is registered for the task's type.\n */\nexport function resolveTask(\n registry: AgentRegistry,\n task: QueuedTask,\n store: QueueStore,\n): ResolvedTask {\n const prompt = registry.get(task.type);\n if (!prompt) {\n throw new Error(`No agent prompt registered for task type \"${task.type}\"`);\n }\n\n const body = [\n renderInputs(task),\n prompt.body,\n renderHandoffContext(task, store),\n ]\n .filter(Boolean)\n .join('\\n\\n');\n\n return {\n ...agentRunTools(prompt),\n prompt: body,\n skills: prompt.skills,\n };\n}\n\n/** The model + effort a task runs on for a harness: enqueue override, then the\n * prompt's per-profile frontmatter; the caller's switchboard pick is the fallback. */\nexport function taskModelSpec(\n registry: AgentRegistry,\n task: QueuedTask,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const picked = promptModelFor(\n registry.get(task.type) ?? EMPTY_PROMPT,\n harness,\n );\n return {\n model: task.model ?? picked.model,\n effort: picked.effort,\n };\n}\n\nconst EMPTY_PROMPT = {} as AgentPrompt;\n"],"mappings":";;;;;AAgDA,SAAS,eAAe,KAAwC;AAK9D,QAAO;;;wBAGe,IAAI,UAAU;0BACZ,IAAI,cAAc;kBAC1B,IAAI,KAAK,QAAQ;wEACqC,IAAI,KAAK;;;AAIjF,SAAS,iBAAiB,KAA+C;AACvE,KAAI,CAAC,IAAI,YAAa,QAAO;AAC7B,QAAO,8DAA8D,IAAI,YAAY;;;AAIvF,SAAS,sBAAsB,KAA+C;AAC5E,KAAI,CAAC,IAAI,iBAAkB,QAAO;AAClC,QAAO,iDAAiD,IAAI,iBAAiB;;;;;;;;;;AAW/E,SAAgB,oBAAoB,WAAsC;AACxE,KAAI,UAAU,WAAW,EAAG,QAAO;AACnC,QAAO,6BAA6B,UAAU,KAC5C,KACD,CAAC;;AAGJ,MAAM,cAAc;AAEpB,MAAM,cAAc;;;;;;;;;;;;;AAcpB,SAAS,eACP,OACe;AACf,KAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAO,0WADO,MAAM,KAAK,MAAM,KAAK,EAAE,KAAK,QAAQ,EAAE,GAAG,GAAG,CAC4T,KACrX,KACD;;;;;;;AAQH,SAAS,eAAe,OAAyC;AAC/D,KAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAO,iCADM,MAAM,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,CACP;;;AAI/C,SAAgB,mBACd,KACA,MACA,aAAgC,EAAE,EAC1B;AACR,QAAO;EACL,eAAe,IAAI;EACnB,iBAAiB,IAAI;EACrB,sBAAsB,IAAI;EAC1B,eAAe,WAAW;EAC1B;EACA;EACD,CACE,OAAO,QAAQ,CACf,KAAK,OAAO;;;AAIjB,SAAgB,mBACd,KACA,MACA,YAAqD,EAAE,EAC/C;AACR,QAAO;EAAC,eAAe,IAAI;EAAE;EAAa,eAAe,UAAU;EAAE;EAAK,CACvE,OAAO,QAAQ,CACf,KAAK,OAAO;;;;AAKjB,MAAM,2BAA2B;AACjC,MAAM,qBAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACD,CAAC;;AAGF,MAAa,WAAW;;AAGxB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;;AAU3B,MAAM,uBAAuB;;AAG7B,SAAgB,iBACd,cACS;AACT,SAAQ,gBAAgB,EAAE,EAAE,MACzB,SAAS,SAAA,kBAA6B,SAAS,qBACjD;;;;AAKH,SAAgB,WAAW,iBAA8C;CACvE,MAAM,aAAa,IAAI,IACrB,gBAAgB,KAAK,MAAM,EAAE,QAAQ,0BAA0B,GAAG,CAAC,CACpE;AACD,QAAO,CAAC,GAAG,mBAAmB,CAAC,QAAQ,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;;;AA4ClE,SAAgB,eACd,QACA,SAC4C;CAC5C,MAAM,KAAK,YAAY;AACvB,QAAO;EACL,OAAO,KAAK,OAAO,UAAU,OAAO;EACpC,QAAQ,KAAK,OAAO,WAAW,OAAO;EACvC;;;AAkBH,SAAgB,cACd,SACA,MACA,MAQe;CAIf,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW,EAAE,CAAC;CAC7C,MAAM,SAAS,QACZ,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,SAAS,IAAI,EAAE,KAAK,CAAC,CACvD,KAAK,MAAM;EACV,MAAM,IAAI,MAAM,YAAY,EAAE,OAAO,SAAS,EAAE;AAChD,MAAI,CAAC,EAAG,QAAO;AACf,SAAO;GACL,GAAG;GACH,SAAS,EAAE,SAAS,EAAE;GACtB,UAAU,EAAE,UAAU,EAAE;GACzB;GACD;CACJ,MAAM,SAAS,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CACtD,MAAM,QAAQ,OAAO,QAAQ,MAAM,CAAC,EAAE,KAAK;AAC3C,QAAO;EACL,OAAO,MAAM,KAAK,MAAM,EAAE,KAAK;EAC/B,kBAAkB,MAAM,QAAQ,MAAM,CAAC,EAAE,aAAa,CAAC,KAAK,MAAM,EAAE,KAAK;EACzE,WAAW,MAAM,QAAQ,MAAM,EAAE,KAAK,CAAC,KAAK,MAAM,EAAE,KAAK;EACzD,mBAAmB,MAAM,QAAQ,MAAM,EAAE,aAAa,CAAC,KAAK,MAAM,EAAE,KAAK;EACzE,MAAM,OAAO,MAAM,MAAM,EAAE,KAAK;EAChC,MAAM,SAAS,OAAO,IAAI,KAAK;EAChC;;;AASH,SAAS,eAAe,MAAsB;AAC5C,KAAI,SAAA,aAAmB,QAAO,kBAAkB;AAChD,KAAI,SAAS,gBAAiB,QAAO,kBAAkB;AACvD,KAAI,SAAS,mBAAoB,QAAO,kBAAkB;AAC1D,KAAI,SAAA,eAA2B,QAAO;AACtC,QAAO,mBAAmB,IAAI,KAAK,GAC/B,GAAG,2BAA2B,SAC9B;;;AAIN,SAAgB,cAAc,QAG5B;AACA,QAAO;EACL,cAAc,OAAO,aAAa,IAAI,eAAe;EACrD,iBAAiB,OAAO,gBAAgB,IAAI,eAAe;EAC5D;;AAGH,SAAS,cAAc,OAA0B;AAC/C,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO,EAAE;AACpC,QAAO,MAAM,QAAQ,MAAmB,OAAO,MAAM,SAAS;;;;;;;;;AAUhE,SAAgB,iBACd,MACA,cACA,cACa;CACb,MAAM,QAAQ,KAAK,MAAM,8CAA8C;CACvE,MAAM,cAAc,QAAQ,MAAM,KAAK;CACvC,MAAM,QAAQ,QAAQ,MAAM,KAAK,MAAM,MAAM;CAE7C,MAAM,SAAkC,EAAE;AAC1C,MAAK,MAAM,WAAW,YAAY,MAAM,QAAQ,EAAE;EAChD,MAAM,OAAO,QAAQ,QAAQ,WAAW,GAAG,CAAC,MAAM;AAClD,MAAI,CAAC,QAAQ,KAAK,WAAW,IAAI,CAAE;EACnC,MAAM,KAAK,KAAK,MAAM,qBAAqB;AAC3C,MAAI,CAAC,GAAI;EACT,MAAM,GAAG,KAAK,OAAO;AACrB,MAAI,IAAI,WAAW,IAAI,IAAI,IAAI,SAAS,IAAI,CAC1C,QAAO,OAAO,IACX,MAAM,GAAG,GAAG,CACZ,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,QAAQ,gBAAgB,GAAG,CAAC,CAChD,OAAO,QAAQ;MAElB,QAAO,OAAO,IAAI,QAAQ,gBAAgB,GAAG;;CAIjD,MAAM,OAAO,MAAgB,OAAO,MAAM,WAAW,IAAI,KAAA;CAEzD,MAAM,UAAU,GAAY,QAA2C;AACrE,MAAI,MAAM,KAAA,EAAW,QAAO,KAAA;AAC5B,MAAI,gBAAgB,EAAE,CAAE,QAAO;AAC/B,YACE,kBAAkB,aAAa,qBAAqB,IAAI,IAAI,OAAO,EAAE,CAAC,GACvE;AACD,YAAU,cAAc,+BAA+B;GACrD,WAAW;GACX;GACA,OAAO,OAAO,EAAE;GACjB,CAAC;;AAGJ,QAAO;EACL,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;EACtD,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EACzD,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;EACtD,MAAM,OAAO,SAAS;EACtB,MAAM,OAAO,SAAS;EACtB,cAAc,OAAO,iBAAiB;EACtC,SAAS,IAAI,OAAO,SAAS;EAC7B,UAAU,OAAO,OAAO,WAAW,YAAY;EAC/C,UAAU,IAAI,OAAO,UAAU;EAC/B,WAAW,OAAO,OAAO,YAAY,aAAa;EAClD,QAAQ,cAAc,OAAO,OAAO;EACpC,cAAc,cAAc,OAAO,aAAa;EAChD,iBAAiB,cAAc,OAAO,gBAAgB;EACtD,WAAW,cAAc,OAAO,UAAU;EAC1C;EACD;;AAGH,eAAe,UAAU,KAA8B;AAErD,SADY,MAAM,eAAe,IAAI,EAC1B,MAAM;;;;;;;AAQnB,eAAsB,kBACpB,eACA,MACA,MACwB;CACxB,MAAM,UAAU,MAAM,UAAU,GAAG,cAAc,kBAAkB;CAMnE,MAAM,WALO,KAAK,MAAM,QAAQ,CAKV,UAAU,EAAE,EAAE,QACjC,UAAU,CAAC,MAAM,QAAQ,MAAM,SAAS,KAC1C;AAQD,QAAO,cAPS,MAAM,QAAQ,IAC5B,QAAQ,IAAI,OAAO,UAAU;AAE3B,SAAO,iBADM,MAAM,UAAU,MAAM,YAAY,EACjB,MAAM,IAAI,MAAM,KAAK;GACnD,CACH,EAE6B,MAAM,KAAK;;;;;;AAO3C,SAAS,aAAa,MAA0B;CAC9C,MAAM,UAAU,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;AACjD,KAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAO,yBADO,QAAQ,KAAK,CAAC,GAAG,OAAO,KAAK,EAAE,IAAI,iBAAiB,EAAE,GAAG,CACjC,KAAK,KAAK;;AAGlD,SAAS,iBAAiB,OAAwB;AAChD,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAO,KAAK,UAAU,MAAM;;;;;;;AAQ9B,SAAS,YAAY,MAAkB,OAA6B;CAClE,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,UAAoB,EAAE;CAC5B,MAAM,SAAS,OAAqB;AAClC,MAAI,KAAK,IAAI,GAAG,CAAE;AAClB,OAAK,IAAI,GAAG;EACZ,MAAM,IAAI,MAAM,IAAI,GAAG;AACvB,MAAI,CAAC,EAAG;AACR,OAAK,MAAM,OAAO,EAAE,UAAW,OAAM,IAAI;AACzC,UAAQ,KAAK,GAAG;;AAElB,MAAK,MAAM,OAAO,KAAK,UAAW,OAAM,IAAI;AAC5C,QAAO;;;;;;;;;AAUT,SAAS,qBAAqB,MAAkB,OAA2B;CACzE,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,MAAM,YAAY,MAAM,MAAM,EAAE;EACzC,MAAM,MAAM,MAAM,IAAI,GAAG;EACzB,MAAM,UAAU,MAAM,YAAY,GAAG;AACrC,MAAI,CAAC,OAAO,CAAC,QAAS;AACtB,QAAM,KAAK,OAAO,IAAI,OAAO;AAC7B,QAAM,KAAK,UAAU,QAAQ,MAAM;AACnC,QAAM,KAAK,cAAc,QAAQ,eAAe;AAChD,MAAI,QAAQ,cAAc,OACxB,OAAM,KAAK,YAAY,QAAQ,aAAa,KAAK,KAAK,GAAG;AAE3D,MAAI,QAAQ,SACV,OAAM,KAAK,eAAe,QAAQ,WAAW;AAE/C,MAAI,QAAQ,YACV,OAAM,KAAK,cAAc,QAAQ,cAAc;AAEjD,MAAI,QAAQ,cACV,OAAM,KAAK,sBAAsB,QAAQ,gBAAgB;AAE3D,QAAM,KAAK,GAAG;;AAEhB,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAO,qCAAqC,MAAM,KAAK,KAAK,GAAG,MAAM;;;;;;;;AASvE,SAAgB,YACd,UACA,MACA,OACc;CACd,MAAM,SAAS,SAAS,IAAI,KAAK,KAAK;AACtC,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,6CAA6C,KAAK,KAAK,GAAG;CAG5E,MAAM,OAAO;EACX,aAAa,KAAK;EAClB,OAAO;EACP,qBAAqB,MAAM,MAAM;EAClC,CACE,OAAO,QAAQ,CACf,KAAK,OAAO;AAEf,QAAO;EACL,GAAG,cAAc,OAAO;EACxB,QAAQ;EACR,QAAQ,OAAO;EAChB;;;;AAKH,SAAgB,cACd,UACA,MACA,SAC4C;CAC5C,MAAM,SAAS,eACb,SAAS,IAAI,KAAK,KAAK,IAAI,cAC3B,QACD;AACD,QAAO;EACL,OAAO,KAAK,SAAS,OAAO;EAC5B,QAAQ,OAAO;EAChB;;AAGH,MAAM,eAAe,EAAE"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
2
|
import { a as AGENT_ERROR_CODE, d as ErrorCodes, o as AgentSignals, r as skillErrorCode } from "./errors--OqLxmWR.js";
|
|
3
|
-
import {
|
|
4
|
-
import { o as mayReportScanResults } from "./wizard-session-
|
|
5
|
-
import { a as ciExcludedTaskTypes, n as analytics, r as groupsFromUser } from "./analytics-
|
|
6
|
-
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-
|
|
7
|
-
import { c as OAuthError, s as refreshAccessToken, t as getOrAskForProjectData, u as mcpUrlFor } from "./setup-utils-
|
|
8
|
-
import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-
|
|
9
|
-
import { n as isNonInteractiveEnvironment } from "./environment-
|
|
10
|
-
import {
|
|
11
|
-
import { a as detectNodePackageManagers } from "./package-manager-
|
|
12
|
-
import { t as FRAMEWORK_REGISTRY } from "./registry-
|
|
13
|
-
import {
|
|
14
|
-
import { _ as
|
|
15
|
-
import {
|
|
16
|
-
import { a as
|
|
3
|
+
import { A as DEFAULT_AGENT_MODEL, F as GPT5_6_SOL_MODEL, I as GPT5_6_TERRA_MODEL, L as HAIKU_MODEL, P as GPT5_6_LUNA_MODEL, V as Integration, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, c as WIZARD_BENCHMARK_FILE, ct as WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY, et as SONNET_5_MODEL, ft as WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY, g as SERVICE_LABELS, gt as VERSION, i as enableDebugLogs, j as DETECTION_TIMEOUT_MS, l as WIZARD_LOG_FILE, lt as WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY, mt as getSkillsBaseUrl, o as initLogFile, p as getUI, rt as WIZARD_CONTACT_EMAIL, s as logToFile, st as WIZARD_ORCHESTRATOR_FLAG_KEY, t as configureLogFile, tt as Sequence, v as evaluateWizardReadiness, vt as RUN_SURFACE, xt as runtimeEnv, y as getBlockingServiceKeys, z as Harness } from "./debug-C5Zz8hmm.js";
|
|
4
|
+
import { o as mayReportScanResults } from "./wizard-session-FSJCkTcP.js";
|
|
5
|
+
import { a as ciExcludedTaskTypes, n as analytics, r as groupsFromUser } from "./analytics-C_RyE8fz.js";
|
|
6
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-BHLy83N9.js";
|
|
7
|
+
import { c as OAuthError, s as refreshAccessToken, t as getOrAskForProjectData, u as mcpUrlFor } from "./setup-utils-BUAoRjw3.js";
|
|
8
|
+
import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-BCnUgT9z.js";
|
|
9
|
+
import { n as isNonInteractiveEnvironment } from "./environment-B0uTamFf.js";
|
|
10
|
+
import { G as fetchSkillMenu, K as installSkillById, at as createWizardAskBridge, c as checkAllSettingsConflicts, ct as isEnvFileName, d as restoreClaudeSettings, dt as markGrantRevoked, h as createTriageLLMProvider, i as runAgent$1, it as LONGER_ASK_TIMEOUT_MS, l as classifySettingsConflicts, lt as parseEnvKeyNames, n as buildRunTags, r as initializeAgent, s as backupAndFixClaudeSettings, st as MAX_ENV_KEY_SET, ut as toPromptSafeRelativePath } from "./agent-interface-CZWRgZMc.js";
|
|
11
|
+
import { a as detectNodePackageManagers } from "./package-manager-CppzeIgu.js";
|
|
12
|
+
import { t as FRAMEWORK_REGISTRY } from "./registry-COcpEsMD.js";
|
|
13
|
+
import { o as gatewayAuth } from "./gateway-session-C3Uqwc4R.js";
|
|
14
|
+
import { _ as AUDIT_CHECKS_KEY, a as flushScanReport, b as coerceAuditChecks, m as writeScanReport, o as formatScanReport, s as formatYaraAbortMessage } from "./yara-hooks-BJWVgTpU.js";
|
|
15
|
+
import { b as requireKnownModel, d as uncoveredBySink, g as TaskStatus, h as SkipReason, m as QueueStore, p as QUEUE_DIR_NAME, u as dependencyClosure, v as isValidModel } from "./queue-tools-D09PNS0X.js";
|
|
16
|
+
import { a as piBackend, c as createAioCapture } from "./pi-Bs1Tbt0C.js";
|
|
17
|
+
import { a as assembleTaskPrompt, d as taskModelSpec, i as assembleSeedPrompt, n as agentRunTools, o as loadAgentRegistry, s as promptModelFor, t as ASK_TOOL, u as resolveTask } from "./agent-prompt-loader-BobuLDIg.js";
|
|
18
|
+
import { t as startFileWatcher } from "./file-watcher-CiT-oZpu.js";
|
|
17
19
|
import * as semver from "semver";
|
|
18
20
|
import fs, { cpSync, existsSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
|
19
21
|
import * as path$1 from "path";
|
|
20
|
-
import path, { isAbsolute, join, resolve, sep } from "path";
|
|
22
|
+
import path, { isAbsolute, join, relative, resolve, sep } from "path";
|
|
21
23
|
import { z } from "zod";
|
|
22
24
|
import { randomUUID } from "crypto";
|
|
23
25
|
//#region src/lib/agent/runner/shared/authenticate.ts
|
|
@@ -3109,6 +3111,46 @@ function detectWarehousePrerequisites(session, setFrameworkContext) {
|
|
|
3109
3111
|
setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);
|
|
3110
3112
|
}
|
|
3111
3113
|
//#endregion
|
|
3114
|
+
//#region src/lib/programs/shared/package-scanning.ts
|
|
3115
|
+
const POSTHOG_SDKS = new Set([
|
|
3116
|
+
"posthog-js",
|
|
3117
|
+
"posthog-node",
|
|
3118
|
+
"posthog-react-native",
|
|
3119
|
+
"posthog-android",
|
|
3120
|
+
"posthog-ios"
|
|
3121
|
+
]);
|
|
3122
|
+
const STRIPE_SDKS = new Set([
|
|
3123
|
+
"stripe",
|
|
3124
|
+
"@stripe/stripe-js",
|
|
3125
|
+
"@stripe/react-stripe-js"
|
|
3126
|
+
]);
|
|
3127
|
+
const MAX_PACKAGE_MATCHES = 500;
|
|
3128
|
+
/**
|
|
3129
|
+
* Find all package.json files under installDir via the shared bounded walk
|
|
3130
|
+
* (depth cap, ignored dirs, symlink-loop protection, per-dir entry cap).
|
|
3131
|
+
* Returns matches with detected SDKs.
|
|
3132
|
+
*/
|
|
3133
|
+
function findPackageJsons(installDir, maxDepth = 3) {
|
|
3134
|
+
const matches = [];
|
|
3135
|
+
walkProjectFiles(installDir, (name, fullPath) => {
|
|
3136
|
+
if (name !== "package.json" || matches.length >= MAX_PACKAGE_MATCHES) return;
|
|
3137
|
+
const content = safeReadFile(fullPath);
|
|
3138
|
+
if (content === null) return;
|
|
3139
|
+
try {
|
|
3140
|
+
const pkg = JSON.parse(content);
|
|
3141
|
+
const depNames = [...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})];
|
|
3142
|
+
const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.has(d));
|
|
3143
|
+
const stripeSdks = depNames.filter((d) => STRIPE_SDKS.has(d));
|
|
3144
|
+
matches.push({
|
|
3145
|
+
path: relative(installDir, fullPath) || "package.json",
|
|
3146
|
+
posthogSdks,
|
|
3147
|
+
stripeSdks
|
|
3148
|
+
});
|
|
3149
|
+
} catch {}
|
|
3150
|
+
}, maxDepth);
|
|
3151
|
+
return matches;
|
|
3152
|
+
}
|
|
3153
|
+
//#endregion
|
|
3112
3154
|
//#region src/lib/programs/posthog-integration/detect.ts
|
|
3113
3155
|
async function detectPostHogIntegration(ctx) {
|
|
3114
3156
|
const session = ctx.session;
|
|
@@ -3134,6 +3176,7 @@ async function detectPostHogIntegration(ctx) {
|
|
|
3134
3176
|
}
|
|
3135
3177
|
for (const feature of discoverFeatures(installDir)) ctx.addDiscoveredFeature(feature);
|
|
3136
3178
|
detectWarehouseSourcesForSuggestion(ctx, installDir);
|
|
3179
|
+
detectExistingPostHog(ctx, installDir);
|
|
3137
3180
|
ctx.setDetectionComplete();
|
|
3138
3181
|
}
|
|
3139
3182
|
/**
|
|
@@ -3239,6 +3282,16 @@ function reportWarehouseSourcesDetected(session) {
|
|
|
3239
3282
|
}
|
|
3240
3283
|
return true;
|
|
3241
3284
|
}
|
|
3285
|
+
/** Dependency-level signal, not a verified install. A failed scan reports false. */
|
|
3286
|
+
function detectExistingPostHog(ctx, installDir) {
|
|
3287
|
+
try {
|
|
3288
|
+
const pkgJsons = findPackageJsons(installDir);
|
|
3289
|
+
ctx.setPosthogSdkDetected(pkgJsons.some((p) => p.posthogSdks.length > 0));
|
|
3290
|
+
} catch (error) {
|
|
3291
|
+
analytics.captureException(error instanceof Error ? error : new Error(String(error)), { step: "detectExistingPosthog" });
|
|
3292
|
+
ctx.setPosthogSdkDetected(false);
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3242
3295
|
//#endregion
|
|
3243
3296
|
//#region src/lib/agent/runner/harness/anthropic/index.ts
|
|
3244
3297
|
const anthropicBackend = {
|
|
@@ -5035,15 +5088,9 @@ function resolveReferenceSkillId(entries, framework) {
|
|
|
5035
5088
|
return resolveSkillVariantId(entries, "integration", framework);
|
|
5036
5089
|
}
|
|
5037
5090
|
/**
|
|
5038
|
-
* A task that asks the user waits on a person, not on a model: long enough to
|
|
5039
|
-
* open a database console or mint a restricted API key. The drain waits it out
|
|
5040
|
-
* — the executor holds the task's promise — so the only real limit is this one.
|
|
5041
|
-
*/
|
|
5042
|
-
const TASK_ASK_TIMEOUT_MS = 1200 * 1e3;
|
|
5043
|
-
/**
|
|
5044
5091
|
* How long an optional step's notice waits for an answer.
|
|
5045
5092
|
*
|
|
5046
|
-
* Much shorter than
|
|
5093
|
+
* Much shorter than LONGER_ASK_TIMEOUT_MS, because it is asking for something
|
|
5047
5094
|
* much smaller: one keypress to accept or decline, not "go mint a restricted
|
|
5048
5095
|
* Stripe key". It cannot be unbounded either — the notice is a modal, and a run
|
|
5049
5096
|
* that stops forever behind one nobody is looking at is worse than one that
|
|
@@ -5061,7 +5108,7 @@ const TASK_NOTICE_TIMEOUT_MS = 300 * 1e3;
|
|
|
5061
5108
|
*
|
|
5062
5109
|
* Skip is the right default on a timeout: continuing would send the step on to
|
|
5063
5110
|
* ask for credentials that the same absent user cannot supply either, burning
|
|
5064
|
-
* {@link
|
|
5111
|
+
* {@link LONGER_ASK_TIMEOUT_MS} per question before falling back to the same
|
|
5065
5112
|
* links declining gives immediately.
|
|
5066
5113
|
*/
|
|
5067
5114
|
async function offerSeededTask(notice, timeoutMs = TASK_NOTICE_TIMEOUT_MS) {
|
|
@@ -5083,12 +5130,61 @@ async function offerSeededTask(notice, timeoutMs = TASK_NOTICE_TIMEOUT_MS) {
|
|
|
5083
5130
|
if (timer) clearTimeout(timer);
|
|
5084
5131
|
}
|
|
5085
5132
|
}
|
|
5133
|
+
/**
|
|
5134
|
+
* Which runner-seeded task types finished successfully.
|
|
5135
|
+
*
|
|
5136
|
+
* Handed to the program's `buildOutroNextSteps` so it can drop a next step its
|
|
5137
|
+
* own seeded task already carried out. Only `Done` counts: a skipped, declined
|
|
5138
|
+
* or failed step left the work undone, and that is exactly when the outro
|
|
5139
|
+
* bullet pointing at the app is the one thing the user still needs.
|
|
5140
|
+
*/
|
|
5141
|
+
function completedSeededTypes(store, seededTasks) {
|
|
5142
|
+
return seededTasks.filter((task) => store.get(task.id)?.status === TaskStatus.Done).map((task) => task.type);
|
|
5143
|
+
}
|
|
5086
5144
|
/** Which skip reason a negative {@link SeededConsent} carries onto the event. */
|
|
5087
5145
|
function consentSkipReason(consent) {
|
|
5088
5146
|
if (consent.errored) return SkipReason.NoticeError;
|
|
5089
5147
|
return consent.timedOut ? SkipReason.NoticeTimeout : SkipReason.UserDeclined;
|
|
5090
5148
|
}
|
|
5091
5149
|
/**
|
|
5150
|
+
* Apply the seed-time answers to the queue, before the drain starts.
|
|
5151
|
+
*
|
|
5152
|
+
* A declined task is skipped rather than dropped, so the graph the planner saw
|
|
5153
|
+
* is the graph that ran — the sink already depends on this task, and
|
|
5154
|
+
* `nextRunnable` treats a skipped dependency as satisfied, so the report still
|
|
5155
|
+
* runs and can say the step was declined. The decline also stays in the funnel,
|
|
5156
|
+
* arriving as a `skipped` event carrying the reason that caused it rather than
|
|
5157
|
+
* as a task that silently never existed.
|
|
5158
|
+
*
|
|
5159
|
+
* It happens here rather than inside `runTask` because the executor marks a
|
|
5160
|
+
* task running — and fires `orchestrator task started` — before it hands the
|
|
5161
|
+
* task over. A decline applied on the far side of that emitted a start for a
|
|
5162
|
+
* task no agent ever ran, so every rate measured against starts counted the
|
|
5163
|
+
* declines twice: once in the denominator as a task that began, and again in
|
|
5164
|
+
* the numerator as a task that was skipped. Nothing upstream of the drain reads
|
|
5165
|
+
* task status, so applying the answers here changes only what the drain sees.
|
|
5166
|
+
*
|
|
5167
|
+
* Returns how many tasks were skipped, so the caller can redraw once.
|
|
5168
|
+
*/
|
|
5169
|
+
function skipDeclinedSeededTasks(store, consentByTaskId, labelFor) {
|
|
5170
|
+
let skipped = 0;
|
|
5171
|
+
for (const [taskId, consent] of consentByTaskId) {
|
|
5172
|
+
if (consent.keep) continue;
|
|
5173
|
+
const task = store.get(taskId);
|
|
5174
|
+
if (!task) continue;
|
|
5175
|
+
const reason = consentSkipReason(consent);
|
|
5176
|
+
logToFile(`[orchestrator] runner-seeded ${task.type} skipped: ${reason}`);
|
|
5177
|
+
const declinedByUser = reason === SkipReason.UserDeclined;
|
|
5178
|
+
store.skip(taskId, reason, {
|
|
5179
|
+
goals: labelFor(task),
|
|
5180
|
+
did: declinedByUser ? "Nothing — the user chose to skip this step when offered it." : "Nothing — the step was offered at the start of the run and never accepted.",
|
|
5181
|
+
forNextAgent: declinedByUser ? "This step was offered and declined, so it did no work. Report it as skipped at the user’s request, not as failed." : "This step was offered and never accepted, so it did no work. Report it as not set up, and point the user at how to do it later."
|
|
5182
|
+
});
|
|
5183
|
+
skipped += 1;
|
|
5184
|
+
}
|
|
5185
|
+
return skipped;
|
|
5186
|
+
}
|
|
5187
|
+
/**
|
|
5092
5188
|
* Ask for one seeded task's consent, and record how the answer came about.
|
|
5093
5189
|
*
|
|
5094
5190
|
* Consent and execution are separate concerns, and this is the consent half.
|
|
@@ -5338,7 +5434,7 @@ or integrate manually here:
|
|
|
5338
5434
|
analytics.setTag("orchestrator_runner_seeded_types", seededTypes.join(",") || "none");
|
|
5339
5435
|
if (askingTypes.length > 0) analytics.wizardCapture("orchestrator awaits user", {
|
|
5340
5436
|
task_types: askingTypes,
|
|
5341
|
-
ask_timeout_ms:
|
|
5437
|
+
ask_timeout_ms: LONGER_ASK_TIMEOUT_MS
|
|
5342
5438
|
});
|
|
5343
5439
|
const askBridge = shouldDisableAsk(session) ? void 0 : createWizardAskBridge({
|
|
5344
5440
|
getSource: () => session.skillId ?? programConfig.id,
|
|
@@ -5349,7 +5445,7 @@ or integrate manually here:
|
|
|
5349
5445
|
},
|
|
5350
5446
|
cancelQuestion: () => getUI().cancelPendingQuestion(),
|
|
5351
5447
|
richLinks: config.richLinks ?? false,
|
|
5352
|
-
timeoutMs:
|
|
5448
|
+
timeoutMs: LONGER_ASK_TIMEOUT_MS
|
|
5353
5449
|
});
|
|
5354
5450
|
const spinner = getUI().spinner();
|
|
5355
5451
|
const seedPick = resolveHarness(switchboardCtx, "seed");
|
|
@@ -5426,19 +5522,6 @@ or integrate manually here:
|
|
|
5426
5522
|
const preexistingSkills = new Set(existsSync(claudeSkillsDir) ? readdirSync(claudeSkillsDir) : []);
|
|
5427
5523
|
const runTask = async (task) => {
|
|
5428
5524
|
renderQueue();
|
|
5429
|
-
const consent = seededConsent.get(task.id);
|
|
5430
|
-
if (consent && !consent.keep) {
|
|
5431
|
-
const reason = consentSkipReason(consent);
|
|
5432
|
-
logToFile(`[orchestrator] runner-seeded ${task.type} skipped: ${reason}`);
|
|
5433
|
-
const declinedByUser = reason === SkipReason.UserDeclined;
|
|
5434
|
-
store.skip(task.id, reason, {
|
|
5435
|
-
goals: labelFor(task),
|
|
5436
|
-
did: declinedByUser ? "Nothing — the user chose to skip this step when offered it." : "Nothing — the step was offered at the start of the run and never accepted.",
|
|
5437
|
-
forNextAgent: declinedByUser ? "This step was offered and declined, so it did no work. Report it as skipped at the user’s request, not as failed." : "This step was offered and never accepted, so it did no work. Report it as not set up, and point the user at how to do it later."
|
|
5438
|
-
});
|
|
5439
|
-
renderQueue();
|
|
5440
|
-
return;
|
|
5441
|
-
}
|
|
5442
5525
|
try {
|
|
5443
5526
|
const resolved = resolveTask(registry, task, store);
|
|
5444
5527
|
const skillPaths = [];
|
|
@@ -5492,6 +5575,7 @@ or integrate manually here:
|
|
|
5492
5575
|
renderQueue();
|
|
5493
5576
|
}
|
|
5494
5577
|
};
|
|
5578
|
+
if (skipDeclinedSeededTasks(store, seededConsent, labelFor) > 0) renderQueue();
|
|
5495
5579
|
try {
|
|
5496
5580
|
await drainQueue(store, runTask);
|
|
5497
5581
|
} finally {
|
|
@@ -5561,7 +5645,8 @@ or integrate manually here:
|
|
|
5561
5645
|
kind: "success",
|
|
5562
5646
|
message,
|
|
5563
5647
|
body: conflict ? `⚠ Build conflict: ${conflict}\nFull details are in the setup report.` : void 0,
|
|
5564
|
-
docsUrl: "https://posthog.com/docs/ai-engineering/ai-wizard"
|
|
5648
|
+
docsUrl: "https://posthog.com/docs/ai-engineering/ai-wizard",
|
|
5649
|
+
nextSteps: config.buildOutroNextSteps?.(session, boot.credentials, completedSeededTypes(store, seededTasks))
|
|
5565
5650
|
});
|
|
5566
5651
|
getUI().outro(message);
|
|
5567
5652
|
await analytics.shutdown("success");
|
|
@@ -5707,10 +5792,16 @@ const PROGRAM_BINDINGS = {
|
|
|
5707
5792
|
harness: "anthropic",
|
|
5708
5793
|
model: DEFAULT_AGENT_MODEL
|
|
5709
5794
|
},
|
|
5795
|
+
"error-tracking": {
|
|
5796
|
+
sequence: "orchestrator",
|
|
5797
|
+
harness: "pi",
|
|
5798
|
+
model: DEFAULT_AGENT_MODEL
|
|
5799
|
+
},
|
|
5710
5800
|
"ai-observability": {
|
|
5711
5801
|
sequence: "linear",
|
|
5712
|
-
harness: "
|
|
5713
|
-
model:
|
|
5802
|
+
harness: "pi",
|
|
5803
|
+
model: GPT5_6_TERRA_MODEL,
|
|
5804
|
+
thinkingLevel: "high"
|
|
5714
5805
|
},
|
|
5715
5806
|
slack: DEFAULT_BINDING
|
|
5716
5807
|
};
|
|
@@ -5871,7 +5962,6 @@ async function bootstrapProgram(session, config, programConfig) {
|
|
|
5871
5962
|
baseURL: auth.gatewayUrl,
|
|
5872
5963
|
authToken: auth.token,
|
|
5873
5964
|
teamId: auth.teamId,
|
|
5874
|
-
legacy: auth.legacy,
|
|
5875
5965
|
wizardMetadata: {
|
|
5876
5966
|
...wizardMetadata,
|
|
5877
5967
|
call_type: "yara-triage"
|
|
@@ -5888,6 +5978,23 @@ async function bootstrapProgram(session, config, programConfig) {
|
|
|
5888
5978
|
};
|
|
5889
5979
|
}
|
|
5890
5980
|
//#endregion
|
|
5981
|
+
//#region src/lib/programs/audit/ledger-watcher.ts
|
|
5982
|
+
/**
|
|
5983
|
+
* Mirrors the agent's `.posthog-audit-checks.json` into the session, so the TUI
|
|
5984
|
+
* screens and the task stream read one value. `runAgent` owns the lifecycle, so
|
|
5985
|
+
* every path gets it — including the e2e host, which builds no task stream.
|
|
5986
|
+
*/
|
|
5987
|
+
const MAX_LEDGER_FILE_BYTES = 256 * 1024;
|
|
5988
|
+
function startAuditLedgerWatcher(installDir, file, options = {}) {
|
|
5989
|
+
const target = path.join(installDir, file);
|
|
5990
|
+
logToFile(`[audit-ledger] watching ${target}`);
|
|
5991
|
+
return startFileWatcher(target, (parsed) => getUI().setFrameworkContext(AUDIT_CHECKS_KEY, coerceAuditChecks(parsed)), {
|
|
5992
|
+
ignoreInitialFile: true,
|
|
5993
|
+
maxFileSizeBytes: MAX_LEDGER_FILE_BYTES,
|
|
5994
|
+
...options
|
|
5995
|
+
});
|
|
5996
|
+
}
|
|
5997
|
+
//#endregion
|
|
5891
5998
|
//#region src/lib/agent/runner/index.ts
|
|
5892
5999
|
/**
|
|
5893
6000
|
* Resolve a ProgramConfig's agent run definition and execute the pipeline.
|
|
@@ -5895,7 +6002,13 @@ async function bootstrapProgram(session, config, programConfig) {
|
|
|
5895
6002
|
*/
|
|
5896
6003
|
async function runAgent(programConfig, session, options = {}) {
|
|
5897
6004
|
if (!programConfig.run) throw new Error(`Program "${programConfig.id}" has no run configuration.`);
|
|
5898
|
-
|
|
6005
|
+
const ledger = programConfig.auditLedgerFile ? startAuditLedgerWatcher(session.installDir, programConfig.auditLedgerFile) : null;
|
|
6006
|
+
if (ledger) registerCleanup(() => ledger.stop());
|
|
6007
|
+
try {
|
|
6008
|
+
await runProgram(session, typeof programConfig.run === "function" ? await programConfig.run(session) : programConfig.run, programConfig, options);
|
|
6009
|
+
} finally {
|
|
6010
|
+
ledger?.stop();
|
|
6011
|
+
}
|
|
5899
6012
|
}
|
|
5900
6013
|
/**
|
|
5901
6014
|
* Run a program's agent pipeline.
|
|
@@ -5982,6 +6095,6 @@ function tagBinding(boot, binding) {
|
|
|
5982
6095
|
//#region src/lib/agent/agent-runner.ts
|
|
5983
6096
|
var agent_runner_exports = /* @__PURE__ */ __exportAll({ runAgent: () => runAgent });
|
|
5984
6097
|
//#endregion
|
|
5985
|
-
export {
|
|
6098
|
+
export { detectProjectsWithAgent as _, formatCostUsd as a, detectFramework as b, maybeStampAiSdkDetected as c, STRIPE_SDKS as d, findPackageJsons as f, detectWarehouseSources as g, getDetectedWarehouseSources as h, computeTokenCostUsd as i, reportWarehouseSourcesDetected as l, detectWarehousePrerequisites as m, runAgent as n, formatTokenCount as o, WAREHOUSE_ABORT_CASES as p, shouldDisableAsk as r, detectPostHogIntegration as s, agent_runner_exports as t, POSTHOG_SDKS as u, resolveProjectDir as v, authenticate as x, gatherFrameworkContext as y };
|
|
5986
6099
|
|
|
5987
|
-
//# sourceMappingURL=agent-runner-
|
|
6100
|
+
//# sourceMappingURL=agent-runner-C_R1X_UT.js.map
|