@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
package/src/npm.ts
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
export * as Npm from "./npm"
|
|
2
|
+
|
|
3
|
+
import path from "path"
|
|
4
|
+
import npa from "npm-package-arg"
|
|
5
|
+
import { Effect, Schema, Context, Layer, Option, FileSystem } from "effect"
|
|
6
|
+
import { NodeFileSystem } from "@effect/platform-node"
|
|
7
|
+
import { FSUtil } from "./fs-util"
|
|
8
|
+
import { Global } from "./global"
|
|
9
|
+
import { EffectFlock } from "./util/effect-flock"
|
|
10
|
+
import { makeGlobalNode } from "./effect/app-node"
|
|
11
|
+
import { filesystem } from "./effect/app-node-platform"
|
|
12
|
+
import { LayerNode } from "./effect/layer-node"
|
|
13
|
+
import { makeRuntime } from "./effect/runtime"
|
|
14
|
+
import { NpmConfig } from "./npm-config"
|
|
15
|
+
|
|
16
|
+
export class InstallFailedError extends Schema.TaggedErrorClass<InstallFailedError>()("NpmInstallFailedError", {
|
|
17
|
+
add: Schema.Array(Schema.String).pipe(Schema.optional),
|
|
18
|
+
dir: Schema.String,
|
|
19
|
+
cause: Schema.optional(Schema.Defect()),
|
|
20
|
+
}) {}
|
|
21
|
+
|
|
22
|
+
export interface EntryPoint {
|
|
23
|
+
readonly directory: string
|
|
24
|
+
readonly entrypoint?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Interface {
|
|
28
|
+
readonly add: (pkg: string) => Effect.Effect<EntryPoint, InstallFailedError | EffectFlock.LockError>
|
|
29
|
+
readonly install: (
|
|
30
|
+
dir: string,
|
|
31
|
+
input?: {
|
|
32
|
+
add: {
|
|
33
|
+
name: string
|
|
34
|
+
version?: string
|
|
35
|
+
}[]
|
|
36
|
+
},
|
|
37
|
+
) => Effect.Effect<void, EffectFlock.LockError | InstallFailedError>
|
|
38
|
+
readonly which: (pkg: string, bin?: string) => Effect.Effect<string | undefined>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class Service extends Context.Service<Service, Interface>()("@neurocode/Npm") {}
|
|
42
|
+
|
|
43
|
+
const illegal = process.platform === "win32" ? new Set(["<", ">", ":", '"', "|", "?", "*"]) : undefined
|
|
44
|
+
|
|
45
|
+
export function sanitize(pkg: string) {
|
|
46
|
+
if (!illegal) return pkg
|
|
47
|
+
return Array.from(pkg, (char) => (illegal.has(char) || char.charCodeAt(0) < 32 ? "_" : char)).join("")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const resolveEntryPoint = (name: string, dir: string): EntryPoint => {
|
|
51
|
+
let entrypoint: string | undefined
|
|
52
|
+
try {
|
|
53
|
+
entrypoint = typeof Bun !== "undefined" ? import.meta.resolve(name, dir) : import.meta.resolve(dir)
|
|
54
|
+
} catch {
|
|
55
|
+
entrypoint = undefined
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
directory: dir,
|
|
59
|
+
entrypoint,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ArboristNode {
|
|
64
|
+
name: string
|
|
65
|
+
path: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ArboristTree {
|
|
69
|
+
edgesOut: Map<string, { to?: ArboristNode }>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const layer = Layer.effect(
|
|
73
|
+
Service,
|
|
74
|
+
Effect.gen(function* () {
|
|
75
|
+
const afs = yield* FSUtil.Service
|
|
76
|
+
const global = yield* Global.Service
|
|
77
|
+
const fs = yield* FileSystem.FileSystem
|
|
78
|
+
const flock = yield* EffectFlock.Service
|
|
79
|
+
const directory = (pkg: string) => path.join(global.cache, "packages", sanitize(pkg))
|
|
80
|
+
const reify = (input: { dir: string; add?: string[] }) =>
|
|
81
|
+
Effect.gen(function* () {
|
|
82
|
+
yield* flock.acquire(`npm-install:${input.dir}`)
|
|
83
|
+
const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist"))
|
|
84
|
+
const add = input.add ?? []
|
|
85
|
+
const npmOptions = yield* NpmConfig.load(input.dir)
|
|
86
|
+
const arborist = new Arborist({
|
|
87
|
+
...npmOptions,
|
|
88
|
+
path: input.dir,
|
|
89
|
+
binLinks: true,
|
|
90
|
+
progress: false,
|
|
91
|
+
savePrefix: "",
|
|
92
|
+
ignoreScripts: true,
|
|
93
|
+
})
|
|
94
|
+
return yield* Effect.tryPromise({
|
|
95
|
+
try: () =>
|
|
96
|
+
arborist.reify({
|
|
97
|
+
...npmOptions,
|
|
98
|
+
add,
|
|
99
|
+
save: true,
|
|
100
|
+
saveType: "prod",
|
|
101
|
+
}),
|
|
102
|
+
catch: (cause) =>
|
|
103
|
+
new InstallFailedError({
|
|
104
|
+
cause,
|
|
105
|
+
add,
|
|
106
|
+
dir: input.dir,
|
|
107
|
+
}),
|
|
108
|
+
}) as Effect.Effect<ArboristTree, InstallFailedError>
|
|
109
|
+
}).pipe(
|
|
110
|
+
Effect.withSpan("Npm.reify", {
|
|
111
|
+
attributes: input,
|
|
112
|
+
}),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
const add = Effect.fn("Npm.add")(function* (pkg: string) {
|
|
116
|
+
const dir = directory(pkg)
|
|
117
|
+
const name = (() => {
|
|
118
|
+
try {
|
|
119
|
+
return npa(pkg).name ?? pkg
|
|
120
|
+
} catch {
|
|
121
|
+
return pkg
|
|
122
|
+
}
|
|
123
|
+
})()
|
|
124
|
+
|
|
125
|
+
if (yield* afs.existsSafe(path.join(dir, "node_modules", name))) {
|
|
126
|
+
return resolveEntryPoint(name, path.join(dir, "node_modules", name))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const tree = yield* reify({ dir, add: [pkg] })
|
|
130
|
+
const first = tree.edgesOut.values().next().value?.to
|
|
131
|
+
if (!first) {
|
|
132
|
+
const result = resolveEntryPoint(name, path.join(dir, "node_modules", name))
|
|
133
|
+
if (result.entrypoint) return result
|
|
134
|
+
return yield* new InstallFailedError({ add: [pkg], dir })
|
|
135
|
+
}
|
|
136
|
+
return resolveEntryPoint(first.name, first.path)
|
|
137
|
+
}, Effect.scoped)
|
|
138
|
+
|
|
139
|
+
const install: Interface["install"] = Effect.fn("Npm.install")(function* (dir, input) {
|
|
140
|
+
const canWrite = yield* afs.access(dir, { writable: true }).pipe(
|
|
141
|
+
Effect.as(true),
|
|
142
|
+
Effect.orElseSucceed(() => false),
|
|
143
|
+
)
|
|
144
|
+
if (!canWrite) return
|
|
145
|
+
|
|
146
|
+
const add = input?.add.map((pkg) => [pkg.name, pkg.version].filter(Boolean).join("@")) ?? []
|
|
147
|
+
if (
|
|
148
|
+
yield* Effect.gen(function* () {
|
|
149
|
+
const nodeModulesExists = yield* afs.existsSafe(path.join(dir, "node_modules"))
|
|
150
|
+
if (!nodeModulesExists) {
|
|
151
|
+
yield* reify({ add, dir })
|
|
152
|
+
return true
|
|
153
|
+
}
|
|
154
|
+
return false
|
|
155
|
+
}).pipe(Effect.withSpan("Npm.checkNodeModules"))
|
|
156
|
+
)
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
yield* Effect.gen(function* () {
|
|
160
|
+
const pkg = yield* afs.readJson(path.join(dir, "package.json")).pipe(Effect.orElseSucceed(() => ({})))
|
|
161
|
+
const lock = yield* afs.readJson(path.join(dir, "package-lock.json")).pipe(Effect.orElseSucceed(() => ({})))
|
|
162
|
+
|
|
163
|
+
const pkgAny = pkg as any
|
|
164
|
+
const lockAny = lock as any
|
|
165
|
+
const declared = new Set([
|
|
166
|
+
...Object.keys(pkgAny?.dependencies || {}),
|
|
167
|
+
...Object.keys(pkgAny?.devDependencies || {}),
|
|
168
|
+
...Object.keys(pkgAny?.peerDependencies || {}),
|
|
169
|
+
...Object.keys(pkgAny?.optionalDependencies || {}),
|
|
170
|
+
...(input?.add || []).map((pkg) => pkg.name),
|
|
171
|
+
])
|
|
172
|
+
|
|
173
|
+
const root = lockAny?.packages?.[""] || {}
|
|
174
|
+
const locked = new Set([
|
|
175
|
+
...Object.keys(root?.dependencies || {}),
|
|
176
|
+
...Object.keys(root?.devDependencies || {}),
|
|
177
|
+
...Object.keys(root?.peerDependencies || {}),
|
|
178
|
+
...Object.keys(root?.optionalDependencies || {}),
|
|
179
|
+
])
|
|
180
|
+
|
|
181
|
+
for (const name of declared) {
|
|
182
|
+
if (!locked.has(name)) {
|
|
183
|
+
yield* reify({ dir, add })
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}).pipe(Effect.withSpan("Npm.checkDirty"))
|
|
188
|
+
|
|
189
|
+
return
|
|
190
|
+
}, Effect.scoped)
|
|
191
|
+
|
|
192
|
+
const which = Effect.fn("Npm.which")(function* (pkg: string, bin?: string) {
|
|
193
|
+
const dir = directory(pkg)
|
|
194
|
+
const binDir = path.join(dir, "node_modules", ".bin")
|
|
195
|
+
|
|
196
|
+
const pick = Effect.fnUntraced(function* () {
|
|
197
|
+
const files = yield* fs.readDirectory(binDir).pipe(Effect.catch(() => Effect.succeed([] as string[])))
|
|
198
|
+
|
|
199
|
+
if (files.length === 0) return Option.none<string>()
|
|
200
|
+
// Caller picked a specific bin (e.g. pyright exposes both `pyright` and
|
|
201
|
+
// `pyright-langserver`); trust the hint if the package provides it.
|
|
202
|
+
if (bin) return files.includes(bin) ? Option.some(bin) : Option.none<string>()
|
|
203
|
+
if (files.length === 1) return Option.some(files[0])
|
|
204
|
+
|
|
205
|
+
const pkgJson = yield* afs.readJson(path.join(dir, "node_modules", pkg, "package.json")).pipe(Effect.option)
|
|
206
|
+
|
|
207
|
+
if (Option.isSome(pkgJson)) {
|
|
208
|
+
const parsed = pkgJson.value as { bin?: string | Record<string, string> }
|
|
209
|
+
if (parsed?.bin) {
|
|
210
|
+
const unscoped = pkg.startsWith("@") ? pkg.split("/")[1] : pkg
|
|
211
|
+
const parsedBin = parsed.bin
|
|
212
|
+
if (typeof parsedBin === "string") return Option.some(unscoped)
|
|
213
|
+
const keys = Object.keys(parsedBin)
|
|
214
|
+
if (keys.length === 1) return Option.some(keys[0])
|
|
215
|
+
return parsedBin[unscoped] ? Option.some(unscoped) : Option.some(keys[0])
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return Option.some(files[0])
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
return Option.getOrUndefined(
|
|
223
|
+
yield* Effect.gen(function* () {
|
|
224
|
+
const bin = yield* pick()
|
|
225
|
+
if (Option.isSome(bin)) {
|
|
226
|
+
return Option.some(path.join(binDir, bin.value))
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
yield* fs.remove(path.join(dir, "package-lock.json")).pipe(Effect.orElseSucceed(() => {}))
|
|
230
|
+
|
|
231
|
+
yield* add(pkg)
|
|
232
|
+
|
|
233
|
+
const resolved = yield* pick()
|
|
234
|
+
if (Option.isNone(resolved)) return Option.none<string>()
|
|
235
|
+
return Option.some(path.join(binDir, resolved.value))
|
|
236
|
+
}).pipe(
|
|
237
|
+
Effect.scoped,
|
|
238
|
+
Effect.orElseSucceed(() => Option.none<string>()),
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
return Service.of({
|
|
244
|
+
add,
|
|
245
|
+
install,
|
|
246
|
+
which,
|
|
247
|
+
})
|
|
248
|
+
}),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
export const node = makeGlobalNode({
|
|
252
|
+
service: Service,
|
|
253
|
+
layer: layer,
|
|
254
|
+
deps: [FSUtil.node, Global.node, filesystem, EffectFlock.node],
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
const { runPromise } = makeRuntime(Service, LayerNode.compile(node))
|
|
258
|
+
|
|
259
|
+
export async function install(...args: Parameters<Interface["install"]>) {
|
|
260
|
+
return runPromise((svc) => svc.install(...args))
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export async function add(...args: Parameters<Interface["add"]>) {
|
|
264
|
+
return runPromise((svc) => svc.add(...args))
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export async function which(...args: Parameters<Interface["which"]>) {
|
|
268
|
+
return runPromise((svc) => svc.which(...args))
|
|
269
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// Branded HTML pages for local OAuth callback servers.
|
|
2
|
+
//
|
|
3
|
+
// These are served by the loopback HTTP servers that finish an OAuth exchange
|
|
4
|
+
// (MCP, Codex/ChatGPT, xAI, Snowflake, DigitalOcean, ...). The functions return
|
|
5
|
+
// a fully self-contained HTML string with no external assets, so they work
|
|
6
|
+
// offline and drop into any transport (`res.end(...)`, Effect `response.end`,
|
|
7
|
+
// etc.).
|
|
8
|
+
//
|
|
9
|
+
// The visual language mirrors the NeuroCode app: the design tokens are a curated
|
|
10
|
+
// subset of the OC-2 semantic tokens in `packages/ui/src/styles/theme.css`, and
|
|
11
|
+
// the wordmark is the same geometry as `packages/ui/src/components/logo.tsx`.
|
|
12
|
+
// Keep this file in sync with those sources when the brand changes.
|
|
13
|
+
|
|
14
|
+
export interface CallbackPageOptions {
|
|
15
|
+
/** Friendly integration name shown as a subtitle, e.g. "xAI", "Snowflake", "MCP". */
|
|
16
|
+
provider?: string
|
|
17
|
+
/** Attempt to close the window shortly after success. Defaults to true. */
|
|
18
|
+
autoClose?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function success(options?: CallbackPageOptions) {
|
|
22
|
+
const provider = options?.provider
|
|
23
|
+
return renderDocument({
|
|
24
|
+
title: "Authorization successful",
|
|
25
|
+
body: renderCard({
|
|
26
|
+
status: "success",
|
|
27
|
+
headline: "Authorization successful",
|
|
28
|
+
message: provider ? `NeuroCode is now connected to ${escapeHtml(provider)}.` : "NeuroCode is now authorized.",
|
|
29
|
+
footnote: "You can close this window.",
|
|
30
|
+
}),
|
|
31
|
+
script: options?.autoClose === false ? undefined : AUTO_CLOSE_SCRIPT,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function error(detail: string, options?: CallbackPageOptions) {
|
|
36
|
+
const provider = options?.provider
|
|
37
|
+
return renderDocument({
|
|
38
|
+
title: "Authorization failed",
|
|
39
|
+
body: renderCard({
|
|
40
|
+
status: "error",
|
|
41
|
+
headline: "Authorization failed",
|
|
42
|
+
message: provider
|
|
43
|
+
? `NeuroCode couldn't finish connecting to ${escapeHtml(provider)}.`
|
|
44
|
+
: "NeuroCode couldn't complete authorization.",
|
|
45
|
+
detail,
|
|
46
|
+
footnote: "Close this window and try again from NeuroCode.",
|
|
47
|
+
}),
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface BootstrapOptions {
|
|
52
|
+
/** Same-origin path the in-browser script POSTs the parsed callback to. */
|
|
53
|
+
tokenPath: string
|
|
54
|
+
provider?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// For flows where the credential arrives in the URL fragment (implicit grant),
|
|
58
|
+
// the browser must relay it back to the loopback server. This renders a pending
|
|
59
|
+
// page whose script reads the fragment, POSTs it to `tokenPath`, then resolves
|
|
60
|
+
// to the success or error state in place.
|
|
61
|
+
export function bootstrap(options: BootstrapOptions) {
|
|
62
|
+
return renderDocument({
|
|
63
|
+
title: "Finishing sign-in",
|
|
64
|
+
body: renderCard({
|
|
65
|
+
status: "pending",
|
|
66
|
+
headline: "Finishing sign-in",
|
|
67
|
+
message: options.provider
|
|
68
|
+
? `Completing your ${escapeHtml(options.provider)} authorization.`
|
|
69
|
+
: "Completing authorization.",
|
|
70
|
+
footnote: "You can close this window once sign-in finishes.",
|
|
71
|
+
}),
|
|
72
|
+
script: bootstrapScript(options),
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export * as OauthCallbackPage from "./page"
|
|
77
|
+
|
|
78
|
+
type Status = "pending" | "success" | "error"
|
|
79
|
+
|
|
80
|
+
function renderCard(input: { status: Status; headline: string; message: string; detail?: string; footnote: string }) {
|
|
81
|
+
const detail = input.detail?.trim()
|
|
82
|
+
return `<main class="card" id="oc-card" data-status="${input.status}" role="status" aria-live="polite">
|
|
83
|
+
<div class="brand">${WORDMARK}</div>
|
|
84
|
+
<div class="status" aria-hidden="true">
|
|
85
|
+
<span class="icon icon-pending">${ICON_SPINNER}</span>
|
|
86
|
+
<span class="icon icon-success">${ICON_CHECK}</span>
|
|
87
|
+
<span class="icon icon-error">${ICON_CROSS}</span>
|
|
88
|
+
</div>
|
|
89
|
+
<h1 class="headline" id="oc-headline">${escapeHtml(input.headline)}</h1>
|
|
90
|
+
<p class="message" id="oc-message">${input.message}</p>
|
|
91
|
+
<pre class="detail" id="oc-detail"${detail ? "" : " hidden"}>${detail ? escapeHtml(detail) : ""}</pre>
|
|
92
|
+
<p class="footnote" id="oc-footnote">${escapeHtml(input.footnote)}</p>
|
|
93
|
+
</main>`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function renderDocument(input: { title: string; body: string; script?: string }) {
|
|
97
|
+
return `<!doctype html>
|
|
98
|
+
<html lang="en">
|
|
99
|
+
<head>
|
|
100
|
+
<meta charset="utf-8" />
|
|
101
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
102
|
+
<meta name="robots" content="noindex" />
|
|
103
|
+
<title>${escapeHtml(input.title)} · NeuroCode</title>
|
|
104
|
+
<style>${STYLES}</style>
|
|
105
|
+
</head>
|
|
106
|
+
<body>
|
|
107
|
+
${input.body}${input.script ? `\n <script>${input.script}</script>` : ""}
|
|
108
|
+
</body>
|
|
109
|
+
</html>`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const AUTO_CLOSE_SCRIPT = `setTimeout(function(){try{window.close()}catch(e){}},2500)`
|
|
113
|
+
|
|
114
|
+
function bootstrapScript(options: BootstrapOptions) {
|
|
115
|
+
return `var PROVIDER=${scriptString(options.provider ?? "")};
|
|
116
|
+
var TOKEN_URL=new URL(${scriptString(options.tokenPath)},window.location.origin).href;
|
|
117
|
+
(function(){
|
|
118
|
+
var card=document.getElementById("oc-card"),headline=document.getElementById("oc-headline"),message=document.getElementById("oc-message"),detail=document.getElementById("oc-detail"),footnote=document.getElementById("oc-footnote");
|
|
119
|
+
function fail(text){card.dataset.status="error";headline.textContent="Authorization failed";message.textContent=PROVIDER?("NeuroCode couldn't finish connecting to "+PROVIDER+"."):"NeuroCode couldn't complete authorization.";if(text){detail.textContent=text;detail.hidden=false}footnote.textContent="Close this window and try again from NeuroCode."}
|
|
120
|
+
function ok(){card.dataset.status="success";headline.textContent="Authorization successful";message.textContent=PROVIDER?("NeuroCode is now connected to "+PROVIDER+"."):"NeuroCode is now authorized.";detail.hidden=true;footnote.textContent="You can close this window.";setTimeout(function(){try{window.close()}catch(e){}},2500)}
|
|
121
|
+
try{
|
|
122
|
+
var hash=new URLSearchParams((window.location.hash||"").slice(1));
|
|
123
|
+
var search=new URLSearchParams(window.location.search||"");
|
|
124
|
+
var err=hash.get("error")||search.get("error");
|
|
125
|
+
var errDescription=hash.get("error_description")||search.get("error_description");
|
|
126
|
+
var body=err?{error:err,error_description:errDescription||""}:{access_token:hash.get("access_token")||"",expires_in:hash.get("expires_in")||"0",state:hash.get("state")||""};
|
|
127
|
+
fetch(TOKEN_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)}).then(function(res){
|
|
128
|
+
if(!res.ok)return res.text().catch(function(){return""}).then(function(t){throw new Error(t||("callback failed ("+res.status+")"))});
|
|
129
|
+
if(err){fail(errDescription||err);return}
|
|
130
|
+
ok();
|
|
131
|
+
}).catch(function(e){fail(String(e&&e.message?e.message:e))});
|
|
132
|
+
}catch(e){fail(String(e&&e.message?e.message:e))}
|
|
133
|
+
})()`
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function scriptString(value: string) {
|
|
137
|
+
return JSON.stringify(value).replaceAll("<", "\\u003c")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function escapeHtml(value: string) {
|
|
141
|
+
return value
|
|
142
|
+
.replaceAll("&", "&")
|
|
143
|
+
.replaceAll("<", "<")
|
|
144
|
+
.replaceAll(">", ">")
|
|
145
|
+
.replaceAll('"', """)
|
|
146
|
+
.replaceAll("'", "'")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Curated subset of OC-2 tokens (packages/ui/src/styles/theme.css). Default is
|
|
150
|
+
// light; dark applies via prefers-color-scheme. The [data-theme] selectors let a
|
|
151
|
+
// host force a scheme without changing the default.
|
|
152
|
+
const LIGHT_VARS = `
|
|
153
|
+
--oc-bg: #f8f8f8;
|
|
154
|
+
--oc-card: #fcfcfc;
|
|
155
|
+
--oc-text-strong: #171717;
|
|
156
|
+
--oc-text-base: #6f6f6f;
|
|
157
|
+
--oc-text-weak: #8f8f8f;
|
|
158
|
+
--oc-border-weak: #e5e5e5;
|
|
159
|
+
--oc-icon-strong: #171717;
|
|
160
|
+
--oc-icon-base: #8f8f8f;
|
|
161
|
+
--oc-icon-weak: #dbdbdb;
|
|
162
|
+
--oc-success: #2dba26;
|
|
163
|
+
--oc-error: #ed4831;
|
|
164
|
+
--oc-detail-bg: #fff8f6;
|
|
165
|
+
--oc-detail-border: #fdc3b7;
|
|
166
|
+
--oc-shadow: 0 16px 48px -6px rgba(0,0,0,.10), 0 6px 12px -2px rgba(0,0,0,.05), 0 1px 2px rgba(0,0,0,.06);`
|
|
167
|
+
|
|
168
|
+
const DARK_VARS = `
|
|
169
|
+
--oc-bg: #101010;
|
|
170
|
+
--oc-card: #161616;
|
|
171
|
+
--oc-text-strong: rgba(255,255,255,.936);
|
|
172
|
+
--oc-text-base: rgba(255,255,255,.618);
|
|
173
|
+
--oc-text-weak: rgba(255,255,255,.422);
|
|
174
|
+
--oc-border-weak: #282828;
|
|
175
|
+
--oc-icon-strong: #ededed;
|
|
176
|
+
--oc-icon-base: #7e7e7e;
|
|
177
|
+
--oc-icon-weak: #343434;
|
|
178
|
+
--oc-success: #12c905;
|
|
179
|
+
--oc-error: #fc533a;
|
|
180
|
+
--oc-detail-bg: #28110c;
|
|
181
|
+
--oc-detail-border: #6a1206;
|
|
182
|
+
--oc-shadow: 0 16px 48px -6px rgba(0,0,0,.55), 0 6px 12px -2px rgba(0,0,0,.35), 0 1px 2px rgba(0,0,0,.4);`
|
|
183
|
+
|
|
184
|
+
const STYLES = `
|
|
185
|
+
:root { color-scheme: light dark;${LIGHT_VARS}
|
|
186
|
+
--oc-font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
187
|
+
--oc-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
188
|
+
}
|
|
189
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {${DARK_VARS} } }
|
|
190
|
+
:root[data-theme="dark"] {${DARK_VARS} }
|
|
191
|
+
:root[data-theme="light"] {${LIGHT_VARS} }
|
|
192
|
+
|
|
193
|
+
* { box-sizing: border-box; }
|
|
194
|
+
html, body { margin: 0; height: 100%; }
|
|
195
|
+
body {
|
|
196
|
+
min-height: 100vh;
|
|
197
|
+
display: grid;
|
|
198
|
+
place-items: center;
|
|
199
|
+
padding: 24px;
|
|
200
|
+
background: var(--oc-bg);
|
|
201
|
+
color: var(--oc-text-base);
|
|
202
|
+
font-family: var(--oc-font-sans);
|
|
203
|
+
line-height: 1.5;
|
|
204
|
+
-webkit-font-smoothing: antialiased;
|
|
205
|
+
text-rendering: optimizeLegibility;
|
|
206
|
+
}
|
|
207
|
+
.card {
|
|
208
|
+
width: min(100%, 28rem);
|
|
209
|
+
padding: 2.25rem 2rem 1.75rem;
|
|
210
|
+
background: var(--oc-card);
|
|
211
|
+
border: 1px solid var(--oc-border-weak);
|
|
212
|
+
border-radius: 14px;
|
|
213
|
+
box-shadow: var(--oc-shadow);
|
|
214
|
+
text-align: center;
|
|
215
|
+
}
|
|
216
|
+
.brand { display: flex; justify-content: center; margin-bottom: 1.75rem; }
|
|
217
|
+
.brand svg { height: 19px; width: auto; }
|
|
218
|
+
.status { display: flex; justify-content: center; margin-bottom: 1.125rem; }
|
|
219
|
+
.icon { display: none; line-height: 0; }
|
|
220
|
+
.icon svg { display: block; }
|
|
221
|
+
.card[data-status="pending"] .icon-pending,
|
|
222
|
+
.card[data-status="success"] .icon-success,
|
|
223
|
+
.card[data-status="error"] .icon-error { display: block; }
|
|
224
|
+
.icon-success { color: var(--oc-success); }
|
|
225
|
+
.icon-error { color: var(--oc-error); }
|
|
226
|
+
.icon-pending { color: var(--oc-text-weak); }
|
|
227
|
+
.headline { margin: 0; font-size: 1.1875rem; font-weight: 500; line-height: 1.3; letter-spacing: -0.012em; color: var(--oc-text-strong); }
|
|
228
|
+
.message { margin: 0.5rem 0 0; font-size: 0.9375rem; color: var(--oc-text-base); }
|
|
229
|
+
.detail {
|
|
230
|
+
margin: 1.25rem 0 0;
|
|
231
|
+
padding: 0.75rem 0.875rem;
|
|
232
|
+
text-align: left;
|
|
233
|
+
font-family: var(--oc-font-mono);
|
|
234
|
+
font-size: 0.8125rem;
|
|
235
|
+
line-height: 1.55;
|
|
236
|
+
color: var(--oc-text-strong);
|
|
237
|
+
background: var(--oc-detail-bg);
|
|
238
|
+
border: 1px solid var(--oc-detail-border);
|
|
239
|
+
border-radius: 8px;
|
|
240
|
+
white-space: pre-wrap;
|
|
241
|
+
word-break: break-word;
|
|
242
|
+
max-height: 9.5rem;
|
|
243
|
+
overflow: auto;
|
|
244
|
+
}
|
|
245
|
+
.detail[hidden] { display: none; }
|
|
246
|
+
.footnote { margin: 1.5rem 0 0; font-size: 0.8125rem; color: var(--oc-text-weak); }
|
|
247
|
+
.spinner { animation: oc-spin 0.8s linear infinite; transform-origin: center; }
|
|
248
|
+
@keyframes oc-spin { to { transform: rotate(360deg); } }
|
|
249
|
+
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
|
|
250
|
+
`
|
|
251
|
+
|
|
252
|
+
// NeuroCode wordmark — same path geometry as packages/ui/src/components/logo.tsx (Logo).
|
|
253
|
+
const WORDMARK = `<svg class="wordmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234 42" fill="none" aria-label="NeuroCode" role="img">
|
|
254
|
+
<path d="M18 30H6V18H18V30Z" fill="var(--oc-icon-weak)" />
|
|
255
|
+
<path d="M18 12H6V30H18V12ZM24 36H0V6H24V36Z" fill="var(--oc-icon-base)" />
|
|
256
|
+
<path d="M48 30H36V18H48V30Z" fill="var(--oc-icon-weak)" />
|
|
257
|
+
<path d="M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z" fill="var(--oc-icon-base)" />
|
|
258
|
+
<path d="M84 24V30H66V24H84Z" fill="var(--oc-icon-weak)" />
|
|
259
|
+
<path d="M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z" fill="var(--oc-icon-base)" />
|
|
260
|
+
<path d="M108 36H96V18H108V36Z" fill="var(--oc-icon-weak)" />
|
|
261
|
+
<path d="M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z" fill="var(--oc-icon-base)" />
|
|
262
|
+
<path d="M144 30H126V18H144V30Z" fill="var(--oc-icon-weak)" />
|
|
263
|
+
<path d="M144 12H126V30H144V36H120V6H144V12Z" fill="var(--oc-icon-strong)" />
|
|
264
|
+
<path d="M168 30H156V18H168V30Z" fill="var(--oc-icon-weak)" />
|
|
265
|
+
<path d="M168 12H156V30H168V12ZM174 36H150V6H174V36Z" fill="var(--oc-icon-strong)" />
|
|
266
|
+
<path d="M198 30H186V18H198V30Z" fill="var(--oc-icon-weak)" />
|
|
267
|
+
<path d="M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z" fill="var(--oc-icon-strong)" />
|
|
268
|
+
<path d="M234 24V30H216V24H234Z" fill="var(--oc-icon-weak)" />
|
|
269
|
+
<path d="M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z" fill="var(--oc-icon-strong)" />
|
|
270
|
+
</svg>`
|
|
271
|
+
|
|
272
|
+
const ICON_CHECK = `<svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="m8.5 12.5 2.4 2.4 4.6-5.4" /></svg>`
|
|
273
|
+
|
|
274
|
+
const ICON_CROSS = `<svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="m9 9 6 6m0-6-6 6" /></svg>`
|
|
275
|
+
|
|
276
|
+
const ICON_SPINNER = `<svg class="spinner" viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9" opacity="0.2" /><path d="M21 12a9 9 0 0 0-9-9" /></svg>`
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Formatter, Logger, type LogLevel } from "effect"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { Global } from "../global"
|
|
4
|
+
import { runID } from "./shared"
|
|
5
|
+
|
|
6
|
+
function formatter(id: string = runID) {
|
|
7
|
+
return Logger.map(Logger.formatStructured, (output) => {
|
|
8
|
+
const messages = Array.isArray(output.message) ? output.message : [output.message]
|
|
9
|
+
return [
|
|
10
|
+
["timestamp", output.timestamp],
|
|
11
|
+
["level", output.level],
|
|
12
|
+
["run", id],
|
|
13
|
+
...messages.flatMap((value) => (plain(value) ? flatten(value) : [["message", value] as const])),
|
|
14
|
+
...(output.cause === undefined ? [] : [["cause", output.cause] as const]),
|
|
15
|
+
...flatten(output.spans),
|
|
16
|
+
...flatten(output.annotations),
|
|
17
|
+
]
|
|
18
|
+
.map(([key, value]) => `${key}=${format(value)}`)
|
|
19
|
+
.join(" ")
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function flatten(
|
|
24
|
+
input: Record<string, unknown>,
|
|
25
|
+
prefix = "",
|
|
26
|
+
seen = new WeakSet<object>(),
|
|
27
|
+
): Array<readonly [string, unknown]> {
|
|
28
|
+
if (seen.has(input)) return [[prefix, "[Circular]"]]
|
|
29
|
+
seen.add(input)
|
|
30
|
+
const entries = Object.entries(input)
|
|
31
|
+
if (entries.length === 0 && prefix) return [[prefix, input]]
|
|
32
|
+
return entries.flatMap(([key, value]) => {
|
|
33
|
+
const path = prefix ? `${prefix}.${key}` : key
|
|
34
|
+
return plain(value) ? flatten(value, path, seen) : [[path, value] as const]
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function plain(input: unknown): input is Record<string, unknown> {
|
|
39
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) return false
|
|
40
|
+
const prototype = Object.getPrototypeOf(input)
|
|
41
|
+
return prototype === Object.prototype || prototype === null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function format(input: unknown) {
|
|
45
|
+
const value = typeof input === "string" ? input : Formatter.format(input)
|
|
46
|
+
return /^[^\s="\\]+$/.test(value) ? value : JSON.stringify(value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function fileLogger(file = path.join(Global.Path.log, "neurocode.log"), id: string = runID) {
|
|
50
|
+
// Do not set batchWindow to 0; it causes high idle CPU usage.
|
|
51
|
+
return Logger.toFile(formatter(id), file, { flag: "a" })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const stderrLogger = Logger.make((options) => process.stderr.write(formatter().log(options) + "\n"))
|
|
55
|
+
|
|
56
|
+
export function minimumLogLevel() {
|
|
57
|
+
const value = process.env.NEUROCODE_LOG_LEVEL?.toUpperCase()
|
|
58
|
+
const levels = {
|
|
59
|
+
DEBUG: "Debug",
|
|
60
|
+
INFO: "Info",
|
|
61
|
+
WARN: "Warn",
|
|
62
|
+
ERROR: "Error",
|
|
63
|
+
} as const satisfies Record<string, LogLevel.LogLevel>
|
|
64
|
+
return value && value in levels ? levels[value as keyof typeof levels] : levels.INFO
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function loggers() {
|
|
68
|
+
return process.env.NEUROCODE_PRINT_LOGS === "1" ? [fileLogger(), stderrLogger] : [fileLogger()]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export * as Logging from "./logging"
|