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
@@ -4,9 +4,9 @@
4
4
  */
5
5
  import net from 'node:net';
6
6
  import fs from 'node:fs';
7
- import { v4 as uuid } from 'uuid';
7
+ import { generateId } from '../utils/id-generator.js';
8
8
  import { PROTOCOL_VERSION, } from '../protocol/types.js';
9
- import { encodeFrame, FrameParser } from '../protocol/framing.js';
9
+ import { encodeFrameLegacy as encodeFrame, FrameParser } from '../protocol/framing.js';
10
10
  export class MultiProjectClient {
11
11
  projects;
12
12
  connections = new Map();
@@ -49,10 +49,12 @@ export class MultiProjectClient {
49
49
  const socket = net.createConnection(project.socketPath, () => {
50
50
  this.sendHello(conn);
51
51
  });
52
+ const parser = new FrameParser();
53
+ parser.setLegacyMode(true); // Use 4-byte header for backwards compatibility
52
54
  const conn = {
53
55
  config: project,
54
56
  socket,
55
- parser: new FrameParser(),
57
+ parser,
56
58
  ready: false,
57
59
  };
58
60
  socket.on('data', (data) => this.handleData(conn, data));
@@ -96,7 +98,7 @@ export class MultiProjectClient {
96
98
  const hello = {
97
99
  v: PROTOCOL_VERSION,
98
100
  type: 'HELLO',
99
- id: uuid(),
101
+ id: generateId(),
100
102
  ts: Date.now(),
101
103
  payload: {
102
104
  agent: this.options.agentName,
@@ -142,7 +144,7 @@ export class MultiProjectClient {
142
144
  this.send(conn, {
143
145
  v: PROTOCOL_VERSION,
144
146
  type: 'PONG',
145
- id: uuid(),
147
+ id: generateId(),
146
148
  ts: Date.now(),
147
149
  payload: envelope.payload ?? {},
148
150
  });
@@ -157,7 +159,7 @@ export class MultiProjectClient {
157
159
  this.send(conn, {
158
160
  v: PROTOCOL_VERSION,
159
161
  type: 'ACK',
160
- id: uuid(),
162
+ id: generateId(),
161
163
  ts: Date.now(),
162
164
  payload: {
163
165
  ack_id: envelope.id,
@@ -212,7 +214,7 @@ export class MultiProjectClient {
212
214
  const envelope = {
213
215
  v: PROTOCOL_VERSION,
214
216
  type: 'SEND',
215
- id: uuid(),
217
+ id: generateId(),
216
218
  ts: Date.now(),
217
219
  to: targetAgent,
218
220
  payload: {
@@ -239,7 +241,7 @@ export class MultiProjectClient {
239
241
  const envelope = {
240
242
  v: PROTOCOL_VERSION,
241
243
  type: 'SEND',
242
- id: uuid(),
244
+ id: generateId(),
243
245
  ts: Date.now(),
244
246
  to: '*',
245
247
  payload: {
@@ -313,9 +315,10 @@ export class MultiProjectClient {
313
315
  const socket = net.createConnection(conn.config.socketPath, () => {
314
316
  this.sendHello(conn);
315
317
  });
316
- // Update connection with new socket
318
+ // Update connection with new socket and fresh parser
317
319
  conn.socket = socket;
318
320
  conn.parser = new FrameParser();
321
+ conn.parser.setLegacyMode(true); // Use 4-byte header for backwards compatibility
319
322
  socket.on('data', (data) => this.handleData(conn, data));
320
323
  socket.on('close', () => {
321
324
  const wasReady = conn.ready;
@@ -369,7 +372,7 @@ export class MultiProjectClient {
369
372
  this.send(conn, {
370
373
  v: PROTOCOL_VERSION,
371
374
  type: 'BYE',
372
- id: uuid(),
375
+ id: generateId(),
373
376
  ts: Date.now(),
374
377
  payload: {},
375
378
  });
@@ -23,6 +23,8 @@ interface WorkerMeta {
23
23
  task: string;
24
24
  /** Optional team name this agent belongs to */
25
25
  team?: string;
26
+ /** Optional user ID for per-user credential scoping */
27
+ userId?: string;
26
28
  spawnedAt: number;
27
29
  pid?: number;
28
30
  logFile?: string;
@@ -12,17 +12,35 @@ import { PtyWrapper } from '../wrapper/pty-wrapper.js';
12
12
  import { selectShadowCli } from './shadow-cli.js';
13
13
  import { AgentPolicyService } from '../policy/agent-policy.js';
14
14
  import { buildClaudeArgs } from '../utils/agent-config.js';
15
+ import { getUserDirectoryService } from '../daemon/user-directory.js';
15
16
  /**
16
- * Get a minimal relay reminder.
17
- * Agents already have full relay docs via CLAUDE.md - this is just a brief reminder.
18
- * Loading full docs (400+ lines) overwhelms agents and causes "meandering".
17
+ * Get relay protocol instructions for a spawned agent.
18
+ * This provides the agent with the communication protocol it needs to work with the relay.
19
19
  */
20
- function getMinimalRelayReminder() {
21
- return `# Quick Relay Reference
22
- - Send: \`->relay:Name <<<message>>>\`
23
- - ACK tasks, send DONE when complete
24
- - Use \`trail start/decision/complete\` for trajectories
25
- - Output \`[[SESSION_END]]..[[/SESSION_END]]\` when done`;
20
+ function getRelayInstructions(agentName) {
21
+ return [
22
+ '# Agent Relay Protocol',
23
+ '',
24
+ `You are agent "${agentName}" connected to Agent Relay for multi-agent coordination.`,
25
+ '',
26
+ '## Sending Messages',
27
+ '',
28
+ 'Use fenced format for all messages:',
29
+ '->relay:TargetAgent <<<',
30
+ 'Your message here.>>>',
31
+ '',
32
+ '## Communication Rules',
33
+ '',
34
+ '1. **ACK immediately** - When you receive a task:',
35
+ ' ->relay:Sender <<<',
36
+ ' ACK: Brief description of task received>>>',
37
+ '',
38
+ '2. **Report completion** - When done:',
39
+ ' ->relay:Sender <<<',
40
+ ' DONE: Brief summary of what was completed>>>',
41
+ '',
42
+ '3. Close >>> must immediately follow content (no blank lines before it)',
43
+ ].join('\n');
26
44
  }
27
45
  export class AgentSpawner {
28
46
  activeWorkers = new Map();
@@ -150,7 +168,7 @@ export class AgentSpawner {
150
168
  * Spawn a new worker agent using node-pty
151
169
  */
152
170
  async spawn(request) {
153
- const { name, cli, task, team, spawnerName } = request;
171
+ const { name, cli, task, team, spawnerName, userId } = request;
154
172
  const debug = process.env.DEBUG_SPAWN === '1';
155
173
  // Check if worker already exists
156
174
  if (this.activeWorkers.has(name)) {
@@ -208,6 +226,14 @@ export class AgentSpawner {
208
226
  if (isCodexCli && !args.includes('--dangerously-bypass-approvals-and-sandbox')) {
209
227
  args.push('--dangerously-bypass-approvals-and-sandbox');
210
228
  }
229
+ // Inject relay protocol instructions via CLI-specific system prompt
230
+ const relayInstructions = getRelayInstructions(name);
231
+ if (isClaudeCli && !args.includes('--append-system-prompt')) {
232
+ args.push('--append-system-prompt', relayInstructions);
233
+ }
234
+ else if (isCodexCli && !args.some(a => a.includes('developer_instructions'))) {
235
+ args.push('--config', `developer_instructions=${relayInstructions}`);
236
+ }
211
237
  if (debug)
212
238
  console.log(`[spawner:debug] Spawning ${name} with: ${command} ${args.join(' ')}`);
213
239
  // Create PtyWrapper config
@@ -219,6 +245,19 @@ export class AgentSpawner {
219
245
  const agentCwd = request.cwd || this.projectRoot;
220
246
  // Log whether nested spawning will be enabled for this agent
221
247
  console.log(`[spawner] Spawning ${name}: dashboardPort=${this.dashboardPort || 'none'} (${this.dashboardPort ? 'nested spawns enabled' : 'nested spawns disabled'})`);
248
+ let userEnv;
249
+ if (userId) {
250
+ try {
251
+ const userDirService = getUserDirectoryService();
252
+ userEnv = userDirService.getUserEnvironment(userId);
253
+ }
254
+ catch (err) {
255
+ console.warn('[spawner] Failed to resolve user environment, using default', {
256
+ userId,
257
+ error: err instanceof Error ? err.message : String(err),
258
+ });
259
+ }
260
+ }
222
261
  const ptyConfig = {
223
262
  name,
224
263
  command,
@@ -227,11 +266,14 @@ export class AgentSpawner {
227
266
  cwd: agentCwd,
228
267
  logsDir: this.logsDir,
229
268
  dashboardPort: this.dashboardPort,
269
+ env: userEnv,
230
270
  // Interactive mode - disables auto-accept for auth setup flows
231
271
  interactive: request.interactive,
232
272
  // Shadow agent configuration
233
273
  shadowOf: request.shadowOf,
234
274
  shadowSpeakOn: request.shadowSpeakOn,
275
+ // Skip continuity for spawned agents - they're short-lived workers
276
+ skipContinuity: true,
235
277
  // Only use callbacks if dashboardPort is not set (for backwards compatibility)
236
278
  onSpawn: this.dashboardPort ? undefined : async (workerName, workerCli, workerTask) => {
237
279
  // Handle nested spawn requests (legacy path, may fail in non-TTY)
@@ -242,6 +284,7 @@ export class AgentSpawner {
242
284
  cli: workerCli,
243
285
  task: workerTask,
244
286
  // Nested spawns don't inherit team - they're flat by default
287
+ userId,
245
288
  });
246
289
  },
247
290
  onRelease: this.dashboardPort ? undefined : async (workerName) => {
@@ -314,78 +357,16 @@ export class AgentSpawner {
314
357
  error,
315
358
  };
316
359
  }
317
- // Build the full message: minimal relay reminder + policy instructions (if any) + task
318
- // Only build message if there's an actual task - empty task means interactive mode
319
- let fullMessage = task || '';
320
- // Only prepend relay reminder if we have an actual task
321
- // Empty task = interactive mode, user will respond to prompts directly
322
- if (fullMessage.trim()) {
323
- // Prepend a brief relay reminder (agents have full docs via CLAUDE.md)
324
- // Note: Previously loaded full 400+ line docs which overwhelmed agents
325
- const relayReminder = getMinimalRelayReminder();
326
- if (relayReminder) {
327
- fullMessage = `${relayReminder}\n\n---\n\n${fullMessage}`;
328
- if (debug)
329
- console.log(`[spawner:debug] Prepended relay reminder for ${name}`);
330
- }
331
- }
332
- // Prepend policy instructions if enforcement is enabled (only if we have a task)
333
- if (fullMessage.trim() && this.policyEnforcementEnabled && this.policyService) {
334
- const policyInstruction = await this.policyService.getPolicyInstruction(name);
335
- if (policyInstruction) {
336
- fullMessage = `${policyInstruction}\n\n${fullMessage}`;
337
- if (debug)
338
- console.log(`[spawner:debug] Prepended policy instructions to task for ${name}`);
339
- }
340
- }
341
- // Send task via relay message if provided (not via direct PTY injection)
342
- // This ensures the agent is ready to receive before processing the task
343
- if (fullMessage && fullMessage.trim()) {
344
- if (debug)
345
- console.log(`[spawner:debug] Will send task via relay: ${fullMessage.substring(0, 50)}...`);
346
- // If we have dashboard API, send task as relay message
347
- if (this.dashboardPort) {
348
- // Wait a moment for the agent's relay client to be ready
349
- await sleep(1000);
350
- try {
351
- const response = await fetch(`http://localhost:${this.dashboardPort}/api/send`, {
352
- method: 'POST',
353
- headers: { 'Content-Type': 'application/json' },
354
- body: JSON.stringify({
355
- to: name,
356
- message: fullMessage,
357
- from: '__spawner__',
358
- }),
359
- });
360
- const result = await response.json();
361
- if (result.success) {
362
- if (debug)
363
- console.log(`[spawner:debug] Task sent via relay to ${name}`);
364
- }
365
- else {
366
- console.warn(`[spawner] Failed to send task via relay: ${result.error}`);
367
- // Fall back to direct injection
368
- pty.write(fullMessage + '\r');
369
- }
370
- }
371
- catch (err) {
372
- console.warn(`[spawner] Relay send failed, falling back to direct injection: ${err.message}`);
373
- pty.write(fullMessage + '\r');
374
- }
375
- }
376
- else {
377
- // No dashboard API available - use direct injection as fallback
378
- if (debug)
379
- console.log(`[spawner:debug] No dashboard API, using direct injection`);
380
- pty.write(fullMessage + '\r');
381
- }
382
- }
360
+ // Note: Task is NOT sent here. The spawning agent (wrapper) waits for the worker
361
+ // to come online and then sends the task via normal relay message.
362
+ // This avoids race conditions with the agent's readyForMessages state.
383
363
  // Track the worker
384
364
  const workerInfo = {
385
365
  name,
386
366
  cli,
387
367
  task,
388
368
  team,
369
+ userId,
389
370
  spawnedAt: Date.now(),
390
371
  pid: pty.pid,
391
372
  pty,
@@ -674,6 +655,7 @@ export class AgentSpawner {
674
655
  cli: w.cli,
675
656
  task: w.task,
676
657
  team: w.team,
658
+ userId: w.userId,
677
659
  spawnedAt: w.spawnedAt,
678
660
  pid: w.pid,
679
661
  logFile: w.logFile,
@@ -53,6 +53,8 @@ export interface SpawnRequest {
53
53
  shadowTriggers?: Array<'SESSION_END' | 'CODE_WRITTEN' | 'REVIEW_REQUEST' | 'EXPLICIT_ASK' | 'ALL_MESSAGES'>;
54
54
  /** When the shadow should speak (default: ['EXPLICIT_ASK']) */
55
55
  shadowSpeakOn?: Array<'SESSION_END' | 'CODE_WRITTEN' | 'REVIEW_REQUEST' | 'EXPLICIT_ASK' | 'ALL_MESSAGES'>;
56
+ /** User ID for per-user credential storage in shared workspaces */
57
+ userId?: string;
56
58
  }
57
59
  /** Policy decision details */
58
60
  export interface PolicyDecision {
@@ -3,12 +3,14 @@
3
3
  * Agent Relay CLI
4
4
  *
5
5
  * Commands:
6
- * relay <cmd> - Wrap agent with real-time messaging (default)
7
- * relay -n Name cmd - Wrap with specific agent name
8
- * relay up - Start daemon + dashboard
9
- * relay read <id> - Read full message by ID
10
- * relay agents - List connected agents
11
- * relay who - Show currently active agents
6
+ * relay claude - Start daemon + Dashboard coordinator with Claude
7
+ * relay codex - Start daemon + Dasbboard coordinator with Codex
8
+ * relay create-agent <cmd> - Wrap agent with real-time messaging
9
+ * relay create-agent -n Name cmd - Wrap with specific agent name
10
+ * relay up - Start daemon + dashboard
11
+ * relay read <id> - Read full message by ID
12
+ * relay agents - List connected agents
13
+ * relay who - Show currently active agents
12
14
  */
13
15
  export {};
14
16
  //# sourceMappingURL=index.d.ts.map