@av-pi-studio/server 0.0.1
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/README.md +411 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/agent/agent-manager.d.ts +107 -0
- package/dist/agent/agent-manager.d.ts.map +1 -0
- package/dist/agent/agent-manager.js +218 -0
- package/dist/agent/agent-manager.js.map +1 -0
- package/dist/agent/agent-service.d.ts +36 -0
- package/dist/agent/agent-service.d.ts.map +1 -0
- package/dist/agent/agent-service.js +195 -0
- package/dist/agent/agent-service.js.map +1 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +18 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/manifest.d.ts +7 -0
- package/dist/agent/manifest.d.ts.map +1 -0
- package/dist/agent/manifest.js +27 -0
- package/dist/agent/manifest.js.map +1 -0
- package/dist/agent/mcp-server.d.ts +100 -0
- package/dist/agent/mcp-server.d.ts.map +1 -0
- package/dist/agent/mcp-server.js +163 -0
- package/dist/agent/mcp-server.js.map +1 -0
- package/dist/agent/permissions.d.ts +71 -0
- package/dist/agent/permissions.d.ts.map +1 -0
- package/dist/agent/permissions.js +132 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/agent/provider-contract.d.ts +134 -0
- package/dist/agent/provider-contract.d.ts.map +1 -0
- package/dist/agent/provider-contract.js +2 -0
- package/dist/agent/provider-contract.js.map +1 -0
- package/dist/agent/provider-registry.d.ts +37 -0
- package/dist/agent/provider-registry.d.ts.map +1 -0
- package/dist/agent/provider-registry.js +92 -0
- package/dist/agent/provider-registry.js.map +1 -0
- package/dist/agent/provider-snapshot.d.ts +52 -0
- package/dist/agent/provider-snapshot.d.ts.map +1 -0
- package/dist/agent/provider-snapshot.js +73 -0
- package/dist/agent/provider-snapshot.js.map +1 -0
- package/dist/agent/providers/mock/mock-provider.d.ts +44 -0
- package/dist/agent/providers/mock/mock-provider.d.ts.map +1 -0
- package/dist/agent/providers/mock/mock-provider.js +162 -0
- package/dist/agent/providers/mock/mock-provider.js.map +1 -0
- package/dist/agent/providers/pi/agent.d.ts +80 -0
- package/dist/agent/providers/pi/agent.d.ts.map +1 -0
- package/dist/agent/providers/pi/agent.js +322 -0
- package/dist/agent/providers/pi/agent.js.map +1 -0
- package/dist/agent/providers/pi/event-mapper.d.ts +17 -0
- package/dist/agent/providers/pi/event-mapper.d.ts.map +1 -0
- package/dist/agent/providers/pi/event-mapper.js +150 -0
- package/dist/agent/providers/pi/event-mapper.js.map +1 -0
- package/dist/agent/providers/pi/rpc-transport.d.ts +53 -0
- package/dist/agent/providers/pi/rpc-transport.d.ts.map +1 -0
- package/dist/agent/providers/pi/rpc-transport.js +190 -0
- package/dist/agent/providers/pi/rpc-transport.js.map +1 -0
- package/dist/agent/providers/pi/session-hydration.d.ts +11 -0
- package/dist/agent/providers/pi/session-hydration.d.ts.map +1 -0
- package/dist/agent/providers/pi/session-hydration.js +167 -0
- package/dist/agent/providers/pi/session-hydration.js.map +1 -0
- package/dist/agent/rewind-rpc.d.ts +15 -0
- package/dist/agent/rewind-rpc.d.ts.map +1 -0
- package/dist/agent/rewind-rpc.js +30 -0
- package/dist/agent/rewind-rpc.js.map +1 -0
- package/dist/agent/session-operations.d.ts +32 -0
- package/dist/agent/session-operations.d.ts.map +1 -0
- package/dist/agent/session-operations.js +130 -0
- package/dist/agent/session-operations.js.map +1 -0
- package/dist/agent/structured-generation.d.ts +39 -0
- package/dist/agent/structured-generation.d.ts.map +1 -0
- package/dist/agent/structured-generation.js +78 -0
- package/dist/agent/structured-generation.js.map +1 -0
- package/dist/agent/timeline-rpc.d.ts +21 -0
- package/dist/agent/timeline-rpc.d.ts.map +1 -0
- package/dist/agent/timeline-rpc.js +59 -0
- package/dist/agent/timeline-rpc.js.map +1 -0
- package/dist/agent/timeline-store.d.ts +100 -0
- package/dist/agent/timeline-store.d.ts.map +1 -0
- package/dist/agent/timeline-store.js +255 -0
- package/dist/agent/timeline-store.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/password-auth.d.ts +44 -0
- package/dist/auth/password-auth.d.ts.map +1 -0
- package/dist/auth/password-auth.js +78 -0
- package/dist/auth/password-auth.js.map +1 -0
- package/dist/config/daemon-config.d.ts +634 -0
- package/dist/config/daemon-config.d.ts.map +1 -0
- package/dist/config/daemon-config.js +258 -0
- package/dist/config/daemon-config.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/project-config.d.ts +104 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/config/project-config.js +106 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/daemon/bootstrap.d.ts +37 -0
- package/dist/daemon/bootstrap.d.ts.map +1 -0
- package/dist/daemon/bootstrap.js +448 -0
- package/dist/daemon/bootstrap.js.map +1 -0
- package/dist/daemon/dev-bootstrap.d.ts +14 -0
- package/dist/daemon/dev-bootstrap.d.ts.map +1 -0
- package/dist/daemon/dev-bootstrap.js +231 -0
- package/dist/daemon/dev-bootstrap.js.map +1 -0
- package/dist/daemon/dev-main.d.ts +3 -0
- package/dist/daemon/dev-main.d.ts.map +1 -0
- package/dist/daemon/dev-main.js +36 -0
- package/dist/daemon/dev-main.js.map +1 -0
- package/dist/daemon/index.d.ts +15 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +21 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/main.d.ts +3 -0
- package/dist/daemon/main.d.ts.map +1 -0
- package/dist/daemon/main.js +29 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/orchestration-rpc.d.ts +19 -0
- package/dist/daemon/orchestration-rpc.d.ts.map +1 -0
- package/dist/daemon/orchestration-rpc.js +136 -0
- package/dist/daemon/orchestration-rpc.js.map +1 -0
- package/dist/files/download-token-store.d.ts +14 -0
- package/dist/files/download-token-store.d.ts.map +1 -0
- package/dist/files/download-token-store.js +33 -0
- package/dist/files/download-token-store.js.map +1 -0
- package/dist/files/file-explorer.d.ts +54 -0
- package/dist/files/file-explorer.d.ts.map +1 -0
- package/dist/files/file-explorer.js +182 -0
- package/dist/files/file-explorer.js.map +1 -0
- package/dist/files/file-transfer.d.ts +30 -0
- package/dist/files/file-transfer.d.ts.map +1 -0
- package/dist/files/file-transfer.js +132 -0
- package/dist/files/file-transfer.js.map +1 -0
- package/dist/files/index.d.ts +4 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/http/host-allowlist.d.ts +15 -0
- package/dist/http/host-allowlist.d.ts.map +1 -0
- package/dist/http/host-allowlist.js +52 -0
- package/dist/http/host-allowlist.js.map +1 -0
- package/dist/http/http-server.d.ts +27 -0
- package/dist/http/http-server.d.ts.map +1 -0
- package/dist/http/http-server.js +76 -0
- package/dist/http/http-server.js.map +1 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +4 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +48 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +53 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/orchestration/chat-service.d.ts +61 -0
- package/dist/orchestration/chat-service.d.ts.map +1 -0
- package/dist/orchestration/chat-service.js +156 -0
- package/dist/orchestration/chat-service.js.map +1 -0
- package/dist/orchestration/cron.d.ts +30 -0
- package/dist/orchestration/cron.d.ts.map +1 -0
- package/dist/orchestration/cron.js +136 -0
- package/dist/orchestration/cron.js.map +1 -0
- package/dist/orchestration/index.d.ts +5 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +6 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/loop-service.d.ts +129 -0
- package/dist/orchestration/loop-service.d.ts.map +1 -0
- package/dist/orchestration/loop-service.js +234 -0
- package/dist/orchestration/loop-service.js.map +1 -0
- package/dist/orchestration/schedule-service.d.ts +65 -0
- package/dist/orchestration/schedule-service.d.ts.map +1 -0
- package/dist/orchestration/schedule-service.js +201 -0
- package/dist/orchestration/schedule-service.js.map +1 -0
- package/dist/persistence/atomic-store.d.ts +45 -0
- package/dist/persistence/atomic-store.d.ts.map +1 -0
- package/dist/persistence/atomic-store.js +92 -0
- package/dist/persistence/atomic-store.js.map +1 -0
- package/dist/persistence/entity-schemas.d.ts +1707 -0
- package/dist/persistence/entity-schemas.d.ts.map +1 -0
- package/dist/persistence/entity-schemas.js +250 -0
- package/dist/persistence/entity-schemas.js.map +1 -0
- package/dist/persistence/entity-stores.d.ts +46 -0
- package/dist/persistence/entity-stores.d.ts.map +1 -0
- package/dist/persistence/entity-stores.js +167 -0
- package/dist/persistence/entity-stores.js.map +1 -0
- package/dist/persistence/index.d.ts +4 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +5 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/projects/checkout-diff-manager.d.ts +44 -0
- package/dist/projects/checkout-diff-manager.d.ts.map +1 -0
- package/dist/projects/checkout-diff-manager.js +82 -0
- package/dist/projects/checkout-diff-manager.js.map +1 -0
- package/dist/projects/git-checkout-rpc.d.ts +18 -0
- package/dist/projects/git-checkout-rpc.d.ts.map +1 -0
- package/dist/projects/git-checkout-rpc.js +57 -0
- package/dist/projects/git-checkout-rpc.js.map +1 -0
- package/dist/projects/git-detect.d.ts +21 -0
- package/dist/projects/git-detect.d.ts.map +1 -0
- package/dist/projects/git-detect.js +34 -0
- package/dist/projects/git-detect.js.map +1 -0
- package/dist/projects/git-operations.d.ts +67 -0
- package/dist/projects/git-operations.d.ts.map +1 -0
- package/dist/projects/git-operations.js +200 -0
- package/dist/projects/git-operations.js.map +1 -0
- package/dist/projects/github-service.d.ts +80 -0
- package/dist/projects/github-service.d.ts.map +1 -0
- package/dist/projects/github-service.js +172 -0
- package/dist/projects/github-service.js.map +1 -0
- package/dist/projects/index.d.ts +13 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +19 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/projects/open-project.d.ts +35 -0
- package/dist/projects/open-project.d.ts.map +1 -0
- package/dist/projects/open-project.js +106 -0
- package/dist/projects/open-project.js.map +1 -0
- package/dist/projects/reconciliation.d.ts +15 -0
- package/dist/projects/reconciliation.d.ts.map +1 -0
- package/dist/projects/reconciliation.js +63 -0
- package/dist/projects/reconciliation.js.map +1 -0
- package/dist/projects/status-projection.d.ts +33 -0
- package/dist/projects/status-projection.d.ts.map +1 -0
- package/dist/projects/status-projection.js +98 -0
- package/dist/projects/status-projection.js.map +1 -0
- package/dist/projects/workspace-activity.d.ts +28 -0
- package/dist/projects/workspace-activity.d.ts.map +1 -0
- package/dist/projects/workspace-activity.js +74 -0
- package/dist/projects/workspace-activity.js.map +1 -0
- package/dist/projects/workspace-git-service.d.ts +27 -0
- package/dist/projects/workspace-git-service.d.ts.map +1 -0
- package/dist/projects/workspace-git-service.js +60 -0
- package/dist/projects/workspace-git-service.js.map +1 -0
- package/dist/projects/workspace-registry.d.ts +59 -0
- package/dist/projects/workspace-registry.d.ts.map +1 -0
- package/dist/projects/workspace-registry.js +149 -0
- package/dist/projects/workspace-registry.js.map +1 -0
- package/dist/projects/worktree-service.d.ts +100 -0
- package/dist/projects/worktree-service.d.ts.map +1 -0
- package/dist/projects/worktree-service.js +216 -0
- package/dist/projects/worktree-service.js.map +1 -0
- package/dist/proxy/index.d.ts +4 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +5 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/service-hostname.d.ts +21 -0
- package/dist/proxy/service-hostname.d.ts.map +1 -0
- package/dist/proxy/service-hostname.js +44 -0
- package/dist/proxy/service-hostname.js.map +1 -0
- package/dist/proxy/service-port-registry.d.ts +36 -0
- package/dist/proxy/service-port-registry.d.ts.map +1 -0
- package/dist/proxy/service-port-registry.js +55 -0
- package/dist/proxy/service-port-registry.js.map +1 -0
- package/dist/proxy/service-proxy.d.ts +34 -0
- package/dist/proxy/service-proxy.d.ts.map +1 -0
- package/dist/proxy/service-proxy.js +54 -0
- package/dist/proxy/service-proxy.js.map +1 -0
- package/dist/terminal/index.d.ts +4 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +5 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/pty-backend.d.ts +44 -0
- package/dist/terminal/pty-backend.d.ts.map +1 -0
- package/dist/terminal/pty-backend.js +119 -0
- package/dist/terminal/pty-backend.js.map +1 -0
- package/dist/terminal/screen-buffer.d.ts +21 -0
- package/dist/terminal/screen-buffer.d.ts.map +1 -0
- package/dist/terminal/screen-buffer.js +55 -0
- package/dist/terminal/screen-buffer.js.map +1 -0
- package/dist/terminal/terminal-manager.d.ts +79 -0
- package/dist/terminal/terminal-manager.d.ts.map +1 -0
- package/dist/terminal/terminal-manager.js +174 -0
- package/dist/terminal/terminal-manager.js.map +1 -0
- package/dist/terminal/terminal-rpc.d.ts +20 -0
- package/dist/terminal/terminal-rpc.d.ts.map +1 -0
- package/dist/terminal/terminal-rpc.js +122 -0
- package/dist/terminal/terminal-rpc.js.map +1 -0
- package/dist/util/concurrency.d.ts +16 -0
- package/dist/util/concurrency.d.ts.map +1 -0
- package/dist/util/concurrency.js +23 -0
- package/dist/util/concurrency.js.map +1 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +2 -0
- package/dist/util/index.js.map +1 -0
- package/dist/ws/capability-store.d.ts +11 -0
- package/dist/ws/capability-store.d.ts.map +1 -0
- package/dist/ws/capability-store.js +10 -0
- package/dist/ws/capability-store.js.map +1 -0
- package/dist/ws/index.d.ts +5 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/index.js +6 -0
- package/dist/ws/index.js.map +1 -0
- package/dist/ws/router.d.ts +34 -0
- package/dist/ws/router.d.ts.map +1 -0
- package/dist/ws/router.js +97 -0
- package/dist/ws/router.js.map +1 -0
- package/dist/ws/session.d.ts +28 -0
- package/dist/ws/session.d.ts.map +1 -0
- package/dist/ws/session.js +36 -0
- package/dist/ws/session.js.map +1 -0
- package/dist/ws/ws-server.d.ts +41 -0
- package/dist/ws/ws-server.d.ts.map +1 -0
- package/dist/ws/ws-server.js +104 -0
- package/dist/ws/ws-server.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# `@av-pi-studio/server`
|
|
2
|
+
|
|
3
|
+
The **Pi-Studio daemon** — the long-lived server process that runs on a developer's machine and is
|
|
4
|
+
the heart of Pi-Studio. It supervises AI-agent processes, PTY terminals, git worktrees, projects,
|
|
5
|
+
chat rooms, schedules, and loops, and exposes a single **WebSocket JSON+binary API** (plus a small
|
|
6
|
+
HTTP surface) that every client — the CLI, the web UI, and future native apps — connects to.
|
|
7
|
+
|
|
8
|
+
Your code never leaves your machine: the daemon runs locally, talks to the `pi` agent locally, and
|
|
9
|
+
persists all state under a local home directory.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Table of contents
|
|
14
|
+
|
|
15
|
+
- [What the daemon does](#what-the-daemon-does)
|
|
16
|
+
- [Requirements](#requirements)
|
|
17
|
+
- [Install & build](#install--build)
|
|
18
|
+
- [Running the daemon](#running-the-daemon)
|
|
19
|
+
- [Configuration](#configuration)
|
|
20
|
+
- [The wire API](#the-wire-api)
|
|
21
|
+
- [Agent providers](#agent-providers)
|
|
22
|
+
- [Persistence](#persistence)
|
|
23
|
+
- [Architecture](#architecture)
|
|
24
|
+
- [Security model](#security-model)
|
|
25
|
+
- [Logging](#logging)
|
|
26
|
+
- [Development](#development)
|
|
27
|
+
- [Key invariants](#key-invariants)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## What the daemon does
|
|
32
|
+
|
|
33
|
+
A single daemon process owns all runtime state and mediates every operation:
|
|
34
|
+
|
|
35
|
+
- **Agents** — creates, runs, interrupts, updates, resumes, and archives AI coding-agent sessions
|
|
36
|
+
through a provider-neutral interface. Streams every turn event (assistant messages, reasoning,
|
|
37
|
+
tool calls, completion) to subscribed clients in real time.
|
|
38
|
+
- **Terminals** — spawns and multiplexes PTY processes over the same WebSocket using binary frames,
|
|
39
|
+
with screen-buffer snapshots so late subscribers see the current screen.
|
|
40
|
+
- **Projects & git** — opens projects, tracks workspaces, runs git status/branch/diff/commit,
|
|
41
|
+
manages worktrees, and integrates with the GitHub API for PRs/issues.
|
|
42
|
+
- **Orchestration** — chat rooms with `@mentions`, cron/interval **schedules** that fire agent
|
|
43
|
+
prompts, and iterative worker+verifier **loops**.
|
|
44
|
+
- **Files** — directory listing, text/binary file preview, and token-based chunked file download.
|
|
45
|
+
- **Service proxy** — an HTTP reverse proxy that routes to localhost services started by agents.
|
|
46
|
+
|
|
47
|
+
The daemon is **provider-agnostic**: the rest of the code only ever touches the `AgentClient` /
|
|
48
|
+
`AgentSession` interfaces in `src/agent/provider-contract.ts`. Two providers ship today — the real
|
|
49
|
+
`pi` provider and an in-process `mock`.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
- **Node.js ≥ 20** (developed and tested on Node 24). ESM only (`"type": "module"`).
|
|
56
|
+
- **npm** with workspaces (this package lives in the Pi-Studio monorepo).
|
|
57
|
+
- For the real **`pi` provider**: pi *credentials* only. The `pi` CLI is bundled as a dependency
|
|
58
|
+
(`@earendil-works/pi-coding-agent`) — the daemon launches `node <pkg>/dist/cli.js --mode rpc`, so
|
|
59
|
+
**no global `pi` install is required**. Provide credentials via an API key
|
|
60
|
+
(`ANTHROPIC_API_KEY`, etc.) in the daemon's environment, or a configured `~/.pi/agent/auth.json`.
|
|
61
|
+
- The built-in **`mock` provider** needs **no credentials** and is ideal for smoke tests.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Install & build
|
|
66
|
+
|
|
67
|
+
From the monorepo root:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install # install all workspace deps
|
|
71
|
+
npm run build:server # build this package (compiles protocol + highlight first via project refs)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or build everything: `npm run build`.
|
|
75
|
+
|
|
76
|
+
The build emits `dist/`. The production entry point is `dist/daemon/main.js`, also exposed as the
|
|
77
|
+
`pi-studio-daemon` bin.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Running the daemon
|
|
82
|
+
|
|
83
|
+
### Simplest (from monorepo root)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm start # builds the server, then runs the daemon in the foreground
|
|
87
|
+
npm run start:server # runs the already-built daemon without rebuilding
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Directly:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
node packages/server/dist/daemon/main.js
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
On startup the daemon prints its identity and readiness:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
pi-studio daemon listening on http://0.0.0.0:6767
|
|
100
|
+
serverId: 3f2a…
|
|
101
|
+
home: /home/you/.pi-studio
|
|
102
|
+
provider: pi
|
|
103
|
+
ws: ready
|
|
104
|
+
Press Ctrl+C to stop
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
By default the daemon:
|
|
108
|
+
|
|
109
|
+
- listens on **`0.0.0.0:6767`** (override with `PI_STUDIO_LISTEN`) — reachable over the LAN
|
|
110
|
+
- stores all state under **`$PI_STUDIO_HOME`** (default **`~/.pi-studio`**)
|
|
111
|
+
- writes logs to **`$PI_STUDIO_HOME/logs/`**
|
|
112
|
+
- uses the **`pi`** provider
|
|
113
|
+
|
|
114
|
+
It runs in the foreground; **Ctrl-C** (SIGINT) or SIGTERM triggers a clean shutdown that closes the
|
|
115
|
+
HTTP/WS servers and releases resources.
|
|
116
|
+
|
|
117
|
+
### Verify it's up
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
curl http://127.0.0.1:6767/api/health
|
|
121
|
+
# → {"status":"ok"}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`/api/health` is exempt from Host-allowlist and auth checks, so it always answers.
|
|
125
|
+
|
|
126
|
+
### Dev daemon
|
|
127
|
+
|
|
128
|
+
`src/daemon/dev-main.ts` is a development entry that wires the full feature surface and binds
|
|
129
|
+
`0.0.0.0` with developer-friendly defaults. From the root:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm run dev:daemon
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> The production `bootstrap.ts` and dev `dev-bootstrap.ts` both register the full RPC surface;
|
|
136
|
+
> `bootstrap.ts` is production-grade (real provider, disk persistence, config loading) while
|
|
137
|
+
> `dev-bootstrap.ts` is for local testing and **must never be imported by `bootstrap.ts`**.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
Configuration comes from two sources, merged with **environment variables winning** over the file:
|
|
144
|
+
|
|
145
|
+
1. `$PI_STUDIO_HOME/config.json` (optional — a missing or corrupt file is treated as `{}`).
|
|
146
|
+
2. Environment variables (overlaid last).
|
|
147
|
+
|
|
148
|
+
### Environment variables
|
|
149
|
+
|
|
150
|
+
All optional.
|
|
151
|
+
|
|
152
|
+
| Variable | Default | Purpose |
|
|
153
|
+
|----------|---------|---------|
|
|
154
|
+
| `PI_STUDIO_HOME` | `~/.pi-studio` | State + config + logs directory |
|
|
155
|
+
| `PI_STUDIO_LISTEN` | `0.0.0.0:6767` | Daemon listen address (`host:port`) |
|
|
156
|
+
| `PI_STUDIO_PASSWORD` | _(unset)_ | Require this password for connections (bcrypt-checked) |
|
|
157
|
+
| `PI_STUDIO_HOSTNAMES` | `localhost,*.localhost` | Allowed `Host` header values (comma-separated, or `true` to allow all) |
|
|
158
|
+
| `PI_STUDIO_SERVER_ID` | _(persisted/generated)_ | Stable server identity |
|
|
159
|
+
| `PI_STUDIO_SERVICE_PROXY_LISTEN` | _(unset)_ | Service-proxy listen address |
|
|
160
|
+
| `PI_STUDIO_SERVICE_PROXY_PUBLIC_BASE_URL` | _(unset)_ | Public base URL advertised for proxied services |
|
|
161
|
+
| `PI_STUDIO_SERVICE_PROXY_ENABLED` | _(unset)_ | Enable the service proxy (`1`/`true`/`yes`/`on`) |
|
|
162
|
+
|
|
163
|
+
> Literal IP addresses always pass the Host allowlist, so binding `0.0.0.0` and connecting via the
|
|
164
|
+
> server's IP needs no extra config. To reach the daemon by **hostname**, add it to
|
|
165
|
+
> `PI_STUDIO_HOSTNAMES`.
|
|
166
|
+
|
|
167
|
+
Example — isolated home, custom port, password:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
PI_STUDIO_HOME=/tmp/pi-studio-dev \
|
|
171
|
+
PI_STUDIO_LISTEN=127.0.0.1:6790 \
|
|
172
|
+
PI_STUDIO_PASSWORD=hunter2 \
|
|
173
|
+
node packages/server/dist/daemon/main.js
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### `config.json`
|
|
177
|
+
|
|
178
|
+
The persisted config is validated by a Zod schema (`src/config/daemon-config.ts`) with sane
|
|
179
|
+
defaults and `.passthrough()` tolerance for unknown/future keys. Notable sections:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"version": 1,
|
|
184
|
+
"daemon": {
|
|
185
|
+
"listen": "127.0.0.1:6767",
|
|
186
|
+
"hostnames": ["localhost", "*.localhost"],
|
|
187
|
+
"auth": { "password": "$2b$…bcrypt-hash…" },
|
|
188
|
+
"mcp": { "enabled": true, "injectIntoAgents": true },
|
|
189
|
+
"appendSystemPrompt": "",
|
|
190
|
+
"cors": { "allowedOrigins": [] },
|
|
191
|
+
"serviceProxy": { "enabled": false }
|
|
192
|
+
},
|
|
193
|
+
"agents": {
|
|
194
|
+
"providers": {
|
|
195
|
+
"pi": { "command": ["/abs/path/to/pi", "--mode", "rpc"] }
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"log": { "level": "info", "format": "json" }
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
To use a **different `pi` binary** than the bundled one, set
|
|
203
|
+
`agents.providers.pi.command` to an absolute path as shown above. Custom Pi-compatible profiles can
|
|
204
|
+
extend the `pi` provider via `"extends": "pi"` (a custom provider must also set a `label`).
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## The wire API
|
|
209
|
+
|
|
210
|
+
All communication rides a **single WebSocket connection** per client.
|
|
211
|
+
|
|
212
|
+
### Text frames — JSON envelopes discriminated by `type`
|
|
213
|
+
|
|
214
|
+
- `hello` (Client→Server, first frame) — handshake with `clientId`, `clientType`
|
|
215
|
+
(`mobile`/`browser`/`cli`/`mcp`), `protocolVersion`, optional `capabilities`.
|
|
216
|
+
- `status` (Server→Client) — `server_info` payload sent right after a successful hello.
|
|
217
|
+
- `ping` / `pong` — **JSON** liveness (not RFC 6455 ping, which browsers/RN can't send).
|
|
218
|
+
- `session` — the envelope wrapping every RPC request/response/broadcast (`{ type: "session",
|
|
219
|
+
message }`).
|
|
220
|
+
- `rpc_error` — a correlated error response (carries the originating `requestId`).
|
|
221
|
+
|
|
222
|
+
A non-`hello` first frame closes the socket. RPC names follow a dotted convention —
|
|
223
|
+
`domain.provider.operation.direction` (e.g. `agent.permission.respond.request`); legacy flat names
|
|
224
|
+
are accepted via aliases but never generated.
|
|
225
|
+
|
|
226
|
+
### Binary frames — terminal + file transfer
|
|
227
|
+
|
|
228
|
+
Layout: `[1-byte opcode][1-byte slot][payload]`. The `slot` (0–255) demultiplexes multiple
|
|
229
|
+
terminals over the one connection. Codecs use `Uint8Array` (not Node `Buffer`) so they run
|
|
230
|
+
unchanged in browsers and React Native. **File downloads** also ride binary frames: a client
|
|
231
|
+
requests a token via the `file_download_token_request` RPC, then streams `Begin → Chunk* → End`
|
|
232
|
+
frames via `file_download_request`; uploads consume the same frame format.
|
|
233
|
+
|
|
234
|
+
### HTTP surface
|
|
235
|
+
|
|
236
|
+
The HTTP server is intentionally minimal. Beyond liveness, its only application route in production
|
|
237
|
+
is the **service proxy** (reverse proxy to localhost services started by agents).
|
|
238
|
+
|
|
239
|
+
| Route | Auth | Purpose |
|
|
240
|
+
|-------|------|---------|
|
|
241
|
+
| `GET /api/health` | none | Liveness — `{ "status": "ok" }` |
|
|
242
|
+
| `OPTIONS *` | none | CORS preflight (`204`) |
|
|
243
|
+
| _other paths_ | bearer | Delegated to the service proxy; `404` if unmatched |
|
|
244
|
+
|
|
245
|
+
The request pipeline: health + preflight are exempt; then Host-allowlist (`403` on mismatch), CORS
|
|
246
|
+
headers, optional bearer auth (`401`), then application routes (`404` if unmatched).
|
|
247
|
+
|
|
248
|
+
The **schemas are the single source of truth** and are **append-only**: new fields are optional,
|
|
249
|
+
types are never narrowed, and fields/discriminants are never removed — so an older daemon can always
|
|
250
|
+
decode data written by a newer one. They live in `@av-pi-studio/protocol`.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Agent providers
|
|
255
|
+
|
|
256
|
+
The daemon resolves a provider id string to an `AgentClient` via the `ProviderRegistry`. The only
|
|
257
|
+
surface the rest of the daemon depends on is `src/agent/provider-contract.ts`:
|
|
258
|
+
|
|
259
|
+
- `AgentClient.createSession(config, ctx)` → `AgentSession`
|
|
260
|
+
- `AgentSession.run(prompt, opts)` — start a turn; events emitted via `subscribe(handler)`
|
|
261
|
+
- `AgentSession.startTurn(prompt, opts)` — fire-and-forget turn start, returns `{ turnId }`
|
|
262
|
+
- `AgentSession.interrupt()` / `close()` / `update(patch)`
|
|
263
|
+
- `AgentSession.importSession(...)` — resume a provider-native session by its handle
|
|
264
|
+
- `RunOptions.images` carries `ImageAttachment[]` (wire shape `{ mimeType?, data? }`, base64); the
|
|
265
|
+
provider translates it into its native prompt-image format at the boundary.
|
|
266
|
+
|
|
267
|
+
### `pi` (real)
|
|
268
|
+
|
|
269
|
+
- Spawns `pi --mode rpc` (bundled, or a configured `command`) and speaks **strict JSONL RPC** over
|
|
270
|
+
stdin/stdout (`PiRpcTransport`).
|
|
271
|
+
- `event-mapper.ts` maps raw Pi events (`assistant_message`, `tool_call`, `turn_completed`, …) into
|
|
272
|
+
the normalized `AgentStreamEvent` stream.
|
|
273
|
+
- Discovers models/modes via top-level `get_modes`/`get_models` RPCs (no scratch session).
|
|
274
|
+
- **Prompt images:** `startTurn` converts the wire shape `{ mimeType, data }` into Pi's
|
|
275
|
+
`ImageContent` shape `{ type: "image", data, mimeType }` before the `prompt` RPC.
|
|
276
|
+
- A literal `~` in `cwd` is expanded to the home directory before spawning.
|
|
277
|
+
- A missing/unresolvable `pi` surfaces as a clean `rpc_error` ("Pi provider unavailable…") rather
|
|
278
|
+
than crashing the daemon.
|
|
279
|
+
|
|
280
|
+
### `mock` (in-process)
|
|
281
|
+
|
|
282
|
+
Emits synthetic events on a small timer loop. No credentials. Used for smoke tests and CI.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Persistence
|
|
287
|
+
|
|
288
|
+
All state lives under `$PI_STUDIO_HOME/`. Every write goes through `AtomicStore`
|
|
289
|
+
(write-to-temp-then-rename) for crash safety.
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
config.json Daemon config (password hash, provider overrides, service proxy, …)
|
|
293
|
+
server-id Stable server identity
|
|
294
|
+
logs/ Rotating NDJSON log files (pino)
|
|
295
|
+
agents/
|
|
296
|
+
<sanitized-cwd>/
|
|
297
|
+
<agentId>.json Agent record (status, config, timeline seq, labels, …)
|
|
298
|
+
chat/rooms.json Chat rooms + messages
|
|
299
|
+
loops/<loopId>.json Loop records
|
|
300
|
+
schedules/<scheduleId>.json Schedule records
|
|
301
|
+
projects.json Project registry
|
|
302
|
+
workspaces.json Workspace registry
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
All entity schemas use `.passthrough()` and optional fields — unknown/future fields from a newer
|
|
306
|
+
daemon load silently, so there is no migration framework to maintain.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Architecture
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
src/
|
|
314
|
+
daemon/
|
|
315
|
+
main.ts Production entry: parse env, wire bootstrap.ts, listen, handle signals.
|
|
316
|
+
dev-main.ts Dev entry: wires dev-bootstrap.ts (all features, LAN bind).
|
|
317
|
+
bootstrap.ts Production handler wiring (full RPC surface, real provider, disk state).
|
|
318
|
+
dev-bootstrap.ts Dev handler wiring (local testing only).
|
|
319
|
+
orchestration-rpc.ts
|
|
320
|
+
|
|
321
|
+
agent/ Agent lifecycle, provider registry, timeline, permissions.
|
|
322
|
+
agent-manager.ts Single source of truth for agent state + FSM + persistence + broadcast.
|
|
323
|
+
agent-service.ts RPC handler wiring for agent operations.
|
|
324
|
+
provider-contract.ts AgentClient / AgentSession interfaces (the ONLY provider surface).
|
|
325
|
+
provider-registry.ts Register/resolve AgentClient by provider id.
|
|
326
|
+
timeline-store.ts Append/page/cursor the agent event log.
|
|
327
|
+
permissions.ts Park + resolve tool-call permission requests.
|
|
328
|
+
providers/pi/ Real Pi provider (spawn, JSONL transport, event mapper).
|
|
329
|
+
providers/mock/ In-process synthetic provider.
|
|
330
|
+
|
|
331
|
+
ws/ WebSocket server, per-connection Session, HandlerRegistry + frame router.
|
|
332
|
+
http/ HTTP server (/api/health, downloads), Host allowlist.
|
|
333
|
+
auth/ PasswordAuth (bcrypt + WS subprotocol bearer token).
|
|
334
|
+
config/ DaemonConfig (env + config.json merge) and per-project config.
|
|
335
|
+
persistence/ Zod entity schemas, JSON stores, AtomicStore.
|
|
336
|
+
terminal/ TerminalManager (PTY lifecycle, slot mux, snapshot, binary broadcast).
|
|
337
|
+
projects/ Workspaces, projects, git ops, worktrees, GitHub, reconciliation.
|
|
338
|
+
orchestration/ ChatService, ScheduleService, LoopService, cron.
|
|
339
|
+
files/ File explorer + chunked download token store.
|
|
340
|
+
proxy/ ServiceProxy + port registry for agent-started services.
|
|
341
|
+
logging/ Pino logger factory.
|
|
342
|
+
util/ Concurrency helpers.
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Lifecycle FSM
|
|
346
|
+
|
|
347
|
+
`AgentManager` enforces `initializing → idle ↔ running → error → closed`. Every transition persists
|
|
348
|
+
the record **and** broadcasts `agent_update` to subscribers. Archiving soft-deletes (sets
|
|
349
|
+
`archivedAt`). On startup, `running` agents are recovered (crash recovery), and `running` loops are
|
|
350
|
+
recovered as `stopped` with an interruption log entry.
|
|
351
|
+
|
|
352
|
+
For a deeper subsystem reference, see [`AGENTS.md`](AGENTS.md) in this package and the specs under
|
|
353
|
+
[`clean-room-scope/`](../../clean-room-scope/).
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Security model
|
|
358
|
+
|
|
359
|
+
- **Host-header allowlist** (`src/http/host-allowlist.ts`) rejects requests whose `Host` isn't
|
|
360
|
+
allowed — DNS-rebinding protection. Literal IPs always pass; `localhost`/`*.localhost` are always
|
|
361
|
+
allowed; add hostnames via `PI_STUDIO_HOSTNAMES`.
|
|
362
|
+
- **Password auth** (`src/auth/password-auth.ts`) — optional. When a password is configured it is
|
|
363
|
+
bcrypt-checked against either a `password` query param on the WS upgrade URL or a
|
|
364
|
+
`pi-studio-bearer.<base64(password)>` WS subprotocol. An unset password allows all connections
|
|
365
|
+
(fine for a trusted localhost-only setup; set one before exposing the daemon beyond a trusted
|
|
366
|
+
network).
|
|
367
|
+
- **Service-proxy auth bypass is intentional** — the proxy route is deliberately not gated by
|
|
368
|
+
daemon password auth (per spec).
|
|
369
|
+
- **RPC timeouts are operation-level**, never socket death — an `rpcTimeoutMs` expiry yields an
|
|
370
|
+
`rpc_error`, it does not close or reconnect the WebSocket.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Logging
|
|
375
|
+
|
|
376
|
+
`createLogger(name, opts)` returns a `pino` logger that writes pretty output to stdout in
|
|
377
|
+
development and rotating NDJSON to `$PI_STUDIO_HOME/logs/` in production. The level comes from the
|
|
378
|
+
`log.level` config key (default `info`) or `LOG_LEVEL`.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Development
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm test -- --project packages/server # run this package's Vitest suite
|
|
386
|
+
npm run typecheck # tsc -b across all packages
|
|
387
|
+
npm run lint # oxlint
|
|
388
|
+
npm run fmt:check # oxfmt --check
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Tests are co-located as `*.test.ts` next to their source. Provider tests inject stub transports;
|
|
392
|
+
persistence tests use temporary directories; WebSocket tests use in-memory session stubs. Avoid
|
|
393
|
+
real wall-clock timers in tests — await real completion signals instead.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Key invariants
|
|
398
|
+
|
|
399
|
+
1. **`provider-contract.ts` is the only provider surface.** Never import `providers/pi/` or
|
|
400
|
+
`providers/mock/` from outside `agent/`.
|
|
401
|
+
2. **Handler registration is explicit.** Register handlers in `bootstrap.ts`/`dev-bootstrap.ts`, not
|
|
402
|
+
via auto-discovery.
|
|
403
|
+
3. **Agent status changes only via `AgentManager` transitions** — never mutate a record directly.
|
|
404
|
+
4. **All entity + wire schemas use `.passthrough()` and optional fields** — newer data must load on
|
|
405
|
+
older daemons.
|
|
406
|
+
5. **The wire protocol is append-only.** Never remove or narrow a field, never change a discriminant.
|
|
407
|
+
6. **`dev-bootstrap.ts` must not be imported by `bootstrap.ts`.**
|
|
408
|
+
7. **Binary frame codecs are cross-platform** (`Uint8Array`, no Node `Buffer`).
|
|
409
|
+
8. **`~` in `cwd` is expanded server-side** before it reaches a provider.
|
|
410
|
+
```
|
|
411
|
+
|