aegis-bridge 2.2.2
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/LICENSE +21 -0
- package/README.md +244 -0
- package/dashboard/dist/assets/index-CijFoeRu.css +32 -0
- package/dashboard/dist/assets/index-QtT4j0ht.js +262 -0
- package/dashboard/dist/index.html +14 -0
- package/dist/auth.d.ts +76 -0
- package/dist/auth.js +219 -0
- package/dist/channels/index.d.ts +8 -0
- package/dist/channels/index.js +9 -0
- package/dist/channels/manager.d.ts +39 -0
- package/dist/channels/manager.js +101 -0
- package/dist/channels/telegram-style.d.ts +118 -0
- package/dist/channels/telegram-style.js +203 -0
- package/dist/channels/telegram.d.ts +76 -0
- package/dist/channels/telegram.js +1396 -0
- package/dist/channels/types.d.ts +77 -0
- package/dist/channels/types.js +9 -0
- package/dist/channels/webhook.d.ts +58 -0
- package/dist/channels/webhook.js +162 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +223 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.js +188 -0
- package/dist/dashboard/assets/index-CijFoeRu.css +32 -0
- package/dist/dashboard/assets/index-QtT4j0ht.js +262 -0
- package/dist/dashboard/index.html +14 -0
- package/dist/events.d.ts +86 -0
- package/dist/events.js +258 -0
- package/dist/hook-settings.d.ts +67 -0
- package/dist/hook-settings.js +138 -0
- package/dist/hook.d.ts +18 -0
- package/dist/hook.js +199 -0
- package/dist/hooks.d.ts +32 -0
- package/dist/hooks.js +279 -0
- package/dist/jsonl-watcher.d.ts +57 -0
- package/dist/jsonl-watcher.js +159 -0
- package/dist/mcp-server.d.ts +60 -0
- package/dist/mcp-server.js +788 -0
- package/dist/metrics.d.ts +104 -0
- package/dist/metrics.js +226 -0
- package/dist/monitor.d.ts +84 -0
- package/dist/monitor.js +553 -0
- package/dist/permission-guard.d.ts +51 -0
- package/dist/permission-guard.js +197 -0
- package/dist/pipeline.d.ts +84 -0
- package/dist/pipeline.js +218 -0
- package/dist/screenshot.d.ts +26 -0
- package/dist/screenshot.js +57 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +1577 -0
- package/dist/session.d.ts +297 -0
- package/dist/session.js +1275 -0
- package/dist/sse-limiter.d.ts +47 -0
- package/dist/sse-limiter.js +62 -0
- package/dist/sse-writer.d.ts +31 -0
- package/dist/sse-writer.js +95 -0
- package/dist/ssrf.d.ts +57 -0
- package/dist/ssrf.js +169 -0
- package/dist/swarm-monitor.d.ts +114 -0
- package/dist/swarm-monitor.js +267 -0
- package/dist/terminal-parser.d.ts +16 -0
- package/dist/terminal-parser.js +343 -0
- package/dist/tmux.d.ts +161 -0
- package/dist/tmux.js +725 -0
- package/dist/transcript.d.ts +47 -0
- package/dist/transcript.js +244 -0
- package/dist/validation.d.ts +222 -0
- package/dist/validation.js +268 -0
- package/dist/ws-terminal.d.ts +32 -0
- package/dist/ws-terminal.js +297 -0
- package/package.json +71 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jsonl-watcher.ts — fs.watch()-based JSONL file watcher.
|
|
3
|
+
*
|
|
4
|
+
* Replaces polling-based JSONL reading in the monitor with near-instant
|
|
5
|
+
* file change detection. Uses fs.watch() with debouncing to avoid
|
|
6
|
+
* duplicate events from rapid writes.
|
|
7
|
+
*
|
|
8
|
+
* Issue #84: Replace JSONL polling with fs.watch.
|
|
9
|
+
*/
|
|
10
|
+
import { watch } from 'node:fs';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { readNewEntries } from './transcript.js';
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
debounceMs: 100,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Watches JSONL files for changes and emits parsed entries.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* const watcher = new JsonlWatcher();
|
|
21
|
+
* watcher.onEntries((event) => { ... });
|
|
22
|
+
* watcher.watch('session-123', '/path/to/session.jsonl', 0);
|
|
23
|
+
* watcher.unwatch('session-123');
|
|
24
|
+
* watcher.destroy();
|
|
25
|
+
*/
|
|
26
|
+
export class JsonlWatcher {
|
|
27
|
+
entries = new Map();
|
|
28
|
+
listeners = new Array();
|
|
29
|
+
config;
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
32
|
+
}
|
|
33
|
+
/** Register a callback for new entries. */
|
|
34
|
+
onEntries(listener) {
|
|
35
|
+
this.listeners.push(listener);
|
|
36
|
+
return () => {
|
|
37
|
+
const idx = this.listeners.indexOf(listener);
|
|
38
|
+
if (idx >= 0)
|
|
39
|
+
this.listeners.splice(idx, 1);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Start watching a JSONL file for a session.
|
|
43
|
+
* @param initialOffset - byte offset to start reading from (usually 0 or current session.monitorOffset).
|
|
44
|
+
*/
|
|
45
|
+
watch(sessionId, jsonlPath, initialOffset) {
|
|
46
|
+
// Don't double-watch
|
|
47
|
+
if (this.entries.has(sessionId)) {
|
|
48
|
+
this.unwatch(sessionId);
|
|
49
|
+
}
|
|
50
|
+
if (!existsSync(jsonlPath))
|
|
51
|
+
return;
|
|
52
|
+
const fsWatcher = watch(jsonlPath, (eventType) => {
|
|
53
|
+
// 'rename' can mean file was deleted or replaced — check if it still exists
|
|
54
|
+
if (eventType === 'rename') {
|
|
55
|
+
if (!existsSync(jsonlPath)) {
|
|
56
|
+
// File deleted — session likely ended, stop watching
|
|
57
|
+
this.unwatch(sessionId);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// File was replaced (e.g. rotated) — re-read from current offset
|
|
61
|
+
this.scheduleRead(sessionId);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// 'change' — new data written
|
|
65
|
+
this.scheduleRead(sessionId);
|
|
66
|
+
});
|
|
67
|
+
fsWatcher.on('error', (err) => {
|
|
68
|
+
console.error(`JsonlWatcher: error watching ${jsonlPath}:`, err.message);
|
|
69
|
+
// Stop watching on persistent errors
|
|
70
|
+
this.unwatch(sessionId);
|
|
71
|
+
});
|
|
72
|
+
this.entries.set(sessionId, {
|
|
73
|
+
sessionId,
|
|
74
|
+
jsonlPath,
|
|
75
|
+
fsWatcher,
|
|
76
|
+
debounceTimer: null,
|
|
77
|
+
offset: initialOffset,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Stop watching a session's JSONL file. */
|
|
81
|
+
unwatch(sessionId) {
|
|
82
|
+
const entry = this.entries.get(sessionId);
|
|
83
|
+
if (!entry)
|
|
84
|
+
return;
|
|
85
|
+
if (entry.debounceTimer) {
|
|
86
|
+
clearTimeout(entry.debounceTimer);
|
|
87
|
+
}
|
|
88
|
+
entry.fsWatcher.close();
|
|
89
|
+
this.entries.delete(sessionId);
|
|
90
|
+
}
|
|
91
|
+
/** Update the offset for a session (e.g. after manual read during discovery). */
|
|
92
|
+
setOffset(sessionId, offset) {
|
|
93
|
+
const entry = this.entries.get(sessionId);
|
|
94
|
+
if (entry) {
|
|
95
|
+
entry.offset = offset;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Check if a session is being watched. */
|
|
99
|
+
isWatching(sessionId) {
|
|
100
|
+
return this.entries.has(sessionId);
|
|
101
|
+
}
|
|
102
|
+
/** Get the current offset for a watched session. */
|
|
103
|
+
getOffset(sessionId) {
|
|
104
|
+
return this.entries.get(sessionId)?.offset;
|
|
105
|
+
}
|
|
106
|
+
/** Stop all watchers and clean up. */
|
|
107
|
+
destroy() {
|
|
108
|
+
for (const sessionId of this.entries.keys()) {
|
|
109
|
+
this.unwatch(sessionId);
|
|
110
|
+
}
|
|
111
|
+
this.listeners.length = 0;
|
|
112
|
+
}
|
|
113
|
+
/** Schedule a debounced read for a session. */
|
|
114
|
+
scheduleRead(sessionId) {
|
|
115
|
+
const entry = this.entries.get(sessionId);
|
|
116
|
+
if (!entry)
|
|
117
|
+
return;
|
|
118
|
+
if (entry.debounceTimer) {
|
|
119
|
+
clearTimeout(entry.debounceTimer);
|
|
120
|
+
}
|
|
121
|
+
entry.debounceTimer = setTimeout(() => {
|
|
122
|
+
entry.debounceTimer = null;
|
|
123
|
+
void this.readAndEmit(entry);
|
|
124
|
+
}, this.config.debounceMs);
|
|
125
|
+
}
|
|
126
|
+
/** Read new bytes from the JSONL file and emit entries. */
|
|
127
|
+
async readAndEmit(entry) {
|
|
128
|
+
// Session may have been removed during debounce
|
|
129
|
+
if (!this.entries.has(entry.sessionId))
|
|
130
|
+
return;
|
|
131
|
+
if (!existsSync(entry.jsonlPath)) {
|
|
132
|
+
this.unwatch(entry.sessionId);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const previousOffset = entry.offset;
|
|
137
|
+
const result = await readNewEntries(entry.jsonlPath, previousOffset);
|
|
138
|
+
entry.offset = result.newOffset;
|
|
139
|
+
if (result.entries.length > 0 || result.newOffset < previousOffset) {
|
|
140
|
+
// Detect truncation: newOffset went backwards
|
|
141
|
+
const truncated = result.newOffset < previousOffset;
|
|
142
|
+
// Emit to all listeners
|
|
143
|
+
const event = {
|
|
144
|
+
sessionId: entry.sessionId,
|
|
145
|
+
messages: result.entries,
|
|
146
|
+
newOffset: result.newOffset,
|
|
147
|
+
truncated,
|
|
148
|
+
};
|
|
149
|
+
for (const listener of this.listeners) {
|
|
150
|
+
listener(event);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// File may be temporarily unavailable — ignore
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=jsonl-watcher.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-server.ts — MCP server mode for Aegis.
|
|
3
|
+
*
|
|
4
|
+
* Exposes Aegis session orchestration as MCP tools via stdio transport.
|
|
5
|
+
* CC sessions can natively discover and communicate with sibling sessions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* aegis-bridge mcp # default port 9100
|
|
9
|
+
* aegis-bridge mcp --port 3000 # custom port
|
|
10
|
+
* claude mcp add --scope user aegis -- npx aegis-bridge mcp
|
|
11
|
+
*
|
|
12
|
+
* Issue #48: https://github.com/OneStepAt4time/aegis/issues/48
|
|
13
|
+
*/
|
|
14
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
15
|
+
export declare class AegisClient {
|
|
16
|
+
private baseUrl;
|
|
17
|
+
private authToken?;
|
|
18
|
+
constructor(baseUrl: string, authToken?: string | undefined);
|
|
19
|
+
private validateSessionId;
|
|
20
|
+
private request;
|
|
21
|
+
listSessions(filter?: {
|
|
22
|
+
status?: string;
|
|
23
|
+
workDir?: string;
|
|
24
|
+
}): Promise<any[]>;
|
|
25
|
+
getSession(id: string): Promise<any>;
|
|
26
|
+
getHealth(id: string): Promise<any>;
|
|
27
|
+
getTranscript(id: string): Promise<any>;
|
|
28
|
+
sendMessage(id: string, text: string): Promise<any>;
|
|
29
|
+
createSession(opts: {
|
|
30
|
+
workDir: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
prompt?: string;
|
|
33
|
+
}): Promise<any>;
|
|
34
|
+
killSession(id: string): Promise<any>;
|
|
35
|
+
approvePermission(id: string): Promise<any>;
|
|
36
|
+
rejectPermission(id: string): Promise<any>;
|
|
37
|
+
getServerHealth(): Promise<any>;
|
|
38
|
+
escapeSession(id: string): Promise<any>;
|
|
39
|
+
interruptSession(id: string): Promise<any>;
|
|
40
|
+
capturePane(id: string): Promise<any>;
|
|
41
|
+
getSessionMetrics(id: string): Promise<any>;
|
|
42
|
+
getSessionSummary(id: string): Promise<any>;
|
|
43
|
+
sendBash(id: string, command: string): Promise<any>;
|
|
44
|
+
sendCommand(id: string, command: string): Promise<any>;
|
|
45
|
+
getSessionLatency(id: string): Promise<any>;
|
|
46
|
+
batchCreateSessions(sessions: Array<{
|
|
47
|
+
workDir: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
prompt?: string;
|
|
50
|
+
}>): Promise<any>;
|
|
51
|
+
listPipelines(): Promise<any>;
|
|
52
|
+
createPipeline(config: {
|
|
53
|
+
name: string;
|
|
54
|
+
workDir: string;
|
|
55
|
+
steps: any[];
|
|
56
|
+
}): Promise<any>;
|
|
57
|
+
getSwarm(): Promise<any>;
|
|
58
|
+
}
|
|
59
|
+
export declare function createMcpServer(aegisPort: number, authToken?: string): McpServer;
|
|
60
|
+
export declare function startMcpServer(port: number, authToken?: string): Promise<void>;
|