@nghyane/arcane 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +12 -0
- package/examples/README.md +21 -0
- package/examples/custom-tools/README.md +109 -0
- package/examples/custom-tools/hello/index.ts +20 -0
- package/examples/custom-tools/todo/index.ts +206 -0
- package/examples/extensions/README.md +143 -0
- package/examples/extensions/api-demo.ts +89 -0
- package/examples/extensions/chalk-logger.ts +25 -0
- package/examples/extensions/hello.ts +32 -0
- package/examples/extensions/pirate.ts +43 -0
- package/examples/extensions/plan-mode.ts +550 -0
- package/examples/extensions/reload-runtime.ts +37 -0
- package/examples/extensions/todo.ts +296 -0
- package/examples/extensions/tools.ts +144 -0
- package/examples/extensions/with-deps/index.ts +35 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/hooks/README.md +56 -0
- package/examples/hooks/auto-commit-on-exit.ts +48 -0
- package/examples/hooks/confirm-destructive.ts +58 -0
- package/examples/hooks/custom-compaction.ts +116 -0
- package/examples/hooks/dirty-repo-guard.ts +51 -0
- package/examples/hooks/file-trigger.ts +40 -0
- package/examples/hooks/git-checkpoint.ts +52 -0
- package/examples/hooks/handoff.ts +150 -0
- package/examples/hooks/permission-gate.ts +33 -0
- package/examples/hooks/protected-paths.ts +29 -0
- package/examples/hooks/qna.ts +119 -0
- package/examples/hooks/status-line.ts +39 -0
- package/examples/sdk/01-minimal.ts +21 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +43 -0
- package/examples/sdk/04-skills.ts +43 -0
- package/examples/sdk/06-extensions.ts +80 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +35 -0
- package/examples/sdk/08-prompt-templates.ts +36 -0
- package/examples/sdk/08-slash-commands.ts +41 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
- package/examples/sdk/11-sessions.ts +47 -0
- package/examples/sdk/README.md +150 -0
- package/package.json +464 -0
- package/scripts/format-prompts.ts +184 -0
- package/scripts/generate-docs-index.ts +40 -0
- package/scripts/generate-template.ts +32 -0
- package/src/bun-imports.d.ts +22 -0
- package/src/capability/context-file.ts +39 -0
- package/src/capability/extension-module.ts +33 -0
- package/src/capability/extension.ts +47 -0
- package/src/capability/fs.ts +89 -0
- package/src/capability/hook.ts +39 -0
- package/src/capability/index.ts +432 -0
- package/src/capability/instruction.ts +36 -0
- package/src/capability/mcp.ts +60 -0
- package/src/capability/prompt.ts +34 -0
- package/src/capability/rule.ts +223 -0
- package/src/capability/settings.ts +34 -0
- package/src/capability/skill.ts +48 -0
- package/src/capability/slash-command.ts +39 -0
- package/src/capability/ssh.ts +41 -0
- package/src/capability/system-prompt.ts +34 -0
- package/src/capability/tool.ts +37 -0
- package/src/capability/types.ts +156 -0
- package/src/cli/args.ts +259 -0
- package/src/cli/config-cli.ts +357 -0
- package/src/cli/file-processor.ts +124 -0
- package/src/cli/grep-cli.ts +152 -0
- package/src/cli/jupyter-cli.ts +106 -0
- package/src/cli/list-models.ts +103 -0
- package/src/cli/plugin-cli.ts +661 -0
- package/src/cli/session-picker.ts +42 -0
- package/src/cli/setup-cli.ts +376 -0
- package/src/cli/shell-cli.ts +174 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli/stats-cli.ts +197 -0
- package/src/cli/update-cli.ts +286 -0
- package/src/cli/web-search-cli.ts +143 -0
- package/src/cli.ts +65 -0
- package/src/commands/commit.ts +36 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/grep.ts +41 -0
- package/src/commands/jupyter.ts +32 -0
- package/src/commands/launch.ts +139 -0
- package/src/commands/plugin.ts +70 -0
- package/src/commands/setup.ts +42 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/ssh.ts +60 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/web-search.ts +42 -0
- package/src/commit/agentic/agent.ts +311 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +359 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +25 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +38 -0
- package/src/commit/agentic/state.ts +69 -0
- package/src/commit/agentic/tools/analyze-file.ts +118 -0
- package/src/commit/agentic/tools/git-file-diff.ts +194 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +84 -0
- package/src/commit/agentic/tools/index.ts +56 -0
- package/src/commit/agentic/tools/propose-changelog.ts +128 -0
- package/src/commit/agentic/tools/propose-commit.ts +154 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/split-commit.ts +280 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +200 -0
- package/src/commit/analysis/conventional.ts +165 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +112 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +37 -0
- package/src/commit/changelog/generate.ts +110 -0
- package/src/commit/changelog/index.ts +234 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +93 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/git/errors.ts +9 -0
- package/src/commit/git/index.ts +211 -0
- package/src/commit/git/operations.ts +54 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +64 -0
- package/src/commit/map-reduce/map-phase.ts +178 -0
- package/src/commit/map-reduce/reduce-phase.ts +145 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +69 -0
- package/src/commit/pipeline.ts +243 -0
- package/src/commit/prompts/analysis-system.md +148 -0
- package/src/commit/prompts/analysis-user.md +38 -0
- package/src/commit/prompts/changelog-system.md +50 -0
- package/src/commit/prompts/changelog-user.md +18 -0
- package/src/commit/prompts/file-observer-system.md +24 -0
- package/src/commit/prompts/file-observer-user.md +8 -0
- package/src/commit/prompts/reduce-system.md +50 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +3 -0
- package/src/commit/prompts/summary-system.md +38 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/types.ts +109 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/config/file-lock.ts +121 -0
- package/src/config/keybindings.ts +280 -0
- package/src/config/model-registry.ts +1140 -0
- package/src/config/model-resolver.ts +812 -0
- package/src/config/prompt-templates.ts +526 -0
- package/src/config/resolve-config-value.ts +92 -0
- package/src/config/settings-schema.ts +1236 -0
- package/src/config/settings.ts +706 -0
- package/src/config.ts +414 -0
- package/src/cursor.ts +239 -0
- package/src/debug/index.ts +431 -0
- package/src/debug/log-formatting.ts +60 -0
- package/src/debug/log-viewer.ts +903 -0
- package/src/debug/profiler.ts +158 -0
- package/src/debug/report-bundle.ts +366 -0
- package/src/debug/system-info.ts +112 -0
- package/src/discovery/agents-md.ts +68 -0
- package/src/discovery/agents.ts +199 -0
- package/src/discovery/builtin.ts +815 -0
- package/src/discovery/claude-plugins.ts +205 -0
- package/src/discovery/claude.ts +506 -0
- package/src/discovery/cline.ts +83 -0
- package/src/discovery/codex.ts +532 -0
- package/src/discovery/cursor.ts +218 -0
- package/src/discovery/gemini.ts +395 -0
- package/src/discovery/github.ts +117 -0
- package/src/discovery/helpers.ts +698 -0
- package/src/discovery/index.ts +89 -0
- package/src/discovery/mcp-json.ts +156 -0
- package/src/discovery/opencode.ts +394 -0
- package/src/discovery/ssh.ts +160 -0
- package/src/discovery/vscode.ts +103 -0
- package/src/discovery/windsurf.ts +145 -0
- package/src/exa/company.ts +57 -0
- package/src/exa/index.ts +62 -0
- package/src/exa/linkedin.ts +57 -0
- package/src/exa/mcp-client.ts +289 -0
- package/src/exa/render.ts +244 -0
- package/src/exa/researcher.ts +89 -0
- package/src/exa/search.ts +330 -0
- package/src/exa/types.ts +166 -0
- package/src/exa/websets.ts +247 -0
- package/src/exec/bash-executor.ts +184 -0
- package/src/exec/exec.ts +53 -0
- package/src/export/custom-share.ts +65 -0
- package/src/export/html/index.ts +162 -0
- package/src/export/html/template.css +889 -0
- package/src/export/html/template.generated.ts +2 -0
- package/src/export/html/template.html +45 -0
- package/src/export/html/template.js +1329 -0
- package/src/export/html/template.macro.ts +24 -0
- package/src/export/html/vendor/highlight.min.js +1213 -0
- package/src/export/html/vendor/marked.min.js +6 -0
- package/src/export/ttsr.ts +434 -0
- package/src/extensibility/custom-commands/bundled/review/index.ts +433 -0
- package/src/extensibility/custom-commands/index.ts +15 -0
- package/src/extensibility/custom-commands/loader.ts +231 -0
- package/src/extensibility/custom-commands/types.ts +111 -0
- package/src/extensibility/custom-tools/index.ts +22 -0
- package/src/extensibility/custom-tools/loader.ts +235 -0
- package/src/extensibility/custom-tools/types.ts +226 -0
- package/src/extensibility/custom-tools/wrapper.ts +45 -0
- package/src/extensibility/extensions/index.ts +136 -0
- package/src/extensibility/extensions/loader.ts +520 -0
- package/src/extensibility/extensions/runner.ts +774 -0
- package/src/extensibility/extensions/types.ts +1293 -0
- package/src/extensibility/extensions/wrapper.ts +188 -0
- package/src/extensibility/hooks/index.ts +16 -0
- package/src/extensibility/hooks/loader.ts +273 -0
- package/src/extensibility/hooks/runner.ts +441 -0
- package/src/extensibility/hooks/tool-wrapper.ts +106 -0
- package/src/extensibility/hooks/types.ts +817 -0
- package/src/extensibility/plugins/doctor.ts +65 -0
- package/src/extensibility/plugins/git-url.ts +281 -0
- package/src/extensibility/plugins/index.ts +33 -0
- package/src/extensibility/plugins/installer.ts +192 -0
- package/src/extensibility/plugins/loader.ts +338 -0
- package/src/extensibility/plugins/manager.ts +716 -0
- package/src/extensibility/plugins/parser.ts +105 -0
- package/src/extensibility/plugins/types.ts +190 -0
- package/src/extensibility/skills.ts +385 -0
- package/src/extensibility/slash-commands.ts +287 -0
- package/src/extensibility/tool-proxy.ts +25 -0
- package/src/index.ts +275 -0
- package/src/internal-urls/agent-protocol.ts +136 -0
- package/src/internal-urls/artifact-protocol.ts +97 -0
- package/src/internal-urls/docs-index.generated.ts +54 -0
- package/src/internal-urls/docs-protocol.ts +84 -0
- package/src/internal-urls/index.ts +31 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/memory-protocol.ts +133 -0
- package/src/internal-urls/router.ts +70 -0
- package/src/internal-urls/rule-protocol.ts +55 -0
- package/src/internal-urls/skill-protocol.ts +111 -0
- package/src/internal-urls/types.ts +52 -0
- package/src/ipy/executor.ts +556 -0
- package/src/ipy/gateway-coordinator.ts +426 -0
- package/src/ipy/kernel.ts +892 -0
- package/src/ipy/modules.ts +109 -0
- package/src/ipy/prelude.py +831 -0
- package/src/ipy/prelude.ts +3 -0
- package/src/ipy/runtime.ts +222 -0
- package/src/lsp/client.ts +867 -0
- package/src/lsp/clients/biome-client.ts +202 -0
- package/src/lsp/clients/index.ts +50 -0
- package/src/lsp/clients/lsp-linter-client.ts +93 -0
- package/src/lsp/clients/swiftlint-client.ts +120 -0
- package/src/lsp/config.ts +397 -0
- package/src/lsp/defaults.json +464 -0
- package/src/lsp/edits.ts +109 -0
- package/src/lsp/index.ts +1268 -0
- package/src/lsp/lspmux.ts +250 -0
- package/src/lsp/render.ts +689 -0
- package/src/lsp/types.ts +414 -0
- package/src/lsp/utils.ts +549 -0
- package/src/main.ts +773 -0
- package/src/mcp/client.ts +239 -0
- package/src/mcp/config-writer.ts +215 -0
- package/src/mcp/config.ts +363 -0
- package/src/mcp/index.ts +55 -0
- package/src/mcp/json-rpc.ts +84 -0
- package/src/mcp/loader.ts +124 -0
- package/src/mcp/manager.ts +490 -0
- package/src/mcp/oauth-discovery.ts +274 -0
- package/src/mcp/oauth-flow.ts +229 -0
- package/src/mcp/render.ts +123 -0
- package/src/mcp/tool-bridge.ts +372 -0
- package/src/mcp/tool-cache.ts +121 -0
- package/src/mcp/transports/http.ts +332 -0
- package/src/mcp/transports/index.ts +6 -0
- package/src/mcp/transports/stdio.ts +281 -0
- package/src/mcp/types.ts +248 -0
- package/src/memories/index.ts +1099 -0
- package/src/memories/storage.ts +563 -0
- package/src/modes/components/agent-dashboard.ts +1130 -0
- package/src/modes/components/assistant-message.ts +144 -0
- package/src/modes/components/bash-execution.ts +218 -0
- package/src/modes/components/bordered-loader.ts +41 -0
- package/src/modes/components/branch-summary-message.ts +45 -0
- package/src/modes/components/codemode-group.ts +369 -0
- package/src/modes/components/compaction-summary-message.ts +51 -0
- package/src/modes/components/countdown-timer.ts +46 -0
- package/src/modes/components/custom-editor.ts +181 -0
- package/src/modes/components/custom-message.ts +91 -0
- package/src/modes/components/diff.ts +186 -0
- package/src/modes/components/dynamic-border.ts +25 -0
- package/src/modes/components/extensions/extension-dashboard.ts +325 -0
- package/src/modes/components/extensions/extension-list.ts +484 -0
- package/src/modes/components/extensions/index.ts +9 -0
- package/src/modes/components/extensions/inspector-panel.ts +321 -0
- package/src/modes/components/extensions/state-manager.ts +586 -0
- package/src/modes/components/extensions/types.ts +191 -0
- package/src/modes/components/footer.ts +315 -0
- package/src/modes/components/history-search.ts +157 -0
- package/src/modes/components/hook-editor.ts +101 -0
- package/src/modes/components/hook-input.ts +72 -0
- package/src/modes/components/hook-message.ts +100 -0
- package/src/modes/components/hook-selector.ts +155 -0
- package/src/modes/components/index.ts +41 -0
- package/src/modes/components/keybinding-hints.ts +65 -0
- package/src/modes/components/login-dialog.ts +164 -0
- package/src/modes/components/mcp-add-wizard.ts +1295 -0
- package/src/modes/components/model-selector.ts +625 -0
- package/src/modes/components/oauth-selector.ts +210 -0
- package/src/modes/components/plugin-settings.ts +477 -0
- package/src/modes/components/python-execution.ts +196 -0
- package/src/modes/components/queue-mode-selector.ts +56 -0
- package/src/modes/components/read-tool-group.ts +119 -0
- package/src/modes/components/session-selector.ts +242 -0
- package/src/modes/components/settings-defs.ts +340 -0
- package/src/modes/components/settings-selector.ts +529 -0
- package/src/modes/components/show-images-selector.ts +45 -0
- package/src/modes/components/skill-message.ts +90 -0
- package/src/modes/components/status-line/index.ts +4 -0
- package/src/modes/components/status-line/presets.ts +94 -0
- package/src/modes/components/status-line/segments.ts +352 -0
- package/src/modes/components/status-line/separators.ts +55 -0
- package/src/modes/components/status-line/types.ts +75 -0
- package/src/modes/components/status-line-segment-editor.ts +354 -0
- package/src/modes/components/status-line.ts +421 -0
- package/src/modes/components/theme-selector.ts +63 -0
- package/src/modes/components/thinking-selector.ts +64 -0
- package/src/modes/components/todo-display.ts +115 -0
- package/src/modes/components/todo-reminder.ts +40 -0
- package/src/modes/components/tool-execution.ts +703 -0
- package/src/modes/components/tree-selector.ts +904 -0
- package/src/modes/components/ttsr-notification.ts +80 -0
- package/src/modes/components/user-message-selector.ts +146 -0
- package/src/modes/components/user-message.ts +22 -0
- package/src/modes/components/visual-truncate.ts +63 -0
- package/src/modes/components/welcome.ts +247 -0
- package/src/modes/controllers/command-controller.ts +1120 -0
- package/src/modes/controllers/event-controller.ts +479 -0
- package/src/modes/controllers/extension-ui-controller.ts +778 -0
- package/src/modes/controllers/input-controller.ts +671 -0
- package/src/modes/controllers/mcp-command-controller.ts +1315 -0
- package/src/modes/controllers/selector-controller.ts +712 -0
- package/src/modes/controllers/ssh-command-controller.ts +452 -0
- package/src/modes/index.ts +15 -0
- package/src/modes/interactive-mode.ts +1027 -0
- package/src/modes/print-mode.ts +191 -0
- package/src/modes/rpc/rpc-client.ts +583 -0
- package/src/modes/rpc/rpc-mode.ts +700 -0
- package/src/modes/rpc/rpc-types.ts +236 -0
- package/src/modes/theme/dark.json +95 -0
- package/src/modes/theme/defaults/alabaster.json +93 -0
- package/src/modes/theme/defaults/amethyst.json +96 -0
- package/src/modes/theme/defaults/anthracite.json +93 -0
- package/src/modes/theme/defaults/basalt.json +91 -0
- package/src/modes/theme/defaults/birch.json +95 -0
- package/src/modes/theme/defaults/dark-abyss.json +91 -0
- package/src/modes/theme/defaults/dark-arctic.json +104 -0
- package/src/modes/theme/defaults/dark-aurora.json +95 -0
- package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
- package/src/modes/theme/defaults/dark-cavern.json +91 -0
- package/src/modes/theme/defaults/dark-copper.json +95 -0
- package/src/modes/theme/defaults/dark-cosmos.json +90 -0
- package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/modes/theme/defaults/dark-dracula.json +98 -0
- package/src/modes/theme/defaults/dark-eclipse.json +91 -0
- package/src/modes/theme/defaults/dark-ember.json +95 -0
- package/src/modes/theme/defaults/dark-equinox.json +90 -0
- package/src/modes/theme/defaults/dark-forest.json +96 -0
- package/src/modes/theme/defaults/dark-github.json +105 -0
- package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
- package/src/modes/theme/defaults/dark-lavender.json +95 -0
- package/src/modes/theme/defaults/dark-lunar.json +89 -0
- package/src/modes/theme/defaults/dark-midnight.json +95 -0
- package/src/modes/theme/defaults/dark-monochrome.json +94 -0
- package/src/modes/theme/defaults/dark-monokai.json +98 -0
- package/src/modes/theme/defaults/dark-nebula.json +90 -0
- package/src/modes/theme/defaults/dark-nord.json +97 -0
- package/src/modes/theme/defaults/dark-ocean.json +101 -0
- package/src/modes/theme/defaults/dark-one.json +100 -0
- package/src/modes/theme/defaults/dark-rainforest.json +91 -0
- package/src/modes/theme/defaults/dark-reef.json +91 -0
- package/src/modes/theme/defaults/dark-retro.json +92 -0
- package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
- package/src/modes/theme/defaults/dark-sakura.json +95 -0
- package/src/modes/theme/defaults/dark-slate.json +95 -0
- package/src/modes/theme/defaults/dark-solarized.json +97 -0
- package/src/modes/theme/defaults/dark-solstice.json +90 -0
- package/src/modes/theme/defaults/dark-starfall.json +91 -0
- package/src/modes/theme/defaults/dark-sunset.json +99 -0
- package/src/modes/theme/defaults/dark-swamp.json +90 -0
- package/src/modes/theme/defaults/dark-synthwave.json +103 -0
- package/src/modes/theme/defaults/dark-taiga.json +91 -0
- package/src/modes/theme/defaults/dark-terminal.json +95 -0
- package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/modes/theme/defaults/dark-tundra.json +91 -0
- package/src/modes/theme/defaults/dark-twilight.json +91 -0
- package/src/modes/theme/defaults/dark-volcanic.json +91 -0
- package/src/modes/theme/defaults/graphite.json +92 -0
- package/src/modes/theme/defaults/index.ts +195 -0
- package/src/modes/theme/defaults/light-arctic.json +107 -0
- package/src/modes/theme/defaults/light-aurora-day.json +91 -0
- package/src/modes/theme/defaults/light-canyon.json +91 -0
- package/src/modes/theme/defaults/light-catppuccin.json +106 -0
- package/src/modes/theme/defaults/light-cirrus.json +90 -0
- package/src/modes/theme/defaults/light-coral.json +95 -0
- package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
- package/src/modes/theme/defaults/light-dawn.json +90 -0
- package/src/modes/theme/defaults/light-dunes.json +91 -0
- package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
- package/src/modes/theme/defaults/light-forest.json +100 -0
- package/src/modes/theme/defaults/light-frost.json +95 -0
- package/src/modes/theme/defaults/light-github.json +115 -0
- package/src/modes/theme/defaults/light-glacier.json +91 -0
- package/src/modes/theme/defaults/light-gruvbox.json +108 -0
- package/src/modes/theme/defaults/light-haze.json +90 -0
- package/src/modes/theme/defaults/light-honeycomb.json +95 -0
- package/src/modes/theme/defaults/light-lagoon.json +91 -0
- package/src/modes/theme/defaults/light-lavender.json +95 -0
- package/src/modes/theme/defaults/light-meadow.json +91 -0
- package/src/modes/theme/defaults/light-mint.json +95 -0
- package/src/modes/theme/defaults/light-monochrome.json +101 -0
- package/src/modes/theme/defaults/light-ocean.json +99 -0
- package/src/modes/theme/defaults/light-one.json +99 -0
- package/src/modes/theme/defaults/light-opal.json +91 -0
- package/src/modes/theme/defaults/light-orchard.json +91 -0
- package/src/modes/theme/defaults/light-paper.json +95 -0
- package/src/modes/theme/defaults/light-prism.json +90 -0
- package/src/modes/theme/defaults/light-retro.json +98 -0
- package/src/modes/theme/defaults/light-sand.json +95 -0
- package/src/modes/theme/defaults/light-savanna.json +91 -0
- package/src/modes/theme/defaults/light-solarized.json +102 -0
- package/src/modes/theme/defaults/light-soleil.json +90 -0
- package/src/modes/theme/defaults/light-sunset.json +99 -0
- package/src/modes/theme/defaults/light-synthwave.json +98 -0
- package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
- package/src/modes/theme/defaults/light-wetland.json +91 -0
- package/src/modes/theme/defaults/light-zenith.json +89 -0
- package/src/modes/theme/defaults/limestone.json +94 -0
- package/src/modes/theme/defaults/mahogany.json +97 -0
- package/src/modes/theme/defaults/marble.json +93 -0
- package/src/modes/theme/defaults/obsidian.json +91 -0
- package/src/modes/theme/defaults/onyx.json +91 -0
- package/src/modes/theme/defaults/pearl.json +93 -0
- package/src/modes/theme/defaults/porcelain.json +91 -0
- package/src/modes/theme/defaults/quartz.json +96 -0
- package/src/modes/theme/defaults/sandstone.json +95 -0
- package/src/modes/theme/defaults/titanium.json +90 -0
- package/src/modes/theme/light.json +93 -0
- package/src/modes/theme/mermaid-cache.ts +111 -0
- package/src/modes/theme/theme-schema.json +429 -0
- package/src/modes/theme/theme.ts +2333 -0
- package/src/modes/types.ts +216 -0
- package/src/modes/utils/ui-helpers.ts +529 -0
- package/src/patch/applicator.ts +1482 -0
- package/src/patch/diff.ts +425 -0
- package/src/patch/fuzzy.ts +784 -0
- package/src/patch/hashline.ts +972 -0
- package/src/patch/index.ts +964 -0
- package/src/patch/normalize.ts +397 -0
- package/src/patch/normative.ts +72 -0
- package/src/patch/parser.ts +532 -0
- package/src/patch/shared.ts +400 -0
- package/src/patch/types.ts +292 -0
- package/src/priority.json +35 -0
- package/src/prompts/agents/explore.md +48 -0
- package/src/prompts/agents/frontmatter.md +9 -0
- package/src/prompts/agents/init.md +36 -0
- package/src/prompts/agents/librarian.md +53 -0
- package/src/prompts/agents/oracle.md +51 -0
- package/src/prompts/agents/reviewer.md +70 -0
- package/src/prompts/agents/task.md +14 -0
- package/src/prompts/compaction/branch-summary-context.md +5 -0
- package/src/prompts/compaction/branch-summary-preamble.md +2 -0
- package/src/prompts/compaction/branch-summary.md +30 -0
- package/src/prompts/compaction/compaction-short-summary.md +9 -0
- package/src/prompts/compaction/compaction-summary-context.md +5 -0
- package/src/prompts/compaction/compaction-summary.md +38 -0
- package/src/prompts/compaction/compaction-turn-prefix.md +17 -0
- package/src/prompts/compaction/compaction-update-summary.md +45 -0
- package/src/prompts/memories/consolidation.md +30 -0
- package/src/prompts/memories/read_path.md +11 -0
- package/src/prompts/memories/stage_one_input.md +6 -0
- package/src/prompts/memories/stage_one_system.md +21 -0
- package/src/prompts/review-request.md +64 -0
- package/src/prompts/system/agent-creation-architect.md +65 -0
- package/src/prompts/system/agent-creation-user.md +6 -0
- package/src/prompts/system/custom-system-prompt.md +68 -0
- package/src/prompts/system/file-operations.md +10 -0
- package/src/prompts/system/subagent-submit-reminder.md +11 -0
- package/src/prompts/system/subagent-system-prompt.md +31 -0
- package/src/prompts/system/subagent-user-prompt.md +8 -0
- package/src/prompts/system/summarization-system.md +3 -0
- package/src/prompts/system/system-prompt.md +300 -0
- package/src/prompts/system/title-system.md +2 -0
- package/src/prompts/system/ttsr-interrupt.md +7 -0
- package/src/prompts/system/web-search.md +28 -0
- package/src/prompts/tools/ask.md +44 -0
- package/src/prompts/tools/bash.md +24 -0
- package/src/prompts/tools/browser.md +33 -0
- package/src/prompts/tools/calculator.md +12 -0
- package/src/prompts/tools/explore.md +29 -0
- package/src/prompts/tools/fetch.md +16 -0
- package/src/prompts/tools/find.md +18 -0
- package/src/prompts/tools/gemini-image.md +23 -0
- package/src/prompts/tools/grep.md +28 -0
- package/src/prompts/tools/hashline.md +232 -0
- package/src/prompts/tools/librarian.md +24 -0
- package/src/prompts/tools/lsp.md +28 -0
- package/src/prompts/tools/oracle.md +26 -0
- package/src/prompts/tools/patch.md +74 -0
- package/src/prompts/tools/python.md +66 -0
- package/src/prompts/tools/read.md +36 -0
- package/src/prompts/tools/replace.md +38 -0
- package/src/prompts/tools/reviewer.md +41 -0
- package/src/prompts/tools/ssh.md +51 -0
- package/src/prompts/tools/task-summary.md +28 -0
- package/src/prompts/tools/task.md +275 -0
- package/src/prompts/tools/todo-write.md +65 -0
- package/src/prompts/tools/undo-edit.md +7 -0
- package/src/prompts/tools/web-search.md +19 -0
- package/src/prompts/tools/write.md +18 -0
- package/src/sdk.ts +1287 -0
- package/src/secrets/index.ts +116 -0
- package/src/secrets/obfuscator.ts +269 -0
- package/src/secrets/regex.ts +21 -0
- package/src/session/agent-session.ts +4669 -0
- package/src/session/agent-storage.ts +621 -0
- package/src/session/artifacts.ts +132 -0
- package/src/session/auth-storage.ts +1433 -0
- package/src/session/blob-store.ts +103 -0
- package/src/session/compaction/branch-summarization.ts +315 -0
- package/src/session/compaction/compaction.ts +864 -0
- package/src/session/compaction/index.ts +7 -0
- package/src/session/compaction/pruning.ts +91 -0
- package/src/session/compaction/utils.ts +171 -0
- package/src/session/history-storage.ts +170 -0
- package/src/session/messages.ts +317 -0
- package/src/session/session-manager.ts +2276 -0
- package/src/session/session-storage.ts +342 -0
- package/src/session/streaming-output.ts +565 -0
- package/src/slash-commands/builtin-registry.ts +439 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/ssh/connection-manager.ts +444 -0
- package/src/ssh/ssh-executor.ts +127 -0
- package/src/ssh/sshfs-mount.ts +135 -0
- package/src/stt/downloader.ts +71 -0
- package/src/stt/index.ts +3 -0
- package/src/stt/recorder.ts +351 -0
- package/src/stt/setup.ts +52 -0
- package/src/stt/stt-controller.ts +160 -0
- package/src/stt/transcribe.py +70 -0
- package/src/stt/transcriber.ts +91 -0
- package/src/system-prompt.ts +685 -0
- package/src/task/agents.ts +155 -0
- package/src/task/batch.ts +102 -0
- package/src/task/commands.ts +134 -0
- package/src/task/discovery.ts +126 -0
- package/src/task/executor.ts +908 -0
- package/src/task/index.ts +223 -0
- package/src/task/output-manager.ts +107 -0
- package/src/task/parallel.ts +84 -0
- package/src/task/render.ts +326 -0
- package/src/task/subprocess-tool-registry.ts +88 -0
- package/src/task/template.ts +32 -0
- package/src/task/types.ts +144 -0
- package/src/tools/ask.ts +523 -0
- package/src/tools/bash-interactive.ts +419 -0
- package/src/tools/bash-interceptor.ts +105 -0
- package/src/tools/bash-normalize.ts +107 -0
- package/src/tools/bash-skill-urls.ts +177 -0
- package/src/tools/bash.ts +347 -0
- package/src/tools/browser.ts +1374 -0
- package/src/tools/calculator.ts +537 -0
- package/src/tools/context.ts +39 -0
- package/src/tools/explore.ts +23 -0
- package/src/tools/fetch.ts +1091 -0
- package/src/tools/find.ts +540 -0
- package/src/tools/fs-cache-invalidation.ts +28 -0
- package/src/tools/gemini-image.ts +907 -0
- package/src/tools/grep.ts +489 -0
- package/src/tools/index.ts +337 -0
- package/src/tools/json-tree.ts +231 -0
- package/src/tools/jtd-to-json-schema.ts +247 -0
- package/src/tools/jtd-to-typescript.ts +198 -0
- package/src/tools/librarian.ts +33 -0
- package/src/tools/list-limit.ts +40 -0
- package/src/tools/notebook.ts +287 -0
- package/src/tools/oracle.ts +40 -0
- package/src/tools/output-meta.ts +459 -0
- package/src/tools/output-utils.ts +63 -0
- package/src/tools/path-utils.ts +116 -0
- package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
- package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
- package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
- package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
- package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
- package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
- package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
- package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
- package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
- package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
- package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
- package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
- package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
- package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
- package/src/tools/python.ts +1118 -0
- package/src/tools/read.ts +1193 -0
- package/src/tools/render-utils.ts +680 -0
- package/src/tools/renderers.ts +60 -0
- package/src/tools/reviewer-tool.ts +41 -0
- package/src/tools/ssh.ts +326 -0
- package/src/tools/subagent-tool.ts +169 -0
- package/src/tools/submit-result.ts +152 -0
- package/src/tools/todo-write.ts +255 -0
- package/src/tools/tool-errors.ts +92 -0
- package/src/tools/tool-result.ts +86 -0
- package/src/tools/undo-edit.ts +145 -0
- package/src/tools/undo-history.ts +22 -0
- package/src/tools/write.ts +274 -0
- package/src/tui/code-cell.ts +108 -0
- package/src/tui/file-list.ts +47 -0
- package/src/tui/index.ts +11 -0
- package/src/tui/output-block.ts +144 -0
- package/src/tui/status-line.ts +39 -0
- package/src/tui/tree-list.ts +53 -0
- package/src/tui/types.ts +16 -0
- package/src/tui/utils.ts +116 -0
- package/src/utils/changelog.ts +98 -0
- package/src/utils/event-bus.ts +33 -0
- package/src/utils/external-editor.ts +59 -0
- package/src/utils/file-display-mode.ts +36 -0
- package/src/utils/file-mentions.ts +384 -0
- package/src/utils/frontmatter.ts +101 -0
- package/src/utils/fuzzy.ts +108 -0
- package/src/utils/ignore-files.ts +119 -0
- package/src/utils/image-convert.ts +27 -0
- package/src/utils/image-resize.ts +236 -0
- package/src/utils/mime.ts +30 -0
- package/src/utils/open.ts +20 -0
- package/src/utils/shell-snapshot.ts +199 -0
- package/src/utils/timings.ts +26 -0
- package/src/utils/title-generator.ts +167 -0
- package/src/utils/tools-manager.ts +362 -0
- package/src/web/scrapers/artifacthub.ts +215 -0
- package/src/web/scrapers/arxiv.ts +88 -0
- package/src/web/scrapers/aur.ts +175 -0
- package/src/web/scrapers/biorxiv.ts +141 -0
- package/src/web/scrapers/bluesky.ts +284 -0
- package/src/web/scrapers/brew.ts +177 -0
- package/src/web/scrapers/cheatsh.ts +78 -0
- package/src/web/scrapers/chocolatey.ts +158 -0
- package/src/web/scrapers/choosealicense.ts +110 -0
- package/src/web/scrapers/cisa-kev.ts +100 -0
- package/src/web/scrapers/clojars.ts +180 -0
- package/src/web/scrapers/coingecko.ts +184 -0
- package/src/web/scrapers/crates-io.ts +128 -0
- package/src/web/scrapers/crossref.ts +149 -0
- package/src/web/scrapers/devto.ts +177 -0
- package/src/web/scrapers/discogs.ts +307 -0
- package/src/web/scrapers/discourse.ts +221 -0
- package/src/web/scrapers/dockerhub.ts +160 -0
- package/src/web/scrapers/fdroid.ts +158 -0
- package/src/web/scrapers/firefox-addons.ts +214 -0
- package/src/web/scrapers/flathub.ts +239 -0
- package/src/web/scrapers/github-gist.ts +68 -0
- package/src/web/scrapers/github.ts +490 -0
- package/src/web/scrapers/gitlab.ts +456 -0
- package/src/web/scrapers/go-pkg.ts +275 -0
- package/src/web/scrapers/hackage.ts +94 -0
- package/src/web/scrapers/hackernews.ts +208 -0
- package/src/web/scrapers/hex.ts +121 -0
- package/src/web/scrapers/huggingface.ts +385 -0
- package/src/web/scrapers/iacr.ts +86 -0
- package/src/web/scrapers/index.ts +249 -0
- package/src/web/scrapers/jetbrains-marketplace.ts +169 -0
- package/src/web/scrapers/lemmy.ts +220 -0
- package/src/web/scrapers/lobsters.ts +186 -0
- package/src/web/scrapers/mastodon.ts +310 -0
- package/src/web/scrapers/maven.ts +152 -0
- package/src/web/scrapers/mdn.ts +172 -0
- package/src/web/scrapers/metacpan.ts +253 -0
- package/src/web/scrapers/musicbrainz.ts +272 -0
- package/src/web/scrapers/npm.ts +114 -0
- package/src/web/scrapers/nuget.ts +205 -0
- package/src/web/scrapers/nvd.ts +243 -0
- package/src/web/scrapers/ollama.ts +265 -0
- package/src/web/scrapers/open-vsx.ts +119 -0
- package/src/web/scrapers/opencorporates.ts +275 -0
- package/src/web/scrapers/openlibrary.ts +319 -0
- package/src/web/scrapers/orcid.ts +298 -0
- package/src/web/scrapers/osv.ts +192 -0
- package/src/web/scrapers/packagist.ts +174 -0
- package/src/web/scrapers/pub-dev.ts +185 -0
- package/src/web/scrapers/pubmed.ts +177 -0
- package/src/web/scrapers/pypi.ts +129 -0
- package/src/web/scrapers/rawg.ts +124 -0
- package/src/web/scrapers/readthedocs.ts +125 -0
- package/src/web/scrapers/reddit.ts +104 -0
- package/src/web/scrapers/repology.ts +262 -0
- package/src/web/scrapers/rfc.ts +209 -0
- package/src/web/scrapers/rubygems.ts +117 -0
- package/src/web/scrapers/searchcode.ts +217 -0
- package/src/web/scrapers/sec-edgar.ts +274 -0
- package/src/web/scrapers/semantic-scholar.ts +190 -0
- package/src/web/scrapers/snapcraft.ts +200 -0
- package/src/web/scrapers/sourcegraph.ts +373 -0
- package/src/web/scrapers/spdx.ts +121 -0
- package/src/web/scrapers/spotify.ts +217 -0
- package/src/web/scrapers/stackoverflow.ts +124 -0
- package/src/web/scrapers/terraform.ts +304 -0
- package/src/web/scrapers/tldr.ts +51 -0
- package/src/web/scrapers/twitter.ts +97 -0
- package/src/web/scrapers/types.ts +200 -0
- package/src/web/scrapers/utils.ts +142 -0
- package/src/web/scrapers/vimeo.ts +152 -0
- package/src/web/scrapers/vscode-marketplace.ts +195 -0
- package/src/web/scrapers/w3c.ts +163 -0
- package/src/web/scrapers/wikidata.ts +357 -0
- package/src/web/scrapers/wikipedia.ts +95 -0
- package/src/web/scrapers/youtube.ts +312 -0
- package/src/web/search/auth.ts +178 -0
- package/src/web/search/index.ts +598 -0
- package/src/web/search/provider.ts +77 -0
- package/src/web/search/providers/anthropic.ts +284 -0
- package/src/web/search/providers/base.ts +22 -0
- package/src/web/search/providers/brave.ts +165 -0
- package/src/web/search/providers/codex.ts +377 -0
- package/src/web/search/providers/exa.ts +158 -0
- package/src/web/search/providers/gemini.ts +437 -0
- package/src/web/search/providers/jina.ts +99 -0
- package/src/web/search/providers/kimi.ts +196 -0
- package/src/web/search/providers/perplexity.ts +546 -0
- package/src/web/search/providers/synthetic.ts +136 -0
- package/src/web/search/providers/zai.ts +352 -0
- package/src/web/search/render.ts +299 -0
- package/src/web/search/types.ts +437 -0
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,1287 @@
|
|
|
1
|
+
import { Agent, type AgentEvent, type AgentMessage, type AgentTool, type ThinkingLevel } from "@nghyane/arcane-agent";
|
|
2
|
+
import { type Message, type Model, supportsXhigh } from "@nghyane/arcane-ai";
|
|
3
|
+
import { prewarmOpenAICodexResponses } from "@nghyane/arcane-ai/providers/openai-codex-responses";
|
|
4
|
+
import type { Component } from "@nghyane/arcane-tui";
|
|
5
|
+
import { $env, logger, postmortem } from "@nghyane/arcane-utils";
|
|
6
|
+
import { getAgentDbPath, getAgentDir, getProjectDir } from "@nghyane/arcane-utils/dirs";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { loadCapability } from "./capability";
|
|
9
|
+
import { type Rule, ruleCapability } from "./capability/rule";
|
|
10
|
+
import { ModelRegistry } from "./config/model-registry";
|
|
11
|
+
import { formatModelString, parseModelPattern, parseModelString } from "./config/model-resolver";
|
|
12
|
+
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
13
|
+
import { Settings, type SkillsSettings } from "./config/settings";
|
|
14
|
+
import { CursorExecHandlers } from "./cursor";
|
|
15
|
+
import "./discovery";
|
|
16
|
+
import { initializeWithSettings } from "./discovery";
|
|
17
|
+
import { TtsrManager } from "./export/ttsr";
|
|
18
|
+
import {
|
|
19
|
+
type CustomCommandsLoadResult,
|
|
20
|
+
loadCustomCommands as loadCustomCommandsInternal,
|
|
21
|
+
} from "./extensibility/custom-commands";
|
|
22
|
+
import { discoverAndLoadCustomTools } from "./extensibility/custom-tools";
|
|
23
|
+
import type { CustomTool, CustomToolContext, CustomToolSessionEvent } from "./extensibility/custom-tools/types";
|
|
24
|
+
import { CustomToolAdapter } from "./extensibility/custom-tools/wrapper";
|
|
25
|
+
import {
|
|
26
|
+
discoverAndLoadExtensions,
|
|
27
|
+
type ExtensionContext,
|
|
28
|
+
type ExtensionFactory,
|
|
29
|
+
ExtensionRunner,
|
|
30
|
+
ExtensionToolWrapper,
|
|
31
|
+
type ExtensionUIContext,
|
|
32
|
+
type LoadExtensionsResult,
|
|
33
|
+
loadExtensionFromFactory,
|
|
34
|
+
loadExtensions,
|
|
35
|
+
type ToolDefinition,
|
|
36
|
+
wrapRegisteredTools,
|
|
37
|
+
} from "./extensibility/extensions";
|
|
38
|
+
import { loadSkills as loadSkillsInternal, type Skill, type SkillWarning } from "./extensibility/skills";
|
|
39
|
+
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./extensibility/slash-commands";
|
|
40
|
+
import {
|
|
41
|
+
AgentProtocolHandler,
|
|
42
|
+
ArtifactProtocolHandler,
|
|
43
|
+
DocsProtocolHandler,
|
|
44
|
+
InternalUrlRouter,
|
|
45
|
+
MemoryProtocolHandler,
|
|
46
|
+
RuleProtocolHandler,
|
|
47
|
+
SkillProtocolHandler,
|
|
48
|
+
} from "./internal-urls";
|
|
49
|
+
import { disposeAllKernelSessions } from "./ipy/executor";
|
|
50
|
+
import { discoverAndLoadMCPTools, type MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
51
|
+
import { buildMemoryToolDeveloperInstructions, getMemoryRoot, startMemoryStartupTask } from "./memories";
|
|
52
|
+
import { collectEnvSecrets, loadSecrets, obfuscateMessages, SecretObfuscator } from "./secrets";
|
|
53
|
+
import { AgentSession } from "./session/agent-session";
|
|
54
|
+
import { AuthStorage } from "./session/auth-storage";
|
|
55
|
+
import { convertToLlm } from "./session/messages";
|
|
56
|
+
import { SessionManager } from "./session/session-manager";
|
|
57
|
+
import { closeAllConnections } from "./ssh/connection-manager";
|
|
58
|
+
import { unmountAll } from "./ssh/sshfs-mount";
|
|
59
|
+
import {
|
|
60
|
+
buildSystemPrompt as buildSystemPromptInternal,
|
|
61
|
+
loadProjectContextFiles as loadContextFilesInternal,
|
|
62
|
+
} from "./system-prompt";
|
|
63
|
+
import { AgentOutputManager } from "./task/output-manager";
|
|
64
|
+
import {
|
|
65
|
+
BashTool,
|
|
66
|
+
BUILTIN_TOOLS,
|
|
67
|
+
createTools,
|
|
68
|
+
EditTool,
|
|
69
|
+
FindTool,
|
|
70
|
+
GrepTool,
|
|
71
|
+
getSearchTools,
|
|
72
|
+
loadSshTool,
|
|
73
|
+
PythonTool,
|
|
74
|
+
ReadTool,
|
|
75
|
+
setPreferredImageProvider,
|
|
76
|
+
setPreferredSearchProvider,
|
|
77
|
+
type Tool,
|
|
78
|
+
type ToolSession,
|
|
79
|
+
WriteTool,
|
|
80
|
+
warmupLspServers,
|
|
81
|
+
} from "./tools";
|
|
82
|
+
import { ToolContextStore } from "./tools/context";
|
|
83
|
+
import { getGeminiImageTools } from "./tools/gemini-image";
|
|
84
|
+
import { EventBus } from "./utils/event-bus";
|
|
85
|
+
import { time } from "./utils/timings";
|
|
86
|
+
|
|
87
|
+
/** Conditional startup debug prints (stderr) when ARCANE_DEBUG_STARTUP is set */
|
|
88
|
+
const debugStartup = $env.ARCANE_DEBUG_STARTUP
|
|
89
|
+
? (stage: string) => process.stderr.write(`[startup] ${stage}\n`)
|
|
90
|
+
: () => {};
|
|
91
|
+
|
|
92
|
+
// Types
|
|
93
|
+
export interface CreateAgentSessionOptions {
|
|
94
|
+
/** Working directory for project-local discovery. Default: getProjectDir() */
|
|
95
|
+
cwd?: string;
|
|
96
|
+
/** Global config directory. Default: ~/.arcane/agent */
|
|
97
|
+
agentDir?: string;
|
|
98
|
+
/** Spawns to allow. Default: "*" */
|
|
99
|
+
spawns?: string;
|
|
100
|
+
|
|
101
|
+
/** Auth storage for credentials. Default: discoverAuthStorage(agentDir) */
|
|
102
|
+
authStorage?: AuthStorage;
|
|
103
|
+
/** Model registry. Default: discoverModels(authStorage, agentDir) */
|
|
104
|
+
modelRegistry?: ModelRegistry;
|
|
105
|
+
|
|
106
|
+
/** Model to use. Default: from settings, else first available */
|
|
107
|
+
model?: Model;
|
|
108
|
+
/** Raw model pattern string (e.g. from --model CLI flag) to resolve after extensions load.
|
|
109
|
+
* Used when model lookup is deferred because extension-provided models aren't registered yet. */
|
|
110
|
+
modelPattern?: string;
|
|
111
|
+
/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */
|
|
112
|
+
thinkingLevel?: ThinkingLevel;
|
|
113
|
+
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
114
|
+
scopedModels?: Array<{ model: Model; thinkingLevel: ThinkingLevel }>;
|
|
115
|
+
|
|
116
|
+
/** System prompt. String replaces default, function receives default and returns final. */
|
|
117
|
+
systemPrompt?: string | ((defaultPrompt: string) => string);
|
|
118
|
+
|
|
119
|
+
/** Custom tools to register (in addition to built-in tools). Accepts both CustomTool and ToolDefinition. */
|
|
120
|
+
customTools?: (CustomTool | ToolDefinition)[];
|
|
121
|
+
/** Inline extensions (merged with discovery). */
|
|
122
|
+
extensions?: ExtensionFactory[];
|
|
123
|
+
/** Additional extension paths to load (merged with discovery). */
|
|
124
|
+
additionalExtensionPaths?: string[];
|
|
125
|
+
/** Disable extension discovery (explicit paths still load). */
|
|
126
|
+
disableExtensionDiscovery?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Pre-loaded extensions (skips file discovery).
|
|
129
|
+
* @internal Used by CLI when extensions are loaded early to parse custom flags.
|
|
130
|
+
*/
|
|
131
|
+
preloadedExtensions?: LoadExtensionsResult;
|
|
132
|
+
|
|
133
|
+
/** Shared event bus for tool/extension communication. Default: creates new bus. */
|
|
134
|
+
eventBus?: EventBus;
|
|
135
|
+
|
|
136
|
+
/** Skills. Default: discovered from multiple locations */
|
|
137
|
+
skills?: Skill[];
|
|
138
|
+
/** Skills to inline into the system prompt instead of listing available skills. */
|
|
139
|
+
preloadedSkills?: Skill[];
|
|
140
|
+
/** Rules. Default: discovered from multiple locations */
|
|
141
|
+
rules?: Rule[];
|
|
142
|
+
/** Context files (AGENTS.md content). Default: discovered walking up from cwd */
|
|
143
|
+
contextFiles?: Array<{ path: string; content: string }>;
|
|
144
|
+
/** Prompt templates. Default: discovered from cwd/.arcane/prompts/ + agentDir/prompts/ */
|
|
145
|
+
promptTemplates?: PromptTemplate[];
|
|
146
|
+
/** File-based slash commands. Default: discovered from commands/ directories */
|
|
147
|
+
slashCommands?: FileSlashCommand[];
|
|
148
|
+
|
|
149
|
+
/** Enable MCP server discovery from .mcp.json files. Default: true */
|
|
150
|
+
enableMCP?: boolean;
|
|
151
|
+
|
|
152
|
+
/** Enable LSP integration (tool, formatting, diagnostics, warmup). Default: true */
|
|
153
|
+
enableLsp?: boolean;
|
|
154
|
+
/** Skip Python kernel availability check and prelude warmup */
|
|
155
|
+
skipPythonPreflight?: boolean;
|
|
156
|
+
|
|
157
|
+
/** Tool names explicitly requested (enables disabled-by-default tools) */
|
|
158
|
+
toolNames?: string[];
|
|
159
|
+
|
|
160
|
+
/** Output schema for structured completion (subagents) */
|
|
161
|
+
outputSchema?: unknown;
|
|
162
|
+
/** Whether to include the submit_result tool by default */
|
|
163
|
+
requireSubmitResultTool?: boolean;
|
|
164
|
+
/** Task recursion depth (for subagent sessions). Default: 0 */
|
|
165
|
+
taskDepth?: number;
|
|
166
|
+
/** Parent task ID prefix for nested artifact naming (e.g., "6-Extensions") */
|
|
167
|
+
parentTaskPrefix?: string;
|
|
168
|
+
|
|
169
|
+
/** Session manager. Default: SessionManager.create(cwd) */
|
|
170
|
+
sessionManager?: SessionManager;
|
|
171
|
+
|
|
172
|
+
/** Settings instance. Default: Settings.init({ cwd, agentDir }) */
|
|
173
|
+
settings?: Settings;
|
|
174
|
+
|
|
175
|
+
/** Whether UI is available (enables interactive tools like ask). Default: false */
|
|
176
|
+
hasUI?: boolean;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Result from createAgentSession */
|
|
180
|
+
export interface CreateAgentSessionResult {
|
|
181
|
+
/** The created session */
|
|
182
|
+
session: AgentSession;
|
|
183
|
+
/** Extensions result (loaded extensions + runtime) */
|
|
184
|
+
extensionsResult: LoadExtensionsResult;
|
|
185
|
+
/** Update tool UI context (interactive mode) */
|
|
186
|
+
setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
|
|
187
|
+
/** MCP manager for server lifecycle management (undefined if MCP disabled) */
|
|
188
|
+
mcpManager?: MCPManager;
|
|
189
|
+
/** Warning if session was restored with a different model than saved */
|
|
190
|
+
modelFallbackMessage?: string;
|
|
191
|
+
/** LSP servers that were warmed up at startup */
|
|
192
|
+
lspServers?: Array<{ name: string; status: "ready" | "error"; fileTypes: string[]; error?: string }>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Re-exports
|
|
196
|
+
|
|
197
|
+
export type { PromptTemplate } from "./config/prompt-templates";
|
|
198
|
+
export { Settings, type SkillsSettings } from "./config/settings";
|
|
199
|
+
export type { CustomCommand, CustomCommandFactory } from "./extensibility/custom-commands/types";
|
|
200
|
+
export type { CustomTool, CustomToolFactory } from "./extensibility/custom-tools/types";
|
|
201
|
+
export type {
|
|
202
|
+
ExtensionAPI,
|
|
203
|
+
ExtensionCommandContext,
|
|
204
|
+
ExtensionContext,
|
|
205
|
+
ExtensionFactory,
|
|
206
|
+
ToolDefinition,
|
|
207
|
+
} from "./extensibility/extensions";
|
|
208
|
+
export type { Skill } from "./extensibility/skills";
|
|
209
|
+
export type { FileSlashCommand } from "./extensibility/slash-commands";
|
|
210
|
+
export type { MCPManager, MCPServerConfig, MCPServerConnection, MCPToolsLoadResult } from "./mcp";
|
|
211
|
+
export type { Tool } from "./tools";
|
|
212
|
+
|
|
213
|
+
export {
|
|
214
|
+
// Individual tool classes (for custom usage)
|
|
215
|
+
BashTool,
|
|
216
|
+
// Tool classes and factories
|
|
217
|
+
BUILTIN_TOOLS,
|
|
218
|
+
createTools,
|
|
219
|
+
EditTool,
|
|
220
|
+
FindTool,
|
|
221
|
+
GrepTool,
|
|
222
|
+
loadSshTool,
|
|
223
|
+
PythonTool,
|
|
224
|
+
ReadTool,
|
|
225
|
+
WriteTool,
|
|
226
|
+
type ToolSession,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// Helper Functions
|
|
230
|
+
|
|
231
|
+
function getDefaultAgentDir(): string {
|
|
232
|
+
return getAgentDir();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Discovery Functions
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Create an AuthStorage instance with fallback support.
|
|
239
|
+
* Reads from primary path first, then falls back to legacy paths (.pi, .claude).
|
|
240
|
+
*/
|
|
241
|
+
export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): Promise<AuthStorage> {
|
|
242
|
+
const dbPath = getAgentDbPath(agentDir);
|
|
243
|
+
logger.debug("discoverAuthStorage", { agentDir, dbPath });
|
|
244
|
+
|
|
245
|
+
const storage = await AuthStorage.create(dbPath);
|
|
246
|
+
await storage.reload();
|
|
247
|
+
return storage;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Discover extensions from cwd.
|
|
252
|
+
*/
|
|
253
|
+
export async function discoverExtensions(cwd?: string): Promise<LoadExtensionsResult> {
|
|
254
|
+
const resolvedCwd = cwd ?? getProjectDir();
|
|
255
|
+
|
|
256
|
+
return discoverAndLoadExtensions([], resolvedCwd);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Discover skills from cwd and agentDir.
|
|
261
|
+
*/
|
|
262
|
+
export async function discoverSkills(
|
|
263
|
+
cwd?: string,
|
|
264
|
+
_agentDir?: string,
|
|
265
|
+
settings?: SkillsSettings,
|
|
266
|
+
): Promise<{ skills: Skill[]; warnings: SkillWarning[] }> {
|
|
267
|
+
return await loadSkillsInternal({
|
|
268
|
+
...settings,
|
|
269
|
+
cwd: cwd ?? getProjectDir(),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Discover context files (AGENTS.md) walking up from cwd.
|
|
275
|
+
* Returns files sorted by depth (farther from cwd first, so closer files appear last/more prominent).
|
|
276
|
+
*/
|
|
277
|
+
export async function discoverContextFiles(
|
|
278
|
+
cwd?: string,
|
|
279
|
+
_agentDir?: string,
|
|
280
|
+
): Promise<Array<{ path: string; content: string; depth?: number }>> {
|
|
281
|
+
return await loadContextFilesInternal({
|
|
282
|
+
cwd: cwd ?? getProjectDir(),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Discover prompt templates from cwd and agentDir.
|
|
288
|
+
*/
|
|
289
|
+
export async function discoverPromptTemplates(cwd?: string, agentDir?: string): Promise<PromptTemplate[]> {
|
|
290
|
+
return await loadPromptTemplatesInternal({
|
|
291
|
+
cwd: cwd ?? getProjectDir(),
|
|
292
|
+
agentDir: agentDir ?? getDefaultAgentDir(),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Discover file-based slash commands from commands/ directories.
|
|
298
|
+
*/
|
|
299
|
+
export async function discoverSlashCommands(cwd?: string): Promise<FileSlashCommand[]> {
|
|
300
|
+
return loadSlashCommandsInternal({ cwd: cwd ?? getProjectDir() });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Discover custom commands (TypeScript slash commands) from cwd and agentDir.
|
|
305
|
+
*/
|
|
306
|
+
export async function discoverCustomTSCommands(cwd?: string, agentDir?: string): Promise<CustomCommandsLoadResult> {
|
|
307
|
+
const resolvedCwd = cwd ?? getProjectDir();
|
|
308
|
+
const resolvedAgentDir = agentDir ?? getDefaultAgentDir();
|
|
309
|
+
|
|
310
|
+
return loadCustomCommandsInternal({
|
|
311
|
+
cwd: resolvedCwd,
|
|
312
|
+
agentDir: resolvedAgentDir,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Discover MCP servers from .mcp.json files.
|
|
318
|
+
* Returns the manager and loaded tools.
|
|
319
|
+
*/
|
|
320
|
+
export async function discoverMCPServers(cwd?: string): Promise<MCPToolsLoadResult> {
|
|
321
|
+
const resolvedCwd = cwd ?? getProjectDir();
|
|
322
|
+
return discoverAndLoadMCPTools(resolvedCwd);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// API Key Helpers
|
|
326
|
+
|
|
327
|
+
// System Prompt
|
|
328
|
+
|
|
329
|
+
export interface BuildSystemPromptOptions {
|
|
330
|
+
tools?: Tool[];
|
|
331
|
+
skills?: Skill[];
|
|
332
|
+
contextFiles?: Array<{ path: string; content: string }>;
|
|
333
|
+
cwd?: string;
|
|
334
|
+
appendPrompt?: string;
|
|
335
|
+
repeatToolDescriptions?: boolean;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Build the default system prompt.
|
|
340
|
+
*/
|
|
341
|
+
export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}): Promise<string> {
|
|
342
|
+
return await buildSystemPromptInternal({
|
|
343
|
+
cwd: options.cwd,
|
|
344
|
+
skills: options.skills,
|
|
345
|
+
contextFiles: options.contextFiles,
|
|
346
|
+
appendSystemPrompt: options.appendPrompt,
|
|
347
|
+
repeatToolDescriptions: options.repeatToolDescriptions,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Internal Helpers
|
|
352
|
+
|
|
353
|
+
function createCustomToolContext(ctx: ExtensionContext): CustomToolContext {
|
|
354
|
+
return {
|
|
355
|
+
sessionManager: ctx.sessionManager,
|
|
356
|
+
modelRegistry: ctx.modelRegistry,
|
|
357
|
+
model: ctx.model,
|
|
358
|
+
isIdle: ctx.isIdle,
|
|
359
|
+
hasQueuedMessages: ctx.hasPendingMessages,
|
|
360
|
+
abort: ctx.abort,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function isCustomTool(tool: CustomTool | ToolDefinition): tool is CustomTool {
|
|
365
|
+
// To distinguish, we mark converted tools with a hidden symbol property.
|
|
366
|
+
// If the tool doesn't have this marker, it's a CustomTool that needs conversion.
|
|
367
|
+
return !(tool as any).__isToolDefinition;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const TOOL_DEFINITION_MARKER = Symbol("__isToolDefinition");
|
|
371
|
+
|
|
372
|
+
let sshCleanupRegistered = false;
|
|
373
|
+
|
|
374
|
+
async function cleanupSshResources(): Promise<void> {
|
|
375
|
+
const results = await Promise.allSettled([closeAllConnections(), unmountAll()]);
|
|
376
|
+
for (const result of results) {
|
|
377
|
+
if (result.status === "rejected") {
|
|
378
|
+
logger.warn("SSH cleanup failed", { error: String(result.reason) });
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function registerSshCleanup(): void {
|
|
384
|
+
if (sshCleanupRegistered) return;
|
|
385
|
+
sshCleanupRegistered = true;
|
|
386
|
+
postmortem.register("ssh-cleanup", cleanupSshResources);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let pythonCleanupRegistered = false;
|
|
390
|
+
|
|
391
|
+
function registerPythonCleanup(): void {
|
|
392
|
+
if (pythonCleanupRegistered) return;
|
|
393
|
+
pythonCleanupRegistered = true;
|
|
394
|
+
postmortem.register("python-cleanup", disposeAllKernelSessions);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function customToolToDefinition(tool: CustomTool): ToolDefinition {
|
|
398
|
+
const definition: ToolDefinition & { [TOOL_DEFINITION_MARKER]: true } = {
|
|
399
|
+
name: tool.name,
|
|
400
|
+
label: tool.label,
|
|
401
|
+
description: tool.description,
|
|
402
|
+
parameters: tool.parameters,
|
|
403
|
+
execute: (toolCallId, params, signal, onUpdate, ctx) =>
|
|
404
|
+
tool.execute(toolCallId, params, onUpdate, createCustomToolContext(ctx), signal),
|
|
405
|
+
onSession: tool.onSession ? (event, ctx) => tool.onSession?.(event, createCustomToolContext(ctx)) : undefined,
|
|
406
|
+
renderCall: tool.renderCall,
|
|
407
|
+
renderResult: tool.renderResult
|
|
408
|
+
? (result, options, theme): Component => {
|
|
409
|
+
const component = tool.renderResult?.(
|
|
410
|
+
result,
|
|
411
|
+
{ expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame },
|
|
412
|
+
theme,
|
|
413
|
+
);
|
|
414
|
+
// Return empty component if undefined to match Component type requirement
|
|
415
|
+
return component ?? ({ render: () => [] } as unknown as Component);
|
|
416
|
+
}
|
|
417
|
+
: undefined,
|
|
418
|
+
[TOOL_DEFINITION_MARKER]: true,
|
|
419
|
+
};
|
|
420
|
+
return definition;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
|
|
424
|
+
return api => {
|
|
425
|
+
for (const tool of tools) {
|
|
426
|
+
api.registerTool(customToolToDefinition(tool));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const runOnSession = async (event: CustomToolSessionEvent, ctx: ExtensionContext) => {
|
|
430
|
+
for (const tool of tools) {
|
|
431
|
+
if (!tool.onSession) continue;
|
|
432
|
+
try {
|
|
433
|
+
await tool.onSession(event, createCustomToolContext(ctx));
|
|
434
|
+
} catch (err) {
|
|
435
|
+
logger.warn("Custom tool onSession error", { tool: tool.name, error: String(err) });
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
api.on("session_start", async (_event, ctx) =>
|
|
441
|
+
runOnSession({ reason: "start", previousSessionFile: undefined }, ctx),
|
|
442
|
+
);
|
|
443
|
+
api.on("session_switch", async (event, ctx) =>
|
|
444
|
+
runOnSession({ reason: "switch", previousSessionFile: event.previousSessionFile }, ctx),
|
|
445
|
+
);
|
|
446
|
+
api.on("session_branch", async (event, ctx) =>
|
|
447
|
+
runOnSession({ reason: "branch", previousSessionFile: event.previousSessionFile }, ctx),
|
|
448
|
+
);
|
|
449
|
+
api.on("session_tree", async (_event, ctx) =>
|
|
450
|
+
runOnSession({ reason: "tree", previousSessionFile: undefined }, ctx),
|
|
451
|
+
);
|
|
452
|
+
api.on("session_shutdown", async (_event, ctx) =>
|
|
453
|
+
runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx),
|
|
454
|
+
);
|
|
455
|
+
api.on("auto_compaction_start", async (event, ctx) =>
|
|
456
|
+
runOnSession({ reason: "auto_compaction_start", trigger: event.reason }, ctx),
|
|
457
|
+
);
|
|
458
|
+
api.on("auto_compaction_end", async (event, ctx) =>
|
|
459
|
+
runOnSession(
|
|
460
|
+
{
|
|
461
|
+
reason: "auto_compaction_end",
|
|
462
|
+
result: event.result,
|
|
463
|
+
aborted: event.aborted,
|
|
464
|
+
willRetry: event.willRetry,
|
|
465
|
+
errorMessage: event.errorMessage,
|
|
466
|
+
},
|
|
467
|
+
ctx,
|
|
468
|
+
),
|
|
469
|
+
);
|
|
470
|
+
api.on("auto_retry_start", async (event, ctx) =>
|
|
471
|
+
runOnSession(
|
|
472
|
+
{
|
|
473
|
+
reason: "auto_retry_start",
|
|
474
|
+
attempt: event.attempt,
|
|
475
|
+
maxAttempts: event.maxAttempts,
|
|
476
|
+
delayMs: event.delayMs,
|
|
477
|
+
errorMessage: event.errorMessage,
|
|
478
|
+
},
|
|
479
|
+
ctx,
|
|
480
|
+
),
|
|
481
|
+
);
|
|
482
|
+
api.on("auto_retry_end", async (event, ctx) =>
|
|
483
|
+
runOnSession(
|
|
484
|
+
{
|
|
485
|
+
reason: "auto_retry_end",
|
|
486
|
+
success: event.success,
|
|
487
|
+
attempt: event.attempt,
|
|
488
|
+
finalError: event.finalError,
|
|
489
|
+
},
|
|
490
|
+
ctx,
|
|
491
|
+
),
|
|
492
|
+
);
|
|
493
|
+
api.on("ttsr_triggered", async (event, ctx) =>
|
|
494
|
+
runOnSession({ reason: "ttsr_triggered", rules: event.rules }, ctx),
|
|
495
|
+
);
|
|
496
|
+
api.on("todo_reminder", async (event, ctx) =>
|
|
497
|
+
runOnSession(
|
|
498
|
+
{
|
|
499
|
+
reason: "todo_reminder",
|
|
500
|
+
todos: event.todos,
|
|
501
|
+
attempt: event.attempt,
|
|
502
|
+
maxAttempts: event.maxAttempts,
|
|
503
|
+
},
|
|
504
|
+
ctx,
|
|
505
|
+
),
|
|
506
|
+
);
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Factory
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Create an AgentSession with the specified options.
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* ```typescript
|
|
517
|
+
* // Minimal - uses defaults
|
|
518
|
+
* const { session } = await createAgentSession();
|
|
519
|
+
*
|
|
520
|
+
* // With explicit model
|
|
521
|
+
* import { getModel } from '@nghyane/arcane-ai';
|
|
522
|
+
* const { session } = await createAgentSession({
|
|
523
|
+
* model: getModel('anthropic', 'claude-opus-4-5'),
|
|
524
|
+
* thinkingLevel: 'high',
|
|
525
|
+
* });
|
|
526
|
+
*
|
|
527
|
+
* // Continue previous session
|
|
528
|
+
* const { session, modelFallbackMessage } = await createAgentSession({
|
|
529
|
+
* continueSession: true,
|
|
530
|
+
* });
|
|
531
|
+
*
|
|
532
|
+
* // Full control
|
|
533
|
+
* const { session } = await createAgentSession({
|
|
534
|
+
* model: myModel,
|
|
535
|
+
* getApiKey: async () => Bun.env.MY_KEY,
|
|
536
|
+
* systemPrompt: 'You are helpful.',
|
|
537
|
+
* tools: codingTools({ cwd: getProjectDir() }),
|
|
538
|
+
* skills: [],
|
|
539
|
+
* sessionManager: SessionManager.inMemory(),
|
|
540
|
+
* });
|
|
541
|
+
* ```
|
|
542
|
+
*/
|
|
543
|
+
export async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {
|
|
544
|
+
debugStartup("sdk:createAgentSession:entry");
|
|
545
|
+
const cwd = options.cwd ?? getProjectDir();
|
|
546
|
+
const agentDir = options.agentDir ?? getDefaultAgentDir();
|
|
547
|
+
const eventBus = options.eventBus ?? new EventBus();
|
|
548
|
+
|
|
549
|
+
registerSshCleanup();
|
|
550
|
+
registerPythonCleanup();
|
|
551
|
+
|
|
552
|
+
// Use provided or create AuthStorage and ModelRegistry
|
|
553
|
+
const authStorage = options.authStorage ?? (await discoverAuthStorage(agentDir));
|
|
554
|
+
const modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage);
|
|
555
|
+
if (!options.modelRegistry) {
|
|
556
|
+
await modelRegistry.refresh();
|
|
557
|
+
}
|
|
558
|
+
time("discoverModels");
|
|
559
|
+
|
|
560
|
+
const settings = options.settings ?? (await Settings.init({ cwd, agentDir }));
|
|
561
|
+
time("settings");
|
|
562
|
+
initializeWithSettings(settings);
|
|
563
|
+
time("initializeWithSettings");
|
|
564
|
+
const skillsSettings = settings.getGroup("skills") as SkillsSettings;
|
|
565
|
+
const discoveredSkillsPromise =
|
|
566
|
+
options.skills === undefined ? discoverSkills(cwd, agentDir, skillsSettings) : undefined;
|
|
567
|
+
|
|
568
|
+
// Initialize provider preferences from settings
|
|
569
|
+
setPreferredSearchProvider(settings.get("providers.webSearch") ?? "auto");
|
|
570
|
+
setPreferredImageProvider(settings.get("providers.image") ?? "auto");
|
|
571
|
+
|
|
572
|
+
const sessionManager = options.sessionManager ?? SessionManager.create(cwd);
|
|
573
|
+
time("sessionManager");
|
|
574
|
+
const sessionId = sessionManager.getSessionId();
|
|
575
|
+
const modelApiKeyAvailability = new Map<string, boolean>();
|
|
576
|
+
const getModelAvailabilityKey = (candidate: Model): string =>
|
|
577
|
+
`${candidate.provider}\u0000${candidate.baseUrl ?? ""}`;
|
|
578
|
+
const hasModelApiKey = async (candidate: Model): Promise<boolean> => {
|
|
579
|
+
const availabilityKey = getModelAvailabilityKey(candidate);
|
|
580
|
+
const cached = modelApiKeyAvailability.get(availabilityKey);
|
|
581
|
+
if (cached !== undefined) {
|
|
582
|
+
return cached;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const hasKey = !!(await modelRegistry.getApiKey(candidate, sessionId));
|
|
586
|
+
modelApiKeyAvailability.set(availabilityKey, hasKey);
|
|
587
|
+
return hasKey;
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
// Check if session has existing data to restore
|
|
591
|
+
const existingSession = sessionManager.buildSessionContext();
|
|
592
|
+
time("loadSession");
|
|
593
|
+
const hasExistingSession = existingSession.messages.length > 0;
|
|
594
|
+
const hasThinkingEntry = sessionManager.getBranch().some(entry => entry.type === "thinking_level_change");
|
|
595
|
+
|
|
596
|
+
const hasExplicitModel = options.model !== undefined || options.modelPattern !== undefined;
|
|
597
|
+
let model = options.model;
|
|
598
|
+
let modelFallbackMessage: string | undefined;
|
|
599
|
+
// If session has data, try to restore model from it.
|
|
600
|
+
// Skip restore when an explicit model was requested.
|
|
601
|
+
const defaultModelStr = existingSession.models.default;
|
|
602
|
+
if (!hasExplicitModel && !model && hasExistingSession && defaultModelStr) {
|
|
603
|
+
const parsedModel = parseModelString(defaultModelStr);
|
|
604
|
+
if (parsedModel) {
|
|
605
|
+
const restoredModel = modelRegistry.find(parsedModel.provider, parsedModel.id);
|
|
606
|
+
if (restoredModel && (await hasModelApiKey(restoredModel))) {
|
|
607
|
+
model = restoredModel;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
if (!model) {
|
|
611
|
+
modelFallbackMessage = `Could not restore model ${defaultModelStr}`;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// If still no model, try settings default.
|
|
616
|
+
// Skip settings fallback when an explicit model was requested.
|
|
617
|
+
if (!hasExplicitModel && !model) {
|
|
618
|
+
const settingsDefaultModel = settings.getModelRole("default");
|
|
619
|
+
if (settingsDefaultModel) {
|
|
620
|
+
const parsedModel = parseModelString(settingsDefaultModel);
|
|
621
|
+
if (parsedModel) {
|
|
622
|
+
const settingsModel = modelRegistry.find(parsedModel.provider, parsedModel.id);
|
|
623
|
+
if (settingsModel && (await hasModelApiKey(settingsModel))) {
|
|
624
|
+
model = settingsModel;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// For subagent sessions using GitHub Copilot, add X-Initiator header
|
|
631
|
+
// to ensure proper billing (agent-initiated vs user-initiated)
|
|
632
|
+
const taskDepth = options.taskDepth ?? 0;
|
|
633
|
+
const forceCopilotAgentInitiator = taskDepth > 0;
|
|
634
|
+
if (forceCopilotAgentInitiator && model?.provider === "github-copilot") {
|
|
635
|
+
model = {
|
|
636
|
+
...model,
|
|
637
|
+
headers: {
|
|
638
|
+
...model.headers,
|
|
639
|
+
"X-Initiator": "agent",
|
|
640
|
+
},
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
let thinkingLevel = options.thinkingLevel;
|
|
645
|
+
|
|
646
|
+
// If session has data, restore thinking level from it
|
|
647
|
+
if (thinkingLevel === undefined && hasExistingSession) {
|
|
648
|
+
thinkingLevel = hasThinkingEntry
|
|
649
|
+
? (existingSession.thinkingLevel as ThinkingLevel)
|
|
650
|
+
: ((settings.get("defaultThinkingLevel") ?? "off") as ThinkingLevel);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Fall back to settings default
|
|
654
|
+
if (thinkingLevel === undefined) {
|
|
655
|
+
thinkingLevel = settings.get("defaultThinkingLevel") ?? "off";
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Clamp to model capabilities
|
|
659
|
+
if (!model || !model.reasoning) {
|
|
660
|
+
thinkingLevel = "off";
|
|
661
|
+
} else if (thinkingLevel === "xhigh" && !supportsXhigh(model)) {
|
|
662
|
+
thinkingLevel = "high";
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
let skills: Skill[];
|
|
666
|
+
let skillWarnings: SkillWarning[];
|
|
667
|
+
if (options.skills !== undefined) {
|
|
668
|
+
skills = options.skills;
|
|
669
|
+
skillWarnings = [];
|
|
670
|
+
} else {
|
|
671
|
+
const discovered = discoveredSkillsPromise ? await discoveredSkillsPromise : { skills: [], warnings: [] };
|
|
672
|
+
time("discoverSkills");
|
|
673
|
+
skills = discovered.skills;
|
|
674
|
+
skillWarnings = discovered.warnings;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Discover rules
|
|
678
|
+
const ttsrSettings = settings.getGroup("ttsr");
|
|
679
|
+
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
680
|
+
const rulesResult =
|
|
681
|
+
options.rules !== undefined
|
|
682
|
+
? { items: options.rules, warnings: undefined }
|
|
683
|
+
: await loadCapability<Rule>(ruleCapability.id, { cwd });
|
|
684
|
+
const registeredTtsrRuleNames = new Set<string>();
|
|
685
|
+
for (const rule of rulesResult.items) {
|
|
686
|
+
if (rule.condition && rule.condition.length > 0) {
|
|
687
|
+
if (ttsrManager.addRule(rule)) {
|
|
688
|
+
registeredTtsrRuleNames.add(rule.name);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (existingSession.injectedTtsrRules.length > 0) {
|
|
693
|
+
ttsrManager.restoreInjected(existingSession.injectedTtsrRules);
|
|
694
|
+
}
|
|
695
|
+
time("discoverTtsrRules");
|
|
696
|
+
|
|
697
|
+
// Filter rules for the rulebook (non-TTSR, non-alwaysApply, with descriptions)
|
|
698
|
+
const rulebookRules = rulesResult.items.filter((rule: Rule) => {
|
|
699
|
+
if (registeredTtsrRuleNames.has(rule.name)) return false;
|
|
700
|
+
if (rule.alwaysApply) return false;
|
|
701
|
+
if (!rule.description) return false;
|
|
702
|
+
return true;
|
|
703
|
+
});
|
|
704
|
+
time("filterRulebookRules");
|
|
705
|
+
|
|
706
|
+
const contextFiles = options.contextFiles ?? (await discoverContextFiles(cwd, agentDir));
|
|
707
|
+
time("discoverContextFiles");
|
|
708
|
+
|
|
709
|
+
let agent: Agent;
|
|
710
|
+
let session: AgentSession;
|
|
711
|
+
|
|
712
|
+
const enableLsp = options.enableLsp ?? true;
|
|
713
|
+
|
|
714
|
+
const toolSession: ToolSession = {
|
|
715
|
+
cwd,
|
|
716
|
+
hasUI: options.hasUI ?? false,
|
|
717
|
+
enableLsp,
|
|
718
|
+
get hasEditTool() {
|
|
719
|
+
return !options.toolNames || options.toolNames.includes("edit");
|
|
720
|
+
},
|
|
721
|
+
skipPythonPreflight: options.skipPythonPreflight,
|
|
722
|
+
contextFiles,
|
|
723
|
+
skills,
|
|
724
|
+
eventBus,
|
|
725
|
+
outputSchema: options.outputSchema,
|
|
726
|
+
requireSubmitResultTool: options.requireSubmitResultTool,
|
|
727
|
+
taskDepth: options.taskDepth ?? 0,
|
|
728
|
+
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
729
|
+
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
|
730
|
+
getSessionSpawns: () => options.spawns ?? "*",
|
|
731
|
+
getModelString: () => (hasExplicitModel && model ? formatModelString(model) : undefined),
|
|
732
|
+
getActiveModelString: () => {
|
|
733
|
+
const activeModel = agent?.state.model;
|
|
734
|
+
if (activeModel) return formatModelString(activeModel);
|
|
735
|
+
// Fall back to initial model during tool creation (before agent exists)
|
|
736
|
+
if (model) return formatModelString(model);
|
|
737
|
+
return undefined;
|
|
738
|
+
},
|
|
739
|
+
getCompactContext: () => session.formatCompactContext(),
|
|
740
|
+
settings,
|
|
741
|
+
authStorage,
|
|
742
|
+
modelRegistry,
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// Initialize internal URL router for internal protocols (agent://, artifact://, memory://, skill://, rule://)
|
|
746
|
+
const internalRouter = new InternalUrlRouter();
|
|
747
|
+
const getArtifactsDir = () => {
|
|
748
|
+
const sessionFile = sessionManager.getSessionFile();
|
|
749
|
+
return sessionFile ? sessionFile.slice(0, -6) : null; // strip .jsonl
|
|
750
|
+
};
|
|
751
|
+
internalRouter.register(new AgentProtocolHandler({ getArtifactsDir }));
|
|
752
|
+
internalRouter.register(new ArtifactProtocolHandler({ getArtifactsDir }));
|
|
753
|
+
internalRouter.register(
|
|
754
|
+
new MemoryProtocolHandler({
|
|
755
|
+
getMemoryRoot: () => getMemoryRoot(agentDir, settings.getCwd()),
|
|
756
|
+
}),
|
|
757
|
+
);
|
|
758
|
+
internalRouter.register(
|
|
759
|
+
new SkillProtocolHandler({
|
|
760
|
+
getSkills: () => skills,
|
|
761
|
+
}),
|
|
762
|
+
);
|
|
763
|
+
internalRouter.register(
|
|
764
|
+
new RuleProtocolHandler({
|
|
765
|
+
getRules: () => rulebookRules,
|
|
766
|
+
}),
|
|
767
|
+
);
|
|
768
|
+
internalRouter.register(new DocsProtocolHandler());
|
|
769
|
+
toolSession.internalRouter = internalRouter;
|
|
770
|
+
toolSession.getArtifactsDir = getArtifactsDir;
|
|
771
|
+
toolSession.agentOutputManager = new AgentOutputManager(
|
|
772
|
+
getArtifactsDir,
|
|
773
|
+
options.parentTaskPrefix ? { parentPrefix: options.parentTaskPrefix } : undefined,
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
// Create built-in tools (already wrapped with meta notice formatting)
|
|
777
|
+
const builtinTools = await createTools(toolSession, options.toolNames);
|
|
778
|
+
time("createAllTools");
|
|
779
|
+
|
|
780
|
+
// Discover MCP tools from .mcp.json files
|
|
781
|
+
let mcpManager: MCPManager | undefined;
|
|
782
|
+
const enableMCP = options.enableMCP ?? true;
|
|
783
|
+
const customTools: CustomTool[] = [];
|
|
784
|
+
if (enableMCP) {
|
|
785
|
+
const mcpResult = await discoverAndLoadMCPTools(cwd, {
|
|
786
|
+
onConnecting: serverNames => {
|
|
787
|
+
if (options.hasUI && serverNames.length > 0) {
|
|
788
|
+
process.stderr.write(`${chalk.gray(`Connecting to MCP servers: ${serverNames.join(", ")}…`)}\n`);
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
enableProjectConfig: settings.get("mcp.enableProjectConfig") ?? true,
|
|
792
|
+
// Always filter Exa - we have native integration
|
|
793
|
+
filterExa: true,
|
|
794
|
+
// Filter browser MCP servers when builtin browser tool is active
|
|
795
|
+
filterBrowser: (settings.get("browser.enabled") as boolean) ?? false,
|
|
796
|
+
cacheStorage: settings.getStorage(),
|
|
797
|
+
authStorage,
|
|
798
|
+
});
|
|
799
|
+
time("discoverAndLoadMCPTools");
|
|
800
|
+
mcpManager = mcpResult.manager;
|
|
801
|
+
toolSession.mcpManager = mcpManager;
|
|
802
|
+
|
|
803
|
+
// If we extracted Exa API keys from MCP configs and EXA_AARCANE_KEY isn't set, use the first one
|
|
804
|
+
if (mcpResult.exaApiKeys.length > 0 && !$env.EXA_AARCANE_KEY) {
|
|
805
|
+
Bun.env.EXA_AARCANE_KEY = mcpResult.exaApiKeys[0];
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Log MCP errors
|
|
809
|
+
for (const { path, error } of mcpResult.errors) {
|
|
810
|
+
logger.error("MCP tool load failed", { path, error });
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (mcpResult.tools.length > 0) {
|
|
814
|
+
// MCP tools are LoadedCustomTool, extract the tool property
|
|
815
|
+
customTools.push(...mcpResult.tools.map(loaded => loaded.tool));
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// Add Gemini image tools if GEMINI_AARCANE_KEY (or GOOGLE_AARCANE_KEY) is available
|
|
820
|
+
const geminiImageTools = await getGeminiImageTools();
|
|
821
|
+
time("getGeminiImageTools");
|
|
822
|
+
if (geminiImageTools.length > 0) {
|
|
823
|
+
customTools.push(...(geminiImageTools as unknown as CustomTool[]));
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Add specialized Exa web search tools if EXA_AARCANE_KEY is available
|
|
827
|
+
const exaSettings = settings.getGroup("exa");
|
|
828
|
+
if (exaSettings.enabled && exaSettings.enableSearch) {
|
|
829
|
+
const exaSearchTools = await getSearchTools({
|
|
830
|
+
enableLinkedin: exaSettings.enableLinkedin as boolean,
|
|
831
|
+
enableCompany: exaSettings.enableCompany as boolean,
|
|
832
|
+
});
|
|
833
|
+
time("getSearchTools");
|
|
834
|
+
// Filter out the base web_search (already in built-in tools), add specialized Exa tools
|
|
835
|
+
const specializedTools = exaSearchTools.filter(t => t.name !== "web_search");
|
|
836
|
+
if (specializedTools.length > 0) {
|
|
837
|
+
customTools.push(...specializedTools);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Discover and load custom tools from .arcane/tools/, .claude/tools/, etc.
|
|
842
|
+
const builtInToolNames = builtinTools.map(t => t.name);
|
|
843
|
+
const discoveredCustomTools = await discoverAndLoadCustomTools([], cwd, builtInToolNames);
|
|
844
|
+
time("discoverAndLoadCustomTools");
|
|
845
|
+
for (const { path, error } of discoveredCustomTools.errors) {
|
|
846
|
+
logger.error("Custom tool load failed", { path, error });
|
|
847
|
+
}
|
|
848
|
+
if (discoveredCustomTools.tools.length > 0) {
|
|
849
|
+
customTools.push(...discoveredCustomTools.tools.map(loaded => loaded.tool));
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : [];
|
|
853
|
+
if (customTools.length > 0) {
|
|
854
|
+
inlineExtensions.push(createCustomToolsExtension(customTools));
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Load extensions (discovers from standard locations + configured paths)
|
|
858
|
+
let extensionsResult: LoadExtensionsResult;
|
|
859
|
+
if (options.disableExtensionDiscovery) {
|
|
860
|
+
const configuredPaths = options.additionalExtensionPaths ?? [];
|
|
861
|
+
extensionsResult = await loadExtensions(configuredPaths, cwd, eventBus);
|
|
862
|
+
time("loadExtensions");
|
|
863
|
+
for (const { path, error } of extensionsResult.errors) {
|
|
864
|
+
logger.error("Failed to load extension", { path, error });
|
|
865
|
+
}
|
|
866
|
+
} else if (options.preloadedExtensions) {
|
|
867
|
+
extensionsResult = options.preloadedExtensions;
|
|
868
|
+
} else {
|
|
869
|
+
// Merge CLI extension paths with settings extension paths
|
|
870
|
+
const configuredPaths = [
|
|
871
|
+
...(options.additionalExtensionPaths ?? []),
|
|
872
|
+
...((settings.get("extensions") as string[]) ?? []),
|
|
873
|
+
];
|
|
874
|
+
extensionsResult = await discoverAndLoadExtensions(configuredPaths, cwd, eventBus);
|
|
875
|
+
time("discoverAndLoadExtensions");
|
|
876
|
+
for (const { path, error } of extensionsResult.errors) {
|
|
877
|
+
logger.error("Failed to load extension", { path, error });
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Load inline extensions from factories
|
|
882
|
+
if (inlineExtensions.length > 0) {
|
|
883
|
+
for (let i = 0; i < inlineExtensions.length; i++) {
|
|
884
|
+
const factory = inlineExtensions[i];
|
|
885
|
+
const loaded = await loadExtensionFromFactory(
|
|
886
|
+
factory,
|
|
887
|
+
cwd,
|
|
888
|
+
eventBus,
|
|
889
|
+
extensionsResult.runtime,
|
|
890
|
+
`<inline-${i}>`,
|
|
891
|
+
);
|
|
892
|
+
extensionsResult.extensions.push(loaded);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// Process provider registrations queued during extension loading.
|
|
897
|
+
// This must happen before the runner is created so that models registered by
|
|
898
|
+
// extensions are available for model selection on session resume / fallback.
|
|
899
|
+
const activeExtensionSources = extensionsResult.extensions.map(extension => extension.path);
|
|
900
|
+
modelRegistry.syncExtensionSources(activeExtensionSources);
|
|
901
|
+
for (const sourceId of new Set(activeExtensionSources)) {
|
|
902
|
+
modelRegistry.clearSourceRegistrations(sourceId);
|
|
903
|
+
}
|
|
904
|
+
if (extensionsResult.runtime.pendingProviderRegistrations.length > 0) {
|
|
905
|
+
for (const { name, config, sourceId } of extensionsResult.runtime.pendingProviderRegistrations) {
|
|
906
|
+
modelRegistry.registerProvider(name, config, sourceId);
|
|
907
|
+
}
|
|
908
|
+
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Resolve deferred --model pattern now that extension models are registered.
|
|
912
|
+
if (!model && options.modelPattern) {
|
|
913
|
+
const availableModels = modelRegistry.getAll();
|
|
914
|
+
const matchPreferences = {
|
|
915
|
+
usageOrder: settings.getStorage()?.getModelUsageOrder(),
|
|
916
|
+
};
|
|
917
|
+
const { model: resolved } = parseModelPattern(options.modelPattern, availableModels, matchPreferences);
|
|
918
|
+
if (resolved) {
|
|
919
|
+
model = resolved;
|
|
920
|
+
modelFallbackMessage = undefined;
|
|
921
|
+
} else {
|
|
922
|
+
modelFallbackMessage = `Model "${options.modelPattern}" not found`;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Fall back to first available model with a valid API key.
|
|
927
|
+
// Skip fallback if the user explicitly requested a model via --model that wasn't found.
|
|
928
|
+
if (!model && !options.modelPattern) {
|
|
929
|
+
const allModels = modelRegistry.getAll();
|
|
930
|
+
for (const candidate of allModels) {
|
|
931
|
+
if (await hasModelApiKey(candidate)) {
|
|
932
|
+
model = candidate;
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
if (model) {
|
|
937
|
+
if (modelFallbackMessage) {
|
|
938
|
+
modelFallbackMessage += `. Using ${model.provider}/${model.id}`;
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
modelFallbackMessage =
|
|
942
|
+
"No models available. Use /login or set an API key environment variable. Then use /model to select a model.";
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Discover custom commands (TypeScript slash commands)
|
|
947
|
+
const customCommandsResult: CustomCommandsLoadResult = options.disableExtensionDiscovery
|
|
948
|
+
? { commands: [], errors: [] }
|
|
949
|
+
: await loadCustomCommandsInternal({ cwd, agentDir });
|
|
950
|
+
time("discoverCustomCommands");
|
|
951
|
+
if (!options.disableExtensionDiscovery) {
|
|
952
|
+
for (const { path, error } of customCommandsResult.errors) {
|
|
953
|
+
logger.error("Failed to load custom command", { path, error });
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
let extensionRunner: ExtensionRunner | undefined;
|
|
958
|
+
if (extensionsResult.extensions.length > 0) {
|
|
959
|
+
extensionRunner = new ExtensionRunner(
|
|
960
|
+
extensionsResult.extensions,
|
|
961
|
+
extensionsResult.runtime,
|
|
962
|
+
cwd,
|
|
963
|
+
sessionManager,
|
|
964
|
+
modelRegistry,
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
const getSessionContext = () => ({
|
|
969
|
+
sessionManager,
|
|
970
|
+
modelRegistry,
|
|
971
|
+
model: agent.state.model,
|
|
972
|
+
isIdle: () => !session.isStreaming,
|
|
973
|
+
hasQueuedMessages: () => session.queuedMessageCount > 0,
|
|
974
|
+
abort: () => {
|
|
975
|
+
session.abort();
|
|
976
|
+
},
|
|
977
|
+
});
|
|
978
|
+
const toolContextStore = new ToolContextStore(getSessionContext);
|
|
979
|
+
|
|
980
|
+
const registeredTools = extensionRunner?.getAllRegisteredTools() ?? [];
|
|
981
|
+
let wrappedExtensionTools: AgentTool[];
|
|
982
|
+
|
|
983
|
+
if (extensionRunner) {
|
|
984
|
+
// With extension runner: convert CustomTools to ToolDefinitions and wrap all together
|
|
985
|
+
const allCustomTools = [
|
|
986
|
+
...registeredTools,
|
|
987
|
+
...(options.customTools?.map(tool => {
|
|
988
|
+
const definition = isCustomTool(tool) ? customToolToDefinition(tool) : tool;
|
|
989
|
+
return { definition, extensionPath: "<sdk>" };
|
|
990
|
+
}) ?? []),
|
|
991
|
+
];
|
|
992
|
+
wrappedExtensionTools = wrapRegisteredTools(allCustomTools, extensionRunner);
|
|
993
|
+
} else {
|
|
994
|
+
// Without extension runner: wrap CustomTools directly with CustomToolAdapter
|
|
995
|
+
// ToolDefinition items require ExtensionContext and cannot be used without a runner
|
|
996
|
+
const customToolContext = (): CustomToolContext => ({
|
|
997
|
+
sessionManager,
|
|
998
|
+
modelRegistry,
|
|
999
|
+
model: agent?.state.model,
|
|
1000
|
+
isIdle: () => !session?.isStreaming,
|
|
1001
|
+
hasQueuedMessages: () => (session?.queuedMessageCount ?? 0) > 0,
|
|
1002
|
+
abort: () => session?.abort(),
|
|
1003
|
+
});
|
|
1004
|
+
wrappedExtensionTools = (options.customTools ?? [])
|
|
1005
|
+
.filter(isCustomTool)
|
|
1006
|
+
.map(tool => CustomToolAdapter.wrap(tool, customToolContext) as AgentTool);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// All built-in tools are active (conditional tools like git/ask return null from factory if disabled)
|
|
1010
|
+
const toolRegistry = new Map<string, AgentTool>();
|
|
1011
|
+
for (const tool of builtinTools) {
|
|
1012
|
+
toolRegistry.set(tool.name, tool as AgentTool);
|
|
1013
|
+
}
|
|
1014
|
+
for (const tool of wrappedExtensionTools) {
|
|
1015
|
+
toolRegistry.set(tool.name, tool);
|
|
1016
|
+
}
|
|
1017
|
+
if (extensionRunner) {
|
|
1018
|
+
for (const tool of toolRegistry.values()) {
|
|
1019
|
+
toolRegistry.set(tool.name, new ExtensionToolWrapper(tool, extensionRunner));
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
if (model?.provider === "cursor") {
|
|
1023
|
+
toolRegistry.delete("edit");
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
let cursorEventEmitter: ((event: AgentEvent) => void) | undefined;
|
|
1027
|
+
const cursorExecHandlers = new CursorExecHandlers({
|
|
1028
|
+
cwd,
|
|
1029
|
+
tools: toolRegistry,
|
|
1030
|
+
getToolContext: () => toolContextStore.getContext(),
|
|
1031
|
+
emitEvent: event => cursorEventEmitter?.(event),
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
const repeatToolDescriptions = settings.get("repeatToolDescriptions");
|
|
1035
|
+
const rebuildSystemPrompt = async (toolNames: string[], tools: Map<string, AgentTool>): Promise<string> => {
|
|
1036
|
+
toolContextStore.setToolNames(toolNames);
|
|
1037
|
+
const memoryInstructions = await buildMemoryToolDeveloperInstructions(agentDir, settings);
|
|
1038
|
+
const defaultPrompt = await buildSystemPromptInternal({
|
|
1039
|
+
cwd,
|
|
1040
|
+
skills,
|
|
1041
|
+
preloadedSkills: options.preloadedSkills,
|
|
1042
|
+
contextFiles,
|
|
1043
|
+
tools,
|
|
1044
|
+
toolNames,
|
|
1045
|
+
rules: rulebookRules,
|
|
1046
|
+
skillsSettings: settings.getGroup("skills") as SkillsSettings,
|
|
1047
|
+
appendSystemPrompt: memoryInstructions,
|
|
1048
|
+
repeatToolDescriptions,
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
if (options.systemPrompt === undefined) {
|
|
1052
|
+
return defaultPrompt;
|
|
1053
|
+
}
|
|
1054
|
+
if (typeof options.systemPrompt === "string") {
|
|
1055
|
+
return await buildSystemPromptInternal({
|
|
1056
|
+
cwd,
|
|
1057
|
+
skills,
|
|
1058
|
+
preloadedSkills: options.preloadedSkills,
|
|
1059
|
+
contextFiles,
|
|
1060
|
+
tools,
|
|
1061
|
+
toolNames,
|
|
1062
|
+
rules: rulebookRules,
|
|
1063
|
+
skillsSettings: settings.getGroup("skills") as SkillsSettings,
|
|
1064
|
+
customPrompt: options.systemPrompt,
|
|
1065
|
+
appendSystemPrompt: memoryInstructions,
|
|
1066
|
+
repeatToolDescriptions,
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
return options.systemPrompt(defaultPrompt);
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
const toolNamesFromRegistry = Array.from(toolRegistry.keys());
|
|
1073
|
+
const requestedToolNames = options.toolNames ?? toolNamesFromRegistry;
|
|
1074
|
+
const normalizedRequested = requestedToolNames.filter(name => toolRegistry.has(name));
|
|
1075
|
+
const initialToolNames = normalizedRequested;
|
|
1076
|
+
|
|
1077
|
+
// Custom tools and extension-registered tools are always included regardless of toolNames filter
|
|
1078
|
+
const alwaysInclude: string[] = [
|
|
1079
|
+
...(options.customTools?.map(t => (isCustomTool(t) ? t.name : t.name)) ?? []),
|
|
1080
|
+
...registeredTools.map(t => t.definition.name),
|
|
1081
|
+
];
|
|
1082
|
+
for (const name of alwaysInclude) {
|
|
1083
|
+
if (toolRegistry.has(name) && !initialToolNames.includes(name)) {
|
|
1084
|
+
initialToolNames.push(name);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
const systemPrompt = await rebuildSystemPrompt(initialToolNames, toolRegistry);
|
|
1089
|
+
time("buildSystemPrompt");
|
|
1090
|
+
|
|
1091
|
+
const promptTemplates = options.promptTemplates ?? (await discoverPromptTemplates(cwd, agentDir));
|
|
1092
|
+
time("discoverPromptTemplates");
|
|
1093
|
+
toolSession.promptTemplates = promptTemplates;
|
|
1094
|
+
|
|
1095
|
+
const slashCommands = options.slashCommands ?? (await discoverSlashCommands(cwd));
|
|
1096
|
+
time("discoverSlashCommands");
|
|
1097
|
+
|
|
1098
|
+
// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
|
|
1099
|
+
const convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {
|
|
1100
|
+
const converted = convertToLlm(messages);
|
|
1101
|
+
// Check setting dynamically so mid-session changes take effect
|
|
1102
|
+
if (!settings.get("images.blockImages")) {
|
|
1103
|
+
return converted;
|
|
1104
|
+
}
|
|
1105
|
+
// Filter out ImageContent from all messages, replacing with text placeholder
|
|
1106
|
+
return converted.map(msg => {
|
|
1107
|
+
if (msg.role === "user" || msg.role === "toolResult") {
|
|
1108
|
+
const content = msg.content;
|
|
1109
|
+
if (Array.isArray(content)) {
|
|
1110
|
+
const hasImages = content.some(c => c.type === "image");
|
|
1111
|
+
if (hasImages) {
|
|
1112
|
+
const filteredContent = content
|
|
1113
|
+
.map(c => (c.type === "image" ? { type: "text" as const, text: "Image reading is disabled." } : c))
|
|
1114
|
+
.filter(
|
|
1115
|
+
(c, i, arr) =>
|
|
1116
|
+
// Dedupe consecutive "Image reading is disabled." texts
|
|
1117
|
+
!(
|
|
1118
|
+
c.type === "text" &&
|
|
1119
|
+
c.text === "Image reading is disabled." &&
|
|
1120
|
+
i > 0 &&
|
|
1121
|
+
arr[i - 1].type === "text" &&
|
|
1122
|
+
(arr[i - 1] as { type: "text"; text: string }).text === "Image reading is disabled."
|
|
1123
|
+
),
|
|
1124
|
+
);
|
|
1125
|
+
return { ...msg, content: filteredContent };
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return msg;
|
|
1130
|
+
});
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// Load and create secret obfuscator if secrets are enabled
|
|
1134
|
+
let obfuscator: SecretObfuscator | undefined;
|
|
1135
|
+
if (settings.get("secrets.enabled")) {
|
|
1136
|
+
const fileEntries = await loadSecrets(cwd, agentDir);
|
|
1137
|
+
time("loadSecrets");
|
|
1138
|
+
const envEntries = collectEnvSecrets();
|
|
1139
|
+
const allEntries = [...envEntries, ...fileEntries];
|
|
1140
|
+
if (allEntries.length > 0) {
|
|
1141
|
+
obfuscator = new SecretObfuscator(allEntries);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Final convertToLlm: chain block-images filter with secret obfuscation
|
|
1146
|
+
const convertToLlmFinal = (messages: AgentMessage[]): Message[] => {
|
|
1147
|
+
const converted = convertToLlmWithBlockImages(messages);
|
|
1148
|
+
if (!obfuscator?.hasSecrets()) return converted;
|
|
1149
|
+
return obfuscateMessages(obfuscator, converted);
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
const setToolUIContext = (uiContext: ExtensionUIContext, hasUI: boolean) => {
|
|
1153
|
+
toolContextStore.setUIContext(uiContext, hasUI);
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
const initialTools = initialToolNames
|
|
1157
|
+
.map(name => toolRegistry.get(name))
|
|
1158
|
+
.filter((tool): tool is AgentTool => tool !== undefined);
|
|
1159
|
+
|
|
1160
|
+
const openaiWebsocketSetting = settings.get("providers.openaiWebsockets") ?? "auto";
|
|
1161
|
+
const preferOpenAICodexWebsockets =
|
|
1162
|
+
openaiWebsocketSetting === "on" ? true : openaiWebsocketSetting === "off" ? false : undefined;
|
|
1163
|
+
|
|
1164
|
+
agent = new Agent({
|
|
1165
|
+
initialState: {
|
|
1166
|
+
systemPrompt,
|
|
1167
|
+
model,
|
|
1168
|
+
thinkingLevel,
|
|
1169
|
+
tools: initialTools,
|
|
1170
|
+
},
|
|
1171
|
+
convertToLlm: convertToLlmFinal,
|
|
1172
|
+
sessionId: sessionManager.getSessionId(),
|
|
1173
|
+
transformContext: extensionRunner
|
|
1174
|
+
? async messages => {
|
|
1175
|
+
return extensionRunner.emitContext(messages);
|
|
1176
|
+
}
|
|
1177
|
+
: undefined,
|
|
1178
|
+
steeringMode: settings.get("steeringMode") ?? "one-at-a-time",
|
|
1179
|
+
followUpMode: settings.get("followUpMode") ?? "one-at-a-time",
|
|
1180
|
+
interruptMode: settings.get("interruptMode") ?? "immediate",
|
|
1181
|
+
thinkingBudgets: settings.getGroup("thinkingBudgets"),
|
|
1182
|
+
temperature: settings.get("temperature") >= 0 ? settings.get("temperature") : undefined,
|
|
1183
|
+
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
1184
|
+
preferWebsockets: preferOpenAICodexWebsockets,
|
|
1185
|
+
getToolContext: tc => toolContextStore.getContext(tc),
|
|
1186
|
+
getApiKey: async provider => {
|
|
1187
|
+
// Use the provider argument from the in-flight request;
|
|
1188
|
+
// agent.state.model may already be switched mid-turn.
|
|
1189
|
+
const key = await modelRegistry.getApiKeyForProvider(provider, sessionId);
|
|
1190
|
+
if (!key) {
|
|
1191
|
+
throw new Error(`No API key found for provider "${provider}"`);
|
|
1192
|
+
}
|
|
1193
|
+
return key;
|
|
1194
|
+
},
|
|
1195
|
+
cursorExecHandlers,
|
|
1196
|
+
transformToolCallArguments: obfuscator?.hasSecrets() ? args => obfuscator!.deobfuscateObject(args) : undefined,
|
|
1197
|
+
intentTracing: settings.get("tools.intentTracing") || $env.ARCANE_INTENT_TRACING === "1",
|
|
1198
|
+
});
|
|
1199
|
+
cursorEventEmitter = event => agent.emitExternalEvent(event);
|
|
1200
|
+
|
|
1201
|
+
// Restore messages if session has existing data
|
|
1202
|
+
if (hasExistingSession) {
|
|
1203
|
+
agent.replaceMessages(existingSession.messages);
|
|
1204
|
+
if (!hasThinkingEntry) {
|
|
1205
|
+
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
1206
|
+
}
|
|
1207
|
+
} else {
|
|
1208
|
+
// Save initial model and thinking level for new sessions so they can be restored on resume
|
|
1209
|
+
if (model) {
|
|
1210
|
+
sessionManager.appendModelChange(`${model.provider}/${model.id}`);
|
|
1211
|
+
}
|
|
1212
|
+
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
session = new AgentSession({
|
|
1216
|
+
agent,
|
|
1217
|
+
sessionManager,
|
|
1218
|
+
settings,
|
|
1219
|
+
scopedModels: options.scopedModels,
|
|
1220
|
+
promptTemplates,
|
|
1221
|
+
slashCommands,
|
|
1222
|
+
extensionRunner,
|
|
1223
|
+
customCommands: customCommandsResult.commands,
|
|
1224
|
+
skills,
|
|
1225
|
+
skillWarnings,
|
|
1226
|
+
skillsSettings: settings.getGroup("skills") as Required<SkillsSettings>,
|
|
1227
|
+
modelRegistry,
|
|
1228
|
+
toolRegistry,
|
|
1229
|
+
rebuildSystemPrompt,
|
|
1230
|
+
ttsrManager,
|
|
1231
|
+
forceCopilotAgentInitiator,
|
|
1232
|
+
obfuscator,
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
if (model?.api === "openai-codex-responses") {
|
|
1236
|
+
try {
|
|
1237
|
+
await prewarmOpenAICodexResponses(model, {
|
|
1238
|
+
apiKey: await modelRegistry.getApiKey(model, sessionId),
|
|
1239
|
+
sessionId,
|
|
1240
|
+
preferWebsockets: preferOpenAICodexWebsockets,
|
|
1241
|
+
providerSessionState: session.providerSessionState,
|
|
1242
|
+
});
|
|
1243
|
+
time("prewarmCodexWebsocket");
|
|
1244
|
+
} catch (error) {
|
|
1245
|
+
logger.debug("Codex websocket prewarm failed", {
|
|
1246
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1247
|
+
provider: model.provider,
|
|
1248
|
+
model: model.id,
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// Warm up LSP servers (connects to detected servers)
|
|
1254
|
+
let lspServers: CreateAgentSessionResult["lspServers"];
|
|
1255
|
+
if (enableLsp && settings.get("lsp.diagnosticsOnWrite")) {
|
|
1256
|
+
try {
|
|
1257
|
+
const result = await warmupLspServers(cwd, {
|
|
1258
|
+
onConnecting: serverNames => {
|
|
1259
|
+
if (options.hasUI && serverNames.length > 0) {
|
|
1260
|
+
process.stderr.write(chalk.gray(`Starting LSP servers: ${serverNames.join(", ")}…\n`));
|
|
1261
|
+
}
|
|
1262
|
+
},
|
|
1263
|
+
});
|
|
1264
|
+
time("warmupLspServers");
|
|
1265
|
+
lspServers = result.servers;
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
logger.warn("LSP server warmup failed", { cwd, error: String(error) });
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
startMemoryStartupTask({
|
|
1272
|
+
session,
|
|
1273
|
+
settings,
|
|
1274
|
+
modelRegistry,
|
|
1275
|
+
agentDir,
|
|
1276
|
+
taskDepth,
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
return {
|
|
1280
|
+
session,
|
|
1281
|
+
extensionsResult,
|
|
1282
|
+
setToolUIContext,
|
|
1283
|
+
mcpManager,
|
|
1284
|
+
modelFallbackMessage,
|
|
1285
|
+
lspServers,
|
|
1286
|
+
};
|
|
1287
|
+
}
|