@duckcodeailabs/dql-cli 1.6.11 → 1.6.12

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.
Files changed (33) hide show
  1. package/dist/assets/dql-notebook/assets/index-McpLeeN0.js +3802 -0
  2. package/dist/assets/dql-notebook/index.html +1 -1
  3. package/dist/llm/analytics-tools.d.ts +7 -0
  4. package/dist/llm/analytics-tools.d.ts.map +1 -0
  5. package/dist/llm/analytics-tools.js +178 -0
  6. package/dist/llm/analytics-tools.js.map +1 -0
  7. package/dist/llm/index.d.ts.map +1 -1
  8. package/dist/llm/index.js +3 -1
  9. package/dist/llm/index.js.map +1 -1
  10. package/dist/llm/mcp-config.d.ts +43 -0
  11. package/dist/llm/mcp-config.d.ts.map +1 -0
  12. package/dist/llm/mcp-config.js +327 -0
  13. package/dist/llm/mcp-config.js.map +1 -0
  14. package/dist/llm/providers/dql-agent-provider.d.ts +1 -1
  15. package/dist/llm/providers/dql-agent-provider.d.ts.map +1 -1
  16. package/dist/llm/providers/dql-agent-provider.js +9 -1
  17. package/dist/llm/providers/dql-agent-provider.js.map +1 -1
  18. package/dist/llm/providers/native-sdk-provider.d.ts +4 -0
  19. package/dist/llm/providers/native-sdk-provider.d.ts.map +1 -0
  20. package/dist/llm/providers/native-sdk-provider.js +319 -0
  21. package/dist/llm/providers/native-sdk-provider.js.map +1 -0
  22. package/dist/llm/types.d.ts +1 -1
  23. package/dist/llm/types.d.ts.map +1 -1
  24. package/dist/local-runtime.d.ts +2 -0
  25. package/dist/local-runtime.d.ts.map +1 -1
  26. package/dist/local-runtime.js +132 -19
  27. package/dist/local-runtime.js.map +1 -1
  28. package/dist/package.json +13 -11
  29. package/dist/settings/provider-settings.d.ts +2 -0
  30. package/dist/settings/provider-settings.d.ts.map +1 -1
  31. package/dist/settings/provider-settings.js +49 -10
  32. package/dist/settings/provider-settings.js.map +1 -1
  33. package/package.json +14 -12
@@ -3,14 +3,17 @@ import { createServer } from 'node:http';
3
3
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
5
  import { dirname, extname, join, normalize, relative, resolve } from 'node:path';
6
+ import Anthropic from '@anthropic-ai/sdk';
7
+ import OpenAI from 'openai';
6
8
  import { buildExecutionPlan, createWelcomeNotebook, deserializeNotebook, getConnectorFormSchemas, hasSemanticRefs, resolveSemanticRefs, } from '@duckcodeailabs/dql-notebook';
7
9
  import { loadSemanticLayerFromDir, resolveSemanticLayerAsync, getDialect, Parser, buildLineageGraph, buildManifest, findAppDocuments, findDashboardsForApp, isBlockIdRef, loadAppDocument, loadDashboardDocument, analyzeImpact, buildTrustChain, detectDomainFlows, getDomainTrustOverview, queryLineage, queryCompleteLineagePaths, LineageGraph, canonicalize, canonicalizeNotebook, diffDQL, diffNotebook, } from '@duckcodeailabs/dql-core';
8
10
  import { load as loadYaml } from 'js-yaml';
9
11
  import { listBlockTemplates } from './block-templates.js';
10
12
  import { getRunner as getLLMRunner } from './llm/index.js';
13
+ import { listRemoteMcpSettings, saveRemoteMcpSettings } from './llm/mcp-config.js';
11
14
  import { ClaudeProvider, GeminiProvider, MemoryStore, OllamaProvider, OpenAIProvider, buildLocalContextPack, defaultMemoryPath, ensureDefaultMemoryFiles, ensureMetadataCatalogFresh, recordRuntimeSchemaSnapshot, } from '@duckcodeailabs/dql-agent';
12
15
  import { handleAppsApi } from './apps-api.js';
13
- import { getEffectiveProviderConfig, listProviderSettings, saveProviderSettings, } from './settings/provider-settings.js';
16
+ import { getActiveProvider, getEffectiveProviderConfig, listProviderSettings, saveProviderSettings, } from './settings/provider-settings.js';
14
17
  import { DQLAccessDeniedError, activePersonaAppId, assertAppAccess, loadRuntimeApp, runtimeVariables, } from './governance-runtime.js';
15
18
  import { LocalAppStorage, defaultLocalAppsDbPath } from '@duckcodeailabs/dql-project';
16
19
  import { Certifier } from '@duckcodeailabs/dql-governance';
@@ -606,6 +609,24 @@ export async function startLocalServer(opts) {
606
609
  }
607
610
  return;
608
611
  }
612
+ if (req.method === 'GET' && path === '/api/settings/mcp') {
613
+ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
614
+ res.end(serializeJSON({ settings: listRemoteMcpSettings(projectRoot) }));
615
+ return;
616
+ }
617
+ if (req.method === 'POST' && path === '/api/settings/mcp') {
618
+ try {
619
+ const body = await readJSON(req);
620
+ const settings = saveRemoteMcpSettings(projectRoot, { entries: body?.entries });
621
+ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
622
+ res.end(serializeJSON({ ok: true, settings }));
623
+ }
624
+ catch (error) {
625
+ res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });
626
+ res.end(serializeJSON({ ok: false, error: error instanceof Error ? error.message : String(error) }));
627
+ }
628
+ return;
629
+ }
609
630
  if (req.method === 'GET' && path === '/api/agent/memory') {
610
631
  const memory = new MemoryStore(defaultMemoryPath(projectRoot));
611
632
  try {
@@ -3465,16 +3486,23 @@ function normalizeQueryResult(result, semanticRefs) {
3465
3486
  };
3466
3487
  }
3467
3488
  function isLLMProviderId(value) {
3468
- return value === 'claude-agent-sdk'
3489
+ return value === 'anthropic'
3490
+ || value === 'claude-agent-sdk'
3469
3491
  || value === 'claude-code'
3470
3492
  || value === 'openai'
3471
3493
  || value === 'gemini'
3472
3494
  || value === 'ollama'
3473
3495
  || value === 'custom-openai';
3474
3496
  }
3475
- function resolveDefaultLLMProvider(projectRoot) {
3497
+ export function resolveDefaultLLMProvider(projectRoot) {
3476
3498
  const settings = listProviderSettings(projectRoot);
3477
- const preferred = ['openai', 'gemini', 'ollama', 'custom-openai'];
3499
+ const activeProvider = getActiveProvider(projectRoot);
3500
+ if (activeProvider) {
3501
+ const active = settings.find((item) => item.id === activeProvider);
3502
+ if (active?.enabled)
3503
+ return activeProvider;
3504
+ }
3505
+ const preferred = ['openai', 'gemini', 'anthropic', 'custom-openai', 'ollama'];
3478
3506
  for (const id of preferred) {
3479
3507
  const provider = settings.find((item) => item.id === id);
3480
3508
  if (provider?.enabled && provider.hasApiKey)
@@ -4931,9 +4959,11 @@ async function buildBlockStudioAiAssistSummary(projectRoot, action, candidate, v
4931
4959
  }
4932
4960
  async function createBlockStudioAssistProvider(projectRoot, requestedProvider) {
4933
4961
  const settings = listProviderSettings(projectRoot);
4962
+ const activeProvider = getActiveProvider(projectRoot);
4934
4963
  const selected = requestedProvider
4935
4964
  ? settings.find((provider) => provider.id === requestedProvider && provider.enabled && provider.hasApiKey)
4936
- : settings.find((provider) => provider.enabled && provider.hasApiKey);
4965
+ : settings.find((provider) => provider.id === activeProvider && provider.enabled)
4966
+ ?? settings.find((provider) => provider.enabled && provider.hasApiKey);
4937
4967
  if (!selected)
4938
4968
  return null;
4939
4969
  const config = getEffectiveProviderConfig(projectRoot, selected.id);
@@ -6497,11 +6527,17 @@ function isProviderSettingsId(value) {
6497
6527
  }
6498
6528
  async function testProviderConfig(projectRoot, id) {
6499
6529
  const config = getEffectiveProviderConfig(projectRoot, id);
6530
+ const label = providerSettingsLabel(id);
6531
+ const details = providerConfigDetails(id, config);
6532
+ if (!config.enabled) {
6533
+ return { ok: false, message: `${label} is disabled in Settings.` };
6534
+ }
6535
+ if (id === 'openai')
6536
+ return testOpenAIProviderConfig(config, label, details);
6537
+ if (id === 'anthropic')
6538
+ return testAnthropicProviderConfig(config, label, details);
6500
6539
  let provider;
6501
6540
  switch (id) {
6502
- case 'anthropic':
6503
- provider = new ClaudeProvider({ apiKey: config.apiKey, model: config.model });
6504
- break;
6505
6541
  case 'gemini':
6506
6542
  provider = new GeminiProvider({ apiKey: config.apiKey, model: config.model });
6507
6543
  break;
@@ -6509,20 +6545,97 @@ async function testProviderConfig(projectRoot, id) {
6509
6545
  provider = new OllamaProvider({ baseUrl: config.baseUrl, model: config.model });
6510
6546
  break;
6511
6547
  case 'custom-openai':
6512
- provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model, allowNoApiKey: true });
6513
- break;
6514
- case 'openai':
6515
6548
  default:
6516
- provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model });
6549
+ provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model, allowNoApiKey: true });
6517
6550
  break;
6518
6551
  }
6519
- const ok = await provider.available();
6520
- return {
6521
- ok,
6522
- message: ok
6523
- ? `${id} is configured.`
6524
- : `${id} is not configured or not reachable. Check API key, base URL, and local service state.`,
6525
- };
6552
+ const available = await provider.available().catch(() => false);
6553
+ if (!available) {
6554
+ return {
6555
+ ok: false,
6556
+ message: `${label} is not configured or reachable${details}. Check API key, base URL, and local service state.`,
6557
+ };
6558
+ }
6559
+ try {
6560
+ const text = await provider.generate([
6561
+ { role: 'user', content: 'Reply with exactly: OK' },
6562
+ ], { maxTokens: 8, temperature: 0 });
6563
+ return {
6564
+ ok: true,
6565
+ message: `${label} responded${details}: ${text.trim().slice(0, 80) || 'OK'}`,
6566
+ };
6567
+ }
6568
+ catch (error) {
6569
+ return {
6570
+ ok: false,
6571
+ message: `${label} is configured but the model call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
6572
+ };
6573
+ }
6574
+ }
6575
+ async function testOpenAIProviderConfig(config, label, details) {
6576
+ if (!config.apiKey) {
6577
+ return { ok: false, message: `${label} is not configured${details}. Add an API key in Settings or OPENAI_API_KEY.` };
6578
+ }
6579
+ try {
6580
+ const client = new OpenAI({ apiKey: config.apiKey, baseURL: config.baseUrl });
6581
+ const response = await client.responses.create({
6582
+ model: config.model ?? 'gpt-5.5',
6583
+ input: 'Reply with exactly: OK',
6584
+ max_output_tokens: 16,
6585
+ });
6586
+ return {
6587
+ ok: true,
6588
+ message: `${label} SDK responded${details}: ${(response.output_text ?? 'OK').trim().slice(0, 80) || 'OK'}`,
6589
+ };
6590
+ }
6591
+ catch (error) {
6592
+ return {
6593
+ ok: false,
6594
+ message: `${label} SDK call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
6595
+ };
6596
+ }
6597
+ }
6598
+ async function testAnthropicProviderConfig(config, label, details) {
6599
+ if (!config.apiKey) {
6600
+ return { ok: false, message: `${label} is not configured${details}. Add an API key in Settings or ANTHROPIC_API_KEY.` };
6601
+ }
6602
+ try {
6603
+ const client = new Anthropic({ apiKey: config.apiKey });
6604
+ const response = await client.messages.create({
6605
+ model: config.model ?? 'claude-opus-4-8',
6606
+ max_tokens: 16,
6607
+ temperature: 0,
6608
+ messages: [{ role: 'user', content: 'Reply with exactly: OK' }],
6609
+ });
6610
+ const text = response.content?.filter((block) => block.type === 'text').map((block) => block.text ?? '').join('') ?? '';
6611
+ return {
6612
+ ok: true,
6613
+ message: `${label} SDK responded${details}: ${text.trim().slice(0, 80) || 'OK'}`,
6614
+ };
6615
+ }
6616
+ catch (error) {
6617
+ return {
6618
+ ok: false,
6619
+ message: `${label} SDK call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
6620
+ };
6621
+ }
6622
+ }
6623
+ function providerSettingsLabel(id) {
6624
+ switch (id) {
6625
+ case 'anthropic': return 'Anthropic Claude';
6626
+ case 'openai': return 'OpenAI';
6627
+ case 'gemini': return 'Gemini';
6628
+ case 'ollama': return 'Ollama';
6629
+ case 'custom-openai': return 'Custom OpenAI-compatible provider';
6630
+ }
6631
+ }
6632
+ function providerConfigDetails(id, config) {
6633
+ const parts = [
6634
+ config.model ? `model ${config.model}` : '',
6635
+ config.baseUrl ? `base URL ${config.baseUrl}` : '',
6636
+ id === 'ollama' ? 'local endpoint' : config.apiKey ? 'API key present' : 'API key missing',
6637
+ ].filter(Boolean);
6638
+ return parts.length ? ` (${parts.join(', ')})` : '';
6526
6639
  }
6527
6640
  function isAiPinRefreshDue(lastRefreshedAt) {
6528
6641
  if (!lastRefreshedAt)