koro-ai 1.0.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/AGENTS.md +69 -0
- package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/koro +16 -0
- package/bin/opencode +179 -0
- package/bunfig.toml +7 -0
- package/drizzle.config.ts +10 -0
- package/git +0 -0
- package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
- package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
- package/migration/20260211171708_add_project_commands/migration.sql +1 -0
- package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
- package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
- package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
- package/migration/20260225215848_workspace/migration.sql +7 -0
- package/migration/20260225215848_workspace/snapshot.json +959 -0
- package/migration/20260227213759_add_session_workspace_id/migration.sql +2 -0
- package/migration/20260227213759_add_session_workspace_id/snapshot.json +983 -0
- package/migration/20260228203230_blue_harpoon/migration.sql +17 -0
- package/migration/20260228203230_blue_harpoon/snapshot.json +1102 -0
- package/migration/20260303231226_add_workspace_fields/migration.sql +5 -0
- package/migration/20260303231226_add_workspace_fields/snapshot.json +1013 -0
- package/migration/20260309230000_move_org_to_state/migration.sql +3 -0
- package/migration/20260309230000_move_org_to_state/snapshot.json +1156 -0
- package/migration/20260312043431_session_message_cursor/migration.sql +4 -0
- package/migration/20260312043431_session_message_cursor/snapshot.json +1168 -0
- package/migration/20260323234822_events/migration.sql +13 -0
- package/migration/20260323234822_events/snapshot.json +1271 -0
- package/package.json +163 -0
- package/parsers-config.ts +290 -0
- package/script/build-node.ts +56 -0
- package/script/build.ts +276 -0
- package/script/check-migrations.ts +16 -0
- package/script/postinstall.mjs +131 -0
- package/script/publish.ts +181 -0
- package/script/schema.ts +63 -0
- package/script/seed-e2e.ts +60 -0
- package/script/upgrade-opentui.ts +64 -0
- package/specs/effect-migration.md +294 -0
- package/specs/tui-plugins.md +436 -0
- package/src/account/account.sql.ts +39 -0
- package/src/account/index.ts +424 -0
- package/src/account/repo.ts +163 -0
- package/src/account/schema.ts +91 -0
- package/src/acp/README.md +174 -0
- package/src/acp/agent.ts +1763 -0
- package/src/acp/session.ts +116 -0
- package/src/acp/types.ts +24 -0
- package/src/agent/agent.ts +476 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +15 -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/auth/index.ts +109 -0
- package/src/bus/bus-event.ts +40 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +185 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/account.ts +257 -0
- package/src/cli/cmd/acp.ts +70 -0
- package/src/cli/cmd/agent.ts +245 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/db.ts +119 -0
- package/src/cli/cmd/debug/agent.ts +167 -0
- package/src/cli/cmd/debug/config.ts +16 -0
- package/src/cli/cmd/debug/file.ts +97 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +53 -0
- package/src/cli/cmd/debug/ripgrep.ts +87 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +16 -0
- package/src/cli/cmd/debug/snapshot.ts +52 -0
- package/src/cli/cmd/export.ts +89 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1646 -0
- package/src/cli/cmd/import.ts +207 -0
- package/src/cli/cmd/mcp.ts +754 -0
- package/src/cli/cmd/models.ts +78 -0
- package/src/cli/cmd/plug.ts +233 -0
- package/src/cli/cmd/pr.ts +127 -0
- package/src/cli/cmd/providers.ts +478 -0
- package/src/cli/cmd/run.ts +676 -0
- package/src/cli/cmd/serve.ts +24 -0
- package/src/cli/cmd/session.ts +159 -0
- package/src/cli/cmd/stats.ts +410 -0
- package/src/cli/cmd/tui/app.tsx +919 -0
- package/src/cli/cmd/tui/attach.ts +88 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +171 -0
- package/src/cli/cmd/tui/component/dialog-import-share.tsx +118 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +179 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +329 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +168 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/dialog-variant.tsx +39 -0
- package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +320 -0
- package/src/cli/cmd/tui/component/error-component.tsx +92 -0
- package/src/cli/cmd/tui/component/logo.tsx +85 -0
- package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +672 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1310 -0
- package/src/cli/cmd/tui/component/prompt/part.ts +16 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
- package/src/cli/cmd/tui/component/task-panel.tsx +44 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/component/token-bar.tsx +60 -0
- package/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx +151 -0
- package/src/cli/cmd/tui/context/args.tsx +15 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +60 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +105 -0
- package/src/cli/cmd/tui/context/kv.tsx +52 -0
- package/src/cli/cmd/tui/context/local.tsx +412 -0
- package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +52 -0
- package/src/cli/cmd/tui/context/sdk.tsx +128 -0
- package/src/cli/cmd/tui/context/sync.tsx +504 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
- package/src/cli/cmd/tui/context/theme/gtr.json +245 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/koro.json +241 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/opencode.json +245 -0
- package/src/cli/cmd/tui/context/theme/orng.json +249 -0
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1240 -0
- package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
- package/src/cli/cmd/tui/event.ts +49 -0
- package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +152 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +50 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +63 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +96 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +48 -0
- package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +270 -0
- package/src/cli/cmd/tui/plugin/api.tsx +430 -0
- package/src/cli/cmd/tui/plugin/index.ts +3 -0
- package/src/cli/cmd/tui/plugin/internal.ts +27 -0
- package/src/cli/cmd/tui/plugin/runtime.ts +1033 -0
- package/src/cli/cmd/tui/plugin/slots.tsx +60 -0
- package/src/cli/cmd/tui/routes/home.tsx +84 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +65 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +110 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +93 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2270 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +691 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +468 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +74 -0
- package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +131 -0
- package/src/cli/cmd/tui/thread.ts +232 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +89 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +211 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +130 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +409 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +192 -0
- package/src/cli/cmd/tui/ui/link.tsx +28 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +192 -0
- package/src/cli/cmd/tui/util/editor.ts +37 -0
- package/src/cli/cmd/tui/util/model.ts +23 -0
- package/src/cli/cmd/tui/util/scroll.ts +23 -0
- package/src/cli/cmd/tui/util/selection.ts +25 -0
- package/src/cli/cmd/tui/util/signal.ts +7 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/util/transcript.ts +112 -0
- package/src/cli/cmd/tui/win32.ts +129 -0
- package/src/cli/cmd/tui/worker.ts +175 -0
- package/src/cli/cmd/uninstall.ts +353 -0
- package/src/cli/cmd/upgrade.ts +73 -0
- package/src/cli/cmd/web.ts +81 -0
- package/src/cli/effect/prompt.ts +25 -0
- package/src/cli/error.ts +46 -0
- package/src/cli/heap.ts +59 -0
- package/src/cli/logo.ts +14 -0
- package/src/cli/network.ts +60 -0
- package/src/cli/ui.ts +133 -0
- package/src/cli/upgrade.ts +31 -0
- package/src/command/index.ts +195 -0
- package/src/command/template/initialize.txt +66 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/config.ts +1591 -0
- package/src/config/markdown.ts +99 -0
- package/src/config/paths.ts +181 -0
- package/src/config/tui-migrate.ts +155 -0
- package/src/config/tui-schema.ts +36 -0
- package/src/config/tui.ts +171 -0
- package/src/control-plane/adaptors/index.ts +20 -0
- package/src/control-plane/adaptors/worktree.ts +38 -0
- package/src/control-plane/schema.ts +17 -0
- package/src/control-plane/sse.ts +66 -0
- package/src/control-plane/types.ts +21 -0
- package/src/control-plane/workspace.sql.ts +17 -0
- package/src/control-plane/workspace.ts +154 -0
- package/src/effect/cross-spawn-spawner.ts +502 -0
- package/src/effect/instance-ref.ts +6 -0
- package/src/effect/instance-registry.ts +12 -0
- package/src/effect/instance-state.ts +82 -0
- package/src/effect/run-service.ts +33 -0
- package/src/effect/runner.ts +216 -0
- package/src/env/index.ts +28 -0
- package/src/file/ignore.ts +82 -0
- package/src/file/index.ts +686 -0
- package/src/file/protected.ts +59 -0
- package/src/file/ripgrep.ts +376 -0
- package/src/file/time.ts +133 -0
- package/src/file/watcher.ts +171 -0
- package/src/filesystem/index.ts +226 -0
- package/src/flag/flag.ts +155 -0
- package/src/format/formatter.ts +413 -0
- package/src/format/index.ts +203 -0
- package/src/git/index.ts +303 -0
- package/src/global/index.ts +161 -0
- package/src/id/id.ts +85 -0
- package/src/ide/index.ts +74 -0
- package/src/index.ts +240 -0
- package/src/installation/index.ts +355 -0
- package/src/installation/meta.ts +7 -0
- package/src/lsp/client.ts +252 -0
- package/src/lsp/index.ts +558 -0
- package/src/lsp/language.ts +120 -0
- package/src/lsp/launch.ts +21 -0
- package/src/lsp/server.ts +1958 -0
- package/src/mcp/auth.ts +173 -0
- package/src/mcp/index.ts +921 -0
- package/src/mcp/oauth-callback.ts +215 -0
- package/src/mcp/oauth-provider.ts +185 -0
- package/src/memory/index.ts +117 -0
- package/src/node.ts +1 -0
- package/src/npm/index.ts +180 -0
- package/src/orchestrator/agent-registry.ts +38 -0
- package/src/orchestrator/conflict.ts +25 -0
- package/src/orchestrator/context-manager.ts +22 -0
- package/src/orchestrator/index.ts +9 -0
- package/src/orchestrator/scheduler.ts +30 -0
- package/src/orchestrator/state-tracker.ts +71 -0
- package/src/orchestrator/task-manager.ts +69 -0
- package/src/patch/index.ts +680 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/evaluate.ts +15 -0
- package/src/permission/index.ts +325 -0
- package/src/permission/schema.ts +17 -0
- package/src/plugin/codex.ts +596 -0
- package/src/plugin/github-copilot/copilot.ts +353 -0
- package/src/plugin/github-copilot/models.ts +144 -0
- package/src/plugin/index.ts +281 -0
- package/src/plugin/install.ts +439 -0
- package/src/plugin/loader.ts +174 -0
- package/src/plugin/meta.ts +188 -0
- package/src/plugin/shared.ts +307 -0
- package/src/project/bootstrap.ts +31 -0
- package/src/project/instance.ts +175 -0
- package/src/project/project.sql.ts +16 -0
- package/src/project/project.ts +519 -0
- package/src/project/schema.ts +16 -0
- package/src/project/state.ts +70 -0
- package/src/project/vcs.ts +240 -0
- package/src/provider/auth.ts +253 -0
- package/src/provider/error.ts +197 -0
- package/src/provider/models-snapshot.ts +60410 -0
- package/src/provider/models.ts +162 -0
- package/src/provider/provider.ts +1677 -0
- package/src/provider/schema.ts +38 -0
- package/src/provider/sdk/copilot/README.md +5 -0
- package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
- package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +815 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +83 -0
- package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
- package/src/provider/sdk/copilot/index.ts +2 -0
- package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
- package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
- package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
- package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1769 -0
- package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
- package/src/provider/sdk/copilot/responses/tool/file-search.ts +127 -0
- package/src/provider/sdk/copilot/responses/tool/image-generation.ts +114 -0
- package/src/provider/sdk/copilot/responses/tool/local-shell.ts +64 -0
- package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
- package/src/provider/sdk/copilot/responses/tool/web-search.ts +102 -0
- package/src/provider/transform.ts +1046 -0
- package/src/pty/index.ts +401 -0
- package/src/pty/schema.ts +17 -0
- package/src/question/index.ts +224 -0
- package/src/question/schema.ts +17 -0
- package/src/server/error.ts +36 -0
- package/src/server/event.ts +7 -0
- package/src/server/instance.ts +314 -0
- package/src/server/mdns.ts +60 -0
- package/src/server/middleware.ts +33 -0
- package/src/server/projectors.ts +28 -0
- package/src/server/router.ts +99 -0
- package/src/server/routes/config.ts +92 -0
- package/src/server/routes/event.ts +83 -0
- package/src/server/routes/experimental.ts +271 -0
- package/src/server/routes/file.ts +197 -0
- package/src/server/routes/global.ts +312 -0
- package/src/server/routes/mcp.ts +225 -0
- package/src/server/routes/permission.ts +69 -0
- package/src/server/routes/project.ts +118 -0
- package/src/server/routes/provider.ts +171 -0
- package/src/server/routes/pty.ts +211 -0
- package/src/server/routes/question.ts +99 -0
- package/src/server/routes/session.ts +1031 -0
- package/src/server/routes/tui.ts +379 -0
- package/src/server/routes/workspace.ts +94 -0
- package/src/server/server.ts +312 -0
- package/src/session/compaction.ts +428 -0
- package/src/session/index.ts +887 -0
- package/src/session/instruction.ts +258 -0
- package/src/session/llm.ts +370 -0
- package/src/session/message-v2.ts +1031 -0
- package/src/session/message.ts +191 -0
- package/src/session/overflow.ts +22 -0
- package/src/session/processor.ts +523 -0
- package/src/session/projectors.ts +135 -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 +105 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/gpt.txt +107 -0
- package/src/session/prompt/kimi.txt +114 -0
- package/src/session/prompt/max-steps.txt +16 -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 +1908 -0
- package/src/session/retry.ts +106 -0
- package/src/session/revert.ts +176 -0
- package/src/session/schema.ts +38 -0
- package/src/session/session.sql.ts +103 -0
- package/src/session/status.ts +102 -0
- package/src/session/summary.ts +177 -0
- package/src/session/system.ts +76 -0
- package/src/session/todo.ts +95 -0
- package/src/share/share-next.ts +369 -0
- package/src/share/share.sql.ts +13 -0
- package/src/shell/shell.ts +110 -0
- package/src/skill/discovery.ts +116 -0
- package/src/skill/index.ts +277 -0
- package/src/snapshot/index.ts +571 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/db.bun.ts +8 -0
- package/src/storage/db.node.ts +8 -0
- package/src/storage/db.ts +174 -0
- package/src/storage/json-migration.ts +425 -0
- package/src/storage/schema.sql.ts +10 -0
- package/src/storage/schema.ts +5 -0
- package/src/storage/storage.ts +353 -0
- package/src/sync/README.md +179 -0
- package/src/sync/event.sql.ts +16 -0
- package/src/sync/index.ts +263 -0
- package/src/sync/schema.ts +14 -0
- package/src/token/index.ts +77 -0
- package/src/tool/apply_patch.ts +281 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash.ts +496 -0
- package/src/tool/bash.txt +117 -0
- package/src/tool/batch.ts +183 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +132 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +667 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +37 -0
- package/src/tool/glob.ts +78 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +156 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +121 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp.ts +97 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +131 -0
- package/src/tool/question.ts +46 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +296 -0
- package/src/tool/read.txt +14 -0
- package/src/tool/registry.ts +248 -0
- package/src/tool/schema.ts +17 -0
- package/src/tool/skill.ts +105 -0
- package/src/tool/task.ts +166 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +48 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +112 -0
- package/src/tool/truncate.ts +144 -0
- package/src/tool/truncation-dir.ts +4 -0
- package/src/tool/webfetch.ts +206 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +150 -0
- package/src/tool/websearch.txt +14 -0
- package/src/tool/write.ts +84 -0
- package/src/tool/write.txt +8 -0
- package/src/util/abort.ts +35 -0
- package/src/util/archive.ts +17 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/data-url.ts +9 -0
- package/src/util/defer.ts +12 -0
- package/src/util/effect-http-client.ts +11 -0
- package/src/util/effect-zod.ts +98 -0
- package/src/util/error.ts +77 -0
- package/src/util/filesystem.ts +245 -0
- package/src/util/flock.ts +333 -0
- package/src/util/fn.ts +21 -0
- package/src/util/format.ts +20 -0
- package/src/util/glob.ts +34 -0
- package/src/util/hash.ts +7 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +103 -0
- package/src/util/lazy.ts +23 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +182 -0
- package/src/util/network.ts +9 -0
- package/src/util/process.ts +176 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +3 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/schema.ts +53 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/update-schema.ts +13 -0
- package/src/util/which.ts +14 -0
- package/src/util/wildcard.ts +59 -0
- package/src/worktree/index.ts +612 -0
- package/sst-env.d.ts +10 -0
- package/test/AGENTS.md +81 -0
- package/test/account/repo.test.ts +326 -0
- package/test/account/service.test.ts +393 -0
- package/test/acp/agent-interface.test.ts +51 -0
- package/test/acp/event-subscription.test.ts +685 -0
- package/test/agent/agent.test.ts +717 -0
- package/test/auth/auth.test.ts +58 -0
- package/test/bus/bus-effect.test.ts +164 -0
- package/test/bus/bus-integration.test.ts +87 -0
- package/test/bus/bus.test.ts +219 -0
- package/test/cli/account.test.ts +26 -0
- package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
- package/test/cli/github-action.test.ts +198 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/cli/import.test.ts +54 -0
- package/test/cli/plugin-auth-picker.test.ts +120 -0
- package/test/cli/tui/keybind-plugin.test.ts +90 -0
- package/test/cli/tui/plugin-add.test.ts +107 -0
- package/test/cli/tui/plugin-install.test.ts +89 -0
- package/test/cli/tui/plugin-lifecycle.test.ts +225 -0
- package/test/cli/tui/plugin-loader-entrypoint.test.ts +492 -0
- package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
- package/test/cli/tui/plugin-loader.test.ts +752 -0
- package/test/cli/tui/plugin-toggle.test.ts +159 -0
- package/test/cli/tui/slot-replace.test.tsx +47 -0
- package/test/cli/tui/theme-store.test.ts +51 -0
- package/test/cli/tui/thread.test.ts +128 -0
- package/test/cli/tui/transcript.test.ts +426 -0
- package/test/config/agent-color.test.ts +71 -0
- package/test/config/config.test.ts +2348 -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/markdown.test.ts +228 -0
- package/test/config/tui.test.ts +752 -0
- package/test/control-plane/sse.test.ts +56 -0
- package/test/effect/cross-spawn-spawner.test.ts +412 -0
- package/test/effect/instance-state.test.ts +482 -0
- package/test/effect/run-service.test.ts +46 -0
- package/test/effect/runner.test.ts +523 -0
- package/test/fake/provider.ts +81 -0
- package/test/file/fsmonitor.test.ts +62 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/index.test.ts +946 -0
- package/test/file/path-traversal.test.ts +198 -0
- package/test/file/ripgrep.test.ts +54 -0
- package/test/file/time.test.ts +445 -0
- package/test/file/watcher.test.ts +247 -0
- package/test/filesystem/filesystem.test.ts +319 -0
- package/test/fixture/db.ts +11 -0
- package/test/fixture/fixture.test.ts +26 -0
- package/test/fixture/fixture.ts +172 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/fixture/plug-worker.ts +93 -0
- package/test/fixture/plugin-meta-worker.ts +26 -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-plugin.ts +337 -0
- package/test/fixture/tui-runtime.ts +27 -0
- package/test/format/format.test.ts +171 -0
- package/test/git/git.test.ts +128 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/installation/installation.test.ts +151 -0
- package/test/keybind.test.ts +421 -0
- package/test/lib/effect.ts +53 -0
- package/test/lib/filesystem.ts +10 -0
- package/test/lib/llm-server.ts +795 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/lsp/index.test.ts +55 -0
- package/test/lsp/launch.test.ts +22 -0
- package/test/lsp/lifecycle.test.ts +147 -0
- package/test/mcp/headers.test.ts +153 -0
- package/test/mcp/lifecycle.test.ts +750 -0
- package/test/mcp/oauth-auto-connect.test.ts +199 -0
- package/test/mcp/oauth-browser.test.ts +249 -0
- package/test/memory/abort-leak.test.ts +137 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/next.test.ts +1148 -0
- package/test/permission-task.test.ts +323 -0
- package/test/plugin/auth-override.test.ts +74 -0
- package/test/plugin/codex.test.ts +123 -0
- package/test/plugin/github-copilot-models.test.ts +117 -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 +1136 -0
- package/test/plugin/meta.test.ts +137 -0
- package/test/plugin/trigger.test.ts +111 -0
- package/test/preload.ts +90 -0
- package/test/project/migrate-global.test.ts +140 -0
- package/test/project/project.test.ts +459 -0
- package/test/project/state.test.ts +115 -0
- package/test/project/vcs.test.ts +228 -0
- package/test/project/worktree-remove.test.ts +96 -0
- package/test/project/worktree.test.ts +173 -0
- package/test/provider/amazon-bedrock.test.ts +447 -0
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
- package/test/provider/gitlab-duo.test.ts +412 -0
- package/test/provider/provider.test.ts +2284 -0
- package/test/provider/transform.test.ts +2839 -0
- package/test/pty/pty-output-isolation.test.ts +141 -0
- package/test/pty/pty-session.test.ts +92 -0
- package/test/pty/pty-shell.test.ts +59 -0
- package/test/question/question.test.ts +453 -0
- package/test/server/global-session-list.test.ts +89 -0
- package/test/server/project-init-git.test.ts +121 -0
- package/test/server/session-actions.test.ts +83 -0
- package/test/server/session-list.test.ts +98 -0
- package/test/server/session-messages.test.ts +159 -0
- package/test/server/session-select.test.ts +84 -0
- package/test/session/compaction.test.ts +1212 -0
- package/test/session/instruction.test.ts +286 -0
- package/test/session/llm.test.ts +1098 -0
- package/test/session/message-v2.test.ts +957 -0
- package/test/session/messages-pagination.test.ts +885 -0
- package/test/session/processor-effect.test.ts +747 -0
- package/test/session/prompt-effect.test.ts +1241 -0
- package/test/session/prompt.test.ts +518 -0
- package/test/session/retry.test.ts +232 -0
- package/test/session/revert-compact.test.ts +621 -0
- package/test/session/session.test.ts +142 -0
- package/test/session/snapshot-tool-race.test.ts +242 -0
- package/test/session/structured-output-integration.test.ts +233 -0
- package/test/session/structured-output.test.ts +391 -0
- package/test/session/system.test.ts +59 -0
- package/test/share/share-next.test.ts +333 -0
- package/test/shell/shell.test.ts +73 -0
- package/test/skill/discovery.test.ts +116 -0
- package/test/skill/skill.test.ts +392 -0
- package/test/snapshot/snapshot.test.ts +1312 -0
- package/test/storage/db.test.ts +14 -0
- package/test/storage/json-migration.test.ts +849 -0
- package/test/storage/storage.test.ts +295 -0
- package/test/sync/index.test.ts +191 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/apply_patch.test.ts +567 -0
- package/test/tool/bash.test.ts +1099 -0
- package/test/tool/edit.test.ts +681 -0
- package/test/tool/external-directory.test.ts +198 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +65179 -0
- package/test/tool/grep.test.ts +111 -0
- package/test/tool/question.test.ts +126 -0
- package/test/tool/read.test.ts +546 -0
- package/test/tool/registry.test.ts +126 -0
- package/test/tool/skill.test.ts +167 -0
- package/test/tool/task.test.ts +49 -0
- package/test/tool/tool-define.test.ts +101 -0
- package/test/tool/truncation.test.ts +161 -0
- package/test/tool/webfetch.test.ts +101 -0
- package/test/tool/write.test.ts +353 -0
- package/test/util/data-url.test.ts +14 -0
- package/test/util/effect-zod.test.ts +61 -0
- package/test/util/error.test.ts +38 -0
- package/test/util/filesystem.test.ts +656 -0
- package/test/util/flock.test.ts +383 -0
- package/test/util/format.test.ts +59 -0
- package/test/util/glob.test.ts +164 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/lock.test.ts +72 -0
- package/test/util/module.test.ts +59 -0
- package/test/util/process.test.ts +128 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/which.test.ts +100 -0
- package/test/util/wildcard.test.ts +90 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import z from "zod"
|
|
2
|
+
import type { ZodObject } from "zod"
|
|
3
|
+
import { EventEmitter } from "events"
|
|
4
|
+
import { Database, eq } from "@/storage/db"
|
|
5
|
+
import { Bus as ProjectBus } from "@/bus"
|
|
6
|
+
import { BusEvent } from "@/bus/bus-event"
|
|
7
|
+
import { EventSequenceTable, EventTable } from "./event.sql"
|
|
8
|
+
import { EventID } from "./schema"
|
|
9
|
+
import { Flag } from "@/flag/flag"
|
|
10
|
+
|
|
11
|
+
export namespace SyncEvent {
|
|
12
|
+
export type Definition = {
|
|
13
|
+
type: string
|
|
14
|
+
version: number
|
|
15
|
+
aggregate: string
|
|
16
|
+
schema: z.ZodObject
|
|
17
|
+
|
|
18
|
+
// This is temporary and only exists for compatibility with bus
|
|
19
|
+
// event definitions
|
|
20
|
+
properties: z.ZodObject
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type Event<Def extends Definition = Definition> = {
|
|
24
|
+
id: string
|
|
25
|
+
seq: number
|
|
26
|
+
aggregateID: string
|
|
27
|
+
data: z.infer<Def["schema"]>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type SerializedEvent<Def extends Definition = Definition> = Event<Def> & { type: string }
|
|
31
|
+
|
|
32
|
+
type ProjectorFunc = (db: Database.TxOrDb, data: unknown) => void
|
|
33
|
+
|
|
34
|
+
export const registry = new Map<string, Definition>()
|
|
35
|
+
let projectors: Map<Definition, ProjectorFunc> | undefined
|
|
36
|
+
const versions = new Map<string, number>()
|
|
37
|
+
let frozen = false
|
|
38
|
+
let convertEvent: (type: string, event: Event["data"]) => Promise<Record<string, unknown>> | Record<string, unknown>
|
|
39
|
+
|
|
40
|
+
const Bus = new EventEmitter<{ event: [{ def: Definition; event: Event }] }>()
|
|
41
|
+
|
|
42
|
+
export function reset() {
|
|
43
|
+
frozen = false
|
|
44
|
+
projectors = undefined
|
|
45
|
+
convertEvent = (_, data) => data
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; convertEvent?: typeof convertEvent }) {
|
|
49
|
+
projectors = new Map(input.projectors)
|
|
50
|
+
|
|
51
|
+
// Install all the latest event defs to the bus. We only ever emit
|
|
52
|
+
// latest versions from code, and keep around old versions for
|
|
53
|
+
// replaying. Replaying does not go through the bus, and it
|
|
54
|
+
// simplifies the bus to only use unversioned latest events
|
|
55
|
+
for (let [type, version] of versions.entries()) {
|
|
56
|
+
let def = registry.get(versionedType(type, version))!
|
|
57
|
+
|
|
58
|
+
BusEvent.define(def.type, def.properties || def.schema)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Freeze the system so it clearly errors if events are defined
|
|
62
|
+
// after `init` which would cause bugs
|
|
63
|
+
frozen = true
|
|
64
|
+
convertEvent = input.convertEvent || ((_, data) => data)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function versionedType<A extends string>(type: A): A
|
|
68
|
+
export function versionedType<A extends string, B extends number>(type: A, version: B): `${A}/${B}`
|
|
69
|
+
export function versionedType(type: string, version?: number) {
|
|
70
|
+
return version ? `${type}.${version}` : type
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function define<
|
|
74
|
+
Type extends string,
|
|
75
|
+
Agg extends string,
|
|
76
|
+
Schema extends ZodObject<Record<Agg, z.ZodType<string>>>,
|
|
77
|
+
BusSchema extends ZodObject = Schema,
|
|
78
|
+
>(input: { type: Type; version: number; aggregate: Agg; schema: Schema; busSchema?: BusSchema }) {
|
|
79
|
+
if (frozen) {
|
|
80
|
+
throw new Error("Error defining sync event: sync system has been frozen")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const def = {
|
|
84
|
+
type: input.type,
|
|
85
|
+
version: input.version,
|
|
86
|
+
aggregate: input.aggregate,
|
|
87
|
+
schema: input.schema,
|
|
88
|
+
properties: input.busSchema ? input.busSchema : input.schema,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
versions.set(def.type, Math.max(def.version, versions.get(def.type) || 0))
|
|
92
|
+
|
|
93
|
+
registry.set(versionedType(def.type, def.version), def)
|
|
94
|
+
|
|
95
|
+
return def
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function project<Def extends Definition>(
|
|
99
|
+
def: Def,
|
|
100
|
+
func: (db: Database.TxOrDb, data: Event<Def>["data"]) => void,
|
|
101
|
+
): [Definition, ProjectorFunc] {
|
|
102
|
+
return [def, func as ProjectorFunc]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function process<Def extends Definition>(def: Def, event: Event<Def>, options: { publish: boolean }) {
|
|
106
|
+
if (projectors == null) {
|
|
107
|
+
throw new Error("No projectors available. Call `SyncEvent.init` to install projectors")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const projector = projectors.get(def)
|
|
111
|
+
if (!projector) {
|
|
112
|
+
throw new Error(`Projector not found for event: ${def.type}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// idempotent: need to ignore any events already logged
|
|
116
|
+
|
|
117
|
+
Database.transaction((tx) => {
|
|
118
|
+
projector(tx, event.data)
|
|
119
|
+
|
|
120
|
+
if (Flag.OPENCODE_EXPERIMENTAL_WORKSPACES) {
|
|
121
|
+
tx.insert(EventSequenceTable)
|
|
122
|
+
.values({
|
|
123
|
+
aggregate_id: event.aggregateID,
|
|
124
|
+
seq: event.seq,
|
|
125
|
+
})
|
|
126
|
+
.onConflictDoUpdate({
|
|
127
|
+
target: EventSequenceTable.aggregate_id,
|
|
128
|
+
set: { seq: event.seq },
|
|
129
|
+
})
|
|
130
|
+
.run()
|
|
131
|
+
tx.insert(EventTable)
|
|
132
|
+
.values({
|
|
133
|
+
id: event.id,
|
|
134
|
+
seq: event.seq,
|
|
135
|
+
aggregate_id: event.aggregateID,
|
|
136
|
+
type: versionedType(def.type, def.version),
|
|
137
|
+
data: event.data as Record<string, unknown>,
|
|
138
|
+
})
|
|
139
|
+
.run()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
Database.effect(() => {
|
|
143
|
+
Bus.emit("event", {
|
|
144
|
+
def,
|
|
145
|
+
event,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (options?.publish) {
|
|
149
|
+
const result = convertEvent(def.type, event.data)
|
|
150
|
+
if (result instanceof Promise) {
|
|
151
|
+
result.then((data) => {
|
|
152
|
+
ProjectBus.publish({ type: def.type, properties: def.schema }, data)
|
|
153
|
+
})
|
|
154
|
+
} else {
|
|
155
|
+
ProjectBus.publish({ type: def.type, properties: def.schema }, result)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// TODO:
|
|
163
|
+
//
|
|
164
|
+
// * Support applying multiple events at one time. One transaction,
|
|
165
|
+
// and it validets all the sequence ids
|
|
166
|
+
// * when loading events from db, apply zod validation to ensure shape
|
|
167
|
+
|
|
168
|
+
export function replay(event: SerializedEvent, options?: { republish: boolean }) {
|
|
169
|
+
const def = registry.get(event.type)
|
|
170
|
+
if (!def) {
|
|
171
|
+
throw new Error(`Unknown event type: ${event.type}`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const row = Database.use((db) =>
|
|
175
|
+
db
|
|
176
|
+
.select({ seq: EventSequenceTable.seq })
|
|
177
|
+
.from(EventSequenceTable)
|
|
178
|
+
.where(eq(EventSequenceTable.aggregate_id, event.aggregateID))
|
|
179
|
+
.get(),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
const latest = row?.seq ?? -1
|
|
183
|
+
if (event.seq <= latest) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const expected = latest + 1
|
|
188
|
+
if (event.seq !== expected) {
|
|
189
|
+
throw new Error(`Sequence mismatch for aggregate "${event.aggregateID}": expected ${expected}, got ${event.seq}`)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
process(def, event, { publish: !!options?.republish })
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function run<Def extends Definition>(def: Def, data: Event<Def>["data"]) {
|
|
196
|
+
const agg = (data as Record<string, string>)[def.aggregate]
|
|
197
|
+
// This should never happen: we've enforced it via typescript in
|
|
198
|
+
// the definition
|
|
199
|
+
if (agg == null) {
|
|
200
|
+
throw new Error(`SyncEvent.run: "${def.aggregate}" required but not found: ${JSON.stringify(data)}`)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (def.version !== versions.get(def.type)) {
|
|
204
|
+
throw new Error(`SyncEvent.run: running old versions of events is not allowed: ${def.type}`)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Note that this is an "immediate" transaction which is critical.
|
|
208
|
+
// We need to make sure we can safely read and write with nothing
|
|
209
|
+
// else changing the data from under us
|
|
210
|
+
Database.transaction(
|
|
211
|
+
(tx) => {
|
|
212
|
+
const id = EventID.ascending()
|
|
213
|
+
const row = tx
|
|
214
|
+
.select({ seq: EventSequenceTable.seq })
|
|
215
|
+
.from(EventSequenceTable)
|
|
216
|
+
.where(eq(EventSequenceTable.aggregate_id, agg))
|
|
217
|
+
.get()
|
|
218
|
+
const seq = row?.seq != null ? row.seq + 1 : 0
|
|
219
|
+
|
|
220
|
+
const event = { id, seq, aggregateID: agg, data }
|
|
221
|
+
process(def, event, { publish: true })
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
behavior: "immediate",
|
|
225
|
+
},
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function remove(aggregateID: string) {
|
|
230
|
+
Database.transaction((tx) => {
|
|
231
|
+
tx.delete(EventSequenceTable).where(eq(EventSequenceTable.aggregate_id, aggregateID)).run()
|
|
232
|
+
tx.delete(EventTable).where(eq(EventTable.aggregate_id, aggregateID)).run()
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function subscribeAll(handler: (event: { def: Definition; event: Event }) => void) {
|
|
237
|
+
Bus.on("event", handler)
|
|
238
|
+
return () => Bus.off("event", handler)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function payloads() {
|
|
242
|
+
return z
|
|
243
|
+
.union(
|
|
244
|
+
registry
|
|
245
|
+
.entries()
|
|
246
|
+
.map(([type, def]) => {
|
|
247
|
+
return z
|
|
248
|
+
.object({
|
|
249
|
+
type: z.literal(type),
|
|
250
|
+
aggregate: z.literal(def.aggregate),
|
|
251
|
+
data: def.schema,
|
|
252
|
+
})
|
|
253
|
+
.meta({
|
|
254
|
+
ref: "SyncEvent" + "." + def.type,
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
.toArray() as any,
|
|
258
|
+
)
|
|
259
|
+
.meta({
|
|
260
|
+
ref: "SyncEvent",
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Schema } from "effect"
|
|
2
|
+
import z from "zod"
|
|
3
|
+
|
|
4
|
+
import { Identifier } from "@/id/id"
|
|
5
|
+
import { withStatics } from "@/util/schema"
|
|
6
|
+
|
|
7
|
+
export const EventID = Schema.String.pipe(
|
|
8
|
+
Schema.brand("EventID"),
|
|
9
|
+
withStatics((s) => ({
|
|
10
|
+
make: (id: string) => s.makeUnsafe(id),
|
|
11
|
+
ascending: (id?: string) => s.makeUnsafe(Identifier.ascending("event", id)),
|
|
12
|
+
zod: Identifier.schema("event").pipe(z.custom<Schema.Schema.Type<typeof s>>()),
|
|
13
|
+
})),
|
|
14
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CoreMessage } from "ai"
|
|
2
|
+
|
|
3
|
+
export interface TokenUsage {
|
|
4
|
+
session: { input: number; output: number; total: number }
|
|
5
|
+
lastStep: { input: number; output: number }
|
|
6
|
+
byTool: Record<string, number>
|
|
7
|
+
contextUsedPercent: number
|
|
8
|
+
estimatedCost: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function zeroUsage(): TokenUsage {
|
|
12
|
+
return {
|
|
13
|
+
session: { input: 0, output: 0, total: 0 },
|
|
14
|
+
lastStep: { input: 0, output: 0 },
|
|
15
|
+
byTool: {},
|
|
16
|
+
contextUsedPercent: 0,
|
|
17
|
+
estimatedCost: 0,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Approximate cost per 1M tokens for Claude Opus 4.5
|
|
22
|
+
const COST_PER_INPUT_M = 15.0
|
|
23
|
+
const COST_PER_OUTPUT_M = 75.0
|
|
24
|
+
|
|
25
|
+
export class TokenTracker {
|
|
26
|
+
private static instance: TokenTracker | null = null
|
|
27
|
+
private usage: TokenUsage
|
|
28
|
+
|
|
29
|
+
private constructor() {
|
|
30
|
+
this.usage = zeroUsage()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static getInstance(): TokenTracker {
|
|
34
|
+
if (this.instance === null) this.instance = new TokenTracker()
|
|
35
|
+
return this.instance
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
record(response: { usage: { promptTokens: number; completionTokens: number }; model: string }): void {
|
|
39
|
+
const input = response.usage.promptTokens
|
|
40
|
+
const output = response.usage.completionTokens
|
|
41
|
+
|
|
42
|
+
this.usage.lastStep = { input, output }
|
|
43
|
+
this.usage.session.input += input
|
|
44
|
+
this.usage.session.output += output
|
|
45
|
+
this.usage.session.total = this.usage.session.input + this.usage.session.output
|
|
46
|
+
|
|
47
|
+
const inputCost = (this.usage.session.input / 1_000_000) * COST_PER_INPUT_M
|
|
48
|
+
const outputCost = (this.usage.session.output / 1_000_000) * COST_PER_OUTPUT_M
|
|
49
|
+
this.usage.estimatedCost = inputCost + outputCost
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
recordTool(toolName: string, tokens: number): void {
|
|
53
|
+
const prev = this.usage.byTool[toolName] ?? 0
|
|
54
|
+
this.usage.byTool[toolName] = prev + tokens
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
preview(messages: CoreMessage[]): number {
|
|
58
|
+
let chars = 0
|
|
59
|
+
for (const msg of messages) {
|
|
60
|
+
if (typeof msg.content === "string") chars += msg.content.length
|
|
61
|
+
}
|
|
62
|
+
return Math.ceil(chars / 4)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get(): TokenUsage {
|
|
66
|
+
return {
|
|
67
|
+
...this.usage,
|
|
68
|
+
session: { ...this.usage.session },
|
|
69
|
+
lastStep: { ...this.usage.lastStep },
|
|
70
|
+
byTool: { ...this.usage.byTool },
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
reset(): void {
|
|
75
|
+
this.usage = zeroUsage()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import z from "zod"
|
|
2
|
+
import * as path from "path"
|
|
3
|
+
import * as fs from "fs/promises"
|
|
4
|
+
import { Tool } from "./tool"
|
|
5
|
+
import { Bus } from "../bus"
|
|
6
|
+
import { FileWatcher } from "../file/watcher"
|
|
7
|
+
import { Instance } from "../project/instance"
|
|
8
|
+
import { Patch } from "../patch"
|
|
9
|
+
import { createTwoFilesPatch, diffLines } from "diff"
|
|
10
|
+
import { assertExternalDirectory } from "./external-directory"
|
|
11
|
+
import { trimDiff } from "./edit"
|
|
12
|
+
import { LSP } from "../lsp"
|
|
13
|
+
import { Filesystem } from "../util/filesystem"
|
|
14
|
+
import DESCRIPTION from "./apply_patch.txt"
|
|
15
|
+
import { File } from "../file"
|
|
16
|
+
import { Format } from "../format"
|
|
17
|
+
|
|
18
|
+
const PatchParams = z.object({
|
|
19
|
+
patchText: z.string().describe("The full patch text that describes all changes to be made"),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const ApplyPatchTool = Tool.define("apply_patch", {
|
|
23
|
+
description: DESCRIPTION,
|
|
24
|
+
parameters: PatchParams,
|
|
25
|
+
async execute(params, ctx) {
|
|
26
|
+
if (!params.patchText) {
|
|
27
|
+
throw new Error("patchText is required")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Parse the patch to get hunks
|
|
31
|
+
let hunks: Patch.Hunk[]
|
|
32
|
+
try {
|
|
33
|
+
const parseResult = Patch.parsePatch(params.patchText)
|
|
34
|
+
hunks = parseResult.hunks
|
|
35
|
+
} catch (error) {
|
|
36
|
+
throw new Error(`apply_patch verification failed: ${error}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (hunks.length === 0) {
|
|
40
|
+
const normalized = params.patchText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim()
|
|
41
|
+
if (normalized === "*** Begin Patch\n*** End Patch") {
|
|
42
|
+
throw new Error("patch rejected: empty patch")
|
|
43
|
+
}
|
|
44
|
+
throw new Error("apply_patch verification failed: no hunks found")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Validate file paths and check permissions
|
|
48
|
+
const fileChanges: Array<{
|
|
49
|
+
filePath: string
|
|
50
|
+
oldContent: string
|
|
51
|
+
newContent: string
|
|
52
|
+
type: "add" | "update" | "delete" | "move"
|
|
53
|
+
movePath?: string
|
|
54
|
+
diff: string
|
|
55
|
+
additions: number
|
|
56
|
+
deletions: number
|
|
57
|
+
}> = []
|
|
58
|
+
|
|
59
|
+
let totalDiff = ""
|
|
60
|
+
|
|
61
|
+
for (const hunk of hunks) {
|
|
62
|
+
const filePath = path.resolve(Instance.directory, hunk.path)
|
|
63
|
+
await assertExternalDirectory(ctx, filePath)
|
|
64
|
+
|
|
65
|
+
switch (hunk.type) {
|
|
66
|
+
case "add": {
|
|
67
|
+
const oldContent = ""
|
|
68
|
+
const newContent =
|
|
69
|
+
hunk.contents.length === 0 || hunk.contents.endsWith("\n") ? hunk.contents : `${hunk.contents}\n`
|
|
70
|
+
const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, newContent))
|
|
71
|
+
|
|
72
|
+
let additions = 0
|
|
73
|
+
let deletions = 0
|
|
74
|
+
for (const change of diffLines(oldContent, newContent)) {
|
|
75
|
+
if (change.added) additions += change.count || 0
|
|
76
|
+
if (change.removed) deletions += change.count || 0
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fileChanges.push({
|
|
80
|
+
filePath,
|
|
81
|
+
oldContent,
|
|
82
|
+
newContent,
|
|
83
|
+
type: "add",
|
|
84
|
+
diff,
|
|
85
|
+
additions,
|
|
86
|
+
deletions,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
totalDiff += diff + "\n"
|
|
90
|
+
break
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case "update": {
|
|
94
|
+
// Check if file exists for update
|
|
95
|
+
const stats = await fs.stat(filePath).catch(() => null)
|
|
96
|
+
if (!stats || stats.isDirectory()) {
|
|
97
|
+
throw new Error(`apply_patch verification failed: Failed to read file to update: ${filePath}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const oldContent = await fs.readFile(filePath, "utf-8")
|
|
101
|
+
let newContent = oldContent
|
|
102
|
+
|
|
103
|
+
// Apply the update chunks to get new content
|
|
104
|
+
try {
|
|
105
|
+
const fileUpdate = Patch.deriveNewContentsFromChunks(filePath, hunk.chunks)
|
|
106
|
+
newContent = fileUpdate.content
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(`apply_patch verification failed: ${error}`)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, newContent))
|
|
112
|
+
|
|
113
|
+
let additions = 0
|
|
114
|
+
let deletions = 0
|
|
115
|
+
for (const change of diffLines(oldContent, newContent)) {
|
|
116
|
+
if (change.added) additions += change.count || 0
|
|
117
|
+
if (change.removed) deletions += change.count || 0
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const movePath = hunk.move_path ? path.resolve(Instance.directory, hunk.move_path) : undefined
|
|
121
|
+
await assertExternalDirectory(ctx, movePath)
|
|
122
|
+
|
|
123
|
+
fileChanges.push({
|
|
124
|
+
filePath,
|
|
125
|
+
oldContent,
|
|
126
|
+
newContent,
|
|
127
|
+
type: hunk.move_path ? "move" : "update",
|
|
128
|
+
movePath,
|
|
129
|
+
diff,
|
|
130
|
+
additions,
|
|
131
|
+
deletions,
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
totalDiff += diff + "\n"
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
case "delete": {
|
|
139
|
+
const contentToDelete = await fs.readFile(filePath, "utf-8").catch((error) => {
|
|
140
|
+
throw new Error(`apply_patch verification failed: ${error}`)
|
|
141
|
+
})
|
|
142
|
+
const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, ""))
|
|
143
|
+
|
|
144
|
+
const deletions = contentToDelete.split("\n").length
|
|
145
|
+
|
|
146
|
+
fileChanges.push({
|
|
147
|
+
filePath,
|
|
148
|
+
oldContent: contentToDelete,
|
|
149
|
+
newContent: "",
|
|
150
|
+
type: "delete",
|
|
151
|
+
diff: deleteDiff,
|
|
152
|
+
additions: 0,
|
|
153
|
+
deletions,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
totalDiff += deleteDiff + "\n"
|
|
157
|
+
break
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Build per-file metadata for UI rendering (used for both permission and result)
|
|
163
|
+
const files = fileChanges.map((change) => ({
|
|
164
|
+
filePath: change.filePath,
|
|
165
|
+
relativePath: path.relative(Instance.worktree, change.movePath ?? change.filePath).replaceAll("\\", "/"),
|
|
166
|
+
type: change.type,
|
|
167
|
+
diff: change.diff,
|
|
168
|
+
before: change.oldContent,
|
|
169
|
+
after: change.newContent,
|
|
170
|
+
additions: change.additions,
|
|
171
|
+
deletions: change.deletions,
|
|
172
|
+
movePath: change.movePath,
|
|
173
|
+
}))
|
|
174
|
+
|
|
175
|
+
// Check permissions if needed
|
|
176
|
+
const relativePaths = fileChanges.map((c) => path.relative(Instance.worktree, c.filePath).replaceAll("\\", "/"))
|
|
177
|
+
await ctx.ask({
|
|
178
|
+
permission: "edit",
|
|
179
|
+
patterns: relativePaths,
|
|
180
|
+
always: ["*"],
|
|
181
|
+
metadata: {
|
|
182
|
+
filepath: relativePaths.join(", "),
|
|
183
|
+
diff: totalDiff,
|
|
184
|
+
files,
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Apply the changes
|
|
189
|
+
const updates: Array<{ file: string; event: "add" | "change" | "unlink" }> = []
|
|
190
|
+
|
|
191
|
+
for (const change of fileChanges) {
|
|
192
|
+
const edited = change.type === "delete" ? undefined : (change.movePath ?? change.filePath)
|
|
193
|
+
switch (change.type) {
|
|
194
|
+
case "add":
|
|
195
|
+
// Create parent directories (recursive: true is safe on existing/root dirs)
|
|
196
|
+
await fs.mkdir(path.dirname(change.filePath), { recursive: true })
|
|
197
|
+
await fs.writeFile(change.filePath, change.newContent, "utf-8")
|
|
198
|
+
updates.push({ file: change.filePath, event: "add" })
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
case "update":
|
|
202
|
+
await fs.writeFile(change.filePath, change.newContent, "utf-8")
|
|
203
|
+
updates.push({ file: change.filePath, event: "change" })
|
|
204
|
+
break
|
|
205
|
+
|
|
206
|
+
case "move":
|
|
207
|
+
if (change.movePath) {
|
|
208
|
+
// Create parent directories (recursive: true is safe on existing/root dirs)
|
|
209
|
+
await fs.mkdir(path.dirname(change.movePath), { recursive: true })
|
|
210
|
+
await fs.writeFile(change.movePath, change.newContent, "utf-8")
|
|
211
|
+
await fs.unlink(change.filePath)
|
|
212
|
+
updates.push({ file: change.filePath, event: "unlink" })
|
|
213
|
+
updates.push({ file: change.movePath, event: "add" })
|
|
214
|
+
}
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
case "delete":
|
|
218
|
+
await fs.unlink(change.filePath)
|
|
219
|
+
updates.push({ file: change.filePath, event: "unlink" })
|
|
220
|
+
break
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (edited) {
|
|
224
|
+
await Format.file(edited)
|
|
225
|
+
Bus.publish(File.Event.Edited, { file: edited })
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Publish file change events
|
|
230
|
+
for (const update of updates) {
|
|
231
|
+
await Bus.publish(FileWatcher.Event.Updated, update)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Notify LSP of file changes and collect diagnostics
|
|
235
|
+
for (const change of fileChanges) {
|
|
236
|
+
if (change.type === "delete") continue
|
|
237
|
+
const target = change.movePath ?? change.filePath
|
|
238
|
+
await LSP.touchFile(target, true)
|
|
239
|
+
}
|
|
240
|
+
const diagnostics = await LSP.diagnostics()
|
|
241
|
+
|
|
242
|
+
// Generate output summary
|
|
243
|
+
const summaryLines = fileChanges.map((change) => {
|
|
244
|
+
if (change.type === "add") {
|
|
245
|
+
return `A ${path.relative(Instance.worktree, change.filePath).replaceAll("\\", "/")}`
|
|
246
|
+
}
|
|
247
|
+
if (change.type === "delete") {
|
|
248
|
+
return `D ${path.relative(Instance.worktree, change.filePath).replaceAll("\\", "/")}`
|
|
249
|
+
}
|
|
250
|
+
const target = change.movePath ?? change.filePath
|
|
251
|
+
return `M ${path.relative(Instance.worktree, target).replaceAll("\\", "/")}`
|
|
252
|
+
})
|
|
253
|
+
let output = `Success. Updated the following files:\n${summaryLines.join("\n")}`
|
|
254
|
+
|
|
255
|
+
// Report LSP errors for changed files
|
|
256
|
+
const MAX_DIAGNOSTICS_PER_FILE = 20
|
|
257
|
+
for (const change of fileChanges) {
|
|
258
|
+
if (change.type === "delete") continue
|
|
259
|
+
const target = change.movePath ?? change.filePath
|
|
260
|
+
const normalized = Filesystem.normalizePath(target)
|
|
261
|
+
const issues = diagnostics[normalized] ?? []
|
|
262
|
+
const errors = issues.filter((item) => item.severity === 1)
|
|
263
|
+
if (errors.length > 0) {
|
|
264
|
+
const limited = errors.slice(0, MAX_DIAGNOSTICS_PER_FILE)
|
|
265
|
+
const suffix =
|
|
266
|
+
errors.length > MAX_DIAGNOSTICS_PER_FILE ? `\n... and ${errors.length - MAX_DIAGNOSTICS_PER_FILE} more` : ""
|
|
267
|
+
output += `\n\nLSP errors detected in ${path.relative(Instance.worktree, target).replaceAll("\\", "/")}, please fix:\n<diagnostics file="${target}">\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n</diagnostics>`
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
title: output,
|
|
273
|
+
metadata: {
|
|
274
|
+
diff: totalDiff,
|
|
275
|
+
files,
|
|
276
|
+
diagnostics,
|
|
277
|
+
},
|
|
278
|
+
output,
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Use the `apply_patch` tool to edit files. Your patch language is a stripped‑down, file‑oriented diff format designed to be easy to parse and safe to apply. You can think of it as a high‑level envelope:
|
|
2
|
+
|
|
3
|
+
*** Begin Patch
|
|
4
|
+
[ one or more file sections ]
|
|
5
|
+
*** End Patch
|
|
6
|
+
|
|
7
|
+
Within that envelope, you get a sequence of file operations.
|
|
8
|
+
You MUST include a header to specify the action you are taking.
|
|
9
|
+
Each operation starts with one of three headers:
|
|
10
|
+
|
|
11
|
+
*** Add File: <path> - create a new file. Every following line is a + line (the initial contents).
|
|
12
|
+
*** Delete File: <path> - remove an existing file. Nothing follows.
|
|
13
|
+
*** Update File: <path> - patch an existing file in place (optionally with a rename).
|
|
14
|
+
|
|
15
|
+
Example patch:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
*** Begin Patch
|
|
19
|
+
*** Add File: hello.txt
|
|
20
|
+
+Hello world
|
|
21
|
+
*** Update File: src/app.py
|
|
22
|
+
*** Move to: src/main.py
|
|
23
|
+
@@ def greet():
|
|
24
|
+
-print("Hi")
|
|
25
|
+
+print("Hello, world!")
|
|
26
|
+
*** Delete File: obsolete.txt
|
|
27
|
+
*** End Patch
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It is important to remember:
|
|
31
|
+
|
|
32
|
+
- You must include a header with your intended action (Add/Delete/Update)
|
|
33
|
+
- You must prefix new lines with `+` even when creating a new file
|