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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +244 -0
  3. package/dashboard/dist/assets/index-CijFoeRu.css +32 -0
  4. package/dashboard/dist/assets/index-QtT4j0ht.js +262 -0
  5. package/dashboard/dist/index.html +14 -0
  6. package/dist/auth.d.ts +76 -0
  7. package/dist/auth.js +219 -0
  8. package/dist/channels/index.d.ts +8 -0
  9. package/dist/channels/index.js +9 -0
  10. package/dist/channels/manager.d.ts +39 -0
  11. package/dist/channels/manager.js +101 -0
  12. package/dist/channels/telegram-style.d.ts +118 -0
  13. package/dist/channels/telegram-style.js +203 -0
  14. package/dist/channels/telegram.d.ts +76 -0
  15. package/dist/channels/telegram.js +1396 -0
  16. package/dist/channels/types.d.ts +77 -0
  17. package/dist/channels/types.js +9 -0
  18. package/dist/channels/webhook.d.ts +58 -0
  19. package/dist/channels/webhook.js +162 -0
  20. package/dist/cli.d.ts +8 -0
  21. package/dist/cli.js +223 -0
  22. package/dist/config.d.ts +60 -0
  23. package/dist/config.js +188 -0
  24. package/dist/dashboard/assets/index-CijFoeRu.css +32 -0
  25. package/dist/dashboard/assets/index-QtT4j0ht.js +262 -0
  26. package/dist/dashboard/index.html +14 -0
  27. package/dist/events.d.ts +86 -0
  28. package/dist/events.js +258 -0
  29. package/dist/hook-settings.d.ts +67 -0
  30. package/dist/hook-settings.js +138 -0
  31. package/dist/hook.d.ts +18 -0
  32. package/dist/hook.js +199 -0
  33. package/dist/hooks.d.ts +32 -0
  34. package/dist/hooks.js +279 -0
  35. package/dist/jsonl-watcher.d.ts +57 -0
  36. package/dist/jsonl-watcher.js +159 -0
  37. package/dist/mcp-server.d.ts +60 -0
  38. package/dist/mcp-server.js +788 -0
  39. package/dist/metrics.d.ts +104 -0
  40. package/dist/metrics.js +226 -0
  41. package/dist/monitor.d.ts +84 -0
  42. package/dist/monitor.js +553 -0
  43. package/dist/permission-guard.d.ts +51 -0
  44. package/dist/permission-guard.js +197 -0
  45. package/dist/pipeline.d.ts +84 -0
  46. package/dist/pipeline.js +218 -0
  47. package/dist/screenshot.d.ts +26 -0
  48. package/dist/screenshot.js +57 -0
  49. package/dist/server.d.ts +10 -0
  50. package/dist/server.js +1577 -0
  51. package/dist/session.d.ts +297 -0
  52. package/dist/session.js +1275 -0
  53. package/dist/sse-limiter.d.ts +47 -0
  54. package/dist/sse-limiter.js +62 -0
  55. package/dist/sse-writer.d.ts +31 -0
  56. package/dist/sse-writer.js +95 -0
  57. package/dist/ssrf.d.ts +57 -0
  58. package/dist/ssrf.js +169 -0
  59. package/dist/swarm-monitor.d.ts +114 -0
  60. package/dist/swarm-monitor.js +267 -0
  61. package/dist/terminal-parser.d.ts +16 -0
  62. package/dist/terminal-parser.js +343 -0
  63. package/dist/tmux.d.ts +161 -0
  64. package/dist/tmux.js +725 -0
  65. package/dist/transcript.d.ts +47 -0
  66. package/dist/transcript.js +244 -0
  67. package/dist/validation.d.ts +222 -0
  68. package/dist/validation.js +268 -0
  69. package/dist/ws-terminal.d.ts +32 -0
  70. package/dist/ws-terminal.js +297 -0
  71. package/package.json +71 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * transcript.ts — JSONL transcript parser for Claude Code sessions.
3
+ *
4
+ * Port of CCBot's transcript_parser.py.
5
+ * Reads CC session JSONL files and extracts structured messages.
6
+ */
7
+ export interface ParsedEntry {
8
+ role: 'user' | 'assistant' | 'system';
9
+ contentType: 'text' | 'thinking' | 'tool_use' | 'tool_result' | 'tool_error' | 'permission_request' | 'progress';
10
+ text: string;
11
+ toolName?: string;
12
+ toolUseId?: string;
13
+ timestamp?: string;
14
+ }
15
+ interface ContentBlock {
16
+ type: string;
17
+ text?: string;
18
+ thinking?: string;
19
+ name?: string;
20
+ id?: string;
21
+ tool_use_id?: string;
22
+ input?: Record<string, unknown>;
23
+ content?: unknown;
24
+ is_error?: boolean;
25
+ }
26
+ interface JsonlEntry {
27
+ type: string;
28
+ message?: {
29
+ role: string;
30
+ content: string | ContentBlock[];
31
+ stop_reason?: string;
32
+ };
33
+ timestamp?: string;
34
+ tool_use_id?: string;
35
+ data?: Record<string, unknown>;
36
+ }
37
+ /** Parse entries from JSONL data. */
38
+ export declare function parseEntries(entries: JsonlEntry[]): ParsedEntry[];
39
+ /** Read JSONL file from byte offset, return new entries + new offset. */
40
+ export declare function readNewEntries(filePath: string, fromOffset: number): Promise<{
41
+ entries: ParsedEntry[];
42
+ newOffset: number;
43
+ raw: JsonlEntry[];
44
+ }>;
45
+ /** Find the JSONL file for a session ID. */
46
+ export declare function findSessionFile(sessionId: string, claudeProjectsDir?: string): Promise<string | null>;
47
+ export {};
@@ -0,0 +1,244 @@
1
+ /**
2
+ * transcript.ts — JSONL transcript parser for Claude Code sessions.
3
+ *
4
+ * Port of CCBot's transcript_parser.py.
5
+ * Reads CC session JSONL files and extracts structured messages.
6
+ */
7
+ import { stat, readFile, open } from 'node:fs/promises';
8
+ import { createReadStream, existsSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ import { homedir } from 'node:os';
11
+ import { readdir } from 'node:fs/promises';
12
+ import { sessionsIndexSchema } from './validation.js';
13
+ /** Default Claude projects directory */
14
+ const DEFAULT_CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');
15
+ /** Parse a single JSONL line. Returns null if not parseable. */
16
+ function parseLine(line) {
17
+ const trimmed = line.trim();
18
+ if (!trimmed || trimmed[0] !== '{')
19
+ return null;
20
+ try {
21
+ return JSON.parse(trimmed);
22
+ }
23
+ catch { /* malformed JSON — skip line */
24
+ return null;
25
+ }
26
+ }
27
+ /** Summarize a tool_use block. */
28
+ function summarizeTool(name, input) {
29
+ switch (name) {
30
+ case 'Read':
31
+ case 'ReadNotebook':
32
+ return `📖 **Read** ${input.file_path || input.path || ''}`;
33
+ case 'Write':
34
+ case 'MultiWrite':
35
+ return `✏️ **Write** ${input.file_path || input.path || ''}`;
36
+ case 'Edit':
37
+ return `🔧 **Edit** ${input.file_path || input.path || ''}`;
38
+ case 'Bash':
39
+ case 'Terminal':
40
+ return `💻 **Bash** \`${String(input.command || input.cmd || '').slice(0, 80)}\``;
41
+ case 'Grep':
42
+ case 'Search':
43
+ return `🔍 **Search** \`${input.pattern || input.query || ''}\``;
44
+ case 'Glob':
45
+ case 'ListFiles':
46
+ return `📁 **Glob** \`${input.pattern || input.path || ''}\``;
47
+ case 'AskUserQuestion':
48
+ return `❓ **Question**: ${input.question || ''}`;
49
+ case 'TodoWrite':
50
+ return `📝 **Todo** updated`;
51
+ default:
52
+ return `🔧 **${name}**`;
53
+ }
54
+ }
55
+ /** Parse entries from JSONL data. */
56
+ export function parseEntries(entries) {
57
+ const results = [];
58
+ const pendingTools = new Map(); // tool_use_id -> summary
59
+ for (const entry of entries) {
60
+ if (entry.type === 'progress') {
61
+ const text = entry.data ? JSON.stringify(entry.data) : '';
62
+ if (text.trim()) {
63
+ results.push({ role: 'system', contentType: 'progress', text, timestamp: entry.timestamp });
64
+ }
65
+ continue;
66
+ }
67
+ if (!entry.message)
68
+ continue;
69
+ const role = entry.message.role;
70
+ const content = entry.message.content;
71
+ const timestamp = entry.timestamp;
72
+ if (typeof content === 'string') {
73
+ // Simple text message
74
+ if (content.trim()) {
75
+ results.push({ role, contentType: 'text', text: content.trim(), timestamp });
76
+ }
77
+ continue;
78
+ }
79
+ if (!Array.isArray(content))
80
+ continue;
81
+ for (const block of content) {
82
+ switch (block.type) {
83
+ case 'text':
84
+ if (block.text?.trim()) {
85
+ results.push({ role, contentType: 'text', text: block.text.trim(), timestamp });
86
+ }
87
+ break;
88
+ case 'thinking':
89
+ if (block.thinking?.trim()) {
90
+ results.push({ role, contentType: 'thinking', text: block.thinking.trim(), timestamp });
91
+ }
92
+ break;
93
+ case 'tool_use': {
94
+ const name = block.name || 'unknown';
95
+ const input = (block.input || {});
96
+ const summary = summarizeTool(name, input);
97
+ if (block.id) {
98
+ pendingTools.set(block.id, summary);
99
+ }
100
+ results.push({
101
+ role: 'assistant',
102
+ contentType: 'tool_use',
103
+ text: summary,
104
+ toolName: name,
105
+ toolUseId: block.id,
106
+ timestamp,
107
+ });
108
+ break;
109
+ }
110
+ case 'tool_result': {
111
+ const toolId = block.tool_use_id || '';
112
+ let resultText = '';
113
+ if (typeof block.content === 'string') {
114
+ resultText = block.content;
115
+ }
116
+ else if (Array.isArray(block.content)) {
117
+ resultText = block.content
118
+ .filter(c => c.type === 'text')
119
+ .map(c => c.text || '')
120
+ .join('\n');
121
+ }
122
+ // Truncate long results
123
+ if (resultText.length > 500) {
124
+ resultText = resultText.slice(0, 500) + '... (truncated)';
125
+ }
126
+ if (resultText.trim()) {
127
+ results.push({
128
+ role: 'assistant',
129
+ contentType: block.is_error ? 'tool_error' : 'tool_result',
130
+ text: resultText.trim(),
131
+ toolUseId: toolId,
132
+ timestamp,
133
+ });
134
+ }
135
+ pendingTools.delete(toolId);
136
+ break;
137
+ }
138
+ case 'permission_request': {
139
+ const permText = block.text || JSON.stringify(block);
140
+ if (permText.trim()) {
141
+ results.push({
142
+ role: 'user',
143
+ contentType: 'permission_request',
144
+ text: permText.trim(),
145
+ timestamp,
146
+ });
147
+ }
148
+ break;
149
+ }
150
+ }
151
+ }
152
+ }
153
+ return results;
154
+ }
155
+ /** Read JSONL file from byte offset, return new entries + new offset. */
156
+ export async function readNewEntries(filePath, fromOffset) {
157
+ const fileStat = await stat(filePath);
158
+ // File truncated (e.g. after /clear)
159
+ if (fromOffset > fileStat.size) {
160
+ return { entries: [], newOffset: 0, raw: [] };
161
+ }
162
+ if (fromOffset >= fileStat.size) {
163
+ return { entries: [], newOffset: fromOffset, raw: [] };
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);
178
+ }
179
+ finally {
180
+ await fd.close();
181
+ }
182
+ for (let i = scanBuf.length - 1; i >= 0; i--) {
183
+ if (scanBuf[i] === 0x0a) { // '\n'
184
+ effectiveOffset = scanStart + i + 1;
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ const slicedContent = await new Promise((resolve, reject) => {
190
+ const chunks = [];
191
+ const stream = createReadStream(filePath, { start: effectiveOffset });
192
+ stream.on('data', (chunk) => chunks.push(chunk));
193
+ stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
194
+ stream.on('error', reject);
195
+ });
196
+ const lines = slicedContent.split('\n');
197
+ const rawEntries = [];
198
+ for (const line of lines) {
199
+ const entry = parseLine(line);
200
+ if (entry) {
201
+ rawEntries.push(entry);
202
+ }
203
+ }
204
+ const parsed = parseEntries(rawEntries);
205
+ return { entries: parsed, newOffset: fileStat.size, raw: rawEntries };
206
+ }
207
+ /** Find the JSONL file for a session ID. */
208
+ export async function findSessionFile(sessionId, claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR) {
209
+ const projectsDir = claudeProjectsDir;
210
+ if (!existsSync(projectsDir))
211
+ return null;
212
+ // Strategy 1: Direct glob across all project dirs
213
+ const dirs = await readdir(projectsDir, { withFileTypes: true });
214
+ for (const dir of dirs) {
215
+ if (!dir.isDirectory())
216
+ continue;
217
+ const jsonlPath = join(projectsDir, dir.name, `${sessionId}.jsonl`);
218
+ if (existsSync(jsonlPath))
219
+ return jsonlPath;
220
+ }
221
+ // Strategy 2: Check sessions-index.json files
222
+ for (const dir of dirs) {
223
+ if (!dir.isDirectory())
224
+ continue;
225
+ const indexPath = join(projectsDir, dir.name, 'sessions-index.json');
226
+ if (existsSync(indexPath)) {
227
+ try {
228
+ const indexRaw = await readFile(indexPath, 'utf-8');
229
+ const indexParsed = sessionsIndexSchema.safeParse(JSON.parse(indexRaw));
230
+ if (!indexParsed.success)
231
+ continue;
232
+ const entries = indexParsed.data.entries || [];
233
+ for (const entry of entries) {
234
+ if (entry.sessionId === sessionId && entry.fullPath && existsSync(entry.fullPath)) {
235
+ return entry.fullPath;
236
+ }
237
+ }
238
+ }
239
+ catch { /* skip bad index */ }
240
+ }
241
+ }
242
+ return null;
243
+ }
244
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1,222 @@
1
+ /**
2
+ * validation.ts — Zod schemas for API request body validation.
3
+ *
4
+ * Issue #359: Centralized validation for all POST route bodies.
5
+ * Issue #435: Path traversal defense in validateWorkDir.
6
+ */
7
+ import { z } from 'zod';
8
+ /** Regex for UUID v4 format: 8-4-4-4-12 hex digits */
9
+ export declare const UUID_REGEX: RegExp;
10
+ /** POST /v1/auth/keys */
11
+ export declare const authKeySchema: z.ZodObject<{
12
+ name: z.ZodString;
13
+ rateLimit: z.ZodOptional<z.ZodNumber>;
14
+ }, z.core.$strict>;
15
+ /** POST /v1/sessions/:id/send */
16
+ export declare const sendMessageSchema: z.ZodObject<{
17
+ text: z.ZodString;
18
+ }, z.core.$strict>;
19
+ /** POST /v1/sessions/:id/command */
20
+ export declare const commandSchema: z.ZodObject<{
21
+ command: z.ZodString;
22
+ }, z.core.$strict>;
23
+ /** POST /v1/sessions/:id/bash */
24
+ export declare const bashSchema: z.ZodObject<{
25
+ command: z.ZodString;
26
+ }, z.core.$strict>;
27
+ /** POST /v1/sessions/:id/screenshot */
28
+ export declare const screenshotSchema: z.ZodObject<{
29
+ url: z.ZodString;
30
+ fullPage: z.ZodOptional<z.ZodBoolean>;
31
+ width: z.ZodOptional<z.ZodNumber>;
32
+ height: z.ZodOptional<z.ZodNumber>;
33
+ }, z.core.$strict>;
34
+ /** Webhook endpoint — validates structure of each webhook entry */
35
+ export declare const webhookEndpointSchema: z.ZodObject<{
36
+ url: z.ZodString;
37
+ events: z.ZodOptional<z.ZodArray<z.ZodString>>;
38
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
39
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
40
+ }, z.core.$strict>;
41
+ /** POST /v1/sessions/:id/hooks/permission */
42
+ export declare const permissionHookSchema: z.ZodObject<{
43
+ session_id: z.ZodOptional<z.ZodString>;
44
+ tool_name: z.ZodOptional<z.ZodString>;
45
+ tool_input: z.ZodOptional<z.ZodUnknown>;
46
+ permission_mode: z.ZodOptional<z.ZodString>;
47
+ hook_event_name: z.ZodOptional<z.ZodString>;
48
+ }, z.core.$strict>;
49
+ /** POST /v1/sessions/:id/hooks/stop */
50
+ export declare const stopHookSchema: z.ZodObject<{
51
+ session_id: z.ZodOptional<z.ZodString>;
52
+ stop_reason: z.ZodOptional<z.ZodString>;
53
+ hook_event_name: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strict>;
55
+ /** POST /v1/sessions/batch — max 50 sessions per batch */
56
+ export declare const batchSessionSchema: z.ZodObject<{
57
+ sessions: z.ZodArray<z.ZodObject<{
58
+ name: z.ZodOptional<z.ZodString>;
59
+ workDir: z.ZodString;
60
+ prompt: z.ZodOptional<z.ZodString>;
61
+ permissionMode: z.ZodOptional<z.ZodEnum<{
62
+ default: "default";
63
+ bypassPermissions: "bypassPermissions";
64
+ plan: "plan";
65
+ }>>;
66
+ autoApprove: z.ZodOptional<z.ZodBoolean>;
67
+ stallThresholdMs: z.ZodOptional<z.ZodNumber>;
68
+ }, z.core.$strip>>;
69
+ }, z.core.$strict>;
70
+ /** POST /v1/pipelines */
71
+ export declare const pipelineSchema: z.ZodObject<{
72
+ name: z.ZodString;
73
+ workDir: z.ZodString;
74
+ stages: z.ZodArray<z.ZodObject<{
75
+ name: z.ZodString;
76
+ workDir: z.ZodOptional<z.ZodString>;
77
+ prompt: z.ZodString;
78
+ dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
79
+ permissionMode: z.ZodOptional<z.ZodEnum<{
80
+ default: "default";
81
+ bypassPermissions: "bypassPermissions";
82
+ plan: "plan";
83
+ }>>;
84
+ autoApprove: z.ZodOptional<z.ZodBoolean>;
85
+ }, z.core.$strip>>;
86
+ }, z.core.$strict>;
87
+ /** Clamp a numeric value to [min, max]. Returns default if input is NaN. */
88
+ export declare function clamp(value: number, min: number, max: number, fallback: number): number;
89
+ /** Parse an env string to integer with NaN/isFinite guard. Returns fallback on failure. */
90
+ export declare function parseIntSafe(value: string | undefined, fallback: number): number;
91
+ /** Validate that a string looks like a UUID. */
92
+ export declare function isValidUUID(id: string): boolean;
93
+ /** Schema for persisted SessionState (sessions: { [id]: SessionInfo }). */
94
+ export declare const persistedStateSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
95
+ id: z.ZodString;
96
+ windowId: z.ZodString;
97
+ windowName: z.ZodString;
98
+ workDir: z.ZodString;
99
+ claudeSessionId: z.ZodOptional<z.ZodString>;
100
+ jsonlPath: z.ZodOptional<z.ZodString>;
101
+ byteOffset: z.ZodNumber;
102
+ monitorOffset: z.ZodNumber;
103
+ status: z.ZodEnum<{
104
+ unknown: "unknown";
105
+ idle: "idle";
106
+ working: "working";
107
+ permission_prompt: "permission_prompt";
108
+ bash_approval: "bash_approval";
109
+ plan_mode: "plan_mode";
110
+ ask_question: "ask_question";
111
+ settings: "settings";
112
+ }>;
113
+ createdAt: z.ZodNumber;
114
+ lastActivity: z.ZodNumber;
115
+ stallThresholdMs: z.ZodNumber;
116
+ permissionStallMs: z.ZodDefault<z.ZodNumber>;
117
+ permissionMode: z.ZodString;
118
+ settingsPatched: z.ZodOptional<z.ZodBoolean>;
119
+ hookSettingsFile: z.ZodOptional<z.ZodString>;
120
+ lastHookAt: z.ZodOptional<z.ZodNumber>;
121
+ activeSubagents: z.ZodOptional<z.ZodArray<z.ZodString>>;
122
+ permissionPromptAt: z.ZodOptional<z.ZodNumber>;
123
+ permissionRespondedAt: z.ZodOptional<z.ZodNumber>;
124
+ lastHookReceivedAt: z.ZodOptional<z.ZodNumber>;
125
+ lastHookEventAt: z.ZodOptional<z.ZodNumber>;
126
+ model: z.ZodOptional<z.ZodString>;
127
+ lastDeadAt: z.ZodOptional<z.ZodNumber>;
128
+ ccPid: z.ZodOptional<z.ZodNumber>;
129
+ }, z.core.$strip>>;
130
+ /** Schema for session_map.json entries. */
131
+ export declare const sessionMapSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
132
+ session_id: z.ZodString;
133
+ cwd: z.ZodString;
134
+ window_name: z.ZodString;
135
+ transcript_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
136
+ permission_mode: z.ZodOptional<z.ZodNullable<z.ZodString>>;
137
+ agent_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
138
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
139
+ agent_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
140
+ model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
141
+ written_at: z.ZodNumber;
142
+ }, z.core.$strip>>;
143
+ /** Schema for stop_signals.json entries. */
144
+ export declare const stopSignalsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
145
+ event: z.ZodOptional<z.ZodString>;
146
+ timestamp: z.ZodOptional<z.ZodNumber>;
147
+ error: z.ZodOptional<z.ZodUnknown>;
148
+ error_details: z.ZodOptional<z.ZodUnknown>;
149
+ last_assistant_message: z.ZodOptional<z.ZodUnknown>;
150
+ agent_id: z.ZodOptional<z.ZodUnknown>;
151
+ stop_reason: z.ZodOptional<z.ZodString>;
152
+ }, z.core.$strip>>;
153
+ /** Schema for persisted auth keys store (Issue #506). */
154
+ export declare const authStoreSchema: z.ZodObject<{
155
+ keys: z.ZodArray<z.ZodObject<{
156
+ id: z.ZodString;
157
+ name: z.ZodString;
158
+ hash: z.ZodString;
159
+ createdAt: z.ZodNumber;
160
+ lastUsedAt: z.ZodNumber;
161
+ rateLimit: z.ZodNumber;
162
+ }, z.core.$strip>>;
163
+ }, z.core.$strip>;
164
+ /** Schema for sessions-index.json entries (Issue #506). */
165
+ export declare const sessionsIndexSchema: z.ZodObject<{
166
+ entries: z.ZodOptional<z.ZodArray<z.ZodObject<{
167
+ sessionId: z.ZodString;
168
+ fullPath: z.ZodString;
169
+ }, z.core.$strip>>>;
170
+ }, z.core.$strip>;
171
+ /** Schema for persisted metrics file (Issue #506). */
172
+ export declare const metricsFileSchema: z.ZodObject<{
173
+ global: z.ZodOptional<z.ZodObject<{
174
+ sessionsCreated: z.ZodOptional<z.ZodNumber>;
175
+ sessionsCompleted: z.ZodOptional<z.ZodNumber>;
176
+ sessionsFailed: z.ZodOptional<z.ZodNumber>;
177
+ totalMessages: z.ZodOptional<z.ZodNumber>;
178
+ totalToolCalls: z.ZodOptional<z.ZodNumber>;
179
+ autoApprovals: z.ZodOptional<z.ZodNumber>;
180
+ webhooksSent: z.ZodOptional<z.ZodNumber>;
181
+ webhooksFailed: z.ZodOptional<z.ZodNumber>;
182
+ screenshotsTaken: z.ZodOptional<z.ZodNumber>;
183
+ pipelinesCreated: z.ZodOptional<z.ZodNumber>;
184
+ batchesCreated: z.ZodOptional<z.ZodNumber>;
185
+ promptsSent: z.ZodOptional<z.ZodNumber>;
186
+ promptsDelivered: z.ZodOptional<z.ZodNumber>;
187
+ promptsFailed: z.ZodOptional<z.ZodNumber>;
188
+ }, z.core.$loose>>;
189
+ savedAt: z.ZodOptional<z.ZodNumber>;
190
+ }, z.core.$loose>;
191
+ /** Schema for WebSocket inbound messages (Issue #506). */
192
+ export declare const wsInboundMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
193
+ type: z.ZodLiteral<"input">;
194
+ text: z.ZodString;
195
+ }, z.core.$strict>, z.ZodObject<{
196
+ type: z.ZodLiteral<"resize">;
197
+ cols: z.ZodOptional<z.ZodNumber>;
198
+ rows: z.ZodOptional<z.ZodNumber>;
199
+ }, z.core.$strict>, z.ZodObject<{
200
+ type: z.ZodLiteral<"auth">;
201
+ token: z.ZodOptional<z.ZodString>;
202
+ }, z.core.$strict>], "type">;
203
+ /** Schema for CC settings.json shape (Issue #506).
204
+ * Permissive — only validates the fields Aegis cares about. */
205
+ export declare const ccSettingsSchema: z.ZodObject<{
206
+ permissions: z.ZodOptional<z.ZodObject<{
207
+ defaultMode: z.ZodOptional<z.ZodString>;
208
+ }, z.core.$loose>>;
209
+ }, z.core.$loose>;
210
+ /** Helper: extract error message from unknown catch value. */
211
+ export declare function getErrorMessage(e: unknown): string;
212
+ /** Validate workDir to prevent path traversal attacks (Issue #435).
213
+ * 1. Reject raw strings containing ".." before any normalization.
214
+ * 2. Resolve to absolute path and resolve symlinks via fs.realpath().
215
+ * 3. Verify the resolved path is under an allowed directory:
216
+ * - If allowedWorkDirs is configured, use that list.
217
+ * - Otherwise, use default safe dirs (home, /tmp, cwd).
218
+ * Returns the resolved real path on success, or an error object on failure. */
219
+ export declare function validateWorkDir(workDir: string, allowedWorkDirs?: readonly string[]): Promise<string | {
220
+ error: string;
221
+ code: string;
222
+ }>;