agent-coord-mcp 0.26.18 → 0.26.20
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 +82 -0
- package/dist/build.js +113 -0
- package/dist/build.js.map +1 -0
- package/dist/capabilities.js +214 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/prefix.js +64 -0
- package/dist/prefix.js.map +1 -0
- package/dist/roles.js +132 -0
- package/dist/roles.js.map +1 -0
- package/dist/server-identity.js +82 -0
- package/dist/server-identity.js.map +1 -0
- package/dist/server.js +668 -0
- package/dist/server.js.map +1 -0
- package/dist/store.js +553 -0
- package/dist/store.js.map +1 -0
- package/dist/tools/admin.js +323 -0
- package/dist/tools/admin.js.map +1 -0
- package/dist/tools/attention.js +73 -0
- package/dist/tools/attention.js.map +1 -0
- package/dist/tools/away.js +285 -0
- package/dist/tools/away.js.map +1 -0
- package/dist/tools/board-ref.js +208 -0
- package/dist/tools/board-ref.js.map +1 -0
- package/dist/tools/event-kinds.js +39 -0
- package/dist/tools/event-kinds.js.map +1 -0
- package/dist/tools/events.js +234 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/logwatch.js +85 -0
- package/dist/tools/logwatch.js.map +1 -0
- package/dist/tools/messaging.js +706 -0
- package/dist/tools/messaging.js.map +1 -0
- package/dist/tools/record-events.js +380 -0
- package/dist/tools/record-events.js.map +1 -0
- package/dist/tools/records.js +1205 -0
- package/dist/tools/records.js.map +1 -0
- package/dist/tools/registry.js +529 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/render.js +2 -0
- package/dist/tools/render.js.map +1 -0
- package/dist/tools/rooms.js +210 -0
- package/dist/tools/rooms.js.map +1 -0
- package/dist/tools/rotate.js +143 -0
- package/dist/tools/rotate.js.map +1 -0
- package/dist/tools/scopes.js +126 -0
- package/dist/tools/scopes.js.map +1 -0
- package/dist/tools/shared.js +104 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/stall.js +415 -0
- package/dist/tools/stall.js.map +1 -0
- package/dist/tools/transport.js +1918 -0
- package/dist/tools/transport.js.map +1 -0
- package/dist/tools/work.js +465 -0
- package/dist/tools/work.js.map +1 -0
- package/dist/tools/worktrees.js +581 -0
- package/dist/tools/worktrees.js.map +1 -0
- package/dist/transports/config.js +82 -0
- package/dist/transports/config.js.map +1 -0
- package/dist/transports/index.js +113 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/tmux.js +140 -0
- package/dist/transports/tmux.js.map +1 -0
- package/dist/transports/types.js +86 -0
- package/dist/transports/types.js.map +1 -0
- package/dist/typed-records.js +174 -0
- package/dist/typed-records.js.map +1 -0
- package/dist/work.js +2 -0
- package/dist/work.js.map +1 -0
- package/hooks/tmux-pusher.mjs +33 -3
- package/package.json +1 -1
- package/src/capabilities.ts +104 -1
- package/src/server.ts +30 -1
- package/src/tools/records.ts +221 -34
- package/src/tools/registry.ts +36 -5
- package/src/tools/shared.ts +12 -36
- package/src/tools/stall.ts +2 -1
- package/src/tools/transport.ts +96 -43
- package/src/tools/work.ts +95 -3
- package/src/tools/worktrees.ts +234 -32
- package/src/transports/config.ts +110 -0
- package/src/transports/index.ts +126 -0
- package/src/transports/tmux.ts +177 -0
- package/src/transports/types.ts +201 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Event subscriptions — stop relying on someone CHOOSING to tell you.
|
|
3
|
+
*
|
|
4
|
+
* The bus is almost entirely direct messaging: an agent learns something
|
|
5
|
+
* happened because another agent decided to say so. Every miss this week was a
|
|
6
|
+
* missing NOTIFICATION rather than a missing capability — two mergeable PRs sat
|
|
7
|
+
* 17 hours because nobody told the coordinator to gate, the console's trigger
|
|
8
|
+
* ran zero times because nothing woke it, and `stall_check` runs only when a
|
|
9
|
+
* human types it.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { ROOT } from "../store.js";
|
|
16
|
+
import { EVENT_KINDS, EVENT_KIND_IDS } from "./event-kinds.js";
|
|
17
|
+
const subsFile = () => path.join(ROOT, "subscriptions.json");
|
|
18
|
+
// Re-exported so every existing importer keeps its import path. The vocabulary
|
|
19
|
+
// itself is defined beside the emitters (record-events.ts) — Task 9.2: a kind
|
|
20
|
+
// that can be subscribed to but never emitted is unsatisfiable BY CONSTRUCTION
|
|
21
|
+
// only if the enum cannot be widened without an emitter.
|
|
22
|
+
export { EVENT_KINDS, EVENT_KIND_IDS };
|
|
23
|
+
export function readSubs() {
|
|
24
|
+
const f = subsFile();
|
|
25
|
+
if (!existsSync(f))
|
|
26
|
+
return [];
|
|
27
|
+
try {
|
|
28
|
+
return (JSON.parse(readFileSync(f, "utf8")).subscriptions ?? []);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function writeSubs(subs) {
|
|
35
|
+
mkdirSync(ROOT, { recursive: true });
|
|
36
|
+
writeFileSync(subsFile(), `${JSON.stringify({ subscriptions: subs }, null, 2)}\n`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 6.3 — A SUBSCRIPTION THAT NEVER FIRES MUST BE DISTINGUISHABLE FROM ONE NEVER
|
|
40
|
+
* REGISTERED, so never-evaluated is an ERROR rather than a quiet zero.
|
|
41
|
+
*
|
|
42
|
+
* We hit the absence of this rule twice in two days: the console's standing
|
|
43
|
+
* trigger and `stall_check`'s clock both looked healthy while never running. A
|
|
44
|
+
* subscription with no last-evaluated mark has produced no evidence of
|
|
45
|
+
* anything, and "no events" is the same output a broken subscription gives.
|
|
46
|
+
*/
|
|
47
|
+
export function subscriptionHealth(s) {
|
|
48
|
+
const iso = (n) => new Date(n).toISOString();
|
|
49
|
+
// THREE STATES, BECAUSE THERE ARE THREE FACTS. They were two, and the
|
|
50
|
+
// collapse cost a week: an `item` subscriber read `error — never evaluated`
|
|
51
|
+
// the whole time, because `evaluate()` only touches subscriptions whose kind
|
|
52
|
+
// matches the event and no `item` event had fired. The wiring was fine. The
|
|
53
|
+
// health field said it was dead, and the agent holding it believed the field.
|
|
54
|
+
//
|
|
55
|
+
// Same shape as `alive` swallowing `heartbeatFresh`, and as
|
|
56
|
+
// `stall_clock_status` reporting green while covering nothing: one field
|
|
57
|
+
// answering two questions always answers the easier one.
|
|
58
|
+
if (s.lastScannedAt === undefined && s.lastEvaluatedAt === null) {
|
|
59
|
+
// Written before this field existed AND never evaluated. Absent is UNKNOWN,
|
|
60
|
+
// never "never scanned" — inventing a scan nobody observed is the failure
|
|
61
|
+
// this phase is about, and asserting one never happened is the same error
|
|
62
|
+
// pointed the other way.
|
|
63
|
+
return {
|
|
64
|
+
level: "unknown",
|
|
65
|
+
detail: "predates scan tracking and has never been evaluated — whether the machinery has run for it CANNOT be determined from this record. " +
|
|
66
|
+
"It will resolve to ok or error on the next scan; until then this is an absence of evidence, not evidence of absence.",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!s.lastScannedAt) {
|
|
70
|
+
return {
|
|
71
|
+
level: "error",
|
|
72
|
+
detail: "NEVER SCANNED — no scan has run with this subscription registered, so it has produced no evidence of being wired to anything. " +
|
|
73
|
+
"This is the state that means broken.",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (s.lastEvaluatedAt === null) {
|
|
77
|
+
// THE STATE THAT USED TO READ AS BROKEN. The machinery ran and nothing of
|
|
78
|
+
// this kind happened, which is a healthy idle watch.
|
|
79
|
+
return {
|
|
80
|
+
level: "ok",
|
|
81
|
+
detail: `scanned ${iso(s.lastScannedAt)}, never evaluated — the machinery RAN and no '${s.kind}' event has occurred yet. ` +
|
|
82
|
+
"Scanned-and-quiet is healthy; it is not the same as never run, and those shared a field until now.",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
level: "ok",
|
|
87
|
+
detail: s.lastEventAt
|
|
88
|
+
? `scanned ${iso(s.lastScannedAt)}, last evaluated ${iso(s.lastEvaluatedAt)}, last event ${iso(s.lastEventAt)}`
|
|
89
|
+
: `scanned ${iso(s.lastScannedAt)}, last evaluated ${iso(s.lastEvaluatedAt)}, no events yet`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 6.4 — DELIVERY IS AT-LEAST-ONCE BY DESIGN. Safe for a reader, DOUBLE
|
|
94
|
+
* EXECUTION for an executor: a callback that triggers work must carry a key, or
|
|
95
|
+
* the same merge lands twice. The key is derived from the EVENT, never from the
|
|
96
|
+
* delivery attempt, so a retry produces the same key.
|
|
97
|
+
*/
|
|
98
|
+
export const eventKey = (kind, target, ref) => createHash("sha256").update(`${kind}:${target}:${ref}`).digest("hex").slice(0, 16);
|
|
99
|
+
/**
|
|
100
|
+
* 6.2 — EVENTS ARE DERIVED FROM THE RECORD, NEVER PARALLEL TO IT.
|
|
101
|
+
*
|
|
102
|
+
* Enforced here rather than promised in a comment: the event's `ref` must
|
|
103
|
+
* already be present in the record document before anything is emitted. An
|
|
104
|
+
* event stream that can say "task X complete" while DONE.md does not is a
|
|
105
|
+
* second source of truth, and record-vs-state divergence is the defect this
|
|
106
|
+
* fleet hit most this week. ADR-003 keeps markdown authoritative, and this must
|
|
107
|
+
* not quietly reopen it.
|
|
108
|
+
*
|
|
109
|
+
* So the ordering is not a convention: emission READS the record, and an event
|
|
110
|
+
* whose cause is not in the record cannot be emitted at all.
|
|
111
|
+
*/
|
|
112
|
+
export function eventIsDerived(recordText, ev) {
|
|
113
|
+
if (!ev.ref)
|
|
114
|
+
return { ok: false, error: `event for ${ev.kind} ${ev.target} carries no ref — nothing ties it to a record entry` };
|
|
115
|
+
if (!String(recordText).includes(ev.ref))
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
error: `refusing to emit ${ev.kind} ${ev.target}: its ref ${ev.ref} is NOT in the record. ` +
|
|
119
|
+
`An event that exists without the record change that caused it is a second source of truth — ` +
|
|
120
|
+
`the stream would claim something the authoritative document does not.`,
|
|
121
|
+
};
|
|
122
|
+
return { ok: true };
|
|
123
|
+
}
|
|
124
|
+
/** Subscriptions matching an event. Exact target match; no wildcards yet. */
|
|
125
|
+
export const matching = (subs, ev) => subs.filter((s) => s.kind === ev.kind && s.target === ev.target);
|
|
126
|
+
/**
|
|
127
|
+
* Evaluate every subscription against one event and return what to deliver.
|
|
128
|
+
*
|
|
129
|
+
* EVALUATION IS RECORDED EVEN WHEN NOTHING MATCHES — that is 6.3's whole point.
|
|
130
|
+
* A subscription only learns it is alive by being evaluated, so the mark is
|
|
131
|
+
* written for every subscription of that kind, not only the ones that fired.
|
|
132
|
+
*/
|
|
133
|
+
/**
|
|
134
|
+
* Record that a scan RAN, for every live subscription regardless of kind.
|
|
135
|
+
*
|
|
136
|
+
* Called once per scan — including a scan that produced NO events, which is
|
|
137
|
+
* exactly the case that starved the old field: no events of your kind means
|
|
138
|
+
* `evaluate` never touches you, and a subscription that is never touched cannot
|
|
139
|
+
* be told from one that is not wired to anything.
|
|
140
|
+
*/
|
|
141
|
+
export function markScanned(subs, now) {
|
|
142
|
+
return subs.map((s) => ({ ...s, lastScannedAt: now }));
|
|
143
|
+
}
|
|
144
|
+
export function evaluate(subs, ev, now) {
|
|
145
|
+
const key = eventKey(ev.kind, ev.target, ev.ref);
|
|
146
|
+
const deliveries = [];
|
|
147
|
+
const next = subs.map((s) => {
|
|
148
|
+
// Every subscription observed this scan, whatever its kind.
|
|
149
|
+
const scanned = { ...s, lastScannedAt: now };
|
|
150
|
+
if (s.kind !== ev.kind)
|
|
151
|
+
return scanned;
|
|
152
|
+
const evaluated = { ...scanned, lastEvaluatedAt: now };
|
|
153
|
+
if (s.target !== ev.target)
|
|
154
|
+
return evaluated;
|
|
155
|
+
if (s.delivered.includes(key)) {
|
|
156
|
+
deliveries.push({ subscriptionId: s.id, agentId: s.agentId, key, status: "duplicate-suppressed" });
|
|
157
|
+
return evaluated;
|
|
158
|
+
}
|
|
159
|
+
deliveries.push({ subscriptionId: s.id, agentId: s.agentId, key, status: "delivered" });
|
|
160
|
+
return { ...evaluated, lastEventAt: now, delivered: [...s.delivered, key].slice(-200) };
|
|
161
|
+
});
|
|
162
|
+
return { subs: next, deliveries };
|
|
163
|
+
}
|
|
164
|
+
/* ── verbs ─────────────────────────────────────────────────────────────────── */
|
|
165
|
+
export const subscribeSchema = {
|
|
166
|
+
agentId: z.string().min(1),
|
|
167
|
+
kind: z.enum(EVENT_KIND_IDS),
|
|
168
|
+
target: z.string().min(1),
|
|
169
|
+
};
|
|
170
|
+
export async function subscribeTool(args) {
|
|
171
|
+
const subs = readSubs();
|
|
172
|
+
const dupe = subs.find((s) => s.agentId === args.agentId && s.kind === args.kind && s.target === args.target);
|
|
173
|
+
if (dupe)
|
|
174
|
+
return { ok: true, subscription: dupe, note: "already subscribed — returning the existing registration rather than a second one" };
|
|
175
|
+
const sub = {
|
|
176
|
+
id: randomUUID(),
|
|
177
|
+
agentId: args.agentId,
|
|
178
|
+
kind: args.kind,
|
|
179
|
+
target: args.target,
|
|
180
|
+
createdAt: Date.now(),
|
|
181
|
+
// EXPLICIT null, never left absent. `null` means "we know no scan has run
|
|
182
|
+
// for this"; `undefined` means "this record predates the field and we
|
|
183
|
+
// cannot say". A subscription created now is the first case, and writing it
|
|
184
|
+
// explicitly is what keeps a brand-new registration from being reported as
|
|
185
|
+
// unknowable.
|
|
186
|
+
lastScannedAt: null,
|
|
187
|
+
lastEvaluatedAt: null,
|
|
188
|
+
lastEventAt: null,
|
|
189
|
+
delivered: [],
|
|
190
|
+
};
|
|
191
|
+
writeSubs([...subs, sub]);
|
|
192
|
+
return { ok: true, subscription: sub, health: subscriptionHealth(sub) };
|
|
193
|
+
}
|
|
194
|
+
export const unsubscribeSchema = { agentId: z.string().min(1), id: z.string().min(1) };
|
|
195
|
+
export async function unsubscribeTool(args) {
|
|
196
|
+
const subs = readSubs();
|
|
197
|
+
const sub = subs.find((s) => s.id === args.id);
|
|
198
|
+
if (!sub)
|
|
199
|
+
return { ok: false, error: `no subscription '${args.id}'` };
|
|
200
|
+
// Another agent's subscription is not yours to remove: silently dropping
|
|
201
|
+
// someone else's notification is how a miss is manufactured.
|
|
202
|
+
if (sub.agentId !== args.agentId)
|
|
203
|
+
return { ok: false, error: `subscription '${args.id}' belongs to '${sub.agentId}', not '${args.agentId}'` };
|
|
204
|
+
writeSubs(subs.filter((s) => s.id !== args.id));
|
|
205
|
+
return { ok: true, removed: sub };
|
|
206
|
+
}
|
|
207
|
+
export const listSubscriptionsSchema = { agentId: z.string().optional() };
|
|
208
|
+
export async function listSubscriptionsTool(args) {
|
|
209
|
+
const all = readSubs();
|
|
210
|
+
const subs = args.agentId ? all.filter((s) => s.agentId === args.agentId) : all;
|
|
211
|
+
const rows = subs.map((s) => ({ ...s, health: subscriptionHealth(s) }));
|
|
212
|
+
const neverEvaluated = rows.filter((r) => r.health.level === "error");
|
|
213
|
+
const undetermined = rows.filter((r) => r.health.level === "unknown");
|
|
214
|
+
return {
|
|
215
|
+
ok: neverEvaluated.length === 0,
|
|
216
|
+
// Population beside the verdict, always: "no subscriptions" and "none
|
|
217
|
+
// listed for you" are different claims.
|
|
218
|
+
population: { listed: rows.length, total: all.length },
|
|
219
|
+
subscriptions: rows,
|
|
220
|
+
...(neverEvaluated.length
|
|
221
|
+
? { error: `${neverEvaluated.length} of ${rows.length} subscription(s) have NEVER BEEN SCANNED — no scan has run with them registered, so they have produced no evidence of being wired to anything.` }
|
|
222
|
+
: {}),
|
|
223
|
+
...(undetermined.length
|
|
224
|
+
? {
|
|
225
|
+
undetermined: `${undetermined.length} of ${rows.length} subscription(s) predate scan tracking and cannot be judged yet — they resolve on the next scan. Reported rather than counted as either healthy or broken.`,
|
|
226
|
+
}
|
|
227
|
+
: {}),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/** Persist an evaluation. Callers do this after a record write, never before. */
|
|
231
|
+
export function commitEvaluation(next) {
|
|
232
|
+
writeSubs(next);
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/tools/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./shared.js";
|
|
2
|
+
export * from "./registry.js";
|
|
3
|
+
export * from "./rooms.js";
|
|
4
|
+
export * from "./messaging.js";
|
|
5
|
+
export * from "./transport.js";
|
|
6
|
+
export * from "./admin.js";
|
|
7
|
+
export * from "./scopes.js";
|
|
8
|
+
export * from "./work.js";
|
|
9
|
+
export * from "./records.js";
|
|
10
|
+
export * from "./worktrees.js";
|
|
11
|
+
export * from "./stall.js";
|
|
12
|
+
export * from "./events.js";
|
|
13
|
+
export * from "./record-events.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Task 8 — a watch over an append-only log, keyed on FILE OFFSET.
|
|
3
|
+
*
|
|
4
|
+
* A WATCH MUST NOT BE ABLE TO CONSUME. This is Task 7.1's rule at its second
|
|
5
|
+
* caller, not a second fix: the read cursor records what the AGENT has taken
|
|
6
|
+
* delivery of, and only the agent reading may advance it. A pusher typing into
|
|
7
|
+
* a pane is a reader; a watch waiting for traffic is a reader; neither may
|
|
8
|
+
* consume on the agent's behalf.
|
|
9
|
+
*
|
|
10
|
+
* So this keeps its OWN position — `lastLineSeen` — and never touches
|
|
11
|
+
* `cursors/<id>.json`. A watch that advanced the read cursor would reproduce
|
|
12
|
+
* exactly the defect Task 7 removed, one component over: the message would be
|
|
13
|
+
* marked consumed by something that only looked at it.
|
|
14
|
+
*
|
|
15
|
+
* WHY THIS DOES NOT VIOLATE 6.2 (8.5). "Events are derived from the record,
|
|
16
|
+
* never parallel to it." The room and inbox JSONL logs ARE the record — they
|
|
17
|
+
* are the authoritative store, not a projection of one. `land`'s events are
|
|
18
|
+
* derived from a document write; these are derived from the log itself. Both
|
|
19
|
+
* read the authoritative artifact and neither maintains a second source of
|
|
20
|
+
* truth. The test for a violation is whether the stream could assert something
|
|
21
|
+
* the record does not, and it cannot: every event here IS a line in the log,
|
|
22
|
+
* identified by its offset in that log.
|
|
23
|
+
*
|
|
24
|
+
* Keyed on OFFSET rather than timestamp or id, because an offset is a property
|
|
25
|
+
* of the log itself. Two lines can share a `ts`, an id can be rewritten, and a
|
|
26
|
+
* clock can disagree with another clock — a line's position cannot.
|
|
27
|
+
*/
|
|
28
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
import { ROOT } from "../store.js";
|
|
32
|
+
export const logFileFor = (kind, target) => kind === "room" ? path.join(ROOT, "rooms", `${target}.jsonl`) : path.join(ROOT, "inbox", `${target}.jsonl`);
|
|
33
|
+
/** Parsed lines of a log. Malformed lines are SKIPPED but still counted. */
|
|
34
|
+
export function readLog(file) {
|
|
35
|
+
if (!existsSync(file))
|
|
36
|
+
return { entries: [], total: 0 };
|
|
37
|
+
const lines = readFileSync(file, "utf8").split("\n").filter((l) => l.trim());
|
|
38
|
+
const entries = [];
|
|
39
|
+
for (const l of lines) {
|
|
40
|
+
try {
|
|
41
|
+
entries.push(JSON.parse(l));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// A malformed line still OCCUPIES an offset. Skipping it without counting
|
|
45
|
+
// would shift every subsequent line's position by one and silently
|
|
46
|
+
// re-report the whole tail.
|
|
47
|
+
entries.push(null);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { entries, total: lines.length };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Lines appended since `lastLineSeen`.
|
|
54
|
+
*
|
|
55
|
+
* A TRUNCATED LOG IS NOT A QUIET ONE. If the file is SHORTER than the watch's
|
|
56
|
+
* position, something rewrote or pruned it — reporting "no new lines" would be
|
|
57
|
+
* indistinguishable from a healthy quiet period. It is surfaced instead.
|
|
58
|
+
*/
|
|
59
|
+
export function newLines(watch, log) {
|
|
60
|
+
if (log.total < watch.lastLineSeen)
|
|
61
|
+
return { events: [], truncated: true, total: log.total };
|
|
62
|
+
const events = [];
|
|
63
|
+
for (let i = watch.lastLineSeen; i < log.total; i++) {
|
|
64
|
+
events.push({ kind: watch.kind, target: watch.target, offset: i, line: log.entries[i] ?? null });
|
|
65
|
+
}
|
|
66
|
+
return { events, truncated: false, total: log.total };
|
|
67
|
+
}
|
|
68
|
+
/** 8.3 — health, identical in shape to the record subscriptions, plus lastLineSeen. */
|
|
69
|
+
export function watchHealth(w) {
|
|
70
|
+
if (w.lastEvaluatedAt === null)
|
|
71
|
+
return {
|
|
72
|
+
level: "error",
|
|
73
|
+
detail: `never evaluated — this watch has produced no evidence it is attached to anything. "No lines yet" and "never ran" are the same output, and only one of them is healthy.`,
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
level: "ok",
|
|
77
|
+
detail: `last evaluated ${new Date(w.lastEvaluatedAt).toISOString()}, reported up to line ${w.lastLineSeen}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export const logWatchSchema = {
|
|
81
|
+
agentId: z.string().min(1),
|
|
82
|
+
kind: z.enum(["room", "inbox"]),
|
|
83
|
+
target: z.string().min(1),
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=logwatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logwatch.js","sourceRoot":"","sources":["../../src/tools/logwatch.ts"],"names":[],"mappings":"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"}
|