@evident-ai/cli 3.1.1-dev.b860956 → 3.1.1-dev.bc26090

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/README.md CHANGED
@@ -85,6 +85,7 @@ Options:
85
85
 
86
86
  - `-a, --agent [id]` — Runner ID to connect to. Optional when `EVIDENT_AGENT_KEY`
87
87
  is set (the runner is then resolved automatically from the key).
88
+ - `--runner [id]` — Alias for `--agent` (preferred name; wins if both are given).
88
89
  - `-p, --port <port>` — OpenCode port (default: `4096`).
89
90
  - `--log-level <level>` — Log verbosity: `debug | info | warn | error` (default:
90
91
  `info`). Env: `EVIDENT_LOG_LEVEL`.
@@ -105,15 +106,18 @@ targets the **production** Evident platform by default.
105
106
 
106
107
  ## Environment variables
107
108
 
108
- - `EVIDENT_AGENT_KEY` — A runner key. When set, `evident run` authenticates as
109
- that runner and resolves the runner ID automatically, so `--agent` is not
110
- required. Ideal for CI/CD.
109
+ - `EVIDENT_RUNNER_KEY` — A runner key. When set, `evident run` authenticates as
110
+ that runner and resolves the runner ID automatically, so `--runner`/`--agent`
111
+ is not required. Ideal for CI/CD. Preferred name; wins over `EVIDENT_AGENT_KEY`
112
+ if both are set.
113
+ - `EVIDENT_AGENT_KEY` — Alias for `EVIDENT_RUNNER_KEY` (still fully supported).
111
114
  - `EVIDENT_TOKEN` — A user token used for authentication (alternative to a
112
115
  keychain login from `evident login`).
113
116
  - `EVIDENT_API_URL` — Override the API base URL (equivalent to `--endpoint`).
114
117
  - `EVIDENT_TUNNEL_URL` — Override the tunnel relay URL (equivalent to `--tunnel`).
115
118
 
116
- Authentication precedence for `run`: `EVIDENT_AGENT_KEY` → `EVIDENT_TOKEN` →
119
+ Authentication precedence for `run`: `EVIDENT_RUNNER_KEY`/`EVIDENT_AGENT_KEY`
120
+ (tied; `EVIDENT_RUNNER_KEY` wins if both are set) → `EVIDENT_TOKEN` →
117
121
  credentials stored by `evident login`. For the URL flags, an explicit
118
122
  `--endpoint` / `--tunnel` flag wins over the matching environment variable, which
119
123
  in turn overrides the production default.
@@ -150,6 +154,8 @@ For CI or unattended use, set `EVIDENT_AGENT_KEY` and omit `--agent`:
150
154
  EVIDENT_AGENT_KEY=<agent-key> evident run --idle-timeout 30
151
155
  ```
152
156
 
157
+ (`EVIDENT_RUNNER_KEY` is equivalent and the preferred name — use whichever you like.)
158
+
153
159
  ## How it works
154
160
 
155
161
  ```
package/dist/index.js CHANGED
@@ -645,14 +645,27 @@ var EventTypes = {
645
645
  // CLI lifecycle
646
646
  CLI_STARTED: "cli.started",
647
647
  CLI_COMMAND: "cli.command",
648
- CLI_ERROR: "cli.error"
648
+ CLI_ERROR: "cli.error",
649
+ // Deprecation telemetry (#412) — usage of the old `--agent`/`EVIDENT_AGENT_KEY`
650
+ // names instead of the preferred `--runner`/`EVIDENT_RUNNER_KEY` (#409).
651
+ DEPRECATED_AGENT_FLAG_USED: "cli.deprecated_agent_flag_used",
652
+ DEPRECATED_AGENT_KEY_ENV_USED: "cli.deprecated_agent_key_env_used"
649
653
  };
650
654
 
651
655
  // src/lib/auth.ts
652
656
  async function getAuthCredentials() {
657
+ const runnerKey = process.env.EVIDENT_RUNNER_KEY;
653
658
  const agentKey = process.env.EVIDENT_AGENT_KEY;
659
+ if (runnerKey) {
660
+ return {
661
+ token: runnerKey,
662
+ authType: "agent_key",
663
+ keySource: "runner_key",
664
+ notice: agentKey ? "Both EVIDENT_RUNNER_KEY and EVIDENT_AGENT_KEY are set; using EVIDENT_RUNNER_KEY." : void 0
665
+ };
666
+ }
654
667
  if (agentKey) {
655
- return { token: agentKey, authType: "agent_key" };
668
+ return { token: agentKey, authType: "agent_key", keySource: "agent_key" };
656
669
  }
657
670
  const userToken = process.env.EVIDENT_TOKEN;
658
671
  if (userToken) {
@@ -1370,6 +1383,72 @@ function findLastAssistantReplyFor(messages, userMessageId) {
1370
1383
  }
1371
1384
  return lastOk ?? last;
1372
1385
  }
1386
+ function messageUsage(messages, userMessageId) {
1387
+ if (!messages || messages.length === 0) return null;
1388
+ const byParentAll = messages.filter(
1389
+ (m) => roleOf(m) === "assistant" && parentIdOf(m) === userMessageId
1390
+ );
1391
+ const byParentNonErrored = byParentAll.filter((m) => errorOf(m) == null);
1392
+ const byParent = byParentNonErrored.length > 0 ? byParentNonErrored : byParentAll;
1393
+ let correlated;
1394
+ if (byParent.length > 0) {
1395
+ correlated = byParent;
1396
+ } else {
1397
+ const reply = findAssistantReplyAfter(messages, userMessageId);
1398
+ correlated = reply ? [reply] : [];
1399
+ }
1400
+ if (correlated.length === 0) return null;
1401
+ let sawAnyUsage = false;
1402
+ let inputSum = 0;
1403
+ let outputSum = 0;
1404
+ let reasoningSum = 0;
1405
+ let cacheReadSum = 0;
1406
+ let cacheWriteSum = 0;
1407
+ let costSum = 0;
1408
+ let sawCost = false;
1409
+ let modelId = null;
1410
+ let providerId = null;
1411
+ for (const m of correlated) {
1412
+ const info = m.info;
1413
+ if (!info) continue;
1414
+ const tokens = info.tokens;
1415
+ if (tokens) {
1416
+ sawAnyUsage = true;
1417
+ inputSum += tokens.input ?? 0;
1418
+ outputSum += tokens.output ?? 0;
1419
+ reasoningSum += tokens.reasoning ?? 0;
1420
+ cacheReadSum += tokens.cache?.read ?? 0;
1421
+ cacheWriteSum += tokens.cache?.write ?? 0;
1422
+ }
1423
+ if (typeof info.cost === "number") {
1424
+ sawAnyUsage = true;
1425
+ sawCost = true;
1426
+ costSum += info.cost;
1427
+ }
1428
+ if (typeof info.modelID === "string") {
1429
+ sawAnyUsage = true;
1430
+ modelId = info.modelID;
1431
+ }
1432
+ if (typeof info.providerID === "string") {
1433
+ sawAnyUsage = true;
1434
+ providerId = info.providerID;
1435
+ }
1436
+ }
1437
+ if (!sawAnyUsage) return null;
1438
+ return {
1439
+ usage_provider_id: providerId,
1440
+ usage_model_id: modelId,
1441
+ usage_tokens_input: inputSum,
1442
+ usage_tokens_output: outputSum,
1443
+ usage_tokens_reasoning: reasoningSum,
1444
+ usage_tokens_cache_read: cacheReadSum,
1445
+ usage_tokens_cache_write: cacheWriteSum,
1446
+ // NULL means "OpenCode never reported a cost" (never inferred from
1447
+ // tokens) — distinct from a genuine 0-cost turn, which would set
1448
+ // `sawCost` true with `costSum === 0`.
1449
+ usage_cost_usd: sawCost ? costSum : null
1450
+ };
1451
+ }
1373
1452
  function messageRunState(messages, userMessageId) {
1374
1453
  if (!messages || messages.length === 0) return "unknown";
1375
1454
  const hasUser = messages.some((m) => idOf(m) === userMessageId);
@@ -1716,7 +1795,6 @@ function connectTunnel(options) {
1716
1795
  onConnected,
1717
1796
  onDisconnected,
1718
1797
  onError,
1719
- onRequest,
1720
1798
  onResponse,
1721
1799
  onInfo,
1722
1800
  onDrainPing
@@ -1729,18 +1807,8 @@ function connectTunnel(options) {
1729
1807
  Authorization: authHeader
1730
1808
  }
1731
1809
  });
1732
- const streamStartTimes = /* @__PURE__ */ new Map();
1733
1810
  const forwarder = new StreamForwarder(ws, port, {
1734
- onOpen: (sid, method, path) => {
1735
- if (path === TUNNEL_DRAIN_PING_PATH) return;
1736
- streamStartTimes.set(sid, Date.now());
1737
- onRequest?.(method, path, sid);
1738
- },
1739
- onHead: (sid, status) => {
1740
- const startedAt = streamStartTimes.get(sid);
1741
- streamStartTimes.delete(sid);
1742
- onResponse?.(status, startedAt ? Date.now() - startedAt : 0, sid);
1743
- },
1811
+ onHead: () => onResponse?.(),
1744
1812
  onDrainPing: () => onDrainPing?.()
1745
1813
  });
1746
1814
  const connectionTimeout = setTimeout(() => {
@@ -1816,7 +1884,6 @@ function connectTunnel(options) {
1816
1884
  ws.on("close", (code, reason) => {
1817
1885
  const reasonStr = reason.toString() || upgradeRejection || (code === 1006 ? "abnormal closure" : "No reason provided");
1818
1886
  forwarder.abortAll();
1819
- streamStartTimes.clear();
1820
1887
  onDisconnected?.(code, reasonStr);
1821
1888
  });
1822
1889
  });
@@ -2445,7 +2512,7 @@ var ChannelDriver = class {
2445
2512
  }
2446
2513
  /**
2447
2514
  * Fetch ONE inbound image's bytes through Evident's WI-6 endpoint
2448
- * (`GET {apiUrl}/agents/{agentId}/attachments/{messageId}/{index}`) using the
2515
+ * (`GET {apiUrl}/runners/{agentId}/attachments/{messageId}/{index}`) using the
2449
2516
  * existing authenticated fetch, and base64-encode into a
2450
2517
  * `data:<mime>;base64,<…>` URL for the opencode `file` part's `url`.
2451
2518
  *
@@ -2458,7 +2525,7 @@ var ChannelDriver = class {
2458
2525
  async fetchAttachmentDataUrl(messageId, index, mime) {
2459
2526
  try {
2460
2527
  const res = await this.fetchImpl(
2461
- `${this.apiUrl}/agents/${this.agentId}/attachments/${messageId}/${index}`,
2528
+ `${this.apiUrl}/runners/${this.agentId}/attachments/${messageId}/${index}`,
2462
2529
  { headers: { Authorization: this.getAuthHeader() } }
2463
2530
  );
2464
2531
  if (!res.ok) {
@@ -2790,13 +2857,15 @@ var ChannelDriver = class {
2790
2857
  message_id: inFlight.evidentMessageId
2791
2858
  });
2792
2859
  const title = await this.resolveSessionTitle(sessionId, watcher.conv.id);
2860
+ const usage = messageUsage(messages, inFlight.opencodeMessageId);
2793
2861
  try {
2794
2862
  await this.markDone(
2795
2863
  conv.id,
2796
2864
  inFlight.evidentMessageId,
2797
2865
  sessionId,
2798
2866
  inFlight.opencodeMessageId,
2799
- title
2867
+ title,
2868
+ usage
2800
2869
  );
2801
2870
  } catch (err) {
2802
2871
  if (err instanceof ChannelAuthError) throw err;
@@ -2843,8 +2912,9 @@ var ChannelDriver = class {
2843
2912
  conversation_id: conv.id,
2844
2913
  message_id: inFlight.evidentMessageId
2845
2914
  });
2915
+ const usage = messageUsage(messages, inFlight.opencodeMessageId);
2846
2916
  try {
2847
- await this.markFailed(conv.id, inFlight.evidentMessageId, sessionId, error2);
2917
+ await this.markFailed(conv.id, inFlight.evidentMessageId, sessionId, error2, usage);
2848
2918
  } catch (err) {
2849
2919
  if (err instanceof ChannelAuthError) throw err;
2850
2920
  if (err instanceof ChannelTerminalError) {
@@ -3081,7 +3151,8 @@ var ChannelDriver = class {
3081
3151
  });
3082
3152
  try {
3083
3153
  const title = await this.resolveSessionTitle(sessionId, row.conversation_id);
3084
- await this.markDone(row.conversation_id, row.id, sessionId, ocId, title);
3154
+ const usage = messageUsage(messages, ocId ?? "");
3155
+ await this.markDone(row.conversation_id, row.id, sessionId, ocId, title, usage);
3085
3156
  } catch (err) {
3086
3157
  if (err instanceof ChannelAuthError) throw err;
3087
3158
  if (err instanceof ChannelTerminalError) {
@@ -3109,6 +3180,7 @@ var ChannelDriver = class {
3109
3180
  }
3110
3181
  if (state === "failed") {
3111
3182
  const error2 = messageError(messages, ocId ?? "") ?? void 0;
3183
+ const usage = messageUsage(messages, ocId ?? "");
3112
3184
  this.log({
3113
3185
  level: "error",
3114
3186
  message: `Re-adopt: message ${row.id.slice(0, 8)} errored while unwatched \u2014 marking failed: ${error2 ?? "(no error text)"}`,
@@ -3116,7 +3188,7 @@ var ChannelDriver = class {
3116
3188
  message_id: row.id
3117
3189
  });
3118
3190
  try {
3119
- await this.markFailed(row.conversation_id, row.id, sessionId, error2);
3191
+ await this.markFailed(row.conversation_id, row.id, sessionId, error2, usage);
3120
3192
  } catch (err) {
3121
3193
  if (err instanceof ChannelAuthError) throw err;
3122
3194
  if (err instanceof ChannelTerminalError) {
@@ -3719,7 +3791,7 @@ var ChannelDriver = class {
3719
3791
  // Evident API calls (combinedAuth thread routes)
3720
3792
  async getPendingConversations() {
3721
3793
  const res = await this.fetchImpl(
3722
- `${this.apiUrl}/agents/${this.agentId}/conversations/pending`,
3794
+ `${this.apiUrl}/runners/${this.agentId}/conversations/pending`,
3723
3795
  {
3724
3796
  headers: { Authorization: this.getAuthHeader() }
3725
3797
  }
@@ -3737,7 +3809,7 @@ var ChannelDriver = class {
3737
3809
  }
3738
3810
  async getPendingMessages(conversationId) {
3739
3811
  const res = await this.fetchImpl(
3740
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages?status=pending`,
3812
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages?status=pending`,
3741
3813
  { headers: { Authorization: this.getAuthHeader() } }
3742
3814
  );
3743
3815
  this.assertAuth(res, "fetching pending messages");
@@ -3761,7 +3833,7 @@ var ChannelDriver = class {
3761
3833
  */
3762
3834
  async getProcessingMessages() {
3763
3835
  const res = await this.fetchImpl(
3764
- `${this.apiUrl}/agents/${this.agentId}/conversations/processing`,
3836
+ `${this.apiUrl}/runners/${this.agentId}/conversations/processing`,
3765
3837
  { headers: { Authorization: this.getAuthHeader() } }
3766
3838
  );
3767
3839
  this.assertAuth(res, "fetching processing messages");
@@ -3798,7 +3870,7 @@ var ChannelDriver = class {
3798
3870
  */
3799
3871
  async markProcessing(conversationId, messageId, sessionId, opencodeMessageId, title) {
3800
3872
  const res = await this.fetchImpl(
3801
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3873
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3802
3874
  {
3803
3875
  method: "PATCH",
3804
3876
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3845,9 +3917,9 @@ var ChannelDriver = class {
3845
3917
  * watcher retries next tick within the
3846
3918
  * deadline, Finding 4).
3847
3919
  */
3848
- async markDone(conversationId, messageId, sessionId, opencodeMessageId, title) {
3920
+ async markDone(conversationId, messageId, sessionId, opencodeMessageId, title, usage) {
3849
3921
  const res = await this.fetchImpl(
3850
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3922
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3851
3923
  {
3852
3924
  method: "PATCH",
3853
3925
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3855,7 +3927,8 @@ var ChannelDriver = class {
3855
3927
  status: "done",
3856
3928
  opencode_session_id: sessionId,
3857
3929
  ...opencodeMessageId ? { opencode_message_id: opencodeMessageId } : {},
3858
- ...title ? { title } : {}
3930
+ ...title ? { title } : {},
3931
+ ...usage ? usage : {}
3859
3932
  })
3860
3933
  }
3861
3934
  );
@@ -3873,14 +3946,15 @@ var ChannelDriver = class {
3873
3946
  * OpenCode turn sends `{status:'failed', opencode_session_id, error}` so the
3874
3947
  * failure reason reaches the channel.
3875
3948
  */
3876
- async markFailed(conversationId, messageId, sessionId, error2) {
3949
+ async markFailed(conversationId, messageId, sessionId, error2, usage) {
3877
3950
  const body = { status: "failed" };
3878
3951
  if (sessionId !== void 0) body.opencode_session_id = sessionId;
3879
3952
  if (error2 !== void 0) body.error = error2;
3953
+ if (usage) Object.assign(body, usage);
3880
3954
  await this.callWithRetry(
3881
3955
  "marking message as failed",
3882
3956
  () => this.fetchImpl(
3883
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3957
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3884
3958
  {
3885
3959
  method: "PATCH",
3886
3960
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3907,7 +3981,7 @@ var ChannelDriver = class {
3907
3981
  async postSignal(conversationId, messageId, signal, extra) {
3908
3982
  try {
3909
3983
  const res = await this.fetchImpl(
3910
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}/signal`,
3984
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}/signal`,
3911
3985
  {
3912
3986
  method: "POST",
3913
3987
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3936,7 +4010,7 @@ var ChannelDriver = class {
3936
4010
  }
3937
4011
  async persistSession(conversationId, sessionId) {
3938
4012
  const res = await this.fetchImpl(
3939
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}`,
4013
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}`,
3940
4014
  {
3941
4015
  method: "PATCH",
3942
4016
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3962,7 +4036,7 @@ var ChannelDriver = class {
3962
4036
  await this.callWithRetry(
3963
4037
  "reporting interactive event",
3964
4038
  () => this.fetchImpl(
3965
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/interactive-event`,
4039
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/interactive-event`,
3966
4040
  {
3967
4041
  method: "POST",
3968
4042
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -4205,7 +4279,7 @@ async function resolveAgentIdFromKey(authHeader) {
4205
4279
  async function notifyAgentDisconnected(agentId, authHeader) {
4206
4280
  const apiUrl = getApiUrlConfig();
4207
4281
  try {
4208
- const response = await fetch(`${apiUrl}/agents/${agentId}/disconnect`, {
4282
+ const response = await fetch(`${apiUrl}/runners/${agentId}/disconnect`, {
4209
4283
  method: "POST",
4210
4284
  headers: { Authorization: authHeader }
4211
4285
  });
@@ -4224,7 +4298,7 @@ async function notifyAgentDisconnected(agentId, authHeader) {
4224
4298
  async function getAgentInfo(agentId, authHeader) {
4225
4299
  const apiUrl = getApiUrlConfig();
4226
4300
  try {
4227
- const response = await fetch(`${apiUrl}/agents/${agentId}`, {
4301
+ const response = await fetch(`${apiUrl}/runners/${agentId}`, {
4228
4302
  headers: { Authorization: authHeader }
4229
4303
  });
4230
4304
  if (response.status === 401) {
@@ -4611,7 +4685,7 @@ async function run(options) {
4611
4685
  return;
4612
4686
  }
4613
4687
  const state = {
4614
- agentId: options.agent || "",
4688
+ agentId: options.runner || options.agent || "",
4615
4689
  agentName: null,
4616
4690
  port: options.port ?? 4096,
4617
4691
  conversationFilter: options.conversation ?? null,
@@ -4633,6 +4707,19 @@ async function run(options) {
4633
4707
  sessionCleanupTimers: [],
4634
4708
  authHeader: ""
4635
4709
  };
4710
+ if (!options.runner && options.agent) {
4711
+ telemetry.info(
4712
+ EventTypes.DEPRECATED_AGENT_FLAG_USED,
4713
+ "Deprecated --agent flag used instead of --runner",
4714
+ { command: "run" },
4715
+ state.agentId
4716
+ );
4717
+ const agentFlagNotice = "--agent is deprecated, use --runner instead; will be removed in a future release.";
4718
+ log2(state, agentFlagNotice, "warn");
4719
+ if (state.interactive && !state.json) {
4720
+ logActivity(state, { type: "info", level: "warn", message: agentFlagNotice });
4721
+ }
4722
+ }
4636
4723
  if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {
4637
4724
  log2(
4638
4725
  state,
@@ -4661,7 +4748,9 @@ async function run(options) {
4661
4748
  if (!interactive) {
4662
4749
  printError("Authentication required");
4663
4750
  blank();
4664
- console.log(chalk6.dim("Set EVIDENT_AGENT_KEY environment variable for CI"));
4751
+ console.log(
4752
+ chalk6.dim("Set EVIDENT_RUNNER_KEY (or EVIDENT_AGENT_KEY) environment variable for CI")
4753
+ );
4665
4754
  console.log(chalk6.dim("Or run `evident login` for interactive authentication"));
4666
4755
  blank();
4667
4756
  process.exit(1);
@@ -4675,6 +4764,25 @@ async function run(options) {
4675
4764
  );
4676
4765
  }
4677
4766
  state.authHeader = getAuthHeader(credentials2);
4767
+ if (credentials2.notice) {
4768
+ log2(state, credentials2.notice, "warn");
4769
+ if (state.interactive && !state.json) {
4770
+ logActivity(state, { type: "info", level: "warn", message: credentials2.notice });
4771
+ }
4772
+ }
4773
+ if (credentials2.keySource === "agent_key") {
4774
+ telemetry.info(
4775
+ EventTypes.DEPRECATED_AGENT_KEY_ENV_USED,
4776
+ "Deprecated EVIDENT_AGENT_KEY env var used instead of EVIDENT_RUNNER_KEY",
4777
+ { command: "run" },
4778
+ state.agentId
4779
+ );
4780
+ const agentKeyNotice = "EVIDENT_AGENT_KEY is deprecated, use EVIDENT_RUNNER_KEY instead; will be removed in a future release.";
4781
+ log2(state, agentKeyNotice, "warn");
4782
+ if (state.interactive && !state.json) {
4783
+ logActivity(state, { type: "info", level: "warn", message: agentKeyNotice });
4784
+ }
4785
+ }
4678
4786
  if (!state.agentId) {
4679
4787
  if (credentials2.authType === "agent_key") {
4680
4788
  const resolved = await resolveAgentIdFromKey(state.authHeader);
@@ -4692,9 +4800,15 @@ async function run(options) {
4692
4800
  process.exit(1);
4693
4801
  }
4694
4802
  } else {
4695
- printError("--agent is required when not using EVIDENT_AGENT_KEY");
4803
+ printError(
4804
+ "--runner (or --agent) is required when not using EVIDENT_RUNNER_KEY or EVIDENT_AGENT_KEY"
4805
+ );
4696
4806
  blank();
4697
- console.log(chalk6.dim("Either provide --agent <id> or set EVIDENT_AGENT_KEY"));
4807
+ console.log(
4808
+ chalk6.dim(
4809
+ "Either provide --runner/--agent <id> or set EVIDENT_RUNNER_KEY/EVIDENT_AGENT_KEY"
4810
+ )
4811
+ );
4698
4812
  blank();
4699
4813
  process.exit(1);
4700
4814
  }
@@ -4909,7 +5023,7 @@ async function run(options) {
4909
5023
  }
4910
5024
  telemetry.error(EventTypes.CLI_ERROR, `Run command failed: ${message}`, {
4911
5025
  command: "run",
4912
- agentId: options.agent
5026
+ agentId: options.runner || options.agent
4913
5027
  });
4914
5028
  await shutdownTelemetry();
4915
5029
  process.exit(1);
@@ -4934,7 +5048,7 @@ program.name("evident").description("Run OpenCode locally and connect it to Evid
4934
5048
  program.command("login").description("Authenticate with Evident").option("--token", "Use token-based authentication (for CI/CD)").option("--no-browser", "Do not open the browser automatically").action(login);
4935
5049
  program.command("logout").description("Remove stored credentials for the current endpoint").option("--all", "Remove stored credentials for all endpoints").action((options) => logout({ all: options.all }));
4936
5050
  program.command("whoami").description("Show the currently logged in user").action(whoami);
4937
- program.command("run").description("Connect to Evident and process messages").option("-a, --agent [id]", "Runner ID to connect to (optional when EVIDENT_AGENT_KEY is set)").option("-p, --port <port>", "OpenCode port (default: 4096)", "4096").option(
5051
+ program.command("run").description("Connect to Evident and process messages").option("-a, --agent [id]", "Runner ID to connect to (optional when EVIDENT_AGENT_KEY is set)").option("--runner [id]", "Alias for --agent (preferred name; wins if both are given)").option("-p, --port <port>", "OpenCode port (default: 4096)", "4096").option(
4938
5052
  "--log-level <level>",
4939
5053
  "Log verbosity: debug | info | warn | error (default: info). Env: EVIDENT_LOG_LEVEL"
4940
5054
  ).option("-v, --verbose", "Alias for --log-level debug (ignored if --log-level is set)").option("-c, --conversation <id>", "Process only this specific conversation").option("--idle-timeout <seconds>", "Exit after N seconds idle").option("--json", "Output in JSON format").option(
@@ -4950,6 +5064,7 @@ program.command("run").description("Connect to Evident and process messages").op
4950
5064
  (options) => {
4951
5065
  run({
4952
5066
  agent: options.agent,
5067
+ runner: options.runner,
4953
5068
  port: parseInt(options.port, 10),
4954
5069
  // Raw string — validation/precedence is single-sourced in run.ts's
4955
5070
  // resolveLogLevel (flag > -v > EVIDENT_LOG_LEVEL > info).