funolio-agent 1.0.47 → 1.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-config.d.ts +9 -1
- package/dist/agent-config.d.ts.map +1 -1
- package/dist/agent-config.js +4 -1
- package/dist/agent-config.js.map +1 -1
- package/dist/auto-organizer.d.ts.map +1 -1
- package/dist/auto-organizer.js +4 -3
- package/dist/auto-organizer.js.map +1 -1
- package/dist/backfill.d.ts.map +1 -1
- package/dist/backfill.js +3 -2
- package/dist/backfill.js.map +1 -1
- package/dist/bot-manager.d.ts +7 -23
- package/dist/bot-manager.d.ts.map +1 -1
- package/dist/bot-manager.js +52 -388
- package/dist/bot-manager.js.map +1 -1
- package/dist/clerk-model.d.ts +5 -1
- package/dist/clerk-model.d.ts.map +1 -1
- package/dist/clerk-model.js +40 -28
- package/dist/clerk-model.js.map +1 -1
- package/dist/cli-session-epoch.d.ts +10 -0
- package/dist/cli-session-epoch.d.ts.map +1 -0
- package/dist/cli-session-epoch.js +61 -0
- package/dist/cli-session-epoch.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +30 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pool.js +1 -1
- package/dist/commands/pool.js.map +1 -1
- package/dist/commands/setup.d.ts +37 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +146 -43
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +194 -164
- package/dist/commands/start.js.map +1 -1
- package/dist/config-cleanup.d.ts.map +1 -1
- package/dist/config-cleanup.js +2 -1
- package/dist/config-cleanup.js.map +1 -1
- package/dist/config.d.ts +6 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -30
- package/dist/config.js.map +1 -1
- package/dist/context-window.d.ts +33 -5
- package/dist/context-window.d.ts.map +1 -1
- package/dist/context-window.js +121 -20
- package/dist/context-window.js.map +1 -1
- package/dist/eval/orchestrator-front-door-replay.js +1 -1
- package/dist/eval/orchestrator-front-door-replay.js.map +1 -1
- package/dist/eval/policy-detection-replay.js +1 -1
- package/dist/eval/policy-detection-replay.js.map +1 -1
- package/dist/integration-tokens.d.ts +1 -6
- package/dist/integration-tokens.d.ts.map +1 -1
- package/dist/integration-tokens.js +38 -40
- package/dist/integration-tokens.js.map +1 -1
- package/dist/local-cli-pty-manager.d.ts +50 -0
- package/dist/local-cli-pty-manager.d.ts.map +1 -0
- package/dist/local-cli-pty-manager.js +645 -0
- package/dist/local-cli-pty-manager.js.map +1 -0
- package/dist/local-data.d.ts +30 -0
- package/dist/local-data.d.ts.map +1 -1
- package/dist/local-data.js +56 -1
- package/dist/local-data.js.map +1 -1
- package/dist/local-db.d.ts.map +1 -1
- package/dist/local-db.js +54 -1
- package/dist/local-db.js.map +1 -1
- package/dist/local-funnel.d.ts.map +1 -1
- package/dist/local-funnel.js +3 -2
- package/dist/local-funnel.js.map +1 -1
- package/dist/local-memory-search.d.ts +1 -0
- package/dist/local-memory-search.d.ts.map +1 -1
- package/dist/local-memory-search.js +101 -18
- package/dist/local-memory-search.js.map +1 -1
- package/dist/local-server.d.ts +0 -16
- package/dist/local-server.d.ts.map +1 -1
- package/dist/local-server.js +339 -287
- package/dist/local-server.js.map +1 -1
- package/dist/mcp/bridge-server.d.ts.map +1 -1
- package/dist/mcp/bridge-server.js +2 -1
- package/dist/mcp/bridge-server.js.map +1 -1
- package/dist/mcp/local-memory-server.d.ts +5 -0
- package/dist/mcp/local-memory-server.d.ts.map +1 -1
- package/dist/mcp/local-memory-server.js +15 -2
- package/dist/mcp/local-memory-server.js.map +1 -1
- package/dist/mcp/manager.d.ts +3 -22
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +66 -388
- package/dist/mcp/manager.js.map +1 -1
- package/dist/memory-extraction.d.ts +2 -0
- package/dist/memory-extraction.d.ts.map +1 -1
- package/dist/memory-extraction.js +3 -1
- package/dist/memory-extraction.js.map +1 -1
- package/dist/message-loop.d.ts +9 -6
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +217 -538
- package/dist/message-loop.js.map +1 -1
- package/dist/mqtt-client.d.ts +2 -31
- package/dist/mqtt-client.d.ts.map +1 -1
- package/dist/mqtt-client.js +2 -2
- package/dist/mqtt-client.js.map +1 -1
- package/dist/oauth.d.ts +6 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +91 -0
- package/dist/oauth.js.map +1 -1
- package/dist/orchestration/front-door-policy.d.ts +5 -2
- package/dist/orchestration/front-door-policy.d.ts.map +1 -1
- package/dist/orchestration/front-door-policy.js +25 -28
- package/dist/orchestration/front-door-policy.js.map +1 -1
- package/dist/orchestration/orchestrator-blocked-prompt.js +1 -1
- package/dist/orchestration/orchestrator-final-response-prompt.js +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.d.ts +11 -0
- package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.js +67 -44
- package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
- package/dist/orchestration/worker-operating-prompt.js +3 -3
- package/dist/orchestration/worker-operating-prompt.js.map +1 -1
- package/dist/orchestrator.d.ts +5 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +141 -81
- package/dist/orchestrator.js.map +1 -1
- package/dist/prompt-template.js +3 -3
- package/dist/prompt-template.js.map +1 -1
- package/dist/providers/claude-cli-prompt.d.ts.map +1 -1
- package/dist/providers/claude-cli-prompt.js +22 -6
- package/dist/providers/claude-cli-prompt.js.map +1 -1
- package/dist/providers/claude-cli.d.ts.map +1 -1
- package/dist/providers/claude-cli.js +20 -2
- package/dist/providers/claude-cli.js.map +1 -1
- package/dist/providers/codex-cli.d.ts.map +1 -1
- package/dist/providers/codex-cli.js +71 -16
- package/dist/providers/codex-cli.js.map +1 -1
- package/dist/providers/index.d.ts +11 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/runtime-context.d.ts +10 -0
- package/dist/runtime-context.d.ts.map +1 -0
- package/dist/runtime-context.js +30 -0
- package/dist/runtime-context.js.map +1 -0
- package/dist/subagent/queue.d.ts.map +1 -1
- package/dist/subagent/queue.js +1 -0
- package/dist/subagent/queue.js.map +1 -1
- package/dist/summarization-pipeline.d.ts +1 -0
- package/dist/summarization-pipeline.d.ts.map +1 -1
- package/dist/summarization-pipeline.js +94 -25
- package/dist/summarization-pipeline.js.map +1 -1
- package/dist/tool-permissions.d.ts +2 -0
- package/dist/tool-permissions.d.ts.map +1 -0
- package/dist/tool-permissions.js +25 -0
- package/dist/tool-permissions.js.map +1 -0
- package/dist/tools/index.d.ts +7 -8
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +70 -60
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/search-memory.d.ts.map +1 -1
- package/dist/tools/search-memory.js +9 -3
- package/dist/tools/search-memory.js.map +1 -1
- package/dist/tools/spawn-subagent.d.ts.map +1 -1
- package/dist/tools/spawn-subagent.js +1 -0
- package/dist/tools/spawn-subagent.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +1 -1
- package/dist/wizard-support.d.ts.map +1 -1
- package/dist/wizard-support.js +8 -6
- package/dist/wizard-support.js.map +1 -1
- package/dist/workflow-engine.d.ts +6 -2
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/workflow-engine.js +254 -77
- package/dist/workflow-engine.js.map +1 -1
- package/package.json +2 -1
package/dist/commands/start.js
CHANGED
|
@@ -49,11 +49,10 @@ const service_mode_1 = require("../service-mode");
|
|
|
49
49
|
const index_1 = require("../providers/index");
|
|
50
50
|
const sync_cli_config_1 = require("../mcp/sync-cli-config");
|
|
51
51
|
const agent_config_1 = require("../agent-config");
|
|
52
|
+
// refreshOAuthToken removed — token refresh now handled per-request in message-loop.ts
|
|
52
53
|
const local_db_1 = require("../local-db");
|
|
53
54
|
const local_server_1 = require("../local-server");
|
|
54
55
|
const data = __importStar(require("../local-data"));
|
|
55
|
-
const default_tool_profile_1 = require("../default-tool-profile");
|
|
56
|
-
const approval_1 = require("../approval");
|
|
57
56
|
const AUTH_SESSION_KEY = 'auth.session';
|
|
58
57
|
const DESKTOP_PREFS_KEY = 'desktop.preferences';
|
|
59
58
|
const WIZARD_PROFILE_KEY = 'wizard.profile';
|
|
@@ -79,33 +78,15 @@ function readLastInteractionAtMs() {
|
|
|
79
78
|
const parsed = Date.parse(raw);
|
|
80
79
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
81
80
|
}
|
|
82
|
-
/** Minimum hours between maintenance restarts to prevent restart loops */
|
|
83
|
-
const MAINTENANCE_COOLDOWN_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
84
|
-
const MAINTENANCE_RESTART_KEY = 'agent.last_maintenance_restart_at';
|
|
85
81
|
function shouldRunNightlyRestart(now, lastInteractionAtMs, botManager) {
|
|
86
|
-
const hour = now.
|
|
87
|
-
if (hour <
|
|
82
|
+
const hour = now.getHours();
|
|
83
|
+
if (hour < 1 || hour >= 4)
|
|
88
84
|
return false;
|
|
89
85
|
if (botManager.isBusy())
|
|
90
86
|
return false;
|
|
91
87
|
if (!lastInteractionAtMs)
|
|
92
88
|
return false;
|
|
93
|
-
|
|
94
|
-
return false;
|
|
95
|
-
try {
|
|
96
|
-
const lastRestart = data.getSetting(MAINTENANCE_RESTART_KEY);
|
|
97
|
-
if (lastRestart) {
|
|
98
|
-
const lastRestartMs = new Date(lastRestart).getTime();
|
|
99
|
-
if (!isNaN(lastRestartMs) && (now.getTime() - lastRestartMs) < MAINTENANCE_COOLDOWN_MS)
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch { /* best effort */ }
|
|
104
|
-
try {
|
|
105
|
-
data.setSetting(MAINTENANCE_RESTART_KEY, now.toISOString());
|
|
106
|
-
}
|
|
107
|
-
catch { /* best effort */ }
|
|
108
|
-
return true;
|
|
89
|
+
return (now.getTime() - lastInteractionAtMs) >= AGENT_IDLE_RESTART_MS;
|
|
109
90
|
}
|
|
110
91
|
function parseJson(value) {
|
|
111
92
|
if (!value)
|
|
@@ -129,10 +110,11 @@ function loadDbRuntimeConfig() {
|
|
|
129
110
|
const defaultBot = botRows.find((bot) => bot.is_default === 1) || botRows[0];
|
|
130
111
|
const providers = providerRows.map((row) => ({
|
|
131
112
|
id: row.provider_id,
|
|
132
|
-
authType: row.
|
|
133
|
-
? 'cli'
|
|
134
|
-
: (row.auth_type === 'oauth' ? 'oauth' : 'apiKey'),
|
|
113
|
+
authType: row.auth_type === 'oauth' ? 'oauth' : 'apiKey',
|
|
135
114
|
apiKey: row.api_key_enc || undefined,
|
|
115
|
+
oauthToken: row.oauth_token || undefined,
|
|
116
|
+
oauthRefreshToken: row.oauth_refresh_token || undefined,
|
|
117
|
+
oauthExpiresAt: row.oauth_expires_at ?? undefined,
|
|
136
118
|
defaultModel: row.default_model || config_1.DEFAULT_MODELS[row.provider_id] || '',
|
|
137
119
|
label: row.label || undefined,
|
|
138
120
|
}));
|
|
@@ -144,9 +126,9 @@ function loadDbRuntimeConfig() {
|
|
|
144
126
|
projectDir,
|
|
145
127
|
provider: row.provider,
|
|
146
128
|
model: row.model,
|
|
147
|
-
enabledTools:
|
|
129
|
+
enabledTools: parseJson(row.enabled_builtin_tools_json),
|
|
148
130
|
enabledMcpTools: parseJson(row.enabled_mcp_tools_json),
|
|
149
|
-
permissionMode:
|
|
131
|
+
permissionMode: row.permission_mode || 'autopilot',
|
|
150
132
|
systemPrompt: row.final_prompt || undefined,
|
|
151
133
|
agentDescription: row.purpose_md || undefined,
|
|
152
134
|
createdAt: row.created_at,
|
|
@@ -181,6 +163,16 @@ function persistRuntimeAuth(config, useDbRuntime) {
|
|
|
181
163
|
}
|
|
182
164
|
(0, config_1.saveConfig)(config);
|
|
183
165
|
}
|
|
166
|
+
function persistRuntimeProviderToken(providerId, token, refreshToken, expiresAt) {
|
|
167
|
+
const existing = data.findProviderConnection(providerId);
|
|
168
|
+
if (!existing)
|
|
169
|
+
return;
|
|
170
|
+
data.updateProviderConnection(existing.id, {
|
|
171
|
+
oauthToken: token,
|
|
172
|
+
oauthRefreshToken: refreshToken ?? existing.oauth_refresh_token,
|
|
173
|
+
oauthExpiresAt: expiresAt ?? existing.oauth_expires_at,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
184
176
|
async function startCommand(projectDir, options) {
|
|
185
177
|
if (options.mode === 'windows-service') {
|
|
186
178
|
process.env.LOCAL_FIRST_ENABLED = 'true';
|
|
@@ -225,10 +217,10 @@ async function startCommand(projectDir, options) {
|
|
|
225
217
|
});
|
|
226
218
|
}
|
|
227
219
|
if ((0, local_db_1.isLocalFirstEnabled)() && !localServerStarted) {
|
|
228
|
-
console.log(chalk_1.default.blue('Local-first mode enabled
|
|
220
|
+
console.log(chalk_1.default.blue('Local-first mode enabled — initializing local database...'));
|
|
229
221
|
try {
|
|
230
222
|
const dbInfo = (0, local_db_1.initLocalDb)();
|
|
231
|
-
console.log(chalk_1.default.green(
|
|
223
|
+
console.log(chalk_1.default.green(`✓ Local DB ready: ${dbInfo.path}`));
|
|
232
224
|
console.log(chalk_1.default.gray(` WAL mode: ${dbInfo.walMode}, tables: ${dbInfo.tableCount}, write: ${dbInfo.testWrite}, read: ${dbInfo.testRead}`));
|
|
233
225
|
cleanupExpiredMessageActivityRows();
|
|
234
226
|
if (isServiceMode) {
|
|
@@ -236,7 +228,7 @@ async function startCommand(projectDir, options) {
|
|
|
236
228
|
}
|
|
237
229
|
}
|
|
238
230
|
catch (err) {
|
|
239
|
-
console.error(chalk_1.default.red(
|
|
231
|
+
console.error(chalk_1.default.red(`✗ Local DB init failed: ${err.message}`));
|
|
240
232
|
console.error(chalk_1.default.yellow(' Continuing without local-first features.'));
|
|
241
233
|
if (isServiceMode) {
|
|
242
234
|
(0, service_mode_1.emitEvent)('local_db', { status: 'failed', error: err.message });
|
|
@@ -245,13 +237,13 @@ async function startCommand(projectDir, options) {
|
|
|
245
237
|
try {
|
|
246
238
|
await (0, local_server_1.startLocalServer)({ projectDir: initialResolvedDir });
|
|
247
239
|
localServerStarted = true;
|
|
248
|
-
console.log(chalk_1.default.green('
|
|
240
|
+
console.log(chalk_1.default.green('✓ Local HTTP server ready'));
|
|
249
241
|
if (isServiceMode) {
|
|
250
242
|
(0, service_mode_1.emitEvent)('local_server', { status: 'ready', port: LOCAL_SERVER_PORT });
|
|
251
243
|
}
|
|
252
244
|
}
|
|
253
245
|
catch (err) {
|
|
254
|
-
console.error(chalk_1.default.red(
|
|
246
|
+
console.error(chalk_1.default.red(`✗ Local server failed: ${err.message}`));
|
|
255
247
|
console.error(chalk_1.default.yellow(' Desktop UI will not be available.'));
|
|
256
248
|
if (isServiceMode) {
|
|
257
249
|
(0, service_mode_1.emitEvent)('local_server', { status: 'failed', error: err.message });
|
|
@@ -296,10 +288,10 @@ async function startCommand(projectDir, options) {
|
|
|
296
288
|
const text = await res.text().catch(() => '');
|
|
297
289
|
throw new Error(`${res.status} ${res.statusText}${text ? ': ' + text : ''}`);
|
|
298
290
|
}
|
|
299
|
-
const
|
|
300
|
-
auth.mqttJwt =
|
|
301
|
-
auth.mqttJwtExpiresAt =
|
|
302
|
-
auth.expiresAt =
|
|
291
|
+
const data = await res.json();
|
|
292
|
+
auth.mqttJwt = data.mqttJwt;
|
|
293
|
+
auth.mqttJwtExpiresAt = data.mqttJwtExpiresAt;
|
|
294
|
+
auth.expiresAt = data.expiresAt;
|
|
303
295
|
persistRuntimeAuth(config, useDbRuntime);
|
|
304
296
|
console.log(chalk_1.default.green('✓ MQTT token refreshed'));
|
|
305
297
|
}
|
|
@@ -316,6 +308,56 @@ async function startCommand(projectDir, options) {
|
|
|
316
308
|
process.exit(1);
|
|
317
309
|
}
|
|
318
310
|
}
|
|
311
|
+
// Re-sync provider credentials from server (picks up web re-auth tokens)
|
|
312
|
+
if (config.providers?.some(p => p.authType === 'oauth')) {
|
|
313
|
+
try {
|
|
314
|
+
const res = await fetch(`${config_1.FUNOLIO_API_URL}/api/v1/agent/config`, {
|
|
315
|
+
headers: { Authorization: `Bearer ${auth.token}` },
|
|
316
|
+
});
|
|
317
|
+
if (res.ok) {
|
|
318
|
+
const serverConfig = await res.json();
|
|
319
|
+
if (serverConfig.providers) {
|
|
320
|
+
let updated = false;
|
|
321
|
+
for (const sp of serverConfig.providers) {
|
|
322
|
+
if (sp.connectionType !== 'oauth' || !sp.access_token)
|
|
323
|
+
continue;
|
|
324
|
+
const local = config.providers.find(p => p.id === sp.id);
|
|
325
|
+
if (!local || local.authType !== 'oauth')
|
|
326
|
+
continue;
|
|
327
|
+
// Only update if server has a different (newer) token
|
|
328
|
+
if (local.oauthToken !== sp.access_token) {
|
|
329
|
+
local.oauthToken = sp.access_token;
|
|
330
|
+
local.oauthRefreshToken = sp.refresh_token;
|
|
331
|
+
local.oauthExpiresAt = sp.expires_at;
|
|
332
|
+
updated = true;
|
|
333
|
+
console.log(chalk_1.default.green(`✓ Updated ${sp.id} OAuth token from server`));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (updated) {
|
|
337
|
+
(0, config_1.saveConfig)(config);
|
|
338
|
+
// Also update agent config files on disk
|
|
339
|
+
for (const p of config.providers) {
|
|
340
|
+
if (p.authType !== 'oauth' || !p.oauthToken)
|
|
341
|
+
continue;
|
|
342
|
+
const { listAgents, loadAgentConfig: loadAC, saveAgentConfig: saveAC } = await Promise.resolve().then(() => __importStar(require('../agent-config')));
|
|
343
|
+
for (const agentName of listAgents()) {
|
|
344
|
+
const ac = loadAC(agentName);
|
|
345
|
+
if (ac && ac.provider === p.id && ac.oauthToken) {
|
|
346
|
+
ac.oauthToken = p.oauthToken;
|
|
347
|
+
ac.oauthRefreshToken = p.oauthRefreshToken;
|
|
348
|
+
ac.oauthExpiresAt = p.oauthExpiresAt;
|
|
349
|
+
saveAC(agentName, ac);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
console.log(chalk_1.default.gray(` Server config re-sync skipped: ${err.message}`));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
319
361
|
// Load agent-specific config if --agent was specified
|
|
320
362
|
const agentLocalConfig = options.agent ? (0, agent_config_1.loadAgentConfig)(options.agent) : null;
|
|
321
363
|
if (options.agent && !agentLocalConfig) {
|
|
@@ -332,9 +374,12 @@ async function startCommand(projectDir, options) {
|
|
|
332
374
|
id: bot.id,
|
|
333
375
|
name: bot.name,
|
|
334
376
|
provider: bot.provider,
|
|
377
|
+
runtimeProvider: bot.runtimeProvider,
|
|
335
378
|
model: bot.model,
|
|
379
|
+
runtimeModel: bot.runtimeModel,
|
|
380
|
+
accessMode: bot.accessMode,
|
|
336
381
|
projectDir: '.',
|
|
337
|
-
permissionMode:
|
|
382
|
+
permissionMode: 'autopilot',
|
|
338
383
|
createdAt: new Date().toISOString(),
|
|
339
384
|
}));
|
|
340
385
|
if (!config.activeAgentId && config.agents.length > 0) {
|
|
@@ -346,9 +391,13 @@ async function startCommand(projectDir, options) {
|
|
|
346
391
|
}
|
|
347
392
|
// Resolve active agent from agents[] + activeAgentId FIRST (before dir resolution)
|
|
348
393
|
let activeAgentConfig = null;
|
|
349
|
-
let agentPermissionMode =
|
|
394
|
+
let agentPermissionMode = 'autopilot';
|
|
350
395
|
let agentEnabledTools;
|
|
396
|
+
let agentEnabledMcpTools;
|
|
351
397
|
let agentSystemPrompt;
|
|
398
|
+
let reportedProvider;
|
|
399
|
+
let reportedModel;
|
|
400
|
+
let reportedAccessMode;
|
|
352
401
|
if (config.agents && config.agents.length > 0) {
|
|
353
402
|
const activeId = config.activeAgentId;
|
|
354
403
|
activeAgentConfig = (activeId
|
|
@@ -356,9 +405,13 @@ async function startCommand(projectDir, options) {
|
|
|
356
405
|
: config.agents[0]) || null;
|
|
357
406
|
if (activeAgentConfig) {
|
|
358
407
|
console.log(chalk_1.default.blue(`Active agent: ${activeAgentConfig.name || activeAgentConfig.id}`));
|
|
359
|
-
agentPermissionMode = activeAgentConfig.permissionMode ||
|
|
360
|
-
agentEnabledTools =
|
|
408
|
+
agentPermissionMode = activeAgentConfig.permissionMode || 'autopilot';
|
|
409
|
+
agentEnabledTools = activeAgentConfig.enabledTools;
|
|
410
|
+
agentEnabledMcpTools = activeAgentConfig.enabledMcpTools;
|
|
361
411
|
agentSystemPrompt = activeAgentConfig.systemPrompt || activeAgentConfig.agentDescription;
|
|
412
|
+
reportedProvider = activeAgentConfig.provider;
|
|
413
|
+
reportedModel = activeAgentConfig.model;
|
|
414
|
+
reportedAccessMode = activeAgentConfig.accessMode;
|
|
362
415
|
// Use agent's project dir if specified
|
|
363
416
|
if (activeAgentConfig.projectDir && activeAgentConfig.projectDir !== '.') {
|
|
364
417
|
projectDir = activeAgentConfig.projectDir;
|
|
@@ -382,7 +435,11 @@ async function startCommand(projectDir, options) {
|
|
|
382
435
|
console.log('');
|
|
383
436
|
}
|
|
384
437
|
// Resolve active provider — prefer --agent local config, then agent-specific provider, then CLI flag
|
|
385
|
-
const providerOverride = agentLocalConfig?.
|
|
438
|
+
const providerOverride = agentLocalConfig?.runtimeProvider ||
|
|
439
|
+
activeAgentConfig?.runtimeProvider ||
|
|
440
|
+
agentLocalConfig?.provider ||
|
|
441
|
+
activeAgentConfig?.provider ||
|
|
442
|
+
options.provider;
|
|
386
443
|
const activeProvider = (0, config_1.getProvider)(config, providerOverride);
|
|
387
444
|
// Determine provider/model/apiKey from either providers[] or CLI flags/env
|
|
388
445
|
let provider;
|
|
@@ -391,19 +448,39 @@ async function startCommand(projectDir, options) {
|
|
|
391
448
|
let oauthToken;
|
|
392
449
|
if (activeProvider) {
|
|
393
450
|
provider = activeProvider.id;
|
|
394
|
-
model =
|
|
451
|
+
model =
|
|
452
|
+
options.model ||
|
|
453
|
+
agentLocalConfig?.runtimeModel ||
|
|
454
|
+
activeAgentConfig?.runtimeModel ||
|
|
455
|
+
agentLocalConfig?.model ||
|
|
456
|
+
activeAgentConfig?.model ||
|
|
457
|
+
activeProvider.defaultModel;
|
|
395
458
|
apiKey = options.apiKey || agentLocalConfig?.apiKey || activeProvider.apiKey || getEnvApiKey(provider);
|
|
396
459
|
oauthToken = agentLocalConfig?.oauthToken || activeProvider.oauthToken;
|
|
397
460
|
}
|
|
398
461
|
else {
|
|
399
462
|
// Fallback to CLI args / env detection (no providers configured)
|
|
400
|
-
provider =
|
|
401
|
-
|
|
463
|
+
provider =
|
|
464
|
+
agentLocalConfig?.runtimeProvider ||
|
|
465
|
+
activeAgentConfig?.runtimeProvider ||
|
|
466
|
+
agentLocalConfig?.provider ||
|
|
467
|
+
activeAgentConfig?.provider ||
|
|
468
|
+
options.provider ||
|
|
469
|
+
detectProvider();
|
|
470
|
+
model =
|
|
471
|
+
agentLocalConfig?.runtimeModel ||
|
|
472
|
+
activeAgentConfig?.runtimeModel ||
|
|
473
|
+
agentLocalConfig?.model ||
|
|
474
|
+
activeAgentConfig?.model ||
|
|
475
|
+
options.model ||
|
|
476
|
+
defaultModel(provider);
|
|
402
477
|
apiKey = options.apiKey || agentLocalConfig?.apiKey || getEnvApiKey(provider);
|
|
403
478
|
oauthToken = agentLocalConfig?.oauthToken;
|
|
404
479
|
}
|
|
405
|
-
// Auto-detect Claude Code CLI if no API key and no provider explicitly set.
|
|
406
|
-
|
|
480
|
+
// Auto-detect Claude Code CLI if no API key/token and no provider explicitly set.
|
|
481
|
+
// OAuth tokens from claude.ai can't be used with the Anthropic API directly,
|
|
482
|
+
// so we prefer claude-cli when Claude Code is installed.
|
|
483
|
+
if (!apiKey && !oauthToken && !options.provider && !agentLocalConfig?.provider && provider !== 'claude-cli') {
|
|
407
484
|
const claudeVersion = detectClaudeCli();
|
|
408
485
|
if (claudeVersion) {
|
|
409
486
|
console.log(chalk_1.default.green(`✓ Claude Code detected (${claudeVersion}), using your subscription`));
|
|
@@ -417,6 +494,61 @@ async function startCommand(projectDir, options) {
|
|
|
417
494
|
console.error(chalk_1.default.gray(' (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY)'));
|
|
418
495
|
process.exit(1);
|
|
419
496
|
}
|
|
497
|
+
// Check if stored OAuth token is expired before starting — try refresh instead of dying
|
|
498
|
+
if (activeProvider?.authType === 'oauth' && activeProvider.oauthExpiresAt) {
|
|
499
|
+
const oauthExpiresAtMs = activeProvider.oauthExpiresAt < 1e12
|
|
500
|
+
? activeProvider.oauthExpiresAt * 1000
|
|
501
|
+
: activeProvider.oauthExpiresAt;
|
|
502
|
+
if (oauthExpiresAtMs < Date.now()) {
|
|
503
|
+
if (activeProvider.oauthRefreshToken) {
|
|
504
|
+
console.log(chalk_1.default.yellow(`⚠ ${activeProvider.id} OAuth token expired — attempting refresh...`));
|
|
505
|
+
try {
|
|
506
|
+
const { refreshToken } = await Promise.resolve().then(() => __importStar(require('../auth/token-refresh')));
|
|
507
|
+
const result = await refreshToken({
|
|
508
|
+
provider: activeProvider.id,
|
|
509
|
+
accessToken: oauthToken || activeProvider.oauthToken || '',
|
|
510
|
+
refreshToken: activeProvider.oauthRefreshToken,
|
|
511
|
+
expiresAt: oauthExpiresAtMs,
|
|
512
|
+
});
|
|
513
|
+
oauthToken = result.credential.accessToken;
|
|
514
|
+
// Update config so next startup doesn't hit this again
|
|
515
|
+
const freshConfig = (0, config_1.loadConfig)();
|
|
516
|
+
const providerIdx = freshConfig.providers?.findIndex(p => p.id === activeProvider.id);
|
|
517
|
+
if (freshConfig.providers && providerIdx !== undefined && providerIdx >= 0) {
|
|
518
|
+
freshConfig.providers[providerIdx].oauthToken = result.credential.accessToken;
|
|
519
|
+
freshConfig.providers[providerIdx].oauthRefreshToken = result.credential.refreshToken;
|
|
520
|
+
freshConfig.providers[providerIdx].oauthExpiresAt = result.credential.expiresAt;
|
|
521
|
+
(0, config_1.saveConfig)(freshConfig);
|
|
522
|
+
}
|
|
523
|
+
console.log(chalk_1.default.green(`✓ ${activeProvider.id} token refreshed successfully`));
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
const loginCmds = {
|
|
527
|
+
anthropic: 'claude login',
|
|
528
|
+
openai: 'codex login',
|
|
529
|
+
'google-gemini': 'gemini login',
|
|
530
|
+
google: 'gemini login',
|
|
531
|
+
};
|
|
532
|
+
const cmd = loginCmds[activeProvider.id] || `${activeProvider.id} login`;
|
|
533
|
+
console.error(chalk_1.default.red(`✗ Your ${activeProvider.id} OAuth token has expired and refresh failed: ${err.message}`));
|
|
534
|
+
console.error(chalk_1.default.yellow(` Please run \`${cmd}\` and then \`funolio-agent configure\` to re-authenticate.`));
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
const loginCmds = {
|
|
540
|
+
anthropic: 'claude login',
|
|
541
|
+
openai: 'codex login',
|
|
542
|
+
'google-gemini': 'gemini login',
|
|
543
|
+
google: 'gemini login',
|
|
544
|
+
};
|
|
545
|
+
const cmd = loginCmds[activeProvider.id] || `${activeProvider.id} login`;
|
|
546
|
+
console.error(chalk_1.default.red(`✗ Your ${activeProvider.id} OAuth token has expired (no refresh token available).`));
|
|
547
|
+
console.error(chalk_1.default.yellow(` Please run \`${cmd}\` and then \`funolio-agent configure\` to re-authenticate.`));
|
|
548
|
+
process.exit(1);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
420
552
|
// Local-first DB initialization (behind feature flag)
|
|
421
553
|
if ((0, local_db_1.isLocalFirstEnabled)() && !localServerStarted) {
|
|
422
554
|
console.log(chalk_1.default.blue('Local-first mode enabled — initializing local database...'));
|
|
@@ -425,10 +557,6 @@ async function startCommand(projectDir, options) {
|
|
|
425
557
|
console.log(chalk_1.default.green(`✓ Local DB ready: ${dbInfo.path}`));
|
|
426
558
|
console.log(chalk_1.default.gray(` WAL mode: ${dbInfo.walMode}, tables: ${dbInfo.tableCount}, write: ${dbInfo.testWrite}, read: ${dbInfo.testRead}`));
|
|
427
559
|
cleanupExpiredMessageActivityRows();
|
|
428
|
-
const migratedProfiles = data.migrateAgentProfilesToDefaultToolProfile();
|
|
429
|
-
if (migratedProfiles.updated > 0) {
|
|
430
|
-
console.log(chalk_1.default.green(`✓ Migrated ${migratedProfiles.updated} agent profile(s) to default tool profile`));
|
|
431
|
-
}
|
|
432
560
|
if (isServiceMode) {
|
|
433
561
|
(0, service_mode_1.emitEvent)('local_db', { status: 'ready', path: dbInfo.path, walMode: dbInfo.walMode });
|
|
434
562
|
}
|
|
@@ -478,85 +606,15 @@ async function startCommand(projectDir, options) {
|
|
|
478
606
|
authToken: auth.token,
|
|
479
607
|
refreshUrl: `${config_1.FUNOLIO_API_URL}/api/v1/agent/auth/refresh`,
|
|
480
608
|
});
|
|
481
|
-
// Sync integration tokens from server BEFORE launching MCP servers.
|
|
482
|
-
try {
|
|
483
|
-
const authToken = (0, config_1.loadConfig)().auth?.token;
|
|
484
|
-
if (authToken) {
|
|
485
|
-
const tokenRes = await fetch(`${config_1.FUNOLIO_API_URL}/api/v1/google/tokens`, {
|
|
486
|
-
headers: { Authorization: `Bearer ${authToken}` },
|
|
487
|
-
});
|
|
488
|
-
if (tokenRes.ok) {
|
|
489
|
-
const tokenBody = await tokenRes.json();
|
|
490
|
-
if (tokenBody.connected && tokenBody.tokens?.access_token) {
|
|
491
|
-
const { handleIntegrationTokens } = await Promise.resolve().then(() => __importStar(require('../integration-tokens')));
|
|
492
|
-
const expiresAt = tokenBody.tokens.expires_at ? new Date(tokenBody.tokens.expires_at) : null;
|
|
493
|
-
const expiresInSec = expiresAt ? Math.max(0, Math.floor((expiresAt.getTime() - Date.now()) / 1000)) : null;
|
|
494
|
-
handleIntegrationTokens({
|
|
495
|
-
type: 'integration_tokens',
|
|
496
|
-
integration: 'google',
|
|
497
|
-
tokens: {
|
|
498
|
-
access_token: tokenBody.tokens.access_token,
|
|
499
|
-
refresh_token: tokenBody.tokens.refresh_token,
|
|
500
|
-
expires_in: expiresInSec,
|
|
501
|
-
scope: tokenBody.tokens.scope || '',
|
|
502
|
-
},
|
|
503
|
-
clientId: tokenBody.clientId || '',
|
|
504
|
-
clientSecret: tokenBody.clientSecret || '',
|
|
505
|
-
email: tokenBody.email,
|
|
506
|
-
timestamp: Date.now(),
|
|
507
|
-
});
|
|
508
|
-
console.log(chalk_1.default.green(`✓ Synced Google integration tokens from server${tokenBody.email ? ` (${tokenBody.email})` : ''}`));
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
console.log(chalk_1.default.gray(' No Google integration connected on server'));
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
catch (err) {
|
|
517
|
-
console.warn(chalk_1.default.yellow(` [Integration] Token sync failed: ${err.message}`));
|
|
518
|
-
}
|
|
519
609
|
// Create and auto-launch MCP manager for persistent tool discovery
|
|
520
610
|
const { MCPManager } = await Promise.resolve().then(() => __importStar(require('../mcp/manager')));
|
|
521
611
|
const mcpManager = new MCPManager();
|
|
522
612
|
await mcpManager.autoLaunch();
|
|
523
|
-
// Sync MCP servers approved on the server but not yet launched locally
|
|
524
|
-
try {
|
|
525
|
-
const authToken = (0, config_1.loadConfig)().auth?.token;
|
|
526
|
-
if (authToken) {
|
|
527
|
-
const res = await fetch(`${config_1.FUNOLIO_API_URL}/api/v1/agent/mcp/installed?includeEnvVars=true`, {
|
|
528
|
-
headers: { Authorization: `Bearer ${authToken}` },
|
|
529
|
-
});
|
|
530
|
-
if (res.ok) {
|
|
531
|
-
const { servers: approvedServers } = await res.json();
|
|
532
|
-
const running = new Set(mcpManager.getRunningServers());
|
|
533
|
-
const { BUILTIN_REGISTRY } = await Promise.resolve().then(() => __importStar(require('../mcp/registry')));
|
|
534
|
-
for (const srv of approvedServers) {
|
|
535
|
-
if (srv.status === 'approved' && !running.has(srv.serverId)) {
|
|
536
|
-
const entry = BUILTIN_REGISTRY.find((e) => e.id === srv.serverId);
|
|
537
|
-
if (entry) {
|
|
538
|
-
console.log(chalk_1.default.cyan(` 📦 Auto-launching approved MCP server: ${srv.serverId}`));
|
|
539
|
-
try {
|
|
540
|
-
await mcpManager.installAndLaunch(entry, srv.envVars || {}, true);
|
|
541
|
-
}
|
|
542
|
-
catch (err) {
|
|
543
|
-
console.error(chalk_1.default.red(` ✗ Failed to launch ${srv.serverId}: ${err.message}`));
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
catch (err) {
|
|
552
|
-
console.warn(chalk_1.default.yellow(` [MCP] Server-side sync failed: ${err.message}`));
|
|
553
|
-
}
|
|
554
613
|
const mcpServers = mcpManager.getRunningServers();
|
|
555
614
|
if (mcpServers.length > 0) {
|
|
556
615
|
console.log(chalk_1.default.green(` MCP servers running: ${mcpServers.join(', ')} (${mcpManager.getToolDefinitions().length} tools)`));
|
|
557
616
|
}
|
|
558
617
|
// Create bot manager (multi-bot support)
|
|
559
|
-
// Auth modes: CLI providers handle their own auth; API key providers use BYOK.
|
|
560
618
|
const botManager = new bot_manager_1.BotManager({
|
|
561
619
|
projectDir: resolvedDir,
|
|
562
620
|
userId,
|
|
@@ -565,10 +623,11 @@ async function startCommand(projectDir, options) {
|
|
|
565
623
|
defaultModel: model,
|
|
566
624
|
defaultApiKey: apiKey,
|
|
567
625
|
defaultOauthToken: oauthToken,
|
|
568
|
-
defaultOauthRefreshToken: activeProvider?.oauthRefreshToken
|
|
569
|
-
defaultOauthExpiresAt: activeProvider?.oauthExpiresAt
|
|
626
|
+
defaultOauthRefreshToken: activeProvider?.oauthRefreshToken,
|
|
627
|
+
defaultOauthExpiresAt: activeProvider?.oauthExpiresAt,
|
|
570
628
|
permissionMode: agentPermissionMode,
|
|
571
629
|
enabledTools: agentEnabledTools,
|
|
630
|
+
enabledMcpTools: agentEnabledMcpTools,
|
|
572
631
|
systemPrompt: agentSystemPrompt,
|
|
573
632
|
mcpManager,
|
|
574
633
|
});
|
|
@@ -639,37 +698,15 @@ async function startCommand(projectDir, options) {
|
|
|
639
698
|
tools: builtinToolNames,
|
|
640
699
|
serverInfo,
|
|
641
700
|
mcpTools: mcpToolNames,
|
|
642
|
-
llmProvider: provider,
|
|
643
|
-
llmModel: model,
|
|
701
|
+
llmProvider: reportedProvider || provider,
|
|
702
|
+
llmModel: reportedModel || model,
|
|
703
|
+
accessMode: reportedAccessMode,
|
|
644
704
|
};
|
|
645
705
|
fetch(`${config_1.FUNOLIO_API_URL}/api/v1/agent/status`, {
|
|
646
706
|
method: 'POST',
|
|
647
707
|
headers: { 'Content-Type': 'application/json' },
|
|
648
708
|
body: JSON.stringify(statusPayload),
|
|
649
709
|
}).catch(() => { }); // best-effort
|
|
650
|
-
// Sync projects from server to local DB
|
|
651
|
-
try {
|
|
652
|
-
const configRes = await fetch(`${config_1.FUNOLIO_API_URL}/api/v1/agent/config`, {
|
|
653
|
-
headers: { Authorization: `Bearer ${auth.token}` },
|
|
654
|
-
});
|
|
655
|
-
if (configRes.ok) {
|
|
656
|
-
const configBody = await configRes.json();
|
|
657
|
-
if (configBody.projects && Array.isArray(configBody.projects)) {
|
|
658
|
-
for (const p of configBody.projects) {
|
|
659
|
-
data.upsertProject({
|
|
660
|
-
id: p.id || p.name,
|
|
661
|
-
name: p.name,
|
|
662
|
-
folder: p.folderPath || null,
|
|
663
|
-
description: p.description || null,
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
console.log(chalk_1.default.green(` ✓ Synced ${configBody.projects.length} project(s) from server`));
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
catch (err) {
|
|
671
|
-
console.warn(chalk_1.default.yellow(` [Projects] Sync failed: ${err.message}`));
|
|
672
|
-
}
|
|
673
710
|
// Publish available providers to MQTT so web UI can show provider picker
|
|
674
711
|
if (config.providers && config.providers.length > 0) {
|
|
675
712
|
mqttClient.publishProviders(config.providers.map((p) => ({
|
|
@@ -708,9 +745,6 @@ async function startCommand(projectDir, options) {
|
|
|
708
745
|
await botManager.startActive();
|
|
709
746
|
// Start all additional bot loops from ~/.funolio/agents/ configs
|
|
710
747
|
await botManager.startAllBots();
|
|
711
|
-
// Fix B: Sync cloud-configured bots that aren't in local config
|
|
712
|
-
// This ensures bots created on the web UI are available without manual local setup
|
|
713
|
-
await botManager.syncBotsFromCloud();
|
|
714
748
|
try {
|
|
715
749
|
if (!data.getSetting('agent.last_interaction_at')) {
|
|
716
750
|
data.setSetting('agent.last_interaction_at', new Date().toISOString());
|
|
@@ -749,6 +783,7 @@ async function startCommand(projectDir, options) {
|
|
|
749
783
|
console.log(chalk_1.default.blue(` ${config.agents.length} agent(s) configured (active: ${activeAgentConfig?.name || 'default'})`));
|
|
750
784
|
}
|
|
751
785
|
// Sync MCP tools into all configured CLI runtimes so shared tools are available
|
|
786
|
+
// regardless of which provider happens to be active for this launch.
|
|
752
787
|
const cliProvidersToSync = new Set();
|
|
753
788
|
if (index_1.CLI_PROVIDERS.has(provider)) {
|
|
754
789
|
cliProvidersToSync.add(provider);
|
|
@@ -773,21 +808,22 @@ async function startCommand(projectDir, options) {
|
|
|
773
808
|
}
|
|
774
809
|
}
|
|
775
810
|
console.log(chalk_1.default.gray(' Waiting for commands...\n'));
|
|
811
|
+
// OAuth token refresh is handled per-request in message-loop.ts via ensureFreshToken()
|
|
812
|
+
// No background timer needed — this matches the pi-ai/Claude Code CLI pattern of
|
|
813
|
+
// refreshing lazily before each API call, avoiding race conditions on single-use refresh tokens
|
|
776
814
|
// Listen for integration tokens delivered from the web UI via MQTT
|
|
777
815
|
mqttClient.onIntegrationTokens(async (message) => {
|
|
778
816
|
const { handleIntegrationTokens } = require('../integration-tokens');
|
|
779
817
|
handleIntegrationTokens(message);
|
|
780
|
-
// If Google tokens were refreshed, reload any running Google MCP servers
|
|
781
|
-
// so they pick up the fresh credentials without a full agent restart.
|
|
782
818
|
if (message.integration === 'google') {
|
|
783
819
|
try {
|
|
784
820
|
const restarted = await mcpManager.reloadIntegrationServers('google');
|
|
785
821
|
if (restarted.length > 0) {
|
|
786
|
-
console.log(chalk_1.default.green(
|
|
822
|
+
console.log(chalk_1.default.green(`✓ Reloaded Google MCP server(s): ${restarted.join(', ')}`));
|
|
787
823
|
}
|
|
788
824
|
}
|
|
789
825
|
catch (err) {
|
|
790
|
-
console.error(chalk_1.default.
|
|
826
|
+
console.error(chalk_1.default.yellow(`⚠ Failed to reload Google MCP servers: ${err.message}`));
|
|
791
827
|
}
|
|
792
828
|
}
|
|
793
829
|
});
|
|
@@ -795,21 +831,15 @@ async function startCommand(projectDir, options) {
|
|
|
795
831
|
// Also handle MCP marketplace install/uninstall commands
|
|
796
832
|
mqttClient.onCommand(async (message) => {
|
|
797
833
|
if (message.type === 'command' && message.action === 'mcp_install') {
|
|
798
|
-
const { serverId, envVars
|
|
834
|
+
const { serverId, envVars } = message;
|
|
799
835
|
console.log(chalk_1.default.cyan(`📦 Marketplace: installing MCP server "${serverId}"...`));
|
|
800
836
|
try {
|
|
801
837
|
const { BUILTIN_REGISTRY } = await Promise.resolve().then(() => __importStar(require('../mcp/registry')));
|
|
802
|
-
const { MCPManager: MCPMgr } = await Promise.resolve().then(() => __importStar(require('../mcp/manager')));
|
|
803
838
|
const entry = BUILTIN_REGISTRY.find((s) => s.id === serverId);
|
|
804
839
|
if (!entry)
|
|
805
840
|
throw new Error(`Unknown MCP server: ${serverId}`);
|
|
806
|
-
if (entry.npmPackage) {
|
|
807
|
-
MCPMgr.preWarmPackage(entry.npmPackage);
|
|
808
|
-
}
|
|
809
841
|
await mcpManager.installAndLaunch(entry, envVars || {}, true);
|
|
810
|
-
const tools = mcpManager.
|
|
811
|
-
.filter((t) => t.serverId === serverId)
|
|
812
|
-
.map((t) => t.name);
|
|
842
|
+
const tools = mcpManager.getServerInfo(serverId)?.tools.map((t) => t.name) || [];
|
|
813
843
|
console.log(chalk_1.default.green(`✓ MCP server "${serverId}" installed (${tools.length} tools)`));
|
|
814
844
|
await mqttClient.publishResult({
|
|
815
845
|
commandId: message.id,
|
|
@@ -834,7 +864,7 @@ async function startCommand(projectDir, options) {
|
|
|
834
864
|
const { serverId } = message;
|
|
835
865
|
console.log(chalk_1.default.cyan(`📦 Marketplace: uninstalling MCP server "${serverId}"...`));
|
|
836
866
|
try {
|
|
837
|
-
await mcpManager.
|
|
867
|
+
await mcpManager.uninstallServer(serverId);
|
|
838
868
|
console.log(chalk_1.default.green(`✓ MCP server "${serverId}" uninstalled`));
|
|
839
869
|
await mqttClient.publishResult({
|
|
840
870
|
commandId: message.id,
|