aegis-bridge 2.4.0 → 2.5.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/dashboard/dist/assets/{index-DPp-wise.css → index-B7DYf7vF.css} +1 -1
- package/dashboard/dist/assets/{index-I_vW1gcQ.js → index-DxAes2EQ.js} +47 -47
- package/dashboard/dist/index.html +2 -2
- package/dist/auth.js +1 -2
- package/dist/channels/index.js +0 -1
- package/dist/channels/manager.js +0 -1
- package/dist/channels/telegram-style.js +0 -1
- package/dist/channels/telegram.js +0 -1
- package/dist/channels/types.js +0 -1
- package/dist/channels/webhook.js +0 -1
- package/dist/cli.js +0 -1
- package/dist/config.js +11 -5
- package/dist/dashboard/assets/{index-DPp-wise.css → index-B7DYf7vF.css} +1 -1
- package/dist/dashboard/assets/{index-I_vW1gcQ.js → index-DxAes2EQ.js} +47 -47
- package/dist/dashboard/index.html +2 -2
- package/dist/error-categories.js +0 -1
- package/dist/events.d.ts +2 -0
- package/dist/events.js +21 -3
- package/dist/hook-settings.js +13 -7
- package/dist/hook.js +0 -1
- package/dist/hooks.js +21 -20
- package/dist/jsonl-watcher.js +0 -1
- package/dist/mcp-server.js +0 -1
- package/dist/metrics.d.ts +2 -0
- package/dist/metrics.js +30 -17
- package/dist/monitor.js +1 -2
- package/dist/permission-guard.js +0 -1
- package/dist/pipeline.js +0 -1
- package/dist/screenshot.js +0 -1
- package/dist/server.js +88 -274
- package/dist/session.js +14 -9
- package/dist/signal-cleanup-helper.js +0 -1
- package/dist/sse-limiter.js +0 -1
- package/dist/sse-writer.js +0 -1
- package/dist/ssrf.d.ts +4 -0
- package/dist/ssrf.js +23 -2
- package/dist/swarm-monitor.js +1 -3
- package/dist/terminal-parser.js +3 -2
- package/dist/tmux-capture-cache.js +0 -1
- package/dist/tmux.js +1 -2
- package/dist/transcript.js +53 -51
- package/dist/utils/redact-headers.js +0 -1
- package/dist/validation.d.ts +34 -2
- package/dist/validation.js +20 -4
- package/dist/ws-terminal.js +4 -3
- package/package.json +3 -3
package/dist/ssrf.js
CHANGED
|
@@ -17,12 +17,16 @@ import net from 'node:net';
|
|
|
17
17
|
* - Unspecified: ::
|
|
18
18
|
* - IPv6 unique-local: fc00::/7
|
|
19
19
|
* - CGNAT: 100.64.0.0/10 (RFC 6598)
|
|
20
|
+
* - Broadcast: 255.255.255.255
|
|
21
|
+
* - Multicast: 224.0.0.0/4 (RFC 5771)
|
|
22
|
+
* - Documentation: 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 (RFC 5737)
|
|
23
|
+
* - Benchmarking: 198.18.0.0/15 (RFC 2544)
|
|
20
24
|
*/
|
|
21
25
|
export function isPrivateIP(ip) {
|
|
22
26
|
// IPv4
|
|
23
27
|
if (net.isIPv4(ip)) {
|
|
24
28
|
const parts = ip.split('.').map(Number);
|
|
25
|
-
const [a, b] = parts;
|
|
29
|
+
const [a, b, c] = parts;
|
|
26
30
|
// 0.0.0.0/8
|
|
27
31
|
if (a === 0)
|
|
28
32
|
return true;
|
|
@@ -44,6 +48,24 @@ export function isPrivateIP(ip) {
|
|
|
44
48
|
// 100.64.0.0/10 (CGNAT)
|
|
45
49
|
if (a === 100 && b >= 64 && b <= 127)
|
|
46
50
|
return true;
|
|
51
|
+
// 255.255.255.255 (broadcast)
|
|
52
|
+
if (a === 255 && b === 255 && c === 255 && parts[3] === 255)
|
|
53
|
+
return true;
|
|
54
|
+
// 224.0.0.0/4 (multicast) — 224.0.0.0 to 239.255.255.255
|
|
55
|
+
if (a >= 224 && a <= 239)
|
|
56
|
+
return true;
|
|
57
|
+
// 192.0.2.0/24 (documentation, RFC 5737)
|
|
58
|
+
if (a === 192 && b === 0 && c === 2)
|
|
59
|
+
return true;
|
|
60
|
+
// 198.51.100.0/24 (documentation, RFC 5737)
|
|
61
|
+
if (a === 198 && b === 51 && c === 100)
|
|
62
|
+
return true;
|
|
63
|
+
// 203.0.113.0/24 (documentation, RFC 5737)
|
|
64
|
+
if (a === 203 && b === 0 && c === 113)
|
|
65
|
+
return true;
|
|
66
|
+
// 198.18.0.0/15 (benchmarking, RFC 2544) — 198.18.0.0 to 198.19.255.255
|
|
67
|
+
if (a === 198 && b >= 18 && b <= 19)
|
|
68
|
+
return true;
|
|
47
69
|
return false;
|
|
48
70
|
}
|
|
49
71
|
// IPv6
|
|
@@ -166,4 +188,3 @@ export function validateScreenshotUrl(rawUrl) {
|
|
|
166
188
|
}
|
|
167
189
|
return null;
|
|
168
190
|
}
|
|
169
|
-
//# sourceMappingURL=ssrf.js.map
|
package/dist/swarm-monitor.js
CHANGED
|
@@ -154,11 +154,10 @@ export class SwarmMonitor {
|
|
|
154
154
|
return this.cachedSocketNames;
|
|
155
155
|
}
|
|
156
156
|
const entries = await readdir(tmpdir());
|
|
157
|
-
const pattern = this.config.socketGlobPattern.replace('tmux-', '');
|
|
158
157
|
// Match "tmux-<socketName>" directories (tmux socket dirs start with "tmux-")
|
|
159
158
|
const socketNames = [];
|
|
160
159
|
for (const entry of entries) {
|
|
161
|
-
if (entry.startsWith('tmux-')
|
|
160
|
+
if (entry.startsWith('tmux-')) {
|
|
162
161
|
// Extract socket name: tmux-<socketName> → <socketName>
|
|
163
162
|
const socketName = entry.slice(5); // remove "tmux-"
|
|
164
163
|
// Verify it's a claude-swarm-* socket
|
|
@@ -264,4 +263,3 @@ export class SwarmMonitor {
|
|
|
264
263
|
return this.lastResult.swarms.filter(s => s.parentSession !== null && s.teammates.length > 0);
|
|
265
264
|
}
|
|
266
265
|
}
|
|
267
|
-
//# sourceMappingURL=swarm-monitor.js.map
|
package/dist/terminal-parser.js
CHANGED
|
@@ -142,11 +142,13 @@ export function detectUIState(paneText) {
|
|
|
142
142
|
return 'waiting_for_input';
|
|
143
143
|
return 'unknown';
|
|
144
144
|
}
|
|
145
|
+
/** Number of lines from the bottom of the pane to scan for active spinners. */
|
|
146
|
+
const SPINNER_SEARCH_LINES = 30;
|
|
145
147
|
/** Check if any line in the pane has an active spinner character followed by working text. */
|
|
146
148
|
function hasSpinnerAnywhere(lines) {
|
|
147
149
|
// Only check lines in the content area (not the very bottom few which are prompt/footer)
|
|
148
150
|
const searchEnd = Math.max(0, lines.length - 3);
|
|
149
|
-
for (let i = Math.max(0, lines.length -
|
|
151
|
+
for (let i = Math.max(0, lines.length - SPINNER_SEARCH_LINES); i < searchEnd; i++) {
|
|
150
152
|
const stripped = lines[i].trim();
|
|
151
153
|
if (!stripped)
|
|
152
154
|
continue;
|
|
@@ -340,4 +342,3 @@ function findLastNonEmpty(lines, from = 0) {
|
|
|
340
342
|
}
|
|
341
343
|
return last;
|
|
342
344
|
}
|
|
343
|
-
//# sourceMappingURL=terminal-parser.js.map
|
package/dist/tmux.js
CHANGED
|
@@ -39,7 +39,7 @@ export class TmuxManager {
|
|
|
39
39
|
this.socketName = socketName ?? `aegis-${process.pid}`;
|
|
40
40
|
}
|
|
41
41
|
/** Promise-chain queue that serializes all tmux CLI calls to prevent race conditions. */
|
|
42
|
-
queue = Promise.resolve(
|
|
42
|
+
queue = Promise.resolve();
|
|
43
43
|
/** #403: Counter of in-flight createWindow calls — direct methods must queue when > 0. */
|
|
44
44
|
_creatingCount = 0;
|
|
45
45
|
/** #357: Short-lived cache for window existence checks to reduce CLI calls. */
|
|
@@ -748,4 +748,3 @@ export class TmuxManager {
|
|
|
748
748
|
function sleep(ms) {
|
|
749
749
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
750
750
|
}
|
|
751
|
-
//# sourceMappingURL=tmux.js.map
|
package/dist/transcript.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Port of CCBot's transcript_parser.py.
|
|
5
5
|
* Reads CC session JSONL files and extracts structured messages.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { readFile, open } from 'node:fs/promises';
|
|
8
8
|
import { createReadStream, existsSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import { homedir } from 'node:os';
|
|
@@ -154,62 +154,65 @@ export function parseEntries(entries) {
|
|
|
154
154
|
}
|
|
155
155
|
/** Read JSONL file from byte offset, return new entries + new offset. */
|
|
156
156
|
export async function readNewEntries(filePath, fromOffset) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
// Read from byte offset to end using createReadStream to avoid loading entire file
|
|
166
|
-
// Issue #222: Only read from offset forward, not the whole file
|
|
167
|
-
// Issue #259: If offset lands mid-entry, scan backwards to previous newline
|
|
168
|
-
// Issue #409: Use async I/O instead of readFileSync to avoid blocking the event loop
|
|
169
|
-
let effectiveOffset = fromOffset;
|
|
170
|
-
if (effectiveOffset > 0) {
|
|
171
|
-
const scanSize = 4096;
|
|
172
|
-
const scanStart = Math.max(0, effectiveOffset - scanSize);
|
|
173
|
-
const scanLen = effectiveOffset - scanStart;
|
|
174
|
-
const scanBuf = Buffer.alloc(scanLen);
|
|
175
|
-
const fd = await open(filePath, 'r');
|
|
176
|
-
try {
|
|
177
|
-
await fd.read(scanBuf, 0, scanLen, scanStart);
|
|
157
|
+
// Issue #623: Use a single fd for stat + read to eliminate TOCTOU race.
|
|
158
|
+
const fd = await open(filePath, 'r');
|
|
159
|
+
try {
|
|
160
|
+
const fileStat = await fd.stat();
|
|
161
|
+
// File truncated (e.g. after /clear)
|
|
162
|
+
if (fromOffset > fileStat.size) {
|
|
163
|
+
return { entries: [], newOffset: 0, raw: [] };
|
|
178
164
|
}
|
|
179
|
-
|
|
180
|
-
|
|
165
|
+
if (fromOffset >= fileStat.size) {
|
|
166
|
+
return { entries: [], newOffset: fromOffset, raw: [] };
|
|
181
167
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
168
|
+
// Read from byte offset to end using createReadStream to avoid loading entire file
|
|
169
|
+
// Issue #222: Only read from offset forward, not the whole file
|
|
170
|
+
// Issue #259: If offset lands mid-entry, scan backwards to previous newline
|
|
171
|
+
// Issue #409: Use async I/O instead of readFileSync to avoid blocking the event loop
|
|
172
|
+
let effectiveOffset = fromOffset;
|
|
173
|
+
if (effectiveOffset > 0) {
|
|
174
|
+
const scanSize = 4096;
|
|
175
|
+
const scanStart = Math.max(0, effectiveOffset - scanSize);
|
|
176
|
+
const scanLen = effectiveOffset - scanStart;
|
|
177
|
+
const scanBuf = Buffer.alloc(scanLen);
|
|
178
|
+
await fd.read(scanBuf, 0, scanLen, scanStart);
|
|
179
|
+
let foundNewline = false;
|
|
180
|
+
for (let i = scanBuf.length - 1; i >= 0; i--) {
|
|
181
|
+
if (scanBuf[i] === 0x0a) { // '\n'
|
|
182
|
+
effectiveOffset = scanStart + i + 1;
|
|
183
|
+
foundNewline = true;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Issue #579: If no newline found and we didn't scan from byte 0,
|
|
188
|
+
// fall back to offset 0 to avoid starting mid-line.
|
|
189
|
+
if (!foundNewline && scanStart > 0) {
|
|
190
|
+
effectiveOffset = 0;
|
|
188
191
|
}
|
|
189
192
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
const slicedContent = await new Promise((resolve, reject) => {
|
|
194
|
+
const chunks = [];
|
|
195
|
+
// Reuse the same fd — autoClose: false because we close it in the outer finally
|
|
196
|
+
const stream = createReadStream(filePath, { fd: fd.fd, start: effectiveOffset, autoClose: false });
|
|
197
|
+
stream.on('data', (chunk) => { if (typeof chunk !== 'string')
|
|
198
|
+
chunks.push(chunk); });
|
|
199
|
+
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
200
|
+
stream.on('error', reject);
|
|
201
|
+
});
|
|
202
|
+
const lines = slicedContent.split('\n');
|
|
203
|
+
const rawEntries = [];
|
|
204
|
+
for (const line of lines) {
|
|
205
|
+
const entry = parseLine(line);
|
|
206
|
+
if (entry) {
|
|
207
|
+
rawEntries.push(entry);
|
|
208
|
+
}
|
|
194
209
|
}
|
|
210
|
+
const parsed = parseEntries(rawEntries);
|
|
211
|
+
return { entries: parsed, newOffset: fileStat.size, raw: rawEntries };
|
|
195
212
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const stream = createReadStream(filePath, { start: effectiveOffset });
|
|
199
|
-
stream.on('data', (chunk) => chunks.push(chunk));
|
|
200
|
-
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
201
|
-
stream.on('error', reject);
|
|
202
|
-
});
|
|
203
|
-
const lines = slicedContent.split('\n');
|
|
204
|
-
const rawEntries = [];
|
|
205
|
-
for (const line of lines) {
|
|
206
|
-
const entry = parseLine(line);
|
|
207
|
-
if (entry) {
|
|
208
|
-
rawEntries.push(entry);
|
|
209
|
-
}
|
|
213
|
+
finally {
|
|
214
|
+
await fd.close();
|
|
210
215
|
}
|
|
211
|
-
const parsed = parseEntries(rawEntries);
|
|
212
|
-
return { entries: parsed, newOffset: fileStat.size, raw: rawEntries };
|
|
213
216
|
}
|
|
214
217
|
/** Find the JSONL file for a session ID. */
|
|
215
218
|
export async function findSessionFile(sessionId, claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR) {
|
|
@@ -248,4 +251,3 @@ export async function findSessionFile(sessionId, claudeProjectsDir = DEFAULT_CLA
|
|
|
248
251
|
}
|
|
249
252
|
return null;
|
|
250
253
|
}
|
|
251
|
-
//# sourceMappingURL=transcript.js.map
|
package/dist/validation.d.ts
CHANGED
|
@@ -40,6 +40,25 @@ export declare const webhookEndpointSchema: z.ZodObject<{
|
|
|
40
40
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
41
41
|
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
42
42
|
}, z.core.$strict>;
|
|
43
|
+
/** POST /v1/hooks/:eventName — CC hook event payload (Issue #665). */
|
|
44
|
+
export declare const hookBodySchema: z.ZodObject<{
|
|
45
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
46
|
+
agent_name: z.ZodOptional<z.ZodString>;
|
|
47
|
+
agent_type: z.ZodOptional<z.ZodString>;
|
|
48
|
+
tool_name: z.ZodOptional<z.ZodString>;
|
|
49
|
+
tool_input: z.ZodOptional<z.ZodObject<{
|
|
50
|
+
command: z.ZodOptional<z.ZodString>;
|
|
51
|
+
}, z.core.$loose>>;
|
|
52
|
+
tool_use_id: z.ZodOptional<z.ZodString>;
|
|
53
|
+
permission_prompt: z.ZodOptional<z.ZodString>;
|
|
54
|
+
permission_mode: z.ZodOptional<z.ZodString>;
|
|
55
|
+
hook_event_name: z.ZodOptional<z.ZodString>;
|
|
56
|
+
model: z.ZodOptional<z.ZodString>;
|
|
57
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
58
|
+
stop_reason: z.ZodOptional<z.ZodString>;
|
|
59
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
60
|
+
command: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$loose>;
|
|
43
62
|
/** POST /v1/sessions/:id/hooks/permission */
|
|
44
63
|
export declare const permissionHookSchema: z.ZodObject<{
|
|
45
64
|
session_id: z.ZodOptional<z.ZodString>;
|
|
@@ -64,6 +83,9 @@ export declare const batchSessionSchema: z.ZodObject<{
|
|
|
64
83
|
default: "default";
|
|
65
84
|
bypassPermissions: "bypassPermissions";
|
|
66
85
|
plan: "plan";
|
|
86
|
+
acceptEdits: "acceptEdits";
|
|
87
|
+
dontAsk: "dontAsk";
|
|
88
|
+
auto: "auto";
|
|
67
89
|
}>>;
|
|
68
90
|
autoApprove: z.ZodOptional<z.ZodBoolean>;
|
|
69
91
|
stallThresholdMs: z.ZodOptional<z.ZodNumber>;
|
|
@@ -82,6 +104,9 @@ export declare const pipelineSchema: z.ZodObject<{
|
|
|
82
104
|
default: "default";
|
|
83
105
|
bypassPermissions: "bypassPermissions";
|
|
84
106
|
plan: "plan";
|
|
107
|
+
acceptEdits: "acceptEdits";
|
|
108
|
+
dontAsk: "dontAsk";
|
|
109
|
+
auto: "auto";
|
|
85
110
|
}>>;
|
|
86
111
|
autoApprove: z.ZodOptional<z.ZodBoolean>;
|
|
87
112
|
}, z.core.$strip>>;
|
|
@@ -104,9 +129,9 @@ export declare const persistedStateSchema: z.ZodRecord<z.ZodString, z.ZodObject<
|
|
|
104
129
|
monitorOffset: z.ZodNumber;
|
|
105
130
|
status: z.ZodEnum<{
|
|
106
131
|
unknown: "unknown";
|
|
132
|
+
permission_prompt: "permission_prompt";
|
|
107
133
|
idle: "idle";
|
|
108
134
|
working: "working";
|
|
109
|
-
permission_prompt: "permission_prompt";
|
|
110
135
|
bash_approval: "bash_approval";
|
|
111
136
|
plan_mode: "plan_mode";
|
|
112
137
|
ask_question: "ask_question";
|
|
@@ -116,7 +141,14 @@ export declare const persistedStateSchema: z.ZodRecord<z.ZodString, z.ZodObject<
|
|
|
116
141
|
lastActivity: z.ZodNumber;
|
|
117
142
|
stallThresholdMs: z.ZodNumber;
|
|
118
143
|
permissionStallMs: z.ZodDefault<z.ZodNumber>;
|
|
119
|
-
permissionMode: z.
|
|
144
|
+
permissionMode: z.ZodEnum<{
|
|
145
|
+
default: "default";
|
|
146
|
+
bypassPermissions: "bypassPermissions";
|
|
147
|
+
plan: "plan";
|
|
148
|
+
acceptEdits: "acceptEdits";
|
|
149
|
+
dontAsk: "dontAsk";
|
|
150
|
+
auto: "auto";
|
|
151
|
+
}>;
|
|
120
152
|
settingsPatched: z.ZodOptional<z.ZodBoolean>;
|
|
121
153
|
hookSettingsFile: z.ZodOptional<z.ZodString>;
|
|
122
154
|
lastHookAt: z.ZodOptional<z.ZodNumber>;
|
package/dist/validation.js
CHANGED
|
@@ -43,6 +43,23 @@ export const webhookEndpointSchema = z.object({
|
|
|
43
43
|
headers: z.record(z.string(), z.string()).optional(),
|
|
44
44
|
timeoutMs: z.number().int().positive().optional(),
|
|
45
45
|
}).strict();
|
|
46
|
+
/** POST /v1/hooks/:eventName — CC hook event payload (Issue #665). */
|
|
47
|
+
export const hookBodySchema = z.object({
|
|
48
|
+
session_id: z.string().optional(),
|
|
49
|
+
agent_name: z.string().optional(),
|
|
50
|
+
agent_type: z.string().optional(),
|
|
51
|
+
tool_name: z.string().optional(),
|
|
52
|
+
tool_input: z.object({ command: z.string().optional() }).passthrough().optional(),
|
|
53
|
+
tool_use_id: z.string().optional(),
|
|
54
|
+
permission_prompt: z.string().optional(),
|
|
55
|
+
permission_mode: z.string().optional(),
|
|
56
|
+
hook_event_name: z.string().optional(),
|
|
57
|
+
model: z.string().optional(),
|
|
58
|
+
timestamp: z.string().optional(),
|
|
59
|
+
stop_reason: z.string().optional(),
|
|
60
|
+
cwd: z.string().optional(),
|
|
61
|
+
command: z.string().optional(),
|
|
62
|
+
}).passthrough();
|
|
46
63
|
/** POST /v1/sessions/:id/hooks/permission */
|
|
47
64
|
export const permissionHookSchema = z.object({
|
|
48
65
|
session_id: z.string().optional(),
|
|
@@ -61,7 +78,7 @@ const batchSessionSpecSchema = z.object({
|
|
|
61
78
|
name: z.string().max(200).optional(),
|
|
62
79
|
workDir: z.string().min(1),
|
|
63
80
|
prompt: z.string().max(100_000).optional(),
|
|
64
|
-
permissionMode: z.enum(['default', 'bypassPermissions', 'plan']).optional(),
|
|
81
|
+
permissionMode: z.enum(['default', 'bypassPermissions', 'plan', 'acceptEdits', 'dontAsk', 'auto']).optional(),
|
|
65
82
|
autoApprove: z.boolean().optional(),
|
|
66
83
|
stallThresholdMs: z.number().int().positive().max(3_600_000).optional(),
|
|
67
84
|
});
|
|
@@ -74,7 +91,7 @@ const pipelineStageSchema = z.object({
|
|
|
74
91
|
workDir: z.string().min(1).optional(),
|
|
75
92
|
prompt: z.string().min(1).max(MAX_INPUT_LENGTH),
|
|
76
93
|
dependsOn: z.array(z.string()).optional(),
|
|
77
|
-
permissionMode: z.enum(['default', 'bypassPermissions', 'plan']).optional(),
|
|
94
|
+
permissionMode: z.enum(['default', 'bypassPermissions', 'plan', 'acceptEdits', 'dontAsk', 'auto']).optional(),
|
|
78
95
|
autoApprove: z.boolean().optional(),
|
|
79
96
|
});
|
|
80
97
|
/** POST /v1/pipelines */
|
|
@@ -122,7 +139,7 @@ export const persistedStateSchema = z.record(z.string(), z.object({
|
|
|
122
139
|
lastActivity: z.number(),
|
|
123
140
|
stallThresholdMs: z.number(),
|
|
124
141
|
permissionStallMs: z.number().default(300_000),
|
|
125
|
-
permissionMode: z.
|
|
142
|
+
permissionMode: z.enum(['default', 'bypassPermissions', 'plan', 'acceptEdits', 'dontAsk', 'auto']),
|
|
126
143
|
settingsPatched: z.boolean().optional(),
|
|
127
144
|
hookSettingsFile: z.string().optional(),
|
|
128
145
|
lastHookAt: z.number().optional(),
|
|
@@ -267,4 +284,3 @@ export async function validateWorkDir(workDir, allowedWorkDirs = []) {
|
|
|
267
284
|
}
|
|
268
285
|
return realPath;
|
|
269
286
|
}
|
|
270
|
-
//# sourceMappingURL=validation.js.map
|
package/dist/ws-terminal.js
CHANGED
|
@@ -31,7 +31,8 @@ const sessionPolls = new Map();
|
|
|
31
31
|
/** Reset all internal state (for testing). */
|
|
32
32
|
export function _resetForTesting() {
|
|
33
33
|
for (const poll of sessionPolls.values()) {
|
|
34
|
-
|
|
34
|
+
if (poll.timer)
|
|
35
|
+
clearInterval(poll.timer);
|
|
35
36
|
}
|
|
36
37
|
sessionPolls.clear();
|
|
37
38
|
}
|
|
@@ -282,7 +283,8 @@ function evictSubscriber(sessionId, socket, sub) {
|
|
|
282
283
|
poll.subscribers.delete(socket);
|
|
283
284
|
// If no more subscribers, clean up the poll timer
|
|
284
285
|
if (poll.subscribers.size === 0) {
|
|
285
|
-
|
|
286
|
+
if (poll.timer)
|
|
287
|
+
clearInterval(poll.timer);
|
|
286
288
|
sessionPolls.delete(sessionId);
|
|
287
289
|
}
|
|
288
290
|
}
|
|
@@ -300,4 +302,3 @@ function send(ws, msg) {
|
|
|
300
302
|
function sendError(ws, message) {
|
|
301
303
|
send(ws, { type: 'error', message });
|
|
302
304
|
}
|
|
303
|
-
//# sourceMappingURL=ws-terminal.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aegis-bridge",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Orchestrate Claude Code sessions via API. Create, brief, monitor, refine, ship.",
|
|
6
6
|
"main": "dist/server.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "tsc && npm run build:copy-dashboard",
|
|
28
28
|
"build:copy-dashboard": "node scripts/copy-dashboard.mjs",
|
|
29
|
-
"build:dashboard": "cd dashboard && npm
|
|
29
|
+
"build:dashboard": "cd dashboard && npm ci && npm run build",
|
|
30
30
|
"start": "node dist/cli.js",
|
|
31
31
|
"dev": "tsc && node dist/cli.js",
|
|
32
32
|
"prepublishOnly": "npm run build:dashboard && npm run build",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"node": ">=20.0.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@types/node": "^
|
|
66
|
+
"@types/node": "^20.0.0",
|
|
67
67
|
"@types/ws": "^8.18.1",
|
|
68
68
|
"typescript": "^6.0.2",
|
|
69
69
|
"vitest": "^4.1.2"
|