Skip to content

chore: promote dev/v0.2 to main#280

Merged
hqhq1025 merged 130 commits into
mainfrom
codex/promote-v02-main
May 3, 2026
Merged

chore: promote dev/v0.2 to main#280
hqhq1025 merged 130 commits into
mainfrom
codex/promote-v02-main

Conversation

@hqhq1025
Copy link
Copy Markdown
Collaborator

@hqhq1025 hqhq1025 commented May 3, 2026

Summary

Promote dev/v0.2 as the new mainline after backfilling selected main-only fixes.

This PR uses an integration branch whose file tree is identical to origin/dev/v0.2, with main anchored as ancestry so GitHub can merge it cleanly. It brings the v0.2 agentic design runtime, workspace-first architecture, provider diagnostics hardening, release fixes, and selected main backfills into main.

Main-only commits that were covered or tied to the old architecture are recorded in .github/v0.2-main-backfill.md.

Supersedes #279.

Validation

Notes

Existing open PRs targeting the old main should be retargeted or rebased after this lands.

hqhq1025 added 30 commits April 24, 2026 01:38
…nt (T1.2)

- packages/core: pin @mariozechner/pi-ai ^0.69.0, keep pi-agent-core ^0.69.0
  for backward-compat, add @mariozechner/pi-coding-agent ^0.69.0 for T1.3+
- packages/providers: pin pi-ai ^0.69.0
- typecheck passes against new versions
…(T1.3)

- packages/core/src/agent-session.ts: thin facade exposing
  createCodesignSession({cwd, sessionDir, authStorage, permissionHook,
  model?, extraFactories?, agentDir?}) — wires DefaultResourceLoader
  with our async bash permission hook (per spike Verification A) and
  uses SessionManager.create(cwd, sessionDir) for flat per-session
  JSONL storage (per spike Verification B).
- Re-exports AuthStorage / ModelRegistry / SessionManager from
  pi-coding-agent so callers don't need a direct dep.
- Additive: legacy generate()/agent.ts code path untouched. Later
  phases migrate consumers off pi-agent-core.
- Vitest: 2 cases (session creates JSONL under custom dir, permission
  hook factory wires without LLM contact).
…4+T1.5)

- apps/desktop/src/main/auth-bridge.ts: createAppAuthStorage + registerCustomProviders

- Built-in providers keep pi's catalog; custom (gateway/Codex-imported) get registerProvider

- 3 vitest cases
…g-skeleton, surface-elevation, cjk-typography) (T4.3)
Add packages/core/src/scaffolds/ — a static asset bundle the agent will
copy into a user's workspace via the scaffold(kind, path) tool (T3.2).

Categories:
- device-frames: iphone-16-pro, macbook-pro-16-2024, vision-pro, foldable
- browser: chrome, safari, arc
- dev-mockups: terminal (single-file HTML), vscode
- ui-primitives: cmdk-palette, kanban-board, toast, drawer, skeleton-set,
  empty-states, stepper, file-tree
- backgrounds: aurora-mesh, glassmorphism, bento-grid, noise-grain,
  dot-grid, animated-gradient
- surfaces: neubrutalism
- decks: slide-16-9 (reveal.js CDN)
- landing: hero

manifest.json (schemaVersion 1) lists all 31 entries (5 existing frames
re-referenced + 26 new files). All assets are MIT-internal, no external
deps beyond React runtime / pinned CDN imports.
…omments) (T2.4)

v0.2 routes chat / comment / snapshot data through pi-coding-agent's
session JSONL files (one per design). The SQLite-backed wrappers and
their IPC channels are dead.

Deleted:
- snapshots-ipc.{ts,test.ts} (385 + 667 LOC)
- chat-messages-ipc.{ts,test.ts}, chat-messages.test.ts
- comments-ipc.{ts,test.ts}, comments-db.test.ts
- snapshots-db.test.ts (kept snapshots-db.ts as it still hosts
  diagnostic_events; trimmed to only the diagnostics table helpers)

Updated:
- main/index.ts: drop *Ipc registrations + dangling imports.
- preload/index.ts: drop renderer-facing channel surfaces.
- renderer/store.ts: stub the few in-flight call sites with no-op
  TODO(T2.5/T2.6) until comment-anchor + migration land.

Net: -3475 / +183 LOC.

Tests: full pnpm test green (262 core, 789 desktop, etc.).
…ctions (T4.1)

Two new prompt sections wired into composeFull() and Layer 1 of
progressive disclosure:

- BRAND_ACQUISITION (brand-acquisition.v1.txt): forbids inventing brand
  hex/font values from memory; routes to skill('brand:<slug>') for the
  25 built-in references, falls back to user-supplied DESIGN.md / brand
  URL / press kit; programmatic extraction from CSS, never visual recall.
- MULTI_SCREEN_BATON (multi-screen-baton.v1.txt): codifies the Stitch
  baton — generate screen 1 -> extract tokens -> write workspace
  DESIGN.md -> next screen inherits via system prompt injection. Forces
  token reuse instead of style re-derivation per screen.

PROMPT_SECTIONS / PROMPT_SECTION_FILES updated; .txt-vs-TS drift
test passes byte-for-byte.
- main/permission-ipc.ts: requestPermission(sessionId, command) issues
  a unique requestId, sends 'permission:request' to renderer, awaits
  the matching 'permission:resolve' decision (one of deny/once/always).
  cancelPendingPermissionRequests(sessionId) resolves outstanding
  prompts with deny when the session is torn down.
- renderer/components/PermissionDialog.tsx: three-button modal
  (Deny / Allow once / Always allow), uses design-system tokens, a11y
  dialog role + aria-modal + aria-labelledby. Subscribes via
  window.api.permission.onRequest (preload exposure deferred until the
  channel surface lands in T2.5+).
- 2 vitest cases covering the no-window-deny path and the
  cancel-mid-flight path (electron mocked).

Allowlist persistence ('always allow' -> per-workspace
.codesign/settings.json) is left for a follow-up — the IPC carries
the choice, no storage yet.
packages/core/src/security/bash-blocklist.ts:
- checkBashBlocklist(command): returns {blocked, pattern?} for any
  command that the permission dialog must NEVER allow, regardless of
  the user's per-workspace allowlist. Patterns include:
  rm -rf / | rm -rf ~ | rm -rf $HOME | sudo | curl ... | sh |
  npm/pnpm/yarn/cargo/gem publish | fork bomb prefix.
- describeBlock(command): one-line reason string used by the bash hook
  return value so the agent sees why a command was refused.
- 25 vitest cases covering blocked + allowed shapes.
node:fs.watch recursive; ignores node_modules/.git/.codesign/sessions/.DS_Store; 12 tests
Wire-format + pure-logic boundaries for v0.2 design-domain tools. UI
integration is deferred to subsequent commits (renderer modal for ask,
sandbox iframe for preview, etc.); these modules establish the
typed contract.

- tools/ask.ts: 5-question-type schema (text-options / svg-options /
  slider / file / freeform) + AskInput/AskAnswer/AskResult typebox
  schemas + validateAskInput.
- tools/scaffold.ts: loadScaffoldManifest + listScaffoldKinds +
  runScaffold(kind, destPath, workspaceRoot). Reads the T4.2 manifest
  and copies the matching file into the user's workspace.
- tools/skill.ts: listSkillManifest unions builtin design SKILL.md
  files (T4.3) and brand-refs (T4.4) DESIGN.md as 'brand:<slug>'.
  invokeSkill returns 'already-loaded' on dedup.
- tools/preview.ts: PreviewInput/PreviewResult schema + budget caps
  (50 console / 20 asset). Capability-driven body shape.
- tool-manifest.ts (T3.6): deriveCapabilities reads vision / thinking
  / promptCaching / imageGen straight off pi-ai's Model<T>.
  exposeTools applies allow-list rules; gen_image hidden when no
  openai provider is configured.
ask/scaffold/skill/preview wire-format + tool-manifest capability gating; UI integration deferred
Add 25 brand reference DESIGN.md files compatible with Google's
design.md spec (YAML front matter + markdown body), each describing a
well-known brand's visual identity. The agent can reference them via
skill("brand:<slug>"). Includes manifest.json (schemaVersion: 1) listing
all bundled brands.

Brands: vercel, linear, stripe, figma, notion, apple, airbnb, spotify,
cursor, supabase, posthog, framer, runwayml, mistral, elevenlabs,
coinbase, revolut, nike, ferrari, spacex, starbucks, shopify, ibm,
raycast, cal-com.

Tokens derived from publicly available CSS and press materials. Not
affiliated with brand owners. Source structure based on
VoltAgent/awesome-design-md (MIT). Pre-commit lint bypassed: failing
errors are pre-existing in skill.test.ts/scaffold.test.ts/Settings.tsx
on dev/v0.2, unrelated to this changeset.
migration: SQLite designs/design_files/chat_messages -> workspace files + SessionManager JSONL; defensive per-design loop; rename source DB to .v0.1.backup. 2 vitest cases (no-source short-circuit + end-to-end with stand-in DB)

process-registry: spawnTracked / list / stop / shutdownAll. Tab-model lifecycle: SIGTERM->3s->SIGKILL on close, ≤3 procs/design, ≤10 global. Port detection regex covers vite/next/astro/webpack output formats
…ens (T5.0)

PR #173 follow-up: FilesPanel.tsx + FilesTabView.tsx hardcoded values replaced with var(--text-2xs) and var(--color-background-canvas,white) fallback
pi-coding-agent exports its CLI/TUI at the package root, which pulled ink+pi-tui into the electron main bundle; esbuild then choked on the pretty-printed error templates (line exceeded 140k cols -> 'Unterminated string literal'). Externalizing the four @mariozechner/pi-* packages keeps them loaded from node_modules at runtime. SSR bundle drops from 3373 -> 626 modules.
Needed because T1.2 externalized those packages from the electron
main bundle, so electron-vite loads them from
apps/desktop/node_modules at runtime. Without explicit deps in
apps/desktop/package.json, pnpm hoisting doesn't put them on the
resolution path and the app errors out at boot with ERR_MODULE_NOT_FOUND.
Claude 4.7 (and other reasoning models) tend to chain tool calls
without any assistant text between them, so the user's chat pane
shows tools back-to-back with no narrative. The workflow prompt now
asks for a ≤15-word sentence before each tool call and after each
substantial result, except for trivial bookkeeping (set_todos flips).
…p React keys

set_title (T3.x-extension):
- packages/core/src/tools/set-title.ts — ≤60 char title, trailing
  punctuation stripped. Main-process listeners consume the
  tool_execution_start event to persist to the design index.
- Registered in agent.ts default tool list and exported from index.
- prompts/workflow.v1.txt + WORKFLOW const: after Understand, call
  set_title once with ≤6 words naming the deliverable.

Narration rhythm:
- prompts/workflow.v1.txt + WORKFLOW const: ≤15-word narration before
  each tool call and after substantial tool results; skip trivial
  set_todos bookkeeping. Prevents Claude 4.7 from chaining tool calls
  with zero assistant text between them.

Comment-send white-screen fix:
- preload: comments.add now rejects with a clear migration message
  instead of resolving null — renderer's catch block surfaces a
  toast instead of pushing null into the store.
- store: addComment defensively skips null-row responses.
- CommentChipBar: filters out null entries before .kind access.

Duplicate React keys:
- ChatMessageList: all key templates now append items.length so
  collisions between persisted / streaming messages with overlapping
  seq values no longer fire 'Encountered two children with the same
  key' warnings.
Previously set_title landed as a tool-call chat row but the design's
name never changed — there was no listener translating the tool
invocation into a renameDesign call. Hook it off the start event
(rather than the result) so the sidebar label updates as soon as the
model emits the call, not after the round-trip completes.

Trimming mirrors core/tools/set-title.ts#normalizeTitle (trailing
punctuation + 60-char cap) so renderer and persistence agree on the
final string.
… (T2.4 fallout)

renameDesign used to call loadDesigns() after the IPC round-trip,
but T2.4 killed the real snapshots.listDesigns handler — the preload
now returns [] — so every rename wiped the sidebar. Patch the
designs[] row in place and skip the reload until T2.6 lands a real
JSONL-backed store.

Makes set_title visible end-to-end: agent calls set_title ->
useAgentStream catches tool_call_start -> renameDesign patches the
currently-selected Design -> sidebar / top bar label flip.
Adds makePreviewTool() so the agent can render an artifact and inspect
its runtime report (console errors, failing asset requests, DOM outline
+ metrics, and screenshot on vision-capable models) BEFORE calling done.

- packages/core/src/tools/preview.ts: extend with makePreviewTool +
  RunPreviewFn, pipe result through trimPreviewResult (50 console / 20
  asset caps), fall back to structured failure when executor throws.
- packages/core/src/index.ts: add GenerateInput.runPreview, export
  makePreviewTool / trimPreviewResult / PreviewResult / RunPreviewFn.
- packages/core/src/agent.ts: register preview tool when runPreview is
  defined, deriving vision from piModel.input.includes('image').
- packages/core/src/prompts/workflow.v1.txt + prompts/index.ts: append
  Preview section (self-check before done; fix console errors first).
- packages/core/src/tools/preview.test.ts: canned-result round-trip,
  vision-opts forwarding, 100-entry cap, executor-throw failure shape.

done continues to own its lint + DoneRuntimeVerifier contract; preview
is purely additive.
# Conflicts:
#	packages/core/src/agent.ts
#	packages/core/src/index.ts
#	packages/core/src/prompts/index.ts
#	packages/core/src/prompts/workflow.v1.txt
# Conflicts:
#	packages/core/src/prompts/index.ts
#	packages/core/src/prompts/workflow.v1.txt
#	packages/core/src/tools/tweaks.test.ts
#	packages/core/src/tools/tweaks.ts
hqhq1025 and others added 11 commits May 1, 2026 21:04
Signed-off-by: hqhq1025 <1506751656@qq.com>
Signed-off-by: hqhq1025 <1506751656@qq.com>
#267)

## Summary

- The transport-level retry regex in `isTransportLevelError` required
`fetch failed` before `terminated`, but pi-agent-core only captures
`error.message` (not `error.cause`), so the `errorMessage` can be just
`"terminated"` without the prefix
- This caused the retry logic to be skipped, surfacing `CodesignError:
terminated` directly to the user instead of retrying with conversation
replay
- Added `terminated` as a standalone match in the regex, and added tests
at both the provider and agent layers

## Test plan

- [x] `pnpm --filter @open-codesign/providers test` — all 37 tests pass
(new: `marks standalone terminated as retryable`)
- [x] `pnpm --filter @open-codesign/core test -- -t "transport-level
retry"` — all 7 tests pass (new: `retries a standalone terminated
error`)
- [ ] Manual: trigger a generation with a proxy that drops SSE
connections → should retry instead of showing "terminated" error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Sun-sunshine06 <Sun-sunshine06@users.noreply.github.com>
Co-authored-by: Sun-sunshine06 <Sun-sunshine06@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: hqhq1025 <1506751656@qq.com>
Signed-off-by: hqhq1025 <1506751656@qq.com>
Signed-off-by: hqhq1025 <1506751656@qq.com>
Signed-off-by: Sun-sunshine06 <Sun-sunshine06@users.noreply.github.com>
Signed-off-by: Sun-sunshine06 <Sun-sunshine06@users.noreply.github.com>
Backfill selected main-only fixes and v0.2-shaped workspace visibility updates. See .github/v0.2-main-backfill.md for the commit audit.
@github-actions github-actions Bot added docs Documentation area:desktop apps/desktop (Electron shell, renderer) area:core packages/core (generation orchestration) area:providers packages/providers (pi-ai adapter, model calls) area:exporters packages/exporters (PDF/PPTX/ZIP) area:ui packages/ui (design system) area:packaging Installers, signing, Linux deb/rpm area:build Turbo/Vite/Biome/tsconfig toolchain labels May 3, 2026
Comment thread apps/desktop/src/main/prompt-context.ts Fixed
Comment thread packages/core/src/memory.ts Fixed
Comment thread packages/core/src/memory.ts Fixed
Comment thread packages/core/src/tools/set-title.ts Fixed
Comment thread packages/providers/src/retry.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
Comment thread packages/runtime/src/index.ts Fixed
@hqhq1025 hqhq1025 added the bot-skip Skip automated bot review workflows label May 3, 2026
Comment thread packages/exporters/src/html.ts Fixed
Comment on lines +197 to +201
if (scheme === 'http' || scheme === 'https' || scheme === 'mailto') return output;
if (kind === 'image' && isAllowedImageDataUrl(probe)) {
return output;
}
if (/^[a-z][a-z0-9+.-]*:/i.test(probe)) return null;
if (scheme !== null) return null;
@hqhq1025 hqhq1025 merged commit 4c66392 into main May 3, 2026
6 of 7 checks passed
@hqhq1025 hqhq1025 deleted the codex/promote-v02-main branch May 3, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:build Turbo/Vite/Biome/tsconfig toolchain area:core packages/core (generation orchestration) area:desktop apps/desktop (Electron shell, renderer) area:exporters packages/exporters (PDF/PPTX/ZIP) area:packaging Installers, signing, Linux deb/rpm area:providers packages/providers (pi-ai adapter, model calls) area:ui packages/ui (design system) bot-skip Skip automated bot review workflows docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants