2026-05-15 02:35:09 +02:00
|
|
|
|
import { existsSync } from 'node:fs';
|
2026-05-24 16:57:23 +02:00
|
|
|
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
2026-05-10 23:13:17 -07:00
|
|
|
|
import { dirname, join, relative, resolve } from 'node:path';
|
2026-05-19 15:21:49 +02:00
|
|
|
|
import type { Writable } from 'node:stream';
|
2026-05-10 16:01:58 -07:00
|
|
|
|
import { fileURLToPath } from 'node:url';
|
2026-05-19 15:21:49 +02:00
|
|
|
|
import { styleText } from 'node:util';
|
|
|
|
|
|
import { log, outro } from '@clack/prompts';
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
import { loadKtxProject } from './context/project/project.js';
|
|
|
|
|
|
import { markKtxSetupStateStepComplete } from './context/project/setup-config.js';
|
|
|
|
|
|
import { serializeKtxProjectConfig } from './context/project/config.js';
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
import { strToU8, zipSync } from 'fflate';
|
2026-05-10 23:51:24 +02:00
|
|
|
|
import type { KtxCliIo } from './cli-runtime.js';
|
test: split cli tests from source tree (#216)
* feat(cli): define full warehouse dialect contract
* test(cli): keep dialect edge tests focused
* fix(cli): stabilize dialect contract foundation
* refactor(connectors): own read-only query preparation
* refactor(connectors): resolve dialects through registry
* refactor(connectors): keep concrete dialect classes internal
* chore(workspace): enforce dialect import boundary
* refactor(cli): resolve relationship dialect at scan boundary
* refactor(cli): use dialect display parsing for entity details
* refactor(cli): use dialect display parsing for warehouse catalog
* refactor(cli): use dialect SQL in relationship workflows
* test(cli): verify solid dialect scan workflow closure
* test: split cli tests from source tree
* refactor(cli): standardize BigQuery scope listing
* feat(sqlite): implement connector scope listing
* test(connectors): cover required table listing
* feat(cli): add warehouse driver registry
* refactor(setup): route scope discovery through driver registry
* refactor(cli): route local query execution through driver registry
* refactor(historic-sql): route dialect support through driver registry
* refactor(cli): test warehouse connections through driver registry
* fix(cli): close driver registry type export gaps
* Improve setup daemon diagnostics
* refactor(setup): centralize rail-prefixed diagnostics + query-history fallback
Extract errorMessage, writePrefixedLines, and flushPrefixedBufferedCommandOutput
into clack.ts so the setup wizard, managed daemons, and embedding/agent steps
share one rail-formatted writer. setup-databases.ts also adds a
"disable query history and retry" option when the schema-context build fails
and query history is the likely culprit, surfaced via a new
failed-query-history-unavailable status.
* fix(cli): carry catalog through the picker so BigQuery/Snowflake/SQL Server scope filters match
The setup picker's KtxTableListEntry was a 2-level { schema, name }, so
qualifiedTableId always wrote db.name into enabled_tables. When BigQuery,
Snowflake, or SQL Server later ran fast ingest, their introspect step filtered
the scope set with scopedTableNames(scope, { catalog: projectId|database, db })
— catalog was non-null on the introspect side but null in the scope refs, so
every entry was rejected, the live-database adapter staged zero table files,
and detect() failed with 'Adapter "live-database" did not recognize fetched
source output'.
Align the picker boundary with the canonical 3-level KtxTableRef:
- Add catalog: string | null to KtxTableListEntry.
- BigQuery/Snowflake/SQL Server listTables populate catalog from the
resolved projectId / database; Postgres/MySQL/ClickHouse/SQLite set null.
- qualifiedTableId emits catalog.schema.name when catalog is non-null
(resolveEnabledTables already accepts the 3-part shape) and
schemasFromEnabledTables now goes through parseDottedTableEntry so it
recovers the schema correctly from both 2-part and 3-part entries.
- Export parseDottedTableEntry from enabled-tables.ts (@internal) for picker
reuse.
Update listTables expectations in all seven connector tests and the setup /
picker test fixtures. Add a picker regression test that covers the
catalog-bearing round-trip (save + refine).
* fix(cli): allow debug telemetry under opt-out env
2026-05-26 08:49:05 +02:00
|
|
|
|
import { errorMessage, writePrefixedLines } from './clack.js';
|
2026-05-13 17:01:48 +02:00
|
|
|
|
import {
|
|
|
|
|
|
createKtxSetupPromptAdapter,
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
createKtxSetupUiAdapter,
|
2026-05-13 17:01:48 +02:00
|
|
|
|
type KtxSetupPromptOption,
|
|
|
|
|
|
} from './setup-prompts.js';
|
2026-05-15 02:35:09 +02:00
|
|
|
|
import { readKtxMcpDaemonStatus } from './managed-mcp-daemon.js';
|
2026-05-10 23:12:26 +02:00
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
export type KtxAgentTarget = 'claude-code' | 'claude-desktop' | 'codex' | 'cursor' | 'opencode' | 'universal';
|
2026-05-15 02:35:09 +02:00
|
|
|
|
export type KtxAgentScope = 'project' | 'global' | 'local';
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
export type KtxAgentInstallMode = 'mcp' | 'mcp-cli';
|
2026-05-24 19:30:06 +02:00
|
|
|
|
type KtxAgentModePromptChoice = KtxAgentInstallMode | 'skip' | 'back';
|
2026-05-10 23:12:26 +02:00
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export interface KtxSetupAgentsArgs {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
projectDir: string;
|
|
|
|
|
|
inputMode: 'auto' | 'disabled';
|
|
|
|
|
|
yes: boolean;
|
|
|
|
|
|
agents: boolean;
|
2026-05-10 23:51:24 +02:00
|
|
|
|
target?: KtxAgentTarget;
|
|
|
|
|
|
scope: KtxAgentScope;
|
|
|
|
|
|
mode: KtxAgentInstallMode;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
skipAgents: boolean;
|
2026-05-18 18:54:20 -04:00
|
|
|
|
showNextActions?: boolean;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export type KtxSetupAgentsResult =
|
2026-05-10 23:12:26 +02:00
|
|
|
|
| {
|
|
|
|
|
|
status: 'ready';
|
|
|
|
|
|
projectDir: string;
|
2026-05-10 23:51:24 +02:00
|
|
|
|
installs: Array<{ target: KtxAgentTarget; scope: KtxAgentScope; mode: KtxAgentInstallMode }>;
|
2026-05-18 18:54:20 -04:00
|
|
|
|
nextActions?: string;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
| { status: 'skipped'; projectDir: string }
|
|
|
|
|
|
| { status: 'back'; projectDir: string }
|
|
|
|
|
|
| { status: 'missing-input'; projectDir: string }
|
|
|
|
|
|
| { status: 'failed'; projectDir: string };
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export interface KtxAgentInstallManifest {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
version: 1;
|
|
|
|
|
|
projectDir: string;
|
|
|
|
|
|
installedAt: string;
|
2026-05-10 23:51:24 +02:00
|
|
|
|
installs: Array<{ target: KtxAgentTarget; scope: KtxAgentScope; mode: KtxAgentInstallMode }>;
|
2026-05-10 23:13:17 -07:00
|
|
|
|
entries: Array<
|
2026-05-19 15:21:49 +02:00
|
|
|
|
| {
|
|
|
|
|
|
kind: 'file';
|
|
|
|
|
|
path: string;
|
2026-05-24 16:57:23 +02:00
|
|
|
|
role?: 'skill' | 'rule' | 'analytics-skill' | 'claude-desktop-skill-bundle';
|
2026-05-19 15:21:49 +02:00
|
|
|
|
}
|
2026-05-10 23:13:17 -07:00
|
|
|
|
| { kind: 'json-key'; path: string; jsonPath: string[] }
|
|
|
|
|
|
>;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
type InstallEntry = KtxAgentInstallManifest['entries'][number];
|
2026-05-10 23:12:26 +02:00
|
|
|
|
|
2026-05-15 02:35:09 +02:00
|
|
|
|
interface KtxMcpEndpointInfo {
|
|
|
|
|
|
url: string;
|
|
|
|
|
|
tokenAuth: boolean;
|
|
|
|
|
|
running: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface KtxMcpClientInstallResult {
|
|
|
|
|
|
entries: InstallEntry[];
|
|
|
|
|
|
snippets: string[];
|
|
|
|
|
|
notices: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
const MCP_DAEMON_REQUIRED_NOTICE = 'mcp-daemon-required';
|
|
|
|
|
|
|
2026-05-10 16:01:58 -07:00
|
|
|
|
interface KtxCliLauncher {
|
|
|
|
|
|
command: string;
|
|
|
|
|
|
args: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-19 15:21:49 +02:00
|
|
|
|
function isWritableTtyOutput(output: KtxCliIo['stdout']): output is KtxCliIo['stdout'] & Writable {
|
|
|
|
|
|
return (
|
|
|
|
|
|
output.isTTY === true &&
|
|
|
|
|
|
typeof (output as { on?: unknown }).on === 'function' &&
|
|
|
|
|
|
typeof (output as { columns?: unknown }).columns !== 'undefined'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function writeSetupInfo(io: KtxCliIo, message: string): void {
|
|
|
|
|
|
if (isWritableTtyOutput(io.stdout)) {
|
|
|
|
|
|
log.info(message, { output: io.stdout });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
io.stdout.write(`${message}\n`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function writeSetupStep(io: KtxCliIo, message: string): void {
|
|
|
|
|
|
if (isWritableTtyOutput(io.stdout)) {
|
|
|
|
|
|
log.step(message, { output: io.stdout });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
io.stdout.write(`\n${message}\n`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function writeSetupOutro(io: KtxCliIo, message: string): void {
|
|
|
|
|
|
if (isWritableTtyOutput(io.stdout)) {
|
|
|
|
|
|
outro(message, { output: io.stdout });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
io.stdout.write(`\n${message}\n`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const STEP_HEADING_RE = /^(\d+)\. (.+)$/;
|
|
|
|
|
|
const ACTION_MARKER_RE = /^(RUN|PASTE|USE|OPEN):$/;
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
2026-05-19 15:21:49 +02:00
|
|
|
|
export function createAgentNextActionsLineFormatter(
|
|
|
|
|
|
stdout: KtxCliIo['stdout'],
|
|
|
|
|
|
): (line: string) => string {
|
|
|
|
|
|
const maybeHasColors = (stdout as { hasColors?: unknown }).hasColors;
|
|
|
|
|
|
const supportsColor = typeof maybeHasColors === 'function' && Boolean(maybeHasColors.call(stdout));
|
|
|
|
|
|
if (!supportsColor) return (line) => line;
|
|
|
|
|
|
|
|
|
|
|
|
const homeDir = process.env.HOME ? resolve(process.env.HOME) : '';
|
|
|
|
|
|
const styleOptions = { validateStream: false } as const;
|
|
|
|
|
|
const dim = (s: string) => styleText('dim', s, styleOptions);
|
|
|
|
|
|
const bold = (s: string) => styleText('bold', s, styleOptions);
|
|
|
|
|
|
const cyanBold = (s: string) => styleText(['cyan', 'bold'], s, styleOptions);
|
|
|
|
|
|
const dimCyan = (s: string) => styleText(['dim', 'cyan'], s, styleOptions);
|
|
|
|
|
|
const shortenPath = (path: string): string => {
|
|
|
|
|
|
if (!homeDir) return path;
|
|
|
|
|
|
if (path === homeDir) return '~';
|
|
|
|
|
|
if (path.startsWith(`${homeDir}/`)) return `~/${path.slice(homeDir.length + 1)}`;
|
|
|
|
|
|
return path;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (rawLine: string): string => {
|
|
|
|
|
|
if (rawLine.length === 0 || rawLine.includes('[')) return rawLine;
|
|
|
|
|
|
|
|
|
|
|
|
const heading = rawLine.match(STEP_HEADING_RE);
|
|
|
|
|
|
if (heading) {
|
|
|
|
|
|
return `${cyanBold(heading[1])} ${bold(heading[2])}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!rawLine.startsWith(' ')) return rawLine;
|
|
|
|
|
|
const body = rawLine.slice(2);
|
|
|
|
|
|
|
|
|
|
|
|
if (ACTION_MARKER_RE.test(body)) {
|
|
|
|
|
|
return ` ${dim(body)}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (body.endsWith('.zip') && (body.startsWith('/') || body.startsWith('~'))) {
|
|
|
|
|
|
return ` ${dimCyan('•')} ${shortenPath(body)}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (body.includes(' > ')) {
|
|
|
|
|
|
return ` ${body.replaceAll(' > ', ` ${dim('›')} `)}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ` ${dim(body)}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 02:35:09 +02:00
|
|
|
|
async function readJsonObject(path: string): Promise<Record<string, unknown>> {
|
|
|
|
|
|
if (!existsSync(path)) return {};
|
|
|
|
|
|
const parsed = JSON.parse(await readFile(path, 'utf-8')) as unknown;
|
|
|
|
|
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
|
|
|
|
throw new Error(`Expected JSON object in ${path}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
return parsed as Record<string, unknown>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function objectAtPath(root: Record<string, unknown>, jsonPath: string[]): Record<string, unknown> {
|
|
|
|
|
|
let cursor = root;
|
|
|
|
|
|
for (const segment of jsonPath) {
|
|
|
|
|
|
const current = cursor[segment];
|
|
|
|
|
|
if (!current || typeof current !== 'object' || Array.isArray(current)) {
|
|
|
|
|
|
cursor[segment] = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
cursor = cursor[segment] as Record<string, unknown>;
|
|
|
|
|
|
}
|
|
|
|
|
|
return cursor;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function writeJsonKey(path: string, jsonPath: string[], value: unknown): Promise<void> {
|
|
|
|
|
|
const root = await readJsonObject(path);
|
|
|
|
|
|
const parent = objectAtPath(root, jsonPath.slice(0, -1));
|
|
|
|
|
|
parent[jsonPath.at(-1) as string] = value;
|
|
|
|
|
|
await mkdir(dirname(path), { recursive: true });
|
|
|
|
|
|
await writeFile(path, `${JSON.stringify(root, null, 2)}\n`, 'utf-8');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function resolveMcpEndpoint(projectDir: string): Promise<KtxMcpEndpointInfo> {
|
|
|
|
|
|
const status = await readKtxMcpDaemonStatus({ projectDir }).catch(() => null);
|
|
|
|
|
|
if (status?.kind === 'running') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
url: status.url,
|
|
|
|
|
|
tokenAuth: status.state.tokenAuth,
|
|
|
|
|
|
running: true,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
if (status?.kind === 'stale' && status.state) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
url: `http://${status.state.host}:${status.state.port}/mcp`,
|
|
|
|
|
|
tokenAuth: status.state.tokenAuth || Boolean(process.env.KTX_MCP_TOKEN),
|
|
|
|
|
|
running: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
url: 'http://localhost:7878/mcp',
|
|
|
|
|
|
tokenAuth: Boolean(process.env.KTX_MCP_TOKEN),
|
|
|
|
|
|
running: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function tokenHeaders(endpoint: KtxMcpEndpointInfo): Record<string, string> | undefined {
|
|
|
|
|
|
return endpoint.tokenAuth ? { Authorization: 'Bearer ${KTX_MCP_TOKEN}' } : undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function claudeMcpEntry(endpoint: KtxMcpEndpointInfo): Record<string, unknown> {
|
|
|
|
|
|
return {
|
|
|
|
|
|
type: 'http',
|
|
|
|
|
|
url: endpoint.url,
|
|
|
|
|
|
...(tokenHeaders(endpoint) ? { headers: tokenHeaders(endpoint) } : {}),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function cursorMcpEntry(endpoint: KtxMcpEndpointInfo): Record<string, unknown> {
|
|
|
|
|
|
return {
|
|
|
|
|
|
url: endpoint.url,
|
|
|
|
|
|
...(tokenHeaders(endpoint) ? { headers: tokenHeaders(endpoint) } : {}),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function codexSnippet(endpoint: KtxMcpEndpointInfo): string {
|
|
|
|
|
|
if (endpoint.tokenAuth) {
|
|
|
|
|
|
return [
|
|
|
|
|
|
'Codex MCP config does not currently document HTTP headers.',
|
|
|
|
|
|
'Run KTX on loopback without token auth for Codex, or configure headers after Codex documents support.',
|
|
|
|
|
|
].join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
return [`[mcp_servers.ktx]`, `url = "${endpoint.url}"`].join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function opencodeSnippet(endpoint: KtxMcpEndpointInfo): string {
|
|
|
|
|
|
return JSON.stringify(
|
|
|
|
|
|
{
|
|
|
|
|
|
mcp: {
|
|
|
|
|
|
ktx: {
|
|
|
|
|
|
type: 'remote',
|
|
|
|
|
|
url: endpoint.url,
|
|
|
|
|
|
enabled: true,
|
|
|
|
|
|
...(tokenHeaders(endpoint) ? { headers: tokenHeaders(endpoint) } : {}),
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
null,
|
|
|
|
|
|
2,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
function universalMcpSnippet(endpoint: KtxMcpEndpointInfo): string {
|
|
|
|
|
|
return [
|
|
|
|
|
|
'Universal MCP endpoint:',
|
|
|
|
|
|
endpoint.url,
|
|
|
|
|
|
...(endpoint.tokenAuth ? ['Header: Authorization: Bearer ${KTX_MCP_TOKEN}'] : []),
|
|
|
|
|
|
].join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 02:35:09 +02:00
|
|
|
|
function claudeConfigPath(projectDir: string, scope: KtxAgentScope): { path: string; jsonPath: string[] } {
|
|
|
|
|
|
const home = process.env.HOME ?? '';
|
|
|
|
|
|
if (scope === 'global') {
|
|
|
|
|
|
return { path: join(home, '.claude.json'), jsonPath: ['mcpServers', 'ktx'] };
|
|
|
|
|
|
}
|
|
|
|
|
|
if (scope === 'local') {
|
|
|
|
|
|
return { path: join(home, '.claude.json'), jsonPath: ['projects', resolve(projectDir), 'mcpServers', 'ktx'] };
|
|
|
|
|
|
}
|
|
|
|
|
|
return { path: join(resolve(projectDir), '.mcp.json'), jsonPath: ['mcpServers', 'ktx'] };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function cursorConfigPath(projectDir: string, scope: KtxAgentScope): { path: string; jsonPath: string[] } {
|
|
|
|
|
|
const home = process.env.HOME ?? '';
|
|
|
|
|
|
return {
|
|
|
|
|
|
path: scope === 'global' ? join(home, '.cursor/mcp.json') : join(resolve(projectDir), '.cursor/mcp.json'),
|
|
|
|
|
|
jsonPath: ['mcpServers', 'ktx'],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
function claudeDesktopConfigPath(): { path: string; jsonPath: string[] } {
|
|
|
|
|
|
const home = process.env.HOME ?? '';
|
|
|
|
|
|
const path =
|
|
|
|
|
|
process.platform === 'win32'
|
|
|
|
|
|
? join(process.env.APPDATA ?? join(home, 'AppData/Roaming'), 'Claude/claude_desktop_config.json')
|
|
|
|
|
|
: join(home, 'Library/Application Support/Claude/claude_desktop_config.json');
|
|
|
|
|
|
return { path, jsonPath: ['mcpServers', 'ktx'] };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const CLAUDE_DESKTOP_FORWARDED_ENV_KEYS = ['OPENAI_API_KEY', 'ANTHROPIC_API_KEY'] as const;
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
function collectClaudeDesktopForwardedEnv(source: NodeJS.ProcessEnv): Record<string, string> {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const captured: Record<string, string> = {};
|
|
|
|
|
|
for (const [key, value] of Object.entries(source)) {
|
|
|
|
|
|
if (value === undefined || value === '') continue;
|
|
|
|
|
|
if (key.startsWith('KTX_') || (CLAUDE_DESKTOP_FORWARDED_ENV_KEYS as readonly string[]).includes(key)) {
|
|
|
|
|
|
captured[key] = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return captured;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-24 16:57:23 +02:00
|
|
|
|
function claudeDesktopMcpEntry(input: { projectDir: string; env?: NodeJS.ProcessEnv }): Record<string, unknown> {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const captured = collectClaudeDesktopForwardedEnv(input.env ?? process.env);
|
2026-05-24 16:57:23 +02:00
|
|
|
|
const launcher = ktxCliLauncher();
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
return {
|
2026-05-24 16:57:23 +02:00
|
|
|
|
command: launcher.command,
|
|
|
|
|
|
args: [...launcher.args, '--project-dir', input.projectDir, 'mcp', 'stdio'],
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
...(Object.keys(captured).length > 0 ? { env: captured } : {}),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 02:35:09 +02:00
|
|
|
|
async function installMcpClientConfig(input: {
|
|
|
|
|
|
projectDir: string;
|
|
|
|
|
|
target: KtxAgentTarget;
|
|
|
|
|
|
scope: KtxAgentScope;
|
|
|
|
|
|
}): Promise<KtxMcpClientInstallResult> {
|
|
|
|
|
|
const entries: InstallEntry[] = [];
|
|
|
|
|
|
const snippets: string[] = [];
|
|
|
|
|
|
const notices: string[] = [];
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
if (input.target === 'claude-desktop') {
|
|
|
|
|
|
const config = claudeDesktopConfigPath();
|
|
|
|
|
|
await writeJsonKey(
|
|
|
|
|
|
config.path,
|
|
|
|
|
|
config.jsonPath,
|
2026-05-24 16:57:23 +02:00
|
|
|
|
claudeDesktopMcpEntry({ projectDir: input.projectDir }),
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
);
|
|
|
|
|
|
entries.push({ kind: 'json-key', path: config.path, jsonPath: config.jsonPath });
|
|
|
|
|
|
return { entries, snippets, notices };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const endpoint = await resolveMcpEndpoint(input.projectDir);
|
2026-05-15 02:35:09 +02:00
|
|
|
|
if (!endpoint.running) {
|
2026-05-18 18:54:20 -04:00
|
|
|
|
notices.push(MCP_DAEMON_REQUIRED_NOTICE);
|
2026-05-15 02:35:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (input.target === 'claude-code') {
|
|
|
|
|
|
const config = claudeConfigPath(input.projectDir, input.scope);
|
|
|
|
|
|
await writeJsonKey(config.path, config.jsonPath, claudeMcpEntry(endpoint));
|
|
|
|
|
|
entries.push({ kind: 'json-key', path: config.path, jsonPath: config.jsonPath });
|
|
|
|
|
|
} else if (input.target === 'cursor') {
|
|
|
|
|
|
const config = cursorConfigPath(input.projectDir, input.scope);
|
|
|
|
|
|
await writeJsonKey(config.path, config.jsonPath, cursorMcpEntry(endpoint));
|
|
|
|
|
|
entries.push({ kind: 'json-key', path: config.path, jsonPath: config.jsonPath });
|
|
|
|
|
|
} else if (input.target === 'codex') {
|
2026-05-18 18:54:20 -04:00
|
|
|
|
snippets.push(`Add this Codex MCP snippet to ~/.codex/config.toml:\n${codexSnippet(endpoint)}`);
|
2026-05-15 02:35:09 +02:00
|
|
|
|
} else if (input.target === 'opencode') {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const path =
|
|
|
|
|
|
input.scope === 'global'
|
|
|
|
|
|
? '~/.config/opencode/opencode.json'
|
|
|
|
|
|
: relative(input.projectDir, join(input.projectDir, 'opencode.json'));
|
2026-05-18 18:54:20 -04:00
|
|
|
|
snippets.push(`Add this OpenCode MCP snippet to ${path}:\n${opencodeSnippet(endpoint)}`);
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
} else if (input.target === 'universal') {
|
2026-05-18 18:54:20 -04:00
|
|
|
|
snippets.push(`Use this universal MCP endpoint with unsupported MCP clients:\n${universalMcpSnippet(endpoint)}`);
|
2026-05-15 02:35:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { entries, snippets, notices };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
function plannedMcpJsonEntries(input: {
|
|
|
|
|
|
projectDir: string;
|
|
|
|
|
|
target: KtxAgentTarget;
|
|
|
|
|
|
scope: KtxAgentScope;
|
|
|
|
|
|
}): InstallEntry[] {
|
|
|
|
|
|
if (input.target === 'claude-code') {
|
|
|
|
|
|
const config = claudeConfigPath(input.projectDir, input.scope);
|
|
|
|
|
|
return [{ kind: 'json-key', path: config.path, jsonPath: config.jsonPath }];
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.target === 'claude-desktop') {
|
|
|
|
|
|
const config = claudeDesktopConfigPath();
|
|
|
|
|
|
return [{ kind: 'json-key', path: config.path, jsonPath: config.jsonPath }];
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.target === 'cursor') {
|
|
|
|
|
|
const config = cursorConfigPath(input.projectDir, input.scope);
|
|
|
|
|
|
return [{ kind: 'json-key', path: config.path, jsonPath: config.jsonPath }];
|
|
|
|
|
|
}
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
function agentInstallManifestPath(projectDir: string): string {
|
2026-05-10 23:51:24 +02:00
|
|
|
|
return join(resolve(projectDir), '.ktx/agents/install-manifest.json');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-19 15:21:49 +02:00
|
|
|
|
function claudeDesktopAnalyticsSkillBundlePath(projectDir: string): string {
|
|
|
|
|
|
return join(resolve(projectDir), '.ktx/agents/claude/ktx-analytics.zip');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function claudeDesktopAdminSkillBundlePath(projectDir: string): string {
|
|
|
|
|
|
return join(resolve(projectDir), '.ktx/agents/claude/ktx.zip');
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export function plannedKtxAgentFiles(input: {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
projectDir: string;
|
2026-05-10 23:51:24 +02:00
|
|
|
|
target: KtxAgentTarget;
|
|
|
|
|
|
scope: KtxAgentScope;
|
|
|
|
|
|
mode: KtxAgentInstallMode;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}): InstallEntry[] {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const withAdminCli = input.mode === 'mcp-cli';
|
|
|
|
|
|
|
2026-05-10 23:12:26 +02:00
|
|
|
|
if (input.scope === 'global') {
|
|
|
|
|
|
if (input.target === 'claude-code') {
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const home = process.env.HOME ?? '';
|
|
|
|
|
|
return [
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
{ kind: 'file', path: join(home, '.claude/skills/ktx-analytics/SKILL.md'), role: 'analytics-skill' as const },
|
|
|
|
|
|
...(withAdminCli
|
|
|
|
|
|
? [
|
|
|
|
|
|
{ kind: 'file' as const, path: join(home, '.claude/skills/ktx/SKILL.md'), role: 'skill' as const },
|
|
|
|
|
|
{ kind: 'file' as const, path: join(home, '.claude/rules/ktx.md'), role: 'rule' as const },
|
|
|
|
|
|
]
|
|
|
|
|
|
: []),
|
2026-05-10 23:13:17 -07:00
|
|
|
|
];
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
if (input.target === 'codex') {
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const codexHome = process.env.CODEX_HOME ?? join(process.env.HOME ?? '', '.codex');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return [
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
{ kind: 'file', path: join(codexHome, 'skills/ktx-analytics/SKILL.md'), role: 'analytics-skill' as const },
|
|
|
|
|
|
...(withAdminCli
|
|
|
|
|
|
? [
|
|
|
|
|
|
{ kind: 'file' as const, path: join(codexHome, 'skills/ktx/SKILL.md'), role: 'skill' as const },
|
|
|
|
|
|
{ kind: 'file' as const, path: join(codexHome, 'instructions/ktx.md'), role: 'rule' as const },
|
|
|
|
|
|
]
|
|
|
|
|
|
: []),
|
2026-05-10 23:12:26 +02:00
|
|
|
|
];
|
|
|
|
|
|
}
|
2026-05-15 02:35:09 +02:00
|
|
|
|
if (input.target === 'cursor' || input.target === 'opencode') {
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
if (input.target === 'claude-desktop') {
|
|
|
|
|
|
return [
|
2026-05-19 15:21:49 +02:00
|
|
|
|
{
|
|
|
|
|
|
kind: 'file',
|
|
|
|
|
|
path: claudeDesktopAnalyticsSkillBundlePath(input.projectDir),
|
|
|
|
|
|
role: 'claude-desktop-skill-bundle' as const,
|
|
|
|
|
|
},
|
|
|
|
|
|
...(withAdminCli
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
kind: 'file' as const,
|
|
|
|
|
|
path: claudeDesktopAdminSkillBundlePath(input.projectDir),
|
|
|
|
|
|
role: 'claude-desktop-skill-bundle' as const,
|
|
|
|
|
|
},
|
|
|
|
|
|
]
|
|
|
|
|
|
: []),
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
];
|
|
|
|
|
|
}
|
2026-05-13 17:55:25 -04:00
|
|
|
|
throw new Error(`Global ${input.target} installation is not supported; omit --global.`);
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const root = resolve(input.projectDir);
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const analyticsEntries: Partial<Record<KtxAgentTarget, InstallEntry[]>> = {
|
|
|
|
|
|
'claude-code': [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.claude/skills/ktx-analytics/SKILL.md'), role: 'analytics-skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
codex: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.agents/skills/ktx-analytics/SKILL.md'), role: 'analytics-skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
cursor: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.cursor/rules/ktx-analytics.mdc'), role: 'analytics-skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
opencode: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.opencode/commands/ktx-analytics.md'), role: 'analytics-skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
universal: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.agents/skills/ktx-analytics/SKILL.md'), role: 'analytics-skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
'claude-desktop': [],
|
|
|
|
|
|
};
|
2026-05-15 02:35:09 +02:00
|
|
|
|
const cliEntries: Partial<Record<KtxAgentTarget, InstallEntry[]>> = {
|
|
|
|
|
|
'claude-code': [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.claude/skills/ktx/SKILL.md'), role: 'skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
codex: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.agents/skills/ktx/SKILL.md'), role: 'skill' },
|
|
|
|
|
|
],
|
|
|
|
|
|
cursor: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.cursor/rules/ktx.mdc') },
|
|
|
|
|
|
],
|
|
|
|
|
|
opencode: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.opencode/commands/ktx.md') },
|
|
|
|
|
|
],
|
|
|
|
|
|
universal: [
|
|
|
|
|
|
{ kind: 'file', path: join(root, '.agents/skills/ktx/SKILL.md') },
|
|
|
|
|
|
],
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
'claude-desktop': [],
|
2026-05-10 23:12:26 +02:00
|
|
|
|
};
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const ruleEntries: Partial<Record<KtxAgentTarget, InstallEntry>> = {
|
|
|
|
|
|
'claude-code': { kind: 'file', path: join(root, '.claude/rules/ktx.md'), role: 'rule' },
|
|
|
|
|
|
codex: { kind: 'file', path: join(root, '.codex/instructions/ktx.md'), role: 'rule' },
|
|
|
|
|
|
};
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
return [
|
|
|
|
|
|
...(analyticsEntries[input.target] ?? []),
|
|
|
|
|
|
...(withAdminCli ? (cliEntries[input.target] ?? []) : []),
|
|
|
|
|
|
...(withAdminCli ? [ruleEntries[input.target]] : []),
|
|
|
|
|
|
].filter(
|
2026-05-12 23:51:46 +02:00
|
|
|
|
(entry): entry is InstallEntry => entry !== undefined,
|
|
|
|
|
|
);
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 16:01:58 -07:00
|
|
|
|
function ktxCliLauncher(): KtxCliLauncher {
|
|
|
|
|
|
return {
|
|
|
|
|
|
command: process.execPath,
|
|
|
|
|
|
args: [fileURLToPath(new URL('./bin.js', import.meta.url))],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
async function readAnalyticsSkillContent(): Promise<string> {
|
|
|
|
|
|
const path = fileURLToPath(new URL('./skills/analytics/SKILL.md', import.meta.url));
|
2026-05-15 02:35:09 +02:00
|
|
|
|
const content = await readFile(path, 'utf-8');
|
|
|
|
|
|
return content.endsWith('\n') ? content : `${content}\n`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 16:01:58 -07:00
|
|
|
|
function shellQuote(value: string): string {
|
|
|
|
|
|
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
function shellScriptQuote(value: string): string {
|
|
|
|
|
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 16:01:58 -07:00
|
|
|
|
function ktxCommandLine(launcher: KtxCliLauncher, args: string[]): string {
|
|
|
|
|
|
return [launcher.command, ...launcher.args, ...args].map(shellQuote).join(' ');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function cliInstructionContent(input: { projectDir: string; launcher: KtxCliLauncher }): string {
|
2026-05-15 15:31:51 -04:00
|
|
|
|
const projectDirArgs = ['--project-dir', input.projectDir];
|
|
|
|
|
|
const jsonProjectDirArgs = ['--json', ...projectDirArgs];
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return [
|
|
|
|
|
|
'---',
|
2026-05-10 23:51:24 +02:00
|
|
|
|
'name: ktx',
|
2026-05-13 13:01:56 +02:00
|
|
|
|
'description: Use local KTX semantic context and wiki knowledge for this project.',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'---',
|
|
|
|
|
|
'',
|
2026-05-10 23:51:24 +02:00
|
|
|
|
'# KTX Local Context',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'',
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
'This is an admin/developer CLI helper. End-user data agents should use the KTX MCP tools when available.',
|
|
|
|
|
|
'',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
`Use this project with \`--project-dir ${input.projectDir}\`.`,
|
2026-05-10 16:01:58 -07:00
|
|
|
|
'Commands are pinned to the local KTX CLI path that created this file, so agents do not need `ktx` in PATH.',
|
|
|
|
|
|
'If the CLI path no longer exists after moving this checkout or reinstalling KTX, rerun `ktx setup --agents`.',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'',
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
'Agents must not print secrets, credential references, environment variable values, or file contents from ' +
|
|
|
|
|
|
'`.ktx/secrets`.',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'',
|
|
|
|
|
|
'Available commands:',
|
|
|
|
|
|
'',
|
2026-05-15 15:31:51 -04:00
|
|
|
|
`- \`${ktxCommandLine(input.launcher, ['status', ...jsonProjectDirArgs])}\``,
|
2026-05-20 01:52:37 +02:00
|
|
|
|
`- \`${ktxCommandLine(input.launcher, ['sl', ...jsonProjectDirArgs])}\``,
|
|
|
|
|
|
`- \`${ktxCommandLine(input.launcher, ['sl', '<text>', ...jsonProjectDirArgs, '--connection-id', '<id>'])}\``,
|
2026-05-10 16:01:58 -07:00
|
|
|
|
`- \`${ktxCommandLine(input.launcher, [
|
|
|
|
|
|
'sl',
|
|
|
|
|
|
'query',
|
|
|
|
|
|
...projectDirArgs,
|
|
|
|
|
|
'--connection-id',
|
|
|
|
|
|
'<id>',
|
|
|
|
|
|
'--query-file',
|
|
|
|
|
|
'<path>',
|
2026-05-15 15:31:51 -04:00
|
|
|
|
'--format',
|
|
|
|
|
|
'json',
|
2026-05-10 16:01:58 -07:00
|
|
|
|
'--execute',
|
|
|
|
|
|
'--max-rows',
|
|
|
|
|
|
'100',
|
|
|
|
|
|
])}\``,
|
2026-05-20 01:52:37 +02:00
|
|
|
|
`- \`${ktxCommandLine(input.launcher, ['wiki', '<query>', ...jsonProjectDirArgs, '--limit', '10'])}\``,
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'',
|
2026-05-13 13:01:56 +02:00
|
|
|
|
'Use semantic-layer queries before direct database access. Do not print secrets or credential references.',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
'',
|
|
|
|
|
|
].join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-19 15:21:49 +02:00
|
|
|
|
async function writeClaudeDesktopSkillBundle(input: {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
projectDir: string;
|
|
|
|
|
|
path: string;
|
2026-05-19 15:21:49 +02:00
|
|
|
|
skillName: 'ktx-analytics' | 'ktx';
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
launcher: KtxCliLauncher;
|
|
|
|
|
|
}): Promise<void> {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
const content =
|
|
|
|
|
|
input.skillName === 'ktx-analytics'
|
|
|
|
|
|
? await readAnalyticsSkillContent()
|
|
|
|
|
|
: cliInstructionContent({ projectDir: input.projectDir, launcher: input.launcher });
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const files: Record<string, Uint8Array> = {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
[`${input.skillName}/SKILL.md`]: strToU8(content),
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
};
|
|
|
|
|
|
await mkdir(dirname(input.path), { recursive: true });
|
|
|
|
|
|
await writeFile(input.path, Buffer.from(zipSync(files)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-19 15:21:49 +02:00
|
|
|
|
function claudeDesktopSkillNameForBundle(path: string): 'ktx-analytics' | 'ktx' {
|
|
|
|
|
|
if (path.endsWith('/ktx-analytics.zip')) {
|
|
|
|
|
|
return 'ktx-analytics';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (path.endsWith('/ktx.zip')) {
|
|
|
|
|
|
return 'ktx';
|
|
|
|
|
|
}
|
|
|
|
|
|
throw new Error(`Unsupported Claude Desktop skill bundle path: ${path}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:13:17 -07:00
|
|
|
|
function ruleInstructionContent(input: { projectDir: string }): string {
|
|
|
|
|
|
return [
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
`Use the \`ktx\` CLI to query local semantic context and wiki knowledge for this project ` +
|
|
|
|
|
|
`(\`--project-dir ${input.projectDir}\`).`,
|
2026-05-10 23:13:17 -07:00
|
|
|
|
'',
|
|
|
|
|
|
'Use when the user asks about data schemas, metrics, dimensions, database structure, or wants to run SQL queries.',
|
|
|
|
|
|
'',
|
|
|
|
|
|
'Do not use for general programming, code review, or tasks unrelated to data and analytics.',
|
|
|
|
|
|
'',
|
|
|
|
|
|
].join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:12:26 +02:00
|
|
|
|
async function removeJsonKey(path: string, jsonPath: string[]): Promise<void> {
|
|
|
|
|
|
const root = JSON.parse(await readFile(path, 'utf-8')) as Record<string, unknown>;
|
|
|
|
|
|
let cursor: Record<string, unknown> = root;
|
|
|
|
|
|
for (const segment of jsonPath.slice(0, -1)) {
|
|
|
|
|
|
const next = cursor[segment];
|
|
|
|
|
|
if (!next || typeof next !== 'object' || Array.isArray(next)) return;
|
|
|
|
|
|
cursor = next as Record<string, unknown>;
|
|
|
|
|
|
}
|
|
|
|
|
|
delete cursor[jsonPath.at(-1) as string];
|
|
|
|
|
|
await writeFile(path, `${JSON.stringify(root, null, 2)}\n`, 'utf-8');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export async function readKtxAgentInstallManifest(projectDir: string): Promise<KtxAgentInstallManifest | null> {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
try {
|
2026-05-10 23:51:24 +02:00
|
|
|
|
return JSON.parse(await readFile(agentInstallManifestPath(projectDir), 'utf-8')) as KtxAgentInstallManifest;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
} catch {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
async function writeManifest(projectDir: string, manifest: KtxAgentInstallManifest): Promise<void> {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
const path = agentInstallManifestPath(projectDir);
|
|
|
|
|
|
await mkdir(dirname(path), { recursive: true });
|
|
|
|
|
|
await writeFile(path, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function entryKey(entry: InstallEntry): string {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
return entry.kind === 'json-key'
|
|
|
|
|
|
? `${entry.kind}:${entry.path}:${entry.jsonPath.join('.')}`
|
|
|
|
|
|
: `${entry.kind}:${entry.path}`;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function mergeManifest(
|
|
|
|
|
|
projectDir: string,
|
2026-05-10 23:51:24 +02:00
|
|
|
|
existing: KtxAgentInstallManifest | null,
|
|
|
|
|
|
installs: KtxAgentInstallManifest['installs'],
|
2026-05-10 23:12:26 +02:00
|
|
|
|
entries: InstallEntry[],
|
2026-05-10 23:51:24 +02:00
|
|
|
|
): KtxAgentInstallManifest {
|
|
|
|
|
|
const installMap = new Map<string, KtxAgentInstallManifest['installs'][number]>();
|
2026-05-10 23:12:26 +02:00
|
|
|
|
for (const install of [...(existing?.installs ?? []), ...installs]) {
|
|
|
|
|
|
installMap.set(`${install.target}:${install.scope}:${install.mode}`, install);
|
|
|
|
|
|
}
|
|
|
|
|
|
const entryMap = new Map<string, InstallEntry>();
|
|
|
|
|
|
for (const entry of [...(existing?.entries ?? []), ...entries]) {
|
|
|
|
|
|
entryMap.set(entryKey(entry), entry);
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
version: 1,
|
|
|
|
|
|
projectDir,
|
|
|
|
|
|
installedAt: new Date().toISOString(),
|
|
|
|
|
|
installs: [...installMap.values()],
|
|
|
|
|
|
entries: [...entryMap.values()],
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export async function removeKtxAgentInstall(projectDir: string, io: KtxCliIo): Promise<number> {
|
|
|
|
|
|
const manifest = await readKtxAgentInstallManifest(projectDir);
|
2026-05-10 23:12:26 +02:00
|
|
|
|
if (!manifest) {
|
2026-05-10 23:51:24 +02:00
|
|
|
|
io.stdout.write('No KTX agent installation manifest found.\n');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (const entry of manifest.entries) {
|
|
|
|
|
|
if (entry.kind === 'file') await rm(entry.path, { force: true });
|
|
|
|
|
|
if (entry.kind === 'json-key') await removeJsonKey(entry.path, entry.jsonPath).catch(() => undefined);
|
|
|
|
|
|
}
|
|
|
|
|
|
await rm(agentInstallManifestPath(projectDir), { force: true });
|
2026-05-10 23:51:24 +02:00
|
|
|
|
io.stdout.write('Removed KTX agent integration files from manifest.\n');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
interface KtxSetupAgentsPromptAdapter {
|
2026-05-13 17:01:48 +02:00
|
|
|
|
select(options: { message: string; options: KtxSetupPromptOption[] }): Promise<string>;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
multiselect(options: {
|
|
|
|
|
|
message: string;
|
2026-05-13 17:01:48 +02:00
|
|
|
|
options: KtxSetupPromptOption[];
|
2026-05-10 23:12:26 +02:00
|
|
|
|
required?: boolean;
|
|
|
|
|
|
}): Promise<string[]>;
|
|
|
|
|
|
cancel(message: string): void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export interface KtxSetupAgentsDeps {
|
|
|
|
|
|
prompts?: KtxSetupAgentsPromptAdapter;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
function createPromptAdapter(): KtxSetupAgentsPromptAdapter {
|
2026-05-13 17:01:48 +02:00
|
|
|
|
return createKtxSetupPromptAdapter({
|
|
|
|
|
|
selectCancelValue: 'back',
|
|
|
|
|
|
multiselectCancelValue: 'back',
|
|
|
|
|
|
confirmEmptyOptionalMultiselect: true,
|
|
|
|
|
|
});
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const targetDisplayNames: Record<KtxAgentTarget, string> = {
|
|
|
|
|
|
'claude-code': 'Claude Code',
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
'claude-desktop': 'Claude Desktop',
|
2026-05-10 23:13:17 -07:00
|
|
|
|
codex: 'Codex',
|
|
|
|
|
|
cursor: 'Cursor',
|
|
|
|
|
|
opencode: 'OpenCode',
|
|
|
|
|
|
universal: 'Universal .agents',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
export function targetDisplayName(target: string): string {
|
|
|
|
|
|
return Object.hasOwn(targetDisplayNames, target) ? targetDisplayNames[target as KtxAgentTarget] : target;
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function targetSupportsGlobalScope(target: KtxAgentTarget): boolean {
|
|
|
|
|
|
return target === 'claude-code' || target === 'codex';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function effectiveInstallScope(target: KtxAgentTarget, requestedScope: KtxAgentScope): KtxAgentScope {
|
|
|
|
|
|
return target === 'claude-desktop' ? 'global' : requestedScope;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
function scopeDisplayName(scope: KtxAgentScope): string {
|
|
|
|
|
|
if (scope === 'project') return 'Project scope';
|
|
|
|
|
|
if (scope === 'global') return 'Global scope';
|
|
|
|
|
|
return 'Local scope';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function targetUsesHttpMcpDaemon(target: KtxAgentTarget): boolean {
|
|
|
|
|
|
return target !== 'claude-desktop';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function manualMcpConfigInstruction(target: KtxAgentTarget, scope: KtxAgentScope): string {
|
|
|
|
|
|
if (target === 'codex') {
|
|
|
|
|
|
return 'Add the snippet shown below to ~/.codex/config.toml.';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (target === 'opencode') {
|
|
|
|
|
|
return scope === 'global'
|
|
|
|
|
|
? 'Add the snippet shown below to ~/.config/opencode/opencode.json.'
|
|
|
|
|
|
: 'Add the snippet shown below to opencode.json.';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (target === 'universal') {
|
|
|
|
|
|
return 'Use the printed endpoint with unsupported MCP clients.';
|
|
|
|
|
|
}
|
|
|
|
|
|
return 'Add the printed snippet manually.';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function guidanceInstallLine(target: KtxAgentTarget): string {
|
|
|
|
|
|
if (target === 'codex') return 'Codex guidance installed';
|
|
|
|
|
|
if (target === 'cursor') return 'Cursor rules installed';
|
|
|
|
|
|
if (target === 'opencode') return 'OpenCode commands installed';
|
|
|
|
|
|
if (target === 'universal') return '.agents guidance installed';
|
|
|
|
|
|
return 'Agent guidance installed';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function hasEntryRole(entries: InstallEntry[], role: Extract<InstallEntry, { kind: 'file' }>['role']): boolean {
|
|
|
|
|
|
return entries.some((entry) => entry.kind === 'file' && entry.role === role);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function hasAdminCliEntries(entries: InstallEntry[]): boolean {
|
|
|
|
|
|
return entries.some(
|
|
|
|
|
|
(entry) =>
|
|
|
|
|
|
entry.kind === 'file' &&
|
|
|
|
|
|
(entry.role === 'skill' || entry.role === 'rule' || entry.role === undefined),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
2026-05-19 15:21:49 +02:00
|
|
|
|
export interface InstallSummaryEntry {
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
lines: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatInlinePath(path: string): string {
|
|
|
|
|
|
const home = process.env.HOME;
|
|
|
|
|
|
if (!home) return path;
|
|
|
|
|
|
const resolvedHome = resolve(home);
|
|
|
|
|
|
if (path === resolvedHome) return '~';
|
|
|
|
|
|
if (path.startsWith(`${resolvedHome}/`)) {
|
|
|
|
|
|
return `~/${relative(resolvedHome, path)}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
chore(workspace): gate dead-code with knip production mode (#196)
* refactor(workspace): relocate @ktx/llm source into packages/cli/src/llm
* refactor(workspace): rewrite @ktx/llm imports to relative paths
* refactor(workspace): fold internal packages into cli
* chore(workspace): gate dead-code with knip production mode
Turn on production-mode knip plus an autofix run in pre-commit and the
`pnpm dead-code` script, document the `/** @internal */` convention for
test-only exports in AGENTS.md, annotate test-only exports across the
CLI with that JSDoc, and drop dead exports/wrappers the new gate
surfaced (e.g. `cli-project.ts`, `lookerRuntimeSourceToFileAdapterSource`,
`createLocalScanEnrichmentProvidersFromConfig`,
`PGLITE_OWNER_PROCESS_BACKEND_CAPABILITIES`, stale type re-exports).
Replace the loose `ignoreIssues` allowlist in `knip.json` with explicit
production entries so cross-package barrel leaks are caught.
* refactor(cli): delete internal barrel index.ts files
The 34 `index.ts` re-export barrels inside `packages/cli/src/` were
holdovers from the pre-fold multi-workspace structure. Post-fold-in they
served no production purpose: external consumers go through the single
package main entry, and in-repo callers mostly imported through them
only because the path was short. Internally, knip flagged most barrel
re-exports as production-dead (only reached via tests).
This change:
- Deletes every internal barrel except `packages/cli/src/index.ts`
(the published package entry).
- Rewrites ~270 source/test files to import each name directly from
the file that defines it.
- Moves `tools/warehouse-verification/index.ts` to
`create-warehouse-verification-tools.ts` (the function it defined
locally) and updates its single consumer.
- Renames `search/backend-conformance.ts` → `.test-utils.ts` to match
the existing test-helper file convention.
- Deletes 13 dead test-only chains (dbt-descriptions/*,
live-database/extracted-schema, live-database/structural-sync,
relationship-* feedback/review chain) plus their tests and a
cascading orphan integration test.
- Updates test mocks that pointed at deleted barrel paths
(notion-client, connector barrels in scan/local-scan-connectors
tests) to mock the source files instead.
- Points the maintainer benchmark script
(`scripts/relationship-benchmark-report.mjs`) at source files
instead of `dist/context/scan/index.js`.
- Drops the barrel `!` entries from `knip.json`; adds explicit
production entries only for the benchmark code reached via dist by
the maintainer script.
Net: 413 files changed, ~1.2k insertions, ~9.4k deletions.
`pnpm run dead-code` (Biome + knip default + knip production) and
`pnpm run type-check` are clean; 2277 tests pass.
* refactor(workspace): rename @ktx/cli to @kaelio/ktx and pack it directly
Promote the CLI workspace package to the public name `@kaelio/ktx` and
drop the separate `scripts/build-public-npm-package.mjs` wrapper. The
CLI package is now publishable in place (`publishConfig.access: public`,
`provenance: true`), so artifact packing uses `pnpm pack` against
`packages/cli/` instead of assembling a parallel package tree.
Updates all workspace filter invocations, docs, tests, and release
readiness checks to reference the new package name, and folds the
tarball-name helper into `scripts/public-npm-release-metadata.mjs`.
* docs: align "agent clients" and "data agents" terminology
Replace "client agents" with "agent clients" and "database agents" with
"data agents" across AGENTS.md, README.md, the docs-site copy, and the
matching setup-agents test description, matching the canonical
vocabulary in docs/terminology.md.
Also moves packages/cli/tsconfig.json's tsBuildInfoFile from
node_modules/.cache/ to dist/.tsbuildinfo so incremental builds survive
node_modules reinstalls.
* refactor(release): single source of truth for package version
Make packages/cli/package.json the single source of truth for the
@kaelio/ktx version. publicNpmPackageVersion() now reads it directly,
so artifact filenames, release-readiness checks, and the Python wheel
version all derive from one field. The duplicate
release-policy.json.publicNpmPackageVersion is removed.
Previously the two fields could drift: tarballs were named
kaelio-ktx-0.4.1.tgz while internally containing
@kaelio/ktx@0.0.0-private.
- update-public-release-version.mjs rewrites both Python pyproject.toml
files (ktx-daemon, ktx-sl) alongside the npm package.jsons,
normalizing the version for PEP 440 (e.g. 0.1.0-rc.2 -> 0.1.0rc2).
- semantic-release-config.cjs adds the two pyproject.toml files to
@semantic-release/git assets so the release commit back to main
carries every version source in lockstep.
- The six "?? '0.0.0-private'" fallback literals across the CLI are
replaced with "?? getKtxCliPackageInfo().version", and
createDefaultKtxMcpServer makes its version arg required.
- docs/release.md describes the actual commit-back model: the dev tree
always reflects the most recent release; no sentinel pin to
maintain.
Verified: pnpm run artifacts:build now produces
kaelio-ktx-0.4.1.tgz and kaelio_ktx-0.4.1-py3-none-any.whl with
@kaelio/ktx@0.4.1 inside. Full type-check, dead-code, and
2287 vitests + 173 script tests pass.
* refactor(cli): inject embedding provider resolution and detect sentence-transformers runtime
Make resolveProjectEmbeddingProvider and runtimeIo injectable in ingest and
scan command entrypoints so tests can stub them, and teach
resolvePublicIngestRuntimeRequirements to flag the local-embeddings runtime
feature when ktx.yaml selects sentence-transformers.
* chore(cli): mark buildLocalStatsStatus and LocalStatsStatus as @internal
Both symbols are consumed only by status-project.test.ts. Annotating with
/** @internal */ keeps knip's production-mode check clean without changing
runtime behavior.
* fix(cli): use real package metadata in print-command-tree
The stubbed package name embedded a forbidden product identifier that
tripped the boundary check in CI. Read the metadata from package.json
instead — keeps the rendered tree unchanged and removes a duplicate
source of truth.
* feat(cli): show embedding coverage in `ktx status`, drop duplicate disk counts
Inline `(N embedded)` next to the Wiki scope counts and Semantic-layer
source counts, computed with `SUM(embedding_json IS NOT NULL)` over
`knowledge_pages` and `local_sl_sources`. Rename the "Knowledge" label to
"Wiki" (canonical per `docs/terminology.md`) and rename the matching
`localStats.knowledgePages` field to `localStats.wikiPages`.
Drop `wiki=N md` and `semantic-layer=N yaml` from the Disk row — those
duplicated the per-surface rows above. Disk now reports only actual byte
usage (db, cache, raw-sources). The unused `wikiGlobalMarkdownCount` /
`semanticLayerYamlCount` fields, the `isMarkdownEntry` / `isYamlEntry`
helpers, and the `filter` arg on `summarizeDir` are removed.
2026-05-21 15:28:58 +02:00
|
|
|
|
/** @internal */
|
2026-05-19 15:21:49 +02:00
|
|
|
|
export function formatInstallSummaryLines(
|
2026-05-10 23:13:17 -07:00
|
|
|
|
installs: Array<{ target: KtxAgentTarget; scope: KtxAgentScope; mode: KtxAgentInstallMode }>,
|
|
|
|
|
|
entries: InstallEntry[],
|
|
|
|
|
|
projectDir: string,
|
2026-05-19 15:21:49 +02:00
|
|
|
|
): InstallSummaryEntry[] {
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const entriesByTarget = new Map<KtxAgentTarget, InstallEntry[]>();
|
|
|
|
|
|
for (const install of installs) {
|
2026-05-15 02:35:09 +02:00
|
|
|
|
const plannedFilePaths = new Set(
|
|
|
|
|
|
plannedKtxAgentFiles({ projectDir, ...install })
|
|
|
|
|
|
.filter((entry) => entry.kind === 'file')
|
|
|
|
|
|
.map((entry) => entry.path),
|
|
|
|
|
|
);
|
|
|
|
|
|
entriesByTarget.set(
|
|
|
|
|
|
install.target,
|
|
|
|
|
|
entries.filter((entry) => entry.kind === 'file' && plannedFilePaths.has(entry.path)),
|
|
|
|
|
|
);
|
2026-05-10 23:13:17 -07:00
|
|
|
|
}
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const mcpEntriesByTarget = new Map<KtxAgentTarget, InstallEntry[]>();
|
|
|
|
|
|
for (const install of installs) {
|
|
|
|
|
|
const plannedMcpKeys = new Set(plannedMcpJsonEntries({ projectDir, ...install }).map(entryKey));
|
|
|
|
|
|
mcpEntriesByTarget.set(
|
|
|
|
|
|
install.target,
|
|
|
|
|
|
entries.filter((entry) => entry.kind === 'json-key' && plannedMcpKeys.has(entryKey(entry))),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-05-10 23:13:17 -07:00
|
|
|
|
|
2026-05-19 15:21:49 +02:00
|
|
|
|
return installs.map((install) => {
|
2026-05-10 23:13:17 -07:00
|
|
|
|
const targetEntries = entriesByTarget.get(install.target) ?? [];
|
2026-05-18 18:54:20 -04:00
|
|
|
|
const mcpEntry = mcpEntriesByTarget
|
|
|
|
|
|
.get(install.target)
|
|
|
|
|
|
?.find((entry): entry is Extract<InstallEntry, { kind: 'json-key' }> => entry.kind === 'json-key');
|
2026-05-19 15:21:49 +02:00
|
|
|
|
const lines: string[] = [];
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
if (mcpEntry) {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push(formatInlinePath(mcpEntry.path));
|
2026-05-18 18:54:20 -04:00
|
|
|
|
} else if (install.target !== 'claude-desktop') {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push(manualMcpConfigInstruction(install.target, install.scope));
|
2026-05-18 18:54:20 -04:00
|
|
|
|
}
|
2026-05-19 15:21:49 +02:00
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
if (targetUsesHttpMcpDaemon(install.target)) {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push('Requires MCP to be started.');
|
2026-05-18 18:54:20 -04:00
|
|
|
|
}
|
2026-05-19 15:21:49 +02:00
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
const hasAnalytics = hasEntryRole(targetEntries, 'analytics-skill');
|
|
|
|
|
|
const hasAdmin = hasAdminCliEntries(targetEntries);
|
2026-05-19 15:21:49 +02:00
|
|
|
|
const claudeDesktopSkillBundles = targetEntries.filter(
|
|
|
|
|
|
(entry): entry is Extract<InstallEntry, { kind: 'file' }> =>
|
|
|
|
|
|
entry.kind === 'file' && entry.role === 'claude-desktop-skill-bundle',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
if (install.target === 'claude-code') {
|
|
|
|
|
|
if (hasAnalytics) {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push('Analytics skill installed.');
|
2026-05-10 23:13:17 -07:00
|
|
|
|
}
|
2026-05-18 18:54:20 -04:00
|
|
|
|
if (hasAdmin) {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push('Admin CLI skill installed.');
|
2026-05-18 18:54:20 -04:00
|
|
|
|
}
|
2026-05-19 15:21:49 +02:00
|
|
|
|
} else if (install.target === 'claude-desktop') {
|
|
|
|
|
|
if (claudeDesktopSkillBundles.length > 0) {
|
|
|
|
|
|
lines.push('Skill bundles:');
|
|
|
|
|
|
for (const bundle of claudeDesktopSkillBundles) {
|
|
|
|
|
|
lines.push(` ${bundle.path}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (hasAnalytics || hasAdmin) {
|
|
|
|
|
|
lines.push(`${guidanceInstallLine(install.target)}.`);
|
2026-05-10 23:13:17 -07:00
|
|
|
|
}
|
2026-05-19 15:21:49 +02:00
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: `${targetDisplayName(install.target)} · ${scopeDisplayName(install.scope)}`,
|
|
|
|
|
|
lines,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function claudeDesktopSkillBundlePathsForInstalls(
|
|
|
|
|
|
projectDir: string,
|
|
|
|
|
|
installs: Array<{ target: KtxAgentTarget; scope: KtxAgentScope; mode: KtxAgentInstallMode }>,
|
|
|
|
|
|
): string[] {
|
|
|
|
|
|
return installs
|
|
|
|
|
|
.filter((install) => install.target === 'claude-desktop')
|
|
|
|
|
|
.flatMap((install) => plannedKtxAgentFiles({ projectDir, ...install }))
|
|
|
|
|
|
.filter(
|
|
|
|
|
|
(entry): entry is Extract<InstallEntry, { kind: 'file' }> =>
|
|
|
|
|
|
entry.kind === 'file' && entry.role === 'claude-desktop-skill-bundle',
|
|
|
|
|
|
)
|
|
|
|
|
|
.map((entry) => entry.path);
|
2026-05-10 23:13:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 18:54:20 -04:00
|
|
|
|
function humanList(values: string[]): string {
|
|
|
|
|
|
if (values.length <= 2) {
|
|
|
|
|
|
return values.join(' and ');
|
|
|
|
|
|
}
|
|
|
|
|
|
return `${values.slice(0, -1).join(', ')}, and ${values[values.length - 1]}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pushBlankLine(lines: string[]): void {
|
|
|
|
|
|
if (lines.length > 0 && lines[lines.length - 1] !== '') {
|
|
|
|
|
|
lines.push('');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function trimTrailingBlankLines(lines: string[]): void {
|
|
|
|
|
|
while (lines[lines.length - 1] === '') {
|
|
|
|
|
|
lines.pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function manualActionFromSnippet(snippet: string): {
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
instruction: string;
|
|
|
|
|
|
marker: 'PASTE' | 'USE';
|
|
|
|
|
|
body: string[];
|
|
|
|
|
|
} {
|
|
|
|
|
|
const [label = '', ...body] = snippet.split('\n');
|
|
|
|
|
|
const codexPrefix = 'Add this Codex MCP snippet to ~/.codex/config.toml:';
|
|
|
|
|
|
if (label === codexPrefix) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Configure Codex',
|
|
|
|
|
|
instruction: 'Open ~/.codex/config.toml, then paste this block:',
|
|
|
|
|
|
marker: 'PASTE',
|
|
|
|
|
|
body,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const opencodeMatch = label.match(/^Add this OpenCode MCP snippet to (.+):$/);
|
|
|
|
|
|
if (opencodeMatch) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Configure OpenCode',
|
|
|
|
|
|
instruction: `Open ${opencodeMatch[1]}, then paste this block:`,
|
|
|
|
|
|
marker: 'PASTE',
|
|
|
|
|
|
body,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (label === 'Use this universal MCP endpoint with unsupported MCP clients:') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Configure unsupported MCP clients',
|
|
|
|
|
|
instruction: 'Use this endpoint when setting up unsupported MCP clients:',
|
|
|
|
|
|
marker: 'USE',
|
|
|
|
|
|
body,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Configure MCP client',
|
|
|
|
|
|
instruction: label,
|
|
|
|
|
|
marker: 'PASTE',
|
|
|
|
|
|
body,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatAgentNextActions(input: {
|
|
|
|
|
|
projectDir: string;
|
|
|
|
|
|
installs: Array<{ target: KtxAgentTarget; scope: KtxAgentScope; mode: KtxAgentInstallMode }>;
|
|
|
|
|
|
notices: string[];
|
|
|
|
|
|
snippets: string[];
|
|
|
|
|
|
}): string {
|
|
|
|
|
|
const projectDir = resolve(input.projectDir);
|
|
|
|
|
|
const lines: string[] = [];
|
|
|
|
|
|
let step = 1;
|
|
|
|
|
|
|
|
|
|
|
|
for (const snippet of input.snippets) {
|
|
|
|
|
|
const action = manualActionFromSnippet(snippet);
|
|
|
|
|
|
lines.push(`${step}. ${action.title}`);
|
|
|
|
|
|
lines.push(` ${action.instruction}`);
|
|
|
|
|
|
if (action.body.length > 0) {
|
|
|
|
|
|
lines.push('', ` ${action.marker}:`);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (const line of action.body) {
|
|
|
|
|
|
lines.push(` ${line}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const httpTargets = input.installs
|
|
|
|
|
|
.filter((install) => targetUsesHttpMcpDaemon(install.target))
|
|
|
|
|
|
.map((install) => targetDisplayName(install.target));
|
|
|
|
|
|
if (input.notices.length > 0 && httpTargets.length > 0) {
|
|
|
|
|
|
lines.push(`${step}. Start MCP`);
|
|
|
|
|
|
lines.push(` Run this command before using ${humanList(httpTargets)}:`);
|
|
|
|
|
|
lines.push('');
|
|
|
|
|
|
lines.push(' RUN:');
|
|
|
|
|
|
lines.push(` ktx mcp start --project-dir ${projectDir}`);
|
|
|
|
|
|
lines.push('');
|
|
|
|
|
|
lines.push(' If you need to stop MCP later:');
|
|
|
|
|
|
lines.push(` ktx mcp stop --project-dir ${projectDir}`);
|
|
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const claudeCodeInstall = input.installs.find((install) => install.target === 'claude-code');
|
|
|
|
|
|
if (claudeCodeInstall) {
|
|
|
|
|
|
lines.push(`${step}. Open Claude Code`);
|
|
|
|
|
|
if (claudeCodeInstall.scope === 'project') {
|
|
|
|
|
|
lines.push(' Open Claude Code from the KTX project directory:');
|
|
|
|
|
|
lines.push('');
|
|
|
|
|
|
lines.push(' RUN:');
|
|
|
|
|
|
lines.push(` cd ${shellScriptQuote(projectDir)}`);
|
|
|
|
|
|
lines.push(' claude');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
lines.push(' RUN:');
|
|
|
|
|
|
lines.push(' claude');
|
|
|
|
|
|
}
|
|
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const cursorInstall = input.installs.find((install) => install.target === 'cursor');
|
|
|
|
|
|
if (cursorInstall) {
|
|
|
|
|
|
lines.push(`${step}. Open Cursor`);
|
|
|
|
|
|
if (cursorInstall.scope === 'project') {
|
|
|
|
|
|
lines.push(' Open Cursor from the KTX project directory:');
|
|
|
|
|
|
lines.push('');
|
|
|
|
|
|
lines.push(' OPEN:');
|
|
|
|
|
|
lines.push(` ${projectDir}`);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
lines.push(' Open Cursor.');
|
|
|
|
|
|
}
|
|
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (input.installs.some((install) => install.target === 'claude-desktop')) {
|
|
|
|
|
|
lines.push(`${step}. Restart Claude Desktop`);
|
2026-05-19 15:21:49 +02:00
|
|
|
|
lines.push(' Claude Desktop loads KTX MCP after restart.');
|
2026-05-18 18:54:20 -04:00
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
2026-05-19 15:21:49 +02:00
|
|
|
|
|
|
|
|
|
|
const skillBundlePaths = claudeDesktopSkillBundlePathsForInstalls(projectDir, input.installs);
|
|
|
|
|
|
if (skillBundlePaths.length > 0) {
|
|
|
|
|
|
lines.push(`${step}. Upload Claude Desktop skills`);
|
|
|
|
|
|
lines.push(' Open Claude Desktop: Customize > Skills > + > Create skill > Upload a skill.');
|
|
|
|
|
|
lines.push(skillBundlePaths.length === 1 ? ' Upload this file:' : ' Upload each file separately:');
|
|
|
|
|
|
for (const path of skillBundlePaths) {
|
|
|
|
|
|
lines.push(` ${path}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
lines.push(' Toggle the uploaded KTX skills on.');
|
|
|
|
|
|
pushBlankLine(lines);
|
|
|
|
|
|
step += 1;
|
|
|
|
|
|
}
|
2026-05-18 18:54:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (lines.length === 0) {
|
|
|
|
|
|
lines.push('Open your configured agent and ask a data question.');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
trimTrailingBlankLines(lines);
|
|
|
|
|
|
return lines.join('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:12:26 +02:00
|
|
|
|
async function installTarget(input: {
|
|
|
|
|
|
projectDir: string;
|
2026-05-10 23:51:24 +02:00
|
|
|
|
target: KtxAgentTarget;
|
|
|
|
|
|
scope: KtxAgentScope;
|
|
|
|
|
|
mode: KtxAgentInstallMode;
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}): Promise<InstallEntry[]> {
|
2026-05-10 23:51:24 +02:00
|
|
|
|
const entries = plannedKtxAgentFiles(input);
|
2026-05-10 16:01:58 -07:00
|
|
|
|
const launcher = ktxCliLauncher();
|
2026-05-10 23:12:26 +02:00
|
|
|
|
for (const entry of entries) {
|
2026-05-12 23:51:46 +02:00
|
|
|
|
if (entry.kind !== 'file') continue;
|
2026-05-19 15:21:49 +02:00
|
|
|
|
if (entry.role === 'claude-desktop-skill-bundle') {
|
|
|
|
|
|
await writeClaudeDesktopSkillBundle({
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
projectDir: input.projectDir,
|
|
|
|
|
|
path: entry.path,
|
2026-05-19 15:21:49 +02:00
|
|
|
|
skillName: claudeDesktopSkillNameForBundle(entry.path),
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
launcher,
|
|
|
|
|
|
});
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2026-05-12 23:51:46 +02:00
|
|
|
|
const content =
|
|
|
|
|
|
entry.role === 'rule'
|
|
|
|
|
|
? ruleInstructionContent({ projectDir: input.projectDir })
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
: entry.role === 'analytics-skill'
|
|
|
|
|
|
? await readAnalyticsSkillContent()
|
2026-05-12 23:51:46 +02:00
|
|
|
|
: cliInstructionContent({ projectDir: input.projectDir, launcher });
|
|
|
|
|
|
await mkdir(dirname(entry.path), { recursive: true });
|
|
|
|
|
|
await writeFile(entry.path, content, 'utf-8');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
return entries;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function markAgentsComplete(projectDir: string): Promise<void> {
|
2026-05-10 23:51:24 +02:00
|
|
|
|
const project = await loadKtxProject({ projectDir });
|
2026-05-13 13:55:21 +02:00
|
|
|
|
await writeFile(project.configPath, serializeKtxProjectConfig(project.config), 'utf-8');
|
2026-05-12 16:26:23 -07:00
|
|
|
|
await markKtxSetupStateStepComplete(projectDir, 'agents');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 23:51:24 +02:00
|
|
|
|
export async function runKtxSetupAgentsStep(
|
|
|
|
|
|
args: KtxSetupAgentsArgs,
|
|
|
|
|
|
io: KtxCliIo,
|
|
|
|
|
|
deps: KtxSetupAgentsDeps = {},
|
|
|
|
|
|
): Promise<KtxSetupAgentsResult> {
|
2026-05-10 23:12:26 +02:00
|
|
|
|
if (args.skipAgents) {
|
2026-05-12 16:58:09 -07:00
|
|
|
|
io.stdout.write('│ Agent integration skipped.\n');
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return { status: 'skipped', projectDir: args.projectDir };
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!args.agents && args.inputMode === 'disabled') {
|
|
|
|
|
|
return { status: 'skipped', projectDir: args.projectDir };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const prompts = deps.prompts ?? createPromptAdapter();
|
2026-05-19 15:21:49 +02:00
|
|
|
|
if (args.inputMode === 'auto' && args.target === undefined) {
|
|
|
|
|
|
writeSetupInfo(io, 'Space to select, Enter to confirm, Esc to go back.');
|
|
|
|
|
|
}
|
2026-05-10 23:12:26 +02:00
|
|
|
|
const mode =
|
|
|
|
|
|
args.inputMode === 'disabled'
|
|
|
|
|
|
? args.mode
|
|
|
|
|
|
: ((await prompts.select({
|
2026-05-18 18:54:20 -04:00
|
|
|
|
message: 'What should agents be allowed to do with this KTX project?',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
options: [
|
2026-05-18 18:54:20 -04:00
|
|
|
|
{
|
|
|
|
|
|
value: 'mcp',
|
|
|
|
|
|
label: 'Ask data questions with KTX MCP',
|
|
|
|
|
|
hint: 'Installs the MCP connection and analytics workflow skill. Best for normal use.',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 'mcp-cli',
|
|
|
|
|
|
label: 'Ask data questions + manage KTX with CLI commands',
|
|
|
|
|
|
hint: 'Adds an admin CLI skill so agents can run ktx status, sl, wiki, and setup commands.',
|
|
|
|
|
|
},
|
2026-05-24 19:30:06 +02:00
|
|
|
|
{
|
|
|
|
|
|
value: 'skip',
|
|
|
|
|
|
label: 'Skip agent setup for now',
|
|
|
|
|
|
hint: 'Leaves agent integration incomplete. You can run ktx setup --agents later.',
|
|
|
|
|
|
},
|
2026-05-10 23:12:26 +02:00
|
|
|
|
],
|
2026-05-24 19:30:06 +02:00
|
|
|
|
})) as KtxAgentModePromptChoice);
|
2026-05-12 21:31:11 -07:00
|
|
|
|
if (mode === 'back') return { status: 'skipped', projectDir: args.projectDir };
|
2026-05-24 19:30:06 +02:00
|
|
|
|
if (mode === 'skip') {
|
|
|
|
|
|
io.stdout.write('│ Agent integration skipped.\n');
|
|
|
|
|
|
return { status: 'skipped', projectDir: args.projectDir };
|
|
|
|
|
|
}
|
2026-05-10 23:12:26 +02:00
|
|
|
|
|
|
|
|
|
|
const targets =
|
|
|
|
|
|
args.target !== undefined
|
|
|
|
|
|
? [args.target]
|
|
|
|
|
|
: args.inputMode === 'disabled'
|
|
|
|
|
|
? []
|
|
|
|
|
|
: ((await prompts.multiselect({
|
2026-05-19 15:21:49 +02:00
|
|
|
|
message: 'Which agent targets should KTX install?',
|
2026-05-10 23:12:26 +02:00
|
|
|
|
options: [
|
|
|
|
|
|
{ value: 'claude-code', label: 'Claude Code' },
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
{ value: 'claude-desktop', label: 'Claude Desktop' },
|
2026-05-10 23:12:26 +02:00
|
|
|
|
{ value: 'codex', label: 'Codex' },
|
|
|
|
|
|
{ value: 'cursor', label: 'Cursor' },
|
|
|
|
|
|
{ value: 'opencode', label: 'OpenCode' },
|
|
|
|
|
|
{ value: 'universal', label: 'Universal .agents' },
|
|
|
|
|
|
],
|
|
|
|
|
|
required: true,
|
2026-05-10 23:51:24 +02:00
|
|
|
|
})) as KtxAgentTarget[]);
|
|
|
|
|
|
if (targets.includes('back' as KtxAgentTarget)) return { status: 'back', projectDir: args.projectDir };
|
2026-05-10 23:12:26 +02:00
|
|
|
|
if (targets.length === 0) {
|
2026-05-19 19:23:35 +02:00
|
|
|
|
io.stderr.write(
|
|
|
|
|
|
args.inputMode === 'disabled'
|
|
|
|
|
|
? 'Run in a TTY, or pass --target <target>.\n'
|
|
|
|
|
|
: 'Missing agent target: pass --target or use interactive setup.\n',
|
|
|
|
|
|
);
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return { status: 'missing-input', projectDir: args.projectDir };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const scopeTargets = targets.filter((target) => target !== 'claude-desktop');
|
|
|
|
|
|
const selectedScope =
|
|
|
|
|
|
args.inputMode !== 'disabled' &&
|
|
|
|
|
|
args.scope === 'project' &&
|
|
|
|
|
|
scopeTargets.length > 0 &&
|
|
|
|
|
|
scopeTargets.every(targetSupportsGlobalScope)
|
|
|
|
|
|
? ((await prompts.select({
|
2026-05-18 18:54:20 -04:00
|
|
|
|
message: `Where should KTX install supported agent config?\n\nKTX project: ${resolve(args.projectDir)}`,
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
options: [
|
2026-05-18 18:54:20 -04:00
|
|
|
|
{
|
|
|
|
|
|
value: 'project',
|
|
|
|
|
|
label: 'Project scope (KTX project directory)',
|
|
|
|
|
|
hint: 'Only agents opened from this KTX project path load the project-scoped config.',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 'global',
|
|
|
|
|
|
label: 'Global scope (user config)',
|
|
|
|
|
|
hint: 'Agents can load this KTX project from any working directory.',
|
|
|
|
|
|
},
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
],
|
|
|
|
|
|
})) as KtxAgentScope | 'back')
|
|
|
|
|
|
: args.scope;
|
|
|
|
|
|
if (selectedScope === 'back') return { status: 'back', projectDir: args.projectDir };
|
|
|
|
|
|
|
|
|
|
|
|
const installs = targets.map((target) => ({ target, scope: effectiveInstallScope(target, selectedScope), mode }));
|
2026-05-10 23:12:26 +02:00
|
|
|
|
const entries: InstallEntry[] = [];
|
2026-05-15 02:35:09 +02:00
|
|
|
|
const snippets: string[] = [];
|
|
|
|
|
|
const notices = new Set<string>();
|
2026-05-10 23:12:26 +02:00
|
|
|
|
try {
|
2026-05-15 02:35:09 +02:00
|
|
|
|
for (const install of installs) {
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const targetEntries = await installTarget({ projectDir: args.projectDir, ...install });
|
|
|
|
|
|
entries.push(...targetEntries);
|
|
|
|
|
|
const mcpResult = await installMcpClientConfig({
|
|
|
|
|
|
projectDir: args.projectDir,
|
|
|
|
|
|
target: install.target,
|
|
|
|
|
|
scope: install.scope,
|
|
|
|
|
|
});
|
2026-05-15 02:35:09 +02:00
|
|
|
|
entries.push(...mcpResult.entries);
|
|
|
|
|
|
for (const snippet of mcpResult.snippets) snippets.push(snippet);
|
|
|
|
|
|
for (const notice of mcpResult.notices) notices.add(notice);
|
|
|
|
|
|
}
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
await writeManifest(
|
|
|
|
|
|
args.projectDir,
|
|
|
|
|
|
mergeManifest(args.projectDir, await readKtxAgentInstallManifest(args.projectDir), installs, entries),
|
|
|
|
|
|
);
|
2026-05-10 23:12:26 +02:00
|
|
|
|
await markAgentsComplete(args.projectDir);
|
feat(setup): add Claude Desktop target and MCP-first agent setup (#114)
* feat(setup): add Claude Desktop target and MCP-first agent setup
Adds `ktx mcp stdio` and a `claude-desktop` setup target that generates a
local plugin ZIP wiring the analytics skill and a stdio MCP config. Replaces
the CLI-only agent install mode with MCP+analytics (default) and an optional
admin CLI skill, renames the research skill to analytics, and lets interactive
setup pick project vs global scope when every target supports it. Extracts a
shared MCP server factory used by both HTTP and stdio entrypoints.
* Add MCP agent client setup support
* Polish setup output formatting
* Add MCP tool polish design spec
Design for slimming the MCP-registered surface from 25 to 11 tools,
introducing memory_ingest, applying the per-tool polish kit (annotations,
outputSchema, .describe(), in-band error wrapping, union-drift fixes,
type-narrowed jsonToolResult), emitting progress notifications on
sql_execution + sl_query, and refining the ktx-analytics SKILL.md to
match.
* Refine MCP tool polish design spec after adversarial review iteration 1
* Refine MCP tool polish design spec after adversarial review iteration 2
* Refine MCP tool polish design spec after adversarial review iteration 3
* refactor(context): rename memory capture service to ingest
* feat(mcp): slim research tool surface
* refactor(mcp): remove admin ports from server factory
* refactor(cli): rename text ingest memory port
* docs: update analytics skill for memory ingest
* chore: verify mcp surface rename
* Add MCP tool polish v1 surface change plan
* feat(context): polish mcp tool metadata
* fix(context): enforce resolved semantic layer compute sources
* feat(context): emit mcp query progress stages
* fix(context): keep mcp progress event internal
* Add MCP tool polish v1 metadata & progress plan
* Fix CI snapshot and docs checks
2026-05-16 11:39:55 +02:00
|
|
|
|
const setupUi = createKtxSetupUiAdapter();
|
2026-05-19 15:21:49 +02:00
|
|
|
|
for (const summary of formatInstallSummaryLines(installs, entries, args.projectDir)) {
|
|
|
|
|
|
writeSetupStep(
|
|
|
|
|
|
io,
|
|
|
|
|
|
summary.lines.length > 0 ? `${summary.title}\n${summary.lines.join('\n')}` : summary.title,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-05-18 18:54:20 -04:00
|
|
|
|
const nextActions = formatAgentNextActions({
|
|
|
|
|
|
projectDir: args.projectDir,
|
|
|
|
|
|
installs,
|
|
|
|
|
|
notices: [...notices],
|
|
|
|
|
|
snippets,
|
|
|
|
|
|
});
|
|
|
|
|
|
if (args.showNextActions !== false) {
|
2026-05-19 15:21:49 +02:00
|
|
|
|
setupUi.note(nextActions, 'Required before using agents', io, {
|
|
|
|
|
|
format: createAgentNextActionsLineFormatter(io.stdout),
|
|
|
|
|
|
});
|
|
|
|
|
|
writeSetupOutro(io, 'All set.');
|
2026-05-15 02:35:09 +02:00
|
|
|
|
}
|
2026-05-18 18:54:20 -04:00
|
|
|
|
return { status: 'ready', projectDir: args.projectDir, installs, nextActions };
|
2026-05-10 23:12:26 +02:00
|
|
|
|
} catch (error) {
|
test: split cli tests from source tree (#216)
* feat(cli): define full warehouse dialect contract
* test(cli): keep dialect edge tests focused
* fix(cli): stabilize dialect contract foundation
* refactor(connectors): own read-only query preparation
* refactor(connectors): resolve dialects through registry
* refactor(connectors): keep concrete dialect classes internal
* chore(workspace): enforce dialect import boundary
* refactor(cli): resolve relationship dialect at scan boundary
* refactor(cli): use dialect display parsing for entity details
* refactor(cli): use dialect display parsing for warehouse catalog
* refactor(cli): use dialect SQL in relationship workflows
* test(cli): verify solid dialect scan workflow closure
* test: split cli tests from source tree
* refactor(cli): standardize BigQuery scope listing
* feat(sqlite): implement connector scope listing
* test(connectors): cover required table listing
* feat(cli): add warehouse driver registry
* refactor(setup): route scope discovery through driver registry
* refactor(cli): route local query execution through driver registry
* refactor(historic-sql): route dialect support through driver registry
* refactor(cli): test warehouse connections through driver registry
* fix(cli): close driver registry type export gaps
* Improve setup daemon diagnostics
* refactor(setup): centralize rail-prefixed diagnostics + query-history fallback
Extract errorMessage, writePrefixedLines, and flushPrefixedBufferedCommandOutput
into clack.ts so the setup wizard, managed daemons, and embedding/agent steps
share one rail-formatted writer. setup-databases.ts also adds a
"disable query history and retry" option when the schema-context build fails
and query history is the likely culprit, surfaced via a new
failed-query-history-unavailable status.
* fix(cli): carry catalog through the picker so BigQuery/Snowflake/SQL Server scope filters match
The setup picker's KtxTableListEntry was a 2-level { schema, name }, so
qualifiedTableId always wrote db.name into enabled_tables. When BigQuery,
Snowflake, or SQL Server later ran fast ingest, their introspect step filtered
the scope set with scopedTableNames(scope, { catalog: projectId|database, db })
— catalog was non-null on the introspect side but null in the scope refs, so
every entry was rejected, the live-database adapter staged zero table files,
and detect() failed with 'Adapter "live-database" did not recognize fetched
source output'.
Align the picker boundary with the canonical 3-level KtxTableRef:
- Add catalog: string | null to KtxTableListEntry.
- BigQuery/Snowflake/SQL Server listTables populate catalog from the
resolved projectId / database; Postgres/MySQL/ClickHouse/SQLite set null.
- qualifiedTableId emits catalog.schema.name when catalog is non-null
(resolveEnabledTables already accepts the 3-part shape) and
schemasFromEnabledTables now goes through parseDottedTableEntry so it
recovers the schema correctly from both 2-part and 3-part entries.
- Export parseDottedTableEntry from enabled-tables.ts (@internal) for picker
reuse.
Update listTables expectations in all seven connector tests and the setup /
picker test fixtures. Add a picker regression test that covers the
catalog-bearing round-trip (save + refine).
* fix(cli): allow debug telemetry under opt-out env
2026-05-26 08:49:05 +02:00
|
|
|
|
writePrefixedLines((chunk) => io.stderr.write(chunk), errorMessage(error));
|
2026-05-10 23:12:26 +02:00
|
|
|
|
return { status: 'failed', projectDir: args.projectDir };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|