@bubblebrain-ai/bubble 0.0.45 → 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.
- package/dist/agent/child-runner.js +11 -0
- package/dist/agent/internal-reminder-sanitizer.d.ts +7 -0
- package/dist/agent/internal-reminder-sanitizer.js +13 -0
- package/dist/agent/subagent/router.d.ts +65 -0
- package/dist/agent/subagent/router.js +198 -0
- package/dist/agent/subagent/runtime.d.ts +203 -0
- package/dist/agent/subagent/runtime.js +789 -0
- package/dist/agent/subagent-control.d.ts +5 -0
- package/dist/agent/subagent-store.d.ts +18 -2
- package/dist/agent/subagent-store.js +32 -1
- package/dist/agent/tool-intent.d.ts +10 -0
- package/dist/agent/tool-intent.js +18 -0
- package/dist/agent/tool-visibility.d.ts +10 -0
- package/dist/agent/tool-visibility.js +6 -0
- package/dist/agent/workflow/runs.d.ts +72 -0
- package/dist/agent/workflow/runs.js +157 -0
- package/dist/agent.d.ts +78 -96
- package/dist/agent.js +266 -1072
- package/dist/context/compact-llm.js +14 -5
- package/dist/context/compact.d.ts +9 -0
- package/dist/context/compact.js +36 -10
- package/dist/context/compaction-files.d.ts +44 -0
- package/dist/context/compaction-files.js +148 -0
- package/dist/context/llm-compactor.js +24 -5
- package/dist/feishu/agent-host/run-driver.js +3 -0
- package/dist/feishu/serve.js +13 -9
- package/dist/goal/tools.js +12 -3
- package/dist/main.js +24 -19
- package/dist/model-catalog.js +36 -2
- package/dist/model-config.d.ts +2 -0
- package/dist/model-data.generated.d.ts +16 -0
- package/dist/model-data.generated.js +275 -0
- package/dist/model-pricing.d.ts +11 -7
- package/dist/model-pricing.js +0 -0
- package/dist/oauth/grok.d.ts +1 -1
- package/dist/oauth/grok.js +58 -29
- package/dist/oauth/openai-codex.js +13 -0
- package/dist/oauth/storage.d.ts +9 -2
- package/dist/oauth/storage.js +16 -9
- package/dist/orchestrator/default-hooks.d.ts +20 -0
- package/dist/orchestrator/default-hooks.js +47 -295
- package/dist/orchestrator/hooks.d.ts +6 -39
- package/dist/permission/mode.js +1 -1
- package/dist/prompt/reminders.d.ts +9 -35
- package/dist/prompt/reminders.js +30 -136
- package/dist/prompt/task-reminders.d.ts +0 -31
- package/dist/prompt/task-reminders.js +0 -87
- package/dist/provider-ai-sdk.d.ts +2 -0
- package/dist/provider-ai-sdk.js +1 -0
- package/dist/provider-anthropic.d.ts +2 -0
- package/dist/provider-anthropic.js +3 -1
- package/dist/provider-ark-responses.d.ts +2 -0
- package/dist/provider-ark-responses.js +1 -0
- package/dist/provider-registry.d.ts +13 -0
- package/dist/provider-registry.js +83 -0
- package/dist/provider-transform.js +37 -1
- package/dist/provider.d.ts +7 -0
- package/dist/provider.js +13 -1
- package/dist/sdk/index.d.ts +152 -0
- package/dist/sdk/index.js +400 -0
- package/dist/session.js +9 -1
- package/dist/slash-commands/commands.js +33 -19
- package/dist/tools/exit-plan-mode.js +8 -0
- package/dist/tui/detect-theme.d.ts +1 -0
- package/dist/tui/detect-theme.js +11 -5
- package/dist/tui-ink/app.d.ts +2 -6
- package/dist/tui-ink/app.js +11 -18
- package/dist/tui-ink/display-history.d.ts +0 -2
- package/dist/tui-ink/display-history.js +0 -52
- package/dist/tui-ink/footer.js +2 -2
- package/dist/tui-ink/message-list.js +62 -23
- package/dist/tui-ink/run.js +10 -5
- package/dist/tui-ink/sync-output.d.ts +17 -0
- package/dist/tui-ink/sync-output.js +35 -0
- package/dist/tui-ink/theme.d.ts +0 -1
- package/dist/tui-ink/theme.js +0 -2
- package/dist/tui-ink/trace-groups.js +1 -1
- package/dist/types.d.ts +21 -1
- package/package.json +16 -2
- package/dist/agent/discovery-barrier.d.ts +0 -21
- package/dist/agent/discovery-barrier.js +0 -173
- package/dist/agent/evidence-tracker.d.ts +0 -15
- package/dist/agent/evidence-tracker.js +0 -93
- package/dist/agent/execution-governor.d.ts +0 -36
- package/dist/agent/execution-governor.js +0 -218
- package/dist/agent/task-classifier.d.ts +0 -3
- package/dist/agent/task-classifier.js +0 -114
- package/dist/agent/task-size.d.ts +0 -9
- package/dist/agent/task-size.js +0 -33
- package/dist/agent/tool-arbiter.d.ts +0 -7
- package/dist/agent/tool-arbiter.js +0 -33
- package/dist/orchestrator/workflow.d.ts +0 -10
- 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
|
+
}
|
package/dist/tui-ink/theme.d.ts
CHANGED
package/dist/tui-ink/theme.js
CHANGED
|
@@ -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
|
|
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.
|
|
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": "^
|
|
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
|
-
}
|