@posthog/wizard 2.13.0 → 2.14.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/LICENSE +0 -26
- package/README.md +1 -1
- package/dist/TextBlock-B3cm43YY.js +244 -0
- package/dist/TextBlock-B3cm43YY.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-CUNR00bB.js → add-mcp-server-to-clients-BTW9Ey5Z.js} +7 -7
- package/dist/{add-mcp-server-to-clients-CUNR00bB.js.map → add-mcp-server-to-clients-BTW9Ey5Z.js.map} +1 -1
- package/dist/{agent-interface-CV0-vtxj.js → agent-interface-gP4pkZgS.js} +534 -256
- package/dist/agent-interface-gP4pkZgS.js.map +1 -0
- package/dist/{agent-runner-LvVQH31D.js → agent-runner-Bxi71jnp.js} +102 -20
- package/dist/agent-runner-Bxi71jnp.js.map +1 -0
- package/dist/{analytics-VM7laaFx.js → analytics-Dmnxu2zE.js} +2 -2
- package/dist/{analytics-VM7laaFx.js.map → analytics-Dmnxu2zE.js.map} +1 -1
- package/dist/analytics-tslsXyf9.js +2 -0
- package/dist/bin.js +951 -141
- package/dist/bin.js.map +1 -1
- package/dist/{debug-Cqi6nVfX.js → debug-CYUB-urp.js} +26 -21
- package/dist/debug-CYUB-urp.js.map +1 -0
- package/dist/{debug-BdcTB7EF.js → debug-Du7qXlug.js} +1 -1
- package/dist/{defaults-GbLPuHxj.js → defaults-DgKAzsD1.js} +1 -1
- package/dist/{defaults-GbLPuHxj.js.map → defaults-DgKAzsD1.js.map} +1 -1
- package/dist/{detection-CSjmal-X.js → detection-D651Eb5k.js} +4 -4
- package/dist/detection-D651Eb5k.js.map +1 -0
- package/dist/{file-8iNrXHkG.js → file-BKbKreWF.js} +1 -1
- package/dist/{file-8iNrXHkG.js.map → file-BKbKreWF.js.map} +1 -1
- package/dist/{file-utils-DnTSiTJw.js → file-utils-DPmgn9Vm.js} +1 -1
- package/dist/{file-utils-DnTSiTJw.js.map → file-utils-DPmgn9Vm.js.map} +1 -1
- package/dist/{package-json-F_7oktsp.js → package-json-DZpnf6vU.js} +8 -10
- package/dist/package-json-DZpnf6vU.js.map +1 -0
- package/dist/package-json-_4PEss19.js +2 -0
- package/dist/{package-manager-CD8RQW-e.js → package-manager-liwrN_aI.js} +2 -2
- package/dist/{package-manager-CD8RQW-e.js.map → package-manager-liwrN_aI.js.map} +1 -1
- package/dist/{posthog-vm0k9PKS.js → posthog-BbQf_Hzq.js} +1 -1
- package/dist/{posthog-vm0k9PKS.js.map → posthog-BbQf_Hzq.js.map} +1 -1
- package/dist/posthog-integration-C-FFV5ny.js +1012 -0
- package/dist/posthog-integration-C-FFV5ny.js.map +1 -0
- package/dist/provisioning-ByWo5KcQ.js +2 -0
- package/dist/{provisioning-g9aoVIEd.js → provisioning-C4nHkz-O.js} +3 -3
- package/dist/{provisioning-g9aoVIEd.js.map → provisioning-C4nHkz-O.js.map} +1 -1
- package/dist/{registry-BaMEaAKd.js → registry-B92uyoWK.js} +5 -5
- package/dist/{registry-BaMEaAKd.js.map → registry-B92uyoWK.js.map} +1 -1
- package/dist/setup-utils-D5aNKrba.js +2 -0
- package/dist/{setup-utils-CNV7FSlY.js → setup-utils-LvtZIY18.js} +77 -107
- package/dist/setup-utils-LvtZIY18.js.map +1 -0
- package/dist/{AuditChecksViewer-B0J7zcY2.js → slides-yyC_W0RZ.js} +626 -1058
- package/dist/slides-yyC_W0RZ.js.map +1 -0
- package/dist/smoke-test-ci.sh +4 -4
- package/dist/{start-playground-C9GWnVdM.js → start-playground-BhwBUq-a.js} +259 -10
- package/dist/start-playground-BhwBUq-a.js.map +1 -0
- package/dist/{start-tui-B_zwutLe.js → start-tui-BwQa3kmG.js} +288 -446
- package/dist/start-tui-BwQa3kmG.js.map +1 -0
- package/dist/{steps-Dawz7k3T.js → steps-CGpfOAcr.js} +7 -7
- package/dist/{steps-Dawz7k3T.js.map → steps-CGpfOAcr.js.map} +1 -1
- package/dist/{task-stream-CX7Uf6EM.js → task-stream-DUpUZmFQ.js} +8 -8
- package/dist/task-stream-DUpUZmFQ.js.map +1 -0
- package/dist/telemetry-Fmdx1AYv.js +13 -0
- package/dist/telemetry-Fmdx1AYv.js.map +1 -0
- package/dist/{wizard-abort-Dl0BkqhT.js → wizard-abort-BTBccRto.js} +1 -1
- package/dist/{wizard-abort-CJkNkSjT.js → wizard-abort-D-t5yDkY.js} +3 -3
- package/dist/{wizard-abort-CJkNkSjT.js.map → wizard-abort-D-t5yDkY.js.map} +1 -1
- package/dist/wizard-session-CPhhll4P.js +2 -0
- package/dist/{wizard-session-BcNJTl2I.js → wizard-session-CsI33S4_.js} +6 -3
- package/dist/wizard-session-CsI33S4_.js.map +1 -0
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +3 -2
- package/dist/AuditChecksViewer-B0J7zcY2.js.map +0 -1
- package/dist/agent-interface-CV0-vtxj.js.map +0 -1
- package/dist/agent-runner-LvVQH31D.js.map +0 -1
- package/dist/analytics-BH7bEHQR.js +0 -2
- package/dist/debug-Cqi6nVfX.js.map +0 -1
- package/dist/detection-CSjmal-X.js.map +0 -1
- package/dist/package-json-BzVey4Bd.js +0 -2
- package/dist/package-json-F_7oktsp.js.map +0 -1
- package/dist/posthog-integration-BL21S3T6.js +0 -259
- package/dist/posthog-integration-BL21S3T6.js.map +0 -1
- package/dist/provisioning-BdQ1ONIg.js +0 -2
- package/dist/router-COhhuIW3.js +0 -135
- package/dist/router-COhhuIW3.js.map +0 -1
- package/dist/setup-utils-CNV7FSlY.js.map +0 -1
- package/dist/setup-utils-CU4FIqjB.js +0 -2
- package/dist/start-playground-C9GWnVdM.js.map +0 -1
- package/dist/start-tui-B_zwutLe.js.map +0 -1
- package/dist/task-stream-CX7Uf6EM.js.map +0 -1
- package/dist/telemetry-D6bjWA-A.js +0 -13
- package/dist/telemetry-D6bjWA-A.js.map +0 -1
- package/dist/wizard-session-BQC9vy9Z.js +0 -2
- package/dist/wizard-session-BcNJTl2I.js.map +0 -1
|
@@ -1,181 +1,17 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { A as POSTHOG_PROPERTY_HEADER_PREFIX, B as WIZARD_VARIANTS, L as WIZARD_REMARK_EVENT_NAME, O as POSTHOG_FLAG_HEADER_PREFIX, V as WIZARD_VARIANT_FLAG_KEY, a as getLogFilePath, c as getUI, o as initLogFile, r as debug, s as logToFile, z as WIZARD_USER_AGENT } from "./debug-
|
|
2
|
+
import { A as POSTHOG_PROPERTY_HEADER_PREFIX, B as WIZARD_VARIANTS, L as WIZARD_REMARK_EVENT_NAME, O as POSTHOG_FLAG_HEADER_PREFIX, V as WIZARD_VARIANT_FLAG_KEY, a as getLogFilePath, c as getUI, o as initLogFile, r as debug, s as logToFile, z as WIZARD_USER_AGENT } from "./debug-CYUB-urp.js";
|
|
3
3
|
import { i as WIZARD_YARA_REPORT_FILE, o as skillTmpPath } from "./paths-DJS47p5x.js";
|
|
4
|
-
import { n as analytics } from "./analytics-
|
|
5
|
-
import { f as getLlmGatewayUrlFromHost } from "./setup-utils-
|
|
6
|
-
import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-
|
|
7
|
-
import { n as registerCleanup, r as wizardAbort, t as WizardError } from "./wizard-abort-
|
|
4
|
+
import { n as analytics } from "./analytics-Dmnxu2zE.js";
|
|
5
|
+
import { f as getLlmGatewayUrlFromHost } from "./setup-utils-LvtZIY18.js";
|
|
6
|
+
import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-CsI33S4_.js";
|
|
7
|
+
import { n as registerCleanup, r as wizardAbort, t as WizardError } from "./wizard-abort-D-t5yDkY.js";
|
|
8
8
|
import * as fs$1 from "fs";
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import fg from "fast-glob";
|
|
13
13
|
import { execFileSync } from "child_process";
|
|
14
|
-
//#region src/
|
|
15
|
-
/**
|
|
16
|
-
* Builds a list of custom headers for ANTHROPIC_CUSTOM_HEADERS.
|
|
17
|
-
*/
|
|
18
|
-
function createCustomHeaders() {
|
|
19
|
-
const entries = [];
|
|
20
|
-
return {
|
|
21
|
-
add(key, value) {
|
|
22
|
-
const name = key.startsWith("x-") || key.startsWith("X-") ? key : `X-${key}`;
|
|
23
|
-
entries.push({
|
|
24
|
-
key: name,
|
|
25
|
-
value
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
addFlag(flagKey, variant) {
|
|
29
|
-
const headerName = POSTHOG_FLAG_HEADER_PREFIX + flagKey.toUpperCase();
|
|
30
|
-
entries.push({
|
|
31
|
-
key: headerName,
|
|
32
|
-
value: variant
|
|
33
|
-
});
|
|
34
|
-
},
|
|
35
|
-
encode() {
|
|
36
|
-
return entries.map(({ key, value }) => `${key}: ${value}`).join("\n");
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/lib/safe-tools.ts
|
|
42
|
-
const LINTING_TOOLS = [
|
|
43
|
-
"codespell",
|
|
44
|
-
"cspell",
|
|
45
|
-
"git-diff-check",
|
|
46
|
-
"gitleaks",
|
|
47
|
-
"trufflehog",
|
|
48
|
-
"asl-validator",
|
|
49
|
-
"ansible-lint",
|
|
50
|
-
"pmd",
|
|
51
|
-
"biome",
|
|
52
|
-
"cfn-lint",
|
|
53
|
-
"cfnlint",
|
|
54
|
-
"checkov",
|
|
55
|
-
"trivy",
|
|
56
|
-
"test-aztemplate",
|
|
57
|
-
"shellcheck",
|
|
58
|
-
"shfmt",
|
|
59
|
-
"buildifier",
|
|
60
|
-
"cpplint",
|
|
61
|
-
"clang-format",
|
|
62
|
-
"clang-tidy",
|
|
63
|
-
"cmake-format",
|
|
64
|
-
"iwyu",
|
|
65
|
-
"pragma-once",
|
|
66
|
-
"dotnet-format",
|
|
67
|
-
"circleci",
|
|
68
|
-
"clj-kondo",
|
|
69
|
-
"coffeelint",
|
|
70
|
-
"commitlint",
|
|
71
|
-
"jscpd",
|
|
72
|
-
"stylelint",
|
|
73
|
-
"prettier",
|
|
74
|
-
"cue-fmt",
|
|
75
|
-
"dart",
|
|
76
|
-
"hadolint",
|
|
77
|
-
"dotenv-linter",
|
|
78
|
-
"editorconfig-checker",
|
|
79
|
-
"actionlint",
|
|
80
|
-
"zizmor",
|
|
81
|
-
"gofmt",
|
|
82
|
-
"gofumpt",
|
|
83
|
-
"goimports",
|
|
84
|
-
"gokart",
|
|
85
|
-
"golangci-lint",
|
|
86
|
-
"golines",
|
|
87
|
-
"semgrep",
|
|
88
|
-
"goreleaser",
|
|
89
|
-
"graphql-schema-linter",
|
|
90
|
-
"npm-groovy-lint",
|
|
91
|
-
"haml-lint",
|
|
92
|
-
"htmlhint",
|
|
93
|
-
"djlint",
|
|
94
|
-
"checkstyle",
|
|
95
|
-
"google-java-format",
|
|
96
|
-
"eslint",
|
|
97
|
-
"next lint",
|
|
98
|
-
"deno",
|
|
99
|
-
"rome",
|
|
100
|
-
"eslint-plugin-jsonc",
|
|
101
|
-
"eslint-plugin-json",
|
|
102
|
-
"eslint-plugin-jsx-a11y",
|
|
103
|
-
"eslint-plugin-react",
|
|
104
|
-
"nbqa",
|
|
105
|
-
"detekt",
|
|
106
|
-
"ktlint",
|
|
107
|
-
"kubeconform",
|
|
108
|
-
"kube-linter",
|
|
109
|
-
"chktex",
|
|
110
|
-
"luacheck",
|
|
111
|
-
"stylua",
|
|
112
|
-
"markdownlint",
|
|
113
|
-
"markdownlint-cli2",
|
|
114
|
-
"markdown-link-check",
|
|
115
|
-
"markdown-table-prettify",
|
|
116
|
-
"remark-lint",
|
|
117
|
-
"textlint",
|
|
118
|
-
"vale",
|
|
119
|
-
"nixpkgs-fmt",
|
|
120
|
-
"spectral",
|
|
121
|
-
"sort-package-json",
|
|
122
|
-
"perlcritic",
|
|
123
|
-
"perltidy",
|
|
124
|
-
"php-cs-fixer",
|
|
125
|
-
"phpcs",
|
|
126
|
-
"phpstan",
|
|
127
|
-
"psalm",
|
|
128
|
-
"oxipng",
|
|
129
|
-
"psscriptanalyzer",
|
|
130
|
-
"prisma",
|
|
131
|
-
"protolint",
|
|
132
|
-
"buf",
|
|
133
|
-
"pylint",
|
|
134
|
-
"flake8",
|
|
135
|
-
"isort",
|
|
136
|
-
"ruff",
|
|
137
|
-
"black",
|
|
138
|
-
"autopep8",
|
|
139
|
-
"bandit",
|
|
140
|
-
"mypy",
|
|
141
|
-
"pyright",
|
|
142
|
-
"sourcery",
|
|
143
|
-
"yapf",
|
|
144
|
-
"lintr",
|
|
145
|
-
"opa",
|
|
146
|
-
"regal",
|
|
147
|
-
"rubocop",
|
|
148
|
-
"brakeman",
|
|
149
|
-
"rufo",
|
|
150
|
-
"standardrb",
|
|
151
|
-
"clippy",
|
|
152
|
-
"rustfmt",
|
|
153
|
-
"scalafmt",
|
|
154
|
-
"osv-scanner",
|
|
155
|
-
"terrascan",
|
|
156
|
-
"tfsec",
|
|
157
|
-
"snakemake --lint",
|
|
158
|
-
"snakefmt",
|
|
159
|
-
"sqlfluff",
|
|
160
|
-
"sql-formatter",
|
|
161
|
-
"sqlfmt",
|
|
162
|
-
"squawk",
|
|
163
|
-
"svgo",
|
|
164
|
-
"stringslint",
|
|
165
|
-
"swiftformat",
|
|
166
|
-
"swiftlint",
|
|
167
|
-
"tflint",
|
|
168
|
-
"terraform",
|
|
169
|
-
"tofu",
|
|
170
|
-
"terragrunt",
|
|
171
|
-
"txtpbfmt",
|
|
172
|
-
"taplo",
|
|
173
|
-
"eslint-plugin-vue",
|
|
174
|
-
"xmllint",
|
|
175
|
-
"yamllint"
|
|
176
|
-
];
|
|
177
|
-
//#endregion
|
|
178
|
-
//#region src/lib/workflows/audit/types.ts
|
|
14
|
+
//#region src/lib/programs/audit/types.ts
|
|
179
15
|
/** Single source of truth for status glyph + color across audit views. */
|
|
180
16
|
const AUDIT_SEVERITY_STYLE = {
|
|
181
17
|
pending: {
|
|
@@ -293,7 +129,7 @@ function downloadSkill(skillEntry, installDir, skillsRoot) {
|
|
|
293
129
|
}
|
|
294
130
|
/**
|
|
295
131
|
* High-level "install a skill by ID" helper. Fetches the skill menu,
|
|
296
|
-
* finds the skill, downloads and extracts it.
|
|
132
|
+
* finds the skill, downloads and extracts it. Programs should use this
|
|
297
133
|
* instead of composing fetchSkillMenu + downloadSkill themselves.
|
|
298
134
|
*/
|
|
299
135
|
async function installSkillById(skillId, installDir, skillsBaseUrl, skillsRoot) {
|
|
@@ -315,6 +151,25 @@ async function installSkillById(skillId, installDir, skillsBaseUrl, skillsRoot)
|
|
|
315
151
|
};
|
|
316
152
|
}
|
|
317
153
|
/**
|
|
154
|
+
* Pure decision function for the wizard_ask caps. Returns whether the
|
|
155
|
+
* upcoming call should proceed and, if not, the error message to surface
|
|
156
|
+
* to the agent. Extracted so the policy can be unit-tested without
|
|
157
|
+
* spinning up an MCP server.
|
|
158
|
+
*/
|
|
159
|
+
function evaluateAskCap(callCount, maxQuestions) {
|
|
160
|
+
if (callCount >= maxQuestions) return {
|
|
161
|
+
kind: "capped",
|
|
162
|
+
reason: "max_questions",
|
|
163
|
+
message: `Error: wizard_ask cap reached (${maxQuestions} calls in this run). Proceed with sensible defaults using the answers you already have, or emit [ABORT] requirements-incomplete.`
|
|
164
|
+
};
|
|
165
|
+
if (callCount >= 3) return {
|
|
166
|
+
kind: "capped",
|
|
167
|
+
reason: "adjacency",
|
|
168
|
+
message: `Error: too many wizard_ask calls in a row (${callCount} so far). Batch the remaining questions into a single call — the schema accepts up to 8 questions per invocation.`
|
|
169
|
+
};
|
|
170
|
+
return { kind: "ok" };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
318
173
|
* Resolve filePath relative to workingDirectory, rejecting path traversal.
|
|
319
174
|
*/
|
|
320
175
|
function resolveEnvPath(workingDirectory, filePath) {
|
|
@@ -489,8 +344,9 @@ const SERVER_NAME = "wizard-tools";
|
|
|
489
344
|
* Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
|
|
490
345
|
*/
|
|
491
346
|
async function createWizardToolsServer(options) {
|
|
492
|
-
const { workingDirectory, detectPackageManager, skillsBaseUrl } = options;
|
|
347
|
+
const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10 } = options;
|
|
493
348
|
const { tool, createSdkMcpServer } = await getSDKModule$1();
|
|
349
|
+
let askCallCount = 0;
|
|
494
350
|
let cachedSkillMenu = {};
|
|
495
351
|
let categoryNames = ["integration"];
|
|
496
352
|
const menu = await fetchSkillMenu(skillsBaseUrl);
|
|
@@ -591,6 +447,74 @@ async function createWizardToolsServer(options) {
|
|
|
591
447
|
});
|
|
592
448
|
const auditLedgerPath = path.join(workingDirectory, AUDIT_CHECKS_FILE);
|
|
593
449
|
const auditMutex = makeMutex();
|
|
450
|
+
const auditSeedChecks = tool("audit_seed_checks", "Seed the audit ledger at .posthog-audit-checks.json with the full set of pending checks. Call this once at the start of the audit. Atomically replaces any existing ledger.", { checks: z.array(auditCheckSchema).describe("Full pending checklist to write to the ledger") }, async (args) => {
|
|
451
|
+
return auditMutex(() => {
|
|
452
|
+
writeLedgerAtomic(auditLedgerPath, args.checks);
|
|
453
|
+
logToFile(`audit_seed_checks: wrote ${args.checks.length} entries`);
|
|
454
|
+
return { content: [{
|
|
455
|
+
type: "text",
|
|
456
|
+
text: `Seeded ${args.checks.length} audit checks.`
|
|
457
|
+
}] };
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
const auditAddChecks = tool("audit_add_checks", "Append one or more pending checks to the existing audit ledger at .posthog-audit-checks.json. Call audit_seed_checks first. Atomically rejects duplicate ids without changing the ledger.", { checks: z.array(auditCheckSchema).min(1).describe("Additional checks to append to the existing ledger") }, async (args) => {
|
|
461
|
+
return auditMutex(() => {
|
|
462
|
+
const result = appendAuditChecksToLedger(auditLedgerPath, args.checks);
|
|
463
|
+
if (!result.ok) {
|
|
464
|
+
if (result.reason === "missing-ledger") return {
|
|
465
|
+
content: [{
|
|
466
|
+
type: "text",
|
|
467
|
+
text: "Error: audit ledger does not exist. Run audit_seed_checks first."
|
|
468
|
+
}],
|
|
469
|
+
isError: true
|
|
470
|
+
};
|
|
471
|
+
return {
|
|
472
|
+
content: [{
|
|
473
|
+
type: "text",
|
|
474
|
+
text: `Error: duplicate check id(s): ${result.ids.join(", ")}. Check ids must be unique.`
|
|
475
|
+
}],
|
|
476
|
+
isError: true
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
logToFile(`audit_add_checks: added ${result.added} entries`);
|
|
480
|
+
return { content: [{
|
|
481
|
+
type: "text",
|
|
482
|
+
text: `Added ${result.added} audit check(s).`
|
|
483
|
+
}] };
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
const auditResolveChecks = tool("audit_resolve_checks", "Resolve one or more audit checks by id. Patches each entry's status (and optional file/details) and writes the ledger back atomically. Concurrent calls serialize.", { updates: z.array(auditUpdateSchema).min(1).describe("Patches to apply, keyed by check id") }, async (args) => {
|
|
487
|
+
return auditMutex(() => {
|
|
488
|
+
const { next, unknown } = applyAuditUpdates(readLedger(auditLedgerPath), args.updates);
|
|
489
|
+
if (unknown.length > 0) return {
|
|
490
|
+
content: [{
|
|
491
|
+
type: "text",
|
|
492
|
+
text: `Error: unknown check id(s): ${unknown.join(", ")}. Run audit_seed_checks first or check the id.`
|
|
493
|
+
}],
|
|
494
|
+
isError: true
|
|
495
|
+
};
|
|
496
|
+
writeLedgerAtomic(auditLedgerPath, next);
|
|
497
|
+
logToFile(`audit_resolve_checks: applied ${args.updates.length} update(s)`);
|
|
498
|
+
return { content: [{
|
|
499
|
+
type: "text",
|
|
500
|
+
text: `Resolved ${args.updates.length} check(s).`
|
|
501
|
+
}] };
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
const askQuestionSchema = z.object({
|
|
505
|
+
id: z.string().min(1).describe("Stable key for the answer in the response map"),
|
|
506
|
+
prompt: z.string().min(1).describe("Question text shown to the user"),
|
|
507
|
+
kind: z.enum([
|
|
508
|
+
"single",
|
|
509
|
+
"multi",
|
|
510
|
+
"text"
|
|
511
|
+
]).describe("'single' = pick one option, 'multi' = pick any, 'text' = free-form single-line answer"),
|
|
512
|
+
options: z.array(z.object({
|
|
513
|
+
label: z.string(),
|
|
514
|
+
value: z.string()
|
|
515
|
+
})).optional().describe("Required for kind=single|multi; ignored for kind=text"),
|
|
516
|
+
required: z.boolean().optional().describe("Defaults to true")
|
|
517
|
+
});
|
|
594
518
|
return createSdkMcpServer({
|
|
595
519
|
name: SERVER_NAME,
|
|
596
520
|
version: "1.0.0",
|
|
@@ -600,73 +524,247 @@ async function createWizardToolsServer(options) {
|
|
|
600
524
|
detectPM,
|
|
601
525
|
loadSkillMenu,
|
|
602
526
|
installSkill,
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
527
|
+
auditSeedChecks,
|
|
528
|
+
auditAddChecks,
|
|
529
|
+
auditResolveChecks,
|
|
530
|
+
tool("wizard_ask", "Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch related questions into a single call — do not call this multiple times in a row.", { questions: z.array(askQuestionSchema).min(1).max(8) }, async (args) => {
|
|
531
|
+
if (!askBridge) return {
|
|
532
|
+
content: [{
|
|
608
533
|
type: "text",
|
|
609
|
-
text:
|
|
610
|
-
}]
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
logToFile(`audit_add_checks: added ${result.added} entries`);
|
|
633
|
-
return { content: [{
|
|
534
|
+
text: "Error: wizard_ask is not available in this environment (CI / non-interactive). Proceed with sensible defaults or emit [ABORT] requirements-incomplete."
|
|
535
|
+
}],
|
|
536
|
+
isError: true
|
|
537
|
+
};
|
|
538
|
+
const capDecision = evaluateAskCap(askCallCount, askMaxQuestions);
|
|
539
|
+
if (capDecision.kind === "capped") {
|
|
540
|
+
analytics.wizardCapture("wizard_ask capped", {
|
|
541
|
+
reason: capDecision.reason,
|
|
542
|
+
call_count: askCallCount,
|
|
543
|
+
max_questions: askMaxQuestions
|
|
544
|
+
});
|
|
545
|
+
return {
|
|
546
|
+
content: [{
|
|
547
|
+
type: "text",
|
|
548
|
+
text: capDecision.message
|
|
549
|
+
}],
|
|
550
|
+
isError: true
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
for (const q of args.questions) if ((q.kind === "single" || q.kind === "multi") && (!q.options || q.options.length === 0)) return {
|
|
554
|
+
content: [{
|
|
634
555
|
type: "text",
|
|
635
|
-
text: `
|
|
636
|
-
}]
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (unknown.length > 0) return {
|
|
556
|
+
text: `Error: question "${q.id}" has kind="${q.kind}" but no options. Provide at least one { label, value } option, or change kind to "text".`
|
|
557
|
+
}],
|
|
558
|
+
isError: true
|
|
559
|
+
};
|
|
560
|
+
const ids = /* @__PURE__ */ new Set();
|
|
561
|
+
for (const q of args.questions) {
|
|
562
|
+
if (ids.has(q.id)) return {
|
|
643
563
|
content: [{
|
|
644
564
|
type: "text",
|
|
645
|
-
text: `Error:
|
|
565
|
+
text: `Error: duplicate question id "${q.id}". Each question must have a unique id.`
|
|
646
566
|
}],
|
|
647
567
|
isError: true
|
|
648
568
|
};
|
|
649
|
-
|
|
650
|
-
|
|
569
|
+
ids.add(q.id);
|
|
570
|
+
}
|
|
571
|
+
askCallCount += 1;
|
|
572
|
+
try {
|
|
573
|
+
const answers = await askBridge.request({ questions: args.questions });
|
|
574
|
+
logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)`);
|
|
651
575
|
return { content: [{
|
|
652
576
|
type: "text",
|
|
653
|
-
text:
|
|
577
|
+
text: JSON.stringify({ answers }, null, 2)
|
|
654
578
|
}] };
|
|
655
|
-
})
|
|
579
|
+
} catch (err) {
|
|
580
|
+
logToFile(`wizard_ask: error: ${err?.message ?? err}`);
|
|
581
|
+
return {
|
|
582
|
+
content: [{
|
|
583
|
+
type: "text",
|
|
584
|
+
text: `Error: wizard_ask failed: ${err?.message ?? String(err)}`
|
|
585
|
+
}],
|
|
586
|
+
isError: true
|
|
587
|
+
};
|
|
588
|
+
}
|
|
656
589
|
})
|
|
657
590
|
]
|
|
658
591
|
});
|
|
659
592
|
}
|
|
660
|
-
/** Tool names exposed by the wizard-tools server, for use
|
|
661
|
-
const WIZARD_TOOL_NAMES =
|
|
662
|
-
`${SERVER_NAME}:check_env_keys`,
|
|
663
|
-
`${SERVER_NAME}:set_env_values`,
|
|
664
|
-
`${SERVER_NAME}:detect_package_manager`,
|
|
665
|
-
`${SERVER_NAME}:load_skill_menu`,
|
|
666
|
-
`${SERVER_NAME}:install_skill`,
|
|
667
|
-
`${SERVER_NAME}:audit_seed_checks`,
|
|
668
|
-
`${SERVER_NAME}:audit_add_checks`,
|
|
669
|
-
`${SERVER_NAME}:audit_resolve_checks
|
|
593
|
+
/** Tool names exposed by the wizard-tools server, keyed for selective use. */
|
|
594
|
+
const WIZARD_TOOL_NAMES = {
|
|
595
|
+
checkEnvKeys: `${SERVER_NAME}:check_env_keys`,
|
|
596
|
+
setEnvValues: `${SERVER_NAME}:set_env_values`,
|
|
597
|
+
detectPackageManager: `${SERVER_NAME}:detect_package_manager`,
|
|
598
|
+
loadSkillMenu: `${SERVER_NAME}:load_skill_menu`,
|
|
599
|
+
installSkill: `${SERVER_NAME}:install_skill`,
|
|
600
|
+
auditSeedChecks: `${SERVER_NAME}:audit_seed_checks`,
|
|
601
|
+
auditAddChecks: `${SERVER_NAME}:audit_add_checks`,
|
|
602
|
+
auditResolveChecks: `${SERVER_NAME}:audit_resolve_checks`,
|
|
603
|
+
wizardAsk: `${SERVER_NAME}:wizard_ask`
|
|
604
|
+
};
|
|
605
|
+
//#endregion
|
|
606
|
+
//#region src/utils/custom-headers.ts
|
|
607
|
+
/**
|
|
608
|
+
* Builds a list of custom headers for ANTHROPIC_CUSTOM_HEADERS.
|
|
609
|
+
*/
|
|
610
|
+
function createCustomHeaders() {
|
|
611
|
+
const entries = [];
|
|
612
|
+
return {
|
|
613
|
+
add(key, value) {
|
|
614
|
+
const name = key.startsWith("x-") || key.startsWith("X-") ? key : `X-${key}`;
|
|
615
|
+
entries.push({
|
|
616
|
+
key: name,
|
|
617
|
+
value
|
|
618
|
+
});
|
|
619
|
+
},
|
|
620
|
+
addFlag(flagKey, variant) {
|
|
621
|
+
const headerName = POSTHOG_FLAG_HEADER_PREFIX + flagKey.toUpperCase();
|
|
622
|
+
entries.push({
|
|
623
|
+
key: headerName,
|
|
624
|
+
value: variant
|
|
625
|
+
});
|
|
626
|
+
},
|
|
627
|
+
encode() {
|
|
628
|
+
return entries.map(({ key, value }) => `${key}: ${value}`).join("\n");
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
//#endregion
|
|
633
|
+
//#region src/lib/safe-tools.ts
|
|
634
|
+
const LINTING_TOOLS = [
|
|
635
|
+
"codespell",
|
|
636
|
+
"cspell",
|
|
637
|
+
"git-diff-check",
|
|
638
|
+
"gitleaks",
|
|
639
|
+
"trufflehog",
|
|
640
|
+
"asl-validator",
|
|
641
|
+
"ansible-lint",
|
|
642
|
+
"pmd",
|
|
643
|
+
"biome",
|
|
644
|
+
"cfn-lint",
|
|
645
|
+
"cfnlint",
|
|
646
|
+
"checkov",
|
|
647
|
+
"trivy",
|
|
648
|
+
"test-aztemplate",
|
|
649
|
+
"shellcheck",
|
|
650
|
+
"shfmt",
|
|
651
|
+
"buildifier",
|
|
652
|
+
"cpplint",
|
|
653
|
+
"clang-format",
|
|
654
|
+
"clang-tidy",
|
|
655
|
+
"cmake-format",
|
|
656
|
+
"iwyu",
|
|
657
|
+
"pragma-once",
|
|
658
|
+
"dotnet-format",
|
|
659
|
+
"circleci",
|
|
660
|
+
"clj-kondo",
|
|
661
|
+
"coffeelint",
|
|
662
|
+
"commitlint",
|
|
663
|
+
"jscpd",
|
|
664
|
+
"stylelint",
|
|
665
|
+
"prettier",
|
|
666
|
+
"cue-fmt",
|
|
667
|
+
"dart",
|
|
668
|
+
"hadolint",
|
|
669
|
+
"dotenv-linter",
|
|
670
|
+
"editorconfig-checker",
|
|
671
|
+
"actionlint",
|
|
672
|
+
"zizmor",
|
|
673
|
+
"gofmt",
|
|
674
|
+
"gofumpt",
|
|
675
|
+
"goimports",
|
|
676
|
+
"gokart",
|
|
677
|
+
"golangci-lint",
|
|
678
|
+
"golines",
|
|
679
|
+
"semgrep",
|
|
680
|
+
"goreleaser",
|
|
681
|
+
"graphql-schema-linter",
|
|
682
|
+
"npm-groovy-lint",
|
|
683
|
+
"haml-lint",
|
|
684
|
+
"htmlhint",
|
|
685
|
+
"djlint",
|
|
686
|
+
"checkstyle",
|
|
687
|
+
"google-java-format",
|
|
688
|
+
"eslint",
|
|
689
|
+
"next lint",
|
|
690
|
+
"deno",
|
|
691
|
+
"rome",
|
|
692
|
+
"eslint-plugin-jsonc",
|
|
693
|
+
"eslint-plugin-json",
|
|
694
|
+
"eslint-plugin-jsx-a11y",
|
|
695
|
+
"eslint-plugin-react",
|
|
696
|
+
"nbqa",
|
|
697
|
+
"detekt",
|
|
698
|
+
"ktlint",
|
|
699
|
+
"kubeconform",
|
|
700
|
+
"kube-linter",
|
|
701
|
+
"chktex",
|
|
702
|
+
"luacheck",
|
|
703
|
+
"stylua",
|
|
704
|
+
"markdownlint",
|
|
705
|
+
"markdownlint-cli2",
|
|
706
|
+
"markdown-link-check",
|
|
707
|
+
"markdown-table-prettify",
|
|
708
|
+
"remark-lint",
|
|
709
|
+
"textlint",
|
|
710
|
+
"vale",
|
|
711
|
+
"nixpkgs-fmt",
|
|
712
|
+
"spectral",
|
|
713
|
+
"sort-package-json",
|
|
714
|
+
"perlcritic",
|
|
715
|
+
"perltidy",
|
|
716
|
+
"php-cs-fixer",
|
|
717
|
+
"phpcs",
|
|
718
|
+
"phpstan",
|
|
719
|
+
"psalm",
|
|
720
|
+
"oxipng",
|
|
721
|
+
"psscriptanalyzer",
|
|
722
|
+
"prisma",
|
|
723
|
+
"protolint",
|
|
724
|
+
"buf",
|
|
725
|
+
"pylint",
|
|
726
|
+
"flake8",
|
|
727
|
+
"isort",
|
|
728
|
+
"ruff",
|
|
729
|
+
"black",
|
|
730
|
+
"autopep8",
|
|
731
|
+
"bandit",
|
|
732
|
+
"mypy",
|
|
733
|
+
"pyright",
|
|
734
|
+
"sourcery",
|
|
735
|
+
"yapf",
|
|
736
|
+
"lintr",
|
|
737
|
+
"opa",
|
|
738
|
+
"regal",
|
|
739
|
+
"rubocop",
|
|
740
|
+
"brakeman",
|
|
741
|
+
"rufo",
|
|
742
|
+
"standardrb",
|
|
743
|
+
"clippy",
|
|
744
|
+
"rustfmt",
|
|
745
|
+
"scalafmt",
|
|
746
|
+
"osv-scanner",
|
|
747
|
+
"terrascan",
|
|
748
|
+
"tfsec",
|
|
749
|
+
"snakemake --lint",
|
|
750
|
+
"snakefmt",
|
|
751
|
+
"sqlfluff",
|
|
752
|
+
"sql-formatter",
|
|
753
|
+
"sqlfmt",
|
|
754
|
+
"squawk",
|
|
755
|
+
"svgo",
|
|
756
|
+
"stringslint",
|
|
757
|
+
"swiftformat",
|
|
758
|
+
"swiftlint",
|
|
759
|
+
"tflint",
|
|
760
|
+
"terraform",
|
|
761
|
+
"tofu",
|
|
762
|
+
"terragrunt",
|
|
763
|
+
"txtpbfmt",
|
|
764
|
+
"taplo",
|
|
765
|
+
"eslint-plugin-vue",
|
|
766
|
+
"xmllint",
|
|
767
|
+
"yamllint"
|
|
670
768
|
];
|
|
671
769
|
//#endregion
|
|
672
770
|
//#region src/lib/yara-scanner.ts
|
|
@@ -1228,9 +1326,20 @@ const WIZARD_COMMANDMENTS = [
|
|
|
1228
1326
|
"Treat feature flags, custom properties, and event names as part of an analytics contract. Prefer reusing existing names and patterns in the project. When you must introduce new ones, make them clear, descriptive, and consistent with existing conventions, and avoid scattering the same flag or property across many unrelated callsites.",
|
|
1229
1327
|
"Prefer minimal, targeted edits that achieve the requested behavior while preserving existing structure and style. Avoid large refactors, broad reformatting, or unrelated changes unless explicitly requested.",
|
|
1230
1328
|
"Do not spawn subagents unless explicitly instructed to do so.",
|
|
1231
|
-
"
|
|
1232
|
-
"
|
|
1233
|
-
"
|
|
1329
|
+
"Create tasks as soon as you understand the work you are going to carry out. Break the list into distinct stages of work that the user can follow through. Create all tasks in a single tool call, in the order you will be performing them. Drive the work with TaskUpdate: status in_progress when you begin a task, completed when done.",
|
|
1330
|
+
"Keep task titles broad and stage-oriented — describe the purpose or area of work, not the specific files, paths, or symbols involved. Do not name individual files, modules, or directories inside task titles, and do not include illustrative examples within a task title.",
|
|
1331
|
+
"Do not assume \"PostHog provider\" or \"PostHogProvider\" in task labels, status messages, or code. Only use a provider if the skill workflow explicitly requires one for the specific framework.",
|
|
1332
|
+
"If you see a [YARA WARNING] or [YARA VIOLATION] message, handle it silently. Fix the issue (revert the write, avoid the flagged pattern) without mentioning security warnings or YARA to the user. These are internal guardrails, not user-facing alerts. Never show scary security language to the user.",
|
|
1333
|
+
[
|
|
1334
|
+
"When a skill instructs you to gather information from the user, use the `wizard_ask` MCP tool from the wizard-tools server. Never inline questions in your text output expecting a reply — the user has no way to answer text.",
|
|
1335
|
+
"When a skill provides a numbered or bulleted list of questions, translate the entire list into a single `wizard_ask` tool call:",
|
|
1336
|
+
" - One tool call per skill step. Batch every question from that step into the `questions` array — never split into multiple calls.",
|
|
1337
|
+
" - Infer `kind` from the question phrasing: comma-separated alternatives (\"React, Vue, or vanilla JS?\") → `single`; phrasing like \"all that apply\" or \"any of\" → `multi`; everything else → `text`.",
|
|
1338
|
+
" - For `single` and `multi`, extract the alternatives from the prose into `options` as `{ label, value }` pairs. Use the human phrase as `label` and a lowercase-hyphenated form as `value` (e.g., `label: \"Vanilla JS\"`, `value: \"vanilla-js\"`).",
|
|
1339
|
+
" - Use a kebab-case slug of the question label as `id` (e.g., \"Tech stack\" → `tech-stack`, \"Show frequency\" → `show-frequency`).",
|
|
1340
|
+
" - Do not invent fields the schema does not define (no `source`, `category`, `priority`, etc.) — the tool rejects unknown fields and the wizard already knows which skill is running.",
|
|
1341
|
+
"After `wizard_ask` returns, use the answers directly — do not re-ask in text or call `wizard_ask` again for the same fields."
|
|
1342
|
+
].join("\n")
|
|
1234
1343
|
].join("\n");
|
|
1235
1344
|
function getWizardCommandments() {
|
|
1236
1345
|
return WIZARD_COMMANDMENTS;
|
|
@@ -1260,7 +1369,8 @@ const AgentSignals = {
|
|
|
1260
1369
|
ERROR_RESOURCE_MISSING: "[ERROR-RESOURCE-MISSING]",
|
|
1261
1370
|
ABORT: "[ABORT]",
|
|
1262
1371
|
WIZARD_REMARK: "[WIZARD-REMARK]",
|
|
1263
|
-
BENCHMARK: "[BENCHMARK]"
|
|
1372
|
+
BENCHMARK: "[BENCHMARK]",
|
|
1373
|
+
DASHBOARD_URL: "[DASHBOARD_URL]"
|
|
1264
1374
|
};
|
|
1265
1375
|
const BLOCKING_ENV_KEYS = [
|
|
1266
1376
|
"ANTHROPIC_API_KEY",
|
|
@@ -1485,8 +1595,21 @@ function matchesAllowedPrefix(command) {
|
|
|
1485
1595
|
* - Build/typecheck/lint commands for verification
|
|
1486
1596
|
* - Piping to tail/head for output limiting is allowed
|
|
1487
1597
|
* - Stderr redirection (2>&1) is allowed
|
|
1598
|
+
*
|
|
1599
|
+
* `wizardAskPending` is true while a wizard_ask overlay is open — when set,
|
|
1600
|
+
* Write/Edit calls are denied as a defense-in-depth measure against a
|
|
1601
|
+
* misbehaving agent that races to mutate files before the question is
|
|
1602
|
+
* answered. The SDK's tool-result protocol already pauses the agent here;
|
|
1603
|
+
* this guard is a belt-and-suspenders second line.
|
|
1488
1604
|
*/
|
|
1489
|
-
function wizardCanUseTool(toolName, input) {
|
|
1605
|
+
function wizardCanUseTool(toolName, input, context = {}) {
|
|
1606
|
+
if (context.wizardAskPending && (toolName === "Write" || toolName === "Edit")) {
|
|
1607
|
+
logToFile(`Denying ${toolName} while wizard_ask overlay is open`);
|
|
1608
|
+
return {
|
|
1609
|
+
behavior: "deny",
|
|
1610
|
+
message: `${toolName} is paused while a wizard_ask question is open. Wait for the user's answer to come back as a tool result before writing files.`
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1490
1613
|
if (toolName === "Read" || toolName === "Write" || toolName === "Edit") {
|
|
1491
1614
|
const filePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
1492
1615
|
const basename = path.basename(filePath);
|
|
@@ -1604,6 +1727,9 @@ async function initializeAgent(config, options) {
|
|
|
1604
1727
|
process.env.CLAUDE_CODE_OAUTH_TOKEN = config.posthogApiKey;
|
|
1605
1728
|
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "true";
|
|
1606
1729
|
logToFile("Configured LLM gateway:", gatewayUrl);
|
|
1730
|
+
logToFile("API key prefix:", config.posthogApiKey ? `${config.posthogApiKey.slice(0, 4)}***` : "(missing)");
|
|
1731
|
+
const initConflicts = checkAllSettingsConflicts(options.installDir);
|
|
1732
|
+
logToFile("Settings conflicts at agent init:", initConflicts.length > 0 ? initConflicts.map((c) => `${c.source}(${c.keys.join(",")})`).join("; ") : "none");
|
|
1607
1733
|
const mcpServers = {
|
|
1608
1734
|
"posthog-wizard": {
|
|
1609
1735
|
type: "http",
|
|
@@ -1621,15 +1747,20 @@ async function initializeAgent(config, options) {
|
|
|
1621
1747
|
mcpServers["wizard-tools"] = await createWizardToolsServer({
|
|
1622
1748
|
workingDirectory: config.workingDirectory,
|
|
1623
1749
|
detectPackageManager: config.detectPackageManager,
|
|
1624
|
-
skillsBaseUrl: config.skillsBaseUrl
|
|
1750
|
+
skillsBaseUrl: config.skillsBaseUrl,
|
|
1751
|
+
askBridge: config.askBridge,
|
|
1752
|
+
askMaxQuestions: config.askMaxQuestions
|
|
1625
1753
|
});
|
|
1626
|
-
const model = config.integrationLabel === "audit-3000" ? "
|
|
1754
|
+
const model = config.integrationLabel === "audit-3000" ? "claude-opus-4-6" : "claude-sonnet-4-6";
|
|
1627
1755
|
const agentRunConfig = {
|
|
1628
1756
|
workingDirectory: config.workingDirectory,
|
|
1629
1757
|
mcpServers,
|
|
1630
1758
|
model,
|
|
1631
1759
|
wizardFlags: config.wizardFlags,
|
|
1632
|
-
wizardMetadata: config.wizardMetadata
|
|
1760
|
+
wizardMetadata: config.wizardMetadata,
|
|
1761
|
+
allowedTools: config.allowedTools,
|
|
1762
|
+
disallowedTools: config.disallowedTools,
|
|
1763
|
+
getPendingQuestion: config.getPendingQuestion
|
|
1633
1764
|
};
|
|
1634
1765
|
logToFile("Agent config:", {
|
|
1635
1766
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
@@ -1684,6 +1815,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1684
1815
|
let receivedSuccessResult = false;
|
|
1685
1816
|
let loggedInitialContext = false;
|
|
1686
1817
|
let lastResultMessage = null;
|
|
1818
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
1687
1819
|
let signalDone;
|
|
1688
1820
|
const resultReceived = new Promise((resolve) => {
|
|
1689
1821
|
signalDone = resolve;
|
|
@@ -1729,18 +1861,9 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1729
1861
|
const abortController = new AbortController();
|
|
1730
1862
|
let abortReason = null;
|
|
1731
1863
|
try {
|
|
1732
|
-
const
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
"Edit",
|
|
1736
|
-
"Glob",
|
|
1737
|
-
"Grep",
|
|
1738
|
-
"Bash",
|
|
1739
|
-
"Task",
|
|
1740
|
-
"ListMcpResourcesTool",
|
|
1741
|
-
"Skill",
|
|
1742
|
-
...WIZARD_TOOL_NAMES
|
|
1743
|
-
];
|
|
1864
|
+
const disallow = new Set(agentConfig.disallowedTools ?? []);
|
|
1865
|
+
const allowedTools = [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []].filter((t) => !disallow.has(t));
|
|
1866
|
+
const inheritedMcpServerNames = Object.keys(agentConfig.mcpServers);
|
|
1744
1867
|
const response = query({
|
|
1745
1868
|
prompt: createPromptStream(),
|
|
1746
1869
|
options: {
|
|
@@ -1750,10 +1873,17 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1750
1873
|
permissionMode: "acceptEdits",
|
|
1751
1874
|
betas: ["context-1m-2025-08-07"],
|
|
1752
1875
|
mcpServers: agentConfig.mcpServers,
|
|
1876
|
+
agents: { "general-purpose": {
|
|
1877
|
+
description: "General-purpose subagent. Inherits the parent run's tools plus the PostHog and wizard-tools MCP servers, so it can call mcp__posthog-wizard__* directly instead of curling the REST API.",
|
|
1878
|
+
prompt: "You are a general-purpose subagent for the PostHog wizard. Prefer the authenticated mcp__posthog-wizard__* MCP tools over raw HTTP — they are already authenticated for this project. Only fall back to other transports if no MCP tool covers the operation.",
|
|
1879
|
+
mcpServers: inheritedMcpServerNames
|
|
1880
|
+
} },
|
|
1753
1881
|
settingSources: ["project"],
|
|
1882
|
+
skills: "all",
|
|
1754
1883
|
allowedTools,
|
|
1755
1884
|
sandbox: {
|
|
1756
1885
|
enabled: true,
|
|
1886
|
+
failIfUnavailable: false,
|
|
1757
1887
|
allowUnsandboxedCommands: false,
|
|
1758
1888
|
filesystem: { allowWrite: [
|
|
1759
1889
|
"/" + agentConfig.workingDirectory,
|
|
@@ -1762,12 +1892,23 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1762
1892
|
"//tmp/**",
|
|
1763
1893
|
"//private/tmp",
|
|
1764
1894
|
"//private/tmp/**",
|
|
1765
|
-
"~/Library/pnpm
|
|
1766
|
-
"~/.local/share/pnpm
|
|
1895
|
+
"~/Library/pnpm/**",
|
|
1896
|
+
"~/.local/share/pnpm/**",
|
|
1767
1897
|
"~/.pnpm-store/**",
|
|
1768
1898
|
"~/.npm/**",
|
|
1769
1899
|
"~/.yarn/**",
|
|
1770
|
-
"~/.
|
|
1900
|
+
"~/.bun/install/**",
|
|
1901
|
+
"~/.cache/node/corepack/**",
|
|
1902
|
+
"~/Library/Caches/node/corepack/**",
|
|
1903
|
+
"~/.volta/**",
|
|
1904
|
+
"~/.cache/pip/**",
|
|
1905
|
+
"~/Library/Caches/pip/**",
|
|
1906
|
+
"~/.cache/uv/**",
|
|
1907
|
+
"~/Library/Caches/uv/**",
|
|
1908
|
+
"~/.cache/pypoetry/**",
|
|
1909
|
+
"~/Library/Caches/pypoetry/**",
|
|
1910
|
+
"~/.bundle/**",
|
|
1911
|
+
"~/.gem/**"
|
|
1771
1912
|
] },
|
|
1772
1913
|
network: { allowedDomains: [
|
|
1773
1914
|
"github.com",
|
|
@@ -1781,6 +1922,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1781
1922
|
...process.env,
|
|
1782
1923
|
ANTHROPIC_API_KEY: void 0,
|
|
1783
1924
|
ENABLE_TOOL_SEARCH: "auto:0",
|
|
1925
|
+
MCP_CONNECTION_NONBLOCKING: "0",
|
|
1784
1926
|
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {})
|
|
1785
1927
|
},
|
|
1786
1928
|
canUseTool: (toolName, input) => {
|
|
@@ -1788,7 +1930,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1788
1930
|
toolName,
|
|
1789
1931
|
input
|
|
1790
1932
|
});
|
|
1791
|
-
const result = wizardCanUseTool(toolName, input);
|
|
1933
|
+
const result = wizardCanUseTool(toolName, input, { wizardAskPending: agentConfig.getPendingQuestion?.() != null });
|
|
1792
1934
|
logToFile("canUseTool result:", result);
|
|
1793
1935
|
return Promise.resolve(result);
|
|
1794
1936
|
},
|
|
@@ -1833,7 +1975,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1833
1975
|
}
|
|
1834
1976
|
loggedInitialContext = true;
|
|
1835
1977
|
}
|
|
1836
|
-
handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult);
|
|
1978
|
+
handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult, tasks);
|
|
1837
1979
|
if (abortCases.length > 0 && !abortReason && message.type === "assistant") {
|
|
1838
1980
|
const content = message.message?.content;
|
|
1839
1981
|
if (Array.isArray(content)) {
|
|
@@ -1852,8 +1994,16 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1852
1994
|
if (message.type === "assistant" && collectedText.join("\n").includes("API Error: 401")) {
|
|
1853
1995
|
signalDone();
|
|
1854
1996
|
spinner.stop("Authentication failed");
|
|
1855
|
-
|
|
1856
|
-
|
|
1997
|
+
const conflicts = checkAllSettingsConflicts(options.installDir);
|
|
1998
|
+
const hasSettingsConflict = conflicts.length > 0;
|
|
1999
|
+
logToFile("Agent error: 401, showing auth error screen", {
|
|
2000
|
+
hasSettingsConflict,
|
|
2001
|
+
conflicts
|
|
2002
|
+
});
|
|
2003
|
+
getUI().showAuthError({
|
|
2004
|
+
hasSettingsConflict,
|
|
2005
|
+
logFilePath: getLogFilePath()
|
|
2006
|
+
});
|
|
1857
2007
|
await wizardAbort({
|
|
1858
2008
|
message: "Authentication failed (401)",
|
|
1859
2009
|
error: new WizardError("Authentication failed")
|
|
@@ -1964,7 +2114,115 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
1964
2114
|
* while still logging to file. The SDK may emit a second error
|
|
1965
2115
|
* result after success due to cleanup race conditions.
|
|
1966
2116
|
*/
|
|
1967
|
-
|
|
2117
|
+
/**
|
|
2118
|
+
* SDK >=0.3.142 replaced TodoWrite with four discrete Task* tools.
|
|
2119
|
+
* Create / Update mutate the task list; Get / List are read-only.
|
|
2120
|
+
*/
|
|
2121
|
+
let TaskTool = /* @__PURE__ */ function(TaskTool) {
|
|
2122
|
+
TaskTool["Create"] = "TaskCreate";
|
|
2123
|
+
TaskTool["Update"] = "TaskUpdate";
|
|
2124
|
+
TaskTool["Get"] = "TaskGet";
|
|
2125
|
+
TaskTool["List"] = "TaskList";
|
|
2126
|
+
return TaskTool;
|
|
2127
|
+
}({});
|
|
2128
|
+
/**
|
|
2129
|
+
* Tools every program gets unless its ProgramConfig.disallowedTools says
|
|
2130
|
+
* otherwise. Programs add more via ProgramConfig.allowedTools (e.g.
|
|
2131
|
+
* `'Agent'` to opt into subagent dispatch). Skills and PostHog MCP tools
|
|
2132
|
+
* are enabled separately (skills option / mcpServers).
|
|
2133
|
+
*/
|
|
2134
|
+
const BASE_ALLOWED_TOOLS = [
|
|
2135
|
+
"Read",
|
|
2136
|
+
"Write",
|
|
2137
|
+
"Edit",
|
|
2138
|
+
"Glob",
|
|
2139
|
+
"Grep",
|
|
2140
|
+
"Bash",
|
|
2141
|
+
...Object.values(TaskTool),
|
|
2142
|
+
"ListMcpResourcesTool",
|
|
2143
|
+
...Object.values(WIZARD_TOOL_NAMES)
|
|
2144
|
+
];
|
|
2145
|
+
function handleTaskCreate(block, store) {
|
|
2146
|
+
const input = block.input;
|
|
2147
|
+
if (!input?.subject) return;
|
|
2148
|
+
store.tasks.set(block.id, {
|
|
2149
|
+
content: input.subject,
|
|
2150
|
+
status: "pending",
|
|
2151
|
+
activeForm: input.activeForm
|
|
2152
|
+
});
|
|
2153
|
+
store.sync();
|
|
2154
|
+
}
|
|
2155
|
+
function handleTaskUpdate(block, store) {
|
|
2156
|
+
const input = block.input;
|
|
2157
|
+
if (!input?.taskId) return;
|
|
2158
|
+
const existing = store.tasks.get(input.taskId);
|
|
2159
|
+
if (!existing) return;
|
|
2160
|
+
if (input.status === "deleted") store.tasks.delete(input.taskId);
|
|
2161
|
+
else store.tasks.set(input.taskId, {
|
|
2162
|
+
content: input.subject ?? existing.content,
|
|
2163
|
+
status: input.status ?? existing.status,
|
|
2164
|
+
activeForm: input.activeForm ?? existing.activeForm
|
|
2165
|
+
});
|
|
2166
|
+
store.sync();
|
|
2167
|
+
}
|
|
2168
|
+
function handleTaskGet(_block, _store) {}
|
|
2169
|
+
function handleTaskList(_block, _store) {}
|
|
2170
|
+
function dispatchTaskToolUse(block, store) {
|
|
2171
|
+
switch (block.name) {
|
|
2172
|
+
case "TaskCreate": return handleTaskCreate(block, store);
|
|
2173
|
+
case "TaskUpdate": return handleTaskUpdate(block, store);
|
|
2174
|
+
case "TaskGet": return handleTaskGet(block, store);
|
|
2175
|
+
case "TaskList": return handleTaskList(block, store);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* Pull the SDK-assigned task id off a SDKUserMessage.tool_use_result payload.
|
|
2180
|
+
* The SDK already deserialises TaskCreateOutput here, so the shape is the
|
|
2181
|
+
* structured `{ task: { id, subject } }` object — no JSON parsing needed.
|
|
2182
|
+
*/
|
|
2183
|
+
function extractTaskIdFromToolResult(result) {
|
|
2184
|
+
if (!result || typeof result !== "object") return void 0;
|
|
2185
|
+
const obj = result;
|
|
2186
|
+
const task = obj.task;
|
|
2187
|
+
if (task && typeof task.id === "string") return task.id;
|
|
2188
|
+
if (typeof obj.taskId === "string") return obj.taskId;
|
|
2189
|
+
if (typeof obj.id === "string") return obj.id;
|
|
2190
|
+
}
|
|
2191
|
+
/**
|
|
2192
|
+
* Fallback id extractor for the inner tool_result block.content — used only
|
|
2193
|
+
* when message.tool_use_result is absent. In current SDK versions the inner
|
|
2194
|
+
* content is a human-readable string ("Task #1 created successfully: …") so
|
|
2195
|
+
* this path almost always returns undefined.
|
|
2196
|
+
*/
|
|
2197
|
+
function extractTaskIdFromResult(content) {
|
|
2198
|
+
const tryParse = (s) => {
|
|
2199
|
+
try {
|
|
2200
|
+
const parsed = JSON.parse(s);
|
|
2201
|
+
const id = parsed?.task?.id ?? parsed?.taskId ?? parsed?.id;
|
|
2202
|
+
return typeof id === "string" ? id : void 0;
|
|
2203
|
+
} catch {
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
};
|
|
2207
|
+
if (typeof content === "string") return tryParse(content);
|
|
2208
|
+
if (Array.isArray(content)) {
|
|
2209
|
+
for (const block of content) if (block?.type === "text" && typeof block.text === "string") {
|
|
2210
|
+
const id = tryParse(block.text);
|
|
2211
|
+
if (id) return id;
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
function handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult = false, tasks) {
|
|
2216
|
+
const STATUS_RANK = {
|
|
2217
|
+
completed: 0,
|
|
2218
|
+
in_progress: 1
|
|
2219
|
+
};
|
|
2220
|
+
const rank = (status) => STATUS_RANK[status] ?? 2;
|
|
2221
|
+
const syncTasks = () => {
|
|
2222
|
+
if (!tasks) return;
|
|
2223
|
+
const sorted = Array.from(tasks.values()).sort((a, b) => rank(a.status) - rank(b.status));
|
|
2224
|
+
getUI().syncTodos(sorted);
|
|
2225
|
+
};
|
|
1968
2226
|
logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
1969
2227
|
if (options.debug) debug(`SDK Message type: ${message.type}`);
|
|
1970
2228
|
switch (message.type) {
|
|
@@ -1980,11 +2238,31 @@ function handleSDKMessage(message, options, spinner, collectedText, receivedSucc
|
|
|
1980
2238
|
getUI().pushStatus(statusText);
|
|
1981
2239
|
spinner.message(statusText);
|
|
1982
2240
|
}
|
|
2241
|
+
const dashboardRegex = new RegExp(`${AgentSignals.DASHBOARD_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(\\S+)`, "m");
|
|
2242
|
+
const dashboardMatch = block.text.match(dashboardRegex);
|
|
2243
|
+
if (dashboardMatch) getUI().setDashboardUrl(dashboardMatch[1].trim());
|
|
1983
2244
|
}
|
|
1984
|
-
if (block.type === "tool_use" &&
|
|
2245
|
+
if (block.type === "tool_use" && tasks && Object.values(TaskTool).includes(block.name)) dispatchTaskToolUse(block, {
|
|
2246
|
+
tasks,
|
|
2247
|
+
sync: syncTasks
|
|
2248
|
+
});
|
|
1985
2249
|
}
|
|
1986
2250
|
break;
|
|
1987
2251
|
}
|
|
2252
|
+
case "user":
|
|
2253
|
+
if (tasks && tasks.size > 0) {
|
|
2254
|
+
const content = message.message?.content;
|
|
2255
|
+
if (Array.isArray(content)) for (const block of content) {
|
|
2256
|
+
if (block.type !== "tool_result" || typeof block.tool_use_id !== "string" || !tasks.has(block.tool_use_id)) continue;
|
|
2257
|
+
const taskId = extractTaskIdFromToolResult(message.tool_use_result) ?? extractTaskIdFromResult(block.content);
|
|
2258
|
+
if (!taskId) continue;
|
|
2259
|
+
const entry = tasks.get(block.tool_use_id);
|
|
2260
|
+
tasks.delete(block.tool_use_id);
|
|
2261
|
+
tasks.set(taskId, entry);
|
|
2262
|
+
syncTasks();
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
break;
|
|
1988
2266
|
case "result":
|
|
1989
2267
|
if (message.is_error) {
|
|
1990
2268
|
logToFile("Agent result with error:", message.result);
|
|
@@ -2017,6 +2295,6 @@ function handleSDKMessage(message, options, spinner, collectedText, receivedSucc
|
|
|
2017
2295
|
}
|
|
2018
2296
|
}
|
|
2019
2297
|
//#endregion
|
|
2020
|
-
export {
|
|
2298
|
+
export { AUDIT_SEVERITY_STYLE as _, initializeAgent as a, formatScanReport as c, downloadSkill as d, fetchSkillMenu as f, AUDIT_REPORT_FILE as g, AUDIT_CHECKS_KEY as h, checkAllSettingsConflicts as i, writeScanReport as l, AUDIT_CHECKS_FILE as m, backupAndFixClaudeSettings as n, restoreClaudeSettings as o, installSkillById as p, buildWizardMetadata as r, runAgent as s, AgentSignals as t, WIZARD_TOOL_NAMES as u, coerceAuditChecks as v, getAuditChecks as y };
|
|
2021
2299
|
|
|
2022
|
-
//# sourceMappingURL=agent-interface-
|
|
2300
|
+
//# sourceMappingURL=agent-interface-gP4pkZgS.js.map
|