@wrongstack/runtime 0.275.0 → 0.276.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { Config, WstackPaths, Logger, ModelsRegistry, EventBus, Tool, DefaultSys
4
4
  export { DefaultSystemPromptBuilder, DefaultSystemPromptBuilderOptions } from '@wrongstack/core';
5
5
  export { WrongStackPack } from './pack.js';
6
6
  export { AppliedPack, ApplyPackOptions, RuntimeHost, RuntimeHostParts, applyWrongStackPack, applyWrongStackPacks, createRuntimeHostFromParts } from './host.js';
7
- export { ImageInputUnsupportedError, ToolVisionAdapterOptions, VisionAdapter, VisionAdapterInput, VisionAdapters, VisionRoutingOptions, VisionRoutingResult, createToolVisionAdapters, routeImagesForModel } from './vision.js';
7
+ export { ImageInputUnsupportedError, ToolVisionAdapterOptions, VisionAdapter, VisionAdapterInput, VisionAdapters, VisionRoutingOptions, VisionRoutingResult, VisionUrlBlockedError, createToolVisionAdapters, routeImagesForModel } from './vision.js';
8
8
  export { ClipboardImage, readClipboardImage, readClipboardText } from './clipboard.js';
9
9
 
10
10
  interface CreateContainerOptions {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from '@wrongstack/core/defaults';
2
2
  export { DefaultPathResolver, DefaultTokenCounter } from '@wrongstack/core/infrastructure';
3
- import { Container, DefaultConfigStore, TOKENS, DefaultSecretScrubber, DefaultRetryPolicy, DefaultErrorHandler, buildRecoveryStrategies, DefaultTokenCounter, DefaultModeStore, DefaultSessionStore, DefaultMemoryStore, DefaultSkillLoader, DefaultPromptLoader, DefaultSystemPromptBuilder, DefaultPermissionPolicy, createStrategyCompactor, buildChildEnv, EventBus, resolveModelMatrix, resolveModelTargetFromEntry, ToolRegistry, Context, WIDE_SUBAGENT_CAPABILITIES, AutoApprovePermissionPolicy, ToolExecutor, Agent, createDefaultPipelines, createFallbackModelExtension } from '@wrongstack/core';
3
+ import { Container, DefaultConfigStore, TOKENS, DefaultSecretScrubber, DefaultRetryPolicy, DefaultErrorHandler, buildRecoveryStrategies, DefaultTokenCounter, DefaultModeStore, DefaultSessionStore, DefaultMemoryStore, DefaultSkillLoader, DefaultPromptLoader, DefaultSystemPromptBuilder, DefaultPermissionPolicy, createStrategyCompactor, assertNotPrivateHost, buildChildEnv, EventBus, resolveModelMatrix, resolveModelTargetFromEntry, ToolRegistry, Context, WIDE_SUBAGENT_CAPABILITIES, AutoApprovePermissionPolicy, ToolExecutor, Agent, createDefaultPipelines, createFallbackModelExtension } from '@wrongstack/core';
4
4
  export { DefaultSystemPromptBuilder } from '@wrongstack/core';
5
5
  import * as fs2 from 'fs/promises';
6
6
  import * as os2 from 'os';
@@ -140,7 +140,7 @@ function createDefaultContainer(opts) {
140
140
  container.bind(TOKENS.ModelsRegistry, () => modelsRegistry);
141
141
  container.bind(
142
142
  TOKENS.TokenCounter,
143
- () => new DefaultTokenCounter({ registry: modelsRegistry, providerId: config.provider })
143
+ () => new DefaultTokenCounter({ registry: modelsRegistry, providerId: config.provider, events: opts.events })
144
144
  );
145
145
  const modeStore = new DefaultModeStore({ directory: wpaths.configDir });
146
146
  container.bind(TOKENS.ModeStore, () => modeStore);
@@ -218,6 +218,14 @@ var ImageInputUnsupportedError = class extends Error {
218
218
  this.name = "ImageInputUnsupportedError";
219
219
  }
220
220
  };
221
+ var VisionUrlBlockedError = class extends Error {
222
+ url;
223
+ constructor(opts) {
224
+ super(`vision: blocked unsafe image URL "${opts.url}" (${opts.reason})`);
225
+ this.name = "VisionUrlBlockedError";
226
+ this.url = opts.url;
227
+ }
228
+ };
221
229
  async function routeImagesForModel(blocks, opts) {
222
230
  const images = blocks.filter((b) => b.type === "image");
223
231
  if (images.length === 0) {
@@ -332,6 +340,14 @@ async function buildToolPayload(tool, image, prompt = "Describe this image for a
332
340
  const data = image.source.data;
333
341
  const url = image.source.url;
334
342
  let cleanup;
343
+ if (image.source.type === "url" && url) {
344
+ try {
345
+ await assertNotPrivateHost(new URL(url).hostname);
346
+ } catch (err) {
347
+ const reason = err instanceof Error && err.message.startsWith("fetch:") ? err.message.slice("fetch:".length).trim() : "unresolvable host";
348
+ throw new VisionUrlBlockedError({ url, reason });
349
+ }
350
+ }
335
351
  const pathKey = firstPresent(props, [
336
352
  "path",
337
353
  "image_path",
@@ -699,6 +715,6 @@ function cryptoId() {
699
715
  return crypto.randomUUID().slice(0, 8);
700
716
  }
701
717
 
702
- export { ImageInputUnsupportedError, applyWrongStackPack, applyWrongStackPacks, createDefaultContainer, createRuntimeHostFromParts, createToolVisionAdapters, makeLightSubagentFactory, readClipboardImage, readClipboardText, routeImagesForModel };
718
+ export { ImageInputUnsupportedError, VisionUrlBlockedError, applyWrongStackPack, applyWrongStackPacks, createDefaultContainer, createRuntimeHostFromParts, createToolVisionAdapters, makeLightSubagentFactory, readClipboardImage, readClipboardText, routeImagesForModel };
703
719
  //# sourceMappingURL=index.js.map
704
720
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/host.ts","../src/container.ts","../src/vision.ts","../src/clipboard.ts","../src/fleet/light-subagent-factory.ts"],"names":["fs","os","path2","TOKENS"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n Agent,\n Context,\n EventBus,\n ExtensionRegistry,\n PluginAPI,\n ProviderRegistry,\n SessionWriter,\n SlashCommandRegistry,\n ToolRegistry,\n} from '@wrongstack/core';\nimport type { WrongStackPack } from './pack.js';\n\nexport interface RuntimeHost {\n agent: Agent;\n context: Context;\n events: EventBus;\n tools: ToolRegistry;\n providers: ProviderRegistry;\n slashCommands: SlashCommandRegistry;\n session: SessionWriter;\n extensions?: ExtensionRegistry | undefined;\n shutdown(): Promise<void>;\n}\n\nexport interface RuntimeHostParts {\n agent: Agent;\n context: Context;\n events: EventBus;\n tools: ToolRegistry;\n providers: ProviderRegistry;\n slashCommands: SlashCommandRegistry;\n session: SessionWriter;\n extensions?: ExtensionRegistry | undefined;\n shutdown?: (() => void | Promise<void>) | undefined;\n}\n\nexport function createRuntimeHostFromParts(parts: RuntimeHostParts): RuntimeHost {\n return {\n agent: parts.agent,\n context: parts.context,\n events: parts.events,\n tools: parts.tools,\n providers: parts.providers,\n slashCommands: parts.slashCommands,\n session: parts.session,\n extensions: parts.extensions,\n async shutdown() {\n await parts.shutdown?.();\n },\n };\n}\n\nexport interface ApplyPackOptions {\n owner?: string | undefined;\n api?: PluginAPI | undefined;\n}\n\nexport interface AppliedPack {\n pack: WrongStackPack;\n owner: string;\n teardown(): Promise<void>;\n}\n\nexport async function applyWrongStackPack(\n host: Pick<RuntimeHost, 'tools' | 'providers' | 'slashCommands'> & {\n extensions?: ExtensionRegistry | undefined;\n },\n pack: WrongStackPack,\n opts: ApplyPackOptions = {},\n): Promise<AppliedPack> {\n const owner = opts.owner ?? pack.name;\n const unregisterExtensions: Array<() => void> = [];\n\n // Track registered tool names, command names, and provider types so teardown\n // can reverse everything in registration order.\n const registeredToolNames: string[] = [];\n const registeredCommandNames: string[] = [];\n const registeredProviderTypes: string[] = [];\n\n if (pack.tools) {\n const tools = [...pack.tools];\n host.tools.registerAllOrThrow(tools, owner);\n for (const t of tools) registeredToolNames.push(t.name);\n }\n if (pack.providers) {\n const providers = [...pack.providers];\n host.providers.registerAll(providers);\n for (const p of providers) registeredProviderTypes.push(p.type);\n }\n if (pack.slashCommands) {\n const cmds = [...pack.slashCommands];\n host.slashCommands.registerAll(cmds, owner);\n for (const c of cmds) registeredCommandNames.push(c.name);\n }\n if (pack.extensions && host.extensions) {\n for (const ext of pack.extensions) {\n unregisterExtensions.push(host.extensions.register(ext));\n }\n }\n\n // If setup() throws after registration, roll back everything we registered above.\n // This makes applyWrongStackPack() transactional from the caller's perspective —\n // either the pack is fully applied or it is not.\n if (pack.setup) {\n if (!opts.api) {\n throw new Error(`Pack \"${pack.name}\" defines setup() but no PluginAPI was provided`);\n }\n try {\n await pack.setup(opts.api);\n } catch (setupErr) {\n // Roll back in reverse order: extensions first, then commands,\n // then tools, then providers. Extensions are unregistered before\n // tools/commands because extensions may depend on those capabilities;\n // tearing them down first avoids dangling refs.\n for (const unregister of unregisterExtensions.reverse()) {\n unregister();\n }\n for (const name of registeredCommandNames.reverse()) {\n host.slashCommands.unregister(name);\n }\n for (const name of registeredToolNames.reverse()) {\n host.tools.unregister(name);\n }\n for (const type of registeredProviderTypes.reverse()) {\n host.providers.unregister(type);\n }\n throw setupErr;\n }\n }\n\n return {\n pack,\n owner,\n async teardown() {\n for (const unregister of unregisterExtensions.reverse()) {\n unregister();\n }\n // Unregister commands, tools, and providers so the same pack can be\n // re-loaded cleanly without name/type conflicts.\n for (const name of registeredCommandNames.reverse()) {\n host.slashCommands.unregister(name);\n }\n for (const name of registeredToolNames.reverse()) {\n host.tools.unregister(name);\n }\n for (const type of registeredProviderTypes.reverse()) {\n host.providers.unregister(type);\n }\n if (pack.teardown) {\n if (!opts.api) {\n throw new Error(`Pack \"${pack.name}\" defines teardown() but no PluginAPI was provided`);\n }\n await pack.teardown(opts.api);\n }\n },\n };\n}\n\nexport async function applyWrongStackPacks(\n host: Pick<RuntimeHost, 'tools' | 'providers' | 'slashCommands'> & {\n extensions?: ExtensionRegistry | undefined;\n },\n packs: readonly WrongStackPack[],\n opts: ApplyPackOptions = {},\n): Promise<AppliedPack[]> {\n const applied: AppliedPack[] = [];\n try {\n for (const pack of packs) {\n applied.push(await applyWrongStackPack(host, pack, opts));\n }\n return applied;\n } catch (err) {\n // Roll back already-mounted packs. Surface teardown failures via\n // process.emitWarning so they don't mask the original error but\n // remain visible — a silent teardown failure can leave state\n // half-initialized in ways that make the next run fail mysteriously.\n for (const mounted of applied.reverse()) {\n await mounted.teardown().catch((teardownErr) => {\n const detail = teardownErr instanceof Error ? teardownErr.message : String(teardownErr);\n process.emitWarning(\n `Pack teardown during error rollback failed: ${detail}`,\n 'PackRollbackWarning',\n );\n });\n }\n throw err;\n }\n}\n","import {\n type Config,\n Container,\n DefaultConfigStore,\n DefaultErrorHandler,\n DefaultMemoryStore,\n DefaultModeStore,\n DefaultPermissionPolicy,\n DefaultRetryPolicy,\n DefaultPromptLoader,\n DefaultSecretScrubber,\n DefaultSessionStore,\n DefaultSkillLoader,\n DefaultSystemPromptBuilder,\n DefaultTokenCounter,\n type EventBus,\n createStrategyCompactor,\n buildRecoveryStrategies,\n type Logger,\n type ModelsRegistry,\n TOKENS,\n type Tool,\n type WstackPaths,\n} from '@wrongstack/core';\nimport type { DefaultSystemPromptBuilderOptions } from '@wrongstack/core';\n\nexport interface CreateContainerOptions {\n config: Config;\n wpaths: WstackPaths;\n logger: Logger;\n modelsRegistry: ModelsRegistry;\n /**\n * Optional event bus — passed to DefaultMemoryStore so plugins and\n * subsystems can react to memory mutations in real time.\n */\n events?: EventBus | undefined;\n permission?: {\n yolo?: boolean | undefined;\n yoloDestructive?: boolean | undefined;\n /** @deprecated Use `yoloDestructive`. */\n forceAllYolo?: boolean | undefined;\n /** When true, destructive ops prompt even in YOLO mode. */\n confirmDestructive?: boolean | undefined;\n promptDelegate?: (\n tool: Tool,\n input: unknown,\n suggestedPattern: string,\n ) => Promise<'yes' | 'no' | 'always' | 'deny'>;\n };\n compactor?: { preserveK?: number | undefined; eliseThreshold?: number | undefined };\n systemPrompt?: Partial<DefaultSystemPromptBuilderOptions> | undefined;\n /** Bundled skills directory path (resolved at boot time). */\n bundledSkillsDir?: string | undefined;\n /** Bundled prompt dataset directory path (`<core>/data/prompts`, resolved at boot). */\n bundledPromptsDir?: string | undefined;\n}\n\n/**\n * Create a Container pre-bound with all default service implementations.\n * Both CLI and WebUI use this factory so container wiring stays in one place.\n */\nexport function createDefaultContainer(opts: CreateContainerOptions): Container {\n const { config, wpaths, logger, modelsRegistry } = opts;\n const container = new Container();\n\n const configStore = new DefaultConfigStore(config);\n container.bind(TOKENS.ConfigStore, () => configStore);\n container.bind(TOKENS.Logger, () => logger);\n container.bind(TOKENS.SecretScrubber, () => new DefaultSecretScrubber());\n container.bind(TOKENS.RetryPolicy, () => new DefaultRetryPolicy());\n // Wire the compactor into the recovery chain so a 413 / context-overflow\n // response can shed tokens and retry. Without an explicit compactor the\n // default `context_overflow_reduce` strategy is a no-op. The Compactor\n // binding is resolved lazily (it is registered further below).\n container.bind(\n TOKENS.ErrorHandler,\n () =>\n new DefaultErrorHandler(\n buildRecoveryStrategies({\n compactor: container.resolve(TOKENS.Compactor),\n modelsRegistry,\n getConfig: () => configStore.get(),\n }),\n ),\n );\n container.bind(TOKENS.ModelsRegistry, () => modelsRegistry);\n container.bind(\n TOKENS.TokenCounter,\n () => new DefaultTokenCounter({ registry: modelsRegistry, providerId: config.provider }),\n );\n\n const modeStore = new DefaultModeStore({ directory: wpaths.configDir });\n container.bind(TOKENS.ModeStore, () => modeStore);\n container.bind(\n TOKENS.SessionStore,\n () =>\n new DefaultSessionStore({\n dir: wpaths.projectSessions,\n // Scrub secrets out of persisted user/model turns (F-06). Tool output\n // is already scrubbed by the executor.\n secretScrubber: container.resolve(TOKENS.SecretScrubber),\n }),\n );\n\n const memoryStore = new DefaultMemoryStore({ paths: wpaths, events: opts.events });\n container.bind(TOKENS.MemoryStore, () => memoryStore);\n\n const skillLoader = new DefaultSkillLoader({ paths: wpaths, bundledDir: opts.bundledSkillsDir });\n container.bind(TOKENS.SkillLoader, () => skillLoader);\n\n const promptLoader = new DefaultPromptLoader({ paths: wpaths, bundledDir: opts.bundledPromptsDir });\n container.bind(TOKENS.PromptLoader, () => promptLoader);\n\n if (opts.systemPrompt) {\n container.bind(\n TOKENS.SystemPromptBuilder,\n () =>\n new DefaultSystemPromptBuilder({\n instructionPaths: {\n globalDir: wpaths.globalInstructions,\n projectDir: wpaths.inProjectInstructions,\n },\n ...(opts.systemPrompt as DefaultSystemPromptBuilderOptions),\n }),\n );\n }\n\n container.bind(\n TOKENS.PermissionPolicy,\n () => {\n const policyOptions: ConstructorParameters<typeof DefaultPermissionPolicy>[0] = {\n trustFile: wpaths.projectTrust,\n yolo: opts.permission?.yolo ?? false,\n yoloDestructive: opts.permission?.yoloDestructive ?? opts.permission?.forceAllYolo ?? false,\n confirmDestructive: opts.permission?.confirmDestructive ?? false,\n };\n if (opts.permission?.promptDelegate !== undefined) {\n policyOptions.promptDelegate = opts.permission.promptDelegate;\n }\n return new DefaultPermissionPolicy(policyOptions);\n },\n );\n\n container.bind(\n TOKENS.Compactor,\n () =>\n // Strategy comes from config.context.strategy: 'hybrid' (default, lossless\n // rules, no LLM), 'intelligent' (LLM summarization), or 'selective'\n // (LLM-driven selection). The LLM strategies resolve their provider from\n // ctx at compact()-time, so binding here (before context.provider exists)\n // is safe. preserveK / eliseThreshold are class-level fallbacks; the active\n // ContextWindowPolicy in ctx.meta normally overrides both at runtime.\n // eliseThreshold is a TOKEN COUNT — a previous value of 0.7 elided\n // essentially every tool_result (anything > 1 token).\n createStrategyCompactor({\n strategy: config.context?.strategy,\n preserveK: opts.compactor?.preserveK ?? 10,\n eliseThreshold: opts.compactor?.eliseThreshold ?? 2000,\n smart: true,\n summarizerModel: config.context?.summarizerModel,\n llmSelector: config.context?.llmSelector,\n }),\n );\n\n return container;\n}\n","import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ContentBlock, Context, ImageBlock, Tool, ToolRegistry } from '@wrongstack/core';\n\nexport interface VisionAdapterInput {\n image: ImageBlock;\n prompt?: string | undefined;\n ctx: Context;\n signal: AbortSignal;\n}\n\nexport interface VisionAdapter {\n name: string;\n describe(input: VisionAdapterInput): Promise<string>;\n}\n\nexport type VisionAdapters =\n | readonly VisionAdapter[]\n | (() => readonly VisionAdapter[] | Promise<readonly VisionAdapter[]>);\n\nexport interface VisionRoutingOptions {\n supportsVision: boolean;\n adapters?: VisionAdapters | undefined;\n ctx: Context;\n signal: AbortSignal;\n prompt?: string | undefined;\n providerId?: string | undefined;\n model?: string | undefined;\n}\n\nexport interface VisionRoutingResult {\n blocks: ContentBlock[];\n route: 'native' | 'adapter' | 'none';\n convertedImages: number;\n adapterName?: string | undefined;\n}\n\nexport class ImageInputUnsupportedError extends Error {\n constructor(opts: { providerId?: string | undefined; model?: string | undefined; imageCount: number }) {\n const target = [opts.providerId, opts.model].filter(Boolean).join('/') || 'current model';\n super(\n `${target} does not support image input, and no image-understanding adapter is available for ${opts.imageCount} image${opts.imageCount === 1 ? '' : 's'}. Switch to a vision model or enable an MCP/tool adapter that can describe images.`,\n );\n this.name = 'ImageInputUnsupportedError';\n }\n}\n\nexport async function routeImagesForModel(\n blocks: ContentBlock[],\n opts: VisionRoutingOptions,\n): Promise<VisionRoutingResult> {\n const images = blocks.filter((b): b is ImageBlock => b.type === 'image');\n if (images.length === 0) {\n return { blocks, route: 'none', convertedImages: 0 };\n }\n if (opts.supportsVision) {\n return { blocks, route: 'native', convertedImages: 0 };\n }\n\n const adapters = await resolveAdapters(opts.adapters);\n if (adapters.length === 0) {\n throw new ImageInputUnsupportedError({\n providerId: opts.providerId,\n model: opts.model,\n imageCount: images.length,\n });\n }\n\n const out: ContentBlock[] = [];\n let convertedImages = 0;\n let lastErr: unknown;\n let adapterName: string | undefined;\n for (const block of blocks) {\n if (block.type !== 'image') {\n out.push(block);\n continue;\n }\n let description: string | undefined;\n for (const adapter of adapters) {\n try {\n description = await adapter.describe({\n image: block,\n prompt: opts.prompt,\n ctx: opts.ctx,\n signal: opts.signal,\n });\n adapterName = adapter.name;\n break;\n } catch (err) {\n lastErr = err;\n }\n }\n if (!description?.trim()) {\n throw new Error(\n `No image-understanding adapter could process an image.${lastErr instanceof Error ? ` Last error: ${lastErr.message}` : ''}`,\n );\n }\n convertedImages++;\n out.push({\n type: 'text',\n text: `[Image ${convertedImages} analyzed via ${adapterName ?? 'vision adapter'}]\\n${description.trim()}`,\n });\n }\n\n return { blocks: out, route: 'adapter', convertedImages, adapterName };\n}\n\nasync function resolveAdapters(adapters: VisionAdapters | undefined): Promise<readonly VisionAdapter[]> {\n if (!adapters) return [];\n return typeof adapters === 'function' ? await adapters() : adapters;\n}\n\nexport interface ToolVisionAdapterOptions {\n prompt?: string | undefined;\n}\n\nexport function createToolVisionAdapters(\n registry: ToolRegistry,\n opts: ToolVisionAdapterOptions = {},\n): VisionAdapter[] {\n return registry\n .list()\n .filter(isLikelyVisionTool)\n .map((tool) => ({\n name: tool.name,\n async describe(input: VisionAdapterInput): Promise<string> {\n const currentTool = registry.get(tool.name);\n if (!currentTool) {\n throw new Error(`Tool \"${tool.name}\" is no longer registered`);\n }\n const built = await buildToolPayload(currentTool, input.image, input.prompt ?? opts.prompt);\n if (!built) {\n throw new Error(`Tool \"${currentTool.name}\" does not expose a supported image input schema`);\n }\n try {\n const result = await currentTool.execute(built.payload, input.ctx, {\n signal: input.signal,\n });\n return stringifyToolResult(result);\n } finally {\n await built.cleanup?.();\n }\n },\n }));\n}\n\nfunction isLikelyVisionTool(tool: Tool): boolean {\n if (tool.permission !== 'auto' || tool.mutating) return false;\n const haystack = `${tool.name} ${tool.description ?? ''} ${tool.usageHint ?? ''}`.toLowerCase();\n if (/(generate|create|draw|paint|edit|upscale|remove|write|delete)/.test(haystack)) return false;\n if (!/(vision|image|screenshot|ocr|describe|analy[sz]e)/.test(haystack)) return false;\n const props = schemaProperties(tool);\n return [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n ].some((key) => key in props);\n}\n\nasync function buildToolPayload(\n tool: Tool,\n image: ImageBlock,\n prompt = 'Describe this image for a coding agent. Include visible text, UI state, errors, layout, and any details needed to answer the user.',\n): Promise<{ payload: Record<string, unknown>; cleanup?: () => Promise<void> } | null> {\n const props = schemaProperties(tool);\n const payload: Record<string, unknown> = {};\n const mediaType = image.source.media_type ?? 'image/png';\n const data = image.source.data;\n const url = image.source.url;\n let cleanup: (() => Promise<void>) | undefined;\n\n const pathKey = firstPresent(props, [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n ]);\n if (pathKey && image.source.type === 'base64' && data) {\n const p = await writeTempImage(data, mediaType);\n payload[pathKey] = p;\n cleanup = async () => {\n await fs.unlink(p).catch(() => undefined);\n await fs.rmdir(path.dirname(p)).catch(() => undefined);\n };\n } else if ('image' in props) {\n payload.image =\n image.source.type === 'base64'\n ? { type: 'base64', mediaType, media_type: mediaType, data }\n : { type: 'url', url };\n } else if (image.source.type === 'base64' && 'base64' in props) {\n payload.base64 = data;\n } else if (image.source.type === 'base64' && 'data' in props) {\n payload.data = data;\n } else if (image.source.type === 'url' && 'url' in props) {\n payload.url = url;\n } else if (image.source.type === 'url' && 'image_url' in props) {\n payload.image_url = url;\n } else if (image.source.type === 'url' && 'imageUrl' in props) {\n payload.imageUrl = url;\n } else {\n return null;\n }\n\n if ('mediaType' in props) payload.mediaType = mediaType;\n if ('mimeType' in props) payload.mimeType = mediaType;\n if ('media_type' in props) payload.media_type = mediaType;\n if ('prompt' in props) payload.prompt = prompt;\n if ('query' in props) payload.query = prompt;\n if ('instruction' in props) payload.instruction = prompt;\n const built: { payload: Record<string, unknown>; cleanup?: () => Promise<void> } = { payload };\n if (cleanup !== undefined) built.cleanup = cleanup;\n return built;\n}\n\nfunction firstPresent(props: Record<string, unknown>, keys: string[]): string | undefined {\n return keys.find((key) => key in props);\n}\n\nasync function writeTempImage(data: string, mediaType: string): Promise<string> {\n const ext = mediaType.includes('jpeg') || mediaType.includes('jpg') ? 'jpg' : 'png';\n const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'wstack-vision-'));\n const file = path.join(dir, `image.${ext}`);\n await fs.writeFile(file, data, 'base64');\n return file;\n}\n\nfunction schemaProperties(tool: Tool): Record<string, unknown> {\n const schema = tool.inputSchema;\n if (!schema || typeof schema !== 'object') return {};\n const props = (schema as { properties?: unknown | undefined }).properties;\n return props && typeof props === 'object' ? (props as Record<string, unknown>) : {};\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n return value\n .map((item) => {\n if (item && typeof item === 'object' && 'text' in item) {\n return String((item as { text?: unknown | undefined }).text ?? '');\n }\n return typeof item === 'string' ? item : JSON.stringify(item);\n })\n .join('\\n');\n }\n if (value && typeof value === 'object' && 'text' in value) {\n return String((value as { text?: unknown | undefined }).text ?? '');\n }\n return JSON.stringify(value);\n}\n","import { spawn } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { buildChildEnv } from '@wrongstack/core';\n\nexport interface ClipboardImage {\n base64: string;\n mediaType: 'image/png';\n bytes: number;\n}\n\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024;\n\nexport async function readClipboardImage(): Promise<ClipboardImage | null> {\n const platform = process.platform;\n if (platform === 'win32') return readWindows();\n if (platform === 'darwin') return readDarwin();\n if (platform === 'linux') return readLinux();\n return null;\n}\n\n/**\n * Read plain text from the system clipboard. Returns `null` when the clipboard\n * holds no text (or only an image), the read failed, or the platform is\n * unsupported. Used by the TUI's Ctrl+V handler: terminals in raw mode deliver\n * Ctrl+V to the app as a control byte rather than performing a native paste, so\n * we read the clipboard ourselves.\n */\nexport async function readClipboardText(): Promise<string | null> {\n const platform = process.platform;\n if (platform === 'win32') {\n // -Raw preserves embedded newlines; force UTF-8 so non-ASCII survives the\n // pipe. PowerShell appends one trailing newline to stdout — strip it.\n const ps =\n '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-Clipboard -Raw';\n const out = await runCmd('powershell', ['-NoProfile', '-Command', ps]);\n if (out == null) return null;\n const text = out.replace(/\\r?\\n$/, '');\n return text.length > 0 ? text : null;\n }\n if (platform === 'darwin') {\n const out = await runCmd('pbpaste', []);\n return out && out.length > 0 ? out : null;\n }\n if (platform === 'linux') {\n const tries: Array<[string, string[]]> = [\n ['wl-paste', ['--no-newline']],\n ['xclip', ['-selection', 'clipboard', '-o']],\n ];\n for (const [cmd, args] of tries) {\n const out = await runCmd(cmd, args);\n if (out && out.length > 0) return out;\n }\n return null;\n }\n return null;\n}\n\nasync function readWindows(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const ps = [\n 'Add-Type -AssemblyName System.Windows.Forms',\n 'Add-Type -AssemblyName System.Drawing',\n '$img = [System.Windows.Forms.Clipboard]::GetImage()',\n 'if ($img -eq $null) { Write-Output \"NO_IMAGE\"; exit 0 }',\n `$img.Save('${tmp.replace(/\\\\/g, '\\\\\\\\')}', [System.Drawing.Imaging.ImageFormat]::Png)`,\n 'Write-Output \"OK\"',\n ].join('; ');\n const out = await runCmd('powershell', ['-NoProfile', '-Command', ps]);\n if (!out || out.trim() === 'NO_IMAGE') return null;\n if (!out.includes('OK')) return null;\n return readPngFile(tmp);\n}\n\nasync function readDarwin(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const script = [\n 'try',\n ` set the_file to (open for access POSIX file \"${tmp}\" with write permission)`,\n ' write (the clipboard as «class PNGf») to the_file',\n ' close access the_file',\n 'on error',\n ' try',\n ' close access POSIX file \"' + tmp + '\"',\n ' end try',\n ' return \"NO_IMAGE\"',\n 'end try',\n 'return \"OK\"',\n ].join('\\n');\n const out = await runCmd('osascript', ['-e', script]);\n if (out?.trim() !== 'OK') return null;\n return readPngFile(tmp);\n}\n\nasync function readLinux(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const tries: Array<[string, string[]]> = [\n ['wl-paste', ['--type', 'image/png']],\n ['xclip', ['-selection', 'clipboard', '-t', 'image/png', '-o']],\n ];\n for (const [cmd, args] of tries) {\n const ok = await runCmdToFile(cmd, args, tmp).catch(() => false);\n if (ok) return readPngFile(tmp);\n }\n return null;\n}\n\nasync function readPngFile(p: string): Promise<ClipboardImage | null> {\n try {\n const buf = await fs.readFile(p);\n if (buf.length === 0) {\n await fs.unlink(p).catch(() => undefined);\n return null;\n }\n if (buf.length > MAX_IMAGE_BYTES) {\n await fs.unlink(p).catch(() => undefined);\n throw new Error(`Clipboard image exceeds ${MAX_IMAGE_BYTES / 1024 / 1024}MB limit`);\n }\n if (buf[0] !== 0x89 || buf[1] !== 0x50 || buf[2] !== 0x4e || buf[3] !== 0x47) {\n await fs.unlink(p).catch(() => undefined);\n return null;\n }\n await fs.unlink(p).catch(() => undefined);\n return { base64: buf.toString('base64'), mediaType: 'image/png', bytes: buf.length };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n/**\n * Hard ceiling for a clipboard subprocess. Reading the clipboard must never\n * hang the TUI: on a headless/loaded CI runner the PowerShell/xclip/wl-paste\n * read can stall indefinitely (no display, slow shell start). After this we\n * kill the child and resolve the safe default.\n */\nconst CLIPBOARD_CMD_TIMEOUT_MS = 5_000;\n\nfunction runCmd(cmd: string, args: string[]): Promise<string | null> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n let out = '';\n let settled = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n };\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n finish(null);\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => finish(code === 0 ? out : null));\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n const chunks: Buffer[] = [];\n let settled = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n };\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n finish(false);\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (code !== 0 || chunks.length === 0) return finish(false);\n try {\n await fs.writeFile(outPath, Buffer.concat(chunks));\n finish(true);\n } catch {\n finish(false);\n }\n });\n });\n}\n","// makeLightSubagentFactory — a dependency-light `AgentFactory` that builds a\n// fresh, isolated `Agent` per subagent task WITHOUT the full director / budget /\n// ACP machinery of the CLI's `MultiAgentHost`.\n//\n// Why this exists: `MultiAgentHost` lives in `@wrongstack/cli`, which the WebUI\n// packages cannot import (layer rule: webui ⇏ cli). But `SddParallelRun` only\n// needs an `AgentFactory` (a core interface) to run real parallel waves with\n// per-task git-worktree isolation. This factory provides exactly that, built\n// from primitives both webui servers already have (a DI container + the provider\n// and tool registries + a session writer). It deliberately does NOT touch the\n// budget/watchdog/director subsystems — those stay owned by the CLI host.\n//\n// Each call constructs a fresh `Context` + `EventBus` (true isolation) and\n// honours `SubagentConfig.cwd` so per-task worktrees don't collide. Subagents\n// cannot answer interactive permission prompts, so they run under an\n// `AutoApprovePermissionPolicy` granted the wide work capabilities (fs.write,\n// shell, …) — the user authorised the work when they pressed \"Start Run\".\n\nimport {\n Agent,\n AutoApprovePermissionPolicy,\n type AgentFactory,\n type AgentFactoryResult,\n type Config,\n type Container,\n Context,\n createDefaultPipelines,\n createFallbackModelExtension,\n EventBus,\n resolveModelMatrix,\n resolveModelTargetFromEntry,\n type ProviderRegistry,\n type SessionWriter,\n type SubagentConfig,\n type TextBlock,\n type Tool,\n ToolExecutor,\n ToolRegistry,\n TOKENS,\n WIDE_SUBAGENT_CAPABILITIES,\n} from '@wrongstack/core';\n\nexport interface LightSubagentFactoryDeps {\n /** DI container — used to resolve configStore / tokenCounter / scrubber / prompt builder. */\n container: Container;\n /** Provider registry (already populated by the host) used to build per-subagent providers. */\n providerRegistry: ProviderRegistry;\n /** Full tool registry — each subagent gets an isolated clone of it. */\n toolRegistry: ToolRegistry;\n /** Parent session writer; subagent events are interleaved via a guarded shim. */\n session: SessionWriter;\n /** Project root anchor. */\n projectRoot: string;\n /** Default cwd when a SubagentConfig doesn't pin one (worktree path otherwise). */\n cwd?: string | undefined;\n}\n\n/**\n * Build a default subagent baseline so a leaf worker knows it's running under a\n * run, not as the user-facing leader. Kept terse — the system-prompt builder\n * already supplies identity/tools/skills when `subagent: true`.\n */\nconst SUBAGENT_BASELINE =\n 'You are a subagent executing one delegated task end-to-end. Work autonomously with your tools; do not ask for confirmation on routine in-project actions. Keep output concise.';\n\n// Slot in ctx.meta where the per-subagent AbortController is stored.\n// Callers retrieve it via abortLightSubagent(agent).\nconst _SUBAGENT_ABORT = 'wrongstack:subagent-abort-controller';\n\n/**\n * Retrieve and abort a light subagent's AbortController (stored in ctx.meta\n * by makeLightSubagentFactory). Idempotent — calling abort() on an already-aborted\n * signal is a no-op.\n */\nexport function abortLightSubagent(agent: Agent): void {\n const ac = agent.ctx.meta[_SUBAGENT_ABORT] as AbortController | undefined;\n ac?.abort();\n}\n\nexport function makeLightSubagentFactory(deps: LightSubagentFactoryDeps): AgentFactory {\n const configStore = deps.container.resolve(TOKENS.ConfigStore);\n const tokenCounter = deps.container.resolve(TOKENS.TokenCounter);\n const secretScrubber = deps.container.resolve(TOKENS.SecretScrubber);\n const systemPromptBuilder = deps.container.resolve(TOKENS.SystemPromptBuilder);\n\n return async (subCfg: SubagentConfig): Promise<AgentFactoryResult> => {\n const events = new EventBus();\n const config = configStore.get();\n\n const matrixEntry = subCfg.model\n ? undefined\n : resolveModelMatrix(config.modelMatrix, subCfg.role);\n const matrixTarget = resolveModelTargetFromEntry(config, matrixEntry);\n const effProvider = subCfg.provider ?? matrixTarget?.provider ?? config.provider;\n const effModel = subCfg.model ?? matrixTarget?.model ?? config.model;\n const provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n\n const subCwd = subCfg.cwd ?? deps.cwd ?? deps.projectRoot;\n\n // Isolated tool registry per subagent: the run wraps this factory with\n // `withDisabledToolFiltering`, which unregister()s tools (e.g. delegate) on\n // the agent's registry — that must never mutate the shared parent registry.\n const allowed = filterToolList(deps.toolRegistry, subCfg.tools);\n const subRegistry = new ToolRegistry();\n for (const t of allowed) subRegistry.register(t);\n\n const baseSystem: TextBlock[] = await systemPromptBuilder.build({\n cwd: subCwd,\n projectRoot: deps.projectRoot,\n tools: allowed,\n model: effModel,\n provider: effProvider,\n subagent: true,\n });\n baseSystem.unshift({ type: 'text', text: SUBAGENT_BASELINE });\n if (subCfg.systemPromptOverride) {\n baseSystem.push({ type: 'text', text: subCfg.systemPromptOverride });\n }\n\n const agentName = subCfg.name ?? subCfg.id ?? `sub_${cryptoId()}`;\n const session = makeSubagentSessionShim(deps.session);\n\n // Keep the AbortController reference so callers can abort this subagent's\n // work. Stored with a symbol key so it is opaque to general-purpose consumers.\n const ac = new AbortController();\n const ctx = new Context({\n systemPrompt: baseSystem,\n provider,\n session,\n signal: ac.signal,\n tokenCounter,\n cwd: subCwd,\n projectRoot: deps.projectRoot,\n allowOutsideProjectRoot:\n config.features?.allowOutsideProjectRoot ?? !(config.tools?.restrictToProjectRoot ?? false),\n model: effModel,\n tools: allowed,\n agentId: agentName,\n agentName,\n });\n if (subCfg.role) ctx.meta['agentRole'] = subCfg.role;\n // Store the AbortController so abortLightSubagent() can retrieve it.\n (ctx.meta[_SUBAGENT_ABORT] as AbortController) = ac;\n\n // Subagents can't answer prompts — auto-approve the wide work capability set\n // (the spawn site may narrow it via allowedCapabilities). `source: 'yolo'`\n // from this policy is the authoritative-auto waiver the ToolExecutor trusts\n // for dangerous caps (fs.write, shell), so code edits actually go through.\n const caps = subCfg.allowedCapabilities ?? WIDE_SUBAGENT_CAPABILITIES;\n const permissionPolicy = new AutoApprovePermissionPolicy(caps);\n\n const toolExecutor = new ToolExecutor(subRegistry, {\n permissionPolicy,\n secretScrubber,\n events,\n confirmAwaiter: undefined,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? 120_000,\n perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? 100_000,\n tracer: undefined,\n });\n\n const agent = new Agent({\n container: deps.container,\n tools: subRegistry,\n providers: deps.providerRegistry,\n events,\n pipelines: createDefaultPipelines(),\n context: ctx,\n permissionPolicy,\n toolExecutor,\n });\n\n // Fallback chain for THIS worker: a per-task `fallbackModels` (set in the\n // WebUI) overrides the live config's chain; otherwise the config's explicit\n // list or smart default applies. Without this a 429/529/5xx on a worker's\n // model — after its own retries — fails the task instead of rotating. Mirrors\n // the CLI host factory so both surfaces behave identically.\n const subFallbacks = subCfg.fallbackModels;\n const matrixFallbacks = matrixTarget?.fallbackModels;\n agent.extensions.register(\n createFallbackModelExtension({\n getConfig: () => {\n const live = configStore.get();\n if (subFallbacks && subFallbacks.length) return { ...live, fallbackModels: subFallbacks };\n if (matrixFallbacks && matrixFallbacks.length) return { ...live, fallbackModels: matrixFallbacks };\n return live;\n },\n buildProvider: (id) => buildProvider(deps.providerRegistry, configStore.get(), id, effModel),\n events,\n }),\n );\n\n return { agent, events };\n };\n}\n\n// ── helpers ──────────────────────────────────────────────────────────────────\n\nfunction filterToolList(registry: ToolRegistry, allow?: string[]): Tool[] {\n const all = registry.list();\n if (!allow || allow.length === 0) return all;\n const allowSet = new Set(allow);\n return all.filter((t) => allowSet.has(t.name));\n}\n\nfunction buildProvider(\n registry: ProviderRegistry,\n config: Config,\n providerId: string,\n model: string,\n): ReturnType<ProviderRegistry['create']> {\n const providerConfig = config.providers?.[providerId] ?? {\n type: providerId,\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n };\n if (!registry.has(providerId)) {\n throw new Error(\n `No provider factory registered for \"${providerId}\" — cannot build a subagent provider for the SDD run.`,\n );\n }\n return registry.create({ ...providerConfig, type: providerId, model });\n}\n\n/**\n * Guarded SessionWriter shim that interleaves subagent events into the parent\n * JSONL while NEVER touching checkpoint / in-flight / lifecycle state — those\n * belong to the parent and a subagent writing them would corrupt the parent's\n * rewind + crash-recovery markers. Mirrors the CLI host's fallback shim.\n */\nfunction makeSubagentSessionShim(parent: SessionWriter): SessionWriter {\n return {\n id: parent.id,\n transcriptPath: parent.transcriptPath,\n get pendingToolUses(): string[] {\n return [];\n },\n append: (ev) => parent.append({ ...ev }),\n appendBatch: (evs) => parent.appendBatch(evs.map((e) => ({ ...e }))),\n flush: () => parent.flush(),\n close: async () => {},\n recordFileChange: () => {},\n recordSideEffect: () => {},\n writeCheckpoint: async () => {},\n writeFileSnapshot: async () => {},\n truncateToCheckpoint: async () => 0,\n clearSession: async () => {},\n writeInFlightMarker: async () => {},\n clearInFlightMarker: async () => {},\n } satisfies SessionWriter;\n}\n\nfunction cryptoId(): string {\n return crypto.randomUUID().slice(0, 8);\n}\n"]}
1
+ {"version":3,"sources":["../src/host.ts","../src/container.ts","../src/vision.ts","../src/clipboard.ts","../src/fleet/light-subagent-factory.ts"],"names":["fs","os","path2","TOKENS"],"mappings":";;;;;;;;;;;;;AAqCO,SAAS,2BAA2B,KAAA,EAAsC;AAC/E,EAAA,OAAO;AAAA,IACL,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,eAAe,KAAA,CAAM,aAAA;AAAA,IACrB,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,MAAM,QAAA,GAAW;AACf,MAAA,MAAM,MAAM,QAAA,IAAW;AAAA,IACzB;AAAA,GACF;AACF;AAaA,eAAsB,mBAAA,CACpB,IAAA,EAGA,IAAA,EACA,IAAA,GAAyB,EAAC,EACJ;AACtB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,IAAA;AACjC,EAAA,MAAM,uBAA0C,EAAC;AAIjD,EAAA,MAAM,sBAAgC,EAAC;AACvC,EAAA,MAAM,yBAAmC,EAAC;AAC1C,EAAA,MAAM,0BAAoC,EAAC;AAE3C,EAAA,IAAI,KAAK,KAAA,EAAO;AACd,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAA,CAAK,KAAK,CAAA;AAC5B,IAAA,IAAA,CAAK,KAAA,CAAM,kBAAA,CAAmB,KAAA,EAAO,KAAK,CAAA;AAC1C,IAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,mBAAA,CAAoB,IAAA,CAAK,EAAE,IAAI,CAAA;AAAA,EACxD;AACA,EAAA,IAAI,KAAK,SAAA,EAAW;AAClB,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAA,CAAK,SAAS,CAAA;AACpC,IAAA,IAAA,CAAK,SAAA,CAAU,YAAY,SAAS,CAAA;AACpC,IAAA,KAAA,MAAW,CAAA,IAAK,SAAA,EAAW,uBAAA,CAAwB,IAAA,CAAK,EAAE,IAAI,CAAA;AAAA,EAChE;AACA,EAAA,IAAI,KAAK,aAAA,EAAe;AACtB,IAAA,MAAM,IAAA,GAAO,CAAC,GAAG,IAAA,CAAK,aAAa,CAAA;AACnC,IAAA,IAAA,CAAK,aAAA,CAAc,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AAC1C,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,EAAM,sBAAA,CAAuB,IAAA,CAAK,EAAE,IAAI,CAAA;AAAA,EAC1D;AACA,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,UAAA,EAAY;AACtC,IAAA,KAAA,MAAW,GAAA,IAAO,KAAK,UAAA,EAAY;AACjC,MAAA,oBAAA,CAAqB,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,QAAA,CAAS,GAAG,CAAC,CAAA;AAAA,IACzD;AAAA,EACF;AAKA,EAAA,IAAI,KAAK,KAAA,EAAO;AACd,IAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,+CAAA,CAAiD,CAAA;AAAA,IACrF;AACA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AAAA,IAC3B,SAAS,QAAA,EAAU;AAKjB,MAAA,KAAA,MAAW,UAAA,IAAc,oBAAA,CAAqB,OAAA,EAAQ,EAAG;AACvD,QAAA,UAAA,EAAW;AAAA,MACb;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,sBAAA,CAAuB,OAAA,EAAQ,EAAG;AACnD,QAAA,IAAA,CAAK,aAAA,CAAc,WAAW,IAAI,CAAA;AAAA,MACpC;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,mBAAA,CAAoB,OAAA,EAAQ,EAAG;AAChD,QAAA,IAAA,CAAK,KAAA,CAAM,WAAW,IAAI,CAAA;AAAA,MAC5B;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,uBAAA,CAAwB,OAAA,EAAQ,EAAG;AACpD,QAAA,IAAA,CAAK,SAAA,CAAU,WAAW,IAAI,CAAA;AAAA,MAChC;AACA,MAAA,MAAM,QAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAM,QAAA,GAAW;AACf,MAAA,KAAA,MAAW,UAAA,IAAc,oBAAA,CAAqB,OAAA,EAAQ,EAAG;AACvD,QAAA,UAAA,EAAW;AAAA,MACb;AAGA,MAAA,KAAA,MAAW,IAAA,IAAQ,sBAAA,CAAuB,OAAA,EAAQ,EAAG;AACnD,QAAA,IAAA,CAAK,aAAA,CAAc,WAAW,IAAI,CAAA;AAAA,MACpC;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,mBAAA,CAAoB,OAAA,EAAQ,EAAG;AAChD,QAAA,IAAA,CAAK,KAAA,CAAM,WAAW,IAAI,CAAA;AAAA,MAC5B;AACA,MAAA,KAAA,MAAW,IAAA,IAAQ,uBAAA,CAAwB,OAAA,EAAQ,EAAG;AACpD,QAAA,IAAA,CAAK,SAAA,CAAU,WAAW,IAAI,CAAA;AAAA,MAChC;AACA,MAAA,IAAI,KAAK,QAAA,EAAU;AACjB,QAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACb,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,kDAAA,CAAoD,CAAA;AAAA,QACxF;AACA,QAAA,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,MAC9B;AAAA,IACF;AAAA,GACF;AACF;AAEA,eAAsB,oBAAA,CACpB,IAAA,EAGA,KAAA,EACA,IAAA,GAAyB,EAAC,EACF;AACxB,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,IAAI;AACF,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,OAAA,CAAQ,KAAK,MAAM,mBAAA,CAAoB,IAAA,EAAM,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IAC1D;AACA,IAAA,OAAO,OAAA;AAAA,EACT,SAAS,GAAA,EAAK;AAKZ,IAAA,KAAA,MAAW,OAAA,IAAW,OAAA,CAAQ,OAAA,EAAQ,EAAG;AACvC,MAAA,MAAM,OAAA,CAAQ,QAAA,EAAS,CAAE,KAAA,CAAM,CAAC,WAAA,KAAgB;AAC9C,QAAA,MAAM,SAAS,WAAA,YAAuB,KAAA,GAAQ,WAAA,CAAY,OAAA,GAAU,OAAO,WAAW,CAAA;AACtF,QAAA,OAAA,CAAQ,WAAA;AAAA,UACN,+CAA+C,MAAM,CAAA,CAAA;AAAA,UACrD;AAAA,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AC/HO,SAAS,uBAAuB,IAAA,EAAyC;AAC9E,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,gBAAe,GAAI,IAAA;AACnD,EAAA,MAAM,SAAA,GAAY,IAAI,SAAA,EAAU;AAEhC,EAAA,MAAM,WAAA,GAAc,IAAI,kBAAA,CAAmB,MAAM,CAAA;AACjD,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,WAAA,EAAa,MAAM,WAAW,CAAA;AACpD,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,MAAM,MAAM,CAAA;AAC1C,EAAA,SAAA,CAAU,KAAK,MAAA,CAAO,cAAA,EAAgB,MAAM,IAAI,uBAAuB,CAAA;AACvE,EAAA,SAAA,CAAU,KAAK,MAAA,CAAO,WAAA,EAAa,MAAM,IAAI,oBAAoB,CAAA;AAKjE,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,MAAA,CAAO,YAAA;AAAA,IACP,MACE,IAAI,mBAAA;AAAA,MACF,uBAAA,CAAwB;AAAA,QACtB,SAAA,EAAW,SAAA,CAAU,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA;AAAA,QAC7C,cAAA;AAAA,QACA,SAAA,EAAW,MAAM,WAAA,CAAY,GAAA;AAAI,OAClC;AAAA;AACH,GACJ;AACA,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,cAAA,EAAgB,MAAM,cAAc,CAAA;AAC1D,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,MAAA,CAAO,YAAA;AAAA,IACP,MAAM,IAAI,mBAAA,CAAoB,EAAE,QAAA,EAAU,cAAA,EAAgB,UAAA,EAAY,MAAA,CAAO,QAAA,EAAU,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ;AAAA,GAC9G;AAEA,EAAA,MAAM,YAAY,IAAI,gBAAA,CAAiB,EAAE,SAAA,EAAW,MAAA,CAAO,WAAW,CAAA;AACtE,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,SAAA,EAAW,MAAM,SAAS,CAAA;AAChD,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,MAAA,CAAO,YAAA;AAAA,IACP,MACE,IAAI,mBAAA,CAAoB;AAAA,MACtB,KAAK,MAAA,CAAO,eAAA;AAAA;AAAA;AAAA,MAGZ,cAAA,EAAgB,SAAA,CAAU,OAAA,CAAQ,MAAA,CAAO,cAAc;AAAA,KACxD;AAAA,GACL;AAEA,EAAA,MAAM,WAAA,GAAc,IAAI,kBAAA,CAAmB,EAAE,OAAO,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,CAAA;AACjF,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,WAAA,EAAa,MAAM,WAAW,CAAA;AAEpD,EAAA,MAAM,WAAA,GAAc,IAAI,kBAAA,CAAmB,EAAE,OAAO,MAAA,EAAQ,UAAA,EAAY,IAAA,CAAK,gBAAA,EAAkB,CAAA;AAC/F,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,WAAA,EAAa,MAAM,WAAW,CAAA;AAEpD,EAAA,MAAM,YAAA,GAAe,IAAI,mBAAA,CAAoB,EAAE,OAAO,MAAA,EAAQ,UAAA,EAAY,IAAA,CAAK,iBAAA,EAAmB,CAAA;AAClG,EAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,YAAA,EAAc,MAAM,YAAY,CAAA;AAEtD,EAAA,IAAI,KAAK,YAAA,EAAc;AACrB,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,MAAA,CAAO,mBAAA;AAAA,MACP,MACE,IAAI,0BAAA,CAA2B;AAAA,QAC7B,gBAAA,EAAkB;AAAA,UAChB,WAAW,MAAA,CAAO,kBAAA;AAAA,UAClB,YAAY,MAAA,CAAO;AAAA,SACrB;AAAA,QACA,GAAI,IAAA,CAAK;AAAA,OACV;AAAA,KACL;AAAA,EACF;AAEA,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,MAAA,CAAO,gBAAA;AAAA,IACP,MAAM;AACJ,MAAA,MAAM,aAAA,GAA0E;AAAA,QAC9E,WAAW,MAAA,CAAO,YAAA;AAAA,QAClB,IAAA,EAAM,IAAA,CAAK,UAAA,EAAY,IAAA,IAAQ,KAAA;AAAA,QAC/B,iBAAiB,IAAA,CAAK,UAAA,EAAY,eAAA,IAAmB,IAAA,CAAK,YAAY,YAAA,IAAgB,KAAA;AAAA,QACtF,kBAAA,EAAoB,IAAA,CAAK,UAAA,EAAY,kBAAA,IAAsB;AAAA,OAC7D;AACA,MAAA,IAAI,IAAA,CAAK,UAAA,EAAY,cAAA,KAAmB,MAAA,EAAW;AACjD,QAAA,aAAA,CAAc,cAAA,GAAiB,KAAK,UAAA,CAAW,cAAA;AAAA,MACjD;AACA,MAAA,OAAO,IAAI,wBAAwB,aAAa,CAAA;AAAA,IAClD;AAAA,GACF;AAEA,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,MAAA,CAAO,SAAA;AAAA,IACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASE,uBAAA,CAAwB;AAAA,QACtB,QAAA,EAAU,OAAO,OAAA,EAAS,QAAA;AAAA,QAC1B,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,SAAA,IAAa,EAAA;AAAA,QACxC,cAAA,EAAgB,IAAA,CAAK,SAAA,EAAW,cAAA,IAAkB,GAAA;AAAA,QAClD,KAAA,EAAO,IAAA;AAAA,QACP,eAAA,EAAiB,OAAO,OAAA,EAAS,eAAA;AAAA,QACjC,WAAA,EAAa,OAAO,OAAA,EAAS;AAAA,OAC9B;AAAA;AAAA,GACL;AAEA,EAAA,OAAO,SAAA;AACT;AC9HO,IAAM,0BAAA,GAAN,cAAyC,KAAA,CAAM;AAAA,EACpD,YAAY,IAAA,EAA2F;AACrG,IAAA,MAAM,MAAA,GAAS,CAAC,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,eAAA;AAC1E,IAAA,KAAA;AAAA,MACE,CAAA,EAAG,MAAM,CAAA,mFAAA,EAAsF,IAAA,CAAK,UAAU,SAAS,IAAA,CAAK,UAAA,KAAe,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,kFAAA;AAAA,KACzJ;AACA,IAAA,IAAA,CAAK,IAAA,GAAO,4BAAA;AAAA,EACd;AACF;AAYO,IAAM,qBAAA,GAAN,cAAoC,KAAA,CAAM;AAAA,EACtC,GAAA;AAAA,EAET,YAAY,IAAA,EAAuC;AACjD,IAAA,KAAA,CAAM,qCAAqC,IAAA,CAAK,GAAG,CAAA,GAAA,EAAM,IAAA,CAAK,MAAM,CAAA,CAAA,CAAG,CAAA;AACvE,IAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AACZ,IAAA,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA;AAAA,EAClB;AACF;AAEA,eAAsB,mBAAA,CACpB,QACA,IAAA,EAC8B;AAC9B,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAuB,CAAA,CAAE,SAAS,OAAO,CAAA;AACvE,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,iBAAiB,CAAA,EAAE;AAAA,EACrD;AACA,EAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,IAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAU,iBAAiB,CAAA,EAAE;AAAA,EACvD;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,IAAA,CAAK,QAAQ,CAAA;AACpD,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,MAAM,IAAI,0BAAA,CAA2B;AAAA,MACnC,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,YAAY,MAAA,CAAO;AAAA,KACpB,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,MAAsB,EAAC;AAC7B,EAAA,IAAI,eAAA,GAAkB,CAAA;AACtB,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,WAAA;AACJ,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,MAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AACd,MAAA;AAAA,IACF;AACA,IAAA,IAAI,WAAA;AACJ,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,IAAI;AACF,QAAA,WAAA,GAAc,MAAM,QAAQ,QAAA,CAAS;AAAA,UACnC,KAAA,EAAO,KAAA;AAAA,UACP,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,KAAK,IAAA,CAAK,GAAA;AAAA,UACV,QAAQ,IAAA,CAAK;AAAA,SACd,CAAA;AACD,QAAA,WAAA,GAAc,OAAA,CAAQ,IAAA;AACtB,QAAA;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,GAAU,GAAA;AAAA,MACZ;AAAA,IACF;AACA,IAAA,IAAI,CAAC,WAAA,EAAa,IAAA,EAAK,EAAG;AACxB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,yDAAyD,OAAA,YAAmB,KAAA,GAAQ,gBAAgB,OAAA,CAAQ,OAAO,KAAK,EAAE,CAAA;AAAA,OAC5H;AAAA,IACF;AACA,IAAA,eAAA,EAAA;AACA,IAAA,GAAA,CAAI,IAAA,CAAK;AAAA,MACP,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,CAAA,OAAA,EAAU,eAAe,CAAA,cAAA,EAAiB,eAAe,gBAAgB,CAAA;AAAA,EAAM,WAAA,CAAY,MAAM,CAAA;AAAA,KACxG,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,KAAA,EAAO,SAAA,EAAW,iBAAiB,WAAA,EAAY;AACvE;AAEA,eAAe,gBAAgB,QAAA,EAAyE;AACtG,EAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AACvB,EAAA,OAAO,OAAO,QAAA,KAAa,UAAA,GAAa,MAAM,UAAS,GAAI,QAAA;AAC7D;AAMO,SAAS,wBAAA,CACd,QAAA,EACA,IAAA,GAAiC,EAAC,EACjB;AACjB,EAAA,OAAO,QAAA,CACJ,MAAK,CACL,MAAA,CAAO,kBAAkB,CAAA,CACzB,GAAA,CAAI,CAAC,IAAA,MAAU;AAAA,IACd,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,MAAM,SAAS,KAAA,EAA4C;AACzD,MAAA,MAAM,WAAA,GAAc,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAC1C,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,yBAAA,CAA2B,CAAA;AAAA,MAC/D;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,gBAAA,CAAiB,WAAA,EAAa,MAAM,KAAA,EAAO,KAAA,CAAM,MAAA,IAAU,IAAA,CAAK,MAAM,CAAA;AAC1F,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,WAAA,CAAY,IAAI,CAAA,gDAAA,CAAkD,CAAA;AAAA,MAC7F;AACA,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,MAAM,WAAA,CAAY,QAAQ,KAAA,CAAM,OAAA,EAAS,MAAM,GAAA,EAAK;AAAA,UACjE,QAAQ,KAAA,CAAM;AAAA,SACf,CAAA;AACD,QAAA,OAAO,oBAAoB,MAAM,CAAA;AAAA,MACnC,CAAA,SAAE;AACA,QAAA,MAAM,MAAM,OAAA,IAAU;AAAA,MACxB;AAAA,IACF;AAAA,GACF,CAAE,CAAA;AACN;AAEA,SAAS,mBAAmB,IAAA,EAAqB;AAC/C,EAAA,IAAI,IAAA,CAAK,UAAA,KAAe,MAAA,IAAU,IAAA,CAAK,UAAU,OAAO,KAAA;AACxD,EAAA,MAAM,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,IAAa,EAAE,GAAG,WAAA,EAAY;AAC9F,EAAA,IAAI,+DAAA,CAAgE,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,KAAA;AAC3F,EAAA,IAAI,CAAC,mDAAA,CAAoD,IAAA,CAAK,QAAQ,GAAG,OAAO,KAAA;AAChF,EAAA,MAAM,KAAA,GAAQ,iBAAiB,IAAI,CAAA;AACnC,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF,CAAE,IAAA,CAAK,CAAC,GAAA,KAAQ,OAAO,KAAK,CAAA;AAC9B;AAEA,eAAe,gBAAA,CACb,IAAA,EACA,KAAA,EACA,MAAA,GAAS,oIAAA,EAC4E;AACrF,EAAA,MAAM,KAAA,GAAQ,iBAAiB,IAAI,CAAA;AACnC,EAAA,MAAM,UAAmC,EAAC;AAC1C,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,MAAA,CAAO,UAAA,IAAc,WAAA;AAC7C,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,GAAA;AACzB,EAAA,IAAI,OAAA;AASJ,EAAA,IAAI,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,KAAA,IAAS,GAAA,EAAK;AACtC,IAAA,IAAI;AACF,MAAA,MAAM,oBAAA,CAAqB,IAAI,GAAA,CAAI,GAAG,EAAE,QAAQ,CAAA;AAAA,IAClD,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,MAAA,GACJ,GAAA,YAAe,KAAA,IAAS,GAAA,CAAI,QAAQ,UAAA,CAAW,QAAQ,CAAA,GACnD,GAAA,CAAI,QAAQ,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,CAAE,MAAK,GACxC,mBAAA;AACN,MAAA,MAAM,IAAI,qBAAA,CAAsB,EAAE,GAAA,EAAK,QAAQ,CAAA;AAAA,IACjD;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,aAAa,KAAA,EAAO;AAAA,IAClC,MAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,IAAI,OAAA,IAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,YAAY,IAAA,EAAM;AACrD,IAAA,MAAM,CAAA,GAAI,MAAM,cAAA,CAAe,IAAA,EAAM,SAAS,CAAA;AAC9C,IAAA,OAAA,CAAQ,OAAO,CAAA,GAAI,CAAA;AACnB,IAAA,OAAA,GAAU,YAAY;AACpB,MAAA,MAASA,GAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACxC,MAAA,MAASA,UAAW,IAAA,CAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,MAAA,IAAW,WAAW,KAAA,EAAO;AAC3B,IAAA,OAAA,CAAQ,QACN,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,QAAA,GAClB,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,UAAA,EAAY,WAAW,IAAA,EAAK,GACzD,EAAE,IAAA,EAAM,OAAO,GAAA,EAAI;AAAA,EAC3B,WAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,QAAA,IAAY,YAAY,KAAA,EAAO;AAC9D,IAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AAAA,EACnB,WAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,QAAA,IAAY,UAAU,KAAA,EAAO;AAC5D,IAAA,OAAA,CAAQ,IAAA,GAAO,IAAA;AAAA,EACjB,WAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,KAAA,IAAS,SAAS,KAAA,EAAO;AACxD,IAAA,OAAA,CAAQ,GAAA,GAAM,GAAA;AAAA,EAChB,WAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,KAAA,IAAS,eAAe,KAAA,EAAO;AAC9D,IAAA,OAAA,CAAQ,SAAA,GAAY,GAAA;AAAA,EACtB,WAAW,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,KAAA,IAAS,cAAc,KAAA,EAAO;AAC7D,IAAA,OAAA,CAAQ,QAAA,GAAW,GAAA;AAAA,EACrB,CAAA,MAAO;AACL,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,WAAA,IAAe,KAAA,EAAO,OAAA,CAAQ,SAAA,GAAY,SAAA;AAC9C,EAAA,IAAI,UAAA,IAAc,KAAA,EAAO,OAAA,CAAQ,QAAA,GAAW,SAAA;AAC5C,EAAA,IAAI,YAAA,IAAgB,KAAA,EAAO,OAAA,CAAQ,UAAA,GAAa,SAAA;AAChD,EAAA,IAAI,QAAA,IAAY,KAAA,EAAO,OAAA,CAAQ,MAAA,GAAS,MAAA;AACxC,EAAA,IAAI,OAAA,IAAW,KAAA,EAAO,OAAA,CAAQ,KAAA,GAAQ,MAAA;AACtC,EAAA,IAAI,aAAA,IAAiB,KAAA,EAAO,OAAA,CAAQ,WAAA,GAAc,MAAA;AAClD,EAAA,MAAM,KAAA,GAA6E,EAAE,OAAA,EAAQ;AAC7F,EAAA,IAAI,OAAA,KAAY,MAAA,EAAW,KAAA,CAAM,OAAA,GAAU,OAAA;AAC3C,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,YAAA,CAAa,OAAgC,IAAA,EAAoC;AACxF,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,CAAC,GAAA,KAAQ,OAAO,KAAK,CAAA;AACxC;AAEA,eAAe,cAAA,CAAe,MAAc,SAAA,EAAoC;AAC9E,EAAA,MAAM,GAAA,GAAM,UAAU,QAAA,CAAS,MAAM,KAAK,SAAA,CAAU,QAAA,CAAS,KAAK,CAAA,GAAI,KAAA,GAAQ,KAAA;AAC9E,EAAA,MAAM,MAAM,MAASA,GAAA,CAAA,OAAA,CAAa,UAAQC,GAAA,CAAA,MAAA,EAAO,EAAG,gBAAgB,CAAC,CAAA;AACrE,EAAA,MAAM,IAAA,GAAY,IAAA,CAAA,IAAA,CAAK,GAAA,EAAK,CAAA,MAAA,EAAS,GAAG,CAAA,CAAE,CAAA;AAC1C,EAAA,MAASD,GAAA,CAAA,SAAA,CAAU,IAAA,EAAM,IAAA,EAAM,QAAQ,CAAA;AACvC,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,iBAAiB,IAAA,EAAqC;AAC7D,EAAA,MAAM,SAAS,IAAA,CAAK,WAAA;AACpB,EAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,SAAiB,EAAC;AACnD,EAAA,MAAM,QAAS,MAAA,CAAgD,UAAA;AAC/D,EAAA,OAAO,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,GAAY,QAAoC,EAAC;AACpF;AAEA,SAAS,oBAAoB,KAAA,EAAwB;AACnD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,MAAA,IAAI,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,UAAU,IAAA,EAAM;AACtD,QAAA,OAAO,MAAA,CAAQ,IAAA,CAAwC,IAAA,IAAQ,EAAE,CAAA;AAAA,MACnE;AACA,MAAA,OAAO,OAAO,IAAA,KAAS,QAAA,GAAW,IAAA,GAAO,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,IAC9D,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAAA,EACd;AACA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,UAAU,KAAA,EAAO;AACzD,IAAA,OAAO,MAAA,CAAQ,KAAA,CAAyC,IAAA,IAAQ,EAAE,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC7B;ACxSA,IAAM,eAAA,GAAkB,KAAK,IAAA,GAAO,IAAA;AAEpC,eAAsB,kBAAA,GAAqD;AACzE,EAAA,MAAM,WAAW,OAAA,CAAQ,QAAA;AACzB,EAAA,IAAI,QAAA,KAAa,OAAA,EAAS,OAAO,WAAA,EAAY;AAC7C,EAAA,IAAI,QAAA,KAAa,QAAA,EAAU,OAAO,UAAA,EAAW;AAC7C,EAAA,IAAI,QAAA,KAAa,OAAA,EAAS,OAAO,SAAA,EAAU;AAC3C,EAAA,OAAO,IAAA;AACT;AASA,eAAsB,iBAAA,GAA4C;AAChE,EAAA,MAAM,WAAW,OAAA,CAAQ,QAAA;AACzB,EAAA,IAAI,aAAa,OAAA,EAAS;AAGxB,IAAA,MAAM,EAAA,GACJ,8EAAA;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,YAAA,EAAc,CAAC,YAAA,EAAc,UAAA,EAAY,EAAE,CAAC,CAAA;AACrE,IAAA,IAAI,GAAA,IAAO,MAAM,OAAO,IAAA;AACxB,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACrC,IAAA,OAAO,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,IAAA,GAAO,IAAA;AAAA,EAClC;AACA,EAAA,IAAI,aAAa,QAAA,EAAU;AACzB,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,SAAA,EAAW,EAAE,CAAA;AACtC,IAAA,OAAO,GAAA,IAAO,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,IAAA;AAAA,EACvC;AACA,EAAA,IAAI,aAAa,OAAA,EAAS;AACxB,IAAA,MAAM,KAAA,GAAmC;AAAA,MACvC,CAAC,UAAA,EAAY,CAAC,cAAc,CAAC,CAAA;AAAA,MAC7B,CAAC,OAAA,EAAS,CAAC,YAAA,EAAc,WAAA,EAAa,IAAI,CAAC;AAAA,KAC7C;AACA,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,KAAA,EAAO;AAC/B,MAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAClC,MAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG,OAAO,GAAA;AAAA,IACpC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT;AAEA,eAAe,WAAA,GAA8C;AAC3D,EAAA,MAAM,MAAWE,IAAA,CAAA,IAAA,CAAQ,GAAA,CAAA,MAAA,IAAU,CAAA,YAAA,EAAe,UAAA,EAAY,CAAA,IAAA,CAAM,CAAA;AACpE,EAAA,MAAM,EAAA,GAAK;AAAA,IACT,6CAAA;AAAA,IACA,uCAAA;AAAA,IACA,qDAAA;AAAA,IACA,yDAAA;AAAA,IACA,CAAA,WAAA,EAAc,GAAA,CAAI,OAAA,CAAQ,KAAA,EAAO,MAAM,CAAC,CAAA,6CAAA,CAAA;AAAA,IACxC;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AACX,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,YAAA,EAAc,CAAC,YAAA,EAAc,UAAA,EAAY,EAAE,CAAC,CAAA;AACrE,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,IAAA,EAAK,KAAM,YAAY,OAAO,IAAA;AAC9C,EAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,IAAI,GAAG,OAAO,IAAA;AAChC,EAAA,OAAO,YAAY,GAAG,CAAA;AACxB;AAEA,eAAe,UAAA,GAA6C;AAC1D,EAAA,MAAM,MAAWA,IAAA,CAAA,IAAA,CAAQ,GAAA,CAAA,MAAA,IAAU,CAAA,YAAA,EAAe,UAAA,EAAY,CAAA,IAAA,CAAM,CAAA;AACpE,EAAA,MAAM,MAAA,GAAS;AAAA,IACb,KAAA;AAAA,IACA,kDAAkD,GAAG,CAAA,wBAAA,CAAA;AAAA,IACrD,2DAAA;AAAA,IACA,yBAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,kCAAkC,GAAA,GAAM,GAAA;AAAA,IACxC,WAAA;AAAA,IACA,qBAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AACX,EAAA,MAAM,MAAM,MAAM,MAAA,CAAO,aAAa,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AACpD,EAAA,IAAI,GAAA,EAAK,IAAA,EAAK,KAAM,IAAA,EAAM,OAAO,IAAA;AACjC,EAAA,OAAO,YAAY,GAAG,CAAA;AACxB;AAEA,eAAe,SAAA,GAA4C;AACzD,EAAA,MAAM,MAAWA,IAAA,CAAA,IAAA,CAAQ,GAAA,CAAA,MAAA,IAAU,CAAA,YAAA,EAAe,UAAA,EAAY,CAAA,IAAA,CAAM,CAAA;AACpE,EAAA,MAAM,KAAA,GAAmC;AAAA,IACvC,CAAC,UAAA,EAAY,CAAC,QAAA,EAAU,WAAW,CAAC,CAAA;AAAA,IACpC,CAAC,SAAS,CAAC,YAAA,EAAc,aAAa,IAAA,EAAM,WAAA,EAAa,IAAI,CAAC;AAAA,GAChE;AACA,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,KAAA,EAAO;AAC/B,IAAA,MAAM,EAAA,GAAK,MAAM,YAAA,CAAa,GAAA,EAAK,MAAM,GAAG,CAAA,CAAE,KAAA,CAAM,MAAM,KAAK,CAAA;AAC/D,IAAA,IAAI,EAAA,EAAI,OAAO,WAAA,CAAY,GAAG,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,IAAA;AACT;AAEA,eAAe,YAAY,CAAA,EAA2C;AACpE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAS,GAAA,CAAA,QAAA,CAAS,CAAC,CAAA;AAC/B,IAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACpB,MAAA,MAAS,GAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AACxC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,IAAI,GAAA,CAAI,SAAS,eAAA,EAAiB;AAChC,MAAA,MAAS,GAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AACxC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,eAAA,GAAkB,IAAA,GAAO,IAAI,CAAA,QAAA,CAAU,CAAA;AAAA,IACpF;AACA,IAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,GAAA,IAAQ,IAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,MAAM,EAAA,EAAM;AAC5E,MAAA,MAAS,GAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AACxC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAS,GAAA,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AACxC,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,CAAI,QAAA,CAAS,QAAQ,GAAG,SAAA,EAAW,WAAA,EAAa,KAAA,EAAO,GAAA,CAAI,MAAA,EAAO;AAAA,EACrF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AAC7D,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAQA,IAAM,wBAAA,GAA2B,GAAA;AAEjC,SAAS,MAAA,CAAO,KAAa,IAAA,EAAwC;AACnE,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,MAAM,QAAQ,KAAA,CAAM,GAAA,EAAK,IAAA,EAAM,EAAE,KAAK,aAAA,EAAc,EAAG,KAAA,EAAO,CAAC,UAAU,MAAA,EAAQ,MAAM,CAAA,EAAG,WAAA,EAAa,MAAM,CAAA;AAC7G,IAAA,IAAI,GAAA,GAAM,EAAA;AACV,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KAAyB;AACvC,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IACf,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,KAAA,CAAM,KAAK,SAAS,CAAA;AACpB,MAAA,MAAA,CAAO,IAAI,CAAA;AAAA,IACb,GAAG,wBAAwB,CAAA;AAC3B,IAAA,KAAA,CAAM,MAAA,CAAO,EAAA,CAAG,MAAA,EAAQ,CAAC,CAAA,KAAM;AAC7B,MAAA,GAAA,IAAO,OAAO,CAAC,CAAA;AAAA,IACjB,CAAC,CAAA;AACD,IAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,MAAM,MAAA,CAAO,IAAI,CAAC,CAAA;AACpC,IAAA,KAAA,CAAM,EAAA,CAAG,QAAQ,CAAC,IAAA,KAAS,OAAO,IAAA,KAAS,CAAA,GAAI,GAAA,GAAM,IAAI,CAAC,CAAA;AAAA,EAC5D,CAAC,CAAA;AACH;AAEA,SAAS,YAAA,CAAa,GAAA,EAAa,IAAA,EAAgB,OAAA,EAAmC;AACpF,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,MAAM,QAAQ,KAAA,CAAM,GAAA,EAAK,IAAA,EAAM,EAAE,KAAK,aAAA,EAAc,EAAG,KAAA,EAAO,CAAC,UAAU,MAAA,EAAQ,MAAM,CAAA,EAAG,WAAA,EAAa,MAAM,CAAA;AAC7G,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KAAmB;AACjC,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IACf,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,KAAA,CAAM,KAAK,SAAS,CAAA;AACpB,MAAA,MAAA,CAAO,KAAK,CAAA;AAAA,IACd,GAAG,wBAAwB,CAAA;AAC3B,IAAA,KAAA,CAAM,MAAA,CAAO,GAAG,MAAA,EAAQ,CAAC,MAAc,MAAA,CAAO,IAAA,CAAK,CAAC,CAAC,CAAA;AACrD,IAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,MAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACrC,IAAA,KAAA,CAAM,EAAA,CAAG,MAAA,EAAQ,OAAO,IAAA,KAAS;AAC/B,MAAA,IAAI,SAAS,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG,OAAO,OAAO,KAAK,CAAA;AAC1D,MAAA,IAAI;AACF,QAAA,MAAS,GAAA,CAAA,SAAA,CAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,MAAM,CAAC,CAAA;AACjD,QAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MACb,CAAA,CAAA,MAAQ;AACN,QAAA,MAAA,CAAO,KAAK,CAAA;AAAA,MACd;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AChIA,IAAM,iBAAA,GACJ,gLAAA;AAIF,IAAM,eAAA,GAAkB,sCAAA;AAYjB,SAAS,yBAAyB,IAAA,EAA8C;AACrF,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQC,OAAO,WAAW,CAAA;AAC7D,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQA,OAAO,YAAY,CAAA;AAC/D,EAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQA,OAAO,cAAc,CAAA;AACnE,EAAA,MAAM,mBAAA,GAAsB,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQA,OAAO,mBAAmB,CAAA;AAE7E,EAAA,OAAO,OAAO,MAAA,KAAwD;AACpE,IAAA,MAAM,MAAA,GAAS,IAAI,QAAA,EAAS;AAC5B,IAAA,MAAM,MAAA,GAAS,YAAY,GAAA,EAAI;AAE/B,IAAA,MAAM,WAAA,GAAc,OAAO,KAAA,GACvB,MAAA,GACA,mBAAmB,MAAA,CAAO,WAAA,EAAa,OAAO,IAAI,CAAA;AACtD,IAAA,MAAM,YAAA,GAAe,2BAAA,CAA4B,MAAA,EAAQ,WAAW,CAAA;AACpE,IAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,IAAY,YAAA,EAAc,YAAY,MAAA,CAAO,QAAA;AACxE,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,KAAA,IAAS,YAAA,EAAc,SAAS,MAAA,CAAO,KAAA;AAC/D,IAAA,MAAM,WAAW,aAAA,CAAc,IAAA,CAAK,gBAAA,EAAkB,MAAA,EAAQ,aAAa,QAAQ,CAAA;AAEnF,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,IAAO,IAAA,CAAK,OAAO,IAAA,CAAK,WAAA;AAK9C,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,IAAA,CAAK,YAAA,EAAc,OAAO,KAAK,CAAA;AAC9D,IAAA,MAAM,WAAA,GAAc,IAAI,YAAA,EAAa;AACrC,IAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,WAAA,CAAY,QAAA,CAAS,CAAC,CAAA;AAE/C,IAAA,MAAM,UAAA,GAA0B,MAAM,mBAAA,CAAoB,KAAA,CAAM;AAAA,MAC9D,GAAA,EAAK,MAAA;AAAA,MACL,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,KAAA,EAAO,OAAA;AAAA,MACP,KAAA,EAAO,QAAA;AAAA,MACP,QAAA,EAAU,WAAA;AAAA,MACV,QAAA,EAAU;AAAA,KACX,CAAA;AACD,IAAA,UAAA,CAAW,QAAQ,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,mBAAmB,CAAA;AAC5D,IAAA,IAAI,OAAO,oBAAA,EAAsB;AAC/B,MAAA,UAAA,CAAW,KAAK,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,MAAA,CAAO,sBAAsB,CAAA;AAAA,IACrE;AAEA,IAAA,MAAM,YAAY,MAAA,CAAO,IAAA,IAAQ,OAAO,EAAA,IAAM,CAAA,IAAA,EAAO,UAAU,CAAA,CAAA;AAC/D,IAAA,MAAM,OAAA,GAAU,uBAAA,CAAwB,IAAA,CAAK,OAAO,CAAA;AAIpD,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,MAAM,GAAA,GAAM,IAAI,OAAA,CAAQ;AAAA,MACtB,YAAA,EAAc,UAAA;AAAA,MACd,QAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAQ,EAAA,CAAG,MAAA;AAAA,MACX,YAAA;AAAA,MACA,GAAA,EAAK,MAAA;AAAA,MACL,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,yBACE,MAAA,CAAO,QAAA,EAAU,2BAA2B,EAAE,MAAA,CAAO,OAAO,qBAAA,IAAyB,KAAA,CAAA;AAAA,MACvF,KAAA,EAAO,QAAA;AAAA,MACP,KAAA,EAAO,OAAA;AAAA,MACP,OAAA,EAAS,SAAA;AAAA,MACT;AAAA,KACD,CAAA;AACD,IAAA,IAAI,OAAO,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,WAAW,IAAI,MAAA,CAAO,IAAA;AAEhD,IAAC,GAAA,CAAI,IAAA,CAAK,eAAe,CAAA,GAAwB,EAAA;AAMjD,IAAA,MAAM,IAAA,GAAO,OAAO,mBAAA,IAAuB,0BAAA;AAC3C,IAAA,MAAM,gBAAA,GAAmB,IAAI,2BAAA,CAA4B,IAAI,CAAA;AAE7D,IAAA,MAAM,YAAA,GAAe,IAAI,YAAA,CAAa,WAAA,EAAa;AAAA,MACjD,gBAAA;AAAA,MACA,cAAA;AAAA,MACA,MAAA;AAAA,MACA,cAAA,EAAgB,MAAA;AAAA,MAChB,kBAAA,EAAoB,MAAA,CAAO,KAAA,EAAO,kBAAA,IAAsB,IAAA;AAAA,MACxD,0BAAA,EAA4B,MAAA,CAAO,KAAA,EAAO,0BAAA,IAA8B,GAAA;AAAA,MACxE,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM;AAAA,MACtB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,WAAA;AAAA,MACP,WAAW,IAAA,CAAK,gBAAA;AAAA,MAChB,MAAA;AAAA,MACA,WAAW,sBAAA,EAAuB;AAAA,MAClC,OAAA,EAAS,GAAA;AAAA,MACT,gBAAA;AAAA,MACA;AAAA,KACD,CAAA;AAOD,IAAA,MAAM,eAAe,MAAA,CAAO,cAAA;AAC5B,IAAA,MAAM,kBAAkB,YAAA,EAAc,cAAA;AACtC,IAAA,KAAA,CAAM,UAAA,CAAW,QAAA;AAAA,MACf,4BAAA,CAA6B;AAAA,QAC3B,WAAW,MAAM;AACf,UAAA,MAAM,IAAA,GAAO,YAAY,GAAA,EAAI;AAC7B,UAAA,IAAI,YAAA,IAAgB,aAAa,MAAA,EAAQ,OAAO,EAAE,GAAG,IAAA,EAAM,gBAAgB,YAAA,EAAa;AACxF,UAAA,IAAI,eAAA,IAAmB,gBAAgB,MAAA,EAAQ,OAAO,EAAE,GAAG,IAAA,EAAM,gBAAgB,eAAA,EAAgB;AACjG,UAAA,OAAO,IAAA;AAAA,QACT,CAAA;AAAA,QACA,aAAA,EAAe,CAAC,EAAA,KAAO,aAAA,CAAc,IAAA,CAAK,kBAAkB,WAAA,CAAY,GAAA,EAAI,EAAG,EAAA,EAAI,QAAQ,CAAA;AAAA,QAC3F;AAAA,OACD;AAAA,KACH;AAEA,IAAA,OAAO,EAAE,OAAO,MAAA,EAAO;AAAA,EACzB,CAAA;AACF;AAIA,SAAS,cAAA,CAAe,UAAwB,KAAA,EAA0B;AACxE,EAAA,MAAM,GAAA,GAAM,SAAS,IAAA,EAAK;AAC1B,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,GAAA;AACzC,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,KAAK,CAAA;AAC9B,EAAA,OAAO,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,SAAS,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AAC/C;AAEA,SAAS,aAAA,CACP,QAAA,EACA,MAAA,EACA,UAAA,EACA,KAAA,EACwC;AACxC,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,SAAA,GAAY,UAAU,CAAA,IAAK;AAAA,IACvD,IAAA,EAAM,UAAA;AAAA,IACN,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,SAAS,MAAA,CAAO;AAAA,GAClB;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,UAAU,CAAA,EAAG;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,uCAAuC,UAAU,CAAA,0DAAA;AAAA,KACnD;AAAA,EACF;AACA,EAAA,OAAO,QAAA,CAAS,OAAO,EAAE,GAAG,gBAAgB,IAAA,EAAM,UAAA,EAAY,OAAO,CAAA;AACvE;AAQA,SAAS,wBAAwB,MAAA,EAAsC;AACrE,EAAA,OAAO;AAAA,IACL,IAAI,MAAA,CAAO,EAAA;AAAA,IACX,gBAAgB,MAAA,CAAO,cAAA;AAAA,IACvB,IAAI,eAAA,GAA4B;AAC9B,MAAA,OAAO,EAAC;AAAA,IACV,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,EAAA,KAAO,MAAA,CAAO,OAAO,EAAE,GAAG,IAAI,CAAA;AAAA,IACvC,WAAA,EAAa,CAAC,GAAA,KAAQ,MAAA,CAAO,WAAA,CAAY,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,GAAI,CAAC,CAAA;AAAA,IACnE,KAAA,EAAO,MAAM,MAAA,CAAO,KAAA,EAAM;AAAA,IAC1B,OAAO,YAAY;AAAA,IAAC,CAAA;AAAA,IACpB,kBAAkB,MAAM;AAAA,IAAC,CAAA;AAAA,IACzB,kBAAkB,MAAM;AAAA,IAAC,CAAA;AAAA,IACzB,iBAAiB,YAAY;AAAA,IAAC,CAAA;AAAA,IAC9B,mBAAmB,YAAY;AAAA,IAAC,CAAA;AAAA,IAChC,sBAAsB,YAAY,CAAA;AAAA,IAClC,cAAc,YAAY;AAAA,IAAC,CAAA;AAAA,IAC3B,qBAAqB,YAAY;AAAA,IAAC,CAAA;AAAA,IAClC,qBAAqB,YAAY;AAAA,IAAC;AAAA,GACpC;AACF;AAEA,SAAS,QAAA,GAAmB;AAC1B,EAAA,OAAO,MAAA,CAAO,UAAA,EAAW,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA;AACvC","file":"index.js","sourcesContent":["import type {\n Agent,\n Context,\n EventBus,\n ExtensionRegistry,\n PluginAPI,\n ProviderRegistry,\n SessionWriter,\n SlashCommandRegistry,\n ToolRegistry,\n} from '@wrongstack/core';\nimport type { WrongStackPack } from './pack.js';\n\nexport interface RuntimeHost {\n agent: Agent;\n context: Context;\n events: EventBus;\n tools: ToolRegistry;\n providers: ProviderRegistry;\n slashCommands: SlashCommandRegistry;\n session: SessionWriter;\n extensions?: ExtensionRegistry | undefined;\n shutdown(): Promise<void>;\n}\n\nexport interface RuntimeHostParts {\n agent: Agent;\n context: Context;\n events: EventBus;\n tools: ToolRegistry;\n providers: ProviderRegistry;\n slashCommands: SlashCommandRegistry;\n session: SessionWriter;\n extensions?: ExtensionRegistry | undefined;\n shutdown?: (() => void | Promise<void>) | undefined;\n}\n\nexport function createRuntimeHostFromParts(parts: RuntimeHostParts): RuntimeHost {\n return {\n agent: parts.agent,\n context: parts.context,\n events: parts.events,\n tools: parts.tools,\n providers: parts.providers,\n slashCommands: parts.slashCommands,\n session: parts.session,\n extensions: parts.extensions,\n async shutdown() {\n await parts.shutdown?.();\n },\n };\n}\n\nexport interface ApplyPackOptions {\n owner?: string | undefined;\n api?: PluginAPI | undefined;\n}\n\nexport interface AppliedPack {\n pack: WrongStackPack;\n owner: string;\n teardown(): Promise<void>;\n}\n\nexport async function applyWrongStackPack(\n host: Pick<RuntimeHost, 'tools' | 'providers' | 'slashCommands'> & {\n extensions?: ExtensionRegistry | undefined;\n },\n pack: WrongStackPack,\n opts: ApplyPackOptions = {},\n): Promise<AppliedPack> {\n const owner = opts.owner ?? pack.name;\n const unregisterExtensions: Array<() => void> = [];\n\n // Track registered tool names, command names, and provider types so teardown\n // can reverse everything in registration order.\n const registeredToolNames: string[] = [];\n const registeredCommandNames: string[] = [];\n const registeredProviderTypes: string[] = [];\n\n if (pack.tools) {\n const tools = [...pack.tools];\n host.tools.registerAllOrThrow(tools, owner);\n for (const t of tools) registeredToolNames.push(t.name);\n }\n if (pack.providers) {\n const providers = [...pack.providers];\n host.providers.registerAll(providers);\n for (const p of providers) registeredProviderTypes.push(p.type);\n }\n if (pack.slashCommands) {\n const cmds = [...pack.slashCommands];\n host.slashCommands.registerAll(cmds, owner);\n for (const c of cmds) registeredCommandNames.push(c.name);\n }\n if (pack.extensions && host.extensions) {\n for (const ext of pack.extensions) {\n unregisterExtensions.push(host.extensions.register(ext));\n }\n }\n\n // If setup() throws after registration, roll back everything we registered above.\n // This makes applyWrongStackPack() transactional from the caller's perspective —\n // either the pack is fully applied or it is not.\n if (pack.setup) {\n if (!opts.api) {\n throw new Error(`Pack \"${pack.name}\" defines setup() but no PluginAPI was provided`);\n }\n try {\n await pack.setup(opts.api);\n } catch (setupErr) {\n // Roll back in reverse order: extensions first, then commands,\n // then tools, then providers. Extensions are unregistered before\n // tools/commands because extensions may depend on those capabilities;\n // tearing them down first avoids dangling refs.\n for (const unregister of unregisterExtensions.reverse()) {\n unregister();\n }\n for (const name of registeredCommandNames.reverse()) {\n host.slashCommands.unregister(name);\n }\n for (const name of registeredToolNames.reverse()) {\n host.tools.unregister(name);\n }\n for (const type of registeredProviderTypes.reverse()) {\n host.providers.unregister(type);\n }\n throw setupErr;\n }\n }\n\n return {\n pack,\n owner,\n async teardown() {\n for (const unregister of unregisterExtensions.reverse()) {\n unregister();\n }\n // Unregister commands, tools, and providers so the same pack can be\n // re-loaded cleanly without name/type conflicts.\n for (const name of registeredCommandNames.reverse()) {\n host.slashCommands.unregister(name);\n }\n for (const name of registeredToolNames.reverse()) {\n host.tools.unregister(name);\n }\n for (const type of registeredProviderTypes.reverse()) {\n host.providers.unregister(type);\n }\n if (pack.teardown) {\n if (!opts.api) {\n throw new Error(`Pack \"${pack.name}\" defines teardown() but no PluginAPI was provided`);\n }\n await pack.teardown(opts.api);\n }\n },\n };\n}\n\nexport async function applyWrongStackPacks(\n host: Pick<RuntimeHost, 'tools' | 'providers' | 'slashCommands'> & {\n extensions?: ExtensionRegistry | undefined;\n },\n packs: readonly WrongStackPack[],\n opts: ApplyPackOptions = {},\n): Promise<AppliedPack[]> {\n const applied: AppliedPack[] = [];\n try {\n for (const pack of packs) {\n applied.push(await applyWrongStackPack(host, pack, opts));\n }\n return applied;\n } catch (err) {\n // Roll back already-mounted packs. Surface teardown failures via\n // process.emitWarning so they don't mask the original error but\n // remain visible — a silent teardown failure can leave state\n // half-initialized in ways that make the next run fail mysteriously.\n for (const mounted of applied.reverse()) {\n await mounted.teardown().catch((teardownErr) => {\n const detail = teardownErr instanceof Error ? teardownErr.message : String(teardownErr);\n process.emitWarning(\n `Pack teardown during error rollback failed: ${detail}`,\n 'PackRollbackWarning',\n );\n });\n }\n throw err;\n }\n}\n","import {\n type Config,\n Container,\n DefaultConfigStore,\n DefaultErrorHandler,\n DefaultMemoryStore,\n DefaultModeStore,\n DefaultPermissionPolicy,\n DefaultRetryPolicy,\n DefaultPromptLoader,\n DefaultSecretScrubber,\n DefaultSessionStore,\n DefaultSkillLoader,\n DefaultSystemPromptBuilder,\n DefaultTokenCounter,\n type EventBus,\n createStrategyCompactor,\n buildRecoveryStrategies,\n type Logger,\n type ModelsRegistry,\n TOKENS,\n type Tool,\n type WstackPaths,\n} from '@wrongstack/core';\nimport type { DefaultSystemPromptBuilderOptions } from '@wrongstack/core';\n\nexport interface CreateContainerOptions {\n config: Config;\n wpaths: WstackPaths;\n logger: Logger;\n modelsRegistry: ModelsRegistry;\n /**\n * Optional event bus — passed to DefaultMemoryStore so plugins and\n * subsystems can react to memory mutations in real time.\n */\n events?: EventBus | undefined;\n permission?: {\n yolo?: boolean | undefined;\n yoloDestructive?: boolean | undefined;\n /** @deprecated Use `yoloDestructive`. */\n forceAllYolo?: boolean | undefined;\n /** When true, destructive ops prompt even in YOLO mode. */\n confirmDestructive?: boolean | undefined;\n promptDelegate?: (\n tool: Tool,\n input: unknown,\n suggestedPattern: string,\n ) => Promise<'yes' | 'no' | 'always' | 'deny'>;\n };\n compactor?: { preserveK?: number | undefined; eliseThreshold?: number | undefined };\n systemPrompt?: Partial<DefaultSystemPromptBuilderOptions> | undefined;\n /** Bundled skills directory path (resolved at boot time). */\n bundledSkillsDir?: string | undefined;\n /** Bundled prompt dataset directory path (`<core>/data/prompts`, resolved at boot). */\n bundledPromptsDir?: string | undefined;\n}\n\n/**\n * Create a Container pre-bound with all default service implementations.\n * Both CLI and WebUI use this factory so container wiring stays in one place.\n */\nexport function createDefaultContainer(opts: CreateContainerOptions): Container {\n const { config, wpaths, logger, modelsRegistry } = opts;\n const container = new Container();\n\n const configStore = new DefaultConfigStore(config);\n container.bind(TOKENS.ConfigStore, () => configStore);\n container.bind(TOKENS.Logger, () => logger);\n container.bind(TOKENS.SecretScrubber, () => new DefaultSecretScrubber());\n container.bind(TOKENS.RetryPolicy, () => new DefaultRetryPolicy());\n // Wire the compactor into the recovery chain so a 413 / context-overflow\n // response can shed tokens and retry. Without an explicit compactor the\n // default `context_overflow_reduce` strategy is a no-op. The Compactor\n // binding is resolved lazily (it is registered further below).\n container.bind(\n TOKENS.ErrorHandler,\n () =>\n new DefaultErrorHandler(\n buildRecoveryStrategies({\n compactor: container.resolve(TOKENS.Compactor),\n modelsRegistry,\n getConfig: () => configStore.get(),\n }),\n ),\n );\n container.bind(TOKENS.ModelsRegistry, () => modelsRegistry);\n container.bind(\n TOKENS.TokenCounter,\n () => new DefaultTokenCounter({ registry: modelsRegistry, providerId: config.provider, events: opts.events }),\n );\n\n const modeStore = new DefaultModeStore({ directory: wpaths.configDir });\n container.bind(TOKENS.ModeStore, () => modeStore);\n container.bind(\n TOKENS.SessionStore,\n () =>\n new DefaultSessionStore({\n dir: wpaths.projectSessions,\n // Scrub secrets out of persisted user/model turns (F-06). Tool output\n // is already scrubbed by the executor.\n secretScrubber: container.resolve(TOKENS.SecretScrubber),\n }),\n );\n\n const memoryStore = new DefaultMemoryStore({ paths: wpaths, events: opts.events });\n container.bind(TOKENS.MemoryStore, () => memoryStore);\n\n const skillLoader = new DefaultSkillLoader({ paths: wpaths, bundledDir: opts.bundledSkillsDir });\n container.bind(TOKENS.SkillLoader, () => skillLoader);\n\n const promptLoader = new DefaultPromptLoader({ paths: wpaths, bundledDir: opts.bundledPromptsDir });\n container.bind(TOKENS.PromptLoader, () => promptLoader);\n\n if (opts.systemPrompt) {\n container.bind(\n TOKENS.SystemPromptBuilder,\n () =>\n new DefaultSystemPromptBuilder({\n instructionPaths: {\n globalDir: wpaths.globalInstructions,\n projectDir: wpaths.inProjectInstructions,\n },\n ...(opts.systemPrompt as DefaultSystemPromptBuilderOptions),\n }),\n );\n }\n\n container.bind(\n TOKENS.PermissionPolicy,\n () => {\n const policyOptions: ConstructorParameters<typeof DefaultPermissionPolicy>[0] = {\n trustFile: wpaths.projectTrust,\n yolo: opts.permission?.yolo ?? false,\n yoloDestructive: opts.permission?.yoloDestructive ?? opts.permission?.forceAllYolo ?? false,\n confirmDestructive: opts.permission?.confirmDestructive ?? false,\n };\n if (opts.permission?.promptDelegate !== undefined) {\n policyOptions.promptDelegate = opts.permission.promptDelegate;\n }\n return new DefaultPermissionPolicy(policyOptions);\n },\n );\n\n container.bind(\n TOKENS.Compactor,\n () =>\n // Strategy comes from config.context.strategy: 'hybrid' (default, lossless\n // rules, no LLM), 'intelligent' (LLM summarization), or 'selective'\n // (LLM-driven selection). The LLM strategies resolve their provider from\n // ctx at compact()-time, so binding here (before context.provider exists)\n // is safe. preserveK / eliseThreshold are class-level fallbacks; the active\n // ContextWindowPolicy in ctx.meta normally overrides both at runtime.\n // eliseThreshold is a TOKEN COUNT — a previous value of 0.7 elided\n // essentially every tool_result (anything > 1 token).\n createStrategyCompactor({\n strategy: config.context?.strategy,\n preserveK: opts.compactor?.preserveK ?? 10,\n eliseThreshold: opts.compactor?.eliseThreshold ?? 2000,\n smart: true,\n summarizerModel: config.context?.summarizerModel,\n llmSelector: config.context?.llmSelector,\n }),\n );\n\n return container;\n}\n","import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { assertNotPrivateHost } from '@wrongstack/core';\nimport type { ContentBlock, Context, ImageBlock, Tool, ToolRegistry } from '@wrongstack/core';\n\nexport interface VisionAdapterInput {\n image: ImageBlock;\n prompt?: string | undefined;\n ctx: Context;\n signal: AbortSignal;\n}\n\nexport interface VisionAdapter {\n name: string;\n describe(input: VisionAdapterInput): Promise<string>;\n}\n\nexport type VisionAdapters =\n | readonly VisionAdapter[]\n | (() => readonly VisionAdapter[] | Promise<readonly VisionAdapter[]>);\n\nexport interface VisionRoutingOptions {\n supportsVision: boolean;\n adapters?: VisionAdapters | undefined;\n ctx: Context;\n signal: AbortSignal;\n prompt?: string | undefined;\n providerId?: string | undefined;\n model?: string | undefined;\n}\n\nexport interface VisionRoutingResult {\n blocks: ContentBlock[];\n route: 'native' | 'adapter' | 'none';\n convertedImages: number;\n adapterName?: string | undefined;\n}\n\nexport class ImageInputUnsupportedError extends Error {\n constructor(opts: { providerId?: string | undefined; model?: string | undefined; imageCount: number }) {\n const target = [opts.providerId, opts.model].filter(Boolean).join('/') || 'current model';\n super(\n `${target} does not support image input, and no image-understanding adapter is available for ${opts.imageCount} image${opts.imageCount === 1 ? '' : 's'}. Switch to a vision model or enable an MCP/tool adapter that can describe images.`,\n );\n this.name = 'ImageInputUnsupportedError';\n }\n}\n\n/**\n * Thrown when an image URL targets a private / loopback / IMDS address.\n * Vision adapters forward URLs straight to the underlying tool, so without\n * this check a malicious (or accidentally-malformed) `image.source.url`\n * could turn image analysis into an SSRF vector hitting localhost, RFC1918\n * ranges, or the cloud metadata endpoint.\n *\n * Carries the rejected URL so callers can log / surface it without parsing\n * the message.\n */\nexport class VisionUrlBlockedError extends Error {\n readonly url: string;\n\n constructor(opts: { url: string; reason: string }) {\n super(`vision: blocked unsafe image URL \"${opts.url}\" (${opts.reason})`);\n this.name = 'VisionUrlBlockedError';\n this.url = opts.url;\n }\n}\n\nexport async function routeImagesForModel(\n blocks: ContentBlock[],\n opts: VisionRoutingOptions,\n): Promise<VisionRoutingResult> {\n const images = blocks.filter((b): b is ImageBlock => b.type === 'image');\n if (images.length === 0) {\n return { blocks, route: 'none', convertedImages: 0 };\n }\n if (opts.supportsVision) {\n return { blocks, route: 'native', convertedImages: 0 };\n }\n\n const adapters = await resolveAdapters(opts.adapters);\n if (adapters.length === 0) {\n throw new ImageInputUnsupportedError({\n providerId: opts.providerId,\n model: opts.model,\n imageCount: images.length,\n });\n }\n\n const out: ContentBlock[] = [];\n let convertedImages = 0;\n let lastErr: unknown;\n let adapterName: string | undefined;\n for (const block of blocks) {\n if (block.type !== 'image') {\n out.push(block);\n continue;\n }\n let description: string | undefined;\n for (const adapter of adapters) {\n try {\n description = await adapter.describe({\n image: block,\n prompt: opts.prompt,\n ctx: opts.ctx,\n signal: opts.signal,\n });\n adapterName = adapter.name;\n break;\n } catch (err) {\n lastErr = err;\n }\n }\n if (!description?.trim()) {\n throw new Error(\n `No image-understanding adapter could process an image.${lastErr instanceof Error ? ` Last error: ${lastErr.message}` : ''}`,\n );\n }\n convertedImages++;\n out.push({\n type: 'text',\n text: `[Image ${convertedImages} analyzed via ${adapterName ?? 'vision adapter'}]\\n${description.trim()}`,\n });\n }\n\n return { blocks: out, route: 'adapter', convertedImages, adapterName };\n}\n\nasync function resolveAdapters(adapters: VisionAdapters | undefined): Promise<readonly VisionAdapter[]> {\n if (!adapters) return [];\n return typeof adapters === 'function' ? await adapters() : adapters;\n}\n\nexport interface ToolVisionAdapterOptions {\n prompt?: string | undefined;\n}\n\nexport function createToolVisionAdapters(\n registry: ToolRegistry,\n opts: ToolVisionAdapterOptions = {},\n): VisionAdapter[] {\n return registry\n .list()\n .filter(isLikelyVisionTool)\n .map((tool) => ({\n name: tool.name,\n async describe(input: VisionAdapterInput): Promise<string> {\n const currentTool = registry.get(tool.name);\n if (!currentTool) {\n throw new Error(`Tool \"${tool.name}\" is no longer registered`);\n }\n const built = await buildToolPayload(currentTool, input.image, input.prompt ?? opts.prompt);\n if (!built) {\n throw new Error(`Tool \"${currentTool.name}\" does not expose a supported image input schema`);\n }\n try {\n const result = await currentTool.execute(built.payload, input.ctx, {\n signal: input.signal,\n });\n return stringifyToolResult(result);\n } finally {\n await built.cleanup?.();\n }\n },\n }));\n}\n\nfunction isLikelyVisionTool(tool: Tool): boolean {\n if (tool.permission !== 'auto' || tool.mutating) return false;\n const haystack = `${tool.name} ${tool.description ?? ''} ${tool.usageHint ?? ''}`.toLowerCase();\n if (/(generate|create|draw|paint|edit|upscale|remove|write|delete)/.test(haystack)) return false;\n if (!/(vision|image|screenshot|ocr|describe|analy[sz]e)/.test(haystack)) return false;\n const props = schemaProperties(tool);\n return [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n ].some((key) => key in props);\n}\n\nasync function buildToolPayload(\n tool: Tool,\n image: ImageBlock,\n prompt = 'Describe this image for a coding agent. Include visible text, UI state, errors, layout, and any details needed to answer the user.',\n): Promise<{ payload: Record<string, unknown>; cleanup?: () => Promise<void> } | null> {\n const props = schemaProperties(tool);\n const payload: Record<string, unknown> = {};\n const mediaType = image.source.media_type ?? 'image/png';\n const data = image.source.data;\n const url = image.source.url;\n let cleanup: (() => Promise<void>) | undefined;\n\n // SSRF guard: when the image is referenced by URL, validate the host\n // BEFORE forwarding it to the underlying vision tool. The tool may\n // itself fetch the URL (the typical case for an MCP image-understanding\n // adapter), so a URL pointing at localhost / 127.0.0.1 / 169.254.169.254\n // / RFC1918 ranges would otherwise become an SSRF vector. Without this\n // gate, vision is a back-door around the fetch.ts SSRF guard (which\n // only applies when the explicit `fetch` tool is invoked).\n if (image.source.type === 'url' && url) {\n try {\n await assertNotPrivateHost(new URL(url).hostname);\n } catch (err) {\n const reason =\n err instanceof Error && err.message.startsWith('fetch:')\n ? err.message.slice('fetch:'.length).trim()\n : 'unresolvable host';\n throw new VisionUrlBlockedError({ url, reason });\n }\n }\n\n const pathKey = firstPresent(props, [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n ]);\n if (pathKey && image.source.type === 'base64' && data) {\n const p = await writeTempImage(data, mediaType);\n payload[pathKey] = p;\n cleanup = async () => {\n await fs.unlink(p).catch(() => undefined);\n await fs.rmdir(path.dirname(p)).catch(() => undefined);\n };\n } else if ('image' in props) {\n payload.image =\n image.source.type === 'base64'\n ? { type: 'base64', mediaType, media_type: mediaType, data }\n : { type: 'url', url };\n } else if (image.source.type === 'base64' && 'base64' in props) {\n payload.base64 = data;\n } else if (image.source.type === 'base64' && 'data' in props) {\n payload.data = data;\n } else if (image.source.type === 'url' && 'url' in props) {\n payload.url = url;\n } else if (image.source.type === 'url' && 'image_url' in props) {\n payload.image_url = url;\n } else if (image.source.type === 'url' && 'imageUrl' in props) {\n payload.imageUrl = url;\n } else {\n return null;\n }\n\n if ('mediaType' in props) payload.mediaType = mediaType;\n if ('mimeType' in props) payload.mimeType = mediaType;\n if ('media_type' in props) payload.media_type = mediaType;\n if ('prompt' in props) payload.prompt = prompt;\n if ('query' in props) payload.query = prompt;\n if ('instruction' in props) payload.instruction = prompt;\n const built: { payload: Record<string, unknown>; cleanup?: () => Promise<void> } = { payload };\n if (cleanup !== undefined) built.cleanup = cleanup;\n return built;\n}\n\nfunction firstPresent(props: Record<string, unknown>, keys: string[]): string | undefined {\n return keys.find((key) => key in props);\n}\n\nasync function writeTempImage(data: string, mediaType: string): Promise<string> {\n const ext = mediaType.includes('jpeg') || mediaType.includes('jpg') ? 'jpg' : 'png';\n const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'wstack-vision-'));\n const file = path.join(dir, `image.${ext}`);\n await fs.writeFile(file, data, 'base64');\n return file;\n}\n\nfunction schemaProperties(tool: Tool): Record<string, unknown> {\n const schema = tool.inputSchema;\n if (!schema || typeof schema !== 'object') return {};\n const props = (schema as { properties?: unknown | undefined }).properties;\n return props && typeof props === 'object' ? (props as Record<string, unknown>) : {};\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n return value\n .map((item) => {\n if (item && typeof item === 'object' && 'text' in item) {\n return String((item as { text?: unknown | undefined }).text ?? '');\n }\n return typeof item === 'string' ? item : JSON.stringify(item);\n })\n .join('\\n');\n }\n if (value && typeof value === 'object' && 'text' in value) {\n return String((value as { text?: unknown | undefined }).text ?? '');\n }\n return JSON.stringify(value);\n}\n","import { spawn } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { buildChildEnv } from '@wrongstack/core';\n\nexport interface ClipboardImage {\n base64: string;\n mediaType: 'image/png';\n bytes: number;\n}\n\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024;\n\nexport async function readClipboardImage(): Promise<ClipboardImage | null> {\n const platform = process.platform;\n if (platform === 'win32') return readWindows();\n if (platform === 'darwin') return readDarwin();\n if (platform === 'linux') return readLinux();\n return null;\n}\n\n/**\n * Read plain text from the system clipboard. Returns `null` when the clipboard\n * holds no text (or only an image), the read failed, or the platform is\n * unsupported. Used by the TUI's Ctrl+V handler: terminals in raw mode deliver\n * Ctrl+V to the app as a control byte rather than performing a native paste, so\n * we read the clipboard ourselves.\n */\nexport async function readClipboardText(): Promise<string | null> {\n const platform = process.platform;\n if (platform === 'win32') {\n // -Raw preserves embedded newlines; force UTF-8 so non-ASCII survives the\n // pipe. PowerShell appends one trailing newline to stdout — strip it.\n const ps =\n '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-Clipboard -Raw';\n const out = await runCmd('powershell', ['-NoProfile', '-Command', ps]);\n if (out == null) return null;\n const text = out.replace(/\\r?\\n$/, '');\n return text.length > 0 ? text : null;\n }\n if (platform === 'darwin') {\n const out = await runCmd('pbpaste', []);\n return out && out.length > 0 ? out : null;\n }\n if (platform === 'linux') {\n const tries: Array<[string, string[]]> = [\n ['wl-paste', ['--no-newline']],\n ['xclip', ['-selection', 'clipboard', '-o']],\n ];\n for (const [cmd, args] of tries) {\n const out = await runCmd(cmd, args);\n if (out && out.length > 0) return out;\n }\n return null;\n }\n return null;\n}\n\nasync function readWindows(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const ps = [\n 'Add-Type -AssemblyName System.Windows.Forms',\n 'Add-Type -AssemblyName System.Drawing',\n '$img = [System.Windows.Forms.Clipboard]::GetImage()',\n 'if ($img -eq $null) { Write-Output \"NO_IMAGE\"; exit 0 }',\n `$img.Save('${tmp.replace(/\\\\/g, '\\\\\\\\')}', [System.Drawing.Imaging.ImageFormat]::Png)`,\n 'Write-Output \"OK\"',\n ].join('; ');\n const out = await runCmd('powershell', ['-NoProfile', '-Command', ps]);\n if (!out || out.trim() === 'NO_IMAGE') return null;\n if (!out.includes('OK')) return null;\n return readPngFile(tmp);\n}\n\nasync function readDarwin(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const script = [\n 'try',\n ` set the_file to (open for access POSIX file \"${tmp}\" with write permission)`,\n ' write (the clipboard as «class PNGf») to the_file',\n ' close access the_file',\n 'on error',\n ' try',\n ' close access POSIX file \"' + tmp + '\"',\n ' end try',\n ' return \"NO_IMAGE\"',\n 'end try',\n 'return \"OK\"',\n ].join('\\n');\n const out = await runCmd('osascript', ['-e', script]);\n if (out?.trim() !== 'OK') return null;\n return readPngFile(tmp);\n}\n\nasync function readLinux(): Promise<ClipboardImage | null> {\n const tmp = path.join(os.tmpdir(), `wstack-clip-${randomUUID()}.png`);\n const tries: Array<[string, string[]]> = [\n ['wl-paste', ['--type', 'image/png']],\n ['xclip', ['-selection', 'clipboard', '-t', 'image/png', '-o']],\n ];\n for (const [cmd, args] of tries) {\n const ok = await runCmdToFile(cmd, args, tmp).catch(() => false);\n if (ok) return readPngFile(tmp);\n }\n return null;\n}\n\nasync function readPngFile(p: string): Promise<ClipboardImage | null> {\n try {\n const buf = await fs.readFile(p);\n if (buf.length === 0) {\n await fs.unlink(p).catch(() => undefined);\n return null;\n }\n if (buf.length > MAX_IMAGE_BYTES) {\n await fs.unlink(p).catch(() => undefined);\n throw new Error(`Clipboard image exceeds ${MAX_IMAGE_BYTES / 1024 / 1024}MB limit`);\n }\n if (buf[0] !== 0x89 || buf[1] !== 0x50 || buf[2] !== 0x4e || buf[3] !== 0x47) {\n await fs.unlink(p).catch(() => undefined);\n return null;\n }\n await fs.unlink(p).catch(() => undefined);\n return { base64: buf.toString('base64'), mediaType: 'image/png', bytes: buf.length };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n/**\n * Hard ceiling for a clipboard subprocess. Reading the clipboard must never\n * hang the TUI: on a headless/loaded CI runner the PowerShell/xclip/wl-paste\n * read can stall indefinitely (no display, slow shell start). After this we\n * kill the child and resolve the safe default.\n */\nconst CLIPBOARD_CMD_TIMEOUT_MS = 5_000;\n\nfunction runCmd(cmd: string, args: string[]): Promise<string | null> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n let out = '';\n let settled = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n };\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n finish(null);\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => finish(code === 0 ? out : null));\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n const chunks: Buffer[] = [];\n let settled = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n };\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n finish(false);\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (code !== 0 || chunks.length === 0) return finish(false);\n try {\n await fs.writeFile(outPath, Buffer.concat(chunks));\n finish(true);\n } catch {\n finish(false);\n }\n });\n });\n}\n","// makeLightSubagentFactory — a dependency-light `AgentFactory` that builds a\n// fresh, isolated `Agent` per subagent task WITHOUT the full director / budget /\n// ACP machinery of the CLI's `MultiAgentHost`.\n//\n// Why this exists: `MultiAgentHost` lives in `@wrongstack/cli`, which the WebUI\n// packages cannot import (layer rule: webui ⇏ cli). But `SddParallelRun` only\n// needs an `AgentFactory` (a core interface) to run real parallel waves with\n// per-task git-worktree isolation. This factory provides exactly that, built\n// from primitives both webui servers already have (a DI container + the provider\n// and tool registries + a session writer). It deliberately does NOT touch the\n// budget/watchdog/director subsystems — those stay owned by the CLI host.\n//\n// Each call constructs a fresh `Context` + `EventBus` (true isolation) and\n// honours `SubagentConfig.cwd` so per-task worktrees don't collide. Subagents\n// cannot answer interactive permission prompts, so they run under an\n// `AutoApprovePermissionPolicy` granted the wide work capabilities (fs.write,\n// shell, …) — the user authorised the work when they pressed \"Start Run\".\n\nimport {\n Agent,\n AutoApprovePermissionPolicy,\n type AgentFactory,\n type AgentFactoryResult,\n type Config,\n type Container,\n Context,\n createDefaultPipelines,\n createFallbackModelExtension,\n EventBus,\n resolveModelMatrix,\n resolveModelTargetFromEntry,\n type ProviderRegistry,\n type SessionWriter,\n type SubagentConfig,\n type TextBlock,\n type Tool,\n ToolExecutor,\n ToolRegistry,\n TOKENS,\n WIDE_SUBAGENT_CAPABILITIES,\n} from '@wrongstack/core';\n\nexport interface LightSubagentFactoryDeps {\n /** DI container — used to resolve configStore / tokenCounter / scrubber / prompt builder. */\n container: Container;\n /** Provider registry (already populated by the host) used to build per-subagent providers. */\n providerRegistry: ProviderRegistry;\n /** Full tool registry — each subagent gets an isolated clone of it. */\n toolRegistry: ToolRegistry;\n /** Parent session writer; subagent events are interleaved via a guarded shim. */\n session: SessionWriter;\n /** Project root anchor. */\n projectRoot: string;\n /** Default cwd when a SubagentConfig doesn't pin one (worktree path otherwise). */\n cwd?: string | undefined;\n}\n\n/**\n * Build a default subagent baseline so a leaf worker knows it's running under a\n * run, not as the user-facing leader. Kept terse — the system-prompt builder\n * already supplies identity/tools/skills when `subagent: true`.\n */\nconst SUBAGENT_BASELINE =\n 'You are a subagent executing one delegated task end-to-end. Work autonomously with your tools; do not ask for confirmation on routine in-project actions. Keep output concise.';\n\n// Slot in ctx.meta where the per-subagent AbortController is stored.\n// Callers retrieve it via abortLightSubagent(agent).\nconst _SUBAGENT_ABORT = 'wrongstack:subagent-abort-controller';\n\n/**\n * Retrieve and abort a light subagent's AbortController (stored in ctx.meta\n * by makeLightSubagentFactory). Idempotent — calling abort() on an already-aborted\n * signal is a no-op.\n */\nexport function abortLightSubagent(agent: Agent): void {\n const ac = agent.ctx.meta[_SUBAGENT_ABORT] as AbortController | undefined;\n ac?.abort();\n}\n\nexport function makeLightSubagentFactory(deps: LightSubagentFactoryDeps): AgentFactory {\n const configStore = deps.container.resolve(TOKENS.ConfigStore);\n const tokenCounter = deps.container.resolve(TOKENS.TokenCounter);\n const secretScrubber = deps.container.resolve(TOKENS.SecretScrubber);\n const systemPromptBuilder = deps.container.resolve(TOKENS.SystemPromptBuilder);\n\n return async (subCfg: SubagentConfig): Promise<AgentFactoryResult> => {\n const events = new EventBus();\n const config = configStore.get();\n\n const matrixEntry = subCfg.model\n ? undefined\n : resolveModelMatrix(config.modelMatrix, subCfg.role);\n const matrixTarget = resolveModelTargetFromEntry(config, matrixEntry);\n const effProvider = subCfg.provider ?? matrixTarget?.provider ?? config.provider;\n const effModel = subCfg.model ?? matrixTarget?.model ?? config.model;\n const provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n\n const subCwd = subCfg.cwd ?? deps.cwd ?? deps.projectRoot;\n\n // Isolated tool registry per subagent: the run wraps this factory with\n // `withDisabledToolFiltering`, which unregister()s tools (e.g. delegate) on\n // the agent's registry — that must never mutate the shared parent registry.\n const allowed = filterToolList(deps.toolRegistry, subCfg.tools);\n const subRegistry = new ToolRegistry();\n for (const t of allowed) subRegistry.register(t);\n\n const baseSystem: TextBlock[] = await systemPromptBuilder.build({\n cwd: subCwd,\n projectRoot: deps.projectRoot,\n tools: allowed,\n model: effModel,\n provider: effProvider,\n subagent: true,\n });\n baseSystem.unshift({ type: 'text', text: SUBAGENT_BASELINE });\n if (subCfg.systemPromptOverride) {\n baseSystem.push({ type: 'text', text: subCfg.systemPromptOverride });\n }\n\n const agentName = subCfg.name ?? subCfg.id ?? `sub_${cryptoId()}`;\n const session = makeSubagentSessionShim(deps.session);\n\n // Keep the AbortController reference so callers can abort this subagent's\n // work. Stored with a symbol key so it is opaque to general-purpose consumers.\n const ac = new AbortController();\n const ctx = new Context({\n systemPrompt: baseSystem,\n provider,\n session,\n signal: ac.signal,\n tokenCounter,\n cwd: subCwd,\n projectRoot: deps.projectRoot,\n allowOutsideProjectRoot:\n config.features?.allowOutsideProjectRoot ?? !(config.tools?.restrictToProjectRoot ?? false),\n model: effModel,\n tools: allowed,\n agentId: agentName,\n agentName,\n });\n if (subCfg.role) ctx.meta['agentRole'] = subCfg.role;\n // Store the AbortController so abortLightSubagent() can retrieve it.\n (ctx.meta[_SUBAGENT_ABORT] as AbortController) = ac;\n\n // Subagents can't answer prompts — auto-approve the wide work capability set\n // (the spawn site may narrow it via allowedCapabilities). `source: 'yolo'`\n // from this policy is the authoritative-auto waiver the ToolExecutor trusts\n // for dangerous caps (fs.write, shell), so code edits actually go through.\n const caps = subCfg.allowedCapabilities ?? WIDE_SUBAGENT_CAPABILITIES;\n const permissionPolicy = new AutoApprovePermissionPolicy(caps);\n\n const toolExecutor = new ToolExecutor(subRegistry, {\n permissionPolicy,\n secretScrubber,\n events,\n confirmAwaiter: undefined,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? 120_000,\n perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? 100_000,\n tracer: undefined,\n });\n\n const agent = new Agent({\n container: deps.container,\n tools: subRegistry,\n providers: deps.providerRegistry,\n events,\n pipelines: createDefaultPipelines(),\n context: ctx,\n permissionPolicy,\n toolExecutor,\n });\n\n // Fallback chain for THIS worker: a per-task `fallbackModels` (set in the\n // WebUI) overrides the live config's chain; otherwise the config's explicit\n // list or smart default applies. Without this a 429/529/5xx on a worker's\n // model — after its own retries — fails the task instead of rotating. Mirrors\n // the CLI host factory so both surfaces behave identically.\n const subFallbacks = subCfg.fallbackModels;\n const matrixFallbacks = matrixTarget?.fallbackModels;\n agent.extensions.register(\n createFallbackModelExtension({\n getConfig: () => {\n const live = configStore.get();\n if (subFallbacks && subFallbacks.length) return { ...live, fallbackModels: subFallbacks };\n if (matrixFallbacks && matrixFallbacks.length) return { ...live, fallbackModels: matrixFallbacks };\n return live;\n },\n buildProvider: (id) => buildProvider(deps.providerRegistry, configStore.get(), id, effModel),\n events,\n }),\n );\n\n return { agent, events };\n };\n}\n\n// ── helpers ──────────────────────────────────────────────────────────────────\n\nfunction filterToolList(registry: ToolRegistry, allow?: string[]): Tool[] {\n const all = registry.list();\n if (!allow || allow.length === 0) return all;\n const allowSet = new Set(allow);\n return all.filter((t) => allowSet.has(t.name));\n}\n\nfunction buildProvider(\n registry: ProviderRegistry,\n config: Config,\n providerId: string,\n model: string,\n): ReturnType<ProviderRegistry['create']> {\n const providerConfig = config.providers?.[providerId] ?? {\n type: providerId,\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n };\n if (!registry.has(providerId)) {\n throw new Error(\n `No provider factory registered for \"${providerId}\" — cannot build a subagent provider for the SDD run.`,\n );\n }\n return registry.create({ ...providerConfig, type: providerId, model });\n}\n\n/**\n * Guarded SessionWriter shim that interleaves subagent events into the parent\n * JSONL while NEVER touching checkpoint / in-flight / lifecycle state — those\n * belong to the parent and a subagent writing them would corrupt the parent's\n * rewind + crash-recovery markers. Mirrors the CLI host's fallback shim.\n */\nfunction makeSubagentSessionShim(parent: SessionWriter): SessionWriter {\n return {\n id: parent.id,\n transcriptPath: parent.transcriptPath,\n get pendingToolUses(): string[] {\n return [];\n },\n append: (ev) => parent.append({ ...ev }),\n appendBatch: (evs) => parent.appendBatch(evs.map((e) => ({ ...e }))),\n flush: () => parent.flush(),\n close: async () => {},\n recordFileChange: () => {},\n recordSideEffect: () => {},\n writeCheckpoint: async () => {},\n writeFileSnapshot: async () => {},\n truncateToCheckpoint: async () => 0,\n clearSession: async () => {},\n writeInFlightMarker: async () => {},\n clearInFlightMarker: async () => {},\n } satisfies SessionWriter;\n}\n\nfunction cryptoId(): string {\n return crypto.randomUUID().slice(0, 8);\n}\n"]}
package/dist/vision.d.ts CHANGED
@@ -33,10 +33,27 @@ declare class ImageInputUnsupportedError extends Error {
33
33
  imageCount: number;
34
34
  });
35
35
  }
36
+ /**
37
+ * Thrown when an image URL targets a private / loopback / IMDS address.
38
+ * Vision adapters forward URLs straight to the underlying tool, so without
39
+ * this check a malicious (or accidentally-malformed) `image.source.url`
40
+ * could turn image analysis into an SSRF vector hitting localhost, RFC1918
41
+ * ranges, or the cloud metadata endpoint.
42
+ *
43
+ * Carries the rejected URL so callers can log / surface it without parsing
44
+ * the message.
45
+ */
46
+ declare class VisionUrlBlockedError extends Error {
47
+ readonly url: string;
48
+ constructor(opts: {
49
+ url: string;
50
+ reason: string;
51
+ });
52
+ }
36
53
  declare function routeImagesForModel(blocks: ContentBlock[], opts: VisionRoutingOptions): Promise<VisionRoutingResult>;
37
54
  interface ToolVisionAdapterOptions {
38
55
  prompt?: string | undefined;
39
56
  }
40
57
  declare function createToolVisionAdapters(registry: ToolRegistry, opts?: ToolVisionAdapterOptions): VisionAdapter[];
41
58
 
42
- export { ImageInputUnsupportedError, type ToolVisionAdapterOptions, type VisionAdapter, type VisionAdapterInput, type VisionAdapters, type VisionRoutingOptions, type VisionRoutingResult, createToolVisionAdapters, routeImagesForModel };
59
+ export { ImageInputUnsupportedError, type ToolVisionAdapterOptions, type VisionAdapter, type VisionAdapterInput, type VisionAdapters, type VisionRoutingOptions, type VisionRoutingResult, VisionUrlBlockedError, createToolVisionAdapters, routeImagesForModel };
package/dist/vision.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import * as os from 'os';
3
3
  import * as path from 'path';
4
+ import { assertNotPrivateHost } from '@wrongstack/core';
4
5
 
5
6
  // src/vision.ts
6
7
  var ImageInputUnsupportedError = class extends Error {
@@ -12,6 +13,14 @@ var ImageInputUnsupportedError = class extends Error {
12
13
  this.name = "ImageInputUnsupportedError";
13
14
  }
14
15
  };
16
+ var VisionUrlBlockedError = class extends Error {
17
+ url;
18
+ constructor(opts) {
19
+ super(`vision: blocked unsafe image URL "${opts.url}" (${opts.reason})`);
20
+ this.name = "VisionUrlBlockedError";
21
+ this.url = opts.url;
22
+ }
23
+ };
15
24
  async function routeImagesForModel(blocks, opts) {
16
25
  const images = blocks.filter((b) => b.type === "image");
17
26
  if (images.length === 0) {
@@ -126,6 +135,14 @@ async function buildToolPayload(tool, image, prompt = "Describe this image for a
126
135
  const data = image.source.data;
127
136
  const url = image.source.url;
128
137
  let cleanup;
138
+ if (image.source.type === "url" && url) {
139
+ try {
140
+ await assertNotPrivateHost(new URL(url).hostname);
141
+ } catch (err) {
142
+ const reason = err instanceof Error && err.message.startsWith("fetch:") ? err.message.slice("fetch:".length).trim() : "unresolvable host";
143
+ throw new VisionUrlBlockedError({ url, reason });
144
+ }
145
+ }
129
146
  const pathKey = firstPresent(props, [
130
147
  "path",
131
148
  "image_path",
@@ -201,6 +218,6 @@ function stringifyToolResult(value) {
201
218
  return JSON.stringify(value);
202
219
  }
203
220
 
204
- export { ImageInputUnsupportedError, createToolVisionAdapters, routeImagesForModel };
221
+ export { ImageInputUnsupportedError, VisionUrlBlockedError, createToolVisionAdapters, routeImagesForModel };
205
222
  //# sourceMappingURL=vision.js.map
206
223
  //# sourceMappingURL=vision.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vision.ts"],"names":[],"mappings":"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","file":"vision.js","sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ContentBlock, Context, ImageBlock, Tool, ToolRegistry } from '@wrongstack/core';\n\nexport interface VisionAdapterInput {\n image: ImageBlock;\n prompt?: string | undefined;\n ctx: Context;\n signal: AbortSignal;\n}\n\nexport interface VisionAdapter {\n name: string;\n describe(input: VisionAdapterInput): Promise<string>;\n}\n\nexport type VisionAdapters =\n | readonly VisionAdapter[]\n | (() => readonly VisionAdapter[] | Promise<readonly VisionAdapter[]>);\n\nexport interface VisionRoutingOptions {\n supportsVision: boolean;\n adapters?: VisionAdapters | undefined;\n ctx: Context;\n signal: AbortSignal;\n prompt?: string | undefined;\n providerId?: string | undefined;\n model?: string | undefined;\n}\n\nexport interface VisionRoutingResult {\n blocks: ContentBlock[];\n route: 'native' | 'adapter' | 'none';\n convertedImages: number;\n adapterName?: string | undefined;\n}\n\nexport class ImageInputUnsupportedError extends Error {\n constructor(opts: { providerId?: string | undefined; model?: string | undefined; imageCount: number }) {\n const target = [opts.providerId, opts.model].filter(Boolean).join('/') || 'current model';\n super(\n `${target} does not support image input, and no image-understanding adapter is available for ${opts.imageCount} image${opts.imageCount === 1 ? '' : 's'}. Switch to a vision model or enable an MCP/tool adapter that can describe images.`,\n );\n this.name = 'ImageInputUnsupportedError';\n }\n}\n\nexport async function routeImagesForModel(\n blocks: ContentBlock[],\n opts: VisionRoutingOptions,\n): Promise<VisionRoutingResult> {\n const images = blocks.filter((b): b is ImageBlock => b.type === 'image');\n if (images.length === 0) {\n return { blocks, route: 'none', convertedImages: 0 };\n }\n if (opts.supportsVision) {\n return { blocks, route: 'native', convertedImages: 0 };\n }\n\n const adapters = await resolveAdapters(opts.adapters);\n if (adapters.length === 0) {\n throw new ImageInputUnsupportedError({\n providerId: opts.providerId,\n model: opts.model,\n imageCount: images.length,\n });\n }\n\n const out: ContentBlock[] = [];\n let convertedImages = 0;\n let lastErr: unknown;\n let adapterName: string | undefined;\n for (const block of blocks) {\n if (block.type !== 'image') {\n out.push(block);\n continue;\n }\n let description: string | undefined;\n for (const adapter of adapters) {\n try {\n description = await adapter.describe({\n image: block,\n prompt: opts.prompt,\n ctx: opts.ctx,\n signal: opts.signal,\n });\n adapterName = adapter.name;\n break;\n } catch (err) {\n lastErr = err;\n }\n }\n if (!description?.trim()) {\n throw new Error(\n `No image-understanding adapter could process an image.${lastErr instanceof Error ? ` Last error: ${lastErr.message}` : ''}`,\n );\n }\n convertedImages++;\n out.push({\n type: 'text',\n text: `[Image ${convertedImages} analyzed via ${adapterName ?? 'vision adapter'}]\\n${description.trim()}`,\n });\n }\n\n return { blocks: out, route: 'adapter', convertedImages, adapterName };\n}\n\nasync function resolveAdapters(adapters: VisionAdapters | undefined): Promise<readonly VisionAdapter[]> {\n if (!adapters) return [];\n return typeof adapters === 'function' ? await adapters() : adapters;\n}\n\nexport interface ToolVisionAdapterOptions {\n prompt?: string | undefined;\n}\n\nexport function createToolVisionAdapters(\n registry: ToolRegistry,\n opts: ToolVisionAdapterOptions = {},\n): VisionAdapter[] {\n return registry\n .list()\n .filter(isLikelyVisionTool)\n .map((tool) => ({\n name: tool.name,\n async describe(input: VisionAdapterInput): Promise<string> {\n const currentTool = registry.get(tool.name);\n if (!currentTool) {\n throw new Error(`Tool \"${tool.name}\" is no longer registered`);\n }\n const built = await buildToolPayload(currentTool, input.image, input.prompt ?? opts.prompt);\n if (!built) {\n throw new Error(`Tool \"${currentTool.name}\" does not expose a supported image input schema`);\n }\n try {\n const result = await currentTool.execute(built.payload, input.ctx, {\n signal: input.signal,\n });\n return stringifyToolResult(result);\n } finally {\n await built.cleanup?.();\n }\n },\n }));\n}\n\nfunction isLikelyVisionTool(tool: Tool): boolean {\n if (tool.permission !== 'auto' || tool.mutating) return false;\n const haystack = `${tool.name} ${tool.description ?? ''} ${tool.usageHint ?? ''}`.toLowerCase();\n if (/(generate|create|draw|paint|edit|upscale|remove|write|delete)/.test(haystack)) return false;\n if (!/(vision|image|screenshot|ocr|describe|analy[sz]e)/.test(haystack)) return false;\n const props = schemaProperties(tool);\n return [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n ].some((key) => key in props);\n}\n\nasync function buildToolPayload(\n tool: Tool,\n image: ImageBlock,\n prompt = 'Describe this image for a coding agent. Include visible text, UI state, errors, layout, and any details needed to answer the user.',\n): Promise<{ payload: Record<string, unknown>; cleanup?: () => Promise<void> } | null> {\n const props = schemaProperties(tool);\n const payload: Record<string, unknown> = {};\n const mediaType = image.source.media_type ?? 'image/png';\n const data = image.source.data;\n const url = image.source.url;\n let cleanup: (() => Promise<void>) | undefined;\n\n const pathKey = firstPresent(props, [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n ]);\n if (pathKey && image.source.type === 'base64' && data) {\n const p = await writeTempImage(data, mediaType);\n payload[pathKey] = p;\n cleanup = async () => {\n await fs.unlink(p).catch(() => undefined);\n await fs.rmdir(path.dirname(p)).catch(() => undefined);\n };\n } else if ('image' in props) {\n payload.image =\n image.source.type === 'base64'\n ? { type: 'base64', mediaType, media_type: mediaType, data }\n : { type: 'url', url };\n } else if (image.source.type === 'base64' && 'base64' in props) {\n payload.base64 = data;\n } else if (image.source.type === 'base64' && 'data' in props) {\n payload.data = data;\n } else if (image.source.type === 'url' && 'url' in props) {\n payload.url = url;\n } else if (image.source.type === 'url' && 'image_url' in props) {\n payload.image_url = url;\n } else if (image.source.type === 'url' && 'imageUrl' in props) {\n payload.imageUrl = url;\n } else {\n return null;\n }\n\n if ('mediaType' in props) payload.mediaType = mediaType;\n if ('mimeType' in props) payload.mimeType = mediaType;\n if ('media_type' in props) payload.media_type = mediaType;\n if ('prompt' in props) payload.prompt = prompt;\n if ('query' in props) payload.query = prompt;\n if ('instruction' in props) payload.instruction = prompt;\n const built: { payload: Record<string, unknown>; cleanup?: () => Promise<void> } = { payload };\n if (cleanup !== undefined) built.cleanup = cleanup;\n return built;\n}\n\nfunction firstPresent(props: Record<string, unknown>, keys: string[]): string | undefined {\n return keys.find((key) => key in props);\n}\n\nasync function writeTempImage(data: string, mediaType: string): Promise<string> {\n const ext = mediaType.includes('jpeg') || mediaType.includes('jpg') ? 'jpg' : 'png';\n const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'wstack-vision-'));\n const file = path.join(dir, `image.${ext}`);\n await fs.writeFile(file, data, 'base64');\n return file;\n}\n\nfunction schemaProperties(tool: Tool): Record<string, unknown> {\n const schema = tool.inputSchema;\n if (!schema || typeof schema !== 'object') return {};\n const props = (schema as { properties?: unknown | undefined }).properties;\n return props && typeof props === 'object' ? (props as Record<string, unknown>) : {};\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n return value\n .map((item) => {\n if (item && typeof item === 'object' && 'text' in item) {\n return String((item as { text?: unknown | undefined }).text ?? '');\n }\n return typeof item === 'string' ? item : JSON.stringify(item);\n })\n .join('\\n');\n }\n if (value && typeof value === 'object' && 'text' in value) {\n return String((value as { text?: unknown | undefined }).text ?? '');\n }\n return JSON.stringify(value);\n}\n"]}
1
+ {"version":3,"sources":["../src/vision.ts"],"names":[],"mappings":"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","file":"vision.js","sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { assertNotPrivateHost } from '@wrongstack/core';\nimport type { ContentBlock, Context, ImageBlock, Tool, ToolRegistry } from '@wrongstack/core';\n\nexport interface VisionAdapterInput {\n image: ImageBlock;\n prompt?: string | undefined;\n ctx: Context;\n signal: AbortSignal;\n}\n\nexport interface VisionAdapter {\n name: string;\n describe(input: VisionAdapterInput): Promise<string>;\n}\n\nexport type VisionAdapters =\n | readonly VisionAdapter[]\n | (() => readonly VisionAdapter[] | Promise<readonly VisionAdapter[]>);\n\nexport interface VisionRoutingOptions {\n supportsVision: boolean;\n adapters?: VisionAdapters | undefined;\n ctx: Context;\n signal: AbortSignal;\n prompt?: string | undefined;\n providerId?: string | undefined;\n model?: string | undefined;\n}\n\nexport interface VisionRoutingResult {\n blocks: ContentBlock[];\n route: 'native' | 'adapter' | 'none';\n convertedImages: number;\n adapterName?: string | undefined;\n}\n\nexport class ImageInputUnsupportedError extends Error {\n constructor(opts: { providerId?: string | undefined; model?: string | undefined; imageCount: number }) {\n const target = [opts.providerId, opts.model].filter(Boolean).join('/') || 'current model';\n super(\n `${target} does not support image input, and no image-understanding adapter is available for ${opts.imageCount} image${opts.imageCount === 1 ? '' : 's'}. Switch to a vision model or enable an MCP/tool adapter that can describe images.`,\n );\n this.name = 'ImageInputUnsupportedError';\n }\n}\n\n/**\n * Thrown when an image URL targets a private / loopback / IMDS address.\n * Vision adapters forward URLs straight to the underlying tool, so without\n * this check a malicious (or accidentally-malformed) `image.source.url`\n * could turn image analysis into an SSRF vector hitting localhost, RFC1918\n * ranges, or the cloud metadata endpoint.\n *\n * Carries the rejected URL so callers can log / surface it without parsing\n * the message.\n */\nexport class VisionUrlBlockedError extends Error {\n readonly url: string;\n\n constructor(opts: { url: string; reason: string }) {\n super(`vision: blocked unsafe image URL \"${opts.url}\" (${opts.reason})`);\n this.name = 'VisionUrlBlockedError';\n this.url = opts.url;\n }\n}\n\nexport async function routeImagesForModel(\n blocks: ContentBlock[],\n opts: VisionRoutingOptions,\n): Promise<VisionRoutingResult> {\n const images = blocks.filter((b): b is ImageBlock => b.type === 'image');\n if (images.length === 0) {\n return { blocks, route: 'none', convertedImages: 0 };\n }\n if (opts.supportsVision) {\n return { blocks, route: 'native', convertedImages: 0 };\n }\n\n const adapters = await resolveAdapters(opts.adapters);\n if (adapters.length === 0) {\n throw new ImageInputUnsupportedError({\n providerId: opts.providerId,\n model: opts.model,\n imageCount: images.length,\n });\n }\n\n const out: ContentBlock[] = [];\n let convertedImages = 0;\n let lastErr: unknown;\n let adapterName: string | undefined;\n for (const block of blocks) {\n if (block.type !== 'image') {\n out.push(block);\n continue;\n }\n let description: string | undefined;\n for (const adapter of adapters) {\n try {\n description = await adapter.describe({\n image: block,\n prompt: opts.prompt,\n ctx: opts.ctx,\n signal: opts.signal,\n });\n adapterName = adapter.name;\n break;\n } catch (err) {\n lastErr = err;\n }\n }\n if (!description?.trim()) {\n throw new Error(\n `No image-understanding adapter could process an image.${lastErr instanceof Error ? ` Last error: ${lastErr.message}` : ''}`,\n );\n }\n convertedImages++;\n out.push({\n type: 'text',\n text: `[Image ${convertedImages} analyzed via ${adapterName ?? 'vision adapter'}]\\n${description.trim()}`,\n });\n }\n\n return { blocks: out, route: 'adapter', convertedImages, adapterName };\n}\n\nasync function resolveAdapters(adapters: VisionAdapters | undefined): Promise<readonly VisionAdapter[]> {\n if (!adapters) return [];\n return typeof adapters === 'function' ? await adapters() : adapters;\n}\n\nexport interface ToolVisionAdapterOptions {\n prompt?: string | undefined;\n}\n\nexport function createToolVisionAdapters(\n registry: ToolRegistry,\n opts: ToolVisionAdapterOptions = {},\n): VisionAdapter[] {\n return registry\n .list()\n .filter(isLikelyVisionTool)\n .map((tool) => ({\n name: tool.name,\n async describe(input: VisionAdapterInput): Promise<string> {\n const currentTool = registry.get(tool.name);\n if (!currentTool) {\n throw new Error(`Tool \"${tool.name}\" is no longer registered`);\n }\n const built = await buildToolPayload(currentTool, input.image, input.prompt ?? opts.prompt);\n if (!built) {\n throw new Error(`Tool \"${currentTool.name}\" does not expose a supported image input schema`);\n }\n try {\n const result = await currentTool.execute(built.payload, input.ctx, {\n signal: input.signal,\n });\n return stringifyToolResult(result);\n } finally {\n await built.cleanup?.();\n }\n },\n }));\n}\n\nfunction isLikelyVisionTool(tool: Tool): boolean {\n if (tool.permission !== 'auto' || tool.mutating) return false;\n const haystack = `${tool.name} ${tool.description ?? ''} ${tool.usageHint ?? ''}`.toLowerCase();\n if (/(generate|create|draw|paint|edit|upscale|remove|write|delete)/.test(haystack)) return false;\n if (!/(vision|image|screenshot|ocr|describe|analy[sz]e)/.test(haystack)) return false;\n const props = schemaProperties(tool);\n return [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n ].some((key) => key in props);\n}\n\nasync function buildToolPayload(\n tool: Tool,\n image: ImageBlock,\n prompt = 'Describe this image for a coding agent. Include visible text, UI state, errors, layout, and any details needed to answer the user.',\n): Promise<{ payload: Record<string, unknown>; cleanup?: () => Promise<void> } | null> {\n const props = schemaProperties(tool);\n const payload: Record<string, unknown> = {};\n const mediaType = image.source.media_type ?? 'image/png';\n const data = image.source.data;\n const url = image.source.url;\n let cleanup: (() => Promise<void>) | undefined;\n\n // SSRF guard: when the image is referenced by URL, validate the host\n // BEFORE forwarding it to the underlying vision tool. The tool may\n // itself fetch the URL (the typical case for an MCP image-understanding\n // adapter), so a URL pointing at localhost / 127.0.0.1 / 169.254.169.254\n // / RFC1918 ranges would otherwise become an SSRF vector. Without this\n // gate, vision is a back-door around the fetch.ts SSRF guard (which\n // only applies when the explicit `fetch` tool is invoked).\n if (image.source.type === 'url' && url) {\n try {\n await assertNotPrivateHost(new URL(url).hostname);\n } catch (err) {\n const reason =\n err instanceof Error && err.message.startsWith('fetch:')\n ? err.message.slice('fetch:'.length).trim()\n : 'unresolvable host';\n throw new VisionUrlBlockedError({ url, reason });\n }\n }\n\n const pathKey = firstPresent(props, [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n ]);\n if (pathKey && image.source.type === 'base64' && data) {\n const p = await writeTempImage(data, mediaType);\n payload[pathKey] = p;\n cleanup = async () => {\n await fs.unlink(p).catch(() => undefined);\n await fs.rmdir(path.dirname(p)).catch(() => undefined);\n };\n } else if ('image' in props) {\n payload.image =\n image.source.type === 'base64'\n ? { type: 'base64', mediaType, media_type: mediaType, data }\n : { type: 'url', url };\n } else if (image.source.type === 'base64' && 'base64' in props) {\n payload.base64 = data;\n } else if (image.source.type === 'base64' && 'data' in props) {\n payload.data = data;\n } else if (image.source.type === 'url' && 'url' in props) {\n payload.url = url;\n } else if (image.source.type === 'url' && 'image_url' in props) {\n payload.image_url = url;\n } else if (image.source.type === 'url' && 'imageUrl' in props) {\n payload.imageUrl = url;\n } else {\n return null;\n }\n\n if ('mediaType' in props) payload.mediaType = mediaType;\n if ('mimeType' in props) payload.mimeType = mediaType;\n if ('media_type' in props) payload.media_type = mediaType;\n if ('prompt' in props) payload.prompt = prompt;\n if ('query' in props) payload.query = prompt;\n if ('instruction' in props) payload.instruction = prompt;\n const built: { payload: Record<string, unknown>; cleanup?: () => Promise<void> } = { payload };\n if (cleanup !== undefined) built.cleanup = cleanup;\n return built;\n}\n\nfunction firstPresent(props: Record<string, unknown>, keys: string[]): string | undefined {\n return keys.find((key) => key in props);\n}\n\nasync function writeTempImage(data: string, mediaType: string): Promise<string> {\n const ext = mediaType.includes('jpeg') || mediaType.includes('jpg') ? 'jpg' : 'png';\n const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'wstack-vision-'));\n const file = path.join(dir, `image.${ext}`);\n await fs.writeFile(file, data, 'base64');\n return file;\n}\n\nfunction schemaProperties(tool: Tool): Record<string, unknown> {\n const schema = tool.inputSchema;\n if (!schema || typeof schema !== 'object') return {};\n const props = (schema as { properties?: unknown | undefined }).properties;\n return props && typeof props === 'object' ? (props as Record<string, unknown>) : {};\n}\n\nfunction stringifyToolResult(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n return value\n .map((item) => {\n if (item && typeof item === 'object' && 'text' in item) {\n return String((item as { text?: unknown | undefined }).text ?? '');\n }\n return typeof item === 'string' ? item : JSON.stringify(item);\n })\n .join('\\n');\n }\n if (value && typeof value === 'object' && 'text' in value) {\n return String((value as { text?: unknown | undefined }).text ?? '');\n }\n return JSON.stringify(value);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/runtime",
3
- "version": "0.275.0",
3
+ "version": "0.276.2",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack default runtime implementations and host-level composition helpers built on @wrongstack/core.",
6
6
  "repository": {
@@ -47,7 +47,7 @@
47
47
  "README.md"
48
48
  ],
49
49
  "dependencies": {
50
- "@wrongstack/core": "0.275.0"
50
+ "@wrongstack/core": "0.276.2"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "^25.9.3",