instar 1.3.1585 → 1.3.1587
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/dashboard/console/console.css +11 -0
- package/dashboard/console/sessions-model.js +26 -0
- package/dashboard/console/sessions.js +63 -3
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +20 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/core/AutonomousRunStore.d.ts +7 -0
- package/dist/core/AutonomousRunStore.d.ts.map +1 -1
- package/dist/core/AutonomousRunStore.js +8 -1
- package/dist/core/AutonomousRunStore.js.map +1 -1
- package/dist/core/AutonomousStartAdmission.d.ts +94 -0
- package/dist/core/AutonomousStartAdmission.d.ts.map +1 -0
- package/dist/core/AutonomousStartAdmission.js +170 -0
- package/dist/core/AutonomousStartAdmission.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +6 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/QueueDrainLoop.d.ts +10 -2
- package/dist/core/QueueDrainLoop.d.ts.map +1 -1
- package/dist/core/QueueDrainLoop.js +28 -6
- package/dist/core/QueueDrainLoop.js.map +1 -1
- package/dist/core/SessionRouter.d.ts +21 -3
- package/dist/core/SessionRouter.d.ts.map +1 -1
- package/dist/core/SessionRouter.js +58 -6
- package/dist/core/SessionRouter.js.map +1 -1
- package/dist/core/SessionTranscriptReader.d.ts +25 -0
- package/dist/core/SessionTranscriptReader.d.ts.map +1 -0
- package/dist/core/SessionTranscriptReader.js +143 -0
- package/dist/core/SessionTranscriptReader.js.map +1 -0
- package/dist/core/types.d.ts +8 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/native/instar-desktop-host +0 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +4 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +26 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +102 -2
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +37 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.1586.md +28 -0
- package/upgrades/1.3.1587.md +27 -0
- package/upgrades/side-effects/autonomous-start-admission.eli16.md +27 -0
- package/upgrades/side-effects/autonomous-start-admission.md +141 -0
- package/upgrades/side-effects/console-session-history.eli16.md +14 -0
- package/upgrades/side-effects/console-session-history.md +32 -0
- package/upgrades/side-effects/ecosystem-idea-pipeline-spec.md +44 -0
- package/upgrades/side-effects/spawn-handoff-ack.md +117 -0
- package/upgrades/spawn-handoff-ack.eli16.md +43 -0
|
@@ -985,6 +985,17 @@ button.run-mark:focus-visible { outline: 2px solid var(--accent); outline-offset
|
|
|
985
985
|
.sess-term-wrap { position: relative; flex: 1; min-height: 320px; display: flex; }
|
|
986
986
|
.sess-term { flex: 1; min-width: 0; min-height: 320px; height: 52dvh; background: #0a0e17; border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 6px; overflow: hidden; }
|
|
987
987
|
.sess-term.plain { overflow: auto; }
|
|
988
|
+
.sess-tabs { display: flex; gap: var(--s-2); }
|
|
989
|
+
.sess-tab[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-wash); }
|
|
990
|
+
.sess-history { flex: 1; min-width: 0; min-height: 320px; height: 52dvh; overflow-y: auto; padding: var(--s-3); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-md); display: flex; flex-direction: column; gap: var(--s-3); }
|
|
991
|
+
.sess-history[hidden], .sess-term[hidden] { display: none; }
|
|
992
|
+
.sess-history-note { margin: 0; text-align: center; font-size: 13px; color: var(--text-muted); }
|
|
993
|
+
.sess-h { max-width: 92%; }
|
|
994
|
+
.sess-h-user { align-self: flex-end; background: var(--accent-wash); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: var(--s-2) var(--s-3); }
|
|
995
|
+
.sess-h-assistant { align-self: flex-start; }
|
|
996
|
+
.sess-h-who { font-size: 12px; color: var(--text-faint); margin-bottom: 2px; }
|
|
997
|
+
.sess-h-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 14.5px; line-height: 1.5; color: var(--text); }
|
|
998
|
+
.sess-h-tool { margin: 0; font-family: var(--font-mono); font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
|
|
988
999
|
.sess-pre { margin: 0; font-family: var(--font-mono); font-size: 12px; line-height: 1.4; color: #d6dbe4; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
989
1000
|
.sess-resume { position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%); z-index: 2; }
|
|
990
1001
|
.sess-composer { display: flex; gap: var(--s-2); align-items: flex-end; position: sticky; bottom: 0; padding: var(--s-2) 0; background: var(--bg); }
|
|
@@ -121,6 +121,32 @@ export function isInternalSession(s) {
|
|
|
121
121
|
return (s.platform || 'headless') === 'headless' && s.triggeredBy !== OPERATOR_CREATED;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/** The History read for a session: its conversation record, a page at a time. A session
|
|
125
|
+
* on another machine is read through this machine, which asks the owner. */
|
|
126
|
+
export const HISTORY_PAGE = 150;
|
|
127
|
+
export function historyUrl(s, before = null) {
|
|
128
|
+
const q = new URLSearchParams({ limit: String(HISTORY_PAGE) });
|
|
129
|
+
if (before != null) q.set('before', String(before));
|
|
130
|
+
if (s.remote && s.machineId) q.set('machineId', s.machineId);
|
|
131
|
+
return `/sessions/${encodeURIComponent(s.tmuxSession)}/transcript?${q}`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Words for a failed History read: never "no history" when the read failed. */
|
|
135
|
+
export function historyErrorWords(res) {
|
|
136
|
+
const d = (res && res.data) || {};
|
|
137
|
+
if (d.reason === 'no-transcript') return 'This session has no conversation record yet.';
|
|
138
|
+
if (d.reason === 'peer-unreachable' || d.reason === 'peer-unknown') return `Can’t tell: ${d.error || 'the session’s machine did not answer'}.`;
|
|
139
|
+
const why = d.error || (res && res.reason) || (res && res.status ? `the server answered ${res.status}` : 'the server could not be reached');
|
|
140
|
+
return `Can’t tell: ${String(why).replace(/\.$/, '')}.`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** A user line from a chat bridge carries a routing prefix; show only what was said. */
|
|
144
|
+
export function historyText(e) {
|
|
145
|
+
let t = String((e && e.text) || '');
|
|
146
|
+
if (e && e.role === 'user') t = t.replace(/^\[(telegram|slack|whatsapp):[^\]]*\]\s*/, '');
|
|
147
|
+
return t;
|
|
148
|
+
}
|
|
149
|
+
|
|
124
150
|
export function buildSessions(sessionsRes, { ws = null, now = Date.now(), topicNames = {}, showInternal = false } = {}) {
|
|
125
151
|
if (!sessionsRes || !sessionsRes.ok) return { ok: false, reason: `Couldn’t list sessions: ${(sessionsRes && sessionsRes.reason) || 'no answer'}.` };
|
|
126
152
|
const data = sessionsRes.data || {};
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
buildSessions, sessionsHeadline, sessionsFacts, partialWords, titleLine, closeRequest, closeConfirmWords,
|
|
12
12
|
closeResultWords, doorChoices, modelChoices, doorModelWords, regimeWords, machineChoices, PLATFORMS,
|
|
13
13
|
platformAllowsDoor, createBody, createResultWords, defaultWords, profileSourceWords, switchLanded,
|
|
14
|
-
canSwitchDoor, attachmentMessage, KEYS, STOP_KEY, frame, nextHistoryBatch, streamErrorWords, composerRows, modelWords, HISTORY_FIRST,
|
|
14
|
+
canSwitchDoor, attachmentMessage, historyUrl, historyErrorWords, historyText, KEYS, STOP_KEY, frame, nextHistoryBatch, streamErrorWords, composerRows, modelWords, HISTORY_FIRST,
|
|
15
15
|
} from './sessions-model.js';
|
|
16
16
|
import { el, setKids, pageHead, sheet, closeSheet, story, details, note, cantTell } from './ui.js';
|
|
17
17
|
import { legacyHref } from './nav-model.js';
|
|
@@ -266,7 +266,13 @@ function openView(box, row) {
|
|
|
266
266
|
attachBtn.addEventListener('click', () => filePick.click());
|
|
267
267
|
filePick.addEventListener('change', () => { addFiles([...filePick.files]); filePick.value = ''; });
|
|
268
268
|
const tray = el('div', { class: 'keys-tray', hidden: true });
|
|
269
|
-
|
|
269
|
+
// Live (the terminal) or History (the conversation record, which goes back to the start:
|
|
270
|
+
// a full-screen session keeps no terminal scrollback).
|
|
271
|
+
const historyBox = el('div', { class: 'sess-history', hidden: true, 'aria-label': 'Conversation history' });
|
|
272
|
+
const liveTab = el('button', { class: 'chip sess-tab', type: 'button', text: 'Live', 'aria-pressed': 'true', 'data-tab': 'live' });
|
|
273
|
+
const historyTab = el('button', { class: 'chip sess-tab', type: 'button', text: 'History', 'aria-pressed': 'false', 'data-tab': 'history' });
|
|
274
|
+
const tabs = el('div', { class: 'sess-tabs', role: 'group', 'aria-label': 'View' }, liveTab, historyTab);
|
|
275
|
+
const view = { key: row.key, s, titleSub, statusLine, termBox, historyBox, history: null, resume, following: true, pending: null, loaded: HISTORY_FIRST, exhausted: false, loading: false, term: null, fit: null, pre: null };
|
|
270
276
|
st.view = view;
|
|
271
277
|
|
|
272
278
|
// Keys: the ordinary ones, then Stop separated, red, and asked once.
|
|
@@ -316,14 +322,24 @@ function openView(box, row) {
|
|
|
316
322
|
input.addEventListener('keydown', (e) => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); sendText(); } });
|
|
317
323
|
more.addEventListener('click', () => moreSheet(view));
|
|
318
324
|
resume.addEventListener('click', () => backToLive());
|
|
325
|
+
const showTab = (which) => {
|
|
326
|
+
const hist = which === 'history';
|
|
327
|
+
liveTab.setAttribute('aria-pressed', hist ? 'false' : 'true'); historyTab.setAttribute('aria-pressed', hist ? 'true' : 'false');
|
|
328
|
+
termBox.hidden = hist; historyBox.hidden = !hist; if (hist) resume.hidden = true;
|
|
329
|
+
if (hist && !view.history) openHistory(view);
|
|
330
|
+
if (!hist && view.fit) requestAnimationFrame(() => { try { view.fit.fit(); } catch { /* not visible yet */ } });
|
|
331
|
+
};
|
|
332
|
+
liveTab.addEventListener('click', () => showTab('live'));
|
|
333
|
+
historyTab.addEventListener('click', () => showTab('history'));
|
|
319
334
|
|
|
320
335
|
setKids(box, el('div', { class: 'sess-open', 'data-open': row.key },
|
|
321
336
|
el('div', { class: 'sess-bar' },
|
|
322
337
|
el('a', { class: 'chip icon-btn sess-back', href: listHref, 'aria-label': 'All sessions', text: '‹' }),
|
|
323
338
|
el('div', { class: 'sess-titles' }, el('h1', { class: 'sess-title', text: row.title }), titleSub),
|
|
324
339
|
more),
|
|
340
|
+
tabs,
|
|
325
341
|
statusLine,
|
|
326
|
-
el('div', { class: 'sess-term-wrap' }, termBox, resume),
|
|
342
|
+
el('div', { class: 'sess-term-wrap' }, termBox, historyBox, resume),
|
|
327
343
|
chips,
|
|
328
344
|
composer,
|
|
329
345
|
tray));
|
|
@@ -416,6 +432,50 @@ function sendKey(key) {
|
|
|
416
432
|
if (!wsSend(frame('key', st.view.s, { key }))) setStatus('Not sent: live updates are paused.');
|
|
417
433
|
}
|
|
418
434
|
|
|
435
|
+
// ── History: the conversation record, newest at the bottom, older on scroll-up ──
|
|
436
|
+
async function openHistory(view) {
|
|
437
|
+
view.history = { before: null, done: false, loading: false, count: 0 };
|
|
438
|
+
view.historyBox.addEventListener('scroll', () => { if (view.historyBox.scrollTop < 200) loadHistory(view); });
|
|
439
|
+
await loadHistory(view);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function loadHistory(view) {
|
|
443
|
+
const h = view.history;
|
|
444
|
+
if (!h || h.loading || h.done || st.view !== view) return;
|
|
445
|
+
h.loading = true;
|
|
446
|
+
const box = view.historyBox;
|
|
447
|
+
const marker = el('p', { class: 'sess-history-note', text: h.count ? 'Loading earlier messages…' : 'Loading the conversation…' });
|
|
448
|
+
box.prepend(marker);
|
|
449
|
+
const res = await send('GET', historyUrl(view.s, h.before));
|
|
450
|
+
marker.remove();
|
|
451
|
+
h.loading = false;
|
|
452
|
+
if (st.view !== view) return;
|
|
453
|
+
if (!res.ok || !res.data || !Array.isArray(res.data.entries)) {
|
|
454
|
+
h.done = true;
|
|
455
|
+
box.prepend(el('p', { class: 'sess-history-note', text: historyErrorWords(res) }));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const first = !h.count;
|
|
459
|
+
const prevHeight = box.scrollHeight, prevTop = box.scrollTop;
|
|
460
|
+
const frag = document.createDocumentFragment();
|
|
461
|
+
for (const e of res.data.entries) {
|
|
462
|
+
const text = historyText(e);
|
|
463
|
+
if (!text) continue;
|
|
464
|
+
const when = e.at ? new Date(e.at).toLocaleString([], { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : null;
|
|
465
|
+
frag.append(e.role === 'tool'
|
|
466
|
+
? el('p', { class: 'sess-h sess-h-tool', text: `→ ${text}` })
|
|
467
|
+
: el('div', { class: `sess-h sess-h-${e.role}` }, el('div', { class: 'sess-h-who', text: [e.role === 'user' ? 'Message in' : 'Session', when].filter(Boolean).join(' · ') }), el('div', { class: 'sess-h-text', text })));
|
|
468
|
+
}
|
|
469
|
+
h.count += res.data.entries.length;
|
|
470
|
+
h.before = res.data.nextBefore;
|
|
471
|
+
if (h.before == null) { h.done = true; frag.prepend(el('p', { class: 'sess-history-note', text: h.count ? 'The start of this conversation.' : 'Nothing has been said in this session yet.' })); }
|
|
472
|
+
box.prepend(frag);
|
|
473
|
+
if (first) box.scrollTop = box.scrollHeight;
|
|
474
|
+
else box.scrollTop = prevTop + (box.scrollHeight - prevHeight);
|
|
475
|
+
// A short first page may not fill the box: keep loading until it scrolls.
|
|
476
|
+
if (!h.done && box.scrollHeight <= box.clientHeight + 200) loadHistory(view);
|
|
477
|
+
}
|
|
478
|
+
|
|
419
479
|
function leaveView() {
|
|
420
480
|
const v = st.view;
|
|
421
481
|
if (!v) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAuHA,OAAO,EAAE,cAAc,EAAwD,MAAM,2BAA2B,CAAC;AAgBjH,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA6BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6J7D,OAAO,KAAK,EAAW,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AA4GtD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AA0ID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0DD,+EAA+E;AAC/E,wBAAgB,qCAAqC,CACnD,SAAS,EAAE,IAAI,CAAC,OAAO,2BAA2B,EAAE,cAAc,EAAE,QAAQ,CAAC,GAAG,IAAI,EACpF,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAukBD,wBAAsB,oBAAoB,CACxC,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,kBAAkB,CAAC,EAAE,MAAM;AAC3B;;qCAEqC;AACrC,WAAW,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACzD;;wEAEwE;AACxE,SAAS,CAAC,EAAE;IACV,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;sEAGkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACA,OAAO,CAAC,MAAM,CAAC,CAiZjB;AA0xBD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAo4BN;AA+pBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/server.js
CHANGED
|
@@ -26536,11 +26536,29 @@ export async function startServer(options) {
|
|
|
26536
26536
|
}
|
|
26537
26537
|
throw new Error(`deliverMessage rejected: ${res.status} ${res.reason ?? ''}`);
|
|
26538
26538
|
},
|
|
26539
|
-
|
|
26539
|
+
// The placement hop is a deliverMessage at the epoch the CAS just
|
|
26540
|
+
// landed, read exactly like a forward. It used to send epoch 0 and
|
|
26541
|
+
// discard the reply: a receiver holding an older record for the
|
|
26542
|
+
// topic NACKed it stale and the router still logged 'spawned'.
|
|
26543
|
+
spawnOnMachine: async (machineId, msg, ownershipEpoch) => {
|
|
26540
26544
|
const url = peerUrl(machineId);
|
|
26541
26545
|
if (!url)
|
|
26542
26546
|
throw new Error(`no peer url for ${machineId}`);
|
|
26543
|
-
await meshClient.send({ machineId, url }, { type: 'deliverMessage', session: msg.sessionKey, messageId: msg.messageId, payload: msg.payload, ownershipEpoch:
|
|
26547
|
+
const res = await meshClient.send({ machineId, url }, { type: 'deliverMessage', session: msg.sessionKey, messageId: msg.messageId, payload: msg.payload, ownershipEpoch, ...(msg.senderEnvelope ? { senderEnvelope: msg.senderEnvelope } : {}) }, ownershipEpoch);
|
|
26548
|
+
if (res.ok && res.result && typeof res.result === 'object' && 'accepted' in res.result) {
|
|
26549
|
+
return res.result;
|
|
26550
|
+
}
|
|
26551
|
+
throw new Error(`spawn deliverMessage rejected: ${res.status} ${res.reason ?? ''}`);
|
|
26552
|
+
},
|
|
26553
|
+
// Take back a placement whose spawn never landed (see SessionRouter):
|
|
26554
|
+
// only the still-placing record this router put on `placedOn`.
|
|
26555
|
+
reclaimPlacement: (sk, placedOn) => {
|
|
26556
|
+
const cur = ownReg.read(sk);
|
|
26557
|
+
if (!cur || cur.status !== 'placing' || cur.ownerMachineId !== placedOn)
|
|
26558
|
+
return false;
|
|
26559
|
+
const r = ownReg.cas({ type: 'force-claim', machineId: meshSelfId }, { sessionKey: sk, sender: meshSelfId, nonce: `${meshSelfId}:rc:${++routerNonce}` });
|
|
26560
|
+
emitPlacement(sk, r, 'failover', placedOn);
|
|
26561
|
+
return r.ok;
|
|
26544
26562
|
},
|
|
26545
26563
|
handleLocally: async () => { },
|
|
26546
26564
|
// Durable Inbound Message Queue §2.2: tri-state custody taking.
|