@evident-ai/cli 3.0.1-dev.82c68ac → 3.0.1-dev.892519e
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 +79 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { createRequire } from "module";
|
|
4
5
|
import { Command } from "commander";
|
|
5
6
|
|
|
6
7
|
// src/commands/login.ts
|
|
@@ -490,6 +491,29 @@ var TelemetryEventTypes = {
|
|
|
490
491
|
var MAX_FRAME_BYTES = 256 * 1024;
|
|
491
492
|
var TUNNEL_DRAIN_PING_PATH = "/__evident/drain";
|
|
492
493
|
|
|
494
|
+
// ../../packages/types/src/logging/index.ts
|
|
495
|
+
var CORRELATION_ID_HEADER = "x-evident-correlation-id";
|
|
496
|
+
function log(level, event, fields) {
|
|
497
|
+
const method = level === "debug" ? "log" : level;
|
|
498
|
+
try {
|
|
499
|
+
console[method]("[evident]", JSON.stringify({ level, event, ...fields }));
|
|
500
|
+
} catch (err) {
|
|
501
|
+
console.error(
|
|
502
|
+
"[evident] log_serialize_failed",
|
|
503
|
+
event,
|
|
504
|
+
err instanceof Error ? err.message : String(err)
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function stripQuery(url) {
|
|
509
|
+
try {
|
|
510
|
+
return new URL(url).pathname;
|
|
511
|
+
} catch {
|
|
512
|
+
const q = url.indexOf("?");
|
|
513
|
+
return q === -1 ? url : url.slice(0, q);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
493
517
|
// src/lib/telemetry.ts
|
|
494
518
|
var CLI_VERSION = process.env.npm_package_version || "unknown";
|
|
495
519
|
var eventBuffer = [];
|
|
@@ -692,13 +716,13 @@ async function waitForOpenCodeHealth(port, timeoutMs = 3e4) {
|
|
|
692
716
|
|
|
693
717
|
// src/lib/opencode/opencode-version-gate.ts
|
|
694
718
|
var QUEUE_VALIDATED_OPENCODE_VERSIONS = ["1.17.11"];
|
|
695
|
-
function isQueueValidatedVersion(
|
|
696
|
-
if (!
|
|
697
|
-
return QUEUE_VALIDATED_OPENCODE_VERSIONS.includes(
|
|
719
|
+
function isQueueValidatedVersion(version2) {
|
|
720
|
+
if (!version2) return false;
|
|
721
|
+
return QUEUE_VALIDATED_OPENCODE_VERSIONS.includes(version2);
|
|
698
722
|
}
|
|
699
|
-
function buildOpenCodeVersionWarning(
|
|
700
|
-
if (isQueueValidatedVersion(
|
|
701
|
-
const detected =
|
|
723
|
+
function buildOpenCodeVersionWarning(version2) {
|
|
724
|
+
if (isQueueValidatedVersion(version2)) return null;
|
|
725
|
+
const detected = version2 ? `v${version2}` : "unknown";
|
|
702
726
|
const validated = QUEUE_VALIDATED_OPENCODE_VERSIONS.map((v) => `v${v}`).join(", ");
|
|
703
727
|
return `Warning: opencode ${detected} is not a queue-validated version (validated: ${validated}). Native message queuing \u2014 which channel (Slack/WhatsApp) message handling relies on \u2014 is unverified on this version; queued/follow-up messages may behave unexpectedly. Continuing anyway. Bumping the validated set requires re-running the queue validation.`;
|
|
704
728
|
}
|
|
@@ -1192,12 +1216,20 @@ var StreamForwarder = class {
|
|
|
1192
1216
|
}
|
|
1193
1217
|
async handleOpen(frame) {
|
|
1194
1218
|
const { sid, method, path, headers, has_body } = frame;
|
|
1219
|
+
const correlationId = headers?.[CORRELATION_ID_HEADER];
|
|
1220
|
+
const startedAt = Date.now();
|
|
1195
1221
|
if (path === TUNNEL_DRAIN_PING_PATH) {
|
|
1196
1222
|
this.callbacks.onDrainPing?.();
|
|
1197
1223
|
this.send({ type: "head", sid, status: 204, headers: {} });
|
|
1198
1224
|
this.send({ type: "res_end", sid });
|
|
1199
1225
|
return;
|
|
1200
1226
|
}
|
|
1227
|
+
log("info", "agent_request", {
|
|
1228
|
+
correlation_id: correlationId,
|
|
1229
|
+
sid,
|
|
1230
|
+
method,
|
|
1231
|
+
path: stripQuery(path)
|
|
1232
|
+
});
|
|
1201
1233
|
const ac = new AbortController();
|
|
1202
1234
|
let bodyPromise;
|
|
1203
1235
|
let pushBody;
|
|
@@ -1244,6 +1276,12 @@ var StreamForwarder = class {
|
|
|
1244
1276
|
if (!STRIP_RES.has(key.toLowerCase())) resHeaders[key] = value;
|
|
1245
1277
|
});
|
|
1246
1278
|
this.send({ type: "head", sid, status: upstream.status, headers: resHeaders });
|
|
1279
|
+
log("info", "agent_response", {
|
|
1280
|
+
correlation_id: correlationId,
|
|
1281
|
+
sid,
|
|
1282
|
+
status: upstream.status,
|
|
1283
|
+
duration_ms: Date.now() - startedAt
|
|
1284
|
+
});
|
|
1247
1285
|
this.callbacks.onHead?.(sid, upstream.status);
|
|
1248
1286
|
try {
|
|
1249
1287
|
if (upstream.body) {
|
|
@@ -1674,8 +1712,10 @@ var ChannelDriver = class {
|
|
|
1674
1712
|
const sessionId = await this.ensureSession(conv);
|
|
1675
1713
|
const messages = await this.getPendingMessages(conv.id);
|
|
1676
1714
|
let dispatched = 0;
|
|
1715
|
+
let skippedAlreadyDispatched = 0;
|
|
1677
1716
|
for (const message of messages) {
|
|
1678
1717
|
if (this.dispatched.has(message.id)) {
|
|
1718
|
+
skippedAlreadyDispatched += 1;
|
|
1679
1719
|
continue;
|
|
1680
1720
|
}
|
|
1681
1721
|
const opencodeMessageId = opencodeMessageIdFor2(message.id);
|
|
@@ -1708,6 +1748,13 @@ var ChannelDriver = class {
|
|
|
1708
1748
|
this.registerInFlight(conv, sessionId, message, opencodeMessageId);
|
|
1709
1749
|
dispatched += 1;
|
|
1710
1750
|
}
|
|
1751
|
+
if (messages.length > 0 && dispatched === 0 && skippedAlreadyDispatched === messages.length) {
|
|
1752
|
+
this.log({
|
|
1753
|
+
level: "error",
|
|
1754
|
+
message: `Conversation ${conv.id.slice(0, 8)} has ${messages.length} pending message(s) but ALL are already marked dispatched locally (in-flight set: ${this.dispatched.size}) \u2014 none sent to OpenCode this tick. If this repeats, a message may be stuck acknowledged-but-never-dispatched (its watcher never settled).`,
|
|
1755
|
+
conversation_id: conv.id
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1711
1758
|
this.ensureWatcherRunning(sessionId);
|
|
1712
1759
|
return dispatched;
|
|
1713
1760
|
}
|
|
@@ -2526,7 +2573,7 @@ async function getAgentInfo(agentId, authHeader) {
|
|
|
2526
2573
|
// src/commands/run.ts
|
|
2527
2574
|
var MAX_ACTIVITY_LOG_ENTRIES = 10;
|
|
2528
2575
|
var CHANNEL_POLL_INTERVAL_MS = Number(process.env.EVIDENT_CHANNEL_POLL_INTERVAL_MS) || 2e3;
|
|
2529
|
-
function
|
|
2576
|
+
function log2(state, message, isError = false) {
|
|
2530
2577
|
if (state.json) {
|
|
2531
2578
|
console.log(
|
|
2532
2579
|
JSON.stringify({
|
|
@@ -2551,9 +2598,9 @@ function logActivity(state, entry) {
|
|
|
2551
2598
|
}
|
|
2552
2599
|
if (!state.interactive) {
|
|
2553
2600
|
if (entry.type === "error") {
|
|
2554
|
-
|
|
2601
|
+
log2(state, entry.error ?? "Unknown error", true);
|
|
2555
2602
|
} else if (entry.type === "info" && entry.message) {
|
|
2556
|
-
|
|
2603
|
+
log2(state, entry.message);
|
|
2557
2604
|
}
|
|
2558
2605
|
}
|
|
2559
2606
|
}
|
|
@@ -2639,6 +2686,7 @@ async function handleAuthError(state, error2) {
|
|
|
2639
2686
|
}
|
|
2640
2687
|
async function driveChannels(state, driver) {
|
|
2641
2688
|
let idlePolls = 0;
|
|
2689
|
+
let lastSeenProxiedActivityAt = state.lastProxiedActivityAt;
|
|
2642
2690
|
while (state.running) {
|
|
2643
2691
|
if (state.connection?.reconnecting && state.connection.reconnectPromise) {
|
|
2644
2692
|
logActivity(state, { type: "info", message: "Waiting for tunnel reconnection..." });
|
|
@@ -2648,7 +2696,9 @@ async function driveChannels(state, driver) {
|
|
|
2648
2696
|
try {
|
|
2649
2697
|
const processed = await driver.drainPending();
|
|
2650
2698
|
state.messageCount += processed;
|
|
2651
|
-
|
|
2699
|
+
const proxiedActivity = state.lastProxiedActivityAt !== lastSeenProxiedActivityAt;
|
|
2700
|
+
lastSeenProxiedActivityAt = state.lastProxiedActivityAt;
|
|
2701
|
+
if (processed > 0 || driver.hasInFlightWatchers() || proxiedActivity) {
|
|
2652
2702
|
idlePolls = 0;
|
|
2653
2703
|
if (processed > 0 && state.interactive) displayStatus(state);
|
|
2654
2704
|
} else if (state.idleTimeout !== null) {
|
|
@@ -2700,7 +2750,7 @@ async function cleanup(state) {
|
|
|
2700
2750
|
logActivity(state, { type: "info", message: "Stopped OpenCode process" });
|
|
2701
2751
|
displayStatus(state);
|
|
2702
2752
|
} else {
|
|
2703
|
-
|
|
2753
|
+
log2(state, "Stopped OpenCode process");
|
|
2704
2754
|
}
|
|
2705
2755
|
state.opencodeProcess = null;
|
|
2706
2756
|
}
|
|
@@ -2723,10 +2773,11 @@ async function run(options) {
|
|
|
2723
2773
|
running: true,
|
|
2724
2774
|
activityLog: [],
|
|
2725
2775
|
messageCount: 0,
|
|
2776
|
+
lastProxiedActivityAt: null,
|
|
2726
2777
|
authHeader: ""
|
|
2727
2778
|
};
|
|
2728
2779
|
if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {
|
|
2729
|
-
|
|
2780
|
+
log2(
|
|
2730
2781
|
state,
|
|
2731
2782
|
"Warning: No --idle-timeout set in CI environment. The runner will poll indefinitely until the job times out. Consider adding --idle-timeout 30 to avoid wasting runner minutes.",
|
|
2732
2783
|
false
|
|
@@ -2737,7 +2788,7 @@ async function run(options) {
|
|
|
2737
2788
|
logActivity(state, { type: "info", message: "Shutting down..." });
|
|
2738
2789
|
displayStatus(state);
|
|
2739
2790
|
} else {
|
|
2740
|
-
|
|
2791
|
+
log2(state, "Shutting down...");
|
|
2741
2792
|
}
|
|
2742
2793
|
await cleanup(state);
|
|
2743
2794
|
await shutdownTelemetry();
|
|
@@ -2770,7 +2821,7 @@ async function run(options) {
|
|
|
2770
2821
|
const resolved = await resolveAgentIdFromKey(state.authHeader);
|
|
2771
2822
|
if (resolved.agent_id) {
|
|
2772
2823
|
state.agentId = resolved.agent_id;
|
|
2773
|
-
|
|
2824
|
+
log2(state, `Resolved agent ID from key: ${state.agentId}`);
|
|
2774
2825
|
if (state.interactive && !state.json) {
|
|
2775
2826
|
logActivity(state, {
|
|
2776
2827
|
type: "info",
|
|
@@ -2833,17 +2884,17 @@ async function run(options) {
|
|
|
2833
2884
|
port: state.port,
|
|
2834
2885
|
interactive: state.interactive,
|
|
2835
2886
|
agentId: state.agentId,
|
|
2836
|
-
log: (message) =>
|
|
2887
|
+
log: (message) => log2(state, message)
|
|
2837
2888
|
});
|
|
2838
2889
|
state.port = oc.port;
|
|
2839
2890
|
state.opencodeProcess = oc.process;
|
|
2840
2891
|
state.opencodeVersion = oc.version;
|
|
2841
2892
|
state.opencodeConnected = oc.process !== null || oc.version !== null;
|
|
2842
|
-
const
|
|
2843
|
-
ocSpinner?.succeed(`OpenCode running on port ${state.port}${
|
|
2893
|
+
const version2 = state.opencodeVersion ? ` (v${state.opencodeVersion})` : "";
|
|
2894
|
+
ocSpinner?.succeed(`OpenCode running on port ${state.port}${version2}`);
|
|
2844
2895
|
const versionWarning = buildOpenCodeVersionWarning(state.opencodeVersion);
|
|
2845
2896
|
if (versionWarning) {
|
|
2846
|
-
|
|
2897
|
+
log2(state, versionWarning, false);
|
|
2847
2898
|
if (state.interactive && !state.json) {
|
|
2848
2899
|
logActivity(state, { type: "info", message: versionWarning });
|
|
2849
2900
|
}
|
|
@@ -2912,9 +2963,14 @@ async function run(options) {
|
|
|
2912
2963
|
logActivity(state, { type: "error", error: error2 });
|
|
2913
2964
|
if (state.interactive) displayStatus(state);
|
|
2914
2965
|
},
|
|
2915
|
-
// Web traffic is proxied transparently;
|
|
2966
|
+
// Web traffic is proxied transparently; note opencode is live and stamp
|
|
2967
|
+
// proxied activity so the idle loop treats interactive proxy use as work.
|
|
2968
|
+
// Fires per forwarded response head (incl. every SSE open) and excludes
|
|
2969
|
+
// the internal drain-ping, so an actively-used proxy keeps the timer
|
|
2970
|
+
// fresh while a lone idle SSE with no follow-up requests still ages out.
|
|
2916
2971
|
onResponse: () => {
|
|
2917
2972
|
state.opencodeConnected = true;
|
|
2973
|
+
state.lastProxiedActivityAt = Date.now();
|
|
2918
2974
|
},
|
|
2919
2975
|
// A channel message was queued and the api-worker pinged us over the
|
|
2920
2976
|
// tunnel to drain immediately instead of waiting for the next poll tick.
|
|
@@ -2953,7 +3009,7 @@ async function run(options) {
|
|
|
2953
3009
|
throw error2;
|
|
2954
3010
|
}
|
|
2955
3011
|
if (!interactive || state.json) {
|
|
2956
|
-
|
|
3012
|
+
log2(state, "Driving channel messages...");
|
|
2957
3013
|
}
|
|
2958
3014
|
await driveChannels(state, channelDriver);
|
|
2959
3015
|
await cleanup(state);
|
|
@@ -2965,7 +3021,7 @@ async function run(options) {
|
|
|
2965
3021
|
})
|
|
2966
3022
|
);
|
|
2967
3023
|
} else if (!interactive) {
|
|
2968
|
-
|
|
3024
|
+
log2(state, `Completed. Processed ${state.messageCount} message(s).`);
|
|
2969
3025
|
}
|
|
2970
3026
|
await shutdownTelemetry();
|
|
2971
3027
|
process.exit(0);
|
|
@@ -2987,8 +3043,9 @@ async function run(options) {
|
|
|
2987
3043
|
}
|
|
2988
3044
|
|
|
2989
3045
|
// src/index.ts
|
|
3046
|
+
var { version } = createRequire(import.meta.url)("../package.json");
|
|
2990
3047
|
var program = new Command();
|
|
2991
|
-
program.name("evident").description("Run OpenCode locally and connect it to Evident").version(
|
|
3048
|
+
program.name("evident").description("Run OpenCode locally and connect it to Evident").version(version).option(
|
|
2992
3049
|
"--endpoint <url>",
|
|
2993
3050
|
"Evident API base URL (default: production; e.g. http://localhost:3001)"
|
|
2994
3051
|
).option("--tunnel <url>", "Tunnel WebSocket URL (default: production; e.g. ws://localhost:8787)").hook("preAction", (thisCommand) => {
|