@kaelio/ktx 0.13.0 → 0.14.0
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/assets/python/{kaelio_ktx-0.13.0-py3-none-any.whl → kaelio_ktx-0.14.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli-program.js +1 -1
- package/dist/commands/ingest-commands.d.ts +9 -0
- package/dist/commands/ingest-commands.js +37 -1
- package/dist/commands/knowledge-commands.js +3 -0
- package/dist/commands/setup-commands.js +14 -1
- package/dist/connection-drivers.d.ts +2 -0
- package/dist/connection-drivers.js +7 -3
- package/dist/connection.d.ts +3 -0
- package/dist/connection.js +27 -0
- package/dist/connectors/bigquery/connector.d.ts +17 -6
- package/dist/connectors/bigquery/connector.js +152 -76
- package/dist/connectors/bigquery/dialect.d.ts +2 -2
- package/dist/connectors/clickhouse/connector.d.ts +1 -0
- package/dist/connectors/clickhouse/connector.js +45 -16
- package/dist/connectors/clickhouse/dialect.d.ts +2 -2
- package/dist/connectors/mongodb/connector.d.ts +69 -0
- package/dist/connectors/mongodb/connector.js +307 -0
- package/dist/connectors/mongodb/dialect.d.ts +17 -0
- package/dist/connectors/mongodb/dialect.js +50 -0
- package/dist/connectors/mongodb/live-database-introspection.d.ts +10 -0
- package/dist/connectors/mongodb/live-database-introspection.js +24 -0
- package/dist/connectors/mongodb/schema-inference.d.ts +20 -0
- package/dist/connectors/mongodb/schema-inference.js +110 -0
- package/dist/connectors/mysql/connector.d.ts +1 -0
- package/dist/connectors/mysql/connector.js +18 -2
- package/dist/connectors/mysql/dialect.d.ts +2 -2
- package/dist/connectors/postgres/connector.d.ts +1 -0
- package/dist/connectors/postgres/connector.js +20 -3
- package/dist/connectors/postgres/dialect.d.ts +2 -2
- package/dist/connectors/snowflake/connector.d.ts +1 -0
- package/dist/connectors/snowflake/connector.js +27 -3
- package/dist/connectors/snowflake/dialect.d.ts +2 -2
- package/dist/connectors/sqlite/connector.d.ts +11 -1
- package/dist/connectors/sqlite/connector.js +120 -17
- package/dist/connectors/sqlite/dialect.d.ts +2 -2
- package/dist/connectors/sqlite/read-query-child.d.ts +1 -0
- package/dist/connectors/sqlite/read-query-child.js +23 -0
- package/dist/connectors/sqlserver/connector.d.ts +2 -0
- package/dist/connectors/sqlserver/connector.js +23 -5
- package/dist/connectors/sqlserver/dialect.d.ts +2 -2
- package/dist/context/cache/content-result-cache.d.ts +36 -0
- package/dist/context/cache/content-result-cache.js +14 -0
- package/dist/context/cache/sqlite-content-result-cache.d.ts +18 -0
- package/dist/context/cache/sqlite-content-result-cache.js +223 -0
- package/dist/context/connections/bigquery-identifiers.d.ts +1 -0
- package/dist/context/connections/bigquery-identifiers.js +7 -0
- package/dist/context/connections/configured-connections.d.ts +9 -0
- package/dist/context/connections/configured-connections.js +18 -0
- package/dist/context/connections/dialects.d.ts +30 -4
- package/dist/context/connections/dialects.js +38 -11
- package/dist/context/connections/drivers.js +21 -0
- package/dist/context/connections/gdrive-config.d.ts +19 -0
- package/dist/context/connections/gdrive-config.js +57 -0
- package/dist/context/connections/query-deadline.d.ts +31 -0
- package/dist/context/connections/query-deadline.js +37 -0
- package/dist/context/connections/read-only-sql.d.ts +5 -0
- package/dist/context/connections/read-only-sql.js +139 -1
- package/dist/context/ingest/adapters/gdrive/chunk.d.ts +3 -0
- package/dist/context/ingest/adapters/gdrive/chunk.js +74 -0
- package/dist/context/ingest/adapters/gdrive/detect.d.ts +1 -0
- package/dist/context/ingest/adapters/gdrive/detect.js +20 -0
- package/dist/context/ingest/adapters/gdrive/fetch.d.ts +6 -0
- package/dist/context/ingest/adapters/gdrive/fetch.js +95 -0
- package/dist/context/ingest/adapters/gdrive/gdrive-client.d.ts +30 -0
- package/dist/context/ingest/adapters/gdrive/gdrive-client.js +132 -0
- package/dist/context/ingest/adapters/gdrive/gdrive.adapter.d.ts +11 -0
- package/dist/context/ingest/adapters/gdrive/gdrive.adapter.js +27 -0
- package/dist/context/ingest/adapters/gdrive/normalize.d.ts +2 -0
- package/dist/context/ingest/adapters/gdrive/normalize.js +256 -0
- package/dist/context/ingest/adapters/gdrive/types.d.ts +153 -0
- package/dist/context/ingest/adapters/gdrive/types.js +36 -0
- package/dist/context/ingest/adapters/live-database/daemon-introspection.js +24 -0
- package/dist/context/ingest/adapters/live-database/fetch-report.d.ts +8 -0
- package/dist/context/ingest/adapters/live-database/fetch-report.js +37 -0
- package/dist/context/ingest/adapters/live-database/live-database.adapter.d.ts +2 -1
- package/dist/context/ingest/adapters/live-database/live-database.adapter.js +9 -2
- package/dist/context/ingest/adapters/live-database/manifest.d.ts +2 -0
- package/dist/context/ingest/adapters/live-database/manifest.js +8 -4
- package/dist/context/ingest/adapters/live-database/scan-outcome.d.ts +17 -0
- package/dist/context/ingest/adapters/live-database/scan-outcome.js +40 -0
- package/dist/context/ingest/adapters/live-database/stage.js +5 -5
- package/dist/context/ingest/adapters/metabase/types.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/types.js +1 -1
- package/dist/context/ingest/artifact-gates.d.ts +32 -1
- package/dist/context/ingest/artifact-gates.js +85 -18
- package/dist/context/ingest/final-gate-prune.d.ts +35 -0
- package/dist/context/ingest/final-gate-prune.js +229 -0
- package/dist/context/ingest/ingest-bundle.runner.d.ts +3 -0
- package/dist/context/ingest/ingest-bundle.runner.js +459 -240
- package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +0 -11
- package/dist/context/ingest/isolated-diff/patch-integrator.js +0 -44
- package/dist/context/ingest/isolated-diff/work-unit-executor.d.ts +1 -0
- package/dist/context/ingest/isolated-diff/work-unit-executor.js +13 -4
- package/dist/context/ingest/local-adapters.js +6 -0
- package/dist/context/ingest/local-bundle-runtime.js +7 -2
- package/dist/context/ingest/local-ingest.js +1 -1
- package/dist/context/ingest/local-stage-ingest.d.ts +3 -1
- package/dist/context/ingest/local-stage-ingest.js +3 -1
- package/dist/context/ingest/ports.d.ts +3 -0
- package/dist/context/ingest/report-snapshot.js +13 -3
- package/dist/context/ingest/reports.d.ts +3 -3
- package/dist/context/ingest/reports.js +3 -1
- package/dist/context/ingest/stages/build-wu-context.d.ts +1 -0
- package/dist/context/ingest/stages/build-wu-context.js +2 -1
- package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -1
- package/dist/context/ingest/stages/stage-3-work-units.js +4 -10
- package/dist/context/ingest/stages/validate-wu-sources.d.ts +12 -0
- package/dist/context/ingest/stages/validate-wu-sources.js +23 -8
- package/dist/context/ingest/tools/read-raw-file.tool.js +10 -5
- package/dist/context/ingest/tools/read-raw-span.tool.js +10 -5
- package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +1 -1
- package/dist/context/ingest/types.d.ts +3 -0
- package/dist/context/ingest/wiki-body-refs.d.ts +28 -0
- package/dist/context/ingest/wiki-body-refs.js +37 -8
- package/dist/context/ingest/wiki-sl-ref-repair.d.ts +1 -0
- package/dist/context/ingest/wiki-sl-ref-repair.js +4 -0
- package/dist/context/ingest/work-unit-cache.d.ts +67 -0
- package/dist/context/ingest/work-unit-cache.js +230 -0
- package/dist/context/llm/ai-sdk-runtime.d.ts +1 -0
- package/dist/context/llm/ai-sdk-runtime.js +5 -0
- package/dist/context/llm/claude-code-runtime.d.ts +4 -1
- package/dist/context/llm/claude-code-runtime.js +38 -8
- package/dist/context/llm/codex-runtime.d.ts +4 -1
- package/dist/context/llm/codex-runtime.js +48 -35
- package/dist/context/llm/runtime-port.d.ts +26 -0
- package/dist/context/llm/subprocess-generate-object-child.d.ts +1 -0
- package/dist/context/llm/subprocess-generate-object-child.js +34 -0
- package/dist/context/llm/subprocess-generate-object.d.ts +42 -0
- package/dist/context/llm/subprocess-generate-object.js +122 -0
- package/dist/context/mcp/context-tools.d.ts +2 -0
- package/dist/context/mcp/context-tools.js +111 -17
- package/dist/context/mcp/local-project-ports.d.ts +7 -0
- package/dist/context/mcp/local-project-ports.js +29 -0
- package/dist/context/mcp/logger.d.ts +24 -0
- package/dist/context/mcp/logger.js +49 -0
- package/dist/context/mcp/server.js +2 -0
- package/dist/context/mcp/types.d.ts +17 -0
- package/dist/context/memory/memory-agent.service.js +1 -1
- package/dist/context/project/config.d.ts +42 -0
- package/dist/context/project/config.js +5 -0
- package/dist/context/project/driver-schemas.d.ts +20 -0
- package/dist/context/project/driver-schemas.js +50 -1
- package/dist/context/project/project.js +1 -1
- package/dist/context/project/setup-config.js +1 -0
- package/dist/context/scan/description-generation.d.ts +4 -0
- package/dist/context/scan/description-generation.js +100 -13
- package/dist/context/scan/enabled-tables.d.ts +5 -0
- package/dist/context/scan/enabled-tables.js +13 -1
- package/dist/context/scan/enrichment-state.d.ts +50 -7
- package/dist/context/scan/enrichment-state.js +30 -13
- package/dist/context/scan/local-enrichment-artifacts.d.ts +41 -0
- package/dist/context/scan/local-enrichment-artifacts.js +155 -32
- package/dist/context/scan/local-enrichment.d.ts +39 -4
- package/dist/context/scan/local-enrichment.js +345 -92
- package/dist/context/scan/local-scan.d.ts +4 -1
- package/dist/context/scan/local-scan.js +54 -13
- package/dist/context/scan/local-structural-artifacts.d.ts +3 -1
- package/dist/context/scan/local-structural-artifacts.js +5 -0
- package/dist/context/scan/object-introspection.d.ts +21 -0
- package/dist/context/scan/object-introspection.js +35 -0
- package/dist/context/scan/relationship-benchmarks.js +5 -3
- package/dist/context/scan/relationship-composite-candidates.d.ts +6 -3
- package/dist/context/scan/relationship-composite-candidates.js +13 -1
- package/dist/context/scan/relationship-detection-budget.d.ts +35 -0
- package/dist/context/scan/relationship-detection-budget.js +53 -0
- package/dist/context/scan/relationship-diagnostics.d.ts +5 -0
- package/dist/context/scan/relationship-diagnostics.js +2 -0
- package/dist/context/scan/relationship-discovery.d.ts +9 -3
- package/dist/context/scan/relationship-discovery.js +27 -4
- package/dist/context/scan/relationship-llm-proposal.js +36 -27
- package/dist/context/scan/relationship-profiling.d.ts +7 -3
- package/dist/context/scan/relationship-profiling.js +53 -41
- package/dist/context/scan/relationship-validation.d.ts +6 -4
- package/dist/context/scan/relationship-validation.js +46 -32
- package/dist/context/scan/sqlite-local-enrichment-state-store.d.ts +8 -1
- package/dist/context/scan/sqlite-local-enrichment-state-store.js +71 -159
- package/dist/context/scan/types.d.ts +5 -3
- package/dist/context/scan/types.js +2 -0
- package/dist/context/sl/local-query.js +5 -0
- package/dist/context/sl/pglite-sl-search-prototype.js +1 -1
- package/dist/context/sl/semantic-layer.service.js +1 -1
- package/dist/context/sl/source-files.d.ts +5 -0
- package/dist/context/sl/source-files.js +17 -11
- package/dist/context/sl/tools/connection-id-schema.js +1 -1
- package/dist/context/sql-analysis/dialect-notes.d.ts +9 -0
- package/dist/context/sql-analysis/dialect-notes.js +40 -0
- package/dist/context/sql-analysis/dialects/bigquery.md +13 -0
- package/dist/context/sql-analysis/dialects/clickhouse.md +9 -0
- package/dist/context/sql-analysis/dialects/mysql.md +9 -0
- package/dist/context/sql-analysis/dialects/postgres.md +10 -0
- package/dist/context/sql-analysis/dialects/snowflake.md +10 -0
- package/dist/context/sql-analysis/dialects/sqlite.md +11 -0
- package/dist/context/sql-analysis/dialects/tsql.md +10 -0
- package/dist/context/wiki/keys.js +1 -1
- package/dist/context/wiki/knowledge-wiki.service.d.ts +4 -4
- package/dist/context/wiki/knowledge-wiki.service.js +2 -1
- package/dist/context/wiki/local-knowledge.d.ts +13 -0
- package/dist/context/wiki/local-knowledge.js +50 -6
- package/dist/context/wiki/sqlite-knowledge-index.d.ts +2 -0
- package/dist/context/wiki/sqlite-knowledge-index.js +21 -5
- package/dist/context/wiki/tools/wiki-write.tool.d.ts +2 -0
- package/dist/context/wiki/tools/wiki-write.tool.js +27 -0
- package/dist/context/wiki/types.d.ts +6 -0
- package/dist/context-build-view.d.ts +3 -0
- package/dist/context-build-view.js +1 -0
- package/dist/knowledge.d.ts +2 -0
- package/dist/knowledge.js +12 -1
- package/dist/local-adapters.js +11 -0
- package/dist/mcp-http-server.js +15 -1
- package/dist/mcp-server-factory.d.ts +2 -0
- package/dist/mcp-server-factory.js +15 -1
- package/dist/mcp-stdio-server.js +10 -2
- package/dist/notion-page-picker.js +1 -1
- package/dist/prompts/memory_agent_external_ingest.md +2 -0
- package/dist/public-ingest.d.ts +3 -1
- package/dist/public-ingest.js +3 -0
- package/dist/scan.d.ts +3 -1
- package/dist/scan.js +7 -0
- package/dist/setup-databases.d.ts +1 -1
- package/dist/setup-databases.js +43 -1
- package/dist/setup-sources.d.ts +5 -1
- package/dist/setup-sources.js +124 -48
- package/dist/setup.d.ts +3 -0
- package/dist/setup.js +6 -1
- package/dist/skills/analytics/SKILL.md +200 -2
- package/dist/skills/gdrive_synthesize/SKILL.md +97 -0
- package/dist/skills/wiki_capture/SKILL.md +24 -0
- package/dist/sql.js +4 -0
- package/dist/status-project.d.ts +4 -0
- package/dist/status-project.js +54 -2
- package/dist/telemetry/events.d.ts +2 -2
- package/dist/text-ingest.d.ts +4 -0
- package/dist/text-ingest.js +58 -29
- package/dist/verbatim-ingest.d.ts +46 -0
- package/dist/verbatim-ingest.js +193 -0
- package/package.json +5 -1
- package/dist/context/ingest/final-gate-repair.d.ts +0 -28
- package/dist/context/ingest/final-gate-repair.js +0 -91
package/dist/cli-program.js
CHANGED
|
@@ -68,7 +68,7 @@ export function parseBooleanStringOption(value) {
|
|
|
68
68
|
throw new InvalidArgumentError('must be true or false');
|
|
69
69
|
}
|
|
70
70
|
export function parseSafeConnectionIdOption(value) {
|
|
71
|
-
if (!/^[a-zA-Z0-
|
|
71
|
+
if (!/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/.test(value)) {
|
|
72
72
|
throw new InvalidArgumentError(`Unsafe connection id: ${value}`);
|
|
73
73
|
}
|
|
74
74
|
return value;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type Command } from '@commander-js/extra-typings';
|
|
2
2
|
import { type KtxCliCommandContext } from '../cli-program.js';
|
|
3
|
+
import type { KtxScanEnrichmentStage } from '../context/scan/types.js';
|
|
3
4
|
import type { KtxCliDeps, KtxCliIo } from '../index.js';
|
|
4
5
|
import type { KtxTextIngestArgs } from '../text-ingest.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parses `--stages` into an ordered, de-duplicated subset of the canonical
|
|
8
|
+
* enrichment-stage registry. An unknown or empty name is a hard parse error so
|
|
9
|
+
* a typo never silently degrades to "run everything."
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnrichmentStagesOption(value: string): KtxScanEnrichmentStage[];
|
|
5
14
|
interface IngestCommandOptions {
|
|
6
15
|
runTextIngest: (args: KtxTextIngestArgs, io: KtxCliIo, deps: KtxCliDeps) => Promise<number>;
|
|
7
16
|
}
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
import { Option } from '@commander-js/extra-typings';
|
|
1
|
+
import { InvalidArgumentError, Option } from '@commander-js/extra-typings';
|
|
2
2
|
import { collectOption, parsePositiveIntegerOption, resolveCommandProjectDir, } from '../cli-program.js';
|
|
3
|
+
import { KTX_SCAN_ENRICHMENT_STAGES } from '../context/scan/enrichment-state.js';
|
|
3
4
|
import { runtimeInstallPolicyFromFlags } from '../managed-python-command.js';
|
|
4
5
|
import { profileMark } from '../startup-profile.js';
|
|
5
6
|
import { resolveConnectionSelection } from './connection-selection.js';
|
|
6
7
|
profileMark('module:commands/ingest-commands');
|
|
8
|
+
/**
|
|
9
|
+
* Parses `--stages` into an ordered, de-duplicated subset of the canonical
|
|
10
|
+
* enrichment-stage registry. An unknown or empty name is a hard parse error so
|
|
11
|
+
* a typo never silently degrades to "run everything."
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export function parseEnrichmentStagesOption(value) {
|
|
16
|
+
const names = value
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((name) => name.trim())
|
|
19
|
+
.filter((name) => name.length > 0);
|
|
20
|
+
if (names.length === 0) {
|
|
21
|
+
throw new InvalidArgumentError(`must be a non-empty comma-separated list of stages (${KTX_SCAN_ENRICHMENT_STAGES.join(', ')})`);
|
|
22
|
+
}
|
|
23
|
+
const valid = new Set(KTX_SCAN_ENRICHMENT_STAGES);
|
|
24
|
+
const selected = new Set();
|
|
25
|
+
for (const name of names) {
|
|
26
|
+
if (!valid.has(name)) {
|
|
27
|
+
throw new InvalidArgumentError(`unknown stage "${name}"; valid stages are ${KTX_SCAN_ENRICHMENT_STAGES.join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
selected.add(name);
|
|
30
|
+
}
|
|
31
|
+
return KTX_SCAN_ENRICHMENT_STAGES.filter((stage) => selected.has(stage));
|
|
32
|
+
}
|
|
7
33
|
export function registerIngestCommands(program, context, commandOptions) {
|
|
8
34
|
const ingest = program
|
|
9
35
|
.command('ingest')
|
|
@@ -14,8 +40,10 @@ export function registerIngestCommands(program, context, commandOptions) {
|
|
|
14
40
|
.addOption(new Option('--query-history', 'Include database query-history usage patterns').conflicts('noQueryHistory'))
|
|
15
41
|
.addOption(new Option('--no-query-history', 'Skip database query-history usage patterns'))
|
|
16
42
|
.option('--query-history-window-days <days>', 'Query-history lookback window for this run', parsePositiveIntegerOption)
|
|
43
|
+
.option('--stages <stages>', 'Comma-separated enrichment stages to (re)run (descriptions,embeddings,relationships); omit to run all', parseEnrichmentStagesOption)
|
|
17
44
|
.option('--text <content>', 'Capture inline text into ktx memory; repeatable', collectOption, [])
|
|
18
45
|
.option('--file <path>', 'Capture a text file into ktx memory; use - for stdin; repeatable', collectOption, [])
|
|
46
|
+
.option('--verbatim', 'Store each --text/--file document body unchanged as a GLOBAL wiki page; the LLM derives only metadata', false)
|
|
19
47
|
.option('--connection-id <connectionId>', 'ktx connection id to tag captured text/file notes')
|
|
20
48
|
.option('--user-id <id>', 'Memory user id for text/file capture attribution', 'local-cli')
|
|
21
49
|
.option('--fail-fast', 'Stop after the first failed text/file item', false)
|
|
@@ -27,6 +55,12 @@ export function registerIngestCommands(program, context, commandOptions) {
|
|
|
27
55
|
ingest.action(async (connectionId, options, command) => {
|
|
28
56
|
const projectDir = resolveCommandProjectDir(command);
|
|
29
57
|
const hasTextCapture = options.text.length > 0 || options.file.length > 0;
|
|
58
|
+
if (options.verbatim === true && !hasTextCapture) {
|
|
59
|
+
command.error('error: --verbatim requires --text or --file');
|
|
60
|
+
}
|
|
61
|
+
if (options.stages !== undefined && hasTextCapture) {
|
|
62
|
+
command.error('error: --stages applies to database ingest only; it cannot be combined with --text or --file');
|
|
63
|
+
}
|
|
30
64
|
if (hasTextCapture) {
|
|
31
65
|
if (connectionId !== undefined) {
|
|
32
66
|
command.error('error: --text/--file does not accept a positional connection id; use --connection-id <id> to tag captured notes');
|
|
@@ -42,6 +76,7 @@ export function registerIngestCommands(program, context, commandOptions) {
|
|
|
42
76
|
userId: options.userId,
|
|
43
77
|
json: options.json === true,
|
|
44
78
|
failFast: options.failFast === true,
|
|
79
|
+
...(options.verbatim === true ? { verbatim: true } : {}),
|
|
45
80
|
}, context.io, context.deps));
|
|
46
81
|
return;
|
|
47
82
|
}
|
|
@@ -57,6 +92,7 @@ export function registerIngestCommands(program, context, commandOptions) {
|
|
|
57
92
|
inputMode: options.input === false ? 'disabled' : 'auto',
|
|
58
93
|
queryHistory,
|
|
59
94
|
...(options.queryHistoryWindowDays !== undefined ? { queryHistoryWindowDays: options.queryHistoryWindowDays } : {}),
|
|
95
|
+
...(options.stages ? { stages: options.stages } : {}),
|
|
60
96
|
cliVersion: context.packageInfo.version,
|
|
61
97
|
runtimeInstallPolicy: runtimeInstallPolicyFromFlags(options),
|
|
62
98
|
};
|
|
@@ -17,6 +17,7 @@ export function registerWikiCommands(program, context) {
|
|
|
17
17
|
.usage('[options] [query...]')
|
|
18
18
|
.argument('[query...]', 'Search query; omit to list all pages')
|
|
19
19
|
.option('--user-id <id>', 'Local user id', 'local')
|
|
20
|
+
.option('-c, --connection <id>', 'Scope results to one connection (unscoped pages plus pages tagged with it)')
|
|
20
21
|
.option('--limit <number>', 'Maximum search results (search mode only)', parsePositiveIntegerOption)
|
|
21
22
|
.addOption(new Option('--output <mode>', 'Output mode: pretty (default in TTY), plain (TSV), or json').choices([
|
|
22
23
|
'pretty',
|
|
@@ -32,6 +33,7 @@ export function registerWikiCommands(program, context) {
|
|
|
32
33
|
command: 'list',
|
|
33
34
|
projectDir: resolveCommandProjectDir(command),
|
|
34
35
|
userId: options.userId,
|
|
36
|
+
...(options.connection !== undefined ? { connectionId: options.connection } : {}),
|
|
35
37
|
output: options.output,
|
|
36
38
|
json: options.json,
|
|
37
39
|
cliVersion: context.packageInfo.version,
|
|
@@ -43,6 +45,7 @@ export function registerWikiCommands(program, context) {
|
|
|
43
45
|
projectDir: resolveCommandProjectDir(command),
|
|
44
46
|
query: query.join(' '),
|
|
45
47
|
userId: options.userId,
|
|
48
|
+
...(options.connection !== undefined ? { connectionId: options.connection } : {}),
|
|
46
49
|
output: options.output,
|
|
47
50
|
json: options.json,
|
|
48
51
|
...(isDebugEnabled(command) ? { debug: true } : {}),
|
|
@@ -42,7 +42,8 @@ function sourceType(value) {
|
|
|
42
42
|
value === 'metabase' ||
|
|
43
43
|
value === 'looker' ||
|
|
44
44
|
value === 'lookml' ||
|
|
45
|
-
value === 'notion'
|
|
45
|
+
value === 'notion' ||
|
|
46
|
+
value === 'gdrive') {
|
|
46
47
|
return value;
|
|
47
48
|
}
|
|
48
49
|
throw new InvalidArgumentError(`invalid choice '${value}'`);
|
|
@@ -121,6 +122,9 @@ function shouldShowSetupEntryMenu(options, command) {
|
|
|
121
122
|
'sourceTarget',
|
|
122
123
|
'metabaseDatabaseId',
|
|
123
124
|
'notionCrawlMode',
|
|
125
|
+
'gdriveServiceAccountKeyRef',
|
|
126
|
+
'gdriveFolderId',
|
|
127
|
+
'gdriveRecursive',
|
|
124
128
|
'skipSources',
|
|
125
129
|
].some((optionName) => optionWasSpecified(command, optionName));
|
|
126
130
|
}
|
|
@@ -213,6 +217,10 @@ export function registerSetupCommands(program, context) {
|
|
|
213
217
|
.argParser((value, previous) => [...previous, value])
|
|
214
218
|
.default([])
|
|
215
219
|
.hideHelp())
|
|
220
|
+
.addOption(new Option('--gdrive-service-account-key-ref <ref>', 'file: reference to a Google service account JSON key')
|
|
221
|
+
.hideHelp())
|
|
222
|
+
.addOption(new Option('--gdrive-folder-id <id>', 'Google Drive folder id to ingest').hideHelp())
|
|
223
|
+
.addOption(new Option('--gdrive-recursive', 'Recursively traverse Google Drive subfolders').hideHelp().default(false))
|
|
216
224
|
.addOption(new Option('--skip-sources', 'Mark optional source setup complete with no sources').hideHelp().default(false))
|
|
217
225
|
.showHelpAfterError();
|
|
218
226
|
setup.hook('preAction', (_thisCommand, actionCommand) => {
|
|
@@ -349,6 +357,11 @@ export function registerSetupCommands(program, context) {
|
|
|
349
357
|
...(options.metabaseDatabaseId !== undefined ? { metabaseDatabaseId: options.metabaseDatabaseId } : {}),
|
|
350
358
|
...(options.notionCrawlMode ? { notionCrawlMode: options.notionCrawlMode } : {}),
|
|
351
359
|
...(options.notionRootPageId.length > 0 ? { notionRootPageIds: options.notionRootPageId } : {}),
|
|
360
|
+
...(options.gdriveServiceAccountKeyRef
|
|
361
|
+
? { gdriveServiceAccountKeyRef: options.gdriveServiceAccountKeyRef }
|
|
362
|
+
: {}),
|
|
363
|
+
...(options.gdriveFolderId ? { gdriveFolderId: options.gdriveFolderId } : {}),
|
|
364
|
+
...(options.gdriveRecursive ? { gdriveRecursive: true } : {}),
|
|
352
365
|
runInitialSourceIngest: false,
|
|
353
366
|
skipSources: options.skipSources === true,
|
|
354
367
|
showEntryMenu: shouldShowSetupEntryMenu(options, command),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { KtxProjectConnectionConfig } from './context/project/config.js';
|
|
2
|
+
/** @internal Canonical SQL-warehouse driver ids; the dialect-notes coverage test derives its required coverage from this set. */
|
|
3
|
+
export declare const KTX_DATABASE_DRIVER_IDS: readonly ["sqlite", "postgres", "mysql", "clickhouse", "sqlserver", "bigquery", "snowflake"];
|
|
2
4
|
export declare function normalizeConnectionDriver(connection: KtxProjectConnectionConfig): string;
|
|
3
5
|
export declare function isDatabaseDriver(driver: string): boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** @internal Canonical SQL-warehouse driver ids; the dialect-notes coverage test derives its required coverage from this set. */
|
|
2
|
+
export const KTX_DATABASE_DRIVER_IDS = [
|
|
2
3
|
'sqlite',
|
|
3
4
|
'postgres',
|
|
4
5
|
'mysql',
|
|
@@ -6,12 +7,15 @@ const KTX_DATABASE_DRIVER_IDS = new Set([
|
|
|
6
7
|
'sqlserver',
|
|
7
8
|
'bigquery',
|
|
8
9
|
'snowflake',
|
|
9
|
-
]
|
|
10
|
+
];
|
|
11
|
+
// mongodb is a database driver but has no SQL dialect, so it sits outside the
|
|
12
|
+
// dialect-notes coverage set above.
|
|
13
|
+
const databaseDriverIds = new Set([...KTX_DATABASE_DRIVER_IDS, 'mongodb']);
|
|
10
14
|
export function normalizeConnectionDriver(connection) {
|
|
11
15
|
return String(connection.driver ?? '')
|
|
12
16
|
.trim()
|
|
13
17
|
.toLowerCase();
|
|
14
18
|
}
|
|
15
19
|
export function isDatabaseDriver(driver) {
|
|
16
|
-
return
|
|
20
|
+
return databaseDriverIds.has(driver.trim().toLowerCase());
|
|
17
21
|
}
|
package/dist/connection.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { LookerClient } from './context/ingest/adapters/looker/client.js';
|
|
2
2
|
import type { MetabaseRuntimeClient } from './context/ingest/adapters/metabase/client-port.js';
|
|
3
3
|
import { NotionClient } from './context/ingest/adapters/notion/notion-client.js';
|
|
4
|
+
import { createGoogleDocsClients } from './context/ingest/adapters/gdrive/gdrive-client.js';
|
|
4
5
|
import { testRepoConnection } from './context/ingest/repo-fetch.js';
|
|
5
6
|
import { type KtxLocalProject } from './context/project/project.js';
|
|
6
7
|
import type { KtxCliIo } from './index.js';
|
|
@@ -19,12 +20,14 @@ export type KtxConnectionArgs = {
|
|
|
19
20
|
type MetabaseTestPort = Pick<MetabaseRuntimeClient, 'testConnection' | 'getDatabases' | 'cleanup'>;
|
|
20
21
|
type LookerTestPort = Pick<LookerClient, 'testConnection'>;
|
|
21
22
|
type NotionTestPort = Pick<NotionClient, 'retrieveBotUser'>;
|
|
23
|
+
type GdriveTestPort = Pick<ReturnType<typeof createGoogleDocsClients>['drive'], 'listFiles' | 'getFile'>;
|
|
22
24
|
type TestRepoConnection = typeof testRepoConnection;
|
|
23
25
|
export interface KtxConnectionDeps {
|
|
24
26
|
createScanConnector?: typeof createKtxCliScanConnector;
|
|
25
27
|
createMetabaseClient?: (project: KtxLocalProject, connectionId: string) => Promise<MetabaseTestPort>;
|
|
26
28
|
createLookerClient?: (project: KtxLocalProject, connectionId: string) => Promise<LookerTestPort>;
|
|
27
29
|
createNotionClient?: (project: KtxLocalProject, connectionId: string) => Promise<NotionTestPort>;
|
|
30
|
+
createGdriveClient?: (project: KtxLocalProject, connectionId: string) => Promise<GdriveTestPort>;
|
|
28
31
|
testRepoConnection?: TestRepoConnection;
|
|
29
32
|
}
|
|
30
33
|
export declare function runKtxConnection(args: KtxConnectionArgs, io?: KtxCliIo, deps?: KtxConnectionDeps): Promise<number>;
|
package/dist/connection.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { DEFAULT_METABASE_CLIENT_CONFIG, DefaultMetabaseConnectionClientFactory } from './context/ingest/adapters/metabase/client.js';
|
|
2
2
|
import { DefaultLookerConnectionClientFactory } from './context/ingest/adapters/looker/factory.js';
|
|
3
3
|
import { NotionClient } from './context/ingest/adapters/notion/notion-client.js';
|
|
4
|
+
import { parseGdriveConnectionConfig, resolveGdriveServiceAccountKey } from './context/connections/gdrive-config.js';
|
|
4
5
|
import { createLocalLookerCredentialResolver } from './context/ingest/adapters/looker/local-looker.adapter.js';
|
|
5
6
|
import { metabaseRuntimeConfigFromLocalConnection } from './context/ingest/adapters/metabase/local-metabase.adapter.js';
|
|
7
|
+
import { createGoogleDocsClients, verifyGdriveFolderAndCountDocs } from './context/ingest/adapters/gdrive/gdrive-client.js';
|
|
8
|
+
import { gdriveServiceAccountKeySchema } from './context/ingest/adapters/gdrive/types.js';
|
|
6
9
|
import { testRepoConnection } from './context/ingest/repo-fetch.js';
|
|
7
10
|
import { federatedConnectionListing } from './context/connections/federation.js';
|
|
8
11
|
import { getDriverRegistration } from './context/connections/drivers.js';
|
|
@@ -28,6 +31,7 @@ const SUPPORTED_TEST_DRIVERS = [
|
|
|
28
31
|
'metabase',
|
|
29
32
|
'looker',
|
|
30
33
|
'notion',
|
|
34
|
+
'gdrive',
|
|
31
35
|
'dbt',
|
|
32
36
|
'metricflow',
|
|
33
37
|
'lookml',
|
|
@@ -120,6 +124,25 @@ async function testNotionConnection(project, connectionId, createClient) {
|
|
|
120
124
|
const bot = await client.retrieveBotUser();
|
|
121
125
|
return { bot: describeNotionBot(bot) };
|
|
122
126
|
}
|
|
127
|
+
async function createDefaultGdriveClient(project, connectionId) {
|
|
128
|
+
const connection = project.config.connections[connectionId];
|
|
129
|
+
if (!connection) {
|
|
130
|
+
throw new Error(`Connection "${connectionId}" is not configured in ktx.yaml`);
|
|
131
|
+
}
|
|
132
|
+
const parsed = parseGdriveConnectionConfig(connection);
|
|
133
|
+
const keyText = await resolveGdriveServiceAccountKey(parsed.service_account_key_ref);
|
|
134
|
+
const key = gdriveServiceAccountKeySchema.parse(JSON.parse(keyText));
|
|
135
|
+
return createGoogleDocsClients(key).drive;
|
|
136
|
+
}
|
|
137
|
+
async function testGdriveConnection(project, connectionId, createClient) {
|
|
138
|
+
const connection = project.config.connections[connectionId];
|
|
139
|
+
if (!connection) {
|
|
140
|
+
throw new Error(`Connection "${connectionId}" is not configured in ktx.yaml`);
|
|
141
|
+
}
|
|
142
|
+
const parsed = parseGdriveConnectionConfig(connection);
|
|
143
|
+
const client = await createClient(project, connectionId);
|
|
144
|
+
return { docs: await verifyGdriveFolderAndCountDocs(client, parsed.folder_id) };
|
|
145
|
+
}
|
|
123
146
|
function extractGitConnectionFields(project, connectionId, driver) {
|
|
124
147
|
const connection = project.config.connections[connectionId];
|
|
125
148
|
if (!connection) {
|
|
@@ -164,6 +187,10 @@ async function testConnectionByDriver(project, connectionId, deps) {
|
|
|
164
187
|
const result = await testNotionConnection(project, connectionId, deps.createNotionClient ?? createDefaultNotionClient);
|
|
165
188
|
return { driver, detailKey: 'Bot', detailValue: result.bot };
|
|
166
189
|
}
|
|
190
|
+
if (driver === 'gdrive') {
|
|
191
|
+
const result = await testGdriveConnection(project, connectionId, deps.createGdriveClient ?? createDefaultGdriveClient);
|
|
192
|
+
return { driver, detailKey: 'Docs', detailValue: String(result.docs) };
|
|
193
|
+
}
|
|
167
194
|
if (driver === 'dbt' || driver === 'metricflow' || driver === 'lookml') {
|
|
168
195
|
const result = await testGitRepoConnection(project, connectionId, driver, deps.testRepoConnection ?? testRepoConnection);
|
|
169
196
|
return { driver, detailKey: 'Repo', detailValue: result.repoUrl };
|
|
@@ -7,13 +7,23 @@ export interface KtxBigQueryConnectionConfig {
|
|
|
7
7
|
credentials_json?: string;
|
|
8
8
|
location?: string;
|
|
9
9
|
max_bytes_billed?: number | string;
|
|
10
|
-
|
|
10
|
+
query_timeout_ms?: number;
|
|
11
11
|
[key: string]: unknown;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* A dataset to introspect, paired with the project that hosts it. `project`
|
|
15
|
+
* defaults to the billing project (`credentials.project_id`) when an entry has
|
|
16
|
+
* no `project.` prefix; a fully-qualified `project.dataset` entry resolves to
|
|
17
|
+
* its own host project. Jobs always bill in `credentials.project_id`.
|
|
18
|
+
*/
|
|
19
|
+
export interface BigQueryDatasetRef {
|
|
20
|
+
project: string;
|
|
21
|
+
dataset: string;
|
|
22
|
+
}
|
|
13
23
|
export interface KtxBigQueryResolvedConnectionConfig {
|
|
14
24
|
projectId: string;
|
|
15
25
|
credentials: Record<string, unknown>;
|
|
16
|
-
datasetIds:
|
|
26
|
+
datasetIds: BigQueryDatasetRef[];
|
|
17
27
|
location?: string;
|
|
18
28
|
}
|
|
19
29
|
export interface KtxBigQueryReadOnlyQueryInput extends KtxReadOnlyQueryInput {
|
|
@@ -72,7 +82,7 @@ export interface KtxBigQueryClient {
|
|
|
72
82
|
}): Promise<[Array<{
|
|
73
83
|
id?: string;
|
|
74
84
|
}>, ...unknown[]]>;
|
|
75
|
-
dataset(datasetId: string): KtxBigQueryDataset;
|
|
85
|
+
dataset(datasetId: string, projectId: string): KtxBigQueryDataset;
|
|
76
86
|
createQueryJob(input: {
|
|
77
87
|
query: string;
|
|
78
88
|
location?: string;
|
|
@@ -94,7 +104,6 @@ export interface KtxBigQueryScanConnectorOptions {
|
|
|
94
104
|
env?: NodeJS.ProcessEnv;
|
|
95
105
|
now?: () => Date;
|
|
96
106
|
maxBytesBilled?: number | string;
|
|
97
|
-
queryTimeoutMs?: number;
|
|
98
107
|
}
|
|
99
108
|
/** @internal */
|
|
100
109
|
export declare function prepareBigQueryReadOnlyQuery(sql: string, params?: Record<string, unknown>): {
|
|
@@ -117,7 +126,7 @@ export declare class KtxBigQueryScanConnector implements KtxScanConnector {
|
|
|
117
126
|
private readonly clientFactory;
|
|
118
127
|
private readonly now;
|
|
119
128
|
private readonly maxBytesBilled?;
|
|
120
|
-
private readonly
|
|
129
|
+
private readonly deadlineMs;
|
|
121
130
|
private readonly dialect;
|
|
122
131
|
private client;
|
|
123
132
|
constructor(options: KtxBigQueryScanConnectorOptions);
|
|
@@ -130,14 +139,16 @@ export declare class KtxBigQueryScanConnector implements KtxScanConnector {
|
|
|
130
139
|
columnStats(_input: KtxColumnStatsInput, _ctx: KtxScanContext): Promise<KtxColumnStatsResult | null>;
|
|
131
140
|
executeReadOnly(input: KtxBigQueryReadOnlyQueryInput, _ctx: KtxScanContext): Promise<KtxQueryResult>;
|
|
132
141
|
getColumnDistinctValues(table: KtxTableRef, columnName: string, options: KtxBigQueryColumnDistinctValuesOptions): Promise<KtxBigQueryColumnDistinctValuesResult | null>;
|
|
133
|
-
getTableRowCount(tableName: string,
|
|
142
|
+
getTableRowCount(tableName: string, ref?: BigQueryDatasetRef | undefined): Promise<number>;
|
|
134
143
|
qTableName(table: Pick<KtxTableRef, 'name'> & Partial<Pick<KtxTableRef, 'catalog' | 'db'>>): string;
|
|
135
144
|
quoteIdentifier(identifier: string): string;
|
|
136
145
|
listSchemas(): Promise<string[]>;
|
|
137
146
|
listTables(datasetIds?: string[]): Promise<KtxTableListEntry[]>;
|
|
147
|
+
private listTablesInProject;
|
|
138
148
|
cleanup(): Promise<void>;
|
|
139
149
|
private getClient;
|
|
140
150
|
private requireDatasetIdsForScan;
|
|
151
|
+
private qualifiedDatasetLabel;
|
|
141
152
|
private query;
|
|
142
153
|
private queryRaw;
|
|
143
154
|
private singleNumber;
|