mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
798ffaec483b7d19319e07248c5ddb8ea2ca9b22
26
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
671293e7f4 |
feat(cli): od doctor + od config get/set/list/unset
Plan I2 / spec §12.2. `od doctor` is a single-shot diagnostics command that: - hits /api/daemon/status (fails with exit 64 if unreachable) - lists installed plugins and runs the per-plugin doctor route - lists skills / design-systems / atoms for inventory - aggregates issues by severity (warn / error) - exits 1 when any plugin doctor returns ok=false, otherwise 0 This is the CLI entry point a CI runner uses to gate a release on plugin-system health before publishing. --json emits the full report so downstream tooling (e.g. a GitHub Action summary step) can render its own table. `od config list/get/set/unset` wraps GET/PUT /api/app-config so a code agent can flip provider keys / orbit settings / pet config headlessly: od config list od config get <key> (or --json for the value alone) od config set <key> <value> (positional or --value <text>) od config set <key> --value-json '<json>' (nested values) od config unset <key> set on a top-level key only — nested merges go through --value-json which keeps the daemon's existing PUT semantics (full-document replace) intact. Daemon test suite stays at 1476/1476 (the new CLI verbs are thin wrappers over endpoints that already have integration coverage). Co-authored-by: Tom Huang <1043269994@qq.com> |
||
|
|
712c18dbc2 |
feat(cli): od atoms / skills / design-systems / craft / status / version + marketplace search
Plan H2 + H3 + H4 / spec §12.2 / §11.7.
Closes the CLI parity remainder: every UI feature reachable via
/api/* now has a matching CLI verb.
od atoms list List first-party atoms.
od atoms show <id> Print one atom (status + taskKinds).
od skills list / show <id> Wraps GET /api/skills{,/:id}.
od design-systems list / show <id> Wraps GET /api/design-systems{,/:id}.
od craft list / show <id> NEW endpoints GET /api/craft{,/:id}
walk the craft/ directory and
emit { id, label, bytes }.
od status Alias of `od daemon status`.
od version Wraps GET /api/version; --json
emits the structured shape.
od marketplace search "<query>" New verb. Walks every configured
[--tag <tag>] marketplace's plugins[] and
matches by substring on
name + description + tags.
The HTTP additions are GET /api/craft (catalog summary) and
GET /api/craft/:id (raw markdown body), both safe-slug-validated.
Daemon tests: 1472 → 1475 (+3 cases on craft-route covering catalog
shape, malformed slug rejection, miss-as-404).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
45f52d71c4 |
feat(plugins): od plugin publish — catalog PR-template launcher
Plan H1 / spec §14.1.
apps/daemon/src/plugins/publish.ts owns the URL-builder side. Pure
string assembly per catalog target:
anthropics-skills → github.com/anthropics/skills/issues/new
?title=…&body=…
awesome-agent-skills → github.com/VoltAgent/awesome-agent-skills/...
clawhub → github.com/openclaw/clawhub/...
skills-sh → https://skills.sh/ + npx skills add owner/repo
(skills.sh autodiscovers; no PR form needed)
The PR body carries plugin id / version / repo URL plus a compatibility
checklist confirming SKILL.md + open-design.json so the upstream
reviewer can validate against the §3 cross-catalog matrix at a glance.
CLI:
od plugin publish <pluginId> --to <catalog>
[--repo <github-url>] [--snapshot-id <id>]
[--open] [--json]
--open auto-launches the system browser (open / xdg-open / start) on
the catalog URL, so a code agent driving the headless flow can hand
off to the human author with a single command.
The CLI never POSTs anywhere — every catalog upstream stays under the
author's review control.
Daemon tests: 1465 → 1472 (+7 cases on plugins-publish covering URL
shape per target + skills.sh fallback + unknown-catalog rejection).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
04784013e6 |
feat(plugins): od plugin scaffold + od plugin export (Phase 4 author tooling)
Plan G1 + G2 / spec §14.
Two new author-side CLI verbs that close the spec §14 'one repo, every
catalog' loop without leaving the terminal.
apps/daemon/src/plugins/scaffold.ts owns the scaffold path:
od plugin scaffold --id <id> [--title] [--description]
[--task-kind <new-generation|code-migration|
figma-migration|tune-collab>]
[--mode <m>] [--scenario <s>]
[--out <dir>] [--with-claude-plugin]
Writes <out>/<id>/{SKILL.md, open-design.json, README.md} (plus the
optional .claude-plugin/plugin.json for cross-catalog publishing).
Refuses to overwrite an existing scaffold; rejects unsafe ids.
apps/daemon/src/plugins/export.ts + POST /api/applied-plugins/export
own the export path. Three targets:
od → SKILL.md + open-design.json + provenance README
claude-plugin → SKILL.md + .claude-plugin/plugin.json + README
agent-skill → SKILL.md + README only (every catalog accepts this)
od plugin export <projectId> --as od|claude-plugin|agent-skill --out <dir>
od plugin export --snapshot-id <id> --as <target> --out <dir>
The exporter pulls SKILL.md straight off the installed plugin's fsPath
when available and otherwise synthesises one from the snapshot's
frozen plugin metadata, so a publishable folder is reproducible even
after od plugin update / uninstall rotates the live source. The
generated open-design.json carries a provenance block recording
snapshot id + manifestSourceDigest so a downstream catalog viewer can
reverse-resolve the originating run.
The HTTP route is loopback-only (requireLocalDaemonRequest) because
it writes to the host filesystem; the CLI is the canonical caller.
Daemon tests: 1455 → 1465 (+10): plugins-scaffold (5 cases) +
plugins-export (5 cases).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
9927707361 |
feat(plugins): od plugin install <name> resolves through marketplaces
Plan §3.F3 / spec §7.2 + §6 / §16 Phase 3. `resolvePluginInMarketplaces(db, name)` walks every configured marketplace in registration order and returns the first matching plugin entry. The matched entry carries: - the canonical source string (github:owner/repo, https://…tar.gz) that the existing installer backends already understand - the marketplace trust tier and id for the audit trail - the optional description for surface display POST /api/plugins/install detects bare-name sources (anything that isn't a local path / github: / https://) and re-routes through `resolvePluginInMarketplaces` before handing off to the installer. On miss the route returns 404 plugin-not-found with structured error data, so the CLI's structuredHttpFailure helper maps it to exit 65. `od plugin install <name>` (no flag) now works end-to-end. The existing `./folder`, `github:…` and `https://*.tar.gz` shapes are unchanged. Note: per spec §9, marketplace trust does NOT propagate to the installed plugin: a plugin pulled from a 'trusted' marketplace still defaults to its source-kind tier. Trust elevation goes through `od plugin trust` / the Phase 3 trust UI. Daemon tests: 1450 → 1454 (added 4 cases to plugins-marketplaces: canonical-source resolution, case insensitivity, miss → null, registration-order tie-break). Co-authored-by: Tom Huang <1043269994@qq.com> |
||
|
|
1ae977e066 |
feat(cli): od daemon start/status/stop + new HTTP daemon-lifecycle routes
Plan §6 Phase 1.5 / spec §11.7.
The desktop default `od` (no subcommand) keeps its current behaviour
for back-compat. New explicit lifecycle entry:
od daemon start [--headless] [--serve-web] [--port <n>] [--host <addr>]
[--no-open] [--namespace <ns>]
--headless / --no-open / --serve-web all imply 'do not auto-open the
browser', so a code agent / CI runner / Docker entry point can launch
the daemon without electron. The port + host flags fall through to
OD_PORT / OD_BIND_HOST when unset, matching every other surface.
od daemon status [--json] [--daemon-url <url>]
od daemon stop [--daemon-url <url>]
These two CLI verbs hit the new HTTP routes:
GET /api/daemon/status → { ok, version, bindHost, port, pid,
dataDir, mediaConfigDir, namespace,
installedPlugins, shuttingDown }
POST /api/daemon/shutdown → 202; emits SIGTERM so the existing
graceful close path runs unchanged.
requireLocalDaemonRequest enforces the
same loopback / origin check used by
composio config writes (no public
shutdown surface).
This makes `od daemon start --headless --port 17456` followed by
`od plugin install ./fixtures/sample-plugin` and the rest of the
§12.5 walkthrough reachable without electron — exactly the substrate
e2e-3 needs.
Daemon tests: 1448 → 1450 (added daemon-lifecycle with 2 cases:
status snapshot shape; shutdown rejects non-loopback callers).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
3d0ce28346 |
feat(cli): od project / run / files / conversation subcommand routers
Plan §6 Phase 1 follow-up + Phase 2C / spec §12.2.
Wraps the existing daemon HTTP endpoints behind stable CLI subcommands
so a code agent can drive the §12.5 walkthrough end-to-end without
hitting /api/* directly. Every UI feature now has a CLI equivalent
(spec §11.7 invariant).
New CLI groups:
od project create [--name] [--skill] [--design-system] [--plugin]
[--inputs <json>] [--metadata-json <path|->]
[--grant-caps a,b]
od project list / info / delete
od run start --project <id> [--conversation] [--message] [--plugin]
[--inputs <json>] [--grant-caps] [--agent] [--model]
[--snapshot-id] [--follow]
od run watch <runId> ND-JSON SSE relay on stdout
od run cancel <runId>
od run list [--project <id>]
od run info <runId>
od files list <projectId>
od files read <projectId> <relpath>
od files write <projectId> <relpath> (reads stdin)
od files upload <projectId> <localpath> [--as <relpath>]
od files delete <projectId> <name>
od conversation list <projectId>
od conversation info <conversationId>
Plugin runs route through the snapshot resolver from §3.A1 — a code
agent can pass --plugin / --inputs / --grant-caps directly to
`od project create` or `od run start` and the daemon pins the
applied plugin snapshot to the new project / run. Capability gate
failures map to exit 66 / capabilities-required, missing inputs to
exit 67 / missing-input via the structured error envelope from §3.B1.
Daemon test suite stays at 1448/1448 (CLI handlers are thin HTTP
wrappers; the underlying routes already have integration coverage).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
0df9176c2f |
feat(plugins): marketplace registry + od marketplace CLI verbs
Plan §3.B4 / spec §6 / §7.2 / §16 Phase 3 entry slice.
The storage half of federated catalogs:
- New apps/daemon/src/plugins/marketplaces.ts owns add / list / get /
refresh / remove / set-trust over the pre-existing plugin_marketplaces
SQLite table. Uses parseMarketplace from @open-design/plugin-runtime so
validation matches the schema in docs/schemas/open-design.marketplace.v1.json.
Default trust tier is 'restricted' (discovery only) per spec §9.
- HTTP routes:
* GET /api/marketplaces
* POST /api/marketplaces (body { url, trust? })
* GET /api/marketplaces/:id
* DELETE /api/marketplaces/:id
* POST /api/marketplaces/:id/refresh
* POST /api/marketplaces/:id/trust (body { trust })
* GET /api/marketplaces/:id/plugins (catalog passthrough)
- CLI verbs: `od marketplace add/list/info/refresh/remove/trust`.
--trust accepts 'trusted', 'restricted', or 'official'.
Phase 3 follow-up wires `od plugin install <name>` resolution + the trust
UI on top; this commit is the data-layer half so the CLI can already
register and inspect catalogs.
Daemon tests: 1438 → 1443 (added plugins-marketplaces with 5 cases).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
fbabb27143 |
feat(plugins): CLI structured error envelope + apply --grant-caps / --input k=v
Plan §3.B1 + §3.B2 / spec §12.4.
- New exitWithStructuredError() + structuredHttpFailure() helpers in
cli.ts. Maps a daemon HTTP error envelope (or a synthetic local
reason) to the §12.4 exit codes (64–73): daemon-not-running,
plugin-not-found, capabilities-required, missing-input,
project-not-found, run-not-found, provider-not-configured,
plugin-requires-daemon, snapshot-stale, genui-surface-awaiting.
- od plugin apply now:
* accepts --inputs <json> AND repeated --input k=v (auto-coercing
'true'/'false' booleans and numerics) so a code agent can build the
inputs map without shell-escape gymnastics
* accepts --grant-caps a,b for per-snapshot capability grants
* routes 422 (missing inputs) → exit 67, 409 capabilities-required →
exit 66, daemon-down → exit 64, all via the structured envelope.
apps/daemon/src/plugins/installer.ts gets a small TS soundness fix on
the tar filter callback (entry can be Stats or ReadEntry — narrow before
reading .type).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
39820be28b |
feat(plugins): snapshot GC worker + od plugin run shorthand
Plan §3.A5 (snapshot GC) + §3.B3 (od plugin run shorthand).
- New apps/daemon/src/plugins/gc.ts wraps pruneExpiredSnapshots() in a
periodic worker driven by OD_SNAPSHOT_GC_INTERVAL_MS. Daemon boot
starts the worker and runs an immediate sweep so a fresh daemon does
not wait the full interval before reaping pre-existing expired rows.
Setting the interval to 0 disables the worker entirely.
- New HTTP endpoints:
* GET /api/applied-plugins → list all snapshots
* GET /api/projects/:projectId/applied-plugins → list snapshots for
one project
* POST /api/applied-plugins/prune { before? } → operator escape hatch
that calls pruneExpiredSnapshots() with the optional cutoff so a
hosted operator can force-delete unreferenced rows older than ts.
- New CLI verbs:
* od plugin snapshots list [--project <id>]
* od plugin snapshots prune [--before <unix-ms>]
* od plugin run <id> --project <projectId> [--inputs <json>]
[--grant-caps a,b] (apply + run start shorthand). Capability gate
failures map to exit 66; missing-input to exit 67.
- ConnectorApiErrorCode gains CONNECTOR_NOT_GRANTED so the §3.A3 gate
rejection can use the canonical sender.
Daemon tests: 1425 → 1429 (added plugins-snapshot-gc with 4 cases).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
44ea30c986 |
feat(plugins): trust mutation + connector tool-token gate
Plan §3.A2 (trust mutation) and §3.A3 (connector capability gate).
- New POST /api/plugins/:id/trust accepts { capabilities[], action: 'grant' | 'revoke' }
and unions the spec §5.3 vocabulary into installed_plugins.capabilities_granted.
Unknown / malformed strings come back as HTTP 400 with the rejected list so the
CLI can surface exit-2 usage advice. The implicit prompt:inject floor is
preserved on revoke so a plugin never falls below the spec minimum.
- trust.ts gains validateCapabilityList / grantCapabilities / revokeCapabilities.
These are the only writers of installed_plugins.capabilities_granted outside
of install.
- od plugin trust calls the new endpoint instead of printing the deferred
Phase 3 stub. --revoke flag and --grant-caps flag added; PLUGIN_BOOLEAN_FLAGS
/ PLUGIN_STRING_FLAGS extended.
- Tool-token grants now optionally carry pluginSnapshotId / pluginTrust /
pluginCapabilitiesGranted. The mint site in startChatRun resolves these
off the run's appliedPluginSnapshotId so the connector execute route can
re-validate per-call without re-reading SQLite.
- /api/tools/connectors/execute calls a new pure helper
checkConnectorAccess(grant, connectorId). Trusted / bundled implicitly
carry connector:*; restricted plugins must list connector:<id> (or the
coarse connector capability) — otherwise 403 CONNECTOR_NOT_GRANTED.
Daemon test suite: 1417 / 1417 (added plugins-trust + plugins-tool-token-gate).
Co-authored-by: Tom Huang <1043269994@qq.com>
|
||
|
|
89be57b2c4 |
feat(genui): introduce GenUI surface management and event handling
- Added a new GenUI module for managing user interface surfaces, including creation, response handling, and state synchronization. - Implemented API endpoints for listing and responding to GenUI surfaces associated with runs and projects. - Introduced event types and payload helpers for GenUI surface events, enhancing the interaction model for headless operations. - Established a persistent state writer for GenUI surfaces, ensuring reliable data management and retrieval. - Enhanced the plugin system to support auto-derived OAuth prompts for required connectors, improving user experience during plugin application. |
||
|
|
4c7cd5d9f2 |
feat(plugins): introduce plugin system with installation and management capabilities
- Added support for a new plugin system, allowing users to install, uninstall, and manage plugins through the daemon. - Implemented API endpoints for listing installed plugins, retrieving plugin details, and applying plugins with input validation. - Introduced a plugin doctor feature to validate plugin manifests and check for issues before application. - Established a plugin persistence layer with SQLite migrations for managing installed plugins and their metadata. - Enhanced the CLI with commands for plugin operations, improving user interaction with the plugin ecosystem. |
||
|
|
b578b93f3f |
Bug FIx: Media generation task state is volatile and lost on daemon restart #648 (#884)
* feat: implement media tasks persistence
* fix(daemon): satisfy exactOptionalPropertyTypes in media-tasks-routes test
`process.env.OD_DATA_DIR` is `string | undefined`, but `openDatabase`'s
options accept `{ dataDir?: string }`. Under the daemon tsconfig's
exactOptionalPropertyTypes the two are not assignable. Spread the key
in only when defined.
* fix(daemon): restore mcp-config / mcp-oauth / mcp-tokens imports in server.ts
The earlier 'Merge branch main into main' resolved the import-block
conflict by keeping only the new media-tasks import and dropping the
three pre-existing import blocks. server.ts still uses 13+ symbols
from those modules (PendingAuthCache, MCP_TEMPLATES, beginAuth,
readMcpConfig, getToken, etc.), so the daemon crashed at startup with
'ReferenceError: PendingAuthCache is not defined' the moment Playwright
booted it. Restore the three import blocks verbatim from main.
---------
Co-authored-by: lefarcen <935902669@qq.com>
|
||
|
|
208f09c60e |
fix: settle completed runs and clean up shutdown children (#924)
* fix: clean up completed and shutting down runs * fix: bound daemon CLI shutdown Generated-By: looper 0.6.0 (runner=fixer, agent=codex) * fix: harden daemon shutdown cleanup Generated-By: looper 0.6.0 (runner=fixer, agent=codex) * fix: harden daemon shutdown cleanup Generated-By: looper 0.6.0 (runner=fixer, agent=codex) * test: align acp abort fake with typed child |
||
|
|
e52720aa12 |
feat(daemon): add language boost support for Minimax TTS (#773)
* feat(daemon): add language boost support for Minimax TTS Add --language CLI flag to support language boost parameter for Minimax TTS. This enables better pronunciation for specific languages like Cantonese (Yue). * docs(media): add --language flag to media generation contract Document the language boost parameter for Minimax TTS, enabling better pronunciation for specific languages like Cantonese (Yue). * fix(media): correct Cantonese language_boost value and add input validation - Use correct MiniMax value 'Chinese,Yue' for Cantonese (no space) - Add type guard in server.ts to reject non-string language values - Trim language string before sending to MiniMax API --------- Co-authored-by: root <root@DELLN40.asiacredit.org> |
||
|
|
959bfaa817 |
fix(daemon): make MCP install snippet survive daemon port changes (#846)
* fix(daemon): make MCP install snippet survive daemon port changes `od mcp` now discovers the live daemon URL via the sidecar IPC status socket on every spawn, so the Settings -> MCP server snippet no longer bakes in `--daemon-url <port>`. Pasted client configs stay valid across daemon restarts even when the daemon binds an ephemeral port (tools-dev, packaged). Resolution order is --daemon-url > OD_DAEMON_URL > IPC discovery > http://127.0.0.1:7456 so explicit overrides still win for direct `od` launches. * fix(daemon): MCP snippet works in non-default namespaces and direct launches Propagate OD_SIDECAR_NAMESPACE / OD_SIDECAR_IPC_BASE into the snippet env so non-default namespace daemons stay reachable; the spawned MCP client does not inherit the daemon's env, so without this it would probe the default-namespace socket and miss. Restore --daemon-url in the snippet for direct `od --port X` launches that have no IPC socket. Reword `od mcp --help` so it does not imply live URL tracking; each new spawn rediscovers, but a running MCP server caches the URL until the client restarts. |
||
|
|
56bf6ee1b6 |
feat: agent-callable research command and /search (#615)
* feat: pre-generation research (Tavily) for grounded generation
Adds an optional pre-generation research step so the agent can produce
slides / prototypes / decks grounded in real sources instead of guessing.
User flow:
1. Settings -> Tavily Search -> paste API key (or set TAVILY_API_KEY).
2. Click the new Research button in the chat composer.
3. On send, the daemon runs a Tavily search, prepends the findings
as a <research_context> block ahead of the system prompt, and
spawns the agent. Research progress shows up as status pills in
the chat stream; the agent cites sources inline as [1]/[2]/...
Phase 1 surface:
- Single provider (Tavily), single depth ('shallow'), no LLM
synthesis pass (Tavily's `answer` is the summary).
- Composer toggle only; no popover / depth picker yet.
- Reuses the existing `status` SSE agent payload + StatusPill UI
so no new event variants or renderer code are needed.
Layers touched:
- contracts: ResearchOptions / Source / Findings DTOs;
ChatRequest.research; export from index.
- daemon: apps/daemon/src/research/{index,tavily}.ts orchestrator
+ provider; tavily added to MEDIA_PROVIDERS and ENV_KEYS; hook
in startChatRun before prompt assembly.
- web: ChatComposer toggle + ChatSendMeta; threaded through
ChatPane / ProjectView / streamViaDaemon into ChatRequest.
Side fix (required to land the feature, but useful on its own):
contracts internal relative imports lacked the `.js` suffix that
NodeNext module resolution requires. This was already breaking
`pnpm --filter @open-design/daemon typecheck` on main; without the
fix, none of the new research types were visible to the daemon.
All internal contracts imports now carry `.js`.
Spec: specs/current/research-feature.md (phases 2-4 outlined for
follow-up: composer popover, multi-provider, deep recursion, example
skills with research_recommends).
Verified:
- pnpm --filter @open-design/contracts typecheck/test
- pnpm --filter @open-design/daemon typecheck (the chokidar
project-watchers test is a pre-existing flake, unrelated)
- pnpm --filter @open-design/web typecheck
- node scripts/verify-media-models.mjs
* fix(daemon): clamp Tavily max_results to 20
Tavily's /search endpoint requires `max_results` in [0, 20]; sending a
larger value (e.g. when `research.depth: "deep"` resolves to 30) returns
400 and `runResearch` silently falls back to no-research. Clamp at the
provider boundary so Phase 2 depth tiers above 20 still produce results
instead of failing the request.
Generated-By: looper 0.6.1 (runner=fixer, agent=claude-code)
* Remove stale research merge leftovers
* Add agent-callable research search
* Fix Indonesian locale typecheck
* Fix research command invocation edge cases
* Harden slash search prompt expansion
* Honor research source caps in command contract
* Require search reports in design files
* Add research data provider settings
* Wire web research provider fallback order
* Update research provider fallback wording
* Revert "Update research provider fallback wording"
This reverts commit
|
||
|
|
c3d9136a0c |
Add live artifacts and Composio connector catalog (#381)
* docs: add live artifacts implementation spec * docs: align live artifacts implementation plan * Ralph iteration 1: work in progress * Ralph iteration 2: work in progress * Ralph iteration 3: work in progress * Ralph iteration 4: work in progress * Ralph iteration 5: work in progress * Ralph iteration 6: work in progress * Ralph iteration 7: work in progress * Ralph iteration 8: work in progress * Ralph iteration 9: work in progress * Ralph iteration 10: work in progress * Ralph iteration 11: work in progress * Ralph iteration 12: work in progress * Ralph iteration 13: work in progress * Ralph iteration 14: work in progress * Ralph iteration 15: work in progress * Ralph iteration 16: work in progress * Ralph iteration 17: work in progress * Ralph iteration 18: work in progress * Ralph iteration 19: work in progress * Ralph iteration 20: work in progress * Ralph iteration 21: work in progress * Ralph iteration 22: work in progress * Ralph iteration 23: work in progress * Ralph iteration 24: work in progress * Ralph iteration 25: work in progress * Ralph iteration 26: work in progress * Ralph iteration 27: work in progress * Ralph iteration 28: work in progress * Ralph iteration 29: work in progress * Ralph iteration 30: work in progress * Ralph iteration 31: work in progress * Ralph iteration 32: work in progress * Ralph iteration 33: work in progress * Ralph iteration 34: work in progress * Ralph iteration 35: work in progress * Ralph iteration 36: work in progress * Ralph iteration 37: work in progress * Ralph iteration 38: work in progress * Ralph iteration 39: work in progress * Ralph iteration 40: work in progress * Ralph iteration 41: work in progress * Ralph iteration 42: work in progress * Ralph iteration 43: work in progress * Ralph iteration 44: work in progress * Ralph iteration 45: work in progress * Ralph iteration 46: work in progress * Ralph iteration 47: work in progress * Ralph iteration 48: work in progress * Ralph iteration 49: work in progress * Ralph iteration 50: work in progress * Ralph iteration 51: work in progress * Ralph iteration 52: work in progress * Ralph iteration 53: work in progress * Ralph iteration 54: work in progress * Ralph iteration 55: work in progress * Ralph iteration 56: work in progress * Ralph iteration 57: work in progress * Ralph iteration 58: work in progress * Ralph iteration 59: work in progress * Ralph iteration 60: work in progress * Ralph iteration 61: work in progress * Ralph iteration 62: work in progress * Ralph iteration 63: work in progress * Ralph iteration 64: work in progress * Ralph iteration 65: work in progress * Ralph iteration 1: work in progress * Ralph iteration 2: work in progress * Ralph iteration 3: work in progress * Ralph iteration 4: work in progress * Ralph iteration 5: work in progress * Ralph iteration 6: work in progress * Ralph iteration 8: work in progress * Ralph iteration 9: work in progress * Ralph iteration 17: work in progress * Add Composio-backed connectors * Add Composio-backed connector catalog * Fix connector callback flow * Update live artifact connector refresh * Fix live artifact refresh updates * Improve live artifact viewer toolbar * Refine live artifact source tabs * Expand Composio connector catalog * Improve Composio connector browsing * Fix artifact refresh source safety checks Generated-By: looper 0.4.1 (runner=fixer, agent=opencode) * Fix live artifacts PR feedback Generated-By: looper 0.5.0 (runner=fixer, agent=opencode) * Fix live artifact preview CORS validation Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix connector OAuth IPv6 loopback hosts Allow bracketed IPv6 loopback Host headers when deriving connector OAuth callback URLs so IPv6-bound daemons can complete connection flow. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Preserve live artifact refresh permissions Respect explicit refresh permission choices during live artifact create and update flows so revoked connector sources remain gated. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact preview cache freshness Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact refresh validation Guard manual refreshes with local daemon checks and reject daemon_tool sources without a toolName before refresh execution. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix Composio credential invalidation Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact CORS methods Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix workspace validation Restore media config test isolation under Vitest setup data-dir overrides and add the missing French live artifact display copy so the workspace test suite stays aligned.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector safety filtering Keep agent-preview connector listings aligned with execution safety policy and prune stale Composio OAuth state records before they accumulate. Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix agent runtime cleanup Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix live artifact daemon access Validate local-only live artifact routes against the peer socket address and pass daemon-resolved CLI paths to ACP MCP descriptors.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector run limit pruning Evict stale connector rate-limit buckets so long-lived daemon processes do not retain per-run entries indefinitely.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector compact schemas Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Improve connector connection feedback * Adjust connector gate positioning * Fix live artifact refresh commits Avoid marking refresh candidates failed after snapshot or state persistence errors by deferring live artifact mutations until the durable refresh metadata is written. Also align connector OAuth callback host validation with daemon loopback handling.\n\nGenerated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Improve connector search relevance * fix(daemon): harden connector connection state Require loopback daemon validation before connector connect side effects and only clear provider-owned connector statuses during credential reset. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): guard connector disconnect route Require local daemon request validation before connector disconnect side effects. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): guard composio config updates Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): dispatch live artifacts mcp first Route the live-artifacts MCP server before the generic MCP CLI so od mcp live-artifacts starts the dedicated server instead of failing generic argument parsing.\n\nGenerated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): handle integer connector schemas Allow JSON Schema integer connector inputs while preserving fractional-value validation so generated connector tool schemas accept valid page sizes and limits. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix: align live artifact refresh error codes Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Fix live artifact connector refresh flow * Update live artifact design cards * Add beta badge to live artifact form * Remove live artifact tile model * Fix live artifact refresh sync * Fix live artifact MCP refresh durability Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Fix live artifact refresh safety Enforce persisted refresh opt-out and connector auto-read gating before refresh sources execute. Generated-By: looper 0.5.5 (runner=fixer, agent=opencode) |
||
|
|
33c3b94b42 |
feat(daemon): add od mcp - expose Open Design as an MCP server (#399)
* feat(daemon): add `od mcp` subcommand for stdio MCP server
Lets a coding agent in a different repo (Claude Code, Cursor, Zed)
pull files from a locally-running OD project over the Model Context
Protocol — no export/import zip dance.
The MCP server is a thin stdio process that proxies read-only tool
calls to the daemon's existing HTTP API; no daemon-side changes
required. Exposes 8 tools:
list_projects, get_project,
list_files, get_file,
list_skills, get_skill,
list_design_systems, get_design_system
Wired exactly like `od media`: a hoisted flag set, a SUBCOMMAND_MAP
entry, a thin handler that resolves OD_DAEMON_URL and hands off to
src/mcp.ts. Tool dispatch is a switch over the tool name; each branch
fetches the matching daemon route and surfaces the response as MCP
text content. Binary mimes return a clear error pending phase-2
support.
Lifecycle gotcha worth flagging: Server.connect(transport) only
*starts* the stdio reader; the promise resolves immediately. Without
holding the function awaiting until transport/stdin close, cli.ts's
top-level process.exit(0) kills the server before the first request
arrives. The fix in src/mcp.ts holds until onclose / stdin EOF.
Wire-up example for a consuming repo:
{
"mcpServers": {
"open-design": {
"command": "od",
"args": ["mcp"],
"env": { "OD_DAEMON_URL": "http://127.0.0.1:7456" }
}
}
}
New dep: @modelcontextprotocol/sdk (MIT, official Anthropic SDK).
* feat(daemon): add MCP server instructions for zero-shot LLM context
Hand the consuming LLM a system-prompt-style overview of the OD
workflow so it picks the right tool without prompt-engineering on
the user's side. Mentions get_artifact and project-name resolution
ahead of their actual implementation; both ship in the same batch.
* feat(daemon): resolve MCP project args by UUID, name, or substring
Lets a consuming agent say `project: "recaptr"` instead of pasting a
UUID. Match order: exact id → exact name (case-insensitive) →
slug-normalized name (strips trailing " (N)", normalizes whitespace) →
substring (errors if multiple). UUID inputs short-circuit and never
hit the daemon.
* feat(daemon): surface entryFile and kind on MCP get_project response
Promote metadata.entryFile and metadata.kind to top-level fields so
consumers (including get_artifact in this branch) can find the entry
without digging through nested metadata blobs.
* feat(daemon): add MCP get_artifact tool for bundle retrieval
A design rarely lives in a single file. get_artifact pulls the entry
HTML/JSX plus every sibling it references (tokens CSS, JSX modules,
imported components) in one call, so a consuming agent doesn't need
to parse HTML and round-trip per file.
Three modes:
auto (default): BFS over relative <script src>, <link href>,
<img src>, <source/video src>, JSX import/from, CSS url(), with
depth cap 3 and a visited set. CDN, data:, mailto:, anchors, and
paths containing .. are skipped.
all: every textual file in the project (mirror of /archive
minus binaries).
shallow: just the entry file (same as get_file).
Output is a structured JSON blob with name/mime/size/content per
file and the project's manifest metadata at the top.
* feat(daemon): add /api/projects/:id/search route + MCP search_files
Server-side substring search across textual project files. Returns
file, 1-indexed line, and snippet, capped at 1000 matches. Exposed
through the MCP layer as search_files(project, query, pattern?, max?).
Treats the query as a literal substring (regex chars escaped) to
avoid catastrophic-backtracking attacks from LLM-supplied input.
Honors the project dir's existing path-safety guards via listFiles.
* feat(daemon): add since= filter to /files route + MCP list_files arg
Lets a consumer poll for "what's changed since I last looked" without
re-walking every file. Daemon-side: parse since= as ms, filter
listFiles output by mtime. MCP-side: forward as URL query.
* feat(daemon): expose skills and design systems as MCP resources
Catalog reads are stable reference material — they fit MCP's
resources surface (LLM-passive) better than tools (LLM-active).
Skills and design systems each become resources at
od://skills/<id>/SKILL.md and od://design-systems/<id>/DESIGN.md;
existing list_skills / get_skill / list_design_systems /
get_design_system tools remain as fallbacks for clients that don't
handle resources cleanly.
* fix(daemon): tighten MCP correctness in get_artifact and resources
Several silent-failure paths and minor footguns the first pass missed:
- get_artifact auto: the entry's own fetch now raises a clear
error instead of returning files: []. Previously a typo in
`entry:` looked like an empty project.
- get_artifact: invalid `include` value returns a clear error
listing the valid modes instead of silently behaving as auto.
- get_artifact all: includes binary files as metadata stubs to
match auto's behavior. Both modes are now strict supersets of
shallow.
- extractRelativeRefs: gate JS-only patterns (import/from/require/
dynamic-import) by file mime/extension so prose in markdown or
HTML doesn't generate spurious 404 round-trips on words like
"imported from 'X'".
- extractRelativeRefs: cover <iframe>, <audio>, srcset, and
CSS @import — common in real OD output.
- resources/list descriptions are collapsed to a single line
(newlines + repeated whitespace -> one space) so MCP UIs that
don't normalize whitespace render cleanly.
- fetchProjectFile: 0-byte binary files no longer report size: null
due to falsy short-circuit on Number(content-length).
* perf(daemon): cache MCP project list for 5s in resolveProjectId
A typical agent session calls list_files/get_file/get_artifact several
times in a row, each with a project name argument. Each previously
re-fetched /api/projects. Cache the list in module scope with a 5s
TTL so back-to-back lookups are local; renames in the OD UI still
propagate within a few seconds.
* feat(daemon): MCP UX polish — tool order, annotations, get_artifact maxBytes
Three changes well-behaved MCP clients pick up automatically:
- Tool ordering. list_projects + get_artifact are now first; LLMs
that weight earlier entries surface the bundle path before
per-file fetching. Catalog tools (list_skills, get_skill,
list_design_systems, get_design_system) sit at the bottom; they
are also exposed as MCP resources.
- readOnlyHint / idempotentHint / openWorldHint annotations on
every tool so clients can skip confirmation prompts on safe
tools and let the LLM know re-running is fine. Per-tool `title`
annotations give clients a friendlier display name than the
snake_case tool id.
- get_artifact gains a `maxBytes` arg (default 1.5MB). Once the
accumulated textual content crosses the cap, remaining files
are dropped and `truncated: true` is set on the bundle so the
consumer knows to use list_files / get_file for the rest.
* feat(daemon): expose user's active OD project/file via MCP
The "what file are you on?" round-trip the agent had to do every
session is now answered automatically. Three pieces:
- Daemon: in-memory active-context slot with 5-minute TTL.
POST /api/active sets {projectId, fileName}; GET /api/active
returns the current value enriched with projectName, or
{active:false} when the slot is empty/stale. Cleared on
daemon restart.
- Web: a small useEffect in App.tsx posts the active project +
file to the daemon on every route change. Best-effort fire-
and-forget; a missing daemon doesn't surface an error.
- MCP: get_active_context tool (no args) and a matching MCP
resource at od://focus/active. The tool is listed second,
right after list_projects, so an LLM picks it up before
asking for ids. Server instructions tell the model to call
it FIRST when the user says "this file" / "the design I have
open" / "what I'm looking at."
End to end: user opens a project in OD, agent in another repo
calls get_active_context() → gets {projectName: "recaptr",
fileName: "recaptr-onboarding-4.html"}, then immediately calls
get_artifact(project: "recaptr") with no further user input.
* feat(daemon): make MCP project arg optional, fall back to active OD context
get_artifact, get_project, get_file, search_files, and list_files now
accept project as optional. When omitted, the MCP resolves project
from /api/active so an agent in another repo can call
search_files({ query: "Polaroid" })
without first asking the user "which project?". get_file and
get_artifact also default their path/entry to the active file, so
get_file({}) returns whatever the user is currently looking at.
The implicit path stamps `usedActiveContext` on JSON responses (or a
separate `[od:active-context …]` content block on get_file) so the
agent can see exactly which project/file got chosen. Explicit
project args pass through with zero added overhead.
Cuts the common case from two MCP round trips
(get_active_context → search_files) to one. Server instructions and
get_active_context's own description are updated to point at the
new default.
* fix(daemon): require same-origin for /api/active POST and GET
The active-context endpoint was added without isLocalSameOrigin
guard. Since the daemon binds 0.0.0.0 by default, a LAN peer could
GET it to learn what file the user has open, or POST it to redirect
the MCP fallback to a project of their choice. Same-origin only is
the right scope: the web app proxies its requests through Next.js
on the daemon port, and the MCP runs over loopback in-process, so
both legitimate callers pass.
Pattern matches the existing /api/app-config etc. guards.
* feat(daemon): add /api/mcp/install-info for cross-platform install snippets
The Settings -> MCP server panel needs absolute paths to node and
the daemon's built cli.js so it can render snippets that work on a
fresh source clone (where `od` is not on PATH) and dodge the
/usr/bin/od octal-dump tool that ships on macOS/Linux and would
otherwise shadow ours.
Endpoint returns:
- command: process.execPath (the node binary running the daemon)
- args: [<absolute path to dist/cli.js>, "mcp"]
- daemonUrl: http://127.0.0.1:<port>
- platform: process.platform (so the panel can localize ~/.cursor
vs %USERPROFILE%\.cursor and Cmd vs Ctrl shortcuts)
- cliExists / nodeExists: existsSync checks on both binaries
- buildHint: human-readable build/reinstall instructions when
either path is missing
isLocalSameOrigin guard same as /api/active. Cached for 5s because
the panel may re-fetch on every open and the paths cannot change
without a daemon restart.
Test file covers the happy path, cross-origin rejection, two
allowed-Origin variants, and the cache by counting fresh resolves
across rapid calls. 5/5 pass.
* refactor(daemon): tighten MCP surface, trim descriptions, polish copy
Three intertwined cleanups that all live in mcp.ts + cli.ts:
1. Drop catalog tools from MCP. list_skills / get_skill /
list_design_systems / get_design_system are removed. The audience
is a coding agent in a separate repo consuming Open Design's
output; it cannot run skills (those are recipes Open Design uses
to generate) and design-system DESIGN.md is reference material
that already ships as an MCP resource. Keeping the catalog as
tools cost ~350 token-overhead per turn for capabilities the
agent could not act on. Tool count: 11 -> 7.
2. Trim tool descriptions. The active-context fallback explanation
was repeated in 5 separate tool descriptions; hoisted into
PROJECT_ARG and explained once in the server `instructions`
block instead. Saves ~150-200 tokens per tools/list response.
3. User-facing branding pass. Tool titles, tool descriptions,
resource names, error messages, comments, and `od mcp --help`
now consistently use "Open Design" rather than "OD". Internal
abbreviation `OD` is retained only inside the server
instructions block where it is introduced inline as "Open Design
(OD)" for compactness across multi-paragraph guidance.
Em dashes replaced with hyphens throughout, per project style.
* feat(web): add MCP server install panel in Settings
New "MCP server" section in the Settings dialog, surfacing
copy-paste install snippets for the major MCP-compatible coding
agents (Claude Code, Cursor, VS Code, Antigravity, Zed, Windsurf).
Highlights:
- In-brand custom dropdown (reuses the existing .ds-picker
pattern from the design-system / prompt-template pickers, click
outside / Escape to close, chevron animates) instead of a
native <select>.
- Per-client snippet that uses absolute paths to node + cli.js
fetched from /api/mcp/install-info on mount, so it works even
when `od` is not on PATH.
- Cursor gets a one-click "Install in Cursor" deeplink
(cursor://anysphere.cursor-deeplink/mcp/install) that pops an
approval dialog and writes the config for the user. UTF-8-safe
base64 so paths with accented characters do not throw.
- Per-OS path hints (~/.cursor on POSIX, %USERPROFILE%\.cursor
on Windows) and keyboard shortcuts (Cmd vs Ctrl).
- Build-required warning card when cli.js or the node binary
does not exist on disk; deeplink button disables in that state.
- Prominent "restart your client to pick up the new server"
callout below the snippet, with per-client guidance.
- Capability list ("what your agent can do") instead of a tool-
name dump, so non-developer designers can also tell what is
possible without reading MCP docs.
README adds a short "Use Open Design from your coding agent"
section that points at the panel and summarizes the per-client
flow (one-click for Cursor, JSON merge elsewhere). Read-only by
design; the daemon must be running locally.
* docs(readme): align MCP server section with the Settings panel
The "Use Open Design from your coding agent" section had drifted
from what the panel actually emits and lists.
- Add Antigravity to the supported-client list (previously missing).
- Drop the "(GitHub Copilot)" parenthetical from VS Code so the
label matches the panel.
- Fix the Claude Code line: we no longer emit a single
`claude mcp add ...` shell command. The snippet is JSON; the
panel additionally suggests `claude mcp add-json` as the safer
way to apply it instead of hand-editing ~/.claude.json.
- Swap the "find the Polaroid section" example for two more
universal phrases ("build this in my app", "match these
styles") that match what the panel surfaces.
- Add a one-line "restart or reload your client after install"
note - this was prominent in the panel and absent from the
README.
- Trim the /usr/bin/od octal-dump aside; it was technical detail
that did not earn its space at the README intro level.
* feat(web): add Codex CLI to the MCP server install panel
Codex is a first-class supported coding agent (listed alongside
Claude Code, Cursor, etc. in the README's PATH-detected agent
table) but the install panel was missing it.
Codex stores MCP server config at ~/.codex/config.toml (TOML, not
JSON) under an `[mcp_servers.<name>]` table, and the same file is
shared between the Codex CLI and the Codex IDE extension - so one
install covers both. Added a 7th client entry that emits the right
TOML snippet, expanded the snippet-lang union to include 'toml'
(behaves like 'json' for whitespace handling, just a different
syntax-highlight hint).
For our minimal payload (just command + args), JSON.stringify
happens to produce valid TOML literal values since TOML basic
strings use the same double-quote escape rules as JSON, and TOML
inline arrays match JSON array syntax. No new TOML serializer
needed.
README updated to list Codex among the supported clients.
Schema verified against https://developers.openai.com/codex/mcp.
* fix(daemon): accept any loopback origin in same-origin guard
The previous port-pinned check required the request's Origin to match
either the daemon's own port or OD_WEB_PORT. tools-dev does not pass
OD_WEB_PORT to the daemon process, so any browser POST to /api/active
proxied through the dev web (port 17573 etc.) was rejected with 403,
and get_active_context always returned {active: false}.
Relax to a loopback-prefix match: any http://127.0.0.1:*,
http://localhost:*, or http://[::1]:* origin passes regardless of
port. Cross-origin (https://evil.com) is still rejected. The
trade-off is that another local web app on a different loopback port
could now CSRF the daemon; same-origin checks are inherently a CSRF
defense, not a network ACL.
* fix(web): make Claude Code MCP snippet a real copyable one-liner
claude mcp add-json open-design '<json>' takes only the inner
server-config object, not the full {"mcpServers": ...} wrapper, and
rejected the wrapped shape with "Invalid configuration: : Invalid
input". Pass only the inner config, and inline the JSON into the
command itself so the snippet is a real one-liner the user can copy
and paste, no template substitution.
* test(daemon): drop loopback-prefix assertions superseded by upstream origin policy
The two proxy-flow allow tests were added in
|
||
|
|
339a57c65c |
fix(security): bind daemon to localhost by default, add origin validation (#365)
* fix(security): bind daemon to localhost by default, add origin validation middleware The daemon's Express server previously defaulted to binding 0.0.0.0, exposing all 30+ API endpoints to the local network with zero authentication. This included endpoints that spawn CLI agents, write project files, and manage API keys. Changes: - Default bind address changed from 0.0.0.0 to 127.0.0.1 in both server.ts and cli.ts. Users who need network access can still set OD_BIND_HOST=0.0.0.0 explicitly. - Added origin validation middleware on /api/* routes: requests with an Origin header are only allowed from localhost/127.0.0.1/[::1] on the daemon's own port. Non-browser clients (no Origin header) are unaffected. - 7 unit tests for the origin validation logic. - Existing tests: 327/327 passing. * fix: address PR review — fail-closed, OD_WEB_PORT, HTTPS, Origin: null Address feedback from @lefarcen, @mrcfps, and Codex review: P1: Fail-closed when resolvedPort is not yet set (returns 403 instead of passing through). P2: Include OD_WEB_PORT in allowed origins for split-port proxy setups (web port ≠ daemon port). Add HTTPS variants. P3: Exempt Origin: null for sandboxed iframe preview fetches (/api/projects/:id/raw/*) so artifact previews keep working. P4: Update help text from 0.0.0.0 to 127.0.0.1. Test coverage expanded to 13 tests including: - OD_WEB_PORT split-port proxy scenario - Origin: null iframe preview - HTTPS origin variants - Fail-closed before port resolution - Cross-origin rejection with OD_WEB_PORT set All 333 tests passing, TypeScript clean. * fix: scope Origin: null bypass to raw-file previews only, support non-loopback bind host Two issues found in second review round: 1. Origin: null was a global bypass for ALL /api routes, allowing sandboxed iframes to reach state-changing endpoints (project create/delete, agent runs). Now only GET requests to /projects/:id/raw/* pass through with Origin: null — the original intent for iframe file previews. POST/DELETE with Origin: null are rejected. 2. Allowed origins only included loopback addresses. When daemon binds to a non-loopback address (--host for Tailscale, LAN, or 0.0.0.0), browser requests from that address would get 403. Now the bound host is included in allowed origins alongside loopback, keeping the documented network-access escape hatch working for browser clients. Added negative tests for Origin: null on POST/DELETE/non-raw GET, and positive tests for non-loopback bind host scenarios. All 339 tests passing. * fix: centralize origin policy, add spritesheet to Origin: null allowlist Addresses @mrcfps's third review round: 1. isLocalSameOrigin() now uses the same policy as the global origin middleware: HTTPS + HTTP, OD_WEB_PORT, and the explicit bind host (OD_BIND_HOST). Previously it only accepted HTTP on loopback hosts, so requests from https://127.0.0.1 or a Tailscale address could pass the global guard but 403 on per-route checks. 2. /api/codex-pets/:id/spritesheet is a read-only route that sets Access-Control-Allow-Origin: null for canvas drawing by sandboxed iframes. Added to the Origin: null allowlist so the middleware doesn't block it before the route handler runs. 3. buildAllowedOrigins() extracted as a closure so both the middleware and isLocalSameOrigin() share identical logic. 340/340 tests passing. * test: remove dead fail-closed test with unused 5th argument The 'fails closed when port is 0' test called request() with an extra argument the helper ignores, then never asserted on res. Real coverage lives in the dedicated 'fail-closed before port resolution' describe block. |
||
|
|
71370fd9dd |
feat(daemon): add OD_BIND_HOST env var and --host flag for interface binding (#328)
Adds a `host` option to `startServer()` (sourced from `OD_BIND_HOST` env or `--host` CLI flag, defaulting to `'0.0.0.0'` to preserve existing behavior) and wires it through `app.listen(port, host, ...)`. This lets operators restrict the daemon to a single network interface — e.g. a Tailscale IP — for tailnet-only deployments. Without this knob the daemon always bound to all interfaces with no override path. Backward-compatible: the default `'0.0.0.0'` matches current behavior. The reported URL switches from the hardcoded `127.0.0.1` to the actual bound address when a specific interface is requested. Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
8c61e43c44 |
Added Devin for Terminal (#301)
* added Devin for Terminal * updates based on PR feedback |
||
|
|
96db795d7d |
docs: fix spelling mistakes in CLI comment, spec, and video prompt (#300)
* fix: correct cli typo comment * docs: fix spec typo * fix: correct video prompt typo |
||
|
|
3f266103b0 |
feat(media): port generation workflow onto main (#12)
Co-authored-by: Elian <elian@EliandeMacBook-Pro.local> |
||
|
|
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. |