@evident-ai/cli 3.6.1-dev.dac6a7f → 3.6.1-dev.e5cb54f

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
@@ -125,6 +125,10 @@ Options:
125
125
  - `--opencode-config-overlay <path>` — Apply a runner-provided OpenCode config
126
126
  before starting OpenCode. Relative paths are resolved from the working directory;
127
127
  an existing `opencode.jsonc` is replaced before `opencode.json`.
128
+ - `--auto-configure-credentials-proxy` — Install Evident's generated `evident-*`
129
+ OpenCode provider entries for the runner's credential pool. This is off by default;
130
+ without it, the CLI only delivers `EVIDENT_PROXY_TOKEN` and leaves provider
131
+ configuration to you.
128
132
  - `--credential-sync-marker <path>` — Own the interval credential sync and write
129
133
  this marker once the shutdown flush has finished, so the runner image's lifecycle
130
134
  hooks can wait on it.
package/dist/index.js CHANGED
@@ -1442,7 +1442,7 @@ import ora4 from "ora";
1442
1442
  import { select as select4 } from "@inquirer/prompts";
1443
1443
 
1444
1444
  // src/lib/telemetry.ts
1445
- var CLI_VERSION = (true ? "3.6.1-dev.dac6a7f" : void 0) ?? process.env.npm_package_version ?? "unknown";
1445
+ var CLI_VERSION = (true ? "3.6.1-dev.e5cb54f" : void 0) ?? process.env.npm_package_version ?? "unknown";
1446
1446
  function getCliVersion() {
1447
1447
  return CLI_VERSION;
1448
1448
  }
@@ -3209,6 +3209,52 @@ async function getModelAttachmentCapability(port, model, client) {
3209
3209
  return null;
3210
3210
  }
3211
3211
  }
3212
+ async function isPinnedProviderLoaded(port, model, client) {
3213
+ if (client?.version === "v2") return null;
3214
+ const { model: baseModel } = splitModelVariant(model);
3215
+ if (!baseModel) return null;
3216
+ const slash = baseModel.indexOf("/");
3217
+ if (slash <= 0) return null;
3218
+ const providerId = baseModel.slice(0, slash);
3219
+ try {
3220
+ const res = await requestWithClient(port, client, "/config/providers");
3221
+ if (!res.ok) {
3222
+ console.error(
3223
+ `[isPinnedProviderLoaded] GET /config/providers returned HTTP ${res.status} (port ${port})`
3224
+ );
3225
+ return null;
3226
+ }
3227
+ const body = await res.json();
3228
+ if (body === null || typeof body !== "object" || Array.isArray(body)) {
3229
+ console.error(
3230
+ `[isPinnedProviderLoaded] GET /config/providers body was not a plain object (port ${port})`
3231
+ );
3232
+ return null;
3233
+ }
3234
+ const providers = body.providers;
3235
+ if (!Array.isArray(providers)) {
3236
+ console.error(
3237
+ `[isPinnedProviderLoaded] GET /config/providers body had no providers array (port ${port})`
3238
+ );
3239
+ return null;
3240
+ }
3241
+ const providerIds = providers.filter(
3242
+ (provider) => provider !== null && typeof provider === "object" && typeof provider.id === "string"
3243
+ ).map((provider) => provider.id);
3244
+ if (providerIds.length === 0) {
3245
+ console.error(
3246
+ `[isPinnedProviderLoaded] GET /config/providers had no provider entries with string ids (port ${port})`
3247
+ );
3248
+ return null;
3249
+ }
3250
+ return providerIds.includes(providerId);
3251
+ } catch (err) {
3252
+ console.error(
3253
+ `[isPinnedProviderLoaded] GET /config/providers failed (port ${port}): ${err instanceof Error ? err.message : String(err)}`
3254
+ );
3255
+ return null;
3256
+ }
3257
+ }
3212
3258
  async function buildFileParts(attachments, capable) {
3213
3259
  const outcomes = [];
3214
3260
  const parts = [];
@@ -8722,6 +8768,47 @@ var ChannelDriver = class _ChannelDriver {
8722
8768
  agent: message.opencode_agent ?? void 0,
8723
8769
  model: message.opencode_model ?? void 0
8724
8770
  };
8771
+ const pinnedProviderLoaded = await isPinnedProviderLoaded(
8772
+ this.port,
8773
+ options.model,
8774
+ this.openCodeClient
8775
+ );
8776
+ if (pinnedProviderLoaded === false) {
8777
+ const dispatchedModel = message.opencode_model;
8778
+ const separator = dispatchedModel?.indexOf("/") ?? -1;
8779
+ const hasProviderAndModel = dispatchedModel !== null && separator > 0 && separator < dispatchedModel.length - 1;
8780
+ const providerId = hasProviderAndModel ? dispatchedModel.slice(0, separator) : null;
8781
+ const modelId = hasProviderAndModel ? dispatchedModel.slice(separator + 1) : null;
8782
+ const errorMessage3 = `Provider namespace not loaded on this runner: ${message.opencode_model}. Refused before dispatch; no turn was started.`;
8783
+ this.log({
8784
+ level: "error",
8785
+ message: `Refusing message ${message.id.slice(0, 8)} in conversation ${conv.id.slice(0, 8)}: provider namespace ${providerId ?? "(unknown)"} is not loaded; no turn was started`,
8786
+ conversation_id: conv.id,
8787
+ message_id: message.id
8788
+ });
8789
+ try {
8790
+ await this.markFailed(conv.id, message.id, sessionId, errorMessage3, void 0, {
8791
+ classification: {
8792
+ kind: "model_auth",
8793
+ providerId,
8794
+ modelId,
8795
+ reason: "missing"
8796
+ },
8797
+ errorShape: { name: null, statusCode: null }
8798
+ });
8799
+ this.signalDispatchNotStarted(conv, message, "model_provider_absent");
8800
+ } catch (markErr) {
8801
+ this.log({
8802
+ level: "warn",
8803
+ message: `markFailed PATCH for refused message ${message.id.slice(0, 8)} (conversation ${conv.id.slice(0, 8)}) failed: ${markErr instanceof Error ? markErr.message : String(markErr)}`,
8804
+ conversation_id: conv.id,
8805
+ message_id: message.id
8806
+ });
8807
+ this.signalDispatchNotStarted(conv, message, "failure_unreported");
8808
+ }
8809
+ await this.repairProviderRegistry(conv.id, message.id);
8810
+ break;
8811
+ }
8725
8812
  let opencodeMessageId;
8726
8813
  let preDispatchUserIds = null;
8727
8814
  try {
@@ -13920,22 +14007,6 @@ function mergeManagedOpenCodeConfigContent(content, managedProviders) {
13920
14007
  }
13921
14008
  return JSON.stringify({ ...config, provider: { ...provider, ...managedProviders } });
13922
14009
  }
13923
- function removeManagedOpenCodeConfigContent(content) {
13924
- if (!content?.trim()) return content;
13925
- const config = parseConfigContent(content);
13926
- if (typeof config.provider !== "object" || config.provider === null || Array.isArray(config.provider)) {
13927
- return content;
13928
- }
13929
- const provider = { ...config.provider };
13930
- let changed = false;
13931
- for (const namespace of CREDENTIAL_PROXY_NATIVE_NAMESPACES) {
13932
- if (namespace in provider) {
13933
- delete provider[namespace];
13934
- changed = true;
13935
- }
13936
- }
13937
- return changed ? JSON.stringify({ ...config, provider }) : content;
13938
- }
13939
14010
  function isFile(filePath) {
13940
14011
  return existsSync2(filePath) && statSync6(filePath).isFile();
13941
14012
  }
@@ -14397,23 +14468,23 @@ async function responseJson(response) {
14397
14468
  function readSetup(value) {
14398
14469
  if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
14399
14470
  const setup = value;
14400
- if (typeof setup.runner_id !== "string" || typeof setup.generation !== "string" || typeof setup.status !== "string" || setup.token_id !== null && typeof setup.token_id !== "string") {
14471
+ if (typeof setup.runner_id !== "string" || typeof setup.generation !== "string" || typeof setup.status !== "string" || setup.token_id !== null && typeof setup.token_id !== "string" || typeof setup.acknowledged_at !== "string" && setup.acknowledged_at !== null) {
14401
14472
  return null;
14402
14473
  }
14403
14474
  return setup;
14404
14475
  }
14405
14476
  function clearLocalSetup(options) {
14406
14477
  const env = options.env ?? process.env;
14407
- (options.store ?? defaultStore).clear(options.agentId);
14408
- delete env.EVIDENT_PROXY_TOKEN;
14409
- try {
14410
- const content = removeManagedOpenCodeConfigContent(env.OPENCODE_CONFIG_CONTENT);
14411
- if (content === void 0) delete env.OPENCODE_CONFIG_CONTENT;
14412
- else env.OPENCODE_CONFIG_CONTENT = content;
14413
- } catch (error2) {
14478
+ const store = options.store ?? defaultStore;
14479
+ const stored = store.get(options.agentId);
14480
+ store.clear(options.agentId);
14481
+ const token = env.EVIDENT_PROXY_TOKEN;
14482
+ if (token !== void 0 && token === stored?.token) {
14483
+ delete env.EVIDENT_PROXY_TOKEN;
14484
+ } else if (token !== void 0) {
14414
14485
  options.log(
14415
- "MANAGED-INFERENCE-CLEANUP-PARTIAL: stored credentials were removed, but malformed OPENCODE_CONFIG_CONTENT could not be inspected",
14416
- "warn"
14486
+ `MANAGED-INFERENCE-CLEANUP-PRESERVED-EXTERNAL-TOKEN: runner=${options.agentId}`,
14487
+ "debug"
14417
14488
  );
14418
14489
  }
14419
14490
  }
@@ -14439,6 +14510,25 @@ async function discoverManagedInferenceSetup(options) {
14439
14510
  const setup = readSetup(body?.setup);
14440
14511
  return setup ? { kind: "setup", setup } : { kind: "failed", reason: "Managed setup discovery returned an invalid response" };
14441
14512
  }
14513
+ async function enrollManagedInferenceSetup(options) {
14514
+ const response = await post(options, "enroll", {});
14515
+ if (!response) {
14516
+ return { kind: "failed", reason: safeFailure("Managed credential enrollment") };
14517
+ }
14518
+ if (response.status === 404) {
14519
+ return { kind: "none" };
14520
+ }
14521
+ const body = await responseJson(response);
14522
+ if (!response.ok) {
14523
+ const serverError = body?.error;
14524
+ return {
14525
+ kind: "failed",
14526
+ reason: typeof serverError === "string" && serverError.trim() ? redactDiagnosticText(serverError).slice(0, 500) : safeFailure("Managed credential enrollment", response.status)
14527
+ };
14528
+ }
14529
+ const setup = readSetup(body?.setup);
14530
+ return setup ? { kind: "setup", setup } : { kind: "failed", reason: "Managed credential enrollment returned an invalid response" };
14531
+ }
14442
14532
  async function post(options, operation, body) {
14443
14533
  const headers = requestHeaders(options);
14444
14534
  try {
@@ -14453,31 +14543,37 @@ async function post(options, operation, body) {
14453
14543
  }
14454
14544
  }
14455
14545
  function applyCredential(options, credential) {
14456
- const { config, unsupportedProviders } = buildCredentialProxyNativeConfig({
14457
- inferenceBaseUrl: credential.inferenceBaseUrl,
14458
- modelDescriptors: credential.modelDescriptors
14459
- });
14460
- if (unsupportedProviders.length > 0 || Object.keys(config.provider).length === 0) {
14461
- return "Managed setup contains unsupported provider descriptors";
14462
- }
14463
14546
  const env = options.env ?? process.env;
14464
14547
  let merged;
14465
- try {
14466
- merged = mergeManagedOpenCodeConfigContent(env.OPENCODE_CONFIG_CONTENT, config.provider);
14467
- } catch (error2) {
14468
- return "OPENCODE_CONFIG_CONTENT is malformed; managed providers were not installed";
14548
+ if (options.autoConfigureCredentialsProxy) {
14549
+ const { config, unsupportedProviders } = buildCredentialProxyNativeConfig({
14550
+ inferenceBaseUrl: credential.inferenceBaseUrl,
14551
+ modelDescriptors: credential.modelDescriptors
14552
+ });
14553
+ if (unsupportedProviders.length > 0 || Object.keys(config.provider).length === 0) {
14554
+ return "Managed setup contains unsupported provider descriptors";
14555
+ }
14556
+ try {
14557
+ merged = mergeManagedOpenCodeConfigContent(env.OPENCODE_CONFIG_CONTENT, config.provider);
14558
+ } catch (error2) {
14559
+ return "OPENCODE_CONFIG_CONTENT is malformed; managed providers were not installed";
14560
+ }
14469
14561
  }
14470
14562
  try {
14471
14563
  (options.store ?? defaultStore).set(options.agentId, credential);
14472
14564
  } catch (error2) {
14565
+ const detail = (error2 instanceof Error ? error2.message : String(error2)).replaceAll(
14566
+ credential.token,
14567
+ "[redacted]"
14568
+ );
14473
14569
  options.log(
14474
- `MANAGED-INFERENCE-STORE-FAILED: runner=${options.agentId} generation=${credential.generation}`,
14570
+ `MANAGED-INFERENCE-STORE-FAILED: runner=${options.agentId} generation=${credential.generation} detail=${redactDiagnosticText(detail)}`,
14475
14571
  "warn"
14476
14572
  );
14477
14573
  return "Managed credentials could not be written to the protected store";
14478
14574
  }
14479
14575
  env.EVIDENT_PROXY_TOKEN = credential.token;
14480
- env.OPENCODE_CONFIG_CONTENT = merged;
14576
+ if (merged !== void 0) env.OPENCODE_CONFIG_CONTENT = merged;
14481
14577
  return null;
14482
14578
  }
14483
14579
  async function reportManagedInferenceApplyFailure(options, failure) {
@@ -14528,7 +14624,7 @@ async function prepareManagedInferenceSetup(options, discovery, health) {
14528
14624
  }
14529
14625
  return reaffirmStored(options, stored);
14530
14626
  }
14531
- if (discovery.setup.status === "acknowledged" && stored?.generation === discovery.setup.generation && stored.tokenId === discovery.setup.token_id) {
14627
+ if (discovery.setup.acknowledged_at !== null && stored?.generation === discovery.setup.generation && stored.tokenId === discovery.setup.token_id) {
14532
14628
  return reaffirmStored(options, stored);
14533
14629
  }
14534
14630
  const response = await post(options, "bootstrap", { generation: discovery.setup.generation });
@@ -14566,7 +14662,7 @@ async function acknowledgeManagedInferenceSetup(options, preparation) {
14566
14662
  const response = await post(options, "acknowledge", {
14567
14663
  generation: preparation.generation,
14568
14664
  token_id: preparation.tokenId,
14569
- config_validated: true
14665
+ config_validated: options.autoConfigureCredentialsProxy === true
14570
14666
  });
14571
14667
  if (!response?.ok) {
14572
14668
  throw new Error(
@@ -16369,13 +16465,17 @@ async function run(options) {
16369
16465
  agentId: state.agentId,
16370
16466
  apiUrl: getApiUrlConfig(),
16371
16467
  getAuthHeader: () => state.authHeader,
16468
+ autoConfigureCredentialsProxy: options.autoConfigureCredentialsProxy,
16372
16469
  log: (message, level = "info") => logActivity(state, {
16373
16470
  type: level === "error" ? "error" : "info",
16374
16471
  level,
16375
16472
  ...level === "error" ? { error: message } : { message }
16376
16473
  })
16377
16474
  };
16378
- const managedDiscovery = await discoverManagedInferenceSetup(managedSetupOptions);
16475
+ let managedDiscovery = await discoverManagedInferenceSetup(managedSetupOptions);
16476
+ if (managedDiscovery.kind === "none") {
16477
+ managedDiscovery = await enrollManagedInferenceSetup(managedSetupOptions);
16478
+ }
16379
16479
  let managedPreparation = { kind: "none" };
16380
16480
  if (managedDiscovery.kind === "failed") {
16381
16481
  managedPreparation = managedDiscovery;
@@ -16996,6 +17096,9 @@ program.command("run").description("Connect to Evident and process messages").op
16996
17096
  ).option(
16997
17097
  "--opencode-config-overlay <path>",
16998
17098
  "Apply this runner-provided OpenCode config before starting OpenCode."
17099
+ ).option(
17100
+ "--auto-configure-credentials-proxy",
17101
+ "Install Evident's generated OpenCode providers for the runner's credential pool (off by default)."
16999
17102
  ).option(
17000
17103
  "--credential-sync-marker <path>",
17001
17104
  "Own the interval credential sync and write this marker once the shutdown flush has finished, so the runner image's lifecycle hooks can wait on it."
@@ -17039,6 +17142,7 @@ program.command("run").description("Connect to Evident and process messages").op
17039
17142
  restoreSessionDb: options.restoreSessionDb,
17040
17143
  restoreRunnerCredentials: options.restoreRunnerCredentials,
17041
17144
  opencodeConfigOverlay: options.opencodeConfigOverlay,
17145
+ autoConfigureCredentialsProxy: options.autoConfigureCredentialsProxy,
17042
17146
  credentialSyncMarker: options.credentialSyncMarker
17043
17147
  });
17044
17148
  }