mixdog 0.9.93 → 0.9.95
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/NOTICE.md +72 -0
- package/package.json +16 -6
- package/scripts/lib/isolated-root-cleanup.mjs +19 -0
- package/scripts/run-suite.mjs +100 -0
- package/src/lib/rules-builder.cjs +4 -3
- package/src/output-styles/detailed.md +13 -15
- package/src/output-styles/extreme-minimal.md +7 -11
- package/src/output-styles/minimal.md +4 -7
- package/src/output-styles/simple.md +11 -13
- package/src/rules/agent/30-explorer.md +22 -16
- package/src/rules/lead/01-general.md +1 -2
- package/src/rules/lead/lead-brief.md +4 -5
- package/src/rules/lead/lead-tool.md +3 -2
- package/src/rules/shared/01-tool.md +28 -29
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +23 -7
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +4 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +29 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +6 -2
- package/src/runtime/agent/orchestrator/mcp/client.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +97 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +4 -6
- package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +75 -15
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +8 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +14 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +5 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +10 -10
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/registry.mjs +51 -4
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +15 -15
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +12 -32
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +42 -2
- package/src/runtime/agent/orchestrator/session/context-compaction-policy.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +10 -11
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +0 -14
- package/src/runtime/agent/orchestrator/session/loop/stop-hooks.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +40 -13
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +5 -9
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +103 -92
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +98 -3
- package/src/runtime/agent/orchestrator/stall-policy.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +25 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +22 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +491 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +91 -13
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +90 -27
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +19 -9
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +32 -4
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +16 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +546 -23
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +8 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +35 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +98 -0
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +48 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +71 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +104 -14
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +6 -17
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -4
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/env-scrub.mjs +9 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +57 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +151 -18
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +109 -13
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +10 -10
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -5
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +1 -1
- package/src/runtime/channels/backends/discord.mjs +5 -14
- package/src/runtime/channels/backends/telegram.mjs +0 -5
- package/src/runtime/channels/lib/inbound-handler.mjs +0 -1
- package/src/runtime/channels/lib/output-forwarder.mjs +24 -5
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/worker-main.mjs +1 -1
- package/src/runtime/media/renditions.mjs +21 -2
- package/src/runtime/memory/lib/tool-call-handler.mjs +16 -1
- package/src/runtime/memory/tool-defs.mjs +6 -6
- package/src/runtime/shared/atomic-file.mjs +53 -0
- package/src/runtime/shared/background-tasks.mjs +16 -6
- package/src/runtime/shared/child-spawn-gate.mjs +50 -26
- package/src/runtime/shared/resource-admission.mjs +40 -1
- package/src/runtime/shared/task-notification-envelope.mjs +11 -2
- package/src/runtime/shared/tool-card-model.mjs +6 -2
- package/src/runtime/shared/tool-status.mjs +10 -1
- package/src/runtime/shared/tool-surface.mjs +5 -0
- package/src/runtime/shared/turn-snapshot.mjs +385 -21
- package/src/runtime/shared/turn-worktree-snapshot.mjs +540 -0
- package/src/session-runtime/context-status.mjs +9 -3
- package/src/session-runtime/lifecycle-api.mjs +35 -5
- package/src/session-runtime/mcp-glue.mjs +11 -6
- package/src/session-runtime/provider-models.mjs +94 -43
- package/src/session-runtime/provider-usage.mjs +26 -2
- package/src/session-runtime/runtime-core.mjs +46 -8
- package/src/session-runtime/runtime-tunables.mjs +4 -0
- package/src/session-runtime/self-update.mjs +33 -4
- package/src/session-runtime/session-lifecycle.mjs +2 -0
- package/src/session-runtime/session-text.mjs +2 -1
- package/src/session-runtime/session-turn-api.mjs +106 -22
- package/src/session-runtime/workflow.mjs +11 -4
- package/src/standalone/agent-tool.mjs +4 -4
- package/src/standalone/backend-daemon.mjs +570 -0
- package/src/standalone/channel-daemon-transport.mjs +141 -1
- package/src/standalone/channel-worker.mjs +3 -2
- package/src/standalone/engine-daemon-client.mjs +894 -0
- package/src/standalone/engine-daemon-local-bridge.mjs +20 -0
- package/src/standalone/engine-daemon-protocol.mjs +33 -0
- package/src/standalone/engine-daemon-service.mjs +864 -0
- package/src/standalone/engine-daemon-transport.mjs +603 -0
- package/src/standalone/explore-tool.mjs +1 -1
- package/src/tui/App.jsx +62 -47
- package/src/tui/app/app-format.mjs +4 -2
- package/src/tui/app/app-view.jsx +5 -0
- package/src/tui/app/channel-pickers.mjs +7 -6
- package/src/tui/app/core-memory-picker.mjs +4 -4
- package/src/tui/app/extension-pickers.mjs +20 -18
- package/src/tui/app/maintenance-pickers.mjs +27 -27
- package/src/tui/app/onboarding-steps.mjs +23 -18
- package/src/tui/app/prompt-submit.mjs +13 -2
- package/src/tui/app/route-pickers.mjs +13 -8
- package/src/tui/app/settings-picker.mjs +55 -58
- package/src/tui/app/slash-dispatch.mjs +32 -28
- package/src/tui/app/transcript-window.mjs +19 -0
- package/src/tui/app/usage-context-panels.mjs +22 -7
- package/src/tui/app/use-mouse-input.mjs +25 -3
- package/src/tui/app/use-prompt-queue-history.mjs +31 -16
- package/src/tui/app/use-transcript-scroll.mjs +30 -8
- package/src/tui/app/use-transcript-window.mjs +22 -1
- package/src/tui/app/use-welcome-prompt-hint.mjs +2 -2
- package/src/tui/components/PromptInput.jsx +10 -0
- package/src/tui/components/Spinner.jsx +89 -86
- package/src/tui/components/TextEntryPanel.jsx +14 -0
- package/src/tui/components/ToolExecution.jsx +2 -2
- package/src/tui/dist/index.mjs +1537 -9718
- package/src/tui/engine/agent-job-feed.mjs +2 -2
- package/src/tui/engine/live-share.mjs +97 -4
- package/src/tui/engine/session-api-ext.mjs +23 -1
- package/src/tui/engine/session-api.mjs +88 -41
- package/src/tui/engine/session-flow.mjs +43 -4
- package/src/tui/engine/tool-card-results.mjs +6 -0
- package/src/tui/engine/turn.mjs +84 -4
- package/src/tui/engine-local-session.mjs +1108 -0
- package/src/tui/engine.mjs +16 -1057
- package/src/tui/index.jsx +47 -2
- package/src/tui/markdown/stream-fence.mjs +1 -1
- package/src/tui/spinner-meta.mjs +80 -0
- package/src/tui/spinner-verbs.mjs +35 -0
- package/src/ui/statusline-segments.mjs +43 -10
- package/src/ui/statusline.mjs +10 -1
- package/scripts/tmp-cdp-errors.mjs +0 -41
- package/scripts/tmp-cdp-inspect.mjs +0 -41
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +0 -176
- package/src/standalone/channel-daemon.mjs +0 -226
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// Machine-global channels daemon entry.
|
|
2
|
-
//
|
|
3
|
-
// One process per machine hosts the channels runtime (worker-main) and exposes
|
|
4
|
-
// it to many TUIs over a local HTTP + SSE transport (see
|
|
5
|
-
// channel-daemon-transport.mjs) instead of the old per-TUI fork + node-IPC.
|
|
6
|
-
// Spawned (or attached-to) by createStandaloneChannelWorker; ownership is a
|
|
7
|
-
// pid-verified singleton lock (singleton-owner.mjs) — NOT the try-once
|
|
8
|
-
// active-instance lock that starved under 6 contending workers. A stale daemon
|
|
9
|
-
// (dead owner pid) is reclaimed by the next claim; a live peer that wins the
|
|
10
|
-
// race makes this process exit(0) so the spawner attaches to the winner.
|
|
11
|
-
//
|
|
12
|
-
// Boot order matters: MIXDOG_CHANNEL_DAEMON must be set BEFORE importing the
|
|
13
|
-
// channels runtime so worker-main skips its parent-IPC loop (runWorkerIpc) and
|
|
14
|
-
// lets this entry own start()/stop() + the transport.
|
|
15
|
-
process.env.MIXDOG_CHANNEL_DAEMON = '1';
|
|
16
|
-
process.env.MIXDOG_WORKER_MODE = process.env.MIXDOG_WORKER_MODE || '1';
|
|
17
|
-
|
|
18
|
-
// V8 compile cache: the daemon is a standalone child entry (not via cli.mjs);
|
|
19
|
-
// caching compiled bytecode across restarts removes the channels+memory
|
|
20
|
-
// runtime parse cost from every daemon boot. Best-effort.
|
|
21
|
-
try {
|
|
22
|
-
const { enableCompileCache } = await import('node:module');
|
|
23
|
-
enableCompileCache?.();
|
|
24
|
-
} catch { /* launch-speed optimization only */ }
|
|
25
|
-
|
|
26
|
-
import os from 'node:os';
|
|
27
|
-
import path from 'node:path';
|
|
28
|
-
import { mkdirSync, appendFileSync } from 'node:fs';
|
|
29
|
-
import { fileURLToPath } from 'node:url';
|
|
30
|
-
import { performance } from 'node:perf_hooks';
|
|
31
|
-
import { claimSingletonOwner, releaseSingletonOwner } from '../runtime/shared/singleton-owner.mjs';
|
|
32
|
-
import { setChannelNotifySink } from '../runtime/channels/lib/parent-bridge.mjs';
|
|
33
|
-
import { setOwnerContext } from '../runtime/channels/lib/runtime-paths.mjs';
|
|
34
|
-
import { safeIpcSend } from '../runtime/shared/safe-ipc-send.mjs';
|
|
35
|
-
import { createChannelDaemonTransport } from './channel-daemon-transport.mjs';
|
|
36
|
-
import { createStandaloneMemoryRuntime } from './memory-runtime-proxy.mjs';
|
|
37
|
-
|
|
38
|
-
function runtimeRoot() {
|
|
39
|
-
return process.env.MIXDOG_RUNTIME_ROOT
|
|
40
|
-
? path.resolve(process.env.MIXDOG_RUNTIME_ROOT)
|
|
41
|
-
: path.join(os.tmpdir(), 'mixdog');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const RUNTIME_ROOT = runtimeRoot();
|
|
45
|
-
const DATA_DIR = process.env.MIXDOG_DATA_DIR ? path.resolve(process.env.MIXDOG_DATA_DIR) : RUNTIME_ROOT;
|
|
46
|
-
const CWD = process.cwd();
|
|
47
|
-
const DISCOVERY_PATH = path.join(RUNTIME_ROOT, 'channel-daemon.json');
|
|
48
|
-
// Owner-election lock, separate from the channels seat/bridge state. Reused
|
|
49
|
-
// pid-verified claim primitive with real claim-lock retry inside.
|
|
50
|
-
const OWNER_PATH = path.join(DATA_DIR, 'channel-daemon-owner.json');
|
|
51
|
-
// Memory runtime is folded into the daemon: the ONE machine-global process is
|
|
52
|
-
// responsible for starting BOTH the channels runtime and the memory runtime.
|
|
53
|
-
// The memory proxy is spawn-or-attach + singleton (memory-runtime-owner lock)
|
|
54
|
-
// and advertises memory_port to active-instance.json exactly as before, so
|
|
55
|
-
// external readers / memory-client.mjs discovery is UNCHANGED.
|
|
56
|
-
const MEMORY_ENTRY = fileURLToPath(new URL('../runtime/memory/index.mjs', import.meta.url));
|
|
57
|
-
|
|
58
|
-
// The spawning TUI mirrors our stderr into this file ONLY until it sees our
|
|
59
|
-
// 'ready' message; after that its pipe consumer dies on parent exit and later
|
|
60
|
-
// lines would be lost. So once ready we append here ourselves (fileLogging on),
|
|
61
|
-
// keyed to the SAME ready event the spawner detaches on — no loss, no dup.
|
|
62
|
-
const LOG_PATH = path.join(DATA_DIR, 'channels-worker-standalone.log');
|
|
63
|
-
let fileLogging = false;
|
|
64
|
-
function log(line) {
|
|
65
|
-
const text = `[channel-daemon] ${line}`;
|
|
66
|
-
// Exactly ONE sink per line: before ready the spawner mirrors our stderr into
|
|
67
|
-
// the log, so write stderr only; after ready we own the file, so write the
|
|
68
|
-
// file only — never both (no duplicate around the ready handoff).
|
|
69
|
-
if (!fileLogging) {
|
|
70
|
-
try { process.stderr.write(`${text}\n`); } catch {}
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
mkdirSync(path.dirname(LOG_PATH), { recursive: true });
|
|
75
|
-
appendFileSync(LOG_PATH, `[${new Date().toISOString()}] ${text}\n`);
|
|
76
|
-
} catch {}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Redirect raw process.stderr/stdout writes and console.* from ANY module in
|
|
80
|
-
// this process to the daemon log file. Installed at the ready boundary (same
|
|
81
|
-
// point fileLogging flips) so pre-ready lines still reach the spawner mirror.
|
|
82
|
-
function installDaemonLogRedirect() {
|
|
83
|
-
if (process.env.MIXDOG_DAEMON_ALLOW_STDERR === '1') return;
|
|
84
|
-
const file = (chunk) => {
|
|
85
|
-
try {
|
|
86
|
-
const text = String(chunk ?? '').trimEnd();
|
|
87
|
-
if (text) {
|
|
88
|
-
mkdirSync(path.dirname(LOG_PATH), { recursive: true });
|
|
89
|
-
appendFileSync(LOG_PATH, `[${new Date().toISOString()}] ${text}\n`);
|
|
90
|
-
}
|
|
91
|
-
} catch { /* logging must never fail the daemon */ }
|
|
92
|
-
};
|
|
93
|
-
const patch = (stream) => {
|
|
94
|
-
stream.write = ((chunk, encoding, callback) => {
|
|
95
|
-
const done = typeof encoding === 'function' ? encoding : callback;
|
|
96
|
-
file(chunk);
|
|
97
|
-
if (typeof done === 'function') { try { done(); } catch {} }
|
|
98
|
-
return true;
|
|
99
|
-
});
|
|
100
|
-
};
|
|
101
|
-
patch(process.stderr);
|
|
102
|
-
patch(process.stdout);
|
|
103
|
-
for (const m of ['log', 'info', 'warn', 'error', 'debug', 'trace']) {
|
|
104
|
-
console[m] = (...args) => file(`[console.${m}] ${args.map((a) => {
|
|
105
|
-
if (typeof a === 'string') return a;
|
|
106
|
-
try { return JSON.stringify(a); } catch { return String(a); }
|
|
107
|
-
}).join(' ')}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
let channels = null;
|
|
112
|
-
let transport = null;
|
|
113
|
-
let memoryRuntime = null;
|
|
114
|
-
let shuttingDown = false;
|
|
115
|
-
|
|
116
|
-
async function shutdown(reason, code = 0) {
|
|
117
|
-
if (shuttingDown) return;
|
|
118
|
-
shuttingDown = true;
|
|
119
|
-
log(`shutting down (${reason})`);
|
|
120
|
-
try { setChannelNotifySink(null); } catch {}
|
|
121
|
-
try { await channels?.stop?.(); } catch (e) { log(`channels.stop failed: ${e?.message || e}`); }
|
|
122
|
-
// Detach the memory client (never hard-kills the shared memory daemon).
|
|
123
|
-
try { await memoryRuntime?.stop?.(); } catch (e) { log(`memory.stop failed: ${e?.message || e}`); }
|
|
124
|
-
try { await transport?.stop?.(); } catch (e) { log(`transport.stop failed: ${e?.message || e}`); }
|
|
125
|
-
try { releaseSingletonOwner(OWNER_PATH, process.pid); } catch {}
|
|
126
|
-
process.exit(code);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async function main() {
|
|
130
|
-
const startedAt = performance.now();
|
|
131
|
-
try { mkdirSync(RUNTIME_ROOT, { recursive: true }); } catch {}
|
|
132
|
-
|
|
133
|
-
// Pid-verified singleton claim (claimSingletonOwner reclaims a dead-pid owner
|
|
134
|
-
// file and refuses only a LIVE peer). Loser exits so the spawner attaches to
|
|
135
|
-
// the winner instead of running a second daemon.
|
|
136
|
-
const claim = claimSingletonOwner(OWNER_PATH, { kind: 'channel-runtime-daemon', pid: process.pid, meta: { cwd: CWD } });
|
|
137
|
-
if (!claim.owned) {
|
|
138
|
-
log(`live peer holds owner lock (pid=${claim.owner?.pid}) — exiting for attach`);
|
|
139
|
-
process.exit(0);
|
|
140
|
-
}
|
|
141
|
-
process.on('exit', () => { try { releaseSingletonOwner(OWNER_PATH, process.pid); } catch {} });
|
|
142
|
-
|
|
143
|
-
// Import the channels runtime AFTER the daemon env is set so worker-main
|
|
144
|
-
// skips runWorkerIpc; this triggers its boot side effects (config/backend).
|
|
145
|
-
channels = await import('../runtime/channels/index.mjs');
|
|
146
|
-
|
|
147
|
-
// Accepted owner controls refresh active-instance context. The transport
|
|
148
|
-
// admits rebind only for the current manual owner.
|
|
149
|
-
const POINTER_TOOLS = new Set(['activate_channel_bridge', 'rebind_current_transcript']);
|
|
150
|
-
const handleCall = (name, args, ctx) => {
|
|
151
|
-
if (ctx && POINTER_TOOLS.has(name)) {
|
|
152
|
-
try { setOwnerContext({ leadPid: ctx.leadPid, cwd: ctx.cwd }); } catch {}
|
|
153
|
-
}
|
|
154
|
-
return channels.handleToolCallWithBridgeRetry(name, args || {});
|
|
155
|
-
};
|
|
156
|
-
transport = createChannelDaemonTransport({
|
|
157
|
-
handleCall,
|
|
158
|
-
// If a manual owner disappears without sending OFF, deactivate the backend.
|
|
159
|
-
// No survivor is selected or rebound.
|
|
160
|
-
dispatchControl: (name, args, ctx) => handleCall(name, args, ctx),
|
|
161
|
-
discoveryPath: DISCOVERY_PATH,
|
|
162
|
-
log,
|
|
163
|
-
// Self-shutdown when the last attached TUI leaves (reuses the SSE/client
|
|
164
|
-
// registry as the liveness signal — mirrors the memory daemon grace).
|
|
165
|
-
onClientsEmpty: () => { void shutdown('no live clients'); },
|
|
166
|
-
});
|
|
167
|
-
setChannelNotifySink((method, params) => transport.notify(method, params));
|
|
168
|
-
const { port, token } = await transport.start();
|
|
169
|
-
|
|
170
|
-
// Ready handshake for the spawner FIRST (mirrors the memory daemon's ready
|
|
171
|
-
// port). Transport is already listening; signal ready before the heavy
|
|
172
|
-
// Discord connect so the spawner's ready wait never blocks on backend I/O.
|
|
173
|
-
// Take over file logging from the spawner at the ready boundary. No rotate
|
|
174
|
-
// here: the spawner already bounds the file at its own boot (channel-worker
|
|
175
|
-
// rotateBoundedLog), and rotating now would race other processes' buffered
|
|
176
|
-
// appends into the same log.
|
|
177
|
-
fileLogging = true;
|
|
178
|
-
// Global stderr/console redirect: runtime modules hosted in this daemon
|
|
179
|
-
// (session sweeps, scheduler, inbound handlers, providers…) write raw
|
|
180
|
-
// process.stderr lines. With the current pipe stdio those bytes die with the
|
|
181
|
-
// spawner, and a daemon inherited from an older spawn path prints them into
|
|
182
|
-
// whatever terminal originally launched it — the "[session-sweep] …" text
|
|
183
|
-
// observed inside the TUI composer. Route EVERY stderr/console line to the
|
|
184
|
-
// daemon log so no spawn mode can ever reach a user terminal.
|
|
185
|
-
installDaemonLogRedirect();
|
|
186
|
-
// Guard the ready handshake against a dead/closing parent pipe. process.send
|
|
187
|
-
// delivery is async: if the spawner TUI already exited, the write fails with
|
|
188
|
-
// an async 'error' (EPIPE) that a sync try/catch cannot catch — it would
|
|
189
|
-
// surface as uncaughtException and (pre-fix) flip the daemon degraded
|
|
190
|
-
// forever. process.connected gates the obvious-dead case; the send callback
|
|
191
|
-
// swallows the async delivery error so it never reaches uncaughtException.
|
|
192
|
-
if (process.connected && process.send) {
|
|
193
|
-
safeIpcSend(process, { type: 'ready', port, token });
|
|
194
|
-
}
|
|
195
|
-
log(`ready port=${port} pid=${process.pid} in ${(performance.now() - startedAt).toFixed(0)}ms`);
|
|
196
|
-
|
|
197
|
-
// Boot messaging only for an explicit manual remote request. Automation may
|
|
198
|
-
// spawn the shared daemon with no remote intent; keep schedules/webhooks live
|
|
199
|
-
// without connecting the channel backend until a manual Remote ON arrives.
|
|
200
|
-
// Legacy `auto` intent is deliberately ignored.
|
|
201
|
-
const remoteIntent = String(process.env.MIXDOG_REMOTE_INTENT || '');
|
|
202
|
-
const messaging = remoteIntent === 'explicit';
|
|
203
|
-
void Promise.resolve().then(() => channels.start({ messaging }))
|
|
204
|
-
.catch((e) => log(`channels.start failed (non-fatal): ${e?.message || e}`));
|
|
205
|
-
|
|
206
|
-
// Fold memory startup in: eagerly ensure the memory runtime is up under the
|
|
207
|
-
// daemon's lifecycle (spawn-or-attach singleton). Fire-and-forget — memory
|
|
208
|
-
// boot is heavy (DB/embeddings) and must NOT delay the ready handshake below
|
|
209
|
-
// (the spawner's ready wait would time out); the proxy publishes memory_port
|
|
210
|
-
// to active-instance.json when ready and memory-client buffers until then.
|
|
211
|
-
try {
|
|
212
|
-
memoryRuntime = createStandaloneMemoryRuntime({ entry: MEMORY_ENTRY, dataDir: DATA_DIR, cwd: CWD });
|
|
213
|
-
void memoryRuntime.start().catch((e) => log(`memory.start failed (non-fatal): ${e?.message || e}`));
|
|
214
|
-
} catch (e) { log(`memory.start setup failed (non-fatal): ${e?.message || e}`); }
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
process.on('SIGTERM', () => { void shutdown('SIGTERM'); });
|
|
218
|
-
process.on('SIGINT', () => { void shutdown('SIGINT'); });
|
|
219
|
-
process.on('message', (msg) => {
|
|
220
|
-
if (msg && msg.type === 'shutdown') void shutdown('IPC shutdown');
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
main().catch((err) => {
|
|
224
|
-
log(`fatal boot error: ${err?.stack || err?.message || err}`);
|
|
225
|
-
void shutdown('fatal boot error', 2);
|
|
226
|
-
});
|