@agent-relay/utils 2.0.28 → 2.0.30

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,271 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var precompiled_patterns_exports = {};
20
+ __export(precompiled_patterns_exports, {
21
+ StaticPatterns: () => StaticPatterns,
22
+ benchmarkPatterns: () => benchmarkPatterns,
23
+ getCompiledPatterns: () => getCompiledPatterns,
24
+ getPatternMetrics: () => getPatternMetrics,
25
+ isEscapedFenceEndFast: () => isEscapedFenceEndFast,
26
+ isInstructionalTextFast: () => isInstructionalTextFast,
27
+ isPlaceholderTargetFast: () => isPlaceholderTargetFast,
28
+ isSpawnOrReleaseCommandFast: () => isSpawnOrReleaseCommandFast,
29
+ resetPatternMetrics: () => resetPatternMetrics,
30
+ stripAnsiFast: () => stripAnsiFast,
31
+ trackPatternPerformance: () => trackPatternPerformance,
32
+ unescapeFenceMarkersFast: () => unescapeFenceMarkersFast
33
+ });
34
+ module.exports = __toCommonJS(precompiled_patterns_exports);
35
+ const patternCache = /* @__PURE__ */ new Map();
36
+ function escapeRegex(str) {
37
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
38
+ }
39
+ function getCompiledPatterns(prefix = "->relay:", thinkingPrefix = "->thinking:") {
40
+ const cacheKey = `${prefix}|${thinkingPrefix}`;
41
+ const cached = patternCache.get(cacheKey);
42
+ if (cached) {
43
+ return cached;
44
+ }
45
+ const escapedPrefix = escapeRegex(prefix);
46
+ const escapedThinking = escapeRegex(thinkingPrefix);
47
+ const promptChars = String.raw`[>$%#→➜›»●•◦‣⁃\-*⏺◆◇○□■│┃┆┇┊┋╎╏✦]`;
48
+ const lineStartPrefix = String.raw`^(?:\s*(?:${promptChars}\s*)*)?`;
49
+ const threadSyntax = String.raw`(?:\s+\[thread:(?:([\w-]+):)?([\w-]+)\])?`;
50
+ const patterns = {
51
+ // Combined inline pattern for both relay and thinking prefixes
52
+ // Groups: 1=prefix type (relay/thinking), 2=target, 3=thread project, 4=thread id, 5=body
53
+ inline: new RegExp(
54
+ `${lineStartPrefix}(${escapedPrefix}|${escapedThinking})(\\S+)${threadSyntax}\\s+(.+)$`
55
+ ),
56
+ // Combined fenced inline pattern: ->relay:Target <<<
57
+ // Groups: 1=prefix type, 2=target, 3=thread project, 4=thread id
58
+ fencedInline: new RegExp(
59
+ `${lineStartPrefix}(${escapedPrefix}|${escapedThinking})(\\S+)${threadSyntax}\\s+<<<\\s*$`
60
+ ),
61
+ // Escape pattern for \->relay: or \->thinking:
62
+ escape: new RegExp(`^(\\s*)\\\\(${escapedPrefix}|${escapedThinking})`)
63
+ };
64
+ patternCache.set(cacheKey, patterns);
65
+ return patterns;
66
+ }
67
+ const INSTRUCTIONAL_COMBINED = new RegExp(
68
+ [
69
+ String.raw`\bSEND:\s*$`,
70
+ // "SEND:" at end (instruction prefix)
71
+ String.raw`\bPROTOCOL:\s*\(\d+\)`,
72
+ // "PROTOCOL: (1)" - numbered instructions
73
+ String.raw`\bExample:`,
74
+ // "Example:" marker
75
+ String.raw`\\->relay:`,
76
+ // Escaped relay prefix (documentation)
77
+ String.raw`\\->thinking:`,
78
+ // Escaped thinking prefix (documentation)
79
+ String.raw`^AgentName\s+`,
80
+ // Body starting with "AgentName"
81
+ String.raw`^Target\s+`,
82
+ // Body starting with "Target"
83
+ String.raw`\[Agent Relay\]`,
84
+ // Injected instruction header
85
+ String.raw`MULTI-LINE:`,
86
+ // Multi-line format instruction
87
+ String.raw`RECEIVE:`
88
+ // Receive instruction marker
89
+ ].join("|"),
90
+ "i"
91
+ // Case insensitive
92
+ );
93
+ function isInstructionalTextFast(body) {
94
+ return INSTRUCTIONAL_COMBINED.test(body);
95
+ }
96
+ const PLACEHOLDER_TARGETS_SET = /* @__PURE__ */ new Set([
97
+ "agentname",
98
+ "target",
99
+ "recipient",
100
+ "yourtarget",
101
+ "targetagent",
102
+ "someagent",
103
+ "otheragent",
104
+ "worker"
105
+ ]);
106
+ function isPlaceholderTargetFast(target) {
107
+ return PLACEHOLDER_TARGETS_SET.has(target.toLowerCase());
108
+ }
109
+ const ANSI_PATTERN_COMPILED = /\x1b\[[0-9;?]*[a-zA-Z]|\x1b\].*?(?:\x07|\x1b\\)|\r/g;
110
+ const ORPHANED_CSI_COMPILED = /^\s*(\[(?:\?|\d)\d*[A-Za-z])+\s*/g;
111
+ function stripAnsiFast(str) {
112
+ ANSI_PATTERN_COMPILED.lastIndex = 0;
113
+ ORPHANED_CSI_COMPILED.lastIndex = 0;
114
+ let result = str.replace(ANSI_PATTERN_COMPILED, "");
115
+ result = result.replace(ORPHANED_CSI_COMPILED, "");
116
+ return result;
117
+ }
118
+ const StaticPatterns = {
119
+ // Block markers
120
+ BLOCK_END: /\[\[\/RELAY\]\]/,
121
+ BLOCK_METADATA_END: /\[\[\/RELAY_METADATA\]\]/,
122
+ CODE_FENCE: /^```/,
123
+ // Fence markers
124
+ FENCE_END_START: /^(?:\s*)?>>>/,
125
+ FENCE_END_LINE: />>>\s*$/,
126
+ FENCE_END: /^(?:\s*)?>>>|>>>\s*$/,
127
+ // Escape patterns
128
+ ESCAPED_FENCE_START: /\\<<</g,
129
+ ESCAPED_FENCE_END: /\\>>>/g,
130
+ ESCAPED_FENCE_END_CHECK: /\\>>>\s*$/,
131
+ ESCAPED_FENCE_START_CHECK: /^(?:\s*)?\\>>>/,
132
+ // Continuation helpers
133
+ BULLET_OR_NUMBERED_LIST: /^[ \t]*([\-*•◦‣⏺◆◇○□■]|[0-9]+[.)])\s+/,
134
+ PROMPTISH_LINE: /^[\s]*[>$%#➜›»][\s]*$/,
135
+ RELAY_INJECTION_PREFIX: /^\s*Relay message from /,
136
+ // Spawn/release commands
137
+ SPAWN_COMMAND: /->relay:spawn\s+\S+/i,
138
+ RELEASE_COMMAND: /->relay:release\s+\S+/i,
139
+ // Claude extended thinking blocks
140
+ THINKING_START: /<thinking>/,
141
+ THINKING_END: /<\/thinking>/,
142
+ // Agent name validation (PascalCase, 2-30 chars)
143
+ AGENT_NAME: /^[A-Z][a-zA-Z0-9]{1,29}$/,
144
+ // CLI prompt patterns by type
145
+ CLI_PROMPTS: {
146
+ claude: /^[>›»]\s*$/,
147
+ gemini: /^[>›»]\s*$/,
148
+ codex: /^[>›»]\s*$/,
149
+ droid: /^[>›»]\s*$/,
150
+ opencode: /^[>›»]\s*$/,
151
+ spawned: /^[>›»]\s*$/,
152
+ other: /^[>$%#➜›»]\s*$/
153
+ }
154
+ };
155
+ function isSpawnOrReleaseCommandFast(line) {
156
+ return StaticPatterns.SPAWN_COMMAND.test(line) || StaticPatterns.RELEASE_COMMAND.test(line);
157
+ }
158
+ function isEscapedFenceEndFast(line) {
159
+ return StaticPatterns.ESCAPED_FENCE_END_CHECK.test(line) || StaticPatterns.ESCAPED_FENCE_START_CHECK.test(line);
160
+ }
161
+ function unescapeFenceMarkersFast(content) {
162
+ StaticPatterns.ESCAPED_FENCE_START.lastIndex = 0;
163
+ StaticPatterns.ESCAPED_FENCE_END.lastIndex = 0;
164
+ return content.replace(StaticPatterns.ESCAPED_FENCE_START, "<<<").replace(StaticPatterns.ESCAPED_FENCE_END, ">>>");
165
+ }
166
+ const metrics = /* @__PURE__ */ new Map();
167
+ function trackPatternPerformance(name, ms) {
168
+ const existing = metrics.get(name);
169
+ if (existing) {
170
+ existing.calls++;
171
+ existing.totalMs += ms;
172
+ existing.maxMs = Math.max(existing.maxMs, ms);
173
+ } else {
174
+ metrics.set(name, { calls: 1, totalMs: ms, maxMs: ms });
175
+ }
176
+ }
177
+ function getPatternMetrics() {
178
+ const result = /* @__PURE__ */ new Map();
179
+ for (const [name, m] of metrics) {
180
+ result.set(name, {
181
+ ...m,
182
+ avgMs: m.calls > 0 ? m.totalMs / m.calls : 0
183
+ });
184
+ }
185
+ return result;
186
+ }
187
+ function resetPatternMetrics() {
188
+ metrics.clear();
189
+ }
190
+ function benchmarkPatterns(iterations = 1e4) {
191
+ const testStrings = [
192
+ "->relay:Agent Hello world",
193
+ "->relay:Lead [thread:task-123] Starting work",
194
+ " > ->relay:Worker <<<",
195
+ "Some random text without relay",
196
+ "\x1B[32m->relay:Test\x1B[0m message with ANSI",
197
+ '->relay:spawn Worker claude "task"',
198
+ "ACK: Task received",
199
+ "SEND: Protocol instruction",
200
+ "Example: how to use relay"
201
+ ];
202
+ const results = {};
203
+ {
204
+ let maxNs = 0;
205
+ const start = process.hrtime.bigint();
206
+ for (let i = 0; i < iterations; i++) {
207
+ for (const str of testStrings) {
208
+ const s = process.hrtime.bigint();
209
+ isInstructionalTextFast(str);
210
+ const elapsed = Number(process.hrtime.bigint() - s);
211
+ if (elapsed > maxNs) maxNs = elapsed;
212
+ }
213
+ }
214
+ const totalNs = Number(process.hrtime.bigint() - start);
215
+ results["instructionalCheck"] = {
216
+ avgNs: totalNs / (iterations * testStrings.length),
217
+ maxNs
218
+ };
219
+ }
220
+ {
221
+ let maxNs = 0;
222
+ const start = process.hrtime.bigint();
223
+ for (let i = 0; i < iterations; i++) {
224
+ for (const str of testStrings) {
225
+ const s = process.hrtime.bigint();
226
+ stripAnsiFast(str);
227
+ const elapsed = Number(process.hrtime.bigint() - s);
228
+ if (elapsed > maxNs) maxNs = elapsed;
229
+ }
230
+ }
231
+ const totalNs = Number(process.hrtime.bigint() - start);
232
+ results["ansiStrip"] = {
233
+ avgNs: totalNs / (iterations * testStrings.length),
234
+ maxNs
235
+ };
236
+ }
237
+ {
238
+ const targets = ["AgentName", "Lead", "Worker", "target", "Developer"];
239
+ let maxNs = 0;
240
+ const start = process.hrtime.bigint();
241
+ for (let i = 0; i < iterations; i++) {
242
+ for (const t of targets) {
243
+ const s = process.hrtime.bigint();
244
+ isPlaceholderTargetFast(t);
245
+ const elapsed = Number(process.hrtime.bigint() - s);
246
+ if (elapsed > maxNs) maxNs = elapsed;
247
+ }
248
+ }
249
+ const totalNs = Number(process.hrtime.bigint() - start);
250
+ results["placeholderCheck"] = {
251
+ avgNs: totalNs / (iterations * targets.length),
252
+ maxNs
253
+ };
254
+ }
255
+ return results;
256
+ }
257
+ // Annotate the CommonJS export names for ESM import in node:
258
+ 0 && (module.exports = {
259
+ StaticPatterns,
260
+ benchmarkPatterns,
261
+ getCompiledPatterns,
262
+ getPatternMetrics,
263
+ isEscapedFenceEndFast,
264
+ isInstructionalTextFast,
265
+ isPlaceholderTargetFast,
266
+ isSpawnOrReleaseCommandFast,
267
+ resetPatternMetrics,
268
+ stripAnsiFast,
269
+ trackPatternPerformance,
270
+ unescapeFenceMarkersFast
271
+ });
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var relay_pty_path_exports = {};
30
+ __export(relay_pty_path_exports, {
31
+ clearBinaryCache: () => clearBinaryCache,
32
+ findRelayPtyBinary: () => findRelayPtyBinary,
33
+ getCachedRelayPtyPath: () => getCachedRelayPtyPath,
34
+ getLastSearchPaths: () => getLastSearchPaths,
35
+ hasRelayPtyBinary: () => hasRelayPtyBinary
36
+ });
37
+ module.exports = __toCommonJS(relay_pty_path_exports);
38
+ var import_node_fs = __toESM(require("node:fs"), 1);
39
+ var import_node_os = __toESM(require("node:os"), 1);
40
+ var import_node_path = __toESM(require("node:path"), 1);
41
+ function getPlatformBinaryName() {
42
+ const platform = import_node_os.default.platform();
43
+ const arch = import_node_os.default.arch();
44
+ if (platform === "darwin" && arch === "arm64") return "relay-pty-darwin-arm64";
45
+ if (platform === "darwin" && arch === "x64") return "relay-pty-darwin-x64";
46
+ if (platform === "linux" && arch === "arm64") return "relay-pty-linux-arm64";
47
+ if (platform === "linux" && arch === "x64") return "relay-pty-linux-x64";
48
+ return null;
49
+ }
50
+ let cachedBinaryPath;
51
+ let cacheChecked = false;
52
+ let lastSearchPaths = [];
53
+ function getLastSearchPaths() {
54
+ return [...lastSearchPaths];
55
+ }
56
+ function findRelayPtyBinary(callerDirname) {
57
+ const envOverride = process.env.RELAY_PTY_BINARY;
58
+ if (envOverride && import_node_fs.default.existsSync(envOverride)) {
59
+ lastSearchPaths = [envOverride];
60
+ return envOverride;
61
+ }
62
+ let packageRoot;
63
+ if (callerDirname.includes("node_modules/@agent-relay/")) {
64
+ packageRoot = import_node_path.default.join(callerDirname, "..", "..", "..", "..");
65
+ } else if (callerDirname.includes("node_modules/agent-relay")) {
66
+ packageRoot = import_node_path.default.join(callerDirname, "..", "..", "..");
67
+ } else {
68
+ packageRoot = import_node_path.default.join(callerDirname, "..", "..", "..");
69
+ }
70
+ let nodeModulesRoot = null;
71
+ const nodeModulesMatch = callerDirname.match(/^(.+?\/node_modules)\/@agent-relay\//);
72
+ if (nodeModulesMatch) {
73
+ nodeModulesRoot = nodeModulesMatch[1];
74
+ }
75
+ const platformBinary = getPlatformBinaryName();
76
+ const candidates = [
77
+ // Primary: installed by postinstall from platform-specific binary
78
+ import_node_path.default.join(packageRoot, "bin", "relay-pty"),
79
+ // Development: local Rust build
80
+ import_node_path.default.join(packageRoot, "relay-pty", "target", "release", "relay-pty"),
81
+ import_node_path.default.join(packageRoot, "relay-pty", "target", "debug", "relay-pty"),
82
+ // Local build in cwd (for development)
83
+ import_node_path.default.join(process.cwd(), "relay-pty", "target", "release", "relay-pty"),
84
+ // Docker container (CI tests)
85
+ "/app/bin/relay-pty",
86
+ // Installed globally
87
+ "/usr/local/bin/relay-pty",
88
+ // In node_modules (when installed as local dependency)
89
+ import_node_path.default.join(process.cwd(), "node_modules", "agent-relay", "bin", "relay-pty"),
90
+ // Global npm install (nvm) - root package
91
+ import_node_path.default.join(process.env.HOME || "", ".nvm", "versions", "node", process.version, "lib", "node_modules", "agent-relay", "bin", "relay-pty")
92
+ ];
93
+ if (nodeModulesRoot) {
94
+ candidates.push(import_node_path.default.join(nodeModulesRoot, "agent-relay", "bin", "relay-pty"));
95
+ }
96
+ if (process.env.HOME) {
97
+ candidates.push(import_node_path.default.join("/usr/local/lib/node_modules", "agent-relay", "bin", "relay-pty"));
98
+ candidates.push(import_node_path.default.join("/opt/homebrew/lib/node_modules", "agent-relay", "bin", "relay-pty"));
99
+ candidates.push(import_node_path.default.join(process.env.HOME, ".local", "share", "pnpm", "global", "node_modules", "agent-relay", "bin", "relay-pty"));
100
+ }
101
+ if (platformBinary) {
102
+ candidates.push(import_node_path.default.join(packageRoot, "bin", platformBinary));
103
+ candidates.push(import_node_path.default.join(process.cwd(), "node_modules", "agent-relay", "bin", platformBinary));
104
+ candidates.push(import_node_path.default.join(process.env.HOME || "", ".nvm", "versions", "node", process.version, "lib", "node_modules", "agent-relay", "bin", platformBinary));
105
+ if (nodeModulesRoot) {
106
+ candidates.push(import_node_path.default.join(nodeModulesRoot, "agent-relay", "bin", platformBinary));
107
+ }
108
+ if (process.env.HOME) {
109
+ candidates.push(import_node_path.default.join("/usr/local/lib/node_modules", "agent-relay", "bin", platformBinary));
110
+ candidates.push(import_node_path.default.join("/opt/homebrew/lib/node_modules", "agent-relay", "bin", platformBinary));
111
+ candidates.push(import_node_path.default.join(process.env.HOME, ".local", "share", "pnpm", "global", "node_modules", "agent-relay", "bin", platformBinary));
112
+ }
113
+ }
114
+ lastSearchPaths = candidates;
115
+ for (const candidate of candidates) {
116
+ if (import_node_fs.default.existsSync(candidate)) {
117
+ return candidate;
118
+ }
119
+ }
120
+ return null;
121
+ }
122
+ function hasRelayPtyBinary(callerDirname) {
123
+ if (!cacheChecked) {
124
+ cachedBinaryPath = findRelayPtyBinary(callerDirname);
125
+ cacheChecked = true;
126
+ }
127
+ return cachedBinaryPath !== null;
128
+ }
129
+ function getCachedRelayPtyPath() {
130
+ return cachedBinaryPath;
131
+ }
132
+ function clearBinaryCache() {
133
+ cachedBinaryPath = void 0;
134
+ cacheChecked = false;
135
+ }
136
+ // Annotate the CommonJS export names for ESM import in node:
137
+ 0 && (module.exports = {
138
+ clearBinaryCache,
139
+ findRelayPtyBinary,
140
+ getCachedRelayPtyPath,
141
+ getLastSearchPaths,
142
+ hasRelayPtyBinary
143
+ });
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var update_checker_exports = {};
30
+ __export(update_checker_exports, {
31
+ checkForUpdates: () => checkForUpdates,
32
+ checkForUpdatesInBackground: () => checkForUpdatesInBackground,
33
+ printUpdateNotification: () => printUpdateNotification
34
+ });
35
+ module.exports = __toCommonJS(update_checker_exports);
36
+ var import_node_fs = __toESM(require("node:fs"), 1);
37
+ var import_node_path = __toESM(require("node:path"), 1);
38
+ var import_node_https = __toESM(require("node:https"), 1);
39
+ var import_node_os = __toESM(require("node:os"), 1);
40
+ var import_compare_versions = require("compare-versions");
41
+ const PACKAGE_NAME = "agent-relay";
42
+ const CHECK_INTERVAL_MS = 60 * 60 * 1e3;
43
+ const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
44
+ function getCachePath() {
45
+ const cacheDir = import_node_path.default.join(import_node_os.default.homedir(), ".agent-relay");
46
+ return import_node_path.default.join(cacheDir, "update-cache.json");
47
+ }
48
+ function readCache() {
49
+ try {
50
+ const cachePath = getCachePath();
51
+ if (!import_node_fs.default.existsSync(cachePath)) return null;
52
+ const data = import_node_fs.default.readFileSync(cachePath, "utf-8");
53
+ return JSON.parse(data);
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+ function writeCache(cache) {
59
+ try {
60
+ const cachePath = getCachePath();
61
+ const cacheDir = import_node_path.default.dirname(cachePath);
62
+ if (!import_node_fs.default.existsSync(cacheDir)) {
63
+ import_node_fs.default.mkdirSync(cacheDir, { recursive: true });
64
+ }
65
+ import_node_fs.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
66
+ } catch {
67
+ }
68
+ }
69
+ function fetchLatestVersion() {
70
+ return new Promise((resolve, reject) => {
71
+ const req = import_node_https.default.get(NPM_REGISTRY_URL, { timeout: 5e3 }, (res) => {
72
+ if (res.statusCode === 301 || res.statusCode === 302) {
73
+ const location = res.headers.location;
74
+ if (location) {
75
+ import_node_https.default.get(location, { timeout: 5e3 }, (redirectRes) => {
76
+ handleResponse(redirectRes, resolve, reject);
77
+ }).on("error", reject);
78
+ return;
79
+ }
80
+ }
81
+ handleResponse(res, resolve, reject);
82
+ });
83
+ req.on("error", reject);
84
+ req.on("timeout", () => {
85
+ req.destroy();
86
+ reject(new Error("Request timed out"));
87
+ });
88
+ });
89
+ }
90
+ function handleResponse(res, resolve, reject) {
91
+ if (res.statusCode !== 200) {
92
+ reject(new Error(`HTTP ${res.statusCode}`));
93
+ return;
94
+ }
95
+ let data = "";
96
+ res.on("data", (chunk) => {
97
+ data += chunk.toString();
98
+ });
99
+ res.on("end", () => {
100
+ try {
101
+ const json = JSON.parse(data);
102
+ if (json.version) {
103
+ resolve(json.version);
104
+ } else {
105
+ reject(new Error("No version in response"));
106
+ }
107
+ } catch (err) {
108
+ reject(err);
109
+ }
110
+ });
111
+ res.on("error", reject);
112
+ }
113
+ async function checkForUpdates(currentVersion) {
114
+ const cache = readCache();
115
+ const now = Date.now();
116
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
117
+ const updateAvailable = cache.latestVersion ? (0, import_compare_versions.compare)(cache.latestVersion, currentVersion, ">") : false;
118
+ return {
119
+ updateAvailable,
120
+ currentVersion,
121
+ latestVersion: cache.latestVersion,
122
+ error: cache.error
123
+ };
124
+ }
125
+ try {
126
+ const latestVersion = await fetchLatestVersion();
127
+ const updateAvailable = (0, import_compare_versions.compare)(latestVersion, currentVersion, ">");
128
+ writeCache({
129
+ lastCheck: now,
130
+ latestVersion
131
+ });
132
+ return {
133
+ updateAvailable,
134
+ currentVersion,
135
+ latestVersion
136
+ };
137
+ } catch (err) {
138
+ const error = err.message;
139
+ writeCache({
140
+ lastCheck: now,
141
+ latestVersion: cache?.latestVersion || null,
142
+ error
143
+ });
144
+ return {
145
+ updateAvailable: false,
146
+ currentVersion,
147
+ latestVersion: cache?.latestVersion || null,
148
+ error
149
+ };
150
+ }
151
+ }
152
+ function printUpdateNotification(info) {
153
+ if (!info.updateAvailable || !info.latestVersion) return;
154
+ const line1 = `Update available: ${info.currentVersion} \u2192 ${info.latestVersion}`;
155
+ const line2 = "Run: npm install -g agent-relay";
156
+ const contentWidth = Math.max(line1.length, line2.length);
157
+ const boxWidth = contentWidth + 4;
158
+ const top = "\u256D" + "\u2500".repeat(boxWidth) + "\u256E";
159
+ const bottom = "\u2570" + "\u2500".repeat(boxWidth) + "\u256F";
160
+ const row1 = "\u2502 " + line1.padEnd(contentWidth) + " \u2502";
161
+ const row2 = "\u2502 " + line2.padEnd(contentWidth) + " \u2502";
162
+ console.error("");
163
+ console.error(top);
164
+ console.error(row1);
165
+ console.error(row2);
166
+ console.error(bottom);
167
+ console.error("");
168
+ }
169
+ function checkForUpdatesInBackground(currentVersion) {
170
+ if (process.env.AGENT_RELAY_SKIP_UPDATE_CHECK === "1") {
171
+ return;
172
+ }
173
+ checkForUpdates(currentVersion).then((info) => {
174
+ if (info.updateAvailable) {
175
+ printUpdateNotification(info);
176
+ }
177
+ }).catch(() => {
178
+ });
179
+ }
180
+ // Annotate the CommonJS export names for ESM import in node:
181
+ 0 && (module.exports = {
182
+ checkForUpdates,
183
+ checkForUpdatesInBackground,
184
+ printUpdateNotification
185
+ });
@@ -11,15 +11,21 @@
11
11
  * 3. Global npm install via nvm
12
12
  * 4. System-wide installs (/usr/local/bin)
13
13
  */
14
+ /**
15
+ * Get the paths that were checked in the last binary search.
16
+ * Useful for debugging when the binary is not found.
17
+ */
18
+ export declare function getLastSearchPaths(): string[];
14
19
  /**
15
20
  * Find the relay-pty binary.
16
21
  *
17
22
  * Search order:
18
- * 1. bin/relay-pty in package root (installed by postinstall)
19
- * 2. relay-pty/target/release/relay-pty (local Rust build)
20
- * 3. /usr/local/bin/relay-pty (global install)
21
- * 4. In node_modules when installed as dependency
22
- * 5. Global npm installs (nvm) - both scoped and root packages
23
+ * 1. RELAY_PTY_BINARY environment variable (explicit override)
24
+ * 2. bin/relay-pty in package root (installed by postinstall)
25
+ * 3. relay-pty/target/release/relay-pty (local Rust build)
26
+ * 4. /usr/local/bin/relay-pty (global install)
27
+ * 5. In node_modules when installed as dependency
28
+ * 6. Global npm installs (nvm) - both scoped and root packages
23
29
  *
24
30
  * @param callerDirname - The __dirname of the calling module (needed to resolve relative paths)
25
31
  * @returns Path to relay-pty binary, or null if not found
@@ -1 +1 @@
1
- {"version":3,"file":"relay-pty-path.d.ts","sourceRoot":"","sources":["../src/relay-pty-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwEvE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAMhE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS,CAEjE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
1
+ {"version":3,"file":"relay-pty-path.d.ts","sourceRoot":"","sources":["../src/relay-pty-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA8BH;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqGvE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAMhE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS,CAEjE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}