@gajae-code/coding-agent 0.18.11 → 0.18.12
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 +293 -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/cli/accounts-cli.d.ts +2 -2
- 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 +1 -0
- package/dist/types/cli/update-cli.d.ts +14 -1
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +5 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/config/autorouting-tier-map.d.ts +30 -0
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +39 -0
- package/dist/types/config/file-lock.d.ts +8 -1
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +62 -6
- package/dist/types/config/model-registry.d.ts +56 -5
- package/dist/types/config/model-resolver.d.ts +2 -0
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +46 -3
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/modes/patch.d.ts +5 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -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/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +10 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/types.d.ts +15 -3
- 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/theme/theme.d.ts +1 -0
- 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/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +2 -2
- package/dist/types/sdk/broker/broker.d.ts +7 -1
- 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 +136 -7
- package/dist/types/sdk/broker/hop.d.ts +36 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +4 -1
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +23 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.d.ts +32 -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/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 +58 -2
- 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 +13 -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 +7 -3
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/task/executor.d.ts +19 -2
- 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/bash-allowed-prefixes.d.ts +11 -0
- package/dist/types/tools/descriptors.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -1
- package/dist/types/tools/index.d.ts +2 -0
- 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/web/scrapers/types.d.ts +8 -1
- 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 +8 -8
- 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 +22 -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 +27 -19
- package/src/capability/index.ts +2 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +7 -5
- package/src/cli/public-command-errors.ts +4 -0
- package/src/cli/root-flags.ts +2 -2
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +224 -7
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +199 -42
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/message.ts +10 -3
- package/src/config/autorouting-tier-map.ts +30 -0
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +734 -0
- package/src/config/file-lock.ts +216 -56
- 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 +716 -113
- package/src/config/model-registry.ts +1334 -158
- package/src/config/model-resolver.ts +3 -1
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +60 -3
- package/src/config/settings.ts +458 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/crash/sanitize.ts +4 -0
- package/src/customization/import.ts +3 -1
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/debug/crash-diagnostics.ts +2 -1
- package/src/debug/report-bundle.ts +19 -0
- 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/helpers.ts +1 -2
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +13 -17
- package/src/edit/modes/patch.ts +187 -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/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/export/html/index.ts +46 -6
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +8 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/gjc-runtime/gc-runtime.ts +33 -6
- package/src/gjc-runtime/launch-tmux.ts +7 -2
- 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/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/hooks/native-skill-hook.ts +14 -11
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/internal-urls/local-protocol.ts +142 -8
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/migrate/action-planner.ts +57 -0
- package/src/migrate/adapters/claude-code.ts +23 -4
- package/src/migrate/adapters/codex.ts +22 -4
- package/src/migrate/adapters/index.ts +22 -4
- package/src/migrate/adapters/opencode.ts +6 -1
- package/src/migrate/executor.ts +84 -7
- package/src/migrate/report.ts +19 -2
- package/src/migrate/types.ts +14 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/controllers/command-controller.ts +38 -2
- package/src/modes/controllers/plan-mode-controller.ts +17 -7
- package/src/modes/controllers/selector-controller.ts +62 -6
- package/src/modes/interactive-mode.ts +68 -0
- package/src/modes/theme/theme.ts +15 -0
- package/src/prompts/tools/debug.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 +32 -0
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +126 -17
- package/src/sdk/broker/broker-exit.ts +8 -5
- package/src/sdk/broker/broker.ts +342 -82
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1143 -265
- package/src/sdk/broker/hop.ts +274 -0
- package/src/sdk/broker/lifecycle-ledger.ts +35 -11
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +62 -12
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/index.ts +52 -21
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/cli/session-cli.ts +21 -6
- package/src/sdk/host/session-runtime.test.ts +118 -23
- package/src/sdk/host/session-runtime.ts +352 -47
- package/src/sdk/lifecycle/service.ts +1 -0
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/protocol/adapter-validation.ts +53 -11
- package/src/sdk/protocol/operation-inventory.generated.json +101 -2
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +114 -61
- package/src/session/agent-session.ts +1043 -81
- package/src/session/internal/managed-session-scope.ts +126 -39
- package/src/session/internal/managed-session-storage.ts +14 -11
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +236 -14
- 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/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +491 -32
- package/src/slash-commands/builtin-registry.ts +15 -3
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/task/executor.ts +103 -12
- package/src/task/index.ts +389 -175
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +3 -0
- package/src/tools/bash-allowed-prefixes.ts +153 -5
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash.ts +14 -0
- package/src/tools/debug.ts +7 -6
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +34 -2
- package/src/tools/fetch.ts +3 -2
- package/src/tools/index.ts +2 -0
- package/src/tools/output-meta.ts +23 -2
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +17 -35
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +108 -1
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +31 -3
- package/src/tools/write.ts +35 -3
- package/src/utils/commit-message-generator.ts +9 -2
- package/src/utils/file-mentions.ts +29 -1
- package/src/utils/title-generator.ts +7 -2
- 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/providers/insane.ts +91 -28
- package/src/web/search/providers/searxng.ts +62 -10
package/src/dap/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { isRecord } from "@gajae-code/utils";
|
|
3
3
|
import { hasRootMarkers, resolveTrustedCommand } from "../lsp/config";
|
|
4
|
+
import { isProjectControlledPath } from "../lsp/path-trust";
|
|
4
5
|
import DEFAULTS from "./defaults.json" with { type: "json" };
|
|
5
6
|
import type { DapAdapterConfig, DapResolvedAdapter } from "./types";
|
|
6
7
|
|
|
@@ -48,11 +49,20 @@ export function getAdapterConfigs(): Record<string, DapAdapterConfig> {
|
|
|
48
49
|
return { ...DEFAULT_ADAPTERS };
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
/**
|
|
53
|
+
* `trustCwds` are extra trust roots, such as the session workspace when the command
|
|
54
|
+
* cwd is a different directory. A command controlled by any of them is refused.
|
|
55
|
+
*/
|
|
56
|
+
export function resolveAdapter(
|
|
57
|
+
adapterName: string,
|
|
58
|
+
cwd: string,
|
|
59
|
+
trustCwds?: readonly string[],
|
|
60
|
+
): DapResolvedAdapter | null {
|
|
52
61
|
const config = DEFAULT_ADAPTERS[adapterName];
|
|
53
62
|
if (!config) return null;
|
|
54
63
|
const resolvedCommand = resolveTrustedCommand(config.command, cwd);
|
|
55
64
|
if (!resolvedCommand) return null;
|
|
65
|
+
if (trustCwds?.some(root => isProjectControlledPath(resolvedCommand, root))) return null;
|
|
56
66
|
return {
|
|
57
67
|
name: adapterName,
|
|
58
68
|
command: config.command,
|
|
@@ -67,15 +77,15 @@ export function resolveAdapter(adapterName: string, cwd: string): DapResolvedAda
|
|
|
67
77
|
};
|
|
68
78
|
}
|
|
69
79
|
|
|
70
|
-
export function getAvailableAdapters(cwd: string): DapResolvedAdapter[] {
|
|
80
|
+
export function getAvailableAdapters(cwd: string, trustCwds?: readonly string[]): DapResolvedAdapter[] {
|
|
71
81
|
return Object.keys(DEFAULT_ADAPTERS)
|
|
72
|
-
.map(name => resolveAdapter(name, cwd))
|
|
82
|
+
.map(name => resolveAdapter(name, cwd, trustCwds))
|
|
73
83
|
.filter((adapter): adapter is DapResolvedAdapter => adapter !== null);
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
function getMatchingAdapters(program: string, cwd: string): DapResolvedAdapter[] {
|
|
86
|
+
function getMatchingAdapters(program: string, cwd: string, trustCwds?: readonly string[]): DapResolvedAdapter[] {
|
|
77
87
|
const extension = path.extname(program).toLowerCase();
|
|
78
|
-
const available = getAvailableAdapters(cwd);
|
|
88
|
+
const available = getAvailableAdapters(cwd, trustCwds);
|
|
79
89
|
if (!extension) {
|
|
80
90
|
// For extensionless binaries, only consider native debuggers (gdb, lldb-dap)
|
|
81
91
|
// or adapters that match by root markers. Don't silently fall back to
|
|
@@ -124,20 +134,30 @@ function sortAdaptersForLaunch(program: string, cwd: string, adapters: DapResolv
|
|
|
124
134
|
return rootAware.map(entry => entry.adapter);
|
|
125
135
|
}
|
|
126
136
|
|
|
127
|
-
export function selectLaunchAdapter(
|
|
137
|
+
export function selectLaunchAdapter(
|
|
138
|
+
program: string,
|
|
139
|
+
cwd: string,
|
|
140
|
+
adapterName?: string,
|
|
141
|
+
trustCwds?: readonly string[],
|
|
142
|
+
): DapResolvedAdapter | null {
|
|
128
143
|
if (adapterName) {
|
|
129
|
-
return resolveAdapter(adapterName, cwd);
|
|
144
|
+
return resolveAdapter(adapterName, cwd, trustCwds);
|
|
130
145
|
}
|
|
131
|
-
const matches = getMatchingAdapters(program, cwd);
|
|
146
|
+
const matches = getMatchingAdapters(program, cwd, trustCwds);
|
|
132
147
|
const sorted = sortAdaptersForLaunch(program, cwd, matches);
|
|
133
148
|
return sorted[0] ?? null;
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
export function selectAttachAdapter(
|
|
151
|
+
export function selectAttachAdapter(
|
|
152
|
+
cwd: string,
|
|
153
|
+
adapterName?: string,
|
|
154
|
+
port?: number,
|
|
155
|
+
trustCwds?: readonly string[],
|
|
156
|
+
): DapResolvedAdapter | null {
|
|
137
157
|
if (adapterName) {
|
|
138
|
-
return resolveAdapter(adapterName, cwd);
|
|
158
|
+
return resolveAdapter(adapterName, cwd, trustCwds);
|
|
139
159
|
}
|
|
140
|
-
const available = getAvailableAdapters(cwd);
|
|
160
|
+
const available = getAvailableAdapters(cwd, trustCwds);
|
|
141
161
|
if (port !== undefined) {
|
|
142
162
|
const debugpy = available.find(adapter => adapter.name === "debugpy");
|
|
143
163
|
if (debugpy) return debugpy;
|
package/src/dap/defaults.json
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"debugpy": {
|
|
46
46
|
"command": "python",
|
|
47
|
-
"args": ["-m", "debugpy.adapter"],
|
|
47
|
+
"args": ["-I", "-m", "debugpy.adapter"],
|
|
48
48
|
"languages": ["python"],
|
|
49
49
|
"fileTypes": [".py"],
|
|
50
50
|
"rootMarkers": ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { redactCrashSecrets } from "@gajae-code/utils";
|
|
4
5
|
|
|
5
6
|
const CRASH_DIAGNOSTICS_ENV = "GJC_CRASH_DIAGNOSTICS";
|
|
6
7
|
const CRASH_DIAGNOSTICS_DIR_ENV = "GJC_CRASH_DIAGNOSTICS_DIR";
|
|
@@ -169,7 +170,7 @@ export async function writeCrashReport(
|
|
|
169
170
|
pid: process.pid,
|
|
170
171
|
cwd: options.cwd ?? process.cwd(),
|
|
171
172
|
...classification,
|
|
172
|
-
stderrPreview: input.stderr ? trimStartBytes(input.stderr, STDERR_PREVIEW_BYTES) : undefined,
|
|
173
|
+
stderrPreview: input.stderr ? trimStartBytes(redactCrashSecrets(input.stderr), STDERR_PREVIEW_BYTES) : undefined,
|
|
173
174
|
spawnError: input.spawnError === undefined ? undefined : stringifyError(input.spawnError),
|
|
174
175
|
};
|
|
175
176
|
const enabled = crashDiagnosticsEnabled(options.env);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getLogsDir,
|
|
15
15
|
getReportsDir,
|
|
16
16
|
isEnoent,
|
|
17
|
+
redactCrashSecrets,
|
|
17
18
|
resolveEquivalentPath,
|
|
18
19
|
} from "@gajae-code/utils";
|
|
19
20
|
import type { CpuProfile, HeapSnapshot } from "./profiler";
|
|
@@ -228,12 +229,30 @@ export async function createReportBundle(options: ReportBundleOptions): Promise<
|
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
|
|
232
|
+
// Scrub the transcript copies only. Settings, system info, and profiles are
|
|
233
|
+
// separate payloads and stay as collected. Sources on disk are not rewritten.
|
|
234
|
+
for (const archivePath of Object.keys(data)) {
|
|
235
|
+
const content = data[archivePath];
|
|
236
|
+
if (content === undefined || !reportEntryCarriesUserText(archivePath)) continue;
|
|
237
|
+
data[archivePath] = redactCrashSecrets(content);
|
|
238
|
+
}
|
|
239
|
+
|
|
231
240
|
// Write archive
|
|
232
241
|
await Bun.Archive.write(outputPath, data, { compress: "gzip" });
|
|
233
242
|
|
|
234
243
|
return { path: outputPath, files };
|
|
235
244
|
}
|
|
236
245
|
|
|
246
|
+
/** Session, log, artifact, and subagent copies are the transcript the user may attach. */
|
|
247
|
+
function reportEntryCarriesUserText(archivePath: string): boolean {
|
|
248
|
+
return (
|
|
249
|
+
archivePath === "logs.txt" ||
|
|
250
|
+
archivePath === "session.jsonl" ||
|
|
251
|
+
archivePath.startsWith("artifacts/") ||
|
|
252
|
+
archivePath.startsWith("subagents/")
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
237
256
|
/** Add all files from a directory to the archive */
|
|
238
257
|
async function addDirectoryToArchive(
|
|
239
258
|
data: Record<string, string>,
|
package/src/debug/system-info.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import * as os from "node:os";
|
|
6
|
-
import { APP_NAME, formatBytes, getProjectDir, VERSION } from "@gajae-code/utils";
|
|
6
|
+
import { APP_NAME, formatBytes, getProjectDir, redactCrashSecrets, VERSION } from "@gajae-code/utils";
|
|
7
7
|
|
|
8
8
|
export interface SystemInfo {
|
|
9
9
|
os: string;
|
|
@@ -97,7 +97,12 @@ export function formatSystemInfo(info: SystemInfo): string {
|
|
|
97
97
|
return lines.join("\n");
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Sanitize environment variables for a debug report.
|
|
102
|
+
* Sensitive names stay fully replaced. Other values keep their text, with the
|
|
103
|
+
* same credential shapes removed that crash records already scrub before they
|
|
104
|
+
* are written to disk.
|
|
105
|
+
*/
|
|
101
106
|
export function sanitizeEnv(env: Record<string, string | undefined>): Record<string, string> {
|
|
102
107
|
const SENSITIVE_PATTERNS = [
|
|
103
108
|
/key/i,
|
|
@@ -117,7 +122,7 @@ export function sanitizeEnv(env: Record<string, string | undefined>): Record<str
|
|
|
117
122
|
for (const [k, v] of Object.entries(env)) {
|
|
118
123
|
if (v === undefined) continue;
|
|
119
124
|
const isSensitive = SENSITIVE_PATTERNS.some(p => p.test(k));
|
|
120
|
-
result[k] = isSensitive ? "[REDACTED]" : v;
|
|
125
|
+
result[k] = isSensitive ? "[REDACTED]" : redactCrashSecrets(v);
|
|
121
126
|
}
|
|
122
127
|
return result;
|
|
123
128
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { $credentialEnv, $pickCredentialEnv } from '@gajae-code/utils';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_GROK_BUILD_BASE_URL = 'https://cli-chat-proxy.grok.com/v1';
|
|
2
4
|
const ALLOWED_GROK_BUILD_HOSTS = new Set(['cli-chat-proxy.grok.com']);
|
|
5
|
+
const UNSAFE_BASE_URL_ENV = 'GJC_GROK_CLI_ALLOW_UNSAFE_BASE_URL';
|
|
3
6
|
|
|
4
7
|
function normalizeBaseUrl(baseUrl: string): string {
|
|
5
8
|
return baseUrl.trim().replace(/\/+$/, '');
|
|
@@ -14,23 +17,34 @@ function isAllowedCredentialHost(baseUrl: string): boolean {
|
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Operator environment only. `$credentialEnv` already drops a cwd dotenv value,
|
|
22
|
+
* including a dynamic declaration, using the snapshot taken when the env module
|
|
23
|
+
* loaded. A repository `.env` therefore cannot name the Grok Build base URL or
|
|
24
|
+
* approve that URL with the unsafe opt-in.
|
|
25
|
+
*/
|
|
26
|
+
function trustedConfiguredBaseUrl(): string | undefined {
|
|
27
|
+
return $pickCredentialEnv('GJC_GROK_CLI_BASE_URL', 'GROK_CLI_BASE_URL');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function unsafeOverrideAllowed(): boolean {
|
|
31
|
+
return $credentialEnv(UNSAFE_BASE_URL_ENV) === '1';
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
export function getBaseUrl(): string {
|
|
18
|
-
const configured =
|
|
35
|
+
const configured = trustedConfiguredBaseUrl();
|
|
19
36
|
if (!configured) return DEFAULT_GROK_BUILD_BASE_URL;
|
|
20
37
|
|
|
21
38
|
const normalized = normalizeBaseUrl(configured);
|
|
22
39
|
if (isAllowedCredentialHost(normalized)) return normalized;
|
|
23
|
-
|
|
24
|
-
if (process.env.GJC_GROK_CLI_ALLOW_UNSAFE_BASE_URL === '1') return normalized;
|
|
40
|
+
if (unsafeOverrideAllowed()) return normalized;
|
|
25
41
|
|
|
26
42
|
return DEFAULT_GROK_BUILD_BASE_URL;
|
|
27
43
|
}
|
|
28
44
|
|
|
29
45
|
export function isGrokBuildBaseUrlOverrideIgnored(): boolean {
|
|
30
|
-
const configured =
|
|
46
|
+
const configured = trustedConfiguredBaseUrl();
|
|
31
47
|
if (!configured) return false;
|
|
32
48
|
const normalized = normalizeBaseUrl(configured);
|
|
33
|
-
return (
|
|
34
|
-
!isAllowedCredentialHost(normalized) && process.env.GJC_GROK_CLI_ALLOW_UNSAFE_BASE_URL !== '1'
|
|
35
|
-
);
|
|
49
|
+
return !isAllowedCredentialHost(normalized) && !unsafeOverrideAllowed();
|
|
36
50
|
}
|
|
@@ -43,7 +43,7 @@ async function readBoundedAgentsMdFile(
|
|
|
43
43
|
const homeIsStable = async (): Promise<boolean> => {
|
|
44
44
|
if (!options?.home || !options.homeIdentity) return true;
|
|
45
45
|
try {
|
|
46
|
-
const current = await fs.stat(options.home);
|
|
46
|
+
const current = await fs.stat(options.home, { bigint: true });
|
|
47
47
|
return current.dev === options.homeIdentity.dev && current.ino === options.homeIdentity.ino;
|
|
48
48
|
} catch {
|
|
49
49
|
return false;
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -1005,8 +1005,7 @@ export async function readContainedFile(
|
|
|
1005
1005
|
rootIdentity = capturedRoot;
|
|
1006
1006
|
if (
|
|
1007
1007
|
expectedRootIdentity !== undefined &&
|
|
1008
|
-
(rootIdentity.dev !==
|
|
1009
|
-
rootIdentity.ino !== BigInt(expectedRootIdentity.ino))
|
|
1008
|
+
(rootIdentity.dev !== expectedRootIdentity.dev || rootIdentity.ino !== expectedRootIdentity.ino)
|
|
1010
1009
|
)
|
|
1011
1010
|
return null;
|
|
1012
1011
|
await SkillDiscoveryTestHooks.afterContainedRootValidated?.(root);
|
|
@@ -110,23 +110,63 @@ interface CodexMcpServerConfig {
|
|
|
110
110
|
command?: string;
|
|
111
111
|
args?: string[];
|
|
112
112
|
env?: Record<string, string>;
|
|
113
|
-
|
|
113
|
+
/** List of env-var names, or `{ name }` entries. Not a value table. */
|
|
114
|
+
env_vars?: unknown;
|
|
114
115
|
url?: string;
|
|
115
116
|
http_headers?: Record<string, string>;
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
/** Header name to env-var name. Not a header value. */
|
|
118
|
+
env_http_headers?: unknown;
|
|
119
|
+
/** Env-var name whose value is the bearer token. Not the token. */
|
|
120
|
+
bearer_token_env_var?: unknown;
|
|
118
121
|
cwd?: string;
|
|
119
122
|
startup_timeout_sec?: number;
|
|
120
123
|
tool_timeout_sec?: number;
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
/** POSIX env-var name. Rejects values that are not names so they are not stored. */
|
|
127
|
+
function isEnvVarName(value: string): boolean {
|
|
128
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** `${NAME}` keeps the indirection. Callers must not read the process environment. */
|
|
132
|
+
function envVarReference(name: string): string {
|
|
133
|
+
return `\${${name}}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function codexEnvVarEntry(entry: unknown): { name: string; source: string | undefined } | undefined {
|
|
137
|
+
if (typeof entry === "string") return isEnvVarName(entry) ? { name: entry, source: undefined } : undefined;
|
|
138
|
+
if (isRecord(entry) && typeof entry.name === "string" && isEnvVarName(entry.name)) {
|
|
139
|
+
return { name: entry.name, source: typeof entry.source === "string" ? entry.source : undefined };
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Codex remote-executor sources have no local GJC equivalent. */
|
|
145
|
+
function isUnsupportedEnvSource(source: string | undefined): boolean {
|
|
146
|
+
return source !== undefined && source !== "local";
|
|
147
|
+
}
|
|
148
|
+
|
|
123
149
|
/**
|
|
124
150
|
* Extract normalized MCP servers from a Codex `config.toml` `[mcp_servers.*]`
|
|
125
151
|
* section. Codex's config does not carry an `enabled` concept; imported servers
|
|
126
152
|
* default to autoload (startup) behavior after import. Bounded to the supplied
|
|
127
153
|
* content: no filesystem scanning, no user-home reads.
|
|
154
|
+
*
|
|
155
|
+
* `env_vars`, `env_http_headers`, and `bearer_token_env_var` name variables.
|
|
156
|
+
* The process environment is not read. A local name is stored as `${NAME}`
|
|
157
|
+
* only when the destination keeps operator config. A project destination omits
|
|
158
|
+
* the reference: project mcp.json is expanded on a later run, and a name such
|
|
159
|
+
* as `CI_JOB_JWT_V2` is not treated as sensitive, so persisting it would
|
|
160
|
+
* forward a host value. The source level is metadata and does not decide this.
|
|
161
|
+
* A static `env` or `http_headers` value is copied. An entry whose source is
|
|
162
|
+
* not `local` is skipped.
|
|
128
163
|
*/
|
|
129
|
-
function extractCodexMcpServers(
|
|
164
|
+
function extractCodexMcpServers(
|
|
165
|
+
toml: Record<string, unknown>,
|
|
166
|
+
warnings: string[],
|
|
167
|
+
sourcePath: string,
|
|
168
|
+
omitEnvReferences: boolean,
|
|
169
|
+
): Record<string, Partial<MCPServer>> {
|
|
130
170
|
if (!toml.mcp_servers || !isRecord(toml.mcp_servers)) return {};
|
|
131
171
|
|
|
132
172
|
const codexServers = toml.mcp_servers as Record<string, CodexMcpServerConfig>;
|
|
@@ -146,11 +186,38 @@ function extractCodexMcpServers(toml: Record<string, unknown>): Record<string, P
|
|
|
146
186
|
};
|
|
147
187
|
|
|
148
188
|
const env: Record<string, string> = { ...(isStringRecord(serverConfig.env) ? serverConfig.env : {}) };
|
|
149
|
-
if (Array.isArray(serverConfig.env_vars)) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
189
|
+
if (serverConfig.env_vars !== undefined && !Array.isArray(serverConfig.env_vars)) {
|
|
190
|
+
warnings.push(
|
|
191
|
+
`skipped env_vars for "${name}" in ${sourcePath} because it is not a list of environment variable names`,
|
|
192
|
+
);
|
|
193
|
+
} else if (Array.isArray(serverConfig.env_vars)) {
|
|
194
|
+
for (const entry of serverConfig.env_vars) {
|
|
195
|
+
const parsed = codexEnvVarEntry(entry);
|
|
196
|
+
if (!parsed) {
|
|
197
|
+
warnings.push(
|
|
198
|
+
`skipped env_vars entry for "${name}" in ${sourcePath} because it is not an environment variable name`,
|
|
199
|
+
);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (isUnsupportedEnvSource(parsed.source)) {
|
|
203
|
+
warnings.push(
|
|
204
|
+
`skipped env_vars entry ${parsed.name} for "${name}" in ${sourcePath} because source "${parsed.source}" is not executed locally`,
|
|
205
|
+
);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (Object.hasOwn(env, parsed.name)) {
|
|
209
|
+
warnings.push(
|
|
210
|
+
`kept static env ${parsed.name} for "${name}" in ${sourcePath} and did not read the environment`,
|
|
211
|
+
);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (omitEnvReferences) {
|
|
215
|
+
warnings.push(
|
|
216
|
+
`skipped project-scope environment reference ${parsed.name} for "${name}" in ${sourcePath} so a later load cannot expand a host value`,
|
|
217
|
+
);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
env[parsed.name] = envVarReference(parsed.name);
|
|
154
221
|
}
|
|
155
222
|
}
|
|
156
223
|
if (Object.keys(env).length > 0) server.env = env;
|
|
@@ -158,16 +225,50 @@ function extractCodexMcpServers(toml: Record<string, unknown>): Record<string, P
|
|
|
158
225
|
const headers: Record<string, string> = {
|
|
159
226
|
...(isStringRecord(serverConfig.http_headers) ? serverConfig.http_headers : {}),
|
|
160
227
|
};
|
|
161
|
-
if (isRecord(serverConfig.env_http_headers)) {
|
|
228
|
+
if (serverConfig.env_http_headers !== undefined && !isRecord(serverConfig.env_http_headers)) {
|
|
229
|
+
warnings.push(
|
|
230
|
+
`skipped env_http_headers for "${name}" in ${sourcePath} because it is not a table of environment variable names`,
|
|
231
|
+
);
|
|
232
|
+
} else if (isRecord(serverConfig.env_http_headers)) {
|
|
162
233
|
for (const [headerName, envVarName] of Object.entries(serverConfig.env_http_headers)) {
|
|
163
|
-
if (typeof envVarName !== "string")
|
|
164
|
-
|
|
165
|
-
|
|
234
|
+
if (typeof envVarName !== "string" || !isEnvVarName(envVarName)) {
|
|
235
|
+
warnings.push(
|
|
236
|
+
`skipped env_http_headers entry for "${name}" in ${sourcePath} because its value is not an environment variable name`,
|
|
237
|
+
);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (Object.hasOwn(headers, headerName)) {
|
|
241
|
+
warnings.push(
|
|
242
|
+
`kept static header ${headerName} for "${name}" in ${sourcePath} and did not read ${envVarName}`,
|
|
243
|
+
);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (omitEnvReferences) {
|
|
247
|
+
warnings.push(
|
|
248
|
+
`skipped project-scope environment reference ${envVarName} for "${name}" in ${sourcePath} so a later load cannot expand a host value`,
|
|
249
|
+
);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
headers[headerName] = envVarReference(envVarName);
|
|
166
253
|
}
|
|
167
254
|
}
|
|
168
|
-
if (
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
255
|
+
if (serverConfig.bearer_token_env_var !== undefined) {
|
|
256
|
+
const bearerName = serverConfig.bearer_token_env_var;
|
|
257
|
+
if (typeof bearerName !== "string" || !isEnvVarName(bearerName)) {
|
|
258
|
+
warnings.push(
|
|
259
|
+
`skipped bearer_token_env_var for "${name}" in ${sourcePath} because it is not an environment variable name`,
|
|
260
|
+
);
|
|
261
|
+
} else if (Object.hasOwn(headers, "Authorization")) {
|
|
262
|
+
warnings.push(
|
|
263
|
+
`kept static Authorization for "${name}" in ${sourcePath} and did not read bearer_token_env_var ${bearerName}`,
|
|
264
|
+
);
|
|
265
|
+
} else if (omitEnvReferences) {
|
|
266
|
+
warnings.push(
|
|
267
|
+
`skipped project-scope environment reference ${bearerName} for "${name}" in ${sourcePath} so a later load cannot expand a host value`,
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
headers.Authorization = `Bearer ${envVarReference(bearerName)}`;
|
|
271
|
+
}
|
|
171
272
|
}
|
|
172
273
|
if (Object.keys(headers).length > 0) server.headers = headers;
|
|
173
274
|
|
|
@@ -192,6 +293,7 @@ export function normalizeCodexMcpToml(
|
|
|
192
293
|
content: string,
|
|
193
294
|
sourcePath: string,
|
|
194
295
|
level: "project" | "user" = "project",
|
|
296
|
+
options?: { omitEnvReferences?: boolean },
|
|
195
297
|
): MCPCompatNormalizeResult {
|
|
196
298
|
const items: MCPServer[] = [];
|
|
197
299
|
const warnings: string[] = [];
|
|
@@ -212,7 +314,8 @@ export function normalizeCodexMcpToml(
|
|
|
212
314
|
}
|
|
213
315
|
}
|
|
214
316
|
}
|
|
215
|
-
const
|
|
317
|
+
const omitEnvReferences = options?.omitEnvReferences ?? level === "project";
|
|
318
|
+
const servers = extractCodexMcpServers(parsed, warnings, sourcePath, omitEnvReferences);
|
|
216
319
|
for (const [name, config] of Object.entries(servers)) {
|
|
217
320
|
items.push({
|
|
218
321
|
name,
|
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { ApplyPatchError } from "../diff";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
type ApplyPatchOptions,
|
|
17
|
+
type ApplyPatchResult,
|
|
18
|
+
applyPatch,
|
|
19
|
+
type PatchInput,
|
|
20
|
+
preflightPatchMkdir,
|
|
21
|
+
} from "../modes/patch";
|
|
16
22
|
import { parseApplyPatch } from "./parser";
|
|
17
23
|
|
|
18
24
|
export * from "./parser";
|
|
@@ -48,6 +54,11 @@ export async function applyCodexPatch(patchText: string, options: ApplyPatchOpti
|
|
|
48
54
|
deleted: [] as string[],
|
|
49
55
|
};
|
|
50
56
|
|
|
57
|
+
// Containment is checked for every hunk before the first write. A later
|
|
58
|
+
// I/O failure still leaves earlier hunks applied, per spec §6.1.
|
|
59
|
+
for (const hunk of hunks) {
|
|
60
|
+
await preflightPatchMkdir(hunk, options);
|
|
61
|
+
}
|
|
51
62
|
for (const hunk of hunks) {
|
|
52
63
|
const result = await applyPatch(hunk, options);
|
|
53
64
|
results.push(result);
|
package/src/edit/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ import type { VimToolDetails } from "../vim/types";
|
|
|
27
27
|
import { type ApplyPatchParams, applyPatchSchema, expandApplyPatchToEntries } from "./modes/apply-patch";
|
|
28
28
|
import applyPatchGrammar from "./modes/apply-patch.lark" with { type: "text" };
|
|
29
29
|
import { executePatchSingle, type PatchEditEntry, type PatchParams, patchEditSchema } from "./modes/patch";
|
|
30
|
-
import {
|
|
30
|
+
import { executeReplaceEntries, type ReplaceEditEntry, type ReplaceParams, replaceEditSchema } from "./modes/replace";
|
|
31
31
|
import { type EditToolDetails, type EditToolPerFileResult, getLspBatchRequest, type LspBatchRequest } from "./renderer";
|
|
32
32
|
|
|
33
33
|
export { DEFAULT_EDIT_MODE, type EditMode, normalizeEditMode } from "../utils/edit-mode";
|
|
@@ -490,24 +490,20 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
490
490
|
params: EditParams,
|
|
491
491
|
signal: AbortSignal | undefined,
|
|
492
492
|
batchRequest: LspBatchRequest | undefined,
|
|
493
|
-
|
|
493
|
+
_onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
494
494
|
) => {
|
|
495
495
|
const { edits, path } = params as ReplaceParams;
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
508
|
-
}),
|
|
509
|
-
);
|
|
510
|
-
return executeSinglePathEntries(path, runs, batchRequest, onUpdate);
|
|
496
|
+
return executeReplaceEntries({
|
|
497
|
+
session: tool.session,
|
|
498
|
+
path,
|
|
499
|
+
edits: edits as ReplaceEditEntry[],
|
|
500
|
+
signal,
|
|
501
|
+
batchRequest,
|
|
502
|
+
allowFuzzy: tool.#allowFuzzy,
|
|
503
|
+
fuzzyThreshold: tool.#fuzzyThreshold,
|
|
504
|
+
writethrough: tool.#writethrough,
|
|
505
|
+
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
506
|
+
});
|
|
511
507
|
},
|
|
512
508
|
},
|
|
513
509
|
vim: {
|