@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,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
4
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
6
5
|
import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai";
|
|
7
|
-
import { isValidThinkingLevel } from "@oh-my-pi/pi-coding-agent/cli/args";
|
|
8
6
|
import chalk from "chalk";
|
|
7
|
+
import { isValidThinkingLevel } from "../cli/args";
|
|
9
8
|
import type { ModelRegistry } from "./model-registry";
|
|
10
9
|
|
|
11
10
|
/** Default model IDs for each known provider */
|
|
@@ -84,7 +83,7 @@ function tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Mod
|
|
|
84
83
|
const provider = modelPattern.substring(0, slashIndex);
|
|
85
84
|
const modelId = modelPattern.substring(slashIndex + 1);
|
|
86
85
|
const providerMatch = availableModels.find(
|
|
87
|
-
|
|
86
|
+
m => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),
|
|
88
87
|
);
|
|
89
88
|
if (providerMatch) {
|
|
90
89
|
return providerMatch;
|
|
@@ -93,14 +92,14 @@ function tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Mod
|
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
// Check for exact ID match (case-insensitive)
|
|
96
|
-
const exactMatch = availableModels.find(
|
|
95
|
+
const exactMatch = availableModels.find(m => m.id.toLowerCase() === modelPattern.toLowerCase());
|
|
97
96
|
if (exactMatch) {
|
|
98
97
|
return exactMatch;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
// No exact match - fall back to partial matching
|
|
102
101
|
const matches = availableModels.filter(
|
|
103
|
-
|
|
102
|
+
m =>
|
|
104
103
|
m.id.toLowerCase().includes(modelPattern.toLowerCase()) ||
|
|
105
104
|
m.name?.toLowerCase().includes(modelPattern.toLowerCase()),
|
|
106
105
|
);
|
|
@@ -110,8 +109,8 @@ function tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Mod
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
// Separate into aliases and dated versions
|
|
113
|
-
const aliases = matches.filter(
|
|
114
|
-
const datedVersions = matches.filter(
|
|
112
|
+
const aliases = matches.filter(m => isAlias(m.id));
|
|
113
|
+
const datedVersions = matches.filter(m => !isAlias(m.id));
|
|
115
114
|
|
|
116
115
|
if (aliases.length > 0) {
|
|
117
116
|
// Prefer alias - if multiple aliases, pick the one that sorts highest
|
|
@@ -226,7 +225,7 @@ export async function resolveModelScope(patterns: string[], modelRegistry: Model
|
|
|
226
225
|
|
|
227
226
|
// Match against "provider/modelId" format OR just model ID
|
|
228
227
|
// This allows "*sonnet*" to match without requiring "anthropic/*sonnet*"
|
|
229
|
-
const matchingModels = availableModels.filter(
|
|
228
|
+
const matchingModels = availableModels.filter(m => {
|
|
230
229
|
const fullId = `${m.provider}/${m.id}`;
|
|
231
230
|
const glob = new Bun.Glob(globPattern.toLowerCase());
|
|
232
231
|
return glob.match(fullId.toLowerCase()) || glob.match(m.id.toLowerCase());
|
|
@@ -238,7 +237,7 @@ export async function resolveModelScope(patterns: string[], modelRegistry: Model
|
|
|
238
237
|
}
|
|
239
238
|
|
|
240
239
|
for (const model of matchingModels) {
|
|
241
|
-
if (!scopedModels.find(
|
|
240
|
+
if (!scopedModels.find(sm => modelsAreEqual(sm.model, model))) {
|
|
242
241
|
scopedModels.push({ model, thinkingLevel, explicitThinkingLevel });
|
|
243
242
|
}
|
|
244
243
|
}
|
|
@@ -257,7 +256,7 @@ export async function resolveModelScope(patterns: string[], modelRegistry: Model
|
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
// Avoid duplicates
|
|
260
|
-
if (!scopedModels.find(
|
|
259
|
+
if (!scopedModels.find(sm => modelsAreEqual(sm.model, model))) {
|
|
261
260
|
scopedModels.push({ model, thinkingLevel, explicitThinkingLevel });
|
|
262
261
|
}
|
|
263
262
|
}
|
|
@@ -343,7 +342,7 @@ export async function findInitialModel(options: {
|
|
|
343
342
|
// Try to find a default model from known providers
|
|
344
343
|
for (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {
|
|
345
344
|
const defaultId = defaultModelPerProvider[provider];
|
|
346
|
-
const match = availableModels.find(
|
|
345
|
+
const match = availableModels.find(m => m.provider === provider && m.id === defaultId);
|
|
347
346
|
if (match) {
|
|
348
347
|
return { model: match, thinkingLevel: "off", fallbackMessage: undefined };
|
|
349
348
|
}
|
|
@@ -405,7 +404,7 @@ export async function restoreModelFromSession(
|
|
|
405
404
|
let fallbackModel: Model<Api> | undefined;
|
|
406
405
|
for (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {
|
|
407
406
|
const defaultId = defaultModelPerProvider[provider];
|
|
408
|
-
const match = availableModels.find(
|
|
407
|
+
const match = availableModels.find(m => m.provider === provider && m.id === defaultId);
|
|
409
408
|
if (match) {
|
|
410
409
|
fallbackModel = match;
|
|
411
410
|
break;
|
|
@@ -450,7 +449,7 @@ export async function findSmolModel(
|
|
|
450
449
|
if (savedModel) {
|
|
451
450
|
const parsed = parseModelString(savedModel);
|
|
452
451
|
if (parsed) {
|
|
453
|
-
const match = availableModels.find(
|
|
452
|
+
const match = availableModels.find(m => m.provider === parsed.provider && m.id === parsed.id);
|
|
454
453
|
if (match) return match;
|
|
455
454
|
}
|
|
456
455
|
}
|
|
@@ -458,15 +457,15 @@ export async function findSmolModel(
|
|
|
458
457
|
// 2. Try priority chain
|
|
459
458
|
for (const pattern of SMOL_MODEL_PRIORITY) {
|
|
460
459
|
// Try exact match with provider prefix
|
|
461
|
-
const providerMatch = availableModels.find(
|
|
460
|
+
const providerMatch = availableModels.find(m => `${m.provider}/${m.id}`.toLowerCase() === pattern);
|
|
462
461
|
if (providerMatch) return providerMatch;
|
|
463
462
|
|
|
464
463
|
// Try exact match first
|
|
465
|
-
const exactMatch = availableModels.find(
|
|
464
|
+
const exactMatch = availableModels.find(m => m.id.toLowerCase() === pattern);
|
|
466
465
|
if (exactMatch) return exactMatch;
|
|
467
466
|
|
|
468
467
|
// Try fuzzy match (substring)
|
|
469
|
-
const fuzzyMatch = availableModels.find(
|
|
468
|
+
const fuzzyMatch = availableModels.find(m => m.id.toLowerCase().includes(pattern));
|
|
470
469
|
if (fuzzyMatch) return fuzzyMatch;
|
|
471
470
|
}
|
|
472
471
|
|
|
@@ -493,7 +492,7 @@ export async function findSlowModel(
|
|
|
493
492
|
if (savedModel) {
|
|
494
493
|
const parsed = parseModelString(savedModel);
|
|
495
494
|
if (parsed) {
|
|
496
|
-
const match = availableModels.find(
|
|
495
|
+
const match = availableModels.find(m => m.provider === parsed.provider && m.id === parsed.id);
|
|
497
496
|
if (match) return match;
|
|
498
497
|
}
|
|
499
498
|
}
|
|
@@ -501,11 +500,11 @@ export async function findSlowModel(
|
|
|
501
500
|
// 2. Try priority chain
|
|
502
501
|
for (const pattern of SLOW_MODEL_PRIORITY) {
|
|
503
502
|
// Try exact match first
|
|
504
|
-
const exactMatch = availableModels.find(
|
|
503
|
+
const exactMatch = availableModels.find(m => m.id.toLowerCase() === pattern.toLowerCase());
|
|
505
504
|
if (exactMatch) return exactMatch;
|
|
506
505
|
|
|
507
506
|
// Try fuzzy match (substring)
|
|
508
|
-
const fuzzyMatch = availableModels.find(
|
|
507
|
+
const fuzzyMatch = availableModels.find(m => m.id.toLowerCase().includes(pattern.toLowerCase()));
|
|
509
508
|
if (fuzzyMatch) return fuzzyMatch;
|
|
510
509
|
}
|
|
511
510
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { CONFIG_DIR_NAME, getPromptsDir } from "@oh-my-pi/pi-coding-agent/config";
|
|
3
|
-
import { parseFrontmatter } from "@oh-my-pi/pi-coding-agent/utils/frontmatter";
|
|
1
|
+
import * as path from "node:path";
|
|
4
2
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
5
3
|
import Handlebars from "handlebars";
|
|
4
|
+
import { CONFIG_DIR_NAME, getPromptsDir } from "../config";
|
|
5
|
+
import { parseFrontmatter } from "../utils/frontmatter";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Represents a prompt template loaded from a markdown file
|
|
@@ -44,7 +44,7 @@ handlebars.registerHelper(
|
|
|
44
44
|
const suffix = (options.hash.suffix as string) ?? "";
|
|
45
45
|
const rawSeparator = (options.hash.join as string) ?? "\n";
|
|
46
46
|
const separator = rawSeparator.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
|
47
|
-
return context.map(
|
|
47
|
+
return context.map(item => `${prefix}${options.fn(item)}${suffix}`).join(separator);
|
|
48
48
|
},
|
|
49
49
|
);
|
|
50
50
|
|
|
@@ -126,7 +126,7 @@ handlebars.registerHelper(
|
|
|
126
126
|
const headers = headersStr?.split("|") ?? [];
|
|
127
127
|
const separator = headers.map(() => "---").join(" | ");
|
|
128
128
|
const headerRow = headers.length > 0 ? `| ${headers.join(" | ")} |\n| ${separator} |\n` : "";
|
|
129
|
-
const rows = context.map(
|
|
129
|
+
const rows = context.map(item => `| ${options.fn(item).trim()} |`).join("\n");
|
|
130
130
|
return headerRow + rows;
|
|
131
131
|
},
|
|
132
132
|
);
|
|
@@ -235,7 +235,7 @@ function optimizePromptLayout(input: string): string {
|
|
|
235
235
|
// normalize NBSP -> space
|
|
236
236
|
s = s.replace(/\u00A0/g, " ");
|
|
237
237
|
|
|
238
|
-
const lines = s.split("\n").map(
|
|
238
|
+
const lines = s.split("\n").map(line => {
|
|
239
239
|
// 2) remove trailing whitespace (spaces/tabs) per line
|
|
240
240
|
let l = line.replace(/[ \t]+$/g, "");
|
|
241
241
|
|
|
@@ -382,7 +382,7 @@ async function loadTemplatesFromDir(
|
|
|
382
382
|
entries.sort((a, b) => a.split("/").length - b.split("/").length);
|
|
383
383
|
|
|
384
384
|
for (const entry of entries) {
|
|
385
|
-
const fullPath = join(dir, entry);
|
|
385
|
+
const fullPath = path.join(dir, entry);
|
|
386
386
|
const file = Bun.file(fullPath);
|
|
387
387
|
|
|
388
388
|
try {
|
|
@@ -409,7 +409,7 @@ async function loadTemplatesFromDir(
|
|
|
409
409
|
// Get description from frontmatter or first non-empty line
|
|
410
410
|
let description = String(frontmatter.description || "");
|
|
411
411
|
if (!description) {
|
|
412
|
-
const firstLine = body.split("\n").find(
|
|
412
|
+
const firstLine = body.split("\n").find(line => line.trim());
|
|
413
413
|
if (firstLine) {
|
|
414
414
|
// Truncate if too long
|
|
415
415
|
description = firstLine.slice(0, 60);
|
|
@@ -461,11 +461,11 @@ export async function loadPromptTemplates(options: LoadPromptTemplatesOptions =
|
|
|
461
461
|
|
|
462
462
|
// 1. Load global templates from agentDir/prompts/
|
|
463
463
|
// Note: if agentDir is provided, it should be the agent dir, not the prompts dir
|
|
464
|
-
const globalPromptsDir = options.agentDir ? join(options.agentDir, "prompts") : resolvedAgentDir;
|
|
464
|
+
const globalPromptsDir = options.agentDir ? path.join(options.agentDir, "prompts") : resolvedAgentDir;
|
|
465
465
|
templates.push(...(await loadTemplatesFromDir(globalPromptsDir, "user")));
|
|
466
466
|
|
|
467
467
|
// 2. Load project templates from cwd/{CONFIG_DIR_NAME}/prompts/
|
|
468
|
-
const projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, "prompts");
|
|
468
|
+
const projectPromptsDir = path.resolve(resolvedCwd, CONFIG_DIR_NAME, "prompts");
|
|
469
469
|
templates.push(...(await loadTemplatesFromDir(projectPromptsDir, "project")));
|
|
470
470
|
|
|
471
471
|
return templates;
|
|
@@ -482,7 +482,7 @@ export function expandPromptTemplate(text: string, templates: PromptTemplate[]):
|
|
|
482
482
|
const templateName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
483
483
|
const argsString = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1);
|
|
484
484
|
|
|
485
|
-
const template = templates.find(
|
|
485
|
+
const template = templates.find(t => t.name === templateName);
|
|
486
486
|
if (template) {
|
|
487
487
|
const args = parseCommandArgs(argsString);
|
|
488
488
|
const argsText = args.join(" ");
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { YAML } from "bun";
|
|
5
|
+
import { type Settings as SettingsItem, settingsCapability } from "../capability/settings";
|
|
6
|
+
import { getAgentDbPath, getAgentDir } from "../config";
|
|
7
|
+
import { loadCapability } from "../discovery";
|
|
8
|
+
import type { SymbolPreset } from "../modes/theme/theme";
|
|
9
|
+
import { AgentStorage } from "../session/agent-storage";
|
|
10
|
+
import { withFileLock } from "./file-lock";
|
|
9
11
|
|
|
10
12
|
export interface CompactionSettings {
|
|
11
13
|
enabled?: boolean; // default: true
|
|
@@ -117,6 +119,15 @@ export interface PythonSettings {
|
|
|
117
119
|
sharedGateway?: boolean;
|
|
118
120
|
}
|
|
119
121
|
|
|
122
|
+
export interface CommitSettings {
|
|
123
|
+
mapReduceEnabled?: boolean;
|
|
124
|
+
mapReduceMinFiles?: number;
|
|
125
|
+
mapReduceMaxFileTokens?: number;
|
|
126
|
+
mapReduceTimeoutMs?: number;
|
|
127
|
+
mapReduceMaxConcurrency?: number;
|
|
128
|
+
changelogMaxDiffChars?: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
120
131
|
export interface EditSettings {
|
|
121
132
|
fuzzyMatch?: boolean; // default: true (accept high-confidence fuzzy matches for whitespace/indentation)
|
|
122
133
|
fuzzyThreshold?: number; // default: 0.95 (similarity threshold for fuzzy matching)
|
|
@@ -191,6 +202,7 @@ export interface Settings {
|
|
|
191
202
|
interruptMode?: "immediate" | "wait";
|
|
192
203
|
theme?: string;
|
|
193
204
|
symbolPreset?: SymbolPreset; // default: uses theme's preset or "unicode"
|
|
205
|
+
colorBlindMode?: boolean; // default: false (use blue instead of green for diff additions)
|
|
194
206
|
compaction?: CompactionSettings;
|
|
195
207
|
branchSummary?: BranchSummarySettings;
|
|
196
208
|
retry?: RetrySettings;
|
|
@@ -214,6 +226,7 @@ export interface Settings {
|
|
|
214
226
|
mcp?: MCPSettings;
|
|
215
227
|
lsp?: LspSettings;
|
|
216
228
|
python?: PythonSettings;
|
|
229
|
+
commit?: CommitSettings;
|
|
217
230
|
edit?: EditSettings;
|
|
218
231
|
ttsr?: TtsrSettings;
|
|
219
232
|
todoCompletion?: TodoCompletionSettings;
|
|
@@ -330,7 +343,7 @@ function normalizeBashInterceptorSettings(
|
|
|
330
343
|
patterns = DEFAULT_BASH_INTERCEPTOR_RULES;
|
|
331
344
|
} else if (Array.isArray(rawPatterns)) {
|
|
332
345
|
patterns = rawPatterns
|
|
333
|
-
.map(
|
|
346
|
+
.map(rule => normalizeBashInterceptorRule(rule))
|
|
334
347
|
.filter((rule): rule is BashInterceptorRule => rule !== null);
|
|
335
348
|
} else {
|
|
336
349
|
patterns = DEFAULT_BASH_INTERCEPTOR_RULES;
|
|
@@ -359,7 +372,7 @@ function hasNerdFonts(): boolean {
|
|
|
359
372
|
const termProgram = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
360
373
|
const term = (process.env.TERM || "").toLowerCase();
|
|
361
374
|
const nerdTerms = ["iterm", "wezterm", "kitty", "ghostty", "alacritty"];
|
|
362
|
-
cachedNerdFonts = nerdTerms.some(
|
|
375
|
+
cachedNerdFonts = nerdTerms.some(candidate => termProgram.includes(candidate) || term.includes(candidate));
|
|
363
376
|
return cachedNerdFonts;
|
|
364
377
|
}
|
|
365
378
|
|
|
@@ -424,8 +437,10 @@ function deepMergeSettings(base: Settings, overrides: Settings): Settings {
|
|
|
424
437
|
}
|
|
425
438
|
|
|
426
439
|
export class SettingsManager {
|
|
427
|
-
/** SQLite storage for
|
|
440
|
+
/** SQLite storage for auth/cache (null for in-memory mode) */
|
|
428
441
|
private storage: AgentStorage | null;
|
|
442
|
+
/** Path to config.yml (null for in-memory mode) */
|
|
443
|
+
private configPath: string | null;
|
|
429
444
|
private cwd: string | null;
|
|
430
445
|
private globalSettings: Settings;
|
|
431
446
|
private overrides: Settings;
|
|
@@ -434,7 +449,8 @@ export class SettingsManager {
|
|
|
434
449
|
|
|
435
450
|
/**
|
|
436
451
|
* Private constructor - use static factory methods instead.
|
|
437
|
-
* @param storage - SQLite storage instance for
|
|
452
|
+
* @param storage - SQLite storage instance for auth/cache, or null for in-memory mode
|
|
453
|
+
* @param configPath - Path to config.yml for persistence, or null for in-memory mode
|
|
438
454
|
* @param cwd - Current working directory for project settings discovery
|
|
439
455
|
* @param initialSettings - Initial global settings to use
|
|
440
456
|
* @param persist - Whether to persist settings changes to storage
|
|
@@ -442,12 +458,14 @@ export class SettingsManager {
|
|
|
442
458
|
*/
|
|
443
459
|
private constructor(
|
|
444
460
|
storage: AgentStorage | null,
|
|
461
|
+
configPath: string | null,
|
|
445
462
|
cwd: string | null,
|
|
446
463
|
initialSettings: Settings,
|
|
447
464
|
persist: boolean,
|
|
448
465
|
projectSettings: Settings,
|
|
449
466
|
) {
|
|
450
467
|
this.storage = storage;
|
|
468
|
+
this.configPath = configPath;
|
|
451
469
|
this.cwd = cwd;
|
|
452
470
|
this.persist = persist;
|
|
453
471
|
this.globalSettings = initialSettings;
|
|
@@ -479,14 +497,17 @@ export class SettingsManager {
|
|
|
479
497
|
}
|
|
480
498
|
|
|
481
499
|
/**
|
|
482
|
-
* Create a SettingsManager that loads from persistent
|
|
500
|
+
* Create a SettingsManager that loads from persistent config.yml.
|
|
483
501
|
* @param cwd - Current working directory for project settings discovery
|
|
484
|
-
* @param agentDir - Agent directory containing
|
|
502
|
+
* @param agentDir - Agent directory containing config.yml
|
|
485
503
|
* @returns Configured SettingsManager with merged global and user settings
|
|
486
504
|
*/
|
|
487
505
|
static async create(cwd: string = process.cwd(), agentDir: string = getAgentDir()): Promise<SettingsManager> {
|
|
488
|
-
const
|
|
489
|
-
await
|
|
506
|
+
const configPath = path.join(agentDir, "config.yml");
|
|
507
|
+
const storage = await AgentStorage.open(getAgentDbPath(agentDir));
|
|
508
|
+
|
|
509
|
+
// Migrate from legacy storage if config.yml doesn't exist
|
|
510
|
+
await SettingsManager.migrateToYaml(storage, agentDir, configPath);
|
|
490
511
|
|
|
491
512
|
// Use capability API to load user-level settings from all providers
|
|
492
513
|
const result = await loadCapability(settingsCapability.id, { cwd });
|
|
@@ -499,14 +520,14 @@ export class SettingsManager {
|
|
|
499
520
|
}
|
|
500
521
|
}
|
|
501
522
|
|
|
502
|
-
// Load persisted settings from
|
|
503
|
-
const storedSettings = SettingsManager.
|
|
523
|
+
// Load persisted settings from config.yml
|
|
524
|
+
const storedSettings = await SettingsManager.loadFromYaml(configPath);
|
|
504
525
|
globalSettings = deepMergeSettings(globalSettings, storedSettings);
|
|
505
526
|
|
|
506
527
|
// Load project settings before construction (constructor is sync)
|
|
507
528
|
const projectSettings = await SettingsManager.loadProjectSettingsStatic(cwd);
|
|
508
529
|
|
|
509
|
-
return new SettingsManager(storage, cwd, globalSettings, true, projectSettings);
|
|
530
|
+
return new SettingsManager(storage, configPath, cwd, globalSettings, true, projectSettings);
|
|
510
531
|
}
|
|
511
532
|
|
|
512
533
|
/**
|
|
@@ -515,7 +536,7 @@ export class SettingsManager {
|
|
|
515
536
|
* @returns SettingsManager that won't persist changes to disk
|
|
516
537
|
*/
|
|
517
538
|
static inMemory(settings: Partial<Settings> = {}): SettingsManager {
|
|
518
|
-
return new SettingsManager(null, null, settings, false, {});
|
|
539
|
+
return new SettingsManager(null, null, null, settings, false, {});
|
|
519
540
|
}
|
|
520
541
|
|
|
521
542
|
/**
|
|
@@ -534,41 +555,89 @@ export class SettingsManager {
|
|
|
534
555
|
}
|
|
535
556
|
|
|
536
557
|
/**
|
|
537
|
-
* Load settings from
|
|
538
|
-
* @param
|
|
539
|
-
* @returns Parsed and migrated settings, or empty object if
|
|
558
|
+
* Load settings from config.yml, applying any schema migrations.
|
|
559
|
+
* @param configPath - Path to config.yml, or null for in-memory mode
|
|
560
|
+
* @returns Parsed and migrated settings, or empty object if file doesn't exist
|
|
540
561
|
*/
|
|
541
|
-
private static
|
|
542
|
-
if (!
|
|
562
|
+
private static async loadFromYaml(configPath: string | null): Promise<Settings> {
|
|
563
|
+
if (!configPath) {
|
|
543
564
|
return {};
|
|
544
565
|
}
|
|
545
|
-
|
|
546
|
-
|
|
566
|
+
try {
|
|
567
|
+
const content = await Bun.file(configPath).text();
|
|
568
|
+
const parsed = YAML.parse(content);
|
|
569
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
570
|
+
return {};
|
|
571
|
+
}
|
|
572
|
+
return SettingsManager.migrateSettings(parsed as Record<string, unknown>);
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (isEnoent(error)) return {};
|
|
575
|
+
logger.warn("SettingsManager failed to load config.yml", { path: configPath, error: String(error) });
|
|
547
576
|
return {};
|
|
548
577
|
}
|
|
549
|
-
return SettingsManager.migrateSettings(settings as Record<string, unknown>);
|
|
550
578
|
}
|
|
551
579
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
580
|
+
/**
|
|
581
|
+
* Migrate settings from legacy sources to config.yml.
|
|
582
|
+
* Migration order: settings.json -> agent.db -> config.yml
|
|
583
|
+
* Only migrates if config.yml doesn't exist.
|
|
584
|
+
*/
|
|
585
|
+
private static async migrateToYaml(storage: AgentStorage, agentDir: string, configPath: string): Promise<void> {
|
|
558
586
|
try {
|
|
559
|
-
|
|
560
|
-
|
|
587
|
+
await Bun.file(configPath).text();
|
|
588
|
+
return;
|
|
589
|
+
} catch (err) {
|
|
590
|
+
if (!isEnoent(err)) {
|
|
591
|
+
logger.warn("SettingsManager failed to check config.yml", { path: configPath, error: String(err) });
|
|
561
592
|
return;
|
|
562
593
|
}
|
|
563
|
-
|
|
564
|
-
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
let settings: Settings = {};
|
|
597
|
+
let migrated = false;
|
|
598
|
+
|
|
599
|
+
// 1. Try to migrate from settings.json (oldest legacy format)
|
|
600
|
+
const settingsJsonPath = path.join(agentDir, "settings.json");
|
|
601
|
+
try {
|
|
602
|
+
const parsed = JSON.parse(await Bun.file(settingsJsonPath).text());
|
|
603
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
604
|
+
settings = deepMergeSettings(settings, SettingsManager.migrateSettings(parsed));
|
|
605
|
+
migrated = true;
|
|
606
|
+
// Backup settings.json
|
|
607
|
+
try {
|
|
608
|
+
await fs.rename(settingsJsonPath, `${settingsJsonPath}.bak`);
|
|
609
|
+
} catch (error) {
|
|
610
|
+
logger.warn("SettingsManager failed to backup settings.json", { error: String(error) });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (!isEnoent(error)) {
|
|
615
|
+
logger.warn("SettingsManager failed to read settings.json", { error: String(error) });
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// 2. Migrate from agent.db settings table
|
|
620
|
+
try {
|
|
621
|
+
const dbSettings = storage.getSettings();
|
|
622
|
+
if (dbSettings) {
|
|
623
|
+
settings = deepMergeSettings(
|
|
624
|
+
settings,
|
|
625
|
+
SettingsManager.migrateSettings(dbSettings as Record<string, unknown>),
|
|
626
|
+
);
|
|
627
|
+
migrated = true;
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
logger.warn("SettingsManager failed to read agent.db settings", { error: String(error) });
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// 3. Write merged settings to config.yml if we found any
|
|
634
|
+
if (migrated && Object.keys(settings).length > 0) {
|
|
565
635
|
try {
|
|
566
|
-
await
|
|
636
|
+
await Bun.write(configPath, YAML.stringify(settings, null, 2));
|
|
637
|
+
logger.debug("SettingsManager migrated settings to config.yml", { path: configPath });
|
|
567
638
|
} catch (error) {
|
|
568
|
-
logger.warn("SettingsManager failed to
|
|
639
|
+
logger.warn("SettingsManager failed to write config.yml", { path: configPath, error: String(error) });
|
|
569
640
|
}
|
|
570
|
-
} catch (error) {
|
|
571
|
-
logger.warn("SettingsManager failed to migrate settings.json", { error: String(error) });
|
|
572
641
|
}
|
|
573
642
|
}
|
|
574
643
|
|
|
@@ -620,22 +689,24 @@ export class SettingsManager {
|
|
|
620
689
|
}
|
|
621
690
|
|
|
622
691
|
/**
|
|
623
|
-
* Persist current global settings to
|
|
624
|
-
*
|
|
692
|
+
* Persist current global settings to config.yml and rebuild merged settings.
|
|
693
|
+
* Uses file locking to prevent concurrent write races.
|
|
625
694
|
*/
|
|
626
695
|
private async save(): Promise<void> {
|
|
627
|
-
if (this.persist && this.
|
|
696
|
+
if (this.persist && this.configPath) {
|
|
697
|
+
const configPath = this.configPath;
|
|
628
698
|
try {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
699
|
+
await withFileLock(configPath, async () => {
|
|
700
|
+
const currentSettings = await SettingsManager.loadFromYaml(configPath);
|
|
701
|
+
const mergedSettings = deepMergeSettings(currentSettings, this.globalSettings);
|
|
702
|
+
this.globalSettings = mergedSettings;
|
|
703
|
+
await Bun.write(configPath, YAML.stringify(this.globalSettings, null, 2));
|
|
704
|
+
});
|
|
633
705
|
} catch (error) {
|
|
634
706
|
logger.warn("SettingsManager save failed", { error: String(error) });
|
|
635
707
|
}
|
|
636
708
|
}
|
|
637
709
|
|
|
638
|
-
// Always re-merge to update active settings (needed for both file and inMemory modes)
|
|
639
710
|
const projectSettings = await this.loadProjectSettings();
|
|
640
711
|
this.rebuildSettings(projectSettings);
|
|
641
712
|
}
|
|
@@ -724,6 +795,15 @@ export class SettingsManager {
|
|
|
724
795
|
await this.save();
|
|
725
796
|
}
|
|
726
797
|
|
|
798
|
+
getColorBlindMode(): boolean {
|
|
799
|
+
return this.settings.colorBlindMode ?? false;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
async setColorBlindMode(enabled: boolean): Promise<void> {
|
|
803
|
+
this.globalSettings.colorBlindMode = enabled;
|
|
804
|
+
await this.save();
|
|
805
|
+
}
|
|
806
|
+
|
|
727
807
|
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
|
|
728
808
|
return this.settings.defaultThinkingLevel;
|
|
729
809
|
}
|
|
@@ -800,6 +880,17 @@ export class SettingsManager {
|
|
|
800
880
|
};
|
|
801
881
|
}
|
|
802
882
|
|
|
883
|
+
getCommitSettings(): Required<CommitSettings> {
|
|
884
|
+
return {
|
|
885
|
+
mapReduceEnabled: this.settings.commit?.mapReduceEnabled ?? true,
|
|
886
|
+
mapReduceMinFiles: this.settings.commit?.mapReduceMinFiles ?? 4,
|
|
887
|
+
mapReduceMaxFileTokens: this.settings.commit?.mapReduceMaxFileTokens ?? 50_000,
|
|
888
|
+
mapReduceTimeoutMs: this.settings.commit?.mapReduceTimeoutMs ?? 120_000,
|
|
889
|
+
mapReduceMaxConcurrency: this.settings.commit?.mapReduceMaxConcurrency ?? 5,
|
|
890
|
+
changelogMaxDiffChars: this.settings.commit?.changelogMaxDiffChars ?? 120_000,
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
|
|
803
894
|
getRetryMaxRetries(): number {
|
|
804
895
|
return this.settings.retry?.maxRetries ?? 3;
|
|
805
896
|
}
|