aegis-bridge 2.10.0 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hook-settings.js
CHANGED
|
@@ -23,7 +23,8 @@ function isRecord(value) {
|
|
|
23
23
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
24
24
|
}
|
|
25
25
|
function parseSettingsWithFallback(raw) {
|
|
26
|
-
|
|
26
|
+
// Windows editors may write UTF-8 BOM; strip it so JSON.parse does not fail.
|
|
27
|
+
const json = JSON.parse(raw.replace(/^\uFEFF/, ''));
|
|
27
28
|
if (!isRecord(json))
|
|
28
29
|
return undefined;
|
|
29
30
|
const parsed = ccSettingsSchema.safeParse(json);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type PermissionDecision = 'allow' | 'deny';
|
|
2
|
+
export declare class PermissionRequestManager {
|
|
3
|
+
private pendingPermissions;
|
|
4
|
+
waitForPermissionDecision(sessionId: string, timeoutMs?: number, toolName?: string, prompt?: string): Promise<PermissionDecision>;
|
|
5
|
+
hasPendingPermission(sessionId: string): boolean;
|
|
6
|
+
getPendingPermissionInfo(sessionId: string): {
|
|
7
|
+
toolName?: string;
|
|
8
|
+
prompt?: string;
|
|
9
|
+
} | null;
|
|
10
|
+
resolvePendingPermission(sessionId: string, decision: PermissionDecision): boolean;
|
|
11
|
+
cleanupPendingPermission(sessionId: string): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class PermissionRequestManager {
|
|
2
|
+
pendingPermissions = new Map();
|
|
3
|
+
waitForPermissionDecision(sessionId, timeoutMs = 10_000, toolName, prompt) {
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
const timer = setTimeout(() => {
|
|
6
|
+
this.pendingPermissions.delete(sessionId);
|
|
7
|
+
console.log(`Hooks: PermissionRequest timeout for session ${sessionId} - auto-rejecting`);
|
|
8
|
+
resolve('deny');
|
|
9
|
+
}, timeoutMs);
|
|
10
|
+
this.pendingPermissions.set(sessionId, { resolve, timer, toolName, prompt });
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
hasPendingPermission(sessionId) {
|
|
14
|
+
return this.pendingPermissions.has(sessionId);
|
|
15
|
+
}
|
|
16
|
+
getPendingPermissionInfo(sessionId) {
|
|
17
|
+
const pending = this.pendingPermissions.get(sessionId);
|
|
18
|
+
return pending ? { toolName: pending.toolName, prompt: pending.prompt } : null;
|
|
19
|
+
}
|
|
20
|
+
resolvePendingPermission(sessionId, decision) {
|
|
21
|
+
const pending = this.pendingPermissions.get(sessionId);
|
|
22
|
+
if (!pending)
|
|
23
|
+
return false;
|
|
24
|
+
clearTimeout(pending.timer);
|
|
25
|
+
this.pendingPermissions.delete(sessionId);
|
|
26
|
+
pending.resolve(decision);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
cleanupPendingPermission(sessionId) {
|
|
30
|
+
const pending = this.pendingPermissions.get(sessionId);
|
|
31
|
+
if (pending) {
|
|
32
|
+
clearTimeout(pending.timer);
|
|
33
|
+
this.pendingPermissions.delete(sessionId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
package/dist/session.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { type ParsedEntry } from './transcript.js';
|
|
|
9
9
|
import { type UIState } from './terminal-parser.js';
|
|
10
10
|
import type { Config } from './config.js';
|
|
11
11
|
import { type PermissionPolicy } from './validation.js';
|
|
12
|
+
import { type PermissionDecision } from './permission-request-manager.js';
|
|
12
13
|
export interface SessionInfo {
|
|
13
14
|
id: string;
|
|
14
15
|
windowId: string;
|
|
@@ -53,7 +54,7 @@ export interface SessionState {
|
|
|
53
54
|
*/
|
|
54
55
|
export declare function detectApprovalMethod(paneText: string): 'numbered' | 'yes';
|
|
55
56
|
/** Resolves a pending PermissionRequest hook with a decision. */
|
|
56
|
-
export type PermissionDecision
|
|
57
|
+
export type { PermissionDecision };
|
|
57
58
|
export declare class SessionManager {
|
|
58
59
|
private tmux;
|
|
59
60
|
private config;
|
|
@@ -66,7 +67,7 @@ export declare class SessionManager {
|
|
|
66
67
|
private saveQueue;
|
|
67
68
|
private saveDebounceTimer;
|
|
68
69
|
private static readonly SAVE_DEBOUNCE_MS;
|
|
69
|
-
private
|
|
70
|
+
private permissionRequests;
|
|
70
71
|
private pendingQuestions;
|
|
71
72
|
private static readonly MAX_CACHE_ENTRIES_PER_SESSION;
|
|
72
73
|
private parsedEntriesCache;
|
|
@@ -247,10 +248,6 @@ export declare class SessionManager {
|
|
|
247
248
|
toolName?: string;
|
|
248
249
|
prompt?: string;
|
|
249
250
|
} | null;
|
|
250
|
-
/**
|
|
251
|
-
* Resolve a pending permission. Returns true if there was a pending permission to resolve.
|
|
252
|
-
*/
|
|
253
|
-
private resolvePendingPermission;
|
|
254
251
|
/** Clean up any pending permission for a session (e.g. on session delete). */
|
|
255
252
|
cleanupPendingPermission(sessionId: string): void;
|
|
256
253
|
/**
|
package/dist/session.js
CHANGED
|
@@ -17,6 +17,7 @@ import { neutralizeBypassPermissions, restoreSettings, cleanOrphanedBackup } fro
|
|
|
17
17
|
import { persistedStateSchema } from './validation.js';
|
|
18
18
|
import { loadContinuationPointers } from './continuation-pointer.js';
|
|
19
19
|
import { writeHookSettingsFile, cleanupHookSettingsFile, cleanupStaleSessionHooks } from './hook-settings.js';
|
|
20
|
+
import { PermissionRequestManager } from './permission-request-manager.js';
|
|
20
21
|
import { Mutex } from 'async-mutex';
|
|
21
22
|
import { maybeInjectFault } from './fault-injection.js';
|
|
22
23
|
/** Convert parsed JSON arrays to Sets for activeSubagents (#668). */
|
|
@@ -61,7 +62,7 @@ export class SessionManager {
|
|
|
61
62
|
saveQueue = Promise.resolve(); // #218: serialize concurrent saves
|
|
62
63
|
saveDebounceTimer = null;
|
|
63
64
|
static SAVE_DEBOUNCE_MS = 5_000; // #357: debounce offset-only saves
|
|
64
|
-
|
|
65
|
+
permissionRequests = new PermissionRequestManager();
|
|
65
66
|
pendingQuestions = new Map();
|
|
66
67
|
// #357: Cache of all parsed JSONL entries per session to avoid re-reading from offset 0
|
|
67
68
|
// #424: Evict oldest entries when cache exceeds max to prevent unbounded growth
|
|
@@ -961,7 +962,7 @@ export class SessionManager {
|
|
|
961
962
|
if (!session)
|
|
962
963
|
throw new Error(`Session ${id} not found`);
|
|
963
964
|
// Issue #284: Resolve pending hook-based permission first
|
|
964
|
-
if (this.resolvePendingPermission(id, 'allow')) {
|
|
965
|
+
if (this.permissionRequests.resolvePendingPermission(id, 'allow')) {
|
|
965
966
|
session.lastActivity = Date.now();
|
|
966
967
|
if (session.permissionPromptAt) {
|
|
967
968
|
session.permissionRespondedAt = Date.now();
|
|
@@ -983,7 +984,7 @@ export class SessionManager {
|
|
|
983
984
|
if (!session)
|
|
984
985
|
throw new Error(`Session ${id} not found`);
|
|
985
986
|
// Issue #284: Resolve pending hook-based permission first
|
|
986
|
-
if (this.resolvePendingPermission(id, 'deny')) {
|
|
987
|
+
if (this.permissionRequests.resolvePendingPermission(id, 'deny')) {
|
|
987
988
|
session.lastActivity = Date.now();
|
|
988
989
|
if (session.permissionPromptAt) {
|
|
989
990
|
session.permissionRespondedAt = Date.now();
|
|
@@ -1008,43 +1009,19 @@ export class SessionManager {
|
|
|
1008
1009
|
* @returns Promise that resolves with the client's decision
|
|
1009
1010
|
*/
|
|
1010
1011
|
waitForPermissionDecision(sessionId, timeoutMs = 10_000, toolName, prompt) {
|
|
1011
|
-
return
|
|
1012
|
-
const timer = setTimeout(() => {
|
|
1013
|
-
this.pendingPermissions.delete(sessionId);
|
|
1014
|
-
console.log(`Hooks: PermissionRequest timeout for session ${sessionId} — auto-rejecting`);
|
|
1015
|
-
resolve('deny');
|
|
1016
|
-
}, timeoutMs);
|
|
1017
|
-
this.pendingPermissions.set(sessionId, { resolve, timer, toolName, prompt });
|
|
1018
|
-
});
|
|
1012
|
+
return this.permissionRequests.waitForPermissionDecision(sessionId, timeoutMs, toolName, prompt);
|
|
1019
1013
|
}
|
|
1020
1014
|
/** Check if a session has a pending permission request. */
|
|
1021
1015
|
hasPendingPermission(sessionId) {
|
|
1022
|
-
return this.
|
|
1016
|
+
return this.permissionRequests.hasPendingPermission(sessionId);
|
|
1023
1017
|
}
|
|
1024
1018
|
/** Get info about a pending permission (for API responses). */
|
|
1025
1019
|
getPendingPermissionInfo(sessionId) {
|
|
1026
|
-
|
|
1027
|
-
return pending ? { toolName: pending.toolName, prompt: pending.prompt } : null;
|
|
1028
|
-
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Resolve a pending permission. Returns true if there was a pending permission to resolve.
|
|
1031
|
-
*/
|
|
1032
|
-
resolvePendingPermission(sessionId, decision) {
|
|
1033
|
-
const pending = this.pendingPermissions.get(sessionId);
|
|
1034
|
-
if (!pending)
|
|
1035
|
-
return false;
|
|
1036
|
-
clearTimeout(pending.timer);
|
|
1037
|
-
this.pendingPermissions.delete(sessionId);
|
|
1038
|
-
pending.resolve(decision);
|
|
1039
|
-
return true;
|
|
1020
|
+
return this.permissionRequests.getPendingPermissionInfo(sessionId);
|
|
1040
1021
|
}
|
|
1041
1022
|
/** Clean up any pending permission for a session (e.g. on session delete). */
|
|
1042
1023
|
cleanupPendingPermission(sessionId) {
|
|
1043
|
-
|
|
1044
|
-
if (pending) {
|
|
1045
|
-
clearTimeout(pending.timer);
|
|
1046
|
-
this.pendingPermissions.delete(sessionId);
|
|
1047
|
-
}
|
|
1024
|
+
this.permissionRequests.cleanupPendingPermission(sessionId);
|
|
1048
1025
|
}
|
|
1049
1026
|
/**
|
|
1050
1027
|
* Issue #336: Store a pending AskUserQuestion and return a promise that
|