openfork 1.17.14 → 1.17.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +131 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/opencode +199 -0
- package/bunfig.toml +7 -0
- package/git +0 -0
- package/migration/20260511173437_session-metadata/migration.sql +1 -0
- package/migration/20260511173437_session-metadata/snapshot.json +1500 -0
- package/package.json +155 -17
- package/parsers-config.ts +1 -0
- package/script/bench-search.ts +94 -0
- package/script/bench-test-suite.ts +52 -0
- package/script/build.ts +243 -0
- package/script/generate.ts +14 -0
- package/script/httpapi-exercise.ts +1 -0
- package/{postinstall.mjs → script/postinstall.mjs} +0 -0
- package/script/profile-test-files.ts +42 -0
- package/script/publish.ts +82 -0
- package/script/run-workspace-server +106 -0
- package/script/schema.ts +77 -0
- package/script/time.ts +6 -0
- package/script/trace-imports.ts +153 -0
- package/specs/effect/error-boundaries-plan.md +235 -0
- package/specs/effect/errors.md +207 -0
- package/specs/effect/facades.md +218 -0
- package/specs/effect/guide.md +247 -0
- package/specs/effect/instance-context.md +13 -0
- package/specs/effect/loose-ends.md +30 -0
- package/specs/effect/migration.md +62 -0
- package/specs/effect/routes.md +61 -0
- package/specs/effect/schema.md +88 -0
- package/specs/effect/server-package.md +58 -0
- package/specs/effect/todo.md +241 -0
- package/specs/effect/tools.md +88 -0
- package/specs/openapi-translation-cleanup.md +204 -0
- package/specs/tui-plugins.md +544 -0
- package/specs/v2/api.ts +67 -0
- package/specs/v2/message-shape.md +136 -0
- package/specs/v2/notifications.md +13 -0
- package/specs/v2/tui-command-shim.md +67 -0
- package/src/account/account.ts +461 -0
- package/src/account/repo.ts +171 -0
- package/src/account/schema.ts +99 -0
- package/src/account/url.ts +8 -0
- package/src/acp/agent.ts +95 -0
- package/src/acp/config-option.ts +203 -0
- package/src/acp/content.ts +269 -0
- package/src/acp/directory.ts +212 -0
- package/src/acp/error.ts +97 -0
- package/src/acp/event.ts +342 -0
- package/src/acp/permission.ts +254 -0
- package/src/acp/profile.ts +42 -0
- package/src/acp/service.ts +1097 -0
- package/src/acp/session.ts +232 -0
- package/src/acp/tool.ts +364 -0
- package/src/acp/usage.ts +239 -0
- package/src/agent/agent.ts +498 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +9 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/goal.txt +36 -0
- package/src/agent/prompt/review.txt +31 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/agent/subagent-permissions.ts +27 -0
- package/src/audio.d.ts +14 -0
- package/src/auth/index.ts +97 -0
- package/src/background/job.ts +37 -0
- package/src/bus/global.ts +22 -0
- package/src/cli/bootstrap.ts +11 -0
- package/src/cli/cmd/account.ts +264 -0
- package/src/cli/cmd/acp.ts +73 -0
- package/src/cli/cmd/agent.ts +259 -0
- package/src/cli/cmd/attach.ts +148 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/db.ts +62 -0
- package/src/cli/cmd/debug/agent.handler.ts +193 -0
- package/src/cli/cmd/debug/agent.ts +27 -0
- package/src/cli/cmd/debug/config.ts +14 -0
- package/src/cli/cmd/debug/file.ts +73 -0
- package/src/cli/cmd/debug/index.ts +87 -0
- package/src/cli/cmd/debug/lsp.ts +50 -0
- package/src/cli/cmd/debug/ripgrep.ts +79 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +15 -0
- package/src/cli/cmd/debug/snapshot.ts +50 -0
- package/src/cli/cmd/debug/startup.ts +11 -0
- package/src/cli/cmd/debug/v2.ts +42 -0
- package/src/cli/cmd/export.ts +292 -0
- package/src/cli/cmd/generate.ts +54 -0
- package/src/cli/cmd/github.handler.ts +1593 -0
- package/src/cli/cmd/github.shared.ts +30 -0
- package/src/cli/cmd/github.ts +42 -0
- package/src/cli/cmd/import.ts +224 -0
- package/src/cli/cmd/mcp.ts +840 -0
- package/src/cli/cmd/models.ts +66 -0
- package/src/cli/cmd/plug.ts +230 -0
- package/src/cli/cmd/pr.ts +115 -0
- package/src/cli/cmd/prompt-display.ts +1 -0
- package/src/cli/cmd/providers.ts +534 -0
- package/src/cli/cmd/run/demo.ts +1274 -0
- package/src/cli/cmd/run/entry.body.ts +205 -0
- package/src/cli/cmd/run/footer.command.tsx +1064 -0
- package/src/cli/cmd/run/footer.menu.tsx +351 -0
- package/src/cli/cmd/run/footer.permission.tsx +472 -0
- package/src/cli/cmd/run/footer.prompt.tsx +1306 -0
- package/src/cli/cmd/run/footer.question.tsx +573 -0
- package/src/cli/cmd/run/footer.subagent.tsx +175 -0
- package/src/cli/cmd/run/footer.ts +1129 -0
- package/src/cli/cmd/run/footer.view.tsx +945 -0
- package/src/cli/cmd/run/footer.width.ts +27 -0
- package/src/cli/cmd/run/permission.shared.ts +256 -0
- package/src/cli/cmd/run/prompt.editor.ts +157 -0
- package/src/cli/cmd/run/prompt.shared.ts +153 -0
- package/src/cli/cmd/run/question.shared.ts +340 -0
- package/src/cli/cmd/run/runtime.boot.ts +202 -0
- package/src/cli/cmd/run/runtime.lifecycle.ts +406 -0
- package/src/cli/cmd/run/runtime.queue.ts +349 -0
- package/src/cli/cmd/run/runtime.shared.ts +17 -0
- package/src/cli/cmd/run/runtime.stdin.ts +37 -0
- package/src/cli/cmd/run/runtime.ts +814 -0
- package/src/cli/cmd/run/scrollback.shared.ts +92 -0
- package/src/cli/cmd/run/scrollback.surface.ts +431 -0
- package/src/cli/cmd/run/scrollback.writer.tsx +352 -0
- package/src/cli/cmd/run/session-data.ts +1113 -0
- package/src/cli/cmd/run/session-replay.ts +374 -0
- package/src/cli/cmd/run/session.shared.ts +196 -0
- package/src/cli/cmd/run/splash.ts +280 -0
- package/src/cli/cmd/run/stream.transport.ts +1462 -0
- package/src/cli/cmd/run/stream.ts +175 -0
- package/src/cli/cmd/run/subagent-data.ts +876 -0
- package/src/cli/cmd/run/theme.ts +690 -0
- package/src/cli/cmd/run/tool.ts +1953 -0
- package/src/cli/cmd/run/trace.ts +94 -0
- package/src/cli/cmd/run/turn-summary.ts +47 -0
- package/src/cli/cmd/run/types.ts +350 -0
- package/src/cli/cmd/run/variant.shared.ts +216 -0
- package/src/cli/cmd/run.ts +1011 -0
- package/src/cli/cmd/serve.ts +24 -0
- package/src/cli/cmd/session.ts +147 -0
- package/src/cli/cmd/stats.ts +393 -0
- package/src/cli/cmd/tui.ts +305 -0
- package/src/cli/cmd/uninstall.ts +353 -0
- package/src/cli/cmd/upgrade.ts +74 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/effect/prompt.ts +37 -0
- package/src/cli/effect-cmd.ts +96 -0
- package/src/cli/error.ts +130 -0
- package/src/cli/heap.ts +45 -0
- package/src/cli/logo.ts +1 -0
- package/src/cli/network.ts +80 -0
- package/src/cli/tui/layer.ts +8 -0
- package/src/cli/tui/validate-session.ts +29 -0
- package/src/cli/tui/worker.ts +80 -0
- package/src/cli/ui.ts +132 -0
- package/src/cli/upgrade.ts +53 -0
- package/src/command/index.ts +177 -0
- package/src/command/template/initialize.txt +66 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/agent.ts +59 -0
- package/src/config/command.ts +39 -0
- package/src/config/config.ts +680 -0
- package/src/config/entry-name.ts +19 -0
- package/src/config/managed.ts +69 -0
- package/src/config/markdown.ts +36 -0
- package/src/config/parse.ts +79 -0
- package/src/config/paths.ts +45 -0
- package/src/config/plugin.ts +79 -0
- package/src/config/tui-cwd.ts +5 -0
- package/src/config/tui-host-attention.ts +21 -0
- package/src/config/tui-migrate.ts +132 -0
- package/src/config/tui.ts +276 -0
- package/src/config/variable.ts +91 -0
- package/src/control-plane/adapters/index.ts +41 -0
- package/src/control-plane/adapters/worktree.ts +96 -0
- package/src/control-plane/dev/README.md +19 -0
- package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
- package/src/control-plane/types.ts +59 -0
- package/src/control-plane/util.ts +39 -0
- package/src/control-plane/workspace-adapter-runtime.ts +51 -0
- package/src/control-plane/workspace-context.ts +26 -0
- package/src/control-plane/workspace.ts +964 -0
- package/src/effect/app-node-builder-v1.ts +12 -0
- package/src/effect/app-runtime.ts +135 -0
- package/src/effect/bootstrap-runtime.ts +19 -0
- package/src/effect/bridge.ts +84 -0
- package/src/effect/config-service.ts +67 -0
- package/src/effect/instance-ref.ts +11 -0
- package/src/effect/instance-registry.ts +12 -0
- package/src/effect/instance-state.ts +69 -0
- package/src/effect/promise.ts +17 -0
- package/src/effect/run-service.ts +47 -0
- package/src/effect/runner.ts +217 -0
- package/src/effect/runtime-flags.ts +78 -0
- package/src/env/index.ts +41 -0
- package/src/event-manifest.ts +3 -0
- package/src/event-v2-bridge.ts +71 -0
- package/src/format/formatter.ts +404 -0
- package/src/format/index.ts +203 -0
- package/src/git/index.ts +348 -0
- package/src/id/id.ts +80 -0
- package/src/ide/index.ts +54 -0
- package/src/image/image.ts +172 -0
- package/src/index.ts +142 -0
- package/src/installation/index.ts +336 -0
- package/src/lsp/client.ts +650 -0
- package/src/lsp/diagnostic.ts +29 -0
- package/src/lsp/language.ts +121 -0
- package/src/lsp/launch.ts +21 -0
- package/src/lsp/lsp.ts +507 -0
- package/src/lsp/server.ts +1983 -0
- package/src/markdown.d.ts +4 -0
- package/src/mcp/auth.ts +163 -0
- package/src/mcp/catalog.ts +170 -0
- package/src/mcp/index.ts +1018 -0
- package/src/mcp/oauth-callback.ts +194 -0
- package/src/mcp/oauth-provider.ts +259 -0
- package/src/node.ts +4 -0
- package/src/patch/index.ts +686 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/evaluate.ts +1 -0
- package/src/permission/index.ts +223 -0
- package/src/plugin/azure.ts +26 -0
- package/src/plugin/cloudflare.ts +76 -0
- package/src/plugin/digitalocean.ts +325 -0
- package/src/plugin/github-copilot/copilot.ts +414 -0
- package/src/plugin/github-copilot/models.ts +258 -0
- package/src/plugin/index.ts +314 -0
- package/src/plugin/install.ts +439 -0
- package/src/plugin/loader.ts +237 -0
- package/src/plugin/meta.ts +188 -0
- package/src/plugin/openai/README.md +31 -0
- package/src/plugin/openai/codex.ts +556 -0
- package/src/plugin/openai/ws-pool.ts +270 -0
- package/src/plugin/openai/ws.ts +381 -0
- package/src/plugin/pty-environment.ts +24 -0
- package/src/plugin/shared.ts +323 -0
- package/src/plugin/snowflake-cortex.ts +507 -0
- package/src/plugin/tui/internal.ts +10 -0
- package/src/plugin/tui/runtime.ts +1131 -0
- package/src/plugin/xai.ts +626 -0
- package/src/project/bootstrap-service.ts +9 -0
- package/src/project/bootstrap.ts +58 -0
- package/src/project/instance-context.ts +24 -0
- package/src/project/instance-runtime.ts +16 -0
- package/src/project/instance-store.ts +213 -0
- package/src/project/project.ts +483 -0
- package/src/project/vcs.ts +423 -0
- package/src/provider/auth.ts +229 -0
- package/src/provider/error.ts +188 -0
- package/src/provider/model-status.ts +8 -0
- package/src/provider/provider.ts +1981 -0
- package/src/provider/transform.ts +1561 -0
- package/src/question/index.ts +161 -0
- package/src/question/schema.ts +4 -0
- package/src/server/auth.ts +48 -0
- package/src/server/event.ts +10 -0
- package/src/server/global-lifecycle.ts +28 -0
- package/src/server/init-projectors.ts +3 -0
- package/src/server/mdns.ts +47 -0
- package/src/server/projectors.ts +1 -0
- package/src/server/proxy-util.ts +48 -0
- package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
- package/src/server/routes/instance/httpapi/api.ts +97 -0
- package/src/server/routes/instance/httpapi/errors.ts +193 -0
- package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
- package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
- package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
- package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
- package/src/server/routes/instance/httpapi/groups/experimental.ts +275 -0
- package/src/server/routes/instance/httpapi/groups/file.ts +185 -0
- package/src/server/routes/instance/httpapi/groups/global.ts +136 -0
- package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
- package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
- package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
- package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
- package/src/server/routes/instance/httpapi/groups/project-copy.ts +32 -0
- package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
- package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
- package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
- package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
- package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
- package/src/server/routes/instance/httpapi/groups/session.ts +462 -0
- package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
- package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
- package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
- package/src/server/routes/instance/httpapi/handlers/config.ts +34 -0
- package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
- package/src/server/routes/instance/httpapi/handlers/control.ts +43 -0
- package/src/server/routes/instance/httpapi/handlers/event.ts +99 -0
- package/src/server/routes/instance/httpapi/handlers/experimental.ts +193 -0
- package/src/server/routes/instance/httpapi/handlers/file.ts +139 -0
- package/src/server/routes/instance/httpapi/handlers/global.ts +156 -0
- package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
- package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
- package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
- package/src/server/routes/instance/httpapi/handlers/project-copy.ts +83 -0
- package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
- package/src/server/routes/instance/httpapi/handlers/provider.ts +113 -0
- package/src/server/routes/instance/httpapi/handlers/pty.ts +273 -0
- package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
- package/src/server/routes/instance/httpapi/handlers/session-errors.ts +21 -0
- package/src/server/routes/instance/httpapi/handlers/session.ts +442 -0
- package/src/server/routes/instance/httpapi/handlers/sync.ts +89 -0
- package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
- package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
- package/src/server/routes/instance/httpapi/lifecycle.ts +54 -0
- package/src/server/routes/instance/httpapi/middleware/authorization.ts +150 -0
- package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
- package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
- package/src/server/routes/instance/httpapi/middleware/error.ts +43 -0
- package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
- package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
- package/src/server/routes/instance/httpapi/middleware/proxy.ts +108 -0
- package/src/server/routes/instance/httpapi/middleware/schema-error.ts +41 -0
- package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
- package/src/server/routes/instance/httpapi/public.ts +537 -0
- package/src/server/routes/instance/httpapi/server.ts +325 -0
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +60 -0
- package/src/server/server.ts +226 -0
- package/src/server/shared/fence.ts +60 -0
- package/src/server/shared/pty-ticket.ts +15 -0
- package/src/server/shared/public-ui.ts +12 -0
- package/src/server/shared/tui-control.ts +28 -0
- package/src/server/shared/ui.ts +108 -0
- package/src/server/shared/workspace-routing.ts +38 -0
- package/src/server/tui-event.ts +1 -0
- package/src/session/compaction.ts +562 -0
- package/src/session/instruction.ts +237 -0
- package/src/session/llm/AGENTS.md +90 -0
- package/src/session/llm/ai-sdk.ts +288 -0
- package/src/session/llm/native-request.ts +196 -0
- package/src/session/llm/native-runtime.ts +195 -0
- package/src/session/llm/request.ts +226 -0
- package/src/session/llm.ts +404 -0
- package/src/session/message-error.ts +14 -0
- package/src/session/message-v2.ts +734 -0
- package/src/session/message.ts +148 -0
- package/src/session/overflow.ts +34 -0
- package/src/session/processor.ts +718 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex.txt +79 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/default.txt +95 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/gpt.txt +107 -0
- package/src/session/prompt/kimi.txt +95 -0
- package/src/session/prompt/plan-mode.txt +70 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/session/prompt/plan.txt +26 -0
- package/src/session/prompt/trinity.txt +97 -0
- package/src/session/prompt.ts +1631 -0
- package/src/session/reminders.ts +92 -0
- package/src/session/retry.ts +201 -0
- package/src/session/revert.ts +146 -0
- package/src/session/run-state.ts +151 -0
- package/src/session/schema.ts +26 -0
- package/src/session/session.ts +1018 -0
- package/src/session/status.ts +56 -0
- package/src/session/summary.ts +160 -0
- package/src/session/system.ts +143 -0
- package/src/session/todo.ts +74 -0
- package/src/session/tools.ts +590 -0
- package/src/share/session.ts +58 -0
- package/src/share/share-next.ts +371 -0
- package/src/skill/discovery.ts +140 -0
- package/src/skill/index.ts +354 -0
- package/src/snapshot/index.ts +807 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/schema.ts +5 -0
- package/src/storage/storage.ts +327 -0
- package/src/sync/README.md +179 -0
- package/src/sync/schema.ts +11 -0
- package/src/temporary.ts +31 -0
- package/src/tool/apply_patch.ts +313 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/code-mode.ts +324 -0
- package/src/tool/edit.ts +737 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +49 -0
- package/src/tool/glob.ts +76 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +112 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +21 -0
- package/src/tool/json-schema.ts +164 -0
- package/src/tool/lsp.ts +113 -0
- package/src/tool/lsp.txt +24 -0
- package/src/tool/mcp-websearch.ts +96 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +79 -0
- package/src/tool/question.ts +44 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +386 -0
- package/src/tool/read.txt +14 -0
- package/src/tool/registry.ts +450 -0
- package/src/tool/schema.ts +14 -0
- package/src/tool/shell/id.ts +19 -0
- package/src/tool/shell/prompt.ts +293 -0
- package/src/tool/shell/shell.txt +21 -0
- package/src/tool/shell.ts +645 -0
- package/src/tool/skill.ts +70 -0
- package/src/tool/skill.txt +5 -0
- package/src/tool/task.ts +346 -0
- package/src/tool/task.txt +37 -0
- package/src/tool/todo.ts +46 -0
- package/src/tool/todowrite.txt +44 -0
- package/src/tool/tool.ts +183 -0
- package/src/tool/truncate.ts +156 -0
- package/src/tool/truncation-dir.ts +4 -0
- package/src/tool/webfetch.ts +192 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +143 -0
- package/src/tool/websearch.txt +14 -0
- package/src/tool/write.ts +104 -0
- package/src/tool/write.txt +8 -0
- package/src/util/archive.ts +17 -0
- package/src/util/bom.ts +27 -0
- package/src/util/data-url.ts +9 -0
- package/src/util/defer.ts +10 -0
- package/src/util/effect-http-client.ts +11 -0
- package/src/util/error.ts +1 -0
- package/src/util/filesystem.ts +251 -0
- package/src/util/html.ts +8 -0
- package/src/util/iife.ts +3 -0
- package/src/util/lazy.ts +20 -0
- package/src/util/local-context.ts +25 -0
- package/src/util/locale.ts +2 -0
- package/src/util/media.ts +26 -0
- package/src/util/process.ts +177 -0
- package/src/util/proxy-env.ts +72 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +1 -0
- package/src/util/repository.ts +232 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +13 -0
- package/src/util/token.ts +1 -0
- package/src/util/wildcard.ts +59 -0
- package/src/worktree/index.ts +623 -0
- package/test/AGENTS.md +204 -0
- package/test/EFFECT_TEST_MIGRATION.md +169 -0
- package/test/account/repo.test.ts +355 -0
- package/test/account/service.test.ts +456 -0
- package/test/acp/config-option.test.ts +229 -0
- package/test/acp/content.test.ts +235 -0
- package/test/acp/directory.test.ts +188 -0
- package/test/acp/error.test.ts +67 -0
- package/test/acp/event.test.ts +751 -0
- package/test/acp/permission.test.ts +401 -0
- package/test/acp/service-session.test.ts +1248 -0
- package/test/acp/session.test.ts +201 -0
- package/test/acp/tool.test.ts +298 -0
- package/test/acp/usage.test.ts +318 -0
- package/test/agent/agent.test.ts +755 -0
- package/test/agent/plan-mode-subagent-bypass.test.ts +160 -0
- package/test/agent/plugin-agent-regression.test.ts +51 -0
- package/test/auth/auth.test.ts +75 -0
- package/test/background/job.test.ts +244 -0
- package/test/cli/account.test.ts +30 -0
- package/test/cli/acp/acp-test-client.ts +97 -0
- package/test/cli/acp/config-options.test.ts +103 -0
- package/test/cli/acp/helpers.ts +96 -0
- package/test/cli/acp/initialize-auth.test.ts +61 -0
- package/test/cli/acp/lifecycle.test.ts +118 -0
- package/test/cli/acp/prompt-content.test.ts +97 -0
- package/test/cli/acp/skills.test.ts +38 -0
- package/test/cli/cmd/tui/attention.test.ts +484 -0
- package/test/cli/effect-cmd-instance-als.test.ts +40 -0
- package/test/cli/error.test.ts +95 -0
- package/test/cli/github-action.test.ts +199 -0
- package/test/cli/github-remote.test.ts +90 -0
- package/test/cli/help/__snapshots__/help-snapshots.test.ts.snap +623 -0
- package/test/cli/help/help-snapshots.test.ts +140 -0
- package/test/cli/import.test.ts +54 -0
- package/test/cli/mcp-add.test.ts +74 -0
- package/test/cli/plugin-auth-picker.test.ts +120 -0
- package/test/cli/run/entry.body.test.ts +536 -0
- package/test/cli/run/footer.menu.test.ts +43 -0
- package/test/cli/run/footer.view.test.tsx +1375 -0
- package/test/cli/run/footer.width.test.ts +35 -0
- package/test/cli/run/permission.shared.test.ts +144 -0
- package/test/cli/run/prompt.editor.test.ts +101 -0
- package/test/cli/run/prompt.shared.test.ts +101 -0
- package/test/cli/run/question.shared.test.ts +115 -0
- package/test/cli/run/run-process.test.ts +331 -0
- package/test/cli/run/runtime.boot.test.ts +283 -0
- package/test/cli/run/runtime.queue.test.ts +481 -0
- package/test/cli/run/runtime.stdin.test.ts +71 -0
- package/test/cli/run/runtime.test.ts +238 -0
- package/test/cli/run/scrollback.surface.test.ts +1092 -0
- package/test/cli/run/session-data.test.ts +593 -0
- package/test/cli/run/session-replay.test.ts +691 -0
- package/test/cli/run/session.shared.test.ts +247 -0
- package/test/cli/run/stream.test.ts +56 -0
- package/test/cli/run/stream.transport.test.ts +2363 -0
- package/test/cli/run/subagent-data.test.ts +547 -0
- package/test/cli/run/theme.test.ts +177 -0
- package/test/cli/run/variant.shared.test.ts +218 -0
- package/test/cli/serve/serve-process.test.ts +61 -0
- package/test/cli/smokes/read-only.test.ts +115 -0
- package/test/cli/tui/attach.test.ts +11 -0
- package/test/cli/tui/editor-context-zed.test.ts +379 -0
- package/test/cli/tui/editor-context.test.tsx +297 -0
- package/test/cli/tui/plugin-add.test.ts +110 -0
- package/test/cli/tui/plugin-install.test.ts +87 -0
- package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
- package/test/cli/tui/plugin-loader-entrypoint.test.ts +485 -0
- package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
- package/test/cli/tui/plugin-loader.test.ts +1332 -0
- package/test/cli/tui/plugin-toggle.test.ts +264 -0
- package/test/cli/tui/thread.test.ts +95 -0
- package/test/config/agent-color.test.ts +47 -0
- package/test/config/config.test.ts +2027 -0
- package/test/config/entry-name.test.ts +57 -0
- package/test/config/fixtures/empty-frontmatter.md +4 -0
- package/test/config/fixtures/frontmatter.md +28 -0
- package/test/config/fixtures/markdown-header.md +11 -0
- package/test/config/fixtures/no-frontmatter.md +1 -0
- package/test/config/fixtures/weird-model-id.md +13 -0
- package/test/config/lsp.test.ts +69 -0
- package/test/config/markdown.test.ts +228 -0
- package/test/config/plugin.test.ts +0 -0
- package/test/config/tui.test.ts +894 -0
- package/test/control-plane/adapters.test.ts +71 -0
- package/test/control-plane/workspace.test.ts +1701 -0
- package/test/effect/app-runtime-logger.test.ts +101 -0
- package/test/effect/config-service.test.ts +65 -0
- package/test/effect/instance-state.test.ts +392 -0
- package/test/effect/run-service.test.ts +89 -0
- package/test/effect/runner.test.ts +514 -0
- package/test/effect/runtime-flags.test.ts +374 -0
- package/test/event-manifest.test.ts +24 -0
- package/test/fake/account.ts +9 -0
- package/test/fake/auth.ts +8 -0
- package/test/fake/npm.ts +8 -0
- package/test/fake/provider.ts +82 -0
- package/test/fake/skill.ts +8 -0
- package/test/filesystem/filesystem.test.ts +318 -0
- package/test/fixture/agent-plugin.constants.ts +6 -0
- package/test/fixture/agent-plugin.ts +12 -0
- package/test/fixture/config.ts +23 -0
- package/test/fixture/db.ts +11 -0
- package/test/fixture/fixture.test.ts +26 -0
- package/test/fixture/fixture.ts +228 -0
- package/test/fixture/flag.ts +20 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/lsp/fake-lsp-server.js +249 -0
- package/test/fixture/mcp-session-recovery.ts +50 -0
- package/test/fixture/plug-worker.ts +93 -0
- package/test/fixture/plugin-meta-worker.ts +19 -0
- package/test/fixture/plugin.ts +10 -0
- package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
- package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
- package/test/fixture/skills/cloudflare/SKILL.md +211 -0
- package/test/fixture/skills/index.json +6 -0
- package/test/fixture/tui-environment.tsx +32 -0
- package/test/fixture/tui-plugin.ts +355 -0
- package/test/fixture/tui-runtime.ts +56 -0
- package/test/fixture/tui-sdk.ts +82 -0
- package/test/fixture/workspace.ts +34 -0
- package/test/fixtures/recordings/session/native-anthropic-tool-loop.json +49 -0
- package/test/fixtures/recordings/session/native-openai-oauth-tool-loop.json +45 -0
- package/test/fixtures/recordings/session/native-zen-tool-loop.json +49 -0
- package/test/format/format.test.ts +235 -0
- package/test/git/git.test.ts +179 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/image/fixtures/picture-5mb-base64.png +0 -0
- package/test/image/image.test.ts +121 -0
- package/test/installation/installation.test.ts +240 -0
- package/test/lib/cli-process.ts +535 -0
- package/test/lib/effect.ts +177 -0
- package/test/lib/filesystem.ts +10 -0
- package/test/lib/llm-server.ts +779 -0
- package/test/lib/snapshot.ts +73 -0
- package/test/lib/test-provider.ts +37 -0
- package/test/lib/websocket.ts +46 -0
- package/test/lsp/client.test.ts +488 -0
- package/test/lsp/index.test.ts +231 -0
- package/test/lsp/jdtls-root.test.ts +459 -0
- package/test/lsp/launch.test.ts +22 -0
- package/test/lsp/lifecycle.test.ts +160 -0
- package/test/mcp/auth.test.ts +78 -0
- package/test/mcp/catalog.test.ts +47 -0
- package/test/mcp/headers.test.ts +127 -0
- package/test/mcp/lifecycle.test.ts +1304 -0
- package/test/mcp/oauth-auto-connect.test.ts +367 -0
- package/test/mcp/oauth-browser.test.ts +243 -0
- package/test/mcp/oauth-callback.test.ts +114 -0
- package/test/mcp/oauth-provider.test.ts +102 -0
- package/test/mcp/session-recovery.test.ts +27 -0
- package/test/patch/patch.test.ts +384 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/next.test.ts +1174 -0
- package/test/permission-task.test.ts +319 -0
- package/test/plugin/auth-override.test.ts +101 -0
- package/test/plugin/cloudflare.test.ts +68 -0
- package/test/plugin/codex.test.ts +256 -0
- package/test/plugin/github-copilot-models.test.ts +370 -0
- package/test/plugin/install-concurrency.test.ts +140 -0
- package/test/plugin/install.test.ts +570 -0
- package/test/plugin/loader-shared.test.ts +1306 -0
- package/test/plugin/meta.test.ts +137 -0
- package/test/plugin/openai-rollout.test.ts +17 -0
- package/test/plugin/openai-ws.test.ts +884 -0
- package/test/plugin/shared.test.ts +88 -0
- package/test/plugin/snowflake-cortex.test.ts +278 -0
- package/test/plugin/trigger.test.ts +108 -0
- package/test/plugin/workspace-adapter.test.ts +111 -0
- package/test/plugin/xai.test.ts +620 -0
- package/test/preload.ts +92 -0
- package/test/project/instance-bootstrap.test.ts +115 -0
- package/test/project/instance.test.ts +248 -0
- package/test/project/migrate-global.test.ts +168 -0
- package/test/project/project-directory.test.ts +202 -0
- package/test/project/project.test.ts +808 -0
- package/test/project/vcs.test.ts +335 -0
- package/test/project/worktree-remove.test.ts +128 -0
- package/test/project/worktree.test.ts +324 -0
- package/test/provider/amazon-bedrock.test.ts +361 -0
- package/test/provider/cf-ai-gateway-e2e.test.ts +132 -0
- package/test/provider/digitalocean.test.ts +124 -0
- package/test/provider/gitlab-duo.test.ts +412 -0
- package/test/provider/header-timeout.test.ts +234 -0
- package/test/provider/model-status.test.ts +61 -0
- package/test/provider/provider.test.ts +1912 -0
- package/test/provider/transform.test.ts +4742 -0
- package/test/question/question.test.ts +459 -0
- package/test/server/AGENTS.md +15 -0
- package/test/server/auth.test.ts +59 -0
- package/test/server/global-bus.ts +31 -0
- package/test/server/global-session-list.test.ts +108 -0
- package/test/server/httpapi-authorization.test.ts +174 -0
- package/test/server/httpapi-compression.test.ts +151 -0
- package/test/server/httpapi-config.test.ts +110 -0
- package/test/server/httpapi-control-plane.test.ts +63 -0
- package/test/server/httpapi-cors-vary.test.ts +63 -0
- package/test/server/httpapi-cors.test.ts +122 -0
- package/test/server/httpapi-error-middleware.test.ts +101 -0
- package/test/server/httpapi-event.test.ts +94 -0
- package/test/server/httpapi-exercise/assertions.ts +64 -0
- package/test/server/httpapi-exercise/backend.ts +144 -0
- package/test/server/httpapi-exercise/dsl.ts +210 -0
- package/test/server/httpapi-exercise/environment.ts +40 -0
- package/test/server/httpapi-exercise/index.ts +1802 -0
- package/test/server/httpapi-exercise/report.ts +66 -0
- package/test/server/httpapi-exercise/routing.ts +96 -0
- package/test/server/httpapi-exercise/runner.ts +267 -0
- package/test/server/httpapi-exercise/runtime.ts +52 -0
- package/test/server/httpapi-exercise/types.ts +127 -0
- package/test/server/httpapi-experimental.test.ts +298 -0
- package/test/server/httpapi-file.test.ts +83 -0
- package/test/server/httpapi-global.test.ts +66 -0
- package/test/server/httpapi-instance-context.test.ts +337 -0
- package/test/server/httpapi-instance-route-auth.test.ts +81 -0
- package/test/server/httpapi-instance.test.ts +265 -0
- package/test/server/httpapi-layer.ts +33 -0
- package/test/server/httpapi-listen.test.ts +465 -0
- package/test/server/httpapi-mcp-oauth.test.ts +73 -0
- package/test/server/httpapi-mcp.test.ts +223 -0
- package/test/server/httpapi-mdns.test.ts +79 -0
- package/test/server/httpapi-promptasync-context.test.ts +212 -0
- package/test/server/httpapi-provider.test.ts +401 -0
- package/test/server/httpapi-pty.test.ts +299 -0
- package/test/server/httpapi-public-openapi.test.ts +350 -0
- package/test/server/httpapi-query-schema-drift.test.ts +330 -0
- package/test/server/httpapi-reference.test.ts +63 -0
- package/test/server/httpapi-schema-error-body.test.ts +166 -0
- package/test/server/httpapi-sdk.test.ts +913 -0
- package/test/server/httpapi-session.test.ts +1090 -0
- package/test/server/httpapi-sync.test.ts +149 -0
- package/test/server/httpapi-ui.test.ts +456 -0
- package/test/server/httpapi-v2-location.test.ts +126 -0
- package/test/server/httpapi-v2-pty.test.ts +250 -0
- package/test/server/httpapi-workspace-routing.test.ts +552 -0
- package/test/server/httpapi-workspace.test.ts +506 -0
- package/test/server/negative-tokens-regression.test.ts +84 -0
- package/test/server/project-copy.test.ts +127 -0
- package/test/server/project-init-git.test.ts +118 -0
- package/test/server/proxy-util.test.ts +113 -0
- package/test/server/sdk-error-shape.test.ts +81 -0
- package/test/server/sdk-v1-smoke.test.ts +57 -0
- package/test/server/session-actions.test.ts +110 -0
- package/test/server/session-diff-missing-patch.test.ts +97 -0
- package/test/server/session-list.test.ts +302 -0
- package/test/server/session-messages.test.ts +180 -0
- package/test/server/session-select.test.ts +67 -0
- package/test/server/workspace-proxy.test.ts +181 -0
- package/test/server/workspace-routing.test.ts +94 -0
- package/test/server/worktree-endpoint-repro.test.ts +307 -0
- package/test/session/compaction.test.ts +1819 -0
- package/test/session/instruction.test.ts +264 -0
- package/test/session/llm-native-recorded.test.ts +413 -0
- package/test/session/llm-native.test.ts +761 -0
- package/test/session/llm.test.ts +2003 -0
- package/test/session/message-v2.test.ts +1661 -0
- package/test/session/messages-pagination.test.ts +1057 -0
- package/test/session/processor-effect.test.ts +1067 -0
- package/test/session/prompt.test.ts +2402 -0
- package/test/session/retry.test.ts +440 -0
- package/test/session/revert-compact.test.ts +638 -0
- package/test/session/schema-decoding.test.ts +313 -0
- package/test/session/session-schema.test.ts +78 -0
- package/test/session/session.test.ts +253 -0
- package/test/session/snapshot-tool-race.test.ts +189 -0
- package/test/session/structured-output-integration.test.ts +235 -0
- package/test/session/structured-output.test.ts +387 -0
- package/test/session/system.test.ts +142 -0
- package/test/share/share-next.test.ts +324 -0
- package/test/skill/discovery.test.ts +186 -0
- package/test/skill/skill.test.ts +585 -0
- package/test/snapshot/snapshot.test.ts +1218 -0
- package/test/storage/storage.test.ts +297 -0
- package/test/tool/__snapshots__/parameters.test.ts.snap +466 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/apply_patch.test.ts +529 -0
- package/test/tool/code-mode-integration.test.ts +329 -0
- package/test/tool/code-mode.test.ts +714 -0
- package/test/tool/edit.test.ts +574 -0
- package/test/tool/external-directory.test.ts +156 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +117299 -0
- package/test/tool/glob.test.ts +132 -0
- package/test/tool/grep.test.ts +221 -0
- package/test/tool/lsp.test.ts +184 -0
- package/test/tool/parameters.test.ts +290 -0
- package/test/tool/question.test.ts +133 -0
- package/test/tool/read.test.ts +608 -0
- package/test/tool/registry.test.ts +572 -0
- package/test/tool/shell.test.ts +1199 -0
- package/test/tool/skill.test.ts +134 -0
- package/test/tool/task.test.ts +905 -0
- package/test/tool/tool-define.test.ts +154 -0
- package/test/tool/truncation.test.ts +264 -0
- package/test/tool/webfetch.test.ts +119 -0
- package/test/tool/websearch.test.ts +99 -0
- package/test/tool/write.test.ts +279 -0
- package/test/util/data-url.test.ts +14 -0
- package/test/util/error.test.ts +16 -0
- package/test/util/filesystem.test.ts +656 -0
- package/test/util/glob.test.ts +164 -0
- package/test/util/html.test.ts +15 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/module.test.ts +59 -0
- package/test/util/process.test.ts +128 -0
- package/test/util/repository.test.ts +93 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +90 -0
- package/test/v2/session-message-updater.test.ts +269 -0
- package/tsconfig.json +16 -0
- package/LICENSE +0 -21
- package/bin/openfork.exe +0 -10
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Typed Error Migration
|
|
2
|
+
|
|
3
|
+
This note expands the `ERR`, `RENDER`, and `HTTP` tracks from
|
|
4
|
+
[`todo.md`](./todo.md). It is the current reference for expected failures,
|
|
5
|
+
typed service errors, and HTTP error boundaries.
|
|
6
|
+
|
|
7
|
+
For the migration architecture and queue, see
|
|
8
|
+
[`error-boundaries-plan.md`](./error-boundaries-plan.md).
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
|
|
12
|
+
- Expected service failures live on the Effect error channel.
|
|
13
|
+
- Service interfaces expose those failures in their return types.
|
|
14
|
+
- Domain errors are authored with `Schema.TaggedErrorClass`.
|
|
15
|
+
- `Effect.die(...)` is reserved for defects: bugs, impossible states,
|
|
16
|
+
violated invariants, and final unknown-boundary fallbacks.
|
|
17
|
+
- HTTP status codes and public wire bodies are handled at HTTP route
|
|
18
|
+
boundaries, not inside service modules.
|
|
19
|
+
- User-facing boundaries render useful structured error details instead of
|
|
20
|
+
opaque `Error: SomeName` strings.
|
|
21
|
+
|
|
22
|
+
## Service Error Shape
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
export class SessionBusyError extends Schema.TaggedErrorClass<SessionBusyError>()("SessionBusyError", {
|
|
26
|
+
sessionID: SessionID,
|
|
27
|
+
message: Schema.String,
|
|
28
|
+
}) {}
|
|
29
|
+
|
|
30
|
+
export type Error = Storage.Error | SessionBusyError
|
|
31
|
+
|
|
32
|
+
export interface Interface {
|
|
33
|
+
readonly get: (id: SessionID) => Effect.Effect<Info, Error>
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Rules:
|
|
38
|
+
|
|
39
|
+
- Use `Schema.TaggedErrorClass` for expected domain failures.
|
|
40
|
+
- Export a domain-level `Error` union from each service module.
|
|
41
|
+
- Put expected errors in service method signatures.
|
|
42
|
+
- Use `yield* new DomainError(...)` for direct early failures in
|
|
43
|
+
`Effect.gen` / `Effect.fn`.
|
|
44
|
+
- Use `Schema.Defect` for unknown cause fields when preserving the cause is
|
|
45
|
+
useful for logs or callers.
|
|
46
|
+
- Use `Effect.try(...)`, `Effect.tryPromise(...)`, `Effect.mapError`,
|
|
47
|
+
`Effect.catchTag`, and `Effect.catchTags` to translate external
|
|
48
|
+
failures into domain errors.
|
|
49
|
+
- Do not use `throw`, `Effect.die(...)`, or `catchDefect` for expected
|
|
50
|
+
user, IO, validation, missing-resource, auth, provider, worktree, or
|
|
51
|
+
busy-state failures.
|
|
52
|
+
|
|
53
|
+
## HTTP Boundary Shape
|
|
54
|
+
|
|
55
|
+
Service modules stay transport-agnostic. They should not import HTTP
|
|
56
|
+
status codes, `HttpApiError`, `HttpServerResponse`, or route-specific
|
|
57
|
+
error schemas.
|
|
58
|
+
|
|
59
|
+
HTTP handlers translate service errors into public endpoint errors:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const get = Effect.fn("SessionHttpApi.get")(function* (ctx: { params: { sessionID: SessionID } }) {
|
|
63
|
+
return yield* session
|
|
64
|
+
.get(ctx.params.sessionID)
|
|
65
|
+
.pipe(Effect.catchTag("StorageNotFoundError", () => notFound("Session not found")))
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Endpoint definitions declare which public errors can be emitted. Public
|
|
70
|
+
HTTP error schemas carry their response status with `httpApiStatus` or the
|
|
71
|
+
equivalent HttpApi schema annotation.
|
|
72
|
+
|
|
73
|
+
Effect's own HttpApi examples follow this pattern:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
export class Unauthorized extends Schema.TaggedErrorClass<Unauthorized>()(
|
|
77
|
+
"Unauthorized",
|
|
78
|
+
{ message: Schema.String },
|
|
79
|
+
{ httpApiStatus: 401 },
|
|
80
|
+
) {}
|
|
81
|
+
|
|
82
|
+
export class Authorization extends HttpApiMiddleware.Service<
|
|
83
|
+
Authorization,
|
|
84
|
+
{
|
|
85
|
+
provides: CurrentUser
|
|
86
|
+
}
|
|
87
|
+
>()("app/Authorization", {
|
|
88
|
+
security: { bearer: HttpApiSecurity.bearer },
|
|
89
|
+
error: Unauthorized,
|
|
90
|
+
}) {}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Endpoint-level errors use the same idea:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
export class ConfigApiError extends Schema.ErrorClass<ConfigApiError>("ConfigApiError")(
|
|
97
|
+
{
|
|
98
|
+
name: Schema.Union(Schema.Literal("ConfigInvalidError"), Schema.Literal("ConfigJsonError")),
|
|
99
|
+
data: Schema.Struct({ message: Schema.optional(Schema.String), path: Schema.String }),
|
|
100
|
+
},
|
|
101
|
+
{ httpApiStatus: 400 },
|
|
102
|
+
) {}
|
|
103
|
+
|
|
104
|
+
HttpApiEndpoint.get("get", "/config", {
|
|
105
|
+
success: Config.Info,
|
|
106
|
+
error: ConfigApiError,
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The service error and HTTP error may be the same class only when the wire
|
|
111
|
+
shape is intentionally public. Use separate HTTP error schemas when the
|
|
112
|
+
service error contains internals, low-level causes, retry hints, or data
|
|
113
|
+
that should not be exposed to API clients.
|
|
114
|
+
|
|
115
|
+
Do not map every domain error into one universal HTTP error class. Prefer a
|
|
116
|
+
small public error vocabulary by route group: shared shapes like
|
|
117
|
+
`ApiNotFoundError`, route-specific shapes like `ConfigApiError`, and built-in
|
|
118
|
+
empty `HttpApiError.*` only when an empty/no-content body is the intended SDK
|
|
119
|
+
contract.
|
|
120
|
+
|
|
121
|
+
## Mapping Guidance
|
|
122
|
+
|
|
123
|
+
- Keep one-off translations inline in the handler.
|
|
124
|
+
- Extract tiny shared helpers when the same translation repeats across a
|
|
125
|
+
route group.
|
|
126
|
+
- Do not create one giant `unknown -> status` mapper.
|
|
127
|
+
- Do not grow generic HTTP middleware into a registry of domain errors.
|
|
128
|
+
- Preserve existing public `{ name, data }` bodies until a deliberate
|
|
129
|
+
breaking API change.
|
|
130
|
+
- Use built-in `HttpApiError.*` only when its generated body and SDK
|
|
131
|
+
surface are intentionally the public contract.
|
|
132
|
+
- Prefer `Schema.ErrorClass` for public HTTP error bodies whose wire shape is
|
|
133
|
+
not the same as the internal domain error shape.
|
|
134
|
+
- Prefer `Schema.TaggedErrorClass` for service/domain errors and middleware
|
|
135
|
+
errors that are naturally tagged by `_tag`.
|
|
136
|
+
- If preserving a legacy `{ name, data }` body, model that shape explicitly in
|
|
137
|
+
the public API error schema instead of relying on `NamedError.toObject()` in
|
|
138
|
+
generic middleware.
|
|
139
|
+
|
|
140
|
+
## User-Facing Rendering
|
|
141
|
+
|
|
142
|
+
HTTP serialization and user rendering are separate boundaries. The server
|
|
143
|
+
should send structured public errors; CLI and TUI code should format those
|
|
144
|
+
structures through one shared formatter.
|
|
145
|
+
|
|
146
|
+
For SDK calls using `{ throwOnError: true }`, the generated client may wrap the
|
|
147
|
+
decoded response body in an `Error`. The original body should remain available
|
|
148
|
+
under `error.cause.body`; `FormatError` is the right place to unwrap and render
|
|
149
|
+
that body. TUI aggregation helpers should call `FormatError` first, then fall
|
|
150
|
+
back to generic `Error.message` / string rendering.
|
|
151
|
+
|
|
152
|
+
When several parallel startup requests fail from the same underlying issue,
|
|
153
|
+
group identical rendered messages and list the affected request names once.
|
|
154
|
+
For example:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Configuration is invalid at /path/to/openfork.json
|
|
158
|
+
↳ Expected object, got "not-object" provider.bad.options
|
|
159
|
+
Affected startup requests: config.providers, provider.list, app.agents, config.get
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Middleware Guidance
|
|
163
|
+
|
|
164
|
+
HTTP middleware should be cross-cutting: auth, context, schema decode
|
|
165
|
+
formatting, routing, and final unknown-defect fallback.
|
|
166
|
+
|
|
167
|
+
The current compatibility middleware still knows about some legacy domain
|
|
168
|
+
errors. As route groups declare expected errors and handlers map them, that
|
|
169
|
+
middleware should shrink. It should not gain new name checks.
|
|
170
|
+
|
|
171
|
+
Unknown `500` responses should log full details server-side with
|
|
172
|
+
`Cause.pretty(cause)` and return a safe public body.
|
|
173
|
+
|
|
174
|
+
The config startup regression in #27056 is the failure mode this rule is meant
|
|
175
|
+
to avoid: a user-authored invalid `openfork.json` crossed the HttpApi boundary
|
|
176
|
+
as a defect, so middleware replaced a useful `ConfigInvalidError` with a safe
|
|
177
|
+
generic `UnknownError`. The compatibility fix is to preserve config parse and
|
|
178
|
+
validation errors as client-visible `400`s. The target architecture is better:
|
|
179
|
+
config loading should fail on the typed error channel, config HTTP handlers
|
|
180
|
+
should map those errors to declared `ConfigApiError` responses, and the generic
|
|
181
|
+
middleware should never see them.
|
|
182
|
+
|
|
183
|
+
## Migration Order
|
|
184
|
+
|
|
185
|
+
Prefer small vertical slices:
|
|
186
|
+
|
|
187
|
+
1. Fix rendering at one user-visible boundary.
|
|
188
|
+
2. Convert one service domain to `Schema.TaggedErrorClass` errors.
|
|
189
|
+
3. Map those errors at the affected HTTP handlers.
|
|
190
|
+
4. Remove the corresponding name-based middleware branch if possible.
|
|
191
|
+
5. Add or update focused tests for both service error tags and HTTP wire
|
|
192
|
+
bodies.
|
|
193
|
+
|
|
194
|
+
Good early domains are storage not-found, worktree errors, and provider
|
|
195
|
+
auth validation errors because they currently drive HTTP behavior.
|
|
196
|
+
|
|
197
|
+
Config parse and validation errors are also a good early slice because they
|
|
198
|
+
are startup-blocking and must be rendered clearly in both CLI and TUI flows.
|
|
199
|
+
|
|
200
|
+
## Checklist For A PR
|
|
201
|
+
|
|
202
|
+
- [ ] Expected failures are typed errors, not defects.
|
|
203
|
+
- [ ] Service method signatures expose the expected error union.
|
|
204
|
+
- [ ] HTTP handlers translate domain errors at the boundary.
|
|
205
|
+
- [ ] Public HTTP error bodies preserve existing wire contracts.
|
|
206
|
+
- [ ] Generic middleware gets smaller or stays unchanged.
|
|
207
|
+
- [ ] Focused tests cover the service error and any public HTTP response.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Facade removal checklist
|
|
2
|
+
|
|
3
|
+
Concrete inventory of the remaining `makeRuntime(...)`-backed facades in `packages/openfork`.
|
|
4
|
+
|
|
5
|
+
Current status on this branch:
|
|
6
|
+
|
|
7
|
+
- `src/` has 5 `makeRuntime(...)` call sites total.
|
|
8
|
+
- 2 are intentionally excluded from this checklist: `src/bus/index.ts` and `src/effect/cross-spawn-spawner.ts`.
|
|
9
|
+
- That leaves 2 live runtime-backed service facades still worth tracking here: `src/npm/index.ts` and `src/cli/cmd/tui/config/tui.ts`.
|
|
10
|
+
|
|
11
|
+
Recent progress:
|
|
12
|
+
|
|
13
|
+
- Wave 1 is merged: `Pty`, `Skill`, `Vcs`, `ToolRegistry`, `Auth`.
|
|
14
|
+
- Wave 2 is merged: `Config`, `Provider`, `File`, `LSP`, `MCP`.
|
|
15
|
+
|
|
16
|
+
## Priority hotspots
|
|
17
|
+
|
|
18
|
+
- `src/cli/cmd/tui/config/tui.ts` still exports `makeRuntime(...)` plus async facade helpers for `get()` and `waitForDependencies()`.
|
|
19
|
+
- `src/npm/index.ts` still exports `makeRuntime(...)` plus async facade helpers for `install()`, `add()`, `outdated()`, and `which()`.
|
|
20
|
+
|
|
21
|
+
## Completed Batches
|
|
22
|
+
|
|
23
|
+
Low-risk batch, all merged:
|
|
24
|
+
|
|
25
|
+
1. `src/pty/index.ts`
|
|
26
|
+
2. `src/skill/index.ts`
|
|
27
|
+
3. `src/project/vcs.ts`
|
|
28
|
+
4. `src/tool/registry.ts`
|
|
29
|
+
5. `src/auth/index.ts`
|
|
30
|
+
|
|
31
|
+
Caller-heavy batch, all merged:
|
|
32
|
+
|
|
33
|
+
1. `src/config/config.ts`
|
|
34
|
+
2. `src/provider/provider.ts`
|
|
35
|
+
3. `../core/src/filesystem.ts`
|
|
36
|
+
4. `src/lsp/index.ts`
|
|
37
|
+
5. `src/mcp/index.ts`
|
|
38
|
+
|
|
39
|
+
Shared pattern:
|
|
40
|
+
|
|
41
|
+
- one service file still exports `makeRuntime(...)` + async facades
|
|
42
|
+
- one or two route or CLI entrypoints call those facades directly
|
|
43
|
+
- tests call the facade directly and need to switch to `yield* svc.method(...)`
|
|
44
|
+
- once callers are gone, delete `makeRuntime(...)`, remove async facade exports, and drop the `makeRuntime` import
|
|
45
|
+
|
|
46
|
+
## Done means
|
|
47
|
+
|
|
48
|
+
For each service in the low-risk batch, the work is complete only when all of these are true:
|
|
49
|
+
|
|
50
|
+
1. all production callers stop using `Namespace.method(...)` facade calls
|
|
51
|
+
2. all direct test callers stop using the facade and instead yield the service from context
|
|
52
|
+
3. the service file no longer has `makeRuntime(...)`
|
|
53
|
+
4. the service file no longer exports runtime-backed facade helpers
|
|
54
|
+
5. `grep` for the migrated facade methods only finds the service implementation itself or unrelated names
|
|
55
|
+
|
|
56
|
+
## Caller templates
|
|
57
|
+
|
|
58
|
+
### Route handlers
|
|
59
|
+
|
|
60
|
+
Use one `AppRuntime.runPromise(Effect.gen(...))` body and yield the service inside it.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const value = await AppRuntime.runPromise(
|
|
64
|
+
Effect.gen(function* () {
|
|
65
|
+
const pty = yield* Pty.Service
|
|
66
|
+
return yield* pty.list()
|
|
67
|
+
}),
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If two service calls are independent, keep them in the same effect body and use `Effect.all(...)`.
|
|
72
|
+
|
|
73
|
+
### Plain async CLI or script entrypoints
|
|
74
|
+
|
|
75
|
+
If the caller is not itself an Effect service yet, still prefer one contiguous `AppRuntime.runPromise(Effect.gen(...))` block for the whole unit of work.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const skills = await AppRuntime.runPromise(
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
const auth = yield* Auth.Service
|
|
81
|
+
const skill = yield* Skill.Service
|
|
82
|
+
yield* auth.set(key, info)
|
|
83
|
+
return yield* skill.all()
|
|
84
|
+
}),
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Only fall back to `AppRuntime.runPromise(Service.use(...))` for truly isolated one-off calls or awkward callback boundaries. Do not stack multiple tiny `runPromise(...)` calls in the same contiguous workflow.
|
|
89
|
+
|
|
90
|
+
This is the right intermediate state. Do not block facade removal on effectifying the whole CLI file.
|
|
91
|
+
|
|
92
|
+
### Bootstrap or fire-and-forget startup code
|
|
93
|
+
|
|
94
|
+
If the old facade call existed only to kick off initialization, call the service through the existing runtime for that file.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
void BootstrapRuntime.runPromise(Vcs.Service.use((svc) => svc.init()))
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Do not reintroduce a dedicated runtime in the service just for bootstrap.
|
|
101
|
+
|
|
102
|
+
### Tests
|
|
103
|
+
|
|
104
|
+
Convert facade tests to full effect style.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
it.effect("does the thing", () =>
|
|
108
|
+
Effect.gen(function* () {
|
|
109
|
+
const svc = yield* Pty.Service
|
|
110
|
+
const info = yield* svc.create({ command: "cat", title: "a" })
|
|
111
|
+
yield* svc.remove(info.id)
|
|
112
|
+
}).pipe(Effect.provide(Pty.defaultLayer)),
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If the repo test already uses `testEffect(...)`, prefer `testEffect(Service.defaultLayer)` and `yield* Service.Service` inside the test body.
|
|
117
|
+
|
|
118
|
+
Do not route tests through `AppRuntime` unless the test is explicitly exercising the app runtime. For facade removal, tests should usually provide the specific service layer they need.
|
|
119
|
+
|
|
120
|
+
If the test uses `provideTmpdirInstance(...)`, remember that fixture needs a live `ChildProcessSpawner` layer. For services whose `defaultLayer` does not already provide that infra, prefer the repo-standard cross-spawn layer:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const infra = CrossSpawnSpawner.defaultLayer
|
|
124
|
+
|
|
125
|
+
const it = testEffect(Layer.mergeAll(MyService.defaultLayer, infra))
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Without that extra layer, tests fail at runtime with `Service not found: effect/process/ChildProcessSpawner`.
|
|
129
|
+
|
|
130
|
+
## Questions already answered
|
|
131
|
+
|
|
132
|
+
### Do we need to effectify the whole caller first?
|
|
133
|
+
|
|
134
|
+
No.
|
|
135
|
+
|
|
136
|
+
- route files: compose the handler with `AppRuntime.runPromise(Effect.gen(...))`
|
|
137
|
+
- CLI and scripts: use `AppRuntime.runPromise(Service.use(...))`
|
|
138
|
+
- bootstrap: use the existing bootstrap runtime
|
|
139
|
+
|
|
140
|
+
Facade removal does not require a bigger refactor than that.
|
|
141
|
+
|
|
142
|
+
### Should tests keep calling the namespace from async test bodies?
|
|
143
|
+
|
|
144
|
+
No. Convert them now.
|
|
145
|
+
|
|
146
|
+
The end state is `yield* svc.method(...)`, not `await Namespace.method(...)` inside `async` tests.
|
|
147
|
+
|
|
148
|
+
### Should we keep `runPromise` exported for convenience?
|
|
149
|
+
|
|
150
|
+
No. For this batch the goal is to delete the service-local runtime entirely.
|
|
151
|
+
|
|
152
|
+
### What if a route has websocket callbacks or nested async handlers?
|
|
153
|
+
|
|
154
|
+
Keep the route shape, but replace each facade call with `AppRuntime.runPromise(Service.use(...))` or wrap the surrounding async section in one `Effect.gen(...)` when practical. Do not keep the service facade just because the route has callback-shaped code.
|
|
155
|
+
|
|
156
|
+
### Should we use one `runPromise` per service call?
|
|
157
|
+
|
|
158
|
+
No.
|
|
159
|
+
|
|
160
|
+
Default to one contiguous `AppRuntime.runPromise(Effect.gen(...))` block per handler, command, or workflow. Yield every service you need inside that block.
|
|
161
|
+
|
|
162
|
+
Multiple tiny `runPromise(...)` calls are only acceptable when the caller structure forces it, such as websocket lifecycle callbacks, external callback APIs, or genuinely unrelated one-off operations.
|
|
163
|
+
|
|
164
|
+
### Should we wrap a single service expression in `Effect.gen(...)`?
|
|
165
|
+
|
|
166
|
+
Usually no.
|
|
167
|
+
|
|
168
|
+
Prefer the direct form when there is only one expression:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
await Effect.runPromise(FileSystem.Service.use((svc) => svc.read({ path })))
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use `Effect.gen(...)` when the workflow actually needs multiple yielded values or branching.
|
|
175
|
+
|
|
176
|
+
## Learnings
|
|
177
|
+
|
|
178
|
+
These were the recurring mistakes and useful corrections from the first two batches:
|
|
179
|
+
|
|
180
|
+
1. Tests should usually provide the specific service layer, not `AppRuntime`.
|
|
181
|
+
2. If a test uses `provideTmpdirInstance(...)` and needs child processes, prefer `CrossSpawnSpawner.defaultLayer`.
|
|
182
|
+
3. Location-scoped services may need both the service layer and the right location fixture. `FileSystem` tests, for example, provide `Location.Service` plus `FileSystem.locationLayer`.
|
|
183
|
+
4. Do not wrap a single `Service.use(...)` call in `Effect.gen(...)` just to return it. Use the direct form.
|
|
184
|
+
5. For CLI readability, extract file-local preload helpers when the handler starts doing config load + service load + batched effect fanout inline.
|
|
185
|
+
6. When rebasing a facade branch after nearby merges, prefer the already-cleaned service/test version over older inline facade-era code.
|
|
186
|
+
|
|
187
|
+
## Remaining work
|
|
188
|
+
|
|
189
|
+
Most of the original facade-removal backlog is already done. The practical remaining work is narrower now:
|
|
190
|
+
|
|
191
|
+
1. remove the `Npm` runtime-backed facade from `src/npm/index.ts`
|
|
192
|
+
2. remove the `TuiConfig` runtime-backed facade from `src/cli/cmd/tui/config/tui.ts`
|
|
193
|
+
|
|
194
|
+
## Checklist
|
|
195
|
+
|
|
196
|
+
- [ ] `src/npm/index.ts` (`Npm`) - still exports runtime-backed async facade helpers on top of `Npm.Service`
|
|
197
|
+
- [ ] `src/cli/cmd/tui/config/tui.ts` (`TuiConfig`) - still exports runtime-backed async facade helpers on top of `TuiConfig.Service`
|
|
198
|
+
- [x] `src/session/session.ts` / `src/session/prompt.ts` / `src/session/revert.ts` / `src/session/summary.ts` - service-local facades removed
|
|
199
|
+
- [x] `src/agent/agent.ts` (`Agent`) - service-local facades removed
|
|
200
|
+
- [x] `src/permission/index.ts` (`Permission`) - service-local facades removed
|
|
201
|
+
- [x] `src/worktree/index.ts` (`Worktree`) - service-local facades removed
|
|
202
|
+
- [x] `src/plugin/index.ts` (`Plugin`) - service-local facades removed
|
|
203
|
+
- [x] `src/snapshot/index.ts` (`Snapshot`) - service-local facades removed
|
|
204
|
+
- [x] `../core/src/filesystem.ts` (`FileSystem`) - legacy openfork service removed
|
|
205
|
+
- [x] `src/lsp/index.ts` (`LSP`) - facades removed and merged
|
|
206
|
+
- [x] `src/mcp/index.ts` (`MCP`) - facades removed and merged
|
|
207
|
+
- [x] `src/config/config.ts` (`Config`) - facades removed and merged
|
|
208
|
+
- [x] `src/provider/provider.ts` (`Provider`) - facades removed and merged
|
|
209
|
+
- [x] `src/pty/index.ts` (`Pty`) - facades removed and merged
|
|
210
|
+
- [x] `src/skill/index.ts` (`Skill`) - facades removed and merged
|
|
211
|
+
- [x] `src/project/vcs.ts` (`Vcs`) - facades removed and merged
|
|
212
|
+
- [x] `src/tool/registry.ts` (`ToolRegistry`) - facades removed and merged
|
|
213
|
+
- [x] `src/auth/index.ts` (`Auth`) - facades removed and merged
|
|
214
|
+
|
|
215
|
+
## Excluded `makeRuntime(...)` sites
|
|
216
|
+
|
|
217
|
+
- `src/bus/index.ts` - core bus plumbing, not a normal facade-removal target.
|
|
218
|
+
- `src/effect/cross-spawn-spawner.ts` - runtime helper for `ChildProcessSpawner`, not a service namespace facade.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Effect Guide
|
|
2
|
+
|
|
3
|
+
How we write Effect code in `packages/openfork`. The companion roadmap is
|
|
4
|
+
[`todo.md`](./todo.md).
|
|
5
|
+
|
|
6
|
+
This guide describes the preferred shape for new work and migrations. If a
|
|
7
|
+
legacy file differs, migrate it only when it is already in scope.
|
|
8
|
+
|
|
9
|
+
## Service Shape
|
|
10
|
+
|
|
11
|
+
Use one module per service: flat top-level exports, traced Effect methods,
|
|
12
|
+
explicit layers, and a self-reexport at the bottom.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
export interface Interface {
|
|
16
|
+
readonly get: (id: FooID) => Effect.Effect<FooInfo, FooError>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class Service extends Context.Service<Service, Interface>()("@openfork/Foo") {}
|
|
20
|
+
|
|
21
|
+
export const layer = Layer.effect(
|
|
22
|
+
Service,
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const state = yield* InstanceState.make<State>(Effect.fn("Foo.state")(() => Effect.succeed({})))
|
|
25
|
+
|
|
26
|
+
const get = Effect.fn("Foo.get")(function* (id: FooID) {
|
|
27
|
+
const s = yield* InstanceState.get(state)
|
|
28
|
+
return yield* loadFoo(s, id)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return Service.of({ get })
|
|
32
|
+
}),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export const defaultLayer = layer.pipe(Layer.provide(FooDep.defaultLayer))
|
|
36
|
+
|
|
37
|
+
export * as Foo from "./foo"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Rules:
|
|
41
|
+
|
|
42
|
+
- Do not use `export namespace Foo { ... }`.
|
|
43
|
+
- Use `Effect.fn("Foo.method")` for public service methods.
|
|
44
|
+
- Use `Effect.fnUntraced` for small internal helpers that do not need a
|
|
45
|
+
span.
|
|
46
|
+
- Keep helpers as non-exported top-level declarations in the same file.
|
|
47
|
+
- Self-reexport with `export * as Foo from "."` for `index.ts`, otherwise
|
|
48
|
+
`export * as Foo from "./foo"`.
|
|
49
|
+
- In `src/config`, keep the existing top-of-file self-export pattern.
|
|
50
|
+
|
|
51
|
+
## Runtime Boundaries
|
|
52
|
+
|
|
53
|
+
Most code should run through [`AppRuntime`](../../src/effect/app-runtime.ts).
|
|
54
|
+
It hosts `AppLayer`, shares the global `memoMap`, and restores the current
|
|
55
|
+
instance/workspace refs when crossing from non-Effect code.
|
|
56
|
+
|
|
57
|
+
Use `AppRuntime.runPromise(effect)` at app boundaries such as CLI commands,
|
|
58
|
+
HTTP handlers, or plain async adapters.
|
|
59
|
+
|
|
60
|
+
`makeRuntime(...)` still exists for a few intentional service-local
|
|
61
|
+
boundaries and migration leftovers. Do not add a new service-local runtime
|
|
62
|
+
unless the service truly cannot live in `AppLayer`.
|
|
63
|
+
|
|
64
|
+
## Runtime Flags
|
|
65
|
+
|
|
66
|
+
Read openfork runtime flags through
|
|
67
|
+
[`RuntimeFlags.Service`](../../src/effect/runtime-flags.ts), not through
|
|
68
|
+
mutable `Flag` or late `process.env` reads.
|
|
69
|
+
|
|
70
|
+
Tests should vary behavior with explicit layer variants:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const it = testEffect(MyService.defaultLayer.pipe(Layer.provide(RuntimeFlags.layer({ experimentalReferences: true }))))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Do not mutate `process.env` or `Flag` after services/layers are built.
|
|
77
|
+
|
|
78
|
+
## Per-Instance State
|
|
79
|
+
|
|
80
|
+
Use [`InstanceState`](../../src/effect/instance-state.ts) when two open
|
|
81
|
+
directories should not share one copy of a service's state. It is backed by
|
|
82
|
+
a `ScopedCache`, keyed by directory, and disposed automatically when an
|
|
83
|
+
instance is unloaded.
|
|
84
|
+
|
|
85
|
+
Put subscriptions, finalizers, and scoped background work inside the
|
|
86
|
+
`InstanceState.make(...)` initializer:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const cache =
|
|
90
|
+
yield *
|
|
91
|
+
InstanceState.make<State>(
|
|
92
|
+
Effect.fn("Foo.state")(function* () {
|
|
93
|
+
const bus = yield* Bus.Service
|
|
94
|
+
|
|
95
|
+
yield* bus.subscribeAll().pipe(
|
|
96
|
+
Stream.runForEach((event) => handleEvent(event)),
|
|
97
|
+
Effect.forkScoped,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
yield* Effect.acquireRelease(openResource, closeResource)
|
|
101
|
+
|
|
102
|
+
return yield* loadInitialState()
|
|
103
|
+
}),
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Do not add separate `started` flags on top of `InstanceState`. Let
|
|
108
|
+
`ScopedCache` handle run-once and deduplication.
|
|
109
|
+
|
|
110
|
+
To make `init()` non-blocking, fork at the caller/bootstrap boundary. Do
|
|
111
|
+
not fork inside `InstanceState.make(...)` just to return early with
|
|
112
|
+
partially initialized state.
|
|
113
|
+
|
|
114
|
+
## Errors
|
|
115
|
+
|
|
116
|
+
Expected domain failures belong on the Effect error channel. Defects are
|
|
117
|
+
for bugs, impossible states, and final unknown-boundary fallbacks.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
export class SessionBusyError extends Schema.TaggedErrorClass<SessionBusyError>()("SessionBusyError", {
|
|
121
|
+
sessionID: SessionID,
|
|
122
|
+
message: Schema.String,
|
|
123
|
+
}) {}
|
|
124
|
+
|
|
125
|
+
export type Error = Storage.Error | SessionBusyError
|
|
126
|
+
|
|
127
|
+
export interface Interface {
|
|
128
|
+
readonly get: (id: SessionID) => Effect.Effect<Info, Error>
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Rules:
|
|
133
|
+
|
|
134
|
+
- Use `Schema.TaggedErrorClass` for new expected domain errors.
|
|
135
|
+
- Export a domain-level `Error` union from service modules.
|
|
136
|
+
- In `Effect.gen` / `Effect.fn`, prefer `yield* new MyError(...)` for
|
|
137
|
+
direct expected failures.
|
|
138
|
+
- Use `Schema.Defect` for unknown cause fields.
|
|
139
|
+
- Use `Effect.try(...)`, `Effect.tryPromise(...)`, `Effect.mapError`,
|
|
140
|
+
`Effect.catchTag`, and `Effect.catchTags` to translate external
|
|
141
|
+
failures into domain errors.
|
|
142
|
+
- Do not use `Effect.die(...)` for user, IO, validation, missing-resource,
|
|
143
|
+
auth, provider, or busy-state failures.
|
|
144
|
+
|
|
145
|
+
## HTTP Error Boundaries
|
|
146
|
+
|
|
147
|
+
Service modules stay HTTP-agnostic. They should not import HTTP status
|
|
148
|
+
codes, `HttpApiError`, `HttpServerResponse`, or route-specific error
|
|
149
|
+
schemas.
|
|
150
|
+
|
|
151
|
+
HTTP handlers translate service errors into endpoint-declared public error
|
|
152
|
+
schemas. Keep mappings inline when they are one-off; extract tiny shared
|
|
153
|
+
helpers only when the same translation repeats.
|
|
154
|
+
|
|
155
|
+
Do not turn generic middleware into a registry of domain errors. Middleware
|
|
156
|
+
should handle cross-cutting concerns and the final unknown-defect fallback.
|
|
157
|
+
|
|
158
|
+
Preserve legacy public wire shapes, such as `{ name, data }`, until a
|
|
159
|
+
deliberate breaking API change.
|
|
160
|
+
|
|
161
|
+
## Schemas
|
|
162
|
+
|
|
163
|
+
Use Effect Schema as the source of truth.
|
|
164
|
+
|
|
165
|
+
- Use `Schema.Class` for exported data objects with a clear identity.
|
|
166
|
+
- Use `Schema.Struct` for local shapes and simple nested objects.
|
|
167
|
+
- Use `Schema.brand` for single-value IDs.
|
|
168
|
+
- Reuse named refinements instead of re-spelling constraints.
|
|
169
|
+
- Prefer narrow boundary helpers over generic Schema-to-Zod bridges.
|
|
170
|
+
|
|
171
|
+
Intentional boundaries:
|
|
172
|
+
|
|
173
|
+
- Public plugin tools still expose Zod through `tool.schema = z`.
|
|
174
|
+
- Tool parameter JSON Schema is generated through tool-specific helpers.
|
|
175
|
+
- Public config and TUI schemas are generated through the schema script.
|
|
176
|
+
|
|
177
|
+
## Preferred Services
|
|
178
|
+
|
|
179
|
+
In effectified code, yield existing services instead of dropping to ad hoc
|
|
180
|
+
platform APIs.
|
|
181
|
+
|
|
182
|
+
- Use `FSUtil.Service` instead of raw `fs/promises` for app file IO.
|
|
183
|
+
- Use `AppProcess.Service` instead of direct `ChildProcessSpawner.spawn` or
|
|
184
|
+
legacy process helpers.
|
|
185
|
+
- Use `HttpClient.HttpClient` instead of raw `fetch` inside Effect code.
|
|
186
|
+
- Use `Path.Path`, `Config`, `Clock`, and `DateTime` when already inside
|
|
187
|
+
Effect.
|
|
188
|
+
- Use `Effect.callback` for callback-based APIs.
|
|
189
|
+
- Use `Effect.void` instead of `Effect.succeed(undefined)`.
|
|
190
|
+
- Use `Effect.cached` when concurrent callers should share one in-flight
|
|
191
|
+
computation.
|
|
192
|
+
|
|
193
|
+
For background loops, use `Effect.repeat` or `Effect.schedule` with
|
|
194
|
+
`Effect.forkScoped` in the owning layer/state scope.
|
|
195
|
+
|
|
196
|
+
## Promise And ALS Bridges
|
|
197
|
+
|
|
198
|
+
[`EffectBridge`](../../src/effect/bridge.ts) is the sanctioned helper for
|
|
199
|
+
Promise/callback interop that needs to preserve instance/workspace context.
|
|
200
|
+
It preserves explicit `InstanceRef` / `WorkspaceRef` context for effects run
|
|
201
|
+
through the bridge. Plain JS callbacks that need instance data should receive
|
|
202
|
+
that data explicitly.
|
|
203
|
+
|
|
204
|
+
## Testing
|
|
205
|
+
|
|
206
|
+
Detailed test migration rules live in
|
|
207
|
+
[`test/EFFECT_TEST_MIGRATION.md`](../../test/EFFECT_TEST_MIGRATION.md).
|
|
208
|
+
|
|
209
|
+
Core pattern:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const it = testEffect(Layer.mergeAll(MyService.defaultLayer))
|
|
213
|
+
|
|
214
|
+
describe("my service", () => {
|
|
215
|
+
it.instance("does the thing", () =>
|
|
216
|
+
Effect.gen(function* () {
|
|
217
|
+
const svc = yield* MyService.Service
|
|
218
|
+
expect(yield* svc.run()).toEqual("ok")
|
|
219
|
+
}),
|
|
220
|
+
)
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Rules:
|
|
225
|
+
|
|
226
|
+
- Use `it.effect(...)` for TestClock/TestConsole tests.
|
|
227
|
+
- Use `it.live(...)` for real timers, filesystem mtimes, child processes,
|
|
228
|
+
git, locks, or other live integration behavior.
|
|
229
|
+
- Use `it.instance(...)` for service tests that need a scoped instance.
|
|
230
|
+
- Prefer Effect-aware fixtures from `test/fixture/fixture.ts`.
|
|
231
|
+
- Avoid sleeps; wait for real events or deterministic state transitions.
|
|
232
|
+
- Avoid mutable `process.env`, `Flag`, or module-global changes after
|
|
233
|
+
layers are built.
|
|
234
|
+
- Use `Layer.mock` for partial service stubs.
|
|
235
|
+
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` test
|
|
236
|
+
wrappers.
|
|
237
|
+
|
|
238
|
+
## Verification
|
|
239
|
+
|
|
240
|
+
From `packages/openfork`:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
bun run typecheck
|
|
244
|
+
bun run test -- path/to/test.ts
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Do not run tests from the repo root; the repo has a guard for that.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Instance Context
|
|
2
|
+
|
|
3
|
+
Instance selection is now Effect-provided context.
|
|
4
|
+
|
|
5
|
+
Use these APIs:
|
|
6
|
+
|
|
7
|
+
- `InstanceRef` for the current project context.
|
|
8
|
+
- `WorkspaceRef` for the current workspace id.
|
|
9
|
+
- `InstanceState.context` / `InstanceState.directory` inside Effect services that require an instance.
|
|
10
|
+
- `InstanceStore` at entry boundaries that need to load, reload, or dispose project contexts.
|
|
11
|
+
- `EffectBridge` for native, plugin, or plain JavaScript callback boundaries that need to re-enter Effect with captured refs.
|
|
12
|
+
|
|
13
|
+
Do not add new ambient instance globals. Promise and callback boundaries should either stay in Effect, use `EffectBridge`, or pass the required context explicitly.
|