mirror of
https://github.com/ZSeven-W/openpencil.git
synced 2026-06-01 03:14:29 +07:00
18 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f61ca2072b |
fix(ai): unwrap fetch error.cause for actionable network failures
Custom OpenAI-compatible providers surfaced Node's opaque `TypeError: fetch failed` whenever the upstream HTTP call failed (#121) — DNS, TLS handshake, connection refused, timeout — all collapsed to the same useless string. The actual reason was already on `error.cause` as a SystemError but never reached the user. Add `formatFetchError()` that walks the cause chain (including AggregateError emitted when undici tries multiple A records and each attempt fails) and prefixes the SystemError code so users see `ENOTFOUND: getaddrinfo ENOTFOUND api.foo.com` or `ECONNREFUSED: connect ECONNREFUSED 127.0.0.1:443` instead of `fetch failed`. Wire it into the model-list proxy (most common trigger from the AI Settings dialog) and the builtin chat stream. Closes #121 |
||
|
|
c4e5359596 |
docs: drop op export from CLI docs and clarify pen-mcp usage
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 #116 Closes #117 |
||
|
|
a5952bc88b |
fix(ai): swallow image-search network failures into the existing fallback
`fetchFromOpenverse` and `fetchFromWikimedia` were missing try/catch, so a ConnectTimeoutError on `api.openverse.org` (frequent on networks that can't reach Openverse) bubbled up to nitro's default handler and turned a single image-search lookup into a HTTP 500 for the whole design generation flow. The handler already treats `null` (Openverse) and `[]` (Wikimedia) as the documented fallback signals — wrap the fetches and return those on any throw, plus an explicit 8s AbortSignal.timeout so the wait is bounded. |
||
|
|
a727632a63 |
fix(ai): refresh DeepSeek defaults to v4 model series
`/models` now returns only deepseek-v4-pro and deepseek-v4-flash;
deepseek-chat / deepseek-reasoner sunset 2026-07-24 and the
deepseek-v3.2 hard-coded in the ark-coding fallback list never
existed. Both v4 models default to thinking enabled and the API
toggles via `{"thinking":{"type":"disabled"}}` — keep
`thinkingMode: 'disabled'` so the app's fast/non-thinking default
stays intact (server reasoning paths honor it; the Zig openai-compat
path doesn't emit the toggle yet, so calls through that path still
get provider-default thinking until it's wired). v4-pro promoted to
full tier; legacy aliases pinned to an exact RegExp so future
deepseek-* variants don't inherit a forced disabled mode.
Bandaid for the unwired toggle: v4-pro gets `timeoutMultiplier: 2`
because its default-on reasoning blows past the orchestrator's
planning timeout on long system prompts (observed in dev: planning
phase falls back, sub-agent then succeeds — UX degraded but
functional). Drop the multiplier once the Zig path actually sends
`thinking:{type:disabled}`.
Don't add a BUILTIN_MODEL_LISTS.deepseek entry — DeepSeek exposes
/v1/models, so let `fetchProviderModels` pull the live catalog
through `/api/ai/provider-models` instead of pinning a snapshot
(the ark-coding `deepseek-v3.2` ghost above shows what those
snapshots drift into).
|
||
|
|
a1a03bab33 | chore(release): bump to v0.7.4 | ||
|
|
025ab6c4db | style(ai): oxfmt reflow agent-tool-executor.ts | ||
|
|
1c0cb8c7ef |
fix(canvas): require explicit role:'overlay' for layout-flow escape hatch
isBadgeOverlayNode matched role:'badge'|'pill'|'tag' and pulled those children out of their parent's auto-layout, rendering them at (0,0) of the parent and stacking them on top of siblings. But in this repo badge/pill/tag are inline-component roles (see role-resolver NAME_EXACT_MAP and strip-redundant-section-fills PROTECTED_ROLES) — they're meant to flow in layout like any other child. Rename to isOverlayNode and narrow to role:'overlay'. Add matching "Layout-escape roles" guidance in role-definitions.md so generation prompts can reach the new opt-in. Inline roles now flow correctly; true floating decorations (notification dots, corner ribbons) still have a dedicated marker. |
||
|
|
572f71a1a8 |
feat(ai): detect sibling overlaps in snapshot_layout and guide fixes
snapshot_layout now emits an `overlaps` array listing sibling pairs whose rendered bounds intersect, so text-only agents can diagnose stacking bugs without a screenshot. When the shared parent has `layout: "none"` the reason string points at the real cause (absolute x/y stacking) instead of letting models hedge with height/padding tweaks. Handler prompt adds a matching diagnosis workflow so agents fix the parent layout rather than resizing the overlapping children. |
||
|
|
a67debc233
|
V0.7.3 (#111)
* 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> |
||
|
|
904c033290
|
V0.7.2-bugfix (#109)
* 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 |
||
|
|
b51d069ea6
|
V0.7.1 (#102)
* fix(desktop,web): rebuild Electron dev sync + bitmap dragging fix on v0.7.1 (#99) Re-applies |
||
|
|
e20957b740
|
V0.7.0 (#95)
* fix(agent): fix race condition causing 'no text output' on successful tool calls
The done event arrives via SSE before the executor's .then() callback
updates toolCallBlock status from 'running' to 'done'. Checking
status === 'done' at that moment finds nothing, showing the wrong message.
Fix: check if any tool calls exist (length > 0) instead of their status.
If the agent made tool calls and finished normally, the work was done.
* fix(ai): normalize built-in provider base urls
* fix(agent): preserve thinking steps in done handler, don't show empty fallback
The done handler called updateLastMessage(accumulated) which overwrote
the previously displayed thinking steps. Now:
- If tool calls + no text: show "Design generated successfully" with thinking prefix
- If thinking + no text + no tools: keep thinking steps, no fallback message
- If nothing at all: show "Agent completed with no text output"
* chore(agent): add diagnostic logging for agent event stream
* feat(agent): update submodule with tool_use SSE parsing support
* fix(agent): handle tool_use events in zigEventToSSE, suppress incomplete content_block_start
Two issues:
1. content_block_start with tool_name was forwarded as tool_call with
empty args {} (partial_json not yet accumulated). Client dispatched
generate_design with no prompt → error.
2. The complete tool_use event from Zig engine was not handled by
zigEventToSSE → mapped to 'unknown' type → client ignored it.
Fix: add tool_use branch to zigEventToSSE (maps to tool_call with full
args), suppress content_block_start tool calls (return empty string).
* feat(agent): make team mode mandatory when concurrency >= 2, force parallel designers
* feat(ai): add coding plan provider presets
* fix(ai): sync provider preset URL normalization from upstream
Includes canonicalize helpers, legacy URL migration, and region support
for Zhipu, GLM Coding, Kimi, Bailian, StepFun presets.
* test(ai): add preset URL chat/completions endpoint verification
Validates all 13 openai-compat provider presets produce correct
final URLs when combined with agent-native's /chat/completions suffix.
* feat(ai): extend RoleDefaults type with fill, stroke, effects
* feat(ai): add visual defaults to role definitions (fill, stroke, shadow)
* feat(ai): add hexLuminance and hasFill helpers for visual post-pass
* chore(agent): bump agent-native submodule to 2a57ee9
* feat(ai): add button foreground contrast post-pass fix
* feat(ai): add section background alternation post-pass fix
* feat(ai): add orphan container contrast post-pass fix
* feat(ai): add input sibling fill/stroke consistency post-pass fix
* feat(ai): enrich agent tool instructions with design quality brief
Also fix test mock for canvas-text-measure and TS cast in button
foreground contrast.
* feat(ai): infer semantic role from node name for models that don't set role
Weak models (e.g. minimax) often output nodes without the `role` property,
causing all visual defaults to be skipped. This adds name-based inference
that maps common node names (Button, Card, Search, Nav, etc.) to semantic
roles before applying defaults.
* feat(ai): intercept raw design JSON from agent and re-route through orchestrator
Some models (e.g. minimax-m2.5) ignore tool-calling instructions and output
design JSON directly as text instead of calling generate_design. This bypasses
the orchestrator pipeline (spatial decomposition, sub-agents, role resolution).
When the agent stream ends without any tool activity but the accumulated text
contains design JSON, extract the user's original prompt and re-generate
through generateDesign() for proper quality.
* feat(store): add panelWidth, panelHeight, isMaximized to AI store
* fix(ai): detect mobile intent and force 375x812 canvas in orchestrator re-route
When the agent intercept re-routes through generateDesign(), detect mobile
keywords (mobile, 手机, 移动端, app, ios, android, etc.) in the user prompt
and force canvas size to 375x812 instead of using the viewport size.
* fix(ai): clean up inline nodes before orchestrator re-route
When feedText() already inserted nodes during agent text streaming,
remove them before calling generateDesign() to avoid duplicate designs
on canvas.
* refactor(ai): remove feedText() from agent text streaming
Agent text output should never insert nodes inline — if the agent outputs
design JSON as text, the done handler re-routes through generateDesign().
Removes feedText() call and the now-unnecessary cleanup code.
* i18n: add keys for chat panel redesign, file menu, and unsaved dialog
* feat(ai): redesign quick actions to 2x2 card grid with descriptions
* feat(store): add recent files persistence utility
* feat(editor): add UnsavedChangesDialog component
* refactor(ai): simplify agent prompt and remove orchestrator re-route
Shorten AGENT_TOOL_INSTRUCTIONS to 4 clear rules that weak models can
follow: use tools, never output JSON, summarize after tool calls, add
style direction. Remove the complex interceptor that re-called
generateDesign() when the agent output raw JSON — the goal is to make
the agent reliably call the tool in the first place.
* feat(ai): move send/attach buttons into textarea, simplify bottom bar
* feat(editor): add FileMenu dropdown component with recent files
* fix(ai): strengthen generate_design result to prevent double calls
The tool result now explicitly tells the agent "Do NOT call
generate_design again — the task is done" to prevent weak models
from retrying after a successful generation.
* feat(ai): upgrade chat panel to freely resizable window with maximize
* fix(ai): retry sub-agent once on socket close or empty response
When a sub-agent stream fails (e.g. provider socket closed unexpectedly),
retry the subtask once before throwing. This handles transient connection
issues with providers like ark/volces that occasionally drop SSE streams.
* feat(editor): integrate file menu dropdown and recent files into top bar
* fix(ai): move send/attach buttons back to bottom bar with cleaner layout
* feat(editor): replace window.confirm with UnsavedChangesDialog
* refactor(editor): move file menu to left toolbar dropdown, clean up top bar
* fix(editor): add chevron indicator to file menu button
* feat(electron): add Save As, Open Recent to native File menu with recent files sync
* style(editor): redesign UnsavedChangesDialog with icon, glow ring, and stacked layout
* style(editor): redesign unsaved dialog with dark glass morphism and animated glow border
* fix(ai): keep SSE ping alive during builtin provider streaming
streamViaBuiltin() cleared the ping timer on the first SSE event,
leaving no keep-alive for the rest of the stream. If the provider
paused for >10s (thinking, slow generation), Bun's idle timeout
killed the connection. The ping timer is already cleared in the
finally block — removing the premature clearInterval.
* fix(editor): add light/dark theme support to UnsavedChangesDialog
* fix(ai): remove conflicting design knowledge from agent system prompt
The agent prompt combined AGENT_TOOL_INSTRUCTIONS ("FORBIDDEN: do not
output JSON") with pen-ai-skills design knowledge ("you MUST output
JSON"). These contradictory instructions caused weak models to ignore
tool calling. Agent mode now only gets tool instructions — design
knowledge is loaded by the orchestrator sub-agents.
* style(editor): refine unsaved dialog with staggered entry, grain texture, and breathing glow
* fix(ai): abort builtin engine after 60s of no SSE events
When a provider returns 200 OK but never sends SSE data, the Zig
readChunk blocks forever. Add a 60s timer that calls abortEngine()
to unblock the Zig thread, allowing the stream to end gracefully
and the orchestrator to retry or fail fast.
* fix(ai): skip orchestrator planning API for builtin providers
Builtin providers (minimax, etc.) consistently return empty responses
for the long planning system prompt. Skip the planning API call and
use the heuristic fallback plan directly — same result without the
60s timeout wait and wasted API call.
* feat(ai): add plan_layout + batch_insert tools for builtin provider design
For builtin providers (API key direct), the agent now uses plan_layout
and batch_insert tools instead of generate_design. This avoids the
orchestrator's multi-step API calls that unreliable providers can't
handle.
Flow:
1. Agent calls plan_layout(prompt) → creates root frame, returns sections
2. Agent generates PenNode JSON itself
3. Agent calls batch_insert(parentId, nodes) → inserts with role defaults
No extra API calls — the agent's single LLM connection handles everything.
CLI providers still use generate_design → orchestrator pipeline.
* fix(ai): remove design knowledge from builtin agent prompt to prevent JSON output
* fix(ai): prevent duplicate plan_layout calls with layoutCreated guard
* fix(ai): builtin generate_design creates layout frame instead of orchestrator
For builtin providers, generate_design now delegates to plan_layout
(creates root frame) and returns the layout info to the agent. The
agent then generates PenNode JSON and calls batch_insert — no
orchestrator, no extra API calls. CLI providers still use the full
orchestrator pipeline.
* fix(ai): minimize generate_design tool result to reduce token usage
* fix(ai): limit builtin agent to 5 turns to prevent token overflow
* fix(ai): keep long-running sse streams alive
* fix(ai): stop duplicate builtin design runs
* fix(ai): restore typecheck after rebase
* fix(ai): align builtin single-agent tooling
* fix(ai): guard builtin layout loops
* feat(ai): builtin agent uses full generate_design pipeline with streaming
- Remove normalizeKnownMalformedOpenAICompatURL — URL version detection
now handled in agent-native Zig layer
- Builtin agent uses same generate_design orchestrator pipeline as CLI
(StreamingDesignRenderer, breathing glow, skills)
- Fix streamViaBuiltin event parsing — was checking evt.type instead of
evt.stream_event.type, silently dropping all text/thinking events
- Add max_output_tokens/max_context_tokens passthrough in agent endpoint
- Fix tool completion status — add .then() handler to update tool block
to 'done' after execution (was stuck on 'running' forever)
- plan_layout reuses existing root frame via getActivePageChildren()
- batch_insert: breathing glow with random agent identity, streaming
insertion (3-node batches), max 9 nodes per call
- Mobile section element hints prevent Header/Main Content duplication
- Default background #FFFFFF, suppress thinking text in progress steps
- maxTurns unified to 20 for all providers
* fix(agent): lower default max_output_tokens to 16384
Update agent-native submodule — 200K default caused 400 errors on
providers with lower token limits (Volcengine, MiniMax, etc.).
* fix(ai): restore generate_design tool for builtin agent
Remote merge introduced getBuiltinLeadToolDefs() which filtered out
generate_design, reverting builtin agents to plan_layout+batch_insert.
Use getDesignToolDefs() for all agents to ensure the full orchestrator
pipeline is used.
* fix(ai): prevent duplicate content in mobile fallback plan and restore builtin planning
- Use single subtask for mobile fallback plan instead of Header/Main Content
split that caused both sub-agents to generate overlapping UI elements
- Remove login-screen-specific element hints that misled food/general app generation
- Always attempt AI planning for builtin providers (with 30s/60s fast timeout)
instead of unconditionally skipping — callOrchestrator already has internal
fallback for unparseable responses
- Respect user abort during planning — check abortSignal after streaming ends
to prevent fallback plan from continuing canvas mutations
* fix(ai): clean up root frames when sub-agent execution fails
Remove root frames created in Phase 2 before re-throwing, so the
canvas doesn't strand empty frames when orchestration fails after
canvas setup.
* fix(ai): only remove empty root frames on sub-agent failure
Check whether root frames have children before removing them, so
partial output from earlier successful subtasks is preserved.
* fix(ai): detect scaffold-only frames in failure cleanup
Snapshot descendant count after Phase 2 setup and compare on failure.
Only remove root frames whose descendant count hasn't grown beyond
scaffold nodes (status bar, dashboard columns), preserving frames
that received real sub-agent content.
* fix(ai): restore default frame instead of deleting it on failure
When the root frame replaced the default empty frame (DEFAULT_FRAME_ID)
and sub-agents fail, restore it to its empty state rather than removing
it, so the canvas always retains a usable frame.
* fix(ai): fully replace default frame on failure instead of shallow merge
Remove and re-add the default frame so stale layout, gap, fill, and
scaffold children from the failed generation run are fully cleared.
* style(editor): upgrade provider form with shadcn Select, always-visible API format toggle
* fix(editor): hide API format toggle for Anthropic and OpenAI presets
* feat(editor): auto-switch baseURL on API format change, make baseURL always editable
Add dual-format URLs for providers that support both OpenAI and Anthropic:
- OpenRouter: /api/v1 (OpenAI) / /api (Anthropic)
- DeepSeek: /v1 (OpenAI) / /anthropic (Anthropic)
- MiniMax: /v1 (OpenAI) / /anthropic (Anthropic)
* style(editor): redesign provider form with compact layout, field icons, and segmented controls
* fix(editor): lock baseURL for Anthropic and OpenAI presets
* fix(editor): only show API format toggle for providers that support both formats
* refactor(editor): use presetConfig.altType to determine API format toggle visibility
* feat(editor): add Anthropic format support for Zhipu (open.bigmodel.cn/api/anthropic)
* feat(editor): add Anthropic format support for GLM Coding Plan
* feat(editor): add Anthropic format support for Kimi (api.moonshot.cn/anthropic)
* feat(editor): add Anthropic format support for Bailian/DashScope
* feat(editor): add Anthropic format support for DouBao and Ark Coding Plan
* feat(editor): add Anthropic format support for ModelScope
* feat(editor): add Bailian Coding Plan preset with dedicated endpoint and Anthropic support
* feat(editor): add altRegions for region-aware Anthropic URL switching
Providers with regions now correctly switch altBaseURL by region:
- MiniMax: minimaxi.com / minimax.io
- Zhipu: bigmodel.cn / z.ai
- GLM Coding: bigmodel.cn / z.ai
- Kimi: moonshot.cn / moonshot.ai
- Bailian: aliyuncs.com / dashscope-intl
- Bailian Coding: coding.dashscope / coding-intl.dashscope
* fix(ai): remove hardcoded blue fill from button role defaults
Button role was injecting #2563EB fill on any frame inferred as a
button, including container frames named "Button Group" or similar.
This caused mysterious blue backgrounds on non-blue themed designs.
- Remove fill from all three button role branches
- Add word-boundary matching for button name inference
- Add container-suffix exclusion to prevent "Button Group" etc.
from being inferred as button role
* feat(types): add codegen types and wire DTO types to pen-types
Migrate canonical codegen type definitions (Framework, PlannedChunk,
CodePlanFromAI, ExecutableChunk, CodeExecutionPlan, ChunkContract,
ChunkResult, CodeGenProgress, ContractValidationResult) from
pen-codegen to pen-types to establish pen-types as the authoritative
source before pen-codegen package removal.
Add new wire DTO types for MCP/CLI responses:
- NodeSnapshot: depth-limited node snapshot for wire transfer
- ExecutableChunkPayload: hydrated chunk payload with truncated nodes
- ResolvedDepContract: dependency contract with null support
Add comprehensive type tests covering FRAMEWORKS constant, NodeSnapshot
variants, and ResolvedDepContract nullability.
* feat(core): add sanitizeName and nodeTreeToSummary utilities
Migrate utility functions from pen-codegen to pen-core for broader reuse:
- sanitizeName: converts strings to PascalCase
- nodeTreeToSummary: recursively renders node trees for AI prompts
Add comprehensive tests for both utilities.
* feat(mcp): migrate validateContract from pen-codegen
Move the validateContract function into pen-mcp to support the chunked
codegen pipeline. The types (ChunkResult, ContractValidationResult) are
already re-exported from @zseven-w/pen-types (Task 1 completed).
- Create packages/pen-mcp/src/utils/validate-contract.ts
- Add re-export to packages/pen-mcp/src/index.ts
- Add 4 test cases validating PascalCase, code presence, and SFC detection
* feat(mcp): implement read_nodes handler with depth-limited subtree fetching
Adds handleReadNodes() in pen-mcp that supports depth=-1 (full tree),
depth=0 (node only), and depth=N (N levels of children), reusing the
existing readNodeWithDepth utility. Includes 7 Vitest tests.
* feat(editor): implement App-side codegen plan state store
Adds in-memory plan store with createPlan, getPlan, submitChunkResult,
assemblePlan, and cleanPlan. Validates duplicate chunkIds, empty nodeIds,
unknown/circular dependencies, and missing nodes. Hydrates ExecutableChunkPayload
with NodeSnapshot[] and resolved dep contracts. TTL-based expiry (30m).
* fix(codegen): export PlanState interface and narrow statusOverride type
- Export PlanState interface for public API (getPlan returns PlanState | undefined)
- Narrow submitChunkResult statusOverride parameter from ChunkStatus to 'failed' | 'skipped'
(only these two values have defined semantics in the validation logic)
* feat(mcp): add HTTP endpoints for read_nodes and incremental codegen pipeline
Adds five Nitro route handlers under /api/mcp/:
- POST read-nodes: returns node snapshots with depth-limited children
- POST codegen/plan: validates and stores a CodePlanFromAI, returns execution plan
- POST codegen/submit: submits a ChunkResult and returns next ready chunk
- GET codegen/assemble/[id]: assembles final output from completed chunks
- DELETE codegen/plan/[id]: cleans up plan state early
All routes support live canvas (getSyncDocument) and offline file (openDocument)
modes. Adds @zseven-w/pen-mcp as a workspace dependency of apps/web.
* refactor(mcp,web): dedup readNodeWithDepth and validateContract imports
Move readNodeWithDepth export from inline copy in read-nodes.post.ts to
pen-mcp for DRY, and use pen-mcp's validateContract in codegen-plan-store
instead of maintaining duplicate implementation.
- Export readNodeWithDepth from pen-mcp/utils/node-operations
- Remove inline readNodeWithDepth from apps/web/server/api/mcp/read-nodes.post.ts
- Add type cast (as unknown as NodeSnapshot) for pen-mcp readNodeWithDepth result
- Replace validateContractFn with import from pen-mcp in codegen-plan-store.ts
All 36 tests pass (4 validate-contract + 7 read-nodes + 11 plan-store + 14 security)
* feat(mcp): add codegen HTTP client handlers
Implement four thin HTTP client wrappers for codegen pipeline:
- codegen_plan: POST /api/mcp/codegen/plan — initialize plan
- codegen_submit_chunk: POST /api/mcp/codegen/submit — submit chunk result
- codegen_assemble: GET /api/mcp/codegen/assemble/:planId — assemble code
- codegen_clean: DELETE /api/mcp/codegen/plan/:planId — cleanup state
All handlers use await getSyncUrl() to discover running App, throw on missing sync
URL (except codegen_clean which gracefully returns ok). Uses encodeURIComponent for
URL path parameters. No business logic, purely HTTP clients for App endpoint integration.
* feat(mcp): register codegen tools in server and replace export_nodes
Add codegen-routes.ts with definitions and dispatcher for all 5 new tools
(read_nodes, codegen_plan, codegen_submit_chunk, codegen_assemble,
codegen_clean). Replace EXPORT_* wiring in server.ts with CODEGEN_* and
update pen-mcp public API in index.ts to export the new handlers instead
of handleExportNodes.
* feat(cli): add read-nodes and codegen pipeline commands
Add op read-nodes to query document nodes via the App HTTP API, and
op codegen:plan/submit/assemble/clean commands to drive the incremental
codegen pipeline. All five commands are stateless HTTP clients against
the /api/mcp/* endpoints. Also update help text to document the new
commands.
* refactor(codegen): migrate all pen-codegen consumer imports (Task 12)
Replace all @zseven-w/pen-codegen imports in consumer files with their
canonical new homes: types → pen-types, sanitizeName/nodeTreeToSummary →
pen-core, validateContract → pen-mcp, generator functions → pen-sdk
(which retains one pen-codegen re-export until Task 13 deletes the package).
- code-panel.tsx: Framework, CodeGenProgress, ChunkStatus, FRAMEWORKS → pen-types
- code-generation-pipeline.ts: types → pen-types, sanitizeName → pen-core, validateContract → pen-mcp
- codegen-prompts.ts: types → pen-types, nodeTreeToSummary → pen-core
- code-generation-pipeline.test.ts: CodePlanFromAI, PlannedChunk → pen-types
- design-engine.ts: remove pen-codegen import + delete generateCode() method
- design-engine.test.ts: delete generateCode test
- pen-sdk/index.ts: codegen re-export split into types (pen-types) + functions (pen-codegen)
- apps/web/src/services/codegen/*.ts: delete all 9 generator proxy files
- apps/cli: migrate export.ts to pen-sdk; add pen-sdk dependency, drop pen-codegen
* fix(cli,sdk): fix Task 12 spec violations — delete export.ts, remove pen-codegen from pen-sdk
- Delete apps/cli/src/commands/export.ts (replaced by op read-nodes + op codegen:*)
- Remove `case 'export':` dispatcher and help text from apps/cli/src/index.ts
- Remove @zseven-w/pen-sdk dep from apps/cli/package.json (only used by deleted export.ts)
- Remove generator function re-exports from pen-sdk/src/index.ts (codegen section deleted)
- Remove @zseven-w/pen-codegen dep from pen-sdk/package.json
pen-sdk now has zero imports from @zseven-w/pen-codegen, unblocking Task 13.
* chore(codegen): remove pen-codegen package entirely
All consumers have been migrated to pen-types (types) and pen-core
(utility functions) in Tasks 1-12. Delete packages/pen-codegen/ and
remove the workspace dependency from apps/web and pen-engine.
* chore(mcp): remove pen-codegen from CI, scripts, desktop, and delete old export tool files
Cleans up all remaining references to the deleted pen-codegen package from
esbuild alias flags (mcp:compile, cli:compile, desktop dev.ts), publish scripts,
and the GitHub Actions publish workflow. Deletes the superseded export-routes.ts
and export-nodes.ts MCP files that were replaced by codegen-routes.ts in Task 10.
* fix(ai): inline validateContract in code-generation-pipeline to avoid pen-mcp browser import
Importing validateContract from @zseven-w/pen-mcp pulled in document-manager
transitively, which uses node:fs/promises and broke Vite's browser bundle:
"Module node:fs/promises has been externalized for browser compatibility".
Inline the 11-line pure function instead — the original plan listed inlining
as an acceptable option for this client-side consumer.
* fix(panels): force builtin provider in code panel for builtin: models
modelGroups reports 'anthropic' or 'openai' as the provider for builtin
providers (based on bp.type), but streamChat needs 'builtin' to route
the request through streamViaBuiltin on the server. Without this, models
like minimax were sent to streamViaAgentSDK (Claude Code) which rejected
them with "There's an issue with the selected model".
Mirror the same override that ai-chat-handlers.ts already applies, so the
code panel uses the same provider routing as the chat panel.
* fix(mcp): fall back to IPv6 for live sync url discovery
Vite 6+ resolves `localhost` to `::1` only on macOS, leaving IPv4
127.0.0.1 unreachable. The MCP document-manager previously only probed
IPv4 hosts, so every batch_get / open_document / get_variables call
failed with "fetch failed" even though the dev server was running. Add
[::1] to SYNC_BASE_URLS and race all probes in parallel via Promise.any
so the first reachable host wins immediately instead of serially waiting
for IPv4 timeouts.
* fix(ai): harden post-streaming pipeline against layout and phone mockup bugs
Weaker sub-agents (MiniMax M2, GLM, Kimi) were producing two classes of
structural failures that the post-streaming passes did not handle:
1. Missing layout on container frames — children collapsed to (0,0)
because computeLayoutPositions skips frames with no explicit layout.
2. Fake "Phone Mockup" wrappers — the sub-agent pasted phone bezel
properties (cornerRadius 32, width 260, black fill, horizontal layout)
onto its own root frame and stuffed an entire duplicated section tree
inside, compressing everything into a 40px-wide column.
The root cause for #2 was that `jsonl-format.md` (loaded by every
generation sub-agent) and a line in `orchestrator-sub-agent.ts` both
injected the phone-mockup spec unconditionally. On mobile flows where
the whole design IS already a phone screen, this prompt fragment has no
legitimate use and confuses the model.
Fixes:
- Add normalizeTreeLayout in pen-core: writes explicit `layout` for
frames missing it (prefers inferLayout, falls back to `vertical`),
strips stale x/y from auto-layout children. Skips the fallback when
any non-overlay child carries explicit x/y — preserves intentional
absolute positioning (phone mockup internals, hero overlays).
- Add unwrapFakePhoneMockups in pen-core: detects fake phone bezels by
name or visual signature (cornerRadius 28-40 + width 240-320) and
either promotes children to the parent (unwrap) or strips the fake
visuals if the fake wrapper is the root itself (sanitize).
- Remove the phone mockup line from jsonl-format.md; gate the in-code
version behind a subtask-label keyword guard.
- Add an explicit NO-PHONE-MOCKUP-WRAPPER instruction for mobile
sub-agents so M2 doesn't self-wrap.
- Fix stale-reference bug in applyPostStreamingTreeHeuristics: after
resolveTreePostPass calls updateNode, the original rootNode reference
is detached; refetch via getNodeById before running normalizeTreeLayout.
- Fix the same bug inside resolveTreePostPass itself: every internal
updateNode call was followed by direct mutations on a `root` parameter
that Zustand had already replaced. Track `currentRoot` and refresh it
after each updateNode.
- Force a canvas resync after the mutation passes via forcePageResync:
in-place mutations on store-owned nodes do not publish; without this
the canvas stays stale on sub-agent retry paths that skip the implicit
updateNode flush. Use forcePageResync (not a hand-rolled shallow doc
spread) because canvas-document-sync subscribes to active page
children identity, not doc identity.
All correctness guarantees are covered by unit tests in pen-core
(normalize-tree-layout.test.ts 13 cases, unwrap-fake-phone-mockup.test.ts
16 cases).
* fix(ai): require cover ratio for icon fallback fuzzy matching
The icon path resolver matched "heart" inside "heartRate-waveform" via
findSubstringFallback and replaced the waveform geometry with the lucide
heart icon, leaving the real waveform invisible. The root cause was that
both prefix and substring fallbacks accepted any matched key of >= 4
characters, regardless of how little of the name it actually covered.
- findPrefixFallback now requires the matched key to cover at least 50%
of the normalized name. "arrowdowncircle" -> "arrowdown" (60%) still
works; "heartratewaveform" -> "heart" (29%) is rejected.
- findSubstringFallback is now suffix-match only (not "anywhere"), with
the same 50% ratio guard. "badgecheck" -> "check" still resolves, but
"starheartbadge" -> "heart" no longer hijacks an unrelated compound
name.
Legitimate chart icons (chart, barchart, analytics, activity, trendingup)
still resolve via exact lookup and are unaffected by the stricter fallback.
* fix(ai): drop redundant section-level fills from sub-agent output
Sub-agents (MiniMax M2 especially) hedge by hardcoding a "safe dark" hex
(#0A0A0A, #111, etc.) on every section root they emit. That fill then
completely covers the page root's intended background color —
#1a1a2e in the health-tracker case — breaking theme switching and
creating visible seams between sections.
Two-layer fix:
1. Prompt guardrail in orchestrator-sub-agent.ts — tell the sub-agent NOT
to set `fill` on its section root, and show the actual inherited
background color so the model has no reason to hedge.
2. Post-pass cleanup stripRedundantSectionFills in pen-core — for each
direct child of the page root frame, drop the fill if:
- the child has no role or a structural role (section/row/column/
stack/container/hero/footer/cta-section/etc.), AND
- the fill matches the root fill exactly OR is one of the common
"safe dark" hexes sub-agents reach for.
Cards, buttons, chips, badges, inputs, phone mockups, status bars,
banners and other protected roles are never touched. Unknown roles
are also preserved (conservative default).
The pass is wired into both applyPostStreamingTreeHeuristics (streaming
path, runs on the outer parent frame via getParentOf so each sub-agent's
section root is visible at the strip scope) and sanitizeNodesForInsert/
Upsert (batch path). All mutations are covered by the existing
forcePageResync call so the canvas re-renders without a stale frame.
* fix(ai): narrow section-fill strip scope to the true page root
Follow-up on
|
||
|
|
3c697d817d
|
V0.6.0 (#88)
* fix(renderer): skip paragraph image cache when zoomed in * refactor(publish-cli): streamline version publishing process - Removed the check for already published versions to simplify the workflow. - Updated npm publish commands to handle already published versions gracefully, allowing the process to continue without aborting. - Added publishing step for the new pen-ai-skills package, ensuring it is included in the deployment process. * fix(mcp): wire openpencil codex install to config toml (#85) Co-authored-by: Kaiiiiiiiii <182183652+Smile232323@users.noreply.github.com> * refactor(mcp): reorganize codex-cli handling in installation process - Removed the codex-cli configuration from CLI_CONFIGS and adjusted the installation logic to handle codex-cli actions directly. - Improved error handling for unknown CLI tools and streamlined the installation process for codex-cli, ensuring it uses its own commands for adding/removing components. * feat(agent): add built-in agent SDK and web integration Introduces @zseven-w/agent — a domain-agnostic agent SDK with: - Agent loop (plan→act→observe) with dual execution model - Anthropic + OpenAI-compatible provider adapters via Vercel AI SDK - Tool registry with auth levels (read/create/modify/delete/orchestrate) - Agent team orchestration with delegate tool - SSE streaming protocol encoder/decoder - Sliding window context management Web app integration: - Built-in provider config UI with presets (Anthropic, OpenAI, OpenRouter, DeepSeek) - Model search via provider API proxy endpoint - Built-in models appear in the model dropdown alongside CLI agents - Server-side agent SSE endpoint with session management - Client-side tool executor with undo batch support - Inline tool call blocks in chat UI * feat(api): implement keep-alive pings for long-running LLM calls - Added a keep-alive mechanism in the SSE stream for the agent API to prevent timeouts during long-running LLM calls. - Updated the keep-alive interval to 8 seconds to align with Bun.serve's default idle timeout of 10 seconds. - Ensured proper cleanup of the ping timer when the stream is closed. * feat(mcp): enhance live sync diagnostics and port file management - Implemented a mechanism to probe the live sync server's availability, providing clearer diagnostics for connection issues. - Updated the port file structure to include a unique token for better management and cleanup. - Enhanced the `getSyncUrl` and `getLiveSyncState` functions to return detailed status messages based on the server's response. - Added tests for live sync diagnostics to ensure accurate reporting of server states. * feat(mcp): implement sync URL caching for improved performance - Added caching mechanism for sync URLs to reduce repeated reads and health checks, enhancing performance during live document and selection fetches. - Introduced functions to set and clear the cached sync URL, improving connection management. - Updated existing functions to utilize the cached URL when available, streamlining the fetching process. * feat(skia): enhance syncFromDocument error handling and normalize document structure - Wrapped the syncFromDocument method in a try-catch block to log errors during synchronization, improving debugging capabilities. - Introduced normalization of external documents in the document store to ensure consistent structure before processing. - Updated text content resolution to handle both 'content' and 'text' fields, enhancing compatibility with various node formats. - Refactored text measurement functions to streamline text handling and improve layout consistency. * chore: update package versions to 0.6.0 across all modules and enhance code generation pipeline - Bumped version from 0.5.3 to 0.6.0 in package.json files for all modules including core, agent, and various code generation packages. - Refactored code generation functions to utilize a new AI code generation pipeline, marking previous functions as deprecated with plans for removal in v1.0.0. - Introduced new export nodes functionality in the MCP server for raw PenNode data export. * fix(mcp): clear stale sync cache on page load to prevent false dirty state When refreshing the page or opening a new file, the SSE document:init event would echo back the old cached document, causing applyExternalDocument to unconditionally set isDirty=true and trigger a spurious save prompt. * style(panels): improve AI checklist visual design Add progress bar, spinner animation, highlighted active items, and pill-shaped counter badge for a more polished orchestrator progress UI. * feat(ci): add Homebrew Cask update workflow for OpenPencil releases - Implemented a new GitHub Actions job to update the Homebrew Cask for OpenPencil upon new version tags. - The workflow fetches the latest macOS binaries, computes their SHA256 checksums, and updates the cask formula accordingly. - Includes steps for committing and pushing changes to the tap repository. * docs: update installation instructions in README and enhance CI workflow for Scoop bucket updates - Added detailed installation instructions for macOS, Windows, and Linux in the README. - Introduced a new GitHub Actions job to update the Scoop bucket with the latest OpenPencil release, including versioning and SHA256 checksum computation for Windows binaries. * docs: add OpenPencil Skill plugin link to all i18n READMEs Add localized LLM Skill link in CLI section across all 15 README files, pointing to zseven-w/openpencil-skill repository. * docs: add same-name project disclaimer to all i18n READMEs Distinguish from open-pencil/open-pencil (Figma-compatible visual design with real-time collaboration) — this project focuses on AI-native design-to-code workflows. * fix(agent): resolve SSE timeout, routing, and message format issues - Add 5s keep-alive ping to agent SSE stream (prevents Bun 10s idle timeout) - Consolidate tool-result and abort into single agent endpoint (?action=result|abort) - Fix assistant message history: include text alongside tool-call parts - Fix ToolResultPart format: use 'output' field with {type:'text',value} structure - Use openai.chat() instead of openai() for Chat Completions API (OpenRouter compat) - Use proper TOOL_SCHEMAS instead of z.any() for tool parameters * fix(agent): prevent sliding window from splitting assistant+tool groups The sliding window context strategy was naively slicing by message count, which could leave orphaned tool_result messages without their preceding assistant tool_use — causing Claude API to reject the request. Now counts "logical turns" (user/assistant starts) and never cuts inside an assistant→tool group. Also increased default window from 10 to 50 turns. * fix(agent): use correct AI SDK v6 parameter name maxOutputTokens streamText() in AI SDK v6 renamed maxTokens to maxOutputTokens. Default 4096 prevents OpenRouter credit limit errors from requesting the model's full 65536 token capacity. * feat(agent): add API error classification and auto-retry without tools When a model doesn't support function calling (400 errors, missing arguments), the agent loop now classifies the error and automatically retries without tools on the first turn. Also provides user-friendly error messages for common failures: privacy restrictions, credit limits, rate limiting, and incompatible models. * fix(agent): improve system prompt with PenNode schema and workflow guidance - Add PenNode property schema to agent system prompt so models know valid properties (fills, cornerRadius, padding array, etc.) - Explicitly forbid CSS properties (backgroundColor, boxShadow, etc.) - Add workflow steps: plan before creating, avoid create-then-delete - Change max turns reached from error to normal done event * feat(agent): align insert_node with CLI batch_design capability - insert_node now supports nested children arrays (recursive ID generation) - Post-processing pipeline runs after insertion: role resolution, icon resolution, layout sanitization, unique ID enforcement — same as MCP batch_design with postProcess=true - System prompt teaches model to create entire designs in ONE insert_node call with nested children, instead of 20+ individual calls - Includes concrete example of nested PenNode structure in prompt * fix(agent): deep-clone node before post-processing to avoid Zustand mutation Zustand state is immutable — post-processing functions mutate in-place. JSON.parse(JSON.stringify()) creates a mutable copy. Each post-processing step is individually try-caught so partial failures don't break insertion. * fix(agent): return node count in insert_node result to prevent model retries insert_node now returns {id, nodesCreated, message} so the model knows the full tree was created. System prompt reinforces: when insert_node succeeds, do NOT retry. Reduces 5+ duplicate insert calls to exactly 1. * fix(agent): prevent duplicate root-level inserts from weaker models Track the first root-level insert_node ID per session. Subsequent root-level insert_node calls return the existing ID with a message instead of creating duplicates. Fixes M2.5 and similar models that ignore "do not retry" prompt instructions. * feat(agent): support Anthropic API format in custom provider settings Custom provider preset now has an API Format toggle: "OpenAI Compatible" or "Anthropic". This allows users to configure custom Anthropic-compatible endpoints (proxies, mirrors) in addition to OpenAI-compatible ones. Anthropic provider also now accepts optional baseURL for proxy support. * fix(agent): update Custom option label in provider dropdown * fix(agent): match 'invalid function arguments' in error classifier for auto-retry * fix(agent): always auto-retry without tools on first turn errors Many providers (MiniMax, StepFun) have broken tool call implementations. Instead of pattern-matching specific error messages, any streaming error on turn 0 now triggers auto-retry without tools. The model falls back to generating a text-only response instead of failing entirely. * fix(agent): use clean JSON Schema for tool definitions (no $schema field) Replaced Zod schemas with jsonSchema() from AI SDK for tool parameter definitions. Zod's zodToJsonSchema adds "$schema" and "additionalProperties" fields that strict OpenAI-compatible APIs (MiniMax, StepFun) reject with "invalid function arguments". Clean JSON Schema only has type/properties/ required — compatible with all providers. Also added text-mode fallback prompt for when tools are truly unsupported. * fix(agent): ensure tool call args is always {} and fix turn>0 retry Two fixes for MiniMax "invalid function arguments" error: 1. Ensure args is always {} (never undefined/null) when building conversation history — undefined args causes strict APIs to reject 2. Auto-retry without tools now works on ANY turn (not just turn 0) by resetting history to original user messages and restarting * fix(agent): use SDK response.messages for history instead of manual construction Root cause of MiniMax "invalid function arguments" error: we were manually constructing ModelMessage[] for conversation history, which the SDK then failed to convert correctly to OpenAI format (dropping function.arguments). Fix: use response.response.messages from the SDK — it produces correctly formatted messages that the provider knows how to convert. Only manually add tool result messages for client-executed tools (no execute() function). Also keeps a fetch interceptor as safety net to patch any remaining edge cases with missing/malformed arguments. * fix(agent): parse stringified JSON in insert_node data parameter Some models (MiniMax M2.5) send insert_node data as a JSON string instead of an object. Now handleInsertNode detects string data and JSON.parse it before processing. Fixes nodesCreated:1 when model sends nested children as a stringified object. * fix(agent): sanitize node data and catch addNode side-effect errors - Convert model's 'border' property to valid 'strokes' array - Filter null/non-object children before processing - Wrap docStore.addNode in try-catch — canvas sync side-effects (e.g., renderer hitting unknown properties) may throw but the node IS still inserted. Return success regardless. * fix(agent): auto-zoom to fit after insert_node to show new design * fix(agent): align insert_node with batch_design — auto-replace empty root frame When inserting a frame at root level and an empty root frame exists, replace it and inherit its position (x:0, y:0). This matches the MCP batch_design behavior (line 146-161) so the design lands in the visible viewport instead of off-screen at x:1250. * fix(agent): use updateNode for empty frame replacement (no duplicate keys) The remove+add pattern caused React duplicate key errors because two separate Zustand state updates could leave the node in two places. Now uses a single updateNode call to replace the empty frame's properties in-place — atomic operation, no duplicates. * fix(agent): set replaced=true BEFORE updateNode to prevent duplicate on side-effect throw * fix(agent): use atomic tree swap for empty frame replacement updateNode caused canvas sync crash (map on undefined) because the renderer couldn't handle a complete property replacement on an existing node. Now uses removeNodeFromTree + insertNodeInTree in a single setState — same atomic approach as MCP batch_design. The Skia engine sees the new node as a fresh addition, not an update to an existing one. * fix(agent): simplify empty frame replacement to removeNode+addNode via store API * refactor(agent): use applyNodesToCanvas instead of raw addNode The agent's insert_node was bypassing the design pipeline's sanitization and canvas sync code, causing blank canvas rendering. Now delegates to the SAME applyNodesToCanvas function used by the CLI/MCP design pipeline. This handles: - sanitizeNodesForInsert (role defaults, layout fixes, unique IDs) - isCanvasOnlyEmptyFrame → replaceEmptyFrame (empty frame at 0,0) - icon resolution and image scanning - proper Skia canvas sync Removed the custom postProcessNode method — no longer needed since applyNodesToCanvas does the same work correctly. * feat(agent): add generate_design tool using internal CLI design pipeline generate_design delegates to the SAME generateDesign() function the standard chat uses — orchestrator, sub-agents, streaming insertion, post-processing. Finds the first connected CLI provider for LLM calls. Also uses insertStreamingNode with resetGenerationRemapping() for insert_node, matching the CLI streaming pattern exactly. * feat(agent): replace insert_node with generate_design as primary design tool Remove insert_node and find_empty_space from agent tool set — models should use generate_design for creating designs, not raw PenNode JSON. generate_design accepts natural language prompts and delegates to the full internal pipeline. Keeps update_node/delete_node for modifications. * feat(agent): simplify system prompt to direct models to generate_design Clear instruction: when user asks to create/design, MUST call generate_design tool. No JSON output, no manual node construction. * fix(agent): strip <think> tags from model text output in chat UI Models like MiniMax M2.5 and DeepSeek output <think>...</think> as plain text (not via the thinking SSE event). Strip both closed and unclosed <think> tags from the displayed text during streaming. * fix(renderer): skip paragraph image cache when zoomed out below 0.5x Bitmap text cache at fixed DPR resolution produces jagged edges when scaled down significantly. Now only uses cache at 0.5x–1x zoom range. Below 0.5x and above 1x, falls back to vector Paragraph API rendering. * fix(ai): prevent model from using OpenPencil as brand name in generated designs * fix(agent): strip <think> tags from final message, not just during streaming The regex was only applied during text-delta events but the final message (returned by runAgentStream and set in done/error handlers) used the raw accumulated text. Now stripThinkTags() is applied at the return point so the final displayed message is always clean. * fix(ai): reduce keepalive ping interval from 15s to 5s for Bun compatibility Bun.serve has a 10s idle timeout. The previous 15s ping interval meant the first ping arrived AFTER Bun killed the connection, causing "socket connection was closed unexpectedly" errors when waiting for slow LLM responses (extended thinking, TTFT > 10s). Now pings at 5s. * fix(renderer): rasterize paragraph image cache at 2x minimum for crisp text on low-DPR * fix(agent): remove hardcoded TOOL_SCHEMAS and maxOutputTokens - Server uses client-provided JSON schemas (single source of truth) - maxOutputTokens configurable per provider, defaults to model limit - turnTimeout increased to 5min for generate_design pipeline - Session cleanup wrapped in try-catch - Re-export streamText from agent SDK for consumer use * feat(agent): add builtin provider support to /api/ai/chat endpoint streamViaBuiltin() uses Vercel AI SDK to call LLM directly with API key — no CLI tool required. ai-service.ts attaches builtin credentials from agent settings store when provider is 'builtin'. This enables generate_design to work without any CLI provider connected. * fix(agent): align generate_design params with CLI pipeline and handle field name variants - Pass concurrency, variables, themes, designMd to generateDesign() (was missing, causing lower quality output vs CLI mode) - Accept both 'prompt' and 'description' field names from models - Fall back to builtin provider when no CLI provider connected - Enable animated node insertion * feat(agent): dynamic system prompt via pen-ai-skills + misc fixes - Replace hardcoded AGENT_SYSTEM_PROMPT with buildAgentSystemPrompt() that loads design knowledge from pen-ai-skills (same as CLI pipeline) - Validate builtin provider apiKey before agent connection - Client-side tool schema serialization for server (no duplication) - Update tool_call block status locally as fallback for lost SSE events - Pass maxOutputTokens from provider config * refactor(agent): extract builtin provider settings to separate file Split BuiltinProviderForm, BuiltinProviderCard, BuiltinProvidersSection from agent-settings-dialog.tsx (1279→730 lines) into builtin-provider-settings.tsx (394 lines). Both under 800 line limit. * refactor(agent): extract model selector to separate file Split ModelDropdown, ConcurrencyButton, resolveNextModel, PROVIDER_ICON from ai-chat-panel.tsx (915→690 lines) into ai-chat-model-selector.tsx (183 lines). Both under 800 line limit. * fix(renderer): guard against undefined fill entries in resolveFillColor/resolveStrokeColor * feat(ai): extend BuiltinProviderPreset with 9 new providers Add MiniMax, Zhipu, Kimi, Bailian, DouBao, Xiaomi MiMo, ModelScope, StepFun and NVIDIA NIM to the builtin provider preset type union. * feat(ai): add provider presets and region switcher for builtin providers Add preset configs for MiniMax, Zhipu, Kimi, Bailian (DashScope), DouBao Seed, Xiaomi MiMo, ModelScope, StepFun and NVIDIA NIM with correct API base URLs and model placeholders. Providers with separate China/Global endpoints (MiniMax, Zhipu, Kimi, Bailian, StepFun) get a region toggle that auto-switches the base URL. Region inference works both for new providers and when editing existing ones via REGION_URLS reverse-lookup table. * style(ai): increase settings dialog height for more provider entries * feat(ai): add i18n for builtin provider settings (15 locales) Extract all hardcoded strings in builtin-provider-settings.tsx to i18n keys under the builtin.* namespace. Add translations for all 15 supported languages: en, zh, zh-TW, ja, ko, fr, es, de, pt, ru, hi, tr, th, vi, id. * fix(ai): remove remaining hardcoded strings in builtin provider UI - Extract error messages, badge text, tooltip, and placeholder to i18n - Remove unused region label fields from PresetRegion interface - Add 8 new builtin.* keys across all 15 locales - Fix ai-chat-model-selector API Key badge and parallel agents tooltip - Fix ai-chat-panel provider description template - Fix ai-chat-handlers error messages via i18n.t() * fix(agent): clean up pending tool calls on exit and improve error handling P0: Wrap agent loop generator in try-finally to reject all pending tool call promises and clear timeout timers when the loop exits. Prevents timeout leaks when sessions end early. P1: Add HTTP status code matching (429, 402, 403) before regex fallback in classifyAPIError for more reliable error classification. P1: Clone tool registry in createTeam instead of mutating the caller's config.lead.tools. Add doc comment for unused _maxTokens parameter in sliding-window strategy. * fix(ai): add error handling and retry for tool result POST The POST to /api/ai/agent?action=result had no error handling. If it failed, the agent loop would hang forever waiting for the tool result. Now retries once on failure and logs the error. * fix(ai): use lastActivity for session TTL and guard stream init P1: Add lastActivity timestamp to AgentSession, updated on every event and tool result. TTL cleanup now checks lastActivity instead of createdAt, preventing active long-running sessions from being killed. P1: Wrap ReadableStream construction in try-catch to ensure session cleanup if stream initialization fails. * chore: add docs/ to gitignore * fix(ai): update model lists and fix model search for providers - Update Anthropic models to include Claude 4.6 (Opus + Sonnet) - Update model placeholders: OpenAI→gpt-5.4, MiniMax→M2.7, Zhipu→glm-5, Kimi→kimi-k2.5, Xiaomi→mimo-v2-pro - Add hardcoded model lists for MiniMax and DouBao (no /models API) - Generalize ANTHROPIC_MODELS to BUILTIN_MODEL_LISTS lookup table - Fix provider-models proxy to handle { models: [...] } and array response formats in addition to OpenAI's { data: [...] } * docs: update CLAUDE.md and README files for new AI agent SDK and i18n support - Added new sections in CLAUDE.md detailing the AI agent SDK and its multi-provider capabilities. - Updated README files in multiple languages to include information about the built-in AI agent SDK and full interface localization in 15 languages. - Adjusted key technologies and scopes to reflect recent changes in the project structure and features. * docs(agent): add Agent Team web integration design spec Phase 3 design: model routing via Agent Team. Lead agent uses fast model for chat, designer member uses capable model for generation. SDK changes: source tracking on events, member_start/end events, auto team suffix. Web changes: team toggle + design model selector in settings, conditional createTeam in server endpoint. * fix(electron): fix Scoop/Homebrew tap auto-update in CI - Add pre_install to Scoop manifest to rename versioned exe to OpenPencil.exe - Add mkdir -p for Casks/ and bucket/ dirs in tap repos - Use curl -fSL to fail fast on HTTP errors instead of silent mode * docs(agent): add Agent Team web integration implementation plan 9 tasks: SDK event types → SSE tests → team source injection → server team endpoint → settings store → team UI → i18n → chat handler wiring → e2e verification * feat(agent): add source field and team events to AgentEvent type * test(agent): add SSE encoder/decoder tests for source and team events * feat(agent): inject source field and team events in agent-team * feat(ai): extend agent endpoint to support team mode with members * feat(ai): add teamEnabled and teamDesignModel to agent settings store * feat(ai): wire team mode in chat handlers with member events * feat(ai): add i18n keys for team settings (15 locales) * feat(ai): add Team section UI with design model selector * fix(agent): route resolveToolResult to correct agent in team mode Member tool calls (e.g. generate_design) were routed to leadAgent which didn't have them in its pending map. Added toolCallOwners map to track which agent (lead or member) issued each tool call and route resolveToolResult accordingly. * docs(agent): clarify resolveToolResult routing, member tools, and source handling * fix(agent): force delegation in team mode and add turnTimeout support Two fixes for team mode generation failures: 1. Remove generate_design from lead's tool registry in team mode, forcing the lead to delegate design work to the designer member 2. Add turnTimeout to TeamMemberConfig/TeamConfig and pass 5min timeout to member agents (generate_design needs it) * fix(ai): make team mode visually distinct in chat UI - Add source badge on tool call blocks (shows "designer" pill for member-initiated tool calls) - Pass evt.source to ToolCallBlockData - Use blockquote format for member_start/end events so team activity is clearly visible in the chat stream * fix(agent): scope designer tools, streamline delegation, add model hint 1. Designer member only gets generate_design + snapshot_layout (was: all tools, causing 7 wasteful batch_get calls) 2. Team suffix tells lead to delegate immediately without verbose planning text 3. UI shows amber tip when only 2 providers configured, suggesting a more capable model for design * fix(ai): clean up partial nodes on generate_design failure When generate_design fails midway, partial nodes were left on the canvas and rootInsertId was not set, allowing a retry that created a duplicate design. Now: 1. Set rootInsertId='generating' BEFORE calling generateDesign 2. Snapshot node IDs before generation 3. On failure, remove all new nodes and reset rootInsertId to null 4. Remove incorrect same-model warning from Team UI * fix(ai): show Team section with 1 enabled provider * refactor(ai): smart team mode — auto-enable when design model is set Remove manual Team toggle. Selecting a Design Model automatically enables team mode; "None (single agent)" disables it. Simpler UX: one dropdown replaces toggle + dropdown. Updated descriptions and removed obsolete teamTitle/teamSameModelWarning i18n keys. * fix(agent): properly serialize non-Error objects in error messages String(err) on plain objects produces "[object Object]". Changed to err instanceof Error ? err.message : JSON.stringify(err) for readable error messages in tool results and design generation failures. * refactor(ai): auto team mode using current chat model Remove Design Model dropdown from settings. Team mode is now fully automatic: the designer member always uses the same provider/model as the current chat selection. Zero configuration needed — the value is in role separation (different prompts + scoped tools), not model selection. * style(ai): use min/max height for settings dialog instead of fixed height * feat(ai): add Google Gemini to builtin provider presets Base URL: generativelanguage.googleapis.com/v1beta/openai (OpenAI compatible). Hardcoded model list: Gemini 2.5 Pro, 2.5 Flash, 2.0 Flash. API key placeholder: AIza... * feat(ai): update Gemini models to 3.x series --------- Co-authored-by: Fini <fini.yang@gmail.com> Co-authored-by: Kaiiiiiiiii <2761362118@qq.com> Co-authored-by: Kaiiiiiiiii <182183652+Smile232323@users.noreply.github.com> |
||
|
|
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>
|
||
|
|
370e51c0f7
|
V0.5.1 (#78)
* fix(docker): support multi-platform builds and fix monorepo paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization (#76) * fix(canvas): stabilize frame label size during zoom Draw frame labels in screen-space after the viewport transform restore, converting scene coords manually. Previously fontSize=12/zoom fed into Math.ceil caused integer-boundary jumps that made labels flicker during zoom. Also skip shadow rendering while actively zooming for smoother performance. * perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization - Add paraImageCache (SkImage, 128 MB LRU limit) keyed on the same key as paraCache - Use drawImageRect instead of drawParagraph on cache hit, skipping per-frame glyph shaping and rasterization - Fall back to direct drawParagraph only when off-screen surface creation (MakeSurface) fails - Extract _dpr getter to deduplicate device-pixel-ratio resolution logic across draw paths - Evict oldest entries when cache exceeds byte limit; delete SkImage on eviction and dispose() * feat(cli): introduce OpenPencil CLI for terminal control of the design tool - Added a new CLI application under `apps/cli` to manage OpenPencil from the terminal. - Implemented commands for app control (`start`, `stop`, `status`), document operations (`open`, `save`, `get`, `selection`), and design manipulation (`design`, `import`). - Enhanced documentation with usage instructions and platform support details. - Updated build scripts to include CLI compilation and publishing processes. - Introduced a new GitHub Actions workflow for publishing the CLI to npm. - Updated existing workflows to integrate CLI build steps and ensure proper versioning across packages. * docs: update README files to include CLI tool details and multi-platform code export - Added CLI section to README files in multiple languages, detailing commands for terminal control of the design tool. - Included instructions for global installation and usage examples for the CLI. - Expanded documentation on multi-platform code export capabilities from a single `.op` file to various frameworks. - Updated CLAUDE.md to reference the new CLI documentation and its integration with the design tool. * chore(bun.lock): update package dependencies to specific versions - Removed workspace references for several packages in the bun.lock file. - Updated dependencies for `@zseven-w/pen-core`, `@zseven-w/pen-types`, `@zseven-w/pen-codegen`, `@zseven-w/pen-figma`, and `@zseven-w/pen-renderer` to version `0.5.1-beta.1`. - Ensured consistency in dependency management across the project. * fix(docker): add missing CLI package.json to build context The Dockerfile was missing COPY for apps/cli/package.json, causing bun install --frozen-lockfile to fail because the CLI workspace dependency could not be resolved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add unpublish script and enhance CLI publish workflow - Introduced a new `unpublish` script to manage unpublishing of all @zseven-w packages from npm, with options for specific versions, all versions, or deprecation. - Updated the GitHub Actions workflow to check if a version is already published before proceeding with the publish step, ensuring better error handling and preventing conflicts. - Removed the fallback for npm publish commands to fail fast on errors, improving the reliability of the publishing process. * chore(bun.lock): update package versions and configuration - Bumped the configVersion from 0 to 1 in bun.lock. - Updated several package dependencies to their latest versions, including: - @anthropic-ai/claude-agent-sdk to 0.2.81 - @babel/helpers to 7.29.2 - @babel/parser to 7.29.2 - @babel/runtime to 7.29.2 - @csstools/color-helpers to 6.0.2 - @csstools/css-color-parser to 4.0.2 - Ensured consistency in dependency management across the project. * docs: restore Feishu group QR code in Chinese README * chore: update dependencies and add workspace references - Added "h3" package with version "^2.0.1-rc.18" to bun.lock, package.json, and apps/web/package.json. - Updated dependencies in multiple packages to use "workspace:*" for better management and consistency across the project. - Ensured all relevant packages are aligned with the latest workspace structure. * chore: update package versions in bun.lock and package.json - Updated several @tanstack packages to their latest versions, including: - @tanstack/react-devtools to 0.10.0 - @tanstack/react-router to 1.168.1 - @tanstack/react-router-devtools to 1.166.11 - @tanstack/react-router-ssr-query to 1.166.10 - @tanstack/react-start to 1.167.2 - @tanstack/router-plugin to 1.167.1 - Bumped @tanstack/devtools-vite to 0.6.0 in devDependencies. - Mocked 'paper' module in security tests to prevent crashes in jsdom environment. * chore: update CLI and MCP compile scripts to include package aliases - Enhanced the `mcp:compile` and `cli:compile` scripts in `package.json` and `apps/cli/package.json` to include additional package aliases for better module resolution. - This change improves the build process by ensuring that the correct paths are used for various dependencies. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com> Co-authored-by: Fini <fini.yang@gmail.com> |
||
|
|
b4d1d2a7bb
|
V0.5.1 (#77)
* fix(docker): support multi-platform builds and fix monorepo paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization (#76) * fix(canvas): stabilize frame label size during zoom Draw frame labels in screen-space after the viewport transform restore, converting scene coords manually. Previously fontSize=12/zoom fed into Math.ceil caused integer-boundary jumps that made labels flicker during zoom. Also skip shadow rendering while actively zooming for smoother performance. * perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization - Add paraImageCache (SkImage, 128 MB LRU limit) keyed on the same key as paraCache - Use drawImageRect instead of drawParagraph on cache hit, skipping per-frame glyph shaping and rasterization - Fall back to direct drawParagraph only when off-screen surface creation (MakeSurface) fails - Extract _dpr getter to deduplicate device-pixel-ratio resolution logic across draw paths - Evict oldest entries when cache exceeds byte limit; delete SkImage on eviction and dispose() * feat(cli): introduce OpenPencil CLI for terminal control of the design tool - Added a new CLI application under `apps/cli` to manage OpenPencil from the terminal. - Implemented commands for app control (`start`, `stop`, `status`), document operations (`open`, `save`, `get`, `selection`), and design manipulation (`design`, `import`). - Enhanced documentation with usage instructions and platform support details. - Updated build scripts to include CLI compilation and publishing processes. - Introduced a new GitHub Actions workflow for publishing the CLI to npm. - Updated existing workflows to integrate CLI build steps and ensure proper versioning across packages. * docs: update README files to include CLI tool details and multi-platform code export - Added CLI section to README files in multiple languages, detailing commands for terminal control of the design tool. - Included instructions for global installation and usage examples for the CLI. - Expanded documentation on multi-platform code export capabilities from a single `.op` file to various frameworks. - Updated CLAUDE.md to reference the new CLI documentation and its integration with the design tool. * chore(bun.lock): update package dependencies to specific versions - Removed workspace references for several packages in the bun.lock file. - Updated dependencies for `@zseven-w/pen-core`, `@zseven-w/pen-types`, `@zseven-w/pen-codegen`, `@zseven-w/pen-figma`, and `@zseven-w/pen-renderer` to version `0.5.1-beta.1`. - Ensured consistency in dependency management across the project. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com> |
||
|
|
283d17f3c2
|
V0.5.0 (#69)
* docs: add image search & generation design spec and implementation plan - Spec: dual-source image search (Openverse + Wikimedia), multi-provider image generation - Plan: 16 tasks covering types, server endpoints, settings UI, property panel, auto-search pipeline, MCP integration * feat(types): add image service types and imagePrompt to ImageNode * feat(server): add image service API key validation endpoint Adds POST /api/ai/image-service-test that validates credentials for openverse (client_credentials), openai/custom (Bearer + /v1/models), gemini (API key + v1beta/models), and replicate (Bearer + /v1/models). * feat(server): add multi-provider image generation endpoint * feat(server): add dual-source image search endpoint (Openverse + Wikimedia) POST /api/ai/image-search searches freely-licensed images via Openverse with automatic fallback to Wikimedia Commons on 429 rate-limit responses. Supports optional OAuth credentials for authenticated Openverse requests. * feat(store): add imageSearchStatuses to canvas store for runtime status tracking * feat(store): add image generation config and Openverse OAuth to agent settings * feat(editor): add Images tab to agent settings dialog Adds Popover primitive, ImagesPage component with Image Search (Openverse OAuth, test) and Image Generation (provider select, API key, model, base URL) sections, and wires them into the settings dialog sidebar. * feat(panels): add image search popover with Openverse/Wikimedia results grid * feat(panels): add image generate popover with multi-provider support * feat(panels): add Search and Generate buttons to image property section * feat(ai): update prompts to use imagePrompt instead of src for image nodes * feat(ai): add auto-search pipeline with Openverse/Wikimedia fallback * feat(ai): trigger auto image search after design generation completes * feat(mcp): implement G() operation for image search in batch design DSL Adds the G(parent, mode, prompt) operation to batch_design DSL that creates an image node and optionally fetches a real image URL via the image-search API when mode is "search". Converts executeLine to async to support the network call. * feat(mcp): auto-fill images after design refinement in layered pipeline * feat(ai): split imageSearchQuery and imagePrompt for search vs generation - ImageNode now has both imageSearchQuery (short keywords for search) and imagePrompt (long description for AI image generation) - AI prompts instruct LLM to generate both fields - Search pipeline and popovers use imageSearchQuery - Generate popover uses imagePrompt - Server-side simplifySearchQuery kept as fallback for manual input * fix(ai): hook auto image search into orchestrator completion path The primary generation path uses executeOrchestration -> insertStreamingNode, not applyNodesToCanvas/animateNodesToCanvas. Added scanAndFillImages call to orchestrator.ts after all sub-agents complete. Added debug logging. Removed plan/spec docs from git. * style(editor): remove provider names from image search ready status * fix(panels): clean up image gen error display and settings UI - Parse API error response to show concise message instead of raw JSON - Limit error text to 2 lines with line-clamp - Fix image gen test button sending wrong service name - Inline Image Search ready indicator with section header - Remove debug logging from image search pipeline * style(panels): allow up to 4 lines for image gen error message * fix: avoid 1-frame delay when resizing canvas (#60) rAF callbacks run before ResizeObserver in the same frame. Scheduling render in ResizeObserver via rAF defers it to the next frame. Invoke render() synchronously to leverage ResizeObserver's pre-paint timing and ensure immediate visual update. * feat(electron): implement desktop application structure and auto-updater - Introduced a new Electron desktop application with a structured directory for apps and packages. - Added auto-updater functionality to manage application updates seamlessly. - Created a comprehensive menu system for the desktop app. - Implemented logging capabilities for better debugging and error tracking. - Configured build settings for various platforms (macOS, Windows, Linux) using electron-builder. - Established TypeScript configurations for both the desktop and web applications. - Integrated Vite for the web application with support for React and Tailwind CSS. - Added icons and assets for the desktop application. * chore: update package versions to 0.5.0 across all package.json files and add pre-commit hook for version synchronization - Bumped version to 0.5.0 in package.json files for the main project, desktop app, web app, and all packages. - Introduced a pre-commit hook to automatically sync version numbers from branch names to all package.json files. * chore: update package versions to 0.5.0 and refactor Skia components - Bumped version to 0.5.0 in bun.lock and all relevant package.json files. - Refactored Skia components to utilize shared functionality from @zseven-w/pen-renderer, including image loading, hit testing, and path utilities. - Removed redundant code and improved modularity by re-exporting necessary functions and classes from the renderer package. * fix(panels): handle string fill values in icon nodes (#61) AI-generated icon/path nodes may have fill stored as a raw string instead of a PenFill[] array, causing "Cannot use 'in' operator" crash when selecting the node in the property panel. * chore: update documentation and project structure for monorepo organization - Added a new version bump command to synchronize all package.json files. - Updated the project structure to reflect a monorepo setup with organized workspaces for apps and packages. - Enhanced README files in multiple languages to include the new structure and commands. - Adjusted image paths in documentation to point to the correct locations for the desktop application. * feat(ai): incremental image search and improved image generation prompts - Refactor image search from batch post-generation to incremental queue: enqueueImageForSearch() triggers as each image node is inserted during streaming, so images appear progressively instead of all at once after generation completes. scanAndFillImages() remains as a final sweep. - Update imagePrompt guidance to avoid "transparent background" and similar phrases that many models cannot reliably produce. - Pass node width/height from image panel to generation endpoint for aspect-ratio-aware output (Gemini aspect ratio mapping, OpenAI size selection, Replicate dimensions). * feat(ai): multi-profile image generation config and cleaner error messages - Support multiple image generation profiles with active selection; first configured profile becomes default. Old single-config migrated automatically on hydrate. - Fix Gemini aspect ratio: move to generationConfig.imageConfig per API spec. - Extract clean error messages from provider JSON responses (Gemini error.message, OpenAI error.message, Replicate detail) instead of returning raw JSON text. - Remove destructive client-side regex that mangled error display. * feat(design-md): integrate design system panel and functionality - Added a new DesignMdPanel component for managing design system specifications. - Implemented functionality to toggle the design system panel in the editor layout and toolbar. - Introduced new commands for importing, exporting, and auto-generating design.md content. - Updated AI chat handlers to utilize design.md data for enhanced design generation. - Enhanced localization support for design system features across multiple languages. * perf(canvas): skip draw calls for nodes outside the viewport (#64) Add viewport culling in render() to avoid issuing CanvasKit draw calls for off-screen nodes. A 64px screen-space buffer is kept around the viewport edges so nearby nodes are pre-rendered, preventing pop-in during fast panning. * feat(utils): enhance Windows process spawning for CLI scripts - Updated the buildSpawnClaudeCodeProcess function to handle .cmd and .ps1 scripts appropriately. - Implemented PowerShell invocation for .ps1 files and ensured safe defaults for .cmd and .exe files. - Improved handling of command execution to avoid limitations of cmd.exe. * feat(ai): add support for Gemini CLI integration - Extended the AI provider options to include 'gemini' across various components and APIs. - Implemented functions for generating, validating, and connecting to the Gemini CLI. - Added Gemini-specific error handling and model fetching logic. - Updated UI components to display Gemini as a selectable provider with appropriate icons and labels. - Enhanced localization support for Gemini-related features in multiple languages. * feat(editor): warn before closing with unsaved changes Intercept window/tab close when isDirty is true: - Electron: native dialog with Save / Don't Save / Cancel - Web: beforeunload handler + confirm on New/Open actions - i18n: close-confirm strings for all 15 locales * feat(ipc): extract IPC handlers to a dedicated module - Moved IPC dialog handling and updater functions from main.ts to ipc-handlers.ts for better organization and maintainability. - Implemented file open/save dialogs, theme setting, and preferences management through IPC. - Enhanced updater functionality with state management and auto-update settings. - Improved code structure by separating concerns, making it easier to manage IPC-related logic. * feat(docs): update CLAUDE documentation and add new files for desktop and web apps - Enhanced CLAUDE.md with detailed module documentation references for `packages/` and `apps/`. - Updated `pen-core` description to include clone utilities in `pen-core`. - Added new documentation files for the desktop and web applications, outlining their structure, components, and functionalities. - Included IPC handler details in the desktop app documentation for better clarity on file dialogs and theme synchronization. * feat(docker): add Gemini CLI support and update documentation - Introduced a new Docker build stage for the Gemini CLI, allowing users to install and run it. - Updated the Dockerfile to include the installation of the Gemini CLI alongside existing CLI tools. - Enhanced README files in multiple languages to document the new `openpencil-gemini` image variant. - Added Gemini CLI connection instructions to the main README for better user guidance. * feat(docs): add Gemini CLI connection instructions to multiple language READMEs - Updated README files in German, Spanish, French, Hindi, Indonesian, Japanese, Korean, Portuguese, Russian, Thai, Turkish, Vietnamese, and both Traditional and Simplified Chinese to include connection instructions for the Gemini CLI. - Enhanced documentation to improve user guidance for connecting the Gemini CLI in agent settings. * perf(renderer): replace count-based text cache limits with memory-based eviction (#66) previous limits (PARA_CACHE_MAX=200, TEXT_CACHE_MAX=300) were too small for scenes with many nodes, causing constant cache churn and paragraph rebuilds every frame, which dropped FPS significantly during canvas pan. - switch to byte-budget limits (64 MB paragraphs, 256 MB bitmaps) - bitmap size measured exactly as cw*ch*4; paragraph WASM heap estimated as content.length*64+4096 - eviction uses Map insertion order (FIFO) instead of a separate string[] array, replacing O(n) array.shift() with O(1) Map.entries().next() - evict before insert so the budget check includes the incoming entry * feat(docker): update Dockerfile to include additional package.json files - Added package.json files for multiple packages (pen-types, pen-core, pen-codegen, pen-figma, pen-renderer, pen-sdk) and apps (web, desktop) to the Docker build context. - Ensured all necessary dependencies are included for a complete build process. * refactor(docker): update Dockerfile to use new output directory structure - Changed the output directory from `/.output` to `/out/web` for all build stages in the Dockerfile. - Updated CMD instructions to reflect the new path for the server entry point. - Ensured consistency across all CLI variants for improved maintainability. * fix(main): update server entry point paths for development and production - Changed the development server entry point path from `.output/server/index.mjs` to `out/web/server/index.mjs`. - Updated the production comment to reflect the new output directory structure for consistency. --------- Co-authored-by: Fini <fini.yang@gmail.com> Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com> |
||
|
|
03d4433693
|
V0.5.0 (#67)
* docs: add image search & generation design spec and implementation plan - Spec: dual-source image search (Openverse + Wikimedia), multi-provider image generation - Plan: 16 tasks covering types, server endpoints, settings UI, property panel, auto-search pipeline, MCP integration * feat(types): add image service types and imagePrompt to ImageNode * feat(server): add image service API key validation endpoint Adds POST /api/ai/image-service-test that validates credentials for openverse (client_credentials), openai/custom (Bearer + /v1/models), gemini (API key + v1beta/models), and replicate (Bearer + /v1/models). * feat(server): add multi-provider image generation endpoint * feat(server): add dual-source image search endpoint (Openverse + Wikimedia) POST /api/ai/image-search searches freely-licensed images via Openverse with automatic fallback to Wikimedia Commons on 429 rate-limit responses. Supports optional OAuth credentials for authenticated Openverse requests. * feat(store): add imageSearchStatuses to canvas store for runtime status tracking * feat(store): add image generation config and Openverse OAuth to agent settings * feat(editor): add Images tab to agent settings dialog Adds Popover primitive, ImagesPage component with Image Search (Openverse OAuth, test) and Image Generation (provider select, API key, model, base URL) sections, and wires them into the settings dialog sidebar. * feat(panels): add image search popover with Openverse/Wikimedia results grid * feat(panels): add image generate popover with multi-provider support * feat(panels): add Search and Generate buttons to image property section * feat(ai): update prompts to use imagePrompt instead of src for image nodes * feat(ai): add auto-search pipeline with Openverse/Wikimedia fallback * feat(ai): trigger auto image search after design generation completes * feat(mcp): implement G() operation for image search in batch design DSL Adds the G(parent, mode, prompt) operation to batch_design DSL that creates an image node and optionally fetches a real image URL via the image-search API when mode is "search". Converts executeLine to async to support the network call. * feat(mcp): auto-fill images after design refinement in layered pipeline * feat(ai): split imageSearchQuery and imagePrompt for search vs generation - ImageNode now has both imageSearchQuery (short keywords for search) and imagePrompt (long description for AI image generation) - AI prompts instruct LLM to generate both fields - Search pipeline and popovers use imageSearchQuery - Generate popover uses imagePrompt - Server-side simplifySearchQuery kept as fallback for manual input * fix(ai): hook auto image search into orchestrator completion path The primary generation path uses executeOrchestration -> insertStreamingNode, not applyNodesToCanvas/animateNodesToCanvas. Added scanAndFillImages call to orchestrator.ts after all sub-agents complete. Added debug logging. Removed plan/spec docs from git. * style(editor): remove provider names from image search ready status * fix(panels): clean up image gen error display and settings UI - Parse API error response to show concise message instead of raw JSON - Limit error text to 2 lines with line-clamp - Fix image gen test button sending wrong service name - Inline Image Search ready indicator with section header - Remove debug logging from image search pipeline * style(panels): allow up to 4 lines for image gen error message * fix: avoid 1-frame delay when resizing canvas (#60) rAF callbacks run before ResizeObserver in the same frame. Scheduling render in ResizeObserver via rAF defers it to the next frame. Invoke render() synchronously to leverage ResizeObserver's pre-paint timing and ensure immediate visual update. * feat(electron): implement desktop application structure and auto-updater - Introduced a new Electron desktop application with a structured directory for apps and packages. - Added auto-updater functionality to manage application updates seamlessly. - Created a comprehensive menu system for the desktop app. - Implemented logging capabilities for better debugging and error tracking. - Configured build settings for various platforms (macOS, Windows, Linux) using electron-builder. - Established TypeScript configurations for both the desktop and web applications. - Integrated Vite for the web application with support for React and Tailwind CSS. - Added icons and assets for the desktop application. * chore: update package versions to 0.5.0 across all package.json files and add pre-commit hook for version synchronization - Bumped version to 0.5.0 in package.json files for the main project, desktop app, web app, and all packages. - Introduced a pre-commit hook to automatically sync version numbers from branch names to all package.json files. * chore: update package versions to 0.5.0 and refactor Skia components - Bumped version to 0.5.0 in bun.lock and all relevant package.json files. - Refactored Skia components to utilize shared functionality from @zseven-w/pen-renderer, including image loading, hit testing, and path utilities. - Removed redundant code and improved modularity by re-exporting necessary functions and classes from the renderer package. * fix(panels): handle string fill values in icon nodes (#61) AI-generated icon/path nodes may have fill stored as a raw string instead of a PenFill[] array, causing "Cannot use 'in' operator" crash when selecting the node in the property panel. * chore: update documentation and project structure for monorepo organization - Added a new version bump command to synchronize all package.json files. - Updated the project structure to reflect a monorepo setup with organized workspaces for apps and packages. - Enhanced README files in multiple languages to include the new structure and commands. - Adjusted image paths in documentation to point to the correct locations for the desktop application. * feat(ai): incremental image search and improved image generation prompts - Refactor image search from batch post-generation to incremental queue: enqueueImageForSearch() triggers as each image node is inserted during streaming, so images appear progressively instead of all at once after generation completes. scanAndFillImages() remains as a final sweep. - Update imagePrompt guidance to avoid "transparent background" and similar phrases that many models cannot reliably produce. - Pass node width/height from image panel to generation endpoint for aspect-ratio-aware output (Gemini aspect ratio mapping, OpenAI size selection, Replicate dimensions). * feat(ai): multi-profile image generation config and cleaner error messages - Support multiple image generation profiles with active selection; first configured profile becomes default. Old single-config migrated automatically on hydrate. - Fix Gemini aspect ratio: move to generationConfig.imageConfig per API spec. - Extract clean error messages from provider JSON responses (Gemini error.message, OpenAI error.message, Replicate detail) instead of returning raw JSON text. - Remove destructive client-side regex that mangled error display. * feat(design-md): integrate design system panel and functionality - Added a new DesignMdPanel component for managing design system specifications. - Implemented functionality to toggle the design system panel in the editor layout and toolbar. - Introduced new commands for importing, exporting, and auto-generating design.md content. - Updated AI chat handlers to utilize design.md data for enhanced design generation. - Enhanced localization support for design system features across multiple languages. * perf(canvas): skip draw calls for nodes outside the viewport (#64) Add viewport culling in render() to avoid issuing CanvasKit draw calls for off-screen nodes. A 64px screen-space buffer is kept around the viewport edges so nearby nodes are pre-rendered, preventing pop-in during fast panning. * feat(utils): enhance Windows process spawning for CLI scripts - Updated the buildSpawnClaudeCodeProcess function to handle .cmd and .ps1 scripts appropriately. - Implemented PowerShell invocation for .ps1 files and ensured safe defaults for .cmd and .exe files. - Improved handling of command execution to avoid limitations of cmd.exe. * feat(ai): add support for Gemini CLI integration - Extended the AI provider options to include 'gemini' across various components and APIs. - Implemented functions for generating, validating, and connecting to the Gemini CLI. - Added Gemini-specific error handling and model fetching logic. - Updated UI components to display Gemini as a selectable provider with appropriate icons and labels. - Enhanced localization support for Gemini-related features in multiple languages. * feat(editor): warn before closing with unsaved changes Intercept window/tab close when isDirty is true: - Electron: native dialog with Save / Don't Save / Cancel - Web: beforeunload handler + confirm on New/Open actions - i18n: close-confirm strings for all 15 locales * feat(ipc): extract IPC handlers to a dedicated module - Moved IPC dialog handling and updater functions from main.ts to ipc-handlers.ts for better organization and maintainability. - Implemented file open/save dialogs, theme setting, and preferences management through IPC. - Enhanced updater functionality with state management and auto-update settings. - Improved code structure by separating concerns, making it easier to manage IPC-related logic. * feat(docs): update CLAUDE documentation and add new files for desktop and web apps - Enhanced CLAUDE.md with detailed module documentation references for `packages/` and `apps/`. - Updated `pen-core` description to include clone utilities in `pen-core`. - Added new documentation files for the desktop and web applications, outlining their structure, components, and functionalities. - Included IPC handler details in the desktop app documentation for better clarity on file dialogs and theme synchronization. * feat(docker): add Gemini CLI support and update documentation - Introduced a new Docker build stage for the Gemini CLI, allowing users to install and run it. - Updated the Dockerfile to include the installation of the Gemini CLI alongside existing CLI tools. - Enhanced README files in multiple languages to document the new `openpencil-gemini` image variant. - Added Gemini CLI connection instructions to the main README for better user guidance. * feat(docs): add Gemini CLI connection instructions to multiple language READMEs - Updated README files in German, Spanish, French, Hindi, Indonesian, Japanese, Korean, Portuguese, Russian, Thai, Turkish, Vietnamese, and both Traditional and Simplified Chinese to include connection instructions for the Gemini CLI. - Enhanced documentation to improve user guidance for connecting the Gemini CLI in agent settings. * perf(renderer): replace count-based text cache limits with memory-based eviction (#66) previous limits (PARA_CACHE_MAX=200, TEXT_CACHE_MAX=300) were too small for scenes with many nodes, causing constant cache churn and paragraph rebuilds every frame, which dropped FPS significantly during canvas pan. - switch to byte-budget limits (64 MB paragraphs, 256 MB bitmaps) - bitmap size measured exactly as cw*ch*4; paragraph WASM heap estimated as content.length*64+4096 - eviction uses Map insertion order (FIFO) instead of a separate string[] array, replacing O(n) array.shift() with O(1) Map.entries().next() - evict before insert so the budget check includes the incoming entry --------- Co-authored-by: Fini <fini.yang@gmail.com> Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com> |