@rallycry/conveyor-agent 5.9.2 → 5.9.4

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.
@@ -1,3 +1,62 @@
1
+ // src/setup/commands.ts
2
+ import { spawn, execSync } from "child_process";
3
+ function runSetupCommand(cmd, cwd, onOutput) {
4
+ return new Promise((resolve2, reject) => {
5
+ const child = spawn("sh", ["-c", cmd], {
6
+ cwd,
7
+ stdio: ["ignore", "pipe", "pipe"],
8
+ env: { ...process.env }
9
+ });
10
+ child.stdout.on("data", (chunk) => {
11
+ onOutput("stdout", chunk.toString());
12
+ });
13
+ child.stderr.on("data", (chunk) => {
14
+ onOutput("stderr", chunk.toString());
15
+ });
16
+ child.on("close", (code) => {
17
+ if (code === 0) {
18
+ resolve2();
19
+ } else {
20
+ reject(new Error(`Setup command exited with code ${code}`));
21
+ }
22
+ });
23
+ child.on("error", (err) => {
24
+ reject(err);
25
+ });
26
+ });
27
+ }
28
+ var AUTH_TOKEN_TIMEOUT_MS = 3e4;
29
+ function runAuthTokenCommand(cmd, userEmail, cwd) {
30
+ try {
31
+ const output = execSync(`${cmd} ${JSON.stringify(userEmail)}`, {
32
+ cwd,
33
+ timeout: AUTH_TOKEN_TIMEOUT_MS,
34
+ stdio: ["ignore", "pipe", "ignore"],
35
+ env: { ...process.env }
36
+ });
37
+ const token = output.toString().trim();
38
+ return token || null;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+ function runStartCommand(cmd, cwd, onOutput) {
44
+ const child = spawn("sh", ["-c", cmd], {
45
+ cwd,
46
+ stdio: ["ignore", "pipe", "pipe"],
47
+ detached: true,
48
+ env: { ...process.env }
49
+ });
50
+ child.stdout.on("data", (chunk) => {
51
+ onOutput("stdout", chunk.toString());
52
+ });
53
+ child.stderr.on("data", (chunk) => {
54
+ onOutput("stderr", chunk.toString());
55
+ });
56
+ child.unref();
57
+ return child;
58
+ }
59
+
1
60
  // src/connection/task-connection.ts
2
61
  import { io } from "socket.io-client";
3
62
 
@@ -161,6 +220,10 @@ var ConveyorConnection = class _ConveyorConnection {
161
220
  this.socket.on("agentRunner:runStartCommand", () => {
162
221
  if (this.runStartCommandCallback) this.runStartCommandCallback();
163
222
  });
223
+ this.socket.on(
224
+ "agentRunner:runAuthTokenCommand",
225
+ (data, cb) => this.handleRunAuthTokenCommand(data.userEmail, cb)
226
+ );
164
227
  this.socket.on("connect", () => {
165
228
  if (!settled) {
166
229
  settled = true;
@@ -260,6 +323,33 @@ var ConveyorConnection = class _ConveyorConnection {
260
323
  onRunStartCommand(callback) {
261
324
  this.runStartCommandCallback = callback;
262
325
  }
326
+ handleRunAuthTokenCommand(userEmail, cb) {
327
+ try {
328
+ if (process.env.CODESPACES !== "true") {
329
+ cb({ ok: false, error: "Auth token command only available in codespace environments" });
330
+ return;
331
+ }
332
+ const authCmd = process.env.CONVEYOR_AUTH_TOKEN_COMMAND;
333
+ if (!authCmd) {
334
+ cb({ ok: false, error: "CONVEYOR_AUTH_TOKEN_COMMAND not configured" });
335
+ return;
336
+ }
337
+ const token = runAuthTokenCommand(authCmd, userEmail, this.config.workspaceDir);
338
+ if (!token) {
339
+ cb({
340
+ ok: false,
341
+ error: `Auth token command returned empty output. Command: ${authCmd}, Working Dir: ${this.config.workspaceDir}`
342
+ });
343
+ return;
344
+ }
345
+ cb({ ok: true, token });
346
+ } catch (error) {
347
+ cb({
348
+ ok: false,
349
+ error: error instanceof Error ? error.message : "Auth token command failed"
350
+ });
351
+ }
352
+ }
263
353
  emitModeChanged(agentMode) {
264
354
  if (!this.socket) return;
265
355
  this.socket.emit("agentRunner:modeChanged", { agentMode });
@@ -272,10 +362,6 @@ var ConveyorConnection = class _ConveyorConnection {
272
362
  if (!this.socket) return;
273
363
  this.socket.emit("agentRunner:statusUpdate", { status });
274
364
  }
275
- emitAuthToken(token) {
276
- if (!this.socket) return;
277
- this.socket.emit("agentRunner:authToken", { token });
278
- }
279
365
  emitRateLimitPause(resetsAt) {
280
366
  if (!this.socket) return;
281
367
  this.socket.emit("agentRunner:rateLimitPause", { resetsAt });
@@ -509,7 +595,7 @@ var ProjectConnection = class {
509
595
  };
510
596
 
511
597
  // src/runner/worktree.ts
512
- import { execSync } from "child_process";
598
+ import { execSync as execSync2 } from "child_process";
513
599
  import { existsSync } from "fs";
514
600
  import { join } from "path";
515
601
  var WORKTREE_DIR = ".worktrees";
@@ -521,7 +607,7 @@ function ensureWorktree(projectDir, taskId, branch) {
521
607
  if (existsSync(worktreePath)) {
522
608
  if (branch) {
523
609
  try {
524
- execSync(`git checkout --detach origin/${branch}`, {
610
+ execSync2(`git checkout --detach origin/${branch}`, {
525
611
  cwd: worktreePath,
526
612
  stdio: "ignore"
527
613
  });
@@ -531,7 +617,7 @@ function ensureWorktree(projectDir, taskId, branch) {
531
617
  return worktreePath;
532
618
  }
533
619
  const ref = branch ? `origin/${branch}` : "HEAD";
534
- execSync(`git worktree add --detach "${worktreePath}" ${ref}`, {
620
+ execSync2(`git worktree add --detach "${worktreePath}" ${ref}`, {
535
621
  cwd: projectDir,
536
622
  stdio: "ignore"
537
623
  });
@@ -541,7 +627,7 @@ function removeWorktree(projectDir, taskId) {
541
627
  const worktreePath = join(projectDir, WORKTREE_DIR, taskId);
542
628
  if (!existsSync(worktreePath)) return;
543
629
  try {
544
- execSync(`git worktree remove "${worktreePath}" --force`, {
630
+ execSync2(`git worktree remove "${worktreePath}" --force`, {
545
631
  cwd: projectDir,
546
632
  stdio: "ignore"
547
633
  });
@@ -552,7 +638,6 @@ function removeWorktree(projectDir, taskId) {
552
638
  // src/setup/config.ts
553
639
  import { readFile } from "fs/promises";
554
640
  import { join as join2 } from "path";
555
- var CONVEYOR_CONFIG_PATH = ".conveyor/config.json";
556
641
  var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
557
642
  async function loadForwardPorts(workspaceDir) {
558
643
  try {
@@ -563,87 +648,20 @@ async function loadForwardPorts(workspaceDir) {
563
648
  return [];
564
649
  }
565
650
  }
566
- async function loadConveyorConfig(workspaceDir) {
651
+ function loadConveyorConfig(_workspaceDir) {
567
652
  const envSetup = process.env.CONVEYOR_SETUP_COMMAND;
568
653
  const envStart = process.env.CONVEYOR_START_COMMAND;
569
654
  const envPort = process.env.CONVEYOR_PREVIEW_PORT;
570
- const envAuth = process.env.CONVEYOR_AUTH_TOKEN_COMMAND;
571
655
  if (envSetup || envStart) {
572
656
  return {
573
657
  setupCommand: envSetup,
574
658
  startCommand: envStart,
575
- previewPort: envPort ? Number(envPort) : void 0,
576
- authTokenCommand: envAuth
659
+ previewPort: envPort ? Number(envPort) : void 0
577
660
  };
578
661
  }
579
- try {
580
- const raw = await readFile(join2(workspaceDir, CONVEYOR_CONFIG_PATH), "utf-8");
581
- const parsed = JSON.parse(raw);
582
- if (parsed.setupCommand || parsed.startCommand) return parsed;
583
- } catch {
584
- }
585
662
  return null;
586
663
  }
587
664
 
588
- // src/setup/commands.ts
589
- import { spawn, execSync as execSync2 } from "child_process";
590
- function runSetupCommand(cmd, cwd, onOutput) {
591
- return new Promise((resolve2, reject) => {
592
- const child = spawn("sh", ["-c", cmd], {
593
- cwd,
594
- stdio: ["ignore", "pipe", "pipe"],
595
- env: { ...process.env }
596
- });
597
- child.stdout.on("data", (chunk) => {
598
- onOutput("stdout", chunk.toString());
599
- });
600
- child.stderr.on("data", (chunk) => {
601
- onOutput("stderr", chunk.toString());
602
- });
603
- child.on("close", (code) => {
604
- if (code === 0) {
605
- resolve2();
606
- } else {
607
- reject(new Error(`Setup command exited with code ${code}`));
608
- }
609
- });
610
- child.on("error", (err) => {
611
- reject(err);
612
- });
613
- });
614
- }
615
- var AUTH_TOKEN_TIMEOUT_MS = 3e4;
616
- function runAuthTokenCommand(cmd, userEmail, cwd) {
617
- try {
618
- const output = execSync2(`${cmd} ${JSON.stringify(userEmail)}`, {
619
- cwd,
620
- timeout: AUTH_TOKEN_TIMEOUT_MS,
621
- stdio: ["ignore", "pipe", "ignore"],
622
- env: { ...process.env }
623
- });
624
- const token = output.toString().trim();
625
- return token || null;
626
- } catch {
627
- return null;
628
- }
629
- }
630
- function runStartCommand(cmd, cwd, onOutput) {
631
- const child = spawn("sh", ["-c", cmd], {
632
- cwd,
633
- stdio: ["ignore", "pipe", "pipe"],
634
- detached: true,
635
- env: { ...process.env }
636
- });
637
- child.stdout.on("data", (chunk) => {
638
- onOutput("stdout", chunk.toString());
639
- });
640
- child.stderr.on("data", (chunk) => {
641
- onOutput("stderr", chunk.toString());
642
- });
643
- child.unref();
644
- return child;
645
- }
646
-
647
665
  // src/setup/codespace.ts
648
666
  import { execSync as execSync3 } from "child_process";
649
667
  function unshallowRepo(workspaceDir) {
@@ -977,6 +995,8 @@ async function processResultCase(event, host, context, startTime, state) {
977
995
  }
978
996
  async function processEvents(events, context, host) {
979
997
  const startTime = Date.now();
998
+ let lastStatusEmit = Date.now();
999
+ const STATUS_REEMIT_INTERVAL_MS = 5e3;
980
1000
  const state = {
981
1001
  sessionIdStored: false,
982
1002
  isTyping: false,
@@ -989,6 +1009,11 @@ async function processEvents(events, context, host) {
989
1009
  };
990
1010
  for await (const event of events) {
991
1011
  if (host.isStopped()) break;
1012
+ const now = Date.now();
1013
+ if (now - lastStatusEmit >= STATUS_REEMIT_INTERVAL_MS) {
1014
+ host.connection.emitStatus("running");
1015
+ lastStatusEmit = now;
1016
+ }
992
1017
  if (host.pendingModeRestart) {
993
1018
  stopTypingIfNeeded(host, state.isTyping);
994
1019
  return { retriable: false, modeRestart: true };
@@ -1179,7 +1204,8 @@ function buildPropertyInstructions(context) {
1179
1204
  if (context.projectTags && context.projectTags.length > 0) {
1180
1205
  parts.push(``, `Available project tags:`);
1181
1206
  for (const tag of context.projectTags) {
1182
- parts.push(`- ID: "${tag.id}", Name: "${tag.name}"`);
1207
+ const desc = tag.description ? ` \u2014 ${tag.description}` : "";
1208
+ parts.push(`- ID: "${tag.id}", Name: "${tag.name}"${desc}`);
1183
1209
  }
1184
1210
  }
1185
1211
  return parts;
@@ -1426,7 +1452,6 @@ Your responses are sent directly to the task chat \u2014 the team sees everythin
1426
1452
  }
1427
1453
 
1428
1454
  // src/execution/prompt-builder.ts
1429
- var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["InProgress", "ReviewPR", "ReviewDev", "ReviewLive"]);
1430
1455
  function formatFileSize(bytes) {
1431
1456
  if (bytes === void 0) return "";
1432
1457
  if (bytes < 1024) return `${bytes}B`;
@@ -1439,16 +1464,16 @@ function findLastAgentMessageIndex2(history) {
1439
1464
  }
1440
1465
  return -1;
1441
1466
  }
1442
- function detectRelaunchScenario(context) {
1467
+ function detectRelaunchScenario(context, trustChatHistory = false) {
1443
1468
  const lastAgentIdx = findLastAgentMessageIndex2(context.chatHistory);
1444
1469
  if (lastAgentIdx === -1) return "fresh";
1445
- const hasPriorWork = !!context.githubPRUrl || !!context.claudeSessionId || ACTIVE_STATUSES.has(context.status ?? "");
1470
+ const hasPriorWork = !!context.githubPRUrl || !!context.claudeSessionId || trustChatHistory;
1446
1471
  if (!hasPriorWork) return "fresh";
1447
1472
  const messagesAfterAgent = context.chatHistory.slice(lastAgentIdx + 1);
1448
1473
  const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === "user");
1449
1474
  return hasNewUserMessages ? "feedback_relaunch" : "idle_relaunch";
1450
1475
  }
1451
- function buildRelaunchWithSession(mode, context) {
1476
+ function buildRelaunchWithSession(mode, context, agentMode) {
1452
1477
  const scenario = detectRelaunchScenario(context);
1453
1478
  if (!context.claudeSessionId || scenario === "fresh") return null;
1454
1479
  const parts = [];
@@ -1494,9 +1519,18 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
1494
1519
  `You were relaunched but no new instructions have been given since your last run.`,
1495
1520
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
1496
1521
  `Run \`git log --oneline -10\` to review what you already committed.`,
1497
- `Review the current state of the codebase and verify everything is working correctly.`,
1498
- `Reply with a brief status update (visible in chat), then wait for further instructions.`
1522
+ `Review the current state of the codebase and verify everything is working correctly.`
1499
1523
  );
1524
+ if (agentMode === "auto" || agentMode === "building") {
1525
+ parts.push(
1526
+ `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
1527
+ `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
1528
+ );
1529
+ } else {
1530
+ parts.push(
1531
+ `Reply with a brief status update (visible in chat), then wait for further instructions.`
1532
+ );
1533
+ }
1500
1534
  if (context.githubPRUrl) {
1501
1535
  parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);
1502
1536
  }
@@ -1711,10 +1745,19 @@ function buildInstructions(mode, context, scenario, agentMode) {
1711
1745
  parts.push(
1712
1746
  `You were relaunched but no new instructions have been given since your last run.`,
1713
1747
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
1714
- `Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`,
1715
- `Reply with a brief status update summarizing where things stand (visible in chat).`,
1716
- `Then wait for further instructions \u2014 do NOT redo work that was already completed.`
1748
+ `Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`
1717
1749
  );
1750
+ if (agentMode === "auto" || agentMode === "building") {
1751
+ parts.push(
1752
+ `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
1753
+ `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
1754
+ );
1755
+ } else {
1756
+ parts.push(
1757
+ `Reply with a brief status update summarizing where things stand (visible in chat).`,
1758
+ `Then wait for further instructions \u2014 do NOT redo work that was already completed.`
1759
+ );
1760
+ }
1718
1761
  if (context.githubPRUrl) {
1719
1762
  parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);
1720
1763
  }
@@ -1727,10 +1770,11 @@ function buildInstructions(mode, context, scenario, agentMode) {
1727
1770
  function buildInitialPrompt(mode, context, isAuto, agentMode) {
1728
1771
  const isPackRunner = mode === "pm" && !!isAuto && !!context.isParentTask;
1729
1772
  if (!isPackRunner) {
1730
- const sessionRelaunch = buildRelaunchWithSession(mode, context);
1773
+ const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode);
1731
1774
  if (sessionRelaunch) return sessionRelaunch;
1732
1775
  }
1733
- const scenario = detectRelaunchScenario(context);
1776
+ const isPm = mode === "pm";
1777
+ const scenario = detectRelaunchScenario(context, isPm);
1734
1778
  const body = buildTaskBody(context);
1735
1779
  const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode);
1736
1780
  return [...body, ...instructions].join("\n");
@@ -3010,6 +3054,16 @@ ${message}`);
3010
3054
  }
3011
3055
  async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, _effectiveAgentMode, setState) {
3012
3056
  await setState("setup");
3057
+ if (process.env.CONVEYOR_FROM_PROJECT_RUNNER === "true") {
3058
+ const config2 = await loadConveyorConfig(runnerConfig.workspaceDir);
3059
+ const setupEvent = {
3060
+ type: "setup_complete",
3061
+ previewPort: config2?.previewPort ?? void 0
3062
+ };
3063
+ connection.sendEvent(setupEvent);
3064
+ await callbacks.onEvent(setupEvent);
3065
+ return { ok: true, conveyorConfig: config2 };
3066
+ }
3013
3067
  const ports = await loadForwardPorts(runnerConfig.workspaceDir);
3014
3068
  if (ports.length > 0 && process.env.CODESPACE_NAME) {
3015
3069
  const visibility = ports.map((p) => `${p}:public`).join(" ");
@@ -3048,17 +3102,6 @@ The agent cannot start until this is resolved.`
3048
3102
  return { ok: false, conveyorConfig: null };
3049
3103
  }
3050
3104
  }
3051
- function runAuthTokenSafe(config, connection, taskContext) {
3052
- const authCmd = process.env.CONVEYOR_AUTH_TOKEN_COMMAND;
3053
- if (!authCmd || !taskContext.userEmail) return;
3054
- try {
3055
- const token = runAuthTokenCommand(authCmd, taskContext.userEmail, config.workspaceDir);
3056
- if (token) {
3057
- connection.emitAuthToken(token);
3058
- }
3059
- } catch {
3060
- }
3061
- }
3062
3105
  function rerunStartCommand(conveyorConfig, runnerConfig, connection, setupLog) {
3063
3106
  if (!conveyorConfig.startCommand) return;
3064
3107
  pushSetupLog(setupLog, `$ ${conveyorConfig.startCommand} & (background, re-trigger)`);
@@ -3288,9 +3331,6 @@ var AgentRunner = class {
3288
3331
  }
3289
3332
  this.tryInitWorktree();
3290
3333
  if (!await this.fetchAndInitContext()) return;
3291
- if (process.env.CODESPACES === "true" && this.taskContext) {
3292
- runAuthTokenSafe(this.config, this.connection, this.taskContext);
3293
- }
3294
3334
  this.tryPostContextWorktree();
3295
3335
  this.checkoutWorktreeBranch();
3296
3336
  await this.executeInitialMode();
@@ -3844,7 +3884,8 @@ function spawnChildAgent(assignment, workDir) {
3844
3884
  CONVEYOR_USE_WORKTREE: "false",
3845
3885
  CONVEYOR_AGENT_MODE: isAuto ? "auto" : "",
3846
3886
  CONVEYOR_IS_AUTO: isAuto ? "true" : "false",
3847
- CONVEYOR_USE_SANDBOX: useSandbox === true ? "true" : "false"
3887
+ CONVEYOR_USE_SANDBOX: useSandbox === true ? "true" : "false",
3888
+ CONVEYOR_FROM_PROJECT_RUNNER: "true"
3848
3889
  },
3849
3890
  cwd: workDir,
3850
3891
  stdio: ["pipe", "pipe", "pipe", "ipc"]
@@ -4102,17 +4143,17 @@ var FileCache = class {
4102
4143
  };
4103
4144
 
4104
4145
  export {
4146
+ runSetupCommand,
4147
+ runStartCommand,
4105
4148
  ConveyorConnection,
4106
4149
  ProjectConnection,
4107
4150
  ensureWorktree,
4108
4151
  removeWorktree,
4109
4152
  loadConveyorConfig,
4110
- runSetupCommand,
4111
- runStartCommand,
4112
4153
  createServiceLogger,
4113
4154
  errorMeta,
4114
4155
  AgentRunner,
4115
4156
  ProjectRunner,
4116
4157
  FileCache
4117
4158
  };
4118
- //# sourceMappingURL=chunk-X2QE27GN.js.map
4159
+ //# sourceMappingURL=chunk-N3TSLBSH.js.map