@ours.network/fleet 2.1.0 → 2.1.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/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.1.
|
|
3
|
-
"buildId": "
|
|
4
|
-
"commit": "
|
|
2
|
+
"version": "2.1.1",
|
|
3
|
+
"buildId": "27ffd73f427b",
|
|
4
|
+
"commit": "7beeb5809663f045677d7ec92515f88ce0001145",
|
|
5
5
|
"dirty": false,
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-28T12:03:39.903Z",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"service.refresh-v1",
|
|
9
9
|
"managed-cli.codex-reasoning-effort-v1",
|
package/dist/session/control.js
CHANGED
|
@@ -699,13 +699,27 @@ export async function controlRequest(stateDir, request, timeoutMs = 120_000) {
|
|
|
699
699
|
const socket = createConnection(controlSocketPath(stateDir));
|
|
700
700
|
socket.setEncoding('utf8');
|
|
701
701
|
return new Promise((resolve, reject) => {
|
|
702
|
+
let settled = false, expiry;
|
|
703
|
+
const settle = () => { settled = true; clearTimeout(timer); if (expiry)
|
|
704
|
+
clearImmediate(expiry); };
|
|
705
|
+
// Timers run before pending I/O. When this process was busy past the deadline, a reply
|
|
706
|
+
// already waiting on the socket is still unread: give it the next poll phase before
|
|
707
|
+
// declaring the supervisor silent. That is one event-loop turn, not added time; a reply
|
|
708
|
+
// arriving within that turn is accepted, and a silent supervisor fails in the same turn.
|
|
702
709
|
const timer = setTimeout(() => {
|
|
703
|
-
|
|
704
|
-
|
|
710
|
+
expiry = setImmediate(() => {
|
|
711
|
+
if (settled)
|
|
712
|
+
return;
|
|
713
|
+
settle();
|
|
714
|
+
socket.destroy();
|
|
715
|
+
reject(new SessionControlError('timeout', `the role control plane did not answer '${request.command}' within ${timeoutMs}ms`));
|
|
716
|
+
});
|
|
705
717
|
}, timeoutMs);
|
|
706
718
|
let buffer = '';
|
|
707
719
|
socket.once('error', error => {
|
|
708
|
-
|
|
720
|
+
if (settled)
|
|
721
|
+
return;
|
|
722
|
+
settle();
|
|
709
723
|
const code = error.code;
|
|
710
724
|
const permissionHint = code === 'EPERM' || code === 'EACCES'
|
|
711
725
|
? `; the operating system denied access before '${request.command}' reached the supervisor. `
|
|
@@ -718,9 +732,9 @@ export async function controlRequest(stateDir, request, timeoutMs = 120_000) {
|
|
|
718
732
|
socket.on('data', chunk => {
|
|
719
733
|
buffer += chunk;
|
|
720
734
|
const newline = buffer.indexOf('\n');
|
|
721
|
-
if (newline < 0)
|
|
735
|
+
if (newline < 0 || settled)
|
|
722
736
|
return;
|
|
723
|
-
|
|
737
|
+
settle();
|
|
724
738
|
try {
|
|
725
739
|
resolve(JSON.parse(buffer.slice(0, newline)));
|
|
726
740
|
}
|
|
@@ -131,6 +131,8 @@ export declare class FleetResourceViews {
|
|
|
131
131
|
private retire;
|
|
132
132
|
private emit;
|
|
133
133
|
private coverage;
|
|
134
|
+
/** Certify each view's last projected source; never a position its capture did not read. */
|
|
135
|
+
private cover;
|
|
134
136
|
private affects;
|
|
135
137
|
private schedule;
|
|
136
138
|
private refresh;
|
|
@@ -25,6 +25,8 @@ export const RESOURCE_ASSEMBLY_BYTES = 16 * 1024 * 1024;
|
|
|
25
25
|
const CHUNK_BYTES = 256 * 1024;
|
|
26
26
|
/** Minimum spacing of activity-only follow-up captures of one view. */
|
|
27
27
|
export const ACTIVITY_CAPTURE_INTERVAL_MS = 1000;
|
|
28
|
+
/** Sparse health: a current view is qualified at most this often without data. */
|
|
29
|
+
const COVERAGE_INTERVAL_MS = 15000;
|
|
28
30
|
/** Lazily yield byte chunks so backpressure never queues an entire large record.
|
|
29
31
|
* Base64 prevents splitting a Unicode scalar from corrupting JSON/SSE parsing. */
|
|
30
32
|
export function* resourceFrames(envelope) {
|
|
@@ -263,7 +265,7 @@ export class FleetResourceViews {
|
|
|
263
265
|
this.coverage(connection).catch(close);
|
|
264
266
|
if (!connection.views.size)
|
|
265
267
|
response.write(': keepalive\n\n');
|
|
266
|
-
},
|
|
268
|
+
}, COVERAGE_INTERVAL_MS);
|
|
267
269
|
healthTimer.unref();
|
|
268
270
|
}
|
|
269
271
|
return { connectionId: id, close };
|
|
@@ -347,7 +349,11 @@ export class FleetResourceViews {
|
|
|
347
349
|
// complete batch behind any active chunk assembly and earlier data records.
|
|
348
350
|
coverage(connection) {
|
|
349
351
|
const now = Date.now();
|
|
350
|
-
|
|
352
|
+
return this.cover(connection, [...connection.views.values()].filter(view => !view.running && !view.dirty && view.covered?.position === view.source.snapshot().position && now - (view.qualifiedAt ?? 0) >= COVERAGE_INTERVAL_MS), now);
|
|
353
|
+
}
|
|
354
|
+
/** Certify each view's last projected source; never a position its capture did not read. */
|
|
355
|
+
cover(connection, candidates, now) {
|
|
356
|
+
const eligible = candidates.filter(view => this.current(connection, view) && !view.failed && view.payload !== undefined && view.covered && view.covered.health === 'healthy');
|
|
351
357
|
if (!eligible.length)
|
|
352
358
|
return Promise.resolve();
|
|
353
359
|
const views = eligible.map(view => ({ protocolVersion: 1, producerGeneration: this.producerGeneration, viewId: view.descriptor.viewId, subscriptionEpoch: view.epoch, baselineId: view.baselineId, sequence: view.sequence + 1, revision: view.revision, source: view.covered }));
|
|
@@ -502,6 +508,10 @@ export class FleetResourceViews {
|
|
|
502
508
|
return;
|
|
503
509
|
view.payload = payload;
|
|
504
510
|
}
|
|
511
|
+
// Sustained activity can keep a view dirty at every health tick while its payload is
|
|
512
|
+
// unchanged; the completed capture still qualifies the source it read.
|
|
513
|
+
else if (Date.now() - (view.qualifiedAt ?? 0) >= COVERAGE_INTERVAL_MS)
|
|
514
|
+
await this.cover(connection, [view], Date.now());
|
|
505
515
|
if (first) {
|
|
506
516
|
await this.emit(connection, view, 'ready', { baselineId: view.baselineId, source });
|
|
507
517
|
if (this.current(connection, view))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|