instar 1.3.103 → 1.3.105
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +95 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/core/TopicPlacementPinStore.d.ts +37 -0
- package/dist/core/TopicPlacementPinStore.d.ts.map +1 -0
- package/dist/core/TopicPlacementPinStore.js +95 -0
- package/dist/core/TopicPlacementPinStore.js.map +1 -0
- package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.js +6 -1
- package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.d.ts +7 -0
- package/dist/scheduler/MentorOnboardingTick.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.js +8 -3
- package/dist/scheduler/MentorOnboardingTick.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +16 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +13 -0
- package/dist/server/middleware.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.104.md +58 -0
- package/upgrades/1.3.105.md +64 -0
- package/upgrades/side-effects/mentor-stage-a-robustness.md +57 -0
- package/upgrades/side-effects/mesh-rpc-auth-and-transfer-activation.md +72 -0
- package/upgrades/side-effects/mesh-signing-key-filename-fix.md +54 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmSH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmSH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAwvDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+7OtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -308,6 +308,10 @@ let _topicResumeMap = null;
|
|
|
308
308
|
// is byte-identical to today's always-local dispatch. Set once in startServer().
|
|
309
309
|
let _sessionRouter = null;
|
|
310
310
|
let _sessionPoolStage = () => 'dark';
|
|
311
|
+
/** Multi-Machine Session Pool §L4: per-topic placement pin store ("move this to <nickname>"). */
|
|
312
|
+
let _topicPinStore = null;
|
|
313
|
+
/** Recognize + apply a "move/run this on <nickname>" relocation on inbound; returns handled=true when the message WAS a relocation command (so it must not also be dispatched). */
|
|
314
|
+
let _tryNicknameRelocation = null;
|
|
311
315
|
/** Per-topic framework override (claude-code | codex-cli). Populated from
|
|
312
316
|
* `config.topicFrameworks` at server boot. Boot-immutable; runtime
|
|
313
317
|
* mutations go through `_topicFrameworksStore` instead so they persist
|
|
@@ -1173,12 +1177,29 @@ getHubDeps) {
|
|
|
1173
1177
|
// entirely → byte-identical to single-machine dispatch. Any error falls back
|
|
1174
1178
|
// to the local path below (fail-safe). The live-transfer behavior is gated by
|
|
1175
1179
|
// the staged rollout (StageAdvancer); shadow records ownership but stays local.
|
|
1180
|
+
//
|
|
1181
|
+
// §L4 transfer-by-nickname: FIRST, intercept an explicit "move/run this on
|
|
1182
|
+
// <nickname>" relocation command. If recognized, it sets the topic's
|
|
1183
|
+
// placement pin (+ releases local ownership) and is fully handled here — the
|
|
1184
|
+
// command message itself is NOT dispatched to a session. Subsequent messages
|
|
1185
|
+
// for the topic then re-place onto the pinned machine via route() below.
|
|
1186
|
+
if (_tryNicknameRelocation && _sessionPoolStage() !== 'dark') {
|
|
1187
|
+
try {
|
|
1188
|
+
const relo = await _tryNicknameRelocation(topicId, text);
|
|
1189
|
+
if (relo.handled)
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
catch (err) {
|
|
1193
|
+
console.warn(`[session-pool] nickname relocation error for topic ${topicId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1176
1196
|
if (_sessionRouter && _sessionPoolStage() !== 'dark') {
|
|
1177
1197
|
try {
|
|
1178
1198
|
const outcome = await _sessionRouter.route({
|
|
1179
1199
|
sessionKey: String(topicId),
|
|
1180
1200
|
messageId: String(msg.id),
|
|
1181
1201
|
payload: text,
|
|
1202
|
+
topicMetadata: _topicPinStore?.asTopicMetadata(String(topicId)),
|
|
1182
1203
|
});
|
|
1183
1204
|
if (outcome.action === 'forwarded' || outcome.action === 'duplicate') {
|
|
1184
1205
|
console.log(`[session-pool] topic ${topicId} handled by owner ${outcome.owner ?? '?'} (${outcome.action}) — not dispatching locally`);
|
|
@@ -2193,9 +2214,20 @@ export async function startServer(options) {
|
|
|
2193
2214
|
let localSigningKeyPem = '';
|
|
2194
2215
|
if (coordinator.enabled && coordinator.identity) {
|
|
2195
2216
|
try {
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2217
|
+
// The canonical signing-key filename is `signing-key.pem` (MachineIdentity.SIGNING_KEY_FILE,
|
|
2218
|
+
// what every normally-created install has + what idMgr.loadSigningKey reads). This loader
|
|
2219
|
+
// historically hard-coded `signing-private.pem`, which only EXISTS on installs that were
|
|
2220
|
+
// propagated with that (non-canonical) name — so a normally-created machine got an EMPTY
|
|
2221
|
+
// localSigningKeyPem, its MeshRpcClient then signed every cross-machine command with no key,
|
|
2222
|
+
// the send threw, and it could not PULL/transfer to any peer (while still RECEIVING fine,
|
|
2223
|
+
// since receive verifies the OTHER machine's key). Try the canonical name first, then fall
|
|
2224
|
+
// back to the legacy/propagated name so both layouts work.
|
|
2225
|
+
for (const name of ['signing-key.pem', 'signing-private.pem']) {
|
|
2226
|
+
const keyPath = path.join(config.stateDir, 'machine', name);
|
|
2227
|
+
if (fs.existsSync(keyPath)) {
|
|
2228
|
+
localSigningKeyPem = fs.readFileSync(keyPath, 'utf-8');
|
|
2229
|
+
break;
|
|
2230
|
+
}
|
|
2199
2231
|
}
|
|
2200
2232
|
}
|
|
2201
2233
|
catch { /* @silent-fallback-ok — signing key optional */ }
|
|
@@ -8507,6 +8539,66 @@ export async function startServer(options) {
|
|
|
8507
8539
|
}
|
|
8508
8540
|
};
|
|
8509
8541
|
console.log(pc.green(' SessionRouter wired (L4) — inert until rollout stage advances past dark'));
|
|
8542
|
+
// ── L4 transfer-by-nickname activation: the "move/run this on <nickname>"
|
|
8543
|
+
// trigger. The recognizer + planner are pure units; this wires them to the
|
|
8544
|
+
// pin store + ownership so a recognized command pins the topic to the named
|
|
8545
|
+
// machine and (if we currently own it) releases it, so the topic's next
|
|
8546
|
+
// routed message re-places onto the pinned machine via the already-wired
|
|
8547
|
+
// placeAndClaim → spawnOnMachine → owner-side onAccepted resume path.
|
|
8548
|
+
// Inert unless the rollout stage is past 'dark' (gated at the call site).
|
|
8549
|
+
const nickMod = await import('../core/NicknameCommand.js');
|
|
8550
|
+
const transferMod = await import('../core/TransferByNickname.js');
|
|
8551
|
+
const pinMod = await import('../core/TopicPlacementPinStore.js');
|
|
8552
|
+
_topicPinStore = new pinMod.TopicPlacementPinStore({
|
|
8553
|
+
filePath: path.join(config.stateDir, 'session-pool', 'topic-pins.json'),
|
|
8554
|
+
});
|
|
8555
|
+
_tryNicknameRelocation = async (topicId, text) => {
|
|
8556
|
+
const sessionKey = String(topicId);
|
|
8557
|
+
const caps = machinePoolRegistry?.getCapacities() ?? [];
|
|
8558
|
+
const nickToMachine = new Map();
|
|
8559
|
+
for (const c of caps)
|
|
8560
|
+
if (c.nickname)
|
|
8561
|
+
nickToMachine.set(c.nickname.toLowerCase(), c.machineId);
|
|
8562
|
+
const knownNicknames = caps.map((c) => c.nickname).filter((n) => !!n);
|
|
8563
|
+
const cmd = nickMod.recognizeNicknameCommand(text, knownNicknames);
|
|
8564
|
+
if (!cmd)
|
|
8565
|
+
return { handled: false };
|
|
8566
|
+
const plan = transferMod.planTransferByNickname(cmd, {
|
|
8567
|
+
resolveNickname: (n) => nickToMachine.get(n.toLowerCase()) ?? null,
|
|
8568
|
+
validNicknames: () => knownNicknames,
|
|
8569
|
+
isOnline: (m) => machinePoolRegistry?.getCapacity(m)?.online ?? false,
|
|
8570
|
+
currentOwnerOf: (sk) => ownReg.ownerOf(sk),
|
|
8571
|
+
isMidReply: () => false, // best-effort; the pin takes effect on the next routed message
|
|
8572
|
+
lastPlacementUpdateAt: (sk) => _topicPinStore?.lastUpdatedAtMs(sk) ?? null,
|
|
8573
|
+
now: () => Date.now(),
|
|
8574
|
+
}, sessionKey);
|
|
8575
|
+
if (plan.action === 'transfer' || plan.action === 'noop') {
|
|
8576
|
+
const target = plan.targetMachine;
|
|
8577
|
+
_topicPinStore.set(sessionKey, target, plan.setPin ?? true);
|
|
8578
|
+
// If THIS machine actively owns the topic, release so the next message re-places to the pin.
|
|
8579
|
+
try {
|
|
8580
|
+
if (ownReg.ownerOf(sessionKey) === meshSelfId) {
|
|
8581
|
+
ownReg.cas({ type: 'release', machineId: meshSelfId }, { sessionKey, sender: meshSelfId, nonce: `${meshSelfId}:rel:${sessionKey}:${Math.round(performance.now())}` });
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
catch { /* best-effort; route() re-places regardless once the owner is cleared */ }
|
|
8585
|
+
await telegram?.sendToTopic(topicId, plan.action === 'noop'
|
|
8586
|
+
? `This conversation is already pinned to ${cmd.nickname} — it'll keep running there.`
|
|
8587
|
+
: `Moving this conversation to ${cmd.nickname} — it'll pick up there on your next message.`).catch(() => { });
|
|
8588
|
+
console.log(pc.green(` [session-pool] topic ${topicId} pinned to ${target} (${plan.action}) via "${cmd.matchedVerb}"`));
|
|
8589
|
+
return { handled: true };
|
|
8590
|
+
}
|
|
8591
|
+
if (plan.action === 'confirm-required') {
|
|
8592
|
+
await telegram?.sendToTopic(topicId, plan.confirmationPrompt ?? `That machine isn't reachable right now — say "yes, move it" to confirm.`).catch(() => { });
|
|
8593
|
+
return { handled: true };
|
|
8594
|
+
}
|
|
8595
|
+
// reject
|
|
8596
|
+
const validList = (plan.validNicknames ?? []).join(', ');
|
|
8597
|
+
await telegram?.sendToTopic(topicId, plan.rejectReason === 'unknown-machine-nickname'
|
|
8598
|
+
? `I don't know a machine called "${plan.detail}". I can move this to: ${validList || '(no other machines available)'}.`
|
|
8599
|
+
: `I can't move this right now (${plan.rejectReason}).`).catch(() => { });
|
|
8600
|
+
return { handled: true };
|
|
8601
|
+
};
|
|
8510
8602
|
}
|
|
8511
8603
|
catch (err) {
|
|
8512
8604
|
console.log(pc.dim(` [session-router] not wired: ${err instanceof Error ? err.message : String(err)}`));
|