@evident-ai/cli 3.1.1-dev.702ee74 → 3.1.1-dev.8d786ea

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);
@@ -2445,7 +2524,7 @@ var ChannelDriver = class {
2445
2524
  }
2446
2525
  /**
2447
2526
  * Fetch ONE inbound image's bytes through Evident's WI-6 endpoint
2448
- * (`GET {apiUrl}/agents/{agentId}/attachments/{messageId}/{index}`) using the
2527
+ * (`GET {apiUrl}/runners/{agentId}/attachments/{messageId}/{index}`) using the
2449
2528
  * existing authenticated fetch, and base64-encode into a
2450
2529
  * `data:<mime>;base64,<…>` URL for the opencode `file` part's `url`.
2451
2530
  *
@@ -2458,7 +2537,7 @@ var ChannelDriver = class {
2458
2537
  async fetchAttachmentDataUrl(messageId, index, mime) {
2459
2538
  try {
2460
2539
  const res = await this.fetchImpl(
2461
- `${this.apiUrl}/agents/${this.agentId}/attachments/${messageId}/${index}`,
2540
+ `${this.apiUrl}/runners/${this.agentId}/attachments/${messageId}/${index}`,
2462
2541
  { headers: { Authorization: this.getAuthHeader() } }
2463
2542
  );
2464
2543
  if (!res.ok) {
@@ -2790,13 +2869,15 @@ var ChannelDriver = class {
2790
2869
  message_id: inFlight.evidentMessageId
2791
2870
  });
2792
2871
  const title = await this.resolveSessionTitle(sessionId, watcher.conv.id);
2872
+ const usage = messageUsage(messages, inFlight.opencodeMessageId);
2793
2873
  try {
2794
2874
  await this.markDone(
2795
2875
  conv.id,
2796
2876
  inFlight.evidentMessageId,
2797
2877
  sessionId,
2798
2878
  inFlight.opencodeMessageId,
2799
- title
2879
+ title,
2880
+ usage
2800
2881
  );
2801
2882
  } catch (err) {
2802
2883
  if (err instanceof ChannelAuthError) throw err;
@@ -2843,8 +2924,9 @@ var ChannelDriver = class {
2843
2924
  conversation_id: conv.id,
2844
2925
  message_id: inFlight.evidentMessageId
2845
2926
  });
2927
+ const usage = messageUsage(messages, inFlight.opencodeMessageId);
2846
2928
  try {
2847
- await this.markFailed(conv.id, inFlight.evidentMessageId, sessionId, error2);
2929
+ await this.markFailed(conv.id, inFlight.evidentMessageId, sessionId, error2, usage);
2848
2930
  } catch (err) {
2849
2931
  if (err instanceof ChannelAuthError) throw err;
2850
2932
  if (err instanceof ChannelTerminalError) {
@@ -3081,7 +3163,8 @@ var ChannelDriver = class {
3081
3163
  });
3082
3164
  try {
3083
3165
  const title = await this.resolveSessionTitle(sessionId, row.conversation_id);
3084
- await this.markDone(row.conversation_id, row.id, sessionId, ocId, title);
3166
+ const usage = messageUsage(messages, ocId ?? "");
3167
+ await this.markDone(row.conversation_id, row.id, sessionId, ocId, title, usage);
3085
3168
  } catch (err) {
3086
3169
  if (err instanceof ChannelAuthError) throw err;
3087
3170
  if (err instanceof ChannelTerminalError) {
@@ -3109,6 +3192,7 @@ var ChannelDriver = class {
3109
3192
  }
3110
3193
  if (state === "failed") {
3111
3194
  const error2 = messageError(messages, ocId ?? "") ?? void 0;
3195
+ const usage = messageUsage(messages, ocId ?? "");
3112
3196
  this.log({
3113
3197
  level: "error",
3114
3198
  message: `Re-adopt: message ${row.id.slice(0, 8)} errored while unwatched \u2014 marking failed: ${error2 ?? "(no error text)"}`,
@@ -3116,7 +3200,7 @@ var ChannelDriver = class {
3116
3200
  message_id: row.id
3117
3201
  });
3118
3202
  try {
3119
- await this.markFailed(row.conversation_id, row.id, sessionId, error2);
3203
+ await this.markFailed(row.conversation_id, row.id, sessionId, error2, usage);
3120
3204
  } catch (err) {
3121
3205
  if (err instanceof ChannelAuthError) throw err;
3122
3206
  if (err instanceof ChannelTerminalError) {
@@ -3719,7 +3803,7 @@ var ChannelDriver = class {
3719
3803
  // Evident API calls (combinedAuth thread routes)
3720
3804
  async getPendingConversations() {
3721
3805
  const res = await this.fetchImpl(
3722
- `${this.apiUrl}/agents/${this.agentId}/conversations/pending`,
3806
+ `${this.apiUrl}/runners/${this.agentId}/conversations/pending`,
3723
3807
  {
3724
3808
  headers: { Authorization: this.getAuthHeader() }
3725
3809
  }
@@ -3737,7 +3821,7 @@ var ChannelDriver = class {
3737
3821
  }
3738
3822
  async getPendingMessages(conversationId) {
3739
3823
  const res = await this.fetchImpl(
3740
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages?status=pending`,
3824
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages?status=pending`,
3741
3825
  { headers: { Authorization: this.getAuthHeader() } }
3742
3826
  );
3743
3827
  this.assertAuth(res, "fetching pending messages");
@@ -3761,7 +3845,7 @@ var ChannelDriver = class {
3761
3845
  */
3762
3846
  async getProcessingMessages() {
3763
3847
  const res = await this.fetchImpl(
3764
- `${this.apiUrl}/agents/${this.agentId}/conversations/processing`,
3848
+ `${this.apiUrl}/runners/${this.agentId}/conversations/processing`,
3765
3849
  { headers: { Authorization: this.getAuthHeader() } }
3766
3850
  );
3767
3851
  this.assertAuth(res, "fetching processing messages");
@@ -3798,7 +3882,7 @@ var ChannelDriver = class {
3798
3882
  */
3799
3883
  async markProcessing(conversationId, messageId, sessionId, opencodeMessageId, title) {
3800
3884
  const res = await this.fetchImpl(
3801
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3885
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3802
3886
  {
3803
3887
  method: "PATCH",
3804
3888
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3845,9 +3929,9 @@ var ChannelDriver = class {
3845
3929
  * watcher retries next tick within the
3846
3930
  * deadline, Finding 4).
3847
3931
  */
3848
- async markDone(conversationId, messageId, sessionId, opencodeMessageId, title) {
3932
+ async markDone(conversationId, messageId, sessionId, opencodeMessageId, title, usage) {
3849
3933
  const res = await this.fetchImpl(
3850
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3934
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3851
3935
  {
3852
3936
  method: "PATCH",
3853
3937
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3855,7 +3939,8 @@ var ChannelDriver = class {
3855
3939
  status: "done",
3856
3940
  opencode_session_id: sessionId,
3857
3941
  ...opencodeMessageId ? { opencode_message_id: opencodeMessageId } : {},
3858
- ...title ? { title } : {}
3942
+ ...title ? { title } : {},
3943
+ ...usage ? usage : {}
3859
3944
  })
3860
3945
  }
3861
3946
  );
@@ -3873,14 +3958,15 @@ var ChannelDriver = class {
3873
3958
  * OpenCode turn sends `{status:'failed', opencode_session_id, error}` so the
3874
3959
  * failure reason reaches the channel.
3875
3960
  */
3876
- async markFailed(conversationId, messageId, sessionId, error2) {
3961
+ async markFailed(conversationId, messageId, sessionId, error2, usage) {
3877
3962
  const body = { status: "failed" };
3878
3963
  if (sessionId !== void 0) body.opencode_session_id = sessionId;
3879
3964
  if (error2 !== void 0) body.error = error2;
3965
+ if (usage) Object.assign(body, usage);
3880
3966
  await this.callWithRetry(
3881
3967
  "marking message as failed",
3882
3968
  () => this.fetchImpl(
3883
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3969
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
3884
3970
  {
3885
3971
  method: "PATCH",
3886
3972
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3907,7 +3993,7 @@ var ChannelDriver = class {
3907
3993
  async postSignal(conversationId, messageId, signal, extra) {
3908
3994
  try {
3909
3995
  const res = await this.fetchImpl(
3910
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}/signal`,
3996
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}/signal`,
3911
3997
  {
3912
3998
  method: "POST",
3913
3999
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3936,7 +4022,7 @@ var ChannelDriver = class {
3936
4022
  }
3937
4023
  async persistSession(conversationId, sessionId) {
3938
4024
  const res = await this.fetchImpl(
3939
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}`,
4025
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}`,
3940
4026
  {
3941
4027
  method: "PATCH",
3942
4028
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -3962,7 +4048,7 @@ var ChannelDriver = class {
3962
4048
  await this.callWithRetry(
3963
4049
  "reporting interactive event",
3964
4050
  () => this.fetchImpl(
3965
- `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/interactive-event`,
4051
+ `${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/interactive-event`,
3966
4052
  {
3967
4053
  method: "POST",
3968
4054
  headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
@@ -4205,7 +4291,7 @@ async function resolveAgentIdFromKey(authHeader) {
4205
4291
  async function notifyAgentDisconnected(agentId, authHeader) {
4206
4292
  const apiUrl = getApiUrlConfig();
4207
4293
  try {
4208
- const response = await fetch(`${apiUrl}/agents/${agentId}/disconnect`, {
4294
+ const response = await fetch(`${apiUrl}/runners/${agentId}/disconnect`, {
4209
4295
  method: "POST",
4210
4296
  headers: { Authorization: authHeader }
4211
4297
  });
@@ -4224,7 +4310,7 @@ async function notifyAgentDisconnected(agentId, authHeader) {
4224
4310
  async function getAgentInfo(agentId, authHeader) {
4225
4311
  const apiUrl = getApiUrlConfig();
4226
4312
  try {
4227
- const response = await fetch(`${apiUrl}/agents/${agentId}`, {
4313
+ const response = await fetch(`${apiUrl}/runners/${agentId}`, {
4228
4314
  headers: { Authorization: authHeader }
4229
4315
  });
4230
4316
  if (response.status === 401) {
@@ -4611,7 +4697,7 @@ async function run(options) {
4611
4697
  return;
4612
4698
  }
4613
4699
  const state = {
4614
- agentId: options.agent || "",
4700
+ agentId: options.runner || options.agent || "",
4615
4701
  agentName: null,
4616
4702
  port: options.port ?? 4096,
4617
4703
  conversationFilter: options.conversation ?? null,
@@ -4633,6 +4719,19 @@ async function run(options) {
4633
4719
  sessionCleanupTimers: [],
4634
4720
  authHeader: ""
4635
4721
  };
4722
+ if (!options.runner && options.agent) {
4723
+ telemetry.info(
4724
+ EventTypes.DEPRECATED_AGENT_FLAG_USED,
4725
+ "Deprecated --agent flag used instead of --runner",
4726
+ { command: "run" },
4727
+ state.agentId
4728
+ );
4729
+ const agentFlagNotice = "--agent is deprecated, use --runner instead; will be removed in a future release.";
4730
+ log2(state, agentFlagNotice, "warn");
4731
+ if (state.interactive && !state.json) {
4732
+ logActivity(state, { type: "info", level: "warn", message: agentFlagNotice });
4733
+ }
4734
+ }
4636
4735
  if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {
4637
4736
  log2(
4638
4737
  state,
@@ -4661,7 +4760,9 @@ async function run(options) {
4661
4760
  if (!interactive) {
4662
4761
  printError("Authentication required");
4663
4762
  blank();
4664
- console.log(chalk6.dim("Set EVIDENT_AGENT_KEY environment variable for CI"));
4763
+ console.log(
4764
+ chalk6.dim("Set EVIDENT_RUNNER_KEY (or EVIDENT_AGENT_KEY) environment variable for CI")
4765
+ );
4665
4766
  console.log(chalk6.dim("Or run `evident login` for interactive authentication"));
4666
4767
  blank();
4667
4768
  process.exit(1);
@@ -4675,6 +4776,25 @@ async function run(options) {
4675
4776
  );
4676
4777
  }
4677
4778
  state.authHeader = getAuthHeader(credentials2);
4779
+ if (credentials2.notice) {
4780
+ log2(state, credentials2.notice, "warn");
4781
+ if (state.interactive && !state.json) {
4782
+ logActivity(state, { type: "info", level: "warn", message: credentials2.notice });
4783
+ }
4784
+ }
4785
+ if (credentials2.keySource === "agent_key") {
4786
+ telemetry.info(
4787
+ EventTypes.DEPRECATED_AGENT_KEY_ENV_USED,
4788
+ "Deprecated EVIDENT_AGENT_KEY env var used instead of EVIDENT_RUNNER_KEY",
4789
+ { command: "run" },
4790
+ state.agentId
4791
+ );
4792
+ const agentKeyNotice = "EVIDENT_AGENT_KEY is deprecated, use EVIDENT_RUNNER_KEY instead; will be removed in a future release.";
4793
+ log2(state, agentKeyNotice, "warn");
4794
+ if (state.interactive && !state.json) {
4795
+ logActivity(state, { type: "info", level: "warn", message: agentKeyNotice });
4796
+ }
4797
+ }
4678
4798
  if (!state.agentId) {
4679
4799
  if (credentials2.authType === "agent_key") {
4680
4800
  const resolved = await resolveAgentIdFromKey(state.authHeader);
@@ -4692,9 +4812,15 @@ async function run(options) {
4692
4812
  process.exit(1);
4693
4813
  }
4694
4814
  } else {
4695
- printError("--agent is required when not using EVIDENT_AGENT_KEY");
4815
+ printError(
4816
+ "--runner (or --agent) is required when not using EVIDENT_RUNNER_KEY or EVIDENT_AGENT_KEY"
4817
+ );
4696
4818
  blank();
4697
- console.log(chalk6.dim("Either provide --agent <id> or set EVIDENT_AGENT_KEY"));
4819
+ console.log(
4820
+ chalk6.dim(
4821
+ "Either provide --runner/--agent <id> or set EVIDENT_RUNNER_KEY/EVIDENT_AGENT_KEY"
4822
+ )
4823
+ );
4698
4824
  blank();
4699
4825
  process.exit(1);
4700
4826
  }
@@ -4909,7 +5035,7 @@ async function run(options) {
4909
5035
  }
4910
5036
  telemetry.error(EventTypes.CLI_ERROR, `Run command failed: ${message}`, {
4911
5037
  command: "run",
4912
- agentId: options.agent
5038
+ agentId: options.runner || options.agent
4913
5039
  });
4914
5040
  await shutdownTelemetry();
4915
5041
  process.exit(1);
@@ -4934,7 +5060,7 @@ program.name("evident").description("Run OpenCode locally and connect it to Evid
4934
5060
  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
5061
  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
5062
  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(
5063
+ 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
5064
  "--log-level <level>",
4939
5065
  "Log verbosity: debug | info | warn | error (default: info). Env: EVIDENT_LOG_LEVEL"
4940
5066
  ).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 +5076,7 @@ program.command("run").description("Connect to Evident and process messages").op
4950
5076
  (options) => {
4951
5077
  run({
4952
5078
  agent: options.agent,
5079
+ runner: options.runner,
4953
5080
  port: parseInt(options.port, 10),
4954
5081
  // Raw string — validation/precedence is single-sourced in run.ts's
4955
5082
  // resolveLogLevel (flag > -v > EVIDENT_LOG_LEVEL > info).