@twinsearth/w2m-dsh-plugin 2.0.6 → 2.0.8
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 +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +24 -6
- package/codex/mcp-servers.toml +1 -1
- package/docs/acceptance/2.0.7/RELEASE-2070.json +21 -0
- package/docs/acceptance/2.0.8/RELEASE-2080.json +21 -0
- package/docs/plans/IM2A-2.2.2-PLAN.md +293 -0
- package/lib/client.js +1 -1
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/src/agent/chacha.mjs +93 -0
- package/src/agent/crypto.mjs +64 -29
- package/src/agent/transfer/ferry.mjs +195 -0
- package/src/agent/transfer/index.mjs +4 -0
- package/src/agent/transfer/manifest.mjs +92 -0
- package/src/agent/transfer/object-store.mjs +144 -0
- package/src/agent/transfer/publish.mjs +76 -0
- package/src/agent/transfer/reference.mjs +97 -0
- package/src/agent/transfer/want-block.mjs +89 -0
- package/src/game/xiangqi.mjs +217 -0
- package/src/plugin/chat-v2-gate.mjs +40 -0
- package/src/plugin/fleet-binding.mjs +105 -0
- package/src/plugin/fleet-chat-route.mjs +32 -1
- package/src/plugin/tools.mjs +42 -8
package/src/plugin/tools.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { FAILOVER_DEFAULTS, createRelayFailover, relayPool } from './relay-failover.mjs';
|
|
1
|
+
import { FAILOVER_DEFAULTS, createRelayFailover, relayPool } from './relay-failover.mjs';
|
|
2
|
+
import { diagnoseFleetBinding, shouldRejoin } from './fleet-binding.mjs';
|
|
2
3
|
import { DEFAULT_BOOTSTRAP_URL, DEFAULT_BOOTSTRAP_OPERATOR_KEY_PEM } from './bootstrap.mjs';
|
|
3
4
|
/**
|
|
4
5
|
* DSH: Windows2MacO - the DSH Cordis plugin.
|
|
@@ -206,7 +207,8 @@ import { buildBoard } from './task-graph.mjs';
|
|
|
206
207
|
import { verifyEnvelopeSignature } from '../util/envelope-signature.mjs';
|
|
207
208
|
import { createAskStore } from './ask-store.mjs';
|
|
208
209
|
import { deriveTurns } from './turn.mjs';
|
|
209
|
-
import { decryptChatMessage, deriveChatKey, encryptChatText, isEncrypted } from '../util/chat-crypto.mjs';
|
|
210
|
+
import { decryptChatMessage, deriveChatKey, encryptChatText, encryptChatTextV2, isEncrypted } from '../util/chat-crypto.mjs';
|
|
211
|
+
import { chatEncV2Supported } from './chat-v2-gate.mjs';
|
|
210
212
|
|
|
211
213
|
/**
|
|
212
214
|
* v1.2.6 reliability: two small files beside the plugin's state.
|
|
@@ -289,7 +291,7 @@ const MAX_STAGES = 16;
|
|
|
289
291
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
290
292
|
* overrides it at runtime for tests and packagers.
|
|
291
293
|
*/
|
|
292
|
-
const PLUGIN_VERSION = '2.0.
|
|
294
|
+
const PLUGIN_VERSION = '2.0.8';
|
|
293
295
|
|
|
294
296
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
295
297
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -4996,6 +4998,13 @@ const result = await request({
|
|
|
4996
4998
|
};
|
|
4997
4999
|
})();
|
|
4998
5000
|
|
|
5001
|
+
const fleetBinding = await diagnoseFleetBinding({
|
|
5002
|
+
relayUrl: cfg.rabbitUrl,
|
|
5003
|
+
token: device.device_token,
|
|
5004
|
+
machineId: device.machine_id,
|
|
5005
|
+
fleetKey: cfg.fleetKey,
|
|
5006
|
+
});
|
|
5007
|
+
|
|
4999
5008
|
return JSON.stringify(
|
|
5000
5009
|
{
|
|
5001
5010
|
ok: true,
|
|
@@ -5019,7 +5028,8 @@ const result = await request({
|
|
|
5019
5028
|
*/
|
|
5020
5029
|
rabbit_source: cfg.rabbitSource,
|
|
5021
5030
|
rabbit_url: cfg.rabbitUrl,
|
|
5022
|
-
p2p: p2pStatus,
|
|
5031
|
+
p2p: p2pStatus,
|
|
5032
|
+
fleet: fleetBinding,
|
|
5023
5033
|
rtt,
|
|
5024
5034
|
config: {
|
|
5025
5035
|
rabbitUrl: cfg.rabbitUrl,
|
|
@@ -5029,7 +5039,8 @@ const result = await request({
|
|
|
5029
5039
|
projectDir: cfg.projectDir,
|
|
5030
5040
|
autoStartAgent: cfg.autoStartAgent,
|
|
5031
5041
|
allowedCommands: cfg.allowedCommands,
|
|
5032
|
-
pairingCode_configured: cfg.pairingCode !== null,
|
|
5042
|
+
pairingCode_configured: cfg.pairingCode !== null,
|
|
5043
|
+
fleetKey_configured: cfg.fleetKey !== null,
|
|
5033
5044
|
p2pMode: cfg.p2pMode,
|
|
5034
5045
|
// The resolved list, shared server first, exactly as the node will query it.
|
|
5035
5046
|
stunServers: cfg.stunServers,
|
|
@@ -6989,7 +7000,18 @@ hint: 'the local fleet-memory.md is unchanged; action read/show still reads loca
|
|
|
6989
7000
|
*/
|
|
6990
7001
|
const chatKey = deriveChatKey(cfg.fleetKey ?? resolvedFleetKey.value ?? null);
|
|
6991
7002
|
const plainText = typeof args?.text === 'string' ? args.text : '';
|
|
6992
|
-
const
|
|
7003
|
+
const idempotencyKey = typeof args?.idempotency_key === 'string' && args.idempotency_key.trim() !== ''
|
|
7004
|
+
? args.idempotency_key.trim()
|
|
7005
|
+
: 'spool-' + Date.now() + '-' + Math.random().toString(36).slice(2);
|
|
7006
|
+
// A7: v2 only when the relay advertises chat-enc-v2 AND this machine has an id to bind. Otherwise
|
|
7007
|
+
// send v1 (every relay accepts it) rather than an unverifiable v2 envelope.
|
|
7008
|
+
const canV2 = chatKey !== null && typeof cfg.machineId === 'string' && cfg.machineId !== ''
|
|
7009
|
+
&& await chatEncV2Supported({ rabbitUrl: cfg.rabbitUrl ?? null });
|
|
7010
|
+
const sealed = chatKey === null
|
|
7011
|
+
? null
|
|
7012
|
+
: (canV2
|
|
7013
|
+
? encryptChatTextV2(chatKey, plainText, { sessionId, machineId: cfg.machineId, messageId: idempotencyKey })
|
|
7014
|
+
: encryptChatText(chatKey, plainText));
|
|
6993
7015
|
/**
|
|
6994
7016
|
* v1.2.6 reliability: an unreachable Rabbit does not lose the message. The exact body that could not be sent is
|
|
6995
7017
|
* spooled to disk and replayed with the SAME idempotency key next time, so a message the relay actually received
|
|
@@ -7001,7 +7023,7 @@ hint: 'the local fleet-memory.md is unchanged; action read/show still reads loca
|
|
|
7001
7023
|
...(sealed !== null && sealed.ok === true ? { enc: sealed.enc } : {}),
|
|
7002
7024
|
...addressing,
|
|
7003
7025
|
...(mentions.length === 0 ? {} : { mentions }),
|
|
7004
|
-
...
|
|
7026
|
+
...{ idempotency_key: idempotencyKey },
|
|
7005
7027
|
...(typeof args?.reply_state === 'string' && (args.reply_state === 'answered' || args.reply_state === 'refused') ? { reply_state: args.reply_state } : {}),
|
|
7006
7028
|
};
|
|
7007
7029
|
let posted = null;
|
|
@@ -7058,7 +7080,7 @@ hint: 'the local fleet-memory.md is unchanged; action read/show still reads loca
|
|
|
7058
7080
|
const listKey = deriveChatKey(cfg.fleetKey ?? resolvedFleetKey.value ?? null);
|
|
7059
7081
|
const messages = rawMessages.map((message) => {
|
|
7060
7082
|
if (!isEncrypted(message)) return message;
|
|
7061
|
-
const opened = decryptChatMessage(listKey, message);
|
|
7083
|
+
const opened = decryptChatMessage(listKey, message, { sessionId: String(query.session_id ?? message.session_id ?? ''), machineId: typeof message.machine_id === 'string' ? message.machine_id : undefined });
|
|
7062
7084
|
if (opened.ok === true) return { ...message, text: opened.text, decrypted: true };
|
|
7063
7085
|
return { ...message, text: '', decrypted: false, encrypted: true, decrypt_error: opened.code };
|
|
7064
7086
|
});
|
|
@@ -8017,6 +8039,18 @@ async function startLocalStack(ctx, cfg) {
|
|
|
8017
8039
|
if (identityOptions.identity !== undefined && identityOptions.identity !== null) identityOptions.identity.device_token = null;
|
|
8018
8040
|
ctx.logger?.warn?.('w2m: stored device token was rejected by ' + relayForToken + ' (HTTP ' + probe.status + '); pairing again with the fleet key');
|
|
8019
8041
|
}
|
|
8042
|
+
if (alreadyPaired && fleetKeyFromConfig !== null) {
|
|
8043
|
+
const binding = await diagnoseFleetBinding({
|
|
8044
|
+
relayUrl: relayForToken,
|
|
8045
|
+
token: existingToken,
|
|
8046
|
+
machineId: loaded.identity.machine_id,
|
|
8047
|
+
fleetKey: fleetKeyFromConfig,
|
|
8048
|
+
});
|
|
8049
|
+
if (shouldRejoin({ token: existingToken, fleetId: binding.fleet_id, fleetKey: fleetKeyFromConfig })) {
|
|
8050
|
+
alreadyPaired = false;
|
|
8051
|
+
ctx.logger?.warn?.('w2m: FLEET_UNBOUND (token valid, fleet_id=null); re-admitting with the configured fleet key');
|
|
8052
|
+
}
|
|
8053
|
+
}
|
|
8020
8054
|
} catch { /* network error: keep the token, do not force a re-pair */ }
|
|
8021
8055
|
}
|
|
8022
8056
|
}
|