@ccmsg/cli 0.14.0 → 0.14.1
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 +1 -1
- package/src/instance/instance.ts +3 -1
- package/src/messaging/inbox.ts +35 -3
package/package.json
CHANGED
package/src/instance/instance.ts
CHANGED
|
@@ -564,7 +564,9 @@ export class Instance {
|
|
|
564
564
|
},
|
|
565
565
|
});
|
|
566
566
|
|
|
567
|
-
const inbox = new Inbox(inboxPath(paths.stateDir))
|
|
567
|
+
const inbox = new Inbox(inboxPath(paths.stateDir), (msg, fields) => {
|
|
568
|
+
this.log.write(msg, fields);
|
|
569
|
+
});
|
|
568
570
|
inbox.load();
|
|
569
571
|
this.#persisted.push(inbox);
|
|
570
572
|
// Route (a) is the harness's own way in (DESIGN §6.5): Claude Code's messaging
|
package/src/messaging/inbox.ts
CHANGED
|
@@ -4,10 +4,12 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import {
|
|
5
5
|
INBOX_MAX_PER_SID,
|
|
6
6
|
INBOX_RETENTION_MS,
|
|
7
|
-
|
|
7
|
+
InboxMessage,
|
|
8
8
|
type InboxRemovedReason,
|
|
9
|
-
|
|
9
|
+
isValid,
|
|
10
|
+
Sid,
|
|
10
11
|
type Timestamp,
|
|
12
|
+
validationErrors,
|
|
11
13
|
} from "@ccmsg/protocol";
|
|
12
14
|
|
|
13
15
|
export const INBOX_FILE = "inbox.jsonl";
|
|
@@ -50,7 +52,12 @@ export class Inbox {
|
|
|
50
52
|
* subscribed for them to be news to. */
|
|
51
53
|
#onRemoved?: (mid: string, reason: InboxRemovedReason) => void;
|
|
52
54
|
|
|
53
|
-
constructor(
|
|
55
|
+
constructor(
|
|
56
|
+
private readonly file: string,
|
|
57
|
+
/** Where a line the replay could not keep is named. Absent in the tests
|
|
58
|
+
* that are about the holding rather than about what is said of it. */
|
|
59
|
+
private readonly log: (message: string, fields: Record<string, unknown>) => void = () => {},
|
|
60
|
+
) {}
|
|
54
61
|
|
|
55
62
|
/** Hear about messages leaving. */
|
|
56
63
|
onRemoved(told: (mid: string, reason: InboxRemovedReason) => void): void {
|
|
@@ -79,6 +86,7 @@ export class Inbox {
|
|
|
79
86
|
// The last line of a file the daemon was killed while writing.
|
|
80
87
|
continue;
|
|
81
88
|
}
|
|
89
|
+
if (record.v === "add" && !this.#stateable(record.sid, record.message)) continue;
|
|
82
90
|
this.#replay(record);
|
|
83
91
|
}
|
|
84
92
|
this.#expire(now);
|
|
@@ -168,6 +176,30 @@ export class Inbox {
|
|
|
168
176
|
return highest;
|
|
169
177
|
}
|
|
170
178
|
|
|
179
|
+
/** Whether a line read back is a message the contract can state.
|
|
180
|
+
*
|
|
181
|
+
* The file outlives the contract that wrote it, and what is held is answered
|
|
182
|
+
* to a person as rows of the `inbox` topic — so a single line the contract
|
|
183
|
+
* has since outgrown, replayed as if it were current, is a frame the reader
|
|
184
|
+
* refuses and a whole view lost for it. An instance states only what the
|
|
185
|
+
* contract can say, about its own file as much as about anything else.
|
|
186
|
+
*
|
|
187
|
+
* Dropped rather than mended: the message is the sender's words and the
|
|
188
|
+
* contract is what says how they are spelled, so there is nothing here that
|
|
189
|
+
* could write a spelling the contract would accept without inventing it. It
|
|
190
|
+
* leaves through the compaction that follows the replay, which writes back
|
|
191
|
+
* only what is held; nothing is appended and no removal is stated, since a
|
|
192
|
+
* replay has nobody subscribed to hear one and no `mid` the contract would
|
|
193
|
+
* take to name it by. */
|
|
194
|
+
#stateable(sid: unknown, message: unknown): boolean {
|
|
195
|
+
const why = isValid(Sid, sid)
|
|
196
|
+
? validationErrors(InboxMessage, message)
|
|
197
|
+
: [`sid: ${JSON.stringify(sid)} is no session id`];
|
|
198
|
+
if (why.length === 0) return true;
|
|
199
|
+
this.log("dropped an inbox record the contract cannot state", { sid, why });
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
171
203
|
#replay(record: Record_): void {
|
|
172
204
|
if (record.v === "add") {
|
|
173
205
|
const held = this.#held.get(record.sid) ?? [];
|