@songsid/agend 2.1.12-beta.1 → 2.1.12-beta.2
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/agent-cli.js +36 -4
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +3 -1
- package/dist/agent-endpoint.js +7 -1
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/backend/claude-code.d.ts +2 -0
- package/dist/backend/claude-code.js +2 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/session-signals.d.ts +154 -0
- package/dist/backend/session-signals.js +430 -0
- package/dist/backend/session-signals.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +38 -1
- package/dist/channel/adapters/discord.js +131 -8
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +19 -1
- package/dist/channel/adapters/telegram.js +55 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +5 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-queue.d.ts +6 -0
- package/dist/channel/message-queue.js +21 -0
- package/dist/channel/message-queue.js.map +1 -1
- package/dist/channel/sticker-download.d.ts +14 -0
- package/dist/channel/sticker-download.js +42 -0
- package/dist/channel/sticker-download.js.map +1 -0
- package/dist/channel/tool-router.js +12 -5
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +52 -0
- package/dist/cli-flags.d.ts +8 -0
- package/dist/cli-flags.js +22 -0
- package/dist/cli-flags.js.map +1 -0
- package/dist/config-validator.js +25 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +20 -0
- package/dist/daemon.js +155 -3
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +8 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/event-loop-watch.d.ts +25 -0
- package/dist/event-loop-watch.js +40 -0
- package/dist/event-loop-watch.js.map +1 -0
- package/dist/fleet-manager.d.ts +38 -3
- package/dist/fleet-manager.js +248 -12
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +4 -2
- package/dist/locale.js +4 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-schemas.d.ts +15 -1
- package/dist/outbound-schemas.js +19 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/tool-permissions.js +8 -1
- package/dist/tool-permissions.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +7 -0
- package/dist/turn-reply-guard.js +11 -0
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/turn-resume.d.ts +80 -0
- package/dist/turn-resume.js +217 -0
- package/dist/turn-resume.js.map +1 -0
- package/dist/ui/view.html +8 -2
- package/dist/usage/format-rich.js +6 -1
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/i18n.d.ts +2 -0
- package/dist/usage/i18n.js +14 -1
- package/dist/usage/i18n.js.map +1 -1
- package/dist/usage/providers.d.ts +10 -0
- package/dist/usage/providers.js +2 -0
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/usage-api.d.ts +9 -0
- package/dist/usage/usage-api.js +31 -2
- package/dist/usage/usage-api.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection-signal seam: the shared base for #1209 / #1217a / #1210 / #1215.
|
|
3
|
+
*
|
|
4
|
+
* A read-only, query-only observation layer answering ONE question without
|
|
5
|
+
* pane pixels: did the CLI itself re-engage a turn since the checkpoint
|
|
6
|
+
* (double-drive guard)? Per-backend adapters discover the workspace's session
|
|
7
|
+
* in the CLI's own session store and produce a `TurnFingerprint`; the
|
|
8
|
+
* backend-agnostic `compareFingerprints` diffs a pre-action checkpoint
|
|
9
|
+
* against a post-action read.
|
|
10
|
+
*
|
|
11
|
+
* RED LINE: this seam never touches the idle/busy state machine.
|
|
12
|
+
* `readinessFromStore` always returns `unknown` — the pane stays the
|
|
13
|
+
* busyness authority, exactly as today. Nothing here drives, resumes, or
|
|
14
|
+
* writes any CLI state; every read is out-of-band and defensive (an absent
|
|
15
|
+
* field is null, never an exception).
|
|
16
|
+
*
|
|
17
|
+
* SYNC I/O WARNING: every read below is synchronous blocking file/database
|
|
18
|
+
* I/O. Never resolve fingerprints on the fleet event loop or inside a tool
|
|
19
|
+
* handler — use a bounded worker context.
|
|
20
|
+
*
|
|
21
|
+
* What counts as re-engagement: a new TURN, not a store write. CLIs
|
|
22
|
+
* bookkeep without turns (claude `cost-state`/`ai-title`, codex threads-row
|
|
23
|
+
* touches, muse `session.workspace_branch.observed`), so both the mtime and
|
|
24
|
+
* the tail path are gated on turn-shaped journal entries (`isTurnKind`):
|
|
25
|
+
* file mtime is recorded for grace bookkeeping but never drives the verdict
|
|
26
|
+
* alone. Kinds this seam does not recognise default to bookkeeping — a new
|
|
27
|
+
* turn vocabulary delays detection to the next recognised write instead of
|
|
28
|
+
* fabricating or blocking on it.
|
|
29
|
+
*
|
|
30
|
+
* Daemon exclusion covers BOTH paths: the daemon's own action (e.g. a resume)
|
|
31
|
+
* writes tail entries too, so a turn tail counts only past
|
|
32
|
+
* `max(before.tail, daemonCausedMtimeMs) + tailSkewMs`. The skew (default 2s:
|
|
33
|
+
* filesystem timestamp granularity plus entry-ts vs flush-mtime reorder —
|
|
34
|
+
* a live codex tail was observed 2ms AFTER its row mtime) keeps a
|
|
35
|
+
* daemon-caused tail from reading as someone else's turn.
|
|
36
|
+
*
|
|
37
|
+
* Tail-timestamp fields were verified against live stores, not assumed:
|
|
38
|
+
* - claude-code 2.1.289 transcript JSONL: user/assistant/system entries carry
|
|
39
|
+
* ISO `timestamp`, but the tail is usually bookkeeping (`cost-state`,
|
|
40
|
+
* `last-prompt`, `mode`, `ai-title`, …) with NO timestamp — so the reader
|
|
41
|
+
* scans backwards for the newest timestamped TURN entry instead of taking
|
|
42
|
+
* the last line.
|
|
43
|
+
* - codex rollout JSONL: every line of a lived-in 53k-line rollout carries
|
|
44
|
+
* top-level ISO `timestamp`; `type` + `payload.type` name the kind
|
|
45
|
+
* (`response_item:message`, `event_msg:task_started`, `turn_context`,
|
|
46
|
+
* `token_usage_record`, …). threads row verified with `updated_at_ms` /
|
|
47
|
+
* `recency_at_ms` epoch millis.
|
|
48
|
+
* - muse 1.4.x `session.jsonl`: entries carry NO `timestamp` at all — time is
|
|
49
|
+
* `recorded_at` in epoch MICROseconds, kind is `payload_type` (plus inner
|
|
50
|
+
* `payload.kind` for the `runtime.session` envelope: `task`/`run` are the
|
|
51
|
+
* turn frames, surveyed live over 49k lines); the first line is a
|
|
52
|
+
* `retained_frame` wrapper with neither.
|
|
53
|
+
*
|
|
54
|
+
* Flush grace and its residual: a CLI that just re-engaged may not have
|
|
55
|
+
* flushed its store yet, so a checkpoint taken too early reads `quiet` for a
|
|
56
|
+
* live turn. Inside `flushGraceMs` after the daemon's own write the seam
|
|
57
|
+
* answers `unknown` instead of `quiet`. Residual, by design and bounded: a
|
|
58
|
+
* re-engagement that flushes after this compare is caught by the NEXT
|
|
59
|
+
* checkpoint compare (at most one grace period of delayed detection, never a
|
|
60
|
+
* fabricated verdict). A re-engagement that never writes to the session store
|
|
61
|
+
* is invisible to this seam. Callers MUST re-compare across checkpoints; a
|
|
62
|
+
* single `quiet` inside the grace window must never authorize driving.
|
|
63
|
+
*
|
|
64
|
+
* kiro-classic `data.sqlite3` and KAS are deliberately NOT covered here: the
|
|
65
|
+
* classic schema needs its own round (see #1210) and the spike's KAS field
|
|
66
|
+
* assumptions were never verified against a live store.
|
|
67
|
+
*/
|
|
68
|
+
import { closeSync, openSync, readFileSync, readSync, readdirSync, statSync } from "node:fs";
|
|
69
|
+
import { join } from "node:path";
|
|
70
|
+
import { claudeProjectKey } from "./claude-code.js";
|
|
71
|
+
import { findExactCwdCodexSession, openCodexStateReadonly, rolloutRecordsTurn } from "./codex-session-lookup.js";
|
|
72
|
+
import { museSessionCwd, museSessionDirs } from "./muse.js";
|
|
73
|
+
/**
|
|
74
|
+
* How long after the daemon's own store write a `quiet` read is untrustworthy.
|
|
75
|
+
* 10 s matches the transcript-marker wait bound (#758): a journal flush lands
|
|
76
|
+
* well inside it, while the window stays short enough to schedule around.
|
|
77
|
+
*/
|
|
78
|
+
export const DEFAULT_FLUSH_GRACE_MS = 10_000;
|
|
79
|
+
/**
|
|
80
|
+
* Entry-ts vs daemon-mtime skew bound (ms). A daemon-caused tail must clear
|
|
81
|
+
* the daemon's own mtime by more than this to count as someone else's turn.
|
|
82
|
+
*/
|
|
83
|
+
export const DEFAULT_TAIL_SKEW_MS = 2_000;
|
|
84
|
+
/** Epoch microseconds at or above this are muse `recorded_at`, not millis. */
|
|
85
|
+
const MICROSECONDS_FLOOR = 1e14;
|
|
86
|
+
/**
|
|
87
|
+
* Parse an ISO instant, epoch millis, or epoch micros (muse `recorded_at`);
|
|
88
|
+
* anything else is null. Numbers below the micros floor pass through as
|
|
89
|
+
* millis; what no tailed store emits (e.g. epoch seconds) is out of scope.
|
|
90
|
+
*/
|
|
91
|
+
export function asTimestampMs(v) {
|
|
92
|
+
if (typeof v === "number") {
|
|
93
|
+
if (!Number.isFinite(v))
|
|
94
|
+
return null;
|
|
95
|
+
return v >= MICROSECONDS_FLOOR ? v / 1000 : v;
|
|
96
|
+
}
|
|
97
|
+
if (typeof v === "string") {
|
|
98
|
+
const ms = Date.parse(v);
|
|
99
|
+
return Number.isFinite(ms) ? ms : null;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
function str(v) {
|
|
104
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Best-effort kind of one journal entry across the three store shapes:
|
|
108
|
+
* claude `type`/`subtype`, codex `type` + `payload.type`, muse `payload_type`
|
|
109
|
+
* (+ inner `payload.kind` for the `runtime.session` envelope).
|
|
110
|
+
*/
|
|
111
|
+
export function entryKind(entry) {
|
|
112
|
+
const payload = entry.payload;
|
|
113
|
+
const payloadObj = payload && typeof payload === "object" && !Array.isArray(payload)
|
|
114
|
+
? payload
|
|
115
|
+
: null;
|
|
116
|
+
const base = str(entry.type) ?? str(entry.kind) ?? str(entry.payload_type)
|
|
117
|
+
?? str(payloadObj?.type) ?? str(payloadObj?.payload_type) ?? str(payloadObj?.kind);
|
|
118
|
+
if (!base)
|
|
119
|
+
return null;
|
|
120
|
+
const detail = str(entry.subtype) ?? str(payloadObj?.kind) ?? str(entry.payload_type)
|
|
121
|
+
?? str(payloadObj?.type) ?? str(payloadObj?.payload_type);
|
|
122
|
+
return detail && detail !== base ? `${base}:${detail}` : base;
|
|
123
|
+
}
|
|
124
|
+
/** Newest timestamp one journal entry carries across the three store shapes. */
|
|
125
|
+
export function entryTimestampMs(entry) {
|
|
126
|
+
return asTimestampMs(entry.recorded_at ?? entry.timestamp ?? entry.time ?? entry.createdAt ?? entry.lastModifiedAt);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Whether a tail kind proves a turn ran (as opposed to CLI bookkeeping).
|
|
130
|
+
* Unrecognised kinds default to bookkeeping: a new turn vocabulary delays
|
|
131
|
+
* detection instead of blocking legitimate resumes on false positives.
|
|
132
|
+
*/
|
|
133
|
+
export function isTurnKind(backend, kind) {
|
|
134
|
+
if (!kind)
|
|
135
|
+
return false;
|
|
136
|
+
if (backend === "claude")
|
|
137
|
+
return kind === "user" || kind === "assistant";
|
|
138
|
+
if (backend === "codex") {
|
|
139
|
+
return kind === "response_item" || kind.startsWith("response_item:")
|
|
140
|
+
|| kind.startsWith("event_msg:task_");
|
|
141
|
+
}
|
|
142
|
+
if (kind === "command.invoked" || kind === "session.resumed")
|
|
143
|
+
return true;
|
|
144
|
+
if (kind.startsWith("runtime.user_intent."))
|
|
145
|
+
return true;
|
|
146
|
+
if (kind.startsWith("tool_batch.effect."))
|
|
147
|
+
return true;
|
|
148
|
+
return kind === "runtime.session.task" || kind === "runtime.session.task_source_committed"
|
|
149
|
+
|| kind === "runtime.session:task" || kind === "runtime.session:run";
|
|
150
|
+
}
|
|
151
|
+
/** Bytes scanned back from the end of a journal looking for tail entries. */
|
|
152
|
+
const TAIL_SCAN_BYTES = 1024 * 1024;
|
|
153
|
+
/**
|
|
154
|
+
* Read-only tail of a JSONL journal: the newest `want` parseable entries
|
|
155
|
+
* within the last 1 MB, newest first. A truncated line at the window edge or
|
|
156
|
+
* a corrupt line is skipped, never fatal. Windowed by design: when the tail
|
|
157
|
+
* itself is one entry larger than the window, the read still returns the
|
|
158
|
+
* file mtime with an empty entry list (detection delayed, never fabricated).
|
|
159
|
+
* Synchronous blocking I/O — see the module warning.
|
|
160
|
+
*/
|
|
161
|
+
export function readJsonlTailEntries(path, want = 8) {
|
|
162
|
+
if (!(want >= 1))
|
|
163
|
+
want = 1;
|
|
164
|
+
try {
|
|
165
|
+
const st = statSync(path);
|
|
166
|
+
if (!st.isFile())
|
|
167
|
+
return null;
|
|
168
|
+
const window = Math.min(st.size, TAIL_SCAN_BYTES);
|
|
169
|
+
const buf = Buffer.alloc(window);
|
|
170
|
+
const fd = openSync(path, "r");
|
|
171
|
+
try {
|
|
172
|
+
readSync(fd, buf, 0, window, st.size - window);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
try {
|
|
176
|
+
closeSync(fd);
|
|
177
|
+
}
|
|
178
|
+
catch { /* already closed */ }
|
|
179
|
+
}
|
|
180
|
+
const lines = buf.toString("utf8").split("\n");
|
|
181
|
+
const entries = [];
|
|
182
|
+
for (let i = lines.length - 1; i >= 0 && entries.length < want; i--) {
|
|
183
|
+
const line = lines[i].trim();
|
|
184
|
+
if (!line)
|
|
185
|
+
continue;
|
|
186
|
+
try {
|
|
187
|
+
const parsed = JSON.parse(line);
|
|
188
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
189
|
+
entries.push(parsed);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch { /* partial line at the window edge or corrupt: skip */ }
|
|
193
|
+
}
|
|
194
|
+
return { entries, mtimeMs: st.mtimeMs };
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Newest timestamped TURN entry of a tail: skips timestamp-less bookkeeping
|
|
202
|
+
* (claude `cost-state`/`last-prompt`, muse `retained_frame`) AND timestamped
|
|
203
|
+
* non-turn writes (codex `token_count`, muse `workspace_branch.observed`).
|
|
204
|
+
* Null when no turn entry carries time.
|
|
205
|
+
*/
|
|
206
|
+
export function tailEvidence(entries, backend) {
|
|
207
|
+
for (const entry of entries) {
|
|
208
|
+
const kind = entryKind(entry);
|
|
209
|
+
if (!isTurnKind(backend, kind))
|
|
210
|
+
continue;
|
|
211
|
+
const timestampMs = entryTimestampMs(entry);
|
|
212
|
+
if (timestampMs !== null)
|
|
213
|
+
return { timestampMs, kind };
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Backend-agnostic re-engagement verdict. A changed session id means the
|
|
219
|
+
* store now belongs to a different conversation (feeds #1217a). Otherwise
|
|
220
|
+
* only a TURN-tail advance past the daemon's own writes (plus skew) means
|
|
221
|
+
* the CLI wrote on its own — plain mtime movement is bookkeeping until a
|
|
222
|
+
* turn entry says otherwise. Inside the flush-grace window after a daemon
|
|
223
|
+
* write, `quiet` is withheld as `unknown` (see module doc).
|
|
224
|
+
*/
|
|
225
|
+
export function compareFingerprints(before, after, options = {}) {
|
|
226
|
+
if (!before || !after || before.storeMtimeMs < 0 || after.storeMtimeMs < 0)
|
|
227
|
+
return "unknown";
|
|
228
|
+
if (before.sessionId && after.sessionId && before.sessionId !== after.sessionId)
|
|
229
|
+
return "reengaged";
|
|
230
|
+
const daemonCausedMtimeMs = options.daemonCausedMtimeMs ?? -1;
|
|
231
|
+
const tailSkewMs = Math.max(0, options.tailSkewMs ?? DEFAULT_TAIL_SKEW_MS);
|
|
232
|
+
const afterTail = after.tailTimestampMs;
|
|
233
|
+
const pastBefore = afterTail !== null
|
|
234
|
+
&& (before.tailTimestampMs === null || afterTail > before.tailTimestampMs);
|
|
235
|
+
const pastDaemon = afterTail !== null
|
|
236
|
+
&& (daemonCausedMtimeMs < 0 || afterTail > daemonCausedMtimeMs + tailSkewMs);
|
|
237
|
+
if (pastBefore && pastDaemon)
|
|
238
|
+
return "reengaged";
|
|
239
|
+
if (daemonCausedMtimeMs >= 0) {
|
|
240
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
241
|
+
const flushGraceMs = options.flushGraceMs ?? DEFAULT_FLUSH_GRACE_MS;
|
|
242
|
+
if (nowMs - daemonCausedMtimeMs <= flushGraceMs)
|
|
243
|
+
return "unknown";
|
|
244
|
+
}
|
|
245
|
+
return "quiet";
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Store-corroborated busyness, by design always unknown: append-only journals
|
|
249
|
+
* carry no verified completion semantics, so a store alone cannot say "busy"
|
|
250
|
+
* vs "ready" — it can only say "wrote recently". The pane stays authoritative;
|
|
251
|
+
* this seam MUST NOT feed the idle/busy state machine.
|
|
252
|
+
*/
|
|
253
|
+
export function readinessFromStore(_fp) {
|
|
254
|
+
return {
|
|
255
|
+
readiness: "unknown",
|
|
256
|
+
reason: "append-only journal without verified completion entries; pane stays authoritative",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Newest `<sessionId>.jsonl` of `~/.claude/projects/<key>/` plus its newest
|
|
261
|
+
* timestamped TURN tail entry. The session id is discovered from the store,
|
|
262
|
+
* never caller-supplied, so a conversation switch surfaces as an id change.
|
|
263
|
+
*/
|
|
264
|
+
export function claudeFingerprint(r) {
|
|
265
|
+
const dir = join(r.configDir, "projects", claudeProjectKey(r.cwd));
|
|
266
|
+
let names;
|
|
267
|
+
try {
|
|
268
|
+
names = readdirSync(dir);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
let bestFile = null;
|
|
274
|
+
let bestMtime = -1;
|
|
275
|
+
for (const name of names) {
|
|
276
|
+
if (!name.endsWith(".jsonl"))
|
|
277
|
+
continue;
|
|
278
|
+
try {
|
|
279
|
+
const m = statSync(join(dir, name)).mtimeMs;
|
|
280
|
+
if (m > bestMtime) {
|
|
281
|
+
bestMtime = m;
|
|
282
|
+
bestFile = name;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch { /* raced with deletion */ }
|
|
286
|
+
}
|
|
287
|
+
if (!bestFile)
|
|
288
|
+
return null;
|
|
289
|
+
const tail = readJsonlTailEntries(join(dir, bestFile));
|
|
290
|
+
const evidence = tail && tailEvidence(tail.entries, "claude");
|
|
291
|
+
return {
|
|
292
|
+
sessionId: bestFile.slice(0, -".jsonl".length),
|
|
293
|
+
storeMtimeMs: tail?.mtimeMs ?? bestMtime,
|
|
294
|
+
tailTimestampMs: evidence?.timestampMs ?? null,
|
|
295
|
+
tailKind: evidence?.kind ?? null,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* The exact-cwd session from `state_5.sqlite` (same lookup as #984: newest
|
|
300
|
+
* interactive thread of this directory, never `--last`), then its threads
|
|
301
|
+
* row (`updated_at_ms`/`recency_at_ms`) plus rollout tail. The database is
|
|
302
|
+
* opened read-only (never created, checkpointed, or migrated); an unknown
|
|
303
|
+
* session or a schema that no longer matches is null (unknown), never a
|
|
304
|
+
* guess. The session id is discovered from the store, never caller-supplied.
|
|
305
|
+
*/
|
|
306
|
+
export function codexFingerprint(r) {
|
|
307
|
+
const openDb = r.openDb ?? ((path) => openCodexStateReadonly(path));
|
|
308
|
+
const rolloutTail = r.rolloutTail ?? ((path) => readJsonlTailEntries(path));
|
|
309
|
+
const rolloutHasTurn = r.rolloutHasTurn ?? rolloutRecordsTurn;
|
|
310
|
+
const discoveryOpen = (path) => {
|
|
311
|
+
let db = null;
|
|
312
|
+
try {
|
|
313
|
+
db = openDb(path);
|
|
314
|
+
}
|
|
315
|
+
catch { /* fall through to throw */ }
|
|
316
|
+
if (!db)
|
|
317
|
+
throw new Error(`codex state unreadable: ${path}`);
|
|
318
|
+
return db;
|
|
319
|
+
};
|
|
320
|
+
let sessionId;
|
|
321
|
+
try {
|
|
322
|
+
const lookup = findExactCwdCodexSession(r.stateDbPath, r.cwd, discoveryOpen, rolloutHasTurn);
|
|
323
|
+
if (lookup.kind !== "found")
|
|
324
|
+
return null;
|
|
325
|
+
sessionId = lookup.id;
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
let db = null;
|
|
331
|
+
try {
|
|
332
|
+
try {
|
|
333
|
+
db = openDb(r.stateDbPath);
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
if (!db)
|
|
339
|
+
return null;
|
|
340
|
+
const row = db.prepare("SELECT updated_at_ms, recency_at_ms, rollout_path FROM threads WHERE id = ?").get(sessionId);
|
|
341
|
+
if (!row)
|
|
342
|
+
return null;
|
|
343
|
+
let tailTimestampMs = null;
|
|
344
|
+
let tailKind = null;
|
|
345
|
+
let fileMtime = -1;
|
|
346
|
+
if (typeof row.rollout_path === "string") {
|
|
347
|
+
const tail = rolloutTail(row.rollout_path);
|
|
348
|
+
if (tail) {
|
|
349
|
+
fileMtime = tail.mtimeMs;
|
|
350
|
+
const evidence = tailEvidence(tail.entries, "codex");
|
|
351
|
+
tailTimestampMs = evidence?.timestampMs ?? null;
|
|
352
|
+
tailKind = evidence?.kind ?? null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const storeMtimeMs = Math.max(typeof row.updated_at_ms === "number" ? row.updated_at_ms : -1, typeof row.recency_at_ms === "number" ? row.recency_at_ms : -1, fileMtime);
|
|
356
|
+
return storeMtimeMs < 0
|
|
357
|
+
? null
|
|
358
|
+
: { sessionId, storeMtimeMs, tailTimestampMs, tailKind };
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
finally {
|
|
364
|
+
try {
|
|
365
|
+
db?.close();
|
|
366
|
+
}
|
|
367
|
+
catch { /* already closed */ }
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/** Session-id pattern, mirroring muse.ts (MuseBackend session ids are UUIDs). */
|
|
371
|
+
const MUSE_SESSION_ID_RE = /^[0-9a-fA-F-]{8,}$/;
|
|
372
|
+
/** Log head scanned for the workspace marker, mirroring muse.ts. */
|
|
373
|
+
const MUSE_SESSION_HEAD_BYTES = 65_536;
|
|
374
|
+
/**
|
|
375
|
+
* The most recently active session started in this working directory,
|
|
376
|
+
* mirroring MuseBackend.getSessionId (workspace read out of each session's
|
|
377
|
+
* own log, activity = newest inner-file mtime), plus its newest timestamped
|
|
378
|
+
* TURN tail entry. The session id is discovered from the store, never
|
|
379
|
+
* caller-supplied, so a conversation switch surfaces as an id change.
|
|
380
|
+
*/
|
|
381
|
+
export function museFingerprint(r) {
|
|
382
|
+
if (!r.cwd)
|
|
383
|
+
return null;
|
|
384
|
+
let bestId = null;
|
|
385
|
+
let bestDir = "";
|
|
386
|
+
let bestActivity = -1;
|
|
387
|
+
for (const sessionDir of museSessionDirs(r.sessionsRoot)) {
|
|
388
|
+
const name = sessionDir.slice(sessionDir.lastIndexOf("/") + 1);
|
|
389
|
+
if (!MUSE_SESSION_ID_RE.test(name))
|
|
390
|
+
continue;
|
|
391
|
+
let head;
|
|
392
|
+
try {
|
|
393
|
+
head = readFileSync(join(sessionDir, "session.jsonl"), { encoding: "utf-8", flag: "r" })
|
|
394
|
+
.slice(0, MUSE_SESSION_HEAD_BYTES);
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (museSessionCwd(head) !== r.cwd)
|
|
400
|
+
continue;
|
|
401
|
+
let activity = -1;
|
|
402
|
+
try {
|
|
403
|
+
for (const f of readdirSync(sessionDir)) {
|
|
404
|
+
try {
|
|
405
|
+
const m = statSync(join(sessionDir, f)).mtimeMs;
|
|
406
|
+
if (m > activity)
|
|
407
|
+
activity = m;
|
|
408
|
+
}
|
|
409
|
+
catch { /* raced with deletion */ }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch { /* unreadable */ }
|
|
413
|
+
if (activity > bestActivity) {
|
|
414
|
+
bestActivity = activity;
|
|
415
|
+
bestId = name;
|
|
416
|
+
bestDir = sessionDir;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (!bestId)
|
|
420
|
+
return null;
|
|
421
|
+
const tail = readJsonlTailEntries(join(bestDir, "session.jsonl"));
|
|
422
|
+
const evidence = tail && tailEvidence(tail.entries, "muse");
|
|
423
|
+
return {
|
|
424
|
+
sessionId: bestId,
|
|
425
|
+
storeMtimeMs: bestActivity,
|
|
426
|
+
tailTimestampMs: evidence?.timestampMs ?? null,
|
|
427
|
+
tailKind: evidence?.kind ?? null,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
//# sourceMappingURL=session-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-signals.js","sourceRoot":"","sources":["../../src/backend/session-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { Client, ActionRowBuilder, ButtonBuilder } from "discord.js";
|
|
3
|
-
import type { ChannelAdapter, ApprovalHandle, SendOpts, SentMessage, PermissionPrompt, Choice, AlertData, AdapterHealthSnapshot, TopicPresence } from "../types.js";
|
|
3
|
+
import type { ChannelAdapter, ApprovalHandle, SendOpts, SentMessage, PermissionPrompt, Choice, AlertData, AdapterHealthSnapshot, TopicPresence, StickerInfo, StickerList, StickerPreview, StickerTarget } from "../types.js";
|
|
4
4
|
import type { AccessManager } from "../access-manager.js";
|
|
5
5
|
/** Curated ClassicBot backends for Discord's native slash-option dropdown. */
|
|
6
6
|
export declare const DISCORD_START_BACKEND_CHOICES: readonly [{
|
|
@@ -129,6 +129,24 @@ export declare class DiscordAdapter extends EventEmitter implements ChannelAdapt
|
|
|
129
129
|
private startGatewayWatchdog;
|
|
130
130
|
private checkGatewayLiveness;
|
|
131
131
|
getHealthSnapshot(): AdapterHealthSnapshot;
|
|
132
|
+
/**
|
|
133
|
+
* #1231: how late a slash command was by the time it was acknowledged.
|
|
134
|
+
* `createdTimestamp` is Discord's clock (the interaction's snowflake), so
|
|
135
|
+
* "age" also carries clock skew; the defer's own round trip is local. Over
|
|
136
|
+
* half the 3 s window is worth a line: it says whether the time went in
|
|
137
|
+
* delivery (gateway, a blocked event loop) or in the acknowledgement (REST).
|
|
138
|
+
*/
|
|
139
|
+
private noteSlashAckTiming;
|
|
140
|
+
/**
|
|
141
|
+
* #1231: a slash command whose acknowledgement failed. It is NOT run: the
|
|
142
|
+
* user was shown "did not respond" (or will be) and may well run it again,
|
|
143
|
+
* so running it now could do it twice. Already acknowledged (40060) means
|
|
144
|
+
* another session of this bot answered it — that one handles the command,
|
|
145
|
+
* so stay silent. Otherwise say so where the user can see it: a private
|
|
146
|
+
* follow-up when the acknowledgement did land after all, else a message in
|
|
147
|
+
* the channel, never a silent drop.
|
|
148
|
+
*/
|
|
149
|
+
private reportSlashDeferFailure;
|
|
132
150
|
/**
|
|
133
151
|
* Update the bot's profile activity without touching any channel messages.
|
|
134
152
|
* Presence is deliberately best-effort: a reconnecting or not-yet-ready
|
|
@@ -171,6 +189,25 @@ export declare class DiscordAdapter extends EventEmitter implements ChannelAdapt
|
|
|
171
189
|
animated: boolean;
|
|
172
190
|
available: boolean;
|
|
173
191
|
}>>;
|
|
192
|
+
/**
|
|
193
|
+
* The server a channel belongs to (#1226): stickers are per server, and a bot can send only the stickers of the
|
|
194
|
+
* server it posts in. In the channels topology `chatId` can be the server id itself; that is the answer then.
|
|
195
|
+
*/
|
|
196
|
+
private guildOfChannel;
|
|
197
|
+
/**
|
|
198
|
+
* The stickers of the server `target`'s channel is in (#1226) — the only ones this bot can send there. Discord's
|
|
199
|
+
* standard sticker packs are not listed (they are hundreds, and not what an agent picks from).
|
|
200
|
+
*/
|
|
201
|
+
listStickers(target: StickerTarget): Promise<StickerList>;
|
|
202
|
+
/** A still picture of a listed sticker, from Discord's media CDN; null for a Lottie sticker (no still image). */
|
|
203
|
+
fetchStickerPreview(sticker: StickerInfo): Promise<StickerPreview | null>;
|
|
204
|
+
/**
|
|
205
|
+
* Stickers on one message (#1226): with the text's last chunk when there is text (Discord sends both together),
|
|
206
|
+
* alone otherwise. Earlier chunks of a long text go first, as plain messages.
|
|
207
|
+
*/
|
|
208
|
+
sendStickers(chatId: string, stickers: string[], opts?: SendOpts & {
|
|
209
|
+
text?: string;
|
|
210
|
+
}): Promise<SentMessage>;
|
|
174
211
|
/**
|
|
175
212
|
* The servers this bot is a member of, primary first (#1021). A bot can
|
|
176
213
|
* react with a custom emoji from any server it is in, so these are where
|