@lightcone-ai/daemon 0.15.55 → 0.15.57

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.
@@ -111,9 +111,9 @@ export function createDataSourcePoolRegistry({ createPool, logger = () => {} } =
111
111
  const pools = new Map();
112
112
 
113
113
  return {
114
- getOrCreate(dataSourceId, dbConfig) {
115
- const id = String(dataSourceId ?? '').trim();
116
- if (!id) throw new Error('data_source_id must be a non-empty string');
114
+ getOrCreate(dataSource, dbConfig) {
115
+ const id = String(dataSource ?? '').trim();
116
+ if (!id) throw new Error('data_source must be a non-empty string');
117
117
  const nextFingerprint = fingerprintDbConfig(dbConfig);
118
118
  const existing = pools.get(id);
119
119
 
@@ -123,7 +123,7 @@ export function createDataSourcePoolRegistry({ createPool, logger = () => {} } =
123
123
 
124
124
  if (existing) {
125
125
  Promise.resolve(existing.pool.end())
126
- .catch((error) => logger(`[mysql-mcp] failed to close previous pool for data_source_id=${id}: ${error.message}`));
126
+ .catch((error) => logger(`[mysql-mcp] failed to close previous pool for data_source=${id}: ${error.message}`));
127
127
  }
128
128
 
129
129
  const pool = createPool(dbConfig);
@@ -172,10 +172,10 @@ export function createCredentialBrokerClient({
172
172
  const normalizedWorkspaceId = String(workspaceId ?? '').trim();
173
173
  const normalizedBundleId = String(bundleId ?? '').trim();
174
174
 
175
- return async function fetchCredentialEnvVars(dataSourceId) {
176
- const normalizedDataSourceId = String(dataSourceId ?? '').trim();
177
- if (!normalizedDataSourceId) {
178
- throw new Error('data_source_id is required');
175
+ return async function fetchCredentialEnvVars(dataSource) {
176
+ const normalizedDataSource = String(dataSource ?? '').trim();
177
+ if (!normalizedDataSource) {
178
+ throw new Error('data_source is required');
179
179
  }
180
180
  if (!normalizedServerUrl || !normalizedMachineApiKey || !normalizedAgentId) {
181
181
  throw new Error('mysql MCP missing SERVER_URL/MACHINE_API_KEY/AGENT_ID runtime context');
@@ -190,7 +190,7 @@ export function createCredentialBrokerClient({
190
190
  body: JSON.stringify({
191
191
  agent_id: normalizedAgentId,
192
192
  workspace_id: normalizedWorkspaceId || null,
193
- required_credentials: [normalizedDataSourceId],
193
+ required_credentials: [normalizedDataSource],
194
194
  bundle_id: normalizedBundleId || null,
195
195
  }),
196
196
  });
@@ -218,16 +218,16 @@ export function createCredentialBrokerClient({
218
218
  }
219
219
 
220
220
  export async function executeSql({
221
- dataSourceId,
221
+ dataSource,
222
222
  sql,
223
223
  params = [],
224
224
  limit,
225
225
  fetchCredentialEnvVars,
226
226
  poolRegistry,
227
227
  } = {}) {
228
- const normalizedDataSourceId = String(dataSourceId ?? '').trim();
229
- if (!normalizedDataSourceId) {
230
- throw new Error('data_source_id is required');
228
+ const normalizedDataSource = String(dataSource ?? '').trim();
229
+ if (!normalizedDataSource) {
230
+ throw new Error('data_source is required');
231
231
  }
232
232
  if (!Array.isArray(params)) {
233
233
  throw new Error('params must be an array');
@@ -240,9 +240,9 @@ export async function executeSql({
240
240
  }
241
241
 
242
242
  const prepared = prepareSql(sql, limit);
243
- const credentialEnv = await fetchCredentialEnvVars(normalizedDataSourceId);
243
+ const credentialEnv = await fetchCredentialEnvVars(normalizedDataSource);
244
244
  const dbConfig = parseDbConfig(credentialEnv);
245
- const pool = poolRegistry.getOrCreate(normalizedDataSourceId, dbConfig);
245
+ const pool = poolRegistry.getOrCreate(normalizedDataSource, dbConfig);
246
246
 
247
247
  const queryParams = [...params, ...prepared.limitParams];
248
248
  const [result] = await pool.query(prepared.sql, queryParams);
@@ -252,7 +252,7 @@ export async function executeSql({
252
252
  ? result.slice(0, prepared.limit)
253
253
  : result;
254
254
  return {
255
- data_source_id: normalizedDataSourceId,
255
+ data_source: normalizedDataSource,
256
256
  row_count: rows.length,
257
257
  limit: prepared.limit,
258
258
  limit_applied: prepared.limitInjected || rows.length < result.length,
@@ -261,7 +261,7 @@ export async function executeSql({
261
261
  }
262
262
 
263
263
  return {
264
- data_source_id: normalizedDataSourceId,
264
+ data_source: normalizedDataSource,
265
265
  affected_rows: Number(result?.affectedRows ?? 0),
266
266
  changed_rows: Number(result?.changedRows ?? 0),
267
267
  insert_id: result?.insertId ?? null,
@@ -11,7 +11,7 @@ import {
11
11
  } from './core.js';
12
12
 
13
13
  const TOOL_SCHEMA = {
14
- data_source_id: z.string().describe('数据源 ID(当前实现映射为 credential_id)'),
14
+ data_source: z.string().describe('工作区数据源名称,例如 sophon_cub。不要填写数据库密码或内部 ID'),
15
15
  sql: z.string().describe('要执行的 SQL。支持参数占位符 ?'),
16
16
  params: z.array(z.any()).optional().describe('SQL 参数数组(按顺序对应 ? 占位符)'),
17
17
  limit: z.number().int().positive().optional().describe('结果行数上限。默认 200,最大 1000'),
@@ -50,12 +50,12 @@ export function createMysqlMcpServer({
50
50
 
51
51
  server.tool(
52
52
  'query',
53
- '执行通用 SQL。调用时通过 data_source_id 走 credential broker 动态获取 DB 凭证并路由连接。',
53
+ '执行通用 SQL。调用时通过数据源名称走 credential broker 动态获取 DB 凭证并路由连接。',
54
54
  TOOL_SCHEMA,
55
- async ({ data_source_id, sql, params = [], limit }) => {
55
+ async ({ data_source, sql, params = [], limit }) => {
56
56
  try {
57
57
  const payload = await executeSql({
58
- dataSourceId: data_source_id,
58
+ dataSource: data_source,
59
59
  sql,
60
60
  params,
61
61
  limit,
@@ -64,7 +64,7 @@ export function createMysqlMcpServer({
64
64
  });
65
65
  return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
66
66
  } catch (error) {
67
- logger(`[mysql-mcp] query failed for data_source_id=${data_source_id}: ${error.message}`);
67
+ logger(`[mysql-mcp] query failed for data_source=${data_source}: ${error.message}`);
68
68
  return {
69
69
  isError: true,
70
70
  content: [{ type: 'text', text: `query failed: ${error.message}` }],
@@ -10,7 +10,7 @@
10
10
  "smoke_test": {
11
11
  "tool": "query",
12
12
  "arguments": {
13
- "data_source_id": "smoke-test-data-source",
13
+ "data_source": "smoke-test-data-source",
14
14
  "sql": "SELECT 1",
15
15
  "limit": 1
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.15.55",
3
+ "version": "0.15.57",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -184,6 +184,7 @@ export class AgentManager {
184
184
  case 'agent:start': return this._startAgent(msg, connection);
185
185
  case 'agent:stop': return this._stopAgent(msg.agentId, msg.workspaceId, connection);
186
186
  case 'agent:deliver': return this._deliverMessage(msg, connection);
187
+ case 'agent:reprobe': return this._reprobeCapability(msg, connection);
187
188
  case 'publish:job': return this._handlePublishJob(msg, connection);
188
189
  case 'browser:start_login': return this._startBrowserLogin(msg, connection);
189
190
  case 'browser:stop_login': return this._stopBrowserLogin(msg);
@@ -504,6 +505,49 @@ export class AgentManager {
504
505
  });
505
506
  }
506
507
 
508
+ async _reprobeCapability({ agentId, workspaceId }, connection) {
509
+ const normalizedAgentId = String(agentId ?? '').trim();
510
+ if (!normalizedAgentId) {
511
+ console.log('[AgentManager] agent:reprobe ignored: missing agentId');
512
+ return;
513
+ }
514
+ const normalizedWorkspaceId = String(workspaceId ?? '').trim();
515
+ const workspaceDir = this._workspaceDir(normalizedAgentId, normalizedWorkspaceId);
516
+ const chatBridgePath = new URL('./chat-bridge.js', import.meta.url).pathname;
517
+
518
+ this._emitCapabilityProbe(connection, {
519
+ agentId: normalizedAgentId,
520
+ workspaceId: normalizedWorkspaceId,
521
+ capabilityId: CHAT_CAPABILITY_ID,
522
+ state: 'unknown',
523
+ reason: 'reprobe_pending',
524
+ details: { stage: 'reprobe' },
525
+ });
526
+
527
+ const result = await probeChatBridgeCapability({
528
+ chatBridgePath,
529
+ cwd: workspaceDir,
530
+ timeoutMs: CAPABILITY_PROBE_TIMEOUT_MS,
531
+ env: {
532
+ SERVER_URL: this.serverUrl,
533
+ MACHINE_API_KEY: this.machineApiKey,
534
+ AGENT_ID: normalizedAgentId,
535
+ WORKSPACE_ID: normalizedWorkspaceId,
536
+ WORKSPACE_DIR: workspaceDir,
537
+ },
538
+ });
539
+
540
+ this._emitCapabilityProbe(connection, {
541
+ agentId: normalizedAgentId,
542
+ workspaceId: normalizedWorkspaceId,
543
+ capabilityId: CHAT_CAPABILITY_ID,
544
+ state: result.state,
545
+ reason: result.reason,
546
+ details: { ...(result.details ?? {}), stage: 'reprobe' },
547
+ latencyMs: result.latencyMs,
548
+ });
549
+ }
550
+
507
551
  _emitCapabilityProbe(connection, {
508
552
  agentId,
509
553
  workspaceId,
@@ -188,6 +188,7 @@ const DEFAULT_TOOL_CLASSIFICATION = {
188
188
  query_user_history: 'cacheable',
189
189
  list_accounts: 'cacheable',
190
190
  list_credentials: 'cacheable',
191
+ list_data_sources: 'cacheable',
191
192
  get_data_locations: 'cacheable',
192
193
  explain_concept: 'cacheable',
193
194
  get_release_notes: 'cacheable',
@@ -296,6 +297,7 @@ function inferToolForApi(method, apiPath, body) {
296
297
  if (method === 'POST' && cleanPath === '/credential-auth/request') return 'request_credential_auth';
297
298
  if (method === 'POST' && cleanPath === '/content-library/submit') return 'submit_to_library';
298
299
  if (method === 'POST' && cleanPath === '/api/data-sources') return 'register_data_source';
300
+ if (method === 'GET' && cleanPath === '/api/data-sources') return 'list_data_sources';
299
301
  if (method === 'POST' && cleanPath === '/orchestrate/decision') return 'write_governance_decision';
300
302
  if (method === 'POST' && cleanPath === '/orchestrate/correction') return 'write_governance_correction';
301
303
  if (method === 'GET' && cleanPath === '/orchestrate/context') return 'get_orchestrate_context';
@@ -933,6 +935,29 @@ server.tool('list_server', 'List workspaces, agents, and humans on the server',
933
935
  return { content: [{ type: 'text', text: `Workspaces:\n${workspaces}\n\nAgents:\n${agents}\n\nHumans:\n${humans}` }] };
934
936
  });
935
937
 
938
+ // ── list_data_sources ─────────────────────────────────────────────────────────
939
+ server.tool('list_data_sources', 'List named data sources available in the current workspace. Returns names and status only; no internal IDs or secrets.', {
940
+ workspace_id: z.string().optional().describe('Target workspace id. Defaults to current workspace context if omitted.'),
941
+ }, async ({ workspace_id }) => {
942
+ const targetWorkspaceId = (workspace_id ?? currentWorkspaceId ?? WORKSPACE_ID ?? '').trim();
943
+ if (!targetWorkspaceId) {
944
+ return { isError: true, content: [{ type: 'text', text: 'workspace_id is required (no current workspace context).' }] };
945
+ }
946
+ const params = new URLSearchParams({ workspace_id: targetWorkspaceId });
947
+ const data = await api('GET', `/api/data-sources?${params}`);
948
+ const sources = Array.isArray(data.data_sources) ? data.data_sources : [];
949
+ if (sources.length === 0) {
950
+ return { content: [{ type: 'text', text: 'No data sources are configured for this workspace.' }] };
951
+ }
952
+ const text = sources.map((source) => {
953
+ const name = String(source.name ?? '未命名数据源').trim();
954
+ const type = String(source.source_type ?? 'unknown').trim();
955
+ const status = String(source.credential_status ?? 'unknown').trim();
956
+ return `- ${name} (${type}) - connection ${status}`;
957
+ }).join('\n');
958
+ return { content: [{ type: 'text', text }] };
959
+ });
960
+
936
961
  // ── list_tasks ────────────────────────────────────────────────────────────────
937
962
  server.tool('list_tasks', 'List tasks in a workspace', {
938
963
  workspace: z.string().describe('Target: #workspace-name'),
@@ -1457,7 +1482,7 @@ server.tool('submit_to_library',
1457
1482
 
1458
1483
  // ── register_data_source ───────────────────────────────────────────────────────
1459
1484
  server.tool('register_data_source',
1460
- 'Register a workspace data source without binding credential yet. Returns a one-time secure auth URL (10-minute expiry) that should be sent to the user via IM.',
1485
+ 'Register a named workspace data source without binding credential yet. Returns a one-time secure auth URL (10-minute expiry) that should be sent to the user via IM.',
1461
1486
  {
1462
1487
  workspace_id: z.string().optional().describe('Target workspace id. Defaults to current workspace context if omitted.'),
1463
1488
  display_name: z.string().describe('Human-readable data source name.'),
@@ -1484,7 +1509,7 @@ server.tool('register_data_source',
1484
1509
  text:
1485
1510
  `Data source registered.\n` +
1486
1511
  `workspace_id=${data.workspace_id ?? targetWorkspaceId}\n` +
1487
- `data_source_id=${data.data_source_id}\n` +
1512
+ `display_name=${display_name}\n` +
1488
1513
  `source_type=${data.source_type ?? source_type}\n` +
1489
1514
  `expires_at=${data.expires_at ?? 'unknown'}\n` +
1490
1515
  `secure_auth_url=${data.secure_auth_url}\n\n` +