@evident-ai/cli 3.5.2-dev.fbf25b4 → 3.5.2-dev.ffa823b
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 +5 -3
- package/dist/index.js +598 -158
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -315,14 +315,14 @@ function blank() {
|
|
|
315
315
|
console.log();
|
|
316
316
|
}
|
|
317
317
|
function waitForEnter(prompt = "Press Enter to continue...") {
|
|
318
|
-
return new Promise((
|
|
318
|
+
return new Promise((resolve5) => {
|
|
319
319
|
process.stdout.write(chalk.dim(prompt));
|
|
320
320
|
const handler = () => {
|
|
321
321
|
process.stdin.removeListener("data", handler);
|
|
322
322
|
process.stdin.setRawMode?.(false);
|
|
323
323
|
process.stdin.pause();
|
|
324
324
|
console.log();
|
|
325
|
-
|
|
325
|
+
resolve5();
|
|
326
326
|
};
|
|
327
327
|
if (process.stdin.isTTY) {
|
|
328
328
|
process.stdin.setRawMode?.(true);
|
|
@@ -332,7 +332,7 @@ function waitForEnter(prompt = "Press Enter to continue...") {
|
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
334
|
function sleep(ms) {
|
|
335
|
-
return new Promise((
|
|
335
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
// src/commands/login.ts
|
|
@@ -410,19 +410,19 @@ async function tokenLogin() {
|
|
|
410
410
|
);
|
|
411
411
|
blank();
|
|
412
412
|
process.stdout.write("Paste token: ");
|
|
413
|
-
const token = await new Promise((
|
|
413
|
+
const token = await new Promise((resolve5) => {
|
|
414
414
|
let data = "";
|
|
415
415
|
process.stdin.setEncoding("utf8");
|
|
416
416
|
process.stdin.on("data", (chunk) => {
|
|
417
417
|
data += chunk;
|
|
418
418
|
});
|
|
419
419
|
process.stdin.on("end", () => {
|
|
420
|
-
|
|
420
|
+
resolve5(data.trim());
|
|
421
421
|
});
|
|
422
422
|
if (process.stdin.isTTY) {
|
|
423
423
|
process.stdin.once("data", (chunk) => {
|
|
424
424
|
process.stdin.pause();
|
|
425
|
-
|
|
425
|
+
resolve5(chunk.toString().trim());
|
|
426
426
|
});
|
|
427
427
|
process.stdin.resume();
|
|
428
428
|
}
|
|
@@ -1158,7 +1158,7 @@ async function claudeUsage() {
|
|
|
1158
1158
|
// src/commands/run.ts
|
|
1159
1159
|
import { chmodSync as chmodSync3, existsSync as existsSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
1160
1160
|
import { homedir as homedir7 } from "node:os";
|
|
1161
|
-
import { isAbsolute as
|
|
1161
|
+
import { isAbsolute as isAbsolute4, join as join12, parse, resolve as resolvePath2 } from "node:path";
|
|
1162
1162
|
import chalk7 from "chalk";
|
|
1163
1163
|
|
|
1164
1164
|
// ../../packages/types/src/agents/index.ts
|
|
@@ -1322,7 +1322,7 @@ import ora4 from "ora";
|
|
|
1322
1322
|
import { select as select4 } from "@inquirer/prompts";
|
|
1323
1323
|
|
|
1324
1324
|
// src/lib/telemetry.ts
|
|
1325
|
-
var CLI_VERSION = (true ? "3.5.2-dev.
|
|
1325
|
+
var CLI_VERSION = (true ? "3.5.2-dev.ffa823b" : void 0) ?? process.env.npm_package_version ?? "unknown";
|
|
1326
1326
|
function getCliVersion() {
|
|
1327
1327
|
return CLI_VERSION;
|
|
1328
1328
|
}
|
|
@@ -1515,9 +1515,10 @@ function redactDiagnosticText(message) {
|
|
|
1515
1515
|
}
|
|
1516
1516
|
|
|
1517
1517
|
// src/lib/opencode/session-db-reclaim.ts
|
|
1518
|
-
var SESSION_DB_RECLAIM_CHUNK_PAGES =
|
|
1518
|
+
var SESSION_DB_RECLAIM_CHUNK_PAGES = 100;
|
|
1519
1519
|
var SESSION_DB_RECLAIM_TIME_BUDGET_MS = 500;
|
|
1520
1520
|
var SESSION_DB_RECLAIM_PAGE_CEILING = 4e4;
|
|
1521
|
+
var SESSION_DB_RECLAIM_BUSY_TIMEOUT_MS = 5e3;
|
|
1521
1522
|
function errorMessage(error2) {
|
|
1522
1523
|
if (!(error2 instanceof Error)) return String(error2);
|
|
1523
1524
|
return error2.cause instanceof Error ? error2.cause.message : error2.message;
|
|
@@ -1642,6 +1643,7 @@ function readFreelistCount(db) {
|
|
|
1642
1643
|
return db.prepare("PRAGMA freelist_count").get().freelist_count;
|
|
1643
1644
|
}
|
|
1644
1645
|
function readCheckpointResult(db) {
|
|
1646
|
+
db.exec("PRAGMA busy_timeout=0");
|
|
1645
1647
|
const row = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
1646
1648
|
return { busy: row.busy !== 0, log: row.log, checkpointed: row.checkpointed };
|
|
1647
1649
|
}
|
|
@@ -1659,7 +1661,7 @@ async function probeReclaimAvailability(input) {
|
|
|
1659
1661
|
try {
|
|
1660
1662
|
const db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
|
|
1661
1663
|
try {
|
|
1662
|
-
db.exec(
|
|
1664
|
+
db.exec(`PRAGMA busy_timeout=${SESSION_DB_RECLAIM_BUSY_TIMEOUT_MS}`);
|
|
1663
1665
|
autoVacuum = db.prepare("PRAGMA auto_vacuum").get().auto_vacuum;
|
|
1664
1666
|
} finally {
|
|
1665
1667
|
db.close();
|
|
@@ -1679,7 +1681,8 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1679
1681
|
timeBudgetMs = SESSION_DB_RECLAIM_TIME_BUDGET_MS,
|
|
1680
1682
|
chunkPages = SESSION_DB_RECLAIM_CHUNK_PAGES,
|
|
1681
1683
|
now = () => performance.now(),
|
|
1682
|
-
|
|
1684
|
+
hasLiveTurn = false,
|
|
1685
|
+
hasProvenanceAnomaly = false
|
|
1683
1686
|
} = input;
|
|
1684
1687
|
let sqlite;
|
|
1685
1688
|
try {
|
|
@@ -1695,17 +1698,19 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1695
1698
|
let db;
|
|
1696
1699
|
try {
|
|
1697
1700
|
db = new DatabaseSync(dbPath);
|
|
1698
|
-
db.exec(
|
|
1701
|
+
db.exec(`PRAGMA busy_timeout=${SESSION_DB_RECLAIM_BUSY_TIMEOUT_MS}`);
|
|
1699
1702
|
const autoVacuum = db.prepare("PRAGMA auto_vacuum").get().auto_vacuum;
|
|
1700
1703
|
if (autoVacuum === 0) {
|
|
1701
|
-
if (
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1704
|
+
if (hasLiveTurn || hasProvenanceAnomaly) {
|
|
1705
|
+
const detail = [
|
|
1706
|
+
...hasLiveTurn ? ["a session turn is live"] : [],
|
|
1707
|
+
...hasProvenanceAnomaly ? ["session-DB provenance is anomalous"] : []
|
|
1708
|
+
].join(" and ");
|
|
1709
|
+
console.warn(`[reclaimSessionDbSpace] skipping VACUUM conversion of ${dbPath}: ${detail}`);
|
|
1705
1710
|
return {
|
|
1706
1711
|
ok: false,
|
|
1707
1712
|
skipped: "full-vacuum-blocked",
|
|
1708
|
-
detail
|
|
1713
|
+
detail
|
|
1709
1714
|
};
|
|
1710
1715
|
}
|
|
1711
1716
|
const fileBytesForGuard = statSync2(dbPath).size;
|
|
@@ -1723,7 +1728,9 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1723
1728
|
db.exec("VACUUM");
|
|
1724
1729
|
const afterBytes = readLogicalBytes(db);
|
|
1725
1730
|
const freelistAfter = readFreelistCount(db);
|
|
1731
|
+
const checkpointStartedAt = now();
|
|
1726
1732
|
const checkpoint = readCheckpointResult(db);
|
|
1733
|
+
const checkpointElapsedMs = Math.max(0, now() - checkpointStartedAt);
|
|
1727
1734
|
return {
|
|
1728
1735
|
ok: true,
|
|
1729
1736
|
mode: "convert",
|
|
@@ -1734,10 +1741,18 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1734
1741
|
pagesReclaimed: Math.max(0, freelistBefore - freelistAfter),
|
|
1735
1742
|
stoppedBy: "freelist-drained",
|
|
1736
1743
|
elapsedMs: Math.max(0, now() - startedAt),
|
|
1744
|
+
checkpointElapsedMs,
|
|
1737
1745
|
checkpoint
|
|
1738
1746
|
};
|
|
1739
1747
|
}
|
|
1740
1748
|
if (autoVacuum === 2) {
|
|
1749
|
+
if (hasLiveTurn) {
|
|
1750
|
+
const detail = "a session turn is live";
|
|
1751
|
+
console.warn(
|
|
1752
|
+
`[reclaimSessionDbSpace] skipping incremental reclaim of ${dbPath}: ${detail}`
|
|
1753
|
+
);
|
|
1754
|
+
return { ok: false, skipped: "live-turn", detail };
|
|
1755
|
+
}
|
|
1741
1756
|
const beforeBytes = readLogicalBytes(db);
|
|
1742
1757
|
const freelistBefore = readFreelistCount(db);
|
|
1743
1758
|
const startedAt = now();
|
|
@@ -1762,7 +1777,9 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1762
1777
|
freelistAfter = readFreelistCount(db);
|
|
1763
1778
|
}
|
|
1764
1779
|
const afterBytes = readLogicalBytes(db);
|
|
1780
|
+
const checkpointStartedAt = now();
|
|
1765
1781
|
const checkpoint = readCheckpointResult(db);
|
|
1782
|
+
const checkpointElapsedMs = Math.max(0, now() - checkpointStartedAt);
|
|
1766
1783
|
return {
|
|
1767
1784
|
ok: true,
|
|
1768
1785
|
mode: "incremental",
|
|
@@ -1773,6 +1790,7 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1773
1790
|
pagesReclaimed: Math.max(0, freelistBefore - freelistAfter),
|
|
1774
1791
|
stoppedBy,
|
|
1775
1792
|
elapsedMs: Math.max(0, now() - startedAt),
|
|
1793
|
+
checkpointElapsedMs,
|
|
1776
1794
|
checkpoint
|
|
1777
1795
|
};
|
|
1778
1796
|
}
|
|
@@ -1792,6 +1810,263 @@ async function reclaimSessionDbSpace(input) {
|
|
|
1792
1810
|
}
|
|
1793
1811
|
}
|
|
1794
1812
|
|
|
1813
|
+
// src/lib/opencode/dependency-install-diagnostic.ts
|
|
1814
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
1815
|
+
import { basename, dirname as dirname3, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
|
|
1816
|
+
var DEPENDENCY_INSTALL_FAILURE_MESSAGE = "background dependency install failed";
|
|
1817
|
+
var MAX_DISTINCT_DIAGNOSTICS = 32;
|
|
1818
|
+
var EFFECT = "OpenCode could not install background dependencies for this scope; its plugins and tools may be unavailable";
|
|
1819
|
+
function readOpenCodeLogField(line, key) {
|
|
1820
|
+
const match = line.match(new RegExp(`(?:^|\\s)${key}=(?:"((?:\\\\.|[^"])*)"|(\\S+))`));
|
|
1821
|
+
if (!match) return void 0;
|
|
1822
|
+
if (match[1] === void 0) return match[2];
|
|
1823
|
+
return match[1].replace(/\\(["\\n])/g, (_match, escaped) => {
|
|
1824
|
+
return escaped === "n" ? "\n" : escaped;
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
function parseTrigger(line) {
|
|
1828
|
+
if (readOpenCodeLogField(line, "message") !== DEPENDENCY_INSTALL_FAILURE_MESSAGE) {
|
|
1829
|
+
return null;
|
|
1830
|
+
}
|
|
1831
|
+
const error2 = readOpenCodeLogField(line, "error");
|
|
1832
|
+
if (!error2 || !/\bEACCES\b/.test(error2)) return null;
|
|
1833
|
+
const errnoMatch = error2.match(/\bEACCES:\s*permission denied,\s*([a-z_]+)\s+'([^']*)'/);
|
|
1834
|
+
const capturedPath = errnoMatch?.[2];
|
|
1835
|
+
return {
|
|
1836
|
+
dir: readOpenCodeLogField(line, "dir"),
|
|
1837
|
+
op: errnoMatch?.[1],
|
|
1838
|
+
path: capturedPath && isAbsolute(capturedPath) ? capturedPath : void 0
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
function getErrorCode(error2) {
|
|
1842
|
+
if (typeof error2 === "object" && error2 !== null && "code" in error2) {
|
|
1843
|
+
const code = error2.code;
|
|
1844
|
+
if (typeof code === "string") return code;
|
|
1845
|
+
}
|
|
1846
|
+
return "UNKNOWN";
|
|
1847
|
+
}
|
|
1848
|
+
function isWithin(path, root) {
|
|
1849
|
+
const candidate = resolve(path);
|
|
1850
|
+
const resolvedRoot = resolve(root);
|
|
1851
|
+
return candidate === resolvedRoot || candidate.startsWith(`${resolvedRoot}${sep}`);
|
|
1852
|
+
}
|
|
1853
|
+
function rootSpecs(context) {
|
|
1854
|
+
return [
|
|
1855
|
+
{ token: "~", configured: resolve(context.homeDir) },
|
|
1856
|
+
{ token: "$WORKSPACE", configured: resolve(context.cwd) }
|
|
1857
|
+
];
|
|
1858
|
+
}
|
|
1859
|
+
function resolveRoots(context) {
|
|
1860
|
+
const resolved = [];
|
|
1861
|
+
const unresolved = [];
|
|
1862
|
+
for (const spec of rootSpecs(context)) {
|
|
1863
|
+
try {
|
|
1864
|
+
resolved.push({ ...spec, real: realpathSync(spec.configured) });
|
|
1865
|
+
} catch (_error) {
|
|
1866
|
+
unresolved.push(spec);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
return { resolved, unresolved };
|
|
1870
|
+
}
|
|
1871
|
+
function resolveNearestAncestor(failingPath, remaining, error2) {
|
|
1872
|
+
let ancestor = dirname3(failingPath);
|
|
1873
|
+
const suffix = [basename(failingPath), ...remaining];
|
|
1874
|
+
while (ancestor) {
|
|
1875
|
+
try {
|
|
1876
|
+
return {
|
|
1877
|
+
path: resolve(realpathSync(ancestor), ...suffix),
|
|
1878
|
+
failure: { path: resolve(failingPath), error: error2 }
|
|
1879
|
+
};
|
|
1880
|
+
} catch (ancestorError) {
|
|
1881
|
+
if (ancestor === dirname3(ancestor) || !getErrorCode(ancestorError).startsWith("E")) {
|
|
1882
|
+
return null;
|
|
1883
|
+
}
|
|
1884
|
+
suffix.unshift(basename(ancestor));
|
|
1885
|
+
ancestor = dirname3(ancestor);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
function resolveExistingPath(absolutePath) {
|
|
1891
|
+
if (!isAbsolute(absolutePath)) return null;
|
|
1892
|
+
const candidate = resolve(absolutePath);
|
|
1893
|
+
const remaining = [];
|
|
1894
|
+
let current = candidate;
|
|
1895
|
+
while (current) {
|
|
1896
|
+
try {
|
|
1897
|
+
const stat2 = lstatSync(current);
|
|
1898
|
+
if (stat2.isSymbolicLink()) {
|
|
1899
|
+
if (remaining.length === 0) {
|
|
1900
|
+
return { path: join2(realpathSync(dirname3(current)), basename(current)) };
|
|
1901
|
+
}
|
|
1902
|
+
return { path: resolve(realpathSync(current), ...remaining) };
|
|
1903
|
+
}
|
|
1904
|
+
return { path: resolve(realpathSync(current), ...remaining) };
|
|
1905
|
+
} catch (error2) {
|
|
1906
|
+
const code = getErrorCode(error2);
|
|
1907
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
1908
|
+
return resolveNearestAncestor(current, remaining, error2);
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
if (current === dirname3(current)) return null;
|
|
1912
|
+
remaining.unshift(basename(current));
|
|
1913
|
+
current = dirname3(current);
|
|
1914
|
+
}
|
|
1915
|
+
return null;
|
|
1916
|
+
}
|
|
1917
|
+
function tokenise(absolutePath, roots) {
|
|
1918
|
+
const pathResolution = resolveExistingPath(absolutePath);
|
|
1919
|
+
if (!pathResolution) return null;
|
|
1920
|
+
const root = roots.reduce((selected, candidate) => {
|
|
1921
|
+
if (!isWithin(pathResolution.path, candidate.real)) return selected;
|
|
1922
|
+
if (!selected || candidate.real.length > selected.real.length || candidate.real.length === selected.real.length && candidate.token === "$WORKSPACE") {
|
|
1923
|
+
return candidate;
|
|
1924
|
+
}
|
|
1925
|
+
return selected;
|
|
1926
|
+
}, null);
|
|
1927
|
+
if (!root) return null;
|
|
1928
|
+
const suffix = relative(root.real, pathResolution.path);
|
|
1929
|
+
return {
|
|
1930
|
+
value: suffix ? `${root.token}/${suffix.split(sep).join("/")}` : root.token,
|
|
1931
|
+
root,
|
|
1932
|
+
resolutionFailure: pathResolution.failure
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
function classifyScope(dir, roots) {
|
|
1936
|
+
if (!dir) return "other";
|
|
1937
|
+
const tokenisedDir = tokenise(dir, roots.resolved);
|
|
1938
|
+
if (tokenisedDir) return tokenisedDir.root.token === "$WORKSPACE" ? "workspace" : "global";
|
|
1939
|
+
for (const spec of roots.unresolved) {
|
|
1940
|
+
if (isWithin(dir, spec.configured)) {
|
|
1941
|
+
return spec.token === "$WORKSPACE" ? "workspace" : "global";
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return "other";
|
|
1945
|
+
}
|
|
1946
|
+
function unresolvedRootForPath(path, unresolved) {
|
|
1947
|
+
return unresolved.find((spec) => isWithin(path, spec.configured));
|
|
1948
|
+
}
|
|
1949
|
+
function statType(stat2) {
|
|
1950
|
+
if (stat2.isDirectory()) return "d";
|
|
1951
|
+
if (stat2.isFile()) return "f";
|
|
1952
|
+
if (stat2.isSymbolicLink()) return "l";
|
|
1953
|
+
return "o";
|
|
1954
|
+
}
|
|
1955
|
+
function renderStat(name, stat2) {
|
|
1956
|
+
const mode = (stat2.mode & 4095).toString(8).padStart(4, "0");
|
|
1957
|
+
return `${name}:${statType(stat2)}:${stat2.uid}:${stat2.gid}:${mode}`;
|
|
1958
|
+
}
|
|
1959
|
+
function renderStatError(name, error2) {
|
|
1960
|
+
const code = getErrorCode(error2);
|
|
1961
|
+
return `${name}:${renderErrorCode(code)}`;
|
|
1962
|
+
}
|
|
1963
|
+
function renderErrorCode(code) {
|
|
1964
|
+
if (code === "ENOENT") return "missing";
|
|
1965
|
+
return code.startsWith("E") ? code : `E${code}`;
|
|
1966
|
+
}
|
|
1967
|
+
function inspectChain(rootReal, rootToken, absolutePath, resolutionFailure) {
|
|
1968
|
+
const target = resolve(absolutePath);
|
|
1969
|
+
const relativePath = relative(rootReal, target);
|
|
1970
|
+
const components = relativePath ? relativePath.split(sep) : [];
|
|
1971
|
+
const entries = [];
|
|
1972
|
+
let current = rootReal;
|
|
1973
|
+
let status2 = "complete";
|
|
1974
|
+
let finalStat;
|
|
1975
|
+
for (const name of [rootToken, ...components]) {
|
|
1976
|
+
if (name !== rootToken) current = join2(current, name);
|
|
1977
|
+
if (resolutionFailure && resolve(current) === resolve(resolutionFailure.path)) {
|
|
1978
|
+
entries.push(renderStatError(name, resolutionFailure.error));
|
|
1979
|
+
status2 = "stat_failed";
|
|
1980
|
+
break;
|
|
1981
|
+
}
|
|
1982
|
+
try {
|
|
1983
|
+
const stat2 = lstatSync(current);
|
|
1984
|
+
entries.push(renderStat(name, stat2));
|
|
1985
|
+
finalStat = stat2;
|
|
1986
|
+
} catch (error2) {
|
|
1987
|
+
entries.push(renderStatError(name, error2));
|
|
1988
|
+
if (getErrorCode(error2) !== "ENOENT") status2 = "stat_failed";
|
|
1989
|
+
break;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
let symlinkTarget;
|
|
1993
|
+
let symlinkMeta;
|
|
1994
|
+
if (finalStat?.isSymbolicLink() && entries.length === components.length + 1) {
|
|
1995
|
+
try {
|
|
1996
|
+
symlinkTarget = realpathSync(current);
|
|
1997
|
+
try {
|
|
1998
|
+
symlinkMeta = renderStat("", lstatSync(symlinkTarget)).slice(1);
|
|
1999
|
+
} catch (error2) {
|
|
2000
|
+
symlinkMeta = renderErrorCode(getErrorCode(error2));
|
|
2001
|
+
status2 = "stat_failed";
|
|
2002
|
+
}
|
|
2003
|
+
} catch (error2) {
|
|
2004
|
+
symlinkTarget = "<unresolved>";
|
|
2005
|
+
symlinkMeta = renderErrorCode(getErrorCode(error2));
|
|
2006
|
+
status2 = "stat_failed";
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
return { status: status2, chain: entries.join(","), symlinkTarget, symlinkMeta };
|
|
2010
|
+
}
|
|
2011
|
+
function buildDiagnostic(line, context) {
|
|
2012
|
+
const trigger = parseTrigger(line);
|
|
2013
|
+
if (!trigger) return null;
|
|
2014
|
+
const roots = resolveRoots(context);
|
|
2015
|
+
const scope = classifyScope(trigger.dir, roots);
|
|
2016
|
+
const pathSource = trigger.path ? "error" : trigger.dir ? "dir" : "none";
|
|
2017
|
+
const inspectedPath = trigger.path ?? trigger.dir;
|
|
2018
|
+
const microvmId = context.microvmId?.trim() || "unknown";
|
|
2019
|
+
const euid = context.euid === void 0 ? "unavailable" : String(context.euid);
|
|
2020
|
+
const egid = context.egid === void 0 ? "unavailable" : String(context.egid);
|
|
2021
|
+
const op = trigger.op ?? "unknown";
|
|
2022
|
+
if (!inspectedPath) {
|
|
2023
|
+
return {
|
|
2024
|
+
event: `OPENCODE-DEPENDENCY-INSTALL-EACCES: status=no_path path_source=${pathSource} scope=${scope} microvm_id=${microvmId} op=${op} path=unknown cli_euid=${euid} cli_egid=${egid} effect="${EFFECT}" chain=unavailable`,
|
|
2025
|
+
localDetail: null
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
const tokenisedPath = tokenise(inspectedPath, roots.resolved);
|
|
2029
|
+
if (!tokenisedPath) {
|
|
2030
|
+
const unresolvedRoot = unresolvedRootForPath(inspectedPath, roots.unresolved);
|
|
2031
|
+
if (unresolvedRoot) {
|
|
2032
|
+
return {
|
|
2033
|
+
event: `OPENCODE-DEPENDENCY-INSTALL-EACCES: status=root_unresolved path_source=${pathSource} scope=${scope} microvm_id=${microvmId} op=${op} path=unknown cli_euid=${euid} cli_egid=${egid} effect="${EFFECT}" chain=unavailable`,
|
|
2034
|
+
localDetail: null
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
return {
|
|
2038
|
+
event: `OPENCODE-DEPENDENCY-INSTALL-EACCES: status=outside_roots path_source=${pathSource} scope=${scope} microvm_id=${microvmId} op=${op} path=<outside-approved-roots> cli_euid=${euid} cli_egid=${egid} effect="${EFFECT}" chain=unavailable`,
|
|
2039
|
+
localDetail: `OPENCODE-DEPENDENCY-INSTALL-EACCES (local only): outside approved roots: ${inspectedPath}`
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
const inspection = inspectChain(
|
|
2043
|
+
tokenisedPath.root.real,
|
|
2044
|
+
tokenisedPath.root.token,
|
|
2045
|
+
inspectedPath,
|
|
2046
|
+
tokenisedPath.resolutionFailure
|
|
2047
|
+
);
|
|
2048
|
+
const optionalSymlinkFields = inspection.symlinkTarget ? ` symlink_target=${tokenise(inspection.symlinkTarget, roots.resolved)?.value ?? "<outside-approved-roots>"}` + (inspection.symlinkMeta ? ` symlink_meta=${inspection.symlinkMeta}` : "") : "";
|
|
2049
|
+
return {
|
|
2050
|
+
event: `OPENCODE-DEPENDENCY-INSTALL-EACCES: status=${inspection.status} path_source=${pathSource} scope=${scope} microvm_id=${microvmId} op=${op} path=${tokenisedPath.value} cli_euid=${euid} cli_egid=${egid} effect="${EFFECT}" chain=${inspection.chain}${optionalSymlinkFields}`,
|
|
2051
|
+
localDetail: null
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
function createDependencyInstallDiagnosticReporter({
|
|
2055
|
+
context,
|
|
2056
|
+
emitEvent: emitEvent2,
|
|
2057
|
+
emitLocal
|
|
2058
|
+
}) {
|
|
2059
|
+
const emittedEvents = /* @__PURE__ */ new Set();
|
|
2060
|
+
return (line) => {
|
|
2061
|
+
const diagnostic = buildDiagnostic(line, context);
|
|
2062
|
+
if (!diagnostic || emittedEvents.has(diagnostic.event)) return;
|
|
2063
|
+
if (emittedEvents.size >= MAX_DISTINCT_DIAGNOSTICS) return;
|
|
2064
|
+
emittedEvents.add(diagnostic.event);
|
|
2065
|
+
emitEvent2(diagnostic.event);
|
|
2066
|
+
if (diagnostic.localDetail) emitLocal(diagnostic.localDetail);
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
|
|
1795
2070
|
// src/lib/runner-activity-telemetry.ts
|
|
1796
2071
|
var FORWARDED_LEVELS_BY_SOURCE = {
|
|
1797
2072
|
"cli.run": /* @__PURE__ */ new Set(["warn", "error"]),
|
|
@@ -1823,7 +2098,17 @@ function parseOpenCodeLogLine(line) {
|
|
|
1823
2098
|
}
|
|
1824
2099
|
var MAX_LINE_BUFFER_BYTES = 16 * 1024;
|
|
1825
2100
|
var REPEAT_SUPPRESSION_WINDOW_MS = 6e4;
|
|
1826
|
-
function
|
|
2101
|
+
function sanitiseDependencyInstallWarning(line) {
|
|
2102
|
+
const withoutDirectory = line.replace(
|
|
2103
|
+
/((?:^|\s)dir=)(?:"(?:\\.|[^"])*"|\/[^\s)"']+|\S+)/g,
|
|
2104
|
+
"$1<path>"
|
|
2105
|
+
);
|
|
2106
|
+
return withoutDirectory.replace(
|
|
2107
|
+
/((?:^|\s)error=)"((?:\\.|[^"])*)"/,
|
|
2108
|
+
(_match, prefix, error2) => `${prefix}"${error2.replace(/'\/[^']*'/g, "'<path>'")}"`
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
2111
|
+
function createOpenCodeActivityForwarder(getContext, onSessionStoreWriteFailure, onDependencyInstallFailure) {
|
|
1827
2112
|
let buffer = Buffer.alloc(0);
|
|
1828
2113
|
const repeatStates = /* @__PURE__ */ new Map();
|
|
1829
2114
|
const forwardLine = (line, parsed, repeatsSuppressed = 0) => {
|
|
@@ -1835,7 +2120,7 @@ function createOpenCodeActivityForwarder(getContext, onSessionStoreWriteFailure)
|
|
|
1835
2120
|
forwardRunnerActivity(
|
|
1836
2121
|
{
|
|
1837
2122
|
level: parsed.level,
|
|
1838
|
-
error: line,
|
|
2123
|
+
error: parsed.message === DEPENDENCY_INSTALL_FAILURE_MESSAGE ? sanitiseDependencyInstallWarning(line) : line,
|
|
1839
2124
|
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
1840
2125
|
source: "opencode"
|
|
1841
2126
|
},
|
|
@@ -1853,24 +2138,7 @@ function createOpenCodeActivityForwarder(getContext, onSessionStoreWriteFailure)
|
|
|
1853
2138
|
repeatStates.delete(key);
|
|
1854
2139
|
}
|
|
1855
2140
|
};
|
|
1856
|
-
const
|
|
1857
|
-
const parsed = parseOpenCodeLogLine(line);
|
|
1858
|
-
const isDiskFailure = isSessionStoreWriteFailure(line);
|
|
1859
|
-
const cause = sessionStoreCauseToken(line);
|
|
1860
|
-
if (onSessionStoreWriteFailure && (isDiskFailure || cause !== null)) {
|
|
1861
|
-
try {
|
|
1862
|
-
onSessionStoreWriteFailure({
|
|
1863
|
-
isDiskFailure,
|
|
1864
|
-
sessionId: parsed?.sessionID ?? null,
|
|
1865
|
-
cause
|
|
1866
|
-
});
|
|
1867
|
-
} catch (err) {
|
|
1868
|
-
reportTelemetryDiagnostic(
|
|
1869
|
-
`Runner activity telemetry could not record session-store write failure: ${err instanceof Error ? err.message : String(err)}`
|
|
1870
|
-
);
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
if (!parsed) return;
|
|
2141
|
+
const forwardWithRepeatSuppression = (line, parsed) => {
|
|
1874
2142
|
const now = Date.now();
|
|
1875
2143
|
const key = parsed.message === void 0 ? void 0 : `${parsed.level}\0${parsed.message}\0${parsed.sessionID ?? ""}\0${parsed.messageID ?? ""}`;
|
|
1876
2144
|
expireRepeatStates(now, key);
|
|
@@ -1893,6 +2161,35 @@ function createOpenCodeActivityForwarder(getContext, onSessionStoreWriteFailure)
|
|
|
1893
2161
|
previous.parsed = parsed;
|
|
1894
2162
|
previous.repeatsSuppressed++;
|
|
1895
2163
|
};
|
|
2164
|
+
const flushLine = (line) => {
|
|
2165
|
+
const parsed = parseOpenCodeLogLine(line);
|
|
2166
|
+
const isDiskFailure = isSessionStoreWriteFailure(line);
|
|
2167
|
+
const cause = sessionStoreCauseToken(line);
|
|
2168
|
+
if (onSessionStoreWriteFailure && (isDiskFailure || cause !== null)) {
|
|
2169
|
+
try {
|
|
2170
|
+
onSessionStoreWriteFailure({
|
|
2171
|
+
isDiskFailure,
|
|
2172
|
+
sessionId: parsed?.sessionID ?? null,
|
|
2173
|
+
cause
|
|
2174
|
+
});
|
|
2175
|
+
} catch (err) {
|
|
2176
|
+
reportTelemetryDiagnostic(
|
|
2177
|
+
`Runner activity telemetry could not record session-store write failure: ${err instanceof Error ? err.message : String(err)}`
|
|
2178
|
+
);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
if (!parsed) return;
|
|
2182
|
+
forwardWithRepeatSuppression(line, parsed);
|
|
2183
|
+
if (onDependencyInstallFailure && parsed.message === DEPENDENCY_INSTALL_FAILURE_MESSAGE) {
|
|
2184
|
+
try {
|
|
2185
|
+
onDependencyInstallFailure(line);
|
|
2186
|
+
} catch (err) {
|
|
2187
|
+
reportTelemetryDiagnostic(
|
|
2188
|
+
`Runner activity telemetry could not record dependency-install failure diagnostic: ${err instanceof Error ? err.message : String(err)}`
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
};
|
|
1896
2193
|
const forward = ((chunk) => {
|
|
1897
2194
|
buffer = Buffer.concat([buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf-8")]);
|
|
1898
2195
|
let newlineIndex;
|
|
@@ -1932,6 +2229,23 @@ function truncate(message) {
|
|
|
1932
2229
|
const remaining = MAX_MESSAGE_LENGTH - marker.length;
|
|
1933
2230
|
const headLength = Math.ceil(remaining * 0.6);
|
|
1934
2231
|
const tailLength = remaining - headLength;
|
|
2232
|
+
const effectMatch = message.startsWith("OPENCODE-DEPENDENCY-INSTALL-EACCES:") ? message.match(/ effect="[^"]*"/) : null;
|
|
2233
|
+
if (effectMatch?.index !== void 0) {
|
|
2234
|
+
const effectEnd = effectMatch.index + effectMatch[0].length;
|
|
2235
|
+
if (effectEnd > headLength && effectEnd < message.length) {
|
|
2236
|
+
const effectLength = effectMatch[0].length;
|
|
2237
|
+
const nonEffectLength = remaining - effectLength;
|
|
2238
|
+
const preservedTailLength = Math.min(
|
|
2239
|
+
message.length - effectEnd,
|
|
2240
|
+
nonEffectLength - Math.min(effectMatch.index, Math.ceil(nonEffectLength * 0.6))
|
|
2241
|
+
);
|
|
2242
|
+
const preservedHeadLength = Math.min(
|
|
2243
|
+
effectMatch.index,
|
|
2244
|
+
nonEffectLength - preservedTailLength
|
|
2245
|
+
);
|
|
2246
|
+
return message.slice(0, preservedHeadLength) + marker + message.slice(effectMatch.index, effectEnd) + message.slice(message.length - preservedTailLength);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
1935
2249
|
return message.slice(0, headLength) + marker + message.slice(message.length - tailLength);
|
|
1936
2250
|
}
|
|
1937
2251
|
function sanitiseMetadata(metadata) {
|
|
@@ -2009,10 +2323,10 @@ function forwardRunnerActivity(entry, context) {
|
|
|
2009
2323
|
|
|
2010
2324
|
// src/lib/opencode/session-db-recovery-report.ts
|
|
2011
2325
|
import { readFileSync as readFileSync2, unlinkSync } from "node:fs";
|
|
2012
|
-
import { join as
|
|
2326
|
+
import { join as join3 } from "node:path";
|
|
2013
2327
|
function sessionDbRecoveryReportPath(homeDir, env) {
|
|
2014
2328
|
const override = env.EVIDENT_SESSION_DB_RECOVERY_REPORT?.trim();
|
|
2015
|
-
return override ||
|
|
2329
|
+
return override || join3(homeDir, ".local", "state", "evident", "session-db-recovery.jsonl");
|
|
2016
2330
|
}
|
|
2017
2331
|
function drainSessionDbRecoveryReport({
|
|
2018
2332
|
homeDir,
|
|
@@ -2285,7 +2599,7 @@ async function waitForOpenCodeHealth(port, timeoutMs = 3e4) {
|
|
|
2285
2599
|
if (health.healthy || health.authFailed) {
|
|
2286
2600
|
return health;
|
|
2287
2601
|
}
|
|
2288
|
-
await new Promise((
|
|
2602
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1e3));
|
|
2289
2603
|
}
|
|
2290
2604
|
return { healthy: false, error: "Timeout waiting for OpenCode to be healthy" };
|
|
2291
2605
|
}
|
|
@@ -2296,7 +2610,7 @@ async function waitForOpenCode2Health(port, password, timeoutMs = 3e4) {
|
|
|
2296
2610
|
if (health.healthy || health.authFailed) {
|
|
2297
2611
|
return health;
|
|
2298
2612
|
}
|
|
2299
|
-
await new Promise((
|
|
2613
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1e3));
|
|
2300
2614
|
}
|
|
2301
2615
|
return { healthy: false, error: "Timeout waiting for OpenCode to be healthy" };
|
|
2302
2616
|
}
|
|
@@ -2563,7 +2877,18 @@ async function deleteSession(port, id, client) {
|
|
|
2563
2877
|
{ method: "DELETE" },
|
|
2564
2878
|
{ allowStatuses: ALL_HTTP_STATUSES }
|
|
2565
2879
|
);
|
|
2566
|
-
|
|
2880
|
+
if (res.status >= 200 && res.status < 300) {
|
|
2881
|
+
return { ok: true, status: res.status };
|
|
2882
|
+
}
|
|
2883
|
+
try {
|
|
2884
|
+
const body = await res.text();
|
|
2885
|
+
return body ? { ok: false, status: res.status, body } : { ok: false, status: res.status };
|
|
2886
|
+
} catch (error2) {
|
|
2887
|
+
console.error(
|
|
2888
|
+
`[deleteSession] DELETE /session/${id} response body read failed for HTTP ${res.status}: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
2889
|
+
);
|
|
2890
|
+
return { ok: false, status: res.status };
|
|
2891
|
+
}
|
|
2567
2892
|
} catch (error2) {
|
|
2568
2893
|
console.error(
|
|
2569
2894
|
`[deleteSession] DELETE /session/${id} failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
@@ -2875,7 +3200,7 @@ async function sendPromptAsync(port, sessionId, content, options, attachments, c
|
|
|
2875
3200
|
return dispatchedUserMessageId;
|
|
2876
3201
|
}
|
|
2877
3202
|
if (attempt < READ_BACK_ATTEMPTS - 1) {
|
|
2878
|
-
await new Promise((
|
|
3203
|
+
await new Promise((resolve5) => setTimeout(resolve5, READ_BACK_DELAY_MS));
|
|
2879
3204
|
}
|
|
2880
3205
|
}
|
|
2881
3206
|
return null;
|
|
@@ -3047,9 +3372,11 @@ function sumAssistantUsage(messages) {
|
|
|
3047
3372
|
let cacheWriteSum = 0;
|
|
3048
3373
|
let costSum = 0;
|
|
3049
3374
|
let sawCost = false;
|
|
3375
|
+
let toolCallCount = 0;
|
|
3050
3376
|
let modelId = null;
|
|
3051
3377
|
let providerId = null;
|
|
3052
3378
|
for (const m of selected) {
|
|
3379
|
+
toolCallCount += m.parts?.filter((part) => part.type === "tool").length ?? 0;
|
|
3053
3380
|
const info = m.info;
|
|
3054
3381
|
if (!info) continue;
|
|
3055
3382
|
const tokens = info.tokens;
|
|
@@ -3086,7 +3413,8 @@ function sumAssistantUsage(messages) {
|
|
|
3086
3413
|
usage_tokens_cache_write: cacheWriteSum,
|
|
3087
3414
|
// NULL means OpenCode never reported a cost; it is distinct from a genuine
|
|
3088
3415
|
// zero-cost message, which sets `sawCost` with `costSum === 0`.
|
|
3089
|
-
usage_cost_usd: sawCost ? costSum : null
|
|
3416
|
+
usage_cost_usd: sawCost ? costSum : null,
|
|
3417
|
+
turn_tool_calls: toolCallCount
|
|
3090
3418
|
};
|
|
3091
3419
|
}
|
|
3092
3420
|
function messageUsage(messages, userMessageId) {
|
|
@@ -3748,7 +4076,18 @@ async function deleteV2Session(client, sessionId) {
|
|
|
3748
4076
|
{ method: "DELETE" },
|
|
3749
4077
|
{ allowStatuses: Array.from({ length: 500 }, (_, index) => index + 100) }
|
|
3750
4078
|
);
|
|
3751
|
-
|
|
4079
|
+
if (response.status >= 200 && response.status < 300) {
|
|
4080
|
+
return { ok: true, status: response.status };
|
|
4081
|
+
}
|
|
4082
|
+
try {
|
|
4083
|
+
const body = await response.text();
|
|
4084
|
+
return body ? { ok: false, status: response.status, body } : { ok: false, status: response.status };
|
|
4085
|
+
} catch (error2) {
|
|
4086
|
+
console.error(
|
|
4087
|
+
`[deleteV2Session] DELETE /api/session/${sessionId} response body read failed for HTTP ${response.status}: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
4088
|
+
);
|
|
4089
|
+
return { ok: false, status: response.status };
|
|
4090
|
+
}
|
|
3752
4091
|
} catch (error2) {
|
|
3753
4092
|
console.error(
|
|
3754
4093
|
`[deleteV2Session] DELETE /api/session/${sessionId} failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
@@ -3924,12 +4263,12 @@ async function readV2SessionErrorStream(client, options) {
|
|
|
3924
4263
|
|
|
3925
4264
|
// src/lib/opencode/credential-import-v2.ts
|
|
3926
4265
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
3927
|
-
import { join as
|
|
4266
|
+
import { join as join5 } from "node:path";
|
|
3928
4267
|
|
|
3929
4268
|
// src/lib/openai-usage.ts
|
|
3930
4269
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
3931
4270
|
import { homedir as homedir3 } from "node:os";
|
|
3932
|
-
import { join as
|
|
4271
|
+
import { join as join4 } from "node:path";
|
|
3933
4272
|
var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
3934
4273
|
var OPENCODE_AUTH_SEGMENTS = [".local", "share", "opencode", "auth.json"];
|
|
3935
4274
|
var OpenAiUsageError = class extends Error {
|
|
@@ -3943,7 +4282,7 @@ function isLocalCredentialProblem2(err) {
|
|
|
3943
4282
|
}
|
|
3944
4283
|
function readOpenCodeChatGptCredentials() {
|
|
3945
4284
|
try {
|
|
3946
|
-
const raw = readFileSync3(
|
|
4285
|
+
const raw = readFileSync3(join4(homedir3(), ...OPENCODE_AUTH_SEGMENTS), "utf-8");
|
|
3947
4286
|
let parsed;
|
|
3948
4287
|
try {
|
|
3949
4288
|
parsed = JSON.parse(raw);
|
|
@@ -4169,13 +4508,13 @@ var INTEGRATION_LIST_RETRY_DELAY_MS = 1e3;
|
|
|
4169
4508
|
function isRecord3(value) {
|
|
4170
4509
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4171
4510
|
}
|
|
4172
|
-
var sleep2 = (milliseconds) => new Promise((
|
|
4511
|
+
var sleep2 = (milliseconds) => new Promise((resolve5) => setTimeout(resolve5, milliseconds));
|
|
4173
4512
|
function emptyResult(unsupported = [], outcome = "completed") {
|
|
4174
4513
|
return { outcome, imported: [], alreadyConnected: [], unsupported, failed: [] };
|
|
4175
4514
|
}
|
|
4176
4515
|
function readOpenCodeCredentials(homeDir, log3) {
|
|
4177
4516
|
try {
|
|
4178
|
-
const raw = readFileSync4(
|
|
4517
|
+
const raw = readFileSync4(join5(homeDir, ...OPENCODE_AUTH_SEGMENTS), "utf8");
|
|
4179
4518
|
let parsed;
|
|
4180
4519
|
try {
|
|
4181
4520
|
parsed = JSON.parse(raw);
|
|
@@ -4377,7 +4716,7 @@ async function importOpenCodeV2Credentials({
|
|
|
4377
4716
|
import { spawn as spawn2 } from "node:child_process";
|
|
4378
4717
|
import { mkdirSync, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
|
|
4379
4718
|
import { homedir as homedir4 } from "node:os";
|
|
4380
|
-
import { dirname as
|
|
4719
|
+
import { dirname as dirname4, resolve as resolvePath } from "node:path";
|
|
4381
4720
|
|
|
4382
4721
|
// src/lib/runner-synchroniser.ts
|
|
4383
4722
|
import { spawn } from "node:child_process";
|
|
@@ -4387,7 +4726,7 @@ function appendError(stderr, error2) {
|
|
|
4387
4726
|
${message}`;
|
|
4388
4727
|
}
|
|
4389
4728
|
function runSynchroniser(args, opts) {
|
|
4390
|
-
return new Promise((
|
|
4729
|
+
return new Promise((resolve5) => {
|
|
4391
4730
|
let child;
|
|
4392
4731
|
let stdout = "";
|
|
4393
4732
|
let stderr = "";
|
|
@@ -4401,7 +4740,7 @@ function runSynchroniser(args, opts) {
|
|
|
4401
4740
|
if (timer.handle) clearTimeout(timer.handle);
|
|
4402
4741
|
if (abortListener) opts.signal?.removeEventListener("abort", abortListener);
|
|
4403
4742
|
if (spawnListener) child.removeListener("spawn", spawnListener);
|
|
4404
|
-
|
|
4743
|
+
resolve5(result);
|
|
4405
4744
|
};
|
|
4406
4745
|
try {
|
|
4407
4746
|
child = spawn("runner-synchroniser", args, {
|
|
@@ -4505,7 +4844,7 @@ function clearMarker(options) {
|
|
|
4505
4844
|
function markNoReplicate(options, message) {
|
|
4506
4845
|
if (options.noReplicateMarker) {
|
|
4507
4846
|
try {
|
|
4508
|
-
mkdirSync(
|
|
4847
|
+
mkdirSync(dirname4(options.noReplicateMarker), { recursive: true });
|
|
4509
4848
|
writeFileSync(options.noReplicateMarker, "");
|
|
4510
4849
|
} catch (error2) {
|
|
4511
4850
|
options.log(
|
|
@@ -4564,7 +4903,7 @@ function parseSynchroniserEnv(stdout) {
|
|
|
4564
4903
|
return values;
|
|
4565
4904
|
}
|
|
4566
4905
|
function runCommand(command, args, options) {
|
|
4567
|
-
return new Promise((
|
|
4906
|
+
return new Promise((resolve5) => {
|
|
4568
4907
|
let child;
|
|
4569
4908
|
let stdout = "";
|
|
4570
4909
|
let stderr = "";
|
|
@@ -4573,7 +4912,7 @@ function runCommand(command, args, options) {
|
|
|
4573
4912
|
if (settled) return;
|
|
4574
4913
|
settled = true;
|
|
4575
4914
|
if (timer) clearTimeout(timer);
|
|
4576
|
-
|
|
4915
|
+
resolve5(result);
|
|
4577
4916
|
};
|
|
4578
4917
|
try {
|
|
4579
4918
|
child = spawn2(command, args, {
|
|
@@ -4581,7 +4920,7 @@ function runCommand(command, args, options) {
|
|
|
4581
4920
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4582
4921
|
});
|
|
4583
4922
|
} catch (error2) {
|
|
4584
|
-
|
|
4923
|
+
resolve5({
|
|
4585
4924
|
code: null,
|
|
4586
4925
|
stdout,
|
|
4587
4926
|
stderr: error2 instanceof Error ? error2.message : String(error2),
|
|
@@ -4660,7 +4999,7 @@ async function ensureLitestreamConfig(options, env) {
|
|
|
4660
4999
|
return null;
|
|
4661
5000
|
}
|
|
4662
5001
|
try {
|
|
4663
|
-
mkdirSync(
|
|
5002
|
+
mkdirSync(dirname4(configPath), { recursive: true });
|
|
4664
5003
|
writeFileSync(configPath, rendered.stdout);
|
|
4665
5004
|
} catch (error2) {
|
|
4666
5005
|
options.log(
|
|
@@ -4927,7 +5266,7 @@ async function restoreAndVerifySessionDb(options) {
|
|
|
4927
5266
|
// src/lib/opencode/session-db-provenance.ts
|
|
4928
5267
|
import { createRequire } from "node:module";
|
|
4929
5268
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4930
|
-
import { dirname as
|
|
5269
|
+
import { dirname as dirname5, join as join6 } from "node:path";
|
|
4931
5270
|
var require2 = createRequire(import.meta.url);
|
|
4932
5271
|
function readSessionDbMigrationIds(dbPath) {
|
|
4933
5272
|
let db;
|
|
@@ -4964,7 +5303,7 @@ function readSessionDbMigrationIds(dbPath) {
|
|
|
4964
5303
|
}
|
|
4965
5304
|
function sessionDbProvenanceStatePath(homeDir, env) {
|
|
4966
5305
|
const override = env.EVIDENT_SESSION_DB_PROVENANCE_STATE?.trim();
|
|
4967
|
-
return override ||
|
|
5306
|
+
return override || join6(homeDir, ".local", "state", "evident", "session-db-provenance.json");
|
|
4968
5307
|
}
|
|
4969
5308
|
function loadSessionDbProvenanceState(path) {
|
|
4970
5309
|
let value;
|
|
@@ -4993,7 +5332,7 @@ function loadSessionDbProvenanceState(path) {
|
|
|
4993
5332
|
}
|
|
4994
5333
|
function saveSessionDbProvenanceState(path, state) {
|
|
4995
5334
|
try {
|
|
4996
|
-
mkdirSync2(
|
|
5335
|
+
mkdirSync2(dirname5(path), { recursive: true });
|
|
4997
5336
|
writeFileSync2(path, `${JSON.stringify(state, null, 2)}
|
|
4998
5337
|
`, "utf8");
|
|
4999
5338
|
} catch (error2) {
|
|
@@ -5084,7 +5423,7 @@ async function stopProcessAndWait(child, timeoutMs, sendTerm, sendKill) {
|
|
|
5084
5423
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
5085
5424
|
return { outcome: "exited", code: child.exitCode, signal: child.signalCode };
|
|
5086
5425
|
}
|
|
5087
|
-
return new Promise((
|
|
5426
|
+
return new Promise((resolve5, reject) => {
|
|
5088
5427
|
let forced = false;
|
|
5089
5428
|
let settled = false;
|
|
5090
5429
|
const timer = setTimeout(() => {
|
|
@@ -5104,7 +5443,7 @@ async function stopProcessAndWait(child, timeoutMs, sendTerm, sendKill) {
|
|
|
5104
5443
|
settled = true;
|
|
5105
5444
|
clearTimeout(timer);
|
|
5106
5445
|
child.removeListener("exit", onExit);
|
|
5107
|
-
|
|
5446
|
+
resolve5(result);
|
|
5108
5447
|
};
|
|
5109
5448
|
const fail = (error2) => {
|
|
5110
5449
|
if (settled) return;
|
|
@@ -5580,7 +5919,7 @@ function selectSessionsToDelete(sessions, opts) {
|
|
|
5580
5919
|
);
|
|
5581
5920
|
}
|
|
5582
5921
|
var DEFAULT_INTERVAL = "1h";
|
|
5583
|
-
function
|
|
5922
|
+
function resolve2(flag, envValue, fallback) {
|
|
5584
5923
|
return flag ?? envValue ?? fallback;
|
|
5585
5924
|
}
|
|
5586
5925
|
function parseMaxCount(input) {
|
|
@@ -5596,9 +5935,9 @@ function parseMaxCount(input) {
|
|
|
5596
5935
|
}
|
|
5597
5936
|
function resolveSessionCleanupConfig(flags, env = process.env) {
|
|
5598
5937
|
const warnings = [];
|
|
5599
|
-
const maxAgeRaw =
|
|
5600
|
-
const maxCountRaw =
|
|
5601
|
-
const intervalRaw =
|
|
5938
|
+
const maxAgeRaw = resolve2(flags.maxAge, env.EVIDENT_SESSION_CLEANUP_MAX_AGE);
|
|
5939
|
+
const maxCountRaw = resolve2(flags.maxCount, env.EVIDENT_SESSION_CLEANUP_MAX_COUNT);
|
|
5940
|
+
const intervalRaw = resolve2(
|
|
5602
5941
|
flags.interval,
|
|
5603
5942
|
env.EVIDENT_SESSION_CLEANUP_INTERVAL,
|
|
5604
5943
|
DEFAULT_INTERVAL
|
|
@@ -5638,10 +5977,10 @@ function resolveSessionCleanupConfig(flags, env = process.env) {
|
|
|
5638
5977
|
|
|
5639
5978
|
// src/lib/opencode/session-db-size.ts
|
|
5640
5979
|
import { statSync as statSync4 } from "node:fs";
|
|
5641
|
-
import { join as
|
|
5980
|
+
import { join as join7 } from "node:path";
|
|
5642
5981
|
var LARGE_DB_THRESHOLD_BYTES = 268435456;
|
|
5643
5982
|
function statSessionDbBytes(homeDir) {
|
|
5644
|
-
const dbPath =
|
|
5983
|
+
const dbPath = join7(homeDir, ".local", "share", "opencode", "opencode.db");
|
|
5645
5984
|
try {
|
|
5646
5985
|
return statSync4(dbPath).size;
|
|
5647
5986
|
} catch (err) {
|
|
@@ -5671,12 +6010,12 @@ function buildSessionStoreSizeWarning(input) {
|
|
|
5671
6010
|
// src/lib/opencode/log-tail.ts
|
|
5672
6011
|
import { statSync as statSync5 } from "node:fs";
|
|
5673
6012
|
import { homedir as homedir5 } from "node:os";
|
|
5674
|
-
import { join as
|
|
6013
|
+
import { join as join8 } from "node:path";
|
|
5675
6014
|
import { open as open2, stat } from "node:fs/promises";
|
|
5676
6015
|
var DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
5677
6016
|
function resolveOpenCodeLogPath(homeDir = homedir5(), env = process.env) {
|
|
5678
|
-
const dataDir = env.XDG_DATA_HOME ||
|
|
5679
|
-
return
|
|
6017
|
+
const dataDir = env.XDG_DATA_HOME || join8(homeDir, ".local", "share");
|
|
6018
|
+
return join8(dataDir, "opencode", "log", "opencode.log");
|
|
5680
6019
|
}
|
|
5681
6020
|
function isEnoent(error2) {
|
|
5682
6021
|
return error2?.code === "ENOENT";
|
|
@@ -5831,8 +6170,8 @@ var StreamForwarder = class {
|
|
|
5831
6170
|
pauseStream(sid, stream) {
|
|
5832
6171
|
if (!stream.paused) {
|
|
5833
6172
|
stream.paused = true;
|
|
5834
|
-
stream.pausePromise = new Promise((
|
|
5835
|
-
stream.resume =
|
|
6173
|
+
stream.pausePromise = new Promise((resolve5) => {
|
|
6174
|
+
stream.resume = resolve5;
|
|
5836
6175
|
});
|
|
5837
6176
|
}
|
|
5838
6177
|
if (stream.pauseTimer !== null) clearTimeout(stream.pauseTimer);
|
|
@@ -5899,12 +6238,12 @@ var StreamForwarder = class {
|
|
|
5899
6238
|
let endBody;
|
|
5900
6239
|
if (has_body) {
|
|
5901
6240
|
const chunks = [];
|
|
5902
|
-
bodyPromise = new Promise((
|
|
6241
|
+
bodyPromise = new Promise((resolve5) => {
|
|
5903
6242
|
pushBody = (buf) => {
|
|
5904
6243
|
chunks.push(buf);
|
|
5905
6244
|
};
|
|
5906
6245
|
endBody = () => {
|
|
5907
|
-
|
|
6246
|
+
resolve5(Buffer.concat(chunks));
|
|
5908
6247
|
};
|
|
5909
6248
|
});
|
|
5910
6249
|
}
|
|
@@ -6075,7 +6414,7 @@ function connectTunnel(options) {
|
|
|
6075
6414
|
} = options;
|
|
6076
6415
|
const tunnelUrl = getTunnelUrlConfig();
|
|
6077
6416
|
const url = `${tunnelUrl}/tunnel/${agentId}/connect`;
|
|
6078
|
-
return new Promise((
|
|
6417
|
+
return new Promise((resolve5, reject) => {
|
|
6079
6418
|
const ws = new WebSocket2(url, {
|
|
6080
6419
|
headers: {
|
|
6081
6420
|
Authorization: authHeader,
|
|
@@ -6184,7 +6523,7 @@ function connectTunnel(options) {
|
|
|
6184
6523
|
forwarder.setBinaryFramesSupported(message.binary_frames === true);
|
|
6185
6524
|
const connectedAgentId = message.agent_id ?? agentId;
|
|
6186
6525
|
onConnected?.(connectedAgentId);
|
|
6187
|
-
|
|
6526
|
+
resolve5({
|
|
6188
6527
|
ws,
|
|
6189
6528
|
close: () => ws.close(1e3, "CLI shutdown")
|
|
6190
6529
|
});
|
|
@@ -6739,12 +7078,12 @@ function createSessionStoreHealth(options = {}) {
|
|
|
6739
7078
|
import { homedir as homedir6 } from "node:os";
|
|
6740
7079
|
|
|
6741
7080
|
// src/lib/runner-file-sync.ts
|
|
6742
|
-
import { join as
|
|
7081
|
+
import { join as join10 } from "node:path";
|
|
6743
7082
|
|
|
6744
7083
|
// src/lib/file-push.ts
|
|
6745
7084
|
import { randomUUID } from "node:crypto";
|
|
6746
7085
|
import { chmod, mkdir, open as open3, realpath, rename, unlink } from "node:fs/promises";
|
|
6747
|
-
import { basename, dirname as
|
|
7086
|
+
import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute2, join as join9, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
6748
7087
|
var FILE_MODE = 384;
|
|
6749
7088
|
var DIRECTORY_MODE = 448;
|
|
6750
7089
|
async function writePushedFile(request2) {
|
|
@@ -6775,9 +7114,9 @@ async function writePushedFile(request2) {
|
|
|
6775
7114
|
}
|
|
6776
7115
|
try {
|
|
6777
7116
|
const { existingAncestor, missingSegments } = await resolveNearestExistingAncestor(
|
|
6778
|
-
|
|
7117
|
+
dirname6(candidate)
|
|
6779
7118
|
);
|
|
6780
|
-
const realTarget =
|
|
7119
|
+
const realTarget = join9(existingAncestor, ...missingSegments, basename2(candidate));
|
|
6781
7120
|
const allowedDirectory = await findContainingAllowedDirectory(allowedDirectories, realTarget);
|
|
6782
7121
|
if (allowedDirectory === null) {
|
|
6783
7122
|
return refuse("path_not_allowed", "The runner does not allow writing to that location.", {
|
|
@@ -6787,8 +7126,8 @@ async function writePushedFile(request2) {
|
|
|
6787
7126
|
}
|
|
6788
7127
|
if (missingSegments.length > 0) {
|
|
6789
7128
|
await createMissingDirectories(existingAncestor, missingSegments);
|
|
6790
|
-
const realParent = await realpath(
|
|
6791
|
-
if (realParent !==
|
|
7129
|
+
const realParent = await realpath(dirname6(realTarget));
|
|
7130
|
+
if (realParent !== dirname6(realTarget) || !contains(allowedDirectory, realTarget)) {
|
|
6792
7131
|
return refuse("path_not_allowed", "The runner does not allow writing to that location.", {
|
|
6793
7132
|
path: realTarget,
|
|
6794
7133
|
bytes,
|
|
@@ -6813,15 +7152,15 @@ function expandAndValidate(requestedPath, homeDir) {
|
|
|
6813
7152
|
if (requestedPath.trim() === "" || requestedPath.includes("\0")) {
|
|
6814
7153
|
return null;
|
|
6815
7154
|
}
|
|
6816
|
-
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ?
|
|
7155
|
+
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ? join9(homeDir, requestedPath.slice(2)) : requestedPath;
|
|
6817
7156
|
if (expanded.split(/[/\\]/).includes("..")) {
|
|
6818
7157
|
return null;
|
|
6819
7158
|
}
|
|
6820
|
-
if (!
|
|
7159
|
+
if (!isAbsolute2(expanded)) {
|
|
6821
7160
|
return null;
|
|
6822
7161
|
}
|
|
6823
|
-
const candidate =
|
|
6824
|
-
const name =
|
|
7162
|
+
const candidate = resolve3(expanded);
|
|
7163
|
+
const name = basename2(candidate);
|
|
6825
7164
|
return name === "" || name === "." || name === ".." ? null : candidate;
|
|
6826
7165
|
}
|
|
6827
7166
|
async function resolveNearestExistingAncestor(directory) {
|
|
@@ -6831,18 +7170,18 @@ async function resolveNearestExistingAncestor(directory) {
|
|
|
6831
7170
|
try {
|
|
6832
7171
|
return { existingAncestor: await realpath(current), missingSegments };
|
|
6833
7172
|
} catch (err) {
|
|
6834
|
-
const parent =
|
|
7173
|
+
const parent = dirname6(current);
|
|
6835
7174
|
if (err.code !== "ENOENT" || parent === current) {
|
|
6836
7175
|
throw err;
|
|
6837
7176
|
}
|
|
6838
|
-
missingSegments.unshift(
|
|
7177
|
+
missingSegments.unshift(basename2(current));
|
|
6839
7178
|
current = parent;
|
|
6840
7179
|
}
|
|
6841
7180
|
}
|
|
6842
7181
|
}
|
|
6843
7182
|
async function findContainingAllowedDirectory(allowedDirectories, realTarget) {
|
|
6844
7183
|
for (const directory of allowedDirectories) {
|
|
6845
|
-
if (!
|
|
7184
|
+
if (!isAbsolute2(directory)) {
|
|
6846
7185
|
log("warn", "file_push_allowed_directory_skipped", { directory, reason: "not_absolute" });
|
|
6847
7186
|
continue;
|
|
6848
7187
|
}
|
|
@@ -6880,19 +7219,19 @@ async function realpathCreatingIfMissing(directory) {
|
|
|
6880
7219
|
}
|
|
6881
7220
|
}
|
|
6882
7221
|
function contains(realDirectory, realTarget) {
|
|
6883
|
-
const rel =
|
|
6884
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
7222
|
+
const rel = relative2(realDirectory, realTarget);
|
|
7223
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute2(rel);
|
|
6885
7224
|
}
|
|
6886
7225
|
async function createMissingDirectories(existingAncestor, missingSegments) {
|
|
6887
7226
|
let current = existingAncestor;
|
|
6888
7227
|
for (const segment of missingSegments) {
|
|
6889
|
-
current =
|
|
7228
|
+
current = join9(current, segment);
|
|
6890
7229
|
await mkdir(current, { recursive: true, mode: DIRECTORY_MODE });
|
|
6891
7230
|
await chmod(current, DIRECTORY_MODE);
|
|
6892
7231
|
}
|
|
6893
7232
|
}
|
|
6894
7233
|
async function writeAtomically(realTarget, content) {
|
|
6895
|
-
const temporaryPath =
|
|
7234
|
+
const temporaryPath = join9(dirname6(realTarget), `.evident-push-${randomUUID()}.tmp`);
|
|
6896
7235
|
let handle;
|
|
6897
7236
|
try {
|
|
6898
7237
|
handle = await open3(temporaryPath, "wx", FILE_MODE);
|
|
@@ -7022,12 +7361,12 @@ var NOT_APPLIED = {
|
|
|
7022
7361
|
opencodeAuthApplied: false
|
|
7023
7362
|
};
|
|
7024
7363
|
function isClaudeCredentialPath(requestedPath, homeDir) {
|
|
7025
|
-
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ?
|
|
7026
|
-
return expanded ===
|
|
7364
|
+
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ? join10(homeDir, requestedPath.slice(2)) : requestedPath;
|
|
7365
|
+
return expanded === join10(homeDir, ...CLAUDE_CREDENTIALS_SEGMENTS);
|
|
7027
7366
|
}
|
|
7028
7367
|
function isOpenCodeAuthPath(requestedPath, homeDir) {
|
|
7029
|
-
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ?
|
|
7030
|
-
return expanded ===
|
|
7368
|
+
const expanded = requestedPath === "~" ? homeDir : requestedPath.startsWith("~/") ? join10(homeDir, requestedPath.slice(2)) : requestedPath;
|
|
7369
|
+
return expanded === join10(homeDir, ...OPENCODE_AUTH_SEGMENTS);
|
|
7031
7370
|
}
|
|
7032
7371
|
async function applyOne(options, file) {
|
|
7033
7372
|
const label = `${file.id.slice(0, 8)} (${file.path})`;
|
|
@@ -7171,6 +7510,11 @@ function messageIdOf(m) {
|
|
|
7171
7510
|
const infoId = m.info?.id;
|
|
7172
7511
|
return typeof infoId === "string" ? infoId : void 0;
|
|
7173
7512
|
}
|
|
7513
|
+
function composeAbandonmentNote(finish, replyShape, outcome) {
|
|
7514
|
+
const base = `OpenCode ended this turn after a tool call (finish="${finish ?? "(unknown)"}") ` + (outcome === "without-answer" ? "without writing an answer, and confirmed it is no longer working on this conversation. Evident is reporting the run as failed so the failure and its reason are visible in failed runs." : "after writing only part of an answer, and confirmed it is no longer working on this conversation. Evident delivered what was written and is reporting the run as finished.");
|
|
7515
|
+
if (replyShape === null) return base;
|
|
7516
|
+
return `${base} ${replyShape.lastToolName === null ? "No tool call was recorded" : `The last tool call was "${replyShape.lastToolName}" with status "${replyShape.lastToolStatus ?? "(unknown)"}"`}; the reply's final part types were [${replyShape.partTypes.join(", ")}]${replyShape.droppedPartCount > 0 ? ` (${replyShape.droppedPartCount} earlier part types omitted)` : ""}.`;
|
|
7517
|
+
}
|
|
7174
7518
|
function cleanImageMime(contentType) {
|
|
7175
7519
|
if (!contentType) return null;
|
|
7176
7520
|
const media = contentType.split(";")[0].trim().toLowerCase();
|
|
@@ -9905,17 +10249,28 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9905
10249
|
}
|
|
9906
10250
|
} else {
|
|
9907
10251
|
if (inFlight.b2AbandonedSignalled) {
|
|
10252
|
+
const reply = findLastAssistantReplyFor(messages, inFlight.opencodeMessageId);
|
|
10253
|
+
const finish = reply?.info?.finish ?? reply?.finish;
|
|
9908
10254
|
if (inFlight.b2AbandonedWithoutAnswer) {
|
|
9909
|
-
const reply = findLastAssistantReplyFor(messages, inFlight.opencodeMessageId);
|
|
9910
10255
|
await this.settleMessageAbandonedWithoutAnswer(
|
|
9911
10256
|
sessionId,
|
|
9912
10257
|
watcher,
|
|
9913
10258
|
inFlight,
|
|
9914
10259
|
messages,
|
|
9915
|
-
|
|
10260
|
+
finish
|
|
9916
10261
|
);
|
|
9917
10262
|
} else {
|
|
9918
|
-
await this.settleMessageDone(
|
|
10263
|
+
await this.settleMessageDone(
|
|
10264
|
+
sessionId,
|
|
10265
|
+
watcher,
|
|
10266
|
+
inFlight,
|
|
10267
|
+
messages,
|
|
10268
|
+
composeAbandonmentNote(
|
|
10269
|
+
finish,
|
|
10270
|
+
describeAbandonedReplyShape(messages, inFlight.opencodeMessageId),
|
|
10271
|
+
"with-answer"
|
|
10272
|
+
)
|
|
10273
|
+
);
|
|
9919
10274
|
}
|
|
9920
10275
|
return;
|
|
9921
10276
|
}
|
|
@@ -9978,7 +10333,17 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9978
10333
|
...descendantOngoing != null ? { descendant_ongoing: descendantOngoing } : {},
|
|
9979
10334
|
opencode_message_id: inFlight.opencodeMessageId
|
|
9980
10335
|
});
|
|
9981
|
-
await this.settleMessageDone(
|
|
10336
|
+
await this.settleMessageDone(
|
|
10337
|
+
sessionId,
|
|
10338
|
+
watcher,
|
|
10339
|
+
inFlight,
|
|
10340
|
+
messages,
|
|
10341
|
+
composeAbandonmentNote(
|
|
10342
|
+
finish,
|
|
10343
|
+
describeAbandonedReplyShape(messages, inFlight.opencodeMessageId),
|
|
10344
|
+
"with-answer"
|
|
10345
|
+
)
|
|
10346
|
+
);
|
|
9982
10347
|
return;
|
|
9983
10348
|
}
|
|
9984
10349
|
if (rootOngoing === true && !inFlight.b2RootOngoingHeldLogged) {
|
|
@@ -10178,15 +10543,11 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
10178
10543
|
}
|
|
10179
10544
|
}
|
|
10180
10545
|
/**
|
|
10181
|
-
* Settle a message whose run-state has resolved `'done'
|
|
10182
|
-
*
|
|
10183
|
-
*
|
|
10184
|
-
* b2-abandonment resolution) can reach the exact same completion behavior
|
|
10185
|
-
* (delivery-deadline anchoring, title resolution, usage extraction, and
|
|
10186
|
-
* `markDone`'s auth/terminal/transient-retry discipline) without duplicating it
|
|
10187
|
-
* and risking the two copies silently drifting apart.
|
|
10546
|
+
* Settle a message whose run-state has resolved `'done'`. Normal completion and
|
|
10547
|
+
* confirmed b2 abandonment share the same delivery, usage, and terminal handling.
|
|
10548
|
+
* Normal completions omit the optional terminal diagnostic.
|
|
10188
10549
|
*/
|
|
10189
|
-
async settleMessageDone(sessionId, watcher, inFlight, messages) {
|
|
10550
|
+
async settleMessageDone(sessionId, watcher, inFlight, messages, note) {
|
|
10190
10551
|
const conv = watcher.conv;
|
|
10191
10552
|
this.anchorDeliveryDeadline(inFlight);
|
|
10192
10553
|
if (!inFlight.done) {
|
|
@@ -10213,7 +10574,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
10213
10574
|
title,
|
|
10214
10575
|
usage,
|
|
10215
10576
|
usageAgentName,
|
|
10216
|
-
subagentInvocations
|
|
10577
|
+
subagentInvocations,
|
|
10578
|
+
note
|
|
10217
10579
|
);
|
|
10218
10580
|
} catch (err) {
|
|
10219
10581
|
if (err instanceof ChannelAuthError) throw err;
|
|
@@ -10258,9 +10620,11 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
10258
10620
|
/** Report a confirmed b2 abandonment that produced no answer text. */
|
|
10259
10621
|
async settleMessageAbandonedWithoutAnswer(sessionId, watcher, inFlight, messages, finish) {
|
|
10260
10622
|
const conv = watcher.conv;
|
|
10261
|
-
const
|
|
10262
|
-
|
|
10263
|
-
|
|
10623
|
+
const error2 = composeAbandonmentNote(
|
|
10624
|
+
finish,
|
|
10625
|
+
describeAbandonedReplyShape(messages, inFlight.opencodeMessageId),
|
|
10626
|
+
"without-answer"
|
|
10627
|
+
);
|
|
10264
10628
|
this.anchorDeliveryDeadline(inFlight);
|
|
10265
10629
|
this.log({
|
|
10266
10630
|
level: "warn",
|
|
@@ -11497,14 +11861,14 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
11497
11861
|
const fetchChildWithoutBlocking = async (sessionId) => {
|
|
11498
11862
|
const pending = fetchChildMessages(sessionId);
|
|
11499
11863
|
let timer;
|
|
11500
|
-
const timeout = new Promise((
|
|
11864
|
+
const timeout = new Promise((resolve5) => {
|
|
11501
11865
|
timer = setTimeout(() => {
|
|
11502
11866
|
this.log({
|
|
11503
11867
|
level: "warn",
|
|
11504
11868
|
message: `Best-effort subagent session fetch for message ${messageId.slice(0, 8)} and child session ${sessionId.slice(0, 8)} was slow \u2014 omitting invocation telemetry without delaying completion`,
|
|
11505
11869
|
message_id: messageId
|
|
11506
11870
|
});
|
|
11507
|
-
|
|
11871
|
+
resolve5(null);
|
|
11508
11872
|
}, SUBAGENT_TELEMETRY_FETCH_TIMEOUT_MS);
|
|
11509
11873
|
});
|
|
11510
11874
|
try {
|
|
@@ -12064,7 +12428,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
12064
12428
|
* watcher retries next tick within the
|
|
12065
12429
|
* deadline, Finding 4).
|
|
12066
12430
|
*/
|
|
12067
|
-
async markDone(conversationId, messageId, sessionId, opencodeMessageId, title, usage, usageAgentName, subagentInvocations) {
|
|
12431
|
+
async markDone(conversationId, messageId, sessionId, opencodeMessageId, title, usage, usageAgentName, subagentInvocations, error2) {
|
|
12068
12432
|
const res = await this.fetchImpl(
|
|
12069
12433
|
`${this.apiUrl}/runners/${this.agentId}/threads/${conversationId}/messages/${messageId}`,
|
|
12070
12434
|
{
|
|
@@ -12082,7 +12446,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
12082
12446
|
...title ? { title } : {},
|
|
12083
12447
|
...usage ? usage : {},
|
|
12084
12448
|
...usageAgentName ? { usage_agent_name: usageAgentName } : {},
|
|
12085
|
-
...subagentInvocations && subagentInvocations.length > 0 ? { subagent_invocations: subagentInvocations } : {}
|
|
12449
|
+
...subagentInvocations && subagentInvocations.length > 0 ? { subagent_invocations: subagentInvocations } : {},
|
|
12450
|
+
...error2 ? { error: error2 } : {}
|
|
12086
12451
|
})
|
|
12087
12452
|
}
|
|
12088
12453
|
);
|
|
@@ -12745,7 +13110,7 @@ function commandError2(result) {
|
|
|
12745
13110
|
return result.stderr.trim() || `process exited with code ${result.code ?? "null"}`;
|
|
12746
13111
|
}
|
|
12747
13112
|
var runCommand2 = (command, args, opts) => {
|
|
12748
|
-
return new Promise((
|
|
13113
|
+
return new Promise((resolve5) => {
|
|
12749
13114
|
let child;
|
|
12750
13115
|
let stdout = "";
|
|
12751
13116
|
let stderr = "";
|
|
@@ -12755,7 +13120,7 @@ var runCommand2 = (command, args, opts) => {
|
|
|
12755
13120
|
if (settled) return;
|
|
12756
13121
|
settled = true;
|
|
12757
13122
|
if (timer.handle) clearTimeout(timer.handle);
|
|
12758
|
-
|
|
13123
|
+
resolve5(result);
|
|
12759
13124
|
};
|
|
12760
13125
|
try {
|
|
12761
13126
|
child = spawn5(command, args, { env: opts.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -12810,7 +13175,9 @@ async function installRunnerSecret({
|
|
|
12810
13175
|
}) {
|
|
12811
13176
|
const arn = env.RUNNER_SECRET_ARN?.trim();
|
|
12812
13177
|
if (!arn) {
|
|
12813
|
-
|
|
13178
|
+
if (!env.GH_TOKEN) {
|
|
13179
|
+
log3("runner secret is not configured; continuing without GitHub and MCP credentials");
|
|
13180
|
+
}
|
|
12814
13181
|
return false;
|
|
12815
13182
|
}
|
|
12816
13183
|
const result = await (commandRunner ?? runCommand2)(
|
|
@@ -13009,7 +13376,7 @@ async function configureGitHubAccess({ env, log: log3 }) {
|
|
|
13009
13376
|
// src/lib/opencode/config-overlay.ts
|
|
13010
13377
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
13011
13378
|
import { copyFileSync, existsSync as existsSync2, statSync as statSync6 } from "node:fs";
|
|
13012
|
-
import { isAbsolute as
|
|
13379
|
+
import { isAbsolute as isAbsolute3, join as join11, resolve as resolve4 } from "node:path";
|
|
13013
13380
|
function isFile(filePath) {
|
|
13014
13381
|
return existsSync2(filePath) && statSync6(filePath).isFile();
|
|
13015
13382
|
}
|
|
@@ -13022,8 +13389,8 @@ function applyRunnerOpenCodeConfig({
|
|
|
13022
13389
|
log3("runner OpenCode config is not configured; using the baked project config", "debug");
|
|
13023
13390
|
return;
|
|
13024
13391
|
}
|
|
13025
|
-
const source =
|
|
13026
|
-
const target = isFile(
|
|
13392
|
+
const source = isAbsolute3(overlayPath) ? overlayPath : resolve4(cwd, overlayPath);
|
|
13393
|
+
const target = isFile(join11(cwd, "opencode.jsonc")) ? "opencode.jsonc" : "opencode.json";
|
|
13027
13394
|
if (!isFile(source)) {
|
|
13028
13395
|
log3(
|
|
13029
13396
|
`RUNNER-OPENCODE-CONFIG-MISSING: ${source} is not a file; headless turns will wedge on the first external-directory permission prompt (#563)`,
|
|
@@ -13031,7 +13398,7 @@ function applyRunnerOpenCodeConfig({
|
|
|
13031
13398
|
);
|
|
13032
13399
|
return;
|
|
13033
13400
|
}
|
|
13034
|
-
copyFileSync(source,
|
|
13401
|
+
copyFileSync(source, join11(cwd, target));
|
|
13035
13402
|
try {
|
|
13036
13403
|
execFileSync2("git", ["-C", cwd, "update-index", "--skip-worktree", target], {
|
|
13037
13404
|
stdio: "ignore"
|
|
@@ -13040,7 +13407,7 @@ function applyRunnerOpenCodeConfig({
|
|
|
13040
13407
|
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
13041
13408
|
log3(`could not mark ${target} skip-worktree: ${detail}; it may show as a local change`, "warn");
|
|
13042
13409
|
}
|
|
13043
|
-
log3(`Applied runner OpenCode config ${source} to ${
|
|
13410
|
+
log3(`Applied runner OpenCode config ${source} to ${join11(cwd, target)}`);
|
|
13044
13411
|
}
|
|
13045
13412
|
|
|
13046
13413
|
// src/lib/credential-sync.ts
|
|
@@ -13058,14 +13425,14 @@ function errorMessage2(error2) {
|
|
|
13058
13425
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
13059
13426
|
}
|
|
13060
13427
|
function waitForSettlement(promise, timeoutMs) {
|
|
13061
|
-
return new Promise((
|
|
13428
|
+
return new Promise((resolve5) => {
|
|
13062
13429
|
let settled = false;
|
|
13063
13430
|
const timer = setTimeout(() => finish(false), Math.max(0, timeoutMs));
|
|
13064
13431
|
const finish = (value) => {
|
|
13065
13432
|
if (settled) return;
|
|
13066
13433
|
settled = true;
|
|
13067
13434
|
clearTimeout(timer);
|
|
13068
|
-
|
|
13435
|
+
resolve5(value);
|
|
13069
13436
|
};
|
|
13070
13437
|
promise.then(
|
|
13071
13438
|
() => finish(true),
|
|
@@ -13316,8 +13683,8 @@ function resolveFileSyncDirectories(raw, homeDir) {
|
|
|
13316
13683
|
if (trimmed === "") {
|
|
13317
13684
|
throw new Error("--enable-file-sync-to requires a directory path (got an empty value)");
|
|
13318
13685
|
}
|
|
13319
|
-
const expanded = trimmed === "~" ? homeDir : trimmed.startsWith("~/") ?
|
|
13320
|
-
if (!
|
|
13686
|
+
const expanded = trimmed === "~" ? homeDir : trimmed.startsWith("~/") ? join12(homeDir, trimmed.slice(2)) : trimmed;
|
|
13687
|
+
if (!isAbsolute4(expanded)) {
|
|
13321
13688
|
throw new Error(`--enable-file-sync-to requires an absolute directory path; got "${entry}"`);
|
|
13322
13689
|
}
|
|
13323
13690
|
const normalized = resolvePath2(expanded);
|
|
@@ -13417,8 +13784,7 @@ function resolveMaxActiveSessions(options, env = process.env) {
|
|
|
13417
13784
|
function meetsThreshold(state, level) {
|
|
13418
13785
|
return LOG_LEVELS[level] >= LOG_LEVELS[state.logLevel];
|
|
13419
13786
|
}
|
|
13420
|
-
function
|
|
13421
|
-
if (!meetsThreshold(state, level)) return;
|
|
13787
|
+
function writeConsoleLog(state, message, level) {
|
|
13422
13788
|
if (state.json) {
|
|
13423
13789
|
console.log(
|
|
13424
13790
|
JSON.stringify({
|
|
@@ -13427,10 +13793,18 @@ function log2(state, message, level = "info") {
|
|
|
13427
13793
|
message
|
|
13428
13794
|
})
|
|
13429
13795
|
);
|
|
13430
|
-
|
|
13431
|
-
const prefix = level === "error" ? chalk7.red("\u2717") : level === "warn" ? chalk7.yellow("!") : level === "debug" ? chalk7.dim("\xB7") : chalk7.green("\u2022");
|
|
13432
|
-
console.log(`${prefix} ${message}`);
|
|
13796
|
+
return;
|
|
13433
13797
|
}
|
|
13798
|
+
const prefix = level === "error" ? chalk7.red("\u2717") : level === "warn" ? chalk7.yellow("!") : level === "debug" ? chalk7.dim("\xB7") : chalk7.green("\u2022");
|
|
13799
|
+
console.log(`${prefix} ${message}`);
|
|
13800
|
+
}
|
|
13801
|
+
function log2(state, message, level = "info") {
|
|
13802
|
+
if (!meetsThreshold(state, level)) return;
|
|
13803
|
+
if (state.json || !state.interactive) writeConsoleLog(state, message, level);
|
|
13804
|
+
}
|
|
13805
|
+
function logLocalOnly(state, message, level = "info") {
|
|
13806
|
+
if (!meetsThreshold(state, level)) return;
|
|
13807
|
+
writeConsoleLog(state, message, level);
|
|
13434
13808
|
}
|
|
13435
13809
|
function logActivity(state, entry) {
|
|
13436
13810
|
const level = entry.level ?? (entry.type === "error" ? "error" : "info");
|
|
@@ -13732,7 +14106,7 @@ async function driveChannels(state, driver) {
|
|
|
13732
14106
|
}
|
|
13733
14107
|
}
|
|
13734
14108
|
}
|
|
13735
|
-
await new Promise((
|
|
14109
|
+
await new Promise((resolve5) => setTimeout(resolve5, CHANNEL_POLL_INTERVAL_MS));
|
|
13736
14110
|
const cycleMs = performance.now() - cycleStartedAtMs;
|
|
13737
14111
|
if (idleThisCycle) idleMs += cycleMs;
|
|
13738
14112
|
if (unreachableThisCycle) unreachableMs += cycleMs;
|
|
@@ -13754,6 +14128,9 @@ async function driveChannels(state, driver) {
|
|
|
13754
14128
|
}
|
|
13755
14129
|
var SESSION_CLEANUP_FIRST_SWEEP_MS = 1e4;
|
|
13756
14130
|
var SESSION_CLEANUP_MAX_DELETES_PER_SWEEP = 100;
|
|
14131
|
+
var SESSION_CLEANUP_MAX_ISOLATED_DELETE_FAILURES = 2;
|
|
14132
|
+
var SESSION_CLEANUP_GIVE_UP_AFTER_FAILURES = 2;
|
|
14133
|
+
var MAX_SESSION_DELETE_BODY_LENGTH = 200;
|
|
13757
14134
|
function shouldWarnForReclaimSkip(reason) {
|
|
13758
14135
|
if (reason !== "sqlite-unavailable" && reason !== "disk-exhaustion") return false;
|
|
13759
14136
|
const version2 = /^v(\d+)\.(\d+)\.(\d+)$/.exec(process.version);
|
|
@@ -13764,7 +14141,7 @@ function shouldWarnForReclaimSkip(reason) {
|
|
|
13764
14141
|
return major > 22 || major === 22 && (minor > 13 || minor === 13 && patch >= 0);
|
|
13765
14142
|
}
|
|
13766
14143
|
function sessionDbPath() {
|
|
13767
|
-
return
|
|
14144
|
+
return join12(homedir7(), ".local", "share", "opencode", "opencode.db");
|
|
13768
14145
|
}
|
|
13769
14146
|
function logSessionCleanupActivity(state, phase, entry) {
|
|
13770
14147
|
logActivity(state, {
|
|
@@ -13841,8 +14218,12 @@ async function runSweep(state, driver, config) {
|
|
|
13841
14218
|
protectedIds: protectedNow
|
|
13842
14219
|
}
|
|
13843
14220
|
);
|
|
13844
|
-
const
|
|
13845
|
-
|
|
14221
|
+
const eligibleToDelete = toDelete.filter(
|
|
14222
|
+
(id) => (state.sessionDeleteFailures.get(id)?.isolatedFailures ?? 0) < SESSION_CLEANUP_GIVE_UP_AFTER_FAILURES
|
|
14223
|
+
);
|
|
14224
|
+
const deleteCandidates = eligibleToDelete.slice(0, SESSION_CLEANUP_MAX_DELETES_PER_SWEEP);
|
|
14225
|
+
remaining = eligibleToDelete.length - deleteCandidates.length;
|
|
14226
|
+
const answeredFailures = [];
|
|
13846
14227
|
protectedNow = driver.protectedSessionIds();
|
|
13847
14228
|
for (const id of deleteCandidates) {
|
|
13848
14229
|
if (protectedNow.has(id)) {
|
|
@@ -13865,8 +14246,44 @@ async function runSweep(state, driver, config) {
|
|
|
13865
14246
|
if (statusClass === 4) failed4xx++;
|
|
13866
14247
|
else if (statusClass === 5) failed5xx++;
|
|
13867
14248
|
else failedOtherStatus++;
|
|
14249
|
+
answeredFailures.push({
|
|
14250
|
+
id,
|
|
14251
|
+
status: outcome.status,
|
|
14252
|
+
...outcome.body !== void 0 ? { body: outcome.body } : {}
|
|
14253
|
+
});
|
|
14254
|
+
}
|
|
14255
|
+
}
|
|
14256
|
+
const givenUpFailures = [];
|
|
14257
|
+
if (failed > SESSION_CLEANUP_MAX_ISOLATED_DELETE_FAILURES) {
|
|
14258
|
+
for (const { id } of answeredFailures) state.sessionDeleteFailures.delete(id);
|
|
14259
|
+
} else {
|
|
14260
|
+
for (const failure of answeredFailures) {
|
|
14261
|
+
const previous = state.sessionDeleteFailures.get(failure.id);
|
|
14262
|
+
const record = previous?.status === failure.status ? { status: failure.status, isolatedFailures: previous.isolatedFailures + 1 } : { status: failure.status, isolatedFailures: 1 };
|
|
14263
|
+
state.sessionDeleteFailures.set(failure.id, record);
|
|
14264
|
+
if (record.isolatedFailures >= SESSION_CLEANUP_GIVE_UP_AFTER_FAILURES) {
|
|
14265
|
+
givenUpFailures.push(failure);
|
|
14266
|
+
}
|
|
13868
14267
|
}
|
|
13869
14268
|
}
|
|
14269
|
+
for (const failure of givenUpFailures) {
|
|
14270
|
+
const excerpt = redactDiagnosticText(failure.body ?? "(no response body)").slice(
|
|
14271
|
+
0,
|
|
14272
|
+
MAX_SESSION_DELETE_BODY_LENGTH
|
|
14273
|
+
);
|
|
14274
|
+
logSessionCleanupActivity(state, "sweep", {
|
|
14275
|
+
type: "info",
|
|
14276
|
+
level: "warn",
|
|
14277
|
+
message: `Session cleanup: gave up on session ${failure.id} after ${SESSION_CLEANUP_GIVE_UP_AFTER_FAILURES} isolated delete failures (status ${failure.status}): ${excerpt}`,
|
|
14278
|
+
metadata: {
|
|
14279
|
+
outcome: "session-delete-given-up",
|
|
14280
|
+
session_id: failure.id,
|
|
14281
|
+
status: failure.status,
|
|
14282
|
+
body_excerpt: excerpt,
|
|
14283
|
+
given_up_count: givenUpFailures.length
|
|
14284
|
+
}
|
|
14285
|
+
});
|
|
14286
|
+
}
|
|
13870
14287
|
const failedNote = failed > 0 ? `, failed ${failed}` : "";
|
|
13871
14288
|
const skippedNote = skippedNewlyActive > 0 ? `, skipped ${skippedNewlyActive} newly-active` : "";
|
|
13872
14289
|
const remainingNote = remaining > 0 ? `, remaining ${remaining}` : "";
|
|
@@ -13887,21 +14304,31 @@ async function runSweep(state, driver, config) {
|
|
|
13887
14304
|
sessions_remaining: remaining,
|
|
13888
14305
|
...enumerationReason !== null ? { session_enumeration_reason: enumerationReason } : {}
|
|
13889
14306
|
};
|
|
14307
|
+
const protectedForReclaim = driver.protectedSessionIds();
|
|
13890
14308
|
const reclaimResult = await reclaimSessionDbSpace({
|
|
13891
14309
|
dbPath: sessionDbPath(),
|
|
13892
14310
|
chunkPages: SESSION_DB_RECLAIM_CHUNK_PAGES,
|
|
13893
14311
|
pageCeiling: SESSION_DB_RECLAIM_PAGE_CEILING,
|
|
13894
14312
|
timeBudgetMs: SESSION_DB_RECLAIM_TIME_BUDGET_MS,
|
|
13895
|
-
|
|
14313
|
+
hasLiveTurn: protectedForReclaim.size > 0,
|
|
14314
|
+
hasProvenanceAnomaly: state.sessionDbProvenanceAnomaly
|
|
13896
14315
|
});
|
|
13897
14316
|
if (reclaimResult.ok) {
|
|
13898
14317
|
state.sessionStoreHealth.observeWritable();
|
|
13899
14318
|
const beforeMib = (reclaimResult.beforeBytes / 1024 / 1024).toFixed(1);
|
|
13900
14319
|
const afterMib = (reclaimResult.afterBytes / 1024 / 1024).toFixed(1);
|
|
13901
14320
|
const checkpointNote = reclaimResult.checkpoint.busy ? ` (on-disk file truncation deferred: checkpoint busy, ${reclaimResult.checkpoint.log} WAL frames pending)` : "";
|
|
14321
|
+
const loopElapsedMs = Math.max(
|
|
14322
|
+
0,
|
|
14323
|
+
reclaimResult.elapsedMs - reclaimResult.checkpointElapsedMs
|
|
14324
|
+
);
|
|
14325
|
+
const reclaimIsSlow = reclaimResult.elapsedMs >= 4 * SESSION_DB_RECLAIM_TIME_BUDGET_MS;
|
|
14326
|
+
const perPageNote = reclaimResult.pagesReclaimed > 0 ? `, per-page ${(loopElapsedMs / reclaimResult.pagesReclaimed).toFixed(2)} ms/page` : "";
|
|
14327
|
+
const slowReclaimNote = reclaimIsSlow ? ` (slow reclaim: total elapsed ${reclaimResult.elapsedMs} ms, checkpoint ${reclaimResult.checkpointElapsedMs} ms, loop ${loopElapsedMs} ms, budget ${SESSION_DB_RECLAIM_TIME_BUDGET_MS} ms${perPageNote})` : "";
|
|
13902
14328
|
logSessionCleanupActivity(state, "sweep", {
|
|
13903
14329
|
type: "info",
|
|
13904
|
-
|
|
14330
|
+
level: reclaimIsSlow ? "warn" : "info",
|
|
14331
|
+
message: `Session cleanup: reclaimed session-db space (${reclaimResult.mode}): ${beforeMib} MiB -> ${afterMib} MiB (stopped by ${reclaimResult.stoppedBy}; freelist ${reclaimResult.freelistBefore} -> ${reclaimResult.freelistAfter} pages)` + checkpointNote + slowReclaimNote,
|
|
13905
14332
|
metadata: {
|
|
13906
14333
|
outcome: "reclaimed",
|
|
13907
14334
|
mode: reclaimResult.mode,
|
|
@@ -13914,6 +14341,7 @@ async function runSweep(state, driver, config) {
|
|
|
13914
14341
|
freelist_after: reclaimResult.freelistAfter,
|
|
13915
14342
|
pages_reclaimed: reclaimResult.pagesReclaimed,
|
|
13916
14343
|
reclaim_elapsed_ms: reclaimResult.elapsedMs,
|
|
14344
|
+
checkpoint_elapsed_ms: reclaimResult.checkpointElapsedMs,
|
|
13917
14345
|
...sessionMetadata
|
|
13918
14346
|
}
|
|
13919
14347
|
});
|
|
@@ -14393,8 +14821,8 @@ async function beginGracefulShutdown(state, trigger) {
|
|
|
14393
14821
|
return true;
|
|
14394
14822
|
}
|
|
14395
14823
|
);
|
|
14396
|
-
const timedOut = new Promise((
|
|
14397
|
-
timer = setTimeout(() =>
|
|
14824
|
+
const timedOut = new Promise((resolve5) => {
|
|
14825
|
+
timer = setTimeout(() => resolve5(false), telemetryBudgetMs);
|
|
14398
14826
|
});
|
|
14399
14827
|
if (!await Promise.race([flushed, timedOut])) {
|
|
14400
14828
|
log2(state, `Telemetry flush exceeded ${telemetryBudgetMs}ms \u2014 exiting anyway`, "warn");
|
|
@@ -14457,6 +14885,7 @@ async function run(options) {
|
|
|
14457
14885
|
messageCount: 0,
|
|
14458
14886
|
lastProxiedActivityAt: null,
|
|
14459
14887
|
sessionCleanupTimers: [],
|
|
14888
|
+
sessionDeleteFailures: /* @__PURE__ */ new Map(),
|
|
14460
14889
|
claudeUsageTimer: null,
|
|
14461
14890
|
claudeUsageRearm: null,
|
|
14462
14891
|
openaiUsageTimer: null,
|
|
@@ -14665,23 +15094,33 @@ async function run(options) {
|
|
|
14665
15094
|
);
|
|
14666
15095
|
}
|
|
14667
15096
|
}
|
|
14668
|
-
|
|
14669
|
-
|
|
14670
|
-
|
|
14671
|
-
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
} else {
|
|
14676
|
-
logActivity(state, { type: "info", level, message });
|
|
14677
|
-
}
|
|
15097
|
+
const credentialContext = {
|
|
15098
|
+
env: process.env,
|
|
15099
|
+
log: (message, level = "info") => {
|
|
15100
|
+
if (level === "error") {
|
|
15101
|
+
logActivity(state, { type: "error", error: message });
|
|
15102
|
+
} else {
|
|
15103
|
+
logActivity(state, { type: "info", level, message });
|
|
14678
15104
|
}
|
|
14679
|
-
}
|
|
14680
|
-
|
|
15105
|
+
}
|
|
15106
|
+
};
|
|
15107
|
+
const githubTokenPopulated = await installRunnerSecret(credentialContext);
|
|
15108
|
+
if (options.restoreRunnerCredentials) {
|
|
14681
15109
|
await restoreCredentialStores(credentialContext);
|
|
14682
|
-
if (githubTokenPopulated) await configureGitHubAccess(credentialContext);
|
|
14683
15110
|
}
|
|
15111
|
+
if (githubTokenPopulated) await configureGitHubAccess(credentialContext);
|
|
14684
15112
|
state.credentialSync?.arm();
|
|
15113
|
+
const dependencyInstallDiagnosticReporter = createDependencyInstallDiagnosticReporter({
|
|
15114
|
+
context: {
|
|
15115
|
+
homeDir: homedir7(),
|
|
15116
|
+
cwd: process.cwd(),
|
|
15117
|
+
microvmId: process.env.MICROVM_ID?.trim(),
|
|
15118
|
+
euid: process.getuid?.(),
|
|
15119
|
+
egid: process.getgid?.()
|
|
15120
|
+
},
|
|
15121
|
+
emitEvent: (message) => logActivity(state, { type: "info", level: "warn", message }),
|
|
15122
|
+
emitLocal: (message) => logLocalOnly(state, message, "warn")
|
|
15123
|
+
});
|
|
14685
15124
|
const openCodeActivityForwarder = createOpenCodeActivityForwarder(
|
|
14686
15125
|
() => ({
|
|
14687
15126
|
agentId: state.agentId,
|
|
@@ -14692,7 +15131,8 @@ async function run(options) {
|
|
|
14692
15131
|
if (cause !== null && sessionId !== null) {
|
|
14693
15132
|
state.sessionStoreHealth.observeCause(sessionId, cause);
|
|
14694
15133
|
}
|
|
14695
|
-
}
|
|
15134
|
+
},
|
|
15135
|
+
dependencyInstallDiagnosticReporter
|
|
14696
15136
|
);
|
|
14697
15137
|
const openCodeLogTail = tailOpenCodeLogFile(
|
|
14698
15138
|
resolveOpenCodeLogPath(homedir7(), process.env),
|