mixdog 0.9.19 → 0.9.20
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/LICENSE +21 -0
- package/README.md +93 -29
- package/package.json +3 -2
- package/scripts/build-runtime-windows.ps1 +242 -242
- package/scripts/build-tui.mjs +6 -0
- package/scripts/hook-bus-test.mjs +8 -0
- package/scripts/log-writer-guard-smoke.mjs +131 -0
- package/scripts/reactive-compact-persist-smoke.mjs +22 -6
- package/scripts/recall-bench-cases.json +0 -1
- package/scripts/recall-quality-cases.json +1 -2
- package/scripts/recall-usecase-cases.json +1 -1
- package/scripts/session-ingest-compaction-smoke.mjs +241 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -106
- package/scripts/tool-efficiency-diag.mjs +1 -1
- package/scripts/tool-smoke.mjs +150 -45
- package/src/help.mjs +2 -5
- package/src/lib/mixdog-debug.cjs +13 -0
- package/src/mixdog-session-runtime.mjs +7 -3328
- package/src/rules/lead/02-channels.md +3 -3
- package/src/runtime/agent/orchestrator/context/collect.mjs +33 -9
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +663 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +153 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/loop.mjs +8 -1860
- package/src/runtime/agent/orchestrator/session/manager/agent-runtime-singleton.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +686 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +60 -12
- package/src/runtime/agent/orchestrator/session/manager/env-utils.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +159 -0
- package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +143 -0
- package/src/runtime/agent/orchestrator/session/manager/prefetch-bridge.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/manager/provider-cache-key.mjs +22 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-loaders.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +124 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +258 -0
- package/src/runtime/agent/orchestrator/session/manager/session-errors.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-id.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +475 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +88 -2285
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +440 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +153 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +642 -0
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +23 -3
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +108 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +15 -3
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +7 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +24 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +72 -8
- package/src/runtime/agent/orchestrator/tools/shell-policy-danger-target.mjs +5 -1
- package/src/runtime/channels/index.mjs +6 -2183
- package/src/runtime/channels/lib/inbound-handler.mjs +328 -0
- package/src/runtime/channels/lib/interaction-handlers.mjs +260 -0
- package/src/runtime/channels/lib/network-retry.mjs +23 -0
- package/src/runtime/channels/lib/owned-runtime.mjs +547 -0
- package/src/runtime/channels/lib/transcript-binding.mjs +336 -0
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +39 -2
- package/src/runtime/channels/lib/worker-bootstrap.mjs +97 -0
- package/src/runtime/channels/lib/worker-ipc.mjs +201 -0
- package/src/runtime/channels/lib/worker-main.mjs +771 -0
- package/src/runtime/memory/index.mjs +73 -1725
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -2
- package/src/runtime/memory/lib/embedding-worker.mjs +47 -6
- package/src/runtime/memory/lib/http-router.mjs +772 -0
- package/src/runtime/memory/lib/memory-action-handlers.mjs +901 -0
- package/src/runtime/memory/lib/memory-embed.mjs +28 -7
- package/src/runtime/memory/lib/memory-recall-store.mjs +4 -4
- package/src/runtime/memory/lib/query-handlers.mjs +2 -2
- package/src/runtime/memory/lib/session-ingest-runtime.mjs +401 -0
- package/src/session-runtime/boot-profile.mjs +36 -0
- package/src/session-runtime/channel-config-api.mjs +70 -0
- package/src/session-runtime/context-status.mjs +181 -0
- package/src/session-runtime/env.mjs +17 -0
- package/src/session-runtime/lifecycle-api.mjs +242 -0
- package/src/session-runtime/model-route-api.mjs +198 -0
- package/src/session-runtime/provider-auth-api.mjs +135 -0
- package/src/session-runtime/resource-api.mjs +282 -0
- package/src/session-runtime/runtime-core.mjs +2046 -0
- package/src/session-runtime/session-turn-api.mjs +274 -0
- package/src/session-runtime/tool-catalog.mjs +18 -264
- package/src/session-runtime/tool-defs.mjs +2 -2
- package/src/session-runtime/workflow-agents-api.mjs +238 -0
- package/src/standalone/agent-tool.mjs +2 -2
- package/src/standalone/channel-worker.mjs +4 -0
- package/src/standalone/memory-runtime-proxy.mjs +56 -6
- package/src/tui/App.jsx +39 -28
- package/src/tui/app/core-memory-picker.mjs +1 -1
- package/src/tui/app/use-mouse-input.mjs +6 -0
- package/src/tui/app/use-transcript-scroll.mjs +77 -3
- package/src/tui/dist/index.mjs +1990 -1527
- package/src/tui/engine/context-state.mjs +145 -0
- package/src/tui/engine/prompt-history.mjs +27 -0
- package/src/tui/engine/session-api-ext.mjs +478 -0
- package/src/tui/engine/session-api.mjs +545 -0
- package/src/tui/engine/session-flow.mjs +485 -0
- package/src/tui/engine/turn.mjs +1078 -0
- package/src/tui/engine.mjs +68 -2620
- package/src/tui/index.jsx +7 -0
- package/vendor/ink/build/ink.js +16 -1
- package/vendor/ink/build/output.js +30 -4
- package/vendor/ink/build/render.js +5 -0
- package/src/workflows/sequential/WORKFLOW.md +0 -51
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
beginOAuthProviderLogin,
|
|
3
|
+
forgetProviderAuth,
|
|
4
|
+
isKnownProvider,
|
|
5
|
+
loginOAuthProvider,
|
|
6
|
+
renderProviderStatus,
|
|
7
|
+
saveOpenAIUsageSessionKey,
|
|
8
|
+
saveOpenCodeGoUsageAuth,
|
|
9
|
+
loginOpenCodeGoUsage,
|
|
10
|
+
saveProviderApiKey,
|
|
11
|
+
setLocalProvider,
|
|
12
|
+
} from '../standalone/provider-admin.mjs';
|
|
13
|
+
import { clean } from './session-text.mjs';
|
|
14
|
+
|
|
15
|
+
// Provider auth / catalog / preset surface. Extracted verbatim from the runtime
|
|
16
|
+
// API object; the stateless admin helpers are imported directly and the runtime
|
|
17
|
+
// injects the closure-owned config/cache callbacks. `isKnownProvider` is
|
|
18
|
+
// re-imported here from provider-admin (same binding the runtime uses).
|
|
19
|
+
export function createProviderAuthApi({
|
|
20
|
+
cfgMod,
|
|
21
|
+
getConfig,
|
|
22
|
+
saveConfigAndAdopt,
|
|
23
|
+
displayConfig,
|
|
24
|
+
reloadFullConfig,
|
|
25
|
+
invalidateProviderCaches,
|
|
26
|
+
warmProviderModelCache,
|
|
27
|
+
cachedProviderSetup,
|
|
28
|
+
getUsageDashboard,
|
|
29
|
+
collectProviderModels,
|
|
30
|
+
}) {
|
|
31
|
+
return {
|
|
32
|
+
listProviders() {
|
|
33
|
+
return renderProviderStatus(displayConfig());
|
|
34
|
+
},
|
|
35
|
+
async getProviderSetup() {
|
|
36
|
+
return await cachedProviderSetup();
|
|
37
|
+
},
|
|
38
|
+
async getUsageDashboard(options = {}) {
|
|
39
|
+
return await getUsageDashboard(options);
|
|
40
|
+
},
|
|
41
|
+
async authenticateProvider(providerId, secret) {
|
|
42
|
+
const result = String(secret || '').trim()
|
|
43
|
+
? saveProviderApiKey(cfgMod, providerId, secret)
|
|
44
|
+
: await loginOAuthProvider(cfgMod, providerId);
|
|
45
|
+
reloadFullConfig();
|
|
46
|
+
invalidateProviderCaches();
|
|
47
|
+
warmProviderModelCache();
|
|
48
|
+
return result;
|
|
49
|
+
},
|
|
50
|
+
async loginOAuthProvider(providerId) {
|
|
51
|
+
const result = await loginOAuthProvider(cfgMod, providerId);
|
|
52
|
+
reloadFullConfig();
|
|
53
|
+
invalidateProviderCaches();
|
|
54
|
+
warmProviderModelCache();
|
|
55
|
+
return result;
|
|
56
|
+
},
|
|
57
|
+
async beginOAuthProviderLogin(providerId) {
|
|
58
|
+
const result = await beginOAuthProviderLogin(cfgMod, providerId);
|
|
59
|
+
reloadFullConfig();
|
|
60
|
+
return {
|
|
61
|
+
...result,
|
|
62
|
+
waitForCallback: result.waitForCallback?.then((completed) => {
|
|
63
|
+
reloadFullConfig();
|
|
64
|
+
if (completed) {
|
|
65
|
+
invalidateProviderCaches();
|
|
66
|
+
warmProviderModelCache();
|
|
67
|
+
}
|
|
68
|
+
return completed;
|
|
69
|
+
}),
|
|
70
|
+
completeCode: async (code) => {
|
|
71
|
+
const completed = await result.completeCode(code);
|
|
72
|
+
reloadFullConfig();
|
|
73
|
+
invalidateProviderCaches();
|
|
74
|
+
warmProviderModelCache();
|
|
75
|
+
return completed;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
saveProviderApiKey(providerId, secret) {
|
|
80
|
+
const result = saveProviderApiKey(cfgMod, providerId, secret);
|
|
81
|
+
reloadFullConfig();
|
|
82
|
+
invalidateProviderCaches();
|
|
83
|
+
warmProviderModelCache();
|
|
84
|
+
return result;
|
|
85
|
+
},
|
|
86
|
+
saveOpenAIUsageSessionKey(secret) {
|
|
87
|
+
const result = saveOpenAIUsageSessionKey(cfgMod, secret);
|
|
88
|
+
reloadFullConfig();
|
|
89
|
+
invalidateProviderCaches();
|
|
90
|
+
return result;
|
|
91
|
+
},
|
|
92
|
+
saveOpenCodeGoUsageAuth(opts) {
|
|
93
|
+
const result = saveOpenCodeGoUsageAuth(cfgMod, opts);
|
|
94
|
+
reloadFullConfig();
|
|
95
|
+
invalidateProviderCaches();
|
|
96
|
+
return result;
|
|
97
|
+
},
|
|
98
|
+
async loginOpenCodeGoUsage() {
|
|
99
|
+
const result = await loginOpenCodeGoUsage(cfgMod);
|
|
100
|
+
reloadFullConfig();
|
|
101
|
+
invalidateProviderCaches();
|
|
102
|
+
return result;
|
|
103
|
+
},
|
|
104
|
+
setLocalProvider(providerId, opts) {
|
|
105
|
+
const result = setLocalProvider(cfgMod, providerId, opts);
|
|
106
|
+
reloadFullConfig();
|
|
107
|
+
invalidateProviderCaches();
|
|
108
|
+
warmProviderModelCache();
|
|
109
|
+
return result;
|
|
110
|
+
},
|
|
111
|
+
forgetProviderAuth(providerId) {
|
|
112
|
+
const result = forgetProviderAuth(cfgMod, providerId);
|
|
113
|
+
reloadFullConfig();
|
|
114
|
+
invalidateProviderCaches();
|
|
115
|
+
warmProviderModelCache();
|
|
116
|
+
return result;
|
|
117
|
+
},
|
|
118
|
+
listPresets() {
|
|
119
|
+
return cfgMod.listPresets(displayConfig());
|
|
120
|
+
},
|
|
121
|
+
async listProviderModels(options = {}) {
|
|
122
|
+
return await collectProviderModels({
|
|
123
|
+
force: options.force === true || options.refresh === true,
|
|
124
|
+
quick: options.quick === true,
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
async setDefaultProvider(provider) {
|
|
128
|
+
const requested = clean(provider);
|
|
129
|
+
if (!requested) throw new Error('provider is required');
|
|
130
|
+
if (!isKnownProvider(requested)) throw new Error(`unknown provider "${provider}"`);
|
|
131
|
+
saveConfigAndAdopt({ ...getConfig(), defaultProvider: requested });
|
|
132
|
+
return requested;
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import {
|
|
4
|
+
clean,
|
|
5
|
+
toolResponseText,
|
|
6
|
+
isEmptyRecallText,
|
|
7
|
+
currentSessionRecallRows,
|
|
8
|
+
} from './session-text.mjs';
|
|
9
|
+
import {
|
|
10
|
+
addPlugin as registryAddPlugin,
|
|
11
|
+
removePlugin as registryRemovePlugin,
|
|
12
|
+
updatePlugin as registryUpdatePlugin,
|
|
13
|
+
} from '../standalone/plugin-admin.mjs';
|
|
14
|
+
import {
|
|
15
|
+
normalizePluginMcpServerConfig,
|
|
16
|
+
pluginMcpServerName,
|
|
17
|
+
pluginRawMcpServers,
|
|
18
|
+
pluginMcpEnableScript,
|
|
19
|
+
resolveContainedPluginPath,
|
|
20
|
+
} from './plugin-mcp.mjs';
|
|
21
|
+
|
|
22
|
+
// MCP servers, skills, plugins, hooks, and memory/recall surfaces. Extracted
|
|
23
|
+
// verbatim from the runtime API object; stateless helpers are imported directly
|
|
24
|
+
// and the runtime injects live state getters plus the closure callbacks.
|
|
25
|
+
export function createResourceApi(deps) {
|
|
26
|
+
const {
|
|
27
|
+
getConfig, getSession, getCurrentCwd,
|
|
28
|
+
cfgMod, mgr, hooks, STANDALONE_DATA_DIR,
|
|
29
|
+
saveConfigAndAdopt, connectConfiguredMcp, invalidatePreSessionToolSurface,
|
|
30
|
+
recreateCurrentSessionIfReady, normalizeMcpServerInput, mcpStatus,
|
|
31
|
+
skillsStatus, skillContent, addProjectSkill, pluginsStatus, getMemoryModule,
|
|
32
|
+
reloadFullConfig,
|
|
33
|
+
} = deps;
|
|
34
|
+
return {
|
|
35
|
+
mcpStatus() {
|
|
36
|
+
return mcpStatus();
|
|
37
|
+
},
|
|
38
|
+
async reconnectMcp() {
|
|
39
|
+
reloadFullConfig();
|
|
40
|
+
const status = await connectConfiguredMcp({ reset: true });
|
|
41
|
+
invalidatePreSessionToolSurface();
|
|
42
|
+
const session = getSession();
|
|
43
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-mcp-reconnect');
|
|
44
|
+
await recreateCurrentSessionIfReady();
|
|
45
|
+
return status;
|
|
46
|
+
},
|
|
47
|
+
async addMcpServer(input = {}) {
|
|
48
|
+
const { name, config: serverConfig } = normalizeMcpServerInput(input);
|
|
49
|
+
const nextConfig = { ...getConfig() };
|
|
50
|
+
nextConfig.mcpServers = {
|
|
51
|
+
...(nextConfig.mcpServers || {}),
|
|
52
|
+
[name]: serverConfig,
|
|
53
|
+
};
|
|
54
|
+
saveConfigAndAdopt(nextConfig);
|
|
55
|
+
const status = await connectConfiguredMcp({ reset: true });
|
|
56
|
+
invalidatePreSessionToolSurface();
|
|
57
|
+
const session = getSession();
|
|
58
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-mcp-add');
|
|
59
|
+
await recreateCurrentSessionIfReady();
|
|
60
|
+
return { name, status };
|
|
61
|
+
},
|
|
62
|
+
async removeMcpServer(name) {
|
|
63
|
+
const serverName = clean(name);
|
|
64
|
+
if (!serverName) throw new Error('MCP server name is required');
|
|
65
|
+
const nextConfig = { ...getConfig() };
|
|
66
|
+
const current = nextConfig.mcpServers && typeof nextConfig.mcpServers === 'object'
|
|
67
|
+
? { ...nextConfig.mcpServers }
|
|
68
|
+
: {};
|
|
69
|
+
if (!Object.prototype.hasOwnProperty.call(current, serverName)) {
|
|
70
|
+
throw new Error(`MCP server not configured: ${serverName}`);
|
|
71
|
+
}
|
|
72
|
+
delete current[serverName];
|
|
73
|
+
saveConfigAndAdopt({ ...nextConfig, mcpServers: current });
|
|
74
|
+
const status = await connectConfiguredMcp({ reset: true });
|
|
75
|
+
invalidatePreSessionToolSurface();
|
|
76
|
+
const session = getSession();
|
|
77
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-mcp-remove');
|
|
78
|
+
await recreateCurrentSessionIfReady();
|
|
79
|
+
return status;
|
|
80
|
+
},
|
|
81
|
+
async setMcpServerEnabled(name, enabled) {
|
|
82
|
+
const serverName = clean(name);
|
|
83
|
+
if (!serverName) throw new Error('MCP server name is required');
|
|
84
|
+
const nextConfig = { ...getConfig() };
|
|
85
|
+
const current = nextConfig.mcpServers && typeof nextConfig.mcpServers === 'object'
|
|
86
|
+
? { ...nextConfig.mcpServers }
|
|
87
|
+
: {};
|
|
88
|
+
if (!Object.prototype.hasOwnProperty.call(current, serverName)) {
|
|
89
|
+
throw new Error(`MCP server not configured: ${serverName}`);
|
|
90
|
+
}
|
|
91
|
+
current[serverName] = { ...(current[serverName] || {}), enabled: enabled !== false };
|
|
92
|
+
saveConfigAndAdopt({ ...nextConfig, mcpServers: current });
|
|
93
|
+
const status = await connectConfiguredMcp({ reset: true });
|
|
94
|
+
invalidatePreSessionToolSurface();
|
|
95
|
+
const session = getSession();
|
|
96
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-mcp-toggle');
|
|
97
|
+
await recreateCurrentSessionIfReady();
|
|
98
|
+
return status;
|
|
99
|
+
},
|
|
100
|
+
skillsStatus() {
|
|
101
|
+
return skillsStatus();
|
|
102
|
+
},
|
|
103
|
+
skillContent(name) {
|
|
104
|
+
return skillContent(name);
|
|
105
|
+
},
|
|
106
|
+
async addSkill(input = {}) {
|
|
107
|
+
const skill = addProjectSkill(input);
|
|
108
|
+
const session = getSession();
|
|
109
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-skill-add');
|
|
110
|
+
await recreateCurrentSessionIfReady();
|
|
111
|
+
return { skill, status: skillsStatus() };
|
|
112
|
+
},
|
|
113
|
+
async reloadSkills() {
|
|
114
|
+
const session = getSession();
|
|
115
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-skills-reload');
|
|
116
|
+
await recreateCurrentSessionIfReady();
|
|
117
|
+
return skillsStatus();
|
|
118
|
+
},
|
|
119
|
+
pluginsStatus() {
|
|
120
|
+
return pluginsStatus();
|
|
121
|
+
},
|
|
122
|
+
async reloadPlugins() {
|
|
123
|
+
const session = getSession();
|
|
124
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-plugins-reload');
|
|
125
|
+
await recreateCurrentSessionIfReady();
|
|
126
|
+
return pluginsStatus();
|
|
127
|
+
},
|
|
128
|
+
async addPlugin(source) {
|
|
129
|
+
const dataDir = cfgMod.getPluginData?.();
|
|
130
|
+
const plugin = registryAddPlugin(source, { dataDir });
|
|
131
|
+
const session = getSession();
|
|
132
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-plugin-add');
|
|
133
|
+
await recreateCurrentSessionIfReady();
|
|
134
|
+
return { plugin, status: pluginsStatus() };
|
|
135
|
+
},
|
|
136
|
+
async updatePlugin(plugin = {}) {
|
|
137
|
+
const key = clean(plugin.id || plugin.name || plugin);
|
|
138
|
+
const dataDir = cfgMod.getPluginData?.();
|
|
139
|
+
const updated = registryUpdatePlugin(key, { dataDir });
|
|
140
|
+
const session = getSession();
|
|
141
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-plugin-update');
|
|
142
|
+
await recreateCurrentSessionIfReady();
|
|
143
|
+
return { plugin: updated, status: pluginsStatus() };
|
|
144
|
+
},
|
|
145
|
+
async removePlugin(plugin = {}) {
|
|
146
|
+
const key = clean(plugin.id || plugin.name || plugin);
|
|
147
|
+
const dataDir = cfgMod.getPluginData?.();
|
|
148
|
+
const removed = registryRemovePlugin(key, { dataDir });
|
|
149
|
+
const nextConfig = { ...getConfig() };
|
|
150
|
+
const serverName = pluginMcpServerName(plugin);
|
|
151
|
+
const prefix = `${serverName}--`;
|
|
152
|
+
const hasMatch = nextConfig.mcpServers && Object.keys(nextConfig.mcpServers).some(
|
|
153
|
+
(k) => k === serverName || k.startsWith(prefix)
|
|
154
|
+
);
|
|
155
|
+
if (hasMatch) {
|
|
156
|
+
const current = { ...nextConfig.mcpServers };
|
|
157
|
+
for (const k of Object.keys(current)) {
|
|
158
|
+
if (k === serverName || k.startsWith(prefix)) delete current[k];
|
|
159
|
+
}
|
|
160
|
+
saveConfigAndAdopt({ ...nextConfig, mcpServers: current });
|
|
161
|
+
await connectConfiguredMcp({ reset: true });
|
|
162
|
+
invalidatePreSessionToolSurface();
|
|
163
|
+
}
|
|
164
|
+
const session = getSession();
|
|
165
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-plugin-remove');
|
|
166
|
+
await recreateCurrentSessionIfReady();
|
|
167
|
+
return { plugin: removed, status: pluginsStatus() };
|
|
168
|
+
},
|
|
169
|
+
async enablePluginMcp(plugin = {}) {
|
|
170
|
+
const root = clean(plugin.root);
|
|
171
|
+
const script = pluginMcpEnableScript(root, plugin);
|
|
172
|
+
if (!root || !script) throw new Error('plugin has no MCP script');
|
|
173
|
+
const serverName = pluginMcpServerName(plugin);
|
|
174
|
+
const nextConfig = { ...getConfig() };
|
|
175
|
+
const manifestMcp = pluginRawMcpServers(root, script);
|
|
176
|
+
if (manifestMcp) {
|
|
177
|
+
const { rawServers, mcpRoot } = manifestMcp;
|
|
178
|
+
const keys = Object.keys(rawServers).filter((k) => {
|
|
179
|
+
const v = rawServers[k];
|
|
180
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
181
|
+
});
|
|
182
|
+
const ownedPrefix = `${serverName}--`;
|
|
183
|
+
const nextServers = {};
|
|
184
|
+
for (const [k, v] of Object.entries(nextConfig.mcpServers || {})) {
|
|
185
|
+
if (k === serverName || k.startsWith(ownedPrefix)) continue;
|
|
186
|
+
nextServers[k] = v;
|
|
187
|
+
}
|
|
188
|
+
for (const serverKey of keys) {
|
|
189
|
+
const cfg = normalizePluginMcpServerConfig(rawServers[serverKey], mcpRoot);
|
|
190
|
+
cfg.env = {
|
|
191
|
+
...(cfg.env || {}),
|
|
192
|
+
MIXDOG_PLUGIN_ROOT: root,
|
|
193
|
+
MIXDOG_PLUGIN_DATA: join(cfgMod.getPluginData?.() || STANDALONE_DATA_DIR, 'plugins', 'data', clean(plugin.id || plugin.name || serverName)),
|
|
194
|
+
};
|
|
195
|
+
const key = keys.length === 1 ? serverName : `${serverName}--${serverKey}`;
|
|
196
|
+
nextServers[key] = cfg;
|
|
197
|
+
}
|
|
198
|
+
nextConfig.mcpServers = nextServers;
|
|
199
|
+
} else {
|
|
200
|
+
const scriptPath = resolveContainedPluginPath(root, script);
|
|
201
|
+
if (!scriptPath || !existsSync(scriptPath)) throw new Error(`plugin MCP script not found: ${join(root, script)}`);
|
|
202
|
+
nextConfig.mcpServers = {
|
|
203
|
+
...(nextConfig.mcpServers || {}),
|
|
204
|
+
[serverName]: {
|
|
205
|
+
command: 'node',
|
|
206
|
+
args: [scriptPath],
|
|
207
|
+
cwd: root,
|
|
208
|
+
env: {
|
|
209
|
+
MIXDOG_PLUGIN_ROOT: root,
|
|
210
|
+
MIXDOG_PLUGIN_DATA: join(cfgMod.getPluginData?.() || STANDALONE_DATA_DIR, 'plugins', 'data', clean(plugin.id || plugin.name || serverName)),
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
saveConfigAndAdopt(nextConfig);
|
|
216
|
+
const status = await connectConfiguredMcp({ reset: true });
|
|
217
|
+
invalidatePreSessionToolSurface();
|
|
218
|
+
const session = getSession();
|
|
219
|
+
if (session?.id) mgr.closeSession(session.id, 'cli-plugin-mcp-enable');
|
|
220
|
+
await recreateCurrentSessionIfReady();
|
|
221
|
+
return { serverName, status };
|
|
222
|
+
},
|
|
223
|
+
hooksStatus() {
|
|
224
|
+
return hooks.status();
|
|
225
|
+
},
|
|
226
|
+
addHookRule(rule) {
|
|
227
|
+
return hooks.addRule(rule);
|
|
228
|
+
},
|
|
229
|
+
setHookRuleEnabled(index, enabled) {
|
|
230
|
+
return hooks.setRuleEnabled(index, enabled);
|
|
231
|
+
},
|
|
232
|
+
deleteHookRule(index) {
|
|
233
|
+
return hooks.deleteRule(index);
|
|
234
|
+
},
|
|
235
|
+
async memoryControl(args = {}) {
|
|
236
|
+
const memoryMod = await getMemoryModule();
|
|
237
|
+
if (!memoryMod?.handleToolCall) throw new Error('memory runtime is not available');
|
|
238
|
+
return toolResponseText(await memoryMod.handleToolCall('memory', args || {}));
|
|
239
|
+
},
|
|
240
|
+
async recall(query, args = {}) {
|
|
241
|
+
const session = getSession();
|
|
242
|
+
const currentCwd = getCurrentCwd();
|
|
243
|
+
const baseQuery = query || args?.query || '';
|
|
244
|
+
if (args?.currentSession !== false && session?.id) {
|
|
245
|
+
const currentText = currentSessionRecallRows(session, baseQuery, { limit: args?.limit });
|
|
246
|
+
if (!isEmptyRecallText(currentText)) return currentText;
|
|
247
|
+
}
|
|
248
|
+
const memoryMod = await getMemoryModule();
|
|
249
|
+
if (!memoryMod?.handleToolCall) throw new Error('memory runtime is not available');
|
|
250
|
+
const baseArgs = {
|
|
251
|
+
...(args || {}),
|
|
252
|
+
query: baseQuery,
|
|
253
|
+
cwd: args?.cwd || currentCwd,
|
|
254
|
+
...(session?.id ? { currentSessionId: session.id } : {}),
|
|
255
|
+
};
|
|
256
|
+
let result = '(no results)';
|
|
257
|
+
if (session?.id && args?.currentSession !== false && args?.forceCycleOnEmpty !== false) {
|
|
258
|
+
const messages = Array.isArray(session.messages) ? session.messages : [];
|
|
259
|
+
if (messages.length > 0) {
|
|
260
|
+
await memoryMod.handleToolCall('memory', {
|
|
261
|
+
action: 'ingest_session',
|
|
262
|
+
sessionId: session.id,
|
|
263
|
+
cwd: currentCwd,
|
|
264
|
+
messages,
|
|
265
|
+
});
|
|
266
|
+
result = toolResponseText(await memoryMod.handleToolCall('recall', {
|
|
267
|
+
...baseArgs,
|
|
268
|
+
sessionId: session.id,
|
|
269
|
+
currentSession: true,
|
|
270
|
+
projectScope: baseArgs.projectScope || 'all',
|
|
271
|
+
includeRaw: baseArgs.includeRaw !== false,
|
|
272
|
+
includeArchived: baseArgs.includeArchived !== false,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (isEmptyRecallText(result)) {
|
|
277
|
+
result = toolResponseText(await memoryMod.handleToolCall('recall', baseArgs));
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|