@posthog/wizard 2.13.1 → 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.
Files changed (87) hide show
  1. package/LICENSE +0 -26
  2. package/README.md +1 -1
  3. package/dist/TextBlock-B3cm43YY.js +244 -0
  4. package/dist/TextBlock-B3cm43YY.js.map +1 -0
  5. package/dist/{add-mcp-server-to-clients-D1IyBa9u.js → add-mcp-server-to-clients-BTW9Ey5Z.js} +7 -7
  6. package/dist/{add-mcp-server-to-clients-D1IyBa9u.js.map → add-mcp-server-to-clients-BTW9Ey5Z.js.map} +1 -1
  7. package/dist/{agent-interface-D9DeIikl.js → agent-interface-gP4pkZgS.js} +533 -255
  8. package/dist/agent-interface-gP4pkZgS.js.map +1 -0
  9. package/dist/{agent-runner-B41-Iig3.js → agent-runner-Bxi71jnp.js} +102 -20
  10. package/dist/agent-runner-Bxi71jnp.js.map +1 -0
  11. package/dist/{analytics-Cek5hIwm.js → analytics-Dmnxu2zE.js} +2 -2
  12. package/dist/{analytics-Cek5hIwm.js.map → analytics-Dmnxu2zE.js.map} +1 -1
  13. package/dist/analytics-tslsXyf9.js +2 -0
  14. package/dist/bin.js +951 -141
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{debug-B2BH87dh.js → debug-CYUB-urp.js} +26 -21
  17. package/dist/debug-CYUB-urp.js.map +1 -0
  18. package/dist/{debug-BNWsxaDm.js → debug-Du7qXlug.js} +1 -1
  19. package/dist/{defaults-GbLPuHxj.js → defaults-DgKAzsD1.js} +1 -1
  20. package/dist/{defaults-GbLPuHxj.js.map → defaults-DgKAzsD1.js.map} +1 -1
  21. package/dist/{detection-BFl2AYV6.js → detection-D651Eb5k.js} +4 -4
  22. package/dist/detection-D651Eb5k.js.map +1 -0
  23. package/dist/{file-8iNrXHkG.js → file-BKbKreWF.js} +1 -1
  24. package/dist/{file-8iNrXHkG.js.map → file-BKbKreWF.js.map} +1 -1
  25. package/dist/{file-utils-DnTSiTJw.js → file-utils-DPmgn9Vm.js} +1 -1
  26. package/dist/{file-utils-DnTSiTJw.js.map → file-utils-DPmgn9Vm.js.map} +1 -1
  27. package/dist/{package-json-F_7oktsp.js → package-json-DZpnf6vU.js} +8 -10
  28. package/dist/package-json-DZpnf6vU.js.map +1 -0
  29. package/dist/package-json-_4PEss19.js +2 -0
  30. package/dist/{package-manager-BBTvHn9i.js → package-manager-liwrN_aI.js} +2 -2
  31. package/dist/{package-manager-BBTvHn9i.js.map → package-manager-liwrN_aI.js.map} +1 -1
  32. package/dist/{posthog-vm0k9PKS.js → posthog-BbQf_Hzq.js} +1 -1
  33. package/dist/{posthog-vm0k9PKS.js.map → posthog-BbQf_Hzq.js.map} +1 -1
  34. package/dist/posthog-integration-C-FFV5ny.js +1012 -0
  35. package/dist/posthog-integration-C-FFV5ny.js.map +1 -0
  36. package/dist/provisioning-ByWo5KcQ.js +2 -0
  37. package/dist/{provisioning-DRwH4skH.js → provisioning-C4nHkz-O.js} +3 -3
  38. package/dist/{provisioning-DRwH4skH.js.map → provisioning-C4nHkz-O.js.map} +1 -1
  39. package/dist/{registry-CZjMhhsK.js → registry-B92uyoWK.js} +5 -5
  40. package/dist/{registry-CZjMhhsK.js.map → registry-B92uyoWK.js.map} +1 -1
  41. package/dist/setup-utils-D5aNKrba.js +2 -0
  42. package/dist/{setup-utils-DGUR4Djo.js → setup-utils-LvtZIY18.js} +77 -107
  43. package/dist/setup-utils-LvtZIY18.js.map +1 -0
  44. package/dist/{AuditChecksViewer-CjBCZjxG.js → slides-yyC_W0RZ.js} +626 -1058
  45. package/dist/slides-yyC_W0RZ.js.map +1 -0
  46. package/dist/smoke-test-ci.sh +4 -4
  47. package/dist/{start-playground-DPYl5WR-.js → start-playground-BhwBUq-a.js} +259 -10
  48. package/dist/start-playground-BhwBUq-a.js.map +1 -0
  49. package/dist/{start-tui-Cj_4BhK8.js → start-tui-BwQa3kmG.js} +288 -446
  50. package/dist/start-tui-BwQa3kmG.js.map +1 -0
  51. package/dist/{steps-BFD76-MP.js → steps-CGpfOAcr.js} +7 -7
  52. package/dist/{steps-BFD76-MP.js.map → steps-CGpfOAcr.js.map} +1 -1
  53. package/dist/{task-stream-CX7Uf6EM.js → task-stream-DUpUZmFQ.js} +8 -8
  54. package/dist/task-stream-DUpUZmFQ.js.map +1 -0
  55. package/dist/telemetry-Fmdx1AYv.js +13 -0
  56. package/dist/telemetry-Fmdx1AYv.js.map +1 -0
  57. package/dist/{wizard-abort-CZH03nD0.js → wizard-abort-BTBccRto.js} +1 -1
  58. package/dist/{wizard-abort-54DpTnUi.js → wizard-abort-D-t5yDkY.js} +3 -3
  59. package/dist/{wizard-abort-54DpTnUi.js.map → wizard-abort-D-t5yDkY.js.map} +1 -1
  60. package/dist/wizard-session-CPhhll4P.js +2 -0
  61. package/dist/{wizard-session-BcNJTl2I.js → wizard-session-CsI33S4_.js} +6 -3
  62. package/dist/wizard-session-CsI33S4_.js.map +1 -0
  63. package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
  64. package/npm-shrinkwrap.json +2 -2
  65. package/package.json +3 -2
  66. package/dist/AuditChecksViewer-CjBCZjxG.js.map +0 -1
  67. package/dist/agent-interface-D9DeIikl.js.map +0 -1
  68. package/dist/agent-runner-B41-Iig3.js.map +0 -1
  69. package/dist/analytics-CpbY05Lf.js +0 -2
  70. package/dist/debug-B2BH87dh.js.map +0 -1
  71. package/dist/detection-BFl2AYV6.js.map +0 -1
  72. package/dist/package-json-BzVey4Bd.js +0 -2
  73. package/dist/package-json-F_7oktsp.js.map +0 -1
  74. package/dist/posthog-integration-vFBuSN5U.js +0 -259
  75. package/dist/posthog-integration-vFBuSN5U.js.map +0 -1
  76. package/dist/provisioning--RCv39tI.js +0 -2
  77. package/dist/router-COhhuIW3.js +0 -135
  78. package/dist/router-COhhuIW3.js.map +0 -1
  79. package/dist/setup-utils-DGUR4Djo.js.map +0 -1
  80. package/dist/setup-utils-eh1450iu.js +0 -2
  81. package/dist/start-playground-DPYl5WR-.js.map +0 -1
  82. package/dist/start-tui-Cj_4BhK8.js.map +0 -1
  83. package/dist/task-stream-CX7Uf6EM.js.map +0 -1
  84. package/dist/telemetry-DCyjsXhw.js +0 -13
  85. package/dist/telemetry-DCyjsXhw.js.map +0 -1
  86. package/dist/wizard-session-BQC9vy9Z.js +0 -2
  87. 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-B2BH87dh.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-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-Cek5hIwm.js";
5
- import { f as getLlmGatewayUrlFromHost } from "./setup-utils-DGUR4Djo.js";
6
- import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-BcNJTl2I.js";
7
- import { n as registerCleanup, r as wizardAbort, t as WizardError } from "./wizard-abort-54DpTnUi.js";
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/utils/custom-headers.ts
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. Workflows should use this
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
- 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) => {
604
- return auditMutex(() => {
605
- writeLedgerAtomic(auditLedgerPath, args.checks);
606
- logToFile(`audit_seed_checks: wrote ${args.checks.length} entries`);
607
- return { content: [{
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: `Seeded ${args.checks.length} audit checks.`
610
- }] };
611
- });
612
- }),
613
- 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) => {
614
- return auditMutex(() => {
615
- const result = appendAuditChecksToLedger(auditLedgerPath, args.checks);
616
- if (!result.ok) {
617
- if (result.reason === "missing-ledger") return {
618
- content: [{
619
- type: "text",
620
- text: "Error: audit ledger does not exist. Run audit_seed_checks first."
621
- }],
622
- isError: true
623
- };
624
- return {
625
- content: [{
626
- type: "text",
627
- text: `Error: duplicate check id(s): ${result.ids.join(", ")}. Check ids must be unique.`
628
- }],
629
- isError: true
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: `Added ${result.added} audit check(s).`
636
- }] };
637
- });
638
- }),
639
- 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) => {
640
- return auditMutex(() => {
641
- const { next, unknown } = applyAuditUpdates(readLedger(auditLedgerPath), args.updates);
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: unknown check id(s): ${unknown.join(", ")}. Run audit_seed_checks first or check the id.`
565
+ text: `Error: duplicate question id "${q.id}". Each question must have a unique id.`
646
566
  }],
647
567
  isError: true
648
568
  };
649
- writeLedgerAtomic(auditLedgerPath, next);
650
- logToFile(`audit_resolve_checks: applied ${args.updates.length} update(s)`);
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: `Resolved ${args.updates.length} check(s).`
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 in allowedTools */
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
- "After reading the integration skill, use the TodoWrite tool to track your progress. Create a todo list at the describing the high-level areas of work, mark each as in_progress when you begin it, and completed when done. Describe high-level tasks from the workflow (\"inserting event tracking code\", etc), not specific files or lines. For each new stage of the integration, create additional todos if necessary. Create a final \"wrapping up\" step and mark it completed when the integration is complete.",
1232
- "Do not assume \"PostHog provider\" or \"PostHogProvider\" in todo labels, status messages, or code. Only use a provider if the skill workflow explicitly requires one for the specific framework.",
1233
- "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."
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,7 +1747,9 @@ 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
1754
  const model = config.integrationLabel === "audit-3000" ? "claude-opus-4-6" : "claude-sonnet-4-6";
1627
1755
  const agentRunConfig = {
@@ -1629,7 +1757,10 @@ async function initializeAgent(config, options) {
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 allowedTools = [
1733
- "Read",
1734
- "Write",
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/store/**",
1766
- "~/.local/share/pnpm/store/**",
1895
+ "~/Library/pnpm/**",
1896
+ "~/.local/share/pnpm/**",
1767
1897
  "~/.pnpm-store/**",
1768
1898
  "~/.npm/**",
1769
1899
  "~/.yarn/**",
1770
- "~/.yarn/berry/**"
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
- logToFile("Agent error: 401, showing auth error screen");
1856
- getUI().showAuthError();
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
- function handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult = false) {
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" && block.name === "TodoWrite" && block.input?.todos && Array.isArray(block.input.todos)) getUI().syncTodos(block.input.todos);
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 { coerceAuditChecks as _, initializeAgent as a, formatScanReport as c, fetchSkillMenu as d, installSkillById as f, AUDIT_SEVERITY_STYLE as g, AUDIT_REPORT_FILE as h, checkAllSettingsConflicts as i, writeScanReport as l, AUDIT_CHECKS_KEY as m, backupAndFixClaudeSettings as n, restoreClaudeSettings as o, AUDIT_CHECKS_FILE as p, buildWizardMetadata as r, runAgent as s, AgentSignals as t, downloadSkill as u, getAuditChecks as v };
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-D9DeIikl.js.map
2300
+ //# sourceMappingURL=agent-interface-gP4pkZgS.js.map