@oh-my-pi/pi-coding-agent 8.0.20 → 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 +125 -0
- 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 +54 -23
- package/scripts/format-prompts.ts +0 -1
- package/src/capability/context-file.ts +3 -4
- package/src/capability/extension-module.ts +3 -4
- package/src/capability/extension.ts +3 -4
- package/src/capability/fs.ts +20 -21
- package/src/capability/hook.ts +3 -4
- package/src/capability/index.ts +15 -16
- package/src/capability/instruction.ts +3 -4
- package/src/capability/mcp.ts +3 -4
- package/src/capability/prompt.ts +3 -4
- package/src/capability/rule.ts +3 -4
- package/src/capability/settings.ts +2 -3
- package/src/capability/skill.ts +3 -4
- package/src/capability/slash-command.ts +3 -4
- package/src/capability/ssh.ts +3 -4
- package/src/capability/system-prompt.ts +3 -4
- package/src/capability/tool.ts +3 -4
- 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 -25
- 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 +307 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +351 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +26 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +40 -0
- package/src/commit/agentic/state.ts +69 -0
- package/src/commit/agentic/tools/analyze-file.ts +131 -0
- package/src/commit/agentic/tools/git-file-diff.ts +194 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +84 -0
- package/src/commit/agentic/tools/index.ts +56 -0
- package/src/commit/agentic/tools/propose-changelog.ts +128 -0
- package/src/commit/agentic/tools/propose-commit.ts +154 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/split-commit.ts +280 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +200 -0
- package/src/commit/analysis/conventional.ts +165 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +112 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +36 -0
- package/src/commit/changelog/generate.ts +110 -0
- package/src/commit/changelog/index.ts +233 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +93 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/git/errors.ts +11 -0
- package/src/commit/git/index.ts +212 -0
- package/src/commit/git/operations.ts +53 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +63 -0
- package/src/commit/map-reduce/map-phase.ts +178 -0
- package/src/commit/map-reduce/reduce-phase.ts +145 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +80 -0
- package/src/commit/pipeline.ts +240 -0
- package/src/commit/prompts/analysis-system.md +155 -0
- package/src/commit/prompts/analysis-user.md +41 -0
- package/src/commit/prompts/changelog-system.md +56 -0
- package/src/commit/prompts/changelog-user.md +19 -0
- package/src/commit/prompts/file-observer-system.md +26 -0
- package/src/commit/prompts/file-observer-user.md +9 -0
- package/src/commit/prompts/reduce-system.md +60 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +4 -0
- package/src/commit/prompts/summary-system.md +52 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/types.ts +109 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/config/file-lock.ts +121 -0
- package/src/config/keybindings.ts +6 -8
- package/src/config/model-registry.ts +65 -38
- package/src/config/model-resolver.ts +18 -19
- package/src/config/prompt-templates.ts +11 -11
- package/src/config/settings-manager.ts +141 -50
- package/src/config.ts +64 -66
- 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 +22 -24
- 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 +18 -15
- package/src/extensibility/custom-commands/types.ts +2 -3
- package/src/extensibility/custom-tools/loader.ts +11 -12
- package/src/extensibility/custom-tools/types.ts +7 -8
- package/src/extensibility/custom-tools/wrapper.ts +2 -3
- package/src/extensibility/extensions/loader.ts +76 -54
- package/src/extensibility/extensions/runner.ts +11 -12
- package/src/extensibility/extensions/types.ts +20 -27
- package/src/extensibility/extensions/wrapper.ts +3 -4
- package/src/extensibility/hooks/index.ts +1 -1
- package/src/extensibility/hooks/loader.ts +9 -10
- package/src/extensibility/hooks/runner.ts +7 -8
- package/src/extensibility/hooks/tool-wrapper.ts +0 -1
- package/src/extensibility/hooks/types.ts +11 -18
- 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 +54 -54
- 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 +109 -9
- 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 +99 -61
- package/src/lsp/utils.ts +3 -3
- package/src/main.ts +71 -37
- 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 +6 -7
- 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 +63 -52
- package/src/modes/components/armin.ts +4 -5
- package/src/modes/components/assistant-message.ts +33 -5
- 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 +16 -19
- package/src/modes/components/tree-selector.ts +12 -12
- 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 +31 -31
- 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 -28
- package/src/modes/rpc/rpc-types.ts +3 -4
- package/src/modes/theme/mermaid-cache.ts +89 -0
- package/src/modes/theme/theme.ts +130 -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 +11 -18
- 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 +43 -16
- package/src/prompts/tools/task.md +2 -0
- package/src/sdk.ts +100 -65
- package/src/session/agent-session.ts +84 -85
- package/src/session/agent-storage.ts +43 -39
- package/src/session/artifacts.ts +32 -10
- package/src/session/auth-storage.ts +50 -39
- 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 +14 -56
- 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 +28 -35
- 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 +40 -34
- package/src/task/output-manager.ts +93 -0
- package/src/task/parallel.ts +0 -1
- package/src/task/render.ts +24 -30
- package/src/task/subprocess-tool-registry.ts +1 -2
- package/src/task/worker-protocol.ts +3 -3
- package/src/task/worker.ts +33 -39
- package/src/task/worktree.ts +19 -19
- package/src/tools/ask.ts +41 -20
- package/src/tools/bash-interceptor.ts +1 -5
- package/src/tools/bash.ts +91 -97
- package/src/tools/calculator.ts +49 -47
- package/src/tools/complete.ts +4 -5
- package/src/tools/context.ts +2 -2
- package/src/tools/fetch.ts +84 -124
- package/src/tools/find.ts +94 -98
- package/src/tools/gemini-image.ts +14 -14
- package/src/tools/grep.ts +100 -116
- package/src/tools/index.ts +80 -55
- package/src/tools/list-limit.ts +1 -1
- package/src/tools/ls.ts +44 -70
- package/src/tools/notebook.ts +51 -67
- package/src/tools/output-meta.ts +3 -4
- package/src/tools/output-utils.ts +2 -2
- package/src/tools/path-utils.ts +5 -5
- package/src/tools/python.ts +104 -217
- package/src/tools/read.ts +92 -33
- package/src/tools/render-utils.ts +8 -23
- package/src/tools/renderers.ts +6 -7
- package/src/tools/review.ts +8 -11
- package/src/tools/ssh.ts +69 -49
- package/src/tools/todo-write.ts +37 -25
- package/src/tools/tool-errors.ts +3 -3
- package/src/tools/tool-result.ts +3 -8
- package/src/tools/write.ts +99 -75
- package/src/tui/code-cell.ts +109 -0
- package/src/tui/file-list.ts +47 -0
- package/src/tui/index.ts +11 -0
- package/src/tui/output-block.ts +72 -0
- package/src/tui/status-line.ts +39 -0
- package/src/tui/tree-list.ts +55 -0
- package/src/tui/types.ts +16 -0
- package/src/tui/utils.ts +48 -0
- 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 +5 -10
- 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 +129 -175
- package/tsconfig.json +0 -42
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
3
4
|
import { extractPackageName, parsePluginSpec } from "./parser";
|
|
4
5
|
import {
|
|
5
6
|
getPluginsDir,
|
|
@@ -46,43 +47,47 @@ function validatePackageName(name: string): void {
|
|
|
46
47
|
// =============================================================================
|
|
47
48
|
|
|
48
49
|
export class PluginManager {
|
|
49
|
-
private runtimeConfig: PluginRuntimeConfig;
|
|
50
|
+
private runtimeConfig: PluginRuntimeConfig | null = null;
|
|
50
51
|
private cwd: string;
|
|
51
52
|
|
|
52
53
|
constructor(cwd: string = process.cwd()) {
|
|
53
54
|
this.cwd = cwd;
|
|
54
|
-
this.runtimeConfig = this.loadRuntimeConfig();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// ==========================================================================
|
|
58
58
|
// Runtime Config Management
|
|
59
59
|
// ==========================================================================
|
|
60
60
|
|
|
61
|
-
private loadRuntimeConfig(): PluginRuntimeConfig {
|
|
61
|
+
private async loadRuntimeConfig(): Promise<PluginRuntimeConfig> {
|
|
62
62
|
const lockPath = getPluginsLockfile();
|
|
63
|
-
if (!existsSync(lockPath)) {
|
|
64
|
-
return { plugins: {}, settings: {} };
|
|
65
|
-
}
|
|
66
63
|
try {
|
|
67
|
-
return
|
|
68
|
-
} catch {
|
|
64
|
+
return await Bun.file(lockPath).json();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (isEnoent(err)) return { plugins: {}, settings: {} };
|
|
67
|
+
logger.warn("Failed to load plugin runtime config", { path: lockPath, error: String(err) });
|
|
69
68
|
return { plugins: {}, settings: {} };
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
private
|
|
74
|
-
this.
|
|
75
|
-
|
|
72
|
+
private async ensureConfigLoaded(): Promise<PluginRuntimeConfig> {
|
|
73
|
+
if (!this.runtimeConfig) {
|
|
74
|
+
this.runtimeConfig = await this.loadRuntimeConfig();
|
|
75
|
+
}
|
|
76
|
+
return this.runtimeConfig;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private async saveRuntimeConfig(): Promise<void> {
|
|
80
|
+
await this.ensureConfigLoaded();
|
|
81
|
+
await Bun.write(getPluginsLockfile(), JSON.stringify(this.runtimeConfig, null, 2));
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
private loadProjectOverrides(): ProjectPluginOverrides {
|
|
84
|
+
private async loadProjectOverrides(): Promise<ProjectPluginOverrides> {
|
|
79
85
|
const overridesPath = getProjectPluginOverrides(this.cwd);
|
|
80
|
-
if (!existsSync(overridesPath)) {
|
|
81
|
-
return {};
|
|
82
|
-
}
|
|
83
86
|
try {
|
|
84
|
-
return
|
|
85
|
-
} catch {
|
|
87
|
+
return await Bun.file(overridesPath).json();
|
|
88
|
+
} catch (err) {
|
|
89
|
+
if (isEnoent(err)) return {};
|
|
90
|
+
logger.warn("Failed to load project plugin overrides", { path: overridesPath, error: String(err) });
|
|
86
91
|
return {};
|
|
87
92
|
}
|
|
88
93
|
}
|
|
@@ -91,33 +96,32 @@ export class PluginManager {
|
|
|
91
96
|
// Directory Management
|
|
92
97
|
// ==========================================================================
|
|
93
98
|
|
|
94
|
-
private ensurePluginsDir(): void {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
mkdirSync(dir, { recursive: true });
|
|
98
|
-
}
|
|
99
|
-
const nodeModules = getPluginsNodeModules();
|
|
100
|
-
if (!existsSync(nodeModules)) {
|
|
101
|
-
mkdirSync(nodeModules, { recursive: true });
|
|
102
|
-
}
|
|
99
|
+
private async ensurePluginsDir(): Promise<void> {
|
|
100
|
+
await fs.promises.mkdir(getPluginsDir(), { recursive: true });
|
|
101
|
+
await fs.promises.mkdir(getPluginsNodeModules(), { recursive: true });
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
private ensurePackageJson(): void {
|
|
106
|
-
this.ensurePluginsDir();
|
|
104
|
+
private async ensurePackageJson(): Promise<void> {
|
|
107
105
|
const pkgJsonPath = getPluginsPackageJson();
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
try {
|
|
107
|
+
await Bun.file(pkgJsonPath).json();
|
|
108
|
+
} catch (err) {
|
|
109
|
+
if (isEnoent(err)) {
|
|
110
|
+
await Bun.write(
|
|
111
|
+
pkgJsonPath,
|
|
112
|
+
JSON.stringify(
|
|
113
|
+
{
|
|
114
|
+
name: "omp-plugins",
|
|
115
|
+
private: true,
|
|
116
|
+
dependencies: {},
|
|
117
|
+
},
|
|
118
|
+
null,
|
|
119
|
+
2,
|
|
120
|
+
),
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -136,7 +140,7 @@ export class PluginManager {
|
|
|
136
140
|
const spec = parsePluginSpec(specString);
|
|
137
141
|
validatePackageName(spec.packageName);
|
|
138
142
|
|
|
139
|
-
this.ensurePackageJson();
|
|
143
|
+
await this.ensurePackageJson();
|
|
140
144
|
|
|
141
145
|
if (options.dryRun) {
|
|
142
146
|
return {
|
|
@@ -165,13 +169,17 @@ export class PluginManager {
|
|
|
165
169
|
|
|
166
170
|
// Resolve actual package name (strip version specifier)
|
|
167
171
|
const actualName = extractPackageName(spec.packageName);
|
|
168
|
-
const pkgPath = join(getPluginsNodeModules(), actualName, "package.json");
|
|
172
|
+
const pkgPath = path.join(getPluginsNodeModules(), actualName, "package.json");
|
|
169
173
|
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
let pkg: { name: string; version: string; omp?: PluginManifest; pi?: PluginManifest };
|
|
175
|
+
try {
|
|
176
|
+
pkg = await Bun.file(pkgPath).json();
|
|
177
|
+
} catch (err) {
|
|
178
|
+
if (isEnoent(err)) {
|
|
179
|
+
throw new Error(`Package installed but package.json not found at ${pkgPath}`);
|
|
180
|
+
}
|
|
181
|
+
throw err;
|
|
172
182
|
}
|
|
173
|
-
|
|
174
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
175
183
|
const manifest: PluginManifest = pkg.omp || pkg.pi || { version: pkg.version };
|
|
176
184
|
manifest.version = pkg.version;
|
|
177
185
|
|
|
@@ -201,17 +209,18 @@ export class PluginManager {
|
|
|
201
209
|
// null = use defaults
|
|
202
210
|
|
|
203
211
|
// Update runtime config
|
|
204
|
-
|
|
212
|
+
const config = await this.ensureConfigLoaded();
|
|
213
|
+
config.plugins[pkg.name] = {
|
|
205
214
|
version: pkg.version,
|
|
206
215
|
enabledFeatures,
|
|
207
216
|
enabled: true,
|
|
208
217
|
};
|
|
209
|
-
this.saveRuntimeConfig();
|
|
218
|
+
await this.saveRuntimeConfig();
|
|
210
219
|
|
|
211
220
|
return {
|
|
212
221
|
name: pkg.name,
|
|
213
222
|
version: pkg.version,
|
|
214
|
-
path: join(getPluginsNodeModules(), actualName),
|
|
223
|
+
path: path.join(getPluginsNodeModules(), actualName),
|
|
215
224
|
manifest,
|
|
216
225
|
enabledFeatures,
|
|
217
226
|
enabled: true,
|
|
@@ -223,7 +232,7 @@ export class PluginManager {
|
|
|
223
232
|
*/
|
|
224
233
|
async uninstall(name: string): Promise<void> {
|
|
225
234
|
validatePackageName(name);
|
|
226
|
-
this.ensurePackageJson();
|
|
235
|
+
await this.ensurePackageJson();
|
|
227
236
|
|
|
228
237
|
const proc = Bun.spawn(["npm", "uninstall", name], {
|
|
229
238
|
cwd: getPluginsDir(),
|
|
@@ -238,9 +247,10 @@ export class PluginManager {
|
|
|
238
247
|
}
|
|
239
248
|
|
|
240
249
|
// Remove from runtime config
|
|
241
|
-
|
|
242
|
-
delete
|
|
243
|
-
|
|
250
|
+
const config = await this.ensureConfigLoaded();
|
|
251
|
+
delete config.plugins[name];
|
|
252
|
+
delete config.settings[name];
|
|
253
|
+
await this.saveRuntimeConfig();
|
|
244
254
|
}
|
|
245
255
|
|
|
246
256
|
/**
|
|
@@ -248,41 +258,49 @@ export class PluginManager {
|
|
|
248
258
|
*/
|
|
249
259
|
async list(): Promise<InstalledPlugin[]> {
|
|
250
260
|
const pkgJsonPath = getPluginsPackageJson();
|
|
251
|
-
|
|
252
|
-
|
|
261
|
+
let pkg: { dependencies?: Record<string, string> };
|
|
262
|
+
try {
|
|
263
|
+
pkg = await Bun.file(pkgJsonPath).json();
|
|
264
|
+
} catch (err) {
|
|
265
|
+
if (isEnoent(err)) return [];
|
|
266
|
+
throw err;
|
|
253
267
|
}
|
|
254
268
|
|
|
255
|
-
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
256
269
|
const deps = pkg.dependencies || {};
|
|
257
|
-
const projectOverrides = this.loadProjectOverrides();
|
|
270
|
+
const projectOverrides = await this.loadProjectOverrides();
|
|
271
|
+
const config = await this.ensureConfigLoaded();
|
|
258
272
|
const plugins: InstalledPlugin[] = [];
|
|
259
273
|
|
|
260
274
|
for (const [name] of Object.entries(deps)) {
|
|
261
|
-
const pluginPkgPath = join(getPluginsNodeModules(), name, "package.json");
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
version: pluginPkg.version,
|
|
269
|
-
enabledFeatures: null,
|
|
270
|
-
enabled: true,
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// Apply project overrides
|
|
274
|
-
const isDisabledInProject = projectOverrides.disabled?.includes(name) ?? false;
|
|
275
|
-
const projectFeatures = projectOverrides.features?.[name];
|
|
276
|
-
|
|
277
|
-
plugins.push({
|
|
278
|
-
name,
|
|
279
|
-
version: pluginPkg.version,
|
|
280
|
-
path: join(getPluginsNodeModules(), name),
|
|
281
|
-
manifest,
|
|
282
|
-
enabledFeatures: projectFeatures ?? runtimeState.enabledFeatures,
|
|
283
|
-
enabled: runtimeState.enabled && !isDisabledInProject,
|
|
284
|
-
});
|
|
275
|
+
const pluginPkgPath = path.join(getPluginsNodeModules(), name, "package.json");
|
|
276
|
+
let pluginPkg: { version: string; omp?: PluginManifest; pi?: PluginManifest };
|
|
277
|
+
try {
|
|
278
|
+
pluginPkg = await Bun.file(pluginPkgPath).json();
|
|
279
|
+
} catch (err) {
|
|
280
|
+
if (isEnoent(err)) continue;
|
|
281
|
+
throw err;
|
|
285
282
|
}
|
|
283
|
+
const manifest: PluginManifest = pluginPkg.omp || pluginPkg.pi || { version: pluginPkg.version };
|
|
284
|
+
manifest.version = pluginPkg.version;
|
|
285
|
+
|
|
286
|
+
const runtimeState = config.plugins[name] || {
|
|
287
|
+
version: pluginPkg.version,
|
|
288
|
+
enabledFeatures: null,
|
|
289
|
+
enabled: true,
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// Apply project overrides
|
|
293
|
+
const isDisabledInProject = projectOverrides.disabled?.includes(name) ?? false;
|
|
294
|
+
const projectFeatures = projectOverrides.features?.[name];
|
|
295
|
+
|
|
296
|
+
plugins.push({
|
|
297
|
+
name,
|
|
298
|
+
version: pluginPkg.version,
|
|
299
|
+
path: path.join(getPluginsNodeModules(), name),
|
|
300
|
+
manifest,
|
|
301
|
+
enabledFeatures: projectFeatures ?? runtimeState.enabledFeatures,
|
|
302
|
+
enabled: runtimeState.enabled && !isDisabledInProject,
|
|
303
|
+
});
|
|
286
304
|
}
|
|
287
305
|
|
|
288
306
|
return plugins;
|
|
@@ -292,52 +310,53 @@ export class PluginManager {
|
|
|
292
310
|
* Link a local plugin for development.
|
|
293
311
|
*/
|
|
294
312
|
async link(localPath: string): Promise<InstalledPlugin> {
|
|
295
|
-
const absolutePath = resolve(this.cwd, localPath);
|
|
313
|
+
const absolutePath = path.resolve(this.cwd, localPath);
|
|
296
314
|
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
315
|
+
const pkgFilePath = path.join(absolutePath, "package.json");
|
|
316
|
+
let pkg: { name?: string; version: string; omp?: PluginManifest; pi?: PluginManifest };
|
|
317
|
+
try {
|
|
318
|
+
pkg = await Bun.file(pkgFilePath).json();
|
|
319
|
+
} catch (err) {
|
|
320
|
+
if (isEnoent(err)) throw new Error(`package.json not found at ${absolutePath}`);
|
|
321
|
+
throw err;
|
|
300
322
|
}
|
|
301
|
-
|
|
302
|
-
const pkg = JSON.parse(readFileSync(pkgFile, "utf-8"));
|
|
303
323
|
if (!pkg.name) {
|
|
304
324
|
throw new Error("package.json must have a name field");
|
|
305
325
|
}
|
|
306
326
|
|
|
307
|
-
this.ensurePluginsDir();
|
|
327
|
+
await this.ensurePluginsDir();
|
|
308
328
|
|
|
309
|
-
const linkPath = join(getPluginsNodeModules(), pkg.name);
|
|
329
|
+
const linkPath = path.join(getPluginsNodeModules(), pkg.name);
|
|
310
330
|
|
|
311
331
|
// Handle scoped packages
|
|
312
332
|
if (pkg.name.startsWith("@")) {
|
|
313
|
-
const scopeDir = join(getPluginsNodeModules(), pkg.name.split("/")[0]);
|
|
314
|
-
|
|
315
|
-
mkdirSync(scopeDir, { recursive: true });
|
|
316
|
-
}
|
|
333
|
+
const scopeDir = path.join(getPluginsNodeModules(), pkg.name.split("/")[0]);
|
|
334
|
+
await fs.promises.mkdir(scopeDir, { recursive: true });
|
|
317
335
|
}
|
|
318
336
|
|
|
319
337
|
// Remove existing
|
|
320
338
|
try {
|
|
321
|
-
const
|
|
322
|
-
if (
|
|
323
|
-
|
|
339
|
+
const stats = await fs.promises.lstat(linkPath);
|
|
340
|
+
if (stats.isSymbolicLink() || stats.isDirectory()) {
|
|
341
|
+
await fs.promises.unlink(linkPath);
|
|
324
342
|
}
|
|
325
|
-
} catch {
|
|
326
|
-
|
|
343
|
+
} catch (err) {
|
|
344
|
+
if (!isEnoent(err)) throw err;
|
|
327
345
|
}
|
|
328
346
|
|
|
329
|
-
|
|
347
|
+
await fs.promises.symlink(absolutePath, linkPath);
|
|
330
348
|
|
|
331
349
|
const manifest: PluginManifest = pkg.omp || pkg.pi || { version: pkg.version };
|
|
332
350
|
manifest.version = pkg.version;
|
|
333
351
|
|
|
334
352
|
// Add to runtime config
|
|
335
|
-
|
|
353
|
+
const config = await this.ensureConfigLoaded();
|
|
354
|
+
config.plugins[pkg.name] = {
|
|
336
355
|
version: pkg.version,
|
|
337
356
|
enabledFeatures: null,
|
|
338
357
|
enabled: true,
|
|
339
358
|
};
|
|
340
|
-
this.saveRuntimeConfig();
|
|
359
|
+
await this.saveRuntimeConfig();
|
|
341
360
|
|
|
342
361
|
return {
|
|
343
362
|
name: pkg.name,
|
|
@@ -357,11 +376,12 @@ export class PluginManager {
|
|
|
357
376
|
* Enable or disable a plugin globally.
|
|
358
377
|
*/
|
|
359
378
|
async setEnabled(name: string, enabled: boolean): Promise<void> {
|
|
360
|
-
|
|
379
|
+
const config = await this.ensureConfigLoaded();
|
|
380
|
+
if (!config.plugins[name]) {
|
|
361
381
|
throw new Error(`Plugin ${name} not found in runtime config`);
|
|
362
382
|
}
|
|
363
|
-
|
|
364
|
-
this.saveRuntimeConfig();
|
|
383
|
+
config.plugins[name].enabled = enabled;
|
|
384
|
+
await this.saveRuntimeConfig();
|
|
365
385
|
}
|
|
366
386
|
|
|
367
387
|
// ==========================================================================
|
|
@@ -371,22 +391,24 @@ export class PluginManager {
|
|
|
371
391
|
/**
|
|
372
392
|
* Get enabled features for a plugin.
|
|
373
393
|
*/
|
|
374
|
-
getEnabledFeatures(name: string): string[] | null {
|
|
375
|
-
|
|
394
|
+
async getEnabledFeatures(name: string): Promise<string[] | null> {
|
|
395
|
+
const config = await this.ensureConfigLoaded();
|
|
396
|
+
return config.plugins[name]?.enabledFeatures ?? null;
|
|
376
397
|
}
|
|
377
398
|
|
|
378
399
|
/**
|
|
379
400
|
* Set enabled features for a plugin.
|
|
380
401
|
*/
|
|
381
402
|
async setEnabledFeatures(name: string, features: string[] | null): Promise<void> {
|
|
382
|
-
|
|
403
|
+
const config = await this.ensureConfigLoaded();
|
|
404
|
+
if (!config.plugins[name]) {
|
|
383
405
|
throw new Error(`Plugin ${name} not found in runtime config`);
|
|
384
406
|
}
|
|
385
407
|
|
|
386
408
|
// Validate features if setting specific ones
|
|
387
409
|
if (features && features.length > 0) {
|
|
388
410
|
const plugins = await this.list();
|
|
389
|
-
const plugin = plugins.find(
|
|
411
|
+
const plugin = plugins.find(p => p.name === name);
|
|
390
412
|
if (plugin?.manifest.features) {
|
|
391
413
|
for (const feat of features) {
|
|
392
414
|
if (!(feat in plugin.manifest.features)) {
|
|
@@ -398,8 +420,8 @@ export class PluginManager {
|
|
|
398
420
|
}
|
|
399
421
|
}
|
|
400
422
|
|
|
401
|
-
|
|
402
|
-
this.saveRuntimeConfig();
|
|
423
|
+
config.plugins[name].enabledFeatures = features;
|
|
424
|
+
await this.saveRuntimeConfig();
|
|
403
425
|
}
|
|
404
426
|
|
|
405
427
|
// ==========================================================================
|
|
@@ -409,9 +431,10 @@ export class PluginManager {
|
|
|
409
431
|
/**
|
|
410
432
|
* Get all settings for a plugin.
|
|
411
433
|
*/
|
|
412
|
-
getPluginSettings(name: string): Record<string, unknown
|
|
413
|
-
const
|
|
414
|
-
const
|
|
434
|
+
async getPluginSettings(name: string): Promise<Record<string, unknown>> {
|
|
435
|
+
const config = await this.ensureConfigLoaded();
|
|
436
|
+
const global = config.settings[name] || {};
|
|
437
|
+
const projectOverrides = await this.loadProjectOverrides();
|
|
415
438
|
const project = projectOverrides.settings?.[name] || {};
|
|
416
439
|
|
|
417
440
|
// Project settings override global
|
|
@@ -421,21 +444,23 @@ export class PluginManager {
|
|
|
421
444
|
/**
|
|
422
445
|
* Set a plugin setting value.
|
|
423
446
|
*/
|
|
424
|
-
setPluginSetting(name: string, key: string, value: unknown): void {
|
|
425
|
-
|
|
426
|
-
|
|
447
|
+
async setPluginSetting(name: string, key: string, value: unknown): Promise<void> {
|
|
448
|
+
const config = await this.ensureConfigLoaded();
|
|
449
|
+
if (!config.settings[name]) {
|
|
450
|
+
config.settings[name] = {};
|
|
427
451
|
}
|
|
428
|
-
|
|
429
|
-
this.saveRuntimeConfig();
|
|
452
|
+
config.settings[name][key] = value;
|
|
453
|
+
await this.saveRuntimeConfig();
|
|
430
454
|
}
|
|
431
455
|
|
|
432
456
|
/**
|
|
433
457
|
* Delete a plugin setting.
|
|
434
458
|
*/
|
|
435
|
-
deletePluginSetting(name: string, key: string): void {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
459
|
+
async deletePluginSetting(name: string, key: string): Promise<void> {
|
|
460
|
+
const config = await this.ensureConfigLoaded();
|
|
461
|
+
if (config.settings[name]) {
|
|
462
|
+
delete config.settings[name][key];
|
|
463
|
+
await this.saveRuntimeConfig();
|
|
439
464
|
}
|
|
440
465
|
}
|
|
441
466
|
|
|
@@ -451,15 +476,27 @@ export class PluginManager {
|
|
|
451
476
|
|
|
452
477
|
// Check 1: Plugins directory exists
|
|
453
478
|
const pluginsDir = getPluginsDir();
|
|
479
|
+
const pluginsDirExists = fs.existsSync(pluginsDir);
|
|
454
480
|
checks.push({
|
|
455
481
|
name: "plugins_directory",
|
|
456
|
-
status:
|
|
457
|
-
message:
|
|
482
|
+
status: pluginsDirExists ? "ok" : "warning",
|
|
483
|
+
message: pluginsDirExists ? `Found at ${pluginsDir}` : "Not created yet",
|
|
458
484
|
});
|
|
459
485
|
|
|
460
486
|
// Check 2: package.json exists
|
|
461
487
|
const pkgJsonPath = getPluginsPackageJson();
|
|
462
|
-
|
|
488
|
+
let pkg: { dependencies?: Record<string, string> };
|
|
489
|
+
let hasPkgJson = true;
|
|
490
|
+
try {
|
|
491
|
+
pkg = await Bun.file(pkgJsonPath).json();
|
|
492
|
+
} catch (err) {
|
|
493
|
+
if (isEnoent(err)) {
|
|
494
|
+
hasPkgJson = false;
|
|
495
|
+
pkg = {};
|
|
496
|
+
} else {
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
463
500
|
checks.push({
|
|
464
501
|
name: "package_manifest",
|
|
465
502
|
status: hasPkgJson ? "ok" : "warning",
|
|
@@ -468,7 +505,7 @@ export class PluginManager {
|
|
|
468
505
|
|
|
469
506
|
// Check 3: node_modules exists
|
|
470
507
|
const nodeModulesPath = getPluginsNodeModules();
|
|
471
|
-
const hasNodeModules = existsSync(nodeModulesPath);
|
|
508
|
+
const hasNodeModules = fs.existsSync(nodeModulesPath);
|
|
472
509
|
checks.push({
|
|
473
510
|
name: "node_modules",
|
|
474
511
|
status: hasNodeModules ? "ok" : hasPkgJson ? "error" : "warning",
|
|
@@ -478,36 +515,37 @@ export class PluginManager {
|
|
|
478
515
|
if (!hasPkgJson) {
|
|
479
516
|
return checks;
|
|
480
517
|
}
|
|
481
|
-
|
|
482
|
-
// Check each installed plugin
|
|
483
|
-
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
484
518
|
const deps = pkg.dependencies || {};
|
|
519
|
+
const config = await this.ensureConfigLoaded();
|
|
485
520
|
|
|
486
521
|
for (const [name] of Object.entries(deps)) {
|
|
487
|
-
const pluginPath = join(nodeModulesPath, name);
|
|
488
|
-
const pluginPkgPath = join(pluginPath, "package.json");
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
522
|
+
const pluginPath = path.join(nodeModulesPath, name);
|
|
523
|
+
const pluginPkgPath = path.join(pluginPath, "package.json");
|
|
524
|
+
|
|
525
|
+
let pluginPkg: { version: string; description?: string; omp?: PluginManifest; pi?: PluginManifest };
|
|
526
|
+
try {
|
|
527
|
+
pluginPkg = await Bun.file(pluginPkgPath).json();
|
|
528
|
+
} catch (err) {
|
|
529
|
+
if (isEnoent(err)) {
|
|
530
|
+
if (!fs.existsSync(pluginPath)) {
|
|
531
|
+
const fixed = options.fix ? await this.fixMissingPlugin() : false;
|
|
532
|
+
checks.push({
|
|
533
|
+
name: `plugin:${name}`,
|
|
534
|
+
status: "error",
|
|
535
|
+
message: "Missing from node_modules",
|
|
536
|
+
fixed,
|
|
537
|
+
});
|
|
538
|
+
} else {
|
|
539
|
+
checks.push({
|
|
540
|
+
name: `plugin:${name}`,
|
|
541
|
+
status: "error",
|
|
542
|
+
message: "Missing package.json",
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
throw err;
|
|
508
548
|
}
|
|
509
|
-
|
|
510
|
-
const pluginPkg = JSON.parse(readFileSync(pluginPkgPath, "utf-8"));
|
|
511
549
|
const hasManifest = !!(pluginPkg.omp || pluginPkg.pi);
|
|
512
550
|
const manifest: PluginManifest | undefined = pluginPkg.omp || pluginPkg.pi;
|
|
513
551
|
|
|
@@ -521,8 +559,8 @@ export class PluginManager {
|
|
|
521
559
|
|
|
522
560
|
// Check tools path exists if specified
|
|
523
561
|
if (manifest?.tools) {
|
|
524
|
-
const toolsPath = join(pluginPath, manifest.tools);
|
|
525
|
-
if (!existsSync(toolsPath)) {
|
|
562
|
+
const toolsPath = path.join(pluginPath, manifest.tools);
|
|
563
|
+
if (!fs.existsSync(toolsPath)) {
|
|
526
564
|
checks.push({
|
|
527
565
|
name: `plugin:${name}:tools`,
|
|
528
566
|
status: "error",
|
|
@@ -533,8 +571,8 @@ export class PluginManager {
|
|
|
533
571
|
|
|
534
572
|
// Check hooks path exists if specified
|
|
535
573
|
if (manifest?.hooks) {
|
|
536
|
-
const hooksPath = join(pluginPath, manifest.hooks);
|
|
537
|
-
if (!existsSync(hooksPath)) {
|
|
574
|
+
const hooksPath = path.join(pluginPath, manifest.hooks);
|
|
575
|
+
if (!fs.existsSync(hooksPath)) {
|
|
538
576
|
checks.push({
|
|
539
577
|
name: `plugin:${name}:hooks`,
|
|
540
578
|
status: "error",
|
|
@@ -544,11 +582,11 @@ export class PluginManager {
|
|
|
544
582
|
}
|
|
545
583
|
|
|
546
584
|
// Check enabled features exist in manifest
|
|
547
|
-
const runtimeState =
|
|
585
|
+
const runtimeState = config.plugins[name];
|
|
548
586
|
if (runtimeState?.enabledFeatures && manifest?.features) {
|
|
549
587
|
for (const feat of runtimeState.enabledFeatures) {
|
|
550
588
|
if (!(feat in manifest.features)) {
|
|
551
|
-
const fixed = options.fix ? this.removeInvalidFeature(name, feat) : false;
|
|
589
|
+
const fixed = options.fix ? await this.removeInvalidFeature(name, feat) : false;
|
|
552
590
|
checks.push({
|
|
553
591
|
name: `plugin:${name}:feature:${feat}`,
|
|
554
592
|
status: "warning",
|
|
@@ -561,9 +599,9 @@ export class PluginManager {
|
|
|
561
599
|
}
|
|
562
600
|
|
|
563
601
|
// Check for orphaned runtime config entries
|
|
564
|
-
for (const name of Object.keys(
|
|
602
|
+
for (const name of Object.keys(config.plugins)) {
|
|
565
603
|
if (!(name in deps)) {
|
|
566
|
-
const fixed = options.fix ? this.removeOrphanedConfig(name) : false;
|
|
604
|
+
const fixed = options.fix ? await this.removeOrphanedConfig(name) : false;
|
|
567
605
|
checks.push({
|
|
568
606
|
name: `orphan:${name}`,
|
|
569
607
|
status: "warning",
|
|
@@ -590,20 +628,22 @@ export class PluginManager {
|
|
|
590
628
|
}
|
|
591
629
|
}
|
|
592
630
|
|
|
593
|
-
private removeInvalidFeature(name: string, feat: string): boolean {
|
|
594
|
-
const
|
|
631
|
+
private async removeInvalidFeature(name: string, feat: string): Promise<boolean> {
|
|
632
|
+
const config = await this.ensureConfigLoaded();
|
|
633
|
+
const state = config.plugins[name];
|
|
595
634
|
if (state?.enabledFeatures) {
|
|
596
|
-
state.enabledFeatures = state.enabledFeatures.filter(
|
|
597
|
-
this.saveRuntimeConfig();
|
|
635
|
+
state.enabledFeatures = state.enabledFeatures.filter(f => f !== feat);
|
|
636
|
+
await this.saveRuntimeConfig();
|
|
598
637
|
return true;
|
|
599
638
|
}
|
|
600
639
|
return false;
|
|
601
640
|
}
|
|
602
641
|
|
|
603
|
-
private removeOrphanedConfig(name: string): boolean {
|
|
604
|
-
|
|
605
|
-
delete
|
|
606
|
-
|
|
642
|
+
private async removeOrphanedConfig(name: string): Promise<boolean> {
|
|
643
|
+
const config = await this.ensureConfigLoaded();
|
|
644
|
+
delete config.plugins[name];
|
|
645
|
+
delete config.settings[name];
|
|
646
|
+
await this.saveRuntimeConfig();
|
|
607
647
|
return true;
|
|
608
648
|
}
|
|
609
649
|
}
|
|
@@ -57,7 +57,7 @@ export function parsePluginSpec(spec: string): ParsedPluginSpec {
|
|
|
57
57
|
// Specific features (comma-separated)
|
|
58
58
|
const features = featureStr
|
|
59
59
|
.split(",")
|
|
60
|
-
.map(
|
|
60
|
+
.map(f => f.trim())
|
|
61
61
|
.filter(Boolean);
|
|
62
62
|
|
|
63
63
|
return { packageName, features };
|