@north-light/crouter 0.3.181 → 0.3.182
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.
|
@@ -18,5 +18,9 @@ export declare function readBrokerCursor(nodeId: string): BrokerInboxEntryId | u
|
|
|
18
18
|
export declare function readBrokerInboxSince(nodeId: string, cursor?: string): BrokerInboxEntry[];
|
|
19
19
|
export declare function readBrokerInboxRange(nodeId: string, after: string | undefined, through: string): BrokerInboxEntry[];
|
|
20
20
|
export declare function readBrokerCanceledEntryIds(nodeId: string): Set<BrokerInboxEntryId>;
|
|
21
|
+
/** The node id a canonical report ref points at, or undefined when the ref is
|
|
22
|
+
* absent, absolute, or not a report path. Callers use it to tell whether the
|
|
23
|
+
* report-node projection they hold can still resolve the ref. */
|
|
24
|
+
export declare function reportRefNodeId(ref: string | undefined): string | undefined;
|
|
21
25
|
/** Render the existing inbox digest wording with daemon-projected report existence. */
|
|
22
26
|
export declare function coalesceBrokerInbox(entries: readonly BrokerInboxEntry[], reportNodes: ReadonlyMap<string, BrokerReportNodeDTO>): string;
|
|
@@ -101,16 +101,25 @@ function clipBody(body) {
|
|
|
101
101
|
}
|
|
102
102
|
return { text: text.trimEnd(), clipped };
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
/** The node id a canonical report ref points at, or undefined when the ref is
|
|
105
|
+
* absent, absolute, or not a report path. Callers use it to tell whether the
|
|
106
|
+
* report-node projection they hold can still resolve the ref. */
|
|
107
|
+
export function reportRefNodeId(ref) {
|
|
108
|
+
if (ref === undefined || ref.startsWith('/'))
|
|
109
|
+
return undefined;
|
|
110
|
+
const separator = ref.indexOf(':');
|
|
108
111
|
if (separator <= 0)
|
|
112
|
+
return undefined;
|
|
113
|
+
const relpath = ref.slice(separator + 1);
|
|
114
|
+
if (!relpath.startsWith('reports/') || relpath.includes('..') || relpath.startsWith('/'))
|
|
115
|
+
return undefined;
|
|
116
|
+
return ref.slice(0, separator);
|
|
117
|
+
}
|
|
118
|
+
function inlineReport(entry, reportNodes) {
|
|
119
|
+
const nodeId = reportRefNodeId(entry.ref);
|
|
120
|
+
if (nodeId === undefined || !reportNodes.has(nodeId))
|
|
109
121
|
return null;
|
|
110
|
-
const
|
|
111
|
-
const relpath = entry.ref.slice(separator + 1);
|
|
112
|
-
if (!reportNodes.has(nodeId) || !relpath.startsWith('reports/') || relpath.includes('..') || relpath.startsWith('/'))
|
|
113
|
-
return null;
|
|
122
|
+
const relpath = entry.ref.slice(entry.ref.indexOf(':') + 1);
|
|
114
123
|
const path = `${nodeDir(nodeId)}/${relpath}`;
|
|
115
124
|
try {
|
|
116
125
|
const body = readFileSync(path, 'utf8');
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// return is only a handoff. Exact cursor persistence at agent_settled is the
|
|
6
6
|
// durable boundary; an uncommitted process exit is recovered by rereading from
|
|
7
7
|
// the unchanged cursor.
|
|
8
|
-
import { coalesceBrokerInbox, readBrokerCanceledEntryIds, readBrokerCursor, readBrokerInboxSince, } from '../core/runtime/broker/inbox.js';
|
|
8
|
+
import { coalesceBrokerInbox, readBrokerCanceledEntryIds, readBrokerCursor, readBrokerInboxSince, reportRefNodeId, } from '../core/runtime/broker/inbox.js';
|
|
9
9
|
import { advanceBrokerInboxCursor, brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
10
10
|
import { emitEvent } from '../core/events/emit.js';
|
|
11
11
|
import { errorClassFromError } from '../core/events/errors.js';
|
|
@@ -186,6 +186,8 @@ class CanvasInboxWatcher {
|
|
|
186
186
|
fatalError;
|
|
187
187
|
fatalEscaped = false;
|
|
188
188
|
reportNodes = new Map();
|
|
189
|
+
reportNodesAsked = new Set();
|
|
190
|
+
reportNodesRefreshing = false;
|
|
189
191
|
constructor(pi, cadence, generation) {
|
|
190
192
|
this.pi = pi;
|
|
191
193
|
this.cadence = cadence;
|
|
@@ -288,6 +290,7 @@ class CanvasInboxWatcher {
|
|
|
288
290
|
async refreshReportNodes(nodeId) {
|
|
289
291
|
if (nodeId === undefined)
|
|
290
292
|
return;
|
|
293
|
+
this.reportNodesRefreshing = true;
|
|
291
294
|
try {
|
|
292
295
|
const state = await brokerExtensionState(nodeId);
|
|
293
296
|
if (!this.canMutate())
|
|
@@ -297,6 +300,33 @@ class CanvasInboxWatcher {
|
|
|
297
300
|
catch {
|
|
298
301
|
// Report bodies remain canonical pointers until the daemon projection is available.
|
|
299
302
|
}
|
|
303
|
+
finally {
|
|
304
|
+
this.reportNodesRefreshing = false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/** True when delivery must wait a tick for a report-node projection refresh.
|
|
308
|
+
* The projection captured at session_start omits every node created since —
|
|
309
|
+
* each `crtr human ask` bridge and each child this node spawns — so their
|
|
310
|
+
* reports would render as bare refs instead of inlined bodies. One refresh
|
|
311
|
+
* per unknown node id keeps a genuinely missing node from stalling delivery. */
|
|
312
|
+
refreshForUnknownReportRefs() {
|
|
313
|
+
if (this.reportNodesRefreshing)
|
|
314
|
+
return true;
|
|
315
|
+
const unknown = [];
|
|
316
|
+
for (const entry of this.buffer) {
|
|
317
|
+
const refNodeId = reportRefNodeId(entry.ref);
|
|
318
|
+
if (refNodeId === undefined)
|
|
319
|
+
continue;
|
|
320
|
+
if (this.reportNodes.has(refNodeId) || this.reportNodesAsked.has(refNodeId))
|
|
321
|
+
continue;
|
|
322
|
+
unknown.push(refNodeId);
|
|
323
|
+
}
|
|
324
|
+
if (unknown.length === 0)
|
|
325
|
+
return false;
|
|
326
|
+
for (const refNodeId of unknown)
|
|
327
|
+
this.reportNodesAsked.add(refNodeId);
|
|
328
|
+
void this.refreshReportNodes(currentNodeId());
|
|
329
|
+
return this.reportNodesRefreshing;
|
|
300
330
|
}
|
|
301
331
|
arm() {
|
|
302
332
|
if (this.armed)
|
|
@@ -343,6 +373,7 @@ class CanvasInboxWatcher {
|
|
|
343
373
|
this.cursor = undefined;
|
|
344
374
|
this.durableCursor = undefined;
|
|
345
375
|
this.reportNodes.clear();
|
|
376
|
+
this.reportNodesAsked.clear();
|
|
346
377
|
this.pendingCommit = undefined;
|
|
347
378
|
this.nodeId = undefined;
|
|
348
379
|
this.lastCtx = undefined;
|
|
@@ -509,6 +540,8 @@ class CanvasInboxWatcher {
|
|
|
509
540
|
this.lastArrival = Date.now();
|
|
510
541
|
}
|
|
511
542
|
if (this.buffer.length > 0 && Date.now() - this.lastArrival >= this.cadence.debounceMs) {
|
|
543
|
+
if (this.refreshForUnknownReportRefs())
|
|
544
|
+
return;
|
|
512
545
|
this.flushOrdinary(nodeId);
|
|
513
546
|
}
|
|
514
547
|
}
|
package/package.json
CHANGED
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.182",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.182",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|