@agent-relay/utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Command Path Resolver
3
+ *
4
+ * Resolves full paths for CLI commands to avoid posix_spawnp failures
5
+ * when PATH isn't properly inherited in spawned processes.
6
+ */
7
+ /**
8
+ * Resolve the full path of a command using 'which' and resolve any symlinks
9
+ * Returns the full path if found, or the original command if not found
10
+ * (letting the spawn fail with a clearer error)
11
+ */
12
+ export declare function resolveCommand(command: string): string;
13
+ /**
14
+ * Check if a command exists in PATH
15
+ */
16
+ export declare function commandExists(command: string): boolean;
17
+ //# sourceMappingURL=command-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-resolver.d.ts","sourceRoot":"","sources":["../src/command-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6BtD;AAwBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAUtD"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Command Path Resolver
3
+ *
4
+ * Resolves full paths for CLI commands to avoid posix_spawnp failures
5
+ * when PATH isn't properly inherited in spawned processes.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ import fs from 'node:fs';
9
+ /**
10
+ * Resolve the full path of a command using 'which' and resolve any symlinks
11
+ * Returns the full path if found, or the original command if not found
12
+ * (letting the spawn fail with a clearer error)
13
+ */
14
+ export function resolveCommand(command) {
15
+ // If already an absolute path, just resolve symlinks
16
+ if (command.startsWith('/')) {
17
+ return resolveSymlinks(command);
18
+ }
19
+ try {
20
+ const output = execSync(`which ${command}`, {
21
+ encoding: 'utf-8',
22
+ stdio: ['pipe', 'pipe', 'pipe'],
23
+ // Ensure we have a reasonable PATH
24
+ env: {
25
+ ...process.env,
26
+ PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin',
27
+ },
28
+ });
29
+ const resolvedPath = output.trim();
30
+ if (resolvedPath) {
31
+ // Resolve any symlinks to get the actual binary path
32
+ // This fixes posix_spawnp issues with symlinked binaries
33
+ return resolveSymlinks(resolvedPath);
34
+ }
35
+ }
36
+ catch (err) {
37
+ // Command not found in PATH - log for debugging
38
+ console.warn(`[command-resolver] 'which ${command}' failed:`, err.message?.split('\n')[0] || 'unknown error');
39
+ }
40
+ // Return original command - spawn will fail with a clearer error
41
+ return command;
42
+ }
43
+ /**
44
+ * Resolve symlinks to get the actual file path
45
+ * Uses fs.realpathSync which handles all symlink levels
46
+ */
47
+ function resolveSymlinks(filePath) {
48
+ try {
49
+ const resolved = fs.realpathSync(filePath);
50
+ // Debug log only - symlink resolution is noisy
51
+ if (resolved !== filePath && process.env.DEBUG_SPAWN === '1') {
52
+ console.log(`[command-resolver] Resolved symlink: ${filePath} -> ${resolved}`);
53
+ }
54
+ return resolved;
55
+ }
56
+ catch (err) {
57
+ // If realpath fails, return original (spawn will give clearer error)
58
+ // Only warn in debug mode - this is common and not actionable
59
+ if (process.env.DEBUG_SPAWN === '1') {
60
+ console.warn(`[command-resolver] realpath failed for ${filePath}:`, err.message);
61
+ }
62
+ return filePath;
63
+ }
64
+ }
65
+ /**
66
+ * Check if a command exists in PATH
67
+ */
68
+ export function commandExists(command) {
69
+ try {
70
+ execSync(`which ${command}`, {
71
+ encoding: 'utf-8',
72
+ stdio: ['pipe', 'pipe', 'pipe'],
73
+ });
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ //# sourceMappingURL=command-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-resolver.js","sourceRoot":"","sources":["../src/command-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,qDAAqD;IACrD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,OAAO,EAAE,EAAE;YAC1C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,mCAAmC;YACnC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,gDAAgD;aAC3E;SACF,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,YAAY,EAAE,CAAC;YACjB,qDAAqD;YACrD,yDAAyD;YACzD,OAAO,eAAe,CAAC,YAAY,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,gDAAgD;QAChD,OAAO,CAAC,IAAI,CAAC,6BAA6B,OAAO,WAAW,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC;IAChH,CAAC;IAED,iEAAiE;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,+CAA+C;QAC/C,IAAI,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,EAAE,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,wCAAwC,QAAQ,OAAO,QAAQ,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,qEAAqE;QACrE,8DAA8D;QAC9D,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,0CAA0C,QAAQ,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,OAAO,EAAE,EAAE;YAC3B,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Error Tracking Utilities
3
+ *
4
+ * Provides traceable error IDs that users can report to support.
5
+ * Support can then search logs for the error ID to find full context.
6
+ *
7
+ * Error ID format: ERR-{timestamp}-{random}
8
+ * Example: ERR-1706012345-a7f3
9
+ *
10
+ * Usage:
11
+ * const error = createTraceableError('Failed to spawn agent', { agentName, cli });
12
+ * console.error(error.logMessage); // Full details for logs
13
+ * return { error: error.userMessage }; // Safe message with ID for user
14
+ */
15
+ export interface TraceableError {
16
+ /** Unique error ID for support lookup (e.g., ERR-1706012345-a7f3) */
17
+ errorId: string;
18
+ /** User-facing message with error ID (safe to display) */
19
+ userMessage: string;
20
+ /** Full log message with all context (for server logs) */
21
+ logMessage: string;
22
+ /** ISO timestamp when error occurred */
23
+ timestamp: string;
24
+ /** Original error message */
25
+ message: string;
26
+ /** Additional context data */
27
+ context: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Generate a unique error ID.
31
+ * Format: ERR-{unix_timestamp}-{4_random_hex_chars}
32
+ */
33
+ export declare function generateErrorId(): string;
34
+ /**
35
+ * Create a traceable error with ID for support lookup.
36
+ *
37
+ * @param message - Human-readable error description
38
+ * @param context - Additional context (agentName, workspaceId, etc.)
39
+ * @param originalError - Original error object if wrapping
40
+ * @returns TraceableError with ID, user message, and log message
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const error = createTraceableError('Failed to spawn agent', {
45
+ * agentName: 'Worker1',
46
+ * cli: 'claude',
47
+ * reason: 'timeout'
48
+ * });
49
+ *
50
+ * // Log full details for support
51
+ * console.error(error.logMessage);
52
+ * // => [ERR-1706012345-a7f3] Failed to spawn agent | agentName=Worker1 cli=claude reason=timeout
53
+ *
54
+ * // Return safe message to user
55
+ * res.status(500).json({ error: error.userMessage });
56
+ * // => "Failed to spawn agent (Error ID: ERR-1706012345-a7f3 - share this with support)"
57
+ * ```
58
+ */
59
+ export declare function createTraceableError(message: string, context?: Record<string, unknown>, originalError?: Error): TraceableError;
60
+ /**
61
+ * Log a traceable error and return user-safe response.
62
+ * Convenience wrapper that logs and returns in one call.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const { userMessage, errorId } = logAndTraceError(
67
+ * 'Workspace creation failed',
68
+ * { workspaceId, userId },
69
+ * err
70
+ * );
71
+ * res.status(500).json({ error: userMessage, errorId });
72
+ * ```
73
+ */
74
+ export declare function logAndTraceError(message: string, context?: Record<string, unknown>, originalError?: Error): TraceableError;
75
+ /**
76
+ * Wrap an async function to automatically trace errors.
77
+ * Useful for API handlers.
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * app.post('/api/spawn', withErrorTracing(async (req, res) => {
82
+ * // ... handler code
83
+ * // Errors automatically get traced
84
+ * }, { endpoint: '/api/spawn' }));
85
+ * ```
86
+ */
87
+ export declare function withErrorTracing<T extends (...args: unknown[]) => Promise<unknown>>(fn: T, baseContext?: Record<string, unknown>): T;
88
+ /**
89
+ * Error class that includes trace information.
90
+ * Thrown by withErrorTracing wrapper.
91
+ */
92
+ export declare class TracedError extends Error {
93
+ readonly errorId: string;
94
+ readonly userMessage: string;
95
+ readonly context: Record<string, unknown>;
96
+ constructor(traced: TraceableError);
97
+ }
98
+ /**
99
+ * Search hint for support: how to find errors in logs.
100
+ * Include this in documentation or support portal.
101
+ */
102
+ export declare const ERROR_SEARCH_HINT = "\nTo find error details in logs, search for the error ID:\n\n grep \"ERR-1706012345-a7f3\" /var/log/agent-relay/*.log\n\nOr in cloud logging:\n\n fly logs -a agent-relay-cloud | grep \"ERR-1706012345-a7f3\"\n\nThe log entry will include full context: user ID, workspace ID, agent name, etc.\n";
103
+ //# sourceMappingURL=error-tracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-tracking.d.ts","sourceRoot":"","sources":["../src/error-tracking.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,aAAa,CAAC,EAAE,KAAK,GACpB,cAAc,CA6BhB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,aAAa,CAAC,EAAE,KAAK,GACpB,cAAc,CAIhB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,EACjF,EAAE,EAAE,CAAC,EACL,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACxC,CAAC,CAaH;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,WAAW,EAAE,MAAM,CAAC;IACpC,SAAgB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAErC,MAAM,EAAE,cAAc;CAOnC;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,2SAU7B,CAAC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Error Tracking Utilities
3
+ *
4
+ * Provides traceable error IDs that users can report to support.
5
+ * Support can then search logs for the error ID to find full context.
6
+ *
7
+ * Error ID format: ERR-{timestamp}-{random}
8
+ * Example: ERR-1706012345-a7f3
9
+ *
10
+ * Usage:
11
+ * const error = createTraceableError('Failed to spawn agent', { agentName, cli });
12
+ * console.error(error.logMessage); // Full details for logs
13
+ * return { error: error.userMessage }; // Safe message with ID for user
14
+ */
15
+ import { randomBytes } from 'node:crypto';
16
+ /**
17
+ * Generate a unique error ID.
18
+ * Format: ERR-{unix_timestamp}-{4_random_hex_chars}
19
+ */
20
+ export function generateErrorId() {
21
+ const timestamp = Math.floor(Date.now() / 1000);
22
+ const random = randomBytes(2).toString('hex');
23
+ return `ERR-${timestamp}-${random}`;
24
+ }
25
+ /**
26
+ * Create a traceable error with ID for support lookup.
27
+ *
28
+ * @param message - Human-readable error description
29
+ * @param context - Additional context (agentName, workspaceId, etc.)
30
+ * @param originalError - Original error object if wrapping
31
+ * @returns TraceableError with ID, user message, and log message
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const error = createTraceableError('Failed to spawn agent', {
36
+ * agentName: 'Worker1',
37
+ * cli: 'claude',
38
+ * reason: 'timeout'
39
+ * });
40
+ *
41
+ * // Log full details for support
42
+ * console.error(error.logMessage);
43
+ * // => [ERR-1706012345-a7f3] Failed to spawn agent | agentName=Worker1 cli=claude reason=timeout
44
+ *
45
+ * // Return safe message to user
46
+ * res.status(500).json({ error: error.userMessage });
47
+ * // => "Failed to spawn agent (Error ID: ERR-1706012345-a7f3 - share this with support)"
48
+ * ```
49
+ */
50
+ export function createTraceableError(message, context = {}, originalError) {
51
+ const errorId = generateErrorId();
52
+ const timestamp = new Date().toISOString();
53
+ // Build context string for logging
54
+ const contextPairs = Object.entries(context)
55
+ .filter(([, v]) => v !== undefined && v !== null)
56
+ .map(([k, v]) => `${k}=${typeof v === 'object' ? JSON.stringify(v) : v}`)
57
+ .join(' ');
58
+ // Include original error stack if available
59
+ const stackInfo = originalError?.stack
60
+ ? `\n Original error: ${originalError.message}\n Stack: ${originalError.stack}`
61
+ : '';
62
+ const logMessage = `[${errorId}] ${message}${contextPairs ? ` | ${contextPairs}` : ''}${stackInfo}`;
63
+ const userMessage = `${message} (Error ID: ${errorId} - share this with support)`;
64
+ return {
65
+ errorId,
66
+ userMessage,
67
+ logMessage,
68
+ timestamp,
69
+ message,
70
+ context: {
71
+ ...context,
72
+ originalError: originalError?.message,
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * Log a traceable error and return user-safe response.
78
+ * Convenience wrapper that logs and returns in one call.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const { userMessage, errorId } = logAndTraceError(
83
+ * 'Workspace creation failed',
84
+ * { workspaceId, userId },
85
+ * err
86
+ * );
87
+ * res.status(500).json({ error: userMessage, errorId });
88
+ * ```
89
+ */
90
+ export function logAndTraceError(message, context = {}, originalError) {
91
+ const error = createTraceableError(message, context, originalError);
92
+ console.error(error.logMessage);
93
+ return error;
94
+ }
95
+ /**
96
+ * Wrap an async function to automatically trace errors.
97
+ * Useful for API handlers.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * app.post('/api/spawn', withErrorTracing(async (req, res) => {
102
+ * // ... handler code
103
+ * // Errors automatically get traced
104
+ * }, { endpoint: '/api/spawn' }));
105
+ * ```
106
+ */
107
+ export function withErrorTracing(fn, baseContext = {}) {
108
+ return (async (...args) => {
109
+ try {
110
+ return await fn(...args);
111
+ }
112
+ catch (err) {
113
+ const error = logAndTraceError(err instanceof Error ? err.message : 'Unknown error', baseContext, err instanceof Error ? err : undefined);
114
+ throw new TracedError(error);
115
+ }
116
+ });
117
+ }
118
+ /**
119
+ * Error class that includes trace information.
120
+ * Thrown by withErrorTracing wrapper.
121
+ */
122
+ export class TracedError extends Error {
123
+ errorId;
124
+ userMessage;
125
+ context;
126
+ constructor(traced) {
127
+ super(traced.message);
128
+ this.name = 'TracedError';
129
+ this.errorId = traced.errorId;
130
+ this.userMessage = traced.userMessage;
131
+ this.context = traced.context;
132
+ }
133
+ }
134
+ /**
135
+ * Search hint for support: how to find errors in logs.
136
+ * Include this in documentation or support portal.
137
+ */
138
+ export const ERROR_SEARCH_HINT = `
139
+ To find error details in logs, search for the error ID:
140
+
141
+ grep "ERR-1706012345-a7f3" /var/log/agent-relay/*.log
142
+
143
+ Or in cloud logging:
144
+
145
+ fly logs -a agent-relay-cloud | grep "ERR-1706012345-a7f3"
146
+
147
+ The log entry will include full context: user ID, workspace ID, agent name, etc.
148
+ `;
149
+ //# sourceMappingURL=error-tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-tracking.js","sourceRoot":"","sources":["../src/error-tracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
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
+ /**
8
+ * Parse a git remote URL to extract owner/repo format.
9
+ *
10
+ * Supports:
11
+ * - git@github.com:owner/repo.git
12
+ * - https://github.com/owner/repo.git
13
+ * - https://github.com/owner/repo
14
+ * - git://github.com/owner/repo.git
15
+ */
16
+ export declare function parseGitRemoteUrl(url: string): string | null;
17
+ /**
18
+ * Get the git remote URL from a directory.
19
+ *
20
+ * @param workingDirectory The directory to check for git remote
21
+ * @param remoteName The remote name to use (default: 'origin')
22
+ * @returns The remote URL or null if not found
23
+ */
24
+ export declare function getGitRemoteUrl(workingDirectory: string, remoteName?: string): string | null;
25
+ /**
26
+ * Get the repository full name (owner/repo) from a working directory.
27
+ *
28
+ * @param workingDirectory The directory to check
29
+ * @returns The repo full name (e.g., "AgentWorkforce/relay") or null
30
+ */
31
+ export declare function getRepoFullName(workingDirectory: string): string | null;
32
+ /**
33
+ * Find the git root directory from a given path.
34
+ * Walks up the directory tree looking for .git folder.
35
+ *
36
+ * @param startPath The path to start searching from
37
+ * @returns The git root directory or null if not in a git repo
38
+ */
39
+ export declare function findGitRoot(startPath: string): string | null;
40
+ /**
41
+ * Get repository full name, walking up to find git root if needed.
42
+ *
43
+ * @param workingDirectory The directory to start from
44
+ * @returns The repo full name or null
45
+ */
46
+ export declare function getRepoFullNameFromPath(workingDirectory: string): string | null;
47
+ //# sourceMappingURL=git-remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-remote.d.ts","sourceRoot":"","sources":["../src/git-remote.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB5D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,EAAE,UAAU,SAAW,GAAG,MAAM,GAAG,IAAI,CAuC9F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc/E"}
@@ -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 @@
1
+ {"version":3,"file":"git-remote.js","sourceRoot":"","sources":["../src/git-remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from './name-generator.js';
2
+ export * from './logger.js';
3
+ export * from './precompiled-patterns.js';
4
+ export * from './command-resolver.js';
5
+ export * from './git-remote.js';
6
+ export * from './update-checker.js';
7
+ export * from './error-tracking.js';
8
+ export * from './model-mapping.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export * from './name-generator.js';
2
+ export * from './logger.js';
3
+ export * from './precompiled-patterns.js';
4
+ export * from './command-resolver.js';
5
+ export * from './git-remote.js';
6
+ export * from './update-checker.js';
7
+ export * from './error-tracking.js';
8
+ export * from './model-mapping.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Lightweight DIY Logger for Agent Relay
3
+ *
4
+ * Minimal logging utility (~50 lines) with:
5
+ * - JSON output for easy parsing with jq
6
+ * - Configurable via environment variables
7
+ * - Debug-only verbose logging
8
+ * - No external dependencies
9
+ */
10
+ export type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
11
+ /**
12
+ * Create a logger for a specific component.
13
+ * @param component - Component name (e.g., 'daemon', 'router', 'connection')
14
+ */
15
+ export declare function createLogger(component: string): {
16
+ debug: (msg: string, extra?: Record<string, unknown>) => void;
17
+ info: (msg: string, extra?: Record<string, unknown>) => void;
18
+ warn: (msg: string, extra?: Record<string, unknown>) => void;
19
+ error: (msg: string, extra?: Record<string, unknown>) => void;
20
+ };
21
+ export declare const daemonLog: {
22
+ debug: (msg: string, extra?: Record<string, unknown>) => void;
23
+ info: (msg: string, extra?: Record<string, unknown>) => void;
24
+ warn: (msg: string, extra?: Record<string, unknown>) => void;
25
+ error: (msg: string, extra?: Record<string, unknown>) => void;
26
+ };
27
+ export declare const routerLog: {
28
+ debug: (msg: string, extra?: Record<string, unknown>) => void;
29
+ info: (msg: string, extra?: Record<string, unknown>) => void;
30
+ warn: (msg: string, extra?: Record<string, unknown>) => void;
31
+ error: (msg: string, extra?: Record<string, unknown>) => void;
32
+ };
33
+ export declare const connectionLog: {
34
+ debug: (msg: string, extra?: Record<string, unknown>) => void;
35
+ info: (msg: string, extra?: Record<string, unknown>) => void;
36
+ warn: (msg: string, extra?: Record<string, unknown>) => void;
37
+ error: (msg: string, extra?: Record<string, unknown>) => void;
38
+ };
39
+ export default createLogger;
40
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAwE3D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM;iBAE7B,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACxC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACvC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;EAEvD;AAGD,eAAO,MAAM,SAAS;iBARL,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACxC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACvC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKT,CAAC;AAChD,eAAO,MAAM,SAAS;iBATL,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACxC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACvC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAMT,CAAC;AAChD,eAAO,MAAM,aAAa;iBAVT,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACxC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACvC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtC,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOD,CAAC;AAGxD,eAAe,YAAY,CAAC"}