@cello-protocol/daemon 0.0.131 → 0.0.133

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.
Files changed (113) hide show
  1. package/dist/content-park.d.ts.map +1 -1
  2. package/dist/content-park.js +29 -11
  3. package/dist/content-park.js.map +1 -1
  4. package/dist/daemon.d.ts +11 -0
  5. package/dist/daemon.d.ts.map +1 -1
  6. package/dist/daemon.js +398 -18
  7. package/dist/daemon.js.map +1 -1
  8. package/dist/document-ack-inbound.d.ts +57 -0
  9. package/dist/document-ack-inbound.d.ts.map +1 -0
  10. package/dist/document-ack-inbound.js +174 -0
  11. package/dist/document-ack-inbound.js.map +1 -0
  12. package/dist/document-control-notifier.d.ts +61 -0
  13. package/dist/document-control-notifier.d.ts.map +1 -0
  14. package/dist/document-control-notifier.js +70 -0
  15. package/dist/document-control-notifier.js.map +1 -0
  16. package/dist/document-delivery-transport.d.ts +94 -0
  17. package/dist/document-delivery-transport.d.ts.map +1 -0
  18. package/dist/document-delivery-transport.js +179 -0
  19. package/dist/document-delivery-transport.js.map +1 -0
  20. package/dist/document-delivery.d.ts +181 -0
  21. package/dist/document-delivery.d.ts.map +1 -0
  22. package/dist/document-delivery.js +289 -0
  23. package/dist/document-delivery.js.map +1 -0
  24. package/dist/document-frame-router.d.ts +210 -0
  25. package/dist/document-frame-router.d.ts.map +1 -0
  26. package/dist/document-frame-router.js +396 -0
  27. package/dist/document-frame-router.js.map +1 -0
  28. package/dist/document-handlers.d.ts +47 -0
  29. package/dist/document-handlers.d.ts.map +1 -0
  30. package/dist/document-handlers.js +657 -0
  31. package/dist/document-handlers.js.map +1 -0
  32. package/dist/document-handshake.d.ts +156 -0
  33. package/dist/document-handshake.d.ts.map +1 -0
  34. package/dist/document-handshake.js +398 -0
  35. package/dist/document-handshake.js.map +1 -0
  36. package/dist/document-inbound.d.ts +91 -0
  37. package/dist/document-inbound.d.ts.map +1 -0
  38. package/dist/document-inbound.js +290 -0
  39. package/dist/document-inbound.js.map +1 -0
  40. package/dist/document-layer.d.ts +137 -0
  41. package/dist/document-layer.d.ts.map +1 -0
  42. package/dist/document-layer.js +255 -0
  43. package/dist/document-layer.js.map +1 -0
  44. package/dist/document-lifecycle.d.ts +125 -0
  45. package/dist/document-lifecycle.d.ts.map +1 -0
  46. package/dist/document-lifecycle.js +433 -0
  47. package/dist/document-lifecycle.js.map +1 -0
  48. package/dist/document-live-docs.d.ts +58 -0
  49. package/dist/document-live-docs.d.ts.map +1 -0
  50. package/dist/document-live-docs.js +126 -0
  51. package/dist/document-live-docs.js.map +1 -0
  52. package/dist/document-notify.d.ts +173 -0
  53. package/dist/document-notify.d.ts.map +1 -0
  54. package/dist/document-notify.js +438 -0
  55. package/dist/document-notify.js.map +1 -0
  56. package/dist/document-publish.d.ts +67 -0
  57. package/dist/document-publish.d.ts.map +1 -0
  58. package/dist/document-publish.js +149 -0
  59. package/dist/document-publish.js.map +1 -0
  60. package/dist/document-reachability.d.ts +42 -0
  61. package/dist/document-reachability.d.ts.map +1 -0
  62. package/dist/document-reachability.js +80 -0
  63. package/dist/document-reachability.js.map +1 -0
  64. package/dist/document-rejection.d.ts +240 -0
  65. package/dist/document-rejection.d.ts.map +1 -0
  66. package/dist/document-rejection.js +407 -0
  67. package/dist/document-rejection.js.map +1 -0
  68. package/dist/document-store.d.ts +154 -8
  69. package/dist/document-store.d.ts.map +1 -1
  70. package/dist/document-store.js +462 -4
  71. package/dist/document-store.js.map +1 -1
  72. package/dist/document-write-path.d.ts.map +1 -1
  73. package/dist/document-write-path.js +10 -43
  74. package/dist/document-write-path.js.map +1 -1
  75. package/dist/inbound-sessions.d.ts +25 -0
  76. package/dist/inbound-sessions.d.ts.map +1 -1
  77. package/dist/inbound-sessions.js +60 -0
  78. package/dist/inbound-sessions.js.map +1 -1
  79. package/dist/initiate-session-handler.d.ts +24 -1
  80. package/dist/initiate-session-handler.d.ts.map +1 -1
  81. package/dist/initiate-session-handler.js +35 -9
  82. package/dist/initiate-session-handler.js.map +1 -1
  83. package/dist/ipc-server.d.ts +11 -1
  84. package/dist/ipc-server.d.ts.map +1 -1
  85. package/dist/ipc-server.js +7 -1
  86. package/dist/ipc-server.js.map +1 -1
  87. package/dist/line-lcs.d.ts +51 -0
  88. package/dist/line-lcs.d.ts.map +1 -0
  89. package/dist/line-lcs.js +71 -0
  90. package/dist/line-lcs.js.map +1 -0
  91. package/dist/notification-handlers.d.ts +2 -1
  92. package/dist/notification-handlers.d.ts.map +1 -1
  93. package/dist/notification-handlers.js +11 -2
  94. package/dist/notification-handlers.js.map +1 -1
  95. package/dist/outbound-sessions.d.ts +2 -0
  96. package/dist/outbound-sessions.d.ts.map +1 -1
  97. package/dist/outbound-sessions.js +23 -2
  98. package/dist/outbound-sessions.js.map +1 -1
  99. package/dist/session-content-handlers.d.ts.map +1 -1
  100. package/dist/session-content-handlers.js +3 -2
  101. package/dist/session-content-handlers.js.map +1 -1
  102. package/dist/session-node-manager.d.ts +15 -0
  103. package/dist/session-node-manager.d.ts.map +1 -1
  104. package/dist/session-node-manager.js +188 -9
  105. package/dist/session-node-manager.js.map +1 -1
  106. package/dist/vocabulary.d.ts.map +1 -1
  107. package/dist/vocabulary.js +16 -0
  108. package/dist/vocabulary.js.map +1 -1
  109. package/dist/wire-content-hash.d.ts +27 -0
  110. package/dist/wire-content-hash.d.ts.map +1 -0
  111. package/dist/wire-content-hash.js +37 -0
  112. package/dist/wire-content-hash.js.map +1 -0
  113. package/package.json +5 -5
@@ -0,0 +1,173 @@
1
+ /**
2
+ * DOD-DOC-NOTIFY-1 — passive notification and the two read calls (§16.5, §4.1).
3
+ *
4
+ * ── WHY NO DOORBELL ───────────────────────────────────────────────────────────────────────────
5
+ *
6
+ * A document update raises NO doorbell (§11.3 — doorbell-on-update is parked). The notice sits in
7
+ * the inbox aggregation and the agent finds it the next time it looks. That is the whole design:
8
+ * a collaborator typing produces a stream of updates, and a doorbell per update would interrupt
9
+ * the operator's agent continuously for something that has no deadline. The one-line summary the
10
+ * agent eventually reads carries the same information at none of the cost.
11
+ *
12
+ * Following the `contact_rename_notices` precedent: there is no inbox store — the inbox is computed
13
+ * per call — so a derived section needs its own table and its own getter.
14
+ *
15
+ * The notice carries `document_id` and a PENDING COUNT, and nothing else. Not a preview, not the
16
+ * first line, not the author's words. Content reaches the agent only through the two read calls
17
+ * below, which are screened; a notification that carried content would be an unscreened path into
18
+ * the agent's context, which is the whole prompt-injection surface §3.1 exists to close.
19
+ *
20
+ * ── THE TWO READ CALLS (§4.1) ─────────────────────────────────────────────────────────────────
21
+ *
22
+ * `diffStats` is STRUCTURAL ONLY — counts, ranges, and the overlap flag. It exists so an agent can
23
+ * decide whether to read without reading, which is exactly what a cautious agent should be able to
24
+ * do. `diff` is the git-like diff itself and is an ordinary screened read.
25
+ *
26
+ * ── SUPPORTED TYPES FOR `diff`, DECIDED IN-UNIT ───────────────────────────────────────────────
27
+ *
28
+ * Markdown, plain text, and JSON. Markdown and plain text share one line-diff implementation (a
29
+ * markdown file IS lines); JSON gets a key-path diff because a line diff over re-serialized JSON
30
+ * reports the whole document as changed whenever a formatter touches it. Anything else returns a
31
+ * REFUSAL naming the type rather than a line diff over bytes that are not lines — a diff that is
32
+ * wrong is worse than no diff, because the agent cannot tell.
33
+ */
34
+ import type { DocumentStore } from "./document-store.js";
35
+ import type { Logger } from "./types.js";
36
+ /** Types `diff` can render. Decided in-unit; see the header for why the list is closed. */
37
+ export declare const DIFFABLE_DOCUMENT_TYPES: readonly ["markdown", "text", "json"];
38
+ export type DiffableDocumentType = (typeof DIFFABLE_DOCUMENT_TYPES)[number];
39
+ export interface DocumentNotice {
40
+ documentId: string;
41
+ pending: number;
42
+ noticedAtMs: number;
43
+ }
44
+ export interface DiffStats {
45
+ documentId: string;
46
+ linesAdded: number;
47
+ linesRemoved: number;
48
+ /** 1-based inclusive line ranges the change touches. Ranges, never the lines themselves. */
49
+ ranges: Array<{
50
+ start: number;
51
+ end: number;
52
+ }>;
53
+ /** For JSON: the key paths touched. Empty for line-oriented types. */
54
+ keyPaths: string[];
55
+ /**
56
+ * Whether the peer's change touches a region this operator also edited. The one field here that
57
+ * is a judgement rather than a count, and the reason an agent reads stats before deciding.
58
+ */
59
+ overlap: boolean | null;
60
+ /** Whether `keyPaths` was computed at all — an empty list is otherwise read as "none changed". */
61
+ keyPathsComputed: boolean;
62
+ /** The document exceeded the LCS limit, so the numbers above are bounds, not a measurement. */
63
+ truncated: boolean;
64
+ }
65
+ export type DiffResult = {
66
+ ok: true;
67
+ documentType: DiffableDocumentType;
68
+ diff: string;
69
+ /**
70
+ * Set when the renderer could not do what the type asked for. A notice inside the diff STRING
71
+ * is readable by a human and invisible to a caller branching on the result — and it travels
72
+ * as screened content, which is the wrong channel for a fact about the renderer.
73
+ */
74
+ fallback?: "unparseable_json_line_diff";
75
+ } | {
76
+ ok: false;
77
+ reason: string;
78
+ detail: string;
79
+ };
80
+ export declare class DocumentNotifications {
81
+ #private;
82
+ constructor(store: DocumentStore, logger: Logger);
83
+ /**
84
+ * Record what this agent last SAW, so a later diff has a "before".
85
+ *
86
+ * REPLACES. A read mark is a bookmark, not a history — keeping every read would make the table
87
+ * grow with attention rather than with content, and no caller wants the second-most-recent read.
88
+ */
89
+ markRead(agentId: string, documentId: string, text: string, nowMs: number): void;
90
+ /**
91
+ * Record the text WE just wrote, against the current read mark.
92
+ *
93
+ * No-ops when there is no read mark: without a baseline there is nothing to measure our edit
94
+ * against, and inventing one would make the first diff after a write report the whole document as
95
+ * a conflict.
96
+ */
97
+ markWritten(agentId: string, documentId: string, text: string): void;
98
+ /**
99
+ * The lines WE edited since the last read, 1-based, in the baseline's coordinate space — or null
100
+ * when we have not written since, which is "not computed" and must stay distinguishable from "no
101
+ * conflict". `diffStats` requires the distinction for exactly that reason.
102
+ */
103
+ /**
104
+ * WHY THIS EXISTS, stated where the reader will need it:
105
+ *
106
+ * At diff time the two texts in hand are the baseline and the current document, and no amount of
107
+ * comparing them says which of the changes were the PEER's. So `overlap` was hardcoded `null`
108
+ * while three shipped instruction sheets told agents to branch on it — and `null` is falsy in
109
+ * JSON, so every one of them got the reassuring answer on every call. That is the precise trap
110
+ * `diffStats` made its `myEdits` parameter required to prevent, defeated by the one caller.
111
+ *
112
+ * Diffing the baseline against what WE last wrote gives our own edited lines in the baseline's
113
+ * coordinate space, which is the space the diff reports its ranges in. Exact, not inferred.
114
+ */
115
+ myEditedLines(agentId: string, documentId: string): number[] | null;
116
+ /**
117
+ * The text this agent last saw, or null if it has never read this document.
118
+ *
119
+ * NULL IS NOT THE EMPTY STRING, and callers must not conflate them. Never-read means the whole
120
+ * document is new to this agent; last-saw-empty means they read it when it was empty and
121
+ * everything since is a change they can be shown against that. Returning "" for both would render
122
+ * a first read of a long document as an enormous diff the agent then treats as "what just
123
+ * changed".
124
+ */
125
+ lastSeen(agentId: string, documentId: string): string | null;
126
+ /**
127
+ * Note that a document has unread updates. Passive — this never pushes anything.
128
+ *
129
+ * The count is REPLACED rather than incremented, and is passed in by the caller from the log,
130
+ * so the notice cannot drift from the document. An incremented counter is a second tally of a
131
+ * fact the log already holds, and the two disagree the first time a notice write is missed.
132
+ */
133
+ notice(agentId: string, documentId: string, pending: number, nowMs: number): void;
134
+ /** The derived inbox section. Read-only — fetching is what clears, and that is explicit. */
135
+ pending(agentId: string): DocumentNotice[];
136
+ /**
137
+ * Cleared by the agent's EXPLICIT fetch, never by the aggregation that displays it.
138
+ *
139
+ * Reading the inbox and clearing the notice are different acts: an inbox render that cleared
140
+ * would drop the notice for an agent that merely glanced at a summary, and the update would then
141
+ * be unread and unannounced — invisible in both directions.
142
+ */
143
+ clear(agentId: string, documentId: string): boolean;
144
+ /**
145
+ * Structural counts and ranges — NO content. Lets an agent decide whether to read.
146
+ *
147
+ * `before` and `after` are the materialized text of the document at the two points; the caller
148
+ * holds the engine and therefore the materialization.
149
+ *
150
+ * Uses the SHARED line LCS, not a positional walk. The first version compared line i to line i,
151
+ * which is correct only while the line count is unchanged: inserting one line at the top of a
152
+ * three-line file reported `+4 -3` with a single range covering the whole document. The counts
153
+ * being wrong is the smaller half — `overlap` is derived from those ranges, so it became
154
+ * permanently true, and a flag that always says yes trains the agent to ignore it. Same defect
155
+ * class WRITE-1 measured, which is why there is now one LCS rather than two.
156
+ */
157
+ diffStats(documentId: string, before: string, after: string,
158
+ /**
159
+ * The operator's own edited line numbers. REQUIRED — pass `null` to say "not computed".
160
+ * Defaulting to `[]` made a caller that simply forgot receive `overlap: false`, the reassuring
161
+ * answer, indistinguishable from "checked, and there is no conflict". This is the one
162
+ * judgement field in an otherwise structural result.
163
+ */
164
+ myEdits: readonly number[] | null, documentType?: string): DiffStats;
165
+ /**
166
+ * The git-like diff. An ordinary screened read — the caller screens it; this renders it.
167
+ *
168
+ * An unsupported type is REFUSED by name rather than line-diffed anyway. A diff that is silently
169
+ * wrong is worse than no diff, because the agent has no way to tell and will act on it.
170
+ */
171
+ diff(documentType: string, before: string, after: string, documentId: string): DiffResult;
172
+ }
173
+ //# sourceMappingURL=document-notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-notify.d.ts","sourceRoot":"","sources":["../src/document-notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,438 @@
1
+ /**
2
+ * DOD-DOC-NOTIFY-1 — passive notification and the two read calls (§16.5, §4.1).
3
+ *
4
+ * ── WHY NO DOORBELL ───────────────────────────────────────────────────────────────────────────
5
+ *
6
+ * A document update raises NO doorbell (§11.3 — doorbell-on-update is parked). The notice sits in
7
+ * the inbox aggregation and the agent finds it the next time it looks. That is the whole design:
8
+ * a collaborator typing produces a stream of updates, and a doorbell per update would interrupt
9
+ * the operator's agent continuously for something that has no deadline. The one-line summary the
10
+ * agent eventually reads carries the same information at none of the cost.
11
+ *
12
+ * Following the `contact_rename_notices` precedent: there is no inbox store — the inbox is computed
13
+ * per call — so a derived section needs its own table and its own getter.
14
+ *
15
+ * The notice carries `document_id` and a PENDING COUNT, and nothing else. Not a preview, not the
16
+ * first line, not the author's words. Content reaches the agent only through the two read calls
17
+ * below, which are screened; a notification that carried content would be an unscreened path into
18
+ * the agent's context, which is the whole prompt-injection surface §3.1 exists to close.
19
+ *
20
+ * ── THE TWO READ CALLS (§4.1) ─────────────────────────────────────────────────────────────────
21
+ *
22
+ * `diffStats` is STRUCTURAL ONLY — counts, ranges, and the overlap flag. It exists so an agent can
23
+ * decide whether to read without reading, which is exactly what a cautious agent should be able to
24
+ * do. `diff` is the git-like diff itself and is an ordinary screened read.
25
+ *
26
+ * ── SUPPORTED TYPES FOR `diff`, DECIDED IN-UNIT ───────────────────────────────────────────────
27
+ *
28
+ * Markdown, plain text, and JSON. Markdown and plain text share one line-diff implementation (a
29
+ * markdown file IS lines); JSON gets a key-path diff because a line diff over re-serialized JSON
30
+ * reports the whole document as changed whenever a formatter touches it. Anything else returns a
31
+ * REFUSAL naming the type rather than a line diff over bytes that are not lines — a diff that is
32
+ * wrong is worse than no diff, because the agent cannot tell.
33
+ */
34
+ import { lineRuns, toChunks } from "./line-lcs.js";
35
+ const CREATE_NOTICES_SQL = `
36
+ CREATE TABLE IF NOT EXISTS document_notices (
37
+ agent_id TEXT NOT NULL,
38
+ document_id TEXT NOT NULL,
39
+ -- The count, not the content. See the header.
40
+ pending INTEGER NOT NULL,
41
+ noticed_at INTEGER NOT NULL,
42
+ PRIMARY KEY (agent_id, document_id)
43
+ );
44
+ `;
45
+ /**
46
+ * WHAT THE OPERATOR LAST SAW, so `diff` can answer "what changed since I looked".
47
+ *
48
+ * The text itself, not a state vector. A state vector says which OPERATIONS this side has seen,
49
+ * which is a fact about the CRDT — and the question an agent is asking before it builds on a shared
50
+ * document is a fact about the TEXT: what words are different from the ones I read. Reconstructing
51
+ * the old text from a vector means replaying the log to a point, which is both expensive and a
52
+ * second answer to a question this column answers directly.
53
+ *
54
+ * Written by READ, never by write or by an arriving update. It marks what a human or an agent
55
+ * actually looked at; moving it on an inbound update would erase the very change the diff exists to
56
+ * show, silently, at the moment it arrived.
57
+ */
58
+ const CREATE_READ_MARKS_SQL = `
59
+ CREATE TABLE IF NOT EXISTS document_read_marks (
60
+ agent_id TEXT NOT NULL,
61
+ document_id TEXT NOT NULL,
62
+ seen_text TEXT NOT NULL,
63
+ seen_at INTEGER NOT NULL,
64
+ -- The last text WE wrote since that read, or NULL if we have not written since. See the
65
+ -- myEditedLines comment below for why it exists: it is what makes the overlap flag a computed
66
+ -- answer rather than a hardcoded null.
67
+ --
68
+ -- No backticks in this string. It is a JS template literal, so one would terminate it — which
69
+ -- is exactly how this shipped broken for a minute.
70
+ my_text TEXT,
71
+ PRIMARY KEY (agent_id, document_id)
72
+ );
73
+ `;
74
+ /** Born on an existing table. See `PEER_DECISION_COLUMNS` in document-handshake.ts for the pattern. */
75
+ const READ_MARK_COLUMNS = ["ALTER TABLE document_read_marks ADD COLUMN my_text TEXT"];
76
+ /** Types `diff` can render. Decided in-unit; see the header for why the list is closed. */
77
+ export const DIFFABLE_DOCUMENT_TYPES = ["markdown", "text", "json"];
78
+ export class DocumentNotifications {
79
+ #store;
80
+ #logger;
81
+ constructor(store, logger) {
82
+ this.#store = store;
83
+ this.#logger = logger;
84
+ this.#store.rawDb.exec(CREATE_NOTICES_SQL);
85
+ this.#store.rawDb.exec(CREATE_READ_MARKS_SQL);
86
+ for (const sql of READ_MARK_COLUMNS) {
87
+ // Birth-gated so a daemon that already holds read marks gains the column instead of losing
88
+ // them. A failure here is either "already present" — the ordinary case — or a locked
89
+ // database, and the latter surfaces loudly on the very next SELECT rather than degrading.
90
+ const has = this.#store.rawDb.prepare("PRAGMA table_info(document_read_marks)").all().some((c) => c.name === "my_text");
91
+ if (!has)
92
+ this.#store.rawDb.exec(sql);
93
+ }
94
+ }
95
+ /**
96
+ * Record what this agent last SAW, so a later diff has a "before".
97
+ *
98
+ * REPLACES. A read mark is a bookmark, not a history — keeping every read would make the table
99
+ * grow with attention rather than with content, and no caller wants the second-most-recent read.
100
+ */
101
+ markRead(agentId, documentId, text, nowMs) {
102
+ this.#store.rawDb
103
+ .prepare(`INSERT INTO document_read_marks (agent_id, document_id, seen_text, seen_at, my_text)
104
+ VALUES (?, ?, ?, ?, NULL)
105
+ ON CONFLICT (agent_id, document_id) DO UPDATE SET
106
+ seen_text = excluded.seen_text, seen_at = excluded.seen_at,
107
+ -- CLEARED. A read establishes a new baseline, so edits made before it are no longer
108
+ -- "mine since I looked" — carrying them forward would report an overlap against work
109
+ -- the operator has already seen merged.
110
+ my_text = NULL`)
111
+ .run(agentId, documentId, text, nowMs);
112
+ }
113
+ /**
114
+ * Record the text WE just wrote, against the current read mark.
115
+ *
116
+ * No-ops when there is no read mark: without a baseline there is nothing to measure our edit
117
+ * against, and inventing one would make the first diff after a write report the whole document as
118
+ * a conflict.
119
+ */
120
+ markWritten(agentId, documentId, text) {
121
+ this.#store.rawDb
122
+ .prepare("UPDATE document_read_marks SET my_text = ? WHERE agent_id = ? AND document_id = ?")
123
+ .run(text, agentId, documentId);
124
+ }
125
+ /**
126
+ * The lines WE edited since the last read, 1-based, in the baseline's coordinate space — or null
127
+ * when we have not written since, which is "not computed" and must stay distinguishable from "no
128
+ * conflict". `diffStats` requires the distinction for exactly that reason.
129
+ */
130
+ /**
131
+ * WHY THIS EXISTS, stated where the reader will need it:
132
+ *
133
+ * At diff time the two texts in hand are the baseline and the current document, and no amount of
134
+ * comparing them says which of the changes were the PEER's. So `overlap` was hardcoded `null`
135
+ * while three shipped instruction sheets told agents to branch on it — and `null` is falsy in
136
+ * JSON, so every one of them got the reassuring answer on every call. That is the precise trap
137
+ * `diffStats` made its `myEdits` parameter required to prevent, defeated by the one caller.
138
+ *
139
+ * Diffing the baseline against what WE last wrote gives our own edited lines in the baseline's
140
+ * coordinate space, which is the space the diff reports its ranges in. Exact, not inferred.
141
+ */
142
+ myEditedLines(agentId, documentId) {
143
+ const row = this.#store.rawDb
144
+ .prepare("SELECT seen_text, my_text FROM document_read_marks WHERE agent_id = ? AND document_id = ?")
145
+ .get(agentId, documentId);
146
+ if (!row || row.my_text === null)
147
+ return null;
148
+ const lines = [];
149
+ const runs = lineRuns(toChunks(row.seen_text), toChunks(row.my_text));
150
+ if (runs === null) {
151
+ // Above the LCS limit. Said as "not computed" rather than degraded into a whole-file range,
152
+ // which would report every diff as an overlap and train the agent to ignore the field.
153
+ return null;
154
+ }
155
+ for (const hunk of runs) {
156
+ // The hunk's BEFORE range, which is what the diff reports its own ranges in. A pure insertion
157
+ // has an empty before-range and is attributed to the line it precedes, matching `diffStats`.
158
+ const start = hunk.aStart + 1;
159
+ const end = hunk.aEnd === hunk.aStart ? hunk.aStart + 1 : hunk.aEnd;
160
+ for (let n = start; n <= end; n++)
161
+ lines.push(n);
162
+ }
163
+ return lines;
164
+ }
165
+ /**
166
+ * The text this agent last saw, or null if it has never read this document.
167
+ *
168
+ * NULL IS NOT THE EMPTY STRING, and callers must not conflate them. Never-read means the whole
169
+ * document is new to this agent; last-saw-empty means they read it when it was empty and
170
+ * everything since is a change they can be shown against that. Returning "" for both would render
171
+ * a first read of a long document as an enormous diff the agent then treats as "what just
172
+ * changed".
173
+ */
174
+ lastSeen(agentId, documentId) {
175
+ const row = this.#store.rawDb
176
+ .prepare("SELECT seen_text FROM document_read_marks WHERE agent_id = ? AND document_id = ?")
177
+ .get(agentId, documentId);
178
+ return row === undefined ? null : row.seen_text;
179
+ }
180
+ /**
181
+ * Note that a document has unread updates. Passive — this never pushes anything.
182
+ *
183
+ * The count is REPLACED rather than incremented, and is passed in by the caller from the log,
184
+ * so the notice cannot drift from the document. An incremented counter is a second tally of a
185
+ * fact the log already holds, and the two disagree the first time a notice write is missed.
186
+ */
187
+ notice(agentId, documentId, pending, nowMs) {
188
+ if (pending <= 0) {
189
+ // Nothing pending is not a notice with zero in it — it is the absence of a notice. A row
190
+ // saying "0 unread" is an inbox entry the agent must read to discover it has nothing to read.
191
+ //
192
+ // Deleted DIRECTLY rather than through `clear()`: that method's event means "the agent
193
+ // fetched", and firing it because a count fell to zero reports a fetch that never happened.
194
+ this.#store.rawDb
195
+ .prepare("DELETE FROM document_notices WHERE agent_id = ? AND document_id = ?")
196
+ .run(agentId, documentId);
197
+ return;
198
+ }
199
+ this.#store.rawDb
200
+ .prepare(`INSERT INTO document_notices (agent_id, document_id, pending, noticed_at)
201
+ VALUES (?, ?, ?, ?)
202
+ ON CONFLICT (agent_id, document_id)
203
+ DO UPDATE SET pending = excluded.pending, noticed_at = excluded.noticed_at`)
204
+ .run(agentId, documentId, pending, nowMs);
205
+ }
206
+ /** The derived inbox section. Read-only — fetching is what clears, and that is explicit. */
207
+ pending(agentId) {
208
+ const rows = this.#store.rawDb
209
+ .prepare(`SELECT document_id, pending, noticed_at FROM document_notices
210
+ WHERE agent_id = ? ORDER BY noticed_at ASC, document_id ASC`)
211
+ .all(agentId);
212
+ return rows.map((r) => ({
213
+ documentId: r["document_id"],
214
+ pending: r["pending"],
215
+ noticedAtMs: r["noticed_at"],
216
+ }));
217
+ }
218
+ /**
219
+ * Cleared by the agent's EXPLICIT fetch, never by the aggregation that displays it.
220
+ *
221
+ * Reading the inbox and clearing the notice are different acts: an inbox render that cleared
222
+ * would drop the notice for an agent that merely glanced at a summary, and the update would then
223
+ * be unread and unannounced — invisible in both directions.
224
+ */
225
+ clear(agentId, documentId) {
226
+ const info = this.#store.rawDb
227
+ .prepare("DELETE FROM document_notices WHERE agent_id = ? AND document_id = ?")
228
+ .run(agentId, documentId);
229
+ const cleared = Number(info.changes) > 0;
230
+ // agentId included: this daemon attends several agents, and an event that names only the
231
+ // document cannot be attributed to one of them.
232
+ if (cleared)
233
+ this.#logger.info("document.notice.cleared", { agentId, documentId });
234
+ return cleared;
235
+ }
236
+ /**
237
+ * Structural counts and ranges — NO content. Lets an agent decide whether to read.
238
+ *
239
+ * `before` and `after` are the materialized text of the document at the two points; the caller
240
+ * holds the engine and therefore the materialization.
241
+ *
242
+ * Uses the SHARED line LCS, not a positional walk. The first version compared line i to line i,
243
+ * which is correct only while the line count is unchanged: inserting one line at the top of a
244
+ * three-line file reported `+4 -3` with a single range covering the whole document. The counts
245
+ * being wrong is the smaller half — `overlap` is derived from those ranges, so it became
246
+ * permanently true, and a flag that always says yes trains the agent to ignore it. Same defect
247
+ * class WRITE-1 measured, which is why there is now one LCS rather than two.
248
+ */
249
+ diffStats(documentId, before, after,
250
+ /**
251
+ * The operator's own edited line numbers. REQUIRED — pass `null` to say "not computed".
252
+ * Defaulting to `[]` made a caller that simply forgot receive `overlap: false`, the reassuring
253
+ * answer, indistinguishable from "checked, and there is no conflict". This is the one
254
+ * judgement field in an otherwise structural result.
255
+ */
256
+ myEdits, documentType) {
257
+ const a = toChunks(before);
258
+ const b = toChunks(after);
259
+ const runs = lineRuns(a, b);
260
+ if (runs === null) {
261
+ // Above the LCS limit. Said plainly rather than degraded silently into a whole-file range
262
+ // that would read as a measurement.
263
+ return {
264
+ documentId,
265
+ linesAdded: b.length,
266
+ linesRemoved: a.length,
267
+ ranges: [{ start: 1, end: Math.max(a.length, b.length) }],
268
+ keyPaths: [],
269
+ keyPathsComputed: false,
270
+ overlap: myEdits === null ? null : myEdits.length > 0,
271
+ truncated: true,
272
+ };
273
+ }
274
+ // G3: for a JSON document the DoD asks for KEY ranges, not line ranges. Produced here rather
275
+ // than left as a permanently-empty array, which reads as "no key paths changed" instead of
276
+ // "not computed" — the same absent-is-not-fine trap as the overlap default above.
277
+ let keyPaths = [];
278
+ let keyPathsComputed = false;
279
+ if (documentType === "json") {
280
+ const paths = changedKeyPaths(before, after);
281
+ if (paths !== null) {
282
+ keyPaths = paths;
283
+ keyPathsComputed = true;
284
+ }
285
+ }
286
+ let added = 0;
287
+ let removed = 0;
288
+ const ranges = [];
289
+ for (const r of runs) {
290
+ added += r.bEnd - r.bStart;
291
+ removed += r.aEnd - r.aStart;
292
+ // 1-based inclusive, over the BEFORE text — which is the text the operator's own edit line
293
+ // numbers refer to, and therefore the only coordinate space in which the overlap comparison
294
+ // means anything. A pure insertion has an empty before-range, so it is reported at the line
295
+ // it precedes rather than as a zero-width range nobody can act on.
296
+ ranges.push({ start: r.aStart + 1, end: r.aEnd === r.aStart ? r.aStart + 1 : r.aEnd });
297
+ }
298
+ const touched = new Set();
299
+ for (const r of ranges)
300
+ for (let n = r.start; n <= r.end; n++)
301
+ touched.add(n);
302
+ return {
303
+ documentId,
304
+ linesAdded: added,
305
+ linesRemoved: removed,
306
+ ranges,
307
+ keyPaths,
308
+ keyPathsComputed,
309
+ overlap: myEdits === null ? null : myEdits.some((line) => touched.has(line)),
310
+ truncated: false,
311
+ };
312
+ }
313
+ /**
314
+ * The git-like diff. An ordinary screened read — the caller screens it; this renders it.
315
+ *
316
+ * An unsupported type is REFUSED by name rather than line-diffed anyway. A diff that is silently
317
+ * wrong is worse than no diff, because the agent has no way to tell and will act on it.
318
+ */
319
+ diff(documentType, before, after, documentId) {
320
+ if (!DIFFABLE_DOCUMENT_TYPES.includes(documentType)) {
321
+ return {
322
+ ok: false,
323
+ reason: "document_type_not_diffable",
324
+ detail: `this build renders diffs for ${DIFFABLE_DOCUMENT_TYPES.join(", ")} and this document is ` +
325
+ `"${documentType}" — read the document instead of a diff that would be guesswork`,
326
+ };
327
+ }
328
+ void documentId;
329
+ if (documentType === "json") {
330
+ // A key-path diff, not a line diff. Re-serialized JSON changes shape whenever a formatter
331
+ // touches it, so a line diff reports the entire document as rewritten for a change of one
332
+ // value — which is the false "everything changed" alarm that makes an agent stop reading
333
+ // diffs at all.
334
+ const parsedPaths = changedKeyPaths(before, after);
335
+ if (parsedPaths === null) {
336
+ return {
337
+ ok: true,
338
+ documentType: "json",
339
+ diff: `! this document does not parse as JSON; showing a line diff instead\n${lineDiff(before, after)}`,
340
+ fallback: "unparseable_json_line_diff",
341
+ };
342
+ }
343
+ return { ok: true, documentType: "json", diff: jsonDiff(before, after) };
344
+ }
345
+ return { ok: true, documentType: documentType, diff: lineDiff(before, after) };
346
+ }
347
+ }
348
+ function lineDiff(before, after) {
349
+ // The SHARED LCS, same as diffStats. This renderer kept the positional walk after diffStats moved
350
+ // off it, which is the worse half to leave behind: inserting one line into a ten-line file
351
+ // rendered eighteen +/- lines, reporting the entire remainder as rewritten. That is the false
352
+ // "everything changed" alarm that makes an agent stop reading diffs at all — the exact reasoning
353
+ // that gave JSON a key-path diff, applied to markdown at last.
354
+ const a = toChunks(before);
355
+ const b = toChunks(after);
356
+ const runs = lineRuns(a, b);
357
+ if (runs === null)
358
+ return "! this document is too large to diff line-by-line";
359
+ const out = [];
360
+ let ai = 0;
361
+ for (const r of runs) {
362
+ for (; ai < r.aStart; ai++)
363
+ out.push(` ${strip(a[ai])}`);
364
+ for (let i = r.aStart; i < r.aEnd; i++)
365
+ out.push(`- ${strip(a[i])}`);
366
+ for (let j = r.bStart; j < r.bEnd; j++)
367
+ out.push(`+ ${strip(b[j])}`);
368
+ ai = r.aEnd;
369
+ }
370
+ for (; ai < a.length; ai++)
371
+ out.push(` ${strip(a[ai])}`);
372
+ return out.join("\n");
373
+ }
374
+ /** Chunks carry their own trailing newline; the rendered diff supplies its own line breaks. */
375
+ function strip(chunk) {
376
+ return chunk.endsWith("\n") ? chunk.slice(0, -1) : chunk;
377
+ }
378
+ function flatten(value, prefix = "") {
379
+ const out = new Map();
380
+ if (value === null || typeof value !== "object") {
381
+ out.set(prefix || "$", JSON.stringify(value));
382
+ return out;
383
+ }
384
+ for (const [k, v] of Object.entries(value)) {
385
+ // The separator is ESCAPED in the key. Unescaped, {"a.b": 1} and {"a": {"b": 1}} flatten to the
386
+ // same path, so a document using dotted keys reports no change where there was one — silently,
387
+ // which is the exact behaviour this unit refuses everywhere else.
388
+ const path = prefix ? `${prefix}.${k.replace(/\\/g, "\\\\").replace(/\./g, "\\.")}` : k.replace(/\\/g, "\\\\").replace(/\./g, "\\.");
389
+ for (const [p, s] of flatten(v, path))
390
+ out.set(p, s);
391
+ }
392
+ return out;
393
+ }
394
+ /** The changed key paths, or null when either side does not parse. */
395
+ function changedKeyPaths(before, after) {
396
+ let a;
397
+ let b;
398
+ try {
399
+ a = flatten(JSON.parse(before));
400
+ b = flatten(JSON.parse(after));
401
+ }
402
+ catch {
403
+ return null;
404
+ }
405
+ const paths = new Set();
406
+ for (const [path, value] of a)
407
+ if (!b.has(path) || b.get(path) !== value)
408
+ paths.add(path);
409
+ for (const [path] of b)
410
+ if (!a.has(path))
411
+ paths.add(path);
412
+ return [...paths].sort();
413
+ }
414
+ function jsonDiff(before, after) {
415
+ let a;
416
+ let b;
417
+ try {
418
+ a = flatten(JSON.parse(before));
419
+ b = flatten(JSON.parse(after));
420
+ }
421
+ catch {
422
+ // Deliberately explicit: unparseable JSON gets a stated fallback, not a silent line diff
423
+ // pretending to be a key diff. The caller sees which it got.
424
+ return `! this document does not parse as JSON; showing a line diff instead\n${lineDiff(before, after)}`;
425
+ }
426
+ const out = [];
427
+ for (const [path, value] of a) {
428
+ if (!b.has(path))
429
+ out.push(`- ${path}: ${value}`);
430
+ else if (b.get(path) !== value)
431
+ out.push(`~ ${path}: ${value} -> ${b.get(path)}`);
432
+ }
433
+ for (const [path, value] of b)
434
+ if (!a.has(path))
435
+ out.push(`+ ${path}: ${value}`);
436
+ return out.join("\n");
437
+ }
438
+ //# sourceMappingURL=document-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-notify.js","sourceRoot":"","sources":["../src/document-notify.ts"],"names":[],"mappings":"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"}