funolio-agent 1.0.47 → 1.0.49
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/auth/auto-detect.d.ts +1 -0
- package/dist/auth/auto-detect.d.ts.map +1 -1
- package/dist/auth/auto-detect.js +16 -13
- package/dist/auth/auto-detect.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 +8 -23
- package/dist/bot-manager.d.ts.map +1 -1
- package/dist/bot-manager.js +61 -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 +154 -43
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +195 -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 +10 -6
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +241 -540
- 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,97 +606,29 @@ 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,
|
|
563
621
|
mqttClient,
|
|
564
622
|
defaultProvider: provider,
|
|
565
623
|
defaultModel: model,
|
|
624
|
+
defaultAccessMode: reportedAccessMode,
|
|
566
625
|
defaultApiKey: apiKey,
|
|
567
626
|
defaultOauthToken: oauthToken,
|
|
568
|
-
defaultOauthRefreshToken: activeProvider?.oauthRefreshToken
|
|
569
|
-
defaultOauthExpiresAt: activeProvider?.oauthExpiresAt
|
|
627
|
+
defaultOauthRefreshToken: activeProvider?.oauthRefreshToken,
|
|
628
|
+
defaultOauthExpiresAt: activeProvider?.oauthExpiresAt,
|
|
570
629
|
permissionMode: agentPermissionMode,
|
|
571
630
|
enabledTools: agentEnabledTools,
|
|
631
|
+
enabledMcpTools: agentEnabledMcpTools,
|
|
572
632
|
systemPrompt: agentSystemPrompt,
|
|
573
633
|
mcpManager,
|
|
574
634
|
});
|
|
@@ -639,37 +699,15 @@ async function startCommand(projectDir, options) {
|
|
|
639
699
|
tools: builtinToolNames,
|
|
640
700
|
serverInfo,
|
|
641
701
|
mcpTools: mcpToolNames,
|
|
642
|
-
llmProvider: provider,
|
|
643
|
-
llmModel: model,
|
|
702
|
+
llmProvider: reportedProvider || provider,
|
|
703
|
+
llmModel: reportedModel || model,
|
|
704
|
+
accessMode: reportedAccessMode,
|
|
644
705
|
};
|
|
645
706
|
fetch(`${config_1.FUNOLIO_API_URL}/api/v1/agent/status`, {
|
|
646
707
|
method: 'POST',
|
|
647
708
|
headers: { 'Content-Type': 'application/json' },
|
|
648
709
|
body: JSON.stringify(statusPayload),
|
|
649
710
|
}).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
711
|
// Publish available providers to MQTT so web UI can show provider picker
|
|
674
712
|
if (config.providers && config.providers.length > 0) {
|
|
675
713
|
mqttClient.publishProviders(config.providers.map((p) => ({
|
|
@@ -708,9 +746,6 @@ async function startCommand(projectDir, options) {
|
|
|
708
746
|
await botManager.startActive();
|
|
709
747
|
// Start all additional bot loops from ~/.funolio/agents/ configs
|
|
710
748
|
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
749
|
try {
|
|
715
750
|
if (!data.getSetting('agent.last_interaction_at')) {
|
|
716
751
|
data.setSetting('agent.last_interaction_at', new Date().toISOString());
|
|
@@ -749,6 +784,7 @@ async function startCommand(projectDir, options) {
|
|
|
749
784
|
console.log(chalk_1.default.blue(` ${config.agents.length} agent(s) configured (active: ${activeAgentConfig?.name || 'default'})`));
|
|
750
785
|
}
|
|
751
786
|
// Sync MCP tools into all configured CLI runtimes so shared tools are available
|
|
787
|
+
// regardless of which provider happens to be active for this launch.
|
|
752
788
|
const cliProvidersToSync = new Set();
|
|
753
789
|
if (index_1.CLI_PROVIDERS.has(provider)) {
|
|
754
790
|
cliProvidersToSync.add(provider);
|
|
@@ -773,21 +809,22 @@ async function startCommand(projectDir, options) {
|
|
|
773
809
|
}
|
|
774
810
|
}
|
|
775
811
|
console.log(chalk_1.default.gray(' Waiting for commands...\n'));
|
|
812
|
+
// OAuth token refresh is handled per-request in message-loop.ts via ensureFreshToken()
|
|
813
|
+
// No background timer needed — this matches the pi-ai/Claude Code CLI pattern of
|
|
814
|
+
// refreshing lazily before each API call, avoiding race conditions on single-use refresh tokens
|
|
776
815
|
// Listen for integration tokens delivered from the web UI via MQTT
|
|
777
816
|
mqttClient.onIntegrationTokens(async (message) => {
|
|
778
817
|
const { handleIntegrationTokens } = require('../integration-tokens');
|
|
779
818
|
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
819
|
if (message.integration === 'google') {
|
|
783
820
|
try {
|
|
784
821
|
const restarted = await mcpManager.reloadIntegrationServers('google');
|
|
785
822
|
if (restarted.length > 0) {
|
|
786
|
-
console.log(chalk_1.default.green(
|
|
823
|
+
console.log(chalk_1.default.green(`✓ Reloaded Google MCP server(s): ${restarted.join(', ')}`));
|
|
787
824
|
}
|
|
788
825
|
}
|
|
789
826
|
catch (err) {
|
|
790
|
-
console.error(chalk_1.default.
|
|
827
|
+
console.error(chalk_1.default.yellow(`⚠ Failed to reload Google MCP servers: ${err.message}`));
|
|
791
828
|
}
|
|
792
829
|
}
|
|
793
830
|
});
|
|
@@ -795,21 +832,15 @@ async function startCommand(projectDir, options) {
|
|
|
795
832
|
// Also handle MCP marketplace install/uninstall commands
|
|
796
833
|
mqttClient.onCommand(async (message) => {
|
|
797
834
|
if (message.type === 'command' && message.action === 'mcp_install') {
|
|
798
|
-
const { serverId, envVars
|
|
835
|
+
const { serverId, envVars } = message;
|
|
799
836
|
console.log(chalk_1.default.cyan(`📦 Marketplace: installing MCP server "${serverId}"...`));
|
|
800
837
|
try {
|
|
801
838
|
const { BUILTIN_REGISTRY } = await Promise.resolve().then(() => __importStar(require('../mcp/registry')));
|
|
802
|
-
const { MCPManager: MCPMgr } = await Promise.resolve().then(() => __importStar(require('../mcp/manager')));
|
|
803
839
|
const entry = BUILTIN_REGISTRY.find((s) => s.id === serverId);
|
|
804
840
|
if (!entry)
|
|
805
841
|
throw new Error(`Unknown MCP server: ${serverId}`);
|
|
806
|
-
if (entry.npmPackage) {
|
|
807
|
-
MCPMgr.preWarmPackage(entry.npmPackage);
|
|
808
|
-
}
|
|
809
842
|
await mcpManager.installAndLaunch(entry, envVars || {}, true);
|
|
810
|
-
const tools = mcpManager.
|
|
811
|
-
.filter((t) => t.serverId === serverId)
|
|
812
|
-
.map((t) => t.name);
|
|
843
|
+
const tools = mcpManager.getServerInfo(serverId)?.tools.map((t) => t.name) || [];
|
|
813
844
|
console.log(chalk_1.default.green(`✓ MCP server "${serverId}" installed (${tools.length} tools)`));
|
|
814
845
|
await mqttClient.publishResult({
|
|
815
846
|
commandId: message.id,
|
|
@@ -834,7 +865,7 @@ async function startCommand(projectDir, options) {
|
|
|
834
865
|
const { serverId } = message;
|
|
835
866
|
console.log(chalk_1.default.cyan(`📦 Marketplace: uninstalling MCP server "${serverId}"...`));
|
|
836
867
|
try {
|
|
837
|
-
await mcpManager.
|
|
868
|
+
await mcpManager.uninstallServer(serverId);
|
|
838
869
|
console.log(chalk_1.default.green(`✓ MCP server "${serverId}" uninstalled`));
|
|
839
870
|
await mqttClient.publishResult({
|
|
840
871
|
commandId: message.id,
|