@kaelio/ktx 0.11.0 → 0.12.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.11.0-py3-none-any.whl → kaelio_ktx-0.12.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/admin.js +1 -1
- package/dist/clack.d.ts +16 -0
- package/dist/clack.js +37 -6
- package/dist/claude-code-prompt-caching.js +1 -1
- package/dist/cli-program.js +3 -3
- package/dist/cli-runtime.js +2 -2
- package/dist/commands/connection-commands.js +1 -1
- package/dist/commands/ingest-commands.js +4 -4
- package/dist/commands/mcp-commands.js +12 -12
- package/dist/commands/runtime-commands.js +4 -4
- package/dist/commands/setup-commands.js +6 -5
- package/dist/commands/sl-commands.js +1 -1
- package/dist/commands/sql-commands.js +1 -1
- package/dist/commands/status-commands.js +1 -1
- package/dist/connection.js +1 -1
- package/dist/connectors/clickhouse/connector.js +1 -1
- package/dist/connectors/mysql/connector.js +1 -1
- package/dist/connectors/snowflake/connector.d.ts +1 -1
- package/dist/connectors/sqlite/connector.js +2 -25
- package/dist/connectors/sqlserver/connector.js +3 -3
- package/dist/context/connections/connection-type.d.ts +1 -1
- package/dist/context/connections/read-only-sql.d.ts +1 -0
- package/dist/context/connections/read-only-sql.js +116 -2
- package/dist/context/core/git.service.d.ts +23 -0
- package/dist/context/core/git.service.js +71 -8
- package/dist/context/ingest/adapters/historic-sql/projection.js +2 -1
- package/dist/context/ingest/adapters/looker/client.js +7 -2
- package/dist/context/ingest/adapters/looker/factory.d.ts +8 -1
- package/dist/context/ingest/adapters/looker/factory.js +9 -0
- package/dist/context/ingest/adapters/looker/mapping.js +1 -1
- package/dist/context/ingest/adapters/looker/types.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/client.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/client.js +1 -1
- package/dist/context/ingest/adapters/metabase/local-metabase.adapter.js +1 -1
- package/dist/context/ingest/adapters/metabase/mapping.js +6 -6
- package/dist/context/ingest/artifact-gates.d.ts +2 -6
- package/dist/context/ingest/artifact-gates.js +5 -47
- package/dist/context/ingest/constrained-repair.d.ts +55 -0
- package/dist/context/ingest/constrained-repair.js +167 -0
- package/dist/context/ingest/final-gate-repair.d.ts +9 -11
- package/dist/context/ingest/final-gate-repair.js +40 -128
- package/dist/context/ingest/finalization-scope.d.ts +1 -1
- package/dist/context/ingest/finalization-scope.js +15 -15
- package/dist/context/ingest/ingest-bundle.runner.d.ts +1 -0
- package/dist/context/ingest/ingest-bundle.runner.js +101 -67
- package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +6 -13
- package/dist/context/ingest/isolated-diff/patch-integrator.js +32 -109
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.d.ts +8 -9
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.js +63 -141
- package/dist/context/ingest/local-bundle-runtime.d.ts +2 -0
- package/dist/context/ingest/local-bundle-runtime.js +9 -10
- package/dist/context/ingest/local-ingest.d.ts +2 -0
- package/dist/context/ingest/local-ingest.js +2 -0
- package/dist/context/ingest/memory-flow/view-model.js +1 -1
- package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -6
- package/dist/context/ingest/stages/stage-3-work-units.js +2 -1
- package/dist/context/ingest/stages/validate-wu-sources.d.ts +7 -1
- package/dist/context/ingest/stages/validate-wu-sources.js +109 -4
- package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.d.ts +2 -0
- package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +3 -3
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.d.ts +3 -1
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +15 -1
- package/dist/context/llm/ai-sdk-runtime.js +2 -2
- package/dist/context/llm/claude-code-runtime.js +1 -1
- package/dist/context/llm/local-config.js +1 -1
- package/dist/context/llm/runtime-tools.js +2 -2
- package/dist/context/mcp/context-tools.js +7 -7
- package/dist/context/mcp/local-project-ports.js +23 -54
- package/dist/context/memory/local-memory.js +4 -1
- package/dist/context/memory/memory-agent.service.js +1 -1
- package/dist/context/project/config.d.ts +11 -4
- package/dist/context/project/config.js +85 -30
- package/dist/context/project/driver-schemas.js +1 -1
- package/dist/context/project/mappings-yaml-schema.js +2 -2
- package/dist/context/project/project.js +12 -4
- package/dist/context/scan/description-generation.js +4 -4
- package/dist/context/scan/local-enrichment-artifacts.js +2 -1
- package/dist/context/scan/local-scan.js +2 -2
- package/dist/context/scan/local-structural-artifacts.js +5 -5
- package/dist/context/scan/relationship-benchmark-report.js +1 -1
- package/dist/context/scan/relationship-discovery.js +3 -3
- package/dist/context/scan/relationship-llm-proposal.js +3 -3
- package/dist/context/sl/local-query.js +3 -33
- package/dist/context/sl/local-sl.d.ts +0 -8
- package/dist/context/sl/local-sl.js +44 -69
- package/dist/context/sl/semantic-layer.service.d.ts +25 -8
- package/dist/context/sl/semantic-layer.service.js +109 -56
- package/dist/context/sl/source-files.d.ts +46 -0
- package/dist/context/sl/source-files.js +131 -0
- package/dist/context/sl/tools/base-semantic-layer.tool.d.ts +2 -2
- package/dist/context/sl/tools/base-semantic-layer.tool.js +2 -7
- package/dist/context/sl/tools/sl-edit-source.tool.js +10 -8
- package/dist/context/sl/tools/sl-warehouse-validation.js +55 -27
- package/dist/context/sl/tools/sl-write-source.tool.js +12 -9
- package/dist/context/sql-analysis/dialect.d.ts +2 -0
- package/dist/context/sql-analysis/dialect.js +20 -0
- package/dist/context/tools/base-tool.d.ts +6 -19
- package/dist/context/tools/base-tool.js +0 -14
- package/dist/context-build-view.js +5 -5
- package/dist/database-tree-picker.js +18 -3
- package/dist/demo-assets.js +0 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +31 -23
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +44 -0
- package/dist/ingest.d.ts +1 -1
- package/dist/ingest.js +8 -2
- package/dist/io/symbols.d.ts +2 -0
- package/dist/io/symbols.js +2 -0
- package/dist/io/tty.d.ts +8 -0
- package/dist/io/tty.js +16 -0
- package/dist/llm/embedding-health.js +1 -1
- package/dist/llm/embedding-provider.js +3 -3
- package/dist/llm/model-provider.js +1 -1
- package/dist/local-adapters.d.ts +1 -0
- package/dist/local-adapters.js +2 -2
- package/dist/local-scan-connectors.js +1 -1
- package/dist/managed-local-embeddings.js +17 -8
- package/dist/managed-mcp-daemon.js +3 -3
- package/dist/managed-python-command.d.ts +7 -0
- package/dist/managed-python-command.js +34 -8
- package/dist/managed-python-daemon.js +2 -2
- package/dist/managed-python-http.js +3 -3
- package/dist/managed-python-runtime.d.ts +30 -1
- package/dist/managed-python-runtime.js +134 -18
- package/dist/managed-uv-release.d.ts +7 -0
- package/dist/managed-uv-release.js +11 -0
- package/dist/mcp-http-server.js +4 -4
- package/dist/mcp-server-factory.js +3 -3
- package/dist/mcp-stdio-server.js +1 -1
- package/dist/memory-flow-hud.js +2 -2
- package/dist/next-steps.js +2 -2
- package/dist/prompt-navigation.d.ts +17 -0
- package/dist/prompt-navigation.js +49 -3
- package/dist/prompts/memory_agent_bundle_ingest_work_unit.md +2 -2
- package/dist/prompts/memory_agent_external_ingest.md +2 -2
- package/dist/public-ingest-copy.js +1 -1
- package/dist/public-ingest.js +3 -3
- package/dist/release-version.js +1 -1
- package/dist/runtime-requirements.js +1 -1
- package/dist/runtime.js +9 -9
- package/dist/scan.js +1 -1
- package/dist/setup-agents.js +21 -30
- package/dist/setup-banner.d.ts +20 -0
- package/dist/setup-banner.js +39 -0
- package/dist/setup-context.js +24 -15
- package/dist/setup-databases.js +31 -59
- package/dist/setup-demo-tour.js +12 -8
- package/dist/setup-embeddings.js +9 -9
- package/dist/setup-interrupt.js +1 -1
- package/dist/setup-models.d.ts +4 -1
- package/dist/setup-models.js +54 -28
- package/dist/setup-project.js +29 -5
- package/dist/setup-prompts.js +16 -1
- package/dist/setup-ready-menu.js +1 -1
- package/dist/setup-sources.js +27 -7
- package/dist/setup.js +13 -13
- package/dist/skills/analytics/SKILL.md +3 -3
- package/dist/skills/dbt_ingest/SKILL.md +3 -3
- package/dist/skills/looker_ingest/SKILL.md +3 -3
- package/dist/skills/lookml_ingest/SKILL.md +7 -7
- package/dist/skills/metabase_ingest/SKILL.md +4 -4
- package/dist/skills/metricflow_ingest/SKILL.md +15 -15
- package/dist/skills/notion_synthesize/SKILL.md +1 -1
- package/dist/skills/sl/SKILL.md +3 -3
- package/dist/skills/sl_capture/SKILL.md +1 -1
- package/dist/skills/wiki_capture/SKILL.md +1 -1
- package/dist/source-mapping.js +1 -1
- package/dist/startup-profile.js +1 -1
- package/dist/status-project.d.ts +0 -2
- package/dist/status-project.js +4 -6
- package/dist/telemetry/events.d.ts +1 -1
- package/dist/telemetry/exception.js +14 -0
- package/dist/text-ingest.js +1 -1
- package/dist/tree-picker-tui.d.ts +0 -1
- package/dist/tree-picker-tui.js +2 -3
- package/package.json +1 -1
package/dist/doctor.js
CHANGED
|
@@ -4,6 +4,7 @@ import { access, readFile } from 'node:fs/promises';
|
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
|
+
import { shouldUseColorOutput } from './io/tty.js';
|
|
7
8
|
import { KTX_NEXT_STEP_DIRECT_COMMANDS } from './next-steps.js';
|
|
8
9
|
const execFileAsync = promisify(execFile);
|
|
9
10
|
function workspaceRootDir() {
|
|
@@ -121,12 +122,6 @@ const GROUP_LABEL = {
|
|
|
121
122
|
search: 'Semantic search',
|
|
122
123
|
history: 'Query history',
|
|
123
124
|
};
|
|
124
|
-
function shouldUseColor(io) {
|
|
125
|
-
if (io.stdout.isTTY !== true)
|
|
126
|
-
return false;
|
|
127
|
-
const env = process.env;
|
|
128
|
-
return !env.NO_COLOR && env.TERM !== 'dumb' && !env.CI;
|
|
129
|
-
}
|
|
130
125
|
function styleStatus(useColor, status, text) {
|
|
131
126
|
if (!useColor)
|
|
132
127
|
return text;
|
|
@@ -322,17 +317,20 @@ export function renderInvalidConfigMessage(projectDir, issues, outputMode, io) {
|
|
|
322
317
|
}, null, 2)}\n`);
|
|
323
318
|
return;
|
|
324
319
|
}
|
|
325
|
-
const useColor =
|
|
320
|
+
const useColor = shouldUseColorOutput(io.stdout);
|
|
326
321
|
const dim = (text) => styleDim(useColor, text);
|
|
327
322
|
const bold = (text) => styleBold(useColor, text);
|
|
328
323
|
const status = (s, text) => styleStatus(useColor, s, text);
|
|
329
324
|
const abbreviated = abbreviateHome(projectDir) ?? projectDir;
|
|
325
|
+
const errorCount = issues.filter((issue) => issue.severity === 'error').length;
|
|
326
|
+
const warningCount = issues.length - errorCount;
|
|
330
327
|
const lines = [];
|
|
331
|
-
lines.push(`${bold('
|
|
328
|
+
lines.push(`${bold('ktx status')} ${dim('·')} ${abbreviated}`);
|
|
332
329
|
lines.push('');
|
|
333
|
-
lines.push(` ${status('fail', '✗')} ${bold('Config')} ktx.yaml has ${
|
|
330
|
+
lines.push(` ${status('fail', '✗')} ${bold('Config')} ktx.yaml has ${errorCount} schema issue${errorCount === 1 ? '' : 's'}${warningCount > 0 ? ` · ${warningCount} ignored field${warningCount === 1 ? '' : 's'}` : ''}`);
|
|
334
331
|
for (const issue of issues) {
|
|
335
|
-
|
|
332
|
+
const glyph = issue.severity === 'error' ? status('fail', '✗') : status('warn', '⚠');
|
|
333
|
+
lines.push(` ${glyph} ${issue.message}`);
|
|
336
334
|
if (issue.fix) {
|
|
337
335
|
lines.push(` ${dim(`→ ${issue.fix}`)}`);
|
|
338
336
|
}
|
|
@@ -342,23 +340,35 @@ export function renderInvalidConfigMessage(projectDir, issues, outputMode, io) {
|
|
|
342
340
|
lines.push('');
|
|
343
341
|
io.stdout.write(lines.join('\n'));
|
|
344
342
|
}
|
|
345
|
-
export function renderValidConfigMessage(projectDir, outputMode, io) {
|
|
343
|
+
export function renderValidConfigMessage(projectDir, outputMode, io, warnings = []) {
|
|
346
344
|
if (outputMode === 'json') {
|
|
347
345
|
io.stdout.write(`${JSON.stringify({
|
|
348
346
|
ok: true,
|
|
349
347
|
projectDir,
|
|
348
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
350
349
|
}, null, 2)}\n`);
|
|
351
350
|
return;
|
|
352
351
|
}
|
|
353
|
-
const useColor =
|
|
352
|
+
const useColor = shouldUseColorOutput(io.stdout);
|
|
354
353
|
const dim = (text) => styleDim(useColor, text);
|
|
355
354
|
const bold = (text) => styleBold(useColor, text);
|
|
356
355
|
const status = (s, text) => styleStatus(useColor, s, text);
|
|
357
356
|
const abbreviated = abbreviateHome(projectDir) ?? projectDir;
|
|
358
357
|
const lines = [];
|
|
359
|
-
lines.push(`${bold('
|
|
358
|
+
lines.push(`${bold('ktx status')} ${dim('·')} ${abbreviated}`);
|
|
360
359
|
lines.push('');
|
|
361
|
-
|
|
360
|
+
if (warnings.length > 0) {
|
|
361
|
+
lines.push(` ${status('warn', '⚠')} ${bold('Config')} ktx.yaml schema valid · ${warnings.length} ignored field${warnings.length === 1 ? '' : 's'}`);
|
|
362
|
+
for (const warning of warnings) {
|
|
363
|
+
lines.push(` ${status('warn', '⚠')} ${warning.message}`);
|
|
364
|
+
if (warning.fix) {
|
|
365
|
+
lines.push(` ${dim(`→ ${warning.fix}`)}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
lines.push(` ${status('pass', '✓')} ${bold('Config')} ${dim('ktx.yaml schema valid')}`);
|
|
371
|
+
}
|
|
362
372
|
lines.push('');
|
|
363
373
|
io.stdout.write(lines.join('\n'));
|
|
364
374
|
}
|
|
@@ -371,15 +381,15 @@ export function renderMissingProjectMessage(projectDir, outputMode, io) {
|
|
|
371
381
|
}, null, 2)}\n`);
|
|
372
382
|
return;
|
|
373
383
|
}
|
|
374
|
-
const useColor =
|
|
384
|
+
const useColor = shouldUseColorOutput(io.stdout);
|
|
375
385
|
const dim = (text) => styleDim(useColor, text);
|
|
376
386
|
const bold = (text) => styleBold(useColor, text);
|
|
377
387
|
const abbreviated = abbreviateHome(projectDir) ?? projectDir;
|
|
378
388
|
const envProjectDir = process.env.KTX_PROJECT_DIR;
|
|
379
389
|
const lines = [];
|
|
380
|
-
lines.push(`${bold('
|
|
390
|
+
lines.push(`${bold('ktx status')} ${dim('·')} ${abbreviated}`);
|
|
381
391
|
lines.push('');
|
|
382
|
-
lines.push(` No
|
|
392
|
+
lines.push(` No ktx project here yet. ${dim('(ktx.yaml not found)')}`);
|
|
383
393
|
lines.push('');
|
|
384
394
|
lines.push(` Run ${bold('ktx setup')} to create one.`);
|
|
385
395
|
if (envProjectDir !== undefined) {
|
|
@@ -402,14 +412,13 @@ export async function runKtxDoctor(args, io = process, deps = {}) {
|
|
|
402
412
|
return 1;
|
|
403
413
|
}
|
|
404
414
|
const { validateKtxProjectConfig } = await import('./context/project/config.js');
|
|
405
|
-
;
|
|
406
415
|
const rawConfig = await readFile(configPath, 'utf-8');
|
|
407
416
|
const validation = validateKtxProjectConfig(rawConfig);
|
|
408
417
|
if (!validation.ok) {
|
|
409
418
|
renderInvalidConfigMessage(args.projectDir, validation.issues, args.outputMode, io);
|
|
410
419
|
return 1;
|
|
411
420
|
}
|
|
412
|
-
renderValidConfigMessage(args.projectDir, args.outputMode, io);
|
|
421
|
+
renderValidConfigMessage(args.projectDir, args.outputMode, io, validation.issues);
|
|
413
422
|
return 0;
|
|
414
423
|
}
|
|
415
424
|
if (args.command === 'project') {
|
|
@@ -420,7 +429,6 @@ export async function runKtxDoctor(args, io = process, deps = {}) {
|
|
|
420
429
|
}
|
|
421
430
|
const { loadKtxProject } = await import('./context/project/project.js');
|
|
422
431
|
const { validateKtxProjectConfig } = await import('./context/project/config.js');
|
|
423
|
-
;
|
|
424
432
|
const { buildProjectStatus, renderProjectStatus } = await import('./status-project.js');
|
|
425
433
|
const rawConfig = await readFile(configPath, 'utf-8');
|
|
426
434
|
const validation = validateKtxProjectConfig(rawConfig);
|
|
@@ -445,7 +453,7 @@ export async function runKtxDoctor(args, io = process, deps = {}) {
|
|
|
445
453
|
else {
|
|
446
454
|
io.stdout.write(renderProjectStatus(projectStatus, {
|
|
447
455
|
verbose,
|
|
448
|
-
useColor:
|
|
456
|
+
useColor: shouldUseColorOutput(io.stdout),
|
|
449
457
|
durationMs: Date.now() - startedAt,
|
|
450
458
|
toolchainChecks,
|
|
451
459
|
}));
|
|
@@ -453,10 +461,10 @@ export async function runKtxDoctor(args, io = process, deps = {}) {
|
|
|
453
461
|
return projectStatus.verdict === 'blocked' ? 1 : 0;
|
|
454
462
|
}
|
|
455
463
|
const setupChecks = await runSetupChecks();
|
|
456
|
-
const report = { title: '
|
|
464
|
+
const report = { title: 'ktx status', checks: setupChecks };
|
|
457
465
|
const renderOptions = {
|
|
458
466
|
verbose: args.verbose ?? false,
|
|
459
|
-
useColor:
|
|
467
|
+
useColor: shouldUseColorOutput(io.stdout),
|
|
460
468
|
durationMs: Date.now() - startedAt,
|
|
461
469
|
command: args.command,
|
|
462
470
|
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks an error as an expected operational outcome that ktx surfaces to its
|
|
3
|
+
* caller (a connected agent or the CLI user) rather than an unexpected ktx
|
|
4
|
+
* fault. Examples: invalid agent input, a warehouse rejecting a query, or a
|
|
5
|
+
* validation guard rejecting a request.
|
|
6
|
+
*
|
|
7
|
+
* `reportException` skips PostHog Error Tracking for these so the bug stream
|
|
8
|
+
* stays free of routine, caller-driven failures. The failure is still surfaced
|
|
9
|
+
* to the caller (as a tool-error result or CLI error) and still recorded by the
|
|
10
|
+
* outcome-tagged telemetry events, so no diagnostic signal is lost.
|
|
11
|
+
*/
|
|
12
|
+
export declare class KtxExpectedError extends Error {
|
|
13
|
+
constructor(message: string, options?: ErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A query was rejected at the warehouse/driver boundary — the warehouse refused
|
|
17
|
+
* to compile or run it, or a read-only guard rejected it. Reuses the underlying
|
|
18
|
+
* error's message so the caller still sees the original warehouse diagnostics,
|
|
19
|
+
* and keeps the driver error as `cause`.
|
|
20
|
+
*/
|
|
21
|
+
export declare class KtxQueryError extends KtxExpectedError {
|
|
22
|
+
constructor(message: string, options?: ErrorOptions);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* True for the native JavaScript error types that signal a programming fault — a
|
|
26
|
+
* bug in ktx code rather than an operational outcome. These are universal
|
|
27
|
+
* language invariants (a `TypeError` never means "the warehouse rejected the
|
|
28
|
+
* query"), so callers can use this to keep genuine faults out of the
|
|
29
|
+
* expected-error classification and let them reach Error Tracking unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isNativeProgrammingFault(error: unknown): boolean;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks an error as an expected operational outcome that ktx surfaces to its
|
|
3
|
+
* caller (a connected agent or the CLI user) rather than an unexpected ktx
|
|
4
|
+
* fault. Examples: invalid agent input, a warehouse rejecting a query, or a
|
|
5
|
+
* validation guard rejecting a request.
|
|
6
|
+
*
|
|
7
|
+
* `reportException` skips PostHog Error Tracking for these so the bug stream
|
|
8
|
+
* stays free of routine, caller-driven failures. The failure is still surfaced
|
|
9
|
+
* to the caller (as a tool-error result or CLI error) and still recorded by the
|
|
10
|
+
* outcome-tagged telemetry events, so no diagnostic signal is lost.
|
|
11
|
+
*/
|
|
12
|
+
export class KtxExpectedError extends Error {
|
|
13
|
+
constructor(message, options) {
|
|
14
|
+
super(message, options);
|
|
15
|
+
this.name = 'KtxExpectedError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A query was rejected at the warehouse/driver boundary — the warehouse refused
|
|
20
|
+
* to compile or run it, or a read-only guard rejected it. Reuses the underlying
|
|
21
|
+
* error's message so the caller still sees the original warehouse diagnostics,
|
|
22
|
+
* and keeps the driver error as `cause`.
|
|
23
|
+
*/
|
|
24
|
+
export class KtxQueryError extends KtxExpectedError {
|
|
25
|
+
constructor(message, options) {
|
|
26
|
+
super(message, options);
|
|
27
|
+
this.name = 'KtxQueryError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* True for the native JavaScript error types that signal a programming fault — a
|
|
32
|
+
* bug in ktx code rather than an operational outcome. These are universal
|
|
33
|
+
* language invariants (a `TypeError` never means "the warehouse rejected the
|
|
34
|
+
* query"), so callers can use this to keep genuine faults out of the
|
|
35
|
+
* expected-error classification and let them reach Error Tracking unchanged.
|
|
36
|
+
*/
|
|
37
|
+
export function isNativeProgrammingFault(error) {
|
|
38
|
+
return (error instanceof TypeError ||
|
|
39
|
+
error instanceof RangeError ||
|
|
40
|
+
error instanceof ReferenceError ||
|
|
41
|
+
error instanceof SyntaxError ||
|
|
42
|
+
error instanceof EvalError ||
|
|
43
|
+
error instanceof URIError);
|
|
44
|
+
}
|
package/dist/ingest.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface KtxIngestDeps {
|
|
|
60
60
|
startLiveMemoryFlow?: typeof startLiveMemoryFlowTui;
|
|
61
61
|
abortSignal?: AbortSignal;
|
|
62
62
|
env?: NodeJS.ProcessEnv;
|
|
63
|
-
localIngestOptions?: Pick<RunLocalIngestOptions, 'agentRunner' | 'llmRuntime' | 'memoryModel' | 'semanticLayerCompute' | 'queryExecutor' | 'logger' | 'pullConfigOptions'>;
|
|
63
|
+
localIngestOptions?: Pick<RunLocalIngestOptions, 'agentRunner' | 'llmRuntime' | 'memoryModel' | 'semanticLayerCompute' | 'queryExecutor' | 'sqlAnalysis' | 'logger' | 'pullConfigOptions'>;
|
|
64
64
|
progress?: (update: KtxIngestProgressUpdate) => void;
|
|
65
65
|
runtimeIo?: KtxIngestIo;
|
|
66
66
|
}
|
package/dist/ingest.js
CHANGED
|
@@ -11,7 +11,7 @@ import { resolveProjectEmbeddingProvider } from './embedding-resolution.js';
|
|
|
11
11
|
import { createKtxCliIngestQueryExecutor } from './ingest-query-executor.js';
|
|
12
12
|
import { readIngestReportSnapshotFile } from './ingest-report-file.js';
|
|
13
13
|
import { createCliOperationalLogger } from './io/logger.js';
|
|
14
|
-
import { createKtxCliLocalIngestAdapters } from './local-adapters.js';
|
|
14
|
+
import { createKtxCliLocalIngestAdapters, resolveKtxCliSqlAnalysis } from './local-adapters.js';
|
|
15
15
|
import { renderMemoryFlowInteractively } from './memory-flow-interactive.js';
|
|
16
16
|
import { renderMemoryFlowTui, startLiveMemoryFlowTui, } from './memory-flow-tui.js';
|
|
17
17
|
import { resolveVizFallback, warnVizFallbackOnce } from './viz-fallback.js';
|
|
@@ -525,7 +525,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
525
525
|
const localIngestOptions = deps.localIngestOptions ?? {};
|
|
526
526
|
const managedDaemon = managedDaemonOptionsForIngestRun(args, deps.runtimeIo ?? io);
|
|
527
527
|
const operationalLogger = createCliOperationalLogger(io, args.outputMode);
|
|
528
|
-
const
|
|
528
|
+
const baseAdapterOptions = {
|
|
529
529
|
...(localIngestOptions.pullConfigOptions ?? {}),
|
|
530
530
|
...(args.databaseIntrospectionUrl ? { databaseIntrospectionUrl: args.databaseIntrospectionUrl } : {}),
|
|
531
531
|
...(managedDaemon ? { managedDaemon } : {}),
|
|
@@ -535,6 +535,10 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
535
535
|
: {}),
|
|
536
536
|
logger: operationalLogger,
|
|
537
537
|
};
|
|
538
|
+
// One parser-backed SQL analysis port per run: the historic-sql adapter and
|
|
539
|
+
// the ingest sql_execution tool share the same daemon-backed validator.
|
|
540
|
+
const sqlAnalysis = localIngestOptions.sqlAnalysis ?? resolveKtxCliSqlAnalysis(baseAdapterOptions);
|
|
541
|
+
const adapterOptions = { ...baseAdapterOptions, sqlAnalysis };
|
|
538
542
|
const queryExecutor = localIngestOptions.queryExecutor ??
|
|
539
543
|
(deps.createQueryExecutor ?? createKtxCliIngestQueryExecutor)(ingestProject);
|
|
540
544
|
if (args.adapter === 'metabase' && args.sourceDir) {
|
|
@@ -577,6 +581,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
577
581
|
metabaseConnectionId: args.connectionId,
|
|
578
582
|
...localIngestOptions,
|
|
579
583
|
queryExecutor,
|
|
584
|
+
sqlAnalysis,
|
|
580
585
|
trigger: 'manual_resync',
|
|
581
586
|
jobIdFactory: deps.jobIdFactory,
|
|
582
587
|
embeddingProvider,
|
|
@@ -650,6 +655,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
650
655
|
jobId,
|
|
651
656
|
...localIngestOptions,
|
|
652
657
|
queryExecutor,
|
|
658
|
+
sqlAnalysis,
|
|
653
659
|
pullConfigOptions: adapterOptions,
|
|
654
660
|
embeddingProvider,
|
|
655
661
|
...(args.debugLlmRequestFile ? { llmDebugRequestFile: args.debugLlmRequestFile } : {}),
|
package/dist/io/symbols.d.ts
CHANGED
package/dist/io/symbols.js
CHANGED
|
@@ -9,6 +9,8 @@ function detectUnicodeSupport(env = process.env) {
|
|
|
9
9
|
env.TERM === 'alacritty');
|
|
10
10
|
}
|
|
11
11
|
const unicode = detectUnicodeSupport();
|
|
12
|
+
/** Whether the active terminal renders Unicode glyphs (block/box drawing, arrows). */
|
|
13
|
+
export const unicodeSupported = unicode;
|
|
12
14
|
export const SYMBOLS = {
|
|
13
15
|
middot: unicode ? '·' : '-',
|
|
14
16
|
emDash: unicode ? '—' : '--',
|
package/dist/io/tty.d.ts
CHANGED
|
@@ -6,4 +6,12 @@ type KtxCliOutput = (KtxCliIo['stdout'] | KtxCliIo['stderr']) & {
|
|
|
6
6
|
on?: unknown;
|
|
7
7
|
};
|
|
8
8
|
export declare function isWritableTtyOutput(output: KtxCliOutput): output is KtxCliOutput & Writable;
|
|
9
|
+
export declare function shouldUseColorOutput(output: {
|
|
10
|
+
isTTY?: boolean;
|
|
11
|
+
}): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Color depth in bits for the given output: 1 when color is disabled, the
|
|
14
|
+
* stream-reported depth when available, and a 16-color baseline otherwise.
|
|
15
|
+
*/
|
|
16
|
+
export declare function colorDepthForOutput(output: KtxCliOutput): number;
|
|
9
17
|
export {};
|
package/dist/io/tty.js
CHANGED
|
@@ -3,3 +3,19 @@ export function isWritableTtyOutput(output) {
|
|
|
3
3
|
typeof output.on === 'function' &&
|
|
4
4
|
typeof output.columns !== 'undefined');
|
|
5
5
|
}
|
|
6
|
+
export function shouldUseColorOutput(output) {
|
|
7
|
+
if (output.isTTY !== true)
|
|
8
|
+
return false;
|
|
9
|
+
const env = process.env;
|
|
10
|
+
return !env.NO_COLOR && env.TERM !== 'dumb' && !env.CI;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Color depth in bits for the given output: 1 when color is disabled, the
|
|
14
|
+
* stream-reported depth when available, and a 16-color baseline otherwise.
|
|
15
|
+
*/
|
|
16
|
+
export function colorDepthForOutput(output) {
|
|
17
|
+
if (!shouldUseColorOutput(output))
|
|
18
|
+
return 1;
|
|
19
|
+
const getColorDepth = output.getColorDepth;
|
|
20
|
+
return typeof getColorDepth === 'function' ? getColorDepth.call(output) : 4;
|
|
21
|
+
}
|
|
@@ -21,7 +21,7 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
21
21
|
export async function runKtxEmbeddingHealthCheck(config, options = {}) {
|
|
22
22
|
try {
|
|
23
23
|
const provider = createKtxEmbeddingProvider(config, options.deps);
|
|
24
|
-
const embedding = await withTimeout(provider.embed(options.text ?? '
|
|
24
|
+
const embedding = await withTimeout(provider.embed(options.text ?? 'ktx embedding health check'), options.timeoutMs ?? 15_000);
|
|
25
25
|
if (embedding.length !== config.dimensions) {
|
|
26
26
|
return {
|
|
27
27
|
ok: false,
|
|
@@ -49,7 +49,7 @@ class OpenAIEmbeddingProvider {
|
|
|
49
49
|
this.dimensions = config.dimensions;
|
|
50
50
|
this.maxBatchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
51
51
|
if (!config.openai?.apiKey) {
|
|
52
|
-
throw new Error('openai.apiKey is required when
|
|
52
|
+
throw new Error('openai.apiKey is required when ktx embedding backend is openai');
|
|
53
53
|
}
|
|
54
54
|
this.client = deps.createOpenAIClient
|
|
55
55
|
? deps.createOpenAIClient({ apiKey: config.openai.apiKey, baseURL: config.openai.baseURL })
|
|
@@ -90,7 +90,7 @@ class SentenceTransformersEmbeddingProvider {
|
|
|
90
90
|
startupProbe;
|
|
91
91
|
constructor(config, deps) {
|
|
92
92
|
if (!config.sentenceTransformers?.baseURL) {
|
|
93
|
-
throw new Error('sentenceTransformers.baseURL is required when
|
|
93
|
+
throw new Error('sentenceTransformers.baseURL is required when ktx embedding backend is sentence-transformers');
|
|
94
94
|
}
|
|
95
95
|
this.dimensions = config.dimensions;
|
|
96
96
|
this.maxBatchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
@@ -156,6 +156,6 @@ export function createKtxEmbeddingProvider(config, deps = {}) {
|
|
|
156
156
|
case 'sentence-transformers':
|
|
157
157
|
return new SentenceTransformersEmbeddingProvider(config, deps);
|
|
158
158
|
default:
|
|
159
|
-
throw new Error(`Unsupported
|
|
159
|
+
throw new Error(`Unsupported ktx embedding backend: ${String(config.backend)}`);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -121,7 +121,7 @@ class DefaultKtxLlmProvider {
|
|
|
121
121
|
}
|
|
122
122
|
if (config.backend === 'vertex') {
|
|
123
123
|
if (!config.vertex?.location) {
|
|
124
|
-
throw new Error('vertex.location is required when
|
|
124
|
+
throw new Error('vertex.location is required when ktx LLM backend is vertex');
|
|
125
125
|
}
|
|
126
126
|
const vertex = (deps.createVertexAnthropic ?? createVertexAnthropic)({
|
|
127
127
|
...(config.vertex.project ? { project: config.vertex.project } : {}),
|
package/dist/local-adapters.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { KtxLocalProject } from './context/project/project.js';
|
|
|
5
5
|
import type { SqlAnalysisPort } from './context/sql-analysis/ports.js';
|
|
6
6
|
import { type ManagedPythonDaemonHttpOptions } from './managed-python-http.js';
|
|
7
7
|
import type { KtxOperationalLogger } from './io/logger.js';
|
|
8
|
+
export declare function resolveKtxCliSqlAnalysis(options: KtxCliLocalIngestAdaptersOptions): SqlAnalysisPort;
|
|
8
9
|
export interface KtxCliLocalIngestAdaptersOptions extends DefaultLocalIngestAdaptersOptions {
|
|
9
10
|
historicSqlConnectionId?: string;
|
|
10
11
|
sqlAnalysis?: SqlAnalysisPort;
|
package/dist/local-adapters.js
CHANGED
|
@@ -45,7 +45,7 @@ function ktxCliLookerOptions(options) {
|
|
|
45
45
|
parser: createManagedDaemonLookerTableIdentifierParser(options.managedDaemon),
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
export function resolveKtxCliSqlAnalysis(options) {
|
|
49
49
|
if (options.sqlAnalysis) {
|
|
50
50
|
return options.sqlAnalysis;
|
|
51
51
|
}
|
|
@@ -234,7 +234,7 @@ function historicSqlOptionsForLocalRun(project, options) {
|
|
|
234
234
|
return undefined;
|
|
235
235
|
}
|
|
236
236
|
const base = {
|
|
237
|
-
sqlAnalysis:
|
|
237
|
+
sqlAnalysis: resolveKtxCliSqlAnalysis(options),
|
|
238
238
|
};
|
|
239
239
|
if (dialect === 'postgres') {
|
|
240
240
|
return {
|
|
@@ -11,7 +11,7 @@ export async function createKtxCliScanConnector(project, connectionId) {
|
|
|
11
11
|
}
|
|
12
12
|
const registration = getDriverRegistration(driver);
|
|
13
13
|
if (!registration) {
|
|
14
|
-
throw new Error(`Connection "${connectionId}" uses driver "${driver}", which has no native standalone
|
|
14
|
+
throw new Error(`Connection "${connectionId}" uses driver "${driver}", which has no native standalone ktx scan connector. Supported drivers: ${SUPPORTED_DRIVERS}.`);
|
|
15
15
|
}
|
|
16
16
|
const connectorModule = await registration.load();
|
|
17
17
|
if (!connectorModule.isConnectionConfig(connection)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createCliSpinner } from './clack.js';
|
|
2
2
|
import { ensureManagedPythonCommandRuntime, } from './managed-python-command.js';
|
|
3
3
|
import { readManagedPythonDaemonStatus, startManagedPythonDaemon, } from './managed-python-daemon.js';
|
|
4
4
|
export function managedLocalEmbeddingHealthConfig(input) {
|
|
@@ -21,14 +21,23 @@ export async function ensureManagedLocalEmbeddingsDaemon(options) {
|
|
|
21
21
|
io: options.io,
|
|
22
22
|
feature: 'local-embeddings',
|
|
23
23
|
});
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const spinner = createCliSpinner(options.io);
|
|
25
|
+
spinner.start('Starting ktx embedding daemon (first run downloads the model)…');
|
|
26
|
+
let daemon;
|
|
27
|
+
try {
|
|
28
|
+
daemon = await startDaemon({
|
|
29
|
+
cliVersion: options.cliVersion,
|
|
30
|
+
projectDir: options.projectDir,
|
|
31
|
+
features: ['local-embeddings'],
|
|
32
|
+
force: false,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
spinner.error('ktx embedding daemon failed to start');
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
30
39
|
const verb = daemon.status === 'started' ? 'Started' : 'Using';
|
|
31
|
-
|
|
40
|
+
spinner.stop(`${verb} ktx daemon: ${daemon.baseUrl}`);
|
|
32
41
|
return {
|
|
33
42
|
baseUrl: daemon.baseUrl,
|
|
34
43
|
stdoutLog: daemon.state.stdoutLog,
|
|
@@ -92,7 +92,7 @@ export async function startKtxMcpDaemon(options) {
|
|
|
92
92
|
url: `http://${existing.host}:${existing.port}/mcp`,
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
throw new Error(`
|
|
95
|
+
throw new Error(`ktx MCP daemon is already running at http://${existing.host}:${existing.port}/mcp ` +
|
|
96
96
|
'with a different configuration. Run `ktx mcp stop` first, then start again.');
|
|
97
97
|
}
|
|
98
98
|
const portAvailable = options.portAvailable ?? defaultPortAvailable;
|
|
@@ -126,7 +126,7 @@ export async function startKtxMcpDaemon(options) {
|
|
|
126
126
|
}),
|
|
127
127
|
});
|
|
128
128
|
if (!child.pid) {
|
|
129
|
-
throw new Error('Failed to start
|
|
129
|
+
throw new Error('Failed to start ktx MCP daemon: child process pid was not available.');
|
|
130
130
|
}
|
|
131
131
|
child.unref();
|
|
132
132
|
const state = {
|
|
@@ -167,7 +167,7 @@ export async function readKtxMcpDaemonStatus(options) {
|
|
|
167
167
|
}
|
|
168
168
|
return {
|
|
169
169
|
kind: 'running',
|
|
170
|
-
detail: `
|
|
170
|
+
detail: `ktx MCP daemon running at http://${state.host}:${state.port}/mcp`,
|
|
171
171
|
state,
|
|
172
172
|
url: `http://${state.host}:${state.port}/mcp`,
|
|
173
173
|
};
|
|
@@ -31,4 +31,11 @@ export interface ManagedPythonSemanticLayerComputeOptions extends ManagedPythonC
|
|
|
31
31
|
export declare function managedRuntimeInstallCommand(feature: KtxRuntimeFeature): string;
|
|
32
32
|
export declare function ensureManagedPythonCommandRuntime(options: ManagedPythonCommandOptions): Promise<ManagedPythonCommandRuntime>;
|
|
33
33
|
export declare function createManagedPythonSemanticLayerComputePort(options: ManagedPythonSemanticLayerComputeOptions): Promise<KtxSemanticLayerComputePort>;
|
|
34
|
+
/**
|
|
35
|
+
* Defers the managed-runtime install to the first semantic-layer call so a
|
|
36
|
+
* long-lived server (the MCP server) can start and serve context tools that
|
|
37
|
+
* need no Python even when uv is absent. Caches on success only, so a runtime
|
|
38
|
+
* installed mid-session is picked up on the next call.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createLazyManagedPythonSemanticLayerComputePort(options: ManagedPythonSemanticLayerComputeOptions): KtxSemanticLayerComputePort;
|
|
34
41
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPythonSemanticLayerComputePort } from './context/daemon/semantic-layer-compute.js';
|
|
2
|
-
import { createClackPromptAdapter,
|
|
2
|
+
import { createClackPromptAdapter, createCliSpinner } from './clack.js';
|
|
3
3
|
import { installManagedPythonRuntime, readManagedPythonRuntimeStatus, } from './managed-python-runtime.js';
|
|
4
4
|
import { readExistingTelemetryProjectId } from './telemetry/identity.js';
|
|
5
5
|
export function runtimeInstallPolicyFromFlags(options) {
|
|
@@ -19,10 +19,10 @@ export function managedRuntimeInstallCommand(feature) {
|
|
|
19
19
|
}
|
|
20
20
|
function installPrompt(feature) {
|
|
21
21
|
const label = feature === 'local-embeddings' ? 'local embeddings Python runtime' : 'core Python runtime';
|
|
22
|
-
return `
|
|
22
|
+
return `ktx needs to install the ${label}. This downloads a pinned, checksum-verified uv build, Python, and dependencies. Continue?`;
|
|
23
23
|
}
|
|
24
24
|
function runtimeRequiredMessage(feature) {
|
|
25
|
-
return `
|
|
25
|
+
return `ktx Python runtime is required for this command. Run: ${managedRuntimeInstallCommand(feature)}`;
|
|
26
26
|
}
|
|
27
27
|
function hasFeature(manifest, feature) {
|
|
28
28
|
return manifest.features.includes(feature);
|
|
@@ -49,22 +49,22 @@ export async function ensureManagedPythonCommandRuntime(options) {
|
|
|
49
49
|
const confirmInstall = options.confirmInstall ?? defaultConfirmInstall;
|
|
50
50
|
const confirmed = await confirmInstall(installPrompt(feature), options.io);
|
|
51
51
|
if (!confirmed) {
|
|
52
|
-
throw new Error(`
|
|
52
|
+
throw new Error(`ktx Python runtime installation was cancelled. Run: ${managedRuntimeInstallCommand(feature)}`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
const progress = (options.spinner ?? (() =>
|
|
56
|
-
progress.start(`Installing
|
|
55
|
+
const progress = (options.spinner ?? (() => createCliSpinner(options.io)))();
|
|
56
|
+
progress.start(`Installing ktx Python runtime (${feature}) with uv...`);
|
|
57
57
|
try {
|
|
58
58
|
const installed = await installRuntime({
|
|
59
59
|
cliVersion: options.cliVersion,
|
|
60
60
|
features: [feature],
|
|
61
61
|
force: false,
|
|
62
62
|
});
|
|
63
|
-
progress.stop(`
|
|
63
|
+
progress.stop(`ktx Python runtime ready: ${installed.layout.versionDir}`);
|
|
64
64
|
return { layout: installed.layout, manifest: installed.manifest };
|
|
65
65
|
}
|
|
66
66
|
catch (error) {
|
|
67
|
-
progress.error(`
|
|
67
|
+
progress.error(`ktx Python runtime install failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
68
|
throw error;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -89,3 +89,29 @@ export async function createManagedPythonSemanticLayerComputePort(options) {
|
|
|
89
89
|
...(projectId ? { projectId } : {}),
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Defers the managed-runtime install to the first semantic-layer call so a
|
|
94
|
+
* long-lived server (the MCP server) can start and serve context tools that
|
|
95
|
+
* need no Python even when uv is absent. Caches on success only, so a runtime
|
|
96
|
+
* installed mid-session is picked up on the next call.
|
|
97
|
+
*/
|
|
98
|
+
export function createLazyManagedPythonSemanticLayerComputePort(options) {
|
|
99
|
+
let cached;
|
|
100
|
+
const resolve = async () => {
|
|
101
|
+
if (!cached) {
|
|
102
|
+
cached = await createManagedPythonSemanticLayerComputePort(options);
|
|
103
|
+
}
|
|
104
|
+
return cached;
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
async query(input) {
|
|
108
|
+
return (await resolve()).query(input);
|
|
109
|
+
},
|
|
110
|
+
async validateSources(input) {
|
|
111
|
+
return (await resolve()).validateSources(input);
|
|
112
|
+
},
|
|
113
|
+
async generateSources(input) {
|
|
114
|
+
return (await resolve()).generateSources(input);
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -11,7 +11,7 @@ export class ManagedPythonDaemonStartError extends Error {
|
|
|
11
11
|
detail;
|
|
12
12
|
stderrLog;
|
|
13
13
|
constructor(detail, stderrLog) {
|
|
14
|
-
super(`
|
|
14
|
+
super(`ktx daemon failed to start: ${detail}. stderr: ${stderrLog}`);
|
|
15
15
|
this.name = 'ManagedPythonDaemonStartError';
|
|
16
16
|
this.detail = detail;
|
|
17
17
|
this.stderrLog = stderrLog;
|
|
@@ -502,7 +502,7 @@ export async function startManagedPythonDaemon(options) {
|
|
|
502
502
|
});
|
|
503
503
|
child.unref();
|
|
504
504
|
if (!child.pid) {
|
|
505
|
-
throw new Error(`
|
|
505
|
+
throw new Error(`ktx daemon did not report a pid. stderr: ${layout.daemonStderrPath}`);
|
|
506
506
|
}
|
|
507
507
|
const state = {
|
|
508
508
|
schemaVersion: 1,
|
|
@@ -12,7 +12,7 @@ function normalizedBaseUrl(baseUrl) {
|
|
|
12
12
|
function parseJsonObject(raw, path) {
|
|
13
13
|
const parsed = JSON.parse(raw);
|
|
14
14
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
15
|
-
throw new Error(`
|
|
15
|
+
throw new Error(`ktx daemon HTTP ${path} returned non-object JSON`);
|
|
16
16
|
}
|
|
17
17
|
return parsed;
|
|
18
18
|
}
|
|
@@ -35,7 +35,7 @@ async function postManagedDaemonJson(baseUrl, path, payload) {
|
|
|
35
35
|
const text = Buffer.concat(chunks).toString('utf8');
|
|
36
36
|
const statusCode = response.statusCode ?? 0;
|
|
37
37
|
if (statusCode < 200 || statusCode >= 300) {
|
|
38
|
-
reject(new Error(`
|
|
38
|
+
reject(new Error(`ktx daemon HTTP ${path} failed with ${statusCode}: ${text}`));
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
try {
|
|
@@ -72,7 +72,7 @@ export function createManagedPythonDaemonBaseUrlResolver(options) {
|
|
|
72
72
|
force: false,
|
|
73
73
|
});
|
|
74
74
|
const verb = daemon.status === 'started' ? 'Started' : 'Using existing';
|
|
75
|
-
writePrefixedLines((chunk) => options.io.stderr.write(chunk), `${verb}
|
|
75
|
+
writePrefixedLines((chunk) => options.io.stderr.write(chunk), `${verb} ktx daemon: ${daemon.baseUrl}`);
|
|
76
76
|
cachedBaseUrl = daemon.baseUrl;
|
|
77
77
|
return cachedBaseUrl;
|
|
78
78
|
};
|