aegis-bridge 2.3.11 → 2.4.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.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * error-categories.ts — Structured error categorization and retry guidance.
3
+ *
4
+ * Issue #701: Provides an ErrorCode enum, categorize() function to inspect
5
+ * unknown errors and return structured metadata, and shouldRetry() helper.
6
+ */
7
+ /** String enum of Aegis error codes. */
8
+ export declare enum ErrorCode {
9
+ /** Session not found, already deleted, or in wrong state. */
10
+ SESSION_NOT_FOUND = "SESSION_NOT_FOUND",
11
+ /** Session creation failed (tmux window, CC launch). */
12
+ SESSION_CREATE_FAILED = "SESSION_CREATE_FAILED",
13
+ /** Permission request was rejected by the user. */
14
+ PERMISSION_REJECTED = "PERMISSION_REJECTED",
15
+ /** Tmux command timed out. */
16
+ TMUX_TIMEOUT = "TMUX_TIMEOUT",
17
+ /** Tmux operation failed (non-timeout). */
18
+ TMUX_ERROR = "TMUX_ERROR",
19
+ /** Request body or parameter failed validation. */
20
+ VALIDATION_ERROR = "VALIDATION_ERROR",
21
+ /** Authentication failed (missing/invalid token). */
22
+ AUTH_ERROR = "AUTH_ERROR",
23
+ /** Rate limit exceeded. */
24
+ RATE_LIMITED = "RATE_LIMITED",
25
+ /** Network or I/O error (transient). */
26
+ NETWORK_ERROR = "NETWORK_ERROR",
27
+ /** Unexpected internal error. */
28
+ INTERNAL_ERROR = "INTERNAL_ERROR"
29
+ }
30
+ /** Structured result returned by categorize(). */
31
+ export interface CategorizedError {
32
+ code: ErrorCode;
33
+ message: string;
34
+ retryable: boolean;
35
+ }
36
+ /** Inspect an unknown error and return a structured categorization. */
37
+ export declare function categorize(error: unknown): CategorizedError;
38
+ /** Return true if the error is worth retrying. */
39
+ export declare function shouldRetry(error: unknown): boolean;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * error-categories.ts — Structured error categorization and retry guidance.
3
+ *
4
+ * Issue #701: Provides an ErrorCode enum, categorize() function to inspect
5
+ * unknown errors and return structured metadata, and shouldRetry() helper.
6
+ */
7
+ import { TmuxTimeoutError } from './tmux.js';
8
+ /** String enum of Aegis error codes. */
9
+ export var ErrorCode;
10
+ (function (ErrorCode) {
11
+ /** Session not found, already deleted, or in wrong state. */
12
+ ErrorCode["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
13
+ /** Session creation failed (tmux window, CC launch). */
14
+ ErrorCode["SESSION_CREATE_FAILED"] = "SESSION_CREATE_FAILED";
15
+ /** Permission request was rejected by the user. */
16
+ ErrorCode["PERMISSION_REJECTED"] = "PERMISSION_REJECTED";
17
+ /** Tmux command timed out. */
18
+ ErrorCode["TMUX_TIMEOUT"] = "TMUX_TIMEOUT";
19
+ /** Tmux operation failed (non-timeout). */
20
+ ErrorCode["TMUX_ERROR"] = "TMUX_ERROR";
21
+ /** Request body or parameter failed validation. */
22
+ ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
23
+ /** Authentication failed (missing/invalid token). */
24
+ ErrorCode["AUTH_ERROR"] = "AUTH_ERROR";
25
+ /** Rate limit exceeded. */
26
+ ErrorCode["RATE_LIMITED"] = "RATE_LIMITED";
27
+ /** Network or I/O error (transient). */
28
+ ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
29
+ /** Unexpected internal error. */
30
+ ErrorCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
31
+ })(ErrorCode || (ErrorCode = {}));
32
+ /** Inspect an unknown error and return a structured categorization. */
33
+ export function categorize(error) {
34
+ // 1. Known typed errors
35
+ if (error instanceof TmuxTimeoutError) {
36
+ return { code: ErrorCode.TMUX_TIMEOUT, message: error.message, retryable: true };
37
+ }
38
+ if (error instanceof Error) {
39
+ const msg = error.message;
40
+ const lower = msg.toLowerCase();
41
+ // 2. Message-based heuristics for common Aegis error patterns
42
+ if (lower.includes('session not found') || lower.includes('no session with id')) {
43
+ return { code: ErrorCode.SESSION_NOT_FOUND, message: msg, retryable: false };
44
+ }
45
+ if (lower.includes('permission denied') || lower.includes('permission rejected')) {
46
+ return { code: ErrorCode.PERMISSION_REJECTED, message: msg, retryable: false };
47
+ }
48
+ if (lower.includes('unauthorized') || lower.includes('invalid token') || lower.includes('authentication')) {
49
+ return { code: ErrorCode.AUTH_ERROR, message: msg, retryable: false };
50
+ }
51
+ if (lower.includes('rate limit') || lower.includes('too many requests')) {
52
+ return { code: ErrorCode.RATE_LIMITED, message: msg, retryable: true };
53
+ }
54
+ if (lower.includes('validation') || lower.includes('invalid ') || lower.includes('required')) {
55
+ return { code: ErrorCode.VALIDATION_ERROR, message: msg, retryable: false };
56
+ }
57
+ if (lower.includes('econnrefused') || lower.includes('econnreset') || lower.includes('etimedout') || lower.includes('fetch failed')) {
58
+ return { code: ErrorCode.NETWORK_ERROR, message: msg, retryable: true };
59
+ }
60
+ if (lower.includes('tmux')) {
61
+ return { code: ErrorCode.TMUX_ERROR, message: msg, retryable: true };
62
+ }
63
+ // 3. Generic Error fallback
64
+ return { code: ErrorCode.INTERNAL_ERROR, message: msg, retryable: false };
65
+ }
66
+ // 4. Non-Error values
67
+ const msg = typeof error === 'string' ? error : String(error);
68
+ return { code: ErrorCode.INTERNAL_ERROR, message: msg, retryable: false };
69
+ }
70
+ /** Return true if the error is worth retrying. */
71
+ export function shouldRetry(error) {
72
+ return categorize(error).retryable;
73
+ }
74
+ //# sourceMappingURL=error-categories.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * tmux-capture-cache.ts — TTL-based cache for capture-pane results.
3
+ *
4
+ * Avoids redundant tmux capture-pane CLI calls when the same window
5
+ * is polled multiple times within a short window (e.g. monitor poll +
6
+ * status check hitting the same pane).
7
+ */
8
+ export declare class TmuxCaptureCache {
9
+ private cache;
10
+ private readonly ttlMs;
11
+ constructor(ttlMs?: number);
12
+ /** Return cached capture-pane text if within TTL, otherwise call `captureFn` and cache. */
13
+ get(windowId: string, captureFn: () => Promise<string>): Promise<string>;
14
+ /** Invalidate a single window's cached result. */
15
+ invalidate(windowId: string): void;
16
+ /** Clear all cached entries. */
17
+ clear(): void;
18
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * tmux-capture-cache.ts — TTL-based cache for capture-pane results.
3
+ *
4
+ * Avoids redundant tmux capture-pane CLI calls when the same window
5
+ * is polled multiple times within a short window (e.g. monitor poll +
6
+ * status check hitting the same pane).
7
+ */
8
+ const DEFAULT_TTL_MS = 500;
9
+ export class TmuxCaptureCache {
10
+ cache = new Map();
11
+ ttlMs;
12
+ constructor(ttlMs = DEFAULT_TTL_MS) {
13
+ this.ttlMs = ttlMs;
14
+ }
15
+ /** Return cached capture-pane text if within TTL, otherwise call `captureFn` and cache. */
16
+ async get(windowId, captureFn) {
17
+ const now = Date.now();
18
+ const entry = this.cache.get(windowId);
19
+ if (entry && now - entry.at < this.ttlMs) {
20
+ return entry.text;
21
+ }
22
+ const text = await captureFn();
23
+ this.cache.set(windowId, { text, at: now });
24
+ return text;
25
+ }
26
+ /** Invalidate a single window's cached result. */
27
+ invalidate(windowId) {
28
+ this.cache.delete(windowId);
29
+ }
30
+ /** Clear all cached entries. */
31
+ clear() {
32
+ this.cache.clear();
33
+ }
34
+ }
35
+ //# sourceMappingURL=tmux-capture-cache.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aegis-bridge",
3
- "version": "2.3.11",
3
+ "version": "2.4.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",