diff --git a/apps/server/src/bin.test.ts b/apps/server/src/bin.test.ts index 5a3f77d19..1964ab94a 100644 --- a/apps/server/src/bin.test.ts +++ b/apps/server/src/bin.test.ts @@ -67,6 +67,7 @@ const makeCliTestServerConfig = (baseDir: string) => mode: "web", port: 0, host: "127.0.0.1", + advertisedHost: undefined, cwd: process.cwd(), baseDir, ...derivedPaths, diff --git a/apps/server/src/cli/config.ts b/apps/server/src/cli/config.ts index ea7aa12e9..3d6e58ec4 100644 --- a/apps/server/src/cli/config.ts +++ b/apps/server/src/cli/config.ts @@ -200,6 +200,13 @@ const EnvServerConfig = Config.all({ Config.string("BADCODE_HOST"), Config.string("T3CODE_HOST"), ), + // The hostname startup URLs advertise, when the bind address is not the + // reachable one -- a container binds 0.0.0.0 and its interfaces are + // internal, so only the operator knows the address clients can reach. + advertisedHost: Config.string("THREADLINES_ADVERTISED_HOST").pipe( + Config.option, + Config.map(Option.getOrUndefined), + ), threadlinesHome: aliasedConfigOption( Config.string("THREADLINES_HOME"), Config.string("BADCODE_HOME"), @@ -485,6 +492,7 @@ export const resolveServerConfig = ( ...derivedPaths, serverTracePath, host, + advertisedHost: env.advertisedHost, staticDir, devUrl, noBrowser, diff --git a/apps/server/src/cli/marketingStudioSeed.ts b/apps/server/src/cli/marketingStudioSeed.ts index aa8c9266c..1aa2386f1 100644 --- a/apps/server/src/cli/marketingStudioSeed.ts +++ b/apps/server/src/cli/marketingStudioSeed.ts @@ -144,6 +144,7 @@ const makeServerConfig = (input: MarketingStudioSeedInput): ServerConfigShape => mode: "desktop", port: 0, host: undefined, + advertisedHost: undefined, cwd: input.cwd, baseDir: input.baseDir, staticDir: undefined, diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index cc793ac28..77e8c8caa 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -63,6 +63,12 @@ export interface ServerConfigShape extends ServerDerivedPaths { readonly mode: RuntimeMode; readonly port: number; readonly host: string | undefined; + /** + * The hostname startup URLs advertise when the bind address is not the + * reachable one. A container binds 0.0.0.0 and its interfaces are internal, + * so only the operator knows what clients can actually reach. + */ + readonly advertisedHost: string | undefined; readonly cwd: string; readonly baseDir: string; readonly staticDir: string | undefined; @@ -194,6 +200,7 @@ export class ServerConfig extends Context.Service Devices). + +ARG THREADLINES_VERSION=latest + +# node-pty compiles natively on install, so the install happens in a stage +# with a toolchain and only the result ships. +FROM node:22-bookworm AS build +ARG THREADLINES_VERSION +RUN npm install -g --prefix /opt/threadlines "@threadlines/server@${THREADLINES_VERSION}" + +FROM node:22-bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + git \ + openssh-client \ + tini \ + && rm -rf /var/lib/apt/lists/* + +# The coding agent CLIs the server orchestrates. Their credentials land in +# the home volume, so sign-ins survive container replacement. +RUN npm install -g @anthropic-ai/claude-code @openai/codex + +COPY --from=build /opt/threadlines /opt/threadlines +RUN ln -s /opt/threadlines/bin/threadlines /usr/local/bin/threadlines + +# Reuse uid/gid 1000 (the image's `node` user) so named volumes and typical +# bind mounts agree on ownership. +RUN userdel -r node \ + && useradd --create-home --uid 1000 --user-group threadlines \ + && mkdir -p /workspace \ + && chown threadlines:threadlines /workspace + +USER threadlines +WORKDIR /workspace + +# Bind-mounted repos rarely share the container user's uid; without this git +# refuses them as "dubious ownership". /workspace is the operator's own code. +RUN git config --global safe.directory "*" + +ENV THREADLINES_HOME=/home/threadlines/.threadlines \ + THREADLINES_HOST=0.0.0.0 \ + THREADLINES_PORT=3773 \ + THREADLINES_NO_BROWSER=1 \ + # A service must not mint a project from its own working directory the way + # a `npx` launch does; operators add projects from /workspace deliberately. + THREADLINES_AUTO_BOOTSTRAP_PROJECT_FROM_CWD=false + +EXPOSE 3773 + +# Agent sessions spawn deep process trees; tini reaps what they leave behind. +ENTRYPOINT ["tini", "--", "threadlines"] + +HEALTHCHECK --interval=30s --timeout=5s --start-period=30s \ + CMD curl -fsS "http://127.0.0.1:${THREADLINES_PORT}/api/auth/session" || exit 1 diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..7927d0196 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,91 @@ +# Threadlines on a server + +Run Threadlines on a machine that is always on: a VPS, a home server, or a +spare computer. Your coding agents keep working when your laptop is closed, +and your phone or any browser connects to them from anywhere. + +## Quick start + +```bash +docker run -d --name threadlines --restart unless-stopped \ + -p 3773:3773 \ + -v threadlines-home:/home/threadlines \ + -v /path/to/your/repos:/workspace \ + ghcr.io/threadlines/threadlines:latest +``` + +Then: + +```bash +docker logs threadlines +``` + +The log prints a one-time link. Open it in a browser to unlock the web app. +From there, Settings -> Devices mints QR codes for pairing your phone. + +That is the whole install. + +## What the pieces mean + +- `--restart unless-stopped` makes Docker bring Threadlines back after a + crash or a server reboot. Nothing to babysit. +- `threadlines-home` is a named volume holding everything that must survive: + your threads, settings, device pairings, and the Claude/Codex sign-ins. + Containers are disposable; this volume is not. +- `/workspace` is where your repositories live. Mount the folder that holds + them and add projects from `/workspace/...` inside the app. +- Port `3773` serves both the web app and the phone connection. + +If clients will reach the server at a known address, tell startup links about +it with `-e THREADLINES_ADVERTISED_HOST=your-server.example.com` so the URL +in `docker logs` is directly clickable. + +## Signing in to the agents + +The Claude Code and Codex CLIs ship inside the image. Sign in once from the +web app (Settings -> Providers); the credentials land in the home volume and +survive container updates. For Claude on a headless server, the +"Advanced: headless chat token" flow in provider settings avoids needing a +browser on the server itself. + +## Updating + +```bash +docker pull ghcr.io/threadlines/threadlines:latest +docker rm -f threadlines +# re-run the same docker run command +``` + +Your data lives in the volume, so this is safe. Pin a version tag +(for example `ghcr.io/threadlines/threadlines:0.3.3`) if you prefer +updates on your own schedule. + +## Reaching it from outside your network + +The safest defaults, in order of effort: + +- **Tailscale or a VPN**: install it on the server and your devices, then use + the server's private address. Nothing is exposed to the internet. +- **A reverse proxy with HTTPS** (Caddy, nginx, Traefik) in front of port + 3773, if you want a public address. Threadlines requires pairing before any + data is served, but public endpoints deserve TLS. + +Avoid exposing port 3773 to the open internet without one of the above. + +## docker-compose + +```yaml +services: + threadlines: + image: ghcr.io/threadlines/threadlines:latest + container_name: threadlines + restart: unless-stopped + ports: + - "3773:3773" + volumes: + - threadlines-home:/home/threadlines + - /path/to/your/repos:/workspace + +volumes: + threadlines-home: +``` diff --git a/patches/effect@4.0.0-beta.98.patch b/patches/effect@4.0.0-beta.98.patch index eb393cfd7..ca73f53b6 100644 --- a/patches/effect@4.0.0-beta.98.patch +++ b/patches/effect@4.0.0-beta.98.patch @@ -1,3 +1,19 @@ +diff --git a/dist/PubSub.js b/dist/PubSub.js +index 5f294e781fcedc57902bf53d20cab83184fe358b..72d3b1f36b84e54a22321ab756401ad144e7c62b 100644 +--- a/dist/PubSub.js ++++ b/dist/PubSub.js +@@ -2049,6 +2049,11 @@ const strategyCompletePollersUnsafe = (strategy, pubsub, subscribers, subscripti + let keepPolling = true; + while (keepPolling && !subscription.isEmpty()) { + const poller = MutableList.take(pollers); ++ // An interrupted poller leaves an undefined hole in the list; completing ++ // it would dereference undefined. Skip holes and keep draining. ++ if (poller === undefined || poller === null) { ++ continue; ++ } + if (poller === MutableList.Empty) { + removeSubscribers(subscribers, subscription, pollers); + if (pollers.length === 0) { diff --git a/dist/unstable/rpc/RpcClient.d.ts b/dist/unstable/rpc/RpcClient.d.ts index a70061a638faabdd663eca25cb79585fec06e03c..1af40759e2d51d1c1d2da86bd00a43fc71cfff3a 100644 --- a/dist/unstable/rpc/RpcClient.d.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7cb03180..0168536b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,7 +78,7 @@ patchedDependencies: hash: 954a7d16cd35f4b31756829c2e8a16c3f3fe0b89d8d69fbfe8d79b9a322f8275 path: patches/brace-expansion@5.0.9.patch effect@4.0.0-beta.98: - hash: 181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2 + hash: d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933 path: patches/effect@4.0.0-beta.98.patch lexical@0.47.0: hash: 4b8dd229acb72970dcf7536933ce8ac8689aeec7d653398adddb203d56f71780 @@ -111,7 +111,7 @@ importers: dependencies: '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@threadlines/contracts': specifier: workspace:* version: link:../../packages/contracts @@ -126,7 +126,7 @@ importers: version: link:../../packages/tailscale effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) electron: specifier: 43.1.0 version: 43.1.0 @@ -136,7 +136,7 @@ importers: devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -216,16 +216,16 @@ importers: version: 0.115.0(zod@4.4.3) '@effect/platform-bun': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=9fc1610289fc4eec0a69d930d8a359b7a4b1055920b831ba4bf91223be7a0e04)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) + version: 4.0.0-beta.98(patch_hash=9fc1610289fc4eec0a69d930d8a359b7a4b1055920b831ba4bf91223be7a0e04)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@effect/platform-node-shared': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) + version: 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) '@effect/sql-sqlite-bun': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) '@opencode-ai/sdk': specifier: ^1.18.15 version: 1.18.15 @@ -234,14 +234,14 @@ importers: version: 1.3.0-beta.9(@shikijs/themes@4.4.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) node-pty: specifier: ^1.1.0 version: 1.1.0 devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@threadlines/contracts': specifier: workspace:* version: link:../../packages/contracts @@ -298,7 +298,7 @@ importers: version: 3.2.2(react@19.2.8) '@effect/atom-react': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(react@19.2.8)(scheduler@0.27.0) + version: 4.0.0-beta.98(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(react@19.2.8)(scheduler@0.27.0) '@fontsource-variable/cascadia-mono': specifier: ^5.3.0 version: 5.3.0 @@ -343,7 +343,7 @@ importers: version: 0.7.1 effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) lexical: specifier: ^0.47.0 version: 0.47.0(patch_hash=4b8dd229acb72970dcf7536933ce8ac8689aeec7d653398adddb203d56f71780)(typescript@7.0.2) @@ -425,20 +425,20 @@ importers: dependencies: '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@oxlint/plugins': specifier: ^1.77.0 version: 1.77.0 effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) oxlint: specifier: ^1.77.0 - version: 1.77.0(vite-plus@0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0)) + version: 1.77.0(oxlint-tsgolint@0.24.0)(vite-plus@0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0)) typescript: specifier: 'catalog:' version: 7.0.2 @@ -462,7 +462,7 @@ importers: version: link:../shared effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: typescript: specifier: 'catalog:' @@ -481,11 +481,11 @@ importers: dependencies: effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) typescript: specifier: 'catalog:' version: 7.0.2 @@ -503,17 +503,17 @@ importers: dependencies: effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/openapi-generator': specifier: 'catalog:' - version: 4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) + version: 4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -534,17 +534,17 @@ importers: dependencies: effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/openapi-generator': specifier: 'catalog:' - version: 4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) + version: 4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -568,17 +568,17 @@ importers: version: link:../contracts effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) yaml: specifier: ^2.9.0 version: 2.9.0 devDependencies: '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -605,14 +605,14 @@ importers: version: link:../shared effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -633,14 +633,14 @@ importers: dependencies: '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) '@types/node': specifier: ^24.10.13 version: 24.13.3 @@ -667,7 +667,7 @@ importers: version: 0.115.0(zod@4.4.3) '@effect/platform-node': specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) + version: 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) '@github/copilot-sdk': specifier: 'catalog:' version: 1.0.9 @@ -679,14 +679,14 @@ importers: version: link:../packages/shared effect: specifier: 4.0.0-beta.98 - version: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + version: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) yaml: specifier: ^2.9.0 version: 2.9.0 devDependencies: '@effect/vitest': specifier: 4.0.0-beta.97 - version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10) + version: 4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10) typescript: specifier: 'catalog:' version: 7.0.2 @@ -6874,41 +6874,41 @@ snapshots: react: 19.2.8 tslib: 2.8.1 - '@effect/atom-react@4.0.0-beta.98(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(react@19.2.8)(scheduler@0.27.0)': + '@effect/atom-react@4.0.0-beta.98(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(react@19.2.8)(scheduler@0.27.0)': dependencies: - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) react: 19.2.8 scheduler: 0.27.0 - '@effect/openapi-generator@4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))': + '@effect/openapi-generator@4.0.0-beta.98(@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1))(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))': dependencies: - '@effect/platform-node': 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1) - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + '@effect/platform-node': 4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) swagger2openapi: 7.0.8 transitivePeerDependencies: - encoding - '@effect/platform-bun@4.0.0-beta.98(patch_hash=9fc1610289fc4eec0a69d930d8a359b7a4b1055920b831ba4bf91223be7a0e04)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))': + '@effect/platform-bun@4.0.0-beta.98(patch_hash=9fc1610289fc4eec0a69d930d8a359b7a4b1055920b831ba4bf91223be7a0e04)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))': dependencies: - '@effect/platform-node-shared': 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + '@effect/platform-node-shared': 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform-node-shared@4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))': + '@effect/platform-node-shared@4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))': dependencies: '@types/ws': 8.18.1 - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) ws: 8.21.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(ioredis@5.11.1)': + '@effect/platform-node@4.0.0-beta.98(patch_hash=0e9f397f8e2ec9aef8e8d4f212b219732c48e5980d32035adad5764f3c56dc19)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(ioredis@5.11.1)': dependencies: - '@effect/platform-node-shared': 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2)) - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + '@effect/platform-node-shared': 4.0.0-beta.98(patch_hash=32a956569b355a7617af71fb5384e5ad2e40a302999506093492facea434779c)(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933)) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) ioredis: 5.11.1 mime: 4.1.0 undici: 8.10.0 @@ -6916,9 +6916,9 @@ snapshots: - bufferutil - utf-8-validate - '@effect/sql-sqlite-bun@4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))': + '@effect/sql-sqlite-bun@4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))': dependencies: - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) '@effect/tsgo-darwin-arm64@0.13.2': optional: true @@ -6951,9 +6951,9 @@ snapshots: '@effect/tsgo-win32-arm64': 0.13.2 '@effect/tsgo-win32-x64': 0.13.2 - '@effect/vitest@4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2))(vitest@4.1.10)': + '@effect/vitest@4.0.0-beta.97(effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933))(vitest@4.1.10)': dependencies: - effect: 4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2) + effect: 4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933) vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(@vitest/browser-preview@4.1.10)(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2)) '@electron-internal/extract-zip@1.0.4': {} @@ -9556,7 +9556,7 @@ snapshots: ee-first@1.1.1: {} - effect@4.0.0-beta.98(patch_hash=181986b14edb53e2f3c82527e8e5a9f7675db32427ed6940ee3da64e2f5968e2): + effect@4.0.0-beta.98(patch_hash=d3f9d7cfbb82a1137d9f5034d2d491aebcfb6386c6e26886eada7c5671c4d933): dependencies: '@standard-schema/spec': 1.1.0 fast-check: 4.9.0 @@ -11163,7 +11163,7 @@ snapshots: oxlint-tsgolint: 0.24.0 vite-plus: 0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0) - oxlint@1.77.0(vite-plus@0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0)): + oxlint@1.77.0(oxlint-tsgolint@0.24.0)(vite-plus@0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.77.0 '@oxlint/binding-android-arm64': 1.77.0 @@ -11184,6 +11184,7 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.77.0 '@oxlint/binding-win32-ia32-msvc': 1.77.0 '@oxlint/binding-win32-x64-msvc': 1.77.0 + oxlint-tsgolint: 0.24.0 vite-plus: 0.2.4(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(typescript@7.0.2)(yaml@2.9.0))(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(playwright@1.62.1)(vitest@4.1.10))(esbuild@0.28.2)(jiti@2.7.0)(msw@2.15.0(@types/node@24.13.3)(typescript@7.0.2))(typescript@7.0.2)(yaml@2.9.0) p-cancelable@2.1.1: {}