@evident-ai/cli 3.5.1 → 3.5.2-dev.4181600

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
@@ -1063,7 +1063,7 @@ async function claudeUsage() {
1063
1063
 
1064
1064
  // src/commands/run.ts
1065
1065
  import { chmodSync as chmodSync3, existsSync as existsSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
1066
- import { homedir as homedir6 } from "node:os";
1066
+ import { homedir as homedir7 } from "node:os";
1067
1067
  import { isAbsolute as isAbsolute3, join as join11, parse, resolve as resolvePath2 } from "node:path";
1068
1068
  import chalk7 from "chalk";
1069
1069
 
@@ -1158,7 +1158,7 @@ import ora4 from "ora";
1158
1158
  import { select as select4 } from "@inquirer/prompts";
1159
1159
 
1160
1160
  // src/lib/telemetry.ts
1161
- var CLI_VERSION = (true ? "3.5.1" : void 0) ?? process.env.npm_package_version ?? "unknown";
1161
+ var CLI_VERSION = (true ? "3.5.2-dev.4181600" : void 0) ?? process.env.npm_package_version ?? "unknown";
1162
1162
  function getCliVersion() {
1163
1163
  return CLI_VERSION;
1164
1164
  }
@@ -1172,6 +1172,23 @@ var authProvider = null;
1172
1172
  function setTelemetryAuthProvider(provider) {
1173
1173
  authProvider = provider;
1174
1174
  }
1175
+ var diagnosticsReporter = null;
1176
+ function setTelemetryDiagnosticsReporter(reporter) {
1177
+ diagnosticsReporter = reporter;
1178
+ }
1179
+ function reportTelemetryDiagnostic(message) {
1180
+ if (!diagnosticsReporter) {
1181
+ console.error(message);
1182
+ return;
1183
+ }
1184
+ try {
1185
+ diagnosticsReporter(message);
1186
+ } catch (error2) {
1187
+ console.error(
1188
+ `Telemetry diagnostics reporter failed: ${error2 instanceof Error ? error2.message : String(error2)}; original diagnostic: ${message}`
1189
+ );
1190
+ }
1191
+ }
1175
1192
  var FLUSH_FAILURE_LOG_INTERVAL_MS = 6e4;
1176
1193
  var lastFlushFailureLoggedAt = 0;
1177
1194
  var suppressedFlushFailureCount = 0;
@@ -1237,7 +1254,9 @@ async function flushEvents() {
1237
1254
  signal: controller.signal
1238
1255
  });
1239
1256
  if (!response.ok) {
1240
- console.error(`Telemetry flush failed: ${response.status}`);
1257
+ reportTelemetryDiagnostic(
1258
+ `Telemetry could not send events (HTTP ${response.status}); runner and OpenCode are unaffected`
1259
+ );
1241
1260
  }
1242
1261
  } finally {
1243
1262
  clearTimeout(timeout);
@@ -1247,7 +1266,9 @@ async function flushEvents() {
1247
1266
  if (now - lastFlushFailureLoggedAt >= FLUSH_FAILURE_LOG_INTERVAL_MS) {
1248
1267
  const message = error2 instanceof Error ? error2.message : String(error2);
1249
1268
  const suffix = suppressedFlushFailureCount > 0 ? ` (${suppressedFlushFailureCount} more suppressed in the last ${FLUSH_FAILURE_LOG_INTERVAL_MS / 1e3}s)` : "";
1250
- console.error(`Telemetry flush error: ${message}${suffix}`);
1269
+ reportTelemetryDiagnostic(
1270
+ `Telemetry flush failed: ${message}; runner and OpenCode are unaffected${suffix}`
1271
+ );
1251
1272
  lastFlushFailureLoggedAt = now;
1252
1273
  suppressedFlushFailureCount = 0;
1253
1274
  } else {
@@ -1299,8 +1320,14 @@ var EventTypes = {
1299
1320
  };
1300
1321
 
1301
1322
  // src/lib/runner-activity-telemetry.ts
1302
- var FORWARDED_LEVELS = /* @__PURE__ */ new Set(["warn", "error"]);
1323
+ import { homedir as homedir2 } from "node:os";
1324
+ var FORWARDED_LEVELS_BY_SOURCE = {
1325
+ "cli.run": /* @__PURE__ */ new Set(["warn", "error"]),
1326
+ opencode: /* @__PURE__ */ new Set(["warn", "error"]),
1327
+ "cli.session-cleanup": /* @__PURE__ */ new Set(["info", "warn", "error"])
1328
+ };
1303
1329
  var SEVERITY_BY_LEVEL = {
1330
+ info: "info",
1304
1331
  warn: "warning",
1305
1332
  error: "error"
1306
1333
  };
@@ -1311,25 +1338,72 @@ function parseOpenCodeLogLine(line) {
1311
1338
  const level = levelMatch[1].toUpperCase();
1312
1339
  if (level !== "WARN" && level !== "ERROR") return null;
1313
1340
  const sessionMatch = normalisedLine.match(/(?:^|\s)sessionID=(\S+)/);
1314
- return { level: level === "WARN" ? "warn" : "error", sessionID: sessionMatch?.[1] };
1341
+ const messageMatch = normalisedLine.match(/(?:^|\s)message=(?:"((?:\\.|[^"])*)"|(\S+))/);
1342
+ const parsed = {
1343
+ level: level === "WARN" ? "warn" : "error",
1344
+ sessionID: sessionMatch?.[1]
1345
+ };
1346
+ const message = messageMatch?.[1] ?? messageMatch?.[2];
1347
+ if (message !== void 0) parsed.message = message;
1348
+ return parsed;
1315
1349
  }
1316
1350
  var MAX_LINE_BUFFER_BYTES = 16 * 1024;
1351
+ var REPEAT_SUPPRESSION_WINDOW_MS = 6e4;
1317
1352
  function createOpenCodeActivityForwarder(getContext) {
1318
1353
  let buffer = Buffer.alloc(0);
1319
- const flushLine = (line) => {
1320
- const parsed = parseOpenCodeLogLine(line);
1321
- if (!parsed) return;
1354
+ const repeatStates = /* @__PURE__ */ new Map();
1355
+ const forwardLine = (line, parsed, repeatsSuppressed = 0) => {
1356
+ const metadata = {
1357
+ ...parsed.sessionID ? { sessionID: parsed.sessionID } : {},
1358
+ ...repeatsSuppressed > 0 ? { repeats_suppressed: repeatsSuppressed } : {}
1359
+ };
1322
1360
  forwardRunnerActivity(
1323
1361
  {
1324
1362
  level: parsed.level,
1325
1363
  error: line,
1326
- metadata: parsed.sessionID ? { sessionID: parsed.sessionID } : void 0,
1364
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
1327
1365
  source: "opencode"
1328
1366
  },
1329
1367
  getContext()
1330
1368
  );
1331
1369
  };
1332
- return (chunk) => {
1370
+ const expireRepeatStates = (now, currentKey) => {
1371
+ for (const [key, state] of repeatStates) {
1372
+ if (key === currentKey || now - state.lastForwardedAt < REPEAT_SUPPRESSION_WINDOW_MS) {
1373
+ continue;
1374
+ }
1375
+ if (state.repeatsSuppressed > 0) {
1376
+ forwardLine(state.line, state.parsed, state.repeatsSuppressed);
1377
+ }
1378
+ repeatStates.delete(key);
1379
+ }
1380
+ };
1381
+ const flushLine = (line) => {
1382
+ const parsed = parseOpenCodeLogLine(line);
1383
+ if (!parsed) return;
1384
+ const now = Date.now();
1385
+ const key = parsed.message === void 0 ? void 0 : `${parsed.level}\0${parsed.message}`;
1386
+ expireRepeatStates(now, key);
1387
+ if (key === void 0) {
1388
+ forwardLine(line, parsed);
1389
+ return;
1390
+ }
1391
+ const previous = repeatStates.get(key);
1392
+ if (!previous || now - previous.lastForwardedAt >= REPEAT_SUPPRESSION_WINDOW_MS) {
1393
+ forwardLine(line, parsed, previous?.repeatsSuppressed ?? 0);
1394
+ repeatStates.set(key, {
1395
+ line,
1396
+ parsed,
1397
+ lastForwardedAt: now,
1398
+ repeatsSuppressed: 0
1399
+ });
1400
+ return;
1401
+ }
1402
+ previous.line = line;
1403
+ previous.parsed = parsed;
1404
+ previous.repeatsSuppressed++;
1405
+ };
1406
+ const forward = ((chunk) => {
1333
1407
  buffer = Buffer.concat([buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf-8")]);
1334
1408
  let newlineIndex;
1335
1409
  while ((newlineIndex = buffer.indexOf(10)) !== -1) {
@@ -1340,14 +1414,44 @@ function createOpenCodeActivityForwarder(getContext) {
1340
1414
  flushLine(buffer.toString("utf-8"));
1341
1415
  buffer = Buffer.alloc(0);
1342
1416
  }
1417
+ });
1418
+ forward.flush = () => {
1419
+ for (const state of repeatStates.values()) {
1420
+ if (state.repeatsSuppressed > 0) {
1421
+ forwardLine(state.line, state.parsed, state.repeatsSuppressed);
1422
+ }
1423
+ }
1424
+ repeatStates.clear();
1343
1425
  };
1426
+ return forward;
1344
1427
  }
1345
1428
  var MAX_MESSAGE_LENGTH = 500;
1346
1429
  var MAX_METADATA_VALUE_LENGTH = 200;
1347
1430
  var MAX_METADATA_ENTRIES = 20;
1348
1431
  var TRUNCATION_MARKER = "\u2026";
1432
+ function redactHomeDirectory(message) {
1433
+ const home = homedir2();
1434
+ if (!home || home === "/") {
1435
+ return message;
1436
+ }
1437
+ const pathSegmentCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
1438
+ let result = "";
1439
+ let searchFrom = 0;
1440
+ let homeIndex;
1441
+ while ((homeIndex = message.indexOf(home, searchFrom)) !== -1) {
1442
+ const homeEnd = homeIndex + home.length;
1443
+ const previousCharacter = message[homeIndex - 1];
1444
+ const nextCharacter = message[homeEnd];
1445
+ const atPathBoundary = home === "/" || (!previousCharacter || !pathSegmentCharacters.includes(previousCharacter)) && (!nextCharacter || !pathSegmentCharacters.includes(nextCharacter));
1446
+ result += message.slice(searchFrom, homeIndex);
1447
+ result += atPathBoundary ? "~" : home;
1448
+ searchFrom = homeEnd;
1449
+ }
1450
+ return result + message.slice(searchFrom);
1451
+ }
1349
1452
  function redact(message) {
1350
- return message.replace(/esk_[A-Za-z0-9_-]+/g, "esk_***").replace(/ct_[A-Za-z0-9_-]+/g, "ct_***").replace(/(?<![A-Za-z0-9_-])sk-ant-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g, "sk-ant-***").replace(/(?<![A-Za-z0-9_-])sk-proj-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g, "sk-proj-***").replace(/(?<![A-Za-z0-9_-])sk-[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/g, "sk-***").replace(/(?<![A-Za-z0-9_-])(gh[oprsu])_[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/g, "$1_***").replace(/(?<![A-Za-z0-9_-])github_pat_[A-Za-z0-9_]{20,}(?![A-Za-z0-9_-])/g, "github_pat_***").replace(/https?:\/\/\S+/g, "<url>");
1453
+ const redacted = message.replace(/esk_[A-Za-z0-9_-]+/g, "esk_***").replace(/ct_[A-Za-z0-9_-]+/g, "ct_***").replace(/(?<![A-Za-z0-9_-])sk-ant-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g, "sk-ant-***").replace(/(?<![A-Za-z0-9_-])sk-proj-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g, "sk-proj-***").replace(/(?<![A-Za-z0-9_-])sk-[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/g, "sk-***").replace(/(?<![A-Za-z0-9_-])(gh[oprsu])_[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/g, "$1_***").replace(/(?<![A-Za-z0-9_-])github_pat_[A-Za-z0-9_]{20,}(?![A-Za-z0-9_-])/g, "github_pat_***").replace(/https?:\/\/\S+/g, "<url>");
1454
+ return redactHomeDirectory(redacted);
1351
1455
  }
1352
1456
  function truncate(message) {
1353
1457
  if (message.length <= MAX_MESSAGE_LENGTH) return message;
@@ -1357,8 +1461,8 @@ function sanitiseMetadata(metadata) {
1357
1461
  if (!metadata) return {};
1358
1462
  const entries = Object.entries(metadata).slice(0, MAX_METADATA_ENTRIES);
1359
1463
  if (Object.keys(metadata).length > entries.length) {
1360
- console.error(
1361
- `[runner-activity-telemetry] dropped ${Object.keys(metadata).length - entries.length} metadata entries`
1464
+ reportTelemetryDiagnostic(
1465
+ `Runner activity telemetry dropped ${Object.keys(metadata).length - entries.length} metadata entries; those entries were not sent`
1362
1466
  );
1363
1467
  }
1364
1468
  const sanitised = [];
@@ -1382,8 +1486,8 @@ function admitUnderRateLimit(source, now) {
1382
1486
  }
1383
1487
  if (now - window.windowStartedAt >= RATE_LIMIT_WINDOW_MS) {
1384
1488
  if (window.windowDroppedCount > 0) {
1385
- console.error(
1386
- `[runner-activity-telemetry] rate cap reached: dropped ${window.windowDroppedCount} ${window.windowDroppedCount === 1 ? "entry" : "entries"} in the last ${RATE_LIMIT_WINDOW_MS / 1e3}s (cap ${RATE_LIMIT_MAX_EVENTS}/min) for source "${source}"`
1489
+ reportTelemetryDiagnostic(
1490
+ `Runner activity telemetry rate cap reached: dropped ${window.windowDroppedCount} ${window.windowDroppedCount === 1 ? "entry" : "entries"} in the last ${RATE_LIMIT_WINDOW_MS / 1e3}s (limit ${RATE_LIMIT_MAX_EVENTS}/min); those entries were not sent for source "${source}"`
1387
1491
  );
1388
1492
  }
1389
1493
  window.windowStartedAt = now;
@@ -1393,8 +1497,8 @@ function admitUnderRateLimit(source, now) {
1393
1497
  if (window.windowCount >= RATE_LIMIT_MAX_EVENTS) {
1394
1498
  window.windowDroppedCount++;
1395
1499
  if (window.windowDroppedCount === 1) {
1396
- console.error(
1397
- `[runner-activity-telemetry] rate cap reached (${RATE_LIMIT_MAX_EVENTS} per ${RATE_LIMIT_WINDOW_MS / 1e3}s) \u2014 dropping further entries this window for source "${source}"`
1500
+ reportTelemetryDiagnostic(
1501
+ `Runner activity telemetry rate cap reached (${RATE_LIMIT_MAX_EVENTS} entries per ${RATE_LIMIT_WINDOW_MS / 1e3}s limit; further entries were not sent for source "${source}"`
1398
1502
  );
1399
1503
  }
1400
1504
  return false;
@@ -1404,9 +1508,9 @@ function admitUnderRateLimit(source, now) {
1404
1508
  }
1405
1509
  function forwardRunnerActivity(entry, context) {
1406
1510
  try {
1407
- if (!FORWARDED_LEVELS.has(entry.level)) return;
1408
- if (!context.agentId || !context.authHeader) return;
1409
1511
  const source = entry.source ?? "cli.run";
1512
+ if (!FORWARDED_LEVELS_BY_SOURCE[source].has(entry.level)) return;
1513
+ if (!context.agentId || !context.authHeader) return;
1410
1514
  if (!admitUnderRateLimit(source, Date.now())) return;
1411
1515
  const rawMessage = entry.error ?? entry.message ?? "";
1412
1516
  const message = truncate(redact(rawMessage));
@@ -1417,8 +1521,8 @@ function forwardRunnerActivity(entry, context) {
1417
1521
  agentId: context.agentId
1418
1522
  });
1419
1523
  } catch (err) {
1420
- console.error(
1421
- `[runner-activity-telemetry] failed to forward runner activity: ${err instanceof Error ? err.message : String(err)}`
1524
+ reportTelemetryDiagnostic(
1525
+ `Runner activity telemetry failed to forward runner activity: ${err instanceof Error ? err.message : String(err)}`
1422
1526
  );
1423
1527
  }
1424
1528
  }
@@ -3214,7 +3318,7 @@ import { join as join4 } from "node:path";
3214
3318
 
3215
3319
  // src/lib/openai-usage.ts
3216
3320
  import { readFileSync as readFileSync3 } from "node:fs";
3217
- import { homedir as homedir2 } from "node:os";
3321
+ import { homedir as homedir3 } from "node:os";
3218
3322
  import { join as join3 } from "node:path";
3219
3323
  var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
3220
3324
  var OPENCODE_AUTH_SEGMENTS = [".local", "share", "opencode", "auth.json"];
@@ -3229,7 +3333,7 @@ function isLocalCredentialProblem2(err) {
3229
3333
  }
3230
3334
  function readOpenCodeChatGptCredentials() {
3231
3335
  try {
3232
- const raw = readFileSync3(join3(homedir2(), ...OPENCODE_AUTH_SEGMENTS), "utf-8");
3336
+ const raw = readFileSync3(join3(homedir3(), ...OPENCODE_AUTH_SEGMENTS), "utf-8");
3233
3337
  let parsed;
3234
3338
  try {
3235
3339
  parsed = JSON.parse(raw);
@@ -3661,7 +3765,7 @@ async function importOpenCodeV2Credentials({
3661
3765
  // src/lib/opencode/session-db-boot.ts
3662
3766
  import { spawn as spawn2 } from "node:child_process";
3663
3767
  import { mkdirSync, statSync as statSync2, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
3664
- import { homedir as homedir3 } from "node:os";
3768
+ import { homedir as homedir4 } from "node:os";
3665
3769
  import { dirname as dirname2, resolve as resolvePath } from "node:path";
3666
3770
 
3667
3771
  // src/lib/runner-synchroniser.ts
@@ -4017,14 +4121,14 @@ async function restoreSessionDb(options, configPath, env) {
4017
4121
  case 0:
4018
4122
  return;
4019
4123
  case 31:
4020
- acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir3(), env));
4124
+ acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir4(), env));
4021
4125
  options.log(
4022
4126
  "SESSION-DB-REPLICA-UNUSABLE: booting with a fresh opencode.db and replicating into the existing prefix this boot",
4023
4127
  "warn"
4024
4128
  );
4025
4129
  return;
4026
4130
  case 32:
4027
- acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir3(), env));
4131
+ acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir4(), env));
4028
4132
  discardSessionDbDebris(options);
4029
4133
  markNoReplicate(
4030
4134
  options,
@@ -4113,7 +4217,7 @@ function fileExists(path) {
4113
4217
  async function restoreAndVerifySessionDb(options) {
4114
4218
  const env = options.env ?? process.env;
4115
4219
  clearMarker(options);
4116
- acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir3(), env));
4220
+ acknowledgeSessionDbRecoveryReport(sessionDbRecoveryReportPath(homedir4(), env));
4117
4221
  const synchroniserEnv = await runSynchroniser(["env"], {
4118
4222
  timeoutMs: SESSION_DB_SYNCHRONISER_TIMEOUT_MS,
4119
4223
  env
@@ -4493,12 +4597,15 @@ function findProcessesByPattern(pgrepPattern, psPattern) {
4493
4597
  }
4494
4598
  } catch {
4495
4599
  try {
4496
- const psOutput = execSync(`ps aux | grep -E "${psPattern}" | grep -v grep`, {
4600
+ const psOutput = execSync("ps aux", {
4497
4601
  encoding: "utf-8",
4498
- stdio: ["pipe", "pipe", "pipe"]
4602
+ stdio: ["pipe", "pipe", "pipe"],
4603
+ // The whole table reaches Node; the 1 MiB default would surface a spurious failure.
4604
+ maxBuffer: 16 * 1024 * 1024
4499
4605
  }).trim();
4500
4606
  if (psOutput) {
4501
4607
  for (const line of psOutput.split("\n")) {
4608
+ if (!psPattern.test(line)) continue;
4502
4609
  const parts = line.trim().split(/\s+/);
4503
4610
  if (parts.length >= 2) {
4504
4611
  const pid = parseInt(parts[1], 10);
@@ -4507,8 +4614,9 @@ function findProcessesByPattern(pgrepPattern, psPattern) {
4507
4614
  }
4508
4615
  }
4509
4616
  } catch (err) {
4617
+ const reason = (typeof err === "object" && err !== null && "stderr" in err && typeof err.stderr === "string" ? err.stderr : "").split("\n").map((line) => line.trim()).find(Boolean) ?? (err instanceof Error ? err.message : String(err)).split("\n").map((line) => line.trim()).find(Boolean) ?? "no error detail available";
4510
4618
  console.warn(
4511
- `findOpenCodeProcesses: ps fallback failed: ${err instanceof Error ? err.message : String(err)}`
4619
+ `Could not list running processes, so an already-running OpenCode may not be detected: ${reason}`
4512
4620
  );
4513
4621
  }
4514
4622
  }
@@ -4540,7 +4648,7 @@ function findProcessesByPattern(pgrepPattern, psPattern) {
4540
4648
  return instances;
4541
4649
  }
4542
4650
  function findOpenCodeProcesses() {
4543
- return findProcessesByPattern("opencode serve|opencode-serve", "opencode (serve|--port)");
4651
+ return findProcessesByPattern("opencode serve|opencode-serve", /opencode (serve|--port)/);
4544
4652
  }
4545
4653
  async function scanPortsForOpenCode() {
4546
4654
  const instances = [];
@@ -4928,11 +5036,11 @@ function buildSessionStoreSizeWarning(input) {
4928
5036
 
4929
5037
  // src/lib/opencode/log-tail.ts
4930
5038
  import { statSync as statSync4 } from "node:fs";
4931
- import { homedir as homedir4 } from "node:os";
5039
+ import { homedir as homedir5 } from "node:os";
4932
5040
  import { join as join7 } from "node:path";
4933
5041
  import { open as open2, stat } from "node:fs/promises";
4934
5042
  var DEFAULT_POLL_INTERVAL_MS = 1e3;
4935
- function resolveOpenCodeLogPath(homeDir = homedir4(), env = process.env) {
5043
+ function resolveOpenCodeLogPath(homeDir = homedir5(), env = process.env) {
4936
5044
  const dataDir = env.XDG_DATA_HOME || join7(homeDir, ".local", "share");
4937
5045
  return join7(dataDir, "opencode", "log", "opencode.log");
4938
5046
  }
@@ -5087,7 +5195,11 @@ async function reclaimSessionDbSpace(input) {
5087
5195
  console.warn(
5088
5196
  `[reclaimSessionDbSpace] skipping VACUUM conversion of ${dbPath}: a session turn is live`
5089
5197
  );
5090
- return { ok: false, skipped: "full-vacuum-blocked" };
5198
+ return {
5199
+ ok: false,
5200
+ skipped: "full-vacuum-blocked",
5201
+ detail: "a session turn is live"
5202
+ };
5091
5203
  }
5092
5204
  const fileBytesForGuard = statSync5(dbPath).size;
5093
5205
  const skipReason = insufficientSpaceReason(dbPath, fileBytesForGuard);
@@ -5095,7 +5207,7 @@ async function reclaimSessionDbSpace(input) {
5095
5207
  console.warn(
5096
5208
  `[reclaimSessionDbSpace] skipping VACUUM conversion of ${dbPath}: ${skipReason}`
5097
5209
  );
5098
- return { ok: false, skipped: "insufficient-disk-space" };
5210
+ return { ok: false, skipped: "insufficient-disk-space", detail: skipReason };
5099
5211
  }
5100
5212
  const beforeBytes = readLogicalBytes(db);
5101
5213
  db.exec("PRAGMA auto_vacuum=INCREMENTAL");
@@ -5976,7 +6088,7 @@ function createResourceUsageCollector(homeDir) {
5976
6088
  }
5977
6089
 
5978
6090
  // src/lib/channels/driver.ts
5979
- import { homedir as homedir5 } from "node:os";
6091
+ import { homedir as homedir6 } from "node:os";
5980
6092
 
5981
6093
  // src/lib/runner-file-sync.ts
5982
6094
  import { join as join9 } from "node:path";
@@ -6859,7 +6971,7 @@ var ChannelDriver = class _ChannelDriver {
6859
6971
  this.stuckQueuedMs = config.stuckQueuedMs ?? DEFAULT_STUCK_QUEUED_MS;
6860
6972
  this.now = config.now ?? (() => Date.now());
6861
6973
  this.fileSyncDirectories = config.fileSyncDirectories ?? [];
6862
- this.homeDir = config.homeDir ?? homedir5();
6974
+ this.homeDir = config.homeDir ?? homedir6();
6863
6975
  this.maxActiveSessions = config.maxActiveSessions;
6864
6976
  this.watcherStallMs = config.watcherStallMs ?? WATCHER_STALL_MS;
6865
6977
  this.wedgeWarningIntervalMs = config.wedgeWarningIntervalMs ?? WEDGE_WARNING_INTERVAL_MS;
@@ -12267,7 +12379,13 @@ function logActivity(state, entry) {
12267
12379
  const level = entry.level ?? (entry.type === "error" ? "error" : "info");
12268
12380
  if (!meetsThreshold(state, level)) return;
12269
12381
  forwardRunnerActivity(
12270
- { level, message: entry.message, error: entry.error, metadata: entry.metadata },
12382
+ {
12383
+ level,
12384
+ message: entry.message,
12385
+ error: entry.error,
12386
+ metadata: entry.metadata,
12387
+ ...entry.source ? { source: entry.source } : {}
12388
+ },
12271
12389
  { agentId: state.agentId, authHeader: state.authHeader }
12272
12390
  );
12273
12391
  const fullEntry = {
@@ -12289,7 +12407,7 @@ function logActivity(state, entry) {
12289
12407
  }
12290
12408
  function reportSessionDbRecovery(state) {
12291
12409
  try {
12292
- const report = drainSessionDbRecoveryReport({ homeDir: homedir6(), env: process.env });
12410
+ const report = drainSessionDbRecoveryReport({ homeDir: homedir7(), env: process.env });
12293
12411
  for (const record of report.records) {
12294
12412
  const activity = buildSessionDbRecoveryActivity(record);
12295
12413
  if (!activity) throw new Error("could not map session-DB recovery record");
@@ -12368,7 +12486,7 @@ async function importOpenCodeV2CredentialsForState(state) {
12368
12486
  }
12369
12487
  const result = await importOpenCodeV2Credentials({
12370
12488
  request: client.request,
12371
- homeDir: homedir6(),
12489
+ homeDir: homedir7(),
12372
12490
  directory,
12373
12491
  guard: state.opencodeV2CredentialImportGuard,
12374
12492
  log: (message, level = "info") => logActivity(state, { type: "info", level, message })
@@ -12587,7 +12705,14 @@ function shouldWarnForReclaimSkip(reason) {
12587
12705
  return major > 22 || major === 22 && (minor > 13 || minor === 13 && patch >= 0);
12588
12706
  }
12589
12707
  function sessionDbPath() {
12590
- return join11(homedir6(), ".local", "share", "opencode", "opencode.db");
12708
+ return join11(homedir7(), ".local", "share", "opencode", "opencode.db");
12709
+ }
12710
+ function logSessionCleanupActivity(state, phase, entry) {
12711
+ logActivity(state, {
12712
+ ...entry,
12713
+ source: "cli.session-cleanup",
12714
+ metadata: { ...entry.metadata, phase }
12715
+ });
12591
12716
  }
12592
12717
  function logSessionDbProvenanceMismatch(state, provenance, currentVersion, preBootMigrationCount) {
12593
12718
  const record = {
@@ -12630,9 +12755,13 @@ async function runSweep(state, driver, config) {
12630
12755
  try {
12631
12756
  const sessions = await listSessions(state.port, state.opencodeClient ?? void 0);
12632
12757
  if (sessions === null) {
12633
- logActivity(state, {
12758
+ logSessionCleanupActivity(state, "sweep", {
12634
12759
  type: "info",
12635
- message: `Session cleanup: could not list sessions (opencode unreachable); skipping this sweep (${mode})`
12760
+ message: `Session cleanup: could not list sessions (opencode unreachable); skipping this sweep (${mode})`,
12761
+ metadata: {
12762
+ outcome: "sweep-skipped",
12763
+ reason: "opencode-unreachable"
12764
+ }
12636
12765
  });
12637
12766
  return;
12638
12767
  }
@@ -12676,21 +12805,47 @@ async function runSweep(state, driver, config) {
12676
12805
  const beforeMib = (reclaimResult.beforeBytes / 1024 / 1024).toFixed(1);
12677
12806
  const afterMib = (reclaimResult.afterBytes / 1024 / 1024).toFixed(1);
12678
12807
  const checkpointNote = reclaimResult.checkpoint.busy ? ` (on-disk file truncation deferred: checkpoint busy, ${reclaimResult.checkpoint.log} WAL frames pending)` : "";
12679
- logActivity(state, {
12808
+ logSessionCleanupActivity(state, "sweep", {
12680
12809
  type: "info",
12681
- message: `Session cleanup: reclaimed session-db space (${reclaimResult.mode}): ${beforeMib} MiB -> ${afterMib} MiB${checkpointNote}`
12810
+ message: `Session cleanup: reclaimed session-db space (${reclaimResult.mode}): ${beforeMib} MiB -> ${afterMib} MiB${checkpointNote}`,
12811
+ metadata: {
12812
+ outcome: "reclaimed",
12813
+ mode: reclaimResult.mode,
12814
+ before_bytes: reclaimResult.beforeBytes,
12815
+ after_bytes: reclaimResult.afterBytes,
12816
+ checkpoint_busy: reclaimResult.checkpoint.busy,
12817
+ wal_frames_pending: reclaimResult.checkpoint.log,
12818
+ sessions_inspected: sessions.length,
12819
+ sessions_deleted: deleted,
12820
+ sessions_failed: failed,
12821
+ sessions_skipped_active: skippedNewlyActive
12822
+ }
12682
12823
  });
12683
12824
  } else {
12684
- logActivity(state, {
12825
+ logSessionCleanupActivity(state, "sweep", {
12685
12826
  type: "info",
12686
- message: `Session cleanup: session-db space reclaim skipped (${reclaimResult.skipped})` + (reclaimResult.detail ? `: ${reclaimResult.detail}` : "")
12827
+ level: reclaimResult.skipped === "reclaim-error" || reclaimResult.skipped === "insufficient-disk-space" ? "warn" : "info",
12828
+ message: `Session cleanup: session-db space reclaim skipped (${reclaimResult.skipped})` + (reclaimResult.detail ? `: ${reclaimResult.detail}` : ""),
12829
+ metadata: {
12830
+ outcome: "reclaim-skipped",
12831
+ reason: reclaimResult.skipped,
12832
+ ...reclaimResult.detail !== void 0 ? { detail: reclaimResult.detail } : {},
12833
+ sessions_inspected: sessions.length,
12834
+ sessions_deleted: deleted,
12835
+ sessions_failed: failed,
12836
+ sessions_skipped_active: skippedNewlyActive
12837
+ }
12687
12838
  });
12688
12839
  }
12689
12840
  } catch (error2) {
12690
12841
  const message = error2 instanceof Error ? error2.message : String(error2);
12691
- logActivity(state, {
12842
+ logSessionCleanupActivity(state, "sweep", {
12692
12843
  type: "error",
12693
- error: `Session cleanup sweep failed (non-fatal, ${mode}): ${message}`
12844
+ error: `Session cleanup sweep failed (non-fatal, ${mode}): ${message}`,
12845
+ metadata: {
12846
+ outcome: "sweep-failed",
12847
+ reason: "sweep-error"
12848
+ }
12694
12849
  });
12695
12850
  }
12696
12851
  }
@@ -12706,14 +12861,19 @@ function scheduleSessionCleanup(state, driver, options) {
12706
12861
  for (const warning2 of config.warnings) {
12707
12862
  logActivity(state, { type: "info", level: "warn", message: `Session cleanup: ${warning2}` });
12708
12863
  }
12709
- const dbBytes = statSessionDbBytes(homedir6());
12864
+ const dbBytes = statSessionDbBytes(homedir7());
12710
12865
  void (async () => {
12711
12866
  const reclaimAvailability = dbBytes !== null && config.enabled ? await probeReclaimAvailability({ dbPath: sessionDbPath(), requiredBytes: dbBytes }) : null;
12712
12867
  if (reclaimAvailability !== null) {
12713
- logActivity(state, {
12868
+ logSessionCleanupActivity(state, "startup", {
12714
12869
  type: "info",
12715
12870
  level: shouldWarnForReclaimSkip(reclaimAvailability.reason) ? "warn" : "info",
12716
- message: `Session cleanup: reclaim preflight skipped (${reclaimAvailability.reason})` + (reclaimAvailability.detail ? `: ${reclaimAvailability.detail}` : "")
12871
+ message: `Session cleanup: reclaim preflight skipped (${reclaimAvailability.reason})` + (reclaimAvailability.detail ? `: ${reclaimAvailability.detail}` : ""),
12872
+ metadata: {
12873
+ outcome: "preflight-skipped",
12874
+ reason: reclaimAvailability.reason,
12875
+ ...reclaimAvailability.detail !== void 0 ? { detail: reclaimAvailability.detail } : {}
12876
+ }
12717
12877
  });
12718
12878
  }
12719
12879
  const sizeWarning = buildSessionStoreSizeWarning({
@@ -12730,9 +12890,15 @@ function scheduleSessionCleanup(state, driver, options) {
12730
12890
  );
12731
12891
  });
12732
12892
  if (!config.enabled) return;
12733
- logActivity(state, {
12893
+ logSessionCleanupActivity(state, "startup", {
12734
12894
  type: "info",
12735
- message: `Session cleanup enabled (age=${config.maxAgeMs ?? "\u2014"}, count=${config.maxCount ?? "\u2014"}, interval=${config.intervalMs}ms)`
12895
+ message: `Session cleanup enabled (age=${config.maxAgeMs ?? "\u2014"}, count=${config.maxCount ?? "\u2014"}, interval=${config.intervalMs}ms)`,
12896
+ metadata: {
12897
+ outcome: "armed",
12898
+ interval_ms: config.intervalMs,
12899
+ max_age_ms: config.maxAgeMs ?? null,
12900
+ max_count: config.maxCount ?? null
12901
+ }
12736
12902
  });
12737
12903
  const interval = setInterval(() => void runSweep(state, driver, config), config.intervalMs);
12738
12904
  const firstSweep = setTimeout(
@@ -12911,7 +13077,7 @@ function scheduleResourceUsageReporting(state, options) {
12911
13077
  });
12912
13078
  return;
12913
13079
  }
12914
- const { collect, stop } = createResourceUsageCollector(homedir6());
13080
+ const { collect, stop } = createResourceUsageCollector(homedir7());
12915
13081
  state.stopResourceUsageSampling = stop;
12916
13082
  let consecutiveFailures = 0;
12917
13083
  const tick = async () => {
@@ -13136,7 +13302,7 @@ async function run(options) {
13136
13302
  let fileSyncDirectories;
13137
13303
  try {
13138
13304
  logLevel = resolveLogLevel(options);
13139
- fileSyncDirectories = resolveFileSyncDirectories(options.enableFileSyncTo, homedir6());
13305
+ fileSyncDirectories = resolveFileSyncDirectories(options.enableFileSyncTo, homedir7());
13140
13306
  if (options.restoreSessionDb && !options.sessionDbNoReplicateMarker) {
13141
13307
  throw new Error(
13142
13308
  "--restore-session-db requires --session-db-no-replicate-marker <path>; restore failures must block Litestream replication"
@@ -13191,6 +13357,7 @@ async function run(options) {
13191
13357
  authHeader: ""
13192
13358
  };
13193
13359
  setTelemetryAuthProvider(() => ({ authHeader: state.authHeader, agentId: state.agentId }));
13360
+ setTelemetryDiagnosticsReporter((message) => log2(state, message, "warn"));
13194
13361
  if (options.credentialSyncMarker) {
13195
13362
  state.credentialSync = createCredentialSync({
13196
13363
  markerPath: options.credentialSyncMarker,
@@ -13376,13 +13543,18 @@ async function run(options) {
13376
13543
  if (githubTokenPopulated) await configureGitHubAccess(credentialContext);
13377
13544
  }
13378
13545
  state.credentialSync?.arm();
13379
- state.stopOpenCodeLogTail = tailOpenCodeLogFile(
13380
- resolveOpenCodeLogPath(homedir6(), process.env),
13381
- createOpenCodeActivityForwarder(() => ({
13382
- agentId: state.agentId,
13383
- authHeader: state.authHeader
13384
- }))
13385
- ).stop;
13546
+ const openCodeActivityForwarder = createOpenCodeActivityForwarder(() => ({
13547
+ agentId: state.agentId,
13548
+ authHeader: state.authHeader
13549
+ }));
13550
+ const openCodeLogTail = tailOpenCodeLogFile(
13551
+ resolveOpenCodeLogPath(homedir7(), process.env),
13552
+ openCodeActivityForwarder
13553
+ );
13554
+ state.stopOpenCodeLogTail = () => {
13555
+ openCodeActivityForwarder.flush();
13556
+ openCodeLogTail.stop();
13557
+ };
13386
13558
  let sessionDbVerifyFatal = false;
13387
13559
  if (!options.restoreSessionDb) {
13388
13560
  log2(state, "Skipping session-DB restore: --restore-session-db was not passed", "debug");
@@ -13499,7 +13671,7 @@ async function run(options) {
13499
13671
  const provenance = checkSessionDbProvenance({
13500
13672
  dbPath: sessionDbPath(),
13501
13673
  currentVersion: state.opencodeVersion,
13502
- homeDir: homedir6(),
13674
+ homeDir: homedir7(),
13503
13675
  env: process.env
13504
13676
  });
13505
13677
  if (provenance.anomaly) {
@@ -13669,7 +13841,7 @@ async function run(options) {
13669
13841
  // #559: the `--enable-file-sync-to` allow-list. Empty ⇒ pending files are
13670
13842
  // REJECTED with `file_sync_disabled` on the ack, not silently ignored.
13671
13843
  fileSyncDirectories,
13672
- homeDir: homedir6(),
13844
+ homeDir: homedir7(),
13673
13845
  maxActiveSessions,
13674
13846
  log: (entry) => (
13675
13847
  // Thread the driver's real level straight through so `debug`/`warn`