The `op export` command was removed in 0.7.x but the README still
advertised it (#116). The pen-mcp README also documented an
`npx @zseven-w/pen-mcp` quick-start that never worked because the
package ships TypeScript source against workspace-only deps with no
`bin` entry (#117).
- Strip `op export` references from all 15 root and 15 cli READMEs
- Sync AGENTS.md, CLAUDE.md, apps/cli/CLAUDE.md to match the codegen-
pipeline reality (no standalone export command anymore)
- Rewrite pen-mcp README's quick-start: explain the package ships as
part of the OpenPencil app and external clients connect over HTTP
Closes#116Closes#117
* fix(ai): stop white section bands on dark-themed pages
- role-resolver: skip fixSectionAlternation when parent fill luminance < 0.5, so we no longer paint #FFFFFF/#F8FAFC over a dark root
- strip-redundant-section-fills: add SAFE_LIGHT_HEXES so stale whites from earlier runs (or weak-model hedges) are cleaned up on the sink side
- regression tests for both layers
* feat(ai): design.md-driven background + sidebar color pipeline
- orchestrator-sidebar-color: extract sidebar surface picker; prefer design.md palette role (sidebar/panel/surface) over catalog style-guide legacy cell
- orchestrator-planning: force rootFrame fill from design.md background when a user spec is provided, so sections don't inherit a bright catalog default
- orchestrator-prompt-optimizer: infer design.md background + neutral theme fallback for sub-agent prompts
- orchestrator-sub-agent / ai-prompts: tell sub-agents to leave section root fills unset when design.md drives the palette
- design-md-style-policy: surface-colors policy block keeps MCP and web pipeline aligned
- add planning + prompt-optimizer regression tests
* chore: ignore .omx/ directory
* Enable local OS fonts with vector rendering and proper permission handling (#110)
* docs(readme): update cover screenshot
* fix(renderer): enable local OS fonts with vector rendering and proper permission handling
* test(renderer): refactoring names and creating vi.stubGlobal for the navigator as it's not available in the test environment.
---------
Co-authored-by: Fini <fini.yang@gmail.com>
Co-authored-by: Daniel Chettiar <danielc@snapwork.com>
* feat(types): add AppendContext and SubTask.existingSectionLabels
* feat(ai): add detectAppendIntent for continue/append prompts
* feat(ai): detect append intent before generate_design dispatch
* feat(ai): add applyAppendContextToPlan helper
* feat(ai): reuse existing content-root in append mode
* feat(ai): sub-agent APPEND MODE preamble for existing siblings
* docs(ai): teach horizontal scroll card-row pattern
* chore(ai): enable incremental-add skill in generation phase
* fix(canvas): render synchronously on resize to prevent white flash
Setting canvas.width/height clears the pixel buffer to transparent.
resize() previously only marked dirty, leaving the canvas transparent
until the next RAF and showing the container bg-muted through for one
frame whenever the flex layout shifted (e.g. RightPanel mount on first
selection after idle). Rendering inline after recreateSurface fills
the new surface before the browser paints, closing that window.
* style: apply oxfmt formatting drift across web and renderer files
Non-semantic line-break and wrapping adjustments picked up by oxfmt.
No behavior changes.
* fix(mcp): run codex via shell on Windows to handle .cmd shims
Since Node 18.20/20.12 (CVE-2024-27980) execFileSync refuses to spawn
.cmd/.bat files directly and throws EINVAL. On Windows route through
execSync with shell resolution so PATHEXT picks whichever shim exists
(codex.exe / codex.cmd / codex.ps1).
* feat(editor): anchor paste to selected container or sibling
Pressing Cmd/Ctrl+V now inserts pasted nodes into the selected
container (if it can hold children) or immediately after the selected
node as a sibling, falling back to the root when nothing is selected.
Previously every paste landed at document root, which broke expected
behavior when working inside nested frames.
* docs(ai): expand horizontal scroll card-row example in overflow skill
Flesh out the inline JSON example so the generation-phase skill shows
the full clipContent + nested fit_content row pattern, instead of a
truncated snippet that left model output inconsistent.
* style(lint): clear 7 oxlint warnings from recent commits
- orchestrator-planning.test.ts: narrow fill-array type to
Array<{...}> | undefined and use ?.[0] instead of unchecked [0]
so optional chain does not throw on short-circuit
- mcp-install.ts: drop `?? {}` fallbacks when spreading
config.mcpServers; spread of undefined in an object literal
is a no-op (ES2018+)
* style(lint): clear remaining 15 oxlint warnings across repo
Removes pre-existing warnings not related to any single feature:
- no-useless-fallback-in-spread (6): drop `?? {}` when spreading
possibly-undefined records (document-store-variable-actions,
pen-mcp/tools/{variables,theme-presets}, variable-theme-manager)
- no-useless-spread (2): replace `[...iterable]` with `Array.from`
in for-of snapshots (document-events, agent-indicator), keeping
the re-entry-safe copy intent explicit
- no-control-regex (2): use `\P{ASCII}` unicode property escape
instead of `[^\x00-\x7F]` to express "non-ASCII" without
referencing U+0000 (opencode clients)
- no-new-array (1): `Array.from({ length }, () => '..')` in
document-assets
- no-unused-vars (3): drop unused catch params (agent.ts,
code-generation-pipeline) and unused globSync import
(patch-srvx-bun)
- no-useless-escape (1): `[[{]` instead of `[\[{]` in
chat-message-content regex
---------
Co-authored-by: Fini <fini.yang@gmail.com>
Co-authored-by: Daniel Chettiar <74943095+1MochaChan1@users.noreply.github.com>
Co-authored-by: Daniel Chettiar <danielc@snapwork.com>
* Stabilize synced main for AI handoff, drag nesting, and Electron dev (#104)
* docs(readme): update cover screenshot
* fix: stabilize electron dev sync and codex env passthrough
* Preserve nested frame behavior during drag reparenting
Reparenting across containers used raw local coordinates and root-only clipping assumptions, which made nodes jump visually and caused dragged frames to lose clip/corner semantics after nesting. This adapts the drag-reparent fix to the current upstream store architecture, keeps frame/shape nodes from auto-detaching on canvas drags, and promotes formerly root-only frame clipping to explicit clipContent when nested.
Constraint: Latest upstream workspace checkout is incomplete locally (missing workspaces/deps), so full upstream verification could not be rerun in this environment
Rejected: Keep using raw local x/y during parent changes | fails for auto-layout/padding-rendered positions
Rejected: Make all nested frames clip unconditionally | would change non-clipping containers
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Preserve visual-position conversion through rendered coordinates when parent changes; local coordinates alone are insufficient once layout participates
Not-tested: Fresh full workspace typecheck/test/build on latest upstream checkout (blocked by missing workspace/dependency setup in this local clone)
* Keep AI codegen requests bounded while exporting asset bundles
The AI codegen pipeline needed two stability fixes: exported design images had to flow through chunk/assembly prompts as reusable asset hints, and oversized chat payloads needed a local guard before hitting provider limits. This commit wires asset extraction into the planning pipeline, threads exported asset paths into prompt assembly, and rejects obviously overlarge chat requests with an actionable client-side error.
Constraint: This branch is split out from a larger local fix stack, so only codegen/prompt/context files are included here
Constraint: Provider request limits are approximate locally, so the payload guard must be conservative rather than exact
Rejected: Inline base64 assets directly into prompts | explodes request size and repeats the same payload per chunk
Rejected: Let provider errors handle oversized payloads | too slow and opaque for users
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep asset references flowing as stable ./assets paths and enforce payload limits before fetch to avoid silent request bloat
Tested: bun x tsc -p apps/web/tsconfig.json --noEmit; cd apps/web && bun --bun vitest run src/services/ai/__tests__/context-optimizer.test.ts src/services/ai/__tests__/codegen-assets.test.ts src/services/ai/__tests__/structure-bundle.test.ts; bun run build
Not-tested: Manual end-to-end AI generation with live providers
* Explain sanitized design views instead of leaving AI to guess
The sanitized structure bundle already stabilized asset paths, but it still exposed low-level image/layout/component fields that models had to interpret on their own. This change adds explicit consumer-view enrichment for fills, layout, text, variables, themes, and component semantics, carries original image size through the Figma import path, and augments sanitized bundles with summary/highlight guidance for downstream AI consumers.
Constraint: This branch is intentionally stacked on the asset-bundle PR because it extends the sanitized/codegen asset pipeline rather than replacing it
Constraint: Figma import data is not always complete, so original image size must be preserved when present and inferred only as a fallback downstream
Rejected: Keep sanitized.json as a pure field-level dump | still leaves AI to misread transforms, layout, and component relationships
Rejected: Put all explain text directly in asset extraction helpers | mixes resource stabilization with semantic enrichment responsibilities
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Treat consumer-view enrichment as a distinct layer on top of stable asset extraction; future AI-facing semantics should land there instead of leaking into unrelated pipeline code
Tested: bun x tsc -p apps/web/tsconfig.json --noEmit; cd apps/web && bun --bun vitest run src/services/ai/__tests__/consumer-view-enrichment.test.ts src/services/ai/__tests__/codegen-assets.test.ts src/services/ai/__tests__/structure-bundle.test.ts ../../packages/pen-figma/src/figma-fill-mapper.test.ts; bun run build
Not-tested: Manual prompt-to-code generation quality with live provider responses
* Restore code-panel bundle exports for AI handoff flows
The code generation backend still produced asset manifests and AI structure bundles, but the code panel UI no longer exposed those export paths after later sync work. This commit reconnects the panel to bundle export actions, restores ZIP download behavior when generated code includes exported assets, and locks the affordances with focused panel tests.
Constraint: Other local fixes are still in progress in the working tree, so this commit is intentionally limited to the code-panel export surface
Rejected: Rebuild export support in a separate panel | users expect the export actions to remain where generation results are shown
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep code-panel UI aligned with codegen asset/bundle backends whenever generation result shape changes
Tested: cd apps/web && bun --bun vitest run src/components/panels/code-panel.test.tsx src/services/ai/__tests__/codegen-assets.test.ts src/services/ai/__tests__/structure-bundle.test.ts; bun run build
Not-tested: Manual click-through of AI Bundle and Download ZIP in the desktop/web UI
* Unblock electron dev startup in the incomplete local workspace
The local workspace was failing before the app could even start: the skills plugin hard-required js-yaml from a node_modules layout that was not present, Vite dev under Bun hit Nitro NodeResponse incompatibilities, and the web tsconfig was missing path mappings for local packages. This commit removes the unnecessary js-yaml dependency from the skills loader, runs Vite under Node for dev startup, hardens readiness probing with socket checks, and points TypeScript/Vite at the in-repo package sources.
Constraint: The current local clone has incomplete hoisted/workspace installation state, so dev startup must not depend on root package links being perfectly present
Constraint: Bun + Nitro dev currently mis-handle NodeResponse in this environment, so the safest startup path is Node-hosted Vite
Rejected: Keep js-yaml and require everyone to fix local hoisting first | still leaves electron:dev broken in the current environment
Rejected: Continue running Vite dev through Bun | reproduces the NodeResponse/Parse Error failure on /api and /editor requests
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep the dev launcher biased toward resilient local startup, even when the workspace install shape is imperfect
Tested: bun -e import('./packages/pen-ai-skills/vite-plugin-skills.ts').then(() => console.log('SKILL_PLUGIN_IMPORT_OK')); bun electron:dev verified Vite ready, MCP/Electron compiled, Electron launched, MCP sync log emitted
Not-tested: Long-running interactive desktop session after startup
* fix(figma): preserve cropped image fill transforms
The synced branch started exporting original image dimensions but dropped the
existing crop transform semantics from the shared image-fill type and both
Figma mappers. That broke the new regression test and stripped metadata that
AI consumer-view/bundle code already relies on.
Constraint: keep app and package Figma mappers in lockstep
Rejected: loosen the new regression test | would hide a real metadata regression
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: when extending image fill metadata, update shared pen-types and both Figma mapper copies together
Tested: bun --bun run test (148/149 files passed; only server/__tests__/sse-keepalive.test.ts blocked by missing agent_napi.node), cd apps/web && bun --bun vitest run src/canvas/skia/drag-reparent-policy.test.ts src/components/panels/layer-dnd-utils.test.ts src/stores/document-position-utils.test.ts src/components/panels/code-panel.test.tsx ../../packages/pen-renderer/src/__tests__/document-flattener.test.ts ../../packages/pen-figma/src/figma-fill-mapper.test.ts, cd apps/web && bun --bun vitest run src/services/ai/__tests__/codegen-assets.test.ts src/services/ai/__tests__/structure-bundle.test.ts src/services/ai/__tests__/consumer-view-enrichment.test.ts, cd apps/web && bun --bun vitest run src/utils/__tests__/security.test.ts, bun test scripts/loopback-no-proxy.test.ts, npx tsc --noEmit, bun --bun run build
Not-tested: server/__tests__/sse-keepalive.test.ts without a locally built @zseven-w/agent-native addon
* docs(editor): normalize new PR comments to English
The PR had a handful of newly introduced Chinese code comments in dev, sync, and AI helper paths. This follow-up keeps the implementation unchanged while translating those comments to English so the PR stays consistent with the repository comment-language expectation.
Constraint: The request was limited to comment language cleanup after the conflict-resolution merge, so behavior had to remain unchanged
Rejected: Leave the mixed-language comments in place | conflicts with the PR requirement for English comments
Rejected: Broader repository-wide translation sweep | unnecessary scope expansion beyond the PR-introduced comments
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep code comments in English on this branch, even when local notes or working memory are in another language
Tested: bun test scripts/loopback-no-proxy.test.ts apps/desktop/__tests__/dev-utils.test.ts; cd apps/web && bun --bun vitest run server/__tests__/mcp-sync-state-active.test.ts src/canvas/skia/__tests__/skia-interaction.test.ts; npx tsc --noEmit; branch-diff comment scan for Han characters in comment lines
Not-tested: Manual runtime behavior, since this change only rewrote comments
* style(editor): apply repository formatting expected by CI
The PR was failing the CI Format check after the conflict-resolution and comment-normalization follow-ups. This commit applies the repository formatter output to the files touched by the branch so CI sees the exact formatting it expects, without changing behavior.
Constraint: The failing GitHub Actions job stopped at Format check, so the fix had to match oxfmt output rather than introduce functional changes
Rejected: Leave the branch as-is and rely on local formatting differences being acceptable | CI explicitly rejects the current formatting
Rejected: Broader code cleanup beyond formatter output | unnecessary scope while repairing the failing check
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: After conflict resolution or comment-only edits on this repo, run bun run format:check before pushing because formatter expectations are stricter than the existing file style in some touched files
Tested: bun run format:check; bun run lint; npx tsc --noEmit
Not-tested: Full test suite after this formatting-only commit (previous run showed formatting was the first CI blocker)
* refactor(editor): remove proxy-specific dev workarounds from PR
The PR no longer needs the loopback proxy bypass layer, so this cleanup removes the proxy-specific dev entrypoint, environment bootstrap, helper module, and its tests while keeping the unrelated Electron and AI handoff changes intact.
Constraint: Removal had to be limited to proxy-related code on PR #104 without undoing the other merged fixes on the branch
Rejected: Keep the helper and stop using it | leaves proxy-specific maintenance surface and tests in the PR
Rejected: Revert the entire Electron dev file to upstream earlier than necessary | would risk dropping unrelated local conflict-resolution choices beyond the proxy scope
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: If proxy handling is reintroduced later, keep it out of this PR unless there is a dedicated, separately justified change for it
Tested: bun run format:check; bun run lint; npx tsc --noEmit
Not-tested: Manual electron:dev behavior after removing the proxy-specific launcher path
* docs(ai): translate JSON-facing semantic descriptions to English
The PR still emitted Chinese semantic description strings inside the AI consumer-view and structure-bundle JSON outputs. This change translates those JSON-facing runtime descriptions and updates the affected tests so exported AI-facing structure data is consistently English.
Constraint: The request was limited to JSON description strings, so the change had to preserve the same semantics and structure while only translating output text
Rejected: Leave Chinese test fixtures and runtime descriptions in place | conflicts with the requirement for English JSON descriptions
Rejected: Broader i18n cleanup outside these AI JSON description paths | unnecessary scope expansion beyond the requested exported-description surface
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep AI/exported JSON explanation strings in English unless a future change explicitly adds localized output modes
Tested: cd apps/web && bun --bun vitest run src/services/ai/__tests__/consumer-view-enrichment.test.ts src/services/ai/__tests__/structure-bundle.test.ts src/services/ai/__tests__/codegen-assets.test.ts; bun run format:check; npx tsc --noEmit
Not-tested: Full app runtime flows that consume these JSON descriptions outside the covered unit tests
* refactor(ai): remove remaining network-proxy handling
The current project still carried Anthropic proxy-specific heuristics and environment handling outside the PR-specific cleanup. Since the earlier crashes and connectivity issues were unrelated to proxying, this removes the remaining network-proxy branches, model remapping, and TLS override advice while leaving unrelated request flows intact.
Constraint: The cleanup needed to remove proxy-specific logic without disturbing unrelated transport concepts such as app-internal API proxy routes or React proxy objects used in tests
Rejected: Keep the proxy heuristics as dormant fallback logic | preserves misleading operational guidance and dead maintenance surface
Rejected: Rename every remaining literal use of the word proxy in the repo | would overreach into unrelated concepts like internal API proxying and JS Proxy-based test setup
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: If endpoint-specific compatibility logic is needed later, add it as explicit endpoint handling rather than generic proxy heuristics
Tested: bun run format:check; bun run lint; npx tsc --noEmit; repo-wide search for network-proxy env references after cleanup
Not-tested: End-to-end Claude connection flows against custom base URLs after removing proxy-specific remapping
* fix(electron): keep Node-backed dev launch for Nitro compatibility
Comparing against upstream commit 7271a03 confirms the current Electron dev fix is not the same idea as the original Bun-based launcher. The upstream version starts Vite with Bun, while the observed failure shows Nitro now crashes in that path with "Vite environment nitro is unavailable". This keeps the non-proxy Node-backed launcher because it fixes the actual regression without restoring the removed proxy code.
Constraint: The request preferred reverting to the upstream original only if the intent matched, but the current Nitro/Electron failure proves the upstream Bun launcher is no longer equivalent in behavior
Rejected: Restore the exact 7271a03 Bun launcher | reproduces the Nitro dev-worker crash and ERR_EMPTY_RESPONSE in Electron
Rejected: Reintroduce the old proxy workaround bundle | unrelated to the reproduced failure and already removed by request
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Electron dev on the Node-backed Vite launcher unless Nitro/Bun dev compatibility is revalidated with a real startup test
Tested: bun run electron:dev (reached Electron launch after Vite/MCP/Electron compile steps); bun test apps/desktop/__tests__/dev-utils.test.ts; bun run format:check; npx tsc --noEmit
Not-tested: Full interactive manual editor workflow after Electron launch
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* fix(ai,cli): openai-compat turn-2, StepFun reasoning+451, Mac CLI discovery
Round up the v0.7.2 stability fixes for AI connectivity and local CLI
detection that surfaced during real user runs against GLM, StepFun, and
Mac users on nvm/fnm/pnpm/bun/mise/asdf/fish shells.
Provider (via @zseven-w/agent-native v0.3.0 submodule bump):
- OpenAI-compat providers can now complete multi-turn tool-calling loops:
the request builder translates Anthropic-shaped message history
(tool_use / tool_result blocks, thinking) into OpenAI's tool_calls +
role="tool" form so turn 2 no longer 400s. system_prompt is finally
injected instead of being silently dropped.
- The SSE parser accepts `delta.reasoning` (StepFun step_plan) alongside
`reasoning_content` (GLM / DeepSeek / Qwen), and also streams tool_call
fragments, which unblocks GLM / dashscope and stops the
firstTextTimeout → fetch abort → std.http panic → Bun segfault cascade.
- HTTP 451 (StepFun content-safety) surfaces as InvalidRequest with a
specific "content blocked by provider safety filter" message instead
of an opaque error_server.
Server route + client watchdog:
- /api/ai/chat forwards the provider's last_error string
(result.errors[0]) so users see "HTTP 451 content blocked" rather than
"Provider error: error_server".
- streamChat clears firstTextTimeout on thinking chunks (when
thinkingResetsTimeout=true), so models that stream long reasoning
before any text aren't falsely killed as "stuck".
Orchestrator sub-agent resilience:
- Failed sub-agents (empty response / unparseable output) now retry once
with a minimal ~3KB kernel prompt (schema + jsonl-format only). Only
the failing subtask re-runs — successful earlier sections are kept.
- Deterministic refusals (HTTP 400/401/429/451, "content blocked",
"censorship", "authentication failed") short-circuit the retry ladder
so a 4-minute StepFun safety scan isn't spent twice in a row.
Local CLI discovery (Mac users on managed shells):
- New server/utils/cli-resolver-helpers.ts exports probeViaLoginShell()
and posixUserBinDirs(). Login-shell probe asks $SHELL (or zsh/bash
fallback — fish added at /opt/homebrew/bin/fish and friends) with
`-ilc 'command -v <cli>'` so nvm/pnpm/bun/mise/asdf/volta/fnm shims
are visible even when Electron scrubs the inherited PATH.
- resolveClaudeCli / resolveGeminiCli / resolveCopilotCli and the
inline codex/opencode resolvers in connect-agent.ts all run the same
PATH → login-shell → npm-prefix → user-bin candidates ladder. Each
step logs via serverLog to ~/.openpencil/logs/server-YYYY-MM-DD.log
for remote diagnosis.
Builtin provider preset:
- Add StepFun Coding Plan (api.stepfun.com/step_plan/v1, label "StepFun
Coding Plan") alongside the existing StepFun preset.
Version bump 0.7.1 → 0.7.2 across all workspaces.
---------
Co-authored-by: RaisCui <857943+raiscui@users.noreply.github.com>
Co-authored-by: Fini <fini.yang@gmail.com>
* fix(desktop,web): rebuild Electron dev sync + bitmap dragging fix on v0.7.1 (#99)
Re-applies b046a0d from the closed PR #97 now that the base is v0.7.1.
Original conflict against v0.7.0 came from the release branch churn —
the cherry-pick onto v0.7.1 applies cleanly.
Keeps dev-startup, sync-noise, and bitmap-dragging fixes; drops the
loopback proxy helper scripts upstream rejected in PR #92. Readiness
probe now does direct socket checks inside the existing dev entrypoint;
sync hardening stays focused on request diagnostics, backpressure, and
drag-time clip-rect correctness.
Original commit: b046a0d
Supersedes: #97 (closed, head branch deleted)
Co-authored-by: Rais <vdcoolzi@gmail.com>
* fix(canvas): use ImageFill.url in skia-interaction test
The image-backed rectangle fixture in the skia-interaction test used
`{ type: 'image', src: '…' }`, but `ImageFill` in pen-types declares
the field as `url`. `npx tsc --noEmit` flagged it as TS2352 on the
`as PenNode` cast. One-word rename.
The squash-merge of #99 captured an earlier snapshot that did not
include this fix, so re-apply directly on v0.7.1.
* feat(cli): add `op install` / `op uninstall` for openpencil-skill
Bundle skill files at build time (scripts/bundle-skill.ts → skill-bundle.json)
so users without GitHub access can install directly. Falls back to git clone
when the bundle is empty.
Supports auto-detection of: Claude Code, Codex, Cursor, Gemini CLI, OpenCode.
CI workflows updated to checkout openpencil-skill before cli:compile.
* fix(panels): allow reparenting nodes into rectangle in layer panel
CONTAINER_TYPES was missing 'rectangle', preventing drag-drop into
rectangles even though the data model (ContainerProps) and store
(moveNode) both support it.
* fix(agent,ai): tool_exec reset + insert_node with after + move_node + CRUD tools
- fix(agent): reset StreamingToolExecutor between turns — prevents stale
tool_use IDs that caused 400 errors on multi-turn tool calls (MiniMax etc.)
- feat(ai): add insert_node "after" parameter — auto-resolves sibling's
parent and position for intuitive node insertion
- feat(ai): add move_node and insert_node to CRUD tool set
- feat(ai): add Chinese keywords (增加/添加/插入) to design intent detection
- fix(ai): insert_node uses addNode directly for existing parents instead
of streaming pipeline, fixing parent resolution
* feat(ai): route CRUD intents to lightweight prompt and tool set
CRUD operations (read/update/delete) now get a focused system prompt
without design generation instructions, and use getCrudToolDefs()
(which includes insert_node and move_node) instead of the full design set.
* fix(agent,mcp): submodule update + MCP tool improvements
- Update agent-native submodule (tool_exec reset, HTTP error diagnostics)
- Improve MCP tool descriptions and parameter schemas
- Enhance agent.ts error handling
* feat(ai): add PenNode examples to CRUD prompt for complete node generation
The CRUD system prompt now includes button and text node examples
showing the full structure (fills, children, icons, layout) so models
generate complete nodes instead of empty frames.
* Update agent-native submodule to commit f9633a8, ensuring compatibility with recent changes and improvements in the agent's functionality.
* fix(ci,agent): generate skill-bundle before type check + fix moveNode arg
- Add `bun run cli:bundle-skill` step in CI before `tsc --noEmit` so
skill-bundle.json exists when type-checking the CLI
- Fix moveNode index parameter: default to -1 when undefined
* fix(ci): add pen-engine and pen-react to npm publish workflow
Insert pen-engine and pen-react in topological order between
pen-renderer and pen-mcp so they are published before pen-sdk.
* docs: add MIT LICENSE and README to all packages
- Add MIT LICENSE to pen-ai-skills, pen-core, pen-engine, pen-figma,
pen-mcp, pen-react, pen-renderer, pen-sdk, pen-types
- Add README.md to pen-engine, pen-react, pen-mcp, pen-ai-skills
* docs: comprehensive package metadata, README, CLAUDE.md, and LICENSE
- Add author, license, repository, bugs, homepage to all package.json
- Homepage points to each package's own directory on GitHub
- Rewrite README for pen-engine, pen-react, pen-mcp, pen-ai-skills
with full API docs, usage examples, and feature tables
- Add CLAUDE.md to pen-types, pen-core, pen-engine, pen-figma,
pen-mcp, pen-react, pen-renderer, pen-sdk
- Add MIT LICENSE to all packages
- Update root CLAUDE.md with index of all sub-CLAUDE.md files
- Fix git URL from nicepkg → ZSeven-W
* docs: package metadata, README, LICENSE, and CLAUDE.md for all packages
- Add author, license, repository, bugs, homepage to all package.json
- Homepage points to each package's own directory on GitHub
- Rewrite README for pen-engine, pen-react, pen-mcp, pen-ai-skills
with full API docs, usage examples, and feature tables
- Add MIT LICENSE to all packages missing it
- Add CLAUDE.md to pen-types
- Update root CLAUDE.md with index of all sub-CLAUDE.md files
- Fix git URL from nicepkg to ZSeven-W
* docs: rewrite README for pen-core, pen-figma, pen-renderer, pen-sdk
Comprehensive READMEs with full API reference, usage examples,
feature tables, and architecture overview for each package.
* feat(acp): acpAgents store — persist, hydrate, CRUD actions
* feat(acp): pen-acp package + agent settings types + store
- pen-acp/types.ts: AcpAgentConfig, AcpAgentInfo, AcpConnectResult, AcpConnectionState
- pen-acp/client.ts: connectAcpAgent (local stdio + remote WebSocket), disconnectAcpAgent
- pen-acp/event-adapter.ts: acpUpdateToSSE (ACP session/update → SSE events)
- agent-settings.ts: AcpAgentConfig type, widen ModelGroup/GroupedModel.provider
- agent-settings-store.ts: acpAgents persist/hydrate/CRUD + acpConnectionStatus
* fix(acp): remove unused type imports in client.ts
* feat(acp): ACP agent settings UI — form, cards, connect/disconnect
* feat(acp): add AcpAgentSection to Agents settings tab
* refactor(agent): AgentSession as discriminated union (native | acp)
* feat(acp): connection manager — connect, disconnect, cleanup
* feat(acp): connect/disconnect API route
* feat(acp): ACP branch in agent result handler
* fix(agent): use NativeAgentSession type for runDelegateMember
* feat(acp): ACP prompt SSE stream in agent endpoint
* feat(acp): ACP agents in model list + request routing
* i18n(acp): add ACP agent translation keys for all 15 locales
* fix(i18n): translate ACP keys for all 15 locales + fix missing key references
- zh.ts/zh-tw.ts: proper Chinese translations (Agent not translated)
- All other locales: translated from English placeholders
- Fix acp.add → acp.addAgent, acp.disconnected → acp.notConnected
* chore: bump agent-native submodule — surface upstream HTTP errors
* feat(acp,build,codegen): comprehensive fixes for ACP integration + prod build
ACP agent integration:
- Rewrite system prompt to enforce layered design pipeline (get_design_prompt
→ design_skeleton → design_content → design_refine) for higher quality output
- Use correct PenNode field names: content for text, iconFontName for icons
- Strict JSON rules to prevent empty-key / trailing-comma / smart-quote errors
- Prefer icon_font over path icons (standalone MCP has no hooks registered)
- Auto-start MCP server before ACP session (lazy bootstrap)
- Auto-reconnect ACP on stale connection (dev server restart scenario)
- Auto-approve tool permission requests (trust model: user configured agent)
- Use type: 'http' + headers: [] for MCP server config (SDK schema requirement)
- Persist ACP connections via globalThis so they survive Vite HMR
Build / packaging:
- Place agent-native under server/node_modules for Nitro to resolve at runtime
- Copy agent_napi.node to napi/ as extraResource
- Kill detached MCP server on Electron quit (before-quit + dev SIGINT handlers)
- Capture drag-dropped filesystem path via webUtils.getPathForFile so recent
files entries are clickable after reopening
Codegen:
- Compact JSON (no indent) + strip noise fields (id, parentId, default rotation
/opacity/visible, layout-managed x/y) to reduce request body size by 60-70%
so proxies don't reject with 403 'Request not allowed'
MCP batch_design robustness:
- splitOperations tracks bracket/quote balance → multi-line JSON now works
- Auto-normalize fill/stroke shorthand forms
- Collect per-line errors instead of aborting whole batch
- Repair empty keys, trailing commas, smart quotes in JSON
- Bindless I(...) form supported (auto-generates binding)
UI:
- ModelDropdown / ChatInput handle ACP model icons (Plug)
- Reset streaming state + abort controller on ACP error path
- Strip h3 JSON error wrapper so chat shows clean error messages
- ACP agent settings form + cards + connect/disconnect
* fix(types): resolve TS errors in CI typecheck
- acp-connection-manager.ts: correct relative import path (utils/ → src/types)
- ai-chat-handlers.ts: cast currentProvider to AIProviderType at design-generator callsites
- ai-chat-panel.tsx: explicitly type groups as ModelGroup[] so 'acp' string fits the widened union
- acp-agent-settings.tsx: cast window through unknown for Record lookup
- electron.d.ts: add getPathForFile to ElectronAPI declaration
- builtin-provider-presets.ts: drop now-redundant config.preset !== 'custom' check (handled by early return)
- pen-acp/client.ts: cast Writable/Readable.toWeb to typed Streams; coerce nullish agentInfo fields to undefined
---------
Co-authored-by: Rais <vdcoolzi@gmail.com>