mixdog 0.9.135 → 0.9.136
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/package.json +3 -1
- package/scripts/tool-stress.mjs +8 -1
- package/src/agents/maintainer/agent.json +1 -1
- package/src/defaults/skills/setup/SKILL.md +8 -43
- package/src/help.mjs +0 -2
- package/src/rules/lead/01-general.md +0 -4
- package/src/rules/shared/01-tool.md +10 -4
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +30 -4
- package/src/runtime/agent/orchestrator/agent-trace-timing.test.mjs +57 -0
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.test.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +7 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -5
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +17 -4
- package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +150 -41
- package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +34 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +10 -9
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +124 -18
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-top-k.test.mjs +39 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +82 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +78 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +34 -3
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +87 -0
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/channels/lib/config.mjs +14 -101
- package/src/runtime/channels/lib/index-drop-trace.mjs +2 -5
- package/src/runtime/channels/lib/owned-runtime.mjs +4 -80
- package/src/runtime/channels/lib/scheduler.mjs +75 -18
- package/src/runtime/channels/lib/status-snapshot.mjs +5 -68
- package/src/runtime/channels/lib/tool-dispatch.mjs +12 -55
- package/src/runtime/channels/lib/worker-ipc.mjs +1 -16
- package/src/runtime/channels/lib/worker-main.mjs +22 -307
- package/src/runtime/media/renditions.mjs +68 -5
- package/src/runtime/media/renditions.test.mjs +45 -0
- package/src/runtime/media/store.mjs +1 -0
- package/src/runtime/memory/index.mjs +4 -3
- package/src/runtime/memory/lib/cycle-scheduler.mjs +17 -6
- package/src/runtime/memory/lib/memory-cycle-packets.test.mjs +7 -1
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +13 -0
- package/src/runtime/shared/config.mjs +8 -49
- package/src/runtime/shared/schedule-time.mjs +25 -0
- package/src/runtime/shared/schedule-time.test.mjs +29 -0
- package/src/runtime/shared/schedules-db.mjs +73 -1
- package/src/runtime/shared/tool-card-model.mjs +1 -1
- package/src/runtime/shared/transcript-writer.mjs +10 -17
- package/src/runtime/shared/update-checker.mjs +7 -2
- package/src/runtime/shared/update-checker.test.mjs +33 -0
- package/src/session-runtime/channel-config-api.mjs +3 -20
- package/src/session-runtime/config-lifecycle.mjs +1 -42
- package/src/session-runtime/lifecycle-api.mjs +1 -19
- package/src/session-runtime/model-route-api.mjs +0 -2
- package/src/session-runtime/model-settings-persist.test.mjs +0 -1
- package/src/session-runtime/prewarm.mjs +2 -7
- package/src/session-runtime/prewarm.test.mjs +0 -1
- package/src/session-runtime/runtime-core.mjs +6 -185
- package/src/session-runtime/session-lifecycle.mjs +4 -17
- package/src/session-runtime/session-transcript.mjs +54 -0
- package/src/session-runtime/session-turn-api.mjs +4 -44
- package/src/session-runtime/settings-api.mjs +0 -45
- package/src/session-runtime/tool-catalog-schema.mjs +1 -1
- package/src/standalone/channel-admin.mjs +8 -150
- package/src/standalone/daemon.mjs +5 -48
- package/src/standalone/seeds.mjs +18 -1
- package/src/standalone/session-protocol.mjs +0 -8
- package/src/standalone/session-service.mjs +1 -3
- package/src/tui/App.jsx +0 -5
- package/src/tui/app/app-view.jsx +1 -2
- package/src/tui/app/create-app-pickers.mjs +0 -20
- package/src/tui/app/doctor.mjs +2 -6
- package/src/tui/app/prompt-submit.mjs +2 -49
- package/src/tui/app/settings-picker.mjs +22 -96
- package/src/tui/app/slash-commands.mjs +0 -2
- package/src/tui/app/slash-dispatch.mjs +0 -17
- package/src/tui/app/use-prompt-handlers.mjs +4 -1
- package/src/tui/components/StatusLine.jsx +4 -4
- package/src/tui/dist/index.mjs +1003 -1461
- package/src/tui/session/context-state.mjs +0 -1
- package/src/tui/session/queue-helpers.mjs +1 -1
- package/src/tui/session/queue-helpers.test.mjs +10 -1
- package/src/tui/session/session-api-ext.mjs +0 -89
- package/src/tui/session/session-api.mjs +0 -2
- package/src/tui/session/tool-card-results.mjs +1 -1
- package/src/tui/session/tool-result-status.mjs +3 -3
- package/src/tui/session/tool-result-status.test.mjs +3 -3
- package/src/tui/session-local.mjs +0 -26
- package/src/workflows/default/WORKFLOW.md +13 -15
- package/src/workflows/solo/WORKFLOW.md +6 -7
- package/src/runtime/channels/lib/config-lock.mjs +0 -13
- package/src/runtime/channels/lib/drop-trace.mjs +0 -71
- package/src/runtime/channels/lib/format.mjs +0 -190
- package/src/runtime/channels/lib/inbound-handler.mjs +0 -387
- package/src/runtime/channels/lib/inbound-routing.mjs +0 -81
- package/src/runtime/channels/lib/interaction-handlers.mjs +0 -70
- package/src/runtime/channels/lib/interaction-workflows.mjs +0 -76
- package/src/runtime/channels/lib/memory-client.mjs +0 -289
- package/src/runtime/channels/lib/output-forwarder.mjs +0 -934
- package/src/runtime/channels/lib/session-control.mjs +0 -36
- package/src/runtime/channels/lib/session-discovery.mjs +0 -217
- package/src/runtime/channels/lib/session-discovery.test.mjs +0 -32
- package/src/runtime/channels/lib/telegram-format.mjs +0 -280
- package/src/runtime/channels/lib/tool-format.mjs +0 -125
- package/src/runtime/channels/lib/transcript-binding.mjs +0 -336
- package/src/runtime/channels/lib/transcript-discovery.mjs +0 -208
- package/src/runtime/channels/providers/discord-access.mjs +0 -30
- package/src/runtime/channels/providers/discord-attachments.mjs +0 -69
- package/src/runtime/channels/providers/discord-gateway.mjs +0 -230
- package/src/runtime/channels/providers/discord.mjs +0 -730
- package/src/runtime/channels/providers/telegram.mjs +0 -598
- package/src/runtime/channels/providers/telegram.test.mjs +0 -75
- package/src/session-runtime/remote-control.mjs +0 -126
- package/src/session-runtime/remote-transcript.mjs +0 -134
- package/src/session-runtime/remote-transition-queue.mjs +0 -14
- package/src/tui/app/channel-pickers.mjs +0 -384
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {
|
|
3
|
+
mkdtempSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
} from 'node:fs';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { test } from 'node:test';
|
|
11
|
+
|
|
12
|
+
test('update checks publish one parseable atomic cache file', async () => {
|
|
13
|
+
const root = mkdtempSync(join(tmpdir(), 'mixdog-update-cache-'));
|
|
14
|
+
const previousFetch = globalThis.fetch;
|
|
15
|
+
globalThis.fetch = async () => ({
|
|
16
|
+
ok: true,
|
|
17
|
+
json: async () => ({ version: '999.0.0' }),
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
const checker = await import(`./update-checker.mjs?test=${Date.now()}`);
|
|
21
|
+
const result = await checker.checkLatestVersion({ force: true, dataDir: root });
|
|
22
|
+
assert.equal(result.latestVersion, '999.0.0');
|
|
23
|
+
const names = readdirSync(root);
|
|
24
|
+
assert.deepEqual(names, ['update-check-cache.json']);
|
|
25
|
+
assert.deepEqual(
|
|
26
|
+
JSON.parse(readFileSync(join(root, 'update-check-cache.json'), 'utf8')),
|
|
27
|
+
{ latestVersion: '999.0.0', lastCheckedAt: result.lastCheckedAt },
|
|
28
|
+
);
|
|
29
|
+
} finally {
|
|
30
|
+
globalThis.fetch = previousFetch;
|
|
31
|
+
rmSync(root, { recursive: true, force: true });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
deleteSchedule,
|
|
4
4
|
deleteWebhook,
|
|
5
5
|
getWebhookSecret,
|
|
6
|
-
setChannelAsync,
|
|
7
6
|
saveSchedule,
|
|
8
7
|
saveWebhook,
|
|
9
8
|
setScheduleEnabled,
|
|
@@ -13,38 +12,22 @@ import {
|
|
|
13
12
|
import { getSchedule } from '../runtime/shared/schedules-db.mjs';
|
|
14
13
|
import { runScheduleSession } from '../runtime/shared/schedule-session-run.mjs';
|
|
15
14
|
|
|
16
|
-
//
|
|
15
|
+
// Webhook/schedule config surface. Extracted verbatim from the runtime
|
|
17
16
|
// API object; the mutating admin helpers are imported directly here and the
|
|
18
|
-
// runtime injects only the closure-owned callbacks (channel
|
|
19
|
-
//
|
|
17
|
+
// runtime injects only the closure-owned callbacks (channel worker handle,
|
|
18
|
+
// soft reload).
|
|
20
19
|
export function createChannelConfigApi({
|
|
21
|
-
flushChannelProviderSave,
|
|
22
20
|
channels,
|
|
23
21
|
reloadChannelsSoon,
|
|
24
22
|
ensureAutomationRuntime = () => {},
|
|
25
|
-
awaitKeychainPrewarm = async () => {},
|
|
26
23
|
}) {
|
|
27
24
|
return {
|
|
28
25
|
async getChannelSetup() {
|
|
29
|
-
// Flush a pending debounced channel provider switch first so setup readers
|
|
30
|
-
// (Settings → Channel Setting, remote toggles) never observe the
|
|
31
|
-
// previous provider during the 150ms debounce window.
|
|
32
|
-
try { await flushChannelProviderSave(); } catch {}
|
|
33
|
-
// Bot tokens live in the OS keychain. Reading them before the batch
|
|
34
|
-
// prewarm lands costs one SYNCHRONOUS PowerShell DPAPI decrypt each
|
|
35
|
-
// (measured 971ms + 579ms on a cold desktop boot, blocking the whole
|
|
36
|
-
// event loop); waiting for the prewarm serves both from its cache.
|
|
37
|
-
try { await awaitKeychainPrewarm(); } catch {}
|
|
38
26
|
return channelSetup();
|
|
39
27
|
},
|
|
40
28
|
getChannelWorkerStatus() {
|
|
41
29
|
return channels.status();
|
|
42
30
|
},
|
|
43
|
-
async setChannel(entry) {
|
|
44
|
-
const result = await setChannelAsync(entry);
|
|
45
|
-
reloadChannelsSoon();
|
|
46
|
-
return result;
|
|
47
|
-
},
|
|
48
31
|
async setWebhookConfig(patch) {
|
|
49
32
|
const result = await setWebhookConfigAsync(patch);
|
|
50
33
|
reloadChannelsSoon();
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
// same-tick readers see fresh state, and DEBOUNCE the disk write so a burst of
|
|
12
12
|
// toggles collapses into one persist. Three independent debounce channels:
|
|
13
13
|
// - config save (cfgMod.saveConfig, agent-section serialize)
|
|
14
|
-
// - channel provider save (channel-admin setChannelProvider, file-locked RMW)
|
|
15
14
|
// - outputStyle (sharedCfgMod.updateConfig whole-root RMW — cfgMod.saveConfig
|
|
16
15
|
// only serializes agent-section fields, so a top-level
|
|
17
16
|
// outputStyle would never reach disk via that path)
|
|
@@ -30,7 +29,6 @@ export function createConfigLifecycle({
|
|
|
30
29
|
// shared modules / helpers
|
|
31
30
|
cfgMod,
|
|
32
31
|
sharedCfgMod,
|
|
33
|
-
setChannelProviderAsync,
|
|
34
32
|
setConfiguredShell,
|
|
35
33
|
normalizeSystemShellConfig,
|
|
36
34
|
normalizeSearchRouteConfig,
|
|
@@ -188,42 +186,6 @@ export function createConfigLifecycle({
|
|
|
188
186
|
return adopted;
|
|
189
187
|
}
|
|
190
188
|
|
|
191
|
-
// --- debounced channel provider switch ----------------------------------------------
|
|
192
|
-
let pendingChannelProvider = null;
|
|
193
|
-
let channelProviderSaveTimer = null;
|
|
194
|
-
let channelProviderFlushInFlight = null;
|
|
195
|
-
|
|
196
|
-
async function runChannelProviderFlushAsync() {
|
|
197
|
-
while (pendingChannelProvider !== null) {
|
|
198
|
-
const name = pendingChannelProvider;
|
|
199
|
-
try {
|
|
200
|
-
await setChannelProviderAsync(name);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
process.stderr.write(`[channels] async setChannelProvider failed: ${err?.message || err}\n`);
|
|
203
|
-
if (pendingChannelProvider === name) pendingChannelProvider = null;
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
if (pendingChannelProvider === name) pendingChannelProvider = null;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function flushChannelProviderSaveAsync() {
|
|
211
|
-
if (channelProviderSaveTimer) { clearTimeout(channelProviderSaveTimer); channelProviderSaveTimer = null; }
|
|
212
|
-
const start = () => runChannelProviderFlushAsync();
|
|
213
|
-
const p = channelProviderFlushInFlight ? channelProviderFlushInFlight.then(start, start) : start();
|
|
214
|
-
channelProviderFlushInFlight = p;
|
|
215
|
-
const clear = () => { if (channelProviderFlushInFlight === p) channelProviderFlushInFlight = null; };
|
|
216
|
-
p.then(clear, clear);
|
|
217
|
-
return p;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function scheduleChannelProviderSave(name) {
|
|
221
|
-
pendingChannelProvider = name;
|
|
222
|
-
if (channelProviderSaveTimer) clearTimeout(channelProviderSaveTimer);
|
|
223
|
-
channelProviderSaveTimer = setTimeout(() => { flushChannelProviderSaveAsync(); }, CONFIG_SAVE_DEBOUNCE_MS);
|
|
224
|
-
channelProviderSaveTimer.unref?.();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
189
|
// --- debounced skills.disabled persist -------------------------------------
|
|
228
190
|
// In-memory skills state is adopted synchronously by setDisabledSkills; the
|
|
229
191
|
// heavy in-lock file RMW (cfgMod.patchSkillsDisabled) is deferred here so a
|
|
@@ -326,11 +288,10 @@ export function createConfigLifecycle({
|
|
|
326
288
|
async function flushAllConfigSavesAsync() {
|
|
327
289
|
await Promise.all([
|
|
328
290
|
flushConfigSaveAsync(),
|
|
329
|
-
flushChannelProviderSaveAsync(),
|
|
330
291
|
flushOutputStyleSaveAsync(),
|
|
331
292
|
]);
|
|
332
293
|
// The shared config layer also tracks writes started directly by channel,
|
|
333
|
-
// webhook, voice,
|
|
294
|
+
// webhook, voice, and future async RMW callers.
|
|
334
295
|
await sharedCfgMod.pendingConfigWrites();
|
|
335
296
|
}
|
|
336
297
|
|
|
@@ -420,8 +381,6 @@ export function createConfigLifecycle({
|
|
|
420
381
|
// Every lifecycle flush uses the async lock path. A synchronous waiter on
|
|
421
382
|
// the same lock would block the event loop needed by an in-flight async
|
|
422
383
|
// writer, so callers must await this before a dependent read/start.
|
|
423
|
-
flushChannelProviderSave: flushChannelProviderSaveAsync,
|
|
424
|
-
scheduleChannelProviderSave,
|
|
425
384
|
flushSkillsSave,
|
|
426
385
|
scheduleSkillsSave,
|
|
427
386
|
flushOutputStyleSave,
|
|
@@ -53,8 +53,7 @@ export function createLifecycleApi(deps) {
|
|
|
53
53
|
invalidateContextStatusCache, invalidatePreSessionToolSurface,
|
|
54
54
|
applyResolvedCwd, resolveRoute, applyDeferredToolSurface, getStandaloneTools,
|
|
55
55
|
beginRoutePreparation, clearRoutePreparation,
|
|
56
|
-
|
|
57
|
-
notificationListeners, clearRuntimeNotifications, remoteStateListeners,
|
|
56
|
+
notificationListeners, clearRuntimeNotifications,
|
|
58
57
|
disposeSessionTitles, abortActiveTurns, getReservedSessionId,
|
|
59
58
|
} = deps;
|
|
60
59
|
const closeSurfaceSession = (session, reason, options) => {
|
|
@@ -321,7 +320,6 @@ export function createLifecycleApi(deps) {
|
|
|
321
320
|
invalidateContextStatusCache();
|
|
322
321
|
if (typeof clearRuntimeNotifications === 'function') clearRuntimeNotifications();
|
|
323
322
|
else notificationListeners?.clear?.();
|
|
324
|
-
remoteStateListeners?.clear?.();
|
|
325
323
|
const shellJobsStop = teardownReapsWork && globalThis.__mixdogShellJobsRuntimeLoaded === true
|
|
326
324
|
? import('../runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs')
|
|
327
325
|
.then((mod) => mod?.shutdownShellJobs?.(reason, {
|
|
@@ -431,7 +429,6 @@ export function createLifecycleApi(deps) {
|
|
|
431
429
|
invalidateContextStatusCache();
|
|
432
430
|
invalidatePreSessionToolSurface();
|
|
433
431
|
await createCurrentSession();
|
|
434
|
-
pushTranscriptRebind?.();
|
|
435
432
|
return true;
|
|
436
433
|
},
|
|
437
434
|
async switchContext({ cwd, desktopSession: nextDesktopSession, forResume = false } = {}) {
|
|
@@ -489,10 +486,6 @@ export function createLifecycleApi(deps) {
|
|
|
489
486
|
}
|
|
490
487
|
invalidateContextStatusCache();
|
|
491
488
|
await createCurrentSession();
|
|
492
|
-
// New session.id => the worker's binding (and persisted status) now point
|
|
493
|
-
// at the previous session's transcript. Push the current transcript so
|
|
494
|
-
// outbound forwarding repoints immediately (best-effort, remote-gated).
|
|
495
|
-
pushTranscriptRebind?.();
|
|
496
489
|
return getSession().id;
|
|
497
490
|
},
|
|
498
491
|
prefetchSession(id) {
|
|
@@ -572,17 +565,6 @@ export function createLifecycleApi(deps) {
|
|
|
572
565
|
invalidatePreSessionToolSurface();
|
|
573
566
|
invalidateContextStatusCache();
|
|
574
567
|
setSessionNeedsCwdRefresh(false);
|
|
575
|
-
// Session swapped to the resumed one: repoint the worker to the current
|
|
576
|
-
// transcript instead of waiting for the next inbound steal.
|
|
577
|
-
pushTranscriptRebind?.();
|
|
578
|
-
// Daemon-boot restore resumes the pinned session AFTER the runtime's
|
|
579
|
-
// one-shot boot probe may have fired with no session (it returns without
|
|
580
|
-
// re-arming). Re-check now that the session identity is final; the probe
|
|
581
|
-
// self-guards (intent match, one-shot, remote already on), so this is a
|
|
582
|
-
// no-op for every non-pinned resume. Without it the runtime stays
|
|
583
|
-
// non-remote after a restart: tool_use rows are never mirrored and the
|
|
584
|
-
// channel shows text without tool markers (user report).
|
|
585
|
-
scheduleRemoteIntentRestore?.(0);
|
|
586
568
|
return {
|
|
587
569
|
id: resumed.id,
|
|
588
570
|
messages: resumed.messages || [],
|
|
@@ -61,7 +61,6 @@ export function createModelRouteApi(deps) {
|
|
|
61
61
|
refreshStatuslineUsageSnapshot, scheduleStatuslineUsageRefresh,
|
|
62
62
|
invalidateContextStatusCache, invalidateProviderCaches,
|
|
63
63
|
createCurrentSession, invalidatePreSessionToolSurface,
|
|
64
|
-
pushTranscriptRebind,
|
|
65
64
|
collectSearchProviderModels,
|
|
66
65
|
} = deps;
|
|
67
66
|
function persistAdoptedModelSettings(route) {
|
|
@@ -212,7 +211,6 @@ export function createModelRouteApi(deps) {
|
|
|
212
211
|
setSession(null);
|
|
213
212
|
invalidatePreSessionToolSurface?.();
|
|
214
213
|
await createCurrentSession('model-switch-empty');
|
|
215
|
-
pushTranscriptRebind?.();
|
|
216
214
|
invalidateContextStatusCache();
|
|
217
215
|
return getRoute();
|
|
218
216
|
}
|
|
@@ -63,7 +63,6 @@ function stubRouteApi({ persistLeadRoute, saveConfigAndAdopt, cfgMod }) {
|
|
|
63
63
|
invalidateProviderCaches: () => {},
|
|
64
64
|
createCurrentSession: async () => {},
|
|
65
65
|
invalidatePreSessionToolSurface: () => {},
|
|
66
|
-
pushTranscriptRebind: () => {},
|
|
67
66
|
collectSearchProviderModels: async () => [],
|
|
68
67
|
});
|
|
69
68
|
}
|
|
@@ -13,8 +13,6 @@ export function createPrewarmSchedulers({
|
|
|
13
13
|
getActiveTurnCount,
|
|
14
14
|
getSessionCreatePromise,
|
|
15
15
|
getSession,
|
|
16
|
-
isRemoteEnabled,
|
|
17
|
-
channelsEnabled,
|
|
18
16
|
hasActiveAutomation,
|
|
19
17
|
getCodeGraphModule,
|
|
20
18
|
createCurrentSession,
|
|
@@ -194,15 +192,12 @@ export function createPrewarmSchedulers({
|
|
|
194
192
|
if (isCloseRequested()) return;
|
|
195
193
|
// Channels-module and remote toggles gate MESSAGING; automation
|
|
196
194
|
// (enabled schedules/webhooks) keeps the worker boot alive — its
|
|
197
|
-
// channel
|
|
195
|
+
// channel worker runs headless: only active automation boots it.
|
|
198
196
|
const automation = await hasActiveAutomation().catch(() => false);
|
|
199
|
-
if (!
|
|
197
|
+
if (!automation) {
|
|
200
198
|
bootProfile('channels:start-disabled');
|
|
201
199
|
return;
|
|
202
200
|
}
|
|
203
|
-
// A deferred start may straddle a stopRemote(); re-check before booting so
|
|
204
|
-
// a turned-off session neither starts channels nor keeps rescheduling.
|
|
205
|
-
if (!isRemoteEnabled() && !automation) return;
|
|
206
201
|
if (isCloseRequested()) return;
|
|
207
202
|
if (getActiveTurnCount() > 0 || getSessionCreatePromise()) {
|
|
208
203
|
bootProfile('channels:start-deferred', { reason: getActiveTurnCount() > 0 ? 'turn-active' : 'session-create' });
|
|
@@ -16,7 +16,6 @@ test('first-visible code graph prewarm overlaps an active turn', async () => {
|
|
|
16
16
|
getActiveTurnCount: () => 1,
|
|
17
17
|
getSessionCreatePromise: () => null,
|
|
18
18
|
getSession: () => null,
|
|
19
|
-
isRemoteEnabled: () => false,
|
|
20
19
|
channelsEnabled: () => false,
|
|
21
20
|
hasActiveAutomation: () => false,
|
|
22
21
|
getCodeGraphModule: async () => ({
|
|
@@ -14,12 +14,10 @@ import { isAgentOwner } from '../runtime/agent/orchestrator/agent-owner.mjs';
|
|
|
14
14
|
import { createStandaloneChannelWorker } from '../standalone/channel-worker.mjs';
|
|
15
15
|
import { createStandaloneHookBus } from '../standalone/hook-bus.mjs';
|
|
16
16
|
import { getStandaloneMemoryRuntime } from '../standalone/memory-runtime-proxy.mjs';
|
|
17
|
-
import { createRemoteTransitionQueue } from './remote-transition-queue.mjs';
|
|
18
17
|
import { writeLastSessionCwd } from '../runtime/shared/user-cwd.mjs';
|
|
19
18
|
import { cancelBackgroundTasks } from '../runtime/shared/background-tasks.mjs';
|
|
20
19
|
import { createTranscriptWriter } from '../runtime/shared/transcript-writer.mjs';
|
|
21
20
|
import { mixdogHome } from '../runtime/shared/plugin-paths.mjs';
|
|
22
|
-
import { remoteIntentMatchesSession } from '../runtime/shared/remote-intent.mjs';
|
|
23
21
|
import { checkLatestVersion, localPackageVersion, isDevInstall } from '../runtime/shared/update-checker.mjs';
|
|
24
22
|
import { spawnStagedInstall, runStagedInstall, isStagedComplete } from '../runtime/shared/staged-update.mjs';
|
|
25
23
|
import {
|
|
@@ -59,19 +57,11 @@ import {
|
|
|
59
57
|
toResponsesCustomTool,
|
|
60
58
|
} from '../runtime/agent/orchestrator/providers/custom-tool-wire.mjs';
|
|
61
59
|
import {
|
|
62
|
-
channelSetup,
|
|
63
60
|
deleteSchedule,
|
|
64
61
|
deleteWebhook,
|
|
65
|
-
forgetDiscordToken,
|
|
66
|
-
forgetTelegramToken,
|
|
67
62
|
hasActiveAutomation,
|
|
68
|
-
setChannel,
|
|
69
|
-
saveDiscordToken,
|
|
70
|
-
saveTelegramToken,
|
|
71
63
|
saveSchedule,
|
|
72
64
|
saveWebhook,
|
|
73
|
-
setChannelProvider,
|
|
74
|
-
setChannelProviderAsync,
|
|
75
65
|
setScheduleEnabled,
|
|
76
66
|
setWebhookEnabled,
|
|
77
67
|
setWebhookConfig,
|
|
@@ -252,8 +242,6 @@ import { createModelRouteApi } from './model-route-api.mjs';
|
|
|
252
242
|
import { createWorkflowAgentsApi } from './workflow-agents-api.mjs';
|
|
253
243
|
import { createSelfUpdateController } from './self-update.mjs';
|
|
254
244
|
import { createSkillsApi } from './skills-api.mjs';
|
|
255
|
-
import { createRemoteTranscript } from './remote-transcript.mjs';
|
|
256
|
-
import { createRemoteControl } from './remote-control.mjs';
|
|
257
245
|
import { createNotificationBus } from './notification-bus.mjs';
|
|
258
246
|
import { createToolSurface } from './tool-surface.mjs';
|
|
259
247
|
import { createToolPolicyRefresh } from './tool-policy-refresh.mjs';
|
|
@@ -344,14 +332,6 @@ export async function createMixdogSessionRuntime({
|
|
|
344
332
|
// (session-lifecycle) instead of the Lead session shape.
|
|
345
333
|
rt.agentSessionSpec = agentSession && typeof agentSession === 'object' ? agentSession : null;
|
|
346
334
|
bootProfile('session-runtime:start', { provider, model, toolMode, cwd });
|
|
347
|
-
rt.remoteEnabled = remote === true;
|
|
348
|
-
// SESSION-SCOPED Remote is manual-only. Explicit ON selects/overrides; no
|
|
349
|
-
// registration, turn, session death, or process death transfers ownership.
|
|
350
|
-
rt.remoteSessionId = null;
|
|
351
|
-
// Desktop/TUI Remote toggles are desired-state transitions. Serialize the
|
|
352
|
-
// daemon deactivate/detach and reconnect/activate chains so an OFF that is
|
|
353
|
-
// still stopping can never tear down the worker created by the following ON.
|
|
354
|
-
const remoteTransitions = createRemoteTransitionQueue();
|
|
355
335
|
// Last assistant text handed to the transcript writer (via onAssistantText),
|
|
356
336
|
// so the post-turn final-content append can skip an exact duplicate.
|
|
357
337
|
rt._lastAppendedAssistant = '';
|
|
@@ -620,14 +600,6 @@ export async function createMixdogSessionRuntime({
|
|
|
620
600
|
rt.codeGraphFirstTurnPrewarmDone = false;
|
|
621
601
|
const modelMetaByRoute = new Map();
|
|
622
602
|
const notificationListeners = new Set();
|
|
623
|
-
// Remote seat listeners (TUI): fired when remote mode flips outside a direct
|
|
624
|
-
// user action — currently only the superseded (seat stolen) path.
|
|
625
|
-
const remoteStateListeners = new Set();
|
|
626
|
-
function emitRemoteStateChange(enabled, reason = '') {
|
|
627
|
-
for (const listener of [...remoteStateListeners]) {
|
|
628
|
-
try { listener({ enabled: enabled === true, reason: String(reason || '') }); } catch {}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
603
|
const providerModelCaches = {
|
|
632
604
|
providerModelsCache: { models: null, at: 0 },
|
|
633
605
|
providerModelsPromise: null,
|
|
@@ -866,16 +838,6 @@ export async function createMixdogSessionRuntime({
|
|
|
866
838
|
// session-pinned channel-link restore for exactly the session that owns it.
|
|
867
839
|
getSessionId: () => rt.session?.id || rt.reservedSessionId || null,
|
|
868
840
|
onNotify: (msg) => {
|
|
869
|
-
// Single-holder remote: the worker reports it lost the bridge seat to a
|
|
870
|
-
// newer remote session. Drop remote mode entirely on this session (no
|
|
871
|
-
// handover, no retry) and tell UI listeners so the indicator updates.
|
|
872
|
-
if (msg?.method === 'notifications/mixdog/remote') {
|
|
873
|
-
if (msg?.params?.state === 'superseded' && rt.remoteEnabled) {
|
|
874
|
-
stopRemote('superseded-by-newer-remote-session');
|
|
875
|
-
emitRemoteStateChange(false, 'superseded');
|
|
876
|
-
}
|
|
877
|
-
return;
|
|
878
|
-
}
|
|
879
841
|
if (msg?.method !== 'notifications/claude/channel') return;
|
|
880
842
|
const params = msg?.params && typeof msg.params === 'object' ? msg.params : {};
|
|
881
843
|
const meta = params.meta && typeof params.meta === 'object' ? params.meta : {};
|
|
@@ -1056,8 +1018,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1056
1018
|
adoptConfig,
|
|
1057
1019
|
saveConfigAndAdopt,
|
|
1058
1020
|
flushConfigSave,
|
|
1059
|
-
flushChannelProviderSave,
|
|
1060
|
-
scheduleChannelProviderSave,
|
|
1061
1021
|
scheduleSkillsSave,
|
|
1062
1022
|
flushSkillsSave,
|
|
1063
1023
|
flushOutputStyleSave,
|
|
@@ -1077,8 +1037,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1077
1037
|
getRoute: () => rt.route,
|
|
1078
1038
|
cfgMod,
|
|
1079
1039
|
sharedCfgMod,
|
|
1080
|
-
setChannelProvider,
|
|
1081
|
-
setChannelProviderAsync,
|
|
1082
1040
|
setConfiguredShell,
|
|
1083
1041
|
normalizeSystemShellConfig,
|
|
1084
1042
|
normalizeSearchRouteConfig,
|
|
@@ -1318,47 +1276,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1318
1276
|
agentTool,
|
|
1319
1277
|
});
|
|
1320
1278
|
const ensureSessionTranscriptWriter = () => remoteTranscript.ensureSessionTranscriptWriter();
|
|
1321
|
-
const ensureRemoteTranscriptWriter = () => remoteTranscript.ensureRemoteTranscriptWriter();
|
|
1322
|
-
const pushTranscriptRebind = () => remoteTranscript.pushTranscriptRebind();
|
|
1323
|
-
const flushPendingTranscriptRebind = () => remoteTranscript.flushPendingTranscriptRebind();
|
|
1324
|
-
|
|
1325
|
-
// Remote (channel relay) claim/release/stop live in remote-control.mjs; the
|
|
1326
|
-
// facade injects the mutable session + remote state they mutate.
|
|
1327
|
-
const remoteControl = createRemoteControl({
|
|
1328
|
-
getSession: () => rt.session,
|
|
1329
|
-
isRemoteEnabled: () => rt.remoteEnabled,
|
|
1330
|
-
setRemoteEnabled: (next) => { rt.remoteEnabled = next; },
|
|
1331
|
-
getRemoteSessionId: () => rt.remoteSessionId,
|
|
1332
|
-
setRemoteSessionId: (next) => { rt.remoteSessionId = next; },
|
|
1333
|
-
isCloseRequested: () => rt.closeRequested,
|
|
1334
|
-
clearChannelStartTimer: () => {
|
|
1335
|
-
if (prewarmTimers.channelStartTimer) {
|
|
1336
|
-
clearTimeout(prewarmTimers.channelStartTimer);
|
|
1337
|
-
prewarmTimers.channelStartTimer = null;
|
|
1338
|
-
}
|
|
1339
|
-
},
|
|
1340
|
-
remoteTransitions,
|
|
1341
|
-
channels,
|
|
1342
|
-
channelsEnabled,
|
|
1343
|
-
hasActiveAutomation,
|
|
1344
|
-
flushChannelProviderSave,
|
|
1345
|
-
invokeChannelStart,
|
|
1346
|
-
createCurrentSession,
|
|
1347
|
-
ensureSessionTranscriptWriter,
|
|
1348
|
-
ensureRemoteTranscriptWriter,
|
|
1349
|
-
getTranscriptPath: () => remoteTranscript.transcriptWriter?.transcriptPath || null,
|
|
1350
|
-
emitRemoteStateChange,
|
|
1351
|
-
getMemoryModule,
|
|
1352
|
-
bootProfile,
|
|
1353
|
-
envFlag,
|
|
1354
|
-
});
|
|
1355
|
-
const startRemote = (options) => remoteControl.startRemote(options);
|
|
1356
|
-
const releaseRemote = (reason) => remoteControl.releaseRemote(reason);
|
|
1357
|
-
const stopRemote = (reason) => remoteControl.stopRemote(reason);
|
|
1358
|
-
|
|
1359
|
-
function isRemoteEnabled() {
|
|
1360
|
-
return rt.remoteEnabled;
|
|
1361
|
-
}
|
|
1362
1279
|
|
|
1363
1280
|
function withTeardownDeadline(promise, ms, fallback = false) {
|
|
1364
1281
|
let timer = null;
|
|
@@ -1391,61 +1308,18 @@ export async function createMixdogSessionRuntime({
|
|
|
1391
1308
|
scheduleModelCatalogWarmup();
|
|
1392
1309
|
scheduleStatuslineUsageWarmup();
|
|
1393
1310
|
}
|
|
1394
|
-
// Channels are opt-in: only boot the worker when this session started in (or
|
|
1395
|
-
// was toggled into) remote mode. Non-remote sessions never contend for the
|
|
1396
|
-
// channel; see startRemote()/stopRemote() and the `/remote` toggle.
|
|
1397
|
-
// A manual `mixdog --remote` request is deferred past the TUI's
|
|
1398
|
-
// first frame. startRemote() front-loads memory initialization
|
|
1399
|
-
// (PG + forced ONNX embed warmup in the child), eager session create, and
|
|
1400
|
-
// the channel-worker fork — and running it inline here interleaves that
|
|
1401
|
-
// CPU/disk load with engine boot, visibly delaying the first ink frame by
|
|
1402
|
-
// seconds. The deferred timer reuses prewarmTimers.channelStartTimer so an
|
|
1403
|
-
// early /remote (startRemote clears it), stopRemote(), and close() all
|
|
1404
|
-
// cancel it through the existing clearTimeout paths. Runtime /remote calls
|
|
1405
|
-
// still start immediately (user-initiated, UI already painted).
|
|
1406
|
-
// Reconnect restore: a session that owned the channel link before the app or
|
|
1407
|
-
// daemon restarted reclaims it by itself. The durable intent used to be
|
|
1408
|
-
// consumed only by the daemon's register-time restore, which never ran for a
|
|
1409
|
-
// non-remote, automation-free session — so the link looked silently dropped
|
|
1410
|
-
// until the user toggled Remote by hand.
|
|
1411
|
-
let remoteIntentRestoreTimer = null;
|
|
1412
|
-
function scheduleRemoteIntentRestore(delayMs = remoteAutoStartDelayMs) {
|
|
1413
|
-
if (rt.agentSessionSpec || rt.remoteIntentRestoreDone) return;
|
|
1414
|
-
if (rt.closeRequested || rt.remoteEnabled || remoteIntentRestoreTimer) return;
|
|
1415
|
-
remoteIntentRestoreTimer = setTimeout(() => {
|
|
1416
|
-
remoteIntentRestoreTimer = null;
|
|
1417
|
-
if (rt.remoteIntentRestoreDone || rt.closeRequested || rt.remoteEnabled) return;
|
|
1418
|
-
const sessionId = rt.session?.id || rt.reservedSessionId || null;
|
|
1419
|
-
if (!sessionId || !remoteIntentMatchesSession(sessionId, rt.currentCwd)) return;
|
|
1420
|
-
rt.remoteIntentRestoreDone = true;
|
|
1421
|
-
bootProfile('channels:remote-intent-restore', { sessionId });
|
|
1422
|
-
void startRemote();
|
|
1423
|
-
}, delayMs);
|
|
1424
|
-
remoteIntentRestoreTimer?.unref?.();
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
1311
|
if (rt.agentSessionSpec) {
|
|
1428
1312
|
// Worker sessions never run channels or schedule automation probes.
|
|
1429
|
-
} else if (rt.remoteEnabled) {
|
|
1430
|
-
bootProfile('channels:manual-start-deferred', { delayMs: remoteAutoStartDelayMs });
|
|
1431
|
-
prewarmTimers.channelStartTimer = setTimeout(() => {
|
|
1432
|
-
prewarmTimers.channelStartTimer = null;
|
|
1433
|
-
if (rt.closeRequested || !rt.remoteEnabled) return;
|
|
1434
|
-
startRemote();
|
|
1435
|
-
}, remoteAutoStartDelayMs);
|
|
1436
|
-
prewarmTimers.channelStartTimer.unref?.();
|
|
1437
1313
|
} else {
|
|
1438
|
-
scheduleRemoteIntentRestore();
|
|
1439
1314
|
// Automation decoupling (user decision): enabled schedules/webhooks boot
|
|
1440
|
-
// the worker on their own — no
|
|
1441
|
-
//
|
|
1442
|
-
// daemon without restarting schedules or webhooks.
|
|
1315
|
+
// the worker on their own — no messaging provider. The worker runs
|
|
1316
|
+
// headless (scheduler/webhooks/voice only).
|
|
1443
1317
|
prewarmTimers.channelStartTimer = setTimeout(() => {
|
|
1444
1318
|
prewarmTimers.channelStartTimer = null;
|
|
1445
|
-
if (rt.closeRequested
|
|
1319
|
+
if (rt.closeRequested) return;
|
|
1446
1320
|
void hasActiveAutomation()
|
|
1447
1321
|
.then((active) => {
|
|
1448
|
-
if (!active || rt.closeRequested
|
|
1322
|
+
if (!active || rt.closeRequested) return;
|
|
1449
1323
|
bootProfile('channels:automation-autostart');
|
|
1450
1324
|
void invokeChannelStart();
|
|
1451
1325
|
})
|
|
@@ -1455,8 +1329,8 @@ export async function createMixdogSessionRuntime({
|
|
|
1455
1329
|
}
|
|
1456
1330
|
|
|
1457
1331
|
// Pure settings-delegate methods (onboarding status/skip, autoClear, profile,
|
|
1458
|
-
// compaction, recap/memory, channels, systemShell, update settings
|
|
1459
|
-
//
|
|
1332
|
+
// compaction, recap/memory, channels, systemShell, update settings).
|
|
1333
|
+
// Extracted to session-runtime/settings-api.mjs
|
|
1460
1334
|
// and SPREAD into the API object below so the external surface is unchanged.
|
|
1461
1335
|
const { refreshEmptySessionToolPolicy } = createToolPolicyRefresh({
|
|
1462
1336
|
getSession: () => rt.session,
|
|
@@ -1475,10 +1349,8 @@ export async function createMixdogSessionRuntime({
|
|
|
1475
1349
|
getConfig: () => rt.config,
|
|
1476
1350
|
getRoute: () => rt.route,
|
|
1477
1351
|
getSession: () => rt.session,
|
|
1478
|
-
getRemoteEnabled: () => rt.remoteEnabled,
|
|
1479
1352
|
adoptConfig,
|
|
1480
1353
|
saveConfigAndAdopt,
|
|
1481
|
-
scheduleChannelProviderSave,
|
|
1482
1354
|
scheduleSkillsSave,
|
|
1483
1355
|
cfgMod,
|
|
1484
1356
|
hasOwn,
|
|
@@ -1519,21 +1391,14 @@ export async function createMixdogSessionRuntime({
|
|
|
1519
1391
|
runUpdateNowInternal: (...a) => runUpdateNowInternal(...a),
|
|
1520
1392
|
reloadChannelsSoon: (...a) => reloadChannelsSoon(...a),
|
|
1521
1393
|
ONBOARDING_VERSION,
|
|
1522
|
-
saveDiscordToken,
|
|
1523
|
-
forgetDiscordToken,
|
|
1524
|
-
saveTelegramToken,
|
|
1525
|
-
forgetTelegramToken,
|
|
1526
|
-
setChannelProvider,
|
|
1527
1394
|
});
|
|
1528
1395
|
|
|
1529
1396
|
const channelConfigApi = createChannelConfigApi({
|
|
1530
|
-
flushChannelProviderSave,
|
|
1531
1397
|
channels,
|
|
1532
1398
|
reloadChannelsSoon,
|
|
1533
1399
|
// Automation saved mid-session boots the worker (claim-if-vacant) even
|
|
1534
1400
|
// though the boot-time autostart window has already passed.
|
|
1535
1401
|
ensureAutomationRuntime: () => scheduleChannelStart(0),
|
|
1536
|
-
awaitKeychainPrewarm,
|
|
1537
1402
|
});
|
|
1538
1403
|
const providerAuthApi = createProviderAuthApi({
|
|
1539
1404
|
cfgMod,
|
|
@@ -1582,17 +1447,10 @@ export async function createMixdogSessionRuntime({
|
|
|
1582
1447
|
statusRoutes,
|
|
1583
1448
|
channels,
|
|
1584
1449
|
agentTool,
|
|
1585
|
-
pushTranscriptRebind,
|
|
1586
|
-
// Post-resume remote-intent recheck (hoisted declaration below). The boot
|
|
1587
|
-
// probe can fire before the daemon-driven resume has established
|
|
1588
|
-
// rt.session/cwd and then never re-arms; a completed resume is the first
|
|
1589
|
-
// moment the pinned session can actually reclaim its channel link.
|
|
1590
|
-
scheduleRemoteIntentRestore,
|
|
1591
1450
|
mcpClient,
|
|
1592
1451
|
warmupTimers,
|
|
1593
1452
|
prewarmTimers,
|
|
1594
1453
|
flushConfigSave,
|
|
1595
|
-
flushChannelProviderSave,
|
|
1596
1454
|
flushOutputStyleSave,
|
|
1597
1455
|
flushAllConfigSavesAsync,
|
|
1598
1456
|
withTeardownDeadline,
|
|
@@ -1666,7 +1524,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1666
1524
|
invalidateProviderCaches,
|
|
1667
1525
|
createCurrentSession,
|
|
1668
1526
|
invalidatePreSessionToolSurface,
|
|
1669
|
-
pushTranscriptRebind,
|
|
1670
1527
|
collectSearchProviderModels,
|
|
1671
1528
|
});
|
|
1672
1529
|
const workflowAgentsApi = createWorkflowAgentsApi({
|
|
@@ -1713,10 +1570,8 @@ export async function createMixdogSessionRuntime({
|
|
|
1713
1570
|
getCodeGraphFirstTurnPrewarmDone: () => rt.codeGraphFirstTurnPrewarmDone,
|
|
1714
1571
|
setCodeGraphFirstTurnPrewarmDone: (v) => { rt.codeGraphFirstTurnPrewarmDone = v; },
|
|
1715
1572
|
codeGraphPrewarmLazy,
|
|
1716
|
-
getRemoteEnabled: () => rt.remoteEnabled,
|
|
1717
1573
|
getCloseRequested: () => rt.closeRequested,
|
|
1718
1574
|
getTranscriptWriter: () => remoteTranscript.transcriptWriter,
|
|
1719
|
-
getTwKey: () => remoteTranscript.transcriptKey,
|
|
1720
1575
|
getLastAppendedAssistant: () => rt._lastAppendedAssistant,
|
|
1721
1576
|
setLastAppendedAssistant: (v) => { rt._lastAppendedAssistant = v; },
|
|
1722
1577
|
scheduleCodeGraphPrewarm,
|
|
@@ -1725,11 +1580,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1725
1580
|
refreshSessionForCwdIfNeeded,
|
|
1726
1581
|
createCurrentSession,
|
|
1727
1582
|
ensureSessionTranscriptWriter,
|
|
1728
|
-
ensureRemoteTranscriptWriter,
|
|
1729
|
-
pushTranscriptRebind,
|
|
1730
|
-
flushPendingTranscriptRebind,
|
|
1731
|
-
channelsEnabled,
|
|
1732
|
-
invokeChannelStart,
|
|
1733
1583
|
channels,
|
|
1734
1584
|
hooks,
|
|
1735
1585
|
hookCommonPayload,
|
|
@@ -1748,7 +1598,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1748
1598
|
resolveCwdPath,
|
|
1749
1599
|
agentStatusState,
|
|
1750
1600
|
notificationListeners,
|
|
1751
|
-
remoteStateListeners,
|
|
1752
1601
|
awaitInitialMcpConnect,
|
|
1753
1602
|
mcpTurnGraceMs,
|
|
1754
1603
|
awaitRoutePreparation: () => routePreparation.wait(),
|
|
@@ -1793,10 +1642,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1793
1642
|
}
|
|
1794
1643
|
rt.reservedSessionId = id;
|
|
1795
1644
|
bindRuntimeNotificationSession(id);
|
|
1796
|
-
// First moment this runtime knows WHICH session it is: re-check the
|
|
1797
|
-
// channel-link intent, since the boot probe may have run before the
|
|
1798
|
-
// daemon addressed this session.
|
|
1799
|
-
scheduleRemoteIntentRestore();
|
|
1800
1645
|
// Reservation is the earliest safe point to prepare keychain, memory,
|
|
1801
1646
|
// provider metadata, hooks, and the provider transport. This starts no
|
|
1802
1647
|
// model response and therefore incurs no inference/token usage. The first
|
|
@@ -1889,30 +1734,6 @@ export async function createMixdogSessionRuntime({
|
|
|
1889
1734
|
renameSessionTitle(sessionId, title) {
|
|
1890
1735
|
return mgr.updateSessionManualTitle(sessionId, title);
|
|
1891
1736
|
},
|
|
1892
|
-
startRemote() {
|
|
1893
|
-
return startRemote();
|
|
1894
|
-
},
|
|
1895
|
-
stopRemote(reason) {
|
|
1896
|
-
return stopRemote(reason);
|
|
1897
|
-
},
|
|
1898
|
-
releaseRemote(reason) {
|
|
1899
|
-
return releaseRemote(reason);
|
|
1900
|
-
},
|
|
1901
|
-
isRemoteEnabled() {
|
|
1902
|
-
return isRemoteEnabled();
|
|
1903
|
-
},
|
|
1904
|
-
// Session-scoped remote: the owning session id (null when off/unassigned).
|
|
1905
|
-
getRemoteSessionId() {
|
|
1906
|
-
return rt.remoteSessionId;
|
|
1907
|
-
},
|
|
1908
|
-
// Subscribe to non-user-initiated remote flips (seat superseded). Returns
|
|
1909
|
-
// an unsubscribe function. TUI uses this to sync its Remote indicator and
|
|
1910
|
-
// show a "remote taken over" notice.
|
|
1911
|
-
onRemoteStateChange(listener) {
|
|
1912
|
-
if (typeof listener !== 'function') return () => {};
|
|
1913
|
-
remoteStateListeners.add(listener);
|
|
1914
|
-
return () => remoteStateListeners.delete(listener);
|
|
1915
|
-
},
|
|
1916
1737
|
get clientHostPid() {
|
|
1917
1738
|
return rt.session?.clientHostPid || process.pid;
|
|
1918
1739
|
},
|