@evident-ai/cli 3.6.1-dev.69de1a0 → 3.6.1-dev.6d23da1
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 +4 -0
- package/dist/index.js +138 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
1445
|
+
var CLI_VERSION = (true ? "3.6.1-dev.6d23da1" : 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,7 +14468,7 @@ 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;
|
|
@@ -14406,16 +14477,6 @@ function clearLocalSetup(options) {
|
|
|
14406
14477
|
const env = options.env ?? process.env;
|
|
14407
14478
|
(options.store ?? defaultStore).clear(options.agentId);
|
|
14408
14479
|
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) {
|
|
14414
|
-
options.log(
|
|
14415
|
-
"MANAGED-INFERENCE-CLEANUP-PARTIAL: stored credentials were removed, but malformed OPENCODE_CONFIG_CONTENT could not be inspected",
|
|
14416
|
-
"warn"
|
|
14417
|
-
);
|
|
14418
|
-
}
|
|
14419
14480
|
}
|
|
14420
14481
|
async function discoverManagedInferenceSetup(options) {
|
|
14421
14482
|
const headers = requestHeaders(options);
|
|
@@ -14439,6 +14500,25 @@ async function discoverManagedInferenceSetup(options) {
|
|
|
14439
14500
|
const setup = readSetup(body?.setup);
|
|
14440
14501
|
return setup ? { kind: "setup", setup } : { kind: "failed", reason: "Managed setup discovery returned an invalid response" };
|
|
14441
14502
|
}
|
|
14503
|
+
async function enrollManagedInferenceSetup(options) {
|
|
14504
|
+
const response = await post(options, "enroll", {});
|
|
14505
|
+
if (!response) {
|
|
14506
|
+
return { kind: "failed", reason: safeFailure("Managed credential enrollment") };
|
|
14507
|
+
}
|
|
14508
|
+
if (response.status === 404) {
|
|
14509
|
+
return { kind: "none" };
|
|
14510
|
+
}
|
|
14511
|
+
const body = await responseJson(response);
|
|
14512
|
+
if (!response.ok) {
|
|
14513
|
+
const serverError = body?.error;
|
|
14514
|
+
return {
|
|
14515
|
+
kind: "failed",
|
|
14516
|
+
reason: typeof serverError === "string" && serverError.trim() ? redactDiagnosticText(serverError).slice(0, 500) : safeFailure("Managed credential enrollment", response.status)
|
|
14517
|
+
};
|
|
14518
|
+
}
|
|
14519
|
+
const setup = readSetup(body?.setup);
|
|
14520
|
+
return setup ? { kind: "setup", setup } : { kind: "failed", reason: "Managed credential enrollment returned an invalid response" };
|
|
14521
|
+
}
|
|
14442
14522
|
async function post(options, operation, body) {
|
|
14443
14523
|
const headers = requestHeaders(options);
|
|
14444
14524
|
try {
|
|
@@ -14453,31 +14533,37 @@ async function post(options, operation, body) {
|
|
|
14453
14533
|
}
|
|
14454
14534
|
}
|
|
14455
14535
|
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
14536
|
const env = options.env ?? process.env;
|
|
14464
14537
|
let merged;
|
|
14465
|
-
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14538
|
+
if (options.autoConfigureCredentialsProxy) {
|
|
14539
|
+
const { config, unsupportedProviders } = buildCredentialProxyNativeConfig({
|
|
14540
|
+
inferenceBaseUrl: credential.inferenceBaseUrl,
|
|
14541
|
+
modelDescriptors: credential.modelDescriptors
|
|
14542
|
+
});
|
|
14543
|
+
if (unsupportedProviders.length > 0 || Object.keys(config.provider).length === 0) {
|
|
14544
|
+
return "Managed setup contains unsupported provider descriptors";
|
|
14545
|
+
}
|
|
14546
|
+
try {
|
|
14547
|
+
merged = mergeManagedOpenCodeConfigContent(env.OPENCODE_CONFIG_CONTENT, config.provider);
|
|
14548
|
+
} catch (error2) {
|
|
14549
|
+
return "OPENCODE_CONFIG_CONTENT is malformed; managed providers were not installed";
|
|
14550
|
+
}
|
|
14469
14551
|
}
|
|
14470
14552
|
try {
|
|
14471
14553
|
(options.store ?? defaultStore).set(options.agentId, credential);
|
|
14472
14554
|
} catch (error2) {
|
|
14555
|
+
const detail = (error2 instanceof Error ? error2.message : String(error2)).replaceAll(
|
|
14556
|
+
credential.token,
|
|
14557
|
+
"[redacted]"
|
|
14558
|
+
);
|
|
14473
14559
|
options.log(
|
|
14474
|
-
`MANAGED-INFERENCE-STORE-FAILED: runner=${options.agentId} generation=${credential.generation}`,
|
|
14560
|
+
`MANAGED-INFERENCE-STORE-FAILED: runner=${options.agentId} generation=${credential.generation} detail=${redactDiagnosticText(detail)}`,
|
|
14475
14561
|
"warn"
|
|
14476
14562
|
);
|
|
14477
14563
|
return "Managed credentials could not be written to the protected store";
|
|
14478
14564
|
}
|
|
14479
14565
|
env.EVIDENT_PROXY_TOKEN = credential.token;
|
|
14480
|
-
env.OPENCODE_CONFIG_CONTENT = merged;
|
|
14566
|
+
if (merged !== void 0) env.OPENCODE_CONFIG_CONTENT = merged;
|
|
14481
14567
|
return null;
|
|
14482
14568
|
}
|
|
14483
14569
|
async function reportManagedInferenceApplyFailure(options, failure) {
|
|
@@ -14528,7 +14614,7 @@ async function prepareManagedInferenceSetup(options, discovery, health) {
|
|
|
14528
14614
|
}
|
|
14529
14615
|
return reaffirmStored(options, stored);
|
|
14530
14616
|
}
|
|
14531
|
-
if (discovery.setup.
|
|
14617
|
+
if (discovery.setup.acknowledged_at !== null && stored?.generation === discovery.setup.generation && stored.tokenId === discovery.setup.token_id) {
|
|
14532
14618
|
return reaffirmStored(options, stored);
|
|
14533
14619
|
}
|
|
14534
14620
|
const response = await post(options, "bootstrap", { generation: discovery.setup.generation });
|
|
@@ -14566,7 +14652,7 @@ async function acknowledgeManagedInferenceSetup(options, preparation) {
|
|
|
14566
14652
|
const response = await post(options, "acknowledge", {
|
|
14567
14653
|
generation: preparation.generation,
|
|
14568
14654
|
token_id: preparation.tokenId,
|
|
14569
|
-
config_validated: true
|
|
14655
|
+
config_validated: options.autoConfigureCredentialsProxy === true
|
|
14570
14656
|
});
|
|
14571
14657
|
if (!response?.ok) {
|
|
14572
14658
|
throw new Error(
|
|
@@ -16369,13 +16455,17 @@ async function run(options) {
|
|
|
16369
16455
|
agentId: state.agentId,
|
|
16370
16456
|
apiUrl: getApiUrlConfig(),
|
|
16371
16457
|
getAuthHeader: () => state.authHeader,
|
|
16458
|
+
autoConfigureCredentialsProxy: options.autoConfigureCredentialsProxy,
|
|
16372
16459
|
log: (message, level = "info") => logActivity(state, {
|
|
16373
16460
|
type: level === "error" ? "error" : "info",
|
|
16374
16461
|
level,
|
|
16375
16462
|
...level === "error" ? { error: message } : { message }
|
|
16376
16463
|
})
|
|
16377
16464
|
};
|
|
16378
|
-
|
|
16465
|
+
let managedDiscovery = await discoverManagedInferenceSetup(managedSetupOptions);
|
|
16466
|
+
if (managedDiscovery.kind === "none") {
|
|
16467
|
+
managedDiscovery = await enrollManagedInferenceSetup(managedSetupOptions);
|
|
16468
|
+
}
|
|
16379
16469
|
let managedPreparation = { kind: "none" };
|
|
16380
16470
|
if (managedDiscovery.kind === "failed") {
|
|
16381
16471
|
managedPreparation = managedDiscovery;
|
|
@@ -16996,6 +17086,9 @@ program.command("run").description("Connect to Evident and process messages").op
|
|
|
16996
17086
|
).option(
|
|
16997
17087
|
"--opencode-config-overlay <path>",
|
|
16998
17088
|
"Apply this runner-provided OpenCode config before starting OpenCode."
|
|
17089
|
+
).option(
|
|
17090
|
+
"--auto-configure-credentials-proxy",
|
|
17091
|
+
"Install Evident's generated OpenCode providers for the runner's credential pool (off by default)."
|
|
16999
17092
|
).option(
|
|
17000
17093
|
"--credential-sync-marker <path>",
|
|
17001
17094
|
"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 +17132,7 @@ program.command("run").description("Connect to Evident and process messages").op
|
|
|
17039
17132
|
restoreSessionDb: options.restoreSessionDb,
|
|
17040
17133
|
restoreRunnerCredentials: options.restoreRunnerCredentials,
|
|
17041
17134
|
opencodeConfigOverlay: options.opencodeConfigOverlay,
|
|
17135
|
+
autoConfigureCredentialsProxy: options.autoConfigureCredentialsProxy,
|
|
17042
17136
|
credentialSyncMarker: options.credentialSyncMarker
|
|
17043
17137
|
});
|
|
17044
17138
|
}
|