@oh-my-pi/pi-coding-agent 17.0.9 → 17.1.1
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 +78 -0
- package/README.md +1 -1
- package/dist/cli.js +4685 -4614
- package/dist/types/async/job-manager.d.ts +37 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +41 -0
- package/dist/types/commands/bench.d.ts +15 -3
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/model-registry.d.ts +3 -1
- package/dist/types/config/models-config-schema.d.ts +18 -6
- package/dist/types/config/models-config.d.ts +14 -5
- package/dist/types/config/provider-globals.d.ts +2 -2
- package/dist/types/config/service-tier.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +374 -47
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/dap/client.d.ts +20 -0
- package/dist/types/exec/bash-executor.d.ts +38 -0
- package/dist/types/exec/direnv.d.ts +33 -0
- package/dist/types/export/html/args.d.ts +15 -0
- package/dist/types/export/html/index.d.ts +11 -26
- package/dist/types/export/html/web-palette.d.ts +55 -116
- package/dist/types/extensibility/extensions/loader.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -2
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +3 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +13 -0
- package/dist/types/live/attestation.d.ts +2 -0
- package/dist/types/live/controller.d.ts +48 -0
- package/dist/types/live/protocol.d.ts +85 -0
- package/dist/types/live/protocol.test.d.ts +1 -0
- package/dist/types/live/transport.d.ts +35 -0
- package/dist/types/live/visualizer.d.ts +30 -0
- package/dist/types/lsp/client.d.ts +16 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -0
- package/dist/types/modes/components/custom-message.d.ts +1 -1
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/message-frame.d.ts +8 -4
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/session-account-selector.d.ts +11 -0
- package/dist/types/modes/components/settings-defs.d.ts +7 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +6 -1
- package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +6 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -2
- package/dist/types/plan-mode/plan-files.d.ts +10 -0
- package/dist/types/registry/agent-lifecycle.d.ts +21 -9
- package/dist/types/registry/agent-registry.d.ts +11 -4
- package/dist/types/sdk.d.ts +15 -1
- package/dist/types/secrets/index.d.ts +15 -2
- package/dist/types/secrets/obfuscator.d.ts +113 -15
- package/dist/types/session/acp-permission-gate.d.ts +19 -0
- package/dist/types/session/agent-session-events.d.ts +84 -0
- package/dist/types/session/agent-session-types.d.ts +321 -0
- package/dist/types/session/agent-session.d.ts +135 -753
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/bash-runner.d.ts +75 -0
- package/dist/types/session/blob-store.d.ts +11 -1
- package/dist/types/session/blob-store.test.d.ts +1 -0
- package/dist/types/session/checkpoint-entries.d.ts +28 -0
- package/dist/types/session/eval-runner.d.ts +51 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +24 -0
- package/dist/types/session/model-controls.d.ts +180 -0
- package/dist/types/session/prewalk.d.ts +46 -0
- package/dist/types/session/queued-messages.d.ts +22 -0
- package/dist/types/session/redis-session-storage.d.ts +1 -0
- package/dist/types/session/retry-fallback-chains.d.ts +74 -0
- package/dist/types/session/role-models.d.ts +15 -0
- package/dist/types/session/session-advisors.d.ts +228 -0
- package/dist/types/session/session-entries.d.ts +8 -0
- package/dist/types/session/session-handoff.d.ts +70 -0
- package/dist/types/session/session-history-format.d.ts +6 -1
- package/dist/types/session/session-maintenance.d.ts +246 -0
- package/dist/types/session/session-manager.d.ts +41 -0
- package/dist/types/session/session-memory.d.ts +56 -0
- package/dist/types/session/session-provider-boundary.d.ts +62 -0
- package/dist/types/session/session-stats.d.ts +48 -0
- package/dist/types/session/session-tools.d.ts +158 -0
- package/dist/types/session/session-workspace.d.ts +32 -0
- package/dist/types/session/stream-guards.d.ts +44 -0
- package/dist/types/session/streaming-output.d.ts +8 -0
- package/dist/types/session/todo-tracker.d.ts +56 -0
- package/dist/types/session/ttsr-coordinator.d.ts +51 -0
- package/dist/types/session/turn-recovery.d.ts +225 -0
- package/dist/types/slash-commands/helpers/session-pin.d.ts +9 -0
- package/dist/types/stt/index.d.ts +0 -2
- package/dist/types/stt/stt-controller.d.ts +7 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +4 -1
- package/dist/types/task/output-manager.d.ts +3 -1
- package/dist/types/tiny/title-client.d.ts +10 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/computer/protocol.d.ts +43 -0
- package/dist/types/tools/computer/supervisor.d.ts +32 -0
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +15 -0
- package/dist/types/tools/computer-renderer.d.ts +22 -0
- package/dist/types/tools/computer.d.ts +71 -0
- package/dist/types/tools/context.d.ts +2 -0
- package/dist/types/tools/default-renderer.d.ts +21 -0
- package/dist/types/tools/image-gen.d.ts +4 -4
- package/dist/types/tools/image-providers.d.ts +38 -0
- package/dist/types/tools/index.d.ts +7 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/todo.d.ts +10 -4
- package/dist/types/tools/xdev.d.ts +5 -1
- package/dist/types/tts/streaming-player.d.ts +10 -29
- package/dist/types/tts/vocalizer.d.ts +5 -0
- package/dist/types/utils/jj.d.ts +29 -0
- package/dist/types/utils/lang-from-path.d.ts +1 -0
- package/dist/types/utils/title-generator.d.ts +30 -0
- package/dist/types/utils/tools-manager.d.ts +1 -2
- package/dist/types/vibe/runtime.d.ts +36 -8
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +15 -5
- package/dist/types/web/search/types.d.ts +94 -0
- package/package.json +12 -12
- package/scripts/generate-share-viewer.ts +4 -6
- package/src/advisor/__tests__/advisor.test.ts +643 -0
- package/src/advisor/runtime.ts +144 -43
- package/src/async/job-manager.ts +90 -2
- package/src/cli/args.ts +3 -0
- package/src/cli/auth-gateway-cli.ts +18 -3
- package/src/cli/bench-cli.ts +395 -29
- package/src/cli/flag-tables.ts +3 -0
- package/src/cli/gc-cli.ts +2 -2
- package/src/cli/setup-cli.ts +2 -14
- package/src/cli/usage-cli.ts +10 -1
- package/src/cli.ts +8 -0
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/model-registry.ts +16 -2
- package/src/config/models-config-schema.ts +15 -4
- package/src/config/provider-globals.ts +9 -9
- package/src/config/service-tier.ts +26 -1
- package/src/config/settings-schema.ts +270 -51
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/executor-base.ts +1 -0
- package/src/eval/js/executor.ts +2 -0
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +90 -6
- package/src/exec/direnv.ts +145 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +45 -47
- package/src/export/html/template.css +19 -1
- package/src/export/html/template.html +6 -0
- package/src/export/html/template.js +21 -0
- package/src/export/html/tool-views.generated.js +31 -31
- package/src/export/html/web-palette.ts +116 -132
- package/src/export/share.ts +249 -49
- package/src/extensibility/extensions/loader.ts +29 -1
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +33 -2
- package/src/extensibility/extensions/wrapper.ts +68 -12
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -1
- package/src/extensibility/plugins/legacy-pi-compat.ts +19 -1
- package/src/hindsight/state.ts +64 -6
- package/src/internal-urls/local-protocol.ts +2 -1
- package/src/internal-urls/memory-protocol.ts +2 -2
- package/src/internal-urls/skill-protocol.ts +2 -2
- package/src/internal-urls/ssh-protocol.ts +2 -1
- package/src/internal-urls/vault-protocol.ts +2 -1
- package/src/live/attestation.ts +91 -0
- package/src/live/controller.ts +517 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.test.ts +140 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +422 -0
- package/src/live/visualizer.ts +214 -0
- package/src/lsp/client.ts +29 -9
- package/src/lsp/index.ts +19 -4
- package/src/main.ts +8 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- package/src/memories/index.ts +40 -20
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/mnemopi/backend.ts +24 -7
- package/src/modes/acp/acp-agent.ts +56 -10
- package/src/modes/acp/acp-event-mapper.ts +8 -1
- package/src/modes/components/agent-hub.ts +1 -1
- package/src/modes/components/assistant-message.ts +7 -2
- package/src/modes/components/custom-message.ts +4 -1
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/message-frame.ts +14 -8
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/session-account-selector.ts +62 -0
- package/src/modes/components/settings-defs.ts +23 -1
- package/src/modes/components/settings-selector.ts +169 -1
- package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
- package/src/modes/components/status-line/component.ts +123 -2
- package/src/modes/components/tool-execution.ts +28 -112
- package/src/modes/controllers/command-controller.ts +56 -15
- package/src/modes/controllers/event-controller.ts +111 -16
- package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +20 -4
- package/src/modes/controllers/input-controller.ts +47 -39
- package/src/modes/controllers/live-command-controller.ts +255 -0
- package/src/modes/controllers/mcp-command-controller.ts +10 -1
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +80 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +176 -38
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +17 -9
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +4 -1
- package/src/modes/utils/context-usage.ts +23 -7
- package/src/modes/utils/ui-helpers.ts +10 -5
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/system/computer-safety.md +14 -0
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/project-prompt.md +8 -1
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/workflow-notice.md +48 -40
- package/src/prompts/system/xdev-mount-notice.md +4 -0
- package/src/prompts/tools/computer.md +26 -0
- package/src/prompts/tools/todo.md +3 -1
- package/src/registry/agent-lifecycle.ts +116 -46
- package/src/registry/agent-registry.ts +35 -8
- package/src/registry/persisted-agents.ts +26 -2
- package/src/sdk.ts +215 -136
- package/src/secrets/index.ts +127 -4
- package/src/secrets/obfuscator.ts +2328 -105
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-error-log.test.ts +1 -1
- package/src/session/agent-session-events.ts +66 -0
- package/src/session/agent-session-types.ts +343 -0
- package/src/session/agent-session.ts +1940 -12218
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/auth-storage.ts +1 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.test.ts +56 -0
- package/src/session/blob-store.ts +18 -2
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/eval-runner.ts +217 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +266 -1
- package/src/session/model-controls.ts +714 -0
- package/src/session/prewalk.ts +252 -0
- package/src/session/queued-messages.ts +93 -0
- package/src/session/redis-session-storage.ts +51 -11
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1679 -0
- package/src/session/session-context.ts +6 -3
- package/src/session/session-entries.ts +8 -0
- package/src/session/session-handoff.ts +308 -0
- package/src/session/session-history-format.ts +20 -9
- package/src/session/session-loader.ts +0 -46
- package/src/session/session-maintenance.ts +2983 -0
- package/src/session/session-manager.ts +390 -30
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-provider-boundary.ts +307 -0
- package/src/session/session-stats.ts +293 -0
- package/src/session/session-tools.ts +980 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/streaming-output.ts +52 -5
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-recovery.ts +1629 -0
- package/src/slash-commands/builtin-registry.ts +257 -20
- package/src/slash-commands/helpers/session-pin.ts +44 -0
- package/src/slash-commands/helpers/usage-report.ts +22 -3
- package/src/stt/downloader.ts +0 -2
- package/src/stt/index.ts +0 -2
- package/src/stt/stt-controller.ts +57 -146
- package/src/system-prompt.ts +45 -17
- package/src/task/executor.ts +285 -70
- package/src/task/index.ts +98 -105
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +1 -0
- package/src/tiny/title-client.ts +22 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +116 -86
- package/src/tools/bash-skill-urls.ts +28 -2
- package/src/tools/bash.ts +339 -123
- package/src/tools/browser/launch.ts +9 -1
- package/src/tools/browser/tab-supervisor.ts +8 -5
- package/src/tools/browser.ts +94 -47
- package/src/tools/builtin-names.ts +1 -0
- package/src/tools/computer/protocol.ts +28 -0
- package/src/tools/computer/supervisor.ts +258 -0
- package/src/tools/computer/worker-entry.ts +25 -0
- package/src/tools/computer/worker.ts +135 -0
- package/src/tools/computer-renderer.ts +108 -0
- package/src/tools/computer.ts +433 -0
- package/src/tools/context.ts +2 -0
- package/src/tools/default-renderer.ts +139 -0
- package/src/tools/essential-tools.ts +1 -0
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +14 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +9 -1
- package/src/tools/todo.ts +101 -11
- package/src/tools/vibe.ts +1 -2
- package/src/tools/write.ts +51 -1
- package/src/tools/xdev.ts +121 -29
- package/src/tts/streaming-player.ts +82 -283
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/clipboard.ts +1 -30
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/mac-file-urls.applescript +37 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/utils/tool-choice.ts +14 -0
- package/src/utils/tools-manager.ts +1 -19
- package/src/vibe/runtime.ts +852 -72
- package/src/web/search/index.ts +3 -6
- package/src/web/search/provider.ts +31 -16
- package/src/web/search/providers/xai.ts +7 -1
- package/src/web/search/types.ts +3 -0
- package/dist/types/stt/recorder.d.ts +0 -30
- package/dist/types/stt/transcriber.d.ts +0 -14
- package/dist/types/stt/wav.d.ts +0 -29
- package/dist/types/tts/player.d.ts +0 -32
- package/src/stt/recorder.ts +0 -551
- package/src/stt/transcriber.ts +0 -60
- package/src/stt/wav.ts +0 -173
- package/src/tts/player.ts +0 -137
package/src/secrets/index.ts
CHANGED
|
@@ -1,9 +1,99 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
1
3
|
import * as path from "node:path";
|
|
2
|
-
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { getAgentDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
3
5
|
import { YAML } from "bun";
|
|
4
|
-
import type
|
|
6
|
+
import { regexHasUnresolvableShortMatchFallback, type SecretEntry, sanitizeSecretFriendlyName } from "./obfuscator";
|
|
5
7
|
import { compileSecretRegex } from "./regex";
|
|
6
8
|
|
|
9
|
+
const PLACEHOLDER_KEY_RE = /^[A-Za-z0-9_-]{43}$/;
|
|
10
|
+
const cachedPlaceholderKeys = new Map<string, string>();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Per-install secret key for the placeholder digest. Persisted under the agent
|
|
14
|
+
* config directory and never sent to a provider, so model-visible placeholders
|
|
15
|
+
* cannot be reversed by dictionary-hashing candidate secrets. Stable across
|
|
16
|
+
* sessions so persisted transcripts deobfuscate consistently. Defaults to
|
|
17
|
+
* `getAgentDir()` — the same directory `createAgentSession()` passes as
|
|
18
|
+
* `agentDir` — so a caller relying on the default reads/writes the identical
|
|
19
|
+
* key file live sessions use, per `~/.omp/agent/secret-placeholder.key` in
|
|
20
|
+
* docs/secrets.md.
|
|
21
|
+
*/
|
|
22
|
+
export async function getSecretPlaceholderKey(keyDir: string = getAgentDir()): Promise<string> {
|
|
23
|
+
const keyPath = path.join(keyDir, "secret-placeholder.key");
|
|
24
|
+
const cached = cachedPlaceholderKeys.get(keyPath);
|
|
25
|
+
if (cached !== undefined) return cached;
|
|
26
|
+
|
|
27
|
+
const existing = await readPlaceholderKeyFile(keyPath, false);
|
|
28
|
+
if (existing !== undefined) {
|
|
29
|
+
cachedPlaceholderKeys.set(keyPath, existing);
|
|
30
|
+
return existing;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const generated = crypto.randomBytes(32).toString("base64url");
|
|
34
|
+
await fs.mkdir(keyDir, { recursive: true });
|
|
35
|
+
try {
|
|
36
|
+
await fs.writeFile(keyPath, generated, { flag: "wx", mode: 0o600 });
|
|
37
|
+
cachedPlaceholderKeys.set(keyPath, generated);
|
|
38
|
+
return generated;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if ((err as NodeJS.ErrnoException).code !== "EEXIST") throw err;
|
|
41
|
+
// Another process won the create race but may still be mid-write: `wx`
|
|
42
|
+
// creates the file empty before the bytes land. Wait for non-empty content
|
|
43
|
+
// instead of caching an empty key (which would be a known, dictionaryable
|
|
44
|
+
// key and would not match tokens other processes persist with the real key).
|
|
45
|
+
const winner = await readPlaceholderKeyFile(keyPath, true);
|
|
46
|
+
if (winner === undefined) {
|
|
47
|
+
throw new Error(`secret placeholder key at ${keyPath} exists but is empty or unreadable`);
|
|
48
|
+
}
|
|
49
|
+
cachedPlaceholderKeys.set(keyPath, winner);
|
|
50
|
+
return winner;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Return an existing placeholder key for redaction without creating a new key file. */
|
|
55
|
+
export async function getExistingSecretPlaceholderKey(keyDir: string = getAgentDir()): Promise<string | undefined> {
|
|
56
|
+
const keyPath = path.join(keyDir, "secret-placeholder.key");
|
|
57
|
+
const cached = cachedPlaceholderKeys.get(keyPath);
|
|
58
|
+
if (cached !== undefined) return cached;
|
|
59
|
+
// Redaction-only: this key is loaded solely to redact an existing key file from
|
|
60
|
+
// provider-visible tool output, never to mint placeholders. A truncated/corrupt
|
|
61
|
+
// or unreadable key must NOT block startup for replace-only/no-secret sessions —
|
|
62
|
+
// an invalid key is not a usable HMAC anyway, and a tool reading the same file
|
|
63
|
+
// gets the same bytes, so there is nothing sensitive to redact.
|
|
64
|
+
let existing: string | undefined;
|
|
65
|
+
try {
|
|
66
|
+
existing = await readPlaceholderKeyFile(keyPath, true);
|
|
67
|
+
} catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
if (existing !== undefined) cachedPlaceholderKeys.set(keyPath, existing);
|
|
71
|
+
return existing;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Read and validate the key file, optionally retrying briefly until a valid key lands. */
|
|
75
|
+
async function readPlaceholderKeyFile(keyPath: string, retry: boolean): Promise<string | undefined> {
|
|
76
|
+
const attempts = retry ? 50 : 1;
|
|
77
|
+
let invalidValue: string | undefined;
|
|
78
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
79
|
+
if (attempt > 0) await Bun.sleep(10);
|
|
80
|
+
try {
|
|
81
|
+
const value = (await Bun.file(keyPath).text()).trim();
|
|
82
|
+
if (PLACEHOLDER_KEY_RE.test(value)) return value;
|
|
83
|
+
if (value.length > 0) invalidValue = value;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
if (isEnoent(err)) return undefined;
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (invalidValue !== undefined) {
|
|
90
|
+
throw new Error(`secret placeholder key at ${keyPath} is invalid`);
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type RawSecretEntry = Omit<SecretEntry, "friendlyName"> & { friendlyName?: unknown };
|
|
96
|
+
|
|
7
97
|
export {
|
|
8
98
|
deobfuscateSessionContext,
|
|
9
99
|
deobfuscateToolArguments,
|
|
@@ -11,6 +101,8 @@ export {
|
|
|
11
101
|
obfuscateProviderContext,
|
|
12
102
|
type SecretEntry,
|
|
13
103
|
SecretObfuscator,
|
|
104
|
+
secretEntriesNeedPlaceholderKey,
|
|
105
|
+
secretEntryNeedsPlaceholderKey,
|
|
14
106
|
} from "./obfuscator";
|
|
15
107
|
|
|
16
108
|
/**
|
|
@@ -65,12 +157,14 @@ async function loadSecretsFile(filePath: string): Promise<SecretEntry[]> {
|
|
|
65
157
|
for (let i = 0; i < raw.length; i++) {
|
|
66
158
|
const entry = raw[i];
|
|
67
159
|
if (!validateEntry(entry, filePath, i)) continue;
|
|
160
|
+
const friendlyName = loadFriendlyName(entry, filePath, i);
|
|
68
161
|
entries.push({
|
|
69
162
|
type: entry.type,
|
|
70
163
|
content: entry.content,
|
|
71
164
|
mode: entry.mode ?? "obfuscate",
|
|
72
165
|
replacement: entry.replacement,
|
|
73
166
|
flags: entry.flags,
|
|
167
|
+
friendlyName,
|
|
74
168
|
});
|
|
75
169
|
}
|
|
76
170
|
return entries;
|
|
@@ -81,7 +175,27 @@ async function loadSecretsFile(filePath: string): Promise<SecretEntry[]> {
|
|
|
81
175
|
}
|
|
82
176
|
}
|
|
83
177
|
|
|
84
|
-
|
|
178
|
+
// Validates the friendlyName but returns it UNSANITIZED: `SecretObfuscator`'s
|
|
179
|
+
// own `#createPlaceholder` sanitizes it again and, critically, needs the raw
|
|
180
|
+
// string for `#friendlyNameCollidesWithSecret`'s regex-collision check — a
|
|
181
|
+
// case-sensitive/punctuated regex pattern (e.g. `tok_[a-z0-9]+`) only matches
|
|
182
|
+
// the label as it was actually written, not an already-uppercased,
|
|
183
|
+
// separator-stripped rendering of it. Pre-sanitizing here would silently
|
|
184
|
+
// defeat that check for every `secrets.yml`-loaded entry.
|
|
185
|
+
function loadFriendlyName(entry: RawSecretEntry, filePath: string, index: number): string | undefined {
|
|
186
|
+
if (entry.friendlyName === undefined) return undefined;
|
|
187
|
+
if (typeof entry.friendlyName !== "string") {
|
|
188
|
+
logger.warn(`secrets.yml[${index}]: friendlyName must be a string`, { path: filePath });
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
if (sanitizeSecretFriendlyName(entry.friendlyName) === undefined) {
|
|
192
|
+
logger.warn(`secrets.yml[${index}]: friendlyName must contain at least one letter or digit`, { path: filePath });
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
return entry.friendlyName;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function validateEntry(entry: unknown, filePath: string, index: number): entry is RawSecretEntry {
|
|
85
199
|
if (entry === null || typeof entry !== "object") {
|
|
86
200
|
logger.warn(`secrets.yml[${index}]: entry must be an object`, { path: filePath });
|
|
87
201
|
return false;
|
|
@@ -108,8 +222,9 @@ function validateEntry(entry: unknown, filePath: string, index: number): entry i
|
|
|
108
222
|
return false;
|
|
109
223
|
}
|
|
110
224
|
if (e.type === "regex") {
|
|
225
|
+
let regex: RegExp;
|
|
111
226
|
try {
|
|
112
|
-
compileSecretRegex(e.content as string, e.flags as string | undefined);
|
|
227
|
+
regex = compileSecretRegex(e.content as string, e.flags as string | undefined);
|
|
113
228
|
} catch (error) {
|
|
114
229
|
logger.warn(`secrets.yml[${index}]: invalid regex pattern`, {
|
|
115
230
|
path: filePath,
|
|
@@ -118,6 +233,14 @@ function validateEntry(entry: unknown, filePath: string, index: number): entry i
|
|
|
118
233
|
});
|
|
119
234
|
return false;
|
|
120
235
|
}
|
|
236
|
+
const mode = (e.mode as "obfuscate" | "replace" | undefined) ?? "obfuscate";
|
|
237
|
+
if (mode === "replace" && e.replacement === undefined && regexHasUnresolvableShortMatchFallback(regex)) {
|
|
238
|
+
logger.warn(
|
|
239
|
+
`secrets.yml[${index}]: regex matches every 1-2 character candidate with no custom replacement, so a match can never be redacted distinctly from itself`,
|
|
240
|
+
{ path: filePath, pattern: e.content },
|
|
241
|
+
);
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
121
244
|
}
|
|
122
245
|
return true;
|
|
123
246
|
}
|