openpencil/scripts/patch-srvx-bun.ts
Kayshen Xu 3caaa495bb
V0.5.2 (#82)
* feat(ai): scaffold pen-ai-skills package

* feat(ai): add pen-ai-skills core types

* feat(ai): add Vite plugin for skill file compilation

* feat(ai): add budget module with token estimation and category-priority trimming

* feat(ai): add skill loader with phase filtering and test injection

* feat(ai): add skill resolver with phase filter, intent match, and dynamic injection

* feat(ai): migrate all prompt content to skill files

Extract prompt content from 7 TypeScript source files into 27 Markdown
skill files with proper frontmatter. Each file contains phase, trigger,
priority, budget, and category metadata for the skill resolution engine.

Planning: decomposition, design-type
Generation: jsonl-format, jsonl-format-simplified, schema, layout,
  text-rules, overflow, style-defaults, variables, design-system,
  design-code, design-md
Validation: vision-feedback
Maintenance: local-edit, incremental-add, style-consistency
Domains: landing-page, dashboard, mobile-app, form-ui, cjk-typography
Knowledge: role-definitions, design-principles, icon-catalog,
  copywriting, examples

* feat(ai): add document context memory module

* feat(ai): add generation history memory module

* feat(ai): wire memory loading into skill resolver

Add memory field to ResolveOptions and load documentContext/generationHistory
into AgentContext with per-phase limits (planning:5, maintenance:3, others:0).
Export memory utility functions from package index.

* refactor(ai): use resolveSkills('planning') in orchestrator

Replace ORCHESTRATOR_PROMPT import with resolveSkills() from pen-ai-skills.
The planning phase system prompt is now resolved dynamically from skill
files instead of a static constant.

* refactor(ai): use resolveSkills('generation') in sub-agent

Replace SUB_AGENT_PROMPT + designPrinciples concatenation with
resolveSkills() from pen-ai-skills. The generation phase system prompt
is now resolved dynamically with flag-based skill filtering for
variables and design.md context.

* refactor(ai): use resolveSkills('validation') in design validation

Replace the 70-line inline VALIDATION_SYSTEM_PROMPT constant with a
lazy resolver function that loads the validation prompt from pen-ai-skills
skill files at call time.

* refactor(mcp): use skill registry for design prompt sections

* refactor(ai): remove old prompt files replaced by pen-ai-skills

Delete prompt files whose content has been migrated to the
pen-ai-skills package:
- ai-prompt-sections.ts (section registry, triggers, builders)
- orchestrator-prompts.ts (orchestrator + sub-agent prompts)
- design-system-prompts.ts (design token generation prompt)
- design-code-prompts.ts (HTML/CSS code-gen prompt)
- design-principles/ directory (5 principle files + index)

Consolidate role-definitions/ 8 sub-files into index.ts
(registerRole calls are runtime behavior, must be preserved).

Move buildDesignMdStylePolicy into ai-prompts.ts. Strip migrated
constants (PEN_NODE_SCHEMA, DESIGN_EXAMPLES, ADAPTIVE_STYLE_POLICY,
CHAT_SYSTEM_PROMPT, DESIGN_GENERATOR_PROMPT, etc.) from ai-prompts.ts.

Add pen-ai-skills alias to mcp:compile esbuild script.

* docs: add pen-ai-skills to architecture documentation

* fix(mcp): use h3 v2 createEventStream API for SSE endpoint

event.node.res was removed in h3 v2. Migrate to createEventStream
which handles SSE headers, streaming, and cleanup automatically.

* chore: update package versions and add pen-ai-skills to Dockerfile

- Bump version for multiple packages to 0.5.2, including pen-ai-skills, pen-codegen, pen-core, pen-figma, pen-renderer, pen-sdk, and pen-types.
- Add pen-ai-skills package to Dockerfile for inclusion in the build process.
- Update TypeScript configuration to ensure proper file inclusion.
- Modify GitHub Actions workflow to trigger on version tags.
- Enhance AI-related functionality by integrating resolveAgentModel for dynamic model resolution in chat and generation APIs.

* refactor: clean up unused imports and improve dynamic content handling

- Removed unused imports from various files, including SkillMeta and ResolvedSkill from types.test.ts, and estimateTokens from resolve-skills.ts.
- Updated the dynamic content injection function to use a more concise parameter in the regex replacement callback.

* chore: enhance build and CI workflows with skill generation

- Added a new script to generate the skill registry during post-installation in package.json.
- Updated the GitHub Actions workflows to include steps for compiling the CLI and generating the skill registry, ensuring all necessary components are built and ready for deployment.

---------

Co-authored-by: Fini <fini.yang@gmail.com>
2026-03-24 21:16:28 +08:00

70 lines
2.3 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'
import { globSync } from 'node:fs'
// 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')
}