@kaelio/ktx 0.1.0-rc.5 → 0.1.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.
Files changed (180) hide show
  1. package/assets/python/kaelio_ktx-0.1.0-py3-none-any.whl +0 -0
  2. package/assets/python/manifest.json +2 -2
  3. package/dist/clack.d.ts +6 -0
  4. package/dist/clack.js +23 -0
  5. package/dist/cli-program.js +5 -2
  6. package/dist/cli-program.test.js +7 -1
  7. package/dist/cli-runtime.d.ts +4 -0
  8. package/dist/cli-runtime.js +8 -1
  9. package/dist/command-schemas.d.ts +1 -1
  10. package/dist/commands/ingest-commands.js +1 -0
  11. package/dist/commands/knowledge-commands.js +5 -0
  12. package/dist/commands/mcp-commands.js +11 -3
  13. package/dist/commands/mcp-commands.test.js +30 -1
  14. package/dist/commands/sql-commands.d.ts +3 -0
  15. package/dist/commands/sql-commands.js +43 -0
  16. package/dist/commands/sql-commands.test.d.ts +1 -0
  17. package/dist/commands/sql-commands.test.js +68 -0
  18. package/dist/context-build-view.js +5 -1
  19. package/dist/dev.test.js +27 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +1 -0
  22. package/dist/index.test.js +56 -21
  23. package/dist/ingest.js +123 -18
  24. package/dist/ingest.test.js +206 -0
  25. package/dist/io/print-list.d.ts +2 -1
  26. package/dist/io/print-list.js +7 -0
  27. package/dist/io/print-list.test.js +13 -11
  28. package/dist/io/symbols.d.ts +2 -2
  29. package/dist/knowledge.d.ts +1 -0
  30. package/dist/knowledge.js +34 -16
  31. package/dist/knowledge.test.js +27 -0
  32. package/dist/managed-python-command.d.ts +2 -0
  33. package/dist/managed-python-command.js +17 -9
  34. package/dist/managed-python-command.test.js +59 -4
  35. package/dist/next-steps.js +1 -1
  36. package/dist/next-steps.test.js +2 -0
  37. package/dist/print-command-tree.js +7 -1
  38. package/dist/public-ingest.d.ts +9 -1
  39. package/dist/public-ingest.js +50 -7
  40. package/dist/public-ingest.test.js +69 -2
  41. package/dist/release-version.d.ts +5 -0
  42. package/dist/release-version.js +44 -0
  43. package/dist/runtime-requirements.d.ts +23 -0
  44. package/dist/runtime-requirements.js +99 -0
  45. package/dist/runtime-requirements.test.d.ts +1 -0
  46. package/dist/runtime-requirements.test.js +63 -0
  47. package/dist/setup-agents.d.ts +11 -3
  48. package/dist/setup-agents.js +397 -134
  49. package/dist/setup-agents.test.js +359 -61
  50. package/dist/setup-embeddings.js +3 -6
  51. package/dist/setup-embeddings.test.js +18 -2
  52. package/dist/setup-models.js +2 -2
  53. package/dist/setup-models.test.js +5 -3
  54. package/dist/setup-ready-menu.d.ts +1 -1
  55. package/dist/setup-ready-menu.js +2 -0
  56. package/dist/setup-ready-menu.test.js +3 -0
  57. package/dist/setup-runtime.d.ts +45 -0
  58. package/dist/setup-runtime.js +47 -0
  59. package/dist/setup-runtime.test.d.ts +1 -0
  60. package/dist/setup-runtime.test.js +110 -0
  61. package/dist/setup-sources-notion.test.d.ts +1 -0
  62. package/dist/setup-sources-notion.test.js +107 -0
  63. package/dist/setup-sources.js +5 -2
  64. package/dist/setup.d.ts +19 -1
  65. package/dist/setup.js +104 -29
  66. package/dist/setup.test.js +221 -57
  67. package/dist/sl.js +2 -2
  68. package/dist/sl.test.js +10 -0
  69. package/dist/source-mapping.js +9 -1
  70. package/dist/source-mapping.test.d.ts +1 -0
  71. package/dist/source-mapping.test.js +65 -0
  72. package/dist/sql.d.ts +22 -0
  73. package/dist/sql.js +125 -0
  74. package/dist/sql.test.d.ts +1 -0
  75. package/dist/sql.test.js +226 -0
  76. package/node_modules/@ktx/connector-clickhouse/dist/package-exports.test.js +1 -1
  77. package/node_modules/@ktx/context/dist/connections/connection-type.d.ts +4 -4
  78. package/node_modules/@ktx/context/dist/core/git.service.d.ts +3 -0
  79. package/node_modules/@ktx/context/dist/core/git.service.js +47 -1
  80. package/node_modules/@ktx/context/dist/core/git.service.patch.test.d.ts +1 -0
  81. package/node_modules/@ktx/context/dist/core/git.service.patch.test.js +40 -0
  82. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/types.d.ts +5 -5
  83. package/node_modules/@ktx/context/dist/ingest/adapters/looker/looker.adapter.d.ts +2 -2
  84. package/node_modules/@ktx/context/dist/ingest/adapters/looker/tools/looker-query-to-sl.tool.d.ts +2 -2
  85. package/node_modules/@ktx/context/dist/ingest/adapters/looker/types.d.ts +16 -16
  86. package/node_modules/@ktx/context/dist/ingest/adapters/lookml/pull-config.d.ts +1 -1
  87. package/node_modules/@ktx/context/dist/ingest/adapters/metabase/fetch.js +16 -0
  88. package/node_modules/@ktx/context/dist/ingest/adapters/metabase/fetch.test.js +41 -0
  89. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/metricflow.adapter.d.ts +2 -1
  90. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/metricflow.adapter.js +40 -0
  91. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/metricflow.adapter.test.js +116 -1
  92. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/projection-config.d.ts +29 -0
  93. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/projection-config.js +40 -0
  94. package/node_modules/@ktx/context/dist/ingest/adapters/metricflow/pull-config.d.ts +1 -1
  95. package/node_modules/@ktx/context/dist/ingest/artifact-gates.d.ts +25 -0
  96. package/node_modules/@ktx/context/dist/ingest/artifact-gates.js +149 -0
  97. package/node_modules/@ktx/context/dist/ingest/artifact-gates.test.d.ts +1 -0
  98. package/node_modules/@ktx/context/dist/ingest/artifact-gates.test.js +167 -0
  99. package/node_modules/@ktx/context/dist/ingest/final-gate-repair.d.ts +29 -0
  100. package/node_modules/@ktx/context/dist/ingest/final-gate-repair.js +178 -0
  101. package/node_modules/@ktx/context/dist/ingest/final-gate-repair.test.d.ts +1 -0
  102. package/node_modules/@ktx/context/dist/ingest/final-gate-repair.test.js +109 -0
  103. package/node_modules/@ktx/context/dist/ingest/index.d.ts +8 -1
  104. package/node_modules/@ktx/context/dist/ingest/index.js +7 -0
  105. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.d.ts +18 -2
  106. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.isolated-diff.test.d.ts +1 -0
  107. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.isolated-diff.test.js +1761 -0
  108. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.js +1695 -901
  109. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.test.js +135 -118
  110. package/node_modules/@ktx/context/dist/ingest/ingest-trace.d.ts +50 -0
  111. package/node_modules/@ktx/context/dist/ingest/ingest-trace.js +88 -0
  112. package/node_modules/@ktx/context/dist/ingest/ingest-trace.test.d.ts +1 -0
  113. package/node_modules/@ktx/context/dist/ingest/ingest-trace.test.js +76 -0
  114. package/node_modules/@ktx/context/dist/ingest/isolated-diff/git-patch.d.ts +16 -0
  115. package/node_modules/@ktx/context/dist/ingest/isolated-diff/git-patch.js +78 -0
  116. package/node_modules/@ktx/context/dist/ingest/isolated-diff/git-patch.test.d.ts +1 -0
  117. package/node_modules/@ktx/context/dist/ingest/isolated-diff/git-patch.test.js +76 -0
  118. package/node_modules/@ktx/context/dist/ingest/isolated-diff/patch-integrator.d.ts +58 -0
  119. package/node_modules/@ktx/context/dist/ingest/isolated-diff/patch-integrator.js +223 -0
  120. package/node_modules/@ktx/context/dist/ingest/isolated-diff/patch-integrator.test.d.ts +1 -0
  121. package/node_modules/@ktx/context/dist/ingest/isolated-diff/patch-integrator.test.js +369 -0
  122. package/node_modules/@ktx/context/dist/ingest/isolated-diff/textual-conflict-resolver.d.ts +23 -0
  123. package/node_modules/@ktx/context/dist/ingest/isolated-diff/textual-conflict-resolver.js +190 -0
  124. package/node_modules/@ktx/context/dist/ingest/isolated-diff/textual-conflict-resolver.test.d.ts +1 -0
  125. package/node_modules/@ktx/context/dist/ingest/isolated-diff/textual-conflict-resolver.test.js +101 -0
  126. package/node_modules/@ktx/context/dist/ingest/isolated-diff/work-unit-executor.d.ts +15 -0
  127. package/node_modules/@ktx/context/dist/ingest/isolated-diff/work-unit-executor.js +61 -0
  128. package/node_modules/@ktx/context/dist/ingest/isolated-diff/work-unit-executor.test.d.ts +1 -0
  129. package/node_modules/@ktx/context/dist/ingest/isolated-diff/work-unit-executor.test.js +137 -0
  130. package/node_modules/@ktx/context/dist/ingest/local-bundle-ingest.test.js +7 -0
  131. package/node_modules/@ktx/context/dist/ingest/local-bundle-runtime.js +54 -10
  132. package/node_modules/@ktx/context/dist/ingest/local-bundle-runtime.test.js +65 -0
  133. package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.d.ts +23 -5
  134. package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.js +17 -0
  135. package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.test.js +1 -0
  136. package/node_modules/@ktx/context/dist/ingest/memory-flow/types.d.ts +6 -0
  137. package/node_modules/@ktx/context/dist/ingest/parsed-target-table.d.ts +1 -1
  138. package/node_modules/@ktx/context/dist/ingest/ports.d.ts +3 -0
  139. package/node_modules/@ktx/context/dist/ingest/report-snapshot.d.ts +32 -7
  140. package/node_modules/@ktx/context/dist/ingest/report-snapshot.js +25 -0
  141. package/node_modules/@ktx/context/dist/ingest/report-snapshot.test.js +124 -0
  142. package/node_modules/@ktx/context/dist/ingest/reports.d.ts +23 -0
  143. package/node_modules/@ktx/context/dist/ingest/semantic-layer-target-policy.d.ts +11 -0
  144. package/node_modules/@ktx/context/dist/ingest/semantic-layer-target-policy.js +26 -0
  145. package/node_modules/@ktx/context/dist/ingest/semantic-layer-target-policy.test.d.ts +1 -0
  146. package/node_modules/@ktx/context/dist/ingest/semantic-layer-target-policy.test.js +25 -0
  147. package/node_modules/@ktx/context/dist/ingest/stages/stage-3-work-units.d.ts +4 -0
  148. package/node_modules/@ktx/context/dist/ingest/stages/stage-3-work-units.js +4 -0
  149. package/node_modules/@ktx/context/dist/ingest/stages/stage-3-work-units.test.js +29 -0
  150. package/node_modules/@ktx/context/dist/ingest/tools/emit-unmapped-fallback.tool.d.ts +1 -1
  151. package/node_modules/@ktx/context/dist/ingest/types.d.ts +24 -0
  152. package/node_modules/@ktx/context/dist/ingest/wiki-body-refs.d.ts +24 -0
  153. package/node_modules/@ktx/context/dist/ingest/wiki-body-refs.js +111 -0
  154. package/node_modules/@ktx/context/dist/ingest/wiki-body-refs.test.d.ts +1 -0
  155. package/node_modules/@ktx/context/dist/ingest/wiki-body-refs.test.js +138 -0
  156. package/node_modules/@ktx/context/dist/llm/claude-code-runtime.js +19 -2
  157. package/node_modules/@ktx/context/dist/llm/claude-code-runtime.test.js +33 -0
  158. package/node_modules/@ktx/context/dist/project/setup-config.d.ts +1 -1
  159. package/node_modules/@ktx/context/dist/project/setup-config.js +10 -1
  160. package/node_modules/@ktx/context/dist/project/setup-config.test.js +3 -2
  161. package/node_modules/@ktx/context/dist/sl/tools/sl-edit-source.tool.js +5 -1
  162. package/node_modules/@ktx/context/dist/sl/tools/sl-edit-source.tool.test.js +15 -0
  163. package/node_modules/@ktx/context/dist/sl/tools/sl-write-source.tool.js +5 -1
  164. package/node_modules/@ktx/context/dist/sl/tools/sl-write-source.tool.test.js +22 -0
  165. package/node_modules/@ktx/context/dist/tools/action-target-connection.d.ts +9 -0
  166. package/node_modules/@ktx/context/dist/tools/action-target-connection.js +14 -0
  167. package/node_modules/@ktx/context/dist/tools/context-candidate-write.tool.d.ts +4 -4
  168. package/node_modules/@ktx/context/dist/tools/index.d.ts +1 -0
  169. package/node_modules/@ktx/context/dist/tools/index.js +1 -0
  170. package/node_modules/@ktx/context/dist/wiki/local-knowledge.js +4 -1
  171. package/node_modules/@ktx/context/dist/wiki/local-knowledge.test.js +44 -0
  172. package/node_modules/@ktx/context/dist/wiki/tools/wiki-write.tool.js +3 -48
  173. package/node_modules/@ktx/context/dist/wiki/tools/wiki-write.tool.test.js +28 -0
  174. package/node_modules/@ktx/context/dist/wiki/wiki-ref-validation.d.ts +17 -0
  175. package/node_modules/@ktx/context/dist/wiki/wiki-ref-validation.js +79 -0
  176. package/node_modules/@ktx/context/dist/wiki/wiki-ref-validation.test.d.ts +1 -0
  177. package/node_modules/@ktx/context/dist/wiki/wiki-ref-validation.test.js +64 -0
  178. package/node_modules/@ktx/context/prompts/memory_agent_bundle_ingest_work_unit.md +23 -4
  179. package/node_modules/@ktx/context/skills/ingest_triage/SKILL.md +7 -3
  180. package/package.json +4 -4
@@ -575,6 +575,42 @@ describe('runKtxPublicIngest', () => {
575
575
  }), io.io);
576
576
  expect(runScan).not.toHaveBeenCalled();
577
577
  });
578
+ it('preflights foreground query-history runtime before starting the context-build view', async () => {
579
+ const io = makeIo({ isTTY: true, interactive: true });
580
+ const calls = [];
581
+ const project = projectWithConnections({
582
+ warehouse: { driver: 'postgres', context: { depth: 'deep' } },
583
+ });
584
+ const ensureRuntime = vi.fn(async () => {
585
+ calls.push('runtime');
586
+ return {};
587
+ });
588
+ const runContextBuild = vi.fn(async () => {
589
+ calls.push('context-build');
590
+ return { exitCode: 0 };
591
+ });
592
+ await expect(runKtxPublicIngest({
593
+ command: 'run',
594
+ projectDir: '/tmp/project',
595
+ targetConnectionId: 'warehouse',
596
+ all: false,
597
+ json: false,
598
+ inputMode: 'auto',
599
+ queryHistory: 'enabled',
600
+ cliVersion: '0.2.0',
601
+ runtimeInstallPolicy: 'prompt',
602
+ }, io.io, {
603
+ loadProject: vi.fn(async () => project),
604
+ ensureRuntime,
605
+ runContextBuild,
606
+ })).resolves.toBe(0);
607
+ expect(calls).toEqual(['runtime', 'context-build']);
608
+ expect(ensureRuntime).toHaveBeenCalledWith(expect.objectContaining({
609
+ cliVersion: '0.2.0',
610
+ installPolicy: 'prompt',
611
+ feature: 'core',
612
+ }));
613
+ });
578
614
  it('runs all independent targets and reports partial failures', async () => {
579
615
  const io = makeIo();
580
616
  const project = projectWithConnections({
@@ -616,7 +652,10 @@ describe('runKtxPublicIngest', () => {
616
652
  warehouse: { driver: 'postgres', context: { depth: 'deep' } },
617
653
  });
618
654
  const runScan = vi.fn(async () => 0);
619
- const runIngest = vi.fn(async () => 1);
655
+ const runIngest = vi.fn(async (_args, ingestIo) => {
656
+ ingestIo.stdout.write('Error: Query history failed for 60 tasks. First failure: Google Cloud authentication failed while analyzing query history: application-default credentials expired or require reauthentication (invalid_grant / invalid_rapt). Run `gcloud auth application-default login`, then retry.\n');
657
+ return 1;
658
+ });
620
659
  await expect(runKtxPublicIngest({
621
660
  command: 'run',
622
661
  projectDir: '/tmp/project',
@@ -626,10 +665,38 @@ describe('runKtxPublicIngest', () => {
626
665
  inputMode: 'disabled',
627
666
  queryHistory: 'enabled',
628
667
  }, io.io, { loadProject: vi.fn(async () => project), runScan, runIngest })).resolves.toBe(1);
629
- expect(io.stdout()).toContain('warehouse failed at query-history.');
668
+ expect(io.stdout()).toMatch(/warehouse\s+done\s+failed\s+skipped\s+skipped/);
669
+ expect(io.stdout()).toContain('warehouse failed: Query history failed for 60 tasks. First failure: Google Cloud authentication failed while analyzing query history');
670
+ expect(io.stdout()).not.toContain('warehouse failed: Error:');
630
671
  expect(io.stdout()).toContain('Retry: ktx ingest warehouse --project-dir /tmp/project --deep --query-history');
631
672
  expect(io.stdout()).not.toContain('historic-sql');
632
673
  });
674
+ it('prints the runtime artifact build hint for missing query-history runtime assets', async () => {
675
+ const io = makeIo();
676
+ const project = deepReadyProject({
677
+ warehouse: { driver: 'postgres', context: { depth: 'deep' } },
678
+ });
679
+ const runScan = vi.fn(async () => 0);
680
+ const runIngest = vi.fn(async (_args, ingestIo) => {
681
+ ingestIo.stderr.write('Missing bundled Python runtime manifest: /repo/packages/cli/assets/python/manifest.json\n');
682
+ ingestIo.stderr.write('In a source checkout, build the local runtime assets with: pnpm run artifacts:build\n');
683
+ ingestIo.stderr.write('Then retry the runtime-backed KTX command.\n');
684
+ return 1;
685
+ });
686
+ await expect(runKtxPublicIngest({
687
+ command: 'run',
688
+ projectDir: '/tmp/project',
689
+ targetConnectionId: 'warehouse',
690
+ all: false,
691
+ json: false,
692
+ inputMode: 'disabled',
693
+ queryHistory: 'enabled',
694
+ }, io.io, { loadProject: vi.fn(async () => project), runScan, runIngest })).resolves.toBe(1);
695
+ expect(io.stdout()).toContain('Missing bundled Python runtime manifest');
696
+ expect(io.stdout()).toContain('In a source checkout, build the local runtime assets with: pnpm run artifacts:build');
697
+ expect(io.stdout()).toContain('Retry: ktx ingest warehouse --project-dir /tmp/project --deep --query-history');
698
+ expect(io.stdout()).not.toContain('Then retry the runtime-backed KTX command');
699
+ });
633
700
  it('fails deep-readiness targets before work starts while continuing independent --all targets', async () => {
634
701
  const io = makeIo();
635
702
  const project = projectWithConnections({
@@ -0,0 +1,5 @@
1
+ export declare function resolveKtxRuntimeVersion(input: {
2
+ packageName: string;
3
+ packageVersion: string;
4
+ startDir?: string;
5
+ }): string;
@@ -0,0 +1,44 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join, parse } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const semverPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
5
+ function isPlainObject(value) {
6
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
7
+ }
8
+ function assertReleaseVersion(value, source) {
9
+ if (typeof value !== 'string' || !semverPattern.test(value)) {
10
+ throw new Error(`Invalid KTX release version in ${source}`);
11
+ }
12
+ return value;
13
+ }
14
+ function findReleasePolicyPath(startDir) {
15
+ let current = startDir;
16
+ const root = parse(current).root;
17
+ while (true) {
18
+ const candidate = join(current, 'release-policy.json');
19
+ if (existsSync(candidate)) {
20
+ return candidate;
21
+ }
22
+ if (current === root) {
23
+ return undefined;
24
+ }
25
+ current = dirname(current);
26
+ }
27
+ }
28
+ function readSourceReleaseVersion(startDir = dirname(fileURLToPath(import.meta.url))) {
29
+ const policyPath = findReleasePolicyPath(startDir);
30
+ if (!policyPath) {
31
+ return undefined;
32
+ }
33
+ const policy = JSON.parse(readFileSync(policyPath, 'utf8'));
34
+ if (!isPlainObject(policy)) {
35
+ throw new Error(`Invalid KTX release policy: ${policyPath}`);
36
+ }
37
+ return assertReleaseVersion(policy.publicNpmPackageVersion, policyPath);
38
+ }
39
+ export function resolveKtxRuntimeVersion(input) {
40
+ if (input.packageName === '@kaelio/ktx') {
41
+ return assertReleaseVersion(input.packageVersion, `${input.packageName}/package.json`);
42
+ }
43
+ return readSourceReleaseVersion(input.startDir) ?? input.packageVersion;
44
+ }
@@ -0,0 +1,23 @@
1
+ import type { KtxProjectConfig } from '@ktx/context/project';
2
+ import type { KtxRuntimeFeature } from './managed-python-runtime.js';
3
+ import type { KtxPublicIngestPlan } from './public-ingest.js';
4
+ type KtxRuntimeRequirementReason = 'query-history' | 'looker-source' | 'database-introspection' | 'local-embeddings';
5
+ interface KtxRuntimeRequirement {
6
+ feature: KtxRuntimeFeature;
7
+ reason: KtxRuntimeRequirementReason;
8
+ detail: string;
9
+ }
10
+ export interface KtxRuntimeRequirements {
11
+ features: KtxRuntimeFeature[];
12
+ requirements: KtxRuntimeRequirement[];
13
+ }
14
+ export interface KtxProjectRuntimeRequirementOptions {
15
+ databaseIntrospectionFallback?: boolean;
16
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
17
+ }
18
+ export interface KtxPublicIngestRuntimeRequirementOptions {
19
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
20
+ }
21
+ export declare function resolveProjectRuntimeRequirements(config: KtxProjectConfig, options?: KtxProjectRuntimeRequirementOptions): KtxRuntimeRequirements;
22
+ export declare function resolvePublicIngestRuntimeRequirements(plan: KtxPublicIngestPlan, options?: KtxPublicIngestRuntimeRequirementOptions): KtxRuntimeRequirements;
23
+ export {};
@@ -0,0 +1,99 @@
1
+ import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context';
2
+ function normalizeDriver(driver) {
3
+ return String(driver ?? '').trim().toLowerCase();
4
+ }
5
+ function recordValue(value) {
6
+ return typeof value === 'object' && value !== null ? value : {};
7
+ }
8
+ function hasEnabledQueryHistory(connection) {
9
+ const context = recordValue(recordValue(connection).context);
10
+ const queryHistory = recordValue(context.queryHistory);
11
+ return queryHistory.enabled === true;
12
+ }
13
+ function hasDaemonOverride(env) {
14
+ return typeof env.KTX_DAEMON_URL === 'string' && env.KTX_DAEMON_URL.trim().length > 0;
15
+ }
16
+ function hasSqlAnalysisOverride(env) {
17
+ return ((typeof env.KTX_SQL_ANALYSIS_URL === 'string' && env.KTX_SQL_ANALYSIS_URL.trim().length > 0) ||
18
+ hasDaemonOverride(env));
19
+ }
20
+ function requiresManagedLocalEmbeddings(embeddings) {
21
+ if (embeddings.backend !== 'sentence-transformers') {
22
+ return false;
23
+ }
24
+ const baseUrl = embeddings.sentenceTransformers?.base_url;
25
+ return baseUrl === undefined || baseUrl === '' || baseUrl === MANAGED_SENTENCE_TRANSFORMERS_BASE_URL;
26
+ }
27
+ function uniqueRequirements(requirements) {
28
+ const seen = new Set();
29
+ const deduped = [];
30
+ for (const requirement of requirements) {
31
+ const key = `${requirement.feature}:${requirement.reason}:${requirement.detail}`;
32
+ if (seen.has(key)) {
33
+ continue;
34
+ }
35
+ seen.add(key);
36
+ deduped.push(requirement);
37
+ }
38
+ const features = [...new Set(deduped.map((requirement) => requirement.feature))].sort((left, right) => left.localeCompare(right));
39
+ return { features, requirements: deduped };
40
+ }
41
+ export function resolveProjectRuntimeRequirements(config, options = {}) {
42
+ const env = options.env ?? process.env;
43
+ const requirements = [];
44
+ if (options.databaseIntrospectionFallback === true && !hasDaemonOverride(env)) {
45
+ requirements.push({
46
+ feature: 'core',
47
+ reason: 'database-introspection',
48
+ detail: 'Database introspection fallback uses the Python daemon.',
49
+ });
50
+ }
51
+ for (const [connectionId, connection] of Object.entries(config.connections)) {
52
+ const driver = normalizeDriver(connection.driver);
53
+ if ((driver === 'looker' || driver === 'local_looker') && !hasDaemonOverride(env)) {
54
+ requirements.push({
55
+ feature: 'core',
56
+ reason: 'looker-source',
57
+ detail: `${connectionId} uses Looker identifier parsing.`,
58
+ });
59
+ }
60
+ if (hasEnabledQueryHistory(connection) && !hasSqlAnalysisOverride(env)) {
61
+ requirements.push({
62
+ feature: 'core',
63
+ reason: 'query-history',
64
+ detail: `${connectionId} has query history enabled.`,
65
+ });
66
+ }
67
+ }
68
+ if (requiresManagedLocalEmbeddings(config.ingest.embeddings)) {
69
+ requirements.push({
70
+ feature: 'local-embeddings',
71
+ reason: 'local-embeddings',
72
+ detail: 'Local sentence-transformers embeddings use the managed Python runtime.',
73
+ });
74
+ }
75
+ return uniqueRequirements(requirements);
76
+ }
77
+ export function resolvePublicIngestRuntimeRequirements(plan, options = {}) {
78
+ const env = options.env ?? process.env;
79
+ const requirements = [];
80
+ for (const target of plan.targets) {
81
+ const driver = normalizeDriver(target.driver);
82
+ const adapter = normalizeDriver(target.adapter);
83
+ if (target.queryHistory?.enabled === true && !hasSqlAnalysisOverride(env)) {
84
+ requirements.push({
85
+ feature: 'core',
86
+ reason: 'query-history',
87
+ detail: `${target.connectionId} query-history ingest uses SQL analysis.`,
88
+ });
89
+ }
90
+ if ((driver === 'looker' || driver === 'local_looker' || adapter === 'looker') && !hasDaemonOverride(env)) {
91
+ requirements.push({
92
+ feature: 'core',
93
+ reason: 'looker-source',
94
+ detail: `${target.connectionId} uses Looker identifier parsing.`,
95
+ });
96
+ }
97
+ }
98
+ return uniqueRequirements(requirements);
99
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context';
2
+ import { buildDefaultKtxProjectConfig } from '@ktx/context/project';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { resolveProjectRuntimeRequirements, resolvePublicIngestRuntimeRequirements, } from './runtime-requirements.js';
5
+ describe('runtime requirement detection', () => {
6
+ it('does not require runtime for agent/MCP setup alone', () => {
7
+ const config = buildDefaultKtxProjectConfig();
8
+ expect(resolveProjectRuntimeRequirements(config).features).toEqual([]);
9
+ });
10
+ it('requires core for Looker source ingest unless an external daemon is configured', () => {
11
+ const config = {
12
+ ...buildDefaultKtxProjectConfig(),
13
+ connections: {
14
+ looker: { driver: 'looker', base_url: 'https://looker.example.com', client_id: 'client-id' },
15
+ },
16
+ };
17
+ expect(resolveProjectRuntimeRequirements(config).features).toEqual(['core']);
18
+ expect(resolveProjectRuntimeRequirements(config, { env: { KTX_DAEMON_URL: 'http://127.0.0.1:8765' } }).features).toEqual([]);
19
+ });
20
+ it('requires core for query-history ingest unless SQL analysis is externally configured', () => {
21
+ const config = {
22
+ ...buildDefaultKtxProjectConfig(),
23
+ connections: {
24
+ warehouse: { driver: 'postgres', context: { queryHistory: { enabled: true } } },
25
+ },
26
+ };
27
+ expect(resolveProjectRuntimeRequirements(config).features).toEqual(['core']);
28
+ expect(resolveProjectRuntimeRequirements(config, { env: { KTX_SQL_ANALYSIS_URL: 'http://127.0.0.1:8765' } }).features).toEqual([]);
29
+ });
30
+ it('requires local-embeddings for managed sentence-transformers embeddings', () => {
31
+ const config = {
32
+ ...buildDefaultKtxProjectConfig(),
33
+ ingest: {
34
+ ...buildDefaultKtxProjectConfig().ingest,
35
+ embeddings: {
36
+ backend: 'sentence-transformers',
37
+ model: 'all-MiniLM-L6-v2',
38
+ dimensions: 384,
39
+ sentenceTransformers: {
40
+ base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL,
41
+ },
42
+ },
43
+ },
44
+ };
45
+ expect(resolveProjectRuntimeRequirements(config).features).toEqual(['local-embeddings']);
46
+ });
47
+ it('detects foreground ingest runtime needs from selected query-history targets', () => {
48
+ expect(resolvePublicIngestRuntimeRequirements({
49
+ projectDir: '/tmp/project',
50
+ warnings: [],
51
+ targets: [
52
+ {
53
+ connectionId: 'warehouse',
54
+ driver: 'postgres',
55
+ operation: 'database-ingest',
56
+ debugCommand: 'ktx ingest warehouse --debug',
57
+ steps: ['database-schema', 'query-history'],
58
+ queryHistory: { enabled: true },
59
+ },
60
+ ],
61
+ }).features).toEqual(['core']);
62
+ });
63
+ });
@@ -12,6 +12,7 @@ export interface KtxSetupAgentsArgs {
12
12
  scope: KtxAgentScope;
13
13
  mode: KtxAgentInstallMode;
14
14
  skipAgents: boolean;
15
+ showNextActions?: boolean;
15
16
  }
16
17
  export type KtxSetupAgentsResult = {
17
18
  status: 'ready';
@@ -21,6 +22,7 @@ export type KtxSetupAgentsResult = {
21
22
  scope: KtxAgentScope;
22
23
  mode: KtxAgentInstallMode;
23
24
  }>;
25
+ nextActions?: string;
24
26
  } | {
25
27
  status: 'skipped';
26
28
  projectDir: string;
@@ -46,7 +48,7 @@ export interface KtxAgentInstallManifest {
46
48
  entries: Array<{
47
49
  kind: 'file';
48
50
  path: string;
49
- role?: 'skill' | 'rule' | 'analytics-skill' | 'claude-plugin' | 'launcher';
51
+ role?: 'skill' | 'rule' | 'analytics-skill' | 'claude-desktop-skill-bundle' | 'launcher';
50
52
  } | {
51
53
  kind: 'json-key';
52
54
  path: string;
@@ -54,6 +56,7 @@ export interface KtxAgentInstallManifest {
54
56
  }>;
55
57
  }
56
58
  type InstallEntry = KtxAgentInstallManifest['entries'][number];
59
+ export declare function createAgentNextActionsLineFormatter(stdout: KtxCliIo['stdout']): (line: string) => string;
57
60
  export declare function collectClaudeDesktopForwardedEnv(source: NodeJS.ProcessEnv): Record<string, string>;
58
61
  export declare function agentInstallManifestPath(projectDir: string): string;
59
62
  export declare function plannedKtxAgentFiles(input: {
@@ -79,10 +82,15 @@ export interface KtxSetupAgentsPromptAdapter {
79
82
  export interface KtxSetupAgentsDeps {
80
83
  prompts?: KtxSetupAgentsPromptAdapter;
81
84
  }
82
- export declare function formatInstallSummary(installs: Array<{
85
+ export declare function targetDisplayName(target: string): string;
86
+ export interface InstallSummaryEntry {
87
+ title: string;
88
+ lines: string[];
89
+ }
90
+ export declare function formatInstallSummaryLines(installs: Array<{
83
91
  target: KtxAgentTarget;
84
92
  scope: KtxAgentScope;
85
93
  mode: KtxAgentInstallMode;
86
- }>, entries: InstallEntry[], projectDir: string): string;
94
+ }>, entries: InstallEntry[], projectDir: string): InstallSummaryEntry[];
87
95
  export declare function runKtxSetupAgentsStep(args: KtxSetupAgentsArgs, io: KtxCliIo, deps?: KtxSetupAgentsDeps): Promise<KtxSetupAgentsResult>;
88
96
  export {};