@evident-ai/cli 3.0.1-dev.caec964 → 3.0.1-dev.ced5d3d
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 +88 -26
- 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
|
|
@@ -470,6 +471,12 @@ import chalk6 from "chalk";
|
|
|
470
471
|
import ora3 from "ora";
|
|
471
472
|
import { select as select3 } from "@inquirer/prompts";
|
|
472
473
|
|
|
474
|
+
// ../../packages/types/src/opencode/index.ts
|
|
475
|
+
function opencodeMessageIdFor(queuedMessageId) {
|
|
476
|
+
const sanitized = queuedMessageId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
477
|
+
return `msg_${sanitized}`;
|
|
478
|
+
}
|
|
479
|
+
|
|
473
480
|
// ../../packages/types/src/telemetry/index.ts
|
|
474
481
|
var TelemetryEventTypes = {
|
|
475
482
|
// Agent activity events (shown in web UI activity log)
|
|
@@ -484,6 +491,29 @@ var TelemetryEventTypes = {
|
|
|
484
491
|
var MAX_FRAME_BYTES = 256 * 1024;
|
|
485
492
|
var TUNNEL_DRAIN_PING_PATH = "/__evident/drain";
|
|
486
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
|
+
|
|
487
517
|
// src/lib/telemetry.ts
|
|
488
518
|
var CLI_VERSION = process.env.npm_package_version || "unknown";
|
|
489
519
|
var eventBuffer = [];
|
|
@@ -686,13 +716,13 @@ async function waitForOpenCodeHealth(port, timeoutMs = 3e4) {
|
|
|
686
716
|
|
|
687
717
|
// src/lib/opencode/opencode-version-gate.ts
|
|
688
718
|
var QUEUE_VALIDATED_OPENCODE_VERSIONS = ["1.17.11"];
|
|
689
|
-
function isQueueValidatedVersion(
|
|
690
|
-
if (!
|
|
691
|
-
return QUEUE_VALIDATED_OPENCODE_VERSIONS.includes(
|
|
719
|
+
function isQueueValidatedVersion(version2) {
|
|
720
|
+
if (!version2) return false;
|
|
721
|
+
return QUEUE_VALIDATED_OPENCODE_VERSIONS.includes(version2);
|
|
692
722
|
}
|
|
693
|
-
function buildOpenCodeVersionWarning(
|
|
694
|
-
if (isQueueValidatedVersion(
|
|
695
|
-
const detected =
|
|
723
|
+
function buildOpenCodeVersionWarning(version2) {
|
|
724
|
+
if (isQueueValidatedVersion(version2)) return null;
|
|
725
|
+
const detected = version2 ? `v${version2}` : "unknown";
|
|
696
726
|
const validated = QUEUE_VALIDATED_OPENCODE_VERSIONS.map((v) => `v${v}`).join(", ");
|
|
697
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.`;
|
|
698
728
|
}
|
|
@@ -1114,9 +1144,8 @@ function messageRunState(messages, userMessageId) {
|
|
|
1114
1144
|
if (finishOf(reply) === "tool-calls") return "running";
|
|
1115
1145
|
return "done";
|
|
1116
1146
|
}
|
|
1117
|
-
function
|
|
1118
|
-
|
|
1119
|
-
return `msg_${sanitized}`;
|
|
1147
|
+
function opencodeMessageIdFor2(queuedMessageId) {
|
|
1148
|
+
return opencodeMessageIdFor(queuedMessageId);
|
|
1120
1149
|
}
|
|
1121
1150
|
|
|
1122
1151
|
// src/lib/tunnel/connection.ts
|
|
@@ -1187,12 +1216,20 @@ var StreamForwarder = class {
|
|
|
1187
1216
|
}
|
|
1188
1217
|
async handleOpen(frame) {
|
|
1189
1218
|
const { sid, method, path, headers, has_body } = frame;
|
|
1219
|
+
const correlationId = headers?.[CORRELATION_ID_HEADER];
|
|
1220
|
+
const startedAt = Date.now();
|
|
1190
1221
|
if (path === TUNNEL_DRAIN_PING_PATH) {
|
|
1191
1222
|
this.callbacks.onDrainPing?.();
|
|
1192
1223
|
this.send({ type: "head", sid, status: 204, headers: {} });
|
|
1193
1224
|
this.send({ type: "res_end", sid });
|
|
1194
1225
|
return;
|
|
1195
1226
|
}
|
|
1227
|
+
log("info", "agent_request", {
|
|
1228
|
+
correlation_id: correlationId,
|
|
1229
|
+
sid,
|
|
1230
|
+
method,
|
|
1231
|
+
path: stripQuery(path)
|
|
1232
|
+
});
|
|
1196
1233
|
const ac = new AbortController();
|
|
1197
1234
|
let bodyPromise;
|
|
1198
1235
|
let pushBody;
|
|
@@ -1239,6 +1276,12 @@ var StreamForwarder = class {
|
|
|
1239
1276
|
if (!STRIP_RES.has(key.toLowerCase())) resHeaders[key] = value;
|
|
1240
1277
|
});
|
|
1241
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
|
+
});
|
|
1242
1285
|
this.callbacks.onHead?.(sid, upstream.status);
|
|
1243
1286
|
try {
|
|
1244
1287
|
if (upstream.body) {
|
|
@@ -1669,11 +1712,13 @@ var ChannelDriver = class {
|
|
|
1669
1712
|
const sessionId = await this.ensureSession(conv);
|
|
1670
1713
|
const messages = await this.getPendingMessages(conv.id);
|
|
1671
1714
|
let dispatched = 0;
|
|
1715
|
+
let skippedAlreadyDispatched = 0;
|
|
1672
1716
|
for (const message of messages) {
|
|
1673
1717
|
if (this.dispatched.has(message.id)) {
|
|
1718
|
+
skippedAlreadyDispatched += 1;
|
|
1674
1719
|
continue;
|
|
1675
1720
|
}
|
|
1676
|
-
const opencodeMessageId =
|
|
1721
|
+
const opencodeMessageId = opencodeMessageIdFor2(message.id);
|
|
1677
1722
|
const options = {
|
|
1678
1723
|
agent: message.opencode_agent ?? void 0,
|
|
1679
1724
|
model: message.opencode_model ?? void 0
|
|
@@ -1703,6 +1748,13 @@ var ChannelDriver = class {
|
|
|
1703
1748
|
this.registerInFlight(conv, sessionId, message, opencodeMessageId);
|
|
1704
1749
|
dispatched += 1;
|
|
1705
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
|
+
}
|
|
1706
1758
|
this.ensureWatcherRunning(sessionId);
|
|
1707
1759
|
return dispatched;
|
|
1708
1760
|
}
|
|
@@ -2521,7 +2573,7 @@ async function getAgentInfo(agentId, authHeader) {
|
|
|
2521
2573
|
// src/commands/run.ts
|
|
2522
2574
|
var MAX_ACTIVITY_LOG_ENTRIES = 10;
|
|
2523
2575
|
var CHANNEL_POLL_INTERVAL_MS = Number(process.env.EVIDENT_CHANNEL_POLL_INTERVAL_MS) || 2e3;
|
|
2524
|
-
function
|
|
2576
|
+
function log2(state, message, isError = false) {
|
|
2525
2577
|
if (state.json) {
|
|
2526
2578
|
console.log(
|
|
2527
2579
|
JSON.stringify({
|
|
@@ -2546,9 +2598,9 @@ function logActivity(state, entry) {
|
|
|
2546
2598
|
}
|
|
2547
2599
|
if (!state.interactive) {
|
|
2548
2600
|
if (entry.type === "error") {
|
|
2549
|
-
|
|
2601
|
+
log2(state, entry.error ?? "Unknown error", true);
|
|
2550
2602
|
} else if (entry.type === "info" && entry.message) {
|
|
2551
|
-
|
|
2603
|
+
log2(state, entry.message);
|
|
2552
2604
|
}
|
|
2553
2605
|
}
|
|
2554
2606
|
}
|
|
@@ -2634,6 +2686,7 @@ async function handleAuthError(state, error2) {
|
|
|
2634
2686
|
}
|
|
2635
2687
|
async function driveChannels(state, driver) {
|
|
2636
2688
|
let idlePolls = 0;
|
|
2689
|
+
let lastSeenProxiedActivityAt = state.lastProxiedActivityAt;
|
|
2637
2690
|
while (state.running) {
|
|
2638
2691
|
if (state.connection?.reconnecting && state.connection.reconnectPromise) {
|
|
2639
2692
|
logActivity(state, { type: "info", message: "Waiting for tunnel reconnection..." });
|
|
@@ -2643,7 +2696,9 @@ async function driveChannels(state, driver) {
|
|
|
2643
2696
|
try {
|
|
2644
2697
|
const processed = await driver.drainPending();
|
|
2645
2698
|
state.messageCount += processed;
|
|
2646
|
-
|
|
2699
|
+
const proxiedActivity = state.lastProxiedActivityAt !== lastSeenProxiedActivityAt;
|
|
2700
|
+
lastSeenProxiedActivityAt = state.lastProxiedActivityAt;
|
|
2701
|
+
if (processed > 0 || driver.hasInFlightWatchers() || proxiedActivity) {
|
|
2647
2702
|
idlePolls = 0;
|
|
2648
2703
|
if (processed > 0 && state.interactive) displayStatus(state);
|
|
2649
2704
|
} else if (state.idleTimeout !== null) {
|
|
@@ -2695,7 +2750,7 @@ async function cleanup(state) {
|
|
|
2695
2750
|
logActivity(state, { type: "info", message: "Stopped OpenCode process" });
|
|
2696
2751
|
displayStatus(state);
|
|
2697
2752
|
} else {
|
|
2698
|
-
|
|
2753
|
+
log2(state, "Stopped OpenCode process");
|
|
2699
2754
|
}
|
|
2700
2755
|
state.opencodeProcess = null;
|
|
2701
2756
|
}
|
|
@@ -2718,10 +2773,11 @@ async function run(options) {
|
|
|
2718
2773
|
running: true,
|
|
2719
2774
|
activityLog: [],
|
|
2720
2775
|
messageCount: 0,
|
|
2776
|
+
lastProxiedActivityAt: null,
|
|
2721
2777
|
authHeader: ""
|
|
2722
2778
|
};
|
|
2723
2779
|
if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {
|
|
2724
|
-
|
|
2780
|
+
log2(
|
|
2725
2781
|
state,
|
|
2726
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.",
|
|
2727
2783
|
false
|
|
@@ -2732,7 +2788,7 @@ async function run(options) {
|
|
|
2732
2788
|
logActivity(state, { type: "info", message: "Shutting down..." });
|
|
2733
2789
|
displayStatus(state);
|
|
2734
2790
|
} else {
|
|
2735
|
-
|
|
2791
|
+
log2(state, "Shutting down...");
|
|
2736
2792
|
}
|
|
2737
2793
|
await cleanup(state);
|
|
2738
2794
|
await shutdownTelemetry();
|
|
@@ -2765,7 +2821,7 @@ async function run(options) {
|
|
|
2765
2821
|
const resolved = await resolveAgentIdFromKey(state.authHeader);
|
|
2766
2822
|
if (resolved.agent_id) {
|
|
2767
2823
|
state.agentId = resolved.agent_id;
|
|
2768
|
-
|
|
2824
|
+
log2(state, `Resolved agent ID from key: ${state.agentId}`);
|
|
2769
2825
|
if (state.interactive && !state.json) {
|
|
2770
2826
|
logActivity(state, {
|
|
2771
2827
|
type: "info",
|
|
@@ -2828,17 +2884,17 @@ async function run(options) {
|
|
|
2828
2884
|
port: state.port,
|
|
2829
2885
|
interactive: state.interactive,
|
|
2830
2886
|
agentId: state.agentId,
|
|
2831
|
-
log: (message) =>
|
|
2887
|
+
log: (message) => log2(state, message)
|
|
2832
2888
|
});
|
|
2833
2889
|
state.port = oc.port;
|
|
2834
2890
|
state.opencodeProcess = oc.process;
|
|
2835
2891
|
state.opencodeVersion = oc.version;
|
|
2836
2892
|
state.opencodeConnected = oc.process !== null || oc.version !== null;
|
|
2837
|
-
const
|
|
2838
|
-
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}`);
|
|
2839
2895
|
const versionWarning = buildOpenCodeVersionWarning(state.opencodeVersion);
|
|
2840
2896
|
if (versionWarning) {
|
|
2841
|
-
|
|
2897
|
+
log2(state, versionWarning, false);
|
|
2842
2898
|
if (state.interactive && !state.json) {
|
|
2843
2899
|
logActivity(state, { type: "info", message: versionWarning });
|
|
2844
2900
|
}
|
|
@@ -2907,9 +2963,14 @@ async function run(options) {
|
|
|
2907
2963
|
logActivity(state, { type: "error", error: error2 });
|
|
2908
2964
|
if (state.interactive) displayStatus(state);
|
|
2909
2965
|
},
|
|
2910
|
-
// 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.
|
|
2911
2971
|
onResponse: () => {
|
|
2912
2972
|
state.opencodeConnected = true;
|
|
2973
|
+
state.lastProxiedActivityAt = Date.now();
|
|
2913
2974
|
},
|
|
2914
2975
|
// A channel message was queued and the api-worker pinged us over the
|
|
2915
2976
|
// tunnel to drain immediately instead of waiting for the next poll tick.
|
|
@@ -2948,7 +3009,7 @@ async function run(options) {
|
|
|
2948
3009
|
throw error2;
|
|
2949
3010
|
}
|
|
2950
3011
|
if (!interactive || state.json) {
|
|
2951
|
-
|
|
3012
|
+
log2(state, "Driving channel messages...");
|
|
2952
3013
|
}
|
|
2953
3014
|
await driveChannels(state, channelDriver);
|
|
2954
3015
|
await cleanup(state);
|
|
@@ -2960,7 +3021,7 @@ async function run(options) {
|
|
|
2960
3021
|
})
|
|
2961
3022
|
);
|
|
2962
3023
|
} else if (!interactive) {
|
|
2963
|
-
|
|
3024
|
+
log2(state, `Completed. Processed ${state.messageCount} message(s).`);
|
|
2964
3025
|
}
|
|
2965
3026
|
await shutdownTelemetry();
|
|
2966
3027
|
process.exit(0);
|
|
@@ -2982,8 +3043,9 @@ async function run(options) {
|
|
|
2982
3043
|
}
|
|
2983
3044
|
|
|
2984
3045
|
// src/index.ts
|
|
3046
|
+
var { version } = createRequire(import.meta.url)("../package.json");
|
|
2985
3047
|
var program = new Command();
|
|
2986
|
-
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(
|
|
2987
3049
|
"--endpoint <url>",
|
|
2988
3050
|
"Evident API base URL (default: production; e.g. http://localhost:3001)"
|
|
2989
3051
|
).option("--tunnel <url>", "Tunnel WebSocket URL (default: production; e.g. ws://localhost:8787)").hook("preAction", (thisCommand) => {
|