@oh-my-pi/pi-coding-agent 8.1.0 → 8.2.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 +21 -1
- package/docs/session.md +111 -46
- package/examples/custom-tools/hello/index.ts +1 -1
- package/examples/custom-tools/todo/index.ts +3 -4
- package/examples/extensions/api-demo.ts +0 -1
- package/examples/extensions/chalk-logger.ts +2 -3
- package/examples/extensions/hello.ts +0 -1
- package/examples/extensions/pirate.ts +0 -1
- package/examples/extensions/plan-mode.ts +15 -16
- package/examples/extensions/todo.ts +3 -4
- package/examples/extensions/tools.ts +1 -2
- package/examples/extensions/with-deps/index.ts +0 -1
- package/examples/hooks/auto-commit-on-exit.ts +1 -2
- package/examples/hooks/confirm-destructive.ts +0 -1
- package/examples/hooks/custom-compaction.ts +1 -2
- package/examples/hooks/dirty-repo-guard.ts +0 -1
- package/examples/hooks/file-trigger.ts +3 -4
- package/examples/hooks/git-checkpoint.ts +0 -1
- package/examples/hooks/handoff.ts +3 -4
- package/examples/hooks/permission-gate.ts +1 -2
- package/examples/hooks/protected-paths.ts +1 -2
- package/examples/hooks/qna.ts +2 -3
- package/examples/hooks/snake.ts +4 -5
- package/examples/hooks/status-line.ts +0 -1
- package/examples/sdk/01-minimal.ts +2 -3
- package/examples/sdk/02-custom-model.ts +2 -3
- package/examples/sdk/03-custom-prompt.ts +3 -4
- package/examples/sdk/04-skills.ts +2 -3
- package/examples/sdk/06-extensions.ts +1 -2
- package/examples/sdk/06-hooks.ts +6 -7
- package/examples/sdk/07-context-files.ts +0 -1
- package/examples/sdk/08-prompt-templates.ts +0 -1
- package/examples/sdk/08-slash-commands.ts +0 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
- package/examples/sdk/10-settings.ts +0 -1
- package/examples/sdk/11-sessions.ts +0 -1
- package/package.json +51 -23
- package/scripts/format-prompts.ts +0 -1
- package/src/capability/context-file.ts +2 -3
- package/src/capability/extension-module.ts +2 -3
- package/src/capability/extension.ts +2 -3
- package/src/capability/fs.ts +20 -21
- package/src/capability/hook.ts +2 -3
- package/src/capability/index.ts +15 -16
- package/src/capability/instruction.ts +2 -3
- package/src/capability/mcp.ts +2 -3
- package/src/capability/prompt.ts +2 -3
- package/src/capability/rule.ts +2 -3
- package/src/capability/settings.ts +1 -2
- package/src/capability/skill.ts +2 -3
- package/src/capability/slash-command.ts +2 -3
- package/src/capability/ssh.ts +2 -3
- package/src/capability/system-prompt.ts +2 -3
- package/src/capability/tool.ts +2 -3
- package/src/cli/args.ts +5 -6
- package/src/cli/config-cli.ts +6 -7
- package/src/cli/file-processor.ts +19 -17
- package/src/cli/jupyter-cli.ts +105 -0
- package/src/cli/list-models.ts +10 -11
- package/src/cli/plugin-cli.ts +20 -21
- package/src/cli/session-picker.ts +2 -3
- package/src/cli/setup-cli.ts +2 -3
- package/src/cli/stats-cli.ts +2 -3
- package/src/cli/update-cli.ts +25 -22
- package/src/commit/agentic/agent.ts +21 -23
- package/src/commit/agentic/fallback.ts +9 -9
- package/src/commit/agentic/index.ts +30 -38
- package/src/commit/agentic/state.ts +1 -6
- package/src/commit/agentic/tools/analyze-file.ts +15 -15
- package/src/commit/agentic/tools/git-file-diff.ts +3 -3
- package/src/commit/agentic/tools/git-hunk.ts +7 -7
- package/src/commit/agentic/tools/git-overview.ts +5 -5
- package/src/commit/agentic/tools/index.ts +14 -14
- package/src/commit/agentic/tools/propose-changelog.ts +6 -6
- package/src/commit/agentic/tools/propose-commit.ts +8 -8
- package/src/commit/agentic/tools/recent-commits.ts +2 -2
- package/src/commit/agentic/tools/split-commit.ts +19 -23
- package/src/commit/agentic/topo-sort.ts +1 -1
- package/src/commit/agentic/trivial.ts +3 -3
- package/src/commit/agentic/validation.ts +12 -12
- package/src/commit/analysis/conventional.ts +7 -11
- package/src/commit/analysis/index.ts +4 -4
- package/src/commit/analysis/scope.ts +4 -4
- package/src/commit/analysis/summary.ts +7 -9
- package/src/commit/analysis/validation.ts +1 -1
- package/src/commit/changelog/detect.ts +6 -6
- package/src/commit/changelog/generate.ts +7 -9
- package/src/commit/changelog/index.ts +13 -13
- package/src/commit/changelog/parse.ts +2 -2
- package/src/commit/cli.ts +1 -1
- package/src/commit/git/diff.ts +3 -3
- package/src/commit/git/index.ts +19 -24
- package/src/commit/index.ts +1 -1
- package/src/commit/map-reduce/index.ts +9 -9
- package/src/commit/map-reduce/map-phase.ts +19 -34
- package/src/commit/map-reduce/reduce-phase.ts +9 -11
- package/src/commit/message.ts +2 -2
- package/src/commit/model-selection.ts +3 -7
- package/src/commit/pipeline.ts +20 -22
- package/src/commit/utils/exclusions.ts +3 -3
- package/src/config/file-lock.ts +17 -7
- package/src/config/keybindings.ts +6 -8
- package/src/config/model-registry.ts +55 -37
- package/src/config/model-resolver.ts +18 -19
- package/src/config/prompt-templates.ts +11 -11
- package/src/config/settings-manager.ts +50 -34
- package/src/config.ts +60 -62
- package/src/cursor.ts +11 -9
- package/src/discovery/agents-md.ts +11 -12
- package/src/discovery/builtin.ts +68 -73
- package/src/discovery/claude.ts +41 -42
- package/src/discovery/cline.ts +11 -12
- package/src/discovery/codex.ts +52 -53
- package/src/discovery/cursor.ts +9 -10
- package/src/discovery/gemini.ts +17 -22
- package/src/discovery/github.ts +13 -14
- package/src/discovery/helpers.ts +35 -34
- package/src/discovery/index.ts +16 -18
- package/src/discovery/mcp-json.ts +8 -9
- package/src/discovery/ssh.ts +8 -9
- package/src/discovery/vscode.ts +4 -5
- package/src/discovery/windsurf.ts +6 -7
- package/src/exa/company.ts +1 -2
- package/src/exa/index.ts +2 -3
- package/src/exa/linkedin.ts +1 -2
- package/src/exa/mcp-client.ts +14 -16
- package/src/exa/render.ts +10 -11
- package/src/exa/researcher.ts +1 -2
- package/src/exa/search.ts +1 -2
- package/src/exa/types.ts +0 -1
- package/src/exa/websets.ts +1 -2
- package/src/exec/bash-executor.ts +3 -4
- package/src/exec/exec.ts +0 -1
- package/src/export/custom-share.ts +5 -6
- package/src/export/html/index.ts +24 -21
- package/src/export/ttsr.ts +2 -3
- package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
- package/src/extensibility/custom-commands/loader.ts +17 -14
- package/src/extensibility/custom-commands/types.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +10 -11
- package/src/extensibility/custom-tools/types.ts +6 -7
- package/src/extensibility/custom-tools/wrapper.ts +2 -3
- package/src/extensibility/extensions/loader.ts +75 -53
- package/src/extensibility/extensions/runner.ts +11 -12
- package/src/extensibility/extensions/types.ts +19 -26
- package/src/extensibility/extensions/wrapper.ts +3 -4
- package/src/extensibility/hooks/index.ts +1 -1
- package/src/extensibility/hooks/loader.ts +8 -9
- package/src/extensibility/hooks/runner.ts +7 -8
- package/src/extensibility/hooks/tool-wrapper.ts +0 -1
- package/src/extensibility/hooks/types.ts +10 -17
- package/src/extensibility/plugins/doctor.ts +3 -3
- package/src/extensibility/plugins/installer.ts +27 -27
- package/src/extensibility/plugins/loader.ts +59 -56
- package/src/extensibility/plugins/manager.ts +211 -171
- package/src/extensibility/plugins/parser.ts +1 -1
- package/src/extensibility/plugins/paths.ts +8 -8
- package/src/extensibility/skills.ts +63 -60
- package/src/extensibility/slash-commands.ts +10 -10
- package/src/index.ts +46 -46
- package/src/internal-urls/agent-protocol.ts +21 -11
- package/src/internal-urls/artifact-protocol.ts +17 -13
- package/src/internal-urls/router.ts +1 -2
- package/src/internal-urls/rule-protocol.ts +3 -4
- package/src/internal-urls/skill-protocol.ts +3 -4
- package/src/ipy/executor.ts +14 -10
- package/src/ipy/gateway-coordinator.ts +79 -90
- package/src/ipy/kernel.ts +32 -30
- package/src/ipy/modules.ts +13 -13
- package/src/lsp/client.ts +21 -10
- package/src/lsp/clients/biome-client.ts +1 -2
- package/src/lsp/clients/index.ts +3 -3
- package/src/lsp/clients/lsp-linter-client.ts +4 -5
- package/src/lsp/config.ts +15 -15
- package/src/lsp/edits.ts +4 -5
- package/src/lsp/index.ts +43 -44
- package/src/lsp/lspmux.ts +8 -8
- package/src/lsp/render.ts +10 -16
- package/src/lsp/utils.ts +3 -3
- package/src/main.ts +55 -34
- package/src/mcp/client.ts +2 -3
- package/src/mcp/config.ts +5 -6
- package/src/mcp/json-rpc.ts +0 -1
- package/src/mcp/loader.ts +3 -4
- package/src/mcp/manager.ts +17 -18
- package/src/mcp/tool-bridge.ts +4 -9
- package/src/mcp/tool-cache.ts +2 -3
- package/src/mcp/transports/http.ts +2 -4
- package/src/mcp/transports/stdio.ts +1 -2
- package/src/migrations.ts +60 -49
- package/src/modes/components/armin.ts +4 -5
- package/src/modes/components/assistant-message.ts +6 -6
- package/src/modes/components/bash-execution.ts +7 -8
- package/src/modes/components/bordered-loader.ts +3 -3
- package/src/modes/components/branch-summary-message.ts +3 -3
- package/src/modes/components/compaction-summary-message.ts +3 -3
- package/src/modes/components/countdown-timer.ts +0 -1
- package/src/modes/components/custom-message.ts +5 -5
- package/src/modes/components/diff.ts +1 -1
- package/src/modes/components/dynamic-border.ts +2 -2
- package/src/modes/components/extensions/extension-dashboard.ts +6 -7
- package/src/modes/components/extensions/extension-list.ts +2 -3
- package/src/modes/components/extensions/inspector-panel.ts +3 -4
- package/src/modes/components/extensions/state-manager.ts +25 -26
- package/src/modes/components/extensions/types.ts +1 -2
- package/src/modes/components/footer.ts +47 -43
- package/src/modes/components/history-search.ts +2 -2
- package/src/modes/components/hook-editor.ts +3 -4
- package/src/modes/components/hook-input.ts +2 -3
- package/src/modes/components/hook-message.ts +5 -5
- package/src/modes/components/hook-selector.ts +2 -3
- package/src/modes/components/keybinding-hints.ts +2 -3
- package/src/modes/components/login-dialog.ts +2 -2
- package/src/modes/components/model-selector.ts +12 -12
- package/src/modes/components/oauth-selector.ts +2 -2
- package/src/modes/components/plugin-settings.ts +20 -20
- package/src/modes/components/python-execution.ts +7 -8
- package/src/modes/components/queue-mode-selector.ts +3 -3
- package/src/modes/components/read-tool-group.ts +2 -2
- package/src/modes/components/session-selector.ts +4 -4
- package/src/modes/components/settings-defs.ts +77 -69
- package/src/modes/components/settings-selector.ts +16 -16
- package/src/modes/components/show-images-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -4
- package/src/modes/components/status-line/separators.ts +1 -1
- package/src/modes/components/status-line/types.ts +2 -2
- package/src/modes/components/status-line-segment-editor.ts +7 -8
- package/src/modes/components/status-line.ts +12 -12
- package/src/modes/components/theme-selector.ts +8 -7
- package/src/modes/components/thinking-selector.ts +4 -4
- package/src/modes/components/todo-display.ts +2 -2
- package/src/modes/components/todo-reminder.ts +4 -4
- package/src/modes/components/tool-execution.ts +11 -16
- package/src/modes/components/tree-selector.ts +11 -11
- package/src/modes/components/ttsr-notification.ts +5 -5
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +1 -1
- package/src/modes/components/visual-truncate.ts +0 -1
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +46 -47
- package/src/modes/controllers/event-controller.ts +16 -20
- package/src/modes/controllers/extension-ui-controller.ts +40 -46
- package/src/modes/controllers/input-controller.ts +17 -18
- package/src/modes/controllers/selector-controller.ts +103 -91
- package/src/modes/index.ts +3 -3
- package/src/modes/interactive-mode.ts +27 -29
- package/src/modes/print-mode.ts +12 -13
- package/src/modes/rpc/rpc-client.ts +7 -8
- package/src/modes/rpc/rpc-mode.ts +24 -25
- package/src/modes/rpc/rpc-types.ts +3 -4
- package/src/modes/theme/mermaid-cache.ts +2 -2
- package/src/modes/theme/theme.ts +128 -53
- package/src/modes/types.ts +10 -10
- package/src/modes/utils/ui-helpers.ts +17 -17
- package/src/patch/applicator.ts +18 -19
- package/src/patch/diff.ts +1 -2
- package/src/patch/fuzzy.ts +1 -2
- package/src/patch/index.ts +10 -11
- package/src/patch/normalize.ts +4 -4
- package/src/patch/normative.ts +1 -2
- package/src/patch/parser.ts +8 -9
- package/src/patch/shared.ts +12 -13
- package/src/sdk.ts +60 -63
- package/src/session/agent-session.ts +83 -84
- package/src/session/agent-storage.ts +11 -11
- package/src/session/artifacts.ts +8 -9
- package/src/session/auth-storage.ts +25 -29
- package/src/session/compaction/branch-summarization.ts +7 -10
- package/src/session/compaction/compaction.ts +8 -19
- package/src/session/compaction/utils.ts +6 -9
- package/src/session/history-storage.ts +10 -10
- package/src/session/messages.ts +4 -5
- package/src/session/session-manager.ts +76 -65
- package/src/session/session-storage.ts +57 -69
- package/src/session/storage-migration.ts +2 -3
- package/src/session/streaming-output.ts +2 -2
- package/src/ssh/connection-manager.ts +43 -50
- package/src/ssh/ssh-executor.ts +2 -2
- package/src/ssh/sshfs-mount.ts +11 -18
- package/src/system-prompt.ts +27 -34
- package/src/task/agents.ts +45 -30
- package/src/task/commands.ts +6 -7
- package/src/task/discovery.ts +39 -76
- package/src/task/executor.ts +14 -15
- package/src/task/index.ts +33 -36
- package/src/task/output-manager.ts +3 -4
- package/src/task/parallel.ts +0 -1
- package/src/task/render.ts +19 -20
- package/src/task/subprocess-tool-registry.ts +1 -2
- package/src/task/worker-protocol.ts +3 -3
- package/src/task/worker.ts +32 -38
- package/src/task/worktree.ts +19 -19
- package/src/tools/ask.ts +8 -9
- package/src/tools/bash-interceptor.ts +1 -5
- package/src/tools/bash.ts +19 -18
- package/src/tools/calculator.ts +12 -12
- package/src/tools/complete.ts +3 -4
- package/src/tools/context.ts +2 -2
- package/src/tools/fetch.ts +23 -26
- package/src/tools/find.ts +15 -16
- package/src/tools/gemini-image.ts +14 -14
- package/src/tools/grep.ts +27 -27
- package/src/tools/index.ts +78 -56
- package/src/tools/list-limit.ts +1 -1
- package/src/tools/ls.ts +7 -7
- package/src/tools/notebook.ts +5 -5
- package/src/tools/output-meta.ts +3 -4
- package/src/tools/output-utils.ts +1 -1
- package/src/tools/path-utils.ts +5 -5
- package/src/tools/python.ts +36 -37
- package/src/tools/read.ts +23 -23
- package/src/tools/render-utils.ts +8 -9
- package/src/tools/renderers.ts +6 -7
- package/src/tools/review.ts +8 -11
- package/src/tools/ssh.ts +31 -30
- package/src/tools/todo-write.ts +13 -13
- package/src/tools/tool-errors.ts +3 -3
- package/src/tools/tool-result.ts +3 -8
- package/src/tools/write.ts +11 -16
- package/src/tui/code-cell.ts +3 -9
- package/src/tui/file-list.ts +3 -4
- package/src/tui/output-block.ts +1 -2
- package/src/tui/status-line.ts +2 -3
- package/src/tui/tree-list.ts +2 -3
- package/src/tui/types.ts +1 -2
- package/src/tui/utils.ts +2 -3
- package/src/utils/changelog.ts +9 -10
- package/src/utils/clipboard.ts +11 -11
- package/src/utils/file-mentions.ts +4 -10
- package/src/utils/frontmatter.ts +6 -3
- package/src/utils/fuzzy.ts +2 -2
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/mime.ts +2 -2
- package/src/utils/shell-snapshot.ts +11 -13
- package/src/utils/shell.ts +4 -5
- package/src/utils/title-generator.ts +8 -9
- package/src/utils/tools-manager.ts +23 -23
- package/src/vendor/photon/index.js +1099 -1059
- package/src/vendor/photon/photon_rs_bg.wasm +0 -0
- package/src/web/scrapers/artifacthub.ts +1 -1
- package/src/web/scrapers/arxiv.ts +2 -2
- package/src/web/scrapers/bluesky.ts +2 -2
- package/src/web/scrapers/cheatsh.ts +1 -1
- package/src/web/scrapers/chocolatey.ts +2 -2
- package/src/web/scrapers/choosealicense.ts +5 -5
- package/src/web/scrapers/cisa-kev.ts +1 -1
- package/src/web/scrapers/crossref.ts +2 -2
- package/src/web/scrapers/devto.ts +3 -3
- package/src/web/scrapers/discogs.ts +3 -4
- package/src/web/scrapers/discourse.ts +1 -1
- package/src/web/scrapers/dockerhub.ts +1 -1
- package/src/web/scrapers/fdroid.ts +2 -2
- package/src/web/scrapers/firefox-addons.ts +3 -3
- package/src/web/scrapers/flathub.ts +1 -1
- package/src/web/scrapers/github.ts +3 -3
- package/src/web/scrapers/gitlab.ts +4 -4
- package/src/web/scrapers/hackernews.ts +2 -2
- package/src/web/scrapers/huggingface.ts +1 -1
- package/src/web/scrapers/iacr.ts +2 -2
- package/src/web/scrapers/index.ts +0 -1
- package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
- package/src/web/scrapers/lemmy.ts +2 -2
- package/src/web/scrapers/maven.ts +2 -2
- package/src/web/scrapers/mdn.ts +2 -4
- package/src/web/scrapers/metacpan.ts +2 -2
- package/src/web/scrapers/musicbrainz.ts +1 -2
- package/src/web/scrapers/npm.ts +1 -1
- package/src/web/scrapers/nuget.ts +2 -2
- package/src/web/scrapers/nvd.ts +3 -3
- package/src/web/scrapers/ollama.ts +7 -9
- package/src/web/scrapers/opencorporates.ts +2 -2
- package/src/web/scrapers/openlibrary.ts +6 -6
- package/src/web/scrapers/orcid.ts +0 -1
- package/src/web/scrapers/osv.ts +2 -2
- package/src/web/scrapers/packagist.ts +1 -1
- package/src/web/scrapers/pubmed.ts +1 -2
- package/src/web/scrapers/rawg.ts +2 -2
- package/src/web/scrapers/readthedocs.ts +1 -2
- package/src/web/scrapers/repology.ts +2 -2
- package/src/web/scrapers/rfc.ts +1 -1
- package/src/web/scrapers/searchcode.ts +2 -2
- package/src/web/scrapers/semantic-scholar.ts +1 -1
- package/src/web/scrapers/snapcraft.ts +2 -2
- package/src/web/scrapers/sourcegraph.ts +1 -1
- package/src/web/scrapers/spdx.ts +3 -3
- package/src/web/scrapers/spotify.ts +0 -1
- package/src/web/scrapers/twitter.ts +1 -1
- package/src/web/scrapers/types.ts +1 -2
- package/src/web/scrapers/utils.ts +5 -5
- package/src/web/scrapers/wikidata.ts +3 -3
- package/src/web/scrapers/youtube.ts +9 -14
- package/src/web/search/auth.ts +4 -9
- package/src/web/search/index.ts +11 -21
- package/src/web/search/providers/anthropic.ts +3 -9
- package/src/web/search/providers/exa.ts +6 -10
- package/src/web/search/providers/perplexity.ts +5 -5
- package/src/web/search/render.ts +16 -18
- package/scripts/generate-wasm-b64.ts +0 -24
- package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
- package/src/task/.executor.ts.kate-swp +0 -0
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
package/src/ipy/modules.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
4
|
|
|
5
5
|
export type PythonModuleSource = "user" | "project";
|
|
6
6
|
|
|
@@ -38,12 +38,12 @@ interface ModuleCandidate {
|
|
|
38
38
|
|
|
39
39
|
async function listModuleCandidates(dir: string, source: PythonModuleSource): Promise<ModuleCandidate[]> {
|
|
40
40
|
try {
|
|
41
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
41
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
42
42
|
return entries
|
|
43
|
-
.filter(
|
|
44
|
-
.map(
|
|
43
|
+
.filter(entry => entry.isFile() && entry.name.endsWith(".py"))
|
|
44
|
+
.map(entry => ({
|
|
45
45
|
name: entry.name,
|
|
46
|
-
path: resolve(dir, entry.name),
|
|
46
|
+
path: path.resolve(dir, entry.name),
|
|
47
47
|
source,
|
|
48
48
|
}));
|
|
49
49
|
} catch {
|
|
@@ -66,13 +66,13 @@ async function readModuleContent(candidate: ModuleCandidate): Promise<PythonModu
|
|
|
66
66
|
*/
|
|
67
67
|
export async function discoverPythonModules(options: DiscoverPythonModulesOptions = {}): Promise<PythonModuleEntry[]> {
|
|
68
68
|
const cwd = options.cwd ?? process.cwd();
|
|
69
|
-
const homeDir = options.homeDir ?? homedir();
|
|
69
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
70
70
|
|
|
71
|
-
const userDirs = [join(homeDir, ".omp", "agent", "modules"), join(homeDir, ".pi", "agent", "modules")];
|
|
72
|
-
const projectDirs = [resolve(cwd, ".omp", "modules"), resolve(cwd, ".pi", "modules")];
|
|
71
|
+
const userDirs = [path.join(homeDir, ".omp", "agent", "modules"), path.join(homeDir, ".pi", "agent", "modules")];
|
|
72
|
+
const projectDirs = [path.resolve(cwd, ".omp", "modules"), path.resolve(cwd, ".pi", "modules")];
|
|
73
73
|
|
|
74
|
-
const userCandidates = (await Promise.all(userDirs.map(
|
|
75
|
-
const projectCandidates = (await Promise.all(projectDirs.map(
|
|
74
|
+
const userCandidates = (await Promise.all(userDirs.map(dir => listModuleCandidates(dir, "user")))).flat();
|
|
75
|
+
const projectCandidates = (await Promise.all(projectDirs.map(dir => listModuleCandidates(dir, "project")))).flat();
|
|
76
76
|
|
|
77
77
|
const byName = new Map<string, ModuleCandidate>();
|
|
78
78
|
for (const candidate of userCandidates) {
|
|
@@ -88,7 +88,7 @@ export async function discoverPythonModules(options: DiscoverPythonModulesOption
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
const sorted = Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
91
|
-
return Promise.all(sorted.map(
|
|
91
|
+
return Promise.all(sorted.map(candidate => readModuleContent(candidate)));
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/**
|
package/src/lsp/client.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ToolAbortError, throwIfAborted } from "
|
|
3
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
1
|
+
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { ToolAbortError, throwIfAborted } from "../tools/tool-errors";
|
|
4
3
|
import { applyWorkspaceEdit } from "./edits";
|
|
5
4
|
import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
|
|
6
5
|
import type {
|
|
@@ -298,7 +297,7 @@ async function handleConfigurationRequest(client: LspClient, message: LspJsonRpc
|
|
|
298
297
|
if (typeof message.id !== "number") return;
|
|
299
298
|
const params = message.params as { items?: Array<{ section?: string }> };
|
|
300
299
|
const items = params?.items ?? [];
|
|
301
|
-
const result = items.map(
|
|
300
|
+
const result = items.map(item => {
|
|
302
301
|
const section = item.section ?? "";
|
|
303
302
|
return client.config.settings?.[section] ?? {};
|
|
304
303
|
});
|
|
@@ -512,7 +511,13 @@ export async function ensureFileOpen(client: LspClient, filePath: string): Promi
|
|
|
512
511
|
return;
|
|
513
512
|
}
|
|
514
513
|
|
|
515
|
-
|
|
514
|
+
let content: string;
|
|
515
|
+
try {
|
|
516
|
+
content = await Bun.file(filePath).text();
|
|
517
|
+
} catch (err) {
|
|
518
|
+
if (isEnoent(err)) return;
|
|
519
|
+
throw err;
|
|
520
|
+
}
|
|
516
521
|
const languageId = detectLanguageId(filePath);
|
|
517
522
|
|
|
518
523
|
await sendNotification(client, "textDocument/didOpen", {
|
|
@@ -634,7 +639,13 @@ export async function refreshFile(client: LspClient, filePath: string): Promise<
|
|
|
634
639
|
return;
|
|
635
640
|
}
|
|
636
641
|
|
|
637
|
-
|
|
642
|
+
let content: string;
|
|
643
|
+
try {
|
|
644
|
+
content = await Bun.file(filePath).text();
|
|
645
|
+
} catch (err) {
|
|
646
|
+
if (isEnoent(err)) return;
|
|
647
|
+
throw err;
|
|
648
|
+
}
|
|
638
649
|
const version = ++info.version;
|
|
639
650
|
|
|
640
651
|
await sendNotification(client, "textDocument/didChange", {
|
|
@@ -748,12 +759,12 @@ export async function sendRequest(
|
|
|
748
759
|
|
|
749
760
|
// Register pending request with timeout wrapper
|
|
750
761
|
client.pendingRequests.set(id, {
|
|
751
|
-
resolve:
|
|
762
|
+
resolve: result => {
|
|
752
763
|
if (timeout) clearTimeout(timeout);
|
|
753
764
|
cleanup();
|
|
754
765
|
resolve(result);
|
|
755
766
|
},
|
|
756
|
-
reject:
|
|
767
|
+
reject: err => {
|
|
757
768
|
if (timeout) clearTimeout(timeout);
|
|
758
769
|
cleanup();
|
|
759
770
|
reject(err);
|
|
@@ -762,7 +773,7 @@ export async function sendRequest(
|
|
|
762
773
|
});
|
|
763
774
|
|
|
764
775
|
// Write request
|
|
765
|
-
writeMessage(client.process.stdin as import("bun").FileSink, request).catch(
|
|
776
|
+
writeMessage(client.process.stdin as import("bun").FileSink, request).catch(err => {
|
|
766
777
|
if (timeout) clearTimeout(timeout);
|
|
767
778
|
client.pendingRequests.delete(id);
|
|
768
779
|
cleanup();
|
|
@@ -816,7 +827,7 @@ export interface LspServerStatus {
|
|
|
816
827
|
* Get status of all active LSP clients.
|
|
817
828
|
*/
|
|
818
829
|
export function getActiveClients(): LspServerStatus[] {
|
|
819
|
-
return Array.from(clients.values()).map(
|
|
830
|
+
return Array.from(clients.values()).map(client => ({
|
|
820
831
|
name: client.config.command,
|
|
821
832
|
status: "ready" as const,
|
|
822
833
|
fileTypes: client.config.fileTypes,
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
* Biome CLI-based linter client.
|
|
3
3
|
* Uses Biome's CLI with JSON output instead of LSP (which has stale diagnostics issues).
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import path from "node:path";
|
|
7
|
-
import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "
|
|
6
|
+
import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "../../lsp/types";
|
|
8
7
|
|
|
9
8
|
// =============================================================================
|
|
10
9
|
// Biome JSON Output Types
|
package/src/lsp/clients/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { LinterClient, ServerConfig } from "../../lsp/types";
|
|
2
|
+
import { LspLinterClient } from "./lsp-linter-client";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Linter client implementations.
|
|
3
6
|
*
|
|
@@ -8,9 +11,6 @@
|
|
|
8
11
|
export { BiomeClient } from "./biome-client";
|
|
9
12
|
export { LspLinterClient } from "./lsp-linter-client";
|
|
10
13
|
|
|
11
|
-
import type { LinterClient, ServerConfig } from "@oh-my-pi/pi-coding-agent/lsp/types";
|
|
12
|
-
import { LspLinterClient } from "./lsp-linter-client";
|
|
13
|
-
|
|
14
14
|
// Cache of linter clients by server name + cwd
|
|
15
15
|
const clientCache = new Map<string, LinterClient>();
|
|
16
16
|
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* LSP-based linter client.
|
|
3
3
|
* Uses the Language Server Protocol for formatting and diagnostics.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import { fileToUri } from "@oh-my-pi/pi-coding-agent/lsp/utils";
|
|
5
|
+
import { getOrCreateClient, notifySaved, sendRequest, syncContent } from "../../lsp/client";
|
|
6
|
+
import { applyTextEditsToString } from "../../lsp/edits";
|
|
7
|
+
import type { Diagnostic, LinterClient, LspClient, ServerConfig, TextEdit } from "../../lsp/types";
|
|
8
|
+
import { fileToUri } from "../../lsp/utils";
|
|
10
9
|
|
|
11
10
|
/** Default formatting options for LSP */
|
|
12
11
|
const DEFAULT_FORMAT_OPTIONS = {
|
package/src/lsp/config.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { getConfigDirPaths } from "@oh-my-pi/pi-coding-agent/config";
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
4
3
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
5
4
|
import { YAML } from "bun";
|
|
6
5
|
import { globSync } from "glob";
|
|
6
|
+
import { getConfigDirPaths } from "../config";
|
|
7
7
|
import { BiomeClient } from "./clients/biome-client";
|
|
8
8
|
import DEFAULTS from "./defaults.json" with { type: "json" };
|
|
9
9
|
import type { ServerConfig } from "./types";
|
|
@@ -30,7 +30,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function parseConfigContent(content: string, filePath: string): unknown {
|
|
33
|
-
const extension = extname(filePath).toLowerCase();
|
|
33
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
34
34
|
if (extension === ".yaml" || extension === ".yml") {
|
|
35
35
|
return YAML.parse(content) as unknown;
|
|
36
36
|
}
|
|
@@ -141,7 +141,7 @@ function applyRuntimeDefaults(servers: Record<string, ServerConfig>): Record<str
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
if (updated.omnisharp?.args) {
|
|
144
|
-
const args = updated.omnisharp.args.map(
|
|
144
|
+
const args = updated.omnisharp.args.map(arg => (arg === PID_TOKEN ? String(process.pid) : arg));
|
|
145
145
|
updated.omnisharp = { ...updated.omnisharp, args };
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -160,7 +160,7 @@ export async function hasRootMarkers(cwd: string, markers: string[]): Promise<bo
|
|
|
160
160
|
// Handle glob-like patterns (e.g., "*.cabal")
|
|
161
161
|
if (marker.includes("*")) {
|
|
162
162
|
try {
|
|
163
|
-
const matches = globSync(join(cwd, marker));
|
|
163
|
+
const matches = globSync(path.join(cwd, marker));
|
|
164
164
|
if (matches.length > 0) {
|
|
165
165
|
return true;
|
|
166
166
|
}
|
|
@@ -169,7 +169,7 @@ export async function hasRootMarkers(cwd: string, markers: string[]): Promise<bo
|
|
|
169
169
|
}
|
|
170
170
|
continue;
|
|
171
171
|
}
|
|
172
|
-
const filePath = join(cwd, marker);
|
|
172
|
+
const filePath = path.join(cwd, marker);
|
|
173
173
|
if (await Bun.file(filePath).exists()) {
|
|
174
174
|
return true;
|
|
175
175
|
}
|
|
@@ -211,7 +211,7 @@ export async function resolveCommand(command: string, cwd: string): Promise<stri
|
|
|
211
211
|
// Check local bin directories based on project markers
|
|
212
212
|
for (const { markers, binDir } of LOCAL_BIN_PATHS) {
|
|
213
213
|
if (await hasRootMarkers(cwd, markers)) {
|
|
214
|
-
const localPath = join(cwd, binDir, command);
|
|
214
|
+
const localPath = path.join(cwd, binDir, command);
|
|
215
215
|
if (await Bun.file(localPath).exists()) {
|
|
216
216
|
return localPath;
|
|
217
217
|
}
|
|
@@ -232,14 +232,14 @@ function getConfigPaths(cwd: string): string[] {
|
|
|
232
232
|
|
|
233
233
|
// Project root files (highest priority)
|
|
234
234
|
for (const filename of filenames) {
|
|
235
|
-
paths.push(join(cwd, filename));
|
|
235
|
+
paths.push(path.join(cwd, filename));
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
// Project config directories (.omp/, .pi/, .claude/)
|
|
239
239
|
const projectDirs = getConfigDirPaths("", { user: false, project: true, cwd });
|
|
240
240
|
for (const dir of projectDirs) {
|
|
241
241
|
for (const filename of filenames) {
|
|
242
|
-
paths.push(join(dir, filename));
|
|
242
|
+
paths.push(path.join(dir, filename));
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
|
|
@@ -247,13 +247,13 @@ function getConfigPaths(cwd: string): string[] {
|
|
|
247
247
|
const userDirs = getConfigDirPaths("", { user: true, project: false });
|
|
248
248
|
for (const dir of userDirs) {
|
|
249
249
|
for (const filename of filenames) {
|
|
250
|
-
paths.push(join(dir, filename));
|
|
250
|
+
paths.push(path.join(dir, filename));
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// User home root files (lowest priority fallback)
|
|
255
255
|
for (const filename of filenames) {
|
|
256
|
-
paths.push(join(homedir(), filename));
|
|
256
|
+
paths.push(path.join(os.homedir(), filename));
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
return paths;
|
|
@@ -352,12 +352,12 @@ export async function loadConfig(cwd: string): Promise<LspConfig> {
|
|
|
352
352
|
* Returns servers sorted with primary (non-linter) servers first.
|
|
353
353
|
*/
|
|
354
354
|
export function getServersForFile(config: LspConfig, filePath: string): Array<[string, ServerConfig]> {
|
|
355
|
-
const ext = extname(filePath).toLowerCase();
|
|
356
|
-
const fileName = basename(filePath).toLowerCase();
|
|
355
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
356
|
+
const fileName = path.basename(filePath).toLowerCase();
|
|
357
357
|
const matches: Array<[string, ServerConfig]> = [];
|
|
358
358
|
|
|
359
359
|
for (const [name, serverConfig] of Object.entries(config.servers)) {
|
|
360
|
-
const supportsFile = serverConfig.fileTypes.some(
|
|
360
|
+
const supportsFile = serverConfig.fileTypes.some(fileType => {
|
|
361
361
|
const normalized = fileType.toLowerCase();
|
|
362
362
|
return normalized === ext || normalized === fileName;
|
|
363
363
|
});
|
package/src/lsp/edits.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { CreateFile, DeleteFile, RenameFile, TextDocumentEdit, TextEdit, WorkspaceEdit } from "./types";
|
|
4
4
|
import { uriToFile } from "./utils";
|
|
@@ -86,20 +86,19 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, cwd: string): Prom
|
|
|
86
86
|
if (change.kind === "create") {
|
|
87
87
|
const createOp = change as CreateFile;
|
|
88
88
|
const filePath = uriToFile(createOp.uri);
|
|
89
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
90
89
|
await Bun.write(filePath, "");
|
|
91
90
|
applied.push(`Created ${path.relative(cwd, filePath)}`);
|
|
92
91
|
} else if (change.kind === "rename") {
|
|
93
92
|
const renameOp = change as RenameFile;
|
|
94
93
|
const oldPath = uriToFile(renameOp.oldUri);
|
|
95
94
|
const newPath = uriToFile(renameOp.newUri);
|
|
96
|
-
await mkdir(path.dirname(newPath), { recursive: true });
|
|
97
|
-
await rename(oldPath, newPath);
|
|
95
|
+
await fs.mkdir(path.dirname(newPath), { recursive: true });
|
|
96
|
+
await fs.rename(oldPath, newPath);
|
|
98
97
|
applied.push(`Renamed ${path.relative(cwd, oldPath)} → ${path.relative(cwd, newPath)}`);
|
|
99
98
|
} else if (change.kind === "delete") {
|
|
100
99
|
const deleteOp = change as DeleteFile;
|
|
101
100
|
const filePath = uriToFile(deleteOp.uri);
|
|
102
|
-
await rm(filePath, { recursive: true });
|
|
101
|
+
await fs.rm(filePath, { recursive: true });
|
|
103
102
|
applied.push(`Deleted ${path.relative(cwd, filePath)}`);
|
|
104
103
|
}
|
|
105
104
|
}
|
package/src/lsp/index.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { existsSync, statSync } from "node:fs";
|
|
1
|
+
import * as fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
5
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
6
|
-
import { type Theme, theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
7
|
-
import lspDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/lsp.md" with { type: "text" };
|
|
8
|
-
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
|
9
|
-
import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
|
10
|
-
import { throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
11
4
|
import { logger, once, untilAborted } from "@oh-my-pi/pi-utils";
|
|
12
5
|
import type { BunFile } from "bun";
|
|
6
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
7
|
+
import { type Theme, theme } from "../modes/theme/theme";
|
|
8
|
+
import lspDescription from "../prompts/tools/lsp.md" with { type: "text" };
|
|
9
|
+
import type { ToolSession } from "../tools";
|
|
10
|
+
import { resolveToCwd } from "../tools/path-utils";
|
|
11
|
+
import { throwIfAborted } from "../tools/tool-errors";
|
|
13
12
|
import {
|
|
14
13
|
ensureFileOpen,
|
|
15
14
|
getActiveClients,
|
|
@@ -254,21 +253,21 @@ function limitDiagnosticMessages(messages: string[]): string[] {
|
|
|
254
253
|
}
|
|
255
254
|
|
|
256
255
|
function findFileByExtensions(baseDir: string, extensions: string[], maxDepth: number): string | null {
|
|
257
|
-
const normalized = extensions.map(
|
|
256
|
+
const normalized = extensions.map(ext => ext.toLowerCase());
|
|
258
257
|
const search = (dir: string, depth: number): string | null => {
|
|
259
258
|
if (depth > maxDepth) return null;
|
|
260
|
-
const entries: Dirent[] = [];
|
|
259
|
+
const entries: fs.Dirent[] = [];
|
|
261
260
|
try {
|
|
262
261
|
const names = Array.from(new Bun.Glob("*").scanSync({ cwd: dir, onlyFiles: false }));
|
|
263
262
|
for (const name of names) {
|
|
264
263
|
const fullPath = path.join(dir, name);
|
|
265
264
|
let isDir = false;
|
|
266
265
|
try {
|
|
267
|
-
isDir = statSync(fullPath).isDirectory();
|
|
266
|
+
isDir = fs.statSync(fullPath).isDirectory();
|
|
268
267
|
} catch {
|
|
269
268
|
continue;
|
|
270
269
|
}
|
|
271
|
-
entries.push({ name, isFile: () => !isDir, isDirectory: () => isDir } as Dirent);
|
|
270
|
+
entries.push({ name, isFile: () => !isDir, isDirectory: () => isDir } as fs.Dirent);
|
|
272
271
|
}
|
|
273
272
|
} catch {
|
|
274
273
|
return null;
|
|
@@ -281,7 +280,7 @@ function findFileByExtensions(baseDir: string, extensions: string[], maxDepth: n
|
|
|
281
280
|
|
|
282
281
|
if (entry.isFile()) {
|
|
283
282
|
const lowerName = entry.name.toLowerCase();
|
|
284
|
-
if (normalized.some(
|
|
283
|
+
if (normalized.some(ext => lowerName.endsWith(ext))) {
|
|
285
284
|
return fullPath;
|
|
286
285
|
}
|
|
287
286
|
} else if (entry.isDirectory()) {
|
|
@@ -362,22 +361,22 @@ interface ProjectType {
|
|
|
362
361
|
/** Detect project type from root markers */
|
|
363
362
|
function detectProjectType(cwd: string): ProjectType {
|
|
364
363
|
// Check for Rust (Cargo.toml)
|
|
365
|
-
if (existsSync(path.join(cwd, "Cargo.toml"))) {
|
|
364
|
+
if (fs.existsSync(path.join(cwd, "Cargo.toml"))) {
|
|
366
365
|
return { type: "rust", command: ["cargo", "check", "--message-format=short"], description: "Rust (cargo check)" };
|
|
367
366
|
}
|
|
368
367
|
|
|
369
368
|
// Check for TypeScript (tsconfig.json)
|
|
370
|
-
if (existsSync(path.join(cwd, "tsconfig.json"))) {
|
|
369
|
+
if (fs.existsSync(path.join(cwd, "tsconfig.json"))) {
|
|
371
370
|
return { type: "typescript", command: ["npx", "tsc", "--noEmit"], description: "TypeScript (tsc --noEmit)" };
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
// Check for Go (go.mod)
|
|
375
|
-
if (existsSync(path.join(cwd, "go.mod"))) {
|
|
374
|
+
if (fs.existsSync(path.join(cwd, "go.mod"))) {
|
|
376
375
|
return { type: "go", command: ["go", "build", "./..."], description: "Go (go build)" };
|
|
377
376
|
}
|
|
378
377
|
|
|
379
378
|
// Check for Python (pyproject.toml or pyrightconfig.json)
|
|
380
|
-
if (existsSync(path.join(cwd, "pyproject.toml")) || existsSync(path.join(cwd, "pyrightconfig.json"))) {
|
|
379
|
+
if (fs.existsSync(path.join(cwd, "pyproject.toml")) || fs.existsSync(path.join(cwd, "pyrightconfig.json"))) {
|
|
381
380
|
return { type: "python", command: ["pyright"], description: "Python (pyright)" };
|
|
382
381
|
}
|
|
383
382
|
|
|
@@ -412,10 +411,10 @@ async function runWorkspaceDiagnostics(
|
|
|
412
411
|
return { output: "No issues found", projectType };
|
|
413
412
|
}
|
|
414
413
|
|
|
415
|
-
const summary = formatDiagnosticsSummary(collected.map(
|
|
416
|
-
const formatted = collected.slice(0, 50).map(
|
|
414
|
+
const summary = formatDiagnosticsSummary(collected.map(d => d.diagnostic));
|
|
415
|
+
const formatted = collected.slice(0, 50).map(d => formatDiagnostic(d.diagnostic, d.filePath));
|
|
417
416
|
const more = collected.length > 50 ? `\n ... and ${collected.length - 50} more` : "";
|
|
418
|
-
return { output: `${summary}:\n${formatted.map(
|
|
417
|
+
return { output: `${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}${more}`, projectType };
|
|
419
418
|
} catch (err) {
|
|
420
419
|
logger.debug("LSP diagnostics failed, falling back to shell", { error: String(err) });
|
|
421
420
|
// Fall through to shell command
|
|
@@ -571,10 +570,10 @@ async function getDiagnosticsForFile(
|
|
|
571
570
|
}
|
|
572
571
|
}
|
|
573
572
|
|
|
574
|
-
const formatted = uniqueDiagnostics.map(
|
|
573
|
+
const formatted = uniqueDiagnostics.map(d => formatDiagnostic(d, relPath));
|
|
575
574
|
const limited = limitDiagnosticMessages(formatted);
|
|
576
575
|
const summary = formatDiagnosticsSummary(uniqueDiagnostics);
|
|
577
|
-
const hasErrors = uniqueDiagnostics.some(
|
|
576
|
+
const hasErrors = uniqueDiagnostics.some(d => d.severity === 1);
|
|
578
577
|
|
|
579
578
|
return {
|
|
580
579
|
server: serverNames.join(", "),
|
|
@@ -1096,8 +1095,8 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1096
1095
|
}
|
|
1097
1096
|
|
|
1098
1097
|
const summary = formatDiagnosticsSummary(uniqueDiagnostics);
|
|
1099
|
-
const formatted = uniqueDiagnostics.map(
|
|
1100
|
-
const output = `${summary}:\n${formatted.map(
|
|
1098
|
+
const formatted = uniqueDiagnostics.map(d => formatDiagnostic(d, relPath));
|
|
1099
|
+
const output = `${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}`;
|
|
1101
1100
|
return {
|
|
1102
1101
|
content: [{ type: "text", text: output }],
|
|
1103
1102
|
details: { action, serverName: Array.from(allServerNames).join(", "), success: true },
|
|
@@ -1187,7 +1186,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1187
1186
|
output = "No definition found";
|
|
1188
1187
|
} else {
|
|
1189
1188
|
const raw = Array.isArray(result) ? result : [result];
|
|
1190
|
-
const locations = raw.flatMap(
|
|
1189
|
+
const locations = raw.flatMap(loc => {
|
|
1191
1190
|
if ("uri" in loc) {
|
|
1192
1191
|
return [loc as Location];
|
|
1193
1192
|
}
|
|
@@ -1203,7 +1202,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1203
1202
|
output = "No definition found";
|
|
1204
1203
|
} else {
|
|
1205
1204
|
output = `Found ${locations.length} definition(s):\n${locations
|
|
1206
|
-
.map(
|
|
1205
|
+
.map(loc => ` ${formatLocation(loc, this.session.cwd)}`)
|
|
1207
1206
|
.join("\n")}`;
|
|
1208
1207
|
}
|
|
1209
1208
|
}
|
|
@@ -1220,7 +1219,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1220
1219
|
if (!result || result.length === 0) {
|
|
1221
1220
|
output = "No references found";
|
|
1222
1221
|
} else {
|
|
1223
|
-
const lines = result.map(
|
|
1222
|
+
const lines = result.map(loc => ` ${formatLocation(loc, this.session.cwd)}`);
|
|
1224
1223
|
output = `Found ${result.length} reference(s):\n${lines.join("\n")}`;
|
|
1225
1224
|
}
|
|
1226
1225
|
break;
|
|
@@ -1257,11 +1256,11 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1257
1256
|
// Check if hierarchical (DocumentSymbol) or flat (SymbolInformation)
|
|
1258
1257
|
if ("selectionRange" in result[0]) {
|
|
1259
1258
|
// Hierarchical
|
|
1260
|
-
const lines = (result as DocumentSymbol[]).flatMap(
|
|
1259
|
+
const lines = (result as DocumentSymbol[]).flatMap(s => formatDocumentSymbol(s));
|
|
1261
1260
|
output = `Symbols in ${relPath}:\n${lines.join("\n")}`;
|
|
1262
1261
|
} else {
|
|
1263
1262
|
// Flat
|
|
1264
|
-
const lines = (result as SymbolInformation[]).map(
|
|
1263
|
+
const lines = (result as SymbolInformation[]).map(s => {
|
|
1265
1264
|
const line = s.location.range.start.line + 1;
|
|
1266
1265
|
const icon = symbolKindToIcon(s.kind);
|
|
1267
1266
|
return `${icon} ${s.name} @ line ${line}`;
|
|
@@ -1285,8 +1284,8 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1285
1284
|
if (!result || result.length === 0) {
|
|
1286
1285
|
output = `No symbols matching "${query}"`;
|
|
1287
1286
|
} else {
|
|
1288
|
-
const lines = result.map(
|
|
1289
|
-
output = `Found ${result.length} symbol(s) matching "${query}":\n${lines.map(
|
|
1287
|
+
const lines = result.map(s => formatSymbolInformation(s, this.session.cwd));
|
|
1288
|
+
output = `Found ${result.length} symbol(s) matching "${query}":\n${lines.map(l => ` ${l}`).join("\n")}`;
|
|
1290
1289
|
}
|
|
1291
1290
|
break;
|
|
1292
1291
|
}
|
|
@@ -1311,10 +1310,10 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1311
1310
|
const shouldApply = apply !== false;
|
|
1312
1311
|
if (shouldApply) {
|
|
1313
1312
|
const applied = await applyWorkspaceEdit(result, this.session.cwd);
|
|
1314
|
-
output = `Applied rename:\n${applied.map(
|
|
1313
|
+
output = `Applied rename:\n${applied.map(a => ` ${a}`).join("\n")}`;
|
|
1315
1314
|
} else {
|
|
1316
1315
|
const preview = formatWorkspaceEdit(result, this.session.cwd);
|
|
1317
|
-
output = `Rename preview:\n${preview.map(
|
|
1316
|
+
output = `Rename preview:\n${preview.map(p => ` ${p}`).join("\n")}`;
|
|
1318
1317
|
}
|
|
1319
1318
|
}
|
|
1320
1319
|
break;
|
|
@@ -1335,7 +1334,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1335
1334
|
const endCharacter = (end_character ?? column ?? 1) - 1;
|
|
1336
1335
|
const range = { start: position, end: { line: endLine, character: endCharacter } };
|
|
1337
1336
|
const relevantDiagnostics = diagnostics.filter(
|
|
1338
|
-
|
|
1337
|
+
d => d.range.start.line <= range.end.line && d.range.end.line >= range.start.line,
|
|
1339
1338
|
);
|
|
1340
1339
|
|
|
1341
1340
|
const codeActionContext: { diagnostics: Diagnostic[]; only?: string[] } = {
|
|
@@ -1401,7 +1400,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1401
1400
|
|
|
1402
1401
|
if (isCodeAction(resolvedAction) && resolvedAction.edit) {
|
|
1403
1402
|
const applied = await applyWorkspaceEdit(resolvedAction.edit, this.session.cwd);
|
|
1404
|
-
output = `Applied "${codeAction.title}":\n${applied.map(
|
|
1403
|
+
output = `Applied "${codeAction.title}":\n${applied.map(a => ` ${a}`).join("\n")}`;
|
|
1405
1404
|
} else {
|
|
1406
1405
|
const commandPayload = getCommandPayload(resolvedAction);
|
|
1407
1406
|
if (commandPayload) {
|
|
@@ -1450,7 +1449,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1450
1449
|
if (!calls || calls.length === 0) {
|
|
1451
1450
|
output = `No callers found for "${item.name}"`;
|
|
1452
1451
|
} else {
|
|
1453
|
-
const lines = calls.map(
|
|
1452
|
+
const lines = calls.map(call => {
|
|
1454
1453
|
const loc = { uri: call.from.uri, range: call.from.selectionRange };
|
|
1455
1454
|
const detail = call.from.detail ? ` (${call.from.detail})` : "";
|
|
1456
1455
|
return ` ${call.from.name}${detail} @ ${formatLocation(loc, this.session.cwd)}`;
|
|
@@ -1465,7 +1464,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1465
1464
|
if (!calls || calls.length === 0) {
|
|
1466
1465
|
output = `"${item.name}" doesn't call any functions`;
|
|
1467
1466
|
} else {
|
|
1468
|
-
const lines = calls.map(
|
|
1467
|
+
const lines = calls.map(call => {
|
|
1469
1468
|
const loc = { uri: call.to.uri, range: call.to.selectionRange };
|
|
1470
1469
|
const detail = call.to.detail ? ` (${call.to.detail})` : "";
|
|
1471
1470
|
return ` ${call.to.name}${detail} @ ${formatLocation(loc, this.session.cwd)}`;
|
|
@@ -1500,10 +1499,10 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1500
1499
|
if (collected.length === 0) {
|
|
1501
1500
|
output = "Flycheck: no issues found";
|
|
1502
1501
|
} else {
|
|
1503
|
-
const summary = formatDiagnosticsSummary(collected.map(
|
|
1504
|
-
const formatted = collected.slice(0, 20).map(
|
|
1502
|
+
const summary = formatDiagnosticsSummary(collected.map(d => d.diagnostic));
|
|
1503
|
+
const formatted = collected.slice(0, 20).map(d => formatDiagnostic(d.diagnostic, d.filePath));
|
|
1505
1504
|
const more = collected.length > 20 ? `\n ... and ${collected.length - 20} more` : "";
|
|
1506
|
-
output = `Flycheck ${summary}:\n${formatted.map(
|
|
1505
|
+
output = `Flycheck ${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}${more}`;
|
|
1507
1506
|
}
|
|
1508
1507
|
break;
|
|
1509
1508
|
}
|
|
@@ -1561,13 +1560,13 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1561
1560
|
const applied = await applyWorkspaceEdit(result, this.session.cwd);
|
|
1562
1561
|
output =
|
|
1563
1562
|
applied.length > 0
|
|
1564
|
-
? `Applied SSR:\n${applied.map(
|
|
1563
|
+
? `Applied SSR:\n${applied.map(a => ` ${a}`).join("\n")}`
|
|
1565
1564
|
: "SSR: no matches found";
|
|
1566
1565
|
} else {
|
|
1567
1566
|
const preview = formatWorkspaceEdit(result, this.session.cwd);
|
|
1568
1567
|
output =
|
|
1569
1568
|
preview.length > 0
|
|
1570
|
-
? `SSR preview:\n${preview.map(
|
|
1569
|
+
? `SSR preview:\n${preview.map(p => ` ${p}`).join("\n")}`
|
|
1571
1570
|
: "SSR: no matches found";
|
|
1572
1571
|
}
|
|
1573
1572
|
break;
|
|
@@ -1592,7 +1591,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1592
1591
|
if (result.length === 0) {
|
|
1593
1592
|
output = "No runnables found";
|
|
1594
1593
|
} else {
|
|
1595
|
-
const lines = result.map(
|
|
1594
|
+
const lines = result.map(r => {
|
|
1596
1595
|
const args = r.args?.cargoArgs?.join(" ") || "";
|
|
1597
1596
|
return ` [${r.kind}] ${r.label}${args ? ` (cargo ${args})` : ""}`;
|
|
1598
1597
|
});
|
|
@@ -1620,7 +1619,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1620
1619
|
if (result.length === 0) {
|
|
1621
1620
|
output = "No related tests found";
|
|
1622
1621
|
} else {
|
|
1623
|
-
output = `Found ${result.length} related test(s):\n${result.map(
|
|
1622
|
+
output = `Found ${result.length} related test(s):\n${result.map(t => ` ${t}`).join("\n")}`;
|
|
1624
1623
|
}
|
|
1625
1624
|
break;
|
|
1626
1625
|
}
|
package/src/lsp/lspmux.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
3
3
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import { TOML } from "bun";
|
|
5
5
|
|
|
@@ -63,14 +63,14 @@ const STATE_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
|
63
63
|
* Matches Rust's `dirs::config_dir()` behavior.
|
|
64
64
|
*/
|
|
65
65
|
function getConfigPath(): string {
|
|
66
|
-
const home = homedir();
|
|
67
|
-
switch (platform()) {
|
|
66
|
+
const home = os.homedir();
|
|
67
|
+
switch (os.platform()) {
|
|
68
68
|
case "win32":
|
|
69
|
-
return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "lspmux", "config.toml");
|
|
69
|
+
return path.join(process.env.APPDATA ?? path.join(home, "AppData", "Roaming"), "lspmux", "config.toml");
|
|
70
70
|
case "darwin":
|
|
71
|
-
return join(home, "Library", "Application Support", "lspmux", "config.toml");
|
|
71
|
+
return path.join(home, "Library", "Application Support", "lspmux", "config.toml");
|
|
72
72
|
default:
|
|
73
|
-
return join(process.env.XDG_CONFIG_HOME ?? join(home, ".config"), "lspmux", "config.toml");
|
|
73
|
+
return path.join(process.env.XDG_CONFIG_HOME ?? path.join(home, ".config"), "lspmux", "config.toml");
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -108,7 +108,7 @@ async function checkServerRunning(binaryPath: string): Promise<boolean> {
|
|
|
108
108
|
|
|
109
109
|
const exited = await Promise.race([
|
|
110
110
|
proc.exited,
|
|
111
|
-
new Promise<null>(
|
|
111
|
+
new Promise<null>(resolve => setTimeout(() => resolve(null), LIVENESS_TIMEOUT_MS)),
|
|
112
112
|
]);
|
|
113
113
|
|
|
114
114
|
if (exited === null) {
|