@pentoshi/clai 3.11.7 → 3.11.9
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 +15 -0
- package/dist/agent/confirm-port.d.ts +4 -0
- package/dist/agent/confirm-port.js +9 -1
- package/dist/agent/confirm-port.js.map +1 -1
- package/dist/agent/finalize-gate.d.ts +57 -0
- package/dist/agent/finalize-gate.js +146 -0
- package/dist/agent/finalize-gate.js.map +1 -0
- package/dist/agent/runner.js +71 -179
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/tool-call-parser.js +3 -0
- package/dist/agent/tool-call-parser.js.map +1 -1
- package/dist/app/adapters/current-interactive-sessions-adapter.d.ts +4 -0
- package/dist/app/adapters/current-interactive-sessions-adapter.js +12 -0
- package/dist/app/adapters/current-interactive-sessions-adapter.js.map +1 -0
- package/dist/app/controllers/cancel-all-result.d.ts +8 -0
- package/dist/app/controllers/cancel-all-result.js +32 -0
- package/dist/app/controllers/cancel-all-result.js.map +1 -0
- package/dist/app/controllers/session-controller.d.ts +3 -0
- package/dist/app/controllers/session-controller.js +22 -6
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/ports/interactive-sessions-port.d.ts +22 -0
- package/dist/app/ports/interactive-sessions-port.js +9 -0
- package/dist/app/ports/interactive-sessions-port.js.map +1 -0
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/dist/interactive-session/artifact-writer.d.ts +54 -0
- package/dist/interactive-session/artifact-writer.js +161 -0
- package/dist/interactive-session/artifact-writer.js.map +1 -0
- package/dist/interactive-session/cleanup.d.ts +37 -0
- package/dist/interactive-session/cleanup.js +191 -0
- package/dist/interactive-session/cleanup.js.map +1 -0
- package/dist/interactive-session/config.d.ts +118 -0
- package/dist/interactive-session/config.js +141 -0
- package/dist/interactive-session/config.js.map +1 -0
- package/dist/interactive-session/input-policy.d.ts +26 -0
- package/dist/interactive-session/input-policy.js +70 -0
- package/dist/interactive-session/input-policy.js.map +1 -0
- package/dist/interactive-session/manager.d.ts +118 -0
- package/dist/interactive-session/manager.js +1214 -0
- package/dist/interactive-session/manager.js.map +1 -0
- package/dist/interactive-session/output-store.d.ts +81 -0
- package/dist/interactive-session/output-store.js +239 -0
- package/dist/interactive-session/output-store.js.map +1 -0
- package/dist/interactive-session/output-view.d.ts +20 -0
- package/dist/interactive-session/output-view.js +142 -0
- package/dist/interactive-session/output-view.js.map +1 -0
- package/dist/interactive-session/recovery-journal.d.ts +53 -0
- package/dist/interactive-session/recovery-journal.js +167 -0
- package/dist/interactive-session/recovery-journal.js.map +1 -0
- package/dist/interactive-session/registry.d.ts +59 -0
- package/dist/interactive-session/registry.js +170 -0
- package/dist/interactive-session/registry.js.map +1 -0
- package/dist/interactive-session/runtime.d.ts +107 -0
- package/dist/interactive-session/runtime.js +191 -0
- package/dist/interactive-session/runtime.js.map +1 -0
- package/dist/interactive-session/session-runtime.d.ts +53 -0
- package/dist/interactive-session/session-runtime.js +65 -0
- package/dist/interactive-session/session-runtime.js.map +1 -0
- package/dist/interactive-session/streaming-redactor.d.ts +53 -0
- package/dist/interactive-session/streaming-redactor.js +271 -0
- package/dist/interactive-session/streaming-redactor.js.map +1 -0
- package/dist/interactive-session/telemetry.d.ts +30 -0
- package/dist/interactive-session/telemetry.js +47 -0
- package/dist/interactive-session/telemetry.js.map +1 -0
- package/dist/interactive-session/transport-factory.d.ts +8 -0
- package/dist/interactive-session/transport-factory.js +16 -0
- package/dist/interactive-session/transport-factory.js.map +1 -0
- package/dist/interactive-session/transport-node-pty.d.ts +38 -0
- package/dist/interactive-session/transport-node-pty.js +390 -0
- package/dist/interactive-session/transport-node-pty.js.map +1 -0
- package/dist/interactive-session/transport-pipe.d.ts +9 -0
- package/dist/interactive-session/transport-pipe.js +267 -0
- package/dist/interactive-session/transport-pipe.js.map +1 -0
- package/dist/interactive-session/transport.d.ts +110 -0
- package/dist/interactive-session/transport.js +89 -0
- package/dist/interactive-session/transport.js.map +1 -0
- package/dist/interactive-session/types.d.ts +258 -0
- package/dist/interactive-session/types.js +191 -0
- package/dist/interactive-session/types.js.map +1 -0
- package/dist/os/process-identity.d.ts +46 -0
- package/dist/os/process-identity.js +147 -0
- package/dist/os/process-identity.js.map +1 -0
- package/dist/os/process-tree.d.ts +1 -0
- package/dist/os/process-tree.js +11 -0
- package/dist/os/process-tree.js.map +1 -1
- package/dist/prompts/embedded.js +1 -1
- package/dist/prompts/embedded.js.map +1 -1
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/index.js +23 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/system.agent.md +3 -0
- package/dist/repl.js +16 -1
- package/dist/repl.js.map +1 -1
- package/dist/safety/classifier.d.ts +9 -0
- package/dist/safety/classifier.js +119 -18
- package/dist/safety/classifier.js.map +1 -1
- package/dist/safety/engagement-policy.d.ts +13 -0
- package/dist/safety/engagement-policy.js +129 -34
- package/dist/safety/engagement-policy.js.map +1 -1
- package/dist/tools/definitions.js +94 -0
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/interactive-session-tools.d.ts +11 -0
- package/dist/tools/interactive-session-tools.js +276 -0
- package/dist/tools/interactive-session-tools.js.map +1 -0
- package/dist/tools/registry.js +3 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tui-v2/bootstrap/composition-root.d.ts +3 -0
- package/dist/tui-v2/bootstrap/composition-root.js +3 -0
- package/dist/tui-v2/bootstrap/composition-root.js.map +1 -1
- package/dist/tui-v2/bootstrap/start-tui-v2.js +8 -0
- package/dist/tui-v2/bootstrap/start-tui-v2.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +7 -6
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session concurrency primitives.
|
|
3
|
+
*
|
|
4
|
+
* The locking model is deliberately fine-grained: one owner-level mutex guards
|
|
5
|
+
* id issuance and live-slot reservation, one mutation mutex per session guards
|
|
6
|
+
* state/input/resize decisions, and output ingestion never takes either lock so
|
|
7
|
+
* a chatty child cannot block Close.
|
|
8
|
+
*/
|
|
9
|
+
export const systemClock = {
|
|
10
|
+
now: () => Date.now(),
|
|
11
|
+
setTimeout(handler, ms) {
|
|
12
|
+
const timer = setTimeout(handler, ms);
|
|
13
|
+
timer.unref?.();
|
|
14
|
+
return { id: timer };
|
|
15
|
+
},
|
|
16
|
+
clearTimeout(handle) {
|
|
17
|
+
clearTimeout(handle.id);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export class AsyncMutex {
|
|
21
|
+
tail = Promise.resolve();
|
|
22
|
+
/** Serialize `fn`; rejections do not poison the queue. */
|
|
23
|
+
run(fn) {
|
|
24
|
+
const result = this.tail.then(fn);
|
|
25
|
+
this.tail = result.then(() => undefined, () => undefined);
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Single-winner terminal work. Every later caller joins the first promise, so
|
|
31
|
+
* cleanup executes exactly once no matter how many triggers race.
|
|
32
|
+
*/
|
|
33
|
+
export class FinalizeOnce {
|
|
34
|
+
promise;
|
|
35
|
+
winnerReason;
|
|
36
|
+
get started() {
|
|
37
|
+
return this.promise !== undefined;
|
|
38
|
+
}
|
|
39
|
+
/** The reason that won the race, useful for choosing a terminal state. */
|
|
40
|
+
get reason() {
|
|
41
|
+
return this.winnerReason;
|
|
42
|
+
}
|
|
43
|
+
run(reason, fn) {
|
|
44
|
+
if (!this.promise) {
|
|
45
|
+
this.winnerReason = reason;
|
|
46
|
+
this.promise = fn();
|
|
47
|
+
}
|
|
48
|
+
return this.promise;
|
|
49
|
+
}
|
|
50
|
+
join() {
|
|
51
|
+
return this.promise;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Version-counter subscription used by blocking reads and send gathering. */
|
|
55
|
+
export class Notifier {
|
|
56
|
+
version = 0;
|
|
57
|
+
listeners = new Set();
|
|
58
|
+
get current() {
|
|
59
|
+
return this.version;
|
|
60
|
+
}
|
|
61
|
+
bump() {
|
|
62
|
+
this.version += 1;
|
|
63
|
+
for (const listener of [...this.listeners])
|
|
64
|
+
listener(this.version);
|
|
65
|
+
}
|
|
66
|
+
subscribe(listener) {
|
|
67
|
+
this.listeners.add(listener);
|
|
68
|
+
return () => {
|
|
69
|
+
this.listeners.delete(listener);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
clear() {
|
|
73
|
+
this.listeners.clear();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Idle resets on activity; lifetime is fixed from confirmed launch. */
|
|
77
|
+
export class TimerSet {
|
|
78
|
+
clock;
|
|
79
|
+
onExpire;
|
|
80
|
+
timers = {};
|
|
81
|
+
constructor(clock, onExpire) {
|
|
82
|
+
this.clock = clock;
|
|
83
|
+
this.onExpire = onExpire;
|
|
84
|
+
}
|
|
85
|
+
armIdle(ms) {
|
|
86
|
+
if (this.timers.idle)
|
|
87
|
+
this.clock.clearTimeout(this.timers.idle);
|
|
88
|
+
this.timers.idle = undefined;
|
|
89
|
+
if (ms === undefined)
|
|
90
|
+
return;
|
|
91
|
+
this.timers.idle = this.clock.setTimeout(() => {
|
|
92
|
+
this.timers.idle = undefined;
|
|
93
|
+
this.onExpire("idle-timeout");
|
|
94
|
+
}, ms);
|
|
95
|
+
}
|
|
96
|
+
armLifetime(ms) {
|
|
97
|
+
if (this.timers.lifetime || ms === undefined)
|
|
98
|
+
return;
|
|
99
|
+
this.timers.lifetime = this.clock.setTimeout(() => {
|
|
100
|
+
this.timers.lifetime = undefined;
|
|
101
|
+
this.onExpire("lifetime-timeout");
|
|
102
|
+
}, ms);
|
|
103
|
+
}
|
|
104
|
+
clearAll() {
|
|
105
|
+
if (this.timers.idle)
|
|
106
|
+
this.clock.clearTimeout(this.timers.idle);
|
|
107
|
+
if (this.timers.lifetime)
|
|
108
|
+
this.clock.clearTimeout(this.timers.lifetime);
|
|
109
|
+
this.timers.idle = undefined;
|
|
110
|
+
this.timers.lifetime = undefined;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export class WaiterSet {
|
|
114
|
+
waiters = new Set();
|
|
115
|
+
add(waiter) {
|
|
116
|
+
this.waiters.add(waiter);
|
|
117
|
+
return () => {
|
|
118
|
+
this.waiters.delete(waiter);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
cancelAll() {
|
|
122
|
+
for (const waiter of [...this.waiters])
|
|
123
|
+
waiter.cancel();
|
|
124
|
+
this.waiters.clear();
|
|
125
|
+
}
|
|
126
|
+
get size() {
|
|
127
|
+
return this.waiters.size;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* FIFO writer lane. Accepted actions are written strictly in ascending sequence
|
|
132
|
+
* order by a single drain loop, so concurrent sends can never interleave bytes
|
|
133
|
+
* or reorder commands.
|
|
134
|
+
*/
|
|
135
|
+
export class OrderedInputQueue {
|
|
136
|
+
queue = [];
|
|
137
|
+
draining = false;
|
|
138
|
+
nextSequence = 1;
|
|
139
|
+
queuedBytes = 0;
|
|
140
|
+
get depth() {
|
|
141
|
+
return this.queue.length;
|
|
142
|
+
}
|
|
143
|
+
get pendingBytes() {
|
|
144
|
+
return this.queuedBytes;
|
|
145
|
+
}
|
|
146
|
+
peekSequence() {
|
|
147
|
+
return this.nextSequence;
|
|
148
|
+
}
|
|
149
|
+
/** Reserve a sequence number and queued-byte budget for one action. */
|
|
150
|
+
reserve(bytes) {
|
|
151
|
+
const sequence = this.nextSequence;
|
|
152
|
+
this.nextSequence += 1;
|
|
153
|
+
this.queuedBytes += bytes;
|
|
154
|
+
return sequence;
|
|
155
|
+
}
|
|
156
|
+
enqueue(action) {
|
|
157
|
+
this.queue.push(action);
|
|
158
|
+
void this.drain();
|
|
159
|
+
}
|
|
160
|
+
async drain() {
|
|
161
|
+
if (this.draining)
|
|
162
|
+
return;
|
|
163
|
+
this.draining = true;
|
|
164
|
+
try {
|
|
165
|
+
while (this.queue.length > 0) {
|
|
166
|
+
const action = this.queue.shift();
|
|
167
|
+
let outcome;
|
|
168
|
+
try {
|
|
169
|
+
outcome = await action.deliver();
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
outcome = { status: "unknown", deliveredBytes: 0, cause: error };
|
|
173
|
+
}
|
|
174
|
+
this.queuedBytes = Math.max(0, this.queuedBytes - action.queuedBytes);
|
|
175
|
+
action.settle(outcome);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
this.draining = false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Reject every undelivered entry, e.g. after process exit or close. */
|
|
183
|
+
rejectAll(outcome) {
|
|
184
|
+
while (this.queue.length > 0) {
|
|
185
|
+
const action = this.queue.shift();
|
|
186
|
+
this.queuedBytes = Math.max(0, this.queuedBytes - action.queuedBytes);
|
|
187
|
+
action.settle(outcome);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/interactive-session/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutable per-session runtime: the transport, the output store, the ordered
|
|
3
|
+
* input lane, timers, and the single finalization promise.
|
|
4
|
+
*
|
|
5
|
+
* Sessions share no locks, queues, cursors, deadlines, or finalization state, so
|
|
6
|
+
* a failure in one session cannot affect another.
|
|
7
|
+
*/
|
|
8
|
+
import type { BoundedArtifactWriter } from "./artifact-writer.js";
|
|
9
|
+
import type { InteractiveSessionConfig } from "./config.js";
|
|
10
|
+
import type { OutputStore } from "./output-store.js";
|
|
11
|
+
import type { InteractiveEngagementState } from "../safety/engagement-policy.js";
|
|
12
|
+
import { AsyncMutex, FinalizeOnce, Notifier, OrderedInputQueue, TimerSet, type Clock } from "./runtime.js";
|
|
13
|
+
import type { SessionTransport } from "./transport.js";
|
|
14
|
+
import type { CloseResult, InteractiveSessionRecord, TerminationReason } from "./types.js";
|
|
15
|
+
export interface SessionRuntimeInit {
|
|
16
|
+
readonly record: InteractiveSessionRecord;
|
|
17
|
+
readonly transport: SessionTransport;
|
|
18
|
+
readonly output: OutputStore;
|
|
19
|
+
readonly artifact: BoundedArtifactWriter;
|
|
20
|
+
readonly config: InteractiveSessionConfig;
|
|
21
|
+
readonly clock: Clock;
|
|
22
|
+
readonly idleTimeoutMs: number | undefined;
|
|
23
|
+
readonly lifetimeTimeoutMs: number | undefined;
|
|
24
|
+
readonly engagementState?: InteractiveEngagementState | undefined;
|
|
25
|
+
readonly onTimeout: (reason: "idle-timeout" | "lifetime-timeout") => void;
|
|
26
|
+
}
|
|
27
|
+
export declare class SessionRuntime {
|
|
28
|
+
readonly record: InteractiveSessionRecord;
|
|
29
|
+
readonly transport: SessionTransport;
|
|
30
|
+
readonly output: OutputStore;
|
|
31
|
+
readonly artifact: BoundedArtifactWriter;
|
|
32
|
+
readonly config: InteractiveSessionConfig;
|
|
33
|
+
readonly clock: Clock;
|
|
34
|
+
readonly input: OrderedInputQueue;
|
|
35
|
+
readonly mutation: AsyncMutex;
|
|
36
|
+
readonly policy: AsyncMutex;
|
|
37
|
+
readonly finalize: FinalizeOnce<CloseResult>;
|
|
38
|
+
readonly timers: TimerSet;
|
|
39
|
+
readonly exitSignal: Notifier;
|
|
40
|
+
engagementState: InteractiveEngagementState;
|
|
41
|
+
/** Set once a terminal transition is chosen so late observations only enrich. */
|
|
42
|
+
processExited: boolean;
|
|
43
|
+
exitObserved: TerminationReason | undefined;
|
|
44
|
+
disposed: boolean;
|
|
45
|
+
private readonly unsubscribes;
|
|
46
|
+
private readonly idleTimeoutMs;
|
|
47
|
+
constructor(init: SessionRuntimeInit);
|
|
48
|
+
track(unsubscribe: () => void): void;
|
|
49
|
+
/** Accepted input and observed output both count as activity. */
|
|
50
|
+
touch(): void;
|
|
51
|
+
syncCursors(): void;
|
|
52
|
+
releaseListeners(): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutable per-session runtime: the transport, the output store, the ordered
|
|
3
|
+
* input lane, timers, and the single finalization promise.
|
|
4
|
+
*
|
|
5
|
+
* Sessions share no locks, queues, cursors, deadlines, or finalization state, so
|
|
6
|
+
* a failure in one session cannot affect another.
|
|
7
|
+
*/
|
|
8
|
+
import { AsyncMutex, FinalizeOnce, Notifier, OrderedInputQueue, TimerSet, } from "./runtime.js";
|
|
9
|
+
export class SessionRuntime {
|
|
10
|
+
record;
|
|
11
|
+
transport;
|
|
12
|
+
output;
|
|
13
|
+
artifact;
|
|
14
|
+
config;
|
|
15
|
+
clock;
|
|
16
|
+
input = new OrderedInputQueue();
|
|
17
|
+
mutation = new AsyncMutex();
|
|
18
|
+
policy = new AsyncMutex();
|
|
19
|
+
finalize = new FinalizeOnce();
|
|
20
|
+
timers;
|
|
21
|
+
exitSignal = new Notifier();
|
|
22
|
+
engagementState;
|
|
23
|
+
/** Set once a terminal transition is chosen so late observations only enrich. */
|
|
24
|
+
processExited = false;
|
|
25
|
+
exitObserved;
|
|
26
|
+
disposed = false;
|
|
27
|
+
unsubscribes = [];
|
|
28
|
+
idleTimeoutMs;
|
|
29
|
+
constructor(init) {
|
|
30
|
+
this.record = init.record;
|
|
31
|
+
this.transport = init.transport;
|
|
32
|
+
this.output = init.output;
|
|
33
|
+
this.artifact = init.artifact;
|
|
34
|
+
this.config = init.config;
|
|
35
|
+
this.clock = init.clock;
|
|
36
|
+
this.engagementState = init.engagementState ?? {};
|
|
37
|
+
this.idleTimeoutMs = init.idleTimeoutMs;
|
|
38
|
+
this.timers = new TimerSet(init.clock, init.onTimeout);
|
|
39
|
+
this.timers.armIdle(init.idleTimeoutMs);
|
|
40
|
+
this.timers.armLifetime(init.lifetimeTimeoutMs);
|
|
41
|
+
}
|
|
42
|
+
track(unsubscribe) {
|
|
43
|
+
this.unsubscribes.push(unsubscribe);
|
|
44
|
+
}
|
|
45
|
+
/** Accepted input and observed output both count as activity. */
|
|
46
|
+
touch() {
|
|
47
|
+
this.record.lastActivityAt = Date.now();
|
|
48
|
+
this.timers.armIdle(this.idleTimeoutMs);
|
|
49
|
+
}
|
|
50
|
+
syncCursors() {
|
|
51
|
+
this.record.earliestCursor = this.output.earliestCursor;
|
|
52
|
+
this.record.latestCursor = this.output.latestCursor;
|
|
53
|
+
}
|
|
54
|
+
releaseListeners() {
|
|
55
|
+
for (const unsubscribe of this.unsubscribes.splice(0)) {
|
|
56
|
+
try {
|
|
57
|
+
unsubscribe();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Listener teardown is best effort; cleanup must still complete.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=session-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-runtime.js","sourceRoot":"","sources":["../../src/interactive-session/session-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EACL,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,QAAQ,GAET,MAAM,cAAc,CAAC;AAqBtB,MAAM,OAAO,cAAc;IAChB,MAAM,CAA2B;IACjC,SAAS,CAAmB;IAC5B,MAAM,CAAc;IACpB,QAAQ,CAAwB;IAChC,MAAM,CAA2B;IACjC,KAAK,CAAQ;IACb,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAChC,QAAQ,GAAG,IAAI,UAAU,EAAE,CAAC;IAC5B,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAC1B,QAAQ,GAAG,IAAI,YAAY,EAAe,CAAC;IAC3C,MAAM,CAAW;IACjB,UAAU,GAAG,IAAI,QAAQ,EAAE,CAAC;IACrC,eAAe,CAA6B;IAE5C,iFAAiF;IACjF,aAAa,GAAG,KAAK,CAAC;IACtB,YAAY,CAAgC;IAC5C,QAAQ,GAAG,KAAK,CAAC;IAEA,YAAY,GAAsB,EAAE,CAAC;IACrC,aAAa,CAAqB;IAEnD,YAAY,IAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC;QAClD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,WAAuB;QAC3B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;IAED,iEAAiE;IACjE,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC;IAED,WAAW;QACT,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;QACxD,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;IACtD,CAAC;IAED,gBAAgB;QACd,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC;gBACH,WAAW,EAAE,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACP,iEAAiE;YACnE,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded streaming redaction over raw child output.
|
|
3
|
+
*
|
|
4
|
+
* Two lanes run before any byte receives a cursor, so raw sensitive data never
|
|
5
|
+
* reaches memory retention, artifacts, telemetry, or presentation:
|
|
6
|
+
*
|
|
7
|
+
* 1. A byte matcher removes the exact UTF-8 encodings of registered sensitive
|
|
8
|
+
* values across arbitrary chunk splits, including next to invalid UTF-8.
|
|
9
|
+
* 2. A decoder applies the existing textual secret patterns to the valid UTF-8
|
|
10
|
+
* runs of the emitted region.
|
|
11
|
+
*
|
|
12
|
+
* Retention is bounded: the only bytes held back are an incomplete trailing
|
|
13
|
+
* UTF-8 code point and a tail that is still a viable prefix of a registered
|
|
14
|
+
* secret. Prompts without a trailing newline therefore emit immediately.
|
|
15
|
+
*/
|
|
16
|
+
import { type SessionOperation } from "./types.js";
|
|
17
|
+
export declare const REDACTION_MARKER = "[redacted]";
|
|
18
|
+
/** Bytes of an incomplete trailing multi-byte UTF-8 sequence, else 0. */
|
|
19
|
+
export declare function trailingIncompleteUtf8Bytes(bytes: Uint8Array): number;
|
|
20
|
+
export interface Utf8Run {
|
|
21
|
+
readonly valid: boolean;
|
|
22
|
+
readonly bytes: Uint8Array;
|
|
23
|
+
}
|
|
24
|
+
/** Split a byte range into maximal valid-UTF-8 runs and invalid byte runs. */
|
|
25
|
+
export declare function splitUtf8Runs(bytes: Uint8Array): Utf8Run[];
|
|
26
|
+
export declare class StreamingSecretRedactor {
|
|
27
|
+
private readonly overlapBytes;
|
|
28
|
+
private pending;
|
|
29
|
+
private readonly secrets;
|
|
30
|
+
private redactedAny;
|
|
31
|
+
private closed;
|
|
32
|
+
constructor(overlapBytes: number);
|
|
33
|
+
get redacted(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Register an exact sensitive value. Values longer than the configured overlap
|
|
36
|
+
* bound are rejected before delivery because they could not be matched across
|
|
37
|
+
* chunk splits without unbounded retention.
|
|
38
|
+
*/
|
|
39
|
+
registerExactSecret(value: string, operation?: SessionOperation): void;
|
|
40
|
+
/** Longest tail of `bytes` that is a proper prefix of any registered secret. */
|
|
41
|
+
private viablePrefixTail;
|
|
42
|
+
/**
|
|
43
|
+
* Tail that is either a partial secret-pattern prefix or an in-progress token
|
|
44
|
+
* that a pattern could still consume.
|
|
45
|
+
*/
|
|
46
|
+
private viablePatternTail;
|
|
47
|
+
/** Feed raw bytes; returns the safe bytes now eligible for cursor assignment. */
|
|
48
|
+
push(raw: Uint8Array): Uint8Array;
|
|
49
|
+
/** Flush retained overlap through both lanes. Idempotent. */
|
|
50
|
+
close(): Uint8Array;
|
|
51
|
+
private transform;
|
|
52
|
+
private applyByteLane;
|
|
53
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded streaming redaction over raw child output.
|
|
3
|
+
*
|
|
4
|
+
* Two lanes run before any byte receives a cursor, so raw sensitive data never
|
|
5
|
+
* reaches memory retention, artifacts, telemetry, or presentation:
|
|
6
|
+
*
|
|
7
|
+
* 1. A byte matcher removes the exact UTF-8 encodings of registered sensitive
|
|
8
|
+
* values across arbitrary chunk splits, including next to invalid UTF-8.
|
|
9
|
+
* 2. A decoder applies the existing textual secret patterns to the valid UTF-8
|
|
10
|
+
* runs of the emitted region.
|
|
11
|
+
*
|
|
12
|
+
* Retention is bounded: the only bytes held back are an incomplete trailing
|
|
13
|
+
* UTF-8 code point and a tail that is still a viable prefix of a registered
|
|
14
|
+
* secret. Prompts without a trailing newline therefore emit immediately.
|
|
15
|
+
*/
|
|
16
|
+
import { redactSecrets } from "../llm/provider.js";
|
|
17
|
+
import { throwSessionError } from "./types.js";
|
|
18
|
+
export const REDACTION_MARKER = "[redacted]";
|
|
19
|
+
const MARKER_BYTES = new Uint8Array(Buffer.from(REDACTION_MARKER, "utf8"));
|
|
20
|
+
/** Bytes of an incomplete trailing multi-byte UTF-8 sequence, else 0. */
|
|
21
|
+
export function trailingIncompleteUtf8Bytes(bytes) {
|
|
22
|
+
const len = bytes.length;
|
|
23
|
+
for (let back = 1; back <= 3 && back <= len; back += 1) {
|
|
24
|
+
const byte = bytes[len - back];
|
|
25
|
+
if ((byte & 0xc0) === 0x80)
|
|
26
|
+
continue;
|
|
27
|
+
let expected = 1;
|
|
28
|
+
if ((byte & 0xe0) === 0xc0)
|
|
29
|
+
expected = 2;
|
|
30
|
+
else if ((byte & 0xf0) === 0xe0)
|
|
31
|
+
expected = 3;
|
|
32
|
+
else if ((byte & 0xf8) === 0xf0)
|
|
33
|
+
expected = 4;
|
|
34
|
+
return expected > back ? back : 0;
|
|
35
|
+
}
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
/** Split a byte range into maximal valid-UTF-8 runs and invalid byte runs. */
|
|
39
|
+
export function splitUtf8Runs(bytes) {
|
|
40
|
+
const runs = [];
|
|
41
|
+
let index = 0;
|
|
42
|
+
let validStart = 0;
|
|
43
|
+
const pushRun = (valid, start, end) => {
|
|
44
|
+
if (end > start)
|
|
45
|
+
runs.push({ valid, bytes: bytes.subarray(start, end) });
|
|
46
|
+
};
|
|
47
|
+
while (index < bytes.length) {
|
|
48
|
+
const width = utf8SequenceWidth(bytes, index);
|
|
49
|
+
if (width > 0) {
|
|
50
|
+
index += width;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
pushRun(true, validStart, index);
|
|
54
|
+
const invalidStart = index;
|
|
55
|
+
while (index < bytes.length && utf8SequenceWidth(bytes, index) === 0)
|
|
56
|
+
index += 1;
|
|
57
|
+
pushRun(false, invalidStart, index);
|
|
58
|
+
validStart = index;
|
|
59
|
+
}
|
|
60
|
+
pushRun(true, validStart, index);
|
|
61
|
+
return runs;
|
|
62
|
+
}
|
|
63
|
+
function utf8SequenceWidth(bytes, index) {
|
|
64
|
+
const byte = bytes[index];
|
|
65
|
+
if (byte < 0x80)
|
|
66
|
+
return 1;
|
|
67
|
+
let width = 0;
|
|
68
|
+
if ((byte & 0xe0) === 0xc0)
|
|
69
|
+
width = 2;
|
|
70
|
+
else if ((byte & 0xf0) === 0xe0)
|
|
71
|
+
width = 3;
|
|
72
|
+
else if ((byte & 0xf8) === 0xf0)
|
|
73
|
+
width = 4;
|
|
74
|
+
else
|
|
75
|
+
return 0;
|
|
76
|
+
if (index + width > bytes.length)
|
|
77
|
+
return 0;
|
|
78
|
+
for (let offset = 1; offset < width; offset += 1) {
|
|
79
|
+
if ((bytes[index + offset] & 0xc0) !== 0x80)
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
// Reject overlong encodings, surrogates, and out-of-range code points so a
|
|
83
|
+
// "valid" run always round-trips through UTF-8 without substitution.
|
|
84
|
+
const second = bytes[index + 1];
|
|
85
|
+
if (width === 2 && byte < 0xc2)
|
|
86
|
+
return 0;
|
|
87
|
+
if (width === 3 && byte === 0xe0 && second < 0xa0)
|
|
88
|
+
return 0;
|
|
89
|
+
if (width === 3 && byte === 0xed && second >= 0xa0)
|
|
90
|
+
return 0;
|
|
91
|
+
if (width === 4 && (byte > 0xf4 || (byte === 0xf0 && second < 0x90)))
|
|
92
|
+
return 0;
|
|
93
|
+
if (width === 4 && byte === 0xf4 && second > 0x8f)
|
|
94
|
+
return 0;
|
|
95
|
+
return width;
|
|
96
|
+
}
|
|
97
|
+
function indexOfSequence(haystack, needle, from) {
|
|
98
|
+
return Buffer.from(haystack.buffer, haystack.byteOffset, haystack.byteLength).indexOf(Buffer.from(needle), from);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Literal prefixes of the textual secret patterns applied by `redactSecrets`.
|
|
102
|
+
* They bound how much tail must be retained so a token split across chunks is
|
|
103
|
+
* still matched, without holding back ordinary prompt text.
|
|
104
|
+
*/
|
|
105
|
+
const TEXT_SECRET_PREFIXES = [
|
|
106
|
+
"gsk_",
|
|
107
|
+
"AIza",
|
|
108
|
+
"AQ.",
|
|
109
|
+
"sk-",
|
|
110
|
+
"nvapi-",
|
|
111
|
+
"wk-",
|
|
112
|
+
"ws-",
|
|
113
|
+
];
|
|
114
|
+
const TOKEN_BODY_RE = /^[A-Za-z0-9._-]*$/;
|
|
115
|
+
export class StreamingSecretRedactor {
|
|
116
|
+
overlapBytes;
|
|
117
|
+
pending = new Uint8Array(0);
|
|
118
|
+
secrets = [];
|
|
119
|
+
redactedAny = false;
|
|
120
|
+
closed = false;
|
|
121
|
+
constructor(overlapBytes) {
|
|
122
|
+
this.overlapBytes = overlapBytes;
|
|
123
|
+
}
|
|
124
|
+
get redacted() {
|
|
125
|
+
return this.redactedAny;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Register an exact sensitive value. Values longer than the configured overlap
|
|
129
|
+
* bound are rejected before delivery because they could not be matched across
|
|
130
|
+
* chunk splits without unbounded retention.
|
|
131
|
+
*/
|
|
132
|
+
registerExactSecret(value, operation = "send") {
|
|
133
|
+
if (value.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
const bytes = new Uint8Array(Buffer.from(value, "utf8"));
|
|
136
|
+
if (bytes.length > this.overlapBytes) {
|
|
137
|
+
throwSessionError({
|
|
138
|
+
code: "INVALID_CONFIGURATION",
|
|
139
|
+
operation,
|
|
140
|
+
message: "A sensitive value exceeds the configured redaction match span and cannot be redacted safely.",
|
|
141
|
+
details: { field: "redactionOverlapBytes", limitBytes: this.overlapBytes },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (this.secrets.some((existing) => Buffer.from(existing).equals(bytes)))
|
|
145
|
+
return;
|
|
146
|
+
this.secrets.push(bytes);
|
|
147
|
+
}
|
|
148
|
+
/** Longest tail of `bytes` that is a proper prefix of any registered secret. */
|
|
149
|
+
viablePrefixTail(bytes) {
|
|
150
|
+
let longest = 0;
|
|
151
|
+
for (const secret of this.secrets) {
|
|
152
|
+
const max = Math.min(secret.length - 1, bytes.length);
|
|
153
|
+
for (let length = max; length > longest; length -= 1) {
|
|
154
|
+
const tail = bytes.subarray(bytes.length - length);
|
|
155
|
+
if (Buffer.from(tail).equals(Buffer.from(secret.subarray(0, length)))) {
|
|
156
|
+
longest = length;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return Math.min(longest, this.overlapBytes);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Tail that is either a partial secret-pattern prefix or an in-progress token
|
|
165
|
+
* that a pattern could still consume.
|
|
166
|
+
*/
|
|
167
|
+
viablePatternTail(bytes) {
|
|
168
|
+
const window = bytes.subarray(Math.max(0, bytes.length - this.overlapBytes));
|
|
169
|
+
const text = Buffer.from(window).toString("latin1");
|
|
170
|
+
let longest = 0;
|
|
171
|
+
for (const prefix of TEXT_SECRET_PREFIXES) {
|
|
172
|
+
const start = text.lastIndexOf(prefix);
|
|
173
|
+
if (start >= 0 && TOKEN_BODY_RE.test(text.slice(start + prefix.length))) {
|
|
174
|
+
longest = Math.max(longest, text.length - start);
|
|
175
|
+
}
|
|
176
|
+
for (let length = Math.min(prefix.length - 1, text.length); length > longest; length -= 1) {
|
|
177
|
+
if (text.endsWith(prefix.slice(0, length))) {
|
|
178
|
+
longest = length;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return Math.min(longest, this.overlapBytes);
|
|
184
|
+
}
|
|
185
|
+
/** Feed raw bytes; returns the safe bytes now eligible for cursor assignment. */
|
|
186
|
+
push(raw) {
|
|
187
|
+
if (this.closed)
|
|
188
|
+
throw new Error("Cannot push into a closed redactor");
|
|
189
|
+
this.pending = concat(this.pending, raw);
|
|
190
|
+
const keepIncomplete = trailingIncompleteUtf8Bytes(this.pending);
|
|
191
|
+
const keepSecret = this.viablePrefixTail(this.pending);
|
|
192
|
+
const keepPattern = this.viablePatternTail(this.pending);
|
|
193
|
+
const keep = Math.min(Math.max(keepIncomplete, keepSecret, keepPattern), Math.min(this.pending.length, this.overlapBytes));
|
|
194
|
+
const emitEnd = this.pending.length - keep;
|
|
195
|
+
if (emitEnd <= 0)
|
|
196
|
+
return new Uint8Array(0);
|
|
197
|
+
const region = this.pending.subarray(0, emitEnd);
|
|
198
|
+
this.pending = new Uint8Array(this.pending.subarray(emitEnd));
|
|
199
|
+
return this.transform(region);
|
|
200
|
+
}
|
|
201
|
+
/** Flush retained overlap through both lanes. Idempotent. */
|
|
202
|
+
close() {
|
|
203
|
+
if (this.closed)
|
|
204
|
+
return new Uint8Array(0);
|
|
205
|
+
this.closed = true;
|
|
206
|
+
const region = this.pending;
|
|
207
|
+
this.pending = new Uint8Array(0);
|
|
208
|
+
return region.length > 0 ? this.transform(region) : new Uint8Array(0);
|
|
209
|
+
}
|
|
210
|
+
transform(region) {
|
|
211
|
+
const byteLane = this.applyByteLane(region);
|
|
212
|
+
const parts = [];
|
|
213
|
+
for (const run of splitUtf8Runs(byteLane)) {
|
|
214
|
+
if (!run.valid) {
|
|
215
|
+
// Binary bytes are preserved verbatim so encoded output and artifacts
|
|
216
|
+
// stay faithful; the byte lane already removed known secrets.
|
|
217
|
+
parts.push(run.bytes);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const text = Buffer.from(run.bytes).toString("utf8");
|
|
221
|
+
const safe = redactSecrets(text);
|
|
222
|
+
if (safe !== text)
|
|
223
|
+
this.redactedAny = true;
|
|
224
|
+
parts.push(new Uint8Array(Buffer.from(safe, "utf8")));
|
|
225
|
+
}
|
|
226
|
+
return concatAll(parts);
|
|
227
|
+
}
|
|
228
|
+
applyByteLane(region) {
|
|
229
|
+
if (this.secrets.length === 0)
|
|
230
|
+
return region;
|
|
231
|
+
let current = region;
|
|
232
|
+
for (const secret of this.secrets) {
|
|
233
|
+
let cursor = 0;
|
|
234
|
+
const parts = [];
|
|
235
|
+
for (;;) {
|
|
236
|
+
const found = indexOfSequence(current, secret, cursor);
|
|
237
|
+
if (found < 0)
|
|
238
|
+
break;
|
|
239
|
+
parts.push(current.subarray(cursor, found), MARKER_BYTES);
|
|
240
|
+
cursor = found + secret.length;
|
|
241
|
+
this.redactedAny = true;
|
|
242
|
+
}
|
|
243
|
+
if (parts.length === 0)
|
|
244
|
+
continue;
|
|
245
|
+
parts.push(current.subarray(cursor));
|
|
246
|
+
current = concatAll(parts);
|
|
247
|
+
}
|
|
248
|
+
return current;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function concat(a, b) {
|
|
252
|
+
if (a.length === 0)
|
|
253
|
+
return new Uint8Array(b);
|
|
254
|
+
if (b.length === 0)
|
|
255
|
+
return a;
|
|
256
|
+
const out = new Uint8Array(a.length + b.length);
|
|
257
|
+
out.set(a, 0);
|
|
258
|
+
out.set(b, a.length);
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
function concatAll(parts) {
|
|
262
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
263
|
+
const out = new Uint8Array(total);
|
|
264
|
+
let offset = 0;
|
|
265
|
+
for (const part of parts) {
|
|
266
|
+
out.set(part, offset);
|
|
267
|
+
offset += part.length;
|
|
268
|
+
}
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=streaming-redactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-redactor.js","sourceRoot":"","sources":["../../src/interactive-session/streaming-redactor.ts"],"names":[],"mappings":"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"}
|