feat(core,exporters,desktop): end-to-end first demo + HTML export#4
Merged
feat(core,exporters,desktop): end-to-end first demo + HTML export#4
Conversation
Wires the full prompt → artifact → preview → export loop so the README's
"first demo" actually produces a design when an API key is provided.
- packages/templates: externalize the design-generator system prompt as
SYSTEM_PROMPTS.designGenerator with a sibling design-generator.md for
reviewable diffs. Replaces the inline string previously hard-coded in
packages/core. Prompt embeds the research-backed Claude Design rules
(single artifact, Tailwind CDN, semantic HTML, CSS variable tokens,
WCAG AA, no lorem ipsum).
- packages/core: pull SYSTEM_PROMPTS.designGenerator from templates,
collapse the duplicated artifact-extraction loop into a `collect()`
helper, add generate.test.ts (mocks the providers boundary, asserts
empty-prompt error, artifact extraction shape, system-prompt wiring).
- packages/exporters: real exportHtml() that ensures a doctype, injects
the Tailwind CDN tag if missing, stamps a generator meta/banner, and
pretty-prints. PDF / PPTX / ZIP each throw CodesignError with code
EXPORTER_NOT_READY ("ships in Phase 2") — no silent fallbacks
(PRINCIPLES §10). Top-level exportArtifact() dispatches lazily so
unused formats stay out of the cold-start bundle (PRINCIPLES §1).
- apps/desktop: codesign:export IPC backed by Electron dialog
showSaveDialog, validates payload via CodesignError, propagates
Phase-2 errors loudly. Preload exposes window.codesign.export().
Store gains exportActive(format) + a toast slot. PreviewToolbar
renders an Export dropdown with HTML enabled and PDF/PPTX/ZIP
disabled with "Coming in Phase 2" tooltips.
- TIER 1 / dev-only fallback: store reads VITE_OPEN_CODESIGN_DEV_KEY
so the demo runs before wt/onboarding lands real keychain plumbing.
Marked clearly for removal in the integration commit.
- examples/calm-spaces: README documents the demo + expected behaviour
+ intentional loud failure modes.
No new third-party dependencies. All UI uses var(--color-*) tokens.
Acceptance test (manual):
VITE_OPEN_CODESIGN_DEV_KEY=sk-ant-... \
pnpm --filter @open-codesign/desktop dev
→ click "Calm Spaces meditation app" → Send → iframe renders
→ Export → HTML → /tmp/out.html → open in browser
→ Export → PDF → toast "PDF export ships in Phase 2"
Signed-off-by: Haoqing Wang <1506751656@qq.com>
hqhq1025
added a commit
that referenced
this pull request
Apr 18, 2026
…rate uiux iterations The squash-merge of #4 (first-demo) accidentally pushed conflict markers in main/index.ts, preload/index.ts, App.tsx, store.ts. This commit: - Properly merges onboarding IPC + exporter IPC registration in main/index.ts - Cleans preload/index.ts (one bogus marker) - Cleans App.tsx (Onboarding gate + PreviewToolbar both retained) - Adds Wordmark component + token additions from the in-flight UIUX iterator - Bumps onboarding/Welcome polish in flight All checks green: pnpm install, pnpm -r typecheck pass. Signed-off-by: hqhq1025 <1506751656@qq.com>
hqhq1025
added a commit
that referenced
this pull request
Apr 22, 2026
…opencode banner) Three round-4 items closed at once — they all touch the import UX but are small, so one commit keeps the diff readable: 1. (#3) parseDotEnv malformed-line warnings. The old parser silently dropped `GEMINI_API_KEY value` (space instead of `=`) with zero signal. Split into parseDotEnvLines (returns {vars, skipped}) + parseDotEnv (thin wrapper preserving the old signature). In readGeminiCliConfig, scan each file's skipped lines for anything that LOOKS like a GEMINI_API_KEY declaration but is missing `=` and surface a targeted warning — works even when the key eventually resolves from shell env, so the user knows their .env line is broken. 2. (#4) detectChatgptSubscription test coverage. Export the function and accept an optional `authPath` test-seam param. Four tests cover: chatgpt auth_mode → true, other auth_mode → false, ENOENT → false (silent), malformed JSON → false (loud, goes through the new logger call from the prior commit). 3. (#5) opencode banner shows provider names, not just a count. Before: "OpenCode config detected — import 4 providers?" left the user guessing WHICH four. Now: "OpenCode detected — import 4 providers (OpenCode · Anthropic, OpenCode · OpenAI, OpenCode · Google +1 more)?". Providers ride along in the banner state as `providerLabels: string[]`. No functional regression; 779 → 787 desktop tests (+8). Signed-off-by: hqhq1025 <1506751656@qq.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Make the README's "first demo" actually work end-to-end IF the user provides
an API key:
Files in
New
packages/templates/src/system/index.ts—SYSTEM_PROMPTS.designGeneratorpackages/templates/src/system/design-generator.md— reviewable prompt sourcepackages/exporters/src/html.ts— realexportHtml()with Tailwind injection + prettifierpackages/exporters/src/{pdf,pptx,zip}.ts— Phase-2 stubs that throwCodesignError(EXPORTER_NOT_READY)apps/desktop/src/main/exporter-ipc.ts—codesign:exporthandler overdialog.showSaveDialogapps/desktop/src/renderer/src/components/PreviewToolbar.tsx— Export dropdown + toast slotpackages/core/src/generate.test.ts— vitest with mocked providerexamples/calm-spaces/README.md— demo docModified
packages/core/src/index.ts— pulls system prompt from templates; collapsed duplicated artifact-extraction loop into acollect()helperpackages/exporters/src/index.ts+package.json— top-levelexportArtifact()that lazy-imports format modules;./htmlsubpath export addedapps/desktop/src/main/index.ts— one new line:registerExporterIpc(() => mainWindow)apps/desktop/src/preload/index.ts— single new method:export(payload)apps/desktop/src/renderer/src/store.ts— additive:VITE_OPEN_CODESIGN_DEV_KEYfallback +exportActive(format)+ toast slotapps/desktop/src/renderer/src/App.tsx— single import +<PreviewToolbar />above the iframe (layout untouched forwt/preview-ux)Files NOT touched
Per worktree boundary:
apps/desktop/src/main/{config,keychain,onboarding-ipc,locale-ipc}.ts,apps/desktop/src/renderer/src/onboarding/**, all preview-ux components(
Toast,Settings,CommandPalette,ThemeToggle,TopBar,Sidebar,PreviewPane,preview/{Empty,Loading,Error}State.tsx,hooks/useKeyboard.ts),packages/i18n/**,packages/ui/src/components/{IconButton,Tooltip}.tsx,packages/{runtime,providers,artifacts,shared}/**.NO new prod deps
Confirmed:
packages/exporters/package.json— no new deppackages/templates/package.json— no new deppackages/core/package.json— only added@open-codesign/templates(workspace internal)apps/desktop/package.json— only added@open-codesign/exporters(workspace internal); uses Electron's built-indialogLockfile diff is workspace edges only. Install size budget unaffected.
Acceptance test outcomes
pnpm installcleanpnpm -r typecheckgreen across 9 workspaces (incl. desktop main + web)pnpm lintgreen (biome check, 61 files, 0 errors, 0 warnings)pnpm -r testgreen: 3 new tests inpackages/core/src/generate.test.ts(empty-prompt error, artifact extraction shape, system-prompt wiring) + existing artifact + runtime suitesVITE_OPEN_CODESIGN_DEV_KEYis read at build time viaimport.meta.env, falls through to existing assistant-message guidance when unsetA reference exported sample will be attached to this PR thread once a key is plumbed in CI; the IPC + exporter logic is unit-covered today.
Integration notes for parallel worktrees
wt/onboarding— when real keychain plumbing lands:apps/desktop/src/renderer/src/store.ts, replace theDEV_API_KEYconstant + theif (!apiKey)guidance branch with the keychain-fetched key (await the new IPC).VITE_OPEN_CODESIGN_DEV_KEYmention inexamples/calm-spaces/README.md.import.meta.env, so leaving the env var unset is harmless until that integration ships.wt/preview-ux—PreviewToolbarlives inapps/desktop/src/renderer/src/components/, the directory it claims. If it migrates to aPreviewPaneshell, simply move the single<PreviewToolbar />JSX line into the new container. The component itself depends only on the store; no layout assumptions baked in. The toast slot in the store (toastMessage/dismissToast) deliberately mirrors what theToastcomponent will need so the two can be merged trivially.wt/i18n— all user-visible strings inPreviewToolbarand theexamples/README are short and English-only; they're easy to swap tot()once the i18n keys exist. The Phase-2 messaging ("… ships in Phase 2") is a stable string suitable for the i18n catalogue.Hard rules checklist
CodesignErrorwith a structuredcodevar(--color-*)tokens; no hardcoded colors / fonts / pxany; bracket notation;import typefor typespnpm -r typecheck && pnpm lint && pnpm -r testall green from worktree root