@kaelio/ktx 0.9.0 → 0.11.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.9.0-py3-none-any.whl → kaelio_ktx-0.11.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/clack.d.ts +6 -0
- package/dist/clack.js +17 -2
- package/dist/cli-program.d.ts +3 -0
- package/dist/cli-program.js +46 -2
- package/dist/cli-runtime.d.ts +5 -0
- package/dist/cli-runtime.js +50 -0
- package/dist/commands/setup-commands.js +2 -3
- package/dist/community-cta.d.ts +11 -0
- package/dist/community-cta.js +19 -0
- package/dist/connection.js +23 -1
- package/dist/connectors/bigquery/connector.d.ts +2 -5
- package/dist/connectors/bigquery/connector.js +2 -2
- package/dist/connectors/clickhouse/connector.d.ts +2 -5
- package/dist/connectors/clickhouse/connector.js +2 -2
- package/dist/connectors/mysql/connector.d.ts +7 -6
- package/dist/connectors/mysql/connector.js +25 -5
- package/dist/connectors/mysql/dialect.d.ts +1 -1
- package/dist/connectors/mysql/dialect.js +12 -2
- package/dist/connectors/postgres/connector.d.ts +2 -5
- package/dist/connectors/postgres/connector.js +2 -2
- package/dist/connectors/snowflake/connector.d.ts +2 -5
- package/dist/connectors/snowflake/connector.js +2 -2
- package/dist/connectors/sqlite/connector.d.ts +2 -5
- package/dist/connectors/sqlite/connector.js +2 -2
- package/dist/connectors/sqlserver/connector.d.ts +2 -5
- package/dist/connectors/sqlserver/connector.js +2 -2
- package/dist/context/connections/drivers.d.ts +0 -1
- package/dist/context/connections/drivers.js +0 -7
- package/dist/context/connections/query-executor.d.ts +2 -1
- package/dist/context/core/abort.d.ts +9 -0
- package/dist/context/core/abort.js +36 -0
- package/dist/context/core/git-env.d.ts +12 -1
- package/dist/context/core/git-env.js +17 -2
- package/dist/context/core/git.service.js +15 -7
- package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.d.ts +1 -0
- package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.js +6 -2
- package/dist/context/ingest/context-candidates/curator-pagination.service.d.ts +1 -5
- package/dist/context/ingest/context-candidates/curator-pagination.service.js +1 -3
- package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.d.ts +1 -1
- package/dist/context/ingest/final-gate-repair.d.ts +1 -0
- package/dist/context/ingest/final-gate-repair.js +1 -0
- package/dist/context/ingest/ingest-bundle.runner.d.ts +3 -0
- package/dist/context/ingest/ingest-bundle.runner.js +127 -53
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.d.ts +1 -0
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.js +1 -0
- package/dist/context/ingest/isolated-diff/work-unit-executor.d.ts +1 -0
- package/dist/context/ingest/local-bundle-runtime.js +11 -4
- package/dist/context/ingest/local-ingest.d.ts +1 -0
- package/dist/context/ingest/local-ingest.js +13 -3
- package/dist/context/ingest/memory-flow/events.js +1 -1
- package/dist/context/ingest/memory-flow/schema.js +8 -3
- package/dist/context/ingest/memory-flow/types.d.ts +7 -3
- package/dist/context/ingest/ports.d.ts +3 -5
- package/dist/context/ingest/stages/stage-3-work-units.d.ts +1 -4
- package/dist/context/ingest/stages/stage-3-work-units.js +5 -1
- package/dist/context/ingest/stages/stage-4-reconciliation.d.ts +1 -4
- package/dist/context/ingest/stages/stage-4-reconciliation.js +1 -1
- package/dist/context/ingest/types.d.ts +1 -0
- package/dist/context/llm/ai-sdk-runtime.d.ts +3 -0
- package/dist/context/llm/ai-sdk-runtime.js +152 -16
- package/dist/context/llm/claude-code-runtime.d.ts +6 -4
- package/dist/context/llm/claude-code-runtime.js +127 -48
- package/dist/context/llm/codex-runtime.d.ts +3 -3
- package/dist/context/llm/codex-runtime.js +90 -47
- package/dist/context/llm/local-config.d.ts +15 -5
- package/dist/context/llm/local-config.js +6 -1
- package/dist/context/llm/rate-limit-governor.d.ts +103 -0
- package/dist/context/llm/rate-limit-governor.js +285 -0
- package/dist/context/llm/runtime-port.d.ts +3 -6
- package/dist/context/mcp/context-tools.js +43 -13
- package/dist/context/project/config.d.ts +12 -0
- package/dist/context/project/config.js +35 -0
- package/dist/context/scan/types.d.ts +15 -2
- package/dist/context/scan/types.js +12 -0
- package/dist/context/sl/description-normalization.js +4 -14
- package/dist/context/tools/context-candidate-mark.tool.d.ts +2 -2
- package/dist/context-build-view.d.ts +13 -0
- package/dist/context-build-view.js +60 -1
- package/dist/demo-metrics.d.ts +0 -2
- package/dist/demo-metrics.js +1 -11
- package/dist/ingest.d.ts +1 -0
- package/dist/ingest.js +32 -3
- package/dist/io/symbols.d.ts +2 -0
- package/dist/io/symbols.js +2 -0
- package/dist/io/tty.d.ts +9 -0
- package/dist/io/tty.js +5 -0
- package/dist/links.d.ts +1 -0
- package/dist/links.js +1 -0
- package/dist/memory-flow-hud.js +8 -16
- package/dist/public-ingest.js +50 -15
- package/dist/reveal-password-prompt.d.ts +24 -0
- package/dist/reveal-password-prompt.js +78 -0
- package/dist/scan.js +18 -2
- package/dist/setup-agents.js +1 -5
- package/dist/setup-databases.d.ts +1 -0
- package/dist/setup-databases.js +23 -3
- package/dist/setup-demo-tour.js +1 -0
- package/dist/setup-embeddings.js +1 -1
- package/dist/setup-models.d.ts +1 -14
- package/dist/setup-models.js +116 -340
- package/dist/setup-prompts.js +4 -7
- package/dist/setup-sources.js +7 -7
- package/dist/setup.d.ts +26 -1
- package/dist/setup.js +78 -7
- package/dist/sl.d.ts +2 -2
- package/dist/sl.js +20 -4
- package/dist/sql.js +18 -2
- package/dist/star-prompt/cache.d.ts +16 -0
- package/dist/star-prompt/cache.js +45 -0
- package/dist/star-prompt/star-count.d.ts +7 -0
- package/dist/star-prompt/star-count.js +66 -0
- package/dist/star-prompt/star-line.d.ts +12 -0
- package/dist/star-prompt/star-line.js +26 -0
- package/dist/telemetry/command-hook.d.ts +24 -0
- package/dist/telemetry/command-hook.js +37 -3
- package/dist/telemetry/emitter.d.ts +10 -0
- package/dist/telemetry/emitter.js +31 -0
- package/dist/telemetry/events.d.ts +24 -0
- package/dist/telemetry/events.js +15 -0
- package/dist/telemetry/exception.d.ts +18 -0
- package/dist/telemetry/exception.js +162 -0
- package/dist/telemetry/index.d.ts +4 -3
- package/dist/telemetry/index.js +3 -2
- package/dist/telemetry/redaction-secrets.d.ts +11 -0
- package/dist/telemetry/redaction-secrets.js +92 -0
- package/dist/update-check/cache.d.ts +21 -0
- package/dist/update-check/cache.js +38 -0
- package/dist/update-check/channel.d.ts +15 -0
- package/dist/update-check/channel.js +30 -0
- package/dist/update-check/registry.d.ts +1 -0
- package/dist/update-check/registry.js +45 -0
- package/dist/update-check/update-check.d.ts +43 -0
- package/dist/update-check/update-check.js +116 -0
- package/package.json +8 -1
- package/dist/context/connections/local-query-executor.d.ts +0 -6
- package/dist/context/connections/local-query-executor.js +0 -39
- package/dist/context/connections/postgres-query-executor.d.ts +0 -25
- package/dist/context/connections/postgres-query-executor.js +0 -53
- package/dist/context/connections/sqlite-query-executor.d.ts +0 -4
- package/dist/context/connections/sqlite-query-executor.js +0 -74
package/dist/ingest.js
CHANGED
|
@@ -17,6 +17,22 @@ import { renderMemoryFlowTui, startLiveMemoryFlowTui, } from './memory-flow-tui.
|
|
|
17
17
|
import { resolveVizFallback, warnVizFallbackOnce } from './viz-fallback.js';
|
|
18
18
|
import { profileMark } from './startup-profile.js';
|
|
19
19
|
profileMark('module:ingest');
|
|
20
|
+
function createCliAbortSignal() {
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
let interrupted = false;
|
|
23
|
+
const onSigint = () => {
|
|
24
|
+
if (interrupted) {
|
|
25
|
+
process.exit(130);
|
|
26
|
+
}
|
|
27
|
+
interrupted = true;
|
|
28
|
+
controller.abort(new DOMException('Aborted', 'AbortError'));
|
|
29
|
+
};
|
|
30
|
+
process.on('SIGINT', onSigint);
|
|
31
|
+
return {
|
|
32
|
+
signal: controller.signal,
|
|
33
|
+
dispose: () => process.off('SIGINT', onSigint),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
20
36
|
const REPORT_SOURCE_LABELS = new Map([
|
|
21
37
|
['live-database', 'Database schema'],
|
|
22
38
|
['historic-sql', 'Query history'],
|
|
@@ -249,6 +265,12 @@ function plainIngestEventProgress(event, snapshot, eventIndex) {
|
|
|
249
265
|
message: event.message,
|
|
250
266
|
...(event.transient !== undefined ? { transient: event.transient } : {}),
|
|
251
267
|
};
|
|
268
|
+
case 'rate_limit_wait':
|
|
269
|
+
return {
|
|
270
|
+
percent: 50,
|
|
271
|
+
message: `Rate-limited (${event.provider}${event.rateLimitType ? ` ${event.rateLimitType}` : ''}); resuming in ${Math.ceil(event.remainingMs / 1_000)}s`,
|
|
272
|
+
transient: true,
|
|
273
|
+
};
|
|
252
274
|
case 'work_unit_started': {
|
|
253
275
|
const total = plannedWorkUnitCountThrough(snapshot, eventIndex);
|
|
254
276
|
const ordinal = workUnitOrdinalThrough(snapshot, eventIndex, event.unitKey);
|
|
@@ -259,9 +281,8 @@ function plainIngestEventProgress(event, snapshot, eventIndex) {
|
|
|
259
281
|
const total = plannedWorkUnitCountThrough(snapshot, eventIndex);
|
|
260
282
|
const completed = completedWorkUnitCountThrough(snapshot, eventIndex);
|
|
261
283
|
const active = activeWorkUnitCountThrough(snapshot, eventIndex);
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
const latest = `${event.unitKey} step ${event.stepIndex}/${event.stepBudget}`;
|
|
284
|
+
const percent = total > 0 ? 55 + Math.ceil((completed / total) * 25) : 55;
|
|
285
|
+
const latest = `${event.unitKey} · ${pluralize(event.toolCalls, 'action')}`;
|
|
265
286
|
return {
|
|
266
287
|
percent,
|
|
267
288
|
message: `Processing tasks: ${completed}/${total} complete, ${active} active; latest ${latest}`,
|
|
@@ -546,6 +567,8 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
546
567
|
: io, deps.progress);
|
|
547
568
|
plainProgress?.start();
|
|
548
569
|
structuredProgress?.start();
|
|
570
|
+
const cliAbort = deps.abortSignal ? null : createCliAbortSignal();
|
|
571
|
+
const abortSignal = deps.abortSignal ?? cliAbort?.signal;
|
|
549
572
|
let result;
|
|
550
573
|
try {
|
|
551
574
|
result = await executeMetabaseFanout({
|
|
@@ -559,6 +582,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
559
582
|
embeddingProvider,
|
|
560
583
|
...(memoryFlow ? { memoryFlow } : {}),
|
|
561
584
|
...(progress ? { progress } : {}),
|
|
585
|
+
...(abortSignal ? { abortSignal } : {}),
|
|
562
586
|
});
|
|
563
587
|
plainProgress?.flush();
|
|
564
588
|
if (args.outputMode === 'json') {
|
|
@@ -570,6 +594,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
570
594
|
}
|
|
571
595
|
finally {
|
|
572
596
|
plainProgress?.flush();
|
|
597
|
+
cliAbort?.dispose();
|
|
573
598
|
}
|
|
574
599
|
return result.status === 'all_failed' ? 1 : 0;
|
|
575
600
|
}
|
|
@@ -612,6 +637,8 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
612
637
|
: undefined;
|
|
613
638
|
plainProgress?.start();
|
|
614
639
|
structuredProgress?.start();
|
|
640
|
+
const cliAbort = deps.abortSignal ? null : createCliAbortSignal();
|
|
641
|
+
const abortSignal = deps.abortSignal ?? cliAbort?.signal;
|
|
615
642
|
try {
|
|
616
643
|
const result = await executeLocalIngest({
|
|
617
644
|
project: ingestProject,
|
|
@@ -627,6 +654,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
627
654
|
embeddingProvider,
|
|
628
655
|
...(args.debugLlmRequestFile ? { llmDebugRequestFile: args.debugLlmRequestFile } : {}),
|
|
629
656
|
...(memoryFlow ? { memoryFlow } : {}),
|
|
657
|
+
...(abortSignal ? { abortSignal } : {}),
|
|
630
658
|
});
|
|
631
659
|
if (shouldUseLiveViz && memoryFlow) {
|
|
632
660
|
latestMemoryFlowSnapshot = finalRunMemoryFlowInput(memoryFlow.snapshot(), result.report);
|
|
@@ -646,6 +674,7 @@ export async function runKtxIngest(args, io = process, deps = {}) {
|
|
|
646
674
|
finally {
|
|
647
675
|
plainProgress?.flush();
|
|
648
676
|
liveTui?.close();
|
|
677
|
+
cliAbort?.dispose();
|
|
649
678
|
}
|
|
650
679
|
}
|
|
651
680
|
if (args.reportFile) {
|
package/dist/io/symbols.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const SYMBOLS: {
|
|
2
2
|
readonly middot: "-" | "·";
|
|
3
3
|
readonly emDash: "--" | "—";
|
|
4
|
+
readonly star: "*" | "★";
|
|
5
|
+
readonly rightArrow: "→" | "->";
|
|
4
6
|
};
|
|
5
7
|
export declare function dim(text: string): string;
|
|
6
8
|
export declare function bold(text: string): string;
|
package/dist/io/symbols.js
CHANGED
|
@@ -12,6 +12,8 @@ const unicode = detectUnicodeSupport();
|
|
|
12
12
|
export const SYMBOLS = {
|
|
13
13
|
middot: unicode ? '·' : '-',
|
|
14
14
|
emDash: unicode ? '—' : '--',
|
|
15
|
+
star: unicode ? '★' : '*',
|
|
16
|
+
rightArrow: unicode ? '→' : '->',
|
|
15
17
|
};
|
|
16
18
|
export function dim(text) {
|
|
17
19
|
return styleText('dim', text);
|
package/dist/io/tty.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
2
|
+
import type { KtxCliIo } from '../cli-runtime.js';
|
|
3
|
+
type KtxCliOutput = (KtxCliIo['stdout'] | KtxCliIo['stderr']) & {
|
|
4
|
+
isTTY?: boolean;
|
|
5
|
+
columns?: number;
|
|
6
|
+
on?: unknown;
|
|
7
|
+
};
|
|
8
|
+
export declare function isWritableTtyOutput(output: KtxCliOutput): output is KtxCliOutput & Writable;
|
|
9
|
+
export {};
|
package/dist/io/tty.js
ADDED
package/dist/links.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SLACK_URL = "https://ktx.sh/slack";
|
package/dist/links.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SLACK_URL = 'https://ktx.sh/slack';
|
package/dist/memory-flow-hud.js
CHANGED
|
@@ -97,27 +97,19 @@ function sourceDescription(input) {
|
|
|
97
97
|
}
|
|
98
98
|
function activeWorkUnits(input) {
|
|
99
99
|
const finishedKeys = new Set();
|
|
100
|
-
const unitMap = new Map();
|
|
101
100
|
for (const e of input.events) {
|
|
102
|
-
if (e.type === 'work_unit_started') {
|
|
103
|
-
unitMap.set(e.unitKey, { stepIndex: 0, stepBudget: e.stepBudget });
|
|
104
|
-
}
|
|
105
|
-
if (e.type === 'work_unit_step') {
|
|
106
|
-
const existing = unitMap.get(e.unitKey);
|
|
107
|
-
if (existing) {
|
|
108
|
-
existing.stepIndex = e.stepIndex;
|
|
109
|
-
existing.stepBudget = e.stepBudget;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
101
|
if (e.type === 'work_unit_finished')
|
|
113
102
|
finishedKeys.add(e.unitKey);
|
|
114
103
|
}
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
const active = [];
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
for (const e of input.events) {
|
|
107
|
+
if (e.type === 'work_unit_started' && !finishedKeys.has(e.unitKey) && !seen.has(e.unitKey)) {
|
|
108
|
+
seen.add(e.unitKey);
|
|
109
|
+
active.push(e.unitKey);
|
|
110
|
+
}
|
|
119
111
|
}
|
|
120
|
-
return
|
|
112
|
+
return active;
|
|
121
113
|
}
|
|
122
114
|
function queuedWorkUnits(input) {
|
|
123
115
|
const startedKeys = new Set();
|
package/dist/public-ingest.js
CHANGED
|
@@ -8,7 +8,8 @@ import { createAggregateProgressPort } from './progress-port-adapter.js';
|
|
|
8
8
|
import { resolvePublicIngestRuntimeRequirements } from './runtime-requirements.js';
|
|
9
9
|
import { profileMark } from './startup-profile.js';
|
|
10
10
|
import { isDemoConnection } from './telemetry/demo-detect.js';
|
|
11
|
-
import { emitProjectStackSnapshot, emitTelemetryEvent } from './telemetry/index.js';
|
|
11
|
+
import { emitProjectStackSnapshot, emitTelemetryEvent, reportException } from './telemetry/index.js';
|
|
12
|
+
import { collectTelemetryRedactionSecrets } from './telemetry/redaction-secrets.js';
|
|
12
13
|
import { formatErrorDetail } from './telemetry/scrubber.js';
|
|
13
14
|
profileMark('module:public-ingest');
|
|
14
15
|
const sourceAdapterByDriver = new Map([
|
|
@@ -733,26 +734,60 @@ export async function runKtxPublicIngest(args, io, deps = {}) {
|
|
|
733
734
|
});
|
|
734
735
|
}
|
|
735
736
|
catch (error) {
|
|
737
|
+
await reportException({
|
|
738
|
+
error,
|
|
739
|
+
context: { source: 'ingest runtime', handled: true, fatal: false },
|
|
740
|
+
projectDir: args.projectDir,
|
|
741
|
+
io,
|
|
742
|
+
redactionSecrets: await collectTelemetryRedactionSecrets({
|
|
743
|
+
project,
|
|
744
|
+
projectDir: args.projectDir,
|
|
745
|
+
connectionId: args.targetConnectionId,
|
|
746
|
+
includeLlm: true,
|
|
747
|
+
includeEmbeddings: true,
|
|
748
|
+
env: deps.env ?? process.env,
|
|
749
|
+
}),
|
|
750
|
+
});
|
|
736
751
|
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
737
752
|
return 1;
|
|
738
753
|
}
|
|
739
754
|
}
|
|
740
755
|
const { runContextBuild } = await import('./context-build-view.js');
|
|
741
756
|
const contextBuild = deps.runContextBuild ?? runContextBuild;
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
757
|
+
try {
|
|
758
|
+
const result = await contextBuild(project, {
|
|
759
|
+
projectDir: args.projectDir,
|
|
760
|
+
...(args.targetConnectionId ? { targetConnectionId: args.targetConnectionId } : {}),
|
|
761
|
+
all: args.all,
|
|
762
|
+
entrypoint: 'ingest',
|
|
763
|
+
inputMode: args.inputMode,
|
|
764
|
+
...(args.queryHistory ? { queryHistory: args.queryHistory } : {}),
|
|
765
|
+
...(args.queryHistoryWindowDays !== undefined ? { queryHistoryWindowDays: args.queryHistoryWindowDays } : {}),
|
|
766
|
+
...(args.scanMode ? { scanMode: args.scanMode } : {}),
|
|
767
|
+
...(args.detectRelationships !== undefined ? { detectRelationships: args.detectRelationships } : {}),
|
|
768
|
+
...(args.cliVersion ? { cliVersion: args.cliVersion } : {}),
|
|
769
|
+
...(args.runtimeInstallPolicy ? { runtimeInstallPolicy: args.runtimeInstallPolicy } : {}),
|
|
770
|
+
}, io);
|
|
771
|
+
return result.exitCode;
|
|
772
|
+
}
|
|
773
|
+
catch (error) {
|
|
774
|
+
await reportException({
|
|
775
|
+
error,
|
|
776
|
+
context: { source: 'ingest context-build', handled: true, fatal: false },
|
|
777
|
+
projectDir: args.projectDir,
|
|
778
|
+
io,
|
|
779
|
+
redactionSecrets: await collectTelemetryRedactionSecrets({
|
|
780
|
+
project,
|
|
781
|
+
projectDir: args.projectDir,
|
|
782
|
+
connectionId: args.targetConnectionId,
|
|
783
|
+
includeLlm: true,
|
|
784
|
+
includeEmbeddings: true,
|
|
785
|
+
env: deps.env ?? process.env,
|
|
786
|
+
}),
|
|
787
|
+
});
|
|
788
|
+
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
789
|
+
return 1;
|
|
790
|
+
}
|
|
756
791
|
}
|
|
757
792
|
const plan = buildPublicIngestPlan(project, args);
|
|
758
793
|
const results = [];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type PasswordOptions } from '@clack/core';
|
|
2
|
+
/**
|
|
3
|
+
* Mask every character of `userInput` except the last `tail`, but only reveal the
|
|
4
|
+
* tail once the secret is long enough that the hidden portion still dominates
|
|
5
|
+
* (`length > tail * 2`). Short secrets stay fully masked so we never expose most
|
|
6
|
+
* of a small value. The returned string keeps the same code-unit length as the
|
|
7
|
+
* input so clack's cursor slicing in `userInputWithCursor` stays aligned.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function maskRevealingTail(userInput: string, maskChar: string, tail: number): string;
|
|
12
|
+
export interface RevealPasswordOptions {
|
|
13
|
+
message: string;
|
|
14
|
+
mask?: string;
|
|
15
|
+
tail?: number;
|
|
16
|
+
validate?: PasswordOptions['validate'];
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Drop-in replacement for clack's `password()` that reveals the last few
|
|
21
|
+
* characters of the entered value while typing. Resolves to the raw value or the
|
|
22
|
+
* clack cancel symbol, matching `password()`'s contract.
|
|
23
|
+
*/
|
|
24
|
+
export declare function revealPassword(options: RevealPasswordOptions): Promise<string | symbol>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
import { PasswordPrompt } from '@clack/core';
|
|
3
|
+
import { S_BAR, S_BAR_END, S_PASSWORD_MASK, settings, symbol } from '@clack/prompts';
|
|
4
|
+
// How many trailing characters of a pasted secret to leave visible so the user
|
|
5
|
+
// can confirm what landed (e.g. `••••••a1b2`). Kept small on purpose.
|
|
6
|
+
const REVEAL_TAIL_COUNT = 4;
|
|
7
|
+
/**
|
|
8
|
+
* Mask every character of `userInput` except the last `tail`, but only reveal the
|
|
9
|
+
* tail once the secret is long enough that the hidden portion still dominates
|
|
10
|
+
* (`length > tail * 2`). Short secrets stay fully masked so we never expose most
|
|
11
|
+
* of a small value. The returned string keeps the same code-unit length as the
|
|
12
|
+
* input so clack's cursor slicing in `userInputWithCursor` stays aligned.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function maskRevealingTail(userInput, maskChar, tail) {
|
|
17
|
+
const revealLength = userInput.length > tail * 2 ? tail : 0;
|
|
18
|
+
const hiddenLength = userInput.length - revealLength;
|
|
19
|
+
return maskChar.repeat(hiddenLength) + userInput.slice(hiddenLength);
|
|
20
|
+
}
|
|
21
|
+
class RevealTailPasswordPrompt extends PasswordPrompt {
|
|
22
|
+
#maskChar;
|
|
23
|
+
#tail;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
super(options);
|
|
26
|
+
this.#maskChar = options.mask ?? S_PASSWORD_MASK;
|
|
27
|
+
this.#tail = options.tail;
|
|
28
|
+
}
|
|
29
|
+
get masked() {
|
|
30
|
+
return maskRevealingTail(this.userInput, this.#maskChar, this.#tail);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Reproduces the @clack/prompts password frame (pinned to the installed version)
|
|
34
|
+
// so this prompt is visually identical to every other setup prompt; the only
|
|
35
|
+
// behavioral change is the tail-revealing `masked` getter above.
|
|
36
|
+
function renderPasswordFrame(prompt, message) {
|
|
37
|
+
const withGuide = settings.withGuide;
|
|
38
|
+
const title = `${withGuide ? `${styleText('gray', S_BAR)}\n` : ''}${symbol(prompt.state)} ${message}\n`;
|
|
39
|
+
const masked = prompt.masked;
|
|
40
|
+
switch (prompt.state) {
|
|
41
|
+
case 'error': {
|
|
42
|
+
const bar = withGuide ? `${styleText('yellow', S_BAR)} ` : '';
|
|
43
|
+
const end = withGuide ? `${styleText('yellow', S_BAR_END)} ` : '';
|
|
44
|
+
return `${title.trim()}\n${bar}${masked}\n${end}${styleText('yellow', prompt.error)}\n`;
|
|
45
|
+
}
|
|
46
|
+
case 'submit': {
|
|
47
|
+
const bar = withGuide ? `${styleText('gray', S_BAR)} ` : '';
|
|
48
|
+
return `${title}${bar}${masked ? styleText('dim', masked) : ''}`;
|
|
49
|
+
}
|
|
50
|
+
case 'cancel': {
|
|
51
|
+
const bar = withGuide ? `${styleText('gray', S_BAR)} ` : '';
|
|
52
|
+
const body = masked ? styleText(['strikethrough', 'dim'], masked) : '';
|
|
53
|
+
return `${title}${bar}${body}${masked && withGuide ? `\n${styleText('gray', S_BAR)}` : ''}`;
|
|
54
|
+
}
|
|
55
|
+
default: {
|
|
56
|
+
const bar = withGuide ? `${styleText('cyan', S_BAR)} ` : '';
|
|
57
|
+
const end = withGuide ? styleText('cyan', S_BAR_END) : '';
|
|
58
|
+
return `${title}${bar}${prompt.userInputWithCursor}\n${end}\n`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Drop-in replacement for clack's `password()` that reveals the last few
|
|
64
|
+
* characters of the entered value while typing. Resolves to the raw value or the
|
|
65
|
+
* clack cancel symbol, matching `password()`'s contract.
|
|
66
|
+
*/
|
|
67
|
+
export function revealPassword(options) {
|
|
68
|
+
const prompt = new RevealTailPasswordPrompt({
|
|
69
|
+
mask: options.mask ?? S_PASSWORD_MASK,
|
|
70
|
+
tail: options.tail ?? REVEAL_TAIL_COUNT,
|
|
71
|
+
validate: options.validate,
|
|
72
|
+
signal: options.signal,
|
|
73
|
+
render() {
|
|
74
|
+
return renderPasswordFrame(this, options.message);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return prompt.prompt();
|
|
78
|
+
}
|
package/dist/scan.js
CHANGED
|
@@ -5,7 +5,8 @@ import { resolveProjectEmbeddingProvider } from './embedding-resolution.js';
|
|
|
5
5
|
import { createKtxCliLocalIngestAdapters } from './local-adapters.js';
|
|
6
6
|
import { createKtxCliScanConnector } from './local-scan-connectors.js';
|
|
7
7
|
import { profileMark } from './startup-profile.js';
|
|
8
|
-
import { emitTelemetryEvent } from './telemetry/index.js';
|
|
8
|
+
import { emitTelemetryEvent, reportException } from './telemetry/index.js';
|
|
9
|
+
import { collectTelemetryRedactionSecrets } from './telemetry/redaction-secrets.js';
|
|
9
10
|
import { formatErrorDetail, scrubErrorClass } from './telemetry/scrubber.js';
|
|
10
11
|
profileMark('module:scan');
|
|
11
12
|
function shouldUseStyledOutput(io) {
|
|
@@ -248,8 +249,9 @@ export function createCliScanProgress(io, state = { progress: 0, hasPendingTrans
|
|
|
248
249
|
}
|
|
249
250
|
export async function runKtxScan(args, io = process, deps = {}) {
|
|
250
251
|
const startedAt = performance.now();
|
|
252
|
+
let project;
|
|
251
253
|
try {
|
|
252
|
-
|
|
254
|
+
project = await loadKtxProject({ projectDir: args.projectDir });
|
|
253
255
|
const resolveEmbeddingProvider = deps.resolveEmbeddingProvider ?? resolveProjectEmbeddingProvider;
|
|
254
256
|
const resolution = await resolveEmbeddingProvider(project, {
|
|
255
257
|
mode: 'ensure',
|
|
@@ -323,6 +325,20 @@ export async function runKtxScan(args, io = process, deps = {}) {
|
|
|
323
325
|
...(errorDetail ? { errorDetail } : {}),
|
|
324
326
|
},
|
|
325
327
|
});
|
|
328
|
+
await reportException({
|
|
329
|
+
error,
|
|
330
|
+
context: { source: 'scan run', handled: true, fatal: false },
|
|
331
|
+
projectDir: args.projectDir,
|
|
332
|
+
io,
|
|
333
|
+
redactionSecrets: await collectTelemetryRedactionSecrets({
|
|
334
|
+
project,
|
|
335
|
+
projectDir: args.projectDir,
|
|
336
|
+
connectionId: args.connectionId,
|
|
337
|
+
includeLlm: true,
|
|
338
|
+
includeEmbeddings: true,
|
|
339
|
+
env: process.env,
|
|
340
|
+
}),
|
|
341
|
+
});
|
|
326
342
|
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
327
343
|
return 1;
|
|
328
344
|
}
|
package/dist/setup-agents.js
CHANGED
|
@@ -9,14 +9,10 @@ import { markKtxSetupStateStepComplete } from './context/project/setup-config.js
|
|
|
9
9
|
import { serializeKtxProjectConfig } from './context/project/config.js';
|
|
10
10
|
import { strToU8, zipSync } from 'fflate';
|
|
11
11
|
import { errorMessage, writePrefixedLines } from './clack.js';
|
|
12
|
+
import { isWritableTtyOutput } from './io/tty.js';
|
|
12
13
|
import { createKtxSetupPromptAdapter, createKtxSetupUiAdapter, } from './setup-prompts.js';
|
|
13
14
|
import { readKtxMcpDaemonStatus } from './managed-mcp-daemon.js';
|
|
14
15
|
const MCP_DAEMON_REQUIRED_NOTICE = 'mcp-daemon-required';
|
|
15
|
-
function isWritableTtyOutput(output) {
|
|
16
|
-
return (output.isTTY === true &&
|
|
17
|
-
typeof output.on === 'function' &&
|
|
18
|
-
typeof output.columns !== 'undefined');
|
|
19
|
-
}
|
|
20
16
|
function writeSetupInfo(io, message) {
|
|
21
17
|
if (isWritableTtyOutput(io.stdout)) {
|
|
22
18
|
log.info(message, { output: io.stdout });
|
|
@@ -12,6 +12,7 @@ export type KtxSetupDatabaseDriver = 'sqlite' | 'postgres' | 'mysql' | 'clickhou
|
|
|
12
12
|
export interface KtxSetupDatabasesArgs {
|
|
13
13
|
projectDir: string;
|
|
14
14
|
inputMode: 'auto' | 'disabled';
|
|
15
|
+
debug?: boolean;
|
|
15
16
|
yes?: boolean;
|
|
16
17
|
cliVersion?: string;
|
|
17
18
|
runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
|
package/dist/setup-databases.js
CHANGED
|
@@ -1206,7 +1206,10 @@ function hasServiceAccountsBlock(connection) {
|
|
|
1206
1206
|
}
|
|
1207
1207
|
return 'serviceAccounts' in filters;
|
|
1208
1208
|
}
|
|
1209
|
-
function printQueryHistoryFilterProposal(io, proposal) {
|
|
1209
|
+
function printQueryHistoryFilterProposal(io, proposal, debug = false) {
|
|
1210
|
+
if (debug && proposal.parseFailedTemplateIds.length > 0) {
|
|
1211
|
+
io.stderr.write(`[debug] query-history filter picker could not parse ${proposal.parseFailedTemplateIds.length} template(s): ${proposal.parseFailedTemplateIds.join(', ')}\n`);
|
|
1212
|
+
}
|
|
1210
1213
|
if (proposal.excludedRoles.length === 0) {
|
|
1211
1214
|
if (proposal.skipped?.reason === 'no-llm') {
|
|
1212
1215
|
io.stdout.write('│ Query-history filter picker skipped: no LLM is configured.\n');
|
|
@@ -1217,6 +1220,10 @@ function printQueryHistoryFilterProposal(io, proposal) {
|
|
|
1217
1220
|
else if (proposal.skipped?.reason === 'no-in-scope-history') {
|
|
1218
1221
|
io.stdout.write('│ Query-history filter picker found no in-scope service-account exclusions.\n');
|
|
1219
1222
|
}
|
|
1223
|
+
if (proposal.parseFailedTemplateIds.length > 0) {
|
|
1224
|
+
const count = proposal.parseFailedTemplateIds.length;
|
|
1225
|
+
io.stdout.write(`│ Skipped ${count} query template${count === 1 ? '' : 's'} ktx could not parse (run with --debug to list them).\n`);
|
|
1226
|
+
}
|
|
1220
1227
|
for (const warning of proposal.warnings) {
|
|
1221
1228
|
io.stdout.write(`│ ! ${warning}\n`);
|
|
1222
1229
|
}
|
|
@@ -1286,7 +1293,8 @@ async function maybeProposeQueryHistoryFilters(input) {
|
|
|
1286
1293
|
consideredRoleCount: 0,
|
|
1287
1294
|
skipped: { reason: 'no-llm' },
|
|
1288
1295
|
warnings: [],
|
|
1289
|
-
|
|
1296
|
+
parseFailedTemplateIds: [],
|
|
1297
|
+
}, input.args.debug === true);
|
|
1290
1298
|
return;
|
|
1291
1299
|
}
|
|
1292
1300
|
const runtime = createKtxCliHistoricSqlRuntime(project, input.connectionId, {
|
|
@@ -1325,7 +1333,19 @@ async function maybeProposeQueryHistoryFilters(input) {
|
|
|
1325
1333
|
pullConfig,
|
|
1326
1334
|
userServiceAccountsPresent,
|
|
1327
1335
|
});
|
|
1328
|
-
printQueryHistoryFilterProposal(input.io, proposal);
|
|
1336
|
+
printQueryHistoryFilterProposal(input.io, proposal, input.args.debug === true);
|
|
1337
|
+
await emitTelemetryEvent({
|
|
1338
|
+
name: 'query_history_filter_completed',
|
|
1339
|
+
projectDir: input.projectDir,
|
|
1340
|
+
io: input.io,
|
|
1341
|
+
fields: {
|
|
1342
|
+
dialect,
|
|
1343
|
+
consideredRoleCount: proposal.consideredRoleCount,
|
|
1344
|
+
excludedRoleCount: proposal.excludedRoles.length,
|
|
1345
|
+
parseFailedCount: proposal.parseFailedTemplateIds.length,
|
|
1346
|
+
outcome: 'ok',
|
|
1347
|
+
},
|
|
1348
|
+
});
|
|
1329
1349
|
if (proposal.skipped?.reason === 'user-block-present') {
|
|
1330
1350
|
input.io.stdout.write('│ Existing query-history service-account filters left unchanged.\n');
|
|
1331
1351
|
return;
|
package/dist/setup-demo-tour.js
CHANGED
package/dist/setup-embeddings.js
CHANGED
|
@@ -138,8 +138,8 @@ async function chooseCredentialRef(backend, args, io, deps) {
|
|
|
138
138
|
const choice = await prompts.select({
|
|
139
139
|
message: `How should KTX find your ${embeddingBackendDisplayName(backend)} embedding API key?`,
|
|
140
140
|
options: [
|
|
141
|
-
{ value: 'env', label: `Use ${defaultEnv} from the environment` },
|
|
142
141
|
{ value: 'paste', label: 'Paste a key and save it as a local secret file' },
|
|
142
|
+
{ value: 'env', label: `Use ${defaultEnv} from the environment` },
|
|
143
143
|
{ value: 'back', label: 'Back' },
|
|
144
144
|
],
|
|
145
145
|
});
|
package/dist/setup-models.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type KtxProjectLlmConfig } from './context/project/config.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type KtxLlmConfig } from './llm/types.js';
|
|
3
3
|
import { type KtxLlmHealthCheckResult } from './llm/model-health.js';
|
|
4
4
|
import { type KtxCliSpinner } from './clack.js';
|
|
5
5
|
import type { KtxCliIo } from './cli-runtime.js';
|
|
@@ -10,7 +10,6 @@ export interface KtxSetupModelArgs {
|
|
|
10
10
|
llmBackend?: KtxSetupLlmBackend;
|
|
11
11
|
anthropicApiKeyEnv?: string;
|
|
12
12
|
anthropicApiKeyFile?: string;
|
|
13
|
-
llmModel?: string;
|
|
14
13
|
vertexProject?: string;
|
|
15
14
|
vertexLocation?: string;
|
|
16
15
|
forcePrompt?: boolean;
|
|
@@ -33,12 +32,6 @@ export type KtxSetupModelResult = {
|
|
|
33
32
|
status: 'failed';
|
|
34
33
|
projectDir: string;
|
|
35
34
|
};
|
|
36
|
-
/** @internal */
|
|
37
|
-
export interface AnthropicModelChoice {
|
|
38
|
-
id: string;
|
|
39
|
-
label: string;
|
|
40
|
-
recommended: boolean;
|
|
41
|
-
}
|
|
42
35
|
export type KtxSetupLlmBackend = 'anthropic' | 'vertex' | 'claude-code' | 'codex';
|
|
43
36
|
/** @internal */
|
|
44
37
|
export interface KtxSetupModelPromptAdapter {
|
|
@@ -62,9 +55,7 @@ export interface KtxSetupModelPromptAdapter {
|
|
|
62
55
|
}
|
|
63
56
|
export interface KtxSetupModelDeps {
|
|
64
57
|
env?: NodeJS.ProcessEnv;
|
|
65
|
-
fetch?: typeof fetch;
|
|
66
58
|
prompts?: KtxSetupModelPromptAdapter;
|
|
67
|
-
listModels?: (apiKey: string) => Promise<AnthropicModelChoice[]>;
|
|
68
59
|
healthCheck?: (config: KtxLlmConfig) => Promise<KtxLlmHealthCheckResult>;
|
|
69
60
|
claudeCodeAuthProbe?: (input: {
|
|
70
61
|
projectDir: string;
|
|
@@ -89,14 +80,10 @@ export interface KtxSetupModelDeps {
|
|
|
89
80
|
listGcloudProjects?: () => Promise<GcloudProjectChoice[]>;
|
|
90
81
|
spinner?: () => KtxCliSpinner;
|
|
91
82
|
}
|
|
92
|
-
/** @internal */
|
|
93
|
-
export declare const BUNDLED_ANTHROPIC_MODELS: AnthropicModelChoice[];
|
|
94
83
|
interface GcloudProjectChoice {
|
|
95
84
|
projectId: string;
|
|
96
85
|
name?: string;
|
|
97
86
|
}
|
|
98
|
-
/** @internal */
|
|
99
|
-
export declare function fetchAnthropicModels(apiKey: string, fetchFn?: typeof fetch): Promise<AnthropicModelChoice[]>;
|
|
100
87
|
export declare function isKtxSetupLlmConfigReady(config: KtxProjectLlmConfig): boolean;
|
|
101
88
|
export declare function runKtxSetupAnthropicModelStep(args: KtxSetupModelArgs, io: KtxCliIo, deps?: KtxSetupModelDeps): Promise<KtxSetupModelResult>;
|
|
102
89
|
export {};
|