@wrongstack/core 0.280.1 → 0.281.1

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 (95) hide show
  1. package/dist/{agent-subagent-runner-PoqNKiR4.d.ts → agent-subagent-runner-DyOSK2Wy.d.ts} +39 -8
  2. package/dist/{compactor-U3agvUIG.d.ts → compactor-BxddyCFu.d.ts} +1 -1
  3. package/dist/{config-Cr3312zc.d.ts → config-CN-vdDEI.d.ts} +82 -2
  4. package/dist/coordination/index.d.ts +203 -20
  5. package/dist/coordination/index.js +981 -52
  6. package/dist/coordination/index.js.map +1 -1
  7. package/dist/defaults/index.d.ts +26 -30
  8. package/dist/defaults/index.js +382 -30
  9. package/dist/defaults/index.js.map +1 -1
  10. package/dist/{events-Bs2fmldo.d.ts → events-C5hLU0AT.d.ts} +38 -2
  11. package/dist/execution/index.d.ts +16 -16
  12. package/dist/execution/index.js +161 -18
  13. package/dist/execution/index.js.map +1 -1
  14. package/dist/execution/prompt-enhancer.d.ts +1 -1
  15. package/dist/execution/prompt-enhancer.js +12 -3
  16. package/dist/execution/prompt-enhancer.js.map +1 -1
  17. package/dist/extension/index.d.ts +6 -6
  18. package/dist/{global-mailbox-Ct7IorLJ.d.ts → global-mailbox-CHM1QkCi.d.ts} +5 -2
  19. package/dist/{goal-store-C4F6DjC0.d.ts → goal-store-BLGZq16t.d.ts} +1 -1
  20. package/dist/hq/index.d.ts +6 -6
  21. package/dist/hq/index.js +35 -13
  22. package/dist/hq/index.js.map +1 -1
  23. package/dist/{index-nP09-oP2.d.ts → index-BEFWNZYs.d.ts} +1 -2
  24. package/dist/{index-kidebiDh.d.ts → index-C1E-_71T.d.ts} +6 -6
  25. package/dist/index.d.ts +44 -48
  26. package/dist/index.js +14855 -13944
  27. package/dist/index.js.map +1 -1
  28. package/dist/infrastructure/index.d.ts +60 -8
  29. package/dist/infrastructure/index.js.map +1 -1
  30. package/dist/kernel/index.d.ts +11 -11
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/{mcp-servers-D910X5_r.d.ts → mcp-servers-EKRAcJDi.d.ts} +97 -4
  33. package/dist/models/index.d.ts +4 -5
  34. package/dist/models/index.js +22 -5
  35. package/dist/models/index.js.map +1 -1
  36. package/dist/{multi-agent-coordinator-CieyUoEL.d.ts → multi-agent-coordinator-IpHCuHUa.d.ts} +29 -1
  37. package/dist/{null-fleet-bus-DkdmZJ_W.d.ts → null-fleet-bus-ZBkKGR9j.d.ts} +105 -7
  38. package/dist/observability/index.d.ts +3 -3
  39. package/dist/{tool-executor-SiE1wlZo.d.ts → parallel-eternal-engine-Cc2CNgmv.d.ts} +6 -202
  40. package/dist/path-resolver-CMS5307d.d.ts +13 -0
  41. package/dist/{permission-Dx6dIqS2.d.ts → permission-B6YAtNFz.d.ts} +1 -1
  42. package/dist/{pipeline-BwAP21_4.d.ts → pipeline-E7_jqGyV.d.ts} +2 -2
  43. package/dist/{provider-model-resolve-CwQNZWt_.d.ts → provider-model-resolve-KgIdiEQ6.d.ts} +118 -5
  44. package/dist/{provider-runner-CYHFImzV.d.ts → provider-runner-DxWXNHL1.d.ts} +3 -3
  45. package/dist/{retry-policy-D4feSLk3.d.ts → retry-policy-V67lBOJz.d.ts} +2 -2
  46. package/dist/sdd/index.d.ts +9 -9
  47. package/dist/sdd/index.js +94 -10
  48. package/dist/sdd/index.js.map +1 -1
  49. package/dist/{permission-policy-C8vJcnX5.d.ts → secret-vault-D7jeyXUQ.d.ts} +119 -3
  50. package/dist/security/index.d.ts +5 -6
  51. package/dist/security/index.js +4 -1
  52. package/dist/security/index.js.map +1 -1
  53. package/dist/{selector-Dy-MzKp1.d.ts → selector-Bx2HgUkU.d.ts} +1 -1
  54. package/dist/{session-event-bridge-CqdiGnfU.d.ts → session-event-bridge-vA2fLV58.d.ts} +1 -1
  55. package/dist/{session-reader-Hk0WbNm9.d.ts → session-reader-B-Fi9L6I.d.ts} +1 -1
  56. package/dist/session-registry-Dvg7i_IA.d.ts +129 -0
  57. package/dist/storage/index.d.ts +71 -142
  58. package/dist/storage/index.js +161 -13
  59. package/dist/storage/index.js.map +1 -1
  60. package/dist/{todos-checkpoint-Bk2uP7Ex.d.ts → todos-checkpoint-B1QVkoa8.d.ts} +23 -5
  61. package/dist/{tool-BkOgs_KL.d.ts → tool-LVSLiE1s.d.ts} +18 -4
  62. package/dist/{strategy-compactor-CQwhbErd.d.ts → tool-executor-BWtYwuPI.d.ts} +210 -12
  63. package/dist/tools/index.d.ts +2 -2
  64. package/dist/tools/index.js.map +1 -1
  65. package/dist/types/index.d.ts +17 -41
  66. package/dist/types/index.js +182 -5085
  67. package/dist/types/index.js.map +1 -1
  68. package/dist/utils/index.d.ts +3 -3
  69. package/dist/utils/index.js +6 -1
  70. package/dist/utils/index.js.map +1 -1
  71. package/dist/{worktree-manager-BjOFF6bt.d.ts → worktree-manager-C6CIilTT.d.ts} +1 -1
  72. package/dist/{wstack-paths-CMl_cYgq.d.ts → wstack-paths-C3K40Qst.d.ts} +2 -0
  73. package/instructions/agents/shadow-agent.md +23 -84
  74. package/instructions/coordination/director-preamble.md +12 -3
  75. package/instructions/coordination/subagent-baseline.md +39 -46
  76. package/instructions/leader-after-task.md +10 -28
  77. package/instructions/llm/llm-selector.md +1 -2
  78. package/instructions/modes/brief-system.md +7 -33
  79. package/instructions/modes/brief.md +5 -20
  80. package/instructions/modes/teach-system.md +12 -72
  81. package/instructions/modes/teach.md +12 -49
  82. package/instructions/sections/tool/commit-hygiene.md +5 -5
  83. package/instructions/sections/tool/context-management-full.md +6 -6
  84. package/instructions/sections/tool/delegation-compact.md +1 -1
  85. package/instructions/sections/tool/delegation-full.md +19 -23
  86. package/instructions/sections/tool/mailbox-full.md +11 -31
  87. package/instructions/sections/tool/mcp-full-control.md +5 -7
  88. package/instructions/sections/tool/mcp-full-use.md +7 -7
  89. package/instructions/system.md +22 -38
  90. package/package.json +1 -29
  91. package/dist/agent-bridge-DXC6QDJ4.d.ts +0 -35
  92. package/dist/logger-D3lV0cUZ.d.ts +0 -101
  93. package/dist/models-registry-CLkoOcHk.d.ts +0 -108
  94. package/dist/path-resolver-XfZ9eLxG.d.ts +0 -67
  95. package/dist/secret-vault-CImt2XrR.d.ts +0 -118
@@ -1,4 +1,4 @@
1
- import { P as Provider, R as ReasoningRequest, a as ReasoningConfig, M as Message } from '../tool-BkOgs_KL.js';
1
+ import { P as Provider, R as ReasoningRequest, a as ReasoningConfig, M as Message } from '../tool-LVSLiE1s.js';
2
2
 
3
3
  /**
4
4
  * Prompt refinement ("did you mean this?").
@@ -11,23 +11,32 @@ function isTextBlock(b) {
11
11
  function toErrorMessage(err) {
12
12
  return err instanceof Error ? err.message : String(err);
13
13
  }
14
+ var textCache = /* @__PURE__ */ new Map();
15
+ var rootCandidates;
14
16
  function readBundledInstructionText(relativePath) {
17
+ const cached = textCache.get(relativePath);
18
+ if (cached !== void 0) return cached;
19
+ let resolved = "";
15
20
  for (const root of instructionRootCandidates()) {
16
21
  try {
17
- return readFileSync(path.join(root, relativePath), "utf8").trimEnd();
22
+ resolved = readFileSync(path.join(root, relativePath), "utf8").trimEnd();
23
+ break;
18
24
  } catch {
19
25
  }
20
26
  }
21
- return "";
27
+ textCache.set(relativePath, resolved);
28
+ return resolved;
22
29
  }
23
30
  function instructionRootCandidates() {
31
+ if (rootCandidates !== void 0) return rootCandidates;
24
32
  const here = path.dirname(fileURLToPath(import.meta.url));
25
33
  const candidates = [
26
34
  path.resolve(here, "../../instructions"),
27
35
  path.resolve(here, "../instructions"),
28
36
  path.resolve(here, "instructions")
29
37
  ];
30
- return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
38
+ rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
39
+ return rootCandidates;
31
40
  }
32
41
  function isDirectory(candidate) {
33
42
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/blocks.ts","../../src/utils/error.ts","../../src/utils/instruction-file.ts","../../src/execution/prompt-enhancer.ts"],"names":[],"mappings":"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","file":"prompt-enhancer.js","sourcesContent":["export interface TextBlock {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' | undefined };\n}\n\nexport interface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n /**\n * Provider-specific opaque metadata captured from the wire response.\n * Echoed back verbatim in the next request so providers that bind\n * extra state to function calls keep working. Example: Gemini's\n * `thoughtSignature` — required for tool-use turns with thinking\n * models, otherwise the next request fails with 400 \"Function call\n * is missing a thought_signature in functionCall parts\".\n *\n * Keys are namespaced by intent so multiple wires can coexist:\n * - `google.thoughtSignature` — Gemini signed-thought blob\n * Other providers can add their own keys without colliding.\n */\n providerMeta?: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n /**\n * The original tool name. Useful for providers like Google Gemini that\n * need the tool name in `functionResponse.name` — the tool_use_id is\n * only a session-local identifier and is not stable across replays.\n * Always set by ToolExecutor; may be absent on manually-constructed blocks.\n */\n name?: string | undefined;\n content: string;\n is_error?: boolean | undefined;\n}\n\nexport interface ImageBlock {\n type: 'image';\n source: {\n type: 'base64' | 'url';\n media_type?: string | undefined;\n data?: string | undefined;\n url?: string | undefined;\n };\n}\n\n/**\n * Chain-of-thought / extended-thinking content emitted by the model.\n *\n * Both Anthropic extended thinking (`{type:'thinking', thinking, signature}`)\n * and DeepSeek reasoning mode (top-level `reasoning_content` on the assistant\n * message) require this content to be echoed back verbatim on the next\n * request, otherwise the provider returns 400:\n * - Anthropic: \"The `content[].thinking` in the thinking mode must be passed back\"\n * - DeepSeek: \"The `reasoning_content` in the thinking mode must be passed back\"\n *\n * `signature` is Anthropic-specific (an opaque integrity blob). DeepSeek\n * doesn't issue a signature — the field is absent for that provider.\n *\n * Per Anthropic, thinking blocks MUST appear before any text/tool_use blocks\n * in an assistant message. Stream builders preserve that order.\n */\nexport interface ThinkingBlock {\n type: 'thinking';\n thinking: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ImageBlock | ThinkingBlock;\n\nexport function isTextBlock(b: ContentBlock): b is TextBlock {\n return b.type === 'text';\n}\nexport function isToolUseBlock(b: ContentBlock): b is ToolUseBlock {\n return b.type === 'tool_use';\n}\nexport function isToolResultBlock(b: ContentBlock): b is ToolResultBlock {\n return b.type === 'tool_result';\n}\nexport function isImageBlock(b: ContentBlock): b is ImageBlock {\n return b.type === 'image';\n}\nexport function isThinkingBlock(b: ContentBlock): b is ThinkingBlock {\n return b.type === 'thinking';\n}\n","/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport function readBundledInstructionText(relativePath: string): string {\n for (const root of instructionRootCandidates()) {\n try {\n return readFileSync(path.join(root, relativePath), 'utf8').trimEnd();\n } catch {\n // try next candidate\n }\n }\n return '';\n}\n\nexport function renderInstructionTemplate(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (match, key: string) =>\n Object.hasOwn(values, key) ? values[key] ?? '' : match,\n );\n}\n\nfunction instructionRootCandidates(): string[] {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../instructions'),\n path.resolve(here, '../instructions'),\n path.resolve(here, 'instructions'),\n ];\n return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n","import type { ContentBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport type {\n Provider,\n ReasoningConfig,\n ReasoningEffort,\n ReasoningRequest,\n Request,\n} from '../types/provider.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\n\n/**\n * Prompt refinement (\"did you mean this?\").\n *\n * Runs a one-shot LLM call in a SEPARATE context (its own system prompt, no\n * conversation history, no tools) that rewrites a raw user message into a\n * clearer, more complete instruction BEFORE the main agent sees it. The goal\n * is to make the main context start from a well-understood request rather than\n * guessing intent from terse input like \"fix the bug\".\n *\n * This mirrors `IntelligentCompactor.callSummarizer` — a plain\n * `provider.complete()` with a dedicated system prompt — and is deliberately\n * free of React / TUI dependencies so it can be unit-tested in isolation.\n */\n\nexport const ENHANCER_SYSTEM_PROMPT = readBundledInstructionText('llm/prompt-enhancer.md');\n\n/** Words/phrases that are control answers, not refinable requests. */\nconst AFFIRMATION_RE =\n /^(y|n|yes|no|yep|nope|ok|okay|sure|go|go ahead|continue|proceed|stop|cancel|done|next|skip|retry|again|please do|do it)\\b[.! ]*$/i;\n\n/**\n * Heuristic gate: should this raw input be sent through the refiner at all?\n * Pure + exported for unit testing. Returns false for inputs where refinement\n * is pointless or unwanted (slash commands, one-word affirmations, trivially\n * short text, bare numbers).\n */\nexport function shouldEnhance(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.startsWith('/')) return false; // slash command\n if (t.length < 12) return false; // too short to be worth refining\n if (AFFIRMATION_RE.test(t)) return false; // \"yes\" / \"continue\" / ...\n if (/^[\\d\\s.,]+$/.test(t)) return false; // bare numbers (menu picks, etc.)\n const words = t.split(/\\s+/).filter(Boolean);\n if (words.length < 3) return false; // 1–2 words rarely benefit\n return true;\n}\n\n/**\n * Preference order when picking an effort level: the cheapest level that still\n * does SOME reasoning first ('low', then 'minimal'), then up the ladder, with\n * fully-off ('none') last so it's only chosen when it's the sole advertised\n * option. This keeps the refiner cheap without dropping reasoning entirely when\n * a little still helps. 'low' leads because it's the most widely accepted low\n * level across adapters (e.g. OpenAI's reasoning_effort set).\n */\nconst EFFORT_PREFERENCE: ReasoningEffort[] = [\n 'low',\n 'minimal',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n 'none',\n];\n\n/**\n * Build a reasoning directive for the refiner that minimizes wasted thinking,\n * gated to what the model actually accepts. Refinement is a shallow rewrite\n * task — extended thinking adds latency and (hidden) token cost for little\n * gain — so we ask the model to spend as little reasoning as it safely can.\n *\n * The gating mirrors `resolveReasoningForRequest` so we never send a field the\n * model would reject:\n * - effort-capable model → its lowest advertised effort level;\n * - else disable-capable model → disable thinking (`enabled: false`);\n * - else (always-on / unknown) → `undefined` (leave the provider default).\n *\n * Returns `undefined` whenever nothing can be safely reduced. Callers forward\n * that verbatim to `enhanceUserPrompt`, which then sends no reasoning field —\n * identical to the behavior before this hint existed. Pure + exported for unit\n * testing.\n */\nexport function gatedEnhancerReasoning(\n rc: ReasoningConfig | undefined,\n): ReasoningRequest | undefined {\n // Capabilities unknown → don't risk an unsupported field (matches the\n // conservative \"capabilities unknown\" branch in resolveReasoningForRequest).\n if (!rc) return undefined;\n if (rc.effortSupported && rc.effortLevels.length > 0) {\n const lowest = EFFORT_PREFERENCE.find((e) => rc.effortLevels.includes(e)) ?? rc.effortLevels[0];\n if (lowest) return { effort: lowest };\n }\n if (rc.disableSupported) return { enabled: false };\n return undefined;\n}\n\n/**\n * Normalize for \"did the refiner actually change anything?\" comparison —\n * collapse whitespace and lowercase so trivial reformatting doesn't trigger\n * the confirmation panel.\n */\nexport function normalizedEqual(a: string, b: string): boolean {\n const norm = (s: string) => s.trim().replace(/\\s+/g, ' ').toLowerCase();\n return norm(a) === norm(b);\n}\n\n/** A single text-only conversation turn used as refiner context. */\nexport interface ConversationTurn {\n role: 'user' | 'assistant';\n text: string;\n}\n\n/**\n * Result of a successful prompt refinement. Carries the original-language and\n * English versions so the UI can offer both. When the input was already in\n * English the refiner emits a single version and both fields hold the same\n * text (the UI then offers two identical choices, which is correct).\n */\nexport interface EnhanceResult {\n /** Refined in the user's original language. */\n refined: string;\n /** Refined in English. Equals `refined` when the input was already English. */\n english: string;\n}\n\nexport interface EnhanceUserPromptOptions {\n provider: Provider;\n model: string;\n text: string;\n /**\n * Recent conversation turns (oldest→newest), text only, used purely as\n * CONTEXT so the refiner can resolve references in a follow-up message\n * (\"it\", \"the same\", \"that file\"). Without this, the refiner is blind to\n * the conversation and can only refine self-contained prompts. Build with\n * `recentTextTurns(ctx.messages)`.\n */\n history?: ConversationTurn[] | undefined;\n /** Parent abort signal (e.g. the run controller / Esc). */\n signal?: AbortSignal | undefined;\n /** Hard cap on how long to wait for the refiner before giving up. Default 90s. */\n timeoutMs?: number | undefined;\n /** Max tokens for the refined output. Default 2048. */\n maxTokens?: number | undefined;\n /**\n * Reasoning directive for the refiner call. Refinement is a shallow\n * restate-this-more-clearly task that does not benefit from extended\n * thinking, so callers pass a low-effort / thinking-disabled hint here to\n * cut latency and (hidden) reasoning-token cost — most impactful on slow\n * reasoning models. Build it with `gatedEnhancerReasoning(rc)` so the field\n * is gated to what the model accepts. Omit (undefined) to send no reasoning\n * directive at all (the provider's own default applies).\n */\n reasoning?: ReasoningRequest | undefined;\n /**\n * Called with a short reason when refinement fails (provider error, timeout,\n * empty response). NOT called when the caller cancels via `signal`. Lets the\n * UI surface *why* a refine fell through instead of a generic message.\n */\n onError?: ((reason: string) => void) | undefined;\n}\n\n/**\n * Compose the single user message sent to the refiner: the recent\n * conversation embedded as plain text (so we never trip provider\n * role-alternation rules) followed by the latest message to refine.\n */\nfunction buildRefinerInput(text: string, history?: ConversationTurn[]): string {\n if (!history || history.length === 0) return text;\n const lines = history.map((t) => `${t.role === 'user' ? 'User' : 'Assistant'}: ${t.text}`);\n return [\n 'Recent conversation (context only — do not act on it):',\n ...lines,\n '',\n 'Latest message to refine:',\n text,\n ].join('\\n');\n}\n\n/**\n * Refine a raw user prompt. Returns the refined text, or `null` when the\n * caller should fall back to the original (refiner errored, timed out, was\n * aborted, or returned nothing useful). NEVER throws — refinement is a\n * best-effort convenience and must never block the user from sending.\n */\nexport async function enhanceUserPrompt(\n opts: EnhanceUserPromptOptions,\n): Promise<EnhanceResult | null> {\n const { provider, model, text } = opts;\n // Reasoning models (\"thinking\" models like DeepSeek reasoner / o1) take\n // longer to first token, so give a generous default window.\n const timeoutMs = opts.timeoutMs ?? 90000;\n // Generous default: on some endpoints the model's hidden \"thinking\" tokens\n // count against this budget, so a small cap can leave NO room for the actual\n // refined text (→ empty completion → null). 2048 keeps the output room ample.\n const maxTokens = opts.maxTokens ?? 2048;\n\n const req: Request = {\n model,\n system: [{ type: 'text', text: ENHANCER_SYSTEM_PROMPT }],\n messages: [{ role: 'user', content: buildRefinerInput(text, opts.history) }],\n maxTokens,\n // NOTE: deliberately NO `temperature`. The main agent loop never sets it,\n // and reasoning models (DeepSeek reasoner, o1/o3, …) return HTTP 400 when\n // `temperature` is present — which would make every refine call fail and\n // silently fall back to the original (no panel shown).\n //\n // A reasoning hint is forwarded ONLY when the caller supplies one (it must\n // already be gated to the model's advertised support — see\n // `gatedEnhancerReasoning`). Absent it, no reasoning field is sent, which\n // is identical to the original behavior.\n ...(opts.reasoning ? { reasoning: opts.reasoning } : {}),\n };\n\n // Link a local timeout to the parent signal so a stuck provider call can't\n // hang the submit path. AbortSignal.any keeps both cancellation sources.\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('enhancer timeout')), timeoutMs);\n const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;\n\n try {\n const res = await provider.complete(req, { signal });\n const raw = res.content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim();\n if (!raw) {\n opts.onError?.('model returned no text');\n return null;\n }\n\n // English input → ONE version (no \"---\"); other languages → two versions\n // separated by a line with only \"---\". Split on the first occurrence so the\n // delimiter can still appear inside the second version's text.\n const sepIdx = raw.indexOf('\\n---\\n');\n if (sepIdx === -1) {\n // Single version: the input was already English (or the model chose not\n // to translate). Use it for both fields — the UI offers identical\n // \"refined\" / \"english\" options, which is correct and saves the model\n // from generating a redundant second copy. NOT an error.\n return { refined: raw, english: raw };\n }\n const refined = raw.slice(0, sepIdx).trim();\n const english = raw.slice(sepIdx + 5).trim(); // skip \"\\n---\\n\"\n if (!refined || !english) {\n opts.onError?.('one or both versions empty');\n return null;\n }\n return { refined, english };\n } catch (err) {\n // User-initiated cancel → stay silent (they chose to send the original).\n if (opts.signal?.aborted) return null;\n if (timer.signal.aborted) {\n opts.onError?.(`timed out after ${Math.round(timeoutMs / 1000)}s`);\n return null;\n }\n opts.onError?.(toErrorMessage(err));\n return null;\n } finally {\n // Idempotent — abort() after signal already fired is a no-op, so this is\n // always safe regardless of whether the timeout fired first.\n timer.abort();\n clearTimeout(to);\n }\n}\n\n/** Pull the visible text out of a message's content (ignores tool blocks). */\nfunction messageText(content: string | ContentBlock[]): string {\n if (typeof content === 'string') return content;\n return content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim();\n}\n\n/**\n * Extract the last few user/assistant TEXT turns from a conversation, newest\n * last, for use as refiner context. Skips system messages and tool-only turns\n * (tool_use / tool_result carry no useful natural-language context and bloat\n * the call). Each turn is truncated to `maxChars`; at most `maxTurns` are\n * returned. Pure + exported for unit testing.\n */\nexport function recentTextTurns(\n messages: Message[],\n maxTurns = 6,\n maxChars = 1500,\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n for (let i = messages.length - 1; i >= 0 && turns.length < maxTurns; i--) {\n const m = messages[i];\n if (!m || (m.role !== 'user' && m.role !== 'assistant')) continue;\n const text = messageText(m.content);\n if (!text) continue;\n turns.unshift({\n role: m.role,\n text: text.length > maxChars ? `${text.slice(0, maxChars - 1)}…` : text,\n });\n }\n return turns;\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/blocks.ts","../../src/utils/error.ts","../../src/utils/instruction-file.ts","../../src/execution/prompt-enhancer.ts"],"names":[],"mappings":"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","file":"prompt-enhancer.js","sourcesContent":["export interface TextBlock {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' | undefined };\n}\n\nexport interface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n /**\n * Provider-specific opaque metadata captured from the wire response.\n * Echoed back verbatim in the next request so providers that bind\n * extra state to function calls keep working. Example: Gemini's\n * `thoughtSignature` — required for tool-use turns with thinking\n * models, otherwise the next request fails with 400 \"Function call\n * is missing a thought_signature in functionCall parts\".\n *\n * Keys are namespaced by intent so multiple wires can coexist:\n * - `google.thoughtSignature` — Gemini signed-thought blob\n * Other providers can add their own keys without colliding.\n */\n providerMeta?: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n /**\n * The original tool name. Useful for providers like Google Gemini that\n * need the tool name in `functionResponse.name` — the tool_use_id is\n * only a session-local identifier and is not stable across replays.\n * Always set by ToolExecutor; may be absent on manually-constructed blocks.\n */\n name?: string | undefined;\n content: string;\n is_error?: boolean | undefined;\n}\n\nexport interface ImageBlock {\n type: 'image';\n source: {\n type: 'base64' | 'url';\n media_type?: string | undefined;\n data?: string | undefined;\n url?: string | undefined;\n };\n}\n\n/**\n * Chain-of-thought / extended-thinking content emitted by the model.\n *\n * Both Anthropic extended thinking (`{type:'thinking', thinking, signature}`)\n * and DeepSeek reasoning mode (top-level `reasoning_content` on the assistant\n * message) require this content to be echoed back verbatim on the next\n * request, otherwise the provider returns 400:\n * - Anthropic: \"The `content[].thinking` in the thinking mode must be passed back\"\n * - DeepSeek: \"The `reasoning_content` in the thinking mode must be passed back\"\n *\n * `signature` is Anthropic-specific (an opaque integrity blob). DeepSeek\n * doesn't issue a signature — the field is absent for that provider.\n *\n * Per Anthropic, thinking blocks MUST appear before any text/tool_use blocks\n * in an assistant message. Stream builders preserve that order.\n */\nexport interface ThinkingBlock {\n type: 'thinking';\n thinking: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ImageBlock | ThinkingBlock;\n\nexport function isTextBlock(b: ContentBlock): b is TextBlock {\n return b.type === 'text';\n}\nexport function isToolUseBlock(b: ContentBlock): b is ToolUseBlock {\n return b.type === 'tool_use';\n}\nexport function isToolResultBlock(b: ContentBlock): b is ToolResultBlock {\n return b.type === 'tool_result';\n}\nexport function isImageBlock(b: ContentBlock): b is ImageBlock {\n return b.type === 'image';\n}\n","/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Cache of resolved instruction text, keyed by the relative path. Bundled\n * instruction files are immutable for the process lifetime, so re-reading them\n * on every call (some callers do so per LLM request) is wasted disk I/O.\n */\nconst textCache = new Map<string, string>();\n\n/** Resolved once — the candidate roots only depend on this module's location. */\nlet rootCandidates: string[] | undefined;\n\nexport function readBundledInstructionText(relativePath: string): string {\n const cached = textCache.get(relativePath);\n if (cached !== undefined) return cached;\n\n let resolved = '';\n for (const root of instructionRootCandidates()) {\n try {\n resolved = readFileSync(path.join(root, relativePath), 'utf8').trimEnd();\n break;\n } catch {\n // try next candidate\n }\n }\n textCache.set(relativePath, resolved);\n return resolved;\n}\n\nexport function renderInstructionTemplate(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (match, key: string) =>\n Object.hasOwn(values, key) ? (values[key] ?? '') : match,\n );\n}\n\nfunction instructionRootCandidates(): string[] {\n if (rootCandidates !== undefined) return rootCandidates;\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../instructions'),\n path.resolve(here, '../instructions'),\n path.resolve(here, 'instructions'),\n ];\n rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n return rootCandidates;\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n","import type { ContentBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport type {\n Provider,\n ReasoningConfig,\n ReasoningEffort,\n ReasoningRequest,\n Request,\n} from '../types/provider.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\n\n/**\n * Prompt refinement (\"did you mean this?\").\n *\n * Runs a one-shot LLM call in a SEPARATE context (its own system prompt, no\n * conversation history, no tools) that rewrites a raw user message into a\n * clearer, more complete instruction BEFORE the main agent sees it. The goal\n * is to make the main context start from a well-understood request rather than\n * guessing intent from terse input like \"fix the bug\".\n *\n * This mirrors `IntelligentCompactor.callSummarizer` — a plain\n * `provider.complete()` with a dedicated system prompt — and is deliberately\n * free of React / TUI dependencies so it can be unit-tested in isolation.\n */\n\nexport const ENHANCER_SYSTEM_PROMPT = readBundledInstructionText('llm/prompt-enhancer.md');\n\n/** Words/phrases that are control answers, not refinable requests. */\nconst AFFIRMATION_RE =\n /^(y|n|yes|no|yep|nope|ok|okay|sure|go|go ahead|continue|proceed|stop|cancel|done|next|skip|retry|again|please do|do it)\\b[.! ]*$/i;\n\n/**\n * Heuristic gate: should this raw input be sent through the refiner at all?\n * Pure + exported for unit testing. Returns false for inputs where refinement\n * is pointless or unwanted (slash commands, one-word affirmations, trivially\n * short text, bare numbers).\n */\nexport function shouldEnhance(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.startsWith('/')) return false; // slash command\n if (t.length < 12) return false; // too short to be worth refining\n if (AFFIRMATION_RE.test(t)) return false; // \"yes\" / \"continue\" / ...\n if (/^[\\d\\s.,]+$/.test(t)) return false; // bare numbers (menu picks, etc.)\n const words = t.split(/\\s+/).filter(Boolean);\n if (words.length < 3) return false; // 1–2 words rarely benefit\n return true;\n}\n\n/**\n * Preference order when picking an effort level: the cheapest level that still\n * does SOME reasoning first ('low', then 'minimal'), then up the ladder, with\n * fully-off ('none') last so it's only chosen when it's the sole advertised\n * option. This keeps the refiner cheap without dropping reasoning entirely when\n * a little still helps. 'low' leads because it's the most widely accepted low\n * level across adapters (e.g. OpenAI's reasoning_effort set).\n */\nconst EFFORT_PREFERENCE: ReasoningEffort[] = [\n 'low',\n 'minimal',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n 'none',\n];\n\n/**\n * Build a reasoning directive for the refiner that minimizes wasted thinking,\n * gated to what the model actually accepts. Refinement is a shallow rewrite\n * task — extended thinking adds latency and (hidden) token cost for little\n * gain — so we ask the model to spend as little reasoning as it safely can.\n *\n * The gating mirrors `resolveReasoningForRequest` so we never send a field the\n * model would reject:\n * - effort-capable model → its lowest advertised effort level;\n * - else disable-capable model → disable thinking (`enabled: false`);\n * - else (always-on / unknown) → `undefined` (leave the provider default).\n *\n * Returns `undefined` whenever nothing can be safely reduced. Callers forward\n * that verbatim to `enhanceUserPrompt`, which then sends no reasoning field —\n * identical to the behavior before this hint existed. Pure + exported for unit\n * testing.\n */\nexport function gatedEnhancerReasoning(\n rc: ReasoningConfig | undefined,\n): ReasoningRequest | undefined {\n // Capabilities unknown → don't risk an unsupported field (matches the\n // conservative \"capabilities unknown\" branch in resolveReasoningForRequest).\n if (!rc) return undefined;\n if (rc.effortSupported && rc.effortLevels.length > 0) {\n const lowest = EFFORT_PREFERENCE.find((e) => rc.effortLevels.includes(e)) ?? rc.effortLevels[0];\n if (lowest) return { effort: lowest };\n }\n if (rc.disableSupported) return { enabled: false };\n return undefined;\n}\n\n/**\n * Normalize for \"did the refiner actually change anything?\" comparison —\n * collapse whitespace and lowercase so trivial reformatting doesn't trigger\n * the confirmation panel.\n */\nexport function normalizedEqual(a: string, b: string): boolean {\n const norm = (s: string) => s.trim().replace(/\\s+/g, ' ').toLowerCase();\n return norm(a) === norm(b);\n}\n\n/** A single text-only conversation turn used as refiner context. */\nexport interface ConversationTurn {\n role: 'user' | 'assistant';\n text: string;\n}\n\n/**\n * Result of a successful prompt refinement. Carries the original-language and\n * English versions so the UI can offer both. When the input was already in\n * English the refiner emits a single version and both fields hold the same\n * text (the UI then offers two identical choices, which is correct).\n */\nexport interface EnhanceResult {\n /** Refined in the user's original language. */\n refined: string;\n /** Refined in English. Equals `refined` when the input was already English. */\n english: string;\n}\n\nexport interface EnhanceUserPromptOptions {\n provider: Provider;\n model: string;\n text: string;\n /**\n * Recent conversation turns (oldest→newest), text only, used purely as\n * CONTEXT so the refiner can resolve references in a follow-up message\n * (\"it\", \"the same\", \"that file\"). Without this, the refiner is blind to\n * the conversation and can only refine self-contained prompts. Build with\n * `recentTextTurns(ctx.messages)`.\n */\n history?: ConversationTurn[] | undefined;\n /** Parent abort signal (e.g. the run controller / Esc). */\n signal?: AbortSignal | undefined;\n /** Hard cap on how long to wait for the refiner before giving up. Default 90s. */\n timeoutMs?: number | undefined;\n /** Max tokens for the refined output. Default 2048. */\n maxTokens?: number | undefined;\n /**\n * Reasoning directive for the refiner call. Refinement is a shallow\n * restate-this-more-clearly task that does not benefit from extended\n * thinking, so callers pass a low-effort / thinking-disabled hint here to\n * cut latency and (hidden) reasoning-token cost — most impactful on slow\n * reasoning models. Build it with `gatedEnhancerReasoning(rc)` so the field\n * is gated to what the model accepts. Omit (undefined) to send no reasoning\n * directive at all (the provider's own default applies).\n */\n reasoning?: ReasoningRequest | undefined;\n /**\n * Called with a short reason when refinement fails (provider error, timeout,\n * empty response). NOT called when the caller cancels via `signal`. Lets the\n * UI surface *why* a refine fell through instead of a generic message.\n */\n onError?: ((reason: string) => void) | undefined;\n}\n\n/**\n * Compose the single user message sent to the refiner: the recent\n * conversation embedded as plain text (so we never trip provider\n * role-alternation rules) followed by the latest message to refine.\n */\nfunction buildRefinerInput(text: string, history?: ConversationTurn[]): string {\n if (!history || history.length === 0) return text;\n const lines = history.map((t) => `${t.role === 'user' ? 'User' : 'Assistant'}: ${t.text}`);\n return [\n 'Recent conversation (context only — do not act on it):',\n ...lines,\n '',\n 'Latest message to refine:',\n text,\n ].join('\\n');\n}\n\n/**\n * Refine a raw user prompt. Returns the refined text, or `null` when the\n * caller should fall back to the original (refiner errored, timed out, was\n * aborted, or returned nothing useful). NEVER throws — refinement is a\n * best-effort convenience and must never block the user from sending.\n */\nexport async function enhanceUserPrompt(\n opts: EnhanceUserPromptOptions,\n): Promise<EnhanceResult | null> {\n const { provider, model, text } = opts;\n // Reasoning models (\"thinking\" models like DeepSeek reasoner / o1) take\n // longer to first token, so give a generous default window.\n const timeoutMs = opts.timeoutMs ?? 90000;\n // Generous default: on some endpoints the model's hidden \"thinking\" tokens\n // count against this budget, so a small cap can leave NO room for the actual\n // refined text (→ empty completion → null). 2048 keeps the output room ample.\n const maxTokens = opts.maxTokens ?? 2048;\n\n const req: Request = {\n model,\n system: [{ type: 'text', text: ENHANCER_SYSTEM_PROMPT }],\n messages: [{ role: 'user', content: buildRefinerInput(text, opts.history) }],\n maxTokens,\n // NOTE: deliberately NO `temperature`. The main agent loop never sets it,\n // and reasoning models (DeepSeek reasoner, o1/o3, …) return HTTP 400 when\n // `temperature` is present — which would make every refine call fail and\n // silently fall back to the original (no panel shown).\n //\n // A reasoning hint is forwarded ONLY when the caller supplies one (it must\n // already be gated to the model's advertised support — see\n // `gatedEnhancerReasoning`). Absent it, no reasoning field is sent, which\n // is identical to the original behavior.\n ...(opts.reasoning ? { reasoning: opts.reasoning } : {}),\n };\n\n // Link a local timeout to the parent signal so a stuck provider call can't\n // hang the submit path. AbortSignal.any keeps both cancellation sources.\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('enhancer timeout')), timeoutMs);\n const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;\n\n try {\n const res = await provider.complete(req, { signal });\n const raw = res.content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim();\n if (!raw) {\n opts.onError?.('model returned no text');\n return null;\n }\n\n // English input → ONE version (no \"---\"); other languages → two versions\n // separated by a line with only \"---\". Split on the first occurrence so the\n // delimiter can still appear inside the second version's text.\n const sepIdx = raw.indexOf('\\n---\\n');\n if (sepIdx === -1) {\n // Single version: the input was already English (or the model chose not\n // to translate). Use it for both fields — the UI offers identical\n // \"refined\" / \"english\" options, which is correct and saves the model\n // from generating a redundant second copy. NOT an error.\n return { refined: raw, english: raw };\n }\n const refined = raw.slice(0, sepIdx).trim();\n const english = raw.slice(sepIdx + 5).trim(); // skip \"\\n---\\n\"\n if (!refined || !english) {\n opts.onError?.('one or both versions empty');\n return null;\n }\n return { refined, english };\n } catch (err) {\n // User-initiated cancel → stay silent (they chose to send the original).\n if (opts.signal?.aborted) return null;\n if (timer.signal.aborted) {\n opts.onError?.(`timed out after ${Math.round(timeoutMs / 1000)}s`);\n return null;\n }\n opts.onError?.(toErrorMessage(err));\n return null;\n } finally {\n // Idempotent — abort() after signal already fired is a no-op, so this is\n // always safe regardless of whether the timeout fired first.\n timer.abort();\n clearTimeout(to);\n }\n}\n\n/** Pull the visible text out of a message's content (ignores tool blocks). */\nfunction messageText(content: string | ContentBlock[]): string {\n if (typeof content === 'string') return content;\n return content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim();\n}\n\n/**\n * Extract the last few user/assistant TEXT turns from a conversation, newest\n * last, for use as refiner context. Skips system messages and tool-only turns\n * (tool_use / tool_result carry no useful natural-language context and bloat\n * the call). Each turn is truncated to `maxChars`; at most `maxTurns` are\n * returned. Pure + exported for unit testing.\n */\nexport function recentTextTurns(\n messages: Message[],\n maxTurns = 6,\n maxChars = 1500,\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n for (let i = messages.length - 1; i >= 0 && turns.length < maxTurns; i--) {\n const m = messages[i];\n if (!m || (m.role !== 'user' && m.role !== 'assistant')) continue;\n const text = messageText(m.content);\n if (!text) continue;\n turns.unshift({\n role: m.role,\n text: text.length > maxChars ? `${text.slice(0, maxChars - 1)}…` : text,\n });\n }\n return turns;\n}\n"]}
@@ -1,10 +1,10 @@
1
- export { j as AfterIterationHook, k as AfterRunHook, l as AfterToolExecutionHook, i as AgentExtension, B as BeforeIterationHook, m as BeforeRunHook, n as BeforeToolExecutionHook, E as ExtensionRegistry, O as OnErrorHook, v as ProviderRunnerFn, t as ProviderRunnerWrapper } from '../index-kidebiDh.js';
2
- import '../tool-BkOgs_KL.js';
1
+ export { j as AfterIterationHook, k as AfterRunHook, l as AfterToolExecutionHook, i as AgentExtension, B as BeforeIterationHook, m as BeforeRunHook, n as BeforeToolExecutionHook, E as ExtensionRegistry, O as OnErrorHook, v as ProviderRunnerFn, t as ProviderRunnerWrapper } from '../index-C1E-_71T.js';
2
+ import '../tool-LVSLiE1s.js';
3
3
  import '../logger-B63L5bTg.js';
4
- import '../pipeline-BwAP21_4.js';
4
+ import '../pipeline-E7_jqGyV.js';
5
5
  import '../mailbox-types-BGZWrYTJ.js';
6
- import '../config-Cr3312zc.js';
7
- import '../permission-Dx6dIqS2.js';
6
+ import '../config-CN-vdDEI.js';
7
+ import '../permission-B6YAtNFz.js';
8
8
  import '../observability-D-HZN_mF.js';
9
- import '../events-Bs2fmldo.js';
9
+ import '../events-C5hLU0AT.js';
10
10
  import '../secret-scrubber-3MHDDAtm.js';
@@ -1,5 +1,5 @@
1
1
  import { M as MailboxMessage, a as MailboxAgentStatus, b as Mailbox, c as MailboxSendInput, d as MailboxQuery, e as MailboxAckInput, f as MailboxAckBatchInput, A as AgentRegistrationInput, g as AgentHeartbeatInput, C as ClientRegistrationInput, h as ClientHeartbeatInput, i as ClientStatus, P as PurgeOptions, j as PurgeResult } from './mailbox-types-BGZWrYTJ.js';
2
- import { E as EventBus } from './events-Bs2fmldo.js';
2
+ import { E as EventBus } from './events-C5hLU0AT.js';
3
3
 
4
4
  declare const HQ_PROTOCOL_VERSION: 1;
5
5
  type HqProtocolVersion = typeof HQ_PROTOCOL_VERSION;
@@ -691,9 +691,12 @@ declare class HqPublisher {
691
691
  }): HqEventEnvelope<HqFleetSnapshotPayload>;
692
692
  pollCommands(): void;
693
693
  ackCommand(result: HqPublisherCommandResult): void;
694
- private sendHello;
694
+ private createHelloFrame;
695
+ private sendHelloNow;
695
696
  private sendFrame;
696
697
  private enqueue;
698
+ /** Batch-dequeue up to 50 frames at a time, yielding to the microtask
699
+ * queue between batches so we don't starve the event loop on reconnect. */
697
700
  private flushQueue;
698
701
  private startCommandPolling;
699
702
  private stopCommandPolling;
@@ -1,4 +1,4 @@
1
- import { E as EventBus } from './events-Bs2fmldo.js';
1
+ import { E as EventBus } from './events-C5hLU0AT.js';
2
2
 
3
3
  /**
4
4
  * Long-running autonomous mission. A goal survives across sessions and
@@ -1,10 +1,10 @@
1
- import { $ as HqRedactionPolicy, t as HqEventEnvelope, W as HqPublisher, p as HqClientIdentity, ac as HqSocketFactory, i as HqClientCapability, X as HqPublisherCommandHandler, G as GlobalMailbox, ab as HqSnapshot, _ as HqQueuedCommand, c as HqAlertMessage, aj as HqTranscriptEntry } from '../global-mailbox-Ct7IorLJ.js';
2
- export { D as DEFAULT_HQ_REDACTION_POLICY, H as HQ_PROTOCOL_VERSION, a as HqAgentMessagePayload, b as HqAgentStatusPayload, d as HqBrainEventKind, e as HqBrainEventPayload, f as HqBrowserEventMessage, g as HqBrowserMessage, h as HqBrowserSnapshotMessage, j as HqClientCommandAckMessage, k as HqClientCommandPollMessage, l as HqClientEventMessage, m as HqClientHeartbeatPayload, n as HqClientHelloMessage, o as HqClientHelloPayload, q as HqClientKind, r as HqClientMessage, s as HqClientRecord, u as HqEventPayloadResult, v as HqEventType, w as HqFleetEventPayload, x as HqFleetSnapshotPayload, y as HqFleetSummary, z as HqGitSnapshotPayload, A as HqMachineRecord, B as HqMailboxAgentStatus, C as HqMailboxAgentSummary, E as HqMailboxEventAction, F as HqMailboxEventPayload, I as HqMailboxMappingOptions, J as HqMailboxMessageSummary, K as HqMailboxMessageType, L as HqMailboxPriority, M as HqMailboxSnapshotOptions, N as HqMailboxSnapshotPayload, O as HqMailboxSummary, P as HqParseResult, Q as HqPathPolicy, R as HqProjectIdentity, S as HqProjectRecord, T as HqProjectStatus, U as HqProtocolVersion, V as HqPublishEventOptions, Y as HqPublisherCommandResult, Z as HqPublisherOptions, a0 as HqServerCommandBatchMessage, a1 as HqServerMessage, a2 as HqSessionAgentLiveStatus, a3 as HqSessionAgentSummary, a4 as HqSessionEndedPayload, a5 as HqSessionLiveStatus, a6 as HqSessionSnapshotPayload, a7 as HqSessionStartedPayload, a8 as HqSessionStatus, a9 as HqSessionStatusPayload, aa as HqSessionSummary, ad as HqSocketLike, ae as HqSubagentSummary, af as HqToolArgsPolicy, ag as HqToolCompletedPayload, ah as HqToolStartedPayload, ai as HqTranscriptAppendPayload, ak as HqTranscriptRole, al as HqUsagePayload, am as HqWelcomePayload, an as HqWorklistCounts, ao as HqWorklistSnapshotPayload, ap as HqWorkspaceKind, aq as HqWorktreeEventKind, ar as HqWorktreeEventPayload, as as createHqEventEnvelope, at as createMailboxEventPayload, au as createMailboxSnapshotPayload, av as createMailboxSnapshotPayloadFromMailbox, aw as mapMailboxAgentToHqSummary, ax as mapMailboxMessageToHqSummary, ay as parseHqEventPayload, az as parseHqFrame } from '../global-mailbox-Ct7IorLJ.js';
3
- import { E as EventBus, T as TrackedAgentSnapshot } from '../events-Bs2fmldo.js';
4
- import { G as HqClientConfig } from '../config-Cr3312zc.js';
1
+ import { $ as HqRedactionPolicy, t as HqEventEnvelope, W as HqPublisher, p as HqClientIdentity, ac as HqSocketFactory, i as HqClientCapability, X as HqPublisherCommandHandler, G as GlobalMailbox, ab as HqSnapshot, _ as HqQueuedCommand, c as HqAlertMessage, aj as HqTranscriptEntry } from '../global-mailbox-CHM1QkCi.js';
2
+ export { D as DEFAULT_HQ_REDACTION_POLICY, H as HQ_PROTOCOL_VERSION, a as HqAgentMessagePayload, b as HqAgentStatusPayload, d as HqBrainEventKind, e as HqBrainEventPayload, f as HqBrowserEventMessage, g as HqBrowserMessage, h as HqBrowserSnapshotMessage, j as HqClientCommandAckMessage, k as HqClientCommandPollMessage, l as HqClientEventMessage, m as HqClientHeartbeatPayload, n as HqClientHelloMessage, o as HqClientHelloPayload, q as HqClientKind, r as HqClientMessage, s as HqClientRecord, u as HqEventPayloadResult, v as HqEventType, w as HqFleetEventPayload, x as HqFleetSnapshotPayload, y as HqFleetSummary, z as HqGitSnapshotPayload, A as HqMachineRecord, B as HqMailboxAgentStatus, C as HqMailboxAgentSummary, E as HqMailboxEventAction, F as HqMailboxEventPayload, I as HqMailboxMappingOptions, J as HqMailboxMessageSummary, K as HqMailboxMessageType, L as HqMailboxPriority, M as HqMailboxSnapshotOptions, N as HqMailboxSnapshotPayload, O as HqMailboxSummary, P as HqParseResult, Q as HqPathPolicy, R as HqProjectIdentity, S as HqProjectRecord, T as HqProjectStatus, U as HqProtocolVersion, V as HqPublishEventOptions, Y as HqPublisherCommandResult, Z as HqPublisherOptions, a0 as HqServerCommandBatchMessage, a1 as HqServerMessage, a2 as HqSessionAgentLiveStatus, a3 as HqSessionAgentSummary, a4 as HqSessionEndedPayload, a5 as HqSessionLiveStatus, a6 as HqSessionSnapshotPayload, a7 as HqSessionStartedPayload, a8 as HqSessionStatus, a9 as HqSessionStatusPayload, aa as HqSessionSummary, ad as HqSocketLike, ae as HqSubagentSummary, af as HqToolArgsPolicy, ag as HqToolCompletedPayload, ah as HqToolStartedPayload, ai as HqTranscriptAppendPayload, ak as HqTranscriptRole, al as HqUsagePayload, am as HqWelcomePayload, an as HqWorklistCounts, ao as HqWorklistSnapshotPayload, ap as HqWorkspaceKind, aq as HqWorktreeEventKind, ar as HqWorktreeEventPayload, as as createHqEventEnvelope, at as createMailboxEventPayload, au as createMailboxSnapshotPayload, av as createMailboxSnapshotPayloadFromMailbox, aw as mapMailboxAgentToHqSummary, ax as mapMailboxMessageToHqSummary, ay as parseHqEventPayload, az as parseHqFrame } from '../global-mailbox-CHM1QkCi.js';
3
+ import { E as EventBus, T as TrackedAgentSnapshot } from '../events-C5hLU0AT.js';
4
+ import { K as HqClientConfig } from '../config-CN-vdDEI.js';
5
5
  import '../mailbox-types-BGZWrYTJ.js';
6
- import '../tool-BkOgs_KL.js';
7
- import '../permission-Dx6dIqS2.js';
6
+ import '../tool-LVSLiE1s.js';
7
+ import '../permission-B6YAtNFz.js';
8
8
 
9
9
  interface HqRedactOptions {
10
10
  policy?: Partial<HqRedactionPolicy>;
package/dist/hq/index.js CHANGED
@@ -826,7 +826,9 @@ var DEFAULT_COMMAND_POLL_LIMIT = 25;
826
826
  function defaultSocketFactory(url) {
827
827
  const WebSocketCtor = globalThis.WebSocket;
828
828
  if (WebSocketCtor === void 0) {
829
- throw new Error("No global WebSocket implementation is available; provide HqPublisherOptions.socketFactory.");
829
+ throw new Error(
830
+ "No global WebSocket implementation is available; provide HqPublisherOptions.socketFactory."
831
+ );
830
832
  }
831
833
  return new WebSocketCtor(url);
832
834
  }
@@ -857,7 +859,12 @@ var HqPublisher = class {
857
859
  this.socketFactory = options.socketFactory ?? defaultSocketFactory;
858
860
  this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
859
861
  this.idFactory = options.idFactory ?? randomUUID;
860
- this.capabilities = options.capabilities ?? ["telemetry.publish", "mailbox.summary", "fleet.summary", "session.summary"];
862
+ this.capabilities = options.capabilities ?? [
863
+ "telemetry.publish",
864
+ "mailbox.summary",
865
+ "fleet.summary",
866
+ "session.summary"
867
+ ];
861
868
  this.reconnect = options.reconnect ?? true;
862
869
  this.reconnectBaseMs = options.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;
863
870
  this.reconnectMaxMs = options.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;
@@ -906,7 +913,7 @@ var HqPublisher = class {
906
913
  this.socket = socket;
907
914
  const onOpen = () => {
908
915
  this.reconnectAttempt = 0;
909
- this.sendHello();
916
+ this.sendHelloNow();
910
917
  this.flushQueue();
911
918
  if (this.options.onCommand !== void 0) {
912
919
  this.startCommandPolling();
@@ -1051,8 +1058,8 @@ var HqPublisher = class {
1051
1058
  ...result.message !== void 0 ? { message: result.message } : {}
1052
1059
  });
1053
1060
  }
1054
- sendHello() {
1055
- this.sendFrame({
1061
+ createHelloFrame() {
1062
+ return {
1056
1063
  type: "client.hello",
1057
1064
  payload: {
1058
1065
  protocolVersion: HQ_PROTOCOL_VERSION,
@@ -1060,12 +1067,20 @@ var HqPublisher = class {
1060
1067
  project: this.options.project,
1061
1068
  capabilities: this.capabilities
1062
1069
  }
1063
- });
1070
+ };
1071
+ }
1072
+ sendHelloNow() {
1073
+ const socket = this.socket;
1074
+ if (socket?.readyState !== OPEN_STATE) {
1075
+ this.sendFrame(this.createHelloFrame());
1076
+ return;
1077
+ }
1078
+ socket.send(JSON.stringify(this.createHelloFrame()));
1064
1079
  }
1065
1080
  sendFrame(frame) {
1066
1081
  const serialized = JSON.stringify(frame);
1067
1082
  const socket = this.socket;
1068
- if (socket?.readyState === OPEN_STATE) {
1083
+ if (socket?.readyState === OPEN_STATE && this.queue.length === 0) {
1069
1084
  socket.send(serialized);
1070
1085
  return;
1071
1086
  }
@@ -1076,16 +1091,21 @@ var HqPublisher = class {
1076
1091
  if (this.queue.length >= this.maxQueuedMessages) this.queue.shift();
1077
1092
  this.queue.push(serialized);
1078
1093
  }
1094
+ /** Batch-dequeue up to 50 frames at a time, yielding to the microtask
1095
+ * queue between batches so we don't starve the event loop on reconnect. */
1079
1096
  flushQueue() {
1080
1097
  const socket = this.socket;
1081
- if (socket?.readyState !== OPEN_STATE) return;
1082
- const pending = this.queue;
1083
- this.queue = [];
1084
- for (const frame of pending) socket.send(frame);
1098
+ if (socket?.readyState !== OPEN_STATE || this.queue.length === 0) return;
1099
+ const batch = this.queue.splice(0, 50);
1100
+ for (const frame of batch) socket.send(frame);
1101
+ if (this.queue.length > 0) setImmediate(() => this.flushQueue());
1085
1102
  }
1086
1103
  startCommandPolling() {
1087
1104
  if (this.options.onCommand === void 0 || this.commandPollTimer !== null) return;
1088
- this.commandPollTimer = setInterval(() => this.pollCommands(), this.options.commandPollIntervalMs ?? DEFAULT_COMMAND_POLL_INTERVAL_MS);
1105
+ this.commandPollTimer = setInterval(
1106
+ () => this.pollCommands(),
1107
+ this.options.commandPollIntervalMs ?? DEFAULT_COMMAND_POLL_INTERVAL_MS
1108
+ );
1089
1109
  this.commandPollTimer.unref?.();
1090
1110
  }
1091
1111
  stopCommandPolling() {
@@ -1127,7 +1147,8 @@ var HqPublisher = class {
1127
1147
  try {
1128
1148
  const result = await handler(command);
1129
1149
  if (result !== void 0) this.ackCommand(result);
1130
- else if (command.requiresAck) this.ackCommand({ commandId: command.commandId, status: "accepted" });
1150
+ else if (command.requiresAck)
1151
+ this.ackCommand({ commandId: command.commandId, status: "accepted" });
1131
1152
  } catch (err) {
1132
1153
  this.ackCommand({
1133
1154
  commandId: command.commandId,
@@ -1241,6 +1262,7 @@ function resolveWstackPaths(opts) {
1241
1262
  projectHash: hash,
1242
1263
  projectSlug: slug,
1243
1264
  projectGoal: path2.join(projectDir, "goal.json"),
1265
+ projectInputHistory: path2.join(projectDir, "input-history.json"),
1244
1266
  projectSpecs: path2.join(projectDir, "specs"),
1245
1267
  projectTaskGraphs: path2.join(projectDir, "task-graphs"),
1246
1268
  projectSddSession: path2.join(projectDir, "sdd-session.json"),