@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
package/src/modes/theme/theme.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { getCustomThemesDir } from "@oh-my-pi/pi-coding-agent/config";
|
|
4
3
|
import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { adjustHsv, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
6
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
7
6
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
8
7
|
import chalk from "chalk";
|
|
9
8
|
import { highlight, supportsLanguage } from "cli-highlight";
|
|
9
|
+
import { getCustomThemesDir } from "../../config";
|
|
10
10
|
// Embed theme JSON files at build time
|
|
11
11
|
import darkThemeJson from "./dark.json" with { type: "json" };
|
|
12
12
|
import { defaultThemes } from "./defaults";
|
|
13
13
|
import lightThemeJson from "./light.json" with { type: "json" };
|
|
14
|
+
import { getMermaidImage } from "./mermaid-cache";
|
|
14
15
|
|
|
15
16
|
// ============================================================================
|
|
16
17
|
// Symbol Presets
|
|
@@ -1599,16 +1600,18 @@ function getBuiltinThemes(): Record<string, ThemeJson> {
|
|
|
1599
1600
|
return BUILTIN_THEMES;
|
|
1600
1601
|
}
|
|
1601
1602
|
|
|
1602
|
-
export function getAvailableThemes(): string[] {
|
|
1603
|
+
export async function getAvailableThemes(): Promise<string[]> {
|
|
1603
1604
|
const themes = new Set<string>(Object.keys(getBuiltinThemes()));
|
|
1604
1605
|
const customThemesDir = getCustomThemesDir();
|
|
1605
|
-
|
|
1606
|
-
const files = fs.
|
|
1606
|
+
try {
|
|
1607
|
+
const files = await fs.promises.readdir(customThemesDir);
|
|
1607
1608
|
for (const file of files) {
|
|
1608
1609
|
if (file.endsWith(".json")) {
|
|
1609
1610
|
themes.add(file.slice(0, -5));
|
|
1610
1611
|
}
|
|
1611
1612
|
}
|
|
1613
|
+
} catch {
|
|
1614
|
+
// Directory doesn't exist or isn't readable
|
|
1612
1615
|
}
|
|
1613
1616
|
return Array.from(themes).sort();
|
|
1614
1617
|
}
|
|
@@ -1618,7 +1621,7 @@ export interface ThemeInfo {
|
|
|
1618
1621
|
path: string | undefined;
|
|
1619
1622
|
}
|
|
1620
1623
|
|
|
1621
|
-
export function getAvailableThemesWithPaths(): ThemeInfo[] {
|
|
1624
|
+
export async function getAvailableThemesWithPaths(): Promise<ThemeInfo[]> {
|
|
1622
1625
|
const result: ThemeInfo[] = [];
|
|
1623
1626
|
|
|
1624
1627
|
// Built-in themes (embedded, no file path)
|
|
@@ -1628,31 +1631,37 @@ export function getAvailableThemesWithPaths(): ThemeInfo[] {
|
|
|
1628
1631
|
|
|
1629
1632
|
// Custom themes
|
|
1630
1633
|
const customThemesDir = getCustomThemesDir();
|
|
1631
|
-
|
|
1632
|
-
|
|
1634
|
+
try {
|
|
1635
|
+
const files = await fs.promises.readdir(customThemesDir);
|
|
1636
|
+
for (const file of files) {
|
|
1633
1637
|
if (file.endsWith(".json")) {
|
|
1634
1638
|
const name = file.slice(0, -5);
|
|
1635
|
-
if (!result.some(
|
|
1639
|
+
if (!result.some(themeInfo => themeInfo.name === name)) {
|
|
1636
1640
|
result.push({ name, path: path.join(customThemesDir, file) });
|
|
1637
1641
|
}
|
|
1638
1642
|
}
|
|
1639
1643
|
}
|
|
1644
|
+
} catch {
|
|
1645
|
+
// Directory doesn't exist or isn't readable
|
|
1640
1646
|
}
|
|
1641
1647
|
|
|
1642
1648
|
return result.sort((a, b) => a.name.localeCompare(b.name));
|
|
1643
1649
|
}
|
|
1644
1650
|
|
|
1645
|
-
function loadThemeJson(name: string): ThemeJson {
|
|
1651
|
+
async function loadThemeJson(name: string): Promise<ThemeJson> {
|
|
1646
1652
|
const builtinThemes = getBuiltinThemes();
|
|
1647
1653
|
if (name in builtinThemes) {
|
|
1648
1654
|
return builtinThemes[name];
|
|
1649
1655
|
}
|
|
1650
1656
|
const customThemesDir = getCustomThemesDir();
|
|
1651
1657
|
const themePath = path.join(customThemesDir, `${name}.json`);
|
|
1652
|
-
|
|
1653
|
-
|
|
1658
|
+
let content: string;
|
|
1659
|
+
try {
|
|
1660
|
+
content = await Bun.file(themePath).text();
|
|
1661
|
+
} catch (err) {
|
|
1662
|
+
if (isEnoent(err)) throw new Error(`Theme not found: ${name}`);
|
|
1663
|
+
throw err;
|
|
1654
1664
|
}
|
|
1655
|
-
const content = fs.readFileSync(themePath, "utf-8");
|
|
1656
1665
|
let json: unknown;
|
|
1657
1666
|
try {
|
|
1658
1667
|
json = JSON.parse(content);
|
|
@@ -1677,7 +1686,7 @@ function loadThemeJson(name: string): ThemeJson {
|
|
|
1677
1686
|
let errorMessage = `Invalid theme "${name}":\n`;
|
|
1678
1687
|
if (missingColors.length > 0) {
|
|
1679
1688
|
errorMessage += `\nMissing required color tokens:\n`;
|
|
1680
|
-
errorMessage += missingColors.map(
|
|
1689
|
+
errorMessage += missingColors.map(c => ` - ${c}`).join("\n");
|
|
1681
1690
|
errorMessage += `\n\nPlease add these colors to your theme's "colors" object.`;
|
|
1682
1691
|
errorMessage += `\nSee the built-in themes (dark.json, light.json) for reference values.`;
|
|
1683
1692
|
}
|
|
@@ -1690,9 +1699,27 @@ function loadThemeJson(name: string): ThemeJson {
|
|
|
1690
1699
|
return json as ThemeJson;
|
|
1691
1700
|
}
|
|
1692
1701
|
|
|
1693
|
-
|
|
1702
|
+
interface CreateThemeOptions {
|
|
1703
|
+
mode?: ColorMode;
|
|
1704
|
+
symbolPresetOverride?: SymbolPreset;
|
|
1705
|
+
colorBlindMode?: boolean;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/** HSV adjustment to shift green toward blue for colorblind mode (red-green colorblindness) */
|
|
1709
|
+
const COLORBLIND_ADJUSTMENT = { h: 60, s: 0.71 };
|
|
1710
|
+
|
|
1711
|
+
function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Theme {
|
|
1712
|
+
const { mode, symbolPresetOverride, colorBlindMode } = options;
|
|
1694
1713
|
const colorMode = mode ?? detectColorMode();
|
|
1695
1714
|
const resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);
|
|
1715
|
+
|
|
1716
|
+
if (colorBlindMode) {
|
|
1717
|
+
const added = resolvedColors.toolDiffAdded;
|
|
1718
|
+
if (typeof added === "string" && added.startsWith("#")) {
|
|
1719
|
+
resolvedColors.toolDiffAdded = adjustHsv(added, COLORBLIND_ADJUSTMENT);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1696
1723
|
const fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;
|
|
1697
1724
|
const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;
|
|
1698
1725
|
const bgColorKeys: Set<string> = new Set([
|
|
@@ -1717,14 +1744,14 @@ function createTheme(themeJson: ThemeJson, mode?: ColorMode, symbolPresetOverrid
|
|
|
1717
1744
|
return new Theme(fgColors, bgColors, colorMode, symbolPreset, symbolOverrides);
|
|
1718
1745
|
}
|
|
1719
1746
|
|
|
1720
|
-
function loadTheme(name: string,
|
|
1721
|
-
const themeJson = loadThemeJson(name);
|
|
1722
|
-
return createTheme(themeJson,
|
|
1747
|
+
async function loadTheme(name: string, options: CreateThemeOptions = {}): Promise<Theme> {
|
|
1748
|
+
const themeJson = await loadThemeJson(name);
|
|
1749
|
+
return createTheme(themeJson, options);
|
|
1723
1750
|
}
|
|
1724
1751
|
|
|
1725
|
-
export function getThemeByName(name: string): Theme | undefined {
|
|
1752
|
+
export async function getThemeByName(name: string): Promise<Theme | undefined> {
|
|
1726
1753
|
try {
|
|
1727
|
-
return loadTheme(name);
|
|
1754
|
+
return await loadTheme(name);
|
|
1728
1755
|
} catch {
|
|
1729
1756
|
return undefined;
|
|
1730
1757
|
}
|
|
@@ -1756,32 +1783,49 @@ function getDefaultTheme(): string {
|
|
|
1756
1783
|
export let theme: Theme;
|
|
1757
1784
|
let currentThemeName: string | undefined;
|
|
1758
1785
|
let currentSymbolPresetOverride: SymbolPreset | undefined;
|
|
1786
|
+
let currentColorBlindMode: boolean = false;
|
|
1759
1787
|
let themeWatcher: fs.FSWatcher | undefined;
|
|
1760
1788
|
let onThemeChangeCallback: (() => void) | undefined;
|
|
1761
1789
|
|
|
1762
|
-
|
|
1790
|
+
function getCurrentThemeOptions(): CreateThemeOptions {
|
|
1791
|
+
return {
|
|
1792
|
+
symbolPresetOverride: currentSymbolPresetOverride,
|
|
1793
|
+
colorBlindMode: currentColorBlindMode,
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
export async function initTheme(
|
|
1798
|
+
themeName?: string,
|
|
1799
|
+
enableWatcher: boolean = false,
|
|
1800
|
+
symbolPreset?: SymbolPreset,
|
|
1801
|
+
colorBlindMode?: boolean,
|
|
1802
|
+
): Promise<void> {
|
|
1763
1803
|
const name = themeName ?? getDefaultTheme();
|
|
1764
1804
|
currentThemeName = name;
|
|
1765
1805
|
currentSymbolPresetOverride = symbolPreset;
|
|
1806
|
+
currentColorBlindMode = colorBlindMode ?? false;
|
|
1766
1807
|
try {
|
|
1767
|
-
theme = loadTheme(name,
|
|
1808
|
+
theme = await loadTheme(name, getCurrentThemeOptions());
|
|
1768
1809
|
if (enableWatcher) {
|
|
1769
|
-
startThemeWatcher();
|
|
1810
|
+
await startThemeWatcher();
|
|
1770
1811
|
}
|
|
1771
1812
|
} catch (err) {
|
|
1772
1813
|
logger.debug("Theme loading failed, falling back to dark theme", { error: String(err) });
|
|
1773
1814
|
currentThemeName = "dark";
|
|
1774
|
-
theme = loadTheme("dark",
|
|
1815
|
+
theme = await loadTheme("dark", getCurrentThemeOptions());
|
|
1775
1816
|
// Don't start watcher for fallback theme
|
|
1776
1817
|
}
|
|
1777
1818
|
}
|
|
1778
1819
|
|
|
1779
|
-
export function setTheme(
|
|
1820
|
+
export async function setTheme(
|
|
1821
|
+
name: string,
|
|
1822
|
+
enableWatcher: boolean = false,
|
|
1823
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
1780
1824
|
currentThemeName = name;
|
|
1781
1825
|
try {
|
|
1782
|
-
theme = loadTheme(name,
|
|
1826
|
+
theme = await loadTheme(name, getCurrentThemeOptions());
|
|
1783
1827
|
if (enableWatcher) {
|
|
1784
|
-
startThemeWatcher();
|
|
1828
|
+
await startThemeWatcher();
|
|
1785
1829
|
}
|
|
1786
1830
|
if (onThemeChangeCallback) {
|
|
1787
1831
|
onThemeChangeCallback();
|
|
@@ -1790,7 +1834,7 @@ export function setTheme(name: string, enableWatcher: boolean = false): { succes
|
|
|
1790
1834
|
} catch (error) {
|
|
1791
1835
|
// Theme is invalid - fall back to dark theme
|
|
1792
1836
|
currentThemeName = "dark";
|
|
1793
|
-
theme = loadTheme("dark",
|
|
1837
|
+
theme = await loadTheme("dark", getCurrentThemeOptions());
|
|
1794
1838
|
// Don't start watcher for fallback theme
|
|
1795
1839
|
return {
|
|
1796
1840
|
success: false,
|
|
@@ -1811,14 +1855,14 @@ export function setThemeInstance(themeInstance: Theme): void {
|
|
|
1811
1855
|
/**
|
|
1812
1856
|
* Set the symbol preset override, recreating the theme with the new preset.
|
|
1813
1857
|
*/
|
|
1814
|
-
export function setSymbolPreset(preset: SymbolPreset): void {
|
|
1858
|
+
export async function setSymbolPreset(preset: SymbolPreset): Promise<void> {
|
|
1815
1859
|
currentSymbolPresetOverride = preset;
|
|
1816
1860
|
if (currentThemeName) {
|
|
1817
1861
|
try {
|
|
1818
|
-
theme = loadTheme(currentThemeName,
|
|
1862
|
+
theme = await loadTheme(currentThemeName, getCurrentThemeOptions());
|
|
1819
1863
|
} catch {
|
|
1820
1864
|
// Fall back to dark theme with new preset
|
|
1821
|
-
theme = loadTheme("dark",
|
|
1865
|
+
theme = await loadTheme("dark", getCurrentThemeOptions());
|
|
1822
1866
|
}
|
|
1823
1867
|
if (onThemeChangeCallback) {
|
|
1824
1868
|
onThemeChangeCallback();
|
|
@@ -1833,6 +1877,32 @@ export function getSymbolPresetOverride(): SymbolPreset | undefined {
|
|
|
1833
1877
|
return currentSymbolPresetOverride;
|
|
1834
1878
|
}
|
|
1835
1879
|
|
|
1880
|
+
/**
|
|
1881
|
+
* Set color blind mode, recreating the theme with the new setting.
|
|
1882
|
+
* When enabled, uses blue instead of green for diff additions.
|
|
1883
|
+
*/
|
|
1884
|
+
export async function setColorBlindMode(enabled: boolean): Promise<void> {
|
|
1885
|
+
currentColorBlindMode = enabled;
|
|
1886
|
+
if (currentThemeName) {
|
|
1887
|
+
try {
|
|
1888
|
+
theme = await loadTheme(currentThemeName, getCurrentThemeOptions());
|
|
1889
|
+
} catch {
|
|
1890
|
+
// Fall back to dark theme
|
|
1891
|
+
theme = await loadTheme("dark", getCurrentThemeOptions());
|
|
1892
|
+
}
|
|
1893
|
+
if (onThemeChangeCallback) {
|
|
1894
|
+
onThemeChangeCallback();
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
/**
|
|
1900
|
+
* Get the current color blind mode setting.
|
|
1901
|
+
*/
|
|
1902
|
+
export function getColorBlindMode(): boolean {
|
|
1903
|
+
return currentColorBlindMode;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1836
1906
|
export function onThemeChange(callback: () => void): void {
|
|
1837
1907
|
onThemeChangeCallback = callback;
|
|
1838
1908
|
}
|
|
@@ -1851,7 +1921,7 @@ export function isValidSymbolPreset(preset: string): preset is SymbolPreset {
|
|
|
1851
1921
|
return preset === "unicode" || preset === "nerd" || preset === "ascii";
|
|
1852
1922
|
}
|
|
1853
1923
|
|
|
1854
|
-
function startThemeWatcher(): void {
|
|
1924
|
+
async function startThemeWatcher(): Promise<void> {
|
|
1855
1925
|
// Stop existing watcher if any
|
|
1856
1926
|
if (themeWatcher) {
|
|
1857
1927
|
themeWatcher.close();
|
|
@@ -1872,34 +1942,40 @@ function startThemeWatcher(): void {
|
|
|
1872
1942
|
}
|
|
1873
1943
|
|
|
1874
1944
|
try {
|
|
1875
|
-
themeWatcher = fs.watch(themeFile,
|
|
1945
|
+
themeWatcher = fs.watch(themeFile, eventType => {
|
|
1876
1946
|
if (eventType === "change") {
|
|
1877
1947
|
// Debounce rapid changes
|
|
1878
1948
|
setTimeout(() => {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1949
|
+
loadTheme(currentThemeName!, getCurrentThemeOptions())
|
|
1950
|
+
.then(loadedTheme => {
|
|
1951
|
+
theme = loadedTheme;
|
|
1952
|
+
if (onThemeChangeCallback) {
|
|
1953
|
+
onThemeChangeCallback();
|
|
1954
|
+
}
|
|
1955
|
+
})
|
|
1956
|
+
.catch(err => {
|
|
1957
|
+
logger.debug("Theme reload error during file change", { error: String(err) });
|
|
1958
|
+
});
|
|
1889
1959
|
}, 100);
|
|
1890
1960
|
} else if (eventType === "rename") {
|
|
1891
1961
|
// File was deleted or renamed - fall back to default theme
|
|
1892
1962
|
setTimeout(() => {
|
|
1893
1963
|
if (!fs.existsSync(themeFile)) {
|
|
1894
1964
|
currentThemeName = "dark";
|
|
1895
|
-
|
|
1965
|
+
loadTheme("dark", getCurrentThemeOptions())
|
|
1966
|
+
.then(loadedTheme => {
|
|
1967
|
+
theme = loadedTheme;
|
|
1968
|
+
if (onThemeChangeCallback) {
|
|
1969
|
+
onThemeChangeCallback();
|
|
1970
|
+
}
|
|
1971
|
+
})
|
|
1972
|
+
.catch(err => {
|
|
1973
|
+
logger.debug("Theme reload error during rename fallback", { error: String(err) });
|
|
1974
|
+
});
|
|
1896
1975
|
if (themeWatcher) {
|
|
1897
1976
|
themeWatcher.close();
|
|
1898
1977
|
themeWatcher = undefined;
|
|
1899
1978
|
}
|
|
1900
|
-
if (onThemeChangeCallback) {
|
|
1901
|
-
onThemeChangeCallback();
|
|
1902
|
-
}
|
|
1903
1979
|
}
|
|
1904
1980
|
}, 100);
|
|
1905
1981
|
}
|
|
@@ -1970,10 +2046,10 @@ function ansi256ToHex(index: number): string {
|
|
|
1970
2046
|
* Get resolved theme colors as CSS-compatible hex strings.
|
|
1971
2047
|
* Used by HTML export to generate CSS custom properties.
|
|
1972
2048
|
*/
|
|
1973
|
-
export function getResolvedThemeColors(themeName?: string): Record<string, string
|
|
2049
|
+
export async function getResolvedThemeColors(themeName?: string): Promise<Record<string, string>> {
|
|
1974
2050
|
const name = themeName ?? getDefaultTheme();
|
|
1975
2051
|
const isLight = name === "light";
|
|
1976
|
-
const themeJson = loadThemeJson(name);
|
|
2052
|
+
const themeJson = await loadThemeJson(name);
|
|
1977
2053
|
const resolved = resolveThemeColors(themeJson.colors, themeJson.vars);
|
|
1978
2054
|
|
|
1979
2055
|
// Default text color for empty values (terminal uses default fg color)
|
|
@@ -2005,14 +2081,14 @@ export function isLightTheme(themeName?: string): boolean {
|
|
|
2005
2081
|
* Get explicit export colors from theme JSON, if specified.
|
|
2006
2082
|
* Returns undefined for each color that isn't explicitly set.
|
|
2007
2083
|
*/
|
|
2008
|
-
export function getThemeExportColors(themeName?: string): {
|
|
2084
|
+
export async function getThemeExportColors(themeName?: string): Promise<{
|
|
2009
2085
|
pageBg?: string;
|
|
2010
2086
|
cardBg?: string;
|
|
2011
2087
|
infoBg?: string;
|
|
2012
|
-
} {
|
|
2088
|
+
}> {
|
|
2013
2089
|
const name = themeName ?? getDefaultTheme();
|
|
2014
2090
|
try {
|
|
2015
|
-
const themeJson = loadThemeJson(name);
|
|
2091
|
+
const themeJson = await loadThemeJson(name);
|
|
2016
2092
|
const exportSection = themeJson.export;
|
|
2017
2093
|
if (!exportSection) return {};
|
|
2018
2094
|
|
|
@@ -2224,6 +2300,7 @@ export function getMarkdownTheme(): MarkdownTheme {
|
|
|
2224
2300
|
underline: (text: string) => theme.underline(text),
|
|
2225
2301
|
strikethrough: (text: string) => chalk.strikethrough(text),
|
|
2226
2302
|
symbols: getSymbolTheme(),
|
|
2303
|
+
getMermaidImage,
|
|
2227
2304
|
highlightCode: (code: string, lang?: string): string[] => {
|
|
2228
2305
|
// Validate language before highlighting to avoid stderr spam from cli-highlight
|
|
2229
2306
|
const validLang = lang && supportsLanguage(lang) ? lang : undefined;
|
|
@@ -2235,7 +2312,7 @@ export function getMarkdownTheme(): MarkdownTheme {
|
|
|
2235
2312
|
try {
|
|
2236
2313
|
return highlight(code, opts).split("\n");
|
|
2237
2314
|
} catch {
|
|
2238
|
-
return code.split("\n").map(
|
|
2315
|
+
return code.split("\n").map(line => theme.fg("mdCodeBlock", line));
|
|
2239
2316
|
}
|
|
2240
2317
|
},
|
|
2241
2318
|
};
|
package/src/modes/types.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import type { KeybindingsManager } from "@oh-my-pi/pi-coding-agent/config/keybindings";
|
|
4
|
-
import type { SettingsManager } from "@oh-my-pi/pi-coding-agent/config/settings-manager";
|
|
5
|
-
import type { ExtensionUIContext } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/index";
|
|
6
|
-
import type { CompactOptions } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/types";
|
|
7
|
-
import type { MCPManager } from "@oh-my-pi/pi-coding-agent/mcp/index";
|
|
8
|
-
import type { AgentSession, AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
|
|
9
|
-
import type { HistoryStorage } from "@oh-my-pi/pi-coding-agent/session/history-storage";
|
|
10
|
-
import type { SessionContext, SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
|
|
11
3
|
import type { Component, Container, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
|
|
4
|
+
import type { KeybindingsManager } from "../config/keybindings";
|
|
5
|
+
import type { SettingsManager } from "../config/settings-manager";
|
|
6
|
+
import type { ExtensionUIContext } from "../extensibility/extensions";
|
|
7
|
+
import type { CompactOptions } from "../extensibility/extensions/types";
|
|
8
|
+
import type { MCPManager } from "../mcp";
|
|
9
|
+
import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
|
|
10
|
+
import type { HistoryStorage } from "../session/history-storage";
|
|
11
|
+
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
12
12
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
13
13
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
14
14
|
import type { CustomEditor } from "./components/custom-editor";
|
|
@@ -132,9 +132,9 @@ export interface InteractiveModeContext {
|
|
|
132
132
|
handleExportCommand(text: string): Promise<void>;
|
|
133
133
|
handleShareCommand(): Promise<void>;
|
|
134
134
|
handleCopyCommand(): Promise<void>;
|
|
135
|
-
handleSessionCommand(): void
|
|
135
|
+
handleSessionCommand(): Promise<void>;
|
|
136
136
|
handleUsageCommand(reports?: UsageReport[] | null): Promise<void>;
|
|
137
|
-
handleChangelogCommand(): void
|
|
137
|
+
handleChangelogCommand(): Promise<void>;
|
|
138
138
|
handleHotkeysCommand(): void;
|
|
139
139
|
handleDumpCommand(): Promise<void>;
|
|
140
140
|
handleClearCommand(): Promise<void>;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, Message } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { AssistantMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/assistant-message";
|
|
4
|
-
import { BashExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/bash-execution";
|
|
5
|
-
import { BranchSummaryMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/branch-summary-message";
|
|
6
|
-
import { CompactionSummaryMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/compaction-summary-message";
|
|
7
|
-
import { CustomMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/custom-message";
|
|
8
|
-
import { DynamicBorder } from "@oh-my-pi/pi-coding-agent/modes/components/dynamic-border";
|
|
9
|
-
import { PythonExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/python-execution";
|
|
10
|
-
import { ReadToolGroupComponent } from "@oh-my-pi/pi-coding-agent/modes/components/read-tool-group";
|
|
11
|
-
import { ToolExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tool-execution";
|
|
12
|
-
import { UserMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/user-message";
|
|
13
|
-
import { theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
14
|
-
import type { CompactionQueuedMessage, InteractiveModeContext } from "@oh-my-pi/pi-coding-agent/modes/types";
|
|
15
|
-
import type { CustomMessage } from "@oh-my-pi/pi-coding-agent/session/messages";
|
|
16
|
-
import type { SessionContext } from "@oh-my-pi/pi-coding-agent/session/session-manager";
|
|
17
3
|
import { Spacer, Text, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
4
|
+
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
5
|
+
import { BashExecutionComponent } from "../../modes/components/bash-execution";
|
|
6
|
+
import { BranchSummaryMessageComponent } from "../../modes/components/branch-summary-message";
|
|
7
|
+
import { CompactionSummaryMessageComponent } from "../../modes/components/compaction-summary-message";
|
|
8
|
+
import { CustomMessageComponent } from "../../modes/components/custom-message";
|
|
9
|
+
import { DynamicBorder } from "../../modes/components/dynamic-border";
|
|
10
|
+
import { PythonExecutionComponent } from "../../modes/components/python-execution";
|
|
11
|
+
import { ReadToolGroupComponent } from "../../modes/components/read-tool-group";
|
|
12
|
+
import { ToolExecutionComponent } from "../../modes/components/tool-execution";
|
|
13
|
+
import { UserMessageComponent } from "../../modes/components/user-message";
|
|
14
|
+
import { theme } from "../../modes/theme/theme";
|
|
15
|
+
import type { CompactionQueuedMessage, InteractiveModeContext } from "../../modes/types";
|
|
16
|
+
import type { CustomMessage } from "../../session/messages";
|
|
17
|
+
import type { SessionContext } from "../../session/session-manager";
|
|
18
18
|
|
|
19
19
|
type TextBlock = { type: "text"; text: string };
|
|
20
20
|
|
|
@@ -33,7 +33,7 @@ export class UiHelpers {
|
|
|
33
33
|
typeof message.content === "string"
|
|
34
34
|
? [{ type: "text", text: message.content }]
|
|
35
35
|
: message.content.filter((content): content is TextBlock => content.type === "text");
|
|
36
|
-
return textBlocks.map(
|
|
36
|
+
return textBlocks.map(block => block.text).join("");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -306,7 +306,7 @@ export class UiHelpers {
|
|
|
306
306
|
|
|
307
307
|
showNewVersionNotification(newVersion: string): void {
|
|
308
308
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
309
|
-
this.ctx.chatContainer.addChild(new DynamicBorder(
|
|
309
|
+
this.ctx.chatContainer.addChild(new DynamicBorder(text => theme.fg("warning", text)));
|
|
310
310
|
this.ctx.chatContainer.addChild(
|
|
311
311
|
new Text(
|
|
312
312
|
theme.bold(theme.fg("warning", "Update Available")) +
|
|
@@ -317,7 +317,7 @@ export class UiHelpers {
|
|
|
317
317
|
0,
|
|
318
318
|
),
|
|
319
319
|
);
|
|
320
|
-
this.ctx.chatContainer.addChild(new DynamicBorder(
|
|
320
|
+
this.ctx.chatContainer.addChild(new DynamicBorder(text => theme.fg("warning", text)));
|
|
321
321
|
this.ctx.ui.requestRender();
|
|
322
322
|
}
|
|
323
323
|
|
package/src/patch/applicator.ts
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
* Applies parsed diff hunks to file content using fuzzy matching
|
|
5
5
|
* for robust handling of whitespace and formatting differences.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { resolveToCwd } from "../tools/path-utils";
|
|
11
10
|
import { DEFAULT_FUZZY_THRESHOLD, findContextLine, findMatch, seekSequence } from "./fuzzy";
|
|
12
11
|
import {
|
|
13
12
|
adjustIndentation,
|
|
@@ -51,10 +50,10 @@ export const defaultFileSystem: FileSystem = {
|
|
|
51
50
|
await Bun.write(path, content);
|
|
52
51
|
},
|
|
53
52
|
async delete(path: string): Promise<void> {
|
|
54
|
-
|
|
53
|
+
await fs.unlink(path);
|
|
55
54
|
},
|
|
56
55
|
async mkdir(path: string): Promise<void> {
|
|
57
|
-
|
|
56
|
+
await fs.mkdir(path, { recursive: true });
|
|
58
57
|
},
|
|
59
58
|
};
|
|
60
59
|
|
|
@@ -204,14 +203,14 @@ function adjustLinesIndentation(patternLines: string[], actualLines: string[], n
|
|
|
204
203
|
deltas.push(aIndent - pIndent);
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
if (deltas.length > 0 && deltas.every(
|
|
206
|
+
if (deltas.length > 0 && deltas.every(value => value === deltas[0])) {
|
|
208
207
|
delta = deltas[0];
|
|
209
208
|
}
|
|
210
209
|
|
|
211
210
|
// Track which actual lines we've used to handle duplicate content correctly
|
|
212
211
|
const usedActualLines = new Map<string, number>(); // trimmed content -> count used
|
|
213
212
|
|
|
214
|
-
return newLines.map(
|
|
213
|
+
return newLines.map(newLine => {
|
|
215
214
|
if (newLine.trim().length === 0) {
|
|
216
215
|
return newLine;
|
|
217
216
|
}
|
|
@@ -277,7 +276,7 @@ function trimCommonContext(oldLines: string[], newLines: string[]): HunkVariant
|
|
|
277
276
|
}
|
|
278
277
|
|
|
279
278
|
function collapseConsecutiveSharedLines(oldLines: string[], newLines: string[]): HunkVariant | undefined {
|
|
280
|
-
const shared = new Set(oldLines.filter(
|
|
279
|
+
const shared = new Set(oldLines.filter(line => newLines.includes(line)));
|
|
281
280
|
const collapse = (lines: string[]): string[] => {
|
|
282
281
|
const out: string[] = [];
|
|
283
282
|
let i = 0;
|
|
@@ -302,7 +301,7 @@ function collapseConsecutiveSharedLines(oldLines: string[], newLines: string[]):
|
|
|
302
301
|
}
|
|
303
302
|
|
|
304
303
|
function collapseRepeatedBlocks(oldLines: string[], newLines: string[]): HunkVariant | undefined {
|
|
305
|
-
const shared = new Set(oldLines.filter(
|
|
304
|
+
const shared = new Set(oldLines.filter(line => newLines.includes(line)));
|
|
306
305
|
const collapse = (lines: string[]): string[] => {
|
|
307
306
|
const output = [...lines];
|
|
308
307
|
let changed = false;
|
|
@@ -313,7 +312,7 @@ function collapseRepeatedBlocks(oldLines: string[], newLines: string[]): HunkVar
|
|
|
313
312
|
const first = output.slice(i, i + size);
|
|
314
313
|
const second = output.slice(i + size, i + size * 2);
|
|
315
314
|
if (first.length !== second.length || first.length === 0) continue;
|
|
316
|
-
if (!first.every(
|
|
315
|
+
if (!first.every(line => shared.has(line))) continue;
|
|
317
316
|
let same = true;
|
|
318
317
|
for (let idx = 0; idx < size; idx++) {
|
|
319
318
|
if (first[idx] !== second[idx]) {
|
|
@@ -379,7 +378,7 @@ function buildFallbackVariants(hunk: DiffHunk): HunkVariant[] {
|
|
|
379
378
|
if (singleLine) variants.push(singleLine);
|
|
380
379
|
|
|
381
380
|
const seen = new Set<string>();
|
|
382
|
-
return variants.filter(
|
|
381
|
+
return variants.filter(variant => {
|
|
383
382
|
if (variant.oldLines.length === 0 && variant.newLines.length === 0) return false;
|
|
384
383
|
const key = `${variant.oldLines.join("\n")}||${variant.newLines.join("\n")}`;
|
|
385
384
|
if (seen.has(key)) return false;
|
|
@@ -443,8 +442,8 @@ function findHierarchicalContext(
|
|
|
443
442
|
if (context.includes("\n")) {
|
|
444
443
|
const parts = context
|
|
445
444
|
.split("\n")
|
|
446
|
-
.map(
|
|
447
|
-
.filter(
|
|
445
|
+
.map(p => p.trim())
|
|
446
|
+
.filter(p => p.length > 0);
|
|
448
447
|
let currentStart = startFrom;
|
|
449
448
|
|
|
450
449
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -488,7 +487,7 @@ function findHierarchicalContext(
|
|
|
488
487
|
}
|
|
489
488
|
|
|
490
489
|
// Try literal context first
|
|
491
|
-
const spaceParts = context.split(/\s+/).filter(
|
|
490
|
+
const spaceParts = context.split(/\s+/).filter(p => p.length > 0);
|
|
492
491
|
const hasSignatureChars = /[(){}[\]]/.test(context);
|
|
493
492
|
if (!hasSignatureChars && spaceParts.length > 2) {
|
|
494
493
|
const outer = spaceParts.slice(0, -1).join(" ");
|
|
@@ -899,7 +898,7 @@ function computeReplacements(
|
|
|
899
898
|
for (const variant of buildFallbackVariants(hunk)) {
|
|
900
899
|
if (variant.oldLines.length !== 1 || variant.newLines.length !== 1) continue;
|
|
901
900
|
const removedLine = variant.oldLines[0];
|
|
902
|
-
const hasSharedDuplicate = hunk.newLines.some(
|
|
901
|
+
const hasSharedDuplicate = hunk.newLines.some(line => line.trim() === removedLine.trim());
|
|
903
902
|
const adjacentIndex = findContextRelativeMatch(
|
|
904
903
|
originalLines,
|
|
905
904
|
removedLine,
|
|
@@ -922,7 +921,7 @@ function computeReplacements(
|
|
|
922
921
|
if (line.trim() === trimmed) occurrenceCount++;
|
|
923
922
|
}
|
|
924
923
|
if (occurrenceCount > 1) {
|
|
925
|
-
const hasSharedDuplicate = hunk.newLines.some(
|
|
924
|
+
const hasSharedDuplicate = hunk.newLines.some(line => line.trim() === trimmed);
|
|
926
925
|
const contextMatch = findContextRelativeMatch(originalLines, pattern[0], contextIndex, hasSharedDuplicate);
|
|
927
926
|
if (contextMatch !== undefined) {
|
|
928
927
|
searchResult = { index: contextMatch, confidence: searchResult.confidence ?? 0.95 };
|
|
@@ -1113,7 +1112,7 @@ async function applyNormalizedPatch(
|
|
|
1113
1112
|
const content = normalizedContent.endsWith("\n") ? normalizedContent : `${normalizedContent}\n`;
|
|
1114
1113
|
|
|
1115
1114
|
if (!dryRun) {
|
|
1116
|
-
const parentDir = dirname(absolutePath);
|
|
1115
|
+
const parentDir = path.dirname(absolutePath);
|
|
1117
1116
|
if (parentDir && parentDir !== ".") {
|
|
1118
1117
|
await fs.mkdir(parentDir);
|
|
1119
1118
|
}
|
|
@@ -1182,7 +1181,7 @@ async function applyNormalizedPatch(
|
|
|
1182
1181
|
|
|
1183
1182
|
if (!dryRun) {
|
|
1184
1183
|
if (isMove) {
|
|
1185
|
-
const parentDir = dirname(destPath);
|
|
1184
|
+
const parentDir = path.dirname(destPath);
|
|
1186
1185
|
if (parentDir && parentDir !== ".") {
|
|
1187
1186
|
await fs.mkdir(parentDir);
|
|
1188
1187
|
}
|
package/src/patch/diff.ts
CHANGED
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* Provides diff string generation and the replace-mode edit logic
|
|
5
5
|
* used when not in patch mode.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
|
9
7
|
import * as Diff from "diff";
|
|
8
|
+
import { resolveToCwd } from "../tools/path-utils";
|
|
10
9
|
import { previewPatch } from "./applicator";
|
|
11
10
|
import { DEFAULT_FUZZY_THRESHOLD, findMatch } from "./fuzzy";
|
|
12
11
|
import { adjustIndentation, normalizeToLF, stripBom } from "./normalize";
|
package/src/patch/fuzzy.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Provides both character-level and line-level fuzzy matching with progressive
|
|
5
5
|
* fallback strategies for finding text in files.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
import { countLeadingWhitespace, normalizeForFuzzy, normalizeUnicode } from "./normalize";
|
|
9
8
|
import type { ContextLineResult, FuzzyMatch, MatchOutcome, SequenceSearchResult } from "./types";
|
|
10
9
|
|
|
@@ -89,7 +88,7 @@ function computeRelativeIndentDepths(lines: string[]): number[] {
|
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
const minIndent = nonEmptyIndents.length > 0 ? Math.min(...nonEmptyIndents) : 0;
|
|
92
|
-
const indentSteps = nonEmptyIndents.map(
|
|
91
|
+
const indentSteps = nonEmptyIndents.map(indent => indent - minIndent).filter(step => step > 0);
|
|
93
92
|
const indentUnit = indentSteps.length > 0 ? Math.min(...indentSteps) : 1;
|
|
94
93
|
|
|
95
94
|
return lines.map((line, index) => {
|