@evident-ai/cli 3.5.2-dev.2828873 → 3.5.2-dev.3431f9f
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 +115 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { createRequire as createRequire2 } from "module";
|
|
5
4
|
import { Command } from "commander";
|
|
6
5
|
|
|
7
6
|
// src/commands/login.ts
|
|
@@ -1158,7 +1157,7 @@ import ora4 from "ora";
|
|
|
1158
1157
|
import { select as select4 } from "@inquirer/prompts";
|
|
1159
1158
|
|
|
1160
1159
|
// src/lib/telemetry.ts
|
|
1161
|
-
var CLI_VERSION = (true ? "3.5.2-dev.
|
|
1160
|
+
var CLI_VERSION = (true ? "3.5.2-dev.3431f9f" : void 0) ?? process.env.npm_package_version ?? "unknown";
|
|
1162
1161
|
function getCliVersion() {
|
|
1163
1162
|
return CLI_VERSION;
|
|
1164
1163
|
}
|
|
@@ -1449,7 +1448,7 @@ function redactHomeDirectory(message) {
|
|
|
1449
1448
|
}
|
|
1450
1449
|
return result + message.slice(searchFrom);
|
|
1451
1450
|
}
|
|
1452
|
-
function
|
|
1451
|
+
function redactDiagnosticText(message) {
|
|
1453
1452
|
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
1453
|
return redactHomeDirectory(redacted);
|
|
1455
1454
|
}
|
|
@@ -1468,7 +1467,10 @@ function sanitiseMetadata(metadata) {
|
|
|
1468
1467
|
const sanitised = [];
|
|
1469
1468
|
for (const [key, value] of entries) {
|
|
1470
1469
|
if (typeof value === "string") {
|
|
1471
|
-
sanitised.push([
|
|
1470
|
+
sanitised.push([
|
|
1471
|
+
key,
|
|
1472
|
+
truncate(redactDiagnosticText(value).slice(0, MAX_METADATA_VALUE_LENGTH))
|
|
1473
|
+
]);
|
|
1472
1474
|
} else if (value === null || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
|
|
1473
1475
|
sanitised.push([key, value]);
|
|
1474
1476
|
}
|
|
@@ -1513,7 +1515,7 @@ function forwardRunnerActivity(entry, context) {
|
|
|
1513
1515
|
if (!context.agentId || !context.authHeader) return;
|
|
1514
1516
|
if (!admitUnderRateLimit(source, Date.now())) return;
|
|
1515
1517
|
const rawMessage = entry.error ?? entry.message ?? "";
|
|
1516
|
-
const message = truncate(
|
|
1518
|
+
const message = truncate(redactDiagnosticText(rawMessage));
|
|
1517
1519
|
logEvent(TelemetryEventTypes.RUNNER_ACTIVITY, {
|
|
1518
1520
|
severity: SEVERITY_BY_LEVEL[entry.level],
|
|
1519
1521
|
message,
|
|
@@ -1812,8 +1814,46 @@ async function waitForOpenCode2Health(port, password, timeoutMs = 3e4) {
|
|
|
1812
1814
|
|
|
1813
1815
|
// src/lib/http-timeout.ts
|
|
1814
1816
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
1817
|
+
var RequestTimeoutError = class extends Error {
|
|
1818
|
+
constructor(operation, timeoutMs, elapsedMs) {
|
|
1819
|
+
super(`${operation} timed out after ${elapsedMs}ms (limit ${timeoutMs}ms)`);
|
|
1820
|
+
this.operation = operation;
|
|
1821
|
+
this.timeoutMs = timeoutMs;
|
|
1822
|
+
this.elapsedMs = elapsedMs;
|
|
1823
|
+
this.name = "TimeoutError";
|
|
1824
|
+
}
|
|
1825
|
+
};
|
|
1826
|
+
function describeRequestOperation(input, init) {
|
|
1827
|
+
const method = (init?.method ?? input.method ?? "GET").toUpperCase();
|
|
1828
|
+
const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
1829
|
+
let path;
|
|
1830
|
+
try {
|
|
1831
|
+
path = new URL(rawUrl).pathname;
|
|
1832
|
+
} catch (error2) {
|
|
1833
|
+
if (!(error2 instanceof TypeError)) throw error2;
|
|
1834
|
+
path = rawUrl.split(/[?#]/, 1)[0];
|
|
1835
|
+
}
|
|
1836
|
+
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1837
|
+
const prefixedIdentifier = /^[a-z]+_[A-Za-z0-9_-]{10,}$/;
|
|
1838
|
+
const maskedPath = path.split("/").map((segment) => uuid.test(segment) || prefixedIdentifier.test(segment) ? ":id" : segment).join("/");
|
|
1839
|
+
return `${method} ${maskedPath}`;
|
|
1840
|
+
}
|
|
1815
1841
|
function withRequestTimeout(fetchImpl, timeoutMs) {
|
|
1816
|
-
return ((input, init) =>
|
|
1842
|
+
return (async (input, init) => {
|
|
1843
|
+
const startedAt = Date.now();
|
|
1844
|
+
try {
|
|
1845
|
+
return await fetchImpl(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
1846
|
+
} catch (error2) {
|
|
1847
|
+
if (error2?.name === "TimeoutError") {
|
|
1848
|
+
throw new RequestTimeoutError(
|
|
1849
|
+
describeRequestOperation(input, init),
|
|
1850
|
+
timeoutMs,
|
|
1851
|
+
Date.now() - startedAt
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
throw error2;
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1817
1857
|
}
|
|
1818
1858
|
|
|
1819
1859
|
// src/lib/opencode/client.ts
|
|
@@ -5470,6 +5510,8 @@ var StreamForwarder = class {
|
|
|
5470
5510
|
if (done) break;
|
|
5471
5511
|
const chunk = Buffer.from(value);
|
|
5472
5512
|
for (let i = 0; i < chunk.length; i += MAX_FRAME_BYTES) {
|
|
5513
|
+
await stream.pausePromise;
|
|
5514
|
+
if (ac.signal.aborted) break;
|
|
5473
5515
|
const slice = chunk.subarray(i, i + MAX_FRAME_BYTES);
|
|
5474
5516
|
if (this.binaryFramesSupported) {
|
|
5475
5517
|
if (this.ws.readyState === WebSocket.OPEN) {
|
|
@@ -5512,6 +5554,7 @@ function classifyUpgradeRejection(headers) {
|
|
|
5512
5554
|
}
|
|
5513
5555
|
var MAX_RECONNECT_DELAY = 3e4;
|
|
5514
5556
|
var BASE_RECONNECT_DELAY = 500;
|
|
5557
|
+
var RELAY_SILENCE_TIMEOUT_MS = 9e4;
|
|
5515
5558
|
function getReconnectDelay(attempt) {
|
|
5516
5559
|
const exponentialDelay = BASE_RECONNECT_DELAY * Math.pow(2, attempt);
|
|
5517
5560
|
const jitter = Math.random() * 1e3;
|
|
@@ -5583,10 +5626,27 @@ function connectTunnel(options) {
|
|
|
5583
5626
|
ws.close();
|
|
5584
5627
|
reject(new Error("Connection timeout"));
|
|
5585
5628
|
}, 3e4);
|
|
5629
|
+
let relaySilenceTimeout;
|
|
5630
|
+
let relaySilenceTimedOut = false;
|
|
5631
|
+
const clearRelaySilenceTimeout = () => {
|
|
5632
|
+
if (relaySilenceTimeout === void 0) return;
|
|
5633
|
+
clearTimeout(relaySilenceTimeout);
|
|
5634
|
+
relaySilenceTimeout = void 0;
|
|
5635
|
+
};
|
|
5636
|
+
const armRelaySilenceTimeout = () => {
|
|
5637
|
+
clearRelaySilenceTimeout();
|
|
5638
|
+
relaySilenceTimeout = setTimeout(() => {
|
|
5639
|
+
relaySilenceTimeout = void 0;
|
|
5640
|
+
relaySilenceTimedOut = true;
|
|
5641
|
+
ws.terminate();
|
|
5642
|
+
}, RELAY_SILENCE_TIMEOUT_MS);
|
|
5643
|
+
relaySilenceTimeout.unref?.();
|
|
5644
|
+
};
|
|
5586
5645
|
let upgradeRejection = null;
|
|
5587
5646
|
let upgradeRejectionReason = null;
|
|
5588
5647
|
ws.on("unexpected-response", (_req, res) => {
|
|
5589
5648
|
clearTimeout(connectionTimeout);
|
|
5649
|
+
clearRelaySilenceTimeout();
|
|
5590
5650
|
const reason = classifyUpgradeRejection(res.headers);
|
|
5591
5651
|
upgradeRejectionReason = reason;
|
|
5592
5652
|
const chunks = [];
|
|
@@ -5616,6 +5676,7 @@ function connectTunnel(options) {
|
|
|
5616
5676
|
onInfo?.("WebSocket connection established");
|
|
5617
5677
|
});
|
|
5618
5678
|
ws.on("message", (data, isBinary) => {
|
|
5679
|
+
if (relaySilenceTimeout !== void 0) armRelaySilenceTimeout();
|
|
5619
5680
|
if (isBinary) {
|
|
5620
5681
|
try {
|
|
5621
5682
|
const frame = decodeBinaryBodyFrame(toUint8Array(data));
|
|
@@ -5649,6 +5710,7 @@ function connectTunnel(options) {
|
|
|
5649
5710
|
switch (message.type) {
|
|
5650
5711
|
case "connected": {
|
|
5651
5712
|
clearTimeout(connectionTimeout);
|
|
5713
|
+
armRelaySilenceTimeout();
|
|
5652
5714
|
forwarder.setBinaryFramesSupported(message.binary_frames === true);
|
|
5653
5715
|
const connectedAgentId = message.agent_id ?? agentId;
|
|
5654
5716
|
onConnected?.(connectedAgentId);
|
|
@@ -5673,6 +5735,7 @@ function connectTunnel(options) {
|
|
|
5673
5735
|
});
|
|
5674
5736
|
ws.on("error", (error2) => {
|
|
5675
5737
|
clearTimeout(connectionTimeout);
|
|
5738
|
+
clearRelaySilenceTimeout();
|
|
5676
5739
|
const detail = upgradeRejection ?? describeSocketError(error2, url);
|
|
5677
5740
|
if (upgradeRejectionReason === "do_code_updated") {
|
|
5678
5741
|
onWarning?.("Relay redeployed \u2014 reconnecting");
|
|
@@ -5684,7 +5747,8 @@ function connectTunnel(options) {
|
|
|
5684
5747
|
);
|
|
5685
5748
|
});
|
|
5686
5749
|
ws.on("close", (code, reason) => {
|
|
5687
|
-
|
|
5750
|
+
clearRelaySilenceTimeout();
|
|
5751
|
+
const reasonStr = (relaySilenceTimedOut ? "no relay heartbeat for 90s \u2014 reconnecting" : void 0) || reason.toString() || upgradeRejection || (code === 1006 ? "abnormal closure" : "No reason provided");
|
|
5688
5752
|
forwarder.abortAll();
|
|
5689
5753
|
onDisconnected?.(code, reasonStr);
|
|
5690
5754
|
});
|
|
@@ -5692,9 +5756,10 @@ function connectTunnel(options) {
|
|
|
5692
5756
|
}
|
|
5693
5757
|
|
|
5694
5758
|
// src/lib/tunnel/runner-connection.ts
|
|
5695
|
-
var RunnerConnection = class {
|
|
5759
|
+
var RunnerConnection = class _RunnerConnection {
|
|
5696
5760
|
opts;
|
|
5697
5761
|
sleep;
|
|
5762
|
+
now;
|
|
5698
5763
|
connection = null;
|
|
5699
5764
|
resolvedAgentId;
|
|
5700
5765
|
/** True while a (re)connect loop is in flight. */
|
|
@@ -5703,10 +5768,17 @@ var RunnerConnection = class {
|
|
|
5703
5768
|
reconnectPromise = null;
|
|
5704
5769
|
/** 1-based count of the current reconnect attempt streak. */
|
|
5705
5770
|
reconnectAttempt = 0;
|
|
5771
|
+
generation = 0;
|
|
5772
|
+
disconnectedAtMs = null;
|
|
5773
|
+
static RELAY_RECONNECT_CLOSE_REASONS = /* @__PURE__ */ new Set([
|
|
5774
|
+
"No pong received",
|
|
5775
|
+
"Orphaned socket"
|
|
5776
|
+
]);
|
|
5706
5777
|
constructor(opts) {
|
|
5707
5778
|
this.opts = opts;
|
|
5708
5779
|
this.resolvedAgentId = opts.agentId;
|
|
5709
5780
|
this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
5781
|
+
this.now = opts.now ?? Date.now;
|
|
5710
5782
|
}
|
|
5711
5783
|
get agentId() {
|
|
5712
5784
|
return this.resolvedAgentId;
|
|
@@ -5742,14 +5814,24 @@ var RunnerConnection = class {
|
|
|
5742
5814
|
port: this.opts.port,
|
|
5743
5815
|
openCodePassword: this.opts.openCodePassword,
|
|
5744
5816
|
onConnected: (agentId) => {
|
|
5817
|
+
const attempt = this.reconnectAttempt + 1;
|
|
5745
5818
|
this.reconnectAttempt = 0;
|
|
5746
5819
|
this.reconnecting = false;
|
|
5747
5820
|
this.resolvedAgentId = agentId;
|
|
5748
|
-
|
|
5821
|
+
this.generation++;
|
|
5822
|
+
const downtimeMs = this.disconnectedAtMs === null ? null : this.now() - this.disconnectedAtMs;
|
|
5823
|
+
this.disconnectedAtMs = null;
|
|
5824
|
+
events.onConnected(agentId, isReconnect, {
|
|
5825
|
+
generation: this.generation,
|
|
5826
|
+
attempt,
|
|
5827
|
+
downtimeMs
|
|
5828
|
+
});
|
|
5749
5829
|
},
|
|
5750
5830
|
onDisconnected: (code, reason) => {
|
|
5751
|
-
|
|
5752
|
-
|
|
5831
|
+
this.disconnectedAtMs = this.now();
|
|
5832
|
+
events.onDisconnected(code, reason, { generation: this.generation });
|
|
5833
|
+
const relayRequestedReconnect = code === 1e3 && _RunnerConnection.RELAY_RECONNECT_CLOSE_REASONS.has(reason);
|
|
5834
|
+
if (this.opts.isRunning() && (code !== 1e3 || relayRequestedReconnect) && !this.reconnecting) {
|
|
5753
5835
|
this.reconnectPromise = this.connectWithRetry(true).catch((err) => {
|
|
5754
5836
|
events.onError?.(`Reconnection failed: ${err.message}`);
|
|
5755
5837
|
});
|
|
@@ -12225,6 +12307,7 @@ function createCredentialSync({
|
|
|
12225
12307
|
|
|
12226
12308
|
// src/commands/run.ts
|
|
12227
12309
|
var MAX_ACTIVITY_LOG_ENTRIES = 10;
|
|
12310
|
+
var MAX_DISCONNECT_REASON_LENGTH = 200;
|
|
12228
12311
|
var CHANNEL_POLL_INTERVAL_MS = Number(process.env.EVIDENT_CHANNEL_POLL_INTERVAL_MS) || 2e3;
|
|
12229
12312
|
var CHANNEL_STUCK_QUEUED_MS = Number(process.env.EVIDENT_STUCK_QUEUED_MS) || void 0;
|
|
12230
12313
|
var SHUTDOWN_DRAIN_TIMEOUT_MS = Number(process.env.EVIDENT_SHUTDOWN_DRAIN_MS) || 25e3;
|
|
@@ -12443,7 +12526,9 @@ function displayStatus(state) {
|
|
|
12443
12526
|
const opencode = state.opencodeConnected ? chalk7.green(`opencode: :${state.port}`) : chalk7.red(`opencode: :${state.port} (down)`);
|
|
12444
12527
|
const messages = state.messageCount > 0 ? chalk7.dim(` \xB7 ${state.messageCount} processed`) : "";
|
|
12445
12528
|
const last = state.activityLog[state.activityLog.length - 1];
|
|
12446
|
-
const detail = last ? chalk7.dim(
|
|
12529
|
+
const detail = last ? chalk7.dim(
|
|
12530
|
+
` \xB7 ${last.timestamp.toISOString()} ${last.type === "error" ? last.error ?? "" : last.message ?? ""}`
|
|
12531
|
+
) : "";
|
|
12447
12532
|
const agent = state.agentName ?? state.agentId;
|
|
12448
12533
|
console.log(
|
|
12449
12534
|
`${chalk7.bold("Evident")} ${chalk7.dim(agent)} ${tunnel} ${opencode}${messages}${detail}`
|
|
@@ -13864,12 +13949,13 @@ async function run(options) {
|
|
|
13864
13949
|
openCodePassword: state.opencodePassword,
|
|
13865
13950
|
isRunning: () => state.running,
|
|
13866
13951
|
events: {
|
|
13867
|
-
onConnected: (agentId, isReconnect) => {
|
|
13952
|
+
onConnected: (agentId, isReconnect, transition) => {
|
|
13868
13953
|
state.connected = true;
|
|
13869
13954
|
state.agentId = agentId;
|
|
13955
|
+
const connectionMessage = isReconnect ? `Tunnel reconnected (runner: ${agentId}, generation: ${transition.generation}, attempt: ${transition.attempt}, offline for ${transition.downtimeMs}ms)` : `Tunnel connected (runner: ${agentId}, generation: ${transition.generation})`;
|
|
13870
13956
|
logActivity(state, {
|
|
13871
13957
|
type: "info",
|
|
13872
|
-
message:
|
|
13958
|
+
message: connectionMessage
|
|
13873
13959
|
});
|
|
13874
13960
|
if (options.tunnelReadyFile) {
|
|
13875
13961
|
const marker = writeTunnelReadyMarker(options.tunnelReadyFile, agentId);
|
|
@@ -13890,7 +13976,12 @@ async function run(options) {
|
|
|
13890
13976
|
version: state.opencodeVersion,
|
|
13891
13977
|
major: state.opencodeApiVersion,
|
|
13892
13978
|
connected: state.opencodeConnected
|
|
13893
|
-
})
|
|
13979
|
+
}),
|
|
13980
|
+
connection_generation: transition.generation,
|
|
13981
|
+
...isReconnect && transition.downtimeMs !== null ? {
|
|
13982
|
+
reconnect_attempt: transition.attempt,
|
|
13983
|
+
downtime_ms: transition.downtimeMs
|
|
13984
|
+
} : {}
|
|
13894
13985
|
});
|
|
13895
13986
|
if (!isReconnect) tunnelSpinner?.succeed("Tunnel connected");
|
|
13896
13987
|
if (state.interactive) displayStatus(state);
|
|
@@ -13912,13 +14003,18 @@ async function run(options) {
|
|
|
13912
14003
|
if (state.interactive) displayStatus(state);
|
|
13913
14004
|
});
|
|
13914
14005
|
},
|
|
13915
|
-
onDisconnected: (code, reason) => {
|
|
14006
|
+
onDisconnected: (code, reason, transition) => {
|
|
13916
14007
|
state.connected = false;
|
|
14008
|
+
const safeReason = redactDiagnosticText(reason).slice(0, MAX_DISCONNECT_REASON_LENGTH);
|
|
13917
14009
|
logActivity(state, {
|
|
13918
14010
|
type: "info",
|
|
13919
|
-
message: `Tunnel disconnected (code: ${code}, reason: ${
|
|
14011
|
+
message: `Tunnel disconnected (generation: ${transition.generation}, code: ${code}, reason: ${safeReason})`
|
|
14012
|
+
});
|
|
14013
|
+
emitAgentDisconnected(state.agentId, {
|
|
14014
|
+
code,
|
|
14015
|
+
reason: safeReason,
|
|
14016
|
+
connection_generation: transition.generation
|
|
13920
14017
|
});
|
|
13921
|
-
emitAgentDisconnected(state.agentId, { code, reason });
|
|
13922
14018
|
if (state.interactive) displayStatus(state);
|
|
13923
14019
|
},
|
|
13924
14020
|
onError: (error2) => {
|
|
@@ -14061,7 +14157,7 @@ async function run(options) {
|
|
|
14061
14157
|
}
|
|
14062
14158
|
|
|
14063
14159
|
// src/index.ts
|
|
14064
|
-
var
|
|
14160
|
+
var version = getCliVersion();
|
|
14065
14161
|
var program = new Command();
|
|
14066
14162
|
program.name("evident").description("Run OpenCode locally and connect it to Evident").version(version).option(
|
|
14067
14163
|
"--endpoint <url>",
|