@neurocode-ai/core 1.18.8
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/bin/neurocode +199 -0
- package/bunfig.toml +2 -0
- package/drizzle.config.ts +10 -0
- package/package.json +131 -0
- package/schema.json +2071 -0
- package/script/fix-node-pty.ts +28 -0
- package/script/migration.ts +196 -0
- package/src/account/sql.ts +39 -0
- package/src/account.ts +101 -0
- package/src/agent.ts +111 -0
- package/src/aisdk.ts +235 -0
- package/src/background-job.ts +365 -0
- package/src/catalog.ts +301 -0
- package/src/command.ts +64 -0
- package/src/config/agent.ts +25 -0
- package/src/config/attachments.ts +15 -0
- package/src/config/command.ts +12 -0
- package/src/config/compaction.ts +15 -0
- package/src/config/experimental.ts +18 -0
- package/src/config/formatter.ts +12 -0
- package/src/config/lsp.ts +18 -0
- package/src/config/markdown.ts +36 -0
- package/src/config/mcp.ts +48 -0
- package/src/config/plugin/agent.ts +179 -0
- package/src/config/plugin/command.ts +83 -0
- package/src/config/plugin/external.ts +91 -0
- package/src/config/plugin/provider.ts +113 -0
- package/src/config/plugin/reference.ts +70 -0
- package/src/config/plugin/skill.ts +50 -0
- package/src/config/plugin.ts +13 -0
- package/src/config/provider.ts +71 -0
- package/src/config/reference.ts +22 -0
- package/src/config/tool-output.ts +9 -0
- package/src/config/watcher.ts +7 -0
- package/src/config.ts +227 -0
- package/src/control-plane/move-session.ts +148 -0
- package/src/control-plane/workspace.sql.ts +20 -0
- package/src/credential/sql.ts +14 -0
- package/src/credential.ts +138 -0
- package/src/cross-spawn-spawner.ts +507 -0
- package/src/data-migration.sql.ts +6 -0
- package/src/database/database.ts +57 -0
- package/src/database/migration/20260127222353_familiar_lady_ursula.ts +107 -0
- package/src/database/migration/20260211171708_add_project_commands.ts +11 -0
- package/src/database/migration/20260213144116_wakeful_the_professor.ts +23 -0
- package/src/database/migration/20260225215848_workspace.ts +19 -0
- package/src/database/migration/20260227213759_add_session_workspace_id.ts +12 -0
- package/src/database/migration/20260228203230_blue_harpoon.ts +30 -0
- package/src/database/migration/20260303231226_add_workspace_fields.ts +15 -0
- package/src/database/migration/20260309230000_move_org_to_state.ts +15 -0
- package/src/database/migration/20260312043431_session_message_cursor.ts +16 -0
- package/src/database/migration/20260323234822_events.ts +26 -0
- package/src/database/migration/20260410174513_workspace-name.ts +29 -0
- package/src/database/migration/20260413175956_chief_energizer.ts +24 -0
- package/src/database/migration/20260423070820_add_icon_url_override.ts +14 -0
- package/src/database/migration/20260427172553_slow_nightmare.ts +30 -0
- package/src/database/migration/20260428004200_add_session_path.ts +11 -0
- package/src/database/migration/20260501142318_next_venus.ts +12 -0
- package/src/database/migration/20260504145000_add_sync_owner.ts +11 -0
- package/src/database/migration/20260507164347_add_workspace_time.ts +11 -0
- package/src/database/migration/20260510033149_session_usage.ts +56 -0
- package/src/database/migration/20260511000411_data_migration_state.ts +16 -0
- package/src/database/migration/20260511173437_session-metadata.ts +16 -0
- package/src/database/migration/20260601010001_normalize_storage_paths.ts +22 -0
- package/src/database/migration/20260601202201_amazing_prowler.ts +11 -0
- package/src/database/migration/20260602002951_lowly_union_jack.ts +24 -0
- package/src/database/migration/20260602182828_add_project_directories.ts +20 -0
- package/src/database/migration/20260603001617_session_message_projection_indexes.ts +19 -0
- package/src/database/migration/20260603040000_session_message_projection_order.ts +19 -0
- package/src/database/migration/20260603141458_session_input_inbox.ts +25 -0
- package/src/database/migration/20260603160727_jittery_ezekiel_stane.ts +20 -0
- package/src/database/migration/20260604172448_event_sourced_session_input.ts +47 -0
- package/src/database/migration/20260605003541_add_session_context_snapshot.ts +21 -0
- package/src/database/migration/20260605042240_add_context_epoch_agent.ts +11 -0
- package/src/database/migration/20260611035744_credential.ts +25 -0
- package/src/database/migration/20260611192811_lush_chimera.ts +25 -0
- package/src/database/migration/20260612174303_project_dir_strategy.ts +29 -0
- package/src/database/migration/20260622142730_simplify_session_context_epoch.ts +13 -0
- package/src/database/migration/20260622170816_reset_v2_session_state.ts +17 -0
- package/src/database/migration/20260622202450_simplify_session_input.ts +17 -0
- package/src/database/migration.gen.ts +44 -0
- package/src/database/migration.ts +81 -0
- package/src/database/path.ts +91 -0
- package/src/database/schema.gen.ts +274 -0
- package/src/database/schema.sql.ts +10 -0
- package/src/database/sqlite.bun.ts +183 -0
- package/src/database/sqlite.node.ts +178 -0
- package/src/database/sqlite.ts +8 -0
- package/src/effect/app-node-builder.ts +23 -0
- package/src/effect/app-node-platform.ts +18 -0
- package/src/effect/app-node.ts +14 -0
- package/src/effect/dfdf +1 -0
- package/src/effect/keyed-mutex.ts +45 -0
- package/src/effect/layer-node.ts +333 -0
- package/src/effect/memo-map.ts +3 -0
- package/src/effect/runtime.ts +21 -0
- package/src/effect/service-use.ts +43 -0
- package/src/event/sql.ts +25 -0
- package/src/event.ts +638 -0
- package/src/file-mutation.ts +207 -0
- package/src/file.ts +6 -0
- package/src/filesystem/fff.bun.ts +140 -0
- package/src/filesystem/fff.node.ts +138 -0
- package/src/filesystem/ignore.ts +67 -0
- package/src/filesystem/protected.ts +53 -0
- package/src/filesystem/search.ts +239 -0
- package/src/filesystem/watcher.ts +140 -0
- package/src/filesystem.ts +118 -0
- package/src/flag/flag.ts +78 -0
- package/src/fs-util.ts +274 -0
- package/src/git.ts +987 -0
- package/src/github-copilot/README.md +5 -0
- package/src/github-copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
- package/src/github-copilot/chat/get-response-metadata.ts +15 -0
- package/src/github-copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/src/github-copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/github-copilot/chat/openai-compatible-chat-language-model.ts +815 -0
- package/src/github-copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/github-copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/github-copilot/chat/openai-compatible-prepare-tools.ts +83 -0
- package/src/github-copilot/copilot-provider.ts +100 -0
- package/src/github-copilot/openai-compatible-error.ts +27 -0
- package/src/github-copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/src/github-copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/github-copilot/responses/openai-config.ts +18 -0
- package/src/github-copilot/responses/openai-error.ts +22 -0
- package/src/github-copilot/responses/openai-responses-api-types.ts +214 -0
- package/src/github-copilot/responses/openai-responses-language-model.ts +1770 -0
- package/src/github-copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/src/github-copilot/responses/openai-responses-settings.ts +1 -0
- package/src/github-copilot/responses/tool/code-interpreter.ts +87 -0
- package/src/github-copilot/responses/tool/file-search.ts +127 -0
- package/src/github-copilot/responses/tool/image-generation.ts +114 -0
- package/src/github-copilot/responses/tool/local-shell.ts +64 -0
- package/src/github-copilot/responses/tool/web-search-preview.ts +103 -0
- package/src/github-copilot/responses/tool/web-search.ts +102 -0
- package/src/global.ts +87 -0
- package/src/id/id.ts +47 -0
- package/src/image/photon.ts +94 -0
- package/src/image.ts +81 -0
- package/src/installation/version.ts +8 -0
- package/src/instruction-context.ts +101 -0
- package/src/integration/connection.ts +12 -0
- package/src/integration.ts +520 -0
- package/src/location-mutation.ts +162 -0
- package/src/location-service-map.ts +18 -0
- package/src/location-services.ts +115 -0
- package/src/location.ts +39 -0
- package/src/markdown.d.ts +4 -0
- package/src/model.ts +41 -0
- package/src/models-dev.ts +260 -0
- package/src/npm-config.ts +40 -0
- package/src/npm.ts +269 -0
- package/src/oauth/page.ts +276 -0
- package/src/observability/logging.ts +71 -0
- package/src/observability/otlp.ts +79 -0
- package/src/observability/shared.ts +1 -0
- package/src/observability.ts +24 -0
- package/src/patch.ts +197 -0
- package/src/permission/saved.ts +79 -0
- package/src/permission/sql.ts +20 -0
- package/src/permission.ts +310 -0
- package/src/plugin/agent.ts +206 -0
- package/src/plugin/command/initialize.txt +65 -0
- package/src/plugin/command/review.txt +100 -0
- package/src/plugin/command.ts +25 -0
- package/src/plugin/host.ts +219 -0
- package/src/plugin/internal.ts +153 -0
- package/src/plugin/layer-map.example.ts +94 -0
- package/src/plugin/models-dev.ts +183 -0
- package/src/plugin/promise.ts +93 -0
- package/src/plugin/provider/alibaba.ts +15 -0
- package/src/plugin/provider/amazon-bedrock.ts +126 -0
- package/src/plugin/provider/anthropic.ts +27 -0
- package/src/plugin/provider/azure.ts +82 -0
- package/src/plugin/provider/cerebras.ts +26 -0
- package/src/plugin/provider/cloudflare-ai-gateway.ts +81 -0
- package/src/plugin/provider/cloudflare-workers-ai.ts +81 -0
- package/src/plugin/provider/cohere.ts +15 -0
- package/src/plugin/provider/deepinfra.ts +15 -0
- package/src/plugin/provider/dynamic.ts +31 -0
- package/src/plugin/provider/gateway.ts +15 -0
- package/src/plugin/provider/github-copilot.ts +52 -0
- package/src/plugin/provider/gitlab.ts +65 -0
- package/src/plugin/provider/google-vertex.ts +173 -0
- package/src/plugin/provider/google.ts +15 -0
- package/src/plugin/provider/groq.ts +15 -0
- package/src/plugin/provider/kilo.ts +21 -0
- package/src/plugin/provider/llmgateway.ts +26 -0
- package/src/plugin/provider/mistral.ts +15 -0
- package/src/plugin/provider/nvidia.ts +22 -0
- package/src/plugin/provider/openai-compatible.ts +17 -0
- package/src/plugin/provider/openai.ts +292 -0
- package/src/plugin/provider/opencode.ts +311 -0
- package/src/plugin/provider/openrouter.ts +36 -0
- package/src/plugin/provider/perplexity.ts +15 -0
- package/src/plugin/provider/sap-ai-core.ts +46 -0
- package/src/plugin/provider/snowflake-cortex.ts +89 -0
- package/src/plugin/provider/togetherai.ts +15 -0
- package/src/plugin/provider/venice.ts +15 -0
- package/src/plugin/provider/vercel.ts +27 -0
- package/src/plugin/provider/xai.ts +22 -0
- package/src/plugin/provider/zenmux.ts +21 -0
- package/src/plugin/provider.ts +71 -0
- package/src/plugin/skill/customize-neurocode.md +452 -0
- package/src/plugin/skill.ts +31 -0
- package/src/plugin/variant.ts +39 -0
- package/src/plugin.ts +167 -0
- package/src/policy.ts +49 -0
- package/src/process.ts +261 -0
- package/src/project/copy-strategies.ts +35 -0
- package/src/project/copy.ts +292 -0
- package/src/project/directories.ts +158 -0
- package/src/project/schema.ts +16 -0
- package/src/project/sql.ts +35 -0
- package/src/project.ts +136 -0
- package/src/provider.ts +25 -0
- package/src/pty/protocol.ts +37 -0
- package/src/pty/pty.bun.ts +26 -0
- package/src/pty/pty.node.ts +29 -0
- package/src/pty/pty.ts +25 -0
- package/src/pty/schema.ts +1 -0
- package/src/pty/ticket.ts +56 -0
- package/src/pty.ts +318 -0
- package/src/public-event-manifest.ts +7 -0
- package/src/question.ts +153 -0
- package/src/reference/guidance.ts +69 -0
- package/src/reference.ts +125 -0
- package/src/repository-cache.ts +259 -0
- package/src/repository.ts +214 -0
- package/src/ripgrep/binary.ts +132 -0
- package/src/ripgrep.ts +281 -0
- package/src/schema.ts +79 -0
- package/src/session/compaction.ts +241 -0
- package/src/session/context-epoch.ts +174 -0
- package/src/session/error.ts +24 -0
- package/src/session/event.ts +2 -0
- package/src/session/execution/local.ts +46 -0
- package/src/session/execution.ts +34 -0
- package/src/session/history.ts +101 -0
- package/src/session/info.ts +50 -0
- package/src/session/input.ts +288 -0
- package/src/session/message-updater.ts +397 -0
- package/src/session/message.ts +2 -0
- package/src/session/projector.ts +458 -0
- package/src/session/prompt.ts +1 -0
- package/src/session/revert.ts +121 -0
- package/src/session/run-coordinator.ts +104 -0
- package/src/session/runner/index.ts +28 -0
- package/src/session/runner/llm.ts +432 -0
- package/src/session/runner/max-steps.ts +16 -0
- package/src/session/runner/model.ts +218 -0
- package/src/session/runner/publish-llm-event.ts +423 -0
- package/src/session/runner/to-llm-message.ts +171 -0
- package/src/session/schema.ts +9 -0
- package/src/session/sql.ts +176 -0
- package/src/session/store.ts +63 -0
- package/src/session/todo.ts +78 -0
- package/src/session.ts +486 -0
- package/src/share/sql.ts +13 -0
- package/src/shell.ts +226 -0
- package/src/skill/discovery.ts +213 -0
- package/src/skill/guidance.ts +76 -0
- package/src/skill.ts +132 -0
- package/src/snapshot.ts +266 -0
- package/src/state.ts +128 -0
- package/src/system-context/builtins.ts +50 -0
- package/src/system-context/index.ts +320 -0
- package/src/system-context/registry.ts +49 -0
- package/src/tool/AGENTS.md +59 -0
- package/src/tool/application-tools.ts +57 -0
- package/src/tool/apply-patch.ts +219 -0
- package/src/tool/bash.ts +207 -0
- package/src/tool/builtins.ts +48 -0
- package/src/tool/edit.ts +223 -0
- package/src/tool/glob.ts +105 -0
- package/src/tool/grep.ts +137 -0
- package/src/tool/http-body.ts +30 -0
- package/src/tool/question.ts +94 -0
- package/src/tool/read-filesystem.ts +366 -0
- package/src/tool/read.ts +117 -0
- package/src/tool/registry.ts +147 -0
- package/src/tool/skill.ts +109 -0
- package/src/tool/todowrite.ts +62 -0
- package/src/tool/tool.ts +162 -0
- package/src/tool/tools.ts +13 -0
- package/src/tool/webfetch.ts +218 -0
- package/src/tool/websearch.ts +260 -0
- package/src/tool/write.ts +101 -0
- package/src/tool-output-store.ts +211 -0
- package/src/util/array.ts +10 -0
- package/src/util/binary.ts +41 -0
- package/src/util/effect-flock.ts +284 -0
- package/src/util/encode.ts +51 -0
- package/src/util/error.ts +70 -0
- package/src/util/flock.ts +358 -0
- package/src/util/glob.ts +34 -0
- package/src/util/hash.ts +11 -0
- package/src/util/identifier.ts +1 -0
- package/src/util/iife.ts +3 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/module.ts +10 -0
- package/src/util/path.ts +37 -0
- package/src/util/retry.ts +42 -0
- package/src/util/slug.ts +74 -0
- package/src/util/token.ts +5 -0
- package/src/util/which.ts +14 -0
- package/src/util/wildcard.ts +14 -0
- package/src/v1/config/agent.ts +89 -0
- package/src/v1/config/attachment.ts +25 -0
- package/src/v1/config/command.ts +13 -0
- package/src/v1/config/config.ts +192 -0
- package/src/v1/config/console-state.ts +16 -0
- package/src/v1/config/error.ts +39 -0
- package/src/v1/config/formatter.ts +13 -0
- package/src/v1/config/layout.ts +6 -0
- package/src/v1/config/lsp.ts +80 -0
- package/src/v1/config/mcp.ts +63 -0
- package/src/v1/config/migrate.ts +254 -0
- package/src/v1/config/permission.ts +50 -0
- package/src/v1/config/plugin.ts +9 -0
- package/src/v1/config/provider-options.ts +227 -0
- package/src/v1/config/provider.ts +121 -0
- package/src/v1/config/server.ts +19 -0
- package/src/v1/config/skills.ts +13 -0
- package/src/v1/permission.ts +33 -0
- package/src/v1/session.ts +68 -0
- package/src/v2-schema.ts +3 -0
- package/src/workspace.ts +6 -0
- package/sst-env.d.ts +10 -0
- package/test/agent.test.ts +131 -0
- package/test/application-tools.test.ts +287 -0
- package/test/background-job.test.ts +106 -0
- package/test/catalog.test.ts +353 -0
- package/test/command.test.ts +56 -0
- package/test/config/agent.test.ts +349 -0
- package/test/config/command.test.ts +83 -0
- package/test/config/config.test.ts +798 -0
- package/test/config/fixtures/plugin/directory-plugin.ts +13 -0
- package/test/config/plugin.test.ts +248 -0
- package/test/config/provider-options.test.ts +224 -0
- package/test/config/provider.test.ts +269 -0
- package/test/config/skill.test.ts +80 -0
- package/test/credential.test.ts +36 -0
- package/test/database-migration.test.ts +644 -0
- package/test/effect/cross-spawn-spawner.test.ts +426 -0
- package/test/effect/keyed-mutex.test.ts +73 -0
- package/test/effect/layer-node/layer-node-types.test.ts +143 -0
- package/test/effect/layer-node/layer-node.test.ts +261 -0
- package/test/effect/layer-node/node-build.test.ts +125 -0
- package/test/effect/observability.test.ts +109 -0
- package/test/event.test.ts +1124 -0
- package/test/file-mutation.test.ts +368 -0
- package/test/filesystem/filesystem.test.ts +387 -0
- package/test/filesystem/ignore.test.ts +10 -0
- package/test/filesystem/search.test.ts +44 -0
- package/test/filesystem/watcher.test.ts +266 -0
- package/test/fixture/effect-flock-worker.ts +60 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/git.ts +49 -0
- package/test/fixture/location.ts +26 -0
- package/test/fixture/tmpdir.ts +25 -0
- package/test/fixtures/recordings/session-runner/openai-chat-streams-text.json +27 -0
- package/test/git.test.ts +164 -0
- package/test/github-copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/github-copilot/copilot-chat-model.test.ts +592 -0
- package/test/github-copilot/openai-responses-language-model.test.ts +206 -0
- package/test/global.test.ts +16 -0
- package/test/instruction-context.test.ts +323 -0
- package/test/integration.test.ts +349 -0
- package/test/legacy-event-schema.test.ts +16 -0
- package/test/lib/effect.ts +53 -0
- package/test/lib/tool.ts +20 -0
- package/test/location-filesystem.test.ts +69 -0
- package/test/location-layer.test.ts +226 -0
- package/test/location-mutation.test.ts +178 -0
- package/test/location.test.ts +42 -0
- package/test/model.test.ts +23 -0
- package/test/models.test.ts +290 -0
- package/test/move-session.test.ts +235 -0
- package/test/npm-config.test.ts +51 -0
- package/test/npm.test.ts +84 -0
- package/test/oauth-page.test.ts +15 -0
- package/test/patch.test.ts +68 -0
- package/test/permission.test.ts +315 -0
- package/test/plugin/command.test.ts +47 -0
- package/test/plugin/fixture.ts +52 -0
- package/test/plugin/fixtures/config-effect-plugin.ts +15 -0
- package/test/plugin/fixtures/config-promise-plugin.ts +13 -0
- package/test/plugin/fixtures/invalid-plugin.ts +1 -0
- package/test/plugin/fixtures/models-dev.json +14 -0
- package/test/plugin/fixtures/provider-factory.ts +9 -0
- package/test/plugin/host.ts +303 -0
- package/test/plugin/models-dev.test.ts +170 -0
- package/test/plugin/promise.test.ts +67 -0
- package/test/plugin/provider-alibaba.test.ts +92 -0
- package/test/plugin/provider-amazon-bedrock.test.ts +622 -0
- package/test/plugin/provider-anthropic.test.ts +94 -0
- package/test/plugin/provider-azure-cognitive-services.test.ts +199 -0
- package/test/plugin/provider-azure.test.ts +293 -0
- package/test/plugin/provider-cerebras.test.ts +136 -0
- package/test/plugin/provider-cloudflare-ai-gateway.test.ts +426 -0
- package/test/plugin/provider-cloudflare-workers-ai.test.ts +279 -0
- package/test/plugin/provider-cohere.test.ts +123 -0
- package/test/plugin/provider-deepinfra.test.ts +159 -0
- package/test/plugin/provider-dynamic.test.ts +184 -0
- package/test/plugin/provider-gateway.test.ts +115 -0
- package/test/plugin/provider-github-copilot.test.ts +278 -0
- package/test/plugin/provider-gitlab.test.ts +308 -0
- package/test/plugin/provider-google-vertex-anthropic.test.ts +264 -0
- package/test/plugin/provider-google-vertex.test.ts +387 -0
- package/test/plugin/provider-google.test.ts +80 -0
- package/test/plugin/provider-groq.test.ts +121 -0
- package/test/plugin/provider-kilo.test.ts +99 -0
- package/test/plugin/provider-llmgateway.test.ts +80 -0
- package/test/plugin/provider-mistral.test.ts +129 -0
- package/test/plugin/provider-nvidia.test.ts +97 -0
- package/test/plugin/provider-openai-compatible.test.ts +107 -0
- package/test/plugin/provider-openai.test.ts +176 -0
- package/test/plugin/provider-opencode.test.ts +423 -0
- package/test/plugin/provider-openrouter.test.ts +113 -0
- package/test/plugin/provider-perplexity.test.ts +122 -0
- package/test/plugin/provider-sap-ai-core.test.ts +159 -0
- package/test/plugin/provider-snowflake-cortex.test.ts +261 -0
- package/test/plugin/provider-togetherai.test.ts +129 -0
- package/test/plugin/provider-venice.test.ts +115 -0
- package/test/plugin/provider-vercel.test.ts +83 -0
- package/test/plugin/provider-xai.test.ts +125 -0
- package/test/plugin/provider-zenmux.test.ts +110 -0
- package/test/plugin/skill.test.ts +25 -0
- package/test/plugin/variant.test.ts +67 -0
- package/test/plugin.test.ts +71 -0
- package/test/policy.test.ts +85 -0
- package/test/preload.ts +5 -0
- package/test/process/process.test.ts +368 -0
- package/test/project-copy.test.ts +400 -0
- package/test/project-directories.test.ts +61 -0
- package/test/project.test.ts +221 -0
- package/test/provider-mistral.test.ts +282 -0
- package/test/provider-xai-responses.test.ts +32 -0
- package/test/pty/info-schema.test.ts +32 -0
- package/test/pty/protocol.test.ts +27 -0
- package/test/pty/pty-session.test.ts +240 -0
- package/test/pty/ticket.test.ts +62 -0
- package/test/question.test.ts +114 -0
- package/test/reference-guidance.test.ts +76 -0
- package/test/reference.test.ts +78 -0
- package/test/repository-cache.test.ts +153 -0
- package/test/repository.test.ts +71 -0
- package/test/ripgrep.test.ts +65 -0
- package/test/session-compaction.test.ts +27 -0
- package/test/session-create.test.ts +425 -0
- package/test/session-history.test.ts +165 -0
- package/test/session-projector.test.ts +533 -0
- package/test/session-prompt.test.ts +584 -0
- package/test/session-run-coordinator.test.ts +418 -0
- package/test/session-runner-message.test.ts +501 -0
- package/test/session-runner-model.test.ts +347 -0
- package/test/session-runner-recorded.test.ts +193 -0
- package/test/session-runner-tool-events.test.ts +136 -0
- package/test/session-runner-tool-registry.test.ts +452 -0
- package/test/session-runner.test.ts +3365 -0
- package/test/session-todo.test.ts +94 -0
- package/test/session-tool-progress.test.ts +158 -0
- package/test/shared-schema.test.ts +206 -0
- package/test/shell.test.ts +108 -0
- package/test/skill/guidance.test.ts +144 -0
- package/test/skill-discovery.test.ts +165 -0
- package/test/skill.test.ts +125 -0
- package/test/snapshot.test.ts +178 -0
- package/test/state.test.ts +115 -0
- package/test/system-context/builtins.test.ts +129 -0
- package/test/system-context/index.test.ts +307 -0
- package/test/system-context/registry.test.ts +114 -0
- package/test/tool-apply-patch.test.ts +436 -0
- package/test/tool-bash.test.ts +437 -0
- package/test/tool-edit.test.ts +434 -0
- package/test/tool-output-store.test.ts +247 -0
- package/test/tool-question.test.ts +162 -0
- package/test/tool-read-filesystem.test.ts +118 -0
- package/test/tool-read.test.ts +674 -0
- package/test/tool-skill.test.ts +149 -0
- package/test/tool-todowrite.test.ts +125 -0
- package/test/tool-webfetch.test.ts +281 -0
- package/test/tool-websearch.test.ts +316 -0
- package/test/tool-write.test.ts +305 -0
- package/test/util/effect-flock.test.ts +392 -0
- package/test/util/flock.test.ts +428 -0
- package/test/util/which.test.ts +100 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { Brand, Context, Layer } from "effect"
|
|
2
|
+
|
|
3
|
+
type AnyNode = Node<unknown, unknown, any>
|
|
4
|
+
type RuntimeLayer = Layer.Layer<never, unknown, unknown>
|
|
5
|
+
type NodeList<Item extends AnyNode = AnyNode> = readonly [] | readonly [Item, ...Item[]]
|
|
6
|
+
export type Output<Item> = [Item] extends [never] ? never : Item extends Node<infer A, unknown, any> ? A : never
|
|
7
|
+
export type Error<Item> = [Item] extends [never] ? never : Item extends Node<unknown, infer E, any> ? E : never
|
|
8
|
+
type NodeTag<Item> = [Item] extends [never] ? undefined : Item extends Node<unknown, unknown, infer T> ? T : never
|
|
9
|
+
type Missing<Required, Dependencies extends NodeList> = Exclude<Required, Output<Dependencies[number]>>
|
|
10
|
+
type CheckDependencies<Implementation extends Layer.Any, Dependencies extends NodeList> = [
|
|
11
|
+
Missing<Layer.Services<Implementation>, Dependencies>,
|
|
12
|
+
] extends [never]
|
|
13
|
+
? unknown
|
|
14
|
+
: { readonly "Missing dependencies": Missing<Layer.Services<Implementation>, Dependencies> }
|
|
15
|
+
declare const $OutputType: unique symbol
|
|
16
|
+
declare const $ErrorType: unique symbol
|
|
17
|
+
|
|
18
|
+
export type Tag<Name extends string = string> = Name & Brand.Brand<"LayerNode.Tag">
|
|
19
|
+
|
|
20
|
+
const makeTag = Brand.nominal<Tag>()
|
|
21
|
+
|
|
22
|
+
export interface Node<A, E = never, T extends Tag | undefined = undefined> {
|
|
23
|
+
readonly kind: "layer" | "unbound" | "group"
|
|
24
|
+
readonly name: string
|
|
25
|
+
readonly service?: Context.Service.Any
|
|
26
|
+
readonly implementation?: Layer.Any
|
|
27
|
+
readonly dependencies: readonly AnyNode[]
|
|
28
|
+
readonly tag?: T
|
|
29
|
+
readonly [$OutputType]?: () => A
|
|
30
|
+
readonly [$ErrorType]?: () => E
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type NodeIdentity =
|
|
34
|
+
| { readonly service: Context.Service.Any; readonly name?: never }
|
|
35
|
+
| { readonly name: string; readonly service?: never }
|
|
36
|
+
type DistributiveOmit<A, K extends PropertyKey> = A extends unknown ? Omit<A, K> : never
|
|
37
|
+
|
|
38
|
+
export type TagConfig = Readonly<Record<string, readonly string[]>>
|
|
39
|
+
type TagNames<Config extends TagConfig> = keyof Config & string
|
|
40
|
+
type NodeInTags<Names extends string> = Node<unknown, unknown, Tag<Names> | undefined>
|
|
41
|
+
type CheckTags<Items extends NodeList, Names extends string> = [Exclude<Items[number], NodeInTags<Names>>] extends [
|
|
42
|
+
never,
|
|
43
|
+
]
|
|
44
|
+
? unknown
|
|
45
|
+
: { readonly "Invalid tag dependencies": Exclude<Items[number], NodeInTags<Names>> }
|
|
46
|
+
|
|
47
|
+
export interface Tags<Config extends TagConfig> {
|
|
48
|
+
readonly values: { readonly [Name in TagNames<Config>]: Tag<Name> }
|
|
49
|
+
readonly make: <Name extends TagNames<Config>>(
|
|
50
|
+
name: Name,
|
|
51
|
+
) => <const Implementation extends Layer.Any, const Items extends NodeList>(
|
|
52
|
+
input: DistributiveOmit<MakeInput<Implementation, Items, Tag<Name>>, "tag"> &
|
|
53
|
+
CheckTags<Items, Name | Extract<Config[Name][number], string>>,
|
|
54
|
+
) => Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, Tag<Name>>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function tags<const Config extends { readonly [Name in keyof Config]: readonly (keyof Config & string)[] }>(
|
|
58
|
+
config: Config,
|
|
59
|
+
): Tags<Config> {
|
|
60
|
+
const names = Object.keys(config) as TagNames<Config>[]
|
|
61
|
+
const values = Object.fromEntries(names.map((name) => [name, makeTag(name)])) as Tags<Config>["values"]
|
|
62
|
+
return {
|
|
63
|
+
values,
|
|
64
|
+
make: ((name: TagNames<Config>) => (input: DistributiveOmit<MakeInput<Layer.Any, NodeList, Tag>, "tag">) =>
|
|
65
|
+
make({ ...input, tag: values[name] })) as Tags<Config>["make"],
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Nodes ---------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
type MakeInput<
|
|
72
|
+
Implementation extends Layer.Any,
|
|
73
|
+
Items extends NodeList,
|
|
74
|
+
T extends Tag | undefined = undefined,
|
|
75
|
+
> = NodeIdentity & {
|
|
76
|
+
readonly layer: Implementation
|
|
77
|
+
readonly deps: Items & CheckDependencies<Implementation, NoInfer<Items>>
|
|
78
|
+
readonly tag?: T
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function make<
|
|
82
|
+
const Implementation extends Layer.Any,
|
|
83
|
+
const Items extends NodeList,
|
|
84
|
+
const T extends Tag | undefined = undefined,
|
|
85
|
+
>(
|
|
86
|
+
input: MakeInput<Implementation, Items, T>,
|
|
87
|
+
): Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, T> {
|
|
88
|
+
return {
|
|
89
|
+
kind: "layer",
|
|
90
|
+
name: input.service !== undefined ? input.service.key : input.name,
|
|
91
|
+
service: input.service,
|
|
92
|
+
implementation: input.layer,
|
|
93
|
+
dependencies: input.deps,
|
|
94
|
+
tag: input.tag,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function unbound<R, Shape, const T extends Tag>(service: Context.Key<R, Shape>, tag: T): Node<R, never, T> {
|
|
99
|
+
return {
|
|
100
|
+
kind: "unbound",
|
|
101
|
+
name: service.key,
|
|
102
|
+
service,
|
|
103
|
+
dependencies: [],
|
|
104
|
+
tag,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function group<const Items extends readonly AnyNode[]>(
|
|
109
|
+
dependencies: Items,
|
|
110
|
+
): Node<Output<Items[number]>, Error<Items[number]>, NodeTag<Items[number]>> {
|
|
111
|
+
return { kind: "group", name: "group", dependencies }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type Replacement = readonly [source: AnyNode, replacement: AnyNode | Layer.Any]
|
|
115
|
+
export type Replacements = readonly Replacement[]
|
|
116
|
+
|
|
117
|
+
type CheckReplacementErrors<SourceError, ReplacementError> = [Exclude<ReplacementError, SourceError>] extends [never]
|
|
118
|
+
? unknown
|
|
119
|
+
: { readonly "New replacement errors": Exclude<ReplacementError, SourceError> }
|
|
120
|
+
|
|
121
|
+
type CheckReplacement<Item> = Item extends readonly [Node<infer A, infer E, infer T>, infer Replacement]
|
|
122
|
+
? Replacement extends Node<NoInfer<A>, infer E2, T>
|
|
123
|
+
? CheckReplacementErrors<E, NoInfer<E2>>
|
|
124
|
+
: Replacement extends Layer.Layer<NoInfer<A>, infer E2, never>
|
|
125
|
+
? CheckReplacementErrors<E, NoInfer<E2>>
|
|
126
|
+
: { readonly "Invalid replacement": Replacement }
|
|
127
|
+
: { readonly "Invalid replacement": Item }
|
|
128
|
+
|
|
129
|
+
type CheckReplacements<Items extends Replacements> = {
|
|
130
|
+
readonly [K in keyof Items]: CheckReplacement<Items[K]>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
type ValidReplacements<Items extends Replacements> = Items & CheckReplacements<Items>
|
|
134
|
+
|
|
135
|
+
function replacementNode(source: AnyNode, replacement: AnyNode | Layer.Any) {
|
|
136
|
+
const replacementNode = isNode(replacement)
|
|
137
|
+
? replacement
|
|
138
|
+
: make({
|
|
139
|
+
...nodeMakeIdentity(source),
|
|
140
|
+
layer: replacement as Layer.Layer<unknown, unknown>,
|
|
141
|
+
deps: [],
|
|
142
|
+
tag: source.tag,
|
|
143
|
+
})
|
|
144
|
+
if (source.name !== replacementNode.name) {
|
|
145
|
+
throw new Error(`Cannot replace ${source.name} with ${replacementNode.name}`)
|
|
146
|
+
}
|
|
147
|
+
if (source.tag !== replacementNode.tag) {
|
|
148
|
+
throw new Error(`Cannot replace ${source.name} across tags`)
|
|
149
|
+
}
|
|
150
|
+
return replacementNode
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function nodeMakeIdentity(node: AnyNode): NodeIdentity {
|
|
154
|
+
if (node.service !== undefined) return { service: node.service }
|
|
155
|
+
return { name: node.name }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function isNode(input: Layer.Any | AnyNode): input is AnyNode {
|
|
159
|
+
return "kind" in input && "dependencies" in input
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Tree -----------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
type Visit<Result> = (node: AnyNode, context: VisitContext<Result>) => Result
|
|
165
|
+
|
|
166
|
+
type VisitContext<Result> = {
|
|
167
|
+
readonly cache: Map<AnyNode, Result>
|
|
168
|
+
readonly visit: (node: AnyNode) => Result
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function walk<Result>(
|
|
172
|
+
root: AnyNode,
|
|
173
|
+
visit: Visit<Result>,
|
|
174
|
+
options: {
|
|
175
|
+
readonly cache?: Map<AnyNode, Result>
|
|
176
|
+
readonly resolve?: (node: AnyNode) => AnyNode
|
|
177
|
+
readonly detectCycles?: boolean
|
|
178
|
+
} = {},
|
|
179
|
+
) {
|
|
180
|
+
const cache = options.cache ?? new Map<AnyNode, Result>()
|
|
181
|
+
const visiting = new Set<AnyNode>()
|
|
182
|
+
const stack: AnyNode[] = []
|
|
183
|
+
|
|
184
|
+
const recur = (node: AnyNode): Result => {
|
|
185
|
+
const target = options.resolve?.(node) ?? node
|
|
186
|
+
const cached = cache.get(target)
|
|
187
|
+
if (cached !== undefined || cache.has(target)) return cached!
|
|
188
|
+
|
|
189
|
+
if (options.detectCycles !== false && visiting.has(target)) {
|
|
190
|
+
const start = stack.indexOf(target)
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Cycle detected in layer tree: ${[...stack.slice(start), target].map((item) => item.name).join(" -> ")}`,
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
visiting.add(target)
|
|
197
|
+
stack.push(target)
|
|
198
|
+
try {
|
|
199
|
+
const result = visit(target, { cache, visit: recur })
|
|
200
|
+
if (!cache.has(target)) cache.set(target, result)
|
|
201
|
+
return result
|
|
202
|
+
} finally {
|
|
203
|
+
stack.pop()
|
|
204
|
+
visiting.delete(target)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return recur(root)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function hoist<A, E, T extends Tag, const Items extends Replacements = readonly []>(
|
|
212
|
+
root: Node<A, E, any>,
|
|
213
|
+
tag: T,
|
|
214
|
+
replacements?: ValidReplacements<Items>,
|
|
215
|
+
): {
|
|
216
|
+
readonly node: Node<A, E>
|
|
217
|
+
readonly hoisted: Node<unknown, E>
|
|
218
|
+
} {
|
|
219
|
+
const hoisted = new Map<string, AnyNode>()
|
|
220
|
+
const replacementMap = replacementMapFrom(replacements)
|
|
221
|
+
|
|
222
|
+
const node = walk<AnyNode>(
|
|
223
|
+
root,
|
|
224
|
+
(node, context) => {
|
|
225
|
+
if (node.kind === "group") {
|
|
226
|
+
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
|
227
|
+
}
|
|
228
|
+
if (node.tag === tag) {
|
|
229
|
+
const existing = hoisted.get(node.name)
|
|
230
|
+
if (existing && existing !== node) {
|
|
231
|
+
throw new Error(`Tag ${tag} has conflicting implementations for ${node.name}`)
|
|
232
|
+
}
|
|
233
|
+
hoisted.set(node.name, rewriteReplacementDependencies(node, replacementMap))
|
|
234
|
+
return group([])
|
|
235
|
+
}
|
|
236
|
+
if (node.kind === "unbound") {
|
|
237
|
+
return node
|
|
238
|
+
}
|
|
239
|
+
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
|
240
|
+
},
|
|
241
|
+
{ resolve: (node) => replacementMap.get(node.name) ?? node },
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
node: node as Node<A, E>,
|
|
246
|
+
hoisted: group(Array.from(hoisted.values())) as Node<unknown, E>,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function compile<A, E, const Items extends Replacements = readonly []>(
|
|
251
|
+
root: Node<A, E, any>,
|
|
252
|
+
replacements?: ValidReplacements<Items>,
|
|
253
|
+
): Layer.Layer<A, E> {
|
|
254
|
+
const replacementMap = replacementMapFrom(replacements)
|
|
255
|
+
const cache = new Map<AnyNode, RuntimeLayer>()
|
|
256
|
+
const compileNode = (node: AnyNode) =>
|
|
257
|
+
walk<RuntimeLayer>(
|
|
258
|
+
node,
|
|
259
|
+
(node, context) => {
|
|
260
|
+
if (node.kind === "unbound") throw new Error(`Unbound layer node: ${node.name}`)
|
|
261
|
+
const dependencies = node.dependencies.flatMap(flatten).map(context.visit)
|
|
262
|
+
const implementation = node.implementation! as RuntimeLayer
|
|
263
|
+
return dependencies.length === 0
|
|
264
|
+
? implementation
|
|
265
|
+
: implementation.pipe(Layer.provide(dependencies as [RuntimeLayer, ...RuntimeLayer[]]))
|
|
266
|
+
},
|
|
267
|
+
{ cache, resolve: (node) => replacementMap.get(node.name) ?? node },
|
|
268
|
+
)
|
|
269
|
+
const layers = flatten(root).map((node) => compileNode(node))
|
|
270
|
+
const layer = layers.reduce<RuntimeLayer>((result, layer) => layer.pipe(Layer.provideMerge(result)), Layer.empty)
|
|
271
|
+
return layer as Layer.Layer<A, E>
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function replacementMapFrom(replacements?: Replacements) {
|
|
275
|
+
return (
|
|
276
|
+
replacements?.reduce((map, [source, replacement]) => {
|
|
277
|
+
const normalized = rewriteReplacementDependencies(replacementNode(source, replacement), map)
|
|
278
|
+
const current = new Map([[source.name, normalized]])
|
|
279
|
+
for (const [name, node] of map) map.set(name, rewriteReplacementDependencies(node, current))
|
|
280
|
+
map.set(source.name, normalized)
|
|
281
|
+
return map
|
|
282
|
+
}, new Map<string, AnyNode>()) ?? new Map<string, AnyNode>()
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function rewriteReplacementDependencies(root: AnyNode, replacements: ReadonlyMap<string, AnyNode>) {
|
|
287
|
+
if (replacements.size === 0) return root
|
|
288
|
+
const cache = new Map<AnyNode, AnyNode>()
|
|
289
|
+
const visiting = new Set<AnyNode>()
|
|
290
|
+
const stack: AnyNode[] = []
|
|
291
|
+
|
|
292
|
+
const recur = (node: AnyNode, isRoot = false): AnyNode => {
|
|
293
|
+
const target = isRoot ? node : (replacements.get(node.name) ?? node)
|
|
294
|
+
const cached = cache.get(target)
|
|
295
|
+
if (cached !== undefined || cache.has(target)) return cached!
|
|
296
|
+
if (visiting.has(target)) {
|
|
297
|
+
const start = stack.indexOf(target)
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Cycle detected in layer tree: ${[...stack.slice(start), target].map((item) => item.name).join(" -> ")}`,
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
visiting.add(target)
|
|
304
|
+
stack.push(target)
|
|
305
|
+
try {
|
|
306
|
+
const dependencies = target.dependencies.map((dependency) => recur(dependency))
|
|
307
|
+
const result = dependencies.every((dependency, index) => dependency === target.dependencies[index])
|
|
308
|
+
? target
|
|
309
|
+
: { ...target, dependencies }
|
|
310
|
+
cache.set(target, result)
|
|
311
|
+
return result
|
|
312
|
+
} finally {
|
|
313
|
+
stack.pop()
|
|
314
|
+
visiting.delete(target)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return recur(root, true)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function hasUnbound(root: Node<unknown, unknown, any>, source: AnyNode): boolean {
|
|
322
|
+
if (source.kind !== "unbound") throw new Error(`Cannot check non-unbound layer node: ${source.name}`)
|
|
323
|
+
return walk<boolean>(root, (node, context) => {
|
|
324
|
+
if (node === source) return true
|
|
325
|
+
return node.dependencies.some(context.visit)
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function flatten(node: AnyNode): readonly AnyNode[] {
|
|
330
|
+
return node.kind === "group" ? node.dependencies.flatMap(flatten) : [node]
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export * as LayerNode from "./layer-node"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Layer, type Context, ManagedRuntime, type Effect } from "effect"
|
|
2
|
+
import { memoMap } from "./memo-map"
|
|
3
|
+
import { Observability } from "../observability"
|
|
4
|
+
|
|
5
|
+
export function makeRuntime<I, S, E>(service: Context.Service<I, S>, layer: Layer.Layer<I, E>) {
|
|
6
|
+
let rt: ManagedRuntime.ManagedRuntime<I, E> | undefined
|
|
7
|
+
const getRuntime = () =>
|
|
8
|
+
(rt ??= ManagedRuntime.make(Layer.provideMerge(layer, Observability.layer) as Layer.Layer<I, E>, {
|
|
9
|
+
memoMap,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
runSync: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runSync(service.use(fn)),
|
|
14
|
+
runPromiseExit: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>, options?: Effect.RunOptions) =>
|
|
15
|
+
getRuntime().runPromiseExit(service.use(fn), options),
|
|
16
|
+
runPromise: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>, options?: Effect.RunOptions) =>
|
|
17
|
+
getRuntime().runPromise(service.use(fn), options),
|
|
18
|
+
runFork: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runFork(service.use(fn)),
|
|
19
|
+
runCallback: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runCallback(service.use(fn)),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Context, Effect } from "effect"
|
|
2
|
+
|
|
3
|
+
type EffectMethod = (...args: ReadonlyArray<never>) => Effect.Effect<unknown, unknown, unknown>
|
|
4
|
+
|
|
5
|
+
type ServiceUse<Identifier, Shape> = {
|
|
6
|
+
readonly [Key in keyof Shape as Shape[Key] extends EffectMethod ? Key : never]: Shape[Key] extends (
|
|
7
|
+
...args: infer Args
|
|
8
|
+
) => infer Return
|
|
9
|
+
? Args extends ReadonlyArray<unknown>
|
|
10
|
+
? Return extends Effect.Effect<infer A, infer E, infer R>
|
|
11
|
+
? (...args: Args) => Effect.Effect<A, E, R | Identifier>
|
|
12
|
+
: never
|
|
13
|
+
: never
|
|
14
|
+
: never
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const serviceUse = <Identifier, Shape>(tag: Context.Service<Identifier, Shape>) => {
|
|
18
|
+
const cache = new Map<string, (...args: unknown[]) => Effect.Effect<unknown, unknown, unknown>>()
|
|
19
|
+
// This is the only dynamic boundary: TypeScript knows the accessor shape,
|
|
20
|
+
// but Proxy property names are runtime values.
|
|
21
|
+
const access = new Proxy(
|
|
22
|
+
{},
|
|
23
|
+
{
|
|
24
|
+
get: (_, key) => {
|
|
25
|
+
if (typeof key !== "string") return undefined
|
|
26
|
+
const cached = cache.get(key)
|
|
27
|
+
if (cached) return cached
|
|
28
|
+
const accessor = (...args: unknown[]) =>
|
|
29
|
+
tag.use((service) => {
|
|
30
|
+
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Proxy keys are checked at runtime.
|
|
31
|
+
const method = service[key as keyof Shape]
|
|
32
|
+
if (typeof method !== "function") return Effect.die(new Error(`Service method not found: ${key}`))
|
|
33
|
+
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- ServiceUse exposes only Effect-returning methods.
|
|
34
|
+
return (method as (...args: unknown[]) => Effect.Effect<unknown, unknown, unknown>)(...args)
|
|
35
|
+
})
|
|
36
|
+
cache.set(key, accessor)
|
|
37
|
+
return accessor
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Proxy implements the mapped accessor surface lazily.
|
|
42
|
+
return access as ServiceUse<Identifier, Shape>
|
|
43
|
+
}
|
package/src/event/sql.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { sqliteTable, text, integer, index, uniqueIndex } from "drizzle-orm/sqlite-core"
|
|
2
|
+
import type { EventV2 } from "../event"
|
|
3
|
+
|
|
4
|
+
export const EventSequenceTable = sqliteTable("event_sequence", {
|
|
5
|
+
aggregate_id: text().notNull().primaryKey(),
|
|
6
|
+
seq: integer().notNull(),
|
|
7
|
+
owner_id: text(),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const EventTable = sqliteTable(
|
|
11
|
+
"event",
|
|
12
|
+
{
|
|
13
|
+
id: text().$type<EventV2.ID>().primaryKey(),
|
|
14
|
+
aggregate_id: text()
|
|
15
|
+
.notNull()
|
|
16
|
+
.references(() => EventSequenceTable.aggregate_id, { onDelete: "cascade" }),
|
|
17
|
+
seq: integer().notNull(),
|
|
18
|
+
type: text().notNull(),
|
|
19
|
+
data: text({ mode: "json" }).$type<Record<string, unknown>>().notNull(),
|
|
20
|
+
},
|
|
21
|
+
(table) => [
|
|
22
|
+
uniqueIndex("event_aggregate_seq_idx").on(table.aggregate_id, table.seq),
|
|
23
|
+
index("event_aggregate_type_seq_idx").on(table.aggregate_id, table.type, table.seq),
|
|
24
|
+
],
|
|
25
|
+
)
|