agent-relay 1.2.3 → 1.3.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.
Files changed (189) hide show
  1. package/.trajectories/agent-relay-322-324.md +17 -0
  2. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +49 -0
  3. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +31 -0
  4. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +125 -0
  5. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +62 -0
  6. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +49 -0
  7. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +31 -0
  8. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +77 -0
  9. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +42 -0
  10. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +77 -0
  11. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +42 -0
  12. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +77 -0
  13. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +42 -0
  14. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +66 -0
  15. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +36 -0
  16. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +40 -0
  17. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +22 -0
  18. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +121 -0
  19. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +29 -0
  20. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +53 -0
  21. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +32 -0
  22. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +101 -0
  23. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +52 -0
  24. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +49 -0
  25. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +31 -0
  26. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +65 -0
  27. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +37 -0
  28. package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +49 -0
  29. package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +31 -0
  30. package/.trajectories/completed/2026-01/traj_multi_server_arch.md +101 -0
  31. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +27 -0
  32. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +14 -0
  33. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +53 -0
  34. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +32 -0
  35. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +186 -0
  36. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +86 -0
  37. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +77 -0
  38. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +42 -0
  39. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +89 -0
  40. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +47 -0
  41. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +65 -0
  42. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +37 -0
  43. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +49 -0
  44. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +31 -0
  45. package/.trajectories/consolidate-settings-panel.md +24 -0
  46. package/.trajectories/gh-cli-user-token.md +26 -0
  47. package/.trajectories/index.json +155 -1
  48. package/deploy/workspace/codex.config.toml +15 -0
  49. package/deploy/workspace/entrypoint.sh +167 -7
  50. package/deploy/workspace/git-credential-relay +17 -2
  51. package/dist/bridge/spawner.d.ts +7 -0
  52. package/dist/bridge/spawner.js +40 -9
  53. package/dist/bridge/types.d.ts +2 -0
  54. package/dist/cli/index.js +210 -168
  55. package/dist/cloud/api/admin.d.ts +8 -0
  56. package/dist/cloud/api/admin.js +212 -0
  57. package/dist/cloud/api/auth.js +8 -0
  58. package/dist/cloud/api/billing.d.ts +0 -10
  59. package/dist/cloud/api/billing.js +248 -58
  60. package/dist/cloud/api/codex-auth-helper.d.ts +10 -4
  61. package/dist/cloud/api/codex-auth-helper.js +215 -8
  62. package/dist/cloud/api/coordinators.js +402 -0
  63. package/dist/cloud/api/daemons.js +15 -11
  64. package/dist/cloud/api/git.js +104 -17
  65. package/dist/cloud/api/github-app.js +42 -8
  66. package/dist/cloud/api/nango-auth.js +297 -16
  67. package/dist/cloud/api/onboarding.js +97 -33
  68. package/dist/cloud/api/providers.js +12 -16
  69. package/dist/cloud/api/repos.js +200 -124
  70. package/dist/cloud/api/test-helpers.js +40 -0
  71. package/dist/cloud/api/usage.js +13 -0
  72. package/dist/cloud/api/webhooks.js +1 -1
  73. package/dist/cloud/api/workspaces.d.ts +18 -0
  74. package/dist/cloud/api/workspaces.js +945 -15
  75. package/dist/cloud/config.d.ts +8 -0
  76. package/dist/cloud/config.js +15 -0
  77. package/dist/cloud/db/drizzle.d.ts +5 -2
  78. package/dist/cloud/db/drizzle.js +27 -20
  79. package/dist/cloud/db/schema.d.ts +19 -51
  80. package/dist/cloud/db/schema.js +5 -4
  81. package/dist/cloud/index.d.ts +0 -1
  82. package/dist/cloud/index.js +0 -1
  83. package/dist/cloud/provisioner/index.d.ts +93 -1
  84. package/dist/cloud/provisioner/index.js +608 -63
  85. package/dist/cloud/server.js +156 -16
  86. package/dist/cloud/services/compute-enforcement.d.ts +57 -0
  87. package/dist/cloud/services/compute-enforcement.js +175 -0
  88. package/dist/cloud/services/index.d.ts +2 -0
  89. package/dist/cloud/services/index.js +4 -0
  90. package/dist/cloud/services/intro-expiration.d.ts +55 -0
  91. package/dist/cloud/services/intro-expiration.js +211 -0
  92. package/dist/cloud/services/nango.d.ts +14 -0
  93. package/dist/cloud/services/nango.js +74 -14
  94. package/dist/cloud/services/ssh-security.d.ts +31 -0
  95. package/dist/cloud/services/ssh-security.js +63 -0
  96. package/dist/continuity/manager.d.ts +5 -0
  97. package/dist/continuity/manager.js +56 -2
  98. package/dist/daemon/api.d.ts +2 -0
  99. package/dist/daemon/api.js +214 -5
  100. package/dist/daemon/cli-auth.d.ts +13 -1
  101. package/dist/daemon/cli-auth.js +166 -47
  102. package/dist/daemon/connection.d.ts +7 -1
  103. package/dist/daemon/connection.js +15 -0
  104. package/dist/daemon/orchestrator.d.ts +2 -0
  105. package/dist/daemon/orchestrator.js +26 -0
  106. package/dist/daemon/repo-manager.d.ts +116 -0
  107. package/dist/daemon/repo-manager.js +384 -0
  108. package/dist/daemon/router.d.ts +60 -1
  109. package/dist/daemon/router.js +281 -20
  110. package/dist/daemon/user-directory.d.ts +111 -0
  111. package/dist/daemon/user-directory.js +233 -0
  112. package/dist/dashboard/out/404.html +1 -1
  113. package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
  114. package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +1 -0
  115. package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +1 -0
  116. package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +1 -0
  117. package/dist/dashboard/out/_next/static/chunks/899-fc02ed79e3de4302.js +1 -0
  118. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/{page-3fdfa60e53f2810d.js → page-8553743baca53a00.js} +1 -1
  119. package/dist/dashboard/out/_next/static/chunks/app/app/page-c617745b81344f4f.js +1 -0
  120. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-f829604fb75a831a.js +1 -0
  121. package/dist/dashboard/out/_next/static/chunks/app/{page-77e9c65420a06cfb.js → page-dc786c183425c2ac.js} +1 -1
  122. package/dist/dashboard/out/_next/static/chunks/app/providers/page-84322991d7244499.js +1 -0
  123. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-05606941a8e2be83.js +1 -0
  124. package/dist/dashboard/out/_next/static/chunks/{main-ed4e1fb6f29c34cf.js → main-2ee6beb2ae96d210.js} +1 -1
  125. package/dist/dashboard/out/_next/static/css/48a8fbe3e659080e.css +1 -0
  126. package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +1 -0
  127. package/dist/dashboard/out/_next/static/sDcbGRTYLcpPvyTs_rsNb/_ssgManifest.js +1 -0
  128. package/dist/dashboard/out/app/onboarding.html +1 -1
  129. package/dist/dashboard/out/app/onboarding.txt +3 -3
  130. package/dist/dashboard/out/app.html +1 -1
  131. package/dist/dashboard/out/app.txt +3 -3
  132. package/dist/dashboard/out/apple-icon.png +0 -0
  133. package/dist/dashboard/out/connect-repos.html +1 -1
  134. package/dist/dashboard/out/connect-repos.txt +2 -2
  135. package/dist/dashboard/out/history.html +1 -1
  136. package/dist/dashboard/out/history.txt +2 -2
  137. package/dist/dashboard/out/index.html +1 -1
  138. package/dist/dashboard/out/index.txt +3 -3
  139. package/dist/dashboard/out/login.html +2 -2
  140. package/dist/dashboard/out/login.txt +2 -2
  141. package/dist/dashboard/out/metrics.html +1 -1
  142. package/dist/dashboard/out/metrics.txt +3 -3
  143. package/dist/dashboard/out/pricing.html +2 -2
  144. package/dist/dashboard/out/pricing.txt +3 -3
  145. package/dist/dashboard/out/providers/setup/claude.html +1 -0
  146. package/dist/dashboard/out/providers/setup/claude.txt +8 -0
  147. package/dist/dashboard/out/providers/setup/codex.html +1 -0
  148. package/dist/dashboard/out/providers/setup/codex.txt +8 -0
  149. package/dist/dashboard/out/providers.html +1 -1
  150. package/dist/dashboard/out/providers.txt +3 -3
  151. package/dist/dashboard/out/signup.html +2 -2
  152. package/dist/dashboard/out/signup.txt +2 -2
  153. package/dist/dashboard-server/server.js +316 -12
  154. package/dist/dashboard-server/user-bridge.d.ts +103 -0
  155. package/dist/dashboard-server/user-bridge.js +189 -0
  156. package/dist/protocol/channels.d.ts +205 -0
  157. package/dist/protocol/channels.js +154 -0
  158. package/dist/protocol/types.d.ts +13 -1
  159. package/dist/resiliency/provider-context.js +2 -0
  160. package/dist/shared/cli-auth-config.d.ts +19 -0
  161. package/dist/shared/cli-auth-config.js +58 -2
  162. package/dist/utils/agent-config.js +1 -1
  163. package/dist/wrapper/auth-detection.d.ts +49 -0
  164. package/dist/wrapper/auth-detection.js +192 -0
  165. package/dist/wrapper/base-wrapper.d.ts +153 -0
  166. package/dist/wrapper/base-wrapper.js +393 -0
  167. package/dist/wrapper/client.d.ts +7 -1
  168. package/dist/wrapper/client.js +3 -0
  169. package/dist/wrapper/index.d.ts +1 -0
  170. package/dist/wrapper/index.js +4 -3
  171. package/dist/wrapper/pty-wrapper.d.ts +62 -84
  172. package/dist/wrapper/pty-wrapper.js +154 -180
  173. package/dist/wrapper/tmux-wrapper.d.ts +41 -66
  174. package/dist/wrapper/tmux-wrapper.js +90 -134
  175. package/package.json +4 -2
  176. package/scripts/postinstall.js +11 -155
  177. package/scripts/test-interactive-terminal.sh +248 -0
  178. package/dist/cloud/vault/index.d.ts +0 -76
  179. package/dist/cloud/vault/index.js +0 -219
  180. package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +0 -1
  181. package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +0 -9
  182. package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +0 -1
  183. package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +0 -1
  184. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +0 -1
  185. package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +0 -1
  186. package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +0 -1
  187. package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +0 -1
  188. package/dist/dashboard/out/_next/static/wPgKJtcOmTFLpUncDg16A/_ssgManifest.js +0 -1
  189. /package/dist/dashboard/out/_next/static/{wPgKJtcOmTFLpUncDg16A → sDcbGRTYLcpPvyTs_rsNb}/_buildManifest.js +0 -0
@@ -18,6 +18,19 @@ export interface PromptHandler {
18
18
  /** Description for logging/debugging */
19
19
  description: string;
20
20
  }
21
+ /**
22
+ * Error pattern configuration for detecting auth failures
23
+ */
24
+ export interface ErrorPattern {
25
+ /** Pattern to detect in CLI output */
26
+ pattern: RegExp;
27
+ /** User-friendly error message */
28
+ message: string;
29
+ /** Whether this error is recoverable by retrying */
30
+ recoverable: boolean;
31
+ /** Optional hint for the user */
32
+ hint?: string;
33
+ }
21
34
  /**
22
35
  * CLI auth configuration for each provider
23
36
  */
@@ -38,6 +51,8 @@ export interface CLIAuthConfig {
38
51
  prompts: PromptHandler[];
39
52
  /** Success indicators in output */
40
53
  successPatterns: RegExp[];
54
+ /** Error patterns to detect auth failures */
55
+ errorPatterns?: ErrorPattern[];
41
56
  /** How long to wait for URL to appear (ms) */
42
57
  waitTimeout: number;
43
58
  /** Whether this provider supports device flow */
@@ -66,6 +81,10 @@ export declare function matchesSuccessPattern(text: string, patterns: RegExp[]):
66
81
  * Find matching prompt handler that hasn't been responded to yet
67
82
  */
68
83
  export declare function findMatchingPrompt(text: string, prompts: PromptHandler[], respondedPrompts: Set<string>): PromptHandler | null;
84
+ /**
85
+ * Check if text matches any error pattern and return the matched error
86
+ */
87
+ export declare function findMatchingError(text: string, errorPatterns?: ErrorPattern[]): ErrorPattern | null;
69
88
  /**
70
89
  * Get list of supported provider IDs
71
90
  */
@@ -72,6 +72,8 @@ export const CLI_AUTH_CONFIG = {
72
72
  {
73
73
  // Fallback: Any "press enter" or "enter to confirm/continue" prompt
74
74
  // Keep this LAST so more specific handlers match first
75
+ // NOTE: Error messages like "Press Enter to retry" are handled by checking
76
+ // error patterns FIRST in the PTY handler, so this won't trigger on errors
75
77
  pattern: /press\s*enter|enter\s*to\s*(confirm|continue|proceed)|hit\s*enter/i,
76
78
  response: '\r',
77
79
  delay: 300,
@@ -79,6 +81,38 @@ export const CLI_AUTH_CONFIG = {
79
81
  },
80
82
  ],
81
83
  successPatterns: [/success/i, /authenticated/i, /logged\s*in/i, /you.*(?:are|now).*logged/i],
84
+ errorPatterns: [
85
+ {
86
+ pattern: /oauth\s*error.*(?:status\s*code\s*)?400/i,
87
+ message: 'Authentication failed - the authorization code was invalid or expired',
88
+ recoverable: true,
89
+ hint: 'This usually happens if the login took too long or the code was already used. Please try again and complete the browser login within a few minutes.',
90
+ },
91
+ {
92
+ pattern: /oauth\s*error.*(?:status\s*code\s*)?401/i,
93
+ message: 'Authentication failed - unauthorized',
94
+ recoverable: true,
95
+ hint: 'Please try logging in again.',
96
+ },
97
+ {
98
+ pattern: /oauth\s*error.*(?:status\s*code\s*)?403/i,
99
+ message: 'Authentication failed - access denied',
100
+ recoverable: true,
101
+ hint: 'Your account may not have access to Claude Code. Please check your Anthropic subscription.',
102
+ },
103
+ {
104
+ pattern: /network\s*error|ENOTFOUND|ECONNREFUSED|timeout/i,
105
+ message: 'Network error during authentication',
106
+ recoverable: true,
107
+ hint: 'Please check your internet connection and try again.',
108
+ },
109
+ {
110
+ pattern: /invalid\s*(?:code|token)|code\s*(?:expired|invalid)/i,
111
+ message: 'The authorization code was invalid or has expired',
112
+ recoverable: true,
113
+ hint: 'OAuth codes expire quickly. Please try again and complete the browser login promptly.',
114
+ },
115
+ ],
82
116
  },
83
117
  openai: {
84
118
  command: 'codex',
@@ -160,10 +194,18 @@ export const CLI_AUTH_CONFIG = {
160
194
  /**
161
195
  * Strip ANSI escape codes from text
162
196
  */
197
+ /* eslint-disable no-control-regex */
163
198
  export function stripAnsiCodes(text) {
164
- // eslint-disable-next-line no-control-regex
165
- return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
199
+ // Handle various ANSI escape sequences:
200
+ // - CSI sequences: ESC [ params letter (params can include ?, >, =, etc.)
201
+ // - OSC sequences: ESC ] ... BEL/ST
202
+ // - Simple escapes: ESC letter
203
+ return text
204
+ .replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '') // CSI sequences including private modes (?2026h, etc.)
205
+ .replace(/\x1b\][^\x07]*\x07/g, '') // OSC sequences (title, etc.)
206
+ .replace(/\x1b[a-zA-Z]/g, ''); // Simple escape sequences
166
207
  }
208
+ /* eslint-enable no-control-regex */
167
209
  /**
168
210
  * Check if text matches any success pattern
169
211
  */
@@ -185,6 +227,20 @@ export function findMatchingPrompt(text, prompts, respondedPrompts) {
185
227
  }
186
228
  return null;
187
229
  }
230
+ /**
231
+ * Check if text matches any error pattern and return the matched error
232
+ */
233
+ export function findMatchingError(text, errorPatterns) {
234
+ if (!errorPatterns || errorPatterns.length === 0)
235
+ return null;
236
+ const cleanText = stripAnsiCodes(text);
237
+ for (const error of errorPatterns) {
238
+ if (error.pattern.test(cleanText)) {
239
+ return error;
240
+ }
241
+ }
242
+ return null;
243
+ }
188
244
  /**
189
245
  * Get list of supported provider IDs
190
246
  */
@@ -102,7 +102,7 @@ export function isClaudeCli(command) {
102
102
  export function buildClaudeArgs(agentName, existingArgs = [], projectRoot) {
103
103
  const config = findAgentConfig(agentName, projectRoot);
104
104
  if (!config) {
105
- return existingArgs;
105
+ return [...existingArgs]; // Return a copy to avoid reference issues
106
106
  }
107
107
  const newArgs = [...existingArgs];
108
108
  // Add --model if specified in config and not already in args
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Auth Revocation Detection
3
+ *
4
+ * Detects when an AI CLI's authentication has been revoked.
5
+ * This can happen when:
6
+ * 1. User authenticates the same provider elsewhere (limited sessions)
7
+ * 2. Token expires or is invalidated
8
+ * 3. OAuth refresh fails
9
+ */
10
+ /**
11
+ * Patterns that indicate authentication has been revoked or expired.
12
+ * These are typically output by Claude CLI, Codex, etc. when auth fails.
13
+ */
14
+ export declare const AUTH_REVOCATION_PATTERNS: RegExp[];
15
+ /**
16
+ * Patterns that should NOT trigger auth revocation detection.
17
+ * These are false positives that might match auth patterns but aren't actual auth errors.
18
+ */
19
+ export declare const AUTH_FALSE_POSITIVE_PATTERNS: RegExp[];
20
+ export interface AuthRevocationResult {
21
+ detected: boolean;
22
+ pattern?: string;
23
+ confidence: 'high' | 'medium' | 'low';
24
+ message?: string;
25
+ }
26
+ /**
27
+ * Detect if output indicates authentication has been revoked.
28
+ *
29
+ * @param output - The CLI output to analyze
30
+ * @param recentOutputOnly - If true, only check the last ~500 chars (for real-time detection)
31
+ * @returns Detection result with confidence level
32
+ */
33
+ export declare function detectAuthRevocation(output: string, recentOutputOnly?: boolean): AuthRevocationResult;
34
+ /**
35
+ * Check if the given text looks like an auth-related CLI prompt
36
+ * that's waiting for user action (not an error, but a request to auth).
37
+ */
38
+ export declare function isAuthPrompt(text: string): boolean;
39
+ /**
40
+ * Provider-specific auth detection configuration.
41
+ * Different AI CLIs may have different error messages.
42
+ */
43
+ export declare const PROVIDER_AUTH_PATTERNS: Record<string, RegExp[]>;
44
+ /**
45
+ * Detect auth revocation for a specific provider.
46
+ * Uses provider-specific patterns in addition to general patterns.
47
+ */
48
+ export declare function detectProviderAuthRevocation(output: string, provider: string): AuthRevocationResult;
49
+ //# sourceMappingURL=auth-detection.d.ts.map
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Auth Revocation Detection
3
+ *
4
+ * Detects when an AI CLI's authentication has been revoked.
5
+ * This can happen when:
6
+ * 1. User authenticates the same provider elsewhere (limited sessions)
7
+ * 2. Token expires or is invalidated
8
+ * 3. OAuth refresh fails
9
+ */
10
+ /**
11
+ * Patterns that indicate authentication has been revoked or expired.
12
+ * These are typically output by Claude CLI, Codex, etc. when auth fails.
13
+ */
14
+ export const AUTH_REVOCATION_PATTERNS = [
15
+ // Session/token expiration
16
+ /session\s+(has\s+)?expired/i,
17
+ /token\s+(has\s+)?expired/i,
18
+ /credentials?\s+(have\s+)?expired/i,
19
+ // Login required
20
+ /please\s+log\s*in\s+again/i,
21
+ /login\s+required/i,
22
+ /authentication\s+required/i,
23
+ /must\s+(be\s+)?log(ged)?\s*in/i,
24
+ /you\s+need\s+to\s+log\s*in/i,
25
+ // Unauthorized
26
+ /\bunauthorized\b/i,
27
+ /not\s+authorized/i,
28
+ /access\s+denied/i,
29
+ // Invalid credentials
30
+ /invalid\s+credentials?/i,
31
+ /invalid\s+token/i,
32
+ /invalid\s+session/i,
33
+ /not\s+authenticated/i,
34
+ // OAuth specific
35
+ /oauth\s+error.*401/i,
36
+ /oauth\s+error.*403/i,
37
+ /refresh\s+token\s+(is\s+)?invalid/i,
38
+ /failed\s+to\s+refresh/i,
39
+ // API errors that indicate auth issues
40
+ /api\s+error.*401/i,
41
+ /api\s+error.*403/i,
42
+ /http\s+401/i,
43
+ /http\s+403/i,
44
+ // Claude-specific patterns
45
+ /your\s+api\s+key\s+is\s+invalid/i,
46
+ /api\s+key\s+not\s+found/i,
47
+ /signed\s+out/i,
48
+ /session\s+revoked/i,
49
+ ];
50
+ /**
51
+ * Patterns that should NOT trigger auth revocation detection.
52
+ * These are false positives that might match auth patterns but aren't actual auth errors.
53
+ */
54
+ export const AUTH_FALSE_POSITIVE_PATTERNS = [
55
+ // Documentation or help text
56
+ /how\s+to\s+log\s*in/i,
57
+ /login\s+instructions/i,
58
+ /authentication\s+guide/i,
59
+ // Code comments or strings
60
+ /\/\/.*unauthorized/i,
61
+ /\/\*.*unauthorized.*\*\//i,
62
+ /".*unauthorized.*"/i,
63
+ /'.*unauthorized.*'/i,
64
+ // Error handling code
65
+ /catch.*unauthorized/i,
66
+ /handle.*auth.*error/i,
67
+ /if.*session.*expired/i,
68
+ // Instructional content
69
+ /you\s+should\s+log\s*in/i,
70
+ /make\s+sure\s+you('re)?\s+logged\s*in/i,
71
+ ];
72
+ /**
73
+ * Detect if output indicates authentication has been revoked.
74
+ *
75
+ * @param output - The CLI output to analyze
76
+ * @param recentOutputOnly - If true, only check the last ~500 chars (for real-time detection)
77
+ * @returns Detection result with confidence level
78
+ */
79
+ export function detectAuthRevocation(output, recentOutputOnly = false) {
80
+ // If checking recent output only, truncate to last 500 chars
81
+ const textToCheck = recentOutputOnly ? output.slice(-500) : output;
82
+ // First check for false positives
83
+ for (const falsePositive of AUTH_FALSE_POSITIVE_PATTERNS) {
84
+ if (falsePositive.test(textToCheck)) {
85
+ return { detected: false, confidence: 'low' };
86
+ }
87
+ }
88
+ // Check each auth revocation pattern
89
+ for (const pattern of AUTH_REVOCATION_PATTERNS) {
90
+ const match = textToCheck.match(pattern);
91
+ if (match) {
92
+ // Determine confidence based on pattern specificity
93
+ const confidence = getConfidenceLevel(pattern, match[0]);
94
+ return {
95
+ detected: true,
96
+ pattern: pattern.source,
97
+ confidence,
98
+ message: match[0],
99
+ };
100
+ }
101
+ }
102
+ return { detected: false, confidence: 'low' };
103
+ }
104
+ /**
105
+ * Determine confidence level based on the matched pattern.
106
+ */
107
+ function getConfidenceLevel(pattern, matchedText) {
108
+ const patternStr = pattern.source.toLowerCase();
109
+ // High confidence: Explicit auth failure messages
110
+ if (patternStr.includes('session') && patternStr.includes('expired') ||
111
+ patternStr.includes('please') && patternStr.includes('log') ||
112
+ patternStr.includes('authentication required') ||
113
+ patternStr.includes('token') && patternStr.includes('expired') ||
114
+ patternStr.includes('signed out') ||
115
+ patternStr.includes('session revoked')) {
116
+ return 'high';
117
+ }
118
+ // Medium confidence: General auth errors
119
+ if (patternStr.includes('unauthorized') ||
120
+ patternStr.includes('401') ||
121
+ patternStr.includes('403') ||
122
+ patternStr.includes('invalid') && patternStr.includes('credentials')) {
123
+ return 'medium';
124
+ }
125
+ // Low confidence: Could be related to other errors
126
+ return 'low';
127
+ }
128
+ /**
129
+ * Check if the given text looks like an auth-related CLI prompt
130
+ * that's waiting for user action (not an error, but a request to auth).
131
+ */
132
+ export function isAuthPrompt(text) {
133
+ const authPromptPatterns = [
134
+ /open\s+this\s+url/i,
135
+ /visit\s+.*to\s+authorize/i,
136
+ /enter\s+your\s+api\s+key/i,
137
+ /paste\s+your\s+token/i,
138
+ /waiting\s+for\s+authorization/i,
139
+ /complete\s+login\s+in\s+browser/i,
140
+ ];
141
+ return authPromptPatterns.some(pattern => pattern.test(text));
142
+ }
143
+ /**
144
+ * Provider-specific auth detection configuration.
145
+ * Different AI CLIs may have different error messages.
146
+ */
147
+ export const PROVIDER_AUTH_PATTERNS = {
148
+ claude: [
149
+ /claude.*session.*expired/i,
150
+ /anthropic.*unauthorized/i,
151
+ /claude.*not\s+authenticated/i,
152
+ /please\s+run\s+claude\s+login/i,
153
+ ],
154
+ codex: [
155
+ /codex.*session.*expired/i,
156
+ /openai.*unauthorized/i,
157
+ /codex.*not\s+authenticated/i,
158
+ ],
159
+ gemini: [
160
+ /gemini.*session.*expired/i,
161
+ /google.*unauthorized/i,
162
+ /gemini.*not\s+authenticated/i,
163
+ ],
164
+ };
165
+ /**
166
+ * Detect auth revocation for a specific provider.
167
+ * Uses provider-specific patterns in addition to general patterns.
168
+ */
169
+ export function detectProviderAuthRevocation(output, provider) {
170
+ // First check general patterns
171
+ const generalResult = detectAuthRevocation(output, true);
172
+ if (generalResult.detected && generalResult.confidence === 'high') {
173
+ return generalResult;
174
+ }
175
+ // Check provider-specific patterns
176
+ const providerPatterns = PROVIDER_AUTH_PATTERNS[provider.toLowerCase()];
177
+ if (providerPatterns) {
178
+ for (const pattern of providerPatterns) {
179
+ const match = output.match(pattern);
180
+ if (match) {
181
+ return {
182
+ detected: true,
183
+ pattern: pattern.source,
184
+ confidence: 'high',
185
+ message: match[0],
186
+ };
187
+ }
188
+ }
189
+ }
190
+ return generalResult;
191
+ }
192
+ //# sourceMappingURL=auth-detection.js.map
@@ -0,0 +1,153 @@
1
+ /**
2
+ * BaseWrapper - Abstract base class for agent wrappers
3
+ *
4
+ * Provides shared functionality between TmuxWrapper and PtyWrapper:
5
+ * - Message queue management and deduplication
6
+ * - Spawn/release command parsing and execution
7
+ * - Continuity integration (agent ID, summary saving)
8
+ * - Relay command handling
9
+ * - Line joining for multi-line commands
10
+ *
11
+ * Subclasses implement:
12
+ * - start() - Initialize and start the agent process
13
+ * - stop() - Stop the agent process
14
+ * - performInjection() - Inject content into the agent
15
+ * - getCleanOutput() - Get cleaned output for parsing
16
+ */
17
+ import { EventEmitter } from 'node:events';
18
+ import { RelayClient } from './client.js';
19
+ import type { ParsedCommand, ParsedSummary } from './parser.js';
20
+ import type { SendPayload, SendMeta, SpeakOnTrigger } from '../protocol/types.js';
21
+ import { type QueuedMessage, type InjectionMetrics, type CliType } from './shared.js';
22
+ import { type ContinuityManager } from '../continuity/index.js';
23
+ /**
24
+ * Base configuration shared by all wrapper types
25
+ */
26
+ export interface BaseWrapperConfig {
27
+ /** Agent name (must be unique) */
28
+ name: string;
29
+ /** Command to execute */
30
+ command: string;
31
+ /** Command arguments */
32
+ args?: string[];
33
+ /** Relay daemon socket path */
34
+ socketPath?: string;
35
+ /** Working directory */
36
+ cwd?: string;
37
+ /** Environment variables */
38
+ env?: Record<string, string>;
39
+ /** Relay prefix pattern (default: '->relay:') */
40
+ relayPrefix?: string;
41
+ /** CLI type (auto-detected if not set) */
42
+ cliType?: CliType;
43
+ /** Dashboard port for spawn/release API */
44
+ dashboardPort?: number;
45
+ /** Callback when spawn command is parsed */
46
+ onSpawn?: (name: string, cli: string, task: string) => Promise<void>;
47
+ /** Callback when release command is parsed */
48
+ onRelease?: (name: string) => Promise<void>;
49
+ /** Agent ID to resume from (for continuity) */
50
+ resumeAgentId?: string;
51
+ /** Stream logs to daemon */
52
+ streamLogs?: boolean;
53
+ /** Task/role description */
54
+ task?: string;
55
+ /** Shadow configuration */
56
+ shadowOf?: string;
57
+ shadowSpeakOn?: SpeakOnTrigger[];
58
+ }
59
+ /**
60
+ * Abstract base class for agent wrappers
61
+ */
62
+ export declare abstract class BaseWrapper extends EventEmitter {
63
+ protected config: BaseWrapperConfig;
64
+ protected client: RelayClient;
65
+ protected relayPrefix: string;
66
+ protected cliType: CliType;
67
+ protected running: boolean;
68
+ protected messageQueue: QueuedMessage[];
69
+ protected sentMessageHashes: Set<string>;
70
+ protected isInjecting: boolean;
71
+ protected receivedMessageIds: Set<string>;
72
+ protected injectionMetrics: InjectionMetrics;
73
+ protected processedSpawnCommands: Set<string>;
74
+ protected processedReleaseCommands: Set<string>;
75
+ protected pendingFencedSpawn: {
76
+ name: string;
77
+ cli: string;
78
+ taskLines: string[];
79
+ } | null;
80
+ protected continuity?: ContinuityManager;
81
+ protected agentId?: string;
82
+ protected processedContinuityCommands: Set<string>;
83
+ protected sessionEndProcessed: boolean;
84
+ protected sessionEndData?: {
85
+ summary?: string;
86
+ completedTasks?: string[];
87
+ };
88
+ protected lastSummaryRawContent: string;
89
+ constructor(config: BaseWrapperConfig);
90
+ /** Start the agent process */
91
+ abstract start(): Promise<void>;
92
+ /** Stop the agent process */
93
+ abstract stop(): Promise<void> | void;
94
+ /** Inject content into the agent */
95
+ protected abstract performInjection(content: string): Promise<void>;
96
+ /** Get cleaned output for parsing */
97
+ protected abstract getCleanOutput(): string;
98
+ get isRunning(): boolean;
99
+ get name(): string;
100
+ getAgentId(): string | undefined;
101
+ getInjectionMetrics(): InjectionMetrics & {
102
+ successRate: number;
103
+ };
104
+ get pendingMessageCount(): number;
105
+ /**
106
+ * Handle incoming message from relay
107
+ */
108
+ protected handleIncomingMessage(from: string, payload: SendPayload, messageId: string, meta?: SendMeta, originalTo?: string): void;
109
+ /**
110
+ * Send a relay command via the client
111
+ */
112
+ protected sendRelayCommand(cmd: ParsedCommand): void;
113
+ /**
114
+ * Parse spawn and release commands from output
115
+ */
116
+ protected parseSpawnReleaseCommands(content: string): void;
117
+ /**
118
+ * Execute a spawn command
119
+ */
120
+ protected executeSpawn(name: string, cli: string, task: string): Promise<void>;
121
+ /**
122
+ * Execute a release command
123
+ */
124
+ protected executeRelease(name: string): Promise<void>;
125
+ /**
126
+ * Initialize agent ID for continuity/resume
127
+ */
128
+ protected initializeAgentId(): Promise<void>;
129
+ /**
130
+ * Parse continuity commands from output
131
+ */
132
+ protected parseContinuityCommands(content: string): Promise<void>;
133
+ /**
134
+ * Save a parsed summary to the continuity ledger
135
+ */
136
+ protected saveSummaryToLedger(summary: ParsedSummary): Promise<void>;
137
+ /**
138
+ * Reset session-specific state for wrapper reuse
139
+ */
140
+ resetSessionState(): void;
141
+ /**
142
+ * Join continuation lines for multi-line relay/continuity commands.
143
+ * TUIs like Claude Code insert real newlines in output, causing
144
+ * messages to span multiple lines. This joins indented
145
+ * continuation lines back to the command line.
146
+ */
147
+ protected joinContinuationLines(content: string): string;
148
+ /**
149
+ * Clean up resources
150
+ */
151
+ protected destroyClient(): void;
152
+ }
153
+ //# sourceMappingURL=base-wrapper.d.ts.map