mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
agent-runtime
17
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0f0d2879ff | Make de/fr/ru content i18n optional (#1511) | ||
|
|
a75d9938c7 |
feat(design-systems): add structured tokens.css schema (default + kami) (#1231)
* feat(design-systems): add structured tokens.css schema (default + kami) Compile each brand's DESIGN.md prose into a machine-readable :root block agents paste verbatim, removing the "Primary → --accent" translation step where most token misuse happens. Daemon prompt injection lands in a follow-up; lint-artifact already enforces the shared token vocabulary so no rule changes needed. Schema validated across two contrasting aesthetics: - default (sans-serif, cobalt, B2B utility) — stress test the shallow form, 2-level fg / 2-level surface - kami (serif, parchment, ink-blue, print-first) — stress test the rich form, 4-level fg ramp, 3-level surface, ring elevation, i18n font stacks, and solid-hex tag tints (print renderers double-paint alpha) Schema growth from kami's stress test (5 new optional slots, all backward-compatible — default aliases via var() to existing tokens): - --fg-2 / --meta (4-level fg ramp) - --surface-warm (3-level surface) - --border-soft (2-level border) - --elev-ring (ring elevation as first-class level) Brand-specific extensions live in tokens.css with explicit "NOT in shared schema" labels and a documented promotion path (≥2 brands need it → promote to schema slot). components.html in each brand is a self-contained reference fixture that exercises every token through real layouts. Both fixtures lint clean against apps/daemon/src/lint-artifact.ts. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(design-systems): add token-fixture drift guard Each design system in design-systems/<brand>/ ships two files agents consume in tandem: tokens.css (canonical token bindings) and components.html (a self-contained fixture whose first <style> embeds the same :root paste so the file renders standalone). The fixture's :root block is a copy of tokens.css's :root block, kept in sync only by an inline comment. This adds scripts/check-tokens-fixture-sync.ts and registers it in pnpm guard. The check pairs each brand's tokens.css with its components.html and asserts the unscoped :root block is byte-equivalent after canonical normalization (CSS comments stripped, whitespace collapsed, separator spacing normalized). Brands missing one half of the pair, or with no :root rule in either file, fail the guard. Scoped overrides like :root[lang="zh-CN"] are not required to appear in the fixture (per the kami fixture's inline comment they are pasted only when an artifact's <html lang> matches), so the check only compares the unscoped :root block. Verified: pnpm guard passes for default + kami, fails on intentional value drift, fails on missing token, tolerates whitespace-only formatting differences. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(design-systems): point fixture CTAs to real files Both default and kami components.html advertised in-page anchors (#tokens, #spec, #surface, #accent, #type, #components) but defined no matching ids, so every CTA was a no-op when the fixture was opened locally — flagged by mrcfps in #1231. Re-point each link to a real artifact in the same brand directory: - "View tokens" / "Inspect tokens" / "Inspect typography" → ./tokens.css - "Read the spec" / "Read the rule" → ./DESIGN.md Browsers render these as raw source views, which is the desired UX for a reference fixture: clicking the CTA shows the underlying contract instead of jumping to nothing. Agents copying the fixture also learn the pattern of "buttons link to actual sibling resources". The :root token block is unchanged, so the token-fixture drift guard still passes for both brands. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(design-systems): codify token schema (A1/A2/B/C layers) The two-brand pilot (default + kami) settled the shape of the shared token schema; this commit codifies it as a machine-readable contract and enforces it in pnpm guard, addressing lefarcen's review on #1231: > the optional-vs-required split won't generalize cleanly when brand > #3 needs different Layer A tokens or when multiple brands converge > on the same extension (promoting C→B→A). Consider surfacing that > limitation in the PR narrative or in a future SCHEMA.md. Schema lives under design-systems/_schema/ as three files: - tokens.schema.ts — TypeScript declaration of every shared token with its layer (A1-identity / A1-structure / A2 / B-slot), plus per-brand C-extension allowlists and a global C-prefix allowlist - defaults.css — CSS mirror of A2 fallback values, used as the human-readable contract reviewer's-eye copy and the future input to the derive script - AGENTS.md — schema layer model, C → B-slot → A2 promotion rules, when-not-to-add-a-token guidance Layer model: A1-identity 8 tokens — bg/surface/fg/muted/border/accent + font-display/font-body. The brand IS these values; no fallback is defensible. A1-structure 18 tokens — type scale (8), leading (2), tracking (1), section-y (3), container (4). Structural decisions vary per brand by design and have no cross-brand default. A2 26 tokens — accent states, semantic colors, motion, base spacing scale, radius, elevation, focus, font-mono. Required in every tokens.css; fallback lives in defaults.css for the future derive script to inline when DESIGN.md does not specify the value. B-slot 4 tokens — fg-2 / meta / surface-warm / border-soft. Brand may bind independently or alias the named sibling via var(...) for components that target the richer ramp. C-extension n tokens — brand-specific names (kami's tag-bg-*, leading-display, accent-light, etc.). Allowlisted per-brand in BRAND_EXTENSIONS or globally by prefix in BRAND_EXTENSION_PREFIXES. Promote when a second brand adopts the same name. Why A2 fails the guard today: Artifacts are generated by agents pasting one brand's :root block into a single <style>; there is no global stylesheet that supplies fallbacks at runtime. A tokens.css missing an A2 declaration would silently break any var() reference in the fixture. Until the derive script (PR-B) lands and inlines defaults, every brand's tokens.css must declare every A2 token directly. The guard enforces this strictly. Why --font-mono lands in A2 (not A1): 149 brands' DESIGN.md files were surveyed: 87 (58%) declare a monospace stack, 62 (42%) do not — including major brands like bmw / nike / apple / notion / mastercard / meta. Agent paste cannot rely on the brand author having written it down; a defaultable A2 fallback (with CJK brands like kami overriding) is safer than forcing every brand author to add a field they may not realize their kbd / code-block components need. Five guard checks, each registered as its own entry in scripts/guard.ts so failures attribute to a specific contract: 1. token-fixture sync — components.html :root ↔ tokens.css :root byte-equivalent (existing) 2. A1 required tokens — every brand declares every A1 token 3. A2 required tokens — every brand declares every A2 token 4. unknown token allowlist — every declared token is in schema or brand-extension allowlist 5. A2 defaults parity — defaults.css ↔ tokens.schema.ts fallback byte-equivalent Verified on default + kami: - 26 A1 tokens declared in both brands - 26 A2 tokens declared in both brands - 129 total declarations, all match shared schema or brand extensions - defaults.css ↔ tokens.schema.ts parity holds - sanity test: drifting --motion-fast in defaults.css fails check 5 with a clear divergence message The PR description originally listed "Dedicated SCHEMA.md" as explicitly NOT in this PR ("Once 3+ brands ship, extracting a single source of truth becomes worthwhile"). That boundary moves: lefarcen's review surfaced the schema-generalization risk, and the schema must exist as a machine-enforced contract before the derive script can read it. The TS file replaces the markdown that was deferred. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web/tests): pass missing designTemplates prop to ProjectView Pre-existing typecheck regression on main: PR #955 ( |
||
|
|
be77dc0394 | Default English resource i18n fallback (#1270) | ||
|
|
b5eb8c1647 |
feat: generic skills + split skills/design-templates + finalize-design API (#955)
* feat: general-purpose skills with @-mention composition and user import
Lift skills from "one mode-bound skill per project" to a generic capability
the user can compose per turn:
- Daemon: scan multiple skill roots (user-skills under runtime data, then
the bundled `skills/`); user-imported skills can shadow built-ins by id.
- New `POST /api/skills/import` and `DELETE /api/skills/:id` endpoints,
with CONFLICT/BAD_REQUEST/NOT_FOUND error codes and built-in delete
protection.
- ChatRequest gains `skillIds: string[]`; the chat run concatenates each
picked skill's body (and merges craftRequires) into the system prompt
for that turn only — the project's persistent `skillId` is untouched.
- Web composer: `@` popover now lists skills alongside project files;
picks render as removable chips above the textarea and ride along with
the request as `skillIds`.
- Settings → Library: import form (name/description/triggers/body),
per-card delete for user skills, "user" origin badge.
* chore(web): drop welcome pet teaser + add ds→prompt-template mapping util
- SettingsDialog: remove the inline pet adoption teaser from the welcome
panel so the first-run modal stays focused on configuration.
- New `inferPromptTemplateCategoriesForDs(ds)` helper that maps a design
system's authored metadata to prompt-template gallery categories.
Imported by the design-system gallery wiring on a sibling branch; no
callers in this branch yet.
* feat: split skills/design-templates and add finalize-design API
Phase 0 of the skills/design-templates refactor (specs/current/
skills-and-design-templates.md):
- Move ~104 rendering catalogue entries from skills/ to design-templates/
and keep skills/ for the small set of functional skills that *do work*
on user input (utilities, briefs, packagers).
- Add design-templates/AGENTS.md and skills/AGENTS.md describing the
contract, and a brand-agnostic craft/ surface for opt-in craft rules.
- Daemon: add DESIGN_TEMPLATES_DIR / USER_DESIGN_TEMPLATES_DIR roots and
an /api/design-templates surface mirroring /api/skills. Asset/example
routes still span both registries so existing srcdoc URLs keep
resolving across the rename.
- Web: split LibrarySection into SkillsSection + DesignSystemsSection,
rename the EntryView "Examples" tab to "Templates", and update locales
+ the New-project picker accordingly.
Adds the finalize-design endpoint:
- New apps/daemon/src/finalize-design.ts and packages/contracts/src/api/
finalize.ts — one-shot synthesis of a project's transcript + active
design system + current artifact into <projectDir>/DESIGN.md via the
Anthropic Messages API. Per-project .finalize.lock mirrors the
transcript-export hygiene from PR #493; provider credentials are not
persisted by the daemon.
Other supporting changes:
- README + AGENTS.md updates to document the new directory split and
craft/ surface, plus i18n strings across 13 locales.
- Test refactors and new coverage (finalize-design, runs, sidecar
server, plus refreshed daemon integration tests).
- .gitignore: scope the *.exe ignore to /OpenDesign.exe so legitimate
vendor binaries are no longer hidden.
* fix(merge): move clinical-case-report to design-templates/
Origin/main added the clinical-case-report skill under skills/ before
the skills/design-templates split landed. Its od.mode is prototype, so
per specs/current/skills-and-design-templates.md it is a design template
and belongs alongside the other rendering catalogue entries — not under
the slimmed-down functional skills/ root. Moving it keeps the EntryView
Templates tab consistent with origin/main's intent.
* feat(skills): curated design/creative catalogue + collapsible Settings rows
Seed ~100 curated design/creative skill stubs under skills/ sourced from
awesome-claude-skills (ComposioHQ) and awesome-agent-skills (VoltAgent).
Each stub carries an od.category tag so the new filter pill row in
Settings -> Skills can group them. The seed script
(scripts/seed-curated-design-skills.ts, pnpm seed:curated-design-skills)
is idempotent: it only creates folders that don't already exist, so
hand-edited stubs are never overwritten.
- Daemon: parse and surface od.category on SkillInfo with a strict slug
normaliser; mirror the field on SkillSummary in @open-design/contracts.
Category is purely a UI hint — system-prompt composition is unchanged.
- Web: rewrite SkillsSection from a left-list / right-detail grid into a
vertical stack of collapsible rows mirroring the External MCP panel
(header always visible with name + mode/source/category pills + per-row
enable toggle; SKILL.md preview, file tree and inline edit form expand
on demand). Add a Category filter row above the list. Reorder Settings
nav so Skills + External MCP sit above the Composio/MCP cluster. Update
composer placeholder/hint across 17 locales to advertise '@ files or
skills · / for commands'.
- Docs: extend skills/AGENTS.md with the curated catalogue rules
(idempotency, category vocabulary, no upstream vendoring).
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(skills): teach localized-content + system-prompt tests about the skills/design-templates split
mrcfps blocking review on PR #955: the skills/design-templates split
(
|
||
|
|
31e57fd773 |
fix(daemon): persist runStatus/endedAt on chat run termination (#1230)
* fix(daemon): persist runStatus/endedAt on chat run termination (#135) POST /api/runs created the run but never reconciled the messages row on terminal status. If the web failed to persist the cancel (refresh, dropped PUT), the row stayed at run_status='running' / ended_at=NULL, and on reload the elapsed timer kept climbing because the renderer fell back to now - startedAt. Mirror routine/orbit reconciliation: attach a wait-completion handler that updates run_status and ended_at, guarded by COALESCE and a run_status IN ('queued','running') filter so concurrent web persists are not clobbered. Adds cancelRun helper and two regression specs under e2e/tests/dialog/. * fix(daemon): annotate reconcile callback params for chat-routes The chat run reconciliation block landed in chat-routes.ts after the recent server-route split (#1043), where stricter type checking surfaces implicit `any` parameters. Annotate the wait/then callback as `{ status: string }` and the catch callback as `unknown`. * refactor(daemon): extract reconcileAssistantMessageOnRunEnd helper The inline if/wait/then/catch block in POST /api/runs read as a bolt-on patch. Lift it to a named file-scope helper so the route handler stays intent-level (start the run, arrange follow-up reconciliation) and the guard for missing assistantMessageId is an internal detail. The helper's docblock describes the invariant ("messages row reflects the run's terminal state even without web persist"); commit history keeps the issue context. * test(e2e): wait for any terminal status in stop-reconcile spec The earlier .catch fallback chained two waitForRunStatus calls (canceled then succeeded). waitForRunStatus throws on the first non-expected terminal, so a canceled run that resolves to failed (e.g. agent exits non-zero on SIGTERM) would still abort the test before reaching the messages-row assertion. Add waitForRunTerminal to e2e/lib/vitest/runs.ts: polls until any terminal status without throwing on mismatch, since this spec's claim is about the resulting messages row, not which terminal the run took. Addresses Codex inline review on PR #1230. |
||
|
|
976edaf38e |
test: harden e2e smoke and release reports (#1140)
* test: harden e2e inspect specs * test: wire e2e release reports * chore: bump packaged beta base to 0.6.1 * test: run release smoke vitest directly * test: add suite-owned tools-dev lifecycle * ci: harden stable release packaging * fix(release,e2e): gate stable signing on verify and harden suite cleanup - restore `needs: [metadata, verify]` on the stable release `build_mac`, `build_mac_intel`, `build_win`, and `build_linux` jobs so Apple signing/notarization and Windows release builds cannot run before pnpm guard, typecheck, and layout checks complete on the metadata commit. - in `runToolsDevSuite`, drop the `started` flag and always attempt `stopToolsDevWeb` in `finally`; record stop errors in diagnostics, and when the test body succeeded, escalate the stop failure to the suite result and rethrow — so orphan daemon/web processes from an interrupted `startToolsDevWeb` or a broken shutdown can no longer pass silently. Addresses PR #1140 review feedback from lefarcen and mrcfps. |
||
|
|
84f768d4a2 |
feat: add WeChat design system, login-flow skill, and fix API mode tool_calls bug (#1083)
* feat: add WeChat design system, login-flow skill, and fix API mode tool_calls bug - Add WeChat design system (design-systems/wechat/) with full brand spec including color palette, typography, and component rules for chat UI - Add login-flow skill (skills/login-flow/) for mobile authentication flows with P0 checklist, example HTML, and i18n registration across 3 locales - Fix DeepSeek V4 bug: API/BYOK mode (streamFormat=plain) models now receive a directive to emit only <artifact> HTML blocks and suppress tool_calls, since plain adapters proxy to external providers that cannot execute tools * fix: restore full server.ts and WeChat DESIGN.md from ad46d8cd commit Restore files that were corrupted in PR #1083 head branch. The WeChat DESIGN.md was reduced to a single line (filename only) and server.ts was reduced to ~1 line. Both are restored to their original ad46d8cd state with full content. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: restore full server.ts and WeChat DESIGN.md from ad46d8cd Restore files corrupted in PR #1083: - apps/daemon/src/server.ts: restored 7106-line file - design-systems/wechat/DESIGN.md: restored 301-line WeChat design spec - skills/login-flow/SKILL.md: restored from local working state - skills/login-flow/example.html: restored 351-line example HTML * fix: only suppress tool_calls when streamFormat='plain' explicitly, remove nonexistent assets/template.html 1. streamFormat check now requires explicit 'plain' value instead of defaulting to 'plain' when undefined. This prevents normal tool-using chat runs from incorrectly inheriting the API/BYOK tool_calls suppression rule. 2. login-flow SKILL.md: removed reference to assets/template.html since that file does not exist in the skill bundle and derivePreflight() would inject a hard instruction to read it before any other tool, causing pre-flight to fail. * fix: thread streamFormat to composeSystemPrompt in server.ts call Previously the composeSystemPrompt call at line ~4940 omitted streamFormat, causing the composer to default to 'plain' and suppress tool_calls even for tool-using chat runs. Now streamFormat is passed through from the adapter definition so the API mode rule only fires when streamFormat='plain' is explicitly set. * fix: WeChat category metadata, font-family, and login-flow example interactivity WeChat DESIGN.md: - Add Category: Social & Messaging metadata so it appears correctly in picker - Fix font-family declaration: remove invalid -webkit-font-family prefix, use standard font-family so downstream CSS generation works correctly skills/login-flow/example.html: - Add password toggle click handler so show/hide actually works - Change Apple icon fill from hardcoded #fff to currentColor so it is visible on light backgrounds * fix: mirror streamFormat suppression in contracts composer and add WeChat i18n 1. packages/contracts/src/prompts/system.ts: Add streamFormat parameter to ComposeInput and ComposeInput interface, mirroring the same suppression rule from daemon prompts/system.ts. When streamFormat='plain' is passed, a directive is appended telling models not to emit tool_calls and to only output <artifact> HTML blocks. 2. apps/web/src/i18n/content.{ts,fr,ru}.ts: Add WeChat design system entries: - Add 'wechat' to DE/FR/RU_DESIGN_SYSTEM_IDS_WITH_EN_FALLBACK arrays - Add 'wechat' summary to DE/FR/RU_DESIGN_SYSTEM_SUMMARIES - Add 'Social & Messaging' category to DE/FR/RU_DESIGN_SYSTEM_CATEGORIES (matching the Category: Social & Messaging metadata in WeChat DESIGN.md) * fix: thread streamFormat='plain' into web composeSystemPrompt for api mode * test: focus localized content coverage on missing resources --------- Co-authored-by: Open Design Contributor <z@open-design.dev> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: mrcfps <mrc@powerformer.com> |
||
|
|
b06f26a5fd |
test: strengthen e2e PR coverage (#796)
* test: strengthen e2e PR coverage * fix: address e2e PR feedback Generated-By: looper 0.6.1 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Generated-By: looper 0.6.1 (runner=fixer, agent=opencode) * ci: cache Windows packaged smoke builds * test: fake additional agent runtimes * fix: address e2e PR feedback Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Route tools-pack mac starts through a launch-time packaged config override so portable packaged smoke runs keep using the namespace runtime root that inspect and logs expect. Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Fall back to the packaged app's embedded config when the build output config is missing so installed mac starts still work. Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: align packaged mac PR smoke with tools-pack runtime mode Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Keep blake3-wasm out of the packaged mac daemon prebundle so the standalone runtime loads the Cloudflare asset hasher from node_modules instead of crashing in ESM. Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix: address e2e PR feedback Skip the portable mac launch override when the bundled packaged config is missing so installed fallback app targets can still boot with packaged defaults. Add a regression test covering the missing-config start path. Generated-By: looper 0.6.2 (runner=fixer, agent=opencode) * fix(pack): remove duplicate mac prebundle dependency key |
||
|
|
f1cdb2844a |
test(e2e): gate beta packaged runtime (#637)
* test(e2e): gate beta mac packaged runtime * test(e2e): separate ui automation layout * test(e2e): move localized content coverage * chore(release): prepare packaged 0.4.1 beta validation * test(e2e): keep ui lane playwright-only * fix(web): keep chat recoverable after conversation load failure * fix(desktop): honor native mac quit |
||
|
|
d1d63f9dae |
Fix/error message persistence (#623)
* test(ProjectView): persists daemon errors on assistant messages Signed-off-by: nhancdt2602 <nhancu2602@gmail.com> * fix(ProjectView): persists daemon errors on assistant message Signed-off-by: nhancdt2602 <nhancu2602@gmail.com> * test(e2e): cover agent switch and persistence Signed-off-by: nhancdt2602 <nhancu2602@gmail.com> * chore(chat-event): handle falsy empty error detail Signed-off-by: nhancdt2602 <nhancu2602@gmail.com> --------- Signed-off-by: nhancdt2602 <nhancu2602@gmail.com> |
||
|
|
2473ab9567 |
fix(web): add copy buttons for FileViewer code blocks (#471)
* fix(web): add copy buttons for FileViewer code blocks * fix(web): harden FileViewer markdown copy controls * fix(web): restore focus after clipboard fallback * test(e2e): restore execCommand after markdown copy tests |
||
|
|
5a0f954297 |
fix(daemon): emit tool_use from tool_execution_start in pi-rpc (#186)
* fix(daemon): emit tool_use from tool_execution_start in pi-rpc The pi-rpc adapter emitted tool_use from message_end, which fires before tool execution starts. The web UI pairs tool results to prior tool_use events, so receiving tool_result without a preceding tool_use broke tool card rendering and file auto-open behavior. Move tool_use emission to tool_execution_start, matching the pattern in copilot-stream.ts. Remove redundant tool call extraction from message_end (tool_use is now emitted at execution time, usage is already emitted from turn_end). Extract mapPiRpcEvent as a pure exported function so tests exercise the real event mapping logic instead of an inlined copy that can diverge from production. Ref: mrcfps review comments on PR #117 * docs(daemon): clarify mapPiRpcEvent mutability contract The function mutates ctx.sentFirstToken to track streaming state. Calling it "pure" is misleading; revised the doc comment to say no I/O or child process interaction instead. * fix(pi-rpc): remove redundant status(tool) emission from tool_execution_start Now that tool_use fires inline from tool_execution_start, the accompanying status(tool) event is redundant: tool_use already carries the tool name, and the UI renders running state from the tool card. The extra status pill breaks consecutive tool_use grouping in AssistantMessage.buildBlocks. Aligns with copilot-stream, which emits only tool_use from tool.execution_start with no status event. |
||
|
|
0bafc73d24 |
Add visible conversation timestamps (#120)
* Add visible conversation timestamps Generated-By: looper 0.2.7 (runner=worker, agent=codex) * Fix assistant message timestamps Generated-By: looper 0.2.7 (runner=fixer, agent=codex) |
||
|
|
f8af2cd875 |
fix(web): exit PreviewModal fullscreen on first Esc press (#168)
Closes #141. When the user clicked the Fullscreen button, requestFullscreen() put the stage element into native browser fullscreen and React's `fullscreen` state was set true. Pressing Esc was meant to exit the overlay, but in browsers like Firefox the browser consumes Esc to drop its native fullscreen element without delivering keydown to JS. The React state stayed true, the `ds-modal-fullscreen` class lingered, and only a second Esc reached the keydown handler that flipped the state. Subscribe to `fullscreenchange` so the React state mirrors the native state. When the browser exits its fullscreen element, the overlay drops on the same keystroke. The keydown handler is still needed for the fallback path (no native fullscreen API support, where requestFullscreen is undefined and only React state is set). Adds three regression tests in e2e/tests/preview-modal-fullscreen.test.tsx covering the bug fix path, the keydown fallback, and a non-collapse guard for transitions where another element is still fullscreen. Co-authored-by: d 🔹 <258577966+voidborne-d@users.noreply.github.com> |
||
|
|
8f34e39b7b |
feat(daemon): add pi coding agent adapter (#117)
* feat(daemon): add pi coding agent adapter Add pi (https://pi.dev) as a supported coding agent, using its --mode rpc JSON-RPC protocol over stdio for structured event streaming. Changes: - apps/daemon/pi-rpc.js: new RPC session handler that drives pi's --mode rpc protocol, translating typed agent events (text_delta, thinking_delta, tool_use, tool_result, usage, status) into the daemon's UI event format. Auto-resolves extension UI requests (fire-and-forget consumed, dialogs auto-approved) so pi stays unblocked in the headless web UI. Kills the process after agent_end since pi's RPC process is designed for multi-prompt sessions. - apps/daemon/agents.js: add pi agent definition with custom fetchModels (pi --list-models outputs to stderr, not stdout), 575+ models from 20+ providers, reasoning/thinking level support via --thinking flag, and streamFormat 'pi-rpc'. - apps/daemon/server.js: wire pi-rpc stream format to attachPiRpcSession; skip stdin.end() for pi-rpc since the RPC session manages stdin bidirectionally. - apps/daemon/acp.js: export createJsonLineStream for reuse by pi-rpc.js. - apps/daemon/pi-rpc.test.mjs: 19 unit tests covering model list parsing (TSV, dedup, edge cases), RPC event translation (text, thinking, tools, usage, compaction, retry), sendCommand wire format, extension UI auto-resolution. - e2e/tests/structured-streams.test.ts: add pi RPC tool_use/tool_result event mapping test alongside existing Claude/Copilot fixtures. Verified end-to-end: daemon /api/chat → pi RPC → SSE stream with status, text_delta, usage, and tool events. Live E2E test passes (OD_E2E_RUNTIMES=pi). All 59 project tests green. * refactor(daemon): migrate pi-rpc to TypeScript Follow upstream #118 TypeScript migration convention: rename pi-rpc.js → pi-rpc.ts and pi-rpc.test.mjs → pi-rpc.test.ts with @ts-nocheck header (same as all other daemon modules). Import paths remain ./pi-rpc.js per NodeNext module resolution. * fix(daemon): avoid duplicate usage events in pi-rpc handler Pi emits both message_end and turn_end per turn, both carrying usage data. Emitting from both handlers caused double-counting in the UI and any consumer that aggregates usage. Remove usage emission from the message_end branch since turn_end is the canonical per-turn usage source. Keep tool call extraction in message_end (unique data not available in turn_end). Add regression test confirming exactly one usage event is emitted when both message_end and turn_end carry usage for the same turn. Addresses Copilot P2 review on PR #117. * fix(daemon): scope pi RPC id counter per session, bump graceful shutdown Move nextRpcId and sendCommand inside attachPiRpcSession as local state, matching the pattern in acp.ts where nextId is scoped per session. Prevents RPC id collisions across concurrent /api/chat requests. Bump post-agent_end SIGTERM grace period from 2s to 5s and make it configurable via PI_GRACEFUL_SHUTDOWN_MS env var for resource- constrained machines. Add test confirming concurrent sessions get independent id sequences. * fix(daemon): wrap parser.feed in try-catch in pi-rpc Catch errors from parser.feed and route them through the existing fail() handler instead of letting them propagate as unhandled exceptions. |
||
|
|
c6d11018a0 |
Refresh desktop integration control plane (#123)
* feat(dev): add desktop tools-dev control plane * refactor(sidecar): split Open Design contracts Move Open Design-specific sidecar protocol definitions into @open-design/contracts so sidecar and platform can remain descriptor-driven primitives. * refactor(daemon): organize package sources Keep daemon app code, tests, and sidecar entrypoints in separate package directories so each layer can be built and verified independently. * chore(repo): streamline maintenance entrypoints Centralize agent guidance by directory and reduce root command chains while preserving the existing build scope. * docs: translate agent guidance to English * fix(sidecar): tolerate stale IPC sockets Remove stale Unix socket files only after confirming no listener is active, so tools-dev can restart after unclean shutdowns. |
||
|
|
cfebff9653 |
Align app directories and isolate e2e tests (#102)
* chore: align app directories * test: consolidate external suites under e2e |