@evident-ai/cli 3.4.1-dev.1549524 → 3.4.1-dev.1856549

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
@@ -1524,7 +1524,7 @@ function drainSessionDbRecoveryReport({
1524
1524
  skippedLines++;
1525
1525
  return [];
1526
1526
  }
1527
- return [value];
1527
+ return [{ ...value, replication_suspended: value.replication_suspended ?? false }];
1528
1528
  } catch (error2) {
1529
1529
  skippedLines++;
1530
1530
  console.error(
@@ -1549,12 +1549,39 @@ function buildSessionDbRecoveryActivity(record) {
1549
1549
  const level = record.severity === "warning" ? "warn" : record.severity === "error" ? "error" : null;
1550
1550
  if (!level) return null;
1551
1551
  const noVerifiedPoint = record.verified_restore_point ? ` The verified restore point is ${record.verified_restore_point}.` : " No verified restore point is known.";
1552
+ const replication = record.replication_suspended ? " This start is not backing up its new session history; restart after fixing the cause." : "";
1553
+ const giveupMessage = (() => {
1554
+ switch (record.reason) {
1555
+ case "restore_deadline_exceeded":
1556
+ return "The restore did not finish before this startup deadline. Earlier sessions are unavailable for this start; collect the SESSION-DB-RESTORE-TRUNCATED boot log before retrying.";
1557
+ case "restore_tool_unusable":
1558
+ case "classification_unrecognised":
1559
+ return "The restore or classification tool produced an unsupported result. Inspect the named boot marker or log and repair the runner image or bundle before restarting.";
1560
+ case "synchroniser_config_unevaluable":
1561
+ case "synchroniser_config_incomplete":
1562
+ return "The installed hook and synchroniser bundle could not agree on configuration. Inspect the named boot marker or log and repair the runner image or bundle before restarting.";
1563
+ case "synchroniser_config_unresolved":
1564
+ return "The synchroniser configuration could not be resolved. Inspect the preceding boot error and repair the identified runner image, bundle, or local environment before restarting.";
1565
+ case "litestream_config_unavailable":
1566
+ return "The local Litestream configuration could not be generated or written. Inspect the preceding boot error and repair the runner image, bundle, local environment, or write permissions before restarting.";
1567
+ case "classification_fatal":
1568
+ return "Session history could not be restored because backup setup could not be established. Inspect the named boot marker or log and repair the identified backup configuration or permissions.";
1569
+ default:
1570
+ return null;
1571
+ }
1572
+ })();
1573
+ if (giveupMessage)
1574
+ return {
1575
+ level,
1576
+ metadata: withoutContractFields(record),
1577
+ message: `${giveupMessage}${replication}`
1578
+ };
1552
1579
  switch (record.outcome) {
1553
1580
  case "fresh_session_db":
1554
1581
  return {
1555
1582
  level,
1556
1583
  metadata: withoutContractFields(record),
1557
- message: `This runner started with a fresh session database. Earlier sessions are unavailable, and queued conversation or session references from before this start may no longer resolve.${noVerifiedPoint} Review the runner's backup configuration before relying on restored session history.`
1584
+ message: `This runner started with a fresh session database. Earlier sessions are unavailable, and queued conversation or session references from before this start may no longer resolve.${noVerifiedPoint} Review the runner's backup configuration before relying on restored session history.${replication}`
1558
1585
  };
1559
1586
  case "restore_retried":
1560
1587
  return {
@@ -1592,7 +1619,7 @@ function buildSessionDbRecoveryActivity(record) {
1592
1619
  return {
1593
1620
  level,
1594
1621
  metadata: withoutContractFields(record),
1595
- message: "This runner started with a fresh session database because it could not verify where its session history is backed up. Nothing in the backup was changed; check the runner backup configuration and permissions."
1622
+ message: `This runner started without restoring session history because it could not verify where its session history is backed up. Nothing in the backup was changed; check the runner backup configuration and permissions.${replication}`
1596
1623
  };
1597
1624
  case "session_db_boot_refused":
1598
1625
  return {
@@ -1632,7 +1659,7 @@ var STRING_OR_NULL_FIELDS = ["quarantine_destination", "verified_restore_point"]
1632
1659
  function isSessionDbRecoveryRecord(value) {
1633
1660
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1634
1661
  const record = value;
1635
- return record.v === 1 && record.event === "session_db_recovery" && typeof record.at === "string" && STAGES.has(record.stage) && OUTCOMES.has(record.outcome) && SEVERITIES.has(record.severity) && typeof record.reason === "string" && NUMBER_FIELDS.every((field) => record[field] === null || Number.isInteger(record[field])) && STRING_OR_NULL_FIELDS.every(
1662
+ return record.v === 1 && record.event === "session_db_recovery" && typeof record.at === "string" && STAGES.has(record.stage) && OUTCOMES.has(record.outcome) && SEVERITIES.has(record.severity) && typeof record.reason === "string" && (record.replication_suspended === void 0 || typeof record.replication_suspended === "boolean") && NUMBER_FIELDS.every((field) => record[field] === null || Number.isInteger(record[field])) && STRING_OR_NULL_FIELDS.every(
1636
1663
  (field) => record[field] === null || typeof record[field] === "string"
1637
1664
  );
1638
1665
  }
@@ -2208,6 +2235,7 @@ async function createOpenCodeSession(port, directory) {
2208
2235
  return data.id;
2209
2236
  }
2210
2237
  async function getModelAttachmentCapability(port, model) {
2238
+ const { model: baseModel } = splitModelVariant(model);
2211
2239
  try {
2212
2240
  const res = await timedFetch(`${opencodeBase(port)}/config/providers`);
2213
2241
  if (!res.ok) {
@@ -2224,9 +2252,9 @@ async function getModelAttachmentCapability(port, model) {
2224
2252
  );
2225
2253
  return null;
2226
2254
  }
2227
- const slash = model ? model.indexOf("/") : -1;
2228
- const providerId = slash > 0 ? model.slice(0, slash) : void 0;
2229
- let modelId = slash > 0 ? model.slice(slash + 1) : void 0;
2255
+ const slash = baseModel ? baseModel.indexOf("/") : -1;
2256
+ const providerId = slash > 0 ? baseModel.slice(0, slash) : void 0;
2257
+ let modelId = slash > 0 ? baseModel.slice(slash + 1) : void 0;
2230
2258
  const defaults2 = body?.default && typeof body.default === "object" ? body.default : void 0;
2231
2259
  let provider = providerId ? providers.find((p) => p?.id === providerId) : void 0;
2232
2260
  if (!provider && !providerId) {
@@ -2306,6 +2334,29 @@ async function buildFileParts(attachments, capable) {
2306
2334
  }
2307
2335
  return { parts, outcomes, capabilityUnknown };
2308
2336
  }
2337
+ function splitModelVariant(raw) {
2338
+ const value = raw?.trim();
2339
+ if (!value) return {};
2340
+ const hashIndex = value.indexOf("#");
2341
+ if (hashIndex === -1) return { model: value };
2342
+ const model = value.slice(0, hashIndex).trim() || void 0;
2343
+ const variant = value.slice(hashIndex + 1).trim() || void 0;
2344
+ return { model, variant };
2345
+ }
2346
+ function applyModelOptions(body, options) {
2347
+ if (options?.agent) body.agent = options.agent;
2348
+ const { model, variant } = splitModelVariant(options?.model);
2349
+ if (model) {
2350
+ const slashIndex = model.indexOf("/");
2351
+ if (slashIndex !== -1) {
2352
+ body.model = {
2353
+ providerID: model.substring(0, slashIndex),
2354
+ modelID: model.substring(slashIndex + 1)
2355
+ };
2356
+ }
2357
+ }
2358
+ if (variant) body.variant = variant;
2359
+ }
2309
2360
  function messageText(m) {
2310
2361
  if (!m || !Array.isArray(m.parts)) return "";
2311
2362
  return m.parts.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
@@ -2330,18 +2381,7 @@ async function sendPromptAsync(port, sessionId, content, options, attachments) {
2330
2381
  const body = {
2331
2382
  parts
2332
2383
  };
2333
- if (options?.agent) {
2334
- body.agent = options.agent;
2335
- }
2336
- if (options?.model) {
2337
- const slashIndex = options.model.indexOf("/");
2338
- if (slashIndex !== -1) {
2339
- body.model = {
2340
- providerID: options.model.substring(0, slashIndex),
2341
- modelID: options.model.substring(slashIndex + 1)
2342
- };
2343
- }
2344
- }
2384
+ applyModelOptions(body, options);
2345
2385
  const res = await timedFetch(`${opencodeBase(port)}/session/${sessionId}/prompt_async`, {
2346
2386
  method: "POST",
2347
2387
  headers: { "Content-Type": "application/json" },
@@ -2349,7 +2389,10 @@ async function sendPromptAsync(port, sessionId, content, options, attachments) {
2349
2389
  });
2350
2390
  if (res.status < 200 || res.status >= 300) {
2351
2391
  const text = await res.text().catch(() => "");
2352
- throw new Error(`OpenCode prompt_async failed: HTTP ${res.status}${text ? `: ${text}` : ""}`);
2392
+ const { variant } = splitModelVariant(options?.model);
2393
+ throw new Error(
2394
+ `OpenCode prompt_async failed: HTTP ${res.status}${text ? `: ${text}` : ""}${variant ? ` (variant: ${variant})` : ""}`
2395
+ );
2353
2396
  }
2354
2397
  const READ_BACK_ATTEMPTS = 5;
2355
2398
  const READ_BACK_DELAY_MS = 150;