@wnzzer/agentdock 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wnzzer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # AgentDock
2
+
3
+ A host-native workspace for official Claude Code / Codex clients, built with Rust + Vue 3 + TypeScript. Light UI, recursive split/tab docking, first-class Git review, files and optional terminals. No Docker requirement.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i -g @wnzzer/agentdock # or: npx @wnzzer/agentdock
9
+ agentdock
10
+ ```
11
+
12
+ One prebuilt binary per platform, carrying the Web client and the native bridge inside it. npm fetches only the one matching this machine, through `os`/`cpu` on its optional dependencies; there is no postinstall step, so `--ignore-scripts` installs work. Prebuilt for macOS (arm64, x64) and Linux (x64, arm64, static musl). Other platforms build from source below.
13
+
14
+ Node is a requirement rather than an extra: the native-history and conversation bridges run as Node subprocesses, and Claude Code and Codex are themselves installed from npm.
15
+
16
+ Tarballs with a `SHA256SUMS` are attached to each [release](https://github.com/wnzzer/agentdock/releases) for installing without npm.
17
+
18
+ ## Build from source (macOS / Linux)
19
+
20
+ Requires Rust stable (1.89+), **Node.js 24+** and **pnpm 10.30.3**. `.nvmrc` / `.node-version` and CI use Node 24; an installed newer Node is also supported by the project engine range. Install Claude Code and/or Codex separately.
21
+
22
+ ```sh
23
+ pnpm install --frozen-lockfile
24
+ pnpm run build:web
25
+ cargo run -p agentdock-server
26
+ ```
27
+
28
+ Open **http://127.0.0.1:8787/**. The Rust server serves the built Web client and API on the same origin.
29
+
30
+ For development, run `pnpm run dev` to start Cargo + Vite, then open **http://127.0.0.1:5173/**. If Rust is already running, use only `pnpm run dev:web`. Vite proxies `/api` and WebSockets to Rust. pnpm manages the workspace and dependencies; Vite, Vue SFC typechecking, tests and the native-history bridge run under Node. Rust builds still use Cargo.
31
+
32
+ The previous Bun lockfile and version pin are retained under `docs/toolchain-history/` as historical evidence, not an active toolchain. Do not use them for current installs. In the observed macOS debugging case, the backend WebSocket opened directly but timed out through Bun-run Vite; running Vite under Node restored the proxy handshake. The existing development frontend on 5173 was switched to Node without restarting the running backend on 8787 or its Agent processes.
33
+
34
+ Choose an existing host directory in the workspace picker, then create/open a session. New Web-created Agent sessions use structured conversation cards on a capable backend; existing PTY sessions keep their original interface. Tool approvals remain native decisions, rendered by the Web client. **Interrupt** cancels current work, while **End session** remains a separate, confirmed secondary action. Closing a pane never ends its process.
35
+
36
+ ## What works in the MVP
37
+
38
+ Current implementation includes Chinese/English UI, the shared split/tab canvas, native structured conversation adapters, account/configuration management and first-class file/Git panes. Implementation and fixture coverage do not mean every live provider/account flow has been exercised; deployment-specific verification stays in [the acceptance record](docs/mvp-status.md).
39
+
40
+ - Recursive horizontal/vertical splits, drag-to-edge docking, center-drop tabs, resize/snap, 1:1 / 2×2 / 1:2:1 presets, maximize and restore.
41
+ - Below 280×180, panes become tabs without overwriting the saved layout. Sessions and in-memory file/commit drafts survive view remounts.
42
+ - Workspace registry and fuzzy-searchable global sessions; opening connects, while ending remains an explicit secondary action. Refreshing a stopped session does not restart it.
43
+ - Two-level workspace → session navigation, with one shared canvas across projects. Expanding/selecting a workspace does not replace existing panes. Files and Git actions stay bound to each pane's workspace; the explorer follows focus or can be pinned.
44
+ - **Load existing session** lists native Codex/Claude Code history belonging to the chosen workspace, supports fuzzy search, and links a selected history after confirmation. It resumes history, not an already-running external terminal.
45
+ - Structured Agent messages, folding tool cards, native approval/question cards, usage and turn status, with responsive controls for narrow layouts. Rust supervises a bounded Node JSONL bridge: Codex uses official `app-server`; Claude Code uses the user's existing CLI `stream-json` control interface. Neither adapter implements an Agent loop.
46
+ - Claude Code/Codex legacy PTY sessions and optional host-shell terminals remain available. A live PTY is never silently taken over by structured chat. Disconnect/reconnect preserves its running process.
47
+ - Confirmed, same-client endpoint/configuration switching while idle: close the old bridge, use a fresh native conversation and configuration generation, and retain earlier UI history without forwarding it or the old environment to the new endpoint.
48
+ - Process state and stream connection state are displayed separately. An 8-second WebSocket handshake watchdog reports an actionable connection failure instead of staying “connecting”; it does not automatically retry, restart a process, or replay user input.
49
+ - Custom profiles keep per-session endpoint snapshots, model and permission-intent mapping. Profile edits affect future sessions only.
50
+ - Advanced environment editors for profile defaults, new sessions, history loading and existing sessions. Host environment inheritance remains process-local; explicit overrides are validated and stored separately.
51
+ - **Import existing configuration** adds a reusable reference to the host's existing Codex/Claude Code home. New sessions can reuse its login, model, endpoint and native settings without copying credentials. This shared reference is explicitly different from an isolated custom profile.
52
+ - Profiles can fetch model IDs explicitly: native Codex uses app-server `model/list`; custom endpoints use the read-only models API. Manual model IDs/aliases are always available. Account access can differ from catalogue visibility.
53
+ - A new isolated/custom-profile session can override its model without changing its profile or other sessions. A host-reference session keeps its native model settings; an optional advanced process-environment overlay never writes back to the source configuration.
54
+ - Lazy expandable file tree with keyboard navigation and per-workspace remembered expansion, plus **Reveal in file tree** on previews.
55
+ - **Syntax highlighting and rendered Markdown** in the file pane. A `.md` file opens rendered, with its source one click away; code files are highlighted behind the editor, so editing and colour are not a choice between two modes. The highlighter and each grammar load on demand — a TypeScript file fetches about 11 kB and nothing else does — and a file past 512 kB stays plain rather than stuttering on every keystroke.
56
+ - **Workspace-wide file search**, in the tree and as `@path` completion in the composer. It uses the Codex app-server's own index, which honours `.gitignore` so build output and dependencies stay out, and which needs no account — verified against an empty `CODEX_HOME`. It therefore runs against a configuration directory holding no credentials, and is available to any session, not only Codex ones. Without Codex installed the tree falls back to filtering the entries it has already loaded, and says which of the two it is doing.
57
+ - Text edit/save with version conflicts, image/video/audio/PDF browser previews and download.
58
+ - First-class Git status/diff, staged/unstaged groups, file/all staging, unstaging and explicit commit.
59
+ - SQLite WAL metadata, schema 9, persisted layouts and sequenced conversation events. The recent transcript window is bounded; control anchors and pending approvals survive display-window trimming. UUID/SHA-256 submission receipts prevent replay across reconnects/restarts.
60
+ - Official-account records with private native config directories. Codex browser/device login, cancellation, token refresh, logout, available official quota information and eligible earned reset credits use the official client APIs. Claude login remains under the official client; usage is an explicit read of the official OAuth usage endpoint, while login/token refresh and quota reset remain unavailable. See [official account boundaries](docs/official-accounts.md).
61
+ - Local Host/Origin/CSRF checks; optional access-token login and HttpOnly cookie for private remote use.
62
+
63
+ ## State and credentials
64
+
65
+ New installations initialize state at **`~/.agentdock/`**, independently of project directories. Run **`pnpm run init`** (not `pnpm init`, which is pnpm's package-initialization command), or `agentdock-server init` for a built binary; first server startup can also initialize it. This creates state only, not a system service or a downloaded installation.
66
+
67
+ Path priority: `AGENTDOCK_STATE_DIR` → `AGENTDOCK_HOME` → an existing `./.agentdock/agentdock.db` for legacy compatibility → `~/.agentdock`. Existing local data is never silently moved. Set `AGENTDOCK_HOME` explicitly to use the home directory while running from an older checkout. Keep the selected state directory between restarts:
68
+
69
+ ```text
70
+ ~/.agentdock/
71
+ ├── agentdock.db
72
+ ├── sessions/<session-id>/ # generated native CLI configuration/history
73
+ │ └── configurations/<revision>/ # fresh isolated home after confirmed configuration switches
74
+ └── accounts/<account-id>/ # private manifest and native-owned account configuration
75
+ ```
76
+
77
+ Configuration directories are 0700, generated Codex config files are 0600. The native client manages its login cache. These paths can contain credentials; don't commit/share them. Use SQLite Online Backup for the DB and protect backups of native state separately.
78
+
79
+ API-key profiles currently use a **reference**, e.g. `env:AGENTDOCK_SECRET_WORK`. Set that environment variable for the server; never enter the key into the profile form. AgentDock resolves the selected reference on the backend and injects its value into the selected child-process destination variable.
80
+
81
+ New sessions without a host-reference profile use separate generated native configuration directories. **Loaded native histories are different:** resuming uses the original client configuration/login/history directory, after explicit confirmation. These loaded sessions share their source account/configuration, do not copy credentials into AgentDock, and do not add endpoint/model/permission-policy overrides. Structured mode supplies the required stdio transport flags separately. Explicit advanced environment overrides are optional. Metadata listing uses official SDK/app-server APIs, makes no model request, returns at most 500 workspace-scoped items, and reports truncation. Missing/incompatible native clients produce an actionable error rather than scraping terminal output.
82
+
83
+ ### Reuse the host's existing configuration
84
+
85
+ In **Endpoint profiles → Import existing configuration**, choose the host's Codex or Claude Code source, name it, and confirm shared configuration. Then choose that profile when creating a new session. Repeated imports return the same profile instead of duplicating it.
86
+
87
+ Importing also selects that profile for future new sessions of this client in the current browser. New-session dialogs remember the last successfully used configuration per provider. Without a saved choice, one imported host profile is preselected; multiple imported profiles require an explicit choice. An explicitly chosen isolated configuration remains available and is remembered. Refreshing the profile list never silently replaces a valid account already displayed in an open form.
88
+
89
+ Importing **does not rebind existing sessions**. If a session still asks for login, check its configuration badge: an isolated session uses a separate login environment even when a host profile exists. Create a new session with the imported host profile to reuse its valid sign-in. The UI now distinguishes this case explicitly.
90
+
91
+ - Discovery checks directory availability only. It does not inspect credential contents, claim that login is valid, launch a client, or perform inference.
92
+ - Source resolution follows the same deployment settings as native history: `AGENTDOCK_CODEX_HISTORY_DIR` → `CODEX_HOME` → `~/.codex`, and `AGENTDOCK_CLAUDE_HISTORY_DIR` → `CLAUDE_CONFIG_DIR` → `~/.claude`. These are the **server user's** directories, not the browser machine's.
93
+ - A reference pins the provider, source ID, canonical directory and original directory-environment context. A changed/deleted source is rejected at create/start. The **directory's contents remain live**, not an immutable copy; native configuration changes can affect subsequent starts.
94
+ - The original unset-versus-explicit `CODEX_HOME`/`CLAUDE_CONFIG_DIR` state is preserved. On macOS, explicitly setting even the default Claude directory can select a different Keychain login context. Explicit absolute paths keep their original spelling; relative directory variables are rejected because the workspace changes the child's working directory.
95
+ - AgentDock neither creates a new config home nor rewrites the source settings. The native client still manages its own credential refresh and conversation history. Existing login is reused when valid; reauthorization can still be required by the provider.
96
+ - Host-reference profiles support rename, advanced environment defaults and removal of the reference. Direct endpoint/model/proxy/permission fields and the native source identity remain read-only. Removing one never deletes the native home, logs out the account, or removes snapshots from existing sessions.
97
+ - Native clients inherit the backend process's environment, excluding AgentDock's private secret namespace/access token and required native-context removals. AgentDock does not source shell startup files or import aliases, shell functions, temporary exports or flags from another terminal. There is no generic import/conversion of CLIProxyAPI token JSON.
98
+
99
+ This is an explicit **shared native configuration reference**, not a copied account or a claim of process-level credential isolation. The separate official-account manager creates its own private account directories; imported host references retain their existing source directory. Each new session gets its own process/conversation; loading a specific old conversation remains **Load existing session**. Managed account/profile ownership must not be broken by deleting its profile independently.
100
+
101
+ ### Structured conversations and retained history
102
+
103
+ The Web client requests `interaction_mode: "structured"` for new Agent conversations when `structured_chat` is advertised. Omitting the field in the HTTP API still defaults to `pty` for older callers. A stopped legacy Agent session may explicitly opt into chat; a running PTY must first be ended by its user. Ordinary view remounts do not restart stopped sessions.
104
+
105
+ Chat initialization does not inject a prompt. Codex starts/resumes its thread only after an explicit message; Claude uses its installed native CLI and existing settings rather than an SDK OAuth/login proxy. Native startup hooks/settings remain native behavior. Tool permission defaults are not bypassed; unsupported interactions fail closed. Claude's noninteractive `--print` mode skips its interactive workspace-trust dialog, so use registered directories you trust.
106
+
107
+ SQLite schema 9 assigns monotonic event sequences, stores endpoint reasoning defaults, and retains a recent 2,000-event / 8 MiB display window, plus the latest control anchors and at most 32 unresolved approvals. These extra anchors mean a snapshot can exceed the recent window's event count. Submission receipts contain message UUIDs and content SHA-256 hashes rather than another full prompt copy; receipts are not discarded merely because visible history was trimmed. Input is persisted before dispatch and is never automatically replayed after an uncertain outcome.
108
+
109
+ The Node bridge limits text fields to 64 KiB, marking truncated text, and serialized output lines to 192 KiB; the Rust receiver also enforces its own frame limits. Reconnection restores stored events, not a lost live process. **Imported native history currently supplies resume context to the CLI; its older full transcript is not backfilled into the structured Web view.** Do not mistake an empty imported Web transcript for a newly empty native conversation.
110
+
111
+ See [structured UI implementation and limitations](docs/structured-agent-ui.md) for the protocol and configuration-switch semantics.
112
+
113
+ ### Advanced environment configuration
114
+
115
+ Expand **Advanced environment** in an endpoint profile, new-session form or native-history loader. To inspect an existing session without launching it, use its sidebar settings gear or the pane's session-actions menu. A running session is read-only here; only `stopped` / `failed` sessions can save changes. Saving never starts, stops or restarts a process. Changes apply at its next explicit launch.
116
+
117
+ - Profile environment defaults are merged with new-session overrides and snapshotted into that session's effective explicit map. Later profile edits do not change existing sessions. Editing an existing session **replaces the entire effective map**, not a partial merge.
118
+ - History loading with no overrides omits the environment field and preserves an already-imported session's map. Repeating an import with different explicit overrides returns a conflict (409); it never silently changes a running session.
119
+ - The inherited backend environment is not copied into SQLite or exposed by the editor. Another terminal's exports, shell startup configuration and an old session's temporary environment cannot be reconstructed from history. Native configuration files retain the CLI's own precedence; an environment overlay does not rewrite those files or promise to override every native setting.
120
+ - **Literal** assigns the exact value: `$PATH`, `${NAME}`, `~` and command-looking text are not shell-expanded. Literal values are plaintext local metadata, so never enter credentials there. **Secret reference** accepts only `env:AGENTDOCK_SECRET_NAME`; configure that variable for the backend and it is resolved only at launch, never returned as an editor value. **Unset** explicitly removes a child-process variable.
121
+ - Deleting an override is not the same as **Unset**. In a new-session draft it reveals any profile default; in an existing session's replacement map it drops that explicit value and leaves the base launch environment to apply. Native config-file settings still follow native-client behavior.
122
+ - Names use `[A-Za-z_][A-Za-z0-9_]{0,127}`. `HOME`, `USERPROFILE`, `PWD`, `OLDPWD`, `CODEX_HOME`, `CLAUDE_CONFIG_DIR`, `CLAUDECODE` and all `AGENTDOCK_*` names are reserved, case-insensitively. Names containing `TOKEN`, `SECRET`, `PASSWORD`, `PRIVATE_KEY`, `API_KEY` or `AUTHORIZATION`, and proxy/base URLs containing user information, require a secret reference instead of a literal value (or may be unset).
123
+ - Limits: 64 explicit entries and 64 KiB of serialized JSON; literal and resolved secret values are at most 8192 UTF-8 bytes and cannot contain NUL. Profile defaults and per-session overrides must also fit the limits after merging.
124
+
125
+ An optional interactive **Terminal** still follows its shell's own startup-file behavior; that does not make those files or an old terminal's exports an imported native-session snapshot.
126
+
127
+ SQLite schema 6 adds explicit environment maps with empty defaults, preserving older records and snapshots. The backend advertises `session_environment` in `/api/health`; editors are disabled with an upgrade explanation when it is absent. Updating frontend files alone does not enable this API on an already-running old backend. Upgrade that backend through an orderly restart after saving/ending its active native sessions; do not interrupt them merely to enable the editor.
128
+
129
+ ```text
130
+ AGENTDOCK_DB # optional database path
131
+ AGENTDOCK_HOME # installation/state home; default ~/.agentdock for new installs
132
+ AGENTDOCK_STATE_DIR # optional persistent state directory
133
+ AGENTDOCK_ADDR # default 127.0.0.1:8787
134
+ AGENTDOCK_WEB_DIR # state-dir/web if installed, else source apps/web/dist
135
+ AGENTDOCK_NATIVE_BRIDGE # optional path to packages/native-bridge/history.mjs
136
+ AGENTDOCK_JS_RUNTIME # native helper/chat/account runtime; default node (absolute path supported)
137
+ AGENTDOCK_CHAT_BRIDGE # optional path to packages/native-bridge/chat.mjs
138
+ AGENTDOCK_ACCOUNT_BRIDGE # optional path to packages/native-bridge/account.mjs
139
+ AGENTDOCK_NODE_BIN # legacy runtime override, used only if JS_RUNTIME is unset/empty
140
+ AGENTDOCK_CODEX_HISTORY_DIR # optional history source; otherwise CODEX_HOME or ~/.codex
141
+ AGENTDOCK_CLAUDE_HISTORY_DIR # optional history source; otherwise CLAUDE_CONFIG_DIR or ~/.claude
142
+ AGENTDOCK_CLAUDE_BIN # optional absolute path to claude
143
+ AGENTDOCK_CODEX_BIN # optional absolute path to codex
144
+ AGENTDOCK_SHELL # optional shell; defaults to SHELL or /bin/sh
145
+ AGENTDOCK_BROWSE_ROOTS # optional directory-picker roots, OS path-list (macOS/Linux colon-separated)
146
+ AGENTDOCK_WORKSPACE_ROOTS # optional roots a new workspace may sit under; defaults to the browsing roots
147
+ AGENTDOCK_INSTANCE_LABEL # optional UI label for isolated preview deployments
148
+ ```
149
+
150
+ ## Private remote access
151
+
152
+ Simplest: keep loopback binding and use SSH port forwarding, `ssh -L 8787:127.0.0.1:8787 user@server`.
153
+
154
+ For a network bind, configure `AGENTDOCK_TOKEN` (24+ random characters), `AGENTDOCK_ALLOWED_ORIGINS=https://your-host`, and an HTTPS reverse proxy that preserves Host and WebSocket upgrades. Then sign in using the token in the Web UI. Do not expose this trusted-host workspace to untrusted users.
155
+
156
+ ## Boundaries
157
+
158
+ This is a **single trusted user's host workspace**, not a multi-tenant sandbox. Native tool permissions remain native. A working-directory check or config directory is not an OS isolation boundary.
159
+
160
+ ### What this server can reach
161
+
162
+ - **Network**: loopback only by default. A non-loopback bind refuses to start without `AGENTDOCK_TOKEN` (24+ characters), and Origin/Host must be allow-listed.
163
+ - **Directory picker**: limited to `AGENTDOCK_BROWSE_ROOTS`, defaulting to the working directory and the server user's home.
164
+ - **New workspaces**: limited to `AGENTDOCK_WORKSPACE_ROOTS`, defaulting to the browsing roots. Workspaces created before this rule keep working; it governs new ones.
165
+ - **File read/write**: confined to a workspace root. Paths are canonicalised and anything resolving outside is refused, as are `.git`, `.agentdock` and client configuration files. Deleting never follows a symlink out of the tree.
166
+ - **Agent processes are not confined by any of the above.** `claude` and `codex` run with your full user permissions. AgentDock sets their working directory and forwards their permission prompts; it never answers one for you, and it never reads their credentials. What an Agent can reach is decided by that client's own permission settings, not by this server.
167
+
168
+ Anyone who can reach the API has the authority of the user running the server. Treat the token as that user's credentials.
169
+
170
+ - Browser disconnection preserves processes; server shutdown stops managed processes. Restart marks old running records stopped. It does not revive a lost PTY.
171
+ - State and database ownership locks prevent two new-version servers from managing the same sessions. Port binding and ownership checks happen before migration/reconciliation. `init` also respects these locks and never resets running-session status. Keep state on a local filesystem with working OS file locks; do not remove lock files while a process is alive.
172
+ - Terminal replay is the most recent 1 MiB in memory, not a durable transcript. After a server restart use the native client's history/resume workflow.
173
+ - Model-generation and paid API requests are not part of the automated tests; sign in or supply your own provider reference.
174
+ - No custom Agent reasoning loop, token-exchange server, provider reverse proxy, Keychain editor, automatic account import, strong cross-process credential isolation, hunk staging, Git network/PR workflow, LSP or computer-desktop control in this MVP.
175
+ - Media playback depends on browser codecs. Text editing limit: 2 MiB. Large Git output is rejected; no silent truncation.
176
+ - Common proxy support is HTTP/HTTPS without inline passwords. Claude Code does not support SOCKS. Empty proxy follows host settings; explicit profiles override inherited proxy variables for that process only.
177
+ - Model listing never performs inference. HTTP requests have time/body limits and do not follow redirects with credentials; non-compatible endpoints keep manual model entry as fallback.
178
+ - Resource guardrails bound layout depth/nodes, event windows and runtime replay. Managed process groups receive bounded cleanup; deliberately detached daemons remain outside that group boundary.
179
+ - macOS has been run locally. Linux has a CI target, not a claim of a completed deployment here.
180
+
181
+ ## Verify
182
+
183
+ ```sh
184
+ cargo fmt --all -- --check
185
+ cargo clippy --workspace --all-targets -- -D warnings
186
+ cargo test --workspace
187
+ pnpm run check
188
+ pnpm run build:web
189
+ ```
190
+
191
+ See [API contract](docs/api.md) and [acceptance record](docs/mvp-status.md). Earlier design documents describe the broader roadmap, not finished features.
192
+
193
+ ### Read-only UI preview and deployment caution
194
+
195
+ With the development frontend running, `http://127.0.0.1:5173/ui-preview.html` renders the actual UI components against clearly labeled local snapshots. It does not call the user's Agent backend. Its 390px container previews narrow-screen layout; it is **not** a real-phone or touch-device acceptance test.
196
+
197
+ The existing 5173/8787 development installation has four user-owned active sessions; do not restart its backend or end those sessions merely to expose new capabilities. Use an explicitly separate state/database/port for feature previews (8788 is the designated preview port), and record what was actually verified there. Do not infer live OAuth success, a paid model turn, Linux deployment or mobile-device acceptance from compiled code, fixtures or the read-only preview.
198
+
199
+ ## Shared workspace canvas
200
+
201
+ The sidebar groups sessions directly under expandable workspaces. File, Git and new-session shortcuts belong to each workspace; provider/account/branch information does not add extra navigation levels. Sessions from any workspace can be opened or dragged into the same split/tab layout. Workspace selection only changes the navigation/new-session target, not the existing canvas.
202
+
203
+ Every bound pane includes an explicit workspace ID. File IDs include both workspace and relative path, so two `README.md` files cannot overwrite each other's view. Each Git pane has a fixed repository; changing sidebar selection never redirects staging or commits. Pane headers show the workspace, and the explorer can follow focus or stay pinned. Layout manipulation still never terminates an Agent.
204
+
205
+ New servers advertise `shared_canvas` through `/api/health` and store one revisioned layout in the singleton introduced by SQLite schema 5. Concurrent saves use compare-and-swap; a conflict keeps the current local copy and offers loading the server layout or explicitly saving the current one. First use seeds the shared canvas from the previously selected workspace's legacy layout when no shared/local layout exists. The old per-workspace layouts are never overwritten or deleted by this migration.
206
+
207
+ On an older running backend, the UI remains usable without restarting its sessions: the shared canvas is saved in this browser, visibly labeled as such, scoped by origin and the oldest workspace registration. It does **not** issue unsupported shared-canvas requests or overwrite a project's old layout. When local storage is unavailable the UI says **Memory only**. An updated backend is still required for native-history loading, configuration import, folder/model discovery and environment editing; unsupported controls are disabled with an upgrade explanation. Refresh the page after a normal backend upgrade. UI layout caches contain pane placement/identifiers, not file bodies, native terminal output or credentials.
@@ -0,0 +1,25 @@
1
+ # Third-party brand vectors
2
+
3
+ Claude asterisk and OpenAI knot paths are sourced from `@lobehub/icons-static-svg@1.95.0` ([LobeHub Icons](https://github.com/lobehub/lobe-icons)). Codex is identified with the OpenAI mark **and the Codex text label**; this does not claim a distinct official Codex logo or any endorsement. Brand trademarks remain their owners' property.
4
+
5
+ MIT License
6
+
7
+ Copyright (c) 2023 LobeHub
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ // Entry point for `@wnzzer/agentdock`. The real program is a Rust binary that
3
+ // ships in a per-platform package; npm installs only the one matching this
4
+ // machine, via the `os`/`cpu` fields on those packages. This file finds it and
5
+ // hands over.
6
+ //
7
+ // CommonJS on purpose: `require.resolve` is how a sibling optional dependency
8
+ // is located, and the package deliberately declares no `type`, so `.js`/`.cjs`
9
+ // here is CJS regardless of what any parent directory says.
10
+ 'use strict';
11
+
12
+ const { spawn } = require('node:child_process');
13
+ const path = require('node:path');
14
+
15
+ // Keys are `${process.platform}-${process.arch}`, which is what npm itself
16
+ // matches `os`/`cpu` against, so this table and the published packages cannot
17
+ // disagree about what a platform is called.
18
+ const PACKAGES = {
19
+ 'darwin-arm64': '@wnzzer/agentdock-darwin-arm64',
20
+ 'darwin-x64': '@wnzzer/agentdock-darwin-x64',
21
+ 'linux-x64': '@wnzzer/agentdock-linux-x64',
22
+ 'linux-arm64': '@wnzzer/agentdock-linux-arm64',
23
+ };
24
+
25
+ const BINARY = 'agentdock-server';
26
+
27
+ function fail(message) {
28
+ process.stderr.write(`agentdock: ${message}\n`);
29
+ process.exit(1);
30
+ }
31
+
32
+ function locate() {
33
+ const key = `${process.platform}-${process.arch}`;
34
+ const pkg = PACKAGES[key];
35
+ if (!pkg) {
36
+ fail(
37
+ `no prebuilt binary for ${key}.\n` +
38
+ ` Supported: ${Object.keys(PACKAGES).join(', ')}.\n` +
39
+ ' Build from source instead: https://github.com/wnzzer/agentdock',
40
+ );
41
+ }
42
+ // Resolve the manifest rather than the binary: a package.json is resolvable
43
+ // whatever the file layout, and the error it throws names the missing
44
+ // package instead of a path inside it.
45
+ let manifest;
46
+ try {
47
+ manifest = require.resolve(`${pkg}/package.json`);
48
+ } catch {
49
+ fail(
50
+ `${pkg} is not installed.\n` +
51
+ ' It is an optional dependency, so npm skips it silently when the\n' +
52
+ ' install ran on a different platform or with a lockfile from one.\n' +
53
+ ` Reinstall on this machine, or add it directly: npm i ${pkg}`,
54
+ );
55
+ }
56
+ return path.join(path.dirname(manifest), 'bin', BINARY);
57
+ }
58
+
59
+ const child = spawn(locate(), process.argv.slice(2), { stdio: 'inherit' });
60
+
61
+ // A terminal delivers Ctrl+C to the whole foreground group, so the server
62
+ // already sees it. Forwarding covers the other caller — a process manager
63
+ // signalling this pid alone, which would otherwise leave the server orphaned.
64
+ const FORWARDED = ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGQUIT'];
65
+ for (const signal of FORWARDED) {
66
+ process.on(signal, () => {
67
+ if (child.exitCode === null && child.signalCode === null) child.kill(signal);
68
+ });
69
+ }
70
+
71
+ child.on('error', (error) => fail(`could not start the server: ${error.message}`));
72
+ child.on('exit', (code, signal) => {
73
+ // Report a signalled death as a shell does, so `$?` still distinguishes
74
+ // "killed" from "exited with that number".
75
+ process.exit(signal ? 128 + (require('node:os').constants.signals[signal] ?? 0) : (code ?? 0));
76
+ });
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@wnzzer/agentdock",
3
+ "version": "0.1.0",
4
+ "description": "Remote multi-agent development workspace for the official Claude Code and Codex CLIs",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/wnzzer/agentdock",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/wnzzer/agentdock.git"
10
+ },
11
+ "engines": {
12
+ "node": ">=20"
13
+ },
14
+ "keywords": [
15
+ "claude-code",
16
+ "codex",
17
+ "agent",
18
+ "workspace",
19
+ "cli"
20
+ ],
21
+ "bin": {
22
+ "agentdock": "bin/agentdock.js"
23
+ },
24
+ "optionalDependencies": {
25
+ "@wnzzer/agentdock-darwin-arm64": "0.1.0",
26
+ "@wnzzer/agentdock-darwin-x64": "0.1.0",
27
+ "@wnzzer/agentdock-linux-x64": "0.1.0",
28
+ "@wnzzer/agentdock-linux-arm64": "0.1.0"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ "LICENSE",
33
+ "THIRD-PARTY-NOTICES.md",
34
+ "README.md"
35
+ ]
36
+ }