@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/eval/py/runner.py
CHANGED
|
@@ -29,6 +29,7 @@ import asyncio
|
|
|
29
29
|
import ast
|
|
30
30
|
import base64
|
|
31
31
|
import builtins
|
|
32
|
+
import codecs
|
|
32
33
|
import inspect
|
|
33
34
|
import io
|
|
34
35
|
import json
|
|
@@ -49,9 +50,14 @@ from typing import Any, Callable
|
|
|
49
50
|
# Frame writer
|
|
50
51
|
# ---------------------------------------------------------------------------
|
|
51
52
|
|
|
52
|
-
_RAW_STDOUT = sys.__stdout__
|
|
53
53
|
_RAW_STDERR = sys.__stderr__
|
|
54
54
|
_OUT_LOCK = threading.Lock()
|
|
55
|
+
_PROTO_FD: int | None = None
|
|
56
|
+
_CAP_LOCK = threading.Lock()
|
|
57
|
+
_FLUSH_EVENT = threading.Event()
|
|
58
|
+
_FLUSH_TOKEN: bytes | None = None
|
|
59
|
+
_CAPTURED = b""
|
|
60
|
+
_CAPTURE_DECODER = codecs.getincrementaldecoder("utf-8")(errors="replace")
|
|
55
61
|
|
|
56
62
|
|
|
57
63
|
def _json_default(o: Any) -> Any:
|
|
@@ -61,13 +67,141 @@ def _json_default(o: Any) -> Any:
|
|
|
61
67
|
return f"<unrepr {type(o).__name__}>"
|
|
62
68
|
|
|
63
69
|
|
|
70
|
+
def _write_all(fd: int, data: bytes) -> None:
|
|
71
|
+
view = memoryview(data)
|
|
72
|
+
while len(view):
|
|
73
|
+
written = os.write(fd, view)
|
|
74
|
+
if written <= 0:
|
|
75
|
+
raise OSError(0, "protocol write returned no bytes")
|
|
76
|
+
view = view[written:]
|
|
77
|
+
|
|
78
|
+
|
|
64
79
|
def _emit(frame: dict) -> None:
|
|
65
80
|
"""Serialize a frame and write it to the host as a single NDJSON line."""
|
|
66
|
-
|
|
81
|
+
payload = (json.dumps(frame, ensure_ascii=False, default=_json_default) + "\n").encode("utf-8")
|
|
82
|
+
fd = _PROTO_FD if _PROTO_FD is not None else 1
|
|
67
83
|
with _OUT_LOCK:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
_write_all(fd, payload)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _token_suffix_len(buf: bytes, token: bytes) -> int:
|
|
88
|
+
max_n = min(len(buf), len(token) - 1)
|
|
89
|
+
for size in range(max_n, 0, -1):
|
|
90
|
+
if buf.endswith(token[:size]):
|
|
91
|
+
return size
|
|
92
|
+
return 0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _take_captured_locked() -> tuple[list[bytes], bool]:
|
|
96
|
+
"""Split captured fd-1 bytes. A flush token is a delimiter, not output."""
|
|
97
|
+
global _CAPTURED, _FLUSH_TOKEN
|
|
98
|
+
pieces: list[bytes] = []
|
|
99
|
+
flushed = False
|
|
100
|
+
while True:
|
|
101
|
+
token = _FLUSH_TOKEN
|
|
102
|
+
if token is None:
|
|
103
|
+
if _CAPTURED:
|
|
104
|
+
pieces.append(_CAPTURED)
|
|
105
|
+
_CAPTURED = b""
|
|
106
|
+
return pieces, flushed
|
|
107
|
+
idx = _CAPTURED.find(token)
|
|
108
|
+
if idx < 0:
|
|
109
|
+
keep = _token_suffix_len(_CAPTURED, token)
|
|
110
|
+
if len(_CAPTURED) > keep:
|
|
111
|
+
pieces.append(_CAPTURED[: len(_CAPTURED) - keep])
|
|
112
|
+
_CAPTURED = _CAPTURED[-keep:] if keep else b""
|
|
113
|
+
return pieces, flushed
|
|
114
|
+
if idx:
|
|
115
|
+
pieces.append(_CAPTURED[:idx])
|
|
116
|
+
_CAPTURED = _CAPTURED[idx + len(token) :]
|
|
117
|
+
_FLUSH_TOKEN = None
|
|
118
|
+
flushed = True
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _publish_captured(pieces: list[bytes], flushed: bool) -> None:
|
|
122
|
+
global _CAPTURE_DECODER
|
|
123
|
+
for piece in pieces:
|
|
124
|
+
text = _CAPTURE_DECODER.decode(piece)
|
|
125
|
+
if text:
|
|
126
|
+
_forward_captured_stdout(text)
|
|
127
|
+
if not flushed:
|
|
128
|
+
return
|
|
129
|
+
tail = _CAPTURE_DECODER.decode(b"", final=True)
|
|
130
|
+
if tail:
|
|
131
|
+
_forward_captured_stdout(tail)
|
|
132
|
+
_CAPTURE_DECODER = codecs.getincrementaldecoder("utf-8")(errors="replace")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _forward_captured_stdout(text: str) -> None:
|
|
136
|
+
rid = _STATE.current_id
|
|
137
|
+
if not text:
|
|
138
|
+
return
|
|
139
|
+
if rid is None:
|
|
140
|
+
_RAW_STDERR.write(text)
|
|
141
|
+
_RAW_STDERR.flush()
|
|
142
|
+
return
|
|
143
|
+
_emit({"type": "stdout", "id": rid, "data": text})
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _pump_captured_stdout(read_fd: int) -> None:
|
|
147
|
+
global _CAPTURED
|
|
148
|
+
while True:
|
|
149
|
+
try:
|
|
150
|
+
chunk = os.read(read_fd, 65536)
|
|
151
|
+
except OSError:
|
|
152
|
+
return
|
|
153
|
+
if not chunk:
|
|
154
|
+
return
|
|
155
|
+
with _CAP_LOCK:
|
|
156
|
+
_CAPTURED += chunk
|
|
157
|
+
pieces, flushed = _take_captured_locked()
|
|
158
|
+
_publish_captured(pieces, flushed)
|
|
159
|
+
if flushed:
|
|
160
|
+
_FLUSH_EVENT.set()
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _capture_user_stdout() -> None:
|
|
164
|
+
"""Move the host pipe off fd 1 so raw user writes are cell output."""
|
|
165
|
+
global _PROTO_FD
|
|
166
|
+
if _PROTO_FD is not None:
|
|
167
|
+
return
|
|
168
|
+
try:
|
|
169
|
+
sys.__stdout__.flush()
|
|
170
|
+
except Exception:
|
|
171
|
+
pass
|
|
172
|
+
proto = os.dup(1)
|
|
173
|
+
os.set_inheritable(proto, False)
|
|
174
|
+
_PROTO_FD = proto
|
|
175
|
+
read_fd, write_fd = os.pipe()
|
|
176
|
+
os.set_inheritable(read_fd, False)
|
|
177
|
+
os.dup2(write_fd, 1, inheritable=True)
|
|
178
|
+
os.close(write_fd)
|
|
179
|
+
threading.Thread(
|
|
180
|
+
target=_pump_captured_stdout,
|
|
181
|
+
args=(read_fd,),
|
|
182
|
+
name="gjc-stdout-capture",
|
|
183
|
+
daemon=True,
|
|
184
|
+
).start()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _flush_captured_stdout() -> None:
|
|
188
|
+
if _PROTO_FD is None:
|
|
189
|
+
return
|
|
190
|
+
token = b"\0gjcfd1:" + os.urandom(8).hex().encode("ascii") + b"\0"
|
|
191
|
+
with _CAP_LOCK:
|
|
192
|
+
global _FLUSH_TOKEN
|
|
193
|
+
_FLUSH_EVENT.clear()
|
|
194
|
+
_FLUSH_TOKEN = token
|
|
195
|
+
_write_all(1, token)
|
|
196
|
+
if _FLUSH_EVENT.wait(5):
|
|
197
|
+
return
|
|
198
|
+
with _CAP_LOCK:
|
|
199
|
+
if _FLUSH_TOKEN == token:
|
|
200
|
+
_FLUSH_TOKEN = None
|
|
201
|
+
pieces, flushed = _take_captured_locked()
|
|
202
|
+
else:
|
|
203
|
+
pieces, flushed = [], False
|
|
204
|
+
_publish_captured(pieces, flushed)
|
|
71
205
|
|
|
72
206
|
|
|
73
207
|
# ---------------------------------------------------------------------------
|
|
@@ -902,6 +1036,10 @@ def _handle_request(req: dict) -> None:
|
|
|
902
1036
|
_flush_matplotlib_figures()
|
|
903
1037
|
except Exception:
|
|
904
1038
|
pass
|
|
1039
|
+
try:
|
|
1040
|
+
_flush_captured_stdout()
|
|
1041
|
+
except Exception:
|
|
1042
|
+
pass
|
|
905
1043
|
|
|
906
1044
|
_emit({
|
|
907
1045
|
"type": "done",
|
|
@@ -930,6 +1068,7 @@ def _emit_error(rid: str, exc: BaseException) -> None:
|
|
|
930
1068
|
|
|
931
1069
|
|
|
932
1070
|
def main() -> None:
|
|
1071
|
+
_capture_user_stdout()
|
|
933
1072
|
sys.stdout = _StreamProxy("stdout")
|
|
934
1073
|
sys.stderr = _StreamProxy("stderr")
|
|
935
1074
|
_install_idle_sigint()
|
package/src/eval/py/runtime.ts
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
-
import { $env, $which, getPythonEnvDir, WhichCachePolicy } from "@gajae-code/utils";
|
|
10
|
+
import { $env, $which, getPythonEnvDir, relativePathEscapesRoot, WhichCachePolicy } from "@gajae-code/utils";
|
|
11
11
|
import { withFileLock } from "../../config/file-lock";
|
|
12
|
+
import { isProjectControlledPath } from "../../lsp/path-trust";
|
|
12
13
|
|
|
13
14
|
export const RLM_MANAGED_PYTHON_PACKAGES: readonly string[] = ["numpy", "pandas", "matplotlib", "polars"];
|
|
14
15
|
|
|
@@ -133,6 +134,47 @@ function resolvePythonCandidateInVenv(venvPath: string): { venvPath: string; pyt
|
|
|
133
134
|
return { venvPath, pythonPath, binDir };
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
/**
|
|
138
|
+
* A workspace `.venv` or `venv` directory is repository content. Use it only when
|
|
139
|
+
* it is a real virtualenv (`pyvenv.cfg`) whose interpreter file resolves outside
|
|
140
|
+
* the project. An in-tree script or binary is not an interpreter.
|
|
141
|
+
*
|
|
142
|
+
* True when `candidate` is `root` or a descendant after `path.resolve`.
|
|
143
|
+
* A name such as `..payload` stays inside. Only `..` and a parent segment escape.
|
|
144
|
+
*/
|
|
145
|
+
export function workspacePathContained(root: string, candidate: string): boolean {
|
|
146
|
+
const normalize = (value: string): string => {
|
|
147
|
+
const resolved = path.resolve(value);
|
|
148
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
149
|
+
};
|
|
150
|
+
return !relativePathEscapesRoot(path.relative(normalize(root), normalize(candidate)));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isAutoDetectedWorkspaceVenv(candidate: string, cwd: string): boolean {
|
|
154
|
+
try {
|
|
155
|
+
if (!fs.statSync(path.join(candidate, "pyvenv.cfg")).isFile()) return false;
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
let canonicalPython: string;
|
|
160
|
+
try {
|
|
161
|
+
canonicalPython = fs.realpathSync(resolvePythonCandidateInVenv(candidate).pythonPath);
|
|
162
|
+
} catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
// HOME stops project-root discovery, so a workspace that is the home directory
|
|
166
|
+
// is not project-controlled. Refuse an interpreter that still resolves inside
|
|
167
|
+
// cwd, including a file whose name is `..payload`.
|
|
168
|
+
let canonicalCwd = path.resolve(cwd);
|
|
169
|
+
try {
|
|
170
|
+
canonicalCwd = fs.realpathSync(cwd);
|
|
171
|
+
} catch {
|
|
172
|
+
// Missing cwd keeps the resolved path.
|
|
173
|
+
}
|
|
174
|
+
if (workspacePathContained(canonicalCwd, canonicalPython)) return false;
|
|
175
|
+
return !isProjectControlledPath(canonicalPython, cwd);
|
|
176
|
+
}
|
|
177
|
+
|
|
136
178
|
function resolveManagedPythonCandidate(): { venvPath: string; pythonPath: string; binDir: string } {
|
|
137
179
|
return resolvePythonCandidateInVenv(resolveGlobalManagedPythonEnv());
|
|
138
180
|
}
|
|
@@ -197,9 +239,7 @@ export function resolveVenvPath(cwd: string): string | undefined {
|
|
|
197
239
|
if ($env.CONDA_PREFIX) return $env.CONDA_PREFIX;
|
|
198
240
|
const candidates = [path.join(cwd, ".venv"), path.join(cwd, "venv")];
|
|
199
241
|
for (const candidate of candidates) {
|
|
200
|
-
if (
|
|
201
|
-
return candidate;
|
|
202
|
-
}
|
|
242
|
+
if (isAutoDetectedWorkspaceVenv(candidate, cwd)) return candidate;
|
|
203
243
|
}
|
|
204
244
|
return undefined;
|
|
205
245
|
}
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ShellRunResult,
|
|
13
13
|
} from "@gajae-code/natives";
|
|
14
14
|
import { postmortem } from "@gajae-code/utils";
|
|
15
|
+
import { projectDeclaredSpawnHookNames, stripProjectSpawnHooks } from "@gajae-code/utils/shell-config";
|
|
15
16
|
import { Settings, type ShellMinimizerSettings } from "../config/settings";
|
|
16
17
|
import { formatCrashDiagnosticNotice, writeCrashReport } from "../debug/crash-diagnostics";
|
|
17
18
|
import {
|
|
@@ -93,6 +94,20 @@ export function setShellFactoryForTests(factory: ShellFactory | undefined): void
|
|
|
93
94
|
shellFactoryForTests = factory;
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
function projectHookUnsetEnv(
|
|
98
|
+
unsetEnv: string[] | undefined,
|
|
99
|
+
env: Record<string, string> | undefined,
|
|
100
|
+
sessionEnv: Record<string, string>,
|
|
101
|
+
): string[] | undefined {
|
|
102
|
+
// Keys present in `sessionEnv` (e.g. the trusted HOME replacement) already
|
|
103
|
+
// override the ambient import, so only shadow the ones it does not carry.
|
|
104
|
+
const hooks = projectDeclaredSpawnHookNames().filter(
|
|
105
|
+
name => !Object.hasOwn(env ?? {}, name) && !Object.hasOwn(sessionEnv, name),
|
|
106
|
+
);
|
|
107
|
+
if (hooks.length === 0) return unsetEnv;
|
|
108
|
+
return [...(unsetEnv ?? []), ...hooks.filter(name => !unsetEnv?.includes(name))];
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
async function createShell(
|
|
97
112
|
options?: ShellOptions,
|
|
98
113
|
onTerminal?: (shell: Shell) => void,
|
|
@@ -414,13 +429,67 @@ async function resolveShellCwd(cwd: string | undefined): Promise<string | undefi
|
|
|
414
429
|
}
|
|
415
430
|
}
|
|
416
431
|
|
|
432
|
+
function presentMinimizerString(value: unknown): string | undefined {
|
|
433
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
type ShellMinimizerSource = {
|
|
437
|
+
getGroup(prefix: "shellMinimizer"): ShellMinimizerSettings;
|
|
438
|
+
getGlobal?(path: "shellMinimizer.settingsPath" | "shellMinimizer.settingsHash"): unknown;
|
|
439
|
+
getOverride?(path: "shellMinimizer.settingsPath"): unknown;
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* A repo `.gjc/settings.json` must not point the minimizer at a TOML file.
|
|
444
|
+
* The native gate loads that file only when `settingsHash` matches, and the
|
|
445
|
+
* pin is the user/global value. A user path or a runtime override is still
|
|
446
|
+
* passed through. A project path is passed only together with that pin.
|
|
447
|
+
*/
|
|
448
|
+
export function resolveTrustedShellMinimizer(settings: ShellMinimizerSource): ShellMinimizerSettings {
|
|
449
|
+
const group = settings.getGroup("shellMinimizer");
|
|
450
|
+
const globalPath =
|
|
451
|
+
typeof settings.getGlobal === "function"
|
|
452
|
+
? presentMinimizerString(settings.getGlobal("shellMinimizer.settingsPath"))
|
|
453
|
+
: undefined;
|
|
454
|
+
const globalHash =
|
|
455
|
+
typeof settings.getGlobal === "function"
|
|
456
|
+
? presentMinimizerString(settings.getGlobal("shellMinimizer.settingsHash"))
|
|
457
|
+
: undefined;
|
|
458
|
+
const overridePath =
|
|
459
|
+
typeof settings.getOverride === "function"
|
|
460
|
+
? presentMinimizerString(settings.getOverride("shellMinimizer.settingsPath"))
|
|
461
|
+
: undefined;
|
|
462
|
+
const effectivePath = presentMinimizerString(group.settingsPath);
|
|
463
|
+
|
|
464
|
+
let settingsPath: string | undefined;
|
|
465
|
+
if (overridePath && effectivePath === overridePath) {
|
|
466
|
+
settingsPath = overridePath;
|
|
467
|
+
} else if (globalPath) {
|
|
468
|
+
settingsPath = globalPath;
|
|
469
|
+
} else if (effectivePath && globalHash) {
|
|
470
|
+
settingsPath = effectivePath;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// A runtime override of a different path is operator input, not the file the
|
|
474
|
+
// user hash pins. Every other admitted path is checked with that pin.
|
|
475
|
+
const unpinnedOverride = overridePath !== undefined && settingsPath === overridePath && settingsPath !== globalPath;
|
|
476
|
+
return {
|
|
477
|
+
...group,
|
|
478
|
+
settingsPath,
|
|
479
|
+
settingsHash: globalHash && settingsPath && !unpinnedOverride ? globalHash : undefined,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
417
483
|
/** Translate `ShellMinimizerSettings` into native `MinimizerOptions`, or `undefined` when disabled. */
|
|
418
484
|
export function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerOptions | undefined {
|
|
419
485
|
if (!group.enabled) return undefined;
|
|
420
486
|
const maxCaptureBytes = Math.min(4 * 1024 * 1024, Math.max(1024, Math.trunc(group.maxCaptureBytes)));
|
|
487
|
+
const settingsPath = group.settingsPath || undefined;
|
|
488
|
+
const settingsHash = settingsPath && group.settingsHash ? group.settingsHash : undefined;
|
|
421
489
|
return {
|
|
422
490
|
enabled: true,
|
|
423
|
-
settingsPath
|
|
491
|
+
settingsPath,
|
|
492
|
+
...(settingsHash ? { settingsHash } : {}),
|
|
424
493
|
only: group.only.length > 0 ? group.only : undefined,
|
|
425
494
|
except: group.except.length > 0 ? group.except : undefined,
|
|
426
495
|
maxCaptureBytes,
|
|
@@ -429,12 +498,16 @@ export function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerO
|
|
|
429
498
|
|
|
430
499
|
export async function executeBash(command: string, options?: BashExecutorOptions): Promise<BashResult> {
|
|
431
500
|
const settings = options?.settings ?? (await Settings.init());
|
|
432
|
-
const { shell, env:
|
|
501
|
+
const { shell, env: configEnv, prefix } = settings.getShellConfig();
|
|
502
|
+
// The shell config env is shared with other consumers (Python kernels keep
|
|
503
|
+
// their own documented allowlist). Only the bash tool's shell must not see
|
|
504
|
+
// project hook variables such as BASH_ENV or GIT_CONFIG_*.
|
|
505
|
+
const shellEnv = stripProjectSpawnHooks({ ...configEnv });
|
|
433
506
|
const configuredPrefix = options?.ignoreShellPrefix ? undefined : prefix;
|
|
434
507
|
const snapshotPath =
|
|
435
508
|
!options?.disableShellSnapshot && shell.includes("bash") ? await getOrCreateSnapshot(shell, shellEnv) : null;
|
|
436
509
|
|
|
437
|
-
const minimizer = buildMinimizerOptions(settings
|
|
510
|
+
const minimizer = buildMinimizerOptions(resolveTrustedShellMinimizer(settings));
|
|
438
511
|
|
|
439
512
|
const commandCwd = await resolveShellCwd(options?.cwd);
|
|
440
513
|
const commandEnv = options?.env ? { ...NON_INTERACTIVE_ENV, ...options.env } : NON_INTERACTIVE_ENV;
|
|
@@ -580,7 +653,11 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
580
653
|
command: finalCommand,
|
|
581
654
|
cwd: commandCwd,
|
|
582
655
|
env: commandEnv,
|
|
583
|
-
|
|
656
|
+
// The native shell imports the host process environment before
|
|
657
|
+
// `sessionEnv`, and where it runs in-process (Windows) that environment
|
|
658
|
+
// holds the autoloaded project `.env`. Shadow project hook variables per
|
|
659
|
+
// run unless this call sets them explicitly.
|
|
660
|
+
unsetEnv: projectHookUnsetEnv(options?.unsetEnv, options?.env, shellEnv),
|
|
584
661
|
timeoutMs: executionTimeoutMs,
|
|
585
662
|
signal: runAbortController.signal,
|
|
586
663
|
};
|
|
@@ -8,6 +8,7 @@ import * as path from "node:path";
|
|
|
8
8
|
import * as readline from "node:readline";
|
|
9
9
|
import type { Process as NativeProcess } from "@gajae-code/natives";
|
|
10
10
|
import { isCompiledBinary } from "@gajae-code/utils/env";
|
|
11
|
+
import { projectSafeSpawnEnv } from "@gajae-code/utils/shell-config";
|
|
11
12
|
import { BASH_SHELL_SUPERVISOR_ARG, type BashShellWorkerRequest } from "./bash-shell-worker-protocol";
|
|
12
13
|
|
|
13
14
|
type NativeProcessBindings = { Process: typeof NativeProcess };
|
|
@@ -401,7 +402,9 @@ export async function runBashShellGuardian(): Promise<void> {
|
|
|
401
402
|
const [executable, ...args] = supervisorArgv();
|
|
402
403
|
const supervisor = childProcess.spawn(executable!, args, {
|
|
403
404
|
detached: process.platform !== "win32",
|
|
404
|
-
|
|
405
|
+
// This process reloaded the project `.env` on startup; keep project hook
|
|
406
|
+
// variables out of the supervisor -> runtime -> native shell chain.
|
|
407
|
+
env: projectSafeSpawnEnv(),
|
|
405
408
|
stdio: ["pipe", "inherit", "inherit"],
|
|
406
409
|
windowsHide: true,
|
|
407
410
|
});
|
|
@@ -8,6 +8,7 @@ import * as path from "node:path";
|
|
|
8
8
|
import * as readline from "node:readline";
|
|
9
9
|
import type { Process as NativeProcess } from "@gajae-code/natives";
|
|
10
10
|
import { isCompiledBinary } from "@gajae-code/utils/env";
|
|
11
|
+
import { projectSafeSpawnEnv } from "@gajae-code/utils/shell-config";
|
|
11
12
|
import { parseLinuxProcParentPid, parseLinuxProcStartTime, parseLinuxProcState } from "../gjc-runtime/linux-proc";
|
|
12
13
|
import { processIncarnation } from "../sdk/broker/process-incarnation";
|
|
13
14
|
import { fatalCatchableSignals, signalExitCode } from "./bash-shell-signals";
|
|
@@ -39,9 +40,10 @@ function darwinUniqueProcessId(pid: number, incarnation: string): string | undef
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
function runtimeArgv(): string[] {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
if (isCompiledBinary()) return [process.execPath, BASH_SHELL_RUNTIME_ARG];
|
|
44
|
+
// The supervisor already sanitized this environment. Do not let the source
|
|
45
|
+
// runtime reload a cwd `.env` that may have changed since the snapshot.
|
|
46
|
+
return [process.execPath, "--no-env-file", path.join(import.meta.dir, "bash-shell-runtime-entry.ts")];
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
function enableLinuxChildSubreaper(): void {
|
|
@@ -264,7 +266,9 @@ export async function runBashShellSupervisor(): Promise<void> {
|
|
|
264
266
|
const worker = childProcess.spawn(command!, args, {
|
|
265
267
|
cwd: process.cwd(),
|
|
266
268
|
detached: false,
|
|
267
|
-
|
|
269
|
+
// This process reloaded the project `.env` on startup; the runtime's native
|
|
270
|
+
// shell imports its environment wholesale, so drop project hook variables.
|
|
271
|
+
env: { ...projectSafeSpawnEnv(), GJC_ISOLATED_SHELL_RUNTIME: "1" },
|
|
268
272
|
stdio: ["pipe", "pipe", "pipe"],
|
|
269
273
|
windowsHide: true,
|
|
270
274
|
});
|
|
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import * as readline from "node:readline";
|
|
6
6
|
import type { ShellRunOptions } from "@gajae-code/natives";
|
|
7
7
|
import { isCompiledBinary } from "@gajae-code/utils/env";
|
|
8
|
+
import { projectSafeSpawnEnv } from "@gajae-code/utils/shell-config";
|
|
8
9
|
import {
|
|
9
10
|
BASH_SHELL_WORKER_ARG,
|
|
10
11
|
type BashShellWorkerRequest,
|
|
@@ -84,7 +85,10 @@ export class IsolatedShell {
|
|
|
84
85
|
this.#child = childProcess.spawn(command!, args, {
|
|
85
86
|
cwd: process.cwd(),
|
|
86
87
|
detached: process.platform !== "win32",
|
|
87
|
-
env
|
|
88
|
+
// The worker chain (guardian -> supervisor -> runtime) inherits this env and
|
|
89
|
+
// the native shell imports it wholesale, so project hook variables must be
|
|
90
|
+
// gone here, not only from the per-session overlay.
|
|
91
|
+
env: projectSafeSpawnEnv(),
|
|
88
92
|
stdio: ["pipe", "pipe", "pipe"],
|
|
89
93
|
windowsHide: true,
|
|
90
94
|
});
|
|
@@ -24,7 +24,6 @@ export const NON_INTERACTIVE_ENV: Readonly<Record<string, string>> = {
|
|
|
24
24
|
EDITOR: "true",
|
|
25
25
|
GIT_TERMINAL_PROMPT: "0",
|
|
26
26
|
SSH_ASKPASS: "/usr/bin/false",
|
|
27
|
-
CI: "1",
|
|
28
27
|
// Package manager defaults for unattended execution.
|
|
29
28
|
npm_config_yes: "true",
|
|
30
29
|
npm_config_update_notifier: "false",
|
package/src/export/html/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as syncFs from "node:fs";
|
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { AgentState } from "@gajae-code/agent-core";
|
|
5
|
-
import { APP_NAME, isEnoent } from "@gajae-code/utils";
|
|
5
|
+
import { APP_NAME, isCredentialKey, isEnoent, redactCrashSecrets } from "@gajae-code/utils";
|
|
6
6
|
import { getResolvedThemeColors, getThemeExportColors } from "../../modes/theme/theme";
|
|
7
7
|
import { SessionManager } from "../../session/session-manager";
|
|
8
8
|
// Pre-generated template (created by scripts/generate-template.ts at publish time)
|
|
@@ -226,18 +226,18 @@ async function writeSessionHtml(
|
|
|
226
226
|
};
|
|
227
227
|
try {
|
|
228
228
|
sink.write(themedTemplate.slice(0, markerOffset));
|
|
229
|
-
writeEncoded(`{"header":${
|
|
229
|
+
writeEncoded(`{"header":${sessionEmbedJson(sm.getHeader())},"entries":[`);
|
|
230
230
|
let first = true;
|
|
231
231
|
sm.visitEntriesForExport(entry => {
|
|
232
|
-
writeEncoded(`${first ? "" : ","}${
|
|
232
|
+
writeEncoded(`${first ? "" : ","}${sessionEmbedJson(entry)}`);
|
|
233
233
|
first = false;
|
|
234
234
|
});
|
|
235
|
-
writeEncoded(`],"leafId":${
|
|
235
|
+
writeEncoded(`],"leafId":${sessionEmbedJson(sm.getLeafId())}`);
|
|
236
236
|
if (state?.systemPrompt !== undefined)
|
|
237
|
-
writeEncoded(`,"systemPrompt":${
|
|
237
|
+
writeEncoded(`,"systemPrompt":${sessionEmbedJson(state.systemPrompt.join("\n\n"))}`);
|
|
238
238
|
if (state?.tools !== undefined)
|
|
239
239
|
writeEncoded(
|
|
240
|
-
`,"tools":${
|
|
240
|
+
`,"tools":${sessionEmbedJson(state.tools.map(tool => ({ name: tool.name, description: tool.description })))}`,
|
|
241
241
|
);
|
|
242
242
|
writeEncoded("}");
|
|
243
243
|
const final = encoder.finish();
|
|
@@ -253,6 +253,86 @@ async function writeSessionHtml(
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Own `__proto__` stays a data property; a normal object would turn that assignment into the prototype.
|
|
258
|
+
* Credential keys mask every JSON value, and string values are scrubbed directly so JSON escaping
|
|
259
|
+
* cannot turn ordinary quote characters into credential-value delimiters.
|
|
260
|
+
*/
|
|
261
|
+
function redactJsonValue(value: unknown): unknown {
|
|
262
|
+
if (typeof value === "string") return redactCrashSecrets(value);
|
|
263
|
+
if (Array.isArray(value)) {
|
|
264
|
+
const isFlatKeyValueArray =
|
|
265
|
+
value.length > 0 &&
|
|
266
|
+
value.length % 2 === 0 &&
|
|
267
|
+
value.every((item, index) => index % 2 === 1 || typeof item === "string");
|
|
268
|
+
if (isFlatKeyValueArray) {
|
|
269
|
+
return value.map((item, index) => {
|
|
270
|
+
if (index % 2 === 1) {
|
|
271
|
+
const key = value[index - 1];
|
|
272
|
+
if (typeof key === "string" && isCredentialKey(key)) return "«redacted»";
|
|
273
|
+
}
|
|
274
|
+
return redactJsonValue(item);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return value.map(item => redactJsonValue(item));
|
|
278
|
+
}
|
|
279
|
+
if (value === null || typeof value !== "object") return value;
|
|
280
|
+
const source = value as Record<string, unknown>;
|
|
281
|
+
const sourceKeys = Object.keys(source);
|
|
282
|
+
let hasCredentialHeaderName = false;
|
|
283
|
+
let hasHeaderValue = false;
|
|
284
|
+
for (const key of sourceKeys) {
|
|
285
|
+
const field = key.toLowerCase();
|
|
286
|
+
if (field === "value" || field === "values") hasHeaderValue = true;
|
|
287
|
+
if (field !== "name" && field !== "key") continue;
|
|
288
|
+
const headerName = source[key];
|
|
289
|
+
if (typeof headerName === "string" && isCredentialKey(headerName)) hasCredentialHeaderName = true;
|
|
290
|
+
}
|
|
291
|
+
const redactHeaderValue = hasCredentialHeaderName && hasHeaderValue;
|
|
292
|
+
const redacted = Object.create(null) as Record<string, unknown>;
|
|
293
|
+
const nextSuffixByKey = new Map<string, number>();
|
|
294
|
+
for (const key of sourceKeys) {
|
|
295
|
+
const redactedKey = uniqueJsonObjectKey(redacted, redactCrashSecrets(key), nextSuffixByKey);
|
|
296
|
+
const field = key.toLowerCase();
|
|
297
|
+
if (redactHeaderValue && (field === "value" || field === "values")) {
|
|
298
|
+
const headerValue = source[key];
|
|
299
|
+
redacted[redactedKey] =
|
|
300
|
+
field === "values" && Array.isArray(headerValue) ? headerValue.map(() => "«redacted»") : "«redacted»";
|
|
301
|
+
} else {
|
|
302
|
+
redacted[redactedKey] = redactKeyedValue(key, source[key]);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return redacted;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Resume after the last collision for this base key rather than rescanning prior suffixes.
|
|
309
|
+
function uniqueJsonObjectKey(
|
|
310
|
+
target: Record<string, unknown>,
|
|
311
|
+
key: string,
|
|
312
|
+
nextSuffixByKey: Map<string, number>,
|
|
313
|
+
): string {
|
|
314
|
+
if (!Object.hasOwn(target, key)) return key;
|
|
315
|
+
let suffix = nextSuffixByKey.get(key) ?? 2;
|
|
316
|
+
let candidate = `${key}#${suffix}`;
|
|
317
|
+
while (Object.hasOwn(target, candidate)) {
|
|
318
|
+
suffix += 1;
|
|
319
|
+
candidate = `${key}#${suffix}`;
|
|
320
|
+
}
|
|
321
|
+
nextSuffixByKey.set(key, suffix + 1);
|
|
322
|
+
return candidate;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function redactKeyedValue(key: string, value: unknown): unknown {
|
|
326
|
+
// A recognized key is authoritative for every JSON type, including a short
|
|
327
|
+
// string, a number, an array, or a nested object.
|
|
328
|
+
if (isCredentialKey(key)) return "«redacted»";
|
|
329
|
+
return typeof value === "string" ? redactCrashSecrets(value) : redactJsonValue(value);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function sessionEmbedJson(value: unknown): string {
|
|
333
|
+
return JSON.stringify(redactJsonValue(JSON.parse(JSON.stringify(value))));
|
|
334
|
+
}
|
|
335
|
+
|
|
256
336
|
/** Export session to HTML using SessionManager and AgentState. */
|
|
257
337
|
export async function exportSessionToHtml(
|
|
258
338
|
sm: SessionManager,
|