@kaelio/ktx 0.8.0 → 0.9.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.8.0-py3-none-any.whl → kaelio_ktx-0.9.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli-runtime.js +50 -3
- package/dist/commands/setup-commands.js +1 -1
- package/dist/connection-recovery.d.ts +34 -0
- package/dist/connection-recovery.js +82 -0
- package/dist/connection.js +3 -1
- package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.js +71 -20
- package/dist/context/ingest/adapters/historic-sql/chunk-unified.js +2 -1
- package/dist/context/ingest/adapters/historic-sql/connection-dialect.d.ts +9 -0
- package/dist/context/ingest/adapters/historic-sql/connection-dialect.js +15 -4
- package/dist/context/ingest/adapters/historic-sql/pattern-inputs.js +8 -2
- package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.d.ts +29 -0
- package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.js +190 -0
- package/dist/context/ingest/adapters/historic-sql/scope-floor.d.ts +18 -0
- package/dist/context/ingest/adapters/historic-sql/scope-floor.js +229 -0
- package/dist/context/ingest/adapters/historic-sql/scope-membership.d.ts +8 -0
- package/dist/context/ingest/adapters/historic-sql/scope-membership.js +29 -0
- package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.js +68 -19
- package/dist/context/ingest/adapters/historic-sql/stage-unified.js +57 -50
- package/dist/context/ingest/adapters/historic-sql/types.d.ts +36 -3
- package/dist/context/ingest/adapters/historic-sql/types.js +14 -2
- package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.d.ts +1 -1
- package/dist/context/ingest/isolated-diff/patch-integrator.js +75 -5
- package/dist/context/ingest/local-adapters.js +21 -4
- package/dist/context/ingest/local-bundle-runtime.js +3 -2
- package/dist/context/llm/codex-exec-events.d.ts +20 -0
- package/dist/context/llm/codex-exec-events.js +155 -0
- package/dist/context/llm/codex-isolation.d.ts +3 -0
- package/dist/context/llm/codex-isolation.js +5 -0
- package/dist/context/llm/codex-mcp-runtime-server.d.ts +24 -0
- package/dist/context/llm/codex-mcp-runtime-server.js +51 -0
- package/dist/context/llm/codex-models.d.ts +2 -0
- package/dist/context/llm/codex-models.js +17 -0
- package/dist/context/llm/codex-runtime-config.d.ts +16 -0
- package/dist/context/llm/codex-runtime-config.js +19 -0
- package/dist/context/llm/codex-runtime.d.ts +37 -0
- package/dist/context/llm/codex-runtime.js +304 -0
- package/dist/context/llm/codex-sdk-runner.d.ts +21 -0
- package/dist/context/llm/codex-sdk-runner.js +63 -0
- package/dist/context/llm/local-config.d.ts +2 -0
- package/dist/context/llm/local-config.js +12 -1
- package/dist/context/project/config.d.ts +2 -0
- package/dist/context/project/config.js +2 -2
- package/dist/context/sql-analysis/http-sql-analysis-port.js +32 -2
- package/dist/context/sql-analysis/ports.d.ts +12 -2
- package/dist/context/tools/context-candidate-mark.tool.d.ts +2 -2
- package/dist/context-build-view.js +4 -32
- package/dist/io/buffered-command-io.d.ts +11 -0
- package/dist/io/buffered-command-io.js +28 -0
- package/dist/llm/types.d.ts +1 -1
- package/dist/local-adapters.d.ts +10 -2
- package/dist/local-adapters.js +19 -3
- package/dist/next-steps.js +1 -2
- package/dist/progress-port-adapter.d.ts +6 -0
- package/dist/progress-port-adapter.js +18 -0
- package/dist/public-ingest.d.ts +20 -1
- package/dist/public-ingest.js +178 -27
- package/dist/scan.js +3 -1
- package/dist/setup-context.d.ts +2 -0
- package/dist/setup-context.js +133 -27
- package/dist/setup-databases.d.ts +17 -1
- package/dist/setup-databases.js +358 -249
- package/dist/setup-models.d.ts +10 -1
- package/dist/setup-models.js +90 -2
- package/dist/setup-ready-menu.d.ts +16 -2
- package/dist/setup-ready-menu.js +37 -5
- package/dist/setup-sources.js +108 -28
- package/dist/setup.js +22 -10
- package/dist/status-project.d.ts +11 -0
- package/dist/status-project.js +50 -1
- package/dist/telemetry/command-hook.d.ts +1 -0
- package/dist/telemetry/command-hook.js +3 -1
- package/dist/telemetry/events.d.ts +11 -6
- package/dist/telemetry/events.js +10 -2
- package/dist/telemetry/identity.d.ts +0 -1
- package/dist/telemetry/identity.js +6 -6
- package/dist/telemetry/index.d.ts +12 -0
- package/dist/telemetry/index.js +13 -2
- package/dist/telemetry/scrubber.d.ts +10 -0
- package/dist/telemetry/scrubber.js +20 -0
- package/package.json +5 -4
package/dist/setup-context.js
CHANGED
|
@@ -5,7 +5,10 @@ import { loadKtxProject } from './context/project/project.js';
|
|
|
5
5
|
import { markKtxSetupStateStepComplete, readKtxSetupState } from './context/project/setup-config.js';
|
|
6
6
|
import { serializeKtxProjectConfig } from './context/project/config.js';
|
|
7
7
|
import { errorMessage, writePrefixedLines } from './clack.js';
|
|
8
|
+
import { formatErrorDetail } from './telemetry/scrubber.js';
|
|
8
9
|
import { buildPublicIngestPlan } from './public-ingest.js';
|
|
10
|
+
import { runKtxConnection } from './connection.js';
|
|
11
|
+
import { createBufferedCommandIo } from './io/buffered-command-io.js';
|
|
9
12
|
import { runContextBuild, } from './context-build-view.js';
|
|
10
13
|
import { createKtxSetupPromptAdapter, } from './setup-prompts.js';
|
|
11
14
|
const SETUP_CONTEXT_STATE_PATH = ['.ktx', 'setup', 'context-build.json'];
|
|
@@ -169,6 +172,98 @@ function listContextTargets(project) {
|
|
|
169
172
|
.map((target) => target.connectionId),
|
|
170
173
|
};
|
|
171
174
|
}
|
|
175
|
+
function requiredConnectionIds(targets) {
|
|
176
|
+
return [...targets.primarySourceConnectionIds, ...targets.contextSourceConnectionIds];
|
|
177
|
+
}
|
|
178
|
+
function connectorTypeLabel(project, connectionId) {
|
|
179
|
+
const driver = String(project.config.connections[connectionId]?.driver ?? '')
|
|
180
|
+
.trim()
|
|
181
|
+
.toLowerCase();
|
|
182
|
+
return driver.length > 0 ? driver : 'unknown';
|
|
183
|
+
}
|
|
184
|
+
async function defaultGateTestConnection(projectDir, connectionId, io) {
|
|
185
|
+
return await runKtxConnection({ command: 'test', projectDir, connectionId }, io);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Runs a live connection test for every connection the build depends on. Each
|
|
189
|
+
* test's output is captured in a buffer and discarded so raw error text never
|
|
190
|
+
* reaches the user — callers surface only the connection id and connector type.
|
|
191
|
+
*/
|
|
192
|
+
async function testRequiredConnections(projectDir, project, targets, testConnection) {
|
|
193
|
+
const failures = [];
|
|
194
|
+
for (const connectionId of requiredConnectionIds(targets)) {
|
|
195
|
+
const buffered = createBufferedCommandIo();
|
|
196
|
+
const exitCode = await testConnection(projectDir, connectionId, buffered);
|
|
197
|
+
if (exitCode !== 0) {
|
|
198
|
+
failures.push({ connectionId, driver: connectorTypeLabel(project, connectionId) });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return failures.length === 0 ? { ok: true } : { ok: false, failures };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Loads the project and resolves the connections the build depends on, applying
|
|
205
|
+
* the empty-targets and preflight-capability checks. Used both on first entry
|
|
206
|
+
* and on interactive retry so a fix that adds, removes, or reconfigures a
|
|
207
|
+
* connection is honored.
|
|
208
|
+
*/
|
|
209
|
+
async function prepareBuildTargets(args, io) {
|
|
210
|
+
const project = await loadKtxProject({ projectDir: args.projectDir });
|
|
211
|
+
const targets = listContextTargets(project);
|
|
212
|
+
if (targets.primarySourceConnectionIds.length === 0 && targets.contextSourceConnectionIds.length === 0) {
|
|
213
|
+
if (args.allowEmpty === true) {
|
|
214
|
+
return { kind: 'result', result: { status: 'skipped', projectDir: args.projectDir } };
|
|
215
|
+
}
|
|
216
|
+
io.stderr.write('No databases or context sources are configured for a KTX context build.\n');
|
|
217
|
+
return { kind: 'result', result: { status: 'failed', projectDir: args.projectDir } };
|
|
218
|
+
}
|
|
219
|
+
const preflightPlan = buildPublicIngestPlan(project, { projectDir: project.projectDir, all: true });
|
|
220
|
+
const preflightFailures = preflightPlan.targets.flatMap((target) => target.preflightFailure ? [`${target.connectionId}: ${target.preflightFailure}`] : []);
|
|
221
|
+
if (preflightFailures.length > 0) {
|
|
222
|
+
if (args.allowEmpty === true) {
|
|
223
|
+
return { kind: 'result', result: { status: 'skipped', projectDir: args.projectDir } };
|
|
224
|
+
}
|
|
225
|
+
writeMissingCapabilities(preflightFailures, io);
|
|
226
|
+
return { kind: 'result', result: { status: 'missing-input', projectDir: args.projectDir } };
|
|
227
|
+
}
|
|
228
|
+
return { kind: 'ready', project, targets };
|
|
229
|
+
}
|
|
230
|
+
function writeConnectionGateFailureLines(io, projectDir, failures) {
|
|
231
|
+
io.stderr.write('KTX cannot build context: a required connection failed its live test.\n\n');
|
|
232
|
+
io.stderr.write('Failed connections:\n');
|
|
233
|
+
for (const failure of failures) {
|
|
234
|
+
io.stderr.write(` ${failure.connectionId} (${failure.driver})\n`);
|
|
235
|
+
}
|
|
236
|
+
io.stderr.write('\nEach connection must be reachable before KTX builds context.\n');
|
|
237
|
+
io.stderr.write(`Run \`ktx connection test <id> --project-dir ${resolve(projectDir)}\` to see the error, fix the connection, then retry.\n`);
|
|
238
|
+
}
|
|
239
|
+
function connectionGateFailureReason(failures) {
|
|
240
|
+
const names = failures.map((failure) => `${failure.connectionId} (${failure.driver})`).join(', ');
|
|
241
|
+
return `Required connections failed their live test: ${names}.`;
|
|
242
|
+
}
|
|
243
|
+
async function writeConnectionGateFailedState(args, deps, targets, failures) {
|
|
244
|
+
const at = (deps.now ?? (() => new Date()))().toISOString();
|
|
245
|
+
await writeKtxSetupContextState(args.projectDir, {
|
|
246
|
+
status: 'failed',
|
|
247
|
+
startedAt: at,
|
|
248
|
+
updatedAt: at,
|
|
249
|
+
primarySourceConnectionIds: targets.primarySourceConnectionIds,
|
|
250
|
+
contextSourceConnectionIds: targets.contextSourceConnectionIds,
|
|
251
|
+
reportIds: [],
|
|
252
|
+
artifactPaths: [],
|
|
253
|
+
retryableFailedTargets: [],
|
|
254
|
+
commands: contextBuildCommands(args.projectDir),
|
|
255
|
+
failureReason: connectionGateFailureReason(failures),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
async function promptConnectionGateRetry(prompts) {
|
|
259
|
+
return (await prompts.select({
|
|
260
|
+
message: 'Fix the failing connection, then choose how to proceed.',
|
|
261
|
+
options: [
|
|
262
|
+
{ value: 'retry', label: 'Retry connection tests' },
|
|
263
|
+
{ value: 'back', label: 'Back' },
|
|
264
|
+
],
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
172
267
|
async function hasFileWithExtension(root, extensions, options = {}) {
|
|
173
268
|
if (!(await pathExists(root))) {
|
|
174
269
|
return false;
|
|
@@ -303,12 +398,10 @@ function writeMissingCapabilities(missing, io) {
|
|
|
303
398
|
}
|
|
304
399
|
io.stderr.write('\nFix this in setup before building context.\n');
|
|
305
400
|
}
|
|
306
|
-
function writeSkippedContext(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
io.stdout.write(
|
|
310
|
-
io.stdout.write(`Build context:\n ktx setup --project-dir ${resolve(projectDir)}\n\n`);
|
|
311
|
-
io.stdout.write(`Check status:\n ktx status --project-dir ${resolve(projectDir)}\n`);
|
|
401
|
+
function writeSkippedContext(io) {
|
|
402
|
+
// The setup completion screen owns "what to do next" (it points at `ktx ingest`),
|
|
403
|
+
// so keep this to a short acknowledgement rather than a competing command list.
|
|
404
|
+
io.stdout.write('\nLeaving context unbuilt for now.\n');
|
|
312
405
|
}
|
|
313
406
|
function writeSuccess(readiness, targets, io) {
|
|
314
407
|
io.stdout.write('\nKTX context is ready for agents.\n\n');
|
|
@@ -473,7 +566,6 @@ async function completeExistingContext(args, io, deps, targets) {
|
|
|
473
566
|
}
|
|
474
567
|
export async function runKtxSetupContextStep(args, io, deps = {}) {
|
|
475
568
|
try {
|
|
476
|
-
const project = await loadKtxProject({ projectDir: args.projectDir });
|
|
477
569
|
const prompts = deps.prompts ?? createPromptAdapter();
|
|
478
570
|
const existingState = await readKtxSetupContextState(args.projectDir);
|
|
479
571
|
const completedSteps = (await readKtxSetupState(args.projectDir)).completed_steps;
|
|
@@ -487,43 +579,57 @@ export async function runKtxSetupContextStep(args, io, deps = {}) {
|
|
|
487
579
|
if (existingState.status === 'stale') {
|
|
488
580
|
io.stdout.write('Previous context build state is stale; starting a fresh foreground build.\n');
|
|
489
581
|
}
|
|
490
|
-
const
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
return { status: 'skipped', projectDir: args.projectDir };
|
|
494
|
-
}
|
|
495
|
-
io.stderr.write('No databases or context sources are configured for a KTX context build.\n');
|
|
496
|
-
return { status: 'failed', projectDir: args.projectDir };
|
|
497
|
-
}
|
|
498
|
-
const preflightPlan = buildPublicIngestPlan(project, { projectDir: project.projectDir, all: true });
|
|
499
|
-
const preflightFailures = preflightPlan.targets.flatMap((target) => target.preflightFailure ? [`${target.connectionId}: ${target.preflightFailure}`] : []);
|
|
500
|
-
if (preflightFailures.length > 0) {
|
|
501
|
-
if (args.allowEmpty === true) {
|
|
502
|
-
return { status: 'skipped', projectDir: args.projectDir };
|
|
503
|
-
}
|
|
504
|
-
writeMissingCapabilities(preflightFailures, io);
|
|
505
|
-
return { status: 'missing-input', projectDir: args.projectDir };
|
|
582
|
+
const prepared = await prepareBuildTargets(args, io);
|
|
583
|
+
if (prepared.kind === 'result') {
|
|
584
|
+
return prepared.result;
|
|
506
585
|
}
|
|
586
|
+
let { project, targets } = prepared;
|
|
587
|
+
const interactive = args.inputMode !== 'disabled' && args.prompt !== false;
|
|
507
588
|
if (args.forcePrompt !== true && args.prompt !== false && deps.verifyContextReady === undefined) {
|
|
508
589
|
const existingContextResult = await completeExistingContext(args, io, deps, targets);
|
|
509
590
|
if (existingContextResult) {
|
|
510
591
|
return existingContextResult;
|
|
511
592
|
}
|
|
512
593
|
}
|
|
513
|
-
if (
|
|
594
|
+
if (interactive) {
|
|
514
595
|
const choice = await promptForBuild(prompts);
|
|
515
596
|
if (choice === 'back') {
|
|
516
597
|
return { status: 'back', projectDir: args.projectDir };
|
|
517
598
|
}
|
|
518
599
|
if (choice === 'skip') {
|
|
519
|
-
writeSkippedContext(
|
|
600
|
+
writeSkippedContext(io);
|
|
520
601
|
return { status: 'skipped', projectDir: args.projectDir };
|
|
521
602
|
}
|
|
522
603
|
}
|
|
523
|
-
|
|
604
|
+
// Live-connection gate: every connection the build depends on must pass a
|
|
605
|
+
// live test before the (expensive) build starts. A red connection is a hard
|
|
606
|
+
// stop — we surface only the connection id and connector type, never raw
|
|
607
|
+
// error text.
|
|
608
|
+
const testConnection = deps.testConnection ?? defaultGateTestConnection;
|
|
609
|
+
while (true) {
|
|
610
|
+
const gate = await testRequiredConnections(args.projectDir, project, targets, testConnection);
|
|
611
|
+
if (gate.ok) {
|
|
612
|
+
return await runBuild(args, io, deps, project, targets);
|
|
613
|
+
}
|
|
614
|
+
writeConnectionGateFailureLines(io, args.projectDir, gate.failures);
|
|
615
|
+
if (!interactive) {
|
|
616
|
+
await writeConnectionGateFailedState(args, deps, targets, gate.failures);
|
|
617
|
+
return { status: 'failed', projectDir: args.projectDir };
|
|
618
|
+
}
|
|
619
|
+
const choice = await promptConnectionGateRetry(prompts);
|
|
620
|
+
if (choice === 'back') {
|
|
621
|
+
return { status: 'back', projectDir: args.projectDir };
|
|
622
|
+
}
|
|
623
|
+
const reprepared = await prepareBuildTargets(args, io);
|
|
624
|
+
if (reprepared.kind === 'result') {
|
|
625
|
+
return reprepared.result;
|
|
626
|
+
}
|
|
627
|
+
project = reprepared.project;
|
|
628
|
+
targets = reprepared.targets;
|
|
629
|
+
}
|
|
524
630
|
}
|
|
525
631
|
catch (error) {
|
|
526
632
|
writePrefixedLines((chunk) => io.stderr.write(chunk), errorMessage(error));
|
|
527
|
-
return { status: 'failed', projectDir: args.projectDir };
|
|
633
|
+
return { status: 'failed', projectDir: args.projectDir, errorDetail: formatErrorDetail(error) };
|
|
528
634
|
}
|
|
529
635
|
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import type { KtxLlmRuntimePort } from './context/llm/runtime-port.js';
|
|
2
|
+
import { type ProposeQueryHistoryServiceAccountFiltersInput, type QueryHistoryFilterProposal } from './context/ingest/adapters/historic-sql/query-history-filter-picker.js';
|
|
1
3
|
import { type HistoricSqlReadinessProbe } from './context/ingest/historic-sql-probes.js';
|
|
4
|
+
import { loadKtxProject } from './context/project/project.js';
|
|
2
5
|
import type { KtxTableListEntry } from './context/scan/types.js';
|
|
3
|
-
import type
|
|
6
|
+
import { type KtxCliIo } from './cli-runtime.js';
|
|
4
7
|
import { type DatabaseScopePickResult, type PickDatabaseScopeArgs } from './database-tree-picker.js';
|
|
8
|
+
import type { KtxManagedPythonInstallPolicy } from './managed-python-command.js';
|
|
9
|
+
import type { ManagedPythonCoreDaemonOptions } from './managed-python-http.js';
|
|
5
10
|
import { type KtxSetupPromptOption } from './setup-prompts.js';
|
|
6
11
|
export type KtxSetupDatabaseDriver = 'sqlite' | 'postgres' | 'mysql' | 'clickhouse' | 'sqlserver' | 'bigquery' | 'snowflake';
|
|
7
12
|
export interface KtxSetupDatabasesArgs {
|
|
8
13
|
projectDir: string;
|
|
9
14
|
inputMode: 'auto' | 'disabled';
|
|
15
|
+
yes?: boolean;
|
|
16
|
+
cliVersion?: string;
|
|
17
|
+
runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
|
|
10
18
|
databaseDrivers?: KtxSetupDatabaseDriver[];
|
|
11
19
|
databaseConnectionIds?: string[];
|
|
12
20
|
databaseConnectionId?: string;
|
|
@@ -77,5 +85,13 @@ export interface KtxSetupDatabasesDeps {
|
|
|
77
85
|
listTables?: (projectDir: string, connectionId: string, schemas?: string[]) => Promise<KtxTableListEntry[]>;
|
|
78
86
|
pickDatabaseScope?: (args: PickDatabaseScopeArgs, io: KtxCliIo) => Promise<DatabaseScopePickResult>;
|
|
79
87
|
historicSqlReadinessProbe?: HistoricSqlReadinessProbe;
|
|
88
|
+
queryHistoryFilterPicker?: (input: ProposeQueryHistoryServiceAccountFiltersInput) => Promise<QueryHistoryFilterProposal>;
|
|
89
|
+
createQueryHistoryLlmRuntime?: (projectDir: string, project: Awaited<ReturnType<typeof loadKtxProject>>) => KtxLlmRuntimePort | null;
|
|
80
90
|
}
|
|
91
|
+
/** @internal */
|
|
92
|
+
export declare function managedDaemonOptionsForSetupQueryHistoryPicker(input: {
|
|
93
|
+
projectDir: string;
|
|
94
|
+
args: Pick<KtxSetupDatabasesArgs, 'cliVersion' | 'runtimeInstallPolicy' | 'inputMode'>;
|
|
95
|
+
io: KtxCliIo;
|
|
96
|
+
}): ManagedPythonCoreDaemonOptions;
|
|
81
97
|
export declare function runKtxSetupDatabasesStep(args: KtxSetupDatabasesArgs, io: KtxCliIo, deps?: KtxSetupDatabasesDeps): Promise<KtxSetupDatabasesResult>;
|