@rallycry/conveyor-agent 10.2.4 → 10.2.5

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,28 +1,33 @@
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,
9
11
  applyBootstrapToEnv,
10
12
  awaitGitReady,
13
+ buildPromptBytes,
11
14
  buildSessionPreviewPorts,
15
+ cleanTerminalOutput,
12
16
  createServiceLogger,
13
17
  fetchBootstrap,
18
+ inheritedEnv,
14
19
  loadConveyorConfig,
15
20
  loadForwardPorts,
16
21
  resolveSessionStart,
17
22
  runSetupCommand,
18
23
  runStartCommand,
19
24
  sampleKeyUsage
20
- } from "./chunk-DEMRCBJN.js";
25
+ } from "./chunk-CFELRV35.js";
21
26
  import "./chunk-7TQO4ZF4.js";
22
27
 
23
28
  // src/cli.ts
24
29
  import { readFileSync } from "fs";
25
- import { join, dirname as dirname2 } from "path";
30
+ import { join as join2, dirname as dirname2 } from "path";
26
31
  import { fileURLToPath } from "url";
27
32
 
28
33
  // src/setup/sidecars.ts
@@ -341,8 +346,114 @@ var ProjectSessionRunner = class {
341
346
  }
342
347
  };
343
348
 
349
+ // src/harness/pty/adapters/types.ts
350
+ import { accessSync, constants, statSync } from "fs";
351
+ import { join } from "path";
352
+ var TuiUnavailableError = class extends Error {
353
+ constructor(tui, message) {
354
+ super(message);
355
+ this.tui = tui;
356
+ this.name = "TuiUnavailableError";
357
+ }
358
+ tui;
359
+ };
360
+ function isExecutable(path) {
361
+ try {
362
+ if (!statSync(path).isFile()) return false;
363
+ accessSync(path, constants.X_OK);
364
+ return true;
365
+ } catch {
366
+ return false;
367
+ }
368
+ }
369
+ function findOnPath(binary, env = process.env) {
370
+ if (binary.includes("/")) {
371
+ return isExecutable(binary) ? binary : null;
372
+ }
373
+ for (const dir of (env.PATH ?? "").split(":")) {
374
+ if (!dir) continue;
375
+ const candidate = join(dir, binary);
376
+ if (isExecutable(candidate)) return candidate;
377
+ }
378
+ return null;
379
+ }
380
+
381
+ // src/harness/pty/adapters/opencode.ts
382
+ var PROVIDER_KEY_ENV = {
383
+ openai: "OPENAI_API_KEY",
384
+ anthropic: "ANTHROPIC_API_KEY"
385
+ };
386
+ var OpenCodeTuiAdapter = class {
387
+ constructor(env = process.env) {
388
+ this.env = env;
389
+ }
390
+ env;
391
+ id = "opencode";
392
+ capabilities = {
393
+ resume: false,
394
+ structuredEvents: false,
395
+ prefill: false,
396
+ passiveTurns: false
397
+ };
398
+ resolveBinary(env = this.env) {
399
+ const override = env.CONVEYOR_OPENCODE_BIN;
400
+ const found = override ? findOnPath(override, env) : findOnPath("opencode", env);
401
+ if (!found) {
402
+ throw new TuiUnavailableError(
403
+ "opencode",
404
+ "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."
405
+ );
406
+ }
407
+ return found;
408
+ }
409
+ buildSpawn(input) {
410
+ const env = { ...inheritedEnv() };
411
+ delete env.CONVEYOR_AGENT_KEY;
412
+ const key = this.env.CONVEYOR_AGENT_KEY;
413
+ const provider = this.env.CONVEYOR_AGENT_PROVIDER ?? "openai";
414
+ const keyEnvVar = PROVIDER_KEY_ENV[provider];
415
+ if (key && keyEnvVar) env[keyEnvVar] = key;
416
+ const model = this.env.CONVEYOR_AGENT_MODEL ?? input.options.model;
417
+ const args = [];
418
+ if (model) args.push("--model", model.includes("/") ? model : `${provider}/${model}`);
419
+ return { file: this.resolveBinary(), args, env };
420
+ }
421
+ async prepareEnvironment() {
422
+ }
423
+ spawnFingerprint(input) {
424
+ return JSON.stringify(["opencode", input.model, input.cwd]);
425
+ }
426
+ encodePromptBytes(text) {
427
+ return buildPromptBytes(text);
428
+ }
429
+ buildExitErrors(exitCode, rawOutput) {
430
+ const errors = [`opencode exited (code ${exitCode}) without a result`];
431
+ const tail = cleanTerminalOutput(rawOutput);
432
+ if (tail) errors.push(`Last terminal output before exit:
433
+ ${tail}`);
434
+ return errors;
435
+ }
436
+ };
437
+
438
+ // src/harness/pty/adapters/index.ts
439
+ function resolveTuiAdapter(kind = "claude-code") {
440
+ switch (kind) {
441
+ case "claude-code":
442
+ return new ClaudeTuiAdapter();
443
+ case "opencode":
444
+ return new OpenCodeTuiAdapter();
445
+ default:
446
+ throw new Error(`Unknown TUI kind: ${kind}`);
447
+ }
448
+ }
449
+
344
450
  // src/runner/adhoc-session-runner.ts
345
451
  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.";
452
+ function resolveAdhocTui(env) {
453
+ const raw = env.CONVEYOR_TUI ?? "claude-code";
454
+ if (TUI_KINDS.includes(raw)) return raw;
455
+ throw new Error(`Unknown TUI "${raw}" in CONVEYOR_TUI (expected: ${TUI_KINDS.join(", ")})`);
456
+ }
346
457
  function buildAdhocPtyBridge(connection) {
347
458
  return {
348
459
  sendOutput: (data, dims) => connection.sendPtyOutput(data, dims),
@@ -384,7 +495,10 @@ var AdhocSessionRunner = class {
384
495
  this.config = config;
385
496
  this.callbacks = callbacks;
386
497
  this.connection = deps?.connection ?? new AgentConnection(config.connection);
387
- this.harness = deps?.harness ?? new PtyHarness(buildAdhocPtyBridge(this.connection));
498
+ this.harness = deps?.harness ?? new PtyHarness(
499
+ buildAdhocPtyBridge(this.connection),
500
+ resolveTuiAdapter(resolveAdhocTui(process.env))
501
+ );
388
502
  this.lifecycle = new Lifecycle(
389
503
  // No git flush: the WIP snapshot machinery is branch/task-shaped; the human
390
504
  // commits/pushes explicitly from the interactive shell.
@@ -444,7 +558,7 @@ var AdhocSessionRunner = class {
444
558
  * loop blocks (keeping the pod alive) until the human exits or stop() aborts.
445
559
  */
446
560
  async runInteractiveTui() {
447
- const model = this.config.model ?? process.env.CONVEYOR_ADHOC_MODEL ?? DEFAULT_SONNET_MODEL;
561
+ const model = this.config.model ?? process.env.CONVEYOR_AGENT_MODEL ?? process.env.CONVEYOR_ADHOC_MODEL ?? DEFAULT_SONNET_MODEL;
448
562
  const session = resolveSessionStart(this.config.workspaceId, this.config.workspaceDir);
449
563
  const options = buildAdhocQueryOptions(
450
564
  this.config.workspaceDir,
@@ -453,8 +567,11 @@ var AdhocSessionRunner = class {
453
567
  session
454
568
  );
455
569
  try {
456
- for await (const _event of this.harness.executeQuery({ prompt: "", options })) {
570
+ for await (const event of this.harness.executeQuery({ prompt: "", options })) {
457
571
  if (this.stopped) break;
572
+ if (event.type === "result" && event.subtype === "error") {
573
+ throw new Error(event.errors.join("\n"));
574
+ }
458
575
  }
459
576
  } catch (error) {
460
577
  if (!this.stopped) throw error;
@@ -653,7 +770,7 @@ var ReviewChildSupervisor = class {
653
770
  // src/cli.ts
654
771
  if (process.argv.includes("--version")) {
655
772
  const __dirname = dirname2(fileURLToPath(import.meta.url));
656
- const pkgPath = join(__dirname, "..", "package.json");
773
+ const pkgPath = join2(__dirname, "..", "package.json");
657
774
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
658
775
  process.stdout.write(pkg.version + "\n");
659
776
  process.exit(0);