@vinhnt-sdk/step-executor 0.6.5 → 0.11.0
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/README.md +3 -2
- package/dist/file-snapshot.d.ts +162 -0
- package/dist/file-snapshot.d.ts.map +1 -0
- package/dist/file-snapshot.js +233 -0
- package/dist/file-snapshot.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel-error.d.ts +2 -9
- package/dist/kernel-error.d.ts.map +1 -1
- package/dist/kernel-error.js +1 -11
- package/dist/kernel-error.js.map +1 -1
- package/dist/permission-gate.d.ts +48 -3
- package/dist/permission-gate.d.ts.map +1 -1
- package/dist/permission-gate.js +83 -21
- package/dist/permission-gate.js.map +1 -1
- package/dist/run-state.d.ts +35 -0
- package/dist/run-state.d.ts.map +1 -1
- package/dist/run-state.js +59 -0
- package/dist/run-state.js.map +1 -1
- package/dist/self-correction.d.ts.map +1 -1
- package/dist/self-correction.js +4 -4
- package/dist/self-correction.js.map +1 -1
- package/dist/step-executor.d.ts +22 -0
- package/dist/step-executor.d.ts.map +1 -1
- package/dist/step-executor.js +101 -8
- package/dist/step-executor.js.map +1 -1
- package/dist/tool-context-builder.d.ts +4 -0
- package/dist/tool-context-builder.d.ts.map +1 -1
- package/dist/tool-context-builder.js +6 -1
- package/dist/tool-context-builder.js.map +1 -1
- package/dist/tool-error-router.d.ts.map +1 -1
- package/dist/tool-error-router.js +2 -2
- package/dist/tool-error-router.js.map +1 -1
- package/dist/tool-result-processor.js +5 -4
- package/dist/tool-result-processor.js.map +1 -1
- package/package.json +63 -64
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ pnpm add @vinhnt-sdk/step-executor
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import { StepExecutor, PermissionGate,
|
|
14
|
+
import { StepExecutor, PermissionGate, RunStateMachine } from "@vinhnt-sdk/step-executor";
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Contents
|
|
@@ -22,7 +22,8 @@ import { StepExecutor, PermissionGate, runLoop, RunStateMachine } from "@vinhnt-
|
|
|
22
22
|
- `termination` — stop-condition evaluation and judge-based loop termination
|
|
23
23
|
- `kernel-utils` — doom-loop detection, arg hashing, timeouts, tool domains, defaults
|
|
24
24
|
- `run-state` / `run-context` — per-run state machine and context
|
|
25
|
-
- `
|
|
25
|
+
- `loop-policy` / `path-policy` — loop/path safety policies
|
|
26
|
+
- `kernel-error` — typed step errors; failure isolation via `@vinhnt-sdk/guard` circuit breaker
|
|
26
27
|
|
|
27
28
|
## Hooks
|
|
28
29
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-step file snapshots → undo (P2-3 / G7.2).
|
|
3
|
+
*
|
|
4
|
+
* Before a mutating file tool (`write_file`/`edit_file`/`apply_patch` by
|
|
5
|
+
* default) executes, the recorder captures each target file's PRE-IMAGE:
|
|
6
|
+
* `{existed, content}` (content skipped above `maxContentBytes`). Snapshots
|
|
7
|
+
* are grouped by `runId`/`step`/`toolCallId`, kept in an in-memory bounded
|
|
8
|
+
* store (swap `fs`/store knobs via DI — no global state), and reference
|
|
9
|
+
* metadata (never file content) rides on the `tool.completed` event as
|
|
10
|
+
* `metadata.fileSnapshots`.
|
|
11
|
+
*
|
|
12
|
+
* `undo(filter)` restores newest-first: existing files get their pre-image
|
|
13
|
+
* back, files the tool created are removed, entries without a captured
|
|
14
|
+
* pre-image are reported as skipped. Opt-in via `AgentKernelConfig.fileSnapshot`
|
|
15
|
+
* (default: off — zero behavior change until enabled).
|
|
16
|
+
*/
|
|
17
|
+
/** Pre-image of one file captured before a mutating tool ran. */
|
|
18
|
+
export interface FileSnapshot {
|
|
19
|
+
/** Target path (absolute when `workspaceRoot` is known, else as given). */
|
|
20
|
+
readonly path: string;
|
|
21
|
+
/** Whether the file existed before the tool ran. */
|
|
22
|
+
readonly existed: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Pre-image content. `undefined` when the file did not exist, was
|
|
25
|
+
* unreadable, or exceeded `maxContentBytes` (undo then reports "no
|
|
26
|
+
* pre-image" instead of corrupting the file).
|
|
27
|
+
*/
|
|
28
|
+
readonly content?: string;
|
|
29
|
+
/** Pre-image size in bytes (0 when the file did not exist). */
|
|
30
|
+
readonly size: number;
|
|
31
|
+
readonly toolCallId: string;
|
|
32
|
+
readonly toolName: string;
|
|
33
|
+
readonly step: number;
|
|
34
|
+
readonly runId: string;
|
|
35
|
+
/** ISO timestamp of the capture. */
|
|
36
|
+
readonly at: string;
|
|
37
|
+
/** Set once `undo()` restored/removed this entry (never undone twice). */
|
|
38
|
+
undone: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Lightweight snapshot reference attached to `tool.completed` event metadata. */
|
|
41
|
+
export interface FileSnapshotRef {
|
|
42
|
+
readonly path: string;
|
|
43
|
+
readonly existed: boolean;
|
|
44
|
+
/** Whether a restorable pre-image was captured (false = over-cap/unreadable). */
|
|
45
|
+
readonly hadPreImage: boolean;
|
|
46
|
+
}
|
|
47
|
+
/** Injectable filesystem seam (defaults to `node:fs/promises`). */
|
|
48
|
+
export interface FileSnapshotFs {
|
|
49
|
+
/**
|
|
50
|
+
* Read a utf8 file. Return `content: undefined` when it exceeds `maxBytes`
|
|
51
|
+
* (still report `size`). Throw an error with `code: "ENOENT"` when missing.
|
|
52
|
+
*/
|
|
53
|
+
read(path: string, maxBytes: number): Promise<{
|
|
54
|
+
content?: string;
|
|
55
|
+
size: number;
|
|
56
|
+
}>;
|
|
57
|
+
write(path: string, content: string): Promise<void>;
|
|
58
|
+
remove(path: string): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/** Recorder configuration (all injectable — see defaults below). */
|
|
61
|
+
export interface FileSnapshotConfig {
|
|
62
|
+
/** Tool names eligible for capture. Default: {@link DEFAULT_SNAPSHOT_TOOL_IDS}. */
|
|
63
|
+
readonly toolIds?: readonly string[];
|
|
64
|
+
/** Arg keys holding the target path (first present wins). Default: {@link DEFAULT_SNAPSHOT_PATH_ARGS}. */
|
|
65
|
+
readonly pathArgs?: readonly string[];
|
|
66
|
+
/** Skip capturing content above this many bytes (existence is still recorded). Default: 1 MiB. */
|
|
67
|
+
readonly maxContentBytes?: number;
|
|
68
|
+
/** Max retained snapshots (drop-oldest). Default: 200. */
|
|
69
|
+
readonly maxSnapshots?: number;
|
|
70
|
+
/** Resolve relative target paths against this root. */
|
|
71
|
+
readonly workspaceRoot?: string;
|
|
72
|
+
/** Filesystem seam. Default: {@link createNodeFileSnapshotFs}. */
|
|
73
|
+
readonly fs?: FileSnapshotFs;
|
|
74
|
+
}
|
|
75
|
+
/** Selects snapshots for `list()`/`undo()`. At least one field should match. */
|
|
76
|
+
export interface FileSnapshotFilter {
|
|
77
|
+
readonly runId?: string;
|
|
78
|
+
readonly step?: number;
|
|
79
|
+
readonly path?: string;
|
|
80
|
+
readonly toolCallId?: string;
|
|
81
|
+
}
|
|
82
|
+
/** One successful undo action. */
|
|
83
|
+
export interface FileSnapshotUndoEntry {
|
|
84
|
+
readonly path: string;
|
|
85
|
+
readonly action: "restored" | "removed";
|
|
86
|
+
}
|
|
87
|
+
/** One entry that could not be undone. */
|
|
88
|
+
export interface FileSnapshotUndoSkipped {
|
|
89
|
+
readonly path: string;
|
|
90
|
+
readonly reason: string;
|
|
91
|
+
}
|
|
92
|
+
/** Result of {@link FileSnapshotRecorder.undo}. */
|
|
93
|
+
export interface FileSnapshotUndoResult {
|
|
94
|
+
readonly restored: readonly FileSnapshotUndoEntry[];
|
|
95
|
+
readonly skipped: readonly FileSnapshotUndoSkipped[];
|
|
96
|
+
}
|
|
97
|
+
/** Input to {@link FileSnapshotRecorder.capture}. */
|
|
98
|
+
export interface FileSnapshotCaptureParams {
|
|
99
|
+
readonly toolName: string;
|
|
100
|
+
readonly input: unknown;
|
|
101
|
+
readonly toolCallId: string;
|
|
102
|
+
readonly step: number;
|
|
103
|
+
readonly runId: string;
|
|
104
|
+
/** Override the ISO timestamp source (tests). */
|
|
105
|
+
readonly now?: () => string;
|
|
106
|
+
}
|
|
107
|
+
/** Default mutating tool names eligible for capture. */
|
|
108
|
+
export declare const DEFAULT_SNAPSHOT_TOOL_IDS: readonly ["write_file", "edit_file", "apply_patch"];
|
|
109
|
+
/** Default arg keys carrying the target file path. */
|
|
110
|
+
export declare const DEFAULT_SNAPSHOT_PATH_ARGS: readonly ["filePath", "path"];
|
|
111
|
+
/** Default content cap: 1 MiB (larger files record existence only). */
|
|
112
|
+
export declare const DEFAULT_SNAPSHOT_MAX_CONTENT_BYTES = 1048576;
|
|
113
|
+
/** Default bounded store size (drop-oldest). */
|
|
114
|
+
export declare const DEFAULT_SNAPSHOT_MAX_COUNT = 200;
|
|
115
|
+
/** Filesystem backed by `node:fs/promises`. */
|
|
116
|
+
export declare function createNodeFileSnapshotFs(): FileSnapshotFs;
|
|
117
|
+
/**
|
|
118
|
+
* Extract the target file paths a mutating tool call will touch:
|
|
119
|
+
* structured `apply_patch` patches (via the G2.1 grammar — every
|
|
120
|
+
* `*** Update/Add/Delete File:` path plus `*** Move to:` targets), otherwise
|
|
121
|
+
* the first present path arg (`filePath`/`path` by default).
|
|
122
|
+
* Returns `[]` when nothing extractable (caller skips capture).
|
|
123
|
+
*/
|
|
124
|
+
export declare function extractSnapshotPaths(toolName: string, input: unknown, config?: Pick<FileSnapshotConfig, "pathArgs">): readonly string[];
|
|
125
|
+
/**
|
|
126
|
+
* Bounded in-memory store of file pre-images with capture/undo.
|
|
127
|
+
* Not thread-safe across concurrent captures of the same path (per-tool
|
|
128
|
+
* captures are serialized by the step executor's approval flow).
|
|
129
|
+
*/
|
|
130
|
+
export declare class FileSnapshotRecorder {
|
|
131
|
+
private readonly toolIds;
|
|
132
|
+
private readonly pathArgs;
|
|
133
|
+
private readonly maxContentBytes;
|
|
134
|
+
private readonly maxSnapshots;
|
|
135
|
+
private readonly workspaceRoot;
|
|
136
|
+
private readonly fs;
|
|
137
|
+
private readonly snapshots;
|
|
138
|
+
constructor(config?: FileSnapshotConfig);
|
|
139
|
+
/** Total retained snapshots (bounded by `maxSnapshots`, drop-oldest). */
|
|
140
|
+
get size(): number;
|
|
141
|
+
/** Whether the given tool name is eligible for capture. */
|
|
142
|
+
accepts(toolName: string): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Capture pre-images for a mutating tool call (best-effort — never throws).
|
|
145
|
+
* Returns the lightweight refs to attach to `tool.completed` metadata.
|
|
146
|
+
*/
|
|
147
|
+
capture(params: FileSnapshotCaptureParams): Promise<readonly FileSnapshotRef[]>;
|
|
148
|
+
/** List matching snapshots (copy — oldest first). */
|
|
149
|
+
list(filter?: FileSnapshotFilter): readonly FileSnapshot[];
|
|
150
|
+
/**
|
|
151
|
+
* Undo matching, NOT-yet-undone snapshots, NEWEST FIRST.
|
|
152
|
+
* Existing files → pre-image restored; tool-created files → removed;
|
|
153
|
+
* entries without a captured pre-image → skipped with a reason.
|
|
154
|
+
*/
|
|
155
|
+
undo(filter?: FileSnapshotFilter): Promise<FileSnapshotUndoResult>;
|
|
156
|
+
/** Drop snapshots (all, or only a run's) — e.g. after session cleanup. */
|
|
157
|
+
clear(runId?: string): void;
|
|
158
|
+
private resolvePath;
|
|
159
|
+
}
|
|
160
|
+
/** Factory mirroring the SDK's create* conventions. */
|
|
161
|
+
export declare function createFileSnapshotRecorder(config?: FileSnapshotConfig): FileSnapshotRecorder;
|
|
162
|
+
//# sourceMappingURL=file-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-snapshot.d.ts","sourceRoot":"","sources":["../src/file-snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-step file snapshots → undo (P2-3 / G7.2).
|
|
3
|
+
*
|
|
4
|
+
* Before a mutating file tool (`write_file`/`edit_file`/`apply_patch` by
|
|
5
|
+
* default) executes, the recorder captures each target file's PRE-IMAGE:
|
|
6
|
+
* `{existed, content}` (content skipped above `maxContentBytes`). Snapshots
|
|
7
|
+
* are grouped by `runId`/`step`/`toolCallId`, kept in an in-memory bounded
|
|
8
|
+
* store (swap `fs`/store knobs via DI — no global state), and reference
|
|
9
|
+
* metadata (never file content) rides on the `tool.completed` event as
|
|
10
|
+
* `metadata.fileSnapshots`.
|
|
11
|
+
*
|
|
12
|
+
* `undo(filter)` restores newest-first: existing files get their pre-image
|
|
13
|
+
* back, files the tool created are removed, entries without a captured
|
|
14
|
+
* pre-image are reported as skipped. Opt-in via `AgentKernelConfig.fileSnapshot`
|
|
15
|
+
* (default: off — zero behavior change until enabled).
|
|
16
|
+
*/
|
|
17
|
+
import { readFile, writeFile, rm, stat } from "node:fs/promises";
|
|
18
|
+
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
19
|
+
import { detectApplyPatchFormat, parseApplyPatch } from "@vinhnt-sdk/tools";
|
|
20
|
+
/** Default mutating tool names eligible for capture. */
|
|
21
|
+
export const DEFAULT_SNAPSHOT_TOOL_IDS = ["write_file", "edit_file", "apply_patch"];
|
|
22
|
+
/** Default arg keys carrying the target file path. */
|
|
23
|
+
export const DEFAULT_SNAPSHOT_PATH_ARGS = ["filePath", "path"];
|
|
24
|
+
/** Default content cap: 1 MiB (larger files record existence only). */
|
|
25
|
+
export const DEFAULT_SNAPSHOT_MAX_CONTENT_BYTES = 1_048_576;
|
|
26
|
+
/** Default bounded store size (drop-oldest). */
|
|
27
|
+
export const DEFAULT_SNAPSHOT_MAX_COUNT = 200;
|
|
28
|
+
/** Filesystem backed by `node:fs/promises`. */
|
|
29
|
+
export function createNodeFileSnapshotFs() {
|
|
30
|
+
return {
|
|
31
|
+
async read(path, maxBytes) {
|
|
32
|
+
const info = await stat(path);
|
|
33
|
+
if (info.size > maxBytes)
|
|
34
|
+
return { size: info.size };
|
|
35
|
+
const content = await readFile(path, "utf8");
|
|
36
|
+
return { content, size: Buffer.byteLength(content, "utf8") };
|
|
37
|
+
},
|
|
38
|
+
async write(path, content) {
|
|
39
|
+
await writeFile(path, content, "utf8");
|
|
40
|
+
},
|
|
41
|
+
async remove(path) {
|
|
42
|
+
await rm(path, { force: true });
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extract the target file paths a mutating tool call will touch:
|
|
48
|
+
* structured `apply_patch` patches (via the G2.1 grammar — every
|
|
49
|
+
* `*** Update/Add/Delete File:` path plus `*** Move to:` targets), otherwise
|
|
50
|
+
* the first present path arg (`filePath`/`path` by default).
|
|
51
|
+
* Returns `[]` when nothing extractable (caller skips capture).
|
|
52
|
+
*/
|
|
53
|
+
export function extractSnapshotPaths(toolName, input, config) {
|
|
54
|
+
const record = (typeof input === "object" && input !== null ? input : {});
|
|
55
|
+
if (toolName === "apply_patch" && typeof record.patch === "string") {
|
|
56
|
+
const patch = record.patch;
|
|
57
|
+
if (detectApplyPatchFormat(patch) === "structured") {
|
|
58
|
+
try {
|
|
59
|
+
const program = parseApplyPatch(patch, "lenient");
|
|
60
|
+
const paths = [];
|
|
61
|
+
for (const op of program.ops) {
|
|
62
|
+
paths.push(op.path);
|
|
63
|
+
if (op.kind === "update" && op.moveTo !== undefined)
|
|
64
|
+
paths.push(op.moveTo);
|
|
65
|
+
}
|
|
66
|
+
return [...new Set(paths)];
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Best-effort: fall through to path-arg extraction.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const key of config?.pathArgs ?? DEFAULT_SNAPSHOT_PATH_ARGS) {
|
|
74
|
+
const value = record[key];
|
|
75
|
+
if (typeof value === "string" && value.length > 0)
|
|
76
|
+
return [value];
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Bounded in-memory store of file pre-images with capture/undo.
|
|
82
|
+
* Not thread-safe across concurrent captures of the same path (per-tool
|
|
83
|
+
* captures are serialized by the step executor's approval flow).
|
|
84
|
+
*/
|
|
85
|
+
export class FileSnapshotRecorder {
|
|
86
|
+
toolIds;
|
|
87
|
+
pathArgs;
|
|
88
|
+
maxContentBytes;
|
|
89
|
+
maxSnapshots;
|
|
90
|
+
workspaceRoot;
|
|
91
|
+
fs;
|
|
92
|
+
snapshots = [];
|
|
93
|
+
constructor(config = {}) {
|
|
94
|
+
this.toolIds = new Set(config.toolIds ?? DEFAULT_SNAPSHOT_TOOL_IDS);
|
|
95
|
+
this.pathArgs = config.pathArgs ?? DEFAULT_SNAPSHOT_PATH_ARGS;
|
|
96
|
+
this.maxContentBytes = config.maxContentBytes ?? DEFAULT_SNAPSHOT_MAX_CONTENT_BYTES;
|
|
97
|
+
this.maxSnapshots = Math.max(1, config.maxSnapshots ?? DEFAULT_SNAPSHOT_MAX_COUNT);
|
|
98
|
+
this.workspaceRoot = config.workspaceRoot;
|
|
99
|
+
this.fs = config.fs ?? createNodeFileSnapshotFs();
|
|
100
|
+
}
|
|
101
|
+
/** Total retained snapshots (bounded by `maxSnapshots`, drop-oldest). */
|
|
102
|
+
get size() {
|
|
103
|
+
return this.snapshots.length;
|
|
104
|
+
}
|
|
105
|
+
/** Whether the given tool name is eligible for capture. */
|
|
106
|
+
accepts(toolName) {
|
|
107
|
+
return this.toolIds.has(toolName);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Capture pre-images for a mutating tool call (best-effort — never throws).
|
|
111
|
+
* Returns the lightweight refs to attach to `tool.completed` metadata.
|
|
112
|
+
*/
|
|
113
|
+
async capture(params) {
|
|
114
|
+
if (!this.accepts(params.toolName))
|
|
115
|
+
return [];
|
|
116
|
+
const paths = extractSnapshotPaths(params.toolName, params.input, { pathArgs: this.pathArgs });
|
|
117
|
+
if (paths.length === 0)
|
|
118
|
+
return [];
|
|
119
|
+
const at = (params.now ?? (() => new Date().toISOString()))();
|
|
120
|
+
const refs = [];
|
|
121
|
+
for (const rawPath of paths) {
|
|
122
|
+
try {
|
|
123
|
+
const path = this.resolvePath(rawPath);
|
|
124
|
+
let existed = true;
|
|
125
|
+
let content;
|
|
126
|
+
let size = 0;
|
|
127
|
+
try {
|
|
128
|
+
const result = await this.fs.read(path, this.maxContentBytes);
|
|
129
|
+
content = result.content;
|
|
130
|
+
size = result.size;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (error.code === "ENOENT") {
|
|
134
|
+
existed = false;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
continue; // unreadable (permissions, directory…) — skip this path
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this.snapshots.push({
|
|
141
|
+
path,
|
|
142
|
+
existed,
|
|
143
|
+
...(content !== undefined ? { content } : {}),
|
|
144
|
+
size,
|
|
145
|
+
toolCallId: params.toolCallId,
|
|
146
|
+
toolName: params.toolName,
|
|
147
|
+
step: params.step,
|
|
148
|
+
runId: params.runId,
|
|
149
|
+
at,
|
|
150
|
+
undone: false,
|
|
151
|
+
});
|
|
152
|
+
while (this.snapshots.length > this.maxSnapshots)
|
|
153
|
+
this.snapshots.shift();
|
|
154
|
+
refs.push({ path, existed, hadPreImage: existed && content !== undefined });
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Path resolution failure — never break the tool call.
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return refs;
|
|
161
|
+
}
|
|
162
|
+
/** List matching snapshots (copy — oldest first). */
|
|
163
|
+
list(filter) {
|
|
164
|
+
return this.snapshots.filter((s) => matches(s, filter));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Undo matching, NOT-yet-undone snapshots, NEWEST FIRST.
|
|
168
|
+
* Existing files → pre-image restored; tool-created files → removed;
|
|
169
|
+
* entries without a captured pre-image → skipped with a reason.
|
|
170
|
+
*/
|
|
171
|
+
async undo(filter = {}) {
|
|
172
|
+
const target = this.snapshots
|
|
173
|
+
.filter((s) => !s.undone && matches(s, filter))
|
|
174
|
+
.sort((a, b) => b.at.localeCompare(a.at) || this.snapshots.indexOf(b) - this.snapshots.indexOf(a));
|
|
175
|
+
const restored = [];
|
|
176
|
+
const skipped = [];
|
|
177
|
+
for (const snapshot of target) {
|
|
178
|
+
try {
|
|
179
|
+
if (!snapshot.existed) {
|
|
180
|
+
await this.fs.remove(snapshot.path);
|
|
181
|
+
snapshot.undone = true;
|
|
182
|
+
restored.push({ path: snapshot.path, action: "removed" });
|
|
183
|
+
}
|
|
184
|
+
else if (snapshot.content !== undefined) {
|
|
185
|
+
await this.fs.write(snapshot.path, snapshot.content);
|
|
186
|
+
snapshot.undone = true;
|
|
187
|
+
restored.push({ path: snapshot.path, action: "restored" });
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
skipped.push({ path: snapshot.path, reason: "no pre-image captured (missing or over size cap)" });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
skipped.push({ path: snapshot.path, reason: error instanceof Error ? error.message : String(error) });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { restored, skipped };
|
|
198
|
+
}
|
|
199
|
+
/** Drop snapshots (all, or only a run's) — e.g. after session cleanup. */
|
|
200
|
+
clear(runId) {
|
|
201
|
+
if (runId === undefined) {
|
|
202
|
+
this.snapshots.length = 0;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
for (let i = this.snapshots.length - 1; i >= 0; i--) {
|
|
206
|
+
if (this.snapshots[i]?.runId === runId)
|
|
207
|
+
this.snapshots.splice(i, 1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
resolvePath(path) {
|
|
211
|
+
if (this.workspaceRoot === undefined || isAbsolute(path))
|
|
212
|
+
return path;
|
|
213
|
+
return resolvePath(this.workspaceRoot, path);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/** Factory mirroring the SDK's create* conventions. */
|
|
217
|
+
export function createFileSnapshotRecorder(config) {
|
|
218
|
+
return new FileSnapshotRecorder(config);
|
|
219
|
+
}
|
|
220
|
+
function matches(snapshot, filter) {
|
|
221
|
+
if (filter === undefined)
|
|
222
|
+
return true;
|
|
223
|
+
if (filter.runId !== undefined && snapshot.runId !== filter.runId)
|
|
224
|
+
return false;
|
|
225
|
+
if (filter.step !== undefined && snapshot.step !== filter.step)
|
|
226
|
+
return false;
|
|
227
|
+
if (filter.path !== undefined && snapshot.path !== filter.path)
|
|
228
|
+
return false;
|
|
229
|
+
if (filter.toolCallId !== undefined && snapshot.toolCallId !== filter.toolCallId)
|
|
230
|
+
return false;
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=file-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-snapshot.js","sourceRoot":"","sources":["../src/file-snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
export type { StepExecutorPluginHooks } from "./hooks.js";
|
|
7
7
|
export { StepExecutor } from "./step-executor.js";
|
|
8
8
|
export type { StepExecutorDeps, ToolExecutionPlan, HandoffSignal } from "./step-executor.js";
|
|
9
|
+
export { FileSnapshotRecorder, createFileSnapshotRecorder, createNodeFileSnapshotFs, extractSnapshotPaths, DEFAULT_SNAPSHOT_TOOL_IDS, DEFAULT_SNAPSHOT_PATH_ARGS, DEFAULT_SNAPSHOT_MAX_CONTENT_BYTES, DEFAULT_SNAPSHOT_MAX_COUNT, } from "./file-snapshot.js";
|
|
10
|
+
export type { FileSnapshot, FileSnapshotRef, FileSnapshotFs, FileSnapshotConfig, FileSnapshotFilter, FileSnapshotCaptureParams, FileSnapshotUndoEntry, FileSnapshotUndoSkipped, FileSnapshotUndoResult, } from "./file-snapshot.js";
|
|
9
11
|
export { DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_CALLS_PER_STEP, DOOM_LOOP_THRESHOLD, toolDomain, } from "./kernel-utils.js";
|
|
10
12
|
export { resolveLoopPolicy } from "./loop-policy.js";
|
|
11
13
|
export type { LoopDetectionConfig, LoopDetectionAction, ResolvedLoopPolicy } from "./loop-policy.js";
|
|
@@ -19,6 +21,6 @@ export { KernelError } from "./kernel-error.js";
|
|
|
19
21
|
export type { KernelErrorCode } from "./kernel-error.js";
|
|
20
22
|
export { CircuitBreaker, CircuitBreakerOpenError } from "@vinhnt-sdk/guard";
|
|
21
23
|
export type { CircuitState, CircuitBreakerOptions } from "@vinhnt-sdk/guard";
|
|
22
|
-
export { RunStateMachine } from "./run-state.js";
|
|
23
|
-
export type { RunState } from "./run-state.js";
|
|
24
|
+
export { RunStateMachine, MAX_RETAINED_RUN_STATES } from "./run-state.js";
|
|
25
|
+
export type { RunState, RunStateMachineOptions } from "./run-state.js";
|
|
24
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAI1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAI7F,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAIrG,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpH,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAInH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIpH,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIjE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAI7E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAI1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAI7F,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,yBAAyB,EACzB,0BAA0B,EAC1B,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAIrG,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpH,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAInH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIpH,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIjE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAI7E,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
// === Step Executor ===
|
|
7
7
|
export { StepExecutor } from "./step-executor.js";
|
|
8
|
+
// === File snapshots → undo (G7.2 / P2-3) ===
|
|
9
|
+
export { FileSnapshotRecorder, createFileSnapshotRecorder, createNodeFileSnapshotFs, extractSnapshotPaths, DEFAULT_SNAPSHOT_TOOL_IDS, DEFAULT_SNAPSHOT_PATH_ARGS, DEFAULT_SNAPSHOT_MAX_CONTENT_BYTES, DEFAULT_SNAPSHOT_MAX_COUNT, } from "./file-snapshot.js";
|
|
8
10
|
// === Kernel Utils (public subset) ===
|
|
9
11
|
export { DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_CALLS_PER_STEP, DOOM_LOOP_THRESHOLD, toolDomain, } from "./kernel-utils.js";
|
|
10
12
|
// === Loop Detection Policy (P1-3) ===
|
|
@@ -20,5 +22,5 @@ export { KernelError } from "./kernel-error.js";
|
|
|
20
22
|
// === Circuit Breaker (re-exported from @vinhnt-sdk/guard) ===
|
|
21
23
|
export { CircuitBreaker, CircuitBreakerOpenError } from "@vinhnt-sdk/guard";
|
|
22
24
|
// === Run State ===
|
|
23
|
-
export { RunStateMachine } from "./run-state.js";
|
|
25
|
+
export { RunStateMachine, MAX_RETAINED_RUN_STATES } from "./run-state.js";
|
|
24
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,wBAAwB;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,uCAAuC;AAEvC,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,uCAAuC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,sBAAsB;AAEtB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGpH,0BAA0B;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,sBAAsB;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,uBAAuB;AAEvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,+DAA+D;AAE/D,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAG5E,oBAAoB;AAEpB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,wBAAwB;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,8CAA8C;AAE9C,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,yBAAyB,EACzB,0BAA0B,EAC1B,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAa5B,uCAAuC;AAEvC,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,uCAAuC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,sBAAsB;AAEtB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGpH,0BAA0B;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,sBAAsB;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,uBAAuB;AAEvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,+DAA+D;AAE/D,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAG5E,oBAAoB;AAEpB,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/kernel-error.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type KernelErrorCode = "session_busy" | "cancelled" | "max_steps_exceeded" | "max_tokens_exceeded" | "tool_failed" | "model_failed" | "session_store_failed" | "internal_error" | "timeout" | "model_unavailable" | "guardrail_denied" | "validation_error" | "missed_tool_calls";
|
|
4
|
-
/** Kernel-level failure with a typed {@link KernelErrorCode}. */
|
|
5
|
-
export declare class KernelError extends VntError {
|
|
6
|
-
readonly code: string;
|
|
7
|
-
readonly retryable = false;
|
|
8
|
-
constructor(kernelCode: KernelErrorCode, message: string, cause?: unknown);
|
|
9
|
-
}
|
|
1
|
+
export { KernelError } from "@vinhnt-sdk/schema";
|
|
2
|
+
export type { KernelErrorCode } from "@vinhnt-sdk/schema";
|
|
10
3
|
//# sourceMappingURL=kernel-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel-error.d.ts","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"kernel-error.d.ts","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/kernel-error.js
CHANGED
|
@@ -1,12 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
/** Kernel-level failure with a typed {@link KernelErrorCode}. */
|
|
3
|
-
export class KernelError extends VntError {
|
|
4
|
-
code;
|
|
5
|
-
retryable = false;
|
|
6
|
-
constructor(kernelCode, message, cause) {
|
|
7
|
-
super(message, { cause });
|
|
8
|
-
this.code = kernelCode;
|
|
9
|
-
this.name = `KernelError.${kernelCode}`;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
1
|
+
export { KernelError } from "@vinhnt-sdk/schema";
|
|
12
2
|
//# sourceMappingURL=kernel-error.js.map
|
package/dist/kernel-error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel-error.js","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"kernel-error.js","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RunId, AgentConfig } from "@vinhnt-sdk/schema";
|
|
2
2
|
import type { ToolRisk, PermissionReply } from "@vinhnt-sdk/tools";
|
|
3
3
|
import type { StepExecutorPluginHooks } from "./hooks.js";
|
|
4
|
-
import type { ApprovalStore } from "@vinhnt-sdk/permission";
|
|
4
|
+
import type { ApprovalStore, PermissionMode, PermissionClassifier, ModeEffectSource } from "@vinhnt-sdk/permission";
|
|
5
5
|
import type { RunEventStore } from "@vinhnt-sdk/session";
|
|
6
6
|
import type { EventBus } from "@vinhnt-sdk/event";
|
|
7
7
|
/** Result of an approval check: allow, deny, or needs approval. */
|
|
@@ -17,6 +17,12 @@ export interface PermissionCheckResult {
|
|
|
17
17
|
allowed: boolean;
|
|
18
18
|
reason?: string;
|
|
19
19
|
needsApproval?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Set on needsApproval results (G5): whether the ask came from an explicit
|
|
22
|
+
* `rules` decision or the `risk` floor. The `auto` classifier only ever
|
|
23
|
+
* auto-approves risk-floor asks — explicit rule asks always prompt.
|
|
24
|
+
*/
|
|
25
|
+
source?: ModeEffectSource;
|
|
20
26
|
}
|
|
21
27
|
/** Optional ask options for non-standard permission keys (e.g. doom_loop). */
|
|
22
28
|
export interface AskForToolOptions {
|
|
@@ -27,6 +33,18 @@ export interface AskForToolOptions {
|
|
|
27
33
|
readonly forceAsk?: boolean;
|
|
28
34
|
/** Permission key reported to hooks/events. Default: `tool.<name>`. */
|
|
29
35
|
readonly permissionKey?: string;
|
|
36
|
+
/**
|
|
37
|
+
* G5: risk of the tool, passed to the `auto` classifier.
|
|
38
|
+
* Missing risk makes the default classifier fail closed to the dialog.
|
|
39
|
+
*/
|
|
40
|
+
readonly risk?: string | undefined;
|
|
41
|
+
/** G5: tool args handed to the `auto` classifier (semantic classification). */
|
|
42
|
+
readonly args?: Record<string, unknown> | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* G5: origin of the ask (`checkTool` result source). The classifier only
|
|
45
|
+
* runs for `"risk"` asks — absent/`"rules"` asks always open the dialog.
|
|
46
|
+
*/
|
|
47
|
+
readonly source?: ModeEffectSource | undefined;
|
|
30
48
|
}
|
|
31
49
|
/** Dependencies required by {@link PermissionGate}. */
|
|
32
50
|
export interface PermissionGateDeps {
|
|
@@ -47,6 +65,16 @@ export interface PermissionGateDeps {
|
|
|
47
65
|
* re-requesting variants after timeouts) must not run unbounded.
|
|
48
66
|
*/
|
|
49
67
|
readonly maxApprovalAsksPerRun?: number | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* G5: Claude-style approval mode (`default`/`acceptEdits`/`plan`/`bypass`/
|
|
70
|
+
* `auto` + legacy aliases). Undefined = no mode overlay (legacy behavior).
|
|
71
|
+
*/
|
|
72
|
+
readonly permissionMode?: PermissionMode | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* G5: classifier consulted by `auto` mode for risk-floor asks. Defaults to
|
|
75
|
+
* {@link createRiskPermissionClassifier} (pure, fail-closed).
|
|
76
|
+
*/
|
|
77
|
+
readonly permissionClassifier?: PermissionClassifier | undefined;
|
|
50
78
|
}
|
|
51
79
|
/** Enforces 4-phase permission gating: global rules, agent perms, dynamic rules, risk defaults. */
|
|
52
80
|
export declare class PermissionGate {
|
|
@@ -56,6 +84,12 @@ export declare class PermissionGate {
|
|
|
56
84
|
private riskOverrides?;
|
|
57
85
|
private topLevelRules;
|
|
58
86
|
private autoApproval;
|
|
87
|
+
/** G5: Claude-style mode overlay (undefined = legacy pipeline, no overlay). */
|
|
88
|
+
private mode;
|
|
89
|
+
/** G5: injected classifier for `auto` mode; falls back to the risk classifier. */
|
|
90
|
+
private classifier;
|
|
91
|
+
/** G5: default `auto` classifier — pure, deterministic, fail-closed. */
|
|
92
|
+
private readonly fallbackClassifier;
|
|
59
93
|
/** Per-approval hard timeout — separate from agent stale threshold. */
|
|
60
94
|
private readonly approvalTimeoutMs;
|
|
61
95
|
/** Safety valve — max approval dialogs per run. */
|
|
@@ -67,6 +101,10 @@ export declare class PermissionGate {
|
|
|
67
101
|
constructor(deps: PermissionGateDeps);
|
|
68
102
|
/** Toggle auto-approval at runtime (mirrors config.autoApprovalEnabled). */
|
|
69
103
|
setAutoApprovalEnabled(enabled: boolean): void;
|
|
104
|
+
/** G5: set/replace the permission mode at runtime (undefined = no overlay). */
|
|
105
|
+
setPermissionMode(mode: PermissionMode | undefined): void;
|
|
106
|
+
/** G5: set/replace the `auto` classifier at runtime (undefined = risk default). */
|
|
107
|
+
setPermissionClassifier(classifier: PermissionClassifier | undefined): void;
|
|
70
108
|
/**
|
|
71
109
|
* Parse and apply config-level permission rules (OpenCode-style nested `{ tool: "allow|deny|ask" }`).
|
|
72
110
|
* Bare keys are stored as `tool.<name>` so they match {@link checkTool}'s
|
|
@@ -87,10 +125,17 @@ export declare class PermissionGate {
|
|
|
87
125
|
addDoomLoopBypass(toolName: string): void;
|
|
88
126
|
/** Override risk-level defaults (read→allow, write→approval, destructive→deny). */
|
|
89
127
|
setRiskOverrides(overrides?: Partial<Record<ToolRisk, ApprovalDecision>>): void;
|
|
128
|
+
/**
|
|
129
|
+
* Map a final effect to the check result, applying the G5 mode overlay
|
|
130
|
+
* first. With no mode configured the overlay passes through — behavior is
|
|
131
|
+
* byte-identical to the legacy pipeline.
|
|
132
|
+
*/
|
|
133
|
+
private decide;
|
|
90
134
|
/**
|
|
91
135
|
* Evaluate whether a tool call is allowed.
|
|
92
|
-
* 4-phase gate: global rules → agent permissions → dynamic rules → risk defaults
|
|
93
|
-
*
|
|
136
|
+
* 4-phase gate: global rules → agent permissions → dynamic rules → risk defaults,
|
|
137
|
+
* then the G5 permission-mode overlay (applied inside {@link decide}).
|
|
138
|
+
* Returns { allowed, reason, needsApproval, source }.
|
|
94
139
|
*/
|
|
95
140
|
checkTool(name: string, risk: ToolRisk, args?: Record<string, unknown>, agent?: AgentConfig): PermissionCheckResult;
|
|
96
141
|
/** Check whether combined token count stays within agent's maxTokens limit. */
|