@bubblebrain-ai/bubble 0.0.46 → 0.0.47

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.
Files changed (92) hide show
  1. package/dist/agent/child-runner.js +11 -0
  2. package/dist/agent/internal-reminder-sanitizer.d.ts +7 -0
  3. package/dist/agent/internal-reminder-sanitizer.js +13 -0
  4. package/dist/agent/subagent/router.d.ts +65 -0
  5. package/dist/agent/subagent/router.js +198 -0
  6. package/dist/agent/subagent/runtime.d.ts +203 -0
  7. package/dist/agent/subagent/runtime.js +789 -0
  8. package/dist/agent/subagent-control.d.ts +5 -0
  9. package/dist/agent/subagent-store.d.ts +18 -2
  10. package/dist/agent/subagent-store.js +32 -1
  11. package/dist/agent/tool-intent.d.ts +10 -0
  12. package/dist/agent/tool-intent.js +18 -0
  13. package/dist/agent/tool-visibility.d.ts +10 -0
  14. package/dist/agent/tool-visibility.js +6 -0
  15. package/dist/agent/workflow/runs.d.ts +72 -0
  16. package/dist/agent/workflow/runs.js +157 -0
  17. package/dist/agent.d.ts +78 -96
  18. package/dist/agent.js +266 -1072
  19. package/dist/context/compact-llm.js +14 -5
  20. package/dist/context/compact.d.ts +9 -0
  21. package/dist/context/compact.js +36 -10
  22. package/dist/context/compaction-files.d.ts +44 -0
  23. package/dist/context/compaction-files.js +148 -0
  24. package/dist/context/llm-compactor.js +24 -5
  25. package/dist/feishu/agent-host/run-driver.js +3 -0
  26. package/dist/feishu/serve.js +13 -9
  27. package/dist/goal/tools.js +12 -3
  28. package/dist/main.js +24 -19
  29. package/dist/model-catalog.js +36 -2
  30. package/dist/model-config.d.ts +2 -0
  31. package/dist/model-data.generated.d.ts +16 -0
  32. package/dist/model-data.generated.js +275 -0
  33. package/dist/model-pricing.d.ts +11 -7
  34. package/dist/model-pricing.js +0 -0
  35. package/dist/oauth/grok.d.ts +1 -1
  36. package/dist/oauth/grok.js +5 -2
  37. package/dist/oauth/storage.d.ts +9 -2
  38. package/dist/oauth/storage.js +16 -9
  39. package/dist/orchestrator/default-hooks.d.ts +20 -0
  40. package/dist/orchestrator/default-hooks.js +47 -295
  41. package/dist/orchestrator/hooks.d.ts +6 -39
  42. package/dist/permission/mode.js +1 -1
  43. package/dist/prompt/reminders.d.ts +9 -35
  44. package/dist/prompt/reminders.js +30 -136
  45. package/dist/prompt/task-reminders.d.ts +0 -31
  46. package/dist/prompt/task-reminders.js +0 -87
  47. package/dist/provider-ai-sdk.d.ts +2 -0
  48. package/dist/provider-ai-sdk.js +1 -0
  49. package/dist/provider-anthropic.d.ts +2 -0
  50. package/dist/provider-anthropic.js +3 -1
  51. package/dist/provider-ark-responses.d.ts +2 -0
  52. package/dist/provider-ark-responses.js +1 -0
  53. package/dist/provider-registry.d.ts +13 -0
  54. package/dist/provider-registry.js +83 -0
  55. package/dist/provider-transform.js +37 -1
  56. package/dist/provider.d.ts +7 -0
  57. package/dist/provider.js +13 -1
  58. package/dist/sdk/index.d.ts +152 -0
  59. package/dist/sdk/index.js +400 -0
  60. package/dist/session.js +9 -1
  61. package/dist/slash-commands/commands.js +33 -19
  62. package/dist/tools/exit-plan-mode.js +8 -0
  63. package/dist/tui/detect-theme.d.ts +1 -0
  64. package/dist/tui/detect-theme.js +11 -5
  65. package/dist/tui-ink/app.d.ts +2 -6
  66. package/dist/tui-ink/app.js +11 -18
  67. package/dist/tui-ink/display-history.d.ts +0 -2
  68. package/dist/tui-ink/display-history.js +0 -52
  69. package/dist/tui-ink/footer.js +2 -2
  70. package/dist/tui-ink/message-list.js +62 -23
  71. package/dist/tui-ink/run.js +10 -5
  72. package/dist/tui-ink/sync-output.d.ts +17 -0
  73. package/dist/tui-ink/sync-output.js +35 -0
  74. package/dist/tui-ink/theme.d.ts +0 -1
  75. package/dist/tui-ink/theme.js +0 -2
  76. package/dist/tui-ink/trace-groups.js +1 -1
  77. package/dist/types.d.ts +21 -1
  78. package/package.json +16 -2
  79. package/dist/agent/discovery-barrier.d.ts +0 -21
  80. package/dist/agent/discovery-barrier.js +0 -173
  81. package/dist/agent/evidence-tracker.d.ts +0 -15
  82. package/dist/agent/evidence-tracker.js +0 -93
  83. package/dist/agent/execution-governor.d.ts +0 -36
  84. package/dist/agent/execution-governor.js +0 -218
  85. package/dist/agent/task-classifier.d.ts +0 -3
  86. package/dist/agent/task-classifier.js +0 -114
  87. package/dist/agent/task-size.d.ts +0 -9
  88. package/dist/agent/task-size.js +0 -33
  89. package/dist/agent/tool-arbiter.d.ts +0 -7
  90. package/dist/agent/tool-arbiter.js +0 -33
  91. package/dist/orchestrator/workflow.d.ts +0 -10
  92. package/dist/orchestrator/workflow.js +0 -22
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Synchronized-output wrapper (CSI ?2026, "sync updates").
3
+ *
4
+ * Every frame Ink writes gets bracketed in begin/end synchronized-output so
5
+ * the terminal composites it atomically instead of painting mid-erase state —
6
+ * the primary source of visible flicker during streaming. This is exactly
7
+ * what pi's main-screen renderer does per paint batch; alt-screen is NOT
8
+ * required for it.
9
+ *
10
+ * Terminals that don't implement mode 2026 ignore unknown DEC private modes,
11
+ * so emitting unconditionally is safe; BUBBLE_NO_SYNC_OUTPUT=1 is the escape
12
+ * hatch for anything that misbehaves. Only string chunks are bracketed —
13
+ * Ink writes frames as strings; binary writes pass through untouched.
14
+ */
15
+ export const BEGIN_SYNC = "\x1b[?2026h";
16
+ export const END_SYNC = "\x1b[?2026l";
17
+ export function wrapSynchronizedOutput(stream) {
18
+ if (!stream.isTTY || process.env.BUBBLE_NO_SYNC_OUTPUT === "1")
19
+ return stream;
20
+ return new Proxy(stream, {
21
+ get(target, prop) {
22
+ if (prop === "write") {
23
+ return (chunk, ...rest) => typeof chunk === "string" && chunk.length > 0
24
+ ? target.write(BEGIN_SYNC + chunk + END_SYNC, ...rest)
25
+ : target.write(chunk, ...rest);
26
+ }
27
+ const value = Reflect.get(target, prop, target);
28
+ return typeof value === "function" ? value.bind(target) : value;
29
+ },
30
+ set(target, prop, value) {
31
+ Reflect.set(target, prop, value);
32
+ return true;
33
+ },
34
+ });
35
+ }
@@ -56,7 +56,6 @@ export interface Theme {
56
56
  userMessageBorder: string;
57
57
  userMessageBg: string;
58
58
  userMessageText: string;
59
- userRail: string;
60
59
  /** Painted band backgrounds for diff lines inside user-message cards. */
61
60
  diffAdd: string;
62
61
  diffRemove: string;
@@ -46,7 +46,6 @@ export const darkTheme = {
46
46
  userMessageBorder: "#8A7FC6",
47
47
  userMessageBg: "#2a2a34",
48
48
  userMessageText: "#f3f3f7",
49
- userRail: "#8A7FC6",
50
49
  diffAdd: "#1a3d1a",
51
50
  diffRemove: "#3d1a1a",
52
51
  diffAddFg: "green",
@@ -95,7 +94,6 @@ export const lightTheme = {
95
94
  userMessageBorder: "#356FD2",
96
95
  userMessageBg: "#F1F3F0",
97
96
  userMessageText: "#234B93",
98
- userRail: "#356FD2",
99
97
  diffAdd: "#D7E8D8",
100
98
  diffRemove: "#F7DADC",
101
99
  diffAddFg: "#2F7D4A",
@@ -387,7 +387,7 @@ function isFailedSubagent(subagent) {
387
387
  return subagent.status === "failed" || subagent.status === "blocked" || subagent.status === "cancelled";
388
388
  }
389
389
  function isToolPending(tool) {
390
- return tool.result === undefined && tool.resultCollapsed !== true;
390
+ return tool.result === undefined;
391
391
  }
392
392
  function isDirectoryLikeGlob(pattern) {
393
393
  const normalized = pattern.trim();
package/dist/types.d.ts CHANGED
@@ -130,7 +130,6 @@ export interface ToolResultMetadata {
130
130
  searchSignature?: string;
131
131
  searchFamily?: string;
132
132
  reason?: string;
133
- arbiterNote?: string;
134
133
  diff?: string;
135
134
  addedLines?: number;
136
135
  removedLines?: number;
@@ -235,6 +234,15 @@ export interface ToolRegistryEntry extends ToolDefinition {
235
234
  * fan-out never share it (design v2 §2). Tools without it are shared as-is.
236
235
  */
237
236
  cloneForChild?: () => ToolRegistryEntry;
237
+ /**
238
+ * Optional availability predicate, evaluated on EVERY model call. When it
239
+ * returns false the tool is omitted from the provider's function list
240
+ * entirely — the model cannot see or call it — and reappears on the next
241
+ * call once the predicate flips. For state-gated tools (e.g. update_goal
242
+ * without an active goal) this removes the affordance itself instead of
243
+ * relying on description wording, which strong models ignore.
244
+ */
245
+ enabled?: () => boolean;
238
246
  /** Optional one-line summary for the Available tools section. */
239
247
  promptSnippet?: string;
240
248
  /** Optional tool-specific rules appended to the system prompt when this tool is active. */
@@ -314,6 +322,17 @@ export interface TokenUsage {
314
322
  reasoningTokens?: number;
315
323
  totalTokens?: number;
316
324
  }
325
+ /**
326
+ * Priced token usage (see model-pricing.ts). Lives here rather than in
327
+ * model-pricing.ts because turn_end events carry it and model-pricing
328
+ * already imports from this module.
329
+ */
330
+ export interface UsageCost {
331
+ currency: "USD" | "CNY";
332
+ cost: number;
333
+ /** True when the provider gave no cache breakdown and everything was billed at the miss rate. */
334
+ estimated: boolean;
335
+ }
317
336
  export interface Provider {
318
337
  streamChat(messages: ProviderMessage[], options: {
319
338
  model: string;
@@ -410,6 +429,7 @@ export type AgentEvent = {
410
429
  } | {
411
430
  type: "turn_end";
412
431
  usage?: TokenUsage;
432
+ cost?: UsageCost;
413
433
  willContinue?: boolean;
414
434
  } | {
415
435
  type: "context_recovered";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bubblebrain-ai/bubble",
3
- "version": "0.0.46",
3
+ "version": "0.0.47",
4
4
  "description": "A terminal coding agent",
5
5
  "type": "module",
6
6
  "engines": {
@@ -9,6 +9,18 @@
9
9
  "bin": {
10
10
  "bubble": "dist/bin.js"
11
11
  },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/sdk/index.d.ts",
15
+ "default": "./dist/sdk/index.js"
16
+ },
17
+ "./sdk": {
18
+ "types": "./dist/sdk/index.d.ts",
19
+ "default": "./dist/sdk/index.js"
20
+ },
21
+ "./dist/*": "./dist/*",
22
+ "./package.json": "./package.json"
23
+ },
12
24
  "files": [
13
25
  "dist",
14
26
  "!dist/**/__tests__/**",
@@ -18,6 +30,8 @@
18
30
  "scripts": {
19
31
  "build": "rm -rf dist && tsc && chmod +x dist/bin.js dist/main.js",
20
32
  "dev": "tsc && bun dist/main.js",
33
+ "refresh-models": "NODE_USE_ENV_PROXY=1 node scripts/generate-model-data.mjs",
34
+ "eval": "bun evals/run.ts",
21
35
  "prepack": "npm run build",
22
36
  "start": "bun dist/main.js",
23
37
  "test": "vitest run",
@@ -31,7 +45,7 @@
31
45
  "@types/better-sqlite3": "^7.6.13",
32
46
  "@types/react": "^19.2.14",
33
47
  "@vue/language-server": "^3.2.7",
34
- "better-sqlite3": "^12.9.0",
48
+ "better-sqlite3": "^13.0.1",
35
49
  "chalk": "^5.3.0",
36
50
  "diff": "^9.0.0",
37
51
  "ink": "^7.0.3",
@@ -1,21 +0,0 @@
1
- import type { ContentPart, ParsedToolCall, ToolResult, ToolResultMetadata } from "../types.js";
2
- export interface DiscoveryBarrierOptions {
3
- cwd: string;
4
- input: string | ContentPart[];
5
- enabled: boolean;
6
- }
7
- export declare class DiscoveryBarrier {
8
- private readonly cwd;
9
- private readonly enabled;
10
- private readonly knownPaths;
11
- private readonly userMentionedPaths;
12
- constructor(options: DiscoveryBarrierOptions);
13
- isEnabled(): boolean;
14
- shouldBufferStreamingToolCall(name: string): boolean;
15
- orderToolCalls<T extends ParsedToolCall>(toolCalls: T[]): T[];
16
- beforeToolCall(toolCall: ParsedToolCall): ToolResult | undefined;
17
- afterToolCall(toolCall: ParsedToolCall, result: ToolResult): void;
18
- observeMetadata(metadata: ToolResultMetadata | undefined): void;
19
- }
20
- export declare function isHiddenToolResult(result: ToolResult | undefined): result is ToolResult;
21
- export declare function isHiddenToolMetadata(metadata: ToolResultMetadata | undefined): boolean;
@@ -1,173 +0,0 @@
1
- import { existsSync, realpathSync } from "node:fs";
2
- import { basename, resolve } from "node:path";
3
- import { analyzeToolIntent } from "./tool-intent.js";
4
- import { resolveToolPath } from "../tools/path-utils.js";
5
- export class DiscoveryBarrier {
6
- cwd;
7
- enabled;
8
- knownPaths = new Set();
9
- userMentionedPaths = new Set();
10
- constructor(options) {
11
- this.cwd = options.cwd;
12
- this.enabled = options.enabled;
13
- for (const path of extractUserMentionedPaths(options.input)) {
14
- this.userMentionedPaths.add(canonicalPath(this.cwd, path));
15
- }
16
- }
17
- isEnabled() {
18
- return this.enabled;
19
- }
20
- shouldBufferStreamingToolCall(name) {
21
- return this.enabled && (name === "read" || name === "bash" || name === "lsp");
22
- }
23
- orderToolCalls(toolCalls) {
24
- if (!this.enabled || toolCalls.length < 2)
25
- return toolCalls;
26
- const discovery = [];
27
- const rest = [];
28
- for (const toolCall of toolCalls) {
29
- if (isDiscoveryToolCall(toolCall))
30
- discovery.push(toolCall);
31
- else
32
- rest.push(toolCall);
33
- }
34
- if (discovery.length === 0 || rest.length === 0)
35
- return toolCalls;
36
- return [...discovery, ...rest];
37
- }
38
- beforeToolCall(toolCall) {
39
- if (!this.enabled)
40
- return undefined;
41
- const target = pathSensitiveReadTarget(toolCall);
42
- if (!target)
43
- return undefined;
44
- const canonical = canonicalPath(this.cwd, target.path);
45
- if (this.knownPaths.has(canonical) || this.userMentionedPaths.has(canonical))
46
- return undefined;
47
- return {
48
- content: `Blocked speculative ${target.kind}. The path "${target.path}" has not been discovered in this repository context ` +
49
- "and was not explicitly requested by the user. Run glob/grep discovery first, then read only returned paths. " +
50
- "Do not infer from this blocked call whether the path exists.",
51
- isError: true,
52
- status: "blocked",
53
- metadata: {
54
- kind: "internal",
55
- reason: "speculative_read_blocked",
56
- hiddenFromTranscript: true,
57
- path: canonical,
58
- requestedPath: target.path,
59
- toolName: toolCall.name,
60
- },
61
- };
62
- }
63
- afterToolCall(toolCall, result) {
64
- if (!this.enabled || result.metadata?.hiddenFromTranscript === true)
65
- return;
66
- this.observeMetadata(result.metadata);
67
- if (isSuccessfulAccessResult(result)) {
68
- const target = pathSensitiveReadTarget(toolCall);
69
- if (target)
70
- this.knownPaths.add(canonicalPath(this.cwd, target.path));
71
- }
72
- }
73
- observeMetadata(metadata) {
74
- if (!metadata)
75
- return;
76
- for (const path of metadataPaths(metadata)) {
77
- this.knownPaths.add(canonicalPath(this.cwd, path));
78
- }
79
- }
80
- }
81
- export function isHiddenToolResult(result) {
82
- return result?.metadata?.hiddenFromTranscript === true;
83
- }
84
- export function isHiddenToolMetadata(metadata) {
85
- return metadata?.hiddenFromTranscript === true;
86
- }
87
- function isDiscoveryToolCall(toolCall) {
88
- if (toolCall.name === "glob" || toolCall.name === "grep")
89
- return true;
90
- return analyzeToolIntent(toolCall).family === "search";
91
- }
92
- function pathSensitiveReadTarget(toolCall) {
93
- if (toolCall.name === "read") {
94
- const path = stringArg(toolCall.parsedArgs.path ?? toolCall.parsedArgs.file);
95
- return path ? { kind: "read", path } : undefined;
96
- }
97
- if (toolCall.name === "bash") {
98
- const intent = analyzeToolIntent(toolCall);
99
- const path = intent.read?.path;
100
- return path ? { kind: "bash read", path } : undefined;
101
- }
102
- if (toolCall.name === "lsp") {
103
- const path = stringArg(toolCall.parsedArgs.filePath);
104
- return path ? { kind: "lsp", path } : undefined;
105
- }
106
- return undefined;
107
- }
108
- function metadataPaths(metadata) {
109
- const paths = new Set();
110
- addPathValue(paths, metadata.path);
111
- addPathValue(paths, metadata.paths);
112
- return [...paths];
113
- }
114
- function addPathValue(out, value) {
115
- if (typeof value === "string" && value.trim()) {
116
- out.add(value);
117
- return;
118
- }
119
- if (!Array.isArray(value))
120
- return;
121
- for (const item of value) {
122
- if (typeof item === "string" && item.trim())
123
- out.add(item);
124
- }
125
- }
126
- function isSuccessfulAccessResult(result) {
127
- return !result.isError
128
- && result.status !== "blocked"
129
- && result.status !== "cancelled"
130
- && result.status !== "command_error"
131
- && result.status !== "timeout";
132
- }
133
- function canonicalPath(cwd, value) {
134
- const absolute = resolveToolPath(cwd, value);
135
- try {
136
- if (existsSync(absolute))
137
- return realpathSync.native(absolute);
138
- }
139
- catch {
140
- // Fall back to lexical resolution for unreadable or racing paths.
141
- }
142
- return resolve(absolute);
143
- }
144
- function extractUserMentionedPaths(input) {
145
- const text = typeof input === "string"
146
- ? input
147
- : input
148
- .filter((part) => part.type === "text")
149
- .map((part) => part.text)
150
- .join("\n");
151
- const paths = new Set();
152
- const regex = /(?:^|[\s`'"])(~?\.{0,2}\/[^\s`'"]+|[\w@.-]+\.[A-Za-z0-9][\w.-]*)(?=$|[\s`'",.;:!?,。;:!?))])/g;
153
- let match;
154
- while ((match = regex.exec(text)) !== null) {
155
- const value = match[1]?.trim();
156
- if (value && isLikelyFilePath(value))
157
- paths.add(stripTrailingPunctuation(value));
158
- }
159
- return [...paths];
160
- }
161
- function isLikelyFilePath(value) {
162
- const stripped = stripTrailingPunctuation(value);
163
- if (stripped.startsWith("./") || stripped.startsWith("../") || stripped.startsWith("~/") || stripped.startsWith("/")) {
164
- return true;
165
- }
166
- return /\.[A-Za-z0-9][\w.-]*$/.test(basename(stripped));
167
- }
168
- function stripTrailingPunctuation(value) {
169
- return value.replace(/[.,;:!?,。;:!?))]+$/u, "");
170
- }
171
- function stringArg(value) {
172
- return typeof value === "string" ? value.trim() : "";
173
- }
@@ -1,15 +0,0 @@
1
- import type { ParsedToolCall, ToolResult } from "../types.js";
2
- export interface InvestigationCoverage {
3
- configLoadPaths: boolean;
4
- envReads: boolean;
5
- persistencePaths: boolean;
6
- exposurePaths: boolean;
7
- maskingSignals: boolean;
8
- }
9
- export declare class EvidenceTracker {
10
- private coverage;
11
- observe(toolCall: Pick<ParsedToolCall, "name" | "parsedArgs">, result: ToolResult): void;
12
- snapshot(): InvestigationCoverage;
13
- key(): string;
14
- isCoreCoverageComplete(): boolean;
15
- }
@@ -1,93 +0,0 @@
1
- const DEFAULT_COVERAGE = {
2
- configLoadPaths: false,
3
- envReads: false,
4
- persistencePaths: false,
5
- exposurePaths: false,
6
- maskingSignals: false,
7
- };
8
- const CONFIG_PATTERNS = [
9
- /\bconfig\.(json|ya?ml|toml|ini)\b/i,
10
- /\bsettings\.(json|ya?ml|toml)\b/i,
11
- /\bauth\.json\b/i,
12
- /\buserconfig\b/i,
13
- /\breadfilesync\b/i,
14
- ];
15
- const ENV_PATTERNS = [
16
- /\bprocess\.env\b/i,
17
- /\bimport\.meta\.env\b/i,
18
- /\bgetenv\(/i,
19
- /\bloadenv\b/i,
20
- /\bdotenv\b/i,
21
- /\b\.env\b/i,
22
- ];
23
- const PERSISTENCE_PATTERNS = [
24
- /\bwritefilesync\b/i,
25
- /\bwritefile\b/i,
26
- /\bauth\.json\b/i,
27
- /\bconfig\.json\b/i,
28
- /\blocalstorage\b/i,
29
- /\bsqlite\b/i,
30
- /\bkeychain\b/i,
31
- /\bcredential\b/i,
32
- /\bstore\b/i,
33
- ];
34
- const EXPOSURE_PATTERNS = [
35
- /\bconsole\.log\b/i,
36
- /\blogger\./i,
37
- /\bres\.json\b/i,
38
- /\breturn\s+\{/i,
39
- /\bwindow\./i,
40
- /\bdocument\./i,
41
- /\bserialize\b/i,
42
- /\bresponse\b/i,
43
- ];
44
- const MASKING_PATTERNS = [
45
- /\bmask(key|ed)?\b/i,
46
- /\bredact(ed|ion)?\b/i,
47
- /\bhidden\b/i,
48
- /\bobfuscated\b/i,
49
- /\*\*\*\*/i,
50
- /\.\.\./i,
51
- ];
52
- export class EvidenceTracker {
53
- coverage = { ...DEFAULT_COVERAGE };
54
- observe(toolCall, result) {
55
- const haystack = [
56
- typeof toolCall.parsedArgs.path === "string" ? toolCall.parsedArgs.path : "",
57
- typeof toolCall.parsedArgs.command === "string" ? toolCall.parsedArgs.command : "",
58
- typeof toolCall.parsedArgs.pattern === "string" ? toolCall.parsedArgs.pattern : "",
59
- result.content,
60
- ].join("\n");
61
- if (!this.coverage.configLoadPaths && matchesAny(CONFIG_PATTERNS, haystack)) {
62
- this.coverage.configLoadPaths = true;
63
- }
64
- if (!this.coverage.envReads && matchesAny(ENV_PATTERNS, haystack)) {
65
- this.coverage.envReads = true;
66
- }
67
- if (!this.coverage.persistencePaths && matchesAny(PERSISTENCE_PATTERNS, haystack)) {
68
- this.coverage.persistencePaths = true;
69
- }
70
- if (!this.coverage.exposurePaths && matchesAny(EXPOSURE_PATTERNS, haystack)) {
71
- this.coverage.exposurePaths = true;
72
- }
73
- if (!this.coverage.maskingSignals && matchesAny(MASKING_PATTERNS, haystack)) {
74
- this.coverage.maskingSignals = true;
75
- }
76
- }
77
- snapshot() {
78
- return { ...this.coverage };
79
- }
80
- key() {
81
- const coverage = this.snapshot();
82
- return Object.values(coverage).map((value) => (value ? "1" : "0")).join("");
83
- }
84
- isCoreCoverageComplete() {
85
- return this.coverage.configLoadPaths
86
- && this.coverage.envReads
87
- && this.coverage.persistencePaths
88
- && this.coverage.exposurePaths;
89
- }
90
- }
91
- function matchesAny(patterns, haystack) {
92
- return patterns.some((pattern) => pattern.test(haystack));
93
- }
@@ -1,36 +0,0 @@
1
- import type { ParsedToolCall, ToolRegistryEntry, ToolResult } from "../types.js";
2
- import type { TaskType } from "./task-classifier.js";
3
- export interface GovernorDecision {
4
- blockedResult?: ToolResult;
5
- }
6
- export declare class ExecutionGovernor {
7
- private budget;
8
- private history;
9
- private totalSteps;
10
- private searchSteps;
11
- private readSteps;
12
- private mutationVersion;
13
- private reminderQueue;
14
- private warnedFamilies;
15
- private warnedSignatures;
16
- private softTotalWarned;
17
- private softSearchWarned;
18
- private softReadWarned;
19
- constructor(taskType: TaskType);
20
- consumePendingReminders(): string[];
21
- snapshot(): {
22
- totalSteps: number;
23
- searchSteps: number;
24
- readSteps: number;
25
- searchFrozen: boolean;
26
- explorationFrozen: boolean;
27
- phase: "observe";
28
- };
29
- filterToolDefinitions(toolDefinitions: ToolRegistryEntry[]): ToolRegistryEntry[];
30
- beforeToolCall(toolCall: ParsedToolCall): GovernorDecision;
31
- afterToolResult(toolCall: ParsedToolCall, result: ToolResult): void;
32
- private trailingNoProgressCount;
33
- private hasCurrentMutationObservation;
34
- private warnOnce;
35
- private maybeWarnOnSoftBudgets;
36
- }