@epoch-agent/cli 0.4.0 → 0.5.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/index.js CHANGED
@@ -7,7 +7,7 @@ import { Command } from "commander";
7
7
  import { t as t39 } from "@epoch-agent/infra";
8
8
  // src/commands/agents.ts
9
9
  import { AGENT_ROLE_DIAG_MODULE, findRole, roleSourceLabel } from "@epoch-agent/core";
10
- import { t as t2 } from "@epoch-agent/infra";
10
+ import { t as t2, UNLIMITED_TURNS } from "@epoch-agent/infra";
11
11
  // src/errors.ts
12
12
  import { t } from "@epoch-agent/infra";
13
13
  // src/exit-codes.ts
@@ -88,7 +88,9 @@ function renderRole(role) {
88
88
  lines.push(
89
89
  ` ${role.tools ? t2("agents.tools_declared", { tools: role.tools.join(", ") }) : t2("agents.tools_inherited")}`
90
90
  );
91
- if (role.maxTurns !== void 0) {
91
+ if (role.maxTurns === UNLIMITED_TURNS) {
92
+ lines.push(` ${t2("agents.max_turns_unlimited")}`);
93
+ } else if (role.maxTurns !== void 0) {
92
94
  lines.push(` ${t2("agents.max_turns", { n: role.maxTurns })}`);
93
95
  }
94
96
  return lines;
@@ -478,6 +480,10 @@ function isPositiveNumber(v) {
478
480
  function isPositiveInt(v) {
479
481
  return isPositiveNumber(v) && Number.isInteger(Number(v));
480
482
  }
483
+ function isTurnLimit(v) {
484
+ const n = Number(v);
485
+ return Number.isInteger(n) && n >= 0;
486
+ }
481
487
  var BUDGET_FIELDS = {
482
488
  maxCostUsd: isPositiveNumber,
483
489
  maxTokens: isPositiveNumber,
@@ -485,7 +491,7 @@ var BUDGET_FIELDS = {
485
491
  onUnknownPricing: (v) => v === "block" || v === "warn"
486
492
  };
487
493
  var SCALAR_FIELDS = {
488
- maxTurns: isPositiveInt,
494
+ maxTurns: isTurnLimit,
489
495
  contextLength: isPositiveInt
490
496
  };
491
497
  var SECTION_FIELDS = {
@@ -1376,6 +1382,9 @@ function resolveHeadlessFormats(opts) {
1376
1382
  }
1377
1383
  return { input: input2, output };
1378
1384
  }
1385
+ function refuseEmptyQuery(nonInteractive, output) {
1386
+ return nonInteractive || output !== "text";
1387
+ }
1379
1388
  function resolveApproverProgram(raw) {
1380
1389
  const value = raw?.trim();
1381
1390
  if (!value) return void 0;
@@ -1391,21 +1400,26 @@ function resolveApproverProgram(raw) {
1391
1400
  return `"${abs}"`;
1392
1401
  }
1393
1402
  function parseCallLimits(opts) {
1394
- const turns = parsePositive(opts.maxTurns, "--max-turns", (n) => Number.isInteger(n));
1395
- const usd = parsePositive(opts.maxBudgetUsd, "--max-budget-usd");
1403
+ const turns = parseNumeric(opts.maxTurns, "--max-turns", {
1404
+ allowZero: true,
1405
+ extra: (n) => Number.isInteger(n)
1406
+ });
1407
+ const usd = parseNumeric(opts.maxBudgetUsd, "--max-budget-usd");
1396
1408
  return {
1397
1409
  ...turns !== void 0 ? { maxTurns: turns } : {},
1398
1410
  ...usd !== void 0 ? { maxCallCostUsd: usd } : {}
1399
1411
  };
1400
1412
  }
1401
- function parsePositive(raw, flag, extra = () => true) {
1413
+ function parseNumeric(raw, flag, opts = {}) {
1402
1414
  if (raw === void 0) return void 0;
1415
+ const extra = opts.extra ?? (() => true);
1403
1416
  const n = Number(raw);
1404
- if (!Number.isFinite(n) || n <= 0 || !extra(n)) {
1417
+ const tooSmall = opts.allowZero === true ? n < 0 : n <= 0;
1418
+ if (raw.trim() === "" || !Number.isFinite(n) || tooSmall || !extra(n)) {
1405
1419
  throw new CliError(
1406
1420
  t9("flags.not_a_number", { flag, raw }),
1407
1421
  1,
1408
- flag === "--max-turns" ? t9("flags.want_positive_int") : t9("flags.want_positive")
1422
+ flag === "--max-turns" ? t9("flags.want_turn_limit") : t9("flags.want_positive")
1409
1423
  );
1410
1424
  }
1411
1425
  return n;
@@ -3361,7 +3375,16 @@ function registerRunCommand(program2) {
3361
3375
  }
3362
3376
  const resumeId = await resolveResumeTarget(opts, resumeArg);
3363
3377
  const dispatch = async () => {
3364
- if (!prompt && (opts.image ?? []).length === 0) return launchTui(resumeId);
3378
+ if (!prompt && (opts.image ?? []).length === 0) {
3379
+ if (refuseEmptyQuery(isNonInteractive8(), formats.output)) {
3380
+ throw new CliError(
3381
+ t25("run.no_query_noninteractive"),
3382
+ EXIT_CODES.FAILURE,
3383
+ t25("run.no_query_hint")
3384
+ );
3385
+ }
3386
+ return launchTui(resumeId);
3387
+ }
3365
3388
  return runOnce(prompt, opts, resumeId);
3366
3389
  };
3367
3390
  if (opts.worktree !== true) return dispatch();
@@ -4676,6 +4699,7 @@ ${t37("upgrade.why_manual")}`);
4676
4699
  }
4677
4700
  // src/commands/web.ts
4678
4701
  import { t as t38 } from "@epoch-agent/infra";
4702
+ import { diagnosticToLine } from "@epoch-agent/protocol";
4679
4703
  import { buildRuntime as buildRuntime3 } from "@epoch-agent/runtime";
4680
4704
  import {
4681
4705
  createWebServer,
@@ -4740,10 +4764,12 @@ async function runWeb(opts) {
4740
4764
  if (!binding.ok) return fail(binding.error);
4741
4765
  if (!await maybePromptForTrust()) process.exit(1);
4742
4766
  if (!await maybePromptForExternalImports()) process.exit(1);
4743
- const server = await boot(binding, opts.plugins === true);
4744
- if (!server) return;
4767
+ const booted = await boot(binding, opts.plugins === true);
4768
+ if (!booted) return;
4769
+ const { server } = booted;
4745
4770
  const json = opts.json === true;
4746
4771
  const say = json ? err : out;
4772
+ if (booted.noProvider) for (const line of noProviderLines(booted.providerDiagnostics)) say(line);
4747
4773
  const lines = announceLines({
4748
4774
  url: server.url,
4749
4775
  host: server.host,
@@ -4769,12 +4795,7 @@ async function boot(binding, plugins) {
4769
4795
  interactive: true,
4770
4796
  ...pluginsOption(plugins)
4771
4797
  });
4772
- if (!runtime.session) {
4773
- await runtime.dispose();
4774
- fail(`${t38("cli.web.no_provider")}
4775
- ${runtime.diagnostics.join("\n")}`);
4776
- return null;
4777
- }
4798
+ const noProvider = runtime.session === null;
4778
4799
  const created = await createWebServer({
4779
4800
  runtime,
4780
4801
  version: VERSION,
@@ -4787,7 +4808,14 @@ ${runtime.diagnostics.join("\n")}`);
4787
4808
  fail(created.error);
4788
4809
  return null;
4789
4810
  }
4790
- return created.server;
4811
+ return {
4812
+ server: created.server,
4813
+ noProvider,
4814
+ providerDiagnostics: runtime.diagnosticList.filter((d) => d.module === "Provider").map(diagnosticToLine)
4815
+ };
4816
+ }
4817
+ function noProviderLines(providerDiagnostics) {
4818
+ return [` ${t38("cli.web.no_provider_warn")}`, ...providerDiagnostics.map((line) => ` ${line}`)];
4791
4819
  }
4792
4820
  function announceLines(input2) {
4793
4821
  const human = [];
package/dist/tui-entry.js CHANGED
@@ -1560,7 +1560,7 @@ async function main() {
1560
1560
  });
1561
1561
  const { session, config } = runtime;
1562
1562
  if (!session) {
1563
- process.stderr.write(`${t14("cli.web.no_provider")}
1563
+ process.stderr.write(`${t14("tui.no_provider")}
1564
1564
  ${runtime.diagnostics.join("\n")}
1565
1565
  `);
1566
1566
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epoch-agent/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "epoch-agent CLI 入口",
6
6
  "repository": {
@@ -22,12 +22,12 @@
22
22
  "commander": "^15.0.0",
23
23
  "ink": "^7.1.1",
24
24
  "react": "^19.2.8",
25
- "@epoch-agent/core": "0.4.0",
26
- "@epoch-agent/protocol": "0.4.0",
27
- "@epoch-agent/infra": "0.4.0",
28
- "@epoch-agent/runtime": "0.4.0",
29
- "@epoch-agent/server": "0.4.0",
30
- "@epoch-agent/tui": "^0.4.0"
25
+ "@epoch-agent/runtime": "0.5.0",
26
+ "@epoch-agent/protocol": "0.5.0",
27
+ "@epoch-agent/infra": "0.5.0",
28
+ "@epoch-agent/tui": "^0.5.0",
29
+ "@epoch-agent/core": "0.5.0",
30
+ "@epoch-agent/server": "0.5.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.20.1",