From b42819e9ab30eb6a858949c2e639c094294af6a7 Mon Sep 17 00:00:00 2001 From: Steven Roomberg Date: Sun, 16 Aug 2026 21:17:56 +0000 Subject: [PATCH 01/10] feat: add VS Code adapter and extract @chorus/client Share JoinClient/RelayServer in packages/client for reuse across hosts. Add packages/vscode with share/join/chat commands and a Session sidebar that speaks the same chorus-relay wire protocol as the OpenCode plugin. --- CHANGELOG.md | 4 + README.md | 15 +- bun.lock | 32 ++ docs/DECISIONS.md | 5 +- docs/STATUS.md | 7 + package.json | 17 +- packages/client/dist/index.d.ts | 3 + packages/client/dist/index.d.ts.map | 1 + packages/client/dist/index.js | 3 + packages/client/dist/index.js.map | 1 + packages/client/dist/join.d.ts | 30 ++ packages/client/dist/join.d.ts.map | 1 + packages/client/dist/join.js | 123 +++++ packages/client/dist/join.js.map | 1 + packages/client/dist/relay.d.ts | 63 +++ packages/client/dist/relay.d.ts.map | 1 + packages/client/dist/relay.js | 270 ++++++++++ packages/client/dist/relay.js.map | 1 + packages/client/package.json | 28 + packages/client/src/index.ts | 11 + packages/client/src/join.ts | 158 ++++++ packages/client/src/relay.ts | 498 +++++++++++++++++ packages/{plugin => client}/test/join.test.ts | 3 +- .../{plugin => client}/test/relay.test.ts | 2 +- packages/client/tsconfig.json | 19 + packages/plugin/dist/index.d.ts | 2 +- packages/plugin/package.json | 3 +- packages/plugin/src/join/index.ts | 216 +------- packages/plugin/src/relay/index.ts | 505 +----------------- packages/vscode/README.md | 61 +++ packages/vscode/media/chorus.svg | 5 + packages/vscode/package.json | 135 +++++ packages/vscode/src/controller.ts | 317 +++++++++++ packages/vscode/src/extension.ts | 156 ++++++ packages/vscode/src/format.ts | 19 + packages/vscode/src/sessionView.ts | 134 +++++ packages/vscode/test/format.test.ts | 40 ++ packages/vscode/tsconfig.json | 19 + 38 files changed, 2179 insertions(+), 730 deletions(-) create mode 100644 packages/client/dist/index.d.ts create mode 100644 packages/client/dist/index.d.ts.map create mode 100644 packages/client/dist/index.js create mode 100644 packages/client/dist/index.js.map create mode 100644 packages/client/dist/join.d.ts create mode 100644 packages/client/dist/join.d.ts.map create mode 100644 packages/client/dist/join.js create mode 100644 packages/client/dist/join.js.map create mode 100644 packages/client/dist/relay.d.ts create mode 100644 packages/client/dist/relay.d.ts.map create mode 100644 packages/client/dist/relay.js create mode 100644 packages/client/dist/relay.js.map create mode 100644 packages/client/package.json create mode 100644 packages/client/src/index.ts create mode 100644 packages/client/src/join.ts create mode 100644 packages/client/src/relay.ts rename packages/{plugin => client}/test/join.test.ts (97%) rename packages/{plugin => client}/test/relay.test.ts (99%) create mode 100644 packages/client/tsconfig.json create mode 100644 packages/vscode/README.md create mode 100644 packages/vscode/media/chorus.svg create mode 100644 packages/vscode/package.json create mode 100644 packages/vscode/src/controller.ts create mode 100644 packages/vscode/src/extension.ts create mode 100644 packages/vscode/src/format.ts create mode 100644 packages/vscode/src/sessionView.ts create mode 100644 packages/vscode/test/format.test.ts create mode 100644 packages/vscode/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d582fe..6606006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- VS Code extension (`packages/vscode`) — share/join/chat over the same relay protocol; Session sidebar + commands +- Extract `@chorus/client` (`JoinClient` + `RelayServer`) shared by OpenCode plugin, VS Code, and future adapters +- Cross-adapter relay e2e: VS Code host ↔ terminal joiner and terminal host ↔ VS Code joiner (`bun run test:vscode-relay-e2e`) + ## v2.0.0 — 2026-08-21 Enterprise network lockdown for Chorus: keep the relay off the open internet with CIDR allowlists, private bind, and VPN/VPC deployment docs. diff --git a/README.md b/README.md index 528572c..84046b5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Collaborative OpenCode session sharing. Pair-program a live AI session from anot ## How it works -Chorus is an [OpenCode](https://github.com/sst/opencode) plugin plus a **Rust WebSocket relay** (`chorus-relay`). +Chorus is an [OpenCode](https://github.com/sst/opencode) plugin (plus VS Code / other adapters) and a **Rust WebSocket relay** (`chorus-relay`). ``` Host runs opencode → plugin loads @@ -50,22 +50,29 @@ One monorepo, two ecosystems, one wire contract: | Path | Artifact | Description | |---|---|---| | `packages/plugin` | npm `@chorus/plugin` | OpenCode plugin — tools, hooks, spawns/manages relay | +| `packages/client` | npm `@chorus/client` | Shared `JoinClient` + `RelayServer` for host adapters | +| `packages/vscode` | VS Code extension `chorus` | Share/join Chorus sessions from VS Code | +| `packages/zed` | Zed extension `chorus` | Joiner adapter (WASM + MCP → `chorus-zed-helper`) | | `packages/shared` | npm `@chorus/shared` | TypeScript types + codecs for joiner and host-control protocols | | `crates/chorus-relay` | `chorus-relay` binary | Rust WebSocket relay (`/ws` joiners, `/host` control plane) | +| `crates/chorus-zed-helper` | `chorus-zed-helper` binary | Native Chorus join client (CLI + MCP) for Zed | | `protocol/` | fixtures (not published) | Canonical JSON examples both TS and Rust must deserialize | -Root `package.json` scripts are the only task entry (`build`, `test`, `typecheck`). Bun workspaces own `packages/*`; Cargo owns `crates/*`. +Root `package.json` scripts are the only task entry (`build`, `test`, `typecheck`). Bun workspaces own `packages/*`; Cargo owns `crates/*` (Zed’s `packages/zed` is built separately for `wasm32-wasip2`). ## Development ```sh bun install -bun run build # release relay + TS packages -bun run test # relay tests + TS/Bun tests (includes protocol fixtures) +bun run build # release relay + helper + TS packages +bun run test # relay/helper tests + TS/Bun tests (includes protocol fixtures) bun run typecheck cargo test -p chorus-relay +cargo test -p chorus-zed-helper ``` +Zed joiner (optional): see [packages/zed/README.md](packages/zed/README.md) for Install Dev Extension + `chorus-zed-helper` setup. + ### Multi-agent local testing Run several isolated OpenCode servers on one machine (each with Chorus loaded) and drive share/join over the HTTP API: diff --git a/bun.lock b/bun.lock index e543bac..0f639d2 100644 --- a/bun.lock +++ b/bun.lock @@ -8,12 +8,25 @@ "typescript": "^5.7.3", }, }, + "packages/client": { + "name": "@chorus/client", + "version": "0.1.0", + "dependencies": { + "@chorus/shared": "workspace:*", + }, + "devDependencies": { + "@types/bun": "latest", + "@types/node": "^22.10.7", + "typescript": "^5.7.3", + }, + }, "packages/plugin": { "name": "@chorus/plugin", "version": "0.1.6", "dependencies": { "@aws-sdk/client-s3": "^3.726.0", "@aws-sdk/lib-storage": "^3.726.0", + "@chorus/client": "workspace:*", "@chorus/shared": "workspace:*", "zod": "4.1.8", }, @@ -41,6 +54,19 @@ "vitest": "^2.1.8", }, }, + "packages/vscode": { + "name": "chorus", + "version": "0.1.0", + "dependencies": { + "@chorus/client": "workspace:*", + "@chorus/shared": "workspace:*", + }, + "devDependencies": { + "@types/node": "^22.10.7", + "@types/vscode": "^1.90.0", + "typescript": "^5.7.3", + }, + }, }, "packages": { "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], @@ -107,6 +133,8 @@ "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], + "@chorus/client": ["@chorus/client@workspace:packages/client"], + "@chorus/plugin": ["@chorus/plugin@workspace:packages/plugin"], "@chorus/shared": ["@chorus/shared@workspace:packages/shared"], @@ -235,6 +263,8 @@ "@types/node": ["@types/node@22.19.19", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew=="], + "@types/vscode": ["@types/vscode@1.125.0", "", {}, "sha512-0icm/ZQAaism87P0ekHqi4/Ju9du+Tm0RUW+y7vqRsxY2cY0FNRX1nAnaW7nT6npPt2tfHiheZ55Zm9UhqonFA=="], + "@vitest/expect": ["@vitest/expect@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw=="], "@vitest/mocker": ["@vitest/mocker@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg=="], @@ -265,6 +295,8 @@ "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + "chorus": ["chorus@workspace:packages/vscode"], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 38e25fc..b1bd64b 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -48,8 +48,9 @@ Recommended shape: ``` - **v1:** OpenCode adapter = this repo’s plugin + local **Rust** `chorus-relay` -- **v1.x:** keep `@chorus/shared` as the stable joiner + host-control contract -- **v2:** optional second adapter (Codex app-server is the best #2) only after OpenCode UX is solid +- **v1.x:** keep `@chorus/shared` as the stable joiner + host-control contract; `@chorus/client` holds `JoinClient` / `RelayServer` for non-OpenCode hosts +- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) and Zed (when present) — same wire protocol, host-specific UI only +- **v2:** optional further adapters (Codex app-server remains a strong candidate) once OpenCode UX is solid; split adapter packages into separate repos only when publish/CI ownership diverges **Do not** make Claude Code / Amp the primary host — large audiences, but proprietary control planes. Treat them as distribution adapters later, not the core. diff --git a/docs/STATUS.md b/docs/STATUS.md index b766f5b..d1dac8a 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -75,8 +75,15 @@ Enterprise gap analysis (what would actually pass a security review vs what ship `scripts/multi-agent.ts` (via `bun run multi-agent`) can spawn N isolated `opencode serve` instances with the Chorus plugin, then automate `/chorus-share` + `/chorus-join` through OpenCode’s `/session/:id/command` API. Also includes `relay-stress` for concurrent protocol joiners without OpenCode. +## Adapter surface (monorepo) + +- **OpenCode** (`packages/plugin`) — primary host; full LLM loop + transcript mirror. +- **VS Code** (`packages/vscode`) — share/join via `@chorus/client`; sidebar transcript; joiner `collab.input` works against an OpenCode host. VS Code share does **not** drive OpenCode’s model — publish host lines manually or pair with OpenCode. +- **Zed** — joiner-first scaffold when present under `packages/zed` / related crates (WASM extension limits; helper binary pattern). + ## Explicit non-goals (for now) - Rebuilding a full coding agent harness from scratch. - Competing with multi-agent orchestration plugins. - Making the browser app the primary UX again (optional later for non-OpenCode observers). +- Splitting the monorepo until adapter publish cadence actually diverges. diff --git a/package.json b/package.json index a612396..029b9df 100644 --- a/package.json +++ b/package.json @@ -27,19 +27,26 @@ "scripts": { "build:relay": "cargo build -p chorus-relay --release", "build:shared": "bun run --filter @chorus/shared build", + "build:client": "bun run --filter @chorus/client build", "build:plugin": "bun run --filter @chorus/plugin build", - "build:ts": "bun run build:shared && bun run build:plugin", + "build:vscode": "bun run --filter chorus build", + "build:ts": "bun run build:shared && bun run build:client && bun run build:plugin && bun run build:vscode", "build": "bun run build:relay && bun run build:ts", "test:relay": "cargo test -p chorus-relay", - "test:ts": "bun run build:shared && bun run --filter @chorus/shared test && bun run --filter @chorus/plugin test", + "test:ts": "bun run build:shared && bun run build:client && bun run --filter @chorus/shared test && bun run --filter @chorus/client test && bun run --filter @chorus/plugin test && bun run --filter chorus test", "test": "bun run build:relay && bun run test:relay && bun run test:ts", - "typecheck": "bun run build:shared && bun run --filter @chorus/shared typecheck && bun run --filter @chorus/plugin typecheck", - "clean": "bun run --filter @chorus/shared clean && bun run --filter @chorus/plugin clean && cargo clean", + "typecheck": "bun run build:shared && bun run build:client && bun run --filter @chorus/shared typecheck && bun run --filter @chorus/client typecheck && bun run --filter @chorus/plugin typecheck && bun run --filter chorus typecheck", + "clean": "bun run --filter @chorus/shared clean && bun run --filter @chorus/client clean && bun run --filter @chorus/plugin clean && bun run --filter chorus clean && cargo clean", "multi-agent": "bun scripts/multi-agent.ts", "test:multi-agent": "bun scripts/multi-agent.ts setup --agents 2 && bun scripts/multi-agent.ts up --agents 2 && bun scripts/multi-agent.ts smoke && bun scripts/multi-agent.ts pair && bun scripts/multi-agent.ts down", - "test:integration": "bun run test && bun run typecheck && bun run test:multi-agent && bun run test:security-e2e && bun run test:relay-stress", + "test:integration": "bun run test && bun run typecheck && bun run test:multi-agent && bun run test:security-e2e && bun run test:relay-stress && bun run test:vscode-relay-e2e", "test:relay-stress": "bun scripts/multi-agent.ts relay-stress --agents 5", "test:network-e2e": "bun run build:relay && bun scripts/network-e2e.ts", + "test:security-e2e": "bun scripts/security-e2e.ts", + "test:vscode-e2e": "bun scripts/vscode-e2e.ts", + "test:vscode-relay-e2e": "bun scripts/vscode-relay-e2e.ts", + "test:plugin-e2e": "bun run test:multi-agent && bun run test:security-e2e", + "test:adapters-e2e": "bun run test:vscode-e2e && bun run test:vscode-relay-e2e", "docker-agents": "bun scripts/docker-agents.ts", "test:docker-agents": "bun scripts/docker-agents.ts up --agents 2 && bun scripts/docker-agents.ts smoke && bun scripts/docker-agents.ts pair && bun scripts/docker-agents.ts down" }, diff --git a/packages/client/dist/index.d.ts b/packages/client/dist/index.d.ts new file mode 100644 index 0000000..97ea899 --- /dev/null +++ b/packages/client/dist/index.d.ts @@ -0,0 +1,3 @@ +export { JoinClient, type JoinState, type JoinStatus, } from "./join.js"; +export { RelayServer, relayOptionsFromEnv, type RelayServerOptions, } from "./relay.js"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/client/dist/index.d.ts.map b/packages/client/dist/index.d.ts.map new file mode 100644 index 0000000..1beee6d --- /dev/null +++ b/packages/client/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/packages/client/dist/index.js b/packages/client/dist/index.js new file mode 100644 index 0000000..c71c32b --- /dev/null +++ b/packages/client/dist/index.js @@ -0,0 +1,3 @@ +export { JoinClient, } from "./join.js"; +export { RelayServer, relayOptionsFromEnv, } from "./relay.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/client/dist/index.js.map b/packages/client/dist/index.js.map new file mode 100644 index 0000000..37cad03 --- /dev/null +++ b/packages/client/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,GAEpB,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/packages/client/dist/join.d.ts b/packages/client/dist/join.d.ts new file mode 100644 index 0000000..8472425 --- /dev/null +++ b/packages/client/dist/join.d.ts @@ -0,0 +1,30 @@ +import type { SessionEvent, ConnectedUser } from "@chorus/shared"; +export type JoinStatus = "connecting" | "connected" | "disconnected" | "error"; +export interface JoinState { + status: JoinStatus; + sessionId: string; + users: ConnectedUser[]; + recentEvents: SessionEvent[]; + error?: string; +} +export declare class JoinClient { + private readonly relayUrl; + private readonly token; + private readonly displayName; + private ws; + private state; + private onEvent?; + private onChatMessage?; + private onTyping?; + constructor(relayUrl: string, token: string, displayName: string); + connect(): Promise; + sendInput(content: string): void; + sendChat(content: string): void; + setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; + setTypingHandler(fn: (displayName: string | undefined) => void): void; + setEventHandler(fn: (event: SessionEvent) => void): void; + sendTyping(): void; + getState(): Readonly; + disconnect(): void; +} +//# sourceMappingURL=join.d.ts.map \ No newline at end of file diff --git a/packages/client/dist/join.d.ts.map b/packages/client/dist/join.d.ts.map new file mode 100644 index 0000000..961b323 --- /dev/null +++ b/packages/client/dist/join.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAOlE,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IAQnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAT9B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAC,CAAgC;IAChD,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;gBAG1C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM;IAUtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoFxB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKhC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK/B,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAIrE,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAIxD,UAAU,IAAI,IAAI;IAKlB,QAAQ,IAAI,QAAQ,CAAC,SAAS,CAAC;IAI/B,UAAU,IAAI,IAAI;CAKnB"} \ No newline at end of file diff --git a/packages/client/dist/join.js b/packages/client/dist/join.js new file mode 100644 index 0000000..1d3bbc5 --- /dev/null +++ b/packages/client/dist/join.js @@ -0,0 +1,123 @@ +import { encodeMessage, decodeServerMessage, } from "@chorus/shared"; +export class JoinClient { + relayUrl; + token; + displayName; + ws = null; + state; + onEvent; + onChatMessage; + onTyping; + constructor(relayUrl, token, displayName) { + this.relayUrl = relayUrl; + this.token = token; + this.displayName = displayName; + this.state = { + status: "connecting", + sessionId: "", + users: [], + recentEvents: [], + }; + } + connect() { + return new Promise((resolve, reject) => { + const ws = new WebSocket(this.relayUrl); + this.ws = ws; + ws.onopen = () => { + ws.send(encodeMessage({ type: "auth", token: this.token, displayName: this.displayName })); + }; + ws.onmessage = (ev) => { + let msg; + try { + msg = decodeServerMessage(ev.data); + } + catch { + return; + } + switch (msg.type) { + case "session.history": + this.state.recentEvents = msg.events.slice(-50); + this.state.status = "connected"; + resolve(); + break; + case "session.event": + this.state.recentEvents = [...this.state.recentEvents.slice(-49), msg.event]; + this.onEvent?.(msg.event); + break; + case "user.list": + this.state.users = msg.users; + break; + case "user.joined": + this.state.users = [...this.state.users, msg.user]; + break; + case "user.left": + this.state.users = this.state.users.filter((u) => u.userId !== msg.userId); + break; + case "user.role_changed": + this.state.users = this.state.users.map((u) => u.userId === msg.userId ? { ...u, role: msg.role } : u); + break; + case "chat.message": + this.onChatMessage?.(msg.message.displayName, msg.message.content); + break; + case "user.typing": + this.onTyping?.(msg.displayName); + break; + case "session.closed": + this.state.status = "disconnected"; + ws.close(); + break; + case "error": + this.state.status = "error"; + this.state.error = msg.message; + if (this.state.recentEvents.length === 0) { + reject(new Error(msg.message)); + } + break; + } + }; + ws.onerror = () => { + this.state.status = "error"; + this.state.error = "Connection error"; + reject(new Error("WebSocket connection error")); + }; + ws.onclose = () => { + if (this.state.status === "connected") { + this.state.status = "disconnected"; + } + }; + }); + } + sendInput(content) { + if (!this.ws || this.state.status !== "connected") + return; + this.ws.send(encodeMessage({ type: "collab.input", content })); + } + sendChat(content) { + if (!this.ws || this.state.status !== "connected") + return; + this.ws.send(encodeMessage({ type: "chat.send", content })); + } + setChatHandler(fn) { + this.onChatMessage = fn; + } + setTypingHandler(fn) { + this.onTyping = fn; + } + setEventHandler(fn) { + this.onEvent = fn; + } + sendTyping() { + if (!this.ws || this.state.status !== "connected") + return; + this.ws.send(encodeMessage({ type: "typing" })); + } + getState() { + return this.state; + } + disconnect() { + this.ws?.close(); + this.ws = null; + this.state.status = "disconnected"; + } +} +//# sourceMappingURL=join.js.map \ No newline at end of file diff --git a/packages/client/dist/join.js.map b/packages/client/dist/join.js.map new file mode 100644 index 0000000..0063d25 --- /dev/null +++ b/packages/client/dist/join.js.map @@ -0,0 +1 @@ +{"version":3,"file":"join.js","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/client/dist/relay.d.ts b/packages/client/dist/relay.d.ts new file mode 100644 index 0000000..aad2cee --- /dev/null +++ b/packages/client/dist/relay.d.ts @@ -0,0 +1,63 @@ +import type { SessionEvent, SessionToken, UserRole } from "@chorus/shared"; +export type RelayServerOptions = { + /** Host running the relay (default 127.0.0.1). */ + host?: string; + /** When set with external mode, attach instead of spawning. */ + hostToken?: string; + /** + * Attach to an already-running relay (e.g. on the Docker host). + * When true, requires hostToken and does not spawn/kill a subprocess. + */ + external?: boolean; +}; +/** + * Resolve relay connection settings from env. + * + * External attach (relay already running elsewhere): + * CHORUS_RELAY_HOST=host.docker.internal:7742 + * CHORUS_HOST_TOKEN= + * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) + */ +export declare function relayOptionsFromEnv(defaultPort: number): { + port: number; + opts: RelayServerOptions; +}; +/** + * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. + * Joiner-facing protocol on `/ws` is unchanged; adapters talk to `/host`. + */ +export declare class RelayServer { + private readonly port; + private child; + private ws; + private hostToken; + private running; + private clients; + private readonly host; + private readonly external; + private pendingToken; + private onInjectInput?; + private onChatMessage?; + private onTyping?; + constructor(port: number, opts?: RelayServerOptions); + setInputHandler(fn: (content: string, userId: string, displayName?: string) => Promise): void; + setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; + setTypingHandler(fn: (displayName: string | undefined) => void): void; + start(): Promise; + private statusUrl; + private hostWsUrl; + private waitForPort; + private connectHost; + private handleHostMessage; + private send; + issueToken(sessionId: string, role?: UserRole, ttlMs?: number): Promise; + pushEvent(event: SessionEvent): void; + sendChat(displayName: string | undefined, content: string): void; + stop(): void; + get isRunning(): boolean; + get clientCount(): number; + getPort(): number; + getHost(): string; + isExternal(): boolean; +} +//# sourceMappingURL=relay.d.ts.map \ No newline at end of file diff --git a/packages/client/dist/relay.d.ts.map b/packages/client/dist/relay.d.ts.map new file mode 100644 index 0000000..4200a73 --- /dev/null +++ b/packages/client/dist/relay.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAwB3E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAUF;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAgBA;AAED;;;GAGG;AACH,qBAAa,WAAW;IAkBpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAjBvB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,YAAY,CAGJ;IAEhB,OAAO,CAAC,aAAa,CAAC,CAA2E;IACjG,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;gBAG1C,IAAI,EAAE,MAAM,EAC7B,IAAI,GAAE,kBAAuB;IAO/B,eAAe,CACb,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3E,IAAI;IAIP,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAI/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC5B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;YAIH,WAAW;IAmBzB,OAAO,CAAC,WAAW;IAoCnB,OAAO,CAAC,iBAAiB;IAgDzB,OAAO,CAAC,IAAI;IAKZ,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,QAAiB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB7F,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAIpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIhE,IAAI,IAAI,IAAI;IAqBZ,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM;IAIjB,UAAU,IAAI,OAAO;CAGtB"} \ No newline at end of file diff --git a/packages/client/dist/relay.js b/packages/client/dist/relay.js new file mode 100644 index 0000000..e5ec6c4 --- /dev/null +++ b/packages/client/dist/relay.js @@ -0,0 +1,270 @@ +import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { randomBytes } from "node:crypto"; +import { encodeHostMessage, decodeRelayToHost, } from "@chorus/shared"; +function resolveRelayBin() { + if (process.env["CHORUS_RELAY_BIN"]) + return process.env["CHORUS_RELAY_BIN"]; + const here = dirname(fileURLToPath(import.meta.url)); + const candidates = [ + join(here, "../../../target/release/chorus-relay"), + join(here, "../../../target/debug/chorus-relay"), + join(here, "../../../../target/release/chorus-relay"), + join(here, "../../../../target/debug/chorus-relay"), + ]; + for (const path of candidates) { + if (existsSync(path)) + return path; + } + return "chorus-relay"; +} +function parseRelayHost(raw, fallbackPort) { + if (!raw) + return { host: "127.0.0.1", port: fallbackPort }; + const trimmed = raw.replace(/^wss?:\/\//, "").replace(/\/.*$/, ""); + const [hostPart, portPart] = trimmed.split(":"); + const port = portPart ? parseInt(portPart, 10) : fallbackPort; + return { host: hostPart || "127.0.0.1", port: Number.isFinite(port) ? port : fallbackPort }; +} +/** + * Resolve relay connection settings from env. + * + * External attach (relay already running elsewhere): + * CHORUS_RELAY_HOST=host.docker.internal:7742 + * CHORUS_HOST_TOKEN= + * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) + */ +export function relayOptionsFromEnv(defaultPort) { + const parsed = parseRelayHost(process.env["CHORUS_RELAY_HOST"], defaultPort); + const hostToken = process.env["CHORUS_HOST_TOKEN"]; + const external = process.env["CHORUS_EXTERNAL_RELAY"] === "1" || + process.env["CHORUS_EXTERNAL_RELAY"] === "true" || + Boolean(hostToken && process.env["CHORUS_RELAY_HOST"]); + return { + port: parsed.port, + opts: { + host: parsed.host, + hostToken: hostToken || undefined, + external, + }, + }; +} +/** + * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. + * Joiner-facing protocol on `/ws` is unchanged; adapters talk to `/host`. + */ +export class RelayServer { + port; + child = null; + ws = null; + hostToken = ""; + running = false; + clients = 0; + host; + external; + pendingToken = null; + onInjectInput; + onChatMessage; + onTyping; + constructor(port, opts = {}) { + this.port = port; + this.host = opts.host ?? "127.0.0.1"; + this.external = Boolean(opts.external); + this.hostToken = opts.hostToken ?? ""; + } + setInputHandler(fn) { + this.onInjectInput = fn; + } + setChatHandler(fn) { + this.onChatMessage = fn; + } + setTypingHandler(fn) { + this.onTyping = fn; + } + async start() { + if (this.running) + return; + if (this.external) { + if (!this.hostToken) { + throw new Error("External relay mode requires CHORUS_HOST_TOKEN (and usually CHORUS_RELAY_HOST)."); + } + await this.waitForPort(); + await this.connectHost(); + this.running = true; + return; + } + this.hostToken = this.hostToken || randomBytes(32).toString("hex"); + const bin = resolveRelayBin(); + this.child = spawn(bin, ["--port", String(this.port), "--bind", "0.0.0.0", "--host-token", this.hostToken], { + stdio: ["ignore", "ignore", "pipe"], + env: { ...process.env }, + }); + this.child.on("exit", () => { + this.running = false; + this.ws = null; + }); + await this.waitForPort(); + await this.connectHost(); + this.running = true; + } + statusUrl() { + return `http://${this.host}:${this.port}/status`; + } + hostWsUrl() { + return `ws://${this.host}:${this.port}/host`; + } + async waitForPort(timeoutMs = 8000) { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(1000) }); + if (res.ok) + return; + } + catch { + // not up yet + } + await new Promise((r) => setTimeout(r, 40)); + } + throw new Error(this.external + ? `External chorus-relay not reachable at ${this.host}:${this.port}. Is it running on the host?` + : `chorus-relay did not become ready on port ${this.port}. ` + + `Is the binary available? (CHORUS_RELAY_BIN or cargo build -p chorus-relay --release)`); + } + connectHost() { + return new Promise((resolve, reject) => { + const ws = new WebSocket(this.hostWsUrl()); + this.ws = ws; + const timer = setTimeout(() => reject(new Error("host control connect timeout")), 5000); + ws.onopen = () => { + this.send({ type: "host.auth", token: this.hostToken }); + }; + ws.onmessage = (ev) => { + let msg; + try { + msg = decodeRelayToHost(String(ev.data)); + } + catch { + return; + } + this.handleHostMessage(msg, () => { + clearTimeout(timer); + resolve(); + }); + }; + ws.onerror = () => { + clearTimeout(timer); + reject(new Error("host control WebSocket error")); + }; + ws.onclose = () => { + this.ws = null; + this.running = false; + }; + }); + } + handleHostMessage(msg, onReady) { + switch (msg.type) { + case "host.ready": + onReady?.(); + break; + case "token.issued": { + const { type: _t, ...token } = msg; + this.pendingToken?.resolve(token); + this.pendingToken = null; + break; + } + case "collab.input": + this.onInjectInput?.(msg.content, msg.userId, msg.displayName)?.catch(console.error); + break; + case "chat.message": + this.onChatMessage?.(msg.message.displayName, msg.message.content); + break; + case "user.typing": + this.onTyping?.(msg.displayName); + break; + case "user.joined": + this.clients += 1; + break; + case "user.left": + this.clients = Math.max(0, this.clients - 1); + break; + case "user.list": + this.clients = msg.users.length; + break; + case "status": + this.clients = msg.clients; + break; + case "error": + this.pendingToken?.reject(new Error(msg.message)); + this.pendingToken = null; + break; + } + } + send(msg) { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) + return; + this.ws.send(encodeHostMessage(msg)); + } + issueToken(sessionId, role = "edit", ttlMs) { + return new Promise((resolve, reject) => { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + reject(new Error("relay host control not connected")); + return; + } + this.pendingToken = { resolve, reject }; + this.send({ type: "token.issue", sessionId, role, ttlMs }); + setTimeout(() => { + if (this.pendingToken) { + this.pendingToken.reject(new Error("token.issue timed out")); + this.pendingToken = null; + } + }, 5000); + }); + } + pushEvent(event) { + this.send({ type: "session.event", event }); + } + sendChat(displayName, content) { + this.send({ type: "chat.send", content, displayName }); + } + stop() { + if (!this.external) { + this.send({ type: "host.close" }); + } + try { + this.ws?.close(); + } + catch { + // ignore + } + this.ws = null; + if (this.child && !this.child.killed) { + this.child.kill("SIGTERM"); + setTimeout(() => { + if (this.child && !this.child.killed) + this.child.kill("SIGKILL"); + }, 1000).unref?.(); + } + this.child = null; + this.running = false; + this.clients = 0; + } + get isRunning() { + return this.running; + } + get clientCount() { + return this.clients; + } + getPort() { + return this.port; + } + getHost() { + return this.host; + } + isExternal() { + return this.external; + } +} +//# sourceMappingURL=relay.js.map \ No newline at end of file diff --git a/packages/client/dist/relay.js.map b/packages/client/dist/relay.js.map new file mode 100644 index 0000000..263dfdc --- /dev/null +++ b/packages/client/dist/relay.js.map @@ -0,0 +1 @@ +{"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAGlB,MAAM,gBAAgB,CAAC;AAExB,SAAS,eAAe;IACtB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAE5E,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,EAAE,sCAAsC,CAAC;QAClD,IAAI,CAAC,IAAI,EAAE,oCAAoC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,yCAAyC,CAAC;QACrD,IAAI,CAAC,IAAI,EAAE,uCAAuC,CAAC;KACpD,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACpC,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAcD,SAAS,cAAc,CAAC,GAAuB,EAAE,YAAoB;IACnE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAC9D,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;AAC9F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IAIrD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,WAAW,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnD,MAAM,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG;QAC5C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,MAAM;QAC/C,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAEzD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,SAAS,EAAE,SAAS,IAAI,SAAS;YACjC,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,WAAW;IAkBH;IAjBX,KAAK,GAAwB,IAAI,CAAC;IAClC,EAAE,GAAqB,IAAI,CAAC;IAC5B,SAAS,GAAG,EAAE,CAAC;IACf,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,CAAC,CAAC;IACH,IAAI,CAAS;IACb,QAAQ,CAAU;IAC3B,YAAY,GAGT,IAAI,CAAC;IAER,aAAa,CAA4E;IACzF,aAAa,CAA8D;IAC3E,QAAQ,CAA6C;IAE7D,YACmB,IAAY,EAC7B,OAA2B,EAAE;QADZ,SAAI,GAAJ,IAAI,CAAQ;QAG7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,eAAe,CACb,EAA4E;QAE5E,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,cAAc,CAAC,EAA8D;QAC3E,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,gBAAgB,CAAC,EAA6C;QAC5D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAE9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAChB,GAAG,EACH,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAClF;YACE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;YACnC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,CACF,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACzB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAEO,SAAS;QACf,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,SAAS,CAAC;IACnD,CAAC;IAEO,SAAS;QACf,OAAO,QAAQ,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,OAAO,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjF,IAAI,GAAG,CAAC,EAAE;oBAAE,OAAO;YACrB,CAAC;YAAC,MAAM,CAAC;gBACP,aAAa;YACf,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,IAAI,KAAK,CACb,IAAI,CAAC,QAAQ;YACX,CAAC,CAAC,0CAA0C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,8BAA8B;YAChG,CAAC,CAAC,6CAA6C,IAAI,CAAC,IAAI,IAAI;gBACxD,sFAAsF,CAC7F,CAAC;IACJ,CAAC;IAEO,WAAW;QACjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;YAEb,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAExF,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;gBACf,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC1D,CAAC,CAAC;YAEF,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE;gBACpB,IAAI,GAAgB,CAAC;gBACrB,IAAI,CAAC;oBACH,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC3C,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE;oBAC/B,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;YACL,CAAC,CAAC;YAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBAChB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;YACpD,CAAC,CAAC;YAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB,CAAC,GAAgB,EAAE,OAAoB;QAC9D,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,YAAY;gBACf,OAAO,EAAE,EAAE,CAAC;gBACZ,MAAM;YAER,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,GAAG,CAAC;gBACnC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,MAAM;YACR,CAAC;YAED,KAAK,cAAc;gBACjB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACrF,MAAM;YAER,KAAK,cAAc;gBACjB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnE,MAAM;YAER,KAAK,aAAa;gBAChB,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACjC,MAAM;YAER,KAAK,aAAa;gBAChB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;gBAClB,MAAM;YAER,KAAK,WAAW;gBACd,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;gBAC7C,MAAM;YAER,KAAK,WAAW;gBACd,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;gBAChC,MAAM;YAER,KAAK,QAAQ;gBACX,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;gBAC3B,MAAM;YAER,KAAK,OAAO;gBACV,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,MAAM;QACV,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,GAAgB;QAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;YAAE,OAAO;QAC9D,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,OAAiB,MAAM,EAAE,KAAc;QACnE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACtD,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBACtD,OAAO;YACT,CAAC;YACD,IAAI,CAAC,YAAY,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3D,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACtB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;oBAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC3B,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,CAAC,KAAmB;QAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ,CAAC,WAA+B,EAAE,OAAe;QACvD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACf,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3B,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;oBAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACnE,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"} \ No newline at end of file diff --git a/packages/client/package.json b/packages/client/package.json new file mode 100644 index 0000000..cfb9fb2 --- /dev/null +++ b/packages/client/package.json @@ -0,0 +1,28 @@ +{ + "name": "@chorus/client", + "version": "0.1.0", + "private": true, + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsc", + "typecheck": "tsc --noEmit", + "test": "bun test test/join.test.ts test/relay.test.ts", + "clean": "rm -rf dist" + }, + "dependencies": { + "@chorus/shared": "workspace:*" + }, + "devDependencies": { + "@types/bun": "latest", + "@types/node": "^22.10.7", + "typescript": "^5.7.3" + } +} diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts new file mode 100644 index 0000000..31fcde8 --- /dev/null +++ b/packages/client/src/index.ts @@ -0,0 +1,11 @@ +export { + JoinClient, + type JoinState, + type JoinStatus, +} from "./join.js"; +export { + RelayServer, + relayOptionsFromEnv, + type RelayServerOptions, + type RelayNetworkOptions, +} from "./relay.js"; diff --git a/packages/client/src/join.ts b/packages/client/src/join.ts new file mode 100644 index 0000000..1d5290e --- /dev/null +++ b/packages/client/src/join.ts @@ -0,0 +1,158 @@ +import type { SessionEvent, ConnectedUser } from "@chorus/shared"; +import { + encodeMessage, + decodeServerMessage, + type ServerMessage, +} from "@chorus/shared"; + +export type JoinStatus = "connecting" | "connected" | "disconnected" | "error"; + +export interface JoinState { + status: JoinStatus; + sessionId: string; + users: ConnectedUser[]; + recentEvents: SessionEvent[]; + error?: string; +} + +export class JoinClient { + private ws: WebSocket | null = null; + private state: JoinState; + private onEvent?: (event: SessionEvent) => void; + private onChatMessage?: (displayName: string | undefined, content: string) => void; + private onTyping?: (displayName: string | undefined) => void; + + constructor( + private readonly relayUrl: string, + private readonly token: string, + private readonly displayName: string + ) { + this.state = { + status: "connecting", + sessionId: "", + users: [], + recentEvents: [], + }; + } + + connect(): Promise { + return new Promise((resolve, reject) => { + const ws = new WebSocket(this.relayUrl); + this.ws = ws; + + ws.onopen = () => { + ws.send(encodeMessage({ type: "auth", token: this.token, displayName: this.displayName })); + }; + + ws.onmessage = (ev) => { + let msg: ServerMessage; + try { + msg = decodeServerMessage(ev.data as string); + } catch { + return; + } + + switch (msg.type) { + case "session.history": + this.state.recentEvents = msg.events.slice(-50); + this.state.status = "connected"; + resolve(); + break; + + case "session.event": + this.state.recentEvents = [...this.state.recentEvents.slice(-49), msg.event]; + this.onEvent?.(msg.event); + break; + + case "user.list": + this.state.users = msg.users; + break; + + case "user.joined": + this.state.users = [...this.state.users, msg.user]; + break; + + case "user.left": + this.state.users = this.state.users.filter((u) => u.userId !== msg.userId); + break; + + case "user.role_changed": + this.state.users = this.state.users.map((u) => + u.userId === msg.userId ? { ...u, role: msg.role } : u + ); + break; + + case "chat.message": + this.onChatMessage?.(msg.message.displayName, msg.message.content); + break; + + case "user.typing": + this.onTyping?.(msg.displayName); + break; + + case "session.closed": + this.state.status = "disconnected"; + ws.close(); + break; + + case "error": + this.state.status = "error"; + this.state.error = msg.message; + if (this.state.recentEvents.length === 0) { + reject(new Error(msg.message)); + } + break; + } + }; + + ws.onerror = () => { + this.state.status = "error"; + this.state.error = "Connection error"; + reject(new Error("WebSocket connection error")); + }; + + ws.onclose = () => { + if (this.state.status === "connected") { + this.state.status = "disconnected"; + } + }; + }); + } + + sendInput(content: string): void { + if (!this.ws || this.state.status !== "connected") return; + this.ws.send(encodeMessage({ type: "collab.input", content })); + } + + sendChat(content: string): void { + if (!this.ws || this.state.status !== "connected") return; + this.ws.send(encodeMessage({ type: "chat.send", content })); + } + + setChatHandler(fn: (displayName: string | undefined, content: string) => void): void { + this.onChatMessage = fn; + } + + setTypingHandler(fn: (displayName: string | undefined) => void): void { + this.onTyping = fn; + } + + setEventHandler(fn: (event: SessionEvent) => void): void { + this.onEvent = fn; + } + + sendTyping(): void { + if (!this.ws || this.state.status !== "connected") return; + this.ws.send(encodeMessage({ type: "typing" })); + } + + getState(): Readonly { + return this.state; + } + + disconnect(): void { + this.ws?.close(); + this.ws = null; + this.state.status = "disconnected"; + } +} diff --git a/packages/client/src/relay.ts b/packages/client/src/relay.ts new file mode 100644 index 0000000..7d19f41 --- /dev/null +++ b/packages/client/src/relay.ts @@ -0,0 +1,498 @@ +import { spawn, type ChildProcess } from "node:child_process"; +import { existsSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { randomBytes } from "node:crypto"; +import type { ConnectedUser, SessionEvent, SessionToken, UserRole } from "@chorus/shared"; +import { + encodeHostMessage, + decodeRelayToHost, + type HostToRelay, + type RelayToHost, +} from "@chorus/shared"; + +function resolveRelayBin(): string { + if (process.env["CHORUS_RELAY_BIN"]) return process.env["CHORUS_RELAY_BIN"]; + + const here = dirname(fileURLToPath(import.meta.url)); + const candidates = [ + join(here, "../../../target/release/chorus-relay"), + join(here, "../../../target/debug/chorus-relay"), + join(here, "../../../../target/release/chorus-relay"), + join(here, "../../../../target/debug/chorus-relay"), + join(here, "../../../../../target/release/chorus-relay"), + join(here, "../../../../../target/debug/chorus-relay"), + ]; + for (const path of candidates) { + if (existsSync(path)) return path; + } + return "chorus-relay"; +} + +export type RelayServerOptions = { + /** Host running the relay (default 127.0.0.1). */ + host?: string; + /** When set with external mode, attach instead of spawning. */ + hostToken?: string; + /** + * Attach to an already-running relay (e.g. on the Docker host). + * When true, requires hostToken and does not spawn/kill a subprocess. + */ + external?: boolean; + /** Bind address passed to chorus-relay (default 0.0.0.0). */ + bind?: string; + /** CIDR/IP allowlist for TCP peers. */ + allowedCidrs?: string[]; + /** Explicit deny CIDRs (deny wins). */ + deniedCidrs?: string[]; + /** Peer source-port allowlist (single-machine e2e). */ + allowedPorts?: number[]; + /** Refuse 0.0.0.0 / :: bind when false. */ + allowOpenBind?: boolean; + /** Admit loopback IPs even when allowlist is set (default true). */ + allowLoopback?: boolean; +}; + +export type RelayNetworkOptions = { + bind?: string; + allowedCidrs?: string[]; + deniedCidrs?: string[]; + allowedPorts?: number[]; + allowOpenBind?: boolean; + allowLoopback?: boolean; +}; + +function parseRelayHost(raw: string | undefined, fallbackPort: number): { host: string; port: number } { + if (!raw) return { host: "127.0.0.1", port: fallbackPort }; + const trimmed = raw.replace(/^wss?:\/\//, "").replace(/\/.*$/, ""); + const [hostPart, portPart] = trimmed.split(":"); + const port = portPart ? parseInt(portPart, 10) : fallbackPort; + return { host: hostPart || "127.0.0.1", port: Number.isFinite(port) ? port : fallbackPort }; +} + +/** + * Resolve relay connection settings from env. + * + * External attach (relay already running elsewhere): + * CHORUS_RELAY_HOST=host.docker.internal:7742 + * CHORUS_HOST_TOKEN= + * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) + */ +export function relayOptionsFromEnv(defaultPort: number): { + port: number; + opts: RelayServerOptions; +} { + const parsed = parseRelayHost(process.env["CHORUS_RELAY_HOST"], defaultPort); + const hostToken = process.env["CHORUS_HOST_TOKEN"]; + const external = + process.env["CHORUS_EXTERNAL_RELAY"] === "1" || + process.env["CHORUS_EXTERNAL_RELAY"] === "true" || + Boolean(hostToken && process.env["CHORUS_RELAY_HOST"]); + + return { + port: parsed.port, + opts: { + host: parsed.host, + hostToken: hostToken || undefined, + external, + }, + }; +} + +/** + * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. + * Joiner-facing protocol on `/ws` is unchanged; host adapters talk to `/host`. + */ +export class RelayServer { + private child: ChildProcess | null = null; + private ws: WebSocket | null = null; + private hostToken = ""; + private running = false; + private clients = 0; + private readonly host: string; + private readonly external: boolean; + private bind: string; + private allowedCidrs: string[]; + private deniedCidrs: string[]; + private allowedPorts: number[]; + private allowOpenBind: boolean; + private allowLoopback: boolean; + private pendingToken: { + resolve: (t: SessionToken) => void; + reject: (e: Error) => void; + } | null = null; + + private onInjectInput?: (content: string, userId: string, displayName?: string) => Promise; + private onChatMessage?: (displayName: string | undefined, content: string) => void; + private onTyping?: (displayName: string | undefined) => void; + private onUserPending?: (user: ConnectedUser) => void; + private onUserJoined?: (user: ConnectedUser) => void; + private onUserLeft?: (userId: string) => void; + + constructor( + private readonly port: number, + opts: RelayServerOptions = {} + ) { + this.host = opts.host ?? "127.0.0.1"; + this.external = Boolean(opts.external); + this.hostToken = opts.hostToken ?? ""; + this.bind = opts.bind ?? "0.0.0.0"; + this.allowedCidrs = opts.allowedCidrs ? [...opts.allowedCidrs] : []; + this.deniedCidrs = opts.deniedCidrs ? [...opts.deniedCidrs] : []; + this.allowedPorts = opts.allowedPorts ? [...opts.allowedPorts] : []; + this.allowOpenBind = opts.allowOpenBind ?? true; + this.allowLoopback = opts.allowLoopback ?? true; + } + + /** Apply network policy before start() (from project/org chorus.json). */ + setNetworkOptions(opts: RelayNetworkOptions): void { + if (opts.bind !== undefined) this.bind = opts.bind; + if (opts.allowedCidrs !== undefined) this.allowedCidrs = [...opts.allowedCidrs]; + if (opts.deniedCidrs !== undefined) this.deniedCidrs = [...opts.deniedCidrs]; + if (opts.allowedPorts !== undefined) this.allowedPorts = [...opts.allowedPorts]; + if (opts.allowOpenBind !== undefined) this.allowOpenBind = opts.allowOpenBind; + if (opts.allowLoopback !== undefined) this.allowLoopback = opts.allowLoopback; + } + + setInputHandler( + fn: (content: string, userId: string, displayName?: string) => Promise + ): void { + this.onInjectInput = fn; + } + + setChatHandler(fn: (displayName: string | undefined, content: string) => void): void { + this.onChatMessage = fn; + } + + setTypingHandler(fn: (displayName: string | undefined) => void): void { + this.onTyping = fn; + } + + setUserPendingHandler(fn: (user: ConnectedUser) => void): void { + this.onUserPending = fn; + } + + setUserJoinedHandler(fn: (user: ConnectedUser) => void): void { + this.onUserJoined = fn; + } + + setUserLeftHandler(fn: (userId: string) => void): void { + this.onUserLeft = fn; + } + + async start(): Promise { + if (this.running) return; + + if (this.external) { + if (!this.hostToken) { + throw new Error( + "External relay mode requires CHORUS_HOST_TOKEN (and usually CHORUS_RELAY_HOST)." + ); + } + await this.waitForPort(); + await this.connectHost(); + this.running = true; + return; + } + + this.hostToken = this.hostToken || randomBytes(32).toString("hex"); + const bin = resolveRelayBin(); + + const args = [ + "--port", + String(this.port), + "--bind", + this.bind, + "--host-token", + this.hostToken, + "--allow-open-bind", + this.allowOpenBind ? "true" : "false", + "--allow-loopback", + this.allowLoopback ? "true" : "false", + ]; + for (const cidr of this.allowedCidrs) { + args.push("--allow-cidr", cidr); + } + for (const cidr of this.deniedCidrs) { + args.push("--deny-cidr", cidr); + } + for (const port of this.allowedPorts) { + args.push("--allow-port", String(port)); + } + + this.child = spawn(bin, args, { + stdio: ["ignore", "ignore", "pipe"], + env: { ...process.env }, + }); + + this.child.on("exit", () => { + this.running = false; + this.ws = null; + }); + + await this.waitForPort(); + await this.connectHost(); + this.running = true; + } + + private statusUrl(): string { + return `http://${this.host}:${this.port}/status`; + } + + private hostWsUrl(): string { + return `ws://${this.host}:${this.port}/host`; + } + + private async waitForPort(timeoutMs = 8000): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(1000) }); + if (res.ok) return; + } catch { + // not up yet + } + await new Promise((r) => setTimeout(r, 40)); + } + throw new Error( + this.external + ? `External chorus-relay not reachable at ${this.host}:${this.port}. Is it running on the host?` + : `chorus-relay did not become ready on port ${this.port}. ` + + `Is the binary available? (CHORUS_RELAY_BIN or cargo build -p chorus-relay --release)` + ); + } + + private connectHost(): Promise { + return new Promise((resolve, reject) => { + const ws = new WebSocket(this.hostWsUrl()); + this.ws = ws; + + const timer = setTimeout(() => reject(new Error("host control connect timeout")), 5000); + + ws.onopen = () => { + this.send({ type: "host.auth", token: this.hostToken }); + }; + + ws.onmessage = (ev) => { + let msg: RelayToHost; + try { + msg = decodeRelayToHost(String(ev.data)); + } catch { + return; + } + this.handleHostMessage(msg, () => { + clearTimeout(timer); + resolve(); + }); + }; + + ws.onerror = () => { + clearTimeout(timer); + reject(new Error("host control WebSocket error")); + }; + + ws.onclose = () => { + this.ws = null; + this.running = false; + }; + }); + } + + private handleHostMessage(msg: RelayToHost, onReady?: () => void): void { + switch (msg.type) { + case "host.ready": + onReady?.(); + break; + + case "token.issued": { + const { type: _t, ...token } = msg; + this.pendingToken?.resolve(token); + this.pendingToken = null; + break; + } + + case "collab.input": + this.onInjectInput?.(msg.content, msg.userId, msg.displayName)?.catch(console.error); + break; + + case "chat.message": + this.onChatMessage?.(msg.message.displayName, msg.message.content); + break; + + case "user.typing": + this.onTyping?.(msg.displayName); + break; + + case "user.pending": + this.onUserPending?.(msg.user); + break; + + case "user.joined": + this.clients += 1; + this.onUserJoined?.(msg.user); + break; + + case "user.left": + this.clients = Math.max(0, this.clients - 1); + this.onUserLeft?.(msg.userId); + break; + + case "user.list": + this.clients = msg.users.filter((u) => u.status === "active").length; + break; + + case "status": + this.clients = msg.clients; + break; + + case "error": + this.pendingToken?.reject(new Error(msg.message)); + this.pendingToken = null; + break; + } + } + + private send(msg: HostToRelay): void { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; + this.ws.send(encodeHostMessage(msg)); + } + + issueToken(sessionId: string, role: UserRole = "edit", ttlMs?: number): Promise { + return new Promise((resolve, reject) => { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + reject(new Error("relay host control not connected")); + return; + } + this.pendingToken = { resolve, reject }; + this.send({ type: "token.issue", sessionId, role, ttlMs }); + setTimeout(() => { + if (this.pendingToken) { + this.pendingToken.reject(new Error("token.issue timed out")); + this.pendingToken = null; + } + }, 5000); + }); + } + + setSessionPolicy(opts: { + requireApproval?: boolean; + repoRemote?: string | null; + allowedEmailDomain?: string | null; + additionalRepoRemotePrefixes?: string[] | null; + repoRemoteRewrites?: { from: string; to: string }[] | null; + }): void { + this.send({ + type: "session.policy", + requireApproval: opts.requireApproval, + repoRemote: opts.repoRemote === null ? "" : opts.repoRemote, + allowedEmailDomain: + opts.allowedEmailDomain === null ? "" : opts.allowedEmailDomain, + additionalRepoRemotePrefixes: opts.additionalRepoRemotePrefixes ?? undefined, + repoRemoteRewrites: opts.repoRemoteRewrites ?? undefined, + }); + } + + approveUser(userId: string): void { + this.send({ type: "host.approve", userId }); + } + + denyUser(userId: string): void { + this.send({ type: "host.deny", userId }); + } + + kickUser(userId: string): void { + this.send({ type: "host.kick", userId }); + } + + pushEvent(event: SessionEvent): void { + this.send({ type: "session.event", event }); + } + + sendChat(displayName: string | undefined, content: string): void { + this.send({ type: "chat.send", content, displayName }); + } + + async stop(): Promise { + if (!this.external) { + this.send({ type: "host.close" }); + } + try { + this.ws?.close(); + } catch { + // ignore + } + this.ws = null; + + const child = this.child; + this.child = null; + this.running = false; + this.clients = 0; + + if (child && child.exitCode === null && child.signalCode === null) { + await new Promise((resolve) => { + const finish = () => resolve(); + child.once("exit", finish); + try { + child.kill("SIGTERM"); + } catch { + finish(); + return; + } + setTimeout(() => { + if (child.exitCode === null && child.signalCode === null) { + try { + child.kill("SIGKILL"); + } catch { + finish(); + } + } + }, 1000).unref?.(); + }); + } + + if (!this.external) { + await this.waitUntilStopped(); + } + } + + private async waitUntilStopped(timeoutMs = 2000): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(250) }); + if (!res.ok) return; + } catch { + return; + } + await new Promise((r) => setTimeout(r, 20)); + } + } + + get isRunning(): boolean { + return this.running; + } + + get clientCount(): number { + return this.clients; + } + + getPort(): number { + return this.port; + } + + getHost(): string { + return this.host; + } + + getBind(): string { + return this.bind; + } + + getAllowedCidrs(): string[] { + return [...this.allowedCidrs]; + } + + isExternal(): boolean { + return this.external; + } +} diff --git a/packages/plugin/test/join.test.ts b/packages/client/test/join.test.ts similarity index 97% rename from packages/plugin/test/join.test.ts rename to packages/client/test/join.test.ts index 66f8159..09235bb 100644 --- a/packages/plugin/test/join.test.ts +++ b/packages/client/test/join.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, setDefaultTimeout } from "bun:test"; -import { JoinClient } from "../src/join/index.js"; -import { RelayServer } from "../src/relay/index.js"; +import { JoinClient, RelayServer } from "../src/index.js"; setDefaultTimeout(15_000); diff --git a/packages/plugin/test/relay.test.ts b/packages/client/test/relay.test.ts similarity index 99% rename from packages/plugin/test/relay.test.ts rename to packages/client/test/relay.test.ts index 08062e0..2aa27d7 100644 --- a/packages/plugin/test/relay.test.ts +++ b/packages/client/test/relay.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, setDefaultTimeout } from "bun:test"; -import { RelayServer } from "../src/relay/index.js"; +import { RelayServer } from "../src/index.js"; import type { ServerMessage } from "@chorus/shared"; import { encodeMessage, decodeServerMessage } from "@chorus/shared"; diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json new file mode 100644 index 0000000..bdbdd6e --- /dev/null +++ b/packages/client/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "types": ["bun", "node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} diff --git a/packages/plugin/dist/index.d.ts b/packages/plugin/dist/index.d.ts index 43198b1..191fdc0 100644 --- a/packages/plugin/dist/index.d.ts +++ b/packages/plugin/dist/index.d.ts @@ -111,9 +111,9 @@ export default function chorusPlugin(input: PluginInput): Promise<{ description: string; args: { role: z.ZodOptional>; requireApproval: z.ZodOptional; }; diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 686bdf4..a244815 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -32,13 +32,14 @@ "scripts": { "build": "tsc", "typecheck": "tsc --noEmit", - "test": "vitest run test/access.test.ts test/backup.test.ts test/config.test.ts test/join-command.test.ts test/pending-queue.test.ts test/transcript.test.ts && bun test test/relay.test.ts test/join.test.ts", + "test": "vitest run test/access.test.ts test/backup.test.ts test/config.test.ts test/join-command.test.ts test/pending-queue.test.ts test/transcript.test.ts", "test:watch": "vitest", "clean": "rm -rf dist" }, "dependencies": { "@aws-sdk/client-s3": "^3.726.0", "@aws-sdk/lib-storage": "^3.726.0", + "@chorus/client": "workspace:*", "@chorus/shared": "workspace:*", "zod": "4.1.8" }, diff --git a/packages/plugin/src/join/index.ts b/packages/plugin/src/join/index.ts index e3b78a5..030eff9 100644 --- a/packages/plugin/src/join/index.ts +++ b/packages/plugin/src/join/index.ts @@ -1,215 +1 @@ -import type { SessionEvent, ConnectedUser } from "@chorus/shared"; -import { - encodeMessage, - decodeServerMessage, - type ServerMessage, -} from "@chorus/shared"; - -export type JoinStatus = "connecting" | "pending" | "connected" | "disconnected" | "error"; - -export interface JoinState { - status: JoinStatus; - sessionId: string; - userId?: string; - users: ConnectedUser[]; - recentEvents: SessionEvent[]; - error?: string; -} - -export class JoinClient { - private ws: WebSocket | null = null; - private state: JoinState; - private onEvent?: (event: SessionEvent) => void; - private onChatMessage?: (displayName: string | undefined, content: string) => void; - private onTyping?: (displayName: string | undefined) => void; - private onPending?: (userId: string) => void; - private onApproved?: () => void; - - constructor( - private readonly relayUrl: string, - private readonly token: string, - private readonly displayName: string, - private readonly repoRemote?: string, - private readonly email?: string - ) { - this.state = { - status: "connecting", - sessionId: "", - users: [], - recentEvents: [], - }; - } - - connect(): Promise { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.relayUrl); - this.ws = ws; - let settled = false; - - const succeed = () => { - if (settled) return; - settled = true; - resolve(); - }; - - const fail = (err: Error) => { - if (settled) return; - settled = true; - reject(err); - }; - - ws.onopen = () => { - const auth: { - type: "auth"; - token: string; - displayName: string; - repoRemote?: string; - email?: string; - } = { - type: "auth", - token: this.token, - displayName: this.displayName, - }; - if (this.repoRemote) auth.repoRemote = this.repoRemote; - if (this.email) auth.email = this.email; - ws.send(encodeMessage(auth)); - }; - - ws.onmessage = (ev) => { - let msg: ServerMessage; - try { - msg = decodeServerMessage(ev.data as string); - } catch { - return; - } - - switch (msg.type) { - case "auth.pending": - this.state.status = "pending"; - this.state.userId = msg.userId; - this.onPending?.(msg.userId); - succeed(); - break; - - case "auth.denied": - this.state.status = "error"; - this.state.error = msg.message; - fail(new Error(msg.message)); - ws.close(); - break; - - case "session.history": - this.state.recentEvents = msg.events.slice(-50); - this.state.status = "connected"; - this.onApproved?.(); - succeed(); - break; - - case "session.event": - this.state.recentEvents = [...this.state.recentEvents.slice(-49), msg.event]; - this.onEvent?.(msg.event); - break; - - case "user.list": - this.state.users = msg.users; - break; - - case "user.joined": - this.state.users = [...this.state.users, msg.user]; - break; - - case "user.left": - this.state.users = this.state.users.filter((u) => u.userId !== msg.userId); - break; - - case "user.role_changed": - this.state.users = this.state.users.map((u) => - u.userId === msg.userId ? { ...u, role: msg.role } : u - ); - break; - - case "chat.message": - this.onChatMessage?.(msg.message.displayName, msg.message.content); - break; - - case "user.typing": - this.onTyping?.(msg.displayName); - break; - - case "session.closed": - this.state.status = "disconnected"; - ws.close(); - break; - - case "error": { - const wasAdmitted = - this.state.status === "connected" || this.state.status === "pending"; - this.state.status = "error"; - this.state.error = msg.message; - if (!wasAdmitted) { - fail(new Error(msg.message)); - } - break; - } - } - }; - - ws.onerror = () => { - this.state.status = "error"; - this.state.error = "Connection error"; - fail(new Error("WebSocket connection error")); - }; - - ws.onclose = () => { - if (this.state.status === "connected" || this.state.status === "pending") { - this.state.status = "disconnected"; - } - }; - }); - } - - sendInput(content: string): void { - if (!this.ws || this.state.status !== "connected") return; - this.ws.send(encodeMessage({ type: "collab.input", content })); - } - - sendChat(content: string): void { - if (!this.ws || this.state.status !== "connected") return; - this.ws.send(encodeMessage({ type: "chat.send", content })); - } - - setChatHandler(fn: (displayName: string | undefined, content: string) => void): void { - this.onChatMessage = fn; - } - - setTypingHandler(fn: (displayName: string | undefined) => void): void { - this.onTyping = fn; - } - - setEventHandler(fn: (event: SessionEvent) => void): void { - this.onEvent = fn; - } - - setPendingHandler(fn: (userId: string) => void): void { - this.onPending = fn; - } - - setApprovedHandler(fn: () => void): void { - this.onApproved = fn; - } - - sendTyping(): void { - if (!this.ws || this.state.status !== "connected") return; - this.ws.send(encodeMessage({ type: "typing" })); - } - - getState(): Readonly { - return this.state; - } - - disconnect(): void { - this.ws?.close(); - this.ws = null; - this.state.status = "disconnected"; - } -} +export { JoinClient, type JoinState, type JoinStatus } from "@chorus/client"; diff --git a/packages/plugin/src/relay/index.ts b/packages/plugin/src/relay/index.ts index 5e9d00c..9be2ec4 100644 --- a/packages/plugin/src/relay/index.ts +++ b/packages/plugin/src/relay/index.ts @@ -1,499 +1,6 @@ -import { spawn, type ChildProcess } from "node:child_process"; -import { existsSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { randomBytes } from "node:crypto"; -import type { ConnectedUser, SessionEvent, SessionToken, UserRole } from "@chorus/shared"; -import { - encodeHostMessage, - decodeRelayToHost, - type HostToRelay, - type RelayToHost, -} from "@chorus/shared"; - -function resolveRelayBin(): string { - if (process.env["CHORUS_RELAY_BIN"]) return process.env["CHORUS_RELAY_BIN"]; - - const here = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - join(here, "../../../../target/release/chorus-relay"), - join(here, "../../../../target/debug/chorus-relay"), - join(here, "../../../../../target/release/chorus-relay"), - join(here, "../../../../../target/debug/chorus-relay"), - ]; - for (const path of candidates) { - if (existsSync(path)) return path; - } - return "chorus-relay"; -} - -export type RelayServerOptions = { - /** Host running the relay (default 127.0.0.1). */ - host?: string; - /** When set with external mode, attach instead of spawning. */ - hostToken?: string; - /** - * Attach to an already-running relay (e.g. on the Docker host). - * When true, requires hostToken and does not spawn/kill a subprocess. - */ - external?: boolean; - /** Bind address passed to chorus-relay (default 0.0.0.0). */ - bind?: string; - /** CIDR/IP allowlist for TCP peers. */ - allowedCidrs?: string[]; - /** Explicit deny CIDRs (deny wins). */ - deniedCidrs?: string[]; - /** Peer source-port allowlist (single-machine e2e). */ - allowedPorts?: number[]; - /** Refuse 0.0.0.0 / :: bind when false. */ - allowOpenBind?: boolean; - /** Admit loopback IPs even when allowlist is set (default true). */ - allowLoopback?: boolean; -}; - -export type RelayNetworkOptions = { - bind?: string; - allowedCidrs?: string[]; - deniedCidrs?: string[]; - allowedPorts?: number[]; - allowOpenBind?: boolean; - allowLoopback?: boolean; -}; - -function parseRelayHost(raw: string | undefined, fallbackPort: number): { host: string; port: number } { - if (!raw) return { host: "127.0.0.1", port: fallbackPort }; - // Accept host, host:port, or ws(s)://host:port[/path] - const trimmed = raw.replace(/^wss?:\/\//, "").replace(/\/.*$/, ""); - const [hostPart, portPart] = trimmed.split(":"); - const port = portPart ? parseInt(portPart, 10) : fallbackPort; - return { host: hostPart || "127.0.0.1", port: Number.isFinite(port) ? port : fallbackPort }; -} - -/** - * Resolve relay connection settings from env. - * - * External attach (relay already running elsewhere): - * CHORUS_RELAY_HOST=host.docker.internal:7742 - * CHORUS_HOST_TOKEN= - * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) - */ -export function relayOptionsFromEnv(defaultPort: number): { - port: number; - opts: RelayServerOptions; -} { - const parsed = parseRelayHost(process.env["CHORUS_RELAY_HOST"], defaultPort); - const hostToken = process.env["CHORUS_HOST_TOKEN"]; - const external = - process.env["CHORUS_EXTERNAL_RELAY"] === "1" || - process.env["CHORUS_EXTERNAL_RELAY"] === "true" || - Boolean(hostToken && process.env["CHORUS_RELAY_HOST"]); - - return { - port: parsed.port, - opts: { - host: parsed.host, - hostToken: hostToken || undefined, - external, - }, - }; -} - -/** - * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. - * Joiner-facing protocol on `/ws` is unchanged; the plugin talks to `/host`. - */ -export class RelayServer { - private child: ChildProcess | null = null; - private ws: WebSocket | null = null; - private hostToken = ""; - private running = false; - private clients = 0; - private readonly host: string; - private readonly external: boolean; - private bind: string; - private allowedCidrs: string[]; - private deniedCidrs: string[]; - private allowedPorts: number[]; - private allowOpenBind: boolean; - private allowLoopback: boolean; - private pendingToken: { - resolve: (t: SessionToken) => void; - reject: (e: Error) => void; - } | null = null; - - private onInjectInput?: (content: string, userId: string, displayName?: string) => Promise; - private onChatMessage?: (displayName: string | undefined, content: string) => void; - private onTyping?: (displayName: string | undefined) => void; - private onUserPending?: (user: ConnectedUser) => void; - private onUserJoined?: (user: ConnectedUser) => void; - private onUserLeft?: (userId: string) => void; - - constructor( - private readonly port: number, - opts: RelayServerOptions = {} - ) { - this.host = opts.host ?? "127.0.0.1"; - this.external = Boolean(opts.external); - this.hostToken = opts.hostToken ?? ""; - this.bind = opts.bind ?? "0.0.0.0"; - this.allowedCidrs = opts.allowedCidrs ? [...opts.allowedCidrs] : []; - this.deniedCidrs = opts.deniedCidrs ? [...opts.deniedCidrs] : []; - this.allowedPorts = opts.allowedPorts ? [...opts.allowedPorts] : []; - this.allowOpenBind = opts.allowOpenBind ?? true; - this.allowLoopback = opts.allowLoopback ?? true; - } - - /** Apply network policy before start() (from project/org chorus.json). */ - setNetworkOptions(opts: RelayNetworkOptions): void { - if (opts.bind !== undefined) this.bind = opts.bind; - if (opts.allowedCidrs !== undefined) this.allowedCidrs = [...opts.allowedCidrs]; - if (opts.deniedCidrs !== undefined) this.deniedCidrs = [...opts.deniedCidrs]; - if (opts.allowedPorts !== undefined) this.allowedPorts = [...opts.allowedPorts]; - if (opts.allowOpenBind !== undefined) this.allowOpenBind = opts.allowOpenBind; - if (opts.allowLoopback !== undefined) this.allowLoopback = opts.allowLoopback; - } - - setInputHandler( - fn: (content: string, userId: string, displayName?: string) => Promise - ): void { - this.onInjectInput = fn; - } - - setChatHandler(fn: (displayName: string | undefined, content: string) => void): void { - this.onChatMessage = fn; - } - - setTypingHandler(fn: (displayName: string | undefined) => void): void { - this.onTyping = fn; - } - - setUserPendingHandler(fn: (user: ConnectedUser) => void): void { - this.onUserPending = fn; - } - - setUserJoinedHandler(fn: (user: ConnectedUser) => void): void { - this.onUserJoined = fn; - } - - setUserLeftHandler(fn: (userId: string) => void): void { - this.onUserLeft = fn; - } - - async start(): Promise { - if (this.running) return; - - if (this.external) { - if (!this.hostToken) { - throw new Error( - "External relay mode requires CHORUS_HOST_TOKEN (and usually CHORUS_RELAY_HOST)." - ); - } - await this.waitForPort(); - await this.connectHost(); - this.running = true; - return; - } - - this.hostToken = this.hostToken || randomBytes(32).toString("hex"); - const bin = resolveRelayBin(); - - const args = [ - "--port", - String(this.port), - "--bind", - this.bind, - "--host-token", - this.hostToken, - "--allow-open-bind", - this.allowOpenBind ? "true" : "false", - "--allow-loopback", - this.allowLoopback ? "true" : "false", - ]; - for (const cidr of this.allowedCidrs) { - args.push("--allow-cidr", cidr); - } - for (const cidr of this.deniedCidrs) { - args.push("--deny-cidr", cidr); - } - for (const port of this.allowedPorts) { - args.push("--allow-port", String(port)); - } - - this.child = spawn(bin, args, { - stdio: ["ignore", "ignore", "pipe"], - env: { ...process.env }, - }); - - this.child.on("exit", () => { - this.running = false; - this.ws = null; - }); - - await this.waitForPort(); - await this.connectHost(); - this.running = true; - } - - private statusUrl(): string { - return `http://${this.host}:${this.port}/status`; - } - - private hostWsUrl(): string { - return `ws://${this.host}:${this.port}/host`; - } - - private async waitForPort(timeoutMs = 8000): Promise { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - try { - const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(1000) }); - if (res.ok) return; - } catch { - // not up yet - } - await new Promise((r) => setTimeout(r, 40)); - } - throw new Error( - this.external - ? `External chorus-relay not reachable at ${this.host}:${this.port}. Is it running on the host?` - : `chorus-relay did not become ready on port ${this.port}. ` + - `Is the binary available? (CHORUS_RELAY_BIN or cargo build -p chorus-relay --release)` - ); - } - - private connectHost(): Promise { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.hostWsUrl()); - this.ws = ws; - - const timer = setTimeout(() => reject(new Error("host control connect timeout")), 5000); - - ws.onopen = () => { - this.send({ type: "host.auth", token: this.hostToken }); - }; - - ws.onmessage = (ev) => { - let msg: RelayToHost; - try { - msg = decodeRelayToHost(String(ev.data)); - } catch { - return; - } - this.handleHostMessage(msg, () => { - clearTimeout(timer); - resolve(); - }); - }; - - ws.onerror = () => { - clearTimeout(timer); - reject(new Error("host control WebSocket error")); - }; - - ws.onclose = () => { - this.ws = null; - this.running = false; - }; - }); - } - - private handleHostMessage(msg: RelayToHost, onReady?: () => void): void { - switch (msg.type) { - case "host.ready": - onReady?.(); - break; - - case "token.issued": { - const { type: _t, ...token } = msg; - this.pendingToken?.resolve(token); - this.pendingToken = null; - break; - } - - case "collab.input": - this.onInjectInput?.(msg.content, msg.userId, msg.displayName)?.catch(console.error); - break; - - case "chat.message": - this.onChatMessage?.(msg.message.displayName, msg.message.content); - break; - - case "user.typing": - this.onTyping?.(msg.displayName); - break; - - case "user.pending": - this.onUserPending?.(msg.user); - break; - - case "user.joined": - this.clients += 1; - this.onUserJoined?.(msg.user); - break; - - case "user.left": - this.clients = Math.max(0, this.clients - 1); - this.onUserLeft?.(msg.userId); - break; - - case "user.list": - this.clients = msg.users.filter((u) => u.status === "active").length; - break; - - case "status": - this.clients = msg.clients; - break; - - case "error": - this.pendingToken?.reject(new Error(msg.message)); - this.pendingToken = null; - break; - } - } - - private send(msg: HostToRelay): void { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; - this.ws.send(encodeHostMessage(msg)); - } - - issueToken(sessionId: string, role: UserRole = "edit", ttlMs?: number): Promise { - return new Promise((resolve, reject) => { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { - reject(new Error("relay host control not connected")); - return; - } - this.pendingToken = { resolve, reject }; - this.send({ type: "token.issue", sessionId, role, ttlMs }); - setTimeout(() => { - if (this.pendingToken) { - this.pendingToken.reject(new Error("token.issue timed out")); - this.pendingToken = null; - } - }, 5000); - }); - } - - setSessionPolicy(opts: { - requireApproval?: boolean; - repoRemote?: string | null; - allowedEmailDomain?: string | null; - additionalRepoRemotePrefixes?: string[] | null; - repoRemoteRewrites?: { from: string; to: string }[] | null; - }): void { - this.send({ - type: "session.policy", - requireApproval: opts.requireApproval, - repoRemote: opts.repoRemote === null ? "" : opts.repoRemote, - allowedEmailDomain: - opts.allowedEmailDomain === null ? "" : opts.allowedEmailDomain, - additionalRepoRemotePrefixes: opts.additionalRepoRemotePrefixes ?? undefined, - repoRemoteRewrites: opts.repoRemoteRewrites ?? undefined, - }); - } - - approveUser(userId: string): void { - this.send({ type: "host.approve", userId }); - } - - denyUser(userId: string): void { - this.send({ type: "host.deny", userId }); - } - - kickUser(userId: string): void { - this.send({ type: "host.kick", userId }); - } - - pushEvent(event: SessionEvent): void { - this.send({ type: "session.event", event }); - } - - sendChat(displayName: string | undefined, content: string): void { - this.send({ type: "chat.send", content, displayName }); - } - - async stop(): Promise { - // Only tear down session state on relays we own. External relays stay up - // so container agents can reconnect across test runs. - if (!this.external) { - this.send({ type: "host.close" }); - } - try { - this.ws?.close(); - } catch { - // ignore - } - this.ws = null; - - const child = this.child; - this.child = null; - this.running = false; - this.clients = 0; - - if (child && child.exitCode === null && child.signalCode === null) { - await new Promise((resolve) => { - const finish = () => resolve(); - child.once("exit", finish); - try { - child.kill("SIGTERM"); - } catch { - finish(); - return; - } - setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) { - try { - child.kill("SIGKILL"); - } catch { - finish(); - } - } - }, 1000).unref?.(); - }); - } - - if (!this.external) { - await this.waitUntilStopped(); - } - } - - private async waitUntilStopped(timeoutMs = 2000): Promise { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - try { - const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(250) }); - if (!res.ok) return; - } catch { - return; - } - await new Promise((r) => setTimeout(r, 20)); - } - } - - get isRunning(): boolean { - return this.running; - } - - get clientCount(): number { - return this.clients; - } - - getPort(): number { - return this.port; - } - - getHost(): string { - return this.host; - } - - getBind(): string { - return this.bind; - } - - getAllowedCidrs(): string[] { - return [...this.allowedCidrs]; - } - - isExternal(): boolean { - return this.external; - } -} +export { + RelayServer, + relayOptionsFromEnv, + type RelayServerOptions, + type RelayNetworkOptions, +} from "@chorus/client"; diff --git a/packages/vscode/README.md b/packages/vscode/README.md new file mode 100644 index 0000000..7233f84 --- /dev/null +++ b/packages/vscode/README.md @@ -0,0 +1,61 @@ +# Chorus VS Code extension + +VS Code adapter for [Chorus](../../README.md) — share or join a live collaborative AI session over `chorus-relay`. + +## What it does + +| Command | Behavior | +|---|---| +| **Chorus: Share Session** | Spawns/attaches `chorus-relay`, issues a join token, copies `/chorus-join …` to the clipboard | +| **Chorus: Join Session** | Connects to `/ws` with token + host | +| **Chorus: Send Prompt to Host** | Joiner `collab.input` into the shared session | +| **Chorus: Publish Host Message** | Host `session.event` fan-out to joiners | +| **Chorus: Send Chat Message** | Side-channel chat (not LLM history) | +| **Chorus: Leave / Stop / Status** | Disconnect / tear down / inspect state | + +The **Chorus** activity-bar panel shows the mirrored transcript and a compose box. + +## Honest scope (v1) + +- Speaks the same wire protocol as the OpenCode plugin (`@chorus/shared` + `@chorus/client`). +- VS Code is **not** an OpenCode host: it does not drive OpenCode’s LLM loop. When you **share** from VS Code, collaborator prompts appear in the panel/notifications; publish host/AI lines manually (or pair with an OpenCode host that owns the model). +- When you **join** an OpenCode-hosted session, prompts you send are real `collab.input` and the host transcript streams into the panel. + +## Prerequisites + +```sh +# from repo root +cargo build -p chorus-relay --release +bun install +bun run build:ts +``` + +Ensure `chorus-relay` is on `PATH`, or set `chorus.relayBin` / `CHORUS_RELAY_BIN`. + +## Install (dev) + +1. Build this package: `bun run --filter chorus build` +2. In VS Code: **Extensions: Install from Location…** → select `packages/vscode` + (or use the [VS Code Extension Development Host](https://code.visualstudio.com/api/get-started/your-first-extension) with this folder as the extension root) +3. Command Palette → **Chorus: Share Session** / **Join Session** + +## Settings + +| Setting | Default | Meaning | +|---|---|---| +| `chorus.port` | `7742` | Relay listen port when sharing | +| `chorus.displayName` | OS user | Name shown to peers | +| `chorus.relayBin` | — | Path to `chorus-relay` | +| `chorus.publicHost` | LAN IP:port | Advertised join host | + +Env vars from the root README (`CHORUS_RELAY_HOST`, `CHORUS_HOST_TOKEN`, `CHORUS_EXTERNAL_RELAY`, …) still apply for Docker/external relays. + +## Layout + +``` +packages/vscode/ + src/extension.ts # activate + commands + src/controller.ts # JoinClient + RelayServer orchestration + src/sessionView.ts # sidebar webview + src/format.ts # transcript line formatting +``` diff --git a/packages/vscode/media/chorus.svg b/packages/vscode/media/chorus.svg new file mode 100644 index 0000000..dfa18ef --- /dev/null +++ b/packages/vscode/media/chorus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/vscode/package.json b/packages/vscode/package.json new file mode 100644 index 0000000..dd869da --- /dev/null +++ b/packages/vscode/package.json @@ -0,0 +1,135 @@ +{ + "name": "chorus", + "displayName": "Chorus", + "description": "Pair-program a live Chorus AI session from VS Code — share or join over chorus-relay.", + "version": "0.1.0", + "publisher": "chorus", + "private": true, + "license": "MIT", + "type": "module", + "engines": { + "vscode": "^1.90.0" + }, + "categories": ["Chat", "Other"], + "activationEvents": [ + "onCommand:chorus.share", + "onCommand:chorus.join", + "onCommand:chorus.leave", + "onCommand:chorus.stop", + "onCommand:chorus.chat", + "onCommand:chorus.status", + "onCommand:chorus.sendPrompt", + "onCommand:chorus.publishHostMessage", + "onView:chorus.session" + ], + "main": "./dist/extension.js", + "contributes": { + "commands": [ + { + "command": "chorus.share", + "title": "Chorus: Share Session", + "category": "Chorus" + }, + { + "command": "chorus.join", + "title": "Chorus: Join Session", + "category": "Chorus" + }, + { + "command": "chorus.leave", + "title": "Chorus: Leave Session", + "category": "Chorus" + }, + { + "command": "chorus.stop", + "title": "Chorus: Stop Sharing", + "category": "Chorus" + }, + { + "command": "chorus.chat", + "title": "Chorus: Send Chat Message", + "category": "Chorus" + }, + { + "command": "chorus.status", + "title": "Chorus: Show Status", + "category": "Chorus" + }, + { + "command": "chorus.sendPrompt", + "title": "Chorus: Send Prompt to Host", + "category": "Chorus" + }, + { + "command": "chorus.publishHostMessage", + "title": "Chorus: Publish Host Message", + "category": "Chorus" + }, + { + "command": "chorus.openSession", + "title": "Chorus: Open Session Panel", + "category": "Chorus" + } + ], + "configuration": { + "title": "Chorus", + "properties": { + "chorus.port": { + "type": "number", + "default": 7742, + "description": "Default chorus-relay listen port when sharing." + }, + "chorus.displayName": { + "type": "string", + "default": "", + "description": "Display name shown to collaborators (defaults to OS username)." + }, + "chorus.relayBin": { + "type": "string", + "default": "", + "description": "Path to chorus-relay binary (overrides CHORUS_RELAY_BIN / PATH)." + }, + "chorus.publicHost": { + "type": "string", + "default": "", + "description": "Host:port advertised in join commands (overrides CHORUS_PUBLIC_HOST)." + } + } + }, + "viewsContainers": { + "activitybar": [ + { + "id": "chorus", + "title": "Chorus", + "icon": "media/chorus.svg" + } + ] + }, + "views": { + "chorus": [ + { + "type": "webview", + "id": "chorus.session", + "name": "Session" + } + ] + } + }, + "scripts": { + "build": "tsc -p ./", + "typecheck": "tsc -p ./ --noEmit", + "watch": "tsc -p ./ -w", + "test": "bun test test/format.test.ts", + "clean": "rm -rf dist", + "package": "npm run build" + }, + "dependencies": { + "@chorus/client": "workspace:*", + "@chorus/shared": "workspace:*" + }, + "devDependencies": { + "@types/node": "^22.10.7", + "@types/vscode": "^1.90.0", + "typescript": "^5.7.3" + } +} diff --git a/packages/vscode/src/controller.ts b/packages/vscode/src/controller.ts new file mode 100644 index 0000000..713c628 --- /dev/null +++ b/packages/vscode/src/controller.ts @@ -0,0 +1,317 @@ +import { networkInterfaces } from "node:os"; +import * as vscode from "vscode"; +import { + JoinClient, + RelayServer, + relayOptionsFromEnv, + type JoinState, +} from "@chorus/client"; +import type { SessionEvent, UserRole } from "@chorus/shared"; +import { formatSessionLine, newEventId } from "./format.js"; + +export type ChorusMode = "idle" | "sharing" | "joined"; + +export type TranscriptLine = { + id: string; + text: string; + at: number; + kind: "session" | "chat" | "system"; +}; + +function getLanIp(): string { + const nets = networkInterfaces(); + for (const iface of Object.values(nets)) { + for (const net of iface ?? []) { + if (net.family === "IPv4" && !net.internal) return net.address; + } + } + return "localhost"; +} + +/** + * Host/joiner controller for the VS Code adapter. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + */ +export class ChorusController { + private mode: ChorusMode = "idle"; + private relay: RelayServer | null = null; + private joinClient: JoinClient | null = null; + private sessionId = `vscode-${Date.now().toString(36)}`; + private readonly transcript: TranscriptLine[] = []; + private readonly _onDidChange = new vscode.EventEmitter(); + readonly onDidChange = this._onDidChange.event; + + constructor( + private readonly output: vscode.OutputChannel, + private readonly statusBar: vscode.StatusBarItem + ) { + this.refreshStatus(); + } + + getMode(): ChorusMode { + return this.mode; + } + + getTranscript(): readonly TranscriptLine[] { + return this.transcript; + } + + getJoinState(): JoinState | null { + return this.joinClient?.getState() ?? null; + } + + getShareSummary(): { + sharing: boolean; + clients?: number; + port?: number; + host?: string; + external?: boolean; + } { + if (!this.relay || this.mode !== "sharing") return { sharing: false }; + return { + sharing: true, + clients: this.relay.clientCount, + port: this.relay.getPort(), + host: this.relay.getHost(), + external: this.relay.isExternal(), + }; + } + + private cfg() { + return vscode.workspace.getConfiguration("chorus"); + } + + private displayName(): string { + const configured = this.cfg().get("displayName")?.trim(); + if (configured) return configured; + return process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"; + } + + private defaultPort(): number { + return this.cfg().get("port") ?? 7742; + } + + private publicJoinHost(port: number, relayHost: string, external: boolean): string { + const fromSettings = this.cfg().get("publicHost")?.trim(); + if (fromSettings) return fromSettings; + if (process.env["CHORUS_PUBLIC_HOST"]) return process.env["CHORUS_PUBLIC_HOST"]; + if (external && relayHost && relayHost !== "127.0.0.1") { + return `${relayHost}:${port}`; + } + return `${getLanIp()}:${port}`; + } + + private append(line: TranscriptLine): void { + this.transcript.push(line); + if (this.transcript.length > 500) this.transcript.shift(); + this.output.appendLine(line.text); + this._onDidChange.fire(); + } + + private appendSystem(text: string): void { + this.append({ id: newEventId(), text, at: Date.now(), kind: "system" }); + } + + private appendSession(event: SessionEvent): void { + const text = formatSessionLine(event); + if (!text) return; + this.append({ id: event.id, text, at: event.timestamp, kind: "session" }); + } + + private refreshStatus(): void { + if (this.mode === "sharing" && this.relay) { + this.statusBar.text = `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; + this.statusBar.tooltip = "Chorus is sharing — click for status"; + } else if (this.mode === "joined" && this.joinClient) { + const st = this.joinClient.getState(); + this.statusBar.text = `$(organization) Chorus joined (${st.users.length})`; + this.statusBar.tooltip = "Chorus joined — click for status"; + } else { + this.statusBar.text = "$(circle-slash) Chorus"; + this.statusBar.tooltip = "Chorus idle — Share or Join a session"; + } + this.statusBar.command = "chorus.status"; + this._onDidChange.fire(); + } + + async share(role: UserRole = "edit"): Promise { + if (this.mode === "joined") { + await this.leave(); + } + + const relayBin = this.cfg().get("relayBin")?.trim(); + if (relayBin) process.env["CHORUS_RELAY_BIN"] = relayBin; + + const { port, opts } = relayOptionsFromEnv(this.defaultPort()); + if (!this.relay) { + this.relay = new RelayServer(port, opts); + this.relay.setInputHandler(async (content, userId, displayName) => { + const label = displayName ?? userId.slice(0, 8); + const labeled = `[${label}]: ${content}`; + const event: SessionEvent = { + id: newEventId(), + sessionId: this.sessionId, + type: "user", + payload: labeled, + timestamp: Date.now(), + }; + this.appendSession(event); + this.relay?.pushEvent(event); + void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); + }); + this.relay.setChatHandler((name, content) => { + const text = `💬 [${name ?? "guest"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + this.relay.setTypingHandler((name) => { + this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + } + + if (!this.relay.isRunning) { + await this.relay.start(); + } + + this.mode = "sharing"; + const token = await this.relay.issueToken(this.sessionId, role); + const joinHost = this.publicJoinHost( + this.relay.getPort(), + this.relay.getHost(), + this.relay.isExternal() + ); + const joinCommand = `/chorus-join token="${token.token}" host="${joinHost}"`; + this.appendSystem( + this.relay.isExternal() + ? `Attached to external relay ${this.relay.getHost()}:${this.relay.getPort()}` + : `chorus-relay started on port ${this.relay.getPort()}` + ); + this.appendSystem(`Share ready (${role}). Collaborator command:\n${joinCommand}`); + this.refreshStatus(); + + await vscode.env.clipboard.writeText(joinCommand); + void vscode.window.showInformationMessage( + `Chorus sharing — join command copied to clipboard.`, + "Copy again" + ).then((choice) => { + if (choice === "Copy again") void vscode.env.clipboard.writeText(joinCommand); + }); + + return joinCommand; + } + + async join(token: string, host: string, name?: string): Promise { + if (this.mode === "sharing") { + throw new Error("Stop sharing (Chorus: Stop Sharing) before joining another session."); + } + if (this.joinClient) { + this.joinClient.disconnect(); + this.joinClient = null; + } + + const displayName = name?.trim() || this.displayName(); + const jc = new JoinClient(`ws://${host}/ws`, token, displayName); + await jc.connect(); + + jc.setChatHandler((msgName, content) => { + const text = `💬 [${msgName ?? "host"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + jc.setTypingHandler((typingName) => { + this.statusBar.text = `$(edit) ${typingName ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + jc.setEventHandler((event) => this.appendSession(event)); + + for (const event of jc.getState().recentEvents) { + this.appendSession(event); + } + + this.joinClient = jc; + this.mode = "joined"; + this.appendSystem(`Joined ${host} as ${displayName}`); + this.refreshStatus(); + } + + async leave(): Promise { + this.joinClient?.disconnect(); + this.joinClient = null; + if (this.mode === "joined") this.mode = "idle"; + this.appendSystem("Left shared session"); + this.refreshStatus(); + } + + stop(): void { + this.mode = "idle"; + this.relay?.stop(); + this.relay = null; + this.appendSystem("Stopped sharing"); + this.refreshStatus(); + } + + sendChat(message: string): void { + if (this.mode === "sharing" && this.relay) { + this.relay.sendChat(this.displayName(), message); + this.append({ + id: newEventId(), + text: `💬 [${this.displayName()}]: ${message}`, + at: Date.now(), + kind: "chat", + }); + return; + } + if (this.mode === "joined" && this.joinClient?.getState().status === "connected") { + this.joinClient.sendTyping(); + this.joinClient.sendChat(message); + this.append({ + id: newEventId(), + text: `💬 [${this.displayName()}]: ${message}`, + at: Date.now(), + kind: "chat", + }); + return; + } + throw new Error("Not currently sharing or joined."); + } + + /** Joiner → host collab.input */ + sendPrompt(content: string): void { + if (this.mode !== "joined" || !this.joinClient) { + throw new Error("Join a session first to send prompts to the host."); + } + this.joinClient.sendInput(content); + this.appendSystem(`→ sent prompt to host (${content.slice(0, 80)}${content.length > 80 ? "…" : ""})`); + } + + /** Host publishes a user/assistant line onto the shared transcript. */ + publishHostMessage(content: string, type: "user" | "assistant" = "user"): void { + if (this.mode !== "sharing" || !this.relay) { + throw new Error("Share a session first to publish host messages."); + } + const event: SessionEvent = { + id: newEventId(), + sessionId: this.sessionId, + type, + payload: content, + timestamp: Date.now(), + }; + this.relay.pushEvent(event); + this.appendSession(event); + } + + statusText(): string { + const share = this.getShareSummary(); + const join = this.joinClient + ? { joined: true, ...this.joinClient.getState() } + : { joined: false }; + return JSON.stringify({ mode: this.mode, ...share, ...join }, null, 2); + } + + dispose(): void { + this.joinClient?.disconnect(); + this.relay?.stop(); + this._onDidChange.dispose(); + } +} diff --git a/packages/vscode/src/extension.ts b/packages/vscode/src/extension.ts new file mode 100644 index 0000000..6ee7d53 --- /dev/null +++ b/packages/vscode/src/extension.ts @@ -0,0 +1,156 @@ +import * as vscode from "vscode"; +import type { UserRole } from "@chorus/shared"; +import { ChorusController } from "./controller.js"; +import { SessionViewProvider } from "./sessionView.js"; + +export function activate(context: vscode.ExtensionContext): void { + const output = vscode.window.createOutputChannel("Chorus"); + const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 50); + statusBar.show(); + + const controller = new ChorusController(output, statusBar); + const viewProvider = new SessionViewProvider(controller); + + context.subscriptions.push( + output, + statusBar, + controller, + vscode.window.registerWebviewViewProvider(SessionViewProvider.viewType, viewProvider) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.share", async () => { + try { + const rolePick = await vscode.window.showQuickPick( + [ + { label: "edit", description: "Can send prompts (default)" }, + { label: "view", description: "Read-only" }, + { label: "admin", description: "Full control" }, + ], + { title: "Chorus share role for join token" } + ); + const role = (rolePick?.label ?? "edit") as UserRole; + const joinCommand = await controller.share(role); + output.show(true); + void vscode.commands.executeCommand("chorus.session.focus"); + return joinCommand; + } catch (err) { + void vscode.window.showErrorMessage(`Chorus share failed: ${String(err)}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.join", async () => { + try { + const token = await vscode.window.showInputBox({ + title: "Chorus join token", + prompt: "Paste the token from the host's share command", + ignoreFocusOut: true, + }); + if (!token) return; + + const host = await vscode.window.showInputBox({ + title: "Chorus relay host", + prompt: "host:port (e.g. 192.168.1.5:7742)", + ignoreFocusOut: true, + value: "127.0.0.1:7742", + }); + if (!host) return; + + const name = await vscode.window.showInputBox({ + title: "Display name", + prompt: "Optional — shown to collaborators", + ignoreFocusOut: true, + }); + + await controller.join(token.trim(), host.trim(), name?.trim() || undefined); + output.show(true); + void vscode.window.showInformationMessage("Joined Chorus session"); + } catch (err) { + void vscode.window.showErrorMessage(`Chorus join failed: ${String(err)}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.leave", async () => { + await controller.leave(); + void vscode.window.showInformationMessage("Left Chorus session"); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.stop", () => { + controller.stop(); + void vscode.window.showInformationMessage("Stopped Chorus sharing"); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.chat", async () => { + try { + const message = await vscode.window.showInputBox({ + title: "Chorus chat", + prompt: "Side-channel message (does not enter the LLM transcript)", + ignoreFocusOut: true, + }); + if (!message) return; + controller.sendChat(message); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.sendPrompt", async () => { + try { + const content = await vscode.window.showInputBox({ + title: "Send prompt to Chorus host", + prompt: "Forwarded as collab.input into the shared session", + ignoreFocusOut: true, + }); + if (!content) return; + controller.sendPrompt(content); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.publishHostMessage", async () => { + try { + const content = await vscode.window.showInputBox({ + title: "Publish host message", + prompt: "Pushed to all joiners as a session user event", + ignoreFocusOut: true, + }); + if (!content) return; + controller.publishHostMessage(content, "user"); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.status", async () => { + const text = controller.statusText(); + output.appendLine(text); + output.show(true); + await vscode.window.showInformationMessage(`Chorus mode: ${controller.getMode()}`); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.openSession", async () => { + await vscode.commands.executeCommand("chorus.session.focus"); + }) + ); +} + +export function deactivate(): void { + // disposables handled via subscriptions +} diff --git a/packages/vscode/src/format.ts b/packages/vscode/src/format.ts new file mode 100644 index 0000000..2082ae5 --- /dev/null +++ b/packages/vscode/src/format.ts @@ -0,0 +1,19 @@ +import type { SessionEvent } from "@chorus/shared"; + +const LABELED_LINE = /^\[[^\]]+\]:\s/; + +/** Format a shared session event for the Chorus panel / notifications. */ +export function formatSessionLine(event: SessionEvent): string | null { + const payload = + typeof event.payload === "string" ? event.payload : JSON.stringify(event.payload); + if (event.type === "user") { + if (LABELED_LINE.test(payload)) return payload; + return `[Host]: ${payload}`; + } + if (event.type === "assistant") return `[AI]: ${payload}`; + return `[${event.type}]: ${payload}`; +} + +export function newEventId(): string { + return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; +} diff --git a/packages/vscode/src/sessionView.ts b/packages/vscode/src/sessionView.ts new file mode 100644 index 0000000..42d5455 --- /dev/null +++ b/packages/vscode/src/sessionView.ts @@ -0,0 +1,134 @@ +import * as vscode from "vscode"; +import type { ChorusController, TranscriptLine } from "./controller.js"; + +function escapeHtml(s: string): string { + return s + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function lineClass(line: TranscriptLine): string { + if (line.kind === "chat") return "chat"; + if (line.kind === "system") return "system"; + if (line.text.startsWith("[AI]:")) return "ai"; + if (line.text.startsWith("[Host]:")) return "host"; + return "user"; +} + +export class SessionViewProvider implements vscode.WebviewViewProvider { + public static readonly viewType = "chorus.session"; + private view?: vscode.WebviewView; + + constructor(private readonly controller: ChorusController) { + controller.onDidChange(() => this.render()); + } + + resolveWebviewView( + webviewView: vscode.WebviewView, + _context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken + ): void { + this.view = webviewView; + webviewView.webview.options = { enableScripts: true }; + webviewView.webview.onDidReceiveMessage((msg) => { + if (msg?.type === "chat" && typeof msg.text === "string") { + try { + this.controller.sendChat(msg.text); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + if (msg?.type === "prompt" && typeof msg.text === "string") { + try { + this.controller.sendPrompt(msg.text); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + if (msg?.type === "publish" && typeof msg.text === "string") { + try { + this.controller.publishHostMessage(msg.text, "user"); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + }); + this.render(); + } + + private render(): void { + if (!this.view) return; + const mode = this.controller.getMode(); + const lines = this.controller.getTranscript(); + const body = lines + .map( + (l) => + `
${escapeHtml(l.text)}
` + ) + .join(""); + + this.view.webview.html = ` + + + + + + +
Mode: ${escapeHtml(mode)}
+
${body || "
Idle — Share or Join a Chorus session.
"}
+
+
+ + +
+
+ +
+
+ + +`; + } +} diff --git a/packages/vscode/test/format.test.ts b/packages/vscode/test/format.test.ts new file mode 100644 index 0000000..2dc4efc --- /dev/null +++ b/packages/vscode/test/format.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from "bun:test"; +import { formatSessionLine } from "../src/format.ts"; + +describe("formatSessionLine", () => { + it("labels plain user events as Host", () => { + expect( + formatSessionLine({ + id: "1", + sessionId: "s", + type: "user", + payload: "hello", + timestamp: 1, + }) + ).toBe("[Host]: hello"); + }); + + it("keeps already-labeled collaborator lines", () => { + expect( + formatSessionLine({ + id: "1", + sessionId: "s", + type: "user", + payload: "[Ada]: refactor", + timestamp: 1, + }) + ).toBe("[Ada]: refactor"); + }); + + it("labels assistant events as AI", () => { + expect( + formatSessionLine({ + id: "1", + sessionId: "s", + type: "assistant", + payload: "sure", + timestamp: 1, + }) + ).toBe("[AI]: sure"); + }); +}); diff --git a/packages/vscode/tsconfig.json b/packages/vscode/tsconfig.json new file mode 100644 index 0000000..3d6bd83 --- /dev/null +++ b/packages/vscode/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "sourceMap": true, + "declaration": true, + "types": ["node", "vscode"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} From de649b5d7bd2ae37936734e765e4fb4b39177bae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 16 Aug 2026 21:18:29 +0000 Subject: [PATCH 02/10] chore: update dist [skip ci] --- packages/vscode/dist/controller.d.ts | 55 +++++ packages/vscode/dist/controller.js | 267 ++++++++++++++++++++++++ packages/vscode/dist/controller.js.map | 1 + packages/vscode/dist/extension.d.ts | 3 + packages/vscode/dist/extension.js | 124 +++++++++++ packages/vscode/dist/extension.js.map | 1 + packages/vscode/dist/format.d.ts | 4 + packages/vscode/dist/format.js | 17 ++ packages/vscode/dist/format.js.map | 1 + packages/vscode/dist/sessionView.d.ts | 10 + packages/vscode/dist/sessionView.js | 130 ++++++++++++ packages/vscode/dist/sessionView.js.map | 1 + 12 files changed, 614 insertions(+) create mode 100644 packages/vscode/dist/controller.d.ts create mode 100644 packages/vscode/dist/controller.js create mode 100644 packages/vscode/dist/controller.js.map create mode 100644 packages/vscode/dist/extension.d.ts create mode 100644 packages/vscode/dist/extension.js create mode 100644 packages/vscode/dist/extension.js.map create mode 100644 packages/vscode/dist/format.d.ts create mode 100644 packages/vscode/dist/format.js create mode 100644 packages/vscode/dist/format.js.map create mode 100644 packages/vscode/dist/sessionView.d.ts create mode 100644 packages/vscode/dist/sessionView.js create mode 100644 packages/vscode/dist/sessionView.js.map diff --git a/packages/vscode/dist/controller.d.ts b/packages/vscode/dist/controller.d.ts new file mode 100644 index 0000000..08c69f2 --- /dev/null +++ b/packages/vscode/dist/controller.d.ts @@ -0,0 +1,55 @@ +import * as vscode from "vscode"; +import { type JoinState } from "@chorus/client"; +import type { UserRole } from "@chorus/shared"; +export type ChorusMode = "idle" | "sharing" | "joined"; +export type TranscriptLine = { + id: string; + text: string; + at: number; + kind: "session" | "chat" | "system"; +}; +/** + * Host/joiner controller for the VS Code adapter. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + */ +export declare class ChorusController { + private readonly output; + private readonly statusBar; + private mode; + private relay; + private joinClient; + private sessionId; + private readonly transcript; + private readonly _onDidChange; + readonly onDidChange: vscode.Event; + constructor(output: vscode.OutputChannel, statusBar: vscode.StatusBarItem); + getMode(): ChorusMode; + getTranscript(): readonly TranscriptLine[]; + getJoinState(): JoinState | null; + getShareSummary(): { + sharing: boolean; + clients?: number; + port?: number; + host?: string; + external?: boolean; + }; + private cfg; + private displayName; + private defaultPort; + private publicJoinHost; + private append; + private appendSystem; + private appendSession; + private refreshStatus; + share(role?: UserRole): Promise; + join(token: string, host: string, name?: string): Promise; + leave(): Promise; + stop(): void; + sendChat(message: string): void; + /** Joiner → host collab.input */ + sendPrompt(content: string): void; + /** Host publishes a user/assistant line onto the shared transcript. */ + publishHostMessage(content: string, type?: "user" | "assistant"): void; + statusText(): string; + dispose(): void; +} diff --git a/packages/vscode/dist/controller.js b/packages/vscode/dist/controller.js new file mode 100644 index 0000000..2d0eac8 --- /dev/null +++ b/packages/vscode/dist/controller.js @@ -0,0 +1,267 @@ +import { networkInterfaces } from "node:os"; +import * as vscode from "vscode"; +import { JoinClient, RelayServer, relayOptionsFromEnv, } from "@chorus/client"; +import { formatSessionLine, newEventId } from "./format.js"; +function getLanIp() { + const nets = networkInterfaces(); + for (const iface of Object.values(nets)) { + for (const net of iface ?? []) { + if (net.family === "IPv4" && !net.internal) + return net.address; + } + } + return "localhost"; +} +/** + * Host/joiner controller for the VS Code adapter. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + */ +export class ChorusController { + output; + statusBar; + mode = "idle"; + relay = null; + joinClient = null; + sessionId = `vscode-${Date.now().toString(36)}`; + transcript = []; + _onDidChange = new vscode.EventEmitter(); + onDidChange = this._onDidChange.event; + constructor(output, statusBar) { + this.output = output; + this.statusBar = statusBar; + this.refreshStatus(); + } + getMode() { + return this.mode; + } + getTranscript() { + return this.transcript; + } + getJoinState() { + return this.joinClient?.getState() ?? null; + } + getShareSummary() { + if (!this.relay || this.mode !== "sharing") + return { sharing: false }; + return { + sharing: true, + clients: this.relay.clientCount, + port: this.relay.getPort(), + host: this.relay.getHost(), + external: this.relay.isExternal(), + }; + } + cfg() { + return vscode.workspace.getConfiguration("chorus"); + } + displayName() { + const configured = this.cfg().get("displayName")?.trim(); + if (configured) + return configured; + return process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"; + } + defaultPort() { + return this.cfg().get("port") ?? 7742; + } + publicJoinHost(port, relayHost, external) { + const fromSettings = this.cfg().get("publicHost")?.trim(); + if (fromSettings) + return fromSettings; + if (process.env["CHORUS_PUBLIC_HOST"]) + return process.env["CHORUS_PUBLIC_HOST"]; + if (external && relayHost && relayHost !== "127.0.0.1") { + return `${relayHost}:${port}`; + } + return `${getLanIp()}:${port}`; + } + append(line) { + this.transcript.push(line); + if (this.transcript.length > 500) + this.transcript.shift(); + this.output.appendLine(line.text); + this._onDidChange.fire(); + } + appendSystem(text) { + this.append({ id: newEventId(), text, at: Date.now(), kind: "system" }); + } + appendSession(event) { + const text = formatSessionLine(event); + if (!text) + return; + this.append({ id: event.id, text, at: event.timestamp, kind: "session" }); + } + refreshStatus() { + if (this.mode === "sharing" && this.relay) { + this.statusBar.text = `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; + this.statusBar.tooltip = "Chorus is sharing — click for status"; + } + else if (this.mode === "joined" && this.joinClient) { + const st = this.joinClient.getState(); + this.statusBar.text = `$(organization) Chorus joined (${st.users.length})`; + this.statusBar.tooltip = "Chorus joined — click for status"; + } + else { + this.statusBar.text = "$(circle-slash) Chorus"; + this.statusBar.tooltip = "Chorus idle — Share or Join a session"; + } + this.statusBar.command = "chorus.status"; + this._onDidChange.fire(); + } + async share(role = "edit") { + if (this.mode === "joined") { + await this.leave(); + } + const relayBin = this.cfg().get("relayBin")?.trim(); + if (relayBin) + process.env["CHORUS_RELAY_BIN"] = relayBin; + const { port, opts } = relayOptionsFromEnv(this.defaultPort()); + if (!this.relay) { + this.relay = new RelayServer(port, opts); + this.relay.setInputHandler(async (content, userId, displayName) => { + const label = displayName ?? userId.slice(0, 8); + const labeled = `[${label}]: ${content}`; + const event = { + id: newEventId(), + sessionId: this.sessionId, + type: "user", + payload: labeled, + timestamp: Date.now(), + }; + this.appendSession(event); + this.relay?.pushEvent(event); + void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); + }); + this.relay.setChatHandler((name, content) => { + const text = `💬 [${name ?? "guest"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + this.relay.setTypingHandler((name) => { + this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + } + if (!this.relay.isRunning) { + await this.relay.start(); + } + this.mode = "sharing"; + const token = await this.relay.issueToken(this.sessionId, role); + const joinHost = this.publicJoinHost(this.relay.getPort(), this.relay.getHost(), this.relay.isExternal()); + const joinCommand = `/chorus-join token="${token.token}" host="${joinHost}"`; + this.appendSystem(this.relay.isExternal() + ? `Attached to external relay ${this.relay.getHost()}:${this.relay.getPort()}` + : `chorus-relay started on port ${this.relay.getPort()}`); + this.appendSystem(`Share ready (${role}). Collaborator command:\n${joinCommand}`); + this.refreshStatus(); + await vscode.env.clipboard.writeText(joinCommand); + void vscode.window.showInformationMessage(`Chorus sharing — join command copied to clipboard.`, "Copy again").then((choice) => { + if (choice === "Copy again") + void vscode.env.clipboard.writeText(joinCommand); + }); + return joinCommand; + } + async join(token, host, name) { + if (this.mode === "sharing") { + throw new Error("Stop sharing (Chorus: Stop Sharing) before joining another session."); + } + if (this.joinClient) { + this.joinClient.disconnect(); + this.joinClient = null; + } + const displayName = name?.trim() || this.displayName(); + const jc = new JoinClient(`ws://${host}/ws`, token, displayName); + await jc.connect(); + jc.setChatHandler((msgName, content) => { + const text = `💬 [${msgName ?? "host"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + jc.setTypingHandler((typingName) => { + this.statusBar.text = `$(edit) ${typingName ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + jc.setEventHandler((event) => this.appendSession(event)); + for (const event of jc.getState().recentEvents) { + this.appendSession(event); + } + this.joinClient = jc; + this.mode = "joined"; + this.appendSystem(`Joined ${host} as ${displayName}`); + this.refreshStatus(); + } + async leave() { + this.joinClient?.disconnect(); + this.joinClient = null; + if (this.mode === "joined") + this.mode = "idle"; + this.appendSystem("Left shared session"); + this.refreshStatus(); + } + stop() { + this.mode = "idle"; + this.relay?.stop(); + this.relay = null; + this.appendSystem("Stopped sharing"); + this.refreshStatus(); + } + sendChat(message) { + if (this.mode === "sharing" && this.relay) { + this.relay.sendChat(this.displayName(), message); + this.append({ + id: newEventId(), + text: `💬 [${this.displayName()}]: ${message}`, + at: Date.now(), + kind: "chat", + }); + return; + } + if (this.mode === "joined" && this.joinClient?.getState().status === "connected") { + this.joinClient.sendTyping(); + this.joinClient.sendChat(message); + this.append({ + id: newEventId(), + text: `💬 [${this.displayName()}]: ${message}`, + at: Date.now(), + kind: "chat", + }); + return; + } + throw new Error("Not currently sharing or joined."); + } + /** Joiner → host collab.input */ + sendPrompt(content) { + if (this.mode !== "joined" || !this.joinClient) { + throw new Error("Join a session first to send prompts to the host."); + } + this.joinClient.sendInput(content); + this.appendSystem(`→ sent prompt to host (${content.slice(0, 80)}${content.length > 80 ? "…" : ""})`); + } + /** Host publishes a user/assistant line onto the shared transcript. */ + publishHostMessage(content, type = "user") { + if (this.mode !== "sharing" || !this.relay) { + throw new Error("Share a session first to publish host messages."); + } + const event = { + id: newEventId(), + sessionId: this.sessionId, + type, + payload: content, + timestamp: Date.now(), + }; + this.relay.pushEvent(event); + this.appendSession(event); + } + statusText() { + const share = this.getShareSummary(); + const join = this.joinClient + ? { joined: true, ...this.joinClient.getState() } + : { joined: false }; + return JSON.stringify({ mode: this.mode, ...share, ...join }, null, 2); + } + dispose() { + this.joinClient?.disconnect(); + this.relay?.stop(); + this._onDidChange.dispose(); + } +} +//# sourceMappingURL=controller.js.map \ No newline at end of file diff --git a/packages/vscode/dist/controller.js.map b/packages/vscode/dist/controller.js.map new file mode 100644 index 0000000..b4cf42f --- /dev/null +++ b/packages/vscode/dist/controller.js.map @@ -0,0 +1 @@ +{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/vscode/dist/extension.d.ts b/packages/vscode/dist/extension.d.ts new file mode 100644 index 0000000..c838f76 --- /dev/null +++ b/packages/vscode/dist/extension.d.ts @@ -0,0 +1,3 @@ +import * as vscode from "vscode"; +export declare function activate(context: vscode.ExtensionContext): void; +export declare function deactivate(): void; diff --git a/packages/vscode/dist/extension.js b/packages/vscode/dist/extension.js new file mode 100644 index 0000000..30cd519 --- /dev/null +++ b/packages/vscode/dist/extension.js @@ -0,0 +1,124 @@ +import * as vscode from "vscode"; +import { ChorusController } from "./controller.js"; +import { SessionViewProvider } from "./sessionView.js"; +export function activate(context) { + const output = vscode.window.createOutputChannel("Chorus"); + const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 50); + statusBar.show(); + const controller = new ChorusController(output, statusBar); + const viewProvider = new SessionViewProvider(controller); + context.subscriptions.push(output, statusBar, controller, vscode.window.registerWebviewViewProvider(SessionViewProvider.viewType, viewProvider)); + context.subscriptions.push(vscode.commands.registerCommand("chorus.share", async () => { + try { + const rolePick = await vscode.window.showQuickPick([ + { label: "edit", description: "Can send prompts (default)" }, + { label: "view", description: "Read-only" }, + { label: "admin", description: "Full control" }, + ], { title: "Chorus share role for join token" }); + const role = (rolePick?.label ?? "edit"); + const joinCommand = await controller.share(role); + output.show(true); + void vscode.commands.executeCommand("chorus.session.focus"); + return joinCommand; + } + catch (err) { + void vscode.window.showErrorMessage(`Chorus share failed: ${String(err)}`); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.join", async () => { + try { + const token = await vscode.window.showInputBox({ + title: "Chorus join token", + prompt: "Paste the token from the host's share command", + ignoreFocusOut: true, + }); + if (!token) + return; + const host = await vscode.window.showInputBox({ + title: "Chorus relay host", + prompt: "host:port (e.g. 192.168.1.5:7742)", + ignoreFocusOut: true, + value: "127.0.0.1:7742", + }); + if (!host) + return; + const name = await vscode.window.showInputBox({ + title: "Display name", + prompt: "Optional — shown to collaborators", + ignoreFocusOut: true, + }); + await controller.join(token.trim(), host.trim(), name?.trim() || undefined); + output.show(true); + void vscode.window.showInformationMessage("Joined Chorus session"); + } + catch (err) { + void vscode.window.showErrorMessage(`Chorus join failed: ${String(err)}`); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.leave", async () => { + await controller.leave(); + void vscode.window.showInformationMessage("Left Chorus session"); + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.stop", () => { + controller.stop(); + void vscode.window.showInformationMessage("Stopped Chorus sharing"); + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.chat", async () => { + try { + const message = await vscode.window.showInputBox({ + title: "Chorus chat", + prompt: "Side-channel message (does not enter the LLM transcript)", + ignoreFocusOut: true, + }); + if (!message) + return; + controller.sendChat(message); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.sendPrompt", async () => { + try { + const content = await vscode.window.showInputBox({ + title: "Send prompt to Chorus host", + prompt: "Forwarded as collab.input into the shared session", + ignoreFocusOut: true, + }); + if (!content) + return; + controller.sendPrompt(content); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.publishHostMessage", async () => { + try { + const content = await vscode.window.showInputBox({ + title: "Publish host message", + prompt: "Pushed to all joiners as a session user event", + ignoreFocusOut: true, + }); + if (!content) + return; + controller.publishHostMessage(content, "user"); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.status", async () => { + const text = controller.statusText(); + output.appendLine(text); + output.show(true); + await vscode.window.showInformationMessage(`Chorus mode: ${controller.getMode()}`); + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.openSession", async () => { + await vscode.commands.executeCommand("chorus.session.focus"); + })); +} +export function deactivate() { + // disposables handled via subscriptions +} +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/packages/vscode/dist/extension.js.map b/packages/vscode/dist/extension.js.map new file mode 100644 index 0000000..a27b22e --- /dev/null +++ b/packages/vscode/dist/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/vscode/dist/format.d.ts b/packages/vscode/dist/format.d.ts new file mode 100644 index 0000000..60b1469 --- /dev/null +++ b/packages/vscode/dist/format.d.ts @@ -0,0 +1,4 @@ +import type { SessionEvent } from "@chorus/shared"; +/** Format a shared session event for the Chorus panel / notifications. */ +export declare function formatSessionLine(event: SessionEvent): string | null; +export declare function newEventId(): string; diff --git a/packages/vscode/dist/format.js b/packages/vscode/dist/format.js new file mode 100644 index 0000000..cb3b2d0 --- /dev/null +++ b/packages/vscode/dist/format.js @@ -0,0 +1,17 @@ +const LABELED_LINE = /^\[[^\]]+\]:\s/; +/** Format a shared session event for the Chorus panel / notifications. */ +export function formatSessionLine(event) { + const payload = typeof event.payload === "string" ? event.payload : JSON.stringify(event.payload); + if (event.type === "user") { + if (LABELED_LINE.test(payload)) + return payload; + return `[Host]: ${payload}`; + } + if (event.type === "assistant") + return `[AI]: ${payload}`; + return `[${event.type}]: ${payload}`; +} +export function newEventId() { + return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; +} +//# sourceMappingURL=format.js.map \ No newline at end of file diff --git a/packages/vscode/dist/format.js.map b/packages/vscode/dist/format.js.map new file mode 100644 index 0000000..2f15aad --- /dev/null +++ b/packages/vscode/dist/format.js.map @@ -0,0 +1 @@ +{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,MAAM,OAAO,GACX,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpF,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QAC/C,OAAO,WAAW,OAAO,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,SAAS,OAAO,EAAE,CAAC;IAC1D,OAAO,IAAI,KAAK,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACpE,CAAC"} \ No newline at end of file diff --git a/packages/vscode/dist/sessionView.d.ts b/packages/vscode/dist/sessionView.d.ts new file mode 100644 index 0000000..d3fed7b --- /dev/null +++ b/packages/vscode/dist/sessionView.d.ts @@ -0,0 +1,10 @@ +import * as vscode from "vscode"; +import type { ChorusController } from "./controller.js"; +export declare class SessionViewProvider implements vscode.WebviewViewProvider { + private readonly controller; + static readonly viewType = "chorus.session"; + private view?; + constructor(controller: ChorusController); + resolveWebviewView(webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken): void; + private render; +} diff --git a/packages/vscode/dist/sessionView.js b/packages/vscode/dist/sessionView.js new file mode 100644 index 0000000..195c17d --- /dev/null +++ b/packages/vscode/dist/sessionView.js @@ -0,0 +1,130 @@ +import * as vscode from "vscode"; +function escapeHtml(s) { + return s + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} +function lineClass(line) { + if (line.kind === "chat") + return "chat"; + if (line.kind === "system") + return "system"; + if (line.text.startsWith("[AI]:")) + return "ai"; + if (line.text.startsWith("[Host]:")) + return "host"; + return "user"; +} +export class SessionViewProvider { + controller; + static viewType = "chorus.session"; + view; + constructor(controller) { + this.controller = controller; + controller.onDidChange(() => this.render()); + } + resolveWebviewView(webviewView, _context, _token) { + this.view = webviewView; + webviewView.webview.options = { enableScripts: true }; + webviewView.webview.onDidReceiveMessage((msg) => { + if (msg?.type === "chat" && typeof msg.text === "string") { + try { + this.controller.sendChat(msg.text); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + if (msg?.type === "prompt" && typeof msg.text === "string") { + try { + this.controller.sendPrompt(msg.text); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + if (msg?.type === "publish" && typeof msg.text === "string") { + try { + this.controller.publishHostMessage(msg.text, "user"); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + } + }); + this.render(); + } + render() { + if (!this.view) + return; + const mode = this.controller.getMode(); + const lines = this.controller.getTranscript(); + const body = lines + .map((l) => `
${escapeHtml(l.text)}
`) + .join(""); + this.view.webview.html = ` + + + + + + +
Mode: ${escapeHtml(mode)}
+
${body || "
Idle — Share or Join a Chorus session.
"}
+
+
+ + +
+
+ +
+
+ + +`; + } +} +//# sourceMappingURL=sessionView.js.map \ No newline at end of file diff --git a/packages/vscode/dist/sessionView.js.map b/packages/vscode/dist/sessionView.js.map new file mode 100644 index 0000000..4b6b3e7 --- /dev/null +++ b/packages/vscode/dist/sessionView.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sessionView.js","sourceRoot":"","sources":["../src/sessionView.ts"],"names":[],"mappings":"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"} \ No newline at end of file From df5b18684730e3efec169dacee79dfd2c57759d3 Mon Sep 17 00:00:00 2001 From: Steven Roomberg Date: Sun, 16 Aug 2026 21:18:35 +0000 Subject: [PATCH 03/10] feat(zed): add joiner extension and chorus-zed-helper Ship a practical Zed v1 adapter: WASM extension launches a native helper as an MCP context server. Helper speaks Chorus /ws (join, chat, collab.input, status) with CLI + daemon control and integration tests. --- .gitignore | 1 + Cargo.lock | 16 + Cargo.toml | 4 +- crates/chorus-zed-helper/Cargo.toml | 29 + crates/chorus-zed-helper/src/client.rs | 353 ++++++++ crates/chorus-zed-helper/src/control.rs | 101 +++ crates/chorus-zed-helper/src/lib.rs | 10 + crates/chorus-zed-helper/src/main.rs | 341 +++++++ crates/chorus-zed-helper/src/mcp.rs | 300 +++++++ crates/chorus-zed-helper/tests/join_client.rs | 127 +++ docs/DECISIONS.md | 2 +- docs/STATUS.md | 2 + packages/zed/Cargo.lock | 829 ++++++++++++++++++ packages/zed/Cargo.toml | 17 + packages/zed/README.md | 102 +++ packages/zed/extension.toml | 11 + packages/zed/src/lib.rs | 27 + 17 files changed, 2270 insertions(+), 2 deletions(-) create mode 100644 crates/chorus-zed-helper/Cargo.toml create mode 100644 crates/chorus-zed-helper/src/client.rs create mode 100644 crates/chorus-zed-helper/src/control.rs create mode 100644 crates/chorus-zed-helper/src/lib.rs create mode 100644 crates/chorus-zed-helper/src/main.rs create mode 100644 crates/chorus-zed-helper/src/mcp.rs create mode 100644 crates/chorus-zed-helper/tests/join_client.rs create mode 100644 packages/zed/Cargo.lock create mode 100644 packages/zed/Cargo.toml create mode 100644 packages/zed/README.md create mode 100644 packages/zed/extension.toml create mode 100644 packages/zed/src/lib.rs diff --git a/.gitignore b/.gitignore index 96466e4..143d31e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ coverage/ playwright-report/ test-results/ target/ +packages/zed/target/ .multi-agent/ *.env *.env.local diff --git a/Cargo.lock b/Cargo.lock index 6926b20..2d2c383 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,22 @@ dependencies = [ "url", ] +[[package]] +name = "chorus-zed-helper" +version = "0.1.0" +dependencies = [ + "chorus-relay", + "clap", + "futures-util", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite 0.26.2", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "clap" version = "4.6.5" diff --git a/Cargo.toml b/Cargo.toml index 87ba777..3a5f07e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] resolver = "2" -members = ["crates/chorus-relay"] +members = ["crates/chorus-relay", "crates/chorus-zed-helper"] +exclude = ["packages/zed"] +# packages/zed is a standalone Zed extension (wasm32-wasip2) built by Zed / cargo --target. [workspace.package] edition = "2021" diff --git a/crates/chorus-zed-helper/Cargo.toml b/crates/chorus-zed-helper/Cargo.toml new file mode 100644 index 0000000..67bbbeb --- /dev/null +++ b/crates/chorus-zed-helper/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "chorus-zed-helper" +version = "0.1.0" +edition.workspace = true +license.workspace = true +authors.workspace = true +description = "Native Chorus join client for the Zed extension (CLI + MCP)" +publish = false + +[[bin]] +name = "chorus-zed-helper" +path = "src/main.rs" + +[dependencies] +chorus-relay = { path = "../chorus-relay" } +clap = { version = "4", features = ["derive", "env"] } +futures-util = "0.3" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["full"] } +tokio-tungstenite = "0.26" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +url = "2" + +[dev-dependencies] +chorus-relay = { path = "../chorus-relay" } +tokio-tungstenite = "0.26" +futures-util = "0.3" diff --git a/crates/chorus-zed-helper/src/client.rs b/crates/chorus-zed-helper/src/client.rs new file mode 100644 index 0000000..da941c9 --- /dev/null +++ b/crates/chorus-zed-helper/src/client.rs @@ -0,0 +1,353 @@ +use std::sync::Arc; +use std::time::Duration; + +use chorus_relay::protocol::{ + ChatMessage, ClientMessage, ConnectedUser, ServerMessage, SessionEvent, +}; +use futures_util::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use tokio::sync::{mpsc, RwLock}; +use tokio::task::JoinHandle; +use tokio_tungstenite::{connect_async, tungstenite::Message}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum JoinStatus { + Disconnected, + Connecting, + Connected, + Error, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionSnapshot { + pub status: JoinStatus, + pub host: String, + pub display_name: String, + pub session_id: Option, + pub users: Vec, + pub recent_events: Vec, + pub recent_chat: Vec, + pub last_error: Option, +} + +impl SessionSnapshot { + fn new(host: &str, display_name: &str) -> Self { + Self { + status: JoinStatus::Disconnected, + host: host.to_string(), + display_name: display_name.to_string(), + session_id: None, + users: Vec::new(), + recent_events: Vec::new(), + recent_chat: Vec::new(), + last_error: None, + } + } +} + +/// Live joiner WebSocket client for the Chorus `/ws` surface. +pub struct JoinClient { + inner: Arc>, + outbound: mpsc::UnboundedSender, + reader: Option>, +} + +struct Inner { + snapshot: SessionSnapshot, +} + +impl JoinClient { + /// Connect to `ws://host/ws` (or `wss://`), authenticate, and wait for history. + pub async fn connect( + host: &str, + token: &str, + display_name: &str, + ) -> Result { + let ws_url = normalize_ws_url(host)?; + let (ws, _) = connect_async(&ws_url) + .await + .map_err(|e| format!("connect failed: {e}"))?; + + let (mut write, mut read) = ws.split(); + let auth = ClientMessage::Auth { + token: token.to_string(), + display_name: Some(display_name.to_string()), + }; + write + .send(Message::Text( + serde_json::to_string(&auth) + .map_err(|e| e.to_string())? + .into(), + )) + .await + .map_err(|e| format!("auth send failed: {e}"))?; + + let mut snapshot = SessionSnapshot::new(host, display_name); + snapshot.status = JoinStatus::Connecting; + + // Wait until session.history (connected) or error / timeout. + let deadline = tokio::time::Instant::now() + Duration::from_secs(10); + loop { + if tokio::time::Instant::now() > deadline { + return Err("timed out waiting for session.history".into()); + } + let next = tokio::time::timeout(Duration::from_secs(5), read.next()) + .await + .map_err(|_| "timed out waiting for relay message".to_string())?; + let msg = match next { + Some(Ok(Message::Text(t))) => t, + Some(Ok(Message::Close(frame))) => { + return Err(format!("connection closed before auth: {frame:?}")); + } + Some(Ok(_)) => continue, + Some(Err(e)) => return Err(format!("ws error: {e}")), + None => return Err("connection closed before auth".into()), + }; + let server: ServerMessage = + serde_json::from_str(&msg).map_err(|e| format!("bad server json: {e}"))?; + apply_server_message(&mut snapshot, &server); + match server { + ServerMessage::SessionHistory { .. } => break, + ServerMessage::Error { message, .. } => { + return Err(message); + } + _ => continue, + } + } + + let (outbound_tx, mut outbound_rx) = mpsc::unbounded_channel::(); + let inner = Arc::new(RwLock::new(Inner { snapshot })); + + let writer_inner = Arc::clone(&inner); + let reader = tokio::spawn(async move { + loop { + tokio::select! { + outbound = outbound_rx.recv() => { + let Some(msg) = outbound else { break; }; + let Ok(text) = serde_json::to_string(&msg) else { continue; }; + if write.send(Message::Text(text.into())).await.is_err() { + let mut guard = writer_inner.write().await; + guard.snapshot.status = JoinStatus::Disconnected; + break; + } + } + incoming = read.next() => { + match incoming { + Some(Ok(Message::Text(t))) => { + if let Ok(server) = serde_json::from_str::(&t) { + let mut guard = writer_inner.write().await; + apply_server_message(&mut guard.snapshot, &server); + if matches!(server, ServerMessage::SessionClosed) { + break; + } + } + } + Some(Ok(Message::Close(_))) | None => { + let mut guard = writer_inner.write().await; + guard.snapshot.status = JoinStatus::Disconnected; + break; + } + Some(Ok(_)) => {} + Some(Err(e)) => { + let mut guard = writer_inner.write().await; + guard.snapshot.status = JoinStatus::Error; + guard.snapshot.last_error = Some(e.to_string()); + break; + } + } + } + } + } + }); + + Ok(Self { + inner, + outbound: outbound_tx, + reader: Some(reader), + }) + } + + pub async fn snapshot(&self) -> SessionSnapshot { + self.inner.read().await.snapshot.clone() + } + + pub fn send_chat(&self, content: &str) -> Result<(), String> { + self.outbound + .send(ClientMessage::ChatSend { + content: content.to_string(), + }) + .map_err(|_| "not connected".to_string()) + } + + pub fn send_prompt(&self, content: &str) -> Result<(), String> { + self.outbound + .send(ClientMessage::CollabInput { + content: content.to_string(), + }) + .map_err(|_| "not connected".to_string()) + } + + pub fn send_typing(&self) -> Result<(), String> { + self.outbound + .send(ClientMessage::Typing) + .map_err(|_| "not connected".to_string()) + } + + pub async fn disconnect(mut self) { + drop(self.outbound); + if let Some(handle) = self.reader.take() { + let _ = tokio::time::timeout(Duration::from_secs(1), handle).await; + } + } +} + +fn normalize_ws_url(host: &str) -> Result { + let trimmed = host.trim().trim_end_matches('/'); + if trimmed.is_empty() { + return Err("host is empty".into()); + } + if trimmed.starts_with("ws://") || trimmed.starts_with("wss://") { + if trimmed.ends_with("/ws") { + return Ok(trimmed.to_string()); + } + return Ok(format!("{trimmed}/ws")); + } + // Bare host:port or host + Ok(format!("ws://{trimmed}/ws")) +} + +fn apply_server_message(snapshot: &mut SessionSnapshot, msg: &ServerMessage) { + match msg { + ServerMessage::SessionHistory { events } => { + snapshot.status = JoinStatus::Connected; + snapshot.recent_events = events.clone(); + if let Some(first) = events.first() { + snapshot.session_id = Some(first.session_id.clone()); + } + snapshot.last_error = None; + } + ServerMessage::SessionEvent { event } => { + if snapshot.session_id.is_none() { + snapshot.session_id = Some(event.session_id.clone()); + } + snapshot.recent_events.push(event.clone()); + if snapshot.recent_events.len() > 50 { + let drain = snapshot.recent_events.len() - 50; + snapshot.recent_events.drain(0..drain); + } + } + ServerMessage::ChatMessage { message } => { + snapshot.recent_chat.push(message.clone()); + if snapshot.recent_chat.len() > 50 { + let drain = snapshot.recent_chat.len() - 50; + snapshot.recent_chat.drain(0..drain); + } + } + ServerMessage::UserList { users } => { + snapshot.users = users.clone(); + } + ServerMessage::UserJoined { user } => { + snapshot.users.push(user.clone()); + } + ServerMessage::UserLeft { user_id } => { + snapshot.users.retain(|u| u.user_id != *user_id); + } + ServerMessage::UserRoleChanged { user_id, role } => { + for u in &mut snapshot.users { + if u.user_id == *user_id { + u.role = role.clone(); + } + } + } + ServerMessage::SessionClosed => { + snapshot.status = JoinStatus::Disconnected; + } + ServerMessage::Error { message, .. } => { + snapshot.status = JoinStatus::Error; + snapshot.last_error = Some(message.clone()); + } + ServerMessage::UserTyping { .. } => {} + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn normalize_urls() { + assert_eq!( + normalize_ws_url("127.0.0.1:7742").unwrap(), + "ws://127.0.0.1:7742/ws" + ); + assert_eq!( + normalize_ws_url("ws://127.0.0.1:7742").unwrap(), + "ws://127.0.0.1:7742/ws" + ); + assert_eq!( + normalize_ws_url("ws://127.0.0.1:7742/ws").unwrap(), + "ws://127.0.0.1:7742/ws" + ); + } + + #[test] + fn apply_history_and_chat() { + let mut snap = SessionSnapshot::new("h", "Alice"); + apply_server_message( + &mut snap, + &ServerMessage::SessionHistory { + events: vec![SessionEvent { + id: "e1".into(), + session_id: "sess".into(), + event_type: "message.created".into(), + payload: json!({"text": "hi"}), + timestamp: 1, + }], + }, + ); + assert_eq!(snap.status, JoinStatus::Connected); + assert_eq!(snap.session_id.as_deref(), Some("sess")); + + apply_server_message( + &mut snap, + &ServerMessage::ChatMessage { + message: ChatMessage { + id: "c1".into(), + session_id: "sess".into(), + user_id: "u1".into(), + display_name: Some("Bob".into()), + content: "yo".into(), + timestamp: 2, + }, + }, + ); + assert_eq!(snap.recent_chat.len(), 1); + } + + #[test] + fn client_messages_match_fixtures_shape() { + let auth = serde_json::to_value(ClientMessage::Auth { + token: "abc123".into(), + display_name: Some("Alice".into()), + }) + .unwrap(); + assert_eq!(auth["type"], "auth"); + assert_eq!(auth["token"], "abc123"); + assert_eq!(auth["displayName"], "Alice"); + + let chat = serde_json::to_value(ClientMessage::ChatSend { + content: "hello chat".into(), + }) + .unwrap(); + assert_eq!(chat["type"], "chat.send"); + + let input = serde_json::to_value(ClientMessage::CollabInput { + content: "fix the bug".into(), + }) + .unwrap(); + assert_eq!(input["type"], "collab.input"); + } +} diff --git a/crates/chorus-zed-helper/src/control.rs b/crates/chorus-zed-helper/src/control.rs new file mode 100644 index 0000000..c113e2e --- /dev/null +++ b/crates/chorus-zed-helper/src/control.rs @@ -0,0 +1,101 @@ +//! JSON-line control protocol between CLI subcommands and the background daemon. + +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +use crate::client::{JoinStatus, SessionSnapshot}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "cmd", rename_all = "snake_case")] +pub enum ControlRequest { + Ping, + Join { + host: String, + token: String, + #[serde(default = "default_display_name")] + display_name: String, + }, + Leave, + Chat { + content: String, + }, + Prompt { + content: String, + }, + Status, + Shutdown, +} + +fn default_display_name() -> String { + "Zed".to_string() +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ControlResponse { + pub ok: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub snapshot: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +impl ControlResponse { + pub fn ok_msg(message: impl Into) -> Self { + Self { + ok: true, + error: None, + snapshot: None, + message: Some(message.into()), + } + } + + pub fn ok_status(snapshot: SessionSnapshot) -> Self { + Self { + ok: true, + error: None, + snapshot: Some(snapshot), + message: None, + } + } + + pub fn err(error: impl Into) -> Self { + Self { + ok: false, + error: Some(error.into()), + snapshot: None, + message: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct DaemonState { + pub status: Option, + pub host: Option, +} + +pub fn runtime_dir() -> PathBuf { + if let Ok(dir) = std::env::var("CHORUS_ZED_RUNTIME_DIR") { + return PathBuf::from(dir); + } + if let Ok(dir) = std::env::var("XDG_RUNTIME_DIR") { + return PathBuf::from(dir).join("chorus-zed"); + } + std::env::temp_dir().join(format!( + "chorus-zed-{}", + std::env::var("USER").unwrap_or_else(|_| "user".into()) + )) +} + +pub fn socket_path() -> PathBuf { + runtime_dir().join("control.sock") +} + +pub fn pid_path() -> PathBuf { + runtime_dir().join("daemon.pid") +} diff --git a/crates/chorus-zed-helper/src/lib.rs b/crates/chorus-zed-helper/src/lib.rs new file mode 100644 index 0000000..9fb6048 --- /dev/null +++ b/crates/chorus-zed-helper/src/lib.rs @@ -0,0 +1,10 @@ +//! Chorus join client used by the Zed helper binary (CLI + MCP). +//! +//! Speaks the joiner `/ws` contract from `crates/chorus-relay` / `protocol/`. + +pub mod client; +pub mod control; +pub mod mcp; + +pub use client::{JoinClient, JoinStatus, SessionSnapshot}; +pub use control::{ControlRequest, ControlResponse, DaemonState}; diff --git a/crates/chorus-zed-helper/src/main.rs b/crates/chorus-zed-helper/src/main.rs new file mode 100644 index 0000000..92bf394 --- /dev/null +++ b/crates/chorus-zed-helper/src/main.rs @@ -0,0 +1,341 @@ +use std::fs; +use std::path::PathBuf; +use std::process::{Command, Stdio}; +use std::time::Duration; + +use clap::{Parser, Subcommand}; +use chorus_zed_helper::client::JoinClient; +use chorus_zed_helper::control::{ + pid_path, runtime_dir, socket_path, ControlRequest, ControlResponse, +}; +use chorus_zed_helper::mcp::{self, format_status}; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::net::{UnixListener, UnixStream}; +use tokio::sync::Mutex; + +#[derive(Parser, Debug)] +#[command( + name = "chorus-zed-helper", + about = "Chorus join client for Zed (CLI + MCP). Joiner-only — does not host/share." +)] +struct Args { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Start the background daemon that holds the WebSocket session + Daemon, + /// Connect to a Chorus relay as a joiner + Join { + /// Relay host:port (e.g. 192.168.1.10:7742) or ws:// URL + #[arg(long, env = "CHORUS_RELAY_HOST")] + host: String, + /// Join token from the host share command + #[arg(long)] + token: String, + /// Display name shown to collaborators + #[arg(long, default_value = "Zed", env = "CHORUS_DISPLAY_NAME")] + name: String, + }, + /// Disconnect from the current session + Leave, + /// Send a side-channel chat message + Chat { + /// Message text + content: String, + }, + /// Forward a prompt into the host session (`collab.input`) + Prompt { + /// Prompt text + content: String, + }, + /// Print connection status + Status, + /// Run as an MCP stdio server for Zed + Mcp, + /// Shut down the background daemon + Shutdown, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = Args::parse(); + match args.command { + Commands::Daemon => run_daemon().await?, + Commands::Mcp => { + // MCP uses blocking stdin reads; keep a multi-thread runtime handle. + let handle = tokio::runtime::Handle::current(); + tokio::task::spawn_blocking(move || mcp::run_stdio(handle)) + .await + .map_err(|e| e.to_string())??; + } + Commands::Join { host, token, name } => { + ensure_daemon().await?; + let resp = request(ControlRequest::Join { + host, + token, + display_name: name, + }) + .await?; + print_response(&resp); + if !resp.ok { + std::process::exit(1); + } + } + Commands::Leave => { + let resp = request(ControlRequest::Leave).await?; + print_response(&resp); + if !resp.ok { + std::process::exit(1); + } + } + Commands::Chat { content } => { + let resp = request(ControlRequest::Chat { content }).await?; + print_response(&resp); + if !resp.ok { + std::process::exit(1); + } + } + Commands::Prompt { content } => { + let resp = request(ControlRequest::Prompt { content }).await?; + print_response(&resp); + if !resp.ok { + std::process::exit(1); + } + } + Commands::Status => { + match request(ControlRequest::Status).await { + Ok(resp) => { + print_response(&resp); + if !resp.ok { + std::process::exit(1); + } + } + Err(_) => { + println!("status: disconnected\n(daemon not running)"); + } + } + } + Commands::Shutdown => { + match request(ControlRequest::Shutdown).await { + Ok(resp) => print_response(&resp), + Err(_) => println!("daemon not running"), + } + } + } + Ok(()) +} + +fn print_response(resp: &ControlResponse) { + if let Some(snap) = &resp.snapshot { + print!("{}", format_status(snap)); + } else if let Some(msg) = &resp.message { + println!("{msg}"); + } else if let Some(err) = &resp.error { + eprintln!("error: {err}"); + } else if resp.ok { + println!("ok"); + } +} + +async fn ensure_daemon() -> Result<(), String> { + if ping_daemon().await.is_ok() { + return Ok(()); + } + let dir = runtime_dir(); + fs::create_dir_all(&dir).map_err(|e| e.to_string())?; + let sock = socket_path(); + if sock.exists() { + let _ = fs::remove_file(&sock); + } + + let exe = std::env::current_exe().map_err(|e| e.to_string())?; + let child = Command::new(&exe) + .arg("daemon") + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .map_err(|e| format!("failed to spawn daemon: {e}"))?; + + fs::write(pid_path(), child.id().to_string()).map_err(|e| e.to_string())?; + + for _ in 0..50 { + if ping_daemon().await.is_ok() { + return Ok(()); + } + tokio::time::sleep(Duration::from_millis(50)).await; + } + Err("daemon did not become ready".into()) +} + +async fn ping_daemon() -> Result<(), String> { + let resp = request(ControlRequest::Ping).await?; + if resp.ok { + Ok(()) + } else { + Err(resp.error.unwrap_or_else(|| "ping failed".into())) + } +} + +async fn request(req: ControlRequest) -> Result { + let path = socket_path(); + let mut stream = UnixStream::connect(&path) + .await + .map_err(|e| format!("connect control socket: {e}"))?; + let line = serde_json::to_string(&req).map_err(|e| e.to_string())?; + stream + .write_all(line.as_bytes()) + .await + .map_err(|e| e.to_string())?; + stream + .write_all(b"\n") + .await + .map_err(|e| e.to_string())?; + + let mut reader = BufReader::new(stream); + let mut response = String::new(); + reader + .read_line(&mut response) + .await + .map_err(|e| e.to_string())?; + serde_json::from_str(response.trim()).map_err(|e| format!("bad control response: {e}")) +} + +async fn run_daemon() -> Result<(), Box> { + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")), + ) + .with_writer(std::io::stderr) + .init(); + + let dir = runtime_dir(); + fs::create_dir_all(&dir)?; + let sock: PathBuf = socket_path(); + if sock.exists() { + fs::remove_file(&sock)?; + } + + let listener = UnixListener::bind(&sock)?; + let session: Mutex> = Mutex::new(None); + + loop { + let (stream, _) = listener.accept().await?; + let mut reader = BufReader::new(stream); + let mut line = String::new(); + if reader.read_line(&mut line).await? == 0 { + continue; + } + let req: ControlRequest = match serde_json::from_str(line.trim()) { + Ok(r) => r, + Err(e) => { + let mut stream = reader.into_inner(); + let resp = ControlResponse::err(format!("bad request: {e}")); + let body = serde_json::to_string(&resp)?; + stream.write_all(body.as_bytes()).await?; + stream.write_all(b"\n").await?; + continue; + } + }; + + let (resp, shutdown) = handle_control(&session, req).await; + let mut stream = reader.into_inner(); + let body = serde_json::to_string(&resp)?; + stream.write_all(body.as_bytes()).await?; + stream.write_all(b"\n").await?; + if shutdown { + break; + } + } + + let _ = fs::remove_file(sock); + let _ = fs::remove_file(pid_path()); + Ok(()) +} + +async fn handle_control( + session: &Mutex>, + req: ControlRequest, +) -> (ControlResponse, bool) { + match req { + ControlRequest::Ping => (ControlResponse::ok_msg("pong"), false), + ControlRequest::Shutdown => { + let mut guard = session.lock().await; + if let Some(client) = guard.take() { + client.disconnect().await; + } + (ControlResponse::ok_msg("shutting down"), true) + } + ControlRequest::Join { + host, + token, + display_name, + } => match JoinClient::connect(&host, &token, &display_name).await { + Ok(client) => { + let snap = client.snapshot().await; + let mut guard = session.lock().await; + if let Some(old) = guard.take() { + old.disconnect().await; + } + *guard = Some(client); + (ControlResponse::ok_status(snap), false) + } + Err(e) => (ControlResponse::err(e), false), + }, + ControlRequest::Leave => { + let mut guard = session.lock().await; + if let Some(client) = guard.take() { + client.disconnect().await; + (ControlResponse::ok_msg("left session"), false) + } else { + (ControlResponse::ok_msg("not connected"), false) + } + } + ControlRequest::Chat { content } => { + let guard = session.lock().await; + match guard.as_ref() { + Some(client) => match client.send_chat(&content) { + Ok(()) => (ControlResponse::ok_msg("chat sent"), false), + Err(e) => (ControlResponse::err(e), false), + }, + None => (ControlResponse::err("not connected"), false), + } + } + ControlRequest::Prompt { content } => { + let guard = session.lock().await; + match guard.as_ref() { + Some(client) => match client.send_prompt(&content) { + Ok(()) => (ControlResponse::ok_msg("prompt sent"), false), + Err(e) => (ControlResponse::err(e), false), + }, + None => (ControlResponse::err("not connected"), false), + } + } + ControlRequest::Status => { + let guard = session.lock().await; + match guard.as_ref() { + Some(client) => { + let snap = client.snapshot().await; + (ControlResponse::ok_status(snap), false) + } + None => ( + ControlResponse::ok_status(chorus_zed_helper::client::SessionSnapshot { + status: chorus_zed_helper::client::JoinStatus::Disconnected, + host: String::new(), + display_name: String::new(), + session_id: None, + users: vec![], + recent_events: vec![], + recent_chat: vec![], + last_error: None, + }), + false, + ), + } + } + } +} diff --git a/crates/chorus-zed-helper/src/mcp.rs b/crates/chorus-zed-helper/src/mcp.rs new file mode 100644 index 0000000..9855c04 --- /dev/null +++ b/crates/chorus-zed-helper/src/mcp.rs @@ -0,0 +1,300 @@ +//! Minimal stdio MCP server exposing Chorus join tools to Zed's Agent Panel. + +use std::io::{BufRead, BufReader, Write}; +use std::sync::Arc; + +use serde_json::{json, Value}; +use tokio::runtime::Handle; +use tokio::sync::Mutex; + +use crate::client::{JoinClient, JoinStatus}; + +struct Session { + client: Option, +} + +/// Run an MCP server on stdin/stdout (blocking; requires a Tokio handle). +pub fn run_stdio(handle: Handle) -> Result<(), String> { + let session = Arc::new(Mutex::new(Session { client: None })); + let stdin = std::io::stdin(); + let mut stdout = std::io::stdout(); + let mut reader = BufReader::new(stdin.lock()); + + loop { + let msg = match read_message(&mut reader)? { + Some(v) => v, + None => break, + }; + + let id = msg.get("id").cloned(); + let method = msg.get("method").and_then(|m| m.as_str()).unwrap_or(""); + let params = msg.get("params").cloned().unwrap_or(json!({})); + + // Notifications (no id) — ignore after handling initialize side-effects if any. + if id.is_none() { + continue; + } + + let result = match method { + "initialize" => Ok(json!({ + "protocolVersion": "2024-11-05", + "capabilities": { "tools": {} }, + "serverInfo": { + "name": "chorus-zed", + "version": env!("CARGO_PKG_VERSION") + } + })), + "tools/list" => Ok(json!({ "tools": tool_defs() })), + "tools/call" => { + let name = params + .get("name") + .and_then(|n| n.as_str()) + .unwrap_or(""); + let args = params + .get("arguments") + .cloned() + .unwrap_or(json!({})); + handle.block_on(call_tool(session.clone(), name, args)) + } + "ping" => Ok(json!({})), + _ => Err(format!("method not found: {method}")), + }; + + let response = match result { + Ok(value) => json!({ + "jsonrpc": "2.0", + "id": id, + "result": value + }), + Err(err) => json!({ + "jsonrpc": "2.0", + "id": id, + "error": { "code": -32000, "message": err } + }), + }; + write_message(&mut stdout, &response)?; + } + Ok(()) +} + +fn tool_defs() -> Vec { + vec![ + json!({ + "name": "chorus_join", + "description": "Join an existing Chorus collaborative session as a joiner (connect to relay /ws).", + "inputSchema": { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "Relay host:port (e.g. 192.168.1.10:7742) or full ws:// URL" + }, + "token": { "type": "string", "description": "Join token from the host" }, + "display_name": { + "type": "string", + "description": "Display name shown to collaborators (default: Zed)" + } + }, + "required": ["host", "token"] + } + }), + json!({ + "name": "chorus_leave", + "description": "Leave the current Chorus session and disconnect from the relay.", + "inputSchema": { "type": "object", "properties": {} } + }), + json!({ + "name": "chorus_chat", + "description": "Send a side-channel chat message (does not become an LLM prompt).", + "inputSchema": { + "type": "object", + "properties": { + "content": { "type": "string", "description": "Chat message text" } + }, + "required": ["content"] + } + }), + json!({ + "name": "chorus_prompt", + "description": "Send a collaborative prompt (collab.input) into the host OpenCode session. Requires edit role.", + "inputSchema": { + "type": "object", + "properties": { + "content": { "type": "string", "description": "Prompt text for the host session" } + }, + "required": ["content"] + } + }), + json!({ + "name": "chorus_status", + "description": "Show join connection status, users, and recent session/chat events.", + "inputSchema": { "type": "object", "properties": {} } + }), + ] +} + +async fn call_tool( + session: Arc>, + name: &str, + args: Value, +) -> Result { + match name { + "chorus_join" => { + let host = args + .get("host") + .and_then(|v| v.as_str()) + .ok_or("host is required")? + .to_string(); + let token = args + .get("token") + .and_then(|v| v.as_str()) + .ok_or("token is required")? + .to_string(); + let display_name = args + .get("display_name") + .and_then(|v| v.as_str()) + .unwrap_or("Zed") + .to_string(); + + let client = JoinClient::connect(&host, &token, &display_name).await?; + let snap = client.snapshot().await; + let mut guard = session.lock().await; + if let Some(old) = guard.client.take() { + old.disconnect().await; + } + guard.client = Some(client); + Ok(tool_text(format!( + "Joined Chorus session on {} as {} (status={:?}, users={})", + snap.host, + snap.display_name, + snap.status, + snap.users.len() + ))) + } + "chorus_leave" => { + let mut guard = session.lock().await; + if let Some(client) = guard.client.take() { + client.disconnect().await; + Ok(tool_text("Left Chorus session.".into())) + } else { + Ok(tool_text("Not connected.".into())) + } + } + "chorus_chat" => { + let content = args + .get("content") + .and_then(|v| v.as_str()) + .ok_or("content is required")?; + let guard = session.lock().await; + let client = guard.client.as_ref().ok_or("not connected — call chorus_join first")?; + client.send_chat(content)?; + Ok(tool_text(format!("Chat sent: {content}"))) + } + "chorus_prompt" => { + let content = args + .get("content") + .and_then(|v| v.as_str()) + .ok_or("content is required")?; + let guard = session.lock().await; + let client = guard.client.as_ref().ok_or("not connected — call chorus_join first")?; + client.send_prompt(content)?; + Ok(tool_text(format!("Prompt forwarded to host: {content}"))) + } + "chorus_status" => { + let guard = session.lock().await; + match guard.client.as_ref() { + None => Ok(tool_text( + "status: disconnected\n(no active Chorus join)".into(), + )), + Some(client) => { + let snap = client.snapshot().await; + Ok(tool_text(format_status(&snap))) + } + } + } + other => Err(format!("unknown tool: {other}")), + } +} + +fn tool_text(text: String) -> Value { + json!({ + "content": [{ "type": "text", "text": text }], + "isError": false + }) +} + +pub fn format_status(snap: &crate::client::SessionSnapshot) -> String { + let mut out = String::new(); + out.push_str(&format!("status: {:?}\n", snap.status)); + out.push_str(&format!("host: {}\n", snap.host)); + out.push_str(&format!("displayName: {}\n", snap.display_name)); + if let Some(id) = &snap.session_id { + out.push_str(&format!("sessionId: {id}\n")); + } + if let Some(err) = &snap.last_error { + out.push_str(&format!("error: {err}\n")); + } + out.push_str(&format!("users ({})", snap.users.len())); + if snap.users.is_empty() { + out.push('\n'); + } else { + out.push('\n'); + for u in &snap.users { + let name = u.display_name.as_deref().unwrap_or("(anonymous)"); + out.push_str(&format!(" - {} [{}] {:?}\n", name, u.user_id, u.role)); + } + } + out.push_str(&format!( + "recentEvents: {} | recentChat: {}\n", + snap.recent_events.len(), + snap.recent_chat.len() + )); + if snap.status == JoinStatus::Connected { + for chat in snap.recent_chat.iter().rev().take(5).collect::>().into_iter().rev() + { + let name = chat.display_name.as_deref().unwrap_or(&chat.user_id); + out.push_str(&format!(" chat <{name}> {}\n", chat.content)); + } + } + out +} + +fn read_message(reader: &mut R) -> Result, String> { + let mut headers = String::new(); + loop { + let mut line = String::new(); + let n = reader + .read_line(&mut line) + .map_err(|e| format!("stdin read: {e}"))?; + if n == 0 { + return Ok(None); + } + if line == "\r\n" || line == "\n" { + break; + } + headers.push_str(&line); + } + + let mut content_length: Option = None; + for header in headers.lines() { + let lower = header.to_ascii_lowercase(); + if let Some(rest) = lower.strip_prefix("content-length:") { + content_length = rest.trim().parse().ok(); + } + } + let len = content_length.ok_or("missing Content-Length")?; + let mut buf = vec![0u8; len]; + reader + .read_exact(&mut buf) + .map_err(|e| format!("body read: {e}"))?; + let value = serde_json::from_slice(&buf).map_err(|e| format!("json: {e}"))?; + Ok(Some(value)) +} + +fn write_message(writer: &mut W, value: &Value) -> Result<(), String> { + let body = serde_json::to_vec(value).map_err(|e| e.to_string())?; + write!(writer, "Content-Length: {}\r\n\r\n", body.len()).map_err(|e| e.to_string())?; + writer.write_all(&body).map_err(|e| e.to_string())?; + writer.flush().map_err(|e| e.to_string())?; + Ok(()) +} diff --git a/crates/chorus-zed-helper/tests/join_client.rs b/crates/chorus-zed-helper/tests/join_client.rs new file mode 100644 index 0000000..bebe9a5 --- /dev/null +++ b/crates/chorus-zed-helper/tests/join_client.rs @@ -0,0 +1,127 @@ +//! Integration: JoinClient against a live chorus-relay (auth, chat, collab.input). + +use std::time::Duration; + +use chorus_relay::protocol::{HostToRelay, RelayToHost, UserRole}; +use chorus_relay::server::{serve, RelayConfig}; +use chorus_zed_helper::client::{JoinClient, JoinStatus}; +use futures_util::{SinkExt, StreamExt}; +use tokio_tungstenite::{connect_async, tungstenite::Message}; + +type WsStream = + tokio_tungstenite::WebSocketStream>; + +async fn start_relay(port: u16, host_token: &str) { + let token = host_token.to_string(); + tokio::spawn(async move { + serve(RelayConfig { + port, + host_token: token, + bind: "127.0.0.1".into(), + }) + .await + .expect("relay failed"); + }); + for _ in 0..50 { + if tokio::net::TcpStream::connect(("127.0.0.1", port)) + .await + .is_ok() + { + return; + } + tokio::time::sleep(Duration::from_millis(20)).await; + } + panic!("relay not ready on {port}"); +} + +async fn connect_host(port: u16, host_token: &str) -> WsStream { + let (mut ws, _) = connect_async(format!("ws://127.0.0.1:{port}/host")) + .await + .expect("host connect"); + ws.send(Message::Text( + serde_json::to_string(&HostToRelay::HostAuth { + token: host_token.into(), + }) + .unwrap() + .into(), + )) + .await + .unwrap(); + let msg = recv_json::(&mut ws).await; + assert!(matches!(msg, RelayToHost::HostReady { .. })); + let _ = tokio::time::timeout(Duration::from_millis(100), ws.next()).await; + ws +} + +async fn recv_json(ws: &mut WsStream) -> T { + loop { + let msg = ws.next().await.expect("ended").expect("ws"); + match msg { + Message::Text(t) => return serde_json::from_str(&t).expect("json"), + Message::Close(frame) => panic!("close: {frame:?}"), + _ => continue, + } + } +} + +async fn issue_token(host: &mut WsStream) -> String { + host.send(Message::Text( + serde_json::to_string(&HostToRelay::TokenIssue { + session_id: "sess-zed".into(), + role: Some(UserRole::Edit), + ttl_ms: None, + }) + .unwrap() + .into(), + )) + .await + .unwrap(); + loop { + let msg = recv_json::(host).await; + if let RelayToHost::TokenIssued { token } = msg { + return token.token; + } + } +} + +#[tokio::test] +async fn join_client_auth_chat_and_prompt() { + let port = 17942; + let host_token = "zed-helper-test-token"; + start_relay(port, host_token).await; + let mut host = connect_host(port, host_token).await; + let token = issue_token(&mut host).await; + + let client = JoinClient::connect(&format!("127.0.0.1:{port}"), &token, "ZedTester") + .await + .expect("join"); + let snap = client.snapshot().await; + assert_eq!(snap.status, JoinStatus::Connected); + + client.send_chat("hello from zed helper").unwrap(); + // Host should receive chat.message + let mut saw_chat = false; + for _ in 0..20 { + let msg = recv_json::(&mut host).await; + if let RelayToHost::ChatMessage { message } = msg { + assert_eq!(message.content, "hello from zed helper"); + saw_chat = true; + break; + } + } + assert!(saw_chat, "host did not receive chat"); + + client.send_prompt("fix the bug").unwrap(); + let mut saw_prompt = false; + for _ in 0..20 { + let msg = recv_json::(&mut host).await; + if let RelayToHost::CollabInput { content, .. } = msg { + assert_eq!(content, "fix the bug"); + saw_prompt = true; + break; + } + } + assert!(saw_prompt, "host did not receive collab.input"); + + client.disconnect().await; +} diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index b1bd64b..d46f91c 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -49,7 +49,7 @@ Recommended shape: - **v1:** OpenCode adapter = this repo’s plugin + local **Rust** `chorus-relay` - **v1.x:** keep `@chorus/shared` as the stable joiner + host-control contract; `@chorus/client` holds `JoinClient` / `RelayServer` for non-OpenCode hosts -- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) and Zed (when present) — same wire protocol, host-specific UI only +- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) and Zed (`packages/zed` + `crates/chorus-zed-helper`) — same wire protocol, host-specific UI only. Zed v1 is joiner/MCP-only (no host share). - **v2:** optional further adapters (Codex app-server remains a strong candidate) once OpenCode UX is solid; split adapter packages into separate repos only when publish/CI ownership diverges **Do not** make Claude Code / Amp the primary host — large audiences, but proprietary control planes. Treat them as distribution adapters later, not the core. diff --git a/docs/STATUS.md b/docs/STATUS.md index d1dac8a..b26d080 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -14,6 +14,8 @@ Chorus is an **OpenCode↔OpenCode** LAN collaboration stack: The browser companion (`packages/web`) was intentionally removed. Joiners now mirror the host transcript into their OpenCode session (`[Host]:` / `[AI]:` lines via `noReply` inject); side-channel chat/typing remain toasts. The in-process Bun relay has been replaced by `crates/chorus-relay`. +**Editor adapters (in progress):** VS Code (`packages/vscode`) and Zed (`packages/zed` + `crates/chorus-zed-helper`). Zed v1 is **joiner-only** via MCP/CLI — no host share and no OpenCode transcript injection. + Differentiation vs nearby OpenCode plugins (`opencode-live`, `opencode-sessions`, `opencode-ensemble`, `opencode-relay`): those target **multi-agent / same-DB sync**. Chorus targets **multi-human** pair programming on one live AI session. ## Priority backlog diff --git a/packages/zed/Cargo.lock b/packages/zed/Cargo.lock new file mode 100644 index 0000000..7aec8ee --- /dev/null +++ b/packages/zed/Cargo.lock @@ -0,0 +1,829 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "auditable-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" +dependencies = [ + "semver", + "serde", + "serde_json", + "topological-sort", +] + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chorus-zed" +version = "0.1.0" +dependencies = [ + "zed_extension_api", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "spdx" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3" +dependencies = [ + "smallvec", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "wasm-encoder" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" +dependencies = [ + "anyhow", + "auditable-serde", + "flate2", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "url", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10fb6648689b3929d56bbc7eb1acf70c9a42a29eb5358c67c10f54dbd5d695de" +dependencies = [ + "wit-bindgen-rt", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92fa781d4f2ff6d3f27f3cc9b74a73327b31ca0dc4a3ef25a0ce2983e0e5af9b" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" +dependencies = [ + "bitflags", + "futures", + "once_cell", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0809dc5ba19e2e98661bf32fc0addc5a3ca5bf3a6a7083aa6ba484085ff3ce" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.119", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad19eec017904e04c60719592a803ee5da76cb51c81e3f6fbf9457f59db49799" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.119", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zed_extension_api" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0729d50b4ca0a7e28e590bbe32e3ca0194d97ef654961451a424c661a366fca0" +dependencies = [ + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47402523226a02bfe5230160dc3ccc089aa6f6f19e7fcbb4e6f824bbb1b4aa62" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/packages/zed/Cargo.toml b/packages/zed/Cargo.toml new file mode 100644 index 0000000..4db7fa4 --- /dev/null +++ b/packages/zed/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "chorus-zed" +version = "0.1.0" +edition = "2021" +license = "MIT" +publish = false +description = "Zed extension that launches the Chorus join helper as an MCP context server" + +# Standalone from the monorepo Cargo workspace (wasm32-wasip2 via Zed). +[workspace] + +[lib] +crate-type = ["cdylib"] +path = "src/lib.rs" + +[dependencies] +zed_extension_api = "0.7.0" diff --git a/packages/zed/README.md b/packages/zed/README.md new file mode 100644 index 0000000..09f12f3 --- /dev/null +++ b/packages/zed/README.md @@ -0,0 +1,102 @@ +# Chorus Zed extension (v1 — joiner) + +Join an existing Chorus collaborative session from [Zed](https://zed.dev) via a **native helper** + **MCP context server**. + +Zed extensions run as `wasm32-wasip2` and cannot hold long-lived WebSocket UIs themselves. This package is the thin WASM adapter; `crates/chorus-zed-helper` speaks the Chorus `/ws` protocol. + +## What works (v1) + +| Capability | How | +|---|---| +| Join a host’s relay | MCP tool `chorus_join` or CLI `chorus-zed-helper join` | +| Leave | `chorus_leave` / `leave` | +| Side-channel chat | `chorus_chat` / `chat` | +| Forward prompts (`collab.input`) | `chorus_prompt` / `prompt` (needs `edit` role) | +| Status / recent events | `chorus_status` / `status` | + +## What does **not** work (honest limits) + +- **Host share / stop** — Zed cannot inject into an OpenCode agent session. Hosting still requires the OpenCode plugin (`/chorus-share`). +- **OpenCode transcript mirroring** — session events are visible via `chorus_status` / helper state, not injected into a local agent transcript. +- **Extension slash commands** — Zed removed extension slash commands; use MCP tools (or the CLI). Tool names mirror OpenCode’s `/chorus-join`, `/chorus-leave`, `/chorus-chat`, `/chorus-status`. + +## Architecture + +``` +Zed Agent Panel + └─ MCP (stdio) ──► chorus-zed-helper mcp + └─ WebSocket ──► chorus-relay /ws + └─ host OpenCode plugin +``` + +CLI subcommands talk to a short-lived background daemon over a Unix socket so `join` / `chat` / `status` share one connection. + +## Install the native helper + +From the monorepo root: + +```sh +cargo build -p chorus-zed-helper --release +# put it on PATH, e.g.: +cp target/release/chorus-zed-helper ~/.local/bin/ +``` + +Or: + +```sh +cargo install --path crates/chorus-zed-helper +``` + +Verify: + +```sh +chorus-zed-helper --help +``` + +## Install Dev Extension in Zed + +1. Build/install `chorus-zed-helper` on `PATH` (above). +2. Install the `wasm32-wasip2` target if needed: `rustup target add wasm32-wasip2`. +3. In Zed: command palette → **zed: extensions**. +4. Click **Install Dev Extension**. +5. Select this directory: `packages/zed` (the folder that contains `extension.toml`). +6. Enable the **Chorus** context server in Agent / MCP settings if it is not auto-enabled. +7. Confirm tools `chorus_join`, `chorus_leave`, `chorus_chat`, `chorus_prompt`, `chorus_status` appear. + +If the context server fails to start, Zed cannot find `chorus-zed-helper`. Fix `PATH`, or register a manual context server in `settings.json`: + +```json +{ + "context_servers": { + "chorus": { + "command": "/absolute/path/to/chorus-zed-helper", + "args": ["mcp"] + } + } +} +``` + +## CLI usage (without Zed) + +```sh +# Host must already be sharing via OpenCode /chorus-share +chorus-zed-helper join --host 192.168.1.10:7742 --token --name Alex +chorus-zed-helper status +chorus-zed-helper chat "hey — looking at the failing test" +chorus-zed-helper prompt "fix the flaky auth test" +chorus-zed-helper leave +``` + +## Develop / test + +```sh +# Helper unit + integration tests (spins up chorus-relay) +cargo test -p chorus-zed-helper + +# Extension WASM (optional local check; Zed also builds on Install Dev Extension) +cd packages/zed +rustup target add wasm32-wasip2 +cargo build --target wasm32-wasip2 +``` + +Protocol fixtures live in `/protocol`; Rust types are shared via `chorus-relay::protocol`. diff --git a/packages/zed/extension.toml b/packages/zed/extension.toml new file mode 100644 index 0000000..4340768 --- /dev/null +++ b/packages/zed/extension.toml @@ -0,0 +1,11 @@ +id = "chorus" +name = "Chorus" +description = "Join Chorus collaborative AI sessions from Zed (joiner via native helper + MCP)" +version = "0.1.0" +schema_version = 1 +authors = ["Steven Roomberg"] +repository = "https://github.com/sroomberg/chorus" + +[context_servers.chorus] +name = "Chorus" +description = "Join/leave Chorus sessions, side-channel chat, and collab prompts" diff --git a/packages/zed/src/lib.rs b/packages/zed/src/lib.rs new file mode 100644 index 0000000..dcb7d0d --- /dev/null +++ b/packages/zed/src/lib.rs @@ -0,0 +1,27 @@ +use zed_extension_api::{self as zed, Command, ContextServerId, Project, Result}; + +struct ChorusExtension; + +impl zed::Extension for ChorusExtension { + fn new() -> Self { + Self + } + + fn context_server_command( + &mut self, + _context_server_id: &ContextServerId, + _project: &Project, + ) -> Result { + // The WebSocket join client lives in the native `chorus-zed-helper` binary. + // Install it on PATH (`cargo install --path crates/chorus-zed-helper` from the repo, + // or `cargo build -p chorus-zed-helper --release` and copy `target/release/chorus-zed-helper`). + // Override the binary path via Zed settings `context_servers.chorus` env if needed. + Ok(Command { + command: "chorus-zed-helper".into(), + args: vec!["mcp".into()], + env: vec![], + }) + } +} + +zed::register_extension!(ChorusExtension); From 2ad3534d3ea2404d227d1de9bebd04de2069beba Mon Sep 17 00:00:00 2001 From: sroomberg Date: Wed, 19 Aug 2026 09:00:04 -0400 Subject: [PATCH 04/10] Remove the Zed adapter from this pull request. Keep the VS Code extension and shared client on this branch; Zed moves to a follow-up PR. --- .gitignore | 1 - CHANGELOG.md | 16 + Cargo.lock | 16 - Cargo.toml | 4 +- README.md | 13 +- crates/chorus-zed-helper/Cargo.toml | 29 - crates/chorus-zed-helper/src/client.rs | 353 -------- crates/chorus-zed-helper/src/control.rs | 101 --- crates/chorus-zed-helper/src/lib.rs | 10 - crates/chorus-zed-helper/src/main.rs | 341 ------- crates/chorus-zed-helper/src/mcp.rs | 300 ------- crates/chorus-zed-helper/tests/join_client.rs | 127 --- docs/DECISIONS.md | 2 +- docs/STATUS.md | 3 +- packages/plugin/dist/join/index.d.ts | 38 +- packages/plugin/dist/join/index.js | 173 +--- packages/plugin/dist/relay/index.d.ts | 119 +-- packages/plugin/dist/relay/index.js | 398 +-------- packages/zed/Cargo.lock | 829 ------------------ packages/zed/Cargo.toml | 17 - packages/zed/README.md | 102 --- packages/zed/extension.toml | 11 - packages/zed/src/lib.rs | 27 - 23 files changed, 32 insertions(+), 2998 deletions(-) delete mode 100644 crates/chorus-zed-helper/Cargo.toml delete mode 100644 crates/chorus-zed-helper/src/client.rs delete mode 100644 crates/chorus-zed-helper/src/control.rs delete mode 100644 crates/chorus-zed-helper/src/lib.rs delete mode 100644 crates/chorus-zed-helper/src/main.rs delete mode 100644 crates/chorus-zed-helper/src/mcp.rs delete mode 100644 crates/chorus-zed-helper/tests/join_client.rs delete mode 100644 packages/zed/Cargo.lock delete mode 100644 packages/zed/Cargo.toml delete mode 100644 packages/zed/README.md delete mode 100644 packages/zed/extension.toml delete mode 100644 packages/zed/src/lib.rs diff --git a/.gitignore b/.gitignore index 143d31e..96466e4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ coverage/ playwright-report/ test-results/ target/ -packages/zed/target/ .multi-agent/ *.env *.env.local diff --git a/CHANGELOG.md b/CHANGELOG.md index 6606006..073e5d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - VS Code extension (`packages/vscode`) — share/join/chat over the same relay protocol; Session sidebar + commands - Extract `@chorus/client` (`JoinClient` + `RelayServer`) shared by OpenCode plugin, VS Code, and future adapters - Cross-adapter relay e2e: VS Code host ↔ terminal joiner and terminal host ↔ VS Code joiner (`bun run test:vscode-relay-e2e`) +- Session access control: host approval, required display names, repo/email/domain gates (`session.policy` / `auth.pending` / `host.approve|deny`) +- Hybrid OpenCode security e2e, VS Code adapter e2e, and Cloud Agent install script ## v2.0.0 — 2026-08-21 @@ -126,6 +128,20 @@ Prefer the **OpenCode web UI** for live mirrored lines. `opencode attach` often | `CHORUS_AWS_BUCKET` | — | Optional S3/R2 session backup | Full tables: [README](https://github.com/sroomberg/chorus/blob/main/README.md). Status and backlog: [docs/STATUS.md](https://github.com/sroomberg/chorus/blob/main/docs/STATUS.md). Enterprise gaps: [docs/ENTERPRISE.md](https://github.com/sroomberg/chorus/blob/main/docs/ENTERPRISE.md). +======= +- Session access control: host approval, required display names, repo/email/domain gates (`session.policy` / `auth.pending` / `host.approve|deny`) +- Configurable git remote prefixes and host rewrites; layered `chorus.json` org settings +- Hybrid OpenCode security e2e, VS Code adapter e2e, and Cloud Agent install script +- VS Code extension (`packages/vscode`) — share/join/chat; Session sidebar; approve/deny +- Extract `@chorus/client` (`JoinClient` + `RelayServer`) for reuse by OpenCode, VS Code, and future adapters +- Real-time shared transcript for all agents: fan out collaborator prompts to every joiner, abort joiner local LLM, mirror `[Host]`/`[name]`/`[AI]` (prefer web UI for live view) +- Joiner mirrors host prompts and AI replies into its OpenCode session transcript (`[Host]:` / `[AI]:`), including history replay on join (replaces toast-only viewing) +- Fix: prevent host/joiner feedback loop when the same agent both shares and joins (block join while sharing; never mirror while hosting; drop echoed `[AI]`/`[Host]:` collab lines) +- Replace in-process Bun WebSocket relay with Rust `chorus-relay` binary (`crates/chorus-relay`) +- Host control protocol on `/host` (token issue, session events, chat, collab.input fan-in) +- Joiner protocol on `/ws` unchanged +- Plugin spawns/manages the relay subprocess (`CHORUS_RELAY_BIN` override) +>>>>>>> a29eb58 (Remove the Zed adapter from this pull request.) ## v0.1.6 — 2026-05-27 diff --git a/Cargo.lock b/Cargo.lock index 2d2c383..6926b20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,22 +177,6 @@ dependencies = [ "url", ] -[[package]] -name = "chorus-zed-helper" -version = "0.1.0" -dependencies = [ - "chorus-relay", - "clap", - "futures-util", - "serde", - "serde_json", - "tokio", - "tokio-tungstenite 0.26.2", - "tracing", - "tracing-subscriber", - "url", -] - [[package]] name = "clap" version = "4.6.5" diff --git a/Cargo.toml b/Cargo.toml index 3a5f07e..87ba777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [workspace] resolver = "2" -members = ["crates/chorus-relay", "crates/chorus-zed-helper"] -exclude = ["packages/zed"] -# packages/zed is a standalone Zed extension (wasm32-wasip2) built by Zed / cargo --target. +members = ["crates/chorus-relay"] [workspace.package] edition = "2021" diff --git a/README.md b/README.md index 84046b5..4e8ea86 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Collaborative OpenCode session sharing. Pair-program a live AI session from anot ## How it works -Chorus is an [OpenCode](https://github.com/sst/opencode) plugin (plus VS Code / other adapters) and a **Rust WebSocket relay** (`chorus-relay`). +Chorus is an [OpenCode](https://github.com/sst/opencode) plugin (plus a VS Code adapter) and a **Rust WebSocket relay** (`chorus-relay`). ``` Host runs opencode → plugin loads @@ -52,27 +52,22 @@ One monorepo, two ecosystems, one wire contract: | `packages/plugin` | npm `@chorus/plugin` | OpenCode plugin — tools, hooks, spawns/manages relay | | `packages/client` | npm `@chorus/client` | Shared `JoinClient` + `RelayServer` for host adapters | | `packages/vscode` | VS Code extension `chorus` | Share/join Chorus sessions from VS Code | -| `packages/zed` | Zed extension `chorus` | Joiner adapter (WASM + MCP → `chorus-zed-helper`) | | `packages/shared` | npm `@chorus/shared` | TypeScript types + codecs for joiner and host-control protocols | | `crates/chorus-relay` | `chorus-relay` binary | Rust WebSocket relay (`/ws` joiners, `/host` control plane) | -| `crates/chorus-zed-helper` | `chorus-zed-helper` binary | Native Chorus join client (CLI + MCP) for Zed | | `protocol/` | fixtures (not published) | Canonical JSON examples both TS and Rust must deserialize | -Root `package.json` scripts are the only task entry (`build`, `test`, `typecheck`). Bun workspaces own `packages/*`; Cargo owns `crates/*` (Zed’s `packages/zed` is built separately for `wasm32-wasip2`). +Root `package.json` scripts are the only task entry (`build`, `test`, `typecheck`). Bun workspaces own `packages/*`; Cargo owns `crates/*`. ## Development ```sh bun install -bun run build # release relay + helper + TS packages -bun run test # relay/helper tests + TS/Bun tests (includes protocol fixtures) +bun run build # release relay + TS packages +bun run test # relay tests + TS/Bun tests (includes protocol fixtures) bun run typecheck cargo test -p chorus-relay -cargo test -p chorus-zed-helper ``` -Zed joiner (optional): see [packages/zed/README.md](packages/zed/README.md) for Install Dev Extension + `chorus-zed-helper` setup. - ### Multi-agent local testing Run several isolated OpenCode servers on one machine (each with Chorus loaded) and drive share/join over the HTTP API: diff --git a/crates/chorus-zed-helper/Cargo.toml b/crates/chorus-zed-helper/Cargo.toml deleted file mode 100644 index 67bbbeb..0000000 --- a/crates/chorus-zed-helper/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "chorus-zed-helper" -version = "0.1.0" -edition.workspace = true -license.workspace = true -authors.workspace = true -description = "Native Chorus join client for the Zed extension (CLI + MCP)" -publish = false - -[[bin]] -name = "chorus-zed-helper" -path = "src/main.rs" - -[dependencies] -chorus-relay = { path = "../chorus-relay" } -clap = { version = "4", features = ["derive", "env"] } -futures-util = "0.3" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tokio = { version = "1", features = ["full"] } -tokio-tungstenite = "0.26" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -url = "2" - -[dev-dependencies] -chorus-relay = { path = "../chorus-relay" } -tokio-tungstenite = "0.26" -futures-util = "0.3" diff --git a/crates/chorus-zed-helper/src/client.rs b/crates/chorus-zed-helper/src/client.rs deleted file mode 100644 index da941c9..0000000 --- a/crates/chorus-zed-helper/src/client.rs +++ /dev/null @@ -1,353 +0,0 @@ -use std::sync::Arc; -use std::time::Duration; - -use chorus_relay::protocol::{ - ChatMessage, ClientMessage, ConnectedUser, ServerMessage, SessionEvent, -}; -use futures_util::{SinkExt, StreamExt}; -use serde::{Deserialize, Serialize}; -use tokio::sync::{mpsc, RwLock}; -use tokio::task::JoinHandle; -use tokio_tungstenite::{connect_async, tungstenite::Message}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum JoinStatus { - Disconnected, - Connecting, - Connected, - Error, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SessionSnapshot { - pub status: JoinStatus, - pub host: String, - pub display_name: String, - pub session_id: Option, - pub users: Vec, - pub recent_events: Vec, - pub recent_chat: Vec, - pub last_error: Option, -} - -impl SessionSnapshot { - fn new(host: &str, display_name: &str) -> Self { - Self { - status: JoinStatus::Disconnected, - host: host.to_string(), - display_name: display_name.to_string(), - session_id: None, - users: Vec::new(), - recent_events: Vec::new(), - recent_chat: Vec::new(), - last_error: None, - } - } -} - -/// Live joiner WebSocket client for the Chorus `/ws` surface. -pub struct JoinClient { - inner: Arc>, - outbound: mpsc::UnboundedSender, - reader: Option>, -} - -struct Inner { - snapshot: SessionSnapshot, -} - -impl JoinClient { - /// Connect to `ws://host/ws` (or `wss://`), authenticate, and wait for history. - pub async fn connect( - host: &str, - token: &str, - display_name: &str, - ) -> Result { - let ws_url = normalize_ws_url(host)?; - let (ws, _) = connect_async(&ws_url) - .await - .map_err(|e| format!("connect failed: {e}"))?; - - let (mut write, mut read) = ws.split(); - let auth = ClientMessage::Auth { - token: token.to_string(), - display_name: Some(display_name.to_string()), - }; - write - .send(Message::Text( - serde_json::to_string(&auth) - .map_err(|e| e.to_string())? - .into(), - )) - .await - .map_err(|e| format!("auth send failed: {e}"))?; - - let mut snapshot = SessionSnapshot::new(host, display_name); - snapshot.status = JoinStatus::Connecting; - - // Wait until session.history (connected) or error / timeout. - let deadline = tokio::time::Instant::now() + Duration::from_secs(10); - loop { - if tokio::time::Instant::now() > deadline { - return Err("timed out waiting for session.history".into()); - } - let next = tokio::time::timeout(Duration::from_secs(5), read.next()) - .await - .map_err(|_| "timed out waiting for relay message".to_string())?; - let msg = match next { - Some(Ok(Message::Text(t))) => t, - Some(Ok(Message::Close(frame))) => { - return Err(format!("connection closed before auth: {frame:?}")); - } - Some(Ok(_)) => continue, - Some(Err(e)) => return Err(format!("ws error: {e}")), - None => return Err("connection closed before auth".into()), - }; - let server: ServerMessage = - serde_json::from_str(&msg).map_err(|e| format!("bad server json: {e}"))?; - apply_server_message(&mut snapshot, &server); - match server { - ServerMessage::SessionHistory { .. } => break, - ServerMessage::Error { message, .. } => { - return Err(message); - } - _ => continue, - } - } - - let (outbound_tx, mut outbound_rx) = mpsc::unbounded_channel::(); - let inner = Arc::new(RwLock::new(Inner { snapshot })); - - let writer_inner = Arc::clone(&inner); - let reader = tokio::spawn(async move { - loop { - tokio::select! { - outbound = outbound_rx.recv() => { - let Some(msg) = outbound else { break; }; - let Ok(text) = serde_json::to_string(&msg) else { continue; }; - if write.send(Message::Text(text.into())).await.is_err() { - let mut guard = writer_inner.write().await; - guard.snapshot.status = JoinStatus::Disconnected; - break; - } - } - incoming = read.next() => { - match incoming { - Some(Ok(Message::Text(t))) => { - if let Ok(server) = serde_json::from_str::(&t) { - let mut guard = writer_inner.write().await; - apply_server_message(&mut guard.snapshot, &server); - if matches!(server, ServerMessage::SessionClosed) { - break; - } - } - } - Some(Ok(Message::Close(_))) | None => { - let mut guard = writer_inner.write().await; - guard.snapshot.status = JoinStatus::Disconnected; - break; - } - Some(Ok(_)) => {} - Some(Err(e)) => { - let mut guard = writer_inner.write().await; - guard.snapshot.status = JoinStatus::Error; - guard.snapshot.last_error = Some(e.to_string()); - break; - } - } - } - } - } - }); - - Ok(Self { - inner, - outbound: outbound_tx, - reader: Some(reader), - }) - } - - pub async fn snapshot(&self) -> SessionSnapshot { - self.inner.read().await.snapshot.clone() - } - - pub fn send_chat(&self, content: &str) -> Result<(), String> { - self.outbound - .send(ClientMessage::ChatSend { - content: content.to_string(), - }) - .map_err(|_| "not connected".to_string()) - } - - pub fn send_prompt(&self, content: &str) -> Result<(), String> { - self.outbound - .send(ClientMessage::CollabInput { - content: content.to_string(), - }) - .map_err(|_| "not connected".to_string()) - } - - pub fn send_typing(&self) -> Result<(), String> { - self.outbound - .send(ClientMessage::Typing) - .map_err(|_| "not connected".to_string()) - } - - pub async fn disconnect(mut self) { - drop(self.outbound); - if let Some(handle) = self.reader.take() { - let _ = tokio::time::timeout(Duration::from_secs(1), handle).await; - } - } -} - -fn normalize_ws_url(host: &str) -> Result { - let trimmed = host.trim().trim_end_matches('/'); - if trimmed.is_empty() { - return Err("host is empty".into()); - } - if trimmed.starts_with("ws://") || trimmed.starts_with("wss://") { - if trimmed.ends_with("/ws") { - return Ok(trimmed.to_string()); - } - return Ok(format!("{trimmed}/ws")); - } - // Bare host:port or host - Ok(format!("ws://{trimmed}/ws")) -} - -fn apply_server_message(snapshot: &mut SessionSnapshot, msg: &ServerMessage) { - match msg { - ServerMessage::SessionHistory { events } => { - snapshot.status = JoinStatus::Connected; - snapshot.recent_events = events.clone(); - if let Some(first) = events.first() { - snapshot.session_id = Some(first.session_id.clone()); - } - snapshot.last_error = None; - } - ServerMessage::SessionEvent { event } => { - if snapshot.session_id.is_none() { - snapshot.session_id = Some(event.session_id.clone()); - } - snapshot.recent_events.push(event.clone()); - if snapshot.recent_events.len() > 50 { - let drain = snapshot.recent_events.len() - 50; - snapshot.recent_events.drain(0..drain); - } - } - ServerMessage::ChatMessage { message } => { - snapshot.recent_chat.push(message.clone()); - if snapshot.recent_chat.len() > 50 { - let drain = snapshot.recent_chat.len() - 50; - snapshot.recent_chat.drain(0..drain); - } - } - ServerMessage::UserList { users } => { - snapshot.users = users.clone(); - } - ServerMessage::UserJoined { user } => { - snapshot.users.push(user.clone()); - } - ServerMessage::UserLeft { user_id } => { - snapshot.users.retain(|u| u.user_id != *user_id); - } - ServerMessage::UserRoleChanged { user_id, role } => { - for u in &mut snapshot.users { - if u.user_id == *user_id { - u.role = role.clone(); - } - } - } - ServerMessage::SessionClosed => { - snapshot.status = JoinStatus::Disconnected; - } - ServerMessage::Error { message, .. } => { - snapshot.status = JoinStatus::Error; - snapshot.last_error = Some(message.clone()); - } - ServerMessage::UserTyping { .. } => {} - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::json; - - #[test] - fn normalize_urls() { - assert_eq!( - normalize_ws_url("127.0.0.1:7742").unwrap(), - "ws://127.0.0.1:7742/ws" - ); - assert_eq!( - normalize_ws_url("ws://127.0.0.1:7742").unwrap(), - "ws://127.0.0.1:7742/ws" - ); - assert_eq!( - normalize_ws_url("ws://127.0.0.1:7742/ws").unwrap(), - "ws://127.0.0.1:7742/ws" - ); - } - - #[test] - fn apply_history_and_chat() { - let mut snap = SessionSnapshot::new("h", "Alice"); - apply_server_message( - &mut snap, - &ServerMessage::SessionHistory { - events: vec![SessionEvent { - id: "e1".into(), - session_id: "sess".into(), - event_type: "message.created".into(), - payload: json!({"text": "hi"}), - timestamp: 1, - }], - }, - ); - assert_eq!(snap.status, JoinStatus::Connected); - assert_eq!(snap.session_id.as_deref(), Some("sess")); - - apply_server_message( - &mut snap, - &ServerMessage::ChatMessage { - message: ChatMessage { - id: "c1".into(), - session_id: "sess".into(), - user_id: "u1".into(), - display_name: Some("Bob".into()), - content: "yo".into(), - timestamp: 2, - }, - }, - ); - assert_eq!(snap.recent_chat.len(), 1); - } - - #[test] - fn client_messages_match_fixtures_shape() { - let auth = serde_json::to_value(ClientMessage::Auth { - token: "abc123".into(), - display_name: Some("Alice".into()), - }) - .unwrap(); - assert_eq!(auth["type"], "auth"); - assert_eq!(auth["token"], "abc123"); - assert_eq!(auth["displayName"], "Alice"); - - let chat = serde_json::to_value(ClientMessage::ChatSend { - content: "hello chat".into(), - }) - .unwrap(); - assert_eq!(chat["type"], "chat.send"); - - let input = serde_json::to_value(ClientMessage::CollabInput { - content: "fix the bug".into(), - }) - .unwrap(); - assert_eq!(input["type"], "collab.input"); - } -} diff --git a/crates/chorus-zed-helper/src/control.rs b/crates/chorus-zed-helper/src/control.rs deleted file mode 100644 index c113e2e..0000000 --- a/crates/chorus-zed-helper/src/control.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! JSON-line control protocol between CLI subcommands and the background daemon. - -use std::path::PathBuf; - -use serde::{Deserialize, Serialize}; - -use crate::client::{JoinStatus, SessionSnapshot}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "cmd", rename_all = "snake_case")] -pub enum ControlRequest { - Ping, - Join { - host: String, - token: String, - #[serde(default = "default_display_name")] - display_name: String, - }, - Leave, - Chat { - content: String, - }, - Prompt { - content: String, - }, - Status, - Shutdown, -} - -fn default_display_name() -> String { - "Zed".to_string() -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ControlResponse { - pub ok: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub snapshot: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, -} - -impl ControlResponse { - pub fn ok_msg(message: impl Into) -> Self { - Self { - ok: true, - error: None, - snapshot: None, - message: Some(message.into()), - } - } - - pub fn ok_status(snapshot: SessionSnapshot) -> Self { - Self { - ok: true, - error: None, - snapshot: Some(snapshot), - message: None, - } - } - - pub fn err(error: impl Into) -> Self { - Self { - ok: false, - error: Some(error.into()), - snapshot: None, - message: None, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct DaemonState { - pub status: Option, - pub host: Option, -} - -pub fn runtime_dir() -> PathBuf { - if let Ok(dir) = std::env::var("CHORUS_ZED_RUNTIME_DIR") { - return PathBuf::from(dir); - } - if let Ok(dir) = std::env::var("XDG_RUNTIME_DIR") { - return PathBuf::from(dir).join("chorus-zed"); - } - std::env::temp_dir().join(format!( - "chorus-zed-{}", - std::env::var("USER").unwrap_or_else(|_| "user".into()) - )) -} - -pub fn socket_path() -> PathBuf { - runtime_dir().join("control.sock") -} - -pub fn pid_path() -> PathBuf { - runtime_dir().join("daemon.pid") -} diff --git a/crates/chorus-zed-helper/src/lib.rs b/crates/chorus-zed-helper/src/lib.rs deleted file mode 100644 index 9fb6048..0000000 --- a/crates/chorus-zed-helper/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Chorus join client used by the Zed helper binary (CLI + MCP). -//! -//! Speaks the joiner `/ws` contract from `crates/chorus-relay` / `protocol/`. - -pub mod client; -pub mod control; -pub mod mcp; - -pub use client::{JoinClient, JoinStatus, SessionSnapshot}; -pub use control::{ControlRequest, ControlResponse, DaemonState}; diff --git a/crates/chorus-zed-helper/src/main.rs b/crates/chorus-zed-helper/src/main.rs deleted file mode 100644 index 92bf394..0000000 --- a/crates/chorus-zed-helper/src/main.rs +++ /dev/null @@ -1,341 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -use std::time::Duration; - -use clap::{Parser, Subcommand}; -use chorus_zed_helper::client::JoinClient; -use chorus_zed_helper::control::{ - pid_path, runtime_dir, socket_path, ControlRequest, ControlResponse, -}; -use chorus_zed_helper::mcp::{self, format_status}; -use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; -use tokio::net::{UnixListener, UnixStream}; -use tokio::sync::Mutex; - -#[derive(Parser, Debug)] -#[command( - name = "chorus-zed-helper", - about = "Chorus join client for Zed (CLI + MCP). Joiner-only — does not host/share." -)] -struct Args { - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand, Debug)] -enum Commands { - /// Start the background daemon that holds the WebSocket session - Daemon, - /// Connect to a Chorus relay as a joiner - Join { - /// Relay host:port (e.g. 192.168.1.10:7742) or ws:// URL - #[arg(long, env = "CHORUS_RELAY_HOST")] - host: String, - /// Join token from the host share command - #[arg(long)] - token: String, - /// Display name shown to collaborators - #[arg(long, default_value = "Zed", env = "CHORUS_DISPLAY_NAME")] - name: String, - }, - /// Disconnect from the current session - Leave, - /// Send a side-channel chat message - Chat { - /// Message text - content: String, - }, - /// Forward a prompt into the host session (`collab.input`) - Prompt { - /// Prompt text - content: String, - }, - /// Print connection status - Status, - /// Run as an MCP stdio server for Zed - Mcp, - /// Shut down the background daemon - Shutdown, -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let args = Args::parse(); - match args.command { - Commands::Daemon => run_daemon().await?, - Commands::Mcp => { - // MCP uses blocking stdin reads; keep a multi-thread runtime handle. - let handle = tokio::runtime::Handle::current(); - tokio::task::spawn_blocking(move || mcp::run_stdio(handle)) - .await - .map_err(|e| e.to_string())??; - } - Commands::Join { host, token, name } => { - ensure_daemon().await?; - let resp = request(ControlRequest::Join { - host, - token, - display_name: name, - }) - .await?; - print_response(&resp); - if !resp.ok { - std::process::exit(1); - } - } - Commands::Leave => { - let resp = request(ControlRequest::Leave).await?; - print_response(&resp); - if !resp.ok { - std::process::exit(1); - } - } - Commands::Chat { content } => { - let resp = request(ControlRequest::Chat { content }).await?; - print_response(&resp); - if !resp.ok { - std::process::exit(1); - } - } - Commands::Prompt { content } => { - let resp = request(ControlRequest::Prompt { content }).await?; - print_response(&resp); - if !resp.ok { - std::process::exit(1); - } - } - Commands::Status => { - match request(ControlRequest::Status).await { - Ok(resp) => { - print_response(&resp); - if !resp.ok { - std::process::exit(1); - } - } - Err(_) => { - println!("status: disconnected\n(daemon not running)"); - } - } - } - Commands::Shutdown => { - match request(ControlRequest::Shutdown).await { - Ok(resp) => print_response(&resp), - Err(_) => println!("daemon not running"), - } - } - } - Ok(()) -} - -fn print_response(resp: &ControlResponse) { - if let Some(snap) = &resp.snapshot { - print!("{}", format_status(snap)); - } else if let Some(msg) = &resp.message { - println!("{msg}"); - } else if let Some(err) = &resp.error { - eprintln!("error: {err}"); - } else if resp.ok { - println!("ok"); - } -} - -async fn ensure_daemon() -> Result<(), String> { - if ping_daemon().await.is_ok() { - return Ok(()); - } - let dir = runtime_dir(); - fs::create_dir_all(&dir).map_err(|e| e.to_string())?; - let sock = socket_path(); - if sock.exists() { - let _ = fs::remove_file(&sock); - } - - let exe = std::env::current_exe().map_err(|e| e.to_string())?; - let child = Command::new(&exe) - .arg("daemon") - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .map_err(|e| format!("failed to spawn daemon: {e}"))?; - - fs::write(pid_path(), child.id().to_string()).map_err(|e| e.to_string())?; - - for _ in 0..50 { - if ping_daemon().await.is_ok() { - return Ok(()); - } - tokio::time::sleep(Duration::from_millis(50)).await; - } - Err("daemon did not become ready".into()) -} - -async fn ping_daemon() -> Result<(), String> { - let resp = request(ControlRequest::Ping).await?; - if resp.ok { - Ok(()) - } else { - Err(resp.error.unwrap_or_else(|| "ping failed".into())) - } -} - -async fn request(req: ControlRequest) -> Result { - let path = socket_path(); - let mut stream = UnixStream::connect(&path) - .await - .map_err(|e| format!("connect control socket: {e}"))?; - let line = serde_json::to_string(&req).map_err(|e| e.to_string())?; - stream - .write_all(line.as_bytes()) - .await - .map_err(|e| e.to_string())?; - stream - .write_all(b"\n") - .await - .map_err(|e| e.to_string())?; - - let mut reader = BufReader::new(stream); - let mut response = String::new(); - reader - .read_line(&mut response) - .await - .map_err(|e| e.to_string())?; - serde_json::from_str(response.trim()).map_err(|e| format!("bad control response: {e}")) -} - -async fn run_daemon() -> Result<(), Box> { - tracing_subscriber::fmt() - .with_env_filter( - tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")), - ) - .with_writer(std::io::stderr) - .init(); - - let dir = runtime_dir(); - fs::create_dir_all(&dir)?; - let sock: PathBuf = socket_path(); - if sock.exists() { - fs::remove_file(&sock)?; - } - - let listener = UnixListener::bind(&sock)?; - let session: Mutex> = Mutex::new(None); - - loop { - let (stream, _) = listener.accept().await?; - let mut reader = BufReader::new(stream); - let mut line = String::new(); - if reader.read_line(&mut line).await? == 0 { - continue; - } - let req: ControlRequest = match serde_json::from_str(line.trim()) { - Ok(r) => r, - Err(e) => { - let mut stream = reader.into_inner(); - let resp = ControlResponse::err(format!("bad request: {e}")); - let body = serde_json::to_string(&resp)?; - stream.write_all(body.as_bytes()).await?; - stream.write_all(b"\n").await?; - continue; - } - }; - - let (resp, shutdown) = handle_control(&session, req).await; - let mut stream = reader.into_inner(); - let body = serde_json::to_string(&resp)?; - stream.write_all(body.as_bytes()).await?; - stream.write_all(b"\n").await?; - if shutdown { - break; - } - } - - let _ = fs::remove_file(sock); - let _ = fs::remove_file(pid_path()); - Ok(()) -} - -async fn handle_control( - session: &Mutex>, - req: ControlRequest, -) -> (ControlResponse, bool) { - match req { - ControlRequest::Ping => (ControlResponse::ok_msg("pong"), false), - ControlRequest::Shutdown => { - let mut guard = session.lock().await; - if let Some(client) = guard.take() { - client.disconnect().await; - } - (ControlResponse::ok_msg("shutting down"), true) - } - ControlRequest::Join { - host, - token, - display_name, - } => match JoinClient::connect(&host, &token, &display_name).await { - Ok(client) => { - let snap = client.snapshot().await; - let mut guard = session.lock().await; - if let Some(old) = guard.take() { - old.disconnect().await; - } - *guard = Some(client); - (ControlResponse::ok_status(snap), false) - } - Err(e) => (ControlResponse::err(e), false), - }, - ControlRequest::Leave => { - let mut guard = session.lock().await; - if let Some(client) = guard.take() { - client.disconnect().await; - (ControlResponse::ok_msg("left session"), false) - } else { - (ControlResponse::ok_msg("not connected"), false) - } - } - ControlRequest::Chat { content } => { - let guard = session.lock().await; - match guard.as_ref() { - Some(client) => match client.send_chat(&content) { - Ok(()) => (ControlResponse::ok_msg("chat sent"), false), - Err(e) => (ControlResponse::err(e), false), - }, - None => (ControlResponse::err("not connected"), false), - } - } - ControlRequest::Prompt { content } => { - let guard = session.lock().await; - match guard.as_ref() { - Some(client) => match client.send_prompt(&content) { - Ok(()) => (ControlResponse::ok_msg("prompt sent"), false), - Err(e) => (ControlResponse::err(e), false), - }, - None => (ControlResponse::err("not connected"), false), - } - } - ControlRequest::Status => { - let guard = session.lock().await; - match guard.as_ref() { - Some(client) => { - let snap = client.snapshot().await; - (ControlResponse::ok_status(snap), false) - } - None => ( - ControlResponse::ok_status(chorus_zed_helper::client::SessionSnapshot { - status: chorus_zed_helper::client::JoinStatus::Disconnected, - host: String::new(), - display_name: String::new(), - session_id: None, - users: vec![], - recent_events: vec![], - recent_chat: vec![], - last_error: None, - }), - false, - ), - } - } - } -} diff --git a/crates/chorus-zed-helper/src/mcp.rs b/crates/chorus-zed-helper/src/mcp.rs deleted file mode 100644 index 9855c04..0000000 --- a/crates/chorus-zed-helper/src/mcp.rs +++ /dev/null @@ -1,300 +0,0 @@ -//! Minimal stdio MCP server exposing Chorus join tools to Zed's Agent Panel. - -use std::io::{BufRead, BufReader, Write}; -use std::sync::Arc; - -use serde_json::{json, Value}; -use tokio::runtime::Handle; -use tokio::sync::Mutex; - -use crate::client::{JoinClient, JoinStatus}; - -struct Session { - client: Option, -} - -/// Run an MCP server on stdin/stdout (blocking; requires a Tokio handle). -pub fn run_stdio(handle: Handle) -> Result<(), String> { - let session = Arc::new(Mutex::new(Session { client: None })); - let stdin = std::io::stdin(); - let mut stdout = std::io::stdout(); - let mut reader = BufReader::new(stdin.lock()); - - loop { - let msg = match read_message(&mut reader)? { - Some(v) => v, - None => break, - }; - - let id = msg.get("id").cloned(); - let method = msg.get("method").and_then(|m| m.as_str()).unwrap_or(""); - let params = msg.get("params").cloned().unwrap_or(json!({})); - - // Notifications (no id) — ignore after handling initialize side-effects if any. - if id.is_none() { - continue; - } - - let result = match method { - "initialize" => Ok(json!({ - "protocolVersion": "2024-11-05", - "capabilities": { "tools": {} }, - "serverInfo": { - "name": "chorus-zed", - "version": env!("CARGO_PKG_VERSION") - } - })), - "tools/list" => Ok(json!({ "tools": tool_defs() })), - "tools/call" => { - let name = params - .get("name") - .and_then(|n| n.as_str()) - .unwrap_or(""); - let args = params - .get("arguments") - .cloned() - .unwrap_or(json!({})); - handle.block_on(call_tool(session.clone(), name, args)) - } - "ping" => Ok(json!({})), - _ => Err(format!("method not found: {method}")), - }; - - let response = match result { - Ok(value) => json!({ - "jsonrpc": "2.0", - "id": id, - "result": value - }), - Err(err) => json!({ - "jsonrpc": "2.0", - "id": id, - "error": { "code": -32000, "message": err } - }), - }; - write_message(&mut stdout, &response)?; - } - Ok(()) -} - -fn tool_defs() -> Vec { - vec![ - json!({ - "name": "chorus_join", - "description": "Join an existing Chorus collaborative session as a joiner (connect to relay /ws).", - "inputSchema": { - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "Relay host:port (e.g. 192.168.1.10:7742) or full ws:// URL" - }, - "token": { "type": "string", "description": "Join token from the host" }, - "display_name": { - "type": "string", - "description": "Display name shown to collaborators (default: Zed)" - } - }, - "required": ["host", "token"] - } - }), - json!({ - "name": "chorus_leave", - "description": "Leave the current Chorus session and disconnect from the relay.", - "inputSchema": { "type": "object", "properties": {} } - }), - json!({ - "name": "chorus_chat", - "description": "Send a side-channel chat message (does not become an LLM prompt).", - "inputSchema": { - "type": "object", - "properties": { - "content": { "type": "string", "description": "Chat message text" } - }, - "required": ["content"] - } - }), - json!({ - "name": "chorus_prompt", - "description": "Send a collaborative prompt (collab.input) into the host OpenCode session. Requires edit role.", - "inputSchema": { - "type": "object", - "properties": { - "content": { "type": "string", "description": "Prompt text for the host session" } - }, - "required": ["content"] - } - }), - json!({ - "name": "chorus_status", - "description": "Show join connection status, users, and recent session/chat events.", - "inputSchema": { "type": "object", "properties": {} } - }), - ] -} - -async fn call_tool( - session: Arc>, - name: &str, - args: Value, -) -> Result { - match name { - "chorus_join" => { - let host = args - .get("host") - .and_then(|v| v.as_str()) - .ok_or("host is required")? - .to_string(); - let token = args - .get("token") - .and_then(|v| v.as_str()) - .ok_or("token is required")? - .to_string(); - let display_name = args - .get("display_name") - .and_then(|v| v.as_str()) - .unwrap_or("Zed") - .to_string(); - - let client = JoinClient::connect(&host, &token, &display_name).await?; - let snap = client.snapshot().await; - let mut guard = session.lock().await; - if let Some(old) = guard.client.take() { - old.disconnect().await; - } - guard.client = Some(client); - Ok(tool_text(format!( - "Joined Chorus session on {} as {} (status={:?}, users={})", - snap.host, - snap.display_name, - snap.status, - snap.users.len() - ))) - } - "chorus_leave" => { - let mut guard = session.lock().await; - if let Some(client) = guard.client.take() { - client.disconnect().await; - Ok(tool_text("Left Chorus session.".into())) - } else { - Ok(tool_text("Not connected.".into())) - } - } - "chorus_chat" => { - let content = args - .get("content") - .and_then(|v| v.as_str()) - .ok_or("content is required")?; - let guard = session.lock().await; - let client = guard.client.as_ref().ok_or("not connected — call chorus_join first")?; - client.send_chat(content)?; - Ok(tool_text(format!("Chat sent: {content}"))) - } - "chorus_prompt" => { - let content = args - .get("content") - .and_then(|v| v.as_str()) - .ok_or("content is required")?; - let guard = session.lock().await; - let client = guard.client.as_ref().ok_or("not connected — call chorus_join first")?; - client.send_prompt(content)?; - Ok(tool_text(format!("Prompt forwarded to host: {content}"))) - } - "chorus_status" => { - let guard = session.lock().await; - match guard.client.as_ref() { - None => Ok(tool_text( - "status: disconnected\n(no active Chorus join)".into(), - )), - Some(client) => { - let snap = client.snapshot().await; - Ok(tool_text(format_status(&snap))) - } - } - } - other => Err(format!("unknown tool: {other}")), - } -} - -fn tool_text(text: String) -> Value { - json!({ - "content": [{ "type": "text", "text": text }], - "isError": false - }) -} - -pub fn format_status(snap: &crate::client::SessionSnapshot) -> String { - let mut out = String::new(); - out.push_str(&format!("status: {:?}\n", snap.status)); - out.push_str(&format!("host: {}\n", snap.host)); - out.push_str(&format!("displayName: {}\n", snap.display_name)); - if let Some(id) = &snap.session_id { - out.push_str(&format!("sessionId: {id}\n")); - } - if let Some(err) = &snap.last_error { - out.push_str(&format!("error: {err}\n")); - } - out.push_str(&format!("users ({})", snap.users.len())); - if snap.users.is_empty() { - out.push('\n'); - } else { - out.push('\n'); - for u in &snap.users { - let name = u.display_name.as_deref().unwrap_or("(anonymous)"); - out.push_str(&format!(" - {} [{}] {:?}\n", name, u.user_id, u.role)); - } - } - out.push_str(&format!( - "recentEvents: {} | recentChat: {}\n", - snap.recent_events.len(), - snap.recent_chat.len() - )); - if snap.status == JoinStatus::Connected { - for chat in snap.recent_chat.iter().rev().take(5).collect::>().into_iter().rev() - { - let name = chat.display_name.as_deref().unwrap_or(&chat.user_id); - out.push_str(&format!(" chat <{name}> {}\n", chat.content)); - } - } - out -} - -fn read_message(reader: &mut R) -> Result, String> { - let mut headers = String::new(); - loop { - let mut line = String::new(); - let n = reader - .read_line(&mut line) - .map_err(|e| format!("stdin read: {e}"))?; - if n == 0 { - return Ok(None); - } - if line == "\r\n" || line == "\n" { - break; - } - headers.push_str(&line); - } - - let mut content_length: Option = None; - for header in headers.lines() { - let lower = header.to_ascii_lowercase(); - if let Some(rest) = lower.strip_prefix("content-length:") { - content_length = rest.trim().parse().ok(); - } - } - let len = content_length.ok_or("missing Content-Length")?; - let mut buf = vec![0u8; len]; - reader - .read_exact(&mut buf) - .map_err(|e| format!("body read: {e}"))?; - let value = serde_json::from_slice(&buf).map_err(|e| format!("json: {e}"))?; - Ok(Some(value)) -} - -fn write_message(writer: &mut W, value: &Value) -> Result<(), String> { - let body = serde_json::to_vec(value).map_err(|e| e.to_string())?; - write!(writer, "Content-Length: {}\r\n\r\n", body.len()).map_err(|e| e.to_string())?; - writer.write_all(&body).map_err(|e| e.to_string())?; - writer.flush().map_err(|e| e.to_string())?; - Ok(()) -} diff --git a/crates/chorus-zed-helper/tests/join_client.rs b/crates/chorus-zed-helper/tests/join_client.rs deleted file mode 100644 index bebe9a5..0000000 --- a/crates/chorus-zed-helper/tests/join_client.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! Integration: JoinClient against a live chorus-relay (auth, chat, collab.input). - -use std::time::Duration; - -use chorus_relay::protocol::{HostToRelay, RelayToHost, UserRole}; -use chorus_relay::server::{serve, RelayConfig}; -use chorus_zed_helper::client::{JoinClient, JoinStatus}; -use futures_util::{SinkExt, StreamExt}; -use tokio_tungstenite::{connect_async, tungstenite::Message}; - -type WsStream = - tokio_tungstenite::WebSocketStream>; - -async fn start_relay(port: u16, host_token: &str) { - let token = host_token.to_string(); - tokio::spawn(async move { - serve(RelayConfig { - port, - host_token: token, - bind: "127.0.0.1".into(), - }) - .await - .expect("relay failed"); - }); - for _ in 0..50 { - if tokio::net::TcpStream::connect(("127.0.0.1", port)) - .await - .is_ok() - { - return; - } - tokio::time::sleep(Duration::from_millis(20)).await; - } - panic!("relay not ready on {port}"); -} - -async fn connect_host(port: u16, host_token: &str) -> WsStream { - let (mut ws, _) = connect_async(format!("ws://127.0.0.1:{port}/host")) - .await - .expect("host connect"); - ws.send(Message::Text( - serde_json::to_string(&HostToRelay::HostAuth { - token: host_token.into(), - }) - .unwrap() - .into(), - )) - .await - .unwrap(); - let msg = recv_json::(&mut ws).await; - assert!(matches!(msg, RelayToHost::HostReady { .. })); - let _ = tokio::time::timeout(Duration::from_millis(100), ws.next()).await; - ws -} - -async fn recv_json(ws: &mut WsStream) -> T { - loop { - let msg = ws.next().await.expect("ended").expect("ws"); - match msg { - Message::Text(t) => return serde_json::from_str(&t).expect("json"), - Message::Close(frame) => panic!("close: {frame:?}"), - _ => continue, - } - } -} - -async fn issue_token(host: &mut WsStream) -> String { - host.send(Message::Text( - serde_json::to_string(&HostToRelay::TokenIssue { - session_id: "sess-zed".into(), - role: Some(UserRole::Edit), - ttl_ms: None, - }) - .unwrap() - .into(), - )) - .await - .unwrap(); - loop { - let msg = recv_json::(host).await; - if let RelayToHost::TokenIssued { token } = msg { - return token.token; - } - } -} - -#[tokio::test] -async fn join_client_auth_chat_and_prompt() { - let port = 17942; - let host_token = "zed-helper-test-token"; - start_relay(port, host_token).await; - let mut host = connect_host(port, host_token).await; - let token = issue_token(&mut host).await; - - let client = JoinClient::connect(&format!("127.0.0.1:{port}"), &token, "ZedTester") - .await - .expect("join"); - let snap = client.snapshot().await; - assert_eq!(snap.status, JoinStatus::Connected); - - client.send_chat("hello from zed helper").unwrap(); - // Host should receive chat.message - let mut saw_chat = false; - for _ in 0..20 { - let msg = recv_json::(&mut host).await; - if let RelayToHost::ChatMessage { message } = msg { - assert_eq!(message.content, "hello from zed helper"); - saw_chat = true; - break; - } - } - assert!(saw_chat, "host did not receive chat"); - - client.send_prompt("fix the bug").unwrap(); - let mut saw_prompt = false; - for _ in 0..20 { - let msg = recv_json::(&mut host).await; - if let RelayToHost::CollabInput { content, .. } = msg { - assert_eq!(content, "fix the bug"); - saw_prompt = true; - break; - } - } - assert!(saw_prompt, "host did not receive collab.input"); - - client.disconnect().await; -} diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index d46f91c..e292275 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -49,7 +49,7 @@ Recommended shape: - **v1:** OpenCode adapter = this repo’s plugin + local **Rust** `chorus-relay` - **v1.x:** keep `@chorus/shared` as the stable joiner + host-control contract; `@chorus/client` holds `JoinClient` / `RelayServer` for non-OpenCode hosts -- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) and Zed (`packages/zed` + `crates/chorus-zed-helper`) — same wire protocol, host-specific UI only. Zed v1 is joiner/MCP-only (no host share). +- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) — same wire protocol, host-specific UI only. - **v2:** optional further adapters (Codex app-server remains a strong candidate) once OpenCode UX is solid; split adapter packages into separate repos only when publish/CI ownership diverges **Do not** make Claude Code / Amp the primary host — large audiences, but proprietary control planes. Treat them as distribution adapters later, not the core. diff --git a/docs/STATUS.md b/docs/STATUS.md index b26d080..f4bd433 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -14,7 +14,7 @@ Chorus is an **OpenCode↔OpenCode** LAN collaboration stack: The browser companion (`packages/web`) was intentionally removed. Joiners now mirror the host transcript into their OpenCode session (`[Host]:` / `[AI]:` lines via `noReply` inject); side-channel chat/typing remain toasts. The in-process Bun relay has been replaced by `crates/chorus-relay`. -**Editor adapters (in progress):** VS Code (`packages/vscode`) and Zed (`packages/zed` + `crates/chorus-zed-helper`). Zed v1 is **joiner-only** via MCP/CLI — no host share and no OpenCode transcript injection. +**Editor adapters (in progress):** VS Code (`packages/vscode`). Differentiation vs nearby OpenCode plugins (`opencode-live`, `opencode-sessions`, `opencode-ensemble`, `opencode-relay`): those target **multi-agent / same-DB sync**. Chorus targets **multi-human** pair programming on one live AI session. @@ -81,7 +81,6 @@ Enterprise gap analysis (what would actually pass a security review vs what ship - **OpenCode** (`packages/plugin`) — primary host; full LLM loop + transcript mirror. - **VS Code** (`packages/vscode`) — share/join via `@chorus/client`; sidebar transcript; joiner `collab.input` works against an OpenCode host. VS Code share does **not** drive OpenCode’s model — publish host lines manually or pair with OpenCode. -- **Zed** — joiner-first scaffold when present under `packages/zed` / related crates (WASM extension limits; helper binary pattern). ## Explicit non-goals (for now) diff --git a/packages/plugin/dist/join/index.d.ts b/packages/plugin/dist/join/index.d.ts index 7daf458..030eff9 100644 --- a/packages/plugin/dist/join/index.d.ts +++ b/packages/plugin/dist/join/index.d.ts @@ -1,37 +1 @@ -import type { SessionEvent, ConnectedUser } from "@chorus/shared"; -export type JoinStatus = "connecting" | "pending" | "connected" | "disconnected" | "error"; -export interface JoinState { - status: JoinStatus; - sessionId: string; - userId?: string; - users: ConnectedUser[]; - recentEvents: SessionEvent[]; - error?: string; -} -export declare class JoinClient { - private readonly relayUrl; - private readonly token; - private readonly displayName; - private readonly repoRemote?; - private readonly email?; - private ws; - private state; - private onEvent?; - private onChatMessage?; - private onTyping?; - private onPending?; - private onApproved?; - constructor(relayUrl: string, token: string, displayName: string, repoRemote?: string | undefined, email?: string | undefined); - connect(): Promise; - sendInput(content: string): void; - sendChat(content: string): void; - setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; - setTypingHandler(fn: (displayName: string | undefined) => void): void; - setEventHandler(fn: (event: SessionEvent) => void): void; - setPendingHandler(fn: (userId: string) => void): void; - setApprovedHandler(fn: () => void): void; - sendTyping(): void; - getState(): Readonly; - disconnect(): void; -} -//# sourceMappingURL=index.d.ts.map \ No newline at end of file +export { JoinClient, type JoinState, type JoinStatus } from "@chorus/client"; diff --git a/packages/plugin/dist/join/index.js b/packages/plugin/dist/join/index.js index a8722b1..94cb25f 100644 --- a/packages/plugin/dist/join/index.js +++ b/packages/plugin/dist/join/index.js @@ -1,172 +1 @@ -import { encodeMessage, decodeServerMessage, } from "@chorus/shared"; -export class JoinClient { - relayUrl; - token; - displayName; - repoRemote; - email; - ws = null; - state; - onEvent; - onChatMessage; - onTyping; - onPending; - onApproved; - constructor(relayUrl, token, displayName, repoRemote, email) { - this.relayUrl = relayUrl; - this.token = token; - this.displayName = displayName; - this.repoRemote = repoRemote; - this.email = email; - this.state = { - status: "connecting", - sessionId: "", - users: [], - recentEvents: [], - }; - } - connect() { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.relayUrl); - this.ws = ws; - let settled = false; - const succeed = () => { - if (settled) - return; - settled = true; - resolve(); - }; - const fail = (err) => { - if (settled) - return; - settled = true; - reject(err); - }; - ws.onopen = () => { - const auth = { - type: "auth", - token: this.token, - displayName: this.displayName, - }; - if (this.repoRemote) - auth.repoRemote = this.repoRemote; - if (this.email) - auth.email = this.email; - ws.send(encodeMessage(auth)); - }; - ws.onmessage = (ev) => { - let msg; - try { - msg = decodeServerMessage(ev.data); - } - catch { - return; - } - switch (msg.type) { - case "auth.pending": - this.state.status = "pending"; - this.state.userId = msg.userId; - this.onPending?.(msg.userId); - succeed(); - break; - case "auth.denied": - this.state.status = "error"; - this.state.error = msg.message; - fail(new Error(msg.message)); - ws.close(); - break; - case "session.history": - this.state.recentEvents = msg.events.slice(-50); - this.state.status = "connected"; - this.onApproved?.(); - succeed(); - break; - case "session.event": - this.state.recentEvents = [...this.state.recentEvents.slice(-49), msg.event]; - this.onEvent?.(msg.event); - break; - case "user.list": - this.state.users = msg.users; - break; - case "user.joined": - this.state.users = [...this.state.users, msg.user]; - break; - case "user.left": - this.state.users = this.state.users.filter((u) => u.userId !== msg.userId); - break; - case "user.role_changed": - this.state.users = this.state.users.map((u) => u.userId === msg.userId ? { ...u, role: msg.role } : u); - break; - case "chat.message": - this.onChatMessage?.(msg.message.displayName, msg.message.content); - break; - case "user.typing": - this.onTyping?.(msg.displayName); - break; - case "session.closed": - this.state.status = "disconnected"; - ws.close(); - break; - case "error": { - const wasAdmitted = this.state.status === "connected" || this.state.status === "pending"; - this.state.status = "error"; - this.state.error = msg.message; - if (!wasAdmitted) { - fail(new Error(msg.message)); - } - break; - } - } - }; - ws.onerror = () => { - this.state.status = "error"; - this.state.error = "Connection error"; - fail(new Error("WebSocket connection error")); - }; - ws.onclose = () => { - if (this.state.status === "connected" || this.state.status === "pending") { - this.state.status = "disconnected"; - } - }; - }); - } - sendInput(content) { - if (!this.ws || this.state.status !== "connected") - return; - this.ws.send(encodeMessage({ type: "collab.input", content })); - } - sendChat(content) { - if (!this.ws || this.state.status !== "connected") - return; - this.ws.send(encodeMessage({ type: "chat.send", content })); - } - setChatHandler(fn) { - this.onChatMessage = fn; - } - setTypingHandler(fn) { - this.onTyping = fn; - } - setEventHandler(fn) { - this.onEvent = fn; - } - setPendingHandler(fn) { - this.onPending = fn; - } - setApprovedHandler(fn) { - this.onApproved = fn; - } - sendTyping() { - if (!this.ws || this.state.status !== "connected") - return; - this.ws.send(encodeMessage({ type: "typing" })); - } - getState() { - return this.state; - } - disconnect() { - this.ws?.close(); - this.ws = null; - this.state.status = "disconnected"; - } -} -//# sourceMappingURL=index.js.map \ No newline at end of file +export { JoinClient } from "@chorus/client"; diff --git a/packages/plugin/dist/relay/index.d.ts b/packages/plugin/dist/relay/index.d.ts index 1710d37..9be2ec4 100644 --- a/packages/plugin/dist/relay/index.d.ts +++ b/packages/plugin/dist/relay/index.d.ts @@ -1,113 +1,6 @@ -import type { ConnectedUser, SessionEvent, SessionToken, UserRole } from "@chorus/shared"; -export type RelayServerOptions = { - /** Host running the relay (default 127.0.0.1). */ - host?: string; - /** When set with external mode, attach instead of spawning. */ - hostToken?: string; - /** - * Attach to an already-running relay (e.g. on the Docker host). - * When true, requires hostToken and does not spawn/kill a subprocess. - */ - external?: boolean; - /** Bind address passed to chorus-relay (default 0.0.0.0). */ - bind?: string; - /** CIDR/IP allowlist for TCP peers. */ - allowedCidrs?: string[]; - /** Explicit deny CIDRs (deny wins). */ - deniedCidrs?: string[]; - /** Peer source-port allowlist (single-machine e2e). */ - allowedPorts?: number[]; - /** Refuse 0.0.0.0 / :: bind when false. */ - allowOpenBind?: boolean; - /** Admit loopback IPs even when allowlist is set (default true). */ - allowLoopback?: boolean; -}; -export type RelayNetworkOptions = { - bind?: string; - allowedCidrs?: string[]; - deniedCidrs?: string[]; - allowedPorts?: number[]; - allowOpenBind?: boolean; - allowLoopback?: boolean; -}; -/** - * Resolve relay connection settings from env. - * - * External attach (relay already running elsewhere): - * CHORUS_RELAY_HOST=host.docker.internal:7742 - * CHORUS_HOST_TOKEN= - * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) - */ -export declare function relayOptionsFromEnv(defaultPort: number): { - port: number; - opts: RelayServerOptions; -}; -/** - * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. - * Joiner-facing protocol on `/ws` is unchanged; the plugin talks to `/host`. - */ -export declare class RelayServer { - private readonly port; - private child; - private ws; - private hostToken; - private running; - private clients; - private readonly host; - private readonly external; - private bind; - private allowedCidrs; - private deniedCidrs; - private allowedPorts; - private allowOpenBind; - private allowLoopback; - private pendingToken; - private onInjectInput?; - private onChatMessage?; - private onTyping?; - private onUserPending?; - private onUserJoined?; - private onUserLeft?; - constructor(port: number, opts?: RelayServerOptions); - /** Apply network policy before start() (from project/org chorus.json). */ - setNetworkOptions(opts: RelayNetworkOptions): void; - setInputHandler(fn: (content: string, userId: string, displayName?: string) => Promise): void; - setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; - setTypingHandler(fn: (displayName: string | undefined) => void): void; - setUserPendingHandler(fn: (user: ConnectedUser) => void): void; - setUserJoinedHandler(fn: (user: ConnectedUser) => void): void; - setUserLeftHandler(fn: (userId: string) => void): void; - start(): Promise; - private statusUrl; - private hostWsUrl; - private waitForPort; - private connectHost; - private handleHostMessage; - private send; - issueToken(sessionId: string, role?: UserRole, ttlMs?: number): Promise; - setSessionPolicy(opts: { - requireApproval?: boolean; - repoRemote?: string | null; - allowedEmailDomain?: string | null; - additionalRepoRemotePrefixes?: string[] | null; - repoRemoteRewrites?: { - from: string; - to: string; - }[] | null; - }): void; - approveUser(userId: string): void; - denyUser(userId: string): void; - kickUser(userId: string): void; - pushEvent(event: SessionEvent): void; - sendChat(displayName: string | undefined, content: string): void; - stop(): Promise; - private waitUntilStopped; - get isRunning(): boolean; - get clientCount(): number; - getPort(): number; - getHost(): string; - getBind(): string; - getAllowedCidrs(): string[]; - isExternal(): boolean; -} -//# sourceMappingURL=index.d.ts.map \ No newline at end of file +export { + RelayServer, + relayOptionsFromEnv, + type RelayServerOptions, + type RelayNetworkOptions, +} from "@chorus/client"; diff --git a/packages/plugin/dist/relay/index.js b/packages/plugin/dist/relay/index.js index 5c31c8a..42a1f63 100644 --- a/packages/plugin/dist/relay/index.js +++ b/packages/plugin/dist/relay/index.js @@ -1,397 +1 @@ -import { spawn } from "node:child_process"; -import { existsSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { randomBytes } from "node:crypto"; -import { encodeHostMessage, decodeRelayToHost, } from "@chorus/shared"; -function resolveRelayBin() { - if (process.env["CHORUS_RELAY_BIN"]) - return process.env["CHORUS_RELAY_BIN"]; - const here = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - join(here, "../../../../target/release/chorus-relay"), - join(here, "../../../../target/debug/chorus-relay"), - join(here, "../../../../../target/release/chorus-relay"), - join(here, "../../../../../target/debug/chorus-relay"), - ]; - for (const path of candidates) { - if (existsSync(path)) - return path; - } - return "chorus-relay"; -} -function parseRelayHost(raw, fallbackPort) { - if (!raw) - return { host: "127.0.0.1", port: fallbackPort }; - // Accept host, host:port, or ws(s)://host:port[/path] - const trimmed = raw.replace(/^wss?:\/\//, "").replace(/\/.*$/, ""); - const [hostPart, portPart] = trimmed.split(":"); - const port = portPart ? parseInt(portPart, 10) : fallbackPort; - return { host: hostPart || "127.0.0.1", port: Number.isFinite(port) ? port : fallbackPort }; -} -/** - * Resolve relay connection settings from env. - * - * External attach (relay already running elsewhere): - * CHORUS_RELAY_HOST=host.docker.internal:7742 - * CHORUS_HOST_TOKEN= - * CHORUS_EXTERNAL_RELAY=1 (optional; implied when HOST_TOKEN is set) - */ -export function relayOptionsFromEnv(defaultPort) { - const parsed = parseRelayHost(process.env["CHORUS_RELAY_HOST"], defaultPort); - const hostToken = process.env["CHORUS_HOST_TOKEN"]; - const external = process.env["CHORUS_EXTERNAL_RELAY"] === "1" || - process.env["CHORUS_EXTERNAL_RELAY"] === "true" || - Boolean(hostToken && process.env["CHORUS_RELAY_HOST"]); - return { - port: parsed.port, - opts: { - host: parsed.host, - hostToken: hostToken || undefined, - external, - }, - }; -} -/** - * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. - * Joiner-facing protocol on `/ws` is unchanged; the plugin talks to `/host`. - */ -export class RelayServer { - port; - child = null; - ws = null; - hostToken = ""; - running = false; - clients = 0; - host; - external; - bind; - allowedCidrs; - deniedCidrs; - allowedPorts; - allowOpenBind; - allowLoopback; - pendingToken = null; - onInjectInput; - onChatMessage; - onTyping; - onUserPending; - onUserJoined; - onUserLeft; - constructor(port, opts = {}) { - this.port = port; - this.host = opts.host ?? "127.0.0.1"; - this.external = Boolean(opts.external); - this.hostToken = opts.hostToken ?? ""; - this.bind = opts.bind ?? "0.0.0.0"; - this.allowedCidrs = opts.allowedCidrs ? [...opts.allowedCidrs] : []; - this.deniedCidrs = opts.deniedCidrs ? [...opts.deniedCidrs] : []; - this.allowedPorts = opts.allowedPorts ? [...opts.allowedPorts] : []; - this.allowOpenBind = opts.allowOpenBind ?? true; - this.allowLoopback = opts.allowLoopback ?? true; - } - /** Apply network policy before start() (from project/org chorus.json). */ - setNetworkOptions(opts) { - if (opts.bind !== undefined) - this.bind = opts.bind; - if (opts.allowedCidrs !== undefined) - this.allowedCidrs = [...opts.allowedCidrs]; - if (opts.deniedCidrs !== undefined) - this.deniedCidrs = [...opts.deniedCidrs]; - if (opts.allowedPorts !== undefined) - this.allowedPorts = [...opts.allowedPorts]; - if (opts.allowOpenBind !== undefined) - this.allowOpenBind = opts.allowOpenBind; - if (opts.allowLoopback !== undefined) - this.allowLoopback = opts.allowLoopback; - } - setInputHandler(fn) { - this.onInjectInput = fn; - } - setChatHandler(fn) { - this.onChatMessage = fn; - } - setTypingHandler(fn) { - this.onTyping = fn; - } - setUserPendingHandler(fn) { - this.onUserPending = fn; - } - setUserJoinedHandler(fn) { - this.onUserJoined = fn; - } - setUserLeftHandler(fn) { - this.onUserLeft = fn; - } - async start() { - if (this.running) - return; - if (this.external) { - if (!this.hostToken) { - throw new Error("External relay mode requires CHORUS_HOST_TOKEN (and usually CHORUS_RELAY_HOST)."); - } - await this.waitForPort(); - await this.connectHost(); - this.running = true; - return; - } - this.hostToken = this.hostToken || randomBytes(32).toString("hex"); - const bin = resolveRelayBin(); - const args = [ - "--port", - String(this.port), - "--bind", - this.bind, - "--host-token", - this.hostToken, - "--allow-open-bind", - this.allowOpenBind ? "true" : "false", - "--allow-loopback", - this.allowLoopback ? "true" : "false", - ]; - for (const cidr of this.allowedCidrs) { - args.push("--allow-cidr", cidr); - } - for (const cidr of this.deniedCidrs) { - args.push("--deny-cidr", cidr); - } - for (const port of this.allowedPorts) { - args.push("--allow-port", String(port)); - } - this.child = spawn(bin, args, { - stdio: ["ignore", "ignore", "pipe"], - env: { ...process.env }, - }); - this.child.on("exit", () => { - this.running = false; - this.ws = null; - }); - await this.waitForPort(); - await this.connectHost(); - this.running = true; - } - statusUrl() { - return `http://${this.host}:${this.port}/status`; - } - hostWsUrl() { - return `ws://${this.host}:${this.port}/host`; - } - async waitForPort(timeoutMs = 8000) { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - try { - const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(1000) }); - if (res.ok) - return; - } - catch { - // not up yet - } - await new Promise((r) => setTimeout(r, 40)); - } - throw new Error(this.external - ? `External chorus-relay not reachable at ${this.host}:${this.port}. Is it running on the host?` - : `chorus-relay did not become ready on port ${this.port}. ` + - `Is the binary available? (CHORUS_RELAY_BIN or cargo build -p chorus-relay --release)`); - } - connectHost() { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.hostWsUrl()); - this.ws = ws; - const timer = setTimeout(() => reject(new Error("host control connect timeout")), 5000); - ws.onopen = () => { - this.send({ type: "host.auth", token: this.hostToken }); - }; - ws.onmessage = (ev) => { - let msg; - try { - msg = decodeRelayToHost(String(ev.data)); - } - catch { - return; - } - this.handleHostMessage(msg, () => { - clearTimeout(timer); - resolve(); - }); - }; - ws.onerror = () => { - clearTimeout(timer); - reject(new Error("host control WebSocket error")); - }; - ws.onclose = () => { - this.ws = null; - this.running = false; - }; - }); - } - handleHostMessage(msg, onReady) { - switch (msg.type) { - case "host.ready": - onReady?.(); - break; - case "token.issued": { - const { type: _t, ...token } = msg; - this.pendingToken?.resolve(token); - this.pendingToken = null; - break; - } - case "collab.input": - this.onInjectInput?.(msg.content, msg.userId, msg.displayName)?.catch(console.error); - break; - case "chat.message": - this.onChatMessage?.(msg.message.displayName, msg.message.content); - break; - case "user.typing": - this.onTyping?.(msg.displayName); - break; - case "user.pending": - this.onUserPending?.(msg.user); - break; - case "user.joined": - this.clients += 1; - this.onUserJoined?.(msg.user); - break; - case "user.left": - this.clients = Math.max(0, this.clients - 1); - this.onUserLeft?.(msg.userId); - break; - case "user.list": - this.clients = msg.users.filter((u) => u.status === "active").length; - break; - case "status": - this.clients = msg.clients; - break; - case "error": - this.pendingToken?.reject(new Error(msg.message)); - this.pendingToken = null; - break; - } - } - send(msg) { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) - return; - this.ws.send(encodeHostMessage(msg)); - } - issueToken(sessionId, role = "edit", ttlMs) { - return new Promise((resolve, reject) => { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { - reject(new Error("relay host control not connected")); - return; - } - this.pendingToken = { resolve, reject }; - this.send({ type: "token.issue", sessionId, role, ttlMs }); - setTimeout(() => { - if (this.pendingToken) { - this.pendingToken.reject(new Error("token.issue timed out")); - this.pendingToken = null; - } - }, 5000); - }); - } - setSessionPolicy(opts) { - this.send({ - type: "session.policy", - requireApproval: opts.requireApproval, - repoRemote: opts.repoRemote === null ? "" : opts.repoRemote, - allowedEmailDomain: opts.allowedEmailDomain === null ? "" : opts.allowedEmailDomain, - additionalRepoRemotePrefixes: opts.additionalRepoRemotePrefixes ?? undefined, - repoRemoteRewrites: opts.repoRemoteRewrites ?? undefined, - }); - } - approveUser(userId) { - this.send({ type: "host.approve", userId }); - } - denyUser(userId) { - this.send({ type: "host.deny", userId }); - } - kickUser(userId) { - this.send({ type: "host.kick", userId }); - } - pushEvent(event) { - this.send({ type: "session.event", event }); - } - sendChat(displayName, content) { - this.send({ type: "chat.send", content, displayName }); - } - async stop() { - // Only tear down session state on relays we own. External relays stay up - // so container agents can reconnect across test runs. - if (!this.external) { - this.send({ type: "host.close" }); - } - try { - this.ws?.close(); - } - catch { - // ignore - } - this.ws = null; - const child = this.child; - this.child = null; - this.running = false; - this.clients = 0; - if (child && child.exitCode === null && child.signalCode === null) { - await new Promise((resolve) => { - const finish = () => resolve(); - child.once("exit", finish); - try { - child.kill("SIGTERM"); - } - catch { - finish(); - return; - } - setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) { - try { - child.kill("SIGKILL"); - } - catch { - finish(); - } - } - }, 1000).unref?.(); - }); - } - if (!this.external) { - await this.waitUntilStopped(); - } - } - async waitUntilStopped(timeoutMs = 2000) { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - try { - const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(250) }); - if (!res.ok) - return; - } - catch { - return; - } - await new Promise((r) => setTimeout(r, 20)); - } - } - get isRunning() { - return this.running; - } - get clientCount() { - return this.clients; - } - getPort() { - return this.port; - } - getHost() { - return this.host; - } - getBind() { - return this.bind; - } - getAllowedCidrs() { - return [...this.allowedCidrs]; - } - isExternal() { - return this.external; - } -} -//# sourceMappingURL=index.js.map \ No newline at end of file +export { RelayServer, relayOptionsFromEnv } from "@chorus/client"; diff --git a/packages/zed/Cargo.lock b/packages/zed/Cargo.lock deleted file mode 100644 index 7aec8ee..0000000 --- a/packages/zed/Cargo.lock +++ /dev/null @@ -1,829 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "auditable-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" -dependencies = [ - "semver", - "serde", - "serde_json", - "topological-sort", -] - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chorus-zed" -version = "0.1.0" -dependencies = [ - "zed_extension_api", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "displaydoc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" - -[[package]] -name = "futures-executor" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" - -[[package]] -name = "futures-macro" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "futures-sink" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" - -[[package]] -name = "futures-task" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" - -[[package]] -name = "futures-util" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "icu_collections" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" - -[[package]] -name = "icu_properties" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" - -[[package]] -name = "icu_provider" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.1", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "litemap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" - -[[package]] -name = "log" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "potential_utf" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" -dependencies = [ - "zerovec", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "serde_json" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "simd-adler32" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" - -[[package]] -name = "spdx" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3" -dependencies = [ - "smallvec", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tinystr" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "topological-sort" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "wasm-encoder" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" -dependencies = [ - "anyhow", - "auditable-serde", - "flate2", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "url", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10fb6648689b3929d56bbc7eb1acf70c9a42a29eb5358c67c10f54dbd5d695de" -dependencies = [ - "wit-bindgen-rt", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92fa781d4f2ff6d3f27f3cc9b74a73327b31ca0dc4a3ef25a0ce2983e0e5af9b" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" -dependencies = [ - "bitflags", - "futures", - "once_cell", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0809dc5ba19e2e98661bf32fc0addc5a3ca5bf3a6a7083aa6ba484085ff3ce" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad19eec017904e04c60719592a803ee5da76cb51c81e3f6fbf9457f59db49799" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" - -[[package]] -name = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zed_extension_api" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0729d50b4ca0a7e28e590bbe32e3ca0194d97ef654961451a424c661a366fca0" -dependencies = [ - "serde", - "serde_json", - "wit-bindgen", -] - -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47402523226a02bfe5230160dc3ccc089aa6f6f19e7fcbb4e6f824bbb1b4aa62" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - -[[package]] -name = "zmij" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/packages/zed/Cargo.toml b/packages/zed/Cargo.toml deleted file mode 100644 index 4db7fa4..0000000 --- a/packages/zed/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "chorus-zed" -version = "0.1.0" -edition = "2021" -license = "MIT" -publish = false -description = "Zed extension that launches the Chorus join helper as an MCP context server" - -# Standalone from the monorepo Cargo workspace (wasm32-wasip2 via Zed). -[workspace] - -[lib] -crate-type = ["cdylib"] -path = "src/lib.rs" - -[dependencies] -zed_extension_api = "0.7.0" diff --git a/packages/zed/README.md b/packages/zed/README.md deleted file mode 100644 index 09f12f3..0000000 --- a/packages/zed/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# Chorus Zed extension (v1 — joiner) - -Join an existing Chorus collaborative session from [Zed](https://zed.dev) via a **native helper** + **MCP context server**. - -Zed extensions run as `wasm32-wasip2` and cannot hold long-lived WebSocket UIs themselves. This package is the thin WASM adapter; `crates/chorus-zed-helper` speaks the Chorus `/ws` protocol. - -## What works (v1) - -| Capability | How | -|---|---| -| Join a host’s relay | MCP tool `chorus_join` or CLI `chorus-zed-helper join` | -| Leave | `chorus_leave` / `leave` | -| Side-channel chat | `chorus_chat` / `chat` | -| Forward prompts (`collab.input`) | `chorus_prompt` / `prompt` (needs `edit` role) | -| Status / recent events | `chorus_status` / `status` | - -## What does **not** work (honest limits) - -- **Host share / stop** — Zed cannot inject into an OpenCode agent session. Hosting still requires the OpenCode plugin (`/chorus-share`). -- **OpenCode transcript mirroring** — session events are visible via `chorus_status` / helper state, not injected into a local agent transcript. -- **Extension slash commands** — Zed removed extension slash commands; use MCP tools (or the CLI). Tool names mirror OpenCode’s `/chorus-join`, `/chorus-leave`, `/chorus-chat`, `/chorus-status`. - -## Architecture - -``` -Zed Agent Panel - └─ MCP (stdio) ──► chorus-zed-helper mcp - └─ WebSocket ──► chorus-relay /ws - └─ host OpenCode plugin -``` - -CLI subcommands talk to a short-lived background daemon over a Unix socket so `join` / `chat` / `status` share one connection. - -## Install the native helper - -From the monorepo root: - -```sh -cargo build -p chorus-zed-helper --release -# put it on PATH, e.g.: -cp target/release/chorus-zed-helper ~/.local/bin/ -``` - -Or: - -```sh -cargo install --path crates/chorus-zed-helper -``` - -Verify: - -```sh -chorus-zed-helper --help -``` - -## Install Dev Extension in Zed - -1. Build/install `chorus-zed-helper` on `PATH` (above). -2. Install the `wasm32-wasip2` target if needed: `rustup target add wasm32-wasip2`. -3. In Zed: command palette → **zed: extensions**. -4. Click **Install Dev Extension**. -5. Select this directory: `packages/zed` (the folder that contains `extension.toml`). -6. Enable the **Chorus** context server in Agent / MCP settings if it is not auto-enabled. -7. Confirm tools `chorus_join`, `chorus_leave`, `chorus_chat`, `chorus_prompt`, `chorus_status` appear. - -If the context server fails to start, Zed cannot find `chorus-zed-helper`. Fix `PATH`, or register a manual context server in `settings.json`: - -```json -{ - "context_servers": { - "chorus": { - "command": "/absolute/path/to/chorus-zed-helper", - "args": ["mcp"] - } - } -} -``` - -## CLI usage (without Zed) - -```sh -# Host must already be sharing via OpenCode /chorus-share -chorus-zed-helper join --host 192.168.1.10:7742 --token --name Alex -chorus-zed-helper status -chorus-zed-helper chat "hey — looking at the failing test" -chorus-zed-helper prompt "fix the flaky auth test" -chorus-zed-helper leave -``` - -## Develop / test - -```sh -# Helper unit + integration tests (spins up chorus-relay) -cargo test -p chorus-zed-helper - -# Extension WASM (optional local check; Zed also builds on Install Dev Extension) -cd packages/zed -rustup target add wasm32-wasip2 -cargo build --target wasm32-wasip2 -``` - -Protocol fixtures live in `/protocol`; Rust types are shared via `chorus-relay::protocol`. diff --git a/packages/zed/extension.toml b/packages/zed/extension.toml deleted file mode 100644 index 4340768..0000000 --- a/packages/zed/extension.toml +++ /dev/null @@ -1,11 +0,0 @@ -id = "chorus" -name = "Chorus" -description = "Join Chorus collaborative AI sessions from Zed (joiner via native helper + MCP)" -version = "0.1.0" -schema_version = 1 -authors = ["Steven Roomberg"] -repository = "https://github.com/sroomberg/chorus" - -[context_servers.chorus] -name = "Chorus" -description = "Join/leave Chorus sessions, side-channel chat, and collab prompts" diff --git a/packages/zed/src/lib.rs b/packages/zed/src/lib.rs deleted file mode 100644 index dcb7d0d..0000000 --- a/packages/zed/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -use zed_extension_api::{self as zed, Command, ContextServerId, Project, Result}; - -struct ChorusExtension; - -impl zed::Extension for ChorusExtension { - fn new() -> Self { - Self - } - - fn context_server_command( - &mut self, - _context_server_id: &ContextServerId, - _project: &Project, - ) -> Result { - // The WebSocket join client lives in the native `chorus-zed-helper` binary. - // Install it on PATH (`cargo install --path crates/chorus-zed-helper` from the repo, - // or `cargo build -p chorus-zed-helper --release` and copy `target/release/chorus-zed-helper`). - // Override the binary path via Zed settings `context_servers.chorus` env if needed. - Ok(Command { - command: "chorus-zed-helper".into(), - args: vec!["mcp".into()], - env: vec![], - }) - } -} - -zed::register_extension!(ChorusExtension); From 54a119a74084b04a14d07c82e3946f314ba38c71 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 31 Aug 2026 11:44:17 +0000 Subject: [PATCH 05/10] feat: rebase VS Code adapter onto main and add cross-adapter relay e2e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebase the VS Code plugin and @chorus/client extraction onto v2.0.0 main, merging network CIDR relay options into the shared client. Restore session access control in the VS Code controller (approval, email gate, pending queue). Add vscode-relay-e2e covering three cloud roles (host vscode, joiner vscode, disallowed joiner) plus VS Code↔terminal host/joiner cross-adapter scenarios. Co-authored-by: Steven Roomberg --- CHANGELOG.md | 14 - packages/client/dist/index.d.ts | 2 +- packages/client/dist/index.d.ts.map | 2 +- packages/client/dist/index.js.map | 2 +- packages/client/dist/join.d.ts | 11 +- packages/client/dist/join.d.ts.map | 2 +- packages/client/dist/join.js | 65 ++++- packages/client/dist/join.js.map | 2 +- packages/client/dist/relay.d.ts | 56 +++- packages/client/dist/relay.d.ts.map | 2 +- packages/client/dist/relay.js | 148 ++++++++++- packages/client/dist/relay.js.map | 2 +- packages/client/src/join.ts | 75 +++++- packages/plugin/dist/config/schema.d.ts | 6 +- packages/plugin/dist/join/index.d.ts | 1 + packages/plugin/dist/join/index.d.ts.map | 2 +- packages/plugin/dist/join/index.js | 1 + packages/plugin/dist/join/index.js.map | 2 +- packages/plugin/dist/relay/index.d.ts | 8 +- packages/plugin/dist/relay/index.d.ts.map | 2 +- packages/plugin/dist/relay/index.js | 3 +- packages/plugin/dist/relay/index.js.map | 2 +- packages/vscode/dist/controller.d.ts | 18 +- packages/vscode/dist/controller.js | 184 ++++++++++--- packages/vscode/dist/controller.js.map | 2 +- packages/vscode/dist/extension.js | 68 ++++- packages/vscode/dist/extension.js.map | 2 +- packages/vscode/package.json | 29 +- packages/vscode/src/controller.ts | 212 +++++++++++---- packages/vscode/src/extension.ts | 76 +++++- packages/vscode/src/git.ts | 19 ++ scripts/security-e2e.ts | 2 +- scripts/vscode-e2e.ts | 93 +++++++ scripts/vscode-relay-e2e.ts | 309 ++++++++++++++++++++++ 34 files changed, 1246 insertions(+), 178 deletions(-) create mode 100644 packages/vscode/src/git.ts create mode 100644 scripts/vscode-e2e.ts create mode 100644 scripts/vscode-relay-e2e.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 073e5d9..8f1da0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,20 +128,6 @@ Prefer the **OpenCode web UI** for live mirrored lines. `opencode attach` often | `CHORUS_AWS_BUCKET` | — | Optional S3/R2 session backup | Full tables: [README](https://github.com/sroomberg/chorus/blob/main/README.md). Status and backlog: [docs/STATUS.md](https://github.com/sroomberg/chorus/blob/main/docs/STATUS.md). Enterprise gaps: [docs/ENTERPRISE.md](https://github.com/sroomberg/chorus/blob/main/docs/ENTERPRISE.md). -======= -- Session access control: host approval, required display names, repo/email/domain gates (`session.policy` / `auth.pending` / `host.approve|deny`) -- Configurable git remote prefixes and host rewrites; layered `chorus.json` org settings -- Hybrid OpenCode security e2e, VS Code adapter e2e, and Cloud Agent install script -- VS Code extension (`packages/vscode`) — share/join/chat; Session sidebar; approve/deny -- Extract `@chorus/client` (`JoinClient` + `RelayServer`) for reuse by OpenCode, VS Code, and future adapters -- Real-time shared transcript for all agents: fan out collaborator prompts to every joiner, abort joiner local LLM, mirror `[Host]`/`[name]`/`[AI]` (prefer web UI for live view) -- Joiner mirrors host prompts and AI replies into its OpenCode session transcript (`[Host]:` / `[AI]:`), including history replay on join (replaces toast-only viewing) -- Fix: prevent host/joiner feedback loop when the same agent both shares and joins (block join while sharing; never mirror while hosting; drop echoed `[AI]`/`[Host]:` collab lines) -- Replace in-process Bun WebSocket relay with Rust `chorus-relay` binary (`crates/chorus-relay`) -- Host control protocol on `/host` (token issue, session events, chat, collab.input fan-in) -- Joiner protocol on `/ws` unchanged -- Plugin spawns/manages the relay subprocess (`CHORUS_RELAY_BIN` override) ->>>>>>> a29eb58 (Remove the Zed adapter from this pull request.) ## v0.1.6 — 2026-05-27 diff --git a/packages/client/dist/index.d.ts b/packages/client/dist/index.d.ts index 97ea899..11edbe7 100644 --- a/packages/client/dist/index.d.ts +++ b/packages/client/dist/index.d.ts @@ -1,3 +1,3 @@ export { JoinClient, type JoinState, type JoinStatus, } from "./join.js"; -export { RelayServer, relayOptionsFromEnv, type RelayServerOptions, } from "./relay.js"; +export { RelayServer, relayOptionsFromEnv, type RelayServerOptions, type RelayNetworkOptions, } from "./relay.js"; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/client/dist/index.d.ts.map b/packages/client/dist/index.d.ts.map index 1beee6d..189c941 100644 --- a/packages/client/dist/index.d.ts.map +++ b/packages/client/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/packages/client/dist/index.js.map b/packages/client/dist/index.js.map index 37cad03..1b62086 100644 --- a/packages/client/dist/index.js.map +++ b/packages/client/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,GAEpB,MAAM,YAAY,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,WAAW,EACX,mBAAmB,GAGpB,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/packages/client/dist/join.d.ts b/packages/client/dist/join.d.ts index 8472425..701a4b8 100644 --- a/packages/client/dist/join.d.ts +++ b/packages/client/dist/join.d.ts @@ -1,8 +1,9 @@ import type { SessionEvent, ConnectedUser } from "@chorus/shared"; -export type JoinStatus = "connecting" | "connected" | "disconnected" | "error"; +export type JoinStatus = "connecting" | "pending" | "connected" | "disconnected" | "error"; export interface JoinState { status: JoinStatus; sessionId: string; + userId?: string; users: ConnectedUser[]; recentEvents: SessionEvent[]; error?: string; @@ -11,18 +12,24 @@ export declare class JoinClient { private readonly relayUrl; private readonly token; private readonly displayName; + private readonly repoRemote?; + private readonly email?; private ws; private state; private onEvent?; private onChatMessage?; private onTyping?; - constructor(relayUrl: string, token: string, displayName: string); + private onPending?; + private onApproved?; + constructor(relayUrl: string, token: string, displayName: string, repoRemote?: string | undefined, email?: string | undefined); connect(): Promise; sendInput(content: string): void; sendChat(content: string): void; setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; setTypingHandler(fn: (displayName: string | undefined) => void): void; setEventHandler(fn: (event: SessionEvent) => void): void; + setPendingHandler(fn: (userId: string) => void): void; + setApprovedHandler(fn: () => void): void; sendTyping(): void; getState(): Readonly; disconnect(): void; diff --git a/packages/client/dist/join.d.ts.map b/packages/client/dist/join.d.ts.map index 961b323..c840c37 100644 --- a/packages/client/dist/join.d.ts.map +++ b/packages/client/dist/join.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAOlE,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IAQnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAT9B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAC,CAAgC;IAChD,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;gBAG1C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM;IAUtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoFxB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKhC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK/B,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAIrE,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAIxD,UAAU,IAAI,IAAI;IAKlB,QAAQ,IAAI,QAAQ,CAAC,SAAS,CAAC;IAI/B,UAAU,IAAI,IAAI;CAKnB"} \ No newline at end of file +{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAOlE,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAE3F,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IAUnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IAbzB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAC,CAAgC;IAChD,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAC,CAA2B;IAC7C,OAAO,CAAC,UAAU,CAAC,CAAa;gBAGb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,KAAK,CAAC,EAAE,MAAM,YAAA;IAUjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgIxB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKhC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK/B,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAIrE,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAIxD,iBAAiB,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIrD,kBAAkB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAIxC,UAAU,IAAI,IAAI;IAKlB,QAAQ,IAAI,QAAQ,CAAC,SAAS,CAAC;IAI/B,UAAU,IAAI,IAAI;CAKnB"} \ No newline at end of file diff --git a/packages/client/dist/join.js b/packages/client/dist/join.js index 1d3bbc5..af12bfb 100644 --- a/packages/client/dist/join.js +++ b/packages/client/dist/join.js @@ -3,15 +3,21 @@ export class JoinClient { relayUrl; token; displayName; + repoRemote; + email; ws = null; state; onEvent; onChatMessage; onTyping; - constructor(relayUrl, token, displayName) { + onPending; + onApproved; + constructor(relayUrl, token, displayName, repoRemote, email) { this.relayUrl = relayUrl; this.token = token; this.displayName = displayName; + this.repoRemote = repoRemote; + this.email = email; this.state = { status: "connecting", sessionId: "", @@ -23,8 +29,30 @@ export class JoinClient { return new Promise((resolve, reject) => { const ws = new WebSocket(this.relayUrl); this.ws = ws; + let settled = false; + const succeed = () => { + if (settled) + return; + settled = true; + resolve(); + }; + const fail = (err) => { + if (settled) + return; + settled = true; + reject(err); + }; ws.onopen = () => { - ws.send(encodeMessage({ type: "auth", token: this.token, displayName: this.displayName })); + const auth = { + type: "auth", + token: this.token, + displayName: this.displayName, + }; + if (this.repoRemote) + auth.repoRemote = this.repoRemote; + if (this.email) + auth.email = this.email; + ws.send(encodeMessage(auth)); }; ws.onmessage = (ev) => { let msg; @@ -35,10 +63,23 @@ export class JoinClient { return; } switch (msg.type) { + case "auth.pending": + this.state.status = "pending"; + this.state.userId = msg.userId; + this.onPending?.(msg.userId); + succeed(); + break; + case "auth.denied": + this.state.status = "error"; + this.state.error = msg.message; + fail(new Error(msg.message)); + ws.close(); + break; case "session.history": this.state.recentEvents = msg.events.slice(-50); this.state.status = "connected"; - resolve(); + this.onApproved?.(); + succeed(); break; case "session.event": this.state.recentEvents = [...this.state.recentEvents.slice(-49), msg.event]; @@ -66,22 +107,24 @@ export class JoinClient { this.state.status = "disconnected"; ws.close(); break; - case "error": + case "error": { + const wasAdmitted = this.state.status === "connected" || this.state.status === "pending"; this.state.status = "error"; this.state.error = msg.message; - if (this.state.recentEvents.length === 0) { - reject(new Error(msg.message)); + if (!wasAdmitted) { + fail(new Error(msg.message)); } break; + } } }; ws.onerror = () => { this.state.status = "error"; this.state.error = "Connection error"; - reject(new Error("WebSocket connection error")); + fail(new Error("WebSocket connection error")); }; ws.onclose = () => { - if (this.state.status === "connected") { + if (this.state.status === "connected" || this.state.status === "pending") { this.state.status = "disconnected"; } }; @@ -106,6 +149,12 @@ export class JoinClient { setEventHandler(fn) { this.onEvent = fn; } + setPendingHandler(fn) { + this.onPending = fn; + } + setApprovedHandler(fn) { + this.onApproved = fn; + } sendTyping() { if (!this.ws || this.state.status !== "connected") return; diff --git a/packages/client/dist/join.js.map b/packages/client/dist/join.js.map index 0063d25..6c77a06 100644 --- a/packages/client/dist/join.js.map +++ b/packages/client/dist/join.js.map @@ -1 +1 @@ -{"version":3,"file":"join.js","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"join.js","sourceRoot":"","sources":["../src/join.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/client/dist/relay.d.ts b/packages/client/dist/relay.d.ts index aad2cee..b9b892e 100644 --- a/packages/client/dist/relay.d.ts +++ b/packages/client/dist/relay.d.ts @@ -1,4 +1,4 @@ -import type { SessionEvent, SessionToken, UserRole } from "@chorus/shared"; +import type { ConnectedUser, SessionEvent, SessionToken, UserRole } from "@chorus/shared"; export type RelayServerOptions = { /** Host running the relay (default 127.0.0.1). */ host?: string; @@ -9,6 +9,26 @@ export type RelayServerOptions = { * When true, requires hostToken and does not spawn/kill a subprocess. */ external?: boolean; + /** Bind address passed to chorus-relay (default 0.0.0.0). */ + bind?: string; + /** CIDR/IP allowlist for TCP peers. */ + allowedCidrs?: string[]; + /** Explicit deny CIDRs (deny wins). */ + deniedCidrs?: string[]; + /** Peer source-port allowlist (single-machine e2e). */ + allowedPorts?: number[]; + /** Refuse 0.0.0.0 / :: bind when false. */ + allowOpenBind?: boolean; + /** Admit loopback IPs even when allowlist is set (default true). */ + allowLoopback?: boolean; +}; +export type RelayNetworkOptions = { + bind?: string; + allowedCidrs?: string[]; + deniedCidrs?: string[]; + allowedPorts?: number[]; + allowOpenBind?: boolean; + allowLoopback?: boolean; }; /** * Resolve relay connection settings from env. @@ -24,7 +44,7 @@ export declare function relayOptionsFromEnv(defaultPort: number): { }; /** * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. - * Joiner-facing protocol on `/ws` is unchanged; adapters talk to `/host`. + * Joiner-facing protocol on `/ws` is unchanged; host adapters talk to `/host`. */ export declare class RelayServer { private readonly port; @@ -35,14 +55,28 @@ export declare class RelayServer { private clients; private readonly host; private readonly external; + private bind; + private allowedCidrs; + private deniedCidrs; + private allowedPorts; + private allowOpenBind; + private allowLoopback; private pendingToken; private onInjectInput?; private onChatMessage?; private onTyping?; + private onUserPending?; + private onUserJoined?; + private onUserLeft?; constructor(port: number, opts?: RelayServerOptions); + /** Apply network policy before start() (from project/org chorus.json). */ + setNetworkOptions(opts: RelayNetworkOptions): void; setInputHandler(fn: (content: string, userId: string, displayName?: string) => Promise): void; setChatHandler(fn: (displayName: string | undefined, content: string) => void): void; setTypingHandler(fn: (displayName: string | undefined) => void): void; + setUserPendingHandler(fn: (user: ConnectedUser) => void): void; + setUserJoinedHandler(fn: (user: ConnectedUser) => void): void; + setUserLeftHandler(fn: (userId: string) => void): void; start(): Promise; private statusUrl; private hostWsUrl; @@ -51,13 +85,29 @@ export declare class RelayServer { private handleHostMessage; private send; issueToken(sessionId: string, role?: UserRole, ttlMs?: number): Promise; + setSessionPolicy(opts: { + requireApproval?: boolean; + repoRemote?: string | null; + allowedEmailDomain?: string | null; + additionalRepoRemotePrefixes?: string[] | null; + repoRemoteRewrites?: { + from: string; + to: string; + }[] | null; + }): void; + approveUser(userId: string): void; + denyUser(userId: string): void; + kickUser(userId: string): void; pushEvent(event: SessionEvent): void; sendChat(displayName: string | undefined, content: string): void; - stop(): void; + stop(): Promise; + private waitUntilStopped; get isRunning(): boolean; get clientCount(): number; getPort(): number; getHost(): string; + getBind(): string; + getAllowedCidrs(): string[]; isExternal(): boolean; } //# sourceMappingURL=relay.d.ts.map \ No newline at end of file diff --git a/packages/client/dist/relay.d.ts.map b/packages/client/dist/relay.d.ts.map index 4200a73..f5af588 100644 --- a/packages/client/dist/relay.d.ts.map +++ b/packages/client/dist/relay.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAwB3E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAUF;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAgBA;AAED;;;GAGG;AACH,qBAAa,WAAW;IAkBpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAjBvB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,YAAY,CAGJ;IAEhB,OAAO,CAAC,aAAa,CAAC,CAA2E;IACjG,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;gBAG1C,IAAI,EAAE,MAAM,EAC7B,IAAI,GAAE,kBAAuB;IAO/B,eAAe,CACb,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3E,IAAI;IAIP,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAI/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC5B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;YAIH,WAAW;IAmBzB,OAAO,CAAC,WAAW;IAoCnB,OAAO,CAAC,iBAAiB;IAgDzB,OAAO,CAAC,IAAI;IAKZ,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,QAAiB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB7F,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAIpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIhE,IAAI,IAAI,IAAI;IAqBZ,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM;IAIjB,UAAU,IAAI,OAAO;CAGtB"} \ No newline at end of file +{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/client/dist/relay.js b/packages/client/dist/relay.js index e5ec6c4..1df791d 100644 --- a/packages/client/dist/relay.js +++ b/packages/client/dist/relay.js @@ -13,6 +13,8 @@ function resolveRelayBin() { join(here, "../../../target/debug/chorus-relay"), join(here, "../../../../target/release/chorus-relay"), join(here, "../../../../target/debug/chorus-relay"), + join(here, "../../../../../target/release/chorus-relay"), + join(here, "../../../../../target/debug/chorus-relay"), ]; for (const path of candidates) { if (existsSync(path)) @@ -53,7 +55,7 @@ export function relayOptionsFromEnv(defaultPort) { } /** * Manages the Rust `chorus-relay` subprocess and the host control WebSocket. - * Joiner-facing protocol on `/ws` is unchanged; adapters talk to `/host`. + * Joiner-facing protocol on `/ws` is unchanged; host adapters talk to `/host`. */ export class RelayServer { port; @@ -64,15 +66,45 @@ export class RelayServer { clients = 0; host; external; + bind; + allowedCidrs; + deniedCidrs; + allowedPorts; + allowOpenBind; + allowLoopback; pendingToken = null; onInjectInput; onChatMessage; onTyping; + onUserPending; + onUserJoined; + onUserLeft; constructor(port, opts = {}) { this.port = port; this.host = opts.host ?? "127.0.0.1"; this.external = Boolean(opts.external); this.hostToken = opts.hostToken ?? ""; + this.bind = opts.bind ?? "0.0.0.0"; + this.allowedCidrs = opts.allowedCidrs ? [...opts.allowedCidrs] : []; + this.deniedCidrs = opts.deniedCidrs ? [...opts.deniedCidrs] : []; + this.allowedPorts = opts.allowedPorts ? [...opts.allowedPorts] : []; + this.allowOpenBind = opts.allowOpenBind ?? true; + this.allowLoopback = opts.allowLoopback ?? true; + } + /** Apply network policy before start() (from project/org chorus.json). */ + setNetworkOptions(opts) { + if (opts.bind !== undefined) + this.bind = opts.bind; + if (opts.allowedCidrs !== undefined) + this.allowedCidrs = [...opts.allowedCidrs]; + if (opts.deniedCidrs !== undefined) + this.deniedCidrs = [...opts.deniedCidrs]; + if (opts.allowedPorts !== undefined) + this.allowedPorts = [...opts.allowedPorts]; + if (opts.allowOpenBind !== undefined) + this.allowOpenBind = opts.allowOpenBind; + if (opts.allowLoopback !== undefined) + this.allowLoopback = opts.allowLoopback; } setInputHandler(fn) { this.onInjectInput = fn; @@ -83,6 +115,15 @@ export class RelayServer { setTypingHandler(fn) { this.onTyping = fn; } + setUserPendingHandler(fn) { + this.onUserPending = fn; + } + setUserJoinedHandler(fn) { + this.onUserJoined = fn; + } + setUserLeftHandler(fn) { + this.onUserLeft = fn; + } async start() { if (this.running) return; @@ -97,7 +138,28 @@ export class RelayServer { } this.hostToken = this.hostToken || randomBytes(32).toString("hex"); const bin = resolveRelayBin(); - this.child = spawn(bin, ["--port", String(this.port), "--bind", "0.0.0.0", "--host-token", this.hostToken], { + const args = [ + "--port", + String(this.port), + "--bind", + this.bind, + "--host-token", + this.hostToken, + "--allow-open-bind", + this.allowOpenBind ? "true" : "false", + "--allow-loopback", + this.allowLoopback ? "true" : "false", + ]; + for (const cidr of this.allowedCidrs) { + args.push("--allow-cidr", cidr); + } + for (const cidr of this.deniedCidrs) { + args.push("--deny-cidr", cidr); + } + for (const port of this.allowedPorts) { + args.push("--allow-port", String(port)); + } + this.child = spawn(bin, args, { stdio: ["ignore", "ignore", "pipe"], env: { ...process.env }, }); @@ -184,14 +246,19 @@ export class RelayServer { case "user.typing": this.onTyping?.(msg.displayName); break; + case "user.pending": + this.onUserPending?.(msg.user); + break; case "user.joined": this.clients += 1; + this.onUserJoined?.(msg.user); break; case "user.left": this.clients = Math.max(0, this.clients - 1); + this.onUserLeft?.(msg.userId); break; case "user.list": - this.clients = msg.users.length; + this.clients = msg.users.filter((u) => u.status === "active").length; break; case "status": this.clients = msg.clients; @@ -223,13 +290,32 @@ export class RelayServer { }, 5000); }); } + setSessionPolicy(opts) { + this.send({ + type: "session.policy", + requireApproval: opts.requireApproval, + repoRemote: opts.repoRemote === null ? "" : opts.repoRemote, + allowedEmailDomain: opts.allowedEmailDomain === null ? "" : opts.allowedEmailDomain, + additionalRepoRemotePrefixes: opts.additionalRepoRemotePrefixes ?? undefined, + repoRemoteRewrites: opts.repoRemoteRewrites ?? undefined, + }); + } + approveUser(userId) { + this.send({ type: "host.approve", userId }); + } + denyUser(userId) { + this.send({ type: "host.deny", userId }); + } + kickUser(userId) { + this.send({ type: "host.kick", userId }); + } pushEvent(event) { this.send({ type: "session.event", event }); } sendChat(displayName, content) { this.send({ type: "chat.send", content, displayName }); } - stop() { + async stop() { if (!this.external) { this.send({ type: "host.close" }); } @@ -240,16 +326,50 @@ export class RelayServer { // ignore } this.ws = null; - if (this.child && !this.child.killed) { - this.child.kill("SIGTERM"); - setTimeout(() => { - if (this.child && !this.child.killed) - this.child.kill("SIGKILL"); - }, 1000).unref?.(); - } + const child = this.child; this.child = null; this.running = false; this.clients = 0; + if (child && child.exitCode === null && child.signalCode === null) { + await new Promise((resolve) => { + const finish = () => resolve(); + child.once("exit", finish); + try { + child.kill("SIGTERM"); + } + catch { + finish(); + return; + } + setTimeout(() => { + if (child.exitCode === null && child.signalCode === null) { + try { + child.kill("SIGKILL"); + } + catch { + finish(); + } + } + }, 1000).unref?.(); + }); + } + if (!this.external) { + await this.waitUntilStopped(); + } + } + async waitUntilStopped(timeoutMs = 2000) { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const res = await fetch(this.statusUrl(), { signal: AbortSignal.timeout(250) }); + if (!res.ok) + return; + } + catch { + return; + } + await new Promise((r) => setTimeout(r, 20)); + } } get isRunning() { return this.running; @@ -263,6 +383,12 @@ export class RelayServer { getHost() { return this.host; } + getBind() { + return this.bind; + } + getAllowedCidrs() { + return [...this.allowedCidrs]; + } isExternal() { return this.external; } diff --git a/packages/client/dist/relay.js.map b/packages/client/dist/relay.js.map index 263dfdc..6e17eef 100644 --- a/packages/client/dist/relay.js.map +++ b/packages/client/dist/relay.js.map @@ -1 +1 @@ -{"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/client/src/join.ts b/packages/client/src/join.ts index 1d5290e..e3b78a5 100644 --- a/packages/client/src/join.ts +++ b/packages/client/src/join.ts @@ -5,11 +5,12 @@ import { type ServerMessage, } from "@chorus/shared"; -export type JoinStatus = "connecting" | "connected" | "disconnected" | "error"; +export type JoinStatus = "connecting" | "pending" | "connected" | "disconnected" | "error"; export interface JoinState { status: JoinStatus; sessionId: string; + userId?: string; users: ConnectedUser[]; recentEvents: SessionEvent[]; error?: string; @@ -21,11 +22,15 @@ export class JoinClient { private onEvent?: (event: SessionEvent) => void; private onChatMessage?: (displayName: string | undefined, content: string) => void; private onTyping?: (displayName: string | undefined) => void; + private onPending?: (userId: string) => void; + private onApproved?: () => void; constructor( private readonly relayUrl: string, private readonly token: string, - private readonly displayName: string + private readonly displayName: string, + private readonly repoRemote?: string, + private readonly email?: string ) { this.state = { status: "connecting", @@ -39,9 +44,35 @@ export class JoinClient { return new Promise((resolve, reject) => { const ws = new WebSocket(this.relayUrl); this.ws = ws; + let settled = false; + + const succeed = () => { + if (settled) return; + settled = true; + resolve(); + }; + + const fail = (err: Error) => { + if (settled) return; + settled = true; + reject(err); + }; ws.onopen = () => { - ws.send(encodeMessage({ type: "auth", token: this.token, displayName: this.displayName })); + const auth: { + type: "auth"; + token: string; + displayName: string; + repoRemote?: string; + email?: string; + } = { + type: "auth", + token: this.token, + displayName: this.displayName, + }; + if (this.repoRemote) auth.repoRemote = this.repoRemote; + if (this.email) auth.email = this.email; + ws.send(encodeMessage(auth)); }; ws.onmessage = (ev) => { @@ -53,10 +84,25 @@ export class JoinClient { } switch (msg.type) { + case "auth.pending": + this.state.status = "pending"; + this.state.userId = msg.userId; + this.onPending?.(msg.userId); + succeed(); + break; + + case "auth.denied": + this.state.status = "error"; + this.state.error = msg.message; + fail(new Error(msg.message)); + ws.close(); + break; + case "session.history": this.state.recentEvents = msg.events.slice(-50); this.state.status = "connected"; - resolve(); + this.onApproved?.(); + succeed(); break; case "session.event": @@ -95,24 +141,27 @@ export class JoinClient { ws.close(); break; - case "error": + case "error": { + const wasAdmitted = + this.state.status === "connected" || this.state.status === "pending"; this.state.status = "error"; this.state.error = msg.message; - if (this.state.recentEvents.length === 0) { - reject(new Error(msg.message)); + if (!wasAdmitted) { + fail(new Error(msg.message)); } break; + } } }; ws.onerror = () => { this.state.status = "error"; this.state.error = "Connection error"; - reject(new Error("WebSocket connection error")); + fail(new Error("WebSocket connection error")); }; ws.onclose = () => { - if (this.state.status === "connected") { + if (this.state.status === "connected" || this.state.status === "pending") { this.state.status = "disconnected"; } }; @@ -141,6 +190,14 @@ export class JoinClient { this.onEvent = fn; } + setPendingHandler(fn: (userId: string) => void): void { + this.onPending = fn; + } + + setApprovedHandler(fn: () => void): void { + this.onApproved = fn; + } + sendTyping(): void { if (!this.ws || this.state.status !== "connected") return; this.ws.send(encodeMessage({ type: "typing" })); diff --git a/packages/plugin/dist/config/schema.d.ts b/packages/plugin/dist/config/schema.d.ts index 65ae899..54aae5b 100644 --- a/packages/plugin/dist/config/schema.d.ts +++ b/packages/plugin/dist/config/schema.d.ts @@ -1,9 +1,9 @@ import { z } from "zod"; /** Role granted to new share tokens when the host omits an explicit role. */ export declare const chorusRoleSchema: z.ZodEnum<{ - admin: "admin"; edit: "edit"; view: "view"; + admin: "admin"; }>; export declare const chorusSecurityConfigSchema: z.ZodObject<{ requireApproval: z.ZodDefault; @@ -11,9 +11,9 @@ export declare const chorusSecurityConfigSchema: z.ZodObject<{ requireRepoMatch: z.ZodDefault; requireEmailDomainMatch: z.ZodDefault; defaultRole: z.ZodDefault>; allowedEmailDomain: z.ZodOptional; additionalRepoRemotePrefixes: z.ZodDefault>; @@ -56,9 +56,9 @@ export declare const chorusConfigSchema: z.ZodObject<{ requireRepoMatch: z.ZodDefault; requireEmailDomainMatch: z.ZodDefault; defaultRole: z.ZodDefault>; allowedEmailDomain: z.ZodOptional; additionalRepoRemotePrefixes: z.ZodDefault>; diff --git a/packages/plugin/dist/join/index.d.ts b/packages/plugin/dist/join/index.d.ts index 030eff9..a119e06 100644 --- a/packages/plugin/dist/join/index.d.ts +++ b/packages/plugin/dist/join/index.d.ts @@ -1 +1,2 @@ export { JoinClient, type JoinState, type JoinStatus } from "@chorus/client"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/plugin/dist/join/index.d.ts.map b/packages/plugin/dist/join/index.d.ts.map index 3c2c060..76e7d85 100644 --- a/packages/plugin/dist/join/index.d.ts.map +++ b/packages/plugin/dist/join/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/join/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAOlE,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAE3F,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IAUnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IAbzB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAC,CAAgC;IAChD,OAAO,CAAC,aAAa,CAAC,CAA6D;IACnF,OAAO,CAAC,QAAQ,CAAC,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAC,CAA2B;IAC7C,OAAO,CAAC,UAAU,CAAC,CAAa;gBAGb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,KAAK,CAAC,EAAE,MAAM,YAAA;IAUjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgIxB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKhC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK/B,cAAc,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIpF,gBAAgB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;IAIrE,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAIxD,iBAAiB,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIrD,kBAAkB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAIxC,UAAU,IAAI,IAAI;IAKlB,QAAQ,IAAI,QAAQ,CAAC,SAAS,CAAC;IAI/B,UAAU,IAAI,IAAI;CAKnB"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/join/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC"} \ No newline at end of file diff --git a/packages/plugin/dist/join/index.js b/packages/plugin/dist/join/index.js index 94cb25f..a40d6b6 100644 --- a/packages/plugin/dist/join/index.js +++ b/packages/plugin/dist/join/index.js @@ -1 +1,2 @@ export { JoinClient } from "@chorus/client"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/plugin/dist/join/index.js.map b/packages/plugin/dist/join/index.js.map index eebc8db..dea2dc6 100644 --- a/packages/plugin/dist/join/index.js.map +++ b/packages/plugin/dist/join/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/join/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/join/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmC,MAAM,gBAAgB,CAAC"} \ No newline at end of file diff --git a/packages/plugin/dist/relay/index.d.ts b/packages/plugin/dist/relay/index.d.ts index 9be2ec4..a567d61 100644 --- a/packages/plugin/dist/relay/index.d.ts +++ b/packages/plugin/dist/relay/index.d.ts @@ -1,6 +1,2 @@ -export { - RelayServer, - relayOptionsFromEnv, - type RelayServerOptions, - type RelayNetworkOptions, -} from "@chorus/client"; +export { RelayServer, relayOptionsFromEnv, type RelayServerOptions, type RelayNetworkOptions, } from "@chorus/client"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/plugin/dist/relay/index.d.ts.map b/packages/plugin/dist/relay/index.d.ts.map index 862f647..71e1017 100644 --- a/packages/plugin/dist/relay/index.d.ts.map +++ b/packages/plugin/dist/relay/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC"} \ No newline at end of file diff --git a/packages/plugin/dist/relay/index.js b/packages/plugin/dist/relay/index.js index 42a1f63..947f81c 100644 --- a/packages/plugin/dist/relay/index.js +++ b/packages/plugin/dist/relay/index.js @@ -1 +1,2 @@ -export { RelayServer, relayOptionsFromEnv } from "@chorus/client"; +export { RelayServer, relayOptionsFromEnv, } from "@chorus/client"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/plugin/dist/relay/index.js.map b/packages/plugin/dist/relay/index.js.map index faa6183..70df27f 100644 --- a/packages/plugin/dist/relay/index.js.map +++ b/packages/plugin/dist/relay/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAGlB,MAAM,gBAAgB,CAAC;AAExB,SAAS,eAAe;IACtB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAE5E,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,EAAE,yCAAyC,CAAC;QACrD,IAAI,CAAC,IAAI,EAAE,uCAAuC,CAAC;QACnD,IAAI,CAAC,IAAI,EAAE,4CAA4C,CAAC;QACxD,IAAI,CAAC,IAAI,EAAE,0CAA0C,CAAC;KACvD,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACpC,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAmCD,SAAS,cAAc,CAAC,GAAuB,EAAE,YAAoB;IACnE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC3D,sDAAsD;IACtD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAC9D,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;AAC9F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IAIrD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,WAAW,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnD,MAAM,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG;QAC5C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,MAAM;QAC/C,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAEzD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,SAAS,EAAE,SAAS,IAAI,SAAS;YACjC,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,WAAW;IA2BH;IA1BX,KAAK,GAAwB,IAAI,CAAC;IAClC,EAAE,GAAqB,IAAI,CAAC;IAC5B,SAAS,GAAG,EAAE,CAAC;IACf,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,CAAC,CAAC;IACH,IAAI,CAAS;IACb,QAAQ,CAAU;IAC3B,IAAI,CAAS;IACb,YAAY,CAAW;IACvB,WAAW,CAAW;IACtB,YAAY,CAAW;IACvB,aAAa,CAAU;IACvB,aAAa,CAAU;IACvB,YAAY,GAGT,IAAI,CAAC;IAER,aAAa,CAA4E;IACzF,aAAa,CAA8D;IAC3E,QAAQ,CAA6C;IACrD,aAAa,CAAiC;IAC9C,YAAY,CAAiC;IAC7C,UAAU,CAA4B;IAE9C,YACmB,IAAY,EAC7B,OAA2B,EAAE;QADZ,SAAI,GAAJ,IAAI,CAAQ;QAG7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;QAChD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;IAClD,CAAC;IAED,0EAA0E;IAC1E,iBAAiB,CAAC,IAAyB;QACzC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;YAAE,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7E,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QAC9E,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;IAChF,CAAC;IAED,eAAe,CACb,EAA4E;QAE5E,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,cAAc,CAAC,EAA8D;QAC3E,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,gBAAgB,CAAC,EAA6C;QAC5D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,qBAAqB,CAAC,EAAiC;QACrD,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,oBAAoB,CAAC,EAAiC;QACpD,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;IACzB,CAAC;IAED,kBAAkB,CAAC,EAA4B;QAC7C,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAE9B,MAAM,IAAI,GAAG;YACX,QAAQ;YACR,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACjB,QAAQ;YACR,IAAI,CAAC,IAAI;YACT,cAAc;YACd,IAAI,CAAC,SAAS;YACd,mBAAmB;YACnB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;YACrC,kBAAkB;YAClB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;SACtC,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC5B,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;YACnC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACzB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAEO,SAAS;QACf,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,SAAS,CAAC;IACnD,CAAC;IAEO,SAAS;QACf,OAAO,QAAQ,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,OAAO,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjF,IAAI,GAAG,CAAC,EAAE;oBAAE,OAAO;YACrB,CAAC;YAAC,MAAM,CAAC;gBACP,aAAa;YACf,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,IAAI,KAAK,CACb,IAAI,CAAC,QAAQ;YACX,CAAC,CAAC,0CAA0C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,8BAA8B;YAChG,CAAC,CAAC,6CAA6C,IAAI,CAAC,IAAI,IAAI;gBACxD,sFAAsF,CAC7F,CAAC;IACJ,CAAC;IAEO,WAAW;QACjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;YAEb,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAExF,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;gBACf,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC1D,CAAC,CAAC;YAEF,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE;gBACpB,IAAI,GAAgB,CAAC;gBACrB,IAAI,CAAC;oBACH,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC3C,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE;oBAC/B,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;YACL,CAAC,CAAC;YAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBAChB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;YACpD,CAAC,CAAC;YAEF,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB,CAAC,GAAgB,EAAE,OAAoB;QAC9D,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,YAAY;gBACf,OAAO,EAAE,EAAE,CAAC;gBACZ,MAAM;YAER,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,GAAG,CAAC;gBACnC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,MAAM;YACR,CAAC;YAED,KAAK,cAAc;gBACjB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACrF,MAAM;YAER,KAAK,cAAc;gBACjB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnE,MAAM;YAER,KAAK,aAAa;gBAChB,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACjC,MAAM;YAER,KAAK,cAAc;gBACjB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM;YAER,KAAK,aAAa;gBAChB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC9B,MAAM;YAER,KAAK,WAAW;gBACd,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;gBAC7C,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC9B,MAAM;YAER,KAAK,WAAW;gBACd,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;gBACrE,MAAM;YAER,KAAK,QAAQ;gBACX,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;gBAC3B,MAAM;YAER,KAAK,OAAO;gBACV,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,MAAM;QACV,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,GAAgB;QAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;YAAE,OAAO;QAC9D,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,OAAiB,MAAM,EAAE,KAAc;QACnE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACtD,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBACtD,OAAO;YACT,CAAC;YACD,IAAI,CAAC,YAAY,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3D,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACtB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;oBAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC3B,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB,CAAC,IAMhB;QACC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,gBAAgB;YACtB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,UAAU,EAAE,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU;YAC3D,kBAAkB,EAChB,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB;YACjE,4BAA4B,EAAE,IAAI,CAAC,4BAA4B,IAAI,SAAS;YAC5E,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,IAAI,SAAS;SACzD,CAAC,CAAC;IACL,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ,CAAC,MAAc;QACrB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,QAAQ,CAAC,MAAc;QACrB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,SAAS,CAAC,KAAmB;QAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ,CAAC,WAA+B,EAAE,OAAe;QACvD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,yEAAyE;QACzE,sDAAsD;QACtD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QAEf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QAEjB,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAClE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC3B,IAAI,CAAC;oBACH,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACxB,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,EAAE,CAAC;oBACT,OAAO;gBACT,CAAC;gBACD,UAAU,CAAC,GAAG,EAAE;oBACd,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;wBACzD,IAAI,CAAC;4BACH,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;wBACxB,CAAC;wBAAC,MAAM,CAAC;4BACP,MAAM,EAAE,CAAC;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,SAAS,GAAG,IAAI;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChF,IAAI,CAAC,GAAG,CAAC,EAAE;oBAAE,OAAO;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO;YACT,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,eAAe;QACb,OAAO,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,mBAAmB,GAGpB,MAAM,gBAAgB,CAAC"} \ No newline at end of file diff --git a/packages/vscode/dist/controller.d.ts b/packages/vscode/dist/controller.d.ts index 08c69f2..974d717 100644 --- a/packages/vscode/dist/controller.d.ts +++ b/packages/vscode/dist/controller.d.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { type JoinState } from "@chorus/client"; -import type { UserRole } from "@chorus/shared"; -export type ChorusMode = "idle" | "sharing" | "joined"; +import type { ConnectedUser, UserRole } from "@chorus/shared"; +export type ChorusMode = "idle" | "sharing" | "joined" | "pending"; export type TranscriptLine = { id: string; text: string; @@ -10,7 +10,8 @@ export type TranscriptLine = { }; /** * Host/joiner controller for the VS Code adapter. - * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin, including + * session access control (approval, required name, optional repo gate). */ export declare class ChorusController { private readonly output; @@ -19,12 +20,14 @@ export declare class ChorusController { private relay; private joinClient; private sessionId; + private pendingUsers; private readonly transcript; private readonly _onDidChange; readonly onDidChange: vscode.Event; constructor(output: vscode.OutputChannel, statusBar: vscode.StatusBarItem); getMode(): ChorusMode; getTranscript(): readonly TranscriptLine[]; + getPendingUsers(): readonly ConnectedUser[]; getJoinState(): JoinState | null; getShareSummary(): { sharing: boolean; @@ -32,19 +35,24 @@ export declare class ChorusController { port?: number; host?: string; external?: boolean; + pending?: number; }; private cfg; private displayName; private defaultPort; + private requireApprovalDefault; private publicJoinHost; private append; private appendSystem; private appendSession; private refreshStatus; - share(role?: UserRole): Promise; + private ensureRelayHandlers; + share(role?: UserRole, requireApproval?: boolean): Promise; + approveUser(userId: string): void; + denyUser(userId: string): void; join(token: string, host: string, name?: string): Promise; leave(): Promise; - stop(): void; + stop(): Promise; sendChat(message: string): void; /** Joiner → host collab.input */ sendPrompt(content: string): void; diff --git a/packages/vscode/dist/controller.js b/packages/vscode/dist/controller.js index 2d0eac8..42a5e2d 100644 --- a/packages/vscode/dist/controller.js +++ b/packages/vscode/dist/controller.js @@ -1,7 +1,9 @@ import { networkInterfaces } from "node:os"; import * as vscode from "vscode"; import { JoinClient, RelayServer, relayOptionsFromEnv, } from "@chorus/client"; +import { normalizeDisplayName } from "@chorus/shared"; import { formatSessionLine, newEventId } from "./format.js"; +import { detectRepoRemote } from "./git.js"; function getLanIp() { const nets = networkInterfaces(); for (const iface of Object.values(nets)) { @@ -14,7 +16,8 @@ function getLanIp() { } /** * Host/joiner controller for the VS Code adapter. - * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin, including + * session access control (approval, required name, optional repo gate). */ export class ChorusController { output; @@ -23,6 +26,7 @@ export class ChorusController { relay = null; joinClient = null; sessionId = `vscode-${Date.now().toString(36)}`; + pendingUsers = []; transcript = []; _onDidChange = new vscode.EventEmitter(); onDidChange = this._onDidChange.event; @@ -37,6 +41,9 @@ export class ChorusController { getTranscript() { return this.transcript; } + getPendingUsers() { + return this.pendingUsers; + } getJoinState() { return this.joinClient?.getState() ?? null; } @@ -49,20 +56,28 @@ export class ChorusController { port: this.relay.getPort(), host: this.relay.getHost(), external: this.relay.isExternal(), + pending: this.pendingUsers.length, }; } cfg() { return vscode.workspace.getConfiguration("chorus"); } displayName() { - const configured = this.cfg().get("displayName")?.trim(); - if (configured) - return configured; - return process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"; + const configured = this.cfg().get("displayName"); + const normalized = normalizeDisplayName(configured); + if (normalized) + return normalized; + const fallback = normalizeDisplayName(process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"); + if (!fallback) + throw new Error("A non-empty display name is required (set chorus.displayName)."); + return fallback; } defaultPort() { return this.cfg().get("port") ?? 7742; } + requireApprovalDefault() { + return this.cfg().get("requireApproval") !== false; + } publicJoinHost(port, relayHost, external) { const fromSettings = this.cfg().get("publicHost")?.trim(); if (fromSettings) @@ -92,9 +107,16 @@ export class ChorusController { } refreshStatus() { if (this.mode === "sharing" && this.relay) { - this.statusBar.text = `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; + const pending = this.pendingUsers.length; + this.statusBar.text = pending + ? `$(broadcast) Chorus sharing :${this.relay.getPort()} (${pending} pending)` + : `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; this.statusBar.tooltip = "Chorus is sharing — click for status"; } + else if (this.mode === "pending" && this.joinClient) { + this.statusBar.text = "$(watch) Chorus waiting for host approval"; + this.statusBar.tooltip = "Connected but pending host approval"; + } else if (this.mode === "joined" && this.joinClient) { const st = this.joinClient.getState(); this.statusBar.text = `$(organization) Chorus joined (${st.users.length})`; @@ -107,8 +129,46 @@ export class ChorusController { this.statusBar.command = "chorus.status"; this._onDidChange.fire(); } - async share(role = "edit") { - if (this.mode === "joined") { + ensureRelayHandlers(relay) { + relay.setInputHandler(async (content, userId, displayName) => { + const label = displayName ?? userId.slice(0, 8); + const labeled = `[${label}]: ${content}`; + const event = { + id: newEventId(), + sessionId: this.sessionId, + type: "user", + payload: labeled, + timestamp: Date.now(), + }; + this.appendSession(event); + this.relay?.pushEvent(event); + void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); + }); + relay.setChatHandler((name, content) => { + const text = `💬 [${name ?? "guest"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + relay.setTypingHandler((name) => { + this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + relay.setUserPendingHandler((user) => { + this.pendingUsers = [...this.pendingUsers.filter((u) => u.userId !== user.userId), user]; + this.appendSystem(`Join request from ${user.displayName} (${user.role}) — ${user.userId}`); + this.refreshStatus(); + void vscode.window + .showInformationMessage(`Chorus: ${user.displayName} wants to join (${user.role}).`, "Approve", "Deny") + .then((choice) => { + if (choice === "Approve") + this.approveUser(user.userId); + if (choice === "Deny") + this.denyUser(user.userId); + }); + }); + } + async share(role = "edit", requireApproval) { + if (this.mode === "joined" || this.mode === "pending") { await this.leave(); } const relayBin = this.cfg().get("relayBin")?.trim(); @@ -117,33 +177,19 @@ export class ChorusController { const { port, opts } = relayOptionsFromEnv(this.defaultPort()); if (!this.relay) { this.relay = new RelayServer(port, opts); - this.relay.setInputHandler(async (content, userId, displayName) => { - const label = displayName ?? userId.slice(0, 8); - const labeled = `[${label}]: ${content}`; - const event = { - id: newEventId(), - sessionId: this.sessionId, - type: "user", - payload: labeled, - timestamp: Date.now(), - }; - this.appendSession(event); - this.relay?.pushEvent(event); - void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); - }); - this.relay.setChatHandler((name, content) => { - const text = `💬 [${name ?? "guest"}]: ${content}`; - this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); - void vscode.window.showInformationMessage(text); - }); - this.relay.setTypingHandler((name) => { - this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; - setTimeout(() => this.refreshStatus(), 2000).unref?.(); - }); + this.ensureRelayHandlers(this.relay); } if (!this.relay.isRunning) { await this.relay.start(); } + const approval = requireApproval ?? this.requireApprovalDefault(); + const repoRemote = detectRepoRemote(); + this.relay.setSessionPolicy({ + requireApproval: approval, + repoRemote: repoRemote ?? "", + allowedEmailDomain: this.cfg().get("allowedEmailDomain")?.trim() || undefined, + }); + this.pendingUsers = []; this.mode = "sharing"; const token = await this.relay.issueToken(this.sessionId, role); const joinHost = this.publicJoinHost(this.relay.getPort(), this.relay.getHost(), this.relay.isExternal()); @@ -151,15 +197,41 @@ export class ChorusController { this.appendSystem(this.relay.isExternal() ? `Attached to external relay ${this.relay.getHost()}:${this.relay.getPort()}` : `chorus-relay started on port ${this.relay.getPort()}`); + this.appendSystem(approval + ? "Joiners wait for your approval (Chorus: Approve Joiner / Deny Joiner)." + : "Auto-admit is on (requireApproval=false)."); + if (repoRemote) { + this.appendSystem(`Repo gate on: joiners must share origin ${repoRemote}.`); + } this.appendSystem(`Share ready (${role}). Collaborator command:\n${joinCommand}`); this.refreshStatus(); await vscode.env.clipboard.writeText(joinCommand); - void vscode.window.showInformationMessage(`Chorus sharing — join command copied to clipboard.`, "Copy again").then((choice) => { + void vscode.window + .showInformationMessage(`Chorus sharing — join command copied to clipboard.`, "Copy again") + .then((choice) => { if (choice === "Copy again") void vscode.env.clipboard.writeText(joinCommand); }); return joinCommand; } + approveUser(userId) { + if (!this.relay || this.mode !== "sharing") { + throw new Error("Share a session first to approve joiners."); + } + this.relay.approveUser(userId); + this.pendingUsers = this.pendingUsers.filter((u) => u.userId !== userId); + this.appendSystem(`Approved ${userId}`); + this.refreshStatus(); + } + denyUser(userId) { + if (!this.relay || this.mode !== "sharing") { + throw new Error("Share a session first to deny joiners."); + } + this.relay.denyUser(userId); + this.pendingUsers = this.pendingUsers.filter((u) => u.userId !== userId); + this.appendSystem(`Denied ${userId}`); + this.refreshStatus(); + } async join(token, host, name) { if (this.mode === "sharing") { throw new Error("Stop sharing (Chorus: Stop Sharing) before joining another session."); @@ -168,9 +240,10 @@ export class ChorusController { this.joinClient.disconnect(); this.joinClient = null; } - const displayName = name?.trim() || this.displayName(); - const jc = new JoinClient(`ws://${host}/ws`, token, displayName); - await jc.connect(); + const displayName = normalizeDisplayName(name) ?? this.displayName(); + const repoRemote = detectRepoRemote(); + const email = this.cfg().get("email")?.trim() || undefined; + const jc = new JoinClient(`ws://${host}/ws`, token, displayName, repoRemote, email); jc.setChatHandler((msgName, content) => { const text = `💬 [${msgName ?? "host"}]: ${content}`; this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); @@ -181,26 +254,45 @@ export class ChorusController { setTimeout(() => this.refreshStatus(), 2000).unref?.(); }); jc.setEventHandler((event) => this.appendSession(event)); + jc.setPendingHandler((userId) => { + this.mode = "pending"; + this.appendSystem(`Waiting for host approval (userId=${userId})`); + this.refreshStatus(); + void vscode.window.showInformationMessage("Chorus: waiting for the host to approve your join."); + }); + jc.setApprovedHandler(() => { + this.mode = "joined"; + this.appendSystem("Host approved — you are in the session."); + this.refreshStatus(); + void vscode.window.showInformationMessage("Chorus: host approved your join."); + }); + await jc.connect(); for (const event of jc.getState().recentEvents) { this.appendSession(event); } this.joinClient = jc; - this.mode = "joined"; - this.appendSystem(`Joined ${host} as ${displayName}`); + const st = jc.getState().status; + this.mode = st === "pending" ? "pending" : "joined"; + this.appendSystem(st === "pending" + ? `Connected to ${host} as ${displayName} — pending approval` + : `Joined ${host} as ${displayName}`); this.refreshStatus(); } async leave() { this.joinClient?.disconnect(); this.joinClient = null; - if (this.mode === "joined") + if (this.mode === "joined" || this.mode === "pending") this.mode = "idle"; this.appendSystem("Left shared session"); this.refreshStatus(); } - stop() { + async stop() { this.mode = "idle"; - this.relay?.stop(); + this.pendingUsers = []; + const relay = this.relay; this.relay = null; + if (relay) + await relay.stop(); this.appendSystem("Stopped sharing"); this.refreshStatus(); } @@ -226,13 +318,19 @@ export class ChorusController { }); return; } + if (this.mode === "pending") { + throw new Error("Still waiting for host approval — chat is blocked until then."); + } throw new Error("Not currently sharing or joined."); } /** Joiner → host collab.input */ sendPrompt(content) { - if (this.mode !== "joined" || !this.joinClient) { + if (!this.joinClient) { throw new Error("Join a session first to send prompts to the host."); } + if (this.joinClient.getState().status !== "connected") { + throw new Error("Cannot send prompts while pending host approval."); + } this.joinClient.sendInput(content); this.appendSystem(`→ sent prompt to host (${content.slice(0, 80)}${content.length > 80 ? "…" : ""})`); } @@ -256,11 +354,11 @@ export class ChorusController { const join = this.joinClient ? { joined: true, ...this.joinClient.getState() } : { joined: false }; - return JSON.stringify({ mode: this.mode, ...share, ...join }, null, 2); + return JSON.stringify({ mode: this.mode, pendingUsers: this.pendingUsers, ...share, ...join }, null, 2); } dispose() { this.joinClient?.disconnect(); - this.relay?.stop(); + void this.relay?.stop(); this._onDidChange.dispose(); } } diff --git a/packages/vscode/dist/controller.js.map b/packages/vscode/dist/controller.js.map index b4cf42f..9326958 100644 --- a/packages/vscode/dist/controller.js.map +++ b/packages/vscode/dist/controller.js.map @@ -1 +1 @@ -{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,GAEpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAW5C,SAAS,QAAQ;IACf,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;YAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACjE,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAWR;IACA;IAXX,IAAI,GAAe,MAAM,CAAC;IAC1B,KAAK,GAAuB,IAAI,CAAC;IACjC,UAAU,GAAsB,IAAI,CAAC;IACrC,SAAS,GAAG,UAAU,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IAChD,YAAY,GAAoB,EAAE,CAAC;IAC1B,UAAU,GAAqB,EAAE,CAAC;IAClC,YAAY,GAAG,IAAI,MAAM,CAAC,YAAY,EAAQ,CAAC;IACvD,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IAE/C,YACmB,MAA4B,EAC5B,SAA+B;QAD/B,WAAM,GAAN,MAAM,CAAsB;QAC5B,cAAS,GAAT,SAAS,CAAsB;QAEhD,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC;IAC7C,CAAC;IAED,eAAe;QAQb,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACtE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;YAC/B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YAC1B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YAC1B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;YACjC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM;SAClC,CAAC;IACJ,CAAC;IAEO,GAAG;QACT,OAAO,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAEO,WAAW;QACjB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,aAAa,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;QAClC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,CAAC;QAClG,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACjG,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,WAAW;QACjB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,MAAM,CAAC,IAAI,IAAI,CAAC;IAChD,CAAC;IAEO,sBAAsB;QAC5B,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAU,iBAAiB,CAAC,KAAK,KAAK,CAAC;IAC9D,CAAC;IAEO,cAAc,CAAC,IAAY,EAAE,SAAiB,EAAE,QAAiB;QACvE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC;QAClE,IAAI,YAAY;YAAE,OAAO,YAAY,CAAC;QACtC,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAChF,IAAI,QAAQ,IAAI,SAAS,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;YACvD,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;QAChC,CAAC;QACD,OAAO,GAAG,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;IACjC,CAAC;IAEO,MAAM,CAAC,IAAoB;QACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG;YAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC1D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAEO,YAAY,CAAC,IAAY;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IAEO,aAAa,CAAC,KAAmB;QACvC,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YACzC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,OAAO;gBAC3B,CAAC,CAAC,gCAAgC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,OAAO,WAAW;gBAC7E,CAAC,CAAC,gCAAgC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC;YACvF,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,sCAAsC,CAAC;QAClE,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACtD,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,2CAA2C,CAAC;YAClE,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,qCAAqC,CAAC;QACjE,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,kCAAkC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YAC3E,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,kCAAkC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,wBAAwB,CAAC;YAC/C,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,uCAAuC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,eAAe,CAAC;QACzC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAEO,mBAAmB,CAAC,KAAkB;QAC5C,KAAK,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE;YAC3D,MAAM,KAAK,GAAG,WAAW,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,OAAO,EAAE,CAAC;YACzC,MAAM,KAAK,GAAiB;gBAC1B,EAAE,EAAE,UAAU,EAAE;gBAChB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC;YACF,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;YAC7B,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,KAAK,KAAK,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,OAAO,IAAI,IAAI,OAAO,MAAM,OAAO,EAAE,CAAC;YACnD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACtE,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,EAAE;YAC9B,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,WAAW,IAAI,IAAI,SAAS,UAAU,CAAC;YAC7D,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,qBAAqB,CAAC,CAAC,IAAI,EAAE,EAAE;YACnC,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;YACzF,IAAI,CAAC,YAAY,CAAC,qBAAqB,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3F,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,MAAM;iBACf,sBAAsB,CACrB,WAAW,IAAI,CAAC,WAAW,mBAAmB,IAAI,CAAC,IAAI,IAAI,EAC3D,SAAS,EACT,MAAM,CACP;iBACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACf,IAAI,MAAM,KAAK,SAAS;oBAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxD,IAAI,MAAM,KAAK,MAAM;oBAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAiB,MAAM,EAAE,eAAyB;QAC5D,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACtD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC;QAC5D,IAAI,QAAQ;YAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC;QAEzD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAC1B,eAAe,EAAE,QAAQ;YACzB,UAAU,EAAE,UAAU,IAAI,EAAE;YAC5B,kBAAkB,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS;SACtF,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QAEvB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAClC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EACpB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EACpB,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CACxB,CAAC;QACF,MAAM,WAAW,GAAG,uBAAuB,KAAK,CAAC,KAAK,WAAW,QAAQ,GAAG,CAAC;QAC7E,IAAI,CAAC,YAAY,CACf,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;YACrB,CAAC,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;YAC9E,CAAC,CAAC,gCAAgC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAC3D,CAAC;QACF,IAAI,CAAC,YAAY,CACf,QAAQ;YACN,CAAC,CAAC,wEAAwE;YAC1E,CAAC,CAAC,2CAA2C,CAChD,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,YAAY,CAAC,2CAA2C,UAAU,GAAG,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,gBAAgB,IAAI,6BAA6B,WAAW,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,MAAM,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAClD,KAAK,MAAM,CAAC,MAAM;aACf,sBAAsB,CAAC,oDAAoD,EAAE,YAAY,CAAC;aAC1F,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,IAAI,MAAM,KAAK,YAAY;gBAAE,KAAK,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEL,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,YAAY,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,QAAQ,CAAC,MAAc;QACrB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,YAAY,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,IAAY,EAAE,IAAa;QACnD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;QAED,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAS,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QACnE,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,QAAQ,IAAI,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAEpF,EAAE,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,OAAO,OAAO,IAAI,MAAM,MAAM,OAAO,EAAE,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACtE,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,gBAAgB,CAAC,CAAC,UAAU,EAAE,EAAE;YACjC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,WAAW,UAAU,IAAI,SAAS,UAAU,CAAC;YACnE,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QACzD,EAAE,CAAC,iBAAiB,CAAC,CAAC,MAAM,EAAE,EAAE;YAC9B,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,qCAAqC,MAAM,GAAG,CAAC,CAAC;YAClE,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,oDAAoD,CAAC,CAAC;QAClG,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACzB,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;YACrB,IAAI,CAAC,YAAY,CAAC,yCAAyC,CAAC,CAAC;YAC7D,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kCAAkC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEH,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QAEnB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,CAAC;YAC/C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;QACpD,IAAI,CAAC,YAAY,CACf,EAAE,KAAK,SAAS;YACd,CAAC,CAAC,gBAAgB,IAAI,OAAO,WAAW,qBAAqB;YAC7D,CAAC,CAAC,UAAU,IAAI,OAAO,WAAW,EAAE,CACvC,CAAC;QACF,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;QAC1E,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC;QACzC,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;QACnB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,KAAK;YAAE,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,QAAQ,CAAC,OAAe;QACtB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC;gBACV,EAAE,EAAE,UAAU,EAAE;gBAChB,IAAI,EAAE,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,OAAO,EAAE;gBAC9C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,IAAI,EAAE,MAAM;aACb,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjF,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC;gBACV,EAAE,EAAE,UAAU,EAAE;gBAChB,IAAI,EAAE,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,OAAO,EAAE;gBAC9C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,IAAI,EAAE,MAAM;aACb,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,iCAAiC;IACjC,UAAU,CAAC,OAAe;QACxB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,YAAY,CACf,0BAA0B,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CACnF,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,kBAAkB,CAAC,OAAe,EAAE,OAA6B,MAAM;QACrE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,KAAK,GAAiB;YAC1B,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,UAAU;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU;YAC1B,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE;YACjD,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,SAAS,CACnB,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,EACvE,IAAI,EACJ,CAAC,CACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;IAC9B,CAAC;CACF"} \ No newline at end of file diff --git a/packages/vscode/dist/extension.js b/packages/vscode/dist/extension.js index 30cd519..88da4e9 100644 --- a/packages/vscode/dist/extension.js +++ b/packages/vscode/dist/extension.js @@ -44,23 +44,83 @@ export function activate(context) { return; const name = await vscode.window.showInputBox({ title: "Display name", - prompt: "Optional — shown to collaborators", + prompt: "Required — shown to collaborators (cannot be empty)", ignoreFocusOut: true, + value: vscode.workspace.getConfiguration("chorus").get("displayName") || "", }); + if (name !== undefined && !name.trim()) { + void vscode.window.showErrorMessage("Display name is required."); + return; + } await controller.join(token.trim(), host.trim(), name?.trim() || undefined); output.show(true); - void vscode.window.showInformationMessage("Joined Chorus session"); + const mode = controller.getMode(); + void vscode.window.showInformationMessage(mode === "pending" ? "Connected — waiting for host approval" : "Joined Chorus session"); } catch (err) { void vscode.window.showErrorMessage(`Chorus join failed: ${String(err)}`); } })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.approve", async () => { + try { + const pending = controller.getPendingUsers(); + if (!pending.length) { + const userId = await vscode.window.showInputBox({ + title: "Approve joiner", + prompt: "Pending user id", + ignoreFocusOut: true, + }); + if (!userId) + return; + controller.approveUser(userId.trim()); + return; + } + const pick = await vscode.window.showQuickPick(pending.map((u) => ({ + label: u.displayName, + description: `${u.role} · ${u.userId}`, + userId: u.userId, + })), { title: "Approve joiner" }); + if (!pick) + return; + controller.approveUser(pick.userId); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + })); + context.subscriptions.push(vscode.commands.registerCommand("chorus.deny", async () => { + try { + const pending = controller.getPendingUsers(); + if (!pending.length) { + const userId = await vscode.window.showInputBox({ + title: "Deny joiner", + prompt: "Pending user id", + ignoreFocusOut: true, + }); + if (!userId) + return; + controller.denyUser(userId.trim()); + return; + } + const pick = await vscode.window.showQuickPick(pending.map((u) => ({ + label: u.displayName, + description: `${u.role} · ${u.userId}`, + userId: u.userId, + })), { title: "Deny joiner" }); + if (!pick) + return; + controller.denyUser(pick.userId); + } + catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + })); context.subscriptions.push(vscode.commands.registerCommand("chorus.leave", async () => { await controller.leave(); void vscode.window.showInformationMessage("Left Chorus session"); })); - context.subscriptions.push(vscode.commands.registerCommand("chorus.stop", () => { - controller.stop(); + context.subscriptions.push(vscode.commands.registerCommand("chorus.stop", async () => { + await controller.stop(); void vscode.window.showInformationMessage("Stopped Chorus sharing"); })); context.subscriptions.push(vscode.commands.registerCommand("chorus.chat", async () => { diff --git a/packages/vscode/dist/extension.js.map b/packages/vscode/dist/extension.js.map index a27b22e..5d7db3b 100644 --- a/packages/vscode/dist/extension.js.map +++ b/packages/vscode/dist/extension.js.map @@ -1 +1 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/vscode/package.json b/packages/vscode/package.json index dd869da..7acd3d9 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -20,6 +20,8 @@ "onCommand:chorus.status", "onCommand:chorus.sendPrompt", "onCommand:chorus.publishHostMessage", + "onCommand:chorus.approve", + "onCommand:chorus.deny", "onView:chorus.session" ], "main": "./dist/extension.js", @@ -69,6 +71,16 @@ "command": "chorus.openSession", "title": "Chorus: Open Session Panel", "category": "Chorus" + }, + { + "command": "chorus.approve", + "title": "Chorus: Approve Joiner", + "category": "Chorus" + }, + { + "command": "chorus.deny", + "title": "Chorus: Deny Joiner", + "category": "Chorus" } ], "configuration": { @@ -82,7 +94,22 @@ "chorus.displayName": { "type": "string", "default": "", - "description": "Display name shown to collaborators (defaults to OS username)." + "description": "Display name shown to collaborators (required non-empty; defaults to OS username)." + }, + "chorus.requireApproval": { + "type": "boolean", + "default": true, + "description": "When sharing, hold joiners in pending until Approve/Deny (matches OpenCode plugin default)." + }, + "chorus.email": { + "type": "string", + "default": "", + "description": "Joiner email sent on auth when the host enabled an allowedEmailDomain gate." + }, + "chorus.allowedEmailDomain": { + "type": "string", + "default": "", + "description": "When sharing, require joiners to authenticate with an email at this domain." }, "chorus.relayBin": { "type": "string", diff --git a/packages/vscode/src/controller.ts b/packages/vscode/src/controller.ts index 713c628..7c1d943 100644 --- a/packages/vscode/src/controller.ts +++ b/packages/vscode/src/controller.ts @@ -6,10 +6,12 @@ import { relayOptionsFromEnv, type JoinState, } from "@chorus/client"; -import type { SessionEvent, UserRole } from "@chorus/shared"; +import type { ConnectedUser, SessionEvent, UserRole } from "@chorus/shared"; +import { normalizeDisplayName } from "@chorus/shared"; import { formatSessionLine, newEventId } from "./format.js"; +import { detectRepoRemote } from "./git.js"; -export type ChorusMode = "idle" | "sharing" | "joined"; +export type ChorusMode = "idle" | "sharing" | "joined" | "pending"; export type TranscriptLine = { id: string; @@ -30,13 +32,15 @@ function getLanIp(): string { /** * Host/joiner controller for the VS Code adapter. - * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin. + * Speaks the same `/host` + `/ws` contracts as the OpenCode plugin, including + * session access control (approval, required name, optional repo gate). */ export class ChorusController { private mode: ChorusMode = "idle"; private relay: RelayServer | null = null; private joinClient: JoinClient | null = null; private sessionId = `vscode-${Date.now().toString(36)}`; + private pendingUsers: ConnectedUser[] = []; private readonly transcript: TranscriptLine[] = []; private readonly _onDidChange = new vscode.EventEmitter(); readonly onDidChange = this._onDidChange.event; @@ -56,6 +60,10 @@ export class ChorusController { return this.transcript; } + getPendingUsers(): readonly ConnectedUser[] { + return this.pendingUsers; + } + getJoinState(): JoinState | null { return this.joinClient?.getState() ?? null; } @@ -66,6 +74,7 @@ export class ChorusController { port?: number; host?: string; external?: boolean; + pending?: number; } { if (!this.relay || this.mode !== "sharing") return { sharing: false }; return { @@ -74,6 +83,7 @@ export class ChorusController { port: this.relay.getPort(), host: this.relay.getHost(), external: this.relay.isExternal(), + pending: this.pendingUsers.length, }; } @@ -82,15 +92,22 @@ export class ChorusController { } private displayName(): string { - const configured = this.cfg().get("displayName")?.trim(); - if (configured) return configured; - return process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"; + const configured = this.cfg().get("displayName"); + const normalized = normalizeDisplayName(configured); + if (normalized) return normalized; + const fallback = normalizeDisplayName(process.env["USER"] ?? process.env["USERNAME"] ?? "vscode"); + if (!fallback) throw new Error("A non-empty display name is required (set chorus.displayName)."); + return fallback; } private defaultPort(): number { return this.cfg().get("port") ?? 7742; } + private requireApprovalDefault(): boolean { + return this.cfg().get("requireApproval") !== false; + } + private publicJoinHost(port: number, relayHost: string, external: boolean): string { const fromSettings = this.cfg().get("publicHost")?.trim(); if (fromSettings) return fromSettings; @@ -120,8 +137,14 @@ export class ChorusController { private refreshStatus(): void { if (this.mode === "sharing" && this.relay) { - this.statusBar.text = `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; + const pending = this.pendingUsers.length; + this.statusBar.text = pending + ? `$(broadcast) Chorus sharing :${this.relay.getPort()} (${pending} pending)` + : `$(broadcast) Chorus sharing :${this.relay.getPort()} (${this.relay.clientCount})`; this.statusBar.tooltip = "Chorus is sharing — click for status"; + } else if (this.mode === "pending" && this.joinClient) { + this.statusBar.text = "$(watch) Chorus waiting for host approval"; + this.statusBar.tooltip = "Connected but pending host approval"; } else if (this.mode === "joined" && this.joinClient) { const st = this.joinClient.getState(); this.statusBar.text = `$(organization) Chorus joined (${st.users.length})`; @@ -134,8 +157,49 @@ export class ChorusController { this._onDidChange.fire(); } - async share(role: UserRole = "edit"): Promise { - if (this.mode === "joined") { + private ensureRelayHandlers(relay: RelayServer): void { + relay.setInputHandler(async (content, userId, displayName) => { + const label = displayName ?? userId.slice(0, 8); + const labeled = `[${label}]: ${content}`; + const event: SessionEvent = { + id: newEventId(), + sessionId: this.sessionId, + type: "user", + payload: labeled, + timestamp: Date.now(), + }; + this.appendSession(event); + this.relay?.pushEvent(event); + void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); + }); + relay.setChatHandler((name, content) => { + const text = `💬 [${name ?? "guest"}]: ${content}`; + this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); + void vscode.window.showInformationMessage(text); + }); + relay.setTypingHandler((name) => { + this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; + setTimeout(() => this.refreshStatus(), 2000).unref?.(); + }); + relay.setUserPendingHandler((user) => { + this.pendingUsers = [...this.pendingUsers.filter((u) => u.userId !== user.userId), user]; + this.appendSystem(`Join request from ${user.displayName} (${user.role}) — ${user.userId}`); + this.refreshStatus(); + void vscode.window + .showInformationMessage( + `Chorus: ${user.displayName} wants to join (${user.role}).`, + "Approve", + "Deny" + ) + .then((choice) => { + if (choice === "Approve") this.approveUser(user.userId); + if (choice === "Deny") this.denyUser(user.userId); + }); + }); + } + + async share(role: UserRole = "edit", requireApproval?: boolean): Promise { + if (this.mode === "joined" || this.mode === "pending") { await this.leave(); } @@ -145,35 +209,22 @@ export class ChorusController { const { port, opts } = relayOptionsFromEnv(this.defaultPort()); if (!this.relay) { this.relay = new RelayServer(port, opts); - this.relay.setInputHandler(async (content, userId, displayName) => { - const label = displayName ?? userId.slice(0, 8); - const labeled = `[${label}]: ${content}`; - const event: SessionEvent = { - id: newEventId(), - sessionId: this.sessionId, - type: "user", - payload: labeled, - timestamp: Date.now(), - }; - this.appendSession(event); - this.relay?.pushEvent(event); - void vscode.window.showInformationMessage(`Chorus prompt from ${label}: ${content}`); - }); - this.relay.setChatHandler((name, content) => { - const text = `💬 [${name ?? "guest"}]: ${content}`; - this.append({ id: newEventId(), text, at: Date.now(), kind: "chat" }); - void vscode.window.showInformationMessage(text); - }); - this.relay.setTypingHandler((name) => { - this.statusBar.text = `$(edit) ${name ?? "someone"} typing…`; - setTimeout(() => this.refreshStatus(), 2000).unref?.(); - }); + this.ensureRelayHandlers(this.relay); } if (!this.relay.isRunning) { await this.relay.start(); } + const approval = requireApproval ?? this.requireApprovalDefault(); + const repoRemote = detectRepoRemote(); + this.relay.setSessionPolicy({ + requireApproval: approval, + repoRemote: repoRemote ?? "", + allowedEmailDomain: this.cfg().get("allowedEmailDomain")?.trim() || undefined, + }); + this.pendingUsers = []; + this.mode = "sharing"; const token = await this.relay.issueToken(this.sessionId, role); const joinHost = this.publicJoinHost( @@ -187,20 +238,47 @@ export class ChorusController { ? `Attached to external relay ${this.relay.getHost()}:${this.relay.getPort()}` : `chorus-relay started on port ${this.relay.getPort()}` ); + this.appendSystem( + approval + ? "Joiners wait for your approval (Chorus: Approve Joiner / Deny Joiner)." + : "Auto-admit is on (requireApproval=false)." + ); + if (repoRemote) { + this.appendSystem(`Repo gate on: joiners must share origin ${repoRemote}.`); + } this.appendSystem(`Share ready (${role}). Collaborator command:\n${joinCommand}`); this.refreshStatus(); await vscode.env.clipboard.writeText(joinCommand); - void vscode.window.showInformationMessage( - `Chorus sharing — join command copied to clipboard.`, - "Copy again" - ).then((choice) => { - if (choice === "Copy again") void vscode.env.clipboard.writeText(joinCommand); - }); + void vscode.window + .showInformationMessage(`Chorus sharing — join command copied to clipboard.`, "Copy again") + .then((choice) => { + if (choice === "Copy again") void vscode.env.clipboard.writeText(joinCommand); + }); return joinCommand; } + approveUser(userId: string): void { + if (!this.relay || this.mode !== "sharing") { + throw new Error("Share a session first to approve joiners."); + } + this.relay.approveUser(userId); + this.pendingUsers = this.pendingUsers.filter((u) => u.userId !== userId); + this.appendSystem(`Approved ${userId}`); + this.refreshStatus(); + } + + denyUser(userId: string): void { + if (!this.relay || this.mode !== "sharing") { + throw new Error("Share a session first to deny joiners."); + } + this.relay.denyUser(userId); + this.pendingUsers = this.pendingUsers.filter((u) => u.userId !== userId); + this.appendSystem(`Denied ${userId}`); + this.refreshStatus(); + } + async join(token: string, host: string, name?: string): Promise { if (this.mode === "sharing") { throw new Error("Stop sharing (Chorus: Stop Sharing) before joining another session."); @@ -210,9 +288,10 @@ export class ChorusController { this.joinClient = null; } - const displayName = name?.trim() || this.displayName(); - const jc = new JoinClient(`ws://${host}/ws`, token, displayName); - await jc.connect(); + const displayName = normalizeDisplayName(name) ?? this.displayName(); + const repoRemote = detectRepoRemote(); + const email = this.cfg().get("email")?.trim() || undefined; + const jc = new JoinClient(`ws://${host}/ws`, token, displayName, repoRemote, email); jc.setChatHandler((msgName, content) => { const text = `💬 [${msgName ?? "host"}]: ${content}`; @@ -224,29 +303,50 @@ export class ChorusController { setTimeout(() => this.refreshStatus(), 2000).unref?.(); }); jc.setEventHandler((event) => this.appendSession(event)); + jc.setPendingHandler((userId) => { + this.mode = "pending"; + this.appendSystem(`Waiting for host approval (userId=${userId})`); + this.refreshStatus(); + void vscode.window.showInformationMessage("Chorus: waiting for the host to approve your join."); + }); + jc.setApprovedHandler(() => { + this.mode = "joined"; + this.appendSystem("Host approved — you are in the session."); + this.refreshStatus(); + void vscode.window.showInformationMessage("Chorus: host approved your join."); + }); + + await jc.connect(); for (const event of jc.getState().recentEvents) { this.appendSession(event); } this.joinClient = jc; - this.mode = "joined"; - this.appendSystem(`Joined ${host} as ${displayName}`); + const st = jc.getState().status; + this.mode = st === "pending" ? "pending" : "joined"; + this.appendSystem( + st === "pending" + ? `Connected to ${host} as ${displayName} — pending approval` + : `Joined ${host} as ${displayName}` + ); this.refreshStatus(); } async leave(): Promise { this.joinClient?.disconnect(); this.joinClient = null; - if (this.mode === "joined") this.mode = "idle"; + if (this.mode === "joined" || this.mode === "pending") this.mode = "idle"; this.appendSystem("Left shared session"); this.refreshStatus(); } - stop(): void { + async stop(): Promise { this.mode = "idle"; - this.relay?.stop(); + this.pendingUsers = []; + const relay = this.relay; this.relay = null; + if (relay) await relay.stop(); this.appendSystem("Stopped sharing"); this.refreshStatus(); } @@ -273,16 +373,24 @@ export class ChorusController { }); return; } + if (this.mode === "pending") { + throw new Error("Still waiting for host approval — chat is blocked until then."); + } throw new Error("Not currently sharing or joined."); } /** Joiner → host collab.input */ sendPrompt(content: string): void { - if (this.mode !== "joined" || !this.joinClient) { + if (!this.joinClient) { throw new Error("Join a session first to send prompts to the host."); } + if (this.joinClient.getState().status !== "connected") { + throw new Error("Cannot send prompts while pending host approval."); + } this.joinClient.sendInput(content); - this.appendSystem(`→ sent prompt to host (${content.slice(0, 80)}${content.length > 80 ? "…" : ""})`); + this.appendSystem( + `→ sent prompt to host (${content.slice(0, 80)}${content.length > 80 ? "…" : ""})` + ); } /** Host publishes a user/assistant line onto the shared transcript. */ @@ -306,12 +414,16 @@ export class ChorusController { const join = this.joinClient ? { joined: true, ...this.joinClient.getState() } : { joined: false }; - return JSON.stringify({ mode: this.mode, ...share, ...join }, null, 2); + return JSON.stringify( + { mode: this.mode, pendingUsers: this.pendingUsers, ...share, ...join }, + null, + 2 + ); } dispose(): void { this.joinClient?.disconnect(); - this.relay?.stop(); + void this.relay?.stop(); this._onDidChange.dispose(); } } diff --git a/packages/vscode/src/extension.ts b/packages/vscode/src/extension.ts index 6ee7d53..fe56c82 100644 --- a/packages/vscode/src/extension.ts +++ b/packages/vscode/src/extension.ts @@ -60,19 +60,87 @@ export function activate(context: vscode.ExtensionContext): void { const name = await vscode.window.showInputBox({ title: "Display name", - prompt: "Optional — shown to collaborators", + prompt: "Required — shown to collaborators (cannot be empty)", ignoreFocusOut: true, + value: vscode.workspace.getConfiguration("chorus").get("displayName") || "", }); + if (name !== undefined && !name.trim()) { + void vscode.window.showErrorMessage("Display name is required."); + return; + } await controller.join(token.trim(), host.trim(), name?.trim() || undefined); output.show(true); - void vscode.window.showInformationMessage("Joined Chorus session"); + const mode = controller.getMode(); + void vscode.window.showInformationMessage( + mode === "pending" ? "Connected — waiting for host approval" : "Joined Chorus session" + ); } catch (err) { void vscode.window.showErrorMessage(`Chorus join failed: ${String(err)}`); } }) ); + context.subscriptions.push( + vscode.commands.registerCommand("chorus.approve", async () => { + try { + const pending = controller.getPendingUsers(); + if (!pending.length) { + const userId = await vscode.window.showInputBox({ + title: "Approve joiner", + prompt: "Pending user id", + ignoreFocusOut: true, + }); + if (!userId) return; + controller.approveUser(userId.trim()); + return; + } + const pick = await vscode.window.showQuickPick( + pending.map((u) => ({ + label: u.displayName, + description: `${u.role} · ${u.userId}`, + userId: u.userId, + })), + { title: "Approve joiner" } + ); + if (!pick) return; + controller.approveUser(pick.userId); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("chorus.deny", async () => { + try { + const pending = controller.getPendingUsers(); + if (!pending.length) { + const userId = await vscode.window.showInputBox({ + title: "Deny joiner", + prompt: "Pending user id", + ignoreFocusOut: true, + }); + if (!userId) return; + controller.denyUser(userId.trim()); + return; + } + const pick = await vscode.window.showQuickPick( + pending.map((u) => ({ + label: u.displayName, + description: `${u.role} · ${u.userId}`, + userId: u.userId, + })), + { title: "Deny joiner" } + ); + if (!pick) return; + controller.denyUser(pick.userId); + } catch (err) { + void vscode.window.showErrorMessage(String(err)); + } + }) + ); + context.subscriptions.push( vscode.commands.registerCommand("chorus.leave", async () => { await controller.leave(); @@ -81,8 +149,8 @@ export function activate(context: vscode.ExtensionContext): void { ); context.subscriptions.push( - vscode.commands.registerCommand("chorus.stop", () => { - controller.stop(); + vscode.commands.registerCommand("chorus.stop", async () => { + await controller.stop(); void vscode.window.showInformationMessage("Stopped Chorus sharing"); }) ); diff --git a/packages/vscode/src/git.ts b/packages/vscode/src/git.ts new file mode 100644 index 0000000..266eca7 --- /dev/null +++ b/packages/vscode/src/git.ts @@ -0,0 +1,19 @@ +import { execFileSync } from "node:child_process"; +import * as vscode from "vscode"; + +/** Best-effort `git remote get-url origin` for the active workspace folder. */ +export function detectRepoRemote(): string | undefined { + const folder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + if (!folder) return undefined; + try { + const out = execFileSync("git", ["remote", "get-url", "origin"], { + cwd: folder, + encoding: "utf8", + stdio: ["ignore", "pipe", "ignore"], + timeout: 3000, + }).trim(); + return out || undefined; + } catch { + return undefined; + } +} diff --git a/scripts/security-e2e.ts b/scripts/security-e2e.ts index a10229e..0ea9fd4 100644 --- a/scripts/security-e2e.ts +++ b/scripts/security-e2e.ts @@ -9,7 +9,7 @@ import { readFileSync, existsSync } from "node:fs"; import { join as pathJoin, resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; -import { JoinClient } from "../packages/plugin/src/join/index.js"; +import { JoinClient } from "../packages/client/src/index.ts"; import { detectRepoRemote } from "../packages/plugin/src/git.js"; const REPO = resolve(dirname(fileURLToPath(import.meta.url)), ".."); diff --git a/scripts/vscode-e2e.ts b/scripts/vscode-e2e.ts new file mode 100644 index 0000000..0b0f241 --- /dev/null +++ b/scripts/vscode-e2e.ts @@ -0,0 +1,93 @@ +#!/usr/bin/env bun +/** + * VS Code adapter integration: same JoinClient + RelayServer path the + * extension uses (share policy, pending admit, email gate, collab.input). + * Does not require a VS Code GUI. + */ +import { JoinClient, RelayServer } from "../packages/client/src/index.ts"; + +const PORT = parseInt(process.env["CHORUS_VSCODE_E2E_PORT"] ?? "18742", 10); + +async function expectReject(p: Promise, label: string): Promise { + try { + await p; + throw new Error(`expected ${label} to fail`); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (/expected .+ to fail/.test(msg)) throw err; + console.log(` ${label}: ${msg}`); + } +} + +async function waitUntil(fn: () => boolean, label: string, ms = 8000): Promise { + const deadline = Date.now() + ms; + while (Date.now() < deadline) { + if (fn()) return; + await new Promise((r) => setTimeout(r, 40)); + } + throw new Error(`timeout: ${label}`); +} + +async function main() { + const relay = new RelayServer(PORT); + await relay.start(); + console.log(`✓ relay on :${PORT}`); + + try { + relay.setSessionPolicy({ + requireApproval: true, + allowedEmailDomain: "chorus.test", + }); + + const token = (await relay.issueToken("vscode-e2e", "edit")).token; + + console.log("→ reject wrong email"); + const bad = new JoinClient(`ws://127.0.0.1:${PORT}/ws`, token, "Eve", undefined, "eve@other.com"); + await expectReject(bad.connect(), "wrong-email"); + + const pendingIds: string[] = []; + relay.setUserPendingHandler((u) => pendingIds.push(u.userId)); + const received: string[] = []; + relay.setInputHandler(async (content) => { + received.push(content); + }); + + console.log("→ join with matching email (pending)"); + const jc = new JoinClient( + `ws://127.0.0.1:${PORT}/ws`, + token, + "VscodeJoiner", + undefined, + "dev@chorus.test" + ); + await jc.connect(); + if (jc.getState().status !== "pending") { + throw new Error(`expected pending, got ${jc.getState().status}`); + } + await waitUntil(() => pendingIds.length > 0, "host saw pending"); + console.log(`✓ pending userId=${pendingIds[0]}`); + + jc.sendInput("should-not-land"); + await new Promise((r) => setTimeout(r, 120)); + if (received.length !== 0) throw new Error("collab.input leaked while pending"); + + console.log("→ approve"); + relay.approveUser(pendingIds[0]!); + await waitUntil(() => jc.getState().status === "connected", "joiner admitted"); + console.log("✓ admitted"); + + jc.sendInput("from-vscode-adapter"); + await waitUntil(() => received.includes("from-vscode-adapter"), "collab.input"); + console.log("✓ collab.input after approve"); + + jc.disconnect(); + console.log("\nVS Code adapter e2e passed."); + } finally { + await relay.stop(); + } +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/scripts/vscode-relay-e2e.ts b/scripts/vscode-relay-e2e.ts new file mode 100644 index 0000000..4c307cb --- /dev/null +++ b/scripts/vscode-relay-e2e.ts @@ -0,0 +1,309 @@ +#!/usr/bin/env bun +/** + * Cross-adapter relay e2e — exercises the same `@chorus/client` stack the VS Code + * extension and OpenCode terminal plugin share. + * + * Three cloud-environment roles (set CHORUS_E2E_ROLE): + * host-vscode — env1: VS Code-style host (RelayServer + email/approval policy) + * joiner-vscode — env2: VS Code-style joiner (JoinClient, approved, collab.input) + * disallowed-joiner — env3: join attempt rejected (wrong email domain) + * + * Default role `local` runs all scenarios in one process: + * 1. Three-env gate (host vscode + joiner vscode + disallowed joiner) + * 2. VS Code host relay joined by terminal (OpenCode) JoinClient + * 3. Terminal host relay joined by VS Code JoinClient + * + * Coordination file: CHORUS_E2E_STATE (default /tmp/chorus-vscode-relay-e2e.json) + */ +import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { dirname } from "node:path"; +import { JoinClient, RelayServer } from "../packages/client/src/index.ts"; + +type E2eState = { + port: number; + token: string; + host: string; + allowedEmailDomain: string; + pendingUserId?: string; + phase: "host-ready" | "joiner-done" | "disallowed-done" | "complete"; +}; + +const STATE_PATH = process.env["CHORUS_E2E_STATE"] ?? "/tmp/chorus-vscode-relay-e2e.json"; +const ROLE = process.env["CHORUS_E2E_ROLE"] ?? "local"; +const PORT = parseInt(process.env["CHORUS_VSCODE_RELAY_E2E_PORT"] ?? "18743", 10); +const EMAIL_DOMAIN = "chorus.test"; + +function sleep(ms: number): Promise { + return new Promise((r) => setTimeout(r, ms)); +} + +async function waitUntil(fn: () => boolean, label: string, ms = 12_000): Promise { + const deadline = Date.now() + ms; + while (Date.now() < deadline) { + if (fn()) return; + await sleep(40); + } + throw new Error(`timeout: ${label}`); +} + +async function expectReject(p: Promise, label: string): Promise { + try { + await p; + throw new Error(`expected ${label} to fail`); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (/expected .+ to fail/.test(msg)) throw err; + console.log(` ${label}: ${msg.slice(0, 120)}`); + } +} + +function readState(): E2eState { + if (!existsSync(STATE_PATH)) { + throw new Error(`Missing state file ${STATE_PATH} — run host-vscode first`); + } + return JSON.parse(readFileSync(STATE_PATH, "utf8")) as E2eState; +} + +function writeState(state: E2eState): void { + mkdirSync(dirname(STATE_PATH), { recursive: true }); + writeFileSync(STATE_PATH, JSON.stringify(state, null, 2)); +} + +/** VS Code extension share path: RelayServer + session policy + token issue. */ +async function vscodeHostShare(relay: RelayServer): Promise<{ token: string; port: number }> { + relay.setSessionPolicy({ + requireApproval: true, + allowedEmailDomain: EMAIL_DOMAIN, + }); + const token = (await relay.issueToken("vscode-relay-e2e", "edit")).token; + return { token, port: relay.getPort() }; +} + +async function runHostVscode(): Promise { + const relay = new RelayServer(PORT); + await relay.start(); + console.log(`[env1 host-vscode] relay listening on 127.0.0.1:${PORT}`); + + const { token, port } = await vscodeHostShare(relay); + writeState({ + port, + token, + host: "127.0.0.1", + allowedEmailDomain: EMAIL_DOMAIN, + phase: "host-ready", + }); + console.log(`[env1 host-vscode] token issued — waiting for joiners (state → ${STATE_PATH})`); + + await waitUntil(() => { + const s = readState(); + return s.phase === "complete"; + }, "all joiner phases"); + + await relay.stop(); + console.log("[env1 host-vscode] complete"); +} + +async function runJoinerVscode(): Promise { + const state = readState(); + if (state.phase !== "host-ready" && state.phase !== "joiner-done") { + await waitUntil(() => readState().phase === "host-ready", "host-ready"); + } + const { port, token } = readState(); + + console.log(`[env2 joiner-vscode] connecting to ws://127.0.0.1:${port}/ws`); + const jc = new JoinClient( + `ws://127.0.0.1:${port}/ws`, + token, + "VscodeJoiner", + undefined, + `dev@${EMAIL_DOMAIN}` + ); + await jc.connect(); + if (jc.getState().status !== "pending") { + throw new Error(`expected pending, got ${jc.getState().status}`); + } + console.log(`[env2 joiner-vscode] pending userId=${jc.getState().userId}`); + + writeState({ ...readState(), pendingUserId: jc.getState().userId, phase: "host-ready" }); + + // Host-side approve happens in local orchestrator or manual step; poll until connected. + await waitUntil(() => jc.getState().status === "connected", "host approved joiner", 20_000); + console.log("[env2 joiner-vscode] admitted"); + + jc.sendInput("prompt-from-vscode-joiner"); + await sleep(200); + jc.disconnect(); + + writeState({ ...readState(), phase: "joiner-done" }); + console.log("[env2 joiner-vscode] complete"); +} + +async function runDisallowedJoiner(): Promise { + await waitUntil(() => { + const s = existsSync(STATE_PATH) ? readState() : null; + return Boolean(s && s.phase === "host-ready"); + }, "host-ready for disallowed attempt"); + + const { port, token } = readState(); + console.log("[env3 disallowed-joiner] attempting wrong-email join"); + const bad = new JoinClient( + `ws://127.0.0.1:${port}/ws`, + token, + "BlockedUser", + undefined, + "intruder@other.test" + ); + await expectReject(bad.connect(), "wrong-email-domain"); + writeState({ ...readState(), phase: "disallowed-done" }); + console.log("[env3 disallowed-joiner] rejected as expected"); +} + +async function runLocal(): Promise { + console.log("=== Scenario A: three-env gate (host vscode / joiner vscode / disallowed) ==="); + const relay = new RelayServer(PORT); + await relay.start(); + + const pendingIds: string[] = []; + const hostInputs: string[] = []; + relay.setUserPendingHandler((u) => pendingIds.push(u.userId)); + relay.setInputHandler(async (content) => { + hostInputs.push(content); + }); + + try { + const { token } = await vscodeHostShare(relay); + const wsUrl = `ws://127.0.0.1:${PORT}/ws`; + + console.log("→ env3 disallowed joiner (wrong email)"); + await expectReject( + new JoinClient(wsUrl, token, "Intruder", undefined, "bad@other.test").connect(), + "disallowed-email" + ); + console.log("✓ disallowed joiner rejected"); + + console.log("→ env2 joiner vscode (matching email, pending)"); + const vscodeJoiner = new JoinClient( + wsUrl, + token, + "VscodeJoiner", + undefined, + `alice@${EMAIL_DOMAIN}` + ); + await vscodeJoiner.connect(); + if (vscodeJoiner.getState().status !== "pending") { + throw new Error(`expected pending, got ${vscodeJoiner.getState().status}`); + } + await waitUntil(() => pendingIds.length > 0, "env1 host saw pending"); + console.log(`✓ env2 pending userId=${pendingIds[0]}`); + + relay.approveUser(pendingIds[0]!); + await waitUntil(() => vscodeJoiner.getState().status === "connected", "env2 admitted"); + vscodeJoiner.sendInput("from-vscode-joiner"); + await waitUntil(() => hostInputs.includes("from-vscode-joiner"), "collab.input from vscode joiner"); + console.log("✓ env2 collab.input delivered to env1 host"); + vscodeJoiner.disconnect(); + } finally { + await relay.stop(); + } + + console.log("\n=== Scenario B: VS Code host ← terminal joiner ==="); + { + const relay = new RelayServer(PORT + 1); + await relay.start(); + relay.setSessionPolicy({ requireApproval: false }); + const terminalInputs: string[] = []; + relay.setInputHandler(async (c) => terminalInputs.push(c)); + try { + const token = (await relay.issueToken("terminal-join", "edit")).token; + const terminalJoiner = new JoinClient(`ws://127.0.0.1:${PORT + 1}/ws`, token, "TerminalUser"); + await terminalJoiner.connect(); + terminalJoiner.sendInput("from-terminal-joiner"); + await waitUntil(() => terminalInputs.includes("from-terminal-joiner"), "terminal→vscode-host"); + console.log("✓ terminal joiner reached VS Code-style host relay"); + terminalJoiner.disconnect(); + } finally { + await relay.stop(); + } + } + + console.log("\n=== Scenario C: terminal host → VS Code joiner ==="); + { + const relay = new RelayServer(PORT + 2); + await relay.start(); + relay.setSessionPolicy({ requireApproval: false }); + const terminalHostInputs: string[] = []; + relay.setInputHandler(async (c) => terminalHostInputs.push(c)); + try { + const token = (await relay.issueToken("terminal-host", "edit")).token; + const vscodeJoiner = new JoinClient(`ws://127.0.0.1:${PORT + 2}/ws`, token, "VscodeJoiner"); + await vscodeJoiner.connect(); + vscodeJoiner.sendInput("from-vscode-to-terminal-host"); + await waitUntil( + () => terminalHostInputs.includes("from-vscode-to-terminal-host"), + "vscode→terminal-host" + ); + console.log("✓ VS Code joiner reached terminal-style host relay"); + vscodeJoiner.disconnect(); + } finally { + await relay.stop(); + } + } + + console.log("\n✓ vscode-relay-e2e passed (all scenarios)"); +} + +async function runDistributedOrchestrator(): Promise { + // When roles run on separate machines, host must approve after joiner-vscode connects. + if (ROLE === "host-vscode") { + const relay = new RelayServer(PORT); + await relay.start(); + + const pendingIds: string[] = []; + const hostInputs: string[] = []; + relay.setUserPendingHandler((u) => pendingIds.push(u.userId)); + relay.setInputHandler(async (content) => hostInputs.push(content)); + + const { token, port } = await vscodeHostShare(relay); + writeState({ + port, + token, + host: process.env["CHORUS_PUBLIC_HOST"]?.split(":")[0] ?? "127.0.0.1", + allowedEmailDomain: EMAIL_DOMAIN, + phase: "host-ready", + }); + + await waitUntil(() => readState().pendingUserId, "joiner pending"); + const userId = readState().pendingUserId!; + relay.approveUser(userId); + await waitUntil(() => hostInputs.length > 0, "collab.input from joiner"); + await waitUntil(() => readState().phase === "disallowed-done", "disallowed joiner phase"); + writeState({ ...readState(), phase: "complete" }); + await relay.stop(); + return; + } + + if (ROLE === "joiner-vscode") { + await runJoinerVscode(); + return; + } + + if (ROLE === "disallowed-joiner") { + await runDisallowedJoiner(); + return; + } + + throw new Error(`Unknown CHORUS_E2E_ROLE=${ROLE}`); +} + +async function main() { + if (ROLE === "local") { + await runLocal(); + return; + } + await runDistributedOrchestrator(); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); From 7ff7d6a725f184e64f5f49d93d403a6b099932c3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 31 Aug 2026 11:46:42 +0000 Subject: [PATCH 06/10] docs: update README and adapter docs for VS Code cross-adapter relay Document relay-first model, VS Code install, adapter e2e scripts, and three-environment test roles. Refresh STATUS, DECISIONS, and vscode README. Co-authored-by: Steven Roomberg --- CHANGELOG.md | 1 + README.md | 45 ++++++++++++++++++++++++++----- docs/DECISIONS.md | 2 +- docs/STATUS.md | 30 +++++++++++++-------- packages/vscode/README.md | 57 +++++++++++++++++++++++++++++++++------ 5 files changed, 109 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f1da0c..7dce10f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - VS Code extension (`packages/vscode`) — share/join/chat over the same relay protocol; Session sidebar + commands - Extract `@chorus/client` (`JoinClient` + `RelayServer`) shared by OpenCode plugin, VS Code, and future adapters - Cross-adapter relay e2e: VS Code host ↔ terminal joiner and terminal host ↔ VS Code joiner (`bun run test:vscode-relay-e2e`) +- Docs: README, STATUS, VS Code adapter README updated for relay-first cross-adapter model - Session access control: host approval, required display names, repo/email/domain gates (`session.policy` / `auth.pending` / `host.approve|deny`) - Hybrid OpenCode security e2e, VS Code adapter e2e, and Cloud Agent install script diff --git a/README.md b/README.md index 4e8ea86..f453737 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,17 @@ Collaborative OpenCode session sharing. Pair-program a live AI session from anot ## How it works -Chorus is an [OpenCode](https://github.com/sst/opencode) plugin (plus a VS Code adapter) and a **Rust WebSocket relay** (`chorus-relay`). +Chorus is an [OpenCode](https://github.com/sst/opencode) plugin, a **VS Code adapter**, and a **Rust WebSocket relay** (`chorus-relay`). The relay is the core: adapters are thin clients on the same `/host` + `/ws` wire protocol (`@chorus/shared`). ``` -Host runs opencode → plugin loads -Host runs: /chorus-share → plugin spawns chorus-relay + issues join token -Joiner runs: /chorus-join → connects to relay /ws -Joiner prompts → relay → host control channel → host session.prompt +Host adapter (OpenCode or VS Code) → spawns chorus-relay + issues join token via /host +Joiner adapter (OpenCode or VS Code) → connects to relay /ws +Joiner prompts → relay → host control channel → host session (OpenCode) or host panel (VS Code) ``` -Both sides need OpenCode + the chorus plugin. The host machine needs the `chorus-relay` binary on `PATH` or built in-repo (`target/release/chorus-relay`). Override with `CHORUS_RELAY_BIN`. +**OpenCode ↔ OpenCode** is the primary path (full LLM loop + transcript mirror). **VS Code** uses the same relay: it can host a session that terminal/OpenCode joiners connect to, or join a terminal/OpenCode host. VS Code does not drive OpenCode’s model when sharing — publish host/AI lines manually or pair with an OpenCode host. See [packages/vscode/README.md](packages/vscode/README.md). + +The host machine needs the `chorus-relay` binary on `PATH` or built in-repo (`target/release/chorus-relay`). Override with `CHORUS_RELAY_BIN`. ## Installation @@ -43,6 +44,16 @@ Then add to OpenCode config: } ``` +### VS Code adapter + +```sh +cargo build -p chorus-relay --release +bun install +bun run build:ts +``` + +In VS Code: **Extensions: Install from Location…** → `packages/vscode`, then **Chorus: Share Session** / **Join Session**. Details: [packages/vscode/README.md](packages/vscode/README.md). + ## Layout One monorepo, two ecosystems, one wire contract: @@ -107,6 +118,28 @@ For live mirrored context on joiners, open the **web UI** (not only `opencode at `opencode attach` works for driving the session, but OpenCode’s attach TUI often does not live-render plugin-injected transcript lines. +### Adapter & relay e2e (no GUI) + +Protocol-level tests for the shared `@chorus/client` stack (same code paths as the OpenCode plugin and VS Code extension): + +```sh +bun run test:vscode-e2e # VS Code adapter: email gate, pending approve, collab.input +bun run test:vscode-relay-e2e # cross-adapter: VS Code host ↔ terminal joiner (both directions) +bun run test:adapters-e2e # both of the above +bun run test:security-e2e # OpenCode host + protocol joiner (requires multi-agent up) +bun run test:network-e2e # CIDR / source-port allowlist on chorus-relay +``` + +**Three-environment relay test** (`test:vscode-relay-e2e`): models host vscode, joiner vscode, and a disallowed joiner. Run all scenarios locally (default), or split across machines with `CHORUS_E2E_ROLE`: + +| Env | Role | Command | +|-----|------|---------| +| env1 | host vscode | `CHORUS_E2E_ROLE=host-vscode bun scripts/vscode-relay-e2e.ts` | +| env2 | joiner vscode | `CHORUS_E2E_ROLE=joiner-vscode bun scripts/vscode-relay-e2e.ts` | +| env3 | disallowed joiner | `CHORUS_E2E_ROLE=disallowed-joiner bun scripts/vscode-relay-e2e.ts` | + +Coordination file: `CHORUS_E2E_STATE` (default `/tmp/chorus-vscode-relay-e2e.json`). + ## Configuration Chorus reads a layered **config file** plus environment variables. diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index e292275..3d0ed04 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -49,7 +49,7 @@ Recommended shape: - **v1:** OpenCode adapter = this repo’s plugin + local **Rust** `chorus-relay` - **v1.x:** keep `@chorus/shared` as the stable joiner + host-control contract; `@chorus/client` holds `JoinClient` / `RelayServer` for non-OpenCode hosts -- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) — same wire protocol, host-specific UI only. +- **v1.x adapters in-monorepo:** VS Code (`packages/vscode`) — same wire protocol and `@chorus/client` relay stack; host-specific UI only. Cross-adapter (VS Code host ↔ terminal joiner) is validated by `bun run test:vscode-relay-e2e`. - **v2:** optional further adapters (Codex app-server remains a strong candidate) once OpenCode UX is solid; split adapter packages into separate repos only when publish/CI ownership diverges **Do not** make Claude Code / Amp the primary host — large audiences, but proprietary control planes. Treat them as distribution adapters later, not the core. diff --git a/docs/STATUS.md b/docs/STATUS.md index f4bd433..f79917d 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,20 +1,21 @@ # Chorus status — what still needs to happen -Snapshot as of 2026-08-21 (toward `v2.0.0` network lockdown). Tests/typecheck/build are green. +Snapshot as of 2026-08-31 (post VS Code adapter rebase onto `v2.0.0`). Tests/typecheck/build are green. ## Current state -Chorus is an **OpenCode↔OpenCode** LAN collaboration stack: +Chorus is a **relay-first** LAN collaboration stack with two adapters on one wire protocol: -- Host: `/chorus-share` → spawns Rust `chorus-relay` + issues token via `/host` -- Joiner: `/chorus-join` → connects to relay `/ws`, forwards prompts into the host session -- Side channel: `/chorus-chat` + typing toasts +- **OpenCode** (terminal): `/chorus-share` → spawns Rust `chorus-relay` + issues token via `/host`; `/chorus-join` → `/ws`; full LLM loop + transcript mirror +- **VS Code** (`packages/vscode`): same `JoinClient` + `RelayServer` via `@chorus/client`; can host relay for terminal joiners or join a terminal host +- Side channel: `/chorus-chat` + typing toasts (OpenCode); VS Code panel chat - Optional S3/R2 backup of user events +- **v2.0.0 network lockdown**: CIDR allow/deny, bind policy, source-port allowlist ([docs/NETWORK.md](./NETWORK.md)) -The browser companion (`packages/web`) was intentionally removed. Joiners now mirror the host transcript into their OpenCode session (`[Host]:` / `[AI]:` lines via `noReply` inject); side-channel chat/typing remain toasts. +The browser companion (`packages/web`) was intentionally removed. Joiners mirror the host transcript into their OpenCode session (`[Host]:` / `[AI]:` lines via `noReply` inject); side-channel chat/typing remain toasts. The in-process Bun relay has been replaced by `crates/chorus-relay`. -**Editor adapters (in progress):** VS Code (`packages/vscode`). +**Editor adapters:** VS Code shipped in-repo (`packages/vscode`); Zed adapter deferred to a separate branch/PR. Differentiation vs nearby OpenCode plugins (`opencode-live`, `opencode-sessions`, `opencode-ensemble`, `opencode-relay`): those target **multi-agent / same-DB sync**. Chorus targets **multi-human** pair programming on one live AI session. @@ -66,21 +67,28 @@ Enterprise gap analysis (what would actually pass a security review vs what ship ### P2 — backup & polish -### P2 — backup & polish - 22. Backup AI + chat events; expose restore/list; set `endedAt` on stop. 23. Drop unused `@aws-sdk/lib-storage` or use it. 24. Broader tests: roles/view-forbid, kick/close, chat/typing, plugin entry, tunnel. 25. Native slash-command registration when [opencode#5305](https://github.com/sst/opencode/issues/5305) lands. +### Adapter e2e shipped + +- `bun run test:vscode-e2e` — VS Code path: email gate, pending approve, `collab.input` +- `bun run test:vscode-relay-e2e` — three-env gate (host vscode / joiner vscode / disallowed joiner) + VS Code ↔ terminal cross-adapter +- `bun run test:adapters-e2e` — both of the above +- `bun run test:security-e2e` — OpenCode host + protocol joiner (approval flow) +- `bun run test:network-e2e` — CIDR / source-port allowlist on `chorus-relay` + ## Local multi-agent harness `scripts/multi-agent.ts` (via `bun run multi-agent`) can spawn N isolated `opencode serve` instances with the Chorus plugin, then automate `/chorus-share` + `/chorus-join` through OpenCode’s `/session/:id/command` API. Also includes `relay-stress` for concurrent protocol joiners without OpenCode. ## Adapter surface (monorepo) -- **OpenCode** (`packages/plugin`) — primary host; full LLM loop + transcript mirror. -- **VS Code** (`packages/vscode`) — share/join via `@chorus/client`; sidebar transcript; joiner `collab.input` works against an OpenCode host. VS Code share does **not** drive OpenCode’s model — publish host lines manually or pair with OpenCode. +- **OpenCode** (`packages/plugin`) — primary host; full LLM loop + transcript mirror. Re-exports `@chorus/client` for relay/join. +- **VS Code** (`packages/vscode`) — share/join via `@chorus/client`; sidebar transcript; session access control (approval, email gate, repo gate). Can host relay for terminal joiners or join a terminal host. Does **not** drive OpenCode’s model when sharing — publish host lines manually or pair with OpenCode. +- **Shared client** (`packages/client`) — `JoinClient` + `RelayServer`; used by both adapters. UI is secondary; relay host/joiner interaction is the contract. ## Explicit non-goals (for now) diff --git a/packages/vscode/README.md b/packages/vscode/README.md index 7233f84..6fc2f81 100644 --- a/packages/vscode/README.md +++ b/packages/vscode/README.md @@ -2,12 +2,15 @@ VS Code adapter for [Chorus](../../README.md) — share or join a live collaborative AI session over `chorus-relay`. +The relay is the core; this extension is a thin client on the same `/host` + `/ws` protocol as the OpenCode terminal plugin (`@chorus/client` + `@chorus/shared`). + ## What it does | Command | Behavior | |---|---| -| **Chorus: Share Session** | Spawns/attaches `chorus-relay`, issues a join token, copies `/chorus-join …` to the clipboard | -| **Chorus: Join Session** | Connects to `/ws` with token + host | +| **Chorus: Share Session** | Spawns/attaches `chorus-relay`, sets session policy, issues a join token, copies `/chorus-join …` to the clipboard | +| **Chorus: Join Session** | Connects to `/ws` with token + host (+ optional display name / email) | +| **Chorus: Approve Joiner** / **Deny Joiner** | Host admits or rejects pending joiners (when `chorus.requireApproval` is on) | | **Chorus: Send Prompt to Host** | Joiner `collab.input` into the shared session | | **Chorus: Publish Host Message** | Host `session.event` fan-out to joiners | | **Chorus: Send Chat Message** | Side-channel chat (not LLM history) | @@ -15,11 +18,36 @@ VS Code adapter for [Chorus](../../README.md) — share or join a live collabora The **Chorus** activity-bar panel shows the mirrored transcript and a compose box. -## Honest scope (v1) +## Cross-adapter relay + +Both adapters speak the same wire protocol. Mix and match: + +| Host | Joiner | Notes | +|---|---|---| +| OpenCode (terminal) | OpenCode | Primary path — full LLM loop + transcript mirror | +| VS Code | OpenCode | VS Code hosts relay; terminal joiner sends `collab.input` | +| OpenCode | VS Code | Terminal hosts relay; VS Code joiner sends `collab.input` and receives session events | +| VS Code | VS Code | Same relay semantics; neither side drives an LLM unless paired with OpenCode | + +When **sharing from VS Code**, collaborator prompts appear in the panel/notifications. Publish host/AI lines manually (**Chorus: Publish Host Message**) or pair with an OpenCode host that owns the model. + +When **joining an OpenCode-hosted session**, prompts you send are real `collab.input` and the host transcript streams into the panel. + +Verify cross-adapter behavior without a GUI: + +```sh +# from repo root +bun run test:vscode-relay-e2e +``` + +## Session access control -- Speaks the same wire protocol as the OpenCode plugin (`@chorus/shared` + `@chorus/client`). -- VS Code is **not** an OpenCode host: it does not drive OpenCode’s LLM loop. When you **share** from VS Code, collaborator prompts appear in the panel/notifications; publish host/AI lines manually (or pair with an OpenCode host that owns the model). -- When you **join** an OpenCode-hosted session, prompts you send are real `collab.input` and the host transcript streams into the panel. +Matches the OpenCode plugin: + +- **Required display name** on join (empty names rejected) +- **Host approval** — `chorus.requireApproval` (default `true`); pending joiners trigger Approve/Deny notifications +- **Email domain gate** — set `chorus.allowedEmailDomain` when sharing; joiners set `chorus.email` +- **Repo gate** — when the workspace has a git `origin`, joiners must present the same remote ## Prerequisites @@ -44,11 +72,23 @@ Ensure `chorus-relay` is on `PATH`, or set `chorus.relayBin` / `CHORUS_RELAY_BIN | Setting | Default | Meaning | |---|---|---| | `chorus.port` | `7742` | Relay listen port when sharing | -| `chorus.displayName` | OS user | Name shown to peers | +| `chorus.displayName` | OS user | Name shown to peers (required non-empty) | +| `chorus.requireApproval` | `true` | Hold joiners in pending until Approve/Deny | +| `chorus.email` | — | Joiner email sent on auth (for email domain gate) | +| `chorus.allowedEmailDomain` | — | When sharing, require joiners at this domain | | `chorus.relayBin` | — | Path to `chorus-relay` | | `chorus.publicHost` | LAN IP:port | Advertised join host | -Env vars from the root README (`CHORUS_RELAY_HOST`, `CHORUS_HOST_TOKEN`, `CHORUS_EXTERNAL_RELAY`, …) still apply for Docker/external relays. +Env vars from the root README (`CHORUS_RELAY_HOST`, `CHORUS_HOST_TOKEN`, `CHORUS_EXTERNAL_RELAY`, network allowlists, …) still apply for Docker/external relays. + +## Testing + +```sh +bun run test:vscode-e2e # email gate, pending approve, collab.input +bun run test:vscode-relay-e2e # three-env gate + VS Code ↔ terminal cross-adapter +``` + +Multi-machine three-env roles: set `CHORUS_E2E_ROLE` to `host-vscode`, `joiner-vscode`, or `disallowed-joiner` (see root [README](../../README.md#adapter--relay-e2e-no-gui)). ## Layout @@ -58,4 +98,5 @@ packages/vscode/ src/controller.ts # JoinClient + RelayServer orchestration src/sessionView.ts # sidebar webview src/format.ts # transcript line formatting + src/git.ts # repo remote detection for repo gate ``` From 79405fd66a14031dc48029f5e77c6fb911f64a0d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 31 Aug 2026 11:47:15 +0000 Subject: [PATCH 07/10] chore: update dist [skip ci] --- packages/vscode/dist/git.d.ts | 2 ++ packages/vscode/dist/git.js | 21 +++++++++++++++++++++ packages/vscode/dist/git.js.map | 1 + 3 files changed, 24 insertions(+) create mode 100644 packages/vscode/dist/git.d.ts create mode 100644 packages/vscode/dist/git.js create mode 100644 packages/vscode/dist/git.js.map diff --git a/packages/vscode/dist/git.d.ts b/packages/vscode/dist/git.d.ts new file mode 100644 index 0000000..fab62e9 --- /dev/null +++ b/packages/vscode/dist/git.d.ts @@ -0,0 +1,2 @@ +/** Best-effort `git remote get-url origin` for the active workspace folder. */ +export declare function detectRepoRemote(): string | undefined; diff --git a/packages/vscode/dist/git.js b/packages/vscode/dist/git.js new file mode 100644 index 0000000..b01187b --- /dev/null +++ b/packages/vscode/dist/git.js @@ -0,0 +1,21 @@ +import { execFileSync } from "node:child_process"; +import * as vscode from "vscode"; +/** Best-effort `git remote get-url origin` for the active workspace folder. */ +export function detectRepoRemote() { + const folder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + if (!folder) + return undefined; + try { + const out = execFileSync("git", ["remote", "get-url", "origin"], { + cwd: folder, + encoding: "utf8", + stdio: ["ignore", "pipe", "ignore"], + timeout: 3000, + }).trim(); + return out || undefined; + } + catch { + return undefined; + } +} +//# sourceMappingURL=git.js.map \ No newline at end of file diff --git a/packages/vscode/dist/git.js.map b/packages/vscode/dist/git.js.map new file mode 100644 index 0000000..749d169 --- /dev/null +++ b/packages/vscode/dist/git.js.map @@ -0,0 +1 @@ +{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;IAClE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE;YAC/D,GAAG,EAAE,MAAM;YACX,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,GAAG,IAAI,SAAS,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"} \ No newline at end of file From 09f0fd4dd3623e146f83be6dd66c5e408d43bcb0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 31 Aug 2026 11:50:02 +0000 Subject: [PATCH 08/10] fix(vscode): show pending approval hint in session panel (from PR #3) Co-authored-by: Steven Roomberg --- packages/vscode/dist/sessionView.js | 2 +- packages/vscode/dist/sessionView.js.map | 2 +- packages/vscode/src/sessionView.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/vscode/dist/sessionView.js b/packages/vscode/dist/sessionView.js index 195c17d..f65ea67 100644 --- a/packages/vscode/dist/sessionView.js +++ b/packages/vscode/dist/sessionView.js @@ -87,7 +87,7 @@ export class SessionViewProvider { -
Mode: ${escapeHtml(mode)}
+
Mode: ${escapeHtml(mode)}${mode === "pending" ? " — waiting for host approval" : ""}
${body || "
Idle — Share or Join a Chorus session.
"}
diff --git a/packages/vscode/dist/sessionView.js.map b/packages/vscode/dist/sessionView.js.map index 4b6b3e7..6674579 100644 --- a/packages/vscode/dist/sessionView.js.map +++ b/packages/vscode/dist/sessionView.js.map @@ -1 +1 @@ -{"version":3,"file":"sessionView.js","sourceRoot":"","sources":["../src/sessionView.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sessionView.js","sourceRoot":"","sources":["../src/sessionView.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/vscode/src/sessionView.ts b/packages/vscode/src/sessionView.ts index 42d5455..8d08451 100644 --- a/packages/vscode/src/sessionView.ts +++ b/packages/vscode/src/sessionView.ts @@ -92,7 +92,9 @@ export class SessionViewProvider implements vscode.WebviewViewProvider { -
Mode: ${escapeHtml(mode)}
+
Mode: ${escapeHtml(mode)}${ + mode === "pending" ? " — waiting for host approval" : "" + }
${body || "
Idle — Share or Join a Chorus session.
"}
From 93973ccfbc81bff508e7c21d8d014132898289a5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 31 Aug 2026 13:05:24 +0000 Subject: [PATCH 09/10] docs: add VS Code walkthrough screenshots for PR demo Co-authored-by: Steven Roomberg --- docs/walkthrough/chorus_join_dialog.png | Bin 0 -> 50928 bytes docs/walkthrough/chorus_pending_approve.png | Bin 0 -> 663481 bytes docs/walkthrough/chorus_share_active.png | Bin 0 -> 63592 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/walkthrough/chorus_join_dialog.png create mode 100644 docs/walkthrough/chorus_pending_approve.png create mode 100644 docs/walkthrough/chorus_share_active.png diff --git a/docs/walkthrough/chorus_join_dialog.png b/docs/walkthrough/chorus_join_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..5c35f056726b72691ef09d4f4c48a5c6c6bab63b GIT binary patch literal 50928 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 literal 0 HcmV?d00001 diff --git a/docs/walkthrough/chorus_pending_approve.png b/docs/walkthrough/chorus_pending_approve.png new file mode 100644 index 0000000000000000000000000000000000000000..172708558ce2e781a5f6e3a1fe5c1be0d2e6bb61 GIT binary patch literal 663481 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%0D52&@LHrIiCU5;Y;r^)m*4^bh3`)3eyT9ySCGcW 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�u!HF35`i$ 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�ZSQiFI<1RKUEG811)$>5igU;XjRl@^>-vY|Kwz+ewN-S+Fg%YU$S{IGTr(>4NM`2mOw^Xfa z2D>J&r2LEIFT%Y4M@|nD;ggXG2Y^Lq8GEKIG+Ks>!<#;t;5%Q^=da!D1k|0q4E2S| z_Zu*mL!%omr69Ra=!9k=vLGuQj)p8pzQFz$PhT0-W*2Rp;7)P3V#VFvixg;aD6TE8 z#ih8n#f!VUdvJGmEAAeG4ZXjJ0dq=t zu2%CkyfeLWp~7?hPQF1pzY{JloMVf^eT6hWSVuXW|7q$Pg{qVz^G}}H* z>m&InqHiHbp9~%Fv>KJ{9^z{X`K~~(6ka+@U*XR(M0~k5c)8E_TZiDER3(l=oU2i>sfsuz-({caexuvL( z9}TzryT77TS)x?woAIjW;Vx@7GuIO~9&DT)>pV5{J`V|}n`~R%ds)zzou0=%D!)sG zX5T~Z!v9_LfETAlxc?&ytlb;XHB##$Ycg9W&xa`| zdpo{R0ayRYvZSnW7VdQPLylb+oLkBl0%PhOw^FYca!GRy>e$v&?!sga-plpepNnjX zT69e#iKJo7B%$fm`dDS2xio-rmUb?H$@Ua%o~Mq#Nsh6h{imt)b}gC~b}{#rx-VSZ zt^IeyD(?m&j8&NjqKo!j!g(@^pX<*`Z>r@d!23!$t|r%%D-yw`_!JkG3M@W_C6*#5-&!xT zprA$PUb#UUbNScXdpy~JuW=<+tNNoh@=E2x_~B*mzl8MPf)4Mhk#4o181ic$$Mk!K z57Tb0TOsIxW_n07Ns*DT%9OF$*<&lx<{$jXRMd=%S1T1t_q&m{A$quNkQ*Pjax{R` zBMh~VSNee=<}~{@?HpuwictNZVAg9719Tq;ZI_0k zr@XBlLf0rxyp~;0)QI${iZ4Ili z4YqfE(kZp6DuM_jfO6By7CLf8aIRd6GEyrG&>O`iTZCeM{g8T&s+#{bK*v&z%W2If z2VUh&bjaD5RT#)DPf$$7xc+;H2TGzef#}#C)K9QB`dt~k6_6hrR`ppVs( zcZgNnlY6Izi=sfbpg$_y59SO;_g3whLJvQ7O+n#~)(w>(^vyj>_+e(LSHrU6F2^xv zyc$q--Mc05Oa#EO)yG-%P(?W}{uhhiv9;mrp#d$j~ zskV+u^)E^EF=H!`!c%or)8ZKv1P*^q&A35XJQfE?guSDC}_Fyy46yX+wvnNrm60An>6`}IbI zN~PF+b<67c3()_TmIHd+JF9-SvsQhxv_^U5d&MZZx7v%`Q!ajGAA2&k_DNvtX3aWl z#De<{z^Ett_{C}``#M((vjvx_McowM-#K?hwrkOtJKn6aTldqrX5QR_w)Ea#GmSJ- zW>i+q?_sy@ERa>D4$bI^94dhM=6h`}T|{^uqm*w6v{5#ehU;Do21@@}MttcL4*5&~ z+k1rvs5#Z|_Z;_gxuLY+s?U@C$gUM``?p} zmeuuygbh?tjOpF$@1f&E-L7jtOZ_JgLwLIR^Bzb0YlRN<@jwA1I4h z)I==|E5p+Yv`cF#@89AUZSOzm9gFn0ZPT-_GKs#_q88xnu$<~OAmjjgvQY4jDGfYr zLLvts=!c}QE}zUf-$ebI+U!_UxIq@Rxjz=JoTvaNtwn!+F&!r=5sv6if1IF#757b+ z=#&-tSatMNU^3s{HY@97FB;U@nE1zvKB-tZcXhaJ+fZ$F|M0!5IC4?#QB31S3XKd> zDCr)$g`z2I;7#m+mb4J(#B9IwVuV8oa5DOHo$A@;-Y@)gYue9?YsRllFT7q-n@?+f96En*ydA|MXC0sW9rRTH4C-bFblqP1 zyFhNCh;Tg|&pX%wZV5wsou7Ziz=pIi%sqbc22ad&^No8z?$QJTpwBj}9z&S|Dh1sy zqbzE#2Lb{v6xHRg7c15Q-b))gzLBwEdRsSpQ_C3H*O*;U{Y;rn?~ZJP=`HA6r6W9G zkAQd+^J^yTz-+|gCgKLEKGC60w)lgIZhz808Vq=TbMUEepP72X)8DcUTtBXVNh#r{WgZ&w z`iL858o9%xl%mQ`a4kuCB^1VX!#t>Vu1teH~^%Nm+!@DW#b#g2Zy-* z@J|6#HQyb~!YBvcT2GvT+smxBC<+*!bMa`ypRCr}=__2UjRno?tV8U|OW<`=K z)wXv?%JC+X9}r~2FRJr6$t~4ThR1_13MaY}wKzzofsTpj+5X571xj#Ry8TkS@0HbO zkv{6S@lLl9e>y|XyQjBc-)AZIB2n}olRola)?;1+{lHOh4a_2|UC%6zS6C+vTNy~v#fdvG9Q?hdw z^()`Y)D>@41(R>2ZB9TET~x5{MW4>Vt|ErPr=7vJJGBeLSH)R8Q1IDMKtOEgwK0|N z!^a)y6Nj30*N?mBhY9Gz+TCw#?6vcNbI2C*a}X<*I{WOancKJz)fp z5%8Jhl>rj~9x2WeE|ZOhooi2uTOk*V7y1+u7mx`%qOacC{TG@4GpF?@k7|B6IAD#0DKa zzMO4p3cn6XbcK^_{Mva<0+`r+vHQi+)$tjSitc?dzK^~N1i`5BmT5Z@fZYy1@6l+l zxmhwAyy9rg^tGjd3*QG^EO0{%(FcITCE7+V!~Jnk!uw`y?oetR1gGkFwO7MAE0T@` zX;@dAx8bz$M$Ig#`%P5-C}xo*e)_qNrg|E;z>@T%t1Y6uxg`R8bn zoZlcUQ46v$k}R{sY5%`mfVwgZfexu@4qwVQ5|DdT?c9jyULMblSY1J-53N`y&H`23 zzAf{E0T2Tzq#h!vxR4cV9-@&nZ9xK9p5?2T|2?K+1>JtxD`))>f3G2k{oB?8D$N3&(XI6OaMVB!Df z{$3Y9?j@VMu_HcTb>xe^UpcB@k9{OMp1R#So&NM*U^iGrRxWiEZ`9 z#*KuGH*B^Wa>*NbFFpt&S>9ye1G@(wTQ;A|%@!N_kY>H83nXcX{{SNlAiQ$GTPM66_hzwV1Bl4afinGT}`|sjHV+ev4iG@Qi9%yiHF>`SH>_ zSHr^}oQ56!Z}09q=T`{;#NmYAgVAAOVUk?%wVrz;3B@&uy3-0&J}OXA)c1jB;J3qW zPrwyz%2<#o$VY)=&G=zw#X4KW2WAvR>sazfUpzVkti1K3b1XAMp8+7r?x}lmXl0JE zEgOdKDPM58BR(K*2yglAfy9NDFxvQn<>Htofyq+n3nCwyyTyA-vwjO3R zb4bP7up+%TsY`8%O#HFwxAb*gC#1rd3}9|2)=7!6w;}PyMU2*n`6V6(m+6jgl<<8P zT%4!-U|~VIo$EM`3#2c1Hd}i z5?J6Eyu-E9T^+j^gF8(SVh?_=UbjjenGhdwRg1HVjj1CV#R10 zjFhd%q+o1iRu?Ku79=g(37N@-McH5y9G7yL6Kas~r0Usd zM3jI0VbhXR)>QFRL-~L#O=uISI;ojIw@{Nrq>bQWmWz{Bj%r806}ERaXA+7webXY1NszYQK-BnXbBV%8DHF>~7Y*oYHx&aKK|jOquoO zIFJh$?XedtbkoLx1hI^&PsFTW{~U9U9sIX&%g!RG{fjT-rV;GMCuZ#tPKqw|`!%qW zuMEyL3^6so{9D@Kh~b=WSMb%@!1kS2&eqYqgPn^=Dk5a#3ZoJnE{=-vBC~xaG(y}b5@eJ~rK$NPo(5*|!v4qMMD9_`{nHw(ZkWGY`k z$B)y>=GT**aNx(R_Ot%iuxgqA==GCpV~J2sYjc ziTsj{jM?R!cM?i4avco%Dfh}Kj-MhVbH8>^;g71hQ1{OgQ z#(wvWPINAskIFRfE;=v$?*LK=7h>Kd03;p&+>V^2UZ5`M^W!%{o%55M2RT5D>VGjq zpaWat<-VF~V7T^GLVRRLibur#g!j!68=emsV+cdL6rc%;E(Ya03cT=NJ=VUQvdGhj z{(WHJSGaW61f$Bc^n8#hwUh9tcgwgN@lu75P!CrSWL!6#=eS5eC#xw9Q4{Mh%`sN^NDWmbw zuXp_k@-Md2$QHF?%Sa$;I##FCX!a|JI}@$o@85V9)-3U7lwCFRoo3fl z7pQcgS7hodU(n(bA_yk^!nUY9-=56HvoBF(Oi@3MVhCxUl~)0cG2o+yFH=&>KM>*g z75kyzs7&g;l?eyE@9dh8{cSW?Fw2p4nK;d*mg3@K(bqB-A$lB&0#yT0s!eQ#w;y*hM}DJOMj&%Azq zPkOMd0AJ%$>=R~+`YFSfm4K-$-4!bt#fxXG#qL_}pA<2uG)O~B4k zieo2DMmeC!(7`e2v}mpRxw$Q;s!!ASsG1V+Q;WF0xbEg?-0wdGh$uFOXr8)?Wm-Z) zqYJF&IM0VCj0emd$;^yO2+JMQEZuE4zZQDynX@v6PILmRq-ys@Q7FEVFpbNtPmQW2 zYgA_JvUu*dccZ-Lg&ay9>URK4zFM^&;O6)&NaJdvwPgJ*CZW&jCe9R(P|b{2$;MW@ zR49JL@qh(HddoI86y|=~GW4mw&d%}$ z8aGk3*dH3h`ab^~CP;CagEKcq00BNra-17`b#|Rbqj&DQAI!)d($dnNlW7Y!IZ^|} znJeMo!@3Yz5fE{X28_J_12E1v)N!i-L@5}xqx8L^u}Mq8CP?I}JSqbad&eJ3F6LYl z>%-gGK4N@2^6Qy7wGr>$YS4A0)w z(sSDdStR-RCh3(M&39uF3kV7zwx&L+GWI6{bop8W<+>Cl!TSJWUWC7VozN0;GjMUI zvx!O0E8YtpeACqQpB~PKC+o*e>xMQsK(h$K9+1=c&7)*YSBdj{h738-$J>XIkulal zI+ye4oBubH=j&@{)+2#{frYgR37=82u7`j(>x=IF^1=bgPG&s$vw$!Eq)j(2NxVNL;D`H<^yh}oe(*twI?F?s-_ySYHDES*5)sZjB476> z&Q$v$AT!G@FR1qF(7nE>AS#Uu=-VX`%dku75HUSJb2G4VdqwP)|%FkReU zf=xa&K>R+v7^7VaGr_r^b29bd zO`gq1reJB7?ze|eK+e^PX5X36=Y4F6j~Fkitb7f+p8F?9kNWv-`tSh%*ZU>tRX9vt z9HbA$QHYp*ZfBlV9-?(J?8T+M^FZH92WA3R93-yCl^5`wkPK7=N?9 zsAH8XAqmpWlJ!gJq5vb*KKFfg<#!4eT1|`y=dy9lg}YFGo>2J!VBoJx>?74mHMv~Q zn`M>I$O`4a9IWkoRGs?agjptdq-?>VLBSof#($T5M^>Dfa`g)F(P&c!eCtG!tgW#?TORB*|jS zNji)5!Kk9v$GBQ%4oB*_!|@v(t!-Y(qUG43SNn>Y2RsVbjYFL+Ub+pQ)k@Q*fZLVO>WwP3IA1wz&bSj6T(~rj z)36S#Ok;lzBGB0&+_uN_vEh#)Gv^%IBNb!*e10K!@sR(^1po#msyzV`t!5?X9$J7H zO7_RnE?5roV6+{s$&W7dQkYbd^%q8>kSol3(j^$kp}JEd9l;f-V!Tyb#ZDa%$bM9( zQ!;E^E9IX4_itM-JcjOlk@xfez{&$ah5|XvuHCH*1JJy3P*NptOey~Az6Mhfiw2I* z(q}}ob_oX`oY?D+!K7|L|5M2QtA@O4VkMRLu%c=Ec5zw+ob>|z&OA9$5 zyze*5FCLGf&$){p|E}`m#TPgIy1gLZP!yH5EVm0V180(67grs#y#~V`Ee#vjh=5n- z@e}$WUP^{pS8TchL0x|GykHW`y&ZQ_ZdYg zqHNrKvI0(-I=UByj(dr#)PV(mrj3||LH?{$VLhVNW~-r^eCFZ}`M__JgUKABB*cPN zPx(45kD0}FzqxCi`KCGR(JyOFVj^MlP5tljBPrY5QZ7K^x*zY3%L;~7eqKBbM_M@L zw9JHr?NRVzczdPE*gq{Tb=}0RKf!7xfI(4J7*?Y7 zO022d8Lk~Nkw)~&Na+rqAI@12vw_BB(ROlv$&&Us2hqa8`_R z5%C)Lm5{C51oG#?`r8Vu2OtoCYVp-KxU%fGA^H9wd@E(*c#c`PrO156N7r{KtOl@Y zxnA6>xldp>UD|Qu1`XAP&kY3RO0pl%_G7Trrp(^bE&_{eKJ=LaF~)nDHkMHm<<&WV z=1FZc*N7%MjZ^c)H7XLf7cLCr&s_%46Z-d8&JqzU0LQ&oPyI>vH?G$+^zdb(Karg4Nzg}Jj`YMSJ?fMRsk z9-1jeyK#06^?24_sxwH0!LSCm3CA*wa~x`q-EMXpUFPu}PG>V>)s<_m7JXTZtA}T{ zFW$bl$!l+-)sJGwkC^;#c0(MH!ME@dsHMV7Gm%EXVK(^O&Twn%w-DUbtmPQH)lX$SSQ60R=u0b^2`}lz}#Vy-jiDsyGGz~@Yp>QC>tHH z$JAs`>yfm-CH7p1-m=RSLBWn6)$Va#r1S9hOyzk}T3ohpLU1XR@?N;p4JnmByhZ2E z)ISdGinagE;`zajpQVf8Pr$z!BRud4pY7W;K&6|=+}ynW=eeEV1wbX0SH!Hw%N2Tv z1rn%o=uBUBn~Q&2>-7pKDL$IH+~R0E2v48F38XS={qAYOva`av`4tTmU->GA=-E{D zsq$`+dXc`V&~FV{7|)bCR5}G8gBcl*kK-EN`KL?3}8$a zh)T+#6=;2W3ukhaJ!K>XeCyPC*hy;lxa_)b@^VEm5!QnZY@+ny9b=)hD3th7Z|xlW z+KLf)Y@F7Uo6DHx`9%fa*jZ5;nAO=Q;R{8Uewwm48oAvy{;(0<8T;A%B#lSy;uBX00CgQDWh_z6Ao zrK2fwRhow3Y-<$>d~>8{AjJF6nM5LTA-#|}lIygyJe8JE7D=BWJC zsP{kzkvrwMQ{m+2oINzL;1r@@7L(#6UtITWA<#l``{o*$X_H3SThy;nA;e4UYKE8Y zSp1uapopxVROBK-zz<6X31IC$=%RsgpF2)60N4{AZ^%(iC+;Z>ekW%QE~sD?H>Nz zFGsRR46Ai@?>&&@_vL4dhA>WZv)!*}9lzow&m_ebyw}Z-%_kCu^)yBqCUz$@iMKzz zD@sMXn3lct&Ji;4=jTV4Ga-;JJ9dcpAuOVc{cJ3h;E>Vtt94~WV6{}n5j&=HLBhj( zdp`l*oDm7@B?jPmt1Mw40D-I?8gE>^s0nm?dcI!RGJyiJ(vN)dWbV7M_a79{|4yaj*}8RL_DZdJ1jo}{G4Or)MEbKtb#Z%Sq4af7%$hM5$s3^z$a;Olja6%g!$Eupeb-+&H*3=kRP zy8y+MSnns>FY+V|;53iShwN^q3wc03j~4_A)F{Q(*4BX%9Dt&5ymzz0))FIzO@S;~ zaDGR*Ysa?TisxN(;C>52vl;e`}A0>Ldj=Kxb73QP^@bOB>;FZ$Agu3`6BiS65D z%rlR*tCsKa)yA^Tte(0&tCvO)V^22~f3W-^z_<#a{IHU-a{Jya#VRKFW}77@Le`w^ zaA+5+H4BbhQMDq%)TEa`F9%5y#Z-=ZRuW%|!8E@A=29KLYx-Dzn6i7CnFph!H7lC? zYw7gqn9Q)KE7^CmsHBTI6r`cFMwGyN-Ky{}Vu_Ldr&6C8UC{R_YxCKA`O_)uhq&j8 zQV#ccaDxd*sD&(3BymU?%5w6piGxckjCwcPuneksS(?qb;0E+cFa{cG&T?pVJa7ur ztx8y$ca_kkTKXFhzS$uyPJrtF#+I^Cwq3;540`=wFt7C@R>`f=&-xNJZeSuOJX9U( zw5(Kb6&H=OE~bjlW*~)wWnkk%nYw+rTdAH?J*Zz_UK4o-7!u#dxWi4Usoh{*Z>n*} zfF4~BvXl&koZ>dymwWD9l}OQU%F2GfYLYBFe@CqBDPa=8?X6R!VH+4ObVyPiik2z# z&cet!|2sOla!2glf$(@n&^~51D`j$G5n6k_(!TjWfgA=I zK;0H9Jh55p_OIdress6jm5>w zX4!6x_z%F_wf1!MJ ze_xgx%GTYF2*Cq_XZdyX#|v2*GYXGWX$_hu|FUiM6B!>(-Ywg1-EtGz=woaI5ubh0 zVTAKp#q{REF8or@KAnvM>TOAVGn05q$i~3Hh(b2P41_v7xd>m6O}^q8=IjK;VCSeA zo&>1`OvuYOU2N7{FV3GZP)ZkRq-JinkOHcIUYcBze0#n7n)0^Lx%&3C2oUXfywhMF zUu&>1ltRb<%YhLii?6XQ66%%Lt?c&B%u2Xj4^Wg}Tljz_JbduRRK zz1zQBy?1lvTMDs0%7k%-Y3lXO`~9X%EZnQd<4&guCr_iTNcA2O3t9P=DN<7DFcZW3 zQ-!C1nMAg7-Df;={7>XrcE`Zv_!)!8;fmT!JZDjcI z59r9FO^|eD1eK$vmU@6*?(*KX*Ol^h8;tALoAYYo4U*a17I8$K1+qOFO-PzA2n^|| z-${BW*krt9@Jn0#(fq$$z^|%|TC)K$}eA8xwu(R>tQ3g#&)Ee8)u}!Gq!cXMJ z@1AH}POmYuHZ1oZ4lgPf(`jct8l|suG90h0jhFXqKJgCTZws;Q*pCttE8WGdZ!5O{ z?QkAY%EnFOrQHeHt4Y&^@9UQJX&6*diMh1k&tHQL?;-dAXmFBiW5-|R37_p9s@Fc5 z>{I~j_c#Ent^hFjv`S*ZWKBXH>uUXUmIVd2tF+36fLC|F;rE7C=gf~`lQiD)D^Kbm z&)rZ;E+;kMdt1(fPC4o&AA$J%mfhCclWfR00u3R>ZLtOP<-kvN)Q0tH}E&<}= zQz!jD6{%MoYqmjgX!4Tkyt6T36lU9!_U~HVdGQ_P22udER*XcI8;ATvC?}_T0dPht;v<2UhmXt@(Vl> zdqeCVW~Yq7@j;-EeJ!a>3nh60czZ%~kXnsR2x8 z)oRPXQo_lV4l8oB4QAVVH%Qn)x2(1A`p_%c*K&J6tV4=&e~wM+5O;%H3u;|uy2+OlibW&52=5nbr|Cz!GwVUP%L+qselra+DZOFMwA8i7*|F+Bal%(-gi`V)(H1}*o z<+;=Nc4$oDxidVCuJPKw?mk7lbS?4_i>&?72@Wa|iGOV`S;KlU7I;zn@oV);h))1LdXjBCv*J}m(2tB8-s49?^Mcx9LkYu zx_}u@k*95JAL5dqP8DAe`EjNlZ9IYVhf)pWf=H`3vKhyZuZKadzZdB=Z~uiU42=kw z4a5L-FhFvh>D5E6!u@KY@cvx- zi)dP#aAg`+MW(G!EiZg6rQVQ2AZ}U|pGq}WOqI0Gp2^B)phD#Og4>gI^*t;>n@}Rk z1o_jMf?!#`^4ESM)H6o;iMm(!s>6a$%aPA1hGzzmsVgB=?nv;>8x@%8RZ(QN>w;|m zjMFkfEkY!$Wo=@Yrz(9iH3>Te8#&8o1BkS~sU{2i^n5RH(-ckLNjj=~rLyjt zQ)sX01#5)1+KR=WnWcIbGIRtvXLG#w{IjP>*qOO{9LZl%d|qM^O3y>hjKn7JbG$`? zqbf>3l2Kq&wfiR7&MhjLaY4-*J8PUul!@x4mDfYG{&G2)$f%HX^?6PTZreKZ9#(tP z4Cr(^&OU$Ye$IjhTzH;uIR@NsLAA5MYiqc-g9U$J;3K332MWl5%)xJSe540t%9aFKT3A4=_-kGHes=`dt&WZG<|Wo zlM1_tA(xAYA#6yP;CWN#KJ6#X7BV=)w9?fyuBQ_@h_tBEY z^`d2ML);4u!pm-IE(*e+k+bKYVLa&yd<5Ox+WKT$U_2j#1(=yuocUrYpH23_PHTYQ zg!n0WMhpv{ZS{eB2!}=TF3{48GOq|PD3;%7Jy$q-7KvZV^ap!Svzs!K8V;rk=vIY` z1BrW~kGK1M1}VjLA<&pkbpI}kPk;5wg?~5h%aJDIDkIhqXN?`$3qd45MH~~JvwE1> zx#|M5(}h9InPJIOMC|QgdQ3tsK6AL!_q~9JD4)08_CS7mc7XeBR$uy$*7U4K{tM3P zXMywT%eKn^4Q%K{5ye)=zDxe_|15t&)o0`JDK!{qXns-jQ#`GIsh=G((jeZV-)0rI zQDv9ug6}RQ`6$c4xte84BDYR_wa$S3_h--h9o2$5r3_1+!;BRfAHWO=ciJXe827#3~Ixt55dRpJ4gZpBu`I3;-52d3quUBa+6w;6Ussz;GNM9xF1A zm++&dsYU4W8mC&0F196wU@ow-Q|}b(+R)|q{T(UYn?ek< zny1f_8QOpKx3UOM!AuE2^Yfo`^ayOds3bo*GM~B9$dfkI%|+R-vRnf>2fMGCK|>OstSI{8fzOL~|uJltL zpV$=U)wjN>X_4t54mYIQso#qsDw*}prk3v#7CwhnGbH|{>68@mrd<#zl^2=wggsc? zkLE$kk-6|g8qZtA>yN?<2SmmO(Di>1Yt+EZ36W~5z=Z#y7j0eoZczC8QqKQfX8L=* zs5dFSI}+&uh|)yWfr(kY3Fb_4ikCwVjU*EXa>@Maj@arxs+2>0wZj0Ec*6%5VvVyJEpL$ zxEE)XgPKnOH?57d;9jr~I4n~W81^rVD06UKx2l&>FI7|KyY^ZAz=0kmXpop6HxNe( zzeKc=<>lAydwtX&amO*E6D6zC3eElJb60@;gzuB@;H{n5;FlPv|NW(Gx85oJMv~gv z7_>s1#{Zf%toCS!&})>AS92xoveihuB{y92&Z?D*?0f}nw+`;$T-R)uO$dj`uFd9^ z+IO*>fT*;Wyp&+SB{svz_+cXKm9L6*8HnKF%`{`6N=!A|R6bGlZ}1y{Q$+vvBR>X+ zmBZ1EuEn>xesIkzKeM!(4}25Jh8%|t)1^Uv)!1jym4g}c(`=EBoz}&o!@p!d^aWm0 z_+dm+>7-oymWUPqx7`0NHA(cFRI5+VJv4n*$7Sk!zXV~80=JmrBR&#cT4$og_B-?V z&@h9aecTrqjMlsp!hxn~@a{KA;QD_^3xs96NWLokiQjWdTR@6UclKp*Dkk8Mx6RV3 z;j=I#?ZJb2Bv^bz7svgJ@a7xiK-ORH&5OUGE^e{~a_o5Ng~ zv0{~S8th4mjvI<#l4obH3$;KH^orUc_=J6-apcSJ?;*@BKys-6{ui)m{I;id$}Rx$ z=AW<0fV}SSeg~~O5~4F$s{1ex2ZipwF0O^iP@UJ&f2Aj={ z%z7JnafE~-^kFXORX5C_@p#{SV_8QiDW%cPxUilx_u9&dfYxFfQ_D?{7CUW|xuKbU ztbADtleV9x3dJNuH^vm1V2x!DOFUD&{ITKYmr47yu(AkK{UV#l2Dx+fK2tJddWN># zkh4=H%_ns8qk*+PG(97EYreC73~w1Udr`>`wfihh**vSIk#nVx`)uK_tM% zmXF=oQSAf=99f`}5^s?8r~M$gX^NBM05YX^FUAUllaTNd0S9A-ygKzD~wMz1-?8UMAg z#l}PV*H2Rmx#2QtrdX7~ZxR}9DZM2;e?coQ7!0OY5VIRiuhnGLTme0?Q-ndobyhv( z;61x``_O%DUFTO^y2oFKh2O};-WyF^jcTjA|GFr@lDC}D9XA>4eM!@{^p-=$QR0RR zftUZPa$7_uSo(#h3dDkrTh$B57#IsWrO*;!rsZAMapI$+9;{mJ(H2;h2iS$_`R^Q2 zXgRm{RhE4B`MdeqeX$RdiqZ-bP_rm(@ZG(qs$v=5J91<~HEXWm#x6?U*n$%^CWlEi zDh@x~h#Jd7-W%^vv!)#m&`H;B5Ye-y5qVGzJElABuO|!ft zGChip!7k$5NTBog$eRE|&!g|Rb_!UDACw{V)1sWERyx|oSeFI4Q2XmYKyKoNwa`~a z$H0|sG7Jt&l?1C3;7u$i4Y~GTsY-(6bd{w3G{Ry5k~_ZH$VjW8Y57!K)J`YnI2Ua} zkQ2)__m@3R-6BS|W)$=t>Pr6K%ZWRvMmq@=&cJ&z9AM4&_a#j#puz8K@tE0K8|*g; zD1Pn|=J}UIn4MJa>cxr6NrY`J=#%6*LFa|Q}uzg&oius4g=hs>#^!8qC2WX|CbAJww^g8 zpPd2wh8_~OE!L~-l~L%VZ~V4W=~rG?b~CJ_^`?k)w+(4;a9JG`?nG`w^eH;?I0lDI zqcwj~mcN7p0&CvQ{zlvfN5#t0qoz%D^;67y#dsrduzOw8;a z1eX6W|Gx~v|2#py=wwHrjP?u=%~gI2_L`O4s#wgJiI@f%`fFdJ_LhY@HqQqKc_&uM z5YzGg!JvCQ_+^jh9OjgG;>FijrH2RzC!Hcj-$<2AnNHls^y?KKIx+c5SX&h_(o^HC z`R-U@8h!^>uW_41p;Sit?ELXcuV&gC6Lsk)6W28zp*nV6Li1iiq2`8<-P2K;yYdH4E$<9+WWU19 zAq&(fbSJbi)&PE+xozZRf~heD)$1NhRcze%O{2A6h+i8y@Bg~D{}BmZvTG+L*JgbC^uL1&?+`gmt8t^XTgy!nnz#OTt5kfrqsPt#)h) zoETN4f)Ln>hd3J5V&@pM-l3%5PM?r#(Ie8+mR*eV!;$}QwytG#wj!#Xx{vSxjC{L< zO`cRtZLsi1q={ML@Z>A~aG@EG$)1_00h#&n2Vy~id>S6ohTcS!l)BCeX9jb(8{ZKC z8*1_prIm9}KRrQeQ0^`H+>+Pa6siCBJh7|M^t4C;g4aY%i8K+x%vI+)M`HY@iJ(^l8;u?v~v z(8#};h>@2JA%GCV>9e4kdh}LX6(1G?=Lkyvd@3-Zx7@Lv43rb#xMf@|;}ITf9WJxH zHO(iw(m>!ek0P$pWG4@_j9XR|c(<7l3jC7dRJFV9wSpeyS5ssHrmMFnc$Rx&{`xmE zUl0$4m2`IZ*n_|5hHe=v*gu*O;=^|_oJ8X{Bw8?<+vxNJySM$Up#Y#~zWM=Vzac}$ z`CEvPY6P=PohQExZ>AS5rsX4qE02bvO?XNu+%iib*^Oh$Y6j8m!D!u!`HHQ`=y<(+ z!loru)k>ceHzvfwe()PQ>|<&Q9B*0dDH&K}AlGD#A}6ul2-NLkR!=LD6284M zk$h6ayrI9!Ih6J8{E%hkid&hH!>lV_AIq8Ez;!3q(}SJ(^KYrga<}!PGfE`1c`3o| zjXTa0^3#Td3GhuFR;){61W$t>L4QECpGnQfD?aZDwnTs^^;=XpP1I)?Jfp}G)7`Q? zHf?B)NoNII>b++>+|D)=i!s8CRe&LDjPHZ=} z?KEl|+qP}1X>8lJ-PpFRhK=T%XYc2IuW$bka^+yoZmf0xv@Xe4u^(hOioG|>V(9YL z(*D3f2>d~}l1iq=bTKf55vQ2mlDuV*uU64Ep&m}aFg+JV#H(|7P}Pm+ius|j{9Mo_ zDi4#c?wprr6;e)(fkWordYHq==Mn9ISj(>3HrWCtNrX`LXD zhE*#;^3`iw@nen6YOT<6jT#cNU(s)QyKsPYyw2(k#%)X#PGhN$Zv7Vbst83)M|Z># z;SW64@DvtR-zBeE6H->CW7Bh61|-XwGA8r=jCX`rEg8L2c@fvHDp z#!351GikQ&e5umjZM;QRAVdCKcXn;7YVbkm*@%?%e0*RMzHm0NKf9nKo$Kjg3KR`j zY)}1OsPTn6s0kEG5zMS;yLMo=YAE=mG7p*kpIZH&R_#B3^ykivrH{V5963~DT zmf5dwyIDETG92m~xeeMkR7ZeEaZLrZ$*)oiq#%4J^1}X;+yFfJJqB$+@mkFygh2M= zg^c|zUp?La4p9+c{*_yTq&fQJs4t&%Vl&MOT9ZgdUPa$kwAyOsrK6P08h)KDASBiq z!?CBk$8s-`yZx z7&=+WBamOfrz|ZKW;-?WR5JBWC*CLo=0(epkb7p_c6uPq#k4`rJ|+et!Q9=V)}YmJ z1zC>H3&z+bnSgaeXu(=S_%Vc)(^pixg3Jc*hHx0;WAcj77O7S0KnT|Ui)izgyy^_4;63SUSJj=w@7lL%F^@fAP6#yKq)isxVc%G#Pcg0_N?0ACv}+a z9td+7iYF-(B-ymbSk-CP1WO1oBcksZ8WFuqC^e4G9$0o81HGt4%8 zNlnEzjEdlTp{a{-W(^a|s@kr8EVw~2jqUw267@NL8(3Fk+zla%rQn zqww%z0MxahQ^?RTgUystT*7cNH0ao}7}h&TO<%PQ2(PdNt;{;hT1{OJy*vj`n)U)v za`%lcsvzT-o)*lIXo0Cv5hpWd3RNweQ3&{+0=QF4ZQ!{-P6p5@JRIV4Fbd|Se|;LN z#0k~NQeJ`F6^bKZaaZ8@I(zN63o@WnFv~kKz0H~^2`4jD^@QfrshZ25-iYr`?@sg# zoP$*ueJBK}yzn``LH~jdaCG>5{T((*susM#P1&eDlU)yj}0_tDE_= zN8Pk8++7Rnb4o;L=Nu%W2X+ zk8@CxfI#%KzEhK&zHo(+K~y(Hou#TG(t?iAks0 zs!74sAziTYkblIb5<*6eCkg&%W3Vwc<0^it%`caV!Kbe?1uhs#1ji^`7Xx7RGg4s3 z=2o?a-?o^tUB=^l!qtk6OvX?k?*rFc1ybKKp^NFghwX0+wvz)LQCfGSOm zf@`?8g|`|(4rD0Sot(`$5Sx$^m-RSwpi-U<1Ewggjq69<2RYIrkLF1 z=F{ENq>%)MTEN~q4bLcP4W9Ao`t2;p#$e4uSL@-GytXYDLc=uN+{lJ6+6e2M72vTc zjoc6%sXraGe`mRVB1Lel-30ZErc-n~7T)*mLddprosXW|QeANEJWnYTpkZI>r9Id) zJV4jAKO}?ZCO#xeFd&4_{N0tUg76m*r?H=W;M-pLaRb&sLPoLQ_PtxrU5k!zHopto z$KS}yeysN3(FNmCwzs$vDgCX#1M#t)5rN>n5=-z2@e!3faI)nmJS*x0u30K&VPh0S;dL{7&R2$F@}( znXg6$vT}>~syumz36vi4@I=y`Ixw}lTb-q*>i$Mqrs*AmjV1z74T+E5iiVu)f;K2$1d;KV7I*|Wj&y~U`{|2q~XD4 zSOYxk{6h{Ir9>W(nimgcNnvEuj%sc^y>)b`{Td|r+Zpy}JUb6FwqkWaUTU&@+zZ!e zjSA*vPf!MyjjdFZj08F!ZIHO;>saMQG# z_mZf!sv1+m_o+-*4Z1ki7@Ne_@&(Vntmew^p_;ev88WnE(4y$GvxMoo1tlzyvwQvz z77%Prcy>oxI|@@;IY(eg$JBDl2+dyC@F%;WKF6xE64%gbU}Bjcv+2~W--BNXAi$L^ z_;SD5e|EWgapo%>E~UTmcR-2zinr@p^JK2H#{s}_`W(hgQC{>(X}wM4t`{G8HnMTN zm6K=x-*(Y=siL+|ZwisS1beS<(^@1MzsIO=yzNhsXp{Immx_6~`F;oXv4JV&{tJ+X zfq&LJz8^`cyexuxuZ#;XR({yDH5I$E!GW$m9ZM9S)#RHwsmWA&vDqw}nAhIMm!oqc zXy$gu;n=woo9B7=S%S+UNiD7*PqB2yJcIlg4g>k(1}6e~yYDtIOXU$BO7*^|nWk+^ zbD^r;Rc%Ngv_)I#r9t^VGl-ZghWl7O{_L0Tw$qW^{ZjP5H3@Tlgq>0 zwR;TH+wsW1?T%RB*n31phM7D56LBRSLG2WsdNjm5mT<@#ka3gY&@)gszm7j{qRY%o zv2B5CtTS`G6FZOs5EneDj0V47G=yVUo@$swtw?`aKkq0#&!MjR^FV8lt~En@t?5`E zG&Q-pH;Mf6A=QbmUiz61k9Ri=Yg>ipx#q#oeRoXyn(Lo~#~;51k}})55ck%<*l{*F zs40Ks&%Ed{pw{5tak>Ea4V3HPb^ZuE&*a`}xXqDFoq}3uectRmz0e13^@h3}40wZ0 zr=M`d9uAH_of+1d);ZQY2tI#M{}<{x*7GHmMb>_;fEg&~a~wuR+RX~6`z`sSL`aN5 z1{|XeKTZcxH-IW{gsyIUgr48v5<+b z>3t+bhh?=DuVk{LWdFNk(_Eg zNCPj;#!D$wX4W<<43K*iwuwVU!9p>29r6K(uswQTFC(X-`RERz&%eWzR7K<-j_h@5 zfDeP<>-sK|bjxMN`n!(vz2aM#KY8zegkYbHty^w`sqrd5{RdnpZ0}ETuI9CGuNYe= z$9sncxe2Lz7bOWi28E|6|645xkpK*RKj#IfqQbV?%%rI-+~ZF%#=`#VfipgEiB z3Qp4Ns`Cbi%8rLj&E(+2s@n#Bh+~rbL@dLr!2fQ`%&;Ftt|oGRvX}WHAt0}#VmXpQ z1i5|s!=f9ue}Hv@>M#uJ=Nt;<;7s2a{1WL9+d;RwJzspSODv|57jYe_QY zIgltv1lS3_8+&Mo`mi!V%b*sd0lC$90-~_<&U#|X4EKLdj;EYS!GRl6G4@!N(u1Ec z;WT8L>f+SOGB)~C`#sr z4D<0{EgATlB-&*mkqWpC&|B9Y!ok|x*sH@rT}a2@W|>};?rp{RvT2v^nL;z^yM!Xg zSYSaSxO$pGlT@tgy1E>#NXNALkTGB$4M@8cGLCRZ9mxs3!3UBzFerL+`O1^V_3p>V)%l&k|TtDaOd^|i8FJW3{aS}w*bB49ZJ0l_H` z>Y$Eo-pKG#hf>HUjEA8N_H!&lLCIasdSu9t*9B5sfMInrV(&tmSBLF) zxiUw5mIQsdreSPd^&arTPqvg_f&$tMmd$m-rE?E!`s?HOjDR6sr;b6pre@hg617>} z%joT!AkulqxSrw#JUa}ia8BaTVwg&|+Fo@Zvdn?13AlrFi0p}$F($Ga75fvHeUk@8 zfu!@Ep(piC7UbA3fK5vH2hK`eu8nVn*_nBa ze|g!zk~f56{*tv}sT=<(VEA5lfyGiO@#322n!YiCu~8WuXqskYEX(lbjgO8GkXL1^ zN5I8xnMFb={3^4v>n3?3uKC~uN0p6wU0#%^qXt)+2va zGw5YF1ES|7$2;-!q$uGv82ckCQgLgoz`oZ_7UVqt?;S6i>o&|kL-xODBd?l%zi5eK z$zCxv-x}0oSgIY7Uh*6I0vV>WBN*3b!U_%PpC4Q~JO7uBR^rmROHk_Qn5`BvowmEwW^w&KH zdVEU=Y9!KIQvP3!;%LrL(;89J_pQHh*I=5QO&n7_a!$Jk!sH7ivtD!z;I`8Vhuav=et_%sp?YW|||}X}D=Z za6ugYgAL?<`Oc1@S;%(mK{5Rq8os=o(mO@9ep7~}S5G|uY0ZLraa?V;9N|HSE6hkP z_{Ut@&c!a3AwMfzo2D>c_RkH>LTU1>X42fh7<$Nz|L|s~@UBXG3ww@^McDKa6^NA< zSH~03Tp`a8D*0 zMR#;{LYp`w!{LY`u331I5PA22*!Hs{e6TjqCI7R8?eqR&mBXBrNGYy6o`64P?fE zRIh3@QD>8{t_FDt;fRD<5WHG~n^?SwAA7fwMQnz@H_MYzKw>Yc)V8OTamQ6!>1fQN z<;FNU^pvxO8sQ!3$NKLqL`-XuA%sO%EmhoWE>Wj(Llx2>a7RS62^-4}A^B%;7H&gf z!fq>i%@3xS&O_LOFeCx2N>*s2>o1DxhCRgNu=u@(yC(H~m0D3CLuYYY_+R8>wDO(hOe!-2$fpZ~^kO=g`*Y>I@AqvZ3OzdDSxcxiQ5xtLnNibgFz`NF?f)$;R>~k1E4MX1+#-ov-p!cy8QvsT0z#I~ z0U$!1i6LsE$g1&Z14hM=JvLB^yU~@oGQ5EZixG!+G{Rgz_#4&_5g9r*a8D?|GFSQD zM)0wUl0)i5Q8Ewqw~^(96ar7xozW+f8Y2S9s8el*kjM=GgatZJUq-2ILw04ahxAi< zFiRpT70`9ynxJsH+!jQp64VWnx57D(RKeR0;IjMXuR}~Gx)@>+0qPV8;kw)ErvHB1 zB$Ho_BXTev3-wi(LTg|^#cH#2%{Q}tMC}NI*r;P;inP#y{sM#NV&@%^#`cl0r`~_k zQ!@DHTbcoe2Kh5?UDVejy335fBuhb=vn(k2vKu!k9gE?gN`+y+^;iZ9Lf_(=460zP zX&DHx{z&fi+00uHjm&wK;hqYVI_LANU;WzT5vR$S>t6K8)Z<^ezkUebePrgJDqa4Oic=R)OHLYmcTD7cmKyY-913ZH737TFCWhwZ-enum5X zKMYItswy*@x~=~HDh&cwFDYoTEtmH&zj_NLqAY&z@MRd=tF#du-KTFa=VIlS*80w& zSd_T3!*p88d7xnVKD7IJprWnEx83{v$XGba)$3vMaeWL6xvM+X%r8_8*=6zA@__~C z4pj5Mz?{u)^;q~78TrwfL<WIxI0=nd(CTbCZiC`9l1Fo#!o1|CYDhx2Jcbd{8dZ zJ1DEy*J`d6bRA}Vf>UbuQkwo>hC0LeaY@U3!mf2U1m;?=hHK9V28u=mi3SiDh_MYN zH1uE=V}f5wACoOfUTHOu8Fekyq`W_;u&S0nxJ=I(Y{ZWFqg!*t(!+Eu#6O!2BNdn$ z@w#bO&8bX|%E9_g>k@*-$)#Pi^`xUHornWgJK`{zhrQ+8tFK+H)nL?9aJ(_wDX{oQ zKHt3K?l6^4bw*Q502(UORp>iEi6-C%M?)36vD_u3AbNQd*#Xrh7H0MChygab?_fFYdA zS~3b~EWdu)pnyXjZGl(bk-IE;?O1BmT8T=uJh22-F53A;jZo%7hJ{+>sE!I6pW+vM zvaxE*{z#K|##qbGRc)=XI3ni=vW*C8JCCo(blxz0Fcb7zJwRNPnzu=VRV0I@$ zH{XVZ95%H#a7DW63%KX#z)S?^SQz7>|5g~$Ewb$g;UUYP*oE?n102A}m|a%NBX?uC zpODM0gxRIUYu{a<|GMz&`7sWf{U*C4pv&&06k-<)WVoC(T-HPeD+zhc*rtBM z1AK0Gl`m30xA+DQX8QVaA;FO84cvMe|5lFY^H%z8Qm41U*_F#15t_X)7Zz9Xu)j;0 zMpFmhbfu?ziLXu9%ix>P0mKQ&;biXVVH-v6bCo7xQ9VzH0>JzluHf7Gsktb2BP_Xf z{|a&+tiMN7kyEeIYQOx}TC3Ik{;ief|4L@S%J{NZ2_AGnT4om62A=>*bYFhi?nnj} zxj4LXKPleO_WB=3;8^zq#bg!cg%)ktd>%9emT`K3246D{*bF*e~?s0ZR?8zWY}4CP%mJCIx!vY3&^(ZdEtMZUS{03o&q(zq8fA z@6rWZ1=GoKL9h@l(2L$b7;1!?BRIZZehHOTcd?_Gb}x!7ogmL@Ph8=ryJ-wLy9iKp zC{wHytH9c-K7I*_SEVs|vr{TUsZ2@bHlUXrWvElr-!DZ+o53T~!;e1F&zX=EVhJkG z`=}tyRz>fgl9h`rw^ods8O%8I#9y_xhXQrEBUYDujQYPZI-MIlCpcYPb z=w0b+8nI8cxWE-%G^iQ80GxO581g=|w+L1{LX@*g_qb~fL68*0?Umd-EF*cA+bCKL zcj?*0lZV$GQSMRNeaeJ)Z2kT?jQ=8*?0Mx6XSm%rZ2vd5CheC(ogHTohc?nWh*eu% zq~G+yt=oBT@GL&LamUU7F;l<0(Rz!`F?@+)fke;4+#b|GFZ6VF{SWO|O3ID_Krf%j z7gYFM(!`m{gPFc1FiCY@?*W zFx78Saiu#+5gFNw0n>4<2ey5_vcoU*t3?|SSqb)tIv#o5I&vA_5>bXdiZU9oYA$C& zn|_*7_o{O|ga{6Q=uI3&%QdFr1qAo=8aQDg@*%@{DAh zylbw&{FW7*)*yZ6oJ?hBb7+@oJL(4Ga17^3)d)bx%$RX~G9mcaX~Wi0n*pCkIE-qL z)r;B6rs9+x&Xgi706B@V!Oi7;%ee-_%z&Js(C(0)h?T?P0#&9wun&1YuMb>@RT%UYtNq!|^-^_blpSc$UU{!Rc@z^U__K-ld za&)(8RQ>{i`x3Kt2**J)U)QnkP$2nARU6`G=ouLwkO@wuUUIJPKy~%7ie+!?ATTPm zEjogMrpDpBn&_%D_gU;>d<^^Ai1yhX_X1Yw-`EAK1BJ6>ZrJB;I;)9jWdgT$>)ht$ zo2KKZ$bU7!;ge_K=Fdckw4QF~wGNv8zKvzyi{+W8_IE2zd(W%e$xil~mUp+FqbHyw zw+}Z*1TRD%`{>g(m*O1Jy0n|U23s5nn}2cFMmDNB>5Lr?HxoWC+Kz4KLAcUXh@Ij6 z!b2a$uxZ{h9D=#I;??IKB>9GP3&8^m-|`P*B`;pEl2MMca7(D+<0pr1)163Wj_`e+ zN6it`(pB>#a^G`J((}G&WbE*uefvD?8QI^!!P&S$Wogt!;?CzM?PFm+uk$SjpNWJ@ zrXE3OE1#1o}TINZ771dToV_mK zEpZQHScgc>Hs;38c0^mdY5_mT3^S;O-K(>Ao7lntO|C^4@+r(s>o8x9>uw-YKnM?I z;}6xce2@<`QZ(T%q;Nd!j`7fTgZej& zsKA8ckG39>kT_N|c?ebPFQ|qN#gGl(q@;(@ zIia`lvl|F7Zx7huAR2G2V6)sSWx64W?}wO4yJivN_e|y*U#MQx57q;VT7jqz%Y<1- zaa0GSs&;r~&5+aLL8?4&u6wSvn5~_kbw|l(fv$8K*}#8-vX{D+ZuHd=Wu50PVcL1_ zp?c9H+QH$9D6zTIoQh*8w0+`lzwGdQoBbbTKuC!MZoJm+8W+d#eXW9Z7$N-JfS!M^ zcpkq1$RaR=eqB?zfOjUt!}|KGX2Ec>@n80uJ`-KTA<;Ks;nI~2UB2&MFxYOBAzrrJ zmD)S4=flERY$hx27X z%iZ2^Z>R6}KC`yw4DT;MVcR=vZydb1bO1|{enuKS)t~>n_Y30h}zCQYS@6Hop zFVN|22C!24*XQ4Xe;ypZD3-7PFU~Z5`dt>c?l4_11(B2fH@;pi%!*hG3Y(L{Q2jUT zL!D|MPDXxT5qZ*#%#tqx(|7o-z~1;+PnG269mwlAbb~*o)iOheWm4MnzQbR52W5zB zz=KeTr&qc5VK=l`{EvTYdvM|~a-cODtX_<&A(QbR2;pC5Tdd)Jn4aHP7F6RP!2{K# z%Q>L`?O&Qep_kS1va^ywP`-EQ@Nk(rE^DX;GPeERhITfi1V^@)VHj~Wv5M;#!yHZ; z(|iuYs*!E6APwe-(5Puj)tsj7 zzfEcMV_V@Fee{nM(H5g3fiJI~fy^RFgp<$57fp1vCJ+@93I<$`9`$RCZGVmu9Lc2G z93)j0?MtfZjZ?)UcT!j$2H-pNo%vK$aaN4xvFy1)Tlzuc4J+C1zKCF(v;?I8I z5fH*E0s{AT8)bGH|8^zGp2-2sZ->LoUN$%7J7+Usd@GVu8qjmoPX#(UYki~s)UOcc ze-YJp?YKEhJD-vEbK9BEIa=B(1sS*0gal12UtjyVT$i;(1wL)QB~mE$xLy04q;txp zhYN@BbbZV8x(RkK$w^tM)>CiTzG#+bW+wXB^>JV6Fr8Rn1_cEy_^~ycEopgj2+g4B zQz`ZM??KtCTrGYc%RTo8IO; zZz4G-;7vz6PCiY&TAS>qtO&2f-X}LDj)5QE-S;4`y?5zezMcF7{rlp0ViTOxCdiCF3l`5QLegdHmU*pH4C`R5)Y>>y^cP|AgXdl{t#70 zkPIG*8YZPp1)@5sDW^G-9$b4Ft7fcyW#weB5BMy2-im18z!VMRoe&zz>h=|uBXEOBm-fLvDYd~g#44GZKO1`VK*7o)0ulW8kw z86sRFm_i|9&=mEO5tH>?2xDt`?An2yNz-LnM02i>VW2FkWJbBu=EdY?XdX&R1R2@A zQjLcVsHTNMz>LN6=Gjf5O^mc|lYJ%CLWg4bH^W9R3vO{%{uXP!7S&l0djB6 zxF*Pl8Sc50>}uLUeMEazgY)Y@B^rqtSFU24a$wlCK5shv3tv zq^+7{>O-=JD!cKfa8=Yn0L22p%+DCk>R?FB=Q*EaIkypv62~BoHU_H$9!1G_ws4wG z(}jjv5YVn-2$UI_O_9l^&2Vydhggk|Ehp}52aYqp6HjBUprmkcP$ZR4s{txH~= zL%e-afr^$G%qos}BY;Z5AFVdz+#YGJx?bm)7{*Alifo-I3$F;&)(R#>qEU-KT>Qyf zF@!{y&I;5C8%LWkdyVQ%aR`Lw^y+PKT^7le=1~Wc@DW>%^CUGdh-jF!R|(5SX(u91 zhbZh?k%goySs++Ct%h%tj!lj+89E)91eT+%(Ge4((D{cFI62JsZGTw=HT`OsQ<0xo zK-S8Mlf#`#`>squYQE%4U-M1mVx$;C{;9w_eK|4v)`W<+aq4_A#tkT|*ksl; z?u_IfQAdx|m&H9;07Y<{AZ|}t8>V7H+buc$QtZsIv1RzoVCV@0HIrY5l4#335ib*} zrefm?G!ZRy?io)tKIMs-J>4wXU_BK0)m<@{nF0n&l`XR3X||_hdO80fI-Kv0ZT4f$ zgXJ`VxhU7(oSa^ijrLZ%p6(0I)5qCQSwgJ-%*Bbewagec%lprsya~n`u;HN@$Cp6Z2%v-7t3D4?&QaqhFdR(QUB*+wzei0z62?w)o39g!yXjj?_ljJ|2x zXFXxmYH*ng`WLNkx8_Lc<9_U5JKUX0->0tc1KB6*JD$N0z`FPxUN3#k@vptv1$}vJ zPEb&J=LdZL0~6p;v~4;q{+^%N-NiIA8pou~X{JUFkW~>Ix@y`qU zA^+ab(|7MuDN{QYFp?nnZ1|ksTzRyzZ9euqKggtgKXi6aBA=?JC$X?NapU_y3~@^r zYndJ%r7oj<Z1DHjVi}MIt;KopFnvSAIc#b&F=>d2O`HT>a#k5gr;FNo^gzt z$vI|=f?GJ+XfpO>F);ekN~T#ub&0G9T3_|@m)l$|uAXLyNtpVqpk0)dh+TTUPH4+o z{FLI{-_yXjRu)Eq%Mea>leR}W>U<{++YuwDUlBoyq&jL6>Xns$nYyDT{^5^iM7V7v14whkIV_ zpvF~HeCaPK^k%;Nq0y+@FnXC)Z!l2RyFU5Q*&7Z>EBu<>*~=S4eQcLi;=>43+uH@= z_HtT`^@0N3ssfY=lPn7XH9~Al)tWtgqJYh>^DQeIXLk$YIJ$Ys>Lt!^JAW>PQ?{SA zUPH^LX4W#@(x7I1!4GoJt-I{anqYr)@D!lqx0aZCJvyDdyQ9e)ojhUc!zkAEbYt%# z6ev~kKaJh2>(Ky)vSevn>%!~uba%V}5|cWiE{aCKXfDM%zV7?I&RUD0$JJ{~VjAL& zM(^iULq2q2NqZl6FQ3k=ufK?q&VHy190$|apP$w5r^JE{&-w2O6J`Om%`f0v`Zei4 zZJYmH>!)@9wfFoDfzA8cFa3wu540bki$?ZmJ^7Dp|NYiRSII9r9d^&m)4l%hr~D*{ zTg}of%B2C#7by)MZ+rX#l<(dVop$Qa@64r#N0m~)a{2ww$8uykU4}E7t<~V8K6g(g z(JFu+#y7Xwsnr{A(=a~$(z|bUksMI>;ib}Qi0?Ta6`o5=r|wsY3ncI7KGKsPH8O=b zuODYL%eu*d_Wuu`p-MB8vZ-MxZZO>*SkGQ!u3f(#Fb*$RJPVSOw4uj{?|8|56x!&4znvtyPLgdk(A6c7nxN)1mLlnf z@gZBjQdf-rY+my))R zCGrwWm!d9S=pg~nVg1OsvbPQu&WVyLA*~b(w9hUcOkvEqDW)joPNU6ejQEW&Ne^9u z30R<}$89d2f&hS4?^-m8D%hU8%~8@6F>F94bg#0}rz;CC12XzWH>i!Nt1Z|)Wpz!c zhC3tua(uPFGgny+Vt!MGu+LemJCM$&@Q_3+RDbv3gsz!`PvsIB0CGLl>_S4+csZzZ z*=q5}$(lh+S1P9Ar0BZ%kJdJcHOX$+UWyJx?k3J@58yTT(|^{pJrI$UXbAWBz)0q*XB&%b1X^N-HOz8 zDihOVlb-d)V7#yc>^pqNy!c4}tgQBYxHHXOxRYRQjkCM(o2=5O8;E9ZwfVlUesx@V ziYFp*&P6TF^ln~yj-u&!Pjlg(;-TWp8!RkLKXTWoDm;?jo!qq=T`me^UMKHx3raP5BT?79QnSE| z9G=&0>67l#vkTSYgA=Cl;nWP7S{dyd-IvtVw^SjIF{sq)c&Tpv9#G`R^3agoa=}s-TH^!0A{`jz zye#4JaJKLV4cCWmQcM{kU~DZ~e1z)PpH-s7X?)pPuTvwYW(y%w|IQ(1^p{R~*@1qY zFLF*l$fP9!@k=-^+p(FwL&Hy+Ym_iszGx8%)?`MDOdtVP1*gS&cEwdJdfq%EbXF5A z5mpz=`0`-TR(1QIm#uRTRSrw<5Zi=ETS}cOvLV`^C=QmP)$O~xriI#Vr_(G@qv+k~ z9=R5-{>ap5bZXz54Kh@l-!qQl+6;d5w>}un$-%}iL%v7z8oth{5r<<_G;@xU9G_B% zX|`W4a9N>dW1v5S%x@HW4tZvrl^!};yW^|pQY6mS|B`CXC$F~@S&t=}VGey)R>Z)I zk9P(F5^y5}N#RvgO(xS-p&+U^B~~9e65c89M9==Ion_GDnb@~Rpo-crojq8^00c@y1666w7gr%tNA zfO6wwqknuU@Dx*g^N!~-DuB2@w^)lS}5)tqeT&CnpXg&AWlEvLtyY<>lE2Ng`$ zO6Y8C*Veyx?zkni5UgBwFI9(g0&bhRQ<-;opZ2fJnKu1iH?3!~wtQbhPs3+Ag?*;| zs(RBvD3Emt3G=lTqtLrMp!*xb^I?*=%A??*TN1x(_ns|5mwzP0Xa0Pz`#0U6Ai?<= z*gv&|*`I^LpnG8<77|nVYI_AE%7Pf&Kc>U>0X{Q9JK%Mk}e zYC8{lAlacrP>1*0Uk3g42le_q3WIL!b3W@GAC!E~i_&BoUEcrMqa^yjk8<|7Z0x8o`5m^?@hx-#@v6r40>e| z?QA^nJ6;H63)z0OU(IL|6eZUO{H6pne~3Mwc-+0Hb?}wHq%@C~B+8bji}t&yv@E1h zn5w=%AUSuON+7KZISLZ`z>K;T{xfJfZOBhe9JAhETKtVkbx|y$JpF*Vr4XkM;cUK8`jvcf{nVF=WD+BeW9lBrb5v&7;~O653ilr7;WJHbIQ*~zf|E1Ac}7ox7vDrKKz#8{KWr97x3}gy}s1hOmAPMyqvEyLEWjV}O6Zj&1x@!|DefVXhk3QTMD=5M`2n6a9(-wC`dZC?{J6hOk9PQCtd271UXc}TtsPr5i<=p zOY!6kJ=8_Q>EoBL78!Rmok@);nRt1#Yy2N){6zLOYm(W?@>~~Bg+T{B80_Kr{XVLY zerI2foU$bxbNHHl%AxL)B^OMo+RaKaE0XF6))=)Cs~RTehsC1{2ZZR;FH2CJY<>tE zF}o}nCZ{zvuqkOL>e>A!-d#qNspy+4u6BuqT4JL_2AFm8;oMsZQ5%TOON=I%9ILh3izo*JrwvjkGkDp^lj8zIv+4jki&K&)Z2kd!k;qUdIE!tE0~5O297vj9%O0L;DJ9uKy!= z8ujjOI{UQo$8Z%uL-veYCJwDnSeXQL?vASaqLeJ;_@++wG`IYmc&;Ea| ziEnY`;u$Z%NOSumKZ%7cSaTt?GFXZAxWA&%esY{67?IX4-xt4pu}>iWmtO%3)yzYq;6{_H3)LQ)vj1lbV7h zvuG@n&)leLz#JT^jI4vUX(0D71a*pY|B0=Dggyd@CcsYN~f{cLeY%d) z*I!SS?Ukffx3A`!n0nu=#=eE?`@O9;zge%`RQJ3~U7cqq(+l%CeKrrC*bzejaI(5C*$q3$S56;3+(zt^qDnn2Gz-zi4c!Mf zY=vW38qN$lN0F5RVYOxCD7A+g?CuT3V-!UUB-u3veF%-4(M~>qi6Kb|+3nOPdHeFVws(8u)vwp2xS9>aSI?e9UW-4c{m7bd zYqN-k!WQfZD&UG&o=}_p;+0^*6p?g4!bhUI+Zb@ji{8;;b?atoLPe!n^ZU^-^=cFr z=XZqCV}D))6V!Z4Zib$XtdvT$?K}+q5-~t1k=!1ChcO0SC!@-fM=_{y zPeNDfb06LkMIZK8JdLX`P^oG%Yu{TnAUyTb#r3Df_P{NU2HDl<>HkO8TgFBGZr#H( zq_l{Xw6t_LhzLllNW;)2T|*3wf=Ws^NJ=wwcMpxkz|h?_G=qPB=iKMH&-1zWyLmm= z_1$Z&y{^5!tJ(LpmyZKgLc`DxHb5hbc31%0D6Oe1YU5uHoVmO=9l>$~CR^Z7E9;^k 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�{1I{71o<@EWuU3kQqKGbE9{iF z;*tY-+2Uo26FGvK6xZ~t^M8B+qwPc^_P97p&KxgNK*Ynjen96Hd@WXnKDcQ;8c{H# z5-OsZ(7X%B{uu;GzQaIvrNP;e^*@49@yszB_7X5hp;eakIi^uJd_NXyQq;Ei25pu} zPL7^(27}EajV-8*H8ZWJ+oL}wx|>)8b@6;iKTFw~jajTXf(=NMW1$Qqzjd(l+En_C z{rrvi5baghNsiPTV3IF~3Q;!p*Jjn9m58j$@L{d;k7pY>A^>{1nltC;4D^~4?wD;y zS_e7BzBvS;8k80uPo?;E?}dw47SK+JaejR02<9mIN3v84(~ICApVea~=-6?+dPw}+ z9*1$LgxhRp%NjDI_uIWWP?y^6dkpln-Fmg#T?)0`@NoTn)YaG-U|g7rKn z3teMF>*1Cn-2tqOlUV3c^d^2{bg&s+awer(K=4jm+$Pc6(3v#7W2? z0WTm)>|D)zGdWqDc6MfrzFRno<{NW)$hx*`iPbQ$%gR| zb&#q+X4mc0vvTLGXpeD#=xD3qTRqMr{Kb&nLL(2!hR0Ez8 z3D^+0q&{G4RYOqT1M-rgDpLlZ2v@p@E}JmoH3fR^|FKBXHdSzy2~@OM(Q$c}v>an~ zW^ZyTAnLnZX}EY;ffDebU+!LXG`9E)b6l^uNsq^XKw(#ipf|I(ru3Gl7#UI8KGM;| z`L-=^9jXCA<5UIsm*s0(+l~NauuS>+WXUtJKNIC8F@fB;itY&bu!{ z+R;u=VR~o(c0T=Y%TJj|JW;uG#mFc?PlaHryI^GoE^vqw6%mNQQPL5jmKHN*!r24- zwmyyY2+t>5YC;akzkLq;f=S`Fb8Ppd_Xa^NT9Lu%HX9f1m zj#RGXO}jaRDNs&ir$}>t^(L4rVy~Lk;31R8$c_Y{8@f zkUaT}8MyunZB`dhntpXW=-mBcG7T$(U@eg!$CK8K?3I(44aN6ZQ~hz;jle5jEw`f3 zoE%81ABj9lU@i}4wF%o-Ly1kO!SIL~-~i?$Q5l0%ewbG~kHjs9^*v2V(Y<%v;8`t? z4$WlX-87ko)KUn&K?Nm#%V-f9+}U5;wM$J)^hCalD~?$Dt-Vb{jnl()zM*$9|2@21 za&0O@l8i8LSCekDl>I}K>4ieCS~(FtU1XpxLjgdx{K)=5G&)}E_U)kav@JtbYt5s@i_U6_ z&jTp01z11c5;+c6kaHh`_ffgN=`QcanjcsKoudg3ut_c#Lzb<^Jish1*!g-tf8Tp^ zy?#FfX6w>!_5bl4idfisI8i3iNVXL9$^3Ce0DkS~2f(&${P4n`=>h`ZIq34MgCmY_!nycGh z1KN4`fRJedl(P%2X@QL4YXn(AiH*}w%R_fQIbXW$BvPxXMx5^5OcY*rRw8md8Ad~nam+-`X0JTM#KIWl#-iQz(?dU zAFZuB=l^a~ycc6Cc8o=}jESl&pgFx^kCa(nsSMi}>x-6nnx{CVR)GCvYOTU%2oVJU zb#g8EnpWCYkxJ)S@;Sh~%LdD|x0c;k^>4F^nZ8JI!=@jFJSz?5w4Pw*k}-u)qe}?5 zejEtnbEmBtVBtn^MiuHNi_CZq?RCG4jl~~m6NT|O_uv|6vkKPh(ts>-0@uyZKS>bj zz!*G2nwPPoQkz7XdD>SJqJdTdW?GT>rpTJRHRIsHp|sh#q`ARASlE!gd-{EhP0kdQ zP;uAL$DIrBFnB7#ft;;jyqYzv^9DD6lGT=lf)f17j#(lF8uPlE#WG_y_iPYTExxBz z>Y%?mXNz{3O-JB}DpIH1p{8Aiy zA4x>}AG1?6s?9bG*!1+*!`b6oZMVnuV(LH}_0{q=lq6~gFC$NfBOGoK+9gbfOE_DX zzsp-Jv4Chmr?AJQo4zv?>8T7Bpqv~ znp+$UeTyQwJa7&hZomE37l^G#rs^`+*xXDa1DR;6KrrOG4k%}k)nDxZUtro7Jz-w* z{_TfyaDlaKb0J=8{=@qIH5@V}BL{cY!fw;`=K1B|@L#zQUS?FXD-ep$^w-vwyO|Y& zESAUBCs1+|2qeJS1SO&V*Yp3R$koe~63wWA)X|RSd0Tr`R6I-Pl{sU(;Sj|F9eT_e zxA?8yvfvPhTmc!-$=Vcg;&I;HLiidhq{?6={rt}kx8%D`lB$p5jV8k9fRns|9(_S< z(v=H{DF*KaTY)gSGtk6?Ci$tFY@O*Z6d^QXN3~QV21jS|+g@8uUjI{tF8|d28OvV^ z_ZtUQRHyDsSmzIeTJl8~Vk_(bnCHowbA4^FLsV0}p7hE}y8mE<_j4;^sOP_r=}Crk01IamiQ0-&a(48|YT4(}nlL`BS-Yx$^fDd*!0$j+8qT!SxQ?M}2LIa23*U2qr`3wl zw6DTc1Y4vV2#$mwLii>@;L6x@{-xEt(U4yOgaIogT6eL;sv0C3bw%QszRRw6TJ|P+ zm?@~mAVk=SDGQ+}vgTusf))A9PfGVq(|tdf%8s?^dHKY%eZL!epRUoN@8(u@J3QP; zPTkm8=7E7Hs9UuzF$Hg5mEvqnzT)r1GYdsoAIUBEz4%TOStfFYn?9zK*}-jZwA_7+ zzIr0uw*WH79x{nOU2#>cSFm|Sd5T!D{RA@nZV=57f&G)`@r14lp3NlWv~WPfka}5P zeMNTJSZ>AHrEj+h4G@6qrSQNQxe!^tP3iA%uX59K;>`9D7=C}aB*GyCS*RLvXaS3! zD9A*{_e@Z-YA&O<`sc}$CEqDvV{_t(=CD^Mq|#Mw#%wgyOdU?ILKHKuynpjE9Y`h) zz&@em^#8sxS!~ZGEmzhWt1w#YCNZ2}6=Pd+*_MLjO&>YIIq=z)dbY6E;Va{%=%CU~ z?j9&DA<<7?$lhykCE{T9u}G8SVa#st6fQ0uLP0zkctefWkrJ*xeG8q|3Xtf0f$s-h zhASXEp)Hdo!GFyxy;TsL0GuxX4Vn?J`3%YQRgpt_Q&q3k1wB4|YS=I?wBS1_dD*k! z5(x1!3ri}a5rG|qKP@KFeH@9fyF~Ll=#t35OsJT}xTZLV%;NQw=J%*DH3Zmq@i|yh z1>9G|*L3y0r6%QINrbyq!1VA4X4UxNP^ru^1r<-CjF0Uw8iRn^hoTj=*A4a=v#kzN zF+`T`0Bs~ZcAB8QGX&-FVCoQwf-6affGC4PX%bU`auoIV(c*hNyeRTr(othhEDB%yodGmnup(AAJ$B7V&_NRX)uG^4>nL`dtUD2zaA>`l7vj_n^zn{B= zD<>!aB2Z-n9Wzk0Cr9_yYkwr(#WK%VBkhnK>R1K7TS`}iiw{-8=H3)bXO;|`{ku=mjtw%LxKd%^1L47%fF z(@|D`@(O5rW^<#CAsVKvJX~0lCr`PAFTFhsSJdj>JOfJ;GdtRAg$eFDP-1n&`Y&;R z^kT~h+f0LGxSZwMF$D5Z7sDr3?{2PwPTPYCq+foAcNC&GBmCV=r}|$6HJmyMrYZu&@}NUdPe19&PHLI@Xx1SQy%Y?s*)8?ajbYoe{JU}3%0unaQwq% zls4D8MY&eExB?0=+_lhz1hy0V19fqK_)+GNeDXQK50Y zhv3{FV`>m>nr^-PQPg-lOSDWNoo8gR{nJ4nZQZX-XQOeu|iUd&1S1 zb0mSRt}s@iNt_(wq#v_YARWG;4M_dA&Q(|BHkrK(~7 z569}F`7|xUpj;1Pd?iq0q(jIpW&RY$l$?Tu1b6yRdjiW{F@rqPI9=YKh;&UH0{X*y z)YKFesX~K8Ns~{I8@5MB?fGUX+VxoX>+rm`=YGx7R=49bu~HSWwsTL%{q#TVEljVy z@P+HksLWBV{3R%M%tYb1#XasDHr0RC0wBSCxchCyb(wpy$qbz=tE36S%B)roqcbTg z#kktj$*2FVkFj-6xYn z9~JRTG%_p0)PE7wz*2$H*&|VuK%5WN|$z~k(nrT(cRVx%C zcP0+B^fyxjAgD&5&{*nSaj3Ec*Bh{hra_qosUozI=gj6|)t7IE73`!Fw(&FSx@P=v zUxeX#tk9e(v}TrZYIeIl0n#9}e)Mk8G0r$x6s%j*q{lVbUH*<0czoV%V@rVgN6xal zC&csY+;#+azi>SACAmYATBO^EhK_#g<#}?QXsi8kw;GRV0|N5P;g?o~w5V5$PzI+T3@Astd|5%Xwd|qDaX=Gz(|CC{Q8l)o= zOhk$pXYxJoC_t?scm*6ny&TBV4p;vu(c@Sz^(IBq6dBO5;4Gn022=A%CL5)LM}`QW zWk)`y!eO5`YtI)-bMj@8|AC6=7c+%R(WHt0VGP?!ro2yEISW^DCGg8;PD10;*sLzP zIX^Iax!*HF{2Fbz96jGM!etVmt&iPuffSbsOF#07Gu0+v(^ta);6?gsR6f%e*@prB4AHiQoE{uO^a7{+pOA4#ApjNeFtkb z$hZ^UTXm*y`utUYzhP$)Qhn`-S8`}F$RJ_jL*{!t-?H_763w>N<9=Vbj@Z-PakJI` zUTdS}d;Hq$N#Ao}(({d@*LP$w+HXuJ1LvKaq`0-a`~NxI&E_W1f)g!h28dREL~mk6 zQD<;9i%t8_Nk^hWY~22mxCAg$#Kw}i(~O)=V6jqQ9AsXD{*PuX5yLD$>S4={Ph7nr z^f2wxiwy=6(4+&>un9*%=P}z8;+IIhYqs?w?PL>#jKeSYQp09Sm3>(p!y(fjZADA? z#pr&_kmIoD?v3G!zX7ul7=68APIvsq0j(kV$B9JHHSdwU)-Gov9O4TUjB6I@Y891` zL3)~9A%s?PuZF}Hhf66@CC1~6Jl|&?FH%UftVdj$lNXuqt(V=rroFwkg|LzWC1FYo z;#-GcP;6M8^B5tcmjo{xjhksn8Q^bOpOpkpny75CaEB8vEOMqMV&;w%s()pVVhs3b z^H$_lrt`NlxFpRZHm6r_J}2rLmMP2=*Uq_TK3~QsCKE1}yr1_z;+7b@WKW*0F;jDX z3n<)Z0Jo&JDva#luQhj##@f!30#thNY5PP5?OK0e@MG;S^7LH6I$_6pY&MTnvEf5* zDP-2mp3GEG9!5 zZjYG~uQ1G7(WDQ-5iE(4GNrGr2zzp1#)j`zT8@UXiI$winjdsN;#<@=EoS(O%%P1^ z5L)leo95T}z^U1c_b$O7hGIvQ$r{!0jp)#%s6kB92}=Rw4EefuuIo8!kBO+;?DKuTdxYh_Rd;qDFu$5iw&<(RtS z5^mJ|MTYefewzYEiToJ7kC*4}N3dp3r}KVxCYuj0-`D-}5lAv+0oVH)<~SDRdmYPv z8i&wx`{^C-Sl7X|XF>PE%yqckjKkY0J$B_X7^Zir__1iXVyie}I`z)=9?fT4n`Zm| zzD4g8H%&(luPAc8W;RcNo8BdhYwwEqGE`n}*pu6K{@+!ZB3D_@DsFp)61zXX9iah5 z9mDs|T70t#3G=~b>(%p|`_{50#2_9rt-sl5Ch}(RI)Q`odD#(~9u2AZD-ggHWJ!5g z;JTk_$0Y-=s7w%0k3bSpOh^forI7gTA3nNsFE@KLAu+HEfWmh74QZVY#&S?_{_(tD zPq0lA1~>E65*az=mfK;aL0`qX2;9*qbyn2uFqmt({rHcNSj}eSMq_`!M}8|IOivq; z1pG3~k60vKI;7h*Db)nwe!eQ=VMZDk-TiWbNDot7N!F4aQs7BaZ~YkP2R z7r*DRh}LjgRbUCS4X*Ar75o#js2Q^%=V(kxuiW?G077hUk7H138@7-8`4MQU^?49v zkIU`31;u3fqv(veZ|D8k=^mJtjUu{C_}-c1DV^rI5mZJtKl(L7tYc zX8?RVo@T08X^R`~HHV9jO5>51i3(QmG?4L;tu!&K8S;K(!p+sug^-ic-ox$7wnfI9 z#G|^YG55*nptn5T$-$s5^4v3o-fL-5{4rKnLNthm?cqWygN=bJ6KB}j+I}uaQe>Lz z6(vgQ%+s5;G%zf*ekKaVdPpdXL;V81m+1djqQDjjVsqkU$}>j8XQwFUVKC(Dhyaz~ zz(W!p5k1PA30EL`V-e}13s1r^5iZ~{9U-uGnQ_>JJF3hVX1yYb^^f2?XhIJmEGaP% zjjOj2(MHeTSd8G*S#a(B#r$g<(ry^RMt!xyxSMvC$v~m|su>K3Z!h}ux4|8_B@B&& z@TSM|J7|{9W#8LGS?$nd=|gs4?Y&t+$5g4~V=rMlQE&8M$|(+qPaaB~hXa>2MM zn@M`Cc0BjWe_B&3`J$I(b$trM)#-Oy+&<#c-o76v>(~o2nX%DVKs`whV^d^@7%g4q z(LhHesLhZ7s0W~`eD3aT>h?Ilf!@69jm{Uuay+)}ZkNkXYIY{IrXXi(HixIz&Cb>UiQ)eAlb{}vqZ2vn-|=inB9GKmvS1uH1jKj>?xzfQs|3s2btq0aJg?ezQoC+hjW^WF}}-dmATUITz}W9 z9q59e4*r>5phgWVU^`*V9~^33-38C)LpmVJNJpW#)VYJQ7nE4r>fya%MbOI^9uDpy z-+-u5QG`Srg^ooBuivOQUF~S%Q_i=Ky8kQH1BCLkD0&7^)-!*Kn9*4Ch3NXYByb>) z#LaABq#7jK$Tr0CFlpXf3ZB$-nr44~Wd7O@@UDincy@BOv0G%w95Z3~PNpJ42GS{) zmu4(z!N3OGR$YUV&|W1n$&etosZW}AhxMN`>&mRlngv&`Tp$`5TZ^R=w7?DfsGQ`+ zPYKUmwARe*`&Hf;s8I;lGXxn^E<8?dm(bwYgSs3wpPArp1b9(qjMk0bY4G!TT1@iE z)N0}_IJTDNjx@Q=BMCb3Iq1ypO$98Egx%#u88_%K1b^J~>}d7E|0YIFWen$=7!1xXUn;*7$0SFh)(iSq-i*PlVxNR8=F6*xEq z20uUk4Hz`qz^2r%Vb|f9eX**y;G!g_xl_`P#$fOCPKj-R|5x>YdHhD@n zPp8U<1T|7d_B3s8$FIGYJO~GVzJ93CdMT^D?Y%Tk=XQUbi^lpq-t5*A^1R<{ZGsSP z>nGT!@D)Yq)|WjPVH?IYta~#!M^>j8n46q9*SGBHgQQG)OHH1j)P2?OV-mVe^k_CN z=49gy7Qa|IaJ}RVG7yf&aJc2fl~M#nY`C_RKEKeDSYXbkK_8Ho9*GQ@ ze6X)s*@{Cb(Vve8qqHTAL-+}lx*N+wN$Kp)EsXT$JT$J}&d=}cE_NnJnKVS5JNYN| zi;p<1n)f#tLo6sVjjNL-j}`f!6s}YaivQfuYNsD(O>M=oifnN638O=)klao?Q?w_c zD6Bu!vT--LV26Dv*$ZFTTX1uti;trCgD`&j_TAzu98CN2NJ7Qw^3YvZnD1M*wnRM` zD7w%As;GfJOO@q@_&1g|KVI3+))0lN5!5nXBOf2Hl`yMEVwCmii#bJ? zduJmuooBZr8MSRPXw97Gtzf%VlrXWb{M@q?8VfT8L;e;aLokh7t^MQEDf~Nfyue_9 zkes{&OT{d^62YX>c;LK6&jw!&9~9ryH+pxd_!367Zy9a2(X>X0C!N{_ zL!z?S1XosfQ4m<^9)mqF83dbWl(MMy@ z03B&UM{7>lYGBW@qqlI7(2?c6_#_qQYV*$`f#g300tz?>=}cuU>FN_)QO-WUF}5oQ zhD~h}{$>a~)1}-tOs&>bRQ5R9ApbLuHnDdp)jVgL^9tWGfu4=ukbbig)xMQ@>l=GI z#*$~(|1`$~CY^)fJC*M;0&Wvvtj0nM`f^yakXv>DAN>y$S+kwicr%OcH0kS`n=0S- zyREXNYlCp68V^kd8ZBb#t$%ErpCLki&TV7i_$@j^>}+#;Jezuojpg+WS3VC@E>^BRrBsibkyATH)IS_{EYCN zoK`QAY{;GbKsF-3r`!3)@~UlOq+m3M^Mj3uKQrOT$!RMNH2k&dH;LPMh^ogM{E!Uf z@{kPZc^cdcsq4!&nWeJ$pQ&O_bd9xzG1H_DJ33p5n7*zWimBN%!v?>n|C?aXaBei~y;|S8zo#Vo!OSWI7L(n>kURFB zTNHBbTK;2maRMTv3w-hPoauf%JoxL_{M1Juh!zRoNLDe)lKc*~!J=APWFxPR@Ss*;9@E>2hjFpI4 zL=b5R-ENn)Vjv}Ukp}iM8?6kX$d&v&nF(uViF_zY>bq)f{j5@Od~JnLaLo@9>3Lk3 zt`&>B$5TgtN5Hss*H4{xQ530wb~puEh~l#g2P7DB(#9%+fw&O^j~_G*a1}41v^Y-s zRV}wZ<@MoPdab^Fz|nGB{`bEWtdgr$RT`Qh!73K)RGHjy6G&1@r^lq`8@5rA^QDm2 z-`pZitdPDt_M%QN5zlENCp*4j9&SL&GUdC-ovwTQv=%gdjw0N~s4G_UX5Z7mV^^TY0dES%qU zcQDq8*VgEV78s7x>@cxmm8=Z1(;SNQmXZT~i!o=}vj0*-P-B;6K&WFEKlwVE` zkRU1G%h=cs192q3*7@SBSJ(|rb#*yNz_=}lj}(b@>X9B#dO-qp0%f9kOZl~URxz$ zD<=oyd0TguKbyk?a>b2-0iE1S&}6k68R_g^bPRTI0bG+C?M`=9VR%bu^fEp_Zoce%A>aKGUUxrAIULL>U9shmeNdq6q$EtS$O~62 zjLly+ia)PK{_7G@)Bo99puLm5b%KHnYNjSOcv*rj@I88#=2qA9`^nytkiBCU|L`{Y>||86oMGA z*EY`?l^4%E-u5r0$@IDo(q*1F2w)dzwWbt$ph@au0%>FuO^#E-myCnU1OLXNYeo)E z9D91UHz;h>IthmyF`&j0IlV%r;YZ$Bdr>Xy3E^jJN6n(onu}Fsuw5Obf4~e>U=@@ZM_f~c$S`2ma;w47naqc=g#~~;0nsXV?pAj zYLq$~UiU{`b+Cuw5YT^)aDV$-BhI$K+5N#mYgc90PYISLZM z4?0$tmnic8qw1}q;)<4V-6jwSZo#GT5Zv8@1}C_?ySuw5SmW;Q(h%I!xVr}$hv0tM z=iD>K-Y@HEy{)RbX8rY5{g?)z7)5bJL_hM3LAmfFa@;n*S710m&XEW1J2D!Y=4IEs z%I{&O;YN=u!I$(*HwXD_DxR^T8UvlNz}%3=5c*3wbE|Gt9tv}X!{o$M575#4y&RS$ zzL9(ih?R}i$L1?83CWkGlgvOIWXm^|``bIOhPS<)K3##NZXfQ{cGmST=Rh8~-sjVQ z&Fo(eGw6}06WAL^id3my;XAJf6kt6_4>YQW*vy{y#UU_eW<2-w=LzVQ5gy zJ#(LrVdrr)Ber+obcrkgW!BKxrmsVCVU^Nz)lsTo z9Qat+y6kCGNBLQErJsh!{~B|8pDWo2#hg0^zulf9I^C{v>#JT>+XmXg$yDyj5-Rk7 zlk{lA=#5c$rhL!%&F&>Es@DNcUlP{|8v)lb=v5&^Z-L9UhWOHJsIgxQku8os>*Yzb z-?BB7N{rh)tR)`NqIIahGtM{xByOq4$~czfvg(`CpOhBOD}rBrV~-rSz!WpYg_S0N z*LgXpJn!tOp0%aLR?I+5F|x+?6Ez?L*Uwblfna6v_}HMjALdxr?FIcD6VQG2Fxx8Z z^A9SVBlLQ5`SSB@W5f4&e1^#D_+aJ(YC4nPV&=BE$tn5WeuC_!?%5{;s9)Fk?Og*~ zdC7YwNB{(SCa=GNa~7Q(7(jX4+#-LX4)uYY_ z?{@j1TnWM?CG%zTnVy&PkG9kUpQK)2<}w2M69YQ#vy#ZwC;oIZ1Y;QT$ztbaS3)>Q z_qKw`1$#Is#g(nG`ve(T+^O+J(m+7o&&63as{q}L5E98|BrJ9#REU=Qe_~(Ii@N57 ze#RnA#(-`sH!DkL!rZ|7Q}FHKbsrTz5#t)Aig;aD%UJ1`7a|A*cbmiyrr_6Z?+r~^ z)Gr+9?b21MoEfmrh~MAdKfs@#=kOQ#Ra956TUtDDx&ZjW@jn&9e}eqR`be{1lHW;9 zqq0Q1(e?3*e}A~5+i-CO+YPIJ#wpulMDZp5MN5?WMzn)CO4|-tOZ`IgHB2pK91u%p zFrKP8y<>x!VuyWb6bR}WGa3oy()l~BD>u_%)`b5-gYi{7Dbw)KI%kog_hZK4Tt$ZD z`UecGwHB?s8f?7j6i)9{71$(`u{OHT!|Y8cJ+ZTEAe46tyo69y)08C~bPI-t?U|2y z-~{-T-8tJF7aE#jA?PcTR>8nX({Z3S?+{m=N4N;xgytGs97BQKWO;HY9S(jPe?J)8 zXPBicATG4Id9(ZJ>^xWaNwEk2h$`@@PG_m_^C{p#!Y@ zxN-j6;$H}RRx8tGp#9z+cobUx=}J)%=h_I%HF@%}vjN5DC9cilKzUgxn?Qa7eBBqu z{zcKC9TA~IDD0}IsjkYRN6DMV+m6Y7dn{@MIxzU~cgH?NyS-jV?t;JJMiEzIW~quti&~6p7%NANx|j zO3Z8L{m-Ak0Z&(F(Qwe0!}-xA2--IV7~k3)Lcsva?3|xD0)ib`h!cd4#4PvVCz5HN z5Df9u@l87(8LTt~84-SK$ z;Rx|vM{YjOf8~isnTb4waxks@s(QkXm~f#RC=fe?Xpbkjti{43y3C$HSj?DOfypSN z=}1ebRxaROX4O@TKZNdNMI_z~<-YHQe@LeibJFPVU} zJ09xA^aZP9=J|w-baaw-N78aZV%cyE)V4*4(oak}8Lq~8%C(lZ{7a6;ji@2LDTwQ` zG(yNI!X$!0HwZK!g^$uhvAc@4lZ;YmOwd*GCvJg9$uWD2Hs~INkdm;VQ-2Ne-$e+>RYe zJr6pvgv2$`5h1{|jfQtdPN#O=y?5gaH*maxq$Nn zkEB~{%E2dbyEcF) zA315d-!0g=L(KJ{H7?lw2m3ztl3!}S6JHRZu^s_~CjMAYj}qgD#Klwz#z)d!Z`FCh`u6O#Y(Ried**O20G&>P@TR>l($*?w4zX*u|~Wu*}>L zAPRfRlO?S)dD)#=*ng{UvTi58?RHaC_5$Bz2rV{h*SL~(aMq6O_J$6}%B@+V67G3v zkL0^jo{+6S=B@d5i&G&Q&0@gA=I$yQ>bWkdPxYV_r}|T>G^^>Y|3K!?Xelh`T!rRk z8b zZXDgKz|J9$bLF;NN8F*w4%<!an-;0?ZeWe=%)oAAty>A`ObL6V^t|-ZM)* zXuaW6waogI_i^3b@qH85-)l_Es7*GEX{v({pZ?I{S~a8ecsg|qbl5%WjkghYVWFYF z5IW)|QQ}W-OFI*bObxD@-HURAzZpX6yPFw4Y}p|%e_t)R6xDlkKYd8GnS8r{Uf&e< zd3@NF>h{0b(zrW&IXcTmKVRGMy}H?9etr3mZc7e$<;C-^OGzC|?F!!U-xb4E5jM)V zdQh5tcq{tv3r?9B4oTZvcH&Iqqk8rWlD`J zCyZBP=g6b{=QDk&19S5rBJpcTnGS$|p>n+f$KJBM??~xM)GtS6t1Eh0MBlx2!dyooB*#=#kz^XK^j zNyINK%4Ug#fcc7=c@(j=3LVQY?%pjr;=4;6#)c6@gC7IA6M|5VZQK2Da?#$7unwR* zx;^iT->%%ZT2??|TzYkEtLsfziSzdcmGfq?)mM!!)yAA5vaH;%H!V1Tpv>MMylM>D_mHM z`}L2v?E5!hhbRDzzN)Sd>HVQEPa+129k}9Y@uWG|#C;i)p$tNp3IF8qDNrXgnd{x` z$q*em1=prDl*wFnC(O36AU~zOPpeifb6yxiwgGz~LdQWEzs~5bCu-b|Mqc^N)9RYxA~c{1+u$NA^?HHtAiVmQG46lG54j2o?+|T!r*Y z-OGHnxUi#xSHy%QgjNBAByoo<>unKojJ_|t?>Fs%MFCBK?q%~!+oe0GP{y?R z_MG0pj%?T=HgN~(L~9B9ySEPaR>yEX@C-Il-ep0ssERf8*bBh1f?dn9tlHbza&En>!}fX*L^`Wp+{FsQBdDY!VK& zdT;C4y=30pz0Zvh0PasCa)o>^wmW^!|I^;&Z{>EV#Wi^Q^6tmUyP)Ly?NZFIRl#9^GOWE$tauZ`9EiPS^TNy+Ay*j>N0!KVg2gA6z)DERK4-` z4Y=YZyGg5jW`%k7!4VPnv4-x6G-}+9+jV&7CK4M}2 z_IF3qi^E-Dz$(c=sc|IVkJRfSCC~l77V9{0;5{4GBHgNFR1kv5bs89DwMTe|zGyid z$rUpJLVTb3@`jPjGulzxErG^I4k@`p_*L=Z)AXb!+kABaPB2<)ZKnSb zo4vf$5!TD%uY7}~FA*@Eb_mxHpt#Kfv^J7w$8k6Q!2OUD3V+u*%*uKCWIlb|46@*m zWx0ISR_kW6G{8mL%v1VjG+hYVH>B51rdLH42&N>t4fsggR$j<1+UjVpa_w1gMPe=g zQo=A*+jieXqNLWVI83)y8cU-pU{Ve)eoDR3xA&?hXpdcAK&k$AUO=xirV33{BPv-4 zHR6PqvdYGpK%gzPz%aCXfrTm=Ll;&S4Q6Qd1#6Gy4L7Z9igA!i40g z7OI8rT*;$n)GM*TwY*umuQgxLX_r1=wOVpd)K3N8HevvQ(Nt>Vl)*1J99g}S20w^d8n1)R#}9^&VA2!c)%xRbCX=yilCAzv zLSOSxQ{5Wse)sRNBp)QM`)=CVlilM9Zs7j3Bl=xwsZk;yt4bF4|FnQc&4w0thL^B> zKa0R1qk)f7_N}M&Bu%h7wImQl-V$aiJBGwxjCnrT(R}%BVH)$flw?_RG@md`iH0si8E=gUqX;6}$&?>fI@5E{-_ZV}ot|BIiE zFHQdS;OXnS4a?^JFcPnH`e3Rgu={s7ECFwB2Emih$yE^5QTL_%|LRsPCguE7YuAi= z>#XzbVtFyRT75)Zg^9Q-d$6st7v&#_2}Py0jBuUfO0>%=kKu|L9|=md7%;_z!qnK{ zy&;2yJ~l?WEmT%~0$gK1ByT8u)0S57$UEKMr}Xq1)vhBG$k++#d`n4?6TnRZJCZDQ z@ilrB9QZt!N|nf@{kDv3R-9$o_`RGSWUUpPBh|O@HV(_TTtBjQIX;3}52{=Yxc7aC zrjp1-MKc+F;u?n471e$E?Hu~vr1^eT&g_mG39Btm-tb!#UrtcIXSQ^nG|4!6nj>y*=ixH@5zPPZMO ztKMXC-h_qkAGt4^L+l&h=Zl-9i7YpUF1Uyco-!I8yJihx>)fZQ0rsOX5g~y)XXf>K z&QpR4L=)a^9G@IrI4`T`iv%C?mewvzi@;3dla8zA=kLBgO*Pj`I;;4z5{3;~cuiB; zXZO|9CrIkMU!mSV_FU2E_Z80JA%mQc`sD1(Hb^hpYs_|q`5Aes(7WT{Tf1*BkDYzM zT*0@OSr7lGiKNL~f!CAm5XH02r!>7hZuQNkw+D+rDJDkLG)nesDvS6(iOaP~c(^I^ zYGxag#C(`x9qh41DV}n2Q4uB2kedDEy}l-34ZE*DEC1Gj@A1s&Ncyt4x?Jhi^-N4+ z2|FL7!sxRkB6bGhid5bed;OtH*E(x~_mg~OhzAK1)#bHr7$tUn3UGArWqLI?D@u>| zst^GGWlvueT_DNj@HnY7;JO4p)qAUi?d3NKK{pG(&n5Hr%saNSG~Yw>cwfH!7slhf zgSX1@`nh>foCflf+3iYZGknTJj28nz9#20|eY4RKa4OmfsD9+{R5MJp5I&9tY0LcYT_T+rSf#X0T)?;=%j6L4M7x- z-J)GDmh_zLMM~~KOuWGuyhcxxxc#7Hxn_h4Yn7h_fxV+Pvxrk8O0by}?W5qEd11#7 z>uqe99;h9YkNl+wyf^`8{Ds7KW(%~ZaOHMw3l53BTFOfS@j&;+6Ss{o7w*~&{wDATIsQ5zZ)rsrN*V;r|V|3gS=RGOW!#`v6JNJV3>QCn3Sw06wrH5fX4UGeNK6d8II@V|9T?U9FHjfzg+Eg0uojNC8| z_swzW==XO=pXOx(J#SFkKV$uLckISWrk-i?CEgVb|K;VmB&Dm{GHQSb?ufQKnQBSa zCG|P;Q@pnG^BZQE3OQ@g;d$|>jeUKf`RO(5QTtcR^)Ft=ZFNZ(%Qarb6UFqiL4h@?a9r~0vo(`b*bSe; zxcs<$wxA$^toc>evd^Usgw*gC3tZ*p-_T-W)y(vtq~B%v0?fSW_}rcM#{Lqe z|NalGaU)`iY^H^^r@K5S`*9K*50qR5oV(uT6iOm{AF>-fLAZLI2Rx^K{t&$!a&%u# zu#!8_%s%{eq^T_N=8(=0ep)YHCl{G`0o|co@;cc|DH=@Y_8Z+DN%ocZUNKD)K z8Deh0N-abr$j;hWw8y?^AesLie&XY35AkFS|3{p=$W+*@q()}miVHjpy^+1g>AN?N z|2>%(u7l5vJC!&Wj$2lo$raA3YP&U=$z%`!DD^*dGmdFs>x?+xYlA|3tz}~wvPQ&2 zDkSG^#1rtRI>wG*YqeDrV^1wA4pc5VXWl0S_bEe%cCM$&pI`A|k*de94wP+9Lf1Ukn#W{1k!9qLOm^|h6$!yWlr%@#+n zO)MRLCPh;VXZ0ZOZMl!CvE&p=H~h}j5mA?tUyf)dt~9xQz66gax{db6HVyxw^A0hq zP#-EHp_n9@c>T*|UOUJ*EKgc!=D}KOudSw5X`Mk^eEp3v&!JnQ1wvOpSTZFJaUXBc z>MkbPRd>K&=VrIPKLaAB~gMm1HxSh5UI$c_MLwRlzE8T~P_MVLX`rko2m*xSWr8#j}1OTP6 zj0v)n-LUGRh5h8vmzl*pY+pr;@j(E?&#n(i?2l7@F?~J;f&sUKv!wx^2Z!eyUjH6e ze+q#E-U>TBgnzqOxVX(fSxmy5;e3YJ=4m2P#u?~pf&#bvjT~wDQso8@aC=)1C_Xrg zR~MLy9z&Sq<3`XgA(SEb>}<{Aw4P=sP)_j)U41HmJ^+xLp*2BQu1bTdO-k*kT=X}k zYGHy>JSkV;7%W$!H1Imh2~)P!Pa;`@6qqW zTE+>?m(x{|I&4ydja0{oE!Iwf5GgNbHh1>XyIlEUlcd+|{p8G7Bp(kxf#x#WR&j24 z6#CZt1@Fo094^+&lg9x;B|MQaY5_|KR7h-=3KH*QN|8<1dHpDkan?u4nUDjtJ z4WkkwnFw()Q;~*3j%!B|1@TL&A1=(<%*gB2!$YGq4o^ATgA2J2gG1?qbz0_Wy;0*o z1bfmd$lCf1^moEXbcpWRV(qL*Lf~H(nr_=;exIA?=QSf4NfnQJ1)b>Jp7i?YhPeh}dI6wgUHW_yUjNqZXA6|_O_ z)>-u@+H`}3WL$}v6EBxhlw7W{(F=fG&%x4KWq69gVhQWc8txZk3~JM0qc%6STG^4s z)e576dGKa4tU?Xzcwc=wm(~FloqK%^KRg7C4=dSLV>UhBA{em_zTwK`U2K~K_mZsp zlET<0=O5D?(5bO>9COK@tPIA_a>g&2ZEIIbr|5MsYQZuI3l@Uqb;Ea-E9KAH1+d$>EvgOmoiPxUza z-QBM3E%=rscD@N02nM=!3#RBeMlI|t(oCXByqZDfuCL2}n#LT?J&r7P!Dw z2UQ_N;dDnpQ+1-Een$=M5zlaRr<;jA#wE%R7)Qw&n`cQYYsy-) zIN>Fy$;zR(?8Yk$r!=`*B1g_tV+v6>9uhSo(;tRGY0G#TF-Sg`v95K|^cQdSxzww| z<8Q8JY05}nOBzXe0>B=43H6ZrrTI~Ir8+!zzhK6Act_t~*M({R&m~ifg1O3x_0TC< zpv-3B^04;GylQ-os_V0=E3PVdGaV&`v(eMP4)VzJ`N?;GC?9_R{Q_mm)D0vKyZTU! z-mTRrZ;%_c{+rX|^?FX8diWTa)5eC^fkgr&$WDu*_nisiKmFRu6Z?zb>}y)b@k3s| z1G+&>pbo->f&Ol|7qw3rQNUJ7Wd9{c#NDPdWj5IDP|3mlzxaxGW)He3v4B}5>nXpy zrvArD1oexhkr}#$doJ6+Lpo2RdH;Buq^jhaO}!!xkvxpjLk3(~=+xK`{r>t)@w)hV zLqSvQeV$X$!#oie?oVn?NWLHTyrZDkZ3lAJQui*CY? zT_J-tZE}qSDSMAS@aa|`1U~yZE5pHi0a83=CU(RnG&UgU~wgR zJCJfhrRkKU({;i!qju;es-6wh8Zx*2RgJDM5*c^4q|Lqgm-dM|>McjhX*8-Z-D9M} z^6EN+J7h+Ag4ASC8GCe;hs^Me4i}^+fMeY|@@lM79}Y zxX*+>Ml4;X&_;ZI9lk|HGg-h@P zDeh^kB_-g)!JS!xqwDQqyC@5L;3NZsFM!vh2Yv$qzsFpM?w7+tsdusE{_+I@xY7C4 ztJBJ@u}S-;`*|zDD%MIL|FnK;-c(&npyxX@a~xv=73MV3Au1VQ0=B)7>`Rj)<=e=| zRI;xs20jkQY51LdP9(^TW~9coNb7=zC@-ggEnS(K8+hF8!&TD4=@Ago&5gwDFf4I^{B2q8ZQl9{I5&GzZgrKnHgD|Zsk)w0%e3@ z=me`sI(=m?i&b&^8=pFke9YqRAQfV8S72S|TP2+v7II4_qHb?*;E9ud-OtVEDfX*W zi=Aa%Hus>Mr~KyZ3~Ac(r9*P&ZHdv8kXQMdrUwAZ@unRkc_^nVY@H>jQfsoMS? z%N`Z@K(rVH|%ugTNme}6+#iKQv%8xoZ~aC zQ!S6{0FN)A;`6pTGxPKn(J4#?YK}9v;b53DHiq%-P97~DY@+|j2ErNo_lx^Fs7|nVv{NX zv6UY$;TJjdirX1Gu7een>$?}rnrzrV$1&G0Io=7!dKZ&a z^0yCBFwXR{vv|gc)R|gYIT?z@4ktcnz@|XbsEG}kuMa)K3{wS)EK26dx>Nnnl-xK3 z-B^>Rpb~@#y}$Xy)`q0-Z)RvKd$*#Gb9JDDPC&ken~Ywr);~t+Wh0<|JcP2Q>bRv( z!pItDZ)jxtJYSwD%a~mj6Y9$~1+r1kggbaRscNrNzis}KW63`iez)XVAWZ8Ln)%@U zop2vrV7WIlT5cfmFf2x8QANhx%>U?*F`wHW9>f30cC5Mj0`4d+hP!Y)3>no}8FAA? zwpJv;(mU86Sfm_Mw`=C;WE@!b9f%}^@ypG1Skyo?Mtbi)h2P9vKbth*{gD2S!sP6U z_0Kt|mc`wjBpo5V9LJz&)c<=Rhb*CiU3o^>?MjAOvjDm=GfpRjJKh-#CZt+(s%BdI zjbT5B8C6PnUCZgr826zPw#Rr!CNdFOS>(1_d7)5(=ZNg+#PSDk{Ii7>nUEt8h56D7F&S|g-LX>kEU-;}bXiyL6L|HG&z z4?K(V5y>UR%MEKJayw9i_HlPE2k&Jn3@S)0QHGG%%Xxo%m0})d7fR2~pb^oHml!5E zawnFZcAaAX-AqCR6sol9 zT@!v%mxysL6*mkg+azR2SU^0w{iCqD0Qgly0LWxAY0qX0Dr4U4g^ikZO*4X8{0xb# ziY`}wx#O!EZ;-RL?rEX0pdm2t=P9xXzU8#$ z;A}=`i!h9Q2KTr|R107@X%DY5oaGp!H5(560m<(*OI4q^Y?17D;W3V29piZR)k`f; zxnDL?rQw*LC!`;;BwE7}88!1woG*zKDVtNpm>xp-(K9MeluMCAaJ`8F~TlC-LuUw3e zVlapU`G;&67p|P9wk}lyS>lDP5tLm*U_ntym*1%II+y)h1wwUOQ2RF)J_XhT zI!CvTa{YR~=&m5i1*>^ukPxHZ7t}zn)~LF>Ov*mNq5Uf^25#H|N|{BLm+4nKBsvCv zi~$VM_27M)NMDgyqxr`ZrSO(#Bw(0qt!y@{gx~&kTBO1F|GNzkfCmJ4o^LRpuPyts zpT7tI($@1IBN+2XdItyy&%v^d>>+k#AN2ZKZDBeExOs)xoH%PD*+wbzMweYI3h+$0 zRkSosWtgNLrBqLHO})7P^jYpyd$X5`!GenUC<>VRcFgD8*FyFM}c^my{p zkUr8RWu7>Xu)$P4zf!_eQo9eN@2v8rzyhrmNTYy~ovuGN zrG1-Oh9DLj`0`-;{AVeMYqzp>CjEXp-csn>$jy^%ei(o0fW>57Ja&EmuC;1=a@d1c zlP8Y3M%!!-?fTDglzDJfq9E<9v0a4gVNx2qFqJw`&b(kaVSM|ZOvVQd`8ecO<9|!s z`9O>@5H-k%qz|VS`Q3E2U7fK?jq`({Nv$bNAflVA`d4|_>cIiMoch+o*E+4wNYo=R zuQ()@t~IkThepwAc}=GwWz!r;@?yo6mpT|$Dr$#+Bq2kprPr_?_({Iq23>4R&LM`Y zAqPnx4R%`W+(}|8!h{ZjV_9XR%2qKfXmac&`m1*-S#_8i4?n-8Y$E~2;>J(6(0l5Ny=(VKO=Y!6)Ele!VI^Zv6 z4G_2QTAMH7P!_HD3rfKf~+@7Lc#rUG^awNVkWu8g|8f=^G}tji52tW}Gx4 zE|xO+cilV))4jFCrGRjMsA(SK|C3yQ)&OjEYp+G>q~e`P5XhfH4Tw#ql&xlU(2yS$ zgZJE}g$o*;u*a0~k3s)N$RIu|6B*4fA;+l^8ZC>aXEZ$bDX^Qq%CF;ggWG1Z+xztd za&Z3qu1!vo3O(P1AOMBEueUopGAnC+y6@koZdhnaQLg`B-Ayo5?|CLBQTn27$+TEB z(c=!Ry~JQHL|#LqH5?SAzu;O-#t8YcgmU?~IJ-W}=q4D{?6ZxART7^P-Lt!Bp5aJO ztQ+(=wa6m1K@ICJteG`Gp($5ZraxFZsDl8iXRM-Akw)7+2VVEjs2{OM1wSTcI;2_* z#oze@yyY2-*rJ2Y4cb|$lYT335D{c&#FVn9kIArMD$*%2D9ZQRv>)h=kwECLlHUG~ zWD<(8UG(JKhpyd0o&z1YXwnfLBNW9=5YKw_)t+gr2iQ!CJ?S2*5~UgSNeM`v$p}EC ze^aglRR39{lTn(aIu!Bb@wy1ofgsP)m6hO>`x|=fFMEKUoxXoa>jB=pn2MwNH?6a~ zU$4U$b9dBEgg*ycuLw%~94kO(wcl3@~emd-Qp51Mzjp&73H9t^h_20gzgKjwlPwtyl>k#%XH` z3;w?9uG>2Sk~{FuGAydbG;3yvt;V7MmBrfeoj`Y7$Lv5&Z z{kvh%nVK9}B%7&M0%yS3h}JV}9jKpXwcWY4J(e^oi6KM>roh(STLkV?vLtVOLwcP;Yt5kM?C|yUhWXWSHuYDF~t7y zh~Cym$eEu>p3vJgE|QBm!F9^K=%RS!6qi`k!S8KOuq~QZ2EV2MHOOIY@wI4RdrUe! zY+~#@#+qIE7imV?L2Y-CvpN{s^6`xkwsVJbqX6xkWu^ti?VW3xb{#LAo9ZNaOi#)Z z=r~T-TcJ=%sztgRoAulNHY;RH@YrHDC*Y0zqC)xj@^6`)uE3z;KblXggYfJ1>&wsc z&9}Yj{-40Lm#tf(VuL+@XXpzMVJo1b@6*||OAbO=&XlZ|)!vK0!jDlH)M*6 z#NUtHkwY)J75@v3?D`uP4*E5cQ5SF~;SX&mXtX5Kt&(_BYAM-!38^>u>Ie+Hqx6v! z;?r~C?HlIhxKJqD%ZfXM0>0#!NAKMq43o0Yqq7vXKxfG%)EC37s2r}}ZV`$VqGjDr zYq&CtyGl2EKtCZO>Qd_|bHz;5g$PXjUAk%leQld=; zw?CxAc$CkGQ2Us#c*kWD5l$K(>)C^z?Di5(;O@TSHszb}bIvX?mFZM;6=&igFR1vK zwTcA{y4L);RN(TVAyV56gPgqYnC_+|ELrxQ5@{XNIdbf0FDblq%*1zS8JtG)8VQ#M zj3w402CYo$b1i$uc4IAh6`IZ90ZK_dajA_}rTUuoayv4q+i5mQxJ@W&AxEIB__SiD zO5R9qikKLGrt5esatXwm>9r4rQMGApl0C*Q}!^e$IMbZs)nENkZTS`ee-1!>9ztm8(WIkE&YGwRlkLou9 zzy0DAU`_pV_5~;G22cHe1uKDv(SIdh7R25An+Un?@<7D+>a6&!11&OR1;1{PQWAp} z$mAqutMo1L>GV()`poD`clqFYX3BnR3{ZU$*PA#bzqm?@HZ52Zdw10`v#`3C2yx5j z?GP8DQ=tw0YajKnJVkfJXED=|eDuu+4j^mIG$eJZkd8l7?xQ}>X>(FA_P(CLu>s(y zvK3t)ci&jhI1jSn@|G1uCT3j!C^n0#f+$O=|R`xdIluMJZ! z92}3)a~faVDo5Ntr^WUEv;g8QUBF^JZ$Xs(u%&nVy>|0p*y^@8wVv1}8%;4x&&)3B z4{gH1muth;Z6K~=UtRT&X%f!Jc3InHJN79;{7QQY*kwz|fCDD(CgU*1bdFRZ$@d*n zyX2r9>2Z^Wo*E!LZ`fG+*VPoxi|& z;TH{a?0T071RDe!+V;Gy=*x7t z;fdH_5%fJQH+#rVY=lcit~RN4d*HovI+`3|FoP}q&mPfw)MKb+V&SkCaDy^9xhTxN z;ppAP!w0Dvhg)6veMQmL8n#?~;lHh<#Z_V~a$qZsD*y7jgqWKlo1Gzmbk!7xYXO;vX#)|)s;tNH@j8M&6$NR@7HT| zMc~`*sZ_48|NY@h2e7mG5wco~4RGjsWgmrk$NO?!{`=RQ!56NpyGk}wX?@HID>;Cr zG~nNDJ+4_R_T1DCM_RJNq4{b3dcd@8w7_8T?>BiTiD2Ypd6YGb{U#K+E5|^`)p`B_ zllX7qcQ5dS9v$%;bBjd8Z?MJ5WZ-w_5k<&Oy>jKTO@1uYUpe6r(vstl2uJ@F+1Up6 zbzaGm-%;BfmQICQu7aZcd#&Y1ZP+Jv7c^`>H!U}DBuwR0!a7U$j=DinF*dBsDb$+9 zdAFwf0<}!sU37dC!i5F=i#fit_@0Kg)*nSS@Jv%or=}_M6MX(t?nvjo2pw>h)u2sX zySkxc76E?SCvlA)5eG45j%zn>7)H0BX9@NMox>xA1rl5WpMLx6*Yy8TtP&8b+;r78 zLrV}{@ zA2q52ijIG5m`8DL@eE(ySS@0Xm0||P-*pyHMtofhm(R85s1lVh@X7DIliz-5)kW!X zcsnrpu!WGj-Yo`re)kU*{{1q9@cwE4)22ZR{5fX);)5G(fv{_2pqw?eOC%F^bGP{x z(D%PdY@7P7DG6ay5@e~0YmQV`$aNpjydaDJSR^{~`9%#u%P6qBH*_PpdTMwQ%nJ3p zrHriTz(ol~4XLh^Gh|70L%EiXNknYm{5JQ<_vk<#A?mg#WPxB@LPcft9Vc*I^oc(I zbL96dP`gCbs1rY0e}20Hl$xtU3f3?KEF2Mg%8H``hUz$ob1c2?m6rHnPPT8w0dh9K zU`(V+ea=_37gH1rD{(l`J&HB7B4oMFI>*$Pn$oXbF{Wd0cWF-R>>Tr$$m+}r6g%vW ze45D53pdjgflJxQ<`XAmA4`f)n>`@OV4+j~A zg^-xk?X>f)9%q)=w=5`6kVi|G%a%#^0fM8X~)b>?;x*X zz|D=%{W;!b&hx=;M7NjYd83bqP}kLhRO{w_I*j8x_po&GkkFmMgzxPIw z-DAo`zKuuqv+FrB<&0L>?6b>ic;Vx#4+Xuk7{?i!J=bFUwwxFni?>k^oUpQSJFEBYa98V8t)CBa16vNPkBS}fo>@dSBwIW$1J9{KG zX7~vQ5wA4iw*A5RVx*0G%)`4d6KKk?nP0y!$8XCwj@p{|ZVg{FAI%!*pHydPjgme8i@9jO1iA{F=xg*ir+JA*Tv6M zejek7#clhc%9_S_Dei-ORC=ob*vs$Q4#{nRBt7$OoK&*>zIzh2(yWKuzmp8Bld|J$ zCd^Sx?;<=);ZT~?rR!66Wpgd1aXb>||Nsyl-i zuG8#K608x9_BIvuIbLlqhyD<}*1reW&Z1Zp!I^)ZWAO2r%(O$&2=35g8km6Y930i< zGZf-T0c7eKODS#+*P&0Lv2jO{?}pc;;oEDj zTb5H}Mu_HWUIJFU_V zMb~&1o3PW8J4)XWMb*cJNv*a4g8=_%Pg-x1e8mQV3F@;jE~l)Y4LtMgcS!Cx7ZShH zR|7(%7;a{|$r(HhAaSt*X>uJu01=Iv4!fVDQSRC<98(D2!nH57hKkoE0eSW@T@G z`wv{7^eKB{|9M@kM~&H<=fAoF=i0+l6vr}Mm7_hoSb*JJM~TD{^+tNY7<4JH87tT^ zQs9u=PPS0^^zq1&><-5)qjiZ1jC!VdyIf_-O&p>ViOPy3$!`O0ldZjuT#kjuiXy}6 zLxALparvoI#;-7VY%;eBrh>$u3qG>TKT#m>W=ch?OS(r@d9cUb#}gxq(= z%RPp&=Sx^u?_8$`Lo@c0kcrr{9Hl)MZW7C>95 z?$o;Rif^}jmxd#yj$_tPy3fuUYc1E|HO&lQkL?vY z#UQtCHvbUohOWs29?gt1vDo)2BAoT2;+AFds(x#M^$$Awm;fS9VmV74?d{cOkN1E* z)R@fizj;0cZhHM&9Y%lK-F|tG+n4zxBH&)Y@pwk`MuE9cDxzLizc^Nhr%{ zdAeC&qBvXjkB0OCVz{1>WlcUj!}(GA0fVgCn5uPMt`s@5WL+k|D;a}d4&5m9b=-%t zWlvwbH0Sqp6R+%C(u)bCv)2R6xC{q(4~*Ye*XMj6tj$Vq!&MyIwQ8d>&{T4kp~;-2 zhd8zWvF1|HBuY=R2Jay?BKMVxjJP8B@ zQc+qQJpSF$4gQYaQCg&&&SB}59K~JN2)_Uy)c?=@@fU1``JSAunMjbjy}06U_c`S^ zNcSL)_V&_T^@+8+m31gIUpTv9l)y0?fbbbWxvNRVn>;@sd2X>g? z!8JB)ZHp=X`LDrU(f-W)R;J*LhoyJ^&CuuY<7+EgRgP@8t~Acy@%; zni|9CPX4<6!nUrR&6weim?;Ytvu6dghN$ZAJb-FG9Omn=S+X`ke4U9r_M)X&>y101 zJ;oX3=xCFq!_3p@CDU_rTp9iOcF~q=I}4V;QZFGb=M>G6zaP^C7*LtbddRufB!X2T ze`nzomcyJ^ zXRo>D{HCZLh|}z3^K(SY3El}r8NJ^famn;}d(B|k@VsuLL-)Qpd^df#@bY-Md${>{ zzX9mch8}uo9mP#4N|+v00z)C`TY?D8TUw10n6DN4iB$@SE;Xn9&qO?Lq{3Vc(L*m< zt0hMg)(ME`uso9{IJz#LNE1I$m6%MPsVApKn&N+3yk8$p)!`v#|EkfE$Na2r{FFKo z>c~Y?=jy~<^N+VP{&#AI=CAm^un&H@;zrvToV7>!_{wNaUg2K)vieU5{(Ni_>Uj&J zIvKiJ$tlUriKAa3REU}-BW_PaXMLJ>3=$GNYhpqT?+fST1CE7>b`ZJS?W>3E_x{7P zdUyZT8V$<0WP*WSuDWf@t|7m{srHp9Q-_eFp3;3JM6hQY9-l?Y2Y=j;*t)o+#M&}g zaMFYVHad2*0o13e-{0P}Iv?)r=uj2^M+@+M3ldXwN0bGoJkWUdFN5s2EF3#W-g*Nh zX_7j=VYj(ip1&S_J)#%BPV(-HBh1;`OCUe}gyrJ=@q&HWIbJYTZT&p#rZoXlGWfF^pSBNZC_@aJWXwHX+N70xlY6t zr<;s!Hho97Wjz^T>L50T^)4Kz-8b>g19Sh~abRi|$Gp@wSz&E$Y(Q?K4I=VE`WkR) zwRKN>9psN5Q@L7$3JUwGqw7l?;px!YXW;U8&kh|*5;Z1_sV*mvhye44NLTj7a$>rX z{KvecE$t>O;G`{a-54OX(&8B6a9ouf+Q66FVr}Nd;5xL+XF)BgpP0exJ3bSAXS%wL~= zTUfIX-)nr_buyW#1shI`(sEoe7}BvYn*6E>i5Y@3u=t?z>(IPKnSo;l>JEJkn@O@U zs&2$I;HL3n<0qM5)D6p|n?2|_q*_q=oph2lN7CG|6{7J=Q&Ud|)tQAqNlP=GpC@im zwyCOa ziiLAf+l3u9ss43?B~aQ-*}-uuWSxg8>Dhs8{J$4!g^>+0uw@}+IO0_`mT4rExTtDi zAZxWK{;E^B&;t0BhId{+8P?@2@w6Rv#ihxf37W4JF%^;lzcD(@EpysD23<_MYkIBz zjf!cLwl%}Dh3<55t9D3AMy)>uYn1JJ=u*ny_85t9*#RYWt5O1RC(*E&QzP!6nXZFS zFWjLeIp4aOLIBM$sZ4`JTZ^ORa}@RW@>-Ycv@3`^xUT8=sjQ|e{Dmw-(;3#mG!0{7 zG->vHf|8&iaCJI#vTaXoePPgLrgh6;<U!>zz>k^rZf`vTvbeUN6uVzWS_((#>B;4^P117p=1t0UQ<7Y6o z16feqk4*oFDlr`sw6E==laSIH?r6)4?kW*x*pVVB0hLo{GfDZ3Ec+d1cE?x`>ZUVsc1}}t1O$bdY?75cIvG62!$_6H z!wBXqOh=$)RAY>1^`yo4Mkt!)PTMW>!11A0L3N|5>-*TUfUc1A$4$}%#P*M5?}G{b zI)98{voGv=gGW~WE-zn=rX?ahu9L20R4Y1A@g*JN1Yjqa+M_g7kNadIA)Q^io=z-e zcRbzwsZc`+zBD5i1>%N*AwuuhL`Q48_g(!qpZnqLt>qMGJhmm0a@yoW3fD9tt(2MB zL6DV22tho^4Xrj~v`g_inR^&ngxDUh9`^pGcd$G*>Kq;>Sw31!*_y%d^TdEV&bx43 zq`Tj$V}lUcm{Sxkq8{%@2D^JwbPyi(M4!hY9-+Sl5HjOo1f84eLKV~f*$@R0-SXUO z%uP*@(=t_}?1}C;by93efn}W>Lr5ADCos!Z;ZL%;IBg~Aw^RH@?~~gTw zVPUq)$PxH^XW8qa?)#q7vHbt*i_$fF9lv0qvfrn-vJgBRI9G-ytQ3S%sm@hp}NXv$>KUBLL9ULE~;!B-FHt3Ki@6U$)rwhWa%<@}Wntrq9-(^< z4x_b723=vWQ(CnVNzSJO>y5MvSJBP{ft`g_3kn{GI#ao6Z#iaXm`nWpw22iRImV5h zr9`PlH_mbr%kRZZO##Syb+N?xU&QN8H8ZVI_YQ-L43b!;f?{rZvByW#TmSix5=_VH zZO?^C1d^j$&37%7_`+FU)1|P|!B?&@CL{r-QPJMdrvJK=A^n;r_hG>ie&+7@N%&f( zNjk8AB~4xV@sE|cawwZ?bb>L@693kCk-5BG1b(`%YCiK9l+T9SYuW(%w+@$sp1C=6 zoeA$pllP>ijn|=^2ODUx&*<%M@;uRC zcAq1vI&83cWaxTrdBs%ns7)cNN6r^ou__YB&_J4m>7Hf%`6$m$gA|5yC$NDt5B4Jn zsp;b7r^0B(mynbX{)S{oOeQ@)!ITxso#6N| zVJ5^$KiHmmAeug=53+YxEe@-1d?YlS; zlHg7I?gA*<{!?2}NjIJv@s66?@mdJ*<;)KSK?jV(W^6`b}Z|b#9)9P5WxfhF&e4 z?JTJ6DG9aJrjg^Io~mPhZB$#LTjC{*c0>-;l2(|ydc@L2KlpOkJ2T^CJAuz$yi^2F zpF7jTFcpEsM4ip?-}}cSC910OyIKXy+W<9x?71tAXrK^>O__y+xxPUI<8OZq%&tum^HT38knLf6Q}q7b8^27rd@6D8yb)x#bMiX3a8&WgNs9k% zlF97Xah{HqCB(z82v*7;_MDP_y{>ZmW$+&_R7jAR5`74r)9Y+O8biun%OQBU&+kR* z_7Y0szYg<_yvQ>*#=|ba(qbQL#ob$ByEf-CJ3b@nxPKez6*c<6vM6bJ*geoEbZAzq z_MW<44U~?U&qM4e?JjQ+>8g;&m*^_L?}cQ}?{Q^4`D1Kf9?YG8dT41ysnl%~-N;}L zCRtcw%40}Q{`9vEtzML^R*Vsw-#0>vRg%%LiBZk{R@dl^ycJ1DS>cJC*IhK<%KkkL zUvw@-<^&grP_6L#Bosq2#gfJ(PS4X!)ru%*YE3tvO6j7F$l&LO51$rM=}(ttvc`JS zICj&D8=E*>%~cr2$yl-Vh>xPVXos-?Yljad4A5J7%(TwpmgOI!*wW&a7Rlp%Q$1;g z9YO(bzo^zyh+=POJ(_9B_h<}Q{+7VKYJsW#x2KU_cvAa>J3wWp&6S{rcT?ayp5 z+{)~wwW_&RiwfYg4oiGIpv>v5VBU?PV$)Jnyld&6OO4&$eg3 zL$`z@W*R2pajed^ms0N|j(aZu6U(Y^O;u0CGo9E;GJCrtNzV2&fOerL7e_e}lS2D; zHG6vP!{(5P>4M_c`M2}5DfXM2P8Qi5P zO%|nBCnb7&XLxkDtc279IxaycOIszi<}T8kt+&pOmsr8l|0Bq^;=3&}jd1oa*b8%$~ZtK}7K8j0158&HN)u|>L1n4o3Mt`BTM+cD$D zH3{zX0IfJ=H@BjRqm9(Tg4J?%D9jML+4a+`$a@Dlk>Z@6B0x*V&TiBVraGus^K5An zA*?a?{Da>q&*{%G0q(0JmZFXU3T)Dk)ng4qkr0ovbvJnEGs|8pjJl~<$A#p0f}Zv+ zOkJ2NQj^c@Z@Ye4Ebh5dct==DS?buaTg%*&<_M*F4;v%(B2-i4FBL~->B6V(j6A&8 zc<$qB8oervLcIT<7O;T_c{3jb5+Qu)0B`#N@gN6;;E_n(NQ!|^_AF~! zj^9Im@0<)HFo}eEzsbc~fOIzHlfyO@>|1CCFPX=1)MZAm=3?a(^%YsR7AAaGE~PCp zSy&qjdR6qK3d(#z&GR6iQYR!(LrmFVmOVDKS3RW2nL^CjSO3q*9Ab!NdeuqQ%)NtW zE2t=(u^^Y~C%>w86;%V`Sd-Ty#&Qm-;}5xfjAiTgc7>)9l*SR1a0>m^B%@0WVo+G~ z4s&^_28eokUtk-gy~u(zcY!`bnW2%8o>OR8{lYdy`=Ccf5G*_{na0Bt7Y2^xB>%n| zfE+(osb!y*?1=+te5Jjle83VnY&w~&xwB4bOqvIsb|Y%_6hI4@aiR#QA>6bQB4}<6 zHG&$fyU5BaEuB1puRWVqfyoTYtDP%)HaIq4?d5I?Z+d70+xKeQx-Nj{%&s6NX7)}rpim-9Kq+X z1h&#(F7E|djyTp|q|V#lmKKOX&Exwt{3q?YA?O{5LY=$OL`H!C!KEp!YrQ>=Lw@h= znt!NZH+$|rY97uftkxD>h`dOY*+%=t|3oTscFT5ev8evvaQ?%MKhMo&eP}li-LE(ht3Kf zd-Cb_h_1z=ivN10q?H9;$v22sWS{n1lgZmHM+BKB%Q8)S=tqj$a+Rb{Jqt|9A6g_d zC3KfRVcP_xL9_n0v{w!!?{`)zqooh9=__+a8~d(}ZW3xct^T{2C~{O)}|`GSA|ww3us zio(BK`5ahOpw7$3_4<9CZ2qG0-RxfYzovw#*+^A&;GLs2QlkiAH6Ht-!mxq81HD^W zVh=In&syP-{+(lL+Gu zJ~(`t3zZnxGFkeeZp@7jGKnW{KnyxY!6YA9AjD5jt3>)OJlTLQZ?skUXZ{l#J>5Ag z;AKQ-e~_%2KfT~IwwFs&qHeUkGUQP=5>99SivQ(jO7do(I8SHOiGO^HfVX`Jqg1vXIv>0NFU5M0w^9E}sFL(s4-^bD|sj)_8*T(2*8b1~lqc+ivN8n?A?4+~B>uGM};A0}dq0_@F zlHl>QGt=|=9hN(d?rfodOgp)S;uy zzLdfCL-<^JWGMv+8 zC9KwOK~YuKo^mqhHbFMF1vcn$S-amA5JR!xS6&WluJsM~eG0=|1~W3dq=Pl^!DXqXnRK+Y9xh_09K!WxzreYRhs=U?VHVEkqc^}2fU?=j8QIh4`1 zGG_2D!DEoJ92rZ7W8dXL1e8f5ZNzqTRbO@L{3&4kDi>j{eh}i=2uq!8SAglR`a5Mz zT1LCf6Afex5v@*`H_pT*8nH!Y`>mC2rREYN2ufTs*VGzNcMDCQhA~>5*&tkM*k-2Kfk6QkH=lEGFk}n+3OhN7% zHnW9`BnlAf*0|XiGuCEd=C}nr@gvQu0kJCuW4T*M61N^`2U7HE#BeiCUN5;=&dIGQOR zgS0<13~mPEV(Dh5garwd3YQxAxxHK`#^*zdnQXGKyRN3v1f!wSvd>i_8e?>I>ukQj{Gt;tiV_iVio-3Ize~UwY+jIf_PA{p<|;HR7#ADt)Dk#7?TwJt9X(81m}9!1I#v9h|026I*^_9SgiD}~U3BVS zdp-HF$6>TN*cCo0#tC?Pyj7fqR?8F@wxlp?qw>1V38JK6e1*Hn)Gc#;Yig+hc3`tA zZEhVe8{)VU{7Eq=04{$)%`G_9Gk?qc-)QJw=t&UKRHlr-QVe9|gVX&Yd=ykXry>^% zzZ(qXo&{=Z#I$Dz%a{wfpirYHeNuD^L9hnqU#~Z)q`>YsEp-6SKS^@r$_Zk*NbEfM znW|m+Q%Zk`iQo4*lpQ`gt0ib#za>hWn&$5cB)Ck%Mg|b99#-NVIm(@vny%-lrrzTq8bQ z`x{2^gb%vi)j#1?Nce*OM`mnbdMgXNHZ;J|LX-niVLc# z&Mi}J9MWEIu0Ok7nfN_OqefaPIdcA_%S4S{^liWFx=q{SzhtPq5)w*k%Jlv~E7hs# zsf$nEdh=SCyhf1rx=m^Iq`DMipkZ*ry0cAv2 zCw>vdlaP;iy#;n5?$aiS5)R?07GHq?_M^Iwa=!|rdWsN)n*WK%(9ey` zphYMRe{^$PU+TxiC4w5;tVJa(=LkA-Ii*%fhJoU^qR5EUmCp7{Jz!*7s7hDKV&%K^{f`!q#MS0; zRqJ$~Dur+tYWT0J?81oS!ldq^WT^?)`gQ+V6?*fd***mSF+pzP!~T3J$t3IPXy!;e z$`b{vOO=wXqm#~FkS&dNlbT-@OM%hj7o~TIgf^nvWxQYY#=hwCpD2kgr!^t*-f`t1 zcb89-v^X>gienOa93@NjN`p$WNg(?5)9k_>8(DjWm#=M;DM$Z=fH8)4Uq;WM77Ab# z9F!3lvFvE7lD*-Cu|s^bR-UB`o=U)j ze-^;JKZVrh6x-r|6&A%1rOV2boNY*SX9OwIo9}(D%5k{Nk6m7#7~Q>4X1JX&lF#)a z`}akyDB-A?U8uGx0vEey#@AV70Ar>~VCgg&rltlP zb>{zT;~Z7!9M9@J!k$s^B2d4HW?Ak8pP2}j?oJT5Hprp6H?34S+U?soq(jB(4JD1sG3#9kZ^CgYMGGT>u zY!lFMgjKNCIr5by(kqUe#hD}|`zl*Acw%&o<8U(NT{TnZ$R3JG!&+umVlSvOJza?jK}0SJZ{p%FU=iwR?VE-5X0N9ROTgv=Gtl*J z`w6mQc0W2jMOG?;B-a2QdhBctpby_GST>+z^9SI{*3xeZX4r!0c5z0U=X+9exN5F) zjgf&EM!n&Ogx{h4$JP*a&V|UXj0&I7DG#d)8MTU)^N*M1P0ZloG&@YQ_;4jjq;JwZ z6GS_X+RvbtEbeuC|BOM(LgfoL3(A;WWDr6zHqwAnc=$x`02NTLqPKZs4q(DRVLQ1Z zf1>`24Q%?*k+V}{#LgccxsjRkrEB$ear1nA(2TJ_9#pNlk{NTPLeEW$(92cG&6UVA z`-=O(^m>WuNa;K~WOHV#>p_ z!K;v4_+;ypKze9~;J+ecLpyUO^<{qtQjx^Fdh|XkgrFV0YcqgE+x!XocDqK} z(a~Fp1*j6bvTXM>JR9R1^Tle&jG7%+`4Z$uH25?tD9KoKk{dM;RZ|>!fIO5~)g_+T z3c&_7gs2!86nECSeBd*juI$?US8zlqb@}HNqR(7z3{&b-sVO&Wh8%VI)C7%n5bf?I zR4h}HuShwR+BLLZ_C{`ov8q~nv=dr&g9S)6Ao5VMsux%7bm&xo0y8{;V8X&J8x1-F z)Gj-KfC8y4Pj43L0V37q`R`SJ`dQ=CS^K916LBt4u$2C)r66hdQIG=#z|FxMRw3#; znu4RvKuAw*Ev`LJ!Ev3#TBwbsy)PM58G{iM9s87}ml@2aZ6bvG)~cs9=|rQ%89bPK z{i~94Ts2)^8$Q7Aw%SBFL5qzSF9~U7ss5(&$m25u1UXUJXZX2c0 zsp4UE%vaad4r43f@Wy?|?lQj95@@ZU)BL<2!SLbrG+l-_-f6$}qzmMIxH%Yq zzdb7QzFuq-!7igNjEa!&-JUvfb#x5=QKY)IR$BfkO=wbEj-_zl1lv~wflwv4r+p0u zTVf$*TqtiQgxm!8bNn(^?CdvN_9=-r1^bOt;-62M8QMC+_aa$Vbg+G6(ucv5A=5{k zT{(mQk{Q$r(WC+kv5KOkxV6eXi!G0=`m2~=>TB3qn2!dH{q{^QP`%D`^QJ-qJ%ltL z2^M5l(mo0H_+_QYB^+M;tw6`*27Z>$jGdu+fgdnMED34I!Ev#TYfN7w%MSST$upVx z*Y~kp0sh6g^TEj&m^V+M7%J>5NB&2Z8`&tUvu!B^*E;M>L=IdsvcqL}S4w`i*@f>e zL0+imt}lh8P`S?P|8l(-Wh;h*V{ z6m5iaUS?89NY|dKbM+wqJ7!XNYHk{nkkJG@hbopVbW2lpW&E)lH|8ECv;SbC|9e#g^I8#RT)+d{56(-KD3h9Quk3 z*eTrnjYEIV&63Km9iPG;ANI|N@q0p`MYG?`gTD?NM_KC^aPXkkeBDT?R*mCp$ayNK zmUguBQt>DjfVoR2t(a@1f3{Tu6;C08toD&s11H@3fId^%t~^!zpthR+3h6)^aQ9CE zL#Mv>_U$Qpc(9|02?NkswB{k;a2H{T=k0m*S~Z^aGIw*J^X=ml@;BKpf`}g1iwxji z^pHgrM-vN2S3yX~iz|+IDKy5)>^UOJn*58*k!U{{--3Q#1#U{5h-hV@!G#mo=SN&u z^Mez%Vc5Xj-<@nPvg`K>zjbcwp?BDeLaO>RA^r^OyQSqZ@|HG3maWHG2or{V9h3(* zYvpRawUCc;Cw(@iX!o6lLRGqzEZmAP|A}bNwCGwn2pZN*kqg z5ovP#y5mn@egziV+`K&HPbLW|=zrG^F*l1iob|L^xe3yKdZheeU?%Ox4&N8D^0o!6 zd=P>(M4IlR6bA;-(MY4d4y73W4Wip-sx(Ps%I zbQHVC#npr@YeR3Ktp6~W0J~BiB7F=Ngu*#at}*Er?f<@_wz|_R{{K5bI-8b%(%MRX zs`Sa~@2MZWu-dIiwVWjeSTNbl+C#;<35pJ9^oUR?KIps91gA(kYwbT$ZaCnR)CDt& z30ox)nO%L#fWt`ejUG&vmJfK+F(6V?Ktd)8(_y+u^Z?9zzVS`m!HjvDrYaRTk3D4I_7MVGb!_T_e zwxAI0fvxuN??43Kc8MJ~Yps5uh{><10}F&HY1#qVDU$p(c)Ancm(Tfz)}f7E(}|4` zv=5Cn-~Is9<_f)5HlG`!W*df==Kx3@{m+`)fPLcXFxC%Y7&6dRo=MsX`*P#aKYE^; zlacKMdBCWYn*1y`R;k3;zK7mAzt=55;y?|0pnHuP#W^F@l1DGTujL0Xc_y4*{?Zhr z-V*Df^yb3kU}JpMLn+N$sq<;&X{1WG<8m1;ccUdK%lka(V4NLLWb^hY{U0fZ7GUy| zxrAB~^(=xo?5nK3@(0HYdJ)zR6IB z(|IJ`DVO2UtcpmFQbzvE?~N6qbSX-g&D|vqg6@o0GQHE8UChd234)iW2wYpb#Mn3e`=Ky5 zrK;WrxPafgd~>1Xxu)4^coT4rkUN1IhfCd!q)*KlaLHomhq@k9VIuF3&;T`fE$-lL z3Jp2G_@ph-fEdG##^okT?BrcJ>;XoU-ease?X7hipQf0vsTjv$mGt5Z+i0ju1Qb%t zQYA_DTz(ePWio@T=r#*Sl6G6$0~po+8sB(}>4n3=){}3wyi&<)E!5u4)Z-R>g3wCAPRHY^+(D+BJ~#03s?!6qSXu%k$2rBu zA+$Q5iTAL@=(xBW-S!^pDGgL+`c9d#XDsfD&GL+%|43U)07x=XRV6b-M%=kzb@VBb z9v%yXD{7Fr@=lq`A#kA-b1#Ra$;*J^miz5noU|GOHnfI<7LOc%g`iz5^~Hfb_~${! z1oeTptE-@YOZcOPLquweT~$^BOE#J*I9wXjfyoW2hQ&fbvH_8U&?}~y<b!k6nFzg?_uK zbEqpBL&qd-{LcrWg9)E+E(H1SJm-`R^fz*J{C8GI1rAWjyliGZ?hqW=^HaP~hr1!Q zL_KF1>r`J1UpY1K)1_Y8o@$8bbve9T?P!@9JT5>=y&}6I%!o?9hg}}G1xZalZN#9h zucNoYZ>Bk+3`?}8u4aP)`DcwJkIrM4sq99NxQbeZ9jA*U zl??_jBrW03t+!6?&p=%`7+9e?yE1 zG{&B;tAYzC4=U}2Z37}3VHeC;E57ujMQdj=PBPmq;<)_nsSl^BGMm85_=G?bX6R6{ zxiwAf2qp8Ehk|YGb1N4p70&cjRo>v_$Mq4kkaA%d+ek!|z%@#@Qn8n%3DAIh}_-VHYxE?@|Psm>7$|6Ag)tX@lI=gsF=^dz%e58IXw3Wr=N#)FfMmavr= za%8T0iyPR8^3N-4n@|%P{R3iEql4B(;m2o+`+FgAY&Kr1JOQ`u!45Q6uBQC&R!2*a zTg@Te1LjZ4$gS}RuT4G4ny=p9!=G0dNWwP@vFH%~P#V@avRZgNFH#(ZS!al3S_V?M zphXT~g~s;6_{Qf_7q-M`6E~tcHQk{p6vcK=+}?ckVmKgVkQL+~wgg*achF*U*m_1r zogamU^9W=Wp*=X0CChLM6ua{R-NKY`_EStvwRKj#N}$qh%zZYNI9xqaUHD1JHu$AT z|BFu=Y$^Sxl(wHLStc7D7xsAOCC`o1_q8tl06Aw9&8#3NY(I~3)hMBYkY>i)rFrD!yS-XV3|6Lc1gmLS6Zr1v zNw3rR$^O6;+Vf6EPhR%l!kZDcnN11tv^RbR4f{Ictr(YJ#zLNqmQNY5S z4G*`cZOh%-$P3=$0FS%tlLhAY=V8eA0NHGAugV>acd*I^gJG9vR!ZAWgfmyXgPD=q&=AaR;aPz0}=fS7J z0l<%7maf^C!UdB%ApPbAJrd0=3!w&JFdD1%!%qD7TLTn5Kg%yifaXS?o z!d(@#<=C;afeuP0g@s9Vis~6uK_CyP7Ua{^Z+iYM~|Psj1M ztu4o9VHbLd*Xj+fbqaSS);JXHs0L=aY?ExXv#8k5}iNl)wpkrG`?al%G zOsU=*u)0hS)NawW6@ESl6!%mb>97R&Y;?H2@hmWR+U;DY-Kf9sJQpl5XT9vTnCc3? z+@2MA|3-v*d_a+NkCdmwrh{+1mlU4A3;0*8q$T4o+uKi>h4RkUiHhD>@wbcYzaf7A zQGj{-n#@ep!sUmi@qL)K6JukH$CPh{q`pe;YcY|&*B6X5S(K`XNT|bIVO>^p2BFt_ zIz|X+sRPRpCyeO*n75l4*TLb#_PJxuKQwpGp?$gvs_(h>F+b9F=8b7bKYiQoCJO^h zPg%+v!#4T+BFa&a?}Uf4onvz)@CxJNks*>yDW%D+n^pDneQ7P&!u0~uFse$X$GXbe zEi%3qqcoV5qE-_V{?UA&<6Xm>AKR0ximwahRxzNoZDj`OK@qfoe@2pEt(b~%kzy=j zfJu}MLSOahZoRO}vCau4N!CX?WRTkzc3DfwzXz+%#|nR8=pSdjr5~PU!}v_Bb9LJv zJL99-H1*lsGWmAC#e7wwRCzsyN(EyOG=B{tR+||uCWpSv@%^R0ESw%bZ2@ZAS0gnJ z15i?#+*ntkf3BDjgJ%#HinX)?^zmWa;w?qqosJlO7HUsK$w7Q+Q;Zo&XZ9EMIipRh_4rc@+N(^~hfLNvYR&vR+;$=?)i?erqIe(y zJdRdb_Dys>_EGG8vbc6*FqrZl$h=J_`vaGTOc^6kZ(|QvR;&X zbzg89eEXDCZ)8HnQmQ|CILX$rH! z`w}joa#7FFE=#J7>usn`-OVutn4zGrA`f=}S{I7LakA!mI4}{N^|APum3Y=&7pff3 z=aSUcu#|-&YoFbuuJ>FJTGhaq*4{P=6`97o!aOsMwqo4lEjOCAL^8$}oHA8|QoK)u z8fU6%A5JZU^z^Iw4&Jg3W!I6a8JWZ-G)wbRk1stvtfF75Q4^_k-J8S%LO-8 zzsUjLUh3*5{<+>CWsQG3=lf6Xne>nU^W=!xq^6C{62BBjiYhlV)U4EXm9pGeMXtj< zel|44B|`EM?W+!_^)LWPHOIj5TkPK6`KdmfhW2m<+x<2@Q>%=8Bul_Hi1|rPZ^m>X zd*CoO@x30fC^U)gM3SlU8bmu_ZPPw#T#c{AiHB8;&&*^AnnmGXbeO?X(Zc z2fan@&%vZ=4cNxV*+JZGO||)g8{Zy|t2(AqmbbZU%p`L)!esLq`VJIDn>r&Ui!f`r z6-!kiXtAIsOz`i0+DrEAwPN=~#A}1?F*S`ptny(~zX`N-@&r^d^cp?cmTn+b*o->) zn%DSgSFjRgt&=G=6pm@VM%u|6bA4oG<8^I^+9vCj`?pfyU1K!JaPHiN6~<`S6T7+H zPpQ?*Mwyuxz=yituj)luD<%L|TdzLd|8`F~GRV;Ayr3e?T6=*BU&gaB{`=!>tjq=r zpey)s+;_u*4ajo8H=X!)vwb@A@hpk3*|=V$7<`amf9)HbA>4t*aAft@IdieW#>j#e zF044{-xm5mZb>Nb{cX^J$>WVFqp;&KM}2S*fcQTh<^O4z6-tE$sHcPG=CikIBmN$p3&o=pq5 zIjaZR#lZM%ZT)KMI8;TJK`H%iS&8uD_CPqv{!a2R2uGSBuS`vnzXmy~Ak}a6YY#q+1+=Xn22Qg+IYmB}`5FA)3MS16?Z-hN9wZcY>IoTpA(-#?Hv%0!<+bCdu_~G|@^^gH|S*K?4lNa(P)X z{zfHc_0D!qg8G)-YoX2YlJA5!d?T~Xi&~k*$-|X$aeVTFAVtzoDlXPTQs*&LBs=7` z#m$jA6DyWxiH#v%Ni}DVL-hFgVfD=k;C*Z7=iuT2TnaWRzogX$ZDy2F*FDq)3)UX0 z(U4G~n#V0aRehS4Pyo|2qsJf^Jn3umFRtbOynAj#hYH~JK8HNP1NEqzrPyh^AGQYF zZmCBZ6CPRbSbQEDE{WqDtX3%16qWvzp(4GjF|*E>5KKz6N*Gl4b1f*(*W6Ys#S7f{ zY#8eBhbK0o4gM&U>{uEOYsE_gZ>eRdH>9g03VyH=GBMb({ff-st-snI7tKHM8l{3? zwB%W9Y(t3b`!#ep^$t{$>Au`dRJHOh;zu}A?Y~tquy9nizXo3(ZV7dk@fkhue;MB0 zgjpJYlP<#Yc;2n|R&pV^e5QGWW*iW+V; zuwyrsl9}%nqR0N~&LI?Tn*R?~@8BM1+--kP+%#%zH@0mxjT+l*Y}-zgG|q&LZ8f$t zvDw(1IPW~?T<3b9-@kBwb?>!5d#&k8Jnd{|2MiEYTbmC)1)t@QYvg8~ar}F!wWVpP zKrYTZ{f47xrrjOO#z=ukF=`z1CryH>Hm4195j)xi)EA?t=eDCY_JcUJ@?eFQri<%W zM=|M0a^8kb`&tj&T`wEHk^>qw^a%;zv>I9bs?biltrTvVCeKfA5s zg$y)*H`4!w;A=SJmficjm(}&vK1ZH&0)VApXOYB@OMr& z1pYUcrY`VF5lLvBbs(Jl_q&;2dk@;joYnpM?vpY_3z^TAMg2Az+0lMx`$?lnqy zsu4!4CY+4wxtIJ8RLFI{V|H-=YMzLa++Bx(W`7>-!Nf0~jIBK111i_y zB+!qq$V|}e=Cjxo`Ml0v@QP+n5`81FVN$it2R2!|a+OcSAnJ)^(HEj{HC<;`HF=~t zb}Bb0Y8BMwlrOlQ>so)A97hToVXBh$5^ds#fIGaz64XqD>r;#<-{7^FDJDOyXK`o} zBVwjTAl--oYcwT>>T~o#?68Lm!P*Rw1JTHTFn$|PD$$S0nqcb76Sj?32oSV`0aO{4fW_yrpig%`BOKo?avIhs!(2~gjNE1c>g&T5K&vvw-} zCG;AXgkyLN_D0h^Rf0p~BVYUb}JpF5VtGqT4N7tjcm+C;Y+`#t^1%syTfpBl#&t`LF~{%5JBcKR{ErRYK(G z)}xV-)S{-_Wp6e>&pQVIfqoACy__x%T`U8h?{HxPJ=n*|aH)^^ zy%eW)^W0C4#;KpUJCAS0JTovY%8!S=kt|4r`FE=uk-n zG@YFFsSt(&MzGsnx@3xYlATWk%^sl+Rd+*jDSJx#(DU&^T@Z6yfx;S38nX9b$3udY zUz3Xk20ed}9(yaT#W8P{VS$sb@P!NtM2#WoANyIjiz#6w?)w#+GzQ{JNnbWF8Ul6w zfZRfjj1*w+QIh9YqBAg?%0m;3wIAo1um2)VZJESKCL@Coyd;2d^x!1-x^8Q-j{9rv zB_X?@3ex2D)9Hl?23}RFT-iXgAe_?hD-^vF_IiBo+|7Gdb1fCna<`VQZ7U4mEWe72 zmMJ-IMjq8P4;02B6hT)l_EVHrW4HVBm7Mar+cHz}QU zX)tah>px8`z`yP$_K!{4W{}y9 z?*BE>_%n#RdI`V8dTJxqWr1X+%ARU1r$L;koGosP5Y_SH5Bjfh8x4kuLvtkL*tgNW z8@|j>{I$r)X+>#Sx1r1B^y8=#>$4MGa~Na;>^0Pg6S0*^+?70nrc4gib5+-5*&2MA zrD8Juyw%dUvtJMxKP{C9=)a?us`FWF{whqlgKNKZQ|fN{w^=AK^>autFwPRi2JS_8 zL$95mfsz}Pjjmu7M{Q~0U#JLGRa;xnAe?{L^V&!Q|HD`ris>-}Fu|nGP=+pSQO#1_%A_$LD>Q8hvZ1?FOYS z{{y6X=#51`M~ZxT;-5GDsey~lBiE8Thy;NU7PIW%JPhZ(XcIU=k>T1DMxJ-pNKm-3 z#)bxHZx}%8vO$YJQ77Sp$iC)HiS9^TN*z|V2R!e5Nl>IKd-PO=)Z)k&B)r1Oe?B~T z?v*smI}nCU%COL#5hOPT9(%=}A>Cmjh^lU+vnD0-2P0Vq0pi^%LKPJ)C3Pk&|BnzD z4Pt}QcOvyu%it$CK8=c%Odg}lMl#tut7K=J-l{b5t+MDVNZYkZU0Q{z2|4KWGr z&Z7mr8VvSm25Bdii5^hdDt?)SoZ4QN)YxW4)EEsSVxgIC4IJ3h)V8;ov^x;rCalqE%KI;;yQV3B`)nZvupTw z!3aJ_yp4HBLh1tDv8B%jVI?l(s8iyPlNWOXn)r-83xP^RRs*B*m5925uk;P13`K$| z*592Iq7Tfx(X+FuUTyvXqfILdMDPK6-IF6gnVCAhGGv+>0)p)9#Anl`G{%o|sDeC& zs0HlK%sLIQ@xmN$?NYU4G|RwY_VJ6Y*rgjUMS5a7D`CT!peZ9yB$vw-lZb0zNQ-Eb z0-==0KGcH;QZt9HZpSxZmgZ)c)A6Lu zpW*g^QIpZoKU0dfNN<9f90!LJ5eG@+>=sI1I~HJc#yhF*cW zs4@^#0edX-bgT?NI98sf7!_P_o7!4V{0I2y@9&;j4yG?D)`^_CN8ZstPJZ{Wdb=jC zi?92o|Cq+@#23hVo$lPNItr_jQzW*xOASBBu;z{fBcrFlN1wt_D+%@UCU-A{0ujTk za@~oRzNOV<3(ovi$bt_MIZ?a^#jLv$({`1m8aUN<&i*CJW?Qf|y1*B%imY7aiX7U9 zOqRAxgu1X^{zxD)(@T`TnCcxhn+>R7Z@=g)Zg}YjTlqMHOADI3$ z9JLw*IUe~d#FY#%L+{pW2#VCTngYj?-+g^w+V1|}w*_w}6Odg6Ws8h12kN#qu61WB zsX62f9wI0?RvT2~OK|!@M)fJ;im}6*<+rW0#vQy3SAv`A6}@Grcn8dCiq|h}dv)ea zO+=r(V=ogwf7ctuzX?`CZlDrY`zuF{djvdzZ2$4$(9?=#Ogc+h`N@R6#5vQxvCf+ z*sl5f?g9TGHO33N?5cjR)7qUk;t5(Ww%BWHD?Vlu!{VI&IJIw~AZsaUtyL ztCO+c?1;*IAcUw_qn%5d&^WggMHA=+<%tKyQ`y{kG=}P4X{q&?o6eVLv5)`xs*ZR3 zz43#F=YdoSK?~=C_%n5=xfy>e&K+Gg$tEWL+EL7ZHIko&7En{I-Ey$ZmFM@VjURZJ zF8~)b1)pChF;Z4BJB`qKNo5gkcEF zmYN*>wFK9*($dII>d)Ai^`Hc%+lo0M6E9ysC(_r6L~*UEacd4cIv8fL+Il-iwMsa9 zP)Y7WQmC>QJPfN!*yZZ8&vTyu5|6*n?Fr!$OSjkCu0wS;4FKYR>eB7`kdc-naNA%R z@S1Gtf7d2)X$ij#6p~1e8u+)f$;7Ox>+IA+PnXM|$ux#mvV{tewXGbq7)2O~kc4ew z>;3%j=#uZJ;KWYF8D?6XblocM+GJ^|`f-Q5LXMf|vj*6#t9!rjgY8NV0ZPUq-bsaw zL0hlZ!}#(M?ix@3;KY|-XvPG7W{6(75milHXVonLfBg+uh7F`4y%N13w$4x|`AT3n zOQ5(k>pvloyPo-Npq#O=_*4Gw>i#rFOD(wnVqUR$mo4Aqi-oH316nmFUAv!=@9nK4o;he9k&Lx)3@yztvbL2@D;R4Cg5U}bcVNjmr z4EoN#;6`#LYsLpw=%JA2SipDN*yg{swl`-J%=@Sb)&xjW^ang^_h>5Z;M6>k_!c95 z4NN<0G~$}U*Cy{u9GnUE*K7#FaFaK7(IuTSnaohlR4vyO=xjs8IB{MXKCm;7E0o98 z7rJc5>wwT5y@CFrZkwIz_@$Ej$T)Quju0EY6m-g<+O^vU#}50_O zK%6ZvpKx*hH8?J00iElQWJFlDzyqq}1AO3T1BIqo5VRFrY@^o(S%7BVh$L&b`A zqe{y?F;Pj8{hf2+lY254!_;#3t7oO@Wl$m|Ya(=R2}ZI+N5?ZNQ4H07&8x*xMwW0F z5^Vy*{@~p#>bc3}V(zw`DVugR0cP!(#?{(`Vm=f8kk-a*OSZKTB_4Y-`6r2)a6x~z93SUc)bCTuh$!XXg8caOYEjs&Yj^U#VS5jV_T%h{Q$VO(Wd};30#$Pmfqtut4 zoQsV+r(kz)nwBt$N&B@XAIE=c6u<-ZI_L>|ONfwANLRWd6jG9OyqJ0)S7Fi5B<1Dl zss3LBYLpBbf!g4HEBjtOLyEs_=Duq6@vLLxqHDBYw8^n$rFkl5)OJk29(N$CH7iN} zKrK37G!lhoA0_-H_my0_xsjBTqpY_-yDJv44r^P-0|k;)p}(k7o#?Sb9#!H3s;%nv z9T&r8P9tLN5NnPnD`H}enz9U58qO7{a(uv;I;~^EtjWDsQMl8BuH~1Zty`59A-osl zp>cWfs3OB}%bpGOx5a$dmx^#k+W``jkJZ393huX zCy5-fyr|W3crgtw&Xx)rI2R^|$RG}!A(it^su$rpPKH^=cZp!>$A-ho!}a^WaXJIX ztm3iTMaVngXS{Md0Y05Zo89Li1crF!2VmU_S)6IhOnA?e zG|E!Bz(HrQ&xboIcs#(u*qIw6h>e7b3hGE2)K>_?D(Z0AZ;3iHe`^#z)uFN19pd+HHe|{~01^-CXmDuZ%EX zjM)<;vB?ifgPYE6qvTR~8W_9Jfx$z}k6ABqNg)jgF>r%|m|iEO1!i0ATHD%)m8*f*;Ru3&y7{kf~Xu&*POtwaU=lSA}o zJ?qjxSShOw5;rYGq-5b;L9Y5?)2SNa%Btaf!@r0qc`eXUd)amR^XjXjD=^=5ET8w| zcNyigBxS-VfA=o-=7=7z7A$Oc>B)+he}SDnjj<043ASFxh|Mt|Y&O77UY;#=u4jf0 z`ix_=8B*cWWON%f5IEgX80$>@z5Q3 ze;fW$8VqdIy2V{Ge;DJ2sbTaV>b;n;r5RFK6;#%1&gQ)f{E0b97WrZ;cv!811aSK!(yfz1}8m()|6d z*KKg8JDrbTSs={y;L6?kooNjq;N&FGoNec{F!~qDsfT*^k^tOc)j4J4`xpBE*W{$0 z%P`1Ay%||!R6_{a5+ji7=Gj}!kml$ax>Jrn5K?cRjccGvF_#wn15YgpDDZ( zjOF0~(xnc`Xiu}A7T8cDGY(GH5yK&DRrJ!sU!2La<~~=+1HS+tP?Fo5zb%T@)DP9k z^6Pj#5s=F?$l;)U(|wP0K+QH}!^IYF zfP(5+-HPw2(2LF=2{(m*pVv*G06K!_dF&0P-4RTmOaPP%ChHxRkcT!cbEfGI3z^Xc zc?t2!O$A=G4kU!zhKZ}+@_3?II&K+3`?Unq+}5x1s$X;jH}k<|~rN|8|Se;(ykEEL)r zok~EJB((dy=XHkvceSHCMblw#4FX~{m~^!Zc#92D027PfL(AL{#Khc^17&o_j{!!| zrbyh1DDI8WIkL6C5T3Dt&Gc-1i@~%$vq7=;TJ{zPBSh5dOIK`39bSZd(1borhgpKy zY`)`d9nFB+<|(YtLwo)|f96W>xuQqW5m#S~h2k)DVp8jK9uN9~lpI&yz%#8ux}5miGji1XIy2^cEb51A2yZ z$Z&a<4>Owd+?SodrbPm)@kjXH(iH|jQv(a2Esw+4?P?BNyl%g<{?eQEYR;IF0v|Ou zby=}9%{j$lY!v?Okj9hGI}P|Ari4BH)|W+J!u{EsQpvXFW|^sl6Y{1}L0+*HB8s*| z{XtV`V8`5XAbf|fO~v1z_rVR#N7YRHt;eCefZpSAVQJ|WzS^nF>|dKy-`+VbeS1-^H`j!*mbLI8$EQm^yU1GBCr$=il+ zK--j9QB6&$AT^-(R8@!jBzxeFvG(uk&f9% zd-)^cl3ue1#Uh5?O89nEAcZ7mR1N#Qni(#-7yD?TCE<`F_iyC;BsF>q=jr4HAMTGBc&oE9zFQ`< zi8XiTy{X;3U%geF`{Wc@gw2=rc^dAkLz$>gQH{4Zy5Dv>+fXI%?4QQ=#zG$}4Z~^O zQ!ib1A2>s)=K~q|(E7W5kXbNp_8A^_1eXCPuGxuKQ=KGD{n1|r@8S{k@9JHj?d!M) zDu^aG<8!OvN^E>PKCPmJ5@waEQ#KTA{N)HZe>+Ws>Pefz1a#lLwiycZyv#OCzrLQ$ zu?XJ|Mv6hQgIHYu=M_$n_1h!ddd&T}b>Me*^S|$YT}oi`UfX(|JnDLXpY~h%pY?S? z2Urrq`Mst3C4{Ng<`TwUt|F-mNB~CXYGJueBnB~a^326GZb_8l7NvwzwYG!ddTw2v zFf5cP9e+=BEiNyQPPe(a<&_n3&m7AsQ~#e9@PkPYg6!Y%QuZCUo) zxaBn~E`7<6%nhT+O@02)tXtTEyOQ=0t-U63)<54*r(OD(e6-aE(W6JcSd0f-!zVE4 z#z{eoJJ^9zk&R(zpK%P=Mb3gW$D2dR$+I+lV=Hoc`#ZG_(sf*ZRZM*Pyj;O+RUsYF z8X-y@+|zEk<96YjO1m*s(5pnT47E0t^%DhPG{f>1WrXcCc89)Ivu2vc-Y1?R9WI3J z5avjS_N<|;ToW~jTT^Z_omT1P4cEuwTLnnI4~F|QK#8o#*Qdbq=bpfB&DB8D(5<23 z6Mt|JhkdF|WygVExR)Llf>j->O>cYU_P1yZds;t+R+&tXp{uvf#5l7hwnt#u;d~QS zMICIG&AOEtdIxVFrIK+ipLuF8L-i172EIhT%skk5)m?@mD?|PK!1>|X`G6nl3W0~Y z+i$<`6!#E<$G2&Ig+D%<6A^%n{8@^_@m8`(pRe+;bHT(^u8=K(Jq!dq5K?Vq5oMnn z2QwyAB}g-bJMI2&I~)pZJ%!$_nQc1+ya?pJ)c+@KO5|V_N|qHO!^=6t-crYJ6z}8~)eRwRP+Fs7 zmEtuL9qf5&@Ar*d^l1_P8Saq|r_DMGAcM7EzlrV1tD~03E7xl8-DGH<+YM_kybdxa zbvQGF4&|N&gJ{)cF6u3?V2x^`Mkc->g&(Smbv;OgaB<^=$8aq+!v19BtJ1Go8B66-|T|*qfI+?#QuLO3yj>mNgg|nEuRs zuWHAqIPsAisFS=op|6-!LFo!QzBb?-W#)Lv;%OfvvD%qw@9OPQRJhKNKD2yg#kn z;X(%{t~3lHX43F^^m5?8_qhDrzpLvNeiSb`Y<{Idown-?Q3x>(?W*r}nD<~)WSHAS z$g-cUjfIrdB1ysgkdk88Rw>(Ra^$UY0f#Tgs`_n4CU3s_Q|zxDhf4W4_=Aa%lHkF@ zV-MGW!+v3bYTK34wv|Un1W9k1T7~)TKo2C@M3HDu=yG>2CfViGPj)!GrI^!Uy{j1A zRVPXT8Qk*1GOJEam5&=Y_D%6ZbW`OE@A{$$J5XLa;;l@--EeMn0I@lI(>cqmf`kBR zVrQZ^RdP5}##5`;Q!mP%^7EQ;;$y)N>MC;M9mrZD_p%Z?zqMGGv!!`2#r(yIXYv}*DN zM9S7}v*7+UML%?yMsto46z0GneC^(adqGe=^KHwo-(Gm03bv_y?w@{&hVIK9yshQ^ zu%|h&u%Of}IuA=sF{367DoodLierEFS8zhFa8^sYjGE+A?*iBR7n)2h-SRWl*A3Kl zW|OJop4vX3^~dro5oAf>?vM?3?t8u(uQPmEBv^+@h=8_wmHzzOp#BJWYddCMyO41p zQcLSdp`7DRSm0V^#EEl#of*_Y*F3B4j@q4ui^k;R2kHo50Oz)BeCRnZNuATwws;-d z>ENwyYnv^CcJ4gGId zpFUb|UTxB*JAI8Wa9yUq06tD}p#otT#jt*G$YK|FmARUjcm^nGZgoje${=J`ero+b zD4ki>ZPzKGiYT62^5EunNl3)M%%a`&f`*17?cE^&7IdRX)M&0{M(B|iQTcfmE9mCv z==dLJBO>2Vmj2wxii0v>!B~2#?>yYxtsdZ>BiDM_d&wlCAM1;q4xaQYNj-O8j0mHt zso*@22DuCeEQ(d>;<+I6MR$!!-%B8t4JmKmcARp1TFSb1AhD0t4Lr`CjG6KbH1O^_ zgS2ADXUHPs+w*#&_tNQ(!|$d}B3sK_=Mt*lUp>t@yeRm2@r7Pl?@+q<5W>Sz@4#;E z_Yl(L_;FaM3Q#|kU`NIvo}LWKS8|SlwCHAadGcGyu7~uuf9xM8<}lfO`cDiMN%FHK z;MMH%BR&1ea7*NUtE1~-K?%0U(0_MZ1gPz3;2HIi>4U)cxeK^*odtaEux7PtK6=aj_+$>pf-KZ{OHY*#?1j z30o`7dD*d^wRH>zi_jlTmrsd)>^qt55UAKxul0ourOzu;_^8$#eZv3TEtsFb7>KSj zl-o*^niUFCk(=oY>f}#IVh0>nauq0yBN*`?^H)K6@!^|jMy9g=&XTD(_nzuf`j_3X zSZ8auF?Z?n++I~JKwm15?kyF;RJ$S>QI(6jjX@`GteN zUd!ePI|Rp}vM!YY6U4O!_O*U&8}2K}Zuwf(HxaFn*mmF~m}GO+Shb>cM;SIiO|YW^ zn<0neog>t6Afji)Vnb3?-Ghx^)$O)ey3;4M#!NTB2k&!XY44foX@V(ddbB!~I!`#z zqt1h*kWN^hzxFcQ*wl5juIqdOrTufCObah1zYLE?Uq+;%cPqjc8(&lV*huCRW|BWw z9g$7#FJ16gayr#LZKw2Xr%jCNB~=D$5{90li6oXN-?@o$*)1YdrU)8pSB9lyD^Wd9 zbHsw0m-f2BfY~;@hThS$dTA^_fh{ul@CEJW;MP4`&=du{tnMSL%U)-e=2oZE(|K0f z=3jS6B>?ofhx{-w10lmC5U*(#Vc_$6KG*}MCzNXRUpU2QXE_Bl2b&YQffTi&EK!I& zOwZ=Rc*DxnVmGad3EQ)m1xWwK9{x|CLY9aLf)!d6fHLN7`Tc!i9{AInWOP$OO#zH! zDz~=I7S3j*-3>zQeLCm1^#1&*k}-_e=dl>Sbal6k`({Qyz^YY)Ko(*=!=fSe34v1axVbpEV9KrC@~t$D2cgd+W7B7ay3cn`%T}STj~(8zBy5G$l_e$=79|pvh-1nU5>A8&jxOA!ot- zM$vn2@(HD9(Aawjnoa|Ihzy5-kF;V;@CFHfk;CMj)}ICsGaWvmzY+FM*4$2lvrTFC z+uRoO|DpO9O;t$IdL+9`-k$;#0uH-99&3CV0Uxq2Blwn1?-5%hkIzf1-PbK!-L;Q> z3jxs9;ec1qMNFCLBh3$EFwItl$l6P1#dEjstxfLBSpRduA}TBax^z2rPl{0P(k(np zZE4~_XNFsvb-u-VDdpWK;ZbZ^8fdUM;@8Sx*oX}EM$Vcx>y0VLLwa#@(ELdT(U6UV z;XS9aRYlivonOuN=J?7$j~kR48uJ`cDd9il7<7a zprb<=PT}-YE1NFATfX`M?<79k$P zWE{3&zsQ`ZZjRNR8~a&t%7Z(i=&L3M=>1;PPh6^>N*7On=mhmvFR zQC37v4_2#LwHwqM(>)~A{*{%T4-n_-bh*6hw;I9dJ zbOpQNgNBMq-P5EFju_4g>~WwFyS!s!Avh$4XThaDVw9W94xXC7Zf~=Mnp55G?<<!2->Cd%*Wz1~2u%w@$D-MZ;~E{J=<$_ngVPj!Cr#HZcwL)>yr9Ta;(kxayG625%;A()8!^W?jSb)hUpp971M zR4Zq=7Y3U<13O{0I;+5CAP^;tPoA67R~_{`8lP|_5wgvjO>RTjGK^pG@(N1v3fb}T z#C+%_gN=dv8s_i4he%%{{Q`%Z{`|iFCSYvL?r&n|OD#-t4E-^Oxb_B=!F;G>Z)+>c zAT#s|6z3V~j%tkX?>H}OS^0hn%tFchaNhgz$F?&;9AHW*?<#OhXKS!Q&42cf}MEOJ|-4;fqBF3%$QN z7=(wlhnxMxQP&;r{J4K{Y2e75eKbVab(6NG>uG#FVJH&CBjR)?16vJ4$ohb|`D7_1 zu_ZuB(|Hxry)lVo1Gg>mG1L-pwcbYo^xv5PCtSR#3g6@kK51^f?ZEk6he^Hlp>@A# zD*2W@m67^=$Y|mk7K8wwE_xmOFZtf!UVV3b5V{{|-VxB=-V&H+Dp+_mvq;xzZTl83 z19%=7J57}X9uT%R&mHE|a+d>kBXG624gX%fIk-Q{*pw84Rt>fOJ{NX>M38bVy|P(8 zmEJRKy+A2SkiPbUazr+qU%Kv^LR@8iy>R_KO}0mC8UtSVG;WSX4kKQU7k%BpE&hR+ zbGp^^ThHFAYlfZ=$epjjBqHySFNk2!dUgIFa{6=u_qO8jlopcZe4iUxWKOm9wu#Tb zgftaq$3hPI&(HuE*}E-X?khl#_;~g4nZ`v+*we52PNvfUx^l;>`S6EyfXd#SawQ4s$(of|wRQ8fe6D4{Qdv9bBu?kT*^`Q}~&IG@+LS zO@Srur-c8(jRHZT$XZQQ-j)VEH9^hBbQ-wk_S}~@3Dsk+>zrdW zqwdD8PFQa}Nqz$hSX!pdYFb1dezLZWXF?pkq3fitr&(i}bE}%mk(DC! z1)I>O&66fG7uaq}=CrDIIcGP94=}ojOf8|o&apg@VbWf0k8b)g?@(>cqj?{OZMqXb z#xw(w3!E~b9w8nRd?MhR+Xfb)EdT2mjF5S{Xe&*mCs8-#0}fq_A3Up8FuxVhl@#J6 zylfgSRx`4JM^c|Uom8@>m0L70=)*3yrwZOy1I)b}5` zAHDe^4tyKKowpST0kwG|U^JL>L%-eAt=EqgAIt;Zi`(@y(jDry7Tduj+)95yaQC~eE}phGz zn=(7nZlB4wT%nUpy#(9UJsBF-XI^S{}^6F{*(o` zg&89v5w8K#MdjM6zsW4j9-nfIT{RGIu`71n3_Dld6nCiy!s48yH}1Mhqw@#xS*J+& zvEl1*9)yCDsv3rayNvV=4<;)(xF7JR7KnOMrBZKyS~vH_;aDd8RMT*M-T#@uPw~4g zS+D1BPGY!m>uc=fxs-$tT~@Y>NpSC70K^M3sNMB^=y;xrkWDK3?sJdy3f$Y`O}$7| z5>m9mNL~_8zdiqD&-`bQLL}wTJL?Z?`^8R4?+7GL`yzEA7Oj|K8$sPf%(i1bGcsc| zd=>L4^Eo{7p#d)9+Rqv6CaJZZk0!M&?ccLF|8REv8a5vuWA4heQjqC)KT|M0xSyY> ziObMT=IEBs8AQHX8NJNqe*%t1Ib;jIH(|;c2fJkrkUg1p3iAOXaMXuUd=Lud%;d?d zN1&aIZQaZ&2czjJ!5-CTk0>?SlpBpDR7}laK?2nKOVLB?$GVLyes{ER+&b$vt# z#k{@EeL=*7*yg};)2*G<_HVK-+nB_>K34mcm-UEdGoEHwK`4YG*CU@6^KdjwnHZ>> z`7wuP5{Ns!?Y$&4FHQ4Dpz&FvGv-Y-$I8bIZ4t`GF6>sgSRY3&m2!Y{~>5__>|IcKR)y4!nZPOCm(Xe4=}_@-{NklsiX9(bDE4j|>j$3osLQ zSw7G6X%j71C)$hPuIr#-3QZKj8d^PnS2{I^Wh5`ZuznnpddXJ=(sSGJA>3G0vpvvE z;-`z??jU_MQha;@$zB_1pSL0-mJA0`tt0B>oYeWD7$p!2*N^=&UejT&vphomaybmOE`Z87sL>2|wJ(sY~U*a7bXx^FSb z>-V7nTXoovuV5yo=lG5#-`6Ry#6Wz8(z*U#?(T)sSXS=QgWEVw`z1&MkwM!1cp4nA zV@p)PBa8<&{9S1G_WDQQ>BozT9cJZ`@RRHZ#_vs$g|2V;mmNq-2t7OCfUBt&iMq!= z_S$)h{5QMl8;w(kDs9^57^mKO^DIPhX6Eu0oh93#E|YH*CvAj1hguGc^@|)9w?~ql^J4zZ4G+}T9VTrQmb9}fo z>otyZ#xI)Izh%MCJBJF|798ux=2(-ppH#@sX%M=IzSP*<4>{1%n?t_~1G zni7OJKbMPDFlpeaEa~}ZM#adY+7~+K<}p>d(G4tcbRcIUJes^o46=oG(}bn#po@O^ z=Ghm>EDFpY{^ElYez)p-WCWVgjX(J9QWmo~Aw|=RqFllNONlwcW~WPCoaz#fy1rPi zShc;loU6CM)iLU&+ePm597^a?tvs9a@2~14`DY}XsjMnY4&BoVxMU1Y z(e}QLMK))*6AMrE@5h>Oo9uYYOxH2WQ#UU#&sO`gc8~$3}OA2-g&Bff8K4lq(FKM+=X}h9sa2xTt^j=l`mS?yuH%-wTSjYyG7W(vpzK(38bt66hu7kMI#e zAz>?697>|iW{t$Nx&c*SIUr6AkI;-m1X<9Fep} z^527--I@R%B&*PW86DvGLu^B(X$E@ZT{9Q|eV7tPfF~$u$?dIWC*U0 z!#N0YqTiK-oSJFV8!aF=FhYk|X~(68)@nB^%ky=&-&m{=v*2rQH}c?QiTB4%eqmjS zcgw|RAn;WjT+NcL-{)54UE$Gn*%d*p%k&p1t}VCgG9CvYL5hRg?ekP0;>VRAFWjPs#rxg|DGo=7m z(dMG`hbvnTjF)C_0qxF*+Ls@mUd#%=Uj&sxYc3--ov!j5E1awOZ_Qa z1o&&){sM%mWpDF0J5CPE3-(^qQD^w1M|Dtj%y+9d8f~1!omSp=%LieY@1#m9r1;?v zt%ht$##T5VQ}1-$F-|;+6m?h&>oJ>Rm05IDYD1W{h$f|SSz9&Z=~9e+(U%dcs<2Ue z4H_{V{_JgYt`b9ipOhT^P7lzuWP)V}rQwY+5v7!=S@PkX1+O2h*u_j+pltQ>#yri& zq_0u|3`f+kHq2$cT%S^j3)iD3)Q|C!sC8=gTt|c15eo__=cP~wX6-*C0Yq;9I^+Cx zHdsqS7ntxQ=OmwQqV-12bq@Ur_g(H+O_|`~M3}Twu(#f}#!;HP#u5A>C43?F$thTQ znouFhM>hWE%QvNm3#}c>{DZU2~?cyhtj;n3@q2HH}-R zNi}y?NJGmRBAwcz;3f4zlcpZ`>ab$2CNRFE`g~(1G|h z?O)&AgxdW^GhRgLZkkI^SI9GTrluzX*!HuQ50QNH{a{d^8oO`+)qPKZBy+a{rM873B4<25|31 z+`G5*&S9hb>83=Y(-v3@SK6?AQSxXg=RIiiV)AsY<(>$SME_)AfPCjFF*2_O&7m<+ zczvtWT;edKF{UqRKG@S7hI`+sZ@Cx2uW?|%A(t7c`L31P#-luH?ehOkENt}V}X zPp>AfMH0L(C)j~&{OH9+DjcQDX~Ayx**rxE#E&x1%`M}JGBu?6SpRchP&B#1YvDb{ ze7waV2)7*u&Rq6f#4QzUc|iAgY<+-p?G$DU@_v#vG5wzw&Pn*4EH$I@+0ul%Lj1q9j9@{CWXGIBbBZv z*Z#xkr6j)nn#R3q=U{#Ba(RPa!4C!Q(QfKSaWTLSU_c9XL$fF4&dUO2bo6kL+}W=G zdydipq34vf@Vtdb^*9dUv*V9$hbrqF+*sKrfM@$Iwatp!VAN!Ws+Io~Qg882uB4Aa zz!g_=_)!{1xqZFuFs#oqwVk)PWQLl$zq_j26N6W4Cg|JO{H{NF^}c_o_kRVg%zs}q z-im&5<9Nt&J)?kE#V5BxQY`TuuMn>Y!vArYB%*+fjl1AJ{>PFlTv=H>%09SZ^4N=$ zi4ZFyEU}d8`NXOGtauDbXo8bX<0_{iDQy4G(+@9joVhhCH{+krg66gUCnMYJmpJK z^K=@S=a|eHJFKz$cMkEk?0xSUZd$U0H`J>{-_*l!v+RR@At3B^>E7rd+vC$to2RI?vK=W5@y5->j1&WqJ zaWC#3910XE?(XhT++B*hySqcs;_ks+io3ggdEfsz=etQRa`XJM_cMED*6g+D`n&>2 z=n|brgXgvgs!99AMmW3xldJXkb}J)luzovcdMw30N!d@L$Kx@RS+6~5VHbS9r&dET zK2OVaOfiCQHO@)BpvCipbK7hbX>w47^nFkEm2uh{HI=6f7X|r^^HG`8n52JNfj6j zY4La4tUe$IvFo_e&u#8${dfpnO6281M~q>lt=^ity0Rb3ZnJ?GPJ^?I^^ZClB z!5t}tSV%Lpv!yuyY!oC#`^Rm}-#=}7=L5;M?H`9Pr?>2lEv)JU@YDzUq-uW2F3KwE zxSdb$^WtnSzFpQEO}S1LOducmf&*Y+7{cuxM^DZmcDxe+6lPL|T!;Rcn=(-=58xutUBIE(lUbzmY)9H3_JmL5sy zZ9Y4LyY<2a(?M+4`SLy`N6T=6Y-9d#{2+4k`Y#@Lr5R5DZEJVO*Sp#4GW$i)lU?BH z=_LhM=C}6!fZMLps=#w+JCDG6IuxAoAekr2NTev19{bhsR`$AFI#aqF|80tuK&Kbn zVhu=01J&DFXK`80gvA30^_$Ubk@A<4%|_aPa<2dZ`ToHs6%xKKNsZYXS?LmkvKJxc%qa&`Oyn?JaCidw+YAMg&5W=l9Jv71FB%-Tuniqw zFHTZlOq}X#vmam4!?wCq_Lpj7k26${IaRL>C#$t{aTPbpO=a$>D)19T2bF%Ip`B#8 z@{t;lvT#RdkON+FxniyszZJ>KR_v2->lT*W@|BLHiu=hU$__s+$GkFF5d7x(O_LQg zt?6{wEDddzU=!BYcXN6;=n(`L93F=noU0l1<=`}2R)`m(3Vu!((I+d@%2N-5BPFd0 zaV5ge&0Pf|0NaY-tg({cn1}XoS(7KHEa*vSs!re{YdQem32S|-9G26kbV|k4c+tef zqh@t8x@Wu3eyFm_yGQZa1z5%@W)lQ5C>15b+qR%rz0_mACmvMP6N* zO`B-<)I4{01YpggR9QsXn;P|n&WnANd3;yQwr~i2=$D?DJHF9dWh8FnctRk93QX<7=px zm5i;OdvW|Ym+%{C)t(?HN~ywDlKC#WjMwo{Hs$?(h>m^O%s0lX{?UZF)z0${bYkDX z9?Y^?Z-E$X&%a33)HYr_IdWeA87ugD-;NaQb71N}L3>>z4ehP1gfRSh|HimY;rj1t zD2CC(-{;sd4id%0wS=s*pHy`}K4}=KT=I(J{OD5arKz0nb z!~SMKnf%=^4&7`FVGJ~$FIdnp zeblL?nKCKfwS`wn(Rl&FN|c-@6hkMy3dEb0}zl{BN1UZiY-CzE9ij>$x7kTJ1SJi-HZjQ}^)Wzpg9<@xZu zD)nIH$UAvFh61hBVhv<8)fe+rg{M4WG*f+vUnHtgCiAj$qs{R($~ z4dmu~g0tysVRLCZoI_IOH=B7{-gZS6&)AW@{sn*M$c;UEyG!T)7TUUaqWX`+Xg_Ip zjtS$yCynoAtp6xyO8Wh9Jd8M#`)Yj_W7F&Xagi#f%jtS~brAL$NZm-y)VNiBvL+a` zyw)7Oi*Wo`@xQRmpvVd57ue?WMr1HdN9k#Igy@hO`0Q<|LQ_B^UZ&Y|iO4Wk5kN|> zJV}1Qy;-pgatyHHDH=)E(MQ+(lYnzk80IuU%m_=Z3%ycQZk{vvTKj{eQK&r8B+{zb zyd;RxB)TJCCPin0(K-_;bpRIFAl^0zTwz_ymi7>*V)_nTxV0(zdW_VAi!z@WaloCT z<+4N;zHD&mg4z)WRk^cHQ-c5Vc3@van_GG$Wth} zj9Wcv=@onco34}DAjNKPX+rV~ca1o~O8}Gt ztYtyOZU%*w!lmp|(T1Do*X z>yooQ`kHy_Nk-QU%ZBNi`Qa;)XbtB*_(tO~Q58oE|AX{c!DrNXOxgG`&;6N^2#|FI z6hL;OgO&m(ljp(V^>(UQ_wfohRsU_Z3}Z8$?>=h8h$)NjnQ6-Bs93}f&|L`&PqX9{ zmBaOw@ObsN&PAzK%?gNrT9Em2_?l;W@y4Z2gfoxF;~7=EY3_Y}F{F{ec# zU#{&wkZPROi&;*(+qKd|P3KAAS&rM`h#L!*=Fy^agest0=uM!>awCnV{Yn#fgsJZf z>&{>|jVqNEn^)j*5bQfs1ZhjTy_6CXGoPuTgJUB)Q`5nQ0Am1UG2J8! zJ)1dVXM{ESJrO#dfdI`LK@<=aNiI9^7S&~wiWMQvvU_otu~-cb)141 z3ZEIJ$|e{yB^;Ey<+VYLusxfJ5Uq5*-=V~vqoPK&IT$t~cSy9Dq-4KOVihj75c{Jn z2*WmbJ`1OE*w~Im`b0lund5*1eYtt-eovnCBmCke=^uYQhZd1Qu(wZN_}kzgoksLp z3_30qR!bR%bR>eDdx*)FnVg=Y1q0&zJa{~h?7o>YoyC<|x_y)cCOUQZC_!iuUZ3D5 z`nm5k-(`GOEL)c0s#8ng3e@Q3vzL57t|J3PUEv@P8rsvDWI4RhKcx*75;xJeu$*|f zYefwykBVV5*^IYZ7%Q!gY^MHJ=6Nq?xpO$Zohs3N99bSA&gOYqhZx&}zNaUDggkiu zySA|Zv&6@2IZxwlclaCJZ=)G|WSrj1&Gv86h?iNb)6f&iyVyo@hL89AdcDN?&;Zoq z2O8>bilv+SsAZYNGxFVjdVRZ%@Raq!ExnzbtmjG+6GPd<;dG%@N1!NRU)ih&YvKFm zvtr?lGOkifh|8<6U$9p?^;4Y~@Fg5&p8-nA--~fGxrlQ4Iz=^jc`WTNpFu@PSh1o? zjVct@Z$e$AwCpe+Q4w{;iX|(r9-o}XAwqU2NYFUDi#4wDX+$bnOW@? zr^Oj0B0JVNrJ?ONDyMjeT)XMi?{2ECg*Eof&pQNYa=)g)QR4e-7k`d5VtqCAc+Mwe zGC|QR1{q#g#d@k?|44e9YDaTxDE1|$aea{#fLcm${#SvSa1q#nQd7E7VKlxX6D5v= zI+N-EqHhs6QN1zV>d>VhO~B{RD9g)(gl5mQab6U8-YIe1p67R$^(HfY+>e8E5CL-8 zkLQjkUq!>ee$1|7S=gpE}Agw*0=FTRP7GIT8SeSp3i5Q$kcI<)*pDw&P?GCh10^U-=h(xpCA2FW0wCjFMK z9$f0Y^IBB&=K!qZbohr!ZU{`bN$Oc5jQwn!}*k40bF3gSB zd=U^a@PaWnnhB=~sKgbJyuA3l>!d-1sV{ffrjL}e;2?|HpD|PI%v_aG&13P!X39yOSe1ZSiXv#X*k zxuH!7nGYV9`}s7suJ9Zm4xi_P0|@Y!C2V@y{#&IQ>;nG2r5nnAziw!T0yO9g5#VY{ z3qP-y+pI#=<#%RAqL>g=fzK5id+#&p#tk!fDS1LRI&a&_2=-2eCTM?Wh#&jIYVB%~ z;dh$D2T^ECEB+rsI7{L@{s$vIUQplN5A#BypCP~H+Im!7OF*t2+a#HJ>oV}NJBIYA zRK^GQ*zspnwj;+!@)QjL zLH+eO_>5Z9Z5+{mey$vUn&d4C&>GdcLH%U^EQOn^3M4If!sVZtq>yf|*Ga1e-$=vJ z?kRTmB&7?EiJB;O`f@;~49h2nz8Z9d5-D4lQuZX{E?PBbbM49qTHwB|B6O4b%@(rZ z7M?mV7RA><`Xfx_htuiHIV|u(`||crX?nLtlA$&Oy&W+ z(BQya9}piitXF;o9LC-0JSCe>NUogA3@(9Fi4wmrsh6oaWQX-zHy#K_0CZ(%`ZzzI z))Y^5rvH31d=AdZ^nCYZ`V28`(E)C!_fT6=Uy#MbP@VqTL{4xBt~xTa0(o99t0x)o zL3gJo-T*+yQ_r?Usom;I#U|4y{3z5ji#-_UQ^N3>j&d8LgU+7AnIPSdw{;i;$~A{S zPG_jb@cfVBTrYTY#CEU%0%dt2SWL*rda5SuBHa&#c#N(@N3$x+o}k7tX?@dG68sU2 zYbeYi+EM0KW9|ZJy2@1jX)AOYFzhM}fY%a36acis?eCuKQ%Qvz=q7LIjn%?2ge=O% zH^1rln9r#b3XSw9bfQkL`8G?E$>VMV4=KQt1`vtKJckOA_1-M>K!r>GK6#SAkgI43 z;($8ruYs3u>D3K1HL?5Tw9c|nI-5=EvGk~LgPxJJjfR_}Et#$d*S2Lpe2t)hW>AF_ zl2G}aXw?*Lh?r`7JGh&q(k|_~=CEXDSd`XBPp9%hW{K5mjk`0sZd$(#d|Da#I{}xO zgc)kCwx?9_Ij>2xJQd}pMkIY)!5-4)YO#lOCRTrx2Z#qvotR~Mx8AE1#Jnu!DJs<1 z_m&jS)(t}&RDzjpX`i3@cb^(T?MTa$yeyZrDpnE?T*2MtI%5zi!9i{`@HSmp$yBwt zCkaNItP#RO)w*FEOr^68z+=s>%B|U$-**)0Bvn~X%h#6Dd`B#3vToCrP}>_eJ&mUU z5PUd$JvTkhS(TNkVVLW92z<1UP!4B8$us z5)*Q_s1Ziu;CPmr!T4;{+fh60{xDlTzSDv4Er=6$wbl0NJ{RxX7U8YQn+?!U+1;x? z!}}Zq85Z%V(H^R1dc&Nb2fhg~2-5F!BacyNwZ zD7_r@R@j-{(!Br(=?8>Bf%t$}>)sIXr#OW|`rkyD1CWJjJi&ifWkhzer)o48D(PtT z>p>ppGk>!N=vsJPMWP`{qT*Z_yE-}}ok9~{Eh5@=1GDoVIdkA2brp$r(Ws+{`~gkx8-hd5LY(HAM(Y!M1WHtoGb? zNy^?yg6rfp1Nrt0Df{Dn4?1bn5RJ$`kWr-9!23J`10Q!HGi>k?J~eVbHA+qH2SZXZ$fFx^P)48l5m?82{Gj6Bk#DACR4zDr=E^7Y#9?}GA+ z@j>~1$)<rkGv;^+3a9iW@Az@Y=D%qi+QRe4}pBiHci&i zZ|vYvYDT%++_-o@eO*JsQB7mf0daTI?YfX^{f#v-MDs`jqgG7}wkD@EiD-xJVG797 zS$mk9xi9g>d(v`Gn_^OG{n48VGjC&`b(U_4=9U{bW@YawMZ~Z^`vv51$H@tJuk;^8 z(h#@)n~Y&_a`_$~V4j`5y8I1_OV!0tg|>9ptb*d32x2u$z-N{*oPSX%*6wDKwvzlz zk?EzvyD@A#qow6VY)lw?gB9Gg$L?cO5r!>wYplBuSf~5eVyLL*Q(7iG$yYWA+!1S? zrahMXVDpJ1J%Ns4mMX*<4-Z+U@X%`qhZn^Ojdq2`JEV|6<7MOQ6gruy102S^+O)N3 zJ@#V8wAqx(#}m`j#iON)eRiW*N?&9^2=wb&!j#ud>y=%m*L_7Z0-)wX04I#VLto?s z^YYTLm{I*ff68Ng@AylF7U5);Ra_@8-bz>fyt|F~L!f6{v#a&X&rN+}FDLV<{e_wp zo-dJ+&)@!f3{=`Vx#?dlh(5W_R*S^dT{_r2Jy^`69`kGc$9edllZLZcHHod8JZ}_k zP-!CkI|iPH(aq73yW`45;RN~UzVdu#HBvAZBz(_KJ3AJREb_G}n+-OH)&+TwJP{$d zSaQEn88=KI^&;tEG1F~6y_&l&8E$w=c#A_Nb-=S;Y=Wx!wj(K(&CJ-w8EUIz8^L)M zLDAL{k`|@$76=qG2?2P*wzJUrI;)hD+Z2BqphMO40xM*4@^|BSq>kB2`jj#se$IWF zN_+0wjrBtE=lo?YOAA1vP+hv_znG#@0#guxq&uV$!2xBqm_kDAe?r`o6m*$ek^{ey z#3no4CwW*nga6@NeBCI}&ZOrJ6D_dj5w;L^(CAK8Q`nok>S(iX^`UQI2CjB2r^~`& zQD-&pIeePT(%b<18!vY&;@O(b(|hMNX{_hJu&);GWtqDb4=9WBCj5G=*L-wq@~E|P zizU51VV^SV9&FJC98**y@~;8~{&0@BJrm?1wAVKZ$on;6GPLi?`8k1;^+sGpHkjlY zPKFr#YEo5biY?Y`o|eZtubd%D<~W|i5gh#?=IEC&D;SgWel)%tGsVwz7dT7RdGq?% zoQ?nS3^{e&??C{4E`3q#yl>yn4jtgj56RX~RzY_m-yvuMcLHj_)tqiLx|lZqrmMQh z>$bYTF>U@+;Jm9Im#j-bROIdqMYIpP@hr=e7%7H`dwM?Jck%p?myZW=P}ilgIy8pf zZhj&A`1hu=Ror$UqGcUKnf?!y*o-2S{Z!n+>1Fl+3~!d8)>wl|SICb`V(4lu#j}8XHy{Wl3h0_9Gx@?9-ejxSEws)vsLDzGK*IpfO^D$>taY0C!!= zD~~i6Kdq+mBH5Q`_kdEOb`(KZ)&pT!}gkc`B% zUf1ee(dut_-sXO|(O)l}Csj?_kGG9d&_Pseu`M%Tv)yAN=XE4!{q_Uq|2E3To2E+r zR8p}2x|^s@jZ-E^Oq?urokn@PyOKF*zn@QaBI@WH9Uxw$H9J;a^^j9l6yZCf)4<7- zae+R2kR}TxhBj3`c)uIZ;knXa{n9St)_5Ay11M*`qN|OQ@XnhNKDQF!>1kt*;7v}wR*nl>TtPmaNW@^Mz zYh5+r7@aKKKi%!f(KJ3Pr**J*D2A^bFlXF%;7(#_ml@$l{aMnN9CH5eeAujkl30;B z3=z5=n6`S?;cNV@vNuvwRj@)DRi;JP2~TvfzzCOw`1fcSdNxV!DlRmuuy+Cl(iEhc zWsg#znYuQ4eIVVoCpTzdm%=?#&xY&o&MjN4FgzDL$kLEC?X0K^WM0gw8%52LA6~5g zQBp_GJHKwskyAazGheA7hRqr6J`(;x$^B+&c$~D`s`mrRXItDX=i~i9l6Je_RSyjy z@Z59-W{UBK7?~Hu(0;@?k-es^ccahMFl6BEPC{ew{e;eX*8XoRuK)D{^mkC&y#cl- z5J3}dRj;rL+Smry$@{9k95>;&-Jfr+ju3mexVXAluhkn}^yMW7ClPfRZ5l+rK6_7& zq0|8dxd@`iUv>dZm#U*mVwP#3neewe~7Skoyijfw@N!!iOp zp)1G@O4n2-&!0O+UlfPv8QH=ciY14f>J*#J;33zy`2y@zHE^?qemX3{_2%G$PKz}? zZT%b?5*Oaqj8@0EIkwfYWhXJuruX&P@Uv&{42ypYI6eu3G-{s`KY28Dq-E{8RK=F< z5%~L>FIJ;!;&c4>zS97xFYEE7rH305=<8f@SuCSvfh!X3~ z>&ug9H1TS3IXU;={(P1;L>5C@X+AsYU+Z(*ukKd*fq_3<5zr~cpVW zwN$VTv+nCm;$^rjxFfE4wtNQ3$bt)gCZ~x)3gBA*-9u~MQ-rRsPdTp^B+&mua^^g% zRp(ie?R5i`GJau2l+6v(f_hG_Vue%9UYc%xo?O zkfCrEhA4!&ysP5z{Iy(W=A>Ax*HW80zH6Y8@*j@VZjCBu2uxLB<1T&t}?ez8d0_mR-5iq zAs89uY}3Js(?zy=46tX75O4`2G0%3DpBnaR5Q1oT=hL_N=eEeRmkXNj?X?~o((FF6XgjrG=}C!4n>xks!kpGWWK=Q`G(@e6a~NL=@M@Nx~_QGL zzm=L=!(y0*_@IZ9wi)x`Wjx*n%u-1ZwD)7*n}Ke5H~dTGe3MZ z@P}UH^}ZgrrAU|& zMV1!G5cyXCG|erNmmzYD9XNBARK-o{Nudu1K~_bJf9CUhULd<$2C}w6JhKqE*SeO( zHv4`oGM_<7+LVB?8|Sqq0Wt^JL0By~axI@Alzil2xEjbT8D;c5GV;yBJ-IQo_$1Nt zde`#XM1CYIf(Da#i90wr``5xqBZZpiY2(E(MXB8YL_|2Mi-eCdN9NAoBAsi)a%rm7 zcOo?xtEeEd7Y9J$WCyxAjI?<|U*hIz>of{cPmB3E zQ6$X}l^ITa<&-G~n|nESn{|`zE8NwV8&e7@7Aj*wWzSs)C-VX@H|E3Y#Y}jep*Kg5 z19R+9kEa!bM>#`!k6_%!A0MkU>G}{KWMW6o_YC;kAHo1u+aRn!%KK7;I2rNh|JoHE zHAw*bas_FQ>i`TEe_bF|g4)#$x8@HjtIUh4<+^lkC8?oHM^Y6NZRQZRWyK1Bc2PM3 zJmreHN*0#^$FC!%qV49}2rP4O_0cDI`RyY13mnHe1t|^c@!|K8?+MA~@JQ6fkLt$C z$Px7yoM93~?1wW^X$wQQ_W3Bz+0W&dNth))iuL7^9PzP!|14XPTQI{XXCI^l%t=LX zbTyn3W=7P1c*@GpUc+i_D`KOex-yP64;x-E9$4%(Aa!JM)GBjZr>7~x!kjNVMAb_e zwHXebFi_S!uF(9=LZY$eeJwJg=FH1lsv1H;th4yr%`>2$Z&WU8WqyjzqT-!oqGH1L zEj7Ej_=qcN(nT7!LK(GN)~LA*8AA_)M{$gc4w=u>J;bPoWTKMhui0&ygrrcSAMGZ_ z=ylp$2WCbJzc_ZYtSVAXF}`|XGzA+B0(x^5&?wRb$hBj`fut&O{zsM)qY7W(D!^fW zTFTZVYi9yez@~??eIy>YJu%arjr%R+_j%J?n%iyqPQ{mKk;-E9>>r53V8h zlsvW?`Y+QLd~Uk}&^s@N3V1ET3*J)sUYkL|{U4N;sJaJ#`ni=!!uY4zbc(&cteClk zKM-=&3wdGav5I6(ItifdZ^cqxP&QphoK4l_;yL5K!VC2|xy=eOm+m`Ghh|=Bkb&Iu%$a#o2|o7N zu>LmVOiI^dji%X~5`Fe*$b9yc(WQ1WK!K^4f7_BxmBq*lF}6GS!27R){*z~Wx9ys+G3aEyLwyWzwf`)z6wc14VoWflKJNsWyFp1rbz*(Iivrj$`s zZ8ib0i_|xXv*p)E?Oa=0SW+^RB6m~?&Sw$YRGAIf&8rB3jcfv_%!}zU9vZ#Lr@3(o zqkTh%=eyljwH-4bmYZI=DgK87HVi>N{;R(SLtXq=w~IM%Gg4DxdU#(nb0O)Nn9dDM zK=Si+s9^p6j?IPd2chr1*@yU#-v41)ceV0yo7`AMio?o4nI%!By(GJb4tZJ0M9aHThq@YXf!4=f*t;h7q)zt z;SRLVT?y7c6IP{i2x}qf#^XkbrGcl{T;bPJTT((F6At|uskHG^#I87LR7nD<2H0)! zYg2zjW{!g=^{7P`j0IQmgfaO!TZO3_Z@re^m^Tj!pK;+jpW$cvT(lm)@&vr+IPKVq zgzfb{IaF%ekAv;W;1Zbh3Td+%Nuu0px~n-uysW8(j;!?1fy6v$HyNWMYXMu5CRGRM zk-^L&(?tt8Fjz7C9)EGnMLRHYy6E)!T;8?Htk$R=c#8RRr_o21an!2S-u35x7N`CTJZgBdcYr36!(8)O5XrqdZ2{UTeS z-$SnLGB3o*1ygjVT}%Kn9$jRjxbOh9VrIC9d!$W%pX&30uDr!SG3N~Gr1lSTl@ z{Y~b2kvyGaDyH)FIETo7+1Jatx)0}nhnz9|cQXxg-cLZ5p0*;SH0e&A#U43r69R8C z%dyV9;dvGXI<K9mm%^vry7zimEI@j^OIOezp z{hxh&U#)^^R=z(;62nP`LttlWI6*JbVmhU4gM78%7-q^su?MD;3Ura+f_DDZ6A#xf zC-VMH)u5XGyYE;n7kclmmmTGHGn7_cJxo3Nsm15tc@a3rjOc##y@RsOK&6Zcb1}vs zlV{N#r6UVtq`s!5DU|Zsh86fNz;@(^Lm{jGANR78u$veorB-FtuOu82gpsGF@MH4I9ge)I3Dz zh6Z4xJ$$MrE!1q<8%qe{%a&O*c(Lx2*Gvcp_hs&TXZru*ikhaysRLPR{N(vMMq1_B zN$QdxIe3wHpNxdS8F4hG?3ZyGy^mZgG*!ip585Mf8&`1Nq2L9kM0Z(?cVwqOI~yL) zFCD2FF?F!s^fDD^e;h4`5lct=TKzk!5xAM_5+MA0H2vZUbNQSFLv~!rM?{Ew+Ro!; zPE#(Lyv!#4roI)O{oZqV`1q*)I34)W8kryMEn;NvsVkY3agQ7Y;w#u>e8EPYiOcgI za|~Q`=0_L!ZRliwFgPG}cuX7~iNF*ix~r&VA+6>5@Fiq-?+SdG2kCINY1@?1_HcK$ z47#$A#oR{4Ue+^=I39X51^AeH5s7kgTYgdx4!}F=#87x$9`cEl? z)gkvpv-v{j)Bn-|#AAMyPx@wU=lv%dW$OGG6}+=Vh}Sg%zu9ukvC!|l>IJNTrlii6 zehed2q|_13d+`$x4lT^32_ ziM*Mm6@ks#1%o6OpD}FdJ{?f@B?L)vi_2{8Bd@HRK>y29inIllj*opEH=S(D&sL`|e;YSOH-zN7$J_QRA4QG!Q4I8rju)?HYbHA` zM{jSsQa#Si4rJdC=dLcKBmX+x-pl(fUM#(BRi96y;5R!ls*uwCuNQEKDk?7W!dc_( zxuHH(s!vJkU!0!@!@t^me;X=RAmZ8F@itWRyOHIIiq*a;sNG^ppWUPMz~<8oq=c#q zD@X{r^64-Q?t1|;xl`aBrxdw7pok9%OQ>mX&bxBqalcB~O)X5Uy518<2R-|mh1J`P zbz-6+k;H^NZ$K?nzw`?k9IR*9e!|c-Yg&B?A-gcQ@!jgJLe|^C`Vd0go{!5rnRfn9 z5(9JYOg-bg-EQ^%49WLwsYBFqyG9FSo4~ntD+;Np+2};FjR{4yPBxRn+s2IVOi&WeABO9eGQ@Or%n)%f1tAPu)WnK+{>M-<^wbk7w&NLvxDswA;*m9{N3;HEv!~*;lQ_KsBU=>n|*$Onrie~ zwv5n@vyALUaT;cSLOBjy=mdVMNVc=pXtVvG?0mR1gK0Rcsre1yn)V>vAQG9BeXsSZ zP0F#J{xx}is2!Epib8~RzUAKHe~o%15y`u&y*{AvS=)GDuD}fru4dq zqcqO(GChc&V0qk{lau{8a%3bZ;P?v9MDQ{RA*O;ia!mZ5_-Xo0Ht637U>U11X+3|I zMpCaXEb|gXA)l|-2c;}+^7fMJ#%`$3U2MU^hd>O2&p}`bV<+p|;pyo(@Ks%0bNJbM ztyYWEVRz40?mfwAOdx7ZymB6Kv{+wUU7fkPITs&Lz{AbAWa=2=DTI=VcqU7x+hkqe zU-pECekXg=vC^uE6h(y$GW+~bgkP)eS%fUqg@L(C`|)xsdqRID3qBV!MpU?u4EzVE zHujZ0-_3ek`^1$foDp+iD1`Vlc9HX*4+|IN3vmde0FQ$`lVc>Opv0y2s^;ZZb(GZ# z#Jm?P5EquvA&Njg>niqZbyLuCK_Q5aRO~_JZ!^o#UA*@W6}wzgT7AzCIDs*QuTXs?TTUt%GIQ;JOF-Kk)p&zh5ueemsc|b@qWTw|YqTMRNY|%|r#; z9G)+ZA3*Tjo1yHr9J|J`WQAu>RZN8R4AadzC+BPp)Oyg(to$?(b!{h4&U$-DQgiw< z5vg-u2HcAgTg%A$-|F)*zal>8db6|Ee`8JwRw{%$mA@w+7>`S{nN*EBc0F0tjzDLHKjq=kiV>4x{BwH+R7ooGu%G=q=Kb< zggI@XRZvrJ=TUi?8KSK*K>}6kLnnlCbL zC8`Z^7&d|Mx@FLTGViw%rlDiQ=i<91#|@IJ^08*Icc3{`6ce%x=yP{{^W_QS*qN!e z>T-6PoLtg44GK@E`J^^`u`cK2JCDzCQdxo^uk-0p!qmI@wZ@}9q2P1WRb5S#p!e)Y zm6qlQH^6pv?c@tM8|TXxYMQFEC92&=`v(v_YKV9YfqL}{6wnK-_+(T2&;t_+ckk?S zPD~Vq?9?POABpp#pnrr8}7$_1aihEC6dUA>sHR|48&CO0XO z6nzCbYBWMeizjz$Y`_*>RuDSx#b10k;EO=5(L>$cd$ zN9Vo4?`|EwpnI+}y9$31WV5zWhx(vXDnKr^PK}LuZ@0jq+cBB7(&B1<+ka^9`v8)u zuZW{2X0JR!SC2-%J3C$5SmzAV0#)5Levc$P-CS?YvpEZ~(OOyE_*Y!H4#o~g*7N=M z-yrG#AN6QK+cQT?3PV6xd`(^WrkN4}ho73jVRJH3iico;5sMs+`8`U+e;ofCI+RhA zhB|Sx--NZc{imsEDQg+E9_P%@GIB^R4}JZivVgT+ia&jU7H zaCKc+iXjJO0yd&?wv-`Xk|KjXI$L$|K`%E#9Z!Qx;3=&yW+Hk3X8#?8oy!526Dlo! zG5@JHMXu5BBUw3+)>RXjCowa`QcEr;oLfVyuLw@wPey@MH8=`6cQW)BOA!_uENmK8 zMaotJCUEvON$WfU3VIXv*|~Cn%J23y;rW&mMJNZF^7w0p596~B~k z6NT+u5-=uJxPz^fO?q;j{v4agdZ@8oq1%S9dAqOMVzC_>Po}4^4Px?1GB5LI2kfz$ zSejpudkOxgH8Ur{;1m}RNSKh8jGq1kD9IRTguV>uavkBLO7U%twZuYB52DcI?*5fn z&u^4$uiKo|_GyGi!O;lQ6Yq3&+La0ow@VwAv(}dgp!4q4MQ+{%2MK z)xGI^o_3M#wXZb<=x&aIUIUd`ZFWy@^+h=5nM)B7;^SjTYHz4YqFVHXgg3vq2znW_ zJJ{EtVb87H+x+c=@bC;yXJTX|E1RVSP6C0(6CR8bd=FHFA9v2xLwVH>66ofUrPL^I zz}Ka78Nzn>KH)HY6L&I(^m+eP3bK~zB5|@%4`Ag<{}PP^!Yvox-IJrU)}sHV`s2ru zr}CrgjfYUjio;qQrAmo;iMJ*TO^%)$6&(ScF0UEt z=#yfhT|K#Yr`UPH!qz= zlx?MV_Z`~EyF_!gpq&!8w_0G-c>Q4vDHwK6noM!6fG)lmASI8!^DfO-k*qUf|B>ok zh#*|-RB{8b91Bu*v!xtL_)=vz{KN*KvaLSX8ljkTuRJgNN;|$~)Yl#8w=^Me;`_m1 zRQ`{C^^lt{7bE&KQ#jQi_A#T#K!f1Xz5TJ&tsmBy;)(+u2O zM^YRZDwpisS;tR~v#`du5n!0JT&IU*j=hpk*HC^rcGiBlKWF^6Bn7P%fGD^OGy42Bu!9PFUJYTIb@i*PQ zphw7roMG>X`TH79+IVae?qGzAmGia(&0YJ5 zC1@|&l!A|UW4t)sLGiA|Ffne?;jH=!UxlS)7pveZ`|T3*%p%2gUn$q{zM_wCCCn2C zTh3$2@hOCy|LRj&7DNvOydSDSMlG(?Mx+mOGZ!Z7^4q?edP@@T<7+N3)> zSD@2-Pg(aChJ;PlZT;C=45~KWnbGgH%1kPp5nbOVMdDP|?pJZd?UveuFtKZH<;ho8 z*a5~)=9|Ff@7&;!i7$wc|5*9~L?ZS*87_qJ9Q4immaFv*zGzXC1$p9FJh6)iiXmSZ zn)nY6jORnEr-t^T&`thh>Y5!l?cee`ZCRN5?V9fp~F{Jg6O=A{2%b<%z)eq2Yi z<7j<5A0+X9By-)o>-hpHr{jJ4-;~aUaFyjZ^J{H1$zRG<7VNZ0QJ)JC-vTPx*ReZQ zolR$QM_SE+;Z7F!4Q6TSWJQsMV1a(p@mYwI@Cn)^{#~0zDY!yeKJCE>Q7P%`S)dom z7wM&(+T=h4_Y+_mbnrRulSNaq-E8XlOJQ{YZnVYa5 z>JxN(tiGR*&C5ZM5r3ZBAsrY(ExiZD`*0k?t0_=MnH2X0G3f6EtTpQep$Xca+zfzB zeOmN?!6(?-ca}5kI@6kB8E#)cVAL#4bUxRnuFuaIc6nyD=QZa>rs<|CtB~9q0&u9! ztq9_vl&o;{489yeV`3;*PmGok%0;LB%EQO~@~sr7po<48b243J(+LqjTI`lytH#7} zjXZg`kohfxt!6mH5tQcGaeESSq9SdZf9lINMd`RJOu^kXfou0v87R{p&zY`qT5em6 zczWt`|D@Lmm(8yuCAZVTt@KvCTj5ZY8nT`IgDGo96A1pbIfVbS%CeSJPqcC^I_2~+ zWB=A}yliozY!k;!FCynz#p^nSZR+iHtzT}E;02s!1gWg2*~t)iTf82v_I|SRx99rK zyOl6A>3?Z%yer`pTsDuTu84Aermin|J4M^T@F(rMZ~HP2o(Cv+nd)bEP+a{Umo(j^ z?4unnxI@|nv%n;KtY{nT#LYVWSK(2q)OHNc;507u4Wx^_#;AbgpJFtYi@1bPun*qe zhz4P)i4&bIbJ!cV*bRw6ZN&xhXRIuYd=akaeK$N3MMz|vFDg@He5i!(4@se5_Gi;F z>Lao5=7w@;Nhz4qX2xqMQ+@#~TgrB3b7CUcQ|!}V9Y-vE*Kj=m@dwt6u5vnkA^1wa z*5dtP?`B`KS+SZQ{J&m6O=rG}=g9iz+`2Eg`|E(qb%$pffsy8%ZFX}{pefg;t#R$$S@c5g*cMkJo0>!Zg46Uu|olC)a#A^t&Jy}M}_Zl;(HuGx8 z^J^FD-z0T7Q)IM#C&*x9JlNV8FVz*fsWX1aB{F*wjVC4`B$Lx&)Rfsg9+zJ=Ytc0b z#}CtBew%^EYPoX|9o*xq&lKYT%^3v9l4wgd|52gWC zm4HBhd@tp~8Of;4s|v^z=YhT*sC}QUO`KGaV+~6*v6S0l?5AVv1 ztQLQDhRZGL?Zuh3UNeMdPYiaS`*TuN*P!Zwc#yxz74#s|t-G2H;XzlOO9=ot4 zT*2H{P+$!xhP~Z>x21PxMkhQ!u^vK%Z(FQdpT2?QtnpA{2=e04y{kg+t#wx!FCwF3 znw~=y)S_M()qNSD?N^02nWQj@xzrxKJ_`L;t8MS(E8)L_aH|ftEZ%_LxT#Gm3(A*TDYFZ(_cITOXWG$2tnqRXn}vRVG{r?f6-_D zNc_4noLwkap2!(fxA!oQBsLuInf;X)wZc-dZ9)P+VgRkU=euEe#M+UXkb+Q;)(1PL z!VA^aLrl}t@@)o+vv3kvurcEhL38_(jz5;Kg2BNNC9&%Idjs%Rfb42WKdy^AER-8K zp3!e=Ww2Pm)VuWL7)Z(7uTA{Us2&rS@3hR`*OWrrFHP>kVZcl|z8IYS_Kv;p{n(4%x@kR+Tl-ZK++xDY zeS+_!D*24cHrc^LY8s7NjpX3Grupf_bIOvjwlfPP;Bz1)BrB8iaZho`^ZHu@;rdvT zl<9I>ps@~K*3rh7Pg}fa5EIkWNpKv8AI@^Rq&G%tD|V`a-csu0IMsu){3?n_c>V!S z6TG(kvTi@2w{c(sHA8EAsT{e{QBh`nEiSATAx3bvu%bkq8{ny)(=W}1?>s#V|h-B?05Z}>@R}Iq-Jh8v?&%PoEtMdd~NgB#KVjq z9VTL0%(cAX=(8^5^ZJ?bj@IU?Q%G#SV&zD-hBg@ zH-Z`D)z!ez6EJnpm?RF<-Sbyc`UiM-_n6zXL)T;vJhIgoqWCif5r2aXGLj?)JH?1`3V!t znI;n&T5GeES)?IoH8{#n6%z}v)p+7~z0hQ4P;Jj0-;hX)68aT(IiC(wdbn9HgHDF10u8AOplK$1tz%IJC}LS94$FqT2{6Eq?Uzbdf*=+_@F*wO2)EOBug7OO)hD-$#eFyc}I=@-_=N}C0Y1f+1GJV%Ax{LJn z04&oAnK6v@b~>UiC^=XSvgmeqWSOz=R>v9WASY2o_YOEh8FCq%_tf+@a!UcO zOS0es_P*qfIx?Nlr#;hPi2+)t{8}ra^^O=@i1qD+KxKH`M z3#U78)6p#I(q|Mpb>GQ|1K7St_iV$lb8o>TC#7dKtI`Ubdmh(3T_4y_VcRwFjN_)o zdcQ3R$>RPxkIHmAd?SzaJTtvNGx)j#PHoCCbzeoOFRc*zDwG;DeRD%m(4()Df6r9y zeh9e|p1EKOxmqh#T%2}!N?lecOIm$vTS=B4R5i+R;kyZ2-ZGKCkv7|h&X-dQugy`0 zlh=J7VcV0j7h$DxEtOhY`E}uyg4|LWQa9b@Wz>e-)#`TEcGlKMmYZr-;#HJ;nAIyA zM{)M$wMI5mO)GMqL!)s<3D;b&LlOkd+#JH4W}Lsh$hOM$;NyV~Ba#aigiPRpHKI^U zR|dMUfFE`7GHSeZZQcTuZu?vkI5CPFM@Eh`b1@q%yHC%u9Ksqcxk@d&3hWsTAj*Uq zK=K&`P7xn`axf+$zy)$^FKyDgBLy=EHcyGT#NKwM)(ne-nCH{-8>q!`_3pUXN+b6@ z9P|fgV}6l&PzO7FAAK(T@diqsl zG9>{QNEt3^FK`^g&G|FC*k2m!TdqCXPN_S49n*|l7e1GjGk|McWiHCCLmN7Wd;FwmnpThUz)6x zhC989^a$$h+D zy}dfcMeHVQb9!)_csK=f+9XZ8)>&Qp_?=WPx9BqW^gZn<*~#zQN%%6n;Y9$DlKU$0 z-TD-}1{|0}cHT|4@iw|nc&T;mbWUjawrZ7md_cC0IepH&V|psrA^TPQX#E?IQFxky zT~A@M8*#6+0j{7uLi$OP^&VxhTPxXubexd;Cmq@KzMcfOZ}K=)ZgCNP&g>$MG~Y zVJ9Q`ajlg7a7?Tc(V0?Xl8$JZ=qBbUZuwg9l5VWJ3qqP`-dWx_);0(6RV935qeg21 z#uH|ydxma}pJed_X;^s&+x09Y{csiNAA>c4{GBWjV=)_mWrNj3uLIouCc44~T<4-r z)GnHXQv*0(E7pM<-4^${lYAV(VMJw3@}8B${Ht#PrXh!jAMGg1U&oofP_)VWphc2t)#u4Sn^Khw zm|J%XpZUS-cA+thmpD7+WoGNp68^Ot4jx4;7wpdu%&)M;ntbv&o;H*m>2NUJgemUv zWw<{EP4V1q7<}DFFQj7~e_ zE?hY&e#_;?D6L+*-mdICEFMnNCY!GE4Kvt0s(f2pdF`Gy1nJp4umv_wNwH5yu zZr0p)Ly-%a<_y!QHG_>mF!T|@z*4AAPD=UJi602-__-jcUeMR{=fr78iLo%^lXF0n zSx2sav63?}9)-3GuunvOVeq99*xCAru~SH5(nXmrjZ@&lRgiwjXi?2h(2S0ChlY&Q zhyMY^gB_S)-td2=RmOj?d@Pd1t$f8wQx=`kA77A&k3Itf0%KWCTr&*OQ)J03DjA(` z7_rMiQkb;^>~M>$Qm%*cC3+t$Zb!>Wzac(IS>`}I<+J1tjG&^NrrgSI9B6dQ48`h0 zuGSu&1sLQc{`r-Y7=4q2D2ibb-xsubuHAf|$Cr959w#>K} zVCS^q*Mb1f+`NUYwVd-3r4f?PpeRq0mAAEYsxAp{sX3{85Y=^^EeADVyew`?o#__B zJE~q3`-It9hS0DYp|e|xMn;-VR{~+_vNY{_Vm7%fUzYUVB~+JoH)-B74GEFTQGYX5 z!!PE___qhPtnzlt({+keBW0@{}z8+serv zpR3-x8+nxH(ej)C+`sPuU{D7?kZ0P@jyA2cJ-Z1uT&pdK5l-t@Z3qX43hfTgX-~h` z56MoEr%ku3SykRZnBeW2CAWfoZLjmFJ&^lSS6FXRd=8we?jPM%bA{c_B?5f$H zVI;LKp{+k;Vua4d{K5e40RVUehBQN6`c@a*aQa(!zp~~eX=l7Qi+zU7KL!?LIV7^Y}Zb0fourRTS z3f|CMFTV$VhZ)wsEAVIT=l}wAk;>T6STR?i*c5{>56r2M){+is8t3kqvmvtQVDbLE zh6a8`>}f~^(hu%d1)oimxulVo2bG^O^w+Jv6Ogzwa|l}yuBkWT%ZbLkBlJie)3qh$ zi{44jkuJl&_bvXVH@8bTcm54%1aBb>rzfppVzfz2C1WWV;(I`}CE_E~(8!dC4F5+p=EiTe0 z^~>i5&xf0@yY6k0HrDl#uJ3S`qc0xk>o0Y;yiP19&-+eg*kaJ`WSxa~;#WzQJO6s_ zTc0z*u15~pVQ_)ALhmxMr#+knB`;kTKMd31VHdrb6H)?oLB(uEif)&ja_5Ciy;+6a zO;FwY9>IDgKxXL*lbqtgaGlJZuOzcHN`!761o4kEW*!jLWulyo)=c!*0$_c);i7SU zm7H36&y6uhZFKcE9)##4gNeY51F+EN(69x(&84SBD)xTPyOt8a*|Hf%4#U8Czb>=8 zj@l3yefr@{P=D^5Xcl$=tu*vNvOK7EW`|NJhvm~K?lG*;yMB9+9@7 zU#N*AGs%C3o;S>EgTG1U1v&c zHBDDG$gLed2I@V>!YLn@7zdAlkuSx9$BTpfxv$exR=GuX!NkE+xh!otT>1IvyD?rw zc|^AFy0S3=V+f%e`kp)l`9ZetHqc#xT^@>#>Z?!*tcau-zgKcn6hIPt` zNXb4%Z$j5YWD4dYUK@HuTLUx{3gv?{AW(q~6cRYqHWg$N=vf zXa-w&gdQi3qafPaxQ~e18JxIEa!rQcXeFpJO{Vdx-Ri&pgKyt}dBRc^_oU0U_Jcxt z%3`OwN~a;d_7iJJvCpCHEeovRx>lKbJs*7d}>|taNfFldh1l1dTXs*G75dPxgkjU zO))FiuS8dXDl3;9O_UO8p!%c^v*Dn(dVnJn)Z2?302$ghH>|gy*G20%fkJHRuaRI> zTr6au+uRth9;ZZ47dnE)W03q4-;WAVKT(m?peOyr$8tn5UQ=T!Ngb zblWc1IvEZn#GToog;?8pglJWDc@RnJ!U2VPwdVJmMa+mh!aj|1QqFt$sn}!m6!xWU z?IhEwYR`9qj`)THf>L;>BE>Qsk_~;BTTWaK1cLU(Rn4HgC=PIO-4{&r4_*x)#;4`} zhwDuz35`xqf~9D1Tab<(@>6JIU99zZ&g3!au>MocRvO8XylP6S7!$c2!jflS&R3#q z8VLLGEJ$X{Boi11W8d3(Fb=dU?YX7s2UVrmgvaskzz<`b%P+^{&RX-zwTJKgIjpwN zT+1&hw-?0;QqXNAuBk7Rp_eC(v`vns=d(G4JkLAwwGOcD^F0;=c>P&iz zBv8kD-ChrEm?odakcKqt+HSgcSnLPL3Ff|FiCWWEm? zK3UZYJVN^jbnS?i{!12FV_s;qUt@T6FOTvgmw@54m^{CsTIi@6l zc$-us3O%GpMvpI2!5E6hWW*eK{fq_j!}xg(o93kTZ(PbrQd%h%bN#(Xc@%_B8RmQt zl^hKMdc2J-+t0)Tg&S#TQ*1wqbV)7PI2_5)Obo0A(c+L*C03Oq!QmQ-_NRO0=?K?J z`7Gt$CBJl<2w}}fVrqJN?%bF0f{=FO$gsd4tbtO@DK6*i^Xn8L)6PkHOBAlE(cp7^ z1?~%E^t|z8J!dk0xnH9G{oM=9Ji&bz@_g2Q@Fr-R5X=9vb?D&6>E)*LwSyX`N)YsJ zvA)(yUq{`yNA5(|NQJlyp@CSU85oL_vc<+9@Mt07j~$oVOHR% zRcJFEF+sBSm`svX6354}UX@qtMU-)&J~W($XvLNk0PnI^B;n5Lm!Vql-7G*@rb`X5 zTFEk?6D{G~(X34|gMYT4OfY&-&UHD`>HG+JMvqN!9xH?`}3+>^`E& zc~l%LcZZCK47|Q-`6C{x&u=<`esOsHq$hlj^MnLn1>r7`q7;aNm37c-TYO_EuxgFm zi51`l1g#%mhHD5`(hl+h^`!!Bso{#i?XAAAYo2W6UY(5xiDdJTD8{YE0IjUWl-j7V z$mN(Nf|~^j9ZI;d0XPEc7Y%xXkf%E9dVPuYDzk^xo^;XaNRO*&}N@XFbS+j~%8Z$G^}FER(!aC%Bl?o zz~78?9_xX|)z?0*M46U0jW-{V?Ot?xEZ+CW*SE#NROy5S4J2(FFXxZ4r!}X@?&A8e zi?}F+DY}nOK)dc;fD^CF({tcJ2B4ZaHGxAB$wJI!t#Y}4vu6!<-M?OdF2ve~ zo5tXwCvq^G?iONWriiJmM3eI9AxPZ?ObTx|0`FeQL+rMdOjEBfwOi?M2ijO)xPjV; zYQIbxRG2SmSa*FqYS8t)td_cW)`ycen4i52-HN{1DX<>wm~3)?N{!qT>qw8QwOrk& zt%X8L5A29?TdvNM1J9nU)!6Mf4?i9p7H-_P-K<~%Pn;|sGX8jyQfAYAwaUWDh?c_` z^i*SNNxL)B{FLlLcb+Ld_w|hDBE&jM@Wv2k#B9%!YSAzc*3Fv=%LQ;@h0Hz4T5f&i zzI5?Jt6}{5HmlN5ze@wrOlfuHe-Sh7*-B^>E9Ar^W-p=g2UkVn*P+r$KIfYR&?;u3 zW`{+*VTqx<0{7H;5%tO4_DiV+rH++GUl=7xqA*u_muPl?D&S^qa$=aUQ&vo3Krmr2 zZH+7i*kB=hOPrB&5#irOd$rR^pM@DD5gTN5d;a|fi#Cjb;P3oJ#?9KcQgyldq(5hA zL`iEp1(J3TMVf?y;esv{*Ed`_x!z|9Tu6PC3^58>A@S22B#(A|6$B<566K?VFRR(K z2VolG@6-Q8)Y(s%D9%%(3`e`FC}p(#vyX0Qo{`kfhYABr$HGF{;90EB|C@&q|C1kI zc(;kT*WA!ng>A5-Cy)WCCLq5)G;{9X&#RGK834H|ijW7nEJ&x4{uu1eEQV&Iy4Mh< z1B*BZKAlTyh4-S-mIx$r_}Z9;0H`#5No?Hcl#Y2FTj&9J@3et)ToXm2A9^tsd;o8I zjB>8!WjR`kwCa|>lplASyMk=r zQ{JiYsVN3s0n6BEQ+)UygP%*+x(vh+x*)1HYV>UnE>{D|)Oj^KT*;b#5LX26#{ zT2W^>Bvp+B0oM z(aM&)oUA@Xzqfs!_2Fijx_resDPfjhdEHz@oOwMr>|7t};}x0OkG<)TI`gP zEb)HHJ*?Ybc*#A&dz9zy6#<@oYTBT-!Jnw$;_Qjonv)421B^YteJ5r9;Q z6M9WHqL;IyqqDIIK-O|>_N*bJ2@OhUX~H4dOkO7r%Q`(RBZ(O~FN@Xvl(0Y4OE*m- z1qnt0ikIDMdxaRvRF);`;`JQ+$z~j3RHc7R47S2gBvq6X##7^YY?8SC$%tOomWGO~ z?B!$oRaz-*){d4MG08uZ8ywz_j_Nyxm`G7;p1gDE{f`UitPO1}rO{%hw(qqBbbc)I zpKLN(!3#L|%-WsH)zq8Xy5M<}8)MSZmgR<3QfaU=*=x2_LxR|-FP0A+ry?jH47{kF zgikA@OWMs%_dygWmtm|UIBzwzF#iOY>{nE=wI5s+Z?(7zeAcH(E?oibI}Tj!Jv?E( zy+jk$>L2PC7GB3=L1IQYsDWHsfqQ2`?d90U{YCU;yqawWCAUF#JBh2UsiVHVgy^6= zdat#XP^VB=Rqwcd^E#O8|I*`udM0E7m}oSh-XQY1tUpju72j(FGoukN4OH`+^#tVT zgvJd*eQLwA+38V*6Lvea#R-ElTC0W7YRgubJyfLWd(yT*uuFl6yM5X!p@onBFy0>J zy`%+!Ekx0VICWh!f~Kp$fOG|V9nfX0>;Np|kl}#EAL1d$(AvkitUR;86)@}vwVf*C zB{nhkI(y~W%#TDHBr!6y>KRH4NdI$f`#|JRgoAxtt1)S(cUr(3D{+eyCiTe>fjvDH zjL+y_xz%;316sHw7FLKV&YwJy4F4J{h^u(S*%9RFbj_nZ8n1mp)h19K!s`vw?io}Q ze;OKjFrFszekTz!yH@ni(u~2IlD~?~7}KTU#fzJ92B0wzDs4*JtheFLYT{{?AI-MS zqrWn69mO1<9sHDt-p&=U6|P(%;laQTBXY0C%ENWMKp+oFdV4ks+WLdBebRF?I~Y8L zbx|YSpD}p{MGukfJ#Z!FOe#PRz|vP$8AogLNyfWX*R;gCf;NS%LB^2|$JHzgG054m zKXkUhgPK{j>XQz71j3yHzBZf>>@A_d7|!!98@HOW+`eX0o>nK@?Q6{L2{9xd!2r$} z#|~GaD_|;z=vTap#p3)V$t{THe_f2+aM|0j*T!i!MKl-|4}V;7uOjQvC)PQOX$eJS z-<~V8APhN5bZn)&P&dxwam}r|o=#U%1s=s0oRe37cY>|UfSk6^BeyT_MXq);th+n3 zA}wn7WsV1xeGhJ<_GEy6XK6C?%5%~w30iX6TBa!4FY)_D9FY;Pq?nxs=onO`o#Cu z|JWPa%LU57li=A7#s0mu4waP=>O?+4n6*$hDyv$n`yS7Qzu%IVIq}sp0Ozw#yTspi z0Nm4HQZ|jXwe>dY#;^G&0i?>x!ghNwL_MAM_GD4G&hP&K+vy{^8};M8wWGDU>y+5o ziYBxb=%vrg;9E_ecP@qc_)6rA?BsNo(Kta#8RJMgqow?hIJ+eyi0RAEZ@x2r9pV6}GC6_6#t4ud&l61;pPWoi zPH8K)$N*=J%1T#NP^&RCKI{)4PYF{&9g;~9>){7vCbu=`+F@UDbrgrIGin7EnlJRG zpZCs|j*_9}X?);w!I6P_YgLE=WpUrX5ldnN?Im`h zBPt5J_5 zgwLks759I4zVmncmo#;zP!Crx8E`+CC#Y7SUNGE8+Fk20Tmco-Edkve(bChc=cpbStlgfj zeHN?VB|Q8ZEQx7r`cuYox!?#-Rik(ayY&!O0CHutR^l~#e(Z*7B@=HE=x@&*YQUk4bu!w`!qpbuq5R?_&8H--7500_qw{jKgvXdej%xyB5_D{ zuvW4Pw|gkh1d|nhV7QD8@)k5!Lz+#A+p&VT+tI}<#%7!Dv)UVJ)utit>ZwPytI$oA z#S<06p^&rsCxLh_5+x;vA{WfDju(Tpkx5O|nLz_dJQdHW{Dec#cH8^9e5O39d5e=eS$8upg>t{vqswxG3vGzu_48;egtN<-xoh|ink_f~NsTo%( z_JP8n)rzw0u0riwzCE6#$f}c!9Em#o-S>ti+ zy-#pERthk?2B1-ev0;_Bc_9S(NGEHz79ox;XXjM5x*tBl=MvDRIRW3^`dfi;Q043Y zb~dKAI;tP7K%QSOY>szL9tb^mdH<@}YysE}b{_krr5*6Xc#TF7+e4Qb`3y8&9nBm( z=0ZMzuvd!n>wGO6%7``xxg}_#kh=T#D*br@dx+W$MS%V8y&|JYT2+24_r>+v(E_IZ zA!aZ`Gl5t%b`L82M6J|Oy`^;s0FwQcSaH&^(6)_8!^d88+Z2!Q=)1jrqSqwOmb&4sv(cn9|1EXiO+mz+(hL{ zB^+*mca8N*`r4a{5+hQ+EG?B-8tM^FM+-A3qO@A8&Vd47$9?3@CU|#X(-vcUOP#*J z&g_KPyyue3U`2T>iFwlN@hb#}Vj*Tlkx}1F!W_2uhxHp*q?LB6UnVxBcTvI;u4cyD z=#f+!uZe?Y+Uc`_3!lpucX49N4|sRiHQ(`a(y4m2pq#B3vG+~&$J^6Bx6!(w7W*N8 zEFF;OXq{O|b_Dj}TosTICy2aL?{e@;ye9Y%1C-w?y*UoCNbtk9roM@l(ON=lLD+G> zC{%sjLaLzi4R}dx<>3QO*C>2-SGI-;1YxueUAs_`%HiH7P`XG*w?|7=TZzu(A6jVt zsHs=Q4=#}17pQTM;Mv(QQn7TK9L(zr+e(^cRcj1k8U-VJNIaG&!7aN=h3+RDYqgC3 z8Oaj%(S#b4mSiERT=9$7O8X(P2*V%hmfi||JFF>$75Q&i7`ugl{??*Elc5O1-i)wF z!pEhbnB)^X4Mmhw8b#e8h%K{5MT|?-1Kjf%7N-i=m_?5vStnA$dAxE7S*uxE$bGD@ zpLm*pdeUf!zm5PMuL$Ia&|=W~qBxRpb&K9$^)E=KbSPp4OZ1eo;PCig9BUj?D+Ne4 zE~U8B+;b=?V(*8^OLz`x`l#?zX%NCFsdvR-<9+k0Y%c>K3e5==t}+gy@+csy!e<_M^|Mb<4)j& z=JWneD>lY$<5D1vR}P z@+b;*NofN4zCg{$S2X~)3)ee{hs@UEAdrRBB`)yX?r3r(84*xew{>$m4WB#Bf?FEg zJ~-N-RIbkMkgaO|3y{fxt=4t3eSLGS0p?wVp$u=~xqynY`v+1N^sN@b&#)%>Wk@1X6~hH${ihTwCTxSJ6M3`zyAB%TO`w zjzJK7%^(qPl4y+gX;tYQnRQwlL{fFS6qc)Aj}1x^Zio@u#|@;ruy{!P7*63fm83Tv zarn;@X?kLB5I~S8sm}-H!Pd%LGgm^;#Eqth0Pd*&6uCuOL%Tr)#ye#0e3iEhk|x4b zThW?ZCn<_wyd=c+{=?ILd2GSEl7ncE##PCxlFEPEl1X#X3QS9KxI*bQz_DHf6I>9@ z1+~JgS4OM9!oY~0!8}W311KMq?yQKc*F<$81Em*LEYI5adxqm&G;q0LCs0Jlaqf>{ zv5*-ll40`=Uc1S?G=AxmauXcpy3P7zJjQ`1K5237|BB}mE2Y*HI+;~P3@m6~jho+ZGq_P5!h z4a=d!Gn!b|Fe^c;QD+lQf<9 z<5J~qE?#}utCcN!)(dzdn68_vehB^pV0$TWD(A(PrWU5`j>o!M1_lUt!z*=TjthE6 zi-&`GENPO)#f}OUIjh?_!7=RI;jYB ziS>HUUv;*G05U7G)=$vh17e)w3>*gR0LW9?G>(2S?)ljw+7czX7bsWnxK%zQ6^Vn= zTG*fF14(Zgt!id*wT$G5P7eP__Jq-m%BZde!MFoBX(u=Pi-ye03hkYO0-!P4Jr zi8c+wMybcfsHqc=KK6axoshau;4)8a9C$l)*^z7%5E<<0L2O)iCRLJLb$ZRXZ71jO zDn6ki|c^RhkO4Fw#!ao|JRC^Xso+2WkwbuNB;w$^d%lO(cLF-_{P4RlazuHy`00F&9w9v0Yau zUHs{&=dq?V$<8|Kf(KObiol*1@!k}G2Npi=Cv zx@_a)o|joe8%|8Dsu~nQ}(|ng*Tj#vir_{nLro&kl%Xisnd@V2B z1~t|Z)~CN;w6JZNxfWpeCn!iuN&wEVbG6L zML*hf+^JpK;VX5%`$2Epjml|RmN)Lt7ZFb&-Lb!Dbm0M=0&OHv&87pBk4_1A|KZ48 zI-ehf)@m%z7I~GeJ-%L>;JYEtPQNa~klM1SWI(R{jQC)^Ic`<@(-UY`Xd-)QX(}j) z$?y=phsb>hgD8^F1ysxhRX%H#1&gqmLKEpyC6rQl^P0^!N(Y$g7z_6&X|?k90kXrX z9flG+{5sTPWN><$C&_!{M@dSk{e>iwjTUsPDeZ8LSzGErjd>uQ8Jp3S?>^C*kGHLsVur?O zkC{-lhCBtLt)f=*i{6713$p=q7nh;PzUlz6(EfCxL7?v&K`=dVSS zpOAlbFmVPDW$+qGeI2FcV6TZJ7b!scy44RA01RQeB0J=UGbH;le{L&?yCLFyWh|r1 z5c2jFdMl{tbX3i37Kwi((=Er0LVrOgeg=8l_y^QBJJx73$K_-m{1ym? z1C;mCZU5yhlq@j=*KacORq0iFPWLNk$NxcgukMOJZ%hJKM0p;^25R$?>y4I@*0Pj0 z5C*_xk-!DP&AXBBC+G{puK&$E7{a#S9U_QG8&}N=j=-=hK~f*zaYz&-kvA9%2dmLB z+|Mehm!JLIr-oLxWCZJK3D|BXVH1px+&8}z0+k8!kz@EN74{bh{q1Z3mS1#1@wN|j z5V*_H)W0BJI}j4Td|n*}g0(X$nl5OnMg?eVmgE8GBH}~kJw7F`oJ1tyGr|s&N0CsA zp&jRr?+_1wh1d4Y5DZ7nK+pcpqvOSC{JnQhrwN)1#$ZV1xslyY5rT@ew-F=&GwDh21#6?ilu5B+BiOz_4*)vi z7w;{fx28%Uwry!_NXq?rv`VSRGojcDKN7 z44p0JOH^c?_xu5flAKCc)~vAt!yJ=7{#8{*qXjCztH;y5w=z;9jIyO7qphmkSg%Wk z81`$21wCvzBki~4V{C0H0xp|M0-bt(F+UjDQv4(iQ4)mJuj+NV1`E-_X#>IH7X6Wb zR(JC)2g42nm-a6V6TFmnP!FwFtBY<=@b)fUuLaWz-?>mI@ zR61+>0|p!r-GbNhn7tKeBTcb33efCn1nYg(5TOEnPlO9*Qn;J7&#v7>H#m;5|A$qR zU}U@`hkutSuj(h>MWiCN0HWASEkE;g@P_Lk5&z`u5v$*EI~m=V0nE>>zi=f~D&&Z$ zx@|G!c!$fY6q;U#o}jw)IgF|q4>p4IP!o_G*{ZYNJ7WzsYjb^a{UYJ~9yB^MJ@v%U zygt@2-Ugn)dFz;1ad8XdViLhVqu8AAI034~M-F&4OV0egUKaEHf2Nl7MbD^!I(qd! zK)FzZVG`N)yv;N_97~&gAM5cpW4mUEstwQZI3yd_OqC+FSsyW^Zl$yTMNANlxvZwO zM1Q)Fqr`!T>iud21>(NGuhDeGs4?B8yRk)qe^p;MsMer%*=L}H^pfwoR+sXPf8Nm7nQ@7jGoYd!D%lxM~@uque#EQyval)uC%Xdm(TBBGhegwYZEQ`7Ec!F_BZ=% zV$BB!_>P$r2fQ0t@K;`S)W~0z#UnIufn9&F=GNB!c}(@p>L8nFjhJ{^oi(AWqG(xL zHK1(E^O)l7R)bsYS~vI5_^esIOXr#g=|t$x1@&m{gC#Xt0H7a#mp_~5sP9muL$i%k z--(A9XT>haWO`laWBZ>_M2)E{>M6p9%h!Vy*)mXslL#(PF3}tv#Oa9ch>`&6H~ARnWxkUKnVUY z&X3!Z9SY4R5cKfB#S(ugdSKv<{SV``Z7)KHYKO>z zL^eyLi}o{eKNKjIQFlulQRaWv-jE*W!z%zF{1fCXcZ;=4=Jp`KBp=i(qrrI?eroS( zN4}8)$eaV86BS~DAIf~wOK@+%9_3`A2~?ejcM2hCsX-0kBUB1?{PKrmcSO3C5xE^} zf$<$fAcnJc4ccu!Bta3OxQmpz>+l_{4&8;jhbM38q9{q1b-1n->b#h+Dgny@V^gdHpuJ@JTTWuH6E)9IF12@#{yo zYXy>h7Q2X_g{E0CfsEn0*3lKYMn+2k7C59t=|Wq-=bG8kc3V^YXP9IXNsnH>BMO@TQzRw9J^c9+l zy!3aMKS?@^3cjg5+KwfH886niOh9_APU^=$5?(#mlgic|yb*)wk&){@wKm=DY7I=| zLp}W(ib(dNNCx;x(X5o^1fmFJOo1XYacv(xcd3Eg4)Bx0<};*gKN}T1*ptp|F~d{4 zODjT9l6gYWxaB=emDmVrext`*;?hNv<0D}mr8c7rQo3JZyB+h@(ODE> z50&Sf0iGM+7W|9JQFDH77QfB;Y-*~xvQ!w=QPjuvHou2zA)`+E^$6I0 zZH1mS%R;BaAyNXQk}sM9H~{RcVA2MHt}=FsjO_qB00Z}+Yrlb_Uq$yDg%}WRUGPt6 znJBS)szavF*)%HCAfVe7B>*EiJWL+Un>d~nWXejS3Y~W;kUfMA{;P$xcvu=cSNk7y zdmCaq6pW-aWj+S(TQ*9>tQ_iwwBIZ}v@}9tXM_E8L(ss;UkxsB5z}@==vo=)zf>Qs z926O%J=VLn@=vyfP3(g)jxzZAOS8WXuy73Np)S-BHJki@eAozyk0?iW{mI_BCicKl z(3bf?NJ~6UlJS@;eOX=h*vNkkQvN8YIb*sg;B#Q{DmQ;AzT*Zw_m(`R%687h-~Q+G z^SS+3x%a&k&WDywL9VqlUguW^jFge}Hs#dPy}Z`DDBH;YtKWM|34g{a2_BoNfJCtr zoh%V!D#exG`iLtxjOT|H2$GoH%seV4vnhL=Nv09?wZbE$$ z__d}#5g)Va{O#sT!g^RrF>M(+gPS7@OrizDp>6IiW`*Iq1&VxvdA?<$7d4XSwpr3b zhFIG*d;8`Y+1A~GGRIG9R$35%J$xT&G*P6pf@ie)ww7qrw&{p@c}<^@@rOkAmem2w zT}(h@^%IuBZ82rQws~Tg?`S>8ITRRFfj)+l+20XmQBeEtN+izk{+*8{3&ybP-EQl> zpBm?RxxV zTGc(b91oo^Wxl%X$-k`U((*i)NY|kG`s)fKS^e{AjPi`6x)kda0q#@ho*>sA)&F<< zI6ptP-BVObsU-w5hndomR*j5hv3Lr;ez2>KdIpLbNR#lMPJF`!x}VLrf^g~*$_|u> zY>w*^W_TXMkes2_kJiHzN+Edae$e0ZGw3~eN?lRZ} z$p3KxQkpn6*l%)}Y})a`NCXFXO7X(JQ)rvwp!vMyN4O-K*pWj-s46VPbX?$xj;8%O z74dNaw-~+p0(IwR!c5RJmZim7==NrLR{hRFX7u%OIC+78>SV!NZ7!}CUrSbAo1Yo* z8d18i*P4GkMmo1RGd}!{qI90XXf}ttU-q5u5A0*2S@6Sut=7Wa(OiLUTM_C_v;`cd zijoarnlC{Hds+&&L$h`suxxzyvrmgNh-IcCL)fvKLf;grl_R0O4c;>a0U9(kGFn+8 zf}`>&Awok1zVScwc4;{tQj;I4lKIAGC-DAFK%^hrHT$D)M)8}$Bi=Cp>8TyU6Qs1_ z^fmLKuNc=wG2&VKMl8gvSbJ>nydM-0aUwmcBp~5Xb!3$M^|k02p`&u9nUjbH%b=nH zDxv9(rm0-g`1g$9TLlgUnh3y#L;>#=op->GgtNiQt`jcaCGA%whn={}J3@za5`gE| zu9>s<6fXn8Hf4%h-W2gS&M(FSW7q(t1azt<^3a;hk33q1uX3DvB-G}xn%(Y8#F0h0 zGATS}<4*icl^g-q))pB_PjnI<{aKlsHZ3>n7wf<_0O_Vt8IRPV94tdQ(Cba+Ek^i0 zZ|a5z%cIu-No05oiXur8V+2Z-m~JT^{IQK5P>N)7gZqN32F1FWX5tZsL%Eenfk`Y` z9fQdDDF7_oG}MBG_;Zy*Qbq~_0mMH@EtJ}5zt(F@`Vh}?w*e=BIZV~3-$A=9&Mh>w z_?jrMu|KjX<=dT)*uI`{ z)0pn2@XIJWcz1TK<#Wh2W+aZf?RdzM|3b1fWaiWwzNO!V~FI5`<&UuGYqIL+`fc8%e2DUrt9=Y>VVp@dXxS=W8HJ-_j zOEBk_7}&m?_o(={y<|Xy84EOoxsF)Fq5<607Q&y`Wi71toM0JaV#B``5M@vRAcvy* z0`Rg^08oDMuCVs0I$;F49p+`h_ZHMR*JTZK?RvO(qeVgm6iJH{dLVv_v_%K7yve1+ zWxti$wGwef;hgK65z?v5M)Pk}MnabF&-LXciXqwxp4;&s3_=~>E5HmRf{;C6c9v}a z@Bj_7;Jv%cBJZX^zObech45i8Tv@mp^;>#}&x%hm2?LYM>m%FCK@VWpSMEvp!+fSY zl`pApMC|?J;MWup)Gq2{Kk^n3wpHE+nz96M2p1*L_H@_CKsucQc+zF;H?%NvU)CJ| zBDXufzrC}}qH$kJd(8CI3UBDaYk!=If6__8l`r&vsCozXI=HA!IB1%rv28WB)!1&F zlQgz%yRmKCwsB&!v2D+JX1@2EYktGtd#!t|ePdO>gYu8+gO;k99nwxIEW1_QL8O^3 z1DqA=C{}3#{8sIAHGg}oxyna>XPXP`(WyU?Pl>8GHqEnE+uz1%*8&q*i`rJO;^6dAZc zkOgWTt7F}rikb5b&Q5fxv2W?r4r>hB?sGvTJGq>i4bE~qXbc9O6(DxqQVszr%5rH# zaPVrKp3-@2)2la_bYH}`Uy_>luG$|N?=N!7*99yDCBWW=wCArFvOht5RbN{R?1v79 zRq;=fY!3bY#L3FvbWY=+tAC5VwRn8si@=@<*Al5U3#MAg@S5xvJgJQbaO@`v#}Z0R zOpl5`i$1--eBJz6+;5+GyMB?7j*n+2rwCTqU3MmZC|iqv(%~NDzLtdak848JAmMlb}NUS%{|3)I~>LP*F1gZ#s|3YwE87OI7~!36sUA4Oi{N zG3s@QOzf=w((4SUvovluP~;*O{I{^h=DJA?#-aBzymHfo2=*7*%zFg1nkCBnt~`IG zrSMUFu+MuW-}&(iGz2I=D%gN}!U%_pj+WMI(0#ZdXMvj1x_FN-h;E!%L}&cp284YJ>16U2?W`-C zuDWux7*PH(nx`6pEn~;Bk(!=cSVAhPEp%Cn8fJO;gCBlzP(4!$ud(iI-M`m%;hW2G zfSMT#bht@Yd+PGfw8rq#6DC@vq4z^Gq*rkIzi)<`$C1n{WqT0Kl$WHDq{u*HACXGY zqAJ}mOG;mk%0*3Ws@Aw|tzRriwrzLsRk@S?{g3cxM`hF`wf zm_{+V7=M6jV8gGRGK)vUVxiiz4e|Z)r(6-?-V=d%^@~+RUxu|o7Cixe525ww1eh$G z4IoFGhIRhfl0uk-Zfsr0Q3hrA5jU_CC};U3mvLGw_t8{$*WP`16*AR>%PTnF;+x<8 ztfW41#hBxL)j#H%0fPEox7$RS$jAR3A2pb~=J@}2lut|8etq)gejwS{9qV>|h1yTf zKc>?(X{ta~?T1l`hlbl)iJMOn56lC*ybAn!8XM)pS`X2}6tTRawkl_f8bJv|Ewirpy#~1* z4}>ox$o{FF*z{c)ZfE%E77nf@dzU<)tNPK-Hd~Rr(zBAU3n^o_ zry8j&ls-e?9AnPvTqEN|GKvEkkoWmb2z2Yl=8W6+P6J>Z6DLqW->!Y~{8&i`-wYX0 z@Y^g%*23EwnRkDcVB(C*BLu|mz>5-^rwVaeE$6Bs^F{q(Er*uYvFzz}LWY?gyu>+t9Bm#V2#-_&GwN^X+UcC<@k3%vI~hi=U@ZhKHoc z%TNWpP;qV|`k|4@ROQlxJtC98Q_r;11SnT2HD0MQ-l6q8gI$y_ztg&PD8oM??^cXI zw+K2{Ux zkH7KAB;T8f<5nya6E{mCrgM!G^_tE1ARM6i6^>?~MX5+z7z51r!8c;Q08604p~5J*tln3LZUcUtGg8z-ukW4C zEM`ttMqb?e!+`fXW8dhXfPwNL^V3aWav3a3u`*qt zZ7v&7Q(XX$;pfeHP=1GvcH&)rcwnLLfbr8LoUA^8x6>XpgyZ_lrmNp_pGQqeJ>%yh zGb#mN3D+(vx>iaqcGtP9EcG)`6wGU&xJ!S2v)1BE|Gc~U>Q#FCp{V)}&iYO7x3%vj zsI*GlU1?8;!7TBb5~cEhPEd3Fk_b$Y&4q8hmB>)RYICbdSz&rCDFzOUo;j7C_0AMw zQ`wd+DX|*6F}}I*0&QurN~_Vxe0SX)F5>v#*^+JRhP$z}NpYpu;p$PmYum=GCX*>* z)%J(%!$c_Jyzr*wNOpB~aj=Se|7;%$s;9l$7+_@YafkXh5nuo8eMer zmkTXqEy*72?v#x>Rz)aMnLL&j%?>NC9_)|)!FRR^BE$^Zzh>dNx??=z{C96td{;+8B8#gt2YEl)4e)t8*O zcw+r(M^KRB|_p|%aNr8$_h!<=ur$4y`oN=v_1uOn+y_0I?YPRQBo}c$BB~#8O zhqL#r)fHUK8LxTH=$p63bibz49ZiiEbfJ1XlodGc9gY|w&PQoBnOx+07l8*m9*vI> zbhr=*mff>PEsv>`NDvCVSWKX;@1wsV5f<`N(0Z=rHq30wna0HtRND?w%BRboO{iB% zS8{tbUcRJbO^mA(cgm9pSRAb~lKmGwK$yv-!7NtuWuJlIyVmgl};pu7&H*@%V`gW% z`Q6*8U&`?mvZZw@S<+lD^Ci@7H$}xoHayBc7(6rRG8iNN5<-mmLbFoJbvw0X6+>?t zfSwa!JJ|z0JMm2%rQJg|f0Am<46Cn;5XplGu=}GiJ6#Tm;cun543g35q$m-h={*yE zV6K|H9m2{E*+F_sap^Wpt~0ED{h2D$7_?L&@##1!`00R6f-s$K!8eYASVpgyPR6%; z2nNF%bbeH@W=Ow+0LM(Yag^ojL5JL$^gT}@Go{e>?dnrkGXrT8#)_W>iPao~_nx4y zW|KMba_a@#lP9vm;H9{RFYcc>Qg;`A!qYp?yNs*$~$C$1}Tx%3UaW778 zrMOB_sU*;XSPK&qgU5FsoIrPfu?`p+99#4dVDSL6V|dxe_K@+7p+BsHy2#zAou9el zxUK*fLBDjulaR~M6rY#`SRX&7*}haY8vdsKG&+!$92Ur^UM}x2U-Gd&{?uB3Kmsf~ zdmp8|Ml-Ud2&(9P7M}I{HfMeO+f94YlJ9b){6Edn@CnE7>hbD{pvr8Pv|+J1-^v&y zaFXDhyXxV!@w#s^h4m}rpLcLLh6(&T zm9$}^mGI76_S(iTcQi#IaJlv|xq67H>C?3X#Cjr<^jh>OdaI+?Mk8vm+7wTT^;&FW zHJR%>n#|xV$6@Mkr)I+sIv40FP2F2N&!eRMD0RX5kY=gR zG5O8U)4JtQ!se56?h`gLJjJC2!q}H;RxE@>A#7ZnRh8KnPpz#?Ff{XnOD^tS8XKloYRv_$qXj{HHE!5 z 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 literal 0 HcmV?d00001 From c8610cabc28e3423facb46aee955030a0554c94e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 31 Aug 2026 13:22:48 +0000 Subject: [PATCH 10/10] chore: bump version to v2.1.0 Update CHANGELOG, plugin, client, vscode, and chorus-relay versions. Release notes cover VS Code adapter, @chorus/client extraction, and cross-adapter e2e. Co-authored-by: Steven Roomberg --- CHANGELOG.md | 28 ++++++++++++++++++++++------ Cargo.lock | 2 +- crates/chorus-relay/Cargo.toml | 2 +- docs/STATUS.md | 2 +- packages/client/package.json | 2 +- packages/plugin/package.json | 2 +- packages/vscode/package.json | 2 +- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dce10f..13300f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,28 @@ ## Unreleased -- VS Code extension (`packages/vscode`) — share/join/chat over the same relay protocol; Session sidebar + commands -- Extract `@chorus/client` (`JoinClient` + `RelayServer`) shared by OpenCode plugin, VS Code, and future adapters -- Cross-adapter relay e2e: VS Code host ↔ terminal joiner and terminal host ↔ VS Code joiner (`bun run test:vscode-relay-e2e`) -- Docs: README, STATUS, VS Code adapter README updated for relay-first cross-adapter model -- Session access control: host approval, required display names, repo/email/domain gates (`session.policy` / `auth.pending` / `host.approve|deny`) -- Hybrid OpenCode security e2e, VS Code adapter e2e, and Cloud Agent install script +## v2.1.0 — 2026-08-31 + +VS Code adapter and shared client extraction on top of the v2.0.0 relay. The relay remains the core; OpenCode and VS Code are thin adapters on the same `/host` + `/ws` protocol. + +GitHub tag `v2.1.0` is the source of truth for this release. `@chorus/plugin` remains install-from-git (packages are private). Rebuild `chorus-relay` from this tag when upgrading from v2.0.0. + +### VS Code adapter + +- New extension (`packages/vscode`) — share/join/chat, Session sidebar, approve/deny joiners +- Session access control matches OpenCode: required display name, host approval, optional email/repo gates +- Cross-adapter relay: VS Code can host for terminal joiners or join a terminal host + +### Shared client + +- Extract `@chorus/client` (`JoinClient` + `RelayServer`) used by OpenCode plugin and VS Code +- OpenCode plugin re-exports from `@chorus/client` (includes v2.0.0 network options: CIDR allowlists, async `stop()`) + +### Tests & docs + +- `bun run test:vscode-e2e` — email gate, pending approve, `collab.input` +- `bun run test:vscode-relay-e2e` — three-env gate + VS Code ↔ terminal cross-adapter +- README, STATUS, DECISIONS, and `packages/vscode/README.md` updated ## v2.0.0 — 2026-08-21 diff --git a/Cargo.lock b/Cargo.lock index 6926b20..2500e5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,7 +157,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chorus-relay" -version = "2.0.0" +version = "2.1.0" dependencies = [ "axum", "clap", diff --git a/crates/chorus-relay/Cargo.toml b/crates/chorus-relay/Cargo.toml index 5edfe31..38cd9ce 100644 --- a/crates/chorus-relay/Cargo.toml +++ b/crates/chorus-relay/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-relay" -version = "2.0.0" +version = "2.1.0" edition.workspace = true license.workspace = true authors.workspace = true diff --git a/docs/STATUS.md b/docs/STATUS.md index f79917d..ca0a71d 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,6 +1,6 @@ # Chorus status — what still needs to happen -Snapshot as of 2026-08-31 (post VS Code adapter rebase onto `v2.0.0`). Tests/typecheck/build are green. +Snapshot as of 2026-08-31 (`v2.1.0` — VS Code adapter + `@chorus/client`). Tests/typecheck/build are green. ## Current state diff --git a/packages/client/package.json b/packages/client/package.json index cfb9fb2..700c7a3 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@chorus/client", - "version": "0.1.0", + "version": "2.1.0", "private": true, "type": "module", "main": "./dist/index.js", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index a244815..df790a0 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@chorus/plugin", - "version": "2.0.0", + "version": "2.1.0", "description": "OpenCode plugin for collaborative session sharing via chorus-relay.", "private": true, "license": "MIT", diff --git a/packages/vscode/package.json b/packages/vscode/package.json index 7acd3d9..bfb3cfe 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -2,7 +2,7 @@ "name": "chorus", "displayName": "Chorus", "description": "Pair-program a live Chorus AI session from VS Code — share or join over chorus-relay.", - "version": "0.1.0", + "version": "2.1.0", "publisher": "chorus", "private": true, "license": "MIT",