@gajae-code/coding-agent 0.18.11 → 0.19.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 +760 -0
- package/dist/types/async/job-manager.d.ts +7 -3
- package/dist/types/async/result-formatting.d.ts +2 -0
- package/dist/types/autoresearch/git.d.ts +1 -1
- package/dist/types/capability/fs.d.ts +2 -2
- package/dist/types/capability/rule.d.ts +7 -2
- package/dist/types/cli/accounts-cli.d.ts +2 -2
- package/dist/types/cli/append-system-prompt.d.ts +6 -0
- package/dist/types/cli/args.d.ts +7 -2
- package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
- package/dist/types/cli/customize-doctor.d.ts +4 -3
- package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
- package/dist/types/cli/install-activation.d.ts +10 -4
- package/dist/types/cli/public-command-errors.d.ts +2 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +21 -3
- package/dist/types/cli-main.d.ts +0 -6
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/launch.d.ts +0 -6
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +13 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +53 -1
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +44 -0
- package/dist/types/config/file-lock.d.ts +52 -3
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +79 -9
- package/dist/types/config/model-registry.d.ts +72 -8
- package/dist/types/config/model-resolver.d.ts +7 -4
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +57 -4
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/customization/import.d.ts +2 -0
- package/dist/types/customization/types.d.ts +1 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/dap/session.d.ts +11 -2
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +14 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/export/ttsr.d.ts +19 -0
- package/dist/types/extensibility/extensions/types.d.ts +5 -1
- package/dist/types/extensibility/slash-commands.d.ts +1 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/content.d.ts +5 -6
- package/dist/types/internal-urls/types.d.ts +2 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
- package/dist/types/main.d.ts +23 -18
- package/dist/types/migrate/action-planner.d.ts +10 -1
- package/dist/types/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +42 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/hook-module.d.ts +23 -0
- package/dist/types/migrate/report.d.ts +2 -1
- package/dist/types/migrate/types.d.ts +82 -3
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +43 -0
- package/dist/types/modes/components/settings-selector.d.ts +6 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
- package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
- package/dist/types/runtime-mcp/manager.d.ts +7 -0
- package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
- package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
- package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +3 -3
- package/dist/types/sdk/broker/broker.d.ts +29 -2
- package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
- package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
- package/dist/types/sdk/broker/ensure.d.ts +141 -9
- package/dist/types/sdk/broker/hop.d.ts +45 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +6 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +44 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
- package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/control/operations.d.ts +5 -1
- package/dist/types/sdk/host/events.d.ts +4 -0
- package/dist/types/sdk/host/host.d.ts +2 -1
- package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
- package/dist/types/sdk/host/session-runtime.d.ts +40 -8
- package/dist/types/sdk/host/surface-policy.d.ts +2 -1
- package/dist/types/sdk/lifecycle/service.d.ts +12 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
- package/dist/types/sdk/prompt-status.d.ts +11 -4
- package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
- package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +107 -9
- package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
- package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
- package/dist/types/session/messages.d.ts +5 -1
- package/dist/types/session/session-manager.d.ts +29 -3
- package/dist/types/session/startup-auth-config.d.ts +24 -2
- package/dist/types/session/streaming-output.d.ts +11 -0
- package/dist/types/session/terminal-abort.d.ts +3 -1
- package/dist/types/session-import/service.d.ts +1 -1
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +20 -4
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/executor.d.ts +19 -2
- package/dist/types/task/role-body.d.ts +11 -0
- package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
- package/dist/types/tools/atomic-file-write.d.ts +9 -7
- package/dist/types/tools/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +17 -0
- package/dist/types/tools/bash-skill-urls.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/descriptors.d.ts +15 -2
- package/dist/types/tools/fetch.d.ts +7 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/irc.d.ts +5 -3
- package/dist/types/tools/python.d.ts +1 -1
- package/dist/types/tools/report-issue.d.ts +41 -0
- package/dist/types/tools/subagent.d.ts +23 -0
- package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/file-mentions.d.ts +5 -0
- package/dist/types/utils/image-limits.d.ts +7 -0
- package/dist/types/utils/image-loading.d.ts +0 -1
- package/dist/types/utils/open.d.ts +0 -1
- package/dist/types/utils/pasted-image-loading.d.ts +1 -5
- package/dist/types/utils/prompt-suggestion.d.ts +2 -2
- package/dist/types/utils/shell-snapshot.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +13 -3
- package/dist/types/web/scrapers/types.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +6 -7
- package/dist/types/web/search/providers/insane.d.ts +7 -1
- package/dist/types/web/search/providers/searxng.d.ts +5 -0
- package/package.json +10 -9
- package/scripts/acp-conformance-agent.ts +12 -2
- package/scripts/build-binary.ts +2 -1
- package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
- package/scripts/generate-docs-index.ts +8 -1
- package/scripts/generate-sdk-operation-inventory.ts +38 -4
- package/src/async/job-manager.ts +356 -56
- package/src/async/result-formatting.ts +40 -0
- package/src/autoresearch/git.ts +9 -2
- package/src/autoresearch/prompts/prompt-setup.md +1 -1
- package/src/capability/fs.ts +58 -22
- package/src/capability/index.ts +2 -2
- package/src/capability/rule.ts +11 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -3
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +19 -6
- package/src/cli/public-command-errors.ts +6 -0
- package/src/cli/root-flags.ts +2 -4
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +471 -13
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +277 -50
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/message.ts +10 -3
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +50 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +742 -0
- package/src/config/file-lock.ts +1615 -328
- package/src/config/keybindings.ts +154 -7
- package/src/config/model-bindings-applier.ts +85 -47
- package/src/config/model-discovery-manager.ts +10 -0
- package/src/config/model-profile-activation.ts +889 -148
- package/src/config/model-registry.ts +1706 -205
- package/src/config/model-resolver.ts +52 -22
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +73 -4
- package/src/config/settings.ts +460 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +7 -1
- package/src/customization/import.ts +279 -8
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +89 -6
- package/src/debug/report-bundle.ts +90 -2
- package/src/debug/system-info.ts +8 -3
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/builtin.ts +4 -3
- package/src/discovery/helpers.ts +25 -16
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +204 -22
- package/src/edit/modes/patch.ts +214 -8
- package/src/edit/modes/replace.ts +136 -0
- package/src/eval/js/context-manager.ts +29 -3
- package/src/eval/js/worker-entry.ts +51 -18
- package/src/eval/py/executor.ts +14 -4
- package/src/eval/py/runner.py +144 -5
- package/src/eval/py/runtime.ts +44 -4
- package/src/exec/bash-executor.ts +81 -4
- package/src/exec/bash-shell-guardian.ts +4 -1
- package/src/exec/bash-shell-supervisor.ts +8 -4
- package/src/exec/isolated-shell.ts +5 -1
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +86 -6
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +10 -1
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
- package/src/extensibility/extensions/types.ts +5 -1
- package/src/extensibility/hooks/loader.ts +10 -2
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/extensibility/plugins/marketplace/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +37 -7
- package/src/gjc-runtime/launch-tmux.ts +30 -15
- package/src/gjc-runtime/launch-worktree.test.ts +148 -0
- package/src/gjc-runtime/launch-worktree.ts +101 -14
- package/src/gjc-runtime/managed-owner-admission.ts +46 -2
- package/src/gjc-runtime/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- package/src/gjc-runtime/session-resolution.ts +38 -6
- package/src/gjc-runtime/session-state-lock.ts +59 -14
- package/src/gjc-runtime/state-runtime.ts +23 -19
- package/src/gjc-runtime/state-writer.ts +109 -5
- package/src/gjc-runtime/tmux-sessions.ts +93 -13
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
- package/src/gjc-runtime/ultragoal-guard.ts +9 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
- package/src/harness-control-plane/finalize.ts +11 -0
- package/src/harness-control-plane/receipt-spool.ts +105 -28
- package/src/harness-control-plane/storage.ts +124 -6
- package/src/hindsight/content.ts +116 -16
- package/src/hindsight/mental-models.ts +22 -10
- package/src/hindsight/state.ts +7 -4
- package/src/hooks/native-skill-hook.ts +17 -12
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +23 -22
- package/src/internal-urls/local-protocol.ts +167 -8
- package/src/internal-urls/types.ts +2 -0
- package/src/lsp/client.ts +2 -1
- package/src/lsp/clients/biome-client.ts +2 -0
- package/src/lsp/clients/swiftlint-client.ts +2 -0
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +574 -2
- package/src/migrate/adapters/claude-code.ts +162 -5
- package/src/migrate/adapters/codex.ts +77 -7
- package/src/migrate/adapters/index.ts +258 -5
- package/src/migrate/adapters/opencode.ts +10 -1
- package/src/migrate/executor.ts +222 -7
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +63 -2
- package/src/migrate/types.ts +84 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/customization/customization-dashboard.ts +7 -0
- package/src/modes/components/customization/import-wizard.ts +29 -3
- package/src/modes/components/model-selector.ts +157 -103
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/components/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +300 -9
- package/src/modes/controllers/event-controller.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -1
- package/src/modes/controllers/goal-mode-controller.ts +79 -10
- package/src/modes/controllers/input-controller.ts +2 -0
- package/src/modes/controllers/plan-mode-controller.ts +66 -11
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +76 -7
- package/src/modes/interactive-mode.ts +123 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- package/src/modes/theme/theme.ts +15 -0
- package/src/modes/utils/host-status.ts +21 -10
- package/src/prompts/agent-fragments/browser-aside.md +2 -2
- package/src/prompts/system/irc-incoming.md +3 -1
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/report-issue.md +13 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-credential-selector.ts +2 -2
- package/src/runtime-mcp/content-limits.ts +7 -0
- package/src/runtime-mcp/manager-pool.test.ts +5 -4
- package/src/runtime-mcp/manager.ts +40 -3
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +194 -21
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +10 -5
- package/src/sdk/broker/broker.ts +484 -85
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1214 -268
- package/src/sdk/broker/hop.ts +286 -0
- package/src/sdk/broker/lifecycle-ledger.ts +38 -11
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +91 -16
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +460 -35
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/session-control.ts +2 -0
- package/src/sdk/bus/slack-daemon.ts +105 -9
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -2
- package/src/sdk/bus/threaded-render.ts +20 -1
- package/src/sdk/cli/session-cli.ts +23 -6
- package/src/sdk/host/control/dispatch.ts +13 -1
- package/src/sdk/host/control/operations.ts +10 -1
- package/src/sdk/host/events.ts +67 -4
- package/src/sdk/host/host.ts +8 -2
- package/src/sdk/host/prompt-image-upload.ts +438 -0
- package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
- package/src/sdk/host/session-runtime.test.ts +1737 -129
- package/src/sdk/host/session-runtime.ts +684 -83
- package/src/sdk/host/surface-policy.ts +4 -0
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
- package/src/sdk/host/websocket-transport.ts +19 -7
- package/src/sdk/lifecycle/service.ts +15 -1
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +81 -12
- package/src/sdk/protocol/operation-inventory.generated.json +261 -2
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +237 -97
- package/src/session/agent-session.ts +2726 -479
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +173 -57
- package/src/session/internal/managed-session-storage.ts +85 -12
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +326 -19
- package/src/session/startup-auth-config.ts +116 -8
- package/src/session/streaming-output.ts +262 -4
- package/src/session/terminal-abort.ts +14 -2
- package/src/session-import/redact.ts +53 -2
- package/src/session-import/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +2145 -206
- package/src/slash-commands/builtin-registry.ts +21 -6
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/mcp.ts +11 -3
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/ssh/ssh-executor.ts +9 -2
- package/src/stt/recorder.ts +26 -9
- package/src/system-prompt.ts +61 -16
- package/src/task/executor.ts +115 -20
- package/src/task/index.ts +389 -175
- package/src/task/role-body.ts +84 -0
- package/src/task/token-log-mode.test.ts +162 -0
- package/src/task/token-log.ts +91 -2
- package/src/tools/archive-reader.ts +650 -37
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/ast-grep.ts +7 -2
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +15 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +214 -6
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +113 -26
- package/src/tools/browser/tab-worker.ts +39 -13
- package/src/tools/browser.ts +17 -7
- package/src/tools/cron.ts +10 -1
- package/src/tools/debug.ts +16 -8
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +50 -6
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +93 -4
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/index.ts +2 -0
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +74 -5
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +26 -37
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +118 -5
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +32 -4
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +42 -3
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +12 -4
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +75 -7
- package/src/utils/git.ts +38 -7
- package/src/utils/image-limits.ts +8 -0
- package/src/utils/image-loading.ts +1 -1
- package/src/utils/open.ts +73 -4
- package/src/utils/pasted-image-loading.ts +9 -8
- package/src/utils/prompt-suggestion.ts +5 -4
- package/src/utils/shell-snapshot.ts +9 -1
- package/src/utils/title-generator.ts +72 -22
- package/src/web/scrapers/index.ts +3 -1
- package/src/web/scrapers/types.ts +8 -0
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
- package/src/web/search/providers/insane.ts +91 -28
- package/src/web/search/providers/searxng.ts +62 -10
package/src/config/settings.ts
CHANGED
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
validateAutoroutingEffective,
|
|
63
63
|
validateAutoroutingLocal,
|
|
64
64
|
} from "./autorouting-contract";
|
|
65
|
+
import type { ConfigHotReloadFileSnapshot } from "./config-hot-reload";
|
|
65
66
|
import { isModelSelectorValue, type ModelSelectorValue, normalizeModelSelectorValue } from "./model-selector-value";
|
|
66
67
|
|
|
67
68
|
import {
|
|
@@ -92,6 +93,53 @@ export interface RawSettings {
|
|
|
92
93
|
[key: string]: unknown;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
/** Validated candidate view. `get` includes local patches and effective overlays. */
|
|
97
|
+
export interface SettingsGlobalConfigCandidate {
|
|
98
|
+
readonly configPath: string;
|
|
99
|
+
readonly diagnostics: SettingsSchemaReport;
|
|
100
|
+
get<P extends SettingPath>(settingPath: P): SettingValue<P>;
|
|
101
|
+
/** Candidate global values include pending local patches, but exclude other layers. */
|
|
102
|
+
getGlobal<P extends SettingPath>(settingPath: P): SettingValue<P> | undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface SettingsConfigReloadPublication {
|
|
106
|
+
finalize(): void;
|
|
107
|
+
rollback(): void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export class SettingsGlobalConfigReloadError extends Error {
|
|
111
|
+
constructor(
|
|
112
|
+
message: string,
|
|
113
|
+
readonly configPath: string | null,
|
|
114
|
+
readonly diagnostics?: SettingsSchemaReport,
|
|
115
|
+
) {
|
|
116
|
+
super(message);
|
|
117
|
+
this.name = "SettingsGlobalConfigReloadError";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface SettingsGlobalConfigCandidateState {
|
|
122
|
+
owner: Settings;
|
|
123
|
+
configPath: string;
|
|
124
|
+
globalWithPendingPatches: RawSettings;
|
|
125
|
+
effective: RawSettings;
|
|
126
|
+
diagnostics: SettingsSchemaReport;
|
|
127
|
+
rawConfig: RawSettings;
|
|
128
|
+
currentGlobal: RawSettings;
|
|
129
|
+
currentProject: RawSettings;
|
|
130
|
+
currentOverrides: RawSettings;
|
|
131
|
+
currentMerged: RawSettings;
|
|
132
|
+
cwd: string;
|
|
133
|
+
sourcePresent: boolean;
|
|
134
|
+
futureSchemaVersion: boolean;
|
|
135
|
+
published: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const settingsGlobalConfigCandidateStates = new WeakMap<
|
|
139
|
+
SettingsGlobalConfigCandidate,
|
|
140
|
+
SettingsGlobalConfigCandidateState
|
|
141
|
+
>();
|
|
142
|
+
|
|
95
143
|
const UNSAFE_EDIT_VARIANT_PATTERNS = new Set(["__proto__", "constructor", "prototype"]);
|
|
96
144
|
|
|
97
145
|
const CONFIG_ROOT_WORKFLOW_MIGRATION_KEYS: readonly WorkflowSettingKey[] = [
|
|
@@ -263,6 +311,12 @@ export class NotificationSettingsOverrideError extends Error {
|
|
|
263
311
|
}
|
|
264
312
|
|
|
265
313
|
const LOCAL_NOTIFICATION_SETTING_KEYS = new Set(["terminalBell", "bellOnComplete", "bellOnApproval", "bellOnAsk"]);
|
|
314
|
+
/** `auth.*` keys that select credentials; startup reads them from global config only, so project copies are dropped. */
|
|
315
|
+
const GLOBAL_ONLY_AUTH_SETTING_KEYS = new Set([
|
|
316
|
+
"credentialPins",
|
|
317
|
+
"credentialPinStoreIdentity",
|
|
318
|
+
"credentialPreferences",
|
|
319
|
+
]);
|
|
266
320
|
const LOCAL_NOTIFICATION_SETTING_PATHS = new Set(
|
|
267
321
|
[...LOCAL_NOTIFICATION_SETTING_KEYS].map(key => `notifications.${key}`),
|
|
268
322
|
);
|
|
@@ -336,6 +390,13 @@ const GLOBAL_ONLY_SETTINGS = new Set<SettingPath>([
|
|
|
336
390
|
"paseo.autoImport",
|
|
337
391
|
"ui.language",
|
|
338
392
|
"telemetry.enabled",
|
|
393
|
+
// Destination of the operator Hindsight server. A project file must not redirect it.
|
|
394
|
+
"hindsight.apiUrl",
|
|
395
|
+
// Destination of generic remote compaction. A project file must not redirect the transcript POST.
|
|
396
|
+
"compaction.remoteEndpoint",
|
|
397
|
+
// Operator consent for repository skills. A project file must not flip it.
|
|
398
|
+
"skills.trustProjectSkills",
|
|
399
|
+
"skills.enablePiProject",
|
|
339
400
|
]);
|
|
340
401
|
const LEGACY_THEME_NAME_REPLACEMENTS = {
|
|
341
402
|
dark: "red-claw",
|
|
@@ -544,6 +605,8 @@ export class Settings implements NotificationSettingsReader {
|
|
|
544
605
|
#schemaMigrationPending = false;
|
|
545
606
|
/** A newer config schema must never be rewritten by legacy migrations. */
|
|
546
607
|
#futureSchemaVersion = false;
|
|
608
|
+
/** Set only after a valid disk-backed global config has been loaded or published. */
|
|
609
|
+
#hasAcceptedGlobalConfigFile = false;
|
|
547
610
|
#hasMalformedConfigRoot = false;
|
|
548
611
|
/** YAML syntax was unrecoverable, so the loaded defaults are read-only until config.yml is repaired. */
|
|
549
612
|
#hasRecoveredConfigSyntax = false;
|
|
@@ -745,6 +808,357 @@ export class Settings implements NotificationSettingsReader {
|
|
|
745
808
|
return () => this.#changeListeners.delete(listener);
|
|
746
809
|
}
|
|
747
810
|
|
|
811
|
+
/** The resolved global config.yml path, or null for in-memory settings. */
|
|
812
|
+
getGlobalConfigPath(): string | null {
|
|
813
|
+
return this.#configPath;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Validate the watcher's exact snapshot without writing or rereading it.
|
|
818
|
+
* Rebase pending local patches after prior durable operations settle.
|
|
819
|
+
*/
|
|
820
|
+
async stageGlobalConfigReload(snapshot: ConfigHotReloadFileSnapshot): Promise<SettingsGlobalConfigCandidate> {
|
|
821
|
+
const configPath = this.#configPath;
|
|
822
|
+
if (!configPath) {
|
|
823
|
+
throw new SettingsGlobalConfigReloadError(
|
|
824
|
+
"Global config reload requires a disk-backed Settings instance.",
|
|
825
|
+
null,
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (path.resolve(snapshot.path) !== path.resolve(configPath)) {
|
|
830
|
+
throw new SettingsGlobalConfigReloadError("Global config snapshot path does not match Settings.", configPath);
|
|
831
|
+
}
|
|
832
|
+
const pendingAtStage = structuredClone(this.#pendingPatchesInGenerationOrder());
|
|
833
|
+
return enqueueAtomicYamlOperation(configPath, async () => {
|
|
834
|
+
const sourcePresent = snapshot.text !== null;
|
|
835
|
+
const content = snapshot.text ?? "";
|
|
836
|
+
if (!sourcePresent) {
|
|
837
|
+
if (this.#hasAcceptedGlobalConfigFile) {
|
|
838
|
+
const diagnostics: SettingsSchemaReport = {
|
|
839
|
+
valid: false,
|
|
840
|
+
issues: [
|
|
841
|
+
{
|
|
842
|
+
path: "config.yml",
|
|
843
|
+
kind: "invalid",
|
|
844
|
+
detail: "The previously accepted global config.yml is missing.",
|
|
845
|
+
},
|
|
846
|
+
],
|
|
847
|
+
};
|
|
848
|
+
throw new SettingsGlobalConfigReloadError(
|
|
849
|
+
"Cannot stage global config reload because the previously accepted config.yml is missing.",
|
|
850
|
+
configPath,
|
|
851
|
+
diagnostics,
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
let rawConfig: RawSettings = {};
|
|
857
|
+
if (content.trim() !== "") {
|
|
858
|
+
let parsed: unknown;
|
|
859
|
+
try {
|
|
860
|
+
parsed = YAML.parse(content);
|
|
861
|
+
} catch {
|
|
862
|
+
const diagnostics: SettingsSchemaReport = {
|
|
863
|
+
valid: false,
|
|
864
|
+
issues: [
|
|
865
|
+
{
|
|
866
|
+
path: "config.yml",
|
|
867
|
+
kind: "invalid",
|
|
868
|
+
detail: "Configuration YAML syntax is invalid; repair config.yml before reloading.",
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
};
|
|
872
|
+
throw new SettingsGlobalConfigReloadError(
|
|
873
|
+
"Cannot stage global config reload because config.yml has invalid YAML syntax.",
|
|
874
|
+
configPath,
|
|
875
|
+
diagnostics,
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
if (parsed !== undefined) {
|
|
879
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
880
|
+
const diagnostics: SettingsSchemaReport = {
|
|
881
|
+
valid: false,
|
|
882
|
+
issues: [
|
|
883
|
+
{
|
|
884
|
+
path: "config.yml",
|
|
885
|
+
kind: "invalid",
|
|
886
|
+
detail: "Configuration root must be a YAML mapping.",
|
|
887
|
+
},
|
|
888
|
+
],
|
|
889
|
+
};
|
|
890
|
+
throw new SettingsGlobalConfigReloadError(
|
|
891
|
+
"Cannot stage global config reload because the config.yml root is not a mapping.",
|
|
892
|
+
configPath,
|
|
893
|
+
diagnostics,
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
rawConfig = parsed as RawSettings;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const configSchemaVersion = normalizeConfigSchemaVersion(rawConfig.configSchemaVersion);
|
|
901
|
+
const futureSchemaVersion =
|
|
902
|
+
typeof configSchemaVersion === "number" && configSchemaVersion > CONFIG_SCHEMA_VERSION;
|
|
903
|
+
const migratedRawConfig = this.#migrateRawSettings(structuredClone(rawConfig));
|
|
904
|
+
const reconciled = reconcileSettingsSchema(migratedRawConfig);
|
|
905
|
+
const diagnostics = reconciled.report;
|
|
906
|
+
for (const [settingPath, pathSegments] of [
|
|
907
|
+
["modelRoles", ["modelRoles"]],
|
|
908
|
+
["task.agentModelOverrides", ["task", "agentModelOverrides"]],
|
|
909
|
+
] as const) {
|
|
910
|
+
const value = getByPath(reconciled.settings, [...pathSegments]);
|
|
911
|
+
if (value === undefined) continue;
|
|
912
|
+
const record = rawSettingsRecord(value);
|
|
913
|
+
if (!record || Object.keys(shallowModelSelectorRecord(record)).length !== Object.keys(record).length) {
|
|
914
|
+
diagnostics.issues.push({
|
|
915
|
+
path: settingPath,
|
|
916
|
+
kind: "invalid",
|
|
917
|
+
detail: "Model selector records contain invalid values.",
|
|
918
|
+
});
|
|
919
|
+
diagnostics.valid = false;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (futureSchemaVersion) {
|
|
923
|
+
diagnostics.issues.push({
|
|
924
|
+
path: "configSchemaVersion",
|
|
925
|
+
kind: "pending-migration",
|
|
926
|
+
detail: `Configuration requires schema version ${configSchemaVersion}.`,
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
if (sourcePresent && hasLegacyCustomImageProvider(rawConfig)) {
|
|
930
|
+
diagnostics.issues.push({
|
|
931
|
+
path: "providers.image",
|
|
932
|
+
kind: "invalid",
|
|
933
|
+
detail: LEGACY_CUSTOM_IMAGE_PROVIDER_DIAGNOSTIC,
|
|
934
|
+
});
|
|
935
|
+
diagnostics.valid = false;
|
|
936
|
+
}
|
|
937
|
+
try {
|
|
938
|
+
parseNotificationSettingsSnapshot(rawConfig);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
if (!(error instanceof Error) || error.message !== "gjc_notify_daemon_invalid_configuration") throw error;
|
|
941
|
+
diagnostics.issues.push({
|
|
942
|
+
path: "notifications",
|
|
943
|
+
kind: "invalid",
|
|
944
|
+
detail: "Global notification settings are invalid.",
|
|
945
|
+
});
|
|
946
|
+
diagnostics.valid = false;
|
|
947
|
+
}
|
|
948
|
+
const currentGlobal = structuredClone(this.#global);
|
|
949
|
+
const currentProject = structuredClone(this.#project);
|
|
950
|
+
const currentOverrides = structuredClone(this.#overrides);
|
|
951
|
+
const currentMerged = structuredClone(this.#merged);
|
|
952
|
+
const globalWithPendingPatches = structuredClone(reconciled.settings) as RawSettings;
|
|
953
|
+
const rawWithPendingPatches = structuredClone(rawConfig);
|
|
954
|
+
for (const patch of [...pendingAtStage, ...this.#pendingPatchesInGenerationOrder()]) {
|
|
955
|
+
applySettingsPatch(globalWithPendingPatches, { ...patch, value: structuredClone(patch.value) });
|
|
956
|
+
applySettingsPatch(rawWithPendingPatches, { ...patch, value: structuredClone(patch.value) });
|
|
957
|
+
}
|
|
958
|
+
const effective = this.#mergeSettingsLayers(globalWithPendingPatches, currentProject, currentOverrides);
|
|
959
|
+
diagnostics.issues = diagnostics.issues.filter(
|
|
960
|
+
issue =>
|
|
961
|
+
!(
|
|
962
|
+
(issue.kind === "invalid" || issue.kind === "unknown") &&
|
|
963
|
+
(issue.path === "task.autorouting" || issue.path.startsWith("task.autorouting."))
|
|
964
|
+
),
|
|
965
|
+
);
|
|
966
|
+
for (const source of [globalWithPendingPatches, currentProject, currentOverrides]) {
|
|
967
|
+
const fragment = getByPath(source, ["task", "autorouting"]);
|
|
968
|
+
diagnostics.issues.push(
|
|
969
|
+
...validateAutoroutingLocal(fragment).map(localIssue => ({
|
|
970
|
+
path: localIssue.path ? `task.autorouting.${localIssue.path}` : "task.autorouting",
|
|
971
|
+
kind: "invalid" as const,
|
|
972
|
+
detail: localIssue.detail,
|
|
973
|
+
})),
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
const effectiveAutorouting = validateAutoroutingEffective(getByPath(effective, ["task", "autorouting"]));
|
|
977
|
+
if (!effectiveAutorouting.active && effectiveAutorouting.issue) {
|
|
978
|
+
diagnostics.issues.push({
|
|
979
|
+
path: "task.autorouting",
|
|
980
|
+
kind: "invalid",
|
|
981
|
+
detail: effectiveAutorouting.issue.detail,
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
diagnostics.valid = !diagnostics.issues.some(issue => issue.kind === "invalid");
|
|
985
|
+
if (!diagnostics.valid) {
|
|
986
|
+
throw new SettingsGlobalConfigReloadError(
|
|
987
|
+
"Cannot stage global config reload because settings validation failed.",
|
|
988
|
+
configPath,
|
|
989
|
+
structuredClone(diagnostics),
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
const state: SettingsGlobalConfigCandidateState = {
|
|
993
|
+
owner: this,
|
|
994
|
+
configPath,
|
|
995
|
+
globalWithPendingPatches,
|
|
996
|
+
effective,
|
|
997
|
+
diagnostics: structuredClone(diagnostics),
|
|
998
|
+
rawConfig: rawWithPendingPatches,
|
|
999
|
+
currentGlobal,
|
|
1000
|
+
currentProject,
|
|
1001
|
+
currentOverrides,
|
|
1002
|
+
currentMerged,
|
|
1003
|
+
cwd: this.#cwd,
|
|
1004
|
+
sourcePresent,
|
|
1005
|
+
futureSchemaVersion,
|
|
1006
|
+
published: false,
|
|
1007
|
+
};
|
|
1008
|
+
const candidate: SettingsGlobalConfigCandidate = {
|
|
1009
|
+
configPath,
|
|
1010
|
+
diagnostics: structuredClone(diagnostics),
|
|
1011
|
+
get<P extends SettingPath>(settingPath: P): SettingValue<P> {
|
|
1012
|
+
const value = getByPath(state.effective, settingPath.split("."));
|
|
1013
|
+
if (value === undefined) return structuredClone(getDefault(settingPath));
|
|
1014
|
+
const pathScopedValue = resolvePathScopedStringArray(settingPath, value, state.cwd);
|
|
1015
|
+
return structuredClone((pathScopedValue ?? value) as SettingValue<P>);
|
|
1016
|
+
},
|
|
1017
|
+
getGlobal<P extends SettingPath>(settingPath: P): SettingValue<P> | undefined {
|
|
1018
|
+
const value = getByPath(state.globalWithPendingPatches, settingPath.split("."));
|
|
1019
|
+
return value === undefined ? undefined : structuredClone(value as SettingValue<P>);
|
|
1020
|
+
},
|
|
1021
|
+
};
|
|
1022
|
+
settingsGlobalConfigCandidateStates.set(candidate, state);
|
|
1023
|
+
return Object.freeze(candidate);
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Publish a staged global config and its dependent synchronous model commit as
|
|
1029
|
+
* one in-memory transaction. A thrown commit restores settings without hooks.
|
|
1030
|
+
*/
|
|
1031
|
+
publishGlobalConfigReload(
|
|
1032
|
+
candidate: SettingsGlobalConfigCandidate,
|
|
1033
|
+
commitSync: () => void = () => {},
|
|
1034
|
+
): SettingsConfigReloadPublication {
|
|
1035
|
+
const state = settingsGlobalConfigCandidateStates.get(candidate);
|
|
1036
|
+
if (!state || state.owner !== this) {
|
|
1037
|
+
throw new SettingsGlobalConfigReloadError(
|
|
1038
|
+
"The global config candidate does not belong to this Settings instance.",
|
|
1039
|
+
this.#configPath,
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
if (state.published) {
|
|
1043
|
+
throw new SettingsGlobalConfigReloadError(
|
|
1044
|
+
"The global config candidate has already been published.",
|
|
1045
|
+
state.configPath,
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
if (
|
|
1049
|
+
this.#configPath !== state.configPath ||
|
|
1050
|
+
!util.isDeepStrictEqual(this.#global, state.currentGlobal) ||
|
|
1051
|
+
!util.isDeepStrictEqual(this.#project, state.currentProject) ||
|
|
1052
|
+
!util.isDeepStrictEqual(this.#overrides, state.currentOverrides) ||
|
|
1053
|
+
!util.isDeepStrictEqual(this.#merged, state.currentMerged)
|
|
1054
|
+
) {
|
|
1055
|
+
throw new SettingsGlobalConfigReloadError(
|
|
1056
|
+
"Settings changed while the global config candidate was being prepared; stage it again.",
|
|
1057
|
+
state.configPath,
|
|
1058
|
+
structuredClone(state.diagnostics),
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const previousValues = new Map<SettingPath, unknown>();
|
|
1063
|
+
for (const settingPath of Object.keys(SETTINGS_SCHEMA) as SettingPath[]) {
|
|
1064
|
+
previousValues.set(settingPath, structuredClone(this.get(settingPath)));
|
|
1065
|
+
}
|
|
1066
|
+
const previous = {
|
|
1067
|
+
global: this.#global,
|
|
1068
|
+
overrides: structuredClone(this.#overrides),
|
|
1069
|
+
rawNotificationConfig: this.#rawNotificationConfig,
|
|
1070
|
+
durableRawNotificationConfig: this.#durableRawNotificationConfig,
|
|
1071
|
+
durableNotificationFingerprint: this.#durableNotificationFingerprint,
|
|
1072
|
+
merged: this.#merged,
|
|
1073
|
+
schemaReport: this.#schemaReport,
|
|
1074
|
+
autoroutingEffective: this.#autoroutingEffective,
|
|
1075
|
+
autoroutingLocalIssues: this.#autoroutingLocalIssues,
|
|
1076
|
+
futureSchemaVersion: this.#futureSchemaVersion,
|
|
1077
|
+
hasAcceptedGlobalConfigFile: this.#hasAcceptedGlobalConfigFile,
|
|
1078
|
+
hasMalformedConfigRoot: this.#hasMalformedConfigRoot,
|
|
1079
|
+
hasRecoveredConfigSyntax: this.#hasRecoveredConfigSyntax,
|
|
1080
|
+
hasInvalidNotificationGlobal: this.#hasInvalidNotificationGlobal,
|
|
1081
|
+
notificationValidationGeneration: this.#notificationValidationGeneration,
|
|
1082
|
+
};
|
|
1083
|
+
let publicationState: "pending" | "finalized" | "rolled-back" = "pending";
|
|
1084
|
+
const rollback = () => {
|
|
1085
|
+
if (publicationState === "rolled-back") return;
|
|
1086
|
+
if (publicationState === "finalized") throw new Error("Cannot roll back finalized configuration.");
|
|
1087
|
+
this.#global = previous.global;
|
|
1088
|
+
this.#overrides = previous.overrides;
|
|
1089
|
+
this.#rawNotificationConfig = previous.rawNotificationConfig;
|
|
1090
|
+
this.#durableRawNotificationConfig = previous.durableRawNotificationConfig;
|
|
1091
|
+
this.#durableNotificationFingerprint = previous.durableNotificationFingerprint;
|
|
1092
|
+
this.#merged = previous.merged;
|
|
1093
|
+
this.#schemaReport = previous.schemaReport;
|
|
1094
|
+
this.#autoroutingEffective = previous.autoroutingEffective;
|
|
1095
|
+
this.#autoroutingLocalIssues = previous.autoroutingLocalIssues;
|
|
1096
|
+
this.#futureSchemaVersion = previous.futureSchemaVersion;
|
|
1097
|
+
this.#hasAcceptedGlobalConfigFile = previous.hasAcceptedGlobalConfigFile;
|
|
1098
|
+
this.#hasMalformedConfigRoot = previous.hasMalformedConfigRoot;
|
|
1099
|
+
this.#hasRecoveredConfigSyntax = previous.hasRecoveredConfigSyntax;
|
|
1100
|
+
this.#hasInvalidNotificationGlobal = previous.hasInvalidNotificationGlobal;
|
|
1101
|
+
this.#notificationValidationGeneration = previous.notificationValidationGeneration;
|
|
1102
|
+
publicationState = "rolled-back";
|
|
1103
|
+
};
|
|
1104
|
+
this.#global = structuredClone(state.globalWithPendingPatches);
|
|
1105
|
+
const previousNotificationFingerprint = this.#durableNotificationFingerprint;
|
|
1106
|
+
this.#captureRawNotificationConfig(state.rawConfig);
|
|
1107
|
+
for (const patch of this.#pendingPatchesInGenerationOrder()) {
|
|
1108
|
+
this.#applyNotificationMutationToRaw(patch.path, patch.value);
|
|
1109
|
+
}
|
|
1110
|
+
if (previousNotificationFingerprint !== this.#durableNotificationFingerprint) {
|
|
1111
|
+
this.#notificationValidationGeneration++;
|
|
1112
|
+
}
|
|
1113
|
+
this.#schemaReport = structuredClone(state.diagnostics);
|
|
1114
|
+
this.#futureSchemaVersion = state.futureSchemaVersion;
|
|
1115
|
+
this.#hasMalformedConfigRoot = false;
|
|
1116
|
+
this.#hasRecoveredConfigSyntax = false;
|
|
1117
|
+
this.#hasInvalidNotificationGlobal = false;
|
|
1118
|
+
this.#rebuildMerged();
|
|
1119
|
+
this.#recomputeNotificationValidationFromRaw();
|
|
1120
|
+
|
|
1121
|
+
try {
|
|
1122
|
+
const result: unknown = commitSync();
|
|
1123
|
+
if (result && typeof result === "object" && "then" in result) {
|
|
1124
|
+
throw new TypeError("Global config reload commit callback must be synchronous.");
|
|
1125
|
+
}
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
rollback();
|
|
1128
|
+
throw error;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
this.#hasAcceptedGlobalConfigFile ||= state.sourcePresent;
|
|
1132
|
+
state.published = true;
|
|
1133
|
+
return {
|
|
1134
|
+
rollback,
|
|
1135
|
+
finalize: () => {
|
|
1136
|
+
if (publicationState !== "pending") return;
|
|
1137
|
+
publicationState = "finalized";
|
|
1138
|
+
for (const settingPath of Object.keys(SETTINGS_SCHEMA) as SettingPath[]) {
|
|
1139
|
+
const previousValue = previousValues.get(settingPath);
|
|
1140
|
+
const nextValue = this.get(settingPath);
|
|
1141
|
+
if (util.isDeepStrictEqual(previousValue, nextValue)) continue;
|
|
1142
|
+
const hook = SETTING_HOOKS[settingPath];
|
|
1143
|
+
if (hook) {
|
|
1144
|
+
try {
|
|
1145
|
+
hook(nextValue, previousValue);
|
|
1146
|
+
} catch {
|
|
1147
|
+
logger.warn("Configuration reload setting hook failed", { settingPath });
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
for (const listener of this.#changeListeners) {
|
|
1151
|
+
try {
|
|
1152
|
+
listener(settingPath);
|
|
1153
|
+
} catch {
|
|
1154
|
+
logger.warn("Configuration reload listener failed", { settingPath });
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
|
|
748
1162
|
/** Whether durable settings mutations are permitted for the loaded configuration. */
|
|
749
1163
|
canWriteDurableConfig(): boolean {
|
|
750
1164
|
return !this.#persist || !this.#hasRecoveredConfigSyntax;
|
|
@@ -1156,6 +1570,7 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1156
1570
|
cloned.#autoroutingLocalIssues = structuredClone(this.#autoroutingLocalIssues);
|
|
1157
1571
|
cloned.#schemaMigrationPending = this.#schemaMigrationPending;
|
|
1158
1572
|
cloned.#futureSchemaVersion = this.#futureSchemaVersion;
|
|
1573
|
+
cloned.#hasAcceptedGlobalConfigFile = this.#hasAcceptedGlobalConfigFile;
|
|
1159
1574
|
cloned.#hasMalformedConfigRoot = this.#hasMalformedConfigRoot;
|
|
1160
1575
|
cloned.#hasRecoveredConfigSyntax = this.#hasRecoveredConfigSyntax;
|
|
1161
1576
|
cloned.#hasInvalidNotificationGlobal = this.#hasInvalidNotificationGlobal;
|
|
@@ -1206,10 +1621,12 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1206
1621
|
}
|
|
1207
1622
|
|
|
1208
1623
|
/**
|
|
1209
|
-
*
|
|
1624
|
+
* Shell configuration for bash and the Python executor.
|
|
1625
|
+
* `shellPath` comes from the user/global config only, so a project
|
|
1626
|
+
* `.gjc/settings.json` cannot select the binary those executors run.
|
|
1210
1627
|
*/
|
|
1211
1628
|
getShellConfig() {
|
|
1212
|
-
const shell = this.
|
|
1629
|
+
const shell = this.getGlobal("shellPath");
|
|
1213
1630
|
return resolveShellConfig(shell);
|
|
1214
1631
|
}
|
|
1215
1632
|
|
|
@@ -1516,7 +1933,10 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1516
1933
|
throw error;
|
|
1517
1934
|
}
|
|
1518
1935
|
this.#resetYamlLoadState();
|
|
1519
|
-
if (content.trim() === "")
|
|
1936
|
+
if (content.trim() === "") {
|
|
1937
|
+
if (filePath === this.#configPath) this.#hasAcceptedGlobalConfigFile = true;
|
|
1938
|
+
return {};
|
|
1939
|
+
}
|
|
1520
1940
|
let parsed: unknown;
|
|
1521
1941
|
try {
|
|
1522
1942
|
parsed = YAML.parse(content);
|
|
@@ -1536,7 +1956,10 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1536
1956
|
this.#captureRawNotificationConfig(undefined);
|
|
1537
1957
|
return {};
|
|
1538
1958
|
}
|
|
1539
|
-
if (parsed === undefined)
|
|
1959
|
+
if (parsed === undefined) {
|
|
1960
|
+
if (filePath === this.#configPath) this.#hasAcceptedGlobalConfigFile = true;
|
|
1961
|
+
return {};
|
|
1962
|
+
}
|
|
1540
1963
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1541
1964
|
this.#hasMalformedConfigRoot = true;
|
|
1542
1965
|
this.#schemaReport = {
|
|
@@ -1604,6 +2027,14 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1604
2027
|
});
|
|
1605
2028
|
}
|
|
1606
2029
|
this.#schemaReport = reconciled.report;
|
|
2030
|
+
if (
|
|
2031
|
+
filePath === this.#configPath &&
|
|
2032
|
+
reconciled.report.valid &&
|
|
2033
|
+
!this.#hasInvalidNotificationGlobal &&
|
|
2034
|
+
!hasLegacyCustomImageProvider(parsedRaw)
|
|
2035
|
+
) {
|
|
2036
|
+
this.#hasAcceptedGlobalConfigFile = true;
|
|
2037
|
+
}
|
|
1607
2038
|
return reconciled.settings;
|
|
1608
2039
|
}
|
|
1609
2040
|
|
|
@@ -1625,13 +2056,16 @@ export class Settings implements NotificationSettingsReader {
|
|
|
1625
2056
|
const data = item.path.endsWith(`${path.sep}settings.json`)
|
|
1626
2057
|
? await this.#stripRetiredWorkflowKeys(item.path, structuredClone(item.data as RawSettings))
|
|
1627
2058
|
: (item.data as RawSettings);
|
|
1628
|
-
const { settings, rejectedNotifications,
|
|
2059
|
+
const { settings, rejectedNotifications, rejectedCredentialSelection } =
|
|
1629
2060
|
this.#stripProjectNotificationSettings(data);
|
|
1630
2061
|
if (rejectedNotifications) {
|
|
1631
2062
|
logger.warn("Settings: ignoring project notification settings", { path: item.path });
|
|
1632
2063
|
}
|
|
1633
|
-
if (
|
|
1634
|
-
logger.warn(
|
|
2064
|
+
if (rejectedCredentialSelection) {
|
|
2065
|
+
logger.warn(
|
|
2066
|
+
"Settings: ignoring project auth credential pins/preferences; credential selection is global-only",
|
|
2067
|
+
{ path: item.path },
|
|
2068
|
+
);
|
|
1635
2069
|
}
|
|
1636
2070
|
merged = this.#deepMerge(merged, settings);
|
|
1637
2071
|
}
|
|
@@ -6022,16 +6456,20 @@ export class Settings implements NotificationSettingsReader {
|
|
|
6022
6456
|
}
|
|
6023
6457
|
|
|
6024
6458
|
#rebuildMerged(): void {
|
|
6025
|
-
|
|
6026
|
-
|
|
6459
|
+
this.#merged = this.#mergeSettingsLayers(this.#global, this.#project, this.#overrides);
|
|
6460
|
+
this.#recomputeAutoroutingDiagnostic();
|
|
6461
|
+
}
|
|
6462
|
+
|
|
6463
|
+
#mergeSettingsLayers(global: RawSettings, projectLayer: RawSettings, overrideLayer: RawSettings): RawSettings {
|
|
6464
|
+
const project = structuredClone(projectLayer);
|
|
6465
|
+
const overrides = structuredClone(overrideLayer);
|
|
6027
6466
|
for (const settingPath of GLOBAL_ONLY_SETTINGS) {
|
|
6028
6467
|
const segments = settingPath.split(".");
|
|
6029
6468
|
deleteByPath(project, segments);
|
|
6030
6469
|
deleteByPath(overrides, segments);
|
|
6031
6470
|
}
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
this.#recomputeAutoroutingDiagnostic();
|
|
6471
|
+
const merged = this.#deepMerge(this.#deepMerge({}, global), project);
|
|
6472
|
+
return this.#deepMerge(merged, overrides);
|
|
6035
6473
|
}
|
|
6036
6474
|
|
|
6037
6475
|
#fireAllHooks(): void {
|
|
@@ -6047,27 +6485,25 @@ export class Settings implements NotificationSettingsReader {
|
|
|
6047
6485
|
#stripProjectNotificationSettings(settings: RawSettings): {
|
|
6048
6486
|
settings: RawSettings;
|
|
6049
6487
|
rejectedNotifications: boolean;
|
|
6050
|
-
|
|
6488
|
+
rejectedCredentialSelection: boolean;
|
|
6051
6489
|
} {
|
|
6052
6490
|
let rejectedNotifications = false;
|
|
6053
|
-
let
|
|
6491
|
+
let rejectedCredentialSelection = false;
|
|
6054
6492
|
const sanitized: RawSettings = {};
|
|
6055
6493
|
for (const [key, value] of Object.entries(settings)) {
|
|
6056
6494
|
if (key === "auth" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
6057
6495
|
const authSettings = { ...(value as Record<string, unknown>) };
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
delete authSettings.credentialPinStoreIdentity;
|
|
6064
|
-
rejectedCredentialPins = true;
|
|
6496
|
+
for (const key of GLOBAL_ONLY_AUTH_SETTING_KEYS) {
|
|
6497
|
+
if (Object.hasOwn(authSettings, key)) {
|
|
6498
|
+
delete authSettings[key];
|
|
6499
|
+
rejectedCredentialSelection = true;
|
|
6500
|
+
}
|
|
6065
6501
|
}
|
|
6066
6502
|
if (Object.keys(authSettings).length > 0) sanitized[key] = authSettings;
|
|
6067
6503
|
continue;
|
|
6068
6504
|
}
|
|
6069
|
-
if (key
|
|
6070
|
-
|
|
6505
|
+
if (key.startsWith("auth.") && GLOBAL_ONLY_AUTH_SETTING_KEYS.has(key.slice("auth.".length))) {
|
|
6506
|
+
rejectedCredentialSelection = true;
|
|
6071
6507
|
continue;
|
|
6072
6508
|
}
|
|
6073
6509
|
if (key === "notifications" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
@@ -6088,7 +6524,7 @@ export class Settings implements NotificationSettingsReader {
|
|
|
6088
6524
|
}
|
|
6089
6525
|
sanitized[key] = value;
|
|
6090
6526
|
}
|
|
6091
|
-
return { settings: sanitized, rejectedNotifications,
|
|
6527
|
+
return { settings: sanitized, rejectedNotifications, rejectedCredentialSelection };
|
|
6092
6528
|
}
|
|
6093
6529
|
|
|
6094
6530
|
#deepMerge(base: RawSettings, overrides: RawSettings): RawSettings {
|
|
@@ -3,6 +3,7 @@ import * as nodeFs from "node:fs";
|
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { canonicalEnvKey, projectEnvSnapshot } from "@gajae-code/utils/env-file";
|
|
6
7
|
import { coordinatorMcpStateRoot, gjcRoot } from "../gjc-runtime/session-layout";
|
|
7
8
|
import {
|
|
8
9
|
DEFAULT_SESSION_IDLE_TTL_MS,
|
|
@@ -121,6 +122,30 @@ function parseRootList(value: string | undefined): string[] {
|
|
|
121
122
|
.filter(Boolean);
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
const MANAGED_WORKTREE_DIR_ENV = "GJC_WORKTREE_DIR";
|
|
126
|
+
/** Captured at load so a later chdir or dotenv delete cannot hide the declaration. */
|
|
127
|
+
const startupManagedWorktreeSnapshot = projectEnvSnapshot();
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Operator value only. A project dotenv declaration, including a dynamic one,
|
|
131
|
+
* must not widen managed worktree roots. An operator value the project does
|
|
132
|
+
* not declare is kept.
|
|
133
|
+
*/
|
|
134
|
+
function trustedManagedWorktreeDir(env: NodeJS.ProcessEnv): string | undefined {
|
|
135
|
+
const raw = env[MANAGED_WORKTREE_DIR_ENV];
|
|
136
|
+
if (!raw) return undefined;
|
|
137
|
+
const key = canonicalEnvKey(MANAGED_WORKTREE_DIR_ENV);
|
|
138
|
+
const declared = startupManagedWorktreeSnapshot.values[key];
|
|
139
|
+
const trimmed = raw.trim();
|
|
140
|
+
if (
|
|
141
|
+
declared !== undefined &&
|
|
142
|
+
(startupManagedWorktreeSnapshot.dynamic.has(key) || declared === raw || declared === trimmed)
|
|
143
|
+
) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
124
149
|
function resolveManagedWorktreeRoot(root: string, configured: string | undefined): string {
|
|
125
150
|
// Function replacers so a `$` in the home or repository path is kept verbatim.
|
|
126
151
|
const template = (configured?.trim() || "{repo}/.worktrees").replace(/^~(?=\/|$)/, () => os.homedir());
|
|
@@ -168,7 +193,7 @@ export function buildCoordinatorMcpConfig(env: NodeJS.ProcessEnv = process.env):
|
|
|
168
193
|
return {
|
|
169
194
|
allowedRoots: parseRootList(env.GJC_COORDINATOR_MCP_WORKDIR_ROOTS).map(root => path.resolve(root)),
|
|
170
195
|
managedWorktreeRoots: parseRootList(env.GJC_COORDINATOR_MCP_WORKDIR_ROOTS).map(root =>
|
|
171
|
-
resolveManagedWorktreeRoot(path.resolve(root), env
|
|
196
|
+
resolveManagedWorktreeRoot(path.resolve(root), trustedManagedWorktreeDir(env)),
|
|
172
197
|
),
|
|
173
198
|
mutationClasses: parseMutationClasses(
|
|
174
199
|
env.GJC_COORDINATOR_MCP_MUTATIONS ?? env.GJC_COORDINATOR_MCP_ENABLE_MUTATION_CLASSES,
|