@oh-my-pi/pi-coding-agent 7.0.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/README.md +1 -1
- package/docs/hooks.md +2 -2
- package/docs/sdk.md +1 -1
- package/package.json +10 -10
- package/scripts/format-prompts.ts +143 -0
- package/scripts/generate-template.ts +1 -1
- package/src/cli/args.ts +3 -3
- package/src/cli/config-cli.ts +4 -4
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +2 -2
- package/src/cli/plugin-cli.ts +3 -3
- package/src/cli/session-picker.ts +2 -2
- package/src/cli/setup-cli.ts +2 -2
- package/src/cli/stats-cli.ts +1 -1
- package/src/cli/update-cli.ts +2 -2
- package/src/{core → config}/keybindings.ts +1 -1
- package/src/{core → config}/model-registry.ts +1 -1
- package/src/{core → config}/model-resolver.ts +3 -3
- package/src/{core → config}/prompt-templates.ts +2 -2
- package/src/{core → config}/settings-manager.ts +6 -6
- package/src/{core/cursor/exec-bridge.ts → cursor.ts} +4 -4
- package/src/discovery/agents-md.ts +4 -4
- package/src/discovery/builtin.ts +17 -17
- package/src/discovery/claude.ts +12 -12
- package/src/discovery/cline.ts +6 -6
- package/src/discovery/codex.ts +21 -21
- package/src/discovery/cursor.ts +9 -9
- package/src/discovery/gemini.ts +9 -9
- package/src/discovery/github.ts +6 -6
- package/src/discovery/helpers.ts +4 -4
- package/src/discovery/index.ts +16 -16
- package/src/discovery/mcp-json.ts +4 -4
- package/src/discovery/ssh.ts +4 -4
- package/src/discovery/vscode.ts +4 -4
- package/src/discovery/windsurf.ts +6 -6
- package/src/{core/tools/exa → exa}/company.ts +2 -3
- package/src/{core/tools/exa → exa}/index.ts +2 -2
- package/src/{core/tools/exa → exa}/linkedin.ts +2 -3
- package/src/{core/tools/exa → exa}/mcp-client.ts +2 -2
- package/src/{core/tools/exa → exa}/render.ts +3 -3
- package/src/{core/tools/exa → exa}/researcher.ts +1 -1
- package/src/{core/tools/exa → exa}/search.ts +2 -10
- package/src/{core/tools/exa → exa}/websets.ts +1 -1
- package/src/{core → exec}/bash-executor.ts +22 -6
- package/src/{core → export}/custom-share.ts +1 -1
- package/src/{core/export-html → export/html}/index.ts +3 -3
- package/src/{core → export}/ttsr.ts +2 -2
- package/src/{core → extensibility}/custom-commands/bundled/review/index.ts +4 -4
- package/src/{core → extensibility}/custom-commands/loader.ts +3 -3
- package/src/{core → extensibility}/custom-commands/types.ts +1 -1
- package/src/{core → extensibility}/custom-tools/loader.ts +9 -9
- package/src/{core → extensibility}/custom-tools/types.ts +6 -6
- package/src/{core → extensibility}/custom-tools/wrapper.ts +1 -1
- package/src/{core → extensibility}/extensions/loader.ts +8 -8
- package/src/{core → extensibility}/extensions/runner.ts +3 -3
- package/src/{core → extensibility}/extensions/types.ts +15 -15
- package/src/{core → extensibility}/extensions/wrapper.ts +1 -1
- package/src/{core → extensibility}/hooks/index.ts +1 -1
- package/src/{core → extensibility}/hooks/loader.ts +7 -7
- package/src/{core → extensibility}/hooks/runner.ts +4 -4
- package/src/{core → extensibility}/hooks/types.ts +9 -9
- package/src/{core → extensibility}/plugins/doctor.ts +1 -1
- package/src/{core → extensibility}/plugins/installer.ts +2 -3
- package/src/{core → extensibility}/plugins/paths.ts +1 -1
- package/src/{core → extensibility}/skills.ts +8 -48
- package/src/{core → extensibility}/slash-commands.ts +6 -6
- package/src/index.ts +127 -128
- package/src/internal-urls/agent-protocol.ts +126 -0
- package/src/internal-urls/artifact-protocol.ts +93 -0
- package/src/internal-urls/index.ts +28 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/router.ts +69 -0
- package/src/internal-urls/rule-protocol.ts +56 -0
- package/src/internal-urls/skill-protocol.ts +112 -0
- package/src/internal-urls/types.ts +48 -0
- package/src/{core/python-executor.ts → ipy/executor.ts} +51 -11
- package/src/{core/python-gateway-coordinator.ts → ipy/gateway-coordinator.ts} +41 -325
- package/src/{core/python-kernel.ts → ipy/kernel.ts} +38 -10
- package/src/ipy/prelude.ts +3 -0
- package/src/{core/tools/lsp → lsp}/client.ts +7 -6
- package/src/{core/tools/lsp → lsp}/clients/biome-client.ts +1 -1
- package/src/{core/tools/lsp → lsp}/clients/index.ts +1 -1
- package/src/{core/tools/lsp → lsp}/clients/lsp-linter-client.ts +4 -4
- package/src/{core/tools/lsp → lsp}/config.ts +1 -1
- package/src/{core/tools/lsp → lsp}/index.ts +16 -15
- package/src/{core/tools/lsp → lsp}/render.ts +2 -2
- package/src/{core/tools/lsp → lsp}/types.ts +14 -16
- package/src/{core/tools/lsp → lsp}/utils.ts +1 -1
- package/src/main.ts +12 -12
- package/src/{core/mcp → mcp}/config.ts +8 -8
- package/src/{core/mcp → mcp}/loader.ts +5 -6
- package/src/{core/mcp → mcp}/manager.ts +2 -2
- package/src/{core/mcp → mcp}/tool-bridge.ts +35 -6
- package/src/{core/mcp → mcp}/tool-cache.ts +1 -1
- package/src/{core/mcp → mcp}/transports/http.ts +7 -1
- package/src/{core/mcp → mcp}/transports/stdio.ts +1 -1
- package/src/{core/mcp → mcp}/types.ts +1 -1
- package/src/migrations.ts +2 -2
- package/src/modes/{interactive/components → components}/armin.ts +1 -1
- package/src/modes/{interactive/components → components}/assistant-message.ts +1 -1
- package/src/modes/{interactive/components → components}/bash-execution.ts +37 -29
- package/src/modes/{interactive/components → components}/bordered-loader.ts +1 -1
- package/src/modes/{interactive/components → components}/branch-summary-message.ts +2 -2
- package/src/modes/{interactive/components → components}/compaction-summary-message.ts +2 -2
- package/src/modes/{interactive/components → components}/custom-message.ts +3 -3
- package/src/modes/{interactive/components → components}/diff.ts +1 -1
- package/src/modes/{interactive/components → components}/dynamic-border.ts +1 -1
- package/src/modes/{interactive/components → components}/extensions/extension-dashboard.ts +3 -3
- package/src/modes/{interactive/components → components}/extensions/extension-list.ts +2 -2
- package/src/modes/{interactive/components → components}/extensions/inspector-panel.ts +1 -1
- package/src/modes/{interactive/components → components}/extensions/state-manager.ts +11 -17
- package/src/modes/{interactive/components → components}/extensions/types.ts +1 -1
- package/src/modes/{interactive/components → components}/footer.ts +3 -3
- package/src/modes/{interactive/components → components}/history-search.ts +2 -2
- package/src/modes/{interactive/components → components}/hook-editor.ts +1 -1
- package/src/modes/{interactive/components → components}/hook-input.ts +1 -1
- package/src/modes/{interactive/components → components}/hook-message.ts +3 -3
- package/src/modes/{interactive/components → components}/hook-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/keybinding-hints.ts +2 -2
- package/src/modes/{interactive/components → components}/login-dialog.ts +1 -1
- package/src/modes/{interactive/components → components}/model-selector.ts +5 -5
- package/src/modes/{interactive/components → components}/oauth-selector.ts +2 -2
- package/src/modes/{interactive/components → components}/plugin-settings.ts +3 -3
- package/src/modes/{interactive/components → components}/python-execution.ts +35 -24
- package/src/modes/{interactive/components → components}/queue-mode-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/read-tool-group.ts +2 -2
- package/src/modes/{interactive/components → components}/session-selector.ts +3 -3
- package/src/modes/{interactive/components → components}/settings-defs.ts +2 -2
- package/src/modes/{interactive/components → components}/settings-selector.ts +2 -2
- package/src/modes/{interactive/components → components}/show-images-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/status-line/segments.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line/separators.ts +1 -1
- package/src/modes/{interactive/components → components}/status-line/types.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line-segment-editor.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line.ts +3 -3
- package/src/modes/{interactive/components → components}/theme-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/thinking-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/todo-display.ts +3 -4
- package/src/modes/{interactive/components → components}/todo-reminder.ts +2 -2
- package/src/modes/{interactive/components → components}/tool-execution.ts +8 -8
- package/src/modes/{interactive/components → components}/tree-selector.ts +3 -3
- package/src/modes/{interactive/components → components}/ttsr-notification.ts +2 -2
- package/src/modes/{interactive/components → components}/user-message-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/user-message.ts +1 -1
- package/src/modes/{interactive/components → components}/welcome.ts +2 -2
- package/src/modes/{interactive/controllers → controllers}/command-controller.ts +32 -30
- package/src/modes/{interactive/controllers → controllers}/event-controller.ts +9 -9
- package/src/modes/{interactive/controllers → controllers}/extension-ui-controller.ts +8 -8
- package/src/modes/{interactive/controllers → controllers}/input-controller.ts +6 -6
- package/src/modes/{interactive/controllers → controllers}/selector-controller.ts +16 -16
- package/src/modes/index.ts +1 -1
- package/src/modes/{interactive/interactive-mode.ts → interactive-mode.ts} +14 -14
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +3 -3
- package/src/modes/rpc/rpc-mode.ts +3 -3
- package/src/modes/rpc/rpc-types.ts +3 -3
- package/src/modes/{interactive/theme → theme}/theme.ts +1 -1
- package/src/modes/{interactive/types.ts → types.ts} +8 -9
- package/src/modes/{interactive/utils → utils}/ui-helpers.ts +20 -27
- package/src/{core/tools/patch → patch}/applicator.ts +1 -1
- package/src/{core/tools/patch → patch}/diff.ts +1 -1
- package/src/{core/tools/patch → patch}/index.ts +31 -36
- package/src/{core/tools/patch → patch}/shared.ts +9 -6
- package/src/prompts/agents/explore.md +83 -46
- package/src/prompts/agents/init.md +9 -4
- package/src/prompts/agents/plan.md +8 -7
- package/src/prompts/agents/reviewer.md +36 -18
- package/src/prompts/agents/task.md +4 -4
- package/src/prompts/compaction/branch-summary-preamble.md +0 -1
- package/src/prompts/review-request.md +0 -1
- package/src/prompts/system/custom-system-prompt.md +2 -14
- package/src/prompts/system/file-operations.md +0 -2
- package/src/prompts/system/system-prompt.md +147 -138
- package/src/prompts/system/web-search.md +26 -0
- package/src/prompts/tools/ask.md +31 -24
- package/src/prompts/tools/bash.md +20 -17
- package/src/prompts/tools/calculator.md +9 -5
- package/src/prompts/tools/fetch.md +16 -0
- package/src/prompts/tools/find.md +15 -5
- package/src/prompts/tools/gemini-image.md +21 -6
- package/src/prompts/tools/grep.md +28 -12
- package/src/prompts/tools/lsp.md +35 -14
- package/src/prompts/tools/patch.md +39 -41
- package/src/prompts/tools/python.md +59 -76
- package/src/prompts/tools/read.md +23 -22
- package/src/prompts/tools/replace.md +19 -12
- package/src/prompts/tools/ssh.md +21 -28
- package/src/prompts/tools/task.md +54 -44
- package/src/prompts/tools/todo-write.md +52 -163
- package/src/prompts/tools/web-search.md +16 -9
- package/src/prompts/tools/write.md +13 -2
- package/src/{core/sdk.ts → sdk.ts} +65 -34
- package/src/{core → session}/agent-session.ts +45 -37
- package/src/{core → session}/agent-storage.ts +2 -2
- package/src/session/artifacts.ts +110 -0
- package/src/{core → session}/auth-storage.ts +1 -1
- package/src/{core → session}/compaction/branch-summarization.ts +5 -5
- package/src/{core → session}/compaction/compaction.ts +6 -6
- package/src/{core → session}/compaction/utils.ts +3 -3
- package/src/{core → session}/history-storage.ts +1 -1
- package/src/{core → session}/messages.ts +6 -8
- package/src/{core → session}/session-manager.ts +2 -2
- package/src/{core → session}/storage-migration.ts +2 -2
- package/src/session/streaming-output.ts +177 -0
- package/src/{core/ssh → ssh}/connection-manager.ts +1 -1
- package/src/{core/ssh → ssh}/ssh-executor.ts +19 -4
- package/src/{core/ssh → ssh}/sshfs-mount.ts +1 -1
- package/src/{core/system-prompt.ts → system-prompt.ts} +8 -37
- package/src/{core/tools/task → task}/agents.ts +8 -8
- package/src/{core/tools/task → task}/commands.ts +5 -6
- package/src/{core/tools/task → task}/discovery.ts +3 -3
- package/src/{core/tools/task → task}/executor.ts +34 -44
- package/src/{core/tools/task → task}/index.ts +206 -50
- package/src/{core/tools/task → task}/render.ts +80 -23
- package/src/{core/tools/task → task}/subprocess-tool-registry.ts +1 -1
- package/src/task/template.ts +47 -0
- package/src/{core/tools/task → task}/types.ts +19 -27
- package/src/{core/tools/task → task}/worker-protocol.ts +8 -4
- package/src/{core/tools/task → task}/worker.ts +34 -29
- package/src/task/worktree.ts +166 -0
- package/src/{core/tools → tools}/ask.ts +13 -21
- package/src/{core/tools → tools}/bash-interceptor.ts +1 -1
- package/src/{core/tools → tools}/bash.ts +61 -63
- package/src/{core/tools → tools}/calculator.ts +4 -4
- package/src/{core/tools → tools}/complete.ts +1 -1
- package/src/{core/tools → tools}/context.ts +2 -2
- package/src/{core/tools/web-fetch.ts → tools/fetch.ts} +97 -76
- package/src/{core/tools → tools}/find.ts +80 -104
- package/src/{core/tools → tools}/gemini-image.ts +420 -29
- package/src/{core/tools → tools}/grep.ts +155 -164
- package/src/{core/tools → tools}/index.ts +63 -56
- package/src/tools/list-limit.ts +40 -0
- package/src/{core/tools → tools}/ls.ts +44 -35
- package/src/{core/tools → tools}/notebook.ts +3 -3
- package/src/tools/output-meta.ts +443 -0
- package/src/tools/output-utils.ts +63 -0
- package/src/{core/tools → tools}/python.ts +105 -89
- package/src/tools/read.ts +882 -0
- package/src/{core/tools → tools}/render-utils.ts +1 -1
- package/src/{core/tools → tools}/renderers.ts +8 -10
- package/src/{core/tools → tools}/review.ts +2 -2
- package/src/{core/tools → tools}/ssh.ts +56 -59
- package/src/{core/tools → tools}/todo-write.ts +12 -23
- package/src/tools/tool-errors.ts +95 -0
- package/src/tools/tool-result.ts +92 -0
- package/src/{core/tools → tools}/truncate.ts +2 -2
- package/src/{core/tools → tools}/write.ts +15 -13
- package/src/utils/changelog.ts +1 -1
- package/src/{core → utils}/file-mentions.ts +4 -4
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/shell.ts +1 -1
- package/src/{core → utils}/title-generator.ts +4 -4
- package/src/utils/tools-manager.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/choosealicense.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/twitter.ts +3 -2
- package/src/{core/tools/web-scrapers → web/scrapers}/types.ts +4 -2
- package/src/{core/tools/web-scrapers → web/scrapers}/utils.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/youtube.ts +14 -13
- package/src/{core/tools/web-search → web/search}/auth.ts +4 -4
- package/src/{core/tools/web-search → web/search}/index.ts +22 -71
- package/src/{core/tools/web-search → web/search}/providers/anthropic.ts +7 -10
- package/src/{core/tools/web-search → web/search}/providers/exa.ts +2 -2
- package/src/{core/tools/web-search → web/search}/providers/perplexity.ts +4 -16
- package/src/{core/tools/web-search → web/search}/render.ts +3 -3
- package/scripts/migrate-sessions.sh +0 -93
- package/src/core/index.ts +0 -56
- package/src/core/python-prelude.ts +0 -3
- package/src/core/ssh-executor.ts +0 -5
- package/src/core/streaming-output.ts +0 -115
- package/src/core/tools/output.ts +0 -519
- package/src/core/tools/read.ts +0 -717
- package/src/core/tools/task/template.ts +0 -37
- package/src/prompts/tools/output.md +0 -47
- package/src/prompts/tools/web-fetch.md +0 -9
- /package/src/{core/tools/exa → exa}/types.ts +0 -0
- /package/src/{core → exec}/exec.ts +0 -0
- /package/src/{core/export-html → export/html}/template.css +0 -0
- /package/src/{core/export-html → export/html}/template.generated.ts +0 -0
- /package/src/{core/export-html → export/html}/template.html +0 -0
- /package/src/{core/export-html → export/html}/template.js +0 -0
- /package/src/{core/export-html → export/html}/template.macro.ts +0 -0
- /package/src/{core/export-html → export/html}/vendor/highlight.min.js +0 -0
- /package/src/{core/export-html → export/html}/vendor/marked.min.js +0 -0
- /package/src/{core → extensibility}/custom-commands/index.ts +0 -0
- /package/src/{core → extensibility}/custom-tools/index.ts +0 -0
- /package/src/{core → extensibility}/extensions/index.ts +0 -0
- /package/src/{core → extensibility}/hooks/tool-wrapper.ts +0 -0
- /package/src/{core → extensibility}/plugins/index.ts +0 -0
- /package/src/{core → extensibility}/plugins/loader.ts +0 -0
- /package/src/{core → extensibility}/plugins/manager.ts +0 -0
- /package/src/{core → extensibility}/plugins/parser.ts +0 -0
- /package/src/{core → extensibility}/plugins/types.ts +0 -0
- /package/src/{core/python-modules.ts → ipy/modules.ts} +0 -0
- /package/src/{core/python-prelude.py → ipy/prelude.py} +0 -0
- /package/src/{core/tools/lsp → lsp}/defaults.json +0 -0
- /package/src/{core/tools/lsp → lsp}/edits.ts +0 -0
- /package/src/{core/tools/lsp → lsp}/lspmux.ts +0 -0
- /package/src/{core/tools/lsp → lsp}/rust-analyzer.ts +0 -0
- /package/src/{core/mcp → mcp}/client.ts +0 -0
- /package/src/{core/mcp → mcp}/index.ts +0 -0
- /package/src/{core/mcp → mcp}/json-rpc.ts +0 -0
- /package/src/{core/mcp → mcp}/transports/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/countdown-timer.ts +0 -0
- /package/src/modes/{interactive/components → components}/custom-editor.ts +0 -0
- /package/src/modes/{interactive/components → components}/extensions/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/status-line/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/status-line/presets.ts +0 -0
- /package/src/modes/{interactive/components → components}/visual-truncate.ts +0 -0
- /package/src/modes/{interactive/theme → theme}/dark.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/alabaster.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/amethyst.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/anthracite.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/basalt.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/birch.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-abyss.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-arctic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-aurora.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-catppuccin.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cavern.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-copper.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cosmos.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cyberpunk.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-dracula.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-eclipse.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-ember.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-equinox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-forest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-github.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-gruvbox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-lavender.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-lunar.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-midnight.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-monochrome.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-monokai.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-nebula.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-nord.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-ocean.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-one.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-rainforest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-reef.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-retro.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-rose-pine.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-sakura.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-slate.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-solarized.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-solstice.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-starfall.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-sunset.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-swamp.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-synthwave.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-taiga.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-terminal.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-tokyo-night.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-tundra.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-twilight.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-volcanic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/graphite.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/index.ts +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-arctic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-aurora-day.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-canyon.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-catppuccin.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-cirrus.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-coral.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-cyberpunk.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-dawn.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-dunes.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-eucalyptus.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-forest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-frost.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-github.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-glacier.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-gruvbox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-haze.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-honeycomb.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-lagoon.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-lavender.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-meadow.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-mint.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-monochrome.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-ocean.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-one.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-opal.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-orchard.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-paper.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-prism.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-retro.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-sand.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-savanna.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-solarized.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-soleil.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-sunset.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-synthwave.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-tokyo-night.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-wetland.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-zenith.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/limestone.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/mahogany.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/marble.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/obsidian.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/onyx.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/pearl.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/porcelain.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/quartz.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/sandstone.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/titanium.json +0 -0
- /package/src/modes/{interactive/theme → theme}/light.json +0 -0
- /package/src/modes/{interactive/theme → theme}/theme-schema.json +0 -0
- /package/src/{core/tools/patch → patch}/fuzzy.ts +0 -0
- /package/src/{core/tools/patch → patch}/normalize.ts +0 -0
- /package/src/{core/tools/patch → patch}/normative.ts +0 -0
- /package/src/{core/tools/patch → patch}/parser.ts +0 -0
- /package/src/{core/tools/patch → patch}/types.ts +0 -0
- /package/src/{core → session}/compaction/index.ts +0 -0
- /package/src/{core → session}/session-storage.ts +0 -0
- /package/src/{core/tools/task → task}/name-generator.ts +0 -0
- /package/src/{core/tools/task → task}/omp-command.ts +0 -0
- /package/src/{core/tools/task → task}/parallel.ts +0 -0
- /package/src/{core/tools → tools}/jtd-to-json-schema.ts +0 -0
- /package/src/{core/tools → tools}/path-utils.ts +0 -0
- /package/src/{core → utils}/event-bus.ts +0 -0
- /package/src/{core → utils}/frontmatter.ts +0 -0
- /package/src/{core → utils}/terminal-notify.ts +0 -0
- /package/src/{core → utils}/timings.ts +0 -0
- /package/src/{core → utils}/utils.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/artifacthub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/arxiv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/aur.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/biorxiv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/bluesky.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/brew.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/cheatsh.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/chocolatey.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/cisa-kev.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/clojars.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/coingecko.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/crates-io.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/crossref.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/devto.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/discogs.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/discourse.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/dockerhub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/fdroid.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/firefox-addons.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/flathub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/github-gist.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/github.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/gitlab.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/go-pkg.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hackage.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hackernews.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hex.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/huggingface.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/iacr.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/index.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/jetbrains-marketplace.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/lemmy.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/lobsters.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/mastodon.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/maven.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/mdn.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/metacpan.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/musicbrainz.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/npm.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/nuget.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/nvd.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/ollama.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/open-vsx.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/opencorporates.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/openlibrary.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/orcid.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/osv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/packagist.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pub-dev.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pubmed.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pypi.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rawg.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/readthedocs.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/reddit.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/repology.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rfc.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rubygems.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/searchcode.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/sec-edgar.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/semantic-scholar.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/snapcraft.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/sourcegraph.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/spdx.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/spotify.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/stackoverflow.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/terraform.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/tldr.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/vimeo.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/vscode-marketplace.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/w3c.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/wikidata.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/wikipedia.ts +0 -0
- /package/src/{core/tools/web-search → web/search}/types.ts +0 -0
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
existsSync,
|
|
4
4
|
mkdirSync,
|
|
5
5
|
openSync,
|
|
6
|
-
readdirSync,
|
|
7
6
|
readFileSync,
|
|
8
7
|
renameSync,
|
|
9
8
|
statSync,
|
|
@@ -13,18 +12,16 @@ import {
|
|
|
13
12
|
} from "node:fs";
|
|
14
13
|
import { createServer } from "node:net";
|
|
15
14
|
import { delimiter, join } from "node:path";
|
|
16
|
-
import { logger
|
|
15
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
17
16
|
import type { Subprocess } from "bun";
|
|
18
|
-
import { getAgentDir } from "
|
|
19
|
-
import { getShellConfig, killProcessTree } from "
|
|
20
|
-
import { getOrCreateSnapshot } from "
|
|
17
|
+
import { getAgentDir } from "$c/config";
|
|
18
|
+
import { getShellConfig, killProcessTree } from "$c/utils/shell";
|
|
19
|
+
import { getOrCreateSnapshot } from "$c/utils/shell-snapshot";
|
|
21
20
|
|
|
22
21
|
const GATEWAY_DIR_NAME = "python-gateway";
|
|
23
22
|
const GATEWAY_INFO_FILE = "gateway.json";
|
|
24
23
|
const GATEWAY_LOCK_FILE = "gateway.lock";
|
|
25
|
-
const GATEWAY_CLIENT_PREFIX = "client-";
|
|
26
24
|
const GATEWAY_STARTUP_TIMEOUT_MS = 30000;
|
|
27
|
-
const GATEWAY_IDLE_TIMEOUT_MS = 30000;
|
|
28
25
|
const GATEWAY_LOCK_TIMEOUT_MS = GATEWAY_STARTUP_TIMEOUT_MS + 5000;
|
|
29
26
|
const GATEWAY_LOCK_RETRY_MS = 50;
|
|
30
27
|
const GATEWAY_LOCK_STALE_MS = GATEWAY_STARTUP_TIMEOUT_MS * 2;
|
|
@@ -140,8 +137,6 @@ export interface GatewayInfo {
|
|
|
140
137
|
url: string;
|
|
141
138
|
pid: number;
|
|
142
139
|
startedAt: number;
|
|
143
|
-
refCount: number;
|
|
144
|
-
cwd: string;
|
|
145
140
|
pythonPath?: string;
|
|
146
141
|
venvPath?: string | null;
|
|
147
142
|
}
|
|
@@ -158,61 +153,7 @@ interface AcquireResult {
|
|
|
158
153
|
|
|
159
154
|
let localGatewayProcess: Subprocess | null = null;
|
|
160
155
|
let localGatewayUrl: string | null = null;
|
|
161
|
-
let idleShutdownTimer: ReturnType<typeof setTimeout> | null = null;
|
|
162
156
|
let isCoordinatorInitialized = false;
|
|
163
|
-
let localClientFile: string | null = null;
|
|
164
|
-
let postmortemRegistered = false;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Register cleanup handler for process exit. Called lazily on first gateway acquisition.
|
|
168
|
-
* Ensures the gateway process we spawned is killed when omp exits, preventing orphaned processes.
|
|
169
|
-
*/
|
|
170
|
-
function ensurePostmortemCleanup(): void {
|
|
171
|
-
if (postmortemRegistered) return;
|
|
172
|
-
postmortemRegistered = true;
|
|
173
|
-
|
|
174
|
-
postmortem.register("shared-gateway", async () => {
|
|
175
|
-
cancelIdleShutdown();
|
|
176
|
-
|
|
177
|
-
// Clean up our client file first so refcount is accurate
|
|
178
|
-
if (localClientFile) {
|
|
179
|
-
try {
|
|
180
|
-
unlinkSync(localClientFile);
|
|
181
|
-
} catch {
|
|
182
|
-
// Ignore cleanup errors
|
|
183
|
-
}
|
|
184
|
-
localClientFile = null;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// If we spawned the gateway, kill it only if no other clients remain
|
|
188
|
-
if (localGatewayProcess) {
|
|
189
|
-
const clients = pruneStaleClientInfos(listClientInfos());
|
|
190
|
-
const remainingRefs = clients.reduce((sum, c) => sum + c.info.refCount, 0);
|
|
191
|
-
|
|
192
|
-
if (remainingRefs === 0) {
|
|
193
|
-
logger.debug("Cleaning up shared gateway on process exit", { pid: localGatewayProcess.pid });
|
|
194
|
-
try {
|
|
195
|
-
await killProcessTree(localGatewayProcess.pid);
|
|
196
|
-
} catch (err) {
|
|
197
|
-
logger.warn("Failed to kill shared gateway on exit", {
|
|
198
|
-
error: err instanceof Error ? err.message : String(err),
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
clearGatewayInfo();
|
|
202
|
-
} else {
|
|
203
|
-
logger.debug("Leaving shared gateway running for other clients", {
|
|
204
|
-
pid: localGatewayProcess.pid,
|
|
205
|
-
remainingRefs,
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
localGatewayProcess = null;
|
|
210
|
-
localGatewayUrl = null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
isCoordinatorInitialized = false;
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
157
|
|
|
217
158
|
function filterEnv(env: Record<string, string | undefined>): Record<string, string | undefined> {
|
|
218
159
|
const filtered: Record<string, string | undefined> = {};
|
|
@@ -398,6 +339,7 @@ async function withGatewayLock<T>(handler: () => Promise<T>): Promise<T> {
|
|
|
398
339
|
function readGatewayInfo(): GatewayInfo | null {
|
|
399
340
|
const infoPath = getGatewayInfoPath();
|
|
400
341
|
if (!existsSync(infoPath)) return null;
|
|
342
|
+
|
|
401
343
|
try {
|
|
402
344
|
const content = readFileSync(infoPath, "utf-8");
|
|
403
345
|
const parsed = JSON.parse(content) as Partial<GatewayInfo>;
|
|
@@ -405,16 +347,10 @@ function readGatewayInfo(): GatewayInfo | null {
|
|
|
405
347
|
if (typeof parsed.url !== "string" || typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number") {
|
|
406
348
|
return null;
|
|
407
349
|
}
|
|
408
|
-
if (typeof parsed.cwd !== "string") return null;
|
|
409
|
-
const clients = pruneStaleClientInfos(listClientInfos());
|
|
410
|
-
const totalRefCount = clients.reduce((sum, client) => sum + client.info.refCount, 0);
|
|
411
|
-
const recoveredRefCount = clients.length > 0 ? totalRefCount : 0;
|
|
412
350
|
return {
|
|
413
351
|
url: parsed.url,
|
|
414
352
|
pid: parsed.pid,
|
|
415
353
|
startedAt: parsed.startedAt,
|
|
416
|
-
refCount: recoveredRefCount,
|
|
417
|
-
cwd: parsed.cwd,
|
|
418
354
|
pythonPath: typeof parsed.pythonPath === "string" ? parsed.pythonPath : undefined,
|
|
419
355
|
venvPath: typeof parsed.venvPath === "string" || parsed.venvPath === null ? parsed.venvPath : undefined,
|
|
420
356
|
};
|
|
@@ -450,103 +386,6 @@ function isPidRunning(pid: number): boolean {
|
|
|
450
386
|
}
|
|
451
387
|
}
|
|
452
388
|
|
|
453
|
-
interface GatewayClientInfo {
|
|
454
|
-
pid: number;
|
|
455
|
-
refCount: number;
|
|
456
|
-
updatedAt?: number;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function getClientFilePath(pid: number): string {
|
|
460
|
-
return join(getGatewayDir(), `${GATEWAY_CLIENT_PREFIX}${pid}.json`);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function readClientInfo(path: string): GatewayClientInfo | null {
|
|
464
|
-
try {
|
|
465
|
-
const raw = readFileSync(path, "utf-8");
|
|
466
|
-
const parsed = JSON.parse(raw) as GatewayClientInfo;
|
|
467
|
-
if (typeof parsed.pid !== "number" || typeof parsed.refCount !== "number") return null;
|
|
468
|
-
return parsed;
|
|
469
|
-
} catch {
|
|
470
|
-
return null;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function listClientInfos(): Array<{ path: string; info: GatewayClientInfo }> {
|
|
475
|
-
const dir = getGatewayDir();
|
|
476
|
-
if (!existsSync(dir)) return [];
|
|
477
|
-
const entries = readdirSync(dir);
|
|
478
|
-
const results: Array<{ path: string; info: GatewayClientInfo }> = [];
|
|
479
|
-
for (const entry of entries) {
|
|
480
|
-
if (!entry.startsWith(GATEWAY_CLIENT_PREFIX)) continue;
|
|
481
|
-
const path = join(dir, entry);
|
|
482
|
-
const info = readClientInfo(path);
|
|
483
|
-
if (!info) continue;
|
|
484
|
-
results.push({ path, info });
|
|
485
|
-
}
|
|
486
|
-
return results;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function pruneStaleClientInfos(
|
|
490
|
-
clients: Array<{ path: string; info: GatewayClientInfo }>,
|
|
491
|
-
): Array<{ path: string; info: GatewayClientInfo }> {
|
|
492
|
-
const active: Array<{ path: string; info: GatewayClientInfo }> = [];
|
|
493
|
-
for (const client of clients) {
|
|
494
|
-
if (!isPidRunning(client.info.pid)) {
|
|
495
|
-
try {
|
|
496
|
-
unlinkSync(client.path);
|
|
497
|
-
} catch {
|
|
498
|
-
// Ignore cleanup errors
|
|
499
|
-
}
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
active.push(client);
|
|
503
|
-
}
|
|
504
|
-
return active;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function updateLocalClientRefCount(delta: number): { totalRefCount: number; localRefCount: number } {
|
|
508
|
-
ensureGatewayDir();
|
|
509
|
-
const clients = pruneStaleClientInfos(listClientInfos());
|
|
510
|
-
const localPath = localClientFile ?? getClientFilePath(process.pid);
|
|
511
|
-
const localEntry = clients.find((client) => client.info.pid === process.pid);
|
|
512
|
-
const baseCount = localEntry?.info.refCount ?? 0;
|
|
513
|
-
const nextCount = Math.max(0, baseCount + delta);
|
|
514
|
-
const otherClients = clients.filter((client) => client.info.pid !== process.pid);
|
|
515
|
-
|
|
516
|
-
if (nextCount <= 0) {
|
|
517
|
-
if (localEntry) {
|
|
518
|
-
try {
|
|
519
|
-
unlinkSync(localEntry.path);
|
|
520
|
-
} catch {
|
|
521
|
-
// Ignore cleanup errors
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (localClientFile === localPath) {
|
|
525
|
-
localClientFile = null;
|
|
526
|
-
}
|
|
527
|
-
} else {
|
|
528
|
-
const payload: GatewayClientInfo = { pid: process.pid, refCount: nextCount, updatedAt: Date.now() };
|
|
529
|
-
writeFileSync(localPath, JSON.stringify(payload, null, 2));
|
|
530
|
-
localClientFile = localPath;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const totalRefCount =
|
|
534
|
-
otherClients.reduce((sum, client) => sum + client.info.refCount, 0) + (nextCount > 0 ? nextCount : 0);
|
|
535
|
-
return { totalRefCount, localRefCount: nextCount };
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
function clearClientFiles(): void {
|
|
539
|
-
const clients = listClientInfos();
|
|
540
|
-
for (const client of clients) {
|
|
541
|
-
try {
|
|
542
|
-
unlinkSync(client.path);
|
|
543
|
-
} catch {
|
|
544
|
-
// Ignore cleanup errors
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
localClientFile = null;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
389
|
async function isGatewayHealthy(url: string): Promise<boolean> {
|
|
551
390
|
try {
|
|
552
391
|
const controller = new AbortController();
|
|
@@ -585,11 +424,6 @@ async function startGatewayProcess(
|
|
|
585
424
|
OMP_SHELL_SNAPSHOT: snapshotPath ?? undefined,
|
|
586
425
|
};
|
|
587
426
|
|
|
588
|
-
const pythonPathParts = [cwd, kernelEnv.PYTHONPATH].filter(Boolean).join(delimiter);
|
|
589
|
-
if (pythonPathParts) {
|
|
590
|
-
kernelEnv.PYTHONPATH = pythonPathParts;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
427
|
const gatewayPort = await allocatePort();
|
|
594
428
|
const gatewayUrl = `http://127.0.0.1:${gatewayPort}`;
|
|
595
429
|
|
|
@@ -622,7 +456,6 @@ async function startGatewayProcess(
|
|
|
622
456
|
exited = true;
|
|
623
457
|
});
|
|
624
458
|
|
|
625
|
-
// Wait for gateway to become healthy
|
|
626
459
|
const startTime = Date.now();
|
|
627
460
|
while (Date.now() - startTime < GATEWAY_STARTUP_TIMEOUT_MS) {
|
|
628
461
|
if (exited) {
|
|
@@ -645,70 +478,15 @@ async function startGatewayProcess(
|
|
|
645
478
|
throw new Error("Gateway startup timeout");
|
|
646
479
|
}
|
|
647
480
|
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
clearClientFiles();
|
|
658
|
-
return;
|
|
659
|
-
}
|
|
660
|
-
const clients = pruneStaleClientInfos(listClientInfos());
|
|
661
|
-
const totalRefCount = clients.reduce((sum, client) => sum + client.info.refCount, 0);
|
|
662
|
-
if (totalRefCount > 0) {
|
|
663
|
-
if (info.refCount !== totalRefCount) {
|
|
664
|
-
writeGatewayInfo({ ...info, refCount: totalRefCount });
|
|
665
|
-
}
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
logger.debug("Shutting down idle shared gateway", { pid: info.pid });
|
|
669
|
-
if (localGatewayProcess) {
|
|
670
|
-
await shutdownLocalGateway();
|
|
671
|
-
} else if (isPidRunning(info.pid)) {
|
|
672
|
-
try {
|
|
673
|
-
await killProcessTree(info.pid);
|
|
674
|
-
} catch (err) {
|
|
675
|
-
logger.warn("Failed to kill idle shared gateway", {
|
|
676
|
-
error: err instanceof Error ? err.message : String(err),
|
|
677
|
-
pid: info.pid,
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
clearGatewayInfo();
|
|
682
|
-
clearClientFiles();
|
|
683
|
-
});
|
|
684
|
-
} catch (err) {
|
|
685
|
-
logger.warn("Failed to shutdown idle shared gateway", {
|
|
686
|
-
error: err instanceof Error ? err.message : String(err),
|
|
687
|
-
});
|
|
688
|
-
} finally {
|
|
689
|
-
idleShutdownTimer = null;
|
|
690
|
-
}
|
|
691
|
-
}, GATEWAY_IDLE_TIMEOUT_MS);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
function cancelIdleShutdown(): void {
|
|
695
|
-
if (idleShutdownTimer) {
|
|
696
|
-
clearTimeout(idleShutdownTimer);
|
|
697
|
-
idleShutdownTimer = null;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
async function shutdownLocalGateway(): Promise<void> {
|
|
702
|
-
if (localGatewayProcess) {
|
|
703
|
-
try {
|
|
704
|
-
await killProcessTree(localGatewayProcess.pid);
|
|
705
|
-
} catch (err) {
|
|
706
|
-
logger.warn("Failed to kill shared gateway process", {
|
|
707
|
-
error: err instanceof Error ? err.message : String(err),
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
localGatewayProcess = null;
|
|
711
|
-
localGatewayUrl = null;
|
|
481
|
+
async function killGateway(pid: number, context: string): Promise<void> {
|
|
482
|
+
try {
|
|
483
|
+
await killProcessTree(pid);
|
|
484
|
+
} catch (err) {
|
|
485
|
+
logger.warn("Failed to kill shared gateway process", {
|
|
486
|
+
error: err instanceof Error ? err.message : String(err),
|
|
487
|
+
pid,
|
|
488
|
+
context,
|
|
489
|
+
});
|
|
712
490
|
}
|
|
713
491
|
}
|
|
714
492
|
|
|
@@ -717,72 +495,35 @@ export async function acquireSharedGateway(cwd: string): Promise<AcquireResult |
|
|
|
717
495
|
return null;
|
|
718
496
|
}
|
|
719
497
|
|
|
720
|
-
ensurePostmortemCleanup();
|
|
721
|
-
|
|
722
498
|
try {
|
|
723
499
|
return await withGatewayLock(async () => {
|
|
724
500
|
const existingInfo = readGatewayInfo();
|
|
725
|
-
if (existingInfo
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
existingInfo.cwd !== cwd ||
|
|
733
|
-
!existingInfo.pythonPath ||
|
|
734
|
-
existingInfo.pythonPath !== runtime.pythonPath ||
|
|
735
|
-
existingVenv !== runtimeVenv
|
|
736
|
-
) {
|
|
737
|
-
logger.debug("Shared gateway metadata mismatch", {
|
|
738
|
-
existingCwd: existingInfo.cwd,
|
|
739
|
-
requestedCwd: cwd,
|
|
740
|
-
existingPython: existingInfo.pythonPath,
|
|
741
|
-
runtimePython: runtime.pythonPath,
|
|
742
|
-
existingVenv,
|
|
743
|
-
runtimeVenv,
|
|
744
|
-
});
|
|
745
|
-
return null;
|
|
501
|
+
if (existingInfo) {
|
|
502
|
+
if (await isGatewayAlive(existingInfo)) {
|
|
503
|
+
localGatewayUrl = existingInfo.url;
|
|
504
|
+
isCoordinatorInitialized = true;
|
|
505
|
+
logger.debug("Reusing global Python gateway", { url: existingInfo.url });
|
|
506
|
+
return { url: existingInfo.url, isShared: true };
|
|
746
507
|
}
|
|
747
|
-
const { totalRefCount } = updateLocalClientRefCount(1);
|
|
748
|
-
const updatedInfo = { ...existingInfo, refCount: totalRefCount };
|
|
749
|
-
writeGatewayInfo(updatedInfo);
|
|
750
|
-
cancelIdleShutdown();
|
|
751
|
-
logger.debug("Reusing shared gateway", { url: existingInfo.url, refCount: updatedInfo.refCount });
|
|
752
|
-
isCoordinatorInitialized = true;
|
|
753
|
-
return { url: existingInfo.url, isShared: true };
|
|
754
|
-
}
|
|
755
508
|
|
|
756
|
-
if (existingInfo) {
|
|
757
509
|
logger.debug("Cleaning up stale gateway info", { pid: existingInfo.pid });
|
|
758
510
|
if (isPidRunning(existingInfo.pid)) {
|
|
759
|
-
|
|
760
|
-
await killProcessTree(existingInfo.pid);
|
|
761
|
-
} catch (err) {
|
|
762
|
-
logger.warn("Failed to kill stale shared gateway process", {
|
|
763
|
-
error: err instanceof Error ? err.message : String(err),
|
|
764
|
-
pid: existingInfo.pid,
|
|
765
|
-
});
|
|
766
|
-
}
|
|
511
|
+
await killGateway(existingInfo.pid, "stale");
|
|
767
512
|
}
|
|
768
513
|
clearGatewayInfo();
|
|
769
|
-
clearClientFiles();
|
|
770
514
|
}
|
|
771
515
|
|
|
772
516
|
const { url, pid, pythonPath, venvPath } = await startGatewayProcess(cwd);
|
|
773
|
-
const { totalRefCount } = updateLocalClientRefCount(1);
|
|
774
517
|
const info: GatewayInfo = {
|
|
775
518
|
url,
|
|
776
519
|
pid,
|
|
777
520
|
startedAt: Date.now(),
|
|
778
|
-
refCount: totalRefCount,
|
|
779
|
-
cwd,
|
|
780
521
|
pythonPath,
|
|
781
522
|
venvPath,
|
|
782
523
|
};
|
|
783
524
|
writeGatewayInfo(info);
|
|
784
525
|
isCoordinatorInitialized = true;
|
|
785
|
-
logger.debug("Started
|
|
526
|
+
logger.debug("Started global Python gateway", { url, pid });
|
|
786
527
|
return { url, isShared: true };
|
|
787
528
|
});
|
|
788
529
|
} catch (err) {
|
|
@@ -795,48 +536,24 @@ export async function acquireSharedGateway(cwd: string): Promise<AcquireResult |
|
|
|
795
536
|
|
|
796
537
|
export async function releaseSharedGateway(): Promise<void> {
|
|
797
538
|
if (!isCoordinatorInitialized) return;
|
|
798
|
-
|
|
799
|
-
try {
|
|
800
|
-
await withGatewayLock(async () => {
|
|
801
|
-
const { totalRefCount } = updateLocalClientRefCount(-1);
|
|
802
|
-
const info = readGatewayInfo();
|
|
803
|
-
if (!info) return;
|
|
804
|
-
|
|
805
|
-
const newRefCount = Math.max(0, totalRefCount);
|
|
806
|
-
if (newRefCount === 0) {
|
|
807
|
-
const updatedInfo = { ...info, refCount: 0 };
|
|
808
|
-
writeGatewayInfo(updatedInfo);
|
|
809
|
-
scheduleIdleShutdown();
|
|
810
|
-
logger.debug("Scheduled idle shutdown for shared gateway", { pid: info.pid });
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
const updatedInfo = { ...info, refCount: newRefCount };
|
|
814
|
-
writeGatewayInfo(updatedInfo);
|
|
815
|
-
logger.debug("Released shared gateway reference", { url: info.url, refCount: newRefCount });
|
|
816
|
-
});
|
|
817
|
-
} catch (err) {
|
|
818
|
-
logger.warn("Failed to release shared gateway", {
|
|
819
|
-
error: err instanceof Error ? err.message : String(err),
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
539
|
}
|
|
823
540
|
|
|
824
541
|
export function getSharedGatewayUrl(): string | null {
|
|
825
|
-
return localGatewayUrl;
|
|
542
|
+
if (localGatewayUrl) return localGatewayUrl;
|
|
543
|
+
return readGatewayInfo()?.url ?? null;
|
|
826
544
|
}
|
|
827
545
|
|
|
828
546
|
export function isSharedGatewayActive(): boolean {
|
|
829
|
-
return
|
|
547
|
+
return getGatewayStatus().active;
|
|
830
548
|
}
|
|
831
549
|
|
|
832
550
|
export interface GatewayStatus {
|
|
833
551
|
active: boolean;
|
|
834
|
-
shared: boolean;
|
|
835
552
|
url: string | null;
|
|
836
553
|
pid: number | null;
|
|
837
|
-
refCount: number;
|
|
838
|
-
cwd: string | null;
|
|
839
554
|
uptime: number | null;
|
|
555
|
+
pythonPath: string | null;
|
|
556
|
+
venvPath: string | null;
|
|
840
557
|
}
|
|
841
558
|
|
|
842
559
|
export function getGatewayStatus(): GatewayStatus {
|
|
@@ -844,45 +561,44 @@ export function getGatewayStatus(): GatewayStatus {
|
|
|
844
561
|
if (!info) {
|
|
845
562
|
return {
|
|
846
563
|
active: false,
|
|
847
|
-
shared: false,
|
|
848
564
|
url: null,
|
|
849
565
|
pid: null,
|
|
850
|
-
refCount: 0,
|
|
851
|
-
cwd: null,
|
|
852
566
|
uptime: null,
|
|
567
|
+
pythonPath: null,
|
|
568
|
+
venvPath: null,
|
|
853
569
|
};
|
|
854
570
|
}
|
|
855
571
|
const active = isPidRunning(info.pid);
|
|
856
|
-
const clients = pruneStaleClientInfos(listClientInfos());
|
|
857
|
-
const clientRefCount = clients.reduce((sum, client) => sum + client.info.refCount, 0);
|
|
858
|
-
const refCount = clientRefCount > 0 ? clientRefCount : info.refCount;
|
|
859
572
|
return {
|
|
860
573
|
active,
|
|
861
|
-
shared: active && refCount > 1,
|
|
862
574
|
url: info.url,
|
|
863
575
|
pid: info.pid,
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
576
|
+
uptime: active ? Date.now() - info.startedAt : null,
|
|
577
|
+
pythonPath: info.pythonPath ?? null,
|
|
578
|
+
venvPath: info.venvPath ?? null,
|
|
867
579
|
};
|
|
868
580
|
}
|
|
869
581
|
|
|
870
582
|
export async function shutdownSharedGateway(): Promise<void> {
|
|
871
|
-
cancelIdleShutdown();
|
|
872
583
|
try {
|
|
873
584
|
await withGatewayLock(async () => {
|
|
874
585
|
const info = readGatewayInfo();
|
|
875
|
-
if (info)
|
|
876
|
-
|
|
586
|
+
if (!info) return;
|
|
587
|
+
if (isPidRunning(info.pid)) {
|
|
588
|
+
await killGateway(info.pid, "shutdown");
|
|
877
589
|
}
|
|
878
|
-
|
|
590
|
+
clearGatewayInfo();
|
|
879
591
|
});
|
|
880
592
|
} catch (err) {
|
|
881
593
|
logger.warn("Failed to shutdown shared gateway", {
|
|
882
594
|
error: err instanceof Error ? err.message : String(err),
|
|
883
595
|
});
|
|
884
596
|
} finally {
|
|
885
|
-
|
|
597
|
+
if (localGatewayProcess) {
|
|
598
|
+
await killGateway(localGatewayProcess.pid, "shutdown-local");
|
|
599
|
+
}
|
|
600
|
+
localGatewayProcess = null;
|
|
601
|
+
localGatewayUrl = null;
|
|
886
602
|
isCoordinatorInitialized = false;
|
|
887
603
|
}
|
|
888
604
|
}
|
|
@@ -3,12 +3,12 @@ import { delimiter, join } from "node:path";
|
|
|
3
3
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import { $, type Subprocess } from "bun";
|
|
5
5
|
import { nanoid } from "nanoid";
|
|
6
|
-
import { getShellConfig, killProcessTree } from "
|
|
7
|
-
import { getOrCreateSnapshot } from "
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
6
|
+
import { getShellConfig, killProcessTree } from "$c/utils/shell";
|
|
7
|
+
import { getOrCreateSnapshot } from "$c/utils/shell-snapshot";
|
|
8
|
+
import { htmlToBasicMarkdown } from "$c/web/scrapers/types";
|
|
9
|
+
import { acquireSharedGateway, releaseSharedGateway } from "./gateway-coordinator";
|
|
10
|
+
import { loadPythonModules } from "./modules";
|
|
11
|
+
import { PYTHON_PRELUDE } from "./prelude";
|
|
12
12
|
|
|
13
13
|
const TEXT_ENCODER = new TextEncoder();
|
|
14
14
|
const TEXT_DECODER = new TextDecoder();
|
|
@@ -511,7 +511,7 @@ export class PythonKernel {
|
|
|
511
511
|
|
|
512
512
|
const externalConfig = getExternalGatewayConfig();
|
|
513
513
|
if (externalConfig) {
|
|
514
|
-
return PythonKernel.startWithExternalGateway(externalConfig, options.cwd);
|
|
514
|
+
return PythonKernel.startWithExternalGateway(externalConfig, options.cwd, options.env);
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
// Try shared gateway first (unless explicitly disabled)
|
|
@@ -519,7 +519,7 @@ export class PythonKernel {
|
|
|
519
519
|
try {
|
|
520
520
|
const sharedResult = await acquireSharedGateway(options.cwd);
|
|
521
521
|
if (sharedResult) {
|
|
522
|
-
return PythonKernel.startWithSharedGateway(sharedResult.url, options.cwd);
|
|
522
|
+
return PythonKernel.startWithSharedGateway(sharedResult.url, options.cwd, options.env);
|
|
523
523
|
}
|
|
524
524
|
} catch (err) {
|
|
525
525
|
logger.warn("Failed to acquire shared gateway, falling back to local", {
|
|
@@ -531,7 +531,11 @@ export class PythonKernel {
|
|
|
531
531
|
return PythonKernel.startWithLocalGateway(options);
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
-
private static async startWithExternalGateway(
|
|
534
|
+
private static async startWithExternalGateway(
|
|
535
|
+
config: ExternalGatewayConfig,
|
|
536
|
+
cwd: string,
|
|
537
|
+
env?: Record<string, string | undefined>,
|
|
538
|
+
): Promise<PythonKernel> {
|
|
535
539
|
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
536
540
|
if (config.token) {
|
|
537
541
|
headers.Authorization = `token ${config.token}`;
|
|
@@ -554,6 +558,7 @@ export class PythonKernel {
|
|
|
554
558
|
|
|
555
559
|
try {
|
|
556
560
|
await kernel.connectWebSocket();
|
|
561
|
+
await kernel.initializeKernelEnvironment(cwd, env);
|
|
557
562
|
kernel.startHeartbeat();
|
|
558
563
|
const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
|
|
559
564
|
if (preludeResult.cancelled || preludeResult.status === "error") {
|
|
@@ -567,7 +572,11 @@ export class PythonKernel {
|
|
|
567
572
|
}
|
|
568
573
|
}
|
|
569
574
|
|
|
570
|
-
private static async startWithSharedGateway(
|
|
575
|
+
private static async startWithSharedGateway(
|
|
576
|
+
gatewayUrl: string,
|
|
577
|
+
cwd: string,
|
|
578
|
+
env?: Record<string, string | undefined>,
|
|
579
|
+
): Promise<PythonKernel> {
|
|
571
580
|
const createResponse = await fetch(`${gatewayUrl}/api/kernels`, {
|
|
572
581
|
method: "POST",
|
|
573
582
|
headers: { "Content-Type": "application/json" },
|
|
@@ -586,6 +595,7 @@ export class PythonKernel {
|
|
|
586
595
|
|
|
587
596
|
try {
|
|
588
597
|
await kernel.connectWebSocket();
|
|
598
|
+
await kernel.initializeKernelEnvironment(cwd, env);
|
|
589
599
|
kernel.startHeartbeat();
|
|
590
600
|
const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
|
|
591
601
|
if (preludeResult.cancelled || preludeResult.status === "error") {
|
|
@@ -702,6 +712,7 @@ export class PythonKernel {
|
|
|
702
712
|
|
|
703
713
|
try {
|
|
704
714
|
await kernel.connectWebSocket();
|
|
715
|
+
await kernel.initializeKernelEnvironment(options.cwd, options.env);
|
|
705
716
|
kernel.startHeartbeat();
|
|
706
717
|
const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
|
|
707
718
|
if (preludeResult.cancelled || preludeResult.status === "error") {
|
|
@@ -802,6 +813,23 @@ export class PythonKernel {
|
|
|
802
813
|
return promise;
|
|
803
814
|
}
|
|
804
815
|
|
|
816
|
+
private async initializeKernelEnvironment(cwd: string, env?: Record<string, string | undefined>): Promise<void> {
|
|
817
|
+
const envEntries = Object.entries(env ?? {}).filter(([, value]) => value !== undefined);
|
|
818
|
+
const envPayload = Object.fromEntries(envEntries);
|
|
819
|
+
const initScript = [
|
|
820
|
+
"import os, sys",
|
|
821
|
+
`__omp_cwd = ${JSON.stringify(cwd)}`,
|
|
822
|
+
"os.chdir(__omp_cwd)",
|
|
823
|
+
`__omp_env = ${JSON.stringify(envPayload)}`,
|
|
824
|
+
"for __omp_key, __omp_val in __omp_env.items():\n os.environ[__omp_key] = __omp_val",
|
|
825
|
+
"if __omp_cwd not in sys.path:\n sys.path.insert(0, __omp_cwd)",
|
|
826
|
+
].join("\n");
|
|
827
|
+
const result = await this.execute(initScript, { silent: true, storeHistory: false });
|
|
828
|
+
if (result.cancelled || result.status === "error") {
|
|
829
|
+
throw new Error("Failed to initialize Python kernel environment");
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
805
833
|
private abortPendingExecutions(reason: string): void {
|
|
806
834
|
if (this.#pendingExecutions.size === 0) return;
|
|
807
835
|
for (const cancel of this.#pendingExecutions.values()) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import { ToolAbortError, throwIfAborted } from "$c/tools/tool-errors";
|
|
3
4
|
import { applyWorkspaceEdit } from "./edits";
|
|
4
5
|
import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
|
|
5
6
|
import type {
|
|
@@ -547,7 +548,7 @@ export async function syncContent(
|
|
|
547
548
|
): Promise<void> {
|
|
548
549
|
const uri = fileToUri(filePath);
|
|
549
550
|
const lockKey = `${client.name}:${uri}`;
|
|
550
|
-
|
|
551
|
+
throwIfAborted(signal);
|
|
551
552
|
|
|
552
553
|
const existingLock = fileOperationLocks.get(lockKey);
|
|
553
554
|
if (existingLock) {
|
|
@@ -563,7 +564,7 @@ export async function syncContent(
|
|
|
563
564
|
if (!info) {
|
|
564
565
|
// Open file with provided content instead of reading from disk
|
|
565
566
|
const languageId = detectLanguageId(filePath);
|
|
566
|
-
|
|
567
|
+
throwIfAborted(signal);
|
|
567
568
|
await sendNotification(client, "textDocument/didOpen", {
|
|
568
569
|
textDocument: {
|
|
569
570
|
uri,
|
|
@@ -578,7 +579,7 @@ export async function syncContent(
|
|
|
578
579
|
}
|
|
579
580
|
|
|
580
581
|
const version = ++info.version;
|
|
581
|
-
|
|
582
|
+
throwIfAborted(signal);
|
|
582
583
|
await sendNotification(client, "textDocument/didChange", {
|
|
583
584
|
textDocument: { uri, version },
|
|
584
585
|
contentChanges: [{ text: content }],
|
|
@@ -603,7 +604,7 @@ export async function notifySaved(client: LspClient, filePath: string, signal?:
|
|
|
603
604
|
const info = client.openFiles.get(uri);
|
|
604
605
|
if (!info) return; // File not open, nothing to notify
|
|
605
606
|
|
|
606
|
-
|
|
607
|
+
throwIfAborted(signal);
|
|
607
608
|
await sendNotification(client, "textDocument/didSave", {
|
|
608
609
|
textDocument: { uri },
|
|
609
610
|
});
|
|
@@ -698,7 +699,7 @@ export async function sendRequest(
|
|
|
698
699
|
// Atomically increment and capture request ID
|
|
699
700
|
const id = ++client.requestId;
|
|
700
701
|
if (signal?.aborted) {
|
|
701
|
-
const reason = signal.reason instanceof Error ? signal.reason : new
|
|
702
|
+
const reason = signal.reason instanceof Error ? signal.reason : new ToolAbortError();
|
|
702
703
|
return Promise.reject(reason);
|
|
703
704
|
}
|
|
704
705
|
|
|
@@ -724,7 +725,7 @@ export async function sendRequest(
|
|
|
724
725
|
}
|
|
725
726
|
if (timeout) clearTimeout(timeout);
|
|
726
727
|
cleanup();
|
|
727
|
-
const reason = signal?.reason instanceof Error ? signal.reason : new
|
|
728
|
+
const reason = signal?.reason instanceof Error ? signal.reason : new ToolAbortError();
|
|
728
729
|
reject(reason);
|
|
729
730
|
};
|
|
730
731
|
|