@evident-ai/cli 3.0.1-dev.fbf2c4d → 3.0.1-dev.fe4c93e
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 +3 -1
- package/dist/index.js +123 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,7 +86,9 @@ Options:
|
|
|
86
86
|
- `-a, --agent [id]` — Agent ID to connect to. Optional when `EVIDENT_AGENT_KEY`
|
|
87
87
|
is set (the agent is then resolved automatically from the key).
|
|
88
88
|
- `-p, --port <port>` — OpenCode port (default: `4096`).
|
|
89
|
-
-
|
|
89
|
+
- `--log-level <level>` — Log verbosity: `debug | info | warn | error` (default:
|
|
90
|
+
`info`). Env: `EVIDENT_LOG_LEVEL`.
|
|
91
|
+
- `-v, --verbose` — Alias for `--log-level debug` (an explicit `--log-level` wins).
|
|
90
92
|
- `-c, --conversation <id>` — Process only this specific conversation.
|
|
91
93
|
- `--idle-timeout <seconds>` — Exit after N seconds with no pending work (useful
|
|
92
94
|
in CI to avoid polling indefinitely).
|
package/dist/index.js
CHANGED
|
@@ -1811,6 +1811,12 @@ function messageIdOf(m) {
|
|
|
1811
1811
|
const infoId = m.info?.id;
|
|
1812
1812
|
return typeof infoId === "string" ? infoId : void 0;
|
|
1813
1813
|
}
|
|
1814
|
+
var LOG_LEVELS = {
|
|
1815
|
+
debug: 0,
|
|
1816
|
+
info: 1,
|
|
1817
|
+
warn: 2,
|
|
1818
|
+
error: 3
|
|
1819
|
+
};
|
|
1814
1820
|
var DEFAULT_RETRY_POLICY = {
|
|
1815
1821
|
maxAttempts: 6,
|
|
1816
1822
|
baseDelayMs: 500,
|
|
@@ -2193,7 +2199,7 @@ var ChannelDriver = class {
|
|
|
2193
2199
|
if (await sessionExists(this.port, sessionId) === false) {
|
|
2194
2200
|
this.sessions.delete(conv.id);
|
|
2195
2201
|
this.log({
|
|
2196
|
-
level: "
|
|
2202
|
+
level: "warn",
|
|
2197
2203
|
message: `Message ${message.id.slice(0, 8)} dispatch hit a session (${sessionId.slice(0, 8)}) that was deleted mid-dispatch (cleanup race) \u2014 deferring this and later messages for conversation ${conv.id.slice(0, 8)} to the next tick (recreated then, in order). Already-dispatched turns keep their watcher.`,
|
|
2198
2204
|
conversation_id: conv.id,
|
|
2199
2205
|
message_id: message.id
|
|
@@ -2212,7 +2218,7 @@ var ChannelDriver = class {
|
|
|
2212
2218
|
}
|
|
2213
2219
|
if (opencodeMessageId === null) {
|
|
2214
2220
|
this.log({
|
|
2215
|
-
level: "
|
|
2221
|
+
level: "warn",
|
|
2216
2222
|
message: `Message ${message.id.slice(0, 8)} dispatched but its opencode id could not be read back \u2014 leaving un-tracked to retry next tick`,
|
|
2217
2223
|
conversation_id: conv.id,
|
|
2218
2224
|
message_id: message.id
|
|
@@ -2226,7 +2232,7 @@ var ChannelDriver = class {
|
|
|
2226
2232
|
}
|
|
2227
2233
|
if (messages.length > 0 && dispatched === 0 && skippedAlreadyDispatched === messages.length) {
|
|
2228
2234
|
this.log({
|
|
2229
|
-
level: "
|
|
2235
|
+
level: "warn",
|
|
2230
2236
|
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).`,
|
|
2231
2237
|
conversation_id: conv.id
|
|
2232
2238
|
});
|
|
@@ -2240,7 +2246,7 @@ var ChannelDriver = class {
|
|
|
2240
2246
|
const exists = await sessionExists(this.port, bound);
|
|
2241
2247
|
if (exists === false) {
|
|
2242
2248
|
this.log({
|
|
2243
|
-
level: "
|
|
2249
|
+
level: "debug",
|
|
2244
2250
|
message: `OpenCode session ${bound} for conversation ${conv.id.slice(0, 8)} no longer exists (deleted or DB reset) \u2014 creating a fresh session and rebinding.`,
|
|
2245
2251
|
conversation_id: conv.id
|
|
2246
2252
|
});
|
|
@@ -2275,7 +2281,7 @@ var ChannelDriver = class {
|
|
|
2275
2281
|
this.opencodeDirectory = await getOpenCodeDirectory(this.port);
|
|
2276
2282
|
if (!this.opencodeDirectory) {
|
|
2277
2283
|
this.log({
|
|
2278
|
-
level: "
|
|
2284
|
+
level: "warn",
|
|
2279
2285
|
message: "Could not determine opencode directory (GET /path) \u2014 new sessions may not appear in opencode web"
|
|
2280
2286
|
});
|
|
2281
2287
|
}
|
|
@@ -2553,7 +2559,7 @@ var ChannelDriver = class {
|
|
|
2553
2559
|
} catch (err) {
|
|
2554
2560
|
if (err instanceof ChannelAuthError) throw err;
|
|
2555
2561
|
this.log({
|
|
2556
|
-
level: "
|
|
2562
|
+
level: "warn",
|
|
2557
2563
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} processing (will retry next tick): ${err instanceof Error ? err.message : String(err)}`,
|
|
2558
2564
|
conversation_id: conv.id,
|
|
2559
2565
|
message_id: inFlight.evidentMessageId
|
|
@@ -2563,7 +2569,7 @@ var ChannelDriver = class {
|
|
|
2563
2569
|
inFlight.started = true;
|
|
2564
2570
|
if (!claimed) {
|
|
2565
2571
|
this.log({
|
|
2566
|
-
level: "
|
|
2572
|
+
level: "debug",
|
|
2567
2573
|
message: `Message ${inFlight.evidentMessageId.slice(0, 8)} already marked processing \u2014 continuing`,
|
|
2568
2574
|
conversation_id: conv.id,
|
|
2569
2575
|
message_id: inFlight.evidentMessageId
|
|
@@ -2592,7 +2598,7 @@ var ChannelDriver = class {
|
|
|
2592
2598
|
if (err instanceof ChannelAuthError) throw err;
|
|
2593
2599
|
if (err instanceof ChannelTerminalError) {
|
|
2594
2600
|
this.log({
|
|
2595
|
-
level: "
|
|
2601
|
+
level: "warn",
|
|
2596
2602
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} done (terminal HTTP ${err.status}) \u2014 leaving for the cron safety net: ${err.message}`,
|
|
2597
2603
|
conversation_id: conv.id,
|
|
2598
2604
|
message_id: inFlight.evidentMessageId
|
|
@@ -2602,7 +2608,7 @@ var ChannelDriver = class {
|
|
|
2602
2608
|
}
|
|
2603
2609
|
if (this.now() >= inFlight.deadline) {
|
|
2604
2610
|
this.log({
|
|
2605
|
-
level: "
|
|
2611
|
+
level: "warn",
|
|
2606
2612
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} done within the watch window \u2014 leaving for the cron safety net: ${err instanceof Error ? err.message : String(err)}`,
|
|
2607
2613
|
conversation_id: conv.id,
|
|
2608
2614
|
message_id: inFlight.evidentMessageId
|
|
@@ -2611,7 +2617,7 @@ var ChannelDriver = class {
|
|
|
2611
2617
|
return;
|
|
2612
2618
|
}
|
|
2613
2619
|
this.log({
|
|
2614
|
-
level: "
|
|
2620
|
+
level: "warn",
|
|
2615
2621
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} done (will retry next tick): ${err instanceof Error ? err.message : String(err)}`,
|
|
2616
2622
|
conversation_id: conv.id,
|
|
2617
2623
|
message_id: inFlight.evidentMessageId
|
|
@@ -2639,7 +2645,7 @@ var ChannelDriver = class {
|
|
|
2639
2645
|
if (err instanceof ChannelAuthError) throw err;
|
|
2640
2646
|
if (err instanceof ChannelTerminalError) {
|
|
2641
2647
|
this.log({
|
|
2642
|
-
level: "
|
|
2648
|
+
level: "warn",
|
|
2643
2649
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} failed (terminal HTTP ${err.status}) \u2014 leaving for the cron safety net: ${err.message}`,
|
|
2644
2650
|
conversation_id: conv.id,
|
|
2645
2651
|
message_id: inFlight.evidentMessageId
|
|
@@ -2649,7 +2655,7 @@ var ChannelDriver = class {
|
|
|
2649
2655
|
}
|
|
2650
2656
|
if (this.now() >= inFlight.deadline) {
|
|
2651
2657
|
this.log({
|
|
2652
|
-
level: "
|
|
2658
|
+
level: "warn",
|
|
2653
2659
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} failed within the watch window \u2014 leaving for the cron safety net: ${err instanceof Error ? err.message : String(err)}`,
|
|
2654
2660
|
conversation_id: conv.id,
|
|
2655
2661
|
message_id: inFlight.evidentMessageId
|
|
@@ -2658,7 +2664,7 @@ var ChannelDriver = class {
|
|
|
2658
2664
|
return;
|
|
2659
2665
|
}
|
|
2660
2666
|
this.log({
|
|
2661
|
-
level: "
|
|
2667
|
+
level: "warn",
|
|
2662
2668
|
message: `Failed to mark message ${inFlight.evidentMessageId.slice(0, 8)} failed (will retry next tick): ${err instanceof Error ? err.message : String(err)}`,
|
|
2663
2669
|
conversation_id: conv.id,
|
|
2664
2670
|
message_id: inFlight.evidentMessageId
|
|
@@ -2681,7 +2687,7 @@ var ChannelDriver = class {
|
|
|
2681
2687
|
const activelyRunning = state === "running" && !awaitingHuman;
|
|
2682
2688
|
if (activelyRunning && this.now() - inFlight.processingAnchorMs >= ABSOLUTE_MAX_PROCESSING_MS) {
|
|
2683
2689
|
this.log({
|
|
2684
|
-
level: "
|
|
2690
|
+
level: "warn",
|
|
2685
2691
|
message: `Message ${inFlight.evidentMessageId.slice(0, 8)} exceeded the absolute processing ceiling (${Math.round((this.now() - inFlight.processingAnchorMs) / 6e4)}min, session ${sessionId}) while still actively running \u2014 releasing so the cron can reclaim it`,
|
|
2686
2692
|
conversation_id: conv.id,
|
|
2687
2693
|
message_id: inFlight.evidentMessageId
|
|
@@ -2724,7 +2730,7 @@ var ChannelDriver = class {
|
|
|
2724
2730
|
const queuedBehindRunningSibling = state === "queued" && hasActivelyRunningSibling;
|
|
2725
2731
|
if (!activelyRunning && !queuedBehindRunningSibling && this.now() >= inFlight.deadline) {
|
|
2726
2732
|
this.log({
|
|
2727
|
-
level: "
|
|
2733
|
+
level: "debug",
|
|
2728
2734
|
message: `Message ${inFlight.evidentMessageId.slice(0, 8)} did not complete within the watch window \u2014 leaving for the cron safety net`,
|
|
2729
2735
|
conversation_id: conv.id,
|
|
2730
2736
|
message_id: inFlight.evidentMessageId
|
|
@@ -2767,7 +2773,7 @@ var ChannelDriver = class {
|
|
|
2767
2773
|
this.readoptPollUnresolvedSignalled.delete(id);
|
|
2768
2774
|
if (cleared || clearedUndeliverable) {
|
|
2769
2775
|
this.log({
|
|
2770
|
-
level: "
|
|
2776
|
+
level: "debug",
|
|
2771
2777
|
message: `Re-adopt: message ${id.slice(0, 8)} left the processing list (cron reset) \u2014 cleared gave-up marker`,
|
|
2772
2778
|
message_id: id
|
|
2773
2779
|
});
|
|
@@ -2780,7 +2786,7 @@ var ChannelDriver = class {
|
|
|
2780
2786
|
for (const row of rows) {
|
|
2781
2787
|
if (!row.opencode_session_id) {
|
|
2782
2788
|
this.log({
|
|
2783
|
-
level: "
|
|
2789
|
+
level: "warn",
|
|
2784
2790
|
message: `Cannot re-adopt processing message ${row.id.slice(0, 8)} \u2014 no opencode session id; leaving for the cron safety net`,
|
|
2785
2791
|
conversation_id: row.conversation_id,
|
|
2786
2792
|
message_id: row.id
|
|
@@ -2797,7 +2803,7 @@ var ChannelDriver = class {
|
|
|
2797
2803
|
const res = await this.fetchImpl(`${this.opencodeBase}/session/${sessionId}/message`);
|
|
2798
2804
|
if (!res.ok) {
|
|
2799
2805
|
this.log({
|
|
2800
|
-
level: "
|
|
2806
|
+
level: "warn",
|
|
2801
2807
|
message: `Re-adopt: polling session ${sessionId.slice(0, 8)} returned HTTP ${res.status} \u2014 skipping this session this tick`
|
|
2802
2808
|
});
|
|
2803
2809
|
continue;
|
|
@@ -2805,7 +2811,7 @@ var ChannelDriver = class {
|
|
|
2805
2811
|
const body = await res.json();
|
|
2806
2812
|
if (!Array.isArray(body)) {
|
|
2807
2813
|
this.log({
|
|
2808
|
-
level: "
|
|
2814
|
+
level: "warn",
|
|
2809
2815
|
message: `Re-adopt: polling session ${sessionId.slice(0, 8)} returned a non-array message body \u2014 skipping this session this tick`
|
|
2810
2816
|
});
|
|
2811
2817
|
continue;
|
|
@@ -2813,7 +2819,7 @@ var ChannelDriver = class {
|
|
|
2813
2819
|
messages = body;
|
|
2814
2820
|
} catch (err) {
|
|
2815
2821
|
this.log({
|
|
2816
|
-
level: "
|
|
2822
|
+
level: "warn",
|
|
2817
2823
|
message: `Re-adopt: failed to poll session ${sessionId.slice(0, 8)} (will retry next drain): ${err instanceof Error ? err.message : String(err)}`
|
|
2818
2824
|
});
|
|
2819
2825
|
continue;
|
|
@@ -2846,7 +2852,7 @@ var ChannelDriver = class {
|
|
|
2846
2852
|
async readoptOne(sessionId, row, messages, sessionOngoing) {
|
|
2847
2853
|
if (this.isTracked(sessionId, row.id)) {
|
|
2848
2854
|
this.log({
|
|
2849
|
-
level: "
|
|
2855
|
+
level: "debug",
|
|
2850
2856
|
message: `Re-adopt: message ${row.id.slice(0, 8)} already tracked in-flight \u2014 skipping (owned by the watcher loop)`,
|
|
2851
2857
|
conversation_id: row.conversation_id,
|
|
2852
2858
|
message_id: row.id
|
|
@@ -2858,7 +2864,7 @@ var ChannelDriver = class {
|
|
|
2858
2864
|
if (state === "done") {
|
|
2859
2865
|
if (this.doneUndeliverable.has(row.id)) {
|
|
2860
2866
|
this.log({
|
|
2861
|
-
level: "
|
|
2867
|
+
level: "debug",
|
|
2862
2868
|
message: `Re-adopt: message ${row.id.slice(0, 8)} markDone is terminally undeliverable \u2014 left to the cron; skipping until it leaves processing`,
|
|
2863
2869
|
conversation_id: row.conversation_id,
|
|
2864
2870
|
message_id: row.id
|
|
@@ -2879,7 +2885,7 @@ var ChannelDriver = class {
|
|
|
2879
2885
|
if (err instanceof ChannelTerminalError) {
|
|
2880
2886
|
this.doneUndeliverable.add(row.id);
|
|
2881
2887
|
this.log({
|
|
2882
|
-
level: "
|
|
2888
|
+
level: "warn",
|
|
2883
2889
|
message: `Re-adopt: failed to mark message ${row.id.slice(0, 8)} done (terminal HTTP ${err.status}) \u2014 parking until it leaves processing; leaving for the cron safety net: ${err.message}`,
|
|
2884
2890
|
conversation_id: row.conversation_id,
|
|
2885
2891
|
message_id: row.id
|
|
@@ -2888,7 +2894,7 @@ var ChannelDriver = class {
|
|
|
2888
2894
|
return;
|
|
2889
2895
|
}
|
|
2890
2896
|
this.log({
|
|
2891
|
-
level: "
|
|
2897
|
+
level: "warn",
|
|
2892
2898
|
message: `Re-adopt: failed to mark message ${row.id.slice(0, 8)} done (will retry next drain): ${err instanceof Error ? err.message : String(err)}`,
|
|
2893
2899
|
conversation_id: row.conversation_id,
|
|
2894
2900
|
message_id: row.id
|
|
@@ -2914,7 +2920,7 @@ var ChannelDriver = class {
|
|
|
2914
2920
|
if (err instanceof ChannelTerminalError) {
|
|
2915
2921
|
this.doneUndeliverable.add(row.id);
|
|
2916
2922
|
this.log({
|
|
2917
|
-
level: "
|
|
2923
|
+
level: "warn",
|
|
2918
2924
|
message: `Re-adopt: failed to mark message ${row.id.slice(0, 8)} failed (terminal HTTP ${err.status}) \u2014 parking until it leaves processing; leaving for the cron safety net: ${err.message}`,
|
|
2919
2925
|
conversation_id: row.conversation_id,
|
|
2920
2926
|
message_id: row.id
|
|
@@ -2923,7 +2929,7 @@ var ChannelDriver = class {
|
|
|
2923
2929
|
return;
|
|
2924
2930
|
}
|
|
2925
2931
|
this.log({
|
|
2926
|
-
level: "
|
|
2932
|
+
level: "warn",
|
|
2927
2933
|
message: `Re-adopt: failed to mark message ${row.id.slice(0, 8)} failed (will retry next drain): ${err instanceof Error ? err.message : String(err)}`,
|
|
2928
2934
|
conversation_id: row.conversation_id,
|
|
2929
2935
|
message_id: row.id
|
|
@@ -2936,7 +2942,7 @@ var ChannelDriver = class {
|
|
|
2936
2942
|
}
|
|
2937
2943
|
if (this.dontRedispatch.has(row.id)) {
|
|
2938
2944
|
this.log({
|
|
2939
|
-
level: "
|
|
2945
|
+
level: "debug",
|
|
2940
2946
|
message: `Re-adopt: message ${row.id.slice(0, 8)} already gave up \u2014 left to the cron; skipping until it leaves processing`,
|
|
2941
2947
|
conversation_id: row.conversation_id,
|
|
2942
2948
|
message_id: row.id
|
|
@@ -2961,7 +2967,7 @@ var ChannelDriver = class {
|
|
|
2961
2967
|
}
|
|
2962
2968
|
if (ongoing === true) {
|
|
2963
2969
|
this.log({
|
|
2964
|
-
level: "
|
|
2970
|
+
level: "debug",
|
|
2965
2971
|
message: `Re-adopt: message ${row.id.slice(0, 8)} running/${shape} and session ${sessionId.slice(0, 8)} is ongoing per GET /session/status (busy/retry) \u2014 re-attaching watcher (no re-dispatch)`,
|
|
2966
2972
|
conversation_id: row.conversation_id,
|
|
2967
2973
|
message_id: row.id
|
|
@@ -2969,7 +2975,7 @@ var ChannelDriver = class {
|
|
|
2969
2975
|
} else {
|
|
2970
2976
|
if (shape === "b1") {
|
|
2971
2977
|
this.log({
|
|
2972
|
-
level: "
|
|
2978
|
+
level: "debug",
|
|
2973
2979
|
message: `Re-adopt: message ${row.id.slice(0, 8)} running/b1 but GET /session/status was unreadable (null) for session ${sessionId.slice(0, 8)} \u2014 NOT latching a b1 row on a transient status blip; leaving it un-tracked to re-evaluate on the next drain`,
|
|
2974
2980
|
conversation_id: row.conversation_id,
|
|
2975
2981
|
message_id: row.id
|
|
@@ -2981,7 +2987,7 @@ var ChannelDriver = class {
|
|
|
2981
2987
|
return;
|
|
2982
2988
|
}
|
|
2983
2989
|
this.log({
|
|
2984
|
-
level: "
|
|
2990
|
+
level: "debug",
|
|
2985
2991
|
message: `Re-adopt: message ${row.id.slice(0, 8)} running/${shape} but GET /session/status was unreadable (null) for session ${sessionId.slice(0, 8)} \u2014 falling back to the #253 preamble + descendant cross-check`,
|
|
2986
2992
|
conversation_id: row.conversation_id,
|
|
2987
2993
|
message_id: row.id
|
|
@@ -2992,7 +2998,7 @@ var ChannelDriver = class {
|
|
|
2992
2998
|
const descendantAlive = await this.isAnyDescendantSessionAlive(sessionId);
|
|
2993
2999
|
if (descendantAlive === true) {
|
|
2994
3000
|
this.log({
|
|
2995
|
-
level: "
|
|
3001
|
+
level: "debug",
|
|
2996
3002
|
message: `Re-adopt: message ${row.id.slice(0, 8)} preamble-pinned running (root ${sessionId.slice(0, 8)}) but a live descendant sub-agent session was found \u2014 treating as still running, re-attaching watcher (no re-dispatch)`,
|
|
2997
3003
|
conversation_id: row.conversation_id,
|
|
2998
3004
|
message_id: row.id
|
|
@@ -3016,7 +3022,7 @@ var ChannelDriver = class {
|
|
|
3016
3022
|
this.readopted.add(row.id);
|
|
3017
3023
|
this.ensureWatcherRunning(sessionId);
|
|
3018
3024
|
this.log({
|
|
3019
|
-
level: "
|
|
3025
|
+
level: "debug",
|
|
3020
3026
|
message: `Re-adopt: message ${row.id.slice(0, 8)} ${state} \u2014 re-attached watcher (stored id, no re-dispatch)`,
|
|
3021
3027
|
conversation_id: row.conversation_id,
|
|
3022
3028
|
message_id: row.id
|
|
@@ -3050,7 +3056,7 @@ var ChannelDriver = class {
|
|
|
3050
3056
|
async forceReadoptRun(sessionId, row) {
|
|
3051
3057
|
if (this.stopped) {
|
|
3052
3058
|
this.log({
|
|
3053
|
-
level: "
|
|
3059
|
+
level: "debug",
|
|
3054
3060
|
message: `Re-adopt: message ${row.id.slice(0, 8)} orphaned but the runner is stopping \u2014 not starting a fresh turn; leaving for restart recovery`,
|
|
3055
3061
|
conversation_id: row.conversation_id,
|
|
3056
3062
|
message_id: row.id
|
|
@@ -3059,7 +3065,7 @@ var ChannelDriver = class {
|
|
|
3059
3065
|
}
|
|
3060
3066
|
if (this.awaitingReadopt.has(row.id)) {
|
|
3061
3067
|
this.log({
|
|
3062
|
-
level: "
|
|
3068
|
+
level: "debug",
|
|
3063
3069
|
message: `Re-adopt: message ${row.id.slice(0, 8)} already has a re-dispatch awaiting read-back \u2014 skipping (at most once)`,
|
|
3064
3070
|
conversation_id: row.conversation_id,
|
|
3065
3071
|
message_id: row.id
|
|
@@ -3069,7 +3075,7 @@ var ChannelDriver = class {
|
|
|
3069
3075
|
if (this.processedAtMs(row) + this.pausedMaxWaitMs <= this.now()) {
|
|
3070
3076
|
this.dontRedispatch.add(row.id);
|
|
3071
3077
|
this.log({
|
|
3072
|
-
level: "
|
|
3078
|
+
level: "debug",
|
|
3073
3079
|
message: `Re-adopt: message ${row.id.slice(0, 8)} orphaned but its re-adopt window has already elapsed \u2014 not dispatching an unwatchable turn; parking until it leaves processing (cron will reset it)`,
|
|
3074
3080
|
conversation_id: row.conversation_id,
|
|
3075
3081
|
message_id: row.id
|
|
@@ -3098,7 +3104,7 @@ var ChannelDriver = class {
|
|
|
3098
3104
|
this.awaitingReadopt.delete(row.id);
|
|
3099
3105
|
if (err instanceof ChannelAuthError) throw err;
|
|
3100
3106
|
this.log({
|
|
3101
|
-
level: "
|
|
3107
|
+
level: "warn",
|
|
3102
3108
|
message: `Re-adopt: re-dispatch failed for message ${row.id.slice(0, 8)} (will retry next drain): ${err instanceof Error ? err.message : String(err)}`,
|
|
3103
3109
|
conversation_id: row.conversation_id,
|
|
3104
3110
|
message_id: row.id
|
|
@@ -3109,7 +3115,7 @@ var ChannelDriver = class {
|
|
|
3109
3115
|
if (ocId === null) {
|
|
3110
3116
|
this.awaitingReadopt.delete(row.id);
|
|
3111
3117
|
this.log({
|
|
3112
|
-
level: "
|
|
3118
|
+
level: "warn",
|
|
3113
3119
|
message: `Re-adopt: message ${row.id.slice(0, 8)} re-dispatched but its opencode id could not be read back \u2014 leaving un-tracked to retry next drain`,
|
|
3114
3120
|
conversation_id: row.conversation_id,
|
|
3115
3121
|
message_id: row.id
|
|
@@ -3194,7 +3200,7 @@ var ChannelDriver = class {
|
|
|
3194
3200
|
if (this.readopted.delete(evidentMessageId) && inFlight && !inFlight.done) {
|
|
3195
3201
|
this.dontRedispatch.add(evidentMessageId);
|
|
3196
3202
|
this.log({
|
|
3197
|
-
level: "
|
|
3203
|
+
level: "debug",
|
|
3198
3204
|
message: `Re-adopt: message ${evidentMessageId.slice(0, 8)} gave up \u2014 parking until it leaves the processing list (cron reset)`,
|
|
3199
3205
|
conversation_id: watcher.conv.id,
|
|
3200
3206
|
message_id: evidentMessageId
|
|
@@ -3366,13 +3372,13 @@ var ChannelDriver = class {
|
|
|
3366
3372
|
return null;
|
|
3367
3373
|
}
|
|
3368
3374
|
this.log({
|
|
3369
|
-
level: "
|
|
3375
|
+
level: "debug",
|
|
3370
3376
|
message: `Session title fetch for session ${sessionId.slice(0, 8)} (agent ${this.agentId.slice(0, 8)}) returned HTTP ${res.status} \u2014 omitting title`,
|
|
3371
3377
|
conversation_id: conversationId
|
|
3372
3378
|
});
|
|
3373
3379
|
} catch (err) {
|
|
3374
3380
|
this.log({
|
|
3375
|
-
level: "
|
|
3381
|
+
level: "debug",
|
|
3376
3382
|
message: `Best-effort session title fetch failed for session ${sessionId.slice(0, 8)} (agent ${this.agentId.slice(0, 8)}) \u2014 omitting title: ${err instanceof Error ? err.message : String(err)}`,
|
|
3377
3383
|
conversation_id: conversationId
|
|
3378
3384
|
});
|
|
@@ -3422,7 +3428,7 @@ var ChannelDriver = class {
|
|
|
3422
3428
|
const sessions = await listSessions(this.port);
|
|
3423
3429
|
if (!sessions) {
|
|
3424
3430
|
this.log({
|
|
3425
|
-
level: "
|
|
3431
|
+
level: "warn",
|
|
3426
3432
|
message: `Re-adopt: could not enumerate sessions to cross-check descendant liveness for root ${rootSessionId} (listSessions failed) \u2014 treating child liveness as indeterminate`
|
|
3427
3433
|
});
|
|
3428
3434
|
return null;
|
|
@@ -3708,7 +3714,7 @@ var ChannelDriver = class {
|
|
|
3708
3714
|
);
|
|
3709
3715
|
if (!res.ok) {
|
|
3710
3716
|
this.log({
|
|
3711
|
-
level: "
|
|
3717
|
+
level: "warn",
|
|
3712
3718
|
message: `Signal '${signal}' for message ${messageId.slice(0, 8)} returned HTTP ${res.status} (telemetry-only, ignored)`,
|
|
3713
3719
|
conversation_id: conversationId,
|
|
3714
3720
|
message_id: messageId
|
|
@@ -3718,7 +3724,7 @@ var ChannelDriver = class {
|
|
|
3718
3724
|
return true;
|
|
3719
3725
|
} catch (err) {
|
|
3720
3726
|
this.log({
|
|
3721
|
-
level: "
|
|
3727
|
+
level: "warn",
|
|
3722
3728
|
message: `Signal '${signal}' for message ${messageId.slice(0, 8)} failed (telemetry-only, ignored): ${err instanceof Error ? err.message : String(err)}`,
|
|
3723
3729
|
conversation_id: conversationId,
|
|
3724
3730
|
message_id: messageId
|
|
@@ -4062,23 +4068,53 @@ var MAX_ACTIVITY_LOG_ENTRIES = 10;
|
|
|
4062
4068
|
var CHANNEL_POLL_INTERVAL_MS = Number(process.env.EVIDENT_CHANNEL_POLL_INTERVAL_MS) || 2e3;
|
|
4063
4069
|
var CHANNEL_STUCK_QUEUED_MS = Number(process.env.EVIDENT_STUCK_QUEUED_MS) || void 0;
|
|
4064
4070
|
var SHUTDOWN_DRAIN_TIMEOUT_MS = Number(process.env.EVIDENT_SHUTDOWN_DRAIN_MS) || 25e3;
|
|
4065
|
-
function
|
|
4071
|
+
function resolveLogLevel(options) {
|
|
4072
|
+
const accepted = Object.keys(LOG_LEVELS);
|
|
4073
|
+
const validate = (value, source) => {
|
|
4074
|
+
const normalized = value.trim().toLowerCase();
|
|
4075
|
+
if (!accepted.includes(normalized)) {
|
|
4076
|
+
throw new Error(
|
|
4077
|
+
`Invalid log level "${value}"${source}; expected one of ${accepted.join(", ")}`
|
|
4078
|
+
);
|
|
4079
|
+
}
|
|
4080
|
+
return normalized;
|
|
4081
|
+
};
|
|
4082
|
+
if (options.logLevel !== void 0) {
|
|
4083
|
+
return validate(options.logLevel, " (--log-level)");
|
|
4084
|
+
}
|
|
4085
|
+
if (options.verbose) {
|
|
4086
|
+
return "debug";
|
|
4087
|
+
}
|
|
4088
|
+
const env = process.env.EVIDENT_LOG_LEVEL;
|
|
4089
|
+
if (env !== void 0 && env !== "") {
|
|
4090
|
+
return validate(env, " (EVIDENT_LOG_LEVEL)");
|
|
4091
|
+
}
|
|
4092
|
+
return "info";
|
|
4093
|
+
}
|
|
4094
|
+
function meetsThreshold(state, level) {
|
|
4095
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[state.logLevel];
|
|
4096
|
+
}
|
|
4097
|
+
function log2(state, message, level = "info") {
|
|
4098
|
+
if (!meetsThreshold(state, level)) return;
|
|
4066
4099
|
if (state.json) {
|
|
4067
4100
|
console.log(
|
|
4068
4101
|
JSON.stringify({
|
|
4069
4102
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4070
|
-
level
|
|
4103
|
+
level,
|
|
4071
4104
|
message
|
|
4072
4105
|
})
|
|
4073
4106
|
);
|
|
4074
4107
|
} else if (!state.interactive) {
|
|
4075
|
-
const prefix =
|
|
4108
|
+
const prefix = level === "error" ? chalk6.red("\u2717") : level === "warn" ? chalk6.yellow("!") : level === "debug" ? chalk6.dim("\xB7") : chalk6.green("\u2022");
|
|
4076
4109
|
console.log(`${prefix} ${message}`);
|
|
4077
4110
|
}
|
|
4078
4111
|
}
|
|
4079
4112
|
function logActivity(state, entry) {
|
|
4113
|
+
const level = entry.level ?? (entry.type === "error" ? "error" : "info");
|
|
4114
|
+
if (!meetsThreshold(state, level)) return;
|
|
4080
4115
|
const fullEntry = {
|
|
4081
4116
|
...entry,
|
|
4117
|
+
level,
|
|
4082
4118
|
timestamp: /* @__PURE__ */ new Date()
|
|
4083
4119
|
};
|
|
4084
4120
|
state.activityLog.push(fullEntry);
|
|
@@ -4087,9 +4123,9 @@ function logActivity(state, entry) {
|
|
|
4087
4123
|
}
|
|
4088
4124
|
if (!state.interactive) {
|
|
4089
4125
|
if (entry.type === "error") {
|
|
4090
|
-
log2(state, entry.error ?? "Unknown error",
|
|
4091
|
-
} else if (entry.
|
|
4092
|
-
log2(state, entry.message);
|
|
4126
|
+
log2(state, entry.error ?? "Unknown error", level);
|
|
4127
|
+
} else if (entry.message) {
|
|
4128
|
+
log2(state, entry.message, level);
|
|
4093
4129
|
}
|
|
4094
4130
|
}
|
|
4095
4131
|
}
|
|
@@ -4288,7 +4324,7 @@ function scheduleSessionCleanup(state, driver, options) {
|
|
|
4288
4324
|
process.env
|
|
4289
4325
|
);
|
|
4290
4326
|
for (const warning2 of config2.warnings) {
|
|
4291
|
-
logActivity(state, { type: "info", message: `Session cleanup: ${warning2}` });
|
|
4327
|
+
logActivity(state, { type: "info", level: "warn", message: `Session cleanup: ${warning2}` });
|
|
4292
4328
|
}
|
|
4293
4329
|
if (!config2.enabled) return;
|
|
4294
4330
|
logActivity(state, {
|
|
@@ -4360,6 +4396,20 @@ async function cleanup(state, opts = {}) {
|
|
|
4360
4396
|
}
|
|
4361
4397
|
async function run(options) {
|
|
4362
4398
|
const interactive = isInteractive(options.json);
|
|
4399
|
+
let logLevel;
|
|
4400
|
+
try {
|
|
4401
|
+
logLevel = resolveLogLevel(options);
|
|
4402
|
+
} catch (error2) {
|
|
4403
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
4404
|
+
if (options.json) {
|
|
4405
|
+
console.log(JSON.stringify({ status: "error", error: message }));
|
|
4406
|
+
} else {
|
|
4407
|
+
printError(message);
|
|
4408
|
+
}
|
|
4409
|
+
await shutdownTelemetry();
|
|
4410
|
+
process.exit(1);
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4363
4413
|
const state = {
|
|
4364
4414
|
agentId: options.agent || "",
|
|
4365
4415
|
agentName: null,
|
|
@@ -4368,6 +4418,7 @@ async function run(options) {
|
|
|
4368
4418
|
idleTimeout: options.idleTimeout ?? null,
|
|
4369
4419
|
json: options.json ?? false,
|
|
4370
4420
|
interactive,
|
|
4421
|
+
logLevel,
|
|
4371
4422
|
connected: false,
|
|
4372
4423
|
opencodeConnected: false,
|
|
4373
4424
|
opencodeVersion: null,
|
|
@@ -4385,8 +4436,8 @@ async function run(options) {
|
|
|
4385
4436
|
if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {
|
|
4386
4437
|
log2(
|
|
4387
4438
|
state,
|
|
4388
|
-
"
|
|
4389
|
-
|
|
4439
|
+
"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.",
|
|
4440
|
+
"warn"
|
|
4390
4441
|
);
|
|
4391
4442
|
}
|
|
4392
4443
|
const handleSignal = async () => {
|
|
@@ -4502,9 +4553,9 @@ async function run(options) {
|
|
|
4502
4553
|
ocSpinner?.succeed(`OpenCode running on port ${state.port}${version2}`);
|
|
4503
4554
|
const versionWarning = buildOpenCodeVersionWarning(state.opencodeVersion);
|
|
4504
4555
|
if (versionWarning) {
|
|
4505
|
-
log2(state, versionWarning,
|
|
4556
|
+
log2(state, versionWarning, "warn");
|
|
4506
4557
|
if (state.interactive && !state.json) {
|
|
4507
|
-
logActivity(state, { type: "info", message: versionWarning });
|
|
4558
|
+
logActivity(state, { type: "info", level: "warn", message: versionWarning });
|
|
4508
4559
|
}
|
|
4509
4560
|
}
|
|
4510
4561
|
} catch (error2) {
|
|
@@ -4519,11 +4570,17 @@ async function run(options) {
|
|
|
4519
4570
|
getAuthHeader: () => state.authHeader,
|
|
4520
4571
|
conversationFilter: state.conversationFilter,
|
|
4521
4572
|
stuckQueuedMs: CHANNEL_STUCK_QUEUED_MS,
|
|
4522
|
-
log: (entry) =>
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4573
|
+
log: (entry) => (
|
|
4574
|
+
// Thread the driver's real level straight through so `debug`/`warn`
|
|
4575
|
+
// survive the sink filter (they no longer collapse to info). `type`
|
|
4576
|
+
// stays the coarse error/non-error split the activity log renders with.
|
|
4577
|
+
logActivity(state, {
|
|
4578
|
+
type: entry.level === "error" ? "error" : "info",
|
|
4579
|
+
level: entry.level,
|
|
4580
|
+
message: entry.message,
|
|
4581
|
+
error: entry.level === "error" ? entry.message : void 0
|
|
4582
|
+
})
|
|
4583
|
+
)
|
|
4527
4584
|
});
|
|
4528
4585
|
state.channelDriver = channelDriver;
|
|
4529
4586
|
const connection = new RunnerConnection({
|
|
@@ -4677,7 +4734,10 @@ program.name("evident").description("Run OpenCode locally and connect it to Evid
|
|
|
4677
4734
|
program.command("login").description("Authenticate with Evident").option("--token", "Use token-based authentication (for CI/CD)").option("--no-browser", "Do not open the browser automatically").action(login);
|
|
4678
4735
|
program.command("logout").description("Remove stored credentials for the current endpoint").option("--all", "Remove stored credentials for all endpoints").action((options) => logout({ all: options.all }));
|
|
4679
4736
|
program.command("whoami").description("Show the currently logged in user").action(whoami);
|
|
4680
|
-
program.command("run").description("Connect to Evident and process messages").option("-a, --agent [id]", "Agent ID to connect to (optional when EVIDENT_AGENT_KEY is set)").option("-p, --port <port>", "OpenCode port (default: 4096)", "4096").option(
|
|
4737
|
+
program.command("run").description("Connect to Evident and process messages").option("-a, --agent [id]", "Agent ID to connect to (optional when EVIDENT_AGENT_KEY is set)").option("-p, --port <port>", "OpenCode port (default: 4096)", "4096").option(
|
|
4738
|
+
"--log-level <level>",
|
|
4739
|
+
"Log verbosity: debug | info | warn | error (default: info). Env: EVIDENT_LOG_LEVEL"
|
|
4740
|
+
).option("-v, --verbose", "Alias for --log-level debug (ignored if --log-level is set)").option("-c, --conversation <id>", "Process only this specific conversation").option("--idle-timeout <seconds>", "Exit after N seconds idle").option("--json", "Output in JSON format").option(
|
|
4681
4741
|
"--session-cleanup-max-age <duration>",
|
|
4682
4742
|
"Delete OpenCode sessions idle longer than this (e.g. 7d, 24h). Enables cleanup. Env: EVIDENT_SESSION_CLEANUP_MAX_AGE"
|
|
4683
4743
|
).option(
|
|
@@ -4691,6 +4751,9 @@ program.command("run").description("Connect to Evident and process messages").op
|
|
|
4691
4751
|
run({
|
|
4692
4752
|
agent: options.agent,
|
|
4693
4753
|
port: parseInt(options.port, 10),
|
|
4754
|
+
// Raw string — validation/precedence is single-sourced in run.ts's
|
|
4755
|
+
// resolveLogLevel (flag > -v > EVIDENT_LOG_LEVEL > info).
|
|
4756
|
+
logLevel: options.logLevel,
|
|
4694
4757
|
verbose: options.verbose,
|
|
4695
4758
|
conversation: options.conversation,
|
|
4696
4759
|
idleTimeout: options.idleTimeout ? parseInt(options.idleTimeout, 10) : void 0,
|