@wrongstack/runtime 0.295.1 → 0.296.3

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.
@@ -4,6 +4,15 @@ export interface ClipboardImage {
4
4
  bytes: number;
5
5
  }
6
6
  export declare function readClipboardImage(): Promise<ClipboardImage | null>;
7
+ /**
8
+ * Write plain text to the system clipboard. Returns `true` on success, `false`
9
+ * when the platform is unsupported, no clipboard tool is available, or the
10
+ * child process failed. Mirrors `readClipboardText`'s platform matrix
11
+ * (PowerShell on Windows, `pbcopy` on macOS, `wl-copy`/`xclip` on Linux) and is
12
+ * used by the TUI to copy a chat card's content when its copy icon is clicked —
13
+ * terminals in raw mode never perform a native copy, so we do it ourselves.
14
+ */
15
+ export declare function writeClipboardText(text: string): Promise<boolean>;
7
16
  /**
8
17
  * Read plain text from the system clipboard. Returns `null` when the clipboard
9
18
  * holds no text (or only an image), the read failed, or the platform is
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAMzE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2BhE"}
1
+ {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAMzE;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BvE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2BhE"}
package/dist/clipboard.js CHANGED
@@ -13,6 +13,27 @@ async function readClipboardImage() {
13
13
  if (platform === "linux") return readLinux();
14
14
  return null;
15
15
  }
16
+ async function writeClipboardText(text) {
17
+ const platform = process.platform;
18
+ if (platform === "win32") {
19
+ const ps = "[Console]::InputEncoding = [System.Text.Encoding]::UTF8; $in = [Console]::In.ReadToEnd(); Set-Clipboard -Value $in";
20
+ return runCmdWithInput("powershell", ["-NoProfile", "-Command", ps], text);
21
+ }
22
+ if (platform === "darwin") {
23
+ return runCmdWithInput("pbcopy", [], text);
24
+ }
25
+ if (platform === "linux") {
26
+ const tries = [
27
+ ["wl-copy", []],
28
+ ["xclip", ["-selection", "clipboard"]]
29
+ ];
30
+ for (const [cmd, args] of tries) {
31
+ if (await runCmdWithInput(cmd, args, text)) return true;
32
+ }
33
+ return false;
34
+ }
35
+ return false;
36
+ }
16
37
  async function readClipboardText() {
17
38
  const platform = process.platform;
18
39
  if (platform === "win32") {
@@ -140,6 +161,37 @@ function runCmd(cmd, args) {
140
161
  });
141
162
  });
142
163
  }
164
+ function runCmdWithInput(cmd, args, input) {
165
+ return new Promise((resolve) => {
166
+ const child = spawn(cmd, args, {
167
+ env: buildChildEnv(),
168
+ stdio: ["pipe", "ignore", "ignore"],
169
+ windowsHide: true
170
+ });
171
+ let settled = false;
172
+ let killedByTimeout = false;
173
+ const finish = (value) => {
174
+ if (settled) return;
175
+ settled = true;
176
+ clearTimeout(timer);
177
+ clearTimeout(killCap);
178
+ resolve(value);
179
+ };
180
+ const timer = setTimeout(() => {
181
+ killedByTimeout = true;
182
+ child.kill("SIGTERM");
183
+ }, CLIPBOARD_CMD_TIMEOUT_MS);
184
+ const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2e3);
185
+ child.on("error", () => finish(false));
186
+ child.on("exit", (code) => {
187
+ if (killedByTimeout) return finish(false);
188
+ finish(code === 0);
189
+ });
190
+ child.stdin.on("error", () => {
191
+ });
192
+ child.stdin.end(input, "utf8");
193
+ });
194
+ }
143
195
  function runCmdToFile(cmd, args, outPath) {
144
196
  return new Promise((resolve) => {
145
197
  const child = spawn(cmd, args, {
@@ -178,6 +230,7 @@ function runCmdToFile(cmd, args, outPath) {
178
230
  }
179
231
  export {
180
232
  readClipboardImage,
181
- readClipboardText
233
+ readClipboardText,
234
+ writeClipboardText
182
235
  };
183
236
  //# sourceMappingURL=clipboard.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/clipboard.ts"],
4
- "sourcesContent": ["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/utils';\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 \u2014 strip it.\n const ps = '[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 \u00ABclass PNGf\u00BB) 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, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n let out = '';\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(null), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(null);\n finish(code === 0 ? out : null);\n });\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n const chunks: Buffer[] = [];\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (killedByTimeout) return finish(false);\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"],
5
- "mappings": "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",
4
+ "sourcesContent": ["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/utils';\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 * Write plain text to the system clipboard. Returns `true` on success, `false`\n * when the platform is unsupported, no clipboard tool is available, or the\n * child process failed. Mirrors `readClipboardText`'s platform matrix\n * (PowerShell on Windows, `pbcopy` on macOS, `wl-copy`/`xclip` on Linux) and is\n * used by the TUI to copy a chat card's content when its copy icon is clicked \u2014\n * terminals in raw mode never perform a native copy, so we do it ourselves.\n */\nexport async function writeClipboardText(text: string): Promise<boolean> {\n const platform = process.platform;\n if (platform === 'win32') {\n // Read the payload from stdin so arbitrary text (quotes, newlines,\n // non-ASCII) never has to be escaped into the command line. Force UTF-8 so\n // multibyte characters survive the pipe.\n const ps =\n '[Console]::InputEncoding = [System.Text.Encoding]::UTF8; ' +\n '$in = [Console]::In.ReadToEnd(); ' +\n 'Set-Clipboard -Value $in';\n return runCmdWithInput('powershell', ['-NoProfile', '-Command', ps], text);\n }\n if (platform === 'darwin') {\n return runCmdWithInput('pbcopy', [], text);\n }\n if (platform === 'linux') {\n const tries: Array<[string, string[]]> = [\n ['wl-copy', []],\n ['xclip', ['-selection', 'clipboard']],\n ];\n for (const [cmd, args] of tries) {\n if (await runCmdWithInput(cmd, args, text)) return true;\n }\n return false;\n }\n return false;\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 \u2014 strip it.\n const ps = '[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 \u00ABclass PNGf\u00BB) 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, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n let out = '';\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(null), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(null);\n finish(code === 0 ? out : null);\n });\n });\n}\n\n/**\n * Spawn `cmd` and feed `input` to its stdin, resolving `true` when the child\n * exits 0 within the timeout and `false` on spawn error, non-zero exit, or\n * timeout. Used by `writeClipboardText`; stdin is the payload channel so text\n * never touches the command line.\n */\nfunction runCmdWithInput(cmd: string, args: string[], input: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['pipe', 'ignore', 'ignore'],\n windowsHide: true,\n });\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.on('error', () => finish(false));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(false);\n finish(code === 0);\n });\n // Writing to stdin can EPIPE if the child already exited; swallow it and\n // let the exit handler decide the outcome.\n child.stdin.on('error', () => {});\n child.stdin.end(input, 'utf8');\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n const chunks: Buffer[] = [];\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (killedByTimeout) return finish(false);\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"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iCAAiC,EAEvC,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAU,MAAM,yBAAyB,CAAC;AAS3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQ1D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC3B,cAAc,CAAC,EAAE,CACf,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,OAAO,EACd,gBAAgB,EAAE,MAAM,KACrB,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,CAAC,CAAC;KAChD,CAAC;IACF,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACpF,YAAY,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,GAAG,SAAS,CAAC;IACtE,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,SAAS,CA4L9E"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iCAAiC,EAEvC,MAAM,wBAAwB,CAAC;AAShC,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAU,MAAM,yBAAyB,CAAC;AAS3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQ1D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC3B,cAAc,CAAC,EAAE,CACf,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,OAAO,EACd,gBAAgB,EAAE,MAAM,KACrB,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,CAAC,CAAC;KAChD,CAAC;IACF,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACpF,YAAY,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,GAAG,SAAS,CAAC;IACtE,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,SAAS,CAqM9E"}
@@ -1,5 +1,5 @@
1
1
  import { Agent } from '@wrongstack/core/agent';
2
- import { type AgentFactory } from '@wrongstack/core/coordination';
2
+ import { type AgentFactory, type ProviderModelStatusTracker } from '@wrongstack/core/coordination';
3
3
  import { type Container } from '@wrongstack/core/kernel';
4
4
  import { type ProviderRegistry, ToolRegistry } from '@wrongstack/core/registry';
5
5
  import type { ModelsRegistry, SessionWriter } from '@wrongstack/core/types';
@@ -24,6 +24,16 @@ export interface LightSubagentFactoryDeps {
24
24
  * should leave this unset.
25
25
  */
26
26
  now?: (() => number) | undefined;
27
+ /**
28
+ * Shared (provider, model) health tracker. When provided, the subagent's
29
+ * fallback extension records 429 / 5xx / timeout / stream-hang failures
30
+ * into it and skips blocked entries on subsequent calls — closing the
31
+ * waiting-room trigger for webui-server SDD parallel runs. When unset
32
+ * the extension still works, but a 429 leaves no quarantine signal and
33
+ * round-robin keeps reassigning the doomed model. Mirrors the
34
+ * `host.opts.statusTracker` thread in the CLI factory.
35
+ */
36
+ statusTracker?: ProviderModelStatusTracker | undefined;
27
37
  }
28
38
  /**
29
39
  * Retrieve and abort a light subagent's AbortController (stored in ctx.meta
@@ -1 +1 @@
1
- {"version":3,"file":"light-subagent-factory.d.ts","sourceRoot":"","sources":["../../src/fleet/light-subagent-factory.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,KAAK,EAKN,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,KAAK,gBAAgB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEhF,OAAO,KAAK,EAEV,cAAc,EAGd,aAAa,EAId,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,wBAAwB;IACvC,6FAA6F;IAC7F,SAAS,EAAE,SAAS,CAAC;IACrB,8FAA8F;IAC9F,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,uEAAuE;IACvE,YAAY,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,cAAc,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,iFAAiF;IACjF,OAAO,EAAE,aAAa,CAAC;IACvB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;CAClC;AAcD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAGrD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,wBAAwB,GAAG,YAAY,CAoKrF"}
1
+ {"version":3,"file":"light-subagent-factory.d.ts","sourceRoot":"","sources":["../../src/fleet/light-subagent-factory.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,KAAK,EAKN,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,0BAA0B,EAEhC,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,KAAK,gBAAgB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEhF,OAAO,KAAK,EAEV,cAAc,EAGd,aAAa,EAId,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,wBAAwB;IACvC,6FAA6F;IAC7F,SAAS,EAAE,SAAS,CAAC;IACrB,8FAA8F;IAC9F,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,uEAAuE;IACvE,YAAY,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,cAAc,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,iFAAiF;IACjF,OAAO,EAAE,aAAa,CAAC;IACvB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IACjC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAC;CACxD;AAcD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAGrD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,wBAAwB,GAAG,YAAY,CAyKrF"}
package/dist/index.js CHANGED
@@ -13,6 +13,27 @@ async function readClipboardImage() {
13
13
  if (platform === "linux") return readLinux();
14
14
  return null;
15
15
  }
16
+ async function writeClipboardText(text) {
17
+ const platform = process.platform;
18
+ if (platform === "win32") {
19
+ const ps = "[Console]::InputEncoding = [System.Text.Encoding]::UTF8; $in = [Console]::In.ReadToEnd(); Set-Clipboard -Value $in";
20
+ return runCmdWithInput("powershell", ["-NoProfile", "-Command", ps], text);
21
+ }
22
+ if (platform === "darwin") {
23
+ return runCmdWithInput("pbcopy", [], text);
24
+ }
25
+ if (platform === "linux") {
26
+ const tries = [
27
+ ["wl-copy", []],
28
+ ["xclip", ["-selection", "clipboard"]]
29
+ ];
30
+ for (const [cmd, args] of tries) {
31
+ if (await runCmdWithInput(cmd, args, text)) return true;
32
+ }
33
+ return false;
34
+ }
35
+ return false;
36
+ }
16
37
  async function readClipboardText() {
17
38
  const platform = process.platform;
18
39
  if (platform === "win32") {
@@ -140,6 +161,37 @@ function runCmd(cmd, args) {
140
161
  });
141
162
  });
142
163
  }
164
+ function runCmdWithInput(cmd, args, input) {
165
+ return new Promise((resolve) => {
166
+ const child = spawn(cmd, args, {
167
+ env: buildChildEnv(),
168
+ stdio: ["pipe", "ignore", "ignore"],
169
+ windowsHide: true
170
+ });
171
+ let settled = false;
172
+ let killedByTimeout = false;
173
+ const finish = (value) => {
174
+ if (settled) return;
175
+ settled = true;
176
+ clearTimeout(timer);
177
+ clearTimeout(killCap);
178
+ resolve(value);
179
+ };
180
+ const timer = setTimeout(() => {
181
+ killedByTimeout = true;
182
+ child.kill("SIGTERM");
183
+ }, CLIPBOARD_CMD_TIMEOUT_MS);
184
+ const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2e3);
185
+ child.on("error", () => finish(false));
186
+ child.on("exit", (code) => {
187
+ if (killedByTimeout) return finish(false);
188
+ finish(code === 0);
189
+ });
190
+ child.stdin.on("error", () => {
191
+ });
192
+ child.stdin.end(input, "utf8");
193
+ });
194
+ }
143
195
  function runCmdToFile(cmd, args, outPath) {
144
196
  return new Promise((resolve) => {
145
197
  const child = spawn(cmd, args, {
@@ -191,6 +243,7 @@ import {
191
243
  DefaultRetryPolicy,
192
244
  DefaultSkillLoader
193
245
  } from "@wrongstack/core/execution";
246
+ import { ProviderModelStatusTracker } from "@wrongstack/core/coordination";
194
247
  import { Container, TOKENS } from "@wrongstack/core/kernel";
195
248
  import { DefaultModeStore } from "@wrongstack/core/models";
196
249
  import {
@@ -203,7 +256,7 @@ import { DefaultConfigStore, DefaultSessionStore } from "@wrongstack/core/storag
203
256
  import { buildRecoveryStrategies } from "@wrongstack/core/execution";
204
257
  import { DefaultTokenCounter } from "@wrongstack/core/infrastructure";
205
258
  import { getSessionRegistry } from "@wrongstack/core/storage";
206
- import { createSqliteMemoryPort, isSqliteAvailable } from "@wrongstack/sage";
259
+ import { createProjectSageMemoryPort, isSqliteAvailable } from "@wrongstack/sage";
207
260
  function createDefaultContainer(opts) {
208
261
  const { config, wpaths, logger, modelsRegistry } = opts;
209
262
  const container = new Container();
@@ -212,6 +265,7 @@ function createDefaultContainer(opts) {
212
265
  configStore.watch((next) => fallbackProfileManager.reload(next));
213
266
  container.bind(TOKENS.ConfigStore, () => configStore);
214
267
  container.bind(TOKENS.FallbackProfileManager, () => fallbackProfileManager);
268
+ container.bind(TOKENS.ProviderModelStatusTracker, () => new ProviderModelStatusTracker());
215
269
  container.bind(TOKENS.Logger, () => logger);
216
270
  container.bind(TOKENS.SecretScrubber, () => new DefaultSecretScrubber());
217
271
  container.bind(TOKENS.RetryPolicy, () => new DefaultRetryPolicy());
@@ -247,9 +301,6 @@ function createDefaultContainer(opts) {
247
301
  secretScrubber: container.resolve(TOKENS.SecretScrubber),
248
302
  // Cross-process guard consulted by delete(): refuses to remove a
249
303
  // session that a LIVE terminal/TUI/WebUI in this project is using.
250
- // The store also checks active.json directly; this widens the check
251
- // to every concurrently-running surface (active.json only tracks the
252
- // latest active session per project).
253
304
  isSessionInUse: async (sessionId) => {
254
305
  try {
255
306
  const registry = getSessionRegistry(wpaths.globalRoot);
@@ -269,10 +320,11 @@ function createDefaultContainer(opts) {
269
320
  "SAGE requires Node built-in SQLite (node:sqlite; Node >= 22.5). The JSONL compatibility fallback has been removed."
270
321
  );
271
322
  }
272
- const memoryStore = createSqliteMemoryPort({
323
+ const memoryStore = createProjectSageMemoryPort({
273
324
  projectRoot: wpaths.projectRoot,
274
325
  directory: config.Sage?.storage?.directory,
275
- events: opts.events
326
+ events: opts.events,
327
+ workspaceRoot: wpaths.projectRoot
276
328
  });
277
329
  container.bind(TOKENS.MemoryStore, () => memoryStore);
278
330
  container.bind(TOKENS.MemoryPort, () => memoryStore);
@@ -511,7 +563,12 @@ function makeLightSubagentFactory(deps) {
511
563
  subReasoningConfig = await resolveReasoningConfig(modelsRegistry, id, model);
512
564
  },
513
565
  events,
514
- ...deps.now ? { now: deps.now } : {}
566
+ ...deps.now ? { now: deps.now } : {},
567
+ // Thread the shared ProviderModelStatusTracker so a 429 from this
568
+ // subagent's first call transitions the (provider, model) pair to
569
+ // `state: 'blocked'` instead of silently no-op'ing. Mirrors the CLI
570
+ // factory wiring at host-subagent-factory.ts:336.
571
+ ...deps.statusTracker ? { statusTracker: deps.statusTracker } : {}
515
572
  })
516
573
  );
517
574
  return { agent, events };
@@ -1045,6 +1102,7 @@ export {
1045
1102
  probeLocalLlm,
1046
1103
  readClipboardImage,
1047
1104
  readClipboardText,
1048
- routeImagesForModel
1105
+ routeImagesForModel,
1106
+ writeClipboardText
1049
1107
  };
1050
1108
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/clipboard.ts", "../src/container.ts", "../src/fleet/light-subagent-factory.ts", "../src/host.ts", "../src/local-llm-probe.ts", "../src/vision.ts"],
4
- "sourcesContent": ["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/utils';\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 \u2014 strip it.\n const ps = '[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 \u00ABclass PNGf\u00BB) 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, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n let out = '';\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(null), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(null);\n finish(code === 0 ? out : null);\n });\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n const chunks: Buffer[] = [];\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (killedByTimeout) return finish(false);\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", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport {\n DefaultSystemPromptBuilder,\n type DefaultSystemPromptBuilderOptions,\n FallbackProfileManager,\n} from '@wrongstack/core/agent';\nimport {\n createStrategyCompactor,\n DefaultErrorHandler,\n DefaultPromptLoader,\n DefaultRetryPolicy,\n DefaultSkillLoader,\n} from '@wrongstack/core/execution';\nimport { Container, type EventBus, TOKENS } from '@wrongstack/core/kernel';\nimport { DefaultModeStore } from '@wrongstack/core/models';\nimport {\n DirectoryPermissionPolicy,\n DefaultPermissionPolicy,\n DefaultSecretScrubber,\n validateDirectoryPolicy,\n} from '@wrongstack/core/security';\nimport { DefaultConfigStore, DefaultSessionStore } from '@wrongstack/core/storage';\nimport type { Config, Logger, ModelsRegistry, Tool } from '@wrongstack/core/types';\nimport type { WstackPaths } from '@wrongstack/core/utils';\n// PR-C1 (66c4eb68): execution/ and infrastructure/ symbols come from the\n// published subpaths now that types/index.ts no longer re-exports them.\nimport { buildRecoveryStrategies } from '@wrongstack/core/execution';\nimport { DefaultTokenCounter } from '@wrongstack/core/infrastructure';\nimport { getSessionRegistry } from '@wrongstack/core/storage';\nimport { createSqliteMemoryPort, isSqliteAvailable } from '@wrongstack/sage';\n\nexport interface CreateContainerOptions {\n config: Config;\n wpaths: WstackPaths;\n logger: Logger;\n modelsRegistry: ModelsRegistry;\n /**\n * Optional event bus \u2014 passed to SageStore 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 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 const fallbackProfileManager = new FallbackProfileManager(config);\n configStore.watch((next) => fallbackProfileManager.reload(next as Config));\n container.bind(TOKENS.ConfigStore, () => configStore);\n container.bind(TOKENS.FallbackProfileManager, () => fallbackProfileManager);\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 () =>\n new DefaultTokenCounter({\n registry: modelsRegistry,\n providerId: config.provider,\n events: opts.events,\n }),\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 projectRoot: wpaths.projectRoot,\n logger,\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 // Cross-process guard consulted by delete(): refuses to remove a\n // session that a LIVE terminal/TUI/WebUI in this project is using.\n // The store also checks active.json directly; this widens the check\n // to every concurrently-running surface (active.json only tracks the\n // latest active session per project).\n isSessionInUse: async (sessionId) => {\n try {\n const registry = getSessionRegistry(wpaths.globalRoot);\n const live = await registry.listByProject(wpaths.projectSlug);\n const hit = live.find((e) => e.sessionId === sessionId);\n if (hit) {\n return `active in ${hit.projectName} (PID ${hit.pid})`;\n }\n } catch {\n // registry unavailable \u2014 fall back to the active.json check only\n }\n return null;\n },\n }),\n );\n\n // Single memory backend: SAGE is the only store. `Sage.enabled`\n // no longer swaps the backend \u2014 it only gates automatic context injection and\n // session-end hygiene (see wiring/sage.ts). This guarantees \"one memory\n // system, no other\" across TUI, slash commands, agent tools, and WebUI.\n //\n // SQLite is the sole production backend. Legacy JSONL data is imported by\n // SqliteSageStore on first open, but JSONL can no longer be selected\n // as a writable runtime backend.\n if (!isSqliteAvailable()) {\n throw new Error(\n 'SAGE requires Node built-in SQLite (node:sqlite; Node >= 22.5). ' +\n 'The JSONL compatibility fallback has been removed.',\n );\n }\n const memoryStore = createSqliteMemoryPort({\n projectRoot: wpaths.projectRoot,\n directory: config.Sage?.storage?.directory,\n events: opts.events,\n });\n container.bind(TOKENS.MemoryStore, () => memoryStore);\n container.bind(TOKENS.MemoryPort, () => memoryStore);\n\n const skillLoader = new DefaultSkillLoader({\n paths: wpaths,\n bundledDir: opts.bundledSkillsDir,\n readClaudeSkills: config.skills?.readClaudeSkills,\n foreignSources: config.skills?.foreignSources,\n extraDirs: config.skills?.extraDirs,\n });\n container.bind(TOKENS.SkillLoader, () => skillLoader);\n\n const promptLoader = new DefaultPromptLoader({\n paths: wpaths,\n bundledDir: opts.bundledPromptsDir,\n });\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 skillMode: config.skills?.mode,\n skillEagerMaxChars: config.skills?.eagerMaxChars,\n // SAGE's turn middleware owns memory injection \u2014 don't also\n // inject a static prompt section. Callers may override via\n // opts.systemPrompt if they truly want the static section.\n injectMemory: false,\n ...opts.systemPrompt,\n }),\n );\n }\n\n const directoryPolicyPath = path.join(wpaths.projectRoot, '.wrongstack', 'directory-rules.json');\n let directoryPolicy: ConstructorParameters<typeof DirectoryPermissionPolicy>[1]['policy'] = {\n schemaVersion: 1,\n rules: [],\n };\n try {\n const parsed = JSON.parse(fs.readFileSync(directoryPolicyPath, 'utf8')) as unknown;\n const validation = validateDirectoryPolicy(parsed);\n if (!validation.ok) {\n throw new Error(\n validation.diagnostics\n .map((diagnostic) => `${diagnostic.path}: ${diagnostic.message}`)\n .join('; '),\n );\n }\n directoryPolicy = validation.policy;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(\n `Invalid directory permission policy at ${directoryPolicyPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }\n }\n\n container.bind(TOKENS.PermissionPolicy, () => {\n const policyOptions: ConstructorParameters<typeof DefaultPermissionPolicy>[0] = {\n trustFile: wpaths.projectTrust,\n yolo: opts.permission?.yolo ?? false,\n };\n if (opts.permission?.promptDelegate !== undefined) {\n policyOptions.promptDelegate = opts.permission.promptDelegate;\n }\n return new DirectoryPermissionPolicy(new DefaultPermissionPolicy(policyOptions), {\n policy: directoryPolicy,\n });\n });\n\n container.bind(TOKENS.Compactor, () =>\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 \u2014 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", "// makeLightSubagentFactory \u2014 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 \u21CF 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 \u2014 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, \u2026) \u2014 the user authorised the work when they pressed \"Start Run\".\n\nimport { randomUUID } from 'node:crypto';\nimport {\n Agent,\n FallbackProfileManager,\n Context,\n createDefaultPipelines,\n createFallbackModelExtension,\n} from '@wrongstack/core/agent';\nimport {\n type AgentFactory,\n type AgentFactoryResult,\n resolveSubagentModelTarget,\n} from '@wrongstack/core/coordination';\nimport {\n applyModelRuntime,\n installSubagentAutoCompaction,\n mergeModelRuntime,\n ToolExecutor,\n} from '@wrongstack/core/execution';\nimport { type Container, EventBus, TOKENS } from '@wrongstack/core/kernel';\nimport { type ProviderRegistry, ToolRegistry } from '@wrongstack/core/registry';\nimport { AutoApprovePermissionPolicy, WIDE_SUBAGENT_CAPABILITIES } from '@wrongstack/core/security';\nimport type {\n Config,\n ModelsRegistry,\n ReasoningConfig,\n Request,\n SessionWriter,\n SubagentConfig,\n TextBlock,\n Tool,\n} from '@wrongstack/core/types';\n\nexport interface LightSubagentFactoryDeps {\n /** DI container \u2014 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 \u2014 each subagent gets an isolated clone of it. */\n toolRegistry: ToolRegistry;\n /** Optional models catalog used to gate per-subagent reasoning settings. */\n modelsRegistry?: ModelsRegistry | undefined;\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 * Test hook \u2014 overrides the fallback extension's `now()` so cooldown\n * assertions don't depend on real wall-clock time. Production callers\n * should leave this unset.\n */\n now?: (() => number) | 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 \u2014 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 \u2014 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 existingManager = deps.container.safeResolve(TOKENS.FallbackProfileManager);\n const fallbackProfileManager =\n existingManager ?? new FallbackProfileManager(configStore.get() as Config);\n // A container-provided manager is the host's shared singleton\n // (`packages/runtime/src/container.ts` binds both the manager and the\n // configStore watcher once at boot). Only wire a watcher for a fallback\n // manager we created here; otherwise every makeLightSubagentFactory call\n // (e.g. one per SDD run) would leak a duplicate, never-removed watcher on\n // the long-lived shared configStore.\n if (!existingManager) {\n configStore.watch((next) => fallbackProfileManager.reload(next as Config));\n }\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 const modelsRegistry = deps.modelsRegistry ?? deps.container.safeResolve(TOKENS.ModelsRegistry);\n\n const matrixTarget = subCfg.model ? undefined : resolveSubagentModelTarget(config, subCfg.role);\n let effProvider = subCfg.provider ?? matrixTarget?.provider ?? config.provider;\n let effModel = subCfg.model ?? matrixTarget?.model ?? config.model;\n const fallbackProfile = subCfg.fallbackProfile ?? matrixTarget?.fallbackProfile;\n let provider: ReturnType<ProviderRegistry['create']>;\n try {\n provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n } catch (err) {\n if (effProvider === config.provider && effModel === config.model) throw err;\n effProvider = config.provider;\n effModel = config.model;\n provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n }\n let subReasoningConfig = await resolveReasoningConfig(modelsRegistry, effProvider, effModel);\n const runtimeOverride = subCfg.modelRuntime ?? matrixTarget?.modelRuntime;\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 \u2014 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 traceId: deps.session.traceId,\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 const pipelines = createDefaultPipelines();\n pipelines.request.use({\n name: 'ModelRuntimeSettings',\n async handler(req: Request) {\n return applyModelRuntime(req, {\n getSettings: () => mergeModelRuntime(configStore.get().modelRuntime, runtimeOverride),\n getReasoningConfig: () => subReasoningConfig,\n getCapabilities: () => ctx.provider.capabilities,\n });\n },\n });\n\n // Proactive auto-compaction \u2014 subagents shrink on the warn/soft/hard\n // thresholds (and get the last-resort emergency trim) like the leader,\n // instead of growing unbounded until the provider rejects the request.\n installSubagentAutoCompaction(pipelines, ctx, config.context, events);\n\n // Subagents can't answer prompts \u2014 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,\n context: ctx,\n permissionPolicy,\n toolExecutor,\n loopDetection: config.tools?.loopDetection,\n });\n\n // Fallback chain for THIS worker. Explicit task fallbacks stay pinned, while\n // a matrix-selected named profile is re-resolved from ConfigStore for every\n // provider attempt so WebUI edits/reordering affect active workers.\n agent.extensions.register(\n createFallbackModelExtension({\n // Pin provider/model to THIS worker's target so the extension restores\n // to the worker, not the leader. Other fields stay live so WebUI edits\n // to chains/profiles still reach active workers.\n getConfig: () =>\n ({ ...configStore.get(), provider: effProvider, model: effModel }) as Config,\n fallbackProfileManager,\n getFallbackModels: () => subCfg.fallbackModels,\n getFallbackProfile: () => fallbackProfile,\n buildProvider: (id, model) =>\n buildProvider(\n deps.providerRegistry,\n configStore.get(),\n id,\n /* v8 ignore next -- core fallback entries always carry a model; keep the interface fallback defensive */\n model ?? effModel,\n ),\n onModelSwitch: async (id, model) => {\n subReasoningConfig = await resolveReasoningConfig(modelsRegistry, id, model);\n },\n events,\n ...(deps.now ? { now: deps.now } : {}),\n }),\n );\n\n return { agent, events };\n };\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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}\" \u2014 cannot build a subagent provider for the SDD run.`,\n );\n }\n return registry.create({ ...providerConfig, type: providerId, model });\n}\n\nasync function resolveReasoningConfig(\n registry: ModelsRegistry | undefined,\n providerId: string,\n modelId: string,\n): Promise<ReasoningConfig | undefined> {\n if (!registry) return undefined;\n try {\n return (await registry.getModel(providerId, modelId))?.capabilities.reasoningConfig;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Guarded SessionWriter shim that interleaves subagent events into the parent\n * JSONL while NEVER touching checkpoint / in-flight / lifecycle state \u2014 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 traceId(): string | undefined {\n return parent.traceId;\n },\n set traceId(value: string | undefined) {\n parent.traceId = value;\n },\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 randomUUID().slice(0, 8);\n}\n", "import type { Agent, Context } from '@wrongstack/core/agent';\nimport type { ExtensionRegistry } from '@wrongstack/core/extension';\nimport type { EventBus } from '@wrongstack/core/kernel';\nimport type {\n ProviderRegistry,\n SlashCommandRegistry,\n ToolRegistry,\n} from '@wrongstack/core/registry';\nimport type { PluginAPI, SessionWriter } from '@wrongstack/core/types';\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 // SlashCommandRegistry stores plugin-owned commands under `${owner}:${name}`;\n // track the real lookup key so teardown can unregister them.\n for (const c of cmds)\n registeredCommandNames.push(owner === 'core' ? c.name : `${owner}:${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 \u2014\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 (let i = unregisterExtensions.length - 1; i >= 0; i--) {\n unregisterExtensions[i]!();\n }\n for (let i = registeredCommandNames.length - 1; i >= 0; i--) {\n host.slashCommands.unregister(registeredCommandNames[i]!);\n }\n for (let i = registeredToolNames.length - 1; i >= 0; i--) {\n host.tools.unregister(registeredToolNames[i]!);\n }\n for (let i = registeredProviderTypes.length - 1; i >= 0; i--) {\n host.providers.unregister(registeredProviderTypes[i]!);\n }\n throw setupErr;\n }\n }\n\n return {\n pack,\n owner,\n async teardown() {\n for (let i = unregisterExtensions.length - 1; i >= 0; i--) {\n unregisterExtensions[i]!();\n }\n // Unregister commands, tools, and providers so the same pack can be\n // re-loaded cleanly without name/type conflicts.\n for (let i = registeredCommandNames.length - 1; i >= 0; i--) {\n host.slashCommands.unregister(registeredCommandNames[i]!);\n }\n for (let i = registeredToolNames.length - 1; i >= 0; i--) {\n host.tools.unregister(registeredToolNames[i]!);\n }\n for (let i = registeredProviderTypes.length - 1; i >= 0; i--) {\n host.providers.unregister(registeredProviderTypes[i]!);\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 \u2014 a silent teardown failure can leave state\n // half-initialized in ways that make the next run fail mysteriously.\n for (let i = applied.length - 1; i >= 0; i--) {\n const mounted = applied[i]!;\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", "/**\n * Local-LLM health probe \u2014 `GET <baseUrl>/v1/models`.\n *\n * This module lives in `@wrongstack/runtime` (not `@wrongstack/cli` or\n * `@wrongstack/providers`) so the WebUI server can reuse it without\n * pulling in the entire CLI dependency graph. The function is\n * identical to the one in `@wrongstack/cli/src/auth-menu/local.ts` \u2014\n * we keep a single canonical implementation here and have the CLI\n * re-export from this one.\n *\n * The probe:\n * - Hits `GET <baseUrl>/models` (OpenAI-compatible)\n * - Sends an optional `Authorization: Bearer <key>` header\n * - Scrubs every result through the `SecretScrubber` so a Bearer\n * token accidentally captured in an error page never reaches\n * the renderer\n * - Returns a `ProbeResult` (never throws) so the caller can\n * decide how to react to each `status`\n */\nimport type { SecretScrubber } from '@wrongstack/core/types';\n\n/** Default probe timeout. Local servers should respond in < 100ms. */\nconst PROBE_TIMEOUT_MS = 3_000;\n\nexport interface ProbeOptions {\n baseUrl: string;\n apiKey: string | undefined;\n noAuth: boolean;\n /**\n * Display label for the probed server \u2014 the CLI uses this in the\n * rendered probe result (\"Ollama health probe ok\"). Optional; the\n * probe itself doesn't care.\n */\n presetLabel?: string | undefined;\n /** Used to scrub error-page bodies and network error messages. */\n scrubber: SecretScrubber;\n fetchImpl?: typeof fetch | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport interface ProbeResult {\n ok: boolean;\n status:\n | 'ok'\n | 'unreachable'\n | 'timeout'\n | 'http_error'\n | 'invalid_response'\n | 'skipped'\n | 'no_provider'\n | 'no_base_url';\n httpStatus?: number | undefined;\n elapsedMs?: number | undefined;\n modelCount?: number | undefined;\n /**\n * The actual model ids returned by the server, deduplicated, in\n * server-reported order. Empty (not undefined) when the server\n * returned a valid empty list.\n */\n modelIds?: string[] | undefined;\n /** Redactable error detail (e.g. ECONNREFUSED). */\n detail?: string | undefined;\n}\n\n/**\n * Probe a local LLM server by hitting the OpenAI-compatible\n * `GET /v1/models` endpoint.\n *\n * The probe is fully isolated from the config layer \u2014 it only\n * returns a `ProbeResult` and never throws.\n */\nexport async function probeLocalLlm(opts: ProbeOptions): Promise<ProbeResult> {\n const { baseUrl, apiKey, noAuth, scrubber, fetchImpl, timeoutMs } = opts;\n const fetchFn = fetchImpl ?? fetch;\n const timeout = timeoutMs ?? PROBE_TIMEOUT_MS;\n\n // Normalize the URL: append `/models` if the user gave us the chat\n // completions base. Strip trailing slashes so we can just concatenate.\n const base = baseUrl.replace(/\\/+$/, '');\n const url = /\\/models$/.test(base) ? base : `${base}/models`;\n\n const headers: Record<string, string> = { accept: 'application/json' };\n if (!noAuth && apiKey) {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n const started = Date.now();\n let res: Response;\n try {\n res = await fetchFn(url, {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(timeout),\n });\n } catch (err) {\n const elapsed = Date.now() - started;\n const name = (err as { name?: string } | null)?.name;\n if (name === 'TimeoutError' || name === 'AbortError') {\n return { ok: false, status: 'timeout', elapsedMs: elapsed, detail: `> ${timeout}ms` };\n }\n const detail = scrubber.scrub((err as Error)?.message ?? String(err));\n return { ok: false, status: 'unreachable', elapsedMs: elapsed, detail };\n }\n\n const elapsed = Date.now() - started;\n\n if (!res.ok) {\n let bodySlice = '';\n try {\n const txt = await res.text();\n bodySlice = txt.slice(0, 200);\n } catch {\n // ignore\n }\n return {\n ok: false,\n status: 'http_error',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: scrubber.scrub(bodySlice) || undefined,\n };\n }\n\n const modelIds: string[] = [];\n try {\n const parsed = (await res.json()) as unknown;\n if (!parsed || typeof parsed !== 'object') {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: 'response is not a JSON object',\n };\n }\n const obj = parsed as Record<string, unknown>;\n const dataList = obj['data'];\n const modelsList = obj['models'];\n const rawList: unknown[] | null = Array.isArray(dataList)\n ? (dataList as unknown[])\n : Array.isArray(modelsList)\n ? (modelsList as unknown[])\n : null;\n if (rawList === null) {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: 'no `data` or `models` array in response',\n };\n }\n const seen = new Set<string>();\n for (const entry of rawList) {\n if (!entry || typeof entry !== 'object') continue;\n const e = entry as Record<string, unknown>;\n const raw =\n typeof e['id'] === 'string' ? e['id'] : typeof e['name'] === 'string' ? e['name'] : null;\n if (raw === null) continue;\n const id = scrubber.scrub(raw).trim();\n if (id.length === 0) continue;\n if (seen.has(id)) continue;\n seen.add(id);\n modelIds.push(id);\n }\n } catch (err) {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: scrubber.scrub((err as Error)?.message ?? 'parse failed'),\n };\n }\n\n return {\n ok: true,\n status: 'ok',\n httpStatus: res.status,\n elapsedMs: elapsed,\n modelCount: modelIds.length,\n modelIds,\n };\n}\n", "import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { ToolRegistry } from '@wrongstack/core/registry';\nimport type { ContentBlock, ImageBlock, Tool } from '@wrongstack/core/types';\nimport { assertNotPrivateHost } from '@wrongstack/core/utils';\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: {\n providerId?: string | undefined;\n model?: string | undefined;\n imageCount: number;\n }) {\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 // Native vision providers typically fetch image URLs server-side, so\n // enforce the same SSRF guard used for adapter routes.\n for (const img of images) {\n if (img.source.type === 'url' && img.source.url) {\n try {\n await assertNotPrivateHost(new URL(img.source.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: img.source.url, reason });\n }\n }\n }\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(\n adapters: VisionAdapters | undefined,\n): 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(\n `Tool \"${currentTool.name}\" does not expose a supported image input schema`,\n );\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\nexport const VISION_IMAGE_KEYS = [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n] as const;\n\nexport const VISION_PATH_KEYS = [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n] as const;\n\nexport const VISION_MEDIA_TYPE_KEYS = ['mediaType', 'mimeType', 'media_type'] as const;\nexport const VISION_PROMPT_KEYS = ['prompt', 'query', 'instruction'] as const;\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 VISION_IMAGE_KEYS.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, [...VISION_PATH_KEYS]);\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 for (const key of VISION_MEDIA_TYPE_KEYS) {\n if (key in props) payload[key] = mediaType;\n }\n for (const key of VISION_PROMPT_KEYS) {\n if (key in props) payload[key] = prompt;\n }\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"],
5
- "mappings": "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",
4
+ "sourcesContent": ["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/utils';\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 * Write plain text to the system clipboard. Returns `true` on success, `false`\n * when the platform is unsupported, no clipboard tool is available, or the\n * child process failed. Mirrors `readClipboardText`'s platform matrix\n * (PowerShell on Windows, `pbcopy` on macOS, `wl-copy`/`xclip` on Linux) and is\n * used by the TUI to copy a chat card's content when its copy icon is clicked \u2014\n * terminals in raw mode never perform a native copy, so we do it ourselves.\n */\nexport async function writeClipboardText(text: string): Promise<boolean> {\n const platform = process.platform;\n if (platform === 'win32') {\n // Read the payload from stdin so arbitrary text (quotes, newlines,\n // non-ASCII) never has to be escaped into the command line. Force UTF-8 so\n // multibyte characters survive the pipe.\n const ps =\n '[Console]::InputEncoding = [System.Text.Encoding]::UTF8; ' +\n '$in = [Console]::In.ReadToEnd(); ' +\n 'Set-Clipboard -Value $in';\n return runCmdWithInput('powershell', ['-NoProfile', '-Command', ps], text);\n }\n if (platform === 'darwin') {\n return runCmdWithInput('pbcopy', [], text);\n }\n if (platform === 'linux') {\n const tries: Array<[string, string[]]> = [\n ['wl-copy', []],\n ['xclip', ['-selection', 'clipboard']],\n ];\n for (const [cmd, args] of tries) {\n if (await runCmdWithInput(cmd, args, text)) return true;\n }\n return false;\n }\n return false;\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 \u2014 strip it.\n const ps = '[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 \u00ABclass PNGf\u00BB) 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, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n let out = '';\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: string | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(null), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c) => {\n out += String(c);\n });\n child.on('error', () => finish(null));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(null);\n finish(code === 0 ? out : null);\n });\n });\n}\n\n/**\n * Spawn `cmd` and feed `input` to its stdin, resolving `true` when the child\n * exits 0 within the timeout and `false` on spawn error, non-zero exit, or\n * timeout. Used by `writeClipboardText`; stdin is the payload channel so text\n * never touches the command line.\n */\nfunction runCmdWithInput(cmd: string, args: string[], input: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['pipe', 'ignore', 'ignore'],\n windowsHide: true,\n });\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.on('error', () => finish(false));\n child.on('exit', (code) => {\n if (killedByTimeout) return finish(false);\n finish(code === 0);\n });\n // Writing to stdin can EPIPE if the child already exited; swallow it and\n // let the exit handler decide the outcome.\n child.stdin.on('error', () => {});\n child.stdin.end(input, 'utf8');\n });\n}\n\nfunction runCmdToFile(cmd: string, args: string[], outPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, {\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n const chunks: Buffer[] = [];\n let settled = false;\n let killedByTimeout = false;\n const finish = (value: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(killCap);\n resolve(value);\n };\n const timer = setTimeout(() => {\n killedByTimeout = true;\n child.kill('SIGTERM');\n }, CLIPBOARD_CMD_TIMEOUT_MS);\n // Safety cap: if the child ignores SIGTERM, do not hang forever.\n const killCap = setTimeout(() => finish(false), CLIPBOARD_CMD_TIMEOUT_MS + 2_000);\n child.stdout.on('data', (c: Buffer) => chunks.push(c));\n child.on('error', () => finish(false));\n child.on('exit', async (code) => {\n if (killedByTimeout) return finish(false);\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", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport {\n DefaultSystemPromptBuilder,\n type DefaultSystemPromptBuilderOptions,\n FallbackProfileManager,\n} from '@wrongstack/core/agent';\nimport {\n createStrategyCompactor,\n DefaultErrorHandler,\n DefaultPromptLoader,\n DefaultRetryPolicy,\n DefaultSkillLoader,\n} from '@wrongstack/core/execution';\nimport { ProviderModelStatusTracker } from '@wrongstack/core/coordination';\nimport { Container, type EventBus, TOKENS } from '@wrongstack/core/kernel';\nimport { DefaultModeStore } from '@wrongstack/core/models';\nimport {\n DirectoryPermissionPolicy,\n DefaultPermissionPolicy,\n DefaultSecretScrubber,\n validateDirectoryPolicy,\n} from '@wrongstack/core/security';\nimport { DefaultConfigStore, DefaultSessionStore } from '@wrongstack/core/storage';\nimport type { Config, Logger, ModelsRegistry, Tool } from '@wrongstack/core/types';\nimport type { WstackPaths } from '@wrongstack/core/utils';\n// PR-C1 (66c4eb68): execution/ and infrastructure/ symbols come from the\n// published subpaths now that types/index.ts no longer re-exports them.\nimport { buildRecoveryStrategies } from '@wrongstack/core/execution';\nimport { DefaultTokenCounter } from '@wrongstack/core/infrastructure';\nimport { getSessionRegistry } from '@wrongstack/core/storage';\nimport { createProjectSageMemoryPort, isSqliteAvailable } from '@wrongstack/sage';\n\nexport interface CreateContainerOptions {\n config: Config;\n wpaths: WstackPaths;\n logger: Logger;\n modelsRegistry: ModelsRegistry;\n /**\n * Optional event bus \u2014 passed to SageStore 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 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 const fallbackProfileManager = new FallbackProfileManager(config);\n configStore.watch((next) => fallbackProfileManager.reload(next as Config));\n container.bind(TOKENS.ConfigStore, () => configStore);\n container.bind(TOKENS.FallbackProfileManager, () => fallbackProfileManager);\n // Shared (provider, model) health tracker. The leader's runtime wiring\n // (brain-and-orchestration.ts) constructs its own tracker and threads it\n // into MultiAgentHostOptions; the runtime container ships a default so\n // makeLightSubagentFactory's fallback extension has something to write\n // into when webui-server boots standalone. The CLI factory passes a\n // separate leader-owned instance; the tracker singleton pattern is\n // contractually the same. Without this binding, light-factory subagents\n // (e.g. SDD parallel runs) silently no-op the 429 \u2192 waiting-room trigger\n // on the first rate-limit burst \u2014 see SAGE memory\n // 01KYSCC8A49TS9ENCVCS2J3WJ8 for the parallel gap to the CLI factory.\n container.bind(TOKENS.ProviderModelStatusTracker, () => new ProviderModelStatusTracker());\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 () =>\n new DefaultTokenCounter({\n registry: modelsRegistry,\n providerId: config.provider,\n events: opts.events,\n }),\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 projectRoot: wpaths.projectRoot,\n logger,\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 // Cross-process guard consulted by delete(): refuses to remove a\n // session that a LIVE terminal/TUI/WebUI in this project is using.\n isSessionInUse: async (sessionId) => {\n try {\n const registry = getSessionRegistry(wpaths.globalRoot);\n const live = await registry.listByProject(wpaths.projectSlug);\n const hit = live.find((e) => e.sessionId === sessionId);\n if (hit) {\n return `active in ${hit.projectName} (PID ${hit.pid})`;\n }\n } catch {\n // Registry failures must not make the session store unavailable.\n }\n return null;\n },\n }),\n );\n\n // Single memory backend: SAGE is the only store. `Sage.enabled`\n // no longer swaps the backend \u2014 it only gates automatic context injection and\n // session-end hygiene (see wiring/sage.ts). This guarantees \"one memory\n // system, no other\" across TUI, slash commands, agent tools, and WebUI.\n //\n // The project SAGE server is the sole production owner of SQLite. Legacy\n // JSONL data is imported by that owner on first open; hosts only hold IPC\n // ports and cannot silently open a competing writable backend.\n if (!isSqliteAvailable()) {\n throw new Error(\n 'SAGE requires Node built-in SQLite (node:sqlite; Node >= 22.5). ' +\n 'The JSONL compatibility fallback has been removed.',\n );\n }\n const memoryStore = createProjectSageMemoryPort({\n projectRoot: wpaths.projectRoot,\n directory: config.Sage?.storage?.directory,\n events: opts.events,\n workspaceRoot: wpaths.projectRoot,\n });\n container.bind(TOKENS.MemoryStore, () => memoryStore);\n container.bind(TOKENS.MemoryPort, () => memoryStore);\n\n const skillLoader = new DefaultSkillLoader({\n paths: wpaths,\n bundledDir: opts.bundledSkillsDir,\n readClaudeSkills: config.skills?.readClaudeSkills,\n foreignSources: config.skills?.foreignSources,\n extraDirs: config.skills?.extraDirs,\n });\n container.bind(TOKENS.SkillLoader, () => skillLoader);\n\n const promptLoader = new DefaultPromptLoader({\n paths: wpaths,\n bundledDir: opts.bundledPromptsDir,\n });\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 skillMode: config.skills?.mode,\n skillEagerMaxChars: config.skills?.eagerMaxChars,\n // SAGE's turn middleware owns memory injection \u2014 don't also\n // inject a static prompt section. Callers may override via\n // opts.systemPrompt if they truly want the static section.\n injectMemory: false,\n ...opts.systemPrompt,\n }),\n );\n }\n\n const directoryPolicyPath = path.join(wpaths.projectRoot, '.wrongstack', 'directory-rules.json');\n let directoryPolicy: ConstructorParameters<typeof DirectoryPermissionPolicy>[1]['policy'] = {\n schemaVersion: 1,\n rules: [],\n };\n try {\n const parsed = JSON.parse(fs.readFileSync(directoryPolicyPath, 'utf8')) as unknown;\n const validation = validateDirectoryPolicy(parsed);\n if (!validation.ok) {\n throw new Error(\n validation.diagnostics\n .map((diagnostic) => `${diagnostic.path}: ${diagnostic.message}`)\n .join('; '),\n );\n }\n directoryPolicy = validation.policy;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(\n `Invalid directory permission policy at ${directoryPolicyPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }\n }\n\n container.bind(TOKENS.PermissionPolicy, () => {\n const policyOptions: ConstructorParameters<typeof DefaultPermissionPolicy>[0] = {\n trustFile: wpaths.projectTrust,\n yolo: opts.permission?.yolo ?? false,\n };\n if (opts.permission?.promptDelegate !== undefined) {\n policyOptions.promptDelegate = opts.permission.promptDelegate;\n }\n return new DirectoryPermissionPolicy(new DefaultPermissionPolicy(policyOptions), {\n policy: directoryPolicy,\n });\n });\n\n container.bind(TOKENS.Compactor, () =>\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 \u2014 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", "// makeLightSubagentFactory \u2014 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 \u21CF 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 \u2014 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, \u2026) \u2014 the user authorised the work when they pressed \"Start Run\".\n\nimport { randomUUID } from 'node:crypto';\nimport {\n Agent,\n FallbackProfileManager,\n Context,\n createDefaultPipelines,\n createFallbackModelExtension,\n} from '@wrongstack/core/agent';\nimport {\n type AgentFactory,\n type AgentFactoryResult,\n type ProviderModelStatusTracker,\n resolveSubagentModelTarget,\n} from '@wrongstack/core/coordination';\nimport {\n applyModelRuntime,\n installSubagentAutoCompaction,\n mergeModelRuntime,\n ToolExecutor,\n} from '@wrongstack/core/execution';\nimport { type Container, EventBus, TOKENS } from '@wrongstack/core/kernel';\nimport { type ProviderRegistry, ToolRegistry } from '@wrongstack/core/registry';\nimport { AutoApprovePermissionPolicy, WIDE_SUBAGENT_CAPABILITIES } from '@wrongstack/core/security';\nimport type {\n Config,\n ModelsRegistry,\n ReasoningConfig,\n Request,\n SessionWriter,\n SubagentConfig,\n TextBlock,\n Tool,\n} from '@wrongstack/core/types';\n\nexport interface LightSubagentFactoryDeps {\n /** DI container \u2014 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 \u2014 each subagent gets an isolated clone of it. */\n toolRegistry: ToolRegistry;\n /** Optional models catalog used to gate per-subagent reasoning settings. */\n modelsRegistry?: ModelsRegistry | undefined;\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 * Test hook \u2014 overrides the fallback extension's `now()` so cooldown\n * assertions don't depend on real wall-clock time. Production callers\n * should leave this unset.\n */\n now?: (() => number) | undefined;\n /**\n * Shared (provider, model) health tracker. When provided, the subagent's\n * fallback extension records 429 / 5xx / timeout / stream-hang failures\n * into it and skips blocked entries on subsequent calls \u2014 closing the\n * waiting-room trigger for webui-server SDD parallel runs. When unset\n * the extension still works, but a 429 leaves no quarantine signal and\n * round-robin keeps reassigning the doomed model. Mirrors the\n * `host.opts.statusTracker` thread in the CLI factory.\n */\n statusTracker?: ProviderModelStatusTracker | 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 \u2014 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 \u2014 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 existingManager = deps.container.safeResolve(TOKENS.FallbackProfileManager);\n const fallbackProfileManager =\n existingManager ?? new FallbackProfileManager(configStore.get() as Config);\n // A container-provided manager is the host's shared singleton\n // (`packages/runtime/src/container.ts` binds both the manager and the\n // configStore watcher once at boot). Only wire a watcher for a fallback\n // manager we created here; otherwise every makeLightSubagentFactory call\n // (e.g. one per SDD run) would leak a duplicate, never-removed watcher on\n // the long-lived shared configStore.\n if (!existingManager) {\n configStore.watch((next) => fallbackProfileManager.reload(next as Config));\n }\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 const modelsRegistry = deps.modelsRegistry ?? deps.container.safeResolve(TOKENS.ModelsRegistry);\n\n const matrixTarget = subCfg.model ? undefined : resolveSubagentModelTarget(config, subCfg.role);\n let effProvider = subCfg.provider ?? matrixTarget?.provider ?? config.provider;\n let effModel = subCfg.model ?? matrixTarget?.model ?? config.model;\n const fallbackProfile = subCfg.fallbackProfile ?? matrixTarget?.fallbackProfile;\n let provider: ReturnType<ProviderRegistry['create']>;\n try {\n provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n } catch (err) {\n if (effProvider === config.provider && effModel === config.model) throw err;\n effProvider = config.provider;\n effModel = config.model;\n provider = buildProvider(deps.providerRegistry, config, effProvider, effModel);\n }\n let subReasoningConfig = await resolveReasoningConfig(modelsRegistry, effProvider, effModel);\n const runtimeOverride = subCfg.modelRuntime ?? matrixTarget?.modelRuntime;\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 \u2014 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 traceId: deps.session.traceId,\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 const pipelines = createDefaultPipelines();\n pipelines.request.use({\n name: 'ModelRuntimeSettings',\n async handler(req: Request) {\n return applyModelRuntime(req, {\n getSettings: () => mergeModelRuntime(configStore.get().modelRuntime, runtimeOverride),\n getReasoningConfig: () => subReasoningConfig,\n getCapabilities: () => ctx.provider.capabilities,\n });\n },\n });\n\n // Proactive auto-compaction \u2014 subagents shrink on the warn/soft/hard\n // thresholds (and get the last-resort emergency trim) like the leader,\n // instead of growing unbounded until the provider rejects the request.\n installSubagentAutoCompaction(pipelines, ctx, config.context, events);\n\n // Subagents can't answer prompts \u2014 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,\n context: ctx,\n permissionPolicy,\n toolExecutor,\n loopDetection: config.tools?.loopDetection,\n });\n\n // Fallback chain for THIS worker. Explicit task fallbacks stay pinned, while\n // a matrix-selected named profile is re-resolved from ConfigStore for every\n // provider attempt so WebUI edits/reordering affect active workers.\n agent.extensions.register(\n createFallbackModelExtension({\n // Pin provider/model to THIS worker's target so the extension restores\n // to the worker, not the leader. Other fields stay live so WebUI edits\n // to chains/profiles still reach active workers.\n getConfig: () =>\n ({ ...configStore.get(), provider: effProvider, model: effModel }) as Config,\n fallbackProfileManager,\n getFallbackModels: () => subCfg.fallbackModels,\n getFallbackProfile: () => fallbackProfile,\n buildProvider: (id, model) =>\n buildProvider(\n deps.providerRegistry,\n configStore.get(),\n id,\n /* v8 ignore next -- core fallback entries always carry a model; keep the interface fallback defensive */\n model ?? effModel,\n ),\n onModelSwitch: async (id, model) => {\n subReasoningConfig = await resolveReasoningConfig(modelsRegistry, id, model);\n },\n events,\n ...(deps.now ? { now: deps.now } : {}),\n // Thread the shared ProviderModelStatusTracker so a 429 from this\n // subagent's first call transitions the (provider, model) pair to\n // `state: 'blocked'` instead of silently no-op'ing. Mirrors the CLI\n // factory wiring at host-subagent-factory.ts:336.\n ...(deps.statusTracker ? { statusTracker: deps.statusTracker } : {}),\n }),\n );\n\n return { agent, events };\n };\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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}\" \u2014 cannot build a subagent provider for the SDD run.`,\n );\n }\n return registry.create({ ...providerConfig, type: providerId, model });\n}\n\nasync function resolveReasoningConfig(\n registry: ModelsRegistry | undefined,\n providerId: string,\n modelId: string,\n): Promise<ReasoningConfig | undefined> {\n if (!registry) return undefined;\n try {\n return (await registry.getModel(providerId, modelId))?.capabilities.reasoningConfig;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Guarded SessionWriter shim that interleaves subagent events into the parent\n * JSONL while NEVER touching checkpoint / in-flight / lifecycle state \u2014 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 traceId(): string | undefined {\n return parent.traceId;\n },\n set traceId(value: string | undefined) {\n parent.traceId = value;\n },\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 randomUUID().slice(0, 8);\n}\n", "import type { Agent, Context } from '@wrongstack/core/agent';\nimport type { ExtensionRegistry } from '@wrongstack/core/extension';\nimport type { EventBus } from '@wrongstack/core/kernel';\nimport type {\n ProviderRegistry,\n SlashCommandRegistry,\n ToolRegistry,\n} from '@wrongstack/core/registry';\nimport type { PluginAPI, SessionWriter } from '@wrongstack/core/types';\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 // SlashCommandRegistry stores plugin-owned commands under `${owner}:${name}`;\n // track the real lookup key so teardown can unregister them.\n for (const c of cmds)\n registeredCommandNames.push(owner === 'core' ? c.name : `${owner}:${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 \u2014\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 (let i = unregisterExtensions.length - 1; i >= 0; i--) {\n unregisterExtensions[i]!();\n }\n for (let i = registeredCommandNames.length - 1; i >= 0; i--) {\n host.slashCommands.unregister(registeredCommandNames[i]!);\n }\n for (let i = registeredToolNames.length - 1; i >= 0; i--) {\n host.tools.unregister(registeredToolNames[i]!);\n }\n for (let i = registeredProviderTypes.length - 1; i >= 0; i--) {\n host.providers.unregister(registeredProviderTypes[i]!);\n }\n throw setupErr;\n }\n }\n\n return {\n pack,\n owner,\n async teardown() {\n for (let i = unregisterExtensions.length - 1; i >= 0; i--) {\n unregisterExtensions[i]!();\n }\n // Unregister commands, tools, and providers so the same pack can be\n // re-loaded cleanly without name/type conflicts.\n for (let i = registeredCommandNames.length - 1; i >= 0; i--) {\n host.slashCommands.unregister(registeredCommandNames[i]!);\n }\n for (let i = registeredToolNames.length - 1; i >= 0; i--) {\n host.tools.unregister(registeredToolNames[i]!);\n }\n for (let i = registeredProviderTypes.length - 1; i >= 0; i--) {\n host.providers.unregister(registeredProviderTypes[i]!);\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 \u2014 a silent teardown failure can leave state\n // half-initialized in ways that make the next run fail mysteriously.\n for (let i = applied.length - 1; i >= 0; i--) {\n const mounted = applied[i]!;\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", "/**\n * Local-LLM health probe \u2014 `GET <baseUrl>/v1/models`.\n *\n * This module lives in `@wrongstack/runtime` (not `@wrongstack/cli` or\n * `@wrongstack/providers`) so the WebUI server can reuse it without\n * pulling in the entire CLI dependency graph. The function is\n * identical to the one in `@wrongstack/cli/src/auth-menu/local.ts` \u2014\n * we keep a single canonical implementation here and have the CLI\n * re-export from this one.\n *\n * The probe:\n * - Hits `GET <baseUrl>/models` (OpenAI-compatible)\n * - Sends an optional `Authorization: Bearer <key>` header\n * - Scrubs every result through the `SecretScrubber` so a Bearer\n * token accidentally captured in an error page never reaches\n * the renderer\n * - Returns a `ProbeResult` (never throws) so the caller can\n * decide how to react to each `status`\n */\nimport type { SecretScrubber } from '@wrongstack/core/types';\n\n/** Default probe timeout. Local servers should respond in < 100ms. */\nconst PROBE_TIMEOUT_MS = 3_000;\n\nexport interface ProbeOptions {\n baseUrl: string;\n apiKey: string | undefined;\n noAuth: boolean;\n /**\n * Display label for the probed server \u2014 the CLI uses this in the\n * rendered probe result (\"Ollama health probe ok\"). Optional; the\n * probe itself doesn't care.\n */\n presetLabel?: string | undefined;\n /** Used to scrub error-page bodies and network error messages. */\n scrubber: SecretScrubber;\n fetchImpl?: typeof fetch | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport interface ProbeResult {\n ok: boolean;\n status:\n | 'ok'\n | 'unreachable'\n | 'timeout'\n | 'http_error'\n | 'invalid_response'\n | 'skipped'\n | 'no_provider'\n | 'no_base_url';\n httpStatus?: number | undefined;\n elapsedMs?: number | undefined;\n modelCount?: number | undefined;\n /**\n * The actual model ids returned by the server, deduplicated, in\n * server-reported order. Empty (not undefined) when the server\n * returned a valid empty list.\n */\n modelIds?: string[] | undefined;\n /** Redactable error detail (e.g. ECONNREFUSED). */\n detail?: string | undefined;\n}\n\n/**\n * Probe a local LLM server by hitting the OpenAI-compatible\n * `GET /v1/models` endpoint.\n *\n * The probe is fully isolated from the config layer \u2014 it only\n * returns a `ProbeResult` and never throws.\n */\nexport async function probeLocalLlm(opts: ProbeOptions): Promise<ProbeResult> {\n const { baseUrl, apiKey, noAuth, scrubber, fetchImpl, timeoutMs } = opts;\n const fetchFn = fetchImpl ?? fetch;\n const timeout = timeoutMs ?? PROBE_TIMEOUT_MS;\n\n // Normalize the URL: append `/models` if the user gave us the chat\n // completions base. Strip trailing slashes so we can just concatenate.\n const base = baseUrl.replace(/\\/+$/, '');\n const url = /\\/models$/.test(base) ? base : `${base}/models`;\n\n const headers: Record<string, string> = { accept: 'application/json' };\n if (!noAuth && apiKey) {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n const started = Date.now();\n let res: Response;\n try {\n res = await fetchFn(url, {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(timeout),\n });\n } catch (err) {\n const elapsed = Date.now() - started;\n const name = (err as { name?: string } | null)?.name;\n if (name === 'TimeoutError' || name === 'AbortError') {\n return { ok: false, status: 'timeout', elapsedMs: elapsed, detail: `> ${timeout}ms` };\n }\n const detail = scrubber.scrub((err as Error)?.message ?? String(err));\n return { ok: false, status: 'unreachable', elapsedMs: elapsed, detail };\n }\n\n const elapsed = Date.now() - started;\n\n if (!res.ok) {\n let bodySlice = '';\n try {\n const txt = await res.text();\n bodySlice = txt.slice(0, 200);\n } catch {\n // ignore\n }\n return {\n ok: false,\n status: 'http_error',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: scrubber.scrub(bodySlice) || undefined,\n };\n }\n\n const modelIds: string[] = [];\n try {\n const parsed = (await res.json()) as unknown;\n if (!parsed || typeof parsed !== 'object') {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: 'response is not a JSON object',\n };\n }\n const obj = parsed as Record<string, unknown>;\n const dataList = obj['data'];\n const modelsList = obj['models'];\n const rawList: unknown[] | null = Array.isArray(dataList)\n ? (dataList as unknown[])\n : Array.isArray(modelsList)\n ? (modelsList as unknown[])\n : null;\n if (rawList === null) {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: 'no `data` or `models` array in response',\n };\n }\n const seen = new Set<string>();\n for (const entry of rawList) {\n if (!entry || typeof entry !== 'object') continue;\n const e = entry as Record<string, unknown>;\n const raw =\n typeof e['id'] === 'string' ? e['id'] : typeof e['name'] === 'string' ? e['name'] : null;\n if (raw === null) continue;\n const id = scrubber.scrub(raw).trim();\n if (id.length === 0) continue;\n if (seen.has(id)) continue;\n seen.add(id);\n modelIds.push(id);\n }\n } catch (err) {\n return {\n ok: false,\n status: 'invalid_response',\n httpStatus: res.status,\n elapsedMs: elapsed,\n detail: scrubber.scrub((err as Error)?.message ?? 'parse failed'),\n };\n }\n\n return {\n ok: true,\n status: 'ok',\n httpStatus: res.status,\n elapsedMs: elapsed,\n modelCount: modelIds.length,\n modelIds,\n };\n}\n", "import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { ToolRegistry } from '@wrongstack/core/registry';\nimport type { ContentBlock, ImageBlock, Tool } from '@wrongstack/core/types';\nimport { assertNotPrivateHost } from '@wrongstack/core/utils';\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: {\n providerId?: string | undefined;\n model?: string | undefined;\n imageCount: number;\n }) {\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 // Native vision providers typically fetch image URLs server-side, so\n // enforce the same SSRF guard used for adapter routes.\n for (const img of images) {\n if (img.source.type === 'url' && img.source.url) {\n try {\n await assertNotPrivateHost(new URL(img.source.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: img.source.url, reason });\n }\n }\n }\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(\n adapters: VisionAdapters | undefined,\n): 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(\n `Tool \"${currentTool.name}\" does not expose a supported image input schema`,\n );\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\nexport const VISION_IMAGE_KEYS = [\n 'image',\n 'base64',\n 'data',\n 'url',\n 'image_url',\n 'imageUrl',\n 'path',\n 'image_path',\n 'imagePath',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n 'mediaType',\n 'mimeType',\n] as const;\n\nexport const VISION_PATH_KEYS = [\n 'path',\n 'image_path',\n 'imagePath',\n 'image_url',\n 'imageUrl',\n 'file_path',\n 'filePath',\n 'filename',\n 'file',\n] as const;\n\nexport const VISION_MEDIA_TYPE_KEYS = ['mediaType', 'mimeType', 'media_type'] as const;\nexport const VISION_PROMPT_KEYS = ['prompt', 'query', 'instruction'] as const;\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 VISION_IMAGE_KEYS.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, [...VISION_PATH_KEYS]);\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 for (const key of VISION_MEDIA_TYPE_KEYS) {\n if (key in props) payload[key] = mediaType;\n }\n for (const key of VISION_PROMPT_KEYS) {\n if (key in props) payload[key] = prompt;\n }\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"],
5
+ "mappings": "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",
6
6
  "names": ["fs", "path", "randomUUID", "FallbackProfileManager", "TOKENS", "elapsed", "fs", "os", "path"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/runtime",
3
- "version": "0.295.1",
3
+ "version": "0.296.3",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack default runtime implementations and host-level composition helpers built on @wrongstack/core.",
6
6
  "repository": {
@@ -51,9 +51,9 @@
51
51
  "README.md"
52
52
  ],
53
53
  "dependencies": {
54
- "@wrongstack/core": "0.295.1",
55
- "@wrongstack/tools": "0.295.1",
56
- "@wrongstack/sage": "0.295.1"
54
+ "@wrongstack/core": "0.296.3",
55
+ "@wrongstack/sage": "0.296.3",
56
+ "@wrongstack/tools": "0.296.3"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "^26.1.1",