@oh-my-pi/pi-coding-agent 17.2.10 → 17.2.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 +53 -0
- package/dist/{CHANGELOG-rhwzpexa.md → CHANGELOG-k9ghy5sn.md} +53 -0
- package/dist/cli.js +10775 -10762
- package/dist/types/advisor/runtime.d.ts +1 -1
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/custom-models.d.ts +31 -0
- package/dist/types/config/model-config-values.d.ts +19 -0
- package/dist/types/config/model-patch.d.ts +93 -0
- package/dist/types/config/model-provider-discovery.d.ts +51 -0
- package/dist/types/config/model-registry.d.ts +9 -52
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/config/settings.d.ts +5 -3
- package/dist/types/debug/raw-sse-buffer.d.ts +9 -0
- package/dist/types/discovery/agent-plugin-format.d.ts +136 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +33 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/eval/executor-base.d.ts +8 -2
- package/dist/types/eval/kernel-session-registry.d.ts +60 -0
- package/dist/types/export/share.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +7 -0
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/lsp/diagnostics.d.ts +96 -0
- package/dist/types/lsp/index.d.ts +7 -128
- package/dist/types/lsp/servers.d.ts +72 -0
- package/dist/types/lsp/tool.d.ts +42 -0
- package/dist/types/lsp/workspace-diagnostics.d.ts +12 -0
- package/dist/types/lsp/writethrough.d.ts +33 -0
- package/dist/types/mcp/transports/header-policy.d.ts +46 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/components/agent-hub-projection.d.ts +2 -7
- package/dist/types/modes/components/agent-hub-renderer.d.ts +0 -7
- package/dist/types/modes/components/agent-hub.d.ts +2 -0
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/theme/color.d.ts +19 -0
- package/dist/types/modes/theme/loader.d.ts +19 -0
- package/dist/types/modes/theme/schema.d.ts +175 -0
- package/dist/types/modes/theme/symbols.d.ts +28 -0
- package/dist/types/modes/theme/theme-class.d.ts +244 -0
- package/dist/types/modes/theme/theme.d.ts +9 -280
- package/dist/types/modes/theme/tui-adapters.d.ts +13 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +1 -3
- package/dist/types/secrets/index.d.ts +26 -2
- package/dist/types/secrets/message-transform.d.ts +40 -0
- package/dist/types/secrets/obfuscator.d.ts +0 -108
- package/dist/types/secrets/placeholder-scan.d.ts +95 -0
- package/dist/types/secrets/placeholder.d.ts +94 -0
- package/dist/types/secrets/replacement.d.ts +82 -0
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session-types.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +2 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-handoff.d.ts +3 -3
- package/dist/types/session/session-manager.d.ts +32 -0
- package/dist/types/session/session-provider-boundary.d.ts +1 -1
- package/dist/types/session/session-tools.d.ts +8 -0
- package/dist/types/session/turn-recovery.d.ts +9 -4
- package/dist/types/slash-commands/builtin-collaboration.d.ts +2 -0
- package/dist/types/slash-commands/builtin-completions.d.ts +36 -0
- package/dist/types/slash-commands/builtin-control.d.ts +2 -0
- package/dist/types/slash-commands/builtin-lifecycle.d.ts +3 -0
- package/dist/types/slash-commands/builtin-marketplace.d.ts +11 -0
- package/dist/types/slash-commands/builtin-modes.d.ts +5 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/slash-commands/builtin-session.d.ts +2 -0
- package/dist/types/task/index.d.ts +2 -0
- package/dist/types/tools/gh-common.d.ts +69 -0
- package/dist/types/tools/gh-pr-checkout.d.ts +84 -0
- package/dist/types/tools/gh-pr-diff.d.ts +102 -0
- package/dist/types/tools/gh-run-watch.d.ts +78 -0
- package/dist/types/tools/gh-search.d.ts +61 -0
- package/dist/types/tools/gh-types.d.ts +340 -0
- package/dist/types/tools/gh-view.d.ts +88 -0
- package/dist/types/tools/gh.d.ts +4 -201
- package/dist/types/tools/read-archive.d.ts +16 -0
- package/dist/types/tools/read-format.d.ts +104 -0
- package/dist/types/tools/read-path-resolution.d.ts +19 -0
- package/dist/types/tools/read-pdf-images.d.ts +12 -0
- package/dist/types/tools/read-renderer.d.ts +24 -0
- package/dist/types/tools/read-selector.d.ts +27 -0
- package/dist/types/tools/read-sqlite.d.ts +16 -0
- package/dist/types/tools/read-summary.d.ts +19 -0
- package/dist/types/tools/read.d.ts +1 -23
- package/dist/types/tools/shell-tokenize.d.ts +18 -1
- package/dist/types/utils/changelog.d.ts +0 -5
- package/package.json +13 -13
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +12 -7
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/command-help.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/share.ts +71 -0
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/custom-models.ts +188 -0
- package/src/config/model-config-values.ts +128 -0
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-patch.ts +252 -0
- package/src/config/model-provider-discovery.ts +132 -0
- package/src/config/model-registry.ts +84 -704
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +53 -3
- package/src/debug/raw-sse-buffer.ts +20 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +75 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/edit/hashline/diff.ts +5 -1
- package/src/eval/executor-base.ts +39 -6
- package/src/eval/jl/executor.ts +82 -371
- package/src/eval/kernel-session-registry.ts +398 -0
- package/src/eval/py/executor.ts +53 -261
- package/src/eval/rb/executor.ts +36 -279
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/export/share.ts +2 -1
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/loader.ts +78 -14
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +12 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/lsp/diagnostics.ts +516 -0
- package/src/lsp/index.ts +20 -2819
- package/src/lsp/servers.ts +296 -0
- package/src/lsp/tool.ts +1352 -0
- package/src/lsp/workspace-diagnostics.ts +170 -0
- package/src/lsp/writethrough.ts +561 -0
- package/src/main.ts +3 -2
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +15 -4
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +2 -2
- package/src/modes/components/agent-hub-renderer.ts +3 -7
- package/src/modes/components/agent-hub.ts +5 -0
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +6 -4
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +8 -2
- package/src/modes/controllers/event-controller.ts +15 -15
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/theme/color.ts +133 -0
- package/src/modes/theme/loader.ts +178 -0
- package/src/modes/theme/schema.ts +263 -0
- package/src/modes/theme/symbols.ts +1000 -0
- package/src/modes/theme/theme-class.ts +611 -0
- package/src/modes/theme/theme.ts +27 -2453
- package/src/modes/theme/tui-adapters.ts +279 -0
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/registry/agent-registry.ts +2 -2
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +51 -6
- package/src/secrets/message-transform.ts +287 -0
- package/src/secrets/obfuscator.ts +39 -1303
- package/src/secrets/placeholder-scan.ts +506 -0
- package/src/secrets/placeholder.ts +309 -0
- package/src/secrets/replacement.ts +216 -0
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session-types.ts +6 -0
- package/src/session/agent-session.ts +146 -21
- package/src/session/indexed-session-storage.ts +7 -2
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-advisors.ts +32 -34
- package/src/session/session-context.ts +3 -5
- package/src/session/session-handoff.ts +39 -16
- package/src/session/session-manager.ts +67 -3
- package/src/session/session-provider-boundary.ts +3 -6
- package/src/session/session-tools.ts +37 -3
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +115 -84
- package/src/slash-commands/builtin-collaboration.ts +504 -0
- package/src/slash-commands/builtin-completions.ts +291 -0
- package/src/slash-commands/builtin-control.ts +78 -0
- package/src/slash-commands/builtin-lifecycle.ts +506 -0
- package/src/slash-commands/builtin-marketplace.ts +567 -0
- package/src/slash-commands/builtin-modes.ts +518 -0
- package/src/slash-commands/builtin-registry.ts +21 -2996
- package/src/slash-commands/builtin-session.ts +592 -0
- package/src/task/executor.ts +17 -14
- package/src/task/index.ts +21 -6
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +10 -11
- package/src/tools/debug.ts +1 -1
- package/src/tools/gh-common.ts +288 -0
- package/src/tools/gh-pr-checkout.ts +679 -0
- package/src/tools/gh-pr-diff.ts +473 -0
- package/src/tools/gh-run-watch.ts +1015 -0
- package/src/tools/gh-search.ts +500 -0
- package/src/tools/gh-types.ts +379 -0
- package/src/tools/gh-view.ts +612 -0
- package/src/tools/gh.ts +109 -3821
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/read-archive.ts +209 -0
- package/src/tools/read-format.ts +593 -0
- package/src/tools/read-path-resolution.ts +36 -0
- package/src/tools/read-pdf-images.ts +250 -0
- package/src/tools/read-renderer.ts +289 -0
- package/src/tools/read-selector.ts +84 -0
- package/src/tools/read-sqlite.ts +215 -0
- package/src/tools/read-summary.ts +199 -0
- package/src/tools/read.ts +82 -1824
- package/src/tools/shell-tokenize.ts +99 -1
- package/src/utils/changelog.ts +1 -1
- package/src/utils/title-generator.ts +3 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/zai.ts +12 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { AssistantMessage, Context, Message } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import type { SessionContext } from "../session/session-context.js";
|
|
4
|
+
import type { SecretObfuscator } from "./obfuscator.js";
|
|
5
|
+
/**
|
|
6
|
+
* Restore secret placeholders for local display. Only message kinds the model
|
|
7
|
+
* itself authored from obfuscated context carry placeholders — assistant
|
|
8
|
+
* content and the LLM-written branch/compaction summaries. User, developer, and
|
|
9
|
+
* tool-result messages are persisted with their literal text, so operator-authored
|
|
10
|
+
* placeholder-shaped text must survive untouched; those roles are never walked.
|
|
11
|
+
*/
|
|
12
|
+
export declare function deobfuscateSessionContext(sessionContext: SessionContext, obfuscator: SecretObfuscator | undefined): SessionContext;
|
|
13
|
+
export declare function deobfuscateAgentMessages(obfuscator: SecretObfuscator, messages: AgentMessage[]): AgentMessage[];
|
|
14
|
+
/**
|
|
15
|
+
* Restore placeholders in assistant content: visible text and tool-call
|
|
16
|
+
* arguments/intent/rawBlock. Thinking and signatures are opaque
|
|
17
|
+
* provider-replay/hidden-reasoning data and pass through byte-identical.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deobfuscateAssistantContent(obfuscator: SecretObfuscator, content: AssistantMessage["content"]): AssistantMessage["content"];
|
|
20
|
+
/**
|
|
21
|
+
* Restore placeholders inside a tool call's arguments. Arguments are arbitrary
|
|
22
|
+
* model-authored JSON, so tool-call arguments are the ONLY place a recursive
|
|
23
|
+
* JSON walk runs.
|
|
24
|
+
*/
|
|
25
|
+
export declare function deobfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>): Record<string, unknown>;
|
|
26
|
+
/** Redact secrets inside a tool call's arguments (same JSON-walk exception as {@link deobfuscateToolArguments}). */
|
|
27
|
+
export declare function obfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>, sharedRegexSecretValues?: ReadonlySet<string>): Record<string, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Redact secrets from outbound messages. User messages, tool results, and
|
|
30
|
+
* user-authored developer messages (e.g. `@file` mentions) are obfuscated.
|
|
31
|
+
* Assistant replay content is re-obfuscated too, because session restoration
|
|
32
|
+
* expands keyed placeholders locally before the next provider request. Inline
|
|
33
|
+
* image bytes are never walked.
|
|
34
|
+
*/
|
|
35
|
+
export declare function obfuscateMessages(obfuscator: SecretObfuscator, messages: Message[]): Message[];
|
|
36
|
+
/**
|
|
37
|
+
* Redact outbound provider context. Only conversation messages are rewritten;
|
|
38
|
+
* the static system prompt and tool schemas pass through unchanged.
|
|
39
|
+
*/
|
|
40
|
+
export declare function obfuscateProviderContext(obfuscator: SecretObfuscator | undefined, context: Context): Context;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import type { AssistantMessage, Context, Message } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import type { SessionContext } from "../session/session-context.js";
|
|
4
1
|
export interface SecretEntry {
|
|
5
2
|
type: "plain" | "regex";
|
|
6
3
|
content: string;
|
|
@@ -15,75 +12,6 @@ export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
|
15
12
|
export type JsonRecord = {
|
|
16
13
|
[key: string]: JsonValue | undefined;
|
|
17
14
|
};
|
|
18
|
-
/**
|
|
19
|
-
* Whether a default (no custom `replacement`) replace-mode regex can never
|
|
20
|
-
* safely redact a 1-2 char match: `findNonMatchingReplacement`'s bounded
|
|
21
|
-
* search — the same search `#generateRegexReplacement` runs at match time —
|
|
22
|
-
* finds no candidate the regex fails to re-match. This holds independent of
|
|
23
|
-
* any actual per-install key: the search already exhausts every character in
|
|
24
|
-
* `REPLACEMENT_CHARS` (the alphabet `buildKeyedReplacementRun` draws its
|
|
25
|
-
* fallback marker from) plus punctuation and whitespace, so if none of those
|
|
26
|
-
* escape the regex, no key-derived marker drawn from the same alphabet can
|
|
27
|
-
* either — the marker is guaranteed to re-match too, making every such match
|
|
28
|
-
* unresolvable: the fallback could only ever emit the raw matched text
|
|
29
|
-
* unchanged. Probed with a value (`"\0".repeat(length)`) the bounded search
|
|
30
|
-
* never treats as a real candidate, so the result depends only on the
|
|
31
|
-
* regex's own matching behavior, not on this specific probe.
|
|
32
|
-
*/
|
|
33
|
-
export declare function regexHasUnresolvableShortMatchFallback(regex: RegExp): boolean;
|
|
34
|
-
export declare const MIN_OBFUSCATE_SECRET_LEN = 8;
|
|
35
|
-
/** Normalize a friendly name into the model-visible placeholder prefix. */
|
|
36
|
-
export declare function sanitizeSecretFriendlyName(name: string): string | undefined;
|
|
37
|
-
/**
|
|
38
|
-
* Whether an entry needs the persisted placeholder key: either because it can
|
|
39
|
-
* produce a reversible (keyed) obfuscate-mode placeholder, or because a default
|
|
40
|
-
* (no custom `replacement`) replace-mode regex can reach
|
|
41
|
-
* `#generateRegexReplacement`'s key-derived idempotent fallback marker (see
|
|
42
|
-
* `#generateReplacement`) when every same-length candidate re-matches a
|
|
43
|
-
* pathological match-everything config (e.g. `[\s\S]{8}`). That fallback depends
|
|
44
|
-
* on the persisted per-install key — not just length — to stay a fixed point
|
|
45
|
-
* across a process restart; without a persisted key, a fresh install falls back
|
|
46
|
-
* to a process-random key (`defaultPlaceholderKey()`), so the fallback marker
|
|
47
|
-
* would churn across restarts even though the algorithm itself is stable. A
|
|
48
|
-
* regex WITH a custom `replacement` never reaches that fallback (it always emits
|
|
49
|
-
* the literal configured string), and a plain replace secret's replacement is
|
|
50
|
-
* pure content-hash (`#generateSecretReplacement`), so neither needs the key.
|
|
51
|
-
* Short plain obfuscate entries are toned down (never placeheld), so they must
|
|
52
|
-
* NOT force key creation: otherwise a `secret-placeholder.key` file is written
|
|
53
|
-
* and persisted for a config that ends up with no active secrets, leaving the
|
|
54
|
-
* key readable via a tool and reusable for later placeholders.
|
|
55
|
-
*/
|
|
56
|
-
export declare function secretEntryNeedsPlaceholderKey(entry: SecretEntry): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Whether a SET of entries needs the persisted placeholder key. `obfuscate()`
|
|
59
|
-
* applies plain replace-mode mappings before the plain-obfuscate pass, so a plain
|
|
60
|
-
* obfuscate entry only emits a reversible (keyed) placeholder when its content can
|
|
61
|
-
* still appear AFTER the replace phase. When no obfuscate entry can ever produce a
|
|
62
|
-
* placeholder, the persisted key must NOT be required/created — otherwise an
|
|
63
|
-
* effectively replace-only secret set still writes `secret-placeholder.key` and
|
|
64
|
-
* fails startup when the agent config dir is unwritable.
|
|
65
|
-
*
|
|
66
|
-
* The decision models the replace phase as the obfuscator actually runs it:
|
|
67
|
-
* replace mappings are content-keyed (later duplicate wins) and applied in
|
|
68
|
-
* descending content-length order; for a fresh probe (no prior placeholders) that
|
|
69
|
-
* phase is plain sequential substring replacement. A plain obfuscate entry needs
|
|
70
|
-
* the key when its content survives that simulated phase (direct typing) OR when
|
|
71
|
-
* any effective replacement can form the content via tiling — a substring,
|
|
72
|
-
* wholesale superstring, or prefix/suffix border that joins with surrounding
|
|
73
|
-
* passthrough bytes (see `replacementCanFormContent`). This covers direct
|
|
74
|
-
* shadowing (`SECRET -> safe`), reintroduction, duplicate ordering, transitive
|
|
75
|
-
* chains, and context-joined fragments uniformly. Default (omitted) replacements
|
|
76
|
-
* are deterministic, length-preserving, and distinct, so a same-content shadow
|
|
77
|
-
* with no other interacting replacement stays key-free.
|
|
78
|
-
* Replacement outputs are themselves rewritten by every later (shorter-content)
|
|
79
|
-
* replacement before the plain-obfuscate pass sees them, so a fragment that a
|
|
80
|
-
* subsequent replacement erases (`AA -> SEC` then `S -> X` turns every `SEC` into
|
|
81
|
-
* `XEC`) no longer forces the key. Surrounding bytes stay modeled as arbitrary
|
|
82
|
-
* passthrough, so testing the surviving fragment only drops false positives and
|
|
83
|
-
* never under-approximates a real key need.
|
|
84
|
-
*/
|
|
85
|
-
export declare function secretEntriesNeedPlaceholderKey(entries: SecretEntry[]): boolean;
|
|
86
|
-
export declare function stripPendingSecretPlaceholderSuffix(text: string): string;
|
|
87
15
|
export declare class SecretObfuscator {
|
|
88
16
|
#private;
|
|
89
17
|
constructor(entries: SecretEntry[], key?: string | (() => string));
|
|
@@ -99,39 +27,3 @@ export declare class SecretObfuscator {
|
|
|
99
27
|
collectRegexSecretValuesForObfuscation(text: string): Set<string>;
|
|
100
28
|
stripUnsafeFriendlyPlaceholderPrefixes(text: string, sharedRegexSecretValues: ReadonlySet<string>): string;
|
|
101
29
|
}
|
|
102
|
-
/**
|
|
103
|
-
* Restore secret placeholders for local display. Only message kinds the model
|
|
104
|
-
* itself authored from obfuscated context carry placeholders — assistant
|
|
105
|
-
* content and the LLM-written branch/compaction summaries. User, developer, and
|
|
106
|
-
* tool-result messages are persisted with their literal text, so operator-authored
|
|
107
|
-
* placeholder-shaped text must survive untouched; those roles are never walked.
|
|
108
|
-
*/
|
|
109
|
-
export declare function deobfuscateSessionContext(sessionContext: SessionContext, obfuscator: SecretObfuscator | undefined): SessionContext;
|
|
110
|
-
export declare function deobfuscateAgentMessages(obfuscator: SecretObfuscator, messages: AgentMessage[]): AgentMessage[];
|
|
111
|
-
/**
|
|
112
|
-
* Restore placeholders in assistant content: visible text and tool-call
|
|
113
|
-
* arguments/intent/rawBlock. Thinking and signatures are opaque
|
|
114
|
-
* provider-replay/hidden-reasoning data and pass through byte-identical.
|
|
115
|
-
*/
|
|
116
|
-
export declare function deobfuscateAssistantContent(obfuscator: SecretObfuscator, content: AssistantMessage["content"]): AssistantMessage["content"];
|
|
117
|
-
/**
|
|
118
|
-
* Restore placeholders inside a tool call's arguments. Arguments are arbitrary
|
|
119
|
-
* model-authored JSON, so tool-call arguments are the ONLY place a recursive
|
|
120
|
-
* JSON walk runs.
|
|
121
|
-
*/
|
|
122
|
-
export declare function deobfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>): Record<string, unknown>;
|
|
123
|
-
/** Redact secrets inside a tool call's arguments (same JSON-walk exception as {@link deobfuscateToolArguments}). */
|
|
124
|
-
export declare function obfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>, sharedRegexSecretValues?: ReadonlySet<string>): Record<string, unknown>;
|
|
125
|
-
/**
|
|
126
|
-
* Redact secrets from outbound messages. User messages, tool results, and
|
|
127
|
-
* user-authored developer messages (e.g. `@file` mentions) are obfuscated.
|
|
128
|
-
* Assistant replay content is re-obfuscated too, because session restoration
|
|
129
|
-
* expands keyed placeholders locally before the next provider request. Inline
|
|
130
|
-
* image bytes are never walked.
|
|
131
|
-
*/
|
|
132
|
-
export declare function obfuscateMessages(obfuscator: SecretObfuscator, messages: Message[]): Message[];
|
|
133
|
-
/**
|
|
134
|
-
* Redact outbound provider context. Only conversation messages are rewritten;
|
|
135
|
-
* the static system prompt and tool schemas pass through unchanged.
|
|
136
|
-
*/
|
|
137
|
-
export declare function obfuscateProviderContext(obfuscator: SecretObfuscator | undefined, context: Context): Context;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { JsonValue, SecretObfuscator } from "./obfuscator.js";
|
|
2
|
+
import { type RegexScanSegment, type ReplaceRegexScan } from "./placeholder.js";
|
|
3
|
+
export declare function transformOutsidePlaceholdersTracked(text: string, origin: string, shouldSkipPlaceholder: (placeholder: string) => boolean, transform: (chunk: string) => string, preservePlaceholder?: (placeholder: string) => string): {
|
|
4
|
+
text: string;
|
|
5
|
+
origin: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function trailingOutsidePreservedPlaceholderChunk(text: string, shouldPreservePlaceholder: (placeholder: string) => boolean): string;
|
|
8
|
+
export declare function buildReplaceRegexScan(text: string, ranges: ReadonlyArray<{
|
|
9
|
+
start: number;
|
|
10
|
+
end: number;
|
|
11
|
+
}>, deobfuscateMap: ReadonlyMap<string, {
|
|
12
|
+
secret: string;
|
|
13
|
+
recursive: boolean;
|
|
14
|
+
}>): ReplaceRegexScan;
|
|
15
|
+
export declare function mapReplaceRegexMatch(segments: ReadonlyArray<RegexScanSegment>, scanStart: number, scanEnd: number): {
|
|
16
|
+
start: number;
|
|
17
|
+
end: number;
|
|
18
|
+
recursive: boolean;
|
|
19
|
+
preserveGeneratedPlaceholders: boolean;
|
|
20
|
+
partialPlaceholderCut: boolean;
|
|
21
|
+
cutResumeIndex: number;
|
|
22
|
+
firstPlaceholderScanStart: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Extend a scan-space resume position past a consecutive run of generated
|
|
26
|
+
* placeholder segments starting exactly at it, with no raw gap in between. A
|
|
27
|
+
* cut-resolution resume point that happens to land precisely on the START of
|
|
28
|
+
* ANOTHER placeholder must not stop there and hand it to a fresh `regex.exec`
|
|
29
|
+
* attempt — the same content, scanned as an opaque adjacent placeholder run,
|
|
30
|
+
* must resolve identically whether the run's LEADING member is still raw text
|
|
31
|
+
* (this call is about to placeholder it) or is ALREADY a placeholder from a
|
|
32
|
+
* prior call or an earlier pass of this same call. Without this, a bounded
|
|
33
|
+
* regex whose reach spans two adjacent secrets plus trailing spillover bytes
|
|
34
|
+
* (e.g. `[A-Z]{9}` over `ABCDEFGH` + `SECRETUV` + `A`) resolves the leading
|
|
35
|
+
* secret as its own independent redaction on the FIRST obfuscate() call (a
|
|
36
|
+
* genuinely raw prefix gets its own match, then the discard for the rest
|
|
37
|
+
* resumes right after it), but on a LATER call — once that prefix is itself a
|
|
38
|
+
* placeholder — the very first match attempt starts already inside the
|
|
39
|
+
* placeholder run, cannot be prefix-narrowed at all, and its discard resume
|
|
40
|
+
* point lands mid-run instead of past it, exposing a shorter tail (`SECRETUV`
|
|
41
|
+
* + `A`) to a clean, un-cut match the first call never attempted. Chaining the
|
|
42
|
+
* resume point through every immediately-adjacent placeholder makes both
|
|
43
|
+
* calls land on the exact same next scan position.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extendPastAdjacentPlaceholders(segments: ReadonlyArray<RegexScanSegment>, index: number): number;
|
|
46
|
+
export declare function redactWithFixedReplacementOutsidePlaceholders(text: string, origin: string, replacement: string, shouldPreservePlaceholder: (placeholder: string) => boolean): {
|
|
47
|
+
text: string;
|
|
48
|
+
origin: string;
|
|
49
|
+
};
|
|
50
|
+
export declare function deobfuscateGeneratedPlaceholderRanges(text: string, start: number, end: number, ranges: ReadonlyArray<{
|
|
51
|
+
start: number;
|
|
52
|
+
end: number;
|
|
53
|
+
}>, deobfuscateMap: ReadonlyMap<string, {
|
|
54
|
+
secret: string;
|
|
55
|
+
recursive: boolean;
|
|
56
|
+
}>): {
|
|
57
|
+
text: string;
|
|
58
|
+
recursive: boolean;
|
|
59
|
+
};
|
|
60
|
+
export declare function placeholderInnerText(text: string, start: number, end: number, ranges: ReadonlyArray<{
|
|
61
|
+
start: number;
|
|
62
|
+
end: number;
|
|
63
|
+
}>, deobfuscateMap: ReadonlyMap<string, {
|
|
64
|
+
secret: string;
|
|
65
|
+
recursive: boolean;
|
|
66
|
+
}>): string;
|
|
67
|
+
export declare function textOutsidePlaceholderRanges(text: string, start: number, end: number, ranges: ReadonlyArray<{
|
|
68
|
+
start: number;
|
|
69
|
+
end: number;
|
|
70
|
+
}>): string;
|
|
71
|
+
export declare function outsidePlaceholderRangesAnyIndependentlyMatch(text: string, scanText: string, segments: ReadonlyArray<RegexScanSegment>, start: number, end: number, ranges: ReadonlyArray<{
|
|
72
|
+
start: number;
|
|
73
|
+
end: number;
|
|
74
|
+
}>, regex: RegExp): boolean;
|
|
75
|
+
export declare function firstOutsidePlaceholderRange(start: number, end: number, ranges: ReadonlyArray<{
|
|
76
|
+
start: number;
|
|
77
|
+
end: number;
|
|
78
|
+
}>): {
|
|
79
|
+
start: number;
|
|
80
|
+
end: number;
|
|
81
|
+
} | undefined;
|
|
82
|
+
export declare function countOutsidePlaceholderRanges(start: number, end: number, ranges: ReadonlyArray<{
|
|
83
|
+
start: number;
|
|
84
|
+
end: number;
|
|
85
|
+
}>): number;
|
|
86
|
+
export declare function replaceRange(text: string, start: number, end: number, replacement: string): string;
|
|
87
|
+
/** Deep-walk an object, transforming all string values. */
|
|
88
|
+
export declare function deepWalkStrings<T>(obj: T, transform: (s: string) => string): T;
|
|
89
|
+
export declare function collectJsonRegexSecretValues(obfuscator: SecretObfuscator, value: JsonValue): Set<string>;
|
|
90
|
+
/**
|
|
91
|
+
* Map every string in arbitrary JSON. Used ONLY for tool-call arguments, whose
|
|
92
|
+
* shape is model-authored and not known ahead of time. No other caller may walk
|
|
93
|
+
* untyped data: every message/content path is handled by a typed transformer.
|
|
94
|
+
*/
|
|
95
|
+
export declare function mapJsonStrings(value: JsonValue, fn: (s: string) => string): JsonValue;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { SecretEntry } from "./obfuscator.js";
|
|
2
|
+
export declare const MIN_OBFUSCATE_SECRET_LEN = 8;
|
|
3
|
+
export declare function defaultPlaceholderKey(): string;
|
|
4
|
+
type PlaceholderCaseHint = "U" | "L" | "C" | "M";
|
|
5
|
+
/** Normalize a friendly name into the model-visible placeholder prefix. */
|
|
6
|
+
export declare function sanitizeSecretFriendlyName(name: string): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize a secret value into the same alnum-only, uppercased shape a
|
|
9
|
+
* friendly-name label or placeholder prefix is sanitized into, so comparing a
|
|
10
|
+
* raw (possibly lowercase/punctuated) secret value against already-sanitized,
|
|
11
|
+
* model-visible text does not miss a case- or separator-only variant. Unlike
|
|
12
|
+
* `sanitizeSecretFriendlyName` this never truncates and never signals "empty"
|
|
13
|
+
* via `undefined` — callers already guard on `.length > 0` before comparing.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sanitizeForCollisionCheck(value: string): string;
|
|
16
|
+
export declare function sanitizedLabelCollidesWithSecret(sanitizedLabel: string, sanitizedSecret: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether an entry needs the persisted placeholder key: either because it can
|
|
19
|
+
* produce a reversible (keyed) obfuscate-mode placeholder, or because a default
|
|
20
|
+
* (no custom `replacement`) replace-mode regex can reach
|
|
21
|
+
* `#generateRegexReplacement`'s key-derived idempotent fallback marker (see
|
|
22
|
+
* `#generateReplacement`) when every same-length candidate re-matches a
|
|
23
|
+
* pathological match-everything config (e.g. `[\s\S]{8}`). That fallback depends
|
|
24
|
+
* on the persisted per-install key — not just length — to stay a fixed point
|
|
25
|
+
* across a process restart; without a persisted key, a fresh install falls back
|
|
26
|
+
* to a process-random key (`defaultPlaceholderKey()`), so the fallback marker
|
|
27
|
+
* would churn across restarts even though the algorithm itself is stable. A
|
|
28
|
+
* regex WITH a custom `replacement` never reaches that fallback (it always emits
|
|
29
|
+
* the literal configured string), and a plain replace secret's replacement is
|
|
30
|
+
* pure content-hash (`#generateSecretReplacement`), so neither needs the key.
|
|
31
|
+
* Short plain obfuscate entries are toned down (never placeheld), so they must
|
|
32
|
+
* NOT force key creation: otherwise a `secret-placeholder.key` file is written
|
|
33
|
+
* and persisted for a config that ends up with no active secrets, leaving the
|
|
34
|
+
* key readable via a tool and reusable for later placeholders.
|
|
35
|
+
*/
|
|
36
|
+
export declare function secretEntryNeedsPlaceholderKey(entry: SecretEntry): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Whether a SET of entries needs the persisted placeholder key. `obfuscate()`
|
|
39
|
+
* applies plain replace-mode mappings before the plain-obfuscate pass, so a plain
|
|
40
|
+
* obfuscate entry only emits a reversible (keyed) placeholder when its content can
|
|
41
|
+
* still appear AFTER the replace phase. When no obfuscate entry can ever produce a
|
|
42
|
+
* placeholder, the persisted key must NOT be required/created — otherwise an
|
|
43
|
+
* effectively replace-only secret set still writes `secret-placeholder.key` and
|
|
44
|
+
* fails startup when the agent config dir is unwritable.
|
|
45
|
+
*
|
|
46
|
+
* The decision models the replace phase as the obfuscator actually runs it:
|
|
47
|
+
* replace mappings are content-keyed (later duplicate wins) and applied in
|
|
48
|
+
* descending content-length order; for a fresh probe (no prior placeholders) that
|
|
49
|
+
* phase is plain sequential substring replacement. A plain obfuscate entry needs
|
|
50
|
+
* the key when its content survives that simulated phase (direct typing) OR when
|
|
51
|
+
* any effective replacement can form the content via tiling — a substring,
|
|
52
|
+
* wholesale superstring, or prefix/suffix border that joins with surrounding
|
|
53
|
+
* passthrough bytes (see `replacementCanFormContent`). This covers direct
|
|
54
|
+
* shadowing (`SECRET -> safe`), reintroduction, duplicate ordering, transitive
|
|
55
|
+
* chains, and context-joined fragments uniformly. Default (omitted) replacements
|
|
56
|
+
* are deterministic, length-preserving, and distinct, so a same-content shadow
|
|
57
|
+
* with no other interacting replacement stays key-free.
|
|
58
|
+
* Replacement outputs are themselves rewritten by every later (shorter-content)
|
|
59
|
+
* replacement before the plain-obfuscate pass sees them, so a fragment that a
|
|
60
|
+
* subsequent replacement erases (`AA -> SEC` then `S -> X` turns every `SEC` into
|
|
61
|
+
* `XEC`) no longer forces the key. Surrounding bytes stay modeled as arbitrary
|
|
62
|
+
* passthrough, so testing the surviving fragment only drops false positives and
|
|
63
|
+
* never under-approximates a real key need.
|
|
64
|
+
*/
|
|
65
|
+
export declare function secretEntriesNeedPlaceholderKey(entries: SecretEntry[]): boolean;
|
|
66
|
+
export declare function buildHashBase(key: string, value: string): string;
|
|
67
|
+
export declare function buildKeyedReplacementRun(key: string, length: number): string;
|
|
68
|
+
export declare function inferCaseHint(secret: string): PlaceholderCaseHint | undefined;
|
|
69
|
+
export declare function buildPlaceholder(hint: PlaceholderCaseHint | undefined, base: string, friendlyName?: string): string;
|
|
70
|
+
/** Regex matching `$$HASH$$`, `$$HASH:U$$`, and `$$FRIENDLY_HASH(:hint)$$` placeholders. */
|
|
71
|
+
export declare const PLACEHOLDER_RE: RegExp;
|
|
72
|
+
export declare function resumePlaceholderScanAfterRejectedCandidate(match: RegExpExecArray): void;
|
|
73
|
+
export declare function placeholderWithoutFriendlyName(placeholder: string): string | undefined;
|
|
74
|
+
export declare function lookupFriendlyPlaceholderAlias(deobfuscateMap: ReadonlyMap<string, {
|
|
75
|
+
secret: string;
|
|
76
|
+
recursive: boolean;
|
|
77
|
+
}>, placeholder: string): {
|
|
78
|
+
secret: string;
|
|
79
|
+
recursive: boolean;
|
|
80
|
+
} | undefined;
|
|
81
|
+
export declare function stripPendingSecretPlaceholderSuffix(text: string): string;
|
|
82
|
+
export interface RegexScanSegment {
|
|
83
|
+
scanStart: number;
|
|
84
|
+
scanEnd: number;
|
|
85
|
+
textStart: number;
|
|
86
|
+
textEnd: number;
|
|
87
|
+
generatedPlaceholder: boolean;
|
|
88
|
+
recursive: boolean;
|
|
89
|
+
}
|
|
90
|
+
export interface ReplaceRegexScan {
|
|
91
|
+
text: string;
|
|
92
|
+
segments: RegexScanSegment[];
|
|
93
|
+
}
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export declare const REPLACEMENT_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
2
|
+
/** Generate a deterministic same-length replacement string from a secret value. */
|
|
3
|
+
export declare function generateDeterministicReplacement(secret: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Force a length-preserving deterministic replacement to differ from the secret
|
|
6
|
+
* it stands in for. `generateDeterministicReplacement` seeds its first 1–2 chars
|
|
7
|
+
* with the `Z`/`ZZ` sentinel, so a whole configured value that is exactly `Z` or
|
|
8
|
+
* `ZZ` (or an astronomically unlikely longer hash collision) would otherwise be
|
|
9
|
+
* emitted unchanged and ship the raw secret to the provider. Flip the first char
|
|
10
|
+
* to a fixed different glyph: same length, still deterministic, guaranteed != the
|
|
11
|
+
* secret. Only safe for a whole CONFIGURED value (a plain secret matches its own
|
|
12
|
+
* literal, so the perturbed output is no longer matched and stays a fixed point);
|
|
13
|
+
* per-chunk remainders must keep the sentinel to remain idempotent across restart.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ensureDistinctReplacement(replacement: string, secret: string): string;
|
|
16
|
+
export interface RegexMatchContext {
|
|
17
|
+
/** Full text the match was found in (positions are offsets into it). */
|
|
18
|
+
text: string;
|
|
19
|
+
/** Start/end of the matched span being replaced. */
|
|
20
|
+
start: number;
|
|
21
|
+
end: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Whether `candidate`, substituted for the matched span in its surrounding text,
|
|
25
|
+
* is re-matched by `regex` at its own position. A replace-mode regex that depends
|
|
26
|
+
* on context (lookbehind/lookahead/`\b`) can match a candidate that does NOT match
|
|
27
|
+
* in isolation: e.g. `(?<=api=)[AZ]` never matches a bare `A`, but `api=A` does, so
|
|
28
|
+
* a candidate `A` chosen by an isolation test is re-redacted on the next obfuscate()
|
|
29
|
+
* pass and can oscillate back to the raw matched value. The probe substitutes the
|
|
30
|
+
* candidate into the FULL text — not a truncated window — so a wide lookbehind or
|
|
31
|
+
* lookahead (e.g. `(?<=A{600})`) still evaluates against the context that makes it
|
|
32
|
+
* match. Truncating that context dropped the assertion's reach and falsely
|
|
33
|
+
* accepted an oscillating, leaky candidate. The scan starts a bounded distance
|
|
34
|
+
* left of the span and stops once a match begins at/after the span's end (matches
|
|
35
|
+
* arrive in order), keeping per-candidate cost independent of total text length.
|
|
36
|
+
*/
|
|
37
|
+
export declare function regexRematchesInContext(candidate: string, regex: RegExp, ctx: RegexMatchContext): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Search same-length replacements for one the regex does NOT match, so a default
|
|
40
|
+
* regex secret whose deterministic replacement collides with its own value (the
|
|
41
|
+
* `Z`/`ZZ` sentinel, or an astronomical hash collision) is still redacted to a
|
|
42
|
+
* STABLE nonmatching value instead of shipping the raw secret. A nonmatching
|
|
43
|
+
* candidate is a fixed point under re-obfuscation — the regex never re-matches it,
|
|
44
|
+
* so it cannot re-leak on a later pass. The search stays bounded to O(length *
|
|
45
|
+
* alphabet) regardless of value length: first exhaust every single-position
|
|
46
|
+
* substitution against a deterministic baseline (`AAAA…`, then `!AAA…`, `A!AA…`,
|
|
47
|
+
* …) so any regex that only needs one out-of-class byte — regardless of position —
|
|
48
|
+
* is found in a handful of probes rather than enumerating every combination (which
|
|
49
|
+
* for a 3-byte match-everything config, e.g. `[\s\S]{3}`, would otherwise run
|
|
50
|
+
* 90**3 = 729000 candidates through the regex on every single match, stalling
|
|
51
|
+
* provider requests). Candidates are enumerated deterministically over a stable
|
|
52
|
+
* ASCII alphabet: alphanumerics first (usually enough), then punctuation fallback
|
|
53
|
+
* bytes when the regex covers every alphanumeric candidate. When the regex still
|
|
54
|
+
* matches around a lone perturbed byte (for example `[A-Za-z0-9].*` matching the
|
|
55
|
+
* unperturbed tail), full-width same-byte candidates (`!!!!!`, `_____`, …) are
|
|
56
|
+
* tried next. When the regex covers every non-whitespace candidate (e.g. `\S{n}`),
|
|
57
|
+
* whitespace markers (a full space/tab run, then a single whitespace byte among
|
|
58
|
+
* non-whitespace filler) are tried as a last resort. A genuine match-everything
|
|
59
|
+
* regex (`.`/`[\s\S]`, which also matches space and tab) still exhausts this bounded
|
|
60
|
+
* sweep and returns undefined, letting the caller keep its own fixed-point fallback
|
|
61
|
+
* — bounded search can in principle miss an escape that depends jointly on
|
|
62
|
+
* multiple positions in a way no single-position swap reaches, but no realistic
|
|
63
|
+
* secret-redaction regex (character classes, literal matches, anchored/bounded
|
|
64
|
+
* repeats) has that shape.
|
|
65
|
+
*/
|
|
66
|
+
export declare function findNonMatchingReplacement(value: string, regex: RegExp, context: RegexMatchContext): string | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Whether a default (no custom `replacement`) replace-mode regex can never
|
|
69
|
+
* safely redact a 1-2 char match: `findNonMatchingReplacement`'s bounded
|
|
70
|
+
* search — the same search `#generateRegexReplacement` runs at match time —
|
|
71
|
+
* finds no candidate the regex fails to re-match. This holds independent of
|
|
72
|
+
* any actual per-install key: the search already exhausts every character in
|
|
73
|
+
* `REPLACEMENT_CHARS` (the alphabet `buildKeyedReplacementRun` draws its
|
|
74
|
+
* fallback marker from) plus punctuation and whitespace, so if none of those
|
|
75
|
+
* escape the regex, no key-derived marker drawn from the same alphabet can
|
|
76
|
+
* either — the marker is guaranteed to re-match too, making every such match
|
|
77
|
+
* unresolvable: the fallback could only ever emit the raw matched text
|
|
78
|
+
* unchanged. Probed with a value (`"\0".repeat(length)`) the bounded search
|
|
79
|
+
* never treats as a real candidate, so the result depends only on the
|
|
80
|
+
* regex's own matching behavior, not on this specific probe.
|
|
81
|
+
*/
|
|
82
|
+
export declare function regexHasUnresolvableShortMatchFallback(regex: RegExp): boolean;
|
|
@@ -2,7 +2,7 @@ import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
3
3
|
import type { Effort } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { Rule } from "../capability/rule.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { RetryErrorUpdate } from "../extensibility/shared-events.js";
|
|
6
6
|
import type { Goal, GoalModeState } from "../goals/state.js";
|
|
7
7
|
import type { ConfiguredThinkingLevel } from "../thinking.js";
|
|
8
8
|
import type { TodoItem } from "../tools/todo.js";
|
|
@@ -40,7 +40,7 @@ export type AgentSessionEvent = Exclude<AgentEvent, {
|
|
|
40
40
|
success: boolean;
|
|
41
41
|
attempt: number;
|
|
42
42
|
finalError?: string;
|
|
43
|
-
|
|
43
|
+
retryErrors?: RetryErrorUpdate[];
|
|
44
44
|
} | {
|
|
45
45
|
type: "retry_fallback_applied";
|
|
46
46
|
from: string;
|
|
@@ -24,6 +24,12 @@ export declare const SHUTDOWN_CONSOLIDATE_BUDGET_MS = 1500;
|
|
|
24
24
|
/** Options controlling session disposal. */
|
|
25
25
|
export interface AgentSessionDisposeOptions {
|
|
26
26
|
mnemopiConsolidateTimeoutMs?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Deadline for the settle/drain wait before the terminal memory release
|
|
29
|
+
* (default 5s). The bounded-teardown paths (signal handlers, tests) may
|
|
30
|
+
* shorten it; late event handlers are still finalized after they settle.
|
|
31
|
+
*/
|
|
32
|
+
drainTimeoutMs?: number;
|
|
27
33
|
/**
|
|
28
34
|
* Postmortem reason that triggered this dispose (signal/fatal teardown
|
|
29
35
|
* paths). When set, the persisted `session_exit` diagnostic records it
|
|
@@ -41,7 +41,7 @@ import type { DaemonCompletionNotification } from "../launch/protocol.js";
|
|
|
41
41
|
import { type MnemopiSessionState } from "../mnemopi/state.js";
|
|
42
42
|
import { type PlanApprovalDetails } from "../plan-mode/approved-plan.js";
|
|
43
43
|
import type { PlanModeState } from "../plan-mode/state.js";
|
|
44
|
-
import {
|
|
44
|
+
import type { SecretObfuscator } from "../secrets/obfuscator.js";
|
|
45
45
|
import { type ConfiguredThinkingLevel } from "../thinking.js";
|
|
46
46
|
import { type AskToolDetails, type AskToolInput } from "../tools/ask.js";
|
|
47
47
|
import type { CheckpointState, CompletedRewindState } from "../tools/checkpoint.js";
|
|
@@ -83,7 +83,7 @@ export declare class AgentSession {
|
|
|
83
83
|
/**
|
|
84
84
|
* Arm prewalk outside the normal startup path so an explicit slash command starts immediately.
|
|
85
85
|
*/
|
|
86
|
-
armPrewalk(target: Model, thinkingLevel?: ConfiguredThinkingLevel):
|
|
86
|
+
armPrewalk(target: Model, thinkingLevel?: ConfiguredThinkingLevel): boolean;
|
|
87
87
|
/** Validate the active plan artifact and shape an `xd://propose` result for review-mode hosts. */
|
|
88
88
|
preparePlanForReview(title: string): Promise<AgentToolResult<PlanApprovalDetails>>;
|
|
89
89
|
constructor(config: AgentSessionConfig);
|
|
@@ -12,6 +12,7 @@ import type { OutputMeta } from "../tools/output-meta.js";
|
|
|
12
12
|
export declare const SKILL_PROMPT_MESSAGE_TYPE = "skill-prompt";
|
|
13
13
|
export declare const LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE = "lsp-late-diagnostic";
|
|
14
14
|
export declare const BACKGROUND_TAN_DISPATCH_MESSAGE_TYPE = "background-tan-dispatch";
|
|
15
|
+
export declare const PREWALK_PLAN_MESSAGE_TYPE = "prewalk-plan";
|
|
15
16
|
/**
|
|
16
17
|
* Logs provider-error turns so their actual cause is available outside the
|
|
17
18
|
* session transcript. No-op for non-error stop reasons.
|
|
@@ -6,6 +6,8 @@ import { type ConfiguredThinkingLevel } from "../thinking.js";
|
|
|
6
6
|
import type { PlanProposalHandler } from "../tools/resolve.js";
|
|
7
7
|
import type { PlanYolo, Prewalk } from "./agent-session-types.js";
|
|
8
8
|
import type { SessionManager } from "./session-manager.js";
|
|
9
|
+
/** Hidden plan steering is consumed within the live run and must not reappear after a context rebuild. */
|
|
10
|
+
export declare function isPrewalkPlanNudge(message: AgentMessage): boolean;
|
|
9
11
|
/** Capabilities the prewalk coordinator borrows from its owning session. */
|
|
10
12
|
export interface PrewalkCoordinatorHost {
|
|
11
13
|
agent: Agent;
|
|
@@ -41,7 +43,7 @@ export declare class PrewalkCoordinator {
|
|
|
41
43
|
/** Advances the one-way prewalk switch at a completed assistant-turn boundary. */
|
|
42
44
|
advanceAtTurnEnd(liveMessages: AgentMessage[], context: AgentTurnEndContext | undefined): Promise<void>;
|
|
43
45
|
/** Arms a prewalk immediately for an explicit slash-command request. */
|
|
44
|
-
arm(target: Model, thinkingLevel?: ConfiguredThinkingLevel):
|
|
46
|
+
arm(target: Model, thinkingLevel?: ConfiguredThinkingLevel): boolean;
|
|
45
47
|
/** Lazily enables plan-yolo's plan phase before the first prompt is built. */
|
|
46
48
|
armPlanYoloIfNeeded(): Promise<void>;
|
|
47
49
|
}
|
|
@@ -4,7 +4,7 @@ import type { Message, Model, ServiceTier, SimpleStreamOptions } from "@oh-my-pi
|
|
|
4
4
|
import type { ModelRegistry } from "../config/model-registry.js";
|
|
5
5
|
import type { Settings } from "../config/settings.js";
|
|
6
6
|
import type { ExtensionRunner } from "../extensibility/extensions/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import type { SecretObfuscator } from "../secrets/obfuscator.js";
|
|
8
8
|
import type { HandoffResult, SessionHandoffOptions } from "./agent-session-types.js";
|
|
9
9
|
import type { BashSessionTransition } from "./bash-runner.js";
|
|
10
10
|
import type { SessionContext } from "./session-context.js";
|
|
@@ -55,9 +55,9 @@ export declare class SessionHandoff {
|
|
|
55
55
|
#private;
|
|
56
56
|
constructor(host: SessionHandoffHost);
|
|
57
57
|
/**
|
|
58
|
-
* Cancel in-progress handoff generation.
|
|
58
|
+
* Cancel in-progress handoff generation, preserving a harness-provided reason.
|
|
59
59
|
*/
|
|
60
|
-
abortHandoff(): void;
|
|
60
|
+
abortHandoff(reason?: Error): void;
|
|
61
61
|
/**
|
|
62
62
|
* Check if handoff generation is in progress.
|
|
63
63
|
*/
|
|
@@ -133,6 +133,38 @@ export declare class SessionManager {
|
|
|
133
133
|
flushSync(): void;
|
|
134
134
|
/** Flush, then close the append writer. */
|
|
135
135
|
close(): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Raise the terminal write barrier ahead of the final {@link close}. Once
|
|
138
|
+
* sealed:
|
|
139
|
+
* - every later append, title change, and rewrite is a dropped no-op —
|
|
140
|
+
* including work an event handler tries to enqueue while dispose is
|
|
141
|
+
* awaiting `close()` on the disk tail;
|
|
142
|
+
* - the disk epoch is bumped, so queued-but-unexecuted tail work is
|
|
143
|
+
* superseded and an ALREADY-RUNNING fenced/repair rewrite (awaiting the
|
|
144
|
+
* tail, drain, writer close, or the atomic stage) fails its commit guard
|
|
145
|
+
* at the rename fence instead of publishing over a revived file.
|
|
146
|
+
* The final `close()` itself is scheduled after the bump and still runs;
|
|
147
|
+
* pre-seal hot-path appends are already in the page cache. Idempotent;
|
|
148
|
+
* terminal.
|
|
149
|
+
*/
|
|
150
|
+
seal(): void;
|
|
151
|
+
/**
|
|
152
|
+
* Terminal release: drop the in-memory transcript and complete the
|
|
153
|
+
* {@link seal}. The entry journal and its index mirror the agent's message
|
|
154
|
+
* array (tool results, file contents, base64 frame images); on a disposed
|
|
155
|
+
* session — e.g. a parked subagent still referenced by the lifecycle
|
|
156
|
+
* adoption record — they would otherwise stay pinned for the process
|
|
157
|
+
* lifetime.
|
|
158
|
+
*
|
|
159
|
+
* Closes the append writer; with the seal up, nothing can reopen it. A
|
|
160
|
+
* revival may reopen the same JSONL through a NEW manager the moment
|
|
161
|
+
* dispose returns; a late event handler resuming on THIS manager must
|
|
162
|
+
* never race that writer — and a post-release rewrite would persist the
|
|
163
|
+
* now-empty entry list, truncating the transcript. Reads after this point
|
|
164
|
+
* reopen from disk (revival, `history://`). Only call from session
|
|
165
|
+
* dispose, after the final `close()`; idempotent.
|
|
166
|
+
*/
|
|
167
|
+
releaseRetainedEntries(): void;
|
|
136
168
|
getCwd(): string;
|
|
137
169
|
/** Additional workspace directories beyond cwd (multi-root), absolute and normalized. */
|
|
138
170
|
getAdditionalDirectories(): string[];
|
|
@@ -5,7 +5,7 @@ import type { ImageContent, Message, Model, SimpleStreamOptions } from "@oh-my-p
|
|
|
5
5
|
import type { ModelRegistry } from "../config/model-registry.js";
|
|
6
6
|
import type { Settings } from "../config/settings.js";
|
|
7
7
|
import type { LocalProtocolOptions } from "../internal-urls/index.js";
|
|
8
|
-
import {
|
|
8
|
+
import type { SecretObfuscator } from "../secrets/obfuscator.js";
|
|
9
9
|
import { type CustomMessage } from "./messages.js";
|
|
10
10
|
import type { BuildSessionContextOptions, SessionContext } from "./session-context.js";
|
|
11
11
|
import type { SessionManager } from "./session-manager.js";
|
|
@@ -108,6 +108,14 @@ export declare class SessionTools {
|
|
|
108
108
|
get baseSystemPrompt(): string[];
|
|
109
109
|
/** Replaces the controller-owned base prompt without applying it to the agent. */
|
|
110
110
|
setBaseSystemPrompt(prompt: string[]): void;
|
|
111
|
+
/**
|
|
112
|
+
* Registers the per-turn `before_agent_start` system-prompt override and
|
|
113
|
+
* applies it to the agent. Base rebuilds during the turn preserve it until
|
|
114
|
+
* {@link clearTurnSystemPromptOverride}.
|
|
115
|
+
*/
|
|
116
|
+
setTurnSystemPromptOverride(prompt: string[]): void;
|
|
117
|
+
/** Drops the active per-turn override; later rebuilds fall back to the base prompt. */
|
|
118
|
+
clearTurnSystemPromptOverride(): void;
|
|
111
119
|
/** Skills currently rendered into the system prompt. */
|
|
112
120
|
get skills(): Skill[];
|
|
113
121
|
/** Diagnostics produced while loading the current skills. */
|
|
@@ -100,8 +100,13 @@ export declare class TurnRecovery {
|
|
|
100
100
|
autoContinue: boolean;
|
|
101
101
|
triggerContextTokens?: number;
|
|
102
102
|
}): Promise<RecoveryCompactionResult>;
|
|
103
|
-
/**
|
|
104
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Restores the configured primary after fallback cooldown expiry.
|
|
105
|
+
* @returns true when the active model was actually switched back to the
|
|
106
|
+
* primary, so callers can re-run the pre-send context-fit check against the
|
|
107
|
+
* reverted (possibly smaller) window before issuing the next request.
|
|
108
|
+
*/
|
|
109
|
+
maybeRestoreRetryFallbackPrimary(): Promise<boolean>;
|
|
105
110
|
/** Applies model fallback policy from live usage health before a turn starts. */
|
|
106
111
|
maybeApplyUsageAwareFallback(signal: AbortSignal, confirmer?: UsageFallbackConfirmer): Promise<boolean>;
|
|
107
112
|
/** Applies automatic retry, credential rotation, and model fallback policy. */
|
|
@@ -151,9 +156,9 @@ export declare class TurnRecovery {
|
|
|
151
156
|
*/
|
|
152
157
|
isRetryableReasonlessAbort(message: AssistantMessage): boolean;
|
|
153
158
|
/**
|
|
154
|
-
* Check if an error is retryable (transient errors
|
|
159
|
+
* Check if an error is retryable (transient errors, usage limits, or
|
|
160
|
+
* account-scoped policy denials that can rotate credentials).
|
|
155
161
|
* Context overflow is NOT retryable (handled by compaction instead).
|
|
156
|
-
* Usage-limit errors are retryable because the retry handler performs credential switching.
|
|
157
162
|
*/
|
|
158
163
|
isRetryableError(message: AssistantMessage): boolean;
|
|
159
164
|
/**
|