rimuru-ai 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rimuru/AGENTS.md +30 -0
- package/.rimuru/agents/backend.md +27 -0
- package/.rimuru/agents/database.md +31 -0
- package/.rimuru/agents/devops.md +30 -0
- package/.rimuru/agents/document-prep.md +49 -0
- package/.rimuru/agents/erp-architect.md +41 -0
- package/.rimuru/agents/ethical-hacking.md +49 -0
- package/.rimuru/agents/frontend.md +31 -0
- package/.rimuru/agents/fullstack.md +24 -0
- package/.rimuru/agents/system-engineer.md +31 -0
- package/.rimuru/agents/veldora-agent-tool-dev.md +30 -0
- package/.rimuru/agents/veldora-backend-dev.md +32 -0
- package/.rimuru/agents/veldora-cicd.md +32 -0
- package/.rimuru/agents/veldora-database.md +32 -0
- package/.rimuru/agents/veldora-doc.md +87 -0
- package/.rimuru/agents/veldora-frontend-dev.md +32 -0
- package/.rimuru/agents/veldora-great-sage.md +33 -0
- package/.rimuru/agents/veldora-mcp-creator.md +30 -0
- package/.rimuru/agents/veldora-pro.md +224 -0
- package/.rimuru/agents/veldora-prompt-enhancer.md +27 -0
- package/.rimuru/agents/veldora-skill-creator.md +28 -0
- package/.rimuru/agents/veldora.md +225 -0
- package/.rimuru/agents/veldorapro-agent-tool-dev.md +29 -0
- package/.rimuru/agents/veldorapro-backend-dev.md +29 -0
- package/.rimuru/agents/veldorapro-cicd.md +29 -0
- package/.rimuru/agents/veldorapro-database.md +29 -0
- package/.rimuru/agents/veldorapro-frontend-dev.md +29 -0
- package/.rimuru/agents/veldorapro-great-sage.md +33 -0
- package/.rimuru/agents/veldorapro-mcp-creator.md +27 -0
- package/.rimuru/agents/veldorapro-prompt-enhancer.md +25 -0
- package/.rimuru/agents/veldorapro-skill-creator.md +27 -0
- package/.rimuru/command/ai-deps.md +24 -0
- package/.rimuru/command/changelog.md +49 -0
- package/.rimuru/command/commit.md +37 -0
- package/.rimuru/command/issues.md +23 -0
- package/.rimuru/command/learn.md +42 -0
- package/.rimuru/command/rmslop.md +15 -0
- package/.rimuru/command/spellcheck.md +5 -0
- package/.rimuru/command/translate.md +14 -0
- package/.rimuru/glossary/README.md +63 -0
- package/.rimuru/glossary/ar.md +28 -0
- package/.rimuru/glossary/br.md +34 -0
- package/.rimuru/glossary/bs.md +33 -0
- package/.rimuru/glossary/da.md +27 -0
- package/.rimuru/glossary/de.md +27 -0
- package/.rimuru/glossary/es.md +27 -0
- package/.rimuru/glossary/fr.md +27 -0
- package/.rimuru/glossary/ja.md +33 -0
- package/.rimuru/glossary/ko.md +27 -0
- package/.rimuru/glossary/no.md +38 -0
- package/.rimuru/glossary/pl.md +27 -0
- package/.rimuru/glossary/ru.md +27 -0
- package/.rimuru/glossary/th.md +34 -0
- package/.rimuru/glossary/tr.md +38 -0
- package/.rimuru/glossary/zh-cn.md +42 -0
- package/.rimuru/glossary/zh-tw.md +42 -0
- package/.rimuru/improver/changelog.md +250 -0
- package/.rimuru/improver/knowledge.md +172 -0
- package/.rimuru/improver/plugins.md +21 -0
- package/.rimuru/improver/skills.md +60 -0
- package/.rimuru/improver/token-audit.md +21 -0
- package/.rimuru/opencode.jsonc +140 -0
- package/.rimuru/plugins/smoke-theme.json +223 -0
- package/.rimuru/plugins/tui-smoke.tsx +1019 -0
- package/.rimuru/skills/effect/SKILL.md +38 -0
- package/.rimuru/themes/mytheme.json +223 -0
- package/.rimuru/tool/github-pr-search.ts +64 -0
- package/.rimuru/tool/github-triage.ts +60 -0
- package/README.md +31 -0
- package/package.json +167 -0
- package/src/account/account.ts +463 -0
- package/src/account/repo.ts +173 -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 +250 -0
- package/src/acp/directory.ts +210 -0
- package/src/acp/error.ts +90 -0
- package/src/acp/event.ts +342 -0
- package/src/acp/permission.ts +124 -0
- package/src/acp/profile.ts +42 -0
- package/src/acp/service.ts +1048 -0
- package/src/acp/session.ts +231 -0
- package/src/acp/tool.ts +367 -0
- package/src/acp/usage.ts +232 -0
- package/src/agent/agent.ts +459 -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/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 +99 -0
- package/src/background/job.ts +39 -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 +97 -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 +15 -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 +49 -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 +850 -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 +173 -0
- package/src/cli/cmd/run/footer.ts +1129 -0
- package/src/cli/cmd/run/footer.view.tsx +943 -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 +1489 -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 +215 -0
- package/src/cli/cmd/run.ts +894 -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 +224 -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 +64 -0
- package/src/cli/tui/layer.ts +7 -0
- package/src/cli/tui/validate-session.ts +29 -0
- package/src/cli/tui/worker.ts +71 -0
- package/src/cli/ui.ts +98 -0
- package/src/cli/upgrade.ts +53 -0
- package/src/command/index.ts +184 -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 +686 -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 +274 -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 +989 -0
- package/src/effect/app-runtime.ts +132 -0
- package/src/effect/bootstrap-runtime.ts +23 -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 +79 -0
- package/src/env/index.ts +43 -0
- package/src/event-v2-bridge.ts +79 -0
- package/src/format/formatter.ts +404 -0
- package/src/format/index.ts +205 -0
- package/src/git/index.ts +350 -0
- package/src/id/id.ts +80 -0
- package/src/ide/index.ts +61 -0
- package/src/image/image.ts +174 -0
- package/src/index.ts +142 -0
- package/src/installation/index.ts +350 -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 +511 -0
- package/src/lsp/server.ts +1983 -0
- package/src/markdown.d.ts +4 -0
- package/src/mcp/auth.ts +174 -0
- package/src/mcp/catalog.ts +153 -0
- package/src/mcp/index.ts +946 -0
- package/src/mcp/oauth-callback.ts +233 -0
- package/src/mcp/oauth-provider.ts +206 -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 +230 -0
- package/src/plugin/azure.ts +26 -0
- package/src/plugin/cloudflare.ts +76 -0
- package/src/plugin/digitalocean.ts +383 -0
- package/src/plugin/github-copilot/copilot.ts +413 -0
- package/src/plugin/github-copilot/models.ts +246 -0
- package/src/plugin/index.ts +316 -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 +641 -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 +529 -0
- package/src/plugin/tui/internal.ts +10 -0
- package/src/plugin/tui/runtime.ts +1130 -0
- package/src/plugin/xai.ts +716 -0
- package/src/project/bootstrap-service.ts +9 -0
- package/src/project/bootstrap.ts +76 -0
- package/src/project/instance-context.ts +24 -0
- package/src/project/instance-layer.ts +11 -0
- package/src/project/instance-runtime.ts +16 -0
- package/src/project/instance-store.ts +209 -0
- package/src/project/project.ts +519 -0
- package/src/project/vcs.ts +431 -0
- package/src/provider/auth.ts +233 -0
- package/src/provider/error.ts +188 -0
- package/src/provider/model-status.ts +8 -0
- package/src/provider/provider.ts +1979 -0
- package/src/provider/transform.ts +1426 -0
- package/src/question/index.ts +229 -0
- package/src/question/schema.ts +10 -0
- package/src/server/auth.ts +48 -0
- package/src/server/event.ts +13 -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 +78 -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 +260 -0
- package/src/server/routes/instance/httpapi/groups/file.ts +185 -0
- package/src/server/routes/instance/httpapi/groups/global.ts +138 -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 +187 -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 +440 -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 +535 -0
- package/src/server/routes/instance/httpapi/server.ts +298 -0
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +57 -0
- package/src/server/server.ts +225 -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 +122 -0
- package/src/server/shared/workspace-routing.ts +38 -0
- package/src/server/tui-event.ts +53 -0
- package/src/session/compaction.ts +620 -0
- package/src/session/instruction.ts +241 -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 +196 -0
- package/src/session/llm/request.ts +218 -0
- package/src/session/llm.ts +415 -0
- package/src/session/message-error.ts +14 -0
- package/src/session/message-v2.ts +744 -0
- package/src/session/message.ts +148 -0
- package/src/session/overflow.ts +34 -0
- package/src/session/processor.ts +1084 -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/max-steps.txt +16 -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 +1722 -0
- package/src/session/reminders.ts +92 -0
- package/src/session/retry.ts +201 -0
- package/src/session/revert.ts +160 -0
- package/src/session/run-state.ts +156 -0
- package/src/session/schema.ts +26 -0
- package/src/session/session.ts +1119 -0
- package/src/session/status.ts +97 -0
- package/src/session/summary.ts +165 -0
- package/src/session/system.ts +117 -0
- package/src/session/todo.ts +90 -0
- package/src/session/tools.ts +207 -0
- package/src/share/session.ts +61 -0
- package/src/share/share-next.ts +385 -0
- package/src/skill/discovery.ts +109 -0
- package/src/skill/index.ts +366 -0
- package/src/snapshot/index.ts +808 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/schema.ts +5 -0
- package/src/storage/storage.ts +329 -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/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 +440 -0
- package/src/tool/schema.ts +14 -0
- package/src/tool/shell/id.ts +19 -0
- package/src/tool/shell/prompt.ts +307 -0
- package/src/tool/shell/shell.txt +21 -0
- package/src/tool/shell.ts +657 -0
- package/src/tool/skill.ts +71 -0
- package/src/tool/skill.txt +5 -0
- package/src/tool/task.ts +346 -0
- package/src/tool/task.txt +19 -0
- package/src/tool/todo.ts +57 -0
- package/src/tool/todowrite.txt +44 -0
- package/src/tool/tool.ts +183 -0
- package/src/tool/truncate.ts +158 -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 +654 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { EventV2Bridge } from "@/event-v2-bridge"
|
|
2
|
+
import { TuiEvent } from "@/server/tui-event"
|
|
3
|
+
import { Session } from "@/session/session"
|
|
4
|
+
import { Effect } from "effect"
|
|
5
|
+
import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
|
|
6
|
+
import { nextTuiRequest, submitTuiResponse } from "@/server/shared/tui-control"
|
|
7
|
+
import { InstanceHttpApi } from "../api"
|
|
8
|
+
import { CommandPayload, TuiPublishPayload } from "../groups/tui"
|
|
9
|
+
import * as SessionError from "./session-errors"
|
|
10
|
+
|
|
11
|
+
const commandAliases = {
|
|
12
|
+
session_new: "session.new",
|
|
13
|
+
session_share: "session.share",
|
|
14
|
+
session_interrupt: "session.interrupt",
|
|
15
|
+
session_compact: "session.compact",
|
|
16
|
+
messages_page_up: "session.page.up",
|
|
17
|
+
messages_page_down: "session.page.down",
|
|
18
|
+
messages_line_up: "session.line.up",
|
|
19
|
+
messages_line_down: "session.line.down",
|
|
20
|
+
messages_half_page_up: "session.half.page.up",
|
|
21
|
+
messages_half_page_down: "session.half.page.down",
|
|
22
|
+
messages_first: "session.first",
|
|
23
|
+
messages_last: "session.last",
|
|
24
|
+
agent_cycle: "agent.cycle",
|
|
25
|
+
} as const
|
|
26
|
+
|
|
27
|
+
export const tuiHandlers = HttpApiBuilder.group(InstanceHttpApi, "tui", (handlers) =>
|
|
28
|
+
Effect.gen(function* () {
|
|
29
|
+
const events = yield* EventV2Bridge.Service
|
|
30
|
+
const session = yield* Session.Service
|
|
31
|
+
const publishCommand = (command: typeof TuiEvent.CommandExecute.data.Type.command | undefined) =>
|
|
32
|
+
events.publish(TuiEvent.CommandExecute, { command } as typeof TuiEvent.CommandExecute.data.Type)
|
|
33
|
+
|
|
34
|
+
const appendPrompt = Effect.fn("TuiHttpApi.appendPrompt")(function* (ctx: {
|
|
35
|
+
payload: typeof TuiEvent.PromptAppend.data.Type
|
|
36
|
+
}) {
|
|
37
|
+
yield* events.publish(TuiEvent.PromptAppend, ctx.payload)
|
|
38
|
+
return true
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const openHelp = Effect.fn("TuiHttpApi.openHelp")(function* () {
|
|
42
|
+
yield* publishCommand("help.show")
|
|
43
|
+
return true
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const openSessions = Effect.fn("TuiHttpApi.openSessions")(function* () {
|
|
47
|
+
yield* publishCommand("session.list")
|
|
48
|
+
return true
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const openThemes = Effect.fn("TuiHttpApi.openThemes")(function* () {
|
|
52
|
+
yield* publishCommand("session.list")
|
|
53
|
+
return true
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const openModels = Effect.fn("TuiHttpApi.openModels")(function* () {
|
|
57
|
+
yield* publishCommand("model.list")
|
|
58
|
+
return true
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const submitPrompt = Effect.fn("TuiHttpApi.submitPrompt")(function* () {
|
|
62
|
+
yield* publishCommand("prompt.submit")
|
|
63
|
+
return true
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const clearPrompt = Effect.fn("TuiHttpApi.clearPrompt")(function* () {
|
|
67
|
+
yield* publishCommand("prompt.clear")
|
|
68
|
+
return true
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const executeCommand = Effect.fn("TuiHttpApi.executeCommand")(function* (ctx: {
|
|
72
|
+
payload: typeof CommandPayload.Type
|
|
73
|
+
}) {
|
|
74
|
+
// Legacy only publishes known aliases; unknown commands become undefined.
|
|
75
|
+
yield* publishCommand(commandAliases[ctx.payload.command as keyof typeof commandAliases])
|
|
76
|
+
return true
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const showToast = Effect.fn("TuiHttpApi.showToast")(function* (ctx: {
|
|
80
|
+
payload: typeof TuiEvent.ToastShow.data.Type
|
|
81
|
+
}) {
|
|
82
|
+
yield* events.publish(TuiEvent.ToastShow, ctx.payload)
|
|
83
|
+
return true
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const publish = Effect.fn("TuiHttpApi.publish")(function* (ctx: { payload: typeof TuiPublishPayload.Type }) {
|
|
87
|
+
if (ctx.payload.type === TuiEvent.PromptAppend.type)
|
|
88
|
+
yield* events.publish(TuiEvent.PromptAppend, ctx.payload.properties)
|
|
89
|
+
if (ctx.payload.type === TuiEvent.CommandExecute.type)
|
|
90
|
+
yield* events.publish(TuiEvent.CommandExecute, ctx.payload.properties)
|
|
91
|
+
if (ctx.payload.type === TuiEvent.ToastShow.type)
|
|
92
|
+
yield* events.publish(TuiEvent.ToastShow, ctx.payload.properties)
|
|
93
|
+
if (ctx.payload.type === TuiEvent.SessionSelect.type)
|
|
94
|
+
yield* events.publish(TuiEvent.SessionSelect, ctx.payload.properties)
|
|
95
|
+
return true
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const selectSession = Effect.fn("TuiHttpApi.selectSession")(function* (ctx: {
|
|
99
|
+
payload: typeof TuiEvent.SessionSelect.data.Type
|
|
100
|
+
}) {
|
|
101
|
+
if (!ctx.payload.sessionID.startsWith("ses")) return yield* new HttpApiError.BadRequest({})
|
|
102
|
+
yield* SessionError.mapStorageNotFound(session.get(ctx.payload.sessionID))
|
|
103
|
+
yield* events.publish(TuiEvent.SessionSelect, ctx.payload)
|
|
104
|
+
return true
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const controlNext = Effect.fn("TuiHttpApi.controlNext")(function* () {
|
|
108
|
+
return yield* Effect.promise(() => nextTuiRequest())
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const controlResponse = Effect.fn("TuiHttpApi.controlResponse")(function* (ctx: { payload: unknown }) {
|
|
112
|
+
submitTuiResponse(ctx.payload)
|
|
113
|
+
return true
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return handlers
|
|
117
|
+
.handle("appendPrompt", appendPrompt)
|
|
118
|
+
.handle("openHelp", openHelp)
|
|
119
|
+
.handle("openSessions", openSessions)
|
|
120
|
+
.handle("openThemes", openThemes)
|
|
121
|
+
.handle("openModels", openModels)
|
|
122
|
+
.handle("submitPrompt", submitPrompt)
|
|
123
|
+
.handle("clearPrompt", clearPrompt)
|
|
124
|
+
.handle("executeCommand", executeCommand)
|
|
125
|
+
.handle("showToast", showToast)
|
|
126
|
+
.handle("publish", publish)
|
|
127
|
+
.handle("selectSession", selectSession)
|
|
128
|
+
.handle("controlNext", controlNext)
|
|
129
|
+
.handle("controlResponse", controlResponse)
|
|
130
|
+
}),
|
|
131
|
+
)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { listAdapters } from "@/control-plane/adapters"
|
|
2
|
+
import { Workspace } from "@/control-plane/workspace"
|
|
3
|
+
import * as InstanceState from "@/effect/instance-state"
|
|
4
|
+
import { Vcs } from "@/project/vcs"
|
|
5
|
+
import { Cause, Effect } from "effect"
|
|
6
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
|
7
|
+
import { InstanceHttpApi } from "../api"
|
|
8
|
+
import { notFound } from "../errors"
|
|
9
|
+
import { ApiVcsApplyError } from "../groups/instance"
|
|
10
|
+
import { ApiWorkspaceCreateError, ApiWorkspaceWarpError, CreatePayload, WarpPayload } from "../groups/workspace"
|
|
11
|
+
|
|
12
|
+
export const workspaceHandlers = HttpApiBuilder.group(InstanceHttpApi, "workspace", (handlers) =>
|
|
13
|
+
Effect.gen(function* () {
|
|
14
|
+
const workspace = yield* Workspace.Service
|
|
15
|
+
|
|
16
|
+
const adapters = Effect.fn("WorkspaceHttpApi.adapters")(function* () {
|
|
17
|
+
const instance = yield* InstanceState.context
|
|
18
|
+
return yield* Effect.sync(() => listAdapters(instance.project.id))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const list = Effect.fn("WorkspaceHttpApi.list")(function* () {
|
|
22
|
+
return yield* workspace.list((yield* InstanceState.context).project)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const create = Effect.fn("WorkspaceHttpApi.create")(function* (ctx: { payload: typeof CreatePayload.Type }) {
|
|
26
|
+
const instance = yield* InstanceState.context
|
|
27
|
+
return yield* workspace
|
|
28
|
+
.create({
|
|
29
|
+
...ctx.payload,
|
|
30
|
+
extra: ctx.payload.extra ?? null,
|
|
31
|
+
projectID: instance.project.id,
|
|
32
|
+
})
|
|
33
|
+
.pipe(
|
|
34
|
+
Effect.catchCause((cause) => {
|
|
35
|
+
// Plugin throws surface as defects (because EffectBridge.fromPromise uses Effect.promise),
|
|
36
|
+
// bypassing Effect.mapError. Walk the cause to surface the real error to the client.
|
|
37
|
+
const die = cause.reasons.find(Cause.isDieReason)
|
|
38
|
+
const fail = cause.reasons.find(Cause.isFailReason)
|
|
39
|
+
const reason: unknown = die?.defect ?? fail?.error
|
|
40
|
+
const message = reason instanceof Error ? reason.message : "Workspace creation failed"
|
|
41
|
+
return Effect.fail(
|
|
42
|
+
new ApiWorkspaceCreateError({
|
|
43
|
+
name: "WorkspaceCreateError",
|
|
44
|
+
data: { message },
|
|
45
|
+
}),
|
|
46
|
+
)
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const syncList = Effect.fn("WorkspaceHttpApi.syncList")(function* () {
|
|
52
|
+
yield* workspace.syncList((yield* InstanceState.context).project)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const status = Effect.fn("WorkspaceHttpApi.status")(function* () {
|
|
56
|
+
const ids = new Set((yield* workspace.list((yield* InstanceState.context).project)).map((item) => item.id))
|
|
57
|
+
return (yield* workspace.status()).filter((item) => ids.has(item.workspaceID))
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const remove = Effect.fn("WorkspaceHttpApi.remove")(function* (ctx: { params: { id: Workspace.Info["id"] } }) {
|
|
61
|
+
return yield* workspace.remove(ctx.params.id)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const warp = Effect.fn("WorkspaceHttpApi.warp")(function* (ctx: { payload: typeof WarpPayload.Type }) {
|
|
65
|
+
yield* workspace
|
|
66
|
+
.sessionWarp({
|
|
67
|
+
workspaceID: ctx.payload.id,
|
|
68
|
+
sessionID: ctx.payload.sessionID,
|
|
69
|
+
copyChanges: ctx.payload.copyChanges,
|
|
70
|
+
})
|
|
71
|
+
.pipe(
|
|
72
|
+
Effect.mapError((error) => {
|
|
73
|
+
if (error instanceof Workspace.WorkspaceNotFoundError) return notFound(error.message)
|
|
74
|
+
if (error instanceof Vcs.PatchApplyError) {
|
|
75
|
+
return new ApiVcsApplyError({
|
|
76
|
+
name: "VcsApplyError",
|
|
77
|
+
data: {
|
|
78
|
+
message: error.message,
|
|
79
|
+
reason: error.reason,
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
return new ApiWorkspaceWarpError({
|
|
84
|
+
name: "WorkspaceWarpError",
|
|
85
|
+
data: {
|
|
86
|
+
message: error.message,
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
}),
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
return handlers
|
|
94
|
+
.handle("adapters", adapters)
|
|
95
|
+
.handle("list", list)
|
|
96
|
+
.handle("create", create)
|
|
97
|
+
.handle("syncList", syncList)
|
|
98
|
+
.handle("status", status)
|
|
99
|
+
.handle("remove", remove)
|
|
100
|
+
.handle("warp", warp)
|
|
101
|
+
}),
|
|
102
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { EffectBridge } from "@/effect/bridge"
|
|
2
|
+
import type { InstanceContext } from "@/project/instance-context"
|
|
3
|
+
import { InstanceStore } from "@/project/instance-store"
|
|
4
|
+
import { Effect } from "effect"
|
|
5
|
+
import { HttpEffect, HttpMiddleware, HttpServerRequest } from "effect/unstable/http"
|
|
6
|
+
|
|
7
|
+
type MarkedInstance = {
|
|
8
|
+
ctx: InstanceContext
|
|
9
|
+
store: InstanceStore.Interface
|
|
10
|
+
bridge: EffectBridge.Shape
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Disposal is requested by an endpoint handler, but must run from the outer
|
|
14
|
+
// server middleware after the response has been produced. The original Request
|
|
15
|
+
// object is the stable handoff key between those two phases.
|
|
16
|
+
const disposeAfterResponse = new WeakMap<object, MarkedInstance>()
|
|
17
|
+
|
|
18
|
+
const mark = (ctx: InstanceContext) =>
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
return { ctx, store: yield* InstanceStore.Service, bridge: yield* EffectBridge.make() }
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export const markInstanceForDisposal = (ctx: InstanceContext) =>
|
|
24
|
+
Effect.gen(function* () {
|
|
25
|
+
const marked = yield* mark(ctx)
|
|
26
|
+
return yield* HttpEffect.appendPreResponseHandler((request, response) =>
|
|
27
|
+
Effect.sync(() => {
|
|
28
|
+
// The response is sent before disposeMiddleware performs the teardown.
|
|
29
|
+
disposeAfterResponse.set(request.source, marked)
|
|
30
|
+
return response
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const markInstanceForReload = (ctx: InstanceContext, next: InstanceStore.LoadInput) =>
|
|
36
|
+
Effect.gen(function* () {
|
|
37
|
+
const marked = yield* mark(ctx)
|
|
38
|
+
return yield* HttpEffect.appendPreResponseHandler((_request, response) =>
|
|
39
|
+
Effect.as(Effect.uninterruptible(marked.bridge.run(marked.store.reload(next))), response),
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export const disposeMiddleware: HttpMiddleware.HttpMiddleware = (effect) =>
|
|
44
|
+
Effect.gen(function* () {
|
|
45
|
+
const response = yield* effect
|
|
46
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
47
|
+
const marked = disposeAfterResponse.get(request.source)
|
|
48
|
+
if (!marked) return response
|
|
49
|
+
disposeAfterResponse.delete(request.source)
|
|
50
|
+
yield* Effect.uninterruptible(marked.bridge.run(marked.store.dispose(marked.ctx))).pipe(
|
|
51
|
+
Effect.catchCause((cause) => Effect.logWarning("instance disposal failed", { cause })),
|
|
52
|
+
)
|
|
53
|
+
return response
|
|
54
|
+
})
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { ServerAuth } from "@/server/auth"
|
|
2
|
+
import { Effect, Encoding, Layer, Redacted } from "effect"
|
|
3
|
+
import { HttpEffect, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
|
4
|
+
import { HttpApiError, HttpApiMiddleware } from "effect/unstable/httpapi"
|
|
5
|
+
import { hasPtyConnectTicketURL } from "@/server/shared/pty-ticket"
|
|
6
|
+
import { isPublicUIPath } from "@/server/shared/public-ui"
|
|
7
|
+
export {
|
|
8
|
+
Authorization as ServerAuthorization,
|
|
9
|
+
authorizationLayer as serverAuthorizationLayer,
|
|
10
|
+
} from "@rimurucode-ai/server/middleware/authorization"
|
|
11
|
+
|
|
12
|
+
const AUTH_TOKEN_QUERY = "auth_token"
|
|
13
|
+
const UNAUTHORIZED = 401
|
|
14
|
+
const WWW_AUTHENTICATE = 'Basic realm="Secure Area"'
|
|
15
|
+
|
|
16
|
+
// Avoid HttpApiSecurity alternatives here: Effect security middleware wraps the
|
|
17
|
+
// full handler, so a downstream failure can make the next auth alternative run
|
|
18
|
+
// and remap an authorized NotFound into Unauthorized.
|
|
19
|
+
export class Authorization extends HttpApiMiddleware.Service<Authorization>()(
|
|
20
|
+
"@rimuru/ExperimentalHttpApiAuthorization",
|
|
21
|
+
{
|
|
22
|
+
error: HttpApiError.UnauthorizedNoContent,
|
|
23
|
+
},
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
export class PtyConnectAuthorization extends HttpApiMiddleware.Service<PtyConnectAuthorization>()(
|
|
27
|
+
"@rimuru/ExperimentalHttpApiPtyConnectAuthorization",
|
|
28
|
+
{
|
|
29
|
+
error: HttpApiError.UnauthorizedNoContent,
|
|
30
|
+
},
|
|
31
|
+
) {}
|
|
32
|
+
|
|
33
|
+
function emptyCredential() {
|
|
34
|
+
return {
|
|
35
|
+
username: "",
|
|
36
|
+
password: Redacted.make(""),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function validateCredential<A, E, R>(
|
|
41
|
+
effect: Effect.Effect<A, E, R>,
|
|
42
|
+
credential: ServerAuth.DecodedCredentials,
|
|
43
|
+
config: ServerAuth.Info,
|
|
44
|
+
) {
|
|
45
|
+
return Effect.gen(function* () {
|
|
46
|
+
if (!ServerAuth.required(config)) return yield* effect
|
|
47
|
+
if (!ServerAuth.authorized(credential, config)) {
|
|
48
|
+
yield* HttpEffect.appendPreResponseHandler((_request, response) =>
|
|
49
|
+
Effect.succeed(HttpServerResponse.setHeader(response, "www-authenticate", WWW_AUTHENTICATE)),
|
|
50
|
+
)
|
|
51
|
+
return yield* new HttpApiError.Unauthorized({})
|
|
52
|
+
}
|
|
53
|
+
return yield* effect
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function decodeCredential(input: string) {
|
|
58
|
+
return Effect.fromResult(Encoding.decodeBase64String(input)).pipe(
|
|
59
|
+
Effect.match({
|
|
60
|
+
onFailure: emptyCredential,
|
|
61
|
+
onSuccess: (header) => {
|
|
62
|
+
const separator = header.indexOf(":")
|
|
63
|
+
if (separator === -1) return emptyCredential()
|
|
64
|
+
return {
|
|
65
|
+
username: header.slice(0, separator),
|
|
66
|
+
password: Redacted.make(header.slice(separator + 1)),
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function credentialFromRequest(request: HttpServerRequest.HttpServerRequest) {
|
|
74
|
+
return credentialFromURL(new URL(request.url, "http://localhost"), request)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function credentialFromURL(url: URL, request: HttpServerRequest.HttpServerRequest) {
|
|
78
|
+
const token = url.searchParams.get(AUTH_TOKEN_QUERY)
|
|
79
|
+
if (token) return decodeCredential(token)
|
|
80
|
+
const match = /^Basic\s+(.+)$/i.exec(request.headers.authorization ?? "")
|
|
81
|
+
if (match) return decodeCredential(match[1])
|
|
82
|
+
return Effect.succeed(emptyCredential())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function validateRawCredential<A, E, R>(
|
|
86
|
+
effect: Effect.Effect<A, E, R>,
|
|
87
|
+
credential: ServerAuth.DecodedCredentials,
|
|
88
|
+
config: ServerAuth.Info,
|
|
89
|
+
) {
|
|
90
|
+
if (!ServerAuth.required(config)) return effect
|
|
91
|
+
if (!ServerAuth.authorized(credential, config))
|
|
92
|
+
return Effect.succeed(
|
|
93
|
+
HttpServerResponse.empty({
|
|
94
|
+
status: UNAUTHORIZED,
|
|
95
|
+
headers: { "www-authenticate": WWW_AUTHENTICATE },
|
|
96
|
+
}),
|
|
97
|
+
)
|
|
98
|
+
return effect
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const authorizationRouterMiddleware = HttpRouter.middleware()(
|
|
102
|
+
Effect.gen(function* () {
|
|
103
|
+
const config = yield* ServerAuth.Config
|
|
104
|
+
if (!ServerAuth.required(config)) return (effect) => effect
|
|
105
|
+
|
|
106
|
+
return (effect) =>
|
|
107
|
+
Effect.gen(function* () {
|
|
108
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
109
|
+
const url = new URL(request.url, "http://localhost")
|
|
110
|
+
if (isPublicUIPath(request.method, url.pathname)) return yield* effect
|
|
111
|
+
return yield* credentialFromURL(url, request).pipe(
|
|
112
|
+
Effect.flatMap((credential) => validateRawCredential(effect, credential, config)),
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
}),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
export const authorizationLayer = Layer.effect(
|
|
119
|
+
Authorization,
|
|
120
|
+
Effect.gen(function* () {
|
|
121
|
+
const config = yield* ServerAuth.Config
|
|
122
|
+
if (!ServerAuth.required(config)) return Authorization.of((effect) => effect)
|
|
123
|
+
return Authorization.of((effect) =>
|
|
124
|
+
Effect.gen(function* () {
|
|
125
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
126
|
+
return yield* credentialFromRequest(request).pipe(
|
|
127
|
+
Effect.flatMap((credential) => validateCredential(effect, credential, config)),
|
|
128
|
+
)
|
|
129
|
+
}),
|
|
130
|
+
)
|
|
131
|
+
}),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
export const ptyConnectAuthorizationLayer = Layer.effect(
|
|
135
|
+
PtyConnectAuthorization,
|
|
136
|
+
Effect.gen(function* () {
|
|
137
|
+
const config = yield* ServerAuth.Config
|
|
138
|
+
if (!ServerAuth.required(config)) return PtyConnectAuthorization.of((effect) => effect)
|
|
139
|
+
return PtyConnectAuthorization.of((effect) =>
|
|
140
|
+
Effect.gen(function* () {
|
|
141
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
142
|
+
const url = new URL(request.url, "http://localhost")
|
|
143
|
+
if (hasPtyConnectTicketURL(url)) return yield* effect
|
|
144
|
+
return yield* credentialFromURL(url, request).pipe(
|
|
145
|
+
Effect.flatMap((credential) => validateCredential(effect, credential, config)),
|
|
146
|
+
)
|
|
147
|
+
}),
|
|
148
|
+
)
|
|
149
|
+
}),
|
|
150
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { deflateSync, gzipSync } from "node:zlib"
|
|
2
|
+
import { Effect } from "effect"
|
|
3
|
+
import { HttpBody, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
|
4
|
+
|
|
5
|
+
// Keep the server's compressible content-type set stable across HTTP backend changes.
|
|
6
|
+
const COMPRESSIBLE_CONTENT_TYPE_REGEX =
|
|
7
|
+
/^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i
|
|
8
|
+
|
|
9
|
+
const NO_TRANSFORM_REGEX = /(?:^|,)\s*?no-transform\s*?(?:,|$)/i
|
|
10
|
+
|
|
11
|
+
const STREAMING_PATHS = new Set(["/event", "/global/event"])
|
|
12
|
+
const STREAMING_POST_REGEX = /^\/session\/[^/]+\/(?:message|prompt_async)$/
|
|
13
|
+
|
|
14
|
+
const THRESHOLD_BYTES = 1024
|
|
15
|
+
|
|
16
|
+
type Encoding = "gzip" | "deflate"
|
|
17
|
+
|
|
18
|
+
function pickEncoding(acceptEncoding: string | undefined): Encoding | undefined {
|
|
19
|
+
if (!acceptEncoding) return undefined
|
|
20
|
+
const lower = acceptEncoding.toLowerCase()
|
|
21
|
+
if (lower.includes("gzip")) return "gzip"
|
|
22
|
+
if (lower.includes("deflate")) return "deflate"
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function pathOf(url: string): string {
|
|
27
|
+
const queryIndex = url.indexOf("?")
|
|
28
|
+
return queryIndex === -1 ? url : url.slice(0, queryIndex)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const compressionLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) =>
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
const response = yield* effect
|
|
34
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
35
|
+
|
|
36
|
+
if (request.method === "HEAD") return response
|
|
37
|
+
if (response.headers["content-encoding"]) return response
|
|
38
|
+
if (response.headers["transfer-encoding"]) return response
|
|
39
|
+
|
|
40
|
+
const body = response.body
|
|
41
|
+
if (body._tag !== "Uint8Array") return response
|
|
42
|
+
if (body.body.byteLength < THRESHOLD_BYTES) return response
|
|
43
|
+
|
|
44
|
+
const cacheControl = response.headers["cache-control"]
|
|
45
|
+
if (cacheControl && NO_TRANSFORM_REGEX.test(cacheControl)) return response
|
|
46
|
+
|
|
47
|
+
const path = pathOf(request.url)
|
|
48
|
+
if (STREAMING_PATHS.has(path)) return response
|
|
49
|
+
if (request.method === "POST" && STREAMING_POST_REGEX.test(path)) return response
|
|
50
|
+
|
|
51
|
+
const contentType = body.contentType
|
|
52
|
+
if (!COMPRESSIBLE_CONTENT_TYPE_REGEX.test(contentType)) return response
|
|
53
|
+
|
|
54
|
+
const encoding = pickEncoding(request.headers["accept-encoding"])
|
|
55
|
+
if (!encoding) return response
|
|
56
|
+
|
|
57
|
+
const compressed = encoding === "gzip" ? gzipSync(body.body) : deflateSync(body.body)
|
|
58
|
+
return HttpServerResponse.setHeader(
|
|
59
|
+
HttpServerResponse.setBody(response, HttpBody.uint8Array(compressed, contentType)),
|
|
60
|
+
"content-encoding",
|
|
61
|
+
encoding,
|
|
62
|
+
)
|
|
63
|
+
}),
|
|
64
|
+
).layer
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import { HttpRouter, HttpServerResponse } from "effect/unstable/http"
|
|
3
|
+
|
|
4
|
+
// effect-smol's HttpMiddleware.cors builds OPTIONS preflight responses by
|
|
5
|
+
// spreading allowOrigin() and allowHeaders() into the same record. Both set
|
|
6
|
+
// the `vary` key, so allowHeaders' `Vary: Access-Control-Request-Headers`
|
|
7
|
+
// overwrites allowOrigin's `Vary: Origin`. With dynamic origin echoing, the
|
|
8
|
+
// missing `Vary: Origin` lets shared caches reuse a preflight cached for one
|
|
9
|
+
// origin against a different origin.
|
|
10
|
+
//
|
|
11
|
+
// TODO: upstream a fix that merges Vary values in headersFromRequestOptions
|
|
12
|
+
// (packages/effect/src/unstable/http/HttpMiddleware.ts ~line 332).
|
|
13
|
+
export const corsVaryFix = HttpRouter.middleware(
|
|
14
|
+
(effect) =>
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const response = yield* effect
|
|
17
|
+
const allowOrigin = response.headers["access-control-allow-origin"]
|
|
18
|
+
if (!allowOrigin || allowOrigin === "*") return response
|
|
19
|
+
|
|
20
|
+
const vary = response.headers["vary"]
|
|
21
|
+
if (!vary) return HttpServerResponse.setHeader(response, "vary", "Origin")
|
|
22
|
+
|
|
23
|
+
const tokens = vary.split(",").map((s) => s.trim().toLowerCase())
|
|
24
|
+
if (tokens.includes("origin") || tokens.includes("*")) return response
|
|
25
|
+
|
|
26
|
+
return HttpServerResponse.setHeader(response, "vary", `${vary}, Origin`)
|
|
27
|
+
}),
|
|
28
|
+
{ global: true },
|
|
29
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NamedError } from "@rimurucode-ai/core/util/error"
|
|
2
|
+
import { ConfigErrorV1 } from "@rimurucode-ai/core/v1/config/error"
|
|
3
|
+
import { Cause, Effect } from "effect"
|
|
4
|
+
import { HttpRouter, HttpServerError, HttpServerRespondable, HttpServerResponse } from "effect/unstable/http"
|
|
5
|
+
|
|
6
|
+
// Keep typed HttpApi failures on their declared error path; this boundary only replaces defect-only empty 500s.
|
|
7
|
+
export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) =>
|
|
8
|
+
effect.pipe(
|
|
9
|
+
Effect.catchCause((cause) => {
|
|
10
|
+
const defect = cause.reasons.filter(Cause.isDieReason).find((reason) => {
|
|
11
|
+
if (HttpServerResponse.isHttpServerResponse(reason.defect)) return false
|
|
12
|
+
if (HttpServerError.isHttpServerError(reason.defect)) return false
|
|
13
|
+
if (HttpServerRespondable.isRespondable(reason.defect)) return false
|
|
14
|
+
return true
|
|
15
|
+
})
|
|
16
|
+
if (!defect) return Effect.failCause(cause)
|
|
17
|
+
|
|
18
|
+
const error = defect.defect
|
|
19
|
+
if (
|
|
20
|
+
ConfigErrorV1.JsonError.isInstance(error) ||
|
|
21
|
+
ConfigErrorV1.InvalidError.isInstance(error) ||
|
|
22
|
+
ConfigErrorV1.FrontmatterError.isInstance(error) ||
|
|
23
|
+
ConfigErrorV1.DirectoryTypoError.isInstance(error)
|
|
24
|
+
) {
|
|
25
|
+
return Effect.succeed(HttpServerResponse.jsonUnsafe(error.toObject(), { status: 400 }))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const ref = `err_${crypto.randomUUID().slice(0, 8)}`
|
|
29
|
+
|
|
30
|
+
return Effect.logError("failed", { ref, error, cause: Cause.pretty(cause) }).pipe(
|
|
31
|
+
Effect.as(
|
|
32
|
+
HttpServerResponse.jsonUnsafe(
|
|
33
|
+
new NamedError.Unknown({
|
|
34
|
+
message: "Unexpected server error. Check server logs for details.",
|
|
35
|
+
ref,
|
|
36
|
+
}).toObject(),
|
|
37
|
+
{ status: 500 },
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
}),
|
|
42
|
+
),
|
|
43
|
+
).layer
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Flag } from "@rimurucode-ai/core/flag/flag"
|
|
2
|
+
import { Database } from "@rimurucode-ai/core/database/database"
|
|
3
|
+
import { Effect } from "effect"
|
|
4
|
+
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
|
5
|
+
import * as Fence from "@/server/shared/fence"
|
|
6
|
+
|
|
7
|
+
const ignoredMethods = new Set(["GET", "HEAD", "OPTIONS"])
|
|
8
|
+
|
|
9
|
+
export const fenceLayer = HttpRouter.middleware<{ requires: Database.Service; handles: unknown }>()(
|
|
10
|
+
Effect.gen(function* () {
|
|
11
|
+
const { db } = yield* Database.Service
|
|
12
|
+
return (effect) =>
|
|
13
|
+
Effect.gen(function* () {
|
|
14
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
15
|
+
if (!Flag.OPENCODE_WORKSPACE_ID || ignoredMethods.has(request.method)) return yield* effect
|
|
16
|
+
|
|
17
|
+
const previous = yield* Fence.load(db)
|
|
18
|
+
const response = yield* effect
|
|
19
|
+
const current = Fence.diff(previous, yield* Fence.load(db))
|
|
20
|
+
if (Object.keys(current).length === 0) return response
|
|
21
|
+
|
|
22
|
+
return HttpServerResponse.setHeader(response, Fence.HEADER, JSON.stringify(current))
|
|
23
|
+
})
|
|
24
|
+
}),
|
|
25
|
+
).layer
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { InstanceRef, WorkspaceRef } from "@/effect/instance-ref"
|
|
2
|
+
import { InstanceStore } from "@/project/instance-store"
|
|
3
|
+
import { Effect, Layer } from "effect"
|
|
4
|
+
import { HttpServerResponse } from "effect/unstable/http"
|
|
5
|
+
import { HttpApiMiddleware } from "effect/unstable/httpapi"
|
|
6
|
+
import { WorkspaceRouteContext } from "./workspace-routing"
|
|
7
|
+
|
|
8
|
+
export class InstanceContextMiddleware extends HttpApiMiddleware.Service<
|
|
9
|
+
InstanceContextMiddleware,
|
|
10
|
+
{
|
|
11
|
+
requires: WorkspaceRouteContext
|
|
12
|
+
}
|
|
13
|
+
>()("@rimuru/ExperimentalHttpApiInstanceContext") {}
|
|
14
|
+
|
|
15
|
+
function decode(input: string): string {
|
|
16
|
+
try {
|
|
17
|
+
return decodeURIComponent(input)
|
|
18
|
+
} catch {
|
|
19
|
+
return input
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function provideInstanceContext<E>(
|
|
24
|
+
effect: Effect.Effect<HttpServerResponse.HttpServerResponse, E>,
|
|
25
|
+
store: InstanceStore.Interface,
|
|
26
|
+
): Effect.Effect<HttpServerResponse.HttpServerResponse, E, WorkspaceRouteContext> {
|
|
27
|
+
return Effect.gen(function* () {
|
|
28
|
+
const route = yield* WorkspaceRouteContext
|
|
29
|
+
const ctx = yield* store.load({ directory: decode(route.directory) })
|
|
30
|
+
return yield* effect.pipe(
|
|
31
|
+
Effect.provideService(InstanceRef, ctx),
|
|
32
|
+
Effect.provideService(WorkspaceRef, route.workspaceID),
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const instanceContextLayer = Layer.effect(
|
|
38
|
+
InstanceContextMiddleware,
|
|
39
|
+
Effect.gen(function* () {
|
|
40
|
+
const store = yield* InstanceStore.Service
|
|
41
|
+
return InstanceContextMiddleware.of((effect) => provideInstanceContext(effect, store))
|
|
42
|
+
}),
|
|
43
|
+
)
|