agent-relay 1.3.1 → 1.3.3

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 (202) hide show
  1. package/.trajectories/active/traj_3yx9dy148mge.json +42 -0
  2. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.json +49 -0
  3. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.md +31 -0
  4. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.json +49 -0
  5. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.md +31 -0
  6. package/.trajectories/completed/2026-01/traj_6unwwmgyj5sq.json +109 -0
  7. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.json +49 -0
  8. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.md +31 -0
  9. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.json +66 -0
  10. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.md +36 -0
  11. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.json +49 -0
  12. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.md +31 -0
  13. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.json +65 -0
  14. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.md +37 -0
  15. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.json +36 -0
  16. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.md +21 -0
  17. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.json +101 -0
  18. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.md +52 -0
  19. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.json +61 -0
  20. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.md +36 -0
  21. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.json +73 -0
  22. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.md +41 -0
  23. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.json +77 -0
  24. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.md +42 -0
  25. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.json +109 -0
  26. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.md +56 -0
  27. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.json +113 -0
  28. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.md +57 -0
  29. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.json +61 -0
  30. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.md +36 -0
  31. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.json +49 -0
  32. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.md +31 -0
  33. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.json +49 -0
  34. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.md +31 -0
  35. package/.trajectories/index.json +140 -1
  36. package/README.md +23 -9
  37. package/TRAIL_GIT_AUTH_FIX.md +113 -0
  38. package/deploy/workspace/codex.config.toml +1 -1
  39. package/deploy/workspace/entrypoint.sh +20 -79
  40. package/deploy/workspace/gh-relay +156 -0
  41. package/deploy/workspace/git-credential-relay +5 -1
  42. package/dist/bridge/multi-project-client.js +13 -10
  43. package/dist/bridge/spawner.d.ts +2 -0
  44. package/dist/bridge/spawner.js +58 -76
  45. package/dist/bridge/types.d.ts +2 -0
  46. package/dist/cli/index.d.ts +8 -6
  47. package/dist/cli/index.js +297 -30
  48. package/dist/cloud/api/admin.js +16 -3
  49. package/dist/cloud/api/codex-auth-helper.js +28 -8
  50. package/dist/cloud/api/consensus.d.ts +13 -0
  51. package/dist/cloud/api/consensus.js +259 -0
  52. package/dist/cloud/api/daemons.js +205 -1
  53. package/dist/cloud/api/git.js +37 -7
  54. package/dist/cloud/api/onboarding.js +4 -1
  55. package/dist/cloud/api/provider-env.d.ts +5 -0
  56. package/dist/cloud/api/provider-env.js +27 -0
  57. package/dist/cloud/api/providers.js +2 -0
  58. package/dist/cloud/api/test-helpers.js +130 -0
  59. package/dist/cloud/api/workspaces.js +38 -3
  60. package/dist/cloud/db/bulk-ingest.d.ts +88 -0
  61. package/dist/cloud/db/bulk-ingest.js +268 -0
  62. package/dist/cloud/db/drizzle.d.ts +33 -0
  63. package/dist/cloud/db/drizzle.js +174 -2
  64. package/dist/cloud/db/index.d.ts +24 -5
  65. package/dist/cloud/db/index.js +19 -4
  66. package/dist/cloud/db/schema.d.ts +397 -3
  67. package/dist/cloud/db/schema.js +75 -1
  68. package/dist/cloud/provisioner/index.d.ts +8 -0
  69. package/dist/cloud/provisioner/index.js +256 -50
  70. package/dist/cloud/server.js +47 -3
  71. package/dist/cloud/services/index.d.ts +1 -0
  72. package/dist/cloud/services/index.js +2 -0
  73. package/dist/cloud/services/nango.d.ts +3 -4
  74. package/dist/cloud/services/nango.js +11 -33
  75. package/dist/cloud/services/workspace-keepalive.d.ts +76 -0
  76. package/dist/cloud/services/workspace-keepalive.js +234 -0
  77. package/dist/config/relay-config.d.ts +23 -0
  78. package/dist/config/relay-config.js +23 -0
  79. package/dist/daemon/agent-manager.d.ts +20 -1
  80. package/dist/daemon/agent-manager.js +51 -0
  81. package/dist/daemon/agent-registry.js +4 -4
  82. package/dist/daemon/agent-signing.d.ts +158 -0
  83. package/dist/daemon/agent-signing.js +523 -0
  84. package/dist/daemon/api.js +18 -1
  85. package/dist/daemon/cli-auth.d.ts +4 -1
  86. package/dist/daemon/cli-auth.js +55 -11
  87. package/dist/daemon/cloud-sync.d.ts +47 -1
  88. package/dist/daemon/cloud-sync.js +152 -3
  89. package/dist/daemon/connection.d.ts +28 -0
  90. package/dist/daemon/connection.js +113 -22
  91. package/dist/daemon/consensus-integration.d.ts +167 -0
  92. package/dist/daemon/consensus-integration.js +371 -0
  93. package/dist/daemon/consensus.d.ts +271 -0
  94. package/dist/daemon/consensus.js +632 -0
  95. package/dist/daemon/delivery-tracker.d.ts +34 -0
  96. package/dist/daemon/delivery-tracker.js +104 -0
  97. package/dist/daemon/enhanced-features.d.ts +118 -0
  98. package/dist/daemon/enhanced-features.js +178 -0
  99. package/dist/daemon/index.d.ts +4 -0
  100. package/dist/daemon/index.js +5 -0
  101. package/dist/daemon/rate-limiter.d.ts +68 -0
  102. package/dist/daemon/rate-limiter.js +130 -0
  103. package/dist/daemon/router.d.ts +18 -11
  104. package/dist/daemon/router.js +57 -113
  105. package/dist/daemon/server.d.ts +13 -1
  106. package/dist/daemon/server.js +71 -9
  107. package/dist/daemon/sync-queue.d.ts +116 -0
  108. package/dist/daemon/sync-queue.js +361 -0
  109. package/dist/dashboard/out/404.html +1 -1
  110. package/dist/dashboard/out/_next/static/chunks/116-de2a4ac06e5000dc.js +1 -0
  111. package/dist/dashboard/out/_next/static/chunks/847-f1f467060f32afff.js +1 -0
  112. package/dist/dashboard/out/_next/static/chunks/919-87d604a5d76c1fbd.js +1 -0
  113. package/dist/dashboard/out/_next/static/chunks/app/app/{page-c617745b81344f4f.js → page-7f64824ae7d06707.js} +1 -1
  114. package/dist/dashboard/out/_next/static/chunks/app/cloud/link/page-3f559d393902aad2.js +1 -0
  115. package/dist/dashboard/out/_next/static/chunks/app/login/page-16d1715ddaa874ee.js +1 -0
  116. package/dist/dashboard/out/_next/static/chunks/app/{page-dc786c183425c2ac.js → page-814efc4d77b4191d.js} +1 -1
  117. package/dist/dashboard/out/_next/static/chunks/{main-2ee6beb2ae96d210.js → main-5a40a5ae29646e1b.js} +1 -1
  118. package/dist/dashboard/out/_next/static/css/44d2b52637b511bc.css +1 -0
  119. package/dist/dashboard/out/app/onboarding.html +1 -1
  120. package/dist/dashboard/out/app/onboarding.txt +1 -1
  121. package/dist/dashboard/out/app.html +1 -1
  122. package/dist/dashboard/out/app.txt +2 -2
  123. package/dist/dashboard/out/cloud/link.html +1 -0
  124. package/dist/dashboard/out/cloud/link.txt +7 -0
  125. package/dist/dashboard/out/connect-repos.html +1 -1
  126. package/dist/dashboard/out/connect-repos.txt +1 -1
  127. package/dist/dashboard/out/history.html +1 -1
  128. package/dist/dashboard/out/history.txt +2 -2
  129. package/dist/dashboard/out/index.html +1 -1
  130. package/dist/dashboard/out/index.txt +2 -2
  131. package/dist/dashboard/out/login.html +2 -3
  132. package/dist/dashboard/out/login.txt +2 -2
  133. package/dist/dashboard/out/metrics.html +1 -1
  134. package/dist/dashboard/out/metrics.txt +2 -2
  135. package/dist/dashboard/out/pricing.html +2 -2
  136. package/dist/dashboard/out/pricing.txt +1 -1
  137. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  138. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  139. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  140. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  141. package/dist/dashboard/out/providers.html +1 -1
  142. package/dist/dashboard/out/providers.txt +1 -1
  143. package/dist/dashboard/out/signup.html +2 -2
  144. package/dist/dashboard/out/signup.txt +1 -1
  145. package/dist/dashboard-server/server.js +244 -28
  146. package/dist/health-worker-manager.d.ts +62 -0
  147. package/dist/health-worker-manager.js +144 -0
  148. package/dist/health-worker.d.ts +9 -0
  149. package/dist/health-worker.js +79 -0
  150. package/dist/index.d.ts +2 -1
  151. package/dist/index.js +5 -1
  152. package/dist/memory/context-compaction.d.ts +156 -0
  153. package/dist/memory/context-compaction.js +453 -0
  154. package/dist/memory/index.d.ts +1 -0
  155. package/dist/memory/index.js +1 -0
  156. package/dist/protocol/channels.js +4 -4
  157. package/dist/protocol/framing.d.ts +72 -10
  158. package/dist/protocol/framing.js +194 -25
  159. package/dist/storage/adapter.d.ts +8 -1
  160. package/dist/storage/adapter.js +11 -0
  161. package/dist/storage/batched-sqlite-adapter.d.ts +71 -0
  162. package/dist/storage/batched-sqlite-adapter.js +183 -0
  163. package/dist/storage/dead-letter-queue.d.ts +196 -0
  164. package/dist/storage/dead-letter-queue.js +427 -0
  165. package/dist/storage/dlq-adapter.d.ts +195 -0
  166. package/dist/storage/dlq-adapter.js +664 -0
  167. package/dist/trajectory/config.d.ts +32 -14
  168. package/dist/trajectory/config.js +38 -16
  169. package/dist/trajectory/integration.js +217 -64
  170. package/dist/utils/git-remote.d.ts +47 -0
  171. package/dist/utils/git-remote.js +125 -0
  172. package/dist/utils/id-generator.d.ts +35 -0
  173. package/dist/utils/id-generator.js +60 -0
  174. package/dist/utils/index.d.ts +1 -0
  175. package/dist/utils/index.js +1 -0
  176. package/dist/utils/precompiled-patterns.d.ts +110 -0
  177. package/dist/utils/precompiled-patterns.js +322 -0
  178. package/dist/wrapper/auth-detection.js +1 -1
  179. package/dist/wrapper/base-wrapper.d.ts +40 -0
  180. package/dist/wrapper/base-wrapper.js +60 -6
  181. package/dist/wrapper/client.d.ts +14 -4
  182. package/dist/wrapper/client.js +89 -31
  183. package/dist/wrapper/idle-detector.d.ts +102 -0
  184. package/dist/wrapper/idle-detector.js +279 -0
  185. package/dist/wrapper/parser.d.ts +4 -0
  186. package/dist/wrapper/parser.js +19 -1
  187. package/dist/wrapper/pty-wrapper.d.ts +14 -2
  188. package/dist/wrapper/pty-wrapper.js +132 -32
  189. package/dist/wrapper/shared.d.ts +1 -1
  190. package/dist/wrapper/shared.js +1 -1
  191. package/dist/wrapper/tmux-wrapper.d.ts +20 -2
  192. package/dist/wrapper/tmux-wrapper.js +163 -40
  193. package/package.json +3 -1
  194. package/scripts/run-migrations.js +43 -0
  195. package/scripts/verify-schema.js +134 -0
  196. package/tests/benchmarks/protocol.bench.ts +310 -0
  197. package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +0 -1
  198. package/dist/dashboard/out/_next/static/chunks/899-fc02ed79e3de4302.js +0 -1
  199. package/dist/dashboard/out/_next/static/chunks/app/login/page-c22d080201cbd9fb.js +0 -1
  200. package/dist/dashboard/out/_next/static/css/48a8fbe3e659080e.css +0 -1
  201. /package/dist/dashboard/out/_next/static/{sDcbGRTYLcpPvyTs_rsNb → R-uQOUcOLINtsp6ACeZa9}/_buildManifest.js +0 -0
  202. /package/dist/dashboard/out/_next/static/{sDcbGRTYLcpPvyTs_rsNb → R-uQOUcOLINtsp6ACeZa9}/_ssgManifest.js +0 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Git Remote Detection Utility
3
+ *
4
+ * Detects the git remote URL from a working directory and parses it
5
+ * to extract the repository full name (owner/repo).
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { execSync } from 'node:child_process';
10
+ /**
11
+ * Parse a git remote URL to extract owner/repo format.
12
+ *
13
+ * Supports:
14
+ * - git@github.com:owner/repo.git
15
+ * - https://github.com/owner/repo.git
16
+ * - https://github.com/owner/repo
17
+ * - git://github.com/owner/repo.git
18
+ */
19
+ export function parseGitRemoteUrl(url) {
20
+ if (!url)
21
+ return null;
22
+ // SSH format: git@github.com:owner/repo.git
23
+ const sshMatch = url.match(/git@[^:]+:([^/]+\/[^/]+?)(?:\.git)?$/);
24
+ if (sshMatch) {
25
+ return sshMatch[1];
26
+ }
27
+ // HTTPS/Git format: https://github.com/owner/repo.git
28
+ const httpsMatch = url.match(/(?:https?|git):\/\/[^/]+\/([^/]+\/[^/]+?)(?:\.git)?$/);
29
+ if (httpsMatch) {
30
+ return httpsMatch[1];
31
+ }
32
+ return null;
33
+ }
34
+ /**
35
+ * Get the git remote URL from a directory.
36
+ *
37
+ * @param workingDirectory The directory to check for git remote
38
+ * @param remoteName The remote name to use (default: 'origin')
39
+ * @returns The remote URL or null if not found
40
+ */
41
+ export function getGitRemoteUrl(workingDirectory, remoteName = 'origin') {
42
+ try {
43
+ // First check if it's a git repository
44
+ const gitDir = path.join(workingDirectory, '.git');
45
+ if (!fs.existsSync(gitDir)) {
46
+ return null;
47
+ }
48
+ // Try to get the remote URL using git command
49
+ const result = execSync(`git remote get-url ${remoteName}`, {
50
+ cwd: workingDirectory,
51
+ encoding: 'utf-8',
52
+ timeout: 5000,
53
+ stdio: ['pipe', 'pipe', 'pipe'],
54
+ });
55
+ return result.trim() || null;
56
+ }
57
+ catch {
58
+ // Git command failed - try parsing .git/config directly
59
+ try {
60
+ const configPath = path.join(workingDirectory, '.git', 'config');
61
+ if (!fs.existsSync(configPath)) {
62
+ return null;
63
+ }
64
+ const config = fs.readFileSync(configPath, 'utf-8');
65
+ // Parse git config to find remote URL
66
+ const remoteSection = new RegExp(`\\[remote\\s+"${remoteName}"\\][^\\[]*url\\s*=\\s*([^\\n]+)`, 'i');
67
+ const match = config.match(remoteSection);
68
+ return match?.[1]?.trim() || null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Get the repository full name (owner/repo) from a working directory.
77
+ *
78
+ * @param workingDirectory The directory to check
79
+ * @returns The repo full name (e.g., "AgentWorkforce/relay") or null
80
+ */
81
+ export function getRepoFullName(workingDirectory) {
82
+ const remoteUrl = getGitRemoteUrl(workingDirectory);
83
+ if (!remoteUrl) {
84
+ return null;
85
+ }
86
+ return parseGitRemoteUrl(remoteUrl);
87
+ }
88
+ /**
89
+ * Find the git root directory from a given path.
90
+ * Walks up the directory tree looking for .git folder.
91
+ *
92
+ * @param startPath The path to start searching from
93
+ * @returns The git root directory or null if not in a git repo
94
+ */
95
+ export function findGitRoot(startPath) {
96
+ let currentPath = path.resolve(startPath);
97
+ const root = path.parse(currentPath).root;
98
+ while (currentPath !== root) {
99
+ if (fs.existsSync(path.join(currentPath, '.git'))) {
100
+ return currentPath;
101
+ }
102
+ currentPath = path.dirname(currentPath);
103
+ }
104
+ return null;
105
+ }
106
+ /**
107
+ * Get repository full name, walking up to find git root if needed.
108
+ *
109
+ * @param workingDirectory The directory to start from
110
+ * @returns The repo full name or null
111
+ */
112
+ export function getRepoFullNameFromPath(workingDirectory) {
113
+ // First try the exact directory
114
+ let repoName = getRepoFullName(workingDirectory);
115
+ if (repoName) {
116
+ return repoName;
117
+ }
118
+ // Walk up to find git root
119
+ const gitRoot = findGitRoot(workingDirectory);
120
+ if (gitRoot && gitRoot !== workingDirectory) {
121
+ repoName = getRepoFullName(gitRoot);
122
+ }
123
+ return repoName;
124
+ }
125
+ //# sourceMappingURL=git-remote.js.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Monotonic ID Generator
3
+ *
4
+ * Generates unique, lexicographically sortable IDs that are faster than UUID v4.
5
+ *
6
+ * Format: <timestamp-base36>-<counter-base36>-<nodeId>
7
+ * Example: "lxyz5g8-0001-7d2a"
8
+ *
9
+ * Properties:
10
+ * - Lexicographically sortable by time
11
+ * - Unique across processes (node prefix)
12
+ * - ~16x faster than UUID v4
13
+ * - Shorter (20-24 chars vs 36 chars)
14
+ */
15
+ export declare class IdGenerator {
16
+ private counter;
17
+ private readonly prefix;
18
+ private lastTs;
19
+ constructor(nodeId?: string);
20
+ /**
21
+ * Generate a unique, monotonically increasing ID.
22
+ */
23
+ next(): string;
24
+ /**
25
+ * Generate a short ID (just timestamp + counter, no node prefix).
26
+ * Use when you don't need cross-process uniqueness.
27
+ */
28
+ short(): string;
29
+ }
30
+ export declare const idGen: IdGenerator;
31
+ /**
32
+ * Generate a unique ID (drop-in replacement for uuid()).
33
+ */
34
+ export declare function generateId(): string;
35
+ //# sourceMappingURL=id-generator.d.ts.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Monotonic ID Generator
3
+ *
4
+ * Generates unique, lexicographically sortable IDs that are faster than UUID v4.
5
+ *
6
+ * Format: <timestamp-base36>-<counter-base36>-<nodeId>
7
+ * Example: "lxyz5g8-0001-7d2a"
8
+ *
9
+ * Properties:
10
+ * - Lexicographically sortable by time
11
+ * - Unique across processes (node prefix)
12
+ * - ~16x faster than UUID v4
13
+ * - Shorter (20-24 chars vs 36 chars)
14
+ */
15
+ export class IdGenerator {
16
+ counter = 0;
17
+ prefix;
18
+ lastTs = 0;
19
+ constructor(nodeId) {
20
+ // Use process ID + random suffix for uniqueness across processes
21
+ this.prefix = nodeId ?? `${process.pid.toString(36)}${Math.random().toString(36).slice(2, 6)}`;
22
+ }
23
+ /**
24
+ * Generate a unique, monotonically increasing ID.
25
+ */
26
+ next() {
27
+ const now = Date.now();
28
+ // Reset counter if timestamp changed
29
+ if (now !== this.lastTs) {
30
+ this.lastTs = now;
31
+ this.counter = 0;
32
+ }
33
+ const ts = now.toString(36);
34
+ const seq = (this.counter++).toString(36).padStart(4, '0');
35
+ return `${ts}-${seq}-${this.prefix}`;
36
+ }
37
+ /**
38
+ * Generate a short ID (just timestamp + counter, no node prefix).
39
+ * Use when you don't need cross-process uniqueness.
40
+ */
41
+ short() {
42
+ const now = Date.now();
43
+ if (now !== this.lastTs) {
44
+ this.lastTs = now;
45
+ this.counter = 0;
46
+ }
47
+ const ts = now.toString(36);
48
+ const seq = (this.counter++).toString(36).padStart(4, '0');
49
+ return `${ts}-${seq}`;
50
+ }
51
+ }
52
+ // Singleton instance for the process
53
+ export const idGen = new IdGenerator();
54
+ /**
55
+ * Generate a unique ID (drop-in replacement for uuid()).
56
+ */
57
+ export function generateId() {
58
+ return idGen.next();
59
+ }
60
+ //# sourceMappingURL=id-generator.js.map
@@ -1,3 +1,4 @@
1
1
  export * from './name-generator.js';
2
2
  export * from './logger.js';
3
+ export * from './precompiled-patterns.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,4 @@
1
1
  export * from './name-generator.js';
2
2
  export * from './logger.js';
3
+ export * from './precompiled-patterns.js';
3
4
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Precompiled Pattern Matching
3
+ *
4
+ * Optimized regex patterns for high-performance message parsing.
5
+ * Inspired by russian-code-ts performance targets (<1ms for pattern matching).
6
+ *
7
+ * Strategies:
8
+ * 1. Precompile patterns at module load (not per-instance)
9
+ * 2. Combine multiple patterns into single regex where possible
10
+ * 3. Use non-capturing groups and atomic patterns
11
+ * 4. Cache compiled patterns by prefix
12
+ */
13
+ export interface CompiledPatterns {
14
+ inline: RegExp;
15
+ fencedInline: RegExp;
16
+ escape: RegExp;
17
+ }
18
+ /**
19
+ * Get or create compiled patterns for a given prefix configuration.
20
+ * Patterns are cached for reuse across parser instances.
21
+ */
22
+ export declare function getCompiledPatterns(prefix?: string, thinkingPrefix?: string): CompiledPatterns;
23
+ /**
24
+ * Fast check if text matches any instructional pattern.
25
+ * Single regex test instead of array.some().
26
+ */
27
+ export declare function isInstructionalTextFast(body: string): boolean;
28
+ /**
29
+ * Fast placeholder target check using Set.
30
+ */
31
+ export declare function isPlaceholderTargetFast(target: string): boolean;
32
+ /**
33
+ * Strip ANSI escape codes from a string.
34
+ * Uses precompiled patterns for better performance.
35
+ */
36
+ export declare function stripAnsiFast(str: string): string;
37
+ /**
38
+ * Precompiled static patterns used across parsing operations.
39
+ */
40
+ export declare const StaticPatterns: {
41
+ readonly BLOCK_END: RegExp;
42
+ readonly BLOCK_METADATA_END: RegExp;
43
+ readonly CODE_FENCE: RegExp;
44
+ readonly FENCE_END_START: RegExp;
45
+ readonly FENCE_END_LINE: RegExp;
46
+ readonly FENCE_END: RegExp;
47
+ readonly ESCAPED_FENCE_START: RegExp;
48
+ readonly ESCAPED_FENCE_END: RegExp;
49
+ readonly ESCAPED_FENCE_END_CHECK: RegExp;
50
+ readonly ESCAPED_FENCE_START_CHECK: RegExp;
51
+ readonly BULLET_OR_NUMBERED_LIST: RegExp;
52
+ readonly PROMPTISH_LINE: RegExp;
53
+ readonly RELAY_INJECTION_PREFIX: RegExp;
54
+ readonly SPAWN_COMMAND: RegExp;
55
+ readonly RELEASE_COMMAND: RegExp;
56
+ readonly THINKING_START: RegExp;
57
+ readonly THINKING_END: RegExp;
58
+ readonly AGENT_NAME: RegExp;
59
+ readonly CLI_PROMPTS: {
60
+ readonly claude: RegExp;
61
+ readonly gemini: RegExp;
62
+ readonly codex: RegExp;
63
+ readonly droid: RegExp;
64
+ readonly opencode: RegExp;
65
+ readonly spawned: RegExp;
66
+ readonly other: RegExp;
67
+ };
68
+ };
69
+ /**
70
+ * Check if line is a spawn or release command.
71
+ */
72
+ export declare function isSpawnOrReleaseCommandFast(line: string): boolean;
73
+ /**
74
+ * Check if a line contains an escaped fence end.
75
+ */
76
+ export declare function isEscapedFenceEndFast(line: string): boolean;
77
+ /**
78
+ * Unescape fence markers in content.
79
+ */
80
+ export declare function unescapeFenceMarkersFast(content: string): string;
81
+ interface PatternMetrics {
82
+ calls: number;
83
+ totalMs: number;
84
+ maxMs: number;
85
+ }
86
+ /**
87
+ * Track pattern matching performance (for debugging/profiling).
88
+ * Call with pattern name and execution time.
89
+ */
90
+ export declare function trackPatternPerformance(name: string, ms: number): void;
91
+ /**
92
+ * Get pattern performance metrics.
93
+ */
94
+ export declare function getPatternMetrics(): Map<string, PatternMetrics & {
95
+ avgMs: number;
96
+ }>;
97
+ /**
98
+ * Reset pattern performance metrics.
99
+ */
100
+ export declare function resetPatternMetrics(): void;
101
+ /**
102
+ * Benchmark pattern matching performance.
103
+ * Useful for testing optimization impact.
104
+ */
105
+ export declare function benchmarkPatterns(iterations?: number): Record<string, {
106
+ avgNs: number;
107
+ maxNs: number;
108
+ }>;
109
+ export {};
110
+ //# sourceMappingURL=precompiled-patterns.d.ts.map
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Precompiled Pattern Matching
3
+ *
4
+ * Optimized regex patterns for high-performance message parsing.
5
+ * Inspired by russian-code-ts performance targets (<1ms for pattern matching).
6
+ *
7
+ * Strategies:
8
+ * 1. Precompile patterns at module load (not per-instance)
9
+ * 2. Combine multiple patterns into single regex where possible
10
+ * 3. Use non-capturing groups and atomic patterns
11
+ * 4. Cache compiled patterns by prefix
12
+ */
13
+ const patternCache = new Map();
14
+ /**
15
+ * Escape special regex characters in a string
16
+ */
17
+ function escapeRegex(str) {
18
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19
+ }
20
+ /**
21
+ * Get or create compiled patterns for a given prefix configuration.
22
+ * Patterns are cached for reuse across parser instances.
23
+ */
24
+ export function getCompiledPatterns(prefix = '->relay:', thinkingPrefix = '->thinking:') {
25
+ const cacheKey = `${prefix}|${thinkingPrefix}`;
26
+ const cached = patternCache.get(cacheKey);
27
+ if (cached) {
28
+ return cached;
29
+ }
30
+ const escapedPrefix = escapeRegex(prefix);
31
+ const escapedThinking = escapeRegex(thinkingPrefix);
32
+ // Combined prompt character class for line start
33
+ // Includes: >, $, %, #, →, ➜, ›, », bullets (●•◦‣⁃-*⏺◆◇○□■), box chars (│┃┆┇┊┋╎╏), sparkle (✦)
34
+ const promptChars = String.raw `[>$%#→➜›»●•◦‣⁃\-*⏺◆◇○□■│┃┆┇┊┋╎╏✦]`;
35
+ const lineStartPrefix = String.raw `^(?:\s*(?:${promptChars}\s*)*)?`;
36
+ // Thread syntax: [thread:id] or [thread:project:id]
37
+ const threadSyntax = String.raw `(?:\s+\[thread:(?:([\w-]+):)?([\w-]+)\])?`;
38
+ const patterns = {
39
+ // Combined inline pattern for both relay and thinking prefixes
40
+ // Groups: 1=prefix type (relay/thinking), 2=target, 3=thread project, 4=thread id, 5=body
41
+ inline: new RegExp(`${lineStartPrefix}(${escapedPrefix}|${escapedThinking})(\\S+)${threadSyntax}\\s+(.+)$`),
42
+ // Combined fenced inline pattern: ->relay:Target <<<
43
+ // Groups: 1=prefix type, 2=target, 3=thread project, 4=thread id
44
+ fencedInline: new RegExp(`${lineStartPrefix}(${escapedPrefix}|${escapedThinking})(\\S+)${threadSyntax}\\s+<<<\\s*$`),
45
+ // Escape pattern for \->relay: or \->thinking:
46
+ escape: new RegExp(`^(\\s*)\\\\(${escapedPrefix}|${escapedThinking})`),
47
+ };
48
+ patternCache.set(cacheKey, patterns);
49
+ return patterns;
50
+ }
51
+ // =============================================================================
52
+ // Combined Instructional Markers (Single Regex)
53
+ // =============================================================================
54
+ /**
55
+ * Combined instructional markers pattern.
56
+ * Instead of testing each pattern separately, we combine into one regex.
57
+ *
58
+ * Original patterns:
59
+ * - /\bSEND:\s*$/i
60
+ * - /\bPROTOCOL:\s*\(\d+\)/i
61
+ * - /\bExample:/i
62
+ * - /\\->relay:/
63
+ * - /\\->thinking:/
64
+ * - /^AgentName\s+/
65
+ * - /^Target\s+/
66
+ * - /\[Agent Relay\]/
67
+ * - /MULTI-LINE:/i
68
+ * - /RECEIVE:/i
69
+ */
70
+ const INSTRUCTIONAL_COMBINED = new RegExp([
71
+ String.raw `\bSEND:\s*$`, // "SEND:" at end (instruction prefix)
72
+ String.raw `\bPROTOCOL:\s*\(\d+\)`, // "PROTOCOL: (1)" - numbered instructions
73
+ String.raw `\bExample:`, // "Example:" marker
74
+ String.raw `\\->relay:`, // Escaped relay prefix (documentation)
75
+ String.raw `\\->thinking:`, // Escaped thinking prefix (documentation)
76
+ String.raw `^AgentName\s+`, // Body starting with "AgentName"
77
+ String.raw `^Target\s+`, // Body starting with "Target"
78
+ String.raw `\[Agent Relay\]`, // Injected instruction header
79
+ String.raw `MULTI-LINE:`, // Multi-line format instruction
80
+ String.raw `RECEIVE:`, // Receive instruction marker
81
+ ].join('|'), 'i' // Case insensitive
82
+ );
83
+ /**
84
+ * Fast check if text matches any instructional pattern.
85
+ * Single regex test instead of array.some().
86
+ */
87
+ export function isInstructionalTextFast(body) {
88
+ return INSTRUCTIONAL_COMBINED.test(body);
89
+ }
90
+ // =============================================================================
91
+ // Placeholder Targets (Set for O(1) Lookup)
92
+ // =============================================================================
93
+ /**
94
+ * Placeholder target names - precomputed lowercase set for fast lookup.
95
+ */
96
+ const PLACEHOLDER_TARGETS_SET = new Set([
97
+ 'agentname',
98
+ 'target',
99
+ 'recipient',
100
+ 'yourtarget',
101
+ 'targetagent',
102
+ 'someagent',
103
+ 'otheragent',
104
+ 'worker',
105
+ ]);
106
+ /**
107
+ * Fast placeholder target check using Set.
108
+ */
109
+ export function isPlaceholderTargetFast(target) {
110
+ return PLACEHOLDER_TARGETS_SET.has(target.toLowerCase());
111
+ }
112
+ // =============================================================================
113
+ // ANSI Stripping (Precompiled)
114
+ // =============================================================================
115
+ /**
116
+ * Precompiled ANSI escape sequence pattern.
117
+ * Global flag for replace operations.
118
+ */
119
+ // eslint-disable-next-line no-control-regex
120
+ const ANSI_PATTERN_COMPILED = /\x1b\[[0-9;?]*[a-zA-Z]|\x1b\].*?(?:\x07|\x1b\\)|\r/g;
121
+ /**
122
+ * Precompiled orphaned CSI pattern.
123
+ */
124
+ const ORPHANED_CSI_COMPILED = /^\s*(\[(?:\?|\d)\d*[A-Za-z])+\s*/g;
125
+ /**
126
+ * Strip ANSI escape codes from a string.
127
+ * Uses precompiled patterns for better performance.
128
+ */
129
+ export function stripAnsiFast(str) {
130
+ // Reset lastIndex for global patterns
131
+ ANSI_PATTERN_COMPILED.lastIndex = 0;
132
+ ORPHANED_CSI_COMPILED.lastIndex = 0;
133
+ let result = str.replace(ANSI_PATTERN_COMPILED, '');
134
+ result = result.replace(ORPHANED_CSI_COMPILED, '');
135
+ return result;
136
+ }
137
+ // =============================================================================
138
+ // Static Patterns (Precompiled)
139
+ // =============================================================================
140
+ /**
141
+ * Precompiled static patterns used across parsing operations.
142
+ */
143
+ export const StaticPatterns = {
144
+ // Block markers
145
+ BLOCK_END: /\[\[\/RELAY\]\]/,
146
+ BLOCK_METADATA_END: /\[\[\/RELAY_METADATA\]\]/,
147
+ CODE_FENCE: /^```/,
148
+ // Fence markers
149
+ FENCE_END_START: /^(?:\s*)?>>>/,
150
+ FENCE_END_LINE: />>>\s*$/,
151
+ FENCE_END: /^(?:\s*)?>>>|>>>\s*$/,
152
+ // Escape patterns
153
+ ESCAPED_FENCE_START: /\\<<</g,
154
+ ESCAPED_FENCE_END: /\\>>>/g,
155
+ ESCAPED_FENCE_END_CHECK: /\\>>>\s*$/,
156
+ ESCAPED_FENCE_START_CHECK: /^(?:\s*)?\\>>>/,
157
+ // Continuation helpers
158
+ BULLET_OR_NUMBERED_LIST: /^[ \t]*([\-*•◦‣⏺◆◇○□■]|[0-9]+[.)])\s+/,
159
+ PROMPTISH_LINE: /^[\s]*[>$%#➜›»][\s]*$/,
160
+ RELAY_INJECTION_PREFIX: /^\s*Relay message from /,
161
+ // Spawn/release commands
162
+ SPAWN_COMMAND: /->relay:spawn\s+\S+/i,
163
+ RELEASE_COMMAND: /->relay:release\s+\S+/i,
164
+ // Claude extended thinking blocks
165
+ THINKING_START: /<thinking>/,
166
+ THINKING_END: /<\/thinking>/,
167
+ // Agent name validation (PascalCase, 2-30 chars)
168
+ AGENT_NAME: /^[A-Z][a-zA-Z0-9]{1,29}$/,
169
+ // CLI prompt patterns by type
170
+ CLI_PROMPTS: {
171
+ claude: /^[>›»]\s*$/,
172
+ gemini: /^[>›»]\s*$/,
173
+ codex: /^[>›»]\s*$/,
174
+ droid: /^[>›»]\s*$/,
175
+ opencode: /^[>›»]\s*$/,
176
+ spawned: /^[>›»]\s*$/,
177
+ other: /^[>$%#➜›»]\s*$/,
178
+ },
179
+ };
180
+ // =============================================================================
181
+ // Pattern Matching Utilities
182
+ // =============================================================================
183
+ /**
184
+ * Check if line is a spawn or release command.
185
+ */
186
+ export function isSpawnOrReleaseCommandFast(line) {
187
+ return StaticPatterns.SPAWN_COMMAND.test(line) ||
188
+ StaticPatterns.RELEASE_COMMAND.test(line);
189
+ }
190
+ /**
191
+ * Check if a line contains an escaped fence end.
192
+ */
193
+ export function isEscapedFenceEndFast(line) {
194
+ return StaticPatterns.ESCAPED_FENCE_END_CHECK.test(line) ||
195
+ StaticPatterns.ESCAPED_FENCE_START_CHECK.test(line);
196
+ }
197
+ /**
198
+ * Unescape fence markers in content.
199
+ */
200
+ export function unescapeFenceMarkersFast(content) {
201
+ StaticPatterns.ESCAPED_FENCE_START.lastIndex = 0;
202
+ StaticPatterns.ESCAPED_FENCE_END.lastIndex = 0;
203
+ return content
204
+ .replace(StaticPatterns.ESCAPED_FENCE_START, '<<<')
205
+ .replace(StaticPatterns.ESCAPED_FENCE_END, '>>>');
206
+ }
207
+ const metrics = new Map();
208
+ /**
209
+ * Track pattern matching performance (for debugging/profiling).
210
+ * Call with pattern name and execution time.
211
+ */
212
+ export function trackPatternPerformance(name, ms) {
213
+ const existing = metrics.get(name);
214
+ if (existing) {
215
+ existing.calls++;
216
+ existing.totalMs += ms;
217
+ existing.maxMs = Math.max(existing.maxMs, ms);
218
+ }
219
+ else {
220
+ metrics.set(name, { calls: 1, totalMs: ms, maxMs: ms });
221
+ }
222
+ }
223
+ /**
224
+ * Get pattern performance metrics.
225
+ */
226
+ export function getPatternMetrics() {
227
+ const result = new Map();
228
+ for (const [name, m] of metrics) {
229
+ result.set(name, {
230
+ ...m,
231
+ avgMs: m.calls > 0 ? m.totalMs / m.calls : 0,
232
+ });
233
+ }
234
+ return result;
235
+ }
236
+ /**
237
+ * Reset pattern performance metrics.
238
+ */
239
+ export function resetPatternMetrics() {
240
+ metrics.clear();
241
+ }
242
+ // =============================================================================
243
+ // Benchmark Utility
244
+ // =============================================================================
245
+ /**
246
+ * Benchmark pattern matching performance.
247
+ * Useful for testing optimization impact.
248
+ */
249
+ export function benchmarkPatterns(iterations = 10000) {
250
+ const testStrings = [
251
+ '->relay:Agent Hello world',
252
+ '->relay:Lead [thread:task-123] Starting work',
253
+ ' > ->relay:Worker <<<',
254
+ 'Some random text without relay',
255
+ '\x1b[32m->relay:Test\x1b[0m message with ANSI',
256
+ '->relay:spawn Worker claude "task"',
257
+ 'ACK: Task received',
258
+ 'SEND: Protocol instruction',
259
+ 'Example: how to use relay',
260
+ ];
261
+ const results = {};
262
+ // Benchmark combined instructional check
263
+ {
264
+ let maxNs = 0;
265
+ const start = process.hrtime.bigint();
266
+ for (let i = 0; i < iterations; i++) {
267
+ for (const str of testStrings) {
268
+ const s = process.hrtime.bigint();
269
+ isInstructionalTextFast(str);
270
+ const elapsed = Number(process.hrtime.bigint() - s);
271
+ if (elapsed > maxNs)
272
+ maxNs = elapsed;
273
+ }
274
+ }
275
+ const totalNs = Number(process.hrtime.bigint() - start);
276
+ results['instructionalCheck'] = {
277
+ avgNs: totalNs / (iterations * testStrings.length),
278
+ maxNs,
279
+ };
280
+ }
281
+ // Benchmark ANSI stripping
282
+ {
283
+ let maxNs = 0;
284
+ const start = process.hrtime.bigint();
285
+ for (let i = 0; i < iterations; i++) {
286
+ for (const str of testStrings) {
287
+ const s = process.hrtime.bigint();
288
+ stripAnsiFast(str);
289
+ const elapsed = Number(process.hrtime.bigint() - s);
290
+ if (elapsed > maxNs)
291
+ maxNs = elapsed;
292
+ }
293
+ }
294
+ const totalNs = Number(process.hrtime.bigint() - start);
295
+ results['ansiStrip'] = {
296
+ avgNs: totalNs / (iterations * testStrings.length),
297
+ maxNs,
298
+ };
299
+ }
300
+ // Benchmark placeholder check
301
+ {
302
+ const targets = ['AgentName', 'Lead', 'Worker', 'target', 'Developer'];
303
+ let maxNs = 0;
304
+ const start = process.hrtime.bigint();
305
+ for (let i = 0; i < iterations; i++) {
306
+ for (const t of targets) {
307
+ const s = process.hrtime.bigint();
308
+ isPlaceholderTargetFast(t);
309
+ const elapsed = Number(process.hrtime.bigint() - s);
310
+ if (elapsed > maxNs)
311
+ maxNs = elapsed;
312
+ }
313
+ }
314
+ const totalNs = Number(process.hrtime.bigint() - start);
315
+ results['placeholderCheck'] = {
316
+ avgNs: totalNs / (iterations * targets.length),
317
+ maxNs,
318
+ };
319
+ }
320
+ return results;
321
+ }
322
+ //# sourceMappingURL=precompiled-patterns.js.map
@@ -104,7 +104,7 @@ export function detectAuthRevocation(output, recentOutputOnly = false) {
104
104
  /**
105
105
  * Determine confidence level based on the matched pattern.
106
106
  */
107
- function getConfidenceLevel(pattern, matchedText) {
107
+ function getConfidenceLevel(pattern, _matchedText) {
108
108
  const patternStr = pattern.source.toLowerCase();
109
109
  // High confidence: Explicit auth failure messages
110
110
  if (patternStr.includes('session') && patternStr.includes('expired') ||