@twinsearth/w2m-dsh-plugin 1.1.1 → 1.1.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +44 -0
- package/codex/mcp-servers.toml +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/src/plugin/fleet-target.mjs.bak-arch2 +812 -0
- package/src/plugin/fleet-target.mjs.bak-archive +812 -0
- package/src/plugin/tools.mjs +13 -1
- package/src/relay/state.mjs +38 -3
package/src/plugin/tools.mjs
CHANGED
|
@@ -211,7 +211,7 @@ const MAX_STAGES = 16;
|
|
|
211
211
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
212
212
|
* overrides it at runtime for tests and packagers.
|
|
213
213
|
*/
|
|
214
|
-
const PLUGIN_VERSION = '1.1.
|
|
214
|
+
const PLUGIN_VERSION = '1.1.2';
|
|
215
215
|
|
|
216
216
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
217
217
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -3589,6 +3589,16 @@ export async function apply(ctx, config = {}) {
|
|
|
3589
3589
|
description: 'Number of slices for mode=split. Defaults to 1, which is the only value replicate accepts.',
|
|
3590
3590
|
default: 1,
|
|
3591
3591
|
},
|
|
3592
|
+
include_offline: {
|
|
3593
|
+
type: 'boolean',
|
|
3594
|
+
// v1.1.2. The relay now leases only devices that are online and not silent by default; this asks it to include
|
|
3595
|
+
// the machines that are down as well, which is what an operator wants when queueing work for a machine that
|
|
3596
|
+
// is currently switched off. Default false, because a stale lease is what kept every aggregate at `partial`.
|
|
3597
|
+
description:
|
|
3598
|
+
'Default false: the relay leases only the machines that are online and have not gone silent. Set true to ' +
|
|
3599
|
+
'include machines that are currently down (their lease will simply expire if they do not come back).',
|
|
3600
|
+
default: false,
|
|
3601
|
+
},
|
|
3592
3602
|
cwd_rel: {
|
|
3593
3603
|
type: 'string',
|
|
3594
3604
|
description: 'Working directory relative to the project root, with forward slashes. Defaults to ".".',
|
|
@@ -4023,6 +4033,8 @@ export async function apply(ctx, config = {}) {
|
|
|
4023
4033
|
// in play. Spread after the caller's own field above so the caller always wins even if a
|
|
4024
4034
|
// future edit makes both possible.
|
|
4025
4035
|
...selectionFields,
|
|
4036
|
+
// Named on the wire only when asked, so a default dispatch sends the same bytes as it always did.
|
|
4037
|
+
...(args?.include_offline === true ? { include_offline: true } : {}),
|
|
4026
4038
|
// Only for pipeline. The relay ignores `stages` under the other modes and the validation
|
|
4027
4039
|
// above refuses the combination, so this can never silently mean nothing.
|
|
4028
4040
|
...(mode === 'pipeline' && stagesPayload !== null ? { stages: stagesPayload } : {}),
|
package/src/relay/state.mjs
CHANGED
|
@@ -1257,6 +1257,22 @@ export class RabbitState {
|
|
|
1257
1257
|
* (a test, or a caller that never runs the sweep) cannot report a departed machine as present.
|
|
1258
1258
|
* The sweep is still what fixes the flag and broadcasts; this only refuses to repeat a stale `true`.
|
|
1259
1259
|
*/
|
|
1260
|
+
/**
|
|
1261
|
+
* Whether this device is usable right now: its flag is set AND it is not silent.
|
|
1262
|
+
*
|
|
1263
|
+
* \`device.online === true\` alone is not the answer -- the flag stays true until the sweep runs, so a machine whose
|
|
1264
|
+
* agent stopped heartbeating was still a dispatch target. The same expression appeared in \`deviceStatus\`,
|
|
1265
|
+
* \`publicDevice\` and (v1.1.2) the default target list; one definition keeps the list and the dispatch from
|
|
1266
|
+
* disagreeing about which machines exist.
|
|
1267
|
+
*
|
|
1268
|
+
* \`silentMs === null\` means no contact has ever been observed, and that is NOT silent.
|
|
1269
|
+
*/
|
|
1270
|
+
isOnlineDevice(device, nowMs = this.nowMs()) {
|
|
1271
|
+
if (!device || device.online !== true) return false;
|
|
1272
|
+
const silentMs = this.silenceAgeMs(device, nowMs);
|
|
1273
|
+
return !(silentMs !== null && silentMs >= this.silenceMs);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1260
1276
|
deviceStatus(machineId, nowMs = this.nowMs()) {
|
|
1261
1277
|
const device = this.devices.get(machineId);
|
|
1262
1278
|
if (!device) return null;
|
|
@@ -1270,7 +1286,7 @@ export class RabbitState {
|
|
|
1270
1286
|
relay_id: this.relayId,
|
|
1271
1287
|
connected: (device.streams ?? 0) > 0,
|
|
1272
1288
|
streams: device.streams ?? 0,
|
|
1273
|
-
online: device
|
|
1289
|
+
online: this.isOnlineDevice(device),
|
|
1274
1290
|
/**
|
|
1275
1291
|
* Why this machine is not usable, when it is not. `null` for a healthy one.
|
|
1276
1292
|
*
|
|
@@ -1340,7 +1356,7 @@ export class RabbitState {
|
|
|
1340
1356
|
* the stored flag and broadcasts `peer.bye`; this expression makes the read agree with it even
|
|
1341
1357
|
* between sweeps, so no caller can observe the stale value at all.
|
|
1342
1358
|
*/
|
|
1343
|
-
online: device
|
|
1359
|
+
online: this.isOnlineDevice(device),
|
|
1344
1360
|
streams: device.streams,
|
|
1345
1361
|
/**
|
|
1346
1362
|
* v0.9.1: why this machine is not usable, when it is not.
|
|
@@ -1560,9 +1576,27 @@ export class RabbitState {
|
|
|
1560
1576
|
//
|
|
1561
1577
|
// Resolved before the task literal because the literal records it. (`targets` is computed below,
|
|
1562
1578
|
// so the executor is re-validated against it after that.)
|
|
1579
|
+
/**
|
|
1580
|
+
* v1.1.2: a dispatch that names no machines goes to the machines that are **online**.
|
|
1581
|
+
*
|
|
1582
|
+
* WHY THIS IS THE DEFAULT: this line used to return every paired device, including one whose agent stopped
|
|
1583
|
+
* heartbeating days ago. The relay still built it a lease, that lease expired, and \`partial\` became the only
|
|
1584
|
+
* verdict the task could reach -- so a fleet whose live machines agreed reported "incomplete" forever
|
|
1585
|
+
* (observed 2026-10-17: \`ok: 3, expired: 4\`). Liveness is the relay's own knowledge, which is why the fix
|
|
1586
|
+
* belongs here and not in a client-side pre-read that would add a round trip to every dispatch.
|
|
1587
|
+
*
|
|
1588
|
+
* \`include_offline: true\` restores the old behaviour for the operator who really does want to queue work for a
|
|
1589
|
+
* machine that is down. A device that comes back is online again and rejoins the default set with no bookkeeping:
|
|
1590
|
+
* nothing is deleted, and the only state consulted is \`online\`.
|
|
1591
|
+
*/
|
|
1563
1592
|
const targetIds = Array.isArray(input.target_machines) && input.target_machines.length > 0
|
|
1564
1593
|
? input.target_machines
|
|
1565
|
-
:
|
|
1594
|
+
: input.include_offline === true || mode === 'broadcast'
|
|
1595
|
+
// broadcast is NOT a fan-out: it names one executor and tells the rest the outcome. Narrowing the default set
|
|
1596
|
+
// here would change WHICH machine is elected (or make the election impossible when the fixture's devices are
|
|
1597
|
+
// not marked online), so the default set stays every paired device for this mode only.
|
|
1598
|
+
? [...this.devices.keys()]
|
|
1599
|
+
: [...this.devices.entries()].filter(([, d]) => this.isOnlineDevice(d)).map(([id]) => id);
|
|
1566
1600
|
const executorMachineId = mode === 'broadcast'
|
|
1567
1601
|
? (typeof input.executor_machine_id === 'string' && input.executor_machine_id !== ''
|
|
1568
1602
|
? input.executor_machine_id
|
|
@@ -1587,6 +1621,7 @@ export class RabbitState {
|
|
|
1587
1621
|
base_tree: baseTree,
|
|
1588
1622
|
requirements: input.requirements ?? {},
|
|
1589
1623
|
compare_policy: input.compare_policy ?? {},
|
|
1624
|
+
include_offline: input.include_offline === true,
|
|
1590
1625
|
halt,
|
|
1591
1626
|
created_by: input.created_by ?? null,
|
|
1592
1627
|
created_at_ms: now,
|