openpencil/scripts/patch-srvx-bun.ts
Kayshen-X a7d73ebb62 feat(ai): pencil-style agentic design tool-loop, multi-chat tabs, #27 panel restyle
Built-in design generation now runs as an agentic MCP tool-loop (reusing the
agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the
Settings experimental toggle; the orchestrator stays the default.

- design-agent system prompt + in-process design toolset (parity-locked with
  the MCP surface) + flag-gated Intent::Design routing
- spawn_agents execution as sequential sub-loops + live creation-mode badges
  (per-agent glow + 'N/M designing...' header)
- new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state,
  export_nodes, spawn_agents; style-guide local audit
- #27 AI panel restyle: rounded tool cards + green check-rings, gray user
  bubbles, model-pill bottom toolbar, header, empty-state pills, the
  PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown
- multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI
  (switch / close / + / Cmd+T) with each run bound to its tab

Large checkpoint commit spanning the working tree (Rust shell crates).
2026-07-02 21:21:06 +08:00

76 lines
2.4 KiB
TypeScript

/**
* Patch srvx NodeResponse for Bun compatibility.
*
* Problem: srvx's Node adapter wraps all Response objects in NodeResponse.
* Although NodeResponse inherits from Response via prototype chain,
* Bun's HTTP runtime uses an internal brand check that rejects it.
*
* Fix: Make NodeResponse constructor return a native Response when running in Bun.
* This is safe because Bun doesn't need srvx's Node.js stream bridging.
*
* Run: bun scripts/patch-srvx-bun.ts (called automatically via postinstall)
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { resolve } from 'node:path';
// Find srvx node adapter in various possible locations
const candidates = [
resolve(import.meta.dir, '../node_modules/srvx/dist/adapters/node.mjs'),
...(() => {
try {
// Bun hoists to .bun/ directory
const bunDir = resolve(import.meta.dir, '../node_modules/.bun');
const dirs = require('fs')
.readdirSync(bunDir)
.filter((d: string) => d.startsWith('srvx@'));
return dirs.map((d: string) =>
resolve(bunDir, d, 'node_modules/srvx/dist/adapters/node.mjs'),
);
} catch {
return [];
}
})(),
];
let patched = false;
for (const filePath of candidates) {
if (!existsSync(filePath)) continue;
let code = readFileSync(filePath, 'utf-8');
if (code.includes('__srvx_bun_patched__')) {
console.log(`[patch-srvx-bun] Already patched: ${filePath}`);
patched = true;
continue;
}
// Replace the NodeResponse IIFE to return native Response in Bun
const marker = 'const NodeResponse = /* @__PURE__ */ (() => {';
const endMarker = 'return NodeResponse;\n})();';
if (!code.includes(marker)) {
console.warn(`[patch-srvx-bun] Could not find NodeResponse marker in ${filePath}`);
continue;
}
// Insert a Bun bypass right after the class definition.
// In Bun, replace NodeResponse with native Response constructor
// so Bun's internal brand check passes.
code = code.replace(
endMarker,
`// __srvx_bun_patched__ — Bun bypass: return native Response instead of NodeResponse
if (typeof globalThis.Bun !== 'undefined') {
return NativeResponse;
}
return NodeResponse;
})();`,
);
writeFileSync(filePath, code);
console.log(`[patch-srvx-bun] Patched: ${filePath}`);
patched = true;
}
if (!patched) {
console.warn('[patch-srvx-bun] No srvx node adapter found to patch');
}