@rallycry/conveyor-agent 10.2.4 → 10.3.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.
package/dist/cli.js CHANGED
@@ -1,23 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AgentConnection,
4
+ ClaudeTuiAdapter,
4
5
  DEFAULT_LIFECYCLE_CONFIG,
5
6
  DEFAULT_SONNET_MODEL,
6
7
  Lifecycle,
7
8
  PtyHarness,
8
9
  SessionRunner,
10
+ TUI_KINDS,
11
+ TuiUnavailableError,
9
12
  applyBootstrapToEnv,
10
13
  awaitGitReady,
14
+ buildPromptBytes,
11
15
  buildSessionPreviewPorts,
16
+ cleanTerminalOutput,
12
17
  createServiceLogger,
13
18
  fetchBootstrap,
19
+ findOnPath,
20
+ inheritedEnv,
14
21
  loadConveyorConfig,
15
22
  loadForwardPorts,
23
+ resolvePlaywrightMcpServer,
16
24
  resolveSessionStart,
17
25
  runSetupCommand,
18
26
  runStartCommand,
19
27
  sampleKeyUsage
20
- } from "./chunk-DEMRCBJN.js";
28
+ } from "./chunk-AMPYOJJC.js";
21
29
  import "./chunk-7TQO4ZF4.js";
22
30
 
23
31
  // src/cli.ts
@@ -341,8 +349,82 @@ var ProjectSessionRunner = class {
341
349
  }
342
350
  };
343
351
 
352
+ // src/harness/pty/adapters/opencode.ts
353
+ var PROVIDER_KEY_ENV = {
354
+ openai: "OPENAI_API_KEY",
355
+ anthropic: "ANTHROPIC_API_KEY"
356
+ };
357
+ var OpenCodeTuiAdapter = class {
358
+ constructor(env = process.env) {
359
+ this.env = env;
360
+ }
361
+ env;
362
+ id = "opencode";
363
+ capabilities = {
364
+ resume: false,
365
+ structuredEvents: false,
366
+ prefill: false,
367
+ passiveTurns: false
368
+ };
369
+ resolveBinary(env = this.env) {
370
+ const override = env.CONVEYOR_OPENCODE_BIN;
371
+ const found = override ? findOnPath(override, env) : findOnPath("opencode", env);
372
+ if (!found) {
373
+ throw new TuiUnavailableError(
374
+ "opencode",
375
+ "The opencode CLI is not available in this environment. It must be baked into the pod image (see Dockerfile.base) \u2014 re-run Build Image for this project, or set CONVEYOR_OPENCODE_BIN to its absolute path."
376
+ );
377
+ }
378
+ return found;
379
+ }
380
+ buildSpawn(input) {
381
+ const env = { ...inheritedEnv() };
382
+ delete env.CONVEYOR_AGENT_KEY;
383
+ const key = this.env.CONVEYOR_AGENT_KEY;
384
+ const provider = this.env.CONVEYOR_AGENT_PROVIDER ?? "openai";
385
+ const keyEnvVar = PROVIDER_KEY_ENV[provider];
386
+ if (key && keyEnvVar) env[keyEnvVar] = key;
387
+ const model = this.env.CONVEYOR_AGENT_MODEL ?? input.options.model;
388
+ const args = [];
389
+ if (model) args.push("--model", model.includes("/") ? model : `${provider}/${model}`);
390
+ return { file: this.resolveBinary(), args, env };
391
+ }
392
+ async prepareEnvironment() {
393
+ }
394
+ spawnFingerprint(input) {
395
+ return JSON.stringify(["opencode", input.model, input.cwd]);
396
+ }
397
+ encodePromptBytes(text) {
398
+ return buildPromptBytes(text);
399
+ }
400
+ buildExitErrors(exitCode, rawOutput) {
401
+ const errors = [`opencode exited (code ${exitCode}) without a result`];
402
+ const tail = cleanTerminalOutput(rawOutput);
403
+ if (tail) errors.push(`Last terminal output before exit:
404
+ ${tail}`);
405
+ return errors;
406
+ }
407
+ };
408
+
409
+ // src/harness/pty/adapters/index.ts
410
+ function resolveTuiAdapter(kind = "claude-code") {
411
+ switch (kind) {
412
+ case "claude-code":
413
+ return new ClaudeTuiAdapter();
414
+ case "opencode":
415
+ return new OpenCodeTuiAdapter();
416
+ default:
417
+ throw new Error(`Unknown TUI kind: ${kind}`);
418
+ }
419
+ }
420
+
344
421
  // src/runner/adhoc-session-runner.ts
345
422
  var ADHOC_SYSTEM_NOTE = "You are running in an ad-hoc Conveyor scratch pod \u2014 an interactive terminal on the project's repository checked out at its default branch. There is no task or plan; help the human with whatever they ask directly.";
423
+ function resolveAdhocTui(env) {
424
+ const raw = env.CONVEYOR_TUI ?? "claude-code";
425
+ if (TUI_KINDS.includes(raw)) return raw;
426
+ throw new Error(`Unknown TUI "${raw}" in CONVEYOR_TUI (expected: ${TUI_KINDS.join(", ")})`);
427
+ }
346
428
  function buildAdhocPtyBridge(connection) {
347
429
  return {
348
430
  sendOutput: (data, dims) => connection.sendPtyOutput(data, dims),
@@ -361,7 +443,11 @@ function buildAdhocQueryOptions(workspaceDir, model, abortController, session) {
361
443
  permissionMode: "bypassPermissions",
362
444
  allowDangerouslySkipPermissions: true,
363
445
  tools: { type: "preset", preset: "claude_code" },
364
- mcpServers: {},
446
+ // Browser automation only — the baked playwright-mcp when present.
447
+ mcpServers: (() => {
448
+ const playwright = resolvePlaywrightMcpServer();
449
+ return playwright ? { playwright } : {};
450
+ })(),
365
451
  settingSources: ["user", "project"],
366
452
  // Empty box, unsubmitted: the human types the first prompt themselves.
367
453
  promptDelivery: "prefill",
@@ -384,7 +470,10 @@ var AdhocSessionRunner = class {
384
470
  this.config = config;
385
471
  this.callbacks = callbacks;
386
472
  this.connection = deps?.connection ?? new AgentConnection(config.connection);
387
- this.harness = deps?.harness ?? new PtyHarness(buildAdhocPtyBridge(this.connection));
473
+ this.harness = deps?.harness ?? new PtyHarness(
474
+ buildAdhocPtyBridge(this.connection),
475
+ resolveTuiAdapter(resolveAdhocTui(process.env))
476
+ );
388
477
  this.lifecycle = new Lifecycle(
389
478
  // No git flush: the WIP snapshot machinery is branch/task-shaped; the human
390
479
  // commits/pushes explicitly from the interactive shell.
@@ -444,7 +533,7 @@ var AdhocSessionRunner = class {
444
533
  * loop blocks (keeping the pod alive) until the human exits or stop() aborts.
445
534
  */
446
535
  async runInteractiveTui() {
447
- const model = this.config.model ?? process.env.CONVEYOR_ADHOC_MODEL ?? DEFAULT_SONNET_MODEL;
536
+ const model = this.config.model ?? process.env.CONVEYOR_AGENT_MODEL ?? process.env.CONVEYOR_ADHOC_MODEL ?? DEFAULT_SONNET_MODEL;
448
537
  const session = resolveSessionStart(this.config.workspaceId, this.config.workspaceDir);
449
538
  const options = buildAdhocQueryOptions(
450
539
  this.config.workspaceDir,
@@ -453,8 +542,11 @@ var AdhocSessionRunner = class {
453
542
  session
454
543
  );
455
544
  try {
456
- for await (const _event of this.harness.executeQuery({ prompt: "", options })) {
545
+ for await (const event of this.harness.executeQuery({ prompt: "", options })) {
457
546
  if (this.stopped) break;
547
+ if (event.type === "result" && event.subtype === "error") {
548
+ throw new Error(event.errors.join("\n"));
549
+ }
458
550
  }
459
551
  } catch (error) {
460
552
  if (!this.stopped) throw error;
@@ -830,17 +922,17 @@ if (!CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {
830
922
  logger2.error("CONVEYOR_API_URL is provided via codespace secret or bootstrap.");
831
923
  logger2.error("");
832
924
  logger2.error("Optional:");
833
- logger2.error(" CONVEYOR_MODE - Runner mode: 'task' (default) or 'pm'");
925
+ logger2.error(" CONVEYOR_MODE - Runner mode: 'task' (default), 'pack', or 'pm'");
834
926
  logger2.error(" CONVEYOR_WORKSPACE - Working directory (defaults to cwd)");
835
927
  logger2.error(
836
928
  " Project pods instead require CONVEYOR_PROJECT_ID + CONVEYOR_SESSION_ID + CONVEYOR_MODE=pm"
837
929
  );
838
930
  process.exit(1);
839
931
  }
840
- if (CONVEYOR_MODE !== "task" && CONVEYOR_MODE !== "pm" && CONVEYOR_MODE !== "code-review" && CONVEYOR_MODE !== "adhoc") {
932
+ if (CONVEYOR_MODE !== "task" && CONVEYOR_MODE !== "pm" && CONVEYOR_MODE !== "code-review" && CONVEYOR_MODE !== "adhoc" && CONVEYOR_MODE !== "pack") {
841
933
  logger2.error("Invalid CONVEYOR_MODE", {
842
934
  mode: CONVEYOR_MODE,
843
- expected: ["task", "pm", "code-review", "adhoc"]
935
+ expected: ["task", "pm", "code-review", "adhoc", "pack"]
844
936
  });
845
937
  process.exit(1);
846
938
  }