@kaelio/ktx 0.10.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.
Files changed (193) hide show
  1. package/assets/python/{kaelio_ktx-0.10.0-py3-none-any.whl → kaelio_ktx-0.12.0-py3-none-any.whl} +0 -0
  2. package/assets/python/manifest.json +4 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/admin.js +1 -1
  5. package/dist/clack.d.ts +16 -0
  6. package/dist/clack.js +37 -6
  7. package/dist/claude-code-prompt-caching.js +1 -1
  8. package/dist/cli-program.js +7 -3
  9. package/dist/cli-runtime.d.ts +2 -0
  10. package/dist/cli-runtime.js +14 -8
  11. package/dist/commands/connection-commands.js +1 -1
  12. package/dist/commands/ingest-commands.js +4 -4
  13. package/dist/commands/mcp-commands.js +12 -12
  14. package/dist/commands/runtime-commands.js +4 -4
  15. package/dist/commands/setup-commands.js +6 -5
  16. package/dist/commands/sl-commands.js +1 -1
  17. package/dist/commands/sql-commands.js +1 -1
  18. package/dist/commands/status-commands.js +1 -1
  19. package/dist/community-cta.d.ts +11 -0
  20. package/dist/community-cta.js +19 -0
  21. package/dist/connection.js +1 -1
  22. package/dist/connectors/clickhouse/connector.js +1 -1
  23. package/dist/connectors/mysql/connector.js +1 -1
  24. package/dist/connectors/snowflake/connector.d.ts +1 -1
  25. package/dist/connectors/sqlite/connector.js +2 -25
  26. package/dist/connectors/sqlserver/connector.js +3 -3
  27. package/dist/context/connections/connection-type.d.ts +1 -1
  28. package/dist/context/connections/read-only-sql.d.ts +1 -0
  29. package/dist/context/connections/read-only-sql.js +116 -2
  30. package/dist/context/core/git-env.d.ts +12 -1
  31. package/dist/context/core/git-env.js +17 -2
  32. package/dist/context/core/git.service.d.ts +23 -0
  33. package/dist/context/core/git.service.js +86 -15
  34. package/dist/context/ingest/adapters/historic-sql/projection.js +2 -1
  35. package/dist/context/ingest/adapters/looker/client.js +7 -2
  36. package/dist/context/ingest/adapters/looker/factory.d.ts +8 -1
  37. package/dist/context/ingest/adapters/looker/factory.js +9 -0
  38. package/dist/context/ingest/adapters/looker/mapping.js +1 -1
  39. package/dist/context/ingest/adapters/looker/types.d.ts +1 -1
  40. package/dist/context/ingest/adapters/metabase/client.d.ts +1 -1
  41. package/dist/context/ingest/adapters/metabase/client.js +1 -1
  42. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.js +1 -1
  43. package/dist/context/ingest/adapters/metabase/mapping.js +6 -6
  44. package/dist/context/ingest/artifact-gates.d.ts +2 -6
  45. package/dist/context/ingest/artifact-gates.js +5 -47
  46. package/dist/context/ingest/constrained-repair.d.ts +55 -0
  47. package/dist/context/ingest/constrained-repair.js +167 -0
  48. package/dist/context/ingest/final-gate-repair.d.ts +9 -11
  49. package/dist/context/ingest/final-gate-repair.js +40 -128
  50. package/dist/context/ingest/finalization-scope.d.ts +1 -1
  51. package/dist/context/ingest/finalization-scope.js +15 -15
  52. package/dist/context/ingest/ingest-bundle.runner.d.ts +1 -0
  53. package/dist/context/ingest/ingest-bundle.runner.js +101 -67
  54. package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +6 -13
  55. package/dist/context/ingest/isolated-diff/patch-integrator.js +32 -109
  56. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.d.ts +8 -9
  57. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.js +63 -141
  58. package/dist/context/ingest/local-bundle-runtime.d.ts +2 -0
  59. package/dist/context/ingest/local-bundle-runtime.js +9 -10
  60. package/dist/context/ingest/local-ingest.d.ts +2 -0
  61. package/dist/context/ingest/local-ingest.js +2 -0
  62. package/dist/context/ingest/memory-flow/view-model.js +1 -1
  63. package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -6
  64. package/dist/context/ingest/stages/stage-3-work-units.js +2 -1
  65. package/dist/context/ingest/stages/validate-wu-sources.d.ts +7 -1
  66. package/dist/context/ingest/stages/validate-wu-sources.js +109 -4
  67. package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.d.ts +2 -0
  68. package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.js +1 -1
  69. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +3 -3
  70. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.d.ts +3 -1
  71. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +15 -1
  72. package/dist/context/llm/ai-sdk-runtime.js +2 -2
  73. package/dist/context/llm/claude-code-runtime.js +1 -1
  74. package/dist/context/llm/local-config.js +1 -1
  75. package/dist/context/llm/runtime-tools.js +2 -2
  76. package/dist/context/mcp/context-tools.js +7 -7
  77. package/dist/context/mcp/local-project-ports.js +23 -54
  78. package/dist/context/memory/local-memory.js +4 -1
  79. package/dist/context/memory/memory-agent.service.js +1 -1
  80. package/dist/context/project/config.d.ts +11 -4
  81. package/dist/context/project/config.js +85 -30
  82. package/dist/context/project/driver-schemas.js +1 -1
  83. package/dist/context/project/mappings-yaml-schema.js +2 -2
  84. package/dist/context/project/project.js +12 -4
  85. package/dist/context/scan/description-generation.js +4 -4
  86. package/dist/context/scan/local-enrichment-artifacts.js +2 -1
  87. package/dist/context/scan/local-scan.js +2 -2
  88. package/dist/context/scan/local-structural-artifacts.js +5 -5
  89. package/dist/context/scan/relationship-benchmark-report.js +1 -1
  90. package/dist/context/scan/relationship-discovery.js +3 -3
  91. package/dist/context/scan/relationship-llm-proposal.js +3 -3
  92. package/dist/context/sl/local-query.js +3 -33
  93. package/dist/context/sl/local-sl.d.ts +0 -8
  94. package/dist/context/sl/local-sl.js +44 -69
  95. package/dist/context/sl/semantic-layer.service.d.ts +25 -8
  96. package/dist/context/sl/semantic-layer.service.js +109 -56
  97. package/dist/context/sl/source-files.d.ts +46 -0
  98. package/dist/context/sl/source-files.js +131 -0
  99. package/dist/context/sl/tools/base-semantic-layer.tool.d.ts +2 -2
  100. package/dist/context/sl/tools/base-semantic-layer.tool.js +2 -7
  101. package/dist/context/sl/tools/sl-edit-source.tool.js +10 -8
  102. package/dist/context/sl/tools/sl-warehouse-validation.js +55 -27
  103. package/dist/context/sl/tools/sl-write-source.tool.js +12 -9
  104. package/dist/context/sql-analysis/dialect.d.ts +2 -0
  105. package/dist/context/sql-analysis/dialect.js +20 -0
  106. package/dist/context/tools/base-tool.d.ts +6 -19
  107. package/dist/context/tools/base-tool.js +0 -14
  108. package/dist/context-build-view.js +5 -5
  109. package/dist/database-tree-picker.js +18 -3
  110. package/dist/demo-assets.js +0 -1
  111. package/dist/doctor.d.ts +1 -1
  112. package/dist/doctor.js +31 -23
  113. package/dist/errors.d.ts +31 -0
  114. package/dist/errors.js +44 -0
  115. package/dist/ingest.d.ts +1 -1
  116. package/dist/ingest.js +8 -2
  117. package/dist/io/symbols.d.ts +2 -0
  118. package/dist/io/symbols.js +2 -0
  119. package/dist/io/tty.d.ts +17 -0
  120. package/dist/io/tty.js +21 -0
  121. package/dist/links.d.ts +1 -0
  122. package/dist/links.js +1 -0
  123. package/dist/llm/embedding-health.js +1 -1
  124. package/dist/llm/embedding-provider.js +3 -3
  125. package/dist/llm/model-provider.js +1 -1
  126. package/dist/local-adapters.d.ts +1 -0
  127. package/dist/local-adapters.js +2 -2
  128. package/dist/local-scan-connectors.js +1 -1
  129. package/dist/managed-local-embeddings.js +17 -8
  130. package/dist/managed-mcp-daemon.js +3 -3
  131. package/dist/managed-python-command.d.ts +7 -0
  132. package/dist/managed-python-command.js +34 -8
  133. package/dist/managed-python-daemon.js +2 -2
  134. package/dist/managed-python-http.js +3 -3
  135. package/dist/managed-python-runtime.d.ts +30 -1
  136. package/dist/managed-python-runtime.js +134 -18
  137. package/dist/managed-uv-release.d.ts +7 -0
  138. package/dist/managed-uv-release.js +11 -0
  139. package/dist/mcp-http-server.js +4 -4
  140. package/dist/mcp-server-factory.js +3 -3
  141. package/dist/mcp-stdio-server.js +1 -1
  142. package/dist/memory-flow-hud.js +2 -2
  143. package/dist/next-steps.js +2 -2
  144. package/dist/prompt-navigation.d.ts +17 -0
  145. package/dist/prompt-navigation.js +49 -3
  146. package/dist/prompts/memory_agent_bundle_ingest_work_unit.md +2 -2
  147. package/dist/prompts/memory_agent_external_ingest.md +2 -2
  148. package/dist/public-ingest-copy.js +1 -1
  149. package/dist/public-ingest.js +3 -3
  150. package/dist/release-version.js +1 -1
  151. package/dist/runtime-requirements.js +1 -1
  152. package/dist/runtime.js +9 -9
  153. package/dist/scan.js +1 -1
  154. package/dist/setup-agents.js +22 -35
  155. package/dist/setup-banner.d.ts +20 -0
  156. package/dist/setup-banner.js +39 -0
  157. package/dist/setup-context.js +24 -15
  158. package/dist/setup-databases.js +31 -59
  159. package/dist/setup-demo-tour.js +12 -8
  160. package/dist/setup-embeddings.js +9 -9
  161. package/dist/setup-interrupt.js +1 -1
  162. package/dist/setup-models.d.ts +4 -1
  163. package/dist/setup-models.js +54 -28
  164. package/dist/setup-project.js +29 -5
  165. package/dist/setup-prompts.js +16 -5
  166. package/dist/setup-ready-menu.js +1 -1
  167. package/dist/setup-sources.js +27 -7
  168. package/dist/setup.d.ts +25 -0
  169. package/dist/setup.js +90 -19
  170. package/dist/skills/analytics/SKILL.md +3 -3
  171. package/dist/skills/dbt_ingest/SKILL.md +3 -3
  172. package/dist/skills/looker_ingest/SKILL.md +3 -3
  173. package/dist/skills/lookml_ingest/SKILL.md +7 -7
  174. package/dist/skills/metabase_ingest/SKILL.md +4 -4
  175. package/dist/skills/metricflow_ingest/SKILL.md +15 -15
  176. package/dist/skills/notion_synthesize/SKILL.md +1 -1
  177. package/dist/skills/sl/SKILL.md +3 -3
  178. package/dist/skills/sl_capture/SKILL.md +1 -1
  179. package/dist/skills/wiki_capture/SKILL.md +1 -1
  180. package/dist/source-mapping.js +1 -1
  181. package/dist/startup-profile.js +1 -1
  182. package/dist/status-project.d.ts +0 -2
  183. package/dist/status-project.js +4 -6
  184. package/dist/telemetry/command-hook.d.ts +24 -0
  185. package/dist/telemetry/command-hook.js +37 -3
  186. package/dist/telemetry/events.d.ts +1 -1
  187. package/dist/telemetry/exception.js +14 -0
  188. package/dist/telemetry/index.d.ts +2 -2
  189. package/dist/telemetry/index.js +2 -2
  190. package/dist/text-ingest.js +1 -1
  191. package/dist/tree-picker-tui.d.ts +0 -1
  192. package/dist/tree-picker-tui.js +2 -3
  193. package/package.json +1 -1
@@ -1,12 +1,14 @@
1
1
  import { execFile } from 'node:child_process';
2
2
  import { createHash } from 'node:crypto';
3
- import { access, appendFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { access, appendFile, chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
4
4
  import { homedir } from 'node:os';
5
- import { basename, join } from 'node:path';
5
+ import { basename, dirname, join } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { promisify } from 'node:util';
8
- import { strFromU8, unzipSync } from 'fflate';
8
+ import { gunzipSync, strFromU8, unzipSync } from 'fflate';
9
9
  import { z } from 'zod';
10
+ import { KtxExpectedError } from './errors.js';
11
+ import { MANAGED_UV_ARTIFACTS, MANAGED_UV_VERSION, } from './managed-uv-release.js';
10
12
  const execFileAsync = promisify(execFile);
11
13
  export const runtimeFeatureSchema = z.enum(['core', 'local-embeddings']);
12
14
  const runtimeAssetManifestSchema = z.object({
@@ -32,8 +34,10 @@ const installedRuntimeManifestSchema = z.object({
32
34
  }),
33
35
  installLog: z.string().min(1),
34
36
  });
35
- /** @internal */
36
- export const MISSING_UV_RUNTIME_INSTALL_MESSAGE = 'uv is required to install the KTX Python runtime. KTX does not download uv automatically. Install uv, make sure it is on PATH, and retry: ktx admin runtime install --yes';
37
+ const PINNED_UV_RELEASE = {
38
+ version: MANAGED_UV_VERSION,
39
+ artifacts: MANAGED_UV_ARTIFACTS,
40
+ };
37
41
  function defaultAssetDir() {
38
42
  return fileURLToPath(new URL('../assets/python/', import.meta.url));
39
43
  }
@@ -144,7 +148,7 @@ export async function verifyRuntimeAsset(input) {
144
148
  throw new Error([
145
149
  `Missing bundled Python runtime manifest: ${manifestPath}`,
146
150
  'In a source checkout, build the local runtime assets with: pnpm run artifacts:build',
147
- 'Then retry the runtime-backed KTX command.',
151
+ 'Then retry the runtime-backed ktx command.',
148
152
  ].join('\n'));
149
153
  }
150
154
  throw error;
@@ -221,13 +225,123 @@ async function runLogged(input) {
221
225
  function managedRuntimeUvEnv(baseEnv) {
222
226
  return { ...baseEnv, UV_NO_CONFIG: '1' };
223
227
  }
224
- async function ensureUv(exec, env) {
228
+ function managedUvBinaryName(platform) {
229
+ return platform === 'win32' ? 'uv.exe' : 'uv';
230
+ }
231
+ /** @internal */
232
+ export function managedUvPath(options = {}) {
233
+ const platform = options.platform ?? process.platform;
234
+ const env = options.env ?? process.env;
235
+ const homeDir = options.homeDir ?? homedir();
236
+ const runtimeRoot = options.runtimeRoot ?? runtimeRootFor({ env, homeDir });
237
+ const version = (options.release ?? PINNED_UV_RELEASE).version;
238
+ return join(runtimeRoot, 'uv', version, managedUvBinaryName(platform));
239
+ }
240
+ async function defaultFetchUvArtifact(url) {
241
+ const response = await fetch(url);
242
+ if (!response.ok) {
243
+ throw new Error(`HTTP ${response.status}`);
244
+ }
245
+ return new Uint8Array(await response.arrayBuffer());
246
+ }
247
+ function readTarField(block, start, length) {
248
+ const field = block.subarray(start, start + length);
249
+ const end = field.indexOf(0);
250
+ return strFromU8(end < 0 ? field : field.subarray(0, end));
251
+ }
252
+ function findTarEntry(archive, matches) {
253
+ let offset = 0;
254
+ while (offset + 512 <= archive.length) {
255
+ const block = archive.subarray(offset, offset + 512);
256
+ const name = readTarField(block, 0, 100);
257
+ if (!name) {
258
+ return undefined;
259
+ }
260
+ const size = Number.parseInt(readTarField(block, 124, 12).trim() || '0', 8);
261
+ if (matches(name)) {
262
+ return archive.subarray(offset + 512, offset + 512 + size);
263
+ }
264
+ offset += 512 + Math.ceil(size / 512) * 512;
265
+ }
266
+ return undefined;
267
+ }
268
+ function extractUvFromArchive(input) {
269
+ const entry = input.file.endsWith('.zip')
270
+ ? unzipSync(input.contents)[input.binaryName]
271
+ : findTarEntry(gunzipSync(input.contents), (name) => name === input.binaryName || name.endsWith(`/${input.binaryName}`));
272
+ if (!entry) {
273
+ throw new Error(`uv archive ${input.file} is missing the ${input.binaryName} binary`);
274
+ }
275
+ return entry;
276
+ }
277
+ /**
278
+ * ktx provisions its own pinned uv under the runtime root; uv on PATH is never
279
+ * consulted, so runtime installs behave identically on every machine. All
280
+ * failures here are environment outcomes (offline host, intercepting proxy,
281
+ * unsupported platform) and stay out of Error Tracking via KtxExpectedError —
282
+ * except a pin/layout mismatch inside a checksum-verified archive, which is a
283
+ * ktx release fault and must reach Error Tracking.
284
+ * @internal
285
+ */
286
+ export async function ensureManagedUv(options = {}) {
287
+ const platform = options.platform ?? process.platform;
288
+ const arch = options.arch ?? process.arch;
289
+ const release = options.release ?? PINNED_UV_RELEASE;
290
+ const binaryName = managedUvBinaryName(platform);
291
+ const uvPath = managedUvPath(options);
292
+ if (await pathExists(uvPath)) {
293
+ return uvPath;
294
+ }
295
+ const artifact = release.artifacts[`${platform}-${arch}`];
296
+ if (!artifact) {
297
+ throw new KtxExpectedError(`ktx does not bundle uv for ${platform}-${arch}. Place a uv ${release.version} binary at ${uvPath} and retry: ktx admin runtime install --yes`);
298
+ }
299
+ const url = `https://github.com/astral-sh/uv/releases/download/${release.version}/${artifact.file}`;
300
+ let contents;
225
301
  try {
226
- const result = await exec('uv', ['--version'], { env });
227
- return result.stdout.trim() || 'uv available';
302
+ contents = await (options.fetchArtifact ?? defaultFetchUvArtifact)(url);
228
303
  }
229
- catch {
230
- throw new Error(MISSING_UV_RUNTIME_INSTALL_MESSAGE);
304
+ catch (error) {
305
+ throw new KtxExpectedError(`ktx could not download uv ${release.version} (required to install the ktx Python runtime). ` +
306
+ 'Check network access to github.com and retry: ktx admin runtime install --yes. ' +
307
+ `Air-gapped hosts: place the uv binary at ${uvPath}.`, { cause: error });
308
+ }
309
+ const sha256 = createHash('sha256').update(contents).digest('hex');
310
+ if (sha256 !== artifact.sha256) {
311
+ throw new KtxExpectedError(`Downloaded uv ${release.version} failed checksum verification (a proxy or captive portal may have altered the download). Retry: ktx admin runtime install --yes`);
312
+ }
313
+ const binary = extractUvFromArchive({ file: artifact.file, contents, binaryName });
314
+ await mkdir(dirname(uvPath), { recursive: true });
315
+ const stagedPath = `${uvPath}.${process.pid}.download`;
316
+ await writeFile(stagedPath, binary);
317
+ await chmod(stagedPath, 0o755);
318
+ try {
319
+ await rename(stagedPath, uvPath);
320
+ }
321
+ catch (error) {
322
+ // On Windows a concurrent install may have won the rename; the binary at
323
+ // uvPath is checksum-pinned identical, so reuse it.
324
+ await rm(stagedPath, { force: true });
325
+ if (!(await pathExists(uvPath))) {
326
+ throw error;
327
+ }
328
+ }
329
+ return uvPath;
330
+ }
331
+ async function ensureUv(input) {
332
+ const uvPath = await ensureManagedUv({
333
+ platform: input.options.platform,
334
+ env: input.options.env,
335
+ homeDir: input.options.homeDir,
336
+ runtimeRoot: input.options.runtimeRoot,
337
+ fetchArtifact: input.options.fetchUvArtifact,
338
+ });
339
+ try {
340
+ const result = await input.exec(uvPath, ['--version'], { env: input.uvEnv });
341
+ return { uvPath, version: result.stdout.trim() || `uv ${MANAGED_UV_VERSION}` };
342
+ }
343
+ catch (error) {
344
+ throw new KtxExpectedError(`Managed uv at ${uvPath} failed to run. Delete it and retry: ktx admin runtime install --yes`, { cause: error });
231
345
  }
232
346
  }
233
347
  export async function installManagedPythonRuntime(options) {
@@ -246,21 +360,23 @@ export async function installManagedPythonRuntime(options) {
246
360
  (await pathExists(existing.python.daemonExecutable))) {
247
361
  return { status: 'ready', layout, asset, manifest: existing };
248
362
  }
363
+ // uv is acquired before the version dir is wiped, so a failed acquisition
364
+ // never destroys a previously installed runtime.
365
+ const { uvPath } = await ensureUv({ exec, uvEnv, options });
249
366
  await rm(layout.versionDir, { recursive: true, force: true });
250
367
  await mkdir(layout.versionDir, { recursive: true });
251
368
  await writeFile(layout.installLogPath, '');
252
- await ensureUv(exec, uvEnv);
253
369
  await runLogged({
254
370
  exec,
255
371
  logPath: layout.installLogPath,
256
- command: 'uv',
372
+ command: uvPath,
257
373
  args: ['python', 'install', asset.requiresPython.minimumVersion],
258
374
  env: uvEnv,
259
375
  });
260
376
  await runLogged({
261
377
  exec,
262
378
  logPath: layout.installLogPath,
263
- command: 'uv',
379
+ command: uvPath,
264
380
  args: ['venv', '--python', asset.requiresPython.minimumVersion, layout.venvDir],
265
381
  env: uvEnv,
266
382
  });
@@ -268,7 +384,7 @@ export async function installManagedPythonRuntime(options) {
268
384
  await runLogged({
269
385
  exec,
270
386
  logPath: layout.installLogPath,
271
- command: 'uv',
387
+ command: uvPath,
272
388
  args: ['pip', 'install', '--python', layout.pythonPath, wheelSpec],
273
389
  env: uvEnv,
274
390
  });
@@ -326,15 +442,15 @@ export async function doctorManagedPythonRuntime(options) {
326
442
  const exec = options.exec ?? defaultExec;
327
443
  const checks = [];
328
444
  try {
329
- const version = await ensureUv(exec, managedRuntimeUvEnv(options.env ?? process.env));
330
- checks.push(check('pass', { id: 'uv', label: 'uv', detail: version }));
445
+ const uv = await ensureUv({ exec, uvEnv: managedRuntimeUvEnv(options.env ?? process.env), options });
446
+ checks.push(check('pass', { id: 'uv', label: 'uv', detail: `${uv.version} (managed: ${uv.uvPath})` }));
331
447
  }
332
448
  catch (error) {
333
449
  checks.push(check('fail', {
334
450
  id: 'uv',
335
451
  label: 'uv',
336
452
  detail: error instanceof Error ? error.message : String(error),
337
- fix: 'Install uv, make sure it is on PATH, and run: ktx admin runtime install --yes',
453
+ fix: 'Check network access to github.com and run: ktx admin runtime install --yes',
338
454
  }));
339
455
  }
340
456
  try {
@@ -0,0 +1,7 @@
1
+ export type ManagedUvPlatformKey = 'darwin-arm64' | 'darwin-x64' | 'linux-arm64' | 'linux-x64' | 'win32-arm64' | 'win32-x64';
2
+ export interface ManagedUvArtifact {
3
+ file: string;
4
+ sha256: string;
5
+ }
6
+ export declare const MANAGED_UV_VERSION = "0.11.21";
7
+ export declare const MANAGED_UV_ARTIFACTS: Record<ManagedUvPlatformKey, ManagedUvArtifact>;
@@ -0,0 +1,11 @@
1
+ // Generated by scripts/refresh-uv-manifest.mjs. Do not edit by hand.
2
+ // Regenerate with: node scripts/refresh-uv-manifest.mjs [<uv-version>]
3
+ export const MANAGED_UV_VERSION = '0.11.21';
4
+ export const MANAGED_UV_ARTIFACTS = {
5
+ 'darwin-arm64': { file: 'uv-aarch64-apple-darwin.tar.gz', sha256: '1f921d491ba5ffeea774eb04d6681ecee379101341cbb1500394993b541bf3f4' }, // pragma: allowlist secret
6
+ 'darwin-x64': { file: 'uv-x86_64-apple-darwin.tar.gz', sha256: 'f3c8e5708a84b920c18b691214d54d2b0da6b984789caae95d47c95120cb7765' }, // pragma: allowlist secret
7
+ 'linux-arm64': { file: 'uv-aarch64-unknown-linux-musl.tar.gz', sha256: 'e71badaed2a2c3a404a0a00974b51c7ed5f5bc7be947916846005b739c68a5a2' }, // pragma: allowlist secret
8
+ 'linux-x64': { file: 'uv-x86_64-unknown-linux-musl.tar.gz', sha256: '9dadff5b9e7b1d2d011e41852a1cbca713d9d5d88194f2eb6bd240fa4fb0a719' }, // pragma: allowlist secret
9
+ 'win32-arm64': { file: 'uv-aarch64-pc-windows-msvc.zip', sha256: '74e443f8004022dde57a1bd0d10c097830f9ea8feb4ec927db52cd5d805c2f48' }, // pragma: allowlist secret
10
+ 'win32-x64': { file: 'uv-x86_64-pc-windows-msvc.zip', sha256: 'ace861f360c6de2babedc1607d0f454b6b09a820dbc8182dc15af927e4df9589' }, // pragma: allowlist secret
11
+ };
@@ -38,7 +38,7 @@ function fullOrigin(value) {
38
38
  }
39
39
  export function buildMcpSecurityConfig(input) {
40
40
  if (!isLoopbackHost(input.host) && !input.token) {
41
- throw new Error(`Binding KTX MCP to ${input.host} requires --token or KTX_MCP_TOKEN`);
41
+ throw new Error(`Binding ktx MCP to ${input.host} requires --token or KTX_MCP_TOKEN`);
42
42
  }
43
43
  const allowedHostSet = new Set(DEFAULT_ALLOWED_HOSTS);
44
44
  if (!isLoopbackHost(input.host)) {
@@ -63,16 +63,16 @@ function headerValue(headers, name) {
63
63
  export function isMcpRequestAuthorized(request, config) {
64
64
  const host = headerValue(request.headers, 'host');
65
65
  if (!host || !config.allowedHosts.includes(normalizeHostHeader(host))) {
66
- return { ok: false, status: 403, message: 'Host header is not allowed for KTX MCP.' };
66
+ return { ok: false, status: 403, message: 'Host header is not allowed for ktx MCP.' };
67
67
  }
68
68
  const origin = headerValue(request.headers, 'origin');
69
69
  if (origin && !config.allowedOrigins.includes(origin)) {
70
- return { ok: false, status: 403, message: 'Origin header is not allowed for KTX MCP.' };
70
+ return { ok: false, status: 403, message: 'Origin header is not allowed for ktx MCP.' };
71
71
  }
72
72
  if (request.path === '/mcp' && config.token) {
73
73
  const auth = headerValue(request.headers, 'authorization');
74
74
  if (auth !== `Bearer ${config.token}`) {
75
- return { ok: false, status: 401, message: 'Missing or invalid KTX MCP bearer token.' };
75
+ return { ok: false, status: 401, message: 'Missing or invalid ktx MCP bearer token.' };
76
76
  }
77
77
  }
78
78
  return { ok: true };
@@ -5,7 +5,7 @@ import { createLocalProjectMemoryIngest } from './context/memory/local-memory.js
5
5
  import { resolveProjectEmbeddingProvider } from './embedding-resolution.js';
6
6
  import { createKtxCliIngestQueryExecutor } from './ingest-query-executor.js';
7
7
  import { createKtxCliScanConnector } from './local-scan-connectors.js';
8
- import { createManagedPythonSemanticLayerComputePort } from './managed-python-command.js';
8
+ import { createLazyManagedPythonSemanticLayerComputePort } from './managed-python-command.js';
9
9
  import { createManagedDaemonSqlAnalysisPort } from './managed-python-http.js';
10
10
  function noopMcpIo() {
11
11
  return {
@@ -16,7 +16,7 @@ function noopMcpIo() {
16
16
  export async function createKtxMcpServerFactory(input) {
17
17
  const io = input.io ?? noopMcpIo();
18
18
  const queryExecutor = createKtxCliIngestQueryExecutor(input.project);
19
- const semanticLayerCompute = await createManagedPythonSemanticLayerComputePort({
19
+ const semanticLayerCompute = createLazyManagedPythonSemanticLayerComputePort({
20
20
  cliVersion: input.cliVersion,
21
21
  installPolicy: 'auto',
22
22
  io,
@@ -54,7 +54,7 @@ export async function createKtxMcpServerFactory(input) {
54
54
  });
55
55
  }
56
56
  catch (error) {
57
- io.stderr.write(`KTX MCP memory_ingest disabled: ${error instanceof Error ? error.message : String(error)}\n`);
57
+ io.stderr.write(`ktx MCP memory_ingest disabled: ${error instanceof Error ? error.message : String(error)}\n`);
58
58
  }
59
59
  return () => createDefaultKtxMcpServer({
60
60
  name: 'ktx',
@@ -37,7 +37,7 @@ export async function runKtxMcpStdioServer(options) {
37
37
  };
38
38
  transport.onclose = () => settle(resolve);
39
39
  transport.onerror = (error) => {
40
- options.io?.stderr.write(`KTX MCP stdio transport error: ${error.message}\n`);
40
+ options.io?.stderr.write(`ktx MCP stdio transport error: ${error.message}\n`);
41
41
  settle(() => reject(error));
42
42
  };
43
43
  stdin.once('end', closeTransport);
@@ -198,7 +198,7 @@ export function ActivityFeed(props) {
198
198
  const barWidth = Math.min(40, props.width - 20);
199
199
  return (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [!diffEvent && !workStarted && (_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Connecting to ", src.type.toLowerCase(), "..."] })), diffEvent && (_jsxs(Text, { color: props.theme.complete, children: ["\u2713 Connected \u2014 found ", src.sourceCount, " ", src.itemNounPlural, " to ingest"] })), diffEvent && isIncremental && (_jsx(Text, { color: props.theme.complete, children: "\u2713 Compared with last sync \u2014 only re-analyzing what changed" })), diffEvent && !planEvent && !workStarted && (_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Grouping related ", src.itemNounPlural, " together for deeper analysis..."] })), planEvent && (_jsxs(Text, { color: props.theme.complete, children: ["\u2713 Grouped into ", planEvent.chunkCount, " business area", planEvent.chunkCount === 1 ? '' : 's'] })), workStarted && !allWorkDone && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Ingesting \u2014 ", finishedAreas, "/", totalChunks || '?', " business area", totalChunks === 1 ? '' : 's', " done"] }), _jsxs(Text, { color: props.theme.muted, children: [' ', src.ingestDescription] }), totalChunks > 0 && (_jsxs(Text, { color: props.theme.active, children: [' ', progressBarOverall(finishedAreas, actives.length, totalChunks, barWidth, props.frame)] }))] })), insights.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: props.theme.text, children: " Created so far:" }), insights.map((insight, idx) => (_jsxs(Text, { color: props.theme.muted, children: [' ', insight.icon, " ", insight.text] }, `result-${idx}`)))] })), isReconciling && (_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Deduplicating \u2014 removing overlaps between business areas and checking for conflicts..."] })), reconEvent && (_jsxs(Text, { color: props.theme.complete, children: ["\u2713 Deduplicated", reconEvent.conflictCount > 0
200
200
  ? ` — ${reconEvent.conflictCount} conflict${reconEvent.conflictCount === 1 ? '' : 's'} resolved`
201
- : ' — no conflicts'] })), isSaving && (_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Saving to context layer..."] })), savedEvent && (_jsx(Text, { color: props.theme.complete, children: "\u2713 Saved \u2014 your agents can now use the KTX context layer" })), props.showCompletion && (isDone || isError) && (_jsx(CompletionSummary, { input: props.input, theme: props.theme, frame: props.completionFrame, holdComplete: props.holdComplete }))] }));
201
+ : ' — no conflicts'] })), isSaving && (_jsxs(Text, { color: props.theme.active, children: [spinner(props.frame), " Saving to context layer..."] })), savedEvent && (_jsx(Text, { color: props.theme.complete, children: "\u2713 Saved \u2014 your agents can now use the ktx context layer" })), props.showCompletion && (isDone || isError) && (_jsx(CompletionSummary, { input: props.input, theme: props.theme, frame: props.completionFrame, holdComplete: props.holdComplete }))] }));
202
202
  }
203
203
  function CompletionSummary(props) {
204
204
  const saved = [...props.input.events].reverse().find((e) => e.type === 'saved');
@@ -207,5 +207,5 @@ function CompletionSummary(props) {
207
207
  const isError = props.input.status === 'error';
208
208
  const sl = counterValue(slCount, props.frame);
209
209
  const wiki = counterValue(wikiCount, props.frame);
210
- return (_jsx(Box, { flexDirection: "column", marginTop: 1, children: isError ? (_jsx(Text, { bold: true, color: props.theme.failed, children: "\u2717 Something went wrong \u2014 review the errors above." })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: props.theme.border, children: '─'.repeat(60) }), _jsx(Text, { bold: true, color: props.theme.complete, children: "\u2605 KTX finished ingesting your data" }), (sl > 0 || wiki > 0) && (_jsxs(_Fragment, { children: [_jsx(Text, {}), _jsx(Text, { color: props.theme.text, children: "KTX created:" }), sl > 0 && (_jsxs(Text, { color: props.theme.active, children: [' ', "\uD83D\uDCCA ", sl, " query definition", sl === 1 ? '' : 's', " \u2014 so agents can write accurate SQL for your data"] })), wiki > 0 && (_jsxs(Text, { color: props.theme.complete, children: [' ', "\uD83D\uDCDD ", wiki, " wiki page", wiki === 1 ? '' : 's', " \u2014 so agents understand your business context"] }))] })), _jsx(Text, {}), _jsx(Text, { color: props.theme.text, children: "What to do next:" }), formatNextStepLines().map((line) => (_jsx(Text, { color: props.theme.active, children: line }, line))), props.holdComplete && (_jsxs(_Fragment, { children: [_jsx(Text, {}), _jsx(Text, { color: props.theme.muted, children: "Press q to exit" })] }))] })) }));
210
+ return (_jsx(Box, { flexDirection: "column", marginTop: 1, children: isError ? (_jsx(Text, { bold: true, color: props.theme.failed, children: "\u2717 Something went wrong \u2014 review the errors above." })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: props.theme.border, children: '─'.repeat(60) }), _jsx(Text, { bold: true, color: props.theme.complete, children: "\u2605 ktx finished ingesting your data" }), (sl > 0 || wiki > 0) && (_jsxs(_Fragment, { children: [_jsx(Text, {}), _jsx(Text, { color: props.theme.text, children: "ktx created:" }), sl > 0 && (_jsxs(Text, { color: props.theme.active, children: [' ', "\uD83D\uDCCA ", sl, " query definition", sl === 1 ? '' : 's', " \u2014 so agents can write accurate SQL for your data"] })), wiki > 0 && (_jsxs(Text, { color: props.theme.complete, children: [' ', "\uD83D\uDCDD ", wiki, " wiki page", wiki === 1 ? '' : 's', " \u2014 so agents understand your business context"] }))] })), _jsx(Text, {}), _jsx(Text, { color: props.theme.text, children: "What to do next:" }), formatNextStepLines().map((line) => (_jsx(Text, { color: props.theme.active, children: line }, line))), props.holdComplete && (_jsxs(_Fragment, { children: [_jsx(Text, {}), _jsx(Text, { color: props.theme.muted, children: "Press q to exit" })] }))] })) }));
211
211
  }
@@ -31,7 +31,7 @@ function commandLines(commands, indent) {
31
31
  }
32
32
  export function formatNextStepLines(indent = ' ') {
33
33
  return [
34
- `${indent}KTX context is ready for agents. Open your coding agent from the KTX project directory and ask a data question.`,
34
+ `${indent}ktx context is ready for agents. Open your coding agent from the ktx project directory and ask a data question.`,
35
35
  `${indent}Verify with:`,
36
36
  ...commandLines(KTX_NEXT_STEP_DIRECT_COMMANDS, indent),
37
37
  ];
@@ -59,7 +59,7 @@ export function formatSetupNextStepLines(state, indent = ' ') {
59
59
  }
60
60
  if (!state.agentIntegrationReady) {
61
61
  return [
62
- `${indent}KTX context is built. Install agent rules when you want your coding agent to use it.`,
62
+ `${indent}ktx context is built. Install agent rules when you want your coding agent to use it.`,
63
63
  `${indent}$ ${'ktx setup --agents'.padEnd(KTX_NEXT_STEP_COMMAND_WIDTH)} Install CLI-based agent rules`,
64
64
  `${indent}$ ${'ktx status'.padEnd(KTX_NEXT_STEP_COMMAND_WIDTH)} Check setup and context readiness`,
65
65
  ];
@@ -1,7 +1,24 @@
1
1
  /** @internal */
2
+ export declare const MULTISELECT_NAVIGATION_FRAGMENTS: {
3
+ readonly move: "Up/Down to move";
4
+ readonly expand: "Right/Left to expand or collapse";
5
+ readonly select: "Tab to select or unselect";
6
+ readonly search: "Type to search";
7
+ readonly confirm: "Enter to confirm";
8
+ readonly back: "Escape to go back";
9
+ readonly backSearchableTree: "Escape to clear search or go back";
10
+ readonly exit: "Ctrl+C to exit";
11
+ };
12
+ /** @internal */
13
+ export declare const FLAT_MULTISELECT_NAVIGATION_HINT: string;
14
+ /** @internal */
15
+ export declare const SEARCHABLE_MULTISELECT_NAVIGATION_HINT: string;
16
+ export declare const TREE_PICKER_NAVIGATION_HINT: string;
17
+ /** @internal */
2
18
  export declare function withMenuOptionSpacing(message: string): string;
3
19
  export declare function withMenuOptionsSpacing<T extends {
4
20
  message: string;
5
21
  }>(options: T): T;
6
22
  export declare function withMultiselectNavigation(message: string): string;
23
+ export declare function withSearchableMultiselectNavigation(message: string): string;
7
24
  export declare function withTextInputNavigation(message: string): string;
@@ -1,4 +1,44 @@
1
- const MULTISELECT_MENU_NAVIGATION_HINT = 'Use Up/Down to move, Space to select or unselect, Enter to confirm, Escape to go back, or Ctrl+C to exit.';
1
+ /** @internal */
2
+ export const MULTISELECT_NAVIGATION_FRAGMENTS = {
3
+ move: 'Up/Down to move',
4
+ expand: 'Right/Left to expand or collapse',
5
+ select: 'Tab to select or unselect',
6
+ search: 'Type to search',
7
+ confirm: 'Enter to confirm',
8
+ back: 'Escape to go back',
9
+ backSearchableTree: 'Escape to clear search or go back',
10
+ exit: 'Ctrl+C to exit',
11
+ };
12
+ function composeNavigationHint(fragments) {
13
+ return `${fragments.join(', ')}.`;
14
+ }
15
+ const fragment = MULTISELECT_NAVIGATION_FRAGMENTS;
16
+ /** @internal */
17
+ export const FLAT_MULTISELECT_NAVIGATION_HINT = composeNavigationHint([
18
+ fragment.move,
19
+ fragment.select,
20
+ fragment.confirm,
21
+ fragment.back,
22
+ fragment.exit,
23
+ ]);
24
+ /** @internal */
25
+ export const SEARCHABLE_MULTISELECT_NAVIGATION_HINT = composeNavigationHint([
26
+ fragment.move,
27
+ fragment.select,
28
+ fragment.search,
29
+ fragment.confirm,
30
+ fragment.back,
31
+ fragment.exit,
32
+ ]);
33
+ export const TREE_PICKER_NAVIGATION_HINT = composeNavigationHint([
34
+ fragment.move,
35
+ fragment.expand,
36
+ fragment.select,
37
+ fragment.search,
38
+ fragment.confirm,
39
+ fragment.backSearchableTree,
40
+ fragment.exit,
41
+ ]);
2
42
  const TEXT_INPUT_NAVIGATION_HINT = 'Press Escape to go back.';
3
43
  function removeTrailingBlankLines(message) {
4
44
  return message.replace(/\n+$/, '');
@@ -45,10 +85,16 @@ export function withMenuOptionsSpacing(options) {
45
85
  return { ...options, message: withMenuOptionSpacing(options.message) };
46
86
  }
47
87
  export function withMultiselectNavigation(message) {
48
- if (message.includes(MULTISELECT_MENU_NAVIGATION_HINT)) {
88
+ if (message.includes(FLAT_MULTISELECT_NAVIGATION_HINT)) {
89
+ return message;
90
+ }
91
+ return `${message}\n${FLAT_MULTISELECT_NAVIGATION_HINT}`;
92
+ }
93
+ export function withSearchableMultiselectNavigation(message) {
94
+ if (message.includes(SEARCHABLE_MULTISELECT_NAVIGATION_HINT)) {
49
95
  return message;
50
96
  }
51
- return `${message}\n${MULTISELECT_MENU_NAVIGATION_HINT}`;
97
+ return `${message}\n${SEARCHABLE_MULTISELECT_NAVIGATION_HINT}`;
52
98
  }
53
99
  export function withTextInputNavigation(message) {
54
100
  const messageWithoutHint = removeTrailingBlankLines(message)
@@ -2,7 +2,7 @@
2
2
  You are processing ONE WorkUnit of a multi-file ingest bundle. The WorkUnit
3
3
  gives you a slice of raw source files (LookML views, dbt/MetricFlow YAMLs,
4
4
  Metabase card JSONs, Notion pages, or similar) and you must translate that
5
- slice into KTX semantic-layer sources and/or knowledge wiki pages, in one pass.
5
+ slice into ktx semantic-layer sources and/or knowledge wiki pages, in one pass.
6
6
  You run in an isolated WorkUnit worktree. Deterministic projection output,
7
7
  existing project memory, and listed dependency paths are visible; sibling
8
8
  WorkUnit edits from this same job are not visible until the runner integrates
@@ -10,7 +10,7 @@ accepted patches.
10
10
  </role>
11
11
 
12
12
  <stance>
13
- Assertive. The bundle was explicitly submitted for ingest. Default to capturing everything the raw files declare that maps cleanly to KTX: one SL source per table/view, one wiki page per non-obvious business rule or alias. Do not abandon a WorkUnit because "some content overlaps with another WU"; use `ingest_triage` to reconcile, do not skip.
13
+ Assertive. The bundle was explicitly submitted for ingest. Default to capturing everything the raw files declare that maps cleanly to ktx: one SL source per table/view, one wiki page per non-obvious business rule or alias. Do not abandon a WorkUnit because "some content overlaps with another WU"; use `ingest_triage` to reconcile, do not skip.
14
14
  </stance>
15
15
 
16
16
  <workflow>
@@ -1,5 +1,5 @@
1
1
  <role>
2
- You are ingesting an external technical artifact (a LookML view, dbt model, schema description, business glossary, or other reference document) into KTX organizational memory. The user has explicitly submitted this content for bulk ingest. Assume it is intentional and worth capturing.
2
+ You are ingesting an external technical artifact (a LookML view, dbt model, schema description, business glossary, or other reference document) into ktx organizational memory. The user has explicitly submitted this content for bulk ingest. Assume it is intentional and worth capturing.
3
3
  </role>
4
4
 
5
5
  <stance>
@@ -18,7 +18,7 @@ A single artifact typically produces multiple actions: one SL source per table/v
18
18
  </workflow>
19
19
 
20
20
  <scope>
21
- All wiki writes go to the GLOBAL scope - they will be visible to every user of this KTX project. Phrase wiki pages as objective business knowledge, not personal preference. The `wiki_write` tool handles scope selection automatically for external ingest.
21
+ All wiki writes go to the GLOBAL scope - they will be visible to every user of this ktx project. Phrase wiki pages as objective business knowledge, not personal preference. The `wiki_write` tool handles scope selection automatically for external ingest.
22
22
  </scope>
23
23
 
24
24
  <do_not>
@@ -7,7 +7,7 @@ const DATABASE_INGEST_REPLACEMENTS = [
7
7
  [/\bWriting schema artifacts\b/gi, 'Writing schema context'],
8
8
  [/\bEnriching schema metadata\b/gi, 'Building enriched schema context'],
9
9
  [
10
- /\bKTX scan enrichment failed after structural scan completed\b/gi,
10
+ /\bktx scan enrichment failed after structural scan completed\b/gi,
11
11
  'Database enrichment failed after schema context completed',
12
12
  ],
13
13
  [/\bstructural scan\b/gi, 'schema context'],
@@ -535,8 +535,8 @@ function createPlainPublicIngestProgress(io, options) {
535
535
  };
536
536
  }
537
537
  const INTERNAL_STATUS_LINE_RE = /^(Report|Run|Job|Status|Adapter|Connection|Sync|Diff|Tasks|Work units|Failed tasks|Saved memory|Provenance rows):\s*/;
538
- const ACTIONABLE_FAILURE_LINE_RE = /^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX daemon HTTP|Error:|Failed\b|Could not\b|Cannot\b)/;
539
- const RUNTIME_BACKED_RETRY_LINE_RE = /^Then retry the runtime-backed KTX command\.?$/;
538
+ const ACTIONABLE_FAILURE_LINE_RE = /^(Missing bundled Python runtime manifest|ktx Python runtime is required|ktx daemon HTTP|Error:|Failed\b|Could not\b|Cannot\b)/;
539
+ const RUNTIME_BACKED_RETRY_LINE_RE = /^Then retry the runtime-backed ktx command\.?$/;
540
540
  function trimErrorPrefix(line) {
541
541
  return line.replace(/^Error:\s*/, '');
542
542
  }
@@ -545,7 +545,7 @@ function capturedFailureMessage(output) {
545
545
  .split(/\r?\n/)
546
546
  .map((line) => line.trim())
547
547
  .filter((line) => line.length > 0)
548
- .filter((line) => !line.startsWith('KTX scan completed'))
548
+ .filter((line) => !line.startsWith('ktx scan completed'))
549
549
  .filter((line) => !INTERNAL_STATUS_LINE_RE.test(line))
550
550
  .map(publicIngestOutputLine);
551
551
  const actionableIndex = lines.findIndex((line) => ACTIONABLE_FAILURE_LINE_RE.test(line));
@@ -1,7 +1,7 @@
1
1
  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-]+)*)?$/;
2
2
  export function assertCliVersion(value, source) {
3
3
  if (typeof value !== 'string' || !semverPattern.test(value)) {
4
- throw new Error(`Invalid KTX CLI version in ${source}`);
4
+ throw new Error(`Invalid ktx CLI version in ${source}`);
5
5
  }
6
6
  return value;
7
7
  }
@@ -44,7 +44,7 @@ export function resolveProjectRuntimeRequirements(config, options = {}) {
44
44
  requirements.push({
45
45
  feature: 'core',
46
46
  reason: 'database-introspection',
47
- detail: 'Database introspection fallback uses the KTX daemon.',
47
+ detail: 'Database introspection fallback uses the ktx daemon.',
48
48
  });
49
49
  }
50
50
  for (const [connectionId, connection] of Object.entries(config.connections)) {
package/dist/runtime.js CHANGED
@@ -5,7 +5,7 @@ function writeJson(io, value) {
5
5
  }
6
6
  function writeInstallResult(io, result) {
7
7
  const verb = result.status === 'ready' ? 'Using existing' : 'Installed';
8
- io.stdout.write(`${verb} KTX Python runtime\n`);
8
+ io.stdout.write(`${verb} ktx Python runtime\n`);
9
9
  io.stdout.write(`version: ${result.manifest.cliVersion}\n`);
10
10
  io.stdout.write(`features: ${result.manifest.features.join(', ')}\n`);
11
11
  io.stdout.write(`python: ${result.manifest.python.executable}\n`);
@@ -15,7 +15,7 @@ function writeInstallResult(io, result) {
15
15
  }
16
16
  function writeDaemonStart(io, result) {
17
17
  const verb = result.status === 'reused' ? 'Using existing' : 'Started';
18
- io.stdout.write(`${verb} KTX daemon\n`);
18
+ io.stdout.write(`${verb} ktx daemon\n`);
19
19
  io.stdout.write(`url: ${result.baseUrl}\n`);
20
20
  io.stdout.write(`pid: ${result.state.pid}\n`);
21
21
  io.stdout.write(`version: ${result.state.version}\n`);
@@ -26,10 +26,10 @@ function writeDaemonStart(io, result) {
26
26
  }
27
27
  function writeDaemonStop(io, result) {
28
28
  if (result.status === 'already-stopped') {
29
- io.stdout.write('KTX daemon already stopped\n');
29
+ io.stdout.write('ktx daemon already stopped\n');
30
30
  return;
31
31
  }
32
- io.stdout.write('Stopped KTX daemon\n');
32
+ io.stdout.write('Stopped ktx daemon\n');
33
33
  io.stdout.write(`pid: ${result.state?.pid ?? 'unknown'}\n`);
34
34
  io.stdout.write(`state: ${result.layout.daemonStatePath}\n`);
35
35
  }
@@ -42,11 +42,11 @@ function writeDaemonStopAll(io, result) {
42
42
  result.stale.length === 0 &&
43
43
  result.failed.length === 0 &&
44
44
  result.scanErrors.length === 0) {
45
- io.stdout.write('No KTX daemons found\n');
45
+ io.stdout.write('No ktx daemons found\n');
46
46
  return 0;
47
47
  }
48
48
  if (failed === 0) {
49
- io.stdout.write(`Stopped ${result.stopped.length} KTX daemons\n`);
49
+ io.stdout.write(`Stopped ${result.stopped.length} ktx daemons\n`);
50
50
  if (result.stale.length > 0) {
51
51
  io.stdout.write(`Cleaned ${result.stale.length} stale daemon states\n`);
52
52
  }
@@ -58,7 +58,7 @@ function writeDaemonStopAll(io, result) {
58
58
  }
59
59
  return 0;
60
60
  }
61
- io.stderr.write(`Stopped ${result.stopped.length} KTX daemons; failed ${result.failed.length}${result.stale.length > 0 ? `; cleaned stale ${result.stale.length}` : ''}\n`);
61
+ io.stderr.write(`Stopped ${result.stopped.length} ktx daemons; failed ${result.failed.length}${result.stale.length > 0 ? `; cleaned stale ${result.stale.length}` : ''}\n`);
62
62
  for (const entry of result.failed) {
63
63
  io.stderr.write(`pid: ${entry.pid} source: ${entry.source}${entry.url ? ` url: ${entry.url}` : ''}${entry.health ? ` health: ${entry.health}` : ''} detail: ${entry.detail}\n`);
64
64
  }
@@ -68,7 +68,7 @@ function writeDaemonStopAll(io, result) {
68
68
  return 1;
69
69
  }
70
70
  function writeStatus(io, status) {
71
- io.stdout.write('KTX Python runtime\n');
71
+ io.stdout.write('ktx Python runtime\n');
72
72
  io.stdout.write(`status: ${status.kind}\n`);
73
73
  io.stdout.write(`detail: ${status.detail}\n`);
74
74
  io.stdout.write(`runtime root: ${status.layout.runtimeRoot}\n`);
@@ -80,7 +80,7 @@ function writeStatus(io, status) {
80
80
  }
81
81
  }
82
82
  function writeRuntimeChecks(io, checks) {
83
- io.stdout.write('KTX Python runtime checks\n');
83
+ io.stdout.write('ktx Python runtime checks\n');
84
84
  for (const check of checks) {
85
85
  io.stdout.write(`${check.status.toUpperCase()} ${check.label}: ${check.detail}\n`);
86
86
  if (check.fix) {
package/dist/scan.js CHANGED
@@ -206,7 +206,7 @@ function writeHumanReportBody(report, io) {
206
206
  }
207
207
  function writeRunSummary(report, projectDir, io) {
208
208
  const styled = shouldUseStyledOutput(io);
209
- io.stdout.write(`${styled ? green('✓') : ''}${styled ? ' ' : ''}KTX scan completed\n`);
209
+ io.stdout.write(`${styled ? green('✓') : ''}${styled ? ' ' : ''}ktx scan completed\n`);
210
210
  io.stdout.write('Status: done\n');
211
211
  writeHumanReportBody(report, io);
212
212
  const projectDirArg = quoteCliArg(projectDir);