@duckcodeailabs/dql-cli 1.6.11 → 1.6.13
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/assets/dql-notebook/assets/index-osG-H64_.js +3835 -0
- package/dist/assets/dql-notebook/index.html +1 -1
- package/dist/llm/analytics-tools.d.ts +7 -0
- package/dist/llm/analytics-tools.d.ts.map +1 -0
- package/dist/llm/analytics-tools.js +179 -0
- package/dist/llm/analytics-tools.js.map +1 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +3 -1
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/mcp-config.d.ts +43 -0
- package/dist/llm/mcp-config.d.ts.map +1 -0
- package/dist/llm/mcp-config.js +327 -0
- package/dist/llm/mcp-config.js.map +1 -0
- package/dist/llm/providers/claude-agent-sdk.d.ts.map +1 -1
- package/dist/llm/providers/claude-agent-sdk.js +2 -1
- package/dist/llm/providers/claude-agent-sdk.js.map +1 -1
- package/dist/llm/providers/claude-code.js +1 -0
- package/dist/llm/providers/claude-code.js.map +1 -1
- package/dist/llm/providers/dql-agent-provider.d.ts +1 -1
- package/dist/llm/providers/dql-agent-provider.d.ts.map +1 -1
- package/dist/llm/providers/dql-agent-provider.js +10 -1
- package/dist/llm/providers/dql-agent-provider.js.map +1 -1
- package/dist/llm/providers/native-sdk-provider.d.ts +4 -0
- package/dist/llm/providers/native-sdk-provider.d.ts.map +1 -0
- package/dist/llm/providers/native-sdk-provider.js +319 -0
- package/dist/llm/providers/native-sdk-provider.js.map +1 -0
- package/dist/llm/types.d.ts +2 -1
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/local-runtime.d.ts +13 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +337 -96
- package/dist/local-runtime.js.map +1 -1
- package/dist/package.json +13 -11
- package/dist/settings/provider-settings.d.ts +2 -0
- package/dist/settings/provider-settings.d.ts.map +1 -1
- package/dist/settings/provider-settings.js +49 -10
- package/dist/settings/provider-settings.js.map +1 -1
- package/package.json +14 -12
- package/dist/assets/dql-notebook/assets/index-BbGJ8gZk.js +0 -3639
- package/dist/assets/dql-notebook/assets/index-C4oZK5xm.js +0 -3612
- package/dist/assets/dql-notebook/assets/index-CEMXuPm0.js +0 -3802
- package/dist/assets/dql-notebook/assets/index-CIMLd3Cb.js +0 -3289
- package/dist/assets/dql-notebook/assets/index-DISMWw19.js +0 -3780
package/dist/local-runtime.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { QueryExecutor, type ConnectionConfig, type DatabaseConnector } from '@duckcodeailabs/dql-connectors';
|
|
2
2
|
import { type SemanticLayer, type SemanticLayerProviderConfig } from '@duckcodeailabs/dql-core';
|
|
3
|
+
import type { ProviderId } from './llm/types.js';
|
|
3
4
|
import { type AgentSchemaTable } from '@duckcodeailabs/dql-agent';
|
|
4
5
|
export interface ProjectConfig {
|
|
5
6
|
project?: string;
|
|
@@ -31,6 +32,16 @@ export interface DbtProfileConnectionCandidate {
|
|
|
31
32
|
missingFields: string[];
|
|
32
33
|
warnings: string[];
|
|
33
34
|
}
|
|
35
|
+
export interface ConnectorInstallStatus {
|
|
36
|
+
driver: 'duckdb' | 'snowflake' | 'databricks';
|
|
37
|
+
label: string;
|
|
38
|
+
packageName?: string;
|
|
39
|
+
packageSpec?: string;
|
|
40
|
+
installed: boolean;
|
|
41
|
+
builtIn: boolean;
|
|
42
|
+
installPath: string;
|
|
43
|
+
installCommand?: string;
|
|
44
|
+
}
|
|
34
45
|
export interface LocalServerOptions {
|
|
35
46
|
rootDir: string;
|
|
36
47
|
projectRoot?: string;
|
|
@@ -53,9 +64,11 @@ export interface ConnectionTestResult {
|
|
|
53
64
|
details?: Record<string, unknown>;
|
|
54
65
|
}
|
|
55
66
|
export declare function validateConnectionForTest(connector: DatabaseConnector, connection: ConnectionConfig): Promise<ConnectionTestResult>;
|
|
67
|
+
export declare function resolveDefaultLLMProvider(projectRoot: string): ProviderId | null;
|
|
56
68
|
export declare function serializeJSON(value: unknown): string;
|
|
57
69
|
export declare function findProjectRoot(startDir: string): string;
|
|
58
70
|
export declare function loadProjectConfig(projectRoot: string): ProjectConfig;
|
|
71
|
+
export declare function getConnectorInstallStatuses(projectRoot: string): ConnectorInstallStatus[];
|
|
59
72
|
export declare function prepareLocalExecution(sql: string, connection: ConnectionConfig, projectRoot: string, projectConfig: ProjectConfig): {
|
|
60
73
|
sql: string;
|
|
61
74
|
connection: ConnectionConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-runtime.d.ts","sourceRoot":"","sources":["../src/local-runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local-runtime.d.ts","sourceRoot":"","sources":["../src/local-runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/local-runtime.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
1
|
+
import { execFileSync, execSync } from 'node:child_process';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
3
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
4
5
|
import { homedir } from 'node:os';
|
|
5
6
|
import { dirname, extname, join, normalize, relative, resolve } from 'node:path';
|
|
7
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
+
import OpenAI from 'openai';
|
|
6
9
|
import { buildExecutionPlan, createWelcomeNotebook, deserializeNotebook, getConnectorFormSchemas, hasSemanticRefs, resolveSemanticRefs, } from '@duckcodeailabs/dql-notebook';
|
|
7
10
|
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
11
|
import { load as loadYaml } from 'js-yaml';
|
|
9
12
|
import { listBlockTemplates } from './block-templates.js';
|
|
10
13
|
import { getRunner as getLLMRunner } from './llm/index.js';
|
|
14
|
+
import { listRemoteMcpSettings, saveRemoteMcpSettings } from './llm/mcp-config.js';
|
|
11
15
|
import { ClaudeProvider, GeminiProvider, MemoryStore, OllamaProvider, OpenAIProvider, buildLocalContextPack, defaultMemoryPath, ensureDefaultMemoryFiles, ensureMetadataCatalogFresh, recordRuntimeSchemaSnapshot, } from '@duckcodeailabs/dql-agent';
|
|
12
16
|
import { handleAppsApi } from './apps-api.js';
|
|
13
|
-
import { getEffectiveProviderConfig, listProviderSettings, saveProviderSettings, } from './settings/provider-settings.js';
|
|
17
|
+
import { getActiveProvider, getEffectiveProviderConfig, listProviderSettings, saveProviderSettings, } from './settings/provider-settings.js';
|
|
14
18
|
import { DQLAccessDeniedError, activePersonaAppId, assertAppAccess, loadRuntimeApp, runtimeVariables, } from './governance-runtime.js';
|
|
15
19
|
import { LocalAppStorage, defaultLocalAppsDbPath } from '@duckcodeailabs/dql-project';
|
|
16
20
|
import { Certifier } from '@duckcodeailabs/dql-governance';
|
|
@@ -606,6 +610,24 @@ export async function startLocalServer(opts) {
|
|
|
606
610
|
}
|
|
607
611
|
return;
|
|
608
612
|
}
|
|
613
|
+
if (req.method === 'GET' && path === '/api/settings/mcp') {
|
|
614
|
+
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
615
|
+
res.end(serializeJSON({ settings: listRemoteMcpSettings(projectRoot) }));
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (req.method === 'POST' && path === '/api/settings/mcp') {
|
|
619
|
+
try {
|
|
620
|
+
const body = await readJSON(req);
|
|
621
|
+
const settings = saveRemoteMcpSettings(projectRoot, { entries: body?.entries });
|
|
622
|
+
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
623
|
+
res.end(serializeJSON({ ok: true, settings }));
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
627
|
+
res.end(serializeJSON({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
628
|
+
}
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
609
631
|
if (req.method === 'GET' && path === '/api/agent/memory') {
|
|
610
632
|
const memory = new MemoryStore(defaultMemoryPath(projectRoot));
|
|
611
633
|
try {
|
|
@@ -1907,8 +1929,32 @@ export async function startLocalServer(opts) {
|
|
|
1907
1929
|
?? Object.keys(connections)[0]
|
|
1908
1930
|
?? 'default';
|
|
1909
1931
|
const dbtProfiles = discoverDbtProfileConnections(projectRoot, cfg);
|
|
1932
|
+
const connectorStatus = getConnectorInstallStatuses(projectRoot);
|
|
1910
1933
|
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
1911
|
-
res.end(serializeJSON({ default: defaultKey, connections, dbtProfiles }));
|
|
1934
|
+
res.end(serializeJSON({ default: defaultKey, connections, dbtProfiles, connectorStatus }));
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (req.method === 'POST' && path === '/api/connectors/install') {
|
|
1938
|
+
try {
|
|
1939
|
+
const body = await readJSON(req);
|
|
1940
|
+
const driver = typeof body.driver === 'string' ? body.driver : '';
|
|
1941
|
+
const status = installConnectorPackage(projectRoot, driver);
|
|
1942
|
+
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
1943
|
+
res.end(serializeJSON({
|
|
1944
|
+
ok: true,
|
|
1945
|
+
status,
|
|
1946
|
+
connectorStatus: getConnectorInstallStatuses(projectRoot),
|
|
1947
|
+
}));
|
|
1948
|
+
}
|
|
1949
|
+
catch (error) {
|
|
1950
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1951
|
+
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
1952
|
+
res.end(serializeJSON({
|
|
1953
|
+
ok: false,
|
|
1954
|
+
error: message,
|
|
1955
|
+
connectorStatus: getConnectorInstallStatuses(projectRoot),
|
|
1956
|
+
}));
|
|
1957
|
+
}
|
|
1912
1958
|
return;
|
|
1913
1959
|
}
|
|
1914
1960
|
// Save/update connections
|
|
@@ -3465,16 +3511,23 @@ function normalizeQueryResult(result, semanticRefs) {
|
|
|
3465
3511
|
};
|
|
3466
3512
|
}
|
|
3467
3513
|
function isLLMProviderId(value) {
|
|
3468
|
-
return value === '
|
|
3514
|
+
return value === 'anthropic'
|
|
3515
|
+
|| value === 'claude-agent-sdk'
|
|
3469
3516
|
|| value === 'claude-code'
|
|
3470
3517
|
|| value === 'openai'
|
|
3471
3518
|
|| value === 'gemini'
|
|
3472
3519
|
|| value === 'ollama'
|
|
3473
3520
|
|| value === 'custom-openai';
|
|
3474
3521
|
}
|
|
3475
|
-
function resolveDefaultLLMProvider(projectRoot) {
|
|
3522
|
+
export function resolveDefaultLLMProvider(projectRoot) {
|
|
3476
3523
|
const settings = listProviderSettings(projectRoot);
|
|
3477
|
-
const
|
|
3524
|
+
const activeProvider = getActiveProvider(projectRoot);
|
|
3525
|
+
if (activeProvider) {
|
|
3526
|
+
const active = settings.find((item) => item.id === activeProvider);
|
|
3527
|
+
if (active?.enabled)
|
|
3528
|
+
return activeProvider;
|
|
3529
|
+
}
|
|
3530
|
+
const preferred = ['openai', 'gemini', 'anthropic', 'custom-openai', 'ollama'];
|
|
3478
3531
|
for (const id of preferred) {
|
|
3479
3532
|
const provider = settings.find((item) => item.id === id);
|
|
3480
3533
|
if (provider?.enabled && provider.hasApiKey)
|
|
@@ -3608,6 +3661,90 @@ function getProjectConnectionsForApi(config) {
|
|
|
3608
3661
|
}
|
|
3609
3662
|
return connections;
|
|
3610
3663
|
}
|
|
3664
|
+
const CONNECTOR_INSTALLS = {
|
|
3665
|
+
duckdb: {
|
|
3666
|
+
driver: 'duckdb',
|
|
3667
|
+
label: 'DuckDB',
|
|
3668
|
+
packageName: 'duckdb',
|
|
3669
|
+
packageSpec: 'duckdb@^1.1.0',
|
|
3670
|
+
builtIn: false,
|
|
3671
|
+
},
|
|
3672
|
+
snowflake: {
|
|
3673
|
+
driver: 'snowflake',
|
|
3674
|
+
label: 'Snowflake',
|
|
3675
|
+
packageName: 'snowflake-sdk',
|
|
3676
|
+
packageSpec: 'snowflake-sdk@^1.12.0',
|
|
3677
|
+
builtIn: false,
|
|
3678
|
+
},
|
|
3679
|
+
databricks: {
|
|
3680
|
+
driver: 'databricks',
|
|
3681
|
+
label: 'Databricks',
|
|
3682
|
+
builtIn: true,
|
|
3683
|
+
},
|
|
3684
|
+
};
|
|
3685
|
+
function connectorInstallRoot(projectRoot) {
|
|
3686
|
+
return join(projectRoot, '.dql', 'connectors');
|
|
3687
|
+
}
|
|
3688
|
+
function connectorModuleSearchPaths(projectRoot) {
|
|
3689
|
+
return [connectorInstallRoot(projectRoot), projectRoot];
|
|
3690
|
+
}
|
|
3691
|
+
function connectorInstallCommand(projectRoot, packageSpec) {
|
|
3692
|
+
return `npm install --prefix ${connectorInstallRoot(projectRoot)} ${packageSpec}`;
|
|
3693
|
+
}
|
|
3694
|
+
function isConnectorPackageInstalled(projectRoot, packageName) {
|
|
3695
|
+
for (const basePath of connectorModuleSearchPaths(projectRoot)) {
|
|
3696
|
+
try {
|
|
3697
|
+
const req = createRequire(join(basePath, 'package.json'));
|
|
3698
|
+
req.resolve(packageName);
|
|
3699
|
+
return true;
|
|
3700
|
+
}
|
|
3701
|
+
catch {
|
|
3702
|
+
// Try the next supported location.
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
return false;
|
|
3706
|
+
}
|
|
3707
|
+
export function getConnectorInstallStatuses(projectRoot) {
|
|
3708
|
+
return Object.values(CONNECTOR_INSTALLS).map((definition) => {
|
|
3709
|
+
const installPath = connectorInstallRoot(projectRoot);
|
|
3710
|
+
const installed = definition.builtIn || (definition.packageName
|
|
3711
|
+
? isConnectorPackageInstalled(projectRoot, definition.packageName)
|
|
3712
|
+
: true);
|
|
3713
|
+
return {
|
|
3714
|
+
...definition,
|
|
3715
|
+
installed,
|
|
3716
|
+
installPath,
|
|
3717
|
+
installCommand: definition.packageSpec
|
|
3718
|
+
? connectorInstallCommand(projectRoot, definition.packageSpec)
|
|
3719
|
+
: undefined,
|
|
3720
|
+
};
|
|
3721
|
+
});
|
|
3722
|
+
}
|
|
3723
|
+
function installConnectorPackage(projectRoot, driver) {
|
|
3724
|
+
const definition = CONNECTOR_INSTALLS[driver];
|
|
3725
|
+
if (!definition) {
|
|
3726
|
+
throw new Error(`Unknown connector "${driver}".`);
|
|
3727
|
+
}
|
|
3728
|
+
if (definition.builtIn || !definition.packageSpec) {
|
|
3729
|
+
return getConnectorInstallStatuses(projectRoot).find((status) => status.driver === definition.driver);
|
|
3730
|
+
}
|
|
3731
|
+
const installRoot = connectorInstallRoot(projectRoot);
|
|
3732
|
+
mkdirSync(installRoot, { recursive: true });
|
|
3733
|
+
const packageJsonPath = join(installRoot, 'package.json');
|
|
3734
|
+
if (!existsSync(packageJsonPath)) {
|
|
3735
|
+
writeFileSync(packageJsonPath, JSON.stringify({
|
|
3736
|
+
private: true,
|
|
3737
|
+
description: 'Project-local DQL connector packages',
|
|
3738
|
+
}, null, 2) + '\n', 'utf-8');
|
|
3739
|
+
}
|
|
3740
|
+
execFileSync('npm', ['install', '--prefix', installRoot, '--no-audit', '--no-fund', definition.packageSpec], {
|
|
3741
|
+
cwd: projectRoot,
|
|
3742
|
+
encoding: 'utf-8',
|
|
3743
|
+
stdio: 'pipe',
|
|
3744
|
+
timeout: 10 * 60 * 1000,
|
|
3745
|
+
});
|
|
3746
|
+
return getConnectorInstallStatuses(projectRoot).find((status) => status.driver === definition.driver);
|
|
3747
|
+
}
|
|
3611
3748
|
function getStoredConnections(raw) {
|
|
3612
3749
|
const value = raw.connections;
|
|
3613
3750
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
@@ -3912,6 +4049,9 @@ export function normalizeProjectConnection(connection, projectRoot) {
|
|
|
3912
4049
|
if ((normalized.driver === 'file' || normalized.driver === 'duckdb') && normalized.filepath && normalized.filepath !== ':memory:' && !isAbsoluteLikePath(normalized.filepath)) {
|
|
3913
4050
|
normalized.filepath = resolve(projectRoot, normalized.filepath);
|
|
3914
4051
|
}
|
|
4052
|
+
if (normalized.driver === 'file' || normalized.driver === 'duckdb' || normalized.driver === 'snowflake') {
|
|
4053
|
+
normalized.moduleSearchPaths = connectorModuleSearchPaths(projectRoot);
|
|
4054
|
+
}
|
|
3915
4055
|
if (normalized.driver === 'sqlite' && normalized.database && normalized.database !== ':memory:' && !isAbsoluteLikePath(normalized.database)) {
|
|
3916
4056
|
normalized.database = resolve(projectRoot, normalized.database);
|
|
3917
4057
|
}
|
|
@@ -4931,9 +5071,11 @@ async function buildBlockStudioAiAssistSummary(projectRoot, action, candidate, v
|
|
|
4931
5071
|
}
|
|
4932
5072
|
async function createBlockStudioAssistProvider(projectRoot, requestedProvider) {
|
|
4933
5073
|
const settings = listProviderSettings(projectRoot);
|
|
5074
|
+
const activeProvider = getActiveProvider(projectRoot);
|
|
4934
5075
|
const selected = requestedProvider
|
|
4935
5076
|
? settings.find((provider) => provider.id === requestedProvider && provider.enabled && provider.hasApiKey)
|
|
4936
|
-
: settings.find((provider) => provider.
|
|
5077
|
+
: settings.find((provider) => provider.id === activeProvider && provider.enabled)
|
|
5078
|
+
?? settings.find((provider) => provider.enabled && provider.hasApiKey);
|
|
4937
5079
|
if (!selected)
|
|
4938
5080
|
return null;
|
|
4939
5081
|
const config = getEffectiveProviderConfig(projectRoot, selected.id);
|
|
@@ -5681,45 +5823,7 @@ function mapDbtProfileOutput(output) {
|
|
|
5681
5823
|
result.envRefs.forEach((ref) => envRefs.add(ref));
|
|
5682
5824
|
return result.value;
|
|
5683
5825
|
};
|
|
5684
|
-
const port = numberValue(output, 'port');
|
|
5685
|
-
const sslRaw = read('ssl', 'sslmode');
|
|
5686
|
-
const ssl = sslRaw === undefined
|
|
5687
|
-
? undefined
|
|
5688
|
-
: !['false', '0', 'disable', 'disabled', 'off'].includes(sslRaw.toLowerCase());
|
|
5689
5826
|
switch (adapter) {
|
|
5690
|
-
case 'postgres':
|
|
5691
|
-
case 'postgresql':
|
|
5692
|
-
return {
|
|
5693
|
-
adapter,
|
|
5694
|
-
connection: compactConnection({
|
|
5695
|
-
driver: 'postgresql',
|
|
5696
|
-
host: read('host'),
|
|
5697
|
-
port,
|
|
5698
|
-
database: read('dbname', 'database'),
|
|
5699
|
-
schema: read('schema'),
|
|
5700
|
-
username: read('user', 'username'),
|
|
5701
|
-
password: read('password', 'pass'),
|
|
5702
|
-
ssl,
|
|
5703
|
-
}),
|
|
5704
|
-
envRefs: [...envRefs],
|
|
5705
|
-
warnings,
|
|
5706
|
-
};
|
|
5707
|
-
case 'redshift':
|
|
5708
|
-
return {
|
|
5709
|
-
adapter,
|
|
5710
|
-
connection: compactConnection({
|
|
5711
|
-
driver: 'redshift',
|
|
5712
|
-
host: read('host'),
|
|
5713
|
-
port: port ?? 5439,
|
|
5714
|
-
database: read('dbname', 'database'),
|
|
5715
|
-
schema: read('schema'),
|
|
5716
|
-
username: read('user', 'username'),
|
|
5717
|
-
password: read('password', 'pass'),
|
|
5718
|
-
ssl,
|
|
5719
|
-
}),
|
|
5720
|
-
envRefs: [...envRefs],
|
|
5721
|
-
warnings,
|
|
5722
|
-
};
|
|
5723
5827
|
case 'snowflake': {
|
|
5724
5828
|
const privateKeyPath = read('private_key_path', 'privateKeyPath');
|
|
5725
5829
|
const privateKey = read('private_key', 'privateKey');
|
|
@@ -5729,9 +5833,19 @@ function mapDbtProfileOutput(output) {
|
|
|
5729
5833
|
? 'key_pair'
|
|
5730
5834
|
: normalizedAuthenticator === 'externalbrowser'
|
|
5731
5835
|
? 'external_browser'
|
|
5732
|
-
: normalizedAuthenticator === '
|
|
5733
|
-
? '
|
|
5734
|
-
: '
|
|
5836
|
+
: normalizedAuthenticator === 'usernamepasswordmfa'
|
|
5837
|
+
? 'mfa'
|
|
5838
|
+
: normalizedAuthenticator === 'oauthauthorizationcode'
|
|
5839
|
+
? 'oauth_authorization_code'
|
|
5840
|
+
: normalizedAuthenticator === 'oauthclientcredentials'
|
|
5841
|
+
? 'oauth_client_credentials'
|
|
5842
|
+
: normalizedAuthenticator === 'programmaticaccesstoken'
|
|
5843
|
+
? 'programmatic_access_token'
|
|
5844
|
+
: normalizedAuthenticator === 'workloadidentity'
|
|
5845
|
+
? 'workload_identity'
|
|
5846
|
+
: normalizedAuthenticator === 'oauth'
|
|
5847
|
+
? 'oauth'
|
|
5848
|
+
: 'password';
|
|
5735
5849
|
return {
|
|
5736
5850
|
adapter,
|
|
5737
5851
|
connection: compactConnection({
|
|
@@ -5748,22 +5862,34 @@ function mapDbtProfileOutput(output) {
|
|
|
5748
5862
|
privateKeyPassphrase: read('private_key_passphrase', 'privateKeyPassphrase'),
|
|
5749
5863
|
authenticator,
|
|
5750
5864
|
authMethod,
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5865
|
+
token: read('token'),
|
|
5866
|
+
accessUrl: read('access_url', 'accessUrl'),
|
|
5867
|
+
application: read('application'),
|
|
5868
|
+
browserActionTimeout: readNumber(output, 'browser_action_timeout', 'browserActionTimeout'),
|
|
5869
|
+
clientRequestMFAToken: readBoolean(output, 'client_request_mfa_token', 'clientRequestMFAToken'),
|
|
5870
|
+
clientStoreTemporaryCredential: readBoolean(output, 'client_store_temporary_credential', 'clientStoreTemporaryCredential'),
|
|
5871
|
+
clientSessionKeepAlive: readBoolean(output, 'client_session_keep_alive', 'clientSessionKeepAlive'),
|
|
5872
|
+
clientSessionKeepAliveHeartbeatFrequency: readNumber(output, 'client_session_keep_alive_heartbeat_frequency', 'clientSessionKeepAliveHeartbeatFrequency'),
|
|
5873
|
+
credentialCacheDir: read('credential_cache_dir', 'credentialCacheDir'),
|
|
5874
|
+
keepAlive: readBoolean(output, 'keep_alive', 'keepAlive'),
|
|
5875
|
+
noProxy: read('no_proxy', 'noProxy'),
|
|
5876
|
+
oauthAuthorizationUrl: read('oauth_authorization_url', 'oauthAuthorizationUrl'),
|
|
5877
|
+
oauthClientId: read('oauth_client_id', 'oauthClientId'),
|
|
5878
|
+
oauthClientSecret: read('oauth_client_secret', 'oauthClientSecret'),
|
|
5879
|
+
oauthRedirectUri: read('oauth_redirect_uri', 'oauthRedirectUri'),
|
|
5880
|
+
oauthScope: read('oauth_scope', 'oauthScope'),
|
|
5881
|
+
oauthTokenRequestUrl: read('oauth_token_request_url', 'oauthTokenRequestUrl'),
|
|
5882
|
+
passcode: read('passcode'),
|
|
5883
|
+
passcodeInPassword: readBoolean(output, 'passcode_in_password', 'passcodeInPassword'),
|
|
5884
|
+
proxyHost: read('proxy_host', 'proxyHost'),
|
|
5885
|
+
proxyPassword: read('proxy_password', 'proxyPassword'),
|
|
5886
|
+
proxyPort: readNumber(output, 'proxy_port', 'proxyPort'),
|
|
5887
|
+
proxyProtocol: read('proxy_protocol', 'proxyProtocol'),
|
|
5888
|
+
proxyUser: read('proxy_user', 'proxyUser'),
|
|
5889
|
+
queryTag: read('query_tag', 'queryTag'),
|
|
5890
|
+
timeout: readNumber(output, 'timeout'),
|
|
5891
|
+
workloadIdentityProvider: read('workload_identity_provider', 'workloadIdentityProvider'),
|
|
5892
|
+
workloadIdentityAzureClientId: read('workload_identity_azure_client_id', 'workloadIdentityAzureClientId'),
|
|
5767
5893
|
}),
|
|
5768
5894
|
envRefs: [...envRefs],
|
|
5769
5895
|
warnings,
|
|
@@ -5779,7 +5905,9 @@ function mapDbtProfileOutput(output) {
|
|
|
5779
5905
|
envRefs: [...envRefs],
|
|
5780
5906
|
warnings,
|
|
5781
5907
|
};
|
|
5782
|
-
case 'databricks':
|
|
5908
|
+
case 'databricks': {
|
|
5909
|
+
const databricksAuth = read('auth_type', 'auth_method', 'authMethod');
|
|
5910
|
+
const authMethod = databricksAuth?.toLowerCase().includes('oauth') ? 'oauth' : 'token';
|
|
5783
5911
|
return {
|
|
5784
5912
|
adapter,
|
|
5785
5913
|
connection: compactConnection({
|
|
@@ -5791,15 +5919,44 @@ function mapDbtProfileOutput(output) {
|
|
|
5791
5919
|
database: read('catalog', 'database'),
|
|
5792
5920
|
schema: read('schema'),
|
|
5793
5921
|
token: read('token'),
|
|
5794
|
-
authMethod
|
|
5922
|
+
authMethod,
|
|
5923
|
+
waitTimeout: read('wait_timeout', 'waitTimeout'),
|
|
5924
|
+
byteLimit: readNumber(output, 'byte_limit', 'byteLimit'),
|
|
5795
5925
|
}),
|
|
5796
5926
|
envRefs: [...envRefs],
|
|
5797
5927
|
warnings,
|
|
5798
5928
|
};
|
|
5929
|
+
}
|
|
5799
5930
|
default:
|
|
5800
5931
|
return null;
|
|
5801
5932
|
}
|
|
5802
5933
|
}
|
|
5934
|
+
function readBoolean(source, ...keys) {
|
|
5935
|
+
for (const key of keys) {
|
|
5936
|
+
const raw = source[key];
|
|
5937
|
+
if (typeof raw === 'boolean')
|
|
5938
|
+
return raw;
|
|
5939
|
+
if (raw === undefined || raw === null)
|
|
5940
|
+
continue;
|
|
5941
|
+
const value = String(raw).trim().toLowerCase();
|
|
5942
|
+
if (['true', '1', 'yes', 'y'].includes(value))
|
|
5943
|
+
return true;
|
|
5944
|
+
if (['false', '0', 'no', 'n'].includes(value))
|
|
5945
|
+
return false;
|
|
5946
|
+
}
|
|
5947
|
+
return undefined;
|
|
5948
|
+
}
|
|
5949
|
+
function readNumber(source, ...keys) {
|
|
5950
|
+
for (const key of keys) {
|
|
5951
|
+
const raw = source[key];
|
|
5952
|
+
if (raw === undefined || raw === null || raw === '')
|
|
5953
|
+
continue;
|
|
5954
|
+
const value = Number(raw);
|
|
5955
|
+
if (Number.isFinite(value))
|
|
5956
|
+
return value;
|
|
5957
|
+
}
|
|
5958
|
+
return undefined;
|
|
5959
|
+
}
|
|
5803
5960
|
function text(source, ...keys) {
|
|
5804
5961
|
for (const key of keys) {
|
|
5805
5962
|
const raw = source[key];
|
|
@@ -5825,13 +5982,6 @@ function resolveDbtEnvVars(value) {
|
|
|
5825
5982
|
});
|
|
5826
5983
|
return { value: replaced, envRefs };
|
|
5827
5984
|
}
|
|
5828
|
-
function numberValue(source, key) {
|
|
5829
|
-
const raw = source[key];
|
|
5830
|
-
if (raw === undefined || raw === null || raw === '')
|
|
5831
|
-
return undefined;
|
|
5832
|
-
const value = Number(raw);
|
|
5833
|
-
return Number.isFinite(value) ? value : undefined;
|
|
5834
|
-
}
|
|
5835
5985
|
function compactConnection(connection) {
|
|
5836
5986
|
const compact = {};
|
|
5837
5987
|
for (const [key, value] of Object.entries(connection)) {
|
|
@@ -5849,12 +5999,6 @@ function requiredConnectionFields(connection, envRefs) {
|
|
|
5849
5999
|
missing.add(String(field));
|
|
5850
6000
|
};
|
|
5851
6001
|
switch (connection.driver) {
|
|
5852
|
-
case 'postgresql':
|
|
5853
|
-
case 'redshift':
|
|
5854
|
-
needs('host');
|
|
5855
|
-
needs('database');
|
|
5856
|
-
needs('username');
|
|
5857
|
-
break;
|
|
5858
6002
|
case 'snowflake':
|
|
5859
6003
|
needs('account');
|
|
5860
6004
|
needs('warehouse');
|
|
@@ -5871,13 +6015,27 @@ function requiredConnectionFields(connection, envRefs) {
|
|
|
5871
6015
|
missing.add('token');
|
|
5872
6016
|
}
|
|
5873
6017
|
}
|
|
6018
|
+
else if (connection.authMethod === 'programmatic_access_token') {
|
|
6019
|
+
if (!connection.token && !connection.password) {
|
|
6020
|
+
missing.add('token');
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
else if (connection.authMethod === 'oauth_authorization_code') {
|
|
6024
|
+
needs('oauthClientId');
|
|
6025
|
+
needs('oauthClientSecret');
|
|
6026
|
+
}
|
|
6027
|
+
else if (connection.authMethod === 'oauth_client_credentials') {
|
|
6028
|
+
needs('oauthClientId');
|
|
6029
|
+
needs('oauthClientSecret');
|
|
6030
|
+
needs('oauthTokenRequestUrl');
|
|
6031
|
+
}
|
|
6032
|
+
else if (connection.authMethod === 'workload_identity') {
|
|
6033
|
+
needs('workloadIdentityProvider');
|
|
6034
|
+
}
|
|
5874
6035
|
else if (connection.authMethod !== 'external_browser') {
|
|
5875
6036
|
needs('password');
|
|
5876
6037
|
}
|
|
5877
6038
|
break;
|
|
5878
|
-
case 'bigquery':
|
|
5879
|
-
needs('projectId');
|
|
5880
|
-
break;
|
|
5881
6039
|
case 'duckdb':
|
|
5882
6040
|
needs('filepath');
|
|
5883
6041
|
break;
|
|
@@ -6497,11 +6655,17 @@ function isProviderSettingsId(value) {
|
|
|
6497
6655
|
}
|
|
6498
6656
|
async function testProviderConfig(projectRoot, id) {
|
|
6499
6657
|
const config = getEffectiveProviderConfig(projectRoot, id);
|
|
6658
|
+
const label = providerSettingsLabel(id);
|
|
6659
|
+
const details = providerConfigDetails(id, config);
|
|
6660
|
+
if (!config.enabled) {
|
|
6661
|
+
return { ok: false, message: `${label} is disabled in Settings.` };
|
|
6662
|
+
}
|
|
6663
|
+
if (id === 'openai')
|
|
6664
|
+
return testOpenAIProviderConfig(config, label, details);
|
|
6665
|
+
if (id === 'anthropic')
|
|
6666
|
+
return testAnthropicProviderConfig(config, label, details);
|
|
6500
6667
|
let provider;
|
|
6501
6668
|
switch (id) {
|
|
6502
|
-
case 'anthropic':
|
|
6503
|
-
provider = new ClaudeProvider({ apiKey: config.apiKey, model: config.model });
|
|
6504
|
-
break;
|
|
6505
6669
|
case 'gemini':
|
|
6506
6670
|
provider = new GeminiProvider({ apiKey: config.apiKey, model: config.model });
|
|
6507
6671
|
break;
|
|
@@ -6509,20 +6673,97 @@ async function testProviderConfig(projectRoot, id) {
|
|
|
6509
6673
|
provider = new OllamaProvider({ baseUrl: config.baseUrl, model: config.model });
|
|
6510
6674
|
break;
|
|
6511
6675
|
case 'custom-openai':
|
|
6512
|
-
provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model, allowNoApiKey: true });
|
|
6513
|
-
break;
|
|
6514
|
-
case 'openai':
|
|
6515
6676
|
default:
|
|
6516
|
-
provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model });
|
|
6677
|
+
provider = new OpenAIProvider({ apiKey: config.apiKey, baseUrl: config.baseUrl, model: config.model, allowNoApiKey: true });
|
|
6517
6678
|
break;
|
|
6518
6679
|
}
|
|
6519
|
-
const
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
}
|
|
6680
|
+
const available = await provider.available().catch(() => false);
|
|
6681
|
+
if (!available) {
|
|
6682
|
+
return {
|
|
6683
|
+
ok: false,
|
|
6684
|
+
message: `${label} is not configured or reachable${details}. Check API key, base URL, and local service state.`,
|
|
6685
|
+
};
|
|
6686
|
+
}
|
|
6687
|
+
try {
|
|
6688
|
+
const text = await provider.generate([
|
|
6689
|
+
{ role: 'user', content: 'Reply with exactly: OK' },
|
|
6690
|
+
], { maxTokens: 8, temperature: 0 });
|
|
6691
|
+
return {
|
|
6692
|
+
ok: true,
|
|
6693
|
+
message: `${label} responded${details}: ${text.trim().slice(0, 80) || 'OK'}`,
|
|
6694
|
+
};
|
|
6695
|
+
}
|
|
6696
|
+
catch (error) {
|
|
6697
|
+
return {
|
|
6698
|
+
ok: false,
|
|
6699
|
+
message: `${label} is configured but the model call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
|
|
6700
|
+
};
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
async function testOpenAIProviderConfig(config, label, details) {
|
|
6704
|
+
if (!config.apiKey) {
|
|
6705
|
+
return { ok: false, message: `${label} is not configured${details}. Add an API key in Settings or OPENAI_API_KEY.` };
|
|
6706
|
+
}
|
|
6707
|
+
try {
|
|
6708
|
+
const client = new OpenAI({ apiKey: config.apiKey, baseURL: config.baseUrl });
|
|
6709
|
+
const response = await client.responses.create({
|
|
6710
|
+
model: config.model ?? 'gpt-5.5',
|
|
6711
|
+
input: 'Reply with exactly: OK',
|
|
6712
|
+
max_output_tokens: 16,
|
|
6713
|
+
});
|
|
6714
|
+
return {
|
|
6715
|
+
ok: true,
|
|
6716
|
+
message: `${label} SDK responded${details}: ${(response.output_text ?? 'OK').trim().slice(0, 80) || 'OK'}`,
|
|
6717
|
+
};
|
|
6718
|
+
}
|
|
6719
|
+
catch (error) {
|
|
6720
|
+
return {
|
|
6721
|
+
ok: false,
|
|
6722
|
+
message: `${label} SDK call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
|
|
6723
|
+
};
|
|
6724
|
+
}
|
|
6725
|
+
}
|
|
6726
|
+
async function testAnthropicProviderConfig(config, label, details) {
|
|
6727
|
+
if (!config.apiKey) {
|
|
6728
|
+
return { ok: false, message: `${label} is not configured${details}. Add an API key in Settings or ANTHROPIC_API_KEY.` };
|
|
6729
|
+
}
|
|
6730
|
+
try {
|
|
6731
|
+
const client = new Anthropic({ apiKey: config.apiKey });
|
|
6732
|
+
const response = await client.messages.create({
|
|
6733
|
+
model: config.model ?? 'claude-opus-4-8',
|
|
6734
|
+
max_tokens: 16,
|
|
6735
|
+
temperature: 0,
|
|
6736
|
+
messages: [{ role: 'user', content: 'Reply with exactly: OK' }],
|
|
6737
|
+
});
|
|
6738
|
+
const text = response.content?.filter((block) => block.type === 'text').map((block) => block.text ?? '').join('') ?? '';
|
|
6739
|
+
return {
|
|
6740
|
+
ok: true,
|
|
6741
|
+
message: `${label} SDK responded${details}: ${text.trim().slice(0, 80) || 'OK'}`,
|
|
6742
|
+
};
|
|
6743
|
+
}
|
|
6744
|
+
catch (error) {
|
|
6745
|
+
return {
|
|
6746
|
+
ok: false,
|
|
6747
|
+
message: `${label} SDK call failed${details}: ${error instanceof Error ? error.message : String(error)}`,
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
function providerSettingsLabel(id) {
|
|
6752
|
+
switch (id) {
|
|
6753
|
+
case 'anthropic': return 'Anthropic Claude';
|
|
6754
|
+
case 'openai': return 'OpenAI';
|
|
6755
|
+
case 'gemini': return 'Gemini';
|
|
6756
|
+
case 'ollama': return 'Ollama';
|
|
6757
|
+
case 'custom-openai': return 'Custom OpenAI-compatible provider';
|
|
6758
|
+
}
|
|
6759
|
+
}
|
|
6760
|
+
function providerConfigDetails(id, config) {
|
|
6761
|
+
const parts = [
|
|
6762
|
+
config.model ? `model ${config.model}` : '',
|
|
6763
|
+
config.baseUrl ? `base URL ${config.baseUrl}` : '',
|
|
6764
|
+
id === 'ollama' ? 'local endpoint' : config.apiKey ? 'API key present' : 'API key missing',
|
|
6765
|
+
].filter(Boolean);
|
|
6766
|
+
return parts.length ? ` (${parts.join(', ')})` : '';
|
|
6526
6767
|
}
|
|
6527
6768
|
function isAiPinRefreshDue(lastRefreshedAt) {
|
|
6528
6769
|
if (!lastRefreshedAt)
|