agent-relay 2.0.19 → 2.0.21

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 (142) hide show
  1. package/CHANGELOG.md +217 -24
  2. package/bin/relay-pty-darwin-arm64 +0 -0
  3. package/bin/relay-pty-darwin-x64 +0 -0
  4. package/bin/relay-pty-linux-x64 +0 -0
  5. package/dist/dashboard/out/404.html +1 -1
  6. package/dist/dashboard/out/app/onboarding.html +1 -1
  7. package/dist/dashboard/out/app/onboarding.txt +1 -1
  8. package/dist/dashboard/out/app.html +1 -1
  9. package/dist/dashboard/out/app.txt +1 -1
  10. package/dist/dashboard/out/cloud/link.html +1 -1
  11. package/dist/dashboard/out/cloud/link.txt +1 -1
  12. package/dist/dashboard/out/complete-profile.html +1 -1
  13. package/dist/dashboard/out/complete-profile.txt +1 -1
  14. package/dist/dashboard/out/connect-repos.html +1 -1
  15. package/dist/dashboard/out/connect-repos.txt +1 -1
  16. package/dist/dashboard/out/history.html +1 -1
  17. package/dist/dashboard/out/history.txt +1 -1
  18. package/dist/dashboard/out/index.html +1 -1
  19. package/dist/dashboard/out/index.txt +1 -1
  20. package/dist/dashboard/out/login.html +1 -1
  21. package/dist/dashboard/out/login.txt +1 -1
  22. package/dist/dashboard/out/metrics.html +1 -1
  23. package/dist/dashboard/out/metrics.txt +1 -1
  24. package/dist/dashboard/out/pricing.html +1 -1
  25. package/dist/dashboard/out/pricing.txt +1 -1
  26. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  27. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  28. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  29. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  30. package/dist/dashboard/out/providers/setup/cursor.html +1 -1
  31. package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
  32. package/dist/dashboard/out/providers.html +1 -1
  33. package/dist/dashboard/out/providers.txt +1 -1
  34. package/dist/dashboard/out/signup.html +1 -1
  35. package/dist/dashboard/out/signup.txt +1 -1
  36. package/package.json +23 -17
  37. package/packages/api-types/package.json +2 -2
  38. package/packages/bridge/dist/spawner.d.ts +2 -0
  39. package/packages/bridge/dist/spawner.js +76 -24
  40. package/packages/bridge/package.json +8 -8
  41. package/packages/cli-tester/README.md +277 -0
  42. package/packages/cli-tester/dist/index.d.ts +21 -0
  43. package/packages/cli-tester/dist/index.js +21 -0
  44. package/packages/cli-tester/dist/utils/credential-check.d.ts +56 -0
  45. package/packages/cli-tester/dist/utils/credential-check.js +230 -0
  46. package/packages/cli-tester/dist/utils/socket-client.d.ts +76 -0
  47. package/packages/cli-tester/dist/utils/socket-client.js +153 -0
  48. package/packages/cli-tester/docker/entrypoint.sh +58 -0
  49. package/packages/cli-tester/package.json +32 -0
  50. package/packages/cli-tester/scripts/clear-auth.sh +101 -0
  51. package/packages/cli-tester/scripts/inject-message.sh +42 -0
  52. package/packages/cli-tester/scripts/start.sh +71 -0
  53. package/packages/cli-tester/scripts/test-cli.sh +56 -0
  54. package/packages/cli-tester/scripts/test-full-spawn.sh +238 -0
  55. package/packages/cli-tester/scripts/test-registration.sh +182 -0
  56. package/packages/cli-tester/scripts/test-setup-flow.sh +202 -0
  57. package/packages/cli-tester/scripts/test-spawn.sh +140 -0
  58. package/packages/cli-tester/scripts/test-with-daemon.sh +247 -0
  59. package/packages/cli-tester/scripts/verify-auth.sh +112 -0
  60. package/packages/cloud/package.json +6 -6
  61. package/packages/config/dist/cli-auth-config.js +65 -0
  62. package/packages/config/package.json +2 -2
  63. package/packages/continuity/package.json +1 -1
  64. package/packages/daemon/dist/router.js +4 -4
  65. package/packages/daemon/dist/server.js +38 -19
  66. package/packages/daemon/dist/spawn-manager.d.ts +4 -0
  67. package/packages/daemon/dist/spawn-manager.js +2 -0
  68. package/packages/daemon/package.json +12 -12
  69. package/packages/dashboard/dist/server.js +4 -0
  70. package/packages/dashboard/package.json +14 -14
  71. package/packages/dashboard/ui-dist/404.html +1 -1
  72. package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
  73. package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
  74. package/packages/dashboard/ui-dist/app.html +1 -1
  75. package/packages/dashboard/ui-dist/app.txt +1 -1
  76. package/packages/dashboard/ui-dist/cloud/link.html +1 -1
  77. package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
  78. package/packages/dashboard/ui-dist/complete-profile.html +1 -1
  79. package/packages/dashboard/ui-dist/complete-profile.txt +1 -1
  80. package/packages/dashboard/ui-dist/connect-repos.html +1 -1
  81. package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
  82. package/packages/dashboard/ui-dist/history.html +1 -1
  83. package/packages/dashboard/ui-dist/history.txt +1 -1
  84. package/packages/dashboard/ui-dist/index.html +1 -1
  85. package/packages/dashboard/ui-dist/index.txt +1 -1
  86. package/packages/dashboard/ui-dist/login.html +1 -1
  87. package/packages/dashboard/ui-dist/login.txt +1 -1
  88. package/packages/dashboard/ui-dist/metrics.html +1 -1
  89. package/packages/dashboard/ui-dist/metrics.txt +1 -1
  90. package/packages/dashboard/ui-dist/pricing.html +1 -1
  91. package/packages/dashboard/ui-dist/pricing.txt +1 -1
  92. package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
  93. package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
  94. package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
  95. package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
  96. package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
  97. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
  98. package/packages/dashboard/ui-dist/providers.html +1 -1
  99. package/packages/dashboard/ui-dist/providers.txt +1 -1
  100. package/packages/dashboard/ui-dist/signup.html +1 -1
  101. package/packages/dashboard/ui-dist/signup.txt +1 -1
  102. package/packages/dashboard-server/dist/server.js +4 -0
  103. package/packages/dashboard-server/package.json +12 -12
  104. package/packages/hooks/package.json +4 -4
  105. package/packages/mcp/package.json +2 -2
  106. package/packages/memory/package.json +2 -2
  107. package/packages/policy/package.json +2 -2
  108. package/packages/protocol/package.json +1 -1
  109. package/packages/resiliency/package.json +1 -1
  110. package/packages/sdk/README.md +512 -58
  111. package/packages/sdk/dist/client.d.ts +135 -1
  112. package/packages/sdk/dist/client.js +338 -0
  113. package/packages/sdk/dist/index.d.ts +2 -1
  114. package/packages/sdk/dist/index.js +2 -0
  115. package/packages/sdk/dist/logs.d.ts +61 -0
  116. package/packages/sdk/dist/logs.js +95 -0
  117. package/packages/sdk/dist/protocol/index.d.ts +1 -1
  118. package/packages/sdk/dist/protocol/types.d.ts +186 -1
  119. package/packages/sdk/package.json +3 -3
  120. package/packages/spawner/package.json +2 -2
  121. package/packages/state/package.json +1 -1
  122. package/packages/storage/dist/sqlite-adapter.js +2 -0
  123. package/packages/storage/package.json +2 -2
  124. package/packages/telemetry/package.json +1 -1
  125. package/packages/trajectory/package.json +2 -2
  126. package/packages/user-directory/package.json +2 -2
  127. package/packages/utils/package.json +1 -1
  128. package/packages/wrapper/dist/base-wrapper.js +27 -10
  129. package/packages/wrapper/dist/relay-pty-orchestrator.js +16 -16
  130. package/packages/wrapper/dist/tmux-wrapper.js +16 -0
  131. package/packages/wrapper/package.json +7 -7
  132. package/scripts/hooks/install.sh +16 -0
  133. package/scripts/hooks/pre-commit +60 -0
  134. package/specs/PRIMITIVES_ROADMAP.md +2154 -0
  135. /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
  136. /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
  137. /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
  138. /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
  139. /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_buildManifest.js +0 -0
  140. /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_ssgManifest.js +0 -0
  141. /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_buildManifest.js +0 -0
  142. /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_ssgManifest.js +0 -0
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Log reading utilities for Agent Relay SDK.
3
+ *
4
+ * These utilities read agent logs from the local filesystem.
5
+ */
6
+ import { readFile, readdir, stat } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ /**
9
+ * Get the default logs directory path.
10
+ */
11
+ function getDefaultLogsDir() {
12
+ return join(process.cwd(), '.agent-relay', 'worker-logs');
13
+ }
14
+ /**
15
+ * Read the last N lines from a file.
16
+ */
17
+ async function tailFile(filePath, lines) {
18
+ try {
19
+ const content = await readFile(filePath, 'utf-8');
20
+ const allLines = content.split('\n');
21
+ const tailLines = allLines.slice(-lines);
22
+ return tailLines.join('\n').trim();
23
+ }
24
+ catch {
25
+ return '';
26
+ }
27
+ }
28
+ /**
29
+ * Get logs for a specific agent.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * import { getLogs } from '@agent-relay/sdk';
34
+ *
35
+ * const result = await getLogs('Worker1', { lines: 100 });
36
+ * if (result.found) {
37
+ * console.log(result.content);
38
+ * }
39
+ * ```
40
+ *
41
+ * @param agent - Agent name
42
+ * @param options - Options for reading logs
43
+ * @returns Log content and metadata
44
+ */
45
+ export async function getLogs(agent, options = {}) {
46
+ const logsDir = options.logsDir ?? getDefaultLogsDir();
47
+ const lines = options.lines ?? 50;
48
+ const logFile = join(logsDir, `${agent}.log`);
49
+ try {
50
+ await stat(logFile);
51
+ const content = await tailFile(logFile, lines);
52
+ const lineCount = content ? content.split('\n').length : 0;
53
+ return {
54
+ agent,
55
+ content,
56
+ found: true,
57
+ lineCount,
58
+ };
59
+ }
60
+ catch {
61
+ return {
62
+ agent,
63
+ content: '',
64
+ found: false,
65
+ lineCount: 0,
66
+ };
67
+ }
68
+ }
69
+ /**
70
+ * List all agents that have log files.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * import { listLoggedAgents } from '@agent-relay/sdk';
75
+ *
76
+ * const agents = await listLoggedAgents();
77
+ * console.log('Agents with logs:', agents);
78
+ * ```
79
+ *
80
+ * @param logsDir - Directory containing worker logs
81
+ * @returns Array of agent names
82
+ */
83
+ export async function listLoggedAgents(logsDir) {
84
+ const dir = logsDir ?? getDefaultLogsDir();
85
+ try {
86
+ const files = await readdir(dir);
87
+ return files
88
+ .filter((f) => f.endsWith('.log'))
89
+ .map((f) => f.replace('.log', ''));
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ //# sourceMappingURL=logs.js.map
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Protocol exports for @agent-relay/sdk
3
3
  */
4
- export { PROTOCOL_VERSION, type MessageType, type PayloadKind, type Envelope, type EntityType, type HelloPayload, type WelcomePayload, type SendPayload, type SendMeta, type SyncMeta, type DeliveryInfo, type AckPayload, type NackPayload, type BusyPayload, type PingPayload, type PongPayload, type ErrorCode, type ErrorPayload, type LogPayload, type SyncStream, type SyncPayload, type SpeakOnTrigger, type ShadowConfig, type ShadowBindPayload, type ShadowUnbindPayload, type SpawnPayload, type SpawnPolicyDecision, type SpawnResultPayload, type ReleasePayload, type ReleaseResultPayload, type MessageAttachment, type ChannelJoinPayload, type ChannelLeavePayload, type ChannelMessagePayload, type HelloEnvelope, type WelcomeEnvelope, type SendEnvelope, type DeliverEnvelope, type AckEnvelope, type NackEnvelope, type PingEnvelope, type PongEnvelope, type ErrorEnvelope, type BusyEnvelope, type LogEnvelope, type SyncEnvelope, type ShadowBindEnvelope, type ShadowUnbindEnvelope, type SpawnEnvelope, type SpawnResultEnvelope, type ReleaseEnvelope, type ReleaseResultEnvelope, type ChannelJoinEnvelope, type ChannelLeaveEnvelope, type ChannelMessageEnvelope, } from './types.js';
4
+ export { PROTOCOL_VERSION, type MessageType, type PayloadKind, type Envelope, type EntityType, type HelloPayload, type WelcomePayload, type SendPayload, type SendMeta, type SyncMeta, type DeliveryInfo, type AckPayload, type NackPayload, type BusyPayload, type PingPayload, type PongPayload, type ErrorCode, type ErrorPayload, type LogPayload, type SyncStream, type SyncPayload, type SpeakOnTrigger, type ShadowConfig, type ShadowBindPayload, type ShadowUnbindPayload, type SpawnPayload, type SpawnPolicyDecision, type SpawnResultPayload, type ReleasePayload, type ReleaseResultPayload, type ConsensusType, type VoteValue, type ProposalStatus, type CreateProposalOptions, type VoteOptions, type MessageAttachment, type ChannelJoinPayload, type ChannelLeavePayload, type ChannelMessagePayload, type StatusPayload, type StatusResponsePayload, type InboxPayload, type InboxMessage, type InboxResponsePayload, type ListAgentsPayload, type AgentInfo, type ListAgentsResponsePayload, type HealthPayload, type CrashRecord, type AlertRecord, type HealthResponsePayload, type MetricsPayload, type AgentMetrics, type MetricsResponsePayload, type HelloEnvelope, type WelcomeEnvelope, type SendEnvelope, type DeliverEnvelope, type AckEnvelope, type NackEnvelope, type PingEnvelope, type PongEnvelope, type ErrorEnvelope, type BusyEnvelope, type LogEnvelope, type SyncEnvelope, type ShadowBindEnvelope, type ShadowUnbindEnvelope, type SpawnEnvelope, type SpawnResultEnvelope, type ReleaseEnvelope, type ReleaseResultEnvelope, type ChannelJoinEnvelope, type ChannelLeaveEnvelope, type ChannelMessageEnvelope, type StatusEnvelope, type StatusResponseEnvelope, type InboxEnvelope, type InboxResponseEnvelope, type ListAgentsEnvelope, type ListAgentsResponseEnvelope, type HealthEnvelope, type HealthResponseEnvelope, type MetricsEnvelope, type MetricsResponseEnvelope, } from './types.js';
5
5
  export { MAX_FRAME_BYTES, HEADER_SIZE, LEGACY_HEADER_SIZE, type WireFormat, initMessagePack, hasMessagePack, encodeFrame, encodeFrameLegacy, FrameParser, } from './framing.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -5,7 +5,7 @@
5
5
  * These types define the wire protocol for agent-to-agent communication.
6
6
  */
7
7
  export declare const PROTOCOL_VERSION = 1;
8
- export type MessageType = 'HELLO' | 'WELCOME' | 'SEND' | 'DELIVER' | 'ACK' | 'NACK' | 'PING' | 'PONG' | 'ERROR' | 'BUSY' | 'RESUME' | 'BYE' | 'STATE' | 'SYNC' | 'SYNC_SNAPSHOT' | 'SYNC_DELTA' | 'SUBSCRIBE' | 'UNSUBSCRIBE' | 'SHADOW_BIND' | 'SHADOW_UNBIND' | 'LOG' | 'CHANNEL_JOIN' | 'CHANNEL_LEAVE' | 'CHANNEL_MESSAGE' | 'CHANNEL_INFO' | 'CHANNEL_MEMBERS' | 'CHANNEL_TYPING' | 'SPAWN' | 'SPAWN_RESULT' | 'RELEASE' | 'RELEASE_RESULT';
8
+ export type MessageType = 'HELLO' | 'WELCOME' | 'SEND' | 'DELIVER' | 'ACK' | 'NACK' | 'PING' | 'PONG' | 'ERROR' | 'BUSY' | 'RESUME' | 'BYE' | 'STATE' | 'SYNC' | 'SYNC_SNAPSHOT' | 'SYNC_DELTA' | 'SUBSCRIBE' | 'UNSUBSCRIBE' | 'SHADOW_BIND' | 'SHADOW_UNBIND' | 'LOG' | 'CHANNEL_JOIN' | 'CHANNEL_LEAVE' | 'CHANNEL_MESSAGE' | 'CHANNEL_INFO' | 'CHANNEL_MEMBERS' | 'CHANNEL_TYPING' | 'SPAWN' | 'SPAWN_RESULT' | 'RELEASE' | 'RELEASE_RESULT' | 'STATUS' | 'STATUS_RESPONSE' | 'INBOX' | 'INBOX_RESPONSE' | 'LIST_AGENTS' | 'LIST_AGENTS_RESPONSE' | 'HEALTH' | 'HEALTH_RESPONSE' | 'METRICS' | 'METRICS_RESPONSE';
9
9
  export type PayloadKind = 'message' | 'action' | 'state' | 'thinking';
10
10
  /**
11
11
  * Base envelope structure for all protocol messages.
@@ -312,6 +312,181 @@ export interface ReleaseResultPayload {
312
312
  /** Error message (if failed) */
313
313
  error?: string;
314
314
  }
315
+ export type ConsensusType = 'majority' | 'supermajority' | 'unanimous' | 'weighted' | 'quorum';
316
+ export type VoteValue = 'approve' | 'reject' | 'abstain';
317
+ export type ProposalStatus = 'pending' | 'approved' | 'rejected' | 'expired' | 'cancelled';
318
+ /**
319
+ * Options for creating a consensus proposal.
320
+ */
321
+ export interface CreateProposalOptions {
322
+ /** Proposal title */
323
+ title: string;
324
+ /** Detailed description */
325
+ description: string;
326
+ /** Agents allowed to vote */
327
+ participants: string[];
328
+ /** Consensus type (default: majority) */
329
+ consensusType?: ConsensusType;
330
+ /** Timeout in milliseconds (default: 5 minutes) */
331
+ timeoutMs?: number;
332
+ /** Minimum votes required (for quorum type) */
333
+ quorum?: number;
334
+ /** Threshold for supermajority (0-1, default 0.67) */
335
+ threshold?: number;
336
+ }
337
+ /**
338
+ * Options for voting on a proposal.
339
+ */
340
+ export interface VoteOptions {
341
+ /** Proposal ID to vote on */
342
+ proposalId: string;
343
+ /** Vote value */
344
+ value: VoteValue;
345
+ /** Optional reason for the vote */
346
+ reason?: string;
347
+ }
348
+ /**
349
+ * Payload for STATUS request.
350
+ */
351
+ export interface StatusPayload {
352
+ }
353
+ /**
354
+ * Response payload for STATUS request.
355
+ */
356
+ export interface StatusResponsePayload {
357
+ version?: string;
358
+ uptime?: number;
359
+ agentCount?: number;
360
+ messageCount?: number;
361
+ }
362
+ /**
363
+ * Payload for INBOX request.
364
+ */
365
+ export interface InboxPayload {
366
+ agent: string;
367
+ limit?: number;
368
+ unreadOnly?: boolean;
369
+ from?: string;
370
+ channel?: string;
371
+ }
372
+ /**
373
+ * A stored message in the inbox.
374
+ */
375
+ export interface InboxMessage {
376
+ id: string;
377
+ from: string;
378
+ body: string;
379
+ channel?: string;
380
+ thread?: string;
381
+ timestamp: number;
382
+ }
383
+ /**
384
+ * Response payload for INBOX request.
385
+ */
386
+ export interface InboxResponsePayload {
387
+ messages: InboxMessage[];
388
+ }
389
+ /**
390
+ * Payload for LIST_AGENTS request.
391
+ */
392
+ export interface ListAgentsPayload {
393
+ includeIdle?: boolean;
394
+ project?: string;
395
+ }
396
+ /**
397
+ * Agent info returned by LIST_AGENTS.
398
+ */
399
+ export interface AgentInfo {
400
+ name: string;
401
+ cli?: string;
402
+ idle?: boolean;
403
+ parent?: string;
404
+ task?: string;
405
+ connectedAt?: number;
406
+ }
407
+ /**
408
+ * Response payload for LIST_AGENTS request.
409
+ */
410
+ export interface ListAgentsResponsePayload {
411
+ agents: AgentInfo[];
412
+ }
413
+ /**
414
+ * Payload for HEALTH request.
415
+ */
416
+ export interface HealthPayload {
417
+ includeCrashes?: boolean;
418
+ includeAlerts?: boolean;
419
+ }
420
+ /**
421
+ * A crash record.
422
+ */
423
+ export interface CrashRecord {
424
+ id: string;
425
+ agentName: string;
426
+ crashedAt: string;
427
+ likelyCause: string;
428
+ summary?: string;
429
+ }
430
+ /**
431
+ * An alert record.
432
+ */
433
+ export interface AlertRecord {
434
+ id: string;
435
+ agentName: string;
436
+ alertType: string;
437
+ message: string;
438
+ createdAt: string;
439
+ }
440
+ /**
441
+ * Response payload for HEALTH request.
442
+ */
443
+ export interface HealthResponsePayload {
444
+ healthScore: number;
445
+ summary: string;
446
+ issues: Array<{
447
+ severity: string;
448
+ message: string;
449
+ }>;
450
+ recommendations: string[];
451
+ crashes: CrashRecord[];
452
+ alerts: AlertRecord[];
453
+ stats: {
454
+ totalCrashes24h: number;
455
+ totalAlerts24h: number;
456
+ agentCount: number;
457
+ };
458
+ }
459
+ /**
460
+ * Payload for METRICS request.
461
+ */
462
+ export interface MetricsPayload {
463
+ agent?: string;
464
+ }
465
+ /**
466
+ * Metrics for a single agent.
467
+ */
468
+ export interface AgentMetrics {
469
+ name: string;
470
+ pid?: number;
471
+ status: string;
472
+ rssBytes?: number;
473
+ cpuPercent?: number;
474
+ trend?: string;
475
+ alertLevel?: string;
476
+ highWatermark?: number;
477
+ uptimeMs?: number;
478
+ }
479
+ /**
480
+ * Response payload for METRICS request.
481
+ */
482
+ export interface MetricsResponsePayload {
483
+ agents: AgentMetrics[];
484
+ system: {
485
+ totalMemory: number;
486
+ freeMemory: number;
487
+ heapUsed: number;
488
+ };
489
+ }
315
490
  export type HelloEnvelope = Envelope<HelloPayload>;
316
491
  export type WelcomeEnvelope = Envelope<WelcomePayload>;
317
492
  export type SendEnvelope = Envelope<SendPayload> & {
@@ -338,4 +513,14 @@ export type ReleaseResultEnvelope = Envelope<ReleaseResultPayload>;
338
513
  export type ChannelJoinEnvelope = Envelope<ChannelJoinPayload>;
339
514
  export type ChannelLeaveEnvelope = Envelope<ChannelLeavePayload>;
340
515
  export type ChannelMessageEnvelope = Envelope<ChannelMessagePayload>;
516
+ export type StatusEnvelope = Envelope<StatusPayload>;
517
+ export type StatusResponseEnvelope = Envelope<StatusResponsePayload>;
518
+ export type InboxEnvelope = Envelope<InboxPayload>;
519
+ export type InboxResponseEnvelope = Envelope<InboxResponsePayload>;
520
+ export type ListAgentsEnvelope = Envelope<ListAgentsPayload>;
521
+ export type ListAgentsResponseEnvelope = Envelope<ListAgentsResponsePayload>;
522
+ export type HealthEnvelope = Envelope<HealthPayload>;
523
+ export type HealthResponseEnvelope = Envelope<HealthResponsePayload>;
524
+ export type MetricsEnvelope = Envelope<MetricsPayload>;
525
+ export type MetricsResponseEnvelope = Envelope<MetricsResponsePayload>;
341
526
  //# sourceMappingURL=types.d.ts.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/sdk",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Lightweight SDK for agent-to-agent communication via Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -45,7 +45,7 @@
45
45
  "sdk"
46
46
  ],
47
47
  "author": "Khaliq Gant",
48
- "license": "MIT",
48
+ "license": "Apache-2.0",
49
49
  "repository": {
50
50
  "type": "git",
51
51
  "url": "git+https://github.com/AgentWorkforce/relay.git",
@@ -55,7 +55,7 @@
55
55
  "access": "public"
56
56
  },
57
57
  "dependencies": {
58
- "@agent-relay/protocol": "2.0.19"
58
+ "@agent-relay/protocol": "2.0.21"
59
59
  },
60
60
  "engines": {
61
61
  "node": ">=18.0.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/spawner",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Agent spawning types and utilities for Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -43,5 +43,5 @@
43
43
  "url": "git+https://github.com/AgentWorkforce/relay.git",
44
44
  "directory": "packages/spawner"
45
45
  },
46
- "license": "MIT"
46
+ "license": "Apache-2.0"
47
47
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/state",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Agent state persistence for non-hook CLIs (Codex, Gemini, etc.)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -67,6 +67,8 @@ export class SqliteStorageAdapter {
67
67
  break;
68
68
  }
69
69
  catch (err) {
70
+ const msg = err instanceof Error ? err.message : String(err);
71
+ console.error(`[storage] SQLite driver "${driver}" failed: ${msg}`);
70
72
  lastError = err;
71
73
  }
72
74
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/storage",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Storage adapters and interfaces for Relay message/session persistence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,7 +56,7 @@
56
56
  }
57
57
  },
58
58
  "dependencies": {
59
- "@agent-relay/protocol": "2.0.19"
59
+ "@agent-relay/protocol": "2.0.21"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/telemetry",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Anonymous telemetry for Agent Relay usage analytics",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/trajectory",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Trajectory integration utilities (trail/PDERO) for Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/config": "2.0.19"
25
+ "@agent-relay/config": "2.0.21"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/user-directory",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "User directory service for agent-relay (per-user credential storage)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/resiliency": "2.0.19"
25
+ "@agent-relay/resiliency": "2.0.21"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/utils",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "Shared utilities for agent-relay: logging, name generation, command resolution, update checking",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -317,14 +317,7 @@ export class BaseWrapper extends EventEmitter {
317
317
  console.error(`[base-wrapper] Skipped duplicate message to ${cmd.to}`);
318
318
  return;
319
319
  }
320
- this.sentMessageHashes.add(hash);
321
- // Limit hash set size
322
- if (this.sentMessageHashes.size > 500) {
323
- const oldest = this.sentMessageHashes.values().next().value;
324
- if (oldest)
325
- this.sentMessageHashes.delete(oldest);
326
- }
327
- // Only send if client ready
320
+ // Only send if client ready - check BEFORE adding hash to avoid blocking retries
328
321
  if (this.client.state !== 'READY') {
329
322
  console.error(`[base-wrapper] Client not ready (state=${this.client.state}), dropping message to ${cmd.to}`);
330
323
  return;
@@ -338,14 +331,30 @@ export class BaseWrapper extends EventEmitter {
338
331
  requires_ack: cmd.meta.ackRequired,
339
332
  };
340
333
  }
334
+ // Helper to mark message as sent (only after successful transmission)
335
+ const markSent = () => {
336
+ this.sentMessageHashes.add(hash);
337
+ // Limit hash set size
338
+ if (this.sentMessageHashes.size > 500) {
339
+ const oldest = this.sentMessageHashes.values().next().value;
340
+ if (oldest)
341
+ this.sentMessageHashes.delete(oldest);
342
+ }
343
+ };
341
344
  // Check if target is a channel (starts with #)
342
345
  if (cmd.to.startsWith('#')) {
343
346
  // Use CHANNEL_MESSAGE protocol for channel targets
344
347
  console.error(`[base-wrapper] Sending CHANNEL_MESSAGE to ${cmd.to}`);
345
- this.client.sendChannelMessage(cmd.to, cmd.body, {
348
+ const success = this.client.sendChannelMessage(cmd.to, cmd.body, {
346
349
  thread: cmd.thread,
347
350
  data: cmd.data,
348
351
  });
352
+ if (success) {
353
+ markSent();
354
+ }
355
+ else {
356
+ console.error(`[base-wrapper] sendChannelMessage failed for ${cmd.to}`);
357
+ }
349
358
  }
350
359
  else {
351
360
  // Use SEND protocol for direct messages and broadcasts
@@ -355,12 +364,20 @@ export class BaseWrapper extends EventEmitter {
355
364
  kind: cmd.kind,
356
365
  data: cmd.data,
357
366
  thread: cmd.thread,
367
+ }).then(() => {
368
+ markSent();
358
369
  }).catch((err) => {
359
370
  console.error(`[base-wrapper] sendAndWait failed for ${cmd.to}: ${err.message}`);
360
371
  });
361
372
  }
362
373
  else {
363
- this.client.sendMessage(cmd.to, cmd.body, cmd.kind, cmd.data, cmd.thread, sendMeta);
374
+ const success = this.client.sendMessage(cmd.to, cmd.body, cmd.kind, cmd.data, cmd.thread, sendMeta);
375
+ if (success) {
376
+ markSent();
377
+ }
378
+ else {
379
+ console.error(`[base-wrapper] sendMessage failed for ${cmd.to}`);
380
+ }
364
381
  }
365
382
  }
366
383
  }
@@ -19,6 +19,7 @@ import { spawn } from 'node:child_process';
19
19
  import { createConnection } from 'node:net';
20
20
  import { createHash } from 'node:crypto';
21
21
  import { join, dirname } from 'node:path';
22
+ import { homedir } from 'node:os';
22
23
  import { existsSync, unlinkSync, mkdirSync, symlinkSync, lstatSync, rmSync, watch, readdirSync, readlinkSync, writeFileSync, appendFileSync } from 'node:fs';
23
24
  import { getProjectPaths } from '@agent-relay/config/project-namespace';
24
25
  import { fileURLToPath } from 'node:url';
@@ -140,17 +141,12 @@ export class RelayPtyOrchestrator extends BaseWrapper {
140
141
  this._legacyOutboxPath = `/tmp/relay-outbox/${config.name}`;
141
142
  }
142
143
  else {
143
- // Local mode: use ~/.agent-relay paths directly (no symlinks needed)
144
+ // Local mode: use project paths directly (no symlinks needed)
144
145
  this._outboxPath = this._canonicalOutboxPath;
145
- // Socket at {projectRoot}/.agent-relay/sockets/{agentName}.sock
146
- let localSocketPath = join(projectPaths.dataDir, 'sockets', `${config.name}.sock`);
147
- // If socket path is too long, fall back to /tmp/relay-local/{projectId}/sockets/
148
- if (localSocketPath.length > MAX_SOCKET_PATH_LENGTH) {
149
- const tmpSocketPath = `/tmp/relay-local/${projectPaths.projectId}/sockets/${config.name}.sock`;
150
- console.warn(`[relay-pty-orchestrator:${config.name}] Socket path too long (${localSocketPath.length} chars); using /tmp fallback`);
151
- localSocketPath = tmpSocketPath;
152
- }
153
- this.socketPath = localSocketPath;
146
+ // Socket path: use ~/.agent-relay/sockets/{projectId}/{agentName}.sock
147
+ // This keeps paths short (uses 12-char hashed projectId) while staying organized
148
+ // Example: /Users/foo/.agent-relay/sockets/abc123def456/MyAgent.sock (~65 chars)
149
+ this.socketPath = join(homedir(), '.agent-relay', 'sockets', projectPaths.projectId, `${config.name}.sock`);
154
150
  // Legacy path for backwards compat (older agents might still use /tmp/relay-outbox)
155
151
  // Even in local mode, we need this symlink for agents with stale instructions
156
152
  this._legacyOutboxPath = `/tmp/relay-outbox/${config.name}`;
@@ -385,7 +381,13 @@ export class RelayPtyOrchestrator extends BaseWrapper {
385
381
  throw new Error('relay-pty binary not found. Build with: cd relay-pty && cargo build --release');
386
382
  }
387
383
  this.log(` Using binary: ${binaryPath}`);
388
- // Connect to relay daemon first
384
+ // Spawn relay-pty process FIRST (before connecting to daemon)
385
+ // This ensures the CLI is actually running before we register with the daemon
386
+ await this.spawnRelayPty(binaryPath);
387
+ // Wait for socket to become available and connect
388
+ await this.connectToSocket();
389
+ // Connect to relay daemon AFTER CLI is spawned
390
+ // This prevents the spawner from seeing us as "registered" before the CLI runs
389
391
  try {
390
392
  await this.client.connect();
391
393
  this.log(` Relay daemon connected`);
@@ -393,10 +395,6 @@ export class RelayPtyOrchestrator extends BaseWrapper {
393
395
  catch (err) {
394
396
  this.logError(` Relay connect failed: ${err.message}`);
395
397
  }
396
- // Spawn relay-pty process
397
- await this.spawnRelayPty(binaryPath);
398
- // Wait for socket to become available and connect
399
- await this.connectToSocket();
400
398
  this.running = true;
401
399
  // DON'T set readyForMessages yet - wait for CLI to be ready first
402
400
  // This prevents messages from being injected during CLI startup
@@ -649,7 +647,9 @@ export class RelayPtyOrchestrator extends BaseWrapper {
649
647
  // Wait for process to start
650
648
  await sleep(500);
651
649
  if (proc.exitCode !== null) {
652
- throw new Error(`relay-pty exited immediately with code ${proc.exitCode}`);
650
+ // Include any captured stderr in the error for debugging
651
+ const stderrInfo = stderrBuffer ? `\nStderr: ${stderrBuffer.slice(0, 500)}` : '';
652
+ throw new Error(`relay-pty exited immediately with code ${proc.exitCode}${stderrInfo}`);
653
653
  }
654
654
  // Register for memory/CPU monitoring
655
655
  if (proc.pid) {
@@ -805,6 +805,22 @@ export class TmuxWrapper extends BaseWrapper {
805
805
  requires_ack: cmd.meta.ackRequired,
806
806
  };
807
807
  }
808
+ // Check if target is a channel (starts with #)
809
+ if (cmd.to.startsWith('#')) {
810
+ // Use CHANNEL_MESSAGE protocol for channel targets
811
+ this.logStderr(`→ [channel] ${cmd.to}: ${cmd.body.substring(0, Math.min(RELAY_LOG_TRUNCATE_LENGTH, cmd.body.length))}...`);
812
+ const success = this.client.sendChannelMessage(cmd.to, cmd.body, {
813
+ thread: cmd.thread,
814
+ data: cmd.data,
815
+ });
816
+ if (success) {
817
+ this.sentMessageHashes.add(msgHash);
818
+ this.queuedMessageHashes.delete(msgHash);
819
+ this.trajectory?.message('sent', this.config.name, cmd.to, cmd.body);
820
+ }
821
+ return;
822
+ }
823
+ // Use SEND protocol for direct messages and broadcasts
808
824
  if (cmd.sync?.blocking) {
809
825
  this.client.sendAndWait(cmd.to, cmd.body, {
810
826
  timeoutMs: cmd.sync.timeoutMs,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/wrapper",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "CLI agent wrappers for Agent Relay - tmux, pty integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,11 +30,11 @@
30
30
  "clean": "rm -rf dist"
31
31
  },
32
32
  "dependencies": {
33
- "@agent-relay/api-types": "2.0.19",
34
- "@agent-relay/protocol": "2.0.19",
35
- "@agent-relay/config": "2.0.19",
36
- "@agent-relay/continuity": "2.0.19",
37
- "@agent-relay/resiliency": "2.0.19"
33
+ "@agent-relay/api-types": "2.0.21",
34
+ "@agent-relay/protocol": "2.0.21",
35
+ "@agent-relay/config": "2.0.21",
36
+ "@agent-relay/continuity": "2.0.21",
37
+ "@agent-relay/resiliency": "2.0.21"
38
38
  },
39
39
  "devDependencies": {
40
40
  "typescript": "^5.9.3",
@@ -59,5 +59,5 @@
59
59
  "url": "git+https://github.com/AgentWorkforce/relay.git",
60
60
  "directory": "packages/wrapper"
61
61
  },
62
- "license": "MIT"
62
+ "license": "Apache-2.0"
63
63
  }
@@ -0,0 +1,16 @@
1
+ #!/bin/sh
2
+ # Install git hooks for agent-relay
3
+ # Usage: ./scripts/hooks/install.sh
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7
+ HOOKS_DIR="$REPO_ROOT/.git/hooks"
8
+
9
+ echo "Installing git hooks..."
10
+
11
+ # Install pre-commit hook
12
+ cp "$SCRIPT_DIR/pre-commit" "$HOOKS_DIR/pre-commit"
13
+ chmod +x "$HOOKS_DIR/pre-commit"
14
+ echo " Installed pre-commit hook"
15
+
16
+ echo "Done! Git hooks installed."