@ccmsg/cli 0.5.1 → 0.5.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/package.json
CHANGED
package/src/transcript/index.ts
CHANGED
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
} from "./fold.ts";
|
|
14
14
|
export { READ_LIMIT, readSlice } from "./read.ts";
|
|
15
15
|
export { type Appended, FOLD_TAIL_BYTES, TranscriptTail } from "./tail.ts";
|
|
16
|
-
export { Transcripts, type TranscriptsDeps } from "./transcripts.ts";
|
|
16
|
+
export { ITEMS_SNAPSHOT, Transcripts, type TranscriptsDeps } from "./transcripts.ts";
|
|
@@ -135,8 +135,12 @@ export class Classification {
|
|
|
135
135
|
read(record: Row, source: { offset: number; bytes: number }): void {
|
|
136
136
|
const type = str(record["type"]);
|
|
137
137
|
if (type === undefined || NOT_ITEMS.has(type)) return;
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
// A record the harness wrote without an id of its own still happened, and
|
|
139
|
+
// an item is pointed at by the record it came from — so where the record
|
|
140
|
+
// stands in the file stands in for the id it lacks. The `@` says which of
|
|
141
|
+
// the two it is, since a reader that groups by record must not take an
|
|
142
|
+
// address for something the harness will write again.
|
|
143
|
+
const uuid = str(record["uuid"]) ?? `@${String(source.offset)}`;
|
|
140
144
|
const at = instant(record["timestamp"]);
|
|
141
145
|
// Where in its record an item stood. One record becomes the thinking, the
|
|
142
146
|
// words and each call of a turn, and a link that named only the record
|
package/src/transcript/tail.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FSWatcher, statSync, watch } from "node:fs";
|
|
1
|
+
import { closeSync, type FSWatcher, openSync, readSync, statSync, watch } from "node:fs";
|
|
2
2
|
import { open, stat } from "node:fs/promises";
|
|
3
3
|
import { CONFIRM_POLL_MS } from "../sessions/harness.ts";
|
|
4
4
|
|
|
@@ -86,11 +86,16 @@ export class TranscriptTail {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/** Begin following, seeding the fold from the end of what is already there.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* The seed is read before this returns rather than awaited, for the reason
|
|
91
|
+
* the size is read in the constructor: a subscription's snapshot is answered
|
|
92
|
+
* in the same turn the tail is started, and what the seed settles — the
|
|
93
|
+
* fold's values, and the items a subscriber opens on — would otherwise be
|
|
94
|
+
* stated as empty and the whole existing end of the file would arrive later
|
|
95
|
+
* as though it had just been appended. */
|
|
91
96
|
async start(): Promise<void> {
|
|
92
97
|
if (this.running) return;
|
|
93
|
-
|
|
98
|
+
this.#seed();
|
|
94
99
|
try {
|
|
95
100
|
this.#watcher = watch(this.path, () => void this.refresh());
|
|
96
101
|
} catch {
|
|
@@ -116,11 +121,11 @@ export class TranscriptTail {
|
|
|
116
121
|
return this.#reading;
|
|
117
122
|
}
|
|
118
123
|
|
|
119
|
-
|
|
124
|
+
#seed(): void {
|
|
120
125
|
const size = this.#size;
|
|
121
126
|
if (size === 0) return;
|
|
122
127
|
const from = Math.max(0, size - FOLD_TAIL_BYTES);
|
|
123
|
-
const complete = whole(
|
|
128
|
+
const complete = whole(this.#sliceSync(from, size));
|
|
124
129
|
this.#offset = from + complete.byteLength;
|
|
125
130
|
// The first line is half a record whenever the read began mid-file, so it
|
|
126
131
|
// is dropped: what is read are whole records or nothing.
|
|
@@ -164,6 +169,26 @@ export class TranscriptTail {
|
|
|
164
169
|
* arithmetic puts it, inside a character as readily as before one, and
|
|
165
170
|
* decoding first would turn those bytes into a replacement character of a
|
|
166
171
|
* different length and move every offset derived from it. */
|
|
172
|
+
/** The same range, read without yielding, which is what the seed is read
|
|
173
|
+
* through: the turn that starts a tail is the turn that answers a
|
|
174
|
+
* subscription, and it has to hold the end of the file by then. Bounded by
|
|
175
|
+
* `FOLD_TAIL_BYTES` however large the transcript is. */
|
|
176
|
+
#sliceSync(from: number, to: number): Buffer {
|
|
177
|
+
if (to <= from) return Buffer.alloc(0);
|
|
178
|
+
let handle: number;
|
|
179
|
+
try {
|
|
180
|
+
handle = openSync(this.path, "r");
|
|
181
|
+
} catch {
|
|
182
|
+
return Buffer.alloc(0);
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const buffer = Buffer.alloc(to - from);
|
|
186
|
+
return buffer.subarray(0, readSync(handle, buffer, 0, buffer.length, from));
|
|
187
|
+
} finally {
|
|
188
|
+
closeSync(handle);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
167
192
|
async #slice(from: number, to: number): Promise<Buffer> {
|
|
168
193
|
if (to <= from) return Buffer.alloc(0);
|
|
169
194
|
const handle = await open(this.path, "r").catch(() => undefined);
|